diff --git a/rate-limmiter-md b/rate-limmiter-md new file mode 100644 index 0000000..5a8edc0 --- /dev/null +++ b/rate-limmiter-md @@ -0,0 +1,73 @@ +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 \ No newline at end of file