GNSS

This documentation was generated with the assistance of AI. Please report any inaccuracies.

The com.irurueta.navigation.gnss package estimates a receiver’s position, velocity, and clock offset/drift from GNSS pseudo-range and pseudo-range-rate measurements, following Groves, 2013 (each class also mirrors a script from Groves' companion MATLAB code). It also includes generators that synthesize satellite orbits, measurements, and error biases for testing and simulation. See the bibliography for full citations.

The estimation pipeline

flowchart LR A["Satellite ECEF position/velocity\nSatelliteECEFPositionAndVelocityGenerator"] --> B["Pseudo-range /\npseudo-range-rate measurements\nGNSSMeasurementsGenerator, GNSSBiasesGenerator"] B --> C["Least-squares position/velocity\nGNSSLeastSquaresPositionAndVelocityEstimator"] C --> D["Kalman filter update\nGNSSKalmanEpochEstimator"] D --> E["Estimated state\nposition, velocity, clock offset/drift\nGNSSEstimation / GNSSKalmanState"] E -. previous state .-> D

GNSSKalmanFilteredEstimator wraps the last two boxes: on the first epoch it seeds the filter from GNSSLeastSquaresPositionAndVelocityEstimator (via GNSSKalmanInitializer), then feeds every subsequent epoch’s measurements through GNSSKalmanEpochEstimator.

Least-squares position, velocity, clock offset, and drift

GNSSLeastSquaresPositionAndVelocityEstimator solves for position + clock offset and, separately, velocity
clock drift, each by unweighted iterated least squares. For each satellite measurement, the range prediction first rotates the satellite’s ECEF position into the frame at signal-reception time to compensate for Earth rotation during the signal’s transit — the small-angle approximation of (8.36):







giving the corrected range (8.35) and the ECEF line-of-sight unit vector (8.41):




The predicted pseudo-range (position/clock-offset solve) or pseudo-range rate (velocity/clock-drift solve) and the corresponding row of the measurement matrix — (9.143) and (9.144) in Groves, 2013 — are then assembled for every satellite, and each iteration solves the unweighted least-squares update (9.35)/(9.141):

where is the vector of measured-minus-predicted pseudo-ranges (or rates). The solve repeats until the state update falls below CONVERGENCE_THRESHOLD.

var estimator = new GNSSLeastSquaresPositionAndVelocityEstimator(measurements);
var estimation = estimator.estimate();

var x = estimation.getX();
var y = estimation.getY();
var z = estimation.getZ();
var clockOffset = estimation.getClockOffset();

API reference: GNSSLeastSquaresPositionAndVelocityEstimator (javadoc, source)

Kalman-filtered estimation

GNSSKalmanEpochEstimator implements one epoch of the GNSS extended Kalman filter over an 8-element state (ECEF position, velocity, clock offset, clock drift). Propagation uses the transition matrix (9.147)/(9.150) — a constant-velocity, constant-clock-drift model over the propagation interval — and the general Kalman propagation equations (3.14)/(3.15):




with the system noise covariance built from the acceleration and clock-noise power spectral densities in GNSSKalmanConfig, following (9.152). The measurement update follows the same predicted pseudo-range/pseudo-range-rate and measurement-matrix construction as the least-squares estimator — (9.163), (9.165) — then applies the standard Kalman gain, innovation, state, and covariance updates:






GNSSKalmanFilteredEstimator drives this across epochs, and GNSSKalmanInitializer seeds the very first state/covariance pair from a least-squares solution.

var kalmanConfig = new GNSSKalmanConfig(
        initialPositionUncertainty, initialVelocityUncertainty, initialClockOffsetUncertainty,
        initialClockDriftUncertainty, accelerationPSD, clockFrequencyPSD, clockPhasePSD);

var estimator = new GNSSKalmanFilteredEstimator(kalmanConfig, epochInterval, listener);
estimator.updateMeasurements(measurements, timestamp);

var state = estimator.getState(); // GNSSKalmanState: GNSSEstimation + error covariance

API reference: GNSSKalmanConfig (javadoc, source)
GNSSKalmanFilteredEstimator (javadoc, source)
GNSSKalmanState (javadoc, source)

Synthesizing satellites, measurements, and biases

Three generator classes produce synthetic data for testing and simulation, all driven by a GNSSConfig (number of satellites, orbital radius, inclination, mask angle, error standard deviations, and so on):

SatelliteECEFPositionAndVelocityGenerator places each satellite on a circular orbit. The orbital angular rate follows Kepler’s third law (8.8), and the satellite’s position/velocity in the (rotating) orbital plane — (8.14), (8.25) — is rotated into ECEF axes by the longitude of the ascending node (8.16) and orbital inclination — (8.19) for position, (8.26) for velocity:

GNSSMeasurementsGenerator turns true satellite/user positions and velocities into pseudo-ranges and pseudo-range rates, applying the same transit-time rotation (8.36), range (8.35), range-rate (8.44), and elevation-angle (8.57) relations used by the estimators above, then adding the biases from GNSSBiasesGenerator.

GNSSBiasesGenerator samples signal-in-space, ionosphere, and troposphere range errors as Gaussian noise whose standard deviation grows as the satellite’s elevation angle drops toward the horizon — (9.79)/(9.80) scale the zenith error standard deviation by , with (ionosphere) or (troposphere) and the elevation from (8.57).

var satellites = SatelliteECEFPositionAndVelocityGenerator.generateSatellitesPositionAndVelocity(time, config);

var measurements = GNSSMeasurementsGenerator.generateMeasurements(
        time, satellites, userPositionAndVelocity, config, random);

API reference: SatelliteECEFPositionAndVelocityGenerator (javadoc, source)
GNSSMeasurementsGenerator (javadoc, source)