Go to file
ApsisRS contributors a3028b2029 fix: reject an unordered sample sequence in the access search
The search binary searches the sample list to interpolate between the two
samples that straddle a crossing, and a binary search over an unordered
list returns a wrong index instead of failing. Only the first and last
times were checked, so a sequence whose ends were in order but whose
middle was not refined each crossing against the wrong pair of positions
and reported a pass that never happened. On a circular ground track,
shuffling two samples changed the result from three passes to two and
still returned Ok.

The whole sequence is now checked, with a new UnorderedSamples error kind
that says which pair is out of order. The test covers the middle-of-
sequence case that the end check missed.

Two comments also described something other than what the code does, and
two Option-returning accessors did not say what makes them None:

- GravityModel::x2o3 is the constant 2/3, used as an exponent in the
  mean motion and drag corrections, not 2 * xke^2 as its comment claimed;
  the sgp4 reference implementation uses the same constant the same way.
- WalkerPattern::plane_spacing and phase_offset returned None without
  saying so, which is the case a caller has to handle.

Both READMEs claimed twelve expect sites where there are thirteen, because
apsis-math/src/parallel.rs added one and the count was not carried over.
2026-10-02 00:03:22 +08:00
.github/workflows bench: add a parallel scale benchmark 2026-09-30 17:53:48 +08:00
crates fix: reject an unordered sample sequence in the access search 2026-10-02 00:03:22 +08:00
docs/design docs: give every note an English and a Chinese version 2026-09-30 19:23:26 +08:00
scripts workspace: enforce the layer dependency rule 2026-09-26 23:33:20 +08:00
validation docs: give every note an English and a Chinese version 2026-09-30 19:23:26 +08:00
.gitignore workspace: add geodesy and time cross-check scripts 2026-09-26 13:47:59 +08:00
Cargo.lock access: search a constellation's tracks across several threads 2026-09-30 18:37:02 +08:00
Cargo.toml orbit: add Keplerian elements and two-body propagation 2026-09-26 14:20:09 +08:00
LICENSE-APACHE workspace: initialize workspace with all layer crates 2026-09-26 12:53:13 +08:00
LICENSE-MIT workspace: initialize workspace with all layer crates 2026-09-26 12:53:13 +08:00
README.md fix: reject an unordered sample sequence in the access search 2026-10-02 00:03:22 +08:00
README.zh.md fix: reject an unordered sample sequence in the access search 2026-10-02 00:03:22 +08:00
rust-toolchain.toml workspace: initialize workspace with all layer crates 2026-09-26 12:53:13 +08:00

README.md

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 is apsis
  • Every crate is publish = false at 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 network may use orbit, but orbit may not use network. 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-core in foundation is the global baseline that any crate in any layer may use. apsis-math is 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.

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, expect or panic. A failure on external input is always a Result or an Option. An expect is 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 in docs/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 from src/. They are integration tests and reach the crate only through its public API; no inline #[cfg(test)] module is used
  • Documentation follows the X.md and X.zh.md convention, with English in X.md and Simplified Chinese in X.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:

Licence

MIT OR Apache-2.0, see LICENSE-MIT and LICENSE-APACHE.