自抗扰控制ADRC仿真全解析:从TD/ESO到参数整定与避坑

发布时间:2026/10/13 18:52:29
自抗扰控制ADRC仿真全解析:从TD/ESO到参数整定与避坑
简介ADRC自抗扰控制的MATLAB仿真资源面向控制理论与应用领域的工程师、科研人员和相关专业学生尤其适合需要快速搭建ADRC验证环境、理解状态误差观测器与扩展状态机原理的读者。压缩包共26个文件以Simulink模型文件.mdl为核心搭配.m调参脚本、.c源码、.mexw64编译模块以及.mat参数数据完整覆盖从系统建模、S函数编写到仿真配置的各个环节整体仅191KB轻量易用。截止目前已有3018人学习下载。内容完整演示了ADRC的误差观测器设计、扩展状态构造、控制器与前馈补偿组合以及参数试凑流程其中NESO、Plant等子模块和tuning.m脚本可帮助读者逐段分析扰动估计与误差收敛过程。这套资料既可用于课程实验与论文复现也可作为将ADRC迁移至实际被控对象时的可修改模板具有较好的参考价值。1. ADRC的Matlab仿真先回答“这个仿真到底在验证什么”把 ADRC 的 Matlab 仿真跑出曲线容易跑出能用的曲线难。我见过不少人在 Simulink 里把跟踪微分器、扩张状态观测器、非线性误差反馈三个模块搭好参数套用论文里的初值结果阶跃响应要么超调大到没法看要么在扰动到来时剧烈抖动最后归因于“自抗扰控制是玄学”。其实问题往往不在方法本身而在仿真环节少了一组对抗性实验条件。ADRC 把模型不确定性与外扰统一看成“总扰动”用扩张状态观测器在线估计并补偿仿真的核心价值是在没有实物之前先量化出总扰动估计延迟、带宽受限和测量噪声放大这三组矛盾。这篇文章从拆解 ADRC 的三个环节开始给出一套能在 Matlab 里直接跑通的最小闭环再专门讲仿真里最容易翻车的参数与结构问题。2. 拆开 ADRC 的三个环节TD 的过渡过程、ESO 的观测窗口、误差反馈的组合逻辑自抗扰控制在自动化工程圈子里流行了很多年但绝大多数仿真翻车都是因为把 TD、ESO、误差反馈三个模块当成三个孤立的功能块忽略了它们之间的配合逻辑。这三个环节各自解决一个问题TD 负责把阶跃这类跳变信号安排成平滑轨迹ESO 负责把“模型不确定性加外扰”当成一个新状态实时估出来误差反馈负责在补偿之后整理出一个稳定的闭环。只有把三者的时间尺度对齐仿真才能稳定。2.1 为什么先安排过渡过程TD 的任务不是滤波很多反馈系统里都有微分环节但真实测量信号混噪声时直接做微分会把高频噪声放大到不可用。ADRC 的做法是在入口处先安排过渡过程让控制目标从阶跃变成一条平滑上升的曲线同时用跟踪微分器输出一阶导数信号这个导数信号比直接差分测量值干净得多。跟踪微分器的核心是离散最速控制函数习惯上称为 fhan。它的标准实现如下function [v1n, v2n] td_step(v1, v2, r_ref, r, h) % v1, v2: 当前跟踪位置与速度 % r_ref: 参考输入阶跃目标值 % r: 跟踪速度因子决定过渡过程快慢 % h: 仿真步长 e v1 - r_ref; d r * h^2; a0 h * v2; y e a0; a1 sqrt(d * (d 8 * abs(y))); a2 a0 sign(y) * (a1 - d) / 2; a (a0 y) * (abs(y) d) a2 * (abs(y) d); fh -r * min(max(a / d, -1), 1); % 最速控制综合函数 v1n v1 h * v2; v2n v2 h * fh; end这个函数里的 r 是跟踪速度因子。r 越大过渡过程越快但 v2 的峰值也越高系统对高频分量更敏感h 是积分步长在仿真里要和主循环步长保持一致。需要特别注意的是fhan 里出现了 h 的平方所以步长从 0.001 改成 0.01 时d 会放大 100 倍行为完全不一样。这也是很多人把连续域参数直接搬进离散仿真后失效的原因之一。2.2 ESO观测器的维度比对象多一维才算扩张扩张状态观测器是 ADRC 的核心。对二阶对象ESO 会构造一个三阶状态z1 估计输出z2 估计输出的一阶倒数z3 估计总扰动。这个“扩张出来”的第三维就是 ADRC 能对抗模型不确定性的关键。离散形式的线性 ESO 写起来不复杂function z eso_step(z, y, u, b0, w0, h) % z [z1; z2; z3]y 为被控对象输出u 为控制量 % b0: 控制器使用的模型增益估计 % w0: ESO 带宽 l1 3 * w0; l2 3 * w0^2; l3 w0^3; e z(1) - y; z1_dot z(2) - l1 * e; z2_dot z(3) - l2 * e b0 * u; z3_dot -l3 * e; z(1) z(1) h * z1_dot; z(2) z(2) h * z2_dot; z(3) z(3) h * z3_dot; end这里的 l1、l2、l3 是把观测器特征方程配置到 (s w0)^3 得到的。w0 是 ESO 带宽它的物理含义是观测器能跟踪多快的扰动变化。w0 调大ESO 响应快但测量噪声也会被明显放大w0 太小扰动估计滞后补偿效果变差。b0 则是对被控对象输入通道增益的估计它不一定等于真实值偏差会被当作扰动的一部分进到 z3 里。仿真里常犯的错是把 b0 当成可以随意乱填的常数实际 b0 偏离真实值太多时控制量会在初始阶段出现不必要的冲击。2.3 误差反馈用线性还是非线性仿真第一版建议从线性开始经典 ADRC 里误差反馈会用非线性函数最常见的是 fal(e, alpha, delta)。但非线性反馈带来了更多可调参数而且 alpha 和 delta 的取值直接影响原点附近增益调起来很容易变成玄学。我一般建议仿真第一版先上线性反馈反馈形式参数优点风险线性 PD 型kp, kd参数少与经典控制对应关系清楚容易定位问题小误差区域增益偏低收敛略慢非线性 falalpha, delta小误差时增益高抗扰动更平滑delta 取值敏感噪声环境下容易颤振线性反馈调通之后如果想让扰动恢复过程更利落再引入 fal 不迟。判断标准很简单看同样的阶跃扰动下恢复时间是否显著缩短且没有引入高频抖动。如果抖动更明显多半是 delta 取得太小或者噪声幅度已经超过 delta 的线性区间。3. 在 Matlab 里跑通最小 ADRCm 脚本主循环与 Simulink 连线一套参数跑到底这一章给出可以直接复制的最小闭环。被控对象用一个简单的二阶双积分模型 1/s^2 加扰动真实增益取 1.5而控制器里假设的 b0 取 1.2故意留一点模型不匹配让 ESO 发挥作用。3.1 一个 m 脚本跑完整个闭环主循环里四个环节各占一步把上一章的 td_step 与 eso_step 两个函数保存好然后新建主脚本内容如下% 最小ADRC闭环仿真二阶双积分对象 离散TD/ESO/线性反馈 clear; clc; h 0.001; % 仿真步长 T 5; % 总时长 N round(T / h); t (0:N-1) * h; r_ref 1.0; % 参考输入阶跃 b0 1.2; % 控制器使用的增益 b_real 1.5; % 对象真实增益 w0 10; % ESO带宽 kp 25; kd 10; % 线性反馈增益 r_td 4.0; % TD跟踪速度因子 % 初始化 x [0; 0]; % 对象真实状态 z [0; 0; 0]; % ESO状态 v1 0; v2 0; % TD状态 u 0; y 0; y_rec zeros(N, 1); z3_rec zeros(N, 1); u_rec zeros(N, 1); for i 1:N ti t(i); % 1) TD安排参考输入过渡过程 [v1, v2] td_step(v1, v2, r_ref, r_td, h); % 2) 线性误差反馈 u0 kp * (v1 - z(1)) kd * (v2 - z(2)); u u0 - z(3) / b0; % 扰动补偿 % 3) 被控对象更新真实模型 f_plant 2.0 * (ti 2.0) 0.5 * sin(2 * pi * 1.2 * ti) .* (ti 1.0) - 0.3 * x(2); x(1) x(1) h * x(2); x(2) x(2) h * (b_real * u f_plant); y x(1); % 4) ESO更新 z eso_step(z, y, u, b0, w0, h); % 记录 y_rec(i) y; z3_rec(i) z(3); u_rec(i) u; end % 绘图 figure; subplot(3,1,1); plot(t, y_rec, b, t, ones(N,1)*r_ref, r--); legend(y, r); title(输出跟踪); subplot(3,1,2); plot(t, z3_rec); title(ESO估计的总扰动); subplot(3,1,3); plot(t, u_rec); title(控制量);这段代码里每一步都对应 ADRC 的一个环节。第 1 步 TD 把阶跃 1.0 安排成平滑轨迹v1 和 v2 分别是规划位置与规划速度第 2 步用线性反馈算出未补偿控制量 u0然后减去 z3/b0 完成扰动补偿第 3 步把控制量送进真实对象注意真实增益是 1.5而控制器里用的是 1.2这 0.3 的差值会混入总扰动第 4 步 ESO 用输出 y 和控制量 u 更新状态z3 应该能大致跟踪上 f_plant 的形状。参数选择上h 取 0.001 是为了保证 ESO 离散稳定性w0 取 10 对应 ESO 极点约 10 rad/skp 和 kd 对应的闭环自然频率在 5 rad/s 附近保证反馈环比观测器慢半拍。如果跑出来 z3 明显滞后于真实扰动优先加大 w0如果控制量抖动明显优先减小 w0 而不是动 kp。3.2 Simulink 里搭 ADRC不写脚本也能排错的连线路径如果更喜欢在 Simulink 里调试可以用 MATLAB Function 模块直接调用上面两个函数。推荐模块布局如下模块参数设置说明StepFinal value1.0参考输入MATLAB Function (TD)调用 td_step输入 v1, v2, r_ref输出 v1n, v2nSum两路加减计算 v1-z1 与 v2-z2Gain (kp/kd)kp25, kd10线性反馈增益MATLAB Function (ESO)调用 eso_step输入 z, y, u, b0, w0, hIntegrator 两个串联初始值 0构成二阶受控对象Gain (对象增益)1.5对象真实增益Simulink 里最容易忽略的是求解器设置。ADRC 的离散函数是按固定步长写的求解器必须选择固定步长、离散或 ode4且步长与函数里的 h 保持一致。用变步长求解器时ESO 的离散化假设会被破坏仿真结果会出现莫名其妙的振荡。另外MATLAB Function 里不要写循环直接按单步更新逻辑实现即可。3.3 起步参数与调整顺序照着这套顺序调少走弯路下面是一套能起跑的初始参数后面按顺序调整不要一上来五个参数同时动。参数初始值作用调整方向h0.001离散步长只在稳定性不足时减小b01.2控制增益估计尽量接近真实增益差太多时 z3 初段冲击大w010ESO 带宽先加大到扰动估计跟手再回调到噪声可接受kp25反馈比例增益在 w0 稳定后逐步加大kd10反馈微分增益对应阻尼大了容易放大噪声调整顺序我一般固定为先定 h再校准 b0然后调 w0 看 z3 曲线是否贴合总扰动形状最后加 kp/kd。很多仿真翻车都是先乱调 kp导致系统发散时根本分不清是反馈问题还是观测器问题。把这套顺序当作调试习惯能把黑匣子变成可诊断的模块链路。4. ADRC 仿真避坑五个反复出现的翻车现场与对应修法这一章汇集了 ADRC 仿真里最常出现的五类问题每一条都是现象在前、原因居中、解决在后。对照自己的曲线比自己拍脑袋试参快得多。4.1 仿真发散成 NaN多半是带宽和步长打架现象程序运行到几百步后y_rec 突然出现 Inf 或 NaN曲线直接断掉。原因ESO 带宽 w0 太高而仿真步长 h 太大欧拉离散不稳定。w0 对应的观测器极点若超过采样频率的五分之一离散误差会被放大成数值爆炸。另一个常见来源是 r_td 取太大fhan 里的非线性项产生刚性。解决先固定步长满足 h 不超过 1/(20*w0) 的经验值。当前步长 0.001 时w0 不宜超过 50。如果必须用更大的带宽把 ESO 的欧拉更新改成 RK4 或隐式格式不要硬扛。4.2 阶跃跟踪慢问题可能不在反馈而在 TD现象参考输入 1.0但 y 上升极慢十几秒都稳不住。原因先看 v1 曲线。如果 v1 本身就很慢说明 r_td 太小过渡过程安排得太保守如果 v1 很快而 y 跟不上那才是 kp 或 b0 不匹配。很多人不看 v1直接把 kp 加到很大结果系统开始振荡误判成 ADRC 不稳定。解决把 TD 和 ESO 的曲线分开画。先让 v1 在 0.5 秒左右到达参考值附近再观察 z1 是否跟上 y最后才动反馈增益。4.3 扰动到来时控制量瞬间打满是观测滞后而不是增益不够现象第 2 秒突加阶跃扰动u 立即撞到限幅然后反向回调恢复过程出现明显超调。原因ESO 估计突变的阶跃扰动需要时间z3 还没跟上时反馈回路觉得误差在扩大于是猛打控制量。这不是 kp 不够大而是观测与补偿之间有时间差。解决在仿真里先不设限幅把控制量曲线单独拉出来看是否出现尖峰。如果尖峰明显提高 w0 让 z3 更快收敛同时略微降低 kp让反馈环不抢在观测环前面。必要时可以给控制量加一个速率限制模块更贴近真实执行器。4.4 输出高频颤振像锯齿一样停不下来现象稳态时 y_rec 以很小的幅度高频振荡控制量 u 也在频繁换向。原因测量噪声被高带宽 ESO 放大z3 里混入高频分量补偿信号反过来激励对象。另一个来源是 fal 非线性函数在 delta 附近切换形成极限环。解决仿真里加白噪声后w0 要降下来一般不超过对象有效带宽的两倍。如果已经用了非线性反馈检查 delta 是否大于噪声幅度三倍以上否则改回线性 ESO 和线性反馈。ESO 输入端加一阶低通滤波也能立竿见影但要记住滤波延迟会占据一部分相位裕度。4.5 仿真里稳如泰山换到硬件就崩是离散化没做透现象同一组 kp、kd、w0 在 Simulink 里表现很好移植到嵌入式平台后电机啸叫甚至直接过流保护。原因仿真用的是连续对象加连续观测器而实际系统是在固定控制周期里离散运行的零阶保持器会带来额外相位延迟。执行器饱和、死区、惯性这些非线性因素在纯连续仿真里被省略了。解决从第一版仿真开始就把对象换成带零阶保持器的离散模型并在对象前串联一阶惯性环节和饱和模块。ESO 的离散实现不要用连续方程硬欧拉而要根据实际控制周期写成差分形式。只要仿真的离散化结构和实物一致参数迁移的成功率会明显提升。5. 进阶验证频域看 ESO 带宽时域加噪声与饱和仿真才算真正可落地仿真能跑通只是第一步更重要的是证明参数选择有依据而不是碰巧凑出一组好看的曲线。我的进阶做法分两层一是把主循环封装成函数对关键参数做扫描看趋势是否符合物理直觉二是给仿真加入对抗性条件验证它在“模拟现场”下的表现。5.1 把主循环封装成函数批量扫描 w0把上一章的主循环改造成一个函数输入参数是 kp、kd、w0、b0、h输出是时间序列和控制量function [t, y, u, z3] run_adrc(kp, kd, w0, b0, h) T 5; N round(T / h); t (0:N-1) * h; % ... 内部实现与第3章主循环相同 ... end w0_list [6, 10, 16]; for k 1:length(w0_list) [t, y, u, z3] run_adrc(25, 10, w0_list(k), 1.2, 0.001); err rms(y - 1.0); % 相对参考输入的RMS跟踪误差 fprintf(w0%.0f, RMS误差%.4f, 最大控制量%.2f\n, ... w0_list(k), err, max(abs(u))); end扫描结果通常呈现一个规律w0 提高RMS 误差下降但最大控制量上升。这个趋势比单条曲线更能说明问题——如果 w0 从 6 加到 16误差明显减小而控制量没有爆炸说明带宽选择的方向正确如果误差几乎不变但控制量急剧增大说明带宽已经越过拐点再往上加就是拿噪声换性能。5.2 给仿真加三组对抗性条件建立验收清单我习惯在参数调好后固定跑四组测试单位阶跃、阶跃扰动加正弦扰动、输出叠加白噪声、模型增益从 1.5 拉到 0.8 与 2.0。四组都满足下述标准的参数才值得考虑移植测试条件通过标准阶跃跟踪超调小于 5%上升时间在设定范围突变扰动2% 恢复时间小于 1.5 秒控制量不持续撞限幅测量噪声稳态控制量无明显高频换向模型增益偏差输出不发散RMS 误差相对标称工况上浮不超过 30%这套验收清单的价值在于防止“过拟合参数”。有一次我调出的参数在标称模型下曲线极漂亮但把对象增益偏差 20% 后系统立刻震荡最后发现是 b0 偏离真实增益太多z3 的估计偏差超出了观测器补偿能力。从那以后我养成了习惯先把 ESO 带宽、对象等效增益、控制周期三个数单独写在一行注释里再去看 z3 曲线是否符合物理常识最后才动反馈增益。仿真里能骗人的曲线太多能用指标和趋势说明问题的参数才是真正可信的。希望帮到你。本文还有配套的精品资源点击获取