Octant

Validation

A tool that will not show its working should not be trusted with yours. Octant's propagation is checked against NASA GMAT using real satellites' real TLEs, and the numbers are published whether they flatter or not.

Last run 10 August 2026 · reproducible with the scripts linked below.

The chain

Octant runs Orekit compiled to JavaScript. Trust in a number therefore needs two links, not one — and they are checked separately:

LinkQuestionResult
Browser ≡ native Does compiling Orekit to JavaScript change any answer? Identical to every digit printed
Orekit ≈ GMAT Does Orekit agree with an independent, NASA-built tool? ≤ 7.3 m over 24 h

The first link matters because it is the unusual thing Octant does. IEEE-754 arithmetic is identical on a JVM and in a browser engine, and the measurements say so: the same case run natively and in the browser returns the same position to every digit reported, for analytical and numerical propagation alike.

Against GMAT, on real satellites

GMAT is NASA's General Mission Analysis Tool — open source, used for real mission design, and entirely independent of Orekit. Both were given the same real TLE, fetched from Celestrak, and asked to propagate 24 hours with SGP4.

SatelliteRegimeModelMeanMaxSpeedImplied Δt
ISS (ZARYA)420 km, 51.6°SGP46.60 m7.26 m7.66 km/s0.86 ms
Landsat 8705 km SSOSGP46.43 m7.08 m7.50 km/s0.86 ms
IUS R/B (1)GTO, e = 0.712DeepSDP43.12 m9.21 m3.56 km/s0.90 ms
TDRS 3GEODeepSDP42.85 m3.10 m3.07 km/s0.93 ms

1,442 samples each, one per minute across a full day. Four orbits spanning low Earth orbit, a geostationary transfer orbit and GEO — and both the near-Earth (SGP4) and deep-space (SDP4) branches of the model. Seven metres on a 6,800 km orbit is about one part in a million.

Why SGP4 for the comparison

Deliberately. A TLE plus the SGP4 model determine the answer completely: there is no force model, integrator tolerance or gravity field for two tools to disagree about legitimately. Any difference that remains is implementation — which is the only thing worth measuring in a cross-check. Comparing numerical propagators instead would mostly measure how similarly the two were configured.

What the residual is

Not a propagation disagreement. It is a sub-millisecond time-tag offset, and the four cases above are what establish it.

The difference does not grow over the day, which already rules out genuine divergence. What it does instead is scale with orbital speed: divide each position difference by the satellite's velocity and the result is the same across all four orbits — 0.86, 0.86, 0.90 and 0.93 milliseconds — even though those orbits differ in speed by a factor of 2.5, in eccentricity from 0.0004 to 0.712, and run through two different branches of the model.

A propagation difference would not behave that way. A constant time offset would, and does: the two tools place the satellite in the same place at times that differ by about 0.9 ms, most likely a convention in converting the TLE epoch or in leaving the TEME frame. 0.9 ms of clock is 7 m in low Earth orbit and 3 m at GEO, which is precisely the pattern measured.

This has not been chased to its source, and it is stated rather than rounded away. But it is now an explained residual with a testable signature, not an unexplained one.

The numerical propagator, on the same gravity field

The comparison above is silent about spherical-harmonic gravity, by construction — SGP4 has none. So here is the other half: a full numerical propagation, run in both tools, on the identical gravity field.

That last part is the whole difficulty. Orekit ships eigen-6s and GMAT ships JGM-2, so propagating in each and comparing would mostly measure the difference between two geodesy products — a fact about the world, not about either implementation, and the easy number to mistake for a validation. GMAT's own coefficient file is therefore converted into the format Orekit reads, and both tools integrate the same 2,553 coefficients with the same GM and the same reference radius.

CaseOrbitMedianMeanMaxFirst hour → last
LEO700 km, near-circular0.10 m0.83 m4.83 m0.62 → 0.77 m
GTO200 × 20,000 km0.008 m0.09 m6.53 m0.42 → 0.51 m

JGM-2 truncated to 20×20, gravity only, 24 hours, sampled every 60 s. GMAT: RungeKutta89 at 1e-12 accuracy. Orekit: Dormand-Prince 853 at 1 mm position tolerance. The initial state is taken from GMAT's own first report row, so element conversion is not in the comparison. 2,299 and 1,485 samples.

What is deliberately left out

Drag, solar radiation pressure, third bodies and tides. Each depends on a model the two tools do not share — an atmosphere, a flux history, a spacecraft area — so including them would measure how similarly two people configured two programs, which is the criticism a cross-check has to be immune to. Gravity alone is the part where "the same inputs" can actually be guaranteed.

