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分辨率选14位以上,配合过采样可达到0.1℃精度
- 滑动平均适合一般场景,中值滤波对付脉冲干扰
- 卡尔曼滤波效果最好,但需要调参
- 采样率取系统带宽的5~10倍,别盲目追求高采样率
好了,温度采集与滤波就聊到这儿。记住,没有万能的滤波方法,只有最适合你项目的方案。多试几次,找到那个平衡点。