OpenCV3之卡尔曼滤波KalmanFilter原理、公式推导及其源码代码相关分析


一、适用

  • 适用于线性系统中。
  • 用于一些无法直接测量但可以间接测量的量。
    比如,火箭燃料室内的温度不能直接测量,但可以燃料室外的温度,从而据此估算燃料室内的温度。
  • 用于从受误差影响的传感器测量值中估算系统的状态。
    比如,GPS传感器测量结果是有误差。

二、理解

1.反馈系统

例如火箭燃料问题,要测量燃料室内的温度 T i n T_{in} Tin,已知火箭燃料室外的温度 T e x t T_{ext} Text和燃料的流量 W f u e l W_{fuel} Wfuel

  1. 燃料的流量 W f u e l W_{fuel} Wfuel作为输入,通过真实模型,可以输出得到真实的燃料室内的温度 T i n T_{in} Tin和火箭燃料室外的温度 T e x t T_{ext} Text
    通过数学模型,可以输出估计的燃料室内的温度 T i n ^ \hat{T_{in}} Tin^和火箭燃料室外的温度 T e x t ^ \hat{T_{ext}} Text^
  2. 比较真实的 T e x t T_{ext} Text和估计的 T e x t ^ \hat{T_{ext}} Text^,得到误差 e = T e x t − T e x t ^ e=T_{ext}-\hat{T_{ext}} e=TextText^
  3. e e e去通过控制器K修正(增益)模型。
    在这里插入图片描述
    在这里插入图片描述

2.卡尔曼滤波又叫数据融合算法

  • 假设你有两个传感器,测的是同一个信号。可是它们每次的读数都不太一样,怎么办?
    取平均

  • 再假设你知道其中贵的那个传感器应该准一些,便宜的那个应该差一些。那有比取平均更好的办法吗?
    加权平均。怎么加权?假设两个传感器的误差都符合正态分布,假设你知道这两个正态分布的方差,用这两个方差值,(此处省略若干数学公式),你可以得到一个“最优”的权重。

  • 接下来,重点来了:假设你只有一个传感器,但是你还有一个数学模型。模型可以帮你算出一个值,但也不是那么准。怎么办?把模型算出来的值,和传感器测出的值,(就像两个传感器那样),取加权平均
    OK,最后一点说明:你的模型其实只是一个步长的,也就是说,知道x(k),我可以求x(k+1)。问题是x(k)是多少呢?答案:x(k)就是你上一步卡尔曼滤波得到的、所谓加权平均之后的那个、对x在k时刻的最佳估计值。于是迭代也有了。这就是卡尔曼滤波。(无公式)

@cite https://www.zhihu.com/question/23971601/answer/26254459

3.意义

  • 预测:
    不存在神奇的深度神经网络一样推算出不可知的神奇公式,它的预测是根据你设计的公式推算出的,即 X ^ k ′ = A k X ^ k − 1 + B k U k \hat{X}_{k}'=A_k\hat{X}_{k-1}+B_kU_k X^k=AkX^k1+BkUk
  • 迭代:
    迭代的意义只是保留上一次的状态及其协方差矩阵为下一次用。并不能修改其数学模型中的公式。
  • 作用:
    所以就是用来得到一个相对噪声小的目标状态值,没有什么神奇的预测还是别的作用。

三、公式推导

1.过程

  1. 预测:由k-1时刻的最优的状态估计 x ^ k − 1 \hat{x}_{k-1} x^k1,得出k时刻的预测的状态估计 x ^ k ′ \hat{x}'_{k} x^k
    【先验估计的状态向量】 X ^ k ′ = A k X ^ k − 1 + B k U k \hat{X}_{k}'=A_k\hat{X}_{k-1}+B_kU_k X^k=AkX^k1+BkUk
    【先验估计的状态向量的协方差矩阵】 P k ′ = A k P k − 1 A k T + Q k P_k'=A_kP_{k-1}A_k^T+Q_k Pk=AkPk1AkT+Qk
  2. 处理测量:由传感器得出k时刻的测量值 z k z_k zk
  3. 融合并更新:融合 x ^ k ′ \hat{x}'_{k} x^k z k z_k zk,得到k时刻的最优的状态估计 x ^ k \hat{x}_{k} x^k
    【卡尔曼增益】 K k = P k ′ H k T ( H k P k ′ H k T + R k ) − 1 K_k=P_k'H_k^T(H_kP_k'H_k^T+R_k)^{-1} Kk=PkHkT(HkPkHkT+Rk)1
    【最优的状态估计】 X ^ k = X ^ k ′ + K k ( Z k − H k X ^ k ′ ) \hat{X}_{k}=\hat{X}_{k}'+K_k(Z_k-H_k\hat{X}_{k}') X^k=X^k+Kk(ZkHkX^k)
    【最优的状态估计的协方差】 P k = P k ′ − K k H k P k ′ = P k ′ ( I − K k H k ) P_k=P_k'-K_kH_kP_k'=P_k'(I-K_kH_k) Pk=PkKkHkPk=Pk(IKkHk)

