DSSS Primary Use Cases for Code Acquisition Design¶
Two operating regimes drive the acquisition design. Both are wide-Doppler
(the uncertainty far exceeds one code-period's resolution), but they sit at
opposite ends of the speed-vs-sensitivity trade, so they pick different
methods. The design goal for each is the fastest method that still acquires
at the target (Pfa, Pd).
The method palette¶
Every acquisition method is built from two Doppler primitives — both already shipped in doppler — optionally wrapped in a coarse mixer/tiling layer and a non-coherent layer:
| Method | doppler API | Doppler res / span | Integration | Use when |
|---|---|---|---|---|
| Column-FFT (slow-time) | dsss.Acquisition |
1/(ny·nx) / ±1/(2nx) |
ny epochs coherent | many coherent reps; need the gain |
| 2-D roll (2-D code FFT × signal FFT → 2-D IFFT) | spectral.Corr2D / Detector2D |
1/nx / ±1/2 |
1 epoch | wide Δf, few reps, enough SNR — whole grid in one 2-D op |
| Mixer bank | caller loop (guide) | tiles either, 1/(2nx) step |
— | widen Δf at a fine resolution; linear cost |
| Non-coherent | Acquisition(max_noncoh=…) |
sensitivity past the coherent ceiling | N_nc looks |
data-bit / burst-limited M_coh |
The two primitives are exact duals: the roll's resolution (1/nx) equals
the column-FFT's span (±1/(2nx)). Roll = coarse + wide from one epoch;
column-FFT = fine + narrow from ny coherent epochs. Mixing the input is the
continuous-frequency dual of rolling conj(FFT(code)) by integer bins.
Choosing the method — three knobs¶
- Doppler uncertainty
Δfvs the native span±1/(2nx)(= ±1/(2·T_epoch)). Narrow → one column-FFT covers it. Wide → tile with a mixer bank or sweep all bins at once with a 2-D roll. - Coherent epochs
M_coh— how many epochs you can integrate coherently, capped by the burst length (UC2) or the data-bit period (UC1). Large → the column-FFT's fine resolution +10·log10(ny·N)gain is worth its narrow span. Small (≈1) → the column-FFT is wasted; the roll gives the whole grid for the cost of one epoch. - Sensitivity (
cn0_dbhz) — can one epoch acquire, or do you need the gain? High C/N0 → roll (fast). Low C/N0 → coherent gain (column-FFT) and/or non-coherent looks (max_noncoh) when the coherent ceiling is the data bit.
Decision table (Δf vs native span × M_coh):
M_coh small (≈1) |
M_coh large |
|
|---|---|---|
| Δf narrow | Acquisition, reps=few |
Acquisition alone (fine + gain) |
| Δf wide | 2-D roll (one op, all bins) + non-coherent over reps | 2-D-roll coarse or mixer-tile, then column-FFT fine; pick by channel-count vs one 2-D op |
The cost asymmetry that decides the wide-Δf row: a 2-D roll sweeps all
~Δf/(1/T_epoch) Doppler bins from one epoch, whereas the fine mixer bank
runs that many channels, each a Corr2D tile integrating ny epochs and
resolving ny× finer bins. So the bank costs roughly ny× more per Doppler
window — and measurably more once the finer bin count is included: ≈40× on a
16×2046 (ny=16) grid, ≈10× on a 5×4094 (ny=5) grid — the factor
tracks ny (bench_widedoppler.py). The roll pays for it with one epoch's
gain and 1/nx (coarse) resolution. So: roll when SNR lets one epoch acquire;
column-FFT/mixer when you must buy the coherent gain.
GPS-like always on 1023-chip Gold code¶
- Chip rate < 10 MHz
- Doppler < 25 ppm moves
- Symbol rate kHz range
- Data BPSK asynchronous with code
- Periodic multi-epoch, code-only transmissions
- Plenty of time to acquire and lock
Regime (illustrative: L1 C/A, Rc = 1.023 MHz, L = 1023, spc = 2):
nx = 2046, T_epoch = 1 ms, native span ±500 Hz (one slow-time bin =
1 kHz). 25 ppm of 1.575 GHz ⇒ Doppler ±39 kHz — ~79× the native span,
so decidedly wide. Asynchronous kHz-rate data ⇒ M_coh ≈ 1 on data-bearing
stretches; the periodic code-only epochs are the coherent windows
(M_coh = pilot epochs).
Approach — sensitivity-driven (time is plentiful):
- Coherent inner: run
Acquisitionover the code-only pilot windows for the fine1/(ny·T_epoch)Doppler and full coherent gain. - Non-coherent across:
Acquisition(max_noncoh=…)(P1) accumulates looks across the always-on stream — the data-bit ceiling makes this the real sensitivity engine; "plenty of time" means you can spend many looks. - Wide Δf: a coarse layer in front — either a mixer bank (~158 channels at 50% overlap for \<1 dB edge loss) or a 2-D roll (~79 Doppler bins in one 2-D op per epoch) — then the column-FFT refines each coarse bin.
Because sensitivity, not latency, is the constraint, the column-FFT + P1 stack is the core; the coarse layer just covers the 25 ppm span.
Burst Transmission¶
- Chip rate in MHz, symbol rate in kHz to MHz
- Doppler < 25 ppm moves
- 5+ long (rel. to data code) acquisition code repetitions (no data)
- Payload follows with shorter data code
- Data synchronous with symbols
Regime (illustrative: Rc = 5 MHz, long acq code L = 2047, spc = 2,
carrier 2.4 GHz): nx = 4094, T_epoch ≈ 0.41 ms, native span ±1.2 kHz
(2.44 kHz window). 25 ppm ⇒ Doppler ±60 kHz — ~49× the native span, wide.
The unmodulated preamble gives a clean coherent M_coh = R ≥ 5, and the
burst is latency-bound: acquire within the ~5-epoch preamble (~2 ms) before
the payload.
Approach — speed-driven (latency-bound, wide Δf, few reps):
- 2-D roll is the fit: one 2-D op per epoch sweeps all ~49 Doppler bins
at the coarse
1/nx(2.44 kHz) resolution — ≈10× cheaper on this5×4094grid (bench_widedoppler.py) than running ~98 fine mixer channels each integrating 5 epochs, which a 2-ms latency budget cannot afford serially. - Refine only if needed: if the despreader's pull-in can't swallow a 2.44 kHz
residual, column-FFT over the 5 reps within the winning coarse bin (one
channel) for the fine
1/(5·T_epoch)≈ 490 Hz Doppler. - Hand off: the
(Doppler bin, code phase)seeds the shippedDespreaderon the shorter data code for the synchronous payload.
Here latency and the wide span dominate; the roll's one-epoch coarse sweep beats the coherent bank.
Why these are the fastest — cost model¶
For a Doppler span Δf requiring C = Δf / (1/T_epoch) native windows:
- Mixer + column-FFT:
Cchannels, each aCorr2D(ny, nx)tile —C·nyfine bins, full10·log10(ny·N)coherent gain, but a 2-D FFT overnyepochs per channel. - 2-D roll:
Ccoarse bins from one epoch — one forwardFFT_nxshared acrossCinverseFFT_nx— one epoch's gain,1/nxresolution.
Measured (bench_widedoppler.py): the fine bank is ≈40× the roll on the GPS
16×2046 grid (C=79) and ≈10× on the burst 5×4094 grid (C=49) — it
pays for ny× finer bins and ny epochs of integration, so the gap grows with
ny. So the
choice is gain vs speed at fixed span: spend the compute (and ny epochs of
latency) to buy 10·log10(ny) of coherent gain (UC1, sensitivity-bound), or take
the one-epoch roll when the SNR already supports a single-epoch detection (UC2,
latency-bound). The non-coherent layer (P1) extends UC1's reach when the coherent
ceiling is the data bit. See Benchmarking.
See also¶
- DSSS acquisition architecture + roadmap — the
CAF framing, the trade space, and the phased plan (P1 non-coherent shipped; P2
sub-block
Kis the wide-Doppler widener that cuts the channel count). - DSSS Burst Acquisition guide — the mixer-bank loop and worked ±100 kHz example.
- corr2d interpolated inverse — the code-phase axis (independent of the Doppler-span choice here).