200PLC PID自编库有与其类似的吗 点击:540 | 回复:0



ws176562

    
  • 精华:0帖
  • 求助:0帖
  • 帖子:1帖 | 32回
  • 年度积分:39
  • 历史总积分:141
  • 注册:2015年2月06日
发表于:2015-07-09 08:28:39
楼主

FUNCTION_BLOCK PID3 (*PID控制器 The PID Controller*)

(*************************************************************************************************************)
(* U(s) 1 Td * s *)
(* 传递函数(Transfer Function): --------- = Kp ( 1 + ---------- + --------------- ) *)
(* E(s) Ti * s 1 + Td * s *)
(*************************************************************************************************************)

(*输入变量 Input Variable--------------------------------------------------------------------------------------------------*)
VAR_INPUT
EN: BOOL :=FALSE; (* 使能:TRUE-有效, FALSE-无效。 / Enable: TRUE-valid, FALSE-invalid.*)
MVManual: REAL := 0; (* 手动输出值。 Manual value for the Manipulated Variable.*)
Auto: BOOL := FALSE; (* 自动模式选择:FALSE-手动,TRUE-自动。 / Automatic mode selection: FALSE-Manual mode, TRUE-Automatic mode.*)
SP: REAL := 0; (* 设定值。 / Set Point.*)
PV: REAL := 0; (* 过程值。 / Process Variable.*)
DirectAction: BOOL :=FALSE; (* 正作用方式选择:FALSE-反作用,TRUE-正作用。 / Direct Action mode selection: FALSE-direct action, TRUE-reverse action.*)
Ts: REAL :=0.05; (* 运算周期(单位:秒),Ts>0。 / Sampling time (Unit: Second) Ts>=0 *)
Kp: REAL :=1; (* 比例增益。 / Propotional gain.*)
Ti: REAL :=1; (* 积分时间(单位:秒),Ti>=0。 / Integral time (Unit: Second) Ti >= 0 *)
Td: REAL :=0; (* 微分时间(单位:秒),Td>=0。 / Differential time (Unit: Second) Td>=0 *)
DeadBand: REAL :=0; (* 偏差死区限,DeadBand>=0。 / Dead Band of Error Variable, DeadBand>=0. *)
MVBias: REAL :=0; (* 前馈控制量。 / Feed forward offset for Manipulated Variable.*)
MVMax: REAL :=100; (* 输出值上限。 / Maximum of Manipulated Variable.*)
MVMin: REAL :=-100; (* 输出值下限。 / Minimum of Manipulated Variable.*)
END_VAR

(*输出变量 Output Variable------------------------------------------------------------------------------------------------*)
VAR_OUTPUT
Q: BOOL :=FALSE; (* 使能状态标志:TRUE-有效,FALSE-无效。 / Status flag of Enable.*)
MV: REAL; (* 控制量输出。 / Manipulated Variable, Output of the PID controller.*)
MVMaxAlarm: BOOL :=FALSE; (* 输出值超上限报警。 / Maximum Alarm of the Manipulated Variable. *)
MVMinAlarm: BOOL :=FALSE; (* 输出值超 下限报警。 / Minimum Alarm of the Manipulated Variable.*)
EV: REAL; (* 设定值与过程值的偏差。 / Error Variable of the set point and the process variable.*)
MVp: REAL; (* 比例分量。 / Proportional item of the Manipulated Variable.*)
MVi: REAL; (* 积分分量。 / Integral item of the Manipulated Variable.*)
MVd: REAL; (* 微分分量。 / Differential item of the Manipulated Variable.*)
END_VAR

