import numpy as np
from astrora._core import lambert_solve
MU_SUN = 1.32712440018e11
def get_planet_state_simple(body_name, angle_deg):
if body_name.lower() == "earth":
a = 149.6e6 mu = MU_SUN
elif body_name.lower() == "mars":
a = 227.9e6 mu = MU_SUN
else:
raise ValueError(f"Unknown planet: {body_name}")
v_circ = np.sqrt(mu / a)
theta = np.deg2rad(angle_deg)
position = np.array([a * np.cos(theta), a * np.sin(theta), 0.0])
velocity = np.array([-v_circ * np.sin(theta), v_circ * np.cos(theta), 0.0])
return position, velocity
def compute_earth_mars_transfer_simple(tof_days, earth_angle=0, short_way=True):
tof_seconds = tof_days * 86400
print(f"\n{'='*60}")
print(f"Earth-Mars Transfer Mission (Simplified)")
print(f"{'='*60}")
print(f"Time of flight: {tof_days:.1f} days ({tof_days/30.44:.1f} months)")
print(f"Earth departure angle: {earth_angle:.1f}°")
print(f"{'='*60}\n")
r_earth, v_earth = get_planet_state_simple("earth", earth_angle)
print(f"Earth at departure:")
print(f" Position: [{r_earth[0]:,.0f}, {r_earth[1]:,.0f}, {r_earth[2]:,.0f}] km")
print(f" Velocity: [{v_earth[0]:.3f}, {v_earth[1]:.3f}, {v_earth[2]:.3f}] km/s")
print(f" |r| = {np.linalg.norm(r_earth):,.0f} km ({np.linalg.norm(r_earth)/1.496e8:.3f} AU)")
print(f" |v| = {np.linalg.norm(v_earth):.3f} km/s\n")
earth_period = 365.25 mars_period = 686.98
earth_angular_vel = 360.0 / earth_period
mars_angular_vel = 360.0 / mars_period
mars_angle = earth_angle + (mars_angular_vel * tof_days)
r_mars, v_mars = get_planet_state_simple("mars", mars_angle)
print(f"Mars at arrival:")
print(f" Position: [{r_mars[0]:,.0f}, {r_mars[1]:,.0f}, {r_mars[2]:,.0f}] km")
print(f" Velocity: [{v_mars[0]:.3f}, {v_mars[1]:.3f}, {v_mars[2]:.3f}] km/s")
print(f" |r| = {np.linalg.norm(r_mars):,.0f} km ({np.linalg.norm(r_mars)/1.496e8:.3f} AU)")
print(f" |v| = {np.linalg.norm(v_mars):.3f} km/s\n")
print(f"Solving Lambert's problem...")
result = lambert_solve(
r1=r_earth, r2=r_mars, tof=tof_seconds, mu=MU_SUN, short_way=short_way, revs=0
)
v1 = result["v1"] v2 = result["v2"]
print(f"Transfer orbit solution:")
print(f" v1: [{v1[0]:.3f}, {v1[1]:.3f}, {v1[2]:.3f}] km/s")
print(f" v2: [{v2[0]:.3f}, {v2[1]:.3f}, {v2[2]:.3f}] km/s")
print(f" |v1| = {np.linalg.norm(v1):.3f} km/s")
print(f" |v2| = {np.linalg.norm(v2):.3f} km/s\n")
dv_departure = np.linalg.norm(v1 - v_earth)
dv_arrival = np.linalg.norm(v2 - v_mars)
dv_total = dv_departure + dv_arrival
v_infinity = v1 - v_earth
c3 = np.linalg.norm(v_infinity) ** 2
print(f"Delta-v Requirements:")
print(f"{'='*60}")
print(f" At Earth departure: {dv_departure:.3f} km/s")
print(f" At Mars arrival: {dv_arrival:.3f} km/s")
print(f" Total delta-v: {dv_total:.3f} km/s")
print(f"{'='*60}\n")
print(f"C3 Characteristic Energy:")
print(f"{'='*60}")
print(f" C3 = {c3:.2f} km²/s²")
print(f" v∞ = {np.sqrt(c3):.3f} km/s (hyperbolic excess velocity)")
print(f"\n Launch vehicle capability required:")
if c3 < 15:
print(f" ✓ Atlas V 551 capable (C3 max ~15 km²/s²)")
print(f" ✓ Falcon 9 capable (C3 max ~30 km²/s²)")
elif c3 < 25:
print(f" ✗ Atlas V 551 insufficient")
print(f" ✓ Delta IV Heavy capable (C3 max ~25 km²/s²)")
print(f" ✓ Falcon 9 capable (C3 max ~30 km²/s²)")
elif c3 < 30:
print(f" ✗ Delta IV Heavy insufficient")
print(f" ✓ Falcon 9 (expendable) capable (C3 max ~30 km²/s²)")
elif c3 < 40:
print(f" ✗ Falcon 9 insufficient")
print(f" ✓ Falcon Heavy capable (C3 max ~40 km²/s²)")
else:
print(f" ⚠ Requires Falcon Heavy or SLS (C3 max ~45 km²/s²)")
print(f"{'='*60}\n")
print(f"Transfer Orbit Elements:")
print(f" Semi-major axis: {result['a']:,.0f} km ({result['a']/1.496e8:.3f} AU)")
print(f" Eccentricity: {result['e']:.4f}")
e = result["e"]
if e < 1:
print(f" Orbit type: Elliptic (e < 1)")
a = result["a"]
period_seconds = 2 * np.pi * np.sqrt(a**3 / MU_SUN)
period_days = period_seconds / 86400
print(f" Orbital period: {period_days:.1f} days ({period_days/365.25:.2f} years)")
elif e > 1:
print(f" Orbit type: Hyperbolic (e > 1)")
else:
print(f" Orbit type: Parabolic (e = 1)")
print(f"\n{'='*60}\n")
return {
"r_earth": r_earth,
"v_earth": v_earth,
"r_mars": r_mars,
"v_mars": v_mars,
"v1": v1,
"v2": v2,
"dv_departure": dv_departure,
"dv_arrival": dv_arrival,
"dv_total": dv_total,
"c3": c3,
"v_infinity": np.sqrt(c3),
"tof_days": tof_days,
"transfer_orbit": result,
}
def example_hohmann_transfer():
print("\n" + "=" * 60)
print("Example 1: Hohmann Transfer to Mars")
print("=" * 60)
result = compute_earth_mars_transfer_simple(tof_days=259, earth_angle=0, short_way=True)
print("\nMission Summary:")
print(f" This represents a Hohmann transfer to Mars.")
print(f" Total mission delta-v: {result['dv_total']:.2f} km/s")
print(f" C3 energy: {result['c3']:.2f} km²/s²")
print(f" Transfer time: {result['tof_days']:.0f} days")
print(f" Transfer orbit eccentricity: {result['transfer_orbit']['e']:.3f}")
def example_fast_transfer():
print("\n" + "=" * 60)
print("Example 2: Fast Transfer to Mars (200 days)")
print("=" * 60)
result = compute_earth_mars_transfer_simple(tof_days=200, earth_angle=0, short_way=True)
print("\nMission Summary:")
print(f" Faster transfer requires more delta-v than Hohmann transfer.")
print(f" Total mission delta-v: {result['dv_total']:.2f} km/s")
print(f" C3 energy: {result['c3']:.2f} km²/s² (vs Hohmann: lower)")
print(f" Transfer time: {result['tof_days']:.0f} days")
print(f" Transfer orbit eccentricity: {result['transfer_orbit']['e']:.3f}")
print(f" Trade-off: -23% time compared to Hohmann (259 days)")
print(f" Trade-off: Higher C3 may require larger launch vehicle")
if __name__ == "__main__":
print(
"""
╔══════════════════════════════════════════════════════════════╗
║ Earth-Mars Transfer Mission Planning Example ║
║ Using Astrora's Lambert Solver ║
╚══════════════════════════════════════════════════════════════╝
This example demonstrates interplanetary trajectory design using
Lambert's problem to solve for transfer orbits between planets.
"""
)
example_hohmann_transfer()
print("\n" + "=" * 60 + "\n")
example_fast_transfer()
print(
"""
╔══════════════════════════════════════════════════════════════╗
║ Next Steps ║
╚══════════════════════════════════════════════════════════════╝
1. Optimize launch windows using porkchop plots (see porkchop_plot.py)
2. Account for parking orbit escape and capture burns
3. Consider gravity assists for outer planet missions
4. Add trajectory correction maneuvers (TCM) for mid-course corrections
For more examples, see:
- examples/porkchop_plot.py - Launch window optimization
- examples/gravity_assist.py - Multi-planet flybys
- examples/hohmann_transfer.py - Simple orbital transfers
"""
)