5.1 KiB
Parabolic Orbit Union Implementation Plan
Overview
Add support for parabolic orbits (e≈1.0) using semi-latus rectum parameter p instead of the current hacky semi_major_axis = 1.0e30 infinity approximation.
Problem
Current implementation uses semi_major_axis = 1.0e30 to approximate infinity for parabolic orbits, causing:
- Numerical precision issues with extremely large distances (~6.68e18 AU)
- Velocities approaching zero (1.6e-08 km/s instead of ~42 km/s escape velocity)
- Test failures due to floating-point equality (final_distance ≈ initial_distance)
Solution
Use a union in OrbitalElements struct to support both semi_major_axis (for elliptical/hyperbolic) and semi_latus_rectum (for parabolic).
Mathematical Background
For parabolic orbits (e=1.0), the semi-major axis is theoretically infinity. Using semi-latus rectum p is mathematically correct:
Position: r = p / (1 + cos(ν))
Velocity: v = √(2μ / r)
Where:
p= semi-latus rectumν= true anomalyμ= GM (gravitational parameter)
For parabolic orbits: p = 2q where q is perihelion distance
Implementation Steps
Phase 1: Update OrbitalElements Struct
File: src/orbital_mechanics.h
struct OrbitalElements {
union {
double semi_major_axis; // for elliptical (e<1) and hyperbolic (e>1)
double semi_latus_rectum; // for parabolic (e≈1)
};
double eccentricity;
double true_anomaly;
double inclination;
double longitude_of_ascending_node;
double argument_of_periapsis;
};
Phase 2: Update Config Loader
File: src/config_loader.cpp
Add to parse_toml_body() and parse_toml_spacecraft():
- Parse both
semi_major_axisandsemi_latus_rectumfrom orbit table - Initialize union field based on which is specified
- Validate exactly one is present per eccentricity range
Validation Logic:
bool has_semi_major = (semi_major.type == TOML_FP64);
bool has_semi_latus = (semi_latus.type == TOML_FP64);
if (fabs(elements.eccentricity - 1.0) < 0.005) {
// Parabolic orbit - requires semi_latus_rectum
if (!has_semi_latus) {
printf("Error: Parabolic orbit requires 'semi_latus_rectum'\n");
return false;
}
if (has_semi_major) {
printf("Error: Parabolic orbit cannot have 'semi_major_axis'\n");
return false;
}
elements.semi_latus_rectum = semi_latus.u.fp64;
} else {
// Elliptical or hyperbolic - requires semi_major_axis
if (!has_semi_major) {
printf("Error: Elliptical/hyperbolic orbit requires 'semi_major_axis'\n");
return false;
}
if (has_semi_latus) {
printf("Error: Elliptical/hyperbolic orbit cannot have 'semi_latus_rectum'\n");
return false;
}
elements.semi_major_axis = semi_major.u.fp64;
}
Phase 3: Update orbital_mechanics.cpp
File: src/orbital_mechanics.cpp
Update parabolic case (line 21-23):
} else if (fabs(e - 1.0) < 0.005) {
double p = elements.semi_latus_rectum;
r = p / (1.0 + cos(nu));
v_mag = sqrt(2.0 * mu / r);
}
Remove the 2.0 * a approximation that requires a=1.0e30.
Phase 4: Update Test Configs
File: tests/configs/parabolic_comet.toml
Replace semi_major_axis = 1.0e30 with semi_latus_rectum = 1.496e11 (p = 1 AU):
[[bodies]]
name = "ParabolicComet"
mass = 1.0e14
radius = 5.0e3
parent_index = 0
color = { r = 0.7, g = 0.8, b = 0.9 }
orbit = {
semi_latus_rectum = 1.496e11,
eccentricity = 1.0,
true_anomaly = 0.0
}
Phase 5: Update Documentation
File: docs/technical_reference.md
- Update
OrbitalElementsstruct documentation to show union - Add note about
semi_latus_rectumbeing required for parabolic orbits (e≈1.0) - Document
semi_latus_rectumin config format section
File: docs/unified_orbital_elements_plan.md
Mark union implementation as complete in Phase 7 status.
Validation Steps
- Build:
make clean && make - Run parabolic test:
./orbit_test '[parabolic]' - Verify velocity is correct: should be ~42,127 m/s escape velocity at 1 AU
- Verify energy is ~0 (parabolic orbits have total energy = 0)
Decisions Made
Default Behavior
No backward compatibility for semi_major_axis on parabolic orbits - require explicit semi_latus_rectum for all parabolic configs. This is cleaner than trying to auto-convert p = 2*a.
Spacecraft Altitude Parameter
Spacecraft altitude parameter is not supported for parabolic orbits in this implementation. If user specifies altitude with eccentricity ≈ 1.0, the config loader will require semi_latus_rectum instead and reject altitude or semi_major_axis. Added to future todos for Phase 8+.
Parabolic Detection Tolerance
Using |e - 1.0| < 0.005 as threshold for detecting parabolic orbits. This matches tolerance used elsewhere in the codebase.
Future Enhancements (TODO)
- Spacecraft
altitudeparameter for parabolic orbits: parsealtitudeand convert tosemi_latus_rectum = parent_radius + altitudewhen eccentricity is parabolic - Consider adding explicit
perihelionparameter to config file, then derivesemi_latus_rectum = 2 * perihelionfor parabolic orbits