(*局部变量 Local Variable----------------------------------------------------------------------------------------------------*)
VAR
(* 以下变量供程序内部计算用,无需赋值 *)
OperationMode: ARRAY [1..2] OF BOOL :=FALSE, FALSE; (* 运行模式数组,用于 “手动/自动” 切换的判断:OperationMode[k]代表当前周期的运行模式,OperationMode[k-1]代表前一周期的运行模式 *)
k: INT :=2; (* k专门用来表示PID的当前运算周期,k-1代表前一运算周期 *)
e: ARRAY [1..2] OF REAL :=0, 0; (* PID离散化运算公式中用到的偏差数组:e[k]代表当前周期的偏差,e[k-1]代表前一周期的偏差 *)
up: ARRAY [2..2] OF REAL :=0; (* PID运算的比例分量数组 :up[k]代表当前周期的比例分量 *)
ui: ARRAY [1..2] OF REAL :=0, 0; (* PID运算的积分分量数组 :ui[k]代表当前周期的比例分量,ui[k-1]代表前一周期的比例分量 *)
ud: ARRAY [1..2] OF REAL :=0, 0; (* PID运算的微分分量数组 :ud[k]代表当前周期的微分分量,ud[k-1]代表前一周期的微分分量 *)
u: ARRAY [2..2] OF REAL :=0; (* PID运算所得的总的控制量数组 :u[k]代表当前周期运算所得的总的控制量*)
alfa: REAL :=1; (* 积分饱和系数:用于积分饱和处理 *)
MVPre: REAL :=0; (* 前一周期PID的控制量输出值*)
END_VAR


(* 算法开始 *)

(*记录前一周期的控制量输出*)
MVPre:=MV; (*2008年12月23日修改*)

(* 1 使能的判断 -----------------------------------------------------------------------------------------------------------------------------------*)
IF EN=FALSE THEN (* 如果使能无效,程序不作任何处理 *)
Q:=FALSE; (* 使能无效,状态标志置为无效 *)
RETURN; (* 跳出程序 *)
ELSE (* EN=TRUE 使能有效*)
Q:=TRUE; (* 使能有效,状态标志置为有效*)
END_IF

(* 2 PID参数的合法性判断-----------------------------------------------------------------------------------------------------------------------*)

(* 2.1 运算周期的合法性判断 *)
IF NOT(Ts>0) THEN (* 运算周期必须大于0,否则置为默认值0.05 *)
Ts:=0.05;
END_IF

(* 2.2 积分时间的合法性判断 *)
IF NOT(Ti>=0) THEN (* 积分时间必须大于等于0,否则置为默认值1*)
Ti:=1;
END_IF

(* 2.3 微分时间的合法性判断*)
IF NOT(Td>=0) THEN (* 微分时间必须大于等于0,否则置为默认值0 *)
Td:=0;
END_IF

(* 2.4 偏差死区的合法性判断*)
IF NOT(DeadBand>=0) THEN (* 偏差死区限必须大于等于0,否则置为默认值0 *)
DeadBand:=0;
END_IF

(* 2.5 输出值上下限的合法性判断 *)
IF NOT(MVMax>MVMin) THEN (* 输出值的上限必须大于输出值的下限,否则上下限同时报警并跳出程序 *)
MVMaxAlarm:=TRUE;
MVMinAlarm:=TRUE;
RETURN; (* 跳出程序 *)
ELSE
MVMaxAlarm:=FALSE;
MVMinAlarm:=FALSE;
END_IF

(* 3 运行模式------------------------------------------------------------------------------------------------------------------------------------------*)

(* 3.1 运行模式数组的周期性更新 *)
OperationMode[k-1]:=OperationMode[k];
OperationMode[k]:=Auto;

(* 3.2 手动/自动 两种运行模式 *)
IF Auto=FALSE THEN (* 手动模式 *)
(* 3.2.1 PID手动模式 *)

(* 3.2.1.1 “自动 ->手动” 模式的无扰切换处理 *)
IF (OperationMode[k-1]=TRUE) AND (OperationMode[k]=FALSE) THEN (* 如果前一周期的运行模式为自动,并且当前周的运行模式为手动,则表示“自动 ->手动” 的切换 *)
MVManual:=MV; (* “自动 ->手动” 切换,只要切换前保证 MVManual=MV, 就能保证切换时无扰动。*)
END_IF

(* 3.2.1.2 手动模式的处理 *)
SP:=PV; (* SP跟踪PV *)

(* 3.2.1.2 手动模式的输出处理 *)
MV:=MVManual; (* 手动输出值 *)
EV:=SP-PV; (* 手动时的偏差输出值 *)

ELSE (* Auto=TRUE 自动模式 *)
(* 3.2.2 PID自动运算 *)

