def initializeData(self):

        # Store the variables that will be used durign this data run
        self.startWave = self.startWaveSpinBox.value()
        self.endWave = self.endWaveSpinBox.value()
        self.scanRate = self.scanRateSpinBox.value()
        self.sampleRate = self.sampleRateSpinBox.value()
        self.inputs = self.inputsTextEdit.toPlainText()
        self.fileName = self.fileNameLineEdit.text()
        self.metadata = self.metadataTextEdit.toPlainText()

        # Configure the graph choices comboBoxes
        self.aiPorts = list()
        self.aiNames = list()
        self.graphChoices1.clear()
        self.graphChoices2.clear()
        self.graphChoices3.clear()

        self.inputs = self.inputsTextEdit.toPlainText()
        textLines = self.inputs.split('\n')
        for line in textLines:
            splitLine = line.split(':')
            if len(splitLine) == 2:  # In case there are trailing new lines
                self.aiPorts.append(
                    str.strip(str(splitLine[0]))
                )  # str.strip() gets rid of any leading an trailing spaces
                self.aiNames.append(str.strip(str(splitLine[1])))
                self.graphChoices1.addItem(str.strip(str(splitLine[1])))
                self.graphChoices2.addItem(str.strip(str(splitLine[1])))
                self.graphChoices3.addItem(str.strip(str(splitLine[1])))

        # Initialize some dictionaries to link variables to the port names
        self.aiNameDict = {}
        portString = ""
        for port, name in zip(self.aiPorts, self.aiNames):
            self.aiNameDict[port] = name
            portString += (dev + port + ", ")

        portString = portString[:
                                -2]  # Since we will have a trailing ", " at the end

        ## Configure the Analog Input lines
        self.fSampPerChan = self.sampleRate / len(self.aiPorts)
        self.tSamp = abs(self.endWave - self.startWave) / self.scanRate
        self.nSampPerChan = int(
            self.tSamp *
            self.fSampPerChan)  # pydaqmx.uInt64 can only accept integer inputs

        self.readAI = pydaqmx.TaskHandle()
        pydaqshortcuts.makeAnalogIn(portString, self.readAI, self.fSampPerChan,
                                    self.nSampPerChan)
        pydaqmx.DAQmxCfgDigEdgeStartTrig(
            self.readAI, startTrig, pydaqmx.DAQmx_Val_Rising
        )  # Trigger to actually start collecting data
Exemple #2
0
def setup_hw_di(fs, lines, callback, callback_samples, start_trigger=None,
                clock=None, task_name='hw_di'):
    '''
    M series DAQ cards do not have onboard timing engines for digital IO.
    Therefore, we have to create one (e.g., using a counter or by using the
    analog input or output sample clock.
    '''
    task = create_task(task_name)
    mx.DAQmxCreateDIChan(task, lines, '', mx.DAQmx_Val_ChanForAllLines)

    # Get the current state of the lines so that we know what happened during
    # the first change detection event. Do this before configuring the timing
    # of the lines (otherwise we have to start the master clock as well)!
    mx.DAQmxStartTask(task)
    initial_state = read_digital_lines(task, 1)
    mx.DAQmxStopTask(task)

    # M-series acquisition boards don't have a dedicated engine for digital
    # acquisition. Use a clock to configure the acquisition.
    if clock is not None:
        clock_task = create_task('{}_clock'.format(task_name))
        mx.DAQmxCreateCOPulseChanFreq(clock_task, clock, '', mx.DAQmx_Val_Hz,
                                      mx.DAQmx_Val_Low, 0, fs, 0.5)
        mx.DAQmxCfgImplicitTiming(clock_task, mx.DAQmx_Val_ContSamps, int(fs))
        clock += 'InternalOutput'
        if start_trigger:
            mx.DAQmxCfgDigEdgeStartTrig(clock_task, start_trigger,
                                        mx.DAQmx_Val_Rising)
        setup_timing(task, clock, -1, None)
    else:
        setup_timing(task, fs, -1, start_trigger)

    cb_helper = DigitalSamplesAcquiredCallbackHelper(callback)
    cb_ptr = mx.DAQmxEveryNSamplesEventCallbackPtr(cb_helper)
    mx.DAQmxRegisterEveryNSamplesEvent(task, mx.DAQmx_Val_Acquired_Into_Buffer,
                                       int(callback_samples), 0, cb_ptr, None)

    task._cb_ptr = cb_ptr
    task._cb_helper = cb_helper
    task._initial_state = initial_state

    rate = ctypes.c_double()
    mx.DAQmxGetSampClkRate(task, rate)

    mx.DAQmxTaskControl(task, mx.DAQmx_Val_Task_Reserve)
    mx.DAQmxTaskControl(clock_task, mx.DAQmx_Val_Task_Reserve)

    return [task, clock_task]
