8.9 KiB
Plan: Add Molniya Orbit Test Case
Overview
Add test cases for highly inclined orbits, specifically focusing on Molniya orbits and generic inclined orbit behavior.
Background - Molniya Orbit Properties
From Wikipedia research, Molniya orbits are designed for high-latitude coverage:
- Orbital Period: ~718 minutes (~12 hours, half a sidereal day)
- Eccentricity: ~0.74
- Inclination: 63.4° (critical value that prevents perigee precession)
- Argument of Perigee: 270° (apogee at northernmost point)
- Perigee altitude: ~600 km
- Apogee altitude: ~39,700 km
- Semi-major axis: ~26,600 km
Current Codebase Status
Earth as Root Body
✅ SUPPORTED
- Validator checks:
parent_index < body_index or -1 - Earth can be root if it's first body (index 0)
- No special validation prevents this
3D Orientation Support
⚠️ DEFINED BUT NOT APPLIED
inclination,longitude_of_ascending_node,argument_of_periapsisexist inOrbitalElementsstructorbital_elements_to_cartesian()insrc/orbital_mechanics.cpponly produces 2D orbits (x, y, z=0)- Documented as "deferred implementation" in technical_reference.md line 114
- Config parser supports loading these parameters (src/config_loader.cpp)
- Test approach: Tests will expect 3D behavior and fail with
[!mayfail]tag
Implementation Plan
Step 1: Create Test Configuration File
File: tests/test_molniya.toml
# Test Configuration: Molniya Orbit
# Earth as root body with highly elliptical, highly inclined satellite orbit
[[bodies]]
name = "Earth"
mass = 5.972e24
radius = 6.371e6
parent_index = -1
color = { r = 0.0, g = 0.5, b = 1.0 }
orbit = {
semi_major_axis = 0.0,
eccentricity = 0.0,
true_anomaly = 0.0
}
[[spacecraft]]
name = "Molniya_Satellite"
mass = 1000.0
parent_index = 0
orbit = {
semi_major_axis = 26540000.0,
eccentricity = 0.74,
true_anomaly = 0.0,
inclination = 1.107, # 63.4° in radians
longitude_of_ascending_node = 0.0,
argument_of_periapsis = 4.71 # 270° in radians
}
Key points:
- Earth is root body (index 0, parent_index = -1)
- Spacecraft uses Molniya orbital parameters
- 3D orientation parameters included even though not applied yet
Step 2: Create Test File
File: tests/test_inclined_orbits.cpp
Test Cases:
-
Molniya Position Verification (tagged
[!mayfail])- Test satellite position at true_anomaly = 0 (perigee)
- Test satellite position at true_anomaly = π/2
- Test satellite position at true_anomaly = π (apogee)
- Test satellite position at true_anomaly = 3π/2
- Verify radii match polar equation: r = a(1-e²)/(1+e·cos(ν))
- Check z-coordinate ≠ 0 for inclined orbits (will fail until 3D implemented)
- Tolerance: ±10 km (10,000 meters)
-
Molniya Orbital Period (tagged
[!mayfail])- Verify period matches theoretical calculation from Kepler's 3rd law
- Theoretical period: T = 2π√(a³/μ)
- Use
OrbitTrackerwith minimum time to prevent false completion - Expected: ~11.96 hours
- Tolerance: ±600 seconds (10 minutes)
-
Generic Inclined Orbit (tagged
[!mayfail])- Test moderate inclination (45°) with e=0.5, a=10,000 km
- Verify z-coordinate is non-zero (will fail until 3D implemented)
- Verify position magnitude matches orbital radius
- Simpler case to test 3D orientation without Molniya complexity
-
Inclination Parameter Preservation
- Verify config loader correctly reads and preserves inclination value
- This should PASS (just checking config loading, not physics)
- Ensures 3D parameters are being stored correctly
Constants:
POSITION_TOLERANCE_METERS = 10000.0(±10 km per user request)PERIOD_TOLERANCE_SECONDS = 600.0(±10 minutes)
Step 3: Update Build System
Add test file to existing test build (Catch2 automatically includes all test_*.cpp files)
Step 4: Expected Behavior
Before 3D Implementation
- All tests with
[!mayfail]tag will run but failure is acceptable - Position tests: Pass radius check, fail on z-coordinate check
- Period test: May pass (period independent of inclination for same orbital energy)
- Generic inclined test: Fail on z-coordinate check
- Config preservation test: PASS (just checks config loading)
After 3D Implementation
- All position tests should PASS
- Period test should PASS
- Generic inclined test should PASS
- Config preservation test should PASS
- Remove
[!mayfail]tags from passing tests
Implementation Findings
Bug Discovered in Spacecraft Initialization
Location: src/config_loader.cpp lines 257-259
Code:
if (!is_parabolic && craft->parent_index >= 0 && craft->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[craft->parent_index];
craft->orbit.semi_major_axis += parent->radius; // BUG: Always adds parent radius
}
Problem:
- For spacecraft, code unconditionally adds parent radius to
semi_major_axis - For bodies, this logic does NOT exist (bodies use semi_major_axis as-is)
- This creates an inconsistency between body and spacecraft orbital definitions
- The logic was intended for
altitudeparameter convenience but is applied even whensemi_major_axisis specified directly
Impact on Molniya Tests:
- Config specifies:
semi_major_axis = 26,540,000 m - Actual used:
26,540,000 + 6,371,000 = 32,911,000 m - Position errors: 1.7M m at perigee, 11.1M m at apogee
- Orbital period: ~16.5 hours instead of expected ~12 hours
- All radius-based tests fail with errors far exceeding ±10 km tolerance
Root Cause: The config loader has these paths (simplified):
// For bodies:
if (semi_major_axis.type == TOML_FP64) {
body->orbit.semi_major_axis = semi_major.u.fp64; // Used directly
} else if (altitude.type == TOML_FP64) {
body->orbit.semi_major_axis = altitude.u.fp64; // Stored as altitude
}
// For spacecraft:
if (semi_major_axis.type == TOML_FP64) {
craft->orbit.semi_major_axis = semi_major.u.fp64; // Stored as SMA
} else if (altitude.type == TOML_FP64) {
craft->orbit.semi_major_axis = altitude.u.fp64; // Stored as altitude
}
// AFTER loading all spacecraft (line 253-260):
for (int i = 0; i < sim->craft_count; i++) {
Spacecraft* craft = &sim->spacecraft[i];
bool is_parabolic = (fabs(craft->orbit.eccentricity - 1.0) < 0.005);
if (!is_parabolic && craft->parent_index >= 0) {
CelestialBody* parent = &sim->bodies[craft->parent_index];
craft->orbit.semi_major_axis += parent->radius; // ALWAYS adds!
}
}
Required Fix:
The logic should only add parent radius when altitude was specified:
- Option A: Track which parameter was used during parsing
- Option B: Check if semi_major_axis < parent radius (altitude would be small)
- Option C: Only apply this transformation for altitude-based initialization
Additional Issues Found
OrbitTracker Not Completing
- Symptom: Molniya period test never completes orbit (tracker->orbit_completed = false)
- Possible causes:
- Minimum time threshold too restrictive (currently 0.01 days = 14.4 minutes)
- Quadrant transition logic failing for highly elliptical orbits
- Angle comparison tolerance too tight for large orbital variations
- Status: Not investigated yet, secondary priority to config bug
Test File Name Mismatch
- Original plan:
tests/test_molniya.toml - Actual created:
tests/test_inclined_orbits.toml(matches test file name) - Reason: User preference to have config filename match test filename
- Status: ✅ RESOLVED (updated config in final implementation)
Test Verification Formula
Orbital Radius at True Anomaly
r = a(1-e²) / (1 + e·cos(ν))
Where:
- a = semi-major_axis
- e = eccentricity
- ν = true_anomaly
Orbital Period (Kepler's 3rd Law)
T = 2π√(a³/μ)
Where:
- μ = G·M (standard gravitational parameter)
- M = parent body mass
Questions Resolved
- Tolerance: ±10 km (10,000 meters) - chosen as moderate tolerance for RK4 integration
- Test Scope: Both Molniya + generic inclined orbit tests for completeness
- 3D Status: Tests expect 3D and fail with
[!mayfail]tag, documenting expected behavior
Next Steps After This Plan
-
Implement 3D orientation in
src/orbital_mechanics.cpp- Apply rotation matrices for inclination, RAAN, and argument of periapsis
- Update
orbital_elements_to_cartesian()to include 3D transformations
-
Remove
[!mayfail]tags from tests that now pass -
Add additional 3D-specific tests:
- Verify correct orientation of orbital plane
- Test ascending/descending node crossings
- Verify argument of periapsis positioning
Files to Create
tests/test_molniya.toml(new test config)tests/test_inclined_orbits.cpp(new test file)
Files to Potentially Modify (future 3D implementation)
src/orbital_mechanics.cpp- add 3D rotation logicsrc/orbital_mechanics.h- potentially expose rotation helper functions