2.2 KiB
2.2 KiB
FUNCTION "FC_RateLimiter" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
analog_input : Real; // Raw input signal (setpoint or feedback)
pos_slew_rate : Real := 10.0; // Max allowed increase per PLC scan (engineering units)
neg_slew_rate : Real := 10.0; // Max allowed decrease per PLC scan (engineering units)
enable : Bool := TRUE; // Enable rate limiting
reset : Bool := FALSE; // Reset: output snaps to input immediately
END_VAR
VAR_OUTPUT
rate_limited_output : Real; // Slew-rate limited output
END_VAR
VAR
prev_output : Real; // Previous output value (retains between scans)
initialized : Bool := FALSE; // First-run initialization flag
END_VAR
VAR_TEMP
delta : Real; // Calculated change from previous output
max_rise : Real; // Clamped positive limit for this cycle
max_fall : Real; // Clamped negative limit for this cycle
END_VAR
BEGIN
// Handle reset: snap output to input immediately
IF #reset THEN
#rate_limited_output := #analog_input;
#prev_output := #analog_input;
#initialized := TRUE;
RETURN;
END_IF;
// Bypass if disabled: pass-through mode
IF NOT #enable THEN
#rate_limited_output := #analog_input;
#prev_output := #analog_input;
RETURN;
END_IF;
// Initialize on first run to avoid startup transient
IF NOT #initialized THEN
#rate_limited_output := #analog_input;
#prev_output := #analog_input;
#initialized := TRUE;
RETURN;
END_IF;
// Ensure slew rates are non-negative
#max_rise := ABS(#pos_slew_rate);
#max_fall := ABS(#neg_slew_rate);
// Calculate desired change
#delta := #analog_input - #prev_output;
// Apply asymmetric slew limiting
IF #delta > #max_rise THEN
// Rising too fast: limit to max rise
#rate_limited_output := #prev_output + #max_rise;
ELSIF #delta < -#max_fall THEN
// Falling too fast: limit to max fall
#rate_limited_output := #prev_output - #max_fall;
ELSE
// Within allowed slew range: pass through
#rate_limited_output := #analog_input;
END_IF;
// Store for next scan
#prev_output := #rate_limited_output;
END_FUNCTION