从传统PID到自抗扰控制:ADRC仿真与参数整定实战
简介传统PID控制依赖误差反馈在面对强扰动、参数摄动和非线性对象时往往难以兼顾快速性与稳定性。这份资源以自抗扰控制ADRC为核心配套跟踪微分器TD与扩张状态观测器ESO整理了一套可在Matlab/Simulink中直接运行的算法源码与仿真模型适合自动化、机器人、航空航天等领域的研究生和工程师用于控制算法的学习、对比与二次开发。压缩包共18个文件其中11个m脚本覆盖ADRC、LADRC、PID控制器以及差分进化、Rosenbrock等辅助函数2个slx文件分别给出伺服关节和永磁同步电机的仿真场景另有README、备份文件等整体仅68KB轻量易用。目前已有92人学习该资源。通过阅读源码和运行模型可以直观理解ESO如何估计总扰动、TD如何对噪声信号求取高质量微分以及ADRC如何将扰动补偿融入控制律在此基础上替换被控对象、调整观测器带宽与控制增益即可验证算法在参数摄动、外部阶跃干扰等工况下的鲁棒性是一条快速掌握先进PID控制原理并走向实际应用的便捷路径。1. 先进PID控制算法从传统PID到自抗扰控制的落地实践传统PID控制器在工业现场跑了这么多年结构简单、参数直观但它有个绕不过去的坎——面对强扰动和非线性对象时微分项对噪声极其敏感积分项又容易引发超调和振荡。我最早在调试一个伺服电机位置环的时候PID参数调了整整两周最后发现是负载突变导致的扰动估计不到位传统PID根本补偿不过来。那段时间我开始系统地研究自抗扰控制ADRC、跟踪微分器TD和扩张状态观测器ESO这套东西发现它们并不是什么高不可攀的理论而是能真正替换PID、在Simulink里跑起来、在嵌入式里部署的实用方法。这次拿到的这套资源包含完整的MATLAB脚本和两个Simulink仿真模型适合做控制算法验证的工程师、研究生以及对ADRC感兴趣但不知道怎么入手的开发者。这篇笔记从理论到代码再到参数整定的坑一次说清楚。2. ADRC的控制思想为什么要把扰动“估计”出来再补偿2.1 传统PID的结构局限与控制对象的“总扰动”概念传统PID的反馈量只有误差本身、误差的积分和误差的微分。从频域角度看PID的积分项是低频补偿微分项试图预测趋势但对于一个二阶对象或者带有未建模动态的系统PID能利用的信息太少了。比如一个永磁同步电机调速系统负载转矩突变、定子电阻温漂、反电动势谐波这些都是扰动它们叠加在系统方程里PID只能通过积分慢慢消效果差且滞后。ADRC的核心做法是把“内部不确定性外部扰动”统一看作一个总扰动项想办法在线把它估出来然后在控制器里反向补偿。这样做的好处很明显补偿完之后原对象在控制器眼里就变成了一个接近线性的串联积分器结构剩下的控制问题就简单了。对于一套被控对象模型已知但参数不精确的系统ADRC的这种“先估后补”策略比PID死磕增益要实用得多。2.2 ADRC的控制律结构误差反馈与扰动补偿的前馈通道一个完整的ADRC控制器由三部分组成跟踪微分器TD安排过渡过程、扩张状态观测器ESO估计状态和总扰动、误差反馈控制律通常用PD形式加上扰动补偿项。控制律的数学形式是这样的定义跟踪值v1跟踪输入信号vv2跟踪v的微分定义系统输出yESO给出状态估计z1、z2以及扰动估计z3误差e1 z1 - v1e2 z2 - v2控制量u kpe1 kde2 - z3/b0。最后一个负的z3/b0就是扰动补偿项。b0是被控对象控制增益的估计值。如果ESO估得准那么z3就约等于真实总扰动这一项就直接把扰动抵消了。显然这个方法的成败完全取决于ESO的估计精度。2.3 资源文件里的ADRC.m与LADRC.m的对比这套资源里有两份核心的控制器实现ADRC.m是非线性ADRC实现LADRC.m是线性ADRC实现。非线性ADRC的ESO使用fal函数对扰动有更强的适应性但参数多调起来费劲。线性ADRC的ESO用线性误差项参数少工程上更容易落地。我在调试PMS_Generator.slx模型的时候就体会到了两者差异LADRC的带宽参数可以直接从观测器带宽和控制带宽两个方向去调ADRC的非线性参数则更像玄学。下面是LADRC.m的核心实现逻辑function [u, z1, z2, z3] LADRC_step(y, yd, h, b0, wc, wo, T) % LADRC_step 线性ADRC一步计算 % 输入: y-系统输出 yd-期望参考 h-积分步长 % b0-控制增益估计 wc-控制器带宽 wo-观测器带宽 T-采样周期 % 输出: u-控制量 z1,z2,z3-扩张状态观测器状态 persistent Z; if isempty(Z) Z zeros(3, 1); % 状态初始化 end % 扩张状态观测器增益设计利用带宽法 beta1 3 * wo; beta2 3 * wo^2; beta3 wo^3; % ESO误差 e Z(1) - y; % 观测器状态更新 Z Z T * [Z(2) - beta1*e; Z(3) - beta2*e b0*u_prev; -beta3*e]; % 控制律PD反馈 扰动补偿 u_comp Z(3) / b0; u wc^2*(yd - Z(1)) 2*wc*(0 - Z(2)); u (u - u_comp); % 注意这里的补偿方式 % 保存上一次控制量供观测器迭代使用 u_prev u; end这里的关键点在于观测器增益beta1-beta3是由观测器带宽wo唯一确定的。带宽越大观测器收敛越快但对噪声也越敏感。控制器带宽wc决定闭环响应的快慢太大容易造成执行器饱和。实际调试中我会先固定wc然后把wo从1倍wc往上加直到输出出现明显噪声振荡再退回一点。3. 跟踪微分器TD如何解决微分信号的噪声放大问题3.1 传统微分器为什么不适合工程使用教科书里的微分运算在工程里基本没法直接用。差分法对高频噪声的放大倍数和频率成正比传感器信号里稍微有点毛刺微分输出就飙得到处都是。误差信号的导数在PID控制器里如果用理想微分系统会产生剧烈振荡这也是很多工程师把微分项直接关掉的原因。某一次我调试一个电液伺服系统位移传感器是模拟量输出噪声幅度也就几个毫伏但用差分求速度速度信号完全没法看。跟踪微分器解决了这个问题。它的思路是构造一个二阶系统让它的输出快速跟踪输入信号而输出的导数就是输入信号的微分但因为是经过积分链得到的噪声被系统本身过滤掉了。TD本质上是一个信号处理环节不参与控制律但它的存在直接改善了微分信号的质量。3.2 TD_controller.m的离散化实现与参数选择资源里的TD_controller.m用的是最经典的最速控制综合函数fhan实现离散化公式是每一步计算一个快速最优控制量。这个fhan函数的优点是过渡过程快且没有超调缺点是参数r决定跟踪速度太大会引入振荡太小会滞后。下面是TD的核心代码function [x1, x2] TD_step(v, x1, x2, r, h) % TD_step 跟踪微分器离散一步 % 输入: v-目标输入 x1,x2-当前跟踪值与导数 r-速度因子 h-步长 % 输出: x1,x2-更新后的跟踪值与导数 % fhan函数的核心参数计算 delta h * r; % 时间尺度参数 y x1 - v h * x2; % 根据距离决定控制量实现最快跟踪 a0 sqrt(delta^2 8*r*abs(y)); if abs(y) delta^2 a x2 y/h; else a x2 0.5*(a0-delta)*sign(y); end if abs(a) delta u_td -r * a/delta; else u_td -r * sign(a); end % 状态更新 x1 x1 h * x2; x2 x2 h * u_td; end这个实现里面r是关键参数。r越大跟踪越快但对噪声的滤波效果越差。h是仿真步长或者采样周期在实物上就是控制器任务周期。还有一个值得注意的地方这里的x2输出就是经过滤波后的微分信号可以直接替代PID控制器里的微分项。相比传统差分这个微分信号在小信号下依然平稳我在阶跃响应实验里看过微分信号的毛刺幅值缩小了一个数量级以上。3.3 tracer_filter.m的实际使用场景tracer_filter.m这个文件名字起得比较直白就是跟踪滤波器的意思。它在实际中经常被拿来做信号预处理对给定信号做平滑跟踪顺便输出一阶导数。比如说机器人的关节角度规划曲线往往是由梯形速度规划生成的曲线本身有拐点直接用角度信号做微分去控制速度环会产生振荡用TD做过渡分解之后速度前馈信号变得平滑系统跟踪精度反而上去了。Sil、仿真资源里还有一个Servo_Joint.slx模型我看了一下它的内部结构正好就是TD生成参考轨迹、ESO估计扰动、PD误差反馈的标准ADRC结构。如果在实物调试中测不到速度信号TD的这个微分输出也可以作为观测器的输入替代方案这在无速度传感器的伺服系统里非常常见。4. 扩张状态观测器ESO与仿真验证扰动估计的核心环节4.1 ESO的物理意义与收敛条件扩张状态观测器是ADRC最核心的模块。它把原系统的状态扩展一维把系统的总扰动当作这个扩展状态然后通过观测器实时重构出来。一个二阶系统的ESO结构是这样的z1跟踪系统输出yz2跟踪输出的一阶导数z3跟踪总扰动f。ESO的收敛性取决于两个条件一是观测器带宽需要远高于扰动频率二是控制增益b0的估计不能偏差太大。b0偏差过大会导致扰动估计值偏移这在实际中是常见问题。某次我建模一个直流电机时把b0标称值估错了30%ESO估计出的扰动总是有偏差控制量的补偿就不到位。后来我把b0改成在线辨识的值效果才正常。4.2 非线性ESO与线性ESO的实现差异非线性ESO在ADRC.m里的实现使用了fal函数这个非线性函数的形状决定了ESO在误差大时增益低、误差小时增益高理论上能做到快速收敛和小噪声放大的平衡。但fal函数里的alpha和delta参数比较难调alpha太小容易抖动delta太大就退化成线性了。线性ESO的好处是参数整定有规律可循带宽法在LADRC里是标准做法。实际仿真中我对比了非线性ESO和线性ESO在同一个PMS_Generator.slx模型下的表现。在负载转矩突加的情况下非线性ESO的扰动估计波形上升沿更陡但伴随着轻微振荡线性ESO虽然慢了一拍但波形平滑得多。对于工程应用线性ESO往往够了而且调参效率高。4.3 用Rosenbrock.m做基准测试的可行方法资源里还有Rosenbrock.m这个文件它是求Rosenbrock函数最小值的优化测试程序很多人会好奇它为什么会出现在PID算法包里。常见做法是用它配合差分进化算法Differentail_Evolution.m来做ADRC参数的自动寻优。ADRC参数空间高维且存在耦合人工调参很难逼近最优群体智能算法反而适合。把ADRC的闭环误差积分作为适应度函数然后让差分进化去搜索TD的r、ESO的wo和PD的kp、kd算是一种可行方案。下面是用差分进化整定ADRC参数的核心流程% 参数范围定义速度因子r, 观测器带宽wo, 控制器带宽wc lb [10, 10, 5]; % 下限 ub [500, 200, 100]; % 上限 % Differential_Evolution.m 内部的主要循环简写 for gen 1:max_gen for i 1:NP % 变异操作从种群中随机选取三个个体 if rand CR trial X(r1,:) F * (X(r2,:) - X(r3,:)); else trial X(i,:); end % 边界吸收处理 trial max(min(trial, ub), lb); % 适应度计算调用ADRC仿真函数返回ITAE指标 fitness ADRC_sim_ITAE(trial); if fitness J(i) X(i,:) trial; J(i) fitness; end end end这个整定方法比较吃计算资源因为每次评估都要跑一次仿真但它是全自动的。还有一个更简单的替代方案直接看仿真曲线调慢ESO的wo微调b0这种方式虽然快点但不一定收敛到全局最优。5. 参数整定避坑指南这些坑让我花掉不少周末时间5.1 现象一ESO把控制量“吃掉”系统输出发散打开PMS_Generator.slx模型把wo设置成和wc一样大跑仿真大概率会出现输出发散。原因在于ESO带宽不够时z3无法跟上真实扰动补偿方向出错。解决方法是让wo至少大于3倍wc我通常按5倍起步。但这也不是越大越好wo过大会引入传感器噪声表现为控制量高频抖动。5.2 现象二b0参数偏差导致补偿延迟把LADRC里的b0设置为真值的一半仿真看起来响应变慢了但相位裕度下降得不明显很容易漏掉这个问题。后期做频域分析才发现b0偏差会直接缩短系统的稳定裕度。解决方法是把b0做成随工况变化的调度参数。我之前调试一台液压伺服系统时液压源压力变化导致增益变化用固定的b0效果很差改成查表式b0后就好多了。5.3 现象三TD速度因子r太大给定信号反而出现超调跟踪微分器的原理决定了r越大跟踪越快但r超过某个临界值之后跟踪信号本身会振荡这是快速性带来的代价。我在调试Servo_Joint.slx时遇到过r调到500以上关节角度的参考轨迹在起始阶段出现可见的过冲。解决方式是给TD加一个过渡过程的限制逻辑或者采用多级TD串行结构第一级TD负责平滑拐点第二级TD负责微分输出。5.4 现象四Simulink模型跑出代数环报错有些仿真模型直接用ESO输出作为控制量控制量又反过来进ESO形成代数环。Simulink会报错或者强制插入单位延迟。解决方法是给控制量通路加一个记忆模块或者把仿真求解器改成变步长并启用代数环检测。这个坑在离散化实现中不会出现但在连续模型里很常见。5.5 现象五PID_diff_advance.m和PID_controller_2.m两份代码的结果不一致资源里既有PID_diff_advance.m又有PID_controller_2.m这两个文件的计算逻辑略有不同前者包含微分先行结构后者是标准PID再带滤波。它们的整定参数不能互换。微分先行对给定值变化不引起微分冲击适合跟踪控制滤波PID的微分只作用于被控量适合调节。用错了模型自然会对不上号确认自己的控制结构是哪一种再选代码。6. 进阶调试技巧从波形到频域的验证闭环在整套ADRC算法架构里任何单一时域指标都不足以说明问题。我习惯每次调整参数之后做三件事第一录制系统输出对阶跃输入的响应曲线记录超调量、峰值时间和稳态误差第二在运行到稳态时突发加一个外部扰动观察扰动抑制的时间窗第三把控制量曲线导出检查是否有超出执行器限制的饱和区间。这三个数据点结合起来基本能判断一次参数整定是否成功。更进一步的频域做法是把闭环系统的输入输出数据存成MATLAB的iddata格式用System Identification Toolbox做频域辨识看幅频特性曲线在穿越频率处的斜率。ADRC的优势在这里会体现得非常直观因为扰动被实时补偿掉了中频段的响应比传统PID干净得多没有PID积分项带来的相位滞后也没有微分项带来的高频抬升。还有一个实用技巧就是在Simulink模型里同时跑带扰动和不带扰动两组并观察ESO输出的z3。如果z3在不同工况下都能快速回归稳态说明ESO的“扩张”能力被正确激活了。如果z3在稳态时还有明显的波动优先检查b0的估计精度其次才是wo的带宽设置。另外一个常见误区是把ESO的观测带宽调太高期望它“看到”所有的扰动细节。实际上ESO更像一个带宽受限的状态重构器它对高频扰动的响应能力有限过高的wo只是把噪声敏感度提高了而已。在PMS_Generator.slx中我最终采用的wo是40 rad/s、wc是12 rad/s、b0取电机模型转动惯量的倒数乘以额定力矩系数这个配置在突加100%负载转矩的情况下转速跌落不超过2%恢复时间在0.3秒以内。最后提一个我自己总结的流程拿到任何一套新的ADRC参数先做离线纯仿真再做半实物仿真最后才上实物。纯仿真阶段用差分进化自动整定三组参数分别对应快响应、低超调和高抗扰然后人工从中选取综合最优的一组。从那以后我每次调ADRC参数都强制先跑一遍离线寻优流程再动手碰实物。希望这份笔记能让你少踩几个坑把时间花在真正需要思考的控制问题上。本文还有配套的精品资源点击获取