`stream_readers` array shape validation is incompatible with `READ_ALL_AVAILABLE`
If you use stream_readers to read into a preallocated NumPy array with number_of_samples_per_channel=READ_ALL_AVAILABLE, the stream reader validates the NumPy array shape against the available samples per channel, which is not a predictable number.
Steps to reproduce
Install an X Series or M Series as Dev1 and run this code:
import pprint
import time
import nidaqmx
import numpy
from nidaqmx.constants import AcquisitionType
from nidaqmx.stream_readers import AnalogMultiChannelReader
pp = pprint.PrettyPrinter(indent=4)
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0:1")
task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.CONTINUOUS)
task.start()
time.sleep(100e-3)
reader = AnalogMultiChannelReader(task.in_stream)
data = numpy.zeros((2, 1000), dtype=numpy.double)
reader.read_many_sample(data, timeout=0.0)
pp.pprint(data)
Expected output
Prints array data
Actual output
The required number of samples varies from run to run but is around 100 to 110.
Traceback (most recent call last):
File "D:\dev\nidaqmx-python\examples\ai_raw.py", line 19, in <module>
reader.read_many_sample(data, timeout=0.0)
File "D:\dev\nidaqmx-python\generated\nidaqmx\stream_readers.py", line 322, in read_many_sample
self._verify_array(data, number_of_samples_per_channel, True, True)
File "D:\dev\nidaqmx-python\generated\nidaqmx\stream_readers.py", line 83, in _verify_array
raise DaqError(
nidaqmx.errors.DaqError: Read cannot be performed because the NumPy array passed into this function is not shaped correctly. You must pass in a NumPy array of the correct shape based on the number of channels in task and the number of samples per channel requested.
Shape of NumPy Array provided: (2, 1000)
Shape of NumPy Array required: (2, 105)
Task Name: _unnamedTask<0>
Hmm, good catch. We could allow for a NumPy array that is bigger than necessary since read_many_sample returns how much data is valid.
With GROUP_BY_CHANNEL, a larger array will not have the right binary layout.
- With 3 channels and 3 samples, the array has this layout:
[1,1,1,2,2,2,3,3,3] - With 3 channels and 5 samples, the array has this layout:
[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3] - Writing 3 samples to a (3, 5) array requires leaving gaps between channels:
[1,1,1,0,0,2,2,2,0,0,3,3,3,0,0]
I think this would work better if nidaqmx-python supported F_CONTIGUOUS and GROUP_BY_SCAN_NUMBER as described in https://github.com/ni/nidaqmx-python/issues/90
Then you would have:
- With 3 channels and 3 samples, the array has this layout:
[1,2,3,1,2,3,1,2,3] - With 3 channels and 5 samples, the array has this layout:
[1,2,3,1,2,3,1,2,3,1,2,3,1,2,3] - Writing 3 samples to a (3, 5) array still uses a contiguous array:
[1,2,3,1,2,3,1,2,3,0,0,0,0,0,0]
This would also behave better for partial data after read raises a timeout error. You wouldn't have to resize the array to put each channel in the right place.