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

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

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估计的位置。
在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-29 21:46:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-29 21:46:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-29 21:46:03       82 阅读
  4. Python语言-面向对象

    2024-01-29 21:46:03       91 阅读

热门阅读

  1. jvm垃圾回收器

    2024-01-29 21:46:03       61 阅读
  2. 利用aspose进行word转pdf、打印pdf

    2024-01-29 21:46:03       73 阅读
  3. 爬虫学习笔记-站长素材网站图片下载

    2024-01-29 21:46:03       56 阅读
  4. Linux之父:我们正在从C语言转向Rust

    2024-01-29 21:46:03       52 阅读
  5. 【Python笔记】设计模式

    2024-01-29 21:46:03       64 阅读
  6. 计算机网络之三次握手,四次挥手

    2024-01-29 21:46:03       54 阅读
  7. Mongodb查询投射中的$elemMatch

    2024-01-29 21:46:03       52 阅读
  8. VLM 系列——Monkey——论文解读

    2024-01-29 21:46:03       61 阅读
  9. Web 上升的圆心

    2024-01-29 21:46:03       46 阅读