Rollout修正数学:从误差分解到闭环控制与统计重加权
前阵子调一个轮式平台的预测控制器仿真里预测轨迹画得漂漂亮亮一上真机就眼看着实际轨迹越偏越远。后来把整套逻辑拆开才发现根子不在控制器本身而在“预测出来之后拿什么数学去纠”——也就是标题里说的 Rollout Correction Math。Rollout 这个词在控制、强化学习、运动规划里说的是同一件事拿着当前状态和一套动力学模型把未来若干步的状态先“滚”一遍得到一条预测轨迹。可预测毕竟是预测模型有偏差、初值有误差、环境有扰动滚出来的东西一定会偏。真正决定一个系统好不好用的往往不是预测本身有多准而是修正预测那一步的数学。下面把整理过的误差分解、反馈修正、统计修正加一套能直接抄走的数值算例一次讲清楚。刚碰 MPC 的读者拿它可以少走弯路做强化学习评估时被 off-policy 偏差坑过的人也能在里面找到对应的修正思路。1. 先把 Rollout 定义清楚一条预测轨迹是怎么算出来的1.1 从连续模型到离散递推先统一符号后面所有推导都基于这套记号。连续系统的状态方程通常写成ẋ f(x, u)x 是状态u 是控制输入。计算机没法解析地把微分方程解到未来所以第一步一定是离散化。最简单的做法是欧拉法x_{k1} x_k dt * f(x_k, u_k)更稳一点用 RK4差别只在单步精度。无论用哪种最终得到的都是一个离散映射g(x, u)。Rollout 就是从当前状态x̂_0出发把一段控制序列u_0, u_1, ..., u_{H-1}依次代进映射x̂_1 g(x̂_0, u_0)x̂_2 g(x̂_1, u_1)…x̂_H g(x̂_{H-1}, u_{H-1})这段递推在数学上就是函数的复合。注意这里的 x̂ 是“模型状态”不是实测状态。整条轨迹完全由(x̂_0, u_0..H-1)决定中间没有任何新信息注入所以本质上是开环预测。注意哪怕用的是 MPC每次优化迭代内部生成的那条轨迹也是开环 rollout“闭环”来自每个控制周期用实测状态重新滚动而不是轨迹本身是闭环的。这一点想清楚后面看修正就好理解了。我把预测误差统一记成δ_k x_k(actual) − x̂_k。后面所有修正方法目标都是把 δ 压到一个可接受的范围。1.2 预测为什么一定会偏很多第一次写 rollout 代码的人有个错觉只要模型足够准轨迹就足够真。实际有三个误差源永远躲不掉初值误差。x̂_0 来自状态估计滤波必然有滞后融合出来的位置不可能绝对等于真值。模型失配。摩擦力、风阻、电压下降、负载变化真实 f 和代码里的 f 永远有距离。过程噪声。随机扰动路面颠簸也好、气流也好这一项是统计意义上的不是确定性偏差。用最简单的线性标量系统x_{k1} a x_k b u_k看误差传播δ_{k1} a δ_k (a_real − a_model) x_k ε_k。如果 |a| 1哪怕初值误差只有一点点也会指数放大如果 a 1也就是系统里带着积分器误差永远不会自己衰减只有 0 a 1 的稳定系统初值误差才会逐渐消散。这和天气预报是同一个道理初始场差一点点几天后整条预报轨迹就走样了。控制里更常见的是模型失配这一项因为被控对象里往往天然带着积分器或者不稳定模态。所以“预测漂了”不是算法没写好而是误差机制决定的能改的只有修正这一步。2. 误差的定量拆解三类误差各自怎么长2.1 线性误差递推的推导在设计修正器之前先把误差拆开才知道力气该往哪儿使。假设已经沿名义轨迹 x̂ 把 rollout 滚完真实系统满足x_{k1} f_real(x_k, u_k) ε_k模型输出是x̂_{k1} f_model(x̂_k, u_k)在名义轨迹附近对真实系统做一阶展开得到x_{k1} ≈ f_real(x̂_k, u_k) A_k δ_k ε_k其中A_k ∂f_real/∂x在(x̂_k, u_k)处取值。于是误差递推δ_{k1} ≈ A_k δ_k b_k ε_kb_k f_real(x̂_k, u_k) − f_model(x̂_k, u_k)这里 b_k 是“在名义轨迹附近真实模型和所用模型的输出差”它会随轨迹不同而变化是模型失配在当前点的局部体现。把递推一路展开到 H 步之后就是一条完整的预测误差公式δ_H Φ_{H,0} δ_0 Σ_{i0}^{H-1} Φ_{H,i1} b_i Σ_{i0}^{H-1} Φ_{H,i1} ε_i其中 Φ 是状态转移矩阵的链式乘积Φ_{j,i} A_{j-1} A_{j-2} ... A_i表示从第 i 步到第 j 步的误差放大。翻译成人话最终预测误差 初值误差被动力系统放大后的残留 每一段模型失配沿未来轨迹的累积 每一段过程噪声的累积。2.2 从公式里找修正抓手这条公式最大的价值不是用来算而是用来判断误差是哪一项主导。主导项特征优先处理手段初值误差 δ_0轨迹整体平移、起点就偏改进状态估计滤波模型失配 b_k误差有方向性、逐段累积离线辨识参数或加反馈修正过程噪声 ε_k轨迹抖动、重复试验结果分散滤波平滑反馈增益宜温和模型失配是大多数人第一个想到的但它在三类里往往不是最优投入点。我在某项目里测过一种很典型的现象预测轨迹画出来很平滑真机轨迹却一抖一抖的。一开始我拼命调模型参数后来把噪声项用滑动平均估出来才发现误差里随机成分占了大半钱应该花在滤波和增益上而不是花在模型辨识上。判断误差类型的土办法同一个初始条件、同一条控制序列多跑几次。如果误差方向和大小基本一致偏的主要是模型失配如果结果五花八门噪声和扰动占大头。这个判断先做了后面选修正策略才不会跑偏。3. 反馈修正的数学闭环预测怎么打断误差累积3.1 周期重规划重置初值就是一个修正器最简单也最常用的修正手段是每个控制周期都测一次真实状态把 x̂_0 换成实测值然后重新滚一条轨迹只发送第一个控制量。这就是滚动时域receding horizon的含义。数学上看它做的事情是频繁地把 δ_0 强行置零。哪怕模型失配项 b_k 还在误差也只在单个周期内累积一小段不会被一路放大到 H 步。用一个标量例子就能说明差异。假设模型是x̂_{k1} 0.9 x̂_k u_k真实系统是x_{k1} 1.1 x_k u_k初始状态 x 1目标 0。如果开环一次性算出控制序列 u_0 -0.9 之后全填 0模型认为自己一步归零真实轨迹却从 0.2 开始按 1.1 倍往上长。如果每步实测状态、用同一个错误模型算u_k -0.9 x_k真实递推就变成x_{k1} 1.1 x_k - 0.9 x_k 0.2 x_k误差指数衰减。同一个失配模型加不加“重置初值”结果是天壤之别。代价也明确每个周期都要重新优化算力就是硬约束。于是就有了更便宜的折中——固定增益反馈。3.2 沿名义轨迹的 LQR 反馈增益推导假设已经有一条名义 rollout(x̂_k, û_k)想在它附近求一个线性反馈修正。偏差记成δx x − x̂δu u − û代价函数写成J δx_H^T S_N δx_H Σ_{k0}^{H-1} (δx_k^T Q δx_k δu_k^T R δu_k)离散 LQR 的标准结果是末端反推 Riccati 递推S_N Q_NS_k Q A_k^T S_{k1} A_k − A_k^T S_{k1} B_k (R B_k^T S_{k1} B_k)^{-1} B_k^T S_{k1} A_kK_k −(R B_k^T S_{k1} B_k)^{-1} B_k^T S_{k1} A_k最终控制修正为u_k û_k K_k (x_k − x̂_k)。K_k 的含义非常直白实测状态偏离名义轨迹多少就额外施加多大的控制修正。R 越大说明越舍不得用控制量去纠偏增益越温和Q 越大说明越在乎轨迹精度增益越激进。整个过程就是 iLQR / DDP 的标准结构正向 rollout 生成名义轨迹反向扫一遍算出 K_k再用修正后的控制序列重新 rollout。所谓“校正”数学上就是这组时变增益。对线性时不变系统S 最终收敛为常数解K 也变成常数就是我们熟悉的定常 LQR。对时变系统每个时刻的增益都不同调试时注意别把某一时刻的 K 拿来给别的时刻用。4. 蒙特卡洛 Rollout 的统计修正重要性采样与截断4.1 偏差从哪来Rollout 不只出现在控制里。强化学习做策略评估时常用做法是拿当前策略 π_old 去采样若干条轨迹把累积回报平均作为价值估计。问题在于很多场景下手里只有旧策略采的轨迹却想估新策略 π_new 的价值——直接平均就是有偏的。这里说的“修正”就是重要性采样。轨迹在策略 π 下的概率写成P_π(τ) P(s_0) Π_t P(s_{t1}|s_t, a_t) π(a_t|s_t)同一套环境动力学下新老策略轨迹概率的比值状态转移项会全部约掉只剩P_π_new(τ) / P_π_old(τ) Π_t π_new(a_t|s_t) / π_old(a_t|s_t) Π_t ρ_t于是得到统计意义上的 rollout correctionE_{π_new}[G] E_{π_old}[Π_t ρ_t · G]每条旧样本乘一个权重把采样分布拉回目标策略的分布。这条恒等式没有任何近似是精确的问题出在实操。4.2 权重爆炸与 V-trace 截断数学上无懈可击实际用起来最大的敌人是方差。如果某一时刻 π_old(a|s) 很小而 π_new(a|s) 不小ρ_t 会非常大一条样本就可能把估计值带飞。所以实际系统几乎都要做截断把单步比例限到 c̄常用 1再用一个 λ 系数让远期修正衰减这就是 V-trace 的核心。V-trace 的目标值可以写成v_t V(s_t) Σ_{k≥t} γ^{k−t} (Π_{it}^{k−1} c_i) ρ_k [r_k γ V(s_{k1}) − V(s_t)]c_i λ min(ρ_i, c̄)直观理解ρ_k 决定“这条样本对分布偏差的修正力度”c_i 决定“这个修正能往前传播多远”。两个系数叠加就是偏差和方差之间的旋钮。样本量足够大、动作空间不太高维的时候不做截断也能用动作空间一高维ρ_t 的乘积很容易爆炸。我的建议是先加截断样本量不够时再考虑自归一化权重。后者会引入一点点统计偏差但能大幅稳住方差。有意思的是第 3 节的反馈修正是把初值拉回实测第 4 节的重加权是把采样分布拉回目标分布——一个修状态一个修分布本质都是“用新信息纠正旧预测”。5. 完整数值算例同一个失配模型三种方案的真实差距5.1 算例设置与开环结果设定仿真系统x_{k1} 1.1 x_k u_k我们手里拿到的模型是x̂_{k1} 0.9 x̂_k u_k初始状态 x_0 1控制目标是把状态拉回 0。先看模型给出的开环方案想让模型一步归零取 u_0 -0.9此后 u 全为 0。模型预测 x̂ [1, 0, 0, …]但真实系统按 1.1 倍演化k模型预测 x̂真实状态 x开环误差 δ01.001.0000100.2000.200200.2200.220300.2420.242400.2660.266500.2930.293开环 rollout 的误差一旦产生就不再回头反而一路涨。这在预测控制器里尤其要命控制器完全相信这条预测输出的整段控制序列都是错的。5.2 反馈修正与重规划的效果接着每步实测状态用同一个模型重算控制u_k -0.9 x_k真实递推就变成x_{k1} (1.1 − 0.9) x_k 0.2 x_k。再放一个温和比例反馈u_k -0.5 x_k作对照真实递推为x_{k1} 0.6 x_k。三种方案逐拍对比k开环不修正 x每步重算 x温和比例反馈 x01.0001.0001.00010.2000.2000.60020.2200.0400.36030.2420.0080.21640.2660.0020.13050.2930.0000.078每步重算对应的闭环极点是 0.2收敛最快比例反馈是 0.6收敛次之开环是 1.1不修正。但代价也要看设测量噪声标准差 σ 0.01每步重算的控制量里噪声放大系数是 0.9比例反馈只有 0.5灌进系统的噪声方差分别是 0.81σ² 和 0.25σ²。修正越激进把测量噪声灌进系统也越猛这是同一枚硬币的两面。这个标量例子里压缩了所有要点修正的本质是拿被测状态置换模型状态通过反馈把闭环极点往里拉拉得多狠取决于你对模型失配和测量噪声的相对忍受度。6. 实操层面的选择不同误差该用哪种修正6.1 修正手段的定位对比把前面几类修正放一张表里方便直接对照选型修正手段主战场主要代价常见坑状态估计与滤波初值误差、传感器噪声每个观测周期一次更新无法补偿模型失配滚动时域重规划 MPC模型失配、大扰动每周期一次完整优化算力不足被迫降频LQR / iLQR 反馈增益名义轨迹附近的小偏差每步一次矩阵乘偏差太大时线性化失效重要性采样 / V-trace离策略样本的分布修正每样本一次权重计算不截断则方差爆炸选型顺序我建议固定先保证滚动时域重规划是正确实现的再考虑用固定增益反馈给重规划降频最后才上统计修正。原因很简单前两层把确定性误差和随机误差分流处理了统计修正只处理剩余的小尾巴。6.2 调试中的几个具体坑预测时域不是越长越好。很长一段时间我也默认 MPC 的 H 越大越“有远见”但滚动误差公式写得很清楚模型失配项和噪声项都随 H 累积。在一个失配 10% 的模型上所谓远见就是远方的幻觉。正确做法是把 H 压到动态性能需要的最短值或者对远期误差加权打折扣。别用一个修正器修所有误差。见过有人把反馈增益调得巨大试图一步干掉模型偏差结果系统一上真机就抖——原因就是他把噪声当成失配来修了。最好的做法是先做开环 rollout 对比实测误差有方向性、反复出现那是模型失配反馈修正有效误差杂乱、同场景测几次都不一样那是噪声和扰动得上滤波、降增益。统计修正记得截断。重要性权重不截断的话实际跑起来动辄上万一条样本毁掉整批估计。至少加min(ρ, c̄)并且每批训练后统计平均权重如果长期偏离 1说明新旧策略差得太远修正已经在给不合理的估计打补丁。最后是代码层面的iLQR 反向递推时如果B_k^T S_{k1} B_k R接近奇异K_k 会爆炸。我在调一台 2 自由度机械臂时遇到过处理方式很朴素给求逆加正则项或者把 R 的下限卡住问题立刻消失。这类数值细节不会写在教科书里但真机调试时比算法选型更容易坑人。最后分享一条可以直接抄的小经验新系统上调试 rollout 修正先什么都不调只确保每个周期都用实测状态重新滚动把单步预测误差压到可接受范围然后才考虑加固定增益反馈给重规划降频统计修正那套最后再说。这个顺序我反着走了一次结果是在错误的方向上白调了很久。Rollout 修正的数学不难难的是先搞清楚误差里哪一部分值得修、哪一部分只能忍——把这件事想清楚至少能省掉一半的无用功。