Running Average Filter for S7-1200 and S7-1500 Analog Inputs

David Krause14 min read
S7-1200SiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Running Average Filter for S7-1200 and S7-1500 Analog Inputs

Pressure transducers installed on hydraulic manifolds, pneumatic networks, and process piping rarely deliver a perfectly stable 4–20 mA or 0–10 V signal. Quantization noise, mechanical vibration, pump ripple, and electrical interference combine to produce a fluctuating reading that the controller must smooth before any closed-loop action is taken. A field engineer measuring a 0–10 bar transducer may see ±0.25 bar of jitter where the process can tolerate only ±0.1 bar. The standard fix is a running average filter built on a fixed-size ring buffer, sampled by a cyclic interrupt OB, and exposed to the application as a single normalized REAL value.

This reference covers the complete implementation path on Siemens S7-1200 and S7-1500 controllers using TIA Portal V17 or later. It includes OB time-base differences, OSCAT FT_AVG usage, custom SCL ring-buffer code, alternative filter topologies (median and exponential moving average), commissioning steps, and a troubleshooting matrix.

1. Problem Definition and Filter Selection

A typical 13-bit analog input on the SM 1231 or SM 531 module delivers a step size of roughly 4.88 µA at 4–20 mA, or 2.44 mV at 0–10 V. After scaling in the PLC, that translates to:

Transducer Range Step Size (13-bit) Step Size (16-bit R)
0–10 bar 0.0012 bar 0.00015 bar
0–100 bar 0.012 bar 0.0015 bar
0–600 bar 0.073 bar 0.009 bar

Quantization is rarely the dominant noise source. The dominant noise is low-frequency mechanical and process noise (pump pulsation at 10–25 Hz, regulator hunting, water hammer). To attenuate that noise without adding 100 ms of dead time, a running average over a sliding window of N samples is the simplest viable solution.

Averaging is a low-pass filter with linear phase and -20 dB/decade roll-off. It does not reject impulse spikes as well as a median filter, but for steady-state pressure monitoring it is sufficient and computationally cheap.

When to choose a running average over EMA

  • Running average: equal weight on every sample in the window. Best when the window length matches a known noise period (e.g., one pump cycle).
  • Exponential moving average (EMA): recent samples weighted higher. Best when the noise spectrum is broadband and you want minimal code footprint.
  • Median filter: rejects impulse spikes (e.g., water hammer). Best when the signal is contaminated by single-sample transients.

2. Prerequisites

Item Specification
Controller SIMATIC S7-1200 (CPU 1211C/1212C/1214C/1215C/1217C, firmware V4.2 or later) or SIMATIC S7-1500 (CPU 1511-1 PN through 1518-4 PN/DP, firmware V2.0 or later)
Engineering software STEP 7 Basic/Professional V17 (or V18/V19 with backward compatibility)
Analog input module SM 1231 (S7-1200) or SM 531 (S7-1500), 8 AI or 16 AI variant
Pressure transducer 4–20 mA two-wire or 0–10 V three-wire, output range scaled in the PLC
Optional library OSCAT BASIC library for S7-1200/S7-1500 (FT_AVG, INC1, DELAY_ function blocks)

Download the S7-1200 system manual, S7-1500 system manual, and TIA Portal programming reference from the Siemens support portal. Confirm the firmware version on your CPU under Online > Accessible devices > CPU > Diagnostics before writing OB time bases.

3. Time Base Difference: S7-1200 vs S7-1500

This is the single most common source of errors when porting code between the two families:

Platform Cyclic OB time unit Example: 100 ms
S7-1200 (OB30–OB38) Milliseconds (ms), integer input Phase time = 100
S7-1500 (OB30–OB38) Microseconds (µs), integer input Phase time = 100000

Configure the OB phase time in the project tree under Program blocks > OB30 > Properties > General > Cycle time. Entering 100 on an S7-1500 would yield a 100 µs OB — 1000× faster than intended and likely to overload the cyclic task.

OB30–OB38 exist on both families. OB30 is the recommended default for time-driven sampling because it has the lowest system priority reserved for cyclic tasks. Avoid OB1 for sampling; OB1 cycle time depends on user program length.

4. Siemens Built-in Analog Input Filtering

Before writing any SCL, evaluate the hardware-side filter on the analog module. SM 1231 and SM 531 modules offer a configurable smoothing factor under Device configuration > Properties > Inputs > Channel > Smoothing:

Smoothing level Equivalent samples Typical use
None 1 Fastest response, raw signal
Weak 4 Light noise, fast PID loops
Medium 16 General process monitoring
Strong 32 Slowly changing pressures, tank level

