十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ADRC自抗扰控制仿真实战:MATLAB+Simulink参数整定与实现

ADRC自抗扰控制仿真实战:MATLAB+Simulink参数整定与实现 简介ADRC自抗扰控制MATLAB仿真资源包面向自动控制专业学生、科研人员以及从事运动控制与工业过程控制的工程师。自抗扰控制通过扩张状态观测器实时估计并补偿系统内外扰动本资源围绕这一核心思想在MATLAB/Simulink环境中提供了完整的仿真实现。包内含Simulink仿真模型、基于S函数的ADRC控制算法文件以及扩张状态观测器、被控对象、参数整定等核心功能脚本可直接运行并观察系统在阶跃响应、外部干扰和模型不确定性条件下的控制效果也便于修改参数、替换对象模型开展进一步对比研究。压缩包共26个文件以m脚本、mdl模型、mexw64编译文件为核心辅以c源文件、h头文件、obj目标文件及mat数据文件整体约191KB结构清晰紧凑。已有3016人学习/下载适合初步接触ADRC理论、希望借助仿真实验加深理解并快速上手的读者。 做ADRC仿真这件事说难不难说简单也真不是随便搭个Simulink模型就能跑通的。我最早接触自抗扰控制Active Disturbance Rejection ControlADRC是在一个电机负载扰动抑制的项目里那时候被PID的参数折腾得够呛换成ADRC之后才体会到什么叫“观测器把扰动兜住”。这篇文章就围绕ADRC在MATLAB里的仿真实现展开把三大件的原理、参数整定、代码实现、踩坑实录全部过一遍适合刚接触ADRC、想快速上手仿真的朋友也适合已经在调PID但被扰动搞得头疼的工程师。1. 动手仿真前先把ADRC的“三大件”分工搞清楚很多人一上来就找代码结果把跟踪微分器TD、扩展状态观测器ESO、非线性状态误差反馈控制律NLSEF三个模块拼在一起调半天参数还是发散。根源在于没理解这三部分各自到底在干什么。1.1 三大件的分工逻辑ADRC的核心思想很朴素把系统的“内扰”模型不确定性和“外扰”外部扰动一起看成总扰动通过ESO实时估计出来然后在控制量里补偿掉。听起来很玄但拆开看就是三个独立任务TD跟踪微分器给输入信号安排一个过渡过程同时提取它的微分信号。作用类似一个“平滑滤波器”避免设定值突变时控制量瞬间冲顶。ESO扩展状态观测器这是ADRC的灵魂。它把系统的状态和总扰动一起当成状态来估计输出z1状态估计、z2状态微分的估计、z3总扰动估计。NLSEF非线性状态误差反馈根据TD给出的理想状态和ESO给出的实际状态之间的误差计算出一个“中间控制量”u0再用总扰动估计z3和对象增益估计b0算出最终控制量u。我习惯用一个简单的类比来理解TD像是你开车时看导航规划的“理想轨迹”ESO像是实时告诉你“当前实际车速和路面坡度”NLSEF就是那个踩油门的脚。油门大小不仅取决于理想车速和实际车速的差还要把坡度的干扰z3补偿进去这样上坡时车子才不会因为阻力而掉速。1.2 为什么ADRC能对付“不确定扰动”PID的问题在于误差反馈是“事后纠偏”——扰动已经影响输出了PID才通过误差去调节存在滞后。ADRC的ESO相当于提前“感觉到”扰动进来了在它还没明显影响输出时就在控制量里做了反向补偿。这个区别在仿真里对比阶跃扰动响应时特别直观PID会先掉下去再拉回来ADRC几乎不掉。我在实际仿真中的对比经验是同样一个二阶对象加上突变负载PID的恢复时间可能到2秒ADRC用带宽参数整定后大概0.3秒就能稳住而且超调量小得多。这也是ADRC在电力电子、运动控制领域越来越受欢迎的原因。2. 仿真开始前参数到底应该怎么定“参数太多、不知道从哪下手”是ADRC劝退很多人的地方。其实ADRC参数虽然多但是每个参数都有明确的物理意义比PID那种“三个参数互相牵制”要好调得多。2.1 先确定被控对象模型和仿真步长仿真第一步是先有个“被控对象”。这里用一个典型的二阶系统来演示G(s) 100 / (s^2 10s 20)这个对象相当于一个带阻尼的质量-弹簧系统用状态方程表示就是dx1/dt x2 dx2/dt -20x1 - 10x2 100u写成我们需要的“积分串联型”形式时让 x1 yx2 y然后令 f -20x1 - 10x2 (100-b0)u 为总扰动那么dx1/dt x2 dx2/dt f b0*u这里b0是控制量增益的估计值。这个对象名义上u前面的系数是100所以b0可以取100左右。b0不一定非要精确我后面会专门说b0误差带来的影响。仿真步长h的选择也很关键我一般先取0.001秒也就是1kHz的采样频率。对于大多数机械系统、电力电子系统这个步长足够。如果你做的是慢过程比如温度控制可以放宽到0.01秒甚至0.1秒但要注意ESO的带宽必须远低于采样频率否则离散化误差会很大。2.2 TD和ESO的关键参数怎么取TD只有两个参数速度因子r和仿真步长h。r越大跟踪越快但对噪声的放大也越严重。我习惯先取 r 50~100观察阶跃响应如果初始控制量太大就减小r。h就是仿真的积分步长和整个系统的步长一致。ESO需要三个参数beta01、beta02、beta03对应观测器增益。工程上最常用的整定方法是基于“带宽法”beta01 3 * w0 beta02 3 * w0^2 beta03 w0^3其中w0是观测器带宽。这个公式来自于把ESO的特征方程配置成 (s w0)^3 的标准形式。w0一般取被控对象频率的3~10倍。比如上面的对象自然频率大约是sqrt(20)4.47 rad/s那我习惯先取w020也就是大概5倍。不过这里有个细节带宽法配出来的beta02、beta03往往数值很大w0^3就是8000在Simulink里直接用常数增益模块会带来数值灵敏度问题。我实际仿真中更常用的是给beta01、beta02、beta03一个“从小到大”的比例再微调而不是死板地按三次方放大。2.3 NLSEF的工程整定经验NLSEF通常就是一个非线性PD控制器加上扰动补偿u0 kp * fal(e1, 0.5, delta) kd * fal(e2, 0.25, delta) u (u0 - z3) / b0其中e1是TD的状态x1减去ESO的状态估计z1e2是x2减去z2fal函数是ADRC特有的非线性函数形式为fal(e, alpha, delta) |e|^alpha * sign(e) 当 |e| delta e / delta^(1-alpha) 当 |e| deltaalpha取值一般在0~1之间alpha越小非线性越强小误差时增益越大相当于“小误差时使劲拉”。delta是一个线性区间宽度防止e接近0时fal函数因为符号函数而抖动。我通常取delta 0.01~0.05alpha1取0.5alpha2取0.75~1。kp和kd的整定可以参考临界比例度法的感觉先给一个较小的kp比如5观察响应如果响应太慢就调大kp如果出现振荡就适当增大kd。这里其实比PID的PD部分好调因为ESO已经把扰动补偿掉了PD主要管动态品质。3. 在MATLAB里把ADRC完整跑起来参数整定完成后仿真实现就顺理成章了。我提供了两种方式一种是纯脚本仿真适合理解算法细节另一种是Simulink搭模型适合快速验证和后续扩展。3.1 用MATLAB脚本实现ADRC核心代码纯M脚本的好处是能随时看到每个中间变量调试方便。下面是一段可运行的ADRC控制系统仿真代码包含TD、ESO、NLSEF和被控对象的离散递推%% ADRC仿真示例二阶对象 阶跃扰动 clear; clc; close all; % 仿真参数 h 0.001; % 仿真步长 T 5; % 总仿真时间 t 0:h:T; N length(t); % 被控对象参数名义增益b0 b0 100; % 对对象增益的估计 % 对象状态 x1 0; x2 0; % 实际状态y 和 y y 0; % ADRC参数 r 100; % TD速度因子 w0 20; % ESO带宽 beta01 3*w0; beta02 3*w0^2; beta03 w0^3; kp 300; % 非线性PD比例增益 kd 30; % 非线性PD微分增益 alpha1 0.5; alpha2 0.75; delta 0.01; % 状态初值TD、ESO v1 0; v2 0; % TD状态 z1 0; z2 0; z3 0; % ESO状态z3为总扰动估计 % 存储 y_hist zeros(1,N); u_hist zeros(1,N); z3_hist zeros(1,N); r_hist zeros(1,N); % 目标信号 v_target 1.0; % 阶跃指令 disturbance_start 2.0; % 2秒后加入扰动 for k 1:N % 1. TD跟踪微分器 fh fhan(v1 - v_target, v2, r, h); v1 v1 h*v2; v2 v2 h*fh; % 2. 被控对象二阶系统 扰动 f_plant -20*x1 - 10*x2; % 对象自身的动态 d (t(k) disturbance_start) * 5.0; % 外部阶跃扰动 % 注意总扰动f 对象动态 外部扰动 (100-b0)*u x2 x2 h*(f_plant 100*u d); x1 x1 h*x2; y x1; % 3. ESO扩展状态观测器 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)); % 4. NLSEF非线性状态误差反馈 e1 v1 - z1; e2 v2 - z2; u0 kp*fal(e1, alpha1, delta) kd*fal(e2, alpha2, delta); u (u0 - z3) / b0; % 记录 y_hist(k) y; u_hist(k) u; z3_hist(k) z3; r_hist(k) v1; end % 绘制结果 figure; subplot(3,1,1); plot(t, r_hist, --, t, y_hist, -, LineWidth, 1.2); legend(参考信号v1, 输出y); title(ADRC 阶跃响应); xlabel(时间/s); ylabel(幅值); grid on; subplot(3,1,2); plot(t, u_hist, LineWidth, 1.2); title(控制量u); xlabel(时间/s); ylabel(控制量); grid on; subplot(3,1,3); plot(t, z3_hist, LineWidth, 1.2); title(ESO总扰动估计z3); xlabel(时间/s); ylabel(z3); grid on; % 辅助函数fhan 最速控制综合函数 function fh fhan(x1, x2, r, h) d r*h; d0 h*d; y x1 h*x2; a0 sqrt(d^2 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 end % 辅助函数fal 非线性函数 function f fal(e, alpha, delta) if abs(e) delta f abs(e)^alpha * sign(e); else f e / delta^(1-alpha); end end这段代码的逻辑非常清晰每个循环里先更新TD再更新被控对象接着用ESO估计当前状态和总扰动最后通过NLSEF计算出控制量。需要注意的是ESO里的b0*u是控制量的前馈项ESO能否准确估计扰动和这个前馈项密切相关。初学时很多人在ESO方程里漏掉这一项结果就是z3的估计总是滞后甚至出现偏差。3.2 在Simulink里搭ADRC模型如果你更习惯Simulink搭建思路也是围绕三大件展开。我的做法是用MATLAB Function模块分别封装TD、ESO、NLSEF三个函数被控对象直接用Transfer Fcn模块传函100/(s^210s20)在对象输出端加入一个阶跃信号作为扰动叠加点放在对象输入后面或者输出前面都可以推荐放在对象的输入端模拟负载扰动。Simulink模型里需要注意的一个坑是代数环。ESO的输出z3会反馈到控制量u的计算中而u又进入ESO的微分方程如果不加Memory模块或者单位延迟Simulink可能会报代数环错误或者编译失败。我通常在ESO的反馈回路里加一个Unit Delay模块或者把整个控制器封装成一个MATLAB Function输入为参考信号、反馈输出和上一时刻控制量输出为新控制量天然打散了代数环。另外Simulink里的MATLAB Function模块写的代码头几行最好加上function [z1, z2, z3] ESO(y, u, h, omega0)这样每次调用时把状态值从外部传进来避免在函数内部依赖持久变量。持久变量在Simulink中容易因为步长变化导致状态错乱我踩过这个坑不建议新手使用。3.3 仿真结果怎么判断“调好了”拿到仿真曲线之后我用三个标准来判断ADRC是否调好无扰动时阶跃响应超调小于5%调节时间在期望范围内加入阶跃扰动后输出最大偏差小比如小于设定值的2%恢复时间短z3曲线在扰动发生后能快速逼近真实扰动值并保持平稳。如果z3的估计曲线在扰动发生后出现明显的振荡或发散基本可以判定ESO参数w0或者b0有问题。此时先别急着调kp/kd优先看z3准不准。z3准了ADRC的效果就出来了。4. 仿真过程中的常见问题与排查技巧我根据自己调试ADRC的经验把最容易踩的坑整理成一个速查表每个问题都是我实际遇到过的不是臆想出来的。现象大概率原因排查/解决方法仿真直接发散曲线飞到天上去b0的符号或数量级错误确认b0与对象实际增益同号一般取对象增益估值的50%~200%发散前控制量剧烈振荡仿真步长过大或w0过大减小h如从0.01降到0.001降低w0z3估计曲线持续漂移ESO方程漏了b0*u前馈项检查ESO更新公式必须包含b0*u阶跃响应振荡但z3正常kp过大减小kp或增大kd控制量高频抖动delta取得太小delta增大到0.05~0.1平滑fal函数在零附近的增益初始时刻控制量冲顶TD速度因子r过大减小r或者让参考信号从斜坡开始加入扰动后输出偏差很大w0不够大ESO观测慢增大w0但注意不要超过采样频率的十分之一4.1 一仿真就发散先别怀疑算法很多同学第一次跑ADRC发散第一反应是“我代码写错了”。其实最常碰到的问题是b0和实际对象增益不匹配。在上面的二阶对象中实际增益是100如果b0写成1控制律u(u0-z3)/b0就放大了100倍不发散才怪。我的经验是b0先粗估再逐步减小或者增大观察z3能否跟随扰动。如果z3的幅值远远大于真实扰动说明b0偏小了反之说明b0偏大了。b0的偏差只要在一倍以内ADRC基本都能扛住这也是它比PID对模型误差容忍度高的原因——误差会进到总扰动里被ESO估计和补偿。4.2 ESO不收敛多半是带宽与步长的匹配问题ESO本质上是一个观测器它的收敛速度直接由w0决定。但如果w0取得太大比如100以上而仿真步长还是0.01那么单个步长内系统的动态变化已经超过了ESO能跟踪的极限就会出现数值震荡。我一般在调ESO参数时先定步长再定w0步长与w0满足w0 * h 0.3这个经验规则。4.3 控制量一直在抖问题多半在fal函数fal函数在误差接近零时会从|e|^alpha * sign(e)切换到e/delta^(1-alpha)如果delta取得极小比如1e-5切换点附近数值跳变很明显控制量就会抖。实际工程里delta一般取0.01以上我甚至在慢系统上取到0.1。另外如果alpha取得太小比如0.2小误差区域增益会很大也会导致抖振。4.4 仿真步长选不好全白搭ADRC对步长比PID敏感得多原因是ESO本身就是一个动态系统它的离散化必须足够准确。我在Simulink里常用定步长的ode4四阶龙格库塔步长0.001秒。如果坚持用变步长求解器ESO部分最好用离散模块单独建模否则连续和离散混在一起仿出来的结果可能不稳定。5. 最后一个建议先复现再创新我在带新人做ADRC仿真时总是让他们先把最基础的二阶对象跑通把z3、控制量、输出三条曲线都看明白再去做变参数、加噪声、改对象这类“进阶操作”。千万不要一开始就拿一个高维复杂对象去套ADRC那样很难判断问题是出在算法本身还是模型边界。如果你已经跑通了这个基本示例下一步建议把对象换成实际工程模型比如永磁同步电机的dq轴模型或无人机姿态模型然后把ESO的带宽整定和实际系统带宽关联起来。你会发现ADRC调试从“玄学”变回了“工程”。至少对我而言这种“把算法吃透再落地”的思路远比拿一堆高级工具箱直接拟合参数要扎实得多。本文还有配套的精品资源点击获取
返回列表