卡尔曼滤波器与DSP实现

news2024/9/23 19:25:35

  卡尔曼滤波器是利用系统状态方程,结合测量结果对系统状态进行进行最优估计的算法。本文介绍它的主要公式,并举例在C6000 DSP上实现。

推荐资料

  • KalmanFilter.NET
  • Understanding Kalman Filters
  • 卡尔曼滤波与组合导航原理

“If you can’t explain it simply, you don’t understand it well enough.” —— Albert Einstein

  第一个网站是我认为的讲卡尔曼滤波讲得最好的资料!“如果你不能用简单的话把问题解释清楚,那就是理解得不够”。作者就是能用例子把问题讲得很清楚的那种人。上面举的例子和介绍的思路都非常适合初学者,即使是什么都不懂的人也能非常快速地理解。只是后面还有一些内容比如EKF、UKF等作者还没更新上去,目前只有基础的卡尔曼滤波。
  第二个链接是MathWorks给出的关于卡尔曼滤波的教学视频,还有一个配套的关于单摆的实验,可以一边动手操作一边学习,感觉挺有意思的。
  第三个链接是B站上的西北工业大学的严恭敏老师上课的录屏,严老师还有一本书《捷联惯导算法与组合导航原理》,相当于是课本,推荐想要系统学习的同学去看这个。

基础

  在正式开始介绍之前,首先得有一些基础的概念。

随机变量的期望与方差

  一维的随机变量 x x x可以用它的期望 μ \mu μ和方差 σ 2 \sigma^2 σ2来描述;多维的随机变量 X X X可以用期望 E ( X ) {\rm E}(X) E(X)和协方差矩阵 V ( X ) {\rm V}(X) V(X)来描述。对于一个一维的随机变量 x x x,我们可以采样多个样本 x i x_i xi来对它的期望和方差进行估计。之所以说是“估计”是因为,我们如果想获得真实的期望和方差,就需要采样无穷多的样本,这是不可能做到的。

E ( x ) = 1 n ∑ i = 0 n − 1 x i        V ( x ) = 1 n − 1 ∑ i = 0 n − 1 ( x i − μ ) 2 {\rm{E}}(x) = {1 \over n}\sum\limits_{i = 0}^{n - 1} {{x_i}\;\;\;{\rm{V}}(x)} = {1 \over {n - 1}}\sum\limits_{i = 0}^{n - 1} {{{\left( {{x_i} - \mu } \right)}^2}} E(x)=n1i=0n1xiV(x)=n11i=0n1(xiμ)2

  上面的是公式是利用 n n n个样本对随机变量 x x x的期望和方差的无偏估计。之所以说是无偏是因为,如果再对上面的 E ( x ) {\rm E}(x) E(x) V ( x ) {\rm V}(x) V(x)求期望,分别可以得到 μ \mu μ σ 2 \sigma^2 σ2,它们是准确的估计。卡尔曼滤波算法中虽然不涉及这部分计算,但是最好能有这样的概念,方差可以用来衡量一个随机变量的变化程度。

期望代数(Expectation Algebra)

  因为一维随机变量 x x x是多维随机变量 X X X的情况,所以后面都以多维随机变量 X X X进行讨论。为了和后面的推导统一符号,也用 x x x表示多维随机变量。期望代数是与随机变量的期望与方差相关的一些定理公式,在卡尔曼滤波的推导中会用到。记 x x x的均值和协方差矩阵分别为 μ x \mu_x μx V ( x ) {\rm V}(x) V(x),它们满足:

V ( x ) = E ( ( x − μ x ) ( X − μ x ) T ) {\rm{V}}(x) = {\rm{E}}\left( {\left( {x - {\mu _x}} \right){{\left( {X - {\mu _x}} \right)}^{\rm T}}} \right) V(x)=E((xμx)(Xμx)T)

  如果对随机变量 x x x进行线性变换得到 y = F x y=Fx y=Fx F F F N × N N\times N N×N的方阵, x x x N N N维列向量。那么随机变量 y y y的方差为:

