FUNCTION_BLOCK FB_MovingAverage VAR_INPUT xEnable : BOOL; rInput : REAL; // Raw analog value iWindowSize : INT := 10; // Number of samples (1..100) END_VAR VAR_OUTPUT rOutput : REAL; // Filtered output xReady : BOOL; // TRUE when buffer is full END_VAR VAR arBuffer : ARRAY[0..99] OF REAL; // Circular buffer iIndex : INT := 0; iCount : INT := 0; rSum : REAL := 0.0; iWin : INT; END_VAR IF NOT xEnable THEN rOutput := rInput; iIndex := 0; iCount := 0; rSum := 0.0; RETURN; END_IF; // Clamp window size iWin := MIN(MAX(iWindowSize, 1), 100); // Subtract the oldest value from sum before overwrite rSum := rSum - arBuffer[iIndex]; // Store new value arBuffer[iIndex] := rInput; rSum := rSum + rInput; // Advance circular index iIndex := (iIndex + 1) MOD iWin; // Track how many samples collected IF iCount < iWin THEN iCount := iCount + 1; END_IF; xReady := (iCount >= iWin); rOutput := rSum / INT_TO_REAL(iCount); // Valid even before buffer full