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>
54 lines
1.9 KiB
Matlab
54 lines
1.9 KiB
Matlab
function u = ctrl_operation_lqr(t, x, plant, ref)
|
|
% CTRL_OPERATION_LQR Full-state feedback for operation mode.
|
|
%
|
|
% u = -K * (x - x_op), K from LQR on (A, B) at x_op.
|
|
%
|
|
% Advantages over ctrl_operation (plain P on T_avg):
|
|
% - Damps the fast neutronics and the slow thermal response jointly.
|
|
% - Adds NO state (K is 1x10, feedback is memoryless).
|
|
% - Closed-loop A_cl = A - B*K is trivially propagable for reachability.
|
|
%
|
|
% Q/R are persistently cached on the first call. If the caller mutates
|
|
% plant after the first invocation, gains become stale — clear `persistent`
|
|
% by restarting MATLAB. That's a reach-analysis bookkeeping issue, not a
|
|
% runtime one.
|
|
%
|
|
% Weighting rationale:
|
|
% Q diagonal:
|
|
% n -> 1 (power tracking matters)
|
|
% C1..C6 -> 1e-3 (precursor deviations are informational)
|
|
% T_f -> 1e-2 (care about it but not as much as coolant)
|
|
% T_c -> 1e2 (primary objective)
|
|
% T_cold -> 1 (secondary but consequential)
|
|
% R = 1e6 (discourage large rod movements — one Kp of |u| ~ 1e-3)
|
|
%
|
|
% Inputs:
|
|
% t, x, plant, ref - standard signature. ref is unused; the setpoint
|
|
% is baked in as x_op. If you want to track a
|
|
% different operating point, regenerate K there.
|
|
|
|
persistent K x_op_cached
|
|
|
|
if isempty(K)
|
|
x_op_cached = pke_initial_conditions(plant);
|
|
[A, B, ~] = pke_linearize(plant, x_op_cached, 0, plant.P0);
|
|
|
|
Q = diag([1, ...
|
|
1e-3, 1e-3, 1e-3, 1e-3, 1e-3, 1e-3, ...
|
|
1e-2, 1e2, 1]);
|
|
R = 1e6;
|
|
|
|
% MATLAB's lqr requires Control System Toolbox. Fall back to
|
|
% icare (in base MATLAB from R2019a) if lqr is unavailable.
|
|
try
|
|
K = lqr(A, B, Q, R);
|
|
catch
|
|
[~, ~, K_ric] = icare(A, B, Q, R);
|
|
K = K_ric;
|
|
end
|
|
end
|
|
|
|
u = -K * (x - x_op_cached);
|
|
|
|
end
|