import numpy as np
from astrora._core import hohmann_phase_angle, hohmann_synodic_period, hohmann_transfer
from astrora.bodies import Earth
EARTH_RADIUS = 6378.137 LEO_ALTITUDE = 400 GEO_ALTITUDE = 35786 LUNAR_DISTANCE = 384400
def print_transfer_summary(result, name, r_initial, r_final):
print(f"\n{'='*70}")
print(f"{name}")
print(f"{'='*70}")
print(f"Initial orbit radius: {r_initial:,.0f} km ({r_initial/EARTH_RADIUS:.2f} R⊕)")
print(f"Final orbit radius: {r_final:,.0f} km ({r_final/EARTH_RADIUS:.2f} R⊕)")
print(f"\nTransfer Orbit:")
print(f" Semi-major axis: {result['transfer_sma']/1000:,.0f} km")
print(f" Eccentricity: {result['transfer_eccentricity']:.4f}")
print(f" Periapsis velocity: {result['v_transfer_periapsis']/1000:.3f} km/s")
print(f" Apoapsis velocity: {result['v_transfer_apoapsis']/1000:.3f} km/s")
print(f"\nDelta-v Budget:")
print(f" First burn (ΔV₁): {result['delta_v1']/1000:.3f} km/s")
print(f" Second burn (ΔV₂): {result['delta_v2']/1000:.3f} km/s")
print(f" Total delta-v: {result['delta_v_total']/1000:.3f} km/s")
print(f"\nTiming:")
print(
f" Transfer time: {result['transfer_time']/3600:.2f} hours ({result['transfer_time']/86400:.3f} days)"
)
print(f" Initial orbit velocity: {result['v_initial']/1000:.3f} km/s")
print(f" Final orbit velocity: {result['v_final']/1000:.3f} km/s")
print(f"{'='*70}\n")
def example_leo_to_geo():
r_leo = EARTH_RADIUS + LEO_ALTITUDE
r_geo = EARTH_RADIUS + GEO_ALTITUDE
result = hohmann_transfer(
r_initial=r_leo * 1000, r_final=r_geo * 1000,
mu=Earth.mu, )
print_transfer_summary(result, "LEO to GEO Transfer", r_leo, r_geo)
print("Mission Notes:")
print(" - Total ΔV is ~3.9 km/s for the orbital transfer")
print(" - Add ~9.4 km/s for initial LEO insertion from ground")
print(" - Transfer time is ~5.25 hours (half of transfer orbit period)")
print(" - This is the minimum-energy transfer (Hohmann is optimal)")
print(" - Real missions may use slightly faster transfers for scheduling")
def example_leo_to_lunar():
r_leo = EARTH_RADIUS + LEO_ALTITUDE
r_lunar = LUNAR_DISTANCE
result = hohmann_transfer(r_initial=r_leo * 1000, r_final=r_lunar * 1000, mu=Earth.mu)
print_transfer_summary(result, "LEO to Lunar Transfer Orbit", r_leo, r_lunar)
print("Mission Notes:")
print(" - This is the Trans-Lunar Injection (TLI) maneuver")
print(" - Transfer time is ~5 days (Apollo missions took 3 days with faster trajectory)")
print(" - Moon's gravity will assist in capture (not included in this calculation)")
print(" - Additional ΔV needed for Lunar Orbit Insertion (LOI)")
print(" - Apollo missions used ~3.1 km/s for TLI from LEO")
def example_earth_mars_comparison():
r_earth = 149.6e6 r_mars = 227.9e6
mu_sun = 1.32712440018e11
result = hohmann_transfer(
r_initial=r_earth * 1000, r_final=r_mars * 1000, mu=mu_sun * 1e9 )
print_transfer_summary(result, "Earth-Mars Hohmann Transfer", r_earth, r_mars)
phase_angle_rad = hohmann_phase_angle(
r_initial=r_earth * 1000, r_final=r_mars * 1000, mu=mu_sun * 1e9
)
synodic_period_sec = hohmann_synodic_period(
r_initial=r_earth * 1000, r_final=r_mars * 1000, mu=mu_sun * 1e9
)
print("Launch Window Analysis:")
print(f" Required phase angle: {np.rad2deg(phase_angle_rad):.2f}°")
print(
f" Synodic period: {synodic_period_sec/86400:.1f} days ({synodic_period_sec/(86400*365.25):.2f} years)"
)
print(f" Launch windows occur every ~{synodic_period_sec/(86400*30.44):.1f} months")
print()
print("Mission Notes:")
print(" - Transfer time is ~259 days (~8.5 months)")
print(" - Launch windows occur roughly every 26 months")
print(" - Must launch when Earth-Mars phase angle is correct")
print(" - Real missions account for planetary orbital eccentricity")
print(" - Faster transfers are possible with more delta-v")
print(" - This is the minimum-energy transfer to Mars")
def example_altitude_changes():
print(f"\n{'='*70}")
print("Altitude Change Study: LEO Altitude Adjustments")
print(f"{'='*70}\n")
base_altitude = 400 altitude_changes = [10, 50, 100, 200, 500]
print(f"Base orbit: {base_altitude} km altitude ({EARTH_RADIUS + base_altitude:.0f} km radius)")
print(f"\n{'Δh (km)':>10} {'Total ΔV (m/s)':>18} {'Transfer Time':>18}")
print("-" * 50)
for delta_h in altitude_changes:
r_initial = (EARTH_RADIUS + base_altitude) * 1000
r_final = (EARTH_RADIUS + base_altitude + delta_h) * 1000
result = hohmann_transfer(r_initial, r_final, Earth.mu)
print(
f"{delta_h:>10} {result['delta_v_total']:>18.2f} {result['transfer_time']/60:>15.1f} min"
)
print()
print("Observations:")
print(" - Small altitude changes require less delta-v")
print(" - Delta-v scales roughly linearly with altitude change")
print(" - Transfer time increases slightly with altitude")
print(" - For station-keeping, these are typical maneuver sizes")
if __name__ == "__main__":
print(
"""
╔══════════════════════════════════════════════════════════════════╗
║ Hohmann Transfer Examples ║
║ Using Astrora's Hohmann Transfer Calculator ║
╚══════════════════════════════════════════════════════════════════╝
Hohmann transfers are the most fuel-efficient way to move between
circular coplanar orbits. They require exactly two impulsive burns
and follow an elliptical transfer trajectory.
These examples demonstrate common orbital transfer scenarios.
"""
)
example_leo_to_geo()
print("\n" + "=" * 70 + "\n")
example_leo_to_lunar()
print("\n" + "=" * 70 + "\n")
example_earth_mars_comparison()
print("\n" + "=" * 70 + "\n")
example_altitude_changes()
print(
"""
╔══════════════════════════════════════════════════════════════════╗
║ Key Takeaways ║
╚══════════════════════════════════════════════════════════════════╝
1. Hohmann transfers minimize delta-v but take longer
2. For large radius ratios (>11.94), bi-elliptic transfers can save fuel
3. Launch windows for interplanetary transfers repeat every synodic period
4. Delta-v requirements scale with the magnitude of the orbit change
For more examples, see:
- examples/bielliptic_transfer.py - Alternative 3-burn transfers
- examples/plane_change.py - Inclination changes
- examples/earth_mars_transfer.py - Real planetary positions
- examples/porkchop_plot.py - Launch window optimization
"""
)