资讯动态

极大似然法RML递推辨识:从原理推导到在线监测与PID自整定实战

发布时间:2026/10/24 17:11:21 来源:尧图企业网站定制
简介这份资源围绕系统辨识中的极大似然法展开面向控制理论、信号处理及自动化方向的学习者与研究人员帮助其掌握从理论推导到参数估计落地的完整思路。压缩包共19个文件约865KB以m脚本、mat数据、jpg结果图和pptx讲义为主辅以tmw工程文件覆盖算法实现、数据生成与误差对比等环节。内容涉及RML递归极大似然估计、m序列与PRBS激励信号生成、参数估计误差分析以及白噪声与有色噪声条件下的输出误差对比可帮助读者理解在线学习方式下模型参数的逐步更新过程。已有187人学习下载适合作为课程实验、课题复现或系统辨识入门练习的参考素材便于对照代码与结果图验证算法有效性。1. 从一组发散的温度曲线说起这个压缩包到底装了什么去年帮一个做热处理设备的朋友看数据他手头有六台同型号炉子同一套 PID 参数跑出来的升温曲线却各走各的有的超调 8℃有的死活到不了设定值。他第一反应是传感器坏了换了三批热电偶曲线该发散还是发散。问题其实不在硬件而在于他从来没认真辨识过每台炉子的对象模型——控制器参数是拍脑袋给的模型是拍脑袋想的剩下的全靠玄学。这个「极大似然法.zip」解决的就是这类问题给定一组输入输出观测数据反推出系统的差分方程或传递函数参数。它属于系统辨识里最经典的一类参数估计方法核心思路是构造一个以未知参数为变量的似然函数让观测数据出现的概率最大。压缩包里围绕的是 RMLRecursive Maximum Likelihood递推极大似然法这条线适合控制、自动化、信号处理方向的学生和工程师尤其是需要把辨识算法跑在嵌入式或在线场景里的人。如果你只是想在 MATLAB 里点几下 System Identification Toolbox 出个结果这个包对你意义不大但如果你想搞清楚递推辨识里梯度怎么算、协方差怎么更新、为什么你的辨识结果总在漂那它值得拆开看。2. 极大似然辨识的原理骨架从批处理到递推的推导链2.1 似然函数是怎么和系统模型挂上钩的先把逻辑理清楚。假设系统是 ARMAX 结构A(z⁻¹) y(k) B(z⁻¹) u(k) C(z⁻¹) e(k)其中 e(k) 是零均值高斯白噪声方差为 σ²。在给定参数向量 θ [a₁…aₙ, b₁…bₙ, c₁…cₙ] 和输入序列 u 的条件下输出序列 y 的联合条件概率密度就是似然函数 L(θ)。对高斯噪声取负对数最大化似然等价于最小化V(θ) (1/2) Σ e²(k, θ) / σ² (N/2) ln σ²这里 e(k, θ) 是预测误差也就是用当前参数去预测输出时产生的残差。注意一个关键点ARMAX 里的 C(z⁻¹) 多项式让预测误差不再是简单的 y(k) - φᵀ(k)θ而是经过了一个噪声滤波器的白化处理。这就是极大似然比最小二乘“高级”的地方——最小二乘假设残差白噪声而极大似然显式地对噪声建模所以有色噪声场景下它的一致性更好。批处理版本的做法是给定一整段数据用数值优化牛顿法、高斯-牛顿法、Levenberg-Marquardt直接最小化 V(θ)。但批处理有两个硬伤一是数据量大时矩阵求逆吃不消二是它没法在线更新。RML 就是来解决这两个问题的。2.2 RML 的递推更新公式拆解RML 的核心是把批处理的牛顿迭代改写成递推形式。参数更新式θ(k) θ(k-1) K(k) · ψ(k) · e(k)其中 e(k) 是当前预测误差ψ(k) 是预测误差对参数的梯度也叫灵敏度函数K(k) 是增益矩阵。增益矩阵的更新涉及协方差矩阵 P(k)P(k) [P(k-1) - P(k-1)ψ(k)ψᵀ(k)P(k-1) / (λ ψᵀ(k)P(k-1)ψ(k))] / λλ 是遗忘因子通常取 0.95~0.99。λ1 时退化为标准递推最小二乘的协方差更新λ1 时旧数据被逐渐遗忘适合时变系统。但 λ 太小会导致协方差矩阵“爆炸”参数估计剧烈抖动这是新手最容易翻车的地方。灵敏度函数 ψ(k) 的计算是 RML 区别于 RELS递推增广最小二乘的关键。RELS 直接用数据向量 φ(k) [-y(k-1)…-y(k-n), u(k-1)…u(k-n), e(k-1)…e(k-n)] 近似 ψ(k)而 RML 要求 ψ(k) 满足C(z⁻¹) ψ(k) φ(k)也就是说灵敏度函数本身要经过噪声模型的滤波。实现上通常用递推方式计算ψ(k) φ(k) - c₁ψ(k-1) - … - cₙψ(k-n)这一步是 RML 计算量的大头也是它比 RELS 收敛慢但精度高的原因。压缩包里的实现应该就是围绕这个递推滤波展开的。2.3 为什么选 RML 而不是 RELS 或 ELS选型理由得说清楚。RELS 计算简单每步只需要更新参数和协方差但它在有色噪声下是有偏的——因为 φ(k) 里的 e(k-i) 用的是估计残差和真实噪声有偏差。ELS增广最小二乘试图通过同时估计噪声模型来修正但它的收敛性依赖初值初值不好直接发散。RML 从似然函数出发理论上在噪声模型正确时能达到 Cramér-Rao 下界是一致估计。代价是RML 每步要多算 n 次滤波n 是噪声模型阶数而且对初值 P(0) 和 θ(0) 更敏感。我一般会先用 RELS 跑前 200 步把参数初值稳下来再切到 RML。压缩包里如果提供了切换逻辑那说明作者是踩过坑的。3. 把压缩包跑起来环境、数据与第一个辨识结果3.1 目录结构与依赖确认解压后先别急着跑 main。我拿到一个辨识包的习惯是先看三样东西数据文件格式、主脚本的输入输出、有没有 README 或注释头。这个包的结构大概率是极大似然法/ ├── data/ # 观测数据通常是 .mat 或 .csv ├── rml.m # RML 核心递推函数 ├── rels.m # RELS 对比实现 ├── main_offline.m # 离线批处理辨识入口 ├── main_online.m # 在线递推辨识入口 └── utils/ # 画图、评估指标等辅助函数依赖方面如果是 MATLAB 实现核心递推部分不需要额外工具箱但画 Bode 图、计算频响可能需要 Control System Toolbox。如果是 Python 实现numpy 和 scipy 是底线matplotlib 用于可视化。先确认你的环境里有没有这些缺了先补。3.2 构造一组可复现的辨识数据没有实测数据怎么办自己造。用已知模型生成输入输出这样你才知道辨识结果准不准。下面这段 Python 代码生成一个二阶 ARMAX 系统的数据import numpy as np np.random.seed(42) N 2000 # 真实系统参数: A(z) 1 - 1.5z^-1 0.7z^-2 # B(z) 0.5z^-1 0.3z^-2 # C(z) 1 0.4z^-1 a_true [1.5, -0.7] b_true [0.5, 0.3] c_true [0.4] u np.random.randn(N) * 1.0 # 输入: 零均值高斯激励 e np.random.randn(N) * 0.1 # 噪声: 标准差 0.1 y np.zeros(N) for k in range(2, N): # ARMAX 差分方程 y[k] (1.5*y[k-1] - 0.7*y[k-2] 0.5*u[k-1] 0.3*u[k-2] e[k] 0.4*e[k-1]) np.savez(data/sim_data.npz, uu, yy, ee) print(f数据生成完毕: {N} 点, y 范围 [{y.min():.2f}, {y.max():.2f}])这段代码的逻辑说明先固定随机种子保证可复现然后按 ARMAX 差分方程逐点生成输出。注意 y[k] 的计算里a_true 的符号和差分方程写法有关——这里写的是 y[k] 1.5y[k-1] - 0.7y[k-2] …对应 A(z⁻¹) 1 - 1.5z⁻¹ 0.7z⁻²。参数说明u 的方差决定了信噪比e 的标准差决定了辨识难度。0.1 的噪声水平下RML 应该能在 500 步内收敛到真值附近。3.3 跑通 RML 主流程并检查收敛数据有了接下来调用 RML。假设包里的 rml.m 或 rml.py 接口是theta, P, err rml(u, y, na, nb, nc, lambda_)调用方式from rml import rml_recursive na, nb, nc 2, 2, 1 lam 0.98 # 遗忘因子 theta0 np.zeros(na nb nc) P0 np.eye(na nb nc) * 1000 theta_hist, P_hist, e_hist rml_recursive( u, y, na, nb, nc, lambda_lam, theta0theta0, P0P0 ) # 打印最后一步的参数估计 print(估计参数:, theta_hist[-1]) print(真实参数:, np.array([1.5, -0.7, 0.5, 0.3, 0.4]))参数说明na、nb、nc 分别是输出、输入、噪声的阶数必须和真实系统匹配或略高。λ0.98 是经验值数据量 2000 点且系统时不变时可以取 0.99 甚至 1.0。P0 取大值表示对初值不信任让算法快速修正。theta0 全零是常见做法但如果系统有较大直流增益建议用 RELS 先跑一段。跑完后看什么三个东西参数轨迹是否收敛、残差是否白噪声、P 矩阵是否稳定。如果参数在真值附近 ±5% 内波动且不再漂移基本就对了。如果参数一直振荡先检查 λ 是不是太小再检查数据里有没有直流分量没去掉。4. 避坑与排查RML 辨识中最容易翻车的五个地方4.1 现象参数估计值缓慢漂移越跑越偏原因遗忘因子 λ 设得太小比如 0.9 以下。λ 小意味着旧数据被快速丢弃协方差矩阵 P 无法收敛到稳定值参数跟着噪声走。另一个可能是输入信号激励不足——如果 u 的频谱覆盖不了系统的动态范围某些参数就不可辨识。解决先确认输入信号的持续激励条件。对于二阶系统输入至少要是伪随机序列或扫频信号不能是阶跃或常数。λ 从 0.99 开始试如果系统确实时变再往 0.95 降。降的时候观察 P 矩阵的迹如果迹在 10⁴ 以上还在涨说明 λ 太小了。4.2 现象前 100 步参数剧烈跳变甚至发散原因初值 P0 太大或 θ0 太离谱。P0 取 10⁶ 时第一步增益 K 接近 1参数直接跳到让预测误差最大的方向。如果数据里前几个点有异常值直接带偏。解决P0 取 10³~10⁴ 就够了。更稳的做法是先用 RELS 跑 100~200 步把 θ 和 P 稳下来再切 RML。压缩包里如果有warmup参数把它打开。另外检查数据前 10 个点有尖峰就剔掉。4.3 现象噪声模型阶数 nc 设大了参数估计反而变差原因过拟合。nc 太大时C(z⁻¹) 会去拟合数据里的非噪声成分导致灵敏度函数 ψ(k) 计算失真参数估计的方差增大。RML 对噪声模型阶数比 RELS 更敏感。解决从 nc1 开始试逐步加到 2 或 3。判断标准不是拟合误差最小而是残差的自相关函数是否落在置信区间内。如果 nc 从 1 加到 2 后残差自相关没有明显改善就停在 1。AIC 或 BIC 准则也可以用来定阶但计算量会上去。4.4 现象MATLAB 和 Python 实现结果对不上原因差分方程符号约定不同。MATLAB 的 ARMAX 通常写成 A(z)y(k) B(z)u(k) C(z)e(k)其中 A(z) 1 a₁z⁻¹ …而有些 Python 实现写成 y(k) -a₁y(k-1) - … …符号正好相反。另外MATLAB 的armax返回的 b 参数可能不含延迟而手写实现里 b₁ 对应 u(k-1)。解决拿一组已知参数生成数据分别用两个实现跑对比估计出的参数符号和延迟。如果符号相反在调用前把数据或参数取反。延迟问题看 b 的第一个非零值对应 u(k-d) 里的 d统一约定。4.5 现象在线辨识时 CPU 占用高实时性跟不上原因RML 每步要算 n 次滤波n 是 nc 的阶数加上矩阵运算在低端 MCU 上确实吃力。如果采样周期是 10ms而单步计算要 15ms直接崩。解决降阶。先试 na2, nb2, nc1这是工业对象最常见的配置。如果还不行把 RML 换成 RELS精度损失 10%~20% 但计算量减半。再不行就降采样把辨识周期从 10ms 放到 50ms用牺牲带宽换计算时间。压缩包里如果有定点实现优先用定点版本。5. 进阶技巧用 RML 做在线监测与模型切换5.1 把辨识结果接到控制器参数自整定上RML 跑通之后最有价值的用法不是离线画个 Bode 图而是把在线估计出的模型参数实时喂给控制器。以 PID 为例假设辨识出二阶模型G(z) (b₁z⁻¹ b₂z⁻²) / (1 a₁z⁻¹ a₂z⁻²)可以用零极点对消法反推 PID 参数。下面这段代码演示了从 RML 估计结果计算 PID 增益的流程def rml_to_pid(theta, na, nb, Ts): 从 RML 估计的 ARMAX 参数反推 PID 增益 theta: [a1..ana, b1..bnb, c1..cnc] Ts: 采样周期 a theta[:na] b theta[na:nanb] # 构造离散传递函数 (简化: 忽略噪声模型) # G(z) (b1 z^-1 b2 z^-2) / (1 a1 z^-1 a2 z^-2) # 转成连续近似: 用零阶保持器逆变换 # 这里用一阶近似: K ≈ sum(b) / (1 sum(a)) K sum(b) / (1 sum(a)) tau -Ts / np.log(abs(a[0])) if abs(a[0]) 1e-6 else Ts # Ziegler-Nichols 型整定 Kp 0.6 / K Ti 2.5 * tau Td 0.4 * tau Ki Kp / Ti Kd Kp * Td return Kp, Ki, Kd逻辑说明这段代码做了大量简化实际工程中需要更精确的离散-连续转换。参数说明K 是静态增益tau 是主导时间常数由 a₁ 反推。Kp、Ki、Kd 是 PID 三个增益。注意这只是一个起点实际投运前必须在仿真里验证直接上现场可能振荡。5.2 用残差白噪声检验判断模型是否可信辨识出参数只是第一步模型可不可信要看残差。RML 的残差 e(k) 如果通过白噪声检验说明模型结构对了如果残差还有自相关说明阶数不够或结构不对。下面是一个残差自相关检验的实现def residual_test(e, max_lag20, confidence0.95): 残差自相关检验 e: 预测误差序列 max_lag: 最大滞后阶数 confidence: 置信水平 N len(e) e e - np.mean(e) acf np.correlate(e, e, modefull)[N-1:] / (np.var(e) * N) # 95% 置信区间: ±1.96/sqrt(N) bound 1.96 / np.sqrt(N) lags_out [] for i in range(1, max_lag1): if abs(acf[i]) bound: lags_out.append(i) if len(lags_out) 0: print(残差通过白噪声检验) else: print(f残差在滞后 {lags_out} 处显著非白建议增加阶数) return acf, bound参数说明max_lag 一般取 20 或 N/10。bound 是 95% 置信区间如果 acf 超出这个范围说明残差还有未建模的动态。我一般会把这个检验和参数收敛曲线一起看——参数收敛但残差非白说明模型结构有问题参数不收敛且残差非白说明数据或算法有问题。5.3 模型切换时的平滑处理在线场景里有时候需要从 RELS 切到 RML或者从一阶模型切到二阶。直接切会导致参数跳变控制器输出跟着抖。我一般会在切换点做 20~50 步的线性过渡def smooth_switch(theta_old, theta_new, steps30): 参数平滑过渡 alpha np.linspace(0, 1, steps) theta_hist [] for a in alpha: theta_hist.append((1-a) * theta_old a * theta_new) return np.array(theta_hist)这个技巧没什么理论深度但现场管用。从那以后我每次做在线辨识只要涉及模型切换都强制走一遍平滑过渡哪怕切换前后参数看起来差不多。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