自抗扰控制ADRC二阶ESO公式推导与Simulink仿真实现 简介面向自抗扰控制与扩展状态观测器二阶系统仿真这套 MATLAB/Simulink 源码包特别适合正在学习 ADRC 理论、希望快速搭建 ESO 仿真模型的控制类专业学生与工程师也可用于课程设计、毕业设计或工程预研。资源聚焦 ADRC 中 ESO 公式的工程实现共 9 个文件包含 6 个 M 脚本/函数和 3 个 Simulink 模型文件mdl、slxM 文件覆盖观测器构建、参数整定与频域分析压缩包仅 58KB便于下载与快速上手。已有 1277 人浏览学习。代码中既提供 LESO、NESO 两种观测器的 M 函数也包含用于参数整定和频域分析的脚本配合 Simulink 模型可直接观察二阶系统在 ADRC 控制下的响应并通过 tuning 脚本灵活调整控制器参数。通过实际运行与调整可理解广义扰动实时估计与补偿的完整链路为后续开展复杂被控对象的自抗扰控制设计提供便捷起点和排错参考。1. 为什么ADRC绕着ESO转而不是绕着PID转自抗扰控制ADRC的核心不在控制律而在扩张状态观测器ESO。电机转速环在负载突变后开始振荡Simulink里对好参数的PID模型拿到现场就失效这类问题通常不是增益没调好而是模型和现实相差太多。ESO把模型偏差、参数误差和外部扰动合并成一个总扰动状态实时估计出来再由控制量当场抵消。标题里的“ADRC二阶”指被控对象按二阶结构处理位置环、速度环这类ESO公式因此由三个状态方程组成。这篇文章从ESO公式怎么从对象方程里长出来讲到Simulink里怎么搭、参数怎么整定适合已经玩过PID、想解决扰动抑制问题的工程师直接照做。2. ADRC回路里的ESO输入输出与二阶结构2.1 三个模块里ESO为什么不可省ADRC通常拆成跟踪微分器TD、扩张状态观测器ESO、控制律加扰动补偿三块。TD把阶跃给定揉成平滑的过渡信号ESO负责观测对象状态和总扰动控制律按观测误差算出基本控制量u0再把z3补回去。对大多数现场问题TD可以去掉参考信号直接进控制律系统照样工作响应还会更快一点。ESO却是不可省的。它同时承担三件事给出比测量值更干净的位置估计、给出速度估计、给出总扰动估计。没有ESO控制律拿不到z2和z3扰动补偿也就不存在ADRC退化成一种普通的PD控制。所以标题里的“ADRC二阶”工程上等价于针对二阶对象设计一个三阶ESO再配一条PD路径。理解了这一点后面所有公式和模块连线都有明确指向。2.2 ESO的输入只有两个为什么却要知道b0ESO的输入是对象输入u和测量输出y不需要被控对象的传递函数也不需要模型内部状态。唯一用到的模型信息是b0也就是控制通道增益的粗略估计。b0的作用是让观测器知道“控制量u对状态x2′的贡献有多大”否则观测器无法把内部动态和外部扰动分离开来。这里有个常见误解总扰动里包含了(b-b0)u这一项。b0猜得不准这一项就被当成扰动的一部分由z3兜住所以不要求b0精确。但b0偏差过大时z3的数值会明显偏离真实外扰控制律合成u(u0-z3)/b0时会出现过补偿或欠补偿。这一点在第5章参数部分还会展开现在只需要记住ESO对模型依赖极低但b0是它唯一的“模型记忆”。2.3 二阶结构与一阶结构的ESO形态差异对一阶对象例如y′f(y,w,t)bu扩张状态只取两维z1≈yz2≈总扰动观测器是二阶的。对二阶对象y″f(y,y′,w,t)bu总扰动要再往后推一个状态观测器变成三阶。标题里的“ADRC二阶”指的就是这种三状态ESO而不是说ESO本身是二阶系统这是个容易混淆的点。对比项一阶对象二阶对象对象形式y′fbuy″fbuESO阶数23观测状态z1≈yz2≈总扰动z1≈yz2≈y′z3≈总扰动待定系数β1、β2β1、β2、β3判断对象按一阶还是二阶处理不是看传递函数分母最高次数而是看控制输入到被控输出的相对阶。机械位置环下挂速度环后通常可以降成二阶结构电流环在大多数伺服场合按一阶处理就够。把对象人为升阶也可以ESO会多一层状态观测噪声通路多一条参数也多一组实际收益很小。3. 二阶对象ESO公式从微分方程到离散递推3.1 被控对象的写法与总扰动定义假设被控对象是二阶的写成标准形式y″ f(y, y′, w, t) b·u其中f包含未建模动态和外部扰动wb是真实控制增益。工程上拿到的只是b的粗略估计b0把方程改写成y″ f (b - b0)·u b0·u定义总扰动d f (b - b0)·u。剩下的事情就是把d当作一个需要实时观测的额外状态而不是去精确建模f。这就是“扩张状态”的含义状态向量比被控对象本身多一维多出来的那一维是总扰动。设状态x1yx2y′x3d并令hd′则对象写成三阶状态方程x1′ x2x2′ x3 b0·ux3′ h这里不要求d连续可微h有界就够。h数值大意味着扰动变化剧烈观测误差的收敛上界会变大但ESO的结构不需要改。3.2 线性ESOLESO设计公式与β参数表对上述对象设计连续LESOz1′ z2 β1·(y - z1)z2′ z3 β2·(y - z1) b0·uz3′ β3·(y - z1)这就是标题里“ESO公式”最常见指代。β1、β2、β3是观测器增益工程上按带宽法配置β 系数配置公式观测误差极点β13ωo-ωoβ23ωo²-ωoβ3ωo³-ωo带宽法的好处是三个系数压缩成一个参数ωo观测误差动态的特征多项式变成(sωo)³极点全部落在-ωo处不存在超调振荡问题。ωo是观测带宽取值越大z3跟随总扰动越快但测量噪声经过β3ωo³放大也更凶所以ωo不是越大越好。配合的控制律是u0 ωc²·(v1 - z1) 2ωc·(v2 - z2)u (u0 - z3) / b0ωc是控制带宽决定PD部分的动态。v1和v2是参考信号及其导数没有TD时v1直接给阶跃v2设0即可。3.3 非线性ESO什么时候值得换韩京清方案的经典ESO在误差增益里套一个非线性函数fal(e, α, δ)当|e|≤δ时fale/δ^(1-α)否则fal|e|^α·sign(e)。优点是误差大时增益小、误差小时增益大理论上收敛更快缺点是α和δ没有系统的整定依据而且非线性项在误差过零附近会给数值积分和离散化带来额外负担。工程实现上除非要复现某套老曲线不建议一上来就用非线性ESO。标题既然同时带了ESO公式和Simulink先跑通LESO拿到基线再决定要不要加非线性项更实际。在Simulink里换非线性ESO只需要把β·e替换成fal(e, α, δ)其他连线不动改造代价很低。3.4 离散化采样周期怎么选欧拉法够不够Simulink连续模型可以直接用积分器搭连续ESO但一旦要生成代码或在实时机上跑必须离散化。最常见的做法是前向欧拉代码很短function z eso_euler_step(z, y, u, Ts, b0, wo) % z: 3x1列向量依次是z1、z2、z3 % y: 测量输出u: 控制量Ts: 采样周期 e y - z(1); % 观测误差 b1 3 * wo; % 带宽法配置的β1 b2 3 * wo^2; % 带宽法配置的β2 b3 wo^3; % 带宽法配置的β3 z(1) z(1) Ts * (z(2) b1 * e); z(2) z(2) Ts * (z(3) b2 * e b0 * u); z(3) z(3) Ts * (b3 * e); end代码里先用旧的z1算误差e再用e同时更新三个状态z(2)更新时用的z(2)和z(3)都是上一时刻的值这是标准前向欧拉格式。注意不要在z(1)更新后再拿新z1去算e那会引入一个步长的额外延迟。欧拉法的稳定性和精度要求采样周期满足ωo·Ts在0.1~0.3量级条件紧时改用中点欧拉或零阶保持离散。这个现象和锁相环里多二阶广义积分器SOGI离散化遇到的相位滞后是同一类问题连续域积分器换到离散域后频率响应会偏移校正块参数最好按离散化后的极点位置重新微调。4. 在Simulink里把ESO公式变成可跑的模块4.1 先定对象与接口用一个二阶传递函数做起点为了验证ESO公式先建一个最简单的二阶被控对象G(s)1/(s²3s2)。这个对象有阻尼、有惯性接近伺服位置环的简化模型而且稳态增益是0.5b0就取1附近。Simulink里用两个Integrator串联实现从Library Browser拖入两个Integrator第一个积分器输出是x1第二个输出是x2。在第二个积分器前加Sum把控制量u、反馈项-3x2、-2x1加起来。对象的测量输出y就是x1直接引出给ESO和控制律。给被控对象的输入输出留出明确端口输入是控制量u输出是y。后面接ESO和控制律时所有信号线都围绕这两个端口展开避免信号名混乱。4.2 用Integrator和Gain搭连续ESO的连线顺序连续LESO在Simulink里可以用三个Integrator级联结构和公式逐项对应。搭法如下拖入三个Integrator从上到下排列分别对应z1、z2、z3。每个Integrator前接一个Sum用于累加动态项。从y引一条线与z1做差得到ey-z1e分别乘β1、β2、β3。z1的Sum输入是z2β1·ez2的Sum输入是z3β2·eb0·uz3的Sum输入只有β3·e。模块路径分别是Simulink/Continuous/Integrator和Simulink/Math Operations/Gain、Sum。Gain块里直接填写数值先按ωo20算β160β21200β38000。这一步做完把z1、z2、z3引出到Scope或者To Workspace先单独给ESO一组u和y信号观察z1是否跟住y、z2是否跟住dy/dt、z3是否收敛到一个常数就能验证公式搭得对不对再往下接闭环。4.3 用MATLAB Function搭离散ESO状态怎么自持连续积分器直观但生成代码时不方便。离散ESO在Simulink里可以用MATLAB Function配合Memory块实现Memory块负责把上一时刻的z存住函数内部只做一步欧拉递推function z_new eso_discrete(z, y, u, p) % z: 来自Memory块的3x1列向量 % p: 基础工作区里的参数结构体含Ts、b0、wo e y - z(1); b1 3 * p.wo; b2 3 * p.wo^2; b3 p.wo^3; z_new zeros(3, 1); z_new(1) z(1) p.Ts * (z(2) b1 * e); z_new(2) z(2) p.Ts * (z(3) b2 * e p.b0 * u); z_new(3) z(3) p.Ts * (b3 * e); end基础工作区里先执行p.Ts1e-3; p.b01; p.wo20;MATLAB Function的输出z_new连回Memory块的输入Memory块输出再连回函数输入z形成一步延迟这就是离散状态自持的标准做法。注意Memory块的初值要设成zeros(3,1)否则仿真启动时z是空的函数会报维度错误。4.4 求解器设置和代数环处理连续模型用ode4固定步长步长1e-3或更小离散模型把求解器设成discretefixed-step避免出现连续积分器和离散信号混用时的类型转换警告。闭环里的信号链是u→对象→y→ESO→z1z2z3→控制器→u中间隔着对象积分器和Memory不存在同一时刻的瞬时直通所以不会产生代数环。如果加上了TD并且TD的输出v2直接参与控制律也要注意v2和u之间不能有纯Gain直通路径。Trasport Delay在这里没有用别用连续滞后块去“打断”代数环那只会把相位拖坏。5. 二阶ADRC参数整定ωo、ωc、b0谁先谁后5.1 三个参数的直观含义与起点值LADRC把整定参数压缩到三个b0、ωc、ωo。b0是控制通道增益的估计ωc决定闭环PD的动态ωo决定ESO的观测速度。很多人一上来就动ωo顺序反了系统怎么调都像“压住葫芦浮起瓢”。参数直观含义推荐起点调大效果调小效果b0控制通道增益估计对象稳态增益的数量级补偿量变弱总扰动残留偏大补偿过强容易振荡ωc控制带宽对象开环穿越频率的2~5倍响应快、超调大响应慢、相位裕度大ωo观测带宽3~5倍ωc扰动估计快、噪声放大严重观测延迟大、补偿滞后我一般按“b0先定数量级ωc卡穿越频率ωo从3倍ωc向上试”的顺序调。b0精度要求不高误差2倍以内z3都能兜住ωc定了系统对参考跟踪和扰动的整体响应速度就定了ωo只影响观测收敛和噪声折中不动前两个就动ωo往往会把噪声和观测延迟一起调乱。5.2 用阶跃和正弦扰动做一轮仿真对比在Simulink里给闭环加两组测试信号参考输入给Step扰动信号在对象输入端加一个求和点注入2sin(0.5t)1的复合扰动。用批量脚本扫三组ωo对比y和z3的波形% 需要先把模型存成 adrc_2nd_order.slx并在工作区设置 wo 和 wc clear; close all; woList [20, 30, 50]; for i 1:length(woList) wo woList(i); wc wo / 5; % 控制带宽先取观测带宽的五分之一 b0 1; % 对象G(s)1/(s^23s2)的通道增益约为1 simOut sim(adrc_2nd_order, StopTime, 5); y simOut.yout{1}.Values.Data; t simOut.yout{1}.Values.Time; figure(i); plot(t, y); grid on; xlabel(时间/s); ylabel(输出y); title([wo num2str(wo) , wc num2str(wc)]); end注意不同MATLAB版本里Simulink输出信号的取数接口略有差别有的用yout.get(y)有的用logsout先跑通一个再批量扫参数。三组对比看两点一是阶跃段上升时间和超调二是正弦扰动注入后y的波动幅度。ωo从20升到50扰动抑制会变强但y的高频毛刺也会增多这就是观测噪声的代价。5.3 峰值、噪声放大、b0失配三个典型问题峰值现象是ESO最常遇到的坑。仿真启动瞬间如果z1初值是0而对象输出y(0)明显非零观测误差e会是一个大阶跃z3被β3放大后出现一个很大的瞬时脉冲控制量u0会跟着冲一下。解决办法是z1积分器初值设成y(0)或者其他状态按稳态值预置让观测误差从零附近开始。噪声放大和二阶有源低通滤波器的高Q值行为类似带宽加大截止频率升高噪声和相位滞后同时上来。观测器对测量噪声的传递函数在高频段有ωo³量级的增益所以ωo加得越猛z3越“毛”。折中做法是给y先过一个一阶低通但低通带来的滞后又会被ESO当作扰动去补偿容易形成正反馈滤波截止频率要放在ωo的5倍以上。b0失配的表现为b0偏大时补偿不足z3里残留一部分真实控制通道动态阶跃响应末端出现缓慢收敛的小尾巴b0偏小时补偿过度同样幅值的u0会产生超额控制作用系统在临界点附近开始振荡。失配在2倍以内通常还能靠ωo兜回来超过5倍就重新辨识控制通道增益靠ESO硬扛不现实。在车辆动力学这类场景中把简单二阶传递函数换成carsim与Simulink联合仿真的整车模型后变化的主要是b0的取值β系数通常只需在相近量级内微调这正是ESO对模型依赖低的价值。6. ESO收敛性验证与工程化两个检查6.1 不依赖Simulink的ESO收敛性快速验证调试参数最烦的是模型报错半天找不到是观测器问题还是控制律问题。我习惯先写一段纯MATLAB脚本把真实系统也按同样步长离散化直接看z1、z2、z3对真实状态的跟踪误差Simulink都不开% 验证ESO能否在未知扰动下收敛 Ts 1e-3; N 5000; x [0; 0]; % 对象真实状态 x1、x2 z [0; 0; 0]; % ESO观测状态 z1、z2、z3 u 0; b0 1; wo 30; b [3*wo, 3*wo^2, wo^3]; err zeros(3, N); for k 1:N d 2*sin(0.5*k*Ts) 1; % 未知复合扰动 x(2) x(2) Ts * (d u); % 对象: x2 d u x(1) x(1) Ts * x(2); % 对象: x1 x2 e x(1) - z(1); % 观测误差 z(1) z(1) Ts * (z(2) b(1)*e); z(2) z(2) Ts * (z(3) b(2)*e b0*u); z(3) z(3) Ts * b(3)*e; err(:, k) [x(1)-z(1); x(2)-z(2); d-z(3)]; end plot((1:N)*Ts, err); legend(e1,e2,e3);这里ESO只知道y和u对真实的d函数形式一无所知但z3照样追出一条和2sin(0.5t)1趋势一致的曲线。误差曲线里e1和e2会先快速衰减到零附近e3的稳态幅度受hd′限幅扰动变化越快稳态误差越大这是ESO的理论边界。6.2 导出C代码前和外部模式调试时看什么模型要往实时硬件上搬先把连续求解器换成离散求解器确认模型里没有残留的连续积分器再检查所有ESO相关增益的数据类型是double而不是auto。C代码生成前跑一次模型级仿真把z1、z2、z3的初始瞬态记录下来这段瞬态在代码里同样会出现提前知道峰值幅度就不会在硬件上被吓一跳。外部模式External Mode接上目标机后重点看三条波形z1与实际y的偏差、z2与对象速度信号是否同步、z3在负载变化时是否有对应台阶。z1完全贴合、z2跟手、z3的波动规律与现场负载变化吻合就说明ESO工作正常如果z3一直在缓慢漂移优先检查b0数量级和y的测量噪声而不是继续加ωo。本文还有配套的精品资源点击获取