PWR-HYBRID-3/reachability
Dane Sabo a20d2a05e9 predicates: split operational deadbands from hard safety limits
Previously conflated two different kinds of constraint:
  - operational deadbands (|T_c - T_c0| <= 5 F) used by the DRC for mode
    transitions. Symmetric bands around setpoint. Violating these is an
    operator/operational issue, not a safety issue.
  - safety limits (T_f <= 1200 C, T_c <= 320 C, n <= 1.15, etc.) are
    hard one-sided halfspaces corresponding to physical damage mechanisms
    or reactor-trip setpoints. THESE are what a safety barrier/reach must
    discharge.

predicates.json now has three groups:
  - operational_deadbands (t_avg_above_min, t_avg_in_range, p_above_crit)
  - safety_limits (fuel_centerline, t_avg_high_trip, t_avg_low_trip,
    n_high_trip, n_low_operation, cold_leg_subcooled)
  - mode_invariants (inv1_holds, inv2_holds as conjunctions of safety_limits)

reach_operation.m and barrier_lyapunov.m both now report halfspace-by-
halfspace margins against inv2_holds. Attributable failure analysis:
we can see WHICH limit is tightest.

Reach tube (under +/-15% Q_sg load): passes all 6 safety halfspaces.
Tightest margin is n_high_trip at +0.138 (12% from trip). Temperature
directions have 10-870 K margin.

Lyapunov barrier (same): fails all 6. Worst is n_high_trip with -2365
margin — the ellipsoid says n could deviate by +/-2364, which is
physically meaningless. Anisotropy cost made visible per-direction.
Motivates SOS / polytopic barriers for the thesis chapter.

load_predicates.m now returns .operational_deadbands, .safety_limits,
and .mode_invariants. Existing callers that only used .constants or
.t_avg_in_range still work because those live under the old keys.

Hacker-Split: user caught that the barrier was checking the wrong
invariant; safety limits != operating deadband. Restructured so the
proof target matches the physical claim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:04:40 -04:00
..

Reachability

Continuous-mode verification for the PWR_HYBRID_3 hybrid controller.

Soundness status: APPROXIMATE

The current reach_operation.m result is not a sound reach tube for the physical plant. It is a sound over-approximation of the linearized closed-loop system (A_cl = A - BK around x_op) under bounded disturbance. The linear model is itself an approximation of the nonlinear plant (../plant-model/pke_th_rhs.m), and that approximation error is not currently bounded or inflated into the tube.

Two paths to upgrade to a sound result:

  1. Nonlinear reach directly — CORA nonlinearSys, JuliaReach BlackBoxContinuousSystem, or equivalent. More expensive but the honest answer.
  2. Linear reach + Taylor-remainder inflation — compute an upper bound on ||f_nl(x, u) - (A x + B u)|| over the reach set (via Hessian norm estimate on each component of f_nl) and inflate the linear tube by that bound. Less expensive, still rigorous.

Both are thesis-blocking for any safety claim. Deferred only until the per-mode plumbing is solid; it is not a "nice to have".

The current 5-orders-of-margin buffer (reach envelope ~0.03 K against a 5 K safety band) means linearization error would have to be huge to invalidate the conclusion, but that is vibes, not a proof.

  • Saturation semantics. ctrl_heatup.m uses sat(u, u_min, u_max). Saturation is formally a 3-mode piecewise-affine system. For heatup reach this has to be handled as (a) hybrid locations, or (b) proven dormant via reach on u_unsat. Not modeled in the current artifacts (operation-mode LQR saturation is dormant in practice but the proof is implicit).
  • Parametric uncertainty in α_f, α_c. Real plants have α drift with burnup (~20%), boron (α_c ranges 10×), xenon. The feedback-linearization in ctrl_heatup.m assumes exact α; a robust treatment would make α an interval and propagate parametric reach. Currently idealized — flag in the chapter.

What's here

Per-mode only. Following the compositionality argument in the thesis: verify each continuous mode separately, let the DRC handle discrete switching. Current focus: operation mode under LQR feedback.

What's here

  • linearization_at_op.mat — A, B, B_w and reference point, generated by ../plant-model/test_linearize.m.
  • reach_linear.m — box-zonotope propagation of the closed-loop linear model under bounded disturbance. Pure MATLAB, no external toolbox.
  • barrier_lyapunov.m — Lyapunov-ellipsoid barrier certificate for the closed-loop linear system. Solves a Lyapunov equation, reports the smallest sub-level set containing the initial set and closed under the disturbance.
  • reach_operation.m — end-to-end operation-mode reach: linearize at x_op, compute LQR gain, propagate zonotope reach set, check against the t_avg_in_range predicate.
  • figures/ — generated plots.

Running

From MATLAB:

cd reachability
reach_operation     % computes reach set + plots
barrier_lyapunov    % solves Lyapunov, reports invariant ellipsoid

Tool choice

Currently using a hand-rolled zonotope reach because:

  • Avoids a ~0.5 GB CORA install for a first-pass result.
  • Linear reach with bounded disturbance has a clean analytic form (matrix exponential on the state, integral of e^(A(t-s))·B_w·w ds for the disturbance).
  • Stays inside MATLAB, which is where the plant model lives.

If we need nonlinear reach (and we will, for non-LQR controllers or larger reach sets where linearization error matters), the planned options are CORA (MATLAB) or JuliaReach (port the plant to Julia).

What this does NOT do yet

  • Any sound reach tube (see top of this file).
  • Nonlinear reach for the original P controller on operation.
  • Heatup reach (ramped reference makes x* time-varying — needs trajectory-LQR or a different formulation, and the saturation semantics need to be made explicit).
  • Shutdown, scram, initialization reach.
  • Hybrid-system level verification (mode switching validity).
  • Parametric robustness to α_f, α_c drift.