NI USB-6366 DAQ基于Python的nidaqmx库实现阈值触发式有限样本采集(含预触发与后触发样本)的问题咨询
问题:使用nidaqmx采集带预触发的有限样本(NI USB-6366)
我在使用Python的nidaqmx库读取NI USB-6366 DAQ的样本时遇到困难,目标是采集总计N个样本,其中包含M个预触发样本和(N-M)个后触发样本。触发条件为信号幅值跨越设定阈值(通过手动冲击激发入射波触发,不使用DAQ的其他通道作为触发源)。当前尝试的代码如下:
def hardwareFiniteVoltage(): import nidaqmx import numpy as np import matplotlib.pyplot as plt sampleRate = 2E5 # Sample Rate in Hz secsToAcquire = 1 # Number of seconds over which to acquire data numberOfSamples = int(secsToAcquire * sampleRate) print('Acquiring %d data points' % numberOfSamples) with nidaqmx.Task('hardwareFiniteVoltage') as task: task.ai_channels.add_ai_voltage_chan('Dev1/ai0') task.timing.cfg_samp_clk_timing(sampleRate,samps_per_chan=numberOfSamples, sample_mode=nidaqmx.constants.AcquisitionType(10178)) task.triggers.reference_trigger.cfg_anlg_edge_ref_trig( 'Dev1/ai0',10000,trigger_level=0.1) task.start() data = task.read(number_of_samples_per_channel=numberOfSamples) plt.plot(data) plt.xlabel('time [samples]') plt.ylabel('voltage [V]') plt.grid() plt.show() if __name__ == '__main__': hardwareFiniteVoltage()
恳请协助排查代码问题并提供正确的实现方案。
原代码的问题分析
我帮你梳理下代码里的几个关键问题:
- 触发配置参数错误:
cfg_anlg_edge_ref_trig的第二个参数应该指定触发沿的斜率(比如上升沿/下降沿),你传入的10000是无效值,这会直接导致触发逻辑失效。 - 未设置预触发样本数:参考触发需要明确告诉DAQ要保留多少触发前的样本,否则DAQ无法区分预触发和后触发数据的比例。
- 采样模式的常量使用不规范:直接用数字
10178代替枚举nidaqmx.constants.AcquisitionType.FINITE,不仅可读性差,还容易因为版本更新出现错误。 - 触发逻辑不完整:原代码没有配置触发后的样本采集逻辑,DAQ无法知道触发后需要采集多少样本才能完成总N个样本的目标。
正确的实现方案
下面是调整后的完整代码,我会逐部分解释关键改动:
def hardwareFiniteVoltage(): import nidaqmx from nidaqmx.constants import AcquisitionType, Slope import numpy as np import matplotlib.pyplot as plt # 配置参数:根据你的需求修改 sample_rate = 200000 # 采样率(Hz) total_samples = 200000 # 总采集样本数N pretrigger_samples = 50000 # 预触发样本数M(触发前保留的样本) trigger_level = 0.1 # 触发阈值(V) trigger_slope = Slope.RISING # 触发沿:上升沿(根据你的冲击信号调整,也可以用Slope.FALLING) ai_channel = 'Dev1/ai0' print(f'采集总样本数:{total_samples},其中预触发样本:{pretrigger_samples},后触发样本:{total_samples - pretrigger_samples}') with nidaqmx.Task('pretrigger_acquisition') as task: # 添加模拟输入通道 task.ai_channels.add_ai_voltage_chan(ai_channel) # 配置采样时钟:有限采样模式,总样本数为N task.timing.cfg_samp_clk_timing( rate=sample_rate, samps_per_chan=total_samples, sample_mode=AcquisitionType.FINITE ) # 配置模拟边沿参考触发 # 关键:指定pretrigger_samples参数,告诉DAQ保留M个触发前的样本 task.triggers.reference_trigger.cfg_anlg_edge_ref_trig( trigger_source=ai_channel, trigger_slope=trigger_slope, trigger_level=trigger_level, pretrigger_samples=pretrigger_samples ) # 启动任务:DAQ会先采集预触发样本,等待触发,然后采集剩余的后触发样本 task.start() # 读取所有样本:这里会阻塞直到采集完成 data = task.read(number_of_samples_per_channel=total_samples) # 可视化数据:可以看到触发点在pretrigger_samples的位置 plt.figure(figsize=(12, 6)) plt.plot(data) # 画一条线标记触发位置 plt.axvline(x=pretrigger_samples, color='r', linestyle='--', label='触发点') plt.xlabel('样本序号') plt.ylabel('电压 (V)') plt.title('带预触发的采集数据') plt.grid(True) plt.legend() plt.show() if __name__ == '__main__': hardwareFiniteVoltage()
关键改动说明
- 参数明确化:把总样本数、预触发样本数单独定义,方便你根据需求调整,避免通过时间计算的模糊性。
- 触发配置修正:
- 使用
Slope.RISING(或Slope.FALLING)指定触发沿,匹配你的冲击信号特性。 - 添加
pretrigger_samples参数,告诉DAQ在触发发生时,要保留之前采集的M个样本,之后再采集total_samples - pretrigger_samples个样本完成总采集。
- 使用
- 采样模式规范:用
AcquisitionType.FINITE代替数字常量,代码更清晰可靠。 - 可视化优化:添加了触发位置的标记线,方便你验证预触发和后触发的数据是否正确。
注意事项
- 确保NI USB-6366的驱动已正确安装,设备在NI MAX中可以正常识别。
- 根据你的实际冲击信号调整触发斜率(上升沿/下降沿)和阈值,确保触发能可靠触发。
- 如果预触发样本数设置过大,DAQ的缓冲区可能无法容纳,此时需要调整缓冲区大小(可以用
task.in_stream.input_buf_size设置)。
内容的提问来源于stack exchange,提问作者Khan02




