卡尔曼滤波

原理:1、加权平均数。2、状态空间方程

例子:两个人测同一个数据,甲测出来是x_{1}满足正态分布,均值\mu_{1},方差\sigma ^{2}_{1};乙测出来是x_{2}满足正态分布,均值\mu _{2},方差\sigma _{2}^{2},那么这个数据量x应该是多少呢?

取一个加权平均数:x=kx_{1}+(1-k)x_{2}  

那么这个数的方差:\sigma ^{2}=k^{2}\sigma _{1}^{2}+(1-k)^{2}\sigma _{2}^{2}  

所以现在要求k,使得\sigma ^{2}取得最小值,那么对这个方程求导并等于0,求出当k=\frac{\sigma _{2}^{2}}{\sigma _{1}^{2}+\sigma _{2}^{2}}时使得x方差最小。

如果又测量了x_{3},那么继续用x_{3}x继续加权计算不用保留前面数据导致计算量过大,可以实时计算。

状态转移方程和观测方程方程:

                                        x_{k}=\Phi x_{k-1}+\omega _{k-1}    (1)

                                        z_{k}=Hx_{k}+v_{k}            (2)

                其中\Phi是状态转移矩阵,H是观测方程,\omega ,v是噪声

x初始方差为P\omega方差为Qv方差为R

经典卡尔曼滤波的五个方程

                                        \hat{X}_{k|k-1}=\Phi\hat{X} _{k-1}        (3)

                                        P_{k|k-1}=\Phi P_{k-1}\Phi ^{T}+Q      (4)

                                        K_{k}=P_{k|k-1}H^{T}(HP_{k|k-1}H^{T}+R)^{-1}     (5)

                                        \hat{X}_{k}=\hat{X}_{k|k-1}+K_{k}(z_{k}-H\hat{X}_{k|k-1})         (6)

                                        P_{k}=(I-K_{k}H)P_{k|k-1}                              (7-1)

                                        P_{k}=(I-K_{k}H)P_{k|k-1}(I-K_{k}H)^{T}+K_{k}RK_{k}^{T}    (7-2)

                其中式3是状态变量从k-1到k时刻的预测值;式4对应其协方差矩阵;式5求卡尔曼增益,其中HP_{k|k-1}H^{T}+R可以称为观测方程的协方差;式6更新状态变量后验值,z_{k}-H\hat{X}_{k|k-1}称为残差;式7-2更新状态变量的协方差,式7-1会有数值计算问题,可能会有奇异性,会发散。

下面是一个简单的用卡尔曼滤波求最优解的cpp例子:理想自由落体运动,1、2、3、4、5秒观测的位置是4.9、19.6、44.1、78.7、122.5,求重力加速度。

#include <Eigen/Dense>
#include <iostream>
#include <vector>
#include "matplotlibcpp.h"

using namespace Eigen;
using namespace std;
namespace plt = matplotlibcpp;

int main() {
    VectorXd h(5);
    h << 4.9, 19.6, 44.1, 78.4, 122.5;//观测量
    MatrixXd X(3, 1);//状态变量,位置、速度、加速度
    X << 0, 0, 10;//初始状态变量的值
    MatrixXd Phi0(3, 3);//状态转移矩阵
    Phi0 << 1, 0.001, 0,
            0, 1, 0.001,
            0, 0, 1;//初始状态转移矩阵值    
    MatrixXd Phi = MatrixXd::Identity(3, 3);//单位阵    
    MatrixXd P = MatrixXd::Zero(3, 3);//状态变量的协方差
    P.diagonal() << 0, 0, 0.01;//主对角线的值
    MatrixXd Q = MatrixXd::Zero(3, 3);//状态变量噪声的协方差
    double R = 0.0001;//观测噪声的方差
    RowVectorXd H(3);//观测矩阵
    H << 1, 0, 0;//观测位置

    vector<MatrixXd> data(6, MatrixXd(3, 1));
    data[0] = X;

    for (int n = 1; n <= 5000; ++n) {
        Phi = Phi0 * Phi;//状态转移过程
        if (n % 1000 == 0) {
            MatrixXd Pkk = Phi * P * Phi.transpose() + Q;//预测状态变量的协方差
            double S = (H * Pkk * H.transpose())(0, 0) + R; // 计算S, 是1x1矩阵的第一个元素加R,观测的协方差
            MatrixXd K = Pkk * H.transpose() / S; // 标量除法,计算卡尔曼增益
            P = (MatrixXd::Identity(3, 3) - K * H) * Pkk*(MatrixXd::Identity(3, 3) - K * H) .transpose()+K*R*K.transpose();//更新状态变量的协方差
            MatrixXd Xkk = Phi * X;//状态变量预测值
            double z = h((n / 1000) - 1);//观测值
            X = Xkk + K * (z - (H * Xkk)(0, 0)); // 使用(0, 0)提取矩阵第一个元素,优化残差
            data[n / 1000] = X;
            Phi = MatrixXd::Identity(3, 3);//每次都要初始化是因为状态变量的值是在有观测值的时候更新的,在观测阶段保持的状态变量值在进行下一个状态的估计时,状态转移矩阵需要从零开始
        }
    }

    // Extract data for plotting
    vector<double> plot_data;
    for (const auto& d : data) {
        plot_data.push_back(d(2, 0));  // Third component
    }

    plt::plot(plot_data);
    plt::title("Kalman Filter Results");
    plt::show();

    return 0;
}

        在卡尔曼滤波的过程中,状态变量设置的是[位置、速度、加速度],有一点值得注意的是我只用一个位置观测量却优化得到了我想要的加速度后验值,这一点是由状态空间方程的性质决定的,每个变量之间互相牵连;最终的后验值是由卡尔曼增益决定的,而卡尔曼增益又受状态变量的协方差P影响,P又受状态转移矩阵的影响,状态转移矩阵提供了各个状态变量的相互影响关系,所以经过特定的数学逻辑也就是卡尔曼滤波可以通过观测一个状态变量求出其它所有状态变量包括观测量对应的状态变量。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值