Sidereon.GNSS.Ionosphere (Sidereon v0.13.0)

Copy Markdown View Source

Single-frequency ionospheric group-delay corrections.

Two models are exposed over the sidereon-core crate: the GPS broadcast Klobuchar model (eight alpha/beta coefficients, IS-GPS-200), and an IONEX vertical-TEC-grid slant delay (single-layer model). Both return the group delay in positive meters.

This is the ionosphere correction for a GNSS signal. It is not Sidereon.Atmosphere, which is NRLMSISE-00 neutral-atmosphere mass density for drag, a different quantity entirely.

Sign convention

The returned delay is a group delay and is positive: it increases the measured pseudorange (the signal arrives later than vacuum geometry would predict). The carrier-phase advance is the negation of this value. The ionosphere is dispersive, so the delay reported on a carrier other than the model's native L1 is the L1 delay scaled by (f_L1 / f)^2; pass the carrier via frequency_hz.

Units at the boundary

Public inputs are in degrees (_deg) and meters/hertz, per the Sidereon naming convention. Latitude is positive north, longitude positive east, azimuth clockwise from north.

Summary

Functions

Build an IONEX product from one sample per TEC grid node.

Build an IONEX product directly from whole-grid TEC samples.

Galileo NeQuick-G single-frequency ionospheric group delay, scaled to frequency_hz.

IONEX vertical-TEC-grid slant ionospheric group delay, scaled to frequency_hz.

Serialize a parsed IONEX product back to standard IONEX text.

GPS broadcast Klobuchar L1 ionospheric group delay, scaled to frequency_hz.

Load and parse an IONEX file into a product handle.

Galileo NeQuick-G full slant ionospheric group delay (positive meters).

Galileo NeQuick-G full three-dimensional slant total electron content (TECU).

Parse an in-memory IONEX byte buffer into a product handle.

Extract an IONEX handle as whole-grid TEC samples.

Extract an IONEX handle as one TEC sample per grid node.

Functions

from_node_samples(samples, shell_height_km, base_radius_km, exponent)

@spec from_node_samples(
  [Sidereon.GNSS.Ionosphere.TecSample.t()],
  number(),
  number(),
  integer()
) ::
  {:ok, reference()} | {:error, term()}

Build an IONEX product from one sample per TEC grid node.

shell_height_km and base_radius_km are kilometers. Each Sidereon.GNSS.Ionosphere.TecSample carries latitude/longitude in degrees and vertical TEC/RMS in TECU.

from_samples(samples)

@spec from_samples(Sidereon.GNSS.Ionosphere.TecGridSamples.t()) ::
  {:ok, reference()} | {:error, term()}

Build an IONEX product directly from whole-grid TEC samples.

Axes are degrees, shell and base radii are kilometers, and TEC/RMS grids are TECU. The returned handle is accepted anywhere a parsed IONEX handle is accepted, including ionex_slant_delay/7.

galileo_nequick_g_delay(coeffs, lat_deg, lon_deg, azimuth_deg, elevation_deg, epoch, frequency_hz)

@spec galileo_nequick_g_delay(
  map(),
  number(),
  number(),
  number(),
  number(),
  NaiveDateTime.t() | tuple(),
  number()
) :: {:ok, float()} | {:error, term()}

Galileo NeQuick-G single-frequency ionospheric group delay, scaled to frequency_hz.

coeffs carries the three Galileo broadcast effective-ionisation coefficients as %{ai0: a0, ai1: a1, ai2: a2}. The receiver geodetic latitude/longitude and the satellite azimuth/elevation are in degrees; epoch is a NaiveDateTime or {{y, m, d}, {h, min, s}} tuple in Galileo system time. The NeQuick-G arm maps the slant delay by elevation only, so azimuth_deg is accepted (to match the shared ionosphere-model boundary) but does not change the result. Returns {:ok, delay_m} (positive meters) or {:error, reason}.

ionex_slant_delay(handle, lat_deg, lon_deg, azimuth_deg, elevation_deg, epoch, frequency_hz)

@spec ionex_slant_delay(
  reference(),
  number(),
  number(),
  number(),
  number(),
  NaiveDateTime.t() | tuple(),
  number()
) :: {:ok, float()} | {:error, term()}

IONEX vertical-TEC-grid slant ionospheric group delay, scaled to frequency_hz.

