
聊到工业控制里最简单也常用的控制器大家第一反应肯定是PID。PID确实改变了众多行业的控制方式但真正在现场跑过伺服、温控、电源项目的工程师心里都清楚PID从来不是万能钥匙。被控对象一强耦合、强非线性或者外部扰动特别猛PID那三个增益调来调去往往不是超调就是抖动很难找到一个舒服的工作点。韩京清先生提出的自抗扰控制Active Disturbance Rejection ControlADRC给的是另一条路它不执着于把被控对象模型建得多准而是把系统内部不确定性、外部扰动统统装进一个“总扰动”里由扩展状态观测器实时估计出来再在控制量中把它补偿掉。这样一来再复杂的系统在控制器眼里都被拉回了标准的积分串联结构后续设计就简单了。这篇文章把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 * uy 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 v2v2_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 * ez2_dot z3 - β2 * e b0 * uz3_dot -β3 * e其中e z1 - yz1估计x系统输出z2估计x_dot输出的变化率z3就是扩展出来的那个状态用来估计总扰动f。β1、β2、β3是观测器增益。初看这个结构会觉得奇怪为什么那个e同时出现在三个方程里实际上这就是观测器的修正机制。想象你有一个系统的“虚拟副本”它按照你对系统的理解运行着。你把真实输出和虚拟副本输出之间的误差分别按不同比例反馈到副本的各层状态上不断校正它的内部值。只要反馈增益选得合适过不了多长时间z1就会贴近真实输出yz2贴近真实变化率z3逼近真实总扰动f。信号流的方向是输出误差e先影响到z1估计z1的修正再传导到z2z2的修正再传导到z3。这就像一支小队逐级汇报敌情侦察兵发现偏差班长调整位置排长得到更宏观的态势判断。非线性版本的ESO会把β1 * e这类线性项替换成基于fal函数的非线性项fal(e, α, δ) sign(e) * |e|^α当|e| δ时fal(e, α, δ) e / δ^(1-α)当|e| ≤ δ时α小于1时小误差对应高增益理论上控制精度可以更高。但工程上非线性ESO的参数太多、物理意义不直观所以大量产品中用线性ESOLESO替代也就是把α直接取1再用带宽法整定β参数。很多商业实现中所谓的LADRC本质上就是这套线性化方案效果足够好参数还少。2.3 状态误差反馈与扰动补偿剩下的都是标准流程有了TD提供的过渡参考信号v1、v2有了ESO提供的状态估计z1、z2和扰动估计z3控制律的设计就变得非常“教科书”。取误差e1 v1 - z1e2 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能跟上fb0与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(k1) v1(k) h * v2(k)v2(k1) v2(k) h * fst(v1(k) - v(k), v2(k), r, h0)e(k) z1(k) - y(k)z1(k1) z1(k) h * (z2(k) - 3ω0e(k))z2(k1) z2(k) h * (z3(k) - 3ω0²e(k) b0*u(k))z3(k1) 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、h0ESO有一个ω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。先以工艺允许的目标爬升时间估算rh0取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%修正后系统在ω060时就获得了比之前ω080还好的扰动抑制效果。复盘来看这是典型的“噪声增益偏小”复合问题。只降ω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这三个抓手剩下的都是锦上添花。工程上稳妥的路径永远是先线性后非线性、先仿真后现场、先观测后闭环。