☰
自抗扰控制ADRC原理与工程实现:从PID进阶到现代控制
2026/10/4 7:13:21 网站建设 项目流程

聊到工业控制里最简单也常用的控制器,大家第一反应肯定是PID。PID确实改变了众多行业的控制方式,但真正在现场跑过伺服、温控、电源项目的工程师心里都清楚:PID从来不是万能钥匙。被控对象一强耦合、强非线性,或者外部扰动特别猛,PID那三个增益调来调去,往往不是超调就是抖动,很难找到一个舒服的工作点。

韩京清先生提出的自抗扰控制(Active Disturbance Rejection Control,ADRC)给的是另一条路:它不执着于把被控对象模型建得多准,而是把系统内部不确定性、外部扰动统统装进一个“总扰动”里,由扩展状态观测器实时估计出来,再在控制量中把它补偿掉。这样一来,再复杂的系统,在控制器眼里都被拉回了标准的积分串联结构,后续设计就简单了。

这篇文章把ADRC的原理和控制器设计从头到尾拆一遍,重点放在一阶对象的工程实现、参数整定和调试经验上。适合正在做伺服驱动、运动控制、电力电子、温控等项目的工程师,也适合想从PID进阶到现代控制理论的同学,看完之后从零手写一个能跑的ADRC基本没问题。

1. 自抗扰控制到底要“抗”什么?

1.1 PID为什么不够用

做控制这些年,我越来越觉得PID的问题不是它不好学,而是它的结构决定了它在某些场景下注定吃力。PID的三个增益KP、KI、KD,本质都是对误差的“事后处理”:先出现偏差,再想方设法把偏差压回去。面对线性、时不变、低扰动的对象,这个思路够用;可一旦对象变复杂,短板就暴露了。

第一个痛点是快速性和超调的矛盾。想让阶跃响应更快,最直接的做法就是把比例增益调大,结果响应确实快了,超调也跟着来了。经典的解决办法是引入微分项,让控制器提前“踩刹车”,但理想微分在实际系统中并不存在。用差分近似微分,噪声会被放大得一塌糊涂,所以我见过很多现场工程师最后干脆只用PI,把D关掉。

第二个痛点是扰动抑制太被动。外部扰动出现后,系统要等输出已经发生偏差,控制器才有所动作。这种被动补偿的方式,在扰动小、变化慢的场景下还能忍,但如果扰动来得又急又猛,比如电机负载突变、电网电压跌落,PID的恢复速度常常跟不上。

第三个痛点更隐蔽:PID本质上是拿一个固定结构的控制器去适配不同工况。工作点一变,对象特性就变,当初调好的参数可能立刻失效。这也是为什么很多设备在不同负载条件下表现差异巨大,最终只能靠分段PID或者模糊PID这类补丁来缓解。

1.2 总扰动:把“未知”请进状态空间

回到韩京清先生的原始思考。他关注的不是“怎么调PID更好”,而是“为什么控制问题那么依赖精确模型”。当时的现代控制理论虽然漂亮,但高度依赖对象模型,模型一不准,理论就很难落地。而经典PID虽然不依赖模型,却又不具备对扰动的主动抑制能力。

韩京清的关键洞察是:能不能把系统内部的建模误差、参数变化和外部扰动合并成一个“总扰动”来处理?

考虑一个一阶系统:

x_dot = f(x, w, t) + b * u

y = x

这里x是系统状态,u是控制输入,y是输出,w是外部扰动,f(x, w, t)包含了内部动态、外部扰动、未建模部分的所有影响。如果我能把这个f实时估计出来,并在控制量中加以抵消,那么系统就变成了一个理想的积分器:

x_dot ≈ u0

这种把“未知动态”统一视为一个扩展状态的思想,就是ADRC自抗扰的核心。它不要求你精确知道f长什么样,不要求扰动可测量,只要求系统在结构上满足输入输出关系——这在工程上是极大程度的解放。

为什么叫“自抗扰”?因为系统不是依赖外部扰动模型或前馈传感器来对抗扰动,而是靠回路内部的状态观测器把扰动“看”出来。就像开车上坡,你不需要知道坡度到底多大,只需要根据车速下降的程度和油门开度,就能反推出此时的等效阻力,然后自动补油。ADRC里的扩展状态观测器,干的就是这个“反推阻力”的活。

