|
STAR
Cal STAR — firmware, DAQ server, and engine design
|
Functions | |
| np.ndarray | generate_pressure_curve_from_segments (List[Dict[str, Any]] segments, int n_points=200, *, bool allow_rise=False, bool exact_ends=False) |
| List[Dict[str, Any]] | segments_from_optimizer_vars_pressure (np.ndarray x_segments, int n_segments, float initial_pressure_pa, float min_pressure_pa=1e6) |
| Dict[str, Any] | layer2_flight_vehicle (PintleEngineConfig config) |
| float | calculate_required_impulse_from_mass (float target_apogee_m, float rocket_dry_mass_kg, float total_propellant_mass_kg, float target_burn_time_s, *, Optional[np.ndarray] time_s=None, Optional[np.ndarray] mdot_kg_s=None, Optional[np.ndarray] thrust_n=None, Optional[Dict[str, Any]] vehicle=None) |
| Tuple[float, float, Dict[str, Any], bool] | run_layer2a_minimum_pressures (PintleEngineConfig optimized_config, float initial_lox_pressure_pa, float initial_fuel_pressure_pa, float peak_thrust, float target_apogee_m, float rocket_dry_mass_kg, float max_lox_tank_capacity_kg, float max_fuel_tank_capacity_kg, float target_burn_time, int n_time_points=100, Optional[Callable] update_progress=None, Optional[Callable] log_status=None, float min_pressure_pa=1e6, Optional[float] optimal_of_ratio=None, Optional[float] min_stability_margin=None) |
| Tuple[PintleEngineConfig, np.ndarray, np.ndarray, np.ndarray, Dict[str, Any], bool] | run_layer2_pressure (PintleEngineConfig optimized_config, float initial_lox_pressure_pa, float initial_fuel_pressure_pa, float peak_thrust, float target_apogee_m, float rocket_dry_mass_kg, float max_lox_tank_capacity_kg, float max_fuel_tank_capacity_kg, float target_burn_time, int n_time_points=200, Optional[Callable] update_progress=None, Optional[Callable] log_status=None, float min_pressure_pa=1e6, Optional[float] optimal_of_ratio=None, Optional[float] min_stability_margin=None, int max_iterations=20, Optional[int] max_evaluations=None, bool save_evaluation_plots=False, Optional[float] min_lox_pressure_floor_pa=None, Optional[float] min_fuel_pressure_floor_pa=None, float min_pressure_slope_psi_per_sec=-25.0, Optional[Callable[[int, float, float], None]] objective_callback=None, Optional[Callable[[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray], Optional[np.ndarray]], None]] pressure_curve_callback=None, Optional[Any] stop_event=None, int de_maxiter=5, int de_popsize=2, int de_n_time_points=25, bool use_controller_simulation=False, Optional[Any] controller_config=None) |
Variables | |
| str | N2_Z_LOOKUP_CSV = Path(__file__).resolve().parent.parent.parent.parent / "copv" / "n2_Z_lookup.csv" |
| int | N_SEGMENTS = 8 |
| int | VARS_PER_SEGMENT = 5 |
Layer 2: Pressure Curve Optimization This layer optimizes fuel and oxidizer pressure curves to input into the time series solver. The pressure curves are 200-point arrays broken into N segments (1-20). Each segment has: - Segment length (in terms of points/200) - Region type: linear OR blowdown - Start pressure (matches previous region's end pressure) - End pressure - k-variable for blowdown profile between those 2 points Pressure curves are always decreasing. NOTE (not addressed here -- recorded for whoever picks this up): This layer assumes a BLOWDOWN system. A regulated / flat-pressure engine is only representable as a degenerate case: ``end_pressure_ratio = 1.0``, which is the exact UPPER BOUND of that search variable, and ``generate_pressure_curve_from_segments`` force-clamps ``P_end = 0.95 * P_start`` if a segment ever tries to rise. So a constant 600 psi design is reachable in principle but sits on a bound, which this optimizer has a documented history of handling badly (penalties with ~0 gradient at a band edge park candidates just outside it). Layer 1 is unaffected -- it is time-independent by contract and optimizes a single operating point, so a flat-pressure design is exactly what its static solution already represents. If flat/regulated feed becomes a supported mode rather than an edge case, this layer needs an explicit constant-pressure segment type instead of a boundary value.
| float engine.optimizer.layers.layer2_pressure.calculate_required_impulse_from_mass | ( | float | target_apogee_m, |
| float | rocket_dry_mass_kg, | ||
| float | total_propellant_mass_kg, | ||
| float | target_burn_time_s, | ||
| * | , | ||
| Optional[np.ndarray] | time_s = None, | ||
| Optional[np.ndarray] | mdot_kg_s = None, | ||
| Optional[np.ndarray] | thrust_n = None, | ||
| Optional[Dict[str, Any]] | vehicle = None ) |
Total impulse [N s] that reaches target_apogee_m (above the pad) with this propellant, burn time and mass-flow shape: the vertical 1-DOF of engine/pipeline/flight_1dof with the flight sim's drag (``vehicle`` from layer2_flight_vehicle; none given, no drag). This was (1.15 sqrt(2 g h) + 0.5 g t_b) (m_dry + m_p): delta-v times the lift-off mass where the rocket equation gives c m_p, half the gravity loss, burnout altitude ignored and a flat 15 % for drag. The errors happened to cancel near 6.5 kN (27,094 N s against 25,025 N s at Cd 0.45) and not elsewhere: +18 % at 40 kg / 40 kg / 15 s. With no drag this reduces to Sutton & Biblarz's vertical flight exactly. rocket_dry_mass_kg is airframe + engine + tank and COPV structures; the pressurant gas is added from the vehicle (press_tank.initial_gas_mass).
Definition at line 303 of file layer2_pressure.py.
Referenced by run_layer2_pressure(), and run_layer2a_minimum_pressures().
| np.ndarray engine.optimizer.layers.layer2_pressure.generate_pressure_curve_from_segments | ( | List[Dict[str, Any]] | segments, |
| int | n_points = 200, | ||
| * | , | ||
| bool | allow_rise = False, | ||
| bool | exact_ends = False ) |
Generate a 200-point pressure curve from segments.
Each segment specifies:
- length_ratio: fraction of total points (0-1)
- type: 'linear' or 'blowdown'
- start_pressure: pressure at start [Pa]
- end_pressure: pressure at end [Pa] (must be <= start_pressure)
- k: blowdown parameter (only for blowdown type)
Args:
segments: List of segment dicts
n_points: Total number of points (default 200)
allow_rise: keep a segment whose end is above its start (any feed system whose tank
pressure climbs: a regulator's supply-pressure effect, a pressurant schedule). Off: such
a segment is forced to fall 5 %, which is what Layer 2's search space assumes.
exact_ends: a blowdown segment ends AT its end pressure,
P = P_end + (P_start - P_end)(e^(-k t) - e^(-k))/(1 - e^(-k)) -- the curve the Time-Series
builder draws. Off: P_end + (P_start - P_end) e^(-k t), which stops short of P_end
(61 % of the way back at k = 0.5); Layer 2 has always used it.
Returns:
pressure_array: Array of pressures [Pa] of length n_points
Definition at line 53 of file layer2_pressure.py.
Referenced by run_layer2_pressure().
| Dict[str, Any] engine.optimizer.layers.layer2_pressure.layer2_flight_vehicle | ( | PintleEngineConfig | config | ) |
What the required-impulse flight needs from the config, built once per run: the flight sim's Cd(M) and body area (engine/pipeline/vehicle_drag), the pad, the thrust curve's reference pressure and nozzle exit, and the pressurant carried on top of the dry mass. A config with no vehicle to fly (no rocket, tanks or environment) gets no drag, and the returned "model" says so, so the summary can show it.
Definition at line 266 of file layer2_pressure.py.
Referenced by run_layer2_pressure(), and run_layer2a_minimum_pressures().
| Tuple[PintleEngineConfig, np.ndarray, np.ndarray, np.ndarray, Dict[str, Any], bool] engine.optimizer.layers.layer2_pressure.run_layer2_pressure | ( | PintleEngineConfig | optimized_config, |
| float | initial_lox_pressure_pa, | ||
| float | initial_fuel_pressure_pa, | ||
| float | peak_thrust, | ||
| float | target_apogee_m, | ||
| float | rocket_dry_mass_kg, | ||
| float | max_lox_tank_capacity_kg, | ||
| float | max_fuel_tank_capacity_kg, | ||
| float | target_burn_time, | ||
| int | n_time_points = 200, | ||
| Optional[Callable] | update_progress = None, | ||
| Optional[Callable] | log_status = None, | ||
| float | min_pressure_pa = 1e6, | ||
| Optional[float] | optimal_of_ratio = None, | ||
| Optional[float] | min_stability_margin = None, | ||
| int | max_iterations = 20, | ||
| Optional[int] | max_evaluations = None, | ||
| bool | save_evaluation_plots = False, | ||
| Optional[float] | min_lox_pressure_floor_pa = None, | ||
| Optional[float] | min_fuel_pressure_floor_pa = None, | ||
| float | min_pressure_slope_psi_per_sec = -25.0, | ||
| Optional[Callable[[int, float, float], None]] | objective_callback = None, | ||
| Optional[Callable[[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray], Optional[np.ndarray]], None]] | pressure_curve_callback = None, | ||
| Optional[Any] | stop_event = None, | ||
| int | de_maxiter = 5, | ||
| int | de_popsize = 2, | ||
| int | de_n_time_points = 25, | ||
| bool | use_controller_simulation = False, | ||
| Optional[Any] | controller_config = None ) |
Run Layer 2: Pressure Curve Optimization.
Optimizes fuel and oxidizer pressure curves (200-point arrays) for time series solver.
- Uses a fixed number of segments per tank (N_SEGMENTS)
- Each segment can be linear or blowdown with parameters:
- length_ratio, type, end_pressure_ratio, k
- First performs a global search (differential_evolution), then local polish (L-BFGS-B)
Returns:
Tuple of (optimized_config, time_array, P_tank_O_array, P_tank_F_array, summary, success)
Definition at line 600 of file layer2_pressure.py.
References calculate_required_impulse_from_mass(), generate_pressure_curve_from_segments(), layer2_flight_vehicle(), max, min, and time.time().
| Tuple[float, float, Dict[str, Any], bool] engine.optimizer.layers.layer2_pressure.run_layer2a_minimum_pressures | ( | PintleEngineConfig | optimized_config, |
| float | initial_lox_pressure_pa, | ||
| float | initial_fuel_pressure_pa, | ||
| float | peak_thrust, | ||
| float | target_apogee_m, | ||
| float | rocket_dry_mass_kg, | ||
| float | max_lox_tank_capacity_kg, | ||
| float | max_fuel_tank_capacity_kg, | ||
| float | target_burn_time, | ||
| int | n_time_points = 100, | ||
| Optional[Callable] | update_progress = None, | ||
| Optional[Callable] | log_status = None, | ||
| float | min_pressure_pa = 1e6, | ||
| Optional[float] | optimal_of_ratio = None, | ||
| Optional[float] | min_stability_margin = None ) |
Layer 2a: Find minimum allowable LOX and fuel tank pressures.
This helper layer searches for the lowest *flat* tank pressures (same value
over the full burn) that still satisfy the key constraints:
- Required impulse to reach target apogee
- Tank capacity limits
- Stability margin
- O/F ratio tolerance
The LOX/Fuel tank pressure ratio is kept fixed to the initial ratio from
Layer 1 by scaling both tanks by a common factor.
Returns:
Tuple of (min_lox_pressure_pa, min_fuel_pressure_pa, summary, success)
Definition at line 353 of file layer2_pressure.py.
References calculate_required_impulse_from_mass(), layer2_flight_vehicle(), max, and min.
| List[Dict[str, Any]] engine.optimizer.layers.layer2_pressure.segments_from_optimizer_vars_pressure | ( | np.ndarray | x_segments, |
| int | n_segments, | ||
| float | initial_pressure_pa, | ||
| float | min_pressure_pa = 1e6 ) |
Convert optimizer variables to segment list for pressure curves.
For each segment, optimizer provides:
- length_ratio (0-1, fraction of total 200 points)
- end_pressure_ratio (0-1, ratio relative to initial pressure)
- k (0-2, blowdown parameter)
Start pressure is automatically set to match previous segment's end pressure.
First segment starts at initial_pressure_pa.
Args:
x_segments: Array of optimizer variables for segments
n_segments: Number of segments (1-20)
initial_pressure_pa: Initial pressure from Layer 1 [Pa]
min_pressure_pa: Minimum pressure [Pa]
Returns:
List of segment dicts
Definition at line 179 of file layer2_pressure.py.
| str engine.optimizer.layers.layer2_pressure.N2_Z_LOOKUP_CSV = Path(__file__).resolve().parent.parent.parent.parent / "copv" / "n2_Z_lookup.csv" |
Definition at line 50 of file layer2_pressure.py.
| int engine.optimizer.layers.layer2_pressure.N_SEGMENTS = 8 |
Definition at line 349 of file layer2_pressure.py.
| int engine.optimizer.layers.layer2_pressure.VARS_PER_SEGMENT = 5 |
Definition at line 350 of file layer2_pressure.py.