
简介这是一份基于MATLAB的自抗扰控制ADRC仿真实现适合自动化、电气与机械控制方向的学习者及初级研发人员用于理解其如何观测扰动并实时补偿的核心思想快速搭建算法仿真环境。RAR压缩包共5个文件其中4个M文件承担主流程、自抗扰控制器、系统状态方程及输出函数等核心模块另含1个ASV辅助文件整体仅2KB结构紧凑。已有320人学习/下载。借助扩展状态观测器与非线性控制律仿真时可直观比较有无扰动补偿时系统的响应差异调整观测器带宽、控制增益等参数可观察稳态精度、响应速度与抗扰性能的变化。这套仿真代码对课程设计、毕业设计以及工程预研中的控制算法选型都有参考价值帮助使用者在短时间内掌握自抗扰控制从原理到代码实现的关键环节。 拿到这个adrc_matlab仿真.rar第一反应大概是解压、翻文件、双击某个.m然后被报错或者满屏曲线劝退。我帮人排查过好几个类似的压缩包几乎每个包里都有一套“能跑但不好跑”的ADRC仿真代码。这个现象背后有个原因ADRC算法的仿真难点从来不在代码本身而在你脑子里有没有把“自抗扰”这个框架理顺。框架理顺了代码再乱也能改通框架没理顺别人写好的代码你也调不动。这篇文章我打算把所有关键点一次讲透——ADRC三大核心组件TD、ESO、NLSEF的原理MATLAB环境下的完整仿真实现参数整定的可操作方法以及这类压缩包资源最常见的坑适合所有想系统掌握ADRC并亲手复现仿真的读者。1. 解压之前先想清楚这套仿真要解决什么问题1.1 一个压缩包背后的两类需求同一个压缩包两类人拿到的目标完全不同。第一类是学生论文或课题需要希望快速得到一组漂亮的仿真曲线能放进汇报PPT和毕业论文里第二类是工程师现场遇到环路性能不达标想评估ADRC能否替换现有PID。两类人看代码的切入点也应该不同。如果是学生拿到代码后第一件事是梳理模型结构ADRC那几段函数分别对应哪个模块被控对象是几阶的输入输出怎么接然后换成自己研究对象的传递函数去跑。如果是工程师第一件事是把ESO部分单独抽出来因为这一块是整个算法的灵魂它告诉你如何在不知道扰动模型的情况下把总扰动实时估计出来。我自己两条路径都走过所以后文的写法会同时兼顾这两类诉求。1.2 从PID到ADRC控制思路的转变先简单说清楚ADRC为什么能吸引这么多人。PID控制器工作在一维的误差信号上它不知道系统内部发生了什么更不知道扰动长什么样只能等扰动通过误差体现出来之后再去“救火”。ADRC的思路是从源头解决问题它把系统内部的非线性动态、参数偏差、外部扰动统一成一个总扰动f然后专门用一个扩张出来的状态变量z3去估计f再把这个估计值直接补偿到控制量里。换句话说ADRC不是在对抗扰动而是在“看见”扰动之后把它抵消掉。这个视角的转变使得ADRC对模型精度要求不高对扰动却格外敏感特别适合强扰动、强耦合、被控对象模型不准的场景。你在网上下载到的adrc_matlab仿真.rar核心跑出来就是这件事一个能实时估计扰动并补偿掉的闭环控制系统。2. 三大件拆解TD、ESO、NLSEF各自扮演什么角色2.1 TD跟踪微分器给阶跃信号装一个“缓冲器”跟踪微分器解决的是一个很实际的问题期望输入突然从0跳到1误差瞬间变成1如果控制律直接作用控制量u会一下顶到很大容易饱和进而引发超调甚至振荡。TD的作用是把阶跃安排成一条平滑的过渡曲线同时输出它的导数让控制器看到的参考值是一个“慢慢逼近目标”的过程而不是一个跳变。最经典的是韩京清提出的最速跟踪微分器核心调用最速控制综合函数fhan。在MATLAB里可以单独存成一个子函数function f fhan(x1, x2, r, h) % 最速控制综合函数(常用实现) d r * h; d0 h * d; y x1 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 f -r * a / d; else f -r * sign(a); end end参数r越大跟踪越快但噪声敏感度也会上升h一般取与仿真步长同量级。实际压缩包里你经常能看到TD、ESO、NLSEF各自写成一个function文件互相独立这就是ADRC模块化设计的好处——哪一段出问题了单独替换那一段就行。2.2 ESO扩张状态观测器估计总和扰动的关键ESO是ADRC的心脏。它把被控对象看成积分串联型结构x1是位置量x2是速度量x3是额外扩张出来的总和扰动。以二阶对象为例如果对象动态可以写成x1_dot x2 x2_dot f(t) b0 * u其中f(t)就是总和扰动那么ESO用下面三个式子实时跟踪x1、x2和fe z1 - y z1_dot z2 - beta1 * e z2_dot z3 - beta2 * e b0 * u z3_dot -beta3 * ez1、z2分别是x1、x2的估计z3是总扰动f的估计。这里beta1、beta2、beta3是观测器增益。在高志强提出的线性ADRC框架里这三个增益可以统一写为beta1 3 * wo beta2 3 * wo^2 beta3 wo^3wo是观测器带宽。注意这个参数化的意义把三个离散的数变成一个物理意义明确的带宽后面整定时只需要想“扰动跟踪快不快”不需要逐个试beta。增益越大ESO收敛越快但测量噪声也越容易被放大这个矛盾后面专门讲。2.3 NLSEF与线性替代控制量如何合成在韩京清的原始ADRC中最后的控制律使用非线性状态误差反馈典型形式为u0 beta1 * fal(v1 - z1, alpha1, delta) beta2 * fal(v2 - z2, alpha2, delta)其中fal是非线性函数误差大时增益高、误差小时增益低比纯线性PD在“小误差段”更柔和。fal函数定义为fal(e, alpha, delta) |e|^alpha * sign(e), 当 |e| delta fal(e, alpha, delta) e / delta^(1-alpha), 当 |e| delta但工程实践中更多人直接用线性PD作为前向控制律也就是高志强提出的LADRC线性自抗扰控制u0 kp * (r - z1) - kd * z2 u (u0 - z3) / b0这样控制器的参数就从alpha、delta等一大堆非线性参数收敛成kp、kd两个再对应到控制器带宽wckp wc²kd 2wc。参数少解析清楚调起来也快得多。我给的示例代码就采用这种线性形式先跑通框架再考虑要不要换成非线性。3. 从零复现一个二阶对象的LADRC仿真全流程3.1 被控对象建模与参数设定我选一个运动控制里非常典型的二阶对象来演示G(s) 133 / (s² 25s)这个对象对应带阻尼的惯性系统比如伺服速度环或某些热工对象的简化模型。写成状态方程x1_dot x2 x2_dot -25 * x2 133 * u d把-25x2对象自身动态和外部扰动d都丢进总扰动fESO只负责估计f这样控制器就不需要精确知道对象内部参数。注意b0取133是对控制增益的估计如果实际增益有偏差ESO会把偏差一并当成扰动去估计这就是ADRC对参数不敏感的原因。仿真参数表如下符号数值含义dt0.001 s仿真步长T20 s仿真时长b0133控制增益估计wc5控制器带宽wo20观测器带宽kp25线性PD比例增益kd10线性PD微分增益3.2 完整代码主循环式M文件下面是可以直接运行的完整MATLAB脚本保存为adrc_demo.m在MATLAB中运行即可% adrc_demo.m % 二阶被控对象 线性ADRC(LADRC)仿真 % 对象: x1_dot x2, x2_dot -25*x2 133*u d clear; close all; clc; %% 仿真参数 dt 0.001; T 20; N T / dt; %% 被控对象参数 a1 25; % 对象固有阻尼 b 133; % 真实控制增益 %% ADRC参数 b0 133; % 控制增益估计值 wc 5; % 控制器带宽 wo 20; % 观测器带宽 kp wc * wc; kd 2 * wc; beta1 3 * wo; beta2 3 * wo * wo; beta3 wo * wo * wo; %% 状态初始化 x1 0; x2 0; % 被控对象状态 z1 0; z2 0; z3 0; % ESO状态 u 0; %% 参考信号 r 1; %% 存储数组 t_arr (0:N-1) * dt; y_arr zeros(1, N); u_arr zeros(1, N); z3_arr zeros(1, N); %% 主循环: 前向欧拉离散化 for k 1:N t (k - 1) * dt; % 外部扰动: 2s~4s 加入大小2的阶跃干扰 if t 2 t 4 d 2; else d 0; end % 被控对象更新 x2 x2 (-a1 * x2 b * u d) * dt; x1 x1 x2 * dt; y x1; % 扩张状态观测器更新 e z1 - y; z1 z1 (z2 - beta1 * e) * dt; z2 z2 (z3 - beta2 * e b0 * u) * dt; z3 z3 (-beta3 * e) * dt; % 线性控制律: PD 扰动补偿 u0 kp * (r - z1) - kd * z2; u (u0 - z3) / b0; % 记录数据 y_arr(k) y; u_arr(k) u; z3_arr(k) z3; end %% 绘图 figure(Color, w); subplot(3,1,1); plot(t_arr, y_arr, b-, LineWidth, 1.5); hold on; plot(t_arr, r * ones(size(t_arr)), r--, LineWidth, 1); xlabel(时间 / s); ylabel(输出 y); legend(系统输出, 目标值, Location, southeast); title(ADRC 闭环阶跃响应); grid on; subplot(3,1,2); plot(t_arr, u_arr, k-, LineWidth, 1); xlabel(时间 / s); ylabel(控制量 u); title(控制输入); grid on; subplot(3,1,3); plot(t_arr, z3_arr, m-, LineWidth, 1); xlabel(时间 / s); ylabel(总扰动估计 z3); title(ESO 对总和扰动的估计); grid on;3.3 仿真结果解读三条曲线的信息量跑完这段代码你会看到三张子图。第一张是输出响应大约在1秒左右平滑到达目标值1基本没有超调2秒时刻加入d2的外部扰动输出出现一个短暂的向下凹陷但ESO很快把扰动估计出来控制量补偿上去系统大约在半秒内恢复到目标值。这个“凹陷后快速恢复”的过程就是ADRC抗扰能力的直观体现。第三张图里z3的曲线值得专门说。在阶跃上升阶段z3并不等于2因为它估计的是“总扰动”f-25x2d而不是单纯的外部扰动d。在上升过程中x2不为0-25x2这部分的贡献会让z3出现波动等到输出稳定在1x2归零z3才稳定到你加的扰动值2附近。很多初学者第一次看到z3在上升阶段数值很奇怪以为ESO出bug了其实这正是它把内部动态也当成扰动的一部分在估计属于正常现象。4. 参数整定的可操作方法从带宽法到实际调参4.1 带宽法为什么有效传统ADRC参数多非线性形式下fal函数里的alpha、delta也要一个个试调试门槛高。高志强的线性ADRC把6个关键参数压缩成两个带宽这是整定难度的一次大降维。控制器带宽wc决定闭环响应速度观测器带宽wo决定ESO跟踪扰动的速度。经验上wo取wc的3到10倍比较稳妥。wc太小响应慢wc太大闭环容易振荡。wo太小扰动估计滞后抗扰效果差wo太大噪声被放大控制量抖动明显。这个倍数关系不是严格定理而是大量工程调试得出的合理区间。4.2 整定流程与典型问题我自己的整定流程是这样的先设wc5、wo20跑一遍阶跃如果响应太慢就逐步加大wc每次加1到2观察超调一旦出现明显超调或者高频振荡说明wc过大了往回退一个值。然后在保持wc不变的前提下增大wo观察加入扰动后的恢复时间。wo的调整步长可以取5或10直到抗扰效果满意为止。现象调整方向响应太慢增大 wc出现超调/振荡减小 wc扰动后恢复慢增大 wo控制量抖动减小 wo 或对 z3 滤波稳态有静差检查 b0 是否偏离实际增益过大最后一个静差问题很隐蔽。如果b0与实际增益b偏差很大ESO虽然能估计一部分但估计带宽有限静态误差可能去不掉。这时候要么把b0调到接近b要么适当增大wo。4.3 非线性ADRC与线性ADRC的取舍网上很多ADRC教程喜欢展示非线性版本因为fal函数调得巧妙时响应曲线很漂亮能体现“非线性”的优势。但非线性版本参数多每个参数对性能的影响不直观出了问题不好定位。我的建议是学习阶段先用线性ADRC跑通全流程把带宽法的手感练出来论文里如果需要强调算法创新可以再引入非线性环节对比工程落地则直接上线性版本省心、可控、好维护。你手上那个压缩包里如果同时有LADRC和NLADRC两套文件优先看线性那套原理通了再看不线性。5. 实际下载.rar之后最容易踩的坑5.1 中文注释乱码与编码转换这类压缩包流传多年很多.m文件里的注释是GB2312或GBK编码用新版MATLAB打开中文注释直接变成乱码甚至可能导致脚本解析错误。解决办法很简单用VS Code或Notepad打开乱码的.m文件把编码从ANSI/GBK转成UTF-8另存后再用MATLAB打开。如果文件很多可以用批量转码脚本一次处理整个文件夹。5.2 ESO噪声放大与带宽上限ESO带宽越大扰动估计越猛但同步放大的还有测量噪声。仿真里容易忽视这个问题因为很多仿真模型没有给测量信号加噪声一旦把ADRC代码迁移到真实系统y的方向上有一点点随机噪声z2和z3就会剧烈抖动控制量u跟着抖执行器受不了。应对办法有三个一是把wo压下来在扰动跟踪速度和噪声忍受度之间找平衡二是对z2或z3做一阶低通滤波但要注意相位滞后三是在仿真里主动加入高斯白噪声提前检验ESO的噪声表现。第三种办法最推荐因为把问题暴露在仿真阶段总比上了现场再排查强。5.3 模型文件版本兼容与S函数问题压缩包里有时带.slx或.mdl模型文件新版MATLAB打开老版本模型通常没问题但老版本打开新版本.slx会直接失败。遇到这种情况不要反复尝试直接看模型里用到的S函数很多ADRC的Simulink实现把TD或ESO写在S函数里如果S函数是C Mex格式还需要编译环境如果是.m格式的S函数相对省事但运行效率低。一个更稳妥的替代方案是绕开Simulink用主循环脚本自己搭仿真就像本文第3章的代码那样。脚本方式对版本兼容性最友好也更容易观察每一步的中间变量尤其适合想把ADRC逻辑移植到嵌入式平台的读者。最后说一个我自己的习惯拿到任何ADRC压缩包不要急着改参数先把原始代码原封不动跑通记录下它默认参数下的响应曲线然后只改被控对象不动控制器看鲁棒性最后才进入参数整定环节。这个顺序能帮你快速判断一套代码的底子好不好也能在后续调整时有个对照基准。养成这个习惯之后你再看到类似adrc_matlab仿真.rar的资源就不会被一堆文件吓到了。本文还有配套的精品资源点击获取