What the residual is, and is not

It does not grow. Mean disagreement over the first hour and the last hour of the day differ by about 0.1 m in both cases, and the medians — 10 cm and 8 mm — sit far below the maxima. A force-model disagreement compounds; this does not, which places it with frame realisation and report rounding rather than with the physics.

The maxima land at perigee in the GTO case, where the spacecraft is fastest and any sub-millisecond difference in time-tagging buys the most metres — the same signature the SGP4 comparison above identifies, arriving by the same route.

What remains legitimately different is the Earth-fixed frame the harmonics are evaluated in: Orekit uses ITRF through IERS 2010 conventions with earth-orientation data applied, GMAT its own realisation. That is not a bug in either tool, and it is why this section reports a number rather than asserting a pass.

Run it: benchmark/scripts/validate-forcemodel.sh, after GmatConsole.exe cases/leo_numerical.script. The field conversion is benchmark/scripts/cof-to-gfc.py, and it prints a coefficient count against the number a full field of that degree must contain, because a silently truncated gravity field would look like a small disagreement rather than like a broken input.

What this does not establish

The analyses, and what each one is checked against

The orbit is the part GMAT can arbitrate. Everything built on top of it — link budgets, data budgets, coverage, manoeuvre costs — is checked instead against closed forms, published figures, and invariants that a wrong implementation cannot satisfy. Those are weaker than an independent tool and stronger than nothing, and the difference is worth being explicit about.

Run automatically, against the shipped bundle

Seventeen suites in benchmark/scripts/, run by check-all.sh against the compiled Orekit build rather than the Java source — TeaVM is a translation step that can drop things, and the compiled file is what ships.

