Covers Smith predictor parameter identification (C, M, L, Td) from log data, model-plant replay verification, and controller performance metrics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NSo8R6GjoBQdStB3j67zSs
3.7 KiB
Temperature controller calibration
Controller overview
components/pid/temp_controller_smith.py implements a Smith predictor. Each tick it computes:
theta_ist = theta_ist_model + (theta_ist_plant − theta_ist_model_delay)
theta_ist_model comes from a fast internal Pot (transport delay Td = 0);
theta_ist_model_delay from a second Pot with the full configured Td.
The correction term (theta_ist_plant − theta_ist_model_delay) removes the dead
time from the feedback path.
The plant model (components/plant/pot.py) integrates:
temp += (delayed_power_in − L·M·(temp − theta_amb)) / (M·C) · dt
Four parameters must be calibrated:
| Parameter | Unit | Meaning |
|---|---|---|
| C | J/(kg·K) | Specific thermal capacity |
| M | kg | Mass of pot + water + grain |
| L | W/(kg·K) | Heat loss coefficient |
| Td | s | Transport (heater-to-sensor) delay |
1. Verify model-plant match: replay simulation
Feed the recorded power_eff from a log file into a fresh Pot instance
with the same parameters and compare the simulated temperature to temp_ist.
from components.plant.pot import Pot
pot = Pot(dt=1.0)
pot.set_plant_params({'C': C, 'M': M, 'L': L, 'Td': Td})
pot.set_ambient_temperature(theta_amb)
pot.initial(samples[0]['temp_ist'])
sim_temp = []
for s in samples:
pot.set_power(s['power_eff'])
pot.process()
sim_temp.append(pot.get_temperature())
Plot sim_temp (model) against temp_ist (real) and the residual
temp_ist − sim_temp. What divergence tells you:
| Symptom | Likely cause |
|---|---|
| Ramp slopes differ | C·M wrong |
| Phase shift between power step and temperature rise | Td wrong |
| Wrong equilibrium temperature during HOLD | L wrong |
| Residual grows over a long run | Model drift / L temperature-dependent |
2. Parameter identification from log data
Td — transport delay
Cross-correlate power_eff with temp_ist. The lag at peak correlation is the
actual Td. Alternatively, find a sharp power step (start of a ramp) and measure
the visible delay before temp_ist begins rising.
L — heat loss coefficient
At steady-state HOLD, d(temp)/dt ≈ 0, so all input power compensates losses:
P_hold = L · M · (T − theta_amb)
→ L = P_hold / (M · (T − theta_amb))
Repeat across hold phases at different temperatures and fit a line through
(T − theta_amb) vs P_hold for a more robust estimate.
C — specific heat capacity
During a ramp where heat loss is small relative to input power:
C ≈ power_eff / (M · rate_ist_K_per_s)
rate_ist in the log is K/min; divide by 60 to get K/s. Use a mid-ramp window
where power_eff and rate_ist are both stable.
3. Controller performance metrics
These can be read directly from the log without re-simulation:
| Metric | How to compute |
|---|---|
| Overshoot | max(temp_ist) − temp_soll after each setpoint step |
| Settling time | First time ` |
| Steady-state error | Mean of temp_soll − temp_ist during HOLD phase |
| Rate tracking error | rate_ist − rate_soll during RAMP |
Smith predictor correction signal
The term theta_ist_plant − theta_ist_model_delay is the Smith correction; a
growing correction signal indicates model drift. This is not currently written to
the log. To observe it, log theta_ist_model and theta_ist_model_delay from
temp_controller_smith.py alongside the existing fields.
4. Suggested addition to analyze_log.py
A replay panel added to utils/analyze_log.py would show:
temp_ist(blue) vssim_temp(red dashed) — model accuracy at a glance- Residual
temp_ist − sim_tempin a separate subplot — reveals systematic parameter errors vs noise floor