Skip to content

Commit 9da2ab7

Browse files
committed
docs: enhance README and add formation design documentation
1 parent ba10c9f commit 9da2ab7

2 files changed

Lines changed: 159 additions & 58 deletions

File tree

README.md

Lines changed: 97 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# RPO Toolkit
22

3-
RPO Toolkit is a Rust astrodynamics stack for spacecraft rendezvous and proximity operations that combines a browser-deployable analytical engine for real-time mission design with a nyx-space-backed numerical engine for full-physics validation and Monte Carlo analysis.
3+
RPO Toolkit is a paper-traceable implementation of spacecraft rendezvous and proximity-operations mission design in Rust. Every algorithm — quasi-nonsingular ROE, J2 and DMF-drag analytical STMs, e/i-separation passive safety, null-space-projected formation design, Brent-refined closest-approach — cites its source equation (Koenig 2017, D'Amico 2010, Meeus) and is validated against nyx-space full-physics propagation to the meter.
4+
5+
The workspace is split into two engines with a compile-time license boundary: a microsecond, browser-deployable analytical core (MIT/Apache) and a full-physics numerical engine (AGPL, via nyx-space) for Lambert transfers, validation, and Monte Carlo. The same mission designer that plans a formation in a browser tab runs Monte Carlo on a server.
6+
7+
## Who this is for
8+
9+
- **Formation-flying and proximity-ops researchers** — paper-traceable implementations of quasi-nonsingular ROE methods (Koenig 2017, D'Amico 2010) with equation-level provenance and full-physics validation.
10+
- **Rust and frontend engineers building interactive mission-design tools** — microsecond analytical planning in the browser via WASM and full-physics Monte Carlo on the server, both from the same code.
11+
12+
This is a **ground-based mission-design assistant for human analysts** — interactive, advisory, dual-plan — not an autonomous flight-software stack. See _Formation Design_ below for the distinction.
413

514
## Architecture
615

@@ -27,7 +36,7 @@ rpo-nyx (AGPL-3.0) <-- rpo-cli (AGPL-3.0)
2736

2837
```bash
2938
cargo build # build workspace
30-
cargo test # 619 tests across 5 crates (587 + 32 ignored full-physics; 619 total with -- --include-ignored)
39+
cargo test # 619 tests across 5 crates (see Testing below)
3140
```
3241

3342
Run an example mission (CLI):
@@ -46,6 +55,8 @@ wasm-pack build rpo-wasm --target web
4655

4756
See [CLI Reference](docs/CLI.md) for all commands and flags.
4857

58+
**Full-physics prerequisites.** Running `validate`, `mc`, or any test with `--include-ignored` downloads ~50 MB of ANISE kernels (DE440s, PCK) on first use. Analytical-only operations (`mission` without `--auto-drag`, all WASM functions) have no external dependencies.
59+
4960
## Mission Pipeline
5061

5162
```mermaid
@@ -58,7 +69,7 @@ flowchart TD
5869
D -- "lock in" --> E1["Drag estimation\nfrom perch states\n(~3 s, async)"]
5970
E1 --> S["Formation safety\nrequirements\n(optional)"]
6071
E2 --> S
61-
S --> F["Waypoint planning\nformation design . safety . POCA . COLA . free-drift . covariance . eclipse\n(microseconds)"]
72+
S --> F["Waypoint planning\nformation design . safety . POCA . COLA . free-drift . covariance + mahalanobis . eclipse\n(microseconds)"]
6273
F -- "iterate" --> F
6374
F --> G["Validate\nnyx full-physics\n(seconds)"]
6475
G -- "adjust" --> F
@@ -80,6 +91,23 @@ flowchart TD
8091
| Full-physics validation | `validate_mission_nyx()` | nyx-space | seconds |
8192
| Monte Carlo ensemble | `run_monte_carlo()` | nyx-space | minutes |
8293

94+
## Formation Design
95+
96+
What this tool _is_, in one contrast:
97+
98+
```
99+
PRISMA FSW : sensor → classify → compute correction → execute maneuver
100+
(autonomous, closed-loop, onboard)
101+
102+
RPO Toolkit : compute baseline + enriched plans → present both →
103+
analyst decides → replan
104+
(advisory, human-in-the-loop, ground)
105+
```
106+
107+
The toolkit implements the quasi-nonsingular ROE formation-design vocabulary from D'Amico 2010 — e/i vector separation, null-space waypoint enrichment, perch enrichment, transit monitoring, free-drift abort — as an advisory layer with accept/dismiss affordance. Short maneuver legs naturally produce poor intermediate e/i geometry even when 3D keep-out is fully satisfied, so the tool enforces what must not be violated (keep-out distance, checked at every trajectory sample) and evaluates what requires analyst judgment (passive safety, advisory cards with explicit opt-in).
108+
109+
See [docs/formation-design.md](docs/formation-design.md) for primitive-by-primitive detail and the D'Amico equation-to-function mapping.
110+
83111
## Performance
84112

85113
Analytical engine benchmarks (Apple M-series, single core, `cargo bench -p rpo-core`):
@@ -106,20 +134,29 @@ Criterion HTML reports are generated in `target/criterion/`.
106134

107135
## Validated Accuracy
108136

109-
Validated against nyx-space full-physics propagation (US Std Atm 1976, SRP with eclipses, Sun/Moon third-body) for LEO orbits (~400 km, ~52 deg inclination), ~300-400 m-scale formations.
137+
Validated against nyx-space full-physics propagation — J2 harmonics, US Std Atm 1976 drag, SRP with conical eclipses, Sun/Moon third-body perturbations — for LEO orbits (~400 km altitude, ~51.6° inclination, ISS-class) with ~300 m formation separations.
138+
139+
The table below shows **actual observed errors** from running the bundled validation example — reproducible with one command:
110140

111-
| Scenario | Validated Within | Notes |
112-
| ------------------------------- | ---------------- | -------------------------------------- |
113-
| J2 STM, single leg (~1 orbit) | 100 m | Unmodeled perturbations ~60 m total |
114-
| J2 STM, multi-leg (~2-3 orbits) | 200 m | Includes cross-leg maneuver mismatch |
115-
| J2+Drag STM (~1 orbit) | 200 m | DMF fit error + unmodeled SRP/3rd-body |
116-
| Eclipse: Sun direction | 0.01 deg | Meeus Ch. 25 vs ANISE DE440s |
117-
| Eclipse: entry/exit timing | 90 s | Shadow boundary interpolation |
141+
```bash
142+
cargo run -p rpo-cli -- validate --input examples/validate.json # J2 STM
143+
cargo run -p rpo-cli -- validate --input examples/validate.json --auto-drag # J2 + DMF drag
144+
```
118145

119-
Reproduce with:
146+
| Scenario | Max | Mean | RMS |
147+
| --------------------------------------------- | ---------- | ------ | ---- |
148+
| J2 STM, 3 legs, ~4.5 orbits (no drag) | **58 m** | 32 m | 36 m |
149+
| J2 + DMF-drag STM, 3 legs (auto-drag) | 152 m | 68 m | 79 m |
150+
| Eclipse Sun direction (Meeus vs ANISE DE440s) | **0.005°** | 0.005° ||
151+
| Eclipse entry/exit timing | 83 s | 32 s ||
120152

121-
- `cargo run -p rpo-cli -- validate --input examples/validate.json`
122-
- `cargo run -p rpo-cli -- validate --input examples/validate.json --auto-drag`
153+
Velocity error stays under 40 mm/s (no-drag) and 55 mm/s (auto-drag) across the same run. Per-leg growth under drag: position RMS grows roughly 3× from leg 1 to leg 3 (41 m → 92 m → 138 m) as DMF linearization accumulates — a known linear-regime characteristic, not a bug.
154+
155+
**Test-suite gates (conservative pass/fail with ~10× margin over observed).** The regression tests enforce `FULL_PHYSICS_SINGLE_LEG_POS_TOL_KM = 500 m`, `DRAG_STM_VS_NYX_POS_TOL_KM = 1 km`, and `FULL_PHYSICS_MULTI_LEG_POS_TOL_KM = 3 km` (all in `rpo-nyx/src/validation/trajectory.rs`); eclipse gates are `SUN_DIRECTION_VALIDATION_TOL_RAD = 3.5e-4 rad` (≈ 0.02°) and `ECLIPSE_TIMING_VALIDATION_TOL_S = 120 s` (`rpo-core/src/constants.rs`).
156+
157+
**Per-component ROE validation against Koenig Table 4 Case 1.** The J2 STM is independently validated against the per-component error bounds in Koenig et al. (2017), Table 4 Case 1. Each quasi-nonsingular ROE component (`δa`, `δλ`, `δex`, `δey`, `δix`, `δiy`) is bounded within ~10× of the published errors — e.g. `KOENIG_T4C1_DA_BOUND_M = 385 m`, `KOENIG_T4C1_DIX_BOUND_M = 9 m`. See the `koenig_table4_j2_stm_accuracy_case1` test in `rpo-nyx/tests/regression_tests.rs`.
158+
159+
**Outside the validated regime:** GEO, HEO, highly eccentric orbits, and formations outside the ROE-linear regime (`δr/r > 0.5%`) are not currently validated against full physics. See _Status & Roadmap_.
123160

124161
## Library Usage
125162

@@ -129,12 +166,12 @@ For the full pipeline (classify -> Lambert -> waypoints -> covariance -> eclipse
129166

130167
```rust
131168
use rpo_core::prelude::*;
132-
use rpo_core::mission::ProximityConfig;
133169
use rpo_core::elements::{state_to_keplerian, compute_roe};
170+
use rpo_core::mission::ProximityConfig;
134171
use hifitime::Epoch;
135172
use nalgebra::Vector3;
136173

137-
// Define chief and deputy ECI state vectors
174+
// ~300 m formation at ISS altitude
138175
let epoch = Epoch::from_gregorian_utc(2024, 1, 1, 0, 0, 0, 0);
139176
let chief = StateVector {
140177
epoch,
@@ -147,42 +184,23 @@ let deputy = StateVector {
147184
velocity_eci_km_s: Vector3::new(-2.380612, 4.123067, 6.006817),
148185
};
149186

150-
// Classify: proximity or far-field?
151187
let phase = classify_separation(&chief, &deputy, &ProximityConfig::default())?;
152-
153-
// Build a departure state for the waypoint planner
154188
let chief_elements = state_to_keplerian(&chief)?;
155-
let deputy_elements = state_to_keplerian(&deputy)?;
156-
let roe = compute_roe(&chief_elements, &deputy_elements)?;
157-
let departure = DepartureState { roe, chief: chief_elements, epoch };
158-
159-
// Define waypoints in RIC frame (radial, in-track, cross-track)
160-
let waypoints = vec![
161-
Waypoint {
162-
position_ric_km: Vector3::new(0.0, 2.0, 0.0),
163-
velocity_ric_km_s: Some(Vector3::zeros()),
164-
tof_s: Some(4200.0),
165-
},
166-
Waypoint {
167-
position_ric_km: Vector3::new(0.0, 0.5, 0.0),
168-
velocity_ric_km_s: Some(Vector3::zeros()),
169-
tof_s: Some(4200.0),
170-
},
171-
];
172-
173-
// Plan the mission
189+
let departure = DepartureState {
190+
roe: compute_roe(&chief_elements, &state_to_keplerian(&deputy)?)?,
191+
chief: chief_elements,
192+
epoch,
193+
};
194+
let waypoints = vec![Waypoint {
195+
position_ric_km: Vector3::new(0.0, 0.5, 0.0),
196+
velocity_ric_km_s: Some(Vector3::zeros()),
197+
tof_s: Some(4200.0),
198+
}];
174199
let mission = plan_waypoint_mission(
175-
&departure,
176-
&waypoints,
177-
&MissionConfig::default(),
178-
&PropagationModel::J2Stm,
200+
&departure, &waypoints, &MissionConfig::default(), &PropagationModel::J2Stm,
179201
)?;
180-
181-
println!("Total delta-v: {:.6} km/s", mission.total_dv_km_s);
182-
println!("Legs: {}", mission.legs.len());
183-
for (i, leg) in mission.legs.iter().enumerate() {
184-
println!(" Leg {}: dv={:.6} km/s, tof={:.0} s", i, leg.total_dv_km_s, leg.tof_s);
185-
}
202+
println!("Phase: {phase:?} dv: {:.3} m/s legs: {}",
203+
mission.total_dv_km_s * 1000.0, mission.legs.len());
186204
```
187205

188206
### TypeScript (WASM)
@@ -198,22 +216,38 @@ import init, {
198216

199217
await init();
200218

201-
// Classify: proximity or far-field?
219+
// Classifyfar-field or proximity?
202220
const phase = classify_separation(chief, deputy, { roe_threshold: 0.005 });
221+
if (!("proximity" in phase)) {
222+
// Far-field: request a Lambert transfer from rpo-api over WebSocket
223+
// (see docs/API.md), then resume from the perch state.
224+
throw new Error("Far-field: Lambert transfer required");
225+
}
203226

204-
// Plan waypoints (analytical -- runs in the browser, no server needed)
227+
// Plan — a 2-waypoint approach in microseconds
205228
const mission = plan_waypoint_mission(
206229
departure,
207-
[{ position_ric_km: [0, 0.5, 0], velocity_ric_km_s: null, tof_s: 4200 }],
208-
{}, // MissionConfig defaults
230+
[
231+
{ position_ric_km: [0, 0.5, 0], velocity_ric_km_s: null, tof_s: 4200 },
232+
{ position_ric_km: [0, 0.1, 0], velocity_ric_km_s: [0, 0, 0], tof_s: 4200 },
233+
],
234+
{}, // MissionConfig — all fields optional
209235
"j2", // PropagatorChoice
210236
);
211237

212-
// Safety analysis (free-drift, POCA, optional COLA)
213-
const safety = compute_safety_analysis(mission, null, null, "j2");
238+
// Safety — e/i passive safety + keep-out
239+
const safety = compute_safety_analysis(
240+
mission,
241+
{ min_distance_3d_km: 0.05, min_ei_separation_km: 0.2 },
242+
null,
243+
"j2",
244+
);
245+
246+
// Everything above runs in ~1 ms in the browser. See docs/WASM.md for POCA,
247+
// COLA, covariance, eclipse, formation enrichment, and the full 18-function API.
214248
```
215249

216-
All input/output types have full TypeScript definitions.
250+
All input/output types have full TypeScript definitions. See [docs/WASM.md](docs/WASM.md) for the complete API reference.
217251

218252
## Documentation
219253

@@ -245,10 +279,15 @@ cargo clippy --workspace -- -D warnings # lint (pedantic)
245279

246280
Every module traces to specific equations in these papers; see inline doc-comments for mappings.
247281

248-
## Roadmap
282+
## Status & Roadmap
283+
284+
Solo-authored, actively developed, research-grade Rust. Not on `crates.io` — build from source at the workspace root. Validated for LEO ISS-class orbits (~400 km altitude, ~51.6° inclination) with ~300–400 m formation separations; other regimes are on the roadmap below.
285+
286+
**In progress / next:**
249287

250-
1. **R3F frontend** -- React Three Fiber 3D visualization: orbit arcs, RIC-frame relative motion, maneuver arrows, eclipse timeline, covariance ellipses.
251-
2. **Extended orbit regimes** -- GEO/HEO validation, finite burns.
288+
1. **React Three Fiber frontend** — interactive 3D mission designer running in the browser via the WASM analytical engine, WebSocket to `rpo-api` for nyx-dependent operations (Lambert, validation, Monte Carlo). Analytical ops stay sub-frame; numerical ops stream progress.
289+
2. **Drag-aware formation design** — DMF-rate feedback into waypoint null-space enrichment so drift compensation happens upstream of the analyst advisory rather than as a post-hoc warning.
290+
3. **Extended orbit regimes** — GEO and HEO validation; appropriate STM extensions; finite-burn modeling for maneuvers that cannot be treated as impulsive.
252291

253292
## License
254293

docs/formation-design.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Formation Design
2+
3+
This document covers the formation-design vocabulary implemented in `rpo-core`. For the
4+
architectural positioning (advisory vs enforced, ground-based vs flight software), see the
5+
**Formation Design** section of [the README](../README.md#formation-design).
6+
7+
The toolkit implements the quasi-nonsingular ROE formation-design vocabulary from D'Amico
8+
2010 directly:
9+
10+
- **e/i vector separation** (D'Amico Eq. 2.22) — the passive-safety metric. A formation
11+
maintains minimum radial/cross-track separation across phasing as long as the eccentricity
12+
and inclination vectors are properly separated, independent of along-track drift. The
13+
planner computes it; the analyst decides whether to act on it.
14+
- **Null-space-projected waypoint enrichment** (D'Amico Eq. 2.17, 2.23) — for each
15+
user-placed waypoint, the toolkit computes a "safe alternative" ROE that preserves the
16+
chosen RIC position _exactly_ but adjusts the approach velocity along the null space of the
17+
position-to-ROE map. Improves e/i separation without moving the waypoint. Shown as an
18+
advisory card with baseline-vs-enriched comparison.
19+
- **Perch enrichment** (D'Amico Eq. 2.32) — on departure from a far-field approach, the
20+
perch state's e/i vectors can be adjusted to a user-requested minimum R/C separation. The
21+
solver returns **both** a baseline (unenriched) and an enriched plan. Default is baseline;
22+
the analyst explicitly opts in.
23+
- **Transit monitoring** (D'Amico Eqs. 2.28–2.30) — per-leg e/i separation profiles along
24+
each coast arc with mission-wide minimum flagged. Eq. 2.28 is the J2 secular rate of δα,
25+
Eq. 2.29 the integrated form δα(t) that yields the per-leg profile, and Eq. 2.30 is the
26+
relative-perigee drift `dφ/du = (3/2)γ(5cos²i−1)`. Red zones identify when the formation
27+
would temporarily lose passive-abort capability during a guided approach.
28+
- **Free-drift abort analysis** (D'Amico Eq. 2.33, bounded-motion criterion) — per-leg
29+
diagnostic showing what happens if the departure burn doesn't fire. Eq. 2.33 is the
30+
closed-orbit condition `γ·sin(2i)·Δi + (1/7)·Δa/a = 0`; abort analysis evaluates a given
31+
ROE state against it. Runs alongside the nominal plan, not after it.
32+
33+
## Why advisory, not enforced
34+
35+
Short maneuver legs naturally produce poor intermediate e/i geometry even when operational
36+
safety (3D keep-out distance) is fully satisfied. Enforcing e/i as a hard planning constraint
37+
would reject many otherwise operationally safe guided approaches. The tool enforces what must
38+
not be violated (keep-out distance, checked at every trajectory sample) and evaluates what
39+
requires analyst judgment (passive safety, advisory cards with explicit opt-in).
40+
41+
## Primitive → equation mapping
42+
43+
| Primitive | Function | Source |
44+
| --------------------------------- | -------------------------------------------------------------- | ---------------------- |
45+
| e/i vector passive safety | `assess_safety()` | D'Amico Eq. 2.22 |
46+
| Null-space waypoint enrichment | `enrich_waypoint()``accept_waypoint_enrichment()` | D'Amico Eq. 2.17, 2.23 |
47+
| Perch enrichment | `suggest_enrichment_from_parts()``apply_perch_enrichment()` | D'Amico Eq. 2.32 |
48+
| Transit e/i profile | (inside `plan_waypoint_mission()` output) | D'Amico Eqs. 2.28–2.30 |
49+
| Free-drift abort + bounded-motion | `compute_free_drift_analysis()` | D'Amico Eq. 2.33 |
50+
51+
## See also
52+
53+
Collision avoidance (COLA) is a separate module — reactive burn planning via inverse GVE
54+
when POCA crosses a threshold, rather than passive-geometry design. Sources: D'Amico §2.4
55+
(Relative Orbit Control), Eqs. 2.38–2.41, 2.44, 2.50–2.56. Code: `rpo-core/mission/avoidance/`.
56+
The shared infrastructure is the GVE B matrix (`dv``dROE`) at D'Amico Eq. 2.38, which
57+
lives in `rpo-core/elements/gve.rs` and is used by both formation targeting and avoidance.
58+
59+
## References
60+
61+
- D'Amico, _Autonomous Formation Flying in Low Earth Orbit_, PhD thesis, TU Delft 2010.
62+
[PDF](references/Damico_PhD.pdf).

0 commit comments

Comments
 (0)