import time
import tkinter as tk
import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from math import log10
class Win:
def __init__(self):
# Initialisation de la fenêtre principale
self.win = tk.Tk()
self.win.title("Sonometre") # Titre de la fenêtre
self.win.geometry("700x720") # Taille de la fenêtre
try:
self.win.iconbitmap('microphone.ico') # Tente de définir une icône pour la fenêtre
self.win.iconphoto('microphone.ico')
except:
pass # Ignore les erreurs si l'icône n'est pas trouvée
# Initialisation des variables pour le sonomètre
self.int_db = 0 # Niveau de décibels
self.int_led = 0 # Valeur LED
self.int_maxi = 0 # Valeur maximale
self.int_mini = 255 # Valeur minimale
self.int_moyenne = 0 # Moyenne des valeurs
self.lst_list_moy = [] # Liste pour stocker les valeurs pour le calcul de la moyenne
self.lst_list_led_val = ["00", "01", "03", "07"] # Valeurs possibles pour les LEDs
self.lst_list_ab_val = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] # Valeurs possibles pour AB
self.int_taille_echantillon = 400 # Taille de l'échantillon
self.bool_emul = True # Indicateur d'émulation
self.bool_start_and_stop = False # Indicateur de démarrage/arrêt
# Création du canevas pour dessiner les éléments graphiques
self.canvas = tk.Canvas(self.win, width=700, height=720, bg="#669bbc")
self.canvas.pack()
# Création des LEDs (cercles) pour indiquer le niveau sonore
self.led1 = self.canvas.create_oval(10, 20, 40, 50, fill="#005f00", outline="#003049", width=2) # LED 1
self.led2 = self.canvas.create_oval(50, 20, 80, 50, fill="#c9a227", outline="#003049", width=2) # LED 2
self.led3 = self.canvas.create_oval(90, 20, 120, 50, fill="#990000", outline="#003049", width=2) # LED 3
# Création d'un rectangle pour afficher la dose
self.rect = self.canvas.create_rectangle(530, 20, 580, 280, outline="black", width=2)
self.dose = self.canvas.create_rectangle(530, 280, 580, 280, fill="#00ff00")
# Ajout d'une checkbox pour activer/désactiver l'émulation
self.int_var_led = tk.IntVar(value=True)
self.checkbutton_emul = tk.Checkbutton(self.win, text="Emuler", variable=self.int_var_led, command=self.toggle_leds)
self.checkbutton_emul.place(x=20, y=60)
# Bouton pour démarrer/arrêter la mesure
self.button_start_and_stop = tk.Button(self.win, text="Start", command=self.start_and_stop, background="#00ff00")
self.button_start_and_stop.place(x=200, y=60)
# Création de listes déroulantes (OptionMenu) pour sélectionner les valeurs LED et AB
self.lst_options_led_listbox = self.lst_list_led_val
self.label_led_listbox = tk.Label(self.win, text="", bg="#669bbc")
self.label_led_listbox.place(x=80, y=200)
self.str_option_select_listbox = tk.StringVar(value=self.lst_options_led_listbox[0])
self.dropdown_led = tk.OptionMenu(self.win, self.str_option_select_listbox, *self.lst_options_led_listbox)
self.dropdown_led.place(x=170, y=120)
# Création de listes déroulantes (OptionMenu) pour sélectionner les valeurs LED et AB (bis)
self.label_led_listbox_bis = tk.Label(self.win, text="", bg="#669bbc")
self.label_led_listbox_bis.place(x=80, y=250)
self.str_option_select_listbox_bis = tk.StringVar(value=self.lst_options_led_listbox[0])
self.dropdown_bis = tk.OptionMenu(self.win, self.str_option_select_listbox_bis, *self.lst_options_led_listbox)
self.dropdown_bis.place(x=170, y=170)
# Liste déroulante pour la sélection de valeurs AB
self.lst_options_ab_listbox = self.lst_list_ab_val
self.label_ab_listbox_gauche = tk.Label(self.win, text="", bg="#669bbc")
self.label_ab_listbox_gauche.place(x=80, y=200)
self.str_option_select_ab_listbox_gauche = tk.StringVar(value=self.lst_options_ab_listbox[0])
self.dropdown_ab_gauche = tk.OptionMenu(self.win, self.str_option_select_ab_listbox_gauche, *self.lst_options_ab_listbox)
self.dropdown_ab_gauche.place(x=15, y=120)
# Liste déroulante pour la sélection de valeurs AB (bis)
self.label_ab_listbox_bis_gauche = tk.Label(self.win, text="", bg="#669bbc")
self.label_ab_listbox_bis_gauche.place(x=80, y=250)
self.str_option_select_ab_listbox_bis_gauche = tk.StringVar(value=self.lst_options_ab_listbox[0])
self.dropdown_bis_ab_gauche = tk.OptionMenu(self.win, self.str_option_select_ab_listbox_bis_gauche, *self.lst_options_ab_listbox)
self.dropdown_bis_ab_gauche.place(x=15, y=170)
# Liste déroulante pour la sélection de valeurs AB à droite
self.label_ab_listbox_droite = tk.Label(self.win, text="", bg="#669bbc")
self.label_ab_listbox_droite.place(x=80, y=200)
self.str_option_select_ab_listbox_droite = tk.StringVar(value=self.lst_options_ab_listbox[0])
self.dropdown_ab_droite = tk.OptionMenu(self.win, self.str_option_select_ab_listbox_droite, *self.lst_options_ab_listbox)
self.dropdown_ab_droite.place(x=70, y=120)
# Liste déroulante pour la sélection de valeurs AB (bis) à droite
self.label_ab_listbox_bis_droite = tk.Label(self.win, text="", bg="#669bbc")
self.label_ab_listbox_bis_droite.place(x=80, y=250)
self.str_option_select_ab_listbox_bis_droite = tk.StringVar(value=self.lst_options_ab_listbox[0])
self.dropdown_bis_ab_droite = tk.OptionMenu(self.win, self.str_option_select_ab_listbox_bis_droite, *self.lst_options_ab_listbox)
self.dropdown_bis_ab_droite.place(x=70, y=170)
# Textes pour afficher les niveaux de décibels
self.label_db_text = self.canvas.create_text(300, 35, text="0dB", font=("Arial", 20), fill="black")
self.label_db_min_text = self.canvas.create_text(475, 50, text="min : 0dB", font=("Arial", 13), fill="black")
self.label_db_max_text = self.canvas.create_text(475, 75, text="max : 0dB", font=("Arial", 13), fill="black")
self.label_db_moy_text = self.canvas.create_text(475, 100, text="moy : 0dB", font=("Arial", 13), fill="black")
self.label_de = self.canvas.create_text(150, 135, text="à", font=("Arial", 13), fill="black")
self.label_dede = self.canvas.create_text(150, 185, text="à", font=("Arial", 13), fill="black")
# Création de la figure Matplotlib pour le graphique en temps réel
self.fig, self.ax = plt.subplots(figsize=(6, 4))
self.lst_xdata, self.lst_ydata = [], [] # Données pour le graphique
self.float_time = 0 # Temps initial
self.ln, = self.ax.plot([], [], 'r-', animated=True) # Ligne du graphique
self.ax.set_facecolor("#669bbc") # Couleur de fond de l'axe
self.fig.patch.set_facecolor("#669bbc") # Couleur de fond de la figure
self.ln.set_color('#003566') # Couleur de la ligne
# Limites de l'axe X (temps) et de l'axe Y (dB)
self.ax.set_xlim(0, 10) # Plage initiale de l'axe X (10 secondes visibles)
self.ax.set_ylim(0, 300) # Plage de l'axe Y pour les dB
# Intégration du graphique dans Tkinter via FigureCanvasTkAgg
self.canvas_fig = FigureCanvasTkAgg(self.fig, master=self.canvas)
self.canvas_fig.draw()
self.canvas_fig.get_tk_widget().place(x=42, y=281) # Positionner le graphique en bas de l'écran
# Animation du graphique en temps réel
self.ani = animation.FuncAnimation(self.fig, self.update, frames=np.linspace(0, 2 * np.pi, 128),
init_func=self.init, blit=True, interval=100) # Mise à jour chaque seconde
def toggle_leds(self):
# Fonction pour activer ou désactiver l'émulation des LEDs
if self.int_var_led.get():
self.bool_emul = True # Activer l'émulation
else:
self.bool_emul = False # Désactiver l'émulation
def change_all_val_and_update(self, ab, led):
# Met à jour toutes les valeurs et les affiche
self.change_db(ab) # Met à jour le niveau de décibels
self.change_led(led) # Met à jour la valeur LED
self.change_min(ab) # Met à jour la valeur minimale
self.change_max(ab) # Met à jour la valeur maximale
self.cal_moy(ab) # Calcule la moyenne
self.col_led_dose() # Met à jour les couleurs des LEDs
self.dose_update() # Met à jour l'affichage de la dose
self.text_update() # Met à jour les textes affichés
def gen_data(self):
# Génère des données aléatoires pour simuler les niveaux de décibels
try:
self.lst_ab_gauche = self.lst_list_ab_val[self.lst_list_ab_val.index(self.str_option_select_ab_listbox_gauche.get()) : self.lst_list_ab_val.index(self.str_option_select_ab_listbox_bis_gauche.get()) + 1]
self.lst_ab_droite = self.lst_list_ab_val[self.lst_list_ab_val.index(self.str_option_select_ab_listbox_droite.get()) : self.lst_list_ab_val.index(self.str_option_select_ab_listbox_bis_droite.get()) + 1]
self.lst_led = self.lst_list_led_val[self.lst_list_led_val.index(self.str_option_select_listbox.get()) : self.lst_list_led_val.index(self.str_option_select_listbox_bis.get()) + 1]
chaine = ""
for _ in range(self.int_taille_echantillon):
chaine += "ab" + random.choice(self.lst_ab_gauche) + random.choice(self.lst_ab_droite) + "dc" + random.choice(self.lst_led)
return chaine # Retourne la chaîne générée
except:
return "ab00cd00" # Valeur par défaut en cas d'erreur
time.sleep(500) # Pause de 500 ms
def start_and_stop(self):
# Fonction pour démarrer ou arrêter la mesure
if self.bool_start_and_stop:
self.button_start_and_stop.config(text="Start", bg="#00ff00", fg="black") # Met à jour le bouton pour indiquer le démarrage
print(str(self.bool_start_and_stop))
self.bool_start_and_stop = False # Arrête la mesure
else:
self.button_start_and_stop.config(text="Stop", bg="#ff0000", fg="black") # Met à jour le bouton pour indiquer l'arrêt
print("false" + str(self.bool_start_and_stop))
self.bool_start_and_stop = True # Démarre la mesure
def update(self, frame):
# Met à jour les données du graphique en temps réel
self.float_time += 0.1 # Incrémenter le temps (en secondes)
# Générer de nouvelles données de dB basées sur le temps
dB_value = self.int_db # Utiliser la fonction get_data pour obtenir la valeur du signal en dB
# Ajouter les nouvelles données (temps et dB)
self.lst_xdata.append(self.float_time)
self.lst_ydata.append(dB_value)
# Mettre à jour les limites de l'axe X pour faire défiler le temps
if self.float_time > 10: # Décaler l'axe X pour ne garder que les 10 dernières secondes visibles
self.ax.set_xlim(self.float_time - 10, self.float_time)
# Mettre à jour la courbe avec les nouvelles données
self.ln.set_data(self.lst_xdata, self.lst_ydata)
self.canvas_fig.draw() # Redessiner le graphique
return self.ln, # Retourne la ligne mise à jour
def change_db(self, val):
# Met à jour le niveau de décibels en fonction de la valeur fournie
try:
self.int_db = int(40 * log10(val) - 10) # Calcul du niveau en dB
except:
pass # Ignore les erreurs
def change_led(self, val):
# Met à jour la valeur LED
self.int_led = val
def change_max(self, val):
# Met à jour la valeur maximale
self.int_maxi = max(self.int_maxi, val)
def change_min(self, val):
# Met à jour la valeur minimale
self.int_mini = min(self.int_mini, val)
def cal_moy(self, val):
# Calcule la moyenne des valeurs et l'ajoute à la liste
self.lst_list_moy.append(val)
self.int_moyenne = int(sum(self.lst_list_moy) / len(self.lst_list_moy)) # Calcul de la moyenne
def col_led_dose(self):
# Met à jour les couleurs des LEDs en fonction de la valeur LED
match int(self.int_led):
case 0:
self.led_update("#005f00", "#c9a227", "#990000") # Couleurs pour LED 0
case 1:
self.led_update("#00ff00", "#c9a227", "#990000") # Couleurs pour LED 1
case 3:
self.led_update("#00ff00", "#ffff00", "#990000") # Couleurs pour LED 3
case 7:
self.led_update("#00ff00", "#ffff00", "#ff0000") # Couleurs pour LED 7
def led_update(self, l1=None, l2=None, l3=None):
# Mise à jour des couleurs des LEDs
if l1:
self.canvas.itemconfig(self.led1, fill=l1) # Met à jour la couleur de la LED 1
if l2:
self.canvas.itemconfig(self.led2, fill=l2) # Met à jour la couleur de la LED 2
if l3:
self.canvas.itemconfig(self.led3, fill=l3) # Met à jour la couleur de la LED 3
def dose_update(self):
# Met à jour la représentation de la dose sur le canevas
self.canvas.coords(self.dose, 530, 280 - self.int_db, 580, 280) # Ajuste la position du rectangle de dose
if self.int_db <= 80:
self.canvas.itemconfig(self.dose, fill="#00ff00") # Couleur verte pour les niveaux bas
elif self.int_db <= 170:
self.canvas.itemconfig(self.dose, fill="#fcf300") # Couleur jaune pour les niveaux moyens
else:
self.canvas.itemconfig(self.dose, fill="#ff0000") # Couleur rouge pour les niveaux élevés
def text_update(self):
# Met à jour les textes affichés pour les niveaux de décibels
self.canvas.itemconfig(self.label_db_text, text=str(self.int_db) + "dB") # Affiche le niveau actuel
self.canvas.itemconfig(self.label_db_min_text, text="min : " + str(self.int_mini) + "dB") # Affiche le minimum
self.canvas.itemconfig(self.label_db_max_text, text="max : " + str(self.int_maxi) + "dB") # Affiche le maximum
self.canvas.itemconfig(self.label_db_moy_text, text="moy : " + str(self.int_moyenne) + "dB") # Affiche la moyenne
def init(self):
# Initialise le graphique
self.ln.set_data([], []) # Réinitialise les données de la ligne
return self.ln, # Retourne la ligne initialisée