【滤波第三期】卡尔曼滤波的原理和C代码

news/2024/11/20 6:31:27/

b591e0f8e37e6ae44f9201e150082143.png

卡尔曼滤波(Kalman Filter)是一种递归的、自适应的滤波算法,广泛应用于估计系统状态和观测过程中的噪声。它最初在1960年被提出,被认为是控制理论和信号处理领域中最重要的发展之一。卡尔曼滤波器在许多领域,包括导航、机器人、金融和通信系统中都有广泛的应用。


1,基本原理:

卡尔曼滤波器的核心思想是融合系统的动态模型和实际的观测数据,通过对过程和测量噪声的估计,提供对系统状态的最优估计。其基本原理可以分为两个步骤:预测(Predict)和更新(Update)。


预测(Predict):

在预测阶段,卡尔曼滤波器使用系统的动态模型,以及先前的状态估计来预测系统的下一个状态。这一过程基于系统的状态方程和控制输入,考虑系统的动态演变。预测的结果是对系统状态的先验估计,其中考虑了系统的动态行为。卡尔曼滤波的状态方程通常表示为:

3d8958fa0687f895904e692467a90963.png

其中,Xk是系统状态向量,F 是状态转移矩阵,B 是输入矩阵,Uk是控制输入向量,Wk是过程噪声。


更新(Update):

在更新阶段,卡尔曼滤波器使用实际的测量数据来校正先前的状态估计。这一过程基于测量方程和测量噪声,考虑了观测到的系统输出。更新的结果是对系统状态的后验估计,其中融合了测量信息。

卡尔曼滤波的测量方程通常表示为:

��=���+��

d01b80282e88f9d40160d0ec929d3e6e.png

    其中,Zk是测量向量,H是测量矩阵,Vk测量噪声。


2,状态估计的迭代过程:

卡尔曼滤波是一个迭代的过程,其更新步骤依赖于预测和测量的相互作用。以下是卡尔曼滤波的迭代过程:

初始化: 首先,需要初始化卡尔曼滤波器的状态估计(X0)和协方差矩阵(P0)

预测: 使用系统的状态方程进行状态的预测,并更新状态的协方差矩阵。这一步考虑了系统的动态演变和过程噪声。其中,Xk是先验状态估计,Pk是先验协方差矩阵,Q是过程噪声协方差矩阵。

453b96a2be7c3cb3a51e4f4f3c1b2d99.png

测量更新: 使用测量方程将预测的状态与实际的测量数据进行比较,从而校正状态估计,并更新协方差矩阵。这一步考虑了观测到的系统输出和测量噪声。其中,Kk 是卡尔曼增益,R是测量噪声协方差矩阵,Xk 是后验状态估计,Pk 是后验协方差矩阵。

0f3dc60b8077749b1dfc70c2767b5ce6.png

重复: 重复预测和测量更新步骤,将后验状态估计作为下一步的先验状态估计,持续迭代。


3,关键概念:

卡尔曼增益: 卡尔曼增益是一个关键的概念,它决定了预测和测量更新之间的相对权重。卡尔曼增益越大,系统对测量数据的依赖性越强,反之亦然。

协方差矩阵: 协方差矩阵描述了状态估计的不确定性。通过在迭代过程中更新协方差矩阵,卡尔曼滤波器能够动态调整对状态估计的信任程度。

过程噪声和测量噪声: 过程噪声和测量噪声是卡尔曼滤波中的两个关键参数,它们用于描述系统动态模型和测量过程中的不确定性。适当估计和调整这些噪声是卡尔曼滤波器性能的关键。

4,示例代码:

#include <stdio.h>
// 定义状态向量的维度
#define STATE_DIM 2
// 定义测量向量的维度
#define MEASURE_DIM 1// 定义卡尔曼滤波器结构体
typedef struct {// 状态估计向量float x[STATE_DIM];// 状态协方差矩阵float P[STATE_DIM][STATE_DIM];// 过程噪声协方差矩阵float Q[STATE_DIM][STATE_DIM];// 测量噪声协方差矩阵float R[MEASURE_DIM][MEASURE_DIM];// 状态转移矩阵float F[STATE_DIM][STATE_DIM];// 测量矩阵float H[MEASURE_DIM][STATE_DIM];
} KalmanFilter;// 初始化卡尔曼滤波器
void kalmanFilterInit(KalmanFilter *kf, float initialX, float initialP);
// 卡尔曼滤波预测步骤
void kalmanPredict(KalmanFilter *kf, float controlInput);
// 卡尔曼滤波更新步骤
void kalmanUpdate(KalmanFilter *kf, float measurement);int main() {// 初始化卡尔曼滤波器KalmanFilter kf;kalmanFilterInit(&kf, 0.0, 1.0);// 模拟输入数据float controlInput = 0.1;float measurementNoise = 0.5;// 模拟10次迭代for (int i = 0; i < 10; ++i) {// 预测步骤kalmanPredict(&kf, controlInput);// 模拟测量float trueMeasurement = 2.0 * kf.x[0] + measurementNoise;// 更新步骤kalmanUpdate(&kf, trueMeasurement);// 打印结果printf("Iteration %d - True Value: %f, Estimated Value: %f\n", i + 1, trueMeasurement, kf.x[0]);}return 0;
}// 初始化卡尔曼滤波器
void kalmanFilterInit(KalmanFilter *kf, float initialX, float initialP) {// 初始化状态估计向量kf->x[0] = initialX;kf->x[1] = 0.0;// 初始化状态协方差矩阵kf->P[0][0] = initialP;kf->P[0][1] = 0.0;kf->P[1][0] = 0.0;kf->P[1][1] = initialP;// 初始化过程噪声协方差矩阵kf->Q[0][0] = 0.001;kf->Q[0][1] = 0.0;kf->Q[1][0] = 0.0;kf->Q[1][1] = 0.001;// 初始化测量噪声协方差矩阵kf->R[0][0] = 0.01;// 初始化状态转移矩阵kf->F[0][0] = 1.0;kf->F[0][1] = 1.0;kf->F[1][0] = 0.0;kf->F[1][1] = 1.0;// 初始化测量矩阵kf->H[0][0] = 1.0;kf->H[0][1] = 0.0;
}// 卡尔曼滤波预测步骤
void kalmanPredict(KalmanFilter *kf, float controlInput) {// 预测状态估计kf->x[0] = kf->F[0][0] * kf->x[0] + kf->F[0][1] * kf->x[1] + controlInput;// 预测状态协方差矩阵kf->P[0][0] = kf->F[0][0] * kf->P[0][0] * kf->F[0][0] + kf->F[0][1] * kf->P[1][0];kf->P[0][1] = kf->F[0][0] * kf->P[0][1] * kf->F[0][1] + kf->F[0][1] * kf->P[1][1];kf->P[1][0] = kf->F[1][0] * kf->P[0][0] * kf->F[0][0] + kf->F[1][1] * kf->P[1][0];kf->P[1][1] = kf->F[1][0] * kf->P[0][1] * kf->F[0][1] + kf->F[1][1] * kf->P[1][1] + kf->Q[1][1];
}
// 卡尔曼滤波更新步骤
void kalmanUpdate(KalmanFilter *kf, float measurement) {// 计算卡尔曼增益float K[STATE_DIM][MEASURE_DIM];float S;// 计算卡尔曼增益S = kf->H[0][0] * kf->P[0][0] * kf->H[0][0] + kf->R[0][0];K[0][0] = kf->P[0][0] * kf->H[0][0] / S;K[1][0] = kf->P[1][0] * kf->H[0][0] / S;// 更新状态估计kf->x[0] = kf->x[0] + K[0][0] * (measurement - kf->H[0][0] * kf->x[0]);kf->x[1] = kf->x[1] + K[1][0] * (measurement - kf->H[0][0] * kf->x[0]);// 更新状态协方差矩阵kf->P[0][0] = (1 - K[0][0] * kf->H[0][0]) * kf->P[0][0];kf->P[0][1] = (1 - K[0][0] * kf->H[0][0]) * kf->P[0][1];kf->P[1][0] = -K[1][0] * kf->H[0][0] * kf->P[0][0] + kf->P[1][0];kf->P[1][1] = -K[1][0] * kf->H[0][0] * kf->P[0][1] + kf->P[1][1];
}