Exemple #3
0
def setup_timing(task, channels, delay=0):
    '''
    Configures timing for task

    Parameters
    ----------
    task : niDAQmx task handle
        Task to configure timing for
    channels : list of channels
        List of channels to configure

    References
    ----------
    http://www.ni.com/white-paper/11369/en/
    http://www.ni.com/pdf/manuals/371235h.pdf
    '''
    fs = get_channel_property(channels, 'fs')
    sample_clock = get_channel_property(channels, 'sample_clock')
    start_trigger = get_channel_property(channels, 'start_trigger')
    samples = get_channel_property(channels, 'samples')
    reference_clock = get_channel_property(channels, 'reference_clock')

    if reference_clock:
        mx.DAQmxSetRefClkSrc(task, reference_clock)

    if start_trigger:
        mx.DAQmxCfgDigEdgeStartTrig(task, start_trigger, mx.DAQmx_Val_Rising)

    if samples == 0:
        sample_mode = mx.DAQmx_Val_ContSamps
        samples = 2
    else:
        sample_mode = mx.DAQmx_Val_FiniteSamps
        samples += delay

    mx.DAQmxCfgSampClkTiming(task, sample_clock, fs, mx.DAQmx_Val_Rising,
                             sample_mode, samples)

    properties = get_timing_config(task)
    actual_fs = properties['sample clock rate']
    if round(actual_fs, 4) != round(fs, 4):
        names = ', '.join(get_channel_property(channels, 'name', True))
        m = f'Actual sample clock rate of {actual_fs} does not match ' \
            f'requested sample clock rate of {fs} for {names}'
        raise ValueError(m)

    return properties
Exemple #4
0
    def __init__(self, osas, simulation=False):
        """
        :param osas: dictionary containing OSA configuration info
        :param simulation: if True we operate in simulation mode
        """
        self.simulation = simulation
        self.osas = dict(osas)
        self.handles = {}

        if self.simulation:
            self.f0 = {}
            for osa_name, osa in self.osas.items():
                self.f0[osa_name] = np.random.uniform(0,
                                                      1) * osa["num_samples"]
            return

        try:
            # Reset all DAQ cards
            devices = set([osa["device"] for _, osa in self.osas.items()])
            for device in devices:
                PyDAQmx.DAQmxResetDevice(device)

            for name, osa in self.osas.items():
                self.handles[name] = task_handle = PyDAQmx.TaskHandle(0)
                PyDAQmx.DAQmxCreateTask("osa_" + name, byref(task_handle))

                PyDAQmx.DAQmxCreateAIVoltageChan(
                    task_handle, "/{}/{}".format(osa["device"],
                                                 osa["input_channel"]),
                    "Voltage", PyDAQmx.DAQmx_Val_NRSE, -osa["v_span"] / 2,
                    osa["v_span"] / 2, PyDAQmx.DAQmx_Val_Volts, None)

                PyDAQmx.DAQmxCfgSampClkTiming(task_handle, None,
                                              osa["sample_rate"],
                                              PyDAQmx.DAQmx_Val_Rising,
                                              PyDAQmx.DAQmx_Val_FiniteSamps,
                                              osa["num_samples"])

                PyDAQmx.DAQmxCfgDigEdgeStartTrig(
                    task_handle, "/{}/{}".format(osa["device"],
                                                 osa["trigger_channel"]),
                    PyDAQmx.DAQmx_Val_Falling)

        except DAQError as err:
            self.clear()
            raise OSAException(err)