2. ADRC三大件的原理与分工

2.1 跟踪微分器TD:既平滑信号,又提供微分

跟踪微分器Track Differentiator,作用是解决两个问题:一是从带有噪声的参考信号中提取微分,二是安排过渡过程。

最速跟踪微分器的连续形式写作:

v1_dot = v2

v2_dot = fst(v1 - v, v2, r, h0)

其中v是原始参考输入,v1是v的跟踪输出,v2是v1的微分,fst是最速控制综合函数。简单说,v1会以尽可能快的速度逼近v,但它的变化速率受r约束,不会一下子跳过去。v2就是v1的变化速度,由于是通过对v1的导通得到的,不会像直接对v求差分那样把噪声放大。

它的价值在阶跃输入时体现得最明显。如果直接用阶跃作为控制目标,误差信号一上来就是满幅值,控制器会立刻输出最大控制量,系统很容易超调。但经过TD之后,阶跃被安排成一个斜率受限的斜坡,系统的实际目标在平滑地靠近最终值,超调量大幅下降。

r的含义可以理解为目标的“最大变化速率”。r越大,过渡过程越快,但也越接近直接阶跃输入;r越小,过渡越平缓,系统越稳。现场调试时,可以先根据执行机构允许的最大变化率设定r,再去微调。

2.2 扩展状态观测器ESO:全系统最关键的“侦察兵”

扩展状态观测器是ADRC真正核心的部分,也是理解ADRC的一道坎。它的任务是:在只知道输入u和输出y的前提下,估计出系统的状态以及总扰动。

还是看一阶对象。构造扩张状态观测器:

z1_dot = z2 - β1 * e

z2_dot = z3 - β2 * e + b0 * u

z3_dot = -β3 * e

其中e = z1 - y,z1估计x(系统输出),z2估计x_dot(输出的变化率),z3就是扩展出来的那个状态,用来估计总扰动f。β1、β2、β3是观测器增益。

初看这个结构会觉得奇怪:为什么那个e同时出现在三个方程里?实际上这就是观测器的修正机制。想象你有一个系统的“虚拟副本”,它按照你对系统的理解运行着。你把真实输出和虚拟副本输出之间的误差,分别按不同比例反馈到副本的各层状态上,不断校正它的内部值。只要反馈增益选得合适,过不了多长时间,z1就会贴近真实输出y,z2贴近真实变化率,z3逼近真实总扰动f。

信号流的方向是:输出误差e先影响到z1估计,z1的修正再传导到z2,z2的修正再传导到z3。这就像一支小队逐级汇报敌情:侦察兵发现偏差,班长调整位置,排长得到更宏观的态势判断。

非线性版本的ESO会把β1 * e这类线性项替换成基于fal函数的非线性项:

fal(e, α, δ) = sign(e) * |e|^α,当|e| > δ时

fal(e, α, δ) = e / δ^(1-α),当|e| ≤ δ时

α小于1时,小误差对应高增益,理论上控制精度可以更高。但工程上,非线性ESO的参数太多、物理意义不直观,所以大量产品中用线性ESO(LESO)替代,也就是把α直接取1,再用带宽法整定β参数。很多商业实现中所谓的LADRC,本质上就是这套线性化方案,效果足够好,参数还少。

2.3 状态误差反馈与扰动补偿:剩下的都是标准流程

有了TD提供的过渡参考信号v1、v2,有了ESO提供的状态估计z1、z2和扰动估计z3,控制律的设计就变得非常“教科书”。

取误差:

e1 = v1 - z1

e2 = v2 - z2

对于一阶对象,反馈律可以设计成P控制形式:

u0 = kp * e1

对于二阶对象,则常用PD形式:

u0 = kp * e1 + kd * e2

最终的控制量是:

u = (u0 - z3) / b0

这一步就是扰动补偿。ESO估计出的z3是当前系统承受的总扰动,把它从控制量里减掉,相当于在控制器内部生成了一个反向的“抵消信号”。除以b0,是为了把虚拟控制量u0换算成实际执行器能理解的控制量,因为系统本身的输入增益是b,而我们使用的是一个估计值b0来近似b。