This is a hardware-configured moving average inside the module firmware. It is the lowest-overhead option and is sufficient for many applications. Switch to software filtering only when:

  1. The required window size is not offered in the module's discrete steps.
  2. You need the filter to survive a module hot-swap with identical parameters.
  3. You need access to both the raw and filtered signal in parallel.

5. Ring Buffer Architecture

The running average is implemented on top of a ring buffer (circular queue) of fixed size N. Every sample period, the oldest value is overwritten with the newest reading. The arithmetic mean is recomputed and made available to the application.

Two implementation strategies are common on S7-1200/S7-1500:

  1. Sum-then-subtract: maintain a running SUM. Add the new sample, subtract the oldest sample, divide by N. O(1) per update.
  2. Full re-sum: iterate over all N slots every update. O(N) per update, simpler to debug.

For N ≤ 64 and 10 ms sample period, both strategies fit comfortably inside the cyclic OB budget on a CPU 1214C. The sum-then-subtract approach is recommended because it avoids accumulator drift from floating-point round-off over long runtimes.

6. OSCAT FT_AVG Implementation

The OSCAT BASIC library (open-source, available for S7-1200 and S7-1500) provides a pre-built running average block called FT_AVG that wraps a ring buffer with internal sum management. The block depends on two helper FBs:

  • INC1 — modulo increment with wraparound.
  • DELAY_ — sample-delay line used as the underlying ring buffer.

6.1 Block interface

Input/Output Name Type Description
INPUT IN REAL New sample to insert into the window
INPUT N INT Window length (number of samples)
INPUT RST BOOL Reset the buffer (clears all slots and sum)
OUTPUT OUT REAL Running average
OUTPUT VALID BOOL TRUE once the window is full

6.2 Program structure

Call FT_AVG from a cyclic OB at the sample period you require:

// OB30 — 10 ms cyclic interrupt (S7-1200: phase = 10; S7-1500: phase = 10000)
// Sample the scaled pressure and feed it to the running average
"FT_AVG_DB"(IN := "Pressure_scaled",
           N  := 10,           // 10 samples × 10 ms = 100 ms window
           RST := FALSE,
           OUT => "Pressure_avg",
           VALID => "Pressure_avg_valid");

Initialize the instance DB on first scan using a one-shot in OB100 (warm restart) or OB101 (hot restart). With this configuration, the controller delivers a fresh average every 10 ms, the window represents the last 100 ms of pressure data, and the VALID output goes TRUE after the first 10 calls (100 ms).

7. Custom SCL Implementation (No External Library)

If the OSCAT library is not approved for the project, build the running average directly in SCL. The block below runs on both S7-1200 (firmware V4.2+) and S7-1500 with identical code.

FUNCTION_BLOCK "FB_RunningAvg"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      InputValue : REAL;            // Latest sample (scaled engineering units)
      WindowSize : INT;             // Number of samples (1..64)
      Reset      : BOOL;            // TRUE clears the buffer
   END_VAR
   VAR_OUTPUT
      Average    : REAL;            // Current running average
      BufferFull : BOOL;            // TRUE after WindowSize samples
      SampleCnt  : INT;             // Number of samples seen since reset
   END_VAR
   VAR
      Buffer     : ARRAY[1..64] OF REAL;
      WriteIdx   : INT;             // Next slot to overwrite (1-based)
      Sum        : LREAL;           // Long-real accumulator, avoids float drift
   END_VAR
   VAR_TEMP
      i : INT;
   END_VAR
BEGIN
   IF Reset OR (WindowSize < 1) THEN
      Sum := 0.0;
      WriteIdx := 1;
      SampleCnt := 0;
      BufferFull := FALSE;
      FOR i := 1 TO 64 DO Buffer[i] := 0.0; END_FOR;
      Average := 0.0;
      RETURN;
   END_IF;

   // Subtract the value about to be overwritten, then add the new sample
   Sum := Sum - Buffer[WriteIdx] + InputValue;
   Buffer[WriteIdx] := InputValue;

   // Advance write index with wraparound
   WriteIdx := WriteIdx + 1;
   IF WriteIdx > WindowSize THEN
      WriteIdx := 1;
      BufferFull := TRUE;
   END_IF;

   // Track total samples for VALID semantics
   IF SampleCnt < WindowSize THEN
      SampleCnt := SampleCnt + 1;
   END_IF;

   Average := REAL(Sum / WindowSize);
END_FUNCTION_BLOCK

7.1 Why LREAL for the sum

S7-1200 REAL (32-bit IEEE 754) provides roughly 7 significant decimal digits. With a 100-bar transducer and a 64-sample window, the running sum reaches 6400 bar; small values added to that sum can lose precision. LREAL (64-bit) gives ~15 digits and is supported on both families. Use LREAL internally, cast to REAL only at the output.

