diff --git a/EStiMo_GUI.py b/EStiMo_GUI.py index 047957f..a11da1b 100644 --- a/EStiMo_GUI.py +++ b/EStiMo_GUI.py @@ -30,10 +30,8 @@ import datetime import ctypes import scipy import pywt -# import queue from cycler import cycler -# from matplotlib.backend_bases import MouseButton from PyQt5.QtCore import QTimer, Qt from PyQt5.QtGui import QImage, QPixmap, QIcon, QFont from PyQt5.QtWidgets import (QMainWindow, QFileDialog, QMessageBox, QCheckBox, QLineEdit, QWidget, QPushButton, @@ -154,19 +152,13 @@ class NeurOneOffline(): eeg_chn = np.arange(0,num_electr,1) hdr = mne.io.read_raw_brainvision(tmp_path) - # hdr.set_channel_types({'EMGleft': 'emg', 'EOGright': 'eog'}) - # hdr.set_montage(mne.channels.read_custom_montage('easycap-M10_63_NO.txt')) - # mrk_fullpath = tmp_path[:-4]+'vmrk' - # eeg_fullpath = tmp_path[:-4]+'eeg' #this two are made by hand instead of function. - #Maybe there is some func for this # Annotations returns all events - stimA, stimB, stopA, stopB, start of experiment etc... We chose only stim stim = hdr.annotations.onset[np.logical_or(hdr.annotations.description=="Stimulus/A", hdr.annotations.description=="Stimulus/B")] # Separate stimA and stimB stimA = hdr.annotations.onset[hdr.annotations.description=="Stimulus/A"] stimB = hdr.annotations.onset[hdr.annotations.description=="Stimulus/B"] - #divide for stim A and B - #stimR = hdr.annotations.onset[hdr.annotations.description=='Response/R 16'] + npts = hdr.n_times nfft = int(hdr.info['sfreq']) # Sampling rate [Hz] fs = int(hdr.info['sfreq']) # Sampling rate [Hz] @@ -335,8 +327,7 @@ class AppForm(QMainWindow): 10: 7.812 - 15.625 Hz 11: 15.625 - 31.25 Hz """ - band = band - 9 #weird way, but then call from function works well for particular band - #but works correctly only for this set of features! + band = band - 9 dwt_pw1, dwt_pw2, dwt_pw3, dwt_pw4 = self.dwt[:4] #sum of squares dwt_pw1 = np.sum(dwt_pw1**2) @@ -380,8 +371,7 @@ class AppForm(QMainWindow): 'High Gamma FFT Power', 'Spectral entropy', 'Temporal entropy', 'Line length', 'DWT Power 0-4 Hz', 'DWT 4-8 Hz', 'DWT 8-16 Hz', 'DWT 16-31 Hz','Variance','Correlation'] - # One last thing to use your new function is to add string with its name - # to the other First_window.py: variable features_names in class First_window + def all_params(self, passed_params = None, restarted=''): #reads values from TMS_protocol.txt file @@ -562,10 +552,6 @@ class AppForm(QMainWindow): self.last_sec = ss.filtfilt(A, B, self.last_sec) self.last_sec = ss.detrend(self.last_sec, axis=1) - # plt.figure() - # plt.plot(self.last_sec[self.included_ch].T) - # plt.plot(eog) - #that's stupid, move channel selection before!!!!!!!!!!!!! if self.use_regression: self.last_sec = eye_reg(self.last_sec[self.included_ch], eog) return self.last_sec @@ -592,9 +578,7 @@ class AppForm(QMainWindow): self.results[idx] = self.functions[feature](feature) else: self.results[idx] = self.functions[feature]() - - #Checks how many fields were filled already, so we know what stage are we on - #and where to save the data + x = np.where(self.feature1==None)[0][0] y = np.where(self.feature1==None)[1][0] @@ -616,9 +600,6 @@ class AppForm(QMainWindow): print("Calculation of features: {}".format(times1-times)) - #if value is not within threshold values then background color is red (salmon), otherwise green - - #checks if there is a need to change a color of the background old_prv_state = self.previous_state.copy() if not all(np.isnan(self.thr_1)): if self.results[0]>=self.thr_1[0] and self.results[0]<=self.thr_1[1]: @@ -724,9 +705,7 @@ class AppForm(QMainWindow): #If there is a need to redraw we do that. draw() option is slower, but more robust if need_redraw: self.canvasMap.draw() - #otherwise we can just update the line, or to be precise, I think it just - #draws the line on the old one. In this application it's fine. Faster than previous method. - #I can think about blitting, so it could be even faster... + #otherwise we can just update the line, or to be precise, else: for i in range(3): for j in range(2): @@ -740,8 +719,7 @@ class AppForm(QMainWindow): def update(self): """Updates data, checks if something should be plotted""" time_start = time.time() - # There were some problems with delay. This way it works, but probably it can be done better - # If the queue with data timer is sped up. + if self.q.qsize()>0: self.timer.setInterval(int(1*self.speed_general*0.97)) if self.q.qsize()<1 and self.timer.interval()!= int(self.speed_general*1.1): @@ -827,13 +805,6 @@ class AppForm(QMainWindow): if len(stim)>0: for ind in stim[::-1]: size = self.data_len - (od+ind-int(int_from*self.Fs)) - # print('size:', size) - # print(len(self.loaded)) - # Interpolation - pretty long line, but basically it chooses ranges and - # assign boundary value as a baseline and does that in (I guess) more optimal way than using loops - # self.loaded[:, od+ind-int(int_from*self.Fs):od+ind+int(int_to*self.Fs)] = np.outer( - # self.loaded[:,min(od+ind+int(int_to*self.Fs), 30000-1)], np.ones(min(size, int((int_from+int_to)*self.Fs)))) - # this way is even easier... self.loaded[:, od+ind-int(int_from*self.Fs):od+ind+int(int_to*self.Fs)] = self.loaded[:,min(od+ind+int(int_to*self.Fs), 30000-1)].reshape(-1, 1) # for i in range(self.loaded.shape[0]): # self.loaded[i, od+ind-int(int_from*self.Fs):od+ind+int(int_to*self.Fs)] = np.linspace( @@ -861,8 +832,6 @@ class AppForm(QMainWindow): step9 = time.time()-time_start - # If do_calibration is True and there were trigger recently then stop calibration - # TODO: THAT'S CONDITION REQUIRED FOR STARTING MEASURMENTS. PROBABLY IT WON'T WORK FOR SOME MORE EXTREME SETTINGS # if self.do_calibration and len(stim_where[stim_where>(self.data_len-max( # 2000, round(self.Fs*self.time_between_bursts*0.7, -3)))])>0: if self.do_calibration and len(stim_where[stim_where>(self.data_len-max(2000, self.exp_time+1500))])>0: @@ -876,7 +845,6 @@ class AppForm(QMainWindow): return 0 #ends run of this function so nothing else happens step10 = time.time()-time_start # If set number of stimuli is detected - # doit --> set length of the measurment between bursts # if self.doit==0 and sum(stim_where>self.data_len-max( # 2000, round(self.Fs*self.time_between_bursts*0.7, -3)))==10: print(sum(stim_where>self.data_len-max(2000, self.exp_time+1500))) @@ -900,9 +868,6 @@ class AppForm(QMainWindow): elif self.doit>0: print(self.doit) self.last_stim = stim_where[-1] - # In some situations last stimuli might be already from another train, while - # First 100ms of loaded signal belong to previous one. That is why this exception exists - # EDIT: not sure if it's still needed after other changes I made if any(np.diff(stim_where[stim_where>self.data_len-max( 2000, round(self.Fs*self.time_between_bursts*1.2, -3))])>1000): print('UWAGA NA TO') @@ -1015,7 +980,6 @@ class AppForm(QMainWindow): self.button4.setText("Start calibration") self.button4.setStyleSheet('') #par = self.thr_parameter - #Need to clean the figure to prepare is for a different type of plot for i in range(6): self.axesMap[i//2,i%2].cla() @@ -1120,8 +1084,7 @@ class AppForm(QMainWindow): #calculate fft self.S = abs(np.fft.rfft(self.second_to_analyze)) - #this is a bit shady, but should work. check it out if doesn't! - #do dwt only if any features requires it + if any(feature_num in self.used_features for feature_num in [8,9,10,11]): self.dwt = pywt.wavedec(self.second_to_analyze, 'db1', level=8) @@ -1152,8 +1115,7 @@ class AppForm(QMainWindow): self.cals = [self.f1_cal, self.f2_cal, self.f3_cal, self.f4_cal, self.f5_cal, self.f6_cal] - #!!! Temporary, it's wrong but it's overwritten later. It's needed to check if all features are used, - #but there could be more optimal solution. Remove it at some point! + self.thr_1 = [np.min(self.f1_cal)-0.1*np.min(self.f1_cal), np.max(self.f1_cal)+0.1*np.max(self.f1_cal)] self.thr_2 = [np.min(self.f2_cal)-0.1*np.min(self.f2_cal), @@ -1245,12 +1207,6 @@ class AppForm(QMainWindow): tick.tick2line.set_visible(False) tick.label1.set_visible(False) tick.label2.set_visible(False) - - # for tick in self.axes.yaxis.get_major_ticks(): - # tick.tick1line.set_visible(False) - # tick.tick2line.set_visible(False) - # tick.label1.set_visible(False) - # tick.label2.set_visible(False) self.axes.set_yticks(np.arange(1, (self.num_of_ch)*1.01, 1)) self.axes.set_yticklabels(self.ch_names[::-1]) @@ -1304,14 +1260,6 @@ class AppForm(QMainWindow): self.canvas.draw() self.canvasMap.draw() #update canvas - #NOT NEEDED - # for i in range(self.num_of_ch): - # self.axbackground = self.canvas.copy_from_bbox(self.axes.bbox) - - # texts = [] - # for ind,name in enumerate(self.ch_names): - # texts.append(self.axes.text(-0.03,1-(ind+1)/(len(self.ch_names)+1), - # name, transform=self.axes.transAxes, color='r', fontsize=13)) self.button1 = QPushButton("&Settings") self.button1.setCheckable(False) @@ -1416,8 +1364,3 @@ if __name__ == '__main__': form = First_window(AppForm) #AppForm() form.show() sys.exit(app.exec_()) - -# cut time different from both sides -# some deafult settings. Maybe remember last configuration? -# EMG and EOG - none, more than one? -# change names to final names \ No newline at end of file