在这里插入图片描述

2.公式用到的变量

()内对应KalmanFilter的变量

(1)定义三个列向量

  • 状态向量 X k X_k Xk(state)
  • 测量向量 Z k Z_k Zk(measurement)
  • 控制向量 U k U_k Uk(control)

(2)三个矩阵

  • 状态转移矩阵 A k A_k Ak(transitionMatrix)
  • 控制矩阵 B k B_k Bk(controlMatrix)
  • 测量矩阵 H k Hk Hk(measurementMatrix)

(3)估计的状态向量及其协方差

k-1时刻:

  • 后验估计的状态向量 X ^ k − 1 \hat{X}_{k-1} X^k1(statePost):k-1时刻的最优的状态估计
  • 后验估计的状态向量的协方差矩阵 P k − 1 P_{k-1} Pk1(errorCovPost):k-1时刻的最优的状态估计的协方差

k时刻的:

  • 先验估计的状态向量 X ^ k ′ \hat{X}'_k X^k(statePre):k时刻的预测的状态估计
  • 先验估计的状态向量的协方差矩阵 P k ′ P_{k}' Pk(errorCovPre):k时刻的预测的状态估计的协方差
  • 最优的状态估计 X ^ k \hat{X}_{k} X^k(statePost):求出k时刻的最优的状态估计,就把statePost更新为此值
  • 最优的状态估计的协方差 P k {P}_{k} Pk(errorCovPost):求出k时刻的最优的状态估计的协方差,就把errorCovPost更新为此值

(4)噪声及其协方差矩阵

  • 系统噪声 W k W_k Wk:其协方差为 Q k Q_k Qk(processNoiseCov)
  • 测量噪声 V k V_k Vk:其协方差为 R k R_k Rk(measurementNoiseCov)

(5)卡尔曼增益

  • 卡尔曼增益 K k K_k Kk(gain)

3.公式意思

比如计算匀速直线运动下的角度变化。
状态 X k = [ θ δ θ ] X_k=\begin{bmatrix} \theta \\ \delta \theta \end{bmatrix} Xk=[θδθ],表示角度和角度变化量
状态转移矩阵 A k = [ 1 1 0 1 ] A_k=\begin{bmatrix} 1 & 1\\ 0 & 1 \end{bmatrix} Ak=[1011]
X ^ k ′ = A k ∗ X ^ k − 1 = [ θ + δ θ δ θ ] \hat{X}_{k}'=A_k*\hat{X}_{k-1}=\begin{bmatrix} \theta+\delta \theta \\ \delta \theta \end{bmatrix} X^k=AkX^k1=[θ+δθδθ]

4.对应代码部分

(1)预测predict

【先验估计的状态向量】 X ^ k ′ = A k X ^ k − 1 + B k U k \hat{X}_{k}'=A_k\hat{X}_{k-1}+B_kU_k X^k=AkX^k1+BkUk

// 得出先验估计的状态向量statePre: X'(k) = A*X(k-1)
statePre = transitionMatrix * statePost;

// 得出先验估计的状态向量statePre的后部分:X'(k) += Bk*Uk
if (!control.empty())
    statePre += controlMatrix * control;

【先验估计的状态向量的协方差矩阵】 P k ′ = A k P k − 1 A k T + Q k P_k'=A_kP_{k-1}A_k^T+Q_k Pk=AkPk1AkT+Qk

// temp1 = A*P(k-1)
temp1 = transitionMatrix * errorCovPost;

// P'(k) = temp1*A.t + Q
// errorCovPre = 1 * temp1 * transitionMatrix.t() + 1 * processNoiseCov
gemm(temp1, transitionMatrix, 1, processNoiseCov, 1, errorCovPre, GEMM_2_T);

(2)融合更新correct

【卡尔曼增益】 K k = P k ′ H k T ( H k P k ′ H k T + R k ) − 1 K_k=P_k'H_k^T(H_kP_k'H_k^T+R_k)^{-1} Kk=PkHkT(HkPkHkT+Rk)1

/* 这是在算括号里求逆的部分 */
// temp2 = H*P'(k)
temp2 = measurementMatrix * errorCovPre;

// temp3 = temp2*H.t + R
// temp3 = 1 * temp2 * measurementMatrix.t() + 1 * measurementNoiseCov
gemm(temp2, measurementMatrix, 1, measurementNoiseCov, 1, temp3, GEMM_2_T);

