PID tuning: calculate gains, then test the response

Tune a PID controller against explicit response and effort targets. Convert Ziegler–Nichols settings into parallel gains, understand relay auto-tuning, and compare manual adjustments.

By 13 min read

What you will learn

  • Choose measurable targets before adjusting PID gains.
  • Convert ideal-form time constants into parallel integral and derivative gains.
  • Derive the ultimate gain and period for a three-lag plant.
  • Calculate classical Ziegler–Nichols starting values.
  • Explain the relay estimate and its approximation limits.
  • Compare manual gains without inferring settling from a finite plot.

Before you start

A PID tuning rule can produce a stable controller that misses your task's requirements. In this lesson's model, a rounded Ziegler–Nichols PID setting overshoots the unit reference by about 56.6%.

You will calculate that starting point, adjust the gains, and compare the result against explicit targets. You will also see what a relay auto-tuning measurement can tell you about the plant.

Set requirements before tuning PID gains

Write down what a useful response must do. A gripper might need little overshoot; a positioning stage might also need a short move time and limited command effort. Those requirements can conflict.

Our unit-step exercise uses four checks:

  • The model has asymptotically stable dynamics.
  • Sampled output overshoot above the reference is at most 10% during 0–12 s.
  • Absolute tracking error at 12 s is at most 0.02.
  • Sampled peak command magnitude is at most 6 during 0–12 s.

Signals use normalized units. The command target is an evaluation threshold; the model does not clip its command there. These numbers define this exercise, not a hardware specification.

An end error measures one instant. Settling time requires the response to stay in its band for every later time. The step-response characteristics lesson makes that distinction precise.

Match ideal and parallel PID conventions

The same symbols can mean different things in different controller interfaces. Before copying gains, write the equation the controller implements.

For ideal derivative action on error, two equivalent forms are:

C(s) = Kp[1 + 1/(Ti s) + Td s]
C(s) = Kp + Ki/s + Kd s
Ki = Kp/Ti,   Kd = Kp Td

Here Kp is dimensionless, Ti and Td use seconds, Ki uses 1/s, and Kd uses seconds. Other signal units change the gain units. Setting integral action off means Ki = 0; Ti = 0 would make the ideal form singular.

MathWorks' PID model documentation distinguishes parallel gains from standard-form time constants and includes the derivative filter separately. Review PID control for the role of each term.

Define the plant and controller realization

Reuse the three-lag plant from stability criteria:

G(s) = 6 / [(s + 1)(s + 2)(s + 3)]

Its lag time constants are 1 s, 0.5 s, and 1/3 s. The DC gain is one. Numerical polynomial coefficients suppress their matching powers of seconds.

The lab applies a unit reference step from rest. It uses derivative on output, with the exact model rate y′:

e = 1 − y,   z′ = e
u = Kp e + Ki z − Kd y′
x₁′ = u − x₁,   x₂′ = 2(x₁ − x₂),   y′ = 3(x₂ − y)

All states start at zero. When Ki = 0, the lab removes the unused integrator and holds z at zero. Command remains unrestricted.

Derivative on output avoids differentiating the reference step. It preserves the characteristic denominator of ideal error-based PID, but changes the setpoint numerator. With Ki > 0, this realization gives:

Y/R = 6(Kp s + Ki) / p(s)
p(s) = s⁴ + 6s³ + (11 + 6Kd)s² + 6(1 + Kp)s + 6Ki

An ideal derivative on error would add 6Kd s² to the numerator. A real derivative filter introduces additional dynamics. The plotted response therefore belongs to the stated realization, not every controller called PID.

Make manual tuning comparisons

Manual tuning works best as a sequence of controlled comparisons. Keep the plant, starting state, reference, and measurement window fixed. Change one gain, record the result, and decide which requirement improved or worsened.

For this model, a useful sequence is:

  1. Start with Ki = Kd = 0. Increase Kp within a stable range and compare response speed with oscillation and command effort.
  2. Add a small Ki to reduce persistent tracking error. Check overshoot and stability again; integral action can make both worse.
  3. Add Kd when output-rate feedback improves the transient. In hardware, include its filter and measured noise in the comparison.
  4. Reduce or rebalance gains when the combined controller misses a target. Repeat with disturbances and different operating conditions before accepting a design.

