Jump to content
  • 0

Error 24: Invalid Sampling Rate


trent r

Question

I am using a USB-2416-4AO with AI-EXP32 expansion board and am getting an Error 24: Invalid Sampling Rate. This code works properly using on other DAQ / PC pairs so there must be something wrong with my setup. The DAQ is using the latest firmware (2.03). A colleague recalls seeing something similar when the DAQ came back from calibration and was still in some "calibration" configuration rather than its normal state but does not recall the details - could this be the cause here? Any other suggestions?

 

board_num = 0
dout_low_chan = 0
dout_high_chan = 0
dout_total_count = 10240
dout_rate = 1000
dout_ao_range = ULRange.BIP10VOLTS
dout_memhandle = ul.win_buf_alloc(10240)
dout_scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS)

low_chan = 0
high_chan = 1
ul_buffer_count = 3300
rate = 550
ai_range = ULRange.BIP10VOLTS
memhandle = ul.scaled_win_buf_alloc(3300)
scan_options = (ScanOptions.BLOCKIO | ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS | ScanOptions.SCALEDATA)

chan_array = [0,23]
gain_array = [ULRange.BIP10VOLTS,ULRange.BIP10VOLTS]

ul.a_out_scan(board_num, dout_low_chan, dout_high_chan, dout_total_count, dout_rate, dout_ao_range, dout_memhandle, dout_scan_options)
ul.a_load_queue(board_num, chan_array, gain_array, len(chan_array))
ul.a_in_scan(board_num, low_chan, high_chan, ul_buffer_count, rate, ai_range, memhandle, scan_options) # Running this line results in Error 24

 

Link to comment
Share on other sites

3 answers to this question

Recommended Posts

  • 0

Could you jump into InstaCal and check how channel 0 is configured and how the Data Rate filter property is set? It must be set to 3750 to sample at 550 samples per second. Page 16 in the user manual discusses throughput rates.

Another thing to keep in mind is that the USB-2416-4AO is a device that remembers how it is set even after power is removed. Not all MCC devices do this. So, if a colleague sets it for temperature and you try to use it for voltage, it will generate an error until it is reconfigured with InstaCal.

Link to comment
Share on other sites

  • 0
14 minutes ago, JRys said:

Could you jump into InstaCal and check how channel 0 is configured and how the Data Rate filter property is set? It must be set to 3750 to sample at 550 samples per second. Page 16 in the user manual discusses throughput rates.

Another thing to keep in mind is that the USB-2416-4AO is a device that remembers how it is set even after power is removed. Not all MCC devices do this. So, if a colleague sets it for temperature and you try to use it for voltage, it will generate an error until it is reconfigured with InstaCal.

Oh interesting!  We should be calling ul.ignore_instacal() before setting up the DAQ (which I forgot to include in my stub code - my bad on that! The full code is located below). Changing Ch23's rate to 3750 in InstaCal did resolve it, despite the call to ul.ignore_instacal(). Thanks for the help!

 

from __future__ import absolute_import, division, print_function
from _ctypes import POINTER, addressof, sizeof
from ctypes import c_double, cast

import math
import time
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as signal

from builtins import *  # @UnusedWildImport

from mcculw import ul
from mcculw.enums import ULRange, InfoType, BoardInfo, AiChanType, AnalogInputMode, ScanOptions, FunctionType, InterfaceType, Status, DigitalPortType
from examples.console import util
from examples.props.ao import AnalogOutputProps
from examples.props.ai import AnalogInputProps
from mcculw.ul import ULError

try:
    ul.ignore_instacal()
    device = ul.get_daq_device_inventory(InterfaceType.ANY)[0]
    board_num = 0
    ul.create_daq_device(board_num, device)
    
    dout_low_chan = 0
    dout_high_chan = 0
    dout_total_count = 10240
    dout_rate = 1000
    dout_ao_range = ULRange.BIP10VOLTS
    dout_memhandle = ul.win_buf_alloc(10240)
    dout_scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS)

    low_chan = 0
    high_chan = 1
    ul_buffer_count = 3300
    rate = 550
    ai_range = ULRange.BIP10VOLTS
    memhandle = ul.scaled_win_buf_alloc(3300)
    scan_options = (ScanOptions.BLOCKIO | ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS | ScanOptions.SCALEDATA)


    chan_array = [0,23]
    gain_array = [ULRange.BIP10VOLTS,ULRange.BIP10VOLTS]

    ul.a_out_scan(board_num, dout_low_chan, dout_high_chan, dout_total_count, dout_rate, dout_ao_range, dout_memhandle, dout_scan_options)
    ul.a_load_queue(board_num, chan_array, gain_array, len(chan_array))
    
    ul.a_in_scan(board_num, low_chan, high_chan, ul_buffer_count, rate, ai_range, memhandle, scan_options)
finally:
    ul.stop_background(board_num, FunctionType.AOFUNCTION)
    ul.stop_background(board_num, FunctionType.AIFUNCTION)
    ul.win_buf_free(dout_memhandle)
    ul.win_buf_free(memhandle)

 

Link to comment
Share on other sites

  • 0

