def rereference(raw, ref_new, ref_old=None): """ Reference to new channels. raw object is modified in-place for efficiency. raw: mne.io.RawArray ref_new: None | list of str (RawArray) | list of int (numpy array) Channel(s) to re-reference, e.g. M1, M2. Average of these channel values are substracted from all channel values. ref_old: None | str Channel to recover, assuming this channel was originally used as a reference. """ # Re-reference and recover the original reference channel values if possible if type(raw) == np.ndarray: if raw_ch_old is not None: logger.error('Recovering original reference channel is not yet supported for numpy arrays.') raise NotImplementedError if type(raw_ch_new[0]) is not int: logger.error('Channels must be integer values for numpy arrays') raise ValueError raw -= np.mean(raw[ref_new], axis=0) else: if ref_old is not None: # Add a blank (zero-valued) channel mne.io.add_reference_channels(raw, ref_old, copy=False) # Re-reference mne.io.set_eeg_reference(raw, ref_new, copy=False) return True
def get_decoder_info(classifier): """ Get the classifier information from a .pkl file. Parameters ---------- classifier : str The (absolute) path to the classifier file (.pkl) Returns ------- dict : Classifier info """ with open(classifier, 'rb') as f: model = pickle.load(f) if model is None: logger.error('>> Error loading %s' % model) raise ValueError cls = model['cls'] psde = model['psde'] labels = list(cls.classes_) w_seconds = model['w_seconds'] w_frames = model['w_frames'] wstep = model['wstep'] sfreq = model['sfreq'] psd_temp = psde.transform(np.zeros((1, len(model['picks']), w_frames))) psd_shape = psd_temp.shape psd_size = psd_temp.size info = dict(labels=labels, cls=cls, psde=psde, w_seconds=w_seconds, w_frames=w_frames,\ wstep=wstep, sfreq=sfreq, psd_shape=psd_shape, psd_size=psd_size) return info
def check_config(cfg): """ Ensure that the config file contains the parameters """ critical_vars = { 'COMMON': [ 'TRIGGER_DEVICE', 'TRIGGER_FILE', 'SCREEN_SIZE', 'START_VOICE', 'END_VOICE' ], } optional_vars = { 'GLOBAL_TIME': 2 * 60, 'SCREEN_POS': (0, 0), 'GLASS_USE': False, } for key in critical_vars['COMMON']: if not hasattr(cfg, key): logger.error('%s is a required parameter' % key) raise RuntimeError for key in optional_vars: if not hasattr(cfg, key): setattr(cfg, key, optional_vars[key]) logger.warning('Setting undefined parameter %s=%s' % (key, getattr(cfg, key)))
def move(self, dir, dx, overlay=False, barcolor=None, caption='', caption_color='W'): if barcolor is None: if dx == self.xl2: c = 'G' else: c = 'R' else: c = barcolor self.glass.fullbar_color(c) color = self.color[c] if dir == 'L': if self.pc_feedback: self.img = self.left_images[dx] if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) elif dir == 'R': if self.pc_feedback: self.img = self.right_images[dx] if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) else: logger.error('Unknown direction %s' % dir) self.put_text(caption, caption_color) self.update()
def any2fif(filename, interactive=False, outdir=None, channel_file=None): """ Generic file format converter """ p = qc.parse_path(filename) if outdir is not None: qc.make_dirs(outdir) if p.ext == 'pcl': eve_file = '%s/%s.txt' % (p.dir, p.name.replace('raw', 'eve')) if os.path.exists(eve_file): logger.info('Adding events from %s' % eve_file) else: eve_file = None pcl2fif(filename, interactive=interactive, outdir=outdir, external_event=eve_file) elif p.ext == 'eeg': eeg2fif(filename, interactive=interactive, outdir=outdir) elif p.ext in ['edf', 'bdf']: bdf2fif(filename, interactive=interactive, outdir=outdir) elif p.ext == 'gdf': gdf2fif(filename, interactive=interactive, outdir=outdir, channel_file=channel_file) elif p.ext == 'xdf': xdf2fif(filename, interactive=interactive, outdir=outdir) else: # unknown format logger.error( 'Ignored unrecognized file extension %s. It should be [.pcl | .eeg | .gdf | .bdf]' % p.ext)
def _check_cfg_selected(cfg, optional_vars, select): """ Used in case of dict attributes containing subparams Check that the selected cfg params is valid and that its subparameters are defined. Parameters ---------- cfg : python.module The config module containing the parameters to check optional_vars : The optional parameters with predefined values for the param selected = the cfg parameter (type=dict) containing a key: selected """ param = getattr(cfg, select) selected = param['selected'] if selected not in param: logger.error('%s not defined in config.' % selected) raise RuntimeError for v, vv in optional_vars[selected].items(): if v not in param[selected]: param[selected].update({v: vv}) setattr(cfg, select, param) logger.warning( 'Updating internal parameter for classifier %s: %s=%s' % (selected, v, vv))
def get_timelags(epochs, wlen, wstep, downsample=1, picks=None): """ (DEPRECATED FUNCTION) Get concatenated timelag features TODO: Unit test. Input ===== epochs: input signals wlen: window length (# time points) in downsampled data wstep: window step in downsampled data downsample: downsample signal to be 1/downsample length picks: ignored for now Output ====== X: [epochs] x [windows] x [channels*freqs] y: [epochs] x [labels] """ ''' wlen = int(wlen) wstep = int(wstep) downsample = int(downsample) X_data = None y_data = None labels = epochs.events[:, -1] # every epoch must have event id epochs_data = epochs.get_data() n_channels = epochs_data.shape[1] # trim to the nearest divisible length epoch_ds_len = int(epochs_data.shape[2] / downsample) epoch_len = downsample * epoch_ds_len range_epochs = np.arange(epochs_data.shape[0]) range_channels = np.arange(epochs_data.shape[1]) range_windows = np.arange(epoch_ds_len - wlen, 0, -wstep) X_data = np.zeros((len(range_epochs), len(range_windows), wlen * n_channels)) # for each epoch for ep in range_epochs: epoch = epochs_data[ep, :, :epoch_len] ds = qc.average_every_n(epoch.reshape(-1), downsample) # flatten to 1-D, then downsample epoch_ds = ds.reshape(n_channels, -1) # recover structure to channel x samples # for each window over all channels for i in range(len(range_windows)): w = range_windows[i] X = epoch_ds[:, w:w + wlen].reshape(1, -1) # our feature vector X_data[ep, i, :] = X # fill labels y = np.empty((1, len(range_windows))) # 1 x windows y.fill(labels[ep]) if y_data is None: y_data = y else: y_data = np.concatenate((y_data, y), axis=0) return X_data, y_data ''' logger.error('This function is deprecated.') raise NotImplementedError
def lsl_channel_list(inlet): """ Reads XML description of LSL header and returns channel list Input: pylsl.StreamInlet object Returns: ch_list: [ name1, name2, ... ] """ if not type(inlet) is pylsl.StreamInlet: logger.error('lsl_channel_list(): wrong input type %s' % type(inlet)) raise TypeError root = ET.fromstring(inlet.info().as_xml()) desc = root.find('desc') ch_list = [] for ch in desc.find('channels').getchildren(): ch_name = ch.find('label').text ch_list.append(ch_name) ''' This code may throw access violation error due to bug in pylsl.XMLElement # for some reason type(inlet) returns 'instance' type in Python 2. ch = inlet.info().desc().child('channels').first_child() ch_list = [] for k in range(inlet.info().channel_count()): ch_name = ch.child_value('label') ch_list.append(ch_name) ch = ch.next_sibling() ''' return ch_list
def get_index_max(seq): if type(seq) == list: return max(range(len(seq)), key=seq.__getitem__) elif type(seq) == dict: return max(seq, key=seq.__getitem__) else: logger.error('Unsupported input %s' % type(seq)) return None
def check_connect(self): """ Check connection and automatically connect if not connected """ while not self.connected: logger.error('LSL server not connected yet. Trying to connect automatically.') self.connect() time.sleep(1)
def fit_predict_thres(cls, X_train, Y_train, X_test, Y_test, cnum, label_list, ignore_thres=None, decision_thres=None): """ Any likelihood lower than a threshold is not counted as classification score Confusion matrix, accuracy and F1 score (macro average) are computed. Params ====== ignore_thres: if not None or larger than 0, likelihood values lower than ignore_thres will be ignored while computing confusion matrix. """ timer = qc.Timer() cls.fit(X_train, Y_train) assert ignore_thres is None or ignore_thres >= 0 if ignore_thres is None or ignore_thres == 0: Y_pred = cls.predict(X_test) score = skmetrics.accuracy_score(Y_test, Y_pred) cm = skmetrics.confusion_matrix(Y_test, Y_pred, label_list) f1 = skmetrics.f1_score(Y_test, Y_pred, average='macro') else: if decision_thres is not None: logger.error( 'decision threshold and ignore_thres cannot be set at the same time.' ) raise ValueError Y_pred = cls.predict_proba(X_test) Y_pred_labels = np.argmax(Y_pred, axis=1) Y_pred_maxes = np.array([x[i] for i, x in zip(Y_pred_labels, Y_pred)]) Y_index_overthres = np.where(Y_pred_maxes >= ignore_thres)[0] Y_index_underthres = np.where(Y_pred_maxes < ignore_thres)[0] Y_pred_overthres = np.array( [cls.classes_[x] for x in Y_pred_labels[Y_index_overthres]]) Y_pred_underthres = np.array( [cls.classes_[x] for x in Y_pred_labels[Y_index_underthres]]) Y_pred_underthres_count = np.array( [np.count_nonzero(Y_pred_underthres == c) for c in label_list]) Y_test_overthres = Y_test[Y_index_overthres] score = skmetrics.accuracy_score(Y_test_overthres, Y_pred_overthres) cm = skmetrics.confusion_matrix(Y_test_overthres, Y_pred_overthres, label_list) cm = np.concatenate((cm, Y_pred_underthres_count[:, np.newaxis]), axis=1) f1 = skmetrics.f1_score(Y_test_overthres, Y_pred_overthres, average='macro') logger.info('Cross-validation %d (%.3f) - %.1f sec' % (cnum, score, timer.sec())) return score, cm, f1
def run(cfg, state=mp.Value('i', 1), queue=None, logger=logger): ''' Main function used to run the offline protocol. Parameters ---------- cfg : python.module The loaded config module from the corresponding config_offline.py queue : mp.Queue If not None, redirect sys.stdout to GUI terminal logger : logging.logger The logger to use ''' # Use to redirect sys.stdout to GUI terminal if GUI usage redirect_stdout_to_queue(logger, queue, 'INFO') # Wait the recording to start (GUI) while state.value == 2: # 0: stop, 1:start, 2:wait pass # Protocol start if equals to 1 if not state.value: sys.exit() # Load the mapping from int to string for triggers events cfg.tdef = TriggerDef(cfg.TRIGGER_FILE) # Refresh rate refresh_delay = 1.0 / cfg.REFRESH_RATE # Trigger trigger = Trigger(lpttype=cfg.TRIGGER_DEVICE, state=state) if trigger.init(50) == False: logger.error( '\n** Error connecting to the trigger device. Use a mock trigger instead?' ) input('Press Ctrl+C to stop or Enter to continue.') trigger = Trigger(lpttype='FAKE') trigger.init(50) # timers timer_refresh = Timer() trial = 1 num_trials = cfg.TRIALS_NB # start while trial <= num_trials: timer_refresh.sleep_atleast(refresh_delay) timer_refresh.reset() #------------------------------------- # ADD YOUR CODE HERE #------------------------------------- with state.get_lock(): state.value = 0
def set_pin(self, pin): if self.lpttype == 'SOFTWARE': logger.error('set_pin() not supported for software trigger.') return False elif self.lpttype == 'FAKE': logger.info('FAKE trigger pin %s' % pin) return True else: self.set_data(2**(pin - 1))
def balance_samples(X, Y, balance_type, verbose=False): if balance_type == 'OVER': """ Oversample from classes that lack samples """ label_set = np.unique(Y) max_set = [] X_balanced = np.array(X) Y_balanced = np.array(Y) # find a class with maximum number of samples for c in label_set: yl = np.where(Y == c)[0] if len(max_set) == 0 or len(yl) > max_set[1]: max_set = [c, len(yl)] for c in label_set: if c == max_set[0]: continue yl = np.where(Y == c)[0] extra_samples = max_set[1] - len(yl) extra_idx = np.random.choice(yl, extra_samples) X_balanced = np.append(X_balanced, X[extra_idx], axis=0) Y_balanced = np.append(Y_balanced, Y[extra_idx], axis=0) elif balance_type == 'UNDER': """ Undersample from classes that are excessive """ label_set = np.unique(Y) min_set = [] # find a class with minimum number of samples for c in label_set: yl = np.where(Y == c)[0] if len(min_set) == 0 or len(yl) < min_set[1]: min_set = [c, len(yl)] yl = np.where(Y == min_set[0])[0] X_balanced = np.array(X[yl]) Y_balanced = np.array(Y[yl]) for c in label_set: if c == min_set[0]: continue yl = np.where(Y == c)[0] reduced_idx = np.random.choice(yl, min_set[1]) X_balanced = np.append(X_balanced, X[reduced_idx], axis=0) Y_balanced = np.append(Y_balanced, Y[reduced_idx], axis=0) elif balance_type is None or balance_type is False: return X, Y else: logger.error('Unknown balancing type %s' % balance_type) raise ValueError logger.info_green('\nNumber of samples after %ssampling' % balance_type.lower()) for c in label_set: logger.info( '%s: %d -> %d' % (c, len(np.where(Y == c)[0]), len(np.where(Y_balanced == c)[0]))) return X_balanced, Y_balanced
def move(self, dir, dx, overlay=False, barcolor=None, caption='', caption_color='W'): if not overlay: self.draw_cue() if barcolor is None: if dx == self.xl2: c = 'G' else: c = 'R' else: c = barcolor self.glass.fullbar_color(c) color = self.color[c] if dir == 'L': if self.pc_feedback: cv2.rectangle(self.img, (self.xl1 - dx, self.yl1), (self.xl1, self.yr1), color, -1) if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) elif dir == 'U': if self.pc_feedback: cv2.rectangle(self.img, (self.xl1, self.yl1 - dx), (self.xr1, self.yl1), color, -1) if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) elif dir == 'R': if self.pc_feedback: cv2.rectangle(self.img, (self.xr1, self.yl1), (self.xr1 + dx, self.yr1), color, -1) if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) elif dir == 'D': if self.pc_feedback: cv2.rectangle(self.img, (self.xl1, self.yr1), (self.xr1, self.yr1 + dx), color, -1) if self.glass_feedback: self.glass.move_bar(dir, dx, overlay) elif dir == 'B': if self.pc_feedback: cv2.rectangle(self.img, (self.xl1 - dx, self.yl1), (self.xl1, self.yr1), color, -1) cv2.rectangle(self.img, (self.xr1, self.yl1), (self.xr1 + dx, self.yr1), color, -1) if self.glass_feedback: self.glass.move_bar('S', dx, overlay) else: logger.error('Unknown direction %s' % dir) self.put_text(caption, caption_color)
def get_index_max(seq): """ Get the index of the maximum item in a list or dict """ if type(seq) == list: return max(range(len(seq)), key=seq.__getitem__) elif type(seq) == dict: return max(seq, key=seq.__getitem__) else: logger.error('Unsupported input %s' % type(seq)) return None
def move(self, dir, dx, overlay=False, barcolor=None, caption='', caption_color='W'): #if barcolor is None: #if dx == self.xl2: #c = 'G' #else: #c = 'R' #else: #c = barcolor #color = self.color[c] if dir == 'L': if self.pc_feedback: if barcolor is None: color = ((dx/100) * self.color['B'][0], self.color['B'][1], self.color['B'][2]) else: color = self.color[barcolor] # color = ((dx/100) * self.color['B'][0], self.color['B'][1], self.color['B'][2]) # color = ((dx/100) * color[0], color[1], color[2]) cv2.circle(self.img, (self.cx, self.cy), int(self.cx/8) - int(self.outerRadiusThickness-2), color, -1) # self.draw_fixation_cross() if not overlay: self.draw_cue(self.actual_cue) elif dir == 'R': if self.pc_feedback: if barcolor is None: color = (self.color['R'][0], self.color['R'][1], (dx/100) * self.color['R'][2]) else: color = self.color[barcolor] # color = (color[0], color[1], (dx/100) * color[2]) # color = (self.color['R'][0], self.color['R'][1], (dx/100) * self.color['R'][2]) cv2.circle(self.img, (self.cx, self.cy), int(self.cx/8) - int(self.outerRadiusThickness-2), color, -1) # self.draw_fixation_cross() if not overlay: self.draw_cue(self.actual_cue) #elif dir == 'U': #if self.pc_feedback:tas #color = (self.color['R'][0], self.color['R'][1], (dx/100) * self.color['R'][2]) #cv2.circle(self.img, (self.cx, self.cy), int(self.cx/8), color, -1) #self.draw_fixation_cross() #elif dir == 'D': #if self.pc_feedback: #color = (self.color['R'][0], self.color['R'][1], (dx/100) * self.color['R'][2]) #cv2.circle(self.img, (self.cx, self.cy), int(self.cx/8), color, -1) #self.draw_fixation_cross() else: logger.error('Unknown direction %s' % dir) self.put_text(caption, caption_color)
def check_cfg_mandatory(cfg, critical_vars, key_var): """ Check that the mandatory parameters are defined cfg = config module containing the parameters to check critical_vars = critival parameters needed for the protocol key_var = key to look at in critical_vars """ for v in critical_vars[key_var]: if not hasattr(cfg, v): logger.error('%s not defined in config.' % v) raise RuntimeError
def reset(self): """ Reset the classifier to its initial state. """ # share numpy array self.psd between processes. # to compute the shared memory size, we need to create a temporary decoder object. if self.fake == True: psd_size = None psd_shape = None psd_ctypes = None self.psd = None else: info = get_decoder_info(self.classifier) psd_size = info['psd_size'] psd_shape = info['psd_shape'][1:] # we get only the last window psd_ctypes = sharedctypes.RawArray('d', np.zeros(psd_size)) self.psd = np.frombuffer(psd_ctypes, dtype=np.float64, count=psd_size) self.probs = mp.Array('d', [1.0 / len(self.labels)] * len(self.labels)) self.probs_smooth = mp.Array('d', [1.0 / len(self.labels)] * len(self.labels)) self.pread = mp.Value('i', 1) self.t_problast = mp.Value('d', 0) self.return_psd = mp.Value('i', 0) self.procs = [] mp.freeze_support() if self.parallel: logger.error( 'Parallel decoding is under a rigorous test. Please do not use it for now.' ) raise NotImplementedError num_strides = self.parallel['num_strides'] period = self.parallel['period'] self.running = [mp.Value('i', 0)] * num_strides if num_strides > 1: stride = period / num_strides else: stride = 0 t_start = time.time() for i in range(num_strides): self.procs.append(mp.Process(target=self._daemon, args=\ [self.classifier, self.probs, self.probs_smooth, self.pread, self.t_problast,\ self.running[i], self.return_psd, psd_ctypes, self.psdlock,\ dict(t_start=(t_start+i*stride), period=period), self.label])) else: self.running = [mp.Value('i', 0)] self.procs = [mp.Process(target=self._daemon, args=\ [self.classifier, self.probs, self.probs_smooth, self.pread, self.t_problast,\ self.running[0], self.return_psd, psd_ctypes, self.psdlock, None, self.label])]
def make_dirs(dirname, delete=False): """ Recusively create directories. if delete=true, directory will be deleted first if exists. """ if os.path.exists(dirname) and delete == True: try: shutil.rmtree(dirname) except OSError: logger.error( 'Directory was not completely removed. (Perhaps a Dropbox folder?). Continuing.' ) if not os.path.exists(dirname): os.makedirs(dirname)
def load_raw(rawfile, spfilter=None, spchannels=None, events_ext=None, multiplier=1, verbose='ERROR'): """ Loads data from a fif-format file. You can convert non-fif files (.eeg, .bdf, .gdf, .pcl) to fif format. Parameters: rawfile: (absolute) data file path spfilter: 'car' | 'laplacian' | None spchannels: None | list (for CAR) | dict (for LAPLACIAN) 'car': channel indices used for CAR filtering. If None, use all channels except the trigger channel (index 0). 'laplacian': {channel:[neighbor1, neighbor2, ...], ...} *** Note *** Since neurodecode puts trigger channel as index 0, data channel starts from index 1. events_ext: Add externally recorded events. [ [sample_index1, 0, event_value1],... ] multiplier: Multiply all values except triggers (to convert unit). Returns: raw: mne.io.RawArray object. First channel (index 0) is always trigger channel. events: mne-compatible events numpy array object (N x [frame, 0, type]) spfilter= {None | 'car' | 'laplacian'} """ if not os.path.exists(rawfile): logger.error('File %s not found' % rawfile) raise IOError if not os.path.isfile(rawfile): logger.error('%s is not a file' % rawfile) raise IOError extension = qc.parse_path(rawfile).ext assert extension in ['fif', 'fiff'], 'only fif format is supported' raw = mne.io.Raw(rawfile, preload=True, verbose=verbose) if spfilter is not None or multiplier is not 1: preprocess(raw, spatial=spfilter, spatial_ch=spchannels, multiplier=multiplier) if events_ext is not None: events = mne.read_events(events_ext) else: tch = find_event_channel(raw) if tch is not None: events = mne.find_events(raw, stim_channel=raw.ch_names[tch], shortest_event=1, uint_cast=True, consecutive='increasing') # MNE's annoying hidden cockroach: first_samp events[:, 0] -= raw.first_samp else: events = np.array([], dtype=np.int64) return raw, events
def convert2mat(filename, matfile): """ Convert to mat using MATLAB BioSig sload(). """ basename = '.'.join(filename.split('.')[:-1]) # extension= filename.split('.')[-1] matfile = basename + '.mat' if not os.path.exists(matfile): logger.info('Converting input to mat file') run = "[sig,header]=sload('%s'); save('%s.mat','sig','header');" % ( filename, basename) qc.matlab(run) if not os.path.exists(matfile): logger.error('mat file convertion error.') sys.exit()
def set_data(self, value): if self.lpttype == 'SOFTWARE': logger.error('set_data() not supported for software trigger.') return False elif self.lpttype == 'FAKE': logger.info('FAKE trigger value %s' % value) return True else: if self.lpttype == 'USB2LPT': self.lpt.setdata(value) elif self.lpttype == 'DESKTOP': self.lpt.setdata(self.portaddr, value) elif self.lpttype == 'ARDUINO': self.ser.write(bytes([value])) else: raise RuntimeError('Wrong trigger device')
def start(self): """ Start the daemon """ if self.is_running() > 0: msg = 'Cannot start. Daemon already running. (PID' + ', '.join( ['%d' % proc.pid for proc in self.procs]) + ')' logger.error(msg) return for proc in self.procs: proc.start() if self.wait_init: for running in self.running: while running.value == 0: time.sleep(0.001) logger.info(self.startmsg)
def check_config(cfg): critical_vars = { 'COMMON': [ 'TRIGGER_DEVICE', 'TRIGGER_FILE', 'SCREEN_SIZE', 'DIRECTIONS', 'DIR_RANDOM', 'TRIALS_EACH' ], 'TIMINGS': [ 'INIT', 'GAP', 'CUE', 'READY', 'READY_RANDOMIZE', 'DIR', 'DIR_RANDOMIZE' ] } optional_vars = { 'FEEDBACK_TYPE': 'BAR', 'FEEDBACK_IMAGE_PATH': None, 'SCREEN_POS': (0, 0), 'DIR_RANDOM': True, 'GLASS_USE': False, 'TRIAL_PAUSE': False, 'REFRESH_RATE': 30 } for key in critical_vars['COMMON']: if not hasattr(cfg, key): raise RuntimeError('%s is a required parameter' % key) if not hasattr(cfg, 'TIMINGS'): logger.error('"TIMINGS" not defined in config.') raise RuntimeError for v in critical_vars['TIMINGS']: if v not in cfg.TIMINGS: logger.error('%s not defined in config.' % v) raise RuntimeError for key in optional_vars: if not hasattr(cfg, key): setattr(cfg, key, optional_vars[key]) logger.warning('Setting undefined %s=%s' % (key, optional[key])) if getattr(cfg, 'TRIGGER_DEVICE') == None: logger.warning( 'The trigger device is set to None! No events will be saved.') raise RuntimeError( 'The trigger device is set to None! No events will be saved.')
def bdf2fif(filename, interactive=False, outdir=None): """ EDF or BioSemi BDF format """ # convert to mat using MATLAB (MNE's edf reader has an offset bug) fdir, fname, fext = qc.parse_path_list(filename) if outdir is None: outdir = fdir elif outdir[-1] != '/': outdir += '/' fiffile = outdir + fname + '.fif' raw = mne.io.read_raw_edf(filename, preload=True) # process event channel if raw.info['chs'][-1]['ch_name'] != 'STI 014': logger.error( "The last channel (%s) doesn't seem to be an event channel. Entering debugging mode." % raw.info['chs'][-1]['ch_name']) pdb.set_trace() raw.info['chs'][-1]['ch_name'] = 'TRIGGER' events = mne.find_events(raw, stim_channel='TRIGGER', shortest_event=1, uint_cast=True, consecutive=True) events[:, 2] -= events[:, 1] # set offset to 0 events[:, 1] = 0 # move the event channel to index 0 (for consistency) raw._data = np.concatenate( (raw._data[-1, :].reshape(1, -1), raw._data[:-1, :])) raw._data[0] *= 0 # init the event channel raw.info['chs'] = [raw.info['chs'][-1]] + raw.info['chs'][:-1] # add events raw.add_events(events, 'TRIGGER') # save and close raw.save(fiffile, verbose=False, overwrite=True, fmt='double') logger.info('Saved to %s' % fiffile) saveChannels2txt(outdir, ch_names)
def init(self, duration): if self.lpttype == 'SOFTWARE': logger.info('Ignoring delay parameter for software trigger.') return True elif self.lpttype == 'FAKE': return True else: self.delay = duration / 1000.0 if self.lpttype in ['DESKTOP', 'USB2LPT']: if self.lpt.init() == -1: logger.error( 'Connecting to LPT port failed. Check the driver status.' ) self.lpt = None return False self.action = False self.offtimer = threading.Timer(self.delay, self.signal_off) return True
def check_config(cfg): """ Ensure that the config file contains the parameters """ critical_vars = { 'COMMON': ['DATA_PATH'], } optional_vars = { } for key in critical_vars['COMMON']: if not hasattr(cfg, key): logger.error('%s is a required parameter' % key) raise RuntimeError for key in optional_vars: if not hasattr(cfg, key): setattr(cfg, key, optional_vars[key]) logger.warning('Setting undefined parameter %s=%s' % (key, getattr(cfg, key))) return cfg
def print_c(msg, color=None, end='\n'): """ Colored print using colorama. Fullset: https://pypi.python.org/pypi/colorama Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Style: DIM, NORMAL, BRIGHT, RESET_ALL TODO: Make it using *args and **kwargs to support fully featured print(). """ if color is None: print(str(msg), end=end) return color = str(color) if len(color) != 1: raise ValueError( 'Color parameter must be a single color code, not %s' % type(color)) if color.upper() == 'B': c = colorama.Fore.BLUE elif color.upper() == 'R': c = colorama.Fore.RED elif color.upper() == 'G': c = colorama.Fore.GREEN elif color.upper() == 'Y': c = colorama.Fore.YELLOW elif color.upper() == 'W': c = colorama.Fore.WHITE elif color.upper() == 'C': c = colorama.Fore.CYAN else: logger.error('print_c(): Unknown color code %s' % color) raise ValueError print(colorama.Style.BRIGHT + c + str(msg) + colorama.Style.RESET_ALL, end=end)
def check_config(cfg): """ Ensure that the config file contains the parameters """ critical_vars = {'COMMON': ['DATA_PATH']} optional_vars = { 'AMP_NAME': None, 'AMP_SERIAL': None, 'GLOBAL_TIME': 1.0 * 60, 'NJOBS': 1, } for key in critical_vars['COMMON']: if not hasattr(cfg, key): logger.error('%s is a required parameter' % key) raise RuntimeError for key in optional_vars: if not hasattr(cfg, key): setattr(cfg, key, optional_vars[key]) logger.warning('Setting undefined parameter %s=%s' % (key, getattr(cfg, key)))