PID regelaar
FUNCTION_BLOCK PID_control
VAR_INPUT
ProcesVal :INT; (*proceswaarde*)
SetVal :LREAL; (*wenswaarde*)
Auto :BOOL; (*als true dan automatisch regelen*)
Direct :BOOL; (*als true dan direct acting, oftewel: verwarmen of koelen *)
TimeBase :LREAL; (*moet 1000 of groter zijn*)
Gain :LREAL; (* Kp *)
ResetRate :LREAL; (* Tr *)
Derivative :LREAL; (* Td *)
END_VAR
VAR_OUTPUT
ControllerOut :LREAL; (* output *)
END_VAR
VAR
testbit : BOOL;
TON_pulstijd : TON;
TON_pauzetijd : TON;
Puls : R_TRIG;
Err : LREAL;
ErrLast : LREAL;
ErrlastLast : LREAL;
ControllerOutTemp : LREAL;
END_VAR
testbit := TRUE;
(* cyclustijd PID regeling*)
TON_pulstijd (in := NOT ton_pauzetijd.Q, PT := LREAL_TO_TIME(Timebase - 500));
TON_pauzetijd (in := ton_pulstijd.Q, PT := t#500ms);
Puls (clk := TON_pulstijd.Q);
(* PID regeling*)
IF
Puls.Q
THEN
IF (*---------------------------------------------------------------------auto mode*)
auto
THEN
Err := SetVal - ProcesVal;
IF (*------------------------direct mode*)
NOT direct
THEN
Err := 0 - Err;
END_IF (*-----------------------------------------*)
(*de PID zelf: *)
ControllerOutTemp := ControllerOut + (Gain * ( Err - ErrLast + (ResetRate * Err) + (Derivative * ( Err -(ErrLast *2) + errlastLast))));
ControllerOut := ControllerOutTemp; (*alleen voor controle, verder is het niet nodig dit via een kladvariabele te doen*)
ErrLastLast := ErrLast;
ErrLast := Err;
ELSE
ControllerOut := 0;
ErrLastLast := Err;
ErrLast := Err;
END_IF (*-------------------------------------------------------------------------------*)
END_IF
IF
ControllerOut > 100
AND auto
THEN
ControllerOut := 100;
END_IF
IF
ControllerOut < 0
OR NOT auto
THEN
ControllerOut := 0;
END_IF
Verbeterde PID regeling.
Deze is ook wat eenvoudiger in te regelen. Begin met de resetrate op 0 en probeer dan een zo rustig mogelijke regeling te krijgen. Daarna pas de resetrate inregelen.
Een begin voor een sealbalk van 350W bij een cyclustijd van 10s: Gain 1,5; ResetRate 0,1; Derivative 40
FUNCTION_BLOCK PID_control_2 VAR_INPUT ProcesVal :INT; (*proceswaarde*) SetVal :LREAL; (*wenswaarde*) Auto :BOOL; (*als true dan automatisch regelen*) Direct :BOOL; (*als true dan direct acting*) Gain :LREAL; (* Kp *) ResetRate :LREAL; (* Tr *) Derivative :LREAL; (* Td *) END_VAR VAR_OUTPUT ControllerOut :LREAL; (* output in 1/10% *) Err :LREAL; (* eigenlijk geen output, maar handig bij inregelen *) END_VAR VAR testbit : BOOL; TON_pulstijd : TON; TON_pauzetijd : TON; Puls : R_TRIG; ProcesVal_D : LREAL; ProcesValLast : LREAL; ControllerOut_temp : LREAL; Feedback : LREAL; END_VAR testbit := TRUE; (*cyclustijd PID regeling*) TON_pulstijd (in := NOT ton_pauzetijd.Q, PT := t#5s); TON_pauzetijd (in := ton_pulstijd.Q, PT := t#5s); Puls (clk := TON_pulstijd.Q); (*PID regeling*) IF Puls.Q THEN IF (*---------------------------------------------------------------------auto mode*) auto THEN ProcesVal_D := ProcesVal + ( ProcesVal - ProcesValLast ) * Derivative; ProcesValLast := ProcesVal; Err := SetVal - ProcesVal_D; IF direct THEN Err := 0 - Err; END_IF ControllerOut_temp := Err * Gain + Feedback; IF ControllerOut_temp > 1000 THEN ControllerOut_temp := 1000; END_IF IF ControllerOut_temp < 0 THEN ControllerOut_temp := 0; END_IF ControllerOut := ControllerOut_temp; Feedback := Feedback + ( Controllerout - Feedback ) * ResetRate; ELSE ProcesValLast := Procesval; Feedback := 0; ControllerOut := 0; END_IF (*-------------------------------------------------------------------------------*) END_IF
Let op: dit is een trage en onnauwkeurige PWM, alleen geschikt voor bijvoorbeeld verwarmingselementen met een PWM cyclusduur van minimaal 1000ms, liefst nog langer!
FUNCTION_BLOCK PWM_simple VAR_INPUT PwmVal :LREAL; PwmTimeBase :LREAL; PwmValMax :LREAL; PwmValMin :LREAL; END_VAR VAR_OUTPUT PwmOutput :BOOL; END_VAR VAR PwmPause : TON; PwmPulse : TON; PwmValPause : LREAL; PwmValPulse : LREAL; END_VAR (*PWM only for slow PMW: periode time must be at least > 1000ms*) IF PwmVal > PwmValMax THEN PwmVal := PwmValMax; END_IF IF PwmVal < PwmValMin THEN PwmVal := PwmValMin; END_IF PwmValPause := PwmTimebase * (100 - PwmVal) /100; PwmValPulse := PwmTimebase * PwmVal /100; PwmPause(IN:= NOT PwmPulse.Q, PT:= LREAL_TO_TIME (PwmValPause)); PwmPulse(IN:= PwmPause.Q, PT:= LREAL_TO_TIME (PwmValPulse)); IF PwmVal > 0 THEN PwmOutput := PwmPause.Q; ELSE PwmOutput := FALSE; END_IF
beschrijving
programma