Expand description
Tracking-loop loss-of-lock model: C/N₀ → lock/unlock with hysteresis, the time it takes to lose lock, and the spoof pull-in limits set by code and carrier offset rate.
The engine’s existing denial and capture criteria are ratios on received power: a
jammer denies at J/S = 30 dB and a spoofer captures at J/S = 3 dB
(crate::attack_surface), and a satellite is “lost” when its effective C/N₀ crosses
a flat 25 dB-Hz line (crate::jamming::lock_status). Real loss of lock does not work
that way. A tracking channel gives up when its loop can no longer hold the signal, and
that depends on the loop noise bandwidth B_n, the predetection integration time T,
the correlator spacing d, and the dynamics the loop is being asked to follow. This
module builds that model and reports the denial radius it implies alongside the
power-ratio radius — never in place of it — with the difference named
(denial_radius_delta_km) so the two can be compared rather than quietly swapped.
Nothing here forks a second correlator or a second link budget. The loop primitives are
crate::sdr (correlate, synth_if,
CaCode) and the radiometry is
crate::jamming (j_over_s_db,
effective_cn0_dbhz,
nominal_cn0_dbhz,
q_factor).
§What is modelled
- Carrier-loop thermal jitter — the Costas 1σ phase jitter
σ_PLL = √( (B_n/(C/N₀)) · (1 + 1/(2·T·C/N₀)) )rad, the second factor being the squaring loss. The per-epoch (open-loop) discriminator jitter is the same expression withB_n → 1/(2T), and the two differ by exactly the loop-filter factor√(2·B_n·T). - Code-loop thermal jitter — the non-coherent early/late 1σ code jitter
σ_DLL = √( (d·B_n/(2·C/N₀)) · (1 + 2/((2−d)·T·C/N₀)) )chips. - The tracking-threshold rules — a Costas loop is held to
3σ_PLL + θ_e ≤ 45°(the “15-degree rule”: one sigma may not exceed a quarter of the 60° quarter-cycle budget), and a DLL to3σ_DLL + lag ≤ d/2chips, the discriminator’s linear half-range. Both allowances are inputs; the defaults are the stated rules. - Dynamic stress — a second-order carrier loop carries a steady-state phase error
θ_e = 360·ḟ/ω_n²degrees under a Doppler rateḟ, withω_n = B_n/0.53; a first-order code loop carries a ramp lagẋ/(4·B_n)chips under a code slewẋ. These are what a spoofer pushing on the loop actually has to stay inside. - Hysteresis — a receiver that has lost lock must re-pull-in, and pull-in runs a
wider loop than steady-state tracking. Since jitter grows as
√B_n, the re-lock threshold is strictly above the drop threshold, and the width follows from the bandwidth ratio rather than being asserted: in the thermal-dominated limit it is10·log₁₀(r)dB and in the squaring-loss-dominated limit5·log₁₀(r)dB, so any computed hysteresis must lie between those two bounds. - Time to lose lock — two distinct quantities, both reported. The declared loss
of lock is when a two-threshold lock detector with confirmation dwells transitions,
driven by a C/N₀ profile; the physical escape time is the mean time between cycle
slips of the Costas loop,
T̄ = π²·ρ'·I₀²(ρ')/(2·B_n)withρ' = ρ/4and loop SNRρ = 1/σ_PLL²(Viterbi’s first-order result applied to the doubled phase2φa Costas loop tracks, whose slips are half cycles), reported inlog₁₀ sbecause it spans many decades.
§Validated vs Modelled
Validated against the existing crate::sdr correlator stepped forward — a
genuinely different route to the same numbers, not a restatement:
- the open-loop Costas discriminator jitter including its squaring-loss term agrees
with the measured jitter of
crate::sdr::correlateon seeded synthetic IF to better than 2 % over 35–50 dB-Hz; - the closed-loop jitter reduction
σ_closed = σ_meas·√(2·B_n·T)agrees with a stepped first-order Costas loop built from the same correlator to ~3 %; - the first-order code-loop ramp lag
ẋ/(4·B_n)agrees with the stepped DLL to better than 0.1 %, withB_n = g·slope/(4T)the discrete loop’s equivalent bandwidth andslope = 1/(2−d)the ideal-triangle discriminator gain; bessel_i0agrees with the standard modified-Bessel values to < 2 × 10⁻⁶ relative.
Modelled — the default loop parameters (10 Hz carrier / 1 Hz code noise bandwidth,
1 ms predetection integration, 0.5 chip spacing), the 2× pull-in bandwidth ratio, the
confirmation dwell lengths, the representative jammer power and antenna gains, and the
C/N₀ profile are all representative band figures, not a datasheet for any receiver.
Oscillator (Allan-deviation) and vibration jitter are not modelled: the carrier
budget here is thermal plus dynamic stress only, and a real receiver adds those two
terms, which can only make the threshold worse. Front-end bandwidth limiting, multipath,
AGC dynamics, data-bit-transition losses, and aiding from an inertial or clock reference
are likewise out of scope and stated rather than silently included. The slip time is
Viterbi’s first-order expression; a second-order loop slips more often (GNSS-SDR 0.0.19’s
second-order Costas loop slipped about ten times more often near the threshold in
tests/tracking_loop_gnss_sdr_oracle.rs).
References: Kaplan & Hegarty, Understanding GPS/GNSS (3rd ed.), ch. 8 (carrier and
code tracking loops, thermal jitter, the tracking-threshold rules, the second-order
B_n = 0.53·ω_n relation); A. J. Viterbi, Principles of Coherent Communication
(1966) and F. M. Gardner, Phaselock Techniques (3rd ed.), ch. 9 (mean time between
cycle slips); Abramowitz & Stegun §9.8 (the I₀ polynomial approximations).
Structs§
- Denial
Link - The one-jammer link whose radius both denial criteria are evaluated on. Every leg is
evaluated with the existing
crate::jammingfunctions; nothing here re-derives the radiometry. - Lock
Detector - A two-threshold lock detector with confirmation dwells — the mechanism that makes
lock/unlock hysteretic rather than a single line a noisy C/N₀ estimate chatters
across. Lock is dropped after
drop_confirm_epochsconsecutive epochs belowdrop_cn0_dbhz, and regained afterrelock_confirm_epochsconsecutive epochs at or above the strictly higherrelock_cn0_dbhz. - Lock
History - The outcome of running the hysteretic detector over the C/N₀ profile.
- Loop
Config - The loop geometry a threshold calculation needs.
- Loop
Thresholds - The C/N₀ thresholds a loop configuration implies, with the binding loop named.
- Pull
InCell - One cell of the spoof pull-in map: whether a spoofer slewing the victim’s code at
code_slew_chips_per_sand its carrier atdoppler_rate_hz_per_sstays inside both loops’ following limits. - Tracking
Loop Scenario - A tracking-loop loss-of-lock scenario. Every field is defaulted, so a body of only
kind = "tracking-loop"reproduces the reference configuration.
Enums§
- Lock
State - Whether the receiver currently declares the channel locked.
Constants§
- CN0_
SEARCH_ MAX_ DBHZ - Highest C/N₀ (dB-Hz) considered when solving a tracking threshold.
- CN0_
SEARCH_ MIN_ DBHZ - Lowest C/N₀ (dB-Hz) considered when solving a tracking threshold.
- COSTAS_
THRESHOLD_ DEG - The Costas-loop carrier tracking-threshold allowance (degrees) applied to
3σ + θ_e. This is the “15-degree rule” stated as its three-sigma form: one sigma of phase jitter may not exceed 15°, i.e. three sigma may not exceed 45°. - MAX_
AXIS_ LEN - Hard cap on the length of any input axis (the spoof pull-in grid, the jitter table).
- MAX_
DETECTOR_ STEPS - Hard cap on the number of lock-detector steps a single run may take, so no input can turn the state machine into an unbounded loop.
- RADIUS_
BRACKET_ MAX_ M - Upper bound on the search bracket (m) used when inverting a link for a radius.
- RADIUS_
BRACKET_ MIN_ M - Lower bound on the search bracket (m) used when inverting a link for a radius.
- SECOND_
ORDER_ BN_ OVER_ WN - The ratio
B_n/ω_nfor the standard second-order loop (damping ζ = 1/√2), as used to convert a stated loop noise bandwidth into the natural frequency that sets dynamic stress. Kaplan & Hegarty, ch. 8.
Functions§
- bessel_
i0 - Modified Bessel function of the first kind, order zero. Abramowitz & Stegun §9.8
polynomial approximations: 9.8.1 for
|x| ≤ 3.75(|ε| < 1.6 × 10⁻⁷) and 9.8.2 for|x| > 3.75(|ε| < 1.9 × 10⁻⁷ on the scaled form). Overflows to infinity abovex ≈ 713; useln_bessel_i0where that matters. - carrier_
tracking_ threshold_ cn0_ dbhz - The carrier-loop tracking threshold (dB-Hz): the lowest C/N₀ at which
3·σ_PLL + θ_estill fits insideallowance_deg, for a loop of bandwidthbn_hz, integrationt_s, under a Doppler ratedoppler_rate_hz_per_s. - code_
tracking_ threshold_ cn0_ dbhz - The code-loop tracking threshold (dB-Hz): the lowest C/N₀ at which
3·σ_DLL + lagstill fits insideallowance_chips, for a DLL of bandwidthbn_hz, integrationt_s, correlator spacingspacing_chips, under a code slew ofcode_slew_chips_per_s.Nonewhen the slew lag alone exceeds the allowance. - dll_
measurement_ jitter_ chips - Per-epoch (open-loop) code-error jitter (chips) of a non-coherent early/late
discriminator at correlator spacing
d:σ² = (d/(4·T·C/N₀)) · (1 + 2/((2−d)·T·C/N₀)). - dll_
ramp_ lag_ chips - Steady-state code lag (chips) a first-order code loop of noise bandwidth
bn_hzcarries under a code slew ofcode_slew_chips_per_s:lag = ẋ/(4·B_n). - dll_
thermal_ jitter_ chips - Closed-loop code thermal jitter (chips) for a non-coherent early/late DLL:
σ_DLL² = (d·B_n/(2·C/N₀)) · (1 + 2/((2−d)·T·C/N₀)). - early_
late_ amplitude_ discriminator_ slope - The linear-region gain (chips of discriminator output per chip of code error) of the
normalised early-minus-late amplitude discriminator
½·(|E|−|L|)/(|E|+|L|)for an ideal triangular autocorrelation at spacingd:1/(2−d). This is the constant that maps the per-epoch gain of the discrete loop incrate::sdr::trackonto an equivalent loop noise bandwidth. - equivalent_
first_ order_ bandwidth_ hz - The equivalent one-sided loop noise bandwidth (Hz) of a discrete first-order loop
that applies
gain × discriminatoronce pert_s:B_n = g·k/(4·T), wherekis the discriminator’s linear-region slope. A first-order loop with this bandwidth carries the ramp lagdll_ramp_lag_chipsreturns, which is how the two are cross-checked against thecrate::sdrcorrelator. - ln_
bessel_ i0 - Natural logarithm of
bessel_i0, stable for arbitrarily large arguments: forx > 3.75the A&S 9.8.2 scaled form givesln I₀ = x − ½·ln x + ln(poly(3.75/x)), so a loop SNR of several hundred (whereI₀itself overflows a float) is still reportable. Needed because the mean time between cycle slips grows likee^{2ρ}. - log10_
mean_ time_ to_ cycle_ slip_ s - Mean time between Costas carrier slips (half cycles), reported as
log₁₀(seconds):T̄ = π²·ρ'·I₀²(ρ')/(2·B_n)withρ' = ρ/4and loop SNRρ = 1/σ_PLL²(Viterbi’s first-order, sinusoidal-phase-detector result; Gardner, Phaselock Techniques, ch. 9). - max_
code_ slew_ at_ cn0_ chips_ per_ s - The largest code slew (chips/s) a DLL can be dragged at at signal strength
cn0_dbhz: the ramp lag may only use whatever3σ_DLLleaves ofallowance_chips. Zero when the jitter already fills the budget. Reduces tomax_code_slew_chips_per_sas the jitter goes to zero, and is the ceiling the pull-in map’s cells are decided against, so the two can never disagree. - max_
code_ slew_ chips_ per_ s - The largest code slew (chips/s) a noiseless first-order DLL of bandwidth
bn_hzcan be dragged at before its ramp lag leaves the discriminator’s linear half-rangeallowance_chips:ẋ_max = 4·B_n·allowance. A spoofer slewing faster than this does not capture a locked loop — it outruns it, and the victim falls back onto the authentic peak (or loses lock) instead of following the lie. - max_
doppler_ rate_ hz_ per_ s - The largest carrier Doppler rate (Hz/s) a second-order loop of bandwidth
bn_hzcan be dragged at, at signal strengthcn0_dbhz: the dynamic stress must fit in whatever the jitter leaves ofallowance_deg. Zero when the jitter already fills the budget. - pll_
dynamic_ stress_ deg - Steady-state carrier phase error (degrees) a second-order loop of noise bandwidth
bn_hzcarries under a Doppler rate ofdoppler_rate_hz_per_s:θ_e = 360·ḟ/ω_n²withω_n = B_n/0.53. This is the dynamic-stress term that adds to3σin the 45° carrier budget, and it is what limits how fast a spoofer may slew a victim’s carrier before the victim’s loop simply falls off the back. - pll_
measurement_ jitter_ rad - Per-epoch (open-loop) Costas discriminator phase jitter (rad) at
cn0_dbhzfor a predetection integration timet_s:σ² = (1/(2·C/N₀·T)) · (1 + 1/(2·T·C/N₀)). The first factor is the post-correlation phase noise of a coherent integration; the second is the squaring loss a Costas discriminator pays for being insensitive to the data-bit sign. - pll_
thermal_ jitter_ rad - Closed-loop Costas carrier thermal jitter (rad):
σ_PLL² = (B_n/(C/N₀)) · (1 + 1/(2·T·C/N₀)). - pull_
in_ cell - Evaluate one spoof pull-in cell for a loop configuration at signal strength
cn0_dbhz. - run_
lock_ history - Drive
detectorover the down-then-up C/N₀ ramp at the loop’s own epoch rate and report when it declared loss of lock and when it recovered. Deterministic.