7.2 Calling the FB from a cyclic OB

// OB30 — 10 ms sampling
"iDB_RunningAvg"(InputValue := "Pressure_scaled",
                WindowSize := 10,
                Reset      := FALSE,
                Average    => "Pressure_avg",
                BufferFull => "Pressure_avg_valid",
                SampleCnt  => "Pressure_sample_count");

8. Alternative Filter: Exponential Moving Average

For applications that need a tunable time constant without managing a buffer, EMA is the cheapest option. The single-line update rule is:

y[n] = α·x[n] + (1 − α)·y[n−1]

where α ∈ (0, 1] is the smoothing factor. Equivalent window length is approximately N = 2/α − 1. To match a 100 ms / 10 ms window (N = 10), use α = 0.18.

FUNCTION_BLOCK "FB_EMA"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      InputValue : REAL;
      Alpha      : REAL;   // 0.0..1.0
      Reset      : BOOL;
   END_VAR
   VAR_OUTPUT
      Average : REAL;
   END_VAR
   VAR
      Prev    : REAL;
      Init    : BOOL;
   END_VAR
BEGIN
   IF Reset OR NOT Init THEN
      Prev := InputValue;
      Init := TRUE;
      Average := InputValue;
      RETURN;
   END_IF;
   Prev := Alpha * InputValue + (1.0 - Alpha) * Prev;
   Average := Prev;
END_FUNCTION_BLOCK

EMA reacts faster to real setpoint changes than a sliding window of equal effective length, but it never fully forgets old samples. Use it when RAM is constrained or when the desired window length is non-integer.

9. Alternative Filter: Median-of-5

Median filters reject outliers (single-sample transients from ESD events, valve slam, water hammer). A median-of-5 sorts five consecutive samples and outputs the third. This is recommended for outdoor hydraulic systems with intermittent electrical noise.

// Inside a 10 ms cyclic OB
// SortBuffer[1..5], latest sample in SortBuffer[5]
FOR i := 4 DOWNTO 1 DO
   SortBuffer[i+1] := SortBuffer[i];
END_FOR;
SortBuffer[1] := InputValue;

// Insertion sort (5 elements, negligible cost)
FOR i := 2 TO 5 DO
   key := SortBuffer[i];
   j := i - 1;
   WHILE (j >= 1) AND (SortBuffer[j] > key) DO
      SortBuffer[j+1] := SortBuffer[j];
      j := j - 1;
   END_WHILE;
   SortBuffer[j+1] := key;
END_FOR;
MedianOut := SortBuffer[3];

For many applications, the optimal solution is median-of-5 followed by running average of 4 — that combination rejects impulses and smooths pump pulsation.

10. Step-by-Step Commissioning

  1. Wire and scale the transducer. Connect the pressure transmitter to a free SM 1231/SM 531 channel. Verify the scaling in the technology object or in your FC_Scale block: 4 mA → 0 bar, 20 mA → 10 bar.
  2. Create the cyclic OB. Insert a new Program block > OB > Cyclic interrupt (OB30). Set the phase time to 10 (S7-1200) or 10000 (S7-1500).
  3. Add the filter FB. Insert Program block > FB, paste the SCL from section 7, compile.
  4. Create an instance DB. Right-click the FB, select Generate instance DB.
  5. Call the FB from OB30. Wire the scaled pressure input and set WindowSize = 10.
  6. Initialize on restart. In OB100, set iDB_RunningAvg.Reset := TRUE on the first scan so the buffer starts clean.
  7. Download and go online. Add the filter tags to a watch table. Force the input to a known static pressure and observe the average converge.
  8. Verify VALID. Confirm Pressure_avg_valid goes TRUE within 100 ms of startup.
  9. Tune window size. Increase N until output jitter is below the application threshold (e.g., 0.1 bar). Decrease N if the average lags actual process changes too much.

11. Verification and Diagnostics

Add the following tags to a watch table or HMI trend:

Tag Type Expected behavior
Pressure_scaled REAL Raw scaled pressure, noisy
Pressure_avg REAL Smoothed value, ±0.1 bar jitter on a 0–10 bar transducer
Pressure_avg_valid BOOL TRUE after 100 ms; FALSE only during reset
Pressure_sample_count INT Rises 0 → 10 within first 100 ms, then steady
OB30_execution_us DINT OB30 run time; should stay well below 10000 µs
OB30_overflow_count DINT Non-zero indicates the OB is missing its phase time

To check OB30 run time programmatically, read OB30_PREV_CYCLE (microseconds) inside the OB. If it exceeds the configured phase time, the cyclic task is being pre-empted — typically by a higher-priority OB or by long execution in OB1.

12. Troubleshooting Matrix

