def update_loop(self): # Sharing variable to stop at the GUI level if not self.state.value: logger.info('Viewer stopped') sys.exit() try: # assert self.updating==False, 'thread destroyed?' # self.updating= True # self.handle_tobiid_input() # Read TiDs self.read_eeg() # Read new chunk if len(self.ts_list) > 0: self.filter_signal() # Filter acquired data self.update_ringbuffers() # Update the plotting infor if (not self.stop_plot): self.repaint() # Call paint event except: logger.exception('Exception. Dropping into a shell.') pdb.set_trace() finally: # self.updating= False # using singleShot instead # QtCore.QTimer.singleShot( 20, self.update_loop ) pass
def debug_info(type, value, tb): if hasattr( sys, 'ps1') or not sys.stderr.isatty() or type == KeyboardInterrupt: # interactive mode or no tty-like device sys.__excepthook__(type, value, tb) else: # non-interactive mode logger.exception() pdb.pm()
def read_eeg(self): # if self.updating==True: print( '##### ERROR: thread destroyed ? ######' ) # self.updating= True try: # data, self.ts_list= self.sr.inlets[0].pull_chunk(max_samples=self.config['sf']) # [frames][channels] data, self.ts_list = self.sr.acquire(blocking=False) # TODO: check and change to these two lines #self.sr.acquire(blocking=False, decim=DECIM) #data, self.ts_list = self.sr.get_window() if len(self.ts_list) == 0: # self.eeg= None # self.tri= None return n = self.config['eeg_channels'] ''' x= np.array( data ) trg_ch= self.config['tri_channels'] if trg_ch is not None: self.tri= np.reshape( x[:,trg_ch], (-1,1) ) # samples x 1 self.eeg= np.reshape( x[:,self.sr.eeg_channels], (-1,n) ) # samples x channels ''' trg_ch = self.config['tri_channels'] if trg_ch is not None: self.tri = np.reshape(data[:, trg_ch], (-1, 1)) # samples x 1 self.eeg = np.reshape(data[:, self.sr.eeg_channels], (-1, n)) # samples x channels if DEBUG_TRIGGER: # show trigger value try: trg_value = max(self.tri) if trg_value > 0: logger.info('Received trigger %s' % trg_value) except: logger.exception('Error! self.tri = %s' % self.tri) # Read exg. self.config.samples*self.config.exg_ch, type float # bexg = np.random.rand( 1, self.config['samples'] * self.config['exg_channels'] ) # self.exg = np.reshape(list(bexg), (self.config['samples'],self.config['exg_channels'])) except WindowsError: # print('**** Access violation in read_eeg():\n%s\n%s'% (sys.exc_info()[0], sys.exc_info()[1])) pass except: logger.exception() pdb.set_trace()
def get_buffer(self): """ Returns the entire buffer: samples x channels If multiple amps, signals are concatenated along the channel axis. """ self.check_connect() try: if len(self.timestamps[0]) > 0: w = np.concatenate(self.buffers, axis=1) # samples x channels t = np.array(self.timestamps).reshape(-1, 1) # samples x 1 return w, t else: return np.array([]), np.array([]) except: logger.exception('Sorry! Unexpected error occurred in get_buffer(). Dropping into a shell for debugging.') pdb.pm()
def update_loop(self): ''' Main update function (connected to the timer) ''' # Sharing variable to stop at the GUI level if not self.state.value: logger.info('Viewer stopped') sys.exit() try: self.read_eeg() # Read new chunk if len(self.ts_list) > 0: self.filter_signal() # Filter acquired data self.update_ringbuffers() # Update the plotting infor if (not self.stop_plot): self.repaint() # Call paint event except: logger.exception('Exception. Dropping into a shell.') pdb.set_trace()
def read_eeg(self): ''' Read EEG ''' try: data, self.ts_list = self.sr.acquire(blocking=False) # TODO: check and change to these two lines #self.sr.acquire(blocking=False, decim=DECIM) #data, self.ts_list = self.sr.get_window() if len(self.ts_list) == 0: # self.eeg= None # self.tri= None return n = self.config['eeg_channels'] trg_ch = self.config['tri_channels'] if trg_ch is not None: self.tri = np.reshape(data[:, trg_ch], (-1, 1)) # samples x 1 self.eeg = np.reshape(data[:, self.sr.eeg_channels], (-1, n)) # samples x channels if DEBUG_TRIGGER: # show trigger value try: trg_value = max(self.tri) if trg_value > 0: logger.info('Received trigger %s' % trg_value) except: logger.exception('Error! self.tri = %s' % self.tri) except WindowsError: # print('**** Access violation in read_eeg():\n%s\n%s'% (sys.exc_info()[0], sys.exc_info()[1])) pass except: logger.exception() pdb.set_trace()
def raw2psd(rawfile=None, fmin=1, fmax=40, wlen=0.5, wstep=1, tmin=0.0, tmax=None, channel_picks=None, excludes=[], n_jobs=1): """ Compute PSD features over a sliding window on the entire raw file. Leading edge of the window is the time reference, i.e. do not use future data. Input ===== rawfile: fif file. channel_picks: None or list of channel names tmin (sec): start time of the PSD window relative to the event onset. tmax (sec): end time of the PSD window relative to the event onset. None = until the end. fmin (Hz): minimum PSD frequency fmax (Hz): maximum PSD frequency wlen (sec): sliding window length for computing PSD (sec) wstep (int): sliding window step (time samples) excludes (list): list of channels to exclude """ raw, eve = pu.load_raw(rawfile) sfreq = raw.info['sfreq'] wframes = int(round(sfreq * wlen)) raw_eeg = raw.pick_types(meg=False, eeg=True, stim=False, exclude=excludes) if channel_picks is None: rawdata = raw_eeg._data chlist = raw.ch_names else: chlist = [] for ch in channel_picks: chlist.append(raw.ch_names.index(ch)) rawdata = raw_eeg._data[np.array(chlist)] if tmax is None: t_end = rawdata.shape[1] else: t_end = int(round(tmax * sfreq)) t_start = int(round(tmin * sfreq)) + wframes psde = mne.decoding.PSDEstimator(sfreq, fmin=fmin, fmax=fmax, n_jobs=1,\ bandwidth=None, low_bias=True, adaptive=False, normalization='length', verbose=None) print('[PID %d] %s' % (os.getpid(), rawfile)) psd_all = [] evelist = [] times = [] t_len = t_end - t_start last_eve = 0 y_i = 0 t_last = t_start tm = qc.Timer() for t in range(t_start, t_end, wstep): # compute PSD window = rawdata[:, t - wframes:t] psd = psde.transform( window.reshape((1, window.shape[0], window.shape[1]))) psd = psd.reshape(psd.shape[1], psd.shape[2]) psd_all.append(psd) times.append(t) # matching events at the current window if y_i < eve.shape[0] and t >= eve[y_i][0]: last_eve = eve[y_i][2] y_i += 1 evelist.append(last_eve) if tm.sec() >= 1: perc = (t - t_start) / t_len fps = (t - t_last) / wstep est = (t_end - t) / wstep / fps logger.info('[PID %d] %.1f%% (%.1f FPS, %ds left)' % (os.getpid(), perc * 100.0, fps, est)) t_last = t tm.reset() logger.info('Finished.') # export data try: chnames = [raw.ch_names[ch] for ch in chlist] psd_all = np.array(psd_all) [basedir, fname, fext] = qc.parse_path_list(rawfile) fout_header = '%s/psd-%s-header.pkl' % (basedir, fname) fout_psd = '%s/psd-%s-data.npy' % (basedir, fname) header = { 'psdfile': fout_psd, 'times': np.array(times), 'sfreq': sfreq, 'channels': chnames, 'wframes': wframes, 'events': evelist } qc.save_obj(fout_header, header) np.save(fout_psd, psd_all) logger.info('Exported to:\n(header) %s\n(numpy array) %s' % (fout_header, fout_psd)) except: logger.exception('(%s) Unexpected error occurred while exporting data. Dropping you into a shell for recovery.' %\ os.path.basename(__file__)) embed()
def compute_features(cfg): ''' Compute features using config specification. Performs preprocessing, epcoching and feature computation. Input ===== Config file object Output ====== Feature data in dictionary - X_data: feature vectors - Y_data: feature labels - wlen: window length in seconds - w_frames: window length in frames - psde: MNE PSD estimator object - picks: channels used for feature computation - sfreq: sampling frequency - ch_names: channel names - times: feature timestamp (leading edge of a window) ''' # Preprocessing, epoching and PSD computation ftrain = [] for f in qc.get_file_list(cfg.DATA_PATH, fullpath=True): if f[-4:] in ['.fif', '.fiff']: ftrain.append(f) if len(ftrain) > 1 and cfg.PICKED_CHANNELS is not None and type( cfg.PICKED_CHANNELS[0]) == int: logger.error( 'When loading multiple EEG files, PICKED_CHANNELS must be list of string, not integers because they may have different channel order.' ) raise RuntimeError raw, events = pu.load_multi(ftrain) reref = cfg.REREFERENCE[cfg.REREFERENCE['selected']] if reref is not None: pu.rereference(raw, reref['New'], reref['Old']) if cfg.LOAD_EVENTS[cfg.LOAD_EVENTS['selected']] is not None: events = mne.read_events(cfg.LOAD_EVENTS[cfg.LOAD_EVENTS['selected']]) trigger_def_int = set() for a in cfg.TRIGGER_DEF: trigger_def_int.add(getattr(cfg.tdef, a)) triggers = {cfg.tdef.by_value[c]: c for c in trigger_def_int} # Pick channels if cfg.PICKED_CHANNELS is None: chlist = [int(x) for x in pick_types(raw.info, stim=False, eeg=True)] else: chlist = cfg.PICKED_CHANNELS picks = [] for c in chlist: if type(c) == int: picks.append(c) elif type(c) == str: picks.append(raw.ch_names.index(c)) else: logger.error( 'PICKED_CHANNELS has a value of unknown type %s.\nPICKED_CHANNELS=%s' % (type(c), cfg.PICKED_CHANNELS)) raise RuntimeError if cfg.EXCLUDED_CHANNELS is not None: for c in cfg.EXCLUDED_CHANNELS: if type(c) == str: if c not in raw.ch_names: logger.warning( 'Exclusion channel %s does not exist. Ignored.' % c) continue c_int = raw.ch_names.index(c) elif type(c) == int: c_int = c else: logger.error( 'EXCLUDED_CHANNELS has a value of unknown type %s.\nEXCLUDED_CHANNELS=%s' % (type(c), cfg.EXCLUDED_CHANNELS)) raise RuntimeError if c_int in picks: del picks[picks.index(c_int)] if max(picks) > len(raw.ch_names): logger.error( '"picks" has a channel index %d while there are only %d channels.' % (max(picks), len(raw.ch_names))) raise ValueError if hasattr(cfg, 'SP_CHANNELS') and cfg.SP_CHANNELS is not None: logger.warning( 'SP_CHANNELS parameter is not supported yet. Will be set to PICKED_CHANNELS.' ) if hasattr(cfg, 'TP_CHANNELS') and cfg.TP_CHANNELS is not None: logger.warning( 'TP_CHANNELS parameter is not supported yet. Will be set to PICKED_CHANNELS.' ) if hasattr(cfg, 'NOTCH_CHANNELS') and cfg.NOTCH_CHANNELS is not None: logger.warning( 'NOTCH_CHANNELS parameter is not supported yet. Will be set to PICKED_CHANNELS.' ) if 'decim' not in cfg.FEATURES['PSD']: cfg.FEATURES['PSD']['decim'] = 1 logger.warning('PSD["decim"] undefined. Set to 1.') # Read epochs try: # Experimental: multiple epoch ranges if type(cfg.EPOCH[0]) is list: epochs_train = [] for ep in cfg.EPOCH: epoch = Epochs(raw, events, triggers, tmin=ep[0], tmax=ep[1], proj=False, picks=picks, baseline=None, preload=True, verbose=False, detrend=None) epochs_train.append(epoch) else: # Usual method: single epoch range epochs_train = Epochs(raw, events, triggers, tmin=cfg.EPOCH[0], tmax=cfg.EPOCH[1], proj=False, picks=picks, baseline=None, preload=True, verbose=False, detrend=None, on_missing='warning') except: logger.exception('Problem while epoching.') raise RuntimeError label_set = np.unique(triggers.values()) # Compute features if cfg.FEATURES['selected'] == 'PSD': preprocess = dict(sfreq=epochs_train.info['sfreq'], spatial=cfg.SP_FILTER, spatial_ch=None, spectral=cfg.TP_FILTER[cfg.TP_FILTER['selected']], spectral_ch=None, notch=cfg.NOTCH_FILTER[cfg.NOTCH_FILTER['selected']], notch_ch=None, multiplier=cfg.MULTIPLIER, ch_names=None, rereference=None, decim=cfg.FEATURES['PSD']['decim'], n_jobs=cfg.N_JOBS) featdata = get_psd_feature(epochs_train, cfg.EPOCH, cfg.FEATURES['PSD'], picks=None, preprocess=preprocess, n_jobs=cfg.N_JOBS) elif cfg.FEATURES == 'TIMELAG': ''' TODO: Implement multiple epochs for timelag feature ''' logger.error( 'MULTIPLE EPOCHS NOT IMPLEMENTED YET FOR TIMELAG FEATURE.') raise NotImplementedError elif cfg.FEATURES == 'WAVELET': ''' TODO: Implement multiple epochs for wavelet feature ''' logger.error( 'MULTIPLE EPOCHS NOT IMPLEMENTED YET FOR WAVELET FEATURE.') raise NotImplementedError else: logger.error('%s feature type is not supported.' % cfg.FEATURES) raise NotImplementedError featdata['picks'] = picks featdata['sfreq'] = raw.info['sfreq'] featdata['ch_names'] = raw.ch_names return featdata