You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于nidaqmx的NI PXI采集卡10小时长时监测数据落盘实现问题

长时采集改造方案

你原来的代码核心问题是一次性把全时段的采样数拉到内存读取,完全没用上nidaqmx驱动层自带的环形缓冲能力,按你200kHz采样的参数算,哪怕单通道10小时的单精度数据都有2.88GB,多通道场景下直接就把Python进程内存吃满了。
连续采集模式下不需要把所有数据堆在内存里,只要改成分块轮询读、读一块写一块、及时回收内存的逻辑,哪怕连续跑几十小时,内存占用也能稳定在几十MB级别,根本不会出现内存溢出的问题。

核心配置逻辑

  • 先给驱动层的硬件环形缓冲留够足够空间:按10秒的总采样量设置缓冲大小,公式为 硬件缓冲采样数 = 总通道数 * 200000 * 10,这个大小哪怕程序轮询偶尔卡顿,也不会出现缓冲溢出丢数的问题。
  • 计算固定块的读取大小:按照你想要的块存储容量算对应的单通道采样数,比如想每20MB写一次盘,公式为 单块读取采样数 = (目标块大小MB * 1024 * 1024) / (总通道数 * 4),这里单采样按float32的4字节算,比默认的float64省一半内存和磁盘空间。
  • 循环分块读取:每次固定读指定块大小的采样数,读出来的数组直接写磁盘,写完立刻删除内存引用让Python回收,全程内存里不会堆超过单块大小的数据。

可直接复用的改造代码

import nidaqmx
from nidaqmx.constants import AcquisitionType
import numpy as np

# 基础参数,按实际场景调整
total_sample_time = 10 * 3600  # 总采集时长10小时,单位秒
s_freq = 200000
target_chunk_mb = 20  # 每20MB触发一次磁盘写入
num_channels = 6  # 两块卡各取3通道的总通道数,按实际通道数修改

# 换算单块需要读的单通道采样数
chunks_samples = int((target_chunk_mb * 1024 * 1024) / (num_channels * 4))
# 硬件环形缓冲大小:留10秒的采样余量
hw_buffer_size = num_channels * s_freq * 10
# 总循环读取的块数
total_chunks = int(np.ceil(total_sample_time * s_freq / chunks_samples))

# 打开二进制raw文件存储,写入速度远快于csv、xlsx格式
with open("long_term_vibration_data.raw", "wb") as f:
    # 先写文件头,存基础参数方便后续读取解析
    file_header = np.array([s_freq, num_channels, chunks_samples, total_chunks], dtype=np.float64)
    file_header.tofile(f)

    print("开始长时采集!")
    with nidaqmx.Task() as task:
        # 分别添加两块采集卡的加速度通道,按实际设备路径修改
        task.ai_channels.add_ai_accel_chan("PXI1Slot2/ai1:3",
                                           sensitivity=10000.0,
                                           max_val=1,
                                           min_val=-1)
        task.ai_channels.add_ai_accel_chan("PXI1Slot3/ai1:3",
                                           sensitivity=10000.0,
                                           max_val=1,
                                           min_val=-1)
        # 配置连续采样模式,指定硬件缓冲大小
        task.timing.cfg_samp_clk_timing(s_freq,
                                        sample_mode=AcquisitionType.CONTINUOUS,
                                        buffer_size=hw_buffer_size)
        # 启动采集任务
        task.start()

        for idx in range(total_chunks):
            # 分块读取数据,超时设置比单块采集时长久即可
            data_chunk = task.read(number_of_samples_per_channel=chunks_samples, timeout=10)
            # 转成float32格式存储,省一半磁盘和内存
            data_chunk = np.array(data_chunk, dtype=np.float32)
            # 直接写盘,不把数据堆在内存
            data_chunk.tofile(f)
            # 删除当前块的内存引用,触发垃圾回收
            del data_chunk
            # 每10块打印一次采集进度和硬件缓冲占用
            if idx % 10 == 0:
                elapsed_hour = (idx * chunks_samples / s_freq) / 3600
                buffer_usage = task.in_stream.available_samples_in_buffer / hw_buffer_size
                print(f"已采集 {elapsed_hour:.2f} 小时,硬件缓冲占用 {buffer_usage*100:.1f}%")

print("10小时采集任务完成!")

实操避坑要点

  • 采集循环里别做实时画图、复杂信号计算这类耗时间的操作,这类操作一次就要占几百毫秒,很容易把硬件缓冲挤爆,所有可视化、分析逻辑等采集完读盘再做。
  • 存储数据的硬盘别用系统盘,关掉硬盘自动休眠功能,避免采集过程中硬盘进入休眠状态,导致写入跟不上采集速度丢数。
  • 正式跑长时采集前,先跑5分钟的短测试,观察硬件缓冲的占用率:如果占用率经常超过30%,就把单块读取的采样数调小,或者把硬件缓冲的预留空间从10秒提至30秒,避免缓冲溢出。
  • Windows系统下可以适当把Python进程的优先级调高,避免后台更新、杀毒软件抢占CPU导致程序响应变慢。

内容的提问来源于stack exchange,提问作者Thomas Gaubert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 06:36:04