These are trial directions, not universal monotonic rules. The terms interact. For example, Kp = 1, Ki = 4, Kd = 0 is unstable here even though Kp is far below the proportional-only limit.

The Gentler PID setting uses Kp = 2, Ki = 0.6, Kd = 1. It gives a sampled peak command of about 2.016 and an end error of about 0.00887. It meets this exercise's checks while the faster Ziegler–Nichols starting point misses them.

Find ultimate gain and ultimate period

The classical ultimate-gain experiment disables I and D. It finds the proportional gain Ku at which the linear closed loop reaches sustained oscillation, then measures that oscillation's period Pu.

Our exact model makes a gain sweep unnecessary. Proportional feedback has characteristic polynomial:

s³ + 6s² + 11s + 6(1 + Kp)

Its Routh first column is 1, 6, 10 − Kp, 6(1 + Kp). At Ku = 10, the polynomial factors into (s + 6)(s² + 11). The imaginary pair gives:

ωu = √11 ≈ 3.316625 rad/s
Pu = 2π/ωu ≈ 1.894452 s

At that boundary, free oscillations need not decay. With perfectly zero initial state and zero input, the model still stays at zero; a disturbance or test input must excite the mode to observe it.

This experiment deliberately approaches loss of stability. Use model analysis here. A physical test needs suitable travel and effort limits, a stop condition, and a process that permits oscillation; some plants have no finite proportional-only ultimate gain.

Calculate Ziegler–Nichols starting gains

The classical closed-loop Ziegler–Nichols table uses the measured Ku and Pu. NI's PID theory reference gives these ideal-form settings:

ControllerKpTiTd
P0.5KuIntegral off0
PI0.45KuPu/1.20
PID0.6KuPu/2Pu/8

For Ku = 10 and Pu ≈ 1.894452 s, the PID row gives Kp = 6, Ti ≈ 0.947226 s, and Td ≈ 0.236806 s. Convert the time constants before entering parallel gains:

Ki = Kp/Ti ≈ 6.334287 1/s
Kd = Kp Td ≈ 1.420839 s

The lab rounds these to (6, 6.3, 1.4) to match the sliders' 0.1 increments. It also lists the calculated gains before rounding. The PI row similarly becomes (4.5, 2.9, 0) after rounding.

These empirical settings provide a starting point. They do not optimize our chosen targets or establish performance for a different plant, PID convention, or derivative filter. Evaluate the resulting response before choosing the final gains.

Estimate ultimate gain with relay auto-tuning

A relay test temporarily replaces the continuous controller with a two-level command around an operating point: +d when error is positive, −d when error is negative. For a suitable plant, the loop can develop a repeatable oscillation.

After the transient, measure the output's half-amplitude a and its period. Half-amplitude is half the peak-to-peak range. Use repeated cycles to check whether those measurements are consistent.

The estimate comes from keeping the relay square wave's first harmonic. Its amplitude is 4d/π. If the plant suppresses higher harmonics enough to make output nearly sinusoidal, the first harmonic approximately balances the oscillation:

a ≈ |G(jωu)| · 4d/π
Ku ≈ 1/|G(jωu)| ≈ 4d/(πa),   Pu ≈ measured period

This is a describing-function approximation. Josefin Berner's Lund thesis, Section 2.5, explains its use in relay tuning and how hysteresis shifts the identified frequency-response point. Higher harmonics, noise, and asymmetric motion can also shift the estimate and the apparent oscillation frequency.

For illustrative measurements d = 0.5 and a = 0.06, the estimate is Ku ≈ 10.610330. This is not a simulated relay result for our plant. The lab's response presets use the independently known Ku = 10.

The relay limits command amplitude, but does not guarantee safe output motion or a useful limit cycle. Choose an applicable test and validate its measurements; a single estimated frequency-response point cannot identify every plant dynamic.

Test the gains against the same targets

Choose gains against a requirement

Does this starting point meet the targets?

