class AnalogInput(object): ## This function is a constructor for the AnalogInput 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() ## A boolean that is set to True when the AnalogInput card is 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 input. self._sampleRate = 100e3 ## @var samplesPerChannel # This is the number of samples per channel that will be # acquired in Finite mode. self._samplesPerChannel = 100 ## @var numChannels # This is the number of channels configured in the task. self._numChannels = 0 ## This is the timeout in seconds for functions in the task to timeout. self.timeout = 1 ## This is the mode of operation for the analog inputs. # # There are currently three modes available. # Static mode is where one static voltage is acquired with no need # for a sample clock. # Finite mode is where a finite number of voltages will be acquired 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.Static ## Initializes the analog inputs based on the object's configuration. # @param self The object pointer. # @param physicalChannel A string representing the device and analog # input channels. Example Value: "PXI1Slot3/ao0:7" def init(self, physicalChannel): self.__createTask(physicalChannel) self.getNumChannels() self.initialized = True #Static Mode if self.mode == dutil.Mode.Static: self.setSampleRate(self._sampleRate) self.setSamplesPerChannel(1) def __createTask(self, physicalChannel): """ This is a private method that creates the Task object for use inside the AnalogInput class.""" terminalConfig = DAQmx_Val_Cfg_Default self.status = self.taskRef.CreateAIVoltageChan(physicalChannel, "", terminalConfig, -10, 10, DAQmx_Val_Volts, None) ## 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 sampleRate = property(getSampleRate, setSampleRate) ## 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 samplesPerChannel = property(getSamplesPerChannel, setSamplesPerChannel) ## 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 reads the data from the analogn input based on previous # configuration. # @param self The object reference. def read(self): timeout = float64(self.timeout) arraySize = uInt32(self._numChannels * self._samplesPerChannel) readArray = numpy.zeros((arraySize.value,), dtype = numpy.float64) samplesRead = int32() self.taskRef.ReadAnalogF64(self._samplesPerChannel, timeout, DAQmx_Val_GroupByChannel, readArray, arraySize, ctypes.byref(samplesRead), None) return readArray ## 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 AnalogInput Class. # @param self The object pointer. def __del__(self): if self.initialized: self.close()
class daq(object): """This class prepares and configures a DAQ system for an analog adquisition. The required arguments are the name of the device as a string (p.e. 'Dev3'), the adquisition time in seconds (adqTime), the sampling frequency in Hz (adqFreq), the channels to read as a list of integer values with the available channels, the voltage range of the channels as a list with the maximum positive voltage value and with the same length as the channel list. Optional arguments: - mode = 'FiniteSamps': sets the adquisiton mode to finite sampling (default) or continuous 'ContSamps' - trigger = None: sets the trigger mode. If None it is taken as the clock edge. Otherwise, a 2-element list can be passed, the first value being the channel number and the second the voltage value to configure the trigger to an analog channel in rising mode. This class only contemplates reading volts signal of analog inputs in differential configuration. Future versions might implement other possibilities.""" def __init__(self, device, adqTime, adqFreq, list_channels, rang_channels, mode='FiniteSamps', trigger=None, terminalConfig='diff'): """This will configure the DAQ and Task for the specified configuration""" self.device = device self.adqTime = adqTime # In seconds self.adqFreq = adqFreq self.list_channels = list_channels self.rang_channels = rang_channels self.mode = mode self.N_samples = int(adqTime * adqFreq) self.N_channels = len(list_channels) if terminalConfig is 'diff': self.terminalConfig = DAQmx_Val_Diff elif terminalConfig is 'SE': self.terminalConfig = DAQmx_Val_RSE else: raise Error( 'Terminal configuration "{}" not known'.format(terminalConfig)) print('I will adquire {} samples for each {} channels'.format( self.N_samples, self.N_channels)) # DAQmx Configure Code # We create a Task instance self.ai = Task() # Prepare the type of variable that it returns using the library ctypes that work with C-functions self.read = int32() # The vector data will contain the output of the DAQ card in a single vector with the data from different channels # in a single 1-D vector with the data concatenated self.data = np.zeros((self.N_samples * self.N_channels, ), dtype=np.float64) #self.ai = Task() # This prepares the string that is needed for the ``CreateAIVoltageChan`` depending on the number of channels to # read for channel, Vrange in zip(self.list_channels, self.rang_channels): str_channels = r"{}/ai{:d}".format(self.device, channel) #print(r"{}/ai{:d}".format(self.device,channel) ) self.ai.CreateAIVoltageChan(str_channels, "", self.terminalConfig, -1.0 * Vrange, Vrange, DAQmx_Val_Volts, None) if mode is 'FiniteSamps': self.ai.CfgSampClkTiming("", self.adqFreq, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, self.N_samples) elif mode is 'ContSamps': self.ai.CfgSampClkTiming("", self.adqFreq, DAQmx_Val_Rising, DAQmx_Val_ContSamps, self.N_samples) else: raise Error('Mode not known') if trigger is None: pass else: self.ai.CfgAnlgEdgeStartTrig( r"{}/ai{:d}".format(self.device, trigger[0]), DAQmx_Val_RisingSlope, trigger[1]) # In the case the DAQ accept a trigger from one of the analog channels we could also setup it as # def start(self): self.ai.StartTask() def stop(self): self.ai.StopTask() self.data = np.zeros((self.N_samples * self.N_channels, ), dtype=np.float64) def read_analog(self, timeout=10.0): """Calls the ReadAnalogF64 with the configured parameters. Optional arguments: - timeout = 10.0: timeout in number of seconds. """ self.ai.ReadAnalogF64(self.N_samples, timeout, DAQmx_Val_GroupByChannel, self.data, self.N_samples * self.N_channels, byref(self.read), None) return self.data.reshape((self.N_samples, self.N_channels), order="F") def clear(self): self.ai.ClearTask()
# In[40]: #Setup the data that will be output on the trigger AO_task.WriteAnalogF64(num_AO_samples, 0, 10.0, ni.DAQmx_Val_GroupByChannel, waveform, ni.byref(written), None) # In[41]: AI_task.StartTask() #This will start on the trigger AO_task.StartTask() #This will start on the trigger triggerTask.StartTask() # Start counter and trigger tasks # In[42]: # now, retrieve data AI_task.ReadAnalogF64(num_AI_samples, 10.0, ni.DAQmx_Val_GroupByChannel, data, num_AI_samples, ni.byref(read), None) # In[43]: # And clean up tasks: AO_task.StopTask() AI_task.StopTask() triggerTask.StopTask() # In[44]: plt.plot(data) plt.show() # In[ ]: