# 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)