
简介这是一套ADRC自抗扰控制的Simulink仿真模型资源主要面向学习自抗扰控制、线性扩张状态观测器LESO以及二阶惯性系统仿真的本科生、研究生或工程师。资源包含3个文件1个PDF说明文档、1个.m调参脚本和1个.mdl仿真模型压缩包整体仅136KB文件虽小但结构完整。PDF为韩京清2009年经典论文可辅助理解ADRC原理与“从PID到自抗扰控制”的思想演进m文件用于集中设置控制器与观测器参数便于批量调节mdl模型已针对二阶惯性环节搭建完整的LESO结构参数已调好并额外加入噪声信号测试系统抗扰能力。该模型可直接运行便于观察LESO对扰动的估计效果以及ADRC的动态响应。目前已有3156人学习下载适合需要快速上手ADRC仿真验证、研究LESO参数整定或搭建类似控制系统的读者。1. ADRC为什么值得搭一套Simulink仿真模型——先把要解决的事说清楚在控制领域待久了你会发现一个现象PID用了上百年工程上依然好用但一旦对象变成强耦合、大惯量、强非线性或者外部扰动频繁变化PID的参数往往要反复调、到处补。ADRCActive Disturbance Rejection Control自抗扰控制这几年之所以越来越热就是因为它不依赖精确的数学模型把“没建模的动态”和“外部扰动”一并当成总扰动去估计、去补偿。这个思路听起来很美但真正上手时大多数人第一关就卡在仿真上——ADRC的结构比PID复杂涉及跟踪微分器、扩张状态观测器和非线性反馈光看公式容易晕直接上真机又风险大。所以一套结构清晰、参数可调的Simulink仿真模型就成了理解ADRC、验证控制效果、甚至为后续代码生成做铺垫的最短路径。这篇文章适合正在学ADRC的研究生、想尝试新控制算法的工程师以及被PID调到崩溃又想找个新方案的人。我会从ADRC的核心结构讲起把Simulink里怎么搭、参数怎么给、坑在哪里一次讲透。全程围绕一个典型二阶对象展开给出可直接抄走的模型结构和代码你甚至不需要完整理解韩京清那几篇经典论文也能先把仿真跑起来。2. 从韩京清的三件套到Simulink模块映射TD、ESO、NLSEF逐个拆2.1 跟踪微分器TD给参考信号配一个“平滑过渡”ADRC的第一个环节是TD它的任务是安排过渡过程。为什么需要它因为实际系统中阶跃参考信号直接怼进去驱动器容易饱和输出容易超调。TD的本质是一个动态整形器它跟踪参考信号v输出两个量跟踪值v1和跟踪值的微分v2。这样一来控制器拿到的不再是突变的阶跃而是一条平滑上升的曲线和它的变化速度。Simulink里实现TD最方便的方式是用MATLAB Function写一个最速控制综合函数fhan。经典的离散形式是function [x1, x2] td_update(v, x1_prev, x2_prev, r, h) % 离散跟踪微分器基于fhan函数 d r * h * h; a0 h * x2_prev; y x1_prev - v a0; a1 sqrt(d * (d 8 * abs(y))); a2 a0 sign(y) * (a1 - d) / 2; sy (sign(y d) - sign(y - d)) / 2; a (a0 y - a2) * sy a2; sa (sign(a d) - sign(a - d)) / 2; fhan -r * (a / d - sign(a)) * sa - r * sign(a); x1 x1_prev h * x2_prev; x2 x2_prev h * fhan; end这里面r是速度因子决定过渡过程快慢h是采样周期。你可以把它想成一位司机踩油门的方式r越大司机越激进逼近目标越快但加速度冲击也大r小了车开得平缓但到位慢。TD的好处是v2作为参考信号的微分质量远高于直接对v做差分——后者在噪声环境下基本没法用。2.2 扩张状态观测器ESOADRC的真正灵魂ESO是整个ADRC的核心。它的思路是把系统里所有不确定的东西——未建模动态、参数变化、外部扰动——统统归结为一个“总扰动”然后把它当作一个额外的状态变量去实时估计。这就是“扩张”两字的由来。以二阶对象为例假设对象可以写成x1_dot x2 x2_dot f(x1, x2, w, t) b0 * u y x1其中f包含了内部动态和外部扰动b0是控制增益的估计值。ESO将f扩张成第三个状态z3观测器写成z1_dot z2 beta1 * (y - z1) z2_dot z3 beta2 * (y - z1) b0 * u z3_dot beta3 * (y - z1)当观测器收敛后z1跟踪yz2跟踪x2z3就逼近总扰动f。这个结构翻译成Simulink就是三个积分器串联加反馈增益一点花哨都谈不上但意义重大。注意z3的输入只有beta3 * (y - z1)它没有直接接到系统的任何输入上却能把扰动估计出来——这是ADRC最反直觉也最精彩的地方。2.3 控制律与扰动补偿把估计出来的扰动“消掉”有了TD和ESO控制律就很直接了。经典形式是u0 kp * (v1 - z1) kd * (v2 - z2) u (u0 - z3) / b0第一行是PD形式但它用的不是测量值y和实际微分而是ESO的估计值z1、z2以及TD的平滑信号v1、v2。这样做的直接好处是抑制噪声。第二行是扰动补偿既然z3估计出了总扰动就在控制量里把它减掉再除以b0换算成实际的执行机构输出。整个过程可以理解为先把一切干扰“看见”再“抵消”掉。对于非线性ADRC韩京清的做法是把线性PD换成非线性组合即用fal函数function f fal(e, alpha, delta) % fal非线性函数兼具小误差高增益和大误差低增益特性 f e / (delta^(1 - alpha)) * (abs(e) delta) ... (abs(e)^alpha) * sign(e) * (abs(e) delta); endalpha典型取0.5或0.75delta取0.01左右。非线性组合的核心思想是“小误差大增益大误差小增益”让系统既快又不超调。不过说实话非线性ADRC调起来比线性版麻烦不少我后面会建议先从线性开始。3. 手把手搭建两种Simulink落地方式和一套可直接套用的离散模型3.1 方式一纯模块搭建适合教学和理解原理如果你想看清楚每个信号怎么流动纯模块搭建最合适。以二阶对象的ESO为例用三个Integrator模块串联第一个积分器输出z1第二个输出z2第三个输出z3反馈偏差(y - z1)分别乘以beta1、beta2、beta3加到三条通道的输入端b0*u加到第二条通道的输入端。TD和NLSEF也可以用Gain、Add、Math Function搭出来但fhan函数和fal函数用纯模块搭会比较繁琐我建议这两处用MATLAB Function块。这样Model里既有清晰的信号流又有简洁的算法封装是兼顾可读性和可维护性的折中方案。3.2 方式二MATLAB Function封装核心算法工程验证效率最高我更推荐的方式是把TD、ESO、NLSEF写成一个完整的离散ADRC函数整体放进一个MATLAB Function块里。这样不仅模块图干净后续想要转成C代码也更容易。下面是一个线性ADRC的完整例子function u adrc_discrete(v, y, u_prev, r, h, b0, kp, kd, wo) % 离散ADRC控制器TD LESO 线性反馈 persistent x1_td x2_td z1 z2 z3 if isempty(x1_td) x1_td 0; x2_td 0; z1 0; z2 0; z3 0; end % TD更新 d r * h * h; a0 h * x2_td; yt x1_td - v a0; a1 sqrt(d * (d 8 * abs(yt))); a2 a0 sign(yt) * (a1 - d) / 2; sy (sign(yt d) - sign(yt - d)) / 2; a (a0 yt - a2) * sy a2; sa (sign(a d) - sign(a - d)) / 2; fhan -r * (a / d - sign(a)) * sa - r * sign(a); x1_td x1_td h * x2_td; x2_td x2_td h * fhan; % LESO更新带宽法配置增益 beta1 3 * wo; beta2 3 * wo * wo; beta3 wo * wo * wo; e y - z1; z1 z1 h * (z2 beta1 * e); z2 z2 h * (z3 beta2 * e b0 * u_prev); z3 z3 h * (beta3 * e); % 控制律 e1 x1_td - z1; e2 x2_td - z2; u0 kp * e1 kd * e2; u (u0 - z3) / b0; end在Simulink里使用时把对象的控制输入接到这个块的输出对象的输出y和参考信号v接入输入u_prev要接一个Unit Delay反馈回来的上一拍控制量h直接填采样周期。注意用persistent变量时模型里不要再用其他离散状态复制备份否则仿真结果会打架。3.3 采样周期、求解器和代码生成那些事ADRC是典型的时间驱动控制器所以仿真配置里求解器务必选择“定步长”fixed-step步长和h保持一致。我常用的组合是步长1e-3求解器ode4RK4这和实际嵌入式控制器的节拍更接近。如果用了变步长ESO的收敛性讨论会变得很拧巴步长跳来跳去z3很难干净地估计扰动。另外热词里有人提到Simulink模型生成C代码。ADRC离散模型天然适合代码生成只要保证MATLAB Function里不使用动态内存分配、不依赖外部文件用Embedded Coder就能生成标准C函数。真机部署时的抖动问题仿真阶段就值得提前用定步长模拟。4. 从仿真算例看参数整定带宽公式、b0辨识与调参顺序4.1 一套能直接用的算例参数为了让你不空手而归我给一个典型算例。被控对象是二阶系统G(s) 133 / (s^2 25s)它在电机位置伺服或者机械传动系统里很常见。写成状态方程就是x1_dot x2 x2_dot -25 * x2 133 * u d(t)其中d(t)是外部扰动。仿真里我习惯在3秒时加入一个幅值为50的阶跃扰动或者在2秒后加一个幅值为10、频率2Hz的正弦扰动用来考验ESO的估计能力。线性ADRC的参数可以用带宽法先定出一组能跑的初值。根据期望的闭环响应速度取控制器带宽wc 20 rad/skp wc^2 400kd 2 * wc 40观测器带宽wo一般取3到10倍wc这里取wo 5 * wc 100beta1 3 * wo 300beta2 3 * wo^2 30000beta3 wo^3 1000000b0就是对象控制增益的估计值取133TD的r取200h取0.001。这套参数放到模型里控制器几乎不会发散。之后的优化方向就是观察两个关键指标参考信号阶跃时的超调量和上升时间扰动加入后z3的跟随速度以及输出的最大偏差。4.2 b0不认识的话ADRC的优势直接减半b0是ADRC里一个需要特别尊重的参数。它是对对象控制增益的估计不要求精确但偏差不能离谱。b0偏大时扰动补偿过度系统容易抖动b0偏小时补偿不足抗扰能力下降。实践中我一般通过开环阶跃响应的稳态速率或者简单辨识先估一个b0再去仿真里微调。如果你连b0都完全不知道ADRC的优势就少了一半所以在做仿真之前最好对对象有一个粗略的物理认识比如电机电压-加速度的比例关系或者加热器功率-升温速率的比例关系。4.3 调参顺序先ESO后反馈最后才算微调很多新手一上来就调kp、kd发现系统不收敛就怀疑参数公式算错了。其实顺序反了。ADRC能工作的前提是ESO先收敛有了可靠的状态估计控制律才有意义。所以我的调参习惯是先把对象单独跑起来确认输入输出范围正常只接ESO不接控制律观察z1是否跟上y、z3是否能把扰动估计出来确认ESO跟踪良好后再接入带kp、kd的控制律最后根据超调、快速性微调r和kp/kd。如果ESO没调好就急着调反馈增益系统发散了你根本分不清是观测器的问题还是控制律的问题。这个顺序能让排错范围缩小一半以上。5. 仿真验证、分析与踩坑记录5.1 仿真结果怎么判读三个关键信号把上面的参数放进模型跑一个10秒仿真你会看到几件有意思的事。首先是TD对阶跃参考信号的整形。v1不再是一条直角阶跃线而是一条受r约束的平滑上升曲线v2是类似钟形的速度曲线最大速度随r增大而增大。如果r过大v1就接近阶跃TD反而失去了意义。其次是输出y的响应。在线性ADRC下典型响应是几乎没有超调地跟上v1稳态误差趋近于零。3秒加入扰动d50后系统输出会有一个短暂的波动然后在一两个ESO收敛周期内恢复到参考值。这个恢复速度主要取决于wo的大小——wo越大扰动估计和补偿越快但代价是噪声敏感。最后看z3的曲线。扰动加入后z3会在几十毫秒内从0逼近50附近。这个估计过程在仿真里几乎是看见扰动发生的瞬间。如果你发现z3一直追不上扰动优先检查b0是否正确其次看wo是否被其他约束拉低了。5.2 实战中踩过的坑初始值尖峰、代数环、离散步长不匹配第一个坑是初始值尖峰。如果对象的真实初值和ESO初值不一致模型一启动z1瞬间要追y输出会看到一个很大的尖峰。这个尖峰在仿真里无所谓但如果整定阶段用这个尖峰去评价超调量会让你误判。解决方法是把ESO初始状态z1、z2设为对象状态的初值或者干脆让参考信号从0开始平缓上升。第二个坑是代数环。ADRC的扰动补偿项里包含当前拍的控制量u如果控制律里直接用了y而不是z1、z2很容易在Simulink里形成代数环。Simulink会报错或者提示“Algebraic Loop”。规避的方法是严格使用TD的v1、v2和ESO的z1、z2构成误差不要直接拿测量值y去算控制量。这也是ADRC结构上的一个隐性优点。第三个坑是变步长求解器带来的ESO发散。我见过不止一次有人用默认的变步长ode45跑ADRC结果z3在某个时间段剧烈振荡费半天劲查不出原因。换成定步长ode4、步长设成与控制周期一致问题马上消失。原因是ESO的离散递推公式假定步长恒定变步长会让观测器增益的实际作用忽大忽小属于“模型不匹配”问题。第四个坑是持久变量状态复位。使用MATLAB Function里的persistent变量时如果模型里还有Reset子系统或使能子系统状态复位逻辑一定要处理干净。仿真中途修改参数重新运行persistent变量可能不刷新导致你看到的结果是上一次仿真的残留状态。我的习惯是模型里加一个“初始化子系统”启动时对所有状态清零。5.3 延伸思考ADRC再往后走能接什么搭完这套ADRC仿真模型后你会发现它做的工作远不止是让阶跃不超调。因为ESO把系统的总扰动实时给出来了你可以进一步做很多事情比如把模型做成增益调度、加入前馈、或者把z3作为故障诊断的特征量。很多做导弹BTT/STT控制建模、四旋翼滑模控制仿真的人也会把ADRC作为底层控制器嵌套进联合仿真环境里。Simulink里的ADRC模型同时也是通往C代码生成、硬件在环测试的中间桥梁这一点在工程交付时尤其加分。我把这套模型保存为四个文件对象模型、ADRC控制器、参数初始化脚本、对比分析脚本。这样每次换对象、换扰动场景时不用动模型改参数脚本就行。做仿真这件事尤其是控制仿真最大的成本从来不是搭模型而是排错和调参。你把ADRC的结构吃透了参数顺序弄对了剩下的就是一遍一遍跑仿真、观察曲线、微调参数的自然过程。本文还有配套的精品资源点击获取