恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
自抗扰控制ADRC实战指南:从原理到参数整定与工程落地
首页
资讯中心
/
自抗扰控制ADRC实战指南:从原理到参数整定与工程落地
自抗扰控制ADRC实战指南:从原理到参数整定与工程落地
发布时间:2026/9/16 8:02:25
1. 整体设计思路与核心构成拆解自抗扰控制ADRC这些年几乎成了运动控制和过程控制领域的标配级算法韩京清先生那套思路在工程现场救回了无数被PID参数折磨得焦头烂肺的项目。我第一次理解ADRC时最大的感触是它把扰动这个东西从被动捱打变成了主动认知——控制器不再只知道偏差大了就拼命动作而是先判断到底有什么外力和未建模动态在捣鬼再直接把这个捣鬼项抵消掉。这篇文章我准备照着工程落地的方式去讲适合已经被PID逼疯、刚接触ADRC或者已经在仿真里试过但调不出效果的人看。我先后在三类对象上做过ADRC直流电机速度环、带负载扰动的温度回路、还有一个带弹性形变的伺服位置系统。每次接手新对象时我仍然会先把韩京清先生提出的ADRC核心构成在脑子里过一遍跟踪微分器TD、扩张状态观测器ESO、非线性状态误差反馈控制律NLSEF。这三个模块各有分工合起来才叫完整的自抗扰控制。不会用公式堆出一座墙来劝退你——这篇的重点是把原理讲透把调试经验讲足。1.1 韩京清为什么要把总扰动当作一个状态来看传统PID眼里只有误差本身对它来说系统的非线性、参数摄动、外部负载变化都必须靠积分项去一点一点顶回来。问题在于积分作用是滞后的而且容易和饱和、超调焊死在一起。韩京清先生换了个角度如果我能实时估计出系统承受的总扰动到底是什么趁它还刚在输出端露出苗头就直接在旁边给它抵消掉那闭环特性就不再有扰动这回事了。这就是扩张状态的由来。常规状态观测器只估计系统自身状态比如位置和速度ADRC额外增加了一维去估计那个说不清来源的总扰动f(x1,x2,w,t)。这里的扰动不单指外部负载还包括模型里面写不出来的非线性项、摩擦、未建模动态。把所有可怕的不确定性统统装进一个变量里然后由ESO把它观测出来。这个思路之所以高效是因为它不再做精确建模这个工程上几乎不可能完成的壮举。做控制的人都有这种经历摩擦模型换一个温度就变了负载惯量换一个工况就变了。与其花半年辨识一个精美但脆弱的模型不如承认模型不可靠但可以用观测去补偿模型的不可靠。这就是ADRC工程价值最大的地方。1.2 三个核心模块的分工逻辑一个都不能少按韩京清先生提出的ADRC核心构成我们可以把整套算法拆成三个独立但协同的部分。首先是跟踪微分器TD。它的作用是安排过渡过程给参考输入先塑形。电机位置阶跃给定100°如果你直接让输出追着100°跑输出跑得再快误差一开始也是巨大的PID自然要冲过头。TD会把阶跃指令变成一条平滑的、速度受限的轨迹让实际对象跟着轨迹走而不是被阶跃本身踹一脚。用大白话说TD是在给控制器减负让误差从一开始就别那么大。然后是最关键的扩张状态观测器ESO。ESO的两路输入是实际控制量u和系统可测输出y输出则是被估计的各个状态以及那个额外的总扰动估计值。只要观测器设计得当它就能在扰动真正显形之前提前猜到扰动已经开始作用了。第三块是状态误差反馈控制律也就是NLSEF或用线性组合替代时的LSEF。它的任务是把系统看作一个被补偿后的纯积分串联对象来控制。因为ESO已经实时抵消了总扰动控制器面对的几乎就是一个干净、规矩、已知的动态方程这时候哪怕用占比很轻的PD组合也能把系统定格在期望轨迹上。三块之间的关系是一条清晰的链路TD给出希望的过渡状态ESO反馈出系统当前状态以及总扰动NLSEF根据期望状态减当前状态的误差去计算控制量同时加上扰动补偿项。回头你调试ADRC时如果出了问题基本都能定位到这三个环节中的某一个这是排查的最佳抓手。1.3 ADRC到底解决了PID的什么问题说ADRC是PID的升级版其实有点低估了它它更像是把PID中积分项承担的任务单独拎出来专业化处理。PID的积分项是无差别累计历史误差结果就是积分饱和、抗积分饱和逻辑复杂、整定参数互相牵制。ADRC里的ESO不一样它不给历史误差记账而是实时估计当前的扰动等价量。这带来一个非常明显的好处当扰动消失后补偿项会立刻衰减而不是像积分项那样惯性难收。我对这个问题特别有发言权。某次做温度控制对象有一个时变的换热系数PID调完后负载一变化输出一般都会先用一大段过冲告诉你说它的积分项刚才顶错了。换上ADRC后ESO在扰动起步的半个周期内就把估计值跟上了控制量里多了直接的前馈补偿过冲被压下去一大截。这就是自抗扰这三个字的真正含义不是躲着扰动走而是主动去识别它、抵消它让系统对外表现出抗扰特征。2. 核心细节解析与实操要点这里要深入到数学表达里但我会尽量把公式放到够用就行的程度。ADRC在原理层看着不难真正的门道全部藏在参数选择、离散化处理和对象特性匹配上。做控制器设计第一步永远是搞清楚对象属于什么阶次、什么类型因为ADRC的设计参数是随对象阶数变化的。2.1 从数学模型看ADRC要解决什么问题我们先假设被控对象是一个典型的二阶系统例如电机驱动下的质量-阻尼系统y f(y, y, w(t)) b0 * u其中y是输出u是控制量w是外部扰动。f这一项把系统加速度中除控制输入b0*u之外的所有成分全包进去了未建模摩擦、非线性刚度、参数漂移、外部负载都赖在这里。b0是控制增益的估计值是最需要工程经验去给定的参数。ADRC的设计目标就是让控制器对f完全免疫。办法分两步走第一步ESO把f当成一个新状态来观测。令x1yx2yx3f把原方程改写成状态空间形式。x3虽不可测但只要它能被观测出来我们就可以在控制量里显式减去它。需要注意的是这里隐含了一个假设总扰动是慢变的或者说它在一个控制周期内的变化足够小。好在绝大多数工程扰动满足这一条温度漂移、负载渐变、摩擦切换都够ESO追得上。第二步在控制量计算中加扰动补偿。控制器最终给对象的控制量是u (u0 - z3) / b0u0是误差反馈控制器算出的标称控制量z3是ESO给的总扰动估计。做完这一脚补偿系统从外部的角度看起来就像是一个纯的二重积分对象y u0控制设计就大大简化了。2.2 关键参数怎么选观测器带宽、控制器带宽和b0这里我直接用高志强老师那套基于带宽的线性ADRC参数化方法这是工程中最容易上手的路子。传统非线性ADRC有好多参数要试fal函数里的α、δ已经够让人头疼了。线性ADRC把观测器极点配置到同一位置控制器极点也配置到同一位置这样参数只剩三个控制器带宽ωc、观测器带宽ωo、控制增益b0。以二阶系统为例扩张状态观测器的增益矩阵为L [3ωo, 3ωo², ωo³]ᵀ这个经验的3-3-1结构来自于把ESO的特征方程(sωo)³展开。它保证观测误差按ωo的尺度指数收敛ωo越大观测器就越快看清真实状态和总扰动但代价是噪声会被放大。实际调试时ωo通常取ωc的3到10倍而不是越大越好。控制器那侧如果采用PD形式的控制律则两个增益取为kp ωc²kd 2ωc这同样是把期望闭环特征方程配置成(sωc)²的形式。换算一下就是你先决定系统期望的响应速度ωc然后自然得到控制器增益再根据观测器的噪声水平决定ωo。比PID调三个缠在一起的参数要直观得多。b0是唯一需要了解对象特性的参数。它代表单位控制量能产生多大加速度。估计b0太大会导致补偿过度太小则补偿不足。我的经验是先用对象开环阶跃响应粗算出一个量级然后在仿真里做±50%的扫描看系统稳定性和抗扰性能是否还能维持。ADRC对b0有一定的鲁棒性但偏差超过两倍基本就会出问题。2.3 fal函数和离散化实现时容易踩的坑非线性ADRC里有一个知名角色非线性函数fal(e, α, δ)。它的作用是小误差大增益、大误差小增益比线性比例更聪明地平衡了快速性和小超调。但经典fal函数在误差e0附近存在切换不光滑的问题处理不当会产生稳态抖动。实际工程中我会优先推荐直接用线性增益也就是线性ADRC简单、参数少、稳定性分析工具也齐全性能已经足够覆盖绝大多数场景。想追求极限性能时再加非线性而且要在仿真里反复验证离散采样对fal的影响。离散化是另一个重灾区。ADRC是连续域设计、离散域实现的若直接拿连续公式粗放地差分化观测器很容易在高频下失稳。我踩过最典型的坑是仿真里连续模块看起来一切正常一部署到实际控制器里速度环就开始滋滋作响。后来查明原因EWO的离散化步长和观测器带宽不匹配。经验值是保证ωo * Ts ≤ 0.1其中Ts是控制周期。如果控制周期1ms观测器带宽就不宜超过100rad/s否则必须换更高阶的离散化方法或提高采样率。3. 实操过程与核心环节实现这部分我带大家走一遍完整设计流程。为了兼顾可读性我选择一个非常常见的对象一阶惯性加纯滞后系统例如一个电加热炉的简化模型。别担心一阶对象一样能用ADRC而且恰恰是这种对象最能体现ADRC的优势。3.1 以一阶对象为例设计一套完整的ADRC典型一阶对象可以写为y -a * y b * u其中a是对象自身时间常数相关的系数b是增益。做ADRC的关键是我们不知道a的精确值甚至它可能在运行中漂移而ADRC的价值就体现在这里。我们把模型改写成y f b0 * u其中f -a*y (b-b0)*u这里的f就是总扰动它把参数不确定性和实际的未知动态全包了进去。由于这是一阶对象扩张状态只需要加一个维度ESO的结构是三阶但在内部状态只需要两个。设x1yx2f状态空间方程是x1 x2 b0*u x2 f这里假设f是慢变的即f的值有限且可被估计。非常关键的一点是对于一阶对象我们只需要一个一阶TD来平滑给定值。TD的形式为v1 v2 v2 -r * sign(v1 - v_ref v2*|v2|/(2r))也可以简单地用一阶惯性安排过渡但在标准形式上韩京清先生用的是二阶TD。我这里用二阶为了在整个调试过程中看到平滑的阶跃响应。ESO在离散形式下我推荐用向前欧拉加观测器极点配置的方式e z1 - y z1 z1 h * (z2 - β1e b0u) z2 z2 h * (-β2*e)其中β1 2ωoβ2 ωo²。这里需要注意的是z1对输出的估计和z2对总扰动的估计同时更新。因为是一阶对象观测器增益取为2ωo和ωo²。控制律则直接用比例加扰动补偿u (ωc * (v1 - z1) - z2) / b0可以注意到对于一阶系统控制器没有微分项只有一个误差比例因为被控量的导数信息已经包含在状态估计里了。这也是ADRC工程实现简单的地方。整体算法只有三个设计参数ωc、ωo和b0不用研究复杂的非线性函数调试起来非常愉快。3.2 从MATLAB到C代码各段实现细节逐条讲很多人卡在原理懂了但代码写不出来。我分享一段我常用的C语言风格伪代码既能用于仿真也能直接移植到嵌入式控制器里。typedef struct { float b0; // 控制增益估计 float h; // 采样周期 float wc; // 控制器带宽 float wo; // 观测器带宽 float beta1, beta2; float z1, z2, v1, v2; float u; } ADRC_1st; void adrc_init(ADRC_1st *adrc, float b0, float h, float wc, float wo) { adrc-b0 b0; adrc-h h; adrc-wc wc; adrc-wo wo; adrc-beta1 2.0f * wo; adrc-beta2 wo * wo; adrc-z1 0.0f; adrc-z2 0.0f; adrc-v1 0.0f; adrc-v2 0.0f; } float adrc_run(ADRC_1st *adrc, float ref, float y) { // 1. 跟踪微分器 float v1_dot adrc-v2; float v2_dot -2.0f * adrc-wc * adrc-v2 - adrc-wc * adrc-wc * (adrc-v1 - ref); adrc-v1 adrc-h * v1_dot; adrc-v2 adrc-h * v2_dot; // 2. 扩张状态观测器 float e adrc-z1 - y; adrc-z1 adrc-h * (adrc-z2 - adrc-beta1 * e adrc-b0 * adrc-u); adrc-z2 adrc-h * (-adrc-beta2 * e); // 3. 控制律 float u0 adrc-wc * (adrc-v1 - adrc-z1); adrc-u (u0 - adrc-z2) / adrc-b0; return adrc-u; }这段代码里TD我用了二阶临界阻尼形式的线性跟踪微分器而不是韩京清先生原版带符号函数的非线性TD。两者的区别是非线性TD能获得时间最优的过渡过程但符号函数在离散实现时容易出现抖动尤其当参考接近目标时。线性TD用在大多数过程控制中完全够而且参数可预测性好。ESO部分注意别把u的更新顺序写反了。在同一个采样周期里u应该使用上一周期计算出的控制量也就是我代码里adrc-u而不是本次新计算的u。原因是对象接收到的控制量本来就是上一拍的值这一步错了观测器估计会产生一拍滞后误差抗扰性能直接打折。3.3 参数整定的递进过程跟着做就能完成闭环以单个温控回路为例假设控制增益b0估出来大约等于0.8采样周期0.01秒。参数整定顺序如下第一步先开环确定b0。给一个固定的控制量阶跃测出稳态输出和近似时间常数b0近似等于稳态变化率/控制量。这个值允许有一定误差但方向不能反。第二步设定ωc。期望闭环时间常数τ为1秒那么ωc就取1/τ也就是约1rad/s。这个参数直接决定了对参考轨迹的响应速度。调大ωc系统变快但控制量也更猛烈实际中被执行机构的饱和限制住是常有的事。第三步设定ωo。按ωo5ωc起步在仿真中逐渐增大观察ESO对突加扰动的估计速度。你会在某个区间看到抗扰性能明显变好再继续增加时系统的高频噪声开始变得不可接受控制量会出现细微的颤抖。我当时把ωo从5rad/s一路试到50rad/s最终定在了30rad/s抗扰提升了三倍多而噪声还能接受。第四步打一个扰动测试。运行时给对象注入一个阶跃扰动观察输出恢复时间。ADRC比PID恢复得要快得多而且几乎无超调。如果恢复过程中输出出现振荡多半是ωc太高而ωo跟不上把ωo再提一档或把ωc降一点问题会立刻缓解。4. 常见问题与排查技巧实录下面这些坑是我做ADRC以来被反复暴击过的地方。每个问题我都给了具体现象和排查方向希望能帮大家缩短调试周期。4.1 高频噪声抖动的根源与解法现象控制量输出像锯齿一样高频抖执行机构发热明显嗡嗡声不断。最直接的原因是ωo太高了。ESO把测量噪声当成了高频扰动去估计然后控制量拼命去抵消这个噪声结果就是把噪声引入并放大进控制通道。解决思路有两个一是降低ωo到噪声可接受的程度二是在测量通道加低通滤波但要注意滤波会引入相位滞后反过来限制ESO的估计带宽。我的偏好在方案协调上如果对象本身响应慢那就压低ωo如果对象快且噪声大就考虑把传感器换好一点或者用状态估计协同滤波。仿真里模型是干净的很容易把ωo调到很高但上机台之前一定要把实际噪声数据加进仿真里试一遍否则到了现场才出现高频抖动排查起来十分痛苦。4.2 b0失配会导致什么问题现象同样的ADRC参数在仿真里抗扰很优秀到了真实设备上却出现奇怪的稳态误差或者控制量忽大忽小。b0表示的是控制作用被模型放大的倍数。如果b0给得比真实值大那么系统会认为一级控制量产生了过大的加速度实测状态没跟上这个预期ESO就把这部分差异全都归到总扰动里。结果可能是稳定了但控制量偏大、动作偏猛反过来b0给小了补偿作用不足稳态和动态性能都会打折。排查b0失配有一个很实用的办法把运行中的ESO估计值z2记录出来加一次大的扰动阶跃如果z2跟着出现大幅跳动而且控制量同步猛顶则b0很可能偏小如果z2里混着很多高频成分则b0可能偏大。这个定性判断我屡试不爽。4.3 初始时刻的输出跳变和积分型ESO问题现象控制器一上电输出参考还没动控制量突然冲到一个很大的值。这通常是因为ESO的初始状态和真实状态不匹配。如果z1初始为0而实际输出y已经有一个较大的初值那么观测误差在启动瞬间是巨大的观测器会猛发力去修正它反映到控制通道就是一次冲击。解决方法是把ESO的两个初始状态直接用当前测量值初始化z1(0) y(0)z2(0) 0。对于温度、压力等有缓变初值的对象这个操作能省掉一大半启动电流冲击。对于更复杂的系统ESO还要防止积分型输出带来的稳态问题。如果对象是Type 1型系统含积分环节ESO估计的f在稳态时会趋近0系统保持无静差但如果对象本身没有积分作用而又要求位置无静差单靠一阶ADRC做不到。此时要么增加观察器的阶数要么在控制律中保留一阶积分作用。别想着只要上了ADRC就自动消除一切静差对象结构和控制律结构得匹配才行。5. 个人经验与扩展用法5.1 给初学者的三个建议都是踩过的坑换来的第一不要一上手就搞非线性ADRC参数能从十几个少到三个是最好的起点。线性ADRC在技术上已经完全覆盖大多数产品级需求先跑通它再谈非线性优化。我见过太多人把fal函数的α从0.5调到0.9、δ从0.01改到0.1调了半天也没搞清楚自己在做什么纯属浪费精力。第二做ADRC前先把对象的时间尺度和采样周期搞清楚。高带宽的电机系统需要1kHz以上的控制周期而温控回路10Hz都嫌快。当你发现ESO在实际系统中无论如何都追不上扰动时大概率不是算法问题而是你的采样周期相对于对象动态太慢了。把控制周期缩短十倍的改进往往比调任何参数都有效。第三调试时永远先做离线仿真验证再把同一套参数搬到真实系统。尤其是b0和噪声水平一定先在仿真里把最恶劣的工况跑一遍。ADRC不是万能药但它比PID更贴近模型辅助的边缘好处是参数清晰、行为可预测坏处是你必须认真对待对象的基本特性。5.2 场景选型什么时候该用ADRC什么时候纯粹是杀鸡用牛刀我给一个很务实的判断标准当你的对象存在明显的未建模动态、而你又不想花大力气做精确辨识时ADRC会很香。比如机械臂关节的负载惯量会随位形变化电机驱动系统会有死区、摩擦和弹性变形热工过程会有大惯性和纯滞后这些场景ADRC的补偿效果远远优于PID。反过来如果你的对象是一个干净的、慢变的、单一工况的系统PID已经完全够用不必为了赶时髦上ADRC。ADRC的代价是更多的计算资源、参数规范和维护门槛。以电机速度环为例ADRC只需要增加很少的运算量却能明显改善负载突变时的转速降落这种场景就值得上。我还想提一个ADRC的扩展用法把它当作一个扰动观测器单独抽出来使用。哪怕你暂时不想替换PID也可以只用ESO的输出z2做补偿在原有PID控制量上叠加一个前馈量。这种渐进式改造项目已经帮我在多个老设备上实现了性能升级而不用大规模改动原有的控制架构。这大概也是韩京清先生控制思想里最让人受用的一点不是推翻重来而是先学会看见扰动再用合适的方式抵消它。