简介:本资源是一份聚焦贝叶斯滤波理论与随机过程建模的深度学习材料,面向大数据分析、智能感知及控制领域的高校学生、算法工程师与科研人员,旨在系统厘清贝叶斯公式在动态随机系统中的递推建模逻辑,解决非线性、非高斯场景下状态估计与不确定性传播的核心问题。资源为单文件PDF,大小16.25MB,内容涵盖贝叶斯滤波基本原理、先验/似然/后验概率密度的连续与离散形式推导、与卡尔曼滤波的对比分析、状态方程与观测方程的联合建模方法,以及温度估计等典型实验案例的完整数学演算和直观图示。预览文本显示其包含随机过程独立性讨论、主观概率赋值逻辑、边缘与联合密度积分变换、贝叶斯递推流程图解及预测-更新两步框架详解,结构严谨、推导扎实。目前已有447人学习下载,适合希望夯实概率建模基础、理解滤波算法本质并应用于机器人导航、传感器融合等实际场景的学习者。
1. 贝叶斯滤波为什么不是“套个公式就完事”:它本质是让模型在不确定中持续校准的动态推理引擎
你手头有一组带噪声的传感器读数,比如IMU角速度漂移严重、激光雷达在雨雾中点云稀疏、摄像头在低光照下目标边界模糊——这时候扔一个YOLOv8或ResNet进去,精度可能直接掉20%。但如果你把“当前状态是什么”这个问题,从“静态分类/检测”切换成“随时间演化的概率分布估计”,贝叶斯滤波就不再是教科书里的积分符号,而是你系统里那个边跑边自问“我到底信几分”的实时校准器。它不承诺消除噪声,而是把噪声建模为先验知识的一部分;不追求单次最优解,而是在每一帧输入后,用贝叶斯公式融合新证据与旧信念,输出一个带置信度的状态后验分布。随机过程则为这种“状态如何随时间变化”提供了数学骨架——比如用马尔可夫假设简化状态转移,用高斯白噪声刻画过程不确定性。这不是给算法加一层玄学包装,而是当你的系统必须在工业现场连续运行7×24小时、不能靠人工重置、无法预知下一秒干扰类型时,唯一能扛住真实世界混沌性的底层逻辑。适合正在做机器人定位、电池SOC估计、设备剩余寿命预测、或任何需要“带置信度输出”的嵌入式感知系统的工程师——尤其当你发现滤波结果总在某个阈值附近反复震荡、或者突变后长时间无法收敛时,问题大概率不出在调参,而出在贝叶斯框架的建模完整性上。
2. 从离散到连续:三类贝叶斯滤波器的选型逻辑与适用边界
贝叶斯滤波不是单一算法,而是一族满足“递推贝叶斯更新”结构的算法统称。选错类型,后面所有参数调试都是徒劳。核心差异不在代码复杂度,而在对状态空间和观测模型的数学假设上。
2.1 离散状态+离散观测:直觉最清晰的朴素贝叶斯滤波器(Naive Bayes Filter)
适用于状态可穷举的场景,比如AGV小车在已知拓扑图中的节点定位(仅10个路口)、设备健康状态分级(正常/亚健康/故障三级)。其转移模型 $p(x_t \mid x_{t-1})$ 和观测模型 $p(z_t \mid x_t)$ 均以查表形式存储,无需微分方程。
# 状态空间:['A', 'B', 'C'],观测空间:['red', 'green', 'blue'] transition_matrix = np.array([ [0.7, 0.2, 0.1], # 从A出发,70%留A,20%去B,10%去C [0.1, 0.8, 0.1], # 从B出发... [0.2, 0.1, 0.7] ]) observation_matrix = np.array([ [0.9, 0.05, 0.05], # 在A点,90%概率观测到red [0.05, 0.9, 0.05], # 在B点... [0.05, 0.05, 0.9] ]) def naive_bayes_update(prior, z_obs): # prior: shape (3,) 概率向量 # z_obs: 观测索引,0=red, 1=green, 2=blue likelihood = observation_matrix[:, z_obs] # 取第z_obs列 unnormalized_posterior = likelihood * prior return unnormalized_posterior / unnormalized_posterior.sum() # 初始先验:小车可能在任意节点,均匀分布 prior = np.array([1/3, 1/3, 1/3]) z_seq = [0, 0, 1] # 连续观测到 red, red, green for z in z_seq: prior = naive_bayes_update(prior, z) print(f"观测{z}后,后验: A={prior[0]:.3f}, B={prior[1]:.3f}, C={prior[2]:.3f}")逻辑说明:
naive_bayes_update函数严格实现贝叶斯公式 $p(x_t\mid z_t) \propto p(z_t\mid x_t) \cdot p(x_t)$,其中prior是上一时刻的后验(即当前时刻先验),likelihood是观测似然。关键点在于:离散滤波器的“预测步”由 transition_matrix 完成(prior_next = transition_matrix.T @ prior_current),而代码中省略了这一步,因示例聚焦更新。实际部署必须补全预测-更新两步闭环。
参数说明:
transition_matrix[i,j]表示从状态j转移到状态i的概率(注意行列顺序!),observation_matrix[i,j]表示在状态i下观测到j的概率。矩阵需行和为1(转移)或列和为1(观测),否则会导致概率归一化失败。
2.2 连续状态+线性高斯模型:卡尔曼滤波(Kalman Filter)的不可替代性
当状态向量 $x_t \in \mathbb{R}^n$ 连续,且系统满足线性动力学 $x_t = F_t x_{t-1} + B_t u_t + w_t$、观测满足线性关系 $z_t = H_t x_t + v_t$,且过程噪声 $w_t \sim \mathcal{N}(0, Q_t)$、观测噪声 $v_t \sim \mathcal{N}(0, R_t)$ 时,卡尔曼滤波是贝叶斯滤波的解析解——后验 $p(x_t \mid z_{1:t})$ 恒为高斯分布,只需维护均值 $\hat{x}_t$ 和协方差 $P_t$ 两个参数。
class KalmanFilter: def __init__(self, F, B, H, Q, R, x0, P0): self.F = F # 状态转移矩阵 self.B = B # 控制输入矩阵 self.H = H # 观测矩阵 self.Q = Q # 过程噪声协方差 self.R = R # 观测噪声协方差 self.x = x0 # 当前状态估计 self.P = P0 # 当前协方差估计 def predict(self, u=None): # 预测步:x_{t|t-1} = F x_{t-1|t-1} + B u if u is not None: self.x = self.F @ self.x + self.B @ u else: self.x = self.F @ self.x # P_{t|t-1} = F P_{t-1|t-1} F^T + Q self.P = self.F @ self.P @ self.F.T + self.Q def update(self, z): # 计算卡尔曼增益 K = P H^T (H P H^T + R)^{-1} S = self.H @ self.P @ self.H.T + self.R K = self.P @ self.H.T @ np.linalg.inv(S) # 更新状态:x_{t|t} = x_{t|t-1} + K (z - H x_{t|t-1}) y = z - self.H @ self.x # 新息(Innovation) self.x = self.x + K @ y # 更新协方差:P_{t|t} = (I - K H) P_{t|t-1} I = np.eye(len(self.x)) self.P = (I - K @ self.H) @ self.P # 示例:一维匀速运动目标跟踪(位置+速度) F = np.array([[1, 1], [0, 1]]) # dt=1s,位置=位置+速度*1,速度不变 H = np.array([[1, 0]]) # 仅观测位置 Q = np.array([[0.1, 0], [0, 0.01]]) # 位置过程噪声大,速度小 R = np.array([[0.5]]) # 观测位置噪声 kf = KalmanFilter(F, np.zeros((2,1)), H, Q, R, x0=np.array([0, 0]), P0=np.eye(2)) # 模拟观测序列(含噪声的位置测量) z_seq = [0.1, 0.9, 2.2, 3.0, 3.8] # 真实轨迹应为 0,1,2,3,4 for z in z_seq: kf.predict() kf.update(np.array([z])) print(f"观测{z:.1f}后,估计位置={kf.x[0]:.2f}±{np.sqrt(kf.P[0,0]):.2f}")逻辑说明:
predict()实现先验分布演化,update()执行贝叶斯更新。关键洞察在于:卡尔曼增益 $K$ 是贝叶斯公式的具体化身——它自动权衡“我有多信模型”(由 $P$ 体现)和“我有多信观测”(由 $R$ 体现)。当 $R$ 很小(观测很准),$K$ 接近 $H^{-1}$,几乎全信观测;当 $P$ 很小(模型很准),$K$ 趋近于0,几乎忽略新观测。
参数说明:
Q过大导致滤波器过度平滑、响应迟钝;Q过小则易受噪声冲击、轨迹抖动。R过大让滤波器“怀疑一切”,收敛慢;R过小则“盲目自信”,易被野值带偏。工程经验:先固定R为传感器标称误差平方,再用真实数据调Q——观察残差 $y = z - H\hat{x}$ 的方差是否接近R,若远大于R,说明Q不够大,模型未覆盖足够不确定性。
2.3 连续状态+非线性模型:扩展卡尔曼滤波(EKF)与无迹卡尔曼滤波(UKF)的本质取舍
当系统存在强非线性(如GPS经纬度转UTM坐标、电机电流与转矩的指数关系),线性化假设失效。EKF 用雅可比矩阵局部线性化,UKF 用确定性采样(Sigma Points)捕获非线性变换后的统计特性。
# UKF 核心:生成 Sigma Points 并传播 def ukf_sigma_points(x, P, kappa=0): n = len(x) lambda_ = kappa + n # 生成 2n+1 个 sigma points X = np.zeros((2*n+1, n)) Wm = np.zeros(2*n+1) # 均值权重 Wc = np.zeros(2*n+1) # 协方差权重 X[0] = x Wm[0] = lambda_ / (lambda_ + n) Wc[0] = Wm[0] + (1 - kappa**2 + n) # 计算矩阵平方根(Cholesky分解) sqrtP = np.linalg.cholesky((lambda_ + n) * P) for i in range(n): X[1+i] = x + sqrtP[:, i] X[1+n+i] = x - sqrtP[:, i] Wm[1+i] = Wm[1+n+i] = 0.5 / (lambda_ + n) Wc[1+i] = Wc[1+n+i] = Wm[1+i] return X, Wm, Wc # 示例:非线性观测模型 z = exp(x) + v,x为标量 def nonlinear_observation(x): return np.exp(x) # 假设当前估计 x=0.5, P=0.1 x = 0.5 P = 0.1 X, Wm, Wc = ukf_sigma_points(np.array([x]), np.array([[P]]), kappa=0) # 传播 sigma points 通过非线性函数 Z = np.array([nonlinear_observation(xi[0]) for xi in X]) z_pred = np.sum(Wm * Z) # 加权均值作为预测观测 Pzz = np.sum(Wc * (Z - z_pred)**2) # 观测协方差 Pxz = np.sum(Wc * (X.flatten() - x) * (Z - z_pred)) # 交叉协方差 K = Pxz / Pzz # UKF增益(标量情形) x_updated = x + K * (2.8 - z_pred) # 假设观测z=2.8逻辑说明:UKF 不计算雅可比,而是用
2n+1个精心设计的采样点(Sigma Points)近似原始高斯分布,再将这些点通过真实非线性函数传播,最后用加权统计重构后验。其鲁棒性源于避免了EKF中“线性化点选择不当导致的截断误差”——尤其当非线性函数在工作点曲率极大时(如exp(x)在x=5附近),EKF的雅可比会严重失真。
参数说明:
kappa控制 Sigma Points 分布的“分散度”。kappa=0是标准选择;kappa>0使点更分散,增强对高阶矩的捕捉,但可能引入数值不稳定;kappa<0则更集中,适合弱非线性。血泪经验:永远先用 EKF 快速验证模型逻辑,再切 UKF 调参;UKF 的Q和R初始值可沿用 EKF 调优结果,避免从零摸索。
3. 随机过程建模:为什么你的滤波器总在特定工况下失效?
贝叶斯滤波的性能天花板,80%取决于随机过程建模的质量。很多工程师把Q和R当作“调参旋钮”,却忽略了它们背后对应的物理随机过程。错误的建模假设,会让滤波器在看似合理的参数下集体翻车。
3.1 过程噪声 $w_t$:不是“加点噪声就行”,而是对系统内在不确定性的诚实刻画
过程噪声协方差Q的设计,本质是在回答:“在不受控情况下,我的状态变量每秒自然漂移多少?”
- 错误做法:凭感觉设
Q = 0.01 * eye(n),或直接抄论文值。 - 正确路径:
- 识别主导噪声源:是电机编码器的量化误差?还是机械臂关节的温度漂移?或是电池老化导致的内阻突变?
- 建立物理模型:例如,某电机角速度传感器标称精度 ±0.5°/s,采样周期
dt=0.01s,则位置累积误差方差约为 $(0.5 \times \pi/180)^2 \times dt^2 \approx 7.6e-9$。 - 分块构造
Q:对状态向量[x, v, a](位置、速度、加速度),若加速度由电机力矩控制,其波动主要来自电流环PID的稳态误差,则Q[2,2]应显著大于Q[0,0]和Q[1,1]。
提示:用
np.linalg.eigvalsh(Q)查看Q的特征值。若最大特征值比最小值大5个数量级,说明噪声在不同维度上极不均衡——此时滤波器会过度关注高噪声维度,抑制低噪声维度的更新,导致状态耦合失真。
3.2 观测噪声 $v_t$:标称误差≠实际误差,必须用残差分析反推
观测噪声协方差R的常见误区是直接采用传感器手册的“精度”指标(如“GPS水平精度2m”)。但实际中,多径效应、信号遮挡、时钟不同步会使其在特定场景下恶化10倍。
# 在线估计 R:用滑动窗口计算新息(Innovation)y = z - Hx 的协方差 innovations = [] window_size = 50 def online_R_estimator(y_new): innovations.append(y_new) if len(innovations) > window_size: innovations.pop(0) if len(innovations) >= window_size//2: # 计算窗口内新息的协方差 Y = np.array(innovations) R_est = np.cov(Y.T) # 若Y为(m, T)矩阵,cov返回(m,m) return R_est return None # 在滤波循环中调用 for z in z_seq: kf.predict() kf.update(z) y = z - kf.H @ kf.x # 新息 R_adapt = online_R_estimator(y) if R_adapt is not None: kf.R = 0.9 * kf.R + 0.1 * R_adapt # 指数平滑更新逻辑说明:新息
y理论上应为白噪声,其协方差应等于S = H P H^T + R。若P已较准确,则y的方差主要反映R。该在线估计算法将R从“固定超参”变为“随环境自适应变量”,特别适用于车载视觉SLAM中,当车辆驶入隧道(视觉失效)或强光反射区(特征点误匹配)时,自动增大R,降低视觉观测权重,防止滤波器发散。
参数说明:
window_size决定自适应速度。太小(如10)导致R频繁跳变,滤波器震荡;太大(如500)则响应迟钝,错过快速变化的干扰。推荐起始值:window_size = 100,然后观察R估计值在稳定工况下的标准差,若超过均值15%,则减小窗口。
3.3 相关性陷阱:当Q和R不再是对角阵
真实系统中,噪声常具相关性。例如,IMU的陀螺仪和加速度计共用同一温度传感器,温漂会同时影响两者;多摄像头系统中,同一光源闪烁会同步污染所有图像的亮度通道。
# 构造带相关性的 Q(以2D位置+速度为例) # 假设x和y方向的加速度噪声高度相关(机械振动同源) Q_corr = np.array([ [0.1, 0.08, 0, 0], # x_acc 与 x_acc, x_acc 与 y_acc [0.08, 0.1, 0, 0], # y_acc 与 x_acc, y_acc 与 y_acc [0, 0, 0.01, 0], # x_vel 噪声独立 [0, 0, 0, 0.01] # y_vel 噪声独立 ])避坑点:若忽略相关性,强行用对角
Q,滤波器会低估状态间的耦合强度,导致协方差P过度收缩,进而使卡尔曼增益K偏大——表现为对观测过度反应,轨迹出现高频振荡。验证方法:绘制新息y的自相关函数(ACF),若在滞后1步处显著非零,说明R未建模时间相关性;若y_x与y_y的互相关系数绝对值 >0.3,说明R缺少空间相关性。
4. 贝叶斯公式落地:从理论推导到代码实现的三个致命断层
贝叶斯公式 $p(x\mid z) = \frac{p(z\mid x)p(x)}{p(z)}$ 看似简单,但工程实现中存在三个常被忽视的断层,导致“公式对、代码错、结果崩”。
4.1 断层一:归一化常数 $p(z)$ 不是标量,而是高维积分黑洞
在离散情形,$p(z) = \sum_x p(z\mid x)p(x)$ 可精确计算;但在连续高维状态空间,$p(z) = \int p(z\mid x)p(x)dx$ 无法解析求解,蒙特卡洛采样又计算爆炸。所有实用滤波器都绕过直接计算 $p(z)$:
- 卡尔曼系列:利用高斯假设,使后验解析可得,$p(z)$ 仅用于理论推导,代码中完全不出现;
- 粒子滤波:用重要性采样权重 $w^{(i)} \propto p(z\mid x^{(i)})p(x^{(i)})$,归一化时用 $\sum_i w^{(i)}$ 近似 $p(z)$;
- 致命错误:在粒子滤波中,若忘记对权重归一化,或归一化时用了
sum(w)而非sum(w)/N,会导致所有粒子权重坍缩为0或无穷,滤波器瞬间死亡。
# 粒子滤波权重更新(正确写法) def particle_weight_update(particles, z, likelihood_func, prior_func): weights = np.zeros(len(particles)) for i, x in enumerate(particles): # p(z|x) * p(x) —— 注意:prior_func 返回先验概率密度值,非采样 weights[i] = likelihood_func(x, z) * prior_func(x) # 关键:归一化!且必须处理数值下溢 weights += 1e-300 # 防0除 weights /= np.sum(weights) # 此处 sum(weights) 就是 p(z) 的近似 # 有效粒子数评估(判断是否需重采样) Neff = 1.0 / np.sum(weights**2) return weights, Neff逻辑说明:
weights /= np.sum(weights)这一行,就是用离散和近似了连续积分 $p(z)$。若省略,后续重采样将基于未归一化的权重,导致粒子多样性崩溃。玄学技巧:当weights中最大值与最小值相差超100倍时,先做log_weights = log(likelihood) + log(prior),再用 log-sum-exp 技巧归一化,避免浮点下溢。
4.2 断层二:先验 $p(x)$ 不是“随便设个初值”,而是对初始认知的严谨编码
新手常设x0 = [0,0],P0 = eye(2),认为“反正很快收敛”。但若初始协方差P0过小(如1e-6),滤波器会极度信任初始猜测,拒绝接受早期观测,导致收敛延迟;若P0过大(如1e6),则前期估计方差爆炸,轨迹毛刺。
# 基于先验知识构造 P0 的工程方法 def construct_P0_from_knowledge(): # 场景:无人机GPS冷启动,已知初始位置误差 < 10m(95%置信) # 高斯分布95%置信区间为 ±2σ,故 σ ≈ 10/2 = 5m pos_sigma = 5.0 # 初始速度未知,但物理上不可能 > 30m/s,设 σ_v = 30/3 ≈ 10m/s(3σ原则) vel_sigma = 10.0 # 假设位置与速度无关 P0 = np.diag([pos_sigma**2, vel_sigma**2]) return P0 P0 = construct_P0_from_knowledge() # 比 eye(2) 有物理意义得多参数说明:
P0的对角线元素是各状态分量的方差,非标准差。若用标准差赋值(如P0[0,0] = 5),会导致滤波器认为位置误差只有5米(而非25平方米),严重低估不确定性。后悔药:在滤波初期(前10步),监控trace(P_t)是否单调下降。若先升后降,说明P0过小;若持续高位震荡,说明P0过大或Q不足。
4.3 断层三:似然 $p(z\mid x)$ 不是“套个传感器模型”,而是对观测机制缺陷的显式建模
似然函数常被简化为z ~ N(Hx, R),但这假设观测误差恒为高斯白噪声。现实中,传感器存在:
- 野值(Outliers):激光雷达在玻璃幕墙前产生虚假远距离点;
- 缺失观测(Missing Data):视觉特征点在纹理缺失区域无法提取;
- 异方差(Heteroscedasticity):深度相机在远距离时噪声方差随距离平方增长。
# 健壮似然:混合模型处理野值 def robust_likelihood(x, z, H, R, outlier_ratio=0.05): # 主模型:高斯似然 main_loglik = -0.5 * (z - H @ x).T @ np.linalg.inv(R) @ (z - H @ x) \ - 0.5 * np.log(np.linalg.det(2*np.pi*R)) # 野值模型:均匀分布(覆盖整个观测空间) # 假设观测空间为 [-100, 100],则均匀密度 = 1/200 uniform_loglik = np.log(1/200) # 混合似然 loglik = np.log(outlier_ratio * np.exp(uniform_loglik) + (1-outlier_ratio) * np.exp(main_loglik)) return np.exp(loglik) # 在粒子滤波中使用 weight = robust_likelihood(particle_x, z, H, R)逻辑说明:该似然函数赋予野值一个微小但非零的概率,防止单个错误观测(如激光雷达误测1000m)将整个滤波器拖垮。
outlier_ratio是超参,可通过离线数据集上野值比例估计。实践建议:对关键传感器(如定位用的GNSS),务必在似然中加入野值建模;对冗余传感器(如多IMU),可先用简单高斯似然,再用一致性检验剔除异常。
5. 避坑指南:贝叶斯滤波项目中五个血泪换来的高频问题
5.1 现象:滤波器输出状态平稳,但协方差P持续收缩至接近零,且不再反弹
原因:过程噪声Q设置过小,或观测噪声R过大,导致滤波器“过度自信”——它认为模型完美,观测无用,于是不断压缩不确定性。长期后果是丧失对突发扰动的响应能力,一旦真实系统出现未建模动态(如电机堵转),滤波器将剧烈发散。
解决:检查Q的量纲是否与状态导数单位匹配(如位置状态x的Q应有 $m^2/s^2$ 单位);用np.trace(P)绘图,若其单调递减且趋近于机器精度(1e-15),立即增大Q10倍并重测。
5.2 现象:新息y = z - Hx的均值显著偏离零(如持续为正)
原因:模型偏差(Model Bias)——状态方程F或观测方程H存在系统性误差。例如,用恒速模型跟踪加速车辆,或H矩阵未考虑相机镜头畸变。此时y不是白噪声,而是带有趋势的信号。
解决:在predict步后,不直接update,而是先计算y_mean = mean(y_window),若|y_mean| > 3*std(y_window),则引入偏差补偿项:z_corrected = z - y_mean,再用z_corrected更新。进阶方案是扩展状态向量,将偏差b作为新状态估计(x_aug = [x; b],F_aug增加b恒定假设)。
5.3 现象:粒子滤波中有效粒子数Neff快速衰减至1,重采样后所有粒子相同
原因:重要性权重方差过大,通常因提议分布(Proposal Distribution)与真实后验p(x_t|z_{1:t})匹配度差。常见于非线性强烈且Q过大时,粒子在传播后严重偏离观测区域。
解决:改用辅助粒子滤波(Auxiliary PF),其提议分布融入最新观测信息;或采用正则化粒子滤波(Regularized PF),在重采样后对粒子添加高斯核平滑。代码层面,优先检查likelihood_func是否在粒子位置x处返回了合理概率(非全0或全1)。
5.4 现象:UKF 在状态维度n>10时计算崩溃,sqrtP分解失败
原因:P矩阵病态(条件数过大),常因Q或R设置不当导致协方差矩阵非正定。UKF 的 Cholesky 分解要求P严格正定。
解决:在ukf_sigma_points函数开头添加正则化:P_reg = P + epsilon * np.eye(n),epsilon=1e-8;或改用平方根UKF(SR-UKF),直接维护P = S S^T的平方根S,避免显式计算P和分解。
5.5 现象:多传感器融合时,加入新传感器后整体性能反而下降
原因:未校准传感器间的时间戳偏移(Time Offset)或空间外参(Extrinsic Parameters)。例如,IMU与相机时间不同步10ms,在高速运动下导致H矩阵映射错误;或激光雷达坐标系未精确标定,H矩阵引入系统性旋转误差。
解决:必须进行联合标定。用已知运动轨迹(如标定板匀速平移)采集数据,以时间偏移delta_t和外参T_{lidar2imu}为优化变量,最小化所有传感器重投影误差。工具推荐kalibr(ROS生态)或自研非线性优化(Ceres Solver)。切记:滤波器调参前,先完成标定!
6. 进阶验证:用“残差卡方检验”定量诊断滤波器健康度
参数调优不能只靠肉眼观察轨迹平滑度。一个被工业界广泛采用的定量验证方法是残差卡方检验(Chi-Square Test on Residuals),它直接检验新息y_t = z_t - H_t \hat{x}_{t|t-1}是否符合理论分布 $y_t \sim \mathcal{N}(0, S_t)$,其中 $S_t = H_t P_{t|t-1} H_t^T + R_t$。
6.1 卡方检验的数学基础与工程意义
若滤波器建模正确,新息y_t应为零均值高斯白噪声,其加权平方和 $\gamma_t = y_t^T S_t^{-1} y_t$ 应服从自由度为m(观测维度)的卡方分布 $\chi^2_m$。这意味着:
- 对于单维观测(
m=1),95% 置信区间为[0, 3.84]; - 对于二维观测(
m=2),95% 置信区间为[0, 5.99]; - 若
γ_t频繁超出区间,说明Q、R或H存在系统性偏差。
6.2 实现一个轻量级在线检验器
from scipy.stats import chi2 class ChiSquareValidator: def __init__(self, df, confidence=0.95): self.df = df # 自由度 = 观测维度 m self.confidence = confidence self.chi2_upper = chi2.ppf(confidence, df) # 卡方分布上分位数 self.history = [] def validate(self, y, S): # y: (m,) 观测新息向量 # S: (m,m) 新息协方差矩阵 try: # 计算加权平方和 γ = y^T S^{-1} y S_inv = np.linalg.inv(S) gamma = y.T @ S_inv @ y self.history.append(gamma) # 检查是否越界 is_valid = gamma <= self.chi2_upper if not is_valid: print(f"⚠️ 卡方检验失败:γ={gamma:.3f} > {self.chi2_upper:.3f} " f"(df={self.df}, {self.confidence*100:.0f}%置信)") return is_valid except np.linalg.LinAlgError: print("❌ 卡方检验失败:S矩阵奇异,无法求逆") return False def get_stats(self): if not self.history: return {} arr = <p> <a href="https://download.csdn.net/download/weixin_45075135/86400449" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>