mikewalpole 发表于 2024-12-26 19:25

单片机ADC采样算法:卡尔曼滤波的实践与理解

算法的核心思想是,根据当前的仪器"测量值" 和上一刻的 “预测量” 和 “误差”,计算得到当前的最优量.

再预测下一刻的量, 里面比较突出的是观点是. 把误差纳入计算, 而且分为预测误差和测量误差两种.通称为 噪声. 还有一个非常大的特点是,误差独立存在, 始终不受测量数据的影响。下来先了解一个卡尔曼滤波中几个参数的含义:概率(Probability),随即变量(Random Variable),高斯或正态分配(Gaussian Distribution)还有State-space Model等等。关于卡尔曼公式的含义及推导,网上已经有很多文章了,这里不在赘述,直接看C代码的实现。/*R值固定,Q值越大,代表越信任测量值,Q值无穷大,代表只用测量值。         Q值越小,代表越信任模型预测值,Q值为0,代表只用模型预测值。*///参数一float KalmanFilter( float inData ){static float prevData = 0;                                 //上一个数据static float p = 10, q = 0.001, r = 0.001, kGain = 0;      // q 控制误差 r 控制响应速度p = p + q;kGain = p / ( p + r );                                    //计算卡尔曼增益inData = prevData + ( kGain * ( inData - prevData ) );      //计算本次滤波估计值p = ( 1 - kGain ) * p;                                    //更新测量方差prevData = inData;return inData;                                             //返回估计值}现在测试一下卡尔曼滤波的效果,通过函数发生器产生一个锯齿波,送到单片机的AD口,单片机读取采集到的AD数据后,经过卡尔曼滤波算法,然后将采样的数据和滤波后的数据通过串口发生出来,并在串口波形显示软件上显示。

void main( void ){while( 1 ){    val1 = ReadVol_CH3();            //读取AD采样数据    dat = ( float )val1;    dat =    KalmanFilter( dat );    //卡尔曼滤波    printf("A%drn",val1);          //打印结果    printf("B%2frn",dat);}}现在看一下滤波的结果
https://i-blog.csdnimg.cn/blog_migrate/300b3f9c0580a2218dbc4d160525db49.png蓝色曲线为原始采样的数据曲线,橙色曲线为经过卡尔曼滤波后的曲线。下面改变Q和R的值在测试一下滤波效果。修改后的参数如下//参数二unsigned long kalman_filter( unsigned long ADC_Value ){float LastData;float NowData;float kalman_adc;static float kalman_adc_old = 0;static float P1;static float Q = 0.0003;static float R = 5;static float Kg = 0;static float P = 1;NowData = ADC_Value;LastData = kalman_adc_old;P = P1 + Q;Kg = P / ( P + R );kalman_adc = LastData + Kg * ( NowData - kalman_adc_old );P1 = ( 1 - Kg ) * P;P = P1;kalman_adc_old = kalman_adc;return ( unsigned long )( kalman_adc );}测试波形https://i-blog.csdnimg.cn/blog_migrate/b01d903285bfccf559c549ad79910d21.png蓝色曲线为原始采样的数据曲线,橙色曲线为经过卡尔曼滤波后的曲线。和第一次测试的波形图对比后可以发现,第二次经过卡尔曼滤波后的波形变化非常大,参数改变后锯齿波被滤成接近于直线了。可以看到不同的R、Q值会对测量结果有很大的影响。Q:过程噪声,Q增大,动态响应变快,收敛稳定性变坏R:测量噪声,R增大,动态响应变慢,收敛稳定性变好具体各个参数的如何选择,只有在应用中根据测量结果,自己慢慢调整。

申小林一号 发表于 2025-1-22 09:59

学习一下,提升个人技能

一点点0321 发表于 2025-4-30 22:28

Kalman Gain 是卡尔曼滤波的关键,它用于平衡预测与测量之间的关系。

cemaj 发表于 2025-5-3 21:53

卡尔曼滤波是一种用于估计系统状态的最优递归滤波器,在单片机 ADC(模拟 - 数字转换)采样中使用卡尔曼滤波算法,能够有效减少采样噪声的影响,提高采样数据的准确性。

robincotton 发表于 2025-5-3 22:40

卡尔曼滤波适用于噪声高斯分布且系统动态可建模的场景

febgxu 发表于 2025-5-4 00:13

卡尔曼滤波包含以下两个主要步骤:
预测步骤:根据系统的动态模型,预测下一个时刻的系统状态和误差协方差。
更新步骤:利用当前时刻的测量值,结合预测值,计算卡尔曼增益,然后更新系统状态和误差协方差。

saservice 发表于 2025-5-4 03:15

卡尔曼滤波可以根据系统动态自动调整滤波强度,而固定窗口的平均值滤波适应性较差。

cemaj 发表于 2025-5-4 19:40

可以考虑将卡尔曼滤波与其他滤波算法(如限幅滤波、加权平均滤波等)相结合,以进一步提高采样精度和抗干扰能力。

alvpeg 发表于 2025-5-4 22:42

卡尔曼滤波需要在每次 ADC 采样后进行计算,因此要确保单片机有足够的计算能力,以保证实时性。

fengm 发表于 2025-5-6 10:05

结合硬件滤波(如RC低通)降低高频噪声,减少卡尔曼滤波负担。

deliahouse887 发表于 2025-5-6 11:55

卡尔曼滤波可以立即使用新数据更新估计值,而平均值滤波需要等待足够多的采样点。

backlugin 发表于 2025-5-6 13:42

#include <stdio.h>

// 卡尔曼滤波器结构体
typedef struct {
    float q;// 过程噪声协方差
    float r;// 测量噪声协方差
    float x;// 状态估计值
    float p;// 误差协方差
    float k;// 卡尔曼增益
} KalmanFilter;

// 初始化卡尔曼滤波器
void KalmanFilter_Init(KalmanFilter *kf, float q, float r, float initial_x, float initial_p) {
    kf->q = q;
    kf->r = r;
    kf->x = initial_x;
    kf->p = initial_p;
}

// 卡尔曼滤波更新
float KalmanFilter_Update(KalmanFilter *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;
}

// 模拟ADC采样函数
int adc_sample() {
    // 这里可以替换为实际的ADC采样代码
    // 为了演示,返回一个带有噪声的模拟值
    static int value = 500;
    int noise = (rand() % 21) - 10;// 产生 -10 到 10 的随机噪声
    return value + noise;
}

int main() {
    KalmanFilter kf;
    // 初始化卡尔曼滤波器
    KalmanFilter_Init(&kf, 0.01, 1, 0, 1);

    for (int i = 0; i < 10; i++) {
      int raw_value = adc_sample();
      float filtered_value = KalmanFilter_Update(&kf, (float)raw_value);

      printf("Raw ADC value: %d, Filtered value: %.2f\n", raw_value, filtered_value);
    }

    return 0;
}

uytyu 发表于 2025-5-6 15:33

在单片机上实现卡尔曼滤波时,应注意优化代码结构,减少计算量和内存占用,提高程序的执行效率。

tifmill 发表于 2025-5-6 17:39

卡尔曼滤波是递归算法,不需要存储历史数据,适合资源有限的单片机;而平均值滤波需要存储多个历史数据点。

tabmone 发表于 2025-5-6 19:24

融合多传感器数据(如IMU的加速度计+陀螺仪),实现更复杂的姿态估计。

bestwell 发表于 2025-5-6 21:07

滤波效果不理想,噪声仍然较大。            
页: [1]
查看完整版本: 单片机ADC采样算法:卡尔曼滤波的实践与理解