The Single-Digital-Output PID Problem
A temperature or level loop driven by a single on/off actuator cannot accept a continuous analog command. The PID controller computes a value in the percent range, but the field hardware exposes only one boolean coil that energizes a pneumatic or motorized valve. Driving a 0-100% output into a 1-bit coil collapses the signal to either fully ON or fully OFF, defeating the proportional action that the controller is trying to deliver.
This is a common configuration when:
- A single-acting pneumatic valve is the only final control element available on the skid
- The I/O card has been pre-allocated and only one DO is reserved for the loop
- The cabinet was built with a relay (RLY) output card instead of an analog output (AO) module
- Spare-part or budget constraints prevent adding a positioning actuator
The reference continuous PID block in the modular PID library (Siemens FB59 CONT_C) outputs a floating-point value 0.0-100.0% that must be wired to an analog output word such as PQW 272. It does not include a pulse-width modulator; the duty-cycle conversion is the integrator's responsibility.
Why FB59 Alone Is Not Sufficient for a Boolean Output
FB59 is a continuous-action PID controller with separate inputs for setpoint (SP_INT, REAL), process value (PV_IN, REAL with PV_FAC/PV_OFF scaling), disturbance (DISV, REAL), manual/auto switching, and output range limits. The output LMN is a floating-point value 0-100% representing the requested valve position. See the PID Control V5 Function Block Manual for the full block interface.
Wiring LMN directly to a digital output (Q bit) gives only two states:
- LMN > 0 -> DO ON (valve energized)
- LMN = 0 -> DO OFF (valve de-energized)
A PID block producing 47% is indistinguishable from 88% - both latch the DO closed. The integral term keeps winding because the loop cannot bleed energy through the actuator. The loop either oscillates as the actuator toggles at LMN ~ 0, or saturates fully if the comparator is one-sided.
LMN. Two SFB4 (IEC on-delay timer) blocks are sufficient.PWM-Based Architecture for a Single-DO Actuator
The duty cycle of a slow PWM represents the average valve position over one cycle. With a 10-second cycle:
- 100% PID output -> 10 s ON, 0 s OFF (fully open / active)
- 50% PID output -> 5 s ON, 5 s OFF
- 0% PID output -> 0 s ON, 10 s OFF (fully closed)
The actuator integrates this duty cycle because the process (heat transfer, level rise) is much slower than the PWM period. Typical cycle times for thermal loops are 5-30 s; for level loops 5-15 s. The cycle must be longer than the actuator response time and short enough to avoid visible process ripple.
For a heating valve that opens when energized (single-acting, fail-closed), the same duty cycle controls average heat input. For a fail-open valve (cooling, de-energize to open) the output must be inverted. The S7 IEC timer blocks are documented in the STEP 7 Standard Library Reference.
Scaling PID Output 0-100% into a Time Setpoint
The PID output range LMN is 0.0-100.0%. The PWM logic needs an integer milliseconds value. Convert using:
Fill_Timer_SP_ms = (LMN / 100.0) * Cycle_Time_ms
Implementation notes:
-
Cycle_Timemust be aDINTin milliseconds; the SiemensIEC_TIMERtype stores time as DINT ms -
LMNmust be cast fromREALtoDINTbefore multiplication - Always clamp the result:
0 <= Fill_Timer_SP <= Cycle_Time
Worked example - if LMN = 73.4 and Cycle_Time = 10 000 ms:
Fill_Timer_SP = 73.4 / 100 * 10 000 = 7 340 ms
The remaining 2 660 ms of the cycle the output is OFF. The 4-20 mA analog input from the temperature transmitter must be normalized to engineering units before being passed to FB59 PV_IN; use the PV_FAC/PV_OFF linearization pair or scale the raw input in a preceding block.
SFB4 TON Implementation - Block Diagram
Two SFB4 (On-Delay Timer, IEC 61131-3) blocks implement the PWM:
- Clock_Timer - generates the PWM period tick (PT = Cycle_Time)
- Fill_Timer - generates the ON portion (PT = Fill_Timer_SP)
The Clock_Timer.Q output triggers re-triggering of Fill_Timer at the start of each cycle. The Fill_Timer.Q output is the actual valve command. The Clock_Timer is wired with inverted Q on its own IN input, producing a self-clocked free-running oscillator at exactly the cycle period.
Step-by-Step Structured Text Implementation
// ============================================================
// NETWORK 1 - PID block call (FB59 or FB41 CONT_C)
// ============================================================
CALL "PID_BLOCK" , "PID_DB"
SP_INT := Setpoint_DEG_C // REAL setpoint
PV_IN := Scaled_PV_DEG_C // REAL from AI scaling
MAN := Manual_Mode // BOOL
MAN_ON := Manual_Enable
LMN := LMN_REAL // REAL 0.0 .. 100.0
LMN_HLM := 100.0
LMN_LLM := 0.0
// ... remaining FB59 parameters per library manual
// ============================================================
// NETWORK 2 - Scale LMN to milliseconds, clamp to cycle range
// ============================================================
IF LMN_REAL < 0.0 THEN
Fill_SP_DINT := 0;
ELSIF LMN_REAL > 100.0 THEN
Fill_SP_DINT := Cycle_Time_DINT;
ELSE
Fill_SP_DINT := REAL_TO_DINT(LMN_REAL / 100.0 * INT_TO_REAL(Cycle_Time_DINT));
END_IF;
// ============================================================
// NETWORK 3 - Fill_Timer (drives the valve coil)
// ============================================================
Fill_Timer(IN := Clock_Timer.Q, PT := Fill_SP_DINT);
Valve_Coil := Fill_Timer.Q
AND NOT ESTOP_Active
AND Interlock_OK
AND Sensor_Healthy;
// ============================================================
// NETWORK 4 - Clock_Timer (free-running oscillator)
// ============================================================
Clock_Timer(IN := NOT Clock_Timer.Q, PT := Cycle_Time_DINT);
The Clock_Timer uses inverted Q as its own start input, so it re-arms immediately on expiration. This produces a continuous clock with period Cycle_Time ms. The Fill_Timer IN is gated by Clock_Timer.Q, so it only starts at the beginning of each cycle and times out exactly Fill_SP ms later. Fill_Timer.Q is the actual valve energize command, AND'ed with safety and interlock flags.
Ladder Logic Variant
Clock branch (self-oscillating):
Clock_Timer.Q
-----| |--+-----( S ) // S latch not used; direct IN gating
|
+----| IEC_TIMER_TON, IN=Clock_Timer.Q, PT=Cycle_Time
When Clock_Timer.Q goes high, IN is high and the timer starts. When it times out, Q resets to 0. The next scan IN goes high again, restarting the timer - creating a free-running clock at the desired period.
Fill branch (valve output rung):
Clock_Timer.Q Fill_SP PT
-----| |--------| TON Fill_Timer |
Q----| |-----
ESTOP_Active---|\|---( Valve_Coil )
Interlock_OK-------|\|---
Sensor_Healthy---------------|\|---
All four conditions - timer active, no ESTOP, interlock released, sensor healthy - must be true for the valve to energize. Hardware ESTOP must cut 24 V to the output card via a safety relay; never rely on software alone.
Cycle Time Selection Matrix
| Process type | Recommended cycle | Reason |
|---|---|---|
| Heating loop (slow thermal mass) | 10-30 s | Process time constant much longer than PWM period |
| Level loop (faster dynamics) | 5-15 s | Need quick response to setpoint changes |
| Pressure loop | 2-10 s | Faster dynamics, smaller volumes |
| Cooling/heating with hysteresis | 30-60 s | Allow process to settle between changes |
| Glacial tank heat tracing | 60-120 s | Very slow thermal response, long actuator life |
Shorter cycle times reduce output ripple but increase actuator wear (cycle count per hour). Pneumatic valves are typically rated for 100-200 cycles per minute; a 10 s cycle is well below that. For motorized ball or globe valves, check the duty rating - many are limited to a few hundred cycles per hour. Use HMI to display the cycle count.
Safety Interlocks and Fault Handling
The valve must never be energized under any of the following conditions:
- Emergency stop active (hardware AND software)
- High-temperature or low-level interlock
- Sensor fault (broken 4-20 mA loop, value out of range)
- Manual mode (operator must explicitly enable)
- Cascade master faulted
The hardware ESTOP must cut the 24 V supply to the output card via a safety relay, not just clear a software flag. Software interlocks protect against logic errors; hardware interlocks protect against PLC failure. Refer to the SIMATIC S7 Safety Integrated Manual for category requirements.
Recommended output rung pattern:
Valve_Coil := Fill_Timer.Q
AND NOT ESTOP_Active
AND Interlock_OK
AND Sensor_Healthy
AND Cascade_Active;
Wire the interlock as a series contact in the output rung, never as a parallel override. A parallel contact (OR) cannot disable the output when the timer is ON - it can only enable it.
HMI Operator Interface and Tuning Aids
Expose the following to the operator faceplate:
- Setpoint (REAL, degC or %)
- Process value (REAL, degC or %)
- LMN percent (0-100%)
- Fill_Timer setpoint and elapsed (for debugging)
- Cycle_Time (operator-adjustable, default 10 s)
- Manual mode toggle and manual LMN entry
- Auto-tune button (if FB59 supports it or external autotuner block is used)
- Valve cycle counter (resettable)
For FB59, the autotune function TUN_ON plus the controller-tuning tool from the PID library can find initial Kp, Tn, Td values. See the FB41/FB59 Function Block Reference. After autotune, fine-tune by stepping setpoint and watching the response: increase Kp until a small overshoot appears, then back off 20%, set Tn = 0.4 * oscillation period.
Parallel Tank Level Control - Secondary Problem
A second scenario arises with two recycle tanks feeding a common storage section, each with its own inlet valve (CV-1A, CV-1B) and a shared drain pair (CV-2A, CV-2B) connected in parallel downstream. When the two drain valves share a manifold, the control loops interact: closing one valve changes the hydraulic resistance of the parallel network and affects the other loop.
Observed symptoms:
- One tank (RT-1) reaches setpoint fast, the other (RT-2) lags
- Closing CV-2A raises RT-1 above setpoint while RT-2 remains below
- Manually closing CV-2B disturbs the RT-1 level
Root causes:
- Different valve characteristics (Cv ratings, mechanical stiffness) - one valve opens further at the same command
- Different tank geometries or inlet/outlet resistances
- Cross-coupling through the parallel drain manifold
- Unaccounted leakage in one tank (unmetered outflow)
- Independent loops with no decoupling, so PID-A and PID-B fight each other
Recommended solutions, in order of complexity:
- Add a flow transmitter on each drain line and close the loop on flow, not just valve position
- Use feed-forward from the measured flow into the PID setpoint or output bias term
- Replace on/off valves with control valves sized for the actual duty
- Implement split-range: each PID owns one valve, but a coordination block limits total flow to the storage section
- Add a level cascade: outer level loop sets the inner flow loop setpoint
- For pure level control with significant interaction, switch to model-predictive or override control
Verification and Commissioning Procedure
- Cold start: set PID to manual, force LMN = 0, verify Fill_Timer.Q stays OFF, valve de-energized
- Step LMN to 50% in manual; verify the coil toggles at the expected ratio (5 s ON / 5 s OFF with 10 s cycle)
- Verify cycle period: time Clock_Timer.Q high and low - should be 50% duty each by construction
- Verify scaling: LMN = 25% with 10 s cycle should give 2.5 s ON / 7.5 s OFF; LMN = 90% should give 9 s ON / 1 s OFF
- Switch PID to auto, step setpoint by 5-10%, observe process response - no oscillation, settles in 3-5 time constants
- Tune PID: start with conservative gains (small Kp, long Tn, Td = 0), increase Kp until small oscillation, back off 20%, set Tn = 0.4 * oscillation period
- Verify ESTOP response: activating ESTOP must drop the valve within one PLC scan, and hardware 24 V must be cut by the safety relay
- Verify interlock release: clearing the interlock should not re-energize the valve until the operator explicitly enables (latched permissive)
- Verify sensor fault: unplug the 4-20 mA input; the valve must drop within one scan, not stay at last good output
- Long-term soak: run the loop for 24 hours under normal load, log valve cycles, confirm cycle count is within actuator rating
Use a digital input on the valve position switch (if available) to confirm the valve actually opens. A command that does not produce physical motion indicates a wiring fault, missing pneumatic supply, or a stuck actuator. Cross-check the coil output with a clamp-on current probe or a voltmeter across the coil.
Edge Cases and Field-Proven Caveats
- Scan time vs. timer resolution: if the OB1 cycle is 50 ms and Cycle_Time is 1000 ms, the timer drifts by 50 ms per cycle - tolerable. If the scan is 100 ms and Cycle_Time is 1000 ms, consider moving the timers to a cyclic OB (e.g. OB35 at 100 ms) for accuracy
- Wiring polarity: a single-acting pneumatic valve is typically fail-closed; verify the spring direction. Some valves are fail-open (cooling) - invert the output rung
- Integer overflow: avoid DINT math on LMN before scaling; cast LMN/100 to REAL first, multiply by Cycle_Time as REAL, then cast to DINT
- Bumpless transfer: when switching manual -> auto, initialize PID_ITVAL to current LMN to prevent a step
- Output saturation: clamp LMN_HLM to the maximum safe duty cycle (e.g. 90%) to ensure the valve fully closes at least 10% of every cycle, preventing continuous full-on if the controller saturates
FAQ
Why can't I just use FB59 with a digital output?
FB59 outputs a continuous 0-100% value intended for an analog output. A digital output has only two states, so 47% and 88% are indistinguishable - both look like ON. The PID integral term will wind and the loop will oscillate. Convert the percent to a time-proportioned signal using a PWM generator driven by FB59 LMN and two SFB4 timers.
What cycle time should I choose for a heating loop?
For thermal processes with time constants in minutes, use a 10-30 second PWM cycle. The cycle must be at least 10x longer than the actuator response time but short enough to avoid visible temperature ripple. Monitor the HMI cycle counter to stay below the valve manufacturer's duty rating.
Can I use SFB3 (TP) instead of SFB4 (TON)?
Yes - SFB3 generates a fixed-width pulse independent of the cycle clock. SFB4 (TON) is more flexible because the pulse width follows the PID output directly. For PID duty-cycle conversion SFB4 is the more natural choice; SFB3 requires an additional edge detector on the clock to start the pulse.
What happens if the 4-20 mA analog input fails?
The PID sees a process value that may drive LMN to 100% (if the broken input reads as 0 mA, below setpoint). The valve will stay open. Add a sensor-health check on the AI channel value/status, freeze the PID in last-good state on fault, and drop the interlock to de-energize the valve. The Siemens analog input modules expose a quality byte on the input word that you can evaluate.
How do I tune the PID for a single-DO PWM loop?
Start in manual, step LMN to 50%, watch the process response. Note the dead time and time constant. Then switch to auto with conservative gains: Kp ~= 0.5 * (DeltaProcess / DeltaLMN), Tn = 0.5 * process time constant, Td = 0. Use Ziegler-Nichols or Lambda tuning. If temperature oscillates with a period near the PWM cycle, shorten the cycle or add a small hysteresis to the Fill_Timer output to prevent coil chattering near the LMN = 0 crossover.
How do I keep the valve from chattering at very low PID output?
Add a deadband: if LMN < 2% (configurable), force Fill_Timer IN to 0; if LMN > 98%, force it permanently ON. This prevents very short pulses (under 200 ms) that do not give the valve time to open and close fully. The deadband introduces a small steady-state error proportional to the threshold percent - acceptable for thermal processes with integral action.