STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
engine.layerx.flight Namespace Reference

Classes

class  InlineAscent

Functions

Optional[float] _drawn_length_m (Dict[str, Any] edge)
List[str] _path_to_tank (Any model, str inlet, str tank)
Optional[float] _elevation_m (Dict[str, Any] edge)
List[Dict[str, Any]] line_paths (Dict[str, Any] payload, Any model, Dict[str, str] inlets, Dict[str, str] tanks, Sequence[str] restated)
Optional[str] coolprop_gas (Optional[str] name)
Any _flight_config (Any config, Optional[Dict[str, Any]] timeseries, Dict[str, float] loads, float ambient_pa, Optional[float] pressurant_kg, Optional[float] copv_volume_L, List[str] notes, Optional[str] pressurant_gas=None)
Optional[float] config_dry_kg (Any config)
Optional[Dict[str, Any]] _ceiling (Any config, float apogee_agl, float elevation)
float _axial_drag (Any flight, float t)
float axial_acceleration (Any flight, float t)
Dict[str, Any] _cfg_input (Any section, str field, str unit, str where)
Dict[str, Any] vehicle_stability (Any flight, Any config, Sequence[float] clock)
Dict[str, Any] _stability_or_failure (Any flight, Any config, Sequence[float] clock, Optional[Dict[str, Any]] scalars)
Tuple[float, float, float, Any] _vehicle_terms (Any config, Any drag=None)
Dict[str, Any] inline_specific_force (Any config, Sequence[float] thrust_N, Sequence[float] mdot_total, Sequence[float] t, float liftoff_mass_kg, float ambient_pa, *, Any drag=None, float dt_max=0.01)
Dict[str, Any] liftoff_mass (Any config, Dict[str, float] loads, *, float ambient_pa=101325.0, Optional[float] pressurant_kg=None, Optional[float] copv_volume_L=None, Optional[float] ullage_gas_kg=None, Optional[str] pressurant_gas=None, Optional[float] weighed_kg=None)
Dict[str, Any] fly (Any config, Dict[str, Any] timeseries, Dict[str, float] loads, float ambient_pa, *, Optional[float] pressurant_kg=None, Optional[float] copv_volume_L=None, Optional[float] liftoff_mass_kg=None, Optional[float] ullage_gas_kg=None, Optional[str] pressurant_gas=None)
float schedule_change (Optional[Dict[str, Any]] old, Optional[Dict[str, Any]] new)

Variables

float G0 = 9.80665
int ACCEL_TOLERANCE = 5e-3
int MAX_FLIGHT_PASSES = 4
int TRAJECTORY_POINTS = 240
dict _TO_M = {"m": 1.0, "mm": 1e-3, "cm": 1e-2, "in": 0.0254, "ft": 0.3048}
tuple STABILITY_SOURCE
tuple INLINE_SOURCE

Detailed Description

Phase 6: the burn, flown, and the flight fed back into the burn.

On the stand every liquid column feels one g. In the vehicle it feels the proper acceleration
along the axis (the specific force: thrust less drag over mass, no gravity in it): 8.0-8.25 g at
liftoff and 8.7-9.2 g at burnout on LE4, as flown on 2026-10-02 (docs/layerx/AUDIT.md 9.3). The
tank heads grow with it, and so would the column in each feed line between its tank and the
injector -- but only by the height the drawing gives that line, and no drawing gives any line a
height yet. Flown today, only the tanks' own liquid feels it: +1.1 to +1.6 psi at the injector
inlets. The team's vehicle lines (fuel 4.5 ft, LOX 1 ft) taken as vertical, an upper bound that is
on no drawing, would add +10.7 / +4.1 psi and move O/F 1.518 -> 1.485 (AUDIT 9.3, 7.2).

The coupling is closed by iteration, the same way the throat history is (replay.py):

1. burn on the pad (1 g) until the eroding throat settles: this is the ordinary Layer X result;
2. fly the delivered curve in EngineDesign's flight simulation (RocketPy, ``ui.flight_sim``), and
   read the proper acceleration along the axis at every firing step;
