コード例 #1
0
    def write_ao_raw_sequence(self, c, raw_sequence_channels_list_json):
        """
        NOT all AO channels are written for now, we select channels by the length of sequence, in principle it should be >2.
        
        This function works for analog stream out where sequence input are in 2D, number_of_ports rows, float element array, like [[x, x,..., x], ...],
        where -10.0 <= x <= 10.0.
        Each row corresponds to a channel in the task. Each column corresponds to a sample to write to each channel.
        """
        raw_sequence_channels_list = json.loads(
            raw_sequence_channels_list_json)
        sequence_bytes = make_sequence_bytes_ao(raw_sequence_channels_list)

        num_port = len(sequence_bytes)
        num_samp = len(sequence_bytes[0])

        if self.seq_task_ao:  # Make sure task is close before you add new stuffs.
            self.seq_task_ao.close()

        self.seq_task_ao = nidaqmx.Task()
        self.seq_task_ao.ao_channels.add_ao_voltage_chan(
            'Dev2/ao0:{}'.format(num_port - 1))
        self.seq_task_ao.timing.cfg_samp_clk_timing(
            rate=self.rate_ao,
            source=self.clk_channel_ao,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.writer_ao = AnalogMultiChannelWriter(
            self.seq_task_ao.out_stream, auto_start=False
        )  # use multi-channel writer, so input is 2D array.
        self.writer_ao.write_many_sample(sequence_bytes, timeout=-1)
コード例 #2
0
    def run(self):
        """
        Starts writing a waveform continuously while reading 
        the buffer periodically
        """

        #DAQ
        with nidaqmx.Task() as slave_Task3, nidaqmx.Task() as master_Task:
            #slave_Task3 = nidaqmx.Task()
            slave_Task3.ao_channels.add_ao_voltage_chan("/Dev1/ao0:1")
            master_Task.ai_channels.add_ai_voltage_chan("/Dev1/ai0")

            slave_Task3.timing.cfg_samp_clk_timing(
                rate=self.sampleRate,
                source='ai/SampleClock',
                sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS)

            # Analoginput
            master_Task.timing.cfg_samp_clk_timing(
                rate=self.sampleRate,
                sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS,
                samps_per_chan=self.readNumber)

            reader = AnalogSingleChannelReader(master_Task.in_stream)
            writer = AnalogMultiChannelWriter(slave_Task3.out_stream)

            reader.auto_start = False
            writer.auto_start = False

            writer.write_many_sample(self.wave)
            """Reading data from the buffer in a loop. 
            The idea is to let the task read more than could be loaded in the buffer for each iteration.
            This way the task will have to wait slightly longer for incoming samples. And leaves the buffer
            entirely clean. This way we always know the correct numpy size and are always left with an empty
            buffer (and the buffer will not slowly fill up)."""
            output = np.zeros(self.readNumber)
            slave_Task3.start(
            )  #Will wait for the readtask to start so it can use its clock
            master_Task.start()
            while not self.isInterruptionRequested():
                reader.read_many_sample(
                    data=output, number_of_samples_per_channel=self.readNumber)

                #Emiting the data just received as a signal

                Dataholder_average = np.mean(output.reshape(
                    self.averagenumber, -1),
                                             axis=0)

                self.data_PMT = np.reshape(
                    Dataholder_average,
                    (self.ypixelnumber, self.ScanArrayXnum))

                if self.ypixelnumber == 500:
                    self.data_PMT = self.data_PMT[:, 50:550] * -1
                elif self.ypixelnumber == 256:
                    self.data_PMT = self.data_PMT[:, 70:326] * -1

                self.measurement.emit(self.data_PMT)
コード例 #3
0
    def __init__(self, *args, read_task, write_task_z, write_task_xy):
        super().__init__(*args)
        self.read_task = read_task
        self.write_task_xy = write_task_xy
        self.write_task_z = write_task_z

        self.z_writer = AnalogMultiChannelWriter(write_task_z.out_stream)
        self.xy_writer = AnalogMultiChannelWriter(write_task_xy.out_stream)
        self.z_reader = AnalogSingleChannelReader(read_task.in_stream)

        self.xy_array = np.zeros((2, self.n_samples))
        self.z_array = np.zeros((4, self.n_samples))

        self.read_array = np.zeros(self.n_samples)

        self.setup_tasks()
コード例 #4
0
ファイル: Control.py プロジェクト: sstucker/PyImageOCT
    def _init_hardware_interface(self):
        # Initialize DAQmx interface

        self._scan_task = nidaqmx.Task()
        self._scan_timing = nidaqmx.task.Timing(self._scan_task)
        dac_name = self.niconfig.dac_device
        dac_ao_channel_ids = [
            dac_name + '/' + self.niconfig.line_trig_ch,
            dac_name + '/' + self.niconfig.frame_trig_ch,
            dac_name + '/' + self.niconfig.x_ch,
            dac_name + '/' + self.niconfig.y_ch
        ]
        for ch_name in dac_ao_channel_ids:
            self._scan_task.ao_channels.add_ao_voltage_chan(ch_name)

        self._scan_task.timing.cfg_samp_clk_timing(
            self.niconfig.dac_rate,  # TODO move?
            source="",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS)
        self._scan_task.regen_mode = nidaqmx.constants.RegenerationMode.DONT_ALLOW_REGENERATION  # TODO test
        self._scan_writer = AnalogMultiChannelWriter(
            self._scan_task.out_stream)

        print("NIOCTController: initialized DAQmx interface...")
        # Initialize IMAQ interface
        PyIMAQ.imgOpen(self.niconfig.cam_device)
        PyIMAQ.imgConfigTrigBufferWithTTL1(timeout=1000)
        PyIMAQ.imgSetAttributeROI(0, 0, self.oct.alines_per_buffer,
                                  self.oct.aline_size)
        PyIMAQ.imgInitBuffer(self.niconfig.number_of_imaq_buffers)
        print("NIOCTController: initialized IMAQ interface...")
コード例 #5
0
    def scan_loop(self, read_task, write_task):
        writer = AnalogMultiChannelWriter(write_task.out_stream)
        reader = AnalogMultiChannelReader(read_task.in_stream)

        first_write = True
        i_acquired = 0
        while not self.stop_event.is_set() and (
                not self.scanning_parameters.scanning_state
                == ScanningState.EXPERIMENT_RUNNING
                or i_acquired < self.scanning_parameters.n_frames):
            # The first write has to be defined before the task starts
            try:
                writer.write_many_sample(self.write_signals)
                if i_acquired == 0:
                    self.check_start_plane()
                if first_write:
                    read_task.start()
                    write_task.start()
                    first_write = False
                reader.read_many_sample(
                    self.read_buffer,
                    number_of_samples_per_channel=self.n_samples_in,
                    timeout=1,
                )
                i_acquired += 1
            except nidaqmx.DaqError as e:
                print(e)
                break
            self.data_queue.put(self.read_buffer[0, :])
            # if new parameters have been received and changed, update
            # them, breaking out of the loop if the experiment is not running
            try:
                self.new_parameters = self.parameter_queue.get(timeout=0.0001)
                if self.new_parameters != self.scanning_parameters and (
                        self.scanning_parameters.scanning_state !=
                        ScanningState.EXPERIMENT_RUNNING
                        or self.new_parameters.scanning_state
                        == ScanningState.PREVIEW):
                    break
            except Empty:
                pass

            # calculate duration
            self.calculate_duration()
コード例 #6
0
    def makeSinglePic(self, writeTask, readTask):
        #Check if the measurement is possible and execute
        if self.checkMeasurement():
            self.writeTask.timing.cfg_samp_clk_timing(
                rate=self.sampleRate,
                sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
                samps_per_chan=self.outputData.size)
            self.readTask.timing.cfg_samp_clk_timing(
                rate=self.sampleRate,
                sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
                samps_per_chan=self.inputData.size)

            reader = AnalogSingleChannelReader(self.readTask.in_stream)
            writer = AnalogMultiChannelWriter(self.writeTask.out_stream)

            estT = self.outputData.size / self.sampleRate
            writer.write_many_sample(self.outputData)

            self.writeTask.start()
            reader.read_many_sample(self.inputData, timeout=estT + 5)

            return self.inputData
コード例 #7
0
    def test_one_sample(self, x_series_device, seed):
        # Reset the pseudorandom number generator with seed.
        random.seed(seed)

        # Select a random loopback channel pair on the device.
        loopback_channel_pairs = self._get_analog_loopback_channels(
            x_series_device)

        number_of_channels = random.randint(2, len(loopback_channel_pairs))
        channels_to_test = random.sample(
            loopback_channel_pairs, number_of_channels)

        with nidaqmx.Task() as write_task, nidaqmx.Task() as read_task:
            write_task.ao_channels.add_ao_voltage_chan(
                flatten_channel_string(
                    [c.output_channel for c in channels_to_test]),
                max_val=10, min_val=-10)

            read_task.ai_channels.add_ai_voltage_chan(
                flatten_channel_string(
                    [c.input_channel for c in channels_to_test]),
                max_val=10, min_val=-10)

            writer = AnalogMultiChannelWriter(write_task.out_stream)
            reader = AnalogMultiChannelReader(read_task.in_stream)

            values_to_test = numpy.array(
                [random.uniform(-10, 10) for _ in range(number_of_channels)],
                dtype=numpy.float64)
            writer.write_one_sample(values_to_test)
            time.sleep(0.001)

            values_read = numpy.zeros(number_of_channels, dtype=numpy.float64)
            reader.read_one_sample(values_read)

            numpy.testing.assert_allclose(
                values_read, values_to_test, rtol=0.05, atol=0.005)
コード例 #8
0
def sawtooth(ai_chan, ao_chan_x, ao_chan_y, sRate, imAngle, outputX, outputY,
             xPixels, yPixels, exPixels):
    """
    Notes:
        Variables:
            ai_chan = string specifying the analog input channel
            ao_chan_x, ao_chan_y = string, specifying the analog output channel for x and y
    
    """
    print("Measurement started")
    writingRate = sRate
    readingRate = writingRate

    #radAngle = math.pi/180*imAngle
    #exPixelsX = int(math.cos(radAngle)*exPixels) #Amount of excess pixels in X
    #exPixelsY = int(math.sin(radAngle)*exPixels) #Amount of excess pixels in Y

    totalxPixels = exPixels + xPixels
    totalyPixels = yPixels

    print("total x pixels", totalxPixels, "xpixels", xPixels, "exPixels",
          exPixels)
    inputData = np.zeros(
        outputX.size +
        1)  #Need the extra one because of the sample shift due to the trigger
    outputData = np.array([outputX, outputY])
    outputChannels = ao_chan_x + ", " + ao_chan_y
    with nidaqmx.Task() as writeTask, nidaqmx.Task() as readTask:
        writeTask.ao_channels.add_ao_voltage_chan(outputChannels)
        readTask.ai_channels.add_ai_voltage_chan(ai_chan)

        #In the USB6001 DAQ there seems to be no SampleClock, therefore we cannot sync the signals without an external trigger/clock
        #sample_clock = '/Dev2/ai/SampleClock'

        writeTask.timing.cfg_samp_clk_timing(
            rate=writingRate,
            sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
            samps_per_chan=outputX.size)
        readTask.timing.cfg_samp_clk_timing(
            rate=readingRate,
            sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
            samps_per_chan=inputData.size)
        writeTask.triggers.start_trigger.cfg_dig_edge_start_trig(
            trigger_source='/Dev2/ai/StartTrigger'
        )  #Setting the trigger on the analog input

        reader = AnalogSingleChannelReader(readTask.in_stream)
        writer = AnalogMultiChannelWriter(writeTask.out_stream)

        estT = outputX.size / writingRate
        writer.write_many_sample(outputData)

        writeTask.start()
        reader.read_many_sample(inputData, timeout=estT + 5)

        writeTask.wait_until_done(timeout=estT + 5)
        readTask.wait_until_done(timeout=estT + 5)
        print("Done with data")

    #----------------------------Creating the Image----------------------------
    print("Creating the image")
    #Creating the array for the image
    imArray = inputData[1::].reshape(
        (totalyPixels,
         totalxPixels))  #Not taking into account the first sample

    #Plotting the image
    plt.imshow(imArray, cmap=plt.cm.gray)
    plt.show()
コード例 #9
0
def triangle(ai_chan, ao_chan_x, ao_chan_y, sRate, imAngle, outputX, outputY,
             xPixels, yPixels, exPixels):
    print("Measurement started")
    writingRate = sRate
    readingRate = writingRate

    radAngle = math.pi / 180 * imAngle
    exPixelsX = int(math.cos(radAngle) *
                    exPixels)  #Amount of excess pixels in X
    exPixelsY = int(math.sin(radAngle) *
                    exPixels)  #Amount of excess pixels in Y

    totalxPixels = 2 * exPixelsX + xPixels  #2 times excess pixels because we overshoot on two sides
    totalyPixels = 2 * exPixelsY + yPixels

    inputData = np.zeros(
        outputX.size +
        1)  #Need the extra one because of the sample shift due to the trigger
    outputData = np.array([outputX, outputY])
    outputChannels = ao_chan_x + ", " + ao_chan_y
    with nidaqmx.Task() as writeTask, nidaqmx.Task() as readTask:
        writeTask.ao_channels.add_ao_voltage_chan(outputChannels)
        readTask.ai_channels.add_ai_voltage_chan(ai_chan)

        #In the USB6001 DAQ there seems to be no SampleClock, therefore we cannot sync the signals without an external trigger/clock
        #sample_clock = '/Dev2/ai/SampleClock'

        writeTask.timing.cfg_samp_clk_timing(
            rate=writingRate,
            sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
            samps_per_chan=outputX.size)
        readTask.timing.cfg_samp_clk_timing(
            rate=readingRate,
            sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
            samps_per_chan=inputData.size)
        writeTask.triggers.start_trigger.cfg_dig_edge_start_trig(
            trigger_source='/Dev2/ai/StartTrigger'
        )  #Setting the trigger on the analog input

        reader = AnalogSingleChannelReader(readTask.in_stream)
        writer = AnalogMultiChannelWriter(writeTask.out_stream)

        estT = outputX.size / writingRate
        writer.write_many_sample(outputData)
        writeTask.start()
        reader.read_many_sample(inputData, timeout=estT + 5)

        writeTask.wait_until_done(timeout=estT + 5)
        readTask.wait_until_done(timeout=estT + 5)

    #----------------------------Creating the Image----------------------------
    #Creating the array for the image
    imArray = np.zeros(
        (totalyPixels,
         totalxPixels))  #Not taking into account the first sample

    #Resolving the sample shift
    inputData = inputData[1::]

    #Now we have to loop over the positions because the reshape function does not work
    forward = True
    xPix = exPixelsX  #Defines the x position
    yPix = 0  #Defines the y position

    #Doing the first iteration in case we start at x=0
    imArray[yPix, xPix] = inputData[0]
    xPix += 1

    #Going through all the other values
    i = 1
    while i < inputData.size:
        imArray[yPix, xPix] = inputData[i]

        #Moving one y position up when reaching one end of the image
        if xPix == (totalxPixels - 1):
            xPix = totalxPixels - exPixelsX - 1
            yPix += 1
            #Going to the next value manually
            i += 1
            if i == inputData.size:
                break  #Making sure i does not exceed the input data array
            imArray[yPix, xPix] = inputData[i]
            forward = not forward
        elif xPix == 0:
            xPix = exPixelsX
            yPix += 1
            #Going to the next value manually
            i += 1
            if i == inputData.size:
                break  #Making sure i does not exceed the input data array
            imArray[yPix, xPix] = inputData[i]
            forward = not forward

        if forward == True:
            xPix += 1  #Moving one up if moving forward over the x pixels
        else:
            xPix -= 1  #Moving one down if moving backward over the x pixels

        i += 1  #Going to the next value of the input data

    #Plotting the image
    plt.imshow(imArray, cmap=plt.cm.gray)
    plt.show()
コード例 #10
0
    def load(self, stim, digstim=None, use_ao_trigger=False):
        # check if the modes are up to date
        assert type(stim) is list, 'Stim needs to be a list of numpy arrays'
        self._check_modes()
        self.nsamples = int(
            np.max([np.max(s.shape) for s in stim if not s is None]))
        aoconversion = self._get_conversion(False)

        if not self.task_ai is None and self.task_ao is None:
            self.task_ai.timing.cfg_samp_clk_timing(
                rate=self.srate, samps_per_chan=self.nsamples)

        if not self.task_ao is None:
            self.task_ao.timing.cfg_samp_clk_timing(
                rate=self.srate, samps_per_chan=self.nsamples)
            self.task_ao.export_signals.export_signal(
                nidaqmx.constants.Signal.SAMPLE_CLOCK, 'PFI0')
            if not self.task_ai is None:
                if use_ao_trigger:
                    self.task_ai.triggers.start_trigger.cfg_dig_edge_start_trig(
                        'ao/StartTrigger')

                    self.task_ai.timing.cfg_samp_clk_timing(
                        rate=self.srate,
                        source='PFI0',
                        samps_per_chan=self.nsamples)

            # Take care of the conversions
            stims = np.zeros((self.n_output_chan, self.nsamples),
                             dtype=np.float64)
            # Fix the analog output conversions
            for i in range(self.n_output_chan):
                if i < len(stim):
                    if stim[i] is None:
                        continue
                    if not len(stim[i]):
                        continue
                    stims[i] = stim[i] * aoconversion[i]

            if hasattr(self, 'task_clock'):
                self.task_clock.timing.cfg_implicit_timing(
                    samps_per_chan=self.nsamples)

                if not self.task_ao is None:
                    self.task_ao.timing.cfg_samp_clk_timing(
                        self.srate,
                        source=self.samp_clk_terminal,
                        active_edge=nidaqmx.constants.Edge.RISING,
                        samps_per_chan=self.nsamples)
                if not self.task_ai is None:
                    self.task_ai.timing.cfg_samp_clk_timing(
                        self.srate,
                        source=self.samp_clk_terminal,
                        active_edge=nidaqmx.constants.Edge.FALLING,
                        samps_per_chan=self.nsamples)

            self.writer = AnalogMultiChannelWriter(self.task_ao.out_stream)
            self.reader = AnalogMultiChannelReader(self.task_ai.in_stream)
            self.writer.write_many_sample(stims)

        self.run_do = False
        if not digstim is None:
            if not self.task_do is None:
                self.task_do.timing.cfg_samp_clk_timing(
                    rate=self.srate,
                    source=self.samp_clk_terminal,
                    active_edge=nidaqmx.constants.Edge.RISING,
                    samps_per_chan=self.nsamples)
                #this works for 32 bit ports only, all iputs must be on the same port for now.
                digstims = np.zeros((self.nsamples, 32), dtype=np.uint32)
                for i in range(len(digstim)):
                    if digstim[i] is None:
                        continue
                    if not len(digstim[i]):
                        continue
                    digstims[:, i] = (digstim[i] > 0)
                self.di_writer = DigitalMultiChannelWriter(
                    self.task_do.out_stream)
                self.di_writer.write_many_sample_port_uint32(
                    np.packbits(digstims, bitorder='little').reshape(
                        (1, -1)).view(np.uint32))
                self.run_do = True
        self.acquired = False
コード例 #11
0
    def launch(self):

        if self.outputs is not None:
            self.write_task = nidaqmx.Task()

        if self.Nchannel_analog_in > 0:
            self.read_analog_task = nidaqmx.Task()
        if self.Nchannel_digital_in > 0:
            self.read_digital_task = nidaqmx.Task()
        self.sample_clk_task = nidaqmx.Task()

        # Use a counter output pulse train task as the sample clock source
        # for both the AI and AO tasks.
        self.sample_clk_task.co_channels.add_co_pulse_chan_freq(
            '{0}/ctr0'.format(self.device.name), freq=self.sampling_rate)
        self.sample_clk_task.timing.cfg_implicit_timing(
            samps_per_chan=int(self.max_time / self.dt))
        self.samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(
            self.device.name)

        ### ---- OUTPUTS ---- ##
        if self.outputs is not None:
            self.write_task.ao_channels.add_ao_voltage_chan(
                flatten_channel_string(self.output_channels),
                max_val=10,
                min_val=-10)
            self.write_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))

        ### ---- INPUTS ---- ##
        if self.Nchannel_analog_in > 0:
            self.read_analog_task.ai_channels.add_ai_voltage_chan(
                flatten_channel_string(self.analog_input_channels),
                max_val=10,
                min_val=-10)
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.di_channels.add_di_chan(
                flatten_channel_string(self.digital_input_channels))

        if self.Nchannel_analog_in > 0:
            self.read_analog_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))

        if self.Nchannel_analog_in > 0:
            self.analog_reader = AnalogMultiChannelReader(
                self.read_analog_task.in_stream)
            self.read_analog_task.register_every_n_samples_acquired_into_buffer_event(
                self.buffer_size, self.reading_task_callback)
        if self.Nchannel_digital_in > 0:
            self.digital_reader = DigitalMultiChannelReader(
                self.read_digital_task.in_stream)
            self.read_digital_task.register_every_n_samples_acquired_into_buffer_event(
                self.buffer_size, self.reading_task_callback)

        if self.outputs is not None:
            self.writer = AnalogMultiChannelWriter(self.write_task.out_stream)
            self.writer.write_many_sample(self.outputs)

        # Start the read task before starting the sample clock source task.
        if self.Nchannel_analog_in > 0:
            self.read_analog_task.start()
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.start()

        if self.outputs is not None:
            self.write_task.start()

        self.sample_clk_task.start()
        if self.filename is not None:
            np.save(self.filename.replace('.npy', '.start.npy'),
                    np.ones(1) *
                    time.time())  # saving the time stamp of the start !

        self.running, self.data_saved = True, False
