def connect(self, physical_channel_name, **timing_args): """ Establish connection with NIDAQ apparatus. A virtual output channel and data stream writer are created. :param physical_channel_name: (str or list of str) name of output port on NIDAQ (to see available channel names, open NI MAX (software included with driver installation) and look under "Devices and Interfaces"). The name might look something like "cDAQ1Mod1/ao0". **timing_args : keyword arguments from nidqamx.task.timing.cfg_samp_clk_timing. :return: True if connection was successful, otherwise False. """ # check for multiple channels if isinstance(physical_channel_name, str): self.multiple_channels = False self.n_channels = 1 elif isinstance(physical_channel_name, list): self.multiple_channels = True self.n_channels = len(physical_channel_name) else: self.logger.error("GVS.connect: please specify a valid " "physical channel name.") try: if self.multiple_channels: # connect multiple analog output channels for chan_name in physical_channel_name: self.add_ao_channel(chan_name) # config timing if "rate" not in timing_args: rate = 1e3 self.task.timing.cfg_samp_clk_timing(rate, **timing_args) else: self.task.timing.cfg_samp_clk_timing(**timing_args) # create output stream writer self.writer = stream_writers.AnalogMultiChannelWriter( self.task.out_stream, auto_start=True) else: # connect single analog output channel self.add_ao_channel(physical_channel_name) # config timing if "rate" not in timing_args: rate = 1e3 self.task.timing.cfg_samp_clk_timing(rate, **timing_args) else: self.task.timing.cfg_samp_clk_timing(**timing_args) # create output stream writer self.writer = stream_writers.AnalogSingleChannelWriter( self.task.out_stream, auto_start=True) logging.info("GVS task and channel created") except nidaqmx.errors.DaqError as err: self.logger.error("DAQmx error: {0}".format(err)) return False self.logger.info("GVS task started") return True
def run(self): self.parent.btn_run.setDisabled(True) self.directory() samples, channels, frequency = self.sequence() samples = np.delete(samples, 0, 0) samples = np.delete(samples, 0, axis=1) if len(samples) == (self.parent.table.columnCount() - 3): while self.parent.status_button == True: print samples self.parent.wait_time = int((1.0 / frequency) * len(samples[0]) + 1) print(samples) task = nidaqmx.Task() for channel in channels: task.ao_channels.add_ao_voltage_chan('{0}'.format( channel[1])) task.timing.cfg_samp_clk_timing( rate=frequency, sample_mode=nidaqmx.constants.AcquisitionType.FINITE, samps_per_chan=len(samples[0])) write = stream_writers.AnalogMultiChannelWriter( task.out_stream, auto_start=True) inicio = time.time() write.write_many_sample(samples, timeout=self.parent.wait_time) task.wait_until_done(timeout=self.parent.wait_time) task.stop() task.close() self.write_number() self.parent.shot_number() fim = time.time() print("elapsed time {0} seconds".format(fim - inicio)) #print(len(samples[0])) self.parent.btn_run.setDisabled(False) self.parent.validation = True print('done') self.terminate() else: self.parent.validation = False self.parent.btn_run.setDisabled(False) self.parent.btn_autorun.setDisabled(False) self.terminate()
def open(self): # AI self.t_in = {} for c in self.ai_chan_list: kwargs = dict(c) kwargs.pop("name", None) kwargs.pop("type", None) if c['type'] == 'voltage': kwargs['max_val'] = kwargs.get('max_val', 5) kwargs['min_val'] = kwargs.get('min_val', 0) for k in kwargs: if isinstance(kwargs[k], str): if k == "thermocouple_type": kwargs[k] = thermocouple_type[kwargs[k]] elif k == "units": kwargs[k] = units[kwargs[k]] if not c['type'] in self.t_in: self.t_in[c['type']] = nidaqmx.Task() try: getattr(self.t_in[c['type']].ai_channels, "add_ai_%s_chan" % c['type'])(c['name'], **kwargs) except Exception: print("Invalid channel settings in nidaqmx:" + str(c)) raise self.stream_in = {} for chan_type, t in self.t_in.items(): self.stream_in[chan_type] = \ stream_readers.AnalogMultiChannelReader(t.in_stream) # AO if self.ao_channels: self.t_out = nidaqmx.Task() self.stream_out = stream_writers.AnalogMultiChannelWriter( self.t_out.out_stream, auto_start=True) for c in self.ao_channels: kwargs = dict(c) kwargs.pop("name", None) kwargs.pop("type", None) kwargs['max_val'] = kwargs.get('max_val', 5) kwargs['min_val'] = kwargs.get('min_val', 0) self.t_out.ao_channels.add_ao_voltage_chan(c['name'], **kwargs) # DI if self.di_channels: self.t_di = nidaqmx.Task() for c in self.di_channels: kwargs = dict(c) kwargs.pop("name", None) kwargs.pop("type", None) self.t_di.di_channels.add_di_chan(c['name'], **kwargs) if self.di_channels: self.di_stream = stream_readers.DigitalMultiChannelReader( self.t_di.in_stream) # DO if self.do_channels: self.t_do = nidaqmx.Task() for c in self.do_channels: kwargs = dict(c) kwargs.pop("name", None) kwargs.pop("type", None) self.t_do.do_channels.add_do_chan(c['name'], **kwargs) if self.do_channels: self.do_stream = stream_writers.DigitalMultiChannelWriter( self.t_do.out_stream)
return 0 # Now I start the actual PID loop with nid.Task() as write_task, nid.Task() as read_task: # First I configure the reading read_task.ai_channels.add_ai_voltage_chan( flatten_channel_string(channels_to_read), max_val=10, min_val=-10) reader = sr.AnalogMultiChannelReader(read_task.in_stream) # Now I configure the writing write_task.ao_channels.add_ao_voltage_chan( flatten_channel_string(channels_to_write), max_val=10, min_val=-10) writer = sw.AnalogMultiChannelWriter(write_task.out_stream) # source task. # Start the read and write tasks before starting the sample clock # source task. read_task.start() read_task.register_every_n_samples_acquired_into_buffer_event( 20, # Every 20 samples, call callback function callback) write_task.start() writer.write_many_sample(output_array) values_read = np.zeros((number_of_channels, samples_to_measure), dtype=np.float64)
min_val=-10, max_val=10, terminal_config=nidaqmx.constants.TerminalConfiguration.RSE) ao.timing.cfg_samp_clk_timing( RATE, sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS) ai.timing.cfg_samp_clk_timing( RATE, source='/Dev1/ao/SampleClock', sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS ) # synchronize our reading with when we write ao.out_stream.regen_mode = nidaqmx.constants.RegenerationMode.DONT_ALLOW_REGENERATION # disable repeating old data, instead error if we run out ao.out_stream.output_buf_size = RATE # one second of buffer. For latency, we want to keep this buffer as empty as possible. aow = stream_writers.AnalogMultiChannelWriter( ao.out_stream ) # Lets us stream data into the buffer and thus out onto the pin. aow.auto_start = False aow.write_many_sample( np.zeros((2, RATE // 4), dtype=np.float64), timeout=0 ) # We need to write some data before we start the task, otherwise it complains do.write(True) # SS high to sync with the slave ao.start() threading.Thread(target=saturate_zeros, args=(ao, aow), daemon=True).start() time.sleep( 0.1 ) # Give startup ripples a moment to settle before starting to read data
def __init__(self): #variables for file id base_dir = 'C:/Users/inctel/Documents/ContrastDetectionTask/' expInfo = {'mouse':'Mfake', 'date': datetime.datetime.today().strftime('%Y%m%d-%H_%M_%S'), 'response_window': .5, 'red_gain': 1.26, 'blue_gain': 1.36, 'red_volts':1.3, 'blue_volts':1.4, } dlg = gui.DlgFromDict(dictionary=expInfo, title = 'Contrast Detection Task') if dlg.OK==False: core.quit() #stimulus variables tf = 2 #temporal frequency sf = .08 sizes = [0,20] intensities = {} intensities[0] = [0,0] intensities[20] = [1,2,3,5,20,100] led_conds = ['none','square','noise'] #task variables self.stim_delay = .2 #in s self.stim_time = .5 #in s self.response_window = expInfo['response_window']# in s self.isimin = 3 # in s self.isimax = 8 #in s self.grace_time = 1 #in s self.water_time = 100 #in ms #monitor variables monitor_width = 19.6 #in cm monitor_height = 9.5 #in cm #led variables expInfo['alphaRise'] = .001 expInfo['alphaDecay'] = .005 expInfo['tEPSG'] = .01 expInfo['firingRate'] = 200 self.led_cond_function_key= { 'none': self.gen_no_pulse, 'square': self.gen_square_pulse, 'noise': self.gen_synaptic_noise_stims } print('pre window generation') #initialize expInfo['monitor_dist']=10.47 self.monitor = monitors.Monitor('BoxMonitor1', width=monitor_width, distance=expInfo['monitor_dist']) self.win = visual.Window(fullscr=True, monitor=self.monitor, units="pix") print('generated window') FR = self.win.getActualFrameRate() expInfo['FR'] = FR expInfo['monitor_height'] = monitor_height expInfo['water_time'] = self.water_time expInfo['position'] = np.array([0,0]) expInfo['stim_time'] = self.stim_time expInfo['sf'] = sf #spatial frequency of grating expInfo['tf'] = tf #temporal frequency of greating expInfo['response_window'] = self.response_window expInfo['fs'] = 5000 self.reverse_lick = True #if the lick is represented by low volts self.pix_per_deg = (self.monitor.getSizePix()[1]/ (np.degrees(np.arctan(monitor_height/expInfo['monitor_dist'])))) print('set up some vars') #create trial conditions self.size_int_response = [] #mult = math.ceil(500/(sum([len(intensities(s)) for s in sizes])*4)) #print('I think mult should be ', mult) for temp in range(50): mini_size_int_response = [] for _ in range(1): #how many blocks to shuffle in for s in sizes: for ins in intensities[s]: for led_cond in led_conds: mini_size_int_response.append({'size':s,'intensity':ins, 'corr_response':ins>0, 'led_cond': led_cond}) random.shuffle(mini_size_int_response) self.size_int_response += mini_size_int_response #and some more general variables self.phase_increment = tf/FR self.stim_on_frames = int(self.stim_time*FR) print('conditions genned') self.trial_timer = core.Clock() self.isi_timer = core.Clock() self.grating = visual.GratingStim(win=self.win, size=10*self.pix_per_deg, pos=expInfo['position']*self.pix_per_deg, sf=sf/self.pix_per_deg,units='pix', ori=180+45, mask='circle') #maybe temp, add some display text self.text = visual.TextStim(win=self.win, text='startup', pos = [-250,-150], height=10,opacity=.35) #final setup self.filename = base_dir + expInfo['date']+'_' + expInfo['mouse'] self.exp = data.ExperimentHandler('ContrastDetectionTask','v0', dataFileName = self.filename, extraInfo = expInfo) #set up the nidaq self.lick_daq = ni.Task() self.lick_daq.di_channels.add_di_chan('Dev1/Port1/Line0') self.lick_daq.start() print('daq launched') self.water_daq = ni.Task() self.water_daq.do_channels.add_do_chan('Dev1/Port1/Line2') self.led_daq = ni.Task() self.led_daq.ao_channels.add_ao_voltage_chan('Dev1/ao0') self.led_daq.ao_channels.add_ao_voltage_chan('Dev1/ao1') self.led_daq.timing.cfg_samp_clk_timing(rate=expInfo['fs'], sample_mode= ni.constants.AcquisitionType.FINITE, samps_per_chan= int(np.floor(expInfo['fs']*(self.stim_time+self.response_window)))) self.led_writer = stream_writers.AnalogMultiChannelWriter(self.led_daq.out_stream, auto_start=False) print('other daqs launched') self.fs=expInfo['fs']#TOFO: why here? self.run_blocks()
def start_continuous_acq_n_gen(self): self._ao_task = ni.Task() self._ai_task = ni.Task() ai_args = { 'min_val': self.ai_min_val, 'max_val': self.ai_max_val, 'terminal_config': ni.constants.TerminalConfiguration[self.ai_terminal_config] } self._ai_task.ai_channels.add_ai_voltage_chan(self.ai_a_name, **ai_args) self._ai_task.ai_channels.add_ai_voltage_chan(self.ai_b_name, **ai_args) self._ai_task.timing.cfg_samp_clk_timing( rate=self.ai_fs, sample_mode=ni.constants.AcquisitionType.CONTINUOUS, samps_per_chan=self._input_frame_len) self._ai_task.triggers.start_trigger.cfg_dig_edge_start_trig( "ao/StartTrigger", trigger_edge=ni.constants.Edge.RISING) # Below is a bit clumsy EAFP but we have to be careful writing to properties because they may or may not be # present depending on device type while the "double locking" system with both OVERRIDE and property needing # change requires user to really know what he is doing. In most cases if some control attribute is not # implemented in a device, it can work without issues just with the default settings though. On NI6211, # this code is debugged with, only the default output buffer had to be changed to prevent underflow at high # UBS data rates. I leave this code though for users to experiment in case of issues with other DAQ models. if self.ATTEMPT_OVERRIDE_DEFAULT_INPUT_BUFFER_SIZE: try: self._ai_task.in_stream.input_buf_size = self.sw_input_buffer_size except ni.errors.DaqError as exc: print(exc) print('ATTEMPT_OVERRIDE_DEFAULT_INPUT_BUFFER_SIZE failed') if self.ATTEMPT_OVERRIDE_DEFAULT_INPUT_OVERWRITE_BEHAVIOUR is True: try: if self.INPUT_OVERWRITE is False: self._ai_task.in_stream.over_write = ni.constants.OverwriteMode.DO_NOT_OVERWRITE_UNREAD_SAMPLES elif self.INPUT_OVERWRITE is True: self._ai_task.in_stream.over_write = ni.constants.OverwriteMode.OVERWRITE_UNREAD_SAMPLES except ni.errors.DaqError as exc: print(exc) print( 'ATTEMPT_OVERRIDE_DEFAULT_INPUT_OVERWRITE_BEHAVIOUR failed' ) ao_args = {'min_val': self.ao_min_val, 'max_val': self.ao_max_val} ao_chan_a = self._ao_task.ao_channels.add_ao_voltage_chan( self.ao_a_name, **ao_args) ao_chan_b = self._ao_task.ao_channels.add_ao_voltage_chan( self.ao_b_name, **ao_args) if self.ATTEMPT_OVERRIDE_DEFAULT_USB_XFER is True: try: ao_chan_a.ao_usb_xfer_req_count = self.AO_USB_XFER_REQ_COUNT ao_chan_b.ao_usb_xfer_req_count = self.AO_USB_XFER_REQ_COUNT ao_chan_a.ao_usb_xfer_req_size = self.AO_USB_XFER_REQ_SIZE ao_chan_b.ao_usb_xfer_req_size = self.AO_USB_XFER_REQ_SIZE except ni.errors.DaqError as exc: print(exc) print('ATTEMPT_OVERRIDE_DEFAULT_USB_XFER failed') self._ao_task.timing.cfg_samp_clk_timing( rate=self.ao_fs, samps_per_chan=self._output_frame_len, #TODO bug on dev1 sample_mode=ni.constants.AcquisitionType.CONTINUOUS) if self.ATTEMPT_OVERRIDE_DEFAULT_OUTPUT_REGENERATION_MODE is True: try: if self.ALLOW_OUTPUT_REGENERATION is False: self._ao_task.out_stream.regen_mode = ni.constants.RegenerationMode.DONT_ALLOW_REGENERATION # prevents DAQ card from repeating output, it just waits for more data to be added to the buffer- > but on cards that cant handle to automatically pause output generation when out of buffer this setting will case random and unexpected crash! elif self.ALLOW_OUTPUT_REGENERATION is True: self._ao_task.out_stream.regen_mode = ni.constants.RegenerationMode.ALLOW_REGENERATION except ni.errors.DaqError as exc: print(exc) print( 'ATTEMPT_OVERRIDE_DEFAULT_OUTPUT_REGENERATION_MODE failed') if self.ATTEMPT_OVERRIDE_DEFAULT_UNDERFLOW_BEHAVIOR_TO_PAUSE is True: try: self._ao_task.timing.implicit_underflow_behavior = ni.constants.UnderflowBehavior.AUSE_UNTIL_DATA_AVAILABLE # SIC! except ni.errors.DaqError as exc: print(exc) print('Could not OVERRIDE_DEFAULT_UNDEFLOW_BEHAVIOR') if self._ao_task.out_stream.regen_mode == ni.constants.RegenerationMode.DONT_ALLOW_REGENERATION: print( 'WARNING: Your device does not support pause in case of output underflow while auto ' 'regeneration of the AO buffer is not allowed.\n ' 'In case of output buffer underflow due to system resources the application will crash!\n ' 'To prevent this warning and risk of crash its highly recommended to set _out_stream.regen_' 'mode to ALLOW_REGENERATION.\n ' 'This will allow output glitches in theory but will prevent ' 'application from crashing on output buffer underflow.' ) if self.ATTEMPT_OVERRIDE_DEFAULT_OUTPUT_BUFFER_SIZE is True: try: self._ao_task.out_stream.output_buf_size = self.sw_output_buffer_size # seems like buffer is not calculating correct and we must call out explicitly on NI6211. # Not setting this property leads to a chain of very confusing warnings/glitches. except ni.errors.DaqError as exc: print(exc) self._stream_reader = stream_readers.AnalogMultiChannelReader( self._ai_task.in_stream) self._stream_writer = stream_writers.AnalogMultiChannelWriter( self._ao_task.out_stream) # fill AO buffer with data self.function_gen.generate() buffer_frame = self.function_gen.output_frame for frames in range(self.CM_OUTPUT_FRAMES_PER_BUFFER - 1): # TODO UGLY self.function_gen.generate() buffer_frame = np.append(buffer_frame, self.function_gen.output_frame, axis=1) self._ao_task.write(buffer_frame) self._ai_task.register_every_n_samples_acquired_into_buffer_event( self._input_frame_len, self.reading_task_callback) self._ao_task.register_every_n_samples_transferred_from_buffer_event( self._output_frame_len, self.writing_task_callback) self._ai_task.start() # arm but do not trigger the acquisition self._ao_task.start( ) # trigger both generation and acquisition simultaneously self.cm_measurement_is_running = True