Problem Overview: Level Control with a Hard Flow Cap
The standard single-loop PID use case on a SIMATIC S7-1200 is straightforward: a process variable (PV) is measured, a setpoint (SP) is supplied, and the controller drives a final control element. The original system uses one PID_Compact block to hold a tank level by positioning a control valve. The operator then requested an additional constraint: a hard cap on the maximum flow rate that the valve can pass, in m³/h.
Implementing this on a Siemens S7-1200 (CPU 1214C DC/DC/DC) under TIA Portal V11 Update 2 requires either a configurable output limit on the existing PID or a true cascade of two PID_Compact blocks. Both approaches are valid; the choice depends on whether the flow cap is a slow supervisory limit (Option A) or a fast, hard-responding constraint (Option B). This article documents the hardware, the PID_Compact parameter set, working SCL code for both options, a tuning sequence, and a troubleshooting matrix.
Why a Cascade Is Often the Right Answer
Clamping the master output to a flow value does work, but if the level setpoint changes drastically, the flow loop will see a step change in setpoint and overshoot. A true cascade — where the inner flow loop tracks its setpoint continuously — removes this overshoot and gives a much faster recovery when the level setpoint is changed, when the incoming feed changes, or when the valve characteristic drifts. The same pattern is used in DCS systems (Honeywell, Emerson DeltaV, ABB 800xA) and is exposed in the S7-1200 through two PID_Compact instances and a small SCL wrapper.
Prerequisites and Hardware
| Item | Specification | Notes |
|---|---|---|
| CPU | SIMATIC S7-1200, CPU 1214C DC/DC/DC (6ES7214-1AE30-0XB0) | Firmware V3.0 or higher; TIA V11 supports up to V4.x |
| Engineering | TIA Portal V11 Update 2 (or later) with STEP 7 Basic | Project must be migrated if opened in V13/V14 |
| Flow transmitter | SITRANS MAG5000 (Siemens 7ME6910-1AA30-1AA0) | 4–20 mA + HART, 24 V DC loop-powered, ±0.4 % of rate accuracy |
| Level transmitter | Hydrostatic, ultrasonic, or guided-wave radar (e.g. SITRANS P500, Probe LU) | 4–20 mA into SM 1231 |
| Control valve | Pneumatically actuated with positioner, or electric actuator (e.g. SIPART PS2) | 4–20 mA input from SM 1232 |
| Analog input | SM 1231 AI4 × 13-bit (6ES7231-4HD32-0XB0) or AI8 | Two channels: level and flow |
| Analog output | SM 1232 AQ2 × 14-bit (6ES7232-4HB32-0XB0) or AQ4 | One channel: valve command |
The 1214C has two on-board analog inputs (0–10 V only) which are not suitable for a 4–20 mA loop without an external 500 Ω resistor. Use a signal module instead. Reference the Siemens Industry Online Support portal for the current S7-1200 system manual entry ID 91696622.
Cascade Control Architecture on the S7-1200
The loop is split into two SISO controllers running at the same OB1 cycle:
- Outer (master) loop: PV = tank level (%), SP = level setpoint (%), Output = flow setpoint (m³/h).
- Inner (slave) loop: PV = measured flow (m³/h), SP = outer-loop output (m³/h), Output = valve position (%).
The inner loop runs 3–10× faster than the outer loop in tuning. On the S7-1200 both blocks run in OB1 (cyclic, default 100 ms). When faster inner-loop dynamics are needed, move the slave PID_Compact into a fixed-time OB (e.g. OB30 at 10 ms) — this is supported on the 1214C firmware V3.0 and above.
Option A: Single PID with Output Clamping
If the flow cap is a soft limit (e.g. the customer wants the pump not to exceed 50 m³/h but a transient overshoot of 55 m³/h for 2 seconds is acceptable), use one PID_Compact and clamp the output using the built-in OutputLimit_High input. This requires no SCL code beyond wiring.
| PID_Compact input | Source | Typical value |
|---|---|---|
| Setpoint | HMI tag, e.g. i_LevelSP
|
50.0 % |
| Input | Scale IW96 to % from SM 1231 channel 0 |
0.0–100.0 % |
| SetpointLimit_High | HMI tag, fixed at 100 % | 100.0 |
| SetpointLimit_Low | Fixed at 0 % | 0.0 |
| OutputLimit_High | HMI tag, e.g. r_MaxFlowSP
|
50.0 m³/h |
| OutputLimit_Low | Fixed at 0 | 0.0 |
Because Output is a flow setpoint in m³/h, the actuator scaling must be handled externally: take PID_Master.OutputPerc and rescale it through a NORM_X / SCALE_X pair to drive the valve via SM 1232 (0–27648 → 0–100 % valve position). The OutputLimit_High directly limits the flow setpoint, so the valve cannot command a flow above the cap.
Limitations of Option A
- Disturbance rejection is slow: a step in upstream pressure can push the flow above the cap for several seconds while the level error decays.
- Valve hysteresis and non-linearity are visible at the flow loop level because there is no inner regulator to linearize them.
- Dead time from valve stroking adds directly to the level loop.
For these reasons, Option B (true cascade) is the recommended architecture for any process where the flow cap is a contractual or safety constraint.
Option B: True Cascade with Two PID_Compact Blocks
Instantiate PID_Compact_1 (master, level → flow SP) and PID_Compact_2 (slave, flow → valve %). Both blocks ship with the STEP 7 Basic installation and require no extra library.
Tag and Instance DB Layout
Create a shared data block (DB10) with the following tags. All values are REAL unless noted.
DATA_BLOCK "ProcessData"
VERSION : 0.1
NON_RETAIN
STRUCT
r_LevelPV : REAL; // % from level xmtr
r_LevelSP : REAL; // % from HMI
r_FlowPV : REAL; // m3/h from Mag5000
r_FlowSPmax : REAL; // hard cap from HMI (m3/h)
r_ValveOut : REAL; // % to SM 1232 AQ
b_MasterAuto : BOOL; // 1 = auto, 0 = manual
b_SlaveAuto : BOOL;
r_MasterManual : REAL; // manual flow SP (m3/h)
r_SlaveManual : REAL; // manual valve %
r_CascadeOn : REAL; // 1.0 = cascade, 0.0 = slave direct
END_STRUCT;
END_DATA_BLOCK
Master PID_Compact Configuration (TIA V11)
| Configuration field | Value | Reason |
|---|---|---|
| Input scaling — lower / upper | 0.0 / 100.0 | Level in % |
| Setpoint scaling — lower / upper | 0.0 / 100.0 | Level SP in % |
| Output scaling — lower / upper | 0.0 / 100.0 | Output in m³/h, scaled in HMI |
| OutputLimit_High | Tag r_FlowSPmax
|
Hard cap on flow setpoint |
| OutputLimit_Low | 0.0 | No reverse flow |
| Retain.CtrlParams.Gain | 1.0 (initial) | Tune in step 3 below |
| Retain.CtrlParams.Ti | 20.0 s (initial) | Tune in step 3 |
| Retain.CtrlParams.Td | 0.0 s | Level loop is generally PI only |
| Retain.CtrlParams.InputScaling.UpperPointIn / UpperPointOut | 27648 / 100.0 | SM 1231 raw to % |
Slave PID_Compact Configuration
| Configuration field | Value |
|---|---|
| Input scaling — lower / upper | 0.0 / r_Mag5000_FullScale (e.g. 100.0 m³/h) |
| Setpoint scaling — lower / upper | 0.0 / 100.0 |
| Output scaling — lower / upper | 0.0 / 100.0 |
| OutputLimit_High | 100.0 (valve fully open cap) |
| OutputLimit_Low | 0.0 |
| Retain.CtrlParams.Gain | 0.5 (initial, often negative on direct-acting valves) |
| Retain.CtrlParams.Ti | 2.0 s (initial) |
| Retain.CtrlParams.Td | 0.0 s |
Action sign — this is the most common commissioning error. If opening the valve increases flow, the slave is direct-acting (Gain > 0). If a pneumatic valve with an air-to-close actuator is used, opening the signal decreases flow, and the slave must be configured as reverse-acting (Gain < 0). The PID_Compact Config.InputScaling and Config.OutputScaling invert the sign if you swap upper and lower values, but the cleanest way is to set Retain.CtrlParams.Gain negative for a reverse-acting loop.
SCL Wrapper for Cascade and Bumpless Transfer
The wrapper sits in OB1 between the two PID_Compact blocks. It performs three jobs: (1) select cascade or slave-only mode, (2) pass master output to slave setpoint with hard clamp, (3) drive the analog output with the slave OutputPerc value.
// Cascade wrapper for S7-1200, TIA V11
// Author: process automation note
FUNCTION_BLOCK "CascadeLevelFlow"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 1.0
VAR_INPUT
i_MasterSP : REAL; // %
i_LevelPV : REAL; // %
i_FlowPV : REAL; // m3/h
i_FlowSPmax : REAL; // m3/h
i_CascadeOn : BOOL;
i_MasterAuto : BOOL;
i_SlaveAuto : BOOL;
i_MasterMan : REAL; // m3/h
i_SlaveMan : REAL; // % valve
END_VAR
VAR_OUTPUT
q_ValveOut : REAL; // % 0..100
q_FlowSP : REAL; // m3/h, clamped
q_MasterOut : REAL; // m3/h, unclamped
END_VAR
VAR
// placeholder for inlined PID_Compact calls
END_VAR
BEGIN
// ---- Master mode selection ----
IF #i_MasterAuto THEN
"PID_Compact_1".ManualEnable := FALSE;
"PID_Compact_1".Setpoint := #i_MasterSP;
"PID_Compact_1".Input := #i_LevelPV;
"PID_Compact_1".OutputLimit_High := #i_FlowSPmax;
ELSE
"PID_Compact_1".ManualEnable := TRUE;
"PID_Compact_1".ManualValue := #i_MasterMan;
END_IF;
// ---- Pass master output (clamped by OutputLimit_High already) to slave SP ----
#q_MasterOut := "PID_Compact_1".Output;
#q_FlowSP := "PID_Compact_1".Output; // already in [0 .. FlowSPmax]
// ---- Hard redundancy clamp in case OutputLimit is misconfigured ----
IF #q_FlowSP > #i_FlowSPmax THEN
#q_FlowSP := #i_FlowSPmax;
END_IF;
IF #q_FlowSP < 0.0 THEN
#q_FlowSP := 0.0;
END_IF;
// ---- Slave mode selection (cascade or direct) ----
IF #i_SlaveAuto THEN
"PID_Compact_2".ManualEnable := FALSE;
IF #i_CascadeOn THEN
"PID_Compact_2".Setpoint := #q_FlowSP;
ELSE
// direct mode: slave follows a local flow SP from HMI
"PID_Compact_2".Setpoint := #i_MasterMan;
END_IF;
"PID_Compact_2".Input := #i_FlowPV;
ELSE
"PID_Compact_2".ManualEnable := TRUE;
"PID_Compact_2".ManualValue := #i_SlaveMan;
END_IF;
#q_ValveOut := "PID_Compact_2".OutputPerc;
END_FUNCTION_BLOCK
The slave's OutputPerc is already in the 0–100 % range. Scale it to the SM 1232 raw value:
// In OB1, after the cascade FB call
"DB10".r_ValveOut := "CascadeLevelFlow".q_ValveOut;
"AQW80" := REAL_TO_INT("CascadeLevelFlow".q_ValveOut * 276.48);
// 0..100 % valve → 0..27648 raw → 0..20 mA on the SM 1232
Anti-Windup and Bumpless Transfer
The PID_Compact block has built-in anti-windup: the integral action stops accumulating when the output saturates at OutputLimit_High or OutputLimit_Low. With TIA V11 this is enabled by default and cannot be disabled in the configuration UI. Verify by looking at the Tuning tab in the PID_Compact configuration editor: the Anti-windup box is greyed out and checked.
Bumpless transfer from manual to auto must be implemented manually. Before the operator flips the mode selector, the ManualValue must be set equal to the current Output. The wrapper above assumes the HMI does this — in WinCC Basic on the Panel KTP600, add a value-change event on the auto bit that pre-loads the manual tag from the controller's output.
Commissioning and Tuning Sequence
Always tune from the inside out. A poorly tuned inner loop cannot be compensated by the outer loop.
-
Step 1 — Slave loop manual check. Put
PID_Compact_2in manual, drive the valve from 0 to 100 % in 10 % steps, record the flow at each step. This confirms valve action (direct or reverse) and gives the process gain Kp. The SITRANS MAG5000 should be set to its engineering units (m³/h) using SIMATIC PDM or the local HMI on the transmitter. -
Step 2 — Slave loop auto tune. Switch the slave to auto, set a flow setpoint of 50 % of full scale, enable the “Tune” button on the PID_Compact commissioning tab. The block runs a step response, calculates Kc, Ti, Td, and writes them to the
Retain.CtrlParamsstructure. Initial Kc is typically 0.2–1.0, Ti 1–5 s for a flow loop. - Step 3 — Master loop auto tune. With the slave on auto and in cascade, set the master setpoint to the current level, then trigger the master tune. The level process is generally much slower, expect Ti 20–60 s and Kc 0.5–3.0. The Mag5000 low-flow cutoff can fool the master tune if level changes during the test cause the flow to cross the cutoff — raise the cutoff to 1 % of full scale for the duration of the tune.
-
Step 4 — Limit verification. Lower
r_FlowSPmaxto 60 % of the actual observed flow. The level controller must back off, the valve must close, and the flow must settle at the new cap within 3–5 slave time constants. If the flow overshoots, increase slave Kc or shorten Ti. - Step 5 — Disturbance test. Drop the level setpoint by 20 % and verify the flow ramps to the cap and stays there until the level approaches the new SP. No flow overshoot above the cap is acceptable. This is the canonical cascade test from any PID theory reference and matches the behavior expected in commercial DCS systems.
Verification Procedure
After commissioning, the following checks must pass before handover:
| Test | Procedure | Pass criterion |
|---|---|---|
| Setpoint tracking | Step level SP from 30 % to 70 % | Level reaches 70 % within 3 time constants, no overshoot > 5 % |
| Flow cap adherence | Set FlowSPmax = 50 m³/h, command 100 % level SP | Flow stays ≤ 50.5 m³/h for the full transient |
| Bumpless transfer | Switch master to manual, change manual SP by 10 %, switch back to auto | Valve does not move on the auto transition (output step < 1 %) |
| Mag5000 totalizer sanity | Open valve to constant 30 m³/h for 60 s | Totalizer increases by 0.5 m³ within ± 2 % |
| Sensor break response | Disconnect level loop at the terminal block | PID goes to configured fault output; valve drives to a safe position (closed) |
Troubleshooting Matrix
| Symptom | Likely cause | Action |
|---|---|---|
| Flow spikes above the cap during level SP step changes | Slave loop is in manual, or slave Kc is too low | Confirm slave AutoEnable = TRUE; raise slave Kc in 20 % steps |
| Level oscillates slowly around the setpoint | Master Ti is too short, or master is fighting with the slave | Double Ti; verify OutputLimit_High on master equals FlowSPmax |
| Valve does not move at all | Wrong action sign: Gain set positive on a reverse-acting valve | Toggle Config.InputScaling upper/lower, or set Kc negative |
| Flow reads negative in HMI | Mag5000 signal wiring reversed (terminals 5/6 swapped) | Power down, swap, restart. Verify in PDM |
| Tune button is greyed out | PID_Compact instance has Config.Mode = 0 (inactive) or the block is in manual | Set Mode = 3 (auto), Mode = 1 (pretuning) for the slave first |
| Output stuck at 100 % | OutputLimit_High left at default 100 % while flow cap is lower | Wire r_FlowSPmax directly to OutputLimit_High on the master |
| Integral winds up and overshoots after a long disturbance | Output limit not active because the SP clamp is on the wrong side | Verify SetpointLimit_High/Low are not limiting the wrong direction |
TIA V11 will not let me edit Retain.CtrlParams.Gain
|
The tag is in the retentive area; switch the view in the DB to Retain or use the PID_Compact configuration editor | Use the editor in the project tree, or right-click the DB and choose “Open in editor” |
| Hard to read flow rate | Mag5000 configured in US gpm or in pulses per gallon, not in m³/h | Re-engineer with PDM or the local three-key keypad; restart the transmitter |
Why the Original Idea of a “Second PID in Cascade” Was Correct
Moving from a single-loop S7-1200 application to a cascade is not a luxury — it is the standard solution in any DCS for the exact problem described: a slow outer variable (level) that must respect a hard inner constraint (flow). The same architecture is used in boiler drum level control (level/flow cascade with three-element trim), fired-heater pass temperature control, and distillation reflux control. The S7-1200 PID_Compact is functionally equivalent to a single-loop block in a DCS, so the same pattern applies unchanged. National Instruments' PID theory primer and the Wikipedia PID article cover the tuning math if deeper theory is needed.
Optional Extensions
Three enhancements are worth considering once the basic cascade is stable:
- Feedforward from the inlet flow: add a bias to the master output proportional to a measured inlet flow. This eliminates the level error caused by a step in the inflow without waiting for the level to drift.
-
Anti-windup on the inner loop during cascade breaks: hold the slave's
ManualValueat the last output when the operator opens the cascade break switch. - Totalizer cross-check: in parallel with the Mag5000 built-in totalizer, integrate the measured flow in OB35 (cyclic interrupt, 100 ms) and alarm if the two diverge by more than 2 %. This catches Mag5000 firmware resets and sensor drift.
Field-Proven Caveats
Two issues show up repeatedly on the S7-1200 platform that do not show up in larger PLCs:
- The CPU 1214C has limited work memory; two PID_Compact blocks plus the SCL wrapper fit, but adding a third (e.g. temperature cascade) can push the work memory close to 75 % — the project will compile but may fail to go to RUN if the retain area overflows. Always test go-online after adding a third PID.
- The on-board analog inputs of the 1214C are 0–10 V only. If a 4–20 mA level transmitter is wired there with a 500 Ω resistor, the loop becomes single-faulted (one resistor failure kills the loop) and breaks the SIL assumption. Use an SM 1231 module instead.
Can the S7-1200 PID_Compact do cascade directly, or do I need extra code?
PID_Compact itself is a single-loop SISO block. Cascade is implemented by instantiating two blocks and writing the master Output into the slave Setpoint, with the OutputLimit_High on the master used to cap the flow setpoint. The SCL wrapper shown above handles mode selection, the hard clamp, and bumpless transfer in roughly 40 lines.
What is the difference between OutputLimit_High and SetpointLimit_High on PID_Compact?
SetpointLimit_High/Low clamps the setpoint the operator can enter (the “knob” limit). OutputLimit_High/Low clamps the controller output (the “valve” limit). For a flow cap you want OutputLimit_High on the master set to the cap value, because the controller output is what becomes the slave's setpoint.
Do I need to tune the inner and outer loops separately?
Yes. Tune the slave (flow) loop first with the master in manual, then tune the master (level) loop with the slave in auto. The slave must be 3–10× faster than the master; if the slave is slower than the master, the cascade will oscillate no matter how good the individual tuning is.
Why does the valve keep moving after I stop the pump?
The PID_Compact block is still active and will keep integrating the level error. Either put the master in manual when the pump is off, or use the SetpointLimit_Low input to hold the master output at 0 when the inlet flow is zero. The latter is cleaner and is the typical DCS practice.
Can I run PID_Compact in OB30 to get a faster inner loop?
Yes, on the 1214C with firmware V3.0 or above. Put the slave PID_Compact in OB30 and set the OB30 cycle to 10–50 ms. The master stays in OB1. This is the standard way to give the inner loop the speed it needs without overloading the cyclic task.