GNSS constellation identity catalogs and validation helpers.
This module is a data/catalog layer: it builds normalized satellite identity records from public sources and compares those records with GNSS products. It does not alter positioning solves or infer application-specific health rules.
The identity, parsing, validation, and diff logic lives in the sidereon_core
constellation module (the shared Rust core), reached through the NIF. The
core covers all five GNSS constellations — GPS, Galileo, GLONASS, BeiDou, and
QZSS — so this module is multi-system: from_celestrak_omm/2 dispatches on
the constellation atom (:gps, :galileo, :glonass, :beidou, :qzss) to
the per-system identity adapter in the core.
OMM/JSON source records are parsed from OBJECT_NAME and rendered as the
SP3/RINEX id ("G13", "E07", "R13", "C19", "J02"). GPS constellation
status HTML can be parsed and merged as an optional SVN/usability overlay.
Examples
iex> omms = [
...> %{"OBJECT_NAME" => "GPS BIIF-8 (PRN 03)", "NORAD_CAT_ID" => 40294}
...> ]
iex> {:ok, [record]} = Sidereon.GNSS.Constellation.from_celestrak_omm(:gps, omms)
iex> {record.system, record.prn, record.norad_id, record.sp3_id}
{:gps, 3, 40294, "G03"}
iex> record = %Sidereon.GNSS.Constellation.Record{
...> system: :gps,
...> prn: 3,
...> svn: nil,
...> norad_id: 40294,
...> sp3_id: "G03",
...> active?: true,
...> usable?: true,
...> source: %{}
...> }
iex> Sidereon.GNSS.Constellation.to_csv([record])
"prn,norad_cat_id,active,sp3_id\n3,40294,true,G03\n"Use from_celestrak_omm/2, from_celestrak_omm_lenient/2,
parse_navcen_html/1, and merge_navcen/2 with caller-provided text or
decoded maps.
Summary
Functions
Returns true when a constellation diff has any findings.
Compare two constellation catalog snapshots by {system, prn} identity.
Build records for system from a JSON OMM feed.
Build a lenient catalog from a JSON OMM feed.
Build records for system from CelesTrak OMM/JSON maps, failing on the first
entry whose OBJECT_NAME does not resolve to a PRN for system.
Build records for system from CelesTrak OMM/JSON maps, skipping (rather than
aborting on) entries whose OBJECT_NAME does not resolve to a PRN for
system.
Resolve a Galileo GSATdddd build id to its SVID/PRN (E-number), or nil when
no SVID is assigned yet.
Resolve a GLONASS orbital slot (1..24) to its FDMA L1/L2 frequency-channel
number k, or nil for a slot outside the operational range.
Resolve a GLONASS (Uragan) number to its orbital slot (1..24), or nil when
the number is not in the published constellation table.
Merge NAVCEN status rows into normalized records by PRN.
Parse NAVCEN's GPS constellation status HTML.
Render the canonical SP3/RINEX satellite token for a supported GNSS PRN.
Export records as the compact mapping CSV
Returns true when a validation report has no findings.
Validate catalog identity without an SP3 product.
Validate catalog identity against SP3 satellite ids.
Validate against SP3 satellite ids and raise unless the catalog is clean.
Types
Functions
@spec changed?(Sidereon.GNSS.Constellation.Diff.t()) :: boolean()
Returns true when a constellation diff has any findings.
@spec diff([Sidereon.GNSS.Constellation.Record.t()], [ Sidereon.GNSS.Constellation.Record.t() ]) :: Sidereon.GNSS.Constellation.Diff.t()
Compare two constellation catalog snapshots by {system, prn} identity.
The result separates added/removed PRNs from identity/status changes on a PRN
that exists in both snapshots. Assumes each input has at most one record per
{system, prn}; run validate/1 first on hand-edited catalogs.
iex> previous = [
...> %Sidereon.GNSS.Constellation.Record{
...> system: :gps, prn: 3, svn: 69, norad_id: 40294, sp3_id: "G03",
...> active?: true, usable?: true, source: %{}
...> }
...> ]
iex> current = [%{hd(previous) | norad_id: 99999, active?: false}]
iex> diff = Sidereon.GNSS.Constellation.diff(previous, current)
iex> [norad] = diff.norad_reassigned
iex> {norad.system, norad.prn, norad.from, norad.to}
{:gps, 3, 40294, 99999}
iex> [activity] = diff.activity_changed
iex> {activity.system, activity.prn, activity.from, activity.to}
{:gps, 3, true, false}
iex> Sidereon.GNSS.Constellation.changed?(diff)
true
@spec from_celestrak_json(String.t(), system()) :: {:ok, [Sidereon.GNSS.Constellation.Record.t()]} | error()
Build records for system from a JSON OMM feed.
This is the string-input sibling of from_celestrak_omm/2; decoded entries
are still resolved by the shared Rust core.
@spec from_celestrak_json_lenient(String.t(), system()) :: {:ok, Sidereon.GNSS.Constellation.Catalog.t()} | error()
Build a lenient catalog from a JSON OMM feed.
This is the string-input sibling of from_celestrak_omm_lenient/2.
@spec from_celestrak_omm(system(), [map()]) :: {:ok, [Sidereon.GNSS.Constellation.Record.t()]} | error()
Build records for system from CelesTrak OMM/JSON maps, failing on the first
entry whose OBJECT_NAME does not resolve to a PRN for system.
CelesTrak does not publish SVN, so records built from this source alone have
svn: nil. Records are returned sorted by {system, prn}.
@spec from_celestrak_omm_lenient(String.t()) :: {:ok, Sidereon.GNSS.Constellation.Catalog.t()} | error()
Build records for system from CelesTrak OMM/JSON maps, skipping (rather than
aborting on) entries whose OBJECT_NAME does not resolve to a PRN for
system.
The lenient sibling of from_celestrak_omm/2: every OMM that resolves becomes
a Record; every entry that does not (an other-constellation satellite in a
combined gnss feed, or a freshly launched vehicle whose name does not yet
resolve) is collected into Catalog.skipped with its identity. Resolvable
records are returned sorted by {system, prn}.
Leniency covers identity resolution only: an entry missing a valid
NORAD_CAT_ID still aborts with {:error, reason}.
Examples
iex> omms = [
...> %{"OBJECT_NAME" => "GPS BIIF-8 (PRN 03)", "NORAD_CAT_ID" => 40294},
...> %{"OBJECT_NAME" => "GSAT0210 (GALILEO 13)", "NORAD_CAT_ID" => 41859}
...> ]
iex> {:ok, catalog} = Sidereon.GNSS.Constellation.from_celestrak_omm_lenient(:gps, omms)
iex> Enum.map(catalog.records, & &1.sp3_id)
["G03"]
iex> Enum.map(catalog.skipped, &{&1.object_name, &1.norad_id})
[{"GSAT0210 (GALILEO 13)", 41859}]
@spec from_celestrak_omm_lenient(String.t(), system()) :: {:ok, Sidereon.GNSS.Constellation.Catalog.t()} | error()
@spec from_celestrak_omm_lenient(system(), [map()]) :: {:ok, Sidereon.GNSS.Constellation.Catalog.t()} | error()
Resolve a Galileo GSATdddd build id to its SVID/PRN (E-number), or nil when
no SVID is assigned yet.
iex> Sidereon.GNSS.Constellation.galileo_prn_for_gsat(210)
1
Resolve a GLONASS orbital slot (1..24) to its FDMA L1/L2 frequency-channel
number k, or nil for a slot outside the operational range.
iex> Sidereon.GNSS.Constellation.glonass_fdma_channel(1)
1
iex> Sidereon.GNSS.Constellation.glonass_fdma_channel(2)
-4
iex> Sidereon.GNSS.Constellation.glonass_fdma_channel(0)
nil
Resolve a GLONASS (Uragan) number to its orbital slot (1..24), or nil when
the number is not in the published constellation table.
iex> Sidereon.GNSS.Constellation.glonass_slot_for_number(730)
1
@spec sp3_id(system(), pos_integer()) :: String.t()
Render the canonical SP3/RINEX satellite token for a supported GNSS PRN.
iex> Sidereon.GNSS.Constellation.sp3_id(:gps, 7)
"G07"
iex> Sidereon.GNSS.Constellation.sp3_id(:galileo, 7)
"E07"
@spec to_csv( [Sidereon.GNSS.Constellation.Record.t()], keyword() ) :: String.t()
Export records as the compact mapping CSV:
prn,norad_cat_id,active,sp3_idThe active column is true only when record.active? and record.usable?
are both true. Records are sorted by {system, prn}.
Options
:booleans- how theactivecolumn is rendered::lower(default:true/false) or:title(True/False, for a pandas consumer).
@spec valid?(Sidereon.GNSS.Constellation.Validation.t()) :: boolean()
Returns true when a validation report has no findings.
@spec validate([Sidereon.GNSS.Constellation.Record.t()]) :: Sidereon.GNSS.Constellation.Validation.t()
Validate catalog identity without an SP3 product.
Reports duplicate PRNs, duplicate NORAD ids, and PRNs that are inactive or unusable according to the normalized records.
@spec validate_sp3( [Sidereon.GNSS.Constellation.Record.t()], Sidereon.GNSS.SP3.t() | [String.t()] ) :: Sidereon.GNSS.Constellation.Validation.t()
Validate catalog identity against SP3 satellite ids.
The second argument may be a loaded %Sidereon.GNSS.SP3{} or a list of SP3/RINEX
satellite tokens. missing_sp3_ids reports active+usable catalog ids absent
from the product; extra_sp3_ids reports product ids absent from the
active+usable catalog, restricted to the systems the catalog covers.
@spec validate_sp3!( [Sidereon.GNSS.Constellation.Record.t()], Sidereon.GNSS.SP3.t() | [String.t()] ) :: :ok
Validate against SP3 satellite ids and raise unless the catalog is clean.
A build-time gate: returns :ok when the catalog has no findings, otherwise
raises ArgumentError describing them. Intended for catalog-build / automation
steps, not the positioning runtime.