3. 温度数据采集与滤波:ADC采样原理与分辨率选择

各位工程师朋友,咱们今天聊聊温度采集。这活儿看着简单,其实坑不少。我刚开始做工业控制那会儿,就吃过亏——采集的温度数据跳得像心电图,PID根本稳不住。后来才明白,问题出在ADC选型和滤波策略上。

3.1 ADC采样原理与分辨率选择

ADC采样,说白了就是把模拟电压转成数字量。温度传感器(比如PT100、热电偶)输出的是电压信号,ADC负责把它变成单片机认识的二进制数。

分辨率怎么选? 这得看你的温度精度要求。举个例子:

  • 12位ADC:0~5V对应0~4095,每LSB约1.22mV
  • 16位ADC:0~5V对应0~65535,每LSB约0.076mV

如果温度传感器灵敏度是10mV/℃,那12位ADC的理论温度分辨率是0.122℃,16位是0.0076℃。嗯,这里要注意——理论值不等于实际值,噪声会吃掉低几位。

我的经验:工业控温场景,14位ADC基本够用。16位更好,但成本高。12位的话,得配合过采样技术才能达到0.1℃精度。

采样率呢?温度变化慢,一般1~10Hz就够了。但如果你做快速温控(比如激光焊接),可能需要100Hz以上。

3.2 滑动平均滤波

这是最常用的滤波方法。原理简单:取N个采样值的平均值。

// 滑动平均滤波示例
#define FILTER_N 10
static uint16_t buffer[FILTER_N];
static uint8_t index = 0;
static uint32_t sum = 0;

uint16_t moving_average(uint16_t new_sample) {
    sum -= buffer[index];
    buffer[index] = new_sample;
    sum += new_sample;
    index = (index + 1) % FILTER_N;
    return sum / FILTER_N;
}

N值越大,滤波效果越好,但响应越慢。我一般取5~20之间。曾经有个项目,温度波动大,我取了N=50,结果系统响应慢得像蜗牛,后来改成N=10加中值滤波才搞定。

小技巧:滑动平均适合抑制高频噪声,但对脉冲干扰效果差。如果传感器偶尔受干扰跳变,建议配合中值滤波使用。

3.3 中值滤波

中值滤波对付脉冲干扰特别有效。原理:取N个采样值,排序后取中间值。

// 中值滤波示例
#define MEDIAN_N 5
uint16_t median_filter(uint16_t *samples) {
    uint16_t temp[MEDIAN_N];
    memcpy(temp, samples, MEDIAN_N * sizeof(uint16_t));
    
    // 冒泡排序
    for(int i = 0; i < MEDIAN_N - 1; i++) {
        for(int j = 0; j < MEDIAN_N - 1 - i; j++) {
            if(temp[j] > temp[j+1]) {
                uint16_t t = temp[j];
                temp[j] = temp[j+1];
                temp[j+1] = t;
            }
        }
    }
    return temp[MEDIAN_N / 2];
}

N一般取奇数,3、5、7都行。N越大,抗干扰越强,但计算量也大。我习惯用N=5,效果不错,计算量也小。

注意:中值滤波会丢失一些细节信息。如果温度变化很快,中值滤波可能会把真实变化当成噪声滤掉。我曾经在快速温控项目里吃过这个亏,后来改用卡尔曼滤波。

3.4 卡尔曼滤波在温度数据上的应用

卡尔曼滤波,听着高大上,其实原理不复杂。它根据上一时刻的状态和当前观测值,估算出最优值。说白了,就是「预测+修正」的过程。

温度变化慢,用一维卡尔曼滤波就够了。状态量就是温度值,观测量也是温度值。

// 一维卡尔曼滤波示例
typedef struct {
    float Q;  // 过程噪声协方差
    float R;  // 测量噪声协方差
    float P;  // 估计误差协方差
    float K;  // 卡尔曼增益
    float X;  // 状态估计值
} Kalman_1D;

void Kalman_Init(Kalman_1D *kf, float init_temp) {
    kf->Q = 0.01;   // 温度变化慢,Q设小
    kf->R = 0.1;    // 测量噪声,根据ADC精度调整
    kf->P = 1.0;    // 初始估计误差
    kf->X = init_temp;
}

float Kalman_Update(Kalman_1D *kf, float measurement) {
    // 预测
    kf->P = kf->P + kf->Q;
    
    // 更新
    kf->K = kf->P / (kf->P + kf->R);
    kf->X = kf->X + kf->K * (measurement - kf->X);
    kf->P = (1 - kf->K) * kf->P;
    
    return kf->X;
}

Q和R这两个参数怎么调?Q代表你对模型的信任程度,R代表你对传感器的信任程度。Q越小,滤波越平滑;R越小,响应越快。我一般先设Q=0.01,R=0.1,然后根据实际效果微调。

我的经验:卡尔曼滤波在温度控制上效果非常好。曾经有个恒温槽项目,要求±0.05℃精度,滑动平均和中值滤波都做不到,换成卡尔曼滤波后,稳得一批。

3.5 采样率与精度权衡

采样率越高,数据越丰富,但噪声也越多。采样率越低,数据平滑,但可能丢失细节。

采样率 优点 缺点 适用场景
1~10 Hz 噪声小,数据稳定 响应慢 恒温控制、环境监测
10~100 Hz 响应适中 需要滤波 一般工业控温
100 Hz以上 响应快 噪声大,需复杂滤波 快速温控、激光焊接

怎么权衡?我有个原则:采样率取系统带宽的5~10倍。比如你的温度变化周期是1秒,那采样率5~10Hz就够了。再高就是浪费资源。

避坑指南:我曾经为了追求精度,把采样率提到100Hz,结果CPU负载飙升,其他任务都受影响。后来降到20Hz,配合卡尔曼滤波,效果一样好。记住,不是采样率越高越好。

3.6 三种滤波方法对比

做个总结,方便你选型:

滤波方法 优点 缺点 适用场景
滑动平均 实现简单,抑制高频噪声 对脉冲干扰无效,有延迟 一般温度采集
中值滤波 抗脉冲干扰强 计算量大,丢失细节 传感器受干扰场景
卡尔曼滤波 效果好,自适应 参数调校复杂 高精度控温

我个人习惯:先用滑动平均,效果不行就加中值滤波,还不行就上卡尔曼。别一上来就搞复杂的,简单方法往往够用。

温度数据采集与滤波流程 温度传感器 ADC采样 滤波方法选择 滑动平均滤波 中值滤波 卡尔曼滤波 温度值输出

这张图把整个流程串起来了。从传感器到ADC,再到三种滤波方法,最后输出稳定的温度值。你想想看,是不是很清晰?

核心要点:

  • ADC分辨率选14位以上,配合过采样可达到0.1℃精度
  • 滑动平均适合一般场景,中值滤波对付脉冲干扰
  • 卡尔曼滤波效果最好,但需要调参
  • 采样率取系统带宽的5~10倍,别盲目追求高采样率

好了,温度采集与滤波就聊到这儿。记住,没有万能的滤波方法,只有最适合你项目的方案。多试几次,找到那个平衡点。

专注资料整理