Symptom Likely cause Remediation
Average never changes Input wired to wrong tag; instance DB not refreshed Re-check the call in OB30, confirm the input is non-zero in the watch table
Average stays at 0.0 Reset held TRUE by latching logic Reset the reset coil; verify OB100 one-shot logic
VALID never goes TRUE WindowSize = 0 or negative Clamp WindowSize to 1..64 at the call site
Jitter still ±0.25 bar WindowSize too small or sample period too long Increase N to 25 or sample at 5 ms
Average lags real changes by > 1 s Window too large Reduce N or switch to EMA with α ≈ 0.2
OB30 cycle time exceeded warning Filter FB called from OB1 instead of OB30, or N too large Move call to OB30; verify with OB30_PREV_CYCLE
Drift in average over hours REAL accumulator losing precision Use LREAL internally as shown in section 7
Output spikes during pump start Mechanical transient wider than window Add median-of-5 stage ahead of the average
Different result on S7-1200 vs S7-1500 OB phase time unit mismatch S7-1200 uses ms, S7-1500 uses µs — fix in OB properties
Filter jumps on cold restart Buffer not initialized Drive RST in OB100 on first scan

13. Performance and Resource Budget

On a CPU 1214C (firmware V4.4), the running average FB with N = 32 executes in roughly 80 µs of OB30 time, leaving > 99 % of the 10 000 µs phase budget available for other cyclic work. On a CPU 1516-3 PN/DP, the same block executes in ~5 µs.

Window N Approx. memory (instance DB) Approx. CPU 1214C OB30 time
10 328 bytes 30 µs
32 920 bytes 80 µs
64 1.7 KB 150 µs

For applications that need N > 256, consider whether the time constant justifies the buffer size, or switch to EMA.

14. Integration with PID and Control Loops

If the averaged pressure feeds a PID compact block (PID_Compact for S7-1200, PID_Compact for S7-1500), feed Pressure_avg into the Setpoint and Input parameters. Do not feed the raw noisy signal — the integral term will accumulate quantization noise and produce integrator windup.

Set the PID sampling time to a multiple of the filter window. With a 100 ms filter, a 100 ms PID cycle is acceptable; 1 s is preferred for slow pressure loops. The PID_Compact block's input scaling and process value limits apply downstream of the filter.

If the application requires filtering on the setpoint path as well, run a separate FB instance with identical parameters on the setpoint value. This prevents mismatch between PV and SP dynamics.

15. Field-Proven Tips

  • Always scale the analog input first, then filter. Filtering raw counts introduces non-linearities when the scale curve is non-linear (e.g., square-root for flow).
  • Keep the cyclic OB priority low (OB30, priority 7) and let OB1 run the main sequence. Do not nest filter calls inside FB calls triggered by hardware interrupts unless you can prove the timing budget.
  • Document the WindowSize, sample period, and OB number on the HMI faceplate so maintenance staff can identify which filter is in service.
  • For safety-relevant signals (SIL 2/3), the running average is non-deterministic in response time. Use a separate, certified filter path.
  • On TIA Portal V18 and later, you can use the Trace function to record both the raw and filtered signals simultaneously for tuning.

16. Reference Material

Verify the OB configuration and time-base semantics against the official Siemens documentation:

FAQ

What OB time value should I enter for a 10 ms cyclic interrupt on S7-1200 versus S7-1500?

On S7-1200, set the cyclic OB phase time to 10 (milliseconds). On S7-1500, set it to 10000 (microseconds). Entering 10 on an S7-1500 would call the OB every 10 µs and likely fault the CPU.

How do I stop my 0.25 bar pressure fluctuation without slowing down the control loop?

Use a running average with a window length matched to the dominant noise period. For 100 ms of pump pulsation, sample every 10 ms and average 10 samples (N=10). This delivers a fresh average every 10 ms while cutting jitter by a factor of √10.

Should I use the OSCAT FT_AVG block or a custom SCL implementation?

Use FT_AVG if OSCAT is already approved in your project; it is tested and widely deployed. Use the custom SCL from this article when OSCAT is not permitted or when you need an LREAL accumulator to avoid drift over very long runtimes.

Why does my averaged pressure drift upward over hours of operation?

You are accumulating the running sum in a 32-bit REAL. With large transducer ranges and N above ~32, the precision loss becomes visible. Switch the internal accumulator to LREAL and convert back to REAL at the FB output.

Can the SM 1231 hardware smoothing replace the SCL running average?

For most pressure applications, yes — set the channel smoothing to "Medium" or "Strong" in the device configuration and no software filter is needed. Use a software filter when you need a non-standard window size, when you need to access both raw and filtered values, or when module hot-swap must preserve filter behavior.

Back to blog