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

news2025/1/20 10:59:49

一、概念介绍

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

扩展卡尔曼滤波就是为了解决非线性问题,普通卡尔曼滤波只能应用于线性空间的问题。当系统为线性高斯模型时,滤波器能给出最优的估计,但是实际系统总是存在不同程度的非线性,如平方、三角关系、开方等。对于非线性系统,可以采用的一种方法是通过线性化方法将非线性系统转换为近似的线性系统,即为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]网络资料

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HashMap系列-resize

1.resize public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {final Node<K,V>[] resize() {Node<K,V>[] oldTab table;int oldCap (oldTab null) ? 0 : oldTab.length; //老的数组容量in…

【开源】基于Vue+SpringBoot的快乐贩卖馆管理系统

项目编号&#xff1a; S 064 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S064&#xff0c;文末获取源码。} 项目编号&#xff1a;S064&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 搞笑视频模块2.3 视…

用 PHP和html做一个简单的注册页面

用 PHP和html做一个简单的注册页面 index.html的设计 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title…

手眼标定 - 最终精度和误差优化心得

手眼标定 - 标定误差优化项 一、TCP标定误差优化1、注意标定针摆放范围2、TCP标定时的点次态与工作姿态尽可能保持相近 二、深度相机对齐矩阵误差1、手动计算对齐矩阵 三、拍照姿态1、TCP标定姿态优先2、水平放置棋盘格优先 为减少最终手眼标定的误差&#xff0c;可做或注意以下…

华为数通---配置Smart Link负载分担案例

定义 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个接口作为另一个的备份。Smart Link常用于双上行组网&#xff0c;提供可靠高效的备份和快速的切换机制。 目的 下游设备连接到上游设备&#xff0c;当使用单上行方式时&#x…

【dig命令查询方法】

dig&#xff08;Domain Information Groper&#xff09;是一个用于查询DNS&#xff08;域名系统&#xff09;的命令行工具&#xff0c;它可以帮助您获取关于域名的各种信息&#xff0c;如IP地址、MX记录、NS记录等。下面是dig的详细使用教程。 基本语法&#xff1a; dig [ser…

【华为数据之道学习笔记】3-4主数据治理

主数据是参与业务事件的主体或资源&#xff0c;是具有高业务价值的、跨流程和跨系统重复使用的数据。主数据与基础数据有一定的相似性&#xff0c;都是在业务事件发生之前预先定义&#xff1b;但又与基础数据不同&#xff0c;主数据的取值不受限于预先定义的数据范围&#xff0…

http和https的区别有哪些?

HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;HTTP Secure&#xff09;是互联网上用于数据传输的两种协议。它们的主要区别在于HTTPS提供了加密的传输机制&#xff0c;以提高数据在传输过程中的安全性。以下是HTTP和HTTPS的一些主要区别&#xff1a; 加密&a…

[linux运维] 利用zabbix监控linux高危命令并发送告警(基于Zabbix 6)

之前写过一篇是基于zabbix 5.4的实现文章&#xff0c;但是不太详细&#xff0c;最近已经有两个小伙伴在zabbix 6上操作&#xff0c;发现触发器没有str函数&#xff0c;所以更新一下本文&#xff0c;基于zabbix 6 0x01 来看看效果 高危指令出发问题告警&#xff1a; 发出邮件告…

如何将idea中导入的文件夹中的项目识别为maven项目

问题描述 大家经常遇到导入某个文件夹的时候&#xff0c;需要将某个子文件夹识别为maven项目 解决方案

【教程】逻辑回归怎么做多分类

目录 一、逻辑回归模型介绍 1.1 逻辑回归模型简介 1.2 逻辑回归二分类模型 1.3 逻辑回归多分类模型 二、如何实现逻辑回归二分类 2.1 逻辑回归二分类例子 2.2 逻辑回归二分类实现代码 三、如何实现一个逻辑回归多分类 3.1 逻辑回归多分类问题 3.1 逻辑回归多分类的代…

RabbitMQ-学习笔记(初识 RabbitMQ)

本篇文章学习于 bilibili黑马 的视频 (狗头保命) 同步通讯 & 异步通讯 (RabbitMQ 的前置知识) 同步通讯&#xff1a;类似打电话&#xff0c;只有对方接受了你发起的请求,双方才能进行通讯, 同一时刻你只能跟一个人打视频电话。异步通讯&#xff1a;类似发信息&#xff0c…

Hadoop3.x完全分布式环境搭建Zookeeper和Hbase

先在主节点上进行安装和配置&#xff0c;随后分发到各个从节点上。 1. 安装zookeeper 1.1 解压zookeeper并添加环境变量 1&#xff09;解压zookeeper到/usr/local文件夹下 tar -zxvf /usr/local2&#xff09;进入/usr/local文件夹将apache-zookeeper-3.8.0-bin改名为zookeep…

玩转Sass:掌握数据类型!

当我们在进行前端开发的时候&#xff0c;有时候需要使用一些不同的数据类型来处理样式&#xff0c;Sass 提供的这些数据类型可以帮助我们更高效地进行样式开发&#xff0c;本篇文章将为您详细介绍 Sass 中的数据类型。 布尔类型 在 Sass 中&#xff0c;布尔数据类型可以表示逻…

如何将微服务注册到nacos服务上

首先可在maven的父工程的pom文件中添加maven的dependencyManagement标签&#xff0c;引入spring-cloud-alibaba-dependencies坐标 <properties><spring.cloud.alibaba.version>2.2.9.RELEASE</spring.cloud.alibaba.version></properties><!-- 管理…

IntelliJ IDEA 2023.3 最新变化

关键亮点 AI Assistant 预览阶段结束 全面推出 Ultimate JetBrains AI Assistant 现已全面推出&#xff0c;搭载大量新功能和改进&#xff0c;助力提高您在 JetBrains IDE 中的工作效率。 最新更新包括编辑器中增强的直接代码生成、无需复制代码即可回答项目相关查询的上下文…

Spring Boot的日志

打印日志 打印日志的步骤: • 在程序中得到日志对象. • 使用日志对象输出要打印的内容 在程序中得到日志对象 在程序中获取日志对象需要使用日志工厂LoggerFactory,代码如下: package com.example.demo;import org.slf4j.Logger; import org.slf4j.LoggerFactory;public c…

[VSCode] Java开发环境配置

文章目录 1 VSCode & Java 安装1.1 安装 VSCode1.2 安装 JDK 2 环境变量配置3 在 VSCode 中安装 Java 扩展4 运行测试 1 VSCode & Java 安装 1.1 安装 VSCode Visual Studio Code 官方下载 地址&#xff1a; https://code.visualstudio.com/详细安装步骤这里不做赘…

408——知识点大杂烩

在完成专业课的一轮复习以及历年真题的学习后&#xff0c;发现选择题甚至个别大题的考点就单纯考对概念的理解&#xff0c;会就是会&#xff0c;不会想到脑壳疼都做不出来&#xff0c;而408的知识点主打一个多杂&#xff0c;所以过来整理一下笔记。本文的知识点主要是在我做题过…

【扩散模型】ControlNet从原理到实战

ControlNet从原理到实战 ControlNet原理ControlNet应用于大型预训练扩散模型ControlNet训练过程ControlNet示例1 ControlNet与Canny Edge2. ControlNet与Depth3. ControlNet与M-LSD Lines4. ControlNet与HED Boundary ControlNet实战Canny Edge实战Open Pose 小结参考资料 Cont…