4-20ma

analog

scaling

4-20 mA Scaling Formula: The PLC Engineer's Guide

‌
4-20 mA scaling formula diagram showing PLC analog input conversion to engineering units

Every 4-20 mA transmitter sends you a current that represents a physical value, say 0 to 200 PSI or -40 to 150 °C. Your PLC's analog input module turns that current into a raw integer count. The gap between that raw count and the number you actually want to display, log or act on is the scaling problem. Get it wrong and your HMI shows 47 PSI when the actual pressure is 0, or your high-pressure interlock trips at the wrong setpoint. Get it right and it is just a formula.

The 4-20 mA Scaling Formula

The relationship between current and the measured value is linear, so the scaling is a straight-line interpolation. The general form is:

EU = EU_min + (EU_max - EU_min) × (Raw - Raw_min) / (Raw_max - Raw_min) Where EU = engineering unit output, Raw = raw ADC count from the module, Raw_min = count at 4 mA, Raw_max = count at 20 mA, EU_min = low-end process value, EU_max = high-end process value.

That is it. Everything else is just knowing what Raw_min and Raw_max are for your specific module, and deciding what to do with out-of-range counts.

Raw Count Ranges by Platform

This is where most confusion lives. Different vendors use different ADC resolutions and different count conventions. The formula is the same; the numbers you plug in are not.

Platform / ModuleCount at 4 mA (Raw_min)Count at 20 mA (Raw_max)Notes
Siemens S7-1200 AI (SM 1231)5530276480-27648 = 0-20 mA range; 4 mA sits at 5530
Siemens S7-300/400 AI691227648Same 27648 top; 4 mA = 6912
Rockwell 1756-IF16 (0-21 mA mode)32771638312-bit effective; some configs use 0-32767
Rockwell 1769-IF4 (4-20 mA)624231208Scaled counts; check module config page
CODESYS generic 12-bit AI81940950-4095 for 0-20 mA; 4 mA = 819
Omron NX-AD (16-bit, 4-20 mA)655432767Check IO-Data tab in Sysmac Studio
Mitsubishi Q64AD (4-20 mA mode)04000Factory default; software offset applied
Common raw count ranges for 4-20 mA inputs. Always confirm in the module datasheet before commissioning.
Never assume the counts. A Siemens S7-1200 and an S7-300 both say '0-20 mA' but the count at 4 mA is different (5530 vs 6912). Pull the module manual, not a forum post.

Worked Example: 0-200 PSI Pressure Transmitter on a CODESYS 12-bit Input

Say you have a 0-200 PSI pressure transmitter wired to a generic 12-bit analog input module configured for 4-20 mA. The module outputs 0-4095 counts for 0-20 mA.

  • Raw_min = 819 (4 mA on a 12-bit 0-20 mA range: 4/20 × 4095 = 819)
  • Raw_max = 4095 (20 mA)
  • EU_min = 0 PSI
  • EU_max = 200 PSI
  • Span = Raw_max - Raw_min = 4095 - 819 = 3276 counts

If the module reads 2457 counts:

EU = 0 + 200 × (2457 - 819) / 3276 = 200 × 1638 / 3276 = 200 × 0.5 = 100 PSI

At 2457 counts the transmitter is sitting at half-scale, which is exactly 12 mA. Makes sense.

Scaling in Structured Text (CODESYS / IEC 61131-3)

Here is a clean, reusable function block that does the job. I use REAL math throughout to avoid integer truncation errors, and I clamp the output so a broken cable (counts below 819) does not send a wild negative number to your control logic.

FB_ScaleAnalog.st
FUNCTION_BLOCK FB_ScaleAnalog
VAR_INPUT
    rawValue   : INT;     (* Raw ADC count from module *)
    rawMin     : INT;     (* Count at 4 mA, e.g. 819 for 12-bit 0-20 mA *)
    rawMax     : INT;     (* Count at 20 mA, e.g. 4095 *)
    euMin      : REAL;    (* Engineering unit at 4 mA, e.g. 0.0 *)
    euMax      : REAL;    (* Engineering unit at 20 mA, e.g. 200.0 *)
    clampOutput: BOOL;    (* TRUE = clamp result to euMin..euMax *)
END_VAR
VAR_OUTPUT
    euValue    : REAL;    (* Scaled engineering unit result *)
    underRange : BOOL;    (* Raw below rawMin = wire break / short *)
    overRange  : BOOL;   (* Raw above rawMax = overload or fault *)
END_VAR
VAR
    span       : REAL;
    ratio      : REAL;
END_VAR

span := REAL#1.0 * (rawMax - rawMin);

IF span = 0.0 THEN
    (* Protect against divide-by-zero if misconfigured *)
    euValue   := euMin;
    underRange := FALSE;
    overRange  := FALSE;
    RETURN;
END_IF

ratio    := (INT_TO_REAL(rawValue) - INT_TO_REAL(rawMin)) / span;
euValue  := euMin + ratio * (euMax - euMin);

underRange := rawValue < rawMin;
overRange  := rawValue > rawMax;

IF clampOutput THEN
    IF euValue < euMin THEN euValue := euMin; END_IF
    IF euValue > euMax THEN euValue := euMax; END_IF
