跳到主要内容

PID 控制器

Darra PLC 内置 PID 功能块 (PIDController.cs),实现比例-积分-微分闭环控制,适用于温度、压力、流量、速度等连续过程控制。

PID 原理

PID 控制器根据设定值与反馈值的偏差,计算控制输出:

输出 = Kp × e(t) + Ki × ∫e(t)dt + Kd × de(t)/dt

e(t) = 设定值 - 反馈值
参数作用增大效果减小效果
Kp (比例)响应速度快速响应,可能振荡平稳但缓慢
Ki (积分)消除稳态误差误差快速归零,可能超调稳态误差残留
Kd (微分)抑制超调阻尼增强,抗干扰超调增大

功能块接口

FUNCTION_BLOCK FB_PID
VAR_INPUT
bEnable : BOOL; // 使能
rSetpoint : REAL; // 设定值 (SP)
rFeedback : REAL; // 反馈值 (PV)
rKp : REAL; // 比例增益
rKi : REAL; // 积分增益
rKd : REAL; // 微分增益
rOutMin : REAL; // 输出下限
rOutMax : REAL; // 输出上限
bManual : BOOL; // 手动模式
rManualOut : REAL; // 手动输出值
bReset : BOOL; // 复位积分器
END_VAR
VAR_OUTPUT
rOutput : REAL; // 控制输出 (CV)
rError : REAL; // 当前偏差
bAtSetpoint : BOOL; // 到达设定值 (偏差在死区内)
bLimited : BOOL; // 输出已限幅
END_VAR

温度控制示例

PROGRAM OB30    // 10ms 周期中断
VAR
fbPID_Temp : FB_PID;
rActTemp : REAL; // 实际温度 (°C)
rSetTemp : REAL; // 设定温度 (°C)
rHeaterPwr : REAL; // 加热功率 (%)
END_VAR

// 读取温度传感器 (PT100, 4-20mA → 0-200°C)
rActTemp := INT_TO_REAL(%IW100 - 4000) / 16000.0 * 200.0;

// 设定值来自 HMI
rSetTemp := %MD200;

// PID 计算
fbPID_Temp(
bEnable := TRUE,
rSetpoint := rSetTemp,
rFeedback := rActTemp,
rKp := 5.0,
rKi := 0.8,
rKd := 1.2,
rOutMin := 0.0,
rOutMax := 100.0,
bManual := %MX100.0, // HMI 手动切换
rManualOut := %MD104 // HMI 手动输出
);

// 输出到加热器 (PWM 或模拟量)
rHeaterPwr := fbPID_Temp.rOutput;
%QW200 := REAL_TO_INT(rHeaterPwr * 327.67); // 0-100% → 0-32767

END_PROGRAM

抗积分饱和 (Anti-Windup)

当输出达到限幅时,积分器会继续累积导致超调。PID 功能块内置抗积分饱和机制:

  • 条件积分: 输出饱和时暂停积分累积
  • 回算法: 将超出限幅的部分反馈到积分器中衰减
自动切换

手动/自动模式切换时,积分器自动跟踪手动输出值,实现无扰切换 (Bumpless Transfer)。

输出限幅

// 输出限幅确保安全
fbPID(
rOutMin := 0.0, // 最小输出 (如: 加热器不能负功率)
rOutMax := 100.0 // 最大输出 (如: 100% 功率上限)
);

参数整定建议

Ziegler-Nichols 法

  1. 将 Ki 和 Kd 设为 0
  2. 逐步增大 Kp 直到系统产生等幅振荡
  3. 记录临界增益 Ku 和振荡周期 Tu
  4. 按下表计算参数:
控制器KpKiKd
P0.5×Ku00
PI0.45×Ku1.2×Kp/Tu0
PID0.6×Ku2×Kp/TuKp×Tu/8
实际调参

Ziegler-Nichols 法给出初始参数,实际应用中需要根据系统响应微调。建议使用 IDE 的趋势曲线面板 (TrendPanel) 观察设定值、反馈值和输出值的实时波形进行调参。

常见应用

