S7-1200 PID_Compact: Enable, Tuning, and Adaptive Control

David Krause14 min read
PID ControlSiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

The PID_Compact instruction shipped with the S7-1200 CPU firmware and TIA Portal is the standard closed-loop block for temperature, level, flow, and pressure loops. In TIA Portal V13 with firmware V4.x, the block ships as PID_Compact V2.x, which has a stricter enable contract than the older V1.x block used on firmware V3.x. Field engineers most often hit three problems: the block never turns green (Input/Input_PER out of range), an aggressive output that slams to 100% the instant the loop is enabled, and the inability to simulate the V2.x block inside S7-PLCSIM V13. This reference covers the root cause, the working signal ranges, the simulation downgrade path, bumpless transfer, output slew limiting, PWM configuration, and a practical SCL scaffold for adaptive gain.

Prerequisites

  • SIMATIC S7-1200 CPU (any V4.x firmware; tested behavior on 1212C, 1214C, 1215C, 1217C, 1500S-compatible 1200G).
  • TIA Portal V13 SP1 / V13 Update 9 or later, with PID_Compact V2.x installed from the HSP or library.
  • SM1231 analog input module or onboard AI for the differential-pressure (DP) cell.
  • For commissioning without real plant: S7-PLCSIM V13 (note the simulation limitation described below).
  • Project background OB (typically OB1, OB35 cyclic interrupt at 100 ms for level loops).
Compatibility warning: PID_Compact V2.x is generated by TIA Portal V13 Update 8 and later. Mixing V2.x blocks with PLCSIM V13 on an S7-1200 plant configuration is a known dead end; the block stays in NotEnabled state regardless of input validity. See the Siemens KB 79047807 - PID_Compact does not work in simulation entry for the official statement.

PID_Compact Block Architecture

PID_Compact is a self-tuning, fixed-cycle controller with anti-windup, setpoint ramp, output scaling, and three output modes (analog, PWM, motor stepper). The V2.x block exposes a richer I/O image than V1.x, including Input (floating-point process value, % of scaled range), Input_PER (raw peripheral word, e.g. 0–27648), Setpoint, Disturbance, ManualEnable, and a multi-instance Config / Retain / Cycle structure. The controller sub-state machine is exposed on Instance.State (numeric) and Instance.StateString (text), which the operator faceplate reads directly.

Field Type Range / Units Notes
Input REAL −100.0 … +100.0 (%) by default; user-scalable Engineering units after scaling block
Input_PER INT 0 … 27648 (unipolar) or ±27648 (bipolar) Direct from %IW
Setpoint REAL Same range as Input User units, e.g. 0–500 mm H₂O
Output / Output_PER / Output_PWM REAL / INT / BOOL 0–100 % (analog) or 0–100 % duty (PWM) Mode selected in Config
Cycle TIME ≥ 0.1 s (PID) / ≥ 0.01 s (PWM) OB1 default vs. OB35
Retain.CtrlParams.Gain REAL 0.0 … +∞ Tuned value
Retain.CtrlParams.Ti / Td TIME 0.0 s disables I / D Integral and derivative time

Enable Conditions and Input Range

The block refuses to leave the NotEnabled state (faceplate stays gray) when one of the following preconditions is violated:

  1. Process value out of range. Input must lie within the configured scale (default −100 % to +100 %, equivalent to the high/low limits of Config.InputScaling). A negative-only DP cell mapped to 0–100 % with a transient negative ADC count will trip the check.
  2. Input_PER wiring error. Disconnected or reversed 4-wire DP cell produces 0 counts or 32767 (overflow), both rejected as "out of range." A broken cable produces ±27648 with sign noise, again rejected.
  3. Setpoint outside scale. If the scale is 0–500 mm and the setpoint is 600 mm, the loop is logically inconsistent and the block stays in Inactive.
  4. ManualEnable / ManualValue conflict. ManualEnable=TRUE with ManualValue outside the output range also blocks enable.

