
简介这份资源是围绕Matlab平台整理的自抗扰控制器ADRC与PID控制源码合集面向自动化、电子信息工程、数学等专业的学生及控制算法初学者可用于课程设计、期末大作业或毕业设计中的算法验证与对比研究。包内共36个文件以31个.m脚本为主辅以4个.mdl仿真模型和1个.asv备份文件整体约39KB涵盖被控对象建模、控制器实现、扩张状态观测器、跟踪微分器及仿真绘图等模块便于读者理解ADRC与PID的算法结构与仿真流程。目前已有1250人学习下载说明其在控制类课程与算法入门中具有一定参考价值。读者可借助这些源码搭建仿真环境对比两种控制策略的响应特性学习非线性函数与观测器的实现思路并在此基础上自行调试、修改或扩展功能作为算法学习与项目开发的参考资料。1. 从一份 Matlab 自抗扰PID 源码说起它到底解决什么问题如果你手上有一台位置伺服、四旋翼姿态环、或者温控/流量回路被负载扰动、参数漂移、死区摩擦折腾得够呛那你大概率已经试过 PID。PID 的好处是结构简单、参数少、工程直觉强坏处也明显它靠误差反馈“事后补救”对突变扰动和模型不确定性反应总是慢半拍。自抗扰控制器ADRC走的是另一条路——用扩张状态观测器ESO把“内扰外扰”统一估出来再前馈补偿掉相当于给系统配了个实时扰动黑匣子。这份“基于 Matlab 自抗扰控制器和 PID 控制源码”的工程本质就是把 ADRC 和 PID 放在同一个仿真框架里对比、调参、验证让你能直观看到两种控制律在同一被控对象上的跟踪、抗扰和鲁棒性差异。它适合做控制算法验证的工程师、做课程设计/毕设的学生也适合想把 ADRC 真正落到电机、舵机、温控场景的人。下面我按“先立原理、再跑代码、最后避坑”的顺序把这份源码该怎么读、怎么改、怎么复现讲清楚。2. 自抗扰与 PID 的底层差异为什么 ESO 是分水岭2.1 从 PID 的“误差驱动”到 ADRC 的“扰动估计补偿”PID 的核心逻辑是误差 e r - y输出 u Kp·e Ki·∫e Kd·de/dt。它不关心扰动从哪来、系统内部发生了什么只根据误差大小和变化趋势去“顶”。这在模型准确、扰动缓慢时够用但一旦遇到阶跃扰动、参数摄动、非线性摩擦PID 要么超调、要么响应慢靠调参只能折中。ADRC 的思路完全不同。它把被控对象写成y f(y, y, w, t) b0·u其中 f 是“总扰动”包含内部未建模动态和外部扰动b0 是控制增益的估计值。ADRC 不去精确建模 f而是用扩张状态观测器ESO把 f 当成一个额外状态实时估计出来记作 z3。控制律再取u (u0 - z3) / b0这样扰动在进入系统之前就被“抵消”掉了。剩下的 u0 可以用最简单的 PD 形式比如 u0 kp·(r - z1) - kd·z2。所以 ADRC 的本质是用观测器把扰动变成已知量再用前馈把它消掉。ESO 就是整个控制器的分水岭——它估得准ADRC 就强它估不准ADRC 可能还不如 PID。2.2 一阶/二阶 ADRC 的 Matlab 实现骨架工程里最常见的是一阶和二阶 ADRC。以二阶被控对象为例核心是离散 ESO 和 PD 控制律。下面这段代码是典型的二阶 ADRC 单步更新你可以直接对照源码里的函数结构function [u, z1, z2, z3] adrc_step(r, y, z1, z2, z3, h, b0, kp, kd, beta1, beta2, beta3) % r: 设定值, y: 实际输出, h: 采样步长 % z1,z2: 状态估计, z3: 总扰动估计 % b0: 控制增益估计, kp/kd: 控制器增益 % beta1~3: ESO 观测器增益 e z1 - y; % 观测误差 z1 z1 h * (z2 - beta1 * e); z2 z2 h * (z3 - beta2 * e); z3 z3 h * (-beta3 * e); % 扩张状态总扰动 u0 kp * (r - z1) - kd * z2; % PD 控制律 u (u0 - z3) / b0; % 扰动补偿 end逻辑说明前三行是离散 ESO 的欧拉积分beta1/beta2/beta3 决定观测器收敛速度z3 就是估出来的总扰动。u0 用 PD 形式最后除以 b0 并减去 z3/b0完成补偿。参数说明h 必须和仿真步长一致否则观测器会发散b0 一般取对象高频增益的粗略估计宁可偏大不要偏小kp、kd 按带宽配置常见做法是令 kp wc²kd 2·wcwc 是期望闭环带宽。beta1~3 通常按观测器带宽 wo 配置beta1 3·wobeta2 3·wo²beta3 wo³wo 一般取 3~5 倍 wc。2.3 PID 对照组的实现与参数整定源码里 PID 部分通常就是标准位置式或增量式。为了和 ADRC 公平对比采样步长、被控对象、扰动注入方式必须完全一致。下面是一个带抗积分饱和的 PID 单步实现function [u, integ] pid_step(r, y, integ, h, Kp, Ki, Kd, u_max) % 位置式 PID 积分限幅 e r - y; integ integ Ki * e * h; integ max(min(integ, u_max), -u_max); % 抗积分饱和 deriv (e - (r - y)) / h; % 简化微分项 u Kp * e integ Kd * deriv; u max(min(u, u_max), -u_max); end逻辑说明积分项单独累加并限幅避免执行器饱和时积分继续累积导致退饱和超调。参数说明Kp 决定响应速度Ki 消除稳态误差但太大会振荡Kd 抑制超调但对噪声敏感。工程上常用 Ziegler-Nichols 或内模法先给初值再手动微调。注意如果被控对象有纯延迟PID 的 Kd 要慎用否则噪声放大后执行器会抖。3. 把源码跑起来Matlab 环境、文件结构与最小复现步骤3.1 环境准备与源码目录的典型构成这份源码是 .rar 包解压后一般包含主仿真脚本如 main_sim.m、ADRC 函数文件、PID 函数文件、被控对象模型文件、绘图脚本。Matlab 版本建议 R2016b 及以上因为脚本内定义函数、string 类型等特性在老版本上会报错。不需要额外工具箱基础 Matlab 即可运行如果源码里用了 Simulink 模型则需要 Simulink 授权。常见做法是先不要改任何参数直接运行主脚本看能不能出图。如果报“未定义函数”大概率是当前工作目录没切到源码根目录或者函数文件名和调用名不一致。这一步是血泪经验——很多人卡在路径上以为代码有问题。3.2 最小复现一个二阶对象的 ADRC vs PID 对比下面给一个可以直接抄的最小仿真框架把 ADRC 和 PID 放在同一个循环里跑方便你对照源码理解clear; clc; h 0.001; T 5; N T/h; % 被控对象二阶惯性环节 y -a*y - b*y c*u d a 2; b 10; c 1; d 0; % ADRC 参数 b0 c; wc 20; wo 4*wc; kp wc^2; kd 2*wc; beta1 3*wo; beta2 3*wo^2; beta3 wo^3; z10; z20; z30; % PID 参数 Kp30; Ki50; Kd1; integ0; u_max10; % 状态 y_adrc0; dy_adrc0; y_pid0; dy_pid0; r 1; % 设定值 for k 1:N t k*h; % 扰动2s 时加 0.5 阶跃 dist (t 2) * 0.5; % ADRC [u_adrc, z1, z2, z3] adrc_step(r, y_adrc, z1, z2, z3, h, b0, kp, kd, beta1, beta2, beta3); ddy_adrc -a*dy_adrc - b*y_adrc c*u_adrc dist; dy_adrc dy_adrc h*ddy_adrc; y_adrc y_adrc h*dy_adrc; % PID [u_pid, integ] pid_step(r, y_pid, integ, h, Kp, Ki, Kd, u_max); ddy_pid -a*dy_pid - b*y_pid c*u_pid dist; dy_pid dy_pid h*ddy_pid; y_pid y_pid h*dy_pid; % 记录 Y_adrc(k)y_adrc; Y_pid(k)y_pid; U_adrc(k)u_adrc; U_pid(k)u_pid; end t (0:N-1)*h; plot(t, Y_adrc, b, t, Y_pid, r); legend(ADRC,PID); grid on;逻辑说明被控对象用欧拉法离散积分扰动在 2s 时注入。ADRC 和 PID 共用同一个对象和扰动保证对比公平。参数说明b0 取 c 的估计值wc 是期望闭环带宽越大响应越快但控制量越大wo 取 4 倍 wc 是常见经验观测器要快于控制器。PID 的 Kp/Ki/Kd 需要你根据对象手动调这里给的是一组能出图的初值。跑完后你会看到ADRC 在扰动注入后恢复更快PID 会有明显跌落再慢慢拉回。3.3 参数怎么改从“能跑”到“跑得好”调 ADRC 的顺序是先定 b0再定 wc最后定 wo。b0 偏大控制量偏小、响应慢b0 偏小控制量偏大、容易振荡。wc 决定跟踪速度一般取对象带宽的 2~5 倍。wo 决定扰动估计速度取 3~5 倍 wc太小则扰动补偿滞后太大则对噪声敏感。PID 那边先调 Kp 让响应快起来再加 Ki 消静差最后用 Kd 压超调。注意如果对象有噪声Kd 和 wo 都不能太大否则控制量会抖。4. 避坑与排查ADRCPID 仿真里最容易翻车的 5 个点4.1 现象ADRC 输出剧烈振荡甚至发散原因最常见的是 b0 符号搞反或数量级差太多其次是 h 和仿真步长不一致导致 ESO 积分不匹配。还有一种情况是 wo 取得过大观测器把噪声当扰动放大。解决先检查 b0 是否为正、是否接近对象高频增益。把 wo 降到 2~3 倍 wc 试。确认 adrc_step 里的 h 和主循环的 h 完全一致。如果还振把 kp/kd 减半先让系统稳下来再逐步加。4.2 现象PID 稳态误差消不掉或者积分饱和后大幅超调原因Ki 太小消不掉静差Ki 太大又振荡积分限幅没做执行器饱和后积分继续累积。解决给积分项单独限幅限幅值取执行器上限的 0.5~0.8 倍。如果对象有死区纯 PID 很难消静差这时候 ADRC 的扰动补偿优势就出来了——它能把死区当成总扰动的一部分估出来补掉。4.3 现象ADRC 跟踪阶跃时初始控制量巨大原因阶跃设定值直接进 PD 的 r - z1初始误差大u0 冲得很高。这是 ADRC 的常见问题叫“设定值突变冲击”。解决加跟踪微分器TD对设定值做过渡或者用“安排过渡过程”的方式让 r 缓慢上升。源码里如果有 TD 模块一定要用上没有的话可以自己加一个一阶惯性滤波。4.4 现象仿真步长改小后结果反而变差原因ESO 的离散化用欧拉法步长太小会让 beta 增益对应的数值稳定性变差尤其是 wo 较大时。解决要么保持 h 在 1e-3 量级要么改用更精确的离散化方法如零阶保持、双线性变换。工程上如果实际控制器采样率固定仿真步长就按实际采样率来不要盲目调小。4.5 现象换一个被控对象ADRC 参数全废原因ADRC 虽然不依赖精确模型但 b0 和带宽参数仍然和对象有关。对象增益变了b0 不变就会补偿错误。解决b0 按新对象的高频增益重新估。如果对象增益变化范围大可以考虑在线辨识 b0或者把 b0 取保守值偏大牺牲一点性能换鲁棒性。这也是 ADRC 工程落地时最需要权衡的地方。5. 进阶用法把 ADRC 从仿真推到实际控制器的几个技巧仿真跑通只是第一步真正落地时你会遇到采样延迟、量化噪声、执行器非线性。我一般会做三件事第一把 ESO 的带宽 wo 压到仿真值的 0.5~0.7 倍给噪声和延迟留余量第二在控制量输出后加一个一阶低通滤波截止频率取 wc 的 2~3 倍压掉高频抖动第三用实际采样率重跑仿真把 h 设成真实值看参数是否还稳。验证方法上我习惯先做阶跃响应看超调和调节时间再做扰动注入看恢复时间最后做参数摄动把对象增益改 ±30%看鲁棒性。如果这三项都过基本可以上机试。下面这张表是我常用的参数初值参考参数含义初值建议调整方向b0控制增益估计对象高频增益偏大更稳偏小更快但易振wc控制器带宽对象带宽 2~5 倍越大越快太大超调wo观测器带宽3~5 倍 wc越大估计越快太大噪声敏感kp比例增益wc²随 wc 联动kd微分增益2·wc随 wc 联动h采样步长实际采样周期必须与控制器一致最后说个我自己的习惯每次调 ADRC我都会先把 PID 跑一遍作为基线记下它的超调、调节时间、扰动恢复时间然后再调 ADRC。这样你才能说清楚 ADRC 到底比 PID 强在哪、强多少。如果 ADRC 调完还不如 PID大概率是 ESO 没调好回去查 b0 和 wo。希望帮到你。本文还有配套的精品资源点击获取