You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.9 KiB
4.9 KiB
Exact Position Burn Execution - Implementation Plan
Date: 2026-02-21
Status: COMPLETED ✅
All 143 tests passing.
Problem Statement
True anomaly triggers correctly calculate when a crossing will occur, but burns execute at the current position, not the trigger position.
Original Behavior
Frame N: spacecraft at nu=6.22 rad
Trigger: dt_needed = 52.95s (< 60s dt) → fires
Burn executes at nu=6.22 rad ❌ (should be at nu=0.0)
New Behavior
Frame N: spacecraft at nu=6.22 rad
Trigger: dt_needed = 52.95s → fires, sets maneuver->scheduled_dt = 52.95
execute_pending_maneuvers():
- Propagates spacecraft by 52.95s → spacecraft now at nu=0.0 rad
- Executes burn at exact periapsis ✓
- Propagates by (60 - 52.95) = 7.05s for remaining frame time
Test Failures
| Test | Failure | Root Cause |
|---|---|---|
| Prograde burn at periapsis | Maneuver never fires | Config has true_anomaly=0.1, spacecraft moves AWAY from target |
| Two periapsis burns | Radius mismatch | Burn fires 3.5° before periapsis |
| Periapsis burn crossing | Radius off by 1,785m | Burn fires 3.5° before periapsis |
| Burn location = new periapsis | Position mismatch | Test records position BEFORE burn |
Solution Design
Add a scheduled_dt field to Maneuver struct to communicate the exact propagation time needed from trigger check to execution.
Modified Flow
Frame N: spacecraft at nu=6.22 rad
Trigger: dt_needed = 52.95s → fires, sets maneuver->scheduled_dt = 52.95
execute_pending_maneuvers():
- Propagates spacecraft by 52.95s → spacecraft now at nu=0.0 rad
- Executes burn at exact periapsis ✓
- Propagates by (60 - 52.95) = 7.05s for remaining frame time
Files to Modify
1. src/maneuver.h - Add field to Maneuver struct
struct Maneuver {
char name[64];
int craft_index;
BurnDirection direction;
double delta_v;
TriggerType trigger_type;
double trigger_value;
double scheduled_dt; // NEW: Time to propagate before executing burn
bool executed;
double executed_time;
};
2. src/maneuver.cpp - Modify check_maneuver_trigger()
- When immediate trigger (
current_diff < 0.01): setscheduled_dt = 0.0 - When crossing detected with
dt_needed < sim->dt: setscheduled_dt = dt_needed - Return value unchanged
3. src/simulation.cpp - Modify execute_pending_maneuvers()
void execute_pending_maneuvers(SimulationState* sim) {
for (int i = 0; i < sim->maneuver_count; i++) {
Maneuver* maneuver = &sim->maneuvers[i];
if (maneuver->executed) continue;
if (maneuver->craft_index < 0 || maneuver->craft_index >= sim->craft_count) continue;
Spacecraft* craft = &sim->spacecraft[maneuver->craft_index];
if (check_maneuver_trigger(maneuver, craft, sim)) {
CelestialBody* parent = &sim->bodies[craft->parent_index];
// Propagate to exact trigger position
if (maneuver->scheduled_dt > 0.0) {
craft->orbit = propagate_orbital_elements(craft->orbit, maneuver->scheduled_dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
}
execute_maneuver(maneuver, craft, sim, sim->time + maneuver->scheduled_dt);
// Propagate remaining frame time
double remaining_dt = sim->dt - maneuver->scheduled_dt;
if (remaining_dt > 0.0) {
craft->orbit = propagate_orbital_elements(craft->orbit, remaining_dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
}
maneuver->scheduled_dt = 0.0; // Reset for safety
}
}
}
4. src/maneuver.cpp - create_maneuver()
Initialize scheduled_dt = 0.0
5. src/config_loader.cpp
Initialize scheduled_dt = 0.0 when loading maneuvers from TOML.
Design Decisions
Propagation Strategy (Option 3)
All propagation for maneuvering spacecraft happens in execute_pending_maneuvers(). The update_spacecraft_physics() will still run but the velocity deviation check will reconstruct elements if needed. This keeps maneuver logic contained in one place.
Edge Cases Handled
- scheduled_dt > sim->dt: Defensive check added (should never happen per trigger logic)
- Two burns in same frame: Both can fire if both scheduled_dt values fit within dt
- scheduled_dt = 0: No pre-propagation, burn executes at current position (immediate trigger case)
Cleanup
After tests pass, remove DEBUG INFO printf statements from src/maneuver.cpp (lines ~153-212).
Expected Test Results
- Burns execute at exact periapsis (within floating-point precision)
- All 4 failing tests should pass with current 1000m tolerance
- "Prograde burn at periapsis" may need test config adjustment (starts at true_anomaly=0.1)