Browse Source

Replace mission planning doc with updated LEO spacecraft version

- Old doc renamed to mission_planning.md.old for reference
- New doc (leospacecraft_impulse_burn_plan.md) renamed to mission_planning.md
- Updated version includes LEO spacecraft, impulse burn, test config, and future work
main
cinnaboot 6 months ago
parent
commit
ac434cf7e7
  1. 844
      docs/leospacecraft_impulse_burn_plan.md
  2. 1311
      docs/mission_planning.md
  3. 843
      docs/mission_planning.md.old

844
docs/leospacecraft_impulse_burn_plan.md

@ -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, &params);
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)

1311
docs/mission_planning.md

File diff suppressed because it is too large Load Diff

843
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
Loading…
Cancel
Save