Two zones, one shared thermal mass
The plant is deceptively simple: two resistive heaters, two thermistors, one shared thermal mass. Deceptively, because heat from one zone bleeds into the other — push one heater and the neighboring sensor drifts too. Treating the zones as independent single-loop PID problems ignores that coupling; a multivariable controller that models the interaction directly does not.
Finding SMOC
SMOC traces back to a 1977 paper by Bornard and Gauthier on Linear Algebra Governing (LAG) control, later extended into the multivariable predictive framework used industrially by Shell. Rather than treating it as a black-box algorithm, I worked back through that original paper and the SMOC literature that followed to understand the state-space reasoning underneath it before implementing it on hardware — the kind of grounding that makes the controller's behavior predictable instead of mysterious when it's tuned on real thermal dynamics.
Identifying the plant
Before any controller could be tuned, the plant itself had to be measured. I ran pseudo-random binary sequence (PRBS) excitation on both heater channels and logged the thermistor response, which is a standard way to extract a linear dynamic model — including the cross-coupling terms — without needing to derive the heat-transfer physics analytically from geometry and material properties alone.
Sensing and actuation
Each zone runs a 3Ω, 100W resistor as the heating element, switched through an IRFZ44N MOSFET from the ESP32-S3. Temperature feedback comes from NTC thermistors read on a 12-bit ADC and converted through the Beta equation. Getting clean, low-noise readings at that resolution mattered as much as the control law itself — a noisy identification run produces a wrong model no matter how good the controller math is.