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 update(self): now = local_clock() if (now > self.next_transition): # Transition phase self.in_phase = self.phases[self.in_phase]['next'] self.next_transition = now + self.phases[self.in_phase]['duration'] # Send markers out_string = "undefined" if self.in_phase == 'precue': # transition from evaluate to precue # print("Previous class_id: {}, target_id: {}".format(self.class_id, self.target_id)) self.trial_ix += 1 self.target_id = random.choice(self.target_list) if self.targets_rand else self.target_list[ (self.target_list.index(self.target_id) + 1) % len(self.target_list)] self.class_id = random.choice(self.class_list) if self.classes_rand else self.class_list[ (self.class_list.index(self.class_id) + 1) % len(self.class_list)] # print("New class_id: {}, target_id: {}".format(self.class_id, self.target_id)) out_string = "NewTrial {}, Class {}, Target {}".format(self.trial_ix, self.class_id, self.target_id) elif self.in_phase == 'cue': # transition from precue to cue out_string = "TargetCue, Class {}, Target {}".format(self.class_id, self.target_id) elif self.in_phase == 'go': # transition from cue to go out_string = "GoCue, Class {}, Target {}".format(self.class_id, self.target_id) elif self.in_phase == 'evaluate': # transition from go to evaluate hit_string = "Hit" if random.randint(0, 1) == 1 else "Miss" out_string = "{}, Class {}, Target {}".format(hit_string, self.class_id, self.target_id) print("Marker outlet pushing string: {}".format(out_string)) self.outlet.push_sample([out_string,]) return True return False
def __init__(self, stream, buf_size, col="w", chnames=False, invert=False): """ Initializes the grapher. Args: stream: <pylsl.StreamInfo instance> pointer to a stream buf_size: <integer> visualization buffer length in samples col: <char> color of the line plot (b,r,g,c,m,y,k and w) """ self.stream = stream self.inlet = pylsl.StreamInlet(stream) self.buf_size = buf_size self.channel_count = self.inlet.channel_count self.gbuffer = np.zeros(self.buf_size * self.channel_count) self.gtimes = np.zeros(self.buf_size) + pylsl.local_clock() self.col = col if chnames: if self.channel_count == len(chnames): self.chnames = chnames else: print("Channel names vs channel count mismatch, skipping") else: self.chnames = False if invert: pg.setConfigOption("background", "w") pg.setConfigOption("foreground", "k") self.fill_buffer() self.start_graph()
def update(self, task={'phase': 'precue', 'class': 1}): # Convert phase and class_id into beta_amp if task['phase'] in ['cue', 'go']: beta_amp = 0 if task['class'] == 3 else self.AmpBeta else: beta_amp = self.AmpBeta / 5.0 this_tvec = self.tvec + self.last_time # Sample times # Put the signal together this_sig = self.AmpNoise * np.asarray(self.pinkNoiseGen.generate(), dtype=np.float32) # Start with some pink noise this_sig += beta_amp * np.sin(this_tvec * 2 * np.pi * self.FreqBeta) # Add our beta signal this_sig = np.atleast_2d(this_sig).T * np.ones((1, len(self.channels)), dtype=np.float32) # Tile across channels time_to_sleep = max(0, this_tvec[-1] - local_clock()) time.sleep(time_to_sleep) print("Beta outlet pushing signal with shape {},{} and Beta amp {}".format(this_sig.shape[0], this_sig.shape[1], beta_amp)) self.eeg_outlet.push_chunk(this_sig, timestamp=this_tvec[-1]) self.last_time = local_clock()
def __init__(self, Fs=2**14, FreqBeta=20.0, AmpBeta=100.0, AmpNoise=20.0, NCyclesPerChunk=4, channels=["RAW1", "SPK1", "RAW2", "SPK2", "RAW3", "SPK3"]): """ :param Fs: Sampling rate :param FreqBeta: Central frequency of beta band :param AmpBeta: Amplitude of beta (uV) :param AmpNoise: Amplitude of pink noise (uV) :param NCyclesPerChunk: Minimum number of cycles of beta in a chunk. :param channels: List of channel names """ # Saved arguments self.FreqBeta = FreqBeta self.AmpBeta = AmpBeta # Amplitude of Beta (uV) self.AmpNoise = AmpNoise # Amplitude of pink noise self.channels = channels # Derived variables chunk_dur = NCyclesPerChunk / self.FreqBeta # Duration, in sec, of one chunk chunk_len = int(Fs * chunk_dur) # Number of samples in a chunk self.tvec = 1.0 * (np.arange(chunk_len) + 1) / Fs # time vector for chunk (sec) # Pink noise generator self.pinkNoiseGen = PinkNoiseGenerator(nSampsPerBlock=chunk_len) # Create a stream of fake 'raw' data raw_info = StreamInfo(name='BetaGen', type='EEG', channel_count=len(self.channels), nominal_srate=Fs, channel_format='float32', source_id='betagen1234') raw_xml = raw_info.desc() chans = raw_xml.append_child("channels") for channame in self.channels: chn = chans.append_child("channel") chn.append_child_value("label", channame) chn.append_child_value("unit", "microvolts") chn.append_child_value("type", "generated") self.eeg_outlet = StreamOutlet(raw_info) print("Created outlet with name BetaGen and type EEG") self.last_time = local_clock()
tracker = EyeLink("100.1.1.1") print "Established a primary connection with the eye tracker." # uncomment if you want to get pupil size in diameter, otherwise it is the area # tracker.setPupilSizeDiameter(YES) # tracker.setVelocityThreshold(22) beginRealTimeMode(100) getEYELINK().openDataFile(edfFileName) getEYELINK().startRecording(1, 1, 1, 1) print "Now reading samples..." print "Press \'Esc\' to quit" while quit != 1: sample = getEYELINK().getNewestSample() quit = getEYELINK().escapePressed(); if sample is not None: now = pylsl.local_clock() ppd = sample.getPPD() #values = [0,0, 0,0, 0, 0, sample.getTargetX(),sample.getTargetY(),sample.getTargetDistance(), ppd[0],ppd[1]] values = [0,0, 0,0, 0, 0, ppd[0],ppd[1], sample.getTime(), now] if (sample.isLeftSample()) or (sample.isBinocular()): values[0:2] = sample.getLeftEye().getGaze() values[4] = sample.getLeftEye().getPupilSize() if (sample.isRightSample()) or (sample.isBinocular()): values[2:4] = sample.getRightEye().getGaze() values[5] = sample.getRightEye().getPupilSize() outlet.push_sample(pylsl.vectord(values), now, True) time.sleep(1.0/SR)
# first create a new stream info (here we set the name to BioSemi, # the content-type to EEG, 8 channels, 100 Hz, and float-valued data) The # last value would be the serial number of the device or some other more or # less locally unique identifier for the stream as far as available (you # could also omit it but interrupted connections wouldn't auto-recover) fs = 1000 info = StreamInfo('python', 'EEG', 2) # next make an outlet outlet = StreamOutlet(info) from pylsl import StreamInlet, resolve_stream print('resolving stream') streams = resolve_stream('name', 'matlab') # create a new inlet to read from the stream inlet = StreamInlet(streams[0]) print('resolved') t = 0 mean_time = 0 while True: #time.sleep(0.002) t += 1 clock = local_clock() outlet.push_sample([0, 1]) sample, timestamp = inlet.pull_sample(timeout=1) dt = local_clock() - clock mean_time += dt print(mean_time / t, dt) #time.sleep(0.001)
def get_prob(self, timestamp=False): """ Read the latest window Input ----- timestamp: If True, returns LSL timestamp of the leading edge of the window used for decoding. Returns ------- The likelihood P(X|C), where X=window, C=model """ if self.fake: # fake deocder: biased likelihood for the first class probs = [random.uniform(0.0, 1.0)] # others class likelihoods are just set to equal p_others = (1 - probs[0]) / (len(self.labels) - 1) for x in range(1, len(self.labels)): probs.append(p_others) time.sleep(0.0625) # simulated delay t_prob = pylsl.local_clock() else: self.sr.acquire(blocking=True) w, ts = self.sr.get_window() # w = times x channels t_prob = ts[-1] w = w.T # -> channels x times # re-reference channels # TODO: add re-referencing function to preprocess() # apply filters. Important: maintain the original channel order at this point. w = pu.preprocess(w, sfreq=self.sfreq, spatial=self.spatial, spatial_ch=self.spatial_ch, spectral=self.spectral, spectral_ch=self.spectral_ch, notch=self.notch, notch_ch=self.notch_ch, multiplier=self.multiplier, decim=self.decim) # select the same channels used for training w = w[self.picks] # debug: show max - min # c=1; print( '### %d: %.1f - %.1f = %.1f'% ( self.picks[c], max(w[c]), min(w[c]), max(w[c])-min(w[c]) ) ) # psd = channels x freqs psd = self.psde.transform(w.reshape((1, w.shape[0], w.shape[1]))) # make a feautre vector and classify feats = np.concatenate(psd[0]).reshape(1, -1) # compute likelihoods probs = self.cls.predict_proba(feats)[0] # update psd buffer ( < 1 msec overhead ) ''' if self.psd_buffer is None: self.psd_buffer = psd else: self.psd_buffer = np.concatenate((self.psd_buffer, psd), axis=0) # TODO: CHECK THIS BLOCK self.ts_buffer.append(ts[0]) if ts[0] - self.ts_buffer[0] > self.buffer_sec: # search speed comparison for ordered arrays: # http://stackoverflow.com/questions/16243955/numpy-first-occurence-of-value-greater-than-existing-value #t_index = np.searchsorted(self.ts_buffer, ts[0] - 1.0) t_index = np.searchsorted(self.ts_buffer, ts[0] - self.buffer_sec) self.ts_buffer = self.ts_buffer[t_index:] self.psd_buffer = self.psd_buffer[t_index:, :, :] # numpy delete is slower # assert ts[0] - self.ts_buffer[0] <= self.buffer_sec ''' if timestamp: return probs, t_prob else: return probs
# the content-type to EEG, 8 channels, 100 Hz, and float-valued data) The # last value would be the serial number of the device or some other more or # less locally unique identifier for the stream as far as available (you # could also omit it but interrupted connections wouldn't auto-recover) fs = 1000 info = StreamInfo('BioSemi', 'EEG', 2) # next make an outlet outlet = StreamOutlet(info) print("now sending data...") n_samples = fs * 100 recorder = np.zeros((n_samples, 2)) t = 0 t_start = local_clock() while True: if t > n_samples - 2: break clock = local_clock() if clock - t_start > (t+1)/fs: # make a new random 8-channel sample; this is converted into a # pylsl.vectorf (the data type that is expected by push_sample) second = int(clock) mysample = [clock, int(second%5 == 0) if second - t_start > 5 else -1] t += 1 outlet.push_sample(mysample, clock) recorder[t] = mysample print(local_clock() - t_start) np.save('sent_data.npy', recorder)
def drawAndRecordConfigSeq(dot, lslStream, sequence, pygameWindow): """ Draws the configuration sequence on the screen and sends dot positions to LSL. Keywords arguments: dot ---------- MovingDot object, which is used to store information about the current position of the dot. lslStream ---- LSL StreamOutlet object, which is used to stream positions of the dot to LSL. sequence ----- Array of tuples, which stores the tour of the dot. pygameWindow - Pygame window object to visualize the Experiment. """ # Create a Clock object. clock = pygame.time.Clock() # Display dot at start position until # subject press a button. pygameWindow.fill(GRAY) pygame.draw.circle(pygameWindow, WHITE, (dot.x, dot.y), dot.size, THICKNESS) pygame.display.update() eventOcc = False while True: if eventOcc: break for event in pygame.event.get(): if event.type == KEYDOWN and event.key == K_RETURN: eventOcc = True # Start the calibration sequence. for part in sequence: # Check whether you have fixation or smooth persuit. if (part[1]==0 and part[2]==0): # fixation dot.x = part[0][0] dot.y = part[0][1] dot.dx = 0 dot.dy = 0 pygameWindow.fill(GRAY) pygame.draw.circle(pygameWindow, WHITE, (dot.x, dot.y), dot.size, THICKNESS) pygame.display.update() startTime = currentTime() while (currentTime() < startTime+FIXATIONTIME): pygameWindow.fill(GRAY) pygame.draw.circle(pygameWindow, WHITE, (dot.x, dot.y), dot.size, THICKNESS) clock.tick(SAMPLERATE) pygame.display.update() lslStream.push_sample([dot.x, dot.y], pylsl.local_clock()) else: # smooth persuit pygameWindow.fill(GRAY) pygame.draw.circle(pygameWindow, WHITE, (dot.x, dot.y), dot.size, THICKNESS) clock.tick(SAMPLERATE) pygame.display.update() lslStream.push_sample([dot.x, dot.y], pylsl.local_clock()) dot.dx = part[1] dot.dy = part[2] dot.calcDirection() while True: dot.move() pygameWindow.fill(GRAY) pygame.draw.circle(pygameWindow, WHITE, (dot.x, dot.y), dot.size, THICKNESS) clock.tick(SAMPLERATE) pygame.display.update() lslStream.push_sample([dot.x, dot.y], pylsl.local_clock()) if dot.reachedGoal(part[0]): break # Indicate that the calibration sequence is over. afterTime = currentTime() while (currentTime() < afterTime+500): lslStream.push_sample([-100, -100], pylsl.local_clock())
# graphics def loadImage(filename): return visual.ImageStim(win=mywin, image=filename) mywin = visual.Window([1920, 1080], monitor="testMonitor", units="deg", fullscr=True) targets = map(loadImage, glob('stimulus_presentation/stim/cats_dogs/target-*.jpg')) nontargets = map(loadImage, glob('stimulus_presentation/stim/cats_dogs/nontarget-*.jpg')) for ii, trial in trials.iterrows(): # inter trial interval core.wait(iti + np.random.rand() * jitter) # onset pos = trials['position'].iloc[ii] image = choice(targets if pos == 1 else nontargets) image.draw() timestamp = local_clock() outlet.push_sample([markernames[pos]], timestamp) mywin.flip() # offset core.wait(soa) mywin.flip() if len(event.getKeys()) > 0 or (time() - start) > record_duration: break event.clearEvents() # Cleanup mywin.close()
def add_trial(self, label): self.trial_time_stamps.append(pylsl.local_clock()) self.Y.append(label)
import time import random from pylsl import local_clock for i in range(20): t1 = local_clock() t2 = time.time() print(t2 - t1) time.sleep(random.random() * 10)
def stream_player(fif_file, server_name='StreamPlayer', chunk_size=8, auto_restart=True, wait_start=True, repeat=float('inf'), high_resolution=False, trigger_file=None): """ Input ===== server_name: LSL server name. fif_file: fif file to replay. chunk_size: number of samples to send at once (usually 16-32 is good enough). auto_restart: play from beginning again after reaching the end. wait_start: wait for user to start in the beginning. repeat: number of loops to play. high_resolution: use perf_counter() instead of sleep() for higher time resolution but uses much more cpu due to polling. trigger_file: used to convert event numbers into event strings for readability. Note: Run pycnbi.set_log_level('DEBUG') to print out the relative time stamps since started. """ raw, events = pu.load_raw(fif_file) sfreq = raw.info['sfreq'] # sampling frequency n_channels = len(raw.ch_names) # number of channels if trigger_file is not None: tdef = trigger_def(trigger_file) try: event_ch = raw.ch_names.index('TRIGGER') except ValueError: event_ch = None if raw is not None: logger.info_green('Successfully loaded %s' % fif_file) logger.info('Server name: %s' % server_name) logger.info('Sampling frequency %.3f Hz' % sfreq) logger.info('Number of channels : %d' % n_channels) logger.info('Chunk size : %d' % chunk_size) for i, ch in enumerate(raw.ch_names): logger.info('%d %s' % (i, ch)) logger.info('Trigger channel : %s' % event_ch) else: raise RuntimeError('Error while loading %s' % fif_file) # set server information sinfo = pylsl.StreamInfo(server_name, channel_count=n_channels, channel_format='float32',\ nominal_srate=sfreq, type='EEG', source_id=server_name) desc = sinfo.desc() channel_desc = desc.append_child("channels") for ch in raw.ch_names: channel_desc.append_child('channel').append_child_value('label', str(ch))\ .append_child_value('type','EMG').append_child_value('unit','microvolts') desc.append_child('amplifier').append_child('settings').append_child_value('is_slave', 'false') desc.append_child('acquisition').append_child_value('manufacturer', 'PyCNBI').append_child_value('serial_number', 'N/A') outlet = pylsl.StreamOutlet(sinfo, chunk_size=chunk_size) # if wait_start: # input('Press Enter to start streaming.') logger.info('Streaming started') idx_chunk = 0 t_chunk = chunk_size / sfreq finished = False if high_resolution: t_start = time.perf_counter() else: t_start = time.time() # start streaming played = 1 while played < repeat: idx_current = idx_chunk * chunk_size chunk = raw._data[:, idx_current:idx_current + chunk_size] data = chunk.transpose().tolist() if idx_current >= raw._data.shape[1] - chunk_size: finished = True if high_resolution: # if a resolution over 2 KHz is needed t_sleep_until = t_start + idx_chunk * t_chunk while time.perf_counter() < t_sleep_until: pass else: # time.sleep() can have 500 us resolution using the tweak tool provided. t_wait = t_start + idx_chunk * t_chunk - time.time() if t_wait > 0.001: time.sleep(t_wait) outlet.push_chunk(data) logger.debug('[%8.3fs] sent %d samples (LSL %8.3f)' % (time.perf_counter(), len(data), pylsl.local_clock())) if event_ch is not None: event_values = set(chunk[event_ch]) - set([0]) if len(event_values) > 0: if trigger_file is None: logger.info('Events: %s' % event_values) else: for event in event_values: if event in tdef.by_value: logger.info('Events: %s (%s)' % (event, tdef.by_value[event])) else: logger.info('Events: %s (Undefined event)' % event) idx_chunk += 1 if finished: if auto_restart is False: input('Reached the end of data. Press Enter to restart or Ctrl+C to stop.') else: logger.info('Reached the end of data. Restarting.') idx_chunk = 0 finished = False if high_resolution: t_start = time.perf_counter() else: t_start = time.time() played += 1
def log_decoding(decoder, logfile, amp_name=None, amp_serial=None, pklfile=True, matfile=False, autostop=False, prob_smooth=False): """ Decode online and write results with event timestamps input ----- decoder: Decoder or DecoderDaemon class object. logfile: File name to contain the result in Python pickle format. amp_name: LSL server name (if known). amp_serial: LSL server serial number (if known). pklfile: Export results to Python pickle format. matfile: Export results to Matlab .mat file if True. autostop: Automatically finish when no more data is received. prob_smooth: Use smoothed probability values according to decoder's smoothing parameter. """ import cv2 import scipy # run event acquisition process in the background state = mp.Value('i', 1) event_queue = mp.Queue() proc = mp.Process(target=log_decoding_helper, args=[state, event_queue, amp_name, amp_serial, autostop]) proc.start() logger.info_green('Spawned event acquisition process.') # init variables and choose decoding function labels = decoder.get_label_names() probs = [] prob_times = [] if prob_smooth: decode_fn = decoder.get_prob_smooth_unread else: decode_fn = decoder.get_prob_unread # simple controller UI cv2.namedWindow("Decoding", cv2.WINDOW_AUTOSIZE) cv2.moveWindow("Decoding", 1400, 50) img = np.zeros([100, 400, 3], np.uint8) cv2.putText(img, 'Press any key to start', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2, cv2.LINE_AA) cv2.imshow("Decoding", img) cv2.waitKeyEx() img *= 0 cv2.putText(img, 'Press ESC to stop', (40, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2, cv2.LINE_AA) cv2.imshow("Decoding", img) key = 0 started = False tm_watchdog = qc.Timer(autoreset=True) tm_cls = qc.Timer() while key != 27: prob, prob_time = decode_fn(True) t_lsl = pylsl.local_clock() key = cv2.waitKeyEx(1) if prob is None: # watch dog if tm_cls.sec() > 5: if autostop and started: logger.info('No more streaming data. Finishing.') break tm_cls.reset() tm_watchdog.sleep_atleast(0.001) continue probs.append(prob) prob_times.append(prob_time) txt = '[%.3f] ' % prob_time txt += ', '.join(['%s: %.2f' % (l, p) for l, p in zip(labels, prob)]) txt += ' (%d ms, LSL Diff = %.3f)' % (tm_cls.msec(), (t_lsl-prob_time)) logger.info(txt) if not started: started = True tm_cls.reset() # finish up processes cv2.destroyAllWindows() logger.info('Cleaning up event acquisition process.') state.value = 0 decoder.stop() event_times, event_values = event_queue.get() proc.join() # save values if len(prob_times) == 0: logger.error('No decoding result. Please debug.') import pdb pdb.set_trace() t_start = prob_times[0] probs = np.vstack(probs) event_times = np.array(event_times) - t_start prob_times = np.array(prob_times) - t_start event_values = np.array(event_values) data = dict(probs=probs, prob_times=prob_times, event_times=event_times, event_values=event_values, labels=labels) if pklfile: qc.save_obj(logfile, data) logger.info('Saved to %s' % logfile) if matfile: pp = qc.parse_path(logfile) matout = '%s/%s.mat' % (pp.dir, pp.name) scipy.io.savemat(matout, data) logger.info('Saved to %s' % matout)
"EEG", len(headset.channel_mask), headset.sampling_rate, pylsl.cf_int16, str(headset.serial_number), ) info_desc = info.desc() info_desc.append_child_value("manufacturer", "Emotiv") channels = info_desc.append_child("channels") for ch in headset.channel_mask: channels.append_child("channel").append_child_value("label", ch).append_child_value( "unit", "microvolts" ).append_child_value("type", "EEG") # Outgoing buffer size = 360 seconds, transmission chunk size = 32 samples outlet = pylsl.stream_outlet(info, 1, 32) while True: try: s = headset.get_sample() except epoc.EPOCTurnedOffError, e: print "Headset is turned off, waiting..." time.sleep(0.02) else: if s: outlet.push_sample(pylsl.vectori(s), pylsl.local_clock()) headset.disconnect()
import sys; sys.path.append('..') # help python find pylsl relative to this example program from pylsl import StreamInfo, StreamOutlet, local_clock import random import time # first create a new stream info (here we set the name to BioSemi, the content-type to EEG, 8 channels, 100 Hz, and float-valued data) # The last value would be the serial number of the device or some other more or less locally unique identifier for the stream as far as available (you could also omit it but interrupted connections wouldn't auto-recover). info = StreamInfo('BioSemi','EEG',8,100,'float32','myuid2424'); # append some meta-data info.desc().append_child_value("manufacturer","BioSemi") channels = info.desc().append_child("channels") for c in ["C3","C4","Cz","FPz","POz","CPz","O1","O2"]: channels.append_child("channel").append_child_value("name",c).append_child_value("unit","microvolts").append_child_value("type","EEG") # next make an outlet; we set the transmission chunk size to 32 samples and the outgoing buffer size to 360 seconds (max.) outlet = StreamOutlet(info,32,360) print("now sending data...") while True: # make a new random 8-channel sample; this is converted into a pylsl.vectorf (the data type that is expected by push_sample) mysample = [random.random(),random.random(),random.random(),random.random(),random.random(),random.random(),random.random(),random.random()] # get a time stamp in seconds (we pretend that our samples are actually 125ms old, e.g., as if coming from some external hardware) stamp = local_clock()-0.125 # now send it and wait for a bit outlet.push_sample(mysample,stamp) time.sleep(0.01)
print("LSL INCOMING TRIGGERS TEST\n") name = "stream_trigger2" si = lsl.StreamInfo(name=name, type='Markers', source_id='testing_dep', channel_format=lsl.cf_string) so = lsl.stream_outlet(si) print("It will take 5 seconds to start sending triggers...") time.sleep( 5 ) # Make sure that eego got the news of the new stram and subcribes to it. Not needed from the python side triggers = int(sys.argv[1]) #number of triggers sleeping_time = float(sys.argv[2]) #time in seconds cont = 1 while (cont <= triggers or triggers is -1): string = "%i -> %s" % (cont, datetime.datetime.now().time()) print(string) so.push_sample([string], lsl.local_clock()) cont += 1 time.sleep(sleeping_time)