西门子PLC结构化编程_带前馈控制功能的位置式PID控制器
文章目录
- 前言
- 一、功能概述
- 二、公式推导
- 1. 位置式PID公式推导
- 2. 前馈控制PID公式推导
- 三、程序编写
- 1. 新建自定义数据类型“1_PID_Controller”
- 2. 新建FB块“FB36_PID_Controller_Advanced”
- 3. 编写程序
- 总结
前言
在之前的文章中,我们讨论了增量式PID控制模型的实现方法,见文章《西门子PLC结构化编程_增量式PID功能块》。
在该文章中,我们编写的增量式PID控制程序仅仅实现了基础功能,在工业现场实际应用中,还需要添加更多高级功能。故本篇文章将给出一个更加完善的PID控制功能块,增加了手自动无扰切换、前馈控制等功能。
一、功能概述
优化后的PID控制功能块应具备以下功能:
- 完整的PID实现:包含比例、积分、微分三项计算;
- 防积分饱和:可配置的积分上下限,防止积分项过大;
- 死区控制:防止控制元件频繁抖动;
- 基于过程值的微分:避免设定值变化导致误差过大,造成输出冲击;
- 手动/自动无扰切换:在手动模式下保持积分项,切换时无冲击,同时,将当前PID输出值赋给手动设定值;
- 输出限幅:可配置的输出上下限,保护执行机构;
- 状态监控:提供各项输出用于监控和调试;
- 手动模式:PID控制器取消激活,PID输出值等于手动设定值;
- 半自动模式:PID控制器激活,设定值SP由操作员手动设置;
- 自动模式:PID控制器激活,设定值SP由其它连锁条件计算得出
- Kp:增大使响应加快,但过大会导致振荡;
- Ti:减小使积分作用增强,消除稳态误差;
- Td:增大改善稳定性,抑制超调;
- 可选择控制器正作用/反作用;
- 如果过程是正作用(控制量增加→过程值增加),则控制器应设置为反作用;
- 如果过程是反作用(控制量增加→过程值减少),则控制器应设置为正作用;
- 具有前馈控制功能。
二、公式推导
1. 位置式PID公式推导
在连续时间域中,理想的PID控制器公式为:
其中:
u(t)u(t)u(t):控制器输出
e(t)e(t)e(t):误差信号,e(t)=r(t)−y(t)e(t) = r(t) - y(t)e(t)=r(t)−y(t)(设定值 - 过程值)
KpK_pKp:比例增益
TiT_iTi:积分时间
TdT_dTd:微分时间
为了在数字控制器中实现,我们需要将连续时间公式离散化。采用后向差分法进行离散化。
积分项离散化后:
微分项离散化后:
代入到PID计算公式,可得
令:
Ki=KpTTiK_i = K_p \frac{T}{T_i}Ki=KpTiT(积分系数)
Kd=KpTdTK_d = K_p \frac{T_d}{T}Kd=KpTTd(微分系数)
则位置式PID公式可简写为:
2. 前馈控制PID公式推导
常见PID控制器的核心是 “反馈”,它检测到误差 e(t)e(t)e(t)(即目标与现实的偏差)已经发生,然后产生一个控制作用去纠正这个已经存在的偏差,所以反馈控制具有滞后性,它必须等到误差出现后才开始动作。而前馈控制思想是,在可测量的干扰影响到被控变量之前,就提前产生一个控制作用来抵消这个干扰的影响。
最终的控制器输出 u(t)u(t)u(t) 是反馈(PID)输出和前馈输出的叠加:
展开后即为带前馈的PID最终公式:
离散化后的形式:
其中, KffK_{ff}Kff代表前馈增益。
将前馈控制器的输出与PID控制器的输出相加,形成最终的控制作用。前馈负责“粗调”(快速应对主要干扰),PID负责“细调”(精确消除剩余误差和应对其他未知干扰)。
三、程序编写
1. 新建自定义数据类型“1_PID_Controller”
图1
2. 新建FB块“FB36_PID_Controller_Advanced”
在引脚中添加如下变量:
图2
3. 编写程序
REGION 手动、半自动、自动无扰切换IF #PID.HMI.HMIManual THEN#PID.HMI.ManualSetpoint := #PID.HMI.TotalOutput;END_IF;IF #PID.HMI.HMIAuto THEN#PID.HMI.AutoSetpoint := #PID.InPut.SetpointValue;END_IF;IF #PID.HMI.HMISemiAuto THEN#PID.HMI.SemiAutoSetpoint := #PID.InPut.SetpointValue;END_IF;IF #PID.HMI.Manual_DO THEN#PID.Temp.OutputTemp := #PID.HMI.ManualSetpoint;#PID.HMI.TotalOutput := #PID.HMI.ManualSetpoint;#PID.Static.IntegralTerm := #PID.Static.IntegralTerm; // 在手动模式下保持积分项,防止切换回自动时产生冲击#PID.OutPut.ControllerActive := 0;ELSIF#PID.HMI.SemiAuto_DO THEN#PID.InPut.SetpointValue := #PID.HMI.SemiAutoSetpoint;#PID.OutPut.ControllerActive := 1;ELSIF#PID.HMI.Auto_DO THEN#PID.InPut.SetpointValue := #PID.HMI.AutoSetpoint;#PID.OutPut.ControllerActive := 1;END_IF;END_REGIONREGION 初始化IF #PID.Static.FirstScan OR #PID.HMI.HMIReset THEN#PID.OutPut.Output := 0.0;#PID.OutPut.Error := 0.0;#PID.OutPut.Proportional := 0.0;#PID.OutPut.Integral := 0.0;#PID.OutPut.Derivative := 0.0;#PID.OutPut.FeedforwardOutput := 0.0;#PID.HMI.TotalOutput := 0.0;#PID.Static.LastError := 0.0;#PID.Static.IntegralTerm := 0.0;#PID.Static.LastProcessValue := #PID.HMI.ProcessValue;#PID.Static.FirstScan := FALSE;// 设置初始方向IF #PID.HMI.ControllerDirection = 0 THEN#PID.Static.DirectionSign := 1.0; // 正作用ELSIF#PID.HMI.ControllerDirection = 1 THEN#PID.Static.DirectionSign := -1.0; // 反作用END_IF;IF #PID.HMI.HMIReset THENRETURN; // 重置时立即返回,不执行后续计算END_IF;END_IF;// 时间处理#PID.Static.DeltaTime := #PID.InPut.ScanTime / 1000.0;END_REGIONREGION PID计算IF #PID.OutPut.ControllerActive THEN// 根据作用方向计算当前误差 e(t) = Direction * (SP - PV)IF ABS(#PID.InPut.SetpointValue - #PID.HMI.ProcessValue) <= #PID.InPut.DeadValue THEN#PID.Temp.ErrorTemp := 0; // 死区设置ELSE#PID.Temp.ErrorTemp := #PID.Static.DirectionSign * (#PID.InPut.SetpointValue - #PID.HMI.ProcessValue);END_IF;#PID.OutPut.Error := #PID.Temp.ErrorTemp;// 比例项计算 P = Kp × e(t)#PID.Temp.ProportionalTemp := #PID.HMI.Kp * #PID.Temp.ErrorTemp;#PID.OutPut.Proportional := #PID.Temp.ProportionalTemp;// 积分项计算(防积分饱和) I(k) = I(k-1) + (Kp × e(k) × Δt) / TiIF #PID.HMI.Ti > 0.0 AND #PID.Static.DeltaTime > 0.0 THEN#PID.Temp.IntegralTemp := #PID.Static.IntegralTerm + (#PID.HMI.Kp * #PID.Temp.ErrorTemp * #PID.Static.DeltaTime) / #PID.HMI.Ti;// 积分限幅IF #PID.Temp.IntegralTemp > #PID.InPut.IntegralMax THEN#PID.Temp.IntegralTemp := #PID.InPut.IntegralMax;ELSIF #PID.Temp.IntegralTemp < #PID.InPut.IntegralMin THEN#PID.Temp.IntegralTemp := #PID.InPut.IntegralMin;END_IF;#PID.Static.IntegralTerm := #PID.Temp.IntegralTemp;ELSE#PID.Temp.IntegralTemp := 0.0;END_IF;#PID.OutPut.Integral := #PID.Temp.IntegralTemp;// 微分项计算(基于过程值的变化率,避免设定值变化的冲击) D = -Kp × Td × (PV(k) - PV(k-1)) / Δt#PID.Temp.DerivativeTemp := 0.0;IF #PID.HMI.Td > 0.0 AND #PID.Static.DeltaTime > 0.0 THEN#PID.Temp.DerivativeTemp := - #PID.HMI.Kp * #PID.HMI.Td * (#PID.HMI.ProcessValue - #PID.Static.LastProcessValue) / #PID.Static.DeltaTime;END_IF;#PID.OutPut.Derivative := #PID.Temp.DerivativeTemp;// PID输出求和#PID.Temp.OutputTemp := #PID.Temp.ProportionalTemp + #PID.Temp.IntegralTemp + #PID.Temp.DerivativeTemp;// 前馈控制计算IF #PID.InPut.EnableFeedforward THEN// 前馈变化率限制(不使用外部前馈处理程序时使用),确保前馈输入的变化不会超过每秒±5单位的速率限制// #PID.Static.FeedforwardRateLimit := #PID.Static.FeedforwardRateLimit +// LIMIT(MN := -5.0, IN := #PID.InPut.FeedforwardInput - #PID.Static.LastFeedforwardInput, MX := 5.0);// #PID.Static.LastFeedforwardInput := #PID.InPut.FeedforwardInput;// 根据前馈类型计算前馈输出CASE #PID.InPut.FeedforwardType OF0: // 加法前馈,适用于扰动与控制量呈线性关系的系统// #PID.Temp.FeedforwardTemp := #PID.InPut.FeedforwardGain * #PID.Static.FeedforwardRateLimit; // 不使用外部前馈处理程序时使用#PID.Temp.FeedforwardTemp := #PID.InPut.FeedforwardGain * #PID.InPut.FeedforwardInput;1: // 乘法前馈,适用于扰动影响与控制量大小相关的系统// #PID.Temp.FeedforwardTemp := #PID.Temp.OutputTemp * #PID.InPut.FeedforwardGain * #PID.Static.FeedforwardRateLimit; // 不使用外部前馈处理程序时使用#PID.Temp.FeedforwardTemp := #PID.Temp.OutputTemp * #PID.InPut.FeedforwardGain * #PID.InPut.FeedforwardInput / 100.0;ELSE: // 默认加法前馈// #PID.Temp.FeedforwardTemp := #PID.InPut.FeedforwardGain * #PID.Static.FeedforwardRateLimit; // 不使用外部前馈处理程序时使用#PID.Temp.FeedforwardTemp := #PID.InPut.FeedforwardGain * #PID.InPut.FeedforwardInput;END_CASE;// 前馈输出限幅#PID.Temp.FeedforwardTemp := LIMIT(MN := -50.0, IN := #PID.Temp.FeedforwardTemp, MX := 50.0);#PID.OutPut.FeedforwardOutput := #PID.Temp.FeedforwardTemp;// 总输出 = PID输出 + 前馈输出#PID.Temp.OutputTemp := #PID.Temp.OutputTemp + #PID.Temp.FeedforwardTemp;ELSE#PID.OutPut.FeedforwardOutput := 0.0;END_IF;END_IF;// 输出限幅IF #PID.Temp.OutputTemp > #PID.InPut.OutputMax THEN#PID.Temp.OutputTemp := #PID.InPut.OutputMax;// 抗积分饱和: 当输出饱和时,停止积分作用IF #PID.InPut.EnableFeedforward AND (#PID.Temp.OutputTemp - #PID.OutPut.FeedforwardOutput) > #PID.InPut.OutputMax THEN#PID.Static.IntegralTerm := #PID.Static.IntegralTerm - (#PID.Temp.OutputTemp - #PID.OutPut.FeedforwardOutput - #PID.InPut.OutputMax);END_IF;ELSIF #PID.Temp.OutputTemp < #PID.InPut.OutputMin THEN#PID.Temp.OutputTemp := #PID.InPut.OutputMin;// 抗积分饱和: 当输出饱和时,停止积分作用IF #PID.InPut.EnableFeedforward AND (#PID.Temp.OutputTemp - #PID.OutPut.FeedforwardOutput) < #PID.InPut.OutputMin THEN#PID.Static.IntegralTerm := #PID.Static.IntegralTerm - (#PID.Temp.OutputTemp - #PID.OutPut.FeedforwardOutput - #PID.InPut.OutputMin);END_IF;END_IF;#PID.OutPut.Output := #PID.Temp.OutputTemp;#PID.HMI.TotalOutput := #PID.Temp.OutputTemp;// 保存当前值供下次使用#PID.Static.LastError := #PID.Temp.ErrorTemp;#PID.Static.LastProcessValue := #PID.HMI.ProcessValue;// 更新状态#PID.OutPut.DirectionStatus := #PID.HMI.ControllerDirection;END_REGIONREGION 辅助功能// 按钮自复位#PID.HMI.HMIManual := #PID.HMI.HMIManual AND NOT #PID.Temp.HMIManualReset;#PID.HMI.HMISemiAuto := #PID.HMI.HMISemiAuto AND NOT #PID.Temp.HMISemiAutoReset;#PID.HMI.HMIAuto := #PID.HMI.HMIAuto AND NOT #PID.Temp.HMIAutoReset;// #PID.HMI.HMIReset := #PID.HMI.HMIReset AND NOT #PID.Temp.HMIResetReset;// 自动生成复位信号#PID.Temp.HMIManualReset := #PID.HMI.HMIManual;#PID.Temp.HMISemiAutoReset := #PID.HMI.HMISemiAuto;#PID.Temp.HMIAutoReset := #PID.HMI.HMIAuto;// #PID.Temp.HMIResetReset := #PID.HMI.HMIReset;END_REGION
总结
本文给出了优化的PID控制器模型,增加了抗饱和积分、死区控制、前馈控制、手自动无扰切换、作用方向选择等功能。