16 KiB
Implementation Plan: Config-Based Spacecraft with Impulse Burn
Overview
Replace dynamic spacecraft spawning with config-based LEO spacecraft, implement patched conics impulse burn for Hohmann transfer, and add comprehensive test verification.
Date: January 18, 2026 Status: Ready to implement Branch: mission-planning
Phase 0: Git Workflow Preparation
Step 0.1: Stash debug changes on main
git stash push -m "Debug printf statements for spacecraft parent switch investigation"
Step 0.2: Checkout and update mission-planning branch
git checkout mission-planning
git rebase main # Or git merge main if cleaner
Step 0.3: Apply debug changes to mission-planning branch
git stash list # Verify stash exists
git stash pop # Apply debug changes
Verification: Confirm debug printf statements are in src/simulation.cpp after applying stash
Phase 1: Update Configuration File
Step 1.1: Add spacecraft to tests/configs/earth_mars_simple.toml
Add Spacecraft body to config with placeholder position/velocity (set at runtime by initialize_spacecraft_leo()).
Implementation: See tests/configs/earth_mars_simple.toml for full config
Key parameters:
- mass = 1.0 kg (test particle)
- radius = 1000.0 m
- parent_index = 1 (Earth)
- color = magenta (r=1.0, g=0.0, b=0.5)
- position/velocity: Placeholders (0,0,0)
TODO: Future config format should support:
- Earth-relative position:
{ altitude_km = 200.0 } - Earth-relative orbit:
{ orbit_type = "circular" } - More intuitive spacecraft mission parameters
Phase 2: Mission Planning Module - New Functions
Step 2.1: Add function declarations to src/mission_planning.h
Implementation: See src/mission_planning.h
Functions:
initialize_spacecraft_leo()- Initialize spacecraft in circular LEO around parent bodyapply_transfer_burn()- Apply patched conics impulse burn for Hohmann transfercalculate_phase_angle()- Calculate current phase angle between two bodies (in degrees)
Step 2.2: Implement initialize_spacecraft_leo() in src/mission_planning.cpp
Implementation: src/mission_planning.cpp:20-56
Algorithm:
- Calculate orbital radius = parent radius + altitude
- Position spacecraft radially outward from Sun (any angular position acceptable)
- Calculate circular LEO velocity: v = sqrt(G * M_parent / r)
- Set prograde orientation (tangential to Earth-Sun line)
- Set both local and global coordinates correctly
Key Points:
- LEO orbit is circular at 200km altitude (~7,788 m/s)
- Spacecraft velocity = Earth velocity + LEO velocity
- Local velocity = LEO velocity only (relative to Earth)
Step 2.3: Implement calculate_phase_angle() in src/mission_planning.cpp
Implementation: src/mission_planning.cpp:58-78
Algorithm:
- Calculate angular positions of departure and arrival bodies relative to Sun
- Compute phase difference: θ_arrival - θ_departure
- Normalize to [0°, 360°) range
- Return phase angle in degrees
Step 2.4: Implement apply_transfer_burn() in src/mission_planning.cpp
Implementation: src/mission_planning.cpp:80-116
Algorithm (Patched Conics Approach):
- Calculate required heliocentric transfer velocity magnitude from params
- Determine prograde direction (tangential to departure-Sun line)
- Compute delta-v: Δv = v_transfer - v_current (vector subtraction)
- Apply impulse to spacecraft velocity
- Update local velocity relative to departure body
- Print burn information for debugging
Note: Simplified single-impulse approximation. True patched conics would:
- Calculate Δv to reach SOI boundary
- Calculate velocity at SOI boundary
- Add transfer Δv at SOI boundary
- Combine into equivalent single impulse
Phase 3: Comprehensive Test Case
Step 3.1: Create new test in tests/test_hohmann_transfer.cpp
Implementation: tests/test_hohmann_transfer.cpp - See file for full test
Test: "Earth → Mars Hohmann Transfer with LEO Spacecraft"
Test Structure:
- Load config with 4 bodies (Sun, Earth, Mars, Spacecraft)
- Initialize spacecraft in 200km LEO around Earth
- Verify LEO orbit stability (parent, position, velocity, energy)
- Calculate Hohmann transfer parameters
- Wait for Earth-Mars launch window (within 1° tolerance)
- Verify phase angle accuracy
- Apply impulse burn for transfer
- Verify post-burn energy >= 0 (escape trajectory)
- Simulate transfer for 110% of expected duration
- Track SOI transitions (Earth→Sun→Mars)
- Verify final parent and energy conservation (<5% drift)
- If Mars SOI entry, verify distance (<2×SOI)
Key Assertions:
- Config loading: 4 bodies loaded, spacecraft present
- LEO stability: parent=Earth, position <1km error, velocity <10m/s error, energy <0
- Launch window: opens in ~94 days, phase error <1°
- Transfer: post-burn energy >= 0, Earth→Sun SOI transition, energy conservation
Phase 4: Build and Test
Step 4.1: Update Makefile (if needed)
Verify mission_planning.o is in OBJECTS list and build rule exists.
Step 4.2: Build test executable
make clean
make test-build
Step 4.3: Run comprehensive test
./orbit_test -s 'Earth → Mars Hohmann Transfer with LEO Spacecraft'
Step 4.4: Verify all tests still pass
make test
Phase 5: Cleanup and Documentation
Step 5.1: Remove deprecated function
Remove spawn_spacecraft_on_transfer() from:
src/mission_planning.hsrc/mission_planning.cpp
Step 5.2: Update mission planning documentation
Update docs/mission_planning.md:
- Mark Phase 4 as complete
- Note config-based approach implemented
- Document patched conics impulse burn
- Remove spawn_spacecraft_on_transfer references
Step 5.3: Add TODO comment for config format
Add in docs/mission_planning.md:
TODO: Future config file format improvements:
- Support Earth-relative position specification (e.g., { altitude_km = 200.0 })
- Support Earth-relative orbit specification (e.g., { orbit_type = "circular" })
- More intuitive spacecraft mission parameters
Summary of Changes
New Files/Functions Added
initialize_spacecraft_leo()- Initialize spacecraft in LEOapply_transfer_burn()- Apply patched conics impulse burncalculate_phase_angle()- Calculate phase angle between bodies- Comprehensive test case with SOI transition tracking
Files Modified
tests/configs/earth_mars_simple.toml- Add spacecraft bodysrc/mission_planning.h- Add function declarationssrc/mission_planning.cpp- Implement new functionstests/test_hohmann_transfer.cpp- Add comprehensive test
Functions Removed
spawn_spacecraft_on_transfer()- Still present in code but no longer used
Current Issue Identified
Problem: Incorrect Delta-V Direction After Multi-Day Wait
Symptom:
- Spacecraft enters LEO orbit correctly with negative energy (bound to Earth)
- Waits 94 days for Earth-Mars launch window
- During wait period, spacecraft completes ~6.3 LEO orbits
- LEO orbit phase changes significantly over 94 days
- After wait,
apply_transfer_burn()applies delta-v assuming spacecraft is at Earth's current orbital phase - Result: Delta-v applied in wrong direction, resulting in retrograde burn
- Post-burn energy remains negative (spacecraft still bound to Earth)
Root Cause Analysis:
The apply_transfer_burn() function calculates:
- Required heliocentric transfer velocity magnitude:
v_transfer = 32,697 m/s - Prograde direction based on Earth's current position:
transfer_dir = prograde(t_current) - Target velocity:
v_target = v_transfer * transfer_dir
However, after 94 days:
- Earth has moved to different orbital phase
- Spacecraft in LEO is still orbiting Earth
- Spacecraft's current heliocentric velocity includes Earth's motion + LEO motion
- The calculated transfer direction is based on Earth's instantaneous position, not spacecraft's actual heliocentric velocity vector
- This results in delta-v that doesn't account for spacecraft's phase in LEO
What Should Happen:
- Calculate spacecraft's current heliocentric velocity vector:
v_current - Calculate required heliocentric velocity for transfer orbit:
v_transfer - Apply delta-v:
Δv = v_transfer - v_current(vector subtraction, not magnitude-based)
What Currently Happens:
- Assumes spacecraft starts at Earth's orbital position (ignores LEO phase)
- Calculates transfer direction based on Earth's current prograde vector
- Applies magnitude-based delta-v without considering spacecraft's actual velocity direction
- Results in incorrect burn direction
Solution Required
Modify apply_transfer_burn() to:
- Calculate spacecraft's actual heliocentric velocity:
Vec3 v_current_helio = spacecraft->velocity; // Already in global frame
- Calculate required heliocentric transfer velocity:
double v_transfer_mag = params->departure_velocity; // ~32,697 m/s
// Direction: prograde to Sun (same as Earth's orbital direction)
Vec3 sun_to_earth = vec3_sub(departure->position, sun->position);
Vec3 sun_to_earth_norm = vec3_normalize(sun_to_earth);
Vec3 transfer_dir = (Vec3){-sun_to_earth_norm.y, sun_to_earth_norm.x, 0.0};
Vec3 v_transfer_helio = vec3_scale(transfer_dir, v_transfer_mag);
- Calculate delta-v as vector difference:
Vec3 delta_v = vec3_sub(v_transfer_helio, v_current_helio);
- Apply impulse:
spacecraft->velocity = vec3_add(spacecraft->velocity, delta_v);
spacecraft->local_velocity = vec3_sub(spacecraft->velocity, departure->velocity);
This approach:
- Accounts for spacecraft's actual heliocentric velocity (includes LEO phase)
- Uses vector subtraction instead of magnitude-based calculation
- Produces correct delta-v direction regardless of LEO phase
- Should result in positive post-burn energy (escape trajectory)
Potential Issues and Mitigation
Issue 1: LEO Orbit Position Sensitivity
Spacecraft LEO phase may affect optimal launch window timing.
Mitigation: Test shows we wait for Earth-Mars phase angle, not spacecraft-LEO phase. This should be acceptable.
Issue 2: Impulse Burn Accuracy
Single-impulse approximation may not match true patched conics trajectory.
Mitigation: Initial test focuses on Earth→Sun transition and energy conservation. If needed, can refine to two-impulse burn in future.
Issue 3: Mars SOI Entry
Spacecraft may not enter Mars SOI due to:
- Phase angle tolerance (1°)
- Transfer time approximation
- Impulse burn simplifications
Mitigation: Test includes explicit INFO messages and requires only Earth→Sun transition, not Mars arrival.
Timeline Estimate
- Phase 0 (Git workflow): 10 minutes
- Phase 1 (Config update): 5 minutes
- Phase 2 (Mission planning): 1-2 hours
- Phase 3 (Comprehensive test): 30 minutes
- Phase 4 (Build and test): 20 minutes
- Phase 5 (Cleanup): 20 minutes
Total: 2-3 hours
Test Configuration Reference
earth_mars_simple.toml
Implementation: tests/configs/earth_mars_simple.toml
Bodies:
- Sun (index 0): Root body, 1.989e30 kg
- Earth (index 1): 5.972e24 kg, 1.496e11 m from Sun
- Mars (index 2): 6.39e23 kg, 2.279e11 m from Sun
- Spacecraft (index 3): 1.0 kg, parent=Earth (position/velocity set at runtime)
Spacecraft parameters:
- mass = 1.0 kg
- radius = 1000.0 m
- parent_index = 1 (Earth)
- color = magenta (r=1.0, g=0.0, b=0.5)
- position/velocity: Placeholders (0,0,0) - set by
initialize_spacecraft_leo()
Future Work (Post-Implementation)
Immediate Next Steps
1. Config Format Improvements
- Support Earth-relative position specification (e.g.,
{ altitude_km = 200.0 }) - Support Earth-relative orbit specification (e.g.,
{ orbit_type = "circular" }) - More intuitive spacecraft mission parameters in TOML config
- Support multiple spacecraft in single config file
2. Improved Patched Conics Implementation
- Calculate Δv to reach SOI boundary (escape trajectory)
- Calculate velocity at SOI boundary
- Add transfer Δv at SOI boundary
- Combine into equivalent single impulse
- Test accuracy of two-impulse vs single-impulse approach
3. Inclination Support
- Extend to 3D transfers
- Need 3D angular position calculations
- Longitude of ascending node, inclination, argument of periapsis
- Phase angle calculations in 3D
- Out-of-plane maneuver calculations
4. Capture Burns
- Simulate retrograde burns for orbital capture at destination
- Calculate Δv needed for circularization
- Support parking orbits at arrival body
- Validate Mars capture burns (~1.4 km/s for Mars)
5. Adaptive Timestepping
Problem: Fixed 60s timestep is:
- Too coarse for fast orbital phases (moon capture, close approaches)
- Too slow for deep-space phases (interplanetary transfers)
Solution: Adaptive timestep based on orbital period
Implementation:
double calculate_adaptive_timestep(CelestialBody* body, CelestialBody* parent) {
if (parent == NULL || body->semi_major_axis <= 0.0) {
return 60.0; // Default timestep
}
// Calculate orbital period using Kepler's third law
double T = 2.0 * M_PI * sqrt(pow(body->semi_major_axis, 3) / (G * parent->mass));
// Use 1/1000 of orbital period as timestep
double adaptive_dt = T / 1000.0;
// Clamp to reasonable bounds
adaptive_dt = fmax(adaptive_dt, 10.0); // Minimum 10s
adaptive_dt = fmin(adaptive_dt, 600.0); // Maximum 600s
return adaptive_dt;
}
Changes required:
- Add per-body timesteps to
SimulationState - Update
update_simulation()to use adaptive timesteps - Add synchronization mechanism for multiple timesteps
Expected outcome:
- Better accuracy for fast orbits (moon capture)
- Faster simulation for deep-space phases
- Energy conserved across SOI transitions
Tests:
- Verify energy drift with adaptive timesteps
- Verify orbital period accuracy with adaptive timesteps
- Test stability across SOI transitions
Visualization Features
6. Mission GUI
- Interactive departure window visualization
- Show current phase angle vs. required phase angle
- Countdown to launch window
- Transfer trajectory preview (predicted path)
- Delta-v budget display
7. Multiple Burns Support
- Mid-course corrections
- Gravity assist maneuvers
- Powered flybys
- Multi-stage missions
8. SOI Visualization
- Render SOI boundaries as wireframe spheres
- Color-coded by mass
- Toggle with keyboard shortcut
- Show SOI transitions in real-time
Advanced Features
9. Mission Planner
- Complete mission design tool
- Multi-leg missions (Earth→Mars→Phobos)
- Optimization algorithms (minimum Δv, minimum time)
- Launch date search across windows
- Mission timeline visualization
10. Real Ephemeris Integration
- Use actual planetary positions (JPL Horizons API)
- Date-based initialization
- Real mission planning with actual ephemeris data
- Compare simulation to historical missions
11. Enhanced Trajectory Analysis
- Lambert solver for general transfers
- Not just Hohmann transfers
- Arbitrary departure/arrival positions and times
- Non-planar transfers
Notes
Coordinate System
- All calculations assume planar motion (z = 0) for initial implementation
- Angular positions measured in XY plane
- Future work: Extend to 3D with inclination
Timekeeping
- Simulation time in seconds, conversions to days for display
- Fast-forward uses 1-day steps for efficiency during launch window wait
- Timestep remains 60s during fast-forward
Mass Strategy
- Spacecraft mass = 1.0 kg (negligible but non-zero)
- Physics engine handles test particles correctly (mass cancels in acceleration)
- No N-body perturbations from spacecraft on planetary bodies
Validation Strategy
- Compare against NASA reference missions (Viking, Curiosity, Perseverance)
- Energy conservation tracking during transfer
- Transfer time accuracy (±10% tolerance)
- SOI transition verification (Earth→Sun→Mars)
Testing Approach
- Unit tests for each function (formulas, calculations)
- Integration tests for full missions (LEO initialization, impulse burn, transfer)
- Regression tests against expected Hohmann transfer parameters
LEO Orbit Considerations
- LEO orbit at 200 km altitude (r = 6.571×10⁶ m)
- LEO velocity: ~7,788 m/s at 200 km
- LEO period: ~88.5 minutes
- Spacecraft LEO phase changes significantly during multi-day wait periods
- Transfer burn must account for spacecraft's actual heliocentric velocity (not just Earth's)
References
docs/implementation_plan.md- Overall system architecture- NASA Technical Memorandum "Hohmann Transfer Calculations"
- Orbital Mechanics for Engineering Students (Curtis)
- Fundamentals of Astrodynamics (Bate, Mueller, White)