把u代回系统方程:

x_dot = f + b * u ≈ f + b * (u0 - z3) / b0 ≈ f + u0 - z3 ≈ u0

只要z3能跟上f,b0与b的偏差不太大,系统就会近似成一个积分器:x_dot ≈ u0。在这个近似模型下设计控制器,什么极点配置、带宽设计,都是信手拈来的事。

3. 一阶ADRC控制器设计与离散化实现

3.1 设计一个完整的一阶ADRC需要哪些步骤

下面把设计流程整理成可以直接抄的步骤。这里以一个典型一阶对象为例,比如永磁同步电机的速度环、加热炉的温度控制等效模型,核心思想是一致的。

第一步:确定对象的阶次和控制增益b0。一阶对象在控制量阶跃作用下,输出是近似匀速变化的,因此b0可以通过开环阶跃实验标定。给一个固定控制量u_open,测量输出的变化率Δy/Δt,则b0约等于(Δy/Δt) / u_open。

第二步:设计TD。设定速度因子r和滤波因子h0。r根据执行机构允许的目标变化速率来选,h0一般取5到10倍的采样周期。

第三步:设计ESO。如果用线性ESO,增益按带宽法设定:

β1 = 3 * ω0

β2 = 3 * ω0²

β3 = ω0³

其中ω0是观测器带宽。z1、z2、z3初始赋值为0。

第四步:设计控制律。一阶对象用P控制即可,kp取期望闭环带宽ωc。工程上一般要求ωc小于ω0的三分之一到五分之一。

第五步:离散化。用最简单的欧拉法离散即可,把微分方程改写为差分方程。采样频率至少要大于10倍的ω0,否则观测器会失真。

3.2 离散化核心公式与参考代码

离散化后的核心公式:

v1(k+1) = v1(k) + h * v2(k)

v2(k+1) = v2(k) + h * fst(v1(k) - v(k), v2(k), r, h0)

e(k) = z1(k) - y(k)

z1(k+1) = z1(k) + h * (z2(k) - 3ω0e(k))

z2(k+1) = z2(k) + h * (z3(k) - 3ω0²e(k) + b0*u(k))

z3(k+1) = z3(k) + h * (-ω0³*e(k))

e1(k) = v1(k) - z1(k)

u0(k) = kp * e1(k)

u(k) = (u0(k) - z3(k)) / b0

完整参考代码如下,基于Python写,便于理解,实际移植到C语言时只需加上变量定义和限幅:

import math h = 0.001 # 采样周期 1ms r = 100.0 # TD速度因子 h0 = 0.005 # TD滤波因子 b0 = 50.0 # 控制增益估计 w0 = 30.0 # ESO带宽 kp = 10.0 # 控制律比例增益 u_max = 100.0 # 控制量上限 u_min = -100.0 # 控制量下限 def sat(x, up, low): return max(low, min(up, x)) def fst(v1, v2, v, r, h0): d = r * h0 d0 = d * h0 y = v1 - v + h0 * v2 a0 = math.sqrt(d * d + 8 * r * abs(y)) if abs(y) <= d0: a = v2 + y / h0 else: a = v2 + 0.5 * (a0 - d) * math.copysign(1, y) return -r * sat(a / d, 1, -1) # 初始状态 v1 = 0.0 v2 = 0.0 z1 = 0.0 z2 = 0.0 z3 = 0.0 u = 0.0 # 假设输出函数 def plant_output(x, u): return x # 一阶对象对应关系 # 主控制循环 for step in range(10000): # 参考输入,比如一个阶跃 v_ref = 10.0 if step >= 100 else 0.0 y = plant_output(z1, u) # 这里实际应为真实传感器读取 # 跟踪微分器TD fst_value = fst(v1, v2, v_ref, r, h0) v1 += h * v2 v2 += h * fst_value # 扩展状态观测器ESO e_eso = z1 - y z1 += h * (z2 - 3 * w0 * e_eso) z2 += h * (z3 - 3 * w0 * w0 * e_eso + b0 * u) z3 += h * (-w0 * w0 * w0 * e_eso) # 控制律 u0 = kp * (v1 - z1) u = (u0 - z3) / b0 u = sat(u, u_max, u_min) # 将u施加到真实被控对象,这里由具体硬件完成

