PID

PID Playground

A FOPDT process and parallel-form PID controller, integrated with exact zero-order-hold, fractional dead time, ISA-style derivative filtering, and three selectable anti-windup strategies. Apply Ziegler-Nichols, Cohen-Coon, AMIGO, or lambda tuning rules to the configured plant. Reference simulation only - not for production tuning or process-safety decisions.

Loading WASM simulation engine...

1Process Loop

A self-regulating first-order-plus-dead-time process under parallel-form PID control. Use the Process Narrative buttons to load realistic numbers for fast flow, jacketed temperature, heat exchanger, or composition loops, or stay on the normalized educational case. The dead time can be a non-integer multiple of the integration step; the delay buffer interpolates linearly between samples.

SP target
PV plant state
u actuator command
d load disturbance

Physical Setup

Educational FOPDT
What it is
--
What dominates
--
What to look for
--
Tuning recommendation
--
Cautions
--

2Metrics; shift-click any underlined term for a glossary entry

Overshoot --
Rise time (10-90) --
Settling time --
Final error --
PM (phase margin) --
GM (gain margin) --
Ms (sensitivity peak) --
wgc (crossover) --
IAE --
ISE --
ITAE --
Saturation --
Max PV --
Min PV --
Max output --
Min output --
Settled --
Final PV --
Final output --

3Process Variable

Setpoint PV Measurement

4Controller Output

Output Raw Disturbance

5Open-Loop Frequency Response

|L| |S| wgc marker annotations

Continuous-time loop L(s) = C(s) G(s) computed from the configured FOPDT plant and parallel-form PID gains. The sample-and-hold approximation is omitted; this is the textbook loop the discrete simulator is approximating.

Exports

Build metadata pending.

Method and Scope

Process model

The plant is a first-order-plus-dead-time (FOPDT) self-regulating process driven by a delayed manipulated variable plus an additive load disturbance:

tau * dPV/dt = -(PV - pv_baseline) + K * u(t - theta) + d(t)

The continuous solution under a piecewise-constant input is integrated exactly by zero-order hold each step:

PV[k+1] = PV[k] * exp(-dt/tau)
        + target * (1 - exp(-dt/tau))
target = pv_baseline + K * u_delayed + d

This is exact within floating-point precision and removes any Euler stability constraint on dt. Dead time is implemented as a delay buffer with linear interpolation between adjacent samples when theta is not an integer multiple of dt.

PID controller

Parallel form, evaluated at the controller sample time Ts and held with a zero-order hold between samples:

error = SP - measurement
P = Kp * error
I = I + Ki * error * Ts                  (with anti-windup, see below)
D = -Kd * filtered_derivative_of_measurement   (derivative-on-measurement)
    or
D = +Kd * filtered_derivative_of_error         (derivative-on-error)
u_raw = bias + P + I + D
u     = clamp(u_raw, u_min, u_max)

The derivative branch is the discrete equivalent of a first-order ISA-style filter D(s) = Kd s / (1 + Tf s). The discrete pole is alpha = exp(-Ts / Tf); Tf = 0 disables filtering. The equivalent ideal-form parameters are Ti = Kp / Ki and Td = Kd / Kp; both are shown live next to the gain inputs.

Anti-windup strategies

  • Off. Integrator updates every sample regardless of saturation. Useful only to demonstrate windup behavior.
  • Conditional (clamp). The integrator is frozen whenever the pre-integration command is already saturated and the proposed integral update would push it further into the limit. The other direction is allowed so the integrator can pull the actuator back into range.
  • Back-calculation. Each tick adds (u_clamped - u_raw) * Ts / Tt to the integral. When the controller is unsaturated this term is zero; when saturated, it drives the integrator back at a rate set by the tracking time Tt. This is the strategy used in most modern industrial PID blocks (Siemens, ABB, AB, Honeywell).

Tuning rules

The Tuning Rules panel applies open-loop FOPDT correlations to the configured K, tau, and theta. Each rule rewrites only the controller gains so you can compare them on the same plant:

  • Ziegler-Nichols PI: Kc = 0.9 * tau / (K * theta), Ti = theta / 0.3.
  • Ziegler-Nichols PID: Kc = 1.2 * tau / (K * theta), Ti = 2 * theta, Td = 0.5 * theta.
  • Cohen-Coon PI/PID: classic 1953 correlations; less detuning needed for dead-time-dominated loops than Z-N.
  • AMIGO PI/PID: Astrom-Hagglund robustness-focused rule derived from constrained optimization.
  • Lambda PI: IMC tuning with closed-loop time constant lambda = tau. Decreasing lambda makes the loop faster but less robust.

The displayed Kp / Ki / Kd, plus the matching Ti and Td readouts, are exactly what the tuning rule produced; nothing is silently re-shaped.

Measurement noise

Noise is zero-mean Gaussian with standard deviation equal to the configured amplitude. The generator is Box-Muller built on a deterministic 32-bit LCG so that Rust and Python produce identical sequences from the same seed. Fixtures are reproducible bit-for-bit.

Frequency-domain analysis

The Bode plots evaluate the continuous-time open-loop transfer function on a fixed log frequency grid (1e-3 to 1e3 rad/s, 256 points):

C(s) = Kp + Ki/s + Kd * s / (1 + Tf * s)
G(s) = K * exp(-theta * s) / (1 + tau * s)
L(s) = C(s) * G(s)
S(s) = 1 / (1 + L(s))
  • Phase margin (PM) is 180 deg + angle of L at the first omega where |L(jw)| = 1.
  • Gain margin (GM) is -20 log10 |L(jwpc)| at the first omega where the unwrapped phase crosses -180 deg.
  • Sensitivity peak Ms = max |S(jw)| over the grid. Industrial loops aim for Ms in 1.4-2.0; below 1.4 is conservative and slow, above 2.0 is fragile.
  • Gain crossover wgc marks the closed-loop bandwidth and is annotated on both subplots.

The Bode plot is computed from the configured K, tau, theta, Kp, Ki, Kd, and Tf in closed form -- it updates instantly when any tuning rule or slider is moved, with no second simulation pass needed.

Metrics

  • Overshoot is direction-aware (positive and negative steps both produce non-negative overshoot).
  • Rise time is the 10% to 90% rise time of the PV trajectory after the setpoint step.
  • Settling time is measured against a configurable tolerance band (default 2% of the step magnitude) and is the first time after which PV stays inside the band for the rest of the horizon.
  • IAE / ISE / ITAE integrate absolute, squared, and time-weighted absolute error over the horizon. ITAE is weighted from the step time forward.
  • Saturation percent is the fraction of samples where the actuator command was clamped.
  • Max / Min PV / output are the extrema of the recorded trajectories.
  • Settled is true when the loop reached the tolerance band before the horizon ended.

Verification boundary

The Python reference in verification/pid_reference.py is the numerical ground truth. It generates deterministic fixtures consumed by the Rust crate's regression test, and is also a readable side-by-side derivation of the controller and the integrator. The browser runtime uses the Rust/WASM port; passing tests mean Rust/Python agree to within 1e-8 absolute tolerance on every recorded series and metric.

Scope and limitations

Reference simulation only. FOPDT is a deliberate idealization; real plants have constraints, nonlinearity, valve hysteresis, and stochastic disturbances that this tool does not represent. Do not use these results for process-safety decisions or plant tuning without independent validation. The author makes no warranty as to fitness for any particular use.

Learning References