Module gonioimsoft.stimulus
Functions
def main()
-
Saves stimulus as a json.
Classes
class StimulusBuilder (stim_time, prestim_time, poststim_time, frame_length, stimulus_intensity, illumination_intensity, fs, stimulus_finalval=0, illumination_finalval=0, wtype='square')
-
Get various stimulus waveforms - to the stimulus LED - and on pulse for illumination LED - and square wave for triggering the camera.
stim_time The time stimulus LED is on prestim_time The time the camera is running and illumination is on before the stimulus poststim_time The time the camera is running and illumination is on after the stimulus stimulus_intensity From 0 to 1, the brightness of the stimulus illumination_intensity From 0 to 1, the brightness of the illumination lights wtype "square" or "sinelogsweep" or "squarelogsweep"
Expand source code
class StimulusBuilder: ''' Get various stimulus waveforms - to the stimulus LED - and on pulse for illumination LED - and square wave for triggering the camera. ''' def __init__(self, stim_time, prestim_time, poststim_time, frame_length, stimulus_intensity, illumination_intensity, fs, stimulus_finalval=0, illumination_finalval=0, wtype='square'): ''' stim_time The time stimulus LED is on prestim_time The time the camera is running and illumination is on before the stimulus poststim_time The time the camera is running and illumination is on after the stimulus stimulus_intensity From 0 to 1, the brightness of the stimulus illumination_intensity From 0 to 1, the brightness of the illumination lights wtype "square" or "sinelogsweep" or "squarelogsweep" ''' self.stim_time = stim_time self.prestim_time = prestim_time self.poststim_time = poststim_time self.frame_length = frame_length self.stimulus_intensity = stimulus_intensity self.illumination_intensity = illumination_intensity self.fs = fs self.stimulus_finalval = stimulus_finalval self.illumination_finalval = illumination_finalval self.wtype = wtype self.N_frames = int(round((stim_time+prestim_time+poststim_time)/frame_length)) self.overload_stimulus = None def overload_biosyst_stimulus(self, fn, channel=0): ''' Loads a Biosyst stimulus that gets returned then at get_stimulus_pulse instead. Returns the overload stimulus and new fs ''' if fn.endswith('.json'): ffn = os.path.join(USERDATA_DIR, 'biosyst_stimuli', fn) with open(ffn, 'r') as fp: data = json.load(fp) self.fs = data['fs'] self.overload_stimulus = [] for i_stim in range(10): key = f'stim_{i_stim}' if key not in data: continue self.overload_stimulus.append(np.array(data[key])) return self.overload_stimulus[0], self.fs if bsextract is None: raise ModuleNotFoundError('Module required\npip install python-biosystfiles') ffn = os.path.join(USERDATA_DIR, 'biosyst_stimuli', fn) self.overload_stimulus, self.fs = bsextract(ffn, channel) self.overload_stimulus = self.overload_stimulus.flatten() print(self.overload_stimulus.shape) print(np.max(self.overload_stimulus)) return self.overload_stimulus, self.fs def get_stimulus_pulse(self): ''' Constant value pulse _________stimulus_intensity | | ________| |__________ prestim stim poststim ''' if self.overload_stimulus is not None: return self.overload_stimulus N0_samples = int(self.prestim_time*self.fs) N1_samples = int(self.stim_time*self.fs) N2_samples = int(self.poststim_time*self.fs) if self.wtype == 'square': stimulus = np.concatenate( (np.zeros(N0_samples), np.ones(N1_samples), np.zeros(N2_samples)) ) elif 'logsweep' in self.wtype: try: wtype, f0, f1 = self.wtype.split(',') f0 = float(f0) f1 = float(f1) except: print("Doing logsweep from 0.5 Hz to 100 Hz") f0=0.5 f1=100 wtype = self.wtype times = np.linspace(0, self.stim_time, N1_samples) active = scipy.signal.chirp(times, f0=f0, f1=f1, t1=self.stim_time, phi=-90, method='logarithmic') if wtype == 'squarelogsweep': active[active>0] = 1 active[active<0] = -1 elif wtype == '3steplogsweep': cstep = np.sin(np.pi/4) active[np.abs(active) <= cstep] = 0 active[active > cstep] = 1 active[active < -cstep] = -1 elif wtype == 'sinelogsweep': pass else: raise ValueError('Unkown flash_type'.format(wtype)) # Join with pre and post 0.5 values # and move and scale between 0 and 1 (from - 1 and 1) stimulus = np.concatenate( (np.ones(N0_samples)/2, (active+1)/2, np.ones(N2_samples)/2) ) else: raise ValueError('Invalid wtype given, has to be "square" or "sinelogsweep" or "3steplogsweep"') stimulus = self.stimulus_intensity * stimulus stimulus[-1] = self.stimulus_finalval return stimulus def get_illumination(self): ''' Returns 1D np.array. ''' illumination = np.ones( int((self.stim_time+self.prestim_time+self.poststim_time)*self.fs) ) illumination = self.illumination_intensity * illumination illumination[-1] = self.illumination_finalval return illumination def get_camera(self): ''' Get square wave camera triggering stimulus. Returns 1D np.array. ''' samples_per_frame = int(self.frame_length * self.fs /2) camera = np.concatenate( ( np.ones((samples_per_frame, self.N_frames)), np.zeros((samples_per_frame, self.N_frames)) ) ).T.flatten() camera = 5*camera camera[-1] = 0 return camera
Methods
def get_camera(self)
-
Get square wave camera triggering stimulus.
Returns 1D np.array.
def get_illumination(self)
-
Returns 1D np.array.
def get_stimulus_pulse(self)
-
Constant value pulse
_________stimulus_intensity | |
__| |____ prestim stim poststim
def overload_biosyst_stimulus(self, fn, channel=0)
-
Loads a Biosyst stimulus that gets returned then at get_stimulus_pulse instead.
Returns the overload stimulus and new fs