Diagnosis path:

  1. Go online, open the PID_Compact instance, and watch the "Status" tab. State 0 = Inactive, 1 = NotEnabled, 2 = Manual, 3 = Automatic. NotEnabled means the input check failed.
  2. Force Instance.Input with the watch table to a value inside the configured scale. If the block enables, the I/O wiring is the problem.
  3. Inspect the analog module channel: a SM1231 4AI module on the S7-1200 must have Diagnostics disabled for unused channels, otherwise a single open wire on a sibling channel drags the diagnostic interrupt into the input check and freezes the block.
  4. Confirm the DP cell excitation (24 V) at the terminals. A voltage drop on a long cable produces a calibrated but unstable reading; mechanical noise on a poor connector reads as 0 / 27648 jumps, which the block rejects. Replace the shielded twisted pair and re-terminate at the analog module.
Field-proven fix: A field case where PID_Compact stayed gray for a level loop was traced to a chafed 2-conductor cable between the DP cell and the SM1231. Replacing the cable brought the block to Automatic immediately. Mechanical damage, not logic, is the single most common cause on tank farms.

TIA Portal V13 and S7-PLCSIM Compatibility

PID_Compact V2.x cannot be simulated in S7-PLCSIM V13 against an S7-1200 plant. The block is generated, downloaded, and executes, but its internal state never advances past NotEnabled. The root cause is that V2.x requires firmware V4.1 features (specifically the PRD/WRD runtime services for the controller DB) that PLCSIM V13 does not emulate for the 1200. The symptom is identical to a real wiring fault, so a real CPU and a simulated CPU must be diagnosed differently.

Scenario Block version CPU Result Fix
Real CPU, real I/O V2.x S7-1200 FW 4.x Works None
Real CPU, broken sensor V2.x S7-1200 FW 4.x NotEnabled Repair wiring / scale
PLCSIM V13, V2.x block V2.x S7-PLCSIM 1200 Stuck NotEnabled Downgrade block to V1.x
PLCSIM V13, V1.x block V1.x S7-PLCSIM 1200 Works Use V1.x
PLCSIM V14+ V2.x S7-PLCSIM 1200 Works Upgrade PLCSIM

Downgrade procedure:

  1. Open the project in TIA Portal V13 SP1.
  2. Right-click the PID_Compact instance → Change to version → select V1.x from the list.
  3. Re-compile and re-download. The instance DB retains scaled values; I/O names and Config substructure are preserved.
  4. Confirm Instance.Version shows V1.0 in the watch table.

Long-term recommendation: upgrade the engineering environment to TIA Portal V15.1 or later and PLCSIM V15.1, where the V2.x and V3.x blocks simulate cleanly on the 1200 plant. The Siemens support entry 109740509 - PID_Compact V2 in S7-PLCSIM confirms the limitation and lists the supported PLCSIM versions.

Wiring and Signal Conditioning for DP Cells

A differential-pressure level loop uses a DP cell with H (high) leg at the bottom tap and L (low) leg vented. Standard 4-wire excitation is 24 V at 4 mA loop, 4–20 mA return on a single pair. The SM1231 AI4 (6ES7231-4HD32) accepts 4–20 mA on channel 0 when configured for "Current 4-wire" with the 500 Ω sense resistor on the terminal block.

  • Use shielded twisted pair, drain grounded at the cabinet end only.
  • Route the analog cable in a separate conduit, at least 200 mm from VFD output cables and contactor coils.
  • Bridge the unused analog channel with a 100 Ω resistor between + and − to defeat floating input noise on adjacent channels.
  • Scale the input in PID_Compact: Config.InputScaling.HighLimit = 500.0 (mm H₂O at 20 mA), LowLimit = 0.0 (at 4 mA). The scaled Input in % corresponds to (mm / 500) * 100.

