e = SP − PV
CO = Kp·( e + (1/Ti)·∫e dt − Td·dPV/dt )
Kp is the overall gain; Ti and Td are times in seconds. Internally Kp/Ti
and Kp·Td are cached when tuning is written (pidSetTuning() /
pidRefreshTuning()), so nothing is divided at runtime.
What each constant does
A PID loop looks at the error — how far the measurement (PV) is from the
target (SP) — three different ways, and adds the results together. Using a
pump loop as the example: PV is flow in L/min, CO is drive frequency in Hz.
Kp — react to the error right now. The bigger the error, the harder the
loop pushes: Kp = 5 means every 1 L/min of error adds 5 Hz to the output.
This does most of the work, but it can't finish the job alone — as PV
approaches SP the error shrinks, so the push shrinks too, and the loop
settles just short of target (a permanent offset). Too low: sluggish, big
offset. Too high: the loop overreacts to its own corrections and oscillates.
Ti — patiently work off whatever error remains. The integral term keeps
nudging the output as long as any error persists, which is what finally
lands PV exactly on SP. Ti is how patient it is: it's the time the I term
takes to repeat the P term's correction on a constant error. Ti = 20 means
"take about 20 seconds to double down." Smaller Ti = less patient = stronger
action — note the direction, it trips people up. Too large: the last bit of
error takes forever to clear. Too small: the loop keeps pushing after PV has
started moving, overshoots, then hunts back and forth.
Td — anticipate where PV is heading. The derivative term watches how fast
the measurement is moving and pushes against that motion — braking before
arrival rather than after. Td = 2 means the loop acts as if PV were already
where its current trend puts it 2 seconds from now. It tames overshoot on
slow processes (temperature especially), but it amplifies sensor noise, so
most flow and level loops simply run Td = 0 (PI control).
Rule of thumb: Kp responds to the present error, Ti cleans up the
accumulated past, Td braces for the predicted future.
Parameters
Parameter
Units
Example
Notes
kp
CO units / PV unit
5
Primary control action. Higher = harder response, eventually instability.
ti
s
20
Integral (reset) time; smaller = stronger. 0 = no reset, loop sits at permanent offset.
td
s
2
Derivative lookahead. 0 = PI, correct for most flow/level loops.
outMin / outMax
CO units
0 / 60
Output span in engineering units (e.g. Hz).
outRateLimit
CO units / s
10
Max CO slew. 0 = off. Derive from the actuator, not preference.
dFilterTau
s
0.05
D-term low-pass. Size as Td/10. 0 = off. Default 0.05.
setpoint
PV units
25
Target.
mode
—
AUTO
DISABLED / MANUAL / AUTO.
manualOutput
CO units
—
CO forced (clamped) while in MANUAL.
Converting gains from other controllers
From
To ours
ISA Kc, Ti, Td
Drop straight in: Kp = Kc, Ti/Td unchanged
Parallel gains Kp, Ki, Kd
Ti = Kp/Ki · Td = Kd/Kp
Proportional band
Kp = 100/PB% (only if PV and CO are both % of span)
Derivative on PV — setpoint steps never kick the output; D always
runs through the LPF when dFilterTau > 0.
Anti-windup — the integrator is clamped every cycle so P+I+D lands
inside [outMin, outMax]; it cannot wind past the output span. The slew
limiter runs downstream, so keep rate limits generous.
Bumpless transfer — in MANUAL the integrator tracks the output, so
switching to AUTO starts from the CO already at the actuator.
Reverse-acting loops — no direction flag; negate Kp only. Ti and
Td stay positive and inherit the direction automatically.
Fault handling — NaN/Inf PV holds the last output; a scan gap over
0.5 s resyncs state instead of integrating it.
Manual tuning quickstart
Ti = Td = 0. Raise Kp until the loop just oscillates, then back off.
Bring in Ti (start near the oscillation period) and shrink it until
offset clears without hunting.
Add Td last, only if overshoot is still a problem.