Measurement-quality control for single-point positioning.
The numerical modeling and FDE orchestration live in the
sidereon-core Rust core. This module keeps the Elixir API,
normalizes options and epochs for the NIF, maps errors, and decodes the
unchanged public result maps.
Summary
Types
The result of raim/2.
A {satellite_id, elevation_deg} or {satellite_id, elevation_deg, cn0_dbhz} entry.
Functions
Chi-square inverse CDF (quantile).
Fault detection and exclusion: solve, run RAIM, exclude the worst satellite, and repeat until the measurement set is self-consistent or the exclusion budget is exhausted.
Lint RINEX NAV text.
Lint a parsed RINEX OBS file.
Lint RINEX OBS or CRINEX text.
Observation completeness and signal-quality rollup for a parsed RINEX OBS file.
Pseudorange measurement variance (m^2) from satellite elevation.
Residual-based RAIM: a chi-square goodness-of-fit test on a positioning solution.
Standalone range RAIM/FDE over a caller-supplied linearized measurement set, independent of any full positioning solve.
Render an observation QC report as HTML.
Render an observation QC report as fixed-width text.
Mechanically repair RINEX NAV text.
Mechanically repair RINEX OBS or CRINEX text.
Core robust-reweighted SPP under the RAIM/FDE exclusion loop.
Build a satellite => sigma_m map for a list of weight entries.
Serialize an observation QC report as JSON.
Build a satellite => inverse_variance_weight map for a list of weight entries.
Types
@type raim_result() :: %{ fault_detected?: boolean(), fault_detected: boolean(), test_statistic: float(), threshold: float() | nil, reduced_chi_square: float() | nil, dof: integer(), testable?: boolean(), testable: boolean(), normalized_residuals: %{required(String.t()) => float()}, rms_m: float(), worst_sat: String.t() | nil }
The result of raim/2.
A {satellite_id, elevation_deg} or {satellite_id, elevation_deg, cn0_dbhz} entry.
Functions
@spec chi2_inv(float(), pos_integer()) :: float()
Chi-square inverse CDF (quantile).
@spec fde( term(), [Sidereon.GNSS.Positioning.observation()], Sidereon.GNSS.Positioning.epoch(), keyword() ) :: {:ok, %{ solution: Sidereon.GNSS.Positioning.Solution.t(), excluded: [{String.t(), :raim_excluded}], iterations: non_neg_integer() }} | {:error, {:fault_unresolved, float()}} | {:error, term()}
Fault detection and exclusion: solve, run RAIM, exclude the worst satellite, and repeat until the measurement set is self-consistent or the exclusion budget is exhausted.
Malformed FDE options are returned as tagged errors, including
{:invalid_option, :p_fa}, {:invalid_option, :weights}, and
{:invalid_option, :max_iterations}.
@spec lint_obs(Sidereon.GNSS.RINEX.Observations.t()) :: {:ok, map()} | {:error, term()}
Lint a parsed RINEX OBS file.
Lint RINEX OBS or CRINEX text.
@spec observation_report( Sidereon.GNSS.RINEX.Observations.t(), keyword() ) :: {:ok, Sidereon.GNSS.QC.ObservationReport.t()} | {:error, term()}
Observation completeness and signal-quality rollup for a parsed RINEX OBS file.
@spec pseudorange_variance( number(), keyword() ) :: float() | {:error, :invalid_elevation | :missing_cn0}
Pseudorange measurement variance (m^2) from satellite elevation.
Returns a float, {:error, :invalid_elevation} for elevations at or below the
horizon, or {:error, :missing_cn0} when model: :elevation_cn0 is selected
without :cn0.
@spec raim( Sidereon.GNSS.Positioning.Solution.t() | Sidereon.GNSS.QC.RaimInput.t(), keyword() ) :: raim_result() | Sidereon.GNSS.QC.RaimResult.t()
Residual-based RAIM: a chi-square goodness-of-fit test on a positioning solution.
Pass inverse-variance weights derived from per-satellite residual variances,
either as a %{sat => weight} map or as weight entries consumed by
weight_vector/2. Unit weights with metre-scale residuals make
fault_detected saturate near 100%.
entries = [
%{satellite_id: "G01", elevation_deg: 72.0},
%{satellite_id: "G02", elevation_deg: 42.0}
]
weights = Sidereon.GNSS.QC.weight_vector(entries, a_m: 0.8, b_m: 0.8)
Sidereon.GNSS.QC.raim(input, weights: weights)
Standalone range RAIM/FDE over a caller-supplied linearized measurement set, independent of any full positioning solve.
Each row of rows is a map describing one linearized range measurement:
:id- stable measurement identifier (e.g. a satellite token"G01"):residual_m- observed-minus-computed range residual, metres:design_row- the measurement's row of the design matrix (a list of the partials of the predicted range with respect to each estimated state parameter); every row must carry the same length:weight- inverse-variance weight1 / sigma^2, strictly positive
Options:
:p_fa- false-alarm probability for the global chi-square test (default0.001):max_exclusions- maximum measurements the exclusion loop may remove (default: the row count):min_redundancy- minimum redundancy an exclusion must leave behind (default1)
Returns {:ok, result} where result carries the protected
:state_correction, :state_covariance, the :global_test chi-square map,
the :excluded ids, per-measurement :diagnostics, and the exclusion
:iterations; or {:error, reason} for a malformed or rank-deficient input.
@spec render_html(Sidereon.GNSS.QC.ObservationReport.t()) :: {:ok, String.t()} | {:error, term()}
Render an observation QC report as HTML.
@spec render_text(Sidereon.GNSS.QC.ObservationReport.t()) :: {:ok, String.t()} | {:error, term()}
Render an observation QC report as fixed-width text.
Mechanically repair RINEX OBS or CRINEX text.
@spec robust_fde( term(), [Sidereon.GNSS.Positioning.observation()], Sidereon.GNSS.Positioning.epoch(), keyword() ) :: {:ok, %{ solution: Sidereon.GNSS.Positioning.Solution.t(), excluded: [{String.t(), :raim_excluded}], iterations: non_neg_integer() }} | {:error, term()}
Core robust-reweighted SPP under the RAIM/FDE exclusion loop.
@spec sigmas( [weight_entry()], keyword() ) :: %{required(String.t()) => float()}
Build a satellite => sigma_m map for a list of weight entries.
@spec to_json(Sidereon.GNSS.QC.ObservationReport.t()) :: {:ok, String.t()} | {:error, term()}
Serialize an observation QC report as JSON.
@spec weight_vector( [weight_entry()], keyword() ) :: %{required(String.t()) => float()}
Build a satellite => inverse_variance_weight map for a list of weight entries.