【控制算法笔记】卡尔曼滤波(二)——基于状态空间表达的KF基本计算流程以及Python实现

news2024/11/23 15:12:57

本文是个人学习笔记,包含个人理解,如有错误欢迎指正。

KF算法更多的情况下会用来处理复杂的非线性数据,尤其是当对象特征或检测的状态量不止一个时就得使用状态方程的方法,利用线性代数的计算方式来解决噪声的估计问题。这其中涉及到多个变量数据的融合,协方差的计算等概念。

基于正态分布的样本数据融合-Data Fusion

在实际的数据采集中,通常可能有多个传感器来共同采集一个数据,由于传感器生产运输安装和实际系统的动态扰动,每个传感器采集的数据可能都会存在噪声。人们通常认为这些噪声是符合一个正态分布的随机量,所以我们就可以从多个传感器得到多组符合正态分布的观测样本,怎么将这些数据融合到一起,进而达到降低噪声干扰的目的呢?那就是数据融合(Data Fusion)
假设有两个样本的分布,两个分布都符合正态分布,那从样本数据出发,能够得到两组数据的样本均值和样本方差,一共四个变量。 E ( X ) = 1 n ∑ i = 0 n x i S ( X ) = 1 n − 1 ∑ i = 0 n ( x i − x ˉ ) 2 E(X)=\frac{1}{n}\sum_{i=0}^{n}x_i \quad S(X)=\frac{1}{n-1}\sum_{i=0}^{n}(x_i-\bar{x} )^2 E(X)=n1i=0nxiS(X)=n11i=0n(xixˉ)2 对于我们观测到的两组样本数据,根据卡尔曼估计的原理可以认为在同一个时刻,估计的实际数据满足 Z ^ = Z 1 + K ⋅ ( Z 2 − Z 1 ) \hat{Z} =Z_1 +K\cdot (Z_2-Z_1) Z^=Z1+K(Z2Z1) 其中Z一二是k时刻观测到的两个样本数据,当存在一个K能够使得   Z ^ \ \hat{Z}  Z^ 的方差取得最小值的时候,就认为通过k求出的估计值是概率上最符合两个样本的实际值。
根据概率论中基本的方差计算公式可以得到: S ( Z ^ ) = S { Z 1 + K ⋅ ( Z 2 − Z 1 ) } = S { ( 1 − K ) Z 1 + K ⋅ Z 2 } S(\hat{Z}) = S \left \{ Z_1 +K\cdot (Z_2-Z_1) \right \} =S \left \{(1-K)Z_1+K\cdot Z_2 \right \} S(Z^)=S{Z1+K(Z2Z1)}=S{(1K)Z1+KZ2} 由于观测的样本数据之间相互独立,所以可得 ⇒ S ( Z ^ ) = S [ ( 1 − K ) Z 1 ] + S ( K ⋅ Z 2 ) = ( 1 − K ) 2 ⋅ S ( Z 1 ) + K 2 S ( Z 2 ) \Rightarrow S(\hat{Z})=S[(1-K)Z_1]+S(K\cdot Z_2)=(1-K)^2\cdot S(Z_1)+K^2S(Z_2) S(Z^)=S[(1K)Z1]+S(KZ2)=(1K)2S(Z1)+K2S(Z2) 对等式右端求导,并令导数为0可得: ⇒ S ( Z ^ ) ′ = − 2 ⋅ ( 1 − K ) ⋅ S ( Z 1 ) + 2 ⋅ K ⋅ S ( Z 2 ) = 0 \Rightarrow S(\hat{Z})'=-2\cdot (1-K)\cdot S(Z_1)+2\cdot K\cdot S(Z_2)=0 S(Z^)=2(1K)S(Z1)+2KS(Z2)=0 ⇒ S ( Z ^ ) ′ = ( 1 − K ) ⋅ S ( Z 1 ) + K ⋅ S ( Z 2 ) = 0 \Rightarrow S(\hat{Z})'= (1-K)\cdot S(Z_1)+K\cdot S(Z_2)=0 S(Z^)=(1K)S(Z1)+KS(Z2)=0 ⇒ k = S ( Z 1 ) S ( Z 1 ) + S ( Z 2 ) \Rightarrow k=\frac{S(Z_1)}{S(Z_1)+S(Z_2)} k=S(Z1)+S(Z2)S(Z1) 所以求出了K取值,可以得到概率上最优的融合数据。融合后的数据符合正态分布,且 S ( Z ^ ) = ( 1 − K ) 2 ⋅ S ( Z 1 ) + K 2 ⋅ S ( Z 2 ) E ( Z ^ ) = ( 1 − K ) ⋅ E ( Z 1 ) + K ⋅ E ( Z 2 ) S(\hat{Z} )=(1-K)^2\cdot S(Z_1)+K^2\cdot S(Z_2) \quad E(\hat{Z})=(1-K)\cdot E(Z_1)+K\cdot E(Z_2) S(Z^)=(1K)2S(Z1)+K2S(Z2)E(Z^)=(1K)E(Z1)+KE(Z2)


