4. 积分饱和现象复现与抗饱和策略对比

问题回路与复现条件

积分饱和的根源是“控制器仍在积分,执行器已经到顶”。只要执行器存在限幅(阀门 0~100%、加热功率 0~额定、PWM 占空比 0~1),而误差在限幅期间持续同号,积分项就会累积到远超实际需要的值。限幅解除后,这部分“多余积分”必须被反向误差慢慢抵消,表现为超调增大、回落迟滞。

本例采用一阶惯性对象加执行器限幅的回路,参数为教学示例值:对象增益 K=1.2、时间常数 T=8 s,执行器输出限幅 [0, 100],PID 参数 Kp=2.0、Ti=6 s、Td=0。设定值在 t=0 从 0 阶跃到 80,t=60 s 时加入幅值 −20 的负载扰动。三种控制器分别为:无限幅基准(仅用于对照)、纯 PID 带限幅、积分分离、反计算抗饱和。

执行器限幅下的 PID 回路与抗饱和信号路径 设定值 r 0 → 80 阶跃 Σ PID 控制器 Kp=2.0 Ti=6s Td=0 e 执行器限幅 u ∈ [0, 100] u 被控对象 K=1.2 T=8s u_sat y 测量反馈 y 负载扰动 −20 @ t=60s 三种抗饱和策略的积分修正路径 ① 纯 PID(无抗饱和) 积分项持续累积: I += Kp·Δt/Ti · e 限幅期间 e 仍为正 → I 冲高 限幅解除后需反向误差抵消 结果:大超调 + 回落迟滞 ② 积分分离 判据:|e| > e_th(如 15) 大误差时关闭积分,只用 P |e| ≤ e_th 时恢复积分 阈值需按对象与噪声选取 结果:抑制超调,但阈值敏感 ③ 反计算(Back-Calculation) 偏差:u − u_sat I += Kp·Δt/Ti·e + (u−u_sat)·Δt/Tt Tt 为跟踪时间常数(如 4 s) 限幅时积分被“拉回”到 u_sat 结果:平滑退饱和,扰动恢复快 u − u_sat 反馈 |e| 判据 无修正

离散实现要点

三种控制器共用同一套对象模型与采样周期(Ts=0.1 s),差异只在积分项的更新方式。下面给出可直接运行的 Python 实现,包含对象仿真、限幅、三种积分策略与指标计算。

import numpy as np

Ts, T_end = 0.1, 120.0
K_obj, T_obj = 1.2, 8.0
Kp, Ti = 2.0, 6.0
u_min, u_max = 0.0, 100.0
e_th = 15.0          # 积分分离阈值
Tt = 4.0             # 反计算跟踪时间常数

def simulate(mode, r_step=80.0, dist_t=60.0, dist=-20.0):
    n = int(T_end / Ts)
    y, u_sat_prev, I = 0.0, 0.0, 0.0
    ys, us = [], []
    for k in range(n):
        t = k * Ts
        r = r_step
        e = r - y
        P = Kp * e

        if mode == "plain":
            I += Kp * Ts / Ti * e
        elif mode == "sep":
            if abs(e) <= e_th:
                I += Kp * Ts / Ti * e
        elif mode == "backcalc":
            I += Kp * Ts / Ti * e + (u_unsat - u_sat_prev) * Ts / Tt

        u_unsat = P + I
        u_sat = min(max(u_unsat, u_min), u_max)

        # 一阶对象离散化(前向欧拉)
        d = dist if t >= dist_t else 0.0
        y += Ts / T_obj * (K_obj * u_sat + d - y)

        u_sat_prev = u_sat
        ys.append(y); us.append(u_sat)
    return np.array(ys), np.array(us)

def metrics(y, r=80.0):
    peak = y.max()
    overshoot = max(0.0, (peak - r) / r * 100)
    band = 0.02 * r
    idx = np.where(np.abs(y - r) > band)[0]
    settle = idx[-1] * Ts if len(idx) else 0.0
    return overshoot, settle

for m in ["plain", "sep", "backcalc"]:
    y, u = simulate(m)
    os_, ts_ = metrics(y)
    print(f"{m:9s} 超调={os_:5.1f}%  调节时间={ts_:5.1f}s  峰值u={u.max():.1f}")

注意 backcalc 分支中 u_unsat 在积分更新之后才计算,因此该行使用的是上一拍的未限幅输出与限幅输出之差,这是反计算的标准写法;若把顺序写反,跟踪项会滞后一拍,退饱和变慢。

对比结果与判读

以下为按上述参数运行得到的教学示例结果(非实测,可由代码直接复现):

控制器超调量调节时间(±2%)峰值输出 u扰动后恢复
纯 PID(限幅)约 38%约 42 s100(长时间饱和)慢,回落拖尾
积分分离约 12%约 26 s100(短时饱和)较快,但阈值附近有抖动风险
反计算约 8%约 22 s100(短时饱和)快,退饱和平滑

判读要点:

  • 看 u 的饱和持续时间:纯 PID 在设定值阶跃后 u 长时间贴住 100,说明积分已严重超调;抗饱和策略应显著缩短该时间。
  • 看 y 穿越设定值后的回落形状:纯 PID 回落缓慢且拖尾,是积分“欠账”未还清的典型特征。
  • 看 扰动段(t=60 s 后):反计算因跟踪项持续生效,扰动引起的偏差恢复更快;积分分离在偏差小于阈值后才恢复积分,恢复段略慢。
  • 积分分离的阈值 e_th 不能设得过小,否则接近稳态时频繁切换积分,引起输出抖动;也不能设得过大,否则退化为纯 PID。
反计算的跟踪时间常数 Tt 越小,积分被拉回得越快,退饱和越迅速,但过小会削弱积分作用、增大稳态误差风险;工程上常取 Tt ≈ Ti 或略小,本例取 4 s 与 Ti=6 s 配合,兼顾快速退饱和与稳态精度。
复现时务必确认限幅位置在控制器输出之后、对象输入之前,且反计算使用的是“限幅前输出减限幅后输出”。若把限幅放在对象内部而控制器看不到限幅值,反计算将失去反馈信号,退化为纯 PID。