Output Behavior: Bumpless Transfer and Slew Rate Limiting

When PID_Compact switches from manual to automatic, the I-term is pre-loaded with the current output, producing a bumpless transition. If the loop is enabled from cold (output = 0%, process value far below setpoint), the integral wind-up is zero and the proportional path can drive the output to 100 % in a single cycle when the gain is high. This is normal closed-loop behavior, not a bug, and it is the most common complaint in tank level applications where the PV starts empty and SP is mid-range.

Three correction strategies, in order of priority:

  1. Pre-position in manual. Hold the loop in Manual, drive the output to a value that produces PV ≈ SP (e.g. open the inlet valve until the level reads near the setpoint), then flip to Automatic. The I-term is initialized to the manual output, and the first automatic step is near zero error.
  2. Conservative tuning. Reduce Gain by 50 %, increase Ti by 2×, and disable Td for the first pass. Tune by Ziegler–Nichols open-loop step or use the built-in Controller tuning panel (PID_Compact V2.x: faceplate → Tuning → "Pretuning" / "Fine tuning"). The tuner injects a step, identifies the process gain and time constant, and writes conservative defaults.
  3. Output rate limiter. Add an SCL block between Instance.Output and the analog output that caps the per-cycle change. A typical 0.5 %/s limit on a 100 % range gives a 200-second ramp, which is well within the time constant of a tank but eliminates the perceived "100 % slam."

SCL rate-limiter pattern:

// Rate-limited output
IF bEnable THEN
  IF rPID_Out > rLastOut + rMaxStep THEN
    rOut := rLastOut + rMaxStep;
  ELSIF rPID_Out < rLastOut - rMaxStep THEN
    rOut := rLastOut - rMaxStep;
  ELSE
    rOut := rPID_Out;
  END_IF;
ELSE
  rOut := rPID_Out;
END_IF;
rLastOut := rOut;

Call this FB in the same OB as PID_Compact (OB35 at 100 ms). With rMaxStep = 0.05 (%/cycle) the output moves 0.5 %/s. Tie the rate-limiter bypass to a permissive so bumpless recovery from a fault does not slam the valve.

PWM Output Configuration

For a solenoid or proportional valve driven from a digital output, PID_Compact exposes Output_PWM (BOOL) and Output_PWM_Period (TIME). Set the period to 1.0 s for valve duty control, 0.1 s for heater SSR. The duty cycle is the PID output mapped 0–100 %; the BOOL is high for the on-fraction of the period and low for the off-fraction.

  • Minimum period 10 ms (CPU cycle-bound) and 100 ms (recommended for valve life).
  • Connect Output_PWM to a digital output wired to the relay/SSR. Add a flyback diode across DC loads.
  • When OutputMode is PWM, do NOT connect Output_PER to the analog module; the two paths are mutually exclusive in the Config substructure.
Anti-windup on PWM: The block internally clamps the integral term when Output_PWM saturates at 0 % or 100 % for the entire period, so the loop is naturally windup-protected. Do not add an external anti-windup on the PWM path; it conflicts with the internal clamp.

Manual / Automatic Handover and Bumpless Transfer

The block's ManualEnable input and ManualValue (REAL, 0–100 %) drive manual mode. On the rising edge of ManualEnable the block freezes the integral term and holds the output at ManualValue. On the falling edge the block pre-loads the I-term to the current output and resumes automatic. To verify bumpless behavior:

  1. Force the loop into manual: set ManualEnable=TRUE, ManualValue=40.0, observe the output settle at 40 %.
  2. Watch Instance.IntegralSum in the watch table; it tracks the held output.
  3. Drop ManualEnable to FALSE. The output should not jump; the next PID computation begins with the I-term at 40 %.

If a step appears on transition, the block was re-initialized by a CPU restart, a power cycle, or a re-download of the instance DB. Re-trigger bumpless initialization by writing to Instance.Restart = TRUE for one cycle, or by entering manual, holding for at least one OB35 cycle, and releasing.