协方差矩阵-Covariance Matrix

当样本数据特征不再是一维数据时,往往将多维的数据计算转化到线性代数的计算,所以为了能在多维数据中计算样本的方差数据,我们必须学习样本的协方差矩阵。
现在假设存在三组样本观测数据: X = [ x 1 x 2 x 3 ] Y = [ y 1 y 2 y 3 ] Z = [ z 1 z 2 z 3 ] X=\begin{bmatrix} x_1\\x_2 \\x_3 \end{bmatrix} \quad Y=\begin{bmatrix} y_1 \\y_2 \\y_3 \end{bmatrix} \quad Z=\begin{bmatrix} z_1 \\z_2 \\z_3 \end{bmatrix} X= x1x2x3 Y= y1y2y3 Z= z1z2z3 每组样本可以计算出各自的方差,总的样本方差可以描述为: σ 2 = S ( X ) + S ( Y ) + S ( Z ) = σ ( X ) 2 + σ ( Y ) 2 + σ ( Z ) 2 \sigma^2 =S(X)+S(Y)+S(Z)=\sigma(X)^2+\sigma(Y)^2+\sigma(Z)^2 σ2=S(X)+S(Y)+S(Z)=σ(X)2+σ(Y)2+σ(Z)2 从而可以将总的样本方差使用二次型表示: S ⃗ = [ σ x 2 σ x σ y σ x σ z σ y σ x σ y 2 σ y σ z σ z σ x σ z σ y σ z 2 ] \vec{S} =\begin{bmatrix} {\sigma_x}^2 & \sigma_x\sigma_y & \sigma_x\sigma_z\\ \sigma_y\sigma_x & {\sigma_y}^2 & \sigma_y\sigma_z\\ \sigma_z\sigma_x & \sigma_z\sigma_y & {\sigma_z}^2 \end{bmatrix} S = σx2σyσxσzσxσxσyσy2σzσyσxσzσyσzσz2 其中   σ x 2 \ {\sigma_x}^2  σx2是样本的方差   σ x σ y \ \sigma_x\sigma_y  σxσy是x和y的样本协方差。这样的协方差矩阵通过一定的变换可以加快计算机计算的效率。为此需要引入协方差过度矩阵。
我们令协方差过度矩阵为: a = [ x 1 y 1 z 1 x 2 y 2 z 2 x 3 y 3 z 3 ] − 1 3 [ 1 1 1 1 1 1 1 1 1 ] [ x 1 y 1 z 1 x 2 y 2 z 2 x 3 y 3 z 3 ] a=\begin{bmatrix} x_1 & y_1 & z_1\\ x_2 & y_2 & z_2\\ x_3 & y_3 & z_3 \end{bmatrix} -\frac{1}{3} \begin{bmatrix} 1 & 1 & 1\\ 1 & 1 & 1\\ 1 & 1 & 1 \end{bmatrix} \begin{bmatrix} x_1 & y_1 & z_1\\ x_2 & y_2 & z_2\\ x_3 & y_3 & z_3 \end{bmatrix} a= x1x2x3y1y2y3z1z2z3 31 111111111 x1x2x3y1y2y3z1z2z3 上式中有第一项矩阵为样本数据矩阵,后一项的值就是样本的平均值。通过过度矩阵相乘可以得到协方差矩阵为: P = 1 3 a T a P = \frac{1}{3} a^Ta P=31aTa 这样就能通过矩阵的方式加快计算。


