首页 / 资讯中心 / 文章详情

自适应ADRC从原理到落地:ESO、PID对比与工程避坑

自适应ADRC从原理到落地:ESO、PID对比与工程避坑 ★ FEATURED ARTICLE
简介一份围绕自适应ADRC自抗扰控制与PID干扰抑制的控制项目资料面向自动化与控制工程方向的工程师和研究者专注于处理系统不确定性及外部扰动下的控制器设计。压缩包共10个文件集成Matlab脚本.m、Simulink模型.slx、PDF论文和6张公式/结果图整体大小仅1.25MB兼顾源码、文档和可视化参考。目前已有274人学习下载适合从理论到仿真快速上手。通过研究其中的ADRC控制器实现代码与Simulink仿真模型可理解扩展状态观测器ESO、自适应参数调节及PID协同抗扰的核心机制结合PDF论文与公式截图还能梳理稳定性分析思路为实际系统控制开发提供可迁移的样例。1. 自适应ADRC进入工程视野从PID在强扰动下翻车说起把一套带负载扰动的电机转速环交给 PID参数整定得再漂亮也躲不开一个尴尬局面扰动来得越猛恢复时间越慢超调还跟着放大快速性和抗扰性在同一个环节上互相打架。这就是为什么一看到 adaptive_adrc-master 这类工程示例懂行的人会优先关注它背后的 ADRC 控制器思路——自抗扰控制的核心是把“模型误差 外部扰动”打包成一种可观测的状态再用控制量直接补偿掉而不是像 PID 那样靠误差积分慢慢磨。这篇笔记打算把 ADRC 控制从原理拆到实现再落到一套可复现的仿真实验上和 PID 做同工况干扰对比最后把工程落地时最容易翻车的几个坑一并说清楚。适合正在做运动控制、过程控制或者被扰动和参数漂移折磨过的开发者。2. ADRC控制器三大件拆解TD、ESO与误差反馈各自解决什么问题2.1 ESO是ADRC的灵魂把“不知道的扰动”变成“看得见的状态”扩张状态观测器是 ADRC 区别于 PID 的核心。它不依赖精确的被控对象模型只要求你给一个控制增益的粗略估计 b0然后把“模型没建准的部分”和“外部干扰”合并成一个扩张状态 z2用观测器的形式实时估出来。一阶对象配上二阶 ESO常见写法是e z1 - y z1_dot z2 - β1·e b0·u z2_dot -β2·e其中 z1 跟踪系统输出z2 跟踪总扰动。β1 和 β2 按带宽法取 β1 2ωo、β2 ωo²这样观测器极点都落在 ωo 附近调一个 ωo 就能控制观测速度。ESO 的工程意义在于扰动被估出来之后控制量里直接减掉 z2系统就从“靠误差积分反复修正”变成了“预判扰动并提前抵消”。这也是 PID 干扰对比中 ADRC 恢复速度明显占优的原因。但 ESO 不是万能的。z2 能估出来的前提是 b0 和真实控制增益不能偏差太大否则系统等效扰动里会混入 b0 偏差引起的成分观测器负担加重。更关键的是 ωo 取值要平衡——调大了观测快但噪声也跟着放大调小了扰动估计滞后。这就是后面自适应要介入的理由。2.2 跟踪微分器TD与误差反馈快速性与低超调兼得PID 的 D 项在工程里经常被白瞎掉因为测量噪声被微分放大不得不加滤波滤波一加相位又滞后。ADRC 的做法是用 TD 先从参考信号里解出“安排好的过渡过程”和它的微分再从 ESO 里拿被控对象的估计状态两者做差生成误差反馈。TD 的连续形式大致是v1_dot v2 v2_dot -r²·(v1 - ref) - 2r·v2这里 r 决定跟踪速度。r 越大v1 越逼近参考信号但相应地对参考突变越敏感。工程上通常让 r 和控制器带宽保持合理比例让输出既不丢失快速性又不会因为阶跃参考而产生过大的初始控制量。误差反馈部分则用 v1 - z1 做比例项必要时加上 v2 - z2 的微分项输出 u0。因为扰动已经被 z2 补偿了u0 只需要承担“让状态跟上参考”的任务控制律形式可以比 PID 简单得多。实际项目里TD 还有一个隐蔽价值它让目标信号变得平滑大幅降低了执行机构在急加速和急减速时的冲击。这个好处在伺服和运动控制上体现非常明显同样是位置阶跃带 TD 的系统和直接怼参考值的系统减速机磨损和抖动完全两回事。2.3 线性还是非线性参数个数与调参直觉的工程取舍ADRC 有线性与非线性的分别。非线性 ADRC 在误差反馈和 ESO 误差修正里用 fal(e, α, δ) 这类函数小误差时增益高理论性能更漂亮但参数多出一截α 和 δ 调起来全靠经验对初入门的团队并不友好。线性 ADRCLADRC则直接把 ESO 和反馈都做成线性结构参数收敛到 ωo 和 ωc 两个带宽整定直觉非常清晰。我一般会建议先上线性 ADRC把系统跑明白之后再决定要不要在某个环节引入非线性修正。原因很现实非线性 ADRC 的优势在强扰动大误差场景下明显但它的参数敏感度也高稍有不慎就出现极限环或高频颤振。下面这张表是选型时的常用对照维度线性ADRCLADRC非线性ADRCNLADRC需整定参数以 ωo、ωc、b0 为主ωo、ωc、b0、α、δ、TD的r等调参难度低带宽法直接套用高非线性参数相互影响抗扰性能中上波形平滑大误差区响应更快噪声敏感性依赖带宽选择小误差区增益高噪声容易被放大适合场景电机、伺服、过程量控制强冲击、大范围工况变化的研究型系统从 adaptive_adrc 这类工程名也能看出主流方向是给 LADRC 加上参数自适应而不是一上来就上非线性。理由很简单线性结构的参数物理意义清楚自适应更新规则容易设计和验证非线性结构本身已经复杂再叠加自适应排查问题时会很痛苦。3. 把自适应ADRC控制器跑起来电机模型、参数初值与在线增益辨识实现3.1 被控对象与离散递推一套模拟电机转速环做 ADRC 仿真的第一步是把被控对象搭好。选一个带负载扰动的电机转速环作为对象方程写为J·dw/dt Kt·u - B·w d(t)其中 J 是转动惯量Kt 是力矩系数B 是粘性摩擦系数d(t) 是外部负载扰动。真实控制增益 b_true Kt/J但控制器并不知道它手里只有一个初始估计 b0这个偏差就是自适应的用武之地。仿真采用固定步长欧拉递推步长 dt 0.001 秒总时长 10 秒。为了公平验证自适应效果b0 初始值故意给得和真实值差很多。真实 b_true 约为 60初始 b0 设置为 15相当于控制器对对象增益的理解只有真实的四分之一。在这种情况下固定参数的 ADRC 通常会出现明显的稳态误差或振荡而自适应 ADRC 应该能在几秒内把 b_est 修正到接近真实值。3.2 自适应参数更新实现带死区的增益在线辨识自适应这里不搞复杂的神经网络或模糊推理用最容易解释、也最容易在单片机上演算的梯度法做 b_est 在线更新。核心思想是如果 ESO 的观测误差和当前控制量同号持续存在说明 b_est 和真实增益之间有系统偏差按梯度方向修正它。更新规则为b_est b_est - γ·dt·e_eso·u其中 e_eso z1 - w 是观测器转速估计与实际转速的误差γ 是更新步长。为了防止微小噪声积累导致 b_est 漂移更新前必须经过死区和限幅。完整仿真核心代码如下import numpy as np dt 0.001 # 仿真步长1ms T 10.0 # 仿真时长10s N int(T / dt) # 对象参数 J 0.02 # 转动惯量 Kt 1.2 # 力矩系数 B 0.05 # 粘性摩擦系数 # 控制器初始参数 b0 15.0 # 初始控制增益估计真实约为60 wc 12.0 # 控制器带宽 wo 40.0 # ESO带宽 beta1 2.0 * wo beta2 wo * wo # 自适应参数 b_min, b_max 5.0, 200.0 # b_est的物理上下限 gamma 0.2 # 更新步长不能太大 deadzone 0.02 # 观测误差死区 b_est b0 # 在线增益估计值 # 状态初始化 w 0.0 # 实际转速 z1 0.0 # ESO估计转速 z2 0.0 # ESO估计总扰动 v1 0.0 # TD跟踪参考 v2 0.0 # TD输出的参考微分 u 0.0 # 记录 logs [] for k in range(N): t k * dt # 负载扰动0-3s无扰动3-6s加恒定负载6-10s加正弦扰动 d 0.0 if 3.0 t 6.0: d 8.0 elif t 6.0: d 4.0 * np.sin(2.0 * np.pi * 0.8 * t) # 1) TD安排过渡过程并提取参考微分 e_td v1 - 100.0 v1 v1 dt * v2 v2 v2 dt * (-50.0 * e_td - 10.0 * v2) # 2) ESO用b_est估计转速和总扰动 e_eso z1 - w z1 z1 dt * (z2 - beta1 * e_eso b_est * u) z2 z2 dt * (-beta2 * e_eso) # 3) 误差反馈 扰动补偿 u (wc * (v1 - z1) - z2) / b_est u np.clip(u, -10.0, 10.0) # 4) 自适应更新b_est死区 限幅 if abs(e_eso) deadzone and abs(u) 1e-3: b_est b_est - gamma * dt * e_eso * u b_est np.clip(b_est, b_min, b_max) # 5) 对象递推 w_dot (Kt * u - B * w d) / J w w dt * w_dot logs.append([t, w, z1, u, z2, b_est]) logs np.array(logs)这段代码的关键在于第 4 步。e_eso 是 ESO 对转速的观测误差u 是当前控制量。如果 b_est 偏小ESO 会用偏大的控制量解释转速变化于是观测误差与控制量保持同号b_est 就会向真实方向移动。死区避免噪声让 b_est 来回抖限幅则保证即使更新方向错了也不会把增益拉出物理合理的范围。gamma 的选取直接影响自适应收敛速度。gamma 太大b_est 会出现振荡甚至发散gamma 太小修正需要十几秒扰动来了跟不上。工程上的经验值是 gamma 取 ESO 带宽的 5% 到 10%这里 wo 40gamma 0.2 在安全区间内。3.3 参数初始值怎么定一张表把b0、ωo、ωc与自适应限幅说清楚仿真模型有了接下来的问题是参数初值从哪来。这里给一组工程默认值和调节方向参数初始值作用调大效果调小效果b0按对象模型估算控制增益的名义值控制量偏小控制量偏大ωc815 rad/s反馈控制带宽响应变快响应变缓ωo35倍ωcESO观测带宽扰动估计快但噪声大观测平滑但滞后γ0.050.2ωo自适应更新步长收敛快但易振荡收敛慢但稳定deadzone传感器噪声幅值防止参数漂移抗噪好但更新迟钝更新灵敏但易漂移b_min/b_max名义b0的50%300%约束b_est范围适应性更强稳定性更好b0 的初值最好还是花几分钟算一下。对电机来说就是 Kt 除 J如果你在真机上做通常可以通过一次开环阶跃测试来标定给一个固定控制量测稳态转速变化率反推 b0。这个动作值得做b0 初值越接近真实ESO 的负担越轻后面自适应的修正量也越小。4. PID干扰对比实验设计同工况下用IAE和ITAE量化抗扰差距4.1 三种干扰注入方式与PID整定口径空口说 ADRC 抗扰强没有说服力要和 PID 在同一条跑道上比。干扰注入设成三类分别对应工程里最常见的负载突变、周期性波动和测量噪声背景下的扰动工况时间段扰动形式模拟场景阶跃负载3s6s恒值 d8.0负载突然加载或卸载周期扰动6s10sd4·sin(2π·0.8t)偏心负载、齿轮啮合脉动随机扰动全时段可加高斯白噪声风载、流场脉动等PID 参数按极点配置法整定对象模型已知kp、ki、kd 能直接算出来。这里给一组可用参数kp6.0、ki0.5、kd0.02。不推荐用 Ziegler-Nichols 来定因为临界振荡法只能给出稳定性附近的参数用于性能对比会给 PID 拖后腿。关键是对比必须保证两者控制量限幅一致、采样周期一致、扰动注入序列一致。控制量饱和会掩盖控制器之间的真实差别所以两边都限幅在 ±10。4.2 对比脚本与指标计算IAE、ITAE与控制量方差一起算完整对比脚本这里给出一版它把 PID 和 ADRC 放在同一个对象模型上跑并计算三个指标IAE误差绝对积分、ITAE时间加权误差绝对积分和控制量方差。IAE 反映全程误差总量ITAE 加重稳态长尾部分的权重控制量方差反映执行机构付出的代价。import numpy as np dt 0.001 T 10.0 N int(T / dt) J, Kt, B 0.02, 1.2, 0.05 ref 100.0 # PID参数极点配置法整定 kp, ki, kd 6.0, 0.5, 0.02 # ADRC参数 b0, wc, wo 15.0, 12.0, 40.0 beta1, beta2 2.0 * wo, wo * wo def load_disturbance(t): if 3.0 t 6.0: return 8.0 elif t 6.0: return 4.0 * np.sin(2.0 * np.pi * 0.8 * t) return 0.0 def run_pid(): w, e_int, e_prev, u 0.0, 0.0, 0.0, 0.0 out [] for k in range(N): t k * dt d load_disturbance(t) e ref - w e_int e * dt u kp * e ki * e_int kd * (e - e_prev) / dt u np.clip(u, -10.0, 10.0) w w dt * ((Kt * u - B * w d) / J) e_prev e out.append([t, w, u]) return np.array(out) def run_adrc(): w z1 z2 v1 v2 u 0.0 out [] for k in range(N): t k * dt d load_disturbance(t) e_td v1 - ref v1 dt * v2 v2 dt * (-50.0 * e_td - 10.0 * v2) e_eso z1 - w z1 dt * (z2 - beta1 * e_eso b0 * u) z2 dt * (-beta2 * e_eso) u (wc * (v1 - z1) - z2) / b0 u np.clip(u, -10.0, 10.0) w dt * ((Kt * u - B * w d) / J) out.append([t, w, u]) return np.array(out) def metrics(data): t, w, u data[:, 0], data[:, 1], data[:, 2] e ref - w iae np.sum(np.abs(e) * dt) itae np.sum(np.abs(e) * t) * dt u_var np.var(u) return iae, itae, u_var pid_data run_pid() adrc_data run_adrc() pid_m metrics(pid_data) adrc_m metrics(adrc_data) print(fPID IAE{pid_m[0]:.4f} ITAE{pid_m[1]:.4f} u_var{pid_m[2]:.4f}) print(fADRC IAE{adrc_m[0]:.4f} ITAE{adrc_m[1]:.4f} u_var{adrc_m[2]:.4f})脚本里的 run_adrc 故意用了固定 b0没有加自适应这能先看清纯 ADRC 相对 PID 的抗扰优势。跑完你会发现ADRC 的 ITAE 通常会显著低于 PID尤其在 3s 阶跃负载注入时转速跌落的幅度更小、恢复到稳态更快。控制量方差上 ADRC 一般也不算差因为它的补偿动作是“一次性到位”而不是 PID 那种反复修正。4.3 结果分析顺序先看峰值偏离再看恢复时间最后算控制代价对比结果出来后容易犯一个错只盯着 IAE、ITAE 两个数字就开始下结论。我习惯的分析顺序是三步。第一步看阶跃扰动瞬间的峰值偏离这反映 ESO 观测扰动的速度和补偿的及时性第二步看恢复时间以进入 ±2% 误差带计算这是现场最关心的指标也是 ADRC 和 PID 拉开差距最明显的地方第三步看控制量方差和峰值控制量震荡太猛说明参数偏激进就算误差指标好看也不能直接上真机。如果按这个顺序回看PID 和 ADRC 的行为差异就非常清楚了。PID 的恢复过程是一条慢慢收拢的衰减曲线ADRC 则是先跌一个小坑然后干脆利落地拉回来。周期扰动工况下ADRC 的 z2 能持续跟踪正弦扰动控制量里会主动叠加一个反相分量而 PID 只能靠积分被动追赶表现在误差曲线上就是相位滞后和幅值放大。5. ADRC控制落地避坑ESO欠观测、高频颤振与参数跳变的排查记录5.1 现象一ESO带宽拉高后控制量高频振荡现象是转速输出看起来还算平滑但控制量 u 出现了小幅度高频锯齿执行机构发出明显的嗡嗡声电机电流波形在高频段有毛刺。初学者第一反应是反馈通道有噪声实际上根因往往是 ESO 带宽 ωo 设置过高把传感器噪声放大后进入了控制量。解决方法是先确认噪声来源和频谱对转速反馈做一次功率谱估计找出噪声能量集中的频段把 ωo 压到噪声主频的 1/3 以下。另外可在 ESO 误差通道加一阶低通或者在转速反馈进 ESO 之前做滑动平均滤波。滤波会牺牲一点观测速度但换来的控制量平稳在工程上更值。5.2 现象二自适应更新导致控制量出现台阶b_est 在线更新过程中转速反馈平稳时控制量突然跳变一个台阶随后又慢慢回落。原因很简单自适应更新规则里少了死区和限幅e_eso 和 u 的乘积即使很小经过多个周期积分后也会累积成一个明显的偏移一旦叠加到控制量上就是台阶。解决方式是严格按第 3 章的更新结构来abs(e_eso) 小于 deadzone 时冻结 b_est更新方向不确定时不动作b_est 的上下限也要贴合对象物理边界。这一步偷懒不得无数仿真炫技最后翻车都翻在这。5.3 现象三仿真步长变大后ESO观测值发散同一个模型步长从 1ms 改成 5msESO 的 z2 开始震荡甚至发散固定参数 PID 反而还稳定。原因是连续域极点配置在离散化后稳定边界变了欧拉法对 ωo·dt 的乘积有限制步长变大后等效极点跑出单位圆。解决方法是先校验 ωo·dt 的值经验上限是 0.1 到 0.2。超过这个范围就必须减小仿真步长或者改用双线性变换法离散 ESO。上真机时这一步尤其重要单片机中断周期和仿真步长不是一回事务必按实际执行周期重新校验离散后的 ESO 极点位置。5.4 现象四TD在阶跃参考下输出微分尖峰参考信号直接给阶跃时v1 的跟踪曲线没问题但 v2 会在阶跃瞬间冒出一个尖峰反馈控制量被瞬间拉高执行机构承受一次冲击。原因是连续 TD 的离散实现里参考突变幅度超过了差分格式的平滑能力。解决这类问题有两个常用手法一是参考信号在进入 TD 之前先做斜坡化或一阶惯性滤波二是改用专门的离散快速 TD 公式。从工程习惯上前者更直接因为现场上位机下发的目标值本身就应该带斜率限制这既保护执行机构也让 ADRC 有更充分的时间建立观测。5.5 现象五阶跃扰动第一拍转速仍被拉走即使 ESO 正常工作3s 负载突加时转速还是会先跌一下然后在 200ms 内恢复。有人以为是 ESO 不给力其实这是物理必然——ESO 对扰动的估计和补偿天然滞后一拍扰动作用到对象后转速或状态发生变化ESO 才能把这部分变化解释为扰动并进行补偿。第一拍的偏离是躲不掉的。合理的目标不是让第一拍完全没有偏离而是让偏离幅度小、恢复时间短。方法上可以适当提高 β2 加快扰动收敛但更推荐把速度环采样周期缩短或在电流环上叠加载荷前馈。仿真里看到的 50ms 滞后放到真机上可能被放大三倍调试时别只盯着稳态指标。6. 从仿真走向真机自适应ADRC上设备前的验证清单与一个收盘习惯6.1 上真机前的5项验证清单仿真通过只说明控制算法在理想采样和精确对象条件下成立离真机还有一段距离。我这几年的习惯是固定走一套验证流程五步都过了才允许自己把自适应 ADRC 放进正式固件。第一步确认传感器噪声水平用转速反馈的功率谱估计确定 ωo 的上限超出噪声主频的带宽设定直接否掉。第二步标定 b0 的名义值并测出它随工况的变化范围如果超过 ±30%自适应就不是可选功能而是必选功能。第三步用硬件在环平台把采样周期压到和真机一致跑 1 小时的连续工况观察 b_est 是否在某个区间内缓慢漂移漂移量过大说明死区或更新率偏大。第四步做阶跃扰动扫描实验从 10% 到 100% 负载逐级加载记录不同幅值下的恢复时间检查性能是否单调。第五步把自适应更新产生的中间变量全部做成可读参数至少要能看到 b_est、z2 和 ESO 观测误差的实时曲线。这五步里最容易被跳过的是第一步和第二步。很多开发者拿着仿真参数直接上真机结果 ωo 超出传感器可承受范围控制量全是噪声还有人不管 b0 漂移固件里留一个固定值结果自适应一直处在极限边缘工作。6.2 一个让自适应ADRC少翻车的调试顺序最后一个习惯是我自己的血泪经验换来的所有自适应参数更新必须先死区、后限幅再整定更新率。顺序不能反。先有死区噪声不会累积成参数漂移再有限幅即使整定方向错了也不会把系统推离稳定边界最后调 γ从保守的 5% ωo 开始逐步加大观察收敛速度和振荡的权衡点。另外要清楚一点自适应不是越快越好。仿真里你可以用大 γ 让 b_est 两秒内收敛看起来性能很漂亮但真机上传感器噪声、执行机构饱和、离散误差都会让大 γ 变成不稳定源。一个运行稳定、参数收敛慢 5 秒但整个生命周期内不出问题的自适应环远好过一个仿真里闪闪发光但一周后现场报警的激进方案。如果调试时间紧还有个取舍技巧先把 b0 和 ωo 固定住用纯 ADRC 跑通各项功能指标确认 ESO 观测和扰动补偿这条主链路是好的再打开自适应更新。这样即使自适应部分出问题你也能确定问题集中在参数更新模块而不是整个算法框架。把自适应当成最后一块拼图而不是第一块。希望你调试时少走这些弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站