80 lines
3.3 KiB
Markdown
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.
|