状态空间理论

在经典的控制系统中,使用传递函数的形式描述系统输入和输出之间的关系,传递函数所计算的是系统外部的联系。在现代控制系统中,通过对控制系统内部参数建立状态变量进而通过系统微分方程建立状态状态空间表达式。
正是通过状态空间的思想,可以进一步的在此基础上拓展出复杂系统的卡尔曼滤波计算。通常对一个实际的离散系统,可以表达为: X k = A X k − 1 + B u k − 1 + w k − 1 Z k = H X k + V k \begin{matrix} X_k=AX_{k-1}+B{\large u} _{k-1}+{\large w} _{k-1}\\ Z_k=HX_k+V_k \end{matrix} Xk=AXk1+Buk1+wk1Zk=HXk+Vk上式是一个基本的离散形式状态空间表达式,第一行描述输入和状态变量关系,最后一项是系统工作过程中数据产生的过程噪声。第二行描述了输出和状态变量的关系,最后一项是输出数据的测量噪声,在次基础上就可以使用卡尔曼滤波来实时估计当前状态变量的估计值。
通过系统的状态空间方程的形式可以进一步的推导出KF(卡尔曼滤波)的核心参数卡尔曼增益。

状态空间下的KF核心公式

基于上面的离散系统状态空间表达式和数据融合中的概率论计算方法,可以得到,对于
X k = A X k − 1 + B u k − 1 + w k − 1 Z k = H X k + V k \begin{matrix} X_k=AX_{k-1}+B{\large u} _{k-1}+{\large w} _{k-1}\\ Z_k=HX_k+V_k \end{matrix} Xk=AXk1+Buk1+wk1Zk=HXk+Vk 有预测阶段: X ^ k − = A X ^ k − 1 P k − = A P k − 1 A T + Q \begin{matrix} \hat{X}^-_k=A\hat{X}_{k-1} \\ P^-_k=AP_{k-1}A^T+Q \end{matrix} X^k=AX^k1Pk=APk1AT+Q 其中X为状态变量,A为状态矩阵,Q为噪声协方差矩阵,P为过程噪声矩阵。
随后在矫正参数阶段有当前时刻的卡尔曼增益: K k = P k − H T H P k − H T + R K_k=\frac{P^-_kH^T}{HP^-_kH^T+R} Kk=HPkHT+RPkHT
当前时刻的估计值: X ^ k = X ^ k − + K k ( Z k − H X ^ k − ) \hat{X}_k=\hat{X}^-_k+K_k(Z_k-H\hat{X}^-_k) X^k=X^k+Kk(ZkHX^k) 以及当前时刻的过程估计误差: P k = ( I − K k H ) P k − P_k=(I-K_kH)P^-_k Pk=(IKkH)Pk

二维KF位置估计-Python

假设对一个移动的小车,使用小车的位置x和y坐标作为状态变量,通过附加位置数据的随机噪声,并迭代来计算估计的位置:

import numpy as np
import matplotlib.pyplot as plt

# 状态空间模型参数
dt = 0.1  # 采样时间间隔
A = np.array([[1, dt],
              [0, 1]])  # 状态转移矩阵,描述系统的演化

H = np.array([[1, 0],
              [0, 1]])  # 观测矩阵,描述测量和状态的关系

# 过程噪声和测量噪声的协方差矩阵
Q = np.diag([0.1, 0.1])  # 过程噪声协方差矩阵
R = np.diag([5, 5])  # 测量噪声协方差矩阵

# 初始状态估计
x_hat = np.array([0, 0])  # 初始状态估计
P = np.diag([4, 1])  # 初始状态协方差矩阵

# 生成实际运动的轨迹数据
true_states = []
for t in range(50):
    x_hat = np.dot(A, x_hat) + np.array([1, 1])  # 在X方向上正向运动,在Y方向上正向运动
    true_states.append(x_hat)

true_states = np.array(true_states)

