news 2026/10/15 16:49:58

ADRC的SIMULINK仿真模型搭建与调参避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ADRC的SIMULINK仿真模型搭建与调参避坑指南

简介:这份资源面向控制算法学习者和自抗扰控制(ADRC)入门研究者,提供一套可直接运行的SIMULINK仿真模型,重点针对二阶惯性环节进行仿真配置。包内包含一个.m脚本文件与一个SIMULINK模型文件,模型中搭建了LESO线性状态观测器,用于对系统状态进行实时估计与扰动补偿,参数已预先调好,并额外加入噪声信号测试其抗扰性能,方便读者直接观察控制效果。资源共3个文件,由1个pdf、1个m和1个mdl组成,压缩包约136KB,其中pdf为韩京清《From PID to Active Disturbance Rejection Control》的经典文献,便于理论对照,m文件负责参数整定,mdl文件承载仿真模型,使用时需保证两个文件路径一致,在MATLAB 2014a中即可打开。目前已有3163人学习下载,适合希望快速理解ADRC结构、验证LESO观测效果并在此基础上修改参数开展二次实验的读者。

1. ADRC 的 SIMULINK 仿真模型:为什么你搭的模型一跑就发散

如果你搜到这篇,大概率是手里有个控制对象——电机、四旋翼、倒立摆、温控箱——PID 调了半天,超调压不下去,抗扰又软绵绵,于是有人告诉你试试自抗扰控制(ADRC)。然后你打开 SIMULINK,拖了几个模块,TD、ESO、NLSEF 拼起来,一按运行,波形直接飞了。这不是你手气差,是 ADRC 的仿真模型有几个非常具体的“玄学”点:带宽怎么配、fal 函数在零点怎么处理、离散化步长和 ESO 带宽的关系,任何一个没对齐,模型就是不发散也抖得没法看。

这篇笔记就干一件事:把 ADRC 的 SIMULINK 仿真模型从零搭到能跑、能调、能复现。我会按“先讲清每个模块在仿真里到底代表什么 → 再给可抄的模块参数和脚本 → 最后把踩过的坑摊开”这个顺序写。适合两类人:刚接触 ADRC、想先仿真验证再上板子的新手;以及用过 ADRC 但模型总调不稳、想看看别人参数怎么设的熟手。全程不依赖任何工具箱之外的东西,MATLAB 基础版本加 SIMULINK 就能跟。

2. 把 ADRC 拆成 SIMULINK 能搭的四块:TD、ESO、NLSEF 和对象

ADRC 在论文里公式一堆,但落到 SIMULINK 仿真模型,本质就是四个可独立验证的子系统。这一章先把每一块在仿真语境下的角色说清楚,再给出最小可跑的搭建步骤。你只有先能单独把 ESO 跑通,才有资格谈整环调参,否则整环一发散你根本不知道是谁的锅。

2.1 跟踪微分器 TD:给阶跃信号安排一个“过渡过程”

TD 的作用是把你给的参考信号 r(t) 安排成一个带过渡的 v1,同时给出微分 v2。仿真里最常被忽略的是:TD 不是滤波器,它的输出 v1 会滞后于 r,这个滞后是你主动设计的,不是 bug。最常用的离散 TD 形式是 Han 的 fhan 或最速离散形式,仿真里我一般直接用 MATLAB Function 写,比拖模块清晰。

function [v1, v2] = fhan_td(v, r, h, h0) % v: 当前TD状态 [v1; v2] % r: 输入参考信号 % h: 仿真步长 % h0: 滤波因子,通常取 5~10 倍 h v1 = v(1); v2 = v(2); d = r * h0; % 决定过渡过程快慢的“加速度”尺度 d0 = d * h; y = v1 - r + h * v2; a0 = sqrt(d^2 + 8 * r * abs(y)); if abs(y) <= d0 a = v2 + y / h; else a = v2 + 0.5 * (a0 - d) * sign(y); end v1 = v1 + h * v2; v2 = v2 + h * (-r * sat(a / d, 1)); % sat为饱和函数 end

逻辑说明:这段是离散最速 TD 的常见写法,r越大过渡越快但越容易过冲,h0是滤波因子,用来抑制输入噪声引起的微分抖动。参数上,仿真步长h必须和 SIMULINK 求解器步长一致,否则 v2 会算错。我一般先设r=50~200、h0=5h,看 v1 的过渡时间是否落在你想要的范围内,再微调。注意sat要自己定义成max(-1,min(1,x)),别用 Simulink 自带的 Saturation 模块替代,因为这里是对a/d做归一化饱和,量纲不一样。

2.2 扩张状态观测器 ESO:仿真里最容易发散的一块

