vibe coding an orbital mechanics simulation to try out claude code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

135 lines
4.6 KiB

#!/usr/bin/env python3
"""
Precalculate expected values for test_extreme_eccentricity.cpp.
Usage:
python3 scripts/precalc_extreme_eccentricity.py
Outputs C++-style comments with precalculated values for embedding in the test.
"""
import sys, math
sys.path.insert(0, 'scripts')
from sim_engine import orbital_to_cartesian, cartesian_to_orbital_elements, vmag, OrbitalElements, G
# Spacecraft 0: Highly_Elliptical (e=0.99, a=6.5e8)
mu = G * 5.972e24
a0 = 6.5e8
e0 = 0.99
nu0 = 0.0
elements0 = OrbitalElements(a=a0, e=e0, nu=nu0, inc=0.0, Omega=0.0, omega=0.0)
pos0, vel0 = orbital_to_cartesian(elements0, 5.972e24)
r0 = vmag(pos0)
v0 = vmag(vel0)
expected_r_peri0 = a0 * (1.0 - e0)
expected_r_apo0 = a0 * (1.0 + e0)
# Round-trip
elements0_rt = cartesian_to_orbital_elements(pos0, vel0, 5.972e24)
print("# Spacecraft 0: Highly_Elliptical (e=0.99, a=6.5e8)")
print(f"# r_peri = {expected_r_peri0:.6f} m")
print(f"# r_apo = {expected_r_apo0:.6f} m")
print(f"# r = {r0:.6f} m")
print(f"# v = {v0:.6f} m/s")
print(f"# dr = {abs(r0 - expected_r_peri0):.2e} m")
print(f"# dr_apo = {abs(r0 - expected_r_apo0):.2e} m")
print(f"# e_rt = {elements0_rt.e:.15f} (error: {abs(elements0_rt.e - e0):.2e})")
print(f"# a_rt = {elements0_rt.a:.6f} m")
print()
# Nu = pi (apoapsis)
elements0_pi = OrbitalElements(a=a0, e=e0, nu=math.pi, inc=0.0, Omega=0.0, omega=0.0)
pos0_pi, vel0_pi = orbital_to_cartesian(elements0_pi, 5.972e24)
r0_pi = vmag(pos0_pi)
v0_pi = vmag(vel0_pi)
print(f"# At apoapsis (nu=pi):")
print(f"# r = {r0_pi:.6f} m (expected: {expected_r_apo0:.6f} m)")
print(f"# v = {v0_pi:.6f} m/s")
print(f"# dr = {abs(r0_pi - expected_r_apo0):.2e} m")
print()
# Spacecraft 1: Near_Parabolic (e=0.99, a=7.0e8)
a1 = 7.0e8
e1 = 0.99
nu1 = 0.0
elements1 = OrbitalElements(a=a1, e=e1, nu=nu1, inc=0.0, Omega=0.0, omega=0.0)
pos1, vel1 = orbital_to_cartesian(elements1, 5.972e24)
r1 = vmag(pos1)
v1 = vmag(vel1)
expected_r_peri1 = a1 * (1.0 - e1)
expected_r_apo1 = a1 * (1.0 + e1)
# Apoapsis
elements1_pi = OrbitalElements(a=a1, e=e1, nu=math.pi, inc=0.0, Omega=0.0, omega=0.0)
pos1_pi, vel1_pi = orbital_to_cartesian(elements1_pi, 5.972e24)
r1_pi = vmag(pos1_pi)
v1_pi = vmag(vel1_pi)
print("# Spacecraft 1: Near_Parabolic (e=0.99, a=7.0e8)")
print(f"# r_peri = {expected_r_peri1:.6f} m")
print(f"# r_apo = {expected_r_apo1:.6f} m")
print(f"# r_peri_actual = {r1:.6f} m")
print(f"# v_peri = {v1:.6f} m/s")
print(f"# r_apo_actual = {r1_pi:.6f} m")
print(f"# v_apo = {v1_pi:.6f} m/s")
print(f"# dr_peri = {abs(r1 - expected_r_peri1):.2e} m")
print(f"# dr_apo = {abs(r1_pi - expected_r_apo1):.2e} m")
print(f"# v_peri > v_apo: {v1 > v1_pi}")
print()
# Spacecraft 2: Slightly_Hyperbolic (e=1.05, a=-1.3e8)
a2 = -1.3e8
e2 = 1.05
nu2 = 0.0
elements2 = OrbitalElements(a=a2, e=e2, nu=nu2, inc=0.0, Omega=0.0, omega=0.0)
pos2, vel2 = orbital_to_cartesian(elements2, 5.972e24)
r2 = vmag(pos2)
v2 = vmag(vel2)
escape_vel = math.sqrt(2.0 * mu / r2)
circular_vel = math.sqrt(mu / r2)
expected_v_sq = mu * (2.0 / r2 - 1.0 / a2)
expected_v = math.sqrt(expected_v_sq)
print("# Spacecraft 2: Slightly_Hyperbolic (e=1.05, a=-1.3e8)")
print(f"# r = {r2:.6f} m")
print(f"# v = {v2:.6f} m/s")
print(f"# v_exp = {expected_v:.6f} m/s")
print(f"# v_err = {abs(v2 - expected_v):.2e} m/s")
print(f"# rel_err = {abs(v2 - expected_v) / expected_v:.2e}")
print(f"# escape_vel = {escape_vel:.6f} m/s")
print(f"# circular_vel = {circular_vel:.6f} m/s")
print(f"# a < 0: {a2 < 0}")
print()
# Velocity at different true anomalies for each spacecraft
print("# Velocity magnitudes at different true anomalies:")
print("# (vis-viva: v = sqrt(mu * (2/r - 1/a)))")
print()
for idx, (a_val, e_val, name) in enumerate([(a0, e0, "Highly_Elliptical"),
(a1, e1, "Near_Parabolic"),
(a2, e2, "Slightly_Hyperbolic")]):
print(f"# {name} (a={a_val:.2e}, e={e_val:.2f}):")
for nu in [0.0, math.pi/2.0, math.pi, 3.0*math.pi/2.0]:
if e_val > 1.0:
max_nu = math.acos(-1.0 / e_val)
if abs(nu) >= max_nu:
print(f"# nu={nu:.4f} rad: SKIPPED (hyperbolic limit +/- {max_nu:.4f})")
continue
elem = OrbitalElements(a=a_val, e=e_val, nu=nu, inc=0.0, Omega=0.0, omega=0.0)
p, v = orbital_to_cartesian(elem, 5.972e24)
r = vmag(p)
v_mag = vmag(v)
v_exp = math.sqrt(mu * (2.0/r - 1.0/a_val))
rel_err = abs(v_mag - v_exp) / v_exp
print(f"# nu={nu:.4f} rad: v={v_mag:.6f} m/s, v_exp={v_exp:.6f} m/s, rel_err={rel_err:.2e}")
print()