4. 积分饱和现象抑制与PID参数调整

任务目标

在存在执行器饱和(输出限幅)的系统中,观察积分饱和现象,实现抗积分饱和(Anti-windup)策略,并重新整定PID参数以改善控制性能。通过对比仿真,验证抗积分饱和措施的有效性。

系统描述与问题定义

被控对象为一阶惯性加纯滞后过程(FOPDT):

G(s) = Kp * e^(-Ls) / (T*s + 1),其中 Kp=1.5,T=5s,L=1s

执行器输出限幅为 [0, 10],控制器输出超过该范围时执行器饱和。采用位置式PID控制,采样周期 Ts=0.1s。当设定值阶跃较大时,积分项持续累积导致超调增大、调节时间延长,即积分饱和现象。

抗积分饱和实现方案

采用条件积分法(Conditional Integration):当控制器输出超出执行器限幅且误差方向与积分方向一致时,冻结积分项;否则正常积分。该方法简单有效,无需额外模型。

关键完整代码(Python仿真)

import numpy as np
import matplotlib.pyplot as plt

# 被控对象参数
Kp_obj = 1.5
T_obj = 5.0
L_obj = 1.0
Ts = 0.1

# 执行器饱和限幅
u_min, u_max = 0.0, 10.0

# PID参数(经整定:无抗饱和时需保守,有抗饱和时可更激进)
Kp = 1.2
Ki = 0.25
Kd = 0.8

# 仿真时间
t_end = 40.0
n_steps = int(t_end / Ts)
t = np.arange(0, t_end, Ts)

# 设定值:0→5 阶跃
setpoint = np.zeros(n_steps)
setpoint[10:] = 5.0

# 初始化
y = np.zeros(n_steps)          # 过程输出
y_prev = 0.0
u_sat = np.zeros(n_steps)      # 实际执行器输出(饱和后)
u_ctrl = np.zeros(n_steps)     # 控制器输出(未饱和)
integral = 0.0
error_prev = 0.0

# 纯滞后缓冲(模拟L=1s,即10个采样周期)
delay_buf = np.zeros(int(L_obj / Ts) + 1)
delay_idx = 0

# 抗饱和开关:True=启用,False=禁用
anti_windup = True

for i in range(n_steps):
    # 当前过程输出(从延迟缓冲读取)
    y[i] = delay_buf[delay_idx]
    
    # 误差
    e = setpoint[i] - y[i]
    
    # PID计算(位置式)
    P = Kp * e
    D = Kd * (e - error_prev) / Ts
    
    # 积分项(含抗饱和逻辑)
    if anti_windup:
        # 条件积分:若输出饱和且误差与积分同向,则冻结积分
        u_test = P + integral + D
        if (u_test > u_max and e > 0) or (u_test < u_min and e < 0):
            pass  # 冻结积分
        else:
            integral += Ki * e * Ts
    else:
        integral += Ki * e * Ts
    
    # 控制器输出
    u_ctrl[i] = P + integral + D
    
    # 执行器饱和
    u_sat[i] = np.clip(u_ctrl[i], u_min, u_max)
    
    # 更新被控对象(一阶惯性,使用欧拉法)
    dy = (Kp_obj * u_sat[i] - y_prev) / T_obj
    y_new = y_prev + dy * Ts
    
    # 写入延迟缓冲
    delay_buf[delay_idx] = y_new
    delay_idx = (delay_idx + 1) % len(delay_buf)
    
    # 更新状态
    y_prev = y_new
    error_prev = e

# 绘制对比(需运行两次:anti_windup=False 和 True)
plt.figure(figsize=(10, 5))
plt.plot(t, setpoint, 'k--', label='Setpoint')
plt.plot(t, y, label=f'Output (Anti-windup={anti_windup})')
plt.plot(t, u_sat, label='Actuator output', alpha=0.6)
plt.xlabel('Time (s)')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.title('Integral Windup Comparison')
plt.show()

# 性能指标计算(稳态后)
steady_idx = int(30 / Ts)
y_ss = np.mean(y[steady_idx:])
overshoot = (np.max(y) - 5.0) / 5.0 * 100
print(f'Steady-state value: {y_ss:.3f}')
print(f'Overshoot: {overshoot:.1f}%')

运行与验证方法

  1. 依赖:Python 3.8+,numpy,matplotlib。
  2. 运行步骤:将上述代码保存为 pid_antiwindup.py,先设置 anti_windup = False 运行一次,记录输出曲线与超调量;再改为 True 运行第二次,对比两次结果。
  3. 观察指标:
    - 无抗积分饱和时:输出超调明显(通常>20%),执行器长时间处于饱和上限,调节时间较长;
    - 启用抗积分饱和后:超调显著减小(通常<10%),执行器更快退出饱和,系统响应更平稳。

判定标准

  • 启用抗积分饱和后,超调量较未启用时降低至少50%;
  • 调节时间(进入±5%误差带)缩短至少30%;
  • 执行器饱和持续时间明显减少,控制输出在设定值附近平滑过渡。

PID参数整定说明

本例中PID参数(Kp=1.2, Ki=0.25, Kd=0.8)是在启用抗积分饱和条件下整定的,允许使用更积极的积分增益。若关闭抗积分饱和,需降低Ki至0.1以下才能避免严重超调,但会牺牲响应速度。实际工程中建议先启用抗积分饱和,再按Ziegler-Nichols或ITAE准则整定。

常见问题

  • 积分冻结条件不触发:检查误差方向与输出饱和方向是否一致,注意误差符号定义(本例为设定值减测量值)。
  • 纯滞后处理:本例用环形缓冲模拟延迟,实际系统中延迟由对象固有特性决定,不影响抗积分饱和逻辑。
  • 离散化影响:采样周期Ts需远小于对象时间常数T(本例Ts/T=0.02),否则需改用更精确的离散化方法。