跳转至

卡尔曼滤波器

理论

卡尔曼滤波基于线性、高斯系统的假设,能够利用前一时刻的状态(和可能的测量值)来得到当前时刻下的状态的最优估计。算法由预测、更新(校正)两步骤组成,既能够基于状态空间模型进行状态预测,本质上又是一个数据融合算法。

概述

以状态空间的形式描述一个线性高斯系统,下标表示时刻:

(1)xk=Axk1+Buk+wk1(2)zk=Hxk+vk

其中 A,B 分别表示状态转移矩阵和控制量输入矩阵,H 表示状态观测矩阵; xk 为系统状态量矩阵,zk 为实测得到的状态量矩阵 ;引入高斯分布,wk1 表示过程噪声(理论模型与现实模型的误差),vk 表示观测噪声(量测与现实数据的误差),分别满足 P(w)N(0,Q),P(v)N(0,R),其中 Q 表示过程噪声协方差, R 表示观测噪声协方差。

为区分状态的多种表示,定义以下符号:

xk:x^k measure:x^k:x^k:

现实中我们并不知道噪声的实际值,但我们可以通过迭代优化,逼近最优的状态估计。由 (1) 式,将状态预测方程表示为:

(a)x^k=Ax^k1+Buk

(2) 式,由当下的状态量观测初步得到一个状态估计:

x^k measure=H1zk

由于噪声的存在,x^kx^k measure 都不能准确表示当下的状态,我们采用一个朴素的思想,即对这两者进行加权平均。状态最优估计方程:

x^k=x^k+G(x^k measurex^k)

其中系数 G=0 时,完全相信状态预测;系数 G=1 时,完全相信状态观测。记 G=KH,上式化为:

(b)x^k=x^k+K(zkHx^k)

此处 K[0,H1] 即为卡尔曼增益,求取状态最优估计的问题转化为求取最优 K 的问题。

卡尔曼增益

我们希望最优估计与实际值误差最小,即后验估计误差 ek=xkx^k 绝对值最小。引入后验估计误差的协方差矩阵 Pk=E[ekekT],对 n 个状态变量相互独立,有:

P=[cov(e1,e1)...cov(e1,en).........cov(en,e1)...cov(en,en)]=[σ1e120...00σ2e22...0............00...σnen2]

卡尔曼增益最优问题可转化为求 Kk 使得 tr(Pk) 最小,思路为对 tr(Pk) 求导并令结果为 0 ,进而用其他量表示 Kk。以下进行求解。

(2)(b) 式,有:

x^k=x^k+K(Hxk+vkHx^k)x^k=x^kKH(xkx^k)Kvkxkx^k=xkx^kKH(xkx^k)Kvkek=(IKH)ekKvk

经计算得到:

(3)Pk=E[ekekT]=PkKkHPkPkHTKkT+Kk(HPkHT+R)KkT

tr(Pk)Kk 求导,经计算得到:

tr(Pk)Kk=2PkTHT+2KHPkHT+2KR0

则卡尔曼增益为:

(c)Kk=PkHTHPkHT+R

观察上式可知,观测噪声协方差 R 越小,增益越大,越相信状态观测值;R 越大,越相信状态预测值。

卡尔曼滤波

先验估计误差 ek=xkx^k ,其协方差矩阵 Pk=E[ekekT]。由 (1)(a) 式,,有:

ek=Axk1+Buk+wk1Ax^k1Buk=Aek1+wk1

(c) 式,为得到 Kk,计算先验估计协方差 Pk ,并化简得到:

Pk=E[(Aek1+wk1)(Aek1+wk1)T]=AE[ek1ek1T]AT+E[wk1wk1T](d)=APk1AT+Q

需要上一时刻的后验协方差 Pk1. 进一步联立 (3)(c) 式,计算 Pk

Pk=PkKkHPkPkHTKkT+PkHTHPkHT+R(HPkHT+R)KkT(e)=(IKkH)Pk

此时 (a)(e) 五式形成了迭代预测、更新的关系。此五式即为完整的卡尔曼滤波算法:

x^k=Ax^k1+BukPk=APk1AT+QKk=PkHTHPkHT+Rx^k=x^k+Kk(zkHx^k)Pk=(IKkH)Pk

其中,预测部分将后验状态估计和后验协方差从 k1 时刻推向 k 时刻,形成预测;更新部分首先计算卡尔曼增益,根据该增益,参考状态预测值和观测值,得到状态后验估计,然后更新后验协方差。该过程不断循环;初始状态下,需要给出 x^0P0

观测数据融合

由于卡尔曼滤波的本质是数据融合,在没有状态空间模型的情况下,若有两个观测器对同一个状态进行观测,产生两组数据,则它们也可以通过卡尔曼滤波的思想进行融合。此时,A=I,B=0,H=I,算法简化为:

x^k=Data1Pk=Pk1+QKk=Pk|k1(Pk|k1+R)1x^k=x^k|k1+Kk(Data2x^k)Pk=(IKk)Pk

参数调整