SuiteWhat it asserts
DOM contractevery element id the code reaches for exists in the page
Time axisindex → time → index round-trips, times increase strictly across phase and burn seams, and no consumer assumes an even sample grid — Apollo's steps run 29.4 s to 1563.4 s apart, so an even grid is wrong by up to 40.9 h
Central-body changea 100 km lunar orbit expressed about the Earth stays at lunar-orbit radius from the Moon at every sample while its Earth distance sweeps 400 000 km
Surface pointsa site on the Moon drawn in Earth's frame holds one lunar radius from the Moon across a full month — worst error 0.6 km on 1737.4 km; the local vertical is the geodetic normal, 0.192° off radial at 45° latitude
Apollothe four-phase chain reaches lunar orbit: 54 km periapsis, still in orbit after 3.24 days
LEO→GEO4258 m/s total against a published ~4260, with the residual 0.82° of inclination left visible rather than tuned away
Propagator choiceeach theory is used where it is valid and refuses where it is not, and a refusal is reported rather than silently substituted
The flown flyby hyperbolaefour encounter scenarios hand the entry state to the engine and propagate the hyperbola, rather than replaying a table. Each must come out hyperbolic (e = 1.33 to 5.01 — an elliptical one would be a capture drawing a plausible curve), must reach the closest approach Horizons measured (0.00–0.12%), and must reach it at the measured time, which a hyperbola of the wrong phase would not. Against Horizons across the whole window the two-body arc holds to 80 km at Uranus and 12 466 at Jupiter, worst at the edges where the Sun's pull dominates
The science encountersimported from JPL Horizons — Voyager 2's own trajectory and each moon's, differenced — because the moons are not in DE440 and the tour does not model the flyby hyperbolae. It is what judges the reconstruction: predicted flyby distances of 9.67, 2.60 and 4.20 planet radii against Horizons' 10.09, 2.67 and 4.19, with nothing fitted to them. Every closest approach must also fall inside its search window, after a 36-hour window reported Callisto at 676 000 km when the real encounter was 215 028 km eight hours earlier
Voyager 2's Grand Tourreconstructed from five encounter dates and DE440, then checked against the mission rather than against itself: the launch energy comes out at C3 = 104.5 km²/s² against the ~103 a Titan IIIE-Centaur delivered, and the flyby distances the physics requires are 9.67, 2.60 and 4.20 planet radii against Voyager 2's ~10, ~2.7 and ~4.2. The v-infinity mismatches at each encounter must stay inside a deterministic-manoeuvre budget (112, 136 and 14 m/s on 8–15 km/s), and the launch orbit alone must fall short of Neptune — 6.4 AU against 30
The Grand Tour as one chainthe legs and the flybys are joined at the spheres of influence and flown as eight phases, so the test is whether the arc reaches the planets at all: 0.72, 0.16, 0.11 and 0.03 Gm at the sampled minimum, for 369 m/s of departure and 228 m/s of approach corrections across 12.2 years. The builder refuses to write a chain that misses — it once reported success while sailing 92 Gm wide of Saturn, because “the worker flew it” meant only that nothing threw. Two of the four faults behind that were in the measurement rather than the mission: burns expressed in the frame of the phase they left instead of the one they arrive in, and sample times assumed uniform when the worker samples per phase
Voyager 2 against JPL Horizonsthe reconstruction held against the trajectory actually flown, 886 heliocentric samples every 5 days across the twelve years. Median separation 0.04 Gm, worst 0.33 — 0.00% and 0.07% of the distance from the Sun — best-fit time shift 0 days. The four encounter states are baked from Horizons, so the arcs meet at the planets by construction; what is unpinned is the cruise, and mid-leg the error is 88, 160, 11 and 130 Mm, against 850, 796, 808 and 273 when every leg was two-body. The legs are integrated with the four giants pulling, in a frame whose origin is the central body, and aimed as they are flown — a conic aimed at Jupiter and then integrated lands 30 Gm away by Saturn. The last factor of four came from neither: the sampling pass carried the state from a phase's start to its first sample under the WRONG theory, three days of two-body just outside a sphere of influence, worth 16 m/s and 890 Mm by the end of the leg — the drawn arc and the flown arc differing, which is now 0 Mm
Gravity assista flyby cannot change the spacecraft's speed relative to the planet, only rotate it — measured on a real Earth‑to‑Venus leg as 4.862 km/s in and 4.862 km/s out, a difference of zero, while the heliocentric speed gains 1.756 km/s and the aphelion moves 1.015 → 1.263 AU. The deflection is checked against sin(δ/2) = 1/e, that flying closer turns further, and that the gain stays inside twice the planet's orbital speed
Satellite catalogueevery baked element set is propagated through the engine, its checksums verified, and its period cross-checked against its own semi-major axis by Kepler's third law. Each entry declares a regime as a field, and the orbit must match that regime's altitude AND inclination band — because one entry turned out to be a different satellite from the one requested, and another was matched into the wrong band by a word in its description
Spot checksthe closed-form and invariant comparisons below, re-run on every build rather than measured once: free-space path loss and dish gain against the textbook formulae and against their own doubling invariants (exactly 6.02 dB either way), the bandwidth limit that a power-only budget once ignored, the Doppler sign, the Apollo CSM and ISS masses derived from their parts lists, the CSM tank through the rocket equation, and vis-viva
The flown Earth‑to‑Mars missionthe shipped five-phase chain is flown from the elements and burn in the file: it must start in Earth orbit, change central body to the Sun and then to Mars, deliver the spacecraft to within a sphere of influence of Mars, and pass above the surface at about the 500 km its aim was solved for — 509 km measured. The note's claim that an untargeted burn would miss by millions of kilometres is checked too, since that is the whole argument for targeting
Lambert, the Mars window & the shipped transferthe transfer solver reproduces a known orbit's own velocities to 0.0000 m/s at both ends, and the textbook Hohmann between 1.000 and 1.524 AU to within 0.4 m/s (Δv 2.946 and 2.650 km/s against a published 2.945 and 2.649). Flying the solved departure state arrives at Mars with a 0 km miss, and a scan over departure dates finds the real 2026 window — depart 2026-11-17, 270 days, v-infinity 3.44 km/s — which nothing in the tool was told. The two ends of the mission are checked against published figures as well: trans‑Mars injection from a 200 km parking orbit at 3700 m/s against ~3.6 km/s, and Mars capture into a 500 × 20 000 km ellipse at 1167 m/s against ~1 km/s — with the invariants that make the plausible mistakes fail: the burn must cost more than v‑infinity alone and less than escaping first, and capture at Earth must differ from capture at Mars. The shipped Earth‑to‑Mars scenario is then re-solved from its own epoch and duration: the six elements in the file must BE that solution (worst relative gap 4.7×10−7), its note must quote the departure v-infinity the transfer really has, and flying it must arrive at Mars
Heliocentricthe Sun as a central body, against figures from outside the tool: a circular orbit at 1 AU takes 365.257 days against the 365.256-day sidereal year, Earth's eccentricity sweeps 0.9833–1.0167 AU, and one year later the orbit closes to 1401 km — 0.001% of 1 AU. The mean-element theories are refused with a reason, since a point mass has no oblateness for them to model, and Earth's harmonic field survives the switch
Disposal manoeuvresthe deorbit and re-orbit ΔVs the compliance card quotes are flown through the shipped worker, not compared against a second formula: 99.3 m/s puts a 400 km circular orbit's perigee at 60.0 km exactly, and the IADC re-orbit raises apogee by its full 248 km clearance. At inclination J2 must move the achieved perigee down and never up — 14.3 km low at 28.5°, and the card's quoted allowance must cover it
Finite burnspropellant matches the rocket equation to 4.7e-13 kg; gravity loss falls as thrust rises (82.13 m/s lost of 100 at 40 N, 0.02 at 40 kN); and finite-burn reporting never describes an impulse it did not fly