3. burn again with that acceleration applied to every liquid column at each step
   (``Setup.body_acceleration``), fly again, until neither the acceleration history nor the
   throat history moves.

**The feed lines.** The drawing is the feed system: every line's length, bore, fittings and
height come from it, and the feed twin computes the losses from them. Flight adds one thing, the
acceleration on each liquid column, and a line's column is its ``elevation_change`` as drawn (or
as the person restated it). Layer X never writes geometry into the drawing. :func:`line_paths`
reports each tank-to-injector path, its drawn length and the height it states; a path that states
none carries no line head in flight, and the preflight says so.

**The vehicle's tanks.** These come from the drawing. When the drawing and the config disagree
on tank volume, preflight already says so. The drawing's volumes are measured, and the
config's are sized to the load, so the measured ones are used for the feed system. The flight
simulation keeps the config's tanks for the mass and inertia it flies.

Function Documentation

◆ _axial_drag()

float engine.layerx.flight._axial_drag ( Any flight,
float t )
protected
RocketPy's axial aerodynamic force ``R3`` at ``t`` [N], linear between its solution nodes.

RocketPy's own ``Flight.R3`` is a cubic spline over those nodes (rocketpy 1.11 and 1.13 alike),
and the force steps at burnout, where the drag switches from the power-on to the power-off Cd:
the spline rings across the step. On the LE4 helium flight it read -423 N 36 ms before cutoff,
between -646 N (50 ms earlier) and -747 N (at cutoff), while the speed rose: a +3.4 % spike in
the specific force (inline 94.50 m/s^2 against RocketPy's 97.81), which also set the reported
max acceleration. Linear between nodes is bounded by them; elsewhere the two agree to ~0.1 N.

Definition at line 250 of file flight.py.

Referenced by axial_acceleration().

◆ _ceiling()

Optional[Dict[str, Any]] engine.layerx.flight._ceiling ( Any config,
float apogee_agl,
float elevation )
protected

Definition at line 239 of file flight.py.

Referenced by fly().

◆ _cfg_input()

Dict[str, Any] engine.layerx.flight._cfg_input ( Any section,
str field,
str unit,
str where )
protected
A config value for a ``model`` block: ``{value, unit, provenance}``. A value equal to its
schema default says so, with the schema's own description of that default: "the config says
3.35 m" and "nobody measured the rail" are different statements.

Definition at line 313 of file flight.py.

Referenced by inline_specific_force(), and vehicle_stability().

◆ _drawn_length_m()

Optional[float] engine.layerx.flight._drawn_length_m ( Dict[str, Any] edge)
protected
A drawn line's length [m] from its ``length`` parameter, or None if it states none.

Definition at line 65 of file flight.py.

Referenced by line_paths().

◆ _elevation_m()

Optional[float] engine.layerx.flight._elevation_m ( Dict[str, Any] edge)
protected
The height a drawn line climbs in its drawn direction [m], or None if it states none.

Definition at line 106 of file flight.py.

Referenced by line_paths().

◆ _flight_config()

Any engine.layerx.flight._flight_config ( Any config,
Optional[Dict[str, Any]] timeseries,
Dict[str, float] loads,
float ambient_pa,
Optional[float] pressurant_kg,
Optional[float] copv_volume_L,
List[str] notes,
Optional[str] pressurant_gas = None )
protected

Definition at line 161 of file flight.py.

References coolprop_gas().

Referenced by fly(), and liftoff_mass().

◆ _path_to_tank()

List[str] engine.layerx.flight._path_to_tank ( Any model,
str inlet,
str tank )
protected
Branch ids from the tank down to the injector inlet: a breadth-first walk upstream, so a
fill line or vent tee that also meets the path is not mistaken for the feed.

Definition at line 76 of file flight.py.

Referenced by line_paths().

◆ _stability_or_failure()

Dict[str, Any] engine.layerx.flight._stability_or_failure ( Any flight,
Any config,
Sequence[float] clock,
Optional[Dict[str, Any]] scalars )
protected
The contract block, merged over ``flight_report``'s scalar margins (liftoff, rail exit,
burnout), which the Flight tab reads. A block that cannot be computed says why; the flight
stands.