Adjust parallel PID gains for the three-lag plant. Compare overshoot, end error, and command effort over a fixed twelve-second test.

6.0
6.3
1.4

u = Kp(1 - y) + Ki ∫(1 - y)dt - Kd y′. Derivative acts on the exact model output rate. Each gain change starts a fresh response from rest. Signals are normalized; time is in seconds.

Example targets: a stable model, at most 10% sampled overshoot above the unit reference, at most 0.02 absolute error at 12 s, and sampled peak |u| at most 6. Command has no saturation. These targets describe this exercise.

Output tracking for the manually selected PID gainsThe blue curve shows output over twelve seconds after a unit reference step. The dashed line is the reference at one. The dotted line at 1.1 marks the ten percent overshoot target. This finite curve does not establish settling time.-1020612Time (s)Output y
The dashed line is the unit reference; the dotted line marks 10% overshoot. Plot scales change with the response. Check the readouts when comparing gains.
Command effort for the manually selected PID gainsThe orange curve shows the unrestricted command over twelve seconds. The dotted line at six is an example effort target, not an actuator limit.-3080612Time (s)Command u
Command can exceed the dotted +6 effort target or become negative. The peak readout uses absolute command, including negative effort. No clipping or anti-windup acts here.
Model stability
Asymptotically stable
Output at 12 s
0.999850
Absolute error at 12 s
0.000150
Sampled overshoot (%)
56.586254
Sampled peak |u|
6.409212
Target check
Misses model + sampled targets

This stable model with integral action approaches the unit reference. The sample at twelve seconds is a finite-time value. Metrics sample the numerical response every 0.0025 s; plots use every eighth sample. Sampled peaks can miss extrema between points.

Calculated Ziegler–Nichols parallel gains, before rounding
RuleKpKi (1/s)Kd (s)
P5.0000000.0000000.000000
PI4.5000002.8504290.000000
PID6.0000006.3342871.420839

This plant has exact Ku = 10 and Pu = 1.894452 s. The three rule presets round their calculated gains to 0.1 for the sliders. These are starting values; the derivative-on-output realization also changes setpoint response from the ideal derivative-on-error form.

Estimate ultimate gain from relay measurements

Enter illustrative half-amplitudes: the relay switches between ±d, and output oscillates approximately ±a about its operating point. Ku ≈ 4d/(πa) assumes a nearly sinusoidal output and a symmetric relay without hysteresis.

0.5
0.06
Relay estimate of Ku
10.610330

This calculator uses supplied measurements; it does not simulate a relay experiment or update the manual gains. Measure the oscillation period separately to estimate Pu. A finite relay command does not guarantee safe plant motion.

Start with the rounded Ziegler–Nichols PID gains. The model is stable and its end error is small, yet sampled overshoot reaches about 56.586% and peak command reaches 6.409. Both exceed the exercise targets.

Select Gentler PID, then change one gain. Record the changes in overshoot, error, and effort. Every edit starts a fresh simulation from rest, so the comparison excludes gain-switching transients.

The response uses fourth-order Runge–Kutta integration with a 0.0025 s step. Metrics inspect that grid; the drawings retain one sample every 0.02 s. Sampled peaks can miss extrema between points, and six decimal places do not imply matching physical accuracy.

The relay calculator has a separate role. Changing d or a updates only its gain estimate. A complete relay-based tuning procedure also needs the measured period and a validated controller design after the test.

Check stability and implementation limits

For this plant with Ki > 0, the quartic Routh test requires:

b = 10 + 6Kd − Kp > 0
(1 + Kp)b > 6Ki

The other coefficient signs are positive in the lab's domain: Kp ≥ 0, Kd ≥ 0, Ki > 0. Its Kp ≤ 8 bound also ensures b ≥ 2. With Ki = 0, removing the inactive integrator leaves a stable cubic throughout the slider range.

At (Kp, Ki, Kd) = (2, 4, 0), the strict inequality becomes equality. The polynomial factors as (s² + 3)(s + 2)(s + 4). The imaginary pair sustains an oscillatory mode, so the lab labels this case marginal.