コード例 #12
0
class Acquisition:
    def __init__(
        self,
        dt=1e-3,
        Nchannel_analog_in=2,
        Nchannel_digital_in=1,
        max_time=10,
        buffer_time=0.5,
        filename=None,
        device=None,
        outputs=None,
        output_steps=[],  # should be a set of dictionaries, output_steps=[{'channel':0, 'onset': 2.3, 'duration': 1., 'value':5}]
        verbose=False):

        self.running, self.data_saved = False, False

        self.dt = dt
        self.max_time = max_time
        self.sampling_rate = 1. / self.dt
        self.buffer_size = int(buffer_time / self.dt)
        self.Nchannel_analog_in = Nchannel_analog_in
        self.Nchannel_digital_in = Nchannel_digital_in
        self.filename = filename
        self.select_device()

        # preparing input channels
        # - analog:
        self.analog_data = np.zeros((Nchannel_analog_in, 1), dtype=np.float64)
        if self.Nchannel_analog_in > 0:
            self.analog_input_channels = get_analog_input_channels(
                self.device)[:Nchannel_analog_in]
        # - digital:
        self.digital_data = np.zeros((1, 1), dtype=np.uint32)
        if self.Nchannel_digital_in > 0:
            self.digital_input_channels = get_digital_input_channels(
                self.device)[:Nchannel_digital_in]

        # preparing output channels
        if outputs is not None:  # used as a flag for output or not
            self.output_channels = get_analog_output_channels(
                self.device)[:outputs.shape[0]]
        elif len(output_steps) > 0:
            Nchannel = max([d['channel'] for d in output_steps]) + 1
            # have to be elements
            t = np.arange(int(self.max_time / self.dt)) * self.dt
            outputs = np.zeros((Nchannel, len(t)))
            # add as many channels as necessary
            for step in output_steps:
                if step['channel'] > outputs.shape[0]:
                    outputs = np.append(outputs, np.zeros((1, len(t))), axis=0)
            for step in output_steps:
                cond = (t > step['onset']) & (t <=
                                              step['onset'] + step['duration'])
                outputs[step['channel']][cond] = step['value']
            self.output_channels = get_analog_output_channels(
                self.device)[:outputs.shape[0]]
        self.outputs = outputs

    def launch(self):

        if self.outputs is not None:
            self.write_task = nidaqmx.Task()

        if self.Nchannel_analog_in > 0:
            self.read_analog_task = nidaqmx.Task()
        if self.Nchannel_digital_in > 0:
            self.read_digital_task = nidaqmx.Task()
        self.sample_clk_task = nidaqmx.Task()

        # Use a counter output pulse train task as the sample clock source
        # for both the AI and AO tasks.
        self.sample_clk_task.co_channels.add_co_pulse_chan_freq(
            '{0}/ctr0'.format(self.device.name), freq=self.sampling_rate)
        self.sample_clk_task.timing.cfg_implicit_timing(
            samps_per_chan=int(self.max_time / self.dt))
        self.samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(
            self.device.name)

        ### ---- OUTPUTS ---- ##
        if self.outputs is not None:
            self.write_task.ao_channels.add_ao_voltage_chan(
                flatten_channel_string(self.output_channels),
                max_val=10,
                min_val=-10)
            self.write_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))

        ### ---- INPUTS ---- ##
        if self.Nchannel_analog_in > 0:
            self.read_analog_task.ai_channels.add_ai_voltage_chan(
                flatten_channel_string(self.analog_input_channels),
                max_val=10,
                min_val=-10)
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.di_channels.add_di_chan(
                flatten_channel_string(self.digital_input_channels))

        if self.Nchannel_analog_in > 0:
            self.read_analog_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.timing.cfg_samp_clk_timing(
                self.sampling_rate,
                source=self.samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=int(self.max_time / self.dt))

        if self.Nchannel_analog_in > 0:
            self.analog_reader = AnalogMultiChannelReader(
                self.read_analog_task.in_stream)
            self.read_analog_task.register_every_n_samples_acquired_into_buffer_event(
                self.buffer_size, self.reading_task_callback)
        if self.Nchannel_digital_in > 0:
            self.digital_reader = DigitalMultiChannelReader(
                self.read_digital_task.in_stream)
            self.read_digital_task.register_every_n_samples_acquired_into_buffer_event(
                self.buffer_size, self.reading_task_callback)

        if self.outputs is not None:
            self.writer = AnalogMultiChannelWriter(self.write_task.out_stream)
            self.writer.write_many_sample(self.outputs)

        # Start the read task before starting the sample clock source task.
        if self.Nchannel_analog_in > 0:
            self.read_analog_task.start()
        if self.Nchannel_digital_in > 0:
            self.read_digital_task.start()

        if self.outputs is not None:
            self.write_task.start()

        self.sample_clk_task.start()
        if self.filename is not None:
            np.save(self.filename.replace('.npy', '.start.npy'),
                    np.ones(1) *
                    time.time())  # saving the time stamp of the start !

        self.running, self.data_saved = True, False

    def close(self):
        """
        not optimal...
        
        nidaqmx has weird behaviors sometimes... :(
        """
        if self.running:
            if self.Nchannel_digital_in > 0:
                self.read_digital_task.close()
            if self.Nchannel_analog_in > 0:
                self.read_analog_task.close()
            if self.outputs is not None:
                self.write_task.close()
            self.sample_clk_task.close()

        if (self.filename is not None):
            if self.data_saved:
                print('[ok] NIdaq data already saved as: %s ' % self.filename)
            else:
                np.save(
                    self.filename, {
                        'analog': self.analog_data[:, 1:],
                        'digital': self.digital_data[:, 1:]
                    })
                print('[ok] NIdaq data saved as: %s ' % self.filename)
            self.data_saved = True

        self.running = False

    def reading_task_callback(self,
                              task_idx,
                              event_type,
                              num_samples,
                              callback_data=None):
        if self.running:
            if self.Nchannel_analog_in > 0:
                analog_buffer = np.zeros(
                    (self.Nchannel_analog_in, num_samples), dtype=np.float64)
                self.analog_reader.read_many_sample(analog_buffer,
                                                    num_samples,
                                                    timeout=WAIT_INFINITELY)
                self.analog_data = np.append(self.analog_data,
                                             analog_buffer,
                                             axis=1)

            if self.Nchannel_digital_in > 0:
                digital_buffer = np.zeros((1, num_samples), dtype=np.uint32)
                self.digital_reader.read_many_sample_port_uint32(
                    digital_buffer, num_samples, timeout=WAIT_INFINITELY)
                self.digital_data = np.append(self.digital_data,
                                              digital_buffer,
                                              axis=1)
        else:
            self.close()
        return 0  # needed for this callback to be well defined (see nidaqmx doc).

    def select_device(self):
        success = False
        try:
            self.device = find_x_series_devices()[0]
            print('X-series card found:', self.device)
            success = True
        except BaseException:
            pass
        try:
            self.device = find_m_series_devices()[0]
            print('M-series card found:', self.device)
            success = True
        except BaseException:
            pass
        if not success:
            print('Neither M-series nor X-series NI DAQ card found')
