扩展卡尔曼滤波技术(Extended Kalman Filter,EKF)

一、概念介绍

卡尔曼滤波是一种高效率的递归滤波器(自回归滤波器), 它能够从一系列的不完全包含噪声的测量中,估计动态系统的状态,然而简单的卡尔曼滤波必须应用在符合高斯分布的系统中。

扩展卡尔曼滤波就是为了解决非线性问题,普通卡尔曼滤波只能应用于线性空间的问题。当系统为线性高斯模型时,滤波器能给出最优的估计,但是实际系统总是存在不同程度的非线性,如平方、三角关系、开方等。对于非线性系统,可以采用的一种方法是通过线性化方法将非线性系统转换为近似的线性系统,即为EKF,核心思想是:围绕滤波值将非线性函数展开成泰勒级数并略去二阶及以上项,得到一个近似的线性化模型,然后应用卡尔曼滤波完成状态估计。

卡尔曼滤波是贝叶斯滤波的一个特例。(当贝叶斯滤波中系统状态的置信度分布符合高斯分布时,贝叶斯滤波=卡尔曼滤波)

二、数学表达

系统定义为:

  • 线性运动方程: $x_k=Ax_{k-1}+Bv_k+Gw_k,k=1,\ldots,K$
  • 非线性运动方程:$x_k=f(x_{k-1},v_k)+w_k$
  • 线性观测方程: $y_k=C_kx_k+n_k,k=1,\ldots,K$
  • 非线性观测方程:$y_k=h(x_k)+n_k$
  • 初始条件: $x_0\sim N(\check{x_0},\check{P_0}),w_k\sim N(0,Q),n_k\sim N(0,R)$

并使用\check{\left ( \cdot \right )}表示先验,\hat{\left ( \cdot \right )}表示后验(即最佳估计值)。

1、线性卡尔曼滤波

预测

  • 先验状态估计:

\check{x}=A\hat{x_{k-1}}+Bv_k

  • 先验误差协方差:

\check{P_k}=\hat{AP_{k-1}A^T}+GQG^T

校正

  • 卡尔曼增益:

K_k=\check{P}_kC_k^T(C_k\check{P}_kC_k^T+R)^{-1}

更新

  • 更新后验状态估计:

\hat{x_k}=\check{x_k}+K_k(y_k-C_k\check{x_k})

  • 更新后验误差协方差:

\hat{P_k}=(I-K_kC_k)\check{P_k}

2、扩展卡尔曼滤波

非线性方程线性化

非线性的状态方程和观测方程表示为如上所示,符合正态分布的噪声数据在经过非线性转换后不再是正态分布的随机变量了,此处使用近似处理: 假设噪声符合上述正态分布,而且它们为相互独立、正态分布的白噪声(即把噪声从非线性函数中拿出来)。在后续的线性化过程中,这部分因为以上近似而产生的偏差会得到恢复 (近似地恢复) 。

对以上非线性方程(状态方程和观测方程)进行线性化,具体方法为一阶泰勒展开,忽略高阶项:

$ x_k\approx\check{x}_k+A_{k}(x_{k-1}-\hat{x}_{k-1})+W_kw_k $
$y_k\approx\check{y}_k+H_k(x_k-\check{x}_k)+V_kv_k$

其中:
$A_k$$k$时刻$f$$x$的雅克比矩阵;

$H_k$$k$时刻$h$$x$的雅克比矩阵;

$W_k$$k$时刻$f$$w$的雅克比矩阵;

$V_k$$k$时刻$h$$\upsilon$的雅克比矩阵。

\begin{aligned}&A_{k}=\frac{\partial f(x_{k-1},v_k,w_k)}{\partial x_{k-1}}|_{\hat{x_{k-1}},v_k,0} \\&H_k=\frac{\partial h(x_k,n_k)}{\partial x_k}|_{\check{x_k},0} \\&W_{k}=\frac{\partial f(x_{k-1},v_k,w_k)}{\partial w_{k-1}}|_{\hat{x_{k-1}},v_k,0} \\&V_k=\frac{\partial h(x_k,n_k)}{\partial v_k}|_{\check{x_k},0} \end{aligned}

预测

  • 先验状态估计:

\check{x}=f(\hat{x_{k-1}},v_k,0)

  • 先验误差协方差:

\check{P_k}=A_{k}\hat{P_{k-1}}A_{k}^T+W_{k}QW_{k}^T

校正

  • 卡尔曼增益:

K_k=\check{P}_kH_k^T(H_k\check{P}_kH_k^T+V_{k}RV_{k}^T)^{-1}

更新

  • 更新后验状态估计:

\hat{x_k}=\check{x_k}+K_k(y_k-h(\check{x_k},0))

  • 更新后验误差协方差:

\hat{P_k}=(1-K_kH_k)\check{P_k}

三、应用总结

滤波器针对的问题是如何通过数据来估计自身状态。因此,可以有很多应用场景。

与线性不同,扩展卡尔曼滤波器通常不是最佳估计器(如果测量和状态转换模型都是线性的,则它是最佳的,因为在这种情况下,扩展卡尔曼滤波器与常规滤波器相同)。此外,如果状态的初始估计是错误的,或者如果过程建模不正确,则由于其线性化,滤波器可能会很快发散。扩展卡尔曼滤波器的另一个问题是估计的协方差矩阵往往会低估真实的协方差矩阵,因此在不添加“稳定噪声”的情况下可能会在统计意义上 变得不一致 。更一般地,我们应该考虑非线性滤波问题的无限维性质以及简单均值和方差-协方差估计器不足以完全表示最优滤波器。还应该注意的是,即使对于非常简单的一维系统,扩展卡尔曼滤波器也可能表现不佳。在这种情况下,可以考虑 其他一般的非线性滤波方法。

EKF 方法是解决 SLAM 问题的一种经典方法,其应用依赖于运动模型和观测模型的高斯噪声假设。EFK在数据融合上有很广泛的应用,相对于优化的方法,基于EKF的方法精度虽然较低但是计算效率更高。

四、代码实践

参考资料[2][3]中都含有二维平面小车状态估计的仿真,非常值得看。这里放一下扩展卡尔曼滤波的C++实现,参考[4]。

kalman_filter.cpp

#include <iostream>
#include "kalman_filter.h"

#define PI 3.14159265

using namespace std;
using Eigen::MatrixXd;
using Eigen::VectorXd;

KalmanFilter::KalmanFilter() {}

KalmanFilter::~KalmanFilter() {}

void KalmanFilter::Init(VectorXd &x_in, MatrixXd &P_in, MatrixXd &F_in,
                        MatrixXd &H_in, MatrixXd &R_in, MatrixXd &Q_in) {
  x_ = x_in;
  P_ = P_in;
  F_ = F_in;
  H_ = H_in;
  R_ = R_in;
  Q_ = Q_in;
}

void KalmanFilter::Predict() {
  //Use the state using the state transition matrix
  x_ = F_ * x_;
  //Update the covariance matrix using the process noise and state transition matrix
  MatrixXd Ft = F_.transpose();
  P_ = F_ * P_ * Ft + Q_;

}

void KalmanFilter::Update(const VectorXd &z) {

  MatrixXd Ht = H_.transpose();
  MatrixXd PHt = P_ * Ht;

  VectorXd y = z - H_ * x_;
  MatrixXd S = H_ * PHt + R_;
  MatrixXd K = PHt * S.inverse();

  //Update State
  x_ = x_ + (K * y);
  //Update covariance matrix
  long x_size = x_.size();
  MatrixXd I = MatrixXd::Identity(x_size, x_size);  
  P_ = (I - K*H_) * P_;

}

void KalmanFilter::UpdateEKF(const VectorXd &z) {
  
  float px = x_(0);
  float py = x_(1);
  float vx = x_(2);
  float vy = x_(3);
  
  //Convert the predictions into polar coordinates
  float rho_p = sqrt(px*px + py*py);
  float theta_p = atan2(py,px);

  if (rho_p < 0.0001){
    cout << "Small prediction value - reassigning Rho_p to 0.0005 to avoid division by zero";
    rho_p = 0.0001;
  }
    
  float rho_dot_p = (px*vx + py*vy)/rho_p;

  VectorXd z_pred = VectorXd(3);
  z_pred << rho_p, theta_p, rho_dot_p;

  VectorXd y = z - z_pred;
  
  //Adjust the value of theta if it is outside of [-PI, PI]
  if (y(1) > PI){
    y(1) = y(1) - 2*PI;
  }

  else if (y(1) < -PI){
    y(1) = y(1) + 2*PI;
  }

  MatrixXd Ht = H_.transpose();
  MatrixXd PHt = P_ * Ht;

  MatrixXd S = H_ * PHt + R_;
  MatrixXd K = PHt * S.inverse();

  //Update State
  x_ = x_ + (K * y);
  //Update covariance matrix
  long x_size = x_.size();
  MatrixXd I = MatrixXd::Identity(x_size, x_size);  
  P_ = (I - K*H_) * P_;
}

kalman_filter.h

#ifndef KALMAN_FILTER_H_
#define KALMAN_FILTER_H_
#include "Eigen/Dense"

class KalmanFilter {
public:

  // state vector
  Eigen::VectorXd x_;

  // state covariance matrix
  Eigen::MatrixXd P_;

  // state transition matrix
  Eigen::MatrixXd F_;

