astra.maneuver module¶
ASTRA Core Maneuver Modeling — Frame Transformations & Thrust Application. Implements the mathematics required to convert spacecraft-centric thrust vectors (VNB / RTN) into the inertial frame and to validate maneuver definitions before integration. Frame definitions (all right-handed orthonormal triads):
VNB (Velocity, Normal, Binormal):
V̂ = v / |v|
N̂ = (r × v) / |r × v|
B̂ = V̂ × N̂
RTN (Radial, Transverse, Normal):
R̂ = r / |r|
N̂ = (r × v) / |r × v|
T̂ = N̂ × R̂
References - Vallado, D. A. (2013). Fundamentals of Astrodynamics and Applications, §4.7. - Schaub & Junkins (2018). Analytical Mechanics of Space Systems, §14.2.
- astra.maneuver.rotation_vnb_to_inertial(r_eci, v_eci)[source]¶
Build the 3×3 rotation matrix whose rows are the VNB unit vectors in ECI. Convention (important):
_build_vnb_matrix_njitstores the VNB basis vectors as rows:T[0, :] = V̂ (velocity unit vector) T[1, :] = N̂ (orbit-normal unit vector) T[2, :] = B̂ (binormal unit vector)
- This makes T an VNB→ECI rotation matrix, so:
a_inertial = T @ a_vnb # VNB direction → ECI components
- Parameters:
r_eci – Shape (3,) inertial position [km].
v_eci – Shape (3,) inertial velocity [km/s].
- Returns:
Shape (3, 3) matrix whose columns are [V̂, N̂, B̂] in ECI (i.e. VNB→ECI).
- Raises:
ManeuverError – If velocity magnitude < 1e-12 km/s or if r ∥ v (angular momentum near-zero), making the VNB frame undefined.
- Example::
T = rotation_vnb_to_inertial(r_eci, v_eci) # Prograde burn of 10 m/s: dv_eci = T @ np.array([0.01, 0.0, 0.0]) # V̂ direction → ECI
- astra.maneuver.rotation_rtn_to_inertial(r_eci, v_eci)[source]¶
Build the 3×3 rotation matrix from RTN to inertial (ECI/TEME). Columns of the returned matrix are the RTN unit vectors expressed in the inertial frame:
T = [R̂ | T̂ | N̂]
so that a_inertial = T @ a_rtn. :param r_eci: Shape (3,) inertial position [km]. :param v_eci: Shape (3,) inertial velocity [km/s].
- Returns:
Shape (3, 3) rotation matrix.
- Raises:
ManeuverError – If position magnitude is degenerate (< 1e-12 km), making the frame undefined.
- astra.maneuver.frame_to_inertial(r_eci, v_eci, frame)[source]¶
Return the appropriate frame-to-inertial rotation matrix. Convenience dispatcher that selects VNB or RTN based on the
ManeuverFrameenum value. :param r_eci: Shape (3,) inertial position [km]. :param v_eci: Shape (3,) inertial velocity [km/s]. :param frame: ManeuverFrame.VNB or ManeuverFrame.RTN.- Returns:
Shape (3, 3) rotation matrix T such that
a_inertial = T @ a_frame.
- astra.maneuver.thrust_acceleration_inertial(r_eci, v_eci, mass_kg, burn)[source]¶
Compute the inertial thrust acceleration vector at a single instant. This function is called at every Runge-Kutta sub-step during a powered arc. It re-computes the frame transformation matrix from the instantaneous position and velocity, ensuring that dynamically steered burns (e.g. gravity-turn, velocity-aligned orbit-raise) perfectly track the commanded attitude. :param r_eci: Shape (3,) inertial position [km]. :param v_eci: Shape (3,) inertial velocity [km/s]. :param mass_kg: Instantaneous spacecraft mass [kg] (must be > 0). :param burn: Active
FiniteBurndefinition.- Returns:
Shape (3,) inertial acceleration [km/s²].
- Raises:
ManeuverError – If mass is non-positive (propellant exhausted).
- astra.maneuver.validate_burn(burn, initial_mass_kg)[source]¶
Pre-flight validation of a FiniteBurn definition. Checks physical consistency before handing the burn off to the integrator. Raises
ManeuverErroron the first detected issue. Checks performed:Duration is strictly positive.
Thrust is strictly positive.
Specific impulse is strictly positive.
Direction vector has unit magnitude (within 1e-6 tolerance).
Total propellant consumed does not exceed available mass.
- Parameters:
burn – The
FiniteBurnto validate.initial_mass_kg – Spacecraft wet mass at ignition [kg].
- Raises:
ManeuverError – Descriptive error on validation failure.
- astra.maneuver.validate_burn_sequence(burns)[source]¶
Ensure that a list of FiniteBurn objects does not contain temporal overlaps. This function detects unphysical “dual-thrust” arcs (remediates PHY-F/SE-G). It assumes the burns list is already sorted by ignition time. :param burns: Sorted list of
FiniteBurnobjects.- Raises:
ManeuverError – If an overlap is detected between any two burns.
- astra.maneuver.plan_hohmann(r_initial_km, r_target_km, isp_s, mass_kg, thrust_N, t_ignition_jd, frame=ManeuverFrame.VNB)[source]¶
Plan a two-burn Hohmann transfer between two circular orbits. Computes the two impulsive delta-V maneuvers required for a classical Hohmann transfer, then converts each impulsive delta-V to a finite-burn arc using the Tsiolkovsky rocket equation and the specified engine parameters. For raising transfers, both burns are prograde. For lowering transfers, both burns are retrograde because the transfer ellipse is slower than the initial circular orbit at apoapsis and faster than the final circular orbit at periapsis. Assumptions:
Both initial and target orbits are circular.
Earth’s gravitational parameter μ = 398600.4418 km³/s².
The transfer uses instantaneous acceleration (finite-burn duration is computed from thrust and Isp but the impulsive ΔV is exact).
Coasting time on the transfer arc (half the ellipse period) is computed and used to schedule the second burn epoch.
- Parameters:
r_initial_km – Geocentric radius of the initial circular orbit (km). This is altitude + EARTH_EQUATORIAL_RADIUS_KM.
r_target_km – Geocentric radius of the target circular orbit (km).
isp_s – Engine specific impulse (seconds).
mass_kg – Spacecraft mass at the start of the transfer (kg).
thrust_N – Engine thrust in Newtons.
t_ignition_jd – Julian Date of the first burn ignition.
frame – ManeuverFrame for thrust direction (default VNB).
- Returns:
List of two
FiniteBurnobjects — [burn_1, burn_2].- Raises:
ManeuverError – If the orbit radii are non-positive, target equals initial (null transfer), thrust or Isp are non-positive, or the spacecraft runs out of propellant before completing the transfer.
- Example::
import astra, math from astra.constants import EARTH_EQUATORIAL_RADIUS_KM as Re burns = astra.plan_hohmann(
r_initial_km = Re + 400.0, # 400 km LEO r_target_km = Re + 600.0, # 600 km target isp_s = 300.0, mass_kg = 1000.0, thrust_N = 10.0, t_ignition_jd= 2460000.5,
) traj = astra.propagate_cowell(state, maneuvers=burns, …)
- astra.maneuver.plan_bielliptic(r_initial_km, r_target_km, r_intermediate_km, isp_s, mass_kg, thrust_N, t_ignition_jd, frame=ManeuverFrame.VNB)[source]¶
Plan a three-burn bi-elliptic transfer between two circular orbits.
A bi-elliptic transfer is more efficient than Hohmann when the ratio
r_target / r_initial > 11.94(Vallado §6.3.2). It uses three burns:Burn 1: At initial orbit, raise apoapsis to
r_intermediate.Burn 2: At
r_intermediate, adjust periapsis tor_target.Burn 3: At
r_target, circularize.
- Assumptions:
Initial and target orbits are circular.
Intermediate radius must exceed both
r_initialandr_target.Earth’s gravitational parameter μ = 398600.4418 km³/s².
- Parameters:
r_initial_km – Geocentric radius of the initial circular orbit (km).
r_target_km – Geocentric radius of the target circular orbit (km).
r_intermediate_km – Geocentric radius of the intermediate apoapsis (km). Must be ≥ max(r_initial_km, r_target_km).
isp_s – Engine specific impulse (seconds).
mass_kg – Spacecraft mass at the start of the transfer (kg).
thrust_N – Engine thrust in Newtons.
t_ignition_jd – Julian Date of the first burn ignition.
frame – ManeuverFrame for thrust direction (default VNB).
- Returns:
List of three
FiniteBurnobjects — [burn_1, burn_2, burn_3].- Raises:
ManeuverError – If radii are invalid, intermediate is too small, or the spacecraft runs out of propellant.
Example:
import astra from astra.constants import EARTH_EQUATORIAL_RADIUS_KM as Re burns = astra.plan_bielliptic( r_initial_km = Re + 300.0, r_target_km = Re + 35786.0, # GEO r_intermediate_km= Re + 100000.0, # high intermediate isp_s = 300.0, mass_kg = 2000.0, thrust_N = 50.0, t_ignition_jd = 2460000.5, )
- astra.maneuver.plan_inclination_change(r_km, delta_inc_deg, isp_s, mass_kg, thrust_N, t_ignition_jd, frame=ManeuverFrame.VNB)[source]¶
Plan a single-burn inclination change at the ascending/descending node.
Uses the exact plane-change ΔV formula for circular orbits:
ΔV = 2 · v_circular · sin(Δi / 2)
where
v_circular = √(μ / r)is the orbital velocity at radiusr.The burn is applied normal to the orbital plane (along the N-axis in both VNB and RTN frames). Positive
delta_inc_degincreases inclination (burns at ascending node); negative decreases it (burns at descending node).- Parameters:
r_km – Geocentric orbit radius (km). Must be positive.
delta_inc_deg – Desired inclination change (degrees). Can be negative.
isp_s – Engine specific impulse (seconds).
mass_kg – Spacecraft mass at burn start (kg).
thrust_N – Engine thrust in Newtons.
t_ignition_jd – Julian Date of burn ignition (should be at the ascending or descending node for optimal efficiency).
frame – ManeuverFrame for thrust direction (default VNB).
- Returns:
List containing one
FiniteBurnwith thrust along the normal axis.- Raises:
ManeuverError – If radius, thrust, or Isp are non-positive, or if delta_inc_deg is zero, or if the burn requires more propellant than available.
Example:
import astra from astra.constants import EARTH_EQUATORIAL_RADIUS_KM as Re burns = astra.plan_inclination_change( r_km = Re + 35786.0, # GEO radius delta_inc_deg = -0.5, # reduce inclination by 0.5° isp_s = 300.0, mass_kg = 3000.0, thrust_N = 22.0, t_ignition_jd = 2460000.5, )
- class astra.maneuver.DeltaVBudget(total_delta_v_m_s, total_propellant_kg, final_mass_kg, burns)[source]¶
Bases:
objectPre-propagation ΔV budget summary for a sequence of finite burns.
Provides the total ΔV, total propellant consumption, final mass, and per-burn breakdown without requiring a full numerical propagation.
- total_delta_v_m_s¶
Total ΔV across all burns (m/s).
- Type:
float
- total_propellant_kg¶
Total propellant consumed (kg).
- Type:
float
- final_mass_kg¶
Spacecraft mass after all burns (kg).
- Type:
float
- burns¶
Per-burn breakdown as a list of dicts, each containing:
index,delta_v_m_s,propellant_kg,mass_before_kg,mass_after_kg,duration_s,epoch_ignition_jd.- Type:
list[dict]
- total_delta_v_m_s¶
- total_propellant_kg¶
- final_mass_kg¶
- burns¶
- astra.maneuver.compute_delta_v_budget(burns, initial_mass_kg)[source]¶
Compute a pre-propagation ΔV and propellant budget for a burn sequence.
Uses the Tsiolkovsky rocket equation sequentially on each burn to compute ΔV, propellant consumed, and remaining mass — without running a full numerical propagation.
The ΔV for each burn is computed as:
ΔV = Isp · g₀ · ln(m_before / m_after)
where
m_after = m_before - F · duration / (Isp · g₀).- Parameters:
burns – Ordered list of
FiniteBurnobjects. Burns are processed sequentially; mass depleted by burn N reduces the starting mass for burn N+1.initial_mass_kg – Spacecraft mass before the first burn (kg).
- Returns:
DeltaVBudgetwith total ΔV, propellant, final mass, and per-burn breakdown.- Raises:
ManeuverError – If
initial_mass_kgis non-positive, ifburnsis empty, or if the spacecraft runs out of mass mid-sequence.
Example:
import astra burns = astra.plan_hohmann( r_initial_km=6778.0, r_target_km=7178.0, isp_s=300.0, mass_kg=1000.0, thrust_N=10.0, t_ignition_jd=2460000.5, ) budget = astra.compute_delta_v_budget(burns, initial_mass_kg=1000.0) print(f"Total ΔV: {budget.total_delta_v_m_s:.1f} m/s") print(f"Propellant: {budget.total_propellant_kg:.2f} kg") print(f"Final mass: {budget.final_mass_kg:.2f} kg")