(* 3.2.2.1 “手动 ->自动” 模式的无扰切换处理 *)
IF (OperationMode[k-1]=FALSE) AND (OperationMode[k]=TRUE) THEN (* 如果前一周期的运行模式为手动,并且当前周的运行模式为自动,则表示“手动->自动”的切换 *)
ui[k-1]:=MVPre-MVBias; (* 手动->自动切换,只要切换前保证 u[k-1]+MVBias =MVPre,即 up[k-1]+ui[k-1]+ud[k-1]+MVBias=MVPre, 就能保证切换无扰动。由于切换前SP=PV,E[k-1]=0,up[k-1]=0,ud[k-1]=0,因此有ui[k-1]+MVBias=MVPre *)
END_IF (*2008年12月23日修改*)

(* 3.2.2.2 偏差的计算和处理*)
(* 正反作用的判断 *)
IF DirectAction=FALSE THEN (* 反作用,偏差 EV:=SP-PV *)
EV:=SP-PV;
ELSE (* DirectAction=TRUE 正作用,偏差 EV:=PV-SP *)
EV:=PV-SP;
END_IF
(* 偏差死区的判断 *)
IF ABS(EV)<=DeadBand THEN (* 如果偏差的绝对值小于偏差死区限,即进入偏差死区范围内,则偏差值变为0 *)
EV:=0;
END_IF
(* 公式用到的当前周期的偏差 *)
e[k]:=EV;

(* 3.2.2.3 比例部分*)
up[k]:=Kp*e[k]; (* 比例分量的计算公式*)

(* 3.2.2.4 积分部分 *)
(* 积分饱和处理 *)
IF MV>=MVMax THEN (* 如果输出达到上限,则不再进行正向积分,只进行负向积分 *)
IF e[k]>0 THEN
alfa:=0; (* 正向不积分,积分饱和系数为0*)
ELSE
alfa:=1; (* 负向积分,积分饱和系数为1*)
END_IF
ELSIF MV<=MVMin THEN (* 如果输出达到下限,则不再进行负向积分,只进行正向积分 *)
IF e[k]<0 THEN
alfa:=0; (* 负向不积分,积分饱和系数为0*)
ELSE
alfa:=1; (* 正向积分,积分饱和系数为1*)
END_IF
ELSE (* 其它情况,输出位于上下限之间,正负方向的积分都有效 *)
alfa:=1; (* 正负向都积分,积分饱和系数为1 *)
END_IF
(* 积分分量的计算 *)
IF Ti=0 THEN (* 积分时间Ti等于0时,积分分量为0 *)
ui[k]:=0;
ELSE (* Ti<>0 积分时间Ti不等于0时,积分分量累加 *)
ui[k]:=ui[k-1] + alfa * ( Kp*Ts / Ti ) * e[k]; (* 积分分量的计算公式,带积分饱和处理:积分累加部分乘以积分饱和系数alfa *)
END_IF

(* 3.2.2.5 微分部分 *)
ud[k]:=( Td/ (Ts+Td) ) * ud[k-1] + ( Kp*Td / (Ts+Td ) ) * ( e[k] - e[k-1] ); (* 微分分量的计算公式,带微分滤波处理 *)

(* 3.2.2.6 PID总的运算结果:比例、积分、微分三分量求和 *)
u[k]:=up[k] + ui[k] + ud[k];

(* 3.2.2.7 自动模式的输出处理 *)
MV:=u[k]+MVBias;
MVp:=up[k];
MVi:=ui[k];
MVd:=ud[k];

(*3.2.2.8 运算变量的周期性迭代 *)
e[k-1]:=e[k]; (* 偏差的迭代 *)
ui[k-1]:=ui[k]; (* 积分分量的迭代 *)
ud[k-1]:=ud[k]; (* 微分分量的迭代 *)

END_IF

(* 4 输出超限处理 -------------------------------------------------------------------------------------------------------------------------------------------------*)

(* 4.1 输出超上限处理 *)
IF MV>MVMax THEN
MV:=MVMax; (* 输出超上限时,输出值限定为上限值 *)
MVMaxAlarm:=TRUE; (* 输出超上限报警 *)
ELSE
MVMaxAlarm:=FALSE; (* 上限报警复位*)
END_IF

(* 4.2 输出超下限处理 *)
IF MV<mvmin then MV:=MVMin; (* 输出超下限时,输出值限定为下限值 *)
MVMinAlarm:=TRUE; (* 输出超下限报警 *)
ELSE
MVMinAlarm:=FALSE; (* 下限报警复位*)
END_IF

(* 算法结束*) 

 




热门招聘
相关主题

官方公众号

智造工程师