The following program generates a ~10 Hz sine wave on analog output 0 with an update rate of 1000 S/s. It also captures data on the analog input channel 0 at 500 S/s. I have also tested it at 1100, which is the max. You should be able to use two channels at 550 S/s. The config(board_num, num_chans) function performs the setting normally done by InstaCal. Attached below is the file.

from __future__ import absolute_import, division, print_function

import time

from builtins import *  # @UnusedWildImport
from ctypes import addressof, sizeof, cast, POINTER, c_double, c_ushort

from math import pi, sin
from time import sleep

from mcculw import ul
from mcculw.enums import (AiChanType, BoardInfo, Status, InterfaceType,
                          FunctionType, InfoType, ScanOptions,
                          ULRange, AnalogInputMode)

use_device_detection = True
packet_size = 32


def config(board_num: int, n_channels: int):
    for ch in range(n_channels):
        ul.set_config(
            InfoType.BOARDINFO, board_num, ch,
            BoardInfo.ADCHANTYPE, AiChanType.VOLTAGE
        )
        # ul.set_config(
        #    InfoType.BOARDINFO, board_num, ch,
        #    BoardInfo.CHANTCTYPE, TcType.K
        # )

        ul.set_config(
            InfoType.BOARDINFO, board_num, ch,
            BoardInfo.ADDATARATE, 3750
        )


