Current section
Files
Jump to
Current section
Files
README.md
# sidereon
[](https://hex.pm/packages/sidereon)
[](https://hexdocs.pm/sidereon)
[](https://livebook.dev/run?url=https://github.com/neilberkman/sidereon-ex/blob/main/sidereon.livemd)
GNSS and astrodynamics for Elixir: propagate satellites, predict passes, solve
precise positions (SPP / RTK / PPP / DGNSS), screen for conjunctions, and
convert between coordinate frames and time scales.
This is the Elixir interface to **sidereon**, a GNSS and astrodynamics engine
written in Rust. The numerics run in that engine and ship to you as a
[Rustler](https://github.com/rusterlium/rustler) **precompiled NIF**: adding the
dependency downloads a prebuilt binary for your platform, so there is no Rust
toolchain to install and nothing to compile. You write ordinary Elixir, with
plain `DateTime` and map structures in and typed structs out.
The engine is reference-validated. The SGP4 propagator is a port of David
Vallado's reference implementation, bit-exact to it; frames and time are checked
against Skyfield and IERS; the positioning stack is checked against IGS products.
## Install
Add `:sidereon` to your dependencies in `mix.exs`:
```elixir
def deps do
[{:sidereon, "~> 0.31"}]
end
```
Releases ship precompiled NIFs for common Linux, macOS, and Windows targets and
download automatically, so no Rust build is needed. To force a source build,
install a Rust toolchain, set `SIDEREON_BUILD=1`, and activate Sidereon's
optional Rustler dependency in the consuming application:
```elixir
def deps do
[
{:sidereon, "~> 0.31"},
{:rustler, ">= 0.0.0", optional: true}
]
end
```
## Example: track a satellite
Parse a two-line element set, run SGP4, and take a look angle from a ground
station. No data files and no setup: give it the elements and a station, and it
returns azimuth, elevation, and slant range.
```elixir
line1 = "1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9009"
line2 = "2 25544 51.6400 208.8657 0002644 250.3037 109.7782 15.49560812999990"
station = %{latitude: 51.5, longitude: -0.1, altitude_m: 10.0}
with {:ok, tle} <- Sidereon.parse_tle(line1, line2),
{:ok, look} <- Sidereon.look_angle(tle, ~U[2024-01-01 12:00:00Z], station) do
look.azimuth # degrees
look.elevation # degrees
look.range_km # slant range
end
```
The same parsed elements feed `Sidereon.propagate/2` (TEME position and
velocity), `Sidereon.geodetic/2` (the sub-satellite point), and
`Sidereon.predict_passes/5` (every pass above a minimum elevation over a window).
## Example: solve a position
The positioning engine is the other half of the library. Feed it pseudoranges
and a precise-ephemeris product and it returns a least-squares fix with ECEF and
geodetic positions plus geometry diagnostics.
```elixir
# GPS L1 pseudoranges (meters) for the satellites in view at the epoch.
observations = [
{"G08", 23_825_519.8},
{"G10", 22_717_690.1},
{"G16", 20_478_653.4},
{"G18", 21_768_335.2},
{"G20", 21_248_327.7},
{"G21", 20_808_709.8}
]
# `sp3_data` is a precise SP3 ephemeris (a string, or load one with
# `Sidereon.GNSS.SP3.load/1`).
with {:ok, sp3} <- Sidereon.GNSS.SP3.parse(sp3_data),
{:ok, solution} <-
Sidereon.GNSS.Positioning.solve(sp3, observations, ~N[2020-06-24 12:00:00],
initial_guess: [4_500_000.0, 500_000.0, 4_500_000.0, 0.0]) do
solution.position # %{x_m, y_m, z_m} ITRF/IGS ECEF meters
solution.geodetic # %{lat_rad, lon_rad, height_m}
solution.rx_clock_s # receiver clock bias, seconds
solution.dop.pdop # position dilution of precision
solution.used_sats # satellites that contributed to the fix
end
```
`Sidereon.GNSS.RTK` and the PPP and DGNSS solvers follow the same pattern:
observations and a product in, a typed solution out.
For post-solve integrity checks, use `Sidereon.GNSS.QC.RaimInput.new/2` with
`Sidereon.GNSS.QC.raim/2` to run residual RAIM from satellite ids and
post-fit residuals. RAIM weights must come from per-satellite residual
variances; unit weights on metre-scale residuals make `fault_detected`
saturate near 100%:
```elixir
entries = [
%{satellite_id: "G01", elevation_deg: 72.0},
%{satellite_id: "G02", elevation_deg: 42.0},
%{satellite_id: "G03", elevation_deg: 35.0}
]
weights = Sidereon.GNSS.QC.weight_vector(entries, a_m: 0.8, b_m: 0.8)
Sidereon.GNSS.QC.raim(input, weights: weights)
```
Use `Sidereon.GNSS.ARAIM.Geometry.from_az_el_deg/3` with
`Sidereon.GNSS.ARAIM.araim/3` to compute HPL/VPL protection levels from
azimuth/elevation rows, ISM records, and an integrity allocation.
A runnable [`sidereon.livemd`](sidereon.livemd) walks through propagation,
positioning, and conjunction screening; more notebooks live under
[the examples directory](https://github.com/neilberkman/sidereon-ex/tree/main/examples).
## What's in the box
- **Orbit propagation** SGP4 / SDP4 from TLE and OMM, numerical propagation
with a composable force model (spherical-harmonic geopotential to selectable
degree and order, Sun/Moon third-body, solar radiation pressure, relativistic
correction, atmospheric drag), orbital decay estimation with a post-decay
validity latch, two-body Kepler propagation, ground track,
sub-satellite point, eclipse, Sun and Moon angles, and Doppler. See
`Sidereon`, `Sidereon.Propagator`, `Sidereon.SGP4`, `Sidereon.Drag`.
- **GNSS positioning** single-point positioning (SPP), public multi-epoch
static positioning with covariance, leave-one-out redundancy diagnostics,
and robust weighting, RINEX observation to SPP assembly and solve helpers,
RTK (float, integer-fixed, fix-and-hold) with typed arc/static/wide-lane
configs, PPP with temporal-correlation covariance using calibrated day-length
bounds, optional elevation cutoff, optional tropospheric-gradient estimation,
DGNSS, Huber-reweighted solves, RAIM with fault detection and exclusion,
RAIM over existing SPP solutions, SBAS and RTCM SSR / Galileo HAS corrections,
dilution of precision, and receiver velocity from Doppler. See
`Sidereon.GNSS.Positioning`,
`Sidereon.GNSS.StaticPositioning`, `Sidereon.GNSS.RTK`,
`Sidereon.GNSS.PrecisePositioning`, `Sidereon.GNSS.DGNSS`,
`Sidereon.GNSS.QC`, `Sidereon.GNSS.SBAS`, `Sidereon.GNSS.SSR`.
- **Integrity and error bounds** multi-constellation ARAIM protection levels,
SBAS protection levels (DO-229), per-observation reliability (minimal
detectable bias, internal and external), observability classification of
every solution (rank, redundancy, conditioning), and covariance-derived
error metrics (CEP, R95, SEP, error ellipse) that report wide or flagged
bounds for weak geometry rather than fabricated confidence. See
`Sidereon.GNSS.ARAIM`, `Sidereon.Reliability`, `Sidereon.ErrorMetrics`,
`Sidereon.GNSS.QC`, `Sidereon.GNSS.SBAS`.
- **Timing, estimation, and geodesy** Allan-family clock stability with
power-law noise identification (IEEE 1139), scalar Kalman and alpha-beta
trackers with innovation gating, NIS/MAD/EWMA helpers, and CFAR thresholds,
source localization (ToA/TDOA), station velocity (MIDAS) with trajectory fitting, step
detection, and network motion fields, repeating-geometry (sidereal)
filtering, geodesic direct and inverse problems (Karney), an epoch-aware
terrestrial frame catalog (ITRF/ETRF Helmert sets), PROJ-compatible EGM96
GTX vertical-grid interpolation, EGM2008 geoid grids, and
batch least-squares orbit fitting against precise ephemerides (including
terrestrial-frame SP3) with a per-satellite residual ledger. See
`Sidereon.ClockStability`, `Sidereon.Estimation`, `Sidereon.SourceLocalization`,
`Sidereon.GeodeticTimeSeries`, `Sidereon.Sidereal`, `Sidereon.OrbitDetermination`.
- **GNSS data and observations** SP3 (read, multi-center merge, write), broadcast
navigation (RINEX 3.x / 4.x), IONEX, ANTEX, CLK, satellite code biases
(Bias-SINEX and CODE DCB with OSB / DSB lookup), uniform satellite-state
sampling that treats precise and broadcast sources interchangeably, RTCM 3
broadcast ephemeris decode for GPS (1019), GLONASS (1020), Galileo
(1045/1046), BeiDou (1042), and QZSS (1044), each real-data validated,
RINEX 3 observations with Hatanaka / CRINEX decoding, carrier-phase
combinations, cycle-slip detection, Hatch smoothing, ionosphere-free
combination, precise interpolant artifacts, NTRIP request-byte construction,
and GPS L1 C/A signal generation, acquisition, and LNAV decode.
See `Sidereon.GNSS.SP3`, `Sidereon.GNSS.Broadcast`,
`Sidereon.GNSS.Ephemeris`, `Sidereon.GNSS.Bias`,
`Sidereon.GNSS.CarrierPhase`, `Sidereon.GNSS.RTCM`.
- **Ephemeris and time** JPL SPK / `.bsp` kernels for Sun, Moon, and planets;
TEME, GCRS, ITRS, geodetic, ECEF, and topocentric frames with IAU2000A
nutation and IAU2006 precession; UTC / TAI / TT / TDB / UT1 scales. See
`Sidereon.Ephemeris`, `Sidereon.Coordinates`, `Sidereon.GNSS.Time`.
- **Geometry and events** pass prediction, look angles, conjunction and TCA
screening, collision probability (Foster equal-area and numerical), CCSDS CDM
parsing, covariance propagation, initial orbit determination (Gibbs,
Herrick-Gibbs, Gauss angles-only), Lambert and Battin transfers, relative
motion in RIC / RTN / LVLH frames with Clohessy-Wiltshire propagation,
anomaly conversions, orbital element conversions including equinoctial and
modified equinoctial forms, and angular geometry (angular separation,
position angle, phase angle, beta angle). See `Sidereon.Passes`,
`Sidereon.Conjunction`, `Sidereon.Collision`, `Sidereon.IOD`, `Sidereon.Lambert`,
`Sidereon.OrbitalElements`, `Sidereon.Astro.Relative`, `Sidereon.Astro.Anomaly`,
`Sidereon.Astro.Equinoctial`, `Sidereon.Angles`.
- **Observation and almanac** apparent topocentric places (right ascension,
declination, azimuth, elevation) for the Sun, Moon, and any SPK body;
sub-solar and sub-observer points, terminator latitude, parallactic angle,
and satellite visual magnitude; Moon rise / set, illumination, and meridian
transits; seasons, moon phases, planetary events, and lunar / solar eclipses
over a window. See `Sidereon.Astro.Observe`, `Sidereon.Astro.Almanac`,
`Sidereon.Bodies`, `Sidereon.Observation`.
- **Atmosphere** Klobuchar and Galileo NeQuick-G ionospheric delay, IONEX grids,
tropospheric zenith delay and mapping, and NRLMSISE-00 neutral density. See
`Sidereon.GNSS.Ionosphere`, `Sidereon.GNSS.Troposphere`, `Sidereon.Atmosphere`.
- **RF link budget** free-space path loss, EIRP, C/N0, dish gain, and link
margin. See `Sidereon.RF`.
- **Terrain and data acquisition** DTED terrain elevation lookup with typed
lookup options, memory-mappable terrain stores, EGM2008 raster-window geoid
loading, and cache-first download of GNSS products (SP3, CLK, NAV, IONEX) and
DTED tiles from public archives. Exact SP3/IONEX requests can select direct,
NASA CDDIS/Earthdata, local-file, or in-memory sources without changing
product identity, and return verified provenance. See `Sidereon.Terrain`,
`Sidereon.GNSS.Data`, and `Sidereon.GNSS.Distribution`.
- **GNSS/INS fusion** strapdown mechanization with an error-state EKF (UKF
option), loose and tight coupling with typed measurement inputs, IGG-III loose
updates, an RTS smoother, encoded-state restore helpers, a serializable filter
state, and field mode: zero-velocity and zero-angular-rate updates,
non-holonomic constraints, per-fix-status weighting, and the IMU-to-body
mounting matrix, all off by default. See `Sidereon.GNSS.Fusion`.
- **Reference-station static solve** rover and reference observations in, one
station coordinate with covariance and typed per-mode errors out. See
`Sidereon.GNSS.RTK`.
- **Scenario simulation** deterministic synthetic observables plus a
ground-truth error ledger from a versioned scenario. See `Sidereon.GNSS.Scenario`.
- **Signal analysis** closed-form BPSK/BOC spectra, spectral separation
coefficients, DLL jitter, multipath envelopes, and typed option structs. See
`Sidereon.GNSS.Signal.Analysis`.
- **Format parse and serialize** TLE and OMM (KVN, XML, JSON) parse and encode,
CCSDS OPM / OEM / CDM / TDM, and the GNSS products above. See `Sidereon.Format.TLE`,
`Sidereon.Format.OMM`, `Sidereon.CCSDS.OPM`, `Sidereon.CCSDS.OEM`, `Sidereon.CCSDS.TDM`.
Every result is what the engine computes, returned as plain Elixir structs and
maps with `{:ok, _}` / `{:error, _}` tuples. Full signatures live on
[HexDocs](https://hexdocs.pm/sidereon).
## Other languages
sidereon is one validated engine with first-class interfaces in several
languages: Rust ([sidereon](https://github.com/neilberkman/sidereon)), Python
([sidereon-python](https://github.com/neilberkman/sidereon-python)), C
([sidereon-c](https://github.com/neilberkman/sidereon-c)), Elixir (this
package), and WebAssembly
([sidereon-wasm](https://github.com/neilberkman/sidereon-wasm)). The same numbers
come out everywhere. See the live demo and docs at
[sidereon.dev](https://sidereon.dev).
## License
MIT. The engine's SGP4 propagation is a port of David Vallado's reference
implementation (credit: David Vallado, AIAA 2006); see the core
[sidereon](https://github.com/neilberkman/sidereon) crate for full attribution.