Closed-form and invariant spot checks

Measured against textbook formulae or against a quantity the same run computes another way. Six of these are now re-run on every build by the spot-check suite above — the two radio figures, both derived masses, the CSM tank and vis-viva. Two files had to be split out of the application before that was possible, because the arithmetic lived inside code that needs a browser to load.

Four are still measured-on-a-date and are marked below. The exported velocity, the data latency and the coverage figures come from orchestration — which spacecraft, which pass, which window — rather than from a formula, and reaching them from a headless check needs a harness that does not exist yet. Saying which is which matters more than the count.

QuantityOctantReference
Free-space path loss, 2.2 GHz at 1000 km159.30 dB159.3 dB, textbook
3 m dish gain at 2.2 GHz34.58 dBi~34.4 dBi at 60% efficiency
Orbital speed, 620 km circular7551.9 m/s7543.2 m/s by vis-viva; the 0.12% is J2, which vis-viva omits
Exported velocity vs. its own trajectory (not re-run)0.0015 m/sa 1 s central difference of the exported positions
Radial velocity at t=0, argument of perigee 90°exactly 00 by definition at perigee
Apollo CSM full-tank ΔV2878 m/s~2800 m/s, published SPS capability
Apollo CSM wet mass, from its parts list30 301.5 kg~30 300 kg
ISS mass, from its parts list419 725.0 kg419 725 kg, published
Data latency when the link is not the constraint (not re-run)1 h 36 m 45 sequals the station's longest gap exactly — the two are computed independently
Coverage with the Sun merely above the horizon (not re-run)15.3%29.1% on geometry alone: the terminator halves it

What the analyses do not establish

Reproduce it

Everything here is a script in the repository. Nothing is hand-copied into this page from a run that cannot be repeated.

benchmark/scripts/validate-sgp4.sh          # fetch TLEs, run Orekit, diff against GMAT
GMAT-R2026a/bin/GmatConsole.exe cases/iss_sgp4.script
benchmark/scripts/run-native.sh             # native Orekit timing baseline
benchmark/scripts/run-teavm.sh OctantApi    # the browser build

Raw output lives in benchmark/results/. The GMAT scripts, the TLEs used and the comparison harness are in benchmark/cases/ and benchmark/src/.

Eclipse and ground-station access, against GMAT

Orbits were cross-checked against GMAT from the start; eclipse and visibility were not. That mattered more than it looked: a power budget begins with an eclipse fraction, so an unvalidated eclipse makes every number downstream of it a number with nothing underneath.

GMAT's EclipseLocator and ContactLocator were run over one day of the same orbit, from the same epoch, with the same station. The 10° elevation mask is expressed on our side as the half-cone that is a 10° mask at that altitude — from Wertz, sin ρ = R/(R+h) and cos ε = sin η / sin ρ — so neither tool is answering an easier question than the other.

Loading the measured numbers…

Every number in this section is read at page load from data/validation-events.json — the same file the golden tests assert against. A page whose numbers are typed separately from the numbers the tests enforce is a page that goes quietly out of date.

Reproduce it:

GMAT-R2026a/bin/GmatConsole.exe -r benchmark/cases/eclipse_access.script

Raw GMAT reports are committed at benchmark/results/gmat_eclipse.txt and gmat_contact.txt.

Orbital lifetime — what it is, and what it is not

Lifetime is estimated by integrating the orbit-averaged decay rate, King-Hele's first-order result for a near-circular orbit:

da/dt = −(Cd·A/m) · ρ(a) · √(µ·a)

The density ρ is Orekit's — Harris-Priester, the same atmosphere its numerical propagator uses — sampled around each revolution and averaged, because the day–night bulge changes it by a factor of two.

It is not a numerical propagation with drag. Octant has one, and it is the wrong tool here: a numerical run costs roughly 170× an analytical one, and a lifetime is measured in years. Integrating a decade that way would take longer than the mission.

Computed, for a 3U CubeSat

