Add BOC-aware lock detection and E1C-aided tracking

This commit is contained in:
2026-07-31 01:13:35 +03:00
parent 814a788b36
commit 9db955d02e
133 changed files with 6536 additions and 42 deletions
+79
View File
@@ -0,0 +1,79 @@
# 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.
+12
View File
@@ -25,4 +25,16 @@ Default YAML files:
- `e1_default.yaml`: requested 16.368 MHz nominal defaults.
- `acquisition_example.yaml`: faster 4.092 MHz executable search.
- `tracking_example.yaml`: 4.092 MHz tracking defaults.
- `navigation_collection.yaml`: SignalSim IQ-to-I/NAV regression. Its default
`tracking.architecture` is `e1c_pilot_aided_e1b`; the CLI can select
`e1b_only` for an A/B replay.
The BOC lock detector parameters are part of `TrackingConfig`. The defaults use
25 noncoherent power epochs, three confirmations, and the configured
`loss_of_lock_epochs` for sustained failure. Carrier and BOC central/outer
shape thresholds have explicit entry and exit values. `lock_signal_loss_power_ratio`
sets the five-tap power loss test. These parameters affect monitoring and
reacquisition only; they do not change discriminator or loop-filter coefficients.
`boc_side_peak_coherence_enter/exit` calibrate the coherent E/L-to-P tap-sign
test needed to distinguish the negative half-chip BOC sidelobe from the main
peak using more than magnitude-only information.
+34
View File
@@ -0,0 +1,34 @@
# E1C-pilot-aided E1B tracking
The default E1 architecture uses two phase-coherent correlator branches:
```text
raw SignalSim IQ8
-> E1C PCPS acquisition
-> E1C 25-symbol secondary-code phase/frequency search
-> shared double-precision carrier and code phase vectors
-> E1C VE/E/P/L/VL -> FLL/PLL/DLL/CN0/BOC lock
-> E1B VE/E/P/L/VL -> 4 ms Prompt stream -> I/NAV decoder
```
The secondary synchronizer jointly searches code phase and residual carrier
frequency using complex 4 ms Prompt values. Its estimated secondary phase is
then applied at every E1C primary-code epoch. Integrations may divide the 4 ms
primary period exactly; the 2 ms navigation configuration applies the same
secondary symbol to both halves.
E1B navigation polarity never enters the pilot loop discriminators, C/N0
estimator, or lock detector. The E1B branch receives the identical carrier and
code phase arrays before either NCO advances, preserving sample-by-sample
coherence. Only E1B Prompt I/Q is passed to symbol synchronization and I/NAV
decoding.
The initial 400 ms E1C secondary search operates on a buffered portion of the
same input stream. The offline regression replays that buffer through the
closed loops after synchronization; it does not load frozen Prompt, symbol,
page, or ephemeris artifacts. A streaming implementation can use the same
bounded input buffer or start output after synchronization.
This pilot architecture is a separate robustness improvement. It is not used
to conceal the legacy BOC metric defect: E1B-only and E1C-aided modes are both
evaluated with the same corrected BOC-aware lock detector.
+12 -2
View File
@@ -6,7 +6,10 @@ soft-decision Viterbi decoder or navigation database in RTL.
## Tracking-IP output contract
One record is emitted for every 4 ms E1B primary-code epoch:
The tracking IP uses E1C VE/E/P/L/VL for shared carrier/code loops, C/N0, and
BOC-aware lock monitoring. A separate E1B correlator branch consumes the same
sample-by-sample NCO phases. One navigation record is emitted from that branch
for every 4 ms E1B primary-code epoch:
| Field | Proposed representation | Meaning |
| --- | --- | --- |
@@ -16,7 +19,9 @@ One record is emitted for every 4 ms E1B primary-code epoch:
| carrier phase/frequency | NCO state/measurement words | Reprocessing and phase diagnostics |
| code phase | unsigned fixed-point chips | Code-time association |
| C/N0 | fixed-point dB-Hz or invalid | Monitoring only |
| carrier/code lock | bits | Decoder validity gate |
| carrier/code lock | bits | E1C pilot-derived decoder validity gate |
| lock metric valid | bit | BOC smoothing/calibration window is valid |
| BOC main/side metrics | fixed-point monitor words | false-lock diagnosis |
| cycle slip/discontinuity | bits | Immediate symbol/page synchronizer reset |
| valid | bit | Transaction validity |
@@ -25,6 +30,11 @@ must absorb software service latency; backpressure cannot be allowed to stop the
sample-rate tracking datapath. At 250 records/s/channel, even 36 active E1B
channels produce only 9000 records/s, so a memory-mapped DMA ring is sufficient.
E1C secondary-code synchronization can remain software-assisted initially: a
bounded Prompt buffer is searched for secondary phase and residual carrier
frequency, then the phase is written to tracking-channel state. Continuous
secondary wipeoff and the E1C/E1B correlator branches remain sample-rate RTL.
## Software decoder
Software retains floating `numpy.float64` prompt/soft values in the reference