FUNCTION_BLOCK "FB_RFG_W_RND1"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
i_x : Int; // setpoint
i_high : Real;
i_low : Real;
i_rampTime : Real; // ramp time
i_RndTime : Real; // rounding time
i_Clock : Bool;
i_reset : Bool;
END_VAR
VAR_OUTPUT
o_Y : Real;
END_VAR
VAR
error : Real;
deadband : Real;
timer1 : Int;
Imp_Clock : Bool;
YB : Real;
YA_new : Real;
YA_old : Real;
Y_new : Real;
Y_old : Real;
ph1_started_up : Bool; // phase 1 ramp up started
ph2_started_up : Bool; // phase 2 ramp up started
ph3_started_up : Bool; // phase 3 ramp up started
ph1_started_dn : Bool; // phase 1 ramp down started
ph2_started_dn : Bool; // phase 2 ramp down started
ph3_started_dn : Bool; // phase 3 ramp down started
END_VAR
VAR_TEMP
YAmax : Real;
TU : Real; // ramp-up time
TRU : Real; // rounding ramp--up time
TA : Real;
l_errorThres : Real;
l_decelerFactor : Real;
END_VAR
BEGIN
//setpoint x[n] is in %
//define parameters
#YAmax := 0.01; //maximum ROC of output
#TU := #i_rampTime; //ramp time (ROC is limited)
#TRU := #i_RndTime; //rounding time (ROC is changing)
#TA := 0.005; //Determines YB value (rate of rate of change of Y). If changed->adapt also the #l_errorThres
#YB := (#TA / #TRU) * #YAmax; //determine rate of change of ROC of Y
#l_errorThres := 1.0; //threshold from which error to start phase 3
#l_decelerFactor := 3.0; //how fast we want to converge to sp during phase 3
IF #i_reset THEN
#YA_new := 0.0;
#YA_old := 0.0;
#Y_new := 0.0;
#Y_old := 0.0;
#ph1_started_up := false;
#ph2_started_up := false;
#ph3_started_up := false;
#ph1_started_dn := false;
#ph2_started_dn := false;
#ph3_started_dn := false;
END_IF;
#deadband := 0.1;
#error := DINT_TO_REAL(#i_x) - #Y_old;
IF ABS(#error) <= #deadband THEN //x[n]=y[n]
#timer1 := 0;
#Imp_Clock := false;
#YA_new := 0.0;
#ph1_started_up := false;
#ph2_started_up := false;
#ph3_started_up := false;
#ph1_started_dn := false;
#ph2_started_dn := false;
#ph3_started_dn := false;
ELSE
IF #i_Clock AND NOT #Imp_Clock THEN //solong as x[n]!=y[n] count with clock pulse
#Imp_Clock := true; //Zeitgeber ist überflüssig
#timer1 := #timer1 + 1;
ELSIF NOT #i_Clock THEN
#Imp_Clock := false;
END_IF;
IF #error > 0 THEN
IF #ph1_started_dn OR #ph2_started_dn OR #ph3_started_dn THEN //sudden change of sp to higher value than y[n]
#ph1_started_dn := false;
#ph2_started_dn := false;
#ph3_started_dn := false;
END_IF;
IF #timer1 > 0 AND #YA_new < #YAmax AND (NOT #ph3_started_up OR #error > #l_errorThres) THEN
#ph1_started_up := true;
#YA_new := #YA_old + #YB; //rounding interval
#Y_new := #Y_old + #YA_new;
ELSIF #timer1 > 0 AND #YA_new >= #YAmax AND #error > #l_errorThres THEN
#ph2_started_up := true;
#YA_new := #YAmax; //ramp interval
#Y_new := #Y_old + #YAmax;
ELSIF #timer1 > 0 AND #ph2_started_up OR (#ph1_started_up AND #error <= #l_errorThres) THEN
#ph3_started_up := true;
IF #YA_new > 20 * #YB THEN
#YA_new := #YA_old - #l_decelerFactor * #YB; //rounding interval
END_IF;
#Y_new := #Y_old + #YA_new;
END_IF;
ELSE //error<0
IF #ph1_started_up OR #ph2_started_up OR #ph3_started_up THEN //sudden change of sp to lower value than y[n]
#ph1_started_up := false;
#ph2_started_up := false;
#ph3_started_up := false;
END_IF;
IF #timer1 > 0 AND #YA_new > - #YAmax AND (NOT #ph3_started_dn OR #error < - #l_errorThres) THEN
#ph1_started_dn := true;
#YA_new := #YA_old - #YB; //rounding interval
#Y_new := #Y_old + #YA_new;
ELSIF #timer1 > 0 AND #YA_new <= - #YAmax AND #error < - #l_errorThres THEN
#ph2_started_dn := true;
#YA_new := - #YAmax;
#Y_new := #Y_old - #YAmax;
ELSIF #timer1 > 0 AND #ph2_started_dn OR (#ph1_started_dn AND #error >= - #l_errorThres) THEN
#ph3_started_dn := true;
IF #YA_new < -20 * #YB THEN
#YA_new := #YA_old + #l_decelerFactor * #YB; //rounding interval
END_IF;
#Y_new := #Y_old + #YA_new;
END_IF;
END_IF;
END_IF;
#YA_old := #YA_new;
#Y_old := #Y_new;
//output
#o_Y := #Y_new;
END_FUNCTION_BLOCK