handle is a parsed-IONEX reference from parse_ionex/1 or load_ionex/1. The receiver geodetic latitude/longitude and the satellite azimuth/elevation are in degrees; epoch is a NaiveDateTime or {{y, m, d}, {h, min, s}} tuple (the pierce point rides on the IONEX shell, so the receiver height is not used). Returns {:ok, delay_m} (positive meters) or {:error, reason}.

ionex_to_string(handle)

@spec ionex_to_string(reference()) :: {:ok, String.t()} | {:error, term()}

Serialize a parsed IONEX product back to standard IONEX text.

handle is a parsed-IONEX reference from parse_ionex/1 or load_ionex/1. This is the inverse of parse_ionex/1: re-parsing the output reproduces the same TEC grids. The serialization is deterministic and performs no I/O.

Returns {:ok, text} or {:error, reason}.

Examples

{:ok, handle} = Sidereon.GNSS.Ionosphere.parse_ionex(ionex_bytes)
{:ok, text} = Sidereon.GNSS.Ionosphere.ionex_to_string(handle)
{:ok, _reparsed} = Sidereon.GNSS.Ionosphere.parse_ionex(text)

klobuchar_delay(params, lat_deg, lon_deg, azimuth_deg, elevation_deg, epoch, frequency_hz)

@spec klobuchar_delay(
  map(),
  number(),
  number(),
  number(),
  number(),
  NaiveDateTime.t() | tuple(),
  number()
) :: {:ok, float()} | {:error, term()}

GPS broadcast Klobuchar L1 ionospheric group delay, scaled to frequency_hz.

params carries the eight broadcast coefficients as %{alpha: {a0, a1, a2, a3}, beta: {b0, b1, b2, b3}} (or lists). The receiver geodetic latitude/longitude and the satellite azimuth/elevation are in degrees; epoch is a NaiveDateTime or {{y, m, d}, {h, min, s}} tuple in GPS time. Returns {:ok, delay_m} (positive meters) or {:error, reason}.

load_ionex(path)

@spec load_ionex(String.t()) :: {:ok, reference()} | {:error, term()}

Load and parse an IONEX file into a product handle.

Returns {:ok, reference()} or {:error, reason}.

nequick_g_delay(coeffs, ray, frequency_hz)

@spec nequick_g_delay(map(), map(), number()) :: {:ok, float()} | {:error, term()}

Galileo NeQuick-G full slant ionospheric group delay (positive meters).

The full 3D slant TEC from nequick_g_stec/2 mapped to a dispersive group delay on frequency_hz. coeffs and ray are as in nequick_g_stec/2.

Returns {:ok, delay_m} (positive meters) or {:error, reason}.

nequick_g_stec(coeffs, ray)

@spec nequick_g_stec(map(), map()) :: {:ok, float()} | {:error, term()}

Galileo NeQuick-G full three-dimensional slant total electron content (TECU).

This is the reference-grade full 3D NeQuick-G integration, distinct from the compact single-layer galileo_nequick_g_delay/7. The coeffs map carries the broadcast effective-ionisation coefficients %{ai0:, ai1:, ai2:}. The ray map carries both endpoints of the receiver-to-satellite line of sight, in the reference algorithm's native units:

  • :month - month of the year, 1..12
  • :utc_hours - UTC time of day in hours, [0, 24]
  • :station_lon_deg, :station_lat_deg, :station_height_m
  • :satellite_lon_deg, :satellite_lat_deg, :satellite_height_m

Returns {:ok, stec_tecu} (slant TEC in TECU) or {:error, reason}.

parse_ionex(bytes)

@spec parse_ionex(binary()) :: {:ok, reference()} | {:error, term()}

Parse an in-memory IONEX byte buffer into a product handle.

Returns {:ok, reference()} or {:error, reason}. The buffer is parsed exactly once; the parsed grid is held as a resource handle.

tec_grid_samples(handle)

@spec tec_grid_samples(reference()) ::
  Sidereon.GNSS.Ionosphere.TecGridSamples.t() | {:error, term()}

Extract an IONEX handle as whole-grid TEC samples.

This is the inverse IR for from_samples/1. Axes are degrees, shell and base radii are kilometers, and TEC/RMS grids are TECU.

tec_samples(handle)

@spec tec_samples(reference()) ::
  [Sidereon.GNSS.Ionosphere.TecSample.t()] | {:error, term()}

Extract an IONEX handle as one TEC sample per grid node.

Each returned sample has latitude/longitude in degrees and vertical TEC/RMS in TECU.