应用典型参数范围周期
温度控制Kp=210, Ki=0.12, Kd=0.5~5100ms~1s
压力控制Kp=15, Ki=0.55, Kd=0.1~110ms~100ms
流量控制Kp=0.53, Ki=110, Kd=0~0.510ms~50ms
速度控制Kp=0.11, Ki=550, Kd=0.01~0.11ms~10ms

自整定 (Auto-Tuning)

Darra PID 内置三种自整定算法:

继电式自整定 (Relay-based)

经典 Åström-Hägglund 方法, 用继电器方式激励系统产生极限环:

VAR
fbPID : FB_PID;
fbTune : FB_PID_AutoTune;
END_VAR

// 启动自整定
fbTune(
bStart := bBtn_StartTune,
rSetpoint := rSetTemp,
rFeedback := rActTemp,
rRelayAmplitude := 10.0, // 继电幅度 (% 输出)
rHysteresis := 0.5, // 回差 (输入单位)
iMaxCycles := 5, // 最大振荡周期数
tTimeout := T#10m
);

// 自整定完成后写入 PID
IF fbTune.bDone THEN
fbPID.rKp := fbTune.rKp;
fbPID.rKi := fbTune.rKi;
fbPID.rKd := fbTune.rKd;
END_IF;

阶跃响应法

系统稳态时给一个阶跃输入, 根据响应曲线计算参数:

fbTune(
eMethod := E_TuneMethod.STEP_RESPONSE,
rStepSize := 20.0, // 阶跃幅度
tSettleTime := T#2m // 观察时间
);

频率扫描法

依次施加不同频率的正弦扰动, 绘制伯德图找出频率响应, 参数更精确但耗时:

fbTune(
eMethod := E_TuneMethod.FREQ_SWEEP,
rFreqMin := 0.01,
rFreqMax := 10.0,
iPointsPerDecade := 10
);
自整定安全
  • 自整定期间系统会在设定值附近来回振荡, 确保振荡幅度不会超出安全范围
  • 不要在生产运行时做自整定, 应在设备调试期或停机维护时进行
  • 对温度等缓变系统, 自整定可能需要 10~30 分钟
  • 自整定失败时 (未收敛), PID 参数保持不变, 手动调参

前馈控制 (Feed Forward)

前馈在已知扰动的情况下提前补偿, 不用等偏差出现:

FUNCTION_BLOCK FB_PID_FF
VAR_INPUT
rSetpoint : REAL;
rFeedback : REAL;
rDisturbance : REAL; // 测量到的扰动
rFFGain : REAL := 0.5;
// ... 其他 PID 参数
END_VAR
VAR_OUTPUT
rOutput : REAL;
END_VAR

// PID 闭环
fbPID(rSetpoint := rSetpoint, rFeedback := rFeedback, ...);

// 前馈补偿
rFeedForward := rDisturbance * rFFGain;

// 合成输出
rOutput := LIMIT(rOutMin, fbPID.rOutput + rFeedForward, rOutMax);

END_FUNCTION_BLOCK

典型应用: 温度控制中, 冷料投入量已知 → 提前增加加热功率, 不用等温度掉下来再补。

死区 (Deadband)

偏差在死区内时不调整输出, 避免输出抖动:

VAR
rError : REAL;
rDeadband : REAL := 0.5; // ±0.5 死区
END_VAR

rError := rSetpoint - rFeedback;

IF ABS(rError) < rDeadband THEN
rError := 0.0; // 死区内置零
END_IF;

// 用 rError 做 PID 计算

死区用途:

  • 抑制抖动: 输出不会在设定值附近频繁震荡
  • 保护执行器: 减少阀门 / 变频器的动作次数, 延长寿命
  • 节能: 避免无意义的小幅度调节

反风上 (Anti-Windup)

积分器饱和防护, 防止积分项积累导致超调:

方法 1: 条件积分 (Conditional Integration)

输出饱和时停止积分累积:

// 计算积分项
IF NOT (fbPID.bLimited AND fbPID.rError * SIGN(rOutput) > 0.0) THEN
rIntegral := rIntegral + rError * rKi * dt;
END_IF;