/* 算Kk */
// temp4 = inv(temp3)*temp2,这是最小二乘法求逆再乘
solve(temp3, temp2, temp4, DECOMP_SVD);

// K(k) = temp4.t()是因为A=BC,A.t()=C.t()*B.t()
gain = temp4.t();

【最优的状态估计】 X ^ k = X ^ k ′ + K k ( Z k − H k X ^ k ′ ) \hat{X}_{k}=\hat{X}_{k}'+K_k(Z_k-H_k\hat{X}_{k}') X^k=X^k+Kk(ZkHkX^k)

// 括号里的部分
// temp5 = Z(k)-H*X'(k)
temp5 = measurement - measurementMatrix * statePre;

// 最优的状态估计:X(k) = X'(k) + K(k)*temp5
statePost = statePre + gain * temp5;

【最优的状态估计的协方差】 P k = P k ′ − K k H k P k ′ = P k ′ ( I − K k H k ) P_k=P_k'-K_kH_kP_k'=P_k'(I-K_kH_k) Pk=PkKkHkPk=Pk(IKkHk)

// P(k) = P'(k) - K(k)*temp2
errorCovPost = errorCovPre - gain * temp2;

四、KalmanFilter Class

class CV_EXPORTS_W KalmanFilter
{
public:    
    CV_WRAP KalmanFilter();        
	
	/** @overload
    @param dynamParams 状态向量state的维度
    @param measureParams 测量向量measurement的维度
    @param controlParams 控制向量control的维度
    @param type 这三个向量的Mat类型应该是CV_32F or CV_64F
    */
    CV_WRAP KalmanFilter(int dynamParams, int measureParams, int controlParams=0, int type=CV_32F);
    
    /** @brief 重新初始化KalmanFilter对象,会替换原来的KF对象,原先的被扔掉
     */
    void init(int dynamParams, int measureParams, int controlParams=0, int type=CV_32F);              
  	
  	/** @brief 计算预测的状态值

    @param control 预测,计算先验估计的状态向量及其协方差矩阵
    @discuss
    调用完后,KF.statePre即为k时刻的先验估计的状态向量(预测值),
    直接调用这个值或者返回值(返回得也是这个值,但没必要多保存一个矩阵),
    errorCovPre就是k时刻的先验估计的状态向量(预测值)的协方差矩阵
     */
    const Mat& predict(const Mat& control=Mat());
    
    /** @brief 根据测量向量,融合计算最优的状态估计,并更新状态值

    @param measurement 测量向量
    @discuss
    调用完后,KF.gain即为k时刻的卡尔曼增益,
    KF.statePost即为k时刻最优的状态估计值,
    直接调用这个值或者返回值(返回得也是这个值,但没必要多保存一个矩阵),
    errorCovPost就是k时刻最优的状态估计值的协方差矩阵
     */
    const Mat& correct(const Mat& measurement);
 
 	/* 两个估计的状态向量:先验估计的状态向量(statePre)和后验估计的状态向量(statePost) */
    Mat statePre;            // 先验估计的状态向量
    Mat statePost;           // 后验估计的状态向量
    
    /* 三个矩阵 */
    Mat transitionMatrix;    // 状态转移矩阵 A
    Mat controlMatrix;       // 控制矩阵 B
    Mat measurementMatrix;   // 测量矩阵 H
    
  	/* 两个噪声的协方差矩阵 */ 
    Mat processNoiseCov;     // 系统噪声的协方差矩阵 Q
    Mat measurementNoiseCov; // 测量噪声的协方差矩阵 R

	/* 两个估计状态向量的协方差矩阵 */
    Mat errorCovPre;         // 先验估计状态向量的协方差矩阵 
    Mat errorCovPost;        // 后验估计状态向量的协方差矩阵 

	/* 一个增益 */
    Mat gain;                // 卡尔曼增益
    
 
    // 计算过程中的中间变量
    Mat temp1;	// A*P(k-1)
    Mat temp2;	// H*P'(k)
    Mat temp3;	// 卡尔曼增益括号里求逆的部分
    Mat temp4;	// 卡尔曼增益的转置
    Mat temp5;	// 最优的状态估计括号里的部分
};

五、魔改例子

OpenCV3之卡尔曼滤波KalmanFilter例子魔改代码


参考:

学习OpenCV2——卡尔曼滤波(KalmanFilter)详解
要点初见:反用OpenCV3中的卡尔曼滤波器(KalmanFilter)进行运动预测
学习OpenCV——Kalman滤波
OpenCV里卡尔曼滤波的理解
官网文档:cv::KalmanFilter Class Reference
官网例子:samples/cpp/kalman.cpp
详解卡尔曼滤波原理
如何通俗并尽可能详细地解释卡尔曼滤波?

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值