Definition at line 444 of file flight.py.

References vehicle_stability().

Referenced by fly().

◆ _vehicle_terms()

Tuple[float, float, float, Any] engine.layerx.flight._vehicle_terms ( Any config,
Any drag = None )
protected
(nozzle exit area [m^2], body reference area [m^2], pad elevation [m], Cd(M)) of the vehicle
``ui.flight_sim.setup_flight`` builds from ``config``: the same functions, so the inline ascent
and RocketPy fly one vehicle.

Definition at line 600 of file flight.py.

Referenced by engine.layerx.flight.InlineAscent.from_config(), and inline_specific_force().

◆ axial_acceleration()

float engine.layerx.flight.axial_acceleration ( Any flight,
float t )
Proper acceleration along the vehicle axis at ``t`` [m/s^2]: what an accelerometer on it
reads, and what a liquid column feels. The specific force along the axis: net thrust (the
motor's, corrected from its reference pressure to the ambient at the vehicle's altitude) plus
the axial aerodynamic force, over the vehicle's mass. Gravity is not in it, by definition.

Read this way rather than by differentiating the trajectory. The two agree to 0.01 % through
the burn on the 6.8 kN vehicle, but at the thrust cutoff the interpolated trajectory reads a
spurious 14.8 g. That spike landed on the burn's last step through the feedback. RocketPy's
own ``net_thrust`` reads zero at t = 0, so the motor's is used.

Two conditions follow RocketPy's own equations of motion (``rocketpy/simulation/flight.py``
1.11, ``u_dot_rail1`` and ``u_dot_generalized``):

* **The pressure thrust stops with the motor.** RocketPy adds ``(p_ref - p(z)) A_e`` only while
  ``burn_start_time < t < burn_out_time``. Added in the coast as well, it read +0.34 g at
  apogee where the vehicle is weightless (AUDIT 5.1, 9.3): 251 N of thrust from a cold nozzle.
  Inside the burn (both ends included, so liftoff reads as before) nothing changes.
* **A vehicle held on the rail reads the rail's reaction.** On the rail RocketPy clamps the
  axial acceleration to zero while thrust and drag are below the weight's component along it;
  the rail then carries the difference, so the specific force is ``g0 sin(inclination)``: one
  g0 on a vertical rail, the pad's own value (``Setup.body_acceleration`` default). LE4 lifts
  off at T/W 8, so this never acts on it; a curve with a start ramp would read T/m < 1 g.

Definition at line 269 of file flight.py.

References _axial_drag().

Referenced by fly().

◆ config_dry_kg()

Optional[float] engine.layerx.flight.config_dry_kg ( Any config)
The vehicle empty, as the config states it and ui.flight_sim books it: airframe plus engine,
tank structures and COPV. ``None`` when the config states no vehicle.

Definition at line 223 of file flight.py.

Referenced by liftoff_mass().

◆ coolprop_gas()

Optional[str] engine.layerx.flight.coolprop_gas ( Optional[str] name)
CoolProp's own name for a drawing's fluid (``"helium"`` -> ``"Helium"``); ``None`` for none.
A name CoolProp does not know is passed through, and the flight's density call says so.

Definition at line 148 of file flight.py.

Referenced by _flight_config().

◆ fly()

Dict[str, Any] engine.layerx.flight.fly ( Any config,
Dict[str, Any] timeseries,
Dict[str, float] loads,
float ambient_pa,
* ,
Optional[float] pressurant_kg = None,
Optional[float] copv_volume_L = None,
Optional[float] liftoff_mass_kg = None,
Optional[float] ullage_gas_kg = None,
Optional[str] pressurant_gas = None )
Fly a Layer X burn (``timeseries`` in the Time-Series shape, ``replay.timeseries_payload``)
in EngineDesign's flight simulation. Returns the flight's figures, its trajectory, the
vehicle's stability over the burn (``stability``, DATA-CONTRACT 4), and the proper
acceleration at every firing step on the burn's own clock.

