Skip to content

Control Module: pid-cascade

A PID controller whose setpoint is read from an external tag address, typically the output of an outer-loop controller or a supervisory system. Use this template for the inner loop of a cascade pair, for ratio control, or any situation where the SP does not come from an operator/recipe register.

For a single self-contained loop with an operator- or recipe-writable setpoint, use pid-loop instead.

Where to find it

System endpoint → Equipment Library → Control Modules tab → select pid-cascade.

pid-cascade FBD: AI process variable and AI setpoint feed PV/SP of a PID controller whose output drives an AO

pid-cascade ST: IEC 61131-3 program reading both PV and external SP from AIs, computing the PID output, and writing it to the AO

What you see on the faceplate

Element Meaning
PV Process variable (read-only)
SP Setpoint, sourced from an external AI (read-only)
CV Control output percentage, 0–100 (writable in Manual mode)

Unlike pid-loop, the SP is read-only on the faceplate. If you need to manually override the SP during commissioning, the right move is to switch the outer loop's owner to Manual. That keeps the cascade relationship explicit. Editing this inner loop directly would hide it. CV, by contrast, belongs to this inner loop alone. With the inner loop's own equipment in Manual mode, an operator can drive its CV directly, the same commissioning path pid-loop documents. See "How it works".

Tags

The template declares deviceClass: controller and a role on each tag (ADR 0016), matching pid-loop: SP is the setpoint (read-only here, tracking the external source), PV the feedback and the card's prominent value, and CV the commanded output.

Tag Type Access Role Description
PV Float read feedback Measured process variable, scaled to engineering units. Shown as the card's prominent value.
SP Float read setpoint Setpoint read from the external tag address.
CV Float read/write command Control output (0–100%) driven to the analog output. Writable only in Manual mode — see "How it works" for what a write does.
ILCK Boolean read interlock true while the device interlock is forcing the output to its safe state. Reserve a TagTrue AlarmDefinition for interlocks whose trip is abnormal in itself (why). The historian records every trip either way.
PV_BAD Boolean read alarm true while the process variable is not trusted: the driver reported bad quality, the read failed, or the raw value fell outside the fail band. PV holds its last trusted reading while this is set, and the loop holds its output. See pid-loop for the full behaviour and ADR 0074 for the reasoning.
SP_BAD Boolean read alarm true while the supervisory setpoint is not trusted, on the same three conditions. SP holds its last trusted value and the loop keeps regulating to it, which is the opposite of what PV_BAD does and is deliberate. See "A setpoint that stops arriving" below.

Parameters

Parameter Default What it does
kp 1.0 Proportional gain
ki 0.1 Integral gain
kd 0.01 Derivative gain
eng_min / eng_max (blank) PV and SP scale range
eng_units (blank) Display units for PV and SP
interlockAddress (empty — interlock disabled) Device address of a boolean trip signal, read by the output block every scan; while tripped (or unreadable — fail-safe) the output is forced to the safe value.
interlockInvert false Trip while the signal is false (with the invert off, true trips).
safeValue (empty) Output value forced while interlocked. Empty means the output range minimum.
rawFailLow / rawFailHigh (blank — no band) Raw counts outside which the process variable reading is rejected and PV_BAD is raised. Both or neither. Needed only where the driver reports no quality of its own, and not on a card whose range diagnostic this product already knows.
spRawFailLow / spRawFailHigh (blank — no band) The same band for the supervisory setpoint input, raising SP_BAD. Two pairs because these are two signals on two cards. Without this pair SP_BAD can never go true on Modbus or EtherNet/IP, where a broken wire is a successful read of an underrange register.

Setting interlockAddress on an instance enables the device interlock. See Alarms and Interlocks → Pattern 0.

Scan interval is fixed at 100 ms, matching pid-loop.

How it works

Each scan, the runtime:

  1. Reads PV from the pv input tag address.
  2. Reads SP from the sp input tag address (the outer-loop output, or a supervisory target).
  3. Computes PID output against the error SP − PV.
  4. Writes CV (0–100%) to the out tag address.

Tuning advice is identical to pid-loop. See its tuning section. Both loops use the same PID block, which clamps its own output and backs the current scan's error back out of the integral whenever that clamp engages (see pid-loop's "How it works"). Neither the inner nor the outer integrator keeps accumulating once its own CV saturates.

