diff --git a/docs/leospacecraft_impulse_burn_plan.md b/docs/leospacecraft_impulse_burn_plan.md deleted file mode 100644 index 199d356..0000000 --- a/docs/leospacecraft_impulse_burn_plan.md +++ /dev/null @@ -1,844 +0,0 @@ -# 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 -```bash -git stash push -m "Debug printf statements for spacecraft parent switch investigation" -``` - -### Step 0.2: Checkout and update mission-planning branch -```bash -git checkout mission-planning -git rebase main # Or git merge main if cleaner -``` - -### Step 0.3: Apply debug changes to mission-planning branch -```bash -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` - -Append to config file: -```toml -[[bodies]] -name = "Spacecraft" -mass = 1.0 -radius = 1000.0 -# Position and velocity will be initialized at runtime for LEO orbit -position = { x = 0.0, y = 0.0, z = 0.0 } -velocity = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = 1 # Earth -color = { r = 1.0, g = 0.0, b = 0.5 } -eccentricity = 0.0 -# Semi-major axis will be: Earth radius + 200km -semi_major_axis = 6.571e6 # Placeholder, will be set during initialization -``` - -**Note**: Position/velocity are placeholders; will be calculated by `initialize_spacecraft_leo()` at runtime. - -**TODO**: Future config file format should support: -- Earth-relative position (e.g., `{ altitude_km = 200.0 }`) -- Earth-relative velocity (e.g., `{ 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` - -```cpp -// Initialize spacecraft in circular LEO around parent body -void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, - double altitude_m); - -// Apply patched conics impulse burn for Hohmann transfer -void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, - int departure_idx, TransferParameters* params); - -// Helper: Calculate current phase angle between two bodies (in degrees) -double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx); -``` - -### Step 2.2: Implement `initialize_spacecraft_leo()` in `src/mission_planning.cpp` - -**Algorithm**: -```cpp -void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, - double altitude_m) { - // Calculate orbital radius (distance from Earth center) - double orbital_radius = parent->radius + altitude_m; - - // Position spacecraft radially outward from Earth-Sun line - // Get vector from Sun to Earth - Vec3 sun_to_earth = vec3_sub(parent->position, - (Vec3){0.0, 0.0, 0.0}); // Sun at origin - Vec3 direction = vec3_normalize(sun_to_earth); - - // Position: Earth position + offset radially outward - Vec3 offset = vec3_scale(direction, orbital_radius); - spacecraft->position = vec3_add(parent->position, offset); - - // Initialize local coordinates (relative to parent) - spacecraft->local_position = offset; - spacecraft->local_velocity = (Vec3){0.0, 0.0, 0.0}; // Will be set below - - // Calculate circular LEO velocity magnitude - double v_leo = sqrt(G * parent->mass / orbital_radius); - - // Direction: tangential to Earth-Sun line (prograde) - // If sun_to_earth = (x, y, 0), then tangent = (-y, x, 0) - Vec3 leo_tangent = (Vec3){-direction.y, direction.x, 0.0}; - Vec3 leo_velocity = vec3_scale(leo_tangent, v_leo); - - // Spacecraft velocity = Earth velocity + LEO velocity - spacecraft->velocity = vec3_add(parent->velocity, leo_velocity); - - // Local velocity relative to Earth = LEO velocity only - spacecraft->local_velocity = leo_velocity; - - // Update semi-major axis for reference - spacecraft->semi_major_axis = orbital_radius; - - // SOI will be calculated by config loader -} -``` - -**Key Points**: -- Spacecraft positioned radially outward from Sun (any position is acceptable) -- LEO orbit is circular at 200km altitude -- Prograde orientation (same direction as Earth's orbital velocity) -- Both local and global coordinates set correctly - -### Step 2.3: Implement `calculate_phase_angle()` in `src/mission_planning.cpp` - -**Algorithm**: -```cpp -double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx) { - CelestialBody* departure = &sim->bodies[departure_idx]; - CelestialBody* arrival = &sim->bodies[arrival_idx]; - CelestialBody* sun = &sim->bodies[0]; // Assume Sun at index 0 - - // Calculate angular positions relative to Sun - double theta_depart = calculate_angular_position(departure, sun); - double theta_arrival = calculate_angular_position(arrival, sun); - - // Calculate phase difference - double phase_rad = theta_arrival - theta_depart; - - // Normalize to [0, 2π) - while (phase_rad < 0.0) { - phase_rad += 2.0 * M_PI; - } - while (phase_rad >= 2.0 * M_PI) { - phase_rad -= 2.0 * M_PI; - } - - // Convert to degrees - return phase_rad * 180.0 / M_PI; -} -``` - -### Step 2.4: Implement `apply_transfer_burn()` in `src/mission_planning.cpp` - -**Algorithm (Patched Conics Approach)**: -```cpp -void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, - int departure_idx, TransferParameters* params) { - CelestialBody* spacecraft = &sim->bodies[spacecraft_idx]; - CelestialBody* departure = &sim->bodies[departure_idx]; - CelestialBody* sun = &sim->bodies[0]; // Assume Sun at index 0 - - // Calculate required heliocentric transfer velocity - // v_transfer = params->departure_velocity - // Direction: prograde (tangential to Earth-Sun line) - Vec3 sun_to_earth = vec3_sub(departure->position, sun->position); - Vec3 sun_to_earth_norm = vec3_normalize(sun_to_earth); - - // Tangent direction (prograde): (-y, x, 0) - Vec3 transfer_dir = (Vec3){-sun_to_earth_norm.y, sun_to_earth_norm.x, 0.0}; - Vec3 v_transfer_helio = vec3_scale(transfer_dir, params->departure_velocity); - - // Current heliocentric velocity - Vec3 current_helio = spacecraft->velocity; - - // Calculate total Δv to apply - Vec3 delta_v = vec3_sub(v_transfer_helio, current_helio); - - // Apply impulse burn - spacecraft->velocity = vec3_add(spacecraft->velocity, delta_v); - - // Update local velocity - spacecraft->local_velocity = vec3_sub(spacecraft->velocity, departure->velocity); - - // Print burn information - printf("Transfer burn applied:\n"); - printf(" Current heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", - current_helio.x, current_helio.y, current_helio.z); - printf(" Target heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", - v_transfer_helio.x, v_transfer_helio.y, v_transfer_helio.z); - printf(" Delta-v: (%.2f, %.2f, %.2f) m/s\n", - delta_v.x, delta_v.y, delta_v.z); - printf(" Delta-v magnitude: %.2f m/s (%.3f km/s)\n", - vec3_magnitude(delta_v), vec3_magnitude(delta_v) / 1000.0); -} -``` - -**Note**: This is a simplified single-impulse approach. A true patched conics calculation would: -1. Calculate Δv to reach SOI boundary (escape trajectory) -2. Calculate velocity at SOI boundary -3. Add transfer Δv at SOI boundary -4. Combine into equivalent single impulse - -For initial implementation, we'll use single impulse as approximation. - ---- - -## Phase 3: Comprehensive Test Case - -### Step 3.1: Create new test in `tests/test_hohmann_transfer.cpp` - -```cpp -TEST_CASE("Earth → Mars Hohmann Transfer with LEO Spacecraft", "[mission][hohmann][config][integration]") { - const double TIME_STEP = 60.0; - const double SECONDS_PER_DAY = 86400.0; - const double LEO_ALTITUDE_M = 200000.0; // 200 km - - // 1. Load config with LEO spacecraft - SimulationState* sim = create_simulation(4, TIME_STEP); - REQUIRE(load_system_config(sim, "tests/configs/earth_mars_simple.toml")); - - const int SUN_IDX = 0; - const int EARTH_IDX = 1; - const int MARS_IDX = 2; - const int CRAFT_IDX = 3; - - // Verify spacecraft loaded - REQUIRE(sim->body_count == 4); - REQUIRE(strcmp(sim->bodies[CRAFT_IDX].name, "Spacecraft") == 0); - - // 2. Initialize spacecraft LEO orbit - initialize_spacecraft_leo(&sim->bodies[CRAFT_IDX], &sim->bodies[EARTH_IDX], - LEO_ALTITUDE_M); - - INFO("Spacecraft initialized at %.2f km altitude", LEO_ALTITUDE_M / 1000.0); - INFO("Spacecraft parent: %d (Earth)", sim->bodies[CRAFT_IDX].parent_index); - - // 3. Verify initial LEO orbit is stable - REQUIRE(sim->bodies[CRAFT_IDX].parent_index == EARTH_IDX); - - double dist_to_earth = vec3_distance(sim->bodies[CRAFT_IDX].position, - sim->bodies[EARTH_IDX].position); - double expected_radius = sim->bodies[EARTH_IDX].radius + LEO_ALTITUDE_M; - REQUIRE(fabs(dist_to_earth - expected_radius) < 1000.0); // Within 1 km - - // Verify LEO velocity magnitude - double leo_velocity_mag = sqrt(G * sim->bodies[EARTH_IDX].mass / dist_to_earth); - double v_leo_relative = vec3_magnitude(sim->bodies[CRAFT_IDX].local_velocity); - INFO("Expected LEO velocity: %.2f m/s", leo_velocity_mag); - INFO("Actual LEO velocity: %.2f m/s", v_leo_relative); - REQUIRE(fabs(v_leo_relative - leo_velocity_mag) < 10.0); // Within 10 m/s - - // Verify negative total energy (bound to Earth) - OrbitalMetrics leo_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], - &sim->bodies[EARTH_IDX]); - INFO("LEO total energy: %.2e J", leo_metrics.total_energy); - REQUIRE(leo_metrics.total_energy < 0.0); - - // 4. Calculate Hohmann transfer parameters - double r_earth = vec3_distance(sim->bodies[EARTH_IDX].position, - sim->bodies[SUN_IDX].position); - double r_mars = vec3_distance(sim->bodies[MARS_IDX].position, - sim->bodies[SUN_IDX].position); - TransferParameters params = calculate_hohmann_transfer(r_earth, r_mars, - sim->bodies[SUN_IDX].mass); - - INFO("Transfer time: %.2f days", params.transfer_time / SECONDS_PER_DAY); - INFO("Required phase angle: %.3f degrees", params.phase_angle_deg); - INFO("Delta-v injection: %.3f km/s", params.delta_v_injection / 1000.0); - - // 5. Wait for Earth-Mars launch window - double wait_start_time = sim->time; - wait_for_launch_window(sim, EARTH_IDX, MARS_IDX, params.phase_angle_deg, 1.0); - double wait_duration = sim->time - wait_start_time; - - INFO("Launch window opened after %.2f days", wait_duration / SECONDS_PER_DAY); - - // 6. Verify launch window accuracy (within 1°) - double current_phase = calculate_phase_angle(sim, EARTH_IDX, MARS_IDX); - double phase_error = fabs(current_phase - params.phase_angle_deg); - if (phase_error > 180.0) phase_error = fabs(phase_error - 360.0); - - INFO("Current phase angle: %.3f degrees", current_phase); - INFO("Required phase angle: %.3f degrees", params.phase_angle_deg); - INFO("Phase angle error: %.3f degrees", phase_error); - REQUIRE(phase_error < 1.0); - - // 7. Apply impulse burn for transfer - double pre_burn_time = sim->time; - OrbitalMetrics pre_burn_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], - &sim->bodies[SUN_IDX]); - - apply_transfer_burn(sim, CRAFT_IDX, EARTH_IDX, ¶ms); - - OrbitalMetrics post_burn_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], - &sim->bodies[SUN_IDX]); - - INFO("Pre-burn heliocentric energy: %.2e J", pre_burn_metrics.total_energy); - INFO("Post-burn heliocentric energy: %.2e J", post_burn_metrics.total_energy); - INFO("Energy added: %.2e J", - post_burn_metrics.total_energy - pre_burn_metrics.total_energy); - - // Verify spacecraft is now in escape trajectory (positive or zero energy) - REQUIRE(post_burn_metrics.total_energy >= 0.0); - - // 8. Track SOI transitions during transfer - int earth_soi_exit_step = 0; - int sun_soi_enter_step = 0; - int mars_soi_enter_step = 0; - double transfer_duration = params.transfer_time * 1.1; - int max_steps = (int)(transfer_duration / sim->dt); - - INFO("Simulating for %.2f days (%d steps)", - transfer_duration / SECONDS_PER_DAY, max_steps); - - for (int step = 0; step < max_steps; step++) { - update_simulation(sim); - - // Track Earth SOI exit - if (earth_soi_exit_step == 0 && - sim->bodies[CRAFT_IDX].parent_index != EARTH_IDX) { - earth_soi_exit_step = step; - INFO("Earth SOI exit at step %d (t = %.2f days)", - step, sim->time / SECONDS_PER_DAY); - } - - // Track Sun SOI entry (after leaving Earth) - if (earth_soi_exit_step > 0 && sun_soi_enter_step == 0 && - sim->bodies[CRAFT_IDX].parent_index == SUN_IDX) { - sun_soi_enter_step = step; - INFO("Sun SOI entry at step %d (t = %.2f days)", - step, sim->time / SECONDS_PER_DAY); - } - - // Track Mars SOI entry - if (mars_soi_enter_step == 0 && - sim->bodies[CRAFT_IDX].parent_index == MARS_IDX) { - mars_soi_enter_step = step; - INFO("Mars SOI entry at step %d (t = %.2f days)", - step, sim->time / SECONDS_PER_DAY); - } - } - - // 9. Verify Earth → Sun transition occurred - INFO("Earth SOI exit step: %d", earth_soi_exit_step); - INFO("Sun SOI entry step: %d", sun_soi_enter_step); - - REQUIRE(earth_soi_exit_step > 0); - REQUIRE(sun_soi_enter_step > 0); - - // Final parent should be Sun or Mars - int final_parent = sim->bodies[CRAFT_IDX].parent_index; - REQUIRE(final_parent == SUN_IDX || final_parent == MARS_IDX); - INFO("Final parent: %d (%s)", final_parent, - final_parent == SUN_IDX ? "Sun" : "Mars"); - - // 10. Verify spacecraft followed transfer orbit (energy conservation) - OrbitalMetrics final_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], - &sim->bodies[SUN_IDX]); - - double energy_drift = fabs(final_metrics.total_energy - post_burn_metrics.total_energy); - if (post_burn_metrics.total_energy != 0.0) { - energy_drift /= fabs(post_burn_metrics.total_energy); - } - - INFO("Final orbital radius: %.2f AU", - final_metrics.orbital_radius / 1.496e11); - INFO("Final energy: %.2e J", final_metrics.total_energy); - INFO("Expected energy: %.2e J", post_burn_metrics.total_energy); - INFO("Energy drift: %.2f%%", energy_drift * 100.0); - - REQUIRE(energy_drift < 0.05); // < 5% energy conservation - - // 11. If Mars SOI entry occurred, verify distance - if (mars_soi_enter_step > 0) { - double dist_to_mars = vec3_distance(sim->bodies[CRAFT_IDX].position, - sim->bodies[MARS_IDX].position); - INFO("Distance to Mars: %.2f km", dist_to_mars / 1000.0); - INFO("Mars SOI radius: %.2f km", sim->bodies[MARS_IDX].soi_radius / 1000.0); - REQUIRE(dist_to_mars < 2.0 * sim->bodies[MARS_IDX].soi_radius); - } else { - INFO("Spacecraft did not enter Mars SOI within simulation time"); - INFO("This may be due to phase angle or timing inaccuracies"); - } - - destroy_simulation(sim); -} -``` - ---- - -## 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 -```bash -make clean -make test-build -``` - -### Step 4.3: Run comprehensive test -```bash -./orbit_test -s 'Earth → Mars Hohmann Transfer with LEO Spacecraft' -``` - -### Step 4.4: Verify all tests still pass -```bash -make test -``` - ---- - -## Phase 5: Cleanup and Documentation - -### Step 5.1: Remove deprecated function -Remove `spawn_spacecraft_on_transfer()` from: -- `src/mission_planning.h` -- `src/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 LEO -- `apply_transfer_burn()` - Apply patched conics impulse burn -- `calculate_phase_angle()` - Calculate phase angle between bodies -- Comprehensive test case with SOI transition tracking - -### Files Modified -- `tests/configs/earth_mars_simple.toml` - Add spacecraft body -- `src/mission_planning.h` - Add function declarations -- `src/mission_planning.cpp` - Implement new functions -- `tests/test_hohmann_transfer.cpp` - Add comprehensive test - -### Functions Removed -- `spawn_spacecraft_on_transfer()` - Still present in code but no longer used - ---- - -## Implementation Session Summary - -### Date: January 18, 2026 -### Branch: mission-planning -### Duration: ~2 hours - -### Completed Work - -#### Phase 0: Git Workflow ✅ -- Stashed debug changes on main branch -- Switched to mission-planning branch -- Applied debug printf statements to mission-planning branch -- All debug output from spacecraft parent investigation preserved - -#### Phase 1: Configuration File ✅ -- Added Spacecraft body to `tests/configs/earth_mars_simple.toml` -- Configured with placeholder position/velocity (set at runtime) -- Parent set to Earth (index 1) -- Initial semi-major axis placeholder: 6.571e6 m (Earth radius + 200km) - -#### Phase 2: Mission Planning Module ✅ - -**Function Declarations Added:** -```cpp -void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, - double altitude_m); -void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, - int departure_idx, TransferParameters* params); -double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx); -``` - -**Function Implementations:** - -1. **`initialize_spacecraft_leo()`** - Sets circular LEO orbit at specified altitude - - Calculates orbital radius = Earth radius + altitude - - Positions spacecraft radially outward from Sun - - Calculates LEO velocity: v = sqrt(G * M_earth / r) - - Sets prograde orientation (tangential to Earth-Sun line) - - Verified to produce correct LEO velocity (~7788 m/s at 200km altitude) - -2. **`calculate_phase_angle()`** - Computes phase angle between two bodies - - Calculates angular positions relative to Sun - - Returns phase difference normalized to [0°, 360°) - - Used for launch window verification - -3. **`apply_transfer_burn()`** - Applies impulse burn for Hohmann transfer - - Calculates required heliocentric velocity magnitude from transfer parameters - - Calculates prograde direction (tangential to Earth-Sun line) - - Computes delta-v vector: Δv = v_target - v_current - - Applies impulse to spacecraft velocity - - Updates local velocity relative to departure body - -#### Phase 3: Comprehensive Test Case ✅ - -**Test Structure:** -``` -1. Load config with 4 bodies (Sun, Earth, Mars, Spacecraft) -2. Initialize spacecraft in 200km LEO around Earth -3. Verify LEO orbit stability (parent, position, velocity, energy) -4. Calculate Hohmann transfer parameters -5. Wait for Earth-Mars launch window (within 1°) -6. Verify phase angle accuracy -7. Apply impulse burn for transfer -8. Verify post-burn energy >= 0 (escape trajectory) -9. Simulate transfer for 110% of expected duration -10. Track SOI transitions (Earth→Sun→Mars) -11. Verify final parent and energy conservation -12. If Mars SOI entry, verify distance -``` - -**Test Results (Current Status):** - -✅ PASSED (8 assertions): -- Config loading (4 bodies loaded) -- Spacecraft loaded correctly -- Spacecraft parent = Earth (index 1) -- LEO position within expected radius (<1km error) -- LEO velocity matches expected (<10 m/s error) -- LEO total energy negative (bound to Earth) -- Launch window opened after ~94 days -- Phase angle error < 1° - -❌ FAILED (1 assertion): -- Post-burn heliocentric energy >= 0.0 (expected) - - Actual: -3.5e8 J (negative, still bound) - - Expected: ≥ 0 J (positive, escape trajectory) - -#### Phase 4: Build System ✅ -- Makefile already configured for mission_planning.o -- Test executable builds successfully -- All warnings noted (unused variables, harmless) - -#### Phase 5: Cleanup ⏸️ -- Not yet started (waiting on test fix) - ---- - -## 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: -1. Required heliocentric transfer velocity magnitude: `v_transfer = 32,697 m/s` -2. Prograde direction based on Earth's current position: `transfer_dir = prograde(t_current)` -3. 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:** -1. Calculate spacecraft's current heliocentric velocity vector: `v_current` -2. Calculate required heliocentric velocity for transfer orbit: `v_transfer` -3. Apply delta-v: `Δv = v_transfer - v_current` (vector subtraction, not magnitude-based) - -**What Currently Happens:** -1. Assumes spacecraft starts at Earth's orbital position (ignores LEO phase) -2. Calculates transfer direction based on Earth's current prograde vector -3. Applies magnitude-based delta-v without considering spacecraft's actual velocity direction -4. Results in incorrect burn direction - -### Solution Required - -Modify `apply_transfer_burn()` to: - -1. **Calculate spacecraft's actual heliocentric velocity:** -```cpp -Vec3 v_current_helio = spacecraft->velocity; // Already in global frame -``` - -2. **Calculate required heliocentric transfer velocity:** -```cpp -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); -``` - -3. **Calculate delta-v as vector difference:** -```cpp -Vec3 delta_v = vec3_sub(v_transfer_helio, v_current_helio); -``` - -4. **Apply impulse:** -```cpp -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 -```toml -[[bodies]] -name = "Sun" -mass = 1.989e30 -radius = 6.96e8 -position = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = -1 -color = { r = 1.0, g = 1.0, b = 0.0 } -eccentricity = 0.0 -semi_major_axis = 0.0 - -[[bodies]] -name = "Earth" -mass = 5.972e24 -radius = 6.371e6 -position = { x = 1.496e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.0, g = 0.5, b = 1.0 } -eccentricity = 0.0 -semi_major_axis = 1.496e11 - -[[bodies]] -name = "Mars" -mass = 6.39e23 -radius = 3.3895e6 -position = { x = 2.279e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.8, g = 0.3, b = 0.1 } -eccentricity = 0.0 -semi_major_axis = 2.279e11 - -[[bodies]] -name = "Spacecraft" -mass = 1.0 -radius = 1000.0 -# Position and velocity will be initialized at runtime for LEO orbit -position = { x = 0.0, y = 0.0, z = 0.0 } -velocity = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = 1 # Earth -color = { r = 1.0, g = 0.0, b = 0.5 } -eccentricity = 0.0 -# Semi-major axis will be: Earth radius + 200km -semi_major_axis = 6.571e6 # Placeholder, will be set during initialization -``` - ---- - -## 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) - -### Visualization Features - -#### 5. 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 - -#### 6. Multiple Burns Support -- Mid-course corrections -- Gravity assist maneuvers -- Powered flybys -- Multi-stage missions - -#### 7. SOI Visualization -- Render SOI boundaries as wireframe spheres -- Color-coded by mass -- Toggle with keyboard shortcut -- Show SOI transitions in real-time - -### Advanced Features - -#### 8. 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 - -#### 9. 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 - -#### 10. 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) diff --git a/docs/mission_planning.md b/docs/mission_planning.md index 64cd576..199d356 100644 --- a/docs/mission_planning.md +++ b/docs/mission_planning.md @@ -1,550 +1,683 @@ -# Mission Planning Module - Implementation Plan +# Implementation Plan: Config-Based Spacecraft with Impulse Burn -**Date:** January 16, 2026 -**Status:** Phase 1-3 Complete ✅, Phase 4 Debugging Required 🔄 -**Branch:** patched-conics -**Implementation Progress:** 70% complete (3/6 phases complete, 1 phase debugging) +## 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 -## Implementation Progress +--- -### ✅ Phase 1: Core Transfer Calculations - COMPLETE -**Status:** All tests passing (3/3) -**Date Completed:** January 16, 2026 +## Phase 0: Git Workflow Preparation + +### Step 0.1: Stash debug changes on main +```bash +git stash push -m "Debug printf statements for spacecraft parent switch investigation" +``` -**Implemented:** -- `calculate_hohmann_transfer()` - Computes transfer orbit parameters -- `calculate_angular_position()` - Calculates body angle in XY plane -- `calculate_required_phase_angle()` - Computes optimal launch phase angle +### Step 0.2: Checkout and update mission-planning branch +```bash +git checkout mission-planning +git rebase main # Or git merge main if cleaner +``` -**Validation:** -- Earth→Mars transfer time: 258.8 days (±0.08% of expected) -- Required phase angle: 44.3° (±0.08° of expected) -- Delta-v injection: 2.94 km/s (±0.01% of expected) -- All NASA reference values validated within 5% +### Step 0.3: Apply debug changes to mission-planning branch +```bash +git stash list # Verify stash exists +git stash pop # Apply debug changes +``` -**Tests:** `tests/test_mission_planning.cpp` - 17 assertions, 6 test cases, all pass +**Verification**: Confirm debug printf statements are in `src/simulation.cpp` after applying stash --- -### ✅ Phase 2: Launch Window Detection - COMPLETE -**Status:** All tests passing -**Date Completed:** January 16, 2026 +## Phase 1: Update Configuration File -**Implemented:** -- `check_launch_window()` - Tests if current phase angle allows optimal launch -- `wait_for_launch_window()` - Fast-forwards simulation to launch window +### Step 1.1: Add spacecraft to `tests/configs/earth_mars_simple.toml` -**Validation:** -- Launch window detection works correctly -- Fast-forward advances simulation to correct phase (within 1°) -- Wait time: ~94 days for Earth→Mars transfer window -- Phase angle wrapping handled correctly (0-360° range) +Append to config file: +```toml +[[bodies]] +name = "Spacecraft" +mass = 1.0 +radius = 1000.0 +# Position and velocity will be initialized at runtime for LEO orbit +position = { x = 0.0, y = 0.0, z = 0.0 } +velocity = { x = 0.0, y = 0.0, z = 0.0 } +parent_index = 1 # Earth +color = { r = 1.0, g = 0.0, b = 0.5 } +eccentricity = 0.0 +# Semi-major axis will be: Earth radius + 200km +semi_major_axis = 6.571e6 # Placeholder, will be set during initialization +``` + +**Note**: Position/velocity are placeholders; will be calculated by `initialize_spacecraft_leo()` at runtime. -**Tests:** Integrated into mission planning test suite - all pass +**TODO**: Future config file format should support: +- Earth-relative position (e.g., `{ altitude_km = 200.0 }`) +- Earth-relative velocity (e.g., `{ orbit_type = "circular" }`) +- More intuitive spacecraft mission parameters --- -### ✅ Phase 3: Spacecraft Spawning - COMPLETE -**Status:** All tests passing (9/9 assertions) -**Date Completed:** January 16, 2026 +## Phase 2: Mission Planning Module - New Functions -**Implemented:** -- `add_body_to_simulation()` - Dynamic body creation in simulation.cpp -- `spawn_spacecraft_on_transfer()` - Creates spacecraft with correct velocity +### Step 2.1: Add function declarations to `src/mission_planning.h` -**Validation:** -- Spacecraft spawns at correct position (0m error from departure body) -- Spacecraft velocity = departure velocity + Δv (0% error) -- Spacecraft parent = Sun (index 0) -- Local/global coordinates initialized correctly -- SOI radius calculated correctly +```cpp +// Initialize spacecraft in circular LEO around parent body +void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, + double altitude_m); -**Tests:** `tests/test_hohmann_transfer.cpp::Spacecraft spawning` - 9 assertions, all pass +// Apply patched conics impulse burn for Hohmann transfer +void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, + int departure_idx, TransferParameters* params); -**Key Implementation Details:** -- Uses departure body's actual velocity direction (not computed from position) -- Spacecraft mass = 1.0 kg (test particle, mass cancels in physics) -- Position and velocity set before adding to simulation -- Coordinate transforms handle parent=0 (Sun) correctly +// Helper: Calculate current phase angle between two bodies (in degrees) +double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx); +``` ---- +### Step 2.2: Implement `initialize_spacecraft_leo()` in `src/mission_planning.cpp` -### ⏸️ Phase 4: Full Transfer Test - DEBUGGING REQUIRED -**Status:** Partially implemented, trajectory issue identified -**Date Started:** January 16, 2026 -**Issue:** Spacecraft trajectory deviates from expected Hohmann transfer orbit - -**Implemented:** -- Test framework for Earth→Mars transfer -- Launch window detection and waiting -- Spacecraft spawning with transfer parameters -- Energy drift tracking and validation - -**Current Issue:** -- Spacecraft spawns with correct initial conditions (position, velocity, parent) -- Initial orbital energy: -3.52×10⁸ J (correct for transfer orbit) -- After first `update_simulation()` call, spacecraft trajectory diverges -- Final orbital energy: +3.51×10²³ J (huge energy error, wrong sign!) -- Spacecraft not following Hohmann transfer ellipse -- Energy drift: 9.98×10¹⁶% (unphysically large) - -**Debugging Findings:** -1. Spacecraft spawns correctly: - - Global position matches Earth: (-6.94×10⁹, -1.49×10¹¹, 0) m - - Global velocity correct: (-32697.6, 1518.47, 0) m/s - - Parent = Sun (index 0) - - Local position initially correct relative to Sun - -2. After first `update_simulation()`: - - Local position jumps incorrectly to: (6.11×10⁷, -2.84×10⁶, 0) m - - This suggests `compute_global_coordinates()` or local frame integration is wrong - -3. Possible root causes: - - Bug in `update_simulation()` coordinate transforms for newly added bodies - - Issue with local frame integration when parent = 0 (Sun) - - `compute_global_coordinates()` not called correctly after body addition - - SOI transition logic interfering with spacecraft (only 1 SOI transition detected) - -4. Investigation needed: - - Add debug output to `update_simulation()` to track coordinate transforms - - Check if `find_dominant_body()` incorrectly changing spacecraft's parent - - Verify RK4 integration is using correct reference frame - - Test with spacecraft starting at parent ≠ 0 (compare behavior) - -**Tests:** `tests/test_hohmann_transfer.cpp::Earth → Mars Hohmann Transfer - Basic` -- Current: 4/5 assertions pass -- Failing: Energy drift validation (expect < 5%, actual 9.98×10¹⁶%) - -**Next Steps for Debugging:** -1. Add detailed logging to `update_simulation()` to track coordinate transforms -2. Verify spacecraft's local position/velocity before/after each update -3. Check if parent index changes unexpectedly during simulation -4. Consider if `add_body_to_simulation()` needs to call `compute_global_coordinates()` -5. Test with simplified scenario (e.g., Earth → fake destination at 1.2 AU) - -**Estimated Time to Resolve:** 2-3 hours of focused debugging +**Algorithm**: +```cpp +void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, + double altitude_m) { + // Calculate orbital radius (distance from Earth center) + double orbital_radius = parent->radius + altitude_m; ---- + // Position spacecraft radially outward from Earth-Sun line + // Get vector from Sun to Earth + Vec3 sun_to_earth = vec3_sub(parent->position, + (Vec3){0.0, 0.0, 0.0}); // Sun at origin + Vec3 direction = vec3_normalize(sun_to_earth); -### ⏸️ Phase 5: Enhance Root Body Transition Tests - NOT STARTED -**Status:** Deferred until Phase 4 debugged -**Dependency:** Phase 4 (working transfer orbits required) + // Position: Earth position + offset radially outward + Vec3 offset = vec3_scale(direction, orbital_radius); + spacecraft->position = vec3_add(parent->position, offset); ---- + // Initialize local coordinates (relative to parent) + spacecraft->local_position = offset; + spacecraft->local_velocity = (Vec3){0.0, 0.0, 0.0}; // Will be set below -### ⏸️ Phase 6: Round-Trip Mission - NOT STARTED -**Status:** Deferred until Phase 4 debugged -**Dependency:** Phase 4 (single-leg transfer must work first) + // Calculate circular LEO velocity magnitude + double v_leo = sqrt(G * parent->mass / orbital_radius); ---- - -## Overview -Add a mission planning module to calculate realistic interplanetary transfers with proper departure windows, replacing manual config positioning with computed trajectories. This enables proper testing of patched conics mechanics and provides a foundation for spacecraft simulation. + // Direction: tangential to Earth-Sun line (prograde) + // If sun_to_earth = (x, y, 0), then tangent = (-y, x, 0) + Vec3 leo_tangent = (Vec3){-direction.y, direction.x, 0.0}; + Vec3 leo_velocity = vec3_scale(leo_tangent, v_leo); -## Design Decisions + // Spacecraft velocity = Earth velocity + LEO velocity + spacecraft->velocity = vec3_add(parent->velocity, leo_velocity); -1. **Spacecraft Mass**: Use small but non-zero (1.0 kg) - works with existing physics (mass cancels out in acceleration) -2. **Capture Burns**: Skip for initial implementation - implement flyby missions only -3. **Inclination**: Planar first (z=0), defer 3D to future work -4. **Scope**: Full mission planner with departure window timing, launch window detection, and spacecraft spawning + // Local velocity relative to Earth = LEO velocity only + spacecraft->local_velocity = leo_velocity; -## Key Technical Discovery + // Update semi-major axis for reference + spacecraft->semi_major_axis = orbital_radius; -The physics engine already supports test particles correctly. The acceleration calculation is: -``` -acceleration = (G × body_mass × parent_mass / r²) / body_mass = G × parent_mass / r² + // SOI will be calculated by config loader +} ``` -Body mass cancels out, so any small mass works. We'll use 1.0 kg. +**Key Points**: +- Spacecraft positioned radially outward from Sun (any position is acceptable) +- LEO orbit is circular at 200km altitude +- Prograde orientation (same direction as Earth's orbital velocity) +- Both local and global coordinates set correctly -## Data Structures +### Step 2.3: Implement `calculate_phase_angle()` in `src/mission_planning.cpp` -### TransferParameters +**Algorithm**: ```cpp -struct TransferParameters { - double semi_major_axis; // Transfer orbit semi-major axis (meters) - double eccentricity; // Transfer orbit eccentricity - double periapsis; // Closest approach (departure radius) - double apoapsis; // Furthest distance (arrival radius) - double transfer_time; // Time required for transfer (seconds) - double departure_velocity; // Required velocity at departure (m/s) - double arrival_velocity; // Velocity at arrival (relative to Sun, m/s) - double phase_angle_deg; // Required phase angle for launch (degrees) - double delta_v_injection; // Delta-V needed for transfer injection (m/s) - double delta_v_capture; // Delta-V needed for capture (optional, future) -}; +double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx) { + CelestialBody* departure = &sim->bodies[departure_idx]; + CelestialBody* arrival = &sim->bodies[arrival_idx]; + CelestialBody* sun = &sim->bodies[0]; // Assume Sun at index 0 + + // Calculate angular positions relative to Sun + double theta_depart = calculate_angular_position(departure, sun); + double theta_arrival = calculate_angular_position(arrival, sun); + + // Calculate phase difference + double phase_rad = theta_arrival - theta_depart; + + // Normalize to [0, 2π) + while (phase_rad < 0.0) { + phase_rad += 2.0 * M_PI; + } + while (phase_rad >= 2.0 * M_PI) { + phase_rad -= 2.0 * M_PI; + } + + // Convert to degrees + return phase_rad * 180.0 / M_PI; +} ``` -## Implementation Phases - -### Phase 1: Core Transfer Calculations (1 day) +### Step 2.4: Implement `apply_transfer_burn()` in `src/mission_planning.cpp` -**Goal:** Implement orbital mechanics calculations for Hohmann transfers +**Algorithm (Patched Conics Approach)**: +```cpp +void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, + int departure_idx, TransferParameters* params) { + CelestialBody* spacecraft = &sim->bodies[spacecraft_idx]; + CelestialBody* departure = &sim->bodies[departure_idx]; + CelestialBody* sun = &sim->bodies[0]; // Assume Sun at index 0 + + // Calculate required heliocentric transfer velocity + // v_transfer = params->departure_velocity + // Direction: prograde (tangential to Earth-Sun line) + Vec3 sun_to_earth = vec3_sub(departure->position, sun->position); + Vec3 sun_to_earth_norm = vec3_normalize(sun_to_earth); + + // Tangent direction (prograde): (-y, x, 0) + Vec3 transfer_dir = (Vec3){-sun_to_earth_norm.y, sun_to_earth_norm.x, 0.0}; + Vec3 v_transfer_helio = vec3_scale(transfer_dir, params->departure_velocity); + + // Current heliocentric velocity + Vec3 current_helio = spacecraft->velocity; + + // Calculate total Δv to apply + Vec3 delta_v = vec3_sub(v_transfer_helio, current_helio); + + // Apply impulse burn + spacecraft->velocity = vec3_add(spacecraft->velocity, delta_v); + + // Update local velocity + spacecraft->local_velocity = vec3_sub(spacecraft->velocity, departure->velocity); + + // Print burn information + printf("Transfer burn applied:\n"); + printf(" Current heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", + current_helio.x, current_helio.y, current_helio.z); + printf(" Target heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", + v_transfer_helio.x, v_transfer_helio.y, v_transfer_helio.z); + printf(" Delta-v: (%.2f, %.2f, %.2f) m/s\n", + delta_v.x, delta_v.y, delta_v.z); + printf(" Delta-v magnitude: %.2f m/s (%.3f km/s)\n", + vec3_magnitude(delta_v), vec3_magnitude(delta_v) / 1000.0); +} +``` -**Files:** -- `src/mission_planning.h` (new) - Function declarations -- `src/mission_planning.cpp` (new) - Core calculations -- `tests/test_mission_planning.cpp` (new) - Unit tests for formulas +**Note**: This is a simplified single-impulse approach. A true patched conics calculation would: +1. Calculate Δv to reach SOI boundary (escape trajectory) +2. Calculate velocity at SOI boundary +3. Add transfer Δv at SOI boundary +4. Combine into equivalent single impulse -**Functions to implement:** +For initial implementation, we'll use single impulse as approximation. -#### 1.1 `calculate_hohmann_transfer()` -Calculates transfer orbit parameters given departure and arrival radii. +--- -**Algorithm:** -``` -a_transfer = (r_departure + r_arrival) / 2 -e = (r_arrival - r_departure) / (r_arrival + r_departure) -T_transfer = π × sqrt(a³ / GM) +## Phase 3: Comprehensive Test Case -v_departure = sqrt(G × M × (2/r_departure - 1/a)) -v_arrival = sqrt(G × M × (2/r_arrival - 1/a)) -v_circular = sqrt(G × M / r_departure) +### Step 3.1: Create new test in `tests/test_hohmann_transfer.cpp` -Δv_injection = v_departure - v_circular +```cpp +TEST_CASE("Earth → Mars Hohmann Transfer with LEO Spacecraft", "[mission][hohmann][config][integration]") { + const double TIME_STEP = 60.0; + const double SECONDS_PER_DAY = 86400.0; + const double LEO_ALTITUDE_M = 200000.0; // 200 km + + // 1. Load config with LEO spacecraft + SimulationState* sim = create_simulation(4, TIME_STEP); + REQUIRE(load_system_config(sim, "tests/configs/earth_mars_simple.toml")); + + const int SUN_IDX = 0; + const int EARTH_IDX = 1; + const int MARS_IDX = 2; + const int CRAFT_IDX = 3; + + // Verify spacecraft loaded + REQUIRE(sim->body_count == 4); + REQUIRE(strcmp(sim->bodies[CRAFT_IDX].name, "Spacecraft") == 0); + + // 2. Initialize spacecraft LEO orbit + initialize_spacecraft_leo(&sim->bodies[CRAFT_IDX], &sim->bodies[EARTH_IDX], + LEO_ALTITUDE_M); + + INFO("Spacecraft initialized at %.2f km altitude", LEO_ALTITUDE_M / 1000.0); + INFO("Spacecraft parent: %d (Earth)", sim->bodies[CRAFT_IDX].parent_index); + + // 3. Verify initial LEO orbit is stable + REQUIRE(sim->bodies[CRAFT_IDX].parent_index == EARTH_IDX); + + double dist_to_earth = vec3_distance(sim->bodies[CRAFT_IDX].position, + sim->bodies[EARTH_IDX].position); + double expected_radius = sim->bodies[EARTH_IDX].radius + LEO_ALTITUDE_M; + REQUIRE(fabs(dist_to_earth - expected_radius) < 1000.0); // Within 1 km + + // Verify LEO velocity magnitude + double leo_velocity_mag = sqrt(G * sim->bodies[EARTH_IDX].mass / dist_to_earth); + double v_leo_relative = vec3_magnitude(sim->bodies[CRAFT_IDX].local_velocity); + INFO("Expected LEO velocity: %.2f m/s", leo_velocity_mag); + INFO("Actual LEO velocity: %.2f m/s", v_leo_relative); + REQUIRE(fabs(v_leo_relative - leo_velocity_mag) < 10.0); // Within 10 m/s + + // Verify negative total energy (bound to Earth) + OrbitalMetrics leo_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], + &sim->bodies[EARTH_IDX]); + INFO("LEO total energy: %.2e J", leo_metrics.total_energy); + REQUIRE(leo_metrics.total_energy < 0.0); + + // 4. Calculate Hohmann transfer parameters + double r_earth = vec3_distance(sim->bodies[EARTH_IDX].position, + sim->bodies[SUN_IDX].position); + double r_mars = vec3_distance(sim->bodies[MARS_IDX].position, + sim->bodies[SUN_IDX].position); + TransferParameters params = calculate_hohmann_transfer(r_earth, r_mars, + sim->bodies[SUN_IDX].mass); + + INFO("Transfer time: %.2f days", params.transfer_time / SECONDS_PER_DAY); + INFO("Required phase angle: %.3f degrees", params.phase_angle_deg); + INFO("Delta-v injection: %.3f km/s", params.delta_v_injection / 1000.0); + + // 5. Wait for Earth-Mars launch window + double wait_start_time = sim->time; + wait_for_launch_window(sim, EARTH_IDX, MARS_IDX, params.phase_angle_deg, 1.0); + double wait_duration = sim->time - wait_start_time; + + INFO("Launch window opened after %.2f days", wait_duration / SECONDS_PER_DAY); + + // 6. Verify launch window accuracy (within 1°) + double current_phase = calculate_phase_angle(sim, EARTH_IDX, MARS_IDX); + double phase_error = fabs(current_phase - params.phase_angle_deg); + if (phase_error > 180.0) phase_error = fabs(phase_error - 360.0); + + INFO("Current phase angle: %.3f degrees", current_phase); + INFO("Required phase angle: %.3f degrees", params.phase_angle_deg); + INFO("Phase angle error: %.3f degrees", phase_error); + REQUIRE(phase_error < 1.0); + + // 7. Apply impulse burn for transfer + double pre_burn_time = sim->time; + OrbitalMetrics pre_burn_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], + &sim->bodies[SUN_IDX]); + + apply_transfer_burn(sim, CRAFT_IDX, EARTH_IDX, ¶ms); + + OrbitalMetrics post_burn_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], + &sim->bodies[SUN_IDX]); + + INFO("Pre-burn heliocentric energy: %.2e J", pre_burn_metrics.total_energy); + INFO("Post-burn heliocentric energy: %.2e J", post_burn_metrics.total_energy); + INFO("Energy added: %.2e J", + post_burn_metrics.total_energy - pre_burn_metrics.total_energy); + + // Verify spacecraft is now in escape trajectory (positive or zero energy) + REQUIRE(post_burn_metrics.total_energy >= 0.0); + + // 8. Track SOI transitions during transfer + int earth_soi_exit_step = 0; + int sun_soi_enter_step = 0; + int mars_soi_enter_step = 0; + double transfer_duration = params.transfer_time * 1.1; + int max_steps = (int)(transfer_duration / sim->dt); + + INFO("Simulating for %.2f days (%d steps)", + transfer_duration / SECONDS_PER_DAY, max_steps); + + for (int step = 0; step < max_steps; step++) { + update_simulation(sim); + + // Track Earth SOI exit + if (earth_soi_exit_step == 0 && + sim->bodies[CRAFT_IDX].parent_index != EARTH_IDX) { + earth_soi_exit_step = step; + INFO("Earth SOI exit at step %d (t = %.2f days)", + step, sim->time / SECONDS_PER_DAY); + } + + // Track Sun SOI entry (after leaving Earth) + if (earth_soi_exit_step > 0 && sun_soi_enter_step == 0 && + sim->bodies[CRAFT_IDX].parent_index == SUN_IDX) { + sun_soi_enter_step = step; + INFO("Sun SOI entry at step %d (t = %.2f days)", + step, sim->time / SECONDS_PER_DAY); + } + + // Track Mars SOI entry + if (mars_soi_enter_step == 0 && + sim->bodies[CRAFT_IDX].parent_index == MARS_IDX) { + mars_soi_enter_step = step; + INFO("Mars SOI entry at step %d (t = %.2f days)", + step, sim->time / SECONDS_PER_DAY); + } + } + + // 9. Verify Earth → Sun transition occurred + INFO("Earth SOI exit step: %d", earth_soi_exit_step); + INFO("Sun SOI entry step: %d", sun_soi_enter_step); + + REQUIRE(earth_soi_exit_step > 0); + REQUIRE(sun_soi_enter_step > 0); + + // Final parent should be Sun or Mars + int final_parent = sim->bodies[CRAFT_IDX].parent_index; + REQUIRE(final_parent == SUN_IDX || final_parent == MARS_IDX); + INFO("Final parent: %d (%s)", final_parent, + final_parent == SUN_IDX ? "Sun" : "Mars"); + + // 10. Verify spacecraft followed transfer orbit (energy conservation) + OrbitalMetrics final_metrics = calculate_orbital_metrics(&sim->bodies[CRAFT_IDX], + &sim->bodies[SUN_IDX]); + + double energy_drift = fabs(final_metrics.total_energy - post_burn_metrics.total_energy); + if (post_burn_metrics.total_energy != 0.0) { + energy_drift /= fabs(post_burn_metrics.total_energy); + } + + INFO("Final orbital radius: %.2f AU", + final_metrics.orbital_radius / 1.496e11); + INFO("Final energy: %.2e J", final_metrics.total_energy); + INFO("Expected energy: %.2e J", post_burn_metrics.total_energy); + INFO("Energy drift: %.2f%%", energy_drift * 100.0); + + REQUIRE(energy_drift < 0.05); // < 5% energy conservation + + // 11. If Mars SOI entry occurred, verify distance + if (mars_soi_enter_step > 0) { + double dist_to_mars = vec3_distance(sim->bodies[CRAFT_IDX].position, + sim->bodies[MARS_IDX].position); + INFO("Distance to Mars: %.2f km", dist_to_mars / 1000.0); + INFO("Mars SOI radius: %.2f km", sim->bodies[MARS_IDX].soi_radius / 1000.0); + REQUIRE(dist_to_mars < 2.0 * sim->bodies[MARS_IDX].soi_radius); + } else { + INFO("Spacecraft did not enter Mars SOI within simulation time"); + INFO("This may be due to phase angle or timing inaccuracies"); + } + + destroy_simulation(sim); +} ``` -**Validation:** Earth→Mars values: -- Transfer time: ~259 days -- Phase angle: ~44.3° -- Δv: ~2.94 km/s +--- -#### 1.2 `calculate_angular_position()` -Calculates angular position of a body relative to its center (in XY plane). +## Phase 4: Build and Test -**Algorithm:** -``` -rel_pos = body_position - center_position -angle = atan2(y, x) -Normalize to [0, 2π) -``` +### Step 4.1: Update Makefile (if needed) -#### 1.3 `calculate_required_phase_angle()` -Calculates optimal phase angle for launch. +Verify `mission_planning.o` is in OBJECTS list and build rule exists. -**Algorithm:** -``` -ω_departure = 2π / T_departure -α = ω_departure × T_transfer -phase_angle = π - α (in radians) -Convert to degrees +### Step 4.2: Build test executable +```bash +make clean +make test-build ``` -**Tests:** -- Validate transfer parameters against NASA reference values (±5%) -- Verify angular position calculations for circular orbits -- Test phase angle formula with known cases - -**Expected outcome:** -- ✅ Accurate transfer orbit calculations -- ✅ Verified against known mission parameters +### Step 4.3: Run comprehensive test +```bash +./orbit_test -s 'Earth → Mars Hohmann Transfer with LEO Spacecraft' +``` -**Estimated complexity:** Low -**Risk:** Low (well-known orbital mechanics formulas) +### Step 4.4: Verify all tests still pass +```bash +make test +``` --- -### Phase 2: Launch Window Detection (1 day) +## Phase 5: Cleanup and Documentation -**Goal:** Detect when launch window is open and advance simulation to it +### Step 5.1: Remove deprecated function +Remove `spawn_spacecraft_on_transfer()` from: +- `src/mission_planning.h` +- `src/mission_planning.cpp` -**Files:** -- `src/mission_planning.cpp` (extend) -- `tests/test_launch_window.cpp` (new) +### Step 5.2: Update mission planning documentation -**Functions to implement:** +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 -#### 2.1 `check_launch_window()` -Tests if current positions allow optimal launch. +### Step 5.3: Add TODO comment for config format -**Algorithm:** +Add in `docs/mission_planning.md`: ``` -θ_depart = calculate_angular_position(departure, sun) -θ_arrival = calculate_angular_position(arrival, sun) - -current_phase = θ_arrival - θ_depart (normalize to [0, 2π)) -current_phase_deg = current_phase × (180/π) - -error = |current_phase_deg - required_phase_angle_deg| -Handle wrap-around: if error > 180°, use |error - 360°| - -return error <= tolerance +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 ``` -#### 2.2 `wait_for_launch_window()` -Advances simulation until launch window opens. +--- -**Algorithm:** -``` -while !check_launch_window(...): - Fast-forward by 1 day per iteration (for efficiency) - for i in 0..(86400 / dt): - update_simulation(sim) -``` +## Summary of Changes -**Tests:** -- Create Earth+Mars config at wrong phase angle -- Call `wait_for_launch_window()` - should advance simulation -- Verify phase angle is now within tolerance (1°) -- Measure time waited - should be reasonable (weeks to months) +### New Files/Functions Added +- `initialize_spacecraft_leo()` - Initialize spacecraft in LEO +- `apply_transfer_burn()` - Apply patched conics impulse burn +- `calculate_phase_angle()` - Calculate phase angle between bodies +- Comprehensive test case with SOI transition tracking -**Expected outcome:** -- ✅ Can detect proper launch windows -- ✅ Can advance simulation to launch window -- ✅ Phase angle accuracy within 1° +### Files Modified +- `tests/configs/earth_mars_simple.toml` - Add spacecraft body +- `src/mission_planning.h` - Add function declarations +- `src/mission_planning.cpp` - Implement new functions +- `tests/test_hohmann_transfer.cpp` - Add comprehensive test -**Estimated complexity:** Low-Medium -**Risk:** Low (simulation fast-forward is safe) +### Functions Removed +- `spawn_spacecraft_on_transfer()` - Still present in code but no longer used --- -### Phase 3: Spacecraft Spawning (1.5 days) +## Implementation Session Summary -**Goal:** Create spacecraft at departure with correct velocity +### Date: January 18, 2026 +### Branch: mission-planning +### Duration: ~2 hours -**Files:** -- `src/simulation.h` (+3 lines) - Add function declaration -- `src/simulation.cpp` (+30 lines) - Implement dynamic body addition -- `src/mission_planning.cpp` (+40 lines) - Spacecraft spawning logic +### Completed Work -**Functions to implement:** +#### Phase 0: Git Workflow ✅ +- Stashed debug changes on main branch +- Switched to mission-planning branch +- Applied debug printf statements to mission-planning branch +- All debug output from spacecraft parent investigation preserved -#### 3.1 `add_body_to_simulation()` (in simulation.cpp) -Adds a new body to the simulation at runtime. +#### Phase 1: Configuration File ✅ +- Added Spacecraft body to `tests/configs/earth_mars_simple.toml` +- Configured with placeholder position/velocity (set at runtime) +- Parent set to Earth (index 1) +- Initial semi-major axis placeholder: 6.571e6 m (Earth radius + 200km) -**Algorithm:** -``` -Check capacity (body_count < max_bodies) -Copy body to next available slot -Initialize local coordinates: - if parent_index >= 0: - local_pos = global_pos - parent_pos - local_vel = global_vel - parent_vel - else: - local_pos = global_pos - local_vel = global_vel -Calculate SOI radius (if has parent) -Increment body_count -Return new body index -``` - -#### 3.2 `spawn_spacecraft_on_transfer()` (in mission_planning.cpp) -Creates spacecraft on transfer trajectory at departure. +#### Phase 2: Mission Planning Module ✅ -**Algorithm:** -``` -Create spacecraft body: - name = "Spacecraft" - mass = 1.0 kg (negligible but non-zero) - radius = 1.0 km (for visualization) - color = magenta/pink - eccentricity = transfer.eccentricity - semi_major_axis = transfer.semi_major_axis - -Position = departure.position - -Velocity = departure.velocity + Δv_injection: - departure_pos = departure.position - sun.position - orbit_dir = normalize(cross(departure_pos, z_axis)) - delta_v = orbit_dir × transfer.delta_v_injection - spacecraft.velocity = departure.velocity + delta_v - -Parent = Sun (index 0) -Add to simulation via add_body_to_simulation() -Return spacecraft index +**Function Declarations Added:** +```cpp +void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, + double altitude_m); +void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, + int departure_idx, TransferParameters* params); +double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx); ``` -**Tests:** -- Spawn spacecraft at Earth -- Verify initial position matches Earth -- Verify velocity = Earth velocity + Δv -- Verify parent = Sun -- Verify local coordinates initialized correctly +**Function Implementations:** -**Expected outcome:** -- ✅ Spacecraft spawns correctly at departure -- ✅ Initial velocity matches transfer requirements -- ✅ Parent set to Sun for transfer orbit -- ✅ Local/global coordinates consistent +1. **`initialize_spacecraft_leo()`** - Sets circular LEO orbit at specified altitude + - Calculates orbital radius = Earth radius + altitude + - Positions spacecraft radially outward from Sun + - Calculates LEO velocity: v = sqrt(G * M_earth / r) + - Sets prograde orientation (tangential to Earth-Sun line) + - Verified to produce correct LEO velocity (~7788 m/s at 200km altitude) -**Estimated complexity:** Medium -**Risk:** Medium (dynamic body addition affects simulation state) +2. **`calculate_phase_angle()`** - Computes phase angle between two bodies + - Calculates angular positions relative to Sun + - Returns phase difference normalized to [0°, 360°) + - Used for launch window verification ---- +3. **`apply_transfer_burn()`** - Applies impulse burn for Hohmann transfer + - Calculates required heliocentric velocity magnitude from transfer parameters + - Calculates prograde direction (tangential to Earth-Sun line) + - Computes delta-v vector: Δv = v_target - v_current + - Applies impulse to spacecraft velocity + - Updates local velocity relative to departure body -### Phase 4: Full Transfer Test (1.5 days) +#### Phase 3: Comprehensive Test Case ✅ -**Goal:** End-to-end test of Earth→Mars Hohmann transfer +**Test Structure:** +``` +1. Load config with 4 bodies (Sun, Earth, Mars, Spacecraft) +2. Initialize spacecraft in 200km LEO around Earth +3. Verify LEO orbit stability (parent, position, velocity, energy) +4. Calculate Hohmann transfer parameters +5. Wait for Earth-Mars launch window (within 1°) +6. Verify phase angle accuracy +7. Apply impulse burn for transfer +8. Verify post-burn energy >= 0 (escape trajectory) +9. Simulate transfer for 110% of expected duration +10. Track SOI transitions (Earth→Sun→Mars) +11. Verify final parent and energy conservation +12. If Mars SOI entry, verify distance +``` -**Files:** -- `tests/test_hohmann_transfer.cpp` (new) - Main integration test -- `tests/configs/earth_mars_simple.toml` (new) - Simple 3-body config +**Test Results (Current Status):** -**Test scenario:** -```cpp -TEST_CASE("Earth → Mars Hohmann Transfer", "[mission][hohmann]") { - // 1. Load Earth+Mars system - // 2. Calculate transfer parameters - // 3. Wait for launch window (within 1° tolerance) - // 4. Record departure time - // 5. Spawn spacecraft on transfer trajectory - // 6. Simulate until arrival (transfer_time × 1.1) - // 7. Track SOI transitions (Earth→Sun→Mars) - // 8. Verify arrival at Mars (distance < 2×SOI) - // 9. Verify transfer time accuracy (±10%) -} -``` +✅ PASSED (8 assertions): +- Config loading (4 bodies loaded) +- Spacecraft loaded correctly +- Spacecraft parent = Earth (index 1) +- LEO position within expected radius (<1km error) +- LEO velocity matches expected (<10 m/s error) +- LEO total energy negative (bound to Earth) +- Launch window opened after ~94 days +- Phase angle error < 1° -**Success criteria:** -- Spacecraft enters Mars SOI -- Transfer time: 259 ± 26 days -- Final distance to Mars < 2 × Mars_SOI -- SOI transitions: Earth→Sun→Mars (tracked) -- Energy drift < 1% during transfer +❌ FAILED (1 assertion): +- Post-burn heliocentric energy >= 0.0 (expected) + - Actual: -3.5e8 J (negative, still bound) + - Expected: ≥ 0 J (positive, escape trajectory) -**Expected outcome:** -- ✅ Complete end-to-end transfer validated -- ✅ Patched conics mechanics tested (3 SOI changes) -- ✅ Transfer trajectory matches prediction +#### Phase 4: Build System ✅ +- Makefile already configured for mission_planning.o +- Test executable builds successfully +- All warnings noted (unused variables, harmless) -**Estimated complexity:** Medium-High -**Risk:** Medium-High (integration test may reveal edge cases) +#### Phase 5: Cleanup ⏸️ +- Not yet started (waiting on test fix) --- -### Phase 5: Enhance Root Body Transition Tests (0.5 days) - -**Goal:** Replace manual config positioning with calculated transfers +## Current Issue Identified -**Files:** -- `tests/test_root_body_transitions.cpp` (refactor) -- Remove `tests/configs/manual_root_transition.toml` +### Problem: Incorrect Delta-V Direction After Multi-Day Wait -**Changes:** -1. Replace "Root body transition - Earth to Sun" test: - - Use `spawn_spacecraft_on_transfer()` instead of manual config - - Calculate transfer parameters - - Wait for launch window - - Verify Earth→Sun transition happens +**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) -2. Replace "Root body round-trip" test: - - Calculate Earth→Mars transfer - - Wait for window - - Spawn spacecraft - - Verify round-trip SOI transitions +**Root Cause Analysis:** -3. Add better validation: - - Verify transition order (Earth→Sun→Mars) - - Verify arrival distance < threshold - - Verify energy conservation - - Verify spacecraft follows predicted trajectory +The `apply_transfer_burn()` function calculates: +1. Required heliocentric transfer velocity magnitude: `v_transfer = 32,697 m/s` +2. Prograde direction based on Earth's current position: `transfer_dir = prograde(t_current)` +3. Target velocity: `v_target = v_transfer * transfer_dir` -**Expected outcome:** -- ✅ Realistic mission-based testing -- ✅ Better validation than `sun_transitions >= 1` -- ✅ Eliminates manual config positioning -- ✅ Tests use actual orbital mechanics +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 -**Estimated complexity:** Low -**Risk:** Low (refactoring existing tests) +**What Should Happen:** +1. Calculate spacecraft's current heliocentric velocity vector: `v_current` +2. Calculate required heliocentric velocity for transfer orbit: `v_transfer` +3. Apply delta-v: `Δv = v_transfer - v_current` (vector subtraction, not magnitude-based) ---- +**What Currently Happens:** +1. Assumes spacecraft starts at Earth's orbital position (ignores LEO phase) +2. Calculates transfer direction based on Earth's current prograde vector +3. Applies magnitude-based delta-v without considering spacecraft's actual velocity direction +4. Results in incorrect burn direction -### Phase 6: Round-Trip Mission (1 day) - Optional +### Solution Required -**Goal:** Validate full mission lifecycle with return journey +Modify `apply_transfer_burn()` to: -**Files:** -- `tests/test_round_trip.cpp` (new) +1. **Calculate spacecraft's actual heliocentric velocity:** +```cpp +Vec3 v_current_helio = spacecraft->velocity; // Already in global frame +``` -**Test scenario:** +2. **Calculate required heliocentric transfer velocity:** ```cpp -TEST_CASE("Earth → Mars → Earth Round Trip", "[mission][round-trip]") { - // 1. Earth→Mars transfer - // 2. Verify arrival at Mars - // 3. Wait for Mars→Earth return window - // 4. Spawn new spacecraft at Mars for return - // 5. Simulate Mars→Earth return - // 6. Verify both transfers complete - // 7. Verify return arrival at Earth -} +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); ``` -**Success criteria:** -- Both transfers complete successfully -- Return time: ~259 ± 26 days -- Final distance to Earth < 2 × Earth_SOI -- Energy conserved across entire round-trip +3. **Calculate delta-v as vector difference:** +```cpp +Vec3 delta_v = vec3_sub(v_transfer_helio, v_current_helio); +``` -**Expected outcome:** -- ✅ Full mission lifecycle validated -- ✅ Multiple departure windows handled -- ✅ Patched conics round-trip confirmed +4. **Apply impulse:** +```cpp +spacecraft->velocity = vec3_add(spacecraft->velocity, delta_v); +spacecraft->local_velocity = vec3_sub(spacecraft->velocity, departure->velocity); +``` -**Estimated complexity:** Medium -**Risk:** Medium (long simulation time) +**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) --- -## Integration with Existing Code - -### Reuses Existing Components: +## Potential Issues and Mitigation -**Physics Module:** -- `rk4_step()` - RK4 integration works with any mass -- `evaluate_acceleration()` - Mass cancels out, test particles work +### Issue 1: LEO Orbit Position Sensitivity +Spacecraft LEO phase may affect optimal launch window timing. -**Simulation Module:** -- `find_dominant_body()` - SOI transitions work with parent_index = 0 (Sun) -- `update_simulation()` - Handles root bodies correctly -- Coordinate frames - Local/global transformations already work +**Mitigation**: Test shows we wait for Earth-Mars phase angle, not spacecraft-LEO phase. This should be acceptable. -**Test Utilities:** -- `calculate_orbital_metrics()` - Can use for trajectory validation -- `OrbitTracker` - Can track orbital progress +### Issue 2: Impulse Burn Accuracy +Single-impulse approximation may not match true patched conics trajectory. -### New Components: +**Mitigation**: Initial test focuses on Earth→Sun transition and energy conservation. If needed, can refine to two-impulse burn in future. -**Mission Planning Module:** -- `mission_planning.h/cpp` - Mission calculations -- TransferParameters struct - Transfer orbit description -- Phase angle calculations - Launch window detection +### Issue 3: Mars SOI Entry +Spacecraft may not enter Mars SOI due to: +- Phase angle tolerance (1°) +- Transfer time approximation +- Impulse burn simplifications -**Simulation Extensions:** -- `add_body_to_simulation()` - Dynamic spacecraft creation -- Runtime body addition - No more config-only initialization +**Mitigation**: Test includes explicit INFO messages and requires only Earth→Sun transition, not Mars arrival. --- -## Build System Changes +## Timeline Estimate -### Makefile Modifications +- 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 -**Add to OBJECTS list:** -```makefile -OBJECTS = main.o physics.o simulation.o config_loader.o renderer.o \ - test_utilities.o mission_planning.o -``` - -**Add build rule:** -```makefile -mission_planning.o: src/mission_planning.cpp src/mission_planning.h - $(CXX) $(CXXFLAGS) -c src/mission_planning.cpp -o mission_planning.o -``` - -**Add to test build:** -```makefile -# Test executable includes mission_planning.o -test: test_build - ./orbit_test -``` +**Total**: 2-3 hours --- -## Test Configurations +## Test Configuration Reference ### earth_mars_simple.toml -Simple 3-body system for transfer testing: ```toml [[bodies]] name = "Sun" @@ -575,269 +708,137 @@ parent_index = 0 color = { r = 0.8, g = 0.3, b = 0.1 } eccentricity = 0.0 semi_major_axis = 2.279e11 -``` ---- - -## Success Criteria - -### ✅ Phase 1-2 Success - COMPLETE -- [x] Transfer parameters match NASA reference (±5%) -- [x] Phase angle calculations accurate (±1°) -- [x] Launch window detection works -- [x] Fast-forward to launch window succeeds - -### ✅ Phase 3 Success - COMPLETE -- [x] Spacecraft spawns at correct position -- [x] Initial velocity = Earth velocity + Δv -- [x] Parent = Sun for transfer orbit -- [x] Local/global coordinates consistent - -### ⏸️ Phase 4 Success - IN PROGRESS (DEBUGGING) -- [ ] Earth→Mars transfer completes (time ±10%) -- [ ] Spacecraft reaches Mars SOI (distance < 2×SOI) -- [ ] SOI transitions: Earth→Sun→Mars tracked correctly -- [ ] Energy drift < 1% during transfer (currently 9.98×10¹⁶%) - -### ⏸️ Phase 5 Success - NOT STARTED -- [ ] Root body transition tests use calculated trajectory -- [ ] Manual config positioning eliminated -- [ ] Better validation than `sun_transitions >= 1` - -### ⏸️ Phase 6 Success - NOT STARTED -- [ ] Round-trip mission completes -- [ ] Both transfers validated -- [ ] Return journey matches expectations - ---- - -## Timeline Estimate vs. Actual - -### Planned: -- **Phase 1:** 1 day - Core transfer calculations ✅ COMPLETED (1 day) -- **Phase 2:** 1 day - Launch window detection ✅ COMPLETED (same day) -- **Phase 3:** 1.5 days - Spacecraft spawning ✅ COMPLETED (same day) -- **Phase 4:** 1.5 days - Full transfer integration test ⏸️ IN DEBUGGING -- **Phase 5:** 0.5 days - Enhanced transition tests ⏸️ NOT STARTED -- **Phase 6:** 1 day - Round-trip mission (optional) ⏸️ NOT STARTED - -### Actual Progress (January 16, 2026): -- **Phase 1:** ✅ COMPLETE - All transfer calculations validated -- **Phase 2:** ✅ COMPLETE - Launch window detection working -- **Phase 3:** ✅ COMPLETE - Spacecraft spawning functional -- **Phase 4:** 🔄 PARTIAL - Test framework complete, trajectory bug identified -- **Phase 5:** ⏸️ BLOCKED - Waiting on Phase 4 -- **Phase 6:** ⏸️ BLOCKED - Waiting on Phase 4 - -**Time Invested:** ~6 hours (Phases 1-3) -**Estimated Time to Complete Phase 4:** 2-3 hours debugging -**Total for Phases 1-5:** **~1 day** (excluding Phase 4 debug time) - ---- - -## Files Summary - -### New Files Created: -- `src/mission_planning.h` (+40 lines) ✅ -- `src/mission_planning.cpp` (+150 lines) ✅ -- `tests/test_mission_planning.cpp` (+95 lines) ✅ -- `tests/test_hohmann_transfer.cpp` (+73 lines) ✅ (Phase 4 partial) -- `tests/configs/earth_mars_simple.toml` (+30 lines) ✅ - -### Modified Files: -- `src/simulation.h` (+3 lines) ✅ -- `src/simulation.cpp` (+33 lines) ✅ -- `Makefile` (+5 lines) ✅ -- `tests/test_root_body_transitions.cpp` (refactor - PENDING Phase 5) - -### Net Lines: ~+429 lines (Phases 1-3 complete, Phase 4 partial) - ---- - -## Debugging Notes - -### Phase 4 Trajectory Bug - -**Symptom:** Spacecraft does not follow expected Hohmann transfer orbit - -**Initial Conditions (Correct):** -``` -Spacecraft global position: (-6.94×10⁹, -1.49×10¹¹, 0) m -Spacecraft global velocity: (-32697.6, 1518.47, 0) m/s -Spacecraft parent: 0 (Sun) -Initial orbital energy: -3.52×10⁸ J (correct for Hohmann transfer) -``` - -**After First update_simulation() (Incorrect):** -``` -Spacecraft local position: (6.11×10⁷, -2.84×10⁶, 0) m -Energy: +3.51×10²³ J (wrong sign, unphysically large) -Energy drift: 9.98×10¹⁶% (should be < 5%) -``` - -**Expected Behavior:** -``` -Spacecraft should follow ellipse: -- Periapsis: 1.496×10¹¹ m (Earth distance) -- Apoapsis: 2.279×10¹¹ m (Mars distance) -- Semi-major axis: 1.888×10¹¹ m -- Period: ~518 days (full orbit), ~259 days (half-orbit to Mars) +[[bodies]] +name = "Spacecraft" +mass = 1.0 +radius = 1000.0 +# Position and velocity will be initialized at runtime for LEO orbit +position = { x = 0.0, y = 0.0, z = 0.0 } +velocity = { x = 0.0, y = 0.0, z = 0.0 } +parent_index = 1 # Earth +color = { r = 1.0, g = 0.0, b = 0.5 } +eccentricity = 0.0 +# Semi-major axis will be: Earth radius + 200km +semi_major_axis = 6.571e6 # Placeholder, will be set during initialization ``` -**Actual Behavior:** -- Spacecraft trajectory diverges immediately -- Not following Hohmann ellipse -- Energy becomes positive (hyperbolic, unbound) -- Position magnitude grows to ~10¹³ AU (wrong scale) - -**Hypothesis:** -The issue is likely in `update_simulation()` coordinate transforms for newly added bodies. Specifically: - -1. **Local frame integration error:** `rk4_step()` integrates local coordinates, but newly added spacecraft may have incorrect local coordinates after first update. - -2. **compute_global_coordinates() not called:** After spawning spacecraft, we set both local and global coordinates manually. The first `update_simulation()` may recalculate local coordinates incorrectly. - -3. **SOI transition interference:** Spacecraft parent = 0 (Sun), but `find_dominant_body()` might incorrectly switch parent during first few updates. - -4. **Order of operations issue:** In `update_simulation()`: - - Check SOI transition - - If transition: convert local→global, switch parent, convert global→local - - Integrate: `rk4_step()` on local coordinates - - Compute global: `compute_global_coordinates()` - - The problem: Newly added spacecraft already has correct global coordinates, but `compute_global_coordinates()` may recalculate them incorrectly from possibly corrupted local coordinates. - -**Investigation Plan:** -1. Add printf statements to `update_simulation()` to print spacecraft local/global coordinates before/after each operation -2. Check if `find_dominant_body()` is changing spacecraft parent unexpectedly -3. Verify `rk4_step()` is using correct parameters (position, velocity, dt, body_mass, parent_mass) -4. Test with spacecraft starting at parent ≠ 0 to see if issue is specific to Sun-centered orbits -5. Consider calling `compute_global_coordinates()` immediately after `add_body_to_simulation()` to ensure consistency - -**Key Code Sections to Examine:** -- `src/simulation.cpp::update_simulation()` - lines 95-141 -- `src/simulation.cpp::add_body_to_simulation()` - lines 29-67 -- `src/physics.cpp::rk4_step()` - lines 56-89 -- `src/physics.cpp::evaluate_acceleration()` - lines 91-104 - -**Potential Fix:** -The issue may be that we're setting spacecraft global coordinates manually in `add_body_to_simulation()`, but `update_simulation()` expects to compute them from local coordinates. The fix might be to: -1. Set only local coordinates when adding spacecraft -2. Let `update_simulation()` handle global coordinate computation -3. OR: Add a flag to skip `compute_global_coordinates()` for the first few updates after spawning - -**Workaround for Testing:** -For now, test Phase 1-3 components separately without running full transfer simulation. The core functionality (calculations, launch window, spawning) is validated and working correctly. - ---- - -## Risks and Mitigations - -### High Risk -- **Energy conservation during transfer** - - Mitigation: Verify with energy tracking in tests - - Backup: Use smaller timestep if needed - -- **SOI transition edge cases** - - Mitigation: Comprehensive transition tracking in tests - - Backup: Adjust hysteresis if oscillation occurs - -### Medium Risk -- **Launch window calculation accuracy** - - Mitigation: Validate against known missions (NASA data) - - Backup: Increase tolerance window if needed - -- **Spacecraft spawning bugs** - - Mitigation: Unit tests for velocity/position - - Backup: Manual verification with visualization - -### Low Risk -- **Fast-forward simulation stability** - - Mitigation: Use existing `update_simulation()` (tested) - - Backup: Reduce fast-forward steps if needed - --- ## Future Work (Post-Implementation) ### Immediate Next Steps -1. **Inclination Support** - Extend to 3D transfers - - Need 3D angular position calculations - - Longitude of ascending node, inclination, argument of periapsis - - Phase angle calculations in 3D - -2. **Capture Burns** - Add velocity reduction at arrival - - Simulate retrograde burns for orbital capture - - Calculate Δv needed for circularization -3. **Lambert Solver** - General transfer solver - - Not just Hohmann transfers - - Arbitrary departure/arrival positions and times - - Non-planar transfers +#### 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) ### Visualization Features -4. **Mission GUI** - Interactive departure window visualization - - Show current phase angle vs. required - - Countdown to launch window - - Transfer trajectory preview -5. **Multiple Burns** - Support for course corrections - - Mid-course corrections - - Gravity assist maneuvers - - Powered flybys - -6. **SOI Visualization** - Render SOI boundaries - - Wireframe spheres for each body - - Color-coded by mass - - Toggle with keyboard +#### 5. 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 + +#### 6. Multiple Burns Support +- Mid-course corrections +- Gravity assist maneuvers +- Powered flybys +- Multi-stage missions + +#### 7. SOI Visualization +- Render SOI boundaries as wireframe spheres +- Color-coded by mass +- Toggle with keyboard shortcut +- Show SOI transitions in real-time ### Advanced Features -7. **Mission Planner** - Complete mission design tool - - Multi-leg missions - - Optimization (minimum Δv, minimum time) - - Launch date search - -8. **Real Ephemeris** - Use actual planetary positions - - JPL Horizons API integration - - Date-based initialization - - Real mission planning ---- - -## References - -- `docs/patched_conics_plan.md` - SOI transition implementation -- `docs/hierarchical_frames_plan.md` - Local frame integration (archived) -- `docs/implementation_plan.md` - Overall system architecture -- NASA Technical Memorandum "Hohmann Transfer Calculations" -- Orbital Mechanics for Engineering Students (Curtis) +#### 8. 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 + +#### 9. 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 + +#### 10. Enhanced Trajectory Analysis +- Lambert solver for general transfers +- Not just Hohmann transfers +- Arbitrary departure/arrival positions and times +- Non-planar transfers --- ## Notes -**Coordinate System:** +### 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:** +### Timekeeping - Simulation time in seconds, conversions to days for display -- Fast-forward uses 1-day steps for efficiency +- Fast-forward uses 1-day steps for efficiency during launch window wait - Timestep remains 60s during fast-forward -**Mass Strategy:** +### Mass Strategy - Spacecraft mass = 1.0 kg (negligible but non-zero) -- Physics engine handles test particles correctly (mass cancels) -- No N-body perturbations from spacecraft +- 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, etc.) -- Energy conservation tracking -- Transfer time accuracy -- SOI transition verification +### 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:** +### Testing Approach - Unit tests for each function (formulas, calculations) -- Integration tests for full missions -- Regression tests against manual config approach +- 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) diff --git a/docs/mission_planning.md.old b/docs/mission_planning.md.old new file mode 100644 index 0000000..64cd576 --- /dev/null +++ b/docs/mission_planning.md.old @@ -0,0 +1,843 @@ +# Mission Planning Module - Implementation Plan + +**Date:** January 16, 2026 +**Status:** Phase 1-3 Complete ✅, Phase 4 Debugging Required 🔄 +**Branch:** patched-conics +**Implementation Progress:** 70% complete (3/6 phases complete, 1 phase debugging) + +## Implementation Progress + +### ✅ Phase 1: Core Transfer Calculations - COMPLETE +**Status:** All tests passing (3/3) +**Date Completed:** January 16, 2026 + +**Implemented:** +- `calculate_hohmann_transfer()` - Computes transfer orbit parameters +- `calculate_angular_position()` - Calculates body angle in XY plane +- `calculate_required_phase_angle()` - Computes optimal launch phase angle + +**Validation:** +- Earth→Mars transfer time: 258.8 days (±0.08% of expected) +- Required phase angle: 44.3° (±0.08° of expected) +- Delta-v injection: 2.94 km/s (±0.01% of expected) +- All NASA reference values validated within 5% + +**Tests:** `tests/test_mission_planning.cpp` - 17 assertions, 6 test cases, all pass + +--- + +### ✅ Phase 2: Launch Window Detection - COMPLETE +**Status:** All tests passing +**Date Completed:** January 16, 2026 + +**Implemented:** +- `check_launch_window()` - Tests if current phase angle allows optimal launch +- `wait_for_launch_window()` - Fast-forwards simulation to launch window + +**Validation:** +- Launch window detection works correctly +- Fast-forward advances simulation to correct phase (within 1°) +- Wait time: ~94 days for Earth→Mars transfer window +- Phase angle wrapping handled correctly (0-360° range) + +**Tests:** Integrated into mission planning test suite - all pass + +--- + +### ✅ Phase 3: Spacecraft Spawning - COMPLETE +**Status:** All tests passing (9/9 assertions) +**Date Completed:** January 16, 2026 + +**Implemented:** +- `add_body_to_simulation()` - Dynamic body creation in simulation.cpp +- `spawn_spacecraft_on_transfer()` - Creates spacecraft with correct velocity + +**Validation:** +- Spacecraft spawns at correct position (0m error from departure body) +- Spacecraft velocity = departure velocity + Δv (0% error) +- Spacecraft parent = Sun (index 0) +- Local/global coordinates initialized correctly +- SOI radius calculated correctly + +**Tests:** `tests/test_hohmann_transfer.cpp::Spacecraft spawning` - 9 assertions, all pass + +**Key Implementation Details:** +- Uses departure body's actual velocity direction (not computed from position) +- Spacecraft mass = 1.0 kg (test particle, mass cancels in physics) +- Position and velocity set before adding to simulation +- Coordinate transforms handle parent=0 (Sun) correctly + +--- + +### ⏸️ Phase 4: Full Transfer Test - DEBUGGING REQUIRED +**Status:** Partially implemented, trajectory issue identified +**Date Started:** January 16, 2026 +**Issue:** Spacecraft trajectory deviates from expected Hohmann transfer orbit + +**Implemented:** +- Test framework for Earth→Mars transfer +- Launch window detection and waiting +- Spacecraft spawning with transfer parameters +- Energy drift tracking and validation + +**Current Issue:** +- Spacecraft spawns with correct initial conditions (position, velocity, parent) +- Initial orbital energy: -3.52×10⁸ J (correct for transfer orbit) +- After first `update_simulation()` call, spacecraft trajectory diverges +- Final orbital energy: +3.51×10²³ J (huge energy error, wrong sign!) +- Spacecraft not following Hohmann transfer ellipse +- Energy drift: 9.98×10¹⁶% (unphysically large) + +**Debugging Findings:** +1. Spacecraft spawns correctly: + - Global position matches Earth: (-6.94×10⁹, -1.49×10¹¹, 0) m + - Global velocity correct: (-32697.6, 1518.47, 0) m/s + - Parent = Sun (index 0) + - Local position initially correct relative to Sun + +2. After first `update_simulation()`: + - Local position jumps incorrectly to: (6.11×10⁷, -2.84×10⁶, 0) m + - This suggests `compute_global_coordinates()` or local frame integration is wrong + +3. Possible root causes: + - Bug in `update_simulation()` coordinate transforms for newly added bodies + - Issue with local frame integration when parent = 0 (Sun) + - `compute_global_coordinates()` not called correctly after body addition + - SOI transition logic interfering with spacecraft (only 1 SOI transition detected) + +4. Investigation needed: + - Add debug output to `update_simulation()` to track coordinate transforms + - Check if `find_dominant_body()` incorrectly changing spacecraft's parent + - Verify RK4 integration is using correct reference frame + - Test with spacecraft starting at parent ≠ 0 (compare behavior) + +**Tests:** `tests/test_hohmann_transfer.cpp::Earth → Mars Hohmann Transfer - Basic` +- Current: 4/5 assertions pass +- Failing: Energy drift validation (expect < 5%, actual 9.98×10¹⁶%) + +**Next Steps for Debugging:** +1. Add detailed logging to `update_simulation()` to track coordinate transforms +2. Verify spacecraft's local position/velocity before/after each update +3. Check if parent index changes unexpectedly during simulation +4. Consider if `add_body_to_simulation()` needs to call `compute_global_coordinates()` +5. Test with simplified scenario (e.g., Earth → fake destination at 1.2 AU) + +**Estimated Time to Resolve:** 2-3 hours of focused debugging + +--- + +### ⏸️ Phase 5: Enhance Root Body Transition Tests - NOT STARTED +**Status:** Deferred until Phase 4 debugged +**Dependency:** Phase 4 (working transfer orbits required) + +--- + +### ⏸️ Phase 6: Round-Trip Mission - NOT STARTED +**Status:** Deferred until Phase 4 debugged +**Dependency:** Phase 4 (single-leg transfer must work first) + +--- + +## Overview +Add a mission planning module to calculate realistic interplanetary transfers with proper departure windows, replacing manual config positioning with computed trajectories. This enables proper testing of patched conics mechanics and provides a foundation for spacecraft simulation. + +## Design Decisions + +1. **Spacecraft Mass**: Use small but non-zero (1.0 kg) - works with existing physics (mass cancels out in acceleration) +2. **Capture Burns**: Skip for initial implementation - implement flyby missions only +3. **Inclination**: Planar first (z=0), defer 3D to future work +4. **Scope**: Full mission planner with departure window timing, launch window detection, and spacecraft spawning + +## Key Technical Discovery + +The physics engine already supports test particles correctly. The acceleration calculation is: +``` +acceleration = (G × body_mass × parent_mass / r²) / body_mass = G × parent_mass / r² +``` + +Body mass cancels out, so any small mass works. We'll use 1.0 kg. + +## Data Structures + +### TransferParameters +```cpp +struct TransferParameters { + double semi_major_axis; // Transfer orbit semi-major axis (meters) + double eccentricity; // Transfer orbit eccentricity + double periapsis; // Closest approach (departure radius) + double apoapsis; // Furthest distance (arrival radius) + double transfer_time; // Time required for transfer (seconds) + double departure_velocity; // Required velocity at departure (m/s) + double arrival_velocity; // Velocity at arrival (relative to Sun, m/s) + double phase_angle_deg; // Required phase angle for launch (degrees) + double delta_v_injection; // Delta-V needed for transfer injection (m/s) + double delta_v_capture; // Delta-V needed for capture (optional, future) +}; +``` + +## Implementation Phases + +### Phase 1: Core Transfer Calculations (1 day) + +**Goal:** Implement orbital mechanics calculations for Hohmann transfers + +**Files:** +- `src/mission_planning.h` (new) - Function declarations +- `src/mission_planning.cpp` (new) - Core calculations +- `tests/test_mission_planning.cpp` (new) - Unit tests for formulas + +**Functions to implement:** + +#### 1.1 `calculate_hohmann_transfer()` +Calculates transfer orbit parameters given departure and arrival radii. + +**Algorithm:** +``` +a_transfer = (r_departure + r_arrival) / 2 +e = (r_arrival - r_departure) / (r_arrival + r_departure) +T_transfer = π × sqrt(a³ / GM) + +v_departure = sqrt(G × M × (2/r_departure - 1/a)) +v_arrival = sqrt(G × M × (2/r_arrival - 1/a)) +v_circular = sqrt(G × M / r_departure) + +Δv_injection = v_departure - v_circular +``` + +**Validation:** Earth→Mars values: +- Transfer time: ~259 days +- Phase angle: ~44.3° +- Δv: ~2.94 km/s + +#### 1.2 `calculate_angular_position()` +Calculates angular position of a body relative to its center (in XY plane). + +**Algorithm:** +``` +rel_pos = body_position - center_position +angle = atan2(y, x) +Normalize to [0, 2π) +``` + +#### 1.3 `calculate_required_phase_angle()` +Calculates optimal phase angle for launch. + +**Algorithm:** +``` +ω_departure = 2π / T_departure +α = ω_departure × T_transfer +phase_angle = π - α (in radians) +Convert to degrees +``` + +**Tests:** +- Validate transfer parameters against NASA reference values (±5%) +- Verify angular position calculations for circular orbits +- Test phase angle formula with known cases + +**Expected outcome:** +- ✅ Accurate transfer orbit calculations +- ✅ Verified against known mission parameters + +**Estimated complexity:** Low +**Risk:** Low (well-known orbital mechanics formulas) + +--- + +### Phase 2: Launch Window Detection (1 day) + +**Goal:** Detect when launch window is open and advance simulation to it + +**Files:** +- `src/mission_planning.cpp` (extend) +- `tests/test_launch_window.cpp` (new) + +**Functions to implement:** + +#### 2.1 `check_launch_window()` +Tests if current positions allow optimal launch. + +**Algorithm:** +``` +θ_depart = calculate_angular_position(departure, sun) +θ_arrival = calculate_angular_position(arrival, sun) + +current_phase = θ_arrival - θ_depart (normalize to [0, 2π)) +current_phase_deg = current_phase × (180/π) + +error = |current_phase_deg - required_phase_angle_deg| +Handle wrap-around: if error > 180°, use |error - 360°| + +return error <= tolerance +``` + +#### 2.2 `wait_for_launch_window()` +Advances simulation until launch window opens. + +**Algorithm:** +``` +while !check_launch_window(...): + Fast-forward by 1 day per iteration (for efficiency) + for i in 0..(86400 / dt): + update_simulation(sim) +``` + +**Tests:** +- Create Earth+Mars config at wrong phase angle +- Call `wait_for_launch_window()` - should advance simulation +- Verify phase angle is now within tolerance (1°) +- Measure time waited - should be reasonable (weeks to months) + +**Expected outcome:** +- ✅ Can detect proper launch windows +- ✅ Can advance simulation to launch window +- ✅ Phase angle accuracy within 1° + +**Estimated complexity:** Low-Medium +**Risk:** Low (simulation fast-forward is safe) + +--- + +### Phase 3: Spacecraft Spawning (1.5 days) + +**Goal:** Create spacecraft at departure with correct velocity + +**Files:** +- `src/simulation.h` (+3 lines) - Add function declaration +- `src/simulation.cpp` (+30 lines) - Implement dynamic body addition +- `src/mission_planning.cpp` (+40 lines) - Spacecraft spawning logic + +**Functions to implement:** + +#### 3.1 `add_body_to_simulation()` (in simulation.cpp) +Adds a new body to the simulation at runtime. + +**Algorithm:** +``` +Check capacity (body_count < max_bodies) +Copy body to next available slot +Initialize local coordinates: + if parent_index >= 0: + local_pos = global_pos - parent_pos + local_vel = global_vel - parent_vel + else: + local_pos = global_pos + local_vel = global_vel +Calculate SOI radius (if has parent) +Increment body_count +Return new body index +``` + +#### 3.2 `spawn_spacecraft_on_transfer()` (in mission_planning.cpp) +Creates spacecraft on transfer trajectory at departure. + +**Algorithm:** +``` +Create spacecraft body: + name = "Spacecraft" + mass = 1.0 kg (negligible but non-zero) + radius = 1.0 km (for visualization) + color = magenta/pink + eccentricity = transfer.eccentricity + semi_major_axis = transfer.semi_major_axis + +Position = departure.position + +Velocity = departure.velocity + Δv_injection: + departure_pos = departure.position - sun.position + orbit_dir = normalize(cross(departure_pos, z_axis)) + delta_v = orbit_dir × transfer.delta_v_injection + spacecraft.velocity = departure.velocity + delta_v + +Parent = Sun (index 0) +Add to simulation via add_body_to_simulation() +Return spacecraft index +``` + +**Tests:** +- Spawn spacecraft at Earth +- Verify initial position matches Earth +- Verify velocity = Earth velocity + Δv +- Verify parent = Sun +- Verify local coordinates initialized correctly + +**Expected outcome:** +- ✅ Spacecraft spawns correctly at departure +- ✅ Initial velocity matches transfer requirements +- ✅ Parent set to Sun for transfer orbit +- ✅ Local/global coordinates consistent + +**Estimated complexity:** Medium +**Risk:** Medium (dynamic body addition affects simulation state) + +--- + +### Phase 4: Full Transfer Test (1.5 days) + +**Goal:** End-to-end test of Earth→Mars Hohmann transfer + +**Files:** +- `tests/test_hohmann_transfer.cpp` (new) - Main integration test +- `tests/configs/earth_mars_simple.toml` (new) - Simple 3-body config + +**Test scenario:** +```cpp +TEST_CASE("Earth → Mars Hohmann Transfer", "[mission][hohmann]") { + // 1. Load Earth+Mars system + // 2. Calculate transfer parameters + // 3. Wait for launch window (within 1° tolerance) + // 4. Record departure time + // 5. Spawn spacecraft on transfer trajectory + // 6. Simulate until arrival (transfer_time × 1.1) + // 7. Track SOI transitions (Earth→Sun→Mars) + // 8. Verify arrival at Mars (distance < 2×SOI) + // 9. Verify transfer time accuracy (±10%) +} +``` + +**Success criteria:** +- Spacecraft enters Mars SOI +- Transfer time: 259 ± 26 days +- Final distance to Mars < 2 × Mars_SOI +- SOI transitions: Earth→Sun→Mars (tracked) +- Energy drift < 1% during transfer + +**Expected outcome:** +- ✅ Complete end-to-end transfer validated +- ✅ Patched conics mechanics tested (3 SOI changes) +- ✅ Transfer trajectory matches prediction + +**Estimated complexity:** Medium-High +**Risk:** Medium-High (integration test may reveal edge cases) + +--- + +### Phase 5: Enhance Root Body Transition Tests (0.5 days) + +**Goal:** Replace manual config positioning with calculated transfers + +**Files:** +- `tests/test_root_body_transitions.cpp` (refactor) +- Remove `tests/configs/manual_root_transition.toml` + +**Changes:** +1. Replace "Root body transition - Earth to Sun" test: + - Use `spawn_spacecraft_on_transfer()` instead of manual config + - Calculate transfer parameters + - Wait for launch window + - Verify Earth→Sun transition happens + +2. Replace "Root body round-trip" test: + - Calculate Earth→Mars transfer + - Wait for window + - Spawn spacecraft + - Verify round-trip SOI transitions + +3. Add better validation: + - Verify transition order (Earth→Sun→Mars) + - Verify arrival distance < threshold + - Verify energy conservation + - Verify spacecraft follows predicted trajectory + +**Expected outcome:** +- ✅ Realistic mission-based testing +- ✅ Better validation than `sun_transitions >= 1` +- ✅ Eliminates manual config positioning +- ✅ Tests use actual orbital mechanics + +**Estimated complexity:** Low +**Risk:** Low (refactoring existing tests) + +--- + +### Phase 6: Round-Trip Mission (1 day) - Optional + +**Goal:** Validate full mission lifecycle with return journey + +**Files:** +- `tests/test_round_trip.cpp` (new) + +**Test scenario:** +```cpp +TEST_CASE("Earth → Mars → Earth Round Trip", "[mission][round-trip]") { + // 1. Earth→Mars transfer + // 2. Verify arrival at Mars + // 3. Wait for Mars→Earth return window + // 4. Spawn new spacecraft at Mars for return + // 5. Simulate Mars→Earth return + // 6. Verify both transfers complete + // 7. Verify return arrival at Earth +} +``` + +**Success criteria:** +- Both transfers complete successfully +- Return time: ~259 ± 26 days +- Final distance to Earth < 2 × Earth_SOI +- Energy conserved across entire round-trip + +**Expected outcome:** +- ✅ Full mission lifecycle validated +- ✅ Multiple departure windows handled +- ✅ Patched conics round-trip confirmed + +**Estimated complexity:** Medium +**Risk:** Medium (long simulation time) + +--- + +## Integration with Existing Code + +### Reuses Existing Components: + +**Physics Module:** +- `rk4_step()` - RK4 integration works with any mass +- `evaluate_acceleration()` - Mass cancels out, test particles work + +**Simulation Module:** +- `find_dominant_body()` - SOI transitions work with parent_index = 0 (Sun) +- `update_simulation()` - Handles root bodies correctly +- Coordinate frames - Local/global transformations already work + +**Test Utilities:** +- `calculate_orbital_metrics()` - Can use for trajectory validation +- `OrbitTracker` - Can track orbital progress + +### New Components: + +**Mission Planning Module:** +- `mission_planning.h/cpp` - Mission calculations +- TransferParameters struct - Transfer orbit description +- Phase angle calculations - Launch window detection + +**Simulation Extensions:** +- `add_body_to_simulation()` - Dynamic spacecraft creation +- Runtime body addition - No more config-only initialization + +--- + +## Build System Changes + +### Makefile Modifications + +**Add to OBJECTS list:** +```makefile +OBJECTS = main.o physics.o simulation.o config_loader.o renderer.o \ + test_utilities.o mission_planning.o +``` + +**Add build rule:** +```makefile +mission_planning.o: src/mission_planning.cpp src/mission_planning.h + $(CXX) $(CXXFLAGS) -c src/mission_planning.cpp -o mission_planning.o +``` + +**Add to test build:** +```makefile +# Test executable includes mission_planning.o +test: test_build + ./orbit_test +``` + +--- + +## Test Configurations + +### earth_mars_simple.toml +Simple 3-body system for transfer testing: +```toml +[[bodies]] +name = "Sun" +mass = 1.989e30 +radius = 6.96e8 +position = { x = 0.0, y = 0.0, z = 0.0 } +parent_index = -1 +color = { r = 1.0, g = 1.0, b = 0.0 } +eccentricity = 0.0 +semi_major_axis = 0.0 + +[[bodies]] +name = "Earth" +mass = 5.972e24 +radius = 6.371e6 +position = { x = 1.496e11, y = 0.0, z = 0.0 } +parent_index = 0 +color = { r = 0.0, g = 0.5, b = 1.0 } +eccentricity = 0.0 +semi_major_axis = 1.496e11 + +[[bodies]] +name = "Mars" +mass = 6.39e23 +radius = 3.3895e6 +position = { x = 2.279e11, y = 0.0, z = 0.0 } +parent_index = 0 +color = { r = 0.8, g = 0.3, b = 0.1 } +eccentricity = 0.0 +semi_major_axis = 2.279e11 +``` + +--- + +## Success Criteria + +### ✅ Phase 1-2 Success - COMPLETE +- [x] Transfer parameters match NASA reference (±5%) +- [x] Phase angle calculations accurate (±1°) +- [x] Launch window detection works +- [x] Fast-forward to launch window succeeds + +### ✅ Phase 3 Success - COMPLETE +- [x] Spacecraft spawns at correct position +- [x] Initial velocity = Earth velocity + Δv +- [x] Parent = Sun for transfer orbit +- [x] Local/global coordinates consistent + +### ⏸️ Phase 4 Success - IN PROGRESS (DEBUGGING) +- [ ] Earth→Mars transfer completes (time ±10%) +- [ ] Spacecraft reaches Mars SOI (distance < 2×SOI) +- [ ] SOI transitions: Earth→Sun→Mars tracked correctly +- [ ] Energy drift < 1% during transfer (currently 9.98×10¹⁶%) + +### ⏸️ Phase 5 Success - NOT STARTED +- [ ] Root body transition tests use calculated trajectory +- [ ] Manual config positioning eliminated +- [ ] Better validation than `sun_transitions >= 1` + +### ⏸️ Phase 6 Success - NOT STARTED +- [ ] Round-trip mission completes +- [ ] Both transfers validated +- [ ] Return journey matches expectations + +--- + +## Timeline Estimate vs. Actual + +### Planned: +- **Phase 1:** 1 day - Core transfer calculations ✅ COMPLETED (1 day) +- **Phase 2:** 1 day - Launch window detection ✅ COMPLETED (same day) +- **Phase 3:** 1.5 days - Spacecraft spawning ✅ COMPLETED (same day) +- **Phase 4:** 1.5 days - Full transfer integration test ⏸️ IN DEBUGGING +- **Phase 5:** 0.5 days - Enhanced transition tests ⏸️ NOT STARTED +- **Phase 6:** 1 day - Round-trip mission (optional) ⏸️ NOT STARTED + +### Actual Progress (January 16, 2026): +- **Phase 1:** ✅ COMPLETE - All transfer calculations validated +- **Phase 2:** ✅ COMPLETE - Launch window detection working +- **Phase 3:** ✅ COMPLETE - Spacecraft spawning functional +- **Phase 4:** 🔄 PARTIAL - Test framework complete, trajectory bug identified +- **Phase 5:** ⏸️ BLOCKED - Waiting on Phase 4 +- **Phase 6:** ⏸️ BLOCKED - Waiting on Phase 4 + +**Time Invested:** ~6 hours (Phases 1-3) +**Estimated Time to Complete Phase 4:** 2-3 hours debugging +**Total for Phases 1-5:** **~1 day** (excluding Phase 4 debug time) + +--- + +## Files Summary + +### New Files Created: +- `src/mission_planning.h` (+40 lines) ✅ +- `src/mission_planning.cpp` (+150 lines) ✅ +- `tests/test_mission_planning.cpp` (+95 lines) ✅ +- `tests/test_hohmann_transfer.cpp` (+73 lines) ✅ (Phase 4 partial) +- `tests/configs/earth_mars_simple.toml` (+30 lines) ✅ + +### Modified Files: +- `src/simulation.h` (+3 lines) ✅ +- `src/simulation.cpp` (+33 lines) ✅ +- `Makefile` (+5 lines) ✅ +- `tests/test_root_body_transitions.cpp` (refactor - PENDING Phase 5) + +### Net Lines: ~+429 lines (Phases 1-3 complete, Phase 4 partial) + +--- + +## Debugging Notes + +### Phase 4 Trajectory Bug + +**Symptom:** Spacecraft does not follow expected Hohmann transfer orbit + +**Initial Conditions (Correct):** +``` +Spacecraft global position: (-6.94×10⁹, -1.49×10¹¹, 0) m +Spacecraft global velocity: (-32697.6, 1518.47, 0) m/s +Spacecraft parent: 0 (Sun) +Initial orbital energy: -3.52×10⁸ J (correct for Hohmann transfer) +``` + +**After First update_simulation() (Incorrect):** +``` +Spacecraft local position: (6.11×10⁷, -2.84×10⁶, 0) m +Energy: +3.51×10²³ J (wrong sign, unphysically large) +Energy drift: 9.98×10¹⁶% (should be < 5%) +``` + +**Expected Behavior:** +``` +Spacecraft should follow ellipse: +- Periapsis: 1.496×10¹¹ m (Earth distance) +- Apoapsis: 2.279×10¹¹ m (Mars distance) +- Semi-major axis: 1.888×10¹¹ m +- Period: ~518 days (full orbit), ~259 days (half-orbit to Mars) +``` + +**Actual Behavior:** +- Spacecraft trajectory diverges immediately +- Not following Hohmann ellipse +- Energy becomes positive (hyperbolic, unbound) +- Position magnitude grows to ~10¹³ AU (wrong scale) + +**Hypothesis:** +The issue is likely in `update_simulation()` coordinate transforms for newly added bodies. Specifically: + +1. **Local frame integration error:** `rk4_step()` integrates local coordinates, but newly added spacecraft may have incorrect local coordinates after first update. + +2. **compute_global_coordinates() not called:** After spawning spacecraft, we set both local and global coordinates manually. The first `update_simulation()` may recalculate local coordinates incorrectly. + +3. **SOI transition interference:** Spacecraft parent = 0 (Sun), but `find_dominant_body()` might incorrectly switch parent during first few updates. + +4. **Order of operations issue:** In `update_simulation()`: + - Check SOI transition + - If transition: convert local→global, switch parent, convert global→local + - Integrate: `rk4_step()` on local coordinates + - Compute global: `compute_global_coordinates()` + + The problem: Newly added spacecraft already has correct global coordinates, but `compute_global_coordinates()` may recalculate them incorrectly from possibly corrupted local coordinates. + +**Investigation Plan:** +1. Add printf statements to `update_simulation()` to print spacecraft local/global coordinates before/after each operation +2. Check if `find_dominant_body()` is changing spacecraft parent unexpectedly +3. Verify `rk4_step()` is using correct parameters (position, velocity, dt, body_mass, parent_mass) +4. Test with spacecraft starting at parent ≠ 0 to see if issue is specific to Sun-centered orbits +5. Consider calling `compute_global_coordinates()` immediately after `add_body_to_simulation()` to ensure consistency + +**Key Code Sections to Examine:** +- `src/simulation.cpp::update_simulation()` - lines 95-141 +- `src/simulation.cpp::add_body_to_simulation()` - lines 29-67 +- `src/physics.cpp::rk4_step()` - lines 56-89 +- `src/physics.cpp::evaluate_acceleration()` - lines 91-104 + +**Potential Fix:** +The issue may be that we're setting spacecraft global coordinates manually in `add_body_to_simulation()`, but `update_simulation()` expects to compute them from local coordinates. The fix might be to: +1. Set only local coordinates when adding spacecraft +2. Let `update_simulation()` handle global coordinate computation +3. OR: Add a flag to skip `compute_global_coordinates()` for the first few updates after spawning + +**Workaround for Testing:** +For now, test Phase 1-3 components separately without running full transfer simulation. The core functionality (calculations, launch window, spawning) is validated and working correctly. + +--- + +## Risks and Mitigations + +### High Risk +- **Energy conservation during transfer** + - Mitigation: Verify with energy tracking in tests + - Backup: Use smaller timestep if needed + +- **SOI transition edge cases** + - Mitigation: Comprehensive transition tracking in tests + - Backup: Adjust hysteresis if oscillation occurs + +### Medium Risk +- **Launch window calculation accuracy** + - Mitigation: Validate against known missions (NASA data) + - Backup: Increase tolerance window if needed + +- **Spacecraft spawning bugs** + - Mitigation: Unit tests for velocity/position + - Backup: Manual verification with visualization + +### Low Risk +- **Fast-forward simulation stability** + - Mitigation: Use existing `update_simulation()` (tested) + - Backup: Reduce fast-forward steps if needed + +--- + +## Future Work (Post-Implementation) + +### Immediate Next Steps +1. **Inclination Support** - Extend to 3D transfers + - Need 3D angular position calculations + - Longitude of ascending node, inclination, argument of periapsis + - Phase angle calculations in 3D + +2. **Capture Burns** - Add velocity reduction at arrival + - Simulate retrograde burns for orbital capture + - Calculate Δv needed for circularization + +3. **Lambert Solver** - General transfer solver + - Not just Hohmann transfers + - Arbitrary departure/arrival positions and times + - Non-planar transfers + +### Visualization Features +4. **Mission GUI** - Interactive departure window visualization + - Show current phase angle vs. required + - Countdown to launch window + - Transfer trajectory preview + +5. **Multiple Burns** - Support for course corrections + - Mid-course corrections + - Gravity assist maneuvers + - Powered flybys + +6. **SOI Visualization** - Render SOI boundaries + - Wireframe spheres for each body + - Color-coded by mass + - Toggle with keyboard + +### Advanced Features +7. **Mission Planner** - Complete mission design tool + - Multi-leg missions + - Optimization (minimum Δv, minimum time) + - Launch date search + +8. **Real Ephemeris** - Use actual planetary positions + - JPL Horizons API integration + - Date-based initialization + - Real mission planning + +--- + +## References + +- `docs/patched_conics_plan.md` - SOI transition implementation +- `docs/hierarchical_frames_plan.md` - Local frame integration (archived) +- `docs/implementation_plan.md` - Overall system architecture +- NASA Technical Memorandum "Hohmann Transfer Calculations" +- Orbital Mechanics for Engineering Students (Curtis) + +--- + +## 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 +- 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) +- No N-body perturbations from spacecraft + +**Validation Strategy:** +- Compare against NASA reference missions (Viking, Curiosity, etc.) +- Energy conservation tracking +- Transfer time accuracy +- SOI transition verification + +**Testing Approach:** +- Unit tests for each function (formulas, calculations) +- Integration tests for full missions +- Regression tests against manual config approach