Files
galileo/docs/boc_aware_lock_detector.md

80 lines
3.3 KiB
Markdown

# BOC-aware code-lock detector
## Root cause
The previous code-lock flag compared an instantaneous Prompt power with the
mean Early/Late power:
\[
M_{legacy}=\frac{|P|^2}{(|E|^2+|L|^2)/2}.
\]
That ratio assumes a single-peaked BPSK autocorrelation. It is not a valid
lock predicate for the BOC(1,1) replica used by this SignalSim checkout and the
receiver. With E/L at +/-0.25 chip, the ideal BOC shape at a +0.25-chip local
error has normalized tap powers `E=1`, `P=0.0625`, and `L=0.25`, so the legacy
metric is 0.1 even though the local phase is still inside the central-peak
basin. No threshold on this ratio can distinguish that valid shoulder from a
genuine loss across the complete BOC shape.
SignalSim commit `80b2621` selects `PRN_ATTRIBUTE_BOC`, doubles the nominal
chip rate to 2.046 Mchip/s, shifts the E1B/E1C memory-code index every two
subchips, and negates the second half. It therefore generates BOC(1,1), not the
BOC(6,1) part of full Galileo CBOC. The Python replica follows the same
half-chip convention. The validation plot is generated from SignalSim's actual
E1B code table, not a fabricated PRN.
## Corrected metric
The detector noncoherently averages all five tap powers over a configurable
window. It then evaluates:
\[
M_{main}=\frac{|E|^2+|P|^2+|L|^2}
{|VE|^2+|E|^2+|P|^2+|L|^2+|VL|^2}
\]
and
\[
M_{side}=\frac{\max(|VE|^2,|VL|^2)}{|E|^2+|P|^2+|L|^2}.
\]
Power fractions alone cannot distinguish the negative Prompt sidelobe at a
half-chip error. The detector also smooths the carrier-invariant tap-sign term
\[
M_{coh}=\frac{\operatorname{Re}\{(E+L)P^*\}}
{|P|(|E|+|L|)}.
\]
It is 1 at the ideal main peak, 1/3 at a quarter-chip main shoulder, and 0 at
the +/-0.5-chip negative Prompt sidelobe. Outer-tap dominance covers the
+/-0.75-chip false-lock cases. Both tests have independent hysteresis.
`metric_valid` is independent of `code_lock`. It remains false until the power
window is full, and invalid/non-finite integrations do not enter the smoother.
The tracker currently rejects incomplete integrations before correlation; a
trailing partial block is not measured. At 4.092 MHz there are exactly four
samples/chip. At non-integer ratios, the double-precision code NCO maintains a
fractional-chip phase while replica chips and the rectangular BOC subcarrier
are selected at each sample. There is no unexplained integer sample shift or
interpolation filter in the lock calculation.
Lock uses separate entry/exit limits, consecutive confirmations, and sustained
failure counting. A signal-power peak hold detects signal disappearance. A
sustained outer-tap dominance declares a BOC side-peak condition. A single
instantaneous P/E/L crossing cannot clear lock.
All five accumulations span the same samples and use the same replica amplitude,
so the shape metrics normalize by their own summed tap power; division by the
integration length (or its square for power) cancels exactly. Mixing raw and
normalized taps is prohibited. Boundary-crossing 2 ms dumps are valid because
two dumps exactly tile each 4 ms primary period; only a truncated final dump is
dropped before the detector.
The lock detector does not change PLL, DLL, FLL, carrier NCO, or code NCO
states. Its false-lock and true-loss behavior is regression-tested with ideal
main-peak, quarter-chip shoulder, outer-tap side-peak, zero-signal, invalid
integration, and one-epoch disturbance vectors.