使用nidaqmx python包从国家仪器DAQ连续读取模拟量
受问题答案的启发,我尝试了以下代码:使用nidaqmx python包从国家仪器DAQ连续读取模拟量,python,data-acquisition,nidaqmx,daq-mx,Python,Data Acquisition,Nidaqmx,Daq Mx,受问题答案的启发,我尝试了以下代码: import nidaqmx from nidaqmx import stream_readers from nidaqmx import constants import time sfreq = 1000 bufsize = 100 data = np.zeros((1, 1), dtype = np.float32) # initializes total data file with nidaqmx.Task() as task: t
import nidaqmx
from nidaqmx import stream_readers
from nidaqmx import constants
import time
sfreq = 1000
bufsize = 100
data = np.zeros((1, 1), dtype = np.float32) # initializes total data file
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1")
task.timing.cfg_samp_clk_timing(rate = sfreq, sample_mode = constants.AcquisitionType.CONTINUOUS,
samps_per_chan = bufsize) # unclear samps_per_chan is needed or why it would be different than bufsize
stream = stream_readers.AnalogMultiChannelReader(task.in_stream)
def reading_task_callback(task_id, event_type, num_samples, callback_data=None): # num_samples is set to bufsize
buffer = np.zeros((1, num_samples), dtype = np.float32) # probably better to define it here inside the callback
stream.read_many_sample(buffer, num_samples, timeout = constants.WAIT_INFINITELY)
data = np.append(data, buffer, axis = 1) # hopping to retrieve this data after the read is stopped
task.register_every_n_samples_acquired_into_buffer_event(bufsize, reading_task_callback)
预期行为:它从通道连续读取。我甚至不想让它做一些特定的事情(比如实时绘图),但我希望python控制台一直运行到停止为止,因为它的目标是持续阅读
观察到的行为:运行此代码将快速进行,并返回控制台提示
问题:在我看来,这根本不是持续阅读。此外,数据
变量没有像我希望的那样追加(我知道检索一定数量的数据样本不需要使用nidaqmx进行如此复杂的编码;这只是我认为可以尝试的一种方法,看看这是否符合我的要求,即连续读取并不断地将缓冲样本值附加到数据
,这样我就可以查看总的数据
采集教育部)
任何帮助都将不胜感激。我基本上确信实现这一点的方法是通过使用这些作为nidaqmx一部分的回调,但不知何故,我似乎没有很好地管理它们。注意,我已经能够通过使用read\u many\u sample
从模拟输入通道读取预定义和有限数量的数据样本
详细信息:NI cDAQ 9178,插入NI 9205模块,安装在运行Windows Home 10、python 3.7和用于python的nidaqmx软件包的联想笔记本电脑上
编辑:对于任何感兴趣的人,我现在可以通过以下方式进行操作,使用matplotlib进行实时视觉反馈,并且-还不是100%确定-即使目标是长时间采集(>10分钟),也似乎没有缓冲区问题。下面是代码(未清理,抱歉):
当然,欢迎您发表评论。这可能还不够理想。我不太了解nidaqmx,但看看代码,我感觉您是在创建任务而没有运行它。我希望使用另一个命令,如task.exec()或task.wait().Aouch,你当然是对的。对不起,我没有太多使用像这样的高级Python包的经验(我发现它也是一个文档非常贫乏的包)。谢谢,这有助于我获得不同的错误,这就是进步!你解决了你的问题@Gustavo Lucena Gómez吗?我也遇到了同样的问题…当然,至少在第一个近似值中,问题是这样的(愚蠢的我)我甚至没有开始这项任务。请看上面@Marco的回复!现在我收到了大量的缓冲区错误,我正在尝试让它连续、顺利地读取,没有错误或警告,并不时保存数据。事实上,这将在下周的整个周内完成。
"""
Analog data acquisition for QuSpin's OPMs via National Instruments' cDAQ unit
The following assumes:
"""
# Imports
import matplotlib.pyplot as plt
import numpy as np
import nidaqmx
from nidaqmx.stream_readers import AnalogMultiChannelReader
from nidaqmx import constants
# from nidaqmx import stream_readers # not needed in this script
# from nidaqmx import stream_writers # not needed in this script
import threading
import pickle
from datetime import datetime
import scipy.io
# Parameters
sampling_freq_in = 1000 # in Hz
buffer_in_size = 100
bufsize_callback = buffer_in_size
buffer_in_size_cfg = round(buffer_in_size * 1) # clock configuration
chans_in = 3 # set to number of active OPMs (x2 if By and Bz are used, but that is not recommended)
refresh_rate_plot = 10 # in Hz
crop = 10 # number of seconds to drop at acquisition start before saving
my_filename = 'test_3_opms' # with full path if target folder different from current folder (do not leave trailing /)
# Initialize data placeholders
buffer_in = np.zeros((chans_in, buffer_in_size))
data = np.zeros((chans_in, 1)) # will contain a first column with zeros but that's fine
# Definitions of basic functions
def ask_user():
global running
input("Press ENTER/RETURN to stop acquisition and coil drivers.")
running = False
def cfg_read_task(acquisition): # uses above parameters
acquisition.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1:3") # has to match with chans_in
acquisition.timing.cfg_samp_clk_timing(rate=sampling_freq_in, sample_mode=constants.AcquisitionType.CONTINUOUS,
samps_per_chan=buffer_in_size_cfg)
def reading_task_callback(task_idx, event_type, num_samples, callback_data): # bufsize_callback is passed to num_samples
global data
global buffer_in
if running:
# It may be wiser to read slightly more than num_samples here, to make sure one does not miss any sample,
# see: https://documentation.help/NI-DAQmx-Key-Concepts/contCAcqGen.html
buffer_in = np.zeros((chans_in, num_samples)) # double definition ???
stream_in.read_many_sample(buffer_in, num_samples, timeout=constants.WAIT_INFINITELY)
data = np.append(data, buffer_in, axis=1) # appends buffered data to total variable data
return 0 # Absolutely needed for this callback to be well defined (see nidaqmx doc).
# Configure and setup the tasks
task_in = nidaqmx.Task()
cfg_read_task(task_in)
stream_in = AnalogMultiChannelReader(task_in.in_stream)
task_in.register_every_n_samples_acquired_into_buffer_event(bufsize_callback, reading_task_callback)
# Start threading to prompt user to stop
thread_user = threading.Thread(target=ask_user)
thread_user.start()
# Main loop
running = True
time_start = datetime.now()
task_in.start()
# Plot a visual feedback for the user's mental health
f, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex='all', sharey='none')
while running: # make this adapt to number of channels automatically
ax1.clear()
ax2.clear()
ax3.clear()
ax1.plot(data[0, -sampling_freq_in * 5:].T) # 5 seconds rolling window
ax2.plot(data[1, -sampling_freq_in * 5:].T)
ax3.plot(data[2, -sampling_freq_in * 5:].T)
# Label and axis formatting
ax3.set_xlabel('time [s]')
ax1.set_ylabel('voltage [V]')
ax2.set_ylabel('voltage [V]')
ax3.set_ylabel('voltage [V]')
xticks = np.arange(0, data[0, -sampling_freq_in * 5:].size, sampling_freq_in)
xticklabels = np.arange(0, xticks.size, 1)
ax3.set_xticks(xticks)
ax3.set_xticklabels(xticklabels)
plt.pause(1/refresh_rate_plot) # required for dynamic plot to work (if too low, nulling performance bad)
# Close task to clear connection once done
task_in.close()
duration = datetime.now() - time_start
# Final save data and metadata ... first in python reloadable format:
filename = my_filename
with open(filename, 'wb') as f:
pickle.dump(data, f)
'''
Load this variable back with:
with open(name, 'rb') as f:
data_reloaded = pickle.load(f)
'''
# Human-readable text file:
extension = '.txt'
np.set_printoptions(threshold=np.inf, linewidth=np.inf) # turn off summarization, line-wrapping
with open(filename + extension, 'w') as f:
f.write(np.array2string(data.T, separator=', ')) # improve precision here!
# Now in matlab:
extension = '.mat'
scipy.io.savemat(filename + extension, {'data':data})
# Some messages at the end
num_samples_acquired = data[0,:].size
print("\n")
print("OPM acquisition ended.\n")
print("Acquisition duration: {}.".format(duration))
print("Acquired samples: {}.".format(num_samples_acquired - 1))
# Final plot of whole time course the acquisition
plt.close('all')
f_tot, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex='all', sharey='none')
ax1.plot(data[0, 10:].T) # note the exclusion of the first 10 iterations (automatically zoomed in plot)
ax2.plot(data[1, 10:].T)
ax3.plot(data[2, 10:].T)
# Label formatting ...
ax3.set_xlabel('time [s]')
ax1.set_ylabel('voltage [V]')
ax2.set_ylabel('voltage [V]')
ax3.set_ylabel('voltage [V]')
xticks = np.arange(0, data[0, :].size, sampling_freq_in)
xticklabels = np.arange(0, xticks.size, 1)
ax3.set_xticks(xticks)
ax3.set_xticklabels(xticklabels)
plt.show()