1. Overview
FB41 (CONT_C) is the continuous PID controller function block shipped with the Siemens Standard PID Control toolbox for the S7-300 and S7-400 families. It integrates proportional, integral, and derivative action into a single block with bumpless transfer, anti-windup, dead-band, output limiting, and a derivative-lag (DTL) filter. Despite its age, FB41 is still widely used in S7-300 (CPU 312–319F), S7-400, and the WinAC slot PLCs, and it remains the canonical teaching example for sampled PID loops on Siemens platforms.
The single most common field defect with FB41 is a mismatch between the CYCLE input (sample time) and the actual interval at which the block is called by the CPU. When those two values disagree, the controller still runs, but its integral and derivative terms are computed against the wrong dt: GAIN no longer behaves like a proportional band, TI stretches or shrinks the integral action, and TD either spikes or fails to react. Closed-loop behaviour looks "almost right" at low gain, then becomes unstable the moment an engineer starts tuning.
This reference consolidates the correct calling methodology, the mathematics of the CYCLE parameter, the OB1-versus-OB3x trade-off, the loop-scheduler pattern for multi-PID projects, and the 0.1× dominant-time-constant rule of thumb for selecting the sample time. It also covers dead-time dominated processes and the Smith predictor pattern referenced in Siemens application notes.
2. Prerequisites
- STEP 7 V5.5 or STEP 7 Professional in TIA Portal (V13 or later) with the S7-300/S7-400 CPU family installed.
- Standard PID Control toolbox (FB41, FB42, FB43, FB58, FB59) registered in the project. In TIA Portal this is the optional package "PID Control (S7-300/400)".
- CPU 314 or higher recommended for projects with more than three PID loops; CPU 312C/313C integrated I/O is acceptable for single loops.
- Cycle time of the process available as an estimate (dominant time constant τ_p, dead time θ_p) from step-test or plant documentation.
- Measured value scaled to engineering units (REAL, e.g. 0.0 – 100.0 °C) and clipped to a sensible range to prevent PV spikes propagating into I-action.
3. FB41 CONT_C Architecture and the CYCLE Parameter
FB41 implements a parallel-form PID with anti-windup, manual-to-auto bumpless transfer, and a first-order derivative lag. The I/O structure relevant to the sample-time discussion is shown below.
| Parameter | Type | Meaning | Notes for CYCLE |
|---|---|---|---|
| CYCLE | REAL (s) | Sampling interval of the block | Must equal the OB period, otherwise the block internally re-derives dt and corrupts tuning |
| SP_INT | REAL | Setpoint in engineering units | Independent of CYCLE |
| PV_IN | REAL | Process variable in engineering units | Independent of CYCLE |
| GAIN | REAL | Proportional gain | Multiplies the error after CYCLE-based normalisation |
| TI | REAL (s) | Integral action time | Effective integration is dt/TI; mismatch with CYCLE scales the integrator |
| TD | REAL (s) | Derivative action time | Derivative uses dt; a smaller real dt with a nominal CYCLE produces a stronger D |
| TM_LAG | REAL (s) | Derivative lag time constant | Acts on the D path independent of CYCLE |
| DEADB_W | REAL | Dead-band width | Independent of CYCLE |
| LMN_HLM / LMN_LLM | REAL | Output limits | Anti-windup clamps I-term to these limits |
| I_ITL | BOOL | Initialise integrator | Use to preload I-term on first run |
| IT_ON / DISV | BOOL / REAL | Enable I-term / Disturbance variable | Independent of CYCLE |
The integrator inside FB41 discretises the integral as a rectangular sum with step size equal to CYCLE:
In+1 = In + (GAIN · en / TI) · CYCLE
The derivative term uses a backward difference across one CYCLE period. If the real call interval drifts to k·CYCLE, the integrator accumulates k times faster and the derivative produces k times the expected response. The visible symptom is a controller that is "too aggressive" on the I-side and "too noisy" on the D-side — a textbook signature of a CYCLE mismatch.
4. Why OB1 is the Wrong Default for FB41
OB1 on an S7-300/400 executes once per scan. The scan time of OB1 is the sum of every other OB1 activity plus any higher-priority OB that pre-empts it. With HMI communication, distributed I/O updates, and other OB1 logic, the scan time is rarely constant: 80 ms one cycle, 140 ms the next. Calling FB41 directly from OB1 produces a non-uniform sample time, which violates the assumption baked into CYCLE.
Two failure modes appear in real plants:
- Slow scan creep: Scan time grows from 100 ms to 200 ms as more code is added. The controller silently becomes two times more aggressive on the I-term, which looks like a tuning problem until the engineer realises the scan-time monitor is the smoking gun.
- Long-tail scans: A single 800 ms scan (caused by a flash write or a PROFIBUS reconfiguration) makes the controller output a step of 8·(normal step) on the next call. The output limiter saves the actuator but the I-term winds up to the rail and takes minutes to bleed off.
Siemens documents this in the Standard PID Control manual, which states that FB41 must be called at a fixed time interval, and that the time interval must be entered in the CYCLE parameter.
5. Step-by-Step: Calling FB41 in a Cyclic Interrupt OB (OB3x)
The recommended pattern is to place FB41 inside a cyclic interrupt OB. S7-300 and S7-400 CPUs support OB30 through OB38. Their default and allowed periods are:
| OB | Default period | Min | Max | Resolution |
|---|---|---|---|---|
| OB30 | 5 s | 1 s | 60 s | 1 ms |
| OB31 | 2 s | 500 ms | 60 s | 1 ms |
| OB32 | 1 s | 250 ms | 60 s | 1 ms |
| OB33 | 500 ms | 100 ms | 60 s | 1 ms |
| OB34 | 200 ms | 50 ms | 60 s | 1 ms |
| OB35 | 100 ms | 10 ms | 60 s | 1 ms |
| OB36 | 50 ms | 5 ms | 60 s | 1 ms |
| OB37 | 20 ms | 2 ms | 60 s | 1 ms |
| OB38 | 10 ms | 1 ms | 60 s | 1 ms |
Procedure:
- Open the S7 project in STEP 7 / TIA Portal and navigate to the project tree.
- Add a new FB instance for FB41 by inserting a call from the Standard PID Control library. Accept the default instance DB (e.g. DB41) and assign a symbol, e.g.
PID_TEMP_FURNACE. - Right-click the Blocks folder, choose "Insert New Object → Organization Block", and select a cyclic interrupt OB, for example OB35 (100 ms). Give it a symbolic name, e.g.
OB35_PID_100MS. - Inside OB35, call the FB41 instance. Wire
SP_INT,PV_IN,GAIN,TI,TD, and the outputLMN(analogue output) orLMN_PER(peripheral output for direct PA writes). - Wire
CYCLEto a real constant that matches the OB period. If OB35 is set to 100 ms, hard-codeCYCLE := T#100msin seconds, i.e. 0.1 s. Use a global constantOB35_PERIOD_S := 0.1to keep this in one place. - Configure the OB35 period in HW Config → CPU properties → "Cyclic Interrupts" tab. Enter 100 ms and a phase offset of 0 ms.
- Download and test. The PID self-test should now show a uniform call interval in the trend.
6. Step-by-Step: Calling FB41 in OB1 with a Software Timer
For projects on a CPU that has only one cyclic interrupt (S7-300 with OB35 only) and several PID loops of widely different speed, the loop-scheduler pattern inside OB35 is the field-proven solution. Calling FB41 from OB1 with a self-managed timer is also possible but requires care.
Procedure for the OB1 self-timer approach:
- For each PID loop create two IEC timers or a counter pair: one for the desired CYCLE (e.g. 5 s) and a flag
PID_x_DUE. - In OB1, on every scan, decrement the timer. When it expires, set the
PID_x_DUEflag and reload the timer. - Immediately after, call FB41 inside an IF/THEN guard:
IF PID1_DUE THEN
PID1_DUE := FALSE;
PID1(SP_INT := 80.0,
PV_IN := PV_FURNACE,
GAIN := 1.2,
TI := 120.0,
TD := 0.0,
CYCLE := 5.0, // seconds, matches timer
LMN := MV_FURNACE);
END_IF;
This approach is functionally allowed because the CYCLE constant matches the timer period exactly, so FB41 sees a uniform dt. The disadvantage is that the next call can never be earlier than the next OB1 scan; if OB1 itself takes 250 ms, the effective call is 250 ms + residual timer, not exactly 5.0 s. For a slow process (5 s, 10 s) this is negligible. For fast PIDs it is unacceptable.
The Siemens-recommended approach is to keep all PIDs in OB35 and use a loop scheduler to release them at different multiples of the OB35 period. See Section 8.
7. Cycle Time Selection and the 0.1× Time Constant Rule
The sample time CYCLE is selected based on the process dynamics, not on a generic "fast is better" instinct. The widely used engineering rule of thumb is:
CYCLE ≈ 0.1 · τp
where τp is the dominant (slowest significant) time constant of the process. This rule is stated explicitly in the Siemens Standard PID Control documentation. It produces a controller that is responsive to disturbances without aliasing the dominant mode.
| Process | Typical τp | Suggested CYCLE | OB |
|---|---|---|---|
| Pressure (hydraulic) | 0.5 – 2 s | 50 – 200 ms | OB34 / OB35 |
| Flow (water / air) | 1 – 5 s | 100 – 500 ms | OB35 / OB33 |
| Level (tank) | 5 – 60 s | 500 ms – 6 s | OB33 / OB32 / OB31 |
| Temperature (small furnace) | 30 – 300 s | 3 – 30 s | OB30 + scheduler |
| Temperature (large kiln) | 300 – 3600 s | 30 – 360 s | OB30 + scheduler |
| Position / pH | 5 – 60 s | 500 ms – 6 s | OB33 / OB32 |
If τp is unknown, perform an open-loop step test: drive the output to a small step (5 %), record PV, and fit a first-order-plus-dead-time (FOPDT) model. The plant gain K, time constant τp, and dead time θp come out of the fit and feed both CYCLE and the initial PI/PID tuning (Ziegler-Nichols, Cohen-Coon, or Lambda tuning).
For Lambda tuning the recommended CYCLE is usually a fraction (0.05 to 0.1) of τp; for very slow processes the CYCLE is allowed to be in the multi-second range and the controller will still track a setpoint change with a smooth, low-noise output.
8. Multi-Loop Scheduling: The Loop Scheduler Pattern
When the project contains PIDs with very different cycle times, a single OB35 at 100 ms is wasteful for slow loops and insufficient for fast ones. The loop scheduler is a small cyclic dispatcher inside a fast OB3x that calls each FB41 only when its own period has elapsed.
Pattern (SCL or STL inside OB35):
// Master cycle in OB35 = 100 ms
// Slow loop scheduled every 50 master cycles = 5 s
// Fast loop scheduled every master cycle = 100 ms
// Medium loop every 10 master cycles = 1 s
IF SCHED_FAST THEN
PID_FAST(CYCLE := 0.1, ...);
END_IF;
IF SCHED_MED THEN
PID_MED(CYCLE := 1.0, ...);
END_IF;
IF SCHED_SLOW THEN
PID_SLOW(CYCLE := 5.0, ...);
END_IF;
The scheduler is typically a wraparound counter plus three preloads. Each tick of OB35 increments the counter; when the counter equals the preload, the corresponding SCHED_x flag is set and the counter is reset to 0. This pattern is documented in Siemens application notes and is also implemented in the optional "Modular PID Controller" and "Standard PID Controller" packages as the Loop Scheduler element. For an S7-300 with a single OB35 the scheduler avoids the need for OB30 / OB32 / OB33 and gives every PID its own CYCLE.
For an S7-400 with all eight OB3x available, an alternative is to place each PID in a different OB3x and set the OB period to the required CYCLE. Phase offsets prevent OB3x from queuing at startup. The trade-off is OB count versus dispatcher overhead; for fewer than four PIDs the dispatcher is usually lighter, for more than four the multiple-OB approach is more transparent in the online view.
9. Dead-Time Dominated Processes and the Smith Predictor
FB41 is a single-loop PID and assumes a process whose dynamics are captured by the sampled integrator. Processes with significant dead time (transport delay, chromatograph, long pipe, batch reactor with temperature propagation) do not behave as expected: a CYCLE change that reduces dt does not reduce the observed dead time, so the I-action has to be detuned heavily to remain stable.
The Smith predictor is the standard Siemens-recommended remedy. The structure uses an internal model of the process (gain K, time constant τ, dead time θ) to predict what the PV would be without the delay, and feeds the difference between the predicted and actual PV into the PID. The visible effect is that the PID "sees" a process with no dead time, allowing more aggressive tuning than a classical PID on the real plant.
A pragmatic alternative when Smith is too complex is to add a first-order lag to the PV (PT1) and lengthen CYCLE, which sacrifices dynamic response for stability. The choice is project-dependent and should be documented in the control narrative.
10. Verification and Diagnostics
After commissioning, verify the loop is actually running at the configured CYCLE:
- Open the FB41 instance DB online in STEP 7 / TIA Portal and trend
CYCLEagainst an internal time stamp. Confirm the effective interval is constant. - Use the CPU's online diagnostics (Module Information → Scan Times) to read OB35 worst-case execution time. If the worst-case approaches the period, increase the OB period or split the load into two OBs.
- Apply a small setpoint step (5 %) and observe the response. The characteristic rise time should be 2 to 4 times the configured CYCLE for a properly tuned temperature loop, and 0.5 to 1 times for a fast flow or pressure loop.
- Check
I_ITLon startup. Preload the integrator with the expected steady-state MV (computed from the valve curve or known duty cycle) to avoid the first few minutes of windup on cold start.
11. Common Errors and Field Notes
| Symptom | Likely root cause | Fix |
|---|---|---|
| Output oscillates with period of several seconds at low gain | CYCLE does not match OB period, I-term runs at wrong rate | Verify CYCLE constant vs. HW Config period; trend to confirm |
| MV jumps to LMN_HLM on the first disturbance | Anti-windup not primed, or I-term saturated from a long scan gap | Preload integrator with I_ITL on first run; check LMN_HLM |
| Controller sluggish on slow process | CYCLE is much smaller than τp, integral action builds on noise | Increase CYCLE to 0.1·τp or use scheduler |
| MV noisy on D-term | Derivative action picks up sensor noise amplified by short CYCLE | Increase TM_LAG; check PV filtering; increase CYCLE |
| Loop runs fine in simulation but unstable on plant | Real scan time differs from simulator; OB35 period default of 100 ms may not match | Re-check HW Config → Cyclic Interrupts |
| OB3x time-out alarm (OB80) | OB3x execution longer than its period | Move PIDs to a slower OB or split the dispatcher |
12. Quick Checklist
- FB41 placed in OB3x whose period equals CYCLE, not in OB1.
- HW Config → CPU properties → Cyclic Interrupts shows the intended period.
- Phase offset set so multiple OB3x do not queue.
- Loop scheduler used when more than three PIDs share a single OB.
- CYCLE ≈ 0.1·τp, validated by open-loop step test.
- FB41 instance DB has I_ITL primed for cold start.
- Online trend confirms uniform call interval.
Does FB41 have to be called in a cyclic interrupt OB, or can it stay in OB1?
It can stay in OB1 only if OB1 itself has a constant scan time and the CYCLE constant matches that scan time. In practice the recommended and far more robust approach is to call FB41 from a cyclic interrupt OB (OB30–OB38) and to set the CYCLE input to the OB's configured period. For multi-PID projects, keep all PIDs in OB35 and use a loop scheduler to release each one at its own multiple of 100 ms.
What is the default period of OB35 and how do I change it?
OB35 is pre-configured for 100 ms on most S7-300/400 CPUs. Open the HW Config, select the CPU, and go to Properties → Cyclic Interrupts. Enter the desired period (10 ms to 60 s with 1 ms resolution) and a phase offset (0 to period − 1 ms). The change must be downloaded to the CPU and typically requires a STOP→START transition to take effect.
How do I pick the CYCLE value for a temperature loop on a large furnace?
Perform an open-loop step test and fit a first-order-plus-dead-time model to obtain τp. Set CYCLE to roughly 0.1·τp. For a furnace with τp of 600 s, CYCLE should be 60 s; put the FB41 in OB30 and use a 60 s period, or keep it in OB35 with a scheduler that releases it every 600 master cycles (assuming OB35 is 100 ms).
Can I call multiple FB41 instances in the same OB3x?
Yes, but their CYCLE values must be the same if they share a common call point. If two loops need different CYCLE values, place each in its own OB3x (e.g. OB32 for 1 s, OB35 for 100 ms) or run a loop scheduler inside OB35 that releases each FB41 at its own multiple. The latter is the standard solution for S7-300 CPUs that have only one cyclic interrupt OB.
My controller drifts and then suddenly winds up. Is this FB41 or CYCLE mismatch?
Both are possible, but a windup episode that takes minutes to bleed off after a long OB1 scan gap is a strong indicator of CYCLE mismatch. Trend CYCLE in the instance DB while the scan monitor is active: if the interval varies by more than 5 %, move the FB41 to a dedicated OB3x with a guaranteed period. Also check that LMN_HLM / LMN_LLM are realistic; over-large limits combined with a CYCLE mismatch produce exactly the drift-then-spike signature you are seeing.