Exemple #5
0
def setup_hw_ai(fs, lines, expected_range, callback, callback_samples, sync_ao):
    # Record AI filter delay
    task = create_task()
    lb, ub = expected_range
    mx.DAQmxCreateAIVoltageChan(task, lines, '', mx.DAQmx_Val_RSE, lb, ub,
                                mx.DAQmx_Val_Volts, '')
    if sync_ao:
        mx.DAQmxCfgDigEdgeStartTrig(task, 'ao/StartTrigger',
                                    mx.DAQmx_Val_Rising)
        mx.DAQmxCfgSampClkTiming(task, 'ao/SampleClock', fs,
                                 mx.DAQmx_Val_Rising, mx.DAQmx_Val_ContSamps,
                                 int(fs))
    else:
        mx.DAQmxCfgSampClkTiming(task, '', fs, mx.DAQmx_Val_Rising,
                                 mx.DAQmx_Val_ContSamps, int(fs))

    result = ctypes.c_uint32()
    mx.DAQmxGetBufInputBufSize(task, result)
    buffer_size = result.value
    mx.DAQmxGetTaskNumChans(task, result)
    n_channels = result.value

    log.debug('Buffer size for %s automatically allocated as %d samples',
              lines, buffer_size)
    log.debug('%d channels in task', n_channels)

    new_buffer_size = np.ceil(buffer_size/callback_samples)*callback_samples
    mx.DAQmxSetBufInputBufSize(task, int(new_buffer_size))

    callback_helper = SamplesAcquiredCallbackHelper(callback, n_channels)
    cb_ptr = mx.DAQmxEveryNSamplesEventCallbackPtr(callback_helper)
    mx.DAQmxRegisterEveryNSamplesEvent(task, mx.DAQmx_Val_Acquired_Into_Buffer,
                                       int(callback_samples), 0, cb_ptr, None)

    task._cb_ptr = cb_ptr
    return task
    def set_up_clock(self,
                     clock_frequency=None,
                     clock_channel=None,
                     scanner=False,
                     idle=False,
                     delay=2.0):
        """ Configures the hardware clock of the NiDAQ card to give the timing.

        @param float clock_frequency: if defined, this sets the frequency of
                                      the clock in Hz
        @param string clock_channel: if defined, this is the physical channel
                                     of the clock within the NI card.
        @param bool scanner: if set to True method will set up a clock function
                             for the scanner, otherwise a clock function for a
                             counter will be set.
        @param bool idle: set whether idle situation of the counter (where
                          counter is doing nothing) is defined as
                                True  = 'Voltage High/Rising Edge'
                                False = 'Voltage Low/Falling Edge'

        @return int: error code (0:OK, -1:error)
        """

        if not scanner and self._clock_daq_task is not None:
            self.log.error(
                'Another counter clock is already running, close this one first.'
            )
            return -1

        if scanner and self._scanner_clock_daq_task is not None:
            self.log.error(
                'Another scanner clock is already running, close this one first.'
            )
            return -1

        # Create handle for task, this task will generate pulse signal for
        # photon counting
        my_clock_daq_task = daq.TaskHandle()
        smiq = daq.TaskHandle()
        switch = daq.TaskHandle()
        cam = daq.TaskHandle()

        # assign the clock frequency, if given
        if clock_frequency is not None:
            if not scanner:
                self._clock_frequency = float(clock_frequency)
            else:
                self._scanner_clock_frequency = float(clock_frequency)
                self._smiq_clock_frequency = float(clock_frequency) / 2.
                self._switch_clock_frequency = float(clock_frequency) / 2.
                self._cam_clock_frequency = float(clock_frequency)
        else:
            if not scanner:
                self._clock_frequency = self._default_clock_frequency
            else:
                self._scanner_clock_frequency = self._default_scanner_clock_frequency

        # use the correct clock in this method
        if scanner:
            my_clock_frequency = self._scanner_clock_frequency * 2
        else:
            my_clock_frequency = self._clock_frequency * 2

        # assign the clock channel, if given
        if clock_channel is not None:
            if not scanner:
                self._clock_channel = clock_channel
            else:
                self._scanner_clock_channel = clock_channel

        # use the correct clock channel in this method
        if scanner:
            my_clock_channel = self._scanner_clock_channel
            self._smiq_channel = self._smiq_channel
            self._switch_channel = self._switch_channel
            self._cam_channel = self._cam_channel
        else:
            my_clock_channel = self._clock_channel

        # check whether only one clock pair is available, since some NI cards
        # only one clock channel pair.
        if self._scanner_clock_channel == self._clock_channel:
            if not ((self._clock_daq_task is None) and
                    (self._scanner_clock_daq_task is None)):
                self.log.error(
                    'Only one clock channel is available!\n'
                    'Another clock is already running, close this one first '
                    'in order to use it for your purpose!')
                return -1
        if self.pseudo_pulsed:
            self.clock_duty = self.duty_value / (
                1 / self._scanner_clock_frequency) / 2
            self.switch_duty = self.duty_value / (
                1 / self._switch_clock_frequency) / 2
            self.switch_delay = 0
        else:
            self.clock_duty = 0.9998
            self.switch_duty = 0.5
            self.switch_delay = 0
        # Adjust the idle state if necessary
        my_idle = daq.DAQmx_Val_High if idle else daq.DAQmx_Val_Low
        try:
            # create task for clock
            task_name = 'ScannerClock' if scanner else 'CounterClock'
            daq.DAQmxCreateTask(task_name, daq.byref(my_clock_daq_task))

            # create a digital clock channel with specific clock frequency:
            daq.DAQmxCreateCOPulseChanFreq(
                # The task to which to add the channels
                my_clock_daq_task,
                # which channel is used?
                my_clock_channel,
                # Name to assign to task (NIDAQ uses by # default the physical channel name as
                # the virtual channel name. If name is specified, then you must use the name
                # when you refer to that channel in other NIDAQ functions)
                'Clock Producer',
                # units, Hertz in our case
                daq.DAQmx_Val_Hz,
                # idle state
                my_idle,
                # initial delay
                delay,
                my_clock_frequency / 2,
                self.clock_duty)

            daq.DAQmxCfgImplicitTiming(
                # Define task
                my_clock_daq_task,
                daq.DAQmx_Val_ContSamps,
                # buffer length which stores temporarily the number of
                # generated samples
                1000)
            ##############################
            # Configure SMIQ trigger clock
            ##############################
            duty_cycle = 0.1
            d = 0
            daq.DAQmxCreateTask('mySmiqTask', daq.byref(smiq))
            # Create channel to generate digital pulses that freq and dutyCycle
            # define and adds the channel to the task
            daq.DAQmxCreateCOPulseChanFreq(
                smiq,
                self.
                _smiq_channel,  # The name of the counter to use to create virtual channels
                "mySmiqChannel",  # The name to assign to the created virtual channel
                daq.DAQmx_Val_Hz,  # The units in which to specify freq.
                daq.DAQmx_Val_Low,  # The resting state of the output terminal.
                d,
                # The amount of time in seconds to wait before generating the
                # first pulse.
                self._smiq_clock_frequency,
                # The frequency at which to generate pulses.
                duty_cycle,
                # The width of the pulse divided by the pulse period.
            )

            j = 1000
            # # Sets only the number of samples to acquire or generate without specifying timing.
            daq.DAQmxCfgImplicitTiming(
                smiq,
                # daq.DAQmx_Val_ContSamps,
                daq.DAQmx_Val_ContSamps,
                # Acquire or generate samples until you stop the task.
                j  # the buffer size
            )
            daq.DAQmxCfgDigEdgeStartTrig(smiq,
                                         my_clock_channel + 'InternalOutput',
                                         daq.DAQmx_Val_Rising)
            ##############################
            # Configure switch trigger clock
            ##############################
            duty_cycle = 0.5
            d = 0
            daq.DAQmxCreateTask('mySwitchTask', daq.byref(switch))
            # Create channel to generate digital pulses that freq and dutyCycle
            # define and adds the channel to the task
            daq.DAQmxCreateCOPulseChanFreq(
                switch,
                self.
                _switch_channel,  # The name of the counter to use to create virtual channels
                "mySwitchChannel",  # The name to assign to the created virtual channel
                daq.DAQmx_Val_Hz,  # The units in which to specify freq.
                daq.DAQmx_Val_High,
                # The resting state of the output terminal.
                self.switch_delay,
                # The amount of time in seconds to wait before generating the
                # first pulse.
                self._switch_clock_frequency,
                # The frequency at which to generate pulses.
                self.switch_duty,
                # The width of the pulse divided by the pulse period.
            )

            j = 1000
            # # Sets only the number of samples to acquire or generate without specifying timing.
            daq.DAQmxCfgImplicitTiming(
                switch,
                # daq.DAQmx_Val_ContSamps,
                daq.DAQmx_Val_ContSamps,
                # Acquire or generate samples until you stop the task.
                j  # the buffer size
            )
            daq.DAQmxCfgDigEdgeStartTrig(switch,
                                         my_clock_channel + 'InternalOutput',
                                         daq.DAQmx_Val_Rising)
            ##############################
            # Configure cam trigger clock
            ##############################
            duty_cycle = 0.1
            d = (1. / self._cam_clock_frequency) / 4.
            d = 0
            daq.DAQmxCreateTask('myCamTask', daq.byref(cam))
            # Create channel to generate digital pulses that freq and dutyCycle
            # define and adds the channel to the task
            daq.DAQmxCreateCOPulseChanFreq(
                cam,
                self.
                _cam_channel,  # The name of the counter to use to create virtual channels
                "myCamChannel",  # The name to assign to the created virtual channel
                daq.DAQmx_Val_Hz,  # The units in which to specify freq.
                daq.DAQmx_Val_Low,  # The resting state of the output terminal.
                d,
                # The amount of time in seconds to wait before generating the
                # first pulse.
                self._cam_clock_frequency,
                # The frequency at which to generate pulses.
                duty_cycle,
                # The width of the pulse divided by the pulse period.
            )

            j = 1000
            # # Sets only the number of samples to acquire or generate without specifying timing.
            daq.DAQmxCfgImplicitTiming(
                cam,
                # daq.DAQmx_Val_ContSamps,
                daq.DAQmx_Val_ContSamps,
                # Acquire or generate samples until you stop the task.
                j  # the buffer size
            )
            daq.DAQmxCfgDigEdgeStartTrig(cam,
                                         my_clock_channel + 'InternalOutput',
                                         daq.DAQmx_Val_Rising)

            if scanner:
                self._scanner_clock_daq_task = my_clock_daq_task
                # Added the daq tasks to class variables
                self._smiq_clock_daq_task = smiq
                self._switch_clock_daq_task = switch
                self._cam_clock_daq_task = cam
            else:
                # actually start the preconfigured clock task
                daq.DAQmxStartTask(my_clock_daq_task)
                self._clock_daq_task = my_clock_daq_task
        except BaseException:
            self.log.exception('Error while setting up clock.')
            return -1
        return 0
