|
STAR
Cal STAR — firmware, DAQ server, and engine design
|
Variables | |
| float | STUDY_LOCKUP_PSIA = 564.7 |
| feedtwin = pytest.importorskip("feedtwin", reason="lib/feedtwin is not installed") | |
| ROOT = Path(__file__).resolve().parents[1] | |
| str | BASELINE = ROOT / "docs" / "layerx" / "baseline-2026-10-07.json" |
| str | HE = "copv_study_he" |
| str | SLOW = "1" |
| float | BORE = 10.92e-3 |
| float | AREA = math.pi * BORE ** 2 / 4.0 |
Layer X chug margin on the drawing's basis (engine/layerx/diag/stability.py; audit D7, 9.4). What these check, and against what: * **The config basis is today's replay, exactly.** The diagnostic re-solves EngineDesign's chamber at the replay's own points and geometry; its gate must equal the replay's ``chug_margin`` to the last bit, or it is not the same model and "other basis" comparisons mean nothing. Checked on a short real replay here, and on the LE4 golden burn (1.398) when ``LAYERX_GOLDEN=1``. * **The drawing basis takes the drawing's numbers and nothing else.** Its inertance is checked against sum(L)/A by hand from the shipped helium drawing (0.14 m and 0.9644 m of 10.92 mm tube); its resistance against 2 (line drop + dump) / mdot by hand at the same point. A drawing and a run that declare nothing for it change nothing. Slow cases (one LE4 helium burn, or two for the time-step check) run only with ``LAYERX_GOLDEN=1``.
|
protected |
One stream, regulator off: L(iw) = K_c e^(-iw tau) / ((1 + iw theta)(Z + iw I)). Phase and magnitude both fall monotonically with w, so the worst negative-axis crossing is the first: w tau + atan(w theta) + atan(w I/Z) = pi, and GM = sqrt(1 + (w theta)^2) sqrt(Z^2 + (w I)^2) / K_c. (The constant-lag chug loop with the line's inertia: Summerfield, J. ARS 21(5), 1951.)
Definition at line 508 of file test_layerx_stability.py.
Referenced by test_chug_with_line_inertance_against_the_closed_form().
|
protected |
The stability inputs the block used at replay time ``t``, rebuilt.
Definition at line 363 of file test_layerx_stability.py.
Referenced by test_gate_frequency_follows_the_nominal_when_it_sets_the_gate(), test_nyquist_is_the_models_open_loop_by_hand(), and test_tau_sweep_contains_the_gate_and_the_nominal().
|
protected |
Definition at line 520 of file test_layerx_stability.py.
Referenced by test_chug_on_the_closed_form_boundary_reads_neutral(), and test_chug_with_line_inertance_against_the_closed_form().
|
protected |
One continuous start sampled at ``dt``: both mains open linearly over 50 ms (the drawing's travel), the line exits climbing from 45 % to full with the valve, then a slow rise of 10 psi/s, as the helium burn's do. The same function of time at every ``dt``.
Definition at line 257 of file test_layerx_stability.py.
Referenced by test_start_window_removes_the_dt_dependence().
|
protected |
Definition at line 48 of file test_layerx_stability.py.
Referenced by le4().
|
protected |
A short steady firing at the LE4 helium burn's first-step state (t = 0.05 s of the golden run): line exits 557.0 / 541.5 psia, tank outlets 574.9 / 574.7 psia.
Definition at line 76 of file test_layerx_stability.py.
Referenced by short().
| test_layerx_stability.golden | ( | le4 | ) |
Definition at line 603 of file test_layerx_stability.py.
| test_layerx_stability.le4 | ( | ) |
Definition at line 56 of file test_layerx_stability.py.
References _script().
| test_layerx_stability.prep | ( | le4 | ) |
LE4 on the helium hot-fire drawing, prepared (no burn).
Definition at line 63 of file test_layerx_stability.py.
| test_layerx_stability.short | ( | prep | ) |
A real EngineDesign erosion replay of the short firing: ``{"series", "replay"}``.
Definition at line 93 of file test_layerx_stability.py.
References _series().
| test_layerx_stability.test_acoustics_failure_does_not_take_the_margin | ( | prep, | |
| short, | |||
| monkeypatch ) |
A propellant CoolProp cannot state loses that side's line rows and says so; the chug margin (the block's reason to exist) is unchanged.
Definition at line 488 of file test_layerx_stability.py.
| test_layerx_stability.test_block_follows_the_data_contract | ( | prep, | |
| short ) |
DATA-CONTRACT section 3 ``stability``: the keys, plain JSON (no NaN), a ``model`` block whose every input says where it came from, and a failure that is reported, never raised.
Definition at line 573 of file test_layerx_stability.py.
| test_layerx_stability.test_chug_on_the_closed_form_boundary_reads_neutral | ( | f0 | ) |
Put the loop exactly on its stability boundary at f0 (tau* and K_c* from the closed form, LE4's fuel inertance): the code must read GM = 1 at f0.
Definition at line 550 of file test_layerx_stability.py.
References _one_stream().
| test_layerx_stability.test_chug_with_line_inertance_against_the_closed_form | ( | I | ) |
The gate's own solver (EngineDesign's ``_chug_fast``: the compiled kernel when it is on, and the Python ``chug_margin_fast``) on LE4's fuel side with the line's inertance, against the closed form: GM within 0.5 % (the 200-point grid's interpolation), frequency within 1 %. At LE4's 10297 1/m the inertance moves GM by +25 %, so a dropped I*s term cannot pass.
Definition at line 530 of file test_layerx_stability.py.
References _closed_form(), and _one_stream().
| test_layerx_stability.test_config_basis_reproduces_the_replay_exactly | ( | prep, | |
| short ) |
The config basis is the replay's own chug gate, re-evaluated: equal to the last bit.
Definition at line 123 of file test_layerx_stability.py.
| test_layerx_stability.test_coolprop_liquid_sound_speeds | ( | ) |
LOX at 90 K / 555 psia and ethanol at 293.15 K / 540 psia, straight from CoolProp (audit 9.4 section 4: 1150.2 kg/m3, 923 m/s; 792.6 kg/m3, 1182 m/s).
Definition at line 436 of file test_layerx_stability.py.
| test_layerx_stability.test_drawing_basis_on_a_drawing_that_declares_nothing_changes_nothing | ( | prep, | |
| short ) |
No line on the path and no outlet pressures: the drawing basis is the config basis.
Definition at line 163 of file test_layerx_stability.py.
| test_layerx_stability.test_drawing_basis_streams_by_hand | ( | prep, | |
| short ) |
At one point, the drawing basis's streams carry the drawing's inertance and R = 2 (tank outlet - line exit + exit dump) / mdot, every other input unchanged.
Definition at line 135 of file test_layerx_stability.py.
| test_layerx_stability.test_drawing_inertance_is_sum_L_over_A_by_hand | ( | prep | ) |
Sum of L/A over the drawn lines tank -> injector, each on its own bore. Hand: LOX l_ox1 + l_ox2 = 0.07 + 0.07 m, fuel l_fu1 + l_fu2 = 0.9144 + 0.05 m, all 10.92 mm tube (audit 9.4 section 2: 1495 and 10297 1/m).
Definition at line 106 of file test_layerx_stability.py.
| test_layerx_stability.test_eroded_on_an_uneroded_chamber_changes_nothing | ( | prep, | |
| short ) |
Turned on against a chamber that has not eroded (the replay's geometry set to the design's), ``eroded=True`` gives exactly the design-point answer.
Definition at line 215 of file test_layerx_stability.py.
| test_layerx_stability.test_eroded_reproduces_the_solvers_own_eroded_chug | ( | prep, | |
| short ) |
``eroded=True`` is the coupled solver's ``chug_eroded_geometry=True``, re-evaluated: the replay run with that flag and this diagnostic agree to the last bit, so the geometry the diagnostic rebuilds from the replay's columns is the geometry the solver had.
Definition at line 200 of file test_layerx_stability.py.
| test_layerx_stability.test_eroded_throat_raises_the_margin_by_the_chamber_gain | ( | prep, | |
| short ) |
A larger throat lowers the chamber gain K_c = c*/A_t and shortens theta_c = L* c*/(R T), and the loop gain falls: +4 % of throat area must raise the margin. At the same point the eroded chamber gain is the design's times A_t0/A_t, by hand.
Definition at line 232 of file test_layerx_stability.py.
| test_layerx_stability.test_feed_override_is_opt_in_and_validated | ( | prep, | |
| short ) |
``build_stability_inputs(feed=None)`` is the old call; a bad value is refused, not clipped.
Definition at line 182 of file test_layerx_stability.py.
| test_layerx_stability.test_gate_frequency_follows_the_nominal_when_it_sets_the_gate | ( | prep, | |
| short ) |
chug_band's minimum includes the nominal point, but its ``at_min_fraction`` is the band grid's argmin. When the nominal lag is lower than every band sample (here: a band that ends short of the nominal fraction, on a margin that falls with the lag), the gate *is* the nominal and its frequency is the nominal's -- not the frequency at the band's lowest sample.
Definition at line 328 of file test_layerx_stability.py.
References _inputs_at(), and min.
| test_layerx_stability.test_golden_eroded_raises_burnout | ( | golden | ) |
Audit 9.4 section 3: unfreezing A_t and L* adds ~+0.004 at the minimum and +0.08 at burnout on [doc] (5.7 % throat growth). LE4's YAML grows the throat 4.0 %, so burnout rises ~+0.06.
Definition at line 618 of file test_layerx_stability.py.
| test_layerx_stability.test_golden_start_window_removes_the_dt_dependence | ( | golden, | |
| le4 ) |
The audit's measurement (5.1): the replay's minimum reads 1.367 / 1.161 at 50 / 5 ms on [doc] (1.398 / 1.191 on the YAML). Graded from the first fully-open step, a 5 ms burn and the 50 ms burn agree within 0.01.
Definition at line 630 of file test_layerx_stability.py.
| test_layerx_stability.test_korteweg_by_hand | ( | ) |
a = a0 / sqrt(1 + rho a0^2 D / (E e)): LOX in 1/2 x 0.035 in. 316 tube, 0.981 GPa liquid, 10.92 mm bore, 0.889 mm wall, 193 GPa -> factor 1.031, 896 m/s (audit 9.4 section 4).
Definition at line 448 of file test_layerx_stability.py.
| test_layerx_stability.test_line_acoustics_on_the_helium_drawing | ( | prep, | |
| short ) |
The fuel path (0.9644 m) quarter-wave sits at ~296 Hz and LOX's (0.14 m) at ~1600 Hz, 8-70x above chug: not near it. Put the chug band at the fuel's quarter-wave and it is flagged. The drawing's copied wall thickness is flagged.
Definition at line 464 of file test_layerx_stability.py.
| test_layerx_stability.test_nyquist_is_the_models_open_loop_by_hand | ( | prep, | |
| short ) |
L(iw) = K_c/(theta iw + 1) * sum exp(-iw tau_k)/(I_k iw + R_k + 2 eta_k Pc/mdot_k), written out from each stream's numbers (regulator not modelled), at the lag that sets the gate. Where it crosses the negative real axis, |L| = 1/gate and the frequency is the gate's.
Definition at line 380 of file test_layerx_stability.py.
References _inputs_at(), and max.
| test_layerx_stability.test_start_window_by_hand | ( | prep, | |
| short ) |
Window = the mains' travel (the drawing's 0.05 s) + 3 line time constants, the longest of tau = (sum L/A) mdot / (2 (tank outlet - Pc)) by hand: the fuel's, ~4.9 ms (audit 9.5).
Definition at line 279 of file test_layerx_stability.py.
| test_layerx_stability.test_start_window_from_the_recorded_valve_state | ( | prep, | |
| short ) |
With ``result.network`` (DATA-CONTRACT 2) the mains' recorded opening sets t_open: the first step both are open after one was seen short of open. feedtwin's trace reads a valve with no signal as fully open (``network_trace._opening``), so a recording that is open from its first step proves nothing and the drawing's travel rule is kept -- never a window that starts before Fire.
Definition at line 298 of file test_layerx_stability.py.
References max.
| test_layerx_stability.test_start_window_removes_the_dt_dependence | ( | prep | ) |
The same start sampled at 5 and 50 ms: the minimum over every step (the start included) moves with where the samples fall in the valve ramp; the graded minimum does not.
Definition at line 346 of file test_layerx_stability.py.
References _ramp_series().
| test_layerx_stability.test_tau_sweep_contains_the_gate_and_the_nominal | ( | prep, | |
| short ) |
The sweep is the band, densely: at the band's own five fractions it equals chug_band's gain margins exactly, at the nominal fraction the nominal margin, and its minimum is at most the gate.
Definition at line 413 of file test_layerx_stability.py.
References _inputs_at().
| float test_layerx_stability.AREA = math.pi * BORE ** 2 / 4.0 |
Definition at line 45 of file test_layerx_stability.py.
| str test_layerx_stability.BASELINE = ROOT / "docs" / "layerx" / "baseline-2026-10-07.json" |
Definition at line 39 of file test_layerx_stability.py.
| float test_layerx_stability.BORE = 10.92e-3 |
Definition at line 44 of file test_layerx_stability.py.
| test_layerx_stability.feedtwin = pytest.importorskip("feedtwin", reason="lib/feedtwin is not installed") |
Definition at line 34 of file test_layerx_stability.py.
| str test_layerx_stability.HE = "copv_study_he" |
Definition at line 40 of file test_layerx_stability.py.
| test_layerx_stability.ROOT = Path(__file__).resolve().parents[1] |
Definition at line 38 of file test_layerx_stability.py.
| str test_layerx_stability.SLOW = "1" |
Definition at line 41 of file test_layerx_stability.py.
| float test_layerx_stability.STUDY_LOCKUP_PSIA = 564.7 |
Definition at line 32 of file test_layerx_stability.py.