简介:这份资源是一套基于自抗扰控制(ADRC)理论的MATLAB程序,面向自动化、车辆控制方向的学习者与工程实践者,尤其适合希望将韩京清教授ADRC理论落地到汽车引擎控制场景的读者。压缩包共1个文件,为m脚本类型,大小约563B,核心围绕扩展状态观测器(ESO)的实现展开,可用于在线估计系统状态与外部扰动,为控制器提供补偿依据。资源已有1932人学习下载,说明其在ADRC入门与仿真验证方面具有一定参考价值。读者可从中获得一套经过仿真验证的控制器实现思路,理解ADRC无需精确模型即可抑制不确定性与扰动的特点,并对照汽车引擎控制中的燃油经济性、动力平顺性与排放等目标,体会理论向工程转化的过程,适合作为学习ADRC算法与MATLAB仿真的实践案例。
1. 从一条“抖得没法看”的仿真曲线说起
去年帮一个做底盘电控的朋友看仿真,他丢过来一条横摆角速度跟踪曲线,前 0.5 秒还行,一进弯道就抖成一团,PID 参数调了三天,要么响应慢半拍,要么超调压不住。后来换成自抗扰控制(ADRC)重做了一遍,同样的被控对象、同样的采样步长,跟踪误差直接压下去一个量级。这份 adrc 自抗扰程序就是那类“仿真已经跑通”的 MATLAB 工程:核心是跟踪微分器(TD)、扩张状态观测器(ESO)和非线性状态误差反馈(NLSEF)三件套,配套一个汽车二自由度或横摆动力学模型做验证。它适合两类人:一类是课程设计、毕业设计里要做 ADRC 仿真的学生,另一类是想把 ADRC 往实车控制器上迁移、需要先有个能跑通的参考实现的工程师。关键词里的“自抗扰 adrc 汽车 matlab”基本就是它的全部定位——不是通用工具箱,是一个能打开就跑、跑完能改的仿真工程。
2. 工程结构与控制链路:三件套是怎么串起来的
2.1 目录与文件职责
这类仿真工程通常不会太大,但文件职责分得很清楚。拿到源码先别急着点运行,按下面这个结构对一遍,能省掉后面一半的排查时间。
| 文件/目录 | 职责 | 改动频率 |
|---|---|---|
main.m | 主脚本,清环境、设参数、调仿真、画图 | 低 |
adrc_core.m | ADRC 控制器主体,TD+ESO+NLSEF | 高 |
plant_model.m | 被控对象,汽车动力学模型 | 中 |
params.m | 集中参数配置 | 高 |
sim_setup.m | 仿真步长、时长、初值 | 中 |
plot_result.m | 结果可视化 | 低 |
常见做法是把参数全部收进params.m,主脚本只做流程编排。我一般会先打开params.m看一遍量纲,因为 ADRC 翻车十有八九是参数单位没对齐——比如b0用的是 1/质量 还是 1/(质量·半径),差一个系数整条曲线就废了。
2.2 控制链路:从参考输入到控制量
整条链路是:参考信号v进 TD 得到平滑的v1和微分v2;被控对象输出y和上一拍控制量u一起进 ESO,估计出状态z1、z2和总扰动z3;NLSEF 拿v1-z1、v2-z2算误差反馈,再减去z3/b0做扰动补偿,得到最终u。这个顺序不能乱,ESO 必须拿到上一拍的u,否则扰动估计会滞后一拍,仿真里表现为高频抖动。
% adrc_core.m 核心单步计算(简化示意) function [u, z1, z2, z3] = adrc_core(v, y, u_prev, p) % ---- TD:跟踪微分器,安排过渡过程 ---- fh = fhan(p.v1 - v, p.v2, p.r, p.h); p.v1 = p.v1 + p.h * p.v2; p.v2 = p.v2 + p.h * fh; % ---- ESO:扩张状态观测器,估计状态与总扰动 ---- e = p.z1 - y; fe = fal(e, p.alpha1, p.delta); fe1 = fal(e, p.alpha2, p.delta); p.z1 = p.z1 + p.h * (p.z2 - p.beta1 * e); p.z2 = p.z2 + p.h * (p.z3 - p.beta2 * fe + p.b0 * u_prev); p.z3 = p.z3 + p.h * (-p.beta3 * fe1); % ---- NLSEF:非线性状态误差反馈 + 扰动补偿 ---- e1 = p.v1 - p.z1; e2 = p.v2 - p.z2; u0 = p.beta_f1 * fal(e1, p.alpha3, p.delta) ... + p.beta_f2 * fal(e2, p.alpha4, p.delta); u = (u0 - p.z3) / p.b0; z1 = p.z1; z2 = p.z2; z3 = p.z3; end这段代码里几个参数值得单独说:r是 TD 的跟踪速度因子,越大过渡越快但越容易引入噪声;h是积分步长,必须和仿真步长一致;beta1/beta2/beta3是 ESO 增益,通常按带宽整定,beta1≈3ωo、beta2≈3ωo²、beta3≈ωo³;b0是控制增益的估计值,它不准的话z3补偿会反向放大误差。fal函数在误差小于delta时退化成线性区,避免小误差下的抖振,delta一般取采样步长的几倍。
2.3 被控对象:汽车模型怎么接进来
汽车场景下被控对象一般是二自由度自行车模型或横摆动力学模型,状态量是横摆角速度和质心侧偏角,输入是前轮转角或附加横摆力矩。plant_model.m里通常写成状态空间形式,用欧拉法或四阶龙格库塔推进。这里有个容易忽略的点:ADRC 的b0要和控制输入通道对应,如果输入是附加横摆力矩,b0的量纲是 1/转动惯量;如果输入是前轮转角,b0里还要带上轮胎侧偏刚度。接错通道,ESO 估出来的z3会一直往一个方向漂,曲线看着像“积分饱和”,其实是模型和控制器对不上。
% plant_model.m 二自由度汽车模型单步推进(简化示意) function [x_next, y] = plant_model(x, u, p) % x = [beta; r],质心侧偏角、横摆角速度 beta = x(1); r = x(2); % 轮胎侧偏力(线性区) Fyf = p.Cf * (u - beta - p.a * r / p.vx); Fyr = p.Cr * (-beta + p.b * r / p.vx); % 动力学方程 beta_dot = (Fyf + Fyr) / (p.m * p.vx) - r; r_dot = (p.a * Fyf - p.b * Fyr) / p.Iz; x_next = x + p.h * [beta_dot; r_dot]; y = r; % 以横摆角速度为输出 endCf/Cr是前后轮侧偏刚度,a/b是质心到前后轴距离,m是整车质量,Iz是横摆转动惯量,vx是纵向车速。这套模型在侧偏角小于 3~5 度时够用,做大转角工况会失真,仿真里如果发现高速大转角下跟踪突然发散,先怀疑模型线性区假设,而不是 ADRC 参数。
3. 跑起来:从打开工程到第一条可用曲线
3.1 环境与运行步骤
MATLAB 版本不用太新,R2016b 以后基本都能跑,因为这类工程很少用新语法。不需要额外工具箱,纯基础 MATLAB 就够。步骤按这个顺序走:
- 把整个文件夹设为当前工作路径,别只打开
main.m,否则子函数找不到。 - 先运行
params.m,确认工作区里参数都加载了,尤其是b0、h、beta1~3。 - 运行
main.m,看命令行有没有报“未定义变量”或“维度不匹配”。 - 第一轮先把参考信号设成阶跃,看响应有没有超调、稳态误差。
- 再换成正弦或双移线参考,看跟踪相位滞后。
% main.m 运行骨架(简化示意) clear; clc; close all; p = params(); % 加载全部参数 x = [0; 0]; % 初始状态 u_prev = 0; log = zeros(p.N, 4); % 记录 [参考, 输出, 控制量, z3] for k = 1:p.N t = (k-1) * p.h; v = ref_signal(t, p); % 参考信号 [u, p.z1, p.z2, p.z3] = adrc_core(v, x(2), u_prev, p); [x, y] = plant_model(x, u, p); log(k, :) = [v, y, u, p.z3]; u_prev = u; end plot_result(log, p);p.N是总步数,等于仿真时长除以步长;ref_signal是参考信号生成函数,阶跃、正弦、双移线都从这里切。log里特意记了z3,因为调试时最有用的一列就是它——z3应该在有扰动时快速变化、无扰动时回到零附近,如果它一直单调漂,说明b0或 ESO 增益有问题。
3.2 参数整定的顺序
ADRC 参数多,但整定有固定顺序,乱调会互相打架。我一般按这个顺序来:
先定h,等于仿真步长,不要动。再定b0,用被控对象在额定工作点的“输入到输出”静态增益倒数估算,估不准就先给个数量级对的値。然后整 ESO 带宽ωo,从beta1=3ωo起,ωo先取控制带宽的 3~5 倍,看z3能不能跟上扰动。最后整 NLSEF 的beta_f1/beta_f2,先只留比例项,加到响应够快再加微分项压超调。TD 的r放最后调,它只影响过渡过程平滑度,不影响稳态。
提示:每改一个参数就重跑一次并保存曲线,别一次改三个。ADRC 的参数耦合比 PID 强,一次改多个根本分不清是谁的功劳。
3.3 结果怎么读
跑完至少看三张图:跟踪曲线(参考 vs 输出)、误差曲线、z3曲线。跟踪曲线看超调和上升时间;误差曲线看稳态有没有偏置;z3曲线看扰动估计是否合理。如果跟踪曲线有高频毛刺,先查h和delta是否匹配;如果误差曲线有缓慢漂移,查b0;如果z3在无扰动时明显非零,查 ESO 增益是否过大把噪声当扰动放大了。这三张图基本能定位八成问题。
4. 避坑与排查:仿真跑不通时先看这几条
4.1 曲线高频抖振
现象:输出曲线像加了噪声,步长越小抖得越厉害。原因通常是fal函数的delta设得太小,误差在零点附近反复穿越线性区边界,或者 ESO 增益beta3过大,把数值噪声当扰动放大。解决:把delta调到h的 5~10 倍,beta3按ωo³重新算一遍,别凭感觉加。
4.2 稳态误差消不掉
现象:跟踪阶跃参考时输出稳定差一截,加大反馈增益也没用。原因多半是b0偏大,导致z3/b0补偿不足,等效于控制量整体偏小。解决:把b0往下调 10%~20% 试,或者直接用被控对象静态增益倒数重算。注意b0偏小会导致超调,调的时候两边看。
4.3 ESO 估计发散
现象:z3在几秒内冲到很大值,控制量饱和。原因常见于 ESO 离散化用了前向欧拉但步长偏大,或者u_prev没有正确回传(比如初始化成 0 但实际第一拍控制量很大)。解决:确认adrc_core的输入u_prev是上一拍实际施加的控制量,不是本拍算出来的;步长大于 1ms 时考虑换四阶龙格库塔离散。
4.4 换参考信号就崩
现象:阶跃调好了,换正弦参考立刻跟不上。原因是 TD 的r太小,过渡过程安排得太慢,相位滞后累积。解决:把r按参考信号最大加速度的 2~3 倍估,正弦参考下r要明显大于阶跃时的值。这不是控制器问题,是 TD 没跟上参考。
4.5 汽车模型高速段失真
现象:低速工况跟踪很好,车速一高就发散。原因是线性轮胎模型在大侧偏角下失效,Cf/Cr常数假设不成立。解决:仿真里把车速限制在线性区范围内,或者换魔术公式轮胎模型;如果只是验证 ADRC 结构,没必要在轮胎模型上死磕,把工况收窄更省时间。
5. 二次开发:把仿真工程改成你自己的验证平台
这份工程最大的价值不是那几条曲线,是它把 ADRC 三件套拆成了独立函数,改起来边界很清楚。我一般会做三件事把它变成自己的平台。
第一,把adrc_core.m里的fhan和fal抽成独立文件,方便替换成线性 ADRC(LADRC)做对比。LADRC 就是把 TD 去掉、NLSEF 换成线性 PD、ESO 换成线性 ESO,改完两套控制器共用同一个plant_model,对比实验十分钟就能搭起来。
第二,把params.m改成结构体数组,支持多组参数批量跑。下面这个写法我常用,跑参数扫描时不用手改:
% 批量参数扫描(简化示意) b0_list = [0.8, 1.0, 1.2] * p.b0_nominal; results = cell(numel(b0_list), 1); for i = 1:numel(b0_list) p.b0 = b0_list(i); results{i} = run_sim(p); % run_sim 封装了 main 里的循环 end compare_plot(results, b0_list);run_sim就是把主脚本的仿真循环包成函数,输入参数结构体、输出日志矩阵。这样改一个参数跑一组,比手动改脚本可靠得多。
第三,加一个扰动注入接口。ADRC 的卖点是抗扰,但原工程如果没加扰动,你根本看不出它比 PID 强在哪。在plant_model的输出端叠加一个阶跃扰动或正弦扰动,观察z3的响应和恢复时间,这才是能写进报告里的对比数据。
| 改造点 | 改动文件 | 验证方法 |
|---|---|---|
| 换 LADRC | adrc_core.m | 同工况对比超调与调节时间 |
| 参数扫描 | params.m+ 新增run_sim.m | 看b0失配下的鲁棒性 |
| 扰动注入 | plant_model.m | 看z3跟踪与恢复时间 |
| 换轮胎模型 | plant_model.m | 高速大转角工况是否仍收敛 |
有个血泪教训:改plant_model的时候一定要同步检查b0,模型一换,输入输出增益就变了,b0不跟着改,前面调好的参数全部作废。从那以后我每次换被控对象,都强制先把b0用静态增益重新标一遍再跑闭环,这个习惯帮我省了至少两次通宵排查。希望这份拆解能帮你把仿真跑通,再顺手改成自己的验证平台。
本文还有配套的精品资源,点击获取