END_IF

Call it from your main program like this:

Main.st
VAR
    fbPressure : FB_ScaleAnalog;
    Pressure_PSI : REAL;
    PressureWireFault : BOOL;
END_VAR

(* Called every scan *)
fbPressure(
    rawValue    := AI_Channel1,    (* word from analog input module *)
    rawMin      := 819,
    rawMax      := 4095,
    euMin       := 0.0,
    euMax       := 200.0,
    clampOutput := TRUE
);

Pressure_PSI   := fbPressure.euValue;
PressureWireFault := fbPressure.underRange;
The underRange flag is your wire-break detector. If the current loop is open, the raw count will drop to zero, well below 819. Latch an alarm on that flag rather than acting on the nonsense EU value.

The 3 to 15 PSI Pneumatic Case

One search that comes up a lot is '4-20 mA scaling 3 to 15 PSI'. This is the classic I/P transducer range: 4 mA drives a pneumatic output of 3 PSI, 20 mA drives 15 PSI. Same formula, just different EU limits:

  • EU_min = 3.0 (PSI output at 4 mA)
  • EU_max = 15.0 (PSI output at 20 mA)
  • Use the same Raw_min and Raw_max for your module as before

On a 12-bit module, mid-scale 2457 counts gives: EU = 3 + (15-3) × 0.5 = 3 + 6 = 9 PSI. That is the control point for most spring-diaphragm control valves at 50% lift. Everything lines up.

Siemens S7 Quick Version: NORM_X and SCALE_X

TIA Portal has built-in instructions for this. NORM_X normalises a raw count to a 0.0-1.0 REAL, and SCALE_X maps that to any EU range. Two instructions chained together. The parameters MIN and MAX in NORM_X are where you enter your raw count limits. For an S7-1200 in 4-20 mA mode, set MIN = 5530 and MAX = 27648.

The underlying math is identical to the formula above. NORM_X calculates the ratio, SCALE_X applies it to your EU span. If you understand the formula you can debug NORM_X/SCALE_X problems instantly, which matters when a technician sets the wrong MIN value on site and the reading drifts by 10%.

Siemens NORM_X and SCALE_X blocks for 4-20 mA scaling in TIA Portal
NORM_X normalises the raw count to 0.0-1.0; SCALE_X maps that fraction to your EU range. Same math, two instructions.

Common Scaling Mistakes and How to Avoid Them

  • Using 0 for Raw_min instead of the 4 mA count. If you scale from 0-4095 instead of 819-4095, your zero reading will be wrong by about 20% of span. On a 0-200 PSI transmitter that is a 40 PSI error at zero current.
  • Integer math truncation. Doing (Raw - Raw_min) / (Raw_max - Raw_min) in integer arithmetic in some PLCs truncates to 0 for any input below full scale. Cast to REAL first.
  • Ignoring the underRange flag. A broken cable gives you a stable, believable low reading if you clamp without alarming. Add the wire-break alarm.
  • Mixing up module config and formula. Some modules let you configure them to output pre-scaled REAL values directly (e.g. 0.0 to 100.0%). If you then apply your own formula on top, you double-scale. Check the module output data type in your I/O tree.
  • Not accounting for transmitter live zero vs dead zero. A HART transmitter with 4 mA live zero means 4 mA = valid zero reading. A 0-20 mA transmitter with 0 mA = zero has no wire-break detection. Know which you have.

Use the Analog Scaling Calculator

If you want to verify your numbers quickly, the analog scaling calculator on this site lets you plug in raw counts and EU limits and see the result instantly. Useful for commissioning checks or for explaining the math to a technician on site. You can also use it to reverse-engineer a raw count from a known EU value, which is handy when you are bench-testing a transmitter with a loop calibrator.

Wiring Basics Affect Scaling Accuracy

Scaling math is only as good as the signal feeding it. A voltage drop across a long cable run or a corroded terminal can shift the current seen by the module by 0.2-0.5 mA. On a 16 mA span that is 1-3% error before you even open the PLC. If your scaled value is consistently high or low and the transmitter checks out at the head, measure the actual current at the module terminals with a calibrated clamp meter. For more on getting the wiring right, see PLC Analog Input Wiring: 4-20 mA Step by Step.

For field calibration, use a 4-20 mA loop calibrator (Fluke 707 or similar). Source exactly 4.000 mA and 20.000 mA, read the raw counts in your PLC's online monitor, and use those actual counts as Raw_min and Raw_max. This absorbs any module input impedance error and gives you better accuracy than the datasheet numbers alone.

Scaling Output Signals: PLC to I/P Transducer

The formula works in reverse for analog outputs too. You have an EU value in the PLC (say, a valve position setpoint in percent) and you need to write a raw count to an analog output module that drives a 4-20 mA output.

Raw = Raw_min + (Raw_max - Raw_min) × (EU - EU_min) / (EU_max - EU_min) Same equation rearranged. For a CODESYS 12-bit AO driving 0-100% valve position: Raw = 819 + 3276 × (ValveSetpoint / 100.0)

Clamp the output too. Writing a raw count above 4095 on a 12-bit module does nothing useful, and writing a negative number can cause module faults on some hardware.

Related Blogs