ESO 是 ADRC 的心脏,也是仿真模型里最容易翻车的模块。它用对象输出 y 和控制量 u 去估计三个状态:z1(跟踪 y)、z2(跟踪 y 的微分)、z3(总扰动)。仿真里 ESO 发散,九成是带宽wo和步长h没配好。

function [z1, z2, z3] = eso_update(z, y, u, b0, wo, h) % z: 上一拍状态 [z1;z2;z3] % y: 对象输出, u: 控制量, b0: 控制增益估计 % wo: 观测器带宽, h: 步长 z1 = z(1); z2 = z(2); z3 = z(3); e = z1 - y; beta1 = 3 * wo; beta2 = 3 * wo^2; beta3 = wo^3; z1 = z1 + h * (z2 - beta1 * e); z2 = z2 + h * (z3 - beta2 * e + b0 * u); z3 = z3 + h * (-beta3 * e); end

逻辑说明:这是线性 ESO(LESO)的欧拉离散形式,beta1~beta3用带宽整定法直接由wo算出,这是仿真里最省事的做法。参数上,wo是核心:wo越大估计越快,但对步长越敏感。经验上wo * h不要超过 0.1~0.2,超过就容易数值发散。比如h=1e-3,wo最多给到 100~200。b0是控制增益的估计值,仿真里可以先按对象模型算出来,比如二阶对象y'' = -a*y' - b*y + c*u,那b0就取c的近似值。注意z3的初值一般设 0,别设成你猜的扰动量,否则前几拍会有大跳变。

2.3 非线性状态误差反馈 NLSEF:fal 函数和参数整定

NLSEF 把 TD 的 v1、v2 和 ESO 的 z1、z2 做差,得到 e1、e2,再用 fal 函数做非线性组合,最后减去 z3/b0 得到控制量 u。仿真里 fal 函数的幂次alpha和线性区宽度delta是两个必调参数。

function u0 = nlsef(e1, e2, kp, kd, alpha1, alpha2, delta) % fal: 非线性函数 fal = @(e, alpha, d) (abs(e) <= d) .* (e / d^(1-alpha)) + ... (abs(e) > d) .* (sign(e) .* abs(e).^alpha); u0 = kp * fal(e1, alpha1, delta) + kd * fal(e2, alpha2, delta); end

逻辑说明:fal在|e|<=delta时是线性的,避免零点附近增益无穷大导致抖振;|e|>delta时按幂次alpha压缩。参数上,alpha1常取 0.5~0.75,alpha2常取 1.0~1.5,delta取 0.01~0.1。kp、kd可以先用 PID 的思路给初值,再靠仿真微调。注意delta太小会让 u 在零点附近抖,太大又退化成线性 PD,失去 ADRC 的非线性优势。我一般先设delta=0.05,看 u 的波形有没有高频毛刺再调。

2.4 在 SIMULINK 里把四块接起来的最小步骤

把上面三个 MATLAB Function 模块和一个对象模型接起来,就是最小 ADRC 仿真模型。步骤:

  1. 新建模型,求解器选固定步长Fixed-step,步长h=1e-3,求解器用ode4(RK4)或ode1(欧拉)。ESO 和 TD 用欧拉离散,求解器用ode1最一致,但对象连续部分用ode4更准,所以常见做法是对象用连续模块、控制器用离散 MATLAB Function,求解器选ode4固定步长。
  2. 放三个 MATLAB Function 模块,分别贴上面三段代码,输入输出端口对齐。
  3. 对象用一个二阶传递函数或状态空间模块,比如1/(s^2+2s+1),输出接 ESO 的 y。
  4. 加一个 Step 模块给参考信号,加 Scope 看 v1、y、z3、u 四条线。
  5. 控制量 u = u0 - z3/b0,用一个 Gain 和 Sum 实现。

接好后先别急着看整环,把 ESO 单独跑:给对象一个固定 u,看 z1 能不能跟上 y、z3 能不能收敛到扰动。这一步过了,整环才有意义。

3. 参数怎么设:带宽、步长、b0 的三角关系

ADRC 仿真模型调不调得出来,八成看三个参数:观测器带宽wo、控制器带宽wc、控制增益b0。这一章把这三个参数的整定逻辑和仿真里的具体数值范围讲透,并给出可复现的调参顺序。

3.1 带宽整定法:wo 和 wc 到底差几倍

带宽整定法(Bandwidth Parameterization)是仿真里最实用的整定方式:把 ESO 的极点全配到-wo,把控制器闭环极点配到-wc。经验关系是wo = 3~5 倍 wc。为什么?因为观测器必须比控制器快,才能及时把扰动估出来补掉;但wo又不能无限大,受步长限制。