V ( y ) = F V ( x ) F T {\rm{V}}(y) = F{\rm{V}}(x){F^{\rm T}} V(y)=FV(x)FT

  还有很多简单的公式这里就不列出来了,都在这里可以找到,这是后面推导的基础。

卡尔曼滤波

  卡尔曼滤波可以概括为三个环节,初始化,更新和预测。

初始化 Initiate

  初始化状态向量 x ^ 0 , 0 \hat x_{0,0} x^0,0和表示当前状态估计不确定度的协方差矩阵 P 0 , 0 P_{0,0} P0,0
   x ^ 0 , 0 \hat x_{0,0} x^0,0可以任意,一般都初始化为0向量。在后续时刻经过多次测量后,系统的状态向量能够收敛到真实值附近。

x ^ 0 , 0 = [ 0 , 0 , 0 , ⋯   , 0 ] T {{\hat x}_{0,0}} = {\left[ {0,0,0, \cdots ,0} \right]^{\rm{T}}} x^0,0=[0,0,0,,0]T

  估计的状态 x ^ \hat x x^的协方差矩阵称为估计不确定度(Estimate Uncertainty),用符号 P P P表示。

P n , n = E ( ( x ^ n , n − μ x n , n ) ( x ^ n , n − μ x n , n ) T ) {P_{n,n}} = {\rm{E}}\left( {\left( {{{\hat x}_{n,n}} - {\mu _{{x_{n,n}}}}} \right){{\left( {{{\hat x}_{n,n}} - {\mu _{{x_{n,n}}}}} \right)}^T}} \right) Pn,n=E((x^n,nμxn,n)(x^n,nμxn,n)T)

   P 0 , 0 P_{0,0} P0,0表示在0时刻(初始时刻)对当前状态的估计不确定度。

P 0 , 0 = [ σ 2 0 0 ⋯ 0 0 σ 2 0 ⋯ 0 0 0 σ 2 ⋯ 0 ⋮ ⋮ ⋮ ⋱ 0 0 0 0 0 σ 2 ] {P_{0,0}} = {\begin{bmatrix} {{\sigma ^2}}&0&0& \cdots &0\\ 0&{{\sigma ^2}}&0& \cdots &0\\ 0&0&{{\sigma ^2}}& \cdots &0\\ \vdots & \vdots & \vdots & \ddots &0\\ 0&0&0&0&{{\sigma ^2}} \end{bmatrix}} P0,0= σ20000σ20000σ2000000σ2

   x ^ 0 , 0 \hat x_{0,0} x^0,0 我们是随意设置的,因此0时刻状态的真实期望值 μ x 0 , 0 {\mu_{{x_{0,0}}}} μx0,0很可能和我们随意设置的这个状态的估计值 x ^ 0 , 0 \hat x_{0,0} x^0,0有很大的偏差。而这个估计的不确定度自然很大,我们可以为每个维度的方差设置一个很大的值,表示初始的估计是“不靠谱”的。同样随着后续的不断测量,我们在每一时刻的估计不确定度 P n , n P_{n,n} Pn,n也会同系统状态向量的估计 x ^ n , n \hat x_{n,n} x^n,n一起不断更新。
  除了这 x ^ 0 , 0 \hat x_{0,0} x^0,0 P 0 , 0 P_{0,0} P0,0需要初始化以外,还有状态转移矩阵 F F F,系统噪声的协方差矩阵 Q Q Q,测量噪声的协方差矩阵 R R R,观测矩阵 H H H需要给出。这几个矩阵都是常量,不会随着时间变化,在后面提到了再作介绍。

预测 Predict

系统状态预测

  卡尔曼滤波的使用是建立在状态空间模型(State Space Model)之上的。状态外推方程(state extrapolate equation)用于状态的预测,它的一般形式:

