题名里的“非线性干扰观测器 + 滑模反演控制 + Simulink 模型复现”,说人话就是:给直升机飞控做一个能抗风的控制器,并把这个控制器在 Simulink 里完整搭出来、跑通。我做这类复现不是第一次,但直升机模型比四旋翼麻烦不少,尤其是模型结构、状态通道和干扰观测器之间的配合,稍不注意就跑飞。这篇文章会把我的复现路线、核心公式、Simulink 搭建细节和调试中踩过的坑完整写出来,给正在做相关课题或者写论文需要仿真支撑的朋友一个可以直接参考的版本。
这套方案适合三类人:一是控制方向的研究生,想快速复现论文结果;二是做直升机或无人机飞控开发的工程师,需要一版可继续改写的 Simulink 原型;三是准备做毕业设计、需要从“理论推导”过渡到“仿真实现”的本科生。为了让文章足够聚焦,我下面的模型做了合理简化,但控制框架不是玩具,干扰观测器设计、反演推导、滑模鲁棒项都是完整可用的。
1. 控制方案总体思路与复现目标
1.1 为什么把干扰观测器、反演和滑模放在一起
这一篇比较推荐的起点是先想明白“这三个东西各干什么”,否则后面在 Simulink 里连线会很混乱。
反演控制(Backstepping)适合处理满足“严格反馈形式”的级联系统。直升机高度通道、位置通道、偏航通道,本质上都能写成“位置/角度环 + 速度/角速度环”的两层结构,这正是反演控制的用武之地。它的思想是一级一级地构造虚拟控制量,每一步都用 Lyapunov 函数把子系统“稳定住”,最终反推回真实控制输入。这个方法的优点是设计过程非常系统,控制律形式清晰;缺点是对模型误差和外部扰动比较敏感,因为每一步虚拟控制都依赖模型,扰一动,整个链路误差就被放大了。
滑模控制的优点是鲁棒性直接,只要扰动有界,选择合适的切换增益,就能把系统状态拉到滑模面上。缺点也非常经典:控制量上带了符号函数,会产生高频抖振,仿真里会出现大量高频毛刺,实物中会磨损执行机构。
非线性干扰观测器(NDO)解决的是“扰动能不能被估出来”的问题。它不直接去构造鲁棒项硬扛扰动,而是通过观测器把外部扰动估计出来,在前馈通道里把它补偿掉。这样滑模部分就不需要把切换增益设得特别大,抖振能被有效压低。三者的关系可以这样理解:反演负责把通道结构理顺,干扰观测器把看得见的扰动提前抵消,滑模负责吞掉观测残差和未建模误差。
1.2 复现前先做模型降阶
真正的直升机六自由度模型包含主旋翼拉力、尾桨推力、挥舞动力学、地面效应等,直接全量建模会让控制器设计非常困难。论文复现里绝大多数做法是先砍掉非核心环节,用“悬停点附近的线性化通道模型”或“带扰动的二阶严格反馈模型”来验证算法。
我复现时选择了三通道独立设计的简化方案:垂向高度通道、水平纵向通道、偏航通道。每个通道我都写成一个二阶系统,形式是:状态一为位置或角度,状态二为速度或角速度,外部扰动作为外加项进入速度通道。这样的好处是反演控制可以非常干净地套用,干扰观测器也可以逐通道独立设计。
需要注意,三通道独立设计意味着忽略了通道间的耦合。对直升机全包线飞行来说这不够,但在悬停和小范围机动场景下是工程上常用且有效的验证方式。如果你的论文需要更漂亮的结果,可以把三通道合并成完整六状态模型,控制结构不变,只是每个状态方程里多出耦合项,NDO 和反演推导会复杂一点。
2. 控制算法推导与关键参数设计
2.1 通道模型的严格反馈形式
以垂向高度通道为例,我把模型写成:
x1_dot = x2
x2_dot = f(x) + g(x) * u + d
其中 x1 是高度,x2 是垂向速度,u 是等效垂向控制量,d 是外部扰动(风力、吊挂负载等)。对高度通道来说,f(x) 里至少包含 -g,g(x) 里包含与姿态角相关的推力分量。为了聚焦算法实现,我在复现中直接令 f(x) = -g,g(x) = 1,等效控制输入可以理解为经过姿态解耦后的“期望垂向加速度”。
偏航通道写成角位置和角速度的二阶形式,纵向通道同理。采用这种形式后,反演设计的推导非常机械,也方便后续扩展成六个状态。
2.2 非线性干扰观测器设计
这里重点说 NDO 的实现公式,因为 Simulink 模型里所有核心模块都围绕它展开。
对于系统:
x2_dot = f(x) + g(x) * u + d
在扰动缓慢变化的前提下,即 d_dot 近似为 0,NDO 的标准设计为:
d_hat = z + p(x2)
z_dot = -l * g(x) * z - l * [ g(x) * p(x2) + f(x) + g(x) * u ]
其中 l 是观测器增益。取 p(x2) = l * x2,则:
d_hat = z + l * x2
z_dot = -l * g(x) * (z + l * x2) - l * (f(x) + g(x) * u)
把 x2_dot 代入推导,可以得到观测误差的收敛方程为:
d_tilde_dot = -l * g(x) * d_tilde
也就是只要 x2 通道的控制系数 g(x) 不为零,并且 l 为正数,观测误差就指数收敛到零。这个推导是 NDO 子系统的设计基石,在 Simulink 里搭 NDO 时,第一个积分器的输入直接按 z_dot 的表达式接就行。
2.3 反演滑模控制律设计
反演控制的第一步是定义跟踪误差:
e1 = x1 - x1_ref
对高度通道,x1_ref 是期望高度。构造虚拟控制量:
alpha1 = x1_ref_dot - c1 * e1
其中 c1 为正数,决定位置环收敛速度。再定义速度跟踪误差:
e2 = x2 - alpha1
到这里,传统反演会直接选择控制律使 e2 收敛。为了加入滑模的鲁棒性,我构造滑模面:
s = e2 + lambda * e1
lambda 是滑模面系数,可以是常数,也可以是自适应形式。对 s 求导:
s_dot = x2_dot - alpha1_dot + lambda * e1_dot
= f(x) + g(x) * u + d - alpha1_dot + lambda * (x2 - x1_ref_dot)
把 NDO 估计出来的 d_hat 代入,设计控制律:
u = (1 / g(x)) * [ -f(x) - d_hat + alpha1_dot - lambda * (x2 - x1_ref_dot) - k * s - eta * sign(s) ]
其中 k 是滑模趋近律增益,eta 是切换增益。这样设计之后,s_dot 变成:
s_dot = d_tilde - k * s - eta * sign(s)
其中 d_tilde = d - d_hat 是观测残差。只要 eta 大于观测残差的最大幅值,系统就能进入滑模面,并保持最终一致有界稳定。
2.4 稳定性结论与参数整定逻辑
Lyapunov 分析是控制论文里必须写的一块,但复现时更重要的是理解增益如何影响响应。对滑模面取 V = 0.5 * s^2,则有:
V_dot = s * (d_tilde - k * s - eta * sign(s))
<= -k * s^2 - eta * |s| + |s| * d_max
当 eta 大于观测残差上界 d_max 时,V_dot 为负定,系统收敛。这意味着切换增益 eta 只需要大于“观测误差的界”,而不是大于原始扰动的界。扰动越大的工况,NDO 的补偿优势越明显,这也是整套方案的核心竞争力。
参数整定的逻辑通常是先定反演增益 c1,再定滑模面系数 lambda,接着调趋近律增益 k,最后根据 NDO 残差大小定 eta。顺序错了,后面调参会非常痛苦。
3. Simulink 建模与子系统实现
3.1 顶层模型架构
我的顶层模型分为五块:参考轨迹生成、控制器、干扰观测器、被控对象、数据观察与记录。控制器和干扰观测器各用独立子系统封装,被控对象也单独建子系统,这样每个环节都能单独加示波器或者 To Workspace 模块观察中间变量。
很重要的一点是,顶层模型里要明确区分“控制量 u”和“执行机构实际输出 u_act”。控制器算出来的 u 经过饱和限幅后变成 u_act,u_act 进入被控对象,同时 u_act 也必须反馈给干扰观测器使用。很多复现模型的扰动估计发散,就是因为观测器用的是控制器输出而不是实际饱和输出。
3.2 被控对象子系统搭建
被控对象是标准的二阶积分链。我用积分模块直接搭,不用传递函数,这样方便把非线性项和扰动项直接做加法。
比如高度通道:外界正弦风扰 d = A * sin(w * t) + B,加在速度状态 x2 的积分器输入端。模型内部写:
x2_dot = -g + u_act + d
这部分用加减法模块、增益模块和一个正弦信号源就能完成。如果后续要换真实直升机模型,只需要替换这个子系统里的计算逻辑,控制器和观测器不需要大改。
3.3 NDO 子系统搭建
NDO 子系统的输入是两个:被控对象输出状态 x2 和实际控制量 u_act。子系统内部按照 z_dot 的公式搭建:
z_dot = -l * g * z - l * (g * l * x2 + f + g * u_act)
输出是 d_hat = z + l * x2。
实际搭的时候注意三点。第一,代码生成后 z_dot 的积分器初值一般设 0,但如果有先验扰动信息,设成预估初值能缩短过渡过程。第二,f(x) 和 g(x) 必须与当前通道保持完全一致,比如垂向通道里的 f 要含 -g,g 是系数 1,偏航通道的 g 是转动惯量倒数。第三,NDO 里的 l 不能一次加太大,否则高频噪声会被放大,观测值会出现毛刺,进而耦合到控制量里。
3.4 反演滑模控制器子系统搭建
控制器子系统内部先算 e1、alpha1、e2、s,然后计算控制律。建议把这些量用 Bus 对象或者信号标签整理好,方便在 Scope 里单独看。
核心部分有一个需要特别处理的讨厌点:alpha1_dot。alpha1 是参考速度减去 c1 倍位置误差,所以:
alpha1_dot = x1_ref_ddot - c1 * (x2 - x1_ref_dot)
这里 x1_ref_ddot 必须由参考轨迹生成器提供解析表达式,不能直接对阶跃信号求导。我实测中如果参考轨迹是阶跃,x1_ref_dot 和 x1_ref_ddot 实际是脉冲函数,控制器瞬间输出巨大控制量,仿真直接发散。解决办法是给参考轨迹加一个低通滤波器,或者用平滑的 S 曲线轨迹规划。
滑模项里的 sign(s) 我建议先用饱和函数 sat(s / phi) 或 tanh(s / phi) 代替,phi 取 0.01 到 0.1。直接在 Simulink 里用符号函数模块做高频切换,调参数时极其痛苦。
3.5 参考轨迹生成与数据导出
高度参考我常用三段式轨迹:先给一个斜坡过渡,再加一阶滤波,最后稳定在目标高度。偏航参考则用 Smooth Step 或 S 曲线。总之,参考轨迹的一阶导和二阶导必须是连续有界的,否则反演控制里的 alpha1_dot 会出问题。
数据导出建议用 To Workspace 模块,把 e1、e2、s、d_hat、d、u、u_act 都记录成数组。调试时绘制同一张图确认扰动估计是否跟上真实扰动。如果 d_hat 的波形明显滞后真实扰动,说明 l 偏低;如果出现高频震荡,说明 l 过高。
4. 参数整定、仿真调试与常见问题
4.1 参数整定顺序和实用初值
我复现时用的初始参数如下,可以作为第一组可运行初值:
通道模型取 m = 1,g = 9.8,转动惯量取 0.5。控制器增益按这个顺序调:c1 = 2,lambda = 2,k = 5,eta = 0.5,NDO 增益 l = 10。如果系统响应太慢,先加 k,再加 c1,尽量不要先动 lambda。滑模饱和边界 phi 取 0.05。
一个容易被忽略的关键点是 NDO 的 l 和滑模切换增益 eta 的配合。l 太低,观测残差大,eta 必须加大,抖振随之变大;l 太高,噪声放大,同样导致抖振。理想的配合是先把 eta 设为 0,只加 NDO 补偿,看系统能否稳定,再逐步增加 eta 到抖动可控。
4.2 抖振抑制和扰动观测器增益匹配
这可能是复现中最耗时的一步。滑模控制仿真里最容易看到的现象是控制量出现高频开关形态,即使连续饱和函数也会在误差极小时出现锯齿。
我调试时用过三招。第一招是把 sign(s) 换成 sat(s / phi),phi 不能太大,太大滑模精度下降,相当于变成高增益反馈。第二招是通过 NDO 把 eta 压到很小的值,比如 0.1,这样滑模项本身不剧烈。第三招是检查参考轨迹是否平滑,如果参考本身有高频分量,滑模面会持续震荡,控制器也会跟着抖。
4.3 代数环、过零检测与求解器设置
Simulink 里最容易报的警告是“Algebraic Loop”。反演控制器里,如果某些信号直接从输出反馈到同一采样步的输入,就会出现代数环。我复现时没有遇到严重的代数环,因为控制律依赖的是状态变量而非控制输出。但如果你把饱和模块的输出再用于计算控制目标,就要小心。
仿真求解器我推荐固定步长 ode4(四阶龙格库塔),步长取 0.001 秒。变步长求解器在滑模切换时步长会反复调整,仿真速度慢,而且结果重复性差。如果你想快速看趋势,可以临时用 ode45,但最终出图建议用固定步长。
4.4 常见问题速查表
这里整理几个我实际遇到并且查资料确认过的问题,方便排查。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 仿真刚开始就发散 | 参考轨迹导数不连续 | 改用平滑参考轨迹 |
| 高度跟踪误差始终为正 | NDO 观测值滞后 | 增大 l |
| 控制量高频抖动剧烈 | eta 过大或 phi 过小 | 降低 eta,增大 phi |
| NDO 输出发散 | 观测器使用了饱和前的 u | 改用 u_act 接入观测器 |
| 位置发散但角度正常 | 通道间耦合被忽略 | 检查状态方程是否写错 |
| 调大 l 后噪声明显 | 状态信号含高频噪声 | 先不要一味加大 l |
4.5 复现结果怎么看
仿真跑完之后,至少要完成三项检查。第一项,看高度跟踪曲线,要确认稳态误差小于设定阈值,过渡过程没有明显超调。第二项,看扰动估计曲线和真实扰动曲线,两条线重合程度越高,说明 NDO 越成功。第三项,看控制量曲线,正常的滑模反演控制量应该连续,只有不超过 10% 的高频毛刺,这才说明整套方案的鲁棒性和工程性都过关。
5. 个人复现心得与扩展建议
这套模型我在不同机器上跑过,最终稳定运行的核心不是算法本身有多复杂,而是每一层信号都干净。把状态量、参考量、控制量、扰动估计量全部用明确命名的信号线接出来,后面排查问题能省一半时间。
最后分享一个小技巧:搭建时先用“无扰动 + 无滑模项”把反演链路跑通,再依次加入 NDO、加入滑模项、加入扰动。这种分层验证的思路,能让你迅速定位是哪一层引入的问题,而不是在整套系统里大海捞针。如果你后续要扩展到四旋翼或六自由度直升机,只需要把通道模型换成完整状态方程,控制结构和这里完全一致。