4、数据采集模块测试:ADC精度测试、采样率验证、数据滤波效果测试

数据采集模块,说白了就是整个水质监测系统的「眼睛」和「耳朵」。ADC 要是出了问题,后面再好的算法也白搭。我这些年调试过的板子,少说也有几十块了,ADC 这块踩过的坑真不少。今天咱们就聊聊怎么把 ADC 精度、采样率和滤波效果这三项核心指标测透。

4.1 ADC 精度测试

ADC 精度测试,核心就一句话:给已知电压,看读回来准不准。但实际操作起来,门道可不少。

我个人习惯用高精度信号源(比如 Fluke 5700A 或 Keysight 33500B)输出直流电压。别用普通万用表当信号源,那玩意儿输出纹波大,测出来的结果你根本分不清是 ADC 的问题还是信号源的问题。我曾经就吃过这个亏,折腾了两天才发现是信号源太烂。

测试步骤我一般这么走:

  1. 零点校准:输入 0V(短接 ADC 输入端),读取转换结果。理想值是 0,但实际会有偏移。我见过最夸张的一块板子,偏移量达到了 15mV,后来发现是 PCB 布局时模拟地和数字地没处理好。
  2. 满量程校准:输入接近参考电压的值(比如 3.3V 参考就输 3.3V),看满量程误差。
  3. 线性度测试:在量程内均匀取 10~20 个点,记录每个点的理论值和实测值。

关键指标

  • 偏移误差:零点处的偏差,单位 mV 或 LSB
  • 增益误差:满量程处的偏差,通常用百分比表示
  • 积分非线性(INL):实际传输曲线与理想直线的最大偏差
  • 微分非线性(DNL):相邻两个码字之间的步进偏差

嗯,这里要注意:测试 INL 和 DNL 时,信号源的分辨率至少要比 ADC 高 4 倍。比如你测 12 位 ADC,信号源最好有 16 位以上的分辨率。不然你测出来的非线性,其实是信号源的非线性。

我给大家一个简单的测试表格模板:

输入电压 (V) 理论码值 实测码值 误差 (LSB) 误差 (mV)
0.000 0 2 +2 +1.6
0.500 620 621 +1 +0.8
1.000 1241 1240 -1 -0.8
2.000 2482 2485 +3 +2.4
3.300 4095 4093 -2 -1.6

小技巧:测试时每次改变电压后,等 500ms 再读数。因为信号源和 ADC 输入端的 RC 滤波电路有建立时间。我习惯写个自动化脚本,用 Python 控制信号源和读取 ADC 数据,一次跑完所有点,省时省力。

4.2 采样率验证

采样率验证,说白了就是看 ADC 能不能按你设定的速度干活。很多工程师以为配置好寄存器就完事了,其实不然。我遇到过好几次,配置的是 1kHz,实际跑起来只有 800Hz,原因是时钟分频配置错了。

验证方法有两种:

  • 方法一:示波器测量 DRDY 引脚。大多数 ADC 芯片都有数据就绪引脚(Data Ready),每转换完一次就输出一个脉冲。用示波器测这个脉冲的频率,就是实际采样率。这是最直接的方法。
  • 方法二:软件计时法。在代码里记录每收到 1000 个数据点的时间差,然后计算平均采样率。这个方法适合没有 DRDY 引脚的芯片。

我个人更推荐方法一,因为它能同时看到脉冲的抖动情况。如果脉冲间隔忽大忽小,说明采样时钟不稳定,可能是 PLL 锁相环没锁住,或者外部晶振有问题。

注意:采样率不是越高越好。对于水质监测这种慢变信号,100Hz 通常就足够了。采样率太高反而会引入更多噪声,而且数据量大了 MCU 处理不过来。我曾经有个项目,把采样率设到 10kHz,结果 MCU 大部分时间都在处理 ADC 中断,主循环几乎跑不动。

采样率验证的合格标准:实测值与设定值的偏差在 ±5% 以内。如果偏差超过 10%,基本可以断定时钟配置有问题。

4.3 数据滤波效果测试

ADC 原始数据,说白了就是「毛坯房」,必须经过滤波才能用。水质监测中常见的噪声源有:工频 50Hz 干扰、水泵振动噪声、传感器自身噪声。

滤波效果测试,我一般分三步走:

  1. 采集原始数据:在静止水体中,连续采集 1000 个点,不滤波。
  2. 施加已知干扰:用信号发生器在 ADC 输入端叠加一个 50Hz、100mVpp 的正弦波,模拟工频干扰。
  3. 对比滤波前后:分别用移动平均滤波、中值滤波、卡尔曼滤波处理数据,看效果。

下面是我常用的几种滤波算法对比:

滤波方法 原理 优点 缺点 适用场景
移动平均滤波 取 N 个点的平均值 简单、计算快 有延迟、对突变不敏感 缓慢变化的 pH、温度
中值滤波 取 N 个点的中间值 抗脉冲干扰强 计算量大、平滑效果一般 有尖峰噪声的浊度信号
一阶低通滤波 Y(n) = α*X(n) + (1-α)*Y(n-1) 实时性好、内存占用小 参数 α 需要调试 通用场景
卡尔曼滤波 基于状态空间模型 精度高、自适应 实现复杂、需要调参 高精度要求的溶解氧

代码示例(一阶低通滤波):

// 一阶低通滤波器实现
// alpha = 0.1 表示滤波强度大,响应慢
// alpha = 0.5 表示滤波强度小,响应快

#define ALPHA 0.15f

float lowpass_filter(float raw_value, float prev_filtered) {
    return ALPHA * raw_value + (1.0f - ALPHA) * prev_filtered;
}

// 使用示例
float filtered_value = 0.0f;
while(1) {
    float raw = read_adc();
    filtered_value = lowpass_filter(raw, filtered_value);
    printf("Raw: %.2f, Filtered: %.2f\n", raw, filtered_value);
    delay_ms(10);
}

滤波效果评估指标

  • 信噪比提升:滤波后 SNR 比滤波前高多少 dB
  • 响应时间:输入阶跃信号后,滤波输出达到稳态值 90% 所需时间
  • 稳态波动:滤波后数据的峰峰值,越小越好

举个例子,我在测试溶解氧传感器时,原始数据波动有 ±0.5mg/L,用了 16 点移动平均滤波后,波动降到了 ±0.05mg/L。但代价是响应时间从 0 变成了 160ms(16 个点 × 10ms 采样间隔)。所以滤波不是越强越好,得在平滑度和响应速度之间找平衡。

避坑指南:我曾经在滤波上犯过一个低级错误——在中断服务函数里做滤波计算。结果滤波还没算完,下一个中断又来了,导致数据丢失。后来我把滤波放到主循环里做,用双缓冲区解决数据同步问题。记住:中断里只做数据搬运,不做数据处理

最后总结一下:ADC 精度测试是基础,采样率验证是保障,滤波效果测试是升华。这三项都过了,你的数据采集模块才算真正靠谱。下次咱们聊传感器接口测试,那又是另一番天地了。