Adaptive Control with SCL

PID_Compact is a fixed-gain PI/PID controller. It does not include gain scheduling, model-reference adaptive control, or auto-tuning beyond the built-in pretuning/fine tuning passes. Engineers who need adaptive gain (e.g. a tank with a 5× change in cross-section between the cone and the cylinder, or a nonlinear valve curve) must implement the adaptation externally and overwrite Instance.Retain.CtrlParams.Gain / Ti / Td on a slow update.

A practical gain-scheduling pattern:

FUNCTION_BLOCK FB_AdaptiveGain
VAR_INPUT
  rPV : REAL;        // process value in %
  rSetpoint : REAL;
  rGainLow : REAL := 0.4;
  rGainHigh : REAL := 1.2;
  rPV_Threshold : REAL := 60.0; // switch at 60 % level
  bUpdate : BOOL;
END_VAR
VAR_OUTPUT
  rGain : REAL;
  rTi : TIME;
END_VAR
VAR
  rLastPV : REAL;
  rRampGain : REAL;
END_VAR
BEGIN
  // Schedule gain on PV region
  IF rPV < rPV_Threshold THEN
    rGain := rGainLow;
    rTi := T#20S;
  ELSE
    rGain := rGainHigh;
    rTi := T#8S;
  END_IF;
  // Slew the gain update to avoid step on the loop
  rRampGain := rLastPV * 0.9 + rPV * 0.1;
  rLastPV := rRampGain;
  // Push into PID_Compact retain
  IF bUpdate THEN
    Instance.Retain.CtrlParams.Gain := rGain;
    Instance.Retain.CtrlParams.Ti := rTi;
  END_IF;
END_FUNCTION_BLOCK

Calling pattern: invoke FB_AdaptiveGain in OB35 at 100 ms with bUpdate gated by a 5-second timer to avoid writing the retain structure on every cycle. For more advanced schemes (MRAC, self-tuning regulators, fuzzy PID) implement a discrete estimator in SCL and overwrite the controller parameters only on convergence; never write to CtrlParams mid-cycle from OB1.

For time-proportional output (e.g. heater on/off with a window comparator and duty-cycle timer), the recommended path is to keep PID_Compact in PWM mode and let the built-in PWM generator produce the duty cycle. Custom time-proportional logic outside the block is rarely necessary on S7-1200.

Tuning the PID

Sequential procedure for a level loop driven by a 4–20 mA proportional valve:

  1. Set Gain = 0.3, Ti = T#30s, Td = T#0s. Hold the loop in manual.
  2. Drive ManualValue to 30 %, record PV for 60 s, then to 60 %, record for 60 s. Compute open-loop gain K = ΔPV / ΔMV (in %/%).
  3. Compute dead time L and time constant T from the step response.
  4. Apply Ziegler–Nichols open-loop: Kp = 1.2 * T / (K * L), Ti = 2 * L, Td = 0.5 * L.
  5. Or run the built-in pretuning (faceplate → Tuning → Pretuning) with the loop in manual and the process at a stable point.
  6. Switch to automatic with the calculated or tuned values. Watch for overshoot; if overshoot exceeds 10 %, halve Kp and double Ti.

For an integrating process (tank with pump-out), use Ziegler–Nichols closed-loop: increase Kp until sustained oscillation, record ultimate gain Ku and period Pu, then Kp = 0.45 * Ku, Ti = Pu / 1.2, Td = Pu / 8.

Verification