# 模拟测量数据(带有噪声)
measurements = np.dot(H, true_states.T).T + np.random.multivariate_normal([0, 0], R, size=len(true_states))

# 存储估计值
estimated_states = []

# 卡尔曼滤波过程
for z in measurements:
    # 预测步骤
    x_hat_minus = np.dot(A, x_hat)
    P_minus = np.dot(np.dot(A, P), A.T) + Q

    # 更新步骤
    K = np.dot(np.dot(P_minus, H.T), np.linalg.inv(np.dot(np.dot(H, P_minus), H.T) + R))
    x_hat = x_hat_minus + np.dot(K, z - np.dot(H, x_hat_minus))
    P = np.dot((np.eye(2) - np.dot(K, H)), P_minus)

    estimated_states.append(x_hat)

estimated_states = np.array(estimated_states)

# 绘制真实轨迹和估计值
plt.plot(true_states[:, 0], true_states[:, 1], 'b',label='True States', linestyle='--')
plt.plot(measurements[:, 0], measurements[:, 1], 'ro', label='Measurements')
plt.plot(estimated_states[:, 0], estimated_states[:, 1],'bo', label='Estimated States')

plt.title('State Space Kalman Filter Example')
plt.xlabel('X Position')
plt.ylabel('Y Position')
plt.legend()
plt.show()

将生成的带噪声轨迹数据和KF估计的位置数据用散点的方式绘制出来,其中红色为带噪声的模拟测量位置,蓝色为KF估计的位置。
在这里插入图片描述

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

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

相关文章

uniapp微信小程序-请求二次封装(直接可用)

一、请求封装优点 代码重用性:通过封装请求,你可以在整个项目中重用相同的请求逻辑。这样一来,如果 API 发生变化或者需要进行优化,你只需在一个地方修改代码,而不是在每个使用这个请求的地方都进行修改。 可维护性&a…

Java基础数据结构之哈希表

概念 顺序结构以及平衡树 中,元素关键码与其存储位置之间没有对应的关系,因此在 查找一个元素时,必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) ,平衡树中为树的高度,即 O( log2N ) ,搜索的效…

应急响应-内存分析

在应急响应过程中,除了上述几个通用的排查项,有时也需要对应响应服务器进行内存的提权,从而分析其中的隐藏进程。 内存的获取 内存的获取方法有如下几种: 基于用户模式程序的内存获取;基于内核模式程序的内存获取&a…

SparkSql---用户自定义函数UDFUDAF

文章目录 1.UDF2.UDAF2.1 UDF函数实现原理2.2需求:计算用户平均年龄2.2.1 使用RDD实现2.2.2 使用UDAF弱类型实现2.2.3 使用UDAF强类型实现 1.UDF 用户可以通过 spark.udf 功能添加自定义函数,实现自定义功能。 如:实现需求在用户name前加上"Name:…

lv14 内核内存管理、动态分频及IO访问 12

一、内核内存管理框架 内核将物理内存等分成N块4KB,称之为一页,每页都用一个struct page来表示,采用伙伴关系算法维护 补充: Linux内存管理采用了虚拟内存机制,这个机制可以在内存有限的情况下提供更多可用的内存空…

docker compose实现mysql一主多从

参考了很多博客,死磕了几天,最终跑起来了,不容易,晚上喝瓶82年可乐庆祝下。 1、整体文件结构,这里忽略log、conf、data映射目录 2、docker-compose.yml文件内容如下: version: 3.3 services:mysql-master…

Android App开发-简单控件(3)——常用布局

3.3 常用布局 本节介绍常见的几种布局用法,包括在某个方向上顺序排列的线性布局,参照其他视图的位置相对排列的相对布局,像表格那样分行分列显示的网格布局,CommonLayouts以及支持通过滑动操作拉出更多内容的滚动视图。 3.3.1 线…

代码随想录算法训练DAY29|回溯5

算法训练DAY29|回溯5 491.递增子序列 力扣题目链接 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] 说…

【QT】QPainter基本绘图