コード例 #13
0
    def run(self):
        """
        Starts writing a waveform continuously while reading 
        the buffer periodically
        """

        with nidaqmx.Task() as slave_Task, nidaqmx.Task() as master_Task:

            slave_Task.ao_channels.add_ao_voltage_chan("/Dev1/ao0:1")
            master_Task.ai_channels.add_ai_voltage_chan("/Dev1/ai0")

            if self.flag_continuous == False:
                # Timing of analog output channels
                slave_Task.timing.cfg_samp_clk_timing(
                    rate=self.Daq_sample_rate,
                    source='ai/SampleClock',
                    sample_mode=AcquisitionType.FINITE,
                    samps_per_chan=self.Totalscansamples)

                # Timing of recording channels
                master_Task.timing.cfg_samp_clk_timing(
                    rate=self.Daq_sample_rate,
                    sample_mode=AcquisitionType.FINITE,
                    samps_per_chan=self.Totalscansamples)
            else:
                # Timing of analog output channels
                slave_Task.timing.cfg_samp_clk_timing(
                    rate=self.Daq_sample_rate,
                    source='ai/SampleClock',
                    sample_mode=AcquisitionType.CONTINUOUS)

                # Timing of recording channels
                master_Task.timing.cfg_samp_clk_timing(
                    rate=self.Daq_sample_rate,
                    sample_mode=AcquisitionType.CONTINUOUS,
                    samps_per_chan=self.Totalscansamples)

            reader = AnalogSingleChannelReader(master_Task.in_stream)
            writer = AnalogMultiChannelWriter(slave_Task.out_stream)

            reader.auto_start = False
            writer.auto_start = False

            writer.write_many_sample(self.Galvo_samples)
            """Reading data from the buffer in a loop. 
            The idea is to let the task read more than could be loaded in the buffer for each iteration.
            This way the task will have to wait slightly longer for incoming samples. And leaves the buffer
            entirely clean. This way we always know the correct numpy size and are always left with an empty
            buffer (and the buffer will not slowly fill up)."""
            output = np.zeros(self.Totalscansamples)
            slave_Task.start(
            )  #Will wait for the readtask to start so it can use its clock
            master_Task.start()

            # while not self.isInterruptionRequested():
            reader.read_many_sample(
                data=output,
                number_of_samples_per_channel=self.Totalscansamples)

            Dataholder_average = np.mean(output.reshape(self.averagenum, -1),
                                         axis=0)

            if self.flag_return_image == True:
                # Calculate the mean of average frames.
                self.data_PMT = np.reshape(
                    Dataholder_average,
                    (self.pixel_number, self.total_X_sample_number))

                # Cut off the flying back part.
                if self.pixel_number == 500:
                    self.image_PMT = self.data_PMT[:, 50:550] * -1
                elif self.pixel_number == 256:
                    self.image_PMT = self.data_PMT[:, 70:326] * -1

                return self.image_PMT