Cd = 2.2, area 0.03 m², mass 4 kg — a ballistic coefficient of 0.0165 m²/kg, circular, 51.6° inclination.

Note the vehicle these came from. Those are bare figures, typed. The 3U CubeSat in Octant’s own vehicle library derives 0.0204 m²/kg — it has four deployed panels and a camera, so it is both heavier and draggier, and it would decay sooner than the table says. Neither number is wrong; they describe different spacecraft. Deriving the coefficient from parts rather than typing it is what makes that difference visible instead of silent.

AltitudeOctantTypically quoted, mean solar activity
300 km1.1 months2–3 months
350 km3.2 months6–9 months
400 km7.3 months1–2 years

That comparison was wrong, and GMAT settled it. This page used to say Octant’s figures were “short, consistently and by roughly a factor of two” against the published column above. Given the same spacecraft — Cd·A/m = 0.0165 m²/kg — an independent tool reproduces our numbers instead:

Loading the measured numbers…

Lifetime cannot be a like-for-like check the way SGP4 was: GMAT does not implement Harris-Priester at all. So the question is not whether GMAT agrees to a digit but whether we sit inside the spread two respectable atmospheres produce — and we do, at 300 km and at 400 km, and within 7% at 350 km. At 400 km GMAT’s two atmospheres differ from each other by 41%, more than either differs from us.

A published lifetime table is only meaningful with its ballistic coefficient and its solar activity attached; the column above carried neither. The self-criticism was honest and it was wrong, which is a decent argument for checking against a tool rather than against a remembered range.

The uncertainty that dominates everything above — now measured

The solar cycle. This page used to assert that it dominated. It does, and here is by how much. Harris-Priester has no solar-activity input at all — one fixed table — so the same decay was run over Orekit’s NRLMSISE00, which does, at three points of the cycle.

Loading…

Two things fall out. The spread grows with altitude — a factor of 4 at 300 km, 10 at 400 km. And Harris-Priester turns out to track the mid-cycle case to within 5% at every altitude, so calling it “a fixed level on the high side” was wrong in the same way the factor-of-two claim was. It is essentially the mean.

NRLMSISE00 needs no space-weather file here, which is why this was affordable at all: Orekit drives it through a five-method interface, and that interface can be implemented with constants. The activity becomes an explicit input the caller chooses rather than a data file to bake and keep current. Constants rather than a predicted flux series on purpose — a prediction would give one confident answer for a launch date five years out, which is exactly the false precision worth avoiding.

What the averaging costs — the one thing GMAT could not tell us

GMAT averages the same kind of thing we do, so both tools could share an approximation error and agree beautifully. Isolating it needs the same spacecraft, the same epoch and the same atmosphere integrated two ways: Orekit’s numerical propagator with a real drag force and no averaging anywhere, against the King-Hele orbit-averaged loop Octant ships.

Loading…

Orbit-averaging over-predicts lifetime by 3.5% at 400 km, rising to 11% at 300 km. The sign is consistent and the trend is the right way round: the approximation assumes the orbit changes little over one revolution, and that weakens exactly where the decay per revolution grows. Over-predicting is also the safe direction for a disposal argument — it makes a 25-year claim harder to satisfy, not easier.

The numerical side is stepped one day at a time, so it is quantised to a whole day — at 300 km that is 4% of the answer and a real part of the 11%. Reproduce with benchmark/scripts/validate-decay.sh.

So which uncertainty actually matters

Loading…

They are not the same size, and that is the practical conclusion of this whole section. The tool now shows a range rather than a number — not out of caution, but because the headline uncertainty is two orders of magnitude larger than the modelling ones, and a single figure to three digits would be a statement about arithmetic rather than about the spacecraft.

What is checked, and what is not

Checked: against GMAT at three altitudes with two independent atmospheres — reproducible with GmatConsole.exe -r benchmark/cases/lifetime.script, raw output committed at benchmark/results/gmat_lifetime.txt. The scaling also behaves as it should, about ×2.5 per 50 km, which is the expected exponential.

Not checked: against a numerical propagation with drag over the full decay. The orbit-averaging approximation itself has not been isolated from the atmosphere it is averaging, and agreement with GMAT does not do that — both tools are being asked to average the same kind of thing.

Scope

Earth only — the Moon has no atmosphere and Mars is not implemented. Near-circular orbits only (e < 0.05): King-Hele's eccentric case is a different formula, and applying the circular one to a transfer orbit would produce a confident wrong answer rather than no answer. TLE objects are refused, because SGP4 elements carry their own B* drag term which this estimate would contradict rather than use.