Replace manual buffer management (malloc/free/snprintf) with a simple
stack-allocated TestOutput helper. Uses dump_simulation_state's 4-param
API with a single dump_state() method. Verification stays as individual
INFO() calls outside the loop.
Planning doc updates:
- Replace estimate table with actual measured values from DT sweep test
- Add 0.5s and 2.0s data points (69m and 228m respectively)
- Mark DT sweep tests as COMPLETED section
- Add analysis note about linear scaling with DT
New tests in test_maneuver_planning.cpp:
1. DT sweep: Hohmann transfer separation vs time step
- Runs full Hohmann transfer at DT = {0.1, 0.5, 1.0, 2.0, 5.0, 10.0}
- Verifies final separation matches expected ranges
- Confirms ecc < 0.01 for DT <= 1.0
2. DT sweep: quantization error is bounded by DT
- Tests 9 trigger offsets per DT value at DT = {1, 5, 10, 30}
- Verifies quantization error is always in [0, DT)
- Verifies execution time matches ceil-to-step-boundary
3. DT sweep: Hohmann arrival burn timing error
- Measures exact timing error at each DT
- Reports position error estimate (timing_error × velocity)
- Confirms timing error < DT
All 157 tests pass (240,742 assertions).
Previous: 154 tests, 240,445 assertions.
Rename src/rendezvous_hohmann.{h,cpp} to src/rendezvous.{h,cpp} and
tests/test_rendezvous_hohmann.{cpp,toml} to tests/test_rendezvous.{cpp,toml}.
This consolidates the rendezvous module under a simpler name since the
old CW-based rendezvous module was removed and only Hohmann transfer
functionality remains.
Update all includes, config paths, and Makefile references.
Reduce TIME_STEP from 10.0 to 0.1 and increase MAX_STEPS to 700000
to achieve sub-10m rendezvous accuracy. Update milestone dump timing
to correctly capture pre/post-burn states. Revert test config to
original values to match test expectations.
Remove src/rendezvous.h, src/rendezvous.cpp, tests/test_rendezvous.cpp,
and tests/test_rendezvous.toml. No other modules depend on these files.
Also remove RendezvousState enum, RendezvousTarget struct, and
rendezvous_target field from Spacecraft in orbital_objects.h.
For coplanar orbits (inclination < 0.01 rad), compute omega from the
eccentricity vector (longitude of periapsis) instead of forcing omega=0.
This is necessary for correct post-burn orbital element conversion,
critical for Hohmann transfer accuracy.
Update test_omega_debug to accept the new behavior: omega is computed
from the eccentricity vector direction for coplanar orbits.
- Move RendezvousState and RendezvousTarget from rendezvous_types.h to orbital_objects.h
- Remove rendezvous_types.h entirely
- Simplify rendezvous.h to depend on orbital_objects.h
- Delete spacecraft.h and spacecraft.cpp (consolidated into orbital_objects.h)
- Update all include paths across codebase
- All tests pass (4 pre-existing failures unchanged)
- Add scheduled_dt field to Maneuver struct for precise timing
- Propagate spacecraft to exact trigger position before burn execution
- Handle 2π→0 wraparound in trigger crossing detection
- Add spacecraft tracking to prevent double-propagation in same frame
- Fix test configs and tolerances for new behavior
All 143 tests passing.
- Fix omega = π bug for near-zero inclination orbits (src/orbital_mechanics.cpp:277)
- Added inclination threshold (0.01 rad) before using atan2 path
- Prevents unstable omega calculation when h_vec.y is tiny
- Fix true anomaly trigger firing at wrong location (src/maneuver.cpp:172-213)
- Replaced binary search with O(1) analytical time calculation
- Uses mean motion: n = √(μ/a³) to compute exact time to target
- Added true_anomaly_to_eccentric_anomaly() function
See docs/planning/periapsis_burn_bug_analysis.md for technical details
See docs/periaapsis_burn_test_results.md for test results and next steps
Test status:
- Issue 1 (omega): ✅ FIXED and validated
- Issue 2 (triggers): ✅ IMPLEMENTED, 4 tests fail due to design (expected behavior)
- Full suite: 139 passed, 4 failed (all periapsis burn tests)
Next steps: Decide on test tolerance approach (see docs/periaapsis_burn_test_results.md)
Added planning document detailing two separate issues causing
periapsis burns to execute at incorrect locations:
Issue 1: Omega = π instead of 0 for near-zero inclination orbits
- Unstable atan2 calculation in cartesian_to_orbital_elements()
- Occurs when n_mag > 1e-10 due to tiny h_vec.y from i ≈ 0
- Fix: Add inclination threshold (0.01 rad) before using atan2 path
Issue 2: True anomaly trigger fires early at wrong location
- angle_between() detects upcoming crossing, fires immediately
- Executes burn at current position instead of waiting for target angle
- Proposed fixes: Defer execution, interpolate, or remove future check
Also cleaned up:
- Removed temporary debug files (debug_test_burn.cpp, debug_trace.cpp)
- Removed debug output from src/orbital_mechanics.cpp
- Kept tests/test_omega_debug.cpp as it validates Issue 1 fix
See docs/planning/periapsis_burn_bug_analysis.md for full details.
Added test cases that reveal the bug where periapsis burns execute
at apoapsis instead of periapsis after the first burn.
Changes:
- Modified tests/test_periapsis_burn.toml to include second spacecraft
(TestSatelliteCrossing) starting at true_anomaly = 1.57
- Replaced test "Prograde burn at periapsis raises apoapsis" with
"Two periapsis burns execute at same location" to verify sequential
periapsis burns one orbit apart both fire at correct location
- Added test "Periapsis burn fires when crossing periapsis" to verify burn
triggers when spacecraft crosses periapsis from 90 degrees
Both new tests fail as expected, confirming the bug exists in
cartesian_to_orbital_elements() where argument_of_periapsis is
calculated as π instead of 0 after a burn.
Test status: 4 periapsis tests fail (capturing bug)
Swap order in update_simulation() to check maneuvers before physics update.
This ensures triggers fire at the correct position instead of after the
spacecraft has moved past the trigger point.
Also fix test config to avoid interference between time-based and true
anomaly triggers.
Documents a bug where true anomaly triggers set to 0 (periapsis) don't
execute because the spacecraft moves past periapsis before the trigger
check happens. The trigger check occurs after physics propagation in the
simulation update order.
- test_periapsis_burn.cpp: Three test cases demonstrating expected behavior
1. Verify periapsis distance is preserved after prograde burn (fails - shows bug)
2. Verify apoapsis raises and periapsis stays same (skipped - depends on fix)
3. Verify burn location equals new periapsis (skipped - depends on fix)
- test_periapsis_burn.toml: Test configuration with elliptical orbit satellite
starting at periapsis with a true anomaly trigger at 0
- Switch spacecraft and bodies from RK4 to analytical propagation using propagate_orbital_elements()
- Fixed three bugs in hyperbolic orbit propagation (formula errors and insufficient Newton-Raphson iterations)
- Add orbital element reconstruction after burns and SOI transitions
- Zero energy drift for circular, elliptical, parabolic, and hyperbolic orbits
- All 132 tests passing (240,294 assertions)
Moved configs to flatten directory structure:
- test_extreme_orientation_mixed.toml
- test_extreme_timescales.toml
- test_hybrid_burns.toml
- test_hybrid_energy_conservation.toml
Updated corresponding test files to use new paths:
- test_extreme_orientation_mixed.cpp
- test_extreme_timescales.cpp
- test_hybrid_burns.cpp
- test_hybrid_energy_conservation.cpp
All 240,294 assertions passing in 132 test cases
- Combined test_cartesian_to_elements_extreme.cpp (263 lines) and
test_cartesian_to_elements_quadrature.cpp (264 lines) into
test_cartesian_to_elements_advanced.cpp (508 lines, -19 lines saved)
- All 30 test cases preserved (16 from extreme + 14 from quadrature)
- No config files to merge (tests use hardcoded values)
- Added helper functions: find_maneuver_by_name() and execute_maneuver_by_name()
- Modified Hohmann transfer test to use maneuver system via execute_maneuver()
- Modified large burns test to use maneuver system
- Modified energy conservation test to use maneuver system (prograde burn)
- Modified round-trip conversion test to use maneuver system
- Modified multiple burn sequences to use maneuver system for Hohmann transfer
- Tests now properly validate maneuver trigger and execution workflow
- All tests pass (96 assertions in 7 test cases)
- Tests energy comparison between analytical and numerical propagation
- Validates analytical propagation maintains zero energy drift
- Verifies numerical propagation has controlled, expected energy drift
- Tests energy comparison for circular, elliptical, high eccentricity, inclined, fast, and slow orbits
- Tests pre/post burn energy validation (ΔE = v·Δv + 0.5Δv²)
- Tests long-term energy drift comparison (10 orbits)
- Tests energy accuracy across all orbit types
- Validates analytical propagation is more energy-stable than numerical
- Tests fast orbits (LEO, Mercury-like) for numerical precision
- Tests slow orbits (Jupiter-like) for mean anomaly accumulation
- Tests low altitude and super-synchronous orbits
- Validates geosynchronous orbit period accuracy
- Tests period consistency across different true anomalies
- Validates energy conservation across all timescales
- Add solve_barker_equation() function using cubic formula: D + D³/3 = M
- Integrate Barker's equation into propagate_orbital_elements() for parabolic orbits
- Add comprehensive test suite (11 tests, 239 assertions) following TDD
- Use cbrt() for cube root (handles negative numbers properly)
- Parabolic propagation now uses exact analytical solution instead of iterative solver
- All 93 tests passing (239,872 assertions)
- Add 16 minimal comments documenting formulas in orbital_mechanics.cpp
- Fix parabolic test to use orbital_elements_to_cartesian() instead of manual velocity
- Tighten parabolic test tolerance from 1e10 to 1e3 (7 orders of magnitude)
- Reduce parabolic test error from 6.5% to machine precision
- Convert 64 test assertions from Approx() to WithinAbs() in 2 new test files
- Add WithinAbs() testing guidelines to AGENTS.md
- Fix cartesian_to_orbital_elements(): eccentricity vector calculation,
true anomaly normalization, parabolic semi-latus rectum handling
- Add 2 new test files for edge cases and quadrature points
New modular API:
- solve_kepler_elliptical(M, e): Newton-Raphson for E - e·sin(E) = M
- solve_kepler_hyperbolic(M, e): Solver for H - e·sinh(H) = M
- eccentric_to_true_anomaly(E, e): Convert eccentric to true anomaly
- hyperbolic_to_true_anomaly(H, e): Convert hyperbolic to true anomaly
- mean_anomaly_to_true_anomaly(M, e): Unified wrapper (dispatches based on e)
Changes:
- Renamed solve_kepler_equation() → solve_kepler_elliptical() for clarity
- Extracted KEPLER_TOLERANCE and KEPLER_MAX_ITERATIONS constants
- Separated hyperbolic solver logic from combined function
- Fixed test_newton_raphson_convergence to verify Kepler's equation
(instead of incorrectly expecting E ≈ M for small e)
- Added TODO comment for future cartesian_to_orbital_elements refactoring
Config changes:
- 'Slightly_Hyperbolic': e=1.05, a=-1.3e8 (perigee at 6.5e6 m)
- 'Near_Parabolic': e=0.99, a=7.0e8 (perigee at 7e6 m)
Test changes:
- Added check for hyperbolic orbit anomaly limits (|ν| < arccos(-1/e))
- Skip testing ν=π and 3π/2 when they exceed valid range for e>1
Added 6 test files for Newton-Raphson solver and analytical propagation:
- test_cartesian_to_elements_basic.cpp: Tests state vector ↔ orbital elements conversion
- test_newton_raphson_convergence.cpp: Tests Newton-Raphson solver convergence behavior
- test_analytical_propagation_apsides.cpp: Tests propagation through orbital apsides
- test_analytical_propagation_timesteps.cpp: Tests propagation with various timesteps
- test_extreme_eccentricity.cpp: Tests near-parabolic and hyperbolic orbits
- test_precision_boundaries.cpp: Tests exact boundary value handling
Implemented core orbital mechanics functions:
- solve_kepler_equation(): Newton-Raphson solver with 1e-10 tolerance
- get_initial_trial_value(): Series expansion initial guess
- cartesian_to_orbital_elements(): State vectors to orbital elements conversion
- propagate_orbital_elements(): Analytical propagation using Kepler's equation
Updated test plan document with current progress and remaining tests.
Test status: 66 passed, 14 failed (out of 80 test cases)
- Failing tests are expected: implementation needs debugging
- Config validation issues fixed by adjusting orbital parameters
- Add StabilityResult struct to capture per-body results
- Add print_summary() function that displays formatted test results
- Summary includes:
- Stability criteria explanation
- Per-body results table with stability status
- Overall analysis with recommendations
- Current time step assessment
- Status shows current dt=60s is very stable with good margin
- Can be increased significantly if needed for faster simulation
- Create tests/informational/ for diagnostic/informational tests not in main suite
- Move test_time_step_stability.{cpp,toml} from tests/ to informational/
- Add README.md documenting informational tests purpose and usage
- Add dedicated Makefile for building informational tests separately
- Tests find maximum stable time step for RK4 integration across different orbital regimes
- Limiting factor is Mercury orbiter (12h period): max stable dt = 270s
- Current default 60s is very stable with good margin
- Add orbital element fields to OrbitTracker struct (inclination, RAAN, argument_of_periapsis)
- Create create_orbit_tracker_3d() for initializing with orbital elements
- Modify update_orbit_tracker() to use inverse rotation matrix for angle calculation
- Transform 3D position back to orbital plane before computing angle
- Update Molniya period test to use 3D tracker and relaxed tolerance (30 min)
- Remove remaining [!mayfail] tags
All 47 test cases now pass with 239,431 assertions