コード例 #14
0
ファイル: recording.py プロジェクト: yzerlaut/physion
def stim_and_rec(device,
                 t_array,
                 analog_inputs,
                 analog_outputs,
                 N_digital_inputs=0):

    dt = t_array[1] - t_array[0]
    sampling_rate = 1. / dt

    # if analog_outputs.shape[0]>0:
    output_analog_channels = get_analog_output_channels(
        device)[:analog_outputs.shape[0]]
    input_analog_channels = get_analog_input_channels(
        device)[:analog_inputs.shape[0]]
    if N_digital_inputs > 0:
        input_digital_channels = get_digital_input_channels(
            device)[:N_digital_inputs]

    with nidaqmx.Task() as write_analog_task, nidaqmx.Task() as read_analog_task,\
         nidaqmx.Task() as read_digital_task,  nidaqmx.Task() as sample_clk_task:

        # Use a counter output pulse train task as the sample clock source
        # for both the AI and AO tasks.
        sample_clk_task.co_channels.add_co_pulse_chan_freq('{0}/ctr0'.format(
            device.name),
                                                           freq=sampling_rate)
        sample_clk_task.timing.cfg_implicit_timing(samps_per_chan=len(t_array))

        samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(device.name)

        ### ---- OUTPUTS ---- ##
        write_analog_task.ao_channels.add_ao_voltage_chan(
            flatten_channel_string(output_analog_channels),
            max_val=10,
            min_val=-10)
        write_analog_task.timing.cfg_samp_clk_timing(
            sampling_rate,
            source=samp_clk_terminal,
            active_edge=Edge.RISING,
            samps_per_chan=len(t_array))

        ### ---- INPUTS ---- ##
        read_analog_task.ai_channels.add_ai_voltage_chan(
            flatten_channel_string(input_analog_channels),
            max_val=10,
            min_val=-10)
        if N_digital_inputs > 0:
            read_digital_task.di_channels.add_di_chan(
                flatten_channel_string(input_digital_channels))

        read_analog_task.timing.cfg_samp_clk_timing(
            sampling_rate,
            source=samp_clk_terminal,
            active_edge=Edge.FALLING,
            samps_per_chan=len(t_array))
        if N_digital_inputs > 0:
            read_digital_task.timing.cfg_samp_clk_timing(
                sampling_rate,
                source=samp_clk_terminal,
                active_edge=Edge.FALLING,
                samps_per_chan=len(t_array))

        analog_writer = AnalogMultiChannelWriter(write_analog_task.out_stream)
        analog_reader = AnalogMultiChannelReader(read_analog_task.in_stream)
        if N_digital_inputs > 0:
            digital_reader = DigitalMultiChannelReader(
                read_digital_task.in_stream)

        analog_writer.write_many_sample(analog_outputs)

        # Start the read and write tasks before starting the sample clock
        # source task.
        read_analog_task.start()
        if N_digital_inputs > 0:
            read_digital_task.start()
        write_analog_task.start()
        sample_clk_task.start()

        analog_reader.read_many_sample(
            analog_inputs,
            number_of_samples_per_channel=len(t_array),
            timeout=t_array[-1] + 2 * dt)
        if N_digital_inputs > 0:
            digital_inputs = np.zeros((1, len(t_array)), dtype=np.uint32)
            digital_reader.read_many_sample_port_uint32(
                digital_inputs,
                number_of_samples_per_channel=len(t_array),
                timeout=t_array[-1] + 2 * dt)
        else:
            digital_inputs = None
    return analog_inputs, digital_inputs
コード例 #15
0
class SignalWriter(QtCore.QThread):
    """A QThread that periodically reads the voltages output by the data acquisition card.

    This thread outputs signals to the function generator according to parameters. These parameters can be modified
    by other threads as this thread simply reads them. Also, keep in mind that the __init__ method only runs once to
    establish properties and default values.

    Attributes:
        funcg_name (str): name given to the NI card by the drivers
        writechannel_list (list): list containing all of the connected channels
        funcg_rate (int): rate at which the NI DAQ card generate data
        writechunksize (int): The QThread adds this amount of data to the buffer at once. Hard coded to be the rate
            divided by 10.
        zcoeff (float): used to calculate the signals, defined in detail other places
        running (bool): used to control the state of the run loop from outside this thread

    """
    errorMessage = QtCore.pyqtSignal(object)

    def __init__(self, funcg_name, writechannel_list, funcg_rate, writechunksize, zcoeff, vmulti, freq, camber, zphase,
                 calib_xamp, calib_yamp, calib_zamp):
        super().__init__()  # Inherit properties of a QThread

        # Static variables
        self.funcg_name = funcg_name
        self.writechannel_list = writechannel_list
        self.funcg_rate = funcg_rate
        self.writechunksize = self.funcg_rate // 10
        self.zcoeff = zcoeff

        # Changing variables
        self.vmulti = vmulti
        self.freq = freq  # single integer
        self.camber = camber
        self.zphase = zphase  # single integer

        # Calibration variables
        self.calib_mode = False  # variable to store whether in calibration mode
        self.calib_xamp = calib_xamp
        self.calib_yamp = calib_yamp
        self.calib_zamp = calib_zamp

        # pre-allocate an empty output array
        self.output = np.zeros([len(self.writechannel_list), self.writechunksize])
        self.running = False  # Variable to keep track of whether the thread is running.

        # Instantiate the WaveGenerator
        self.WaveGen = WaveGenerator()

    def run(self):
        """Runs when the start method is called on the thread.

        First, the output channels are initialized. If the thread can't, it emits an error signal. Next, it sets the
        generation rate and mode. Other properties are set for continuous modulation of the signal.

        The buffer size is set to be 2 times the *writechunksize* to allow for some wiggle room if a data point is a
        microsecond late.

        Next, an event is registered along with the continuous generation mode that signals the **add_more_data**
        method after every *writechunksize* values are transferred from the buffer. This is what allows this run method
        to loop, as the writeTask never truly finishes as data points are constantly being added to the buffer.

        For the first write to the buffer, two *writechunksize* chunks are written to fill up the buffer completely.

        """
        self.running = True
        self.writeTask = nidaqmx.Task()  # Start the task

        # Add input channels
        for index, i in enumerate(self.writechannel_list):
            channel_string = self.funcg_name + '/' + f'ao{i}'
            try:
                self.writeTask.ao_channels.add_ao_voltage_chan(channel_string)
            except Exception as e:
                if index == 0:
                    self.errorMessage.emit('Could not open write channels. Are device names correct?'
                                           f" Devices connected: {find_ni_devices()}")
                    return

        # Set the generation rate, and buffer size.
        self.writeTask.timing.cfg_samp_clk_timing(
            rate=self.funcg_rate,
            sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS)

        # Set more properties for continuous signal modulation
        self.writeTask.out_stream.regen_mode = nidaqmx.constants.RegenerationMode.DONT_ALLOW_REGENERATION
        self.writeTask.out_stream.output_buf_size = 2 * self.writechunksize

        # Register the listening method to add more data
        self.writeTask.register_every_n_samples_transferred_from_buffer_event(
            sample_interval=self.writechunksize,
            callback_method=self.add_more_data)

        # Initialize the writer
        self.writer = AnalogMultiChannelWriter(self.writeTask.out_stream)

        if not self.calib_mode:
            self.output = self.WaveGen.generate_waves(
                funcg_rate=self.funcg_rate,
                writechunksize=self.writechunksize,
                vmulti=self.vmulti,
                freq=self.freq,
                camber=self.camber,
                zphase=self.zphase,
                zcoeff=self.zcoeff)
        elif self.calib_mode:
            self.output = self.WaveGen.generate_calib_waves(
                funcg_rate=self.funcg_rate,
                writechunksize=self.writechunksize,
                calib_xamp=self.calib_xamp,
                calib_yamp=self.calib_yamp,
                calib_zamp=self.calib_zamp
            )

        # Write the first set of data into the output buffer
        try:
            self.writer.write_many_sample(data=self.output)  # Write two chunks of beginning data to avoid interruption
        except:
            self.errorMessage.emit('Could not write data to the output. Is the output device name correct?'
                                   f" Devices connected: {find_ni_devices()}")
            return

        self.writer.write_many_sample(data=self.output)  # write a second chunk to the buffer

        # Start the task, which will hold the thread at this location, continually calling add_more_data
        self.writeTask.start()

    def add_more_data(self, task_handle, every_n_samples_event_type, number_of_samples, callback_data):
        """This method adds data to the buffer when it is called.

        If running is false, it instead closes the NI writeTask.

        """
        if self.running is True:
            if not self.calib_mode:
                self.output = self.WaveGen.generate_waves(
                    funcg_rate=self.funcg_rate,
                    writechunksize=self.writechunksize,
                    vmulti=self.vmulti,
                    freq=self.freq,
                    camber=self.camber,
                    zphase=self.zphase,
                    zcoeff=self.zcoeff)
            elif self.calib_mode:
                self.output = self.WaveGen.generate_calib_waves(
                    funcg_rate=self.funcg_rate,
                    writechunksize=self.writechunksize,
                    calib_xamp=self.calib_xamp,
                    calib_yamp=self.calib_yamp,
                    calib_zamp=self.calib_zamp
                )
            self.writer.write_many_sample(data=self.output)

        else:
            self.writeTask.close()

        return 0