注意代码中植物输出只是示意,真实系统应从传感器读取y。ESO更新时使用的u必须是限幅后的实际控制量,这一点极其重要,后面会专门讲。

3.3 参数初值与带宽法的对应关系

初次接触ADRC,最大的心理障碍是参数多。TD有两个参数r、h0,ESO有一个ω0,控制律有一个kp,再加上b0和采样周期h,看着有六七个参数。如果像调PID那样这些参数彼此影响,那确实很难。但ADRC参数实际上是分组解耦的:TD只管参考信号整形,ESO只管状态和扰动估计,控制律只管反馈增益。ACR参数之间是弱耦合。

用带宽法之后,初始设置就简单多了:

参数含义初始设置建议
h采样周期根据硬件能力,尽量小,1ms以内较常见
rTD速度因子参考目标最大变化率,越小过渡越慢
h0TD滤波因子取5到10倍h,主要用于减小微分噪声
b0控制增益估计开环阶跃实验获得,有±20%误差可接受
ω0ESO带宽取期望闭环带宽ωc的3到5倍
kp控制律增益一阶对象直接取ωc,即期望闭环带宽

需要注意,对于一阶对象,即使采用的是三阶ESO,反馈控制律用P控制就足够了。二阶对象才需要PD控制,此时需要额外引入v2和z2构成微分通道。

4. 参数整定与工程实施的8个细节

4.1 b0标定是成败的第一步

几乎所有现场调ADRC翻车的项目,最后都能回溯到b0没标准。b0是控制器对“控制输入多大程度影响输出变化率”的估计,它直接决定了扰动补偿量的比例。b0偏大,控制器会认为对象对输入很敏感,实际没那么敏感,补偿不足,系统偏软,响应迟缓;b0偏小,补偿过头,系统容易振荡。

标定方法不复杂。开环状态下,给被控对象一个固定控制量,比如伺服驱动器里直接给一个固定电流值,记录速度响应曲线。稳态段斜率就是Δy/Δt,用斜率除以控制量得到b0。为减小扰动影响,多测几组不同控制量,取平均值。

实际经验是,ADRC对b0误差有一定容忍度,大概正负20%以内都能工作。但超出这个范围,系统要么发软,要么发振。现场如果发现系统对扰动的补偿方向正确但幅度不对,优先怀疑b0。

4.2 ESO带宽、控制带宽与采样周期怎么配

ESO带宽ω0决定观测器跟踪扰动多快,控制带宽ωc决定闭环响应的刚度。两者关系经验上取:

ωc < ω0 / 3

ω0 < fs / 10

其中fs是采样频率。第一条保证观测器比控制器快,否则控制环会拿到一个滞后的扰动估计,补偿动作会“晚半拍”,反而造成振荡。第二条保证离散化不丢信息,采样太慢时,观测器看到的是“稀疏”的信号,很难精确重建快速变化的扰动。

我从项目里的体会是,一上来不要把ω0怼得太高。本子上可以算得很漂亮,但实际系统有测量噪声、有执行器延迟,ω0太高后控制量高频抖得厉害。调试时从低到高慢慢加ω0,直到扰动恢复速度不再明显改善,反而噪声变大,这个拐点就是当前系统条件下的最优观测器带宽。

4.3 非线性fal函数和线性ESO怎么选

韩京清原版ADRC用的是非线性ESO,理论上小误差高增益的特性确实优越。但工程调试中我发现,直接用非线性ESO容易让参数调整变得很抽象。fal函数里的α1、α2、α3、δ四个参数,哪个影响什么,很难从时域曲线上直观判断。

所以我的建议是:第一版调试一律用线性ESO。让系统先动起来,把b0、ω0、kp这些关键参数对齐,确认扰动补偿正确、闭环稳定之后,如果有进一步提升性能的需求,再按原版非线性结构去优化。很多量产产品最终用的也是线性化版本,性能完全够用。

