learn · South Africa
Scaling analog signals: 4-20 mA to engineering units
Scaling analog signals from raw 4-20 mA counts to mm, bar, or degC without losing resolution — worked example, common rounding traps, simulator practice.
Scaling analog signals is one of those tasks every PLC technician does in their first month and roughly half of them get subtly wrong for the next ten years. The maths is six lines of high-school algebra. The traps are not in the maths. They are in the data types you choose, the order in which you do the arithmetic, and the moment some loop on the plant goes open-circuit and your transmitter starts feeding the CPU a number it was never meant to see. This tutorial is for the SA technician who has wired a 4-20 mA tank-level transmitter into a Siemens or Rockwell analog input card and now has to turn 0 to 27648 raw counts into 0 to 5000 millimetres without their HMI looking like it was scaled by a child with a ruler.
Try the simulator →Why this matters on real plants
Bad scaling is silent. The HMI does not throw a fault when your tank reads 4830 mm at the top instead of 5000. The operator just thinks the tank is a bit shorter than it should be and waits another minute before opening the discharge valve. That extra minute, repeated four hundred times a day across a batching plant, is real money in lost throughput. We have walked into a brownfield petrochem site where every analog loop on a four-CPU mining plant was scaled to two decimal places and rounded with INT division. The gauge pressure on a primary separator was reading 3.42 bar when the actual sensor was telling them 3.421875 bar. Eighteen kPa lost in a truncation. Across the plant the cumulative bias was bigger than the instrument tolerance the QA team thought they were measuring against.
The cost of getting this wrong scales with how far the number travels. A poorly scaled raw value gets logged into the historian, gets averaged into shift reports, gets fed into the trend pages the production manager looks at on a Monday morning, and gets used in the alarm thresholds the night-shift technician relies on at three in the morning during load-shedding when the diesel just kicked in and the ambient is up by twelve degrees. Each downstream consumer trusts the number. None of them re-scales it. Once you put a wrong number into the historian, it is wrong forever, and back-correcting historian data is a job nobody wants.
The other reason scaling matters more on SA plants than on textbook examples: there is rarely an instrumentation OEM rep within a four-hour drive. When the number on the HMI looks wrong on a Sunday afternoon, the artisan or junior engineer on call has to reason about it from first principles. Knowing the scaling chain by heart — raw counts in, engineering units out, where the rounding happens, what the data type does to negative values — is the difference between a fifteen-minute fix and an eight-hour outage waiting for a callback.
The mental model — one line, both directions
Every linear scaling, on every PLC brand, on every signal type, is the same equation:
EU = (raw - rawLow) / (rawHigh - rawLow) * (euHigh - euLow) + euLow
That is it. Five inputs, one output. raw is whatever the analog input card reports — counts, percent, normalised value. rawLow and rawHigh are the endpoints of the raw range. euLow and euHigh are the endpoints of the engineering range. EU is the answer in real-world units.
Run the equation backward — solve for raw given an EU value — and you get the inverse scaling for analog outputs (sending a setpoint to a 4-20 mA control valve). The equation is bidirectional. Memorise it once and you scale anything: tank level, line pressure, motor current, oven temperature, flow rate, valve position feedback, any 4-20 mA loop or 0-10 V signal or even a 0-100 percent normalised input from a fieldbus drive.
The mental check that catches half of all scaling bugs: substitute raw = rawLow and raw = rawHigh into the equation. You should get exactly euLow and euHigh out. If you do not, the equation is wrong before you even start. We have watched experienced engineers stare at a misbehaving HMI for an hour without doing this two-second check.
Worked example — a 0-5000 mm tank-level transmitter
Open the simulator, drop a Siemens S7-1500 CPU on the rack, and add an analog input module. Wire a virtual 4-20 mA loop to channel 0 and configure the channel for current input in the module properties. The simulator's analog input panel now reports a live raw value between 0 and 27648 — the standard normalised range for Siemens analog cards on a 4-20 mA input, with 0 corresponding to 4 mA and 27648 corresponding to 20 mA. (Rockwell ControlLogix uses a different normalisation by default — typically 0 to 32767 for a 4-20 mA loop with custom scaling per tag. The numbers change. The equation does not.)
The transmitter on the simulator is a level probe in a tank, range 0 to 5000.0 mm. We want the operator to see the level in mm on the HMI faceplate.
Open a new function block in Structured Text and write the scaling block:
FUNCTION_BLOCK fbScaleAnalog
VAR_INPUT
raw : INT;
rawLow : INT := 0;
rawHigh : INT := 27648;
euLow : REAL := 0.0;
euHigh : REAL := 5000.0;
END_VAR
VAR_OUTPUT
eu : REAL;
fault : BOOL;
END_VAR
VAR
rawR : REAL;
rawLowR : REAL;
rawSpanR : REAL;
euSpanR : REAL;
END_VAR
// promote everything to REAL before any divide
rawR := INT_TO_REAL(raw);
rawLowR := INT_TO_REAL(rawLow);
rawSpanR := INT_TO_REAL(rawHigh - rawLow);
euSpanR := euHigh - euLow;
// guard against a divide-by-zero if somebody mis-configures the inputs
IF rawSpanR = 0.0 THEN
eu := euLow;
fault := TRUE;
RETURN;
END_IF;
// guard against transmitter loss: a healthy 4-20 mA loop will never
// drop below ~3.6 mA. Anything under 4 mA on a Siemens card is reported
// as a value below the rawLow and is treated as a wire-break here.
IF raw < (rawLow - 1382) THEN // 1382 counts ~= 0.8 mA below rawLow
eu := euLow;
fault := TRUE;
RETURN;
END_IF;
eu := (rawR - rawLowR) / rawSpanR * euSpanR + euLow;
fault := FALSE;
The order of operations is the part that matters. Promote every operand to REAL before the first divide, then do the divide, then the multiply, then the add. Do it in that order and you keep all the precision of the 14-bit converter. Do it in any other order and the rounding traps catch you.
The simulator has a live raw value indicator on the analog input card — switch to the Watch panel and you can see raw ticking up as you drag the slider on the simulated transmitter. With the FB called every scan, the eu output should track the slider linearly, reading 0.0 mm at 4 mA, 2500.0 mm at 12 mA, and 5000.0 mm at 20 mA. Hover any value in the watch table and the simulator shows the floating-point representation in IEEE 754 alongside the decimal — useful for spotting the small rounding artefacts that any REAL division introduces in the lowest bit.
Common mistakes
-
Doing the division on INTs.
(raw - rawLow) / (rawHigh - rawLow) * (euHigh - euLow)evaluated entirely on INTs gives you 0 for every raw value belowrawHigh / 2because INT division truncates toward zero. The HMI shows a step function — flat zero up to half-scale, then jumps. The fix is to promote to REAL before the divide, every single time. There is no version of this equation that survives integer arithmetic without ugly intermediate scaling, and the few times you need to keep it INT (cycle-time-critical loops on a small CPU) you do(raw - rawLow) * (euHigh - euLow) / (rawHigh - rawLow)so the multiply is done at full INT precision before the divide. Even then, watch for INT overflow at(raw - rawLow) * (euHigh - euLow)— on a Siemens 16-bit INT, anything above 32767 wraps to negative. -
Raw underflow on transmitter loss. A 4-20 mA loop that goes open-circuit reads
0counts on the card, not0mA. A naive scaling gives the operatorEU = -1250 mm(or whatever the under-range produces), and the operator sees a negative tank level on the HMI and assumes the sensor is in fault. Sometimes they do, sometimes they trust the number and start asking why the tank is empty. Always gate the scaling on araw < (rawLow - tolerance)check and raise a wire-break alarm. The simulator's analog card has a configurable wire-break flag on each channel — turn it on and you get the wire-break bit for free. -
Sign errors on bipolar 4-20 mA. A few legacy transmitters output -100% to +100% mapped to 4-20 mA, with 12 mA as the zero. Scaling that as a 0-100% signal gives you values shifted by 50% and you spend a day chasing the offset. Always read the transmitter datasheet and confirm whether the loop is unipolar or bipolar before touching the scaling block. The same equation handles both —
euLowbecomes -100.0 instead of 0.0 — but you have to know which one you are dealing with. -
Scaling by hand on a calculator and hard-coding the result. Every senior PLC artisan has at least one war story of a code review where they found
eu := raw * 0.18083 - 0.7233hard-coded in a transmitter loop and no comment explaining where the magic numbers came from. The maintenance technician three years later cannot back-figure the constants without a spreadsheet. Use a runtime scaling block with named inputs every time. Five inputs into a function block is more readable than two magic constants and survives the next firmware migration.
How to practise this in the simulator
The simulator's timer ladder preset is built around a TON instruction with an analog gate — a perfect target for adding scaling logic. Open the preset, replace the digital gate condition with a comparison against your scaled eu value (for example, eu > 4500.0 to fire the timer when the tank is above 90% full), and watch the timer count up as you drag the analog slider through the upper range. Then break it on purpose: set rawHigh = 0 and watch the divide-by-zero guard kick in. Set the analog input to its under-range value and confirm the wire-break path fires. Switch the data type from REAL to INT and watch the staircase artefacts appear. Twenty minutes of breaking and fixing in the simulator teaches more than two hours of textbook reading.
Vendor reference
The 4-20 mA current loop standard is older than most of the PLCs running on it — the original specifications are documented in IEC 60381-1 and the practical reference for the loop and its history is the Wikipedia current loop article, which covers the live-zero rationale, the wire-break detection logic, and the reason 4 mA was chosen as the offset rather than 0 mA in the first place. Read it once. The live-zero idea is the single most important detail in analog instrumentation and it is the reason every scaling block in production code has a wire-break guard at the top.
What we don't claim
This site is not SAQA-registered, not MerSETA-accredited, and not an NQF-registered qualification provider. Our completion certificates are course-level only — they describe what you covered, not an NQF Level X qualification. The CCST cert from ISA is the portable industry credential we recommend; we are not an ISA cert delivery partner either, but our cert packs are CCST-aligned. Scaling blocks are a small part of the analog-instrumentation portion of the CCST level-1 study guide and the patterns shown here mirror the way the CCST exam frames the topic.