コード例 #16
0
    def run(self):
        """Runs when the start method is called on the thread.

        First, the output channels are initialized. If the thread can't, it emits an error signal. Next, it sets the
        generation rate and mode. Other properties are set for continuous modulation of the signal.

        The buffer size is set to be 2 times the *writechunksize* to allow for some wiggle room if a data point is a
        microsecond late.

        Next, an event is registered along with the continuous generation mode that signals the **add_more_data**
        method after every *writechunksize* values are transferred from the buffer. This is what allows this run method
        to loop, as the writeTask never truly finishes as data points are constantly being added to the buffer.

        For the first write to the buffer, two *writechunksize* chunks are written to fill up the buffer completely.

        """
        self.running = True
        self.writeTask = nidaqmx.Task()  # Start the task

        # Add input channels
        for index, i in enumerate(self.writechannel_list):
            channel_string = self.funcg_name + '/' + f'ao{i}'
            try:
                self.writeTask.ao_channels.add_ao_voltage_chan(channel_string)
            except Exception as e:
                if index == 0:
                    self.errorMessage.emit('Could not open write channels. Are device names correct?'
                                           f" Devices connected: {find_ni_devices()}")
                    return

        # Set the generation rate, and buffer size.
        self.writeTask.timing.cfg_samp_clk_timing(
            rate=self.funcg_rate,
            sample_mode=nidaqmx.constants.AcquisitionType.CONTINUOUS)

        # Set more properties for continuous signal modulation
        self.writeTask.out_stream.regen_mode = nidaqmx.constants.RegenerationMode.DONT_ALLOW_REGENERATION
        self.writeTask.out_stream.output_buf_size = 2 * self.writechunksize

        # Register the listening method to add more data
        self.writeTask.register_every_n_samples_transferred_from_buffer_event(
            sample_interval=self.writechunksize,
            callback_method=self.add_more_data)

        # Initialize the writer
        self.writer = AnalogMultiChannelWriter(self.writeTask.out_stream)

        if not self.calib_mode:
            self.output = self.WaveGen.generate_waves(
                funcg_rate=self.funcg_rate,
                writechunksize=self.writechunksize,
                vmulti=self.vmulti,
                freq=self.freq,
                camber=self.camber,
                zphase=self.zphase,
                zcoeff=self.zcoeff)
        elif self.calib_mode:
            self.output = self.WaveGen.generate_calib_waves(
                funcg_rate=self.funcg_rate,
                writechunksize=self.writechunksize,
                calib_xamp=self.calib_xamp,
                calib_yamp=self.calib_yamp,
                calib_zamp=self.calib_zamp
            )

        # Write the first set of data into the output buffer
        try:
            self.writer.write_many_sample(data=self.output)  # Write two chunks of beginning data to avoid interruption
        except:
            self.errorMessage.emit('Could not write data to the output. Is the output device name correct?'
                                   f" Devices connected: {find_ni_devices()}")
            return

        self.writer.write_many_sample(data=self.output)  # write a second chunk to the buffer

        # Start the task, which will hold the thread at this location, continually calling add_more_data
        self.writeTask.start()
コード例 #17
0
    def test_many_sample(self, x_series_device, seed):
        # Reset the pseudorandom number generator with seed.
        random.seed(seed)

        number_of_samples = random.randint(20, 100)
        sample_rate = random.uniform(1000, 5000)

        # Select a random loopback channel pair on the device.
        loopback_channel_pairs = self._get_analog_loopback_channels(
            x_series_device)

        number_of_channels = random.randint(2, len(loopback_channel_pairs))
        channels_to_test = random.sample(
            loopback_channel_pairs, number_of_channels)

        with nidaqmx.Task() as write_task, nidaqmx.Task() as read_task, \
                nidaqmx.Task() as sample_clk_task:
            # Use a counter output pulse train task as the sample clock source
            # for both the AI and AO tasks.
            sample_clk_task.co_channels.add_co_pulse_chan_freq(
                '{0}/ctr0'.format(x_series_device.name), freq=sample_rate)
            sample_clk_task.timing.cfg_implicit_timing(
                samps_per_chan=number_of_samples)

            samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(
                x_series_device.name)

            write_task.ao_channels.add_ao_voltage_chan(
                flatten_channel_string(
                    [c.output_channel for c in channels_to_test]),
                max_val=10, min_val=-10)
            write_task.timing.cfg_samp_clk_timing(
                sample_rate, source=samp_clk_terminal,
                active_edge=Edge.RISING, samps_per_chan=number_of_samples)

            read_task.ai_channels.add_ai_voltage_chan(
                flatten_channel_string(
                    [c.input_channel for c in channels_to_test]),
                max_val=10, min_val=-10)
            read_task.timing.cfg_samp_clk_timing(
                sample_rate, source=samp_clk_terminal,
                active_edge=Edge.FALLING, samps_per_chan=number_of_samples)

            writer = AnalogMultiChannelWriter(write_task.out_stream)
            reader = AnalogMultiChannelReader(read_task.in_stream)

            values_to_test = numpy.array(
                [[random.uniform(-10, 10) for _ in range(number_of_samples)]
                 for _ in range(number_of_channels)], dtype=numpy.float64)
            writer.write_many_sample(values_to_test)

            # Start the read and write tasks before starting the sample clock
            # source task.
            read_task.start()
            write_task.start()
            sample_clk_task.start()

            values_read = numpy.zeros(
                (number_of_channels, number_of_samples), dtype=numpy.float64)
            reader.read_many_sample(
                values_read, number_of_samples_per_channel=number_of_samples,
                timeout=2)

            numpy.testing.assert_allclose(
                values_read, values_to_test, rtol=0.05, atol=0.005)
コード例 #18
0
class NIBoards(AbstractScanInterface):
    def __init__(self, *args, read_task, write_task_z, write_task_xy):
        super().__init__(*args)
        self.read_task = read_task
        self.write_task_xy = write_task_xy
        self.write_task_z = write_task_z

        self.z_writer = AnalogMultiChannelWriter(write_task_z.out_stream)
        self.xy_writer = AnalogMultiChannelWriter(write_task_xy.out_stream)
        self.z_reader = AnalogSingleChannelReader(read_task.in_stream)

        self.xy_array = np.zeros((2, self.n_samples))
        self.z_array = np.zeros((4, self.n_samples))

        self.read_array = np.zeros(self.n_samples)

        self.setup_tasks()

    def setup_tasks(self):
        # Configure the channels

        # read channel is only the piezo position on board 1
        self.read_task.ai_channels.add_ai_voltage_chan(
            self.conf["z_board"]["read"]["channel"],
            min_val=self.conf["z_board"]["read"]["min_val"],
            max_val=self.conf["z_board"]["read"]["max_val"],
        )

        # write channels are on board 1: piezo and z galvos
        self.write_task_z.ao_channels.add_ao_voltage_chan(
            self.conf["z_board"]["write"]["channel"],
            min_val=self.conf["z_board"]["write"]["min_val"],
            max_val=self.conf["z_board"]["write"]["max_val"],
        )

        # on board 2: lateral galvos
        self.write_task_xy.ao_channels.add_ao_voltage_chan(
            self.conf["xy_board"]["write"]["channel"],
            min_val=self.conf["xy_board"]["write"]["min_val"],
            max_val=self.conf["xy_board"]["write"]["max_val"],
        )

        # Set the timing of both to the onboard clock so that they are synchronised
        self.read_task.timing.cfg_samp_clk_timing(
            rate=self.sample_rate,
            source="OnboardClock",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS,
            samps_per_chan=self.n_samples,
        )
        self.write_task_z.timing.cfg_samp_clk_timing(
            rate=self.sample_rate,
            source="OnboardClock",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS,
            samps_per_chan=self.n_samples,
        )

        self.write_task_xy.timing.cfg_samp_clk_timing(
            rate=self.sample_rate,
            source="OnboardClock",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS,
            samps_per_chan=self.n_samples,
        )

        # This is necessary to synchronise reading and writing
        self.read_task.triggers.start_trigger.cfg_dig_edge_start_trig(
            self.conf["z_board"]["sync"]["channel"], Edge.RISING)

    def start(self):
        self.read_task.start()
        self.write_task_xy.start()
        self.write_task_z.start()

    def write(self):
        self.z_writer.write_many_sample(self.z_array)
        self.xy_writer.write_many_sample(self.xy_array)

    def read(self):
        self.z_reader.read_many_sample(
            self.read_array,
            number_of_samples_per_channel=self.n_samples,
            timeout=1,
        )
        self.read_array[:] = self.read_array

    @property
    def z_piezo(self):
        return self.read_array / self.conf["piezo"]["scale"]

    @z_piezo.setter
    def z_piezo(self, waveform):
        self.z_array[0, :] = waveform * self.conf["piezo"]["scale"]

    @property
    def z_lateral(self):
        return self.z_array[1, :]

    @property
    def z_frontal(self):
        return self.z_array[2, :]

    @z_lateral.setter
    def z_lateral(self, waveform):
        self.z_array[1, :] = waveform

    @z_frontal.setter
    def z_frontal(self, waveform):
        self.z_array[2, :] = waveform

    @property
    def camera_trigger(self):
        return self.z_array[3, :]

    @camera_trigger.setter
    def camera_trigger(self, waveform):
        self.z_array[3, :] = waveform

    @property
    def xy_frontal(self):
        return self.xy_array[1, :]

    @xy_frontal.setter
    def xy_frontal(self, waveform):
        self.xy_array[1, :] = waveform

    @property
    def xy_lateral(self):
        return self.xy_array[0, :]

    @xy_lateral.setter
    def xy_lateral(self, waveform):
        self.xy_array[0, :] = waveform