x ^ n + 1 , n = F x ^ n , n + G u n + w n {{\hat x}_{n + 1,n}} = F{{\hat x}_{n,n}} + G{u_n} + {w_n} x^n+1,n=Fx^n,n+Gun+wn

  • x ^ n + 1 , n {{\hat x}_{n + 1,n}} x^n+1,n是在 n n n时刻对下一时刻的状态的估计;
  • x ^ n , n {{\hat x}_{n,n}} x^n,n是在 n n n时刻估计的 n n n时刻的状态, F F F是状态转移矩阵(state transition matrix);
  • u n {u_n} un是外部输入,是确定的, G G G是控制矩阵(control matrix)表示外部输入对系统状态的影响;
  • w n {w_n} wn是过程噪声(process noise)或者称为系统噪声,无法直接测量。

估计不确定度预测

P n , n = E ( ( x ^ n , n − μ x n , n ) ( x ^ n , n − μ x n , n ) T ) {P_{n,n}} = {\rm{E}}\left( {\left( {{{\hat x}_{n,n}} - {\mu _{{x_{n,n}}}}} \right){{\left( {{{\hat x}_{n,n}} - {\mu _{{x_{n,n}}}}} \right)}^T}} \right) Pn,n=E((x^n,nμxn,n)(x^n,nμxn,n)T)

P n + 1 , n = E ( ( x ^ n + 1 , n − μ x n + 1 , n ) ( x ^ n + 1 , n − μ x n + 1 , n ) T ) {P_{n + 1,n}} = {\rm{E}}\left( {\left( {{{\hat x}_{n + 1,n}} - {\mu _{{x_{n + 1,n}}}}} \right){{\left( {{{\hat x}_{n + 1,n}} - {\mu _{{x_{n + 1,n}}}}} \right)}^T}} \right) Pn+1,n=E((x^n+1,nμxn+1,n)(x^n+1,nμxn+1,n)T)

  把状态转移方程代入上式后可以得到下式,其中 Q Q Q是过程噪声 w n w_n wn的协方差矩阵。

P n + 1 , n = F P n , n F T + Q {P_{n + 1,n}} = F{P_{n,n}}{F^T} + Q Pn+1,n=FPn,nFT+Q

  因为过程噪声 w n {w_n} wn是无法直接测量的,因此我们一般在初始化的时候就可以给出一个固定的过程噪声的协方差矩阵 Q Q Q Q Q Q矩阵里的值如果太小,则会对系统状态的估计更加取信于模型的预测值,而弱化了观测值的作用,导致对系统状态的估计产生滞后误差(lag error);而如果 Q Q Q矩阵里的值太大,导致估计的不确定度增大,则无法起到很好的滤波效果。

更新 Update

系统状态更新

  首先是状态的更新,从 n − 1 n-1 n1时刻来到 n n n时刻后,多了一个观测值/测量值 z n z_n zn可以帮助我们更准确地进行估计。

x ^ n , n = x ^ n , n − 1 + K n ( z n − H x ^ n , n − 1 ) {{\hat x}_{n,n}} = {{\hat x}_{n,n - 1}} + {K_n}\left( {{z_n} - H{{\hat x}_{n,n - 1}}} \right) x^n,n=x^n,n1+Kn(znHx^n,n1)

   H H H是观测矩阵,系统状态 x x x中某些量我们可能是不能直接观测的,而只有部分可以直接观测,因此需要有一个观测矩阵 H H H从状态向量中提出那些能够与观测值对应的部分。 z n − H x ^ n , n − 1 {z_n} - H{{\hat x}_{n,n - 1}} znHx^n,n1被记作innovation,中文翻译为“新息”,可以理解为“新的部分”。当前时刻的估计是上一时刻的估计与测量值的加权,加权系数是卡尔曼增益 K n K_n Kn。卡尔曼增益的大小直接决定了新的估计值是更加侧重前一时刻的估计值还是测量值。

估计不确定度更新

P n , n = ( I − K n H ) P n , n − 1 ( I − K n H ) T + K n R n K n T {P_{n,n}} = \left( {I - {K_n}H} \right){P_{n,n - 1}}{\left( {I - {K_n}H} \right)^{\rm{T}}} + {K_n}{R_n}K_n^{\rm{T}} Pn,n=(IKnH)Pn,n1(IKnH)T+KnRnKnT

  估计不确定度的更新是根据状态更新的方程得到的,可以重写一下状态更新方程:

