C 语言工业级通用组件手写 23:卡尔曼滤波(简易版)

目录

前言:

一、核心本质与应用场景

[1. 什么是卡尔曼滤波](#1. 什么是卡尔曼滤波)

[2. 解决的核心痛点](#2. 解决的核心痛点)

[3. 典型落地场景](#3. 典型落地场景)

二、核心实现原理

三、工业级设计规范

四、完整可复用源码

filter_kalman.h

filter_kalman.c

五、实战演示

六、进阶优化方向

七、面试考点与易错坑点

面试问答

常见坑点

总结


前言:

在电机转速、姿态传感器、动态压力等快速变化且带噪声 的采集场景中,传统滤波要么滞后严重,要么平滑不足。卡尔曼滤波通过预测 + 更新闭环迭代,在不牺牲响应速度的前提下实现最优降噪,是无人机、机器人、伺服控制、高端仪表的核心算法。

本篇实现轻量化定点卡尔曼,无矩阵、无浮点、可直接在低端 MCU 运行。


一、核心本质与应用场景

1. 什么是卡尔曼滤波

卡尔曼滤波是最优递归滤波

  • 先根据上一状态预测当前值
  • 再用实际采样修正预测值
  • 自动计算卡尔曼增益,动态平衡 "信模型" 还是 "信测量"

核心特性

  • 动态响应极快,几乎无滞后
  • 平滑效果强,抑制高斯噪声
  • 单帧运算,无需缓存窗口
  • 可自适应噪声环境
  • 极小 RAM 占用

2. 解决的核心痛点

  • 传统滤波滞后大,跟不上动态变化
  • 平均 / 中值滤波无法处理高速变化信号
  • 传感器噪声随机,固定算法效果差
  • 需要兼顾实时性与平滑度的高端场景

3. 典型落地场景

  • 陀螺仪 / 加速度计姿态融合 电机转速
  • 电流动态采集 无人机
  • 平衡车姿态估计 动态压力
  • 流量实时监测 高精度伺服闭环反馈滤波

二、核心实现原理

  1. 预测阶段 根据上一时刻结果推算当前值

  2. 卡尔曼增益计算 动态决定信任预测还是信任测量

  3. 更新阶段 融合预测值与采样值,得到最优输出

  4. 误差协方差迭代 持续估计噪声水平,自适应调整滤波强度

全部使用定点整数运算,无浮点、无除法瓶颈。


三、工业级设计规范

  • 结构体封装状态、协方差、噪声参数
  • 多实例独立,多路传感器互不干扰
  • 完整空指针、参数校验
  • 纯静态内存,无堆分配
  • 可在线动态调整噪声参数

四、完整可复用源码

filter_kalman.h

复制代码
#ifndef FILTER_KALMAN_H
#define FILTER_KALMAN_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    int32_t x;      // 估计值
    int32_t p;      // 估计误差协方差
    int32_t q;      // 过程噪声
    int32_t r;      // 测量噪声
} filter_kalman_t;

void filter_kalman_init(filter_kalman_t *k, int32_t init_val, int32_t q, int32_t r);
int32_t filter_kalman_calc(filter_kalman_t *k, int32_t meas);

#ifdef __cplusplus
}
#endif

#endif

filter_kalman.c

复制代码
#include "filter_kalman.h"

#define KALMAN_SCALE 1024

void filter_kalman_init(filter_kalman_t *k, int32_t init_val, int32_t q, int32_t r) {
    if (!k) return;
    k->x = init_val * KALMAN_SCALE;
    k->p = 32 * KALMAN_SCALE;
    k->q = q;
    k->r = r * KALMAN_SCALE;
}

int32_t filter_kalman_calc(filter_kalman_t *k, int32_t meas) {
    if (!k) return meas;

    int32_t m = meas * KALMAN_SCALE;

    // 预测
    k->p += k->q;

    // 卡尔曼增益
    int32_t gain = (k->p * KALMAN_SCALE) / (k->p + k->r);

    // 更新
    k->x += gain * (m - k->x) / KALMAN_SCALE;
    k->p = (KALMAN_SCALE - gain) * k->p / KALMAN_SCALE;

    return k->x / KALMAN_SCALE;
}

五、实战演示

复制代码
#include <stdio.h>
#include "filter_kalman.h"

int main(void) {
    filter_kalman_t k;
    filter_kalman_init(&k, 1000, 5, 100);

    int32_t data[] = {1000, 1002, 998, 1050, 999, 1001, 997, 1003, 1100, 1000};
    for (int i = 0; i < 10; i++) {
        int32_t res = filter_kalman_calc(&k, data[i]);
        printf("raw:%5d  kalman:%5d\n", data[i], res);
    }
    return 0;
}

六、进阶优化方向

  1. 带加速度 / 变速度模型的自适应卡尔曼
  2. 互补滤波 + 卡尔曼级联
  3. 动态调整 Q/R 噪声参数
  4. 多传感器融合扩展(加速度 + 陀螺仪)

七、面试考点与易错坑点

面试问答

Q1:卡尔曼滤波为什么适合动态信号?

答:它是预测 + 修正闭环,不需要窗口缓存,响应极快,同时能最优降噪。

Q2:Q 和 R 分别代表什么?

答:Q 是过程噪声,Q 越大越信任测量;R 是测量噪声,R 越大越信任预测。

Q3:卡尔曼和一阶滞后滤波区别?

答:一阶滞后系数固定;卡尔曼增益动态自适应,效果更智能。

Q4:为什么要用定点运算?

答:低端 MCU 无 FPU,浮点慢且精度差,定点运算更快更稳定。

Q5:卡尔曼滤波缺点是什么?

答:对非高斯噪声效果一般;强尖峰干扰前需加限幅。

Q6:工程上如何调 Q、R?

答:噪声大则 R 调大;变化快则 Q 调大。

常见坑点

  • Q/R 设置极端导致滤波失效
  • 未做定点缩放,数值溢出
  • 多通道共用实例导致状态错乱
  • 初始值设置不合理导致启动漂移
  • 直接用浮点版本导致 MCU 卡顿

总结

卡尔曼滤波是嵌入式高端动态降噪天花板算法,完美兼顾响应速度与平滑度,是传感器融合、电机控制、姿态检测的必备组件。本篇轻量化定点实现无门槛移植,工业级鲁棒稳定,可直接用于量产项目。

创作不易,如果对你有帮助,欢迎点赞、收藏、转发。

相关推荐
888CC++3 小时前
C语言与C++的区别:从面向过程到面向对象
java·c语言·c++
库玛西5 小时前
C++ 运行时多态 :核心总结与原理图解
c语言·c++·笔记
天空'之城7 小时前
C 语言工业级通用组件手写 21:限幅消抖滤波
c语言·嵌入式算法·工业级组件·限幅消抖滤波
Aurorar0rua7 小时前
CS50 x 2024 Notes Algorithms - 07
c语言·开发语言·学习方法
神罚天下ET7 小时前
典型arm位单片机启动流程(从上电到main.c)
c语言·arm开发·单片机
noipp11 小时前
推荐题目:洛谷 P3726 [AHOI2017/HNOI2017] 抛硬币
c语言·数据结构·c++·算法·编程·洛谷·luogu
c2385611 小时前
C/C++每日一练14
c语言·c++·算法
apocelipes12 小时前
Linux NTSYNC 简明教程
c语言·并发·linux编程
caishenzhibiao12 小时前
缠论画线主图 同花顺期货通指标
java·c语言·c#