A,BH 基于状态空间模型设置。

实际实现时,观测噪声协方差 R 一般可以观测到;但过程噪声协方差 Q 较难确定。根据上文,调参的一个基本原则是 R 越小,越相信状态观测值;Q 越小,越相信状态预测值。一般给 Q 一个较小的值有助于更方便地调整 R

调整后验估计误差协方差初值 P0 时,一般给一个较小的初值有利于更快收敛。运行时,若参数逐步收敛并保持为常量,则滤波器系数可以参考此结果进行调整,以期在后续在线运行时获得更好的收敛效率。

此外,可以在运行时根据模型的实际情况改变 Q,R 的值。

快速开始

组件源码仓库地址:https://github.com/ZJU-HelloWorld/HW-Components

要在项目中使用该组件,需添加仓库内的以下文件:

Text Only
1
2
3
4
algorithms/filter.c
algorithms/filter.h
tools.h
system.h

使用前准备

本组件涉及 CMSIS-DSP 矩阵运算等操作。

使用本组件前需要做以下准备:

  • 添加源文件, 包含头文件路径;注意 DSP 版本须在 1.10.0 及以上
  • 添加预处理宏以开启浮点运算单元(FPU)
  • 在使用 STM32CubeMX 生成项目时,请在 Code Generator 界面 Enable Full Assert,来帮助断言设备驱动中的错误;在 main.c 中修改 assert_failed 函数以指示断言结果,如添加 while(1);
  • system.hsystem options: user config 处进行系统设置

示例

在项目中引用头文件:

C
#include "filter.h"

实例化一个卡尔曼滤波器:

指定状态维度、滤波器类型和各矩阵初值,初始化卡尔曼滤波器。

注意以下几点:

  • 若有状态空间模型,需要 x^0,P0,Q,R,A,B,H 七组矩阵数据;若为 2 传感器数据融合,需要 x^0,P0,Q,R 四组矩阵数据。
  • 注意矩阵维度,注意协方差矩阵均为对角阵
  • 矩阵数据的排列顺序:从左至右,从上到下。
C
1
2
3
4
5
6
7
8
float x[2] = {0, 1};
float p[4] = {1, 0, 0, 1};
float q[4] = {1.00, 0, 0, 1.00};
float r[4] = {0.1, 0, 0, 0.1};
float a[4] = {1, 1, 0, 1};
float b[4] = {0, 0, 0, 0};
float h[4] = {1, 0, 0, 1};
KfInit(&kf, 2, KF_MODEL_BASED, x, p, q, r, a, b, h);
C
1
2
3
4
5
float x[2] = {0, 1};
float p[4] = {1, 0, 0, 1};
float q[4] = {1.00, 0, 0, 1.00};
float r[4] = {0.1, 0, 0, 0.1};
KfInit(&kf, 2, KF_SENSOR_FUSION, x, p, q, r);

对于 KF_MODEL_BASED 模式,调用控制量设定方法以及预测方法,获得状态量预测值;对于 KF_SENSOR_FUSION 模式,传入第一个传感器观测状态量的数组指针,得到初步状态估计值。如:

C
1
2
3
kf.setU(&kf, u);
kf.predict(&kf);
kf.getX(&kf, x_prediction);
C
kf.predict(&kf, data1);
kf.getX(&kf, x_prediction);

传入(另一个)传感器观测状态量数组指针,调用更新方法,可获得状态量后验估计,如:

C
kf.update(&kf, z);
kf.getX(&kf, x_estimation);
C
kf.update(&kf, data2);
kf.getX(&kf, x_estimation);

组件说明

Kf

线性卡尔曼滤波器。

属性

名称 类型 示例值 描述
type KfType_t KF_MODEL_BASED
KF_SENSOR_FUSION
滤波器类型
x_dim uint8_t 2 状态维度
x_x1d, P_xxd, Q_xxd, R_zzd, A_xxd, B_xxd, u_x1d, H_zxd arm_matrix_instance_f32 / 各种参数矩阵

方法

名称 参数说明 描述
KfInit 按声明要求传入状态维度、滤波器类型和各矩阵初值等参数 按指定的类型和给定的数据,初始化一个卡尔曼滤波器
predict (仅 KF_SENSOR_FUSION 类型)传入另一组 float* 观测量数组地址 运行卡尔曼滤波预测部分
update 传入 float* 观测量数组地址 根据传入的观测量,运行卡尔曼滤波更新部分
getX 传入 float* 数组地址,用于存储状态量 返回当前状态量
setU (仅 KF_MODEL_BASED 类型)传入 float* u 控制量数组地址 设置控制量
setQ 传入 float* Q 矩阵数组地址 设置过程噪声协方差 Q 矩阵
setR 传入 float* R 矩阵数组地址 设置观测噪声协方差 R 矩阵

附录

版本说明

版本号 发布日期 说明 贡献者
2023.4.11 完成卡尔曼滤波说明文档 薛东来

参考资料

[1] 卡尔曼滤波器介绍

[2] DR_CAN 视频 文档

此页面如何?