After each change, run the following check sequence:

  1. Watch table: confirm Instance.State = 3 (Automatic) and Instance.StateString = "Automatic".
  2. Input check: Instance.Input reads 0–100 %, matches the SCADA display in engineering units.
  3. Output check: Instance.Output follows the PID calculation. If OutputMode is analog, Instance.Output_PER reads 0–27648 scaled. If OutputMode is PWM, Instance.Output_PWM toggles at the configured period.
  4. Step test: bump the setpoint by 5 % and observe rise time, overshoot, settling time. For a 500 mm tank level, target rise time 60–120 s, overshoot less than 5 %.
  5. Bumpless test: toggle ManualEnable and confirm the output does not step more than 0.5 % at the transition.
  6. Fault test: disconnect the DP cell. The block should enter NotEnabled (State=1) and not drive the actuator. Reconnect and confirm recovery within two cycles.

Troubleshooting Matrix

Symptom Likely Root Cause Action
Faceplate stays gray, State=1 Input out of range Inspect wiring, scale limits, ADC count
Faceplate stays gray, simulation only PID_Compact V2.x on PLCSIM V13 Downgrade to V1.x or upgrade PLCSIM
Output jumps to 100 % on enable Large initial error, aggressive Kp Pre-position in manual, reduce Kp, slew limit
Output oscillates Kp too high, Ti too low Halve Kp, double Ti, run pretuning
Output drifts after setpoint change Ti = 0 (no integral action) Set Ti ≥ 0.1 * T_process
Output chatters on PWM Period too short for valve Increase Output_PWM_Period to ≥ 1 s
Manual→Auto steps Block re-initialized Set Restart, hold manual 1 cycle, release
Adaptive gain is unstable Retain written every cycle Gate update to ≥ 5 s, slew gain change
PLCSIM 1200 OK, real CPU 1200 stuck Sensor wiring / ADC overflow Check 24 V, sense resistor, channel diagnostics

Why does PID_Compact stay gray (NotEnabled) in TIA Portal V13 even though the input is in range?

If you are simulating with S7-PLCSIM V13 against an S7-1200 plant, PID_Compact V2.x cannot be simulated and stays in NotEnabled regardless of the input value. Downgrade the block to V1.x in TIA Portal (right-click → Change to version), or upgrade to PLCSIM V14 or later where V2.x is supported. On a real CPU, the most common cause is a wiring or scaling fault producing 0 / 27648 / negative counts; replace the cable and verify the analog channel configuration.

How do I stop the PID output from slamming to 100 % when the loop is enabled?

Three-step correction: (1) pre-position the loop in manual to bring the process value near the setpoint, then release to automatic; (2) reduce the gain by 50 % and double the integral time for the first tuning pass; (3) add a rate limiter on the PID output that caps the per-cycle change to 0.5 %/s. PID_Compact supports bumpless transfer internally, so a step on transition indicates the block was re-initialized.

Can I implement adaptive control or time-proportional control with PID_Compact?

Time-proportional (PWM) output is built-in via Output_PWM; set the period to 1.0 s and connect the BOOL to a digital output. PID_Compact does not include gain scheduling or model-reference adaptation, so adaptive control must be implemented externally in SCL: read the PV, compute the scheduled gain and Ti, and overwrite Instance.Retain.CtrlParams.Gain / Ti on a slow (≥ 5 s) update so the loop is not excited by a step in parameters.

Which PID_Compact version should I use for an S7-1200 with TIA Portal V13?

Use PID_Compact V1.x if you need to simulate in S7-PLCSIM V13. Use V2.x (the default) if you are running on a real S7-1200 CPU with firmware V4.1 or later, since V2.x exposes the richer configuration interface and supports the faceplate tuning panel. For long-term projects, upgrade to TIA Portal V15.1 or later, where V2.x simulates cleanly and V3.x is available for new features.

How do I verify that PID_Compact is in Automatic mode after enabling?

Go online, open the PID_Compact instance in the watch table, and read Instance.State (numeric) and Instance.StateString (text). Automatic corresponds to State = 3 with StateString = "Automatic". If the block reads NotEnabled (1) or Manual (2), inspect the input range, setpoint, and ManualEnable inputs to identify the blocking condition before bumping the setpoint.

Back to blog