``pressurant_kg`` is the bottle's gas at T-0 and ``copv_volume_L`` its volume, both from the
twin. When they are given, they replace the config's COPV sizing in the vehicle's mass.

``pressurant_gas`` is the drawing's pressurant (``prep.derived["pressurant_gas"]``, e.g.
``"helium"``). When given, the T-0 ullage gas and the COPV's refill of the ullages are priced
as that gas instead of the config tanks' ``ullage_gas``; ``None`` keeps the config's.

``liftoff_mass_kg`` is the vehicle as weighed on the rail. When given, the airframe is what is
left of it after the motor, propellants and gases, so the vehicle lifts off at that mass.
``ullage_gas_kg`` is the gas already in the drawing's tanks at Fire, which flies with them.

Definition at line 750 of file flight.py.

References _ceiling(), _flight_config(), _stability_or_failure(), and axial_acceleration().

◆ inline_specific_force()

Dict[str, Any] engine.layerx.flight.inline_specific_force ( Any config,
Sequence[float] thrust_N,
Sequence[float] mdot_total,
Sequence[float] t,
float liftoff_mass_kg,
float ambient_pa,
* ,
Any drag = None,
float dt_max = 0.01 )
The axial specific force at each of the burn's samples, from a vertical 1-DOF ascent on
this thrust and total propellant flow (D5-C, ``settings.flight_coupling = 'inline'``).

``t`` is the burn's clock (any origin; samples before Fire carry zero thrust and read 1 g0);
``thrust_N`` and ``mdot_total`` are sampled at ``t`` and taken linear in between;
``liftoff_mass_kg`` is the vehicle at ``t[0]`` (:func:`liftoff_mass`); ``ambient_pa`` is the
pressure the thrust was computed against. The vehicle (body, nozzle exit, drag, pad) is
``config``'s, as the RocketPy flight builds it; ``drag`` overrides its Cd(M).

Returns ``{t, accel_m_s2, ...}``: ``{t, accel_m_s2}`` is the shape :func:`fly`'s ``schedule``
has, so it drops into the burn loop unchanged. Causal: the value at ``t[k]`` uses samples up to
``t[k]`` only, so a burn pass can also drive :class:`InlineAscent` one step at a time.

Definition at line 615 of file flight.py.

References _cfg_input(), and _vehicle_terms().

◆ liftoff_mass()

Dict[str, Any] engine.layerx.flight.liftoff_mass ( Any config,
Dict[str, float] loads,
* ,
float ambient_pa = 101325.0,
Optional[float] pressurant_kg = None,
Optional[float] copv_volume_L = None,
Optional[float] ullage_gas_kg = None,
Optional[str] pressurant_gas = None,
Optional[float] weighed_kg = None )
The vehicle's mass at Fire [kg], booked as ``ui.flight_sim.setup_flight`` books it, without
building the RocketPy flight: for :func:`inline_specific_force` inside a burn pass.

