
简介这是一份围绕自抗扰控制器ADRC的Simulink仿真学习资源面向控制工程专业学生、研究人员及自动化工程师适合希望掌握ADRC建模、参数调试与抗扰性能验证的读者。包内共36个文件以31个m脚本为主辅以4个mdl仿真模型和1个asv自动保存文件m文件涵盖fal函数、扩张状态观测器ESO、非线性反馈、控制律及被控对象建模等核心环节mdl文件则提供可直接运行的Simulink框图便于对照学习与二次开发。压缩包仅37KB内容精炼、结构清晰。资源围绕TD ESO、误差反馈滤波SEF以及chap6系列案例展开包含多个典型被控对象的仿真实现与绘图脚本能帮助读者从基础原理走向实际搭建。已有1249人学习下载适合通过实例快速上手ADRC仿真并开展控制策略优化。 做控制的人迟早会遇到一个让人头疼的场景模型参数明明没变仿真一切正常可一到现场或换了台设备之前调好的PID全废了。增益没改系统却开始抖。原因无非是对象特性变了、负载变了或者干脆就是建模时候的简化误差在作祟。我当年为解决这个问题折腾了很久最后转到自抗扰控制器ADRC上配合Simulink做开发和验证才算找到一条相对稳妥的路径。这篇内容适合两类人来看一类是刚接触ADRC、想搞明白它到底怎么工作的学生或工程师另一类是在Simulink里搭过模型但调不通、总发散甚至不知道从哪里下手的人。我会把ADRC的三大组成部分、Simulink里的具体搭建方式、参数整定的实战顺序以及我踩过的那些仿真坑全部摊开来讲。整个过程不依赖别人的封装库每个模块都自己搭这样你才能真正理解它而不只是会点“一键应用”。自抗扰到底比PID强在哪一个二阶对象的现实对照先说清楚ADRC的出现背景。PID控制之所以普及是因为它只需要误差、误差积分和误差微分不依赖被控对象模型。但当对象参数摄动明显、外部扰动大时PID的增益一旦固定性能就会退化严重时稳定性都保不住。ADRC的思路很简单不要把控制问题拆成“模型精确描述扰动量级估算”而是把系统内部动态不确定性和外部扰动合并成一个“总扰动”再用扩张状态观测器去实时估计并补偿掉。这套思想最早由韩京清先生系统提出后续又发展出线性化版本LADRC在工业控制里落地得很稳。1.1 模型不确定性和外部扰动为什么难处理想象你控制一个伺服电机驱动的位置系统。你用二阶模型近似它Jθ̈ Kt·u - T_load。但实际转动惯量J会随负载变化摩擦也不是线性的电机参数在发热后会漂移负载力矩更是随时可能变。这一类“模型误差未知外力”在传统控制框架里分别对应参数不确定性和外部扰动。PID对付这些的方式是靠积分项慢慢把稳态误差压下去但动态过程中这些扰动仍然会直接影响系统行为你想提高响应速度就容易把噪声也放大。ADRC的做法是把“J是标称值还是真实值”“摩擦到底多大”“负载力矩多少”这些问题全部丢进总扰动项。你不需要精确知道它只要让观测器把它估出来再在控制量里减去这个估计值系统就变成了一个接近纯粹的二重积分器。这时候再用很简单的PD控制性能也相当好。这就是它不依赖精确模型却能保持鲁棒性的根本原因。1.2 ADRC三件套各自的任务边界一个标准的ADRC由三部分组成跟踪微分器TDTracking Differentiator、扩张状态观测器ESOExtended State Observer、非线性状态误差反馈律NLSEF。用一句话概括它们的分工TD负责“安排过渡过程”ESO负责“看穿总扰动”NLSEF负责“给出补偿力度”。TD解决的是超调与快速性的矛盾。传统PID里阶跃响应想要快误差大微分项会猛烈动作容易超调。TD会把目标信号处理成一条平滑的过渡轨迹控制器在初始阶段追的是“过渡目标”而不是那个陡峭的阶跃超调自然被压下来。ESO是整套方法的核心。它把系统状态x1位置、x2速度以及扩张出来的x3总扰动同时观测出来。你不需要额外装传感器只需要对控制量u和测量输出y做处理x3就会实时逼近真实的扰动。NLSEF做的事情很直白根据当前状态与TD给出的预期轨迹之间的误差计算出一个反馈量再把ESO估计的总扰动补偿进去。补偿完之后控制器面对的“等效对象”就是一个标准二重积分器处理起来非常顺手。Simulink里从零搭ADRC不靠别人的封装理解每一步很多人习惯直接找现成的ADRC工具箱但我强烈建议至少手搭一次。原因是ADRC的调参和排错高度依赖对内部结构的直观理解你只有自己连过线、写过S函数才能在发散的时候知道问题出在哪一层。下面我按TD、ESO、NLSEF三个模块分别说明Simulink中的搭建方法。2.1 安排过渡过程最容易被省略却最有价值的一环TD的用处很多人低估了。实际上即使不加ESO只把PID前的参考信号换成TD的平滑输出超调都会有明显改善。TD的离散形式常采用最速控制综合函数fhanfunction [xh, xh_dot] fhan(x1, x2, v, r, h0) d r * h0 * h0; a0 h0 * x2; y x1 - v a0; a1 sqrt(d * (d 8 * abs(y))); a2 a0 sign(y) * (a1 - d) / 2; a (a0 y) * (fsg(y, d)) a2 * (1 - fsg(y, d)); fhan -r * (a / d) * fsg(a, d) - r * sign(a) * (1 - fsg(a, d)); xh x1 h0 * x2; xh_dot x2 h0 * fhan; end function f fsg(x, d) f (sign(x d) - sign(x - d)) / 2; end在Simulink里搭建TD推荐用MATLAB Function模块。输入是参考信号v输出是过渡位置x1和过渡速度x2。两个输出分别通过积分器反馈回来形成闭环过程。这里要注意循环里不能直接用普通积分器否则有代数环问题。最好把整个递推写进一个函数里状态用persistent变量保存或者用单位延迟模块Unit Delay形成离散状态否则你会在仿真时报代数环错误。如果你只是想先跑通理解流程TD可以简化为一个低通滤波器配置的软启模块。但既然做ADRC我建议一步到位用离散fhan因为它在参数r跟踪速度和h0滤波因子上物理意义明确对后续调参好处很大。2.2 扩张状态观测器整个控制器的灵魂ESO的连续形式可以写成ẑ1 z2 β1·(y - z1) ẑ2 z3 β2·(y - z1) b0·u ẑ3 β3·(y - z1)其中z1观测输出yz2观测速度z3观测总扰动u是控制量b0是控制增益的估计值。在Simulink里搭这个结构很简单三个积分器串联误差项(y - z1)加权后分别反馈到三个积分器输入端。实际使用时我强烈建议使用离散形式function [z1, z2, z3] eso_discrete(y, u, z1, z2, z3, dt, beta1, beta2, beta3, b0) e y - z1; z1 z1 dt * (z2 beta1 * e); z2 z2 dt * (z3 beta2 * e b0 * u); z3 z3 dt * (beta3 * e); end在Simulink里用MATLAB Function模块承载这个函数状态z1、z2、z3通过Unit Delay反馈回来。这样比连续积分器更适合后续做定点仿真和代码生成也不容易出现连续积分器在固定步长下漂移的问题。ESO的参数β1、β2、β3可以根据带宽ωo整定。最经典的方案是配置成观测器特征多项式s³ β1·s² β2·s β3 (s ωo)³于是β1 3ωoβ2 3ωo²β3 ωo³。后面整定部分我会细讲。在连线时务必注意b0·u这路输入要接到第二个积分器的输入端否则ESO对控制效果的估计就不完整。2.3 非线性反馈律把扰动补偿回去NLSEF常规写法是用非线性函数falfunction f fal(e, alpha, delta) if abs(e) delta f sign(e) * abs(e)^alpha; else f e / (delta^(1 - alpha)); end end反馈律可以写成u0 k1·fal(e1, α1, δ) k2·fal(e2, α2, δ)其中e1是TD过渡位置与观测器输出z1的差e2是TD过渡速度与z2的差。最终的控制器输出为u u0 - z3/b0。这里有个很关键的细节扰动补偿方向。实际工程中我的建议是先用线性版本也就是把fal换成普通放大u0 k1·e1 k2·e2。非线性版本的优势在理论边界更清晰但在强噪声环境下α小于1的fal会把测量噪声放大反而不如线性反馈稳定。你完全可以从LADRC线性自抗扰入门跑通了再改非线性对比效果。搭建时把u u0 - z3/b0的计算放在一个单独的模块里方便观测补偿项到底有多大。调试时我会同时把z3和b0·u的数据存到工作区看补偿量是否和实际扰动同一数量级。如果差得太多往往说明b0估得不对。参数整定不是玄学从带宽概念落地的实操顺序ADRC给人的第一印象是参数太多了TD有r和h0ESO有β1β2β3反馈有k1k2还有b0。新手会直接被劝退。但当你把参数映射到“观测器带宽ωo”和“控制器带宽ωc”上就好办多了。3.1 先把观测器带宽定下来再谈控制器ESO的核心任务是让z3足够快地逼近真实扰动。带宽ωo决定ESO跟踪速度ωo越大观测越快但对噪声越敏感。一般建议ωo比期望的闭环控制带宽ωc大3到10倍。为什么因为ESO需要在控制器动作的时间尺度内就把扰动估出来如果ωo低于或接近ωc则扰动补偿滞后期等效于在回路里串了惯性环节会拖累稳定性。具体到离散实现要保证采样频率fs满足fs ωo/(2π)经验值建议fs至少是ωo对应频率的20倍以上。这一步是很多人忽略的坑在Simulink中默认连续仿真没问题但一旦切到离散求解器或做代码生成采样时间太慢ESO表现会急剧恶化。3.2 一组可复现的参数和调参检查表假设被控对象是二阶系统我给出一个可复现的初始参数思路。设期望控制带宽ωc 20 rad/s观测器带宽ωo选5倍即100 rad/s采样步长dt 0.001 s。表ADRC初始参数一览线性形式参数计算方式示例值说明β13ωo300观测位置误差反馈β23ωo²30000观测速度误差反馈β3ωo³1000000总扰动误差反馈k1ωc²400位置误差反馈增益k22ωc40速度误差反馈增益b0对象控制增益估计由对象决定需要单独辨识b0怎么估最简单的方式是做开环阶跃仿真给对象一个恒定的控制输入u0记录输出加速度稳态值a0b0 ≈ a0/u0。对于伺服系统如果你知道J和力矩系数Ktb0 Kt/J。如果你只是随手搭的仿真模型用这种方式测量最靠谱。调参顺序按我的经验是先固定一个b0的初始估计把ωo调到仿真不抖再把ωc逐渐加上去。如果系统开始震荡优先看观测器输出z1和实际输出y之间的误差曲线。如果误差曲线噪声很大说明ωo太大或采样步长不够如果误差曲线有明显滞后说明ωo相对ωc偏低。调完这两个带宽再去动b0b0只在小范围修正一般不要来回动。调不通的时候别急着改增益我在Simulink里踩过的真实坑这一节想重点和大家分享排查思路。仿真发散十有八九不是ADRC算法本身的问题而是实现方式有问题。这里列出三类最常见的坑每一类我都给完整的排查链路。4.1 代数环和采样步长导致的假发散问题现象模型一开始仿真就报“Algebraic loop detected”或者干脆结果变成NaN。排查链路先检查ESO中是否存在纯比例反馈构成的闭环。ESO的误差项e y - z1经过增益后立刻又反馈到z1的积分输入如果用的是连续积分器有积分器隔断不会形成代数环但如果你为了省事把z1直接连到z1的初始值上或者用了增益模块后直接和输入相加就会形成代数环。解决办法是在反馈回路里插一个Unit Delay形成离散状态量。另一个常见原因是采样步长设置过大仿真步长超过ESO离散递推的稳定性边界也会导致数值发散。检查方式是逐步缩小固定步长看发散是否消失。4.2 微分信号噪声放大一阶惯性代替纯微分的实际操作现象仿真结果看起来振荡尤其当测量信号有噪声时控制器输出特别“炸”。原因ESO中z2和z3本质上是微分作用的广义扩展如果y有高频噪声经过观测器增益放大后会直接影响控制量。解决手段不是降低ωo到牺牲性能而是在测量链路里加一阶惯性滤波或者用低通滤波器处理输出反馈。具体操作在Simulink的y信号入口串联一个Transfer Fcn 1/(Tf·s 1)Tf取采样步长的5到10倍。也可以一步到位使用离散滤波模块。这一步看起来很简单但在实际工程中这个滤波器的存在几乎决定你能否把ωo调上去。4.3 饱和与积分器输出限制ESO需要知道执行的边界现象系统一开始正常一旦给定大幅阶跃控制量猛烈冲顶随后系统大幅回摆甚至振荡不收敛。排查链路控制器输出u已经进入饱和区但ESO内部还按照未饱和的u去计算b0·u此时ESO对系统的估计会产生偏差。更麻烦的是积分器输出可能持续累积造成“积分饱和”。解决方法是把实际执行器的饱和限幅反馈给ESO确保ESO里用的u和控制对象真正接收到的u一致。在Simulink里你在Saturation模块前后分别拉一条信号线通过开关选择饱和后的实际输出再送进ESO的b0·u输入口。这一处修改能让系统在大给定下稳定得多。从Simulink模型走向实际工程代码生成和联合仿真的要点做ADRC最大的成就感是模型从仿真跑通到最终能生成C代码嵌入控制器。这一路有很多细节一步没处理好离线仿真和高保真联合仿真结果会差很多。5.1 模型配置与定步长设置如果你计划做代码生成请一定把Simulink配置为固定步长Fixed-step离散求解器。推荐离散求解器如discrete采样时间设为与ESO递推一致的时间步长。连续求解器在代码生成时会产生复杂的积分器算法生成的代码体积大而且可能在硬件上跑出与仿真不一致的结果。在代码生成之前请把模型里的“MATLAB Function”所用到的变量全部显式声明为参数这样可以用Simulink的Parameter Optimization或External Input方式从工作区注入参数。热搜词里提到的“Simulink主模型参数导入方法详解”其实就是指在模型里用Simulink.Parameter封装增益、带宽等参数再通过set_param或模型参数文件批量更新。这样做的好处是当你在上层脚本里做参数扫描时不需要打开模型编辑器直接修改工作区参数就能批量跑仿真或生成不同配置的代码。代码生成环境下ADRC的时序稳定性是首要问题。ESO的递推计算必须在每个采样周期内完成因此代码生成后要在目标硬件上测量最大任务执行时间。如果远超采样周期系统会“跑飞”。在嵌入式环境里我通常会把ESO递推放到高优先级定时中断里NLSEF的计算可以放在同一个中断里连续执行。5.2 与Carsim/AMESim等联合仿真的接口要点联合仿真是ADRC验证的必经之路尤其是汽车、机器人这类场景。以Carsim和Simulink联仿为例Carsim提供车辆动力学模型Simulink里跑你的ADRC控制器。接口上有几个关键点需要关注时间步长匹配Carsim通常以固定步长输出车辆状态Simulink侧的控制器采样频率如果比Carsim高需要把控制器输入做零阶保持如果比Carsim低需要做状态插值。否则会造成控制率与车辆模型更新不同步。变量单位ADRC对量纲极其敏感。速度是km/h还是m/s角度是deg还是rad差一截控制效果就全变了。联仿前务必先做单位一致性检查。接口延迟Carsim与Simulink之间数据交换存在采样保持延迟这个延迟在高频控制下会显著降低系统稳定性。因此联仿时不宜把ωc调得过高否则仿真结果会振荡但实际控制器可能没问题——这个现象容易误判。至于四旋翼、无人机方向用Simulink搭VSG或滑模控制思路类似把对象模型替换成飞行器动力学ADRC作为姿态控制内环。ESO对传感器噪声和模型不确定性的抵抗能力在飞行器上比在电机上更明显因为空气动力学参数不确定性非常大。扩展一个实用小技巧在联合仿真里如果遇到系统振荡先在Simulink的Scope里同时观测z3和实际外部扰动如果有该信号可测看ESO是否准确跟踪。如果z3噪声过大但在合理范围优先怀疑测量信号跳变如果z3与实际扰动相位差太大优先怀疑ωo不足或仿真步长过大。写到最后我想分享一个个人体会ADRC在Simulink里的搭建并不难真正的门槛在于调试时的“工程直觉”。我至今保留一个习惯任何模型都先跑开环用Scope记录输入输出数据确认对象增益b0大致靠谱后再闭合控制环。凡是跳过这一步直接调参的最后基本都会绕回来。如果你也正在调ADRC不妨从今天起把ESO的z3当作最重要的那个观测量来对待盯住它很多问题会提前暴露。本文还有配套的精品资源点击获取