x ^ n , n = ( I − K n H ) x ^ n , n − 1 + K n z n {{\hat x}_{n,n}} = \left( {I - K_nH} \right){{\hat x}_{n,n - 1}} + {K_n}{z_n} x^n,n=(IKnH)x^n,n1+Knzn

  再根据期望代数中的公式即可得到 P n , n {P_{n,n}} Pn,n的计算表达式。其中 z n z_n zn是测量值,而 R n R_n Rn是测量噪声的协方差矩阵,

z n = H x n + v n {z_n} = H{x_n} + {v_n} zn=Hxn+vn

   x n x_n xn n n n时刻系统真实的状态值,也就是系统状态的期望值 μ x n , n {\mu _{{x_{n,n}}}} μxn,n, v n v_n vn是测量噪声, R n = E ( v n v n T ) {R_n} = {\rm{E}}\left( {{v_n}v_n^{\rm{T}}} \right) Rn=E(vnvnT)。详细的推导过程可以看这里。

卡尔曼增益计算

  卡尔曼增益是令估计不确定度 P n , n P_{n,n} Pn,n的迹最小化得到的。 P n , n P_{n,n} Pn,n的对角线是系统状态 x n , n x_{n,n} xn,n每一个维度的方差,它的迹是这些方差之和。最小化 t r ( P n , n ) tr(P_{n,n}) tr(Pn,n)可以通过对 K n K_n Kn求导,并令导数为零矩阵,然后得到最优的 K n K_n Kn。详细的推导过程可以看这里,最后得到如下结果:

K n = P n , n − 1 H T ( H P n , n − 1 H T + R n ) − 1 {K_n} = {P_{n,n - 1}}{H^{\rm{T}}}{\left( {H{P_{n,n - 1}}{H^{\rm{T}}} + {R_n}} \right)^{ - 1}} Kn=Pn,n1HT(HPn,n1HT+Rn)1

  将这一结果再代入 P n , n P_{n,n} Pn,n的计算公式,可以简化 P n , n P_{n,n} Pn,n的计算:

P n , n = ( I − K n H ) P n , n − 1 {P_{n,n}} = \left( {I - {K_n}H} \right){P_{n,n - 1}} Pn,n=(IKnH)Pn,n1

总结

在这里插入图片描述
  图片引用自这里

举例

  在C6000 DSP上实现二维坐标点(x,y)的卡尔曼滤波,源代码。
  首先实现了Matlab版本,依次给出10个二维坐标点作为观测值,然后将卡尔曼滤波后的结果输出显示;DSP上采用相同的参数设置,加载同样的10个二维坐标点,将结果输出显示后与Matlab的结果进行对比,确保结果正确后统计处理所需的时间。

匀速直线运动模型

s t a t e = [ x , v x , y , v y ] state = \left[ {x,{v_x},y,{v_y}} \right] state=[x,vx,y,vy]

F C V = [ 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 1 ] {F_{CV}} = {\begin{bmatrix} 1&1&0&0\\ 0&1&0&0\\ 0&0&1&1\\ 0&0&0&1 \end{bmatrix}} FCV= 1000110000100011
在这里插入图片描述
  10次计算结果一致,DSP上Kalman滤波器初始化需要 6.2 μ s 6.2{\rm{\mu s}} 6.2μs,每次更新和预测平均需要 4.4 μ s 4.4{\rm{\mu s}} 4.4μs

匀加速直线运动模型

s t a t e = [ x , v x , a x , y , v y , a y ] state = \left[ {x,{v_x},{a_x},y,{v_y},{a_y}} \right] state=[x,vx,ax,y,vy,ay]