目录 1 QPainter绘图系统 1.1 QPainter与QPaintDevice 1.2 paintEvent事件和绘图区 1.3 QPainter绘图的主要属性 1.4 创建实例 2 QPen的主要功能 2.1 线条样式 2.2 线条端点样式 2.3 线条连接样式 3 QBrush的主要功能 4 渐变填充 5 QPainter绘制基本图形元件 5.1 基本图形元件 …

burp靶场--身份认证漏洞

burp靶场–身份认证漏洞 https://portswigger.net/web-security/authentication#what-is-authentication 1.身份认证漏洞: ### 身份验证漏洞 从概念上讲,身份验证漏洞很容易理解。然而,由于身份验证和安全性之间的明确关系,它们…

基于Java SSM框架实现学校招生信息网系统项目【项目源码+论文说明】

基于java的SSM框架实现学生招生信息网系统演示 摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,学校招生信息网当然也不能排除在外。学校招生信息网是以实际运用为开发背…

【大数据】Flink 中的状态管理

Flink 中的状态管理 1.算子状态2.键值分区状态3.状态后端4.有状态算子的扩缩容4.1 带有键值分区状态的算子4.2 带有算子列表状态的算子4.3 带有算子联合列表状态的算子4.4 带有算子广播状态的算子 在前面的博客中我们指出,大部分的流式应用都是有状态的。很多算子都…

OpenCV 0 - VS2019配置OpenCV

1 配置好环境变量 根据自己的opencv的安装目录配置 2 新建一个空项目 3 打开 视图->工具栏->属性管理器 4 添加新项目属性表 右键项目名(我这是opencvdemo)添加新项目属性表,如果有配置好了的属性表选添加现有属性表 5 双击选中Debug|x64的刚添加的属性表 6 (重点)添…

[LVGL] 可点击的文字label

LVGL8.x 自带的label 是没有点击响应的功能,即使加了lv_obj_add_event_cb 也不起作用,为了解决这个问题,我们使用了按钮控件去模拟纯label的效果;有了这个demo用户就可以实现类似超链接 点击一个文字就跳转到某个页面的功能。 st…

Kotlin 教程(环境搭建)

Kotlin IntelliJ IDEA环境搭建 IntelliJ IDEA 免费的社区版下载地址:Download IntelliJ IDEA – The Leading Java and Kotlin IDE 下载安装后,我们就可以使用该工具来创建项目,创建过程需要选择 SDK, Kotlin 与 JDK 1.6 一起使…

【大数据】详解 Flink 中的 WaterMark

详解 Flink 中的 WaterMark 1.基础概念1.1 流处理1.2 乱序1.3 窗口及其生命周期1.4 Keyed vs Non-Keyed1.5 Flink 中的时间 2.Watermark2.1 案例一2.2 案例二2.3 如何设置最大乱序时间2.4 延迟数据重定向 3.在 DDL 中的定义3.1 事件时间3.2 处理时间 1.基础概念 1.1 流处理 流…

1.【Vue3】前端开发引入、Vue 简介

1. 前端开发引入 1.1 前端开发前置知识 通过之前的学习,已经通过 SpringBoot 和一些三方技术完成了大事件项目的后端开发。接下来开始学习大事件项目的前端开发,前端部分借助两个框架实现: Vue3(一个 JS 框架)基于 …

Vue-Router: 如何使用路由元信息来管理路由?

Vue-Router是Vue.js官方的路由管理器,它可以帮助我们快速构建单页应用程序(SPA)。除了常见的路由功能外,Vue-Router还支持使用路由元信息来管理和控制路由。路由元信息是可以附加到路由上的自定义属性,它可以帮助我们实…

LandrayOA内存调优 / JAVA内存调优 / Tomcat web.xml 超时时间调优实战

目录 一、背景说明 二、LandrayOA / Tomcat 内存调优 2.1 \win64\tomcat\conf\web.xml 文件调优 2.2 \win64\tomcat\bin\catalina64.bat 文件调优 一、背景说明 随着系统的使用时间越来越长,数据量越多,发现系统的有些功能越来越慢&…

在腾讯云上部署幻兽帕鲁,实现游戏自由!

在帕鲁的世界,你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活,也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活,也可以为你在工厂工作。你也可以将它们进行售卖,或肢解后食用。引用自&#xf…