卡尔曼滤波的优势在于它能够提供对系统状态的最优估计,同时适应于线性和高斯噪声的系统。然而,卡尔曼滤波也有一些限制,例如对非线性系统的适应性较差,且需要对系统动态模型和噪声参数进行良好的估计。

==========

往期回顾:

移动平均滤波的原理和C代码

MOS管防反接电路

STM32的看门狗原理和示例代码

Keil仿真调试STM32与LED

HAL库常用函数汇总【不间断更新】

==========

3bc64bb9b98ecc0640c0bedb27c4f5da.png

c258de878cd5b3e34fdc62894a81aa67.png

becaa3ea0682f43d8fcfdf0535b30a24.png


http://www.ppmy.cn/news/1260354.html

相关文章

【数据结构】——二叉树简答题模板

目录 一、树和二叉树的概念&#xff08;一&#xff09;二叉树的定义和性质&#xff08;二&#xff09;树和二叉树的区别 二、完全二叉树和满二叉树三、二叉树的遍历&#xff08;一&#xff09;由序列确定二叉树&#xff08;二&#xff09;不同遍历序列的关系 四、二叉树的性质&…

html css样式选择器介绍

目录 一、单标签选择器二、多标签选择器三、类选择器四、标签结合类选择器五、多个标签结合类选择器六、子标签选择器七、所有子标签选择器八、相邻选择器九、多种选择器混合使用十、超链接样式选择器 一、单标签选择器 下面的 css 会将所有 h1 标签里的文字设置为红色 <!…

天池SQL训练营(三)-复杂查询方法-视图、子查询、函数等

-天池龙珠计划SQL训练营 SQL训练营页面地址&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicampsql 3.1 视图 我们先来看一个查询语句&#xff08;仅做示例&#xff0c;未提供相关数据&#xff09; SELECT stu_name FROM view_students_info;单从表面上看起来…

Xilinx FPGA平台DDR3设计详解(三):DDR3 介绍

本文介绍一下常用的存储芯片DDR3&#xff0c;包括DDR3的芯片型号识别、DDR3芯片命名、DDR3的基本结构等知识&#xff0c;为后续掌握FPGA DDR3的读写控制打下坚实基础。 一、DDR3芯片型​号 电路板上的镁光DDR3芯片上没有具体的型号名。 ​如果想知道具体的DDR3芯片型号&#…

从零构建属于自己的GPT系列3:模型训练2(训练函数解读、模型训练函数解读、代码逐行解读)

&#x1f6a9;&#x1f6a9;&#x1f6a9;Hugging Face 实战系列 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在PyCharm中进行 本篇文章配套的代码资源已经上传 从零构建属于自己的GPT系列1&#xff1a;数据预处理 从零构建属于自己的GPT系列2&#xff1a;模型训…

《C++ primer》 anki学习卡片txt输出101张,更新至第2章,截止2023年12月6日

C程序中{{c1::}}要有main函数 一定 不一定 一个函数定义包含哪几个部分 返回类型 函数名&#xff08;形参列表&#xff09; { 函数体 } main函数返回值为0时&#xff0c;表示{{c1::}} 成功 失败 无论你使用命令行页面或者IDE&#xff0c;大多数编译器都要求程序源码存储在一…

1-Tornado的介绍

1 tornado的介绍 **Tornado**是一个用Python编写的可扩展的、无阻塞的**Web应用程序框架**和**Web服务器**。 它是由FriendFeed开发使用的&#xff1b;该公司于2009年被Facebook收购&#xff0c;而Tornado很快就开源了龙卷风以其高性能着称。它的设计允许处理大量并发连接&…

【1day】致远 A8+ OA wpsAssistServlet任意文件读取漏洞学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现