Use when you must smooth GNSS code pseudoranges with carrier-phase delta ranges before positioning: run the first-order Hatch recursion at a smoothing time constant, carry the smoothed range between epochs on the precise carrier increments, and monitor the code-carrier ionospheric divergence whose trailing-window slope fit predicts the smoothed-minus-code bias that would alarm a diverging range. Computes the noise-reduction verdict from the exact steady-state code-noise closed form sigma_code...
Scanned 9/27/2026
Install to Claude Code
npx -y skills add ashfordeOU/aero-agent-skills --skill gnss-carrier-smoothing --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Gnss Carrier Smoothing?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ashfordeou-gnss-carrier-smoothing)More formats (shields.io, HTML) on the badges page.
---
name: gnss-carrier-smoothing
description: "Use when you must smooth GNSS code pseudoranges with carrier-phase delta ranges before positioning: run the first-order Hatch recursion at a smoothing time constant, carry the smoothed range between epochs on the precise carrier increments, and monitor the code-carrier ionospheric divergence whose trailing-window slope fit predicts the smoothed-minus-code bias that would alarm a diverging range. Computes the noise-reduction verdict from the exact steady-state code-noise closed form sigma_code*sqrt(alpha/(2 - alpha)), its sigma_code/sqrt(2*tau/T) textbook limit and the carrier delta-range term. Produces the smoothed range time series, the verdict (code-only std, quoted limit, carrier term, total std, improvement factor) and the divergence alarm that gate the range before it feeds positioning. Trigger: carrier-phase smoothing, code-carrier smoothing, hatch recursion, smoothing time constant, code-carrier divergence, ionospheric divergence, smoothed range noise reduction."
license: Apache-2.0
compliance: STANDARDS-REF
standards:
- id: rtca-do-229
reference-only: true
gated: false
domain: gnc-autonomy
pack: navigation
compatibility: "agentskills.io SKILL.md; any SKILL.md host (Claude Code, Hermes, OpenClaw)"
metadata:
domain: gnc-autonomy
subdomain: navigation
tags: [gnss-carrier-smoothing, carrier-phase-smoothing, hatch-filter-recursion, code-carrier-divergence-monitor, ionospheric-divergence-check, smoothed-range-noise-reduction]
version: 0.1.0
author: AeroSkills
---
# GNSS Carrier-Phase Smoothing (gnc-autonomy/navigation/gnss-carrier-smoothing)
Use when the task is smoothing GNSS code pseudoranges with
carrier-phase delta ranges as a measurement preprocessor for
positioning. The code pseudorange is low-pass filtered at a smoothing
time constant tau while the precise carrier delta range carries the
smoothed range between epochs, cutting the raw code noise by about an
order of magnitude while a code-carrier ionospheric divergence monitor
alarms the slowly growing error that a linear ionosphere induces. This
leaf implements the first-order Hatch recursion, its exact
steady-state noise closed forms, and the divergence monitor in pure
Python, stdlib only. It pairs with gnc-autonomy/navigation/
gnss-pseudorange-positioning (the single-epoch snapshot fix that
consumes the smoothed ranges), gnss-raim-fde for integrity on the raw
measurement set, and kalman-filter-design as the alternative
estimation route with a dynamics model. RTCA DO-229 MOPS
carrier-smoothing and divergence concepts appear here in paraphrased
summary form only. Continuous carrier phase between epochs is assumed;
cycle-slip repair and integer ambiguity resolution are out of scope.
## Domain quick reference
- Hatch gain: alpha = T / tau in (0, 1), so the recursion pole
(1 - alpha) lies in (0, 1) and the variance relaxation e-folds in
about tau/2 seconds (50 s at tau = 100 s). A time constant at or
below the update interval (alpha >= 1) means no smoothing.
- Recursion: s_0 = c_0; for k >= 1,
s_k = alpha*c_k + (1 - alpha)*(s_(k-1) + (phi_k - phi_(k-1))).
The code is low-pass filtered while the carrier delta range bridges
epochs, so a slowly growing code bias is smoothed out over tau while
the fast, precise carrier motion is followed.
- Exact code-only steady-state std: sigma_smoothed =
sigma_code*sqrt(alpha/(2 - alpha)). An input fed with weight w to a
pole-(1-alpha) recursion contributes w^2/(alpha*(2 - alpha)) times
its variance, giving the code term alpha^2/(alpha*(2 - alpha)) and
the carrier term (1 - alpha)^2/(alpha*(2 - alpha)).
- Textbook limit: sigma_code/sqrt(2*tau/T) = sigma_code*sqrt(alpha/2),
the tau >> T small-alpha form, with the exact identity
approx = exact*sqrt((2 - alpha)/2) and relative gap
(exact - approx)/exact = alpha/4 + alpha^2/32 + alpha^3/128 + ...,
about 0.0025 at alpha = 0.01.
- Carrier delta-range term std:
(1 - alpha)*sigma_carrier/sqrt(alpha*(2 - alpha)). The two noise
inputs are independent per epoch, so the total smoothed variance is
the exact sum of the code-term and carrier-term variances and the
total std is sqrt(code-term variance + carrier-term variance).
- Improvement factor: sigma_code / total_std (10.025 at the defaults).
- Ionospheric divergence: the code is delayed by +I while the carrier
is advanced by -I, so the code-carrier difference D = code - phi =
2*I grows at rate dD/dt = 2*dI/dt. A Hatch filter lags a linear
ramp: at steady state the smoothed-minus-code error is
-rate*(tau - T) = -2*(dI/dt)*(tau - T), the classic code-carrier
divergence error whose tau >> T form is -2*(dI/dt)*tau.
- Units are SI throughout (m, s, m/s). Deterministic recursion,
closed-form noise and slope fits, stdlib math only.
## Workflow
1. Set the smoothing configuration: choose the smoothing time
constant tau, the update interval T and the raw noise sigmas, and
confirm 0 < T < tau with alpha_from_time_constant so alpha = T/tau
lies in (0, 1). The defaults are tau = 100 s, T = 1 s,
sigma_code = 0.3 m, sigma_carrier = 0.003 m, window 60, threshold
1.0 m.
2. Run the Hatch recursion traverse over the code-carrier stream:
run_hatch_smoother seeds the first epoch with the raw code and each
later epoch applies hatch_update with the carrier delta range
phi_k - phi_(k-1). On a diverging ionosphere the early smoothed
values sink below the raw code, the expected lag signature.
3. Form the noise-reduction verdict with code_noise_std_smoothed and
noise_reduction_verdict: the exact code-only std against the
sigma_code/sqrt(2*tau/T) textbook limit and their identity, the
carrier delta-range term, the total std and the improvement factor
over the raw code.
4. Run the code-carrier divergence monitor: iono_divergence_rate fits
the least-squares slope of the code-carrier difference over the
trailing window (divided by T into m/s), smoothed_iono_bias
predicts the steady-state smoothed-minus-code bias -rate*(tau - T),
and divergence_check raises the alarm when the predicted bias
exceeds the threshold.
5. Gate the smoothed range for positioning: release the smoothed range
time series with the noise-reduction verdict and the divergence
alarm, and confirm the deterministic checks with the contract test
(see Behavior contract below).
## Worked example
Receiver at a fixed 20000000.0 m range, tau = 100 s, T = 1 s,
sigma_code = 0.3 m, sigma_carrier = 0.003 m, divergence window 60
epochs, alarm threshold 1.0 m. All values are real module outputs of
this leaf (deterministic, offline).
- Configuration: alpha = T/tau = 0.010000; pole 1 - alpha = 0.990000;
variance relaxation e-folding about tau/2 = 50.0 s.
- Noise-reduction verdict (noise_reduction_verdict):
- exact code-only std = sigma_code*sqrt(alpha/(2 - alpha)) =
0.021266 m;
- textbook limit sigma_code/sqrt(2*tau/T) = 0.3/sqrt(200) =
0.021213 m, relative gap 0.002503 = alpha/4 + alpha^2/32 +
alpha^3/128 (identity asserted to 1e-8);
- carrier delta-range term = 0.021054 m, comparable to the code term
because the recursion integrates many millimeter increments;
- total smoothed std = 0.029925 m (variance is the exact sum of the
code term and the carrier term, asserted to 1e-15);
- improvement factor = sigma_code/total_std = 10.025: the smoothed
range is about ten times quieter than the raw code.
- Empirical confirmation over 38000 settled epochs: code-only replay
(Random(42), perfect carrier) gives empirical std 0.021043 m against
the closed form 0.021266 m (within 0.002 m and 5%); code plus
carrier replay (Random(7)) gives 0.027221 m against 0.029925 m
(relative difference 0.0904, within the 15% autocorrelation budget,
effective samples about N/(2*tau/T) ~ 190).
- Ionospheric ramp at v = 0.02 m/s (divergence rate dD/dt = 2*v = 0.04
m/s, noise free): closed-form steady-state smoothed-minus-code bias
smoothed_iono_bias(0.04, 100, 1) = -3.9600 m = -(2v)*(tau - T), and
the empirical mean over the last 2000 of 4000 epochs is -3.9600 m
(matched within 0.1%). The smoothed range lags the growing code
delay by about 4 m at this time constant.
- Early epochs of that ramp (raw code 20000000.02 m, carrier delta
-0.0200 m per epoch): smoothed 20000000.000000 (seed),
19999999.980400, 19999999.961196, 19999999.942384,
19999999.923960 m: the recursion sinks below the code while the
ionosphere climbs.
- Divergence monitor on noisy code-carrier differences (code noise
0.3 m on the diffs, Random(123)):
- quiet ionosphere v = 0.001 m/s: estimated rate -0.0001 m/s,
predicted smoothed bias +0.0075 m, alarm False (the noise floor of
the 60 s slope fit stays far below the 1.0 m threshold);
- ramp v = 0.02 m/s: estimated rate 0.0427 m/s (near the true
0.04), predicted smoothed bias -4.2256 m, alarm True.
## Verification
- Confirm alpha_from_time_constant(100, 1) = 0.01 and the pole
0.99 in (0, 1).
- Confirm code_noise_std_smoothed(0.01, 0.3) = 0.021266 m and the
identity approx = 0.021213 = exact*sqrt(1.99/2) to 1e-12.
- Confirm the verdict: carrier_term_std 0.021054 m, total_std 0.029925
m, improvement_factor 10.025; total variance equals the exact sum of
the code and carrier term variances to 1e-15.
- Confirm run_hatch_smoother on the noise-free ramp reproduces the
five early smoothed values above within 1e-6.
- Confirm smoothed_iono_bias(0.04, 100, 1) = -3.96 m and the
divergence_check replayed verdicts (quiet no alarm, ramp alarms).
- Confirm every non-physical input raises ValueError: tau <= 0, T <=
0, T >= tau, alpha outside (0, 1), sigma_code or sigma_carrier at 0
or negative, window below 2 or above the epoch count, non-finite
measurements and differences, threshold at 0 or negative, unequal or
empty epoch lists.
- Run the deterministic contract test offline: python3
scripts/test_gnss_carrier_smoothing.py (34 tests).
## Related leaves
- gnc-autonomy/navigation/gnss-pseudorange-positioning: the
single-epoch snapshot fix that consumes the smoothed pseudoranges
(its scope explicitly excludes smoothing).
- gnc-autonomy/navigation/gnss-raim-fde: integrity fault detection and
exclusion on the raw measurement set, the snapshot guard around the
positioning solution.
- gnc-autonomy/navigation/kalman-filter-design: the scalar
predict/correct estimator with a dynamics model and covariance
tuning, the alternative to the measurement-domain Hatch recursion.
- gnc-autonomy/navigation/dilution-of-precision: geometry quality
reads that complement the range-quality verdict.
- gnc-autonomy/navigation/ins-gnss-integrated-filter: the loosely
coupled integration that consumes gated GNSS range updates.
## Pitfalls
- Reporting the textbook limit as the exact reduction: at alpha =
0.01 the exact code-only std is 0.021266 m while
sigma_code/sqrt(2*tau/T) = 0.021213 m, a 0.25% relative gap that
grows with alpha/4; use the exact closed form and quote the limit
only as the tau >> T approximation.
- Dropping the carrier delta-range term: the carrier increments are
millimeter-level per epoch but the recursion integrates them, so
their term (0.021054 m) rivals the code term (0.021266 m) at the
defaults; the total smoothed std is 0.029925 m, not the code-only
0.021266 m.
- Forgetting the divergence monitor before release: a linear
ionosphere with dI/dt = 0.02 m/s leaves a steady smoothed-minus-code
bias of about -4 m at tau = 100 s, enough to corrupt the position
fix even though the smoothed range looks quiet.
- Running the recursion without validating the configuration: alpha
outside (0, 1), T >= tau, or an empty or unmatched code-carrier
stream raises ValueError rather than producing a plausible-looking
series.
- Assuming continuous carrier phase: the recursion needs an unbroken
carrier arc between epochs; cycle-slip repair and integer ambiguity
resolution are out of scope for this leaf.
## Behavior contract (gate 3)
Run the deterministic contract test (stdlib unittest, offline, exit 0):
python3 scripts/test_gnss_carrier_smoothing.py
The test covers the worked-example contract (alpha 0.01, code-only std
0.021266 m, total std 0.029925 m, improvement factor 10.025, early
ramp epochs), the closed-form identities (textbook limit identity to
1e-12, variance sum to 1e-15, relative-gap expansion to 1e-8), the
empirical replays (Random(42) code-only within 0.002 m and 5%,
Random(7) code plus carrier within 15%, ionospheric ramp bias within
0.1%), the divergence monitor replay (quiet no alarm, ramp rate near
0.04 m/s with alarm), deterministic replay, and ValueError rejection of
every non-physical input.
## Compliance
- Standards referenced, not reproduced: RTCA DO-229 MOPS is the GNSS
airborne equipment standard whose carrier-smoothing and divergence
monitoring concepts this leaf paraphrases in summary form per
standards-map.yaml; no MOPS text is reproduced verbatim.
- compliance: STANDARDS-REF, gated: false.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!