predicates.json is the single source of truth for concretizing the
FRET-spec predicates (t_avg_above_min, t_avg_in_range, p_above_crit,
inv1_holds, inv2_holds) as polytopes {x : A x <= b}. Until now these
were abstract booleans in the synthesis spec; reach analysis
re-invented ad-hoc thresholds that weren't tied to the spec. Closes
the Thrust-1-meets-Thrust-3 seam.
T_standby now defined as T_c0 - 60 F = 275 C (from user review).
Replaces the earlier simplification where shutdown IC held all temps
at T_cold0. 275 C is inside the model's +/-50 C trust region around
operating point and above coolant saturation at reduced pressure.
load_predicates.m in MATLAB reads the JSON and resolves rhs_expr
strings (which reference plant-derived constants like T_c0, T_cold0,
T_standby) into numeric bounds. Returns per-predicate (A_poly, b_poly)
plus a constants struct.
main_mode_sweep.m now pulls T_standby from predicates and uses it
for shutdown + heatup ICs. Heatup horizon extended to 90 min to
cover the wider 60 F -> operating range at 28 C/hr tech-spec limit.
reach_operation.m reads delta_safe_Tc from the t_avg_in_range
halfspace instead of hardcoding +/-5 K. Current concretization is
+/-2.78 C (~5 F); LQR reach still shows 28x margin.
inv1_holds and inv2_holds are marked PLACEHOLDER in the JSON —
engineering best guesses, not derived from a specific plant's tech
specs or a DNBR correlation. Revisit before thesis defense.
Hacker-Split: single-source concretization for FRET predicates,
end seam with reach.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
2.8 KiB
Matlab
74 lines
2.8 KiB
Matlab
function pred = load_predicates(plant)
|
|
% LOAD_PREDICATES Read predicates.json and resolve rhs_expr into numbers.
|
|
%
|
|
% Each halfspace entry in the JSON stores rhs_expr as a string because
|
|
% several of the bounds are defined relative to plant-derived constants
|
|
% (T_c0, T_cold0, T_standby). We evaluate those expressions here in a
|
|
% controlled workspace that exposes exactly those names plus the
|
|
% derived offsets from the JSON.
|
|
%
|
|
% Returns a struct `pred` with one field per predicate, each a struct
|
|
% holding an n_hs x 10 matrix A_poly and an n_hs x 1 vector b_poly such
|
|
% that the predicate is { x : A_poly * x <= b_poly }.
|
|
%
|
|
% Also returns:
|
|
% pred.constants - a struct with T_c0, T_cold0, T_f0, T_standby, etc.
|
|
%
|
|
% Usage:
|
|
% plant = pke_params();
|
|
% pred = load_predicates(plant);
|
|
% A = pred.t_avg_in_range.A_poly; % 2 x 10
|
|
% b = pred.t_avg_in_range.b_poly; % 2 x 1
|
|
% is_in = all(A * x <= b); % predicate check on state x
|
|
|
|
here = fileparts(mfilename('fullpath'));
|
|
raw = fileread(fullfile(here, 'predicates.json'));
|
|
J = jsondecode(raw);
|
|
|
|
% --- Constants used in rhs_expr evaluations ---
|
|
T_c0 = plant.T_c0; %#ok<NASGU>
|
|
T_f0 = plant.T_f0; %#ok<NASGU>
|
|
T_cold0 = plant.T_cold0; %#ok<NASGU>
|
|
T_standby_offset_C = J.derived.T_standby_offset_C;
|
|
T_standby = T_c0 + T_standby_offset_C; %#ok<NASGU>
|
|
|
|
pred.constants = struct( ...
|
|
'T_c0', plant.T_c0, ...
|
|
'T_f0', plant.T_f0, ...
|
|
'T_cold0', plant.T_cold0, ...
|
|
'T_standby', T_standby, ...
|
|
'T_standby_offset_C', T_standby_offset_C, ...
|
|
'T_standby_offset_F', J.derived.T_standby_offset_F, ...
|
|
't_avg_in_range_halfwidth_C', J.derived.t_avg_in_range_halfwidth_C, ...
|
|
'p_above_crit_threshold_n', J.derived.p_above_crit_threshold_n);
|
|
|
|
% --- Loop over predicates, build A/b matrices ---
|
|
names = fieldnames(J.predicates);
|
|
for k = 1:numel(names)
|
|
name = names{k};
|
|
entry = J.predicates.(name);
|
|
hs_list = entry.halfspaces;
|
|
|
|
% jsondecode returns a struct array if entries are uniform, else cell.
|
|
if iscell(hs_list)
|
|
n_hs = numel(hs_list);
|
|
get_hs = @(i) hs_list{i};
|
|
else
|
|
n_hs = numel(hs_list);
|
|
get_hs = @(i) hs_list(i);
|
|
end
|
|
|
|
A_poly = zeros(n_hs, 10);
|
|
b_poly = zeros(n_hs, 1);
|
|
for i = 1:n_hs
|
|
hs = get_hs(i);
|
|
A_poly(i, hs.state_index) = hs.coeff;
|
|
b_poly(i) = eval(hs.rhs_expr); %#ok<EVLDF>
|
|
end
|
|
|
|
pred.(name).A_poly = A_poly;
|
|
pred.(name).b_poly = b_poly;
|
|
pred.(name).meaning = entry.meaning;
|
|
end
|
|
end
|