8.0 KiB
ApsisRS
Computational kernels for commercial spaceflight and satellite internet, in Rust.
English | 简体中文
Scope
- Pure Rust, standard library only, no third-party crate dependency
- Clear domain boundaries with a one-way dependency order between layers
- The public facade crate is
apsis-rs; its library name isapsis - Every crate is
publish = falseat this stage, so none of them is released
Layers
foundation -> physics -> orbit -> rf -> network -> ops -> sim -> apsis-rs
The rules:
- Dependencies flow to the left only. A lower layer may use any layer to its
left; a higher layer may not use any layer to its right. So
networkmay useorbit, butorbitmay not usenetwork. A leftward dependency may cross as many layers as it needs, because the layers in between need not offer a type that carries the value forward. apsis-coreinfoundationis the global baseline that any crate in any layer may use.apsis-mathis the same, because linear algebra is shared across the layers.- Within a layer, that layer's facade crate (
apsis-orbit,apsis-rf,apsis-sim) is the integration point.
scripts/check-layers.sh enforces these rules and CI runs it.
| Layer | Responsibility | Crates |
|---|---|---|
| foundation | Base types, units, mathematics, macros | apsis-core, apsis-units, apsis-math, apsis-macros |
| physics | Time, leap seconds, coordinates, datum | apsis-time, apsis-leap, apsis-coord, apsis-geodesy, apsis-frames |
| orbit | TLE, SGP4, two-body, ephemeris, maneuvers | apsis-tle, apsis-sgp4, apsis-kepler, apsis-ephemeris, apsis-maneuver, apsis-orbit |
| rf | Radio frequency, antennas, link budget | apsis-rf, apsis-antenna, apsis-doppler, apsis-atmosphere, apsis-noise, apsis-interference, apsis-link |
| network | Constellations, coverage, access, topology, routing | apsis-constellation, apsis-coverage, apsis-access, apsis-topology, apsis-isl, apsis-routing, apsis-handover, apsis-mesh |
| ops | Resources, tasks, scheduling, conflicts, schedules | apsis-resource, apsis-task, apsis-scheduler, apsis-conflict, apsis-schedule |
| sim | Simulation engine, scenarios, events, output | apsis-sim-engine, apsis-scenario, apsis-event, apsis-output, apsis-sim |
| facade | Public facade | apsis-rs |
Building
Run every Rust command from the repository root:
cargo check --workspace
cargo test -p apsis-core -p apsis-units -p apsis-math
The apsis-rs facade selects the layers it needs by feature:
[dependencies]
apsis-rs = { path = "...", features = ["orbit"] }
The features are foundation, physics, orbit, rf, network, ops,
sim and full. A layer feature enables the layers below it. full enables
everything including sim; ops is every layer except sim, for a project
that does not run simulations.
Performance
The three benchmarks are examples of the facade. They run in release mode and depend on nothing outside the workspace, so a build is the compiler and nothing else. The figures below are one run on an AMD Ryzen 7 8845HS (eight cores, sixteen threads); absolute times move with the machine, so compare the ratios within a table. The method, every size in the sweeps and the reasoning behind each conclusion are in Benchmark method and results.
One call on the hot paths
| Path | Per call |
|---|---|
| Hermite ephemeris query | 24 ns |
| TEME to Earth-fixed rotation | 27 ns |
| Keplerian elements to a state | 38 ns |
| Earth-fixed to geodetic | 50 ns |
| Link budget C/N0 | 61 ns |
| SGP4 propagation, thirty minutes from epoch | 249 ns |
| Access search, 120 samples | 7.5 us |
| Planning 60 tasks on one resource | 239 us |
An ephemeris query is an order of magnitude cheaper than the propagation it stands in for, which is why a densely queried track is tabulated once and then interpolated.
Growth with size. A flat cost per unit is what shows the complexity is right:
- A day of a constellation at a sixty second step is linear in the satellite count: 24 satellites in 8.7 ms, 2016 in 0.68 s, about 234 ns a sample, an exponent of 0.00.
- Access search is flat at about 7.3 us a track from 8 to 128 tracks.
- Topology construction is about O(n squared) and greedy planning eases from O(n squared) towards O(n); both are limited by their algorithm, and the design note says why.
Threads. The numerical kernels split by satellite. Propagating 2000 satellites over a day takes 671 ms on one thread and 85 ms on sixteen, a speedup of 7.9x; access search over 256 tracks reaches 5.3x. Efficiency is about eighty-five percent at eight threads, one per core; sixteen puts two on a core and returns about half of that. Every parallel result equals the serial one, so threading buys throughput and never changes a number.
Conventions
- Toolchain
stable, edition 2024, rust-version 1.85 - No third-party crate by default, including dev-dependencies and build scripts
- Library code uses no
unwrap,expectorpanic. A failure on external input is always aResultor anOption. Anexpectis allowed on an internal invariant that a check just above already guards, such as the element just pushed onto a vector, or a value whose absence the line above ruled out. There are thirteen such sites and each is listed with its guard indocs/design/errors.md. - Every public item carries a documentation comment, and the comment is self-contained
- Tests live in each crate's
tests/directory, separate fromsrc/. They are integration tests and reach the crate only through its public API; no inline#[cfg(test)]module is used - Documentation follows the
X.mdandX.zh.mdconvention, with English inX.mdand Simplified Chinese inX.zh.md
Layout
apsis-rs/
├── Cargo.toml
├── crates/ # Rust workspace members
│ └── apsis-rs/
│ ├── examples/ # validation dumps and cross-layer checks
│ └── ...
├── scripts/ # repository check scripts
├── validation/ # Python cross-checks
└── docs/design/ # design notes
Tests live in each crate's tests/ directory. The cross-layer integration
checks and the dependency-free benchmarks are examples of the facade:
# Cross-layer integration checks, which CI runs
cargo run -p apsis-rs --features network --example integrate_network
cargo run -p apsis-rs --features ops --example integrate_ops
cargo run -p apsis-rs --features sim --example integrate_sim
# Hot path benchmark, run in release
cargo run --release -p apsis-rs --features full --example bench
# Scale sweep: the input grows and the cost per unit of work shows the trend
cargo run --release -p apsis-rs --features full --example bench_scale
# Parallel sweep: the same work over 1, 2, 4, 8 and 16 threads
cargo run --release -p apsis-rs --features full --example bench_parallel
Documentation
The design notes record the cross-crate decisions that a reader of a single crate cannot infer:
- Units and coordinates
- Errors and tolerances
- Layer boundaries
- Parallelism
- Benchmark method and results
- Glossary and formula conventions
- The simulation layer
The generated API documentation renders mathematical formulas offline. A copy
of MathJax is vendored under docs/vendor/mathjax, docs/mathjax.html loads
it, and crates/apsis-rs/build.rs copies it into the documentation root, so
the generated pages need no network access. Build them with
bash scripts/build-docs.sh --workspace --all-features --no-deps; a plain
cargo doc also works, and the script only makes the copy reliable. A display
formula is written as $$ ... $$ inside a <div>; the surrounding div keeps
the markdown layer from rewriting the LaTeX.
Licence
GPL-3.0-or-later, see LICENSE.
The vendored MathJax under docs/vendor/mathjax is Apache-2.0; see the
LICENSE in that directory.