如果坚持用非线性ESO,δ参数值得说一句。δ是线性段区间,理论上δ越小,小误差时增益越大,跟踪精度越高;但δ太小会放大噪声,容易引起高频极限环。一个可行策略是:先取δ=1%到5%的量程,再逐步减小到系统开始抖动的临界值之前停下。

4.4 控制量饱和与抗饱和处理

ESO内部维护着一个对被控对象的“数字副本”,它认为控制量u是真实施加到对象上的。一旦控制器输出达到执行器限幅,真实施加的控制量就不是计算值,而是限幅后的截断值。如果此时ESO还用未饱和的u去更新z2、z3,它就会严重误判总扰动,等退出饱和时,ESO状态已经漂移,系统会出现大幅超调或迟滞。

处理办法只有一条:送给ESO的u必须是实际限幅后的值。在代码里,先对u做限幅,再用限幅后的u去更新ESO。

更进一步,可以做抗饱和反馈。计算饱和差值u_sat = u_calc - u_actual,把这个差值以一定比例补偿到ESO的z2更新中,这样观测器在饱和期间能感知到执行器已截断,不会盲目积分。常用形式是在z2方程中加一项k_sat * (u_calc - u_actual),k_sat取与β2相当的量级即可。

4.5 测量噪声下面怎么稳住观测器

ESO的性能上限很大程度上由测量噪声决定。z3是扰动估计,但它是由输出误差e一路放大得到的,测量噪声会被带到z3,再进入控制量。很多工程师把ω0调高后,扰动恢复倒是快了,但电机开始嗡嗡响,就是这个原因。

噪声处理有三个方向。一是降低ω0,牺牲一点扰动跟踪速度换控制量平顺;二是在测量通道加低通滤波,滤波引入的相位延迟会限制ω0,需要平衡;三是在采样值送入ESO之前做轻度的滑动平均,注意这种滤波会让ESO看到更平滑的信号,但也有延迟,不能过度使用。

另外一个常用技巧是,不要在控制量u上直接加低通滤波,那是拿系统性能换好看曲线。而是要先把速度/位置反馈信号洗干净,再做ESO。滤波位置放错,控制品质损失很大。

4.6 TD的r和h0到底怎么取

r决定了系统的过渡过程快慢,直观理解就是“目标变化的最大速率”。项目里我会根据实际执行机构能力来定:电机空载所能达到的最大加速度,系统允许的最大参考变化率,或者工艺要求的最短爬坡时间。把这些算成每秒变化多少量,r就取对应量级。

r太大,TD几乎直接放行输入阶跃,过渡过程形同虚设;r太小,系统反应迟钝,参考信号半天爬不到位,会让人觉得“控制很肉”。

h0是滤波因子,作用在fst函数内部,影响过渡过程的平滑程度和噪声抑制。工程上取5到10倍的采样周期比较稳妥。采样周期1ms时,h0取5到10ms,配合r的整定,效果不错。如果现场噪声小,可以取小一点减小延迟;噪声大可适当调大。

4.7 参数整定的推荐顺序

现场调参最怕没章法。我常用的顺序:

第一步,确认采样周期和测量链路。采样周期固定,滤波链固定,后面所有参数都基于这个前提。

第二步,标定b0。开环阶跃实验,测斜率,多测几次取平均值。这一步没做准,后面都是白调。

第三步,设定TD。先以工艺允许的目标爬升时间估算r,h0取5到10倍采样周期。这样参考侧就固定了。

第四步,从较小值开始逐渐加大ω0。观察两个指标:扰动出现后z3的响应速度,以及控制量抖动的幅度。找到一个恢复够快、噪声可接受的折中点。

第五步,调整kp。一阶系统里kp就相当于闭环带宽。先给一个保守值,跑阶跃响应,观察超调和扰动恢复刚度,逐步加大直到闭环动态满足要求。

第六步,回头微调r和h0。如果阶跃超调大,适度减小r;如果微分通道噪声大,增大h0。这时其他参数已经基本就位,微调工作量很小。

这套流程下来,通常两三个小时就能完成一个速度环或者温控回路的整定,比PID盲调快得多。

4.8 和现有PID系统怎么过渡切换

现场已经稳定运行的PID系统,直接换ADRC风险较大,即使仿真效果很好,现场也会有意外。推荐三步走:

