Example #1
0
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()