  // process covariance matrix
  Eigen::MatrixXd Q_;

  // measurement matrix
  Eigen::MatrixXd H_;

  // measurement covariance matrix
  Eigen::MatrixXd R_;

  /**
   * Constructor
   */
  KalmanFilter();

  /**
   * Destructor
   */
  virtual ~KalmanFilter();

  /**
   * Init Initializes Kalman filter
   * @param x_in Initial state
   * @param P_in Initial state covariance
   * @param F_in Transition matrix
   * @param H_in Measurement matrix
   * @param R_in Measurement covariance matrix
   * @param Q_in Process covariance matrix
   */
  void Init(Eigen::VectorXd &x_in, Eigen::MatrixXd &P_in, Eigen::MatrixXd &F_in,
      Eigen::MatrixXd &H_in, Eigen::MatrixXd &R_in, Eigen::MatrixXd &Q_in);

  /**
   * Prediction Predicts the state and the state covariance
   * using the process model
   * @param delta_T Time between k and k+1 in s
   */
  void Predict();

  /**
   * Updates the state by using standard Kalman Filter equations
   * @param z The measurement at k+1
   */
  void Update(const Eigen::VectorXd &z);

  /**
   * Updates the state by using Extended Kalman Filter equations
   * @param z The measurement at k+1
   */
  void UpdateEKF(const Eigen::VectorXd &z);

};

#endif /* KALMAN_FILTER_H_ */

参考资料

[1]扩展卡尔曼滤波(EKF)代码实战 - 小小市民的文章 - 知乎
https://zhuanlan.zhihu.com/p/161886906

[2]扩展卡尔曼滤波器实例与推导 - 西湖大学无人系统的文章 - 知乎
https://zhuanlan.zhihu.com/p/550160197

[3]扩展卡尔曼滤波算法及仿真实例_扩展卡尔曼滤波示例-CSDN博客

[4]GitHub - shazraz/Extended-Kalman-Filter: Implementation of an EKF in C++

[5]网络资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/225693.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Socks VS HTTP 谁才是最快的代理协议

目录 前言 一、Socks代理协议 二、HTTP代理协议 三、Socks代理协议和HTTP代理协议的比较 1. 性能 2. 安全性 3. 灵活性 4. 应用场景 四、哪一个更快&#xff1f; 五、总结 前言 在网络传输中&#xff0c;代理协议扮演着非常重要的角色。Socks协议和HTTP协议是两种常…

探索正则可视化工具:让编程更直观、高效

导语&#xff1a;在当今的编程世界中&#xff0c;正则表达式已成为不可或缺的技能。然而&#xff0c;理解和编写正则表达式往往是一项具有挑战性的任务。为了降低门槛&#xff0c;提高编程效率&#xff0c;正则可视化工具应运而生。 一、正则表达式的简介与历史 正则表达式&a…

Failed to resolve org.junit.platform:junit-platform-launcher:1.9.3

springboot 跑 unit test 的时候&#xff0c;如果报错如题的话&#xff0c;可以更改idea 里的 Settings ——> HTTP Proxy 配置为&#xff1a;Auto-detect proxy settings

2023 CCF中国软件大会(CCF ChinaSoft)“软件定义汽车”论坛成功召开

2023年12月1日下午&#xff0c;2023年度CCF中国软件大会“软件定义汽车”论坛成功召开。 本次论坛由华东师范大学蒲戈光教授、武汉光庭信息技术股份有限公司朱敦尧董事长以及华东师范大学张越龄副教授联合组织举办。论坛主要关注汽车的智能网联化与电动化的融合&#xff0c;包括…

【Android Studio】【入门】helloworld和工程的各个文件的作用

这里写目录标题 可以开发的app类型注意点 搞一个helloworld玩玩各个文件的作用 可以开发的app类型 Phone and Tablet&#xff1a;开发手机和平板的app&#xff1b;Wear OS&#xff1a;穿戴系统&#xff1b;TV&#xff1a;电视app&#xff1b;Android Auto&#xff1a;汽车上的…

Java API接口强势对接:构建高效稳定的系统集成方案

文章目录 1. Java API接口简介2. Java API接口的优势2.1 高度可移植性2.2 强大的网络通信能力2.3 多样化的数据处理能力 3. 实战&#xff1a;Java API接口强势对接示例3.1 场景描述3.2 用户管理系统3.3 订单处理系统3.4 系统集成 4. 拓展&#xff1a;Java API接口在微服务架构中…

ROS 动态坐标变换

在ROS 中&#xff0c;坐标变换是一个重要的概念&#xff0c;因为它允许系统中的不同节点和模块以统一的方式描述物体的位置和方向。 动态坐标变换指的是当机器人或其环境中物体的位姿&#xff08;位置和姿态&#xff09;发生变化时&#xff0c;能够实时更新这些信息的过程。 …

