Full toolchain port. Numerical equivalence verified against MATLAB:
- main_mode_sweep.jl: every mode's final state matches MATLAB to 3-4 dp
- reach_operation.jl: per-halfspace margins match MATLAB exactly
- barrier_lyapunov.jl: per-halfspace bounds match (best Qbar from sweep
yields max|dT_c| = 33.228 K either side)
- barrier_compare_OL_CL.jl: OL gamma 1.038e13, CL gamma 1.848e4
matching the MATLAB result; LQR helps by ~20,000x on every halfspace.
Phase summary:
Phase 1: pke_solver.jl, plot_pke_results.jl (Plots.jl), main_mode_sweep.jl
Phase 2: reach_linear.jl, reach_operation.jl, barrier_lyapunov.jl,
barrier_compare_OL_CL.jl, load_predicates.jl
Phase 3 (this commit): delete plant-model/ entirely, delete reach
code from reachability/ keeping predicates.json + docs,
git mv julia-port/ -> code/, update root README + CLAUDE,
write code/CLAUDE.md and code/README.md, update reach
README + WALKTHROUGH file paths, journal preamble note
that pre-port entries reference MATLAB paths.
Why now: prompt-neutron stiffness in nonlinear reach made it clear we
need TMJets, which is Julia. Already had the Julia plant model
working and matching MATLAB. Two languages = two sources of truth =
two places to drift. One language, one truth.
Manifest.toml gitignored. .mat results gitignored.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
38 lines
1.2 KiB
Julia
38 lines
1.2 KiB
Julia
"""
|
|
pke_linearize(plant; x_star=nothing, u_star=0.0, Q_star=nothing)
|
|
|
|
Numerical Jacobians via central finite differences. Returns
|
|
`(A, B, B_w, x_star, u_star, Q_star)` such that for small (dx, du, dw):
|
|
|
|
dx/dt ≈ A dx + B du + B_w dw, where w = Q_sg.
|
|
|
|
Defaults: `x_star` = operating-point steady state, `u_star = 0`,
|
|
`Q_star = P0`.
|
|
"""
|
|
function pke_linearize(plant; x_star=nothing, u_star=0.0, Q_star=nothing)
|
|
x_star === nothing && (x_star = pke_initial_conditions(plant))
|
|
Q_star === nothing && (Q_star = plant.P0)
|
|
|
|
n = length(x_star)
|
|
eps_rel = 1e-6
|
|
eps_abs = 1e-8
|
|
|
|
f = (x, u, w) -> pke_th_rhs(x, 0.0, plant, t -> w, u)
|
|
|
|
A = zeros(n, n)
|
|
for k in 1:n
|
|
h = max(eps_rel * abs(x_star[k]), eps_abs)
|
|
xp = copy(x_star); xp[k] += h
|
|
xm = copy(x_star); xm[k] -= h
|
|
A[:, k] = (f(xp, u_star, Q_star) - f(xm, u_star, Q_star)) ./ (2h)
|
|
end
|
|
|
|
h = max(eps_rel * abs(u_star), eps_abs)
|
|
B = (f(x_star, u_star + h, Q_star) - f(x_star, u_star - h, Q_star)) ./ (2h)
|
|
|
|
h = max(eps_rel * abs(Q_star), 1.0)
|
|
B_w = (f(x_star, u_star, Q_star + h) - f(x_star, u_star, Q_star - h)) ./ (2h)
|
|
|
|
return A, B, B_w, x_star, u_star, Q_star
|
|
end
|