You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
5.4 KiB
Plaintext

<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4024.12">
<POU Name="fbPID" Id="{ba0371f9-f611-44ea-97d3-8d6e71d4762a}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK fbPID
VAR_INPUT
Setpoint: REAL; (* Desired setpoint *)
ProcessValue: REAL; (* Current process value *)
Enable: BOOL; (* Enable/disable PID control *)
END_VAR
VAR_OUTPUT
ControlOutput: REAL; (* Output of PID controller *)
END_VAR
VAR
// -- PID parameters
Kp: REAL := 0.0; (* Proportional gain *)
Ki: REAL := 0.0; (* Integral gain *)
Kd: REAL := 0.0; (* Derivative gain *)
// -- Internal variables
LastError: REAL := 0.0; (* Error at previous sample *)
Integral: REAL := 0.0; (* Integral of error over time *)
SampleTime: TIME := T#1S; (* Sampling time *)
// -- Auto-tuning parameters
AutoTuneStep: REAL := 0.1; (* Step size for auto-tuning *)
SettlingTime: TIME := T#5S;(* Desired settling time for auto-tuning *)
LastStepTime: TIME := T#0S;(* Time of last auto-tune step *)
AutoTuning: BOOL := FALSE; (* Auto-tuning flag *)
InitStep: BOOL := TRUE; (* Flag for initial step in auto-tuning *)
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[(* Function to perform auto-tuning *)
FUNCTION AutoTunePID : BOOL
VAR
CurrentTime: TIME;
Error: REAL;
DeltaTime: TIME;
BEGIN
CurrentTime := TcSysTime(); (* Get current system time *)
Error := ABS(ProcessValue - Setpoint);
IF Error < 0.05 * Setpoint THEN (* Acceptable error threshold *)
IF NOT InitStep THEN
DeltaTime := CurrentTime - LastStepTime; (* Calculate time difference *)
SampleTime := TIME_TO_REAL(DeltaTime) / 2; (* Calculate sample time *)
Kp := 0.6 / (ProcessValue * AutoTuneStep); (* Calculate proportional gain *)
Ki := 2 * Kp / (0.3 * TIME_TO_REAL(SettlingTime)); (* Calculate integral gain *)
Kd := Kp * 0.125 * TIME_TO_REAL(SettlingTime); (* Calculate derivative gain *)
AutoTuning := FALSE;
AutoTunePID := TRUE;
EXIT;
END_IF;
ELSE
InitStep := FALSE;
LastStepTime := CurrentTime;
IF ProcessValue > Setpoint THEN
ProcessValue := ProcessValue - AutoTuneStep * Setpoint; (* Decrease process value *)
ELSE
ProcessValue := ProcessValue + AutoTuneStep * Setpoint; (* Increase process value *)
END_IF;
END_IF;
AutoTunePID := FALSE;
END_FUNCTION;
(* Function to perform PID control *)
FUNCTION PIDControl : VOID
VAR
Error: REAL;
Proportional: REAL;
IntegralTerm: REAL;
DerivativeTerm: REAL;
BEGIN
IF Enable THEN
Error := Setpoint - ProcessValue;
IF AutoTuning THEN
IF AutoTunePID() THEN
RETURN;
END_IF;
END_IF;
Integral := Integral + (Error * SampleTime); (* Integral term calculation *)
Integral := MAX(MIN(Integral, 1000), -1000); (* Anti-windup limit *)
Proportional := Kp * Error; (* Proportional term *)
IntegralTerm := Ki * Integral; (* Integral term *)
DerivativeTerm := Kd * (Error - LastError) / SampleTime; (* Derivative term *)
ControlOutput := Proportional + IntegralTerm + DerivativeTerm;
LastError := Error; (* Update last error *)
ELSE
ControlOutput := 0.0; (* Disable control if not enabled *)
Integral := 0.0; (* Reset integral term *)
LastError := 0.0; (* Reset last error *)
END_IF;
END_FUNCTION;]]></ST>
</Implementation>
<Method Name="AutoTunePID" Id="{a72ed6ef-5938-4dfc-b7ba-21356dc9bded}">
<Declaration><![CDATA[METHOD AutoTunePID : BOOL
VAR_INPUT
CurrentTime: TIME;
Error: REAL;
DeltaTime: TIME;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[ CurrentTime := TcSysTime(); (* Get current system time *)
Error := ABS(ProcessValue - Setpoint);
IF Error < 0.05 * Setpoint THEN (* Acceptable error threshold *)
IF NOT InitStep THEN
DeltaTime := CurrentTime - LastStepTime; (* Calculate time difference *)
SampleTime := TIME_TO_REAL(DeltaTime) / 2; (* Calculate sample time *)
Kp := 0.6 / (ProcessValue * AutoTuneStep); (* Calculate proportional gain *)
Ki := 2 * Kp / (0.3 * TIME_TO_REAL(SettlingTime)); (* Calculate integral gain *)
Kd := Kp * 0.125 * TIME_TO_REAL(SettlingTime); (* Calculate derivative gain *)
AutoTuning := FALSE;
AutoTunePID := TRUE;
EXIT;
END_IF;
ELSE
InitStep := FALSE;
LastStepTime := CurrentTime;
IF ProcessValue > Setpoint THEN
ProcessValue := ProcessValue - AutoTuneStep * Setpoint; (* Decrease process value *)
ELSE
ProcessValue := ProcessValue + AutoTuneStep * Setpoint; (* Increase process value *)
END_IF;
END_IF;
AutoTunePID := FALSE;]]></ST>
</Implementation>
</Method>
<LineIds Name="fbPID">
<LineId Id="30" Count="65" />
<LineId Id="9" Count="0" />
</LineIds>
<LineIds Name="fbPID.AutoTunePID">
<LineId Id="9" Count="23" />
<LineId Id="5" Count="0" />
</LineIds>
</POU>
</TcPlcObject>