# -*- coding: utf-8 -*- """ Created on Wed Nov 17 11:04:32 2021 @author: f.foc """ ################################################## Modules (ne pas modifier...) ############################### from tkinter.filedialog import askopenfilename #input dialog (fenetre interaction) from pathlib import Path #travailler avec des chemins de fichiers/repertoires import numpy # Travailler avec des "array" (matrices dans matlab) from numpy import loadtxt, array, mean import csv # Gestion des fichiers (lire, ouvrir, ecrire) import os # Interface d'OS (fenetres, etc) import matplotlib.pyplot as plt # Graphiques from scipy.signal import spectrogram, welch # signal processing import biosignalsnotebooks as bsnb # biosignalsnotebooks Python package #import math # Fonctions mathématiques (si vous souhaitez) https://docs.python.org/3/library/math.html ################################################## FONCTIONS (ne pas modifier...) ############################# # Fonction ouvre une interface graphique et permet de selectionner un fichier, renvoie le nom et le chemin def getfile(): filename = askopenfilename(initialdir = "",title = "Select file",filetypes = (("txt files","*.txt"),("all files","*.*"))) nomfichier = os.path.split(filename)[1] return nomfichier, filename # Fonction lit et parse un fichier csv et retourne les données formatées ainsi que la taille des colonnes et lignes def lecturecsv(nomfichier,ligne): datalist = [] dataarray = [] with open(nomfichier, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=';') for rows in reader: datalist.append(rows) #list de str dataarray=numpy.array(datalist[ligne:]) #convert list en array L_rows = len(dataarray) # calcul de longueur de vecteur L_columns = len(dataarray[0]) return dataarray, L_rows, L_columns ############################################# SCRIPT (à modifier gentillement) ################################### nomfichier, chemin=getfile() # Obtient chemin et nom du fichier grace à une fenetre graphique path = Path(chemin) # formatte un str en chemin os.chdir(path.parent.absolute()) # Met l'espace de travail dans le repertoire indiqué data = loadtxt(nomfichier) # Récupère les données brutes channel_column = 2 dataEEG = data[:,channel_column] # Récupère les données EEG (3ème colonne) sampling_rate = 1000 # Défini la fréquence d'acquisition (ici 1000hz) time = bsnb.generate_time(dataEEG, sampling_rate) # Génère un vecteur de temps (à utiliser en abscisse) # Transforme le signal en microvolt (fonction de conversion donnée par PLUX) # https://biosignalsplux.com/learn/notebooks/Categories/Pre-Process/unit_conversion_eeg_rev.php) vcc = 3e6 gain = 40000 resolution = 16 # Resolution (number of available bits) signal_uv = (((array(dataEEG) / 2**resolution) - 0.5) * vcc) / gain # Trace un graphique (plot) le signal EEG (sans post-processing) en fonction du temps plt.figure(1) # défini une figure plt.plot(time, signal_uv, label='Uv') # trace le graphique plt.xlabel('temps (s)') # défini un label en abcisse plt.ylabel('raw data (uV)') # défini un label en ordonnée plt.legend() # défini une légende plt.title("Raw data EEG en microvolt") # défini un titre plt.savefig('graph_raw_uV',dpi=500) # Sauvegarde la figure avec un nom de fichier et une résolution donnée # Spectrogramme du signal EEG : info sur la dynamique du signal (puissance) au cours du temps pour chaque fréquence #https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.spectrogram.html f, t, Sxx = spectrogram(signal_uv, fs = 1000) # Trace le spectrogramme graphique plt.figure(2) plt.pcolormesh(t, f, Sxx, shading='gouraud') # Tracé plt.ylabel('Frequences [Hz]') plt.xlabel('Temps [s]') plt.ylim([0, 30]) #limiter l'ordonnée plt.colorbar().set_label("Power (dB)") # Légende plt.title("Spectrogram") plt.savefig('spectrogram',dpi=500) # Analyse temporelle # Calcul d'une baseline et normalisation avec celle-ci sur une fenetre temporelle particulière sample_start = 1000; # Choix du début sample_end = 3000; # Choix de la fin signal_analysed = array(signal_uv[sample_start:sample_end]) - mean(array(signal_uv[sample_start:sample_end])) # retrait et normalisation par la baseline # Filtrer en appliquant un filtre Butterworth passe-bande (Exemple de la "alpha band") freq_low = 8 # limite basse de alpha band freq_high = 12 #limite haute de alpha band filtered_signal_8_12 = bsnb.bandpass(signal_analysed, freq_low, freq_high, order = 2, fs = 1000) # Application du filtre d'ordre 2 # Tracé de deux graphiques superposés plt.figure(3) plt.plot(time[sample_start:sample_end], filtered_signal_8_12, label='signal filtré') plt.xlabel('temps (s)') plt.ylabel('signal(uV)') plt.title("alpha band") plt.plot(time[sample_start:sample_end], signal_analysed, label='signal brut') plt.legend() plt.savefig('filtered signal',dpi=500) # Calcul de la variable temporelle : l'aire sous la courbe (intégrale) PowerTemp_value = sum(abs(filtered_signal_8_12[sample_start:sample_end])); #Somme des valeurs absolues # Analyse fréquentielle --> fast fourier transform using scipy.signal.welch & power spectrum density computing # Calcul densité spectrale de puissance https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.welch.html freq_axis, power_spect = welch(filtered_signal_8_12, sampling_rate) # Tracé du graphique de densité spectrale de puissance plt.figure(4) plt.plot(freq_axis, power_spect) # seulement les fréquences en dessous de 30 plt.xlim([0, 30]) plt.xlabel('frequency [Hz]') plt.ylabel('PSD') plt.savefig('FFT',dpi=500) # Calcul de la variable fréquentielle : l'aire sous la courbe psd_value = sum(power_spect[freq_low:freq_high]);