Browse Source

docs/planning: add hohmann rendezvous quantization analysis

Document burn timing quantization behavior, DT sweep results,
and proposed fix strategies for Hohmann transfer rendezvous.
main
cinnaboot 3 months ago
parent
commit
3aba55afa7
  1. 192
      docs/planning/hohmann-rendezvous-quantization-fix.md

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