Dane Sabo d2997c2861 plant-model: add shutdown/heatup/scram controllers and LQR, linearize
Fill out the DRC mode set with ctrl_shutdown (u = -5*beta), ctrl_scram
(u = -8*beta), and ctrl_heatup (feedback-linearizing P on ramped T_avg
reference, saturated u, no integrator). Add ctrl_operation_lqr as a
full-state-feedback counterpart to ctrl_operation — K cached, closed-loop
essentially perfect under the 100%->80% Q_sg step where plain P has ~5F
overshoot.

Add pke_linearize for numerical (A, B, B_w) Jacobians at any operating
point; test_linearize confirms ~4e-4 rel err vs nonlinear sim for a
5% Q_sg step. Extend pke_solver with an optional x0 argument so each
mode can start from a plausible IC.

main_mode_sweep.m exercises all five modes back-to-back and saves the
4-panel plots. CLAUDE.md updated with model-validity-range note (trust
region is ~+/-50C around operating point; true cold shutdown is out of
scope for the linear feedback coefficients).

Hacker-Split: build out control layer end-to-end for reachability.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:52:03 -04:00

175 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
Guidance for Claude Code (and any AI agent) working in this subdirectory.
See also: the parent repo's `CLAUDE.md` (living-documentation rule — update
this file when new knowledge is created) and `claude_memory/` for session
notes that haven't yet earned a place here.
## What this is
A 10-state point kinetic equation (PKE) model of a PWR coupled with
lumped-parameter thermal-hydraulics, plus mode-specific continuous
controllers. Implements the *plant* and the *tactical* layer of the HAHACS
methodology — see `../thesis/3-research-approach/approach.tex` sections on
transitory, stabilizing, and expulsory modes.
The model is being developed for hybrid-systems reachability analysis. The
end goal is barrier-certificate and reachability methods (in `../reachability/`)
to prove each continuous mode satisfies its obligations under bounded
`Q_sg(t)` variations.
## Naming convention (thesis-aligned)
Continuous state and control-theory notation matches the thesis:
| Symbol | Meaning |
|---|---|
| `t` | time [s] |
| `x` | continuous state vector, `[n; C1..C6; T_f; T_c; T_cold]` |
| `plant` | parameter struct from `pke_params()` (was `p` — renamed to avoid collision with `p_i` predicates) |
| `u` | control input: external rod reactivity [dk/k] |
| `Q_sg` | bounded disturbance: SG heat removal [W], as a function handle `Q_sg(t)` |
| `ref` | reference/setpoint struct (e.g. `ref.T_avg`) |
`T_avg = T_c` (algebraic alias); `T_hot = 2*T_c - T_cold` (linear coolant
profile assumption).
## Running
From inside MATLAB:
```matlab
main % runs the default closed-loop scenario
```
From a terminal (figures appear as their own windows):
```bash
matlab -nodesktop -nosplash -r "main" # drops at >> prompt; `exit` to quit
matlab -r "main" & # full IDE, backgrounded
matlab -batch "main" # headless sanity check (no figures shown)
```
`main.m` configures the scenario (plant, `Q_sg`, ref, tspan), picks a
controller, and calls `pke_solver`. Tested on MATLAB R2025b; works on any
MATLAB with `ode15s` (R2020b or newer).
## Architecture
```
plant-model/
pke_params.m plant parameters and derived steady state
pke_initial_conditions.m analytic equilibrium x0 from plant
pke_th_rhs.m dynamics: dx/dt = f(t, x, plant, Q_sg, u)
pke_linearize.m numerical (A, B, B_w) at any x_star
pke_solver.m closed-loop driver (optional x0 arg)
plot_pke_results.m 4-panel results plot
load_profile.m canned Q_sg demand shapes
main.m entry point — single-mode scenarios
main_mode_sweep.m runs all DRC modes back-to-back
test_linearize.m sanity-check Jacobians vs nonlinear sim
controllers/
ctrl_null.m u = 0 (baseline, no feedback)
ctrl_shutdown.m hot standby: u = -5*beta (constant)
ctrl_heatup.m ramp T_avg: feedback lin. + P on ramp, saturated u
ctrl_operation.m stabilizing: P on T_avg
ctrl_operation_lqr.m full-state LQR around x_op (persistent-cached K)
ctrl_scram.m emergency: u = -8*beta (constant)
```
**Controller contract:**
```matlab
u = ctrl_<mode>(t, x, plant, ref)
```
Pure function. Returns scalar `u` (external rod reactivity in `dk/k`). All
four signature args are required even if unused — lets the solver swap
controllers by function handle without caring which one it is.
**Solver contract:**
```matlab
[t, X, U] = pke_solver(plant, Q_sg, ctrl_fn, ref, tspan)
```
Builds the closed-loop RHS internally, calls `ode15s`, then reconstructs the
control trajectory `U` by re-evaluating `ctrl_fn` at each returned time step.
For event-driven or hysteretic controllers, this reconstruction may miss
interior solver evaluations — revisit if / when that matters.
## Key design decisions
- **`Q_sg` is the disturbance, never an actuator.** Cold leg temperature is
a dynamic state resulting from SG heat removal — the reachability
formulation needs `Q_sg ∈ [Q_min, Q_max]` as a bounded disturbance, not a
control input.
- **`u` is explicit.** `pke_th_rhs` takes `u` directly instead of reading
`p.rho_ext(t)` from the params struct. This decouples plant from
controller and matches the thesis's `f(x, u)` formulation.
- **Controller gains live in the controller file.** Rough-out phase — we'll
lift to a config struct once we're tuning more than one mode. The gain
in `ctrl_operation` (`Kp = 1e-4 /K`) is chosen to roughly double the
effective moderator coefficient, not for precision tracking.
- **`ode15s` is required** because the system is stiff: `Lambda` (~10⁻⁴ s)
vs thermal time constants (~10100 s).
## Conventions
- One function per file, each file has a single responsibility.
- Internal model uses SI (W, kg, °C); all printed/plotted temperatures in °F.
- Reference setpoints in SI (so `ref.T_avg` is in °C).
- Controllers are pure functions — no persistent state. If a mode ever
needs integral action, augment `x` rather than hiding state in globals.
## Model validity range
The feedback coefficients `alpha_f`, `alpha_c` are *linear* slopes taken
about the full-power operating point `(T_f0, T_c0)`. They become
unphysical when extrapolated far from that reference — e.g. at true
cold shutdown (~50 C everywhere), the model predicts ~+5 $ intrinsic
reactivity that real reactors do not exhibit because temperature
coefficients saturate and flip sign in the cold-unborated state.
**Trust range:** roughly ±50 C around the operating point. "Shutdown"
in this demo means hot standby (~290 C, n≈0), not cold shutdown.
Extending to cold-shutdown semantics requires piecewise-linear or
table-lookup temperature coefficients and is out of scope for the
running example.
## For reachability work
- `pke_th_rhs(t, x, plant, Q_sg, u)` is the `ẋ = f(x, u)` with `Q_sg` as the
disturbance `w`. For a given mode, substitute `u = ctrl_<mode>(t, x, plant, ref)`
to get the closed-loop `ẋ = f_cl(x, w)`.
- Use `pke_linearize(plant, x_star, u_star, Q_star)` for `(A, B, B_w)` at
any operating point; returns central-finite-difference Jacobians. The
result at the full-power point is saved to
`../reachability/linearization_at_op.mat` by `test_linearize.m`.
- Safe regions come from the FRET spec's guards (see
`../fret-pipeline/specs/synthesis_config_v3.json`) — these define
`X_entry`, `X_exit`, `X_safe` per the thesis approach. Numerical
predicate thresholds still need to be pinned (see
`../claude_memory/` notes for the discussion).
- Do NOT try to verify the whole hybrid system at once. Pick one mode,
compute its reach set, discharge the per-mode obligation. The
compositionality argument in the thesis is what makes this tractable.
- First reach set is in `../reachability/reach_operation.m` (operation
mode under LQR); a Lyapunov-ellipsoid barrier-cert attempt is in
`../reachability/barrier_lyapunov.m`.
## For control design
- The LQR gain in `ctrl_operation_lqr.m` is cached in a persistent
variable. If you change `Q_lqr` or `R_lqr` or mutate `plant`, restart
MATLAB to clear the cache.
- `ctrl_heatup.m` uses feedback linearization + saturated P. No
integrator on purpose — adding PI would double the plant's intrinsic
thermal-mass integration and make anti-windup a hybrid mode, both
bad for reach.
- Starting heatup from a truly zero-power IC produces a large lag +
power-spike overshoot in the simulation. Physical resolution: the
reactor should be taken critical in shutdown mode (at ~0.1% power)
before DRC transitions to heatup. `main_mode_sweep.m` uses this IC.