Problem 403981 · medium · Level 04 Non-Linear Data Structures

Tuning the Mash Tun From a Relay Test

relay test · ultimate gain · Ziegler-Nichols · PID tuning · oscillation

A small brewery heats its mash tun (a vat of grain and hot water) with a steam valve, and wants PID gains without weeks of trial and error. The relay test finds them in a few minutes. The controller is replaced by a relay: whenever the temperature is below the target it opens the steam by d kW more than usual, and whenever it is above it closes it by d kW. The temperature settles into a steady oscillation around the target, half a cycle out of step with the relay.

That oscillation tells you two things about the vat:

  • its period Tu (seconds) is the ultimate period: a P controller with a large enough gain would oscillate at (very nearly) this period;
  • its half-height a (°C) gives the ultimate gain, the P gain at which that oscillation would neither grow nor die, estimated as Ku = 4 * d / (pi * a) (kW per °C). A switch of ±d has a strongest sine component of height 4 * d / pi, so the vat turns a push of that size into a swing of a.

You are given the recorded temperatures temps, one every dt seconds, taken after the oscillation became steady. Measure it like this:

hi, lo = the highest and lowest temperature;   mid = (hi + lo) / 2;   a = (hi - lo) / 2
an upward crossing is an index k >= 1 with temps[k-1] < mid <= temps[k]
Tu = (last crossing index - first crossing index) * dt / (number of crossings - 1)

Then apply the Ziegler-Nichols table for the chosen rule, with Ki = Kp / Ti and Kd = Kp * Td (where the table has no Ti or Td, that gain is 0.0):

rule    Kp          Ti          Td
"P"     0.5 * Ku    -           -
"PI"    0.45 * Ku   Tu / 1.2    -
"PID"   0.6 * Ku    Tu / 2      Tu / 8

Write relay_tune(temps, dt, d, rule) that returns the tuple (Ku, Tu, Kp, Ki, Kd), or None if the recording has fewer than two upward crossings (it does not show a full cycle). Plot temps to see the cycle you are measuring.

Examples

Input:  temps = [65, 66, 67, 66, 65, 64, 63, 64, 65, 66, 67, 66, 65, 64, 63, 64, 65],
        dt = 10, d = 4, rule = "PID"
Output: (2.54647909, 80.0, 1.52788745, 0.03819719, 15.27887454)
Explanation: hi = 67, lo = 63, so mid = 65 and a = 2. The upward crossings are at
indices 8 and 16 (64 -> 65), so Tu = 8 * 10 = 80 s. Ku = 16 / (2 * pi) = 2.546 kW/°C;
Kp = 0.6 * Ku, Ti = 40 s, Td = 10 s.

Input:  temps = [20.0, 20.0, 20.0], dt = 1, d = 5, rule = "PI"
Output: None

Constraints

  • rule is "P", "PI" or "PID"
  • answers are compared with a tolerance of 1e-6; do not round

Goals

  • Measure the amplitude and the period of a steady oscillation from samples
  • Estimate the ultimate gain from a relay test with Ku = 4d / (pi * a)
  • Turn the ultimate gain and period into PID gains with a stated table
Starting Python…