``weighed_kg`` (the vehicle on the rail) wins when given. Otherwise: the config's airframe and
motor dry mass (the COPV structure scaled to the twin's bottle as :func:`fly` scales it), the
loads (capped to what the config's tanks hold, as the flight caps them), the bottle's gas, and
the T-0 ullage gas (``ullage_gas_kg``, the drawing's; else the config tanks' own at
``initial_pressure_psi``). Returns ``{value, source, parts, notes}``.

Definition at line 694 of file flight.py.

References _flight_config(), config_dry_kg(), max, and min.

◆ line_paths()

List[Dict[str, Any]] engine.layerx.flight.line_paths ( Dict[str, Any] payload,
Any model,
Dict[str, str] inlets,
Dict[str, str] tanks,
Sequence[str] restated )
Per side, the drawing's path from the tank to the injector: its lines, their drawn length
and the height they state. Read only: the drawing is the feed system.

Definition at line 121 of file flight.py.

References _drawn_length_m(), _elevation_m(), and _path_to_tank().

◆ schedule_change()

float engine.layerx.flight.schedule_change ( Optional[Dict[str, Any]] old,
Optional[Dict[str, Any]] new )
Largest relative move of the acceleration between two histories, on the newer one's
clock. ``inf`` when there was no previous history. The last sample is left out: it sits at
the depletion instant, which moves by a fraction of a step each pass, so it compares the
tail-off of one burn against full thrust of the other and only ever governs a partial step.

Definition at line 840 of file flight.py.

◆ vehicle_stability()

Dict[str, Any] engine.layerx.flight.vehicle_stability ( Any flight,
Any config,
Sequence[float] clock )
The vehicle's static stability over the burn, its max-Q and its rail exit, read off the
RocketPy flight (DATA-CONTRACT 4, ``result.flight.stability``).

``clock`` is the burn's own clock, one value per sample, Fire first (flight time is
``clock - clock[0]``); every time this function returns is on that clock (the ``*_time_s``
scalars :func:`_stability_or_failure` keeps from ``flight_report`` are flight time; Layer X
puts Fire at clock 0, so the two agree there). Positions are from the tail
(RocketPy ``tail_to_nose``), so ``static_margin_cal = (cg_m - cp_m) / diameter``. ``cp_m`` is
Barrowman's CP at Mach 0, the static margin's own basis; the flight-Mach margin RocketPy
tracks to apogee is ``min_stability_margin_cal``.

The CG is the config's vehicle: tank positions and cylinders from ``lox_tank``/``fuel_tank``,
not the drawing's tanks, which the flight does not lay out (AUDIT 9.3, 3).

Definition at line 348 of file flight.py.

References _cfg_input().

Referenced by _stability_or_failure().

Variable Documentation

◆ _TO_M

dict engine.layerx.flight._TO_M = {"m": 1.0, "mm": 1e-3, "cm": 1e-2, "in": 0.0254, "ft": 0.3048}
protected

Definition at line 62 of file flight.py.

◆ ACCEL_TOLERANCE

int engine.layerx.flight.ACCEL_TOLERANCE = 5e-3

Definition at line 48 of file flight.py.

◆ G0

float engine.layerx.flight.G0 = 9.80665

Definition at line 41 of file flight.py.

◆ INLINE_SOURCE

tuple engine.layerx.flight.INLINE_SOURCE
Initial value:
1= (
2 "Vertical point-mass ascent as engine/pipeline/flight_1dof.py: dv/dt = (F + (p_ref - p(z)) A_e - D)/m - g0, "
3 "dm/dt = -mdot (Sutton & Biblarz, Rocket Propulsion Elements, 9th ed., 2017, ch. 4); drag D = 1/2 rho v|v| "
4 "Cd(M) A from engine/pipeline/vehicle_drag (Niskanen, OpenRocket technical documentation, 2013, sec. 3.4); "
5 "atmosphere: U.S. Standard Atmosphere, 1976; the specific force (T + pressure thrust - D)/m is what an "
6 "accelerometer on the axis reads (Titterton & Weston, Strapdown Inertial Navigation Technology, 2nd ed., "
7 "2004); the held vehicle follows RocketPy 1.11's rail clamp (u_dot_rail1)"
8)

Definition at line 462 of file flight.py.

◆ MAX_FLIGHT_PASSES

int engine.layerx.flight.MAX_FLIGHT_PASSES = 4

Definition at line 52 of file flight.py.

◆ STABILITY_SOURCE

tuple engine.layerx.flight.STABILITY_SOURCE
Initial value:
1= (
2 "Barrowman, J. S., 'The Practical Calculation of the Aerodynamic Characteristics of Slender Finned "
3 "Vehicles', M.S. thesis, Catholic University of America, 1967 (CP of nose and fins); as implemented in "
4 "RocketPy 1.11 (Ceotto et al., 'RocketPy: Six Degree-of-Freedom Rocket Trajectory Simulator', J. Aerospace "
5 "Engineering 34(6), 2021): Rocket.static_margin, Rocket.center_of_mass, Rocket.cp_position, "
6 "Flight.max_dynamic_pressure, Flight.out_of_rail_velocity"
7)

Definition at line 339 of file flight.py.

◆ TRAJECTORY_POINTS

int engine.layerx.flight.TRAJECTORY_POINTS = 240

Definition at line 56 of file flight.py.