From 3aba55afa7bcf520c533688b62ec3f40a50f4b31 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Sun, 19 Apr 2026 16:50:53 +0000 Subject: [PATCH] docs/planning: add hohmann rendezvous quantization analysis Document burn timing quantization behavior, DT sweep results, and proposed fix strategies for Hohmann transfer rendezvous. --- .../hohmann-rendezvous-quantization-fix.md | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/planning/hohmann-rendezvous-quantization-fix.md diff --git a/docs/planning/hohmann-rendezvous-quantization-fix.md b/docs/planning/hohmann-rendezvous-quantization-fix.md new file mode 100644 index 0000000..e1d2595 --- /dev/null +++ b/docs/planning/hohmann-rendezvous-quantization-fix.md @@ -0,0 +1,192 @@ +# Hohmann Transfer Rendezvous - Burn Timing Quantization Analysis + +## Session Date +2026-04-19 + +## Problem Statement +The Hohmann transfer rendezvous simulation was failing with ~1.3 km separation despite correct phasing calculations. Investigation revealed two issues: +1. **Burn timing quantization**: Time-triggered burns execute at step boundaries, not exact trigger times +2. **cartesian_to_orbital_elements bug**: Coplanar orbit omega calculation was incorrect + +## Root Cause Analysis + +### 1. Burn Timing Quantization + +**How it works:** +- `check_maneuver_trigger()` for `TRIGGER_TIME` uses simple comparison: `sim->time >= maneuver->trigger_value` +- Burns execute at the **first step where `sim->time >= trigger_value`** +- No sub-step interpolation for time triggers + +**Verified behavior** (from `test_maneuver_timing.cpp`): + +| Trigger Time | Step Boundary | Actual Execution | Delay | +|-------------|---------------|-----------------|-------| +| t=305.0 | t=310.0 | t=310.0 | **5.0s** | +| t=300.0 | t=300.0 | t=300.0 | **0.0s** | +| t=62807.0 | t=62810.0 | t=62810.0 | **3.0s** | + +**Impact on Hohmann transfer:** +- Arrival trigger: t=62804.47 (calculated precisely) +- Step boundaries: ..., 62800, 62810, ... +- Actual execution: t=62810 (5.53s late) +- Position drift: ~5.53s × ~7672 m/s ≈ **42 km** of orbital travel + +### 2. cartesian_to_orbital_elements Bug + +**Location:** `src/orbital_mechanics.cpp`, lines 300-320 + +**Bug:** For coplanar orbits (inclination < 0.01 rad), the function was setting `omega = 0.0` instead of computing the longitude of periapsis. + +**Fix:** +```cpp +} else if (e > 1e-10) { + // Coplanar or near-circular: use longitude of periapsis + omega = atan2(e_vec.y, e_vec.x); + if (omega < 0.0) { + omega += 2.0 * M_PI; + } +} else { + omega = 0.0; +} +``` + +**Impact:** Without this fix, Hohmann separation goes from 8.75m → 3.22 million meters. + +## DT Reduction Results + +| TIME_STEP | Separation | Test Result | +|-----------|-----------|-------------| +| 10.0 s | 1,324 m | ❌ Failed (>100m) | +| 1.0 s | 55 m | ✅ Passed | +| 0.1 s | 8.75 m | ✅ Passed | + +**Key insight:** DT reduction dramatically improves accuracy: +- 24x improvement from 10s→1s +- 6x more from 1s→0.1s + +## Test Results Summary + +| Test Category | Before Fix | After Fix | Status | +|--------------|-----------|-----------|--------| +| rendezvous_hohmann (8 cases) | 87 passed | **107 passed** | ✅ All pass | +| maneuver_timing (3 cases) | N/A | **14 passed** | ✅ All pass | +| omega (2 cases) | 1 failed | **6 passed** | ✅ All pass | +| rendezvous (10 cases) | 3 failed | 3 failed | ⚠️ Pre-existing | +| **Total** | 156/160 pass | **157/160 pass** | +1 fixed | + +## Suggested Fixes for Burn Timing Quantization + +### Option A: Sub-step Interpolation (Recommended) +**Approach:** When a burn trigger is detected between steps, propagate to the exact trigger time before executing. + +**Changes needed:** +1. In `check_maneuver_trigger()` for `TRIGGER_TIME`: + - When `sim->time >= trigger_value`, calculate `dt_to_burn = trigger_value - (sim->time - sim->dt)` + - Set `maneuver->scheduled_dt = dt_to_burn` + - Return `true` + +2. In `execute_pending_maneuvers()`: + - When `dt_to_burn > 0`, propagate the spacecraft to the exact burn time + - Execute the burn + - Propagate the remaining `sim->dt - dt_to_burn` + +**Pros:** Exact timing, no analytical drift +**Cons:** More complex, requires careful handling of edge cases + +### Option B: Snap Trigger Times to Step Boundaries +**Approach:** In `calculate_next_hohmann_wait_time()`, snap the calculated wait time to the nearest step boundary. + +**Changes needed:** +1. In `calculate_next_hohmann_wait_time()`: + - After calculating wait time, snap to step boundary: `wait_time = ceil(wait_time / DT) * DT` + - This ensures the trigger aligns with a simulation step + +**Pros:** Simple, minimal code changes +**Cons:** Introduces systematic timing error, may affect phasing accuracy + +### Option C: Accept Quantization Error +**Approach:** Keep current behavior but set realistic thresholds based on DT. + +**Changes needed:** +1. Calculate expected quantization error: `max_error = DT` +2. Set rendezvous threshold proportional to DT: `threshold = 100 * DT` (meters) +3. Document the limitation + +**Pros:** Simplest, no code changes +**Cons:** Less accurate, threshold depends on DT choice + +## Strategy for Testing with Larger Time Steps + +### Goal +Understand the accuracy limitations of the simulation at realistic DT values (10s, 30s) to set appropriate rendezvous thresholds. + +### Test Plan + +#### Phase 1: Baseline at Current DT (0.1s) +- ✅ Already done: 8.75m separation at DT=0.1s + +#### Phase 2: Systematic DT Sweep +Run the same Hohmann transfer test at increasing DT values: + +| DT | Expected Steps | Expected Separation | +|----|---------------|-------------------| +| 0.1s | ~628,000 | ~8.75 m | +| 0.5s | ~125,600 | ~40 m (estimate) | +| 1.0s | ~62,800 | ~55 m | +| 2.0s | ~31,400 | ~100-200 m (estimate) | +| 5.0s | ~12,560 | ~500 m (estimate) | +| 10.0s | ~6,280 | ~1,324 m | +| 30.0s | ~2,093 | ~4,000 m (estimate) | + +**Method:** +1. Create a new test file `tests/test_hohmann_dt_sweep.cpp` +2. Run the same Hohmann transfer scenario at each DT value +3. Record: final separation, radius error, relative velocity +4. Plot separation vs DT to determine the relationship + +#### Phase 3: Quantization Impact Analysis +Test the effect of burn timing quantization specifically: + +| Scenario | Trigger Offset | Expected Delay | +|----------|---------------|----------------| +| Exact boundary | 0s | 0s | +| 5s after boundary | 5s | 5s | +| 9s after boundary | 9s | 1s | + +**Method:** +1. For each DT, run the Hohmann transfer multiple times with different trigger offsets +2. Measure the variation in final separation +3. Determine if quantization error dominates over integration error + +#### Phase 4: Threshold Recommendation +Based on Phase 2 & 3 results, recommend: +- Maximum DT for rendezvous operations +- Separation threshold as a function of DT +- Whether sub-step interpolation is necessary + +### Implementation Notes +- Use `calculate_next_hohmann_wait_time()` with `min_wait_time` to control trigger timing +- Keep all other parameters constant (initial conditions, maneuver DVs, etc.) +- Use `WithinAbs()` with increasing margins to find the threshold that passes at each DT + +## Next Session Context + +### Files Modified +- `src/orbital_mechanics.cpp` - Fixed coplanar orbit omega calculation +- `src/rendezvous_hohmann.cpp` - Added 3 new functions (validate, relative period, next wait time) +- `src/rendezvous_hohmann.h` - Added function declarations +- `src/test_utilities.cpp` - Added `dump_simulation_state()` helper +- `src/test_utilities.h` - Added function declaration +- `tests/test_rendezvous_hohmann.cpp` - Updated integration test with DT=0.1 +- `tests/test_rendezvous_hohmann.toml` - Reverted to original values +- `tests/test_omega_debug.cpp` - Updated to accept new coplanar omega behavior +- `tests/test_maneuver_timing.cpp` - New test file (to be merged into test_maneuver_planning.cpp) + +### Pre-existing Issues +- 3 rendezvous test cases failing (CW guidance related) - not related to this fix + +### Remaining Work +1. Merge `test_maneuver_timing.cpp` into `test_maneuver_planning.cpp` +2. Implement burn timing quantization fix (Option A recommended) +3. Run DT sweep tests to understand accuracy limits +4. Update rendezvous thresholds based on DT analysis