卡尔曼滤波的概率解释

本文详细介绍了卡尔曼滤波算法,包括其基本前提、数学推导和与其他方法(如递推最小二乘估计RLS、隐马尔可夫模型、最大似然估计)的比较。卡尔曼滤波是一种在高斯噪声中对状态进行最优估计的线性递推算法,适用于状态不可直接观测但可以通过观测值推断的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

由于概率论要求有个结课论文,加上之前学习了下简单的Kalman滤波,发现还有很多有意思的内容不太理解,于是水了这么篇文章。

Kalman滤波

卡尔曼滤波算法需要满足两个前提,另外还有一个隐含的前提:
系统为有限维的线性系统,如果系统非线性,可以用扩展卡尔曼滤波算法(EKF)进行最优估计。
噪声服从高斯分布,即高斯白噪声。
系统在k时刻的状态只与k-1时刻状态和当前输入有关(马尔可夫性)。
卡尔曼滤波算法的过程如下,首先定义FkF_kFk为状态转移矩阵,体现k-1时刻对k时刻的影响;GkG_kGk为控制输入矩阵,表示控制输入对于状态的影响;wkw_kwk为过程噪声矩阵,其服从均值为0,协方差矩阵为QkQ_kQk的高斯分布。
那么从k-1时刻估计k时刻,可以使用下式进行估计, xk\ x_k xk为状态变量在k时刻的真值:
xk=Fkxk−1+Gkuk+wk                             (1−1) {x_k=F}_kx_{k-1}+G_ku_k+w_k\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1-1) xk=Fkxk1+Gkuk+wk                             (11)
那么我们观测的先验估计为,xk∣k−1x_{k|k-1}xkk1为状态变量x根据k-1时刻对k时刻的估计值:
xk∣k−1=Fkxk−1∣k−1+Gkuk+wk                (1−2) {x_{k|k-1}=F}_kx_{k-1|k-1}+G_ku_k+w_k\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1-2) xkk1=Fkxk1k1+Gkuk+wk                (12)
定义k时刻的观测量zkz_kzk,观测矩阵HkH_kHk表示状态空间到观测空间的映射,vkv_kvk为观测噪声矩阵,同样为服从均值为0,协方差矩阵为RkR_kRk的观测噪声矩阵。那么对于从k时刻的观测估计状态量有:
zk=Hkxk+vk                                     (1−3) z_k=H_kx_k+v_k\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1-3) zk=Hkxk+vk                                     (13)
预测过程的误差可使用协方差矩阵Pk∣k−1P_{k|k-1}Pkk1表示,有Pk∣k−1=Cov( xk∣k−1,xk∣k−1)P_{k|k-1}= {Cov(\ x}_{k|k-1},x_{k|k-1})Pkk1=Cov( xkk1,xkk1) ,可以写为:
Pk∣k−1=FkPk−1∣k−1Fkt+Qk                        (1−4)  {P_{k|k-1}=F}_kP_{k-1|k-1}{F_k}^t+Q_k\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1-4)\ Pkk1=FkPk1k1Fkt+Qk                        (14) 
推导过程如下:
KaTeX parse error: Expected group after '\bigm' at end of input: …_k)\ +Q_k\bigm
利用协方差矩阵的性质有:
 =FkCov( xk−1∣k−1,Fkxk∣k−1)+0+Qk= Fk[Cov(Fkxk∣k−1,xk∣k−1)]T+Qk= Fk[FkCov(xk∣k−1)]T+Qk= FkPk−1∣k−1Fkt+Qk {\ =F_kCov(\ x}_{k-1|k-1},F_kx_{k|k-1})+0+Q_k \\ {=\ F}_k\left[Cov\left(F_kx_{k|k-1},x_{k|k-1}\right)\right]^T+Q_k\\ =\ F_k\left[F_kCov\left(x_{k|k-1}\right)\right]^T+Q_k\\ =\ F_kP_{k-1|k-1}{F_k}^t+Q_k  =FkCov( xk1k1,Fkxkk1)+0+Qk= Fk[Cov(

### 关于卡尔曼滤波及其变种在 Python 中的实现 卡尔曼滤波是一种用于线性动态系统的状态估计方法,其核心思想是通过递推的方式最小化预测误差方差[^1]。对于非线性和非高斯系统,则有多种扩展形式,如扩展卡尔曼滤波(Extended Kalman Filter, EKF)、无迹卡尔曼滤波(Unscented Kalman Filter, UKF)以及粒子卡尔曼滤波(Particle Kalman Filter)。以下是这些算法在 Python 中的具体实现方式。 #### 1. **标准卡尔曼滤波** 标准卡尔曼滤波适用于线性高斯系统。其实现可以通过定义状态转移矩阵 \( A \),观测矩阵 \( H \),过程噪声协方差矩阵 \( Q \),测量噪声协方差矩阵 \( R \) 和初始条件来完成。以下是一个简单的 Python 实现: ```python import numpy as np def kalman_filter(x_est_prev, P_prev, u, z, A, B, H, Q, R): # 预测阶段 x_pred = A @ x_est_prev + B @ u P_pred = A @ P_prev @ A.T + Q # 更新阶段 y = z - H @ x_pred S = H @ P_pred @ H.T + R K = P_pred @ H.T @ np.linalg.inv(S) x_est = x_pred + K @ y P_est = (np.eye(len(x_est)) - K @ H) @ P_pred return x_est, P_est ``` 此函数实现了基本的卡尔曼滤波逻辑,其中 `x_est` 是当前的状态估计,而 `P_est` 则表示状态估计的不确定性[^2]。 --- #### 2. **扩展卡尔曼滤波(EKF)** 当系统是非线性的但仍然接近高斯分布时,可以使用扩展卡尔曼滤波。它通过对非线性函数进行局部线性近似来处理非线性问题。下面是一个基于 Jacobian 的简单实现: ```python from scipy.optimize import approx_fprime def jacobian(f, x, *args): """计算 f 在点 x 处的雅可比矩阵""" epsilon = np.sqrt(np.finfo(float).eps) grad = lambda i: approx_fprime(x[i], lambda xi: f(*((xi,) + args))[i], epsilon)[i] J = np.array([grad(i) for i in range(len(x))]) return J def extended_kalman_filter(x_est_prev, P_prev, u, z, f, h, Q, R): F = jacobian(lambda x: f(x, u), x_est_prev) # 状态转移函数的雅可比矩阵 H = jacobian(h, x_est_prev) # 观测函数的雅可比矩阵 # 预测阶段 x_pred = f(x_est_prev, u) P_pred = F @ P_prev @ F.T + Q # 更新阶段 y = z - h(x_pred) S = H @ P_pred @ H.T + R K = P_pred @ H.T @ np.linalg.inv(S) x_est = x_pred + K @ y P_est = (np.eye(len(x_est)) - K @ H) @ P_pred return x_est, P_est ``` 在此代码中,`f` 表示状态转移函数,`h` 表示观测函数,两者均需提供对应的 Jacobian 计算[^2]。 --- #### 3. **无迹卡尔曼滤波(UKF)** 无迹卡尔曼滤波利用 Sigma Points 来捕捉非线性变换后的概率分布特性,从而避免了显式的 Jacobian 或 Hessian 计算。Python 库 `FilterPy` 提供了一个简洁的实现: ```python from filterpy.kalman import UnscentedKalmanFilter as UKF from filterpy.common import Q_discrete_white_noise def sigma_points_func(x, P): """自定义Sigma Point生成函数""" n = len(x) kappa = 0.0 lambda_ = n + kappa sqrt_lambda_P = np.linalg.cholesky((lambda_) * P) points = [] for i in range(n): points.append(x + sqrt_lambda_P[:, i]) points.append(x - sqrt_lambda_P[:, i]) points.append(x) return np.array(points) ukf = UKF(dim_x=4, dim_z=2, dt=0.1, fx=f_state_transition, hx=h_measurement, points=sigma_points_func) ukf.Q = Q_discrete_white_noise(dim=4, dt=0.1, var=0.1) ukf.R = np.diag([0.1, 0.1]) # 测量噪声协方差 ukf.x = np.array([0., 0., 0., 0.]) # 初始状态 ukf.P = np.eye(4) # 初始状态协方差 for z in measurements: ukf.predict() ukf.update(z) print('State estimate:', ukf.x) ``` 这里的关键在于如何设计 `sigma_points_func` 函数以适配具体的应用场景。 --- #### 4. **粒子卡尔曼滤波(PF)** 粒子卡尔曼滤波适合高度非线性和非高斯的情况。它的原理是对状态空间的概率密度函数进行离散采样并加权平均。以下是一个简化版本的实现: ```python class ParticleFilter: def __init__(self, num_particles, state_dim): self.num_particles = num_particles self.particles = np.random.randn(num_particles, state_dim) self.weights = np.ones(num_particles) / num_particles def predict(self, motion_model, noise_std): self.particles += motion_model() + np.random.normal(scale=noise_std, size=self.particles.shape) def update(self, measurement, likelihood_fn): weights = likelihood_fn(measurement, self.particles) self.weights *= weights self.weights /= sum(self.weights) def resample(self): indices = np.random.choice(range(self.num_particles), p=self.weights, size=self.num_particles) self.particles = self.particles[indices] self.weights = np.ones(self.num_particles) / self.num_particles pf = ParticleFilter(num_particles=1000, state_dim=2) for t in range(time_steps): pf.predict(motion_model=lambda: np.zeros(state_dim), noise_std=0.1) pf.update(measurements[t], likelihood_fn=lambda m, s: np.exp(-0.5 * ((m - s)**2))) pf.resample() ``` 以上代码展示了粒子滤波的核心流程:预测、更新和重采样[^3]。 --- ### 总结 上述四种方法分别针对不同类型的动态系统提供了有效的解决方案。标准卡尔曼滤波适用于线性高斯系统;扩展卡尔曼滤波则能应对轻微非线性情况下的建模需求;无迹卡尔曼滤波进一步减少了对导数计算的要求;而粒子卡尔曼滤波则是解决复杂非线性与非高斯问题的强大工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值