Linux---进程管理

本章主要介绍RHEL8中如何管理并查看进程。 了解进程并查看系统中存放的进程了解进程的信号进程优先级设置 进程介绍 在 Windows中打开任务管理器就可以查看到系统中的所有进程&#xff0c;如图下图所示。 这里列出了系统中所有的进程&#xff0c;不过也可以使用命令行工具来…

学生成绩的增删改查

接上一篇MySQL数据库与其管理工具Navicat link 1.下载JDBC 可以登录MySQL的官方网站&#xff1a;www.mysql.com&#xff0c;下载JDBC-MySQL数据库驱动&#xff08;JDBC Driver for MySQL&#xff09;下载mysql-connector-java-5.1.40.zip后&#xff0c;将该zip文件解压至硬盘&a…

html和css写去哪儿导航条

目录 1、css代码 2、html代码 3、效果图 1、css代码 * {padding: 0;margin: 0;list-style: none;text-decoration: none;}.nav {height: 50px;background-color: rgb(36, 210, 188);margin-top: 50px;padding-left: 20px;}li {float: left;width: 75px;line-height: 50px;tex…

【EI会议征稿-ACM出版】2023年信息化教育与人工智能国际学术会议(ICIEAI 2023)

2023年信息化教育与人工智能国际学术会议&#xff08;ICIEAI 2023&#xff09; 2023 International Conference on Information Education and Artificial Intelligence 2023年12月22-24日 中国-厦门 2023年信息化教育与人工智能国际学术会议&#xff08;ICIEAI 2023&#xf…

8. 信号基础

8. 信号基础 1. 基本概念1.1 信号的目的是用来通信的1.2 信号由谁处理、怎么处理1.3 信号是异步的 2. 信号的分类2.1 可靠信号和不可靠信号2.2 实时信号和非实时信号 3. 进程对信号的处理3.1 signal()3.2 sigaction()3.2.1 struct sigaction3.2.2 实例 4. 向进程发送信号4.1 ki…

欧拉操作系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 这个章节主要是介…

微信小程序中生命周期钩子函数

微信小程序 App 的生命周期钩子函数有以下 7 个&#xff1a; onLaunch(options)&#xff1a;当小程序初始化完成时&#xff0c;会触发 onLaunch&#xff08;全局只触发一次&#xff09;。onShow(options)&#xff1a;当小程序启动或从后台进入前台显示时&#xff0c;会触发 on…

CSS属性 display和visibility的区别

在CSS中&#xff0c;有两种让元素隐藏的方式&#xff0c;分别是display和visibility&#xff0c;他们有什么区别呢&#xff1f; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"…

[Kubernetes]1.Kubernetes(K8S)介绍,基于腾讯云的K8S环境搭建集群以及裸机搭建K8S集群

一. Kubernetes(K8S)简介 Kubernetes (K8S) 是一个为 容器化应用 提供 集群部署 和 管理 的开源工具,和docker swarm类似,由 Google 开发. Kubernetes 这个名字源于希腊语,意为 “ 舵手 ” 或 “ 飞行员 ” , k8s 这个缩写是因为 k 和 s 之间有八个字符的关系, Google…

echarts 柱状图 定时自动轮播(非提示框轮播)

看了很多文档都是实现提示框轮播的&#xff0c;而我要实现的功能是&#xff1a;柱状图有多条数据时&#xff0c;轮播展示其中几条&#xff0c;比如我有100条数据&#xff0c;不能全部展示&#xff0c;设置轮播5条或者10条&#xff0c;依次显示数据&#xff0c;并形成闭环。 &a…

远程服务器——如何在Conda中安装R环境

目录 1. R的安装2. VScode 配置参考文献 1. R的安装 推荐使用anaconda或者miniconda&#xff0c;创建虚拟环R_env境然后安装R&#xff1b; 使用conda search r-base查看可下载的R的版本&#xff1b;R版本比较低&#xff0c;一般可以先增加源&#xff1a; % 增加源 conda con…

鸿蒙开发ArkTS语言—状态管理概述

概述 我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面&#xff0c;就需要引入“状态”的概念。 图1 效果图 上面的示例中&#xff0c;用户与应用程序的交互触发了文本状态变更&#xff0c;状态变更引起了UI渲染&#xff0c;UI从“Hello World”变更为“Hel…

一.初始typescript

什么是ts 首先我们要确认typescript是一个语言&#xff0c;是等同于JavaScript层级得&#xff0c;并不是一些人认为得是JavaScript得类型规范工具或者插件。 ts与js的差异 从type script这个名字就可以看出&#xff0c;ts其实是JavaScript的一个类型化超集&#xff0c;它增…