コード例 #19
0
class NIServer(ThreadedServer):
    """ Provide access to NI DAQ via nidaqmx."""
    name = 'ni'

    def initServer(self):

        self.rate_do = config().set_do_rate()
        self.timeout_do = 150
        self.clk_channel_do = 'PFI4'

        self.rate_ao = config().set_ao_rate()
        self.timeout_ao = 150
        self.trigger_channel = 'PFI0'
        self.clk_channel_ao = 'PFI1'

        self.rate_clk = config().set_clk()
        # self.source = '100kHzTimebase'
        # self.source = 'PXI_Clk10' # Internal clock source, 10 MHz
        self.source = 'PFI0'  #External CLK source input, 10 MHz
        self.timeout_clk = 150
        # (Variable clock output is = p0.0)

        self.seq_task_ao = None
        self.seq_task_do = None
        self.seq_task_clk = None

        self.ai_trigger = 'PFI1'  # Should be PFI1
        self.pd_task_ai = None
        self.pmt_task_ai = None
        self.timeout_ai = 180

        super(NIServer, self).initServer()

    @setting(1)
    def write_ao_manual(self, c, voltage, port):
        """
        Writes Voltage for ONE channel that we are interested in.
        """
        if self.seq_task_ao:  # Make sure task is close before you add new stuffs.
            self.seq_task_ao.close()
            self.seq_task_ao = None

        with nidaqmx.Task() as task:
            task.ao_channels.add_ao_voltage_chan('Dev2/ao{}'.format(port))

            task.write(voltage, auto_start=True)
            task.stop()

    @setting(2)
    def write_do_manual(self, c, boolean):
        """
        Writes Boolean for channels set to "manual"
        """
        if self.seq_task_do:  # Make sure task is close before you add new stuffs.
            self.seq_task_do.close()
            self.seq_task_do = None

        with nidaqmx.Task() as task:
            task.do_channels.add_do_chan(
                'Dev1/port0/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
            task.do_channels.add_do_chan(
                'Dev1/port1/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
            task.do_channels.add_do_chan(
                'Dev1/port2/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
            task.do_channels.add_do_chan(
                'Dev1/port3/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)

            task.write(boolean, auto_start=True)
            task.stop()

    @setting(3)
    def write_clk_manual(self, c, boolean):
        """
        CLK Manual value is always False.
        """
        if self.seq_task_clk:  # Make sure task is close before you add new stuffs.
            self.seq_task_clk.close()
            self.seq_task_clk = None

        with nidaqmx.Task() as task:
            task.do_channels.add_do_chan('Dev0/port0/line0')

            task.write(boolean, auto_start=True)
            task.stop()

    @setting(4, sequence='s')
    def write_ao_sequence(self, c, sequence):
        """
        NOT all AO channels are written, we selecte channels by the length of sequence, in principle it should be >2.
        """
        sequence_json = json.loads(sequence)

        num_port = len(sequence_json)
        num_samp = len(sequence_json[0])

        if self.seq_task_ao:  # Make sure task is close before you add new stuffs.
            self.seq_task_ao.close()

        self.seq_task_ao = nidaqmx.Task()
        self.seq_task_ao.ao_channels.add_ao_voltage_chan(
            'Dev2/ao0:{}'.format(num_port - 1))
        self.seq_task_ao.timing.cfg_samp_clk_timing(
            rate=self.rate_ao,
            source=self.clk_channel_ao,
            samps_per_chan=num_samp)  #rate, samps_per_chan
        # self.seq_task_ao.triggers.start_trigger.cfg_dig_edge_start_trig(self.trigger_channel)  # Default with rising edge
        # If share the same clock, there is no need to use DO trigger

        self.seq_task_ao.write(sequence_json, auto_start=False, timeout=-1)

    @setting(5, sequence='s')
    def write_do_sequence(self, c, sequence):
        """
        We write all 32 DO channels at a time.
        Default time-out is 120 s, which sets the limit of total sequence length.
        """

        sequence_json = json.loads(sequence)

        num_samp = len(sequence_json[0])

        if self.seq_task_do:  # Make sure task is close before you add new stuffs.
            self.seq_task_do.close()

        self.seq_task_do = nidaqmx.Task()
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port0/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port1/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port2/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port3/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
        self.seq_task_do.timing.cfg_samp_clk_timing(
            rate=self.rate_do,
            source=self.clk_channel_do,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.seq_task_do.write(sequence_json, auto_start=False, timeout=-1)

    @setting(6, sequence_path='s')
    def write_clk_sequence(self, c, sequence_path):
        """
        We use port0/line0 on AI card as the "Variable Clock Reference" to sample the DO and AO card.
        """

        sequence = np.load(sequence_path + '.npy').tolist()

        num_samp = len(sequence)
        if self.seq_task_clk:  # Make sure task is close before you add new stuffs.
            self.seq_task_clk.close()

        self.seq_task_clk = nidaqmx.Task()
        self.seq_task_clk.do_channels.add_do_chan('Dev0/port0/line0')

        self.seq_task_clk.timing.cfg_samp_clk_timing(
            rate=self.rate_clk, source=self.source,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.seq_task_clk.write(sequence, auto_start=False, timeout=-1)

    @setting(11)
    def start_ao_sequence(self, c):
        if self.seq_task_ao.is_task_done():
            self.seq_task_ao.start()

        else:
            print('Sequencer AO tasks do not exist!')

    @setting(12)
    def start_do_sequence(self, c):
        if self.seq_task_do.is_task_done():
            self.seq_task_do.start()

        else:
            print('Sequencer DO tasks do not exist!')

    @setting(13)
    def start_clk_sequence(self, c):
        if self.seq_task_clk.is_task_done():
            self.seq_task_clk.start()

            # conductor_server = self.client.conductor
            # shot = conductor_server.get_shotnumber()
            # print('NI DAQ tasks shot#{} started'.format(shot))

            self.seq_task_ao.wait_until_done(self.timeout_ao)
            # print('ao done')
            self.seq_task_do.wait_until_done(self.timeout_do)
            # print('do done')
            self.seq_task_clk.wait_until_done(self.timeout_clk)
            # print('clk done')

            self.seq_task_ao.stop()
            self.seq_task_do.stop()
            self.seq_task_clk.stop()

            # print('NI DAQ tasks shot#{} done'.format(shot))

        else:
            print('Sequencer CLK tasks do not exist!')

    # @setting(11)
    # def stop_sequence(self, c):
    #     if self.seq_task_clk != None and self.seq_task_do != None and self.seq_task_ao != None:
    #         self.seq_task_clk.close()
    #         self.seq_task_do.close()
    #         self.seq_task_ao.close()

    #     else:
    #         pass

    @setting(15)
    def read_ai_manual(self, c, port):
        with nidaqmx.Task() as task:
            task.ai_channels.add_ai_voltage_chan("Dev0/ai{}".format(port))
            data = task.read()
        return data

    @setting(16, returns='s')
    def pd_ai_trigger(self, c, port, samp_rate, n_samp):
        """
        Read Analog-In voltage for PD in Trigger Mode
        """
        if self.pd_task_ai:  # Make sure task is close before you add new stuffs.
            self.pd_task_ai.close()

        self.pd_task_ai = nidaqmx.Task()
        self.pd_task_ai.ai_channels.add_ai_voltage_chan(
            "Dev0/ai{}".format(port))
        self.pd_task_ai.timing.cfg_samp_clk_timing(
            rate=int(samp_rate),
            samps_per_chan=int(n_samp))  #rate, samps_per_chan
        self.pd_task_ai.triggers.start_trigger.cfg_dig_edge_start_trig(
            self.ai_trigger)  # Default with rising edge

        print('AI configured.')

        data = self.pd_task_ai.read(
            number_of_samples_per_channel=-1, timeout=self.timeout_ai
        )  # -1 means will read all available samples
        self.pd_task_ai.wait_until_done(self.timeout_ao)

        self.pd_task_ai.stop()
        data_json = json.dumps(data)
        return data_json

    @setting(19)
    def reset_devices(self, c):
        available_devices = list(nidaqmx.system.System.local().devices)
        if available_devices:
            for device in available_devices:
                device.reset_device()
        else:
            pass

    # @setting(20, raw_sequence_channels_list_json ='s')
    # def write_ao_raw_sequence(self, c, raw_sequence_channels_list_json):
    #     """
    #     NOT all AO channels are written for now, we select channels by the length of sequence, in principle it should be >2.
    #     """
    #     raw_sequence_channels_list = json.loads(raw_sequence_channels_list_json)
    #     sequence_bytes = make_sequence_bytes_ao(raw_sequence_channels_list)

    #     num_port = len(sequence_bytes)
    #     num_samp = len(sequence_bytes[0])

    #     if self.seq_task_ao: # Make sure task is close before you add new stuffs.
    #         self.seq_task_ao.close()

    #     self.seq_task_ao = nidaqmx.Task()
    #     self.seq_task_ao.ao_channels.add_ao_voltage_chan('Dev2/ao0:{}'.format(num_port-1))
    #     self.seq_task_ao.timing.cfg_samp_clk_timing(rate = self.rate_ao, source = self.clk_channel_ao, samps_per_chan = num_samp)    #rate, samps_per_chan

    #     self.seq_task_ao.write(sequence_bytes, auto_start = False, timeout = -1)

    # @setting(21, raw_sequence_json ='s', channels_list_json = 's')
    # def write_do_raw_sequence(self, c, raw_sequence_json, channels_list_json):
    #     """
    #     Write all 32 DO channels at a time.
    #     Default time-out is 120 s, which sets the limit of total sequence length.
    #     Input at this point is json.dump(raw_sequence).
    #     """
    #     raw_sequence = json.loads(raw_sequence_json)
    #     channels_list = json.loads(channels_list_json)
    #     sequence_bytes = make_sequence_bytes_do(raw_sequence, channels_list)

    #     num_samp = len(sequence_bytes[0])

    #     if self.seq_task_do: # Make sure task is close before you add new stuffs.
    #         self.seq_task_do.close()

    #     self.seq_task_do = nidaqmx.Task()
    #     self.seq_task_do.do_channels.add_do_chan('Dev1/port0/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
    #     self.seq_task_do.do_channels.add_do_chan('Dev1/port1/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
    #     self.seq_task_do.do_channels.add_do_chan('Dev1/port2/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
    #     self.seq_task_do.do_channels.add_do_chan('Dev1/port3/line0:7', line_grouping=LineGrouping.CHAN_PER_LINE)
    #     self.seq_task_do.timing.cfg_samp_clk_timing(rate = self.rate_do, source = self.clk_channel_do, samps_per_chan = num_samp)    #rate, samps_per_chan

    #     self.seq_task_do.write(sequence_bytes, auto_start = False, timeout = -1)

    # @setting(22, raw_sequence_json = 's')
    # def write_clk_raw_sequence(self, c, raw_sequence_json):
    #     """
    #     We use port0/line0 on AI card as the "Variable Clock Reference" to sample the DO and AO card.
    #     Input at this point is json.dump(raw_sequence).
    #     """
    #     raw_sequence = json.loads(raw_sequence_json)

    #     sequence_bytes = make_sequence_bytes_clk(raw_sequence)

    #     t1 = time.time()

    #     num_samp = len(sequence_bytes)
    #     if self.seq_task_clk: # Make sure task is close before you add new stuffs.
    #         self.seq_task_clk.close()

    #     self.seq_task_clk = nidaqmx.Task()
    #     self.seq_task_clk.do_channels.add_do_chan('Dev0/port0/line0')

    #     self.seq_task_clk.timing.cfg_samp_clk_timing(rate = self.rate_clk, source = self.source, samps_per_chan = num_samp)    #rate, samps_per_chan

    #     self.seq_task_clk.write(sequence_bytes, auto_start = False, timeout = -1)

    #     print('DAQ ', time.time() - t1)

    @setting(20, raw_sequence_channels_list_json='s')
    def write_ao_raw_sequence(self, c, raw_sequence_channels_list_json):
        """
        NOT all AO channels are written for now, we select channels by the length of sequence, in principle it should be >2.
        
        This function works for analog stream out where sequence input are in 2D, number_of_ports rows, float element array, like [[x, x,..., x], ...],
        where -10.0 <= x <= 10.0.
        Each row corresponds to a channel in the task. Each column corresponds to a sample to write to each channel.
        """
        raw_sequence_channels_list = json.loads(
            raw_sequence_channels_list_json)
        sequence_bytes = make_sequence_bytes_ao(raw_sequence_channels_list)

        num_port = len(sequence_bytes)
        num_samp = len(sequence_bytes[0])

        if self.seq_task_ao:  # Make sure task is close before you add new stuffs.
            self.seq_task_ao.close()

        self.seq_task_ao = nidaqmx.Task()
        self.seq_task_ao.ao_channels.add_ao_voltage_chan(
            'Dev2/ao0:{}'.format(num_port - 1))
        self.seq_task_ao.timing.cfg_samp_clk_timing(
            rate=self.rate_ao,
            source=self.clk_channel_ao,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.writer_ao = AnalogMultiChannelWriter(
            self.seq_task_ao.out_stream, auto_start=False
        )  # use multi-channel writer, so input is 2D array.
        self.writer_ao.write_many_sample(sequence_bytes, timeout=-1)

    @setting(21, raw_sequence_json='s', channels_list_json='s')
    def write_do_raw_sequence(self, c, raw_sequence_json, channels_list_json):
        """
        We write all 32 DO channels together at the time where one of the channel output changes.
        We group 8 lines from each port as a channel, so the input should have 4 rows.
        
        This function works for digital stream out where sequence input are in 2D, 32 rows, 8 bit NumPy array, like [[x, x,..., x], ...], where 0 <= x < 2^8.
        Each row corresponds to a channel in the task. Each column corresponds to a sample to write to each channel.
        Here 0 stands for all off. 1 stands for the first channel on, with 100..0, and so on.
        The elements can be calculated using "element += out_list[i]*2**j for j in range(len(channel))".
        Each element should be in "dtype = numpy.uint8".
        """
        raw_sequence = json.loads(raw_sequence_json)
        channels_list = json.loads(channels_list_json)
        sequence_bytes = make_sequence_bytes_do(raw_sequence, channels_list)

        num_samp = len(sequence_bytes[0])

        if self.seq_task_do:  # Make sure task is close before you add new stuffs.
            self.seq_task_do.close()

        self.seq_task_do = nidaqmx.Task()
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port0/line0:7',
            line_grouping=LineGrouping.CHAN_FOR_ALL_LINES)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port1/line0:7',
            line_grouping=LineGrouping.CHAN_FOR_ALL_LINES)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port2/line0:7',
            line_grouping=LineGrouping.CHAN_FOR_ALL_LINES)
        self.seq_task_do.do_channels.add_do_chan(
            'Dev1/port3/line0:7',
            line_grouping=LineGrouping.CHAN_FOR_ALL_LINES)
        self.seq_task_do.timing.cfg_samp_clk_timing(
            rate=self.rate_do,
            source=self.clk_channel_do,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.writer_do = DigitalMultiChannelWriter(
            self.seq_task_do.out_stream, auto_start=False
        )  # use multi-channel writer, so input is 2D array.
        self.writer_do.write_many_sample_port_byte(sequence_bytes, timeout=-1)

    @setting(22, raw_sequence_json='s')
    def write_clk_raw_sequence(self, c, raw_sequence_json):
        """
        We use port0/line0 on AI card as the "Variable Clock Reference" to sample the DO and AO card.
        Input at this point is json.dump(raw_sequence). 
        This function works for digital stream out where sequence input are in 1D, 8 bit NumPy array, like [1010...].
        Each element represents on (1) and off (0), and should be in "dtype = numpy.uint8".
        """
        raw_sequence = json.loads(raw_sequence_json)

        sequence_bytes = make_sequence_bytes_clk(raw_sequence)

        # t1 = time.time()

        num_samp = len(sequence_bytes)
        if self.seq_task_clk:  # Make sure task is close before you add new stuffs.
            self.seq_task_clk.close()

        self.seq_task_clk = nidaqmx.Task()
        self.seq_task_clk.do_channels.add_do_chan(
            'Dev0/port0/line0', line_grouping=LineGrouping.CHAN_PER_LINE)
        self.seq_task_clk.timing.cfg_samp_clk_timing(
            rate=self.rate_clk, source=self.source,
            samps_per_chan=num_samp)  #rate, samps_per_chan

        self.writer_clk = DigitalSingleChannelWriter(
            self.seq_task_clk.out_stream, auto_start=False)
        self.writer_clk.write_many_sample_port_byte(sequence_bytes, timeout=-1)
コード例 #20
0
class IOTaskNidaq(BaseTask):
    # This is only nidaq for now.
    def __init__(self, channels, modes):
        '''
        IOTask for using nidaqmx cards on Windows.
        '''
        super(IOTaskNidaq, self).__init__(channels, modes)
        self.buff_dtype = np.float64

    def _create_tasks(self):
        if self.n_output_chan:
            for ichan in self.output_chan_index:
                dev = self.chaninfo[ichan]['device']
                if 'ni:' in dev:
                    dev = dev.strip('ni:')
                    chanstr = dev + '/' + self.chaninfo[ichan]['channel']
                    if self.task_ao is None:
                        self.task_ao = nidaqmx.Task()
                    if not 'range' in self.chaninfo[ichan].keys():
                        self.chaninfo[ichan]['range'] = [-10, 10]
                    self.task_ao.ao_channels.add_ao_voltage_chan(
                        chanstr,
                        min_val=self.chaninfo[ichan]['range'][0],
                        max_val=self.chaninfo[ichan]['range'][1])
                    self.task_ao_modes.append(self.chaninfo[ichan]['modes'][0])
                    if 'acq_rate' in self.chaninfo[ichan].keys():
                        self.srate = self.chaninfo[ichan]['acq_rate']
        if len(self.digioutput_chan_index):
            for ichan in self.digioutput_chan_index:
                dev = self.chaninfo[ichan]['device']
                if 'ni:' in dev:
                    dev = dev.strip('ni:')
                chanstr = dev + '/' + self.chaninfo[ichan]['channel']
                if self.task_do is None:
                    self.task_do = nidaqmx.Task()
                self.task_do.do_channels.add_do_chan(
                    chanstr,
                    line_grouping=nidaqmx.constants.LineGrouping.
                    CHAN_FOR_ALL_LINES)
                self.task_do_modes.append(self.chaninfo[ichan]['modes'][0])
        if self.n_input_chan:
            for ichan in self.input_chan_index:
                dev = self.chaninfo[ichan]['device']
                if 'ni:' in dev:
                    dev = dev.strip('ni:')
                    chanstr = dev + '/' + self.chaninfo[ichan]['channel']
                    if self.task_ai is None:
                        self.task_ai = nidaqmx.Task()
                    if not 'range' in self.chaninfo[ichan].keys():
                        self.chaninfo[ichan]['range'] = [-10, 10]
                    self.task_ai.ai_channels.add_ai_voltage_chan(
                        chanstr,
                        min_val=self.chaninfo[ichan]['range'][0],
                        max_val=self.chaninfo[ichan]['range'][1])
                    self.task_ai_modes.append(self.chaninfo[ichan]['modes'][0])
                    if 'acq_rate' in self.chaninfo[ichan].keys():
                        self.srate = self.chaninfo[ichan]['acq_rate']
        # uses the device of the first channel.
        # this part needs to be better specified to make it more general.
        dev = self.chaninfo[0]['device']
        if 'ni:' in dev:
            dev = dev.strip('ni:')
        self.task_clock = nidaqmx.Task()
        self.task_clock.co_channels.add_co_pulse_chan_freq(dev + '/ctr0',
                                                           freq=self.srate)
        self.samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(dev)
        # This should probably be on an independent function.
        if len(self.axon200B_mode):
            ichan = self.axon200B_mode[0]
            dev = self.chaninfo[ichan]['device']
            if 'ni:' in dev:
                dev = dev.strip('ni:')
                chanstr = dev + '/' + self.chaninfo[ichan]['channel']
                if not hasattr(self, 'task_axon200B_mode'):
                    self.task_axon200B_mode = nidaqmx.Task()
                if not 'range' in self.chaninfo[ichan].keys():
                    self.chaninfo[ichan]['range'] = [-10, 10]
                self.task_axon200B_mode.ai_channels.add_ai_voltage_chan(
                    chanstr,
                    min_val=self.chaninfo[ichan]['range'][0],
                    max_val=self.chaninfo[ichan]['range'][1])

    def load(self, stim, digstim=None, use_ao_trigger=False):
        # check if the modes are up to date
        assert type(stim) is list, 'Stim needs to be a list of numpy arrays'
        self._check_modes()
        self.nsamples = int(
            np.max([np.max(s.shape) for s in stim if not s is None]))
        aoconversion = self._get_conversion(False)

        if not self.task_ai is None and self.task_ao is None:
            self.task_ai.timing.cfg_samp_clk_timing(
                rate=self.srate, samps_per_chan=self.nsamples)

        if not self.task_ao is None:
            self.task_ao.timing.cfg_samp_clk_timing(
                rate=self.srate, samps_per_chan=self.nsamples)
            self.task_ao.export_signals.export_signal(
                nidaqmx.constants.Signal.SAMPLE_CLOCK, 'PFI0')
            if not self.task_ai is None:
                if use_ao_trigger:
                    self.task_ai.triggers.start_trigger.cfg_dig_edge_start_trig(
                        'ao/StartTrigger')

                    self.task_ai.timing.cfg_samp_clk_timing(
                        rate=self.srate,
                        source='PFI0',
                        samps_per_chan=self.nsamples)

            # Take care of the conversions
            stims = np.zeros((self.n_output_chan, self.nsamples),
                             dtype=np.float64)
            # Fix the analog output conversions
            for i in range(self.n_output_chan):
                if i < len(stim):
                    if stim[i] is None:
                        continue
                    if not len(stim[i]):
                        continue
                    stims[i] = stim[i] * aoconversion[i]

            if hasattr(self, 'task_clock'):
                self.task_clock.timing.cfg_implicit_timing(
                    samps_per_chan=self.nsamples)

                if not self.task_ao is None:
                    self.task_ao.timing.cfg_samp_clk_timing(
                        self.srate,
                        source=self.samp_clk_terminal,
                        active_edge=nidaqmx.constants.Edge.RISING,
                        samps_per_chan=self.nsamples)
                if not self.task_ai is None:
                    self.task_ai.timing.cfg_samp_clk_timing(
                        self.srate,
                        source=self.samp_clk_terminal,
                        active_edge=nidaqmx.constants.Edge.FALLING,
                        samps_per_chan=self.nsamples)

            self.writer = AnalogMultiChannelWriter(self.task_ao.out_stream)
            self.reader = AnalogMultiChannelReader(self.task_ai.in_stream)
            self.writer.write_many_sample(stims)

        self.run_do = False
        if not digstim is None:
            if not self.task_do is None:
                self.task_do.timing.cfg_samp_clk_timing(
                    rate=self.srate,
                    source=self.samp_clk_terminal,
                    active_edge=nidaqmx.constants.Edge.RISING,
                    samps_per_chan=self.nsamples)
                #this works for 32 bit ports only, all iputs must be on the same port for now.
                digstims = np.zeros((self.nsamples, 32), dtype=np.uint32)
                for i in range(len(digstim)):
                    if digstim[i] is None:
                        continue
                    if not len(digstim[i]):
                        continue
                    digstims[:, i] = (digstim[i] > 0)
                self.di_writer = DigitalMultiChannelWriter(
                    self.task_do.out_stream)
                self.di_writer.write_many_sample_port_uint32(
                    np.packbits(digstims, bitorder='little').reshape(
                        (1, -1)).view(np.uint32))
                self.run_do = True
        self.acquired = False

    def _run(self, blocking=True):
        #self.task_ao.ao_channels.all.ao_dac_ref_allow_conn_to_gnd = True
        if not self.task_ai is None:
            self.task_ai.start()
        if self.run_do:
            self.task_do.start()
        if not self.task_ao is None:
            self.task_ao.start()
        if not self.task_clock is None:
            self.task_clock.start()
        #self.task_ao.ao_channels.all.ao_dac_ref_conn_to_gnd = False
        if blocking:
            self.reader.read_many_sample(
                self.data,
                number_of_samples_per_channel=self.nsamples,
                timeout=self.nsamples / self.srate + 1)
            self.data = self.data * aiconversion
            self.ibuff = self.nsamples
            self._clean_run()
            return self.data
        else:

            def run_thread():
                self.reader.read_all_avail_samp = True
                buffer = np.zeros((self.n_input_chan, 1000), dtype=np.float64)
                while not self.ibuff == self.nsamples:
                    nsamples = self.reader.read_many_sample(
                        buffer, number_of_samples_per_channel=1000, timeout=1)
                    self.data[:, self.ibuff:self.ibuff +
                              nsamples] = buffer[:, :nsamples] * aiconversion
                    self.ibuff += int(nsamples)
                self._clean_run()

            self.thread_task = threading.Thread(target=run_thread)
            self.thread_task.start()
            return None

    def _clean_run(self):
        self.task_clock.wait_until_done()
        self.task_clock.stop()

        if not self.task_ai is None:
            self.task_ai.wait_until_done()
            self.task_ai.stop()
        if not self.task_ao is None:
            self.task_ao.wait_until_done()
            self.task_ao.stop()
        if self.run_do:
            self.task_do.wait_until_done()
            self.task_do.stop()
        self.acquired = True

    def _get_axon200B_mode(self):
        mm = int(np.round(self.task_axon200B_mode.read()))
        if mm in [2, 1]:
            self.mode = 'cc'
        elif mm == 3:
            self.mode = 'cc=0'
        elif mm in [4, 6]:
            self.mode = 'vc'

    def close(self):
        self.task_ai.close()
        self.task_ao.close()
        self.task_do.close()
        self.task_clock.close()
コード例 #21
0
ファイル: test.py プロジェクト: yzerlaut/physion
                                               min_val=-10)
    write_task.timing.cfg_samp_clk_timing(sample_rate,
                                          source=samp_clk_terminal,
                                          active_edge=Edge.RISING,
                                          samps_per_chan=number_of_samples)

    read_task.ai_channels.add_ai_voltage_chan(flatten_channel_string(
        [c.input_channel for c in channels_to_test]),
                                              max_val=10,
                                              min_val=-10)
    read_task.timing.cfg_samp_clk_timing(sample_rate,
                                         source=samp_clk_terminal,
                                         active_edge=Edge.FALLING,
                                         samps_per_chan=number_of_samples)

    writer = AnalogMultiChannelWriter(write_task.out_stream)
    reader = AnalogMultiChannelReader(read_task.in_stream)

    values_to_test = np.array([waveform for _ in range(number_of_channels)],
                              dtype=np.float64)
    writer.write_many_sample(values_to_test)

    # Start the read and write tasks before starting the sample clock
    # source task.
    read_task.start()
    write_task.start()
    sample_clk_task.start()

    values_read = np.zeros((number_of_channels, number_of_samples),
                           dtype=np.float64)
コード例 #22
0
def momi(signal, fs, aolist, ailist, rangeval, numsamprec, savedirname=None):
    """Perform multiple output voltage transmission and multiple input voltage reception. The recorded data is a 2-D array which each row consists of a channel recording. The implementation is referred to test_read_write.py from nidaqmx.
    
    :params signal: transmitted signals
    :params fs: sampling rate 
    :params aolist: list of analog output channel name
    :params ailist: list of analog input channel name
    :params rangeval: list contains minimum and maximum amplitude values of the transmitted and received signals
    :params numsamprec: number of recording samples 
    :params savedirname: directory and filename to save the recording (None means do not save)
    :params returns: 2-D array with the last column as the reference signal and others as the recorded data
    """
    system = nidaqmx.system.System.local()
    devicename = system.devices[0].name
    outputchannel = [devicename + '/' + ao for ao in aolist]
    inputchannel = [devicename + '/' + ai for ai in ailist]
    numoutputchannel = len(outputchannel)
    numinputchannel = len(inputchannel)

    numsignal, numsamptrans = signal.shape
    if numsignal != numoutputchannel:
        raise ValueError('dimension mismatch')
    if numsamptrans > numsamprec:
        print(
            "Number of samples of the transmitted signals is greater than the recordings."
        )
    print("Device name: {}".format(devicename))
    print("Output channel: {}".format(outputchannel))
    print("Input channel: {}".format(inputchannel))

    minval, maxval = rangeval
    numsampclk = max(numsamptrans, numsamprec)
    timeout = _np.ceil(numsamprec / fs)
    with nidaqmx.Task() as write_task, nidaqmx.Task(
    ) as read_task, nidaqmx.Task() as sample_clk_task:
        sample_clk_task.co_channels.add_co_pulse_chan_freq(
            '{0}/ctr0'.format(devicename), freq=fs)
        sample_clk_task.timing.cfg_implicit_timing(samps_per_chan=numsampclk)

        samp_clk_terminal = '/{0}/Ctr0InternalOutput'.format(devicename)

        write_task.ao_channels.add_ao_voltage_chan(
            flatten_channel_string(outputchannel),
            max_val=maxval,
            min_val=minval)
        write_task.timing.cfg_samp_clk_timing(fs,
                                              source=samp_clk_terminal,
                                              active_edge=Edge.RISING,
                                              samps_per_chan=numsamptrans)

        read_task.ai_channels.add_ai_voltage_chan(
            flatten_channel_string(inputchannel),
            max_val=maxval,
            min_val=minval,
            terminal_config=TerminalConfiguration.RSE)
        read_task.timing.cfg_samp_clk_timing(fs,
                                             source=samp_clk_terminal,
                                             active_edge=Edge.FALLING,
                                             samps_per_chan=numsamprec)

        writer = AnalogMultiChannelWriter(write_task.out_stream)
        reader = AnalogMultiChannelReader(read_task.in_stream)

        writer.write_many_sample(signal)

        read_task.start()
        write_task.start()
        sample_clk_task.start()

        data = _np.zeros((numinputchannel, numsamprec), dtype=_np.float64)
        reader.read_many_sample(data,
                                number_of_samples_per_channel=numsamprec,
                                timeout=timeout)

        if savedirname is not None:
            if _os.path.isfile('.'.join([savedirname, 'npy'])):
                print('The file exists. The current data has not been saved.')
            else:
                _np.save(savedirname, data)
        return data