仿真里我一般这样起步:先按对象带宽估一个wc,比如对象自然频率 10 rad/s,那wc取 20~50;然后wo取3~5 倍 wc,即 60~250;再检查wo*h是否小于 0.2。如果h=1e-3,wo=200时wo*h=0.2,已经在边界上,再大就要减小步长或换离散方法。

参数含义仿真起步值约束
wc控制器带宽20~50 rad/s越大响应越快,超调越大
wo观测器带宽3~5 倍 wcwo*h < 0.2
b0控制增益估计对象 u 到 y'' 的增益偏差 20% 内可接受
h仿真步长1e-3 s与 wo 联动
deltafal 线性区0.05太小抖,太大退化

3.2 b0 估偏了会怎样:仿真里故意试一次

b0是 ADRC 里最“反直觉”的参数:它不需要精确,但偏太多会直接影响 z3 的估计和 u 的幅值。仿真里我建议你故意把b0设成真实值的 0.5 倍和 2 倍各跑一次,看波形。

% 在脚本里批量试 b0 b0_true = 1.0; for ratio = [0.5, 1.0, 2.0] b0 = b0_true * ratio; sim('adrc_model'); % 运行模型 % 记录 y 的超调和 z3 的收敛时间 end

逻辑说明:b0偏小,z3 会估出一个虚假的大扰动,u 会偏大,系统可能过冲;b0偏大,z3 估计不足,抗扰变慢。参数上,仿真里b0在真实值 0.5~2 倍内,ADRC 一般还能稳住,但超调和恢复时间会明显变化。注意别把b0和kp一起乱调,先固定b0再调kp/kd,否则你分不清是谁的贡献。

3.3 离散化步长和求解器的选择:ode1 还是 ode4

仿真里 ESO 和 TD 是离散迭代,对象可能是连续模块,两者混用时求解器选择很关键。常见做法:

  • 控制器全用离散 MATLAB Function,对象用连续状态空间,求解器选ode4固定步长1e-3。这样对象积分精度够,控制器按步长离散。
  • 如果全用离散模块,求解器选ode1,步长1e-3,最一致但对象精度差。
  • 不建议用变步长求解器,因为 ESO 的h必须固定,变步长会让beta系数失效。

我一般用ode4+ 固定步长,然后在 ESO 里显式用h=1e-3。注意 SIMULINK 的 MATLAB Function 模块里不能直接读求解器步长,要把h作为参数传进去,或者用Sample time设成1e-3并勾选“视为离散”。

4. 避坑与排查:仿真模型发散、抖振、稳态误差的 5 个血泪记录

这一章全是踩过的坑,每条按“现象 → 原因 → 解决”写。你如果模型跑不通,先来这里对号入座,比重新读论文快。

4.1 现象:一运行就发散,y 指数上升

原因:最常见是 ESO 的wo太大,wo*h超过 0.2,欧拉离散不稳定;其次是b0符号搞反,导致 z3 正反馈。

解决:先把wo降到0.1/h以下,比如h=1e-3时wo<=100;再检查b0的符号,对象u增大时y应该同向变化,如果反了就把b0取负。还不行就把 ESO 单独跑,给固定u,看 z1 是否发散。

4.2 现象:波形能跑但 u 高频抖振,电机仿真里尤其明显

原因:fal的delta太小,零点附近增益过大;或者wo太高,z3 把噪声放大后补到 u 上。

解决:把delta从 0.01 提到 0.05~0.1;在 ESO 的y输入前加一个一阶低通,截止频率取wo/3~wo/5;或者把wo降到3 倍 wc而不是 5 倍。注意低通会引入相位滞后,别加太狠。

4.3 现象:稳态有误差,z3 收敛但 y 到不了参考值

原因:NLSEF 里忘了减z3/b0,或者b0偏大导致补偿不足;也可能是 TD 的v1本身没到参考值。

解决:检查 u 的表达式是不是u = u0 - z3/b0;把b0调小 10%~20% 看误差是否减小;单独看v1的稳态值,如果v1就没到 r,那是 TD 的r太小或h0太大。

4.4 现象:改了步长后原来能跑的模型又发散了

原因:beta1~beta3是按wo算的,但离散化误差随h变化,h变大后欧拉法精度下降。

解决:步长和wo必须联动。h加倍,wo要减半,保持wo*h不变。或者换用双线性离散(Tustin)的 ESO,对步长没那么敏感,但代码要改。

4.5 现象:对象参数变了,ADRC 还能跑但性能下降明显

原因:b0是按标称对象算的,对象增益变化后b0失配;ESO 虽然能估总扰动,但b0失配太大时 z3 会估出一个包含模型误差的“假扰动”,补偿后仍有残差。

解决:仿真里试b0在 ±50% 内的鲁棒性,如果不够,把wo提高一点(在步长允许范围内)加快扰动估计;或者上自适应 ADRC,但那是另一个话题了。

5. 进阶技巧:用脚本批量扫参和自动验证 ESO 收敛性

仿真模型搭通之后,真正省时间的是把调参变成脚本化。这一章给两个具体技巧:用 MATLAB 脚本批量扫wo和wc,以及用李雅普诺夫式的数值检查自动判断 ESO 是否收敛。最后说一个我自己的习惯。

5.1 批量扫参:把 wo 和 wc 的网格跑成热力图

手动改参数跑仿真太慢,我一般写个脚本循环,把超调和调节时间存成矩阵,画热力图找最优区。

wc_list = 20:10:80; wo_ratio = 2:0.5:6; result = zeros(length(wc_list), length(wo_ratio)); for i = 1:length(wc_list) for j = 1:length(wo_ratio) wc = wc_list(i); wo = wc * wo_ratio(j); if wo * 1e-3 > 0.2 result(i,j) = NaN; % 跳过不稳定区 continue; end assignin('base', 'wc', wc); assignin('base', 'wo', wo); sim('adrc_model'); result(i,j) = max(y_out) - 1; % 超调量 end end imagesc(wo_ratio, wc_list, result); colorbar; xlabel('wo/wc'); ylabel('wc');

逻辑说明:assignin把参数推到工作区,模型里用wc、wo变量引用。result存超调量,NaN标记wo*h>0.2的不稳定区。参数上,wc扫 20~80,wo/wc扫 2~6,步长按需。注意每次sim前要set_param重置模型状态,否则上一轮的结果会污染下一轮。这个脚本跑完,你能一眼看出稳定且超调小的参数区,比手动试快十倍。

5.2 自动验证 ESO 收敛:看 z3 的残差而不是看波形

ESO 收没收敛,肉眼看波形不准。我一般加一个数值检查:在仿真结束后取 z3 的最后 10% 数据,算它的标准差,如果标准差小于某个阈值,就认为收敛。

z3_data = logsout.get('z3').Values.Data; n = length(z3_data); tail = z3_data(round(0.9*n):end); if std(tail) < 1e-3 disp('ESO 收敛'); else disp('ESO 未收敛,检查 wo 和 h'); end

逻辑说明:logsout是 SIMULINK 的信号记录,z3要提前勾选记录。tail取后 10%,std小说明 z3 稳定。参数上,阈值1e-3按你的扰动量级调,扰动大就放宽。注意这个检查要在对象进入稳态后做,如果参考信号一直在变,z3 本来就在动,不能这么判。

5.3 我自己的习惯:先跑开环 ESO,再闭环,最后加扰动

搭 ADRC 仿真模型,我从来不一开始就跑整环。我的顺序是:第一步,对象给固定 u,单独跑 ESO,确认 z1 跟得上 y、z3 能收敛;第二步,接上 NLSEF 和 TD,给阶跃参考,看跟踪;第三步,在对象输入端加一个阶跃扰动,看 z3 能不能估出来并补掉。这三步任何一步不过,都不往下走。这个习惯帮我省了无数“整环发散但不知道谁的问题”的时间。ADRC 的仿真模型不难,难的是你愿不愿意把它拆开一块块验证。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 16:49:58

工厂MES系统为什么需要数据中台

很多工厂管理者都有类似困惑&#xff1a;花大钱上了MES系统&#xff0c;数据调取却还依赖人工导表和手动汇总&#xff0c;导致实际应用往往出现各种误差。原因可能在于系统设计上。MES被设计出来&#xff0c;解决的是“生产执行过程的管理问题”&#xff1a;工单下发、工序流转…

作者头像 李华
网站建设 2026/10/15 16:49:10

C++内存池技术解析:消除延迟毛刺与内存碎片

简介&#xff1a;一套C内存池实现源码包&#xff0c;采用一级全局内存池与每线程独立二级内存池的双层结构&#xff0c;面向需要优化高并发场景下频繁分配与释放小块内存的C开发者&#xff0c;可有效减少系统调用和内存碎片。资源共33个文件&#xff0c;以17个h头文件和9个cpp源…

作者头像 李华
网站建设 2026/10/15 16:48:39

无线话筒射频链路复现指南:从综合文档到可量产方案

简介&#xff1a;这份资源是围绕无线话筒技术整理的综合性文档包&#xff0c;面向音频工程初学者、电子设计爱好者及需要了解无线传输原理的从业者&#xff0c;帮助其系统认识无线话筒的工作机制与工程实现。压缩包共12个文件&#xff0c;约70KB&#xff0c;以Altium Designer工…

作者头像 李华