27Industrial patterns
Analogue signal processing: counts to engineering units, NE43 and filtering
The whole analogue input chain: raw counts to engineering units, 4-20 mA scaling, NAMUR NE43 fault bands, an EMA filter, and a rate-of-change limit that catches a failing sensor.
What arrives is not a value
An analogue input does not hand you "52.3%". It hands you counts: an integer from an ADC. And every vendor counts differently:
Family | 0-100% range | Note |
|---|---|---|
Siemens S7 | 0 … 27648 | up to 32511 for over-range |
Rockwell / Allen-Bradley | 0 … 32767 | or a pre-scaled value |
Beckhoff / CODESYS | 0 … 32767 | configurable |
12-bit converter | 0 … 4095 | on simple cards |
27648 is not arbitrary: it is 1.25 × 22118, and the headroom up to 32511 exists because a transmitter can legitimately send more than 20 mA.
The 4-20 mA loop
Field zero is 4 mA, not zero. That is the live zero, and the reason is diagnostic: if the wire breaks the current is zero, zero is not a valid reading, so you know you have a fault. With 0-10 V you cannot tell "zero" from "cut".
mA := 4.0 + Counts * 16.0 / 27648.0;
Eng := (mA - 4.0) * 100.0 / 16.0;Or straight to a general form for any range:
Eng := EngMin + (Counts - CntMin) * (EngMax - EngMin) / (CntMax - CntMin);Write the constants with a decimal point (16.0, not 16) or you do integer division and throw the fraction away.
NAMUR NE43: the current tells you its own health
NAMUR NE43 splits the loop into bands, and it is now general industrial practice:
Current | Meaning |
|---|---|
below 3.6 mA | fault: broken wire or dead transmitter |
3.6 … 3.8 mA | transition band |
3.8 … 20.5 mA | valid measurement, including over-range |
20.5 … 21.0 mA | transition band |
above 21.0 mA | fault: short circuit or failed transmitter |
So do not test "is this value plausible?". Test the current, before scaling. And put a short on-delay on the fault, because an electrical transient is not a failed sensor.
The EMA filter
An exponential moving average is one line, and its memory is one variable:
Filt := Filt + Alpha * (Eng - Filt);Alpha is between 0 and 1. One means no filter, 0.05 is heavy. The relation to a time constant:
Alpha ≈ Ts / (Tau + Ts)At a 50 ms scan, Alpha = 0.15 gives roughly a 280 ms time constant. Rule of thumb: light filtering on level and pressure, heavier on flow, and almost none on anything feeding safety logic, because a filter delays.
The rate-of-change limit
This is the strongest way to catch a sensor failing inside its valid band. Ask what the process can physically do. In this lab the pump moves the level 6% per second, so a 40%-per-second jump is not process, it is a wire or a loose terminal.
Slope := ABS(Eng - Prev) / Ts;
IF Slope > 40.0 THEN
(* do not feed the filter; hold the last good value *)
END_IF;Order matters
Counts, NE43 check, engineering units, rate limit, filter, logic. Never filter before you validate: the filter hides the fault and makes a broken wire look like a dignified slow decline.
Try it in the lab
The lab runs in your browser: an ST editor, a virtual process that suits the lesson, the same program as a live ladder diagram, a watch table, and export to Siemens SCL.
What to try
- Run the program and watch mA, Eng and Filt side by side while the tank cycles between 30 and 85%.
- Notice Filt trailing Eng slightly: that is the filter.
- Hold STOP: mA drops to 0, Bad raises the alarm, the pump stops safely and Eng holds its last good value.
- Change Alpha to 0.5, then to 0.01, and compare.
Terms in this lesson
People find this lesson by searching
4-20mA scaling plc structured textanalog input scaling plcNAMUR NE43 fault bandsraw counts to engineering unitsexponential moving average filter plcsensor fault detection plcrate of change limit plcsiemens 27648 analog scaling
Course outline
- 01What is Structured Text, and when to use it instead of ladder
- 02How a PLC runs your code: the scan cycle and the process image
- 03Program structure: POUs, PROGRAM, FUNCTION and FUNCTION_BLOCK
- 04Your first program: starting a pump with seal-in logic
- 05Data types: BOOL, INT, REAL, TIME and the rest
- 06Declaring variables: VAR, VAR_INPUT and RETAIN
- 07Literals and constants: 16#FF, 2#1010 and T#5s
- 08Type conversion and scaling a 4-20 mA signal
- 09Assignment and arithmetic in ST: := and operator precedence
- 10Boolean logic, comparisons and bit operations
- 11Standard functions: ABS, SQRT, MIN, MAX, LIMIT, SEL, MUX
- 12IF, ELSIF and ELSE: the rules and when to avoid them
- 13The CASE statement and your first state machine
- 14The FOR loop and the watchdog
- 15WHILE, REPEAT, EXIT, CONTINUE and RETURN
- 16Edge detection: R_TRIG, F_TRIG and the "it fired every scan" bug
- 17Timers: TON, TOF and TP
- 18Counters: CTU, CTD and CTUD
- 19SR and RS flip-flops: which one wins
- 20Writing your own function
- 21Writing a function block
- 22Arrays in Structured Text
- 23Structs and enumerations
- 24References and pointers
- 25The state machine pattern: a batch sequence that cannot get stuck
- 26Alarm management to ISA-18.2: delay, deadband, latch, acknowledge, first-out
- 27Analogue signal processing: counts to engineering units, NE43 and filtering
- 28Closed-loop control in ST: hysteresis first, then a practical PID
- 29Motors and valves in practice: permissives, feedback and travel time
- 30The same ST on every platform: SCL, Studio 5000, CODESYS, TwinCAT
- 31Testing and debugging ST: the watch table, forcing and simulation
- 32An ST style guide: naming, comments, constants and version control
- 33Final project: a complete tank station with a state machine and alarms
- 3420 interview questions on ST and PLC programming, with answers