图1.3 微分环节功能块DifferentialBlock
FUNCTION_BLOCK DifferentialBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
IN1: REAL;(*前一个采样周期的输入值*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*微分环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
OUT:=(IN-IN1)/TS;(*微分环节的迭代公式。*)
IN1:=IN;(*输入值替换。*)
END_IF
1.4 一阶惯性环节
一阶惯性环节的传递函数:
所对应的微分方程:
以采样周期TS进行采样,得离散化后的差分方程:
一阶惯性环节功能块FirstOrderLagBlock如图1.4所示,其变量声明和程序代码如下所示。

图1.4 一阶惯性环节功能块FirstOrderLagBlock
FUNCTION_BLOCK FirstOrderLagBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
T: REAL;(*一阶惯性环节的时间常数,秒*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
OUT1: REAL;(*前一个采样周期的输出值*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*一阶惯性环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
OUT:=(TS*IN+T*OUT1)/(T+TS);(*一阶惯性环节的迭代公式。*)
OUT1:=OUT;(*输出值替换。*)
END_IF
1.5 二阶振荡环节
二阶振荡环节的传递函数:
所对应的微分方程:
以采样周期TS进行采样,得离散化后的差分方程:

二阶振荡环节功能块SecondOrderLagBlock如图1.5所示,其变量声明和程序代码如下所示。

图1.5 二阶振荡环节功能块SecondOrderLagBlock
FUNCTION_BLOCK SecondOrderLagBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
T: REAL;(*二阶振荡环节的时间常数,秒*)
Zeta: REAL;(*二阶振荡环节的阻尼比*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
OUT1: REAL;(*前一个采样周期的输出值*)
OUT2: REAL;(*前两个采样周期的输出值*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*二阶振荡环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
OUT:=(TS*TS*IN+2*T*(T+Zeta*TS)*OUT1-T*T*OUT2)/(T*T+2*Zeta*T*TS+TS*TS);(*二阶振荡环节的迭代公式。*)
OUT2:=OUT1;(*输出值替换。*)
OUT1:=OUT;(*输出值替换。*)
END_IF
1.6 一阶微分环节
一阶微分环节的传递函数:
所对应的微分方程:
以采样周期TS进行采样,得离散化后的差分方程:
一阶微分环节功能块FirstOrderLeadBlock如图1.6所示,其变量声明和程序代码如下所示。

图1.6 一阶微分环节功能块FirstOrderLeadBlock
FUNCTION_BLOCK FirstOrderLeadBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
T: REAL;(*一阶微分环节的时间常数,秒*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
IN1: REAL;(*前一个采样周期的输入值*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*一阶微分环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
OUT:=(IN-IN1)*T/TS+IN;(*一阶微分环节的迭代公式。*)
IN1:=IN;(*输入值替换。*)
END_IF
1.7 二阶微分环节
二阶微分环节的传递函数:
所对应的微分方程: 
以采样周期TS进行采样,得离散化后的差分方程:

二阶微分环节功能块SecondOrderLeadBlock如图1.7所示,其变量声明和程序代码如下所示。

图1.7 二阶微分环节功能块SecondOrderLeadBlock
FUNCTION_BLOCK SecondOrderLeadBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
T: REAL;(*二阶微分环节的时间常数,秒*)
Zeta: REAL;(*二阶微分环节的阻尼比*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
IN1: REAL;(*前一个采样周期的输入值*)
IN2: REAL;(*前两个采样周期的输入值*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*二阶微分环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
OUT:=(IN-2*IN1+IN2)*T*T/TS/TS+(IN-IN1)*2*Zeta*T/TS+IN;(*二阶微分环节的迭代公式。*)
IN2:=IN1;(*输入值替换。*)
IN1:=IN;(*输入值替换。*)
END_IF
1.8 延迟环节
延迟环节的传递函数:
所对应的微分方程:
以采样周期TS进行采样,得离散化后的差分方程:
延迟环节功能块DelayBlock如图1.8所示,其变量声明和程序代码如下所示。

图1.8 延迟环节功能块DelayBlock
FUNCTION_BLOCK DelayBlock
VAR_INPUT
IN: REAL;(*输入值*)
TS: REAL;(*采样周期,秒*)
Delay: TIME;(*延迟的时间,秒*)
END_VAR
VAR_OUTPUT
OUT: REAL;(*输出值*)
END_VAR
VAR
TimePeriod: TP;(*定时器*)
RisingTrigger: R_TRIG;(*触发器*)
TONDelay: TON;(*定时器*)
END_VAR
(*采样周期的判断。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*延迟环节的时间响应。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
TONDelay(IN := TRUE, PT := Delay);(*调用定时器。*)
IF TONDelay.Q THEN(*如果到达延迟的时间,则开始输出。*)
OUT := IN;
END_IF
END_IF
2 PID控制的基本原理及离散算法
2.1 PID控制的基本概念
PID控制是控制工程中技术成熟且应用广泛的一种控制策略。经过长期的工程实践,已经形成了一套完整的PID控制方法和典型结构,不仅适用于数学模型已知的控制系统,而且对于数学模型难以确定的工业过程也可以应用。PID控制参数整定方便,结构改变灵活,在众多工业过程控制中取得了满意的应用效果。
在闭环负反馈控制系统中,系统的偏差信号e(t)是系统进行控制的最基本的原始信号。为了提高控制系统的性能指标,可以对偏差信号e(t)进行改造,使其按照某种函数关系进行变化,形成所需要的控制规律u(t),从而使控制系统达到所要求的性能指标,即 
所谓PID控制,就是对偏差信号e(t)进行“比例加积分加微分”形式的改造,形成新的控制规律u(t)。即

其中:
是比例控制部分,
称为比例常数;
是积分控制部分,
称为积分时间常数;
是微分控制部分,
称为微分时间常数。
在零初始条件下,将上式两边取拉普拉斯变换,可得

基于PID控制的闭环负反馈控制系统的传递函数方块图如图2.1所示。

图2.1 基于PID控制的闭环负反馈控制系统
2.2 PID控制的离散算法
(1)位置式算法
设采样周期为T,将前述PID控制规律u(t)进行离散化处理,可得PID控制的第k个采样周期的位置式离散算法u(k)为

其中:
比例控制部分
离散化为
。
积分控制部分
离散化为
。令
,并称为积分控制部分的加权系数。
微分控制部分
离散化为
。令
,并称为微分控制部分的加权系数。
(2)增量式算法
根据PID控制的位置式离散算法,可得PID控制的第k-1个采样周期的位置式输出
为

将上述两式u(k)与u(k-1)相减,可得PID控制的第k个采样周期的增量式离散算法
为

于是可得PID控制的第k个采样周期的位置式输出u(k)为
2.3 PID控制的程序实现
功能块BasicPID如图2.2所示。
在功能块BasicPID中,采用ST语言实现了PID控制的基本离散算法,其变量声明和程序代码如下所示,可以同时提供位置式输出和增量式输出。

图2.2 PID控制的基本离散算法功能块BasicPID
FUNCTION_BLOCK BasicPID
VAR_INPUT
SP: REAL; (* Setpoint/设定点 *)
PV: REAL; (* Process Variable/过程值,或称Input/输入值,或称Feedback/反馈值 *)
TS: REAL := 1; (* Sample Time/采样间隔,或称Loop Update Time/计算周期,秒 *)
KP: REAL := 1; (* ISA Dependent Gains/ISA相关增益,无量纲 *)
TI: REAL := 1; (* Integral Time/积分时间常数>0,秒 *)
TD: REAL := 0; (* Differential Time/微分时间常数>=0,秒 *)
END_VAR
VAR_OUTPUT
CV: REAL; (* Control Variable from the Current Sampling Step/当前采样周期的位置式输出值 *)
dCV: REAL; (* Delta CV or CV Change from the Current Sampling Step/当前采样周期的增量式输出值 *)
END_VAR
VAR
TimePeriod: TP; (* 定时器 *)
RisingTrigger: R_TRIG; (* 触发器 *)
ki: REAL; (* Integral Gain/积分增益系数 *)
kd: REAL; (* Differential Gain/微分增益系数 *)
ev0: REAL; (* Error Variable or System Deviation from the Current Sampling Step/当前采样周期的偏差值ev(k)=SP(k)-PV(k) *)
ev1: REAL; (* Error Variable or System Deviation from the Previous Sampling Step/前一个采样周期的偏差值ev(k-1)=SP(k-1)-PV(k-1) *)
ev2: REAL; (* Error Variable or System Deviation from the Previous before Previous Sampling Step/前两个采样周期的偏差值ev(k-2)=SP(k-2)-PV(k-2) *)
cv1: REAL; (* Control Variable from the Previous Sampling Step/前一个采样周期的位置式输出值 *)
END_VAR
(*参数的判断与计算。*)
IF NOT(TS>0) THEN(*采样周期必须大于0,否则将其置为1秒。*)
TS:=1;
END_IF
IF NOT(TI>0) THEN(*积分时间常数必须大于0,否则将其置为0,表示没有积分环节,但是应当避免被0除。*)
TI:=0;(*如果积分时间常数为负或为0,则将其置为0,表示没有积分环节。*)
ki:=0;(*此时将积分增益系数置为0,表示没有积分环节。*)
ELSE
ki:=KP/TI*TS;(*计算积分增益系数,无量纲/秒*秒=无量纲,即离散化后此系数无量纲。*)
END_IF
IF TD<0 THEN(*可以没有微积分环节,但是微分时间常数不能为负。*)
TD:=0;(*如果微分时间常数为负,则将其置为0,表示没有微分环节。*)
kd:=0;(*此时将微分增益系数置为0,表示没有微分环节。*)
ELSE
kd:=KP*TD/TS;(*计算微分增益系数,无量纲*秒/秒=无量纲,即离散化后此系数无量纲。*)
END_IF
(*采样周期的生成。*)
TimePeriod(IN:=NOT(TimePeriod.Q),PT:=REAL_TO_TIME(TS*1000));(*调用定时器。*)
RisingTrigger(CLK:=TimePeriod.Q);(*调用触发器。*)
(*PID算法的迭代过程。*)
IF RisingTrigger.Q THEN(*在采样时刻进行迭代计算。*)
ev0:=SP-PV;(*计算偏差值。*)
dCV:=KP*(ev0-ev1)+ki*ev0+kd*(ev0-2*ev1+ev2);(*当前采样周期的增量式输出值的迭代公式。*)
CV:=cv1+dCV;(*当前采样周期的位置式输出值的迭代公式。*)
ev2:=ev1;(*偏差值迭代。*)
ev1:=ev0;(*偏差值迭代。*)
cv1:=CV;(*位置式输出值迭代。*)
END_IF
3 算法举例
【例1】某单位负反馈控制系统如图3.1所示,其开环传递函数为。试在PLC中编程计算其单位阶跃响应。

图3.1 单位负反馈控制系统
【解】首先将该系统的开环传递函数分解为典型环节的组合:

因此,该系统的开环传递函数由比例环节
、积分环节
和一阶惯性环节
的串联所组成,其结构分解图如图3.2所示,在编程时可以分别调用上述典型环节所对应的功能块。

图3.2 单位负反馈控制系统的结构分解图
采用LD语言计算该系统的单位阶跃响应,变量声明如下:
PROGRAM PLC_PRG
VAR
Ts1: REAL := 0.1; (* 采样时间,秒 *)
SP1: REAL := 1; (* 设定值 *)
PV1: REAL; (* 过程值 *)
ProportionalBlock1: ProportionalBlock; (* 比例环节 *)
ProportionalBlock1OUT: REAL; (* 比例环节的输出 *)
IntegralBlock1: IntegralBlock; (* 积分环节 *)
IntegralBlock1OUT: REAL; (* 积分环节的输出 *)
FirstOrderLagBlock1: FirstOrderLagBlock; (* 一阶惯性环节 *)
FirstOrderLagBlock1OUT: REAL; (* 一阶惯性环节的输出 *)
END_VAR
LD如图3.3所示,单位阶跃响应曲线如图3.4所示。
图3.3 采用LD计算单位阶跃响应

图3.4 单位阶跃响应曲线
【例2】带有PID控制器的单位负反馈控制系统如图3.5所示,已知
。试在PLC中编程计算其单位阶跃响应。

图3.5 带有PID控制器的单位负反馈控制系统
【解】本例与例1所述的系统基本相同,唯一不同之处是增加了PID控制器。采用CFC语言计算该系统的单位阶跃响应,变量声明如下:
PROGRAM PLC_PRG
VAR
Ts1: REAL := 0.1; (* 采样时间,秒 *)
SP1: REAL := 1; (* 设定值 *)
PV1: REAL; (* 过程值 *)
BasicPID1: BasicPID; (* PID控制器 *)
KP1: REAL := 2; (* PID控制器的相关增益常数,无量纲 *)
TI1: REAL := 3; (* PID控制器的积分时间常数,秒 *)
TD1: REAL := 1; (* PID控制器的微分时间常数,秒 *)
ProportionalBlock1: ProportionalBlock; (* 比例环节 *)
IntegralBlock1: IntegralBlock; (* 积分环节 *)
FirstOrderLagBlock1: FirstOrderLagBlock; (* 一阶惯性环节 *)
END_VAR

图3.6 采用CFC计算带有PID控制器的单位阶跃响应

图3.7 带有PID控制器的单位阶跃响应曲线
CFC如图3.6所示,单位阶跃响应曲线如图3.7所示。比较图3.4和图3.7可以看出,采用PID控制后,改善了系统的综合性能。
——转自《自动化博览》