方法 2: 回算法 (Back Calculation)

将饱和差值反馈到积分器:

// 回算
rExcess := fbPID.rRawOutput - fbPID.rOutput; // 超出限幅的部分
rIntegral := rIntegral - rExcess * rKt; // 反向衰减

Darra PID 默认启用回算法, 参数 rKt 默认 1 / T_track = 1 / (rKp * 0.5)

级联 PID (Cascaded)

多个 PID 串联, 外环设定值 = 内环输出:

┌──────────────────┐
│ SP_Temperature │ ← HMI 温度设定
└────────┬─────────┘

┌────────┴─────────┐ ← 外环 (慢, 100ms)
│ PID_Temp │
│ 反馈: 温度传感器│
└────────┬─────────┘
↓ (输出作为内环设定值)
┌────────┴─────────┐
│ SP_Flow │
└────────┬─────────┘

┌────────┴─────────┐ ← 内环 (快, 10ms)
│ PID_Flow │
│ 反馈: 流量传感器│
└────────┬─────────┘

阀门开度输出

ST 实现:

// 外环: 温度控制
PROGRAM OB30_100ms // 100ms 周期
VAR
fbPID_Temp : FB_PID;
END_VAR

fbPID_Temp(
rSetpoint := rSetTemp,
rFeedback := rActTemp,
rKp := 2.0, rKi := 0.3, rKd := 0.5,
rOutMin := 0.0, rOutMax := 100.0
);

// 外环输出 = 流量设定值 (传递到内环)
rSetFlow := fbPID_Temp.rOutput;

END_PROGRAM

// 内环: 流量控制
PROGRAM OB30_10ms // 10ms 周期
VAR
fbPID_Flow : FB_PID;
END_VAR

fbPID_Flow(
rSetpoint := rSetFlow, // 来自外环
rFeedback := rActFlow,
rKp := 5.0, rKi := 2.0, rKd := 0.1,
rOutMin := 0.0, rOutMax := 100.0
);

// 最终输出到阀门
%QW200 := REAL_TO_INT(fbPID_Flow.rOutput * 327.67);

END_PROGRAM

级联 PID 的优势:

  • 快速抑制扰动: 内环快速响应流量扰动, 外环负责长期温度稳定
  • 分离时间常数: 内外环独立调参, 内快外慢
  • 限幅更灵活: 外环可直接限制内环设定值上下限

在线调参

PID 调参建议在 趋势图 中观察实时响应:

  1. 配置趋势记录: rSetpoint, rFeedback, rOutput, rError
  2. 采样 10~100ms (根据被控对象时间常数)
  3. 先调 Kp (从 0 开始递增, 直到出现轻微振荡)
  4. 加 Ki 消除稳态误差 (从小值开始, 避免超调)
  5. 加 Kd 抑制超调 (如不需要可保持 0)
  6. 整定期间趋势图记录前后对比

排错表

问题原因解决
输出持续饱和Kp 太大 / 限幅太紧减小 Kp 或放宽限幅
稳态有残差未启用积分增大 Ki
震荡剧烈Kp 太大 / Kd 不够减小 Kp 或增大 Kd
响应缓慢Kp 太小增大 Kp
换方向超调积分饱和确认抗积分饱和已启用
手动→自动切换跳变积分未跟踪启用 Bumpless Transfer
输出抖动未用死区启用死区 rDeadband

最佳实践

  • 先比例, 再积分, 最后微分: 按此顺序调参
  • Ki 一定要限幅: 防止积分饱和引起超调
  • 微分项加滤波: 原始 Kd 对噪声敏感, 建议用 Kd / (1 + s*tau) 滤波
  • OB 周期稳定: PID 放 OB30 (周期中断), 不要放 OB1
  • 级联优于单环: 复杂系统用级联结构, 比单环 PID 更稳
  • 自整定在调试期做, 生产时别动
  • 趋势图长期监控: 24h 记录便于排查偶发问题

相关文档