def AI_start_delay(device_name): if 'PFI0' not in DAQmxGetDevTerminals(device_name): return None task = Task() clock_terminal = '/' + device_name + '/PFI0' rate = DAQmxGetDevAIMaxSingleChanRate(device_name) Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2] num_samples = 1000 chan = device_name + '/ai0' task.CreateAIVoltageChan(chan, "", c.DAQmx_Val_RSE, Vmin, Vmax, c.DAQmx_Val_Volts, None) task.CfgSampClkTiming("", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, num_samples) task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising) start_trig_delay = float64() delay_from_sample_clock = float64() sample_timebase_rate = float64() task.GetStartTrigDelay(start_trig_delay) task.GetDelayFromSampClkDelay(delay_from_sample_clock) task.GetSampClkTimebaseRate(sample_timebase_rate) task.ClearTask() total_delay_in_ticks = start_trig_delay.value + delay_from_sample_clock.value total_delay_in_seconds = total_delay_in_ticks / sample_timebase_rate.value return total_delay_in_seconds
def AI_start_delay(device_name): """Empirically determines the analog inputs' start delay. Args: device_name (str): NI-MAX device name Returns: float: Analog input start delay in seconds. `None` if analog inputs not supported. """ if 'PFI0' not in DAQmxGetDevTerminals(device_name): return None task = Task() clock_terminal = '/' + device_name + '/PFI0' rate = DAQmxGetDevAIMaxSingleChanRate(device_name) Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2] num_samples = 1000 chan = device_name + '/ai0' supp_types = DAQmxGetPhysicalChanAITermCfgs(chan) if supp_types & c.DAQmx_Val_Bit_TermCfg_RSE: input_type = c.DAQmx_Val_RSE elif supp_types & c.DAQmx_Val_Bit_TermCfg_Diff: input_type = c.DAQmx_Val_Diff elif supp_types & c.DAQmx_Val_Bit_TermCfg_PseudoDIFF: input_type = c.DAQmx_Val_PseudoDiff task.CreateAIVoltageChan( chan, "", input_type, Vmin, Vmax, c.DAQmx_Val_Volts, None ) task.CfgSampClkTiming( "", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, num_samples ) task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising) start_trig_delay = float64() delay_from_sample_clock = float64() sample_timebase_rate = float64() try: task.GetStartTrigDelay(start_trig_delay) except PyDAQmx.DAQmxFunctions.AttributeNotSupportedInTaskContextError: # device does not have a Start Trigger Delay property # is likely a dynamic signal acquisition device with filter # delays instead. start_trig_delay.value = 0 try: task.GetDelayFromSampClkDelay(delay_from_sample_clock) except PyDAQmx.DAQmxFunctions.AttributeNotSupportedInTaskContextError: # seems simultaneous sampling devices do not have this property, # so assume it is zero delay_from_sample_clock.value = 0 task.GetSampClkTimebaseRate(sample_timebase_rate) task.ClearTask() total_delay_in_ticks = start_trig_delay.value + delay_from_sample_clock.value total_delay_in_seconds = total_delay_in_ticks / sample_timebase_rate.value return total_delay_in_seconds
def trigger_analog_output(devport, edge_selection): ''' Using PFI to Trigger an Analog Output Generation in devport = Device/port e.g. Dev2/PFI0 out task = Task handle ''' logger.info("testlog, Device: {}".format(devport)) max_num_samples = 2 task = Task() task.CreateAOVoltageChan(devport, '', -10.0, 10.0, DAQmx_Val_Volts, None) task.CfgSampClkTiming('', float64(100), DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, uInt64(max_num_samples)) if edge_selection == 'R': task.CfgDigEdgeStartTrig("/Dev2/PFI1", DAQmx_Val_Rising) #logger.info("testlog, trigger analog output -function, Rising: {}") else: task.CfgDigEdgeStartTrig("/Dev2/PFI1", DAQmx_Val_Falling) #logger.info("testlog, trigger analog output -function, Falling: {}") return task
def trigger_analog_input(devport, samples, rate, edge_selection): ''' Using PFI to Trigger an Analog Input Acquisition in devport = Device/port e.g. Dev2/PFI0 out task = Task handle ''' logger.info("testlog, Device: {}".format(devport)) max_num_samples = samples task = Task() task.CreateAIVoltageChan(devport, '', DAQmx_Val_RSE, -10.0, 10.0, DAQmx_Val_Volts, None) task.CfgSampClkTiming('', float64(rate), DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, uInt64(max_num_samples)) #logger.info("trigger analog input -function, 1: {}") if edge_selection == 'R': task.CfgDigEdgeStartTrig("/Dev2/PFI0", DAQmx_Val_Rising) logger.info("testlog, trigger analog input -function, Rising: {}") else: task.CfgDigEdgeStartTrig("/Dev2/PFI0", DAQmx_Val_Falling) logger.info("testlog, trigger analog input -function, Falling: {}") task.StartTask() return task
def createCOPulseTask(chan, freq, delay, duty, numPulses=4, edge=DAQmx_Val_Rising, triggerSource="PFI0"): th = Task() th.CreateCOPulseChanFreq(chan, "", DAQmx_Val_Hz, DAQmx_Val_Low, delay, freq, duty) th.CfgDigEdgeStartTrig(triggerSource, edge) th.CfgImplicitTiming(DAQmx_Val_FiniteSamps, numPulses) th.SetTrigAttribute(DAQmx_StartTrig_Retriggerable, True) return th
def createCOPulseTask2(chan, totTime, delay, pulseWidth, numPulses=4, edge=DAQmx_Val_Rising, triggerSource="PFI0"): th = Task() #th.CreateCOPulseChanFreq ( chan, "", DAQmx_Val_Hz, DAQmx_Val_Low, delay, freq, th.CreateCOPulseChanTime(chan, "", DAQmx_Val_Seconds, DAQmx_Val_Low, delay, totTime - pulseWidth, pulseWidth) th.CfgDigEdgeStartTrig(triggerSource, edge) th.CfgImplicitTiming(DAQmx_Val_FiniteSamps, numPulses) th.SetTrigAttribute(DAQmx_StartTrig_Retriggerable, True) return th
def AI_filter_delay(device_name): """Determine the filter delay for dynamic signal acquistion devices. Returns the delay in clock cycles. Absolute delay will vary with sample rate. Args: device_name (str): NI-MAX device name Returns: int: Number of analog input delays ticks between task start and acquisition start. """ if 'PFI0' not in DAQmxGetDevTerminals(device_name): return None task = Task() clock_terminal = '/' + device_name + '/PFI0' rate = DAQmxGetDevAIMaxSingleChanRate(device_name) Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2] num_samples = 1000 chan = device_name + '/ai0' task.CreateAIVoltageChan( chan, "", c.DAQmx_Val_PseudoDiff, Vmin, Vmax, c.DAQmx_Val_Volts, None ) task.CfgSampClkTiming( "", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, num_samples ) task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising) start_filter_delay = float64() sample_timebase_rate = float64() # get delay in number of clock samples task.SetAIFilterDelayUnits("", c.DAQmx_Val_SampleClkPeriods) task.GetAIFilterDelay("", start_filter_delay) task.GetSampClkTimebaseRate(sample_timebase_rate) task.ClearTask() return int(start_filter_delay.value)
from PyDAQmx import Task import PyDAQmx import numpy as np from ctypes import byref pulse = Task() pulse.CreateCOPulseChanTime("/Dev2/ctr0", "LED pulse", PyDAQmx.DAQmx_Val_Seconds, PyDAQmx.DAQmx_Val_Low, 1.00, 10, 10) pulse.StartTask() voltage = Task() voltage.CreateAOVoltageChan("/Dev2/ao1", "LED", 0, 5, PyDAQmx.DAQmx_Val_Volts, None) voltage.CfgImplicitTiming(PyDAQmx.DAQmx_Val_ContSamps, 1000) voltage.CfgDigEdgeStartTrig("/Dev2/pfi0", PyDAQmx.DAQmx_Val_Rising) voltage.WriteAnalogScalarF64(1, 0, 3, None) # voltage.CfgSampClkTiming(None,1000,PyDAQmx.DAQmx_Val_Rising,PyDAQmx.DAQmx_Val_ContSamps,4000) # voltage.CfgDigEdgeStartTrig("/Dev2/pfi0",PyDAQmx.DAQmx_Val_Rising) # voltage.StartTask() # voltage.WriteAnalogF64(1,0,voltage_out,None) # taskHandle,4000,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL) # class LED(Task): # def __init__(self): # Task.__init__(self) # self.CreateAOVoltageChan("/Dev2/ao1","LED",0,5,PyDAQmx.DAQmx_Val_Volts,None) # self.CfgSampClkTiming(None,1000,PyDAQmx.DAQmx_Val_Rising,PyDAQmx.DAQmx_Val_ContSamps,1000) # self.CfgDigEdgeStartTrig("/Dev2/pfi0",PyDAQmx.DAQmx_Val_Rising) # self.AutoRegisterDoneEvent(0)
class digFreqGenerator(object): def __init__(self): self.counter = '' self.Task = Task() self.initialized = False self.initialDelay = 0 self.dutyCycle = 0.50 self.frequency = 1e6 self._numberOfPulses = 0 self.status = 0 self._startTriggerSource = '' self.triggerType = TriggerType.Software self.timeout = -1 def _getStartTriggerSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.Task.GetDigEdgeStartTrigSrc(buff, buffSize) self._startTriggerSource = buff.value return self._startTriggerSource def _setStartTriggerSource(self, value): if self.initialized: self.status = self.Task.SetDigEdgeStartTrigSrc(value) #value = self._getStartTriggerSource() self._startTriggerSource = value startTriggerSource = property(_getStartTriggerSource, _setStartTriggerSource) def _getNumberOfPulses(self): if self.initialized: sampPerChan = uInt32() self.status = self.Task.GetSampQuantSampPerChan(sampPerChan) self._numberOfPulses = sampPerChan.value return self._numberOfPulses def _setNumberOfPulses(self, value): if self.initialized: self.status = self.Task.SetSampQuantSampPerChan(value) if value > 0: self.status = self.Task.SetSampQuantSampMode( DAQmx_Val_FiniteSamps) else: self.status = self.Task.SetSampQuantSampMode( DAQmx_Val_ContSamps) self._numberOfPulses = value numberOfPulses = property(_getNumberOfPulses, _setNumberOfPulses) def init(self, counter=None): if counter is not None: self.counter = counter self.status = self.Task.CreateCOPulseChanFreq(self.counter, '', DAQmx_Val_Hz, DAQmx_Val_Low, numpy.float64(self.initialDelay), numpy.float64(self.frequency), numpy.float64(self.dutyCycle)) if self._numberOfPulses > 0: self.status = self.Task.CfgImplicitTiming(DAQmx_Val_FiniteSamps, uInt64(self._numberOfPulses)) else: self.status = self.Task.CfgImplicitTiming(DAQmx_Val_ContSamps, uInt64(int(1e6))) if self.triggerType == TriggerType.Hardware: self.status = self.Task.CfgDigEdgeStartTrig( self._startTriggerSource, DAQmx_Val_Rising) self.status = self.Task.SetStartTrigRetriggerable(bool32(True)) self.initialized = True def _getOutputTerm(self): buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.Task.GetCOPulseTerm(self.counter, buff, buffSize) return buff.value def _setOutputTerm(self, term = 'PFI0'): self.status = self.Task.SetCOPulseTerm(self.counter, term) outputTerm = property(_getOutputTerm, _setOutputTerm) def start(self): self.status = self.Task.StartTask() def waitUntilDone(self): self.status = self.Task.WaitUntilTaskDone(self.timeout) def stop(self): retriggerable = bool32() self.status = self.Task.GetStartTrigRetriggerable(retriggerable) try: if retriggerable == 0: self.status = self.Task.StopTask() except DAQError as e: print(e.error) print(retriggerable.value) if e.error == 200010 and retriggerable.value == 1: print('caught') pass else: raise e def close(self): self.status = self.Task.ClearTask() self.Task = Task() self.initialized = False
class pCounter(object): ## This function is the constructor for the pCounter class. # # It creates internal variables required to perform functions within # the class. This function does not initialize any hardware. # @param self The object pointer. def __init__(self, **kwargs): #super(pCounter, self).__init__() ## The string that identifies the DAQmx device and counter # for the counter that is used to count edges. # # Example: PXISlot5/ctr0 self.edgeCounter = '' ## The string that identifies the DAQmx device and counter # for the counter that is used to create the sample clock. # # Example: /PXI1Slot5/ctr0 self.clockCounter = '' ## A boolean that enables the start trigger. # # The default is false, which disables the start trigger. # The measurement will immediately start when the start() # method is called. # A true value will make the measurement start when a digital # trigger is received on the line specified by the triggerSource # variable. self.enableStartTrigger = False ## A string that identifies the DAQmx digital line that will # be used as an input to the edge counter. # # Default: PFI0 self.edgeCntrTerm = kwargs.get('edgeCntrTerm', 'PFI0') self._triggerClkSource = 'Ctr0InternalOutput' ## A string that identifies the DAQmx digital line that will # be used as the start trigger. # # Default: PFI1 self.triggerSource = 'PFI1' ## A string that identifies the DAQmx digital line that will # output the sample clock. # # Default: PFI12 self.clockSourceTerm = kwargs.get('clockSourceterm', 'PFI12') ## The task reference for the edge counter. self.edgeCntrTask = Task() ## The task reference for the sample clock counter. self.clockCntrTask = Task() ## @var samples # This is the number of samples to take. It is the size # of the data array returned by the read() method. self._samples = kwargs.get('samples', None) ## @var sampleRate # This is the sample rate to use when counting edges. self._sampleRate = kwargs.get('sampleRate', None) ## @var acqTime # This is the time in milliseconds for a full acquisition # period. self._acqTime = None ## @var binTime # This is the time in millisenconds to take a single sample. self._binTime = None self._status = int32() ## This is the time to wait for a start trigger. # # If the timeout passes, then an error is generated. Ignore # this variable if the start trigger is disabled. self.timeout = kwargs.get('timeout', 1) self._samplesRead = None def _calcBinAndAcq(self): self._binTime = 1000. / self._sampleRate self._acqTime = (self._samples - 1.) * self._binTime def _calcSampsAndSampRate(self): self._sampleRate = 1000 / self._binTime self._samples = int((self._acqTime / self._binTime) + 1) def _getSamples(self): return self._samples def _setSamples(self, value): self._samples = value if self._sampleRate: self._calcBinAndAcq() samples = property(_getSamples, _setSamples) def _getSampleRate(self): return self._sampleRate def _setSampleRate(self, value): self._sampleRate = value if self._samples: self._calcBinAndAcq() sampleRate = property(_getSampleRate, _setSampleRate) def _getBinTime(self): return self._binTime def _setBinTime(self, value): self._binTime = value if self._acqTime: self._calcSampsAndSampRate() binTime = property(_getBinTime, _setBinTime) def _getAcqTime(self): return self._acqTime def _setAcqTime(self, value): self._acqTime = value if self._binTime: self._calcSampsAndSampRate() acqTime = property(_getAcqTime, _setAcqTime) ## This function initializes the pCounter class and opens a # reference to the DAQmx device(s). # # If specifiying a acqTime and binTime or samples and sampleRate, # only one pair of parameters need to be provided. When specifying # acqTime and binTime, the samples and sampleRate are calculated. # When specifying the samples and sampleRate, the acqTime and # binTime are calculated. # # @param self The object pointer. # @param clockCounter The string that identifies the DAQmx # device and counter for the counter that is used to create # the sample clock. # @param edgeCounter The string that identifies the DAQmx # device and counter for the counter that is used to count edges. # @param acqTime This is the time in milliseconds for a full # acquisition period. # @param binTime This is the time in millisenconds to take a # single sample. # @param samples The number of samples for the pCounter to take. # @param sampleRate The frequency of the samples taken by the # pCounter. def init(self, clockCounter=None, edgeCounter=None, acqTime=None, binTime=None, samples=None, sampleRate=None): if edgeCounter: self.edgeCounter = edgeCounter if clockCounter: self.clockCounter = clockCounter if samples and sampleRate: self._samples = samples self._sampleRate = sampleRate self._calcBinandAcq() if acqTime and binTime: self._acqTime = acqTime self._binTime = binTime self._calcSampsAndSampRate() # Setup the Edge Counter self._status = self.edgeCntrTask.CreateCICountEdgesChan( self.edgeCounter, '', DAQmx_Val_Rising, 0, DAQmx_Val_CountUp) self._status = self.edgeCntrTask.SetCICountEdgesTerm( self.edgeCounter, self.edgeCntrTerm) self._status = self.edgeCntrTask.CfgSampClkTiming( self._triggerClkSource, float64(self._sampleRate), DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, uInt64(self._samples + 1)) # Setup the Clock Source Counter self._status = self.clockCntrTask.CreateCOPulseChanFreq( self.clockCounter, '', DAQmx_Val_Hz, DAQmx_Val_Low, 0, float64(self._sampleRate), float64(0.5)) self._status = self.clockCntrTask.SetCOPulseTerm( self.clockCounter, self.clockSourceTerm) self._status = self.clockCntrTask.CfgImplicitTiming( DAQmx_Val_ContSamps, uInt64(self._samples + 1)) if self.enableStartTrigger: self._status = self.clockCntrTask.CfgDigEdgeStartTrig( self.triggerSource, DAQmx_Val_Rising) ## This function initializes the pCounter class using the # chassis config file and opens a reference to the DAQmx device(s). # # @param self The object reference. # @param filepath The path to the chassis config file. def initFromFile(self, filepath): from .chassisConfigParser import chassisConfigParser config = chassisConfigParser() edgeCounter, clockCounter = config.readCntrSection(filepath) self.init(clockCounter, edgeCounter) ## This function starts the measurement. # # If the start trigger is enabled, then a the pCounter waits # for that digital trigger. Otherwise the measurement takes # place immediately. # @param self The object pointer. def start(self): self._status = self.edgeCntrTask.StartTask() self._status = self.clockCntrTask.StartTask() ## This function stops the measurement. # # It needs to be called everytime the start() method is called. # @param self The object pointer. def stop(self): self._status = self.edgeCntrTask.StopTask() self._status = self.clockCntrTask.StopTask() ## This function returns an array of the edge counts with an # array size equal to the number of samples. # # @param self The object pointer. def read(self): samplesRead = int32() data = np.zeros(self._samples + 1, dtype=np.uint32) self._status = self.edgeCntrTask.ReadCounterU32( int32(self._samples + 1), float64(self.timeout), data, uInt32(self._samples + 1), ctypes.byref(samplesRead), None) self._samplesRead = samplesRead.value dataDelta = [] for i, item in enumerate(data): if i > 0: dataDelta.append(item - preValue) preValue = item length = len(dataDelta) dataSum = 0 for item in dataDelta: dataSum += item mean = float(dataSum / length) sqSum = 0 for item in dataDelta: sq = np.square(item - mean) sqSum += sq stdDev = sqrt(sqSum / length) return dataDelta, mean, stdDev ## This function performs the start(), read(), and stop() methods # in one function call. # # This is useful for when the results of the read() method can be # retrieved immediately after a start() # @param self The object pointer. def measure(self): # Start the Tasks self.start() # Read the data data, mean, stdDev = self.read() # Stop the Tasks self.stop() return data, mean, stdDev ## This function closes the refences to the DAQmx devices. # # @param self The object pointer. def close(self): self._status = self.edgeCntrTask.ClearTask() self.edgeCntrTask = Task() self._status = self.clockCntrTask.ClearTask() self.clockCntrTask = Task() ## This function is the destructor for the pCounter class. # # It deletes internal variables and closes the references to # the DAQmx devices if they are not already closed. # @param self The object pointer. def __del__(self): self.close() del self.edgeCounter del self.clockCounter del self.enableStartTrigger del self.edgeCntrTerm del self._triggerClkSource del self.triggerSource del self.clockSourceTerm del self.edgeCntrTask del self.clockCntrTask del self._samples del self._sampleRate del self._acqTime del self._binTime del self._status del self.timeout del self._samplesRead
class TriggerOutputDig(object): t = None wvfms = None Nsamps = None sampleRate = None pulseLength = None def __init__(self, port="Dev12/port0", startTrigChan="PFI0"): self.th = Task() #Task.__init__(self) self.th.CreateDOChan(port, "", DAQmx_Val_ChanForAllLines) #self.setTiming(sampleRate, pulseLength) self.th.CfgDigEdgeStartTrig(startTrigChan, DAQmx_Val_Rising) self.th.SetStartTrigRetriggerable(True) #DAQmxLoadTask("WvfmOutputTask", byref(self.taskHandle)) def start(self): self.th.StartTask() def stop(self): try: self.th.StopTask() except DAQError as e: if e.error == 200010: self.th.StopTask() else: raise (e) def setTiming(self, sampleRate, waveformLength): Nsamps = int(waveformLength * sampleRate) #self.th.CfgSampClkTiming("",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps, 5*Nsamps); self.th.CfgSampClkTiming("", sampleRate, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, Nsamps) self.sampleRate = sampleRate self.Nsamps = Nsamps def reset(self): try: self.stop() sleep(0.2) except DAQError: pass finally: self.start() def setWaveforms(self, t, *wvfms): Npts = t.size sampleRate = 1. / (t[1] - t[0]) totalLength = Npts / sampleRate self.setTiming(sampleRate, totalLength) wvfmPort = np.zeros(t.size, dtype='u4') for k, wv in enumerate(wvfms): wv[:] = np.where(wv, 1, 0) wv = wv.astype('u4') wvfmPort += (k + 1) * wv written = int32() self.th.WriteDigitalU32(1 * wvfmPort.size, 1, 10, DAQmx_Val_GroupByChannel, np.hstack(1 * [wvfmPort]).astype('u4'), byref(written), None) self.t = t self.wvfms = wvfms return self.t, wvfmPort
class AnalogOutput(object): ## This function is a constructor for the AnalogOutput class. # # It creates the internal variables required to perform functions within the # class. This function does not initialize any hardware. def __init__(self): ## The DAQmx task reference. self.taskRef = Task() ## This is a boolean that is true when the DAQmx task has been initialized. self.initialized = False ## This is the status of the DAQmx task. # # A value greater than 0 means that an error has occurred. When the status # is greater than 0 an error should be reported by the class. self.status = int32() ## @var sampleRate # This is the sample rate of the analog output. self._sampleRate = 100e3 ## @var numChannels # This is the number of channels configured in the task. self._numChannels = 0 ## @var samplesPerChannel # This is the number of samples per channel that will be # generated in Finite mode. self._samplesPerChannel = 100 ## @var clkSource # This is the sample clock source terminal. It can be set to an # internal clock or external clock such as a PFI line i.e. "/PXI1Slot3/PFI15." self._clkSource = '' ## @var startTriggerSource # This is the start trigger source terminal. The software # ignores this value when the triggerType is set to "Software". Otherwise when # the triggerType is "Hardware," this terminal is used to start analog # generation. Example Value: "/PXI1Slot3/PFI0" self._startTriggerSource = '' ## @var pauseTriggerSource # The source terminal of the pause trigger. This can be # any PFI or backplane trigger such as 'PFI5' and 'PXI_TRIG5' self._pauseTriggerSource = '' ## This is the start trigger terminal of the NI-Sync card. # # Setting this value will make sure that the start trigger will be # propogated through the PXI backplane. If there is no sync card needed # leave the value default. self.startTriggerSyncCard = '' ## This is the mode of operation for the analog outputs. # # There are currently three modes available. Static mode is where one # static voltage is set with no need for a sample clock. Finite mode is # where a finite number of voltages will be set at a sample clock rate. # Continuous mode is where a sequence of voltages are generated at a sample # rate and then repeated until the stop() method is called. self.mode = dutil.Mode.Finite ## The trigger type for the analog outputs. # # There are currently two trigger types - "Software" and # "Hardware." The "Software" mode means that analog output channels are not # syncronized. While "Hardware" means that analog output channels are # syncronized to a start trigger. The startTriggerSouce attribute must be # configured appropriately. self.triggerType = dutil.TriggerType.Software ## The number of times to iterate over a Finite number of samples. # # This value is only useful in the "Finite" mode. It is the number of # times that a sequence of voltages will be looped. The default is allways 1. self.loops = 1 ## The estimated time to generate the samples for a Finite generation. # # Once the input buffer of the analog input is configured, the # amount of time it takes to generate the voltages in the buffer can be # estimated. This is a function of the sample rate and the number of samples # per channel. (This attribute is for internal use only. This attribute may # not return an accurate value.) self.estAcqTime = 0 ## The analog output buffer. # # This is the data that is stored in the buffer of the Analog Output card. self.buff = None self._timeoutPad = 0.01 def _getDone(self): done = bool32() if self.initialized: self.status = self.taskRef.GetTaskComplete(ctypes.byref(done)) else: done.value = 1 return bool(done.value) ## @var done # Returns the task done status. # # This mode works differently depending on the mode. <br /> # <ul> # <li><B>Static and Continuous</B>: done is false after a start # method and true</li> # only after a stop method. # <li><B>Finite</B>: done is false until all samples are # generated.</li></ul> done = property(_getDone) def _getPauseTriggerSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetDigLvlPauseTrigSrc(buff, buffSize) self._pauseTriggerSource = buff.value return self._pauseTriggerSource def _setPauseTriggerSource(self, value): if self.initialized: if value == '': self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_None) self.status = self.taskRef.ResetDigLvlPauseTrigSrc() else: self.status = self.taskRef.SetDigLvlPauseTrigWhen( DAQmx_Val_High) self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_DigLvl) self.status = self.taskRef.SetDigLvlPauseTrigSrc(value) self._pauseTriggerSource = value pauseTriggerSource = property(_getPauseTriggerSource, _setPauseTriggerSource) ## Initializes the analog outputs based on the object's configuration. # @param self The object pointer. # @param physicalChannel A string representing the device and analog # output channels. Example Value: "PXI1Slot3/ao0:7" def init(self, physicalChannel): self.__createTask(physicalChannel) self.initialized = True #Finite Mode if self.mode == dutil.Mode.Finite: self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen) self.__configTiming(DAQmx_Val_FiniteSamps) #Continuous Mode elif self.mode == dutil.Mode.Continuous: self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen) self.__configTiming(DAQmx_Val_ContSamps) #Static Mode elif self.mode == dutil.Mode.Static: self.setSampleRate(self._sampleRate) self.setSamplesPerChannel(1) self.pauseTriggerSource = self._pauseTriggerSource #print self.samplesPerChannel #print self._sampleRate #print self.clkSource #print self.startTriggerSource ## This function returns the samples per channel configured in the DAQmx Task. # @param self The object pointer. def getSamplesPerChannel(self): if self.initialized: samplesPerChannel = uInt64() self.status = self.taskRef.GetSampQuantSampPerChan( ctypes.byref(samplesPerChannel)) self._samplesPerChannel = samplesPerChannel.value return self._samplesPerChannel ## This function sets the samples per channel in the DAQmx Task. # @param self The object pointer. # @param value The value to set the samples per channel. def setSamplesPerChannel(self, value): if self.initialized: self.status = self.taskRef.SetSampQuantSampPerChan(uInt64(value)) self._samplesPerChannel = value ## This funciton deletes the samplesPerChannel variable inside the AnalogOutput # object. # # It is an internal function that is called in the class destructor. It should # not be called. def _delSamplesPerChannel(self): """ This funciton deletes the samplesPerChannel variable inside the AnalogOutput object. It is an internal function that is called in the class destructor. It should not be called. """ del self._samplesPerChannel samplesPerChannel = property(getSamplesPerChannel, setSamplesPerChannel, _delSamplesPerChannel) ## This function returns the sample clock source configured in the DAQmx Task. # @param self The object pointer. def getClkSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetSampClkSrc(buff, buffSize) self._clkSource = buff.value return self._clkSource ## This function sets the sample clock source in the DAQmx Task. # @param self The object pointer. # @param value The string value for the clock source terminal. def setClkSource(self, value): if self.initialized: self.status = self.taskRef.SetSampClkSrc(value) value = self.getClkSource() self._clkSource = value ## This function deletes the clkSource variable within the AnalogOutput object. # # It is an internal function that is called in the class destructor. It should # not be called. def _delClkSource(self): del self._clkSource clkSource = property(getClkSource, setClkSource, _delClkSource) ## This function return the start trigger source configured in the DAQmx Task. # @param self The object pointer. def getStartTriggerSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetDigEdgeStartTrigSrc(buff, buffSize) self._startTriggerSource = buff.value return self._startTriggerSource ## This function sets the start trigger source in the DAQmx Task. # @param self The object pointer. # @param value The string vaue of the start trigger source. # Example value: "\PXI1Slot3\PFI0" def setStartTriggerSource(self, value): if self.initialized: self.status = self.taskRef.SetDigEdgeStartTrigSrc(value) value = self.getStartTriggerSource() self._startTriggerSource = value ## This function deletes the startTriggerSource variable within the AnalogOutput object. # # It is an internal function that is called in the class destructor. It should # not be called. def _delStartTriggerSource(self): del self._startTriggerSource startTriggerSource = property(getStartTriggerSource, setStartTriggerSource, _delStartTriggerSource) ## This function returns the number of channels configured in the DAQmx Task. # @param self The object pointer. def getNumChannels(self): if self.initialized: numChannels = uInt32() self.status = self.taskRef.GetTaskNumChans( ctypes.byref(numChannels)) self._numChannels = numChannels.value return self._numChannels numChannels = property(getNumChannels) ## This function returns the sample rate configured in the DAQmx Task. # @param self The object pointer. def getSampleRate(self): if self.initialized: sampleRate = float64() self.status = self.taskRef.GetSampClkRate(ctypes.byref(sampleRate)) self._sampleRate = sampleRate.value return self._sampleRate ## This funciton sets the sample rate in the DAQmx Task. # @param self The object pointer. # @param value The value of the sample rate. def setSampleRate(self, value): if self.initialized: self.status = self.taskRef.SetSampClkRate(float64(value)) self._sampleRate = value ## This function deletes the sample rate variable inside the AnalogOutput object. # @param self The object pointer. def _delSampleRate(self): del self._sampleRate sampleRate = property(getSampleRate, setSampleRate, _delSampleRate) ## This function returns a 1D numpy array of samples with random voltages. # The returned value is intended to be used to write samples to the buffer with # the writeToBuffer() method. # @param self The object pointer. # @param numChannels The number of channels to generate. If this parameter is # not provided, Then the function will generate the number of channels configured # in the analog output task. def createTestBuffer(self, numChannels=0): numChannels = numChannels if numChannels > 0 else self.getNumChannels() return numpy.float64( numpy.random.rand(self._samplesPerChannel * numChannels)) ## This function returns a 1D numpy array of sine waves. The returned # value is intended to be used to write samples to the buffer with the # writeToBuffer() method. # @param self The object pointer. def createSineTestBuffer(self): from .createSineWave import createSineWave numChannels = self.getNumChannels() for i in range(numChannels): data = createSineWave(10, 100e3, self._sampleRate, self._samplesPerChannel, ((2 * numpy.pi) / numChannels) * i) if i == 0: sineData = data['amplitude'] else: sineData = numpy.append(sineData, data['amplitude']) return sineData ## This function writes the specified values into the buffer. # @param self The object pointer. # @param data This is a 1D 64-bit floating point numpy array that contians data # for each channel. Channels are non-interleaved (channel1 n-samples then # channel2 n-samples). def writeToBuffer(self, data): autostart = self.mode == dutil.Mode.Static self.buff = data samplesWritten = int32() self.status = self.taskRef.WriteAnalogF64(self._samplesPerChannel, autostart, 10, DAQmx_Val_GroupByChannel, data, ctypes.byref(samplesWritten), None) return samplesWritten.value ## This function starts the analog output generation. # @param self The object pointer. def start(self): self.status = self.taskRef.StartTask() ## This functions waits for the analog output generation to complete. # @param self The object pointer. def waitUntilDone(self): sampPerChan = uInt64() self.status = self.taskRef.GetSampQuantSampPerChan( ctypes.byref(sampPerChan)) self.estAcqTime = (self.loops * sampPerChan.value) / self._sampleRate #print 'SamplesPerChannel: ' + str(sampPerChan.value) #print 'Estimated Acquisition Time: ' + str(self.estAcqTime) #if (self.estAcqTime >= 0.01 and self.mode != dutil.Mode.Static): if self.mode != dutil.Mode.Static: self.status = self.taskRef.WaitUntilTaskDone( float64(self.estAcqTime + self._timeoutPad)) ## This function stops the analog output generation. # @param self The object pointer. def stop(self): self.status = self.taskRef.StopTask() def __createTask(self, physicalChannel): """ This is a private method that creates the Task object for use inside the AnalogOutput class.""" self.status = self.taskRef.CreateAOVoltageChan(physicalChannel, "", -10, 10, DAQmx_Val_Volts, None) def __configTiming(self, sampleMode): """ This is a private method that configures the timing for the Analog Output class. """ totalSamples = self._samplesPerChannel * self.loops onDemand = bool32() self.status = self.taskRef.GetOnDemandSimultaneousAOEnable( ctypes.byref(onDemand)) #print 'On Demand: ' + str(onDemand.value) #print 'Trigger Type: ' + str(self.triggerType) #print 'Software Trigger Type: ' + str(dutil.TriggerType.Software) if self.triggerType == dutil.TriggerType.Software: #print 'Software Timing' self.status = self.taskRef.CfgSampClkTiming( 'OnboardClock', float64(self._sampleRate), DAQmx_Val_Rising, sampleMode, uInt64(totalSamples)) elif self.triggerType == dutil.TriggerType.Hardware: #print 'Hardware Timing' self.status = self.taskRef.CfgSampClkTiming( self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling, sampleMode, uInt64(totalSamples)) self.status = self.taskRef.CfgDigEdgeStartTrig( self._startTriggerSource, DAQmx_Val_Rising) if self.startTriggerSyncCard != '': DAQmxConnectTerms(self.startTriggerSyncCard, self._startTriggerSource, DAQmx_Val_DoNotInvertPolarity) ## This function will close connection to the analog output device and channels. # @param self The object pointer. def close(self): self.initialized = False if self.startTriggerSyncCard != '': DAQmxDisconnectTerms(self._startTriggerSource, self.startTriggerSyncCard) self.status = self.taskRef.ClearTask() self.taskRef = Task() ## This is the destructor for the AnalogOutput Class. # @param self The object pointer. def __del__(self): if self.initialized: self.close() del self.taskRef del self.initialized del self.status del self.sampleRate del self._numChannels del self.samplesPerChannel del self.clkSource del self.startTriggerSource del self.startTriggerSyncCard del self.mode del self.triggerType del self.loops del self.estAcqTime
y_freq = 200.0 written = ni.int32() waveform, t = gen_waveform(x_freq, y_freq, num_AO_samples, AO_sample_rate, amplitude) AO_task = Task() AO_task.CreateAOVoltageChan("/Dev1/ao0:1", "", -10.0, 10.0, ni.DAQmx_Val_Volts, None) #AO_task.StartTask() # Specify Sample Clock Timing AO_task.CfgSampClkTiming("OnboardClock", AO_sample_rate, ni.DAQmx_Val_Rising, ni.DAQmx_Val_ContSamps, num_AO_samples) #Trigger on the counter. PFI12 is the output of counter 0 AO_task.CfgDigEdgeStartTrig("/Dev1/PFI12", ni.DAQmx_Val_Rising) # ## Analog input # --------------------------------------------------------------------------------------------------------------------------------------------- # In[36]: # Define analog input task AI_task = Task() AI_task.CreateAIVoltageChan("/Dev1/ai1", "", ni.DAQmx_Val_RSE, -10.0, 10.0, ni.DAQmx_Val_Volts, None) # In[37]: # set analog input parameters num_images = 1
class DigitalOutput(object): #-- Sample Rate Property ## This function returns the sample rate configured in the DAQmx Task. # @param self The object reference. def getSampleRate(self): if self.initialized: sampleRate = float64() self.status = self.taskRef.GetSampClkRate(ctypes.byref(sampleRate)) self._sampleRate = sampleRate.value return self._sampleRate ## This function sets the sample rate in the DAQmx Task. # @param self The object reference. # @param value The value to set the sample rate. def setSampleRate(self, value): if self.initialized: self.status = self.taskRef.SetSampClkRate(float64(value)) self._sampleRate = value ## This function deletes the sample rate variable inside the # DigitalOutput object. # @param self The object reference. def _delSampleRate(self): del self._sampleRate sampleRate = property(getSampleRate, setSampleRate, _delSampleRate, doc="""The sample rate of the digital output.""") #-- Samples Per Channel Property ## This function returns the samples per channel configured in the # DAQmx Task. # @param self The object reference. def getSamplesPerChannel(self): if self.initialized: samplesPerChannel = uInt64() self.status = self.taskRef.GetSampQuantSampPerChan( ctypes.byref(samplesPerChannel)) self._samplesPerChannel = samplesPerChannel.value return self._samplesPerChannel ## This function sets the samples per channel in the DAQmx Task. # @param self The object reference. # @param value The value to set the samples per channel. def setSamplesPerChannel(self, value): if self.initialized: self.status = self.taskRef.SetSampQuantSampPerChan(uInt64(value)) self._samplesPerChannel = value ## This function deletes the samplesPerChannel variable from the # DigitalOutput object. # @param self The object reference. def _delSamplesPerChannel(self): del self._samplesPerChannel samplesPerChannel = property( getSamplesPerChannel, setSamplesPerChannel, _delSamplesPerChannel, """The samples per channel of the digital output.""") #-- Clock Source Property ## This function returns the sample clock source configured in the # DAQmx Task. # @param self The object reference. def getClkSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetSampClkSrc(buff, buffSize) self._clkSource = buff.value return self._clkSource ## This function sets the sample clock source in the DAQmx Task. # @param self The object reference. # @param value The value to set the clock source. def setClkSource(self, value): if self.initialized: self.status = self.taskRef.SetSampClkSrc(value) value = self.getClkSource() self._clkSource = value ## This function deletes the clkSource variable within the # DigitalOutput # object. # @param self The object reference. def _delClkSource(self): del self._clkSource clkSource = property( getClkSource, setClkSource, _delClkSource, """The clock source for the digital outputsample clock.""") #-- Start Trigger Property ## This function returns the start trigger source configured in the # DAQmx Task. # @param self The object reference. def _getStartTriggerSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetDigEdgeStartTrigSrc(buff, buffSize) self._startTriggerSource = buff.value return self._startTriggerSource ## This function sets the start trigger source in the DAQmx Task. # @param self The object reference. # @param value The value to set the start trigger. def _setStartTriggerSource(self, value): if self.initialized: self.status = self.taskRef.SetDigEdgeStartTrigSrc(value) value = self.getStartTriggerSource() self._startTriggerSource = value startTriggerSource = property(_getStartTriggerSource, _setStartTriggerSource) #-- Done Property def _getDone(self): done = bool32() if self.initialized: self.status = self.taskRef.GetTaskComplete(ctypes.byref(done)) else: done.value = 1 return bool(done.value) ## @var done # Returns the task done status. # # This mode works differently depending on the mode. <br /> # <ul> # <li><B>Static and Continuous</B>: done is false after a start # method and true</li> # only after a stop method. # <li><B>Finite</B>: done is false until all samples are # generated.</li></ul> done = property(_getDone) #-- Pause Trigger Source def _getPauseTriggerSource(self): if self.initialized: buffSize = uInt32(255) buff = ctypes.create_string_buffer(buffSize.value) self.status = self.taskRef.GetDigLvlPauseTrigSrc(buff, buffSize) self._pauseTriggerSource = buff.value return self._pauseTriggerSource def _setPauseTriggerSource(self, value): if self.initialized: if value == '': self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_None) self.status = self.taskRef.ResetDigLvlPauseTrigSrc() else: self.status = self.taskRef.SetDigLvlPauseTrigWhen( DAQmx_Val_High) self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_DigLvl) self.status = self.taskRef.SetDigLvlPauseTrigSrc(value) self._pauseTriggerSource = value pauseTriggerSource = property(_getPauseTriggerSource, _setPauseTriggerSource) #-------------------- Functions -------------------- ## This function is a constructor for the DigitalOutput class. # # It creates the internal variables required to perform functions # within the class. This function does not initialize any hardware. # @param self This object reference def __init__(self): ## The DAQmx task reference. self.taskRef = Task() ## This is the status of the DAQmx task. # # A value greater than 0 means that an error has occurred. When # the status is greater than 0 an error should be reported by # the class. self.status = int32() ## This is a boolean that is true when the DAQmx task has been # initialized. self.initialized = False ## @var sampleRate # This is the sample rate of the digital output. self._sampleRate = 100e3 ## @var samplesPerChannel # This is the number of samples per channel that will be generated # in Finite mode. self._samplesPerChannel = 100 ## @var clkSource # This is the sample clock source terminal. It can be set to an # internal clock or external clock such as a PFI line i.e. # "/PXI1Slot3/PFI15." self._clkSource = '' ## @var startTriggerSource # This is the start trigger source terminal. It can be set to # a PFI line such as "/PXISlot3/PFI0" self._startTriggerSource = '' ## @var pauseTriggerSource # The source terminal of the pause trigger. This can be # any PFI or backplane trigger such as 'PFI5' and 'PXI_TRIG5' self._pauseTriggerSource = '' ## This is the mode of operation for the digital outputs. # # There are currently three modes available. Static mode is # where one static digital sample is set with no need for a # sample clock. Finite mode is where a finite number of digital # samples will be set at a sample clock rate. Continuous mode is # where a sequence of voltages are generated at a sample rate and # then repeated until the stop() method is called. self.mode = dutil.Mode.Finite self.triggerType = dutil.TriggerType.Software ## The number of time to iterate over a Finite number of samples. # # This value is only useful in the "Finite" mode. It is the # number of times that a sequence of digital samples will be # looped. The default is allways 1. self.loops = 1 ## The time in seconds to wait for a trigger or for a digital # state change. self.timeout = 1 self.timeoutPad = 10 self._pCh = '' ## Initialize the digital outputs based on the object's configuration. # @param self The object reference. # @param physicalChannel A string representing the device and digital # output channels. Example value: "PXI1Slot3/ao0:7" def init(self, physicalChannel): self._pCh = physicalChannel self.__createTask(physicalChannel) self.initialized = True #Finite Mode if self.mode == dutil.Mode.Finite: self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen) self.__configTiming(DAQmx_Val_FiniteSamps) #Continuous Mode if self.mode == dutil.Mode.Continuous: self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen) self.__configTiming(DAQmx_Val_ContSamps) #Static Mode if self.mode == dutil.Mode.Static: pass ## This function returns a random 1D numpy array of samples for # writing the buffer of digital output channels. # @param self The objet reference. def createTestBuffer(self): import numpy data = numpy.random.rand(self._samplesPerChannel) data = numpy.ubyte(data * 255) return data ## This function returns the number of digital lines configured in # the DAQmx Task. # @param self The object reference. def getNumLines(self): numLines = uInt32() #bufferSize = 255 #channel = ctypes.create_string_buffer(bufferSize) #self.taskRef.GetTaskChannels(channel, bufferSize) #print channel.value self.taskRef.GetDONumLines('', ctypes.byref(numLines)) return numLines.value ## This function returns the number of digital channels configured in # the DAQmx Task. # @param self The object reference. def getNumChannels(self): numChannels = uInt32() self.taskRef.GetTaskNumChans(ctypes.byref(numChannels)) return numChannels.value ## This function writes the specified values into the buffer. # @param self The object reference. # @param data This is a 1D 8-bit unsigned integer array that # contians samples for each digital channel. Channels are # non-interleaved (channel1 n-samples then channel2 n-samples). def writeToBuffer(self, data): autostart = self.mode == dutil.Mode.Static samplesWritten = int32() self.buff = data self.status = self.taskRef.WriteDigitalU8(self._samplesPerChannel, autostart, 10, DAQmx_Val_GroupByChannel, data, ctypes.byref(samplesWritten), None) #print 'Samples Written: ' + str(samplesWritten.value) return samplesWritten.value ## This function writes a static value to the digital line(s) # configured in the init() method. # @param self The object reference. # @param data The static value to send to the digital line(s). def writeStatic(self, data): if isinstance(data, bool) and data == True: digLineNum = int(self._pCh[len(self._pCh) - 1]) data = 2**digLineNum autostart = True self.status = self.taskRef.WriteDigitalScalarU32( autostart, float64(self.timeout), uInt32(data), None) ## This function starts the digital output generation. # @param self The object reference. def start(self): self.status = self.taskRef.StartTask() ## This functions waits for the digital output generation to complete. # @param self The object reference. def waitUntilDone(self): sampPerChan = uInt64() self.status = self.taskRef.GetSampQuantSampPerChan( ctypes.byref(sampPerChan)) #print 'DO Samples Per Channel: ' + str(sampPerChan.value) estAcqTime = (self.loops * sampPerChan.value) / self._sampleRate #print "Estimated Acquisition Time: " + str(estAcqTime) if self.mode != dutil.Mode.Static: self.status = self.taskRef.WaitUntilTaskDone( float64(estAcqTime + self.timeoutPad)) ## This function stops the digital output generation. # @param self The object reference. def stop(self): self.status = self.taskRef.StopTask() ## This is a private method that creates the Task object for use # inside the DigitalOutput class. def __createTask(self, physicalChannel): self.status = self.taskRef.CreateDOChan(physicalChannel, '', DAQmx_Val_ChanForAllLines) ## This is a private method that configures the timing for the # DigitalOutput class. # @param self The object reference. def __configTiming(self, sampleMode): totalSamples = self._samplesPerChannel * self.loops if self.triggerType == dutil.TriggerType.Software: self.status = self.taskRef.CfgSampClkTiming( self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling, sampleMode, uInt64(totalSamples)) elif self.triggerType == dutil.TriggerType.Hardware: self.status = self.taskRef.CfgSampClkTiming( self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling, sampleMode, uInt64(totalSamples)) self.status = self.taskRef.CfgDigEdgeStartTrig( self._startTriggerSource, DAQmx_Val_Falling) ## This function will close connection to the digital ouput device and # channels. # @param self The object reference. def close(self): self.initialized = False self.status = self.taskRef.ClearTask() self.taskRef = Task() ## This is the destructor for the DigitalOutput Class. # @param self The object reference. def __del__(self): if self.initialized: self.close() del self.taskRef del self.status del self.initialized del self.sampleRate del self.samplesPerChannel del self.clkSource del self.mode del self.loops del self.timeout del self.timeoutPad del self._pCh