def __init__(self, parent=None): super(Ui, self).__init__(parent) self.setupUi(self) self.show() self.FDS_R = int(cfg["H_reflex"]["fds_r"]) sinfo = liesl.get_streaminfos_matching(type="EEG")[0] self.buffer = liesl.RingBuffer(sinfo, duration_in_ms=500) self.buffer.start() self.buffer.await_running() time.sleep(1) self.addToolBar(NavigationToolbar(self.MplWidget.canvas, self)) self.download() self.intensity_minus_1000.clicked.connect( partial(self.decrease_intensity, 1000)) self.intensity_plus_1000.clicked.connect( partial(self.increase_intensity, 1000)) self.intensity_minus_100.clicked.connect( partial(self.decrease_intensity, 100)) self.intensity_plus_100.clicked.connect( partial(self.increase_intensity, 100)) self.trigger.clicked.connect(self.start_stimulation) push("hreflex_start")
def show(self, duration: float = 0, canvas=None, safetime=.2): """present all stimuli stored in the cue args ---- duration: float how many seconds you want to present the visual stimuli on the canvas. Defaults to zero. Using zero will result in the function returning immediatly, while keeping the visual stimulus maintained on the canvas. In that regard, it resembles presentation forever, (or until another cue is presented). This can confuse Windows 10 if the canvas is moved or resized, as the OS thinks the canvas is `unresponsive`. Any other positive values cause the function to not return and block for the whole duration. canvas: :class:`reiz.Canvas` In case you decide to present the Cue on a different canvas instead to the one assigned during instantiation. Will be ignored otherwise. safetime: float continuous presentation causes the canvas to be updated at the flip rate of your screen and grapics cards (usually aroung 60Hz). This hardware limitation means that the duration of presentation will be quantizised, i.e. the duration of presentation will be a multiple of 16.6ms for a 60Hz screen. To achieve more accurate duration, the safetime parameters sets how long to the end of the duration we will no longer flip the screen. By default, we won't flip the screen during the last 200ms. This can cause the OS to consider the screen `unresponsive` (see duration above). Please note that this does not improve the timing of the actual drawing on the screen, it just allows the :meth:`~.show` to return at a more accurate time. """ if canvas is not None: self.canvas = canvas if self.audio is not None: self.audio.play() if self.marker is not None: marker.push(self.marker) if duration is not None and self.visual is not None: if duration == 0: # show "forever" self.canvas.show(self.visual) return 0 else: # show for duration clk = _Clock() dt = clk.now() clk.tick() self.canvas.show(self.visual) while dt <= duration and self.canvas.available: # flipping quantizises the sleep duration, therefore we # don't flip anymore if that would become relevant # we only repeat presentation of the visual stimulus # as audio and markers would be senseless and overlays if abs(duration - dt) > safetime: self.canvas.show(self.visual) clk.sleep_debiased(.1) dt = clk.now() return dt
def auto_trigger(coil: Coil, lucky, marker: MarkerStreamInlet, buffer: DataRingBuffer, timeout: Seconds = 1): """Expect the TMS to be triggered manually We wait a certain time for the response to arrive. If this time has passed, we trigger again, assuming that somehow the TCP-IP command was lost in transition. """ marker.pull_chunk( ) #flush the buffer to be sure we catch the latest sample # lucky.trigger_now() #trigger the coil lucky.trigger() push('TMS_auto_trigger', sanitize=False) _, onset_in_ms = marker.pull_sample() try: response = wait_for_trigger(coil, marker, buffer, onset_in_ms, timeout) #wait for the response except TimeOutException: logger.warning("Timeout,. repeating command to stimulate") response = auto_trigger(coil, lucky, marker, buffer, timeout) return response
def manual_trigger(coil: Coil, marker: MarkerStreamInlet, buffer: DataRingBuffer): """Expect the TMS to be triggered manually We therefore also wait forever for the response to arrive. If examiner becomes inpatient as the trigger was swallowed, a manual repetition is necessary """ print('wait for manual trigger') marker.pull_chunk( ) #flush the buffer to be sure we catch the latest sample while True: marker.pull_chunk() didt_catch, onset_in_ms = marker.pull_sample() if didt_catch[0][9:13] == 'didt': break push('TMS_manual_trigger', sanitize=False) # wait forever for the response, because response = wait_for_trigger(coil, marker, buffer, onset_in_ms, timeout=FOREVER) return response
def closeEvent(self, event): push("hreflex_end") session.stop_recording() app.aboutToQuit.connect(on_close)
def start_stimulation(self): push("h_reflex_stim_" + str(self.cur / 1000)) self.mcs.start_stimulation() time.sleep(0.25) self.plot_hreflex()
def search_hotspot(trials=40, isi=(3.5, 4.5), task_description='Start Hotspot Search', env=None, run_automatic: bool = False): print(__file__) labels = env.labels emg_labels = env.emg_labels coil, marker, buffer, lucky = env.coil, env.marker, env.buffer, env.lucky task = Message(task_description) time.sleep(0.1) plt.close('all') def create_hotspot_canvas(emg_labels): nr, nc = 2, len(emg_labels) // 2 if len(emg_labels) % 2: #uneven nc += 1 fig, axes = plt.subplots(nrows=nr, ncols=nc, sharex=True, sharey=True) fig.canvas.manager.window.move(-1280, 20) fig.canvas.manager.window.resize(1280, 1024) fig.tight_layout() return fig, axes fig, axes = create_hotspot_canvas(emg_labels) def show(response, axes, emg_labels, labels): xticks, xticklabels, xlim = response.get_xaxis(stepsize=25) for ax, lbl in zip(axes.flatten(), emg_labels): ax.cla() trace = response.get_trace(channel_idx=labels.index(lbl)) vpp = response.get_vpp(channel_idx=labels.index(lbl)) ax.plot(trace) for pos, val in zip(response.peakpos_in_ms, response.peakval): ax.plot([pos, pos], [0, val], color='red', linestyle=':') #TG: for test temporary change scale to [-1 1] ax.axvline(x=response.pre_in_ms, color='red') textstr = 'Vpp = {0:3.2f}'.format(vpp) props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14, verticalalignment='top', bbox=props) ax.set_title(lbl) ax.set_xticks(xticks) ax.set_xlim(xlim) ax.set_xticklabels(xticklabels) plt.show() task.play_blocking() if coil.amplitude == 0: entamp.play_blocking() response = manual_trigger(coil, marker, buffer) #coil.amplitude = amplitude amplitude = coil.amplitude amplitude = coil.amplitude else: amplitude = coil.amplitude amplitude = coil.amplitude counter = 0 collection = [] automatic = False has_started = False while counter < trials: if run_automatic or automatic: if counter == 0: coil.amplitude = 0 manual_trigger(coil, marker, buffer) coil.amplitude = amplitude time.sleep(isi[0] + (random.random() * (isi[1] - isi[0]))) response = auto_trigger(coil, lucky, marker, buffer) else: if not has_started: ready.play_blocking() has_started = True coil.amplitude = amplitude response = manual_trigger(coil, marker, buffer) hotspot_amplitude = coil.amplitude hotspot_amplitude = coil.amplitude if amplitude != hotspot_amplitude: amplitude = hotspot_amplitude if run_automatic: automatic = True response_marker = create_marker(response, coil, emg_labels, labels, amplitude) coil_message = json.loads( response.as_json( channel_idx=labels.index(env.channel_of_interest))) print('before push') coil.set_response(mepmaxtime=coil_message['mepmaxtime'], mepamplitude=coil_message['mepamplitude'], mepmin=coil_message['mepmin'], mepmax=coil_message['mepmax']) coil.push_marker(json.dumps(response_marker)) push(json.dumps(response_marker), sanitize=False) show(response, axes, emg_labels, labels) props = dict(boxstyle='round', facecolor='white', alpha=1) counter += 1 print(f'this is the {counter} trial') ax = axes[0, 0] ax.text(-.15, 1.05, f'{counter} of {trials}', transform=ax.transAxes, fontsize=14, verticalalignment='top', bbox=props) collection.append(response_marker) plt.pause(0.05) run_ended.play_blocking() time.sleep(2) return collection
def start_intervention(cfg, condition, stim_number, verbose: bool = False): RMT = get_RMT(max_percent_RMT=120) run_length = int(cfg['main']['run_length']) condition_idx = condition['index'] """Save the condition""" condition_order_directory = cfg['main']['recordings_path'] + "\\" + cfg[ 'general']['subject_token'] + '\\condition_%s\\config\\' % condition_idx condition_order_file_path = condition_order_directory + 'config.json' try: with open(condition_order_file_path) as json_file: stimuli = json.load(json_file) print('Loaded condition file') break_idx, timeleft = create_break_idx_timeleft( stimuli, condition, run_length) stimuli = stimuli[stim_number:] except: stimuli = create_stim_list(condition, cfg) print('create new condition file') break_idx, timeleft = create_break_idx_timeleft( stimuli, condition, run_length) os.makedirs(condition_order_directory) with open(condition_order_file_path, 'w') as file: file.write(json.dumps(stimuli)) #überschreibt immer print('Created new condition file') """Check if all streams are available""" # streamargs = [{'name':"localite_marker"}, # comments: make a real list # {'name':"reiz-marker"}, # {'name':"eego"}, # {'name':"LuckyLoop"}, # {'name':"pupil_capture"}, # {'name':"GDX-RB_0K2002A1"}] streamargs = [{'name': "eego"}] session = Session(prefix=cfg['general']['subject_token'], streamargs=streamargs) """Define stimulation intensity""" stimulation_intensity = round(condition['percent_RMT'] * RMT / 100) print(f"Stimulation intensity {stimulation_intensity}") """"Calculate the time duration for the intervention""" # TMS_stimulus = {'stim_type': 'TMS', 'frequency':condition['frequency'], 'phase':condition['phase_in_deg']} # N = stimuli.count(TMS_stimulus) # expected_duration = (N * 10) / 60 # print(f'Expected duration is around {expected_duration:.2f} min') #%% """Intit Lucky Client""" print("Init lucky") #lucky = LuckyClient('134.2.117.144') """Init Coil""" print("Init coil") coil = Coil(0) time.sleep(.8) coil.amplitude = stimulation_intensity time.sleep(.8) """Init Sandy""" print("Init sandy") # sandy_cli = sandy.Arduino(timeout=1.5, version = 'v0.3.1 - StalwartSandy') # sandy_cli.reset() # sandy_cli.set_threshold(150) # sandy_cli.blink(5) #sandy_cli.set_threshold(0) print("Sandy in standby") time.sleep(1) """Create the GUI""" canvas = Canvas() canvas.open() labcue = reiz.Cue(canvas, visualstim=reiz.visual.library.logo) labcue.show(duration=2) #%% with session("TMS_intervention"): print("Started recording") canvas.window.start_run = False start_protocol = reiz.Cue( canvas, visualstim=Mural(text='Start protocol with F5')) print("Waiting for user to start in GUI") while not canvas.window.start_run: start_protocol.show(duration=1) countdown(canvas, 5) labcue.show() t0 = time.time() break_counter = 0 reaction_times = [] """ set up phase and frequency parameter """ phase = condition['phase_in_deg'] frequency = condition['frequency'] lucky.phase = phase lucky.frequency = frequency for single_stimulus in stimuli: """get some parameter informations""" stimulus_idx = single_stimulus['stimulus_idx'] stim_type = single_stimulus['stim_type'] print(f"Stimulation index {single_stimulus['stimulus_idx']}") time.sleep(0.5) time_setup_trial = time.time() # sends current setup as marker push(json.dumps({ 'stimulus_idx': str(stimulus_idx), 'stim_type': stim_type, 'freq': str(frequency), 'phase': str(phase) }), sanitize=False) if verbose: print("Start " + stim_type + " for frequency " + str(frequency) + ' and phase ' + str(phase)) # conditional of stimtype, setup TMS and Arduino this trial if stim_type == 'TMS': coil.amplitude = stimulation_intensity time.sleep(.8) t1 = time.time() trial_time = t1 - t0 if verbose: print("\n Trial time: " + str(trial_time)) # TG: wait and trigger phase and frequency dependent, if next stimuli is TMS, then wait 10s, else wait 5s if stimulus_idx < (stimuli[-1]['stimulus_idx']) and stimuli[ stimulus_idx - stim_number + 1]['stim_type'] == 'TMS': sleep_time = random_time(min=9.5 - trial_time, max=10.5 - trial_time) else: sleep_time = random_time(min=4.5 - trial_time, max=5.5 - trial_time) if stim_type == 'PVT': coil.amplitude = 0 time.sleep(.8) # wait and trigger phase and frequency dependent t1 = time.time() trial_time = t1 - t0 if verbose: print("\n Trial time: " + str(trial_time)) sleep_time = random_time(min=4.5 - trial_time, max=5.5 - trial_time) try: sandy_cli.await_blink() if verbose: print('Sandy is waiting for blink') except: raise ConnectionError('Sandy in unclear state') print(f"\n Setup: {(time.time()-time_setup_trial):.2f}s") if sleep_time < 0.75: sleep_time = 0.75 if True or verbose: print(f"\n Sleep_time = {sleep_time:.2f}s") print(f"\n ISI = {sleep_time+trial_time:.2f}s\n") labcue.show(duration=sleep_time) t0 = time.time() # conditional on stimtype, wait for keypress if stim_type == 'PVT': event_list = [] sandy_cli.receive() blink_wait_start = time.time() while not (event_list) or len(event_list) == 0: if time.time() - blink_wait_start > 30: raise ConnectionError( f"Sandy could not be triggered for 30 seconds. Stimulus idx: {stimulus_idx}" ) break print(f"Wait for blink trigger. Stim: {stimulus_idx}") lucky.trigger() event_list = sandy_cli.receive() print(f"Event list: {event_list}") for event in event_list: if event['state-change'] == 'blink-started': time_trigger = int(event['timestamp']) time_wait_for_press = time.time() print("Waiting for button pressed") atleast_one_button_pressed = False time_reaction = False while time.time() - time_wait_for_press < 1.25: response = sandy_cli.receive() if response: event_list.extend(response) if event_list: for event in event_list: if event: print(event) button_1_pressed = event[ 'state-change'] == 'button-1-pressed' button_2_pressed = event[ 'state-change'] == 'button-2-pressed' both_buttons_pressed = event[ 'state-change'] == 'both-buttons-pressed' atleast_one_button_pressed = button_1_pressed or button_2_pressed or both_buttons_pressed if atleast_one_button_pressed: time_reaction = int(event['timestamp']) break if atleast_one_button_pressed: break if verbose: print(f"Trigger timestamp= {time_trigger}") if time_trigger is not None: # led was turned on if verbose: print("Reaction timestamp= " + str(time_reaction)) if not ( time_reaction ) or time_reaction - time_trigger < 0 or time_reaction - time_trigger > 1000: reaction_time = "No reaction" rt = reiz.Cue(canvas, visualstim=Mural(text=reaction_time)) else: reaction_time = time_reaction - time_trigger reaction_times.append(reaction_time) rt = reiz.Cue( canvas, visualstim=Mural( text='{0:3.1f} ms'.format(reaction_time))) if verbose: print('Reaction time: ' + str(reaction_time)) push(json.dumps({'reaction_time': str(reaction_time)}), sanitize=False) rt.show(duration=1) else: # when TMS stimulus lucky.trigger() try: if stimuli[stimulus_idx - stim_number]['stim_type'] == "PVT": coil.amplitude = 0 time.sleep(.8) except IndexError: print("Index error") if stimulus_idx in break_idx: #make a break after cfg.run_length stimuli if experiment is not over break_counter += 1 if break_counter == 1: mean_run_reaction_time = np.mean( reaction_times[:break_idx.index(stimulus_idx)]) else: mean_run_reaction_time = np.mean(reaction_times[( break_idx[break_idx.index(stimulus_idx) - 1] - stim_number + 1):break_idx[break_idx.index(stimulus_idx)]]) mean_overall_reaction_time = np.mean(reaction_times) #displays run reaction time v_run_reaction_time = reiz.Cue( canvas, visualstim=Mural( text='Run reaction time = ' + '{0:3.1f} ms'.format(mean_run_reaction_time))) v_run_reaction_time.show(duration=2) #displays overall reaction time v_overall_reaction_time = reiz.Cue( canvas, visualstim=Mural( text='Overall reaction time = ' + '{0:3.1f} ms'.format(mean_overall_reaction_time))) v_overall_reaction_time.show(duration=2) #calculates and shows the expected duration of the intervention that is left expected_duration_left = timeleft[break_idx.index( stimulus_idx)] print( f'Expected duration is around {expected_duration_left} min' ) v_expected_duration_left = reiz.Cue( canvas, visualstim=Mural( text='Expected duration left = ' + '{0:3.1f} min'.format(expected_duration_left))) v_expected_duration_left.show(duration=4) canvas.window.start_run = False nextrun = reiz.Cue(canvas, visualstim=Mural(text='Continue with F5')) while not canvas.window.start_run: nextrun.show(duration=1) countdown(canvas, 5) labcue.show() v_intervention_finished = reiz.Cue( canvas, visualstim=Mural( text='Intervention is finished. Please stop the recording')) v_intervention_finished.show(duration=1)