Filtering a noisy measurement
The Core Idea
A measurement filter smooths rapid changes in a sensor reading. It changes the value the program uses, with a tradeoff between a steadier reading and a slower response to a real process change.
What you will learn
See what a first-order filter does to a noisy level reading: it gets smoother, and it gets later.
Build the filter from three math blocks: every scan, the filtered value moves a fraction K of the way toward the raw reading.
Choose a filter strength that stops an alarm flickering without making it late, and recognize when a signal should not be filtered at all.
Why it matters
A noisy reading can make indications and commands jump around. You need enough smoothing to help the application without hiding changes it must respond to.
The problem
A tank has a level transmitter and a high-level alarm at 70%. The level itself changes smoothly, but the transmitter's reading jumps around it by up to ±8%: electrical noise, a rippling surface, and the transmitter's own resolution all add to the measurement. Near 70% that noise turns the alarm on and off many times a second.
| Signal | What it means |
FILL_SW | TRUE while the fill pump runs. The level rises 10 %/s. The switch runs the pump directly; the program does not use it |
DRAIN_SW | TRUE while the drain valve is open. The level falls 10 %/s |
LEVEL_RAW | The transmitter's reading, in %, with up to ±8% of noise |
FILTER_K | Filter strength (demo only): the fraction of the gap the filtered level closes each 100 ms scan, from 0.02 to 1. At 1 there is no filtering |
LEVEL_GAP | LEVEL_RAW − LEVEL_FILT, in % |
FILTER_STEP | K × LEVEL_GAP, in %: how far the filtered level moves this scan |
LEVEL_FILT | The filtered level, in % |
RAW_HIGH | TRUE while LEVEL_RAW is 70% or more |
FILT_HIGH | TRUE while LEVEL_FILT is 70% or more |
This simulator runs a tank model beside the program: the switches change the level over time, and the transmitter adds noise from a fixed seed, so every run sees the same noise. The trend also shows the Actual level. Only a simulator knows it; a real plant sees only the raw reading, and the program here cannot read it either.
You used math blocks on REAL (floating-point number) values in Scale a 4–20 mA Signal and met alarm chatter in Analog Alarms and Hysteresis.
Predict
Watch the trend at rest first: Raw jumps around, Filtered is nearly flat, and Actual is flat. Then press FILL and watch both alarm lamps. Press FILL again to stop filling, and DRAIN to bring the level back down.
Try it
Keep using the demo above. It appears once you lock in a prediction. Each step uses the FILL and DRAIN buttons, which stay on until pressed again, and the Filter strength K box.
Noise. With K at 0.1, fill until Actual reads about 66% in the trend legend, then stop. HIGH (RAW) flickers on and off, though the tank is 4% below the trip point. HIGH (FILTERED) stays off, and the Filtered trace wobbles by a percent or two instead of eight.
Lag. Fill again past 70%. Filtered runs parallel to Actual but behind it, about 9% lower while the level rises. HIGH (FILTERED) comes on about a second after Actual passes 70%. Stop filling, then drain below 70%: the filtered alarm also clears about a second late.
No filter. Set K to 1. Filtered lies on top of Raw, and both alarms flicker near 70%. K = 1 closes the whole gap every scan, so nothing is smoothed.
Too much filter. Set K to 0.02 and repeat step 2. Filtered is almost a straight line, but it trails a rising level by several seconds, and its alarm comes on long after the tank passed 70%.
Neither extreme is "better". Each K buys smoothness with delay, and the right one depends on what the value is for.
Look closer
Right after the demo starts, Filtered begins at 0% and takes a few seconds to climb to the tank level. That start-up climb is the same lag you saw while filling.
Pause and press Step one scan. In the scan stepper, read LEVEL_RAW, LEVEL_GAP, FILTER_STEP, and LEVEL_FILT. Suppose the raw reading is 47.2% and the filtered level is 40.0%. The gap is 7.2%, a tenth of it is 0.72%, and the filtered level becomes 40.72%. A single noise spike of +8% moves the filtered level by only 0.8%, and the next spike is as likely to go the other way. A real change keeps the gap open scan after scan, so the filtered level keeps following it until it catches up.
The three rungs are a subtract block (SUB), a multiply block (MUL), and an add block (ADD). The same filter in Structured Text is one assignment:
LEVEL_FILT := LEVEL_FILT + FILTER_K * (LEVEL_RAW - LEVEL_FILT);The two alarm rungs are identical except for the value they compare with 70%, using a greater-than-or-equal comparison (GE).
Change it
The guided program has the whole filter, but its multiply block uses K = 1, so the filtered level copies the raw reading. Fill the tank to about 66% and watch both alarms flicker. Change K to 0.1, then fill again: the filtered alarm stops flickering. Then try 0.02 and fill past 70%: now it comes on several seconds late. Run the checks with each value and compare which ones pass.
Check yourself
The challenge program has both alarm rungs, three empty rungs, and no filter. Build the filter, typing your choice of K into the multiply block, so that:
with the tank held at 66%, noise never turns on the filtered alarm, and
while filling at 10 %/s, the filtered alarm stays off until the actual level reaches 70% (at 4.0 s) and is on no more than 2.5 s after that.
Hidden checks hold the tank at 74%, where the alarm must not drop out, and drain it, where the alarm must clear in time. More than one value of K passes; values near either extreme fail one requirement or the other. Retry as often as you need.
Hint 1: What moves, and toward what?Each scan the filtered level moves toward the raw reading. How far should it move?
Hint 2: Three blocksSubtract into LEVEL_GAP, multiply by K into FILTER_STEP, then add into LEVEL_FILT. Use K between 0.05 and 0.3.
Hint 3: The exact blocksLEVEL_GAP = LEVEL_RAW − LEVEL_FILT. FILTER_STEP = LEVEL_GAP × 0.1. LEVEL_FILT = LEVEL_FILT + FILTER_STEP.
Show a worked solution
In the first empty rung, a subtract block takes LEVEL_RAW minus LEVEL_FILT into LEVEL_GAP. In the second, a multiply block takes LEVEL_GAP times 0.1 into FILTER_STEP. In the third, an add block takes LEVEL_FILT plus FILTER_STEP back into LEVEL_FILT. Keep that order so each scan uses the gap it has just calculated.
With K = 0.1 the filtered level wobbles by a percent or two at 66%, well clear of the trip point, and trails a rising level by about 0.9 s, so the alarm comes on about a second after the tank reaches 70%. K = 0.5 lets enough noise through to touch 70% from 66%. K = 0.02 is so slow that the alarm comes on almost 4 s after the tank reaches 70%, past its 2.5 s limit.
What happened and why
On a single scan the filter cannot tell noise from a real change: it moves part of the way toward whatever it reads. Noise goes up and down, so its pushes mostly cancel. A real change pushes the same way scan after scan, so the filtered value follows it, late. Smoothing and delay are one effect seen from two sides, and K sets the trade: a smaller K averages over more scans, which means more smoothing and more delay.
A filter is a trade, not an upgrade. It suits a value that people read, a slow decision, or an alarm that must not nuisance-trip, as long as its delay is acceptable. It does not suit a signal that must act fast. A high-high level that stops a pump before the tank overflows should use the raw reading or its own level switch, because a filter's delay is time the tank keeps filling. For alarm chatter, hysteresis is the other tool: it adds no delay to the measurement, only a reset band. And when the noise comes from wiring or grounding, fix the source before filtering it. Filter as little as the purpose needs. The proportional-integral-derivative (PID) lessons build on this later, with what a filter's delay does inside a control loop.
Show the math
Each scan, LEVEL_FILT new = LEVEL_FILT old + K × (LEVEL_RAW − LEVEL_FILT old) = (1 − K) × LEVEL_FILT old + K × LEVEL_RAW.
Step change. After n scans, the share of a step not yet passed through is (1 − K)ⁿ. With K = 0.1 and 100 ms scans, after 10 scans (1 s) it is 0.9¹⁰ ≈ 0.35, so about 65% of the step has come through.
Delay on a steady rise. The filtered value trails by scan time × (1 − K) ÷ K = 100 ms × 0.9 ÷ 0.1 = 0.9 s. At 10 %/s that is 9%. With K = 0.02 it is 100 ms × 0.98 ÷ 0.02 = 4.9 s.
Noise. When the noise changes every scan, the filtered noise is √(K ÷ (2 − K)) of the raw noise: about 0.23 for K = 0.1, so a raw spread of ±8% shrinks to about ±2% at its rare extremes.
K is per scan. The same K at a 50 ms scan halves the delay, and smooths less. A filter written this way must be retuned if its scan time changes.
Common mistakes
Filtering too hard. Cause: a very small K. Symptom: the display looks calm, but the alarm or display reacts seconds after the process changed. Fix: start from the delay the purpose can accept, then raise K until the delay fits.
Filtering too little. Cause: K near 1. Symptom: the filtered value and its alarm flicker like the raw reading. Fix: lower K, or add hysteresis to the alarm.
Subtracting in the wrong order. Cause:
LEVEL_FILT−LEVEL_RAW. Symptom: the filtered value runs away from the reading instead of settling on it. Fix: the gap isLEVEL_RAW−LEVEL_FILT.Building on the raw reading. Cause: adding
FILTER_STEPtoLEVEL_RAW. Symptom: the result is noisier than the raw reading. Fix: add the step to the previousLEVEL_FILT.Filtering a protective trip. Cause: using one filtered value for every decision. Symptom: the trip acts late exactly when it matters. Fix: give fast protective decisions the raw signal or a separate device.
Platform notes
Many analog input cards have a configurable input filter, set in the card's configuration rather than in the program. Many controllers also offer a first-order filter or lag instruction or function block; IEC 61131-3 (the international standard for programmable controller languages) does not define a standard one, so names and settings differ.
Before relying on a built-in filter, check what its setting means: a time constant in ms or s, a cutoff frequency, or a per-scan factor like K here. Check also whether it runs every scan or on a fixed period. A per-scan factor changes its delay when the scan time changes; a filter on a fixed period or defined by a time constant does not.
Enable JavaScript to run the embedded simulator and complete the interactive exercises.