def run_example():

    

    dev_id_list = []
    board_num = 0
    desired_rate = 512
    actual_rate = 0
    desired_out_rate = 1000
    actual_out_rate = 0
    file_name = 'scan_data.csv'
    memhandle = None

    # The size of the UL buffer to create, in seconds
    buffer_size_seconds = 2
    # The number of buffers to write. After this number of UL buffers are
    # written to file, the example will be stopped.
    num_buffers_to_write = 5

    board_num = 0
    board_index = 0
    find_device = "USB-2416-4AO"
    if use_device_detection:
        board_num = -1
        ul.ignore_instacal()
        dev_list = ul.get_daq_device_inventory(InterfaceType.USB)
        if len(dev_list) > 0:
            for device in dev_list:
                if str(device) == find_device:
                    print(f"Found {find_device} board number = {board_index}")
                    print(f"Serial number: {device.unique_id}")
                    print(f"Product type: {hex(device.product_id)}")
                    board_num = board_index
                    ul.create_daq_device(board_num, device)
                board_index = board_index + 1
            if board_num == -1:
                print(f"Device {find_device} not found")
                return
        else:
            print("No devices detected")
            return
    # **********End of Discovery************

    try:

        chan = 0
        num_chans = 1
        config(board_num, num_chans)
        ul.a_chan_input_mode(board_num, chan, AnalogInputMode.SINGLE_ENDED)

        # Create a circular buffer that can hold buffer_size_seconds worth of
        # data, or at least 10 points (this may need to be adjusted to prevent
        # a buffer overrun)
        points_per_channel = max(desired_rate * buffer_size_seconds, 10)
        ul_buffer_count = points_per_channel * num_chans

        # Write the UL buffer to the file num_buffers_to_write times.
        points_to_write = ul_buffer_count * num_buffers_to_write

        # When handling the buffer, we will read 1/10 of the buffer at a time
        write_chunk_size = int(ul_buffer_count / 10)

        scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS |
                        ScanOptions.SCALEDATA)

        memhandle = ul.scaled_win_buf_alloc(ul_buffer_count)

        # Allocate an array of doubles temporary storage of the data
        write_chunk_array = (c_double * write_chunk_size)()

        # Check if the buffer was successfully allocated
        if not memhandle:
            raise Exception('Failed to allocate memory')

        # set output to zero
        zero_volts = 0.0
        ul.v_out(board_num, 0, ULRange.BIP10VOLTS, zero_volts, 0)

        # Allocate a buffer for the scan
        count = 1024
        memhandle2 = ul.win_buf_alloc(count)

        # Convert the memhandle to a ctypes array
        # Note: the ctypes array will no longer be valid after win_buf_free
        # is called.
        # A copy of the buffer can be created using win_buf_to_array
        # before the memory is freed. The copy can be used at any time.
        ctypes_array = cast(memhandle2, POINTER(c_ushort))

        # Check if the buffer was successfully allocated
        if not memhandle2:
            raise Exception('Error: Failed to allocate memory')

        frequencies = add_example_data(board_num, ctypes_array, ULRange.BIP10VOLTS,
                                       num_chans, desired_out_rate, count)

        print("Channel", chan, 'Output Signal Frequency:', frequencies[chan])

        # Start single channel output scan
        actual_out_rate = ul.a_out_scan(board_num,
                                        chan, chan,
                                        count,
                                        desired_out_rate,
                                        ULRange.BIP10VOLTS,
                                        memhandle2,
                                        ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS)

        print('desired output rate =: ' + str(desired_out_rate))
        print('actual output rate  =: ' + str(actual_out_rate))

        # Start the scan
        actual_rate = ul.a_in_scan(
            board_num, chan, chan, ul_buffer_count,
            desired_rate, ULRange.BIP10VOLTS, memhandle, scan_options)

        print('desired input rate =: ' + str(desired_rate))
        print('actual input rate  =: ' + str(actual_rate))

        status = Status.IDLE
        # Wait for the scan to start fully
        while status == Status.IDLE:
            status, _, _ = ul.get_status(board_num, FunctionType.AIFUNCTION)

        # Create a file for storing the data
        with open(file_name, 'w') as f:
            print('Writing data to ' + file_name, end='')

            # Write a header to the file
            for chan_num in range(chan, chan + 1):
                f.write('Channel ' + str(chan_num) + ',')
            f.write(u'\n')

            prev_count = 0
            prev_index = 0
            write_ch_num = chan
            while status != Status.IDLE:
                # Get the latest counts
                status, curr_count, _ = ul.get_status(board_num, FunctionType.AIFUNCTION)

                new_data_count = curr_count - prev_count

                # Check for a buffer overrun before copying the data, so
                # that no attempts are made to copy more than a full buffer
                # of data
                if new_data_count > ul_buffer_count:
                    # Print an error and stop writing
                    ul.stop_background(board_num, FunctionType.AIFUNCTION)
                    print('A buffer overrun occurred')
                    break

                # Check if a chunk is available
                if new_data_count > write_chunk_size:
                    wrote_chunk = True
                    # Copy the current data to a new array

                    # Check if the data wraps around the end of the UL
                    # buffer. Multiple copy operations will be required.
                    if prev_index + write_chunk_size > ul_buffer_count - 1:
                        first_chunk_size = ul_buffer_count - prev_index
                        second_chunk_size = (
                                write_chunk_size - first_chunk_size)

                        # Copy the first chunk of data to the
                        # write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, write_chunk_array, prev_index,
                            first_chunk_size)

                        # Create a pointer to the location in
                        # write_chunk_array where we want to copy the
                        # remaining data
                        second_chunk_pointer = cast(addressof(write_chunk_array)
                                                    + first_chunk_size
                                                    * sizeof(c_double),
                                                    POINTER(c_double))

                        # Copy the second chunk of data to the
                        # write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, second_chunk_pointer,
                            0, second_chunk_size)
                    else:
                        # Copy the data to the write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, write_chunk_array, prev_index,
                            write_chunk_size)

                    # Check for a buffer overrun just after copying the data
                    # from the UL buffer. This will ensure that the data was
                    # not overwritten in the UL buffer before the copy was
                    # completed. This should be done before writing to the
                    # file, so that corrupt data does not end up in it.
                    status, curr_count, _ = ul.get_status(
                        board_num, FunctionType.AIFUNCTION)
                    if curr_count - prev_count > ul_buffer_count:
                        # Print an error and stop writing
                        ul.stop_background(board_num, FunctionType.AIFUNCTION)
                        print('A buffer overrun occurred')
                        break

                    for i in range(write_chunk_size):
                        f.write(str(write_chunk_array[i]) + ',')
                        write_ch_num += 1
                        if write_ch_num == chan + 1:
                            write_ch_num = chan
                            f.write(u'\n')
                else:
                    wrote_chunk = False

                if wrote_chunk:
                    # Increment prev_count by the chunk size
                    prev_count += write_chunk_size
                    # Increment prev_index by the chunk size
                    prev_index += write_chunk_size
                    # Wrap prev_index to the size of the UL buffer
                    prev_index %= ul_buffer_count

                    if prev_count >= points_to_write:
                        break
                    print('.', end='')
                else:
                    # Wait a short amount of time for more data to be
                    # acquired.
                    sleep(0.1)
        ul.stop_background(board_num, FunctionType.AOFUNCTION)
        ul.v_out(board_num, 0, ULRange.BIP10VOLTS, zero_volts, 0)
        ul.stop_background(board_num, FunctionType.AIFUNCTION)
    except Exception as e:
        print('\n', e)
    finally:
        print('Done')
        if memhandle:
            # Free the buffer in a final block to prevent  a memory leak.
            ul.win_buf_free(memhandle)
        if use_device_detection:
            ul.release_daq_device(board_num)


def add_example_data(board_num, data_array, ao_range, num_chans, rate,
                     points_per_channel):
    # Calculate frequencies that will work well with the size of the array
    frequencies = []
    for channel_num in range(num_chans):
        frequencies.append(
            (channel_num + 1) / (points_per_channel / rate) * 10)

    # Calculate an amplitude and y-offset for the signal
    # to fill the analog output range
    amplitude = (ao_range.range_max - ao_range.range_min) / 2
    y_offset = (amplitude + ao_range.range_min) / 2

    # Fill the array with sine wave data at the calculated frequencies.
    # Note that since we are using the SCALEDATA option, the values
    # added to data_array are the actual voltage values that the device
    # will output
    data_index = 0
    for point_num in range(points_per_channel):
        for channel_num in range(num_chans):
            freq = frequencies[channel_num]
            value = amplitude * sin(2 * pi * freq * point_num / rate) + y_offset
            raw_value = ul.from_eng_units(board_num, ao_range, value)
            data_array[data_index] = raw_value

            data_index += 1

    return frequencies


if __name__ == '__main__':
    run_example()
 

a_in_scan_file_2416_py.txt

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...