apsis-rs/docs/design/units.md

120 lines
5.6 KiB
Markdown

# Units and coordinates
English | [简体中文](./units.zh.md)
This file records the unit and coordinate conventions that cross layers. The
conventions inside a single crate are in its module documentation; what
belongs here is the part that must agree **across a layer boundary**, because
a unit that disagrees at a boundary is the easiest mistake to introduce in
this repository and the hardest to find.
## Two units of length
The repository uses both kilometres and metres, with the boundary between the
orbit layer and the physics layer:
| Layer / crate | Unit of length |
| --- | --- |
| `apsis-kepler`, `apsis-sgp4`, `apsis-tle` | kilometres |
| `apsis-ephemeris` | kilometres |
| `apsis-maneuver` | kilometres |
| `apsis-constellation`, `apsis-coverage`, `apsis-access`, `apsis-isl` | kilometres |
| `apsis-topology`, `apsis-routing`, `apsis-mesh` | length is computed only in `apsis-isl`; an edge's `cost` is a dimensionless value the caller defines |
| `apsis-handover` | no length; `quality` is defined by the caller and time is in seconds |
| `apsis-coord` (`Eci`, `Ecef`) | metres |
| `apsis-geodesy` (geodetic height, ellipsoid semi-axes, Cartesian position) | metres |
| `apsis-frames` | dimensionless (angles and rotations) |
| `apsis-rf`, `apsis-antenna`, `apsis-atmosphere`, `apsis-noise`, `apsis-doppler`, `apsis-interference`, `apsis-link` | metres, hertz |
The choice is not arbitrary. Satellite orbits read naturally in kilometres,
which is the magnitude `apsis-sgp4` produces, and a radio link reads
naturally in metres, which is what the ITU-R recommendations use. The cost is
that the boundary needs an explicit conversion.
### Converting at the boundary
Multiply by `1000.0` on the way from the orbit layer into the physics layer,
and divide on the way back:
```rust
// A position in kilometres from the orbit layer becomes metres in physics.
let position_km = satellite.propagate_minutes(0.0)?.position; // kilometres
let ecef = Ecef::new(position_km * 1_000.0); // metres
```
Omitting this step puts the satellite inside the Earth, and the numbers still
look plausible rather than failing at once. The `integrate_network` example
asserts on this boundary: the radius after the conversion must match the
radius the propagator reports, which is the only check that finds a missing
multiply or divide automatically.
## Angles
**Every angle used in a calculation is in radians.** Latitude, longitude,
inclination, right ascension of the ascending node, argument of perigee, true
anomaly, elevation, azimuth and antenna pattern angle are all radians.
The only exception is the two-line element set, whose raw fields are in
degrees and revolutions per day because that is how the file encodes them.
`apsis-sgp4` converts them to radians and radians per minute on
initialisation.
## Time
Time is in seconds throughout, with the origin chosen by the caller:
- The ops and sim layers count seconds from the scenario epoch.
- The orbit layer uses minutes from the element set epoch in `apsis-sgp4`;
`apsis-ephemeris` and the rest use seconds.
- Calendar time: `apsis-time::Epoch` holds a TAI Julian date, and a
conversion to UTC goes through the leap second table in `apsis-leap`.
`Orbit::sample_ephemeris` is the boundary between the two representations: it
takes minutes from the element epoch and the ephemeris it returns is in
seconds, with the conversion done inside the method.
## Coordinate frames
| Frame | Type | Notes |
| --- | --- | --- |
| TEME | `apsis_sgp4::State` | the true equator, mean equinox frame the SGP4 model defines |
| ECI | `apsis_coord::Eci` | inertial Cartesian coordinates |
| ECEF | `apsis_coord::Ecef` | Earth-fixed Cartesian coordinates |
| Geodetic | `apsis_geodesy::Geodetic` | latitude, longitude, height above the ellipsoid |
| Ground point | `apsis_coverage::GroundPoint` | a geodetic position plus an elevation mask |
Going from TEME to ECEF needs the Earth rotation angle
(`apsis-frames::EarthRotationAngle`) together with precession and nutation.
`apsis-coord` provides the transformation and `apsis-frames` provides the
angle. TEME differs from ECI by the equation of the equinoxes, which is below
a thousandth of a degree; the `integrate_network` example treats it as the
inertial frame and says so, because for that example it is an approximation.
## Other quantities
- The gravitational parameter is `apsis-kepler::GravityParameter`, in
cubic kilometres per second squared. WGS 72 goes with SGP4 and WGS 84 with
everything else; choosing the wrong one shifts the osculating semi-major
axis by about one part in a million. The `apsis-orbit::Orbit` facade binds
the parameter to the propagator so that this cannot go wrong.
- Velocity follows the unit of length in its own layer, so km/s or m/s.
- Power is in watts, frequency in hertz and temperature in kelvin. A decibel
is a power ratio; `dBi` is relative to an isotropic radiator and `dBd` to a
half-wave dipole, which is 2.15 dB more directive.
- Every relative quantity is dimensionless: eccentricity, fill rate,
utilisation and a signal to noise ratio in decibels.
## Checks
Nothing in the type system protects a unit boundary, so the tests and this
document carry it:
- Each layer's tests cover the conversions inside that layer.
- `integrate_network` asserts that the kilometre to metre boundary conversion
preserves the radius.
- `integrate_ops` and `integrate_sim` cover the time axis conventions of the
ops and sim layers.
- `cargo run --release -p apsis-rs --features full --example bench` touches
the hot path of every layer, so an interface change in any of them shows up
there as a build failure.