2026-06-01 09:40:38 +00:00
|
|
|
```
|
2026-06-01 09:40:01 +00:00
|
|
|
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;
|
|
|
|
|
|
2026-06-01 09:40:38 +00:00
|
|
|
END_FUNCTION
|
|
|
|
|
|
|
|
|
|
```
|