Exemple #7
0
    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
Exemple #8
0
    def start(self, test=False, **kwargs):
        """
        1. Creates a task using settings.
        2. Starts the task.
        3. Fetches data.

        You need to call read_and_clean() after start().

        kwargs are sent to self() to set parameters.
        """

        # update any last-minute settings
        self(**kwargs)
        debug(self.settings)

        # 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("input task handle")
        _mx.DAQmxClearTask(self._handle)
        _mx.DAQmxCreateTask(self["ai_task_name"], _mx.byref(self._handle))

        # Loop over all the input channel names and create a channel for each
        debug("input channels")
        for n in range(len(self["ai_channels"])):

            # get the channel-specific attributes
            name = self["ai_channels"][n]
            nickname = name.replace("/", "")
            debug(name)

            if isinstance(self["ai_terminal_config"], Iterable):
                ai_terminal_config = self["ai_terminal_config"][n]
            else:
                ai_terminal_config = self["ai_terminal_config"]

            if isinstance(self["ai_min"], Iterable):
                ai_min = self["ai_min"][n]
            else:
                ai_min = self["ai_min"]

            if isinstance(self["ai_max"], Iterable):
                ai_max = self["ai_max"][n]
            else:
                ai_max = self["ai_max"]

            if isinstance(self["ai_units"], Iterable):
                ai_units = self["ai_units"][n]
            else:
                ai_units = self["ai_units"]

            # add an input channel
            debug(name)
            _mx.DAQmxCreateAIVoltageChan(self._handle, name, nickname,
                                         ai_terminal_config, ai_min, ai_max,
                                         ai_units, "")

            # set the input coupling (optional)
            if not self["ai_input_couplings"] == None:
                ai_input_coupling = self["ai_input_couplings"][n]
                if ai_input_coupling == "AC":
                    _mx.DAQmxSetAICoupling(self._handle, name,
                                           _mx.DAQmx_Val_AC)
                if ai_input_coupling == "DC":
                    _mx.DAQmxSetAICoupling(self._handle, name,
                                           _mx.DAQmx_Val_DC)
                if ai_input_coupling == "GND":
                    _mx.DAQmxSetAICoupling(self._handle, name,
                                           _mx.DAQmx_Val_GND)

        # Configure the clock
        debug("input clock")

        # make sure we don't exceed the max
        ai_max_rate = _mx.float64()
        _mx.DAQmxGetSampClkMaxRate(self._handle, _mx.byref(ai_max_rate))
        if self['ai_rate'] > ai_max_rate.value:
            print("ERROR: ai_rate is too high! Current max = " +
                  str(ai_max_rate.value))
            self.clean()
            return False

        _mx.DAQmxCfgSampClkTiming(self._handle, self["ai_clock_source"],
                                  self["ai_rate"], self["ai_clock_edge"],
                                  self["ai_mode"], self["ai_samples"])

        # get the actual ai_rate
        ai_rate = _mx.float64()
        _mx.DAQmxGetSampClkRate(self._handle, _mx.byref(ai_rate))
        debug("input actual ai_rate =", ai_rate.value)
        self(ai_rate=ai_rate.value)

        # Configure the trigger
        debug("input trigger")
        _mx.DAQmxCfgDigEdgeStartTrig(self._handle,
                                     self.settings["ai_trigger_source"],
                                     self.settings["ai_trigger_slope"])

        # Set the post-trigger delay
        try:
            n = self["ai_delay"] * 10e6
            if n < 2: n = 2
            _mx.DAQmxSetStartTrigDelayUnits(self._handle, _mx.DAQmx_Val_Ticks)
            _mx.DAQmxSetStartTrigDelay(self._handle, n)
        except:
            _traceback.print_exc()

        # in test mode, just check that it doesn't fail and clean up.
        if test:
            self.clean()

            # otherwise, start the show!
        else:
            debug("input start")
            try:
                _mx.DAQmxStartTask(self._handle)
            except:
                _traceback.print_exc()

        return True
