def setup_sw_ao(lines, expected_range, task_name='sw_ao'): # TODO: DAQmxSetAOTermCfg task = create_task(task_name) lb, ub = expected_range mx.DAQmxCreateAOVoltageChan(task, lines, '', lb, ub, mx.DAQmx_Val_Volts, '') mx.DAQmxTaskControl(task, mx.DAQmx_Val_Task_Reserve) return task
def configure_pulser_task(self): """ Clear pulser task and set to current settings. @return: """ a_channels = [self.channel_map[k] for k in self.a_names] d_channels = [self.channel_map[k] for k in self.d_names] # clear task daq.DAQmxClearTask(self.pulser_task) # add channels if len(a_channels) > 0: print(self.a_names, a_channels) daq.DAQmxCreateAOVoltageChan(self.pulser_task, ', '.join(a_channels), ', '.join(self.a_names), self.min_volts, self.max_volts, daq.DAQmx_Val_Volts, '') if len(d_channels) > 0: print(self.d_names, d_channels) daq.DAQmxCreateDOChan(self.pulser_task, ', '.join(d_channels), ', '.join(self.d_names), daq.DAQmx_Val_ChanForAllLines) # set sampling frequency daq.DAQmxCfgSampClkTiming(self.pulser_task, 'OnboardClock', self.sample_rate, daq.DAQmx_Val_Rising, daq.DAQmx_Val_ContSamps, 10 * self.sample_rate)
def _start_analog_output(self): """ Creates for each physical channel a task and its virtual channel @returns: error code: ok = 0, error = -1 """ try: # create a dictionary with physical channel name as key and a pointer as value {'/Dev1/AO0': c_void_p(None), ... } taskhandles = dict([(name, daq.TaskHandle(0)) for name in self._ao_channels]) # if an analog task is already running, stop it first (safety if one of the created pointers already points somewhere) for channel in self._ao_channels: if taskhandles[channel].value is not None: # stop analog output task daq.DAQmxStopTask(taskhandles[channel]) # delete the configuration of the analog task daq.DAQmxClearTask(taskhandles[channel]) # set the task handle to None as a safety taskhandles[channel].value = None # create an individual task and a channel per analog output for n, channel in enumerate(self._ao_channels): daq.DAQmxCreateTask('', daq.byref(taskhandles[channel])) daq.DAQmxCreateAOVoltageChan(taskhandles[channel], channel, '', self._ao_voltage_ranges[n][0], self._ao_voltage_ranges[n][1], daq.DAQmx_Val_Volts, None) self.ao_taskhandles = taskhandles except: self.log.exception('Error starting analog output task.') return -1 return 0
def setup_hw_ao(fs, lines, expected_range, callback, callback_samples): # TODO: DAQmxSetAOTermCfg task = create_task() lb, ub = expected_range mx.DAQmxCreateAOVoltageChan(task, lines, '', lb, ub, mx.DAQmx_Val_Volts, '') mx.DAQmxCfgSampClkTiming(task, '', fs, mx.DAQmx_Val_Rising, mx.DAQmx_Val_ContSamps, int(fs)) # This controls how quickly we can update the buffer on the device. On some # devices it is not user-settable. On the X-series PCIe-6321 I am able to # change it. On the M-xeries PCI 6259 it appears to be fixed at 8191 # samples. mx.DAQmxSetBufOutputOnbrdBufSize(task, 8191) # If the write reaches the end of the buffer and no new data has been # provided, do not loop around to the beginning and start over. mx.DAQmxSetWriteRegenMode(task, mx.DAQmx_Val_DoNotAllowRegen) mx.DAQmxSetBufOutputBufSize(task, int(callback_samples*100)) result = ctypes.c_uint32() mx.DAQmxGetTaskNumChans(task, result) n_channels = result.value callback_helper = SamplesGeneratedCallbackHelper(callback, n_channels) cb_ptr = mx.DAQmxEveryNSamplesEventCallbackPtr(callback_helper) mx.DAQmxRegisterEveryNSamplesEvent(task, mx.DAQmx_Val_Transferred_From_Buffer, int(callback_samples), 0, cb_ptr, None) task._cb_ptr = cb_ptr return task
def makeAnalogOutSource(portString, handle, source, freq, amp, offset, waveform): outScan = handle taskName = '' # Name of the task (I don't know when this would not be an empty string...) input1Pointer = ctypes.byref( outScan ) # Equivalent to &setStates in C, the pointer to the task handle pydaqmx.DAQmxCreateTask(taskName, input1Pointer) chan = portString # Location of the channel (this should be a physical channel, but it will be used as a virtual channel?) chanName = "" # Name(s) to assign to the created virtual channel(s). "" means physical channel name will be used minVal = pydaqmx.float64(-10.0) maxVal = pydaqmx.float64(10.0) units = pydaqmx.DAQmx_Val_Volts pydaqmx.DAQmxCreateAOVoltageChan(outScan, chan, chanName, minVal, maxVal, units, 0) fSamp = 1000 nSamp = 1000 #source = None # If you use an external clock, specify here, otherwise it should be None rate = pydaqmx.float64( fSamp ) # The sampling rate in samples per second per channel. If you use an external source for the Sample Clock, set this value to the maximum expected rate of that clock. edge = pydaqmx.DAQmx_Val_Rising # Which edge of the clock (Rising/Falling) to acquire data sampMode = pydaqmx.DAQmx_Val_ContSamps # Acquire samples continuously or just a finite number of samples sampPerChan = pydaqmx.uInt64( nSamp) # Total number of sample to acquire for each channel pydaqmx.DAQmxCfgSampClkTiming(outScan, source, rate, edge, sampMode, sampPerChan) # writeArray = np.zeros((int(nSamp),), dtype=np.float64) if waveform == 'sin': x = 2 * np.pi * freq * np.array(range(nSamp)) / 1000.0 writeArray = np.array(amp * np.sin(x) + offset, dtype=np.float64) if waveform == 'saw': # The amplitude is the peak-to-peak voltage in this waveform if freq != np.ceil(freq): print( "I don't understand decimals yet, the frequency I'm actually using is " + str(np.ceil(freq) + "Hz")) writeArray = amp / 1000.0 * (np.array(range(1000)) * freq % 1000) + offset written = pydaqmx.int32() nSampPerChan = pydaqmx.int32(nSamp) pydaqmx.DAQmxWriteAnalogF64(outScan, nSampPerChan, pydaqmx.bool32(0), pydaqmx.DAQmx_Val_WaitInfinitely, pydaqmx.DAQmx_Val_GroupByChannel, writeArray, ctypes.byref(written), None)
def setVoltage_2(val): try: taskHandle = tp.TaskHandle() daq.DAQmxCreateTask("",taskHandle) # print "taskHandle Value", taskHandle.value daq.DAQmxCreateAOVoltageChan(taskHandle,"Dev1/ao1","",0.0,10.0,cnst.DAQmx_Val_Volts,"") daq.DAQmxStartTask(taskHandle) daq.DAQmxWriteAnalogScalarF64(taskHandle,1,5.0,tp.float64(val),None) if not taskHandle == 0 : # print "Stopping Tasks\n" daq.DAQmxStopTask(taskHandle) daq.DAQmxClearTask(taskHandle) return 0 except: errBuff=tp.create_string_buffer(b"",2048) daq.DAQmxGetExtendedErrorInfo(errBuff,2048) print(errBuff.value)
def _start_analog_output(self): try: if self._laser_ao_task is not None: daq.DAQmxStopTask(self._laser_ao_task) daq.DAQmxClearTask(self._laser_ao_task) self._laser_ao_task = None self._laser_ao_task = daq.TaskHandle() daq.DAQmxCreateTask('usbAO', daq.byref(self._laser_ao_task)) daq.DAQmxCreateAOVoltageChan(self._laser_ao_task, self._NI_analog_channel, 'Laser ao channel', self._NI_voltage_range[0], self._NI_voltage_range[1], daq.DAQmx_Val_Volts, '') except: self.log.exception('Error starting analog output task.') return -1 return 0
def channel_info(channels, channel_type): task = create_task() if channel_type in ('di', 'do', 'digital'): mx.DAQmxCreateDIChan(task, channels, '', mx.DAQmx_Val_ChanPerLine) elif channel_type == 'ao': mx.DAQmxCreateAOVoltageChan(task, channels, '', -10, 10, mx.DAQmx_Val_Volts, '') elif channel_type == 'ai': mx.DAQmxCreateAIVoltageChan(task, channels, '', mx.DAQmx_Val_Cfg_Default, -10, 10, mx.DAQmx_Val_Volts, '') channels = ctypes.create_string_buffer('', 4096) mx.DAQmxGetTaskChannels(task, channels, len(channels)) devices = ctypes.create_string_buffer('', 4096) mx.DAQmxGetTaskDevices(task, devices, len(devices)) mx.DAQmxClearTask(task) return { 'channels': [c.strip() for c in channels.value.split(',')], 'devices': [d.strip() for d in devices.value.split(',')], }
def start(self, test=False, **kwargs): """ 1. Creates a task using settings. 2. Starts the task. You need to call wait_and_clean() after you start() kwargs are sent to self() to set parameters. """ self(**kwargs) # make sure everything that should be a list is a list if not isinstance(self["ao_channels"], Iterable): self["ao_channels"] = [self["ao_channels"]] # if the first element of the waveform is not an array if len(_n.shape(self["ao_waveforms"][0])) < 1: self["ao_waveforms"] = [self["ao_waveforms"]] # create the task object. This doesn't return an object, because # National Instruments. Instead, we have this handle, and we need # to be careful about clearing the thing attached to the handle. debug("output task handle") _mx.DAQmxClearTask(self._handle) _mx.DAQmxCreateTask(self["ao_task_name"], _mx.byref(self._handle)) # create all the output channels debug("output channels") # this is an array of output data arrays, grouped by channel samples = 0 data = _n.array([]) # loop over all the channels for n in range(len(self["ao_channels"])): # get the channel-specific attributes name = self["ao_channels"][n] nickname = name.replace("/", "") debug(name) if isinstance(self["ao_min"], Iterable): ao_min = self["ao_min"][n] else: ao_min = self["ao_min"] if isinstance(self["ao_max"], Iterable): ao_max = self["ao_max"][n] else: ao_max = self["ao_max"] if isinstance(self["ao_units"], Iterable): ao_units = self["ao_units"][n] else: ao_units = self["ao_units"] waveform = self["ao_waveforms"][n] # add an output channel _mx.DAQmxCreateAOVoltageChan(self._handle, name, nickname, ao_min, ao_max, ao_units, "") # add the corresponding output wave to the master data array debug("data", data, "waveform", waveform) data = _n.concatenate([data, waveform]) # Set the samples number to the biggest output array size samples = max(len(self["ao_waveforms"][n]), samples) # Configure the clock debug("output clock") # make sure we don't exceed the max #ao_max_rate = _mx.float64() #_mx.DAQmxGetSampClkMaxRate(self._handle, _mx.byref(ao_max_rate)) #if self['ao_rate'] > ao_max_rate.value: # print "ERROR: ao_rate is too high! Current max = "+str(ao_max_rate.value) # self.clean() # return False _mx.DAQmxCfgSampClkTiming(self._handle, self["ao_clock_source"], self["ao_rate"], self["ao_clock_edge"], self["ao_mode"], samples) # if we're supposed to, export a signal if not self['ao_export_terminal'] == None: _mx.DAQmxExportSignal(self._handle, self['ao_export_signal'], self['ao_export_terminal']) # update to the actual ao_rate (may be different than what was set) ao_rate = _mx.float64() _mx.DAQmxGetSampClkRate(self._handle, _mx.byref(ao_rate)) debug("output actual ao_rate =", ao_rate.value) self(ao_rate=ao_rate.value) # Configure the trigger debug("output trigger") _mx.DAQmxCfgDigEdgeStartTrig(self._handle, self["ao_trigger_source"], self["ao_trigger_slope"]) # Set the post-trigger delay try: n = self["ao_delay"] * 10e6 if n < 2: n = 2 _mx.DAQmxSetStartTrigDelayUnits(self._handle, _mx.DAQmx_Val_Ticks) _mx.DAQmxSetStartTrigDelay(self._handle, n) except: _traceback.print_exc() # write the data to the analog outputs (arm it) debug("output write", len(data)) write_success = _mx.int32() _mx.DAQmxWriteAnalogF64( self._handle, samples, False, self["ao_timeout"], _mx. DAQmx_Val_GroupByChannel, # Type of grouping of data in the array (for interleaved use DAQmx_Val_GroupByScanNumber) data, # Array of data to output _mx.byref(write_success), # Output the number of successful write None) # Reserved input (just put in None...) debug("success:", samples, write_success) if test: self.clean() else: # Start the task!! debug("output start") try: _mx.DAQmxStartTask(self._handle) except: _traceback.print_exc() return True
def setup_hw_ao(channels, buffer_duration, callback_interval, callback, task_name='hw_ao'): lines = get_channel_property(channels, 'channel', True) names = get_channel_property(channels, 'name', True) expected_ranges = get_channel_property(channels, 'expected_range', True) start_trigger = get_channel_property(channels, 'start_trigger') terminal_mode = get_channel_property(channels, 'terminal_mode') terminal_mode = NIDAQEngine.terminal_mode_map[terminal_mode] task = create_task(task_name) merged_lines = ','.join(lines) for line, name, (vmin, vmax) in zip(lines, names, expected_ranges): log.debug(f'Configuring line %s (%s) with voltage range %f-%f', line, name, vmin, vmax) mx.DAQmxCreateAOVoltageChan(task, line, name, vmin, vmax, mx.DAQmx_Val_Volts, '') properties = setup_timing(task, channels) result = ctypes.c_double() try: for line in lines: mx.DAQmxGetAOGain(task, line, result) properties['{} AO gain'.format(line)] = result.value except: # This means that the gain is not settable properties['{} AO gain'.format(line)] = 0 fs = properties['sample clock rate'] log_ao.info('AO properties: %r', properties) if terminal_mode is not None: mx.DAQmxSetAOTermCfg(task, merged_lines, terminal_mode) # If the write reaches the end of the buffer and no new data has been # provided, do not loop around to the beginning and start over. mx.DAQmxSetWriteRegenMode(task, mx.DAQmx_Val_DoNotAllowRegen) mx.DAQmxSetWriteRelativeTo(task, mx.DAQmx_Val_CurrWritePos) callback_samples = int(round(fs*callback_interval)) if buffer_duration is None: log_ao.debug('Buffer duration not provided. Setting to 10x callback.') buffer_samples = round(callback_samples*10) else: buffer_samples = round(buffer_duration*fs) # Now, make sure that buffer_samples is an integer multiple of callback_samples. log_ao.debug('Requested buffer samples %d', buffer_samples) n = int(round(buffer_samples / callback_samples)) buffer_samples = callback_samples * n log_ao.debug('Coerced buffer samples to %d (%dx %d callback_samples)', buffer_samples, n, callback_samples) log_ao.debug('Setting output buffer size to %d samples', buffer_samples) mx.DAQmxSetBufOutputBufSize(task, buffer_samples) task._buffer_samples = buffer_samples result = ctypes.c_uint32() mx.DAQmxGetTaskNumChans(task, result) task._n_channels = result.value log_ao.debug('%d channels in task', task._n_channels) #mx.DAQmxSetAOMemMapEnable(task, lines, True) #mx.DAQmxSetAODataXferReqCond(task, lines, mx.DAQmx_Val_OnBrdMemHalfFullOrLess) # This controls how quickly we can update the buffer on the device. On some # devices it is not user-settable. On the X-series PCIe-6321 I am able to # change it. On the M-xeries PCI 6259 it appears to be fixed at 8191 # samples. Haven't really been able to do much about this. mx.DAQmxGetBufOutputOnbrdBufSize(task, result) task._onboard_buffer_size = result.value log_ao.debug('Onboard buffer size %d', task._onboard_buffer_size) result = ctypes.c_int32() mx.DAQmxGetAODataXferMech(task, merged_lines, result) log_ao.debug('Data transfer mechanism %d', result.value) mx.DAQmxGetAODataXferReqCond(task, merged_lines, result) log_ao.debug('Data transfer condition %d', result.value) #result = ctypes.c_uint32() #mx.DAQmxGetAOUseOnlyOnBrdMem(task, merged_lines, result) #log_ao.debug('Use only onboard memory %d', result.value) #mx.DAQmxGetAOMemMapEnable(task, merged_lines, result) #log_ao.debug('Memory mapping enabled %d', result.value) #mx.DAQmxGetAIFilterDelayUnits(task, merged_lines, result) #log_ao.debug('AI filter delay unit %d', result.value) #result = ctypes.c_int32() #mx.DAQmxGetAODataXferMech(task, result) #log_ao.debug('DMA transfer mechanism %d', result.value) log_ao.debug('Creating callback after every %d samples', callback_samples) task._cb = partial(hw_ao_helper, callback) task._cb_ptr = mx.DAQmxEveryNSamplesEventCallbackPtr(task._cb) mx.DAQmxRegisterEveryNSamplesEvent( task, mx.DAQmx_Val_Transferred_From_Buffer, int(callback_samples), 0, task._cb_ptr, None) mx.DAQmxTaskControl(task, mx.DAQmx_Val_Task_Reserve) task._names = verify_channel_names(task, names) task._devices = device_list(task) task._fs = fs return task
import numpy as np import time outScan = pydaqmx.TaskHandle() taskName = '' # Name of the task (I don't know when this would not be an empty string...) input1Pointer = ctypes.byref( outScan) # Equivalent to &setStates in C, the pointer to the task handle pydaqmx.DAQmxCreateTask(taskName, input1Pointer) chan = 'Dev1/ao1' # Location of the channel (this should be a physical channel, but it will be used as a virtual channel?) chanName = "" # Name(s) to assign to the created virtual channel(s). "" means physical channel name will be used minVal = pydaqmx.float64(-10.0) maxVal = pydaqmx.float64(10.0) units = pydaqmx.DAQmx_Val_Volts pydaqmx.DAQmxCreateAOVoltageChan(outScan, chan, chanName, minVal, maxVal, units, 0) fSamp = 1000 nSamp = 1000 freq = 50 # Frequency in Hertz amp = 10 # Amplitude in volts source = None # If you use an external clock, specify here, otherwise it should be None rate = pydaqmx.float64( fSamp ) # The sampling rate in samples per second per channel. If you use an external source for the Sample Clock, set this value to the maximum expected rate of that clock. edge = pydaqmx.DAQmx_Val_Rising # Which edge of the clock (Rising/Falling) to acquire data sampMode = pydaqmx.DAQmx_Val_ContSamps # Acquire samples continuously or just a finite number of samples sampPerChan = pydaqmx.uInt64( nSamp) # Total number of sample to acquire for each channel pydaqmx.DAQmxCfgSampClkTiming(outScan, source, rate, edge, sampMode, sampPerChan)
def activate_AO(self, taskhandles, channel, voltage_range): daq.DAQmxCreateTask('', daq.byref(taskhandles)) daq.DAQmxCreateAOVoltageChan(taskhandles, channel, '', voltage_range[0], voltage_range[1], daq.DAQmx_Val_Volts, None) return taskhandles
def set_up_scanner(self, counter_channel = None, photon_source = None, clock_channel = None, scanner_ao_channels = None): """ Configures the actual scanner with a given clock. @param string counter_channel: if defined, this is the physical channel of the counter @param string photon_source: if defined, this is the physical channel where the photons are to count from @param string clock_channel: if defined, this specifies the clock for the counter @param string scanner_ao_channels: if defined, this specifies the analoque output channels @return int: error code (0:OK, -1:error) """ if self._scanner_clock_daq_task == None and clock_channel == None: self.logMsg('No clock running, call set_up_clock before starting the counter.', \ msgType='error') return -1 if self._scanner_counter_daq_task != None: self.logMsg('Another counter is already running, close this one first.', \ msgType='error') return -1 if counter_channel != None: self._scanner_counter_channel = counter_channel if photon_source != None: self._photon_source = photon_source if clock_channel != None: self._my_scanner_clock_channel = clock_channel else: self._my_scanner_clock_channel = self._scanner_clock_channel if scanner_ao_channels != None: self._scanner_ao_channels = scanner_ao_channels # init ao channels / task for scanner, should always be active # the type definition for the task, an unsigned integer datatype (uInt32): self._scanner_ao_task = daq.TaskHandle() daq.DAQmxCreateTask('', daq.byref(self._scanner_ao_task)) # Assign the created task to an analog output voltage channel daq.DAQmxCreateAOVoltageChan(self._scanner_ao_task, # add to this task self._scanner_ao_channels, '', # use sanncer ao_channels, name = '' self._voltage_range[0], # min voltage self._voltage_range[1], # max voltage daq.DAQmx_Val_Volts,'') # units is Volt # set task timing to on demand, i.e. when demanded by software daq.DAQmxSetSampTimingType(self._scanner_ao_task, daq.DAQmx_Val_OnDemand) #self.set_scanner_command_length(self._DefaultAOLength) self._scanner_counter_daq_task = daq.TaskHandle() daq.DAQmxCreateTask('', daq.byref(self._scanner_counter_daq_task)) # TODO: change this to DAQmxCreateCISemiPeriodChan daq.DAQmxCreateCIPulseWidthChan(self._scanner_counter_daq_task, #add to this task self._scanner_counter_channel, #use this counter '', #name 0, #expected minimum value self._max_counts*self._scanner_clock_frequency, #expected maximum value daq.DAQmx_Val_Ticks, #units of width measurement, here photon ticks daq.DAQmx_Val_Rising, '') #start pulse width measurement on rising edge #set the pulses to counter self._trace_counter_in daq.DAQmxSetCIPulseWidthTerm(self._scanner_counter_daq_task, self._scanner_counter_channel, self._my_scanner_clock_channel+'InternalOutput') #set the timebase for width measurement as self._photon_source daq.DAQmxSetCICtrTimebaseSrc(self._scanner_counter_daq_task, self._scanner_counter_channel, self._photon_source ) return 0
def setup_sw_ao(lines, expected_range): # TODO: DAQmxSetAOTermCfg task = create_task() lb, ub = expected_range mx.DAQmxCreateAOVoltageChan(task, lines, '', lb, ub, mx.DAQmx_Val_Volts, '') return task