F C A = [ 1 1 0.5 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0.5 0 0 0 0 1 1 0 0 0 0 0 1 ] {F_{CA}} = {\begin{bmatrix} 1&1&{0.5}&0&0&0\\ 0&1&1&0&0&0\\ 0&0&1&0&0&0\\ 0&0&0&1&1&{0.5}\\ 0&0&0&0&1&1\\ 0&0&0&0&0&1 \end{bmatrix}} FCA= 1000001100000.5110000001000001100000.511
在这里插入图片描述
  10次计算结果一致,DSP上Kalman滤波器初始化需要 7.0 μ s 7.0{\rm{\mu s}} 7.0μs,每次更新和预测平均需要 5.4 μ s 5.4{\rm{\mu s}} 5.4μs

EKF & UKF

  如果系统状态的状态转移方程或者观测方程是非线性的,那么就不能简单地用固定的 F F F H H H来表示系统的状态转移和观测矩阵。这时候就需要用到EKF或者UKF了。
  EKF解决非线性的问题采用的是一阶泰勒展开来近似。这相比于KF就引入了额外的一些计算量,因为 F F F H H H不是固定的,每次系统状态改变都需要重新计算。
  UKF采用的是类似蒙特卡洛分析的方法,用几个中心对称的sigma点来估计非线性变换后的随机变量的协方差矩阵。

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

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

相关文章

rust 程序设计语言入门(1)

本文是阅读《Rust程序设计语言》的学习记录,配合视频《Rust编程语言入门教程》食用更佳 环境搭建 windows下载rustup_init.exe,点击安装,默认选择msvc的toolchain,一路default即可 解决下载慢的问题,在powershell中修…

libxlsxwriter条件格式

今天来看一个libxlsxwriter的高级用法:一个条件格式的示例。 说它“高级”,也是基于非Excel专家的小白们的视角。对,没错,本小白正是这样的小白。 1 一个简单的问题 来看我们今天的场景问题:有一列数据,有…

操作系统(一): 进程和线程,进程的多种状态以及进程的调度算法

文章目录前言一、进程和线程1. 进程2. 线程二、进程和线程的区别(面试常问)三、进程调度算法3.1. 批处理系统3.2. 交互式系统3.2.1 时间片轮转3.2.2 优先级调度3.2.3 多级别反馈队列3.3. 实时系统四、进程的状态五、进程同步5.1 什么是进程同步5.2 进程同步应该遵循的几点原则前…

Qt 学习(四) —— QGridLayout栅格布局

目录一、QGridLayout布局规则二、创建QGridLayout三、成员函数1. 控件间距2. 可拉伸控件(弹簧)3. 最小行高/列宽4. 行数和列数5. 锁定纵横比6. 添加控件7. 添加布局8. 设置栅格布局原点位置9. 操作布局项9.1 访问布局项9.2 删除布局项9.3 通过索引获取布…

Git教程个人分享:如何将一个本地项目上传至远程仓库的流程

前言: 今天来分享一下,关于Git的一些教程,同时这也是我自己曾今学习Git时候的笔记,之所以更,也是方便后期自己可以去回顾,当然后面也会出一部分关于Git其他操作方面的内容。 这次我们分享的是&#xff0c…

基于JavaScript的Web端股票价格查看器——大道

🐶 基于JavaScript的Web端股票价格查看器——大道 一、项目背景 当下互联网发展迅速,互联网已经不断向传统金融领域渗透。在互联网上有大量金融领域的数据,如何利用好这些数据,对于投资者来说是十分重要的一件事情。股票价格实时…

JavaSE学习day4_01 循环for,while,do...while

1. 循环高级 1.1 无限循环 for、while、do...while都有无限循环的写法。 最为常用的是while格式的。 因为无限循环是不知道循环次数的,所以用while格式的 代码示例: while(true){} 1.2 跳转控制语句(掌握) 跳转控制语句&…

MySQL 插入数据

数据库与表创建成功以后,需要向数据库的表中插入数据。在 MySQL 中可以使用 INSERT 语句向数据库已有的表中插入一行或者多行元组数据。 你可以通过 mysql> 命令提示窗口中向数据表中插入数据,或者通过PHP脚本来插入数据。 语法 以下为向MySQL数据表…