第一步,让ESO在线运行但不参与控制。代码里同时跑PID和ESO,观察z3估计出来的扰动与实际负载变化是否吻合。比如设备周期性加载,z3应该出现和负载同步的波动。这相当于在正式使用前先让“侦察兵”熟悉地形。

第二步,把z3补偿项叠加到PID输出上。保留PID作为主控制器,ADRC只负责扰动前馈补偿。不要怕补偿方向反了,调试中一旦发现扰动抑制变差,说明z3极性反了,把符号反一下即可。

第三步,切换到完整ADRC闭环,保留PID输出作为限幅参考,或者用一个速度极慢的切换斜坡把控制权过渡过去。这样即使现场参数不理想,切回PID也只是一瞬间的事。

5. 调试实录:三个常见问题与复盘

5.1 高频抖动:伺服速度环的“嗡嗡”声

某次调试伺服速度环,一上电电机就发出轻微的高频嗡嗡声,控制量波形上能明显看到高频噪声分量。排查时先看速度反馈,示波器显示噪声峰峰值并不大。再看z3,发现扰动估计在±一个比较大的范围来回跳动。

初步判断是ESO带宽过高,把测量噪声放大了。把ω0从80降到40,噪声明显减小,但扰动恢复也慢了。后来重新做了b0标定,发现最初的b0比真实值低了约30%,修正后系统在ω0=60时就获得了比之前ω0=80还好的扰动抑制效果。

复盘来看,这是典型的“噪声+增益偏小”复合问题。只降ω0会牺牲性能,重新标b0之后,等价于提高了扰动补偿的准确性,才真正解决问题。

5.2 温控阶跃超调:TD的过渡过程不是摆设

某加热炉温度控制项目,目标温度从200度提高到400度,超调高达15度以上。检查参数时发现,为了追求快速,TD的r设置得非常大,过渡过程几乎等同于直接阶跃。ESO的ω0只是控制带宽的2倍,补偿滞后明显。

处理方式是对症下药:把r从5000降到1000,目标从200到400的过渡时间从不到3秒延长到接近8秒;同时将ω0提高到控制带宽的4倍。再次跑阶跃,超调降到1度以内,升温时间只比原来慢了不到1秒。

这个案例提醒我,ESO再强,TD的安排过渡过程也不能省。参考侧的整形和控制侧的补偿是两回事,跳过TD会直接面对快速性和超调这对老矛盾。

5.3 电源负载突变恢复慢:ESO带宽才是瓶颈

一个DC-DC电源项目,负载从空载切换到满载,输出电压跌落约200mV,恢复时间接近50ms。这里已经用了ADRC,但效果比之前的PID好不到哪去。

排查思路是观察ESO的估计值。将z3波形和负载电流波形对比,发现负载突变时z3确实在变大,但速度偏慢,扰动都作用到输出上了,z3还没跟踪到位。这说明ω0设置太保守,观测器跟不上扰动的变化速率。

把ω0从20逐步加到80,配合提高控制律增益kp,恢复时间最短做到了约5ms,且没有出现明显的高频抖动。项目结束后复盘,我把“扰动恢复速度主要由ESO带宽决定”这一条记进了团队的控制调试规范里。

以下是问题速查表,现场遇到类似现象可以直接对照:

现象可能原因处理方向
控制量高频抖动ω0过高 / b0偏小 / 测量噪声大降ω0、重新标定b0、加测量滤波
阶跃响应超调大r过大 / ω0偏低 / kp过大减小r、提高ω0、降低kp
扰动恢复慢ω0偏低 / b0偏大提高ω0、重新标定b0
低频极限环振荡δ过小 / b0偏大 / 饱和处理不当增大δ、核对b0、加抗饱和逻辑
稳态误差明显执行器死区 / b0偏小 / 控制律刚度不足补偿死区、提高kp、必要时加积分

最后再分享一个个人经验:每次调ADRC之前,先花十分钟把b0标准,后面省下的时间远远不止十分钟。ADRC看起来参数多,但只要抓住b0、ω0、kp这三个抓手,剩下的都是锦上添花。工程上稳妥的路径永远是先线性后非线性、先仿真后现场、先观测后闭环。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询