def event_timestamps_to_indices(sigfile, eventfile): """ Convert LSL timestamps to sample indices for separetely recorded events. Parameters: sigfile: raw signal file (Python Pickle) recorded with stream_recorder.py. eventfile: event file where events are indexed with LSL timestamps. Returns: events list, which can be used as an input to mne.io.RawArray.add_events(). """ raw= qc.load_obj(sigfile) ts= raw['timestamps'].reshape(-1) ts_min= min(ts) ts_max= max(ts) events= [] with open(eventfile) as f: for l in f: data= l.strip().split('\t') event_ts= float( data[0] ) event_value= int( data[2] ) # find the first index not smaller than ts next_index= np.searchsorted(ts, event_ts) if next_index >= len(ts): qc.print_c( '** WARNING: Event %d at time %.3f is out of time range (%.3f - %.3f).'% (event_value,event_ts,ts_min,ts_max), 'y' ) else: events.append( [next_index, 0, event_value] ) #print(events[-1]) return events
def search_lsl(ignore_markers=False): import pylsl, time # look for LSL servers amp_list = [] amp_list_backup = [] while True: streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, si in enumerate(streamInfos): amp_serial = pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() amp_name = si.name() if 'Markers' in amp_name: amp_list_backup.append((index, amp_name, amp_serial)) else: amp_list.append((index, amp_name, amp_serial)) break print('No server available yet on the network...') time.sleep(1) if ignore_markers is False: amp_list += amp_list_backup qc.print_c('-- List of servers --', 'W') for i, (index, amp_name, amp_serial) in enumerate(amp_list): if amp_serial == '': amp_ser = 'N/A' else: amp_ser = amp_serial qc.print_c('%d: %s (Serial %s)' % (i, amp_name, amp_ser), 'W') if len(amp_list) == 1: index = 0 dong = 0 else: dong = 1 index = raw_input( 'Amp index? Hit enter without index to select the first server.\n>> ' ).strip() index = int(index) # dong #amp_index, amp_name, amp_serial= [(0, u'g.USBamp-1',u'UB-2010.06.31')] #qc.shell() amp_index, amp_name, amp_serial = amp_list[index] #if dong == 1: #amp_index = 0 #print('!!!!!!!!!!!!!!!') si = streamInfos[amp_index] assert amp_name == si.name() assert amp_serial == pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() print('Selected %s (Serial: %s)' % (amp_name, amp_serial)) return amp_name, amp_serial
def load_raw(rawfile, spfilter=None, spchannels=None, events_ext=None, multiplier=1): if not os.path.exists(rawfile): qc.print_c('# ERROR: File %s not found'% rawfile, 'r') sys.exit(-1) extension= rawfile.split('.')[-1] assert extension in ['fif','fiff'], 'only fif format is supported' raw= mne.io.Raw(rawfile, preload=True) if 'TRIGGER' in raw.ch_names: tch_name= 'TRIGGER' elif 'STI ' in raw.ch_names: # e.g. 'STI 014' tch_name= 'STI ' elif 'Trig1' in raw.ch_names: tch_name = 'Trig1' else: raise RuntimeError, 'No trigger channel found.' # find a value changing from zero to a non-zero value tch= raw.ch_names.index(tch_name) events= mne.find_events(raw, stim_channel=tch_name, shortest_event=1, uint_cast=True) n_channels= raw._data.shape[0] eeg_channels= list(range(n_channels)) eeg_channels.pop(tch) if multiplier != 1: raw._data[eeg_channels] *= multiplier # apply spatial filter if spfilter=='car': if not spchannels: raw._data[eeg_channels]= raw._data[eeg_channels] - np.mean( raw._data[eeg_channels], axis=0 ) else: raw._data[spchannels]= raw._data[spchannels] - np.mean( raw._data[spchannels], axis=0 ) elif spfilter=='laplacian': if type(spchannels) is not dict: raise RuntimeError, 'For Lapcacian, SP_CHANNELS must be of a form {CHANNEL:[NEIGHBORS], ...}' rawcopy= raw._data.copy() for src in spchannels: nei= spchannels[src] raw._data[src]= rawcopy[src] - np.mean( rawcopy[nei], axis=0 ) elif spfilter=='bipolar': raw._data[1:] -= raw._data[spchannels] elif spfilter is None: pass else: qc.print_c('# ERROR: Unknown spatial filter', spfilter, 'r') sys.exit(-1) return raw, events
def init_loop(self): self.updating = False self.sr = StreamReceiver(window_size=1, buffer_size=10, amp_serial=self.amp_serial, amp_name=self.amp_name) srate = int(self.sr.sample_rate) #n_channels= self.sr.channels # 12 unsigned ints (4 bytes) ########## TODO: assumkng 32 samples chunk => make it read from LSL header data = [ 'EEG', srate, ['L', 'R'], 32, len(self.sr.get_eeg_channels()), 0, self.sr.get_trigger_channel(), None, None, None, None, None ] qc.print_c('Trigger channel is %d' % self.sr.get_trigger_channel(), 'G') self.config = { 'id': data[0], 'sf': data[1], 'labels': data[2], 'samples': data[3], 'eeg_channels': data[4], 'exg_channels': data[5], 'tri_channels': data[6], 'eeg_type': data[8], 'exg_type': data[9], 'tri_type': data[10], 'lbl_type': data[11], 'tim_size': 1, 'idx_size': 1 } self.tri = np.zeros(self.config['samples']) self.last_tri = 0 self.eeg = np.zeros( (self.config['samples'], self.config['eeg_channels']), dtype=np.float) self.exg = np.zeros( (self.config['samples'], self.config['exg_channels']), dtype=np.float) self.ts_list = [] self.ts_list_tri = []
cnbidirs = [ 'libLSL', 'Triggers', 'StreamReceiver', 'StreamRecorder', 'StreamViewer', 'Decoder', 'Utils', 'Glass' ] cnbiroot = os.path.dirname(os.path.realpath(__file__)) + '/' sys.path.append(cnbiroot) for d in cnbidirs: sys.path.append(cnbiroot + d) # check MNE version. MNE < 0.11 has an offset bug for BDF data. import mne mne_ver = mne.__version__.split('.') if mne_ver[0] == '0' and float(mne_ver[1]) < 12: import q_common as qc qc.print_c( '\n\n*** WARNING: Your Python-MNE version is %s. Please upgrade to 0.12 or higher. ***\n' % mne.__version__, 'r') # channel names (trigger channel is index 0 so that eeg channels start from index 1) CAP = { 'GTEC_16': [ 'TRIGGER', 'Fz', 'FC3', 'FC1', 'FCz', 'FC2', 'FC4', 'C3', 'C1', 'Cz', 'C2', 'C4', 'CP3', 'CP1', 'CPz', 'CP2', 'CP4' ], 'GTEC_16_INFO': ['stim'] + ['eeg'] * 16, 'BIOSEMI_64': [ 'TRIGGER', 'Fp1', 'AF7', 'AF3', 'F1', 'F3', 'F5', 'F7', 'FT7', 'FC5', 'FC3', 'FC1', 'C1', 'C3', 'C5', 'T7', 'TP7', 'CP5', 'CP3', 'CP1', 'P1', 'P3', 'P5', 'P7', 'P9', 'PO7', 'PO3', 'O1', 'Iz', 'Oz', 'POz', 'Pz', 'CPz', 'Fpz', 'Fp2', 'AF8', 'AF4', 'AFz', 'Fz', 'F2', 'F4', 'F6', 'F8', 'FT8', 'FC6', 'FC4', 'FC2', 'FCz', 'Cz', 'C2', 'C4', 'C6', 'T8', 'TP8',
def print(self, msg): qc.print_c('[StreamViewer] %s' % msg, color='W')
def connect(self, find_any=True): """ Run in child process """ server_found = False amps = [] channels = 0 while server_found == False: if self.amp_name is None and self.amp_serial is None: self.print("Looking for a streaming server...") else: self.print("Looking for %s (Serial %s) ..." % (self.amp_name, self.amp_serial)) streamInfos = pylsl.resolve_streams() #print(streamInfos) if len(streamInfos) > 0: # For now, only 1 amp is supported by a single StreamReceiver object. for si in streamInfos: #is_slave= ('true'==pylsl.StreamInlet(si).info().desc().child('amplifier').child('settings').child('is_slave').first_child().value() ) inlet = pylsl.StreamInlet(si) amp_serial = inlet.info().desc().child( 'acquisition').child_value('serial_number') amp_name = si.name() #qc.print_c('Found %s (%s)'% (amp_name,amp_serial), 'G') # connect to a specific amp only? if self.amp_serial is not None and self.amp_serial != amp_serial: continue # connect to a specific amp only? if self.amp_name is not None and self.amp_name != amp_name: continue # EEG streaming server only? if self.eeg_only and si.type() != 'EEG': continue if 'USBamp' in amp_name: self.print('Found USBamp streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) self.lsl_tr_channel = 16 channels += si.channel_count() ch_list = pu.lsl_channel_list(inlet) amps.append(si) server_found = True break elif 'BioSemi' in amp_name: self.print('Found BioSemi streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) self.lsl_tr_channel = 0 # or subtract -6684927? (value when trigger==0) channels += si.channel_count() ch_list = pu.lsl_channel_list(inlet) amps.append(si) server_found = True break elif 'SmartBCI' in amp_name: self.print('Found SmartBCI streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) self.lsl_tr_channel = 23 channels += si.channel_count() ch_list = pu.lsl_channel_list(inlet) amps.append(si) server_found = True break elif 'StreamPlayer' in amp_name: self.print('Found StreamPlayer streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) self.lsl_tr_channel = 0 channels += si.channel_count() ch_list = pu.lsl_channel_list(inlet) amps.append(si) server_found = True break elif 'openvibeSignal' in amp_name: self.print('Found an Openvibe signal streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) ch_list = pu.lsl_channel_list(inlet) if 'TRIGGER' in ch_list: self.lsl_tr_channel = ch_list.index('TRIGGER') else: self.lsl_tr_channel = None channels += si.channel_count() amps.append(si) server_found = True self.multiplier = 10**6 break elif 'openvibeMarkers' in amp_name: self.print('Found an Openvibe markers server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) ch_list = pu.lsl_channel_list(inlet) if 'TRIGGER' in ch_list: self.lsl_tr_channel = ch_list.index('TRIGGER') else: self.lsl_tr_channel = None channels += si.channel_count() amps.append(si) server_found = True #self.multiplier= 10**6 break elif find_any: self.print('Found a streaming server %s (type %s, amp_serial %s) @ %s.'\ % (amp_name, si.type(), amp_serial, si.hostname()) ) self.lsl_tr_channel = 0 # needs to be changed channels += si.channel_count() from IPython import embed embed() ch_list = pu.lsl_channel_list(inlet) amps.append(si) server_found = True break time.sleep(1) self.amp_name = amp_name # define EEG channel indices self.lsl_eeg_channels = range(channels) if self.lsl_tr_channel is not None: self.print('Assuming trigger channel to be %d' % self.lsl_tr_channel) self.lsl_eeg_channels.pop(self.lsl_tr_channel) self.lsl_eeg_channels = np.array(self.lsl_eeg_channels) self.tr_channel = 0 # trigger channel is always set to 0. self.eeg_channels = np.arange( 1, channels) # signal channels start from 1. # create new inlets to read from the stream inlets_master = [] inlets_slaves = [] for amp in amps: inlet = pylsl.StreamInlet(amp) inlets_master.append(inlet) ''' if True==inlet.info().desc().child('amplifier').child('settings').child('is_slave').first_child().value(): self.print('Slave amp: %s.'% amp.name() ) inlets_slaves.append(inlet) else: self.print('Master amp: %s.'% amp.name() ) inlets_master.append(inlet) ''' self.buffers.append([]) self.timestamps.append([]) inlets = inlets_master + inlets_slaves sample_rate = amps[0].nominal_srate() self.print('Channels: %d' % channels) self.print('LSL Protocol version: %s' % amps[0].version()) self.print('Source sampling rate: %.1f' % sample_rate) self.print('Unit multiplier: %.1f' % self.multiplier) # set member vars self.channels = channels # includes trigger channel self.winsize = int(round(self.winsec * sample_rate)) self.bufsize = int(round(self.bufsec * sample_rate)) self.sample_rate = sample_rate self.connected = True self.inlets = inlets # NOTE: not picklable! self.ch_list = ch_list for i, chn in enumerate(self.ch_list): if chn == 'TRIGGER' or 'STI ' in chn: self.ch_list.pop(i) self.ch_list = ['TRIGGER'] + self.ch_list break qc.print_c('self.ch_list %s' % self.ch_list, 'Y') # fill in initial buffer self.print('Waiting to fill initial buffer of length %d' % (self.winsize)) while len(self.timestamps[0]) < self.winsize: self.acquire() time.sleep(0.1) self.ready = True self.print('Start receiving stream data.')
def print(self, msg): qc.print_c('[StreamReceiver] %s' % msg, 'W')
import q_common as qc import mne amp_name, amp_serial = pu.search_lsl() sr = StreamReceiver(window_size=1, buffer_size=1, amp_serial=amp_serial, eeg_only=False, amp_name=amp_name) sfreq = sr.get_sample_rate() watchdog = qc.Timer() tm = qc.Timer(autoreset=True) trg_ch = sr.get_trigger_channel() qc.print_c('Trigger channel: %d' % trg_ch, 'G') psde= mne.decoding.PSDEstimator(sfreq=sfreq, fmin=1, fmax=50, bandwidth=None,\ adaptive=False, low_bias=True, n_jobs=1, normalization='length', verbose=None) last_ts = 0 while True: lsl_time = pylsl.local_clock() sr.acquire() window, tslist = sr.get_window() window = window.T # print event values tsnew = np.where(np.array(tslist) > last_ts)[0][0] trigger = np.unique(window[trg_ch, tsnew:])
def load_raw_old(rawfile, spfilter=None, spchannels=None, events_ext=None): """ ** Deprecated function ** Please use convert2fif to convert non-fif files to fif first. Returns raw data and events Supports gdf, bdf, fif, and Python raw format (pcl). Any non-fif file will be saved into .fif format in the fif/ directory after loading. 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 PyCNBI puts trigger channel as index 0, data channel starts from index 1. events_mne: Add externally recorded events (e.g. software trigger). events_mne is of format: [ [sample_index1, 0, event_value1],... ] 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): qc.print_c('# ERROR: File %s not found' % rawfile, 'r') sys.exit(-1) rawfile = rawfile.replace('\\', '/') dirs = rawfile.split('/') if len(dirs) == 1: basedir = './' else: basedir = '/'.join(dirs[:-1]) + '/' extension = rawfile.split('.')[-1] basename = '.'.join(rawfile.split('.')[:-1]) raw = None events = [] if extension == 'pcl': data = qc.load_obj(rawfile) if type(data['signals']) == list: print('Converting into numpy format') signals_raw = np.array( data['signals'][0]).T # to channels x samples else: signals_raw = data['signals'].T # to channels x samples sample_rate = data['sample_rate'] events_raw = data['events'] # BioSemi or gtec? if data['channels'] == 17: # move the trigger channel to the first row if find_event_channel(signals_raw) != 16: qc.print_c( '**** WARNING: Assuming GTEC_16 format. Double-check trigger channel !! *****', 'r') signals = np.concatenate( (signals_raw[16, :].reshape(1, -1), signals_raw[:16, :])) info = mne.create_info(CAP['GTEC_16'], sample_rate, CAP['GTEC_16_INFO']) elif data['channels'] >= 73: signals = signals_raw[: 73, :] # trigger channel is already the first row sigtrig = signals[0, :] - 1 signals[0, :] = 0xFF & sigtrig.astype( int) # keep only the low 8 bits info = mne.create_info(CAP['BIOSEMI_64'], sample_rate, CAP['BIOSEMI_64_INFO']) elif data['channels'] == 24: qc.print_c( '**** ASSUMING SmartBCI system with no trigger channel ****', 'y') if True: # A1=9, A2=16 ear_avg = (signals_raw[8] + signals_raw[15]) / 2.0 signals = signals_raw - ear_avg trigger = np.zeros((1, signals_raw.shape[1])) signals = np.vstack((trigger, signals)) else: signals = signals_raw[: 24, :] # trigger channel is already the first row sigtrig = signals[0, :] signals[0, :] = 0x00 info = mne.create_info(CAP['SMARTBCI_24'], sample_rate, CAP['SMARTBCI_24_INFO']) else: # ok, unknown format # guess trigger channel trig_ch = find_event_channel(signals_raw) if trig_ch is not None: qc.print_c( 'Found trigger channel %d. Moving to channel 0.' % trig_ch, 'y') signals = np.concatenate( (signals_raw[[trig_ch]], signals_raw[:trig_ch], signals_raw[trig_ch + 1:]), axis=0) assert signals_raw.shape == signals.shape num_eeg_channels = data['channels'] - 1 else: # assuming no trigger channel exists, add a trigger channel to index 0 for consistency. qc.print_c( '**** Unrecognized number of channels (%d). Adding an event channel to index 0.' % data['channels'], 'r') eventch = np.zeros([1, signals_raw.shape[1]]) signals = np.concatenate((eventch, signals_raw), axis=0) num_eeg_channels = data['channels'] ch_names = ['TRIGGER'] + [ 'CH%d' % (x + 1) for x in range(num_eeg_channels) ] ch_info = ['stim'] + ['eeg'] * num_eeg_channels info = mne.create_info(ch_names, sample_rate, ch_info) elif extension in ['fif', 'fiff']: raw = mne.io.Raw(rawfile, preload=True) elif extension in ['bdf', 'gdf']: # convert to mat using MATLAB (MNE's edf reader has an offset bug) matfile = basename + '.mat' if not os.path.exists(matfile): print('>> Converting input to mat file') run = "[sig,header]=sload('%s.%s'); save('%s.mat','sig','header');" % ( basename, extension, basename) qc.matlab(run) if not os.path.exists(matfile): qc.print_c('>> ERROR: mat file convertion error.', 'r') sys.exit() mat = scipy.io.loadmat(matfile) os.remove(matfile) sample_rate = int(mat['header']['SampleRate']) nch = mat['sig'].shape[1] if extension == 'gdf': # Note: gdf might have a software trigger channel if nch == 17: ch_names = CAP['GTEC_16'] ch_info = CAP['GTEC_16_INFO'][:nch] else: ch_names = ['TRIGGER'] + ['ch%d' % x for x in range(1, nch)] ch_info = ['stim'] + ['eeg'] * (nch - 1) # read events from header ''' Important: event position may have the same frame number for two consecutive events It might be due to the CNBI software trigger bug Example: f1.20121220.102907.offline.mi.mi_rhlh.gdf (Two 10201's in evpos) ''' evtype = mat['header']['EVENT'][0][0][0]['TYP'][0] evpos = mat['header']['EVENT'][0][0][0]['POS'][0] for e in range(evtype.shape[0]): label = int(evtype[e]) events.append([int(evpos[e][0]), 0, label]) elif extension == 'bdf': # assume Biosemi always has the same number of channels if nch == 73: ch_names = CAP['BIOSEMI_64'] extra_ch = nch - len(CAP['BIOSEMI_64_INFO']) extra_names = [] for ch in range(extra_ch): extra_names.append('EXTRA%d' % ch) ch_names = ch_names + extra_names ch_info = CAP['BIOSEMI_64_INFO'] + ['misc'] * extra_ch else: qc.print_c( '****** load_raw(): WARNING: Unrecognized number of channels (%d) ******' % nch, 'y') qc.print_c( 'The last channel will be assumed to be trigger. Press Enter to continue, or Ctrl+C to break.', 'r') raw_input() # Set the trigger to be channel 0 because later we will move it to channel 0. ch_names = ['TRIGGER' ] + ['CH%d' % (x + 1) for x in range(nch - 1)] ch_info = ['stim'] + ['eeg'] * (nch - 1) # Move the event channel to 0 (for consistency) signals_raw = mat['sig'].T # -> channels x samples signals = np.concatenate( (signals_raw[-1, :].reshape(1, -1), signals_raw[:-1, :])) # Note: Biosig's sload() sometimes returns bogus event values so we use the following for events bdf = mne.io.read_raw_edf(rawfile, preload=True) events = mne.find_events(bdf) signals[-1][:] = bdf._data[ -1][:] # overwrite with the correct event values info = mne.create_info(ch_names, sample_rate, ch_info) else: # unknown format qc.print_c( 'ERROR: Unrecognized file extension %s. It should be [.pcl | .fif | .fiff | .gdf | .bdf]' % extension, 'r') sys.exit(-1) if raw is None: # signals= channels x samples raw = mne.io.RawArray(signals, info) # check if software trigger trigch = raw.info['ch_names'].index('TRIGGER') if events != [] and max(raw[trigch][0][0]) == 0: raw.add_events(events, stim_channel='TRIGGER') # external events with LSL timestamps if events_ext != None: if extension != 'pcl': qc.print_c( '>> ERROR: external events can be only added to raw .pcl files', 'r') sys.exit(-1) events_index = event_timestamps_to_indices(rawfile, events_ext) raw.add_events(events_index, stim_channel='TRIGGER') qc.make_dirs(basedir + 'fif/') fifname = basedir + 'fif/' + basename.split('/')[-1] + '.fif' raw.save(fifname, overwrite=True, verbose=False) print('Saving to', fifname) # find a value changing from zero to a non-zero value events = mne.find_events(raw, stim_channel='TRIGGER', shortest_event=1) # apply spatial filter n_channels = raw._data.shape[0] if spfilter == 'car': if not spchannels: raw._data[1:] = raw._data[1:] - np.mean(raw._data[1:], axis=0) else: raw._data[spchannels] = raw._data[spchannels] - np.mean( raw._data[spchannels], axis=0) elif spfilter == 'laplacian': if type(spchannels) is not dict: raise RuntimeError, 'For Lapcacian, SP_CHANNELS must be of a form {CHANNEL:[NEIGHBORS], ...}' rawcopy = raw._data.copy() for src in spchannels: nei = spchannels[src] raw._data[src] = rawcopy[src] - np.mean(rawcopy[nei], axis=0) elif spfilter == 'bipolar': raw._data[1:] -= raw._data[spchannels] elif spfilter is None: pass else: qc.print_c('# ERROR: Unknown spatial filter', spfilter, 'r') sys.exit(-1) return raw, events
def load_raw(rawfile, spfilter=None, spchannels=None, events_ext=None, multiplier=1): """ 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 PyCNBI puts trigger channel as index 0, data channel starts from index 1. events_mne: Add externally recorded events (e.g. software trigger). events_mne is of format: [ [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): qc.print_c('# ERROR: File %s not found' % rawfile, 'r') sys.exit(-1) extension = rawfile.split('.')[-1] assert extension in ['fif', 'fiff'], 'only fif format is supported' raw = mne.io.Raw(rawfile, preload=True) if 'TRIGGER' in raw.ch_names: tch_name = 'TRIGGER' elif 'STI ' in raw.ch_names: # e.g. 'STI 014' tch_name = 'STI ' elif 'Trig1' in raw.ch_names: tch_name = 'Trig1' else: raise RuntimeError, 'No trigger channel found.' # find a value changing from zero to a non-zero value tch = raw.ch_names.index(tch_name) events = mne.find_events(raw, stim_channel=tch_name, shortest_event=1, uint_cast=True) n_channels = raw._data.shape[0] eeg_channels = list(range(n_channels)) eeg_channels.pop(tch) if multiplier != 1: raw._data[eeg_channels] *= multiplier # apply spatial filter if spfilter == 'car': if not spchannels: raw._data[eeg_channels] = raw._data[eeg_channels] - np.mean( raw._data[eeg_channels], axis=0) else: raw._data[spchannels] = raw._data[spchannels] - np.mean( raw._data[spchannels], axis=0) elif spfilter == 'laplacian': if type(spchannels) is not dict: raise RuntimeError, 'For Lapcacian, SP_CHANNELS must be of a form {CHANNEL:[NEIGHBORS], ...}' rawcopy = raw._data.copy() for src in spchannels: nei = spchannels[src] raw._data[src] = rawcopy[src] - np.mean(rawcopy[nei], axis=0) elif spfilter == 'bipolar': raw._data[1:] -= raw._data[spchannels] elif spfilter is None: pass else: qc.print_c('# ERROR: Unknown spatial filter', spfilter, 'r') sys.exit(-1) return raw, events
def record(state, amp_name, amp_serial, eeg_only=False): # set data file name filename = time.strftime(OUT_DIR + "/%Y%m%d-%H%M%S-raw.pcl", time.localtime()) qc.print_c('\n>> Output file: %s' % (filename), 'W') # test writability try: qc.make_dirs(OUT_DIR) open( filename, 'w').write('The data will written when the recording is finished.') except: qc.print_c( '\n*** ERROR: There was a problem writing file %s\n' % filename, 'W') sys.exit(-1) # start a server for sending out data filename for software trigger outlet = cnbi_lsl.start_server('StreamRecorderInfo', channel_format='string', source_id=filename, stype='Markers') # connect to EEG stream server sr = receiver.StreamReceiver(amp_name=amp_name, amp_serial=amp_serial, eeg_only=eeg_only) # record start qc.print_c('\n>> Recording started (PID %d).' % os.getpid(), 'W') qc.print_c('\n>> Press Enter to stop recording', 'G') tm = qc.Timer(autoreset=True) next_sec = 1 while state.value == 1: sr.acquire() if sr.get_buflen() > next_sec: duration = str(datetime.timedelta(seconds=int(sr.get_buflen()))) print('RECORDING %s' % duration) next_sec += 1 ###################################################### #data, ts= sr.get_window() #tc= pylsl.local_clock() #tson= np.argmax( ts >= int(tc) ) #print( ts[tson], tson, data[tson,0] ) ###################################################### tm.sleep_atleast(0.01) # record stop qc.print_c('>> Stop requested. Copying buffer', 'G') buffers, times = sr.get_buffer() # DO NOT INFER TRIGGER CHANNEL AUTOMATICALLY ''' signal_idx= [] for x in range(buffers.shape[1]): if x != sr.get_trigger_channel(): signal_idx.append(x) signals= buffers[:, signal_idx] events= buffers[ :, sr.get_trigger_channel() ] ''' signals = buffers events = None # channels = total channels from amp, including trigger channel data = { 'signals': signals, 'timestamps': times, 'events': events, 'sample_rate': sr.get_sample_rate(), 'channels': sr.get_num_channels(), 'ch_names': sr.get_channel_names() } qc.print_c('Saving data ...', 'W') qc.save_obj(filename, data) print('Saved to %s' % filename) import convert2fif as cf cf.pcl2fif(filename) qc.print_c('File saved and converted to fif format.', 'W')
qc.print_c('File saved and converted to fif format.', 'W') if __name__ == '__main__': eeg_only = False if len(sys.argv) == 2: amp_name = sys.argv[1] amp_serial = None elif len(sys.argv) == 3: amp_name, amp_serial = sys.argv[1:3] else: amp_name, amp_serial = pu.search_lsl(ignore_markers=True) if amp_name == 'None': amp_name = None qc.print_c( 'Connecting to a server %s (Serial %s)' % (amp_name, amp_serial), 'W') qc.print_c('\n>> Press Enter to start recording.', 'G') key = raw_input() state = mp.Value('i', 1) proc = mp.Process(target=record, args=[state, amp_name, amp_serial, eeg_only]) proc.start() raw_input('') state.value = 0 qc.print_c('(main) Waiting for recorder process to finish.', 'W') proc.join(10) if proc.is_alive(): qc.print_c( '>> ERROR: Recorder process not finihsing. Are you running from Spyder?',
def cross_validate(data, cls_params): """ Do cross-validation CV_PERFORM= ['LeaveOneOut' | 'StratifiedShuffleSplit' | 'KFold'] """ CV_PERFORM = 'KFold' CV_FOLDS = 6 # parameters for StratifiedShuffleSplit only CV_TEST_RATIO = 0.2 CV_SEED = 0 acc_subject = {} scores_all = [] for subject in data: gbp = cls_params[subject] cls1 = GradientBoostingClassifier(n_estimators=gbp['trees'], learning_rate=gbp['learning_rate'], max_depth=gbp['max_depth'], max_features=gbp['max_features'], subsample=gbp['subsample'], random_state=gbp['random_state']) cls2 = GradientBoostingClassifier(n_estimators=gbp['trees'], learning_rate=gbp['learning_rate'], max_depth=gbp['max_depth'], max_features=gbp['max_features'], subsample=gbp['subsample'], random_state=gbp['random_state']) qc.print_c('Parameters\nGB %s' % (gbp), 'W') X1 = data[subject]['X1'] X2 = data[subject]['X2'] Y = data[subject]['Y'] if CV_PERFORM == 'LeaveOneOut': print('\n>> %s: %d-fold leave-one-out cross-validation' % (subject, ntrials)) cv = LeaveOneOut() elif CV_PERFORM == 'StratifiedShuffleSplit': print('\n>> %s: %d-fold stratified cross-validation with test set ratio %.2f' % (subject, CV_FOLDS, CV_TEST_RATIO)) cv = StratifiedShuffleSplit(CV_FOLDS, test_size=CV_TEST_RATIO, random_state=CV_SEED) elif CV_PERFORM == 'KFold': cv = KFold(CV_FOLDS) label_set = list(np.unique(Y)) scores = [] num_labels = len(label_set) cms = np.zeros((num_labels, num_labels)) cnum = 1 if N_JOBS > 1: results = [] pool = mp.Pool(mp.cpu_count()) for train, test in cv.split(Y): p = pool.apply_async(fit_predict, [cls1, cls2, X1[train], X2[train], Y[train], X1[test], X2[test], Y[test], cnum, label_set]) results.append(p) cnum += 1 pool.close() pool.join() for r in results: score, cm = r.get() scores.append(score) cms += cm else: for train, test in cv.split(Y): score, cm = fit_predict(cls1, cls2, X1[train], X2[train], Y[train], X1[test], X2[test], Y[test], cnum, label_set) scores.append(score) cms += cm cnum += 1 # Show confusion matrix cm_rate = cms.astype('float') / cms.sum(axis=1)[:, np.newaxis] cm_txt = '\nY: ground-truth, X: predicted\n' for l in label_set: cm_txt += '%4d\t' % l cm_txt += '\n' for r in cm_rate: for c in r: cm_txt += '%-4.3f\t' % c cm_txt += '\n' acc = np.mean(scores) print('Average accuracy: %.3f' % acc) print(cm_txt) acc_subject[subject] = acc scores_all += scores # Assuming every subject has equal number of trials for subject in acc_subject: print('%s: %.3f' % (subject, acc_subject[subject])) acc_all = np.mean(scores_all) print('Average accuracy over all subjects: %.3f' % acc_all) return acc_all, acc_subject