These statements depend on the exact model and realization. A practical derivative filter, sample delay, or plant error can change the characteristic equation. Evaluate model uncertainty and the actual controller implementation as part of the design.

Actuator saturation also changes the loop. The unlimited command in this lesson exposes requested effort; integral windup explains what can happen when the actuator cannot deliver it. Recheck disturbance rejection as well as setpoint tracking, since a good reference step alone does not establish both.

Reproduce the tuning comparison in Python

This standard-library example uses the same controller realization and sample grid. It prints finite-window measurements, without assigning a settling time.

from math import pi, sqrt

def response(kp, ki, kd):
    h = 0.0025
    x = [0.0, 0.0, 0.0, 0.0]

    def command(x):
        return kp*(1-x[2]) + ki*x[3] - kd*3*(x[1]-x[2])

    def slope(x):
        return [command(x)-x[0], 2*(x[0]-x[1]),
                3*(x[1]-x[2]), 1-x[2] if ki > 0 else 0.0]

    peak_y, peak_u = 0.0, abs(command(x))
    for _ in range(round(12/h)):
        a = slope(x)
        b = slope([v+h*k/2 for v, k in zip(x, a)])
        c = slope([v+h*k/2 for v, k in zip(x, b)])
        d = slope([v+h*k for v, k in zip(x, c)])
        x = [v+h*(aa+2*bb+2*cc+dd)/6
             for v, aa, bb, cc, dd in zip(x, a, b, c, d)]
        peak_y = max(peak_y, x[2])
        peak_u = max(peak_u, abs(command(x)))
    return x[2], abs(1-x[2]), max(0, peak_y-1)*100, peak_u

pu = 2*pi/sqrt(11)
print(f"Ku=10, Pu={pu:.6f} s")
print(f"PID: Kp=6, Ki={12/pu:.6f}, Kd={6*pu/8:.6f}")
for label, gains in [
    ("rounded PID", (6, 6.3, 1.4)),
    ("gentler PID", (2, 0.6, 1)),
    ("excessive I", (1, 4, 0)),
]:
    y, error, overshoot, effort = response(*gains)
    print(f"{label}: y(12)={y:.6f}, error={error:.6f}, "
          f"overshoot={overshoot:.6f}%, peak|u|={effort:.6f}")
print(f"Relay estimate: Ku={4*0.5/(pi*0.06):.6f}")

Output:

Ku=10, Pu=1.894452 s
PID: Kp=6, Ki=6.334287, Kd=1.420839
rounded PID: y(12)=0.999850, error=0.000150, overshoot=56.586254%, peak|u|=6.409212
gentler PID: y(12)=0.991128, error=0.008872, overshoot=0.000000%, peak|u|=2.016052
excessive I: y(12)=-1.235236, error=2.235236, overshoot=332.871034%, peak|u|=9.535898
Relay estimate: Ku=10.610330

Try it yourself

Exercise 1. A different plant has Ku = 8 and Pu = 2 s. Calculate the classical ideal-form PID settings and convert them to parallel gains. If its interface asks for Ki, should you enter Ti directly?

Check the PID convention conversion

The ideal settings are Kp = 4.8, Ti = 1 s, and Td = 0.25 s. The parallel gains are Kp = 4.8, Ki = 4.8 1/s, and Kd = 1.2 s.

Enter Kp/Ti in the Ki field. Ti and Ki have different meanings and units. These calculations still provide starting values, so test the implemented controller against the requirements.

Exercise 2. A symmetric relay switches between −0.5 and +0.5. The output ranges from −0.1 to +0.1 about its operating point. Find the estimated Ku, and explain what goes wrong if you use the output's peak-to-peak value as a.

Check the relay amplitude measurement

Use d = 0.5 and a = 0.1. The estimate is 4(0.5)/(π × 0.1) = 6.366198.

Using the peak-to-peak value 0.2 would halve the estimate to 3.183099. You still need the oscillation period and evidence that the waveform supports the first-harmonic approximation.

Sources and further study

Continue with integral windup and apply an actuator limit. Compare the requested command with the command the actuator can deliver, then decide how the integral state should respond to that difference.