As with pid-loop, when the device interlock is enabled and trips, the template freezes the integrator (TRK) and back-calculates it from the output's actually-written value (TRK_VAL). The inner loop tracks what the device really sees and resumes bumplessly on release. The same back-calculation mechanism is how a cascade inner loop initializes from its real output. Wire the outer loop's TRK_VAL from the inner loop's setpoint source so the outer loop hands off without a bump when it takes over (see the wiring pattern below).

Manual mode drives the inner loop's CV directly, the same mechanism pid-loop documents: with the inner loop's equipment in Manual mode, writing CV overrides the PID block's own output, and the block tracks the override the same way it tracks a device-forced value above, bumpless in both directions. Automatic mode refuses the write and, on return to Automatic, hands control back to the loop's own computation with no extra step. This is independent of the outer loop. Switching the inner loop to Manual overrides only its own CV. It does not touch the outer loop's setpoint output.

A setpoint that stops arriving

The supervisory setpoint is an analog input, so it fails the way any instrument fails. read_sp refuses to publish a reading it does not trust. It holds SP at the last trusted value and raises SP_BAD. It also faults, which puts the control program into Degraded with read_sp named.

The loop keeps regulating. It does not hold its output the way it does on a bad PV, and that asymmetry is deliberate (ADR 0074). A dead PV blinds the loop, so it has no basis on which to act. A dead SP leaves the measurement live and the valve live, and takes away only the target. Freezing the output there would throw both working things away and leave the process open loop against whatever disturbs it, on what is usually a transient supervisory link failure. Holding the last cascade setpoint and continuing to control is the standard answer.

So SP_BAD is annunciation, and it is the whole of the automatic response. What to do about it is an operator decision:

  • Leave it. The process stays at the last target the supervisor asked for, which is often the right place for it.
  • Take the inner loop to Manual and drive CV directly, the commissioning path above.
  • Alarm on it. Declare a TagTrue AlarmDefinition on SP_BAD so the condition annunciates. On its own it only sits on a faceplate. A batch that must not run to a frozen target holds on the alarm.

Where the driver reports no quality of its own, set spRawFailLow and spRawFailHigh on the instance, or SP_BAD never goes true. On a card whose range diagnostic this product knows the driver already reports a broken wire and no band is needed. A card that maps 4 mA onto raw zero admits no band that would separate one. See the process-variable band in pid-loop for why.

Cascade wiring pattern

Typical pairing:

  • Outer loop — pid-loop driving the cascade setpoint. CV of the outer loop is written (via an analog output address, or directly via an internal tag) to the same tag address that the inner loop reads as sp.
  • Inner loop — pid-cascade, taking its SP from that address.

The outer-loop scan rate should be slower than the inner's, typically 2–10×. A reactor temperature / jacket temperature cascade might run the outer loop at 1 s and the inner at 100 ms.

Failure modes

  • SP source tag goes stale / offline — pid-cascade continues regulating to the last-read value, by design. SP_BAD is what makes that visible. See "A setpoint that stops arriving" for the remedies. An AlarmDefinition on IOModule StateEquals: Offline covers the case where the whole supervisory module drops. SP_BAD alone does not distinguish that from a single dead channel.
  • Outer loop saturated long-term — SP pinned at its limit means the cascade can't deliver what the supervisory loop wants. Fix by revisiting outer-loop tuning or actuator sizing. Raising inner gains fixes nothing here.

Reference instances

Deployment Unit Instance Purpose
newark-plant granulator-1 jacket-temp-ctrl Granulator bowl jacket temperature tracks the recipe-driven SP written by the outer temperature loop

The reference plant currently has no pid-cascade instances. It uses pid-loop for its single closed loop (N2 blanket pressure). Add a pid-cascade when demonstrating reactor-jacket cascade control.

Try it

On newark-plant:

  1. Process → newark-plant → granulator-1
  2. Click jacket-temp-ctrl on the unit detail view
  3. Observe PV, SP, and CV — note that SP is read-only on the faceplate
  4. Write to the Granulator1.JacketTempSP address (via the outer loop or an operator override) and watch the cascade track