尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ADRC自抗扰控制Simulink仿真与调参实践:TD、ESO、NLSEF模块拆解

ADRC自抗扰控制Simulink仿真与调参实践:TD、ESO、NLSEF模块拆解 第一次看到ADRC那一堆公式的时候我一度怀疑自己是不是不适合做控制。韩京清先生提出的ADRC核心构成就是TD、ESO、NLSEF三个模块名字一个比一个抽象网上资料又大多是“从原理到证明”的学术写法初学者很容易卡在第二步就放弃。但后来我用MATLAB/Simulink把这三个模块一个个搭起来、跑通参数之后发现ADRC的调参逻辑其实比想象中清晰。它不是玄学只是需要先搞清楚三个模块各自在干什么、参数各自影响什么再按照一个固定顺序去调。这篇东西我就按自己实际调试的顺序写从模块拆解、Simulink搭建到完整参数表最后把仿真里踩过的坑一并列出来。适合正在做控制类毕设、刚接触ADRC的工程师或者想快速用Simulink验证一下这个控制器的同学。1. 先用一句话拆掉ADRC的心理门槛1.1 PID调不顺的问题ADRC到底改了什么先说个老生常谈的问题。PID不是不好而是误差直接驱动这件事本身有先天矛盾目标值一阶跃初始误差瞬间变得很大比例项为了快速响应会把控制量推得很猛超调就跟着来了。你想减小超调就得降低比例增益但响应又慢了。积分项能消稳态误差可它反应慢而且积分饱和在工程里特别烦人。更麻烦的是PID默认控制器面对的是一个固定模型一旦对象参数变化或者外部扰动进来原先调好的那组参数可能立刻失效。ADRC的思路完全不一样。它不跟误差较劲而是先把目标信号“处理”得平缓一点再把系统内部的不确定性、外部扰动统统当成一个“总扰动”给估计出来最后在控制量里主动把它们抵消掉。整个控制结构可以看作三个分工明确的模块TD负责给目标信号安排过渡过程同时把信号和微分提取出来ESO负责盯着系统输出把状态和“总扰动”一起观测出来NLSEF负责把跟踪误差组合成控制量再把扰动补偿进去。这三块拼在一起就构成了完整的ADRC。很多初学者一上来就去啃非线性函数的数学证明其实完全没必要。先用Simulink把回路跑通再回过头看公式会顺得多。1.2 TD、ESO、NLSEF三个缩写分别管什么为了好记我喜欢打个比方控制就像开车去一个目的地。TD是导航里的“路线规划器”它不让车速瞬间拉满而是根据当前路况给出一条平滑的速度曲线。它输入一个阶跃目标输出一条不突变的跟踪轨迹和对应的“速度”信号。ESO是副驾驶它不掌握真实路况但通过对比车辆实际表现和模型预期能估算出当前风阻、坡度、路面摩擦这些“干扰”到底有多大然后实时报告给你。NLSEF是你踩油门和打方向的手脚它把导航目标、车辆当前状态、副驾驶报上来的干扰综合在一起输出一个最终的控制动作。这样一拆ADRC的调参就变成了三件独立的事把导航调平顺把副驾驶调准把手脚调协调。只要逐个解决整体控制效果自然就出来了。下面我按这个顺序把每个模块的公式、参数和Simulink实现拆开讲。2. 三个核心模块逐个拆解公式和参数不再劝退2.1 TD跟踪微分器先给信号穿一件“平滑衣”TD最直观的作用是把一个阶跃信号变成一条平滑的过渡曲线并且顺便给出它的“速度”。为什么要这样做因为真实物理系统里面的执行器、机械结构都有惯性你直接给它一个阶跃电压它容易冲过头但如果目标信号是从0平缓爬到1的系统就能比较从容地跟上超调自然会小。离散化之后我习惯直接在MATLAB Function里写这样的TDfunction [v1, v2] TD(v0, r, h) persistent x1 x2 if isempty(x1) x1 0; x2 0; end e x1 - v0; % 最速控制综合函数 fhan d r * h; d0 h * d; y e h * x2; a0 sqrt(d * d 8 * r * abs(y)); if abs(y) d0 a x2 y / h; else a x2 0.5 * (a0 - d) * sign(y); end if abs(a) d fh -r * a / d; else fh -r * sign(a); end x1 x1 h * x2; x2 x2 h * fh; v1 x1; v2 x2; end这里r是快速因子决定过渡过程快慢。r越大v1跟踪目标越快但微分信号v2的噪声也会被放大。h是采样步长必须和Simulink里设置的求解器步长一致。实际使用时我还习惯在TD内部用一个比h稍大的滤波步长h0来抑制微分噪声常见取法是h0 2*h ~ 10*h这样既能保留过渡过程又不会让v2毛刺太多。初调的时候建议先把TD单独拿出来看。给一个阶跃输入观察v1是否光滑地爬到目标值观察v2是否像一个“速度曲线”。如果v1有明显超调说明r偏大如果响应太拖沓说明r偏小。这个模块调好了后面两个模块才有好的输入信号可用。2.2 ESO扩张状态观测器全场最重要的观测员ESO是整个ADRC的灵魂。它的任务是把系统的状态和“总扰动”一起估出来。这里的“总扰动”是个广义概念既包含外部干扰也包含模型参数不准、未建模动态等内部不确定性。对于常见的二阶对象x1_dot x2 x2_dot f(x1, x2, w, t) b0 * u其中f就是总扰动b0是控制增益的估计值。ESO把f扩张成第三个状态z3通过输出y的反馈不断修正估计。离散化之后我常用的代码是这样的function [z1, z2, z3] ESO(y, u, h, b0, beta01, beta02, beta03, delta) persistent z1 z2 z3 if isempty(z1) z1 0; z2 0; z3 0; end e z1 - y; z1 z1 h * (z2 - beta01 * e); z2 z2 h * (z3 - beta02 * fal(e, 0.5, delta) b0 * u); z3 z3 h * (-beta03 * fal(e, 0.25, delta)); end function f fal(e, alpha, delta) if abs(e) delta f e / (delta^(1 - alpha)); else f abs(e)^alpha * sign(e); end end这里的fal是一个非线性函数在误差小时近似线性误差大时保持非线性特性作用是让ESO在误差较小时也能有较好的估计精度同时又不会因为误差太大而发飙。参数alpha一般取0.5和0.25delta取0.01左右这两个值不需要频繁改动。真正需要花心思的是beta01、beta02、beta03这三个观测器增益。我建议不要手拍直接用“带宽法”起步。把观测器期望带宽记为wo则beta01 3 * wo beta02 3 * wo^2 beta03 wo^3先给wo一个20左右的值这样beta0160、beta021200、beta038000。跑起来之后如果ESO跟踪输出慢就提高wo如果出现高频振荡就降低wo。wo越大ESO响应越快但对噪声越敏感而且仿真步长不够小时很容易数值发散这点后面还会展开说。2.3 NLSEF非线性状态误差反馈把误差按非线性捏成控制量TD给出了目标信号v1和微分v2ESO给出了状态估计z1、z2和扰动估计z3。NLSEF要做的是把这些信号组合成一个控制量。我常用的离散形式是这样的function u NLSEF(v1, v2, z1, z2, z3, b0, beta1, beta2, alpha1, alpha2, delta, u_max) e1 v1 - z1; e2 v2 - z2; u0 beta1 * fal(e1, alpha1, delta) beta2 * fal(e2, alpha2, delta); u (u0 - z3) / b0; if abs(u) u_max u sign(u) * u_max; end ende1是位置误差e2是速度误差。beta1相当于比例增益负责“推一把”beta2相当于阻尼负责“拉住它”。alpha1取0.5左右alpha2取1.5左右delta同样取0.01。控制量最后由(u0 - z3) / b0给出这里减掉z3就是把ESO估计出来的总扰动主动补偿掉也是ADRC叫“自抗扰”的原因它不是被动等扰动影响输出而是先把扰动估出来怼回去。注意u_max必须根据执行器能力设置。如果不限幅扰动估计阶段z3稍微抖一下控制量就可能冲到天上去仿真直接崩掉。我在实际调试中限幅这一行从来没省略过。3. MATLAB/Simulink实操搭一套完整的ADRC并跑通3.1 被控对象与仿真模型框架为了演示我选一个典型的二阶对象G(s) 133 / (s^2 25s)对应状态方程可以写成x1_dot x2 x2_dot -25 * x2 133 * u d(t)其中d(t)是外部扰动仿真时我习惯叠加一个正弦扰动sin(10t)或者阶跃扰动。这个对象在实际里很像一个电机速度环或者简单机械系统参数不强求精确主要用来验证ADRC的鲁棒性。Simulink模型框架不复杂核心是四条信号线目标值进TDTD输出和ESO输出进NLSEFNLSEF出控制量给被控对象被控对象输出再回给ESO。我建议在Simulink里用MATLAB Function模块分别封装TD、ESO、NLSEF而不是用一堆积分器和加法器手动搭因为代码方式改参数更直观也方便以后移植到嵌入式平台。被控对象本身可以用传递函数模块也可以直接用积分器搭给dx2加一个常值增益模拟-25*x2加一个133*u输入外面再加一个“扰动注入”的加法器这样方便观察ESO对扰动的估计。仿真求解器我强烈建议设置成固定步长步长0.001秒离散求解器或者ode4都行。ADRC的TD和ESO本质上是离散迭代算法如果Simulink用变步长MATLAB Function被调用的间隔不稳定persistent变量里的h就和实际采样间隔对不上参数再对也容易出问题。3.2 TD和ESO模块的MATLAB Function实现打开Simulink新建一个模型按下面的步骤操作从Simulink库拖入三个MATLAB Function模块分别命名为TD、ESO、NLSEF。双击TD模块把上面2.1节的代码粘进去。需要注意MATLAB Function模块的输入输出端口要和函数签名一一对应。TD模块的输入是v0、r、h输出是v1、v2。r和h可以直接在模型里用常量模块给定也可以在MATLAB Function内写成局部常量但为了调参方便我建议把r、h、b0这些核心参数全部从模型外部接进去这样用Simulink的Signal Editor或者直接在WorkSpace里改参数都能实时生效。ESO模块同样。输入端口我习惯按照y、u、h、b0、beta01、beta02、beta03、delta的顺序接。注意u这里必须接限幅之后、真正送入被控对象的那个控制量而不是NLSEF计算出来的原始值。这个细节非常关键如果接错了ESO估计的扰动会偏大严重的时候整个回路会振荡。TD和ESO里的persistent变量初始值建议设成0。如果被控对象初始状态不是0ESO会有一段收敛过程这是正常的。想要起始阶段更平顺可以把z1的初始值设成对象输出的初始值。3.3 NLSEF与整体回路连接NLSEF模块的输入是v1、v2、z1、z2、z3、b0、beta1、beta2、alpha1、alpha2、delta、u_max输出是u。接线顺序建议按照信号流向从左到右排列方便阅读。整个模型连接完成后还要加一个饱和模块。我建议在NLSEF内部用代码限幅但同时在Simulink里再加一道Saturation保险这样即使NLSEF代码改逻辑也不会真的把控制量送到执行器范围之外。给被控对象加扰动时注意把扰动信号和对象内部累加的地方接好。我想检查ESO的扰动估计能力一般会在0.5秒时加一个幅值为1的阶跃扰动然后在示波器里同时看z3和实际扰动。如果ESO正常z3应该在大约0.1~0.3秒内追到扰动附近而且曲线平稳。3.4 完整参数表可以直接抄的第一组参数下面给出针对上述对象的第一组可运行参数。这个表可以直接抄进Simulink跑通之后再根据你的实际对象微调。模块参数推荐初值初始调整思路TDr200响应太慢加大超调/噪声大减小TDh0.001与Simulink固定步长一致TDh00.01抑制微分噪声可调大但不要超过过渡过程尺度ESOb0120由对象增益粗略定实际133故意留一点模型失配让ESO补偿ESObeta0160对应wo20响应慢可提高ESObeta021200对应wo20响应慢可提高ESObeta038000对应wo20注意过大会振荡ESOdelta0.01一般不动太小容易抖太大会损失精度NLSEFbeta110响应慢加大振荡减小NLSEFbeta25阻尼作用振荡加大NLSEFalpha10.5一般不动NLSEFalpha21.5一般不动NLSEFdelta0.01一般不动NLSEFu_max10按执行器限幅设这套参数跑出来的典型指标大致是阶跃响应上升时间0.3秒出头无超调或者只有轻微超调加入阶跃扰动后输出波动能在0.2秒内恢复。如果你希望响应更快可以尝试把r提高到400、wo提高到40对应beta01120、beta024800、beta0364000并把beta1提高到20。但要注意步长0.001秒在高带宽下可能不够稳遇到振荡先把步长降到0.0005秒试试。4. 调参顺序、踩坑记录和问题速查表4.1 我的推荐调参顺序TD - ESO - NLSEF无数次仿真之后我总结出一个固定调参顺序这个顺序能避免90%的“调不出来”。第一步只调TD。把NLSEF断开让TD输出直接接示波器给一个阶跃输入。观察v1是不是平滑上升、v2是不是光滑。先不用管上升时间多快只要不超调、不抖r就基本合格。如果r太大v1会冲过头这时候调小如果v2毛刺很多把h0调大。第二步调ESO。把TD的输出撤掉或者直接给控制器一个很小的常值控制量让被控对象开环运行。在Simulink里观察ESO的z1是否紧紧贴住对象输出y再看z3是否能估出外加扰动。如果z1跟不上提高wo如果z3振荡发散降低wo或减小仿真步长。这个阶段不要管控制效果只看观测器跟得准不准。第三步闭合回路调NLSEF。先把beta1和beta2都设得很小比如beta12、beta21保证回路稳定不炸然后逐步加大beta1提高响应速度出现振荡后适当加大beta2压住。一次只动一个参数每动一次看一次波形这比同时改三个参数然后盲目试要高效得多。4.2 仿真现场最常见的5个问题我把自己还有身边人跑ADRC时踩过的坑整理成了一张速查表按“问题现象 - 可能原因 - 处理方向”的顺序给出来排查的时候直接对照。问题现象可能原因处理方向仿真直接发散变量跑到10的几十次方步长过大、ESO带宽太高、b0与真实增益差太多先确认固定步长0.001把wo降到20以下把b0调到接近实际模型增益闭环出现持续高频振铃采样步长不够小、beta1过大、delta太小步长降到0.0005降低beta1delta从0.005试到0.05阶跃响应慢但加大beta1后一上来就振TD的r太小导致误差长期偏大反馈一味加大会触发非线性段先加大r缩短过渡过程再小幅增加beta1存在明显的稳态误差比如目标1实际只有0.98ESO补偿不干净或控制量进入饱和检查ESO的u是不是用了限幅后的值确认b0符号和数量级查看控制量是否提前顶到u_max加入扰动后输出波动很大且恢复慢ESO带宽不够z3收敛慢提高wo同时检查z3波形是否被噪声淹没必要时把delta稍微调大这里特别想强调一下b0的问题。很多初学者把b0理解成模型参数非要精确定义成133。实际上ADRC的鲁棒性恰恰体现在b0不准也能工作因为偏差会算进总扰动里被ESO补偿。但b0不能错一个数量级。如果实际增益是133你填了13ESO会严重高估控制量对应的加速度z3会被强行拉偏整个回路很容易崩。我调试时习惯先用模型粗算一下b0然后把参数表里的120和133都试一遍观察哪个更稳再在这个范围附近微调。4.3 几个不太会写进论文的排错细节除了参数Simulink里还有一些“看起来不是问题的问题”我第一次排查时花了不少时间。第一个是代数环。如果ESO的u接的是NLSEF输出而被控对象是连续模块有时Simulink会因为信号流关系报代数环报错信息很吓人。解决办法很简单在NLSEF输出到ESO输入之间加一个Memory模块或者把ESO作为离散模块并设置采样时间用离散采样打破连续直通。加了之后不影响控制效果但能消除代数环。第二个是MATLAB Function模块的采样时间设置。默认情况下MATLAB Function可能会被当作连续模块来处理但如果里面用了persistent和h递推必须显式设置采样时间为0.001。我通常在每个MATLAB Function模块的参数设置里把采样时间填成跟固定步长一样的值。这个细节不做到位有时候模型也能跑但结果每次都不一样特别容易产生“薛定谔的仿真结果”。第三个是对ESO的z3不要抱太完美的预期。z3估计的是总扰动但如果扰动是突变阶跃z3的收敛总是需要时间的不可能瞬间追上。只要z3能在被控对象输出明显变化之前给出大致趋势ESO就是合格的。想让z3追得更快只能提高wo而wo提高会放大噪声这不是一个可以无限调大的参数。实际工程里我在做系统设计时通常先定执行器和传感器采样周期再反推ESO带宽能设计到多少而不是一上来就把带宽拉满。5. 写在最后一些个人习惯和提醒5.1 我最常用的一组调试习惯做ADRC仿真这么多次我自己最依赖的一个习惯是先把ESO单独“钓”出来看曲线不急着闭环。具体操作是把NLSEF的输出旁路掉给被控对象一个手动控制量或者干脆让控制量为0然后在示波器里同时放y、z1、z3。看到z1贴合y、z3能跟踪扰动我再闭环保准没问题。ESO看得准ADRC就成功了一大半ESO看不准后面NLSEF参数怎么调都白搭。第二个习惯是参数一次只动一个。听起来像废话但实际操作时因为Simulink改参数太方便人特别容易同时动r、wo、beta1结果问题出在哪都不知道。每次改完参数记录一下改前改后的波形这个习惯在复杂对象上能省出好几倍的时间。第三个习惯是用脚本批量扫参。把r、wo、beta1这些参数定义成MATLAB工作区变量然后用for循环配合sim命令跑多次仿真最后把阶跃响应的超调量、上升时间、稳态误差汇总成表格挑选。这样虽然粗暴但比一个人盯着示波器猜要快得多。Simulink还支持parsim并行跑多个参数组合同时仿真几分钟就能扫完一组初值范围。5.2 一个小工具建议最后再分享一个实用小技巧不管你最后要不要做实物我都建议在Simulink里把ESO的z3和NLSEF的u同时接进示波器控制量饱和标志也拉出来。这两个信号能直接告诉你系统是不是已经被推到了边界。很多时候ADRC参数看起来不错但控制量一直在饱和边界上反复横跳这种情况上实物大概率会出问题。提前看到这一点比在硬件上发现问题再去调要省太多时间。ADRC的调参没有想象中那么神秘本质还是“一个模块一个模块看曲线、改参数、比效果”。把TD当成给信号整形把ESO当成一个观测仪把NLSEF当成最后的反馈增益组合整个过程就顺了。希望这篇实操分享能让你在Simulink里少走几步弯路早日调出满意的曲线。
返回列表