Exemple #9
0
 def setTriggerFalling(self, c, name, chan):
     pydaqmx.DAQmxCfgDigEdgeStartTrig(self.handleDict[name], chan, pydaqmx.DAQmx_Val_Falling)
    def takeData(self):
        self.takingData = True
        time.sleep(0.5)
        print "Starting scan"
        self.readAI = pydaqmx.TaskHandle()
        pydaqshortcuts.makeAnalogIn(self.portString, self.readAI,
                                    self.sampFreqPerChan, self.nSampsPerChan)
        pydaqmx.DAQmxCfgDigEdgeStartTrig(
            self.readAI, startTrig, pydaqmx.DAQmx_Val_Rising
        )  # Trigger to actually start collecting data
        pydaqmx.DAQmxStartTask(self.readAI)
        self.tn.write("(exec 'laser1:ctl:scan:start) \r\n")

        # Initialize some variables
        ptsPerChan = 0
        stepBuffer = np.zeros(
            (int(self.stepBufferSize), ), dtype=np.int16
        )  # Needs to be int16 to work with PyDAQmx, the DAQ units are all integers anyway
        fullBuffer = np.zeros(
            (int(self.nSampsPerChan), int(self.nChan) + 1), dtype=np.float32
        )  # One extra column for the nominal wavelength. Use float32 so we can cast an int16 into it as well as put floats in
        fullBuffer[:, -1] = np.linspace(
            self.startWave, self.endWave, self.nSampsPerChan
        )  # Place nominal wavelengths in the last column just so we don't have "+1" floating around the loops
        while (self.nChan * ptsPerChan
               ) < self.nSamps:  # While we haven't collected all the data
            # Make a thread to grab data from the readAI task in parallel to the rest of the code
            t = threading.Thread(target=pydaqshortcuts.putDataInQueue,
                                 args=(self.readAI, stepBuffer, self.nChan,
                                       self.q))
            t.start()

            # Retrieve the data from the queue and sort it
            stepData = self.q.get()
            numTakenPerChan = self.q.get(
            ).value  # The ctypes object stores the value in a python-friendly format using the .value attribute
            for j in range(self.nChan):
                fullBuffer[ptsPerChan:ptsPerChan + numTakenPerChan,
                           j] = stepData[j * numTakenPerChan:(j + 1) *
                                         numTakenPerChan]
            ptsPerChan += numTakenPerChan  # Make sure this is updated AFTER we used it in fullBuffer

            for axis, canvas in zip(self.axes, self.canvases):
                axis.cla(
                )  # Clear the axes so that we aren't re-drawing the old data underneath the new data (which slows down plotting ~1.5x)
                axis.plot(fullBuffer[0:ptsPerChan, -1],
                          fullBuffer[0:ptsPerChan,
                                     self.axisToColDict[axis]], 'k')
                canvas.draw()

            app.processEvents(
            )  # If we don't have this line the graphs don't update until the end of data collection

            # for axis, canvas in zip(self.axes, self.canvases):
            #     p = threading.Thread(target=self.plotData, args=(axis, canvas, fullBuffer[0:ptsPerChan, -1], fullBuffer[0:ptsPerChan, self.axisToColDict[axis]]))
            #     p.start()
            # app.processEvents()  # If we don't have this line the graphs don't update until the end of data collection

        pydaqmx.DAQmxStopTask(self.readAI)
        self.takingData = False
        return fullBuffer