class BetaInlet(object): def __init__(self): print("looking for an EEG stream...") streams = resolve_byprop("type", "EEG") # create a new inlet to read from the stream proc_flags = proc_clocksync | proc_dejitter | proc_monotonize self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) stream_info = self.inlet.info() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") self.channel_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": self.channel_list.append(ch) ch = ch.next_sibling("channel") def update(self): max_samps = 3276 * 2 data = np.nan * np.ones( (max_samps, len(self.channel_list)), dtype=np.float32) _, timestamps = self.inlet.pull_chunk(max_samples=max_samps, dest_obj=data) data = data[:len(timestamps), :] return data, np.asarray(timestamps) def sampling_rate(self): return self.inlet.info().nominal_srate()
class LSLInlet: def __init__(self, name=LSL_STREAM_NAMES[2], max_chunklen=8, n_channels=20): streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT) self.inlet = None self.dtype = 'float64' if len(streams) > 0: self.inlet = StreamInlet(streams[0], max_buflen=1, max_chunklen=max_chunklen) # self.dtype = fmt2string[self.inlet.info().channel_format()] print(self.dtype) self.n_channels = n_channels if n_channels else self.inlet.info( ).channel_count() def get_next_chunk(self, mode=0): # get next chunk chunk, timestamp = self.inlet.pull_chunk() # convert to numpy array chunk = np.array(chunk, dtype=self.dtype) # return first n_channels channels or None if empty chunk return chunk[:, :self.n_channels] if chunk.shape[0] > 0 else None def update_action(self): pass def save_info(self, file): with open(file, 'w', encoding="utf-8") as f: f.write(self.inlet.info().as_xml()) def get_frequency(self): return self.inlet.info().nominal_srate() def get_n_channels(self): return self.n_channels def get_channels_labels_bad(self): time.sleep(0.001) labels = [] ch = self.inlet.info().desc().child("channels").child("channel") for k in range(self.get_n_channels()): labels.append(ch.child_value("label")) ch = ch.next_sibling() return def get_channels_labels(self): return ch_names[:self.n_channels] def disconnect(self): del self.inlet self.inlet = None
def testing(): dummy_streamer = ble2lsl.Dummy(muse2016) # streams = resolve_byprop( "type", "EEG", timeout=5 ) #type: EEG, minimum return streams = 1, timeout after 5 seconds streamIn = StreamInlet( streams[0], max_chunklen=12, recover=True ) #Grab first stream from streams, MUSE chunk 12, drop lost stream print(streamIn) print(streamIn.info().channel_count()) streamIn.open_stream( ) #This actually isn't required: pull_sample() and pull_chunk() implicitly open the stream. #But it's good to be explicit because it makes the code clearer print("Pull Sample") print(streamIn.pull_sample() ) #Returns a tuple with the actual values we want. #The first element is the list of channel values, the second element is a timestamp. This is a snapshot of our stream #at a certain point in time. print("Pull Chunk") ts = time.time() while (1): x = streamIn.pull_chunk() if all(x): #if not np.shape(x) == (2, 0): print(np.shape(x)) print(np.shape(x[1])) t = [t - ts for t in x[1]] print(t) print(t[-1] - t[0]) # for y in x: # for z in y: # print(z) #print("\n") plt.style.use('ggplot') # data first then time stamps, sick pprint(streamIn.info().as_xml()) #what timeC = streamIn.time_correction() print(timeC) #Clean up time streams.clear() streamIn.close_stream() #calls lsl_close_stream streamIn.__del__() #Not throwing errors dummy_streamer.stop()
def dataReaderLSLWithChannelInfo(streamName, q, channelLabels): while True: print("Waiting for LSL stream") try: results = resolve_byprop(prop='name', value=streamName) while len(results) == 0: results = resolve_byprop(prop='name', value=streamName) time.sleep(0.25) info = results[0] inlet = StreamInlet(info, recover=False) info = inlet.info() ch = info.desc().child("channels").child("channel") for k in range(info.channel_count()): channelLabels.append(ch.child_value("label")) ch = ch.next_sibling() #print("In dataReader: ") #print(channelLabels) print("Streaming...") # Read data in forever try: while True: data = inlet.pull_sample() if data: q.put(np.array(data[0])) time.sleep(1 / 1000000) except Exception as e: print(e) pass except Exception as e: print(traceback.format_exc()) pass
class BetaInlet(object): def __init__(self): print("looking for an EEG stream...") streams = resolve_byprop("type", "EEG") # create a new inlet to read from the stream proc_flags = proc_clocksync | proc_dejitter | proc_monotonize self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") self.channel_names = [ch_xml.child_value("label") for ch_xml in chan_xml_list] print("Reading from inlet named {} with channels {} sending data at {} Hz".format(stream_info.name(), self.channel_names, stream_Fs)) def update(self): max_samps = 3276*2 data = np.nan * np.ones((max_samps, len(self.channel_names)), dtype=np.float32) _, timestamps = self.inlet.pull_chunk(max_samples=max_samps, dest_obj=data) data = data[:len(timestamps), :] print("Beta inlet retrieved {} samples.".format(len(timestamps))) return data, np.asarray(timestamps)
def pull_data(self): """Continually pulls data from an LSL stream over the local network and updates data sampling rate-related class attributes. """ print('Looking for an EEG stream...') streams = resolve_stream('type', 'EEG') inlet = StreamInlet(streams[0]) # stream has been found self.resolved = True # getting stream metadata stream_info = inlet.info() # setting class attributes self.sampling_rate = stream_info.nominal_srate() # printing stream info print(f"{'':=^30s} Streams {'':=^30s}") print(f'Channel name: {stream_info.name()}' f'\nData type: {stream_info.type()}' f'\nChannel count: {stream_info.channel_count()}' f'\nSource ID: {stream_info.source_id()}') # nice ;) print(f"{'':=^69s}") # updating sampling rate self.n_data = int(self.sampling_rate * self.x_time) while self._run_thread: # timestamp unused sample, timestamp = inlet.pull_sample() self.ydata[self.iter_n] = sample[0] self.iter_n = (self.iter_n + 1) % self.n_data
def initialize(self): self.debug=self.setting['debug'] == "true" print "Debug: ", self.debug self.stream_type=self.setting['Stream type'] # total channels for all streams self.channelCount = 0 all_streams = self.setting['Get all streams'] == "true" self.overcomeCheck = self.setting['Overcome code check'] == "true" self.stream_name=self.setting['Stream name'] # in case !all_streams print "Looking for streams of type: " + self.stream_type streams = resolve_stream('type',self.stream_type) print "Nb streams: " + str( len(streams)) if not all_streams: print "Will only select (first) stream named: " + self.stream_name self.nb_streams = 1 else: self.nb_streams = len(streams) # create inlets to read from each stream self.inlets = [] # retrieve also corresponding StreamInfo for future uses (eg sampling rate) self.infos = [] # save inlets and info + build signal header for stream in streams: # do not set max_buflen because we *should not* be spammed by values inlet = StreamInlet(stream, max_buflen=1) info = inlet.info() name = info.name() print "Stream name: " + name # if target one stream, ignore false ones if not all_streams and name != self.stream_name: continue print "Nb channels: " + str(info.channel_count()) self.channelCount += info.channel_count() stream_freq = info.nominal_srate() print "Sampling frequency: " + str(stream_freq) if stream_freq != 0: print "WARNING: Wrong stream?" self.inlets.append(inlet) self.infos.append(info) # if we're still here when we target a stream, it means we foand it if not all_streams: print "Found target stream" break # we need at least one stream before we let go if self.channelCount <= 0: raise Exception("Error: no stream found.") # we append to the box output a stimulation header. This is just a header, dates are 0. self.output[0].append(OVStimulationHeader(0., 0.))
class BetaInlet(object): def __init__(self): print("looking for an EEG stream...") streams = resolve_byprop("type", "EEG") # create a new inlet to read from the stream proc_flags = proc_clocksync | proc_dejitter | proc_monotonize self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") self.channel_names = [ ch_xml.child_value("label") for ch_xml in chan_xml_list ] print( "Reading from inlet named {} with channels {} sending data at {} Hz" .format(stream_info.name(), self.channel_names, stream_Fs)) def update(self): max_samps = 3276 * 2 data = np.nan * np.ones( (max_samps, len(self.channel_names)), dtype=np.float32) _, timestamps = self.inlet.pull_chunk(max_samples=max_samps, dest_obj=data) data = data[:len(timestamps), :] print("Beta inlet retrieved {} samples.".format(len(timestamps))) return data, np.asarray(timestamps)
def __init__(self): print('Connecting...') streams = resolve_byprop('type', 'EEG', timeout=2) if len(streams) == 0: raise RuntimeError('Can\'t find EEG stream.') # set up Inlet inlet = StreamInlet(streams[0], max_chunklen=12) eeg_time_correction = inlet.time_correction() # Pull relevant information info = inlet.info() self.desc = info.desc() self.freq = int(info.nominal_srate()) ## TRAIN DATASET print('Recording Baseline') eeg_data_baseline = BCI.record_eeg_filtered( self.TRAINING_LENGTH, self.freq, self.INDEX_CHANNEL, True, ) eeg_epochs_baseline = BCI.epoch_array( eeg_data_baseline, self.EPOCH_LENGTH, self.OVERLAP_LENGTH * self.freq, self.freq) feat_matrix_baseline = BCI.compute_feature_matrix( eeg_epochs_baseline, self.freq) self.baseline = BCI.calc_baseline(feat_matrix_baseline)
def recordeeg(duration): warnings.filterwarnings('ignore') BUFFER_LENGTH = 5 EPOCH_LENGTH = 1 OVERLAP_LENGTH = 0.8 SHIFT_LENGTH = EPOCH_LENGTH - OVERLAP_LENGTH streams = resolve_byprop('type', 'EEG', timeout=2) if len(streams) == 0: raise RuntimeError('Can\'t find EEG stream.') inlet = StreamInlet(streams[0], max_chunklen=12) eeg_time_correction = inlet.time_correction() info = inlet.info() description = info.desc() fs = int(info.nominal_srate()) eeg_buffer = np.zeros((int(fs * BUFFER_LENGTH), 1)) filter_state = None n_win_test = int( np.floor((BUFFER_LENGTH - EPOCH_LENGTH) / SHIFT_LENGTH + 1)) band_buffer = np.zeros((n_win_test, 4)) musedata = [] while True: eeg_data, timestamp = inlet.pull_chunk(timeout=1, max_samples=int(SHIFT_LENGTH * fs)) musedata += eeg_data if len(musedata) > duration * fs: return musedata break
class LSLInlet: def __init__(self, name=LSL_STREAM_NAMES[2], max_chunklen=8, n_channels=20): streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT) self.inlet = None self.dtype = 'float64' if len(streams) > 0: self.inlet = StreamInlet(streams[0], max_buflen=1, max_chunklen=max_chunklen) # self.dtype = fmt2string[self.inlet.info().channel_format()] print(self.dtype) self.n_channels = n_channels if n_channels else self.inlet.info().channel_count() def get_next_chunk(self): # get next chunk chunk, timestamp = self.inlet.pull_chunk() # convert to numpy array chunk = np.array(chunk, dtype=self.dtype) # return first n_channels channels or None if empty chunk return chunk[:, :self.n_channels] if chunk.shape[0] > 0 else None def update_action(self): pass def save_info(self, file): with open(file, 'w') as f: f.write(self.inlet.info().as_xml()) def get_frequency(self): return self.inlet.info().nominal_srate() def get_n_channels(self): return self.n_channels def get_channels_labels_bad(self): time.sleep(0.001) labels = [] ch = self.inlet.info().desc().child("channels").child("channel") for k in range(self.get_n_channels()): labels.append(ch.child_value("label")) ch = ch.next_sibling() return def get_channels_labels(self): return ch_names[:self.n_channels] def disconnect(self): del self.inlet self.inlet = None
class AIYVoiceInterface: def __init__(self, lsl_data_type, num_channels): # default board_id 2 for Cyton self.lsl_data_type = lsl_data_type self.lsl_num_channels = num_channels self.streams = resolve_byprop('name', self.lsl_data_type, timeout=1) if len(self.streams) < 1: raise AttributeError( 'Unable to find LSL Stream with given type {0}'.format( lsl_data_type)) self.inlet = StreamInlet(self.streams[0]) # TO-DO: fix this, we need to re-stream this since sometimes unity doesn't pick up AIY data for some reason info = StreamInfo('VoiceBox', 'Voice', num_channels, 0.0, 'string', 'voice') self.outlet = StreamOutlet(info) pass def start_sensor(self): # connect to the sensor self.streams = resolve_byprop('name', self.lsl_data_type, timeout=1) if len(self.streams) < 1: raise AttributeError( 'Unable to find LSL Stream with given type {0}'.format( self.lsl_data_type)) self.inlet = StreamInlet(self.streams[0]) self.inlet.open_stream() print( 'LSLInletInterface: resolved, created and opened inlet for lsl stream with type ' + self.lsl_data_type) # read the channel names is there's any # tell the sensor to start sending frames def process_frames(self): # return one or more frames of the sensor try: frames, timestamps = self.inlet.pull_chunk() if len(frames) > 0: self.outlet.push_sample(frames[0]) # TO-DO: see above except LostError: frames, timestamps = [], [] pass # TODO handle stream lost return np.transpose(frames), timestamps def stop_sensor(self): if self.inlet: self.inlet.close_stream() print('LSLInletInterface: inlet stream closed.') def info(self): return self.inlet.info() def get_num_chan(self): return self.lsl_num_channels def get_nominal_srate(self): return self.streams[0].nominal_srate()
async def listen(inlet: pylsl.StreamInlet): while True: samples, timestamps = inlet.pull_chunk() for sample, timestamp in zip(samples, timestamps): print('\t'.join( map(lambda x: str(x).ljust(20), [inlet.info().type(), timestamp, sample])), flush=True) await asyncio.sleep(0.1)
def obtain_stream_channel_names(stream): header = [] inlet = StreamInlet(stream) info = inlet.info() ch = info.desc().child("channels").child("channel") for k in range(info.channel_count()): #print(" " + ch.child_value("label")) header.append(ch.child_value("label")) ch = ch.next_sibling() return header
def __init__(self, stream_inlet: StreamInlet, window: float): self.stream_inlet = stream_inlet self.window = window stream_info = stream_inlet.info() self.sfreq = stream_info.nominal_srate() assert self.sfreq != IRREGULAR_RATE self.n_chans = stream_info.channel_count() self.epoch_len = int(self.sfreq * window) assert self.epoch_len > 0 self.deque = collections.deque(maxlen=self.epoch_len)
def get_Stream_Info(self, streams): inlet = StreamInlet( streams[0], max_chunklen=12, recover=False ) ## create a getter to change the chuncklength based on the device timecorrect = inlet.time_correction( ) # gets the time correction of the two buffers info = inlet.info() descrition = info.desc() fs = int(info.nominal_srate()) num_channels = info.channel_count() return inlet, timecorrect, info, descrition, fs, num_channels
def recover_info(stream: StreamInlet) -> StreamInfo: "takes a StreamInlet and casts it into a StreamInfo" info = stream.info() return pylsl.StreamInfo( name=info.name(), type=info.type(), channel_count=info.channel_count(), nominal_srate=info.nominal_srate(), channel_format=info.channel_format(), source_id=info.source_id(), )
def receive(self): streams = resolve_byprop('type', self.settings.type, timeout=LSL_SCAN_TIMEOUT) if len(streams) == 0: print("Can't find %s stream." % self.settings.type) return print("Started acquiring data.") inlet = StreamInlet(streams[0], max_chunklen=self.settings.chunk) info = inlet.info() description = info.desc() n_channels = info.channel_count() ch = description.child('channels').first_child() ch_names = [ch.child_value('label')] for i in range(1, n_channels): ch = ch.next_sibling() ch_names.append(ch.child_value('label')) channel_descriptor = ChannelDescriptor(self.settings.type, ch_names, info.nominal_srate()) res = [] timestamps = [] t_init = time() time_correction = inlet.time_correction() print('Start recording at time t=%.3f' % t_init) print('Time correction: ', time_correction) while (time() - t_init) < 5000: try: data, timestamp = inlet.pull_chunk( timeout=1.0, max_samples=self.settings.chunk) if timestamp: res.append(data) self.subscription.notify_all_subscribers( self.settings.type, data, timestamp, channel_descriptor) timestamps.extend(timestamp) except KeyboardInterrupt: break time_correction = inlet.time_correction() print('Time correction: ', time_correction) res = np.concatenate(res, axis=0) timestamps = np.array(timestamps) + time_correction print('Done .')
class LSLInletInterface: def __init__(self, lsl_data_type): self.streams = resolve_byprop('name', lsl_data_type, timeout=0.1) if len(self.streams) < 1: raise AttributeError( 'Unable to find LSL Stream with given type {0}'.format( lsl_data_type)) self.inlet = StreamInlet(self.streams[0]) self.lsl_data_type = lsl_data_type self.lsl_num_channels = self.inlet.channel_count pass def start_sensor(self): # connect to the sensor self.streams = resolve_byprop('name', self.lsl_data_type, timeout=0.1) if len(self.streams) < 1: raise AttributeError( 'Unable to find LSL Stream with given type {0}'.format( self.lsl_data_type)) if not self.inlet: self.inlet = StreamInlet(self.streams[0]) self.inlet.open_stream() print( 'LSLInletInterface: resolved, created and opened inlet for lsl stream with type ' + self.lsl_data_type) # read the channel names is there's any # tell the sensor to start sending frames def process_frames(self): # return one or more frames of the sensor try: frames, timestamps = self.inlet.pull_chunk() except LostError: frames, timestamps = [], [] pass # TODO handle stream lost return np.transpose(frames), timestamps def stop_sensor(self): if self.inlet: self.inlet.close_stream() print('LSLInletInterface: inlet stream closed.') def info(self): return self.inlet.info() def get_num_chan(self): return self.lsl_num_channels def get_nominal_srate(self): return self.streams[0].nominal_srate()
def acquire_eeg(duration, callback=print_eeg_callback, eeg_chunck=LSL_EEG_CHUNK): DATA_SOURCE = "EEG" print("Looking for a %s stream..." % (DATA_SOURCE)) streams = resolve_byprop('type', DATA_SOURCE, timeout=LSL_SCAN_TIMEOUT) if len(streams) == 0: print("Can't find %s stream." % (DATA_SOURCE)) return print("Started acquiring data.") inlet = StreamInlet(streams[0], max_chunklen=eeg_chunck) info = inlet.info() description = info.desc() Nchan = info.channel_count() ch = description.child('channels').first_child() ch_names = [ch.child_value('label')] for i in range(1, Nchan): ch = ch.next_sibling() ch_names.append(ch.child_value('label')) timestamps = [] t_init = time() time_correction = inlet.time_correction() print('Start acquiring at time t=%.3f' % t_init) print('Time correction: ', time_correction) while (time() - t_init) < duration: try: chunk, timestamps = inlet.pull_chunk(timeout=1.0, max_samples=eeg_chunck) if timestamps: samples = { key: [sample[i] for sample in chunk] for i, key in enumerate(ch_names) } callback(timestamps, samples) except KeyboardInterrupt: break print('Acquisition is done')
def search_streams(): '''Look for EEG streams using LSL protocol. Returns: Array of LSL streams. ''' print("Searching streams") streams = resolve_byprop('type', 'EEG') inlets = [] for stream in streams: inlet = StreamInlet(stream) inlets.append(inlet) print('Stream found: ', inlet.info().source_id()) return inlets
def run(self): self.eeg_data = [] streams = resolve_stream('name', config.eeg_stream_name) print('EEG streams', streams) inlet = StreamInlet(streams[0]) self.s_rate = inlet.info().nominal_srate() while self.running: if self.recording: # get a new sample (you can also omit the timestamp part if you're not # interested in it) sample, timestamp = inlet.pull_sample(timeout=config.collector_timeout) if sample is None: self.running = False else: self.eeg_data.append(sample)
def main(): # create a new StreamInfo object which shall describe our stream info = StreamInfo("MetaTester", "EEG", 8, 100, "float32", "myuid56872") # now attach some meta-data (in accordance with XDF format, # see also https://github.com/sccn/xdf/wiki/Meta-Data) chns = info.desc().append_child("channels") for label in ["C3", "C4", "Cz", "FPz", "POz", "CPz", "O1", "O2"]: ch = chns.append_child("channel") ch.append_child_value("label", label) ch.append_child_value("unit", "microvolts") ch.append_child_value("type", "EEG") info.desc().append_child_value("manufacturer", "SCCN") cap = info.desc().append_child("cap") cap.append_child_value("name", "EasyCap") cap.append_child_value("size", "54") cap.append_child_value("labelscheme", "10-20") # create outlet for the stream outlet = StreamOutlet(info) # (...normally here one might start sending data into the outlet...) # === the following could run on another computer === # first we resolve a stream whose name is MetaTester (note that there are # other ways to query a stream, too - for instance by content-type) results = resolve_stream("name", "MetaTester") # open an inlet so we can read the stream's data (and meta-data) inlet = StreamInlet(results[0]) # get the full stream info (including custom meta-data) and dissect it info = inlet.info() print("The stream's XML meta-data is: ") print(info.as_xml()) print("The manufacturer is: %s" % info.desc().child_value("manufacturer")) print("Cap circumference is: %s" % info.desc().child("cap").child_value("size")) print("The channel labels are as follows:") ch = info.desc().child("channels").child("channel") for k in range(info.channel_count()): print(" " + ch.child_value("label")) ch = ch.next_sibling() time.sleep(3)
class BetaInlet(object): def __init__(self): print("looking for an EEG stream...") streams = resolve_byprop("type", "EEG") # create a new inlet to read from the stream proc_flags = proc_clocksync | proc_dejitter | proc_monotonize self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) def update(self): max_samps = 3276*2 data = np.nan * np.ones((max_samps, 25), dtype=np.float32) _, timestamps = self.inlet.pull_chunk(max_samples=max_samps, dest_obj=data) data = data[:len(timestamps), :] return data, np.asarray(timestamps) def sampling_rate(self): return self.inlet.info().nominal_srate()
def _muse_get_recent(self, n_samples: int = 256, restart_inlet: bool = False): if self._muse_recent_inlet and not restart_inlet: inlet = self._muse_recent_inlet else: # Initiate a new lsl stream streams = resolve_byprop("type", "EEG", timeout=mlsl_cnsts.LSL_SCAN_TIMEOUT) if not streams: raise Exception( "Couldn't find any stream, is your device connected?") inlet = StreamInlet(streams[0], max_chunklen=mlsl_cnsts.LSL_EEG_CHUNK) self._muse_recent_inlet = inlet info = inlet.info() sfreq = info.nominal_srate() description = info.desc() n_chans = info.channel_count() self.sfreq = sfreq self.info = info self.n_chans = n_chans timeout = (n_samples / sfreq) + 0.5 samples, timestamps = inlet.pull_chunk(timeout=timeout, max_samples=n_samples) samples = np.array(samples) timestamps = np.array(timestamps) ch = description.child("channels").first_child() ch_names = [ch.child_value("label")] for i in range(n_chans): ch = ch.next_sibling() lab = ch.child_value("label") if lab != "": ch_names.append(lab) df = pd.DataFrame(samples, index=timestamps, columns=ch_names) return df
def __init__(self, stream_type='PPG', stream_id=None, buflen=5): """ stream_type: LSL type of the stream to check stream_id: will select specifically one stream based on its name "[stream_type]_[stream_id]" """ # first resolve said stream type on the network streams = resolve_stream('type',stream_type) self.nb_streams = 0 if len(streams) < 1: raise NameError('LSLTypeNotFound') print "Detecting", len(streams), stream_type, "streams" # create inlets to read from each stream self.inlets = [] # retrieve also corresponding StreamInfo for future uses (eg sampling rate) self.infos = [] for stream in streams: inlet = StreamInlet(stream, max_buflen=buflen) info = inlet.info() # if an ID is specified, will look only for it, otherwise add everything if stream_id is not None: if info.name() == stream_type + "_" + str(stream_id): # check that there is a unique stream with this name to stop right there any ambiguity if self.nb_streams > 0: raise NameError('LSLDuplicateStreamName') else: self.inlets.append(inlet) self.infos.append(info) self.nb_streams = self.nb_streams + 1 else: self.inlets.append(inlet) self.infos.append(info) self.nb_streams = self.nb_streams + 1 if stream_id and self.nb_streams < 1: raise NameError('LSLStreamNameNotFound') # init list of samples self.samples = [] * self.nb_streams
class MarkerInlet(object): def __init__(self): self.task = {'phase': 'precue', 'class': 1, 'target': 1} print("Looking for stream with type Markers") streams = resolve_bypred("type='Markers'", minimum=1) proc_flags = 0 # Marker events are relatively rare. No need to post-process. self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") stream_ch_names = [ ch_xml.child_value("label") for ch_xml in chan_xml_list ] print("Reading from inlet named {} with channels {}".format( stream_info.name(), stream_ch_names)) def update(self): marker_samples, marker_timestamps = self.inlet.pull_chunk(timeout=0.0) if (marker_timestamps): [phase_str, class_str, targ_str] = marker_samples[-1][0].split(', ') if phase_str in ['TargetCue']: self.task['phase'] = 'cue' elif phase_str in ['GoCue']: self.task['phase'] = 'go' elif phase_str in ['Miss', 'Hit']: self.task['phase'] = 'evaluate' elif phase_str[:8] == 'NewTrial': self.task['phase'] = 'precue' else: print(phase_str) self.task['class'] = int(class_str.split(' ')[1]) self.task['target'] = int(targ_str.split(' ')[1]) print("Marker inlet updated with task {}".format(self.task))
def getData(classifier, mu_ft, std_ft): print('looking for an EEG stream...') streams = resolve_stream('type', 'EEG') if len(streams) == 0: raise (RunTimeError('Cant find EEG stream :(')) window = 1 inlet = StreamInlet(streams[0]) info = inlet.info() descriptions = info.desc() sfreq = info.nominal_srate() n_samples = int(window * sfreq) n_chan = info.channel_count() print('Acquiring data...') data = np.zeros((n_samples, n_chan)) times = np.arange(-window, 0, 1. / sfreq) timer = time.time() while True: samples, timestamps = inlet.pull_chunk(timeout=1.0, max_samples=12) if timestamps: timestamps = np.float64( np.arange(len(timestamps)) ) #creates an array of numbers of numbers from 0 to length timestamps timestamps /= sfreq #divides that array by our sampling freq timestamps += times[-1] + 1 / sfreq # not sure times = np.concatenate( [times, timestamps]) #adds timestamps to the end of the times array times = times[-n_samples:] #takes the last n_samples from times data = np.vstack([data, samples ]) #adds our new samples to the data array data = data[-n_samples:] timer = time.time() n_samples, n_chan = data.shape epochs, remainder = tools.epoching(data, n_samples, samples_overlap=0) feature_matrix = tools.compute_feature_matrix(epochs, sfreq) y_hat = tools.classifier_test(classifier, feature_matrix, mu_ft, std_ft) print(y_hat)
class BciThread (threading.Thread): def __init__(self, name): threading.Thread.__init__(self) self.__streamsEEG = resolve_byprop('type', 'EEG', timeout=TIMEOUT) if len(self.__streamsEEG) == 0: raise RuntimeError("Can't find EEG stream.") self.__inlet = StreamInlet(self.__streamsEEG[0], max_chunklen=12) self.__eeg_time_correction = self.__inlet.time_correction() self.__info = self.__inlet.info() self.__fs = int(self.__info.nominal_srate()) self.name = name self.__lock = threading.Lock() self.__work = False self.__observers = set() def attach(self, observer: Observer): self.__observers.add(observer) def event(self, info): for observer in self.__observers: observer.update_data(info) def detach(self, observer: Observer): self.__observers.remove(observer) def run(self): self.__work = True while self.__work: eeg_data, timestamp = self.__inlet.pull_chunk(timeout=1, max_samples=int(SHIFT_LENGTH * self.__fs)) info = np.column_stack((timestamp, eeg_data)) self.event(info) def get_fs(self): return self.__fs def stop(self): self.__lock.acquire() self.__work = False self.__lock.release()
class MarkerInlet(object): def __init__(self): self.task = {'phase':'precue', 'class':1, 'target':1} print("Looking for stream with type Markers") streams = resolve_bypred("type='Markers'", minimum=1) proc_flags = 0 # Marker events are relatively rare. No need to post-process. self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") stream_ch_names = [ch_xml.child_value("label") for ch_xml in chan_xml_list] print("Reading from inlet named {} with channels {}".format(stream_info.name(), stream_ch_names)) def update(self): marker_samples, marker_timestamps = self.inlet.pull_chunk(timeout=0.0) if (marker_timestamps): [phase_str, class_str, targ_str] = marker_samples[-1][0].split(', ') if phase_str in ['TargetCue']: self.task['phase'] = 'cue' elif phase_str in ['GoCue']: self.task['phase'] = 'go' elif phase_str in ['Miss', 'Hit']: self.task['phase'] = 'evaluate' elif phase_str[:8] == 'NewTrial': self.task['phase'] = 'precue' else: print(phase_str) self.task['class'] = int(class_str.split(' ')[1]) self.task['target'] = int(targ_str.split(' ')[1]) print("Marker inlet updated with task {}".format(self.task))
def getData(runtime=60): print('looking for an EEG stream...') runTime = runtime streams = resolve_stream('type', 'EEG') if len(streams) == 0: raise (RunTimeError('Cant find EEG stream :(')) window = 1 inlet = StreamInlet(streams[0]) info = inlet.info() descriptions = info.desc() sfreq = info.nominal_srate() n_samples = int(window * sfreq) n_chan = info.channel_count() print('Acquiring data...') data = np.zeros((1, n_chan)) times = np.arange(-window, 0, 1. / sfreq) timer = time.time() end = timer + runTime while end > timer: samples, timestamps = inlet.pull_chunk(timeout=1.0, max_samples=12) if timestamps: timestamps = np.float64( np.arange(len(timestamps)) ) #creates an array of numbers of numbers from 0 to length timestamps timestamps /= sfreq #divides that array by our sampling freq timestamps += times[-1] + 1 / sfreq # not sure times = np.concatenate( [times, timestamps]) #adds timestamps to the end of the times array times = times[-n_samples:] #takes the last n_samples from times data = np.vstack([data, samples ]) #adds our new samples to the data array timer = time.time() data = np.delete(data, 0, 0) #deletes first column of zeros return data, sfreq
def inlet_to_dict(inlet: StreamInlet) -> dict: """convert inlet information into a dictionary args ---- inlet: pylsl.StreamInlet the inlet to convert into a dictionary returns ------- output: dict a dictionary of key information parsed from the xml Example:: import liesl stream = liesl.open_stream() d = liesl.inlet_to_dict(stream) """ return streaminfoxml_to_dict(inlet.info().as_xml())
def _muse_get_recent(self, max_samples=100, restart_inlet=False): if self._muse_recent_inlet and restart_inlet == False: inlet = self._muse_recent_inlet else: # Initiate a new lsl stream streams = resolve_byprop('type', 'EEG', timeout=mlsl_cnsts.LSL_SCAN_TIMEOUT) inlet = StreamInlet(streams[0], max_chunklen=mlsl_cnsts.LSL_EEG_CHUNK) self._muse_recent_inlet = inlet _ = inlet.pull_chunk() # seems to be necessary to do this first... time.sleep(1) samples, timestamps = inlet.pull_chunk(timeout=0.0, max_samples=max_samples) samples = np.array(samples) timestamps = np.array(timestamps) info = inlet.info() description = info.desc() sfreq = info.nominal_srate() #window = 10 #n_samples = int(self.sfreq * window) n_chans = info.channel_count() ch = description.child('channels').first_child() ch_names = [ch.child_value('label')] for i in range(n_chans): ch = ch.next_sibling() lab = ch.child_value('label') if lab != '': ch_names.append(lab) df = pd.DataFrame(samples, index=timestamps, columns=ch_names) return df
class Receive(Node): """Receive from a LSL stream. Attributes: o (Port): Default output, provides DataFrame and meta. Args: prop (string): The property to look for during stream resolution (e.g., ``name``, ``type``, ``source_id``). value (string): The value that the property should have (e.g., ``EEG`` for the type property). timeout (float): The resolution timeout, in seconds. unit (string): Unit of the timestamps (e.g., ``s``, ``ms``, ``us``, ``ns``). The LSL library uses seconds by default. Timeflux uses nanoseconds. Default: ``s``. sync (string, None): The method used to synchronize timestamps. Use ``local`` if you receive the stream from another application on the same computer. Use ``network`` if you receive from another computer. Use ``None`` if you receive from a Timeflux instance on the same computer. channels (list, None): Override the channel names. If ``None``, the names defined in the LSL stream will be used. max_samples (int): The maximum number of samples to return per call. Example: .. literalinclude:: /../examples/lsl_multiple.yaml :language: yaml """ def __init__( self, prop="name", value=None, timeout=1.0, unit="s", sync="local", channels=None, max_samples=1024, ): if not value: raise ValueError( "Please specify a stream name or a property and value.") self._prop = prop self._value = value self._inlet = None self._labels = None self._unit = unit self._sync = sync self._channels = channels self._timeout = timeout self._max_samples = max_samples self._offset = np.timedelta64( int((time() - pylsl.local_clock()) * 1e9), "ns") def update(self): if not self._inlet: self.logger.debug( f"Resolving stream with {self._prop} {self._value}") streams = resolve_byprop(self._prop, self._value, timeout=self._timeout) if not streams: return self.logger.debug("Stream acquired") self._inlet = StreamInlet(streams[0]) info = self._inlet.info() self._meta = { "name": info.name(), "type": info.type(), "rate": info.nominal_srate(), "info": str(info.as_xml()).replace("\n", "").replace("\t", ""), } if isinstance(self._channels, list): self._labels = self._channels else: description = info.desc() channel = description.child("channels").first_child() self._labels = [channel.child_value("label")] for _ in range(info.channel_count() - 1): channel = channel.next_sibling() self._labels.append(channel.child_value("label")) if self._inlet: values, stamps = self._inlet.pull_chunk( max_samples=self._max_samples) if stamps: stamps = pd.to_datetime(stamps, format=None, unit=self._unit) if self._sync == "local": stamps += self._offset elif self._sync == "network": stamps = (stamps + np.timedelta64( self._inlet.time_correction() * 1e9, "ns") + self._offset) self.o.set(values, stamps, self._labels, self._meta)
""" 1. CONNECT TO EEG STREAM """ # Search for active LSL stream print('Looking for an EEG stream...') streams = resolve_byprop('type', 'EEG', timeout=2) if len(streams) == 0: raise RuntimeError('Can\'t find EEG stream.') # Set active EEG stream to inlet and apply time correction print("Start acquiring data") inlet = StreamInlet(streams[0], max_chunklen=12) eeg_time_correction = inlet.time_correction() # Get the stream info, description, sampling frequency, number of channels info = inlet.info() description = info.desc() fs = int(info.nominal_srate()) n_channels = info.channel_count() # Get names of all channels ch = description.child('channels').first_child() ch_names = [ch.child_value('label')] for i in range(1, n_channels): ch = ch.next_sibling() ch_names.append(ch.child_value('label')) """ 2. SET EXPERIMENTAL PARAMETERS """ # Length of the EEG data buffer (in seconds) # This buffer will hold last n seconds of data and be used for calculations
ch.append_child_value("label",label) ch.append_child_value("unit","microvolts") ch.append_child_value("type","EEG") info.desc().append_child_value("manufacturer","SCCN") cap = info.desc().append_child("cap") cap.append_child_value("name","EasyCap") cap.append_child_value("size","54") cap.append_child_value("labelscheme","10-20") # create outlet for the stream outlet = StreamOutlet(info) # === the following could run on another computer === # resolve the stream and open an inlet results = resolve_stream("name","MetaTester") inlet = StreamInlet(results[0]) # get the full stream info (including custom meta-data) and dissect it inf = inlet.info() print "The stream's XML meta-data is: " print inf.as_xml() print "The manufacturer is: " + inf.desc().child_value("manufacturer") print "The cap circumference is: " + inf.desc().child("cap").child_value("size") print "The channel labels are as follows:" ch = inf.desc().child("channels").child("channel") for k in range(info.channel_count()): print " " + ch.child_value("label") ch = ch.next_sibling() time.sleep(3)
class MyOVBox(OVBox): def __init__(self): OVBox.__init__(self) # the initialize method reads settings and outputs the first header def initialize(self): self.initLabel = 0 self.debug=self.setting['debug'] == "true" print "Debug: ", self.debug self.stream_type=self.setting['Stream type'] self.stream_name=self.setting['Stream name'] # total channels for all streams self.channelCount = 0 #self.stream_name=self.setting['Stream name'] # in case !all_streams print "Looking for streams of type: " + self.stream_type streams = resolve_stream('type',self.stream_type) print "Nb streams: " + str( len(streams)) self.nb_streams = len(streams) if self.nb_streams == 0: raise Exception("Error: no stream found.") self.inlet = StreamInlet(streams[0], max_buflen=1) self.info = self.inlet.info() self.channelCount = self.info.channel_count() print "Stream name: " + self.info.name() stream_freq = self.info.nominal_srate() if stream_freq != 0: raise Exception("Error: no irregular stream found.") # we append to the box output a stimulation header. This is just a header, dates are 0. self.output[0].append(OVStimulationHeader(0., 0.)) self.init = False # The process method will be called by openvibe on every clock tick def process(self): # A stimulation set is a chunk which starts at current time and end time is the time step between two calls # init here and filled within triger() self.stimSet = OVStimulationSet(self.getCurrentTime(), self.getCurrentTime()+1./self.getClock()) if self.init == False : local_time = local_clock() initSecond=int(local_time) initMillis=int((local_time-initSecond)*1000) self.stimSet.append(OVStimulation(self.initLabel, self.getCurrentTime(), 0.)) self.stimSet.append(OVStimulation(initSecond, self.getCurrentTime(), 0.)) self.stimSet.append(OVStimulation(initMillis, self.getCurrentTime(), 0.)) self.init=True # read all available stream samples=[] sample,timestamp = self.inlet.pull_sample(0) while sample != None: samples += sample sample,timestamp = self.inlet.pull_sample(0) # every value will be converted to openvibe code and a stim will be create for label in samples: label = str(label) if self.debug: print "Got label: ", label self.stimSet.append(OVStimulation(float(label), self.getCurrentTime(), 0.)) # even if it's empty we have to send stim list to keep the rest in sync self.output[0].append(self.stimSet) def uninitialize(self): # we send a stream end. end = self.getCurrentTime() self.output[0].append(OVStimulationEnd(end, end)) self.inlet.close_stream()
def initialize(self): # settings are retrieved in the dictionary try: self.samplingFrequency = int(self.setting['Sampling frequency']) except: print "Sampling frequency not set or error while parsing." self.samplingFrequency = 0 print "Sampling frequency: " + str(self.samplingFrequency) self.epochSampleCount = int(self.setting['Generated epoch sample count']) self.stream_type=self.setting['Stream type'] # total channels for all streams self.channelCount = 0 all_streams = self.setting['Get all streams'] == "true" self.stream_name=self.setting['Stream name'] # in case !all_streams print "Looking for streams of type: " + self.stream_type streams = resolve_stream('type',self.stream_type) print "Nb streams: " + str( len(streams)) if not all_streams: print "Will only select (first) stream named: " + self.stream_name self.nb_streams = 1 else: self.nb_streams = len(streams) # create inlets to read from each stream self.inlets = [] # retrieve also corresponding StreamInfo for future uses (eg sampling rate) self.infos = [] # save inlets and info + build signal header for stream in streams: inlet = StreamInlet(stream) info = inlet.info() name = info.name() print "Stream name: " + name # if target one stream, ignore false ones if not all_streams and name != self.stream_name: continue print "Nb channels: " + str(info.channel_count()) self.channelCount += info.channel_count() stream_freq = info.nominal_srate() print "Sampling frequency: " + str(stream_freq) if self.samplingFrequency == 0: print "Set sampling frequency to:" + str(stream_freq) self.samplingFrequency = stream_freq elif self.samplingFrequency != stream_freq: print "WARNING: sampling frequency of current stream (" + str(stream_freq) + ") differs from option set to box (" + str(self.samplingFrequency) + ")." for i in range(info.channel_count()): self.dimensionLabels.append(name + ":" + str(i)) # We must delay real inlet/info init because we may know the defifitive sampling frequency # limit buflen just to what we need to fill each chuck, kinda drift correction # TODO: not a very pretty code... buffer_length = int(ceil(float(self.epochSampleCount) / self.samplingFrequency)) print "LSL buffer length: " + str(buffer_length) inlet = StreamInlet(stream, max_buflen=buffer_length) info = inlet.info() self.inlets.append(inlet) self.infos.append(info) # if we're still here when we target a stream, it means we foand it if not all_streams: print "Found target stream" break # we need at least one stream before we let go if self.channelCount <= 0: raise Exception("Error: no stream found.") # backup last values pulled in case pull(timeout=0) return None later self.last_values = self.channelCount*[0] self.dimensionLabels += self.epochSampleCount*[''] self.dimensionSizes = [self.channelCount, self.epochSampleCount] self.signalHeader = OVSignalHeader(0., 0., self.dimensionSizes, self.dimensionLabels, self.samplingFrequency) self.output[0].append(self.signalHeader) #creation of the first signal chunk self.endTime = 1.*self.epochSampleCount/self.samplingFrequency self.signalBuffer = numpy.zeros((self.channelCount, self.epochSampleCount)) self.updateTimeBuffer() self.updateSignalBuffer()
"""Example program to show how to read a marker time series from LSL.""" import sys sys.path.append('./pylsl') # help python find pylsl relative to this example program from pylsl import StreamInlet, resolve_stream # first resolve an EEG stream on the lab network print("looking for an BatteryStatus stream...") streams = resolve_stream('name', 'BatteryStatus') streamsFound = len(streams) if (streamsFound > 0): print 'found ' + str(streamsFound) else: print 'found none' # create a new inlet to read from the stream inlet = StreamInlet(streams[0]) hostName = inlet.info().hostname() while True: sample, timestamp = inlet.pull_sample() if(sample): print(str(timestamp) + ' Battery Status of ' + hostName + ' ' + str(sample[0]) +'%')