51单片机——步进电机实验,小白讲解,相互学习

步进电机简介: 步进电机是将电脉冲信号转变为角位移或多线位移的开源控制元件。在非超载的情况下,电机的转速,停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机…

Android - 自动系统签名

一、系统签名 以下是两类应用开发场景: 普通应用开发:使用公司自定义 keystore 进行签名,如:微信、支付宝系统应用开发:使用 AOSP 系统签名或厂商自定义 keystore 进行签名,如:设置、录音 系…

数学建模拓展内容:卡方检验和Fisher精确性检验(附有SPSS使用步骤)

卡方检验和Fisher精确性检验卡方拟合度检验卡方独立性检验卡方检验的前提假设Fisher精确性检验卡方拟合度检验 卡方拟合度检验概要:卡方拟合度检验也被称为单因素卡方检验,用于检验一个分类变量的预期频率和观察到的频率之间是否存在显著差异。 卡方拟…

第一部分:简单句——第二章:简单句的补充

简单句的核心构成:一主一谓 主语/宾语/表语 可以变成名词/代词/doing/to do 谓语动词有四种核心变化:三态 一否 时态语态情态否定 简单句的核心:将简单句给写对 简单句的补充:将简单句给写的更好、更充分 简单句的补充 1、限定…

计算机网络之HTTP04ECDHE握手解析

DH算法 离散读对数问题是DH算法的数学基础 (1)计算公钥 (2)交换公钥,并计算 对方公钥^我的私钥 mod p 离散对数的交换幂运算交换律使二者算出来的值一样,都为K k就是对称加密的秘钥 2. DHE算法 E&#…

DNS 原理入门指南(一)

DNS 是互联网核心协议之一。不管是上网浏览,还是编程开发,都需要了解一点它的知识。 本文详细介绍DNS的原理,以及如何运用工具软件观察它的运作。我的目标是,读完此文后,你就能完全理解DNS。 一、DNS 是什么&#xff1…

记录每日LeetCode 1138.字母板上的路径 Java实现

题目描述: 我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]。 在本题里,字母板为board ["abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"]&#x…

Linux重定向符、管道符讲解

目录 重定向 将命令与文件进行互动 输出重定向 输入重定向 管道符 将命令与命令互动起来 重定向 将命令与文件进行互动 重定向分类 一般情况下,Linux命令运行时都会打开一下三个文件 标准输入文件:stdin文件,文件描述符为0,Li…

自定义ESLint规则开发与使用

自定义eslint及使用 项目结构 |-eslint-plugin-demo //自定义eslint插件项目 | |-demo-app // 使用自定义eslint的测试应用 |-README.md 项目效果: github项目地址 自定义ESLint环境准备 安装脚手架 执行下列命令来安装开发eslint的脚手架。 yo(y…

中小学信息学相关编程比赛清单及报名网站汇总(C++类)

1、NOI系列比赛(CSP-J CSP-S NOIP NOI APIO CTSC IOI ISIJ等) NOI官网 NOI全国青少年信息学奥林匹克竞赛https://www.noi.cn/ 2、蓝桥杯青少年创意编程大赛 https://www.lanqiaoqingshao.cn/home 3、中国电子协会考评中心

数据结构 - Set 与 Map 接口介绍(TreeMap,HashMap,TreeSet,HashSet类)

文章目录前言1. Set / Map接口2. TreeSet类3. TreeMap 类4. HashSet 与 HashMap4.1 HashSet / HashMap 底层哈希表4.2 解决哈希冲突总结✨✨✨学习的道路很枯燥,希望我们能并肩走下来! 编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得…

神经网络基础知识

神经网络基础知识 文章目录神经网络基础知识一、人工神经网络1.激活函数sigmod函数Tanh函数Leaky Relu函数分析2.过拟合和欠拟合二、学习与感知机1.损失函数与代价函数2. 线性回归和逻辑回归3. 监督学习与无监督学习三、优化1.梯度下降法2.随机梯度下降法(SGD)3. 批量梯度下降法…