拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ADRC自抗扰控制Simulink仿真全解析:从TD/ESO原理到参数整定实践

简介面向需要实现ADRC自抗扰控制算法的工程师、研究人员和学生这份资源通过Simulink仿真平台完整呈现自抗扰控制器架构细化ESO扩张状态观测器与TD跟踪微分器等核心模块并提供Simulink模型和S函数两个可对照版本有助于理解控制律、观测器与扰动补偿之间的关系。包内共7个文件以m函数源码、mdl模型文件为主搭配操作演示视频和说明文档构成一套麻雀虽小、五脏俱全的仿真工程压缩包仅707KB便于快速下载部署。资源对运行环境提出明确要求Matlab 2021a或更高版本并提供Runme.m统一入口及操作录像针对当前文件夹路径、子函数调用等易错点做了演示能直接降低上手门槛。目前已有5095人学习适合刚接触自抗扰控制、希望快速搭建仿真验证平台的读者。 我前前后后帮人搭过不少ADRC的Simulink仿真也见过太多人在扩张状态观测器ESO和跟踪微分器TD这两个模块上卡壳。说实话ADRC刚上手的时候确实比PID复杂不少——PID你随便给几个参数就能跑起来ADRC要是参数没给对仿真直接发散或者输出抖得跟筛子一样。但我也得说句公道话一旦你理解了ADRC“观测扰动、补偿扰动”这套思路再回头看它的Simulink实现其实每一步都有章可循比PID那种纯靠经验调试的方式“有逻辑得多”。这篇文章我就拿一个完整的ADRC控制仿真项目来拆解从TD、ESO、NLSEF三个核心模块的原理讲起一直讲到Simulink模型搭建、参数整定、离散化处理最后再聊聊我实际踩过的坑。你要是正准备做ADRC仿真或者已经在做了但结果总是不对这篇文章应该能帮你省下不少时间。1. 先搞明白ADRC在解决什么问题在动手搭Simulink模型之前我建议你先花十分钟想清楚一个问题你到底为什么要用ADRC而不是PID这个问题想不清楚后面调参你一定会调得怀疑人生。PID的核心问题是“基于误差消除误差”——它只知道输出和目标的偏差不知道这个偏差是怎么来的。如果系统里有外部扰动、模型不确定性、参数摄动PID只能被动地等误差出现再去纠正而且增益给大了容易震荡给小了又跟不上。我们把这类扰动统称为“总扰动”PID对总扰动的抵抗能力其实很有限。ADRC的思路是反过来的与其等误差出现不如主动去估计扰动然后把这个估计值直接补偿掉。韩京清先生当年提出自抗扰控制核心思想就是把“不知道的系统内部动态”和“外部的未知扰动”全部看作一个总扰动然后用扩张状态观测器把这个总扰动实时估计出来反馈到控制量里把它抵消掉。这样原本一个充满不确定性的复杂系统就被ADRC“压缩”成了一个简单的串联积分型系统再用一个很简单的控制律就能把它稳住。ADRC的标准结构包含三个部分跟踪微分器TD安排过渡过程既给出跟踪信号又给出它的微分信号解决“快速性”和“超调量”之间的矛盾。扩张状态观测器ESOADRC的心脏实时估计系统状态和总扰动。非线性状态误差反馈控制律NLSEF用非线性组合的方式生成控制量配合ESO的补偿实现对被控对象的有效控制。在Simulink里做ADRC仿真本质上就是把这三个模块一个个搭出来然后用信号线连成一个闭环。2. 核心模块原理与Simulink实现详解2.1 跟踪微分器TD不只是一个微分器很多初学者对TD的作用理解得很浅以为它就是用来求微分的。其实这是个误区。TD更重要的作用是安排过渡过程Transient Profile。你想啊如果参考输入是个阶跃信号直接从0跳到1你让系统去跟踪这个阶跃起始阶段误差很大控制器就会输出一个很大的控制量超调几乎是不可避免的。TD的解决办法是把阶跃信号“揉成”一条平滑的曲线让系统沿着这条曲线平滑地过渡到目标值。TD的离散化公式是这样的x1(k1) x1(k) h * x2(k) x2(k1) x2(k) h * fhan(x1(k)-v(k), x2(k), r, h0)这里的fhan是最速控制综合函数也就是韩京清先生提出的最速跟踪函数。它的作用是在约束条件下让x1以最快的速度跟上输入v同时又不能产生超调。r是快速因子r越大跟踪越快但过渡过程也就越“激进”h0是滤波因子适当大于仿真步长可以增强滤波效果抑制噪声。Simulink搭建思路TD的实现是最直观的。用两个积分器Integrator串联x1是跟踪信号x2是x1的微分。输入端按照离散公式写好fhan函数这个用MATLAB Function模块最方便也可以直接用Fcn模块写表达式但可读性会差很多。我自己一般用MATLAB Function写fhan代码就十几行清爽且不容易错。function [fh, x1_next, x2_next] fhan_step(x1, x2, v, r, h0, h) d r * h0^2; a0 h0 * x2; y x1 - v a0; a1 sqrt(d * (d 8*abs(y))); a2 a0 sign(y) * (a1 - d) / 2; sy sign(y d) - sign(y - d); a (a0 y - a2) * sy a2; sa sign(a d) - sign(a - d); fhan -r * (a/d - sign(a)) * sa - r * sign(a); x1_next x1 h * x2; x2_next x2 h * fhan; fh fhan; end实际调TD的时候r和h0的配合很讲究。r太大过渡过程太快DP微分峰值会很大r太小系统响应迟钝。一个经验做法是先定h0通常等于仿真步长的2~5倍再根据你期望的调节时间反推r。2.2 扩张状态观测器ESO系统的“透视镜”ESO是整个ADRC里最核心、也最不好调的部分。它的思想是把系统模型中的未知动态和外扰合在一起当作一个新的状态变量——“扩张状态”然后用观测器把它估计出来。对于一个二阶系统x1_dot x2 x2_dot f(x1, x2, w, t) b * u y x1扩张状态 x3 f(...)于是系统变成三阶ESO的离散递推公式为e(k) z1(k) - y(k) z1(k1) z1(k) h * (z2(k) - beta1 * e(k)) z2(k1) z2(k) h * (z3(k) - beta2 * fal(e(k), 0.5, delta) b0 * u(k)) z3(k1) z3(k) - h * beta3 * fal(e(k), 0.25, delta)fal是非线性函数在原点附近是线性段远离原点是非线性段目的是“小误差大增益、大误差小增益”。Simulink搭建思路ESO的搭建比TD稍微复杂一点因为涉及三个状态的递推和fal函数。同样推荐用MATLAB Function实现把三个递推式写在同一个函数里返回三个输出。function [z1, z2, z3] eso_update(z1, z2, z3, y, u, h, beta1, beta2, beta3, b0, alpha1, alpha2, delta) e z1 - y; fal1 fal(e, alpha1, delta); fal2 fal(e, alpha2, delta); z1 z1 h * (z2 - beta1 * e); z2 z2 h * (z3 - beta2 * fal1 b0 * u); z3 z3 - h * beta3 * fal2; end function f fal(e, alpha, delta) if abs(e) delta f e / delta^(1 - alpha); else f sign(e) * abs(e)^alpha; end end这里b0是控制增益的估计值也就是你对b的建模估计。**注意b0给错了ESO的扰动估计就会出现偏差。**这不是说要求你精确知道b那就不叫估计了但b0的量级得对。否则扰动补偿的方向是对的幅度却差很多控制性能会明显下降。2.3 非线性状态误差反馈控制律NLSEF有了TD给出的参考信号v1, v2有了ESO给出的状态估计z1, z2和扰动估计z3控制量的生成就很自然了e1 v1 - z1 e2 v2 - z2 u0 beta1 * fal(e1, alpha1, delta) beta2 * fal(e2, alpha2, delta) u u0 - z3 / b0仿真里这个模块很简单用几个Gain和Fcn模块就能搭出来甚至直接用一个MATLAB Function写也行。我更喜欢直接写函数因为后边要换成线性组合、或者加前馈改起来方便。需要强调的是u u0 - z3/b0这一步——扰动补偿。z3是ESO估计出来的总扰动我们直接把控制量里减去这部分相当于“以毒攻毒”把扰动抵消掉。这也是ADRC抗干扰能力的根本来源。3. 完整仿真搭建手把手实操3.1 被控对象的选择为了让示例有意义我用一个带非线性摩擦和外部扰动的二阶系统作为被控对象比如x1_dot x2 x2_dot -25*x1 - 2*x2 0.5*sin(3*t) 8*u这里-25*x1 - 2*x2是线性部分0.5*sin(3*t)是外部扰动8*u是控制输入。实际物体可能比这复杂得多但用它来验证ADRC足够了。在Simulink里被控对象可以直接用积分器加Gain搭也可以用传递函数甚至封装成S-Function。我建议直接用积分器搭因为后面想看状态x1、x2比较方便连线也直观。3.2 模型总体架构我搭模型喜欢分层主层保持干净每个模块单独一个子系统。整体结构是信号源阶跃Step或者更复杂的参考输入TD子系统输入参考v输出v1、v2ESO子系统输入被控对象输出y和控制量u输出z1、z2、z3NLSEF子系统输入v1、v2、z1、z2、z3输出控制量u被控对象子系统输入u输出y这其实就是标准ADRC的五块结构。信号流向是参考输入进TDTD的跟踪信号和ESO的状态估计做差得到误差进NLSEFNLSEF结合ESO的扰动补偿输出控制量控制被控对象被控对象的输出再反馈给ESO。需要注意的地方是代数环。如果把ESO里的控制量u直接取当前时刻的输出而ESO又直接连接被控对象的输入Simulink报代数环错误的概率非常高。解决办法是在被控对象的输入端加一个Memory或Unit Delay模块打断这个直接耦合。这个影响微乎其微但是对仿真稳定性帮助很大。3.3 参数初值与整定实操参数整定是ADRC仿真里最劝退新手的一关。我直接把我常用的整定顺序分享给你**第一步定仿真步长h。**这是基础。我一般用h0.0011ms。如果你做的是快速系统可能要h0.0001慢速系统可以h0.01但不管怎样h必须先定死后面所有参数都跟它有关。**第二步调TD。**先单独给TD一个阶跃输入把h0设为2*h~5*h然后调r观察x1的跟踪速度和x2的峰值。r从几百开始试不够再加直到你得到一个“平滑加速、平滑减速、无超调”的过渡过程。**第三步调ESO的beta参数。**这是最容易让人崩溃的一步。我的经验是先把beta1、beta2、beta3设为1、10、100这种量级然后看z1能否跟上yz3能否逼近真实扰动。如果z1滞后明显增大beta1如果z2抖动减小beta2如果z3收敛太慢增大beta3。记住这三个参数的量级通常是“倍率递增”的beta3往往是beta2的几十倍到上百倍。**第四步调NLSEF的beta1、beta2。**ESO稳定之后再把整个闭环跑起来。先给小的NLSEF增益比如beta11、beta22看系统稳不稳定。稳定了再逐步增大直到你得到满意的响应速度。这两个参数越大系统响应越快但过大会引起震荡。**第五步验证抗扰能力。**在仿真中段比如t3s时加一个突加扰动看ADRC能否快速把输出拉回设定值。如果恢复速度慢优先增大ESO的beta3如果恢复过程震荡减小NLSEF的beta2或者调大TD的r让过渡过程更平缓。我以前整理过一次参数初值参考表实测对大多数二阶对象都成立参数初值范围调整方向备注h0.0001~0.01固定不变越小越稳定但仿真慢r100~5000大则快、小则稳受限于执行器能力h02h~5h大则滤波强太大会导致跟踪滞后b00.5b~1.5b必须接近真实b这是ESO补偿的基准beta1100~1000大则跟踪快过大会放大噪声beta21000~10000大则速度估计快过大会抖动beta310000~100000大则扰动估计快过大会高频振荡NLSEF beta10.1~5大则响应快过大会超调NLSEF beta20.5~20大则阻尼强过大会震荡**再强调一遍b0一定要尽量接近真实b。**这一点怎么强调都不过分。ADRC号称不依赖精确模型但不代表b可以瞎给。b0代表你对控制增益的基本了解程度这属于“模型的最小先验知识”没有这个ESO的补偿方向甚至可能是反的。4. 仿真过程中的常见问题与排查技巧我在帮别人看ADRC仿真问题时遇到的典型问题翻来覆去就那么几个这里给你整理成速查表以后仿真不对了直接来对照。问题一仿真一开始就发散数值爆炸。原因90%是ESO参数太大或者b0给错方向了。先检查b0的符号和量级再检查beta1、beta2、beta3是否过大。有时候你把三个beta都除以10就能跑通然后再慢慢往上加。问题二输出跟踪不上参考信号。如果z1能跟上y说明ESO没问题问题在NLSEF增益不够把NLSEF的beta1、beta2调大。如果z1本身就滞后于y说明ESO的beta1、beta2不够大或者h太大导致观测延迟。问题三控制量高频抖振像锯齿一样。这是fal函数在零点附近切换造成的加上ESO高频增益放大噪声就会这样。解决办法增大delta让线性段范围更宽减小beta2、beta3在控制量输出后加一个一阶低通滤波Simulink里的Transfer Fcn极点设置在50~200rad/s但滤波器会引入相位延迟极点不能设太低。问题四ESO的z3完全估不准和实际扰动差很远。先确认你的扩张状态定义对不对。对二阶系统扰动是通过x2通道进入的z3估的就是x2_dot里面除去b0*u之外的所有东西。如果被控对象里面扰动是从其他通道进入的ESO的结构就得改。另外检查b0是否准确b0偏了z3的估计也会偏。问题五仿真速度极慢。ADRC里面非线性函数多MATLAB Function如果每个步长都调用仿真速度会变得很难看。可以试试把fal函数用查表Lookup Table替代或者用Embedded Coder把MATLAB Function转成C代码再仿真速度提升很明显。如果你的模型最终要跑实时系统这一步基本是必须的。问题六数字实现之后和仿真结果差距大。这是从仿真走到实物最经典的坑。原因主要是仿真里连续模块和离散模块混用导致步长行为不一致。解决方法是仿真阶段就把所有的积分器都用离散形式Forward Euler或Tustin并且固定步长这样生成的代码行为才和仿真一致。5. 从仿真到代码离散化必须注意的细节既然标题里提到了“含代码操作演示视频”这里再多说几句代码实现层面的东西。很多人模型搭得很顺利一到生成C代码就发现乱套核心原因是没有处理好离散化一致性的问题。常用的三种离散化方法Forward Euler前向欧拉最简单和连续仿真直接对应但增益高时容易不稳定。Backward Euler后向欧拉稳定性好一些但实现起来稍微麻烦一点。Tustin双线性变换精度高适合需要精确频率响应的场合比如把连续控制器转成离散控制器。ADRC的离散实现我在实践中更推荐在一开始写MATLAB Function的时候就按离散递推式写。就像我前面给的TD和ESO代码那样直接用x x h * f(x)的形式。这样在Simulink里仿真的时候是离散的生成C代码的时候不需要额外转换行为完全一致省掉很多麻烦。如果是用Simulink自带的连续积分器搭的模型再想转离散建议在求解器设置里选择Fixed-step discrete solver然后手动把所有Integrator换成Discrete-Time Integrator并把Sample time设成h。别偷懒用连续求解器去跑离散模型最后出来的代码行为会很诡异。6. 配套演示视频的使用建议这个项目附带的操作演示视频我建议你这样去用收获最大。先别看视频自己根据文章把TD搭出来单独给阶跃信号跑通观察x1、x2的波形。这一步如果不动手后面ESO一定会卡。然后搭ESO注意这时候先不要闭环直接把被控对象的输出y和输入u喂给ESO对比z1和y的波形是否一致对比z3和真实扰动——如果被控对象内部有明确扰动函数你可以从被控对象里拉一个信号出来对比。等TD和ESO都验证没问题了再看视频里闭环连接的部分通常是信号线的具体连法、子系统输入输出端口的设置这些细节。最后再对照视频里参数整定的过程看人家是怎么一点点调参数的。看参数整定那段的时候重点看别人调整参数之后波形是怎么变化的把这当作“参数与波形对应关系”的学习素材。这个比直接给你一组参数有用得多因为实际系统的参数几乎不可能一模一样你需要的不是一组数值而是“这个参数变了波形会怎么变”的手感。7. 我踩过的坑和最后几条心得聊点课本上看不到的东西。第一个坑b0给反了。一次做仿真系统始终发散怎么调beta都没用排查到半夜发现b0的符号写反了。这种低级错误你检查十遍都可能看不出来因为它藏在某个子系统的Gain模块里。我的习惯是所有关键参数b0、beta1~3、r全部定义到init脚本里模型里不写死数值这样检查参数的时候一目了然改起来也方便。第二个坑ESO参数和NLSEF参数互相打架。你把ESO的beta调大了z3抖动然后你把NLSEF的增益调大去压制结果整个系统高频振荡。正确的思路是ESO只负责“看”NLSEF只负责“控”。ESO让观测更准确NLSEF决定控制力度。两边职责要分开调每次只动一组参数。我见过太多人两个一起调最后都不知道问题出在哪。第三个坑过度依赖非线性组合。韩京清先生提出的是非线性ADRC但我在实际工程中试下来线性ADRCLADRC在很多场合效果也不差而且参数少得多、调参容易得多。LADRC就是把fal换成线性误差ESO变成线性扩张状态观测器LESONLSEF变成PD组合。如果你的应用场景不是极端追求性能我建议先做LADRC稳定可靠之后再考虑换成非线性版本。第四个坑仿真步长和实际采样周期不一致。仿真里h设0.001跑得飞起上了真机发现采样周期只能到0.005整个系统完全变了个样子。所以从第一天起就要想清楚你的控制器最终跑在什么平台上、采样周期大概是多少。按实际的采样周期做仿真比做出来再改要省心得多。最后分享一个我自己的习惯每次做ADRC仿真我都会同时把输出y、跟踪信号v1、ESO估计z1、扰动估计z3、控制量u这五个信号全部记录到Scope里用Scope的多端口显示模式一屏看全。这样做的好处是系统出问题的时候你能一眼看出是哪个环节不对——是跟踪慢了TD问题还是观测滞后ESO问题还是控制量饱和NLSEF或执行器问题。别省这一步调试效率差好几倍。ADRC不难难的是把每个模块的职责搞清楚并且愿意花时间一点点调试。照着这篇文章的步骤走一遍你也会发现它不过如此。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门