File dll_core.h¶
FileList > dll > dll_core.h
Go to the source code of this file
Delay-lock loop (DLL) — non-coherent early/prompt/late code tracking. More...
#include "clib_common.h"#include "dp_state.h"#include "jm_perf.h"#include "loop_filter/loop_filter_core.h"#include <complex.h>#include "detection/detection_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | dll_state_t DLL state. |
Public Functions¶
| Type | Name |
|---|---|
| JM_FORCEINLINE JM_HOT void | dll_accumulate (dll_state_t * s, float complex d) Per-sample early/prompt/late correlate + code-phase advance. |
| JM_FORCEINLINE float | dll_chip_sign (uint8_t c) |
| void | dll_configure (dll_state_t * state, double bn, double zeta) |
| void | dll_configure_lock (dll_state_t * state, double threshold, size_t n_looks, double alpha) Configure the always-on code-lock detector. |
| dll_state_t * | dll_create (const uint8_t * code, size_t code_len, size_t sps, double init_chip, double bn, double zeta, double spacing, size_t segments) Create a DLL instance (COPIES code ). |
| void | dll_destroy (dll_state_t * state) Destroy a DLL instance and release all memory (incl. the code copy). |
| double | dll_get_bn (const dll_state_t * state) |
| double | dll_get_code_phase (const dll_state_t * state) |
| double | dll_get_code_rate (const dll_state_t * state) |
| double | dll_get_last_error (const dll_state_t * state) |
| double | dll_get_lock_stat (const dll_state_t * state) Last lock test statistic R (compare against the configured eta). |
| int | dll_get_locked (const dll_state_t * state) Last lock decision (1 = locked, 0 = not). |
| double | dll_get_noise_est (const dll_state_t * state) Current CFAR noise-power estimate E|O|^2 (offset-tap EMA). |
| size_t | dll_get_segments (const dll_state_t * state) |
| void | dll_get_state (const dll_state_t * state, void * blob) |
| void | dll_init (dll_state_t * s, const uint8_t * code, size_t code_len, size_t sps, double init_chip, double bn, double zeta, double spacing) Initialise a DLL in place (no allocation); BORROWS code . |
| JM_FORCEINLINE float | dll_replica (const dll_state_t * s, double c, double adv) Sub-chip code replica at fractional code phase c (one tap). |
| void | dll_reset (dll_state_t * state) Re-seed the loop to its create-time code phase; keep config. |
| void | dll_set_bn (dll_state_t * state, double val) |
| int | dll_set_state (dll_state_t * state, const void * blob) |
| size_t | dll_state_bytes (const dll_state_t * state) |
| size_t | dll_steps (dll_state_t * state, const float complex * x, size_t x_len, float complex * out, size_t max_out) |
| size_t | dll_steps_max_out (dll_state_t * state) |
| JM_FORCEINLINE JM_HOT void | dll_update (dll_state_t * s) Per-period code discriminator + loop update + phase wrap. |
Macros¶
| Type | Name |
|---|---|
| define | DLL_EPS 1e-12 |
| define | DLL_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('D','L','L',' ') |
| define | DLL_STATE_VERSION 1u |
Detailed Description¶
Tracks the code phase of a continuous, repeating spreading code (e.g. a PN / Gold sequence) on a carrier-wiped sample stream. Per sample it correlates the input against three taps of the local code — early (+spacing chips), prompt, late (-spacing chips) — accumulating an integrate-and-dump over one code period; per period it runs the non-coherent envelope discriminator (|E| - |L|) / (|E| + |L|), filters it through an embedded 2nd-order loop_filter_state_t, and steers the code rate + phase.
It pairs with the carrier loop (costas_core.h): the carrier loop wipes the carrier, the DLL wipes the code. The block API (dll_steps) is the Python face; the JM_FORCEINLINE dll_accumulate()/dll_update() are the C composition API a tracking channel inlines into its own sample loop.
Lifecycle: dll_create -> [steps / configure / reset]* -> dll_destroy, or embed by value with dll_init() (which BORROWS the caller-owned code).
uint8_t code[31] = { ... }; // 0/1 chips, one period
dll_state_t *d = dll_create(code, 31, 2, 0.0, 0.01, 0.707, 0.5);
float complex sym[16];
size_t k = dll_steps(d, rx, rx_len, sym, 16); // one prompt per period
double phase = d->chip_pos; // tracked code phase, chips
dll_destroy(d);
Public Functions Documentation¶
function dll_accumulate¶
Per-sample early/prompt/late correlate + code-phase advance.
Correlates the carrier-wiped sample d against the early, prompt and late code taps (wrapped over the periodic code) and advances the code phase by code_rate / sps chips. Inline, zero call overhead.
Parameters:
sDLL state. Must be non-NULL.dOne carrier-wiped input sample.
function dll_chip_sign¶
0/1 chip -> +1/-1 BPSK sign.
function dll_configure¶
function dll_configure_lock¶
Configure the always-on code-lock detector.
The DLL carries a lock detector that reuses acquisition's non-coherent test statistic. Every emitted look (a partial in segments mode, or the full-epoch prompt when segments == 1) is also correlated at a random off-peak code phase — re-drawn each epoch and kept noise_guard chips clear of the prompt/early/late lobe — to give a signal-free CFAR noise sample (valid for a low-sidelobe code, e.g. Gold). The offset power feeds an EMA reference E|O|^2; the prompt powers of n_looks consecutive looks are summed into S = sum|P_k|^2, and the detector declares lock when
R = sqrt(2 * S / E|O|^2) > threshold
which under H0 has P(R > threshold) = marcum_q(n_looks, 0, threshold) — so a caller sizes threshold = det_threshold_noncoherent(pfa, n_looks) and n_looks = det_n_noncoh(snr, ...) to meet a target (Pfa, Pd). The threshold is passed in (not derived) so the core stays dependency-free; the Python binding converts a pfa via the detection module. The EMA must average many more cells than the test integrates (1/alpha >> n_looks) or the noise estimate's own variance inflates Pfa; the binding defaults 1/alpha to max(1024, 32*n_looks).
Parameters:
stateDLL state. Must be non-NULL.thresholdCFAR threshold eta on the statistic R.n_looksNon-coherent integration depth N (looks); clamped to >= 1.alphaEMA coefficient for the noise reference, in (0, 1].
function dll_create¶
Create a DLL instance (COPIES code ).
dll_state_t * dll_create (
const uint8_t * code,
size_t code_len,
size_t sps,
double init_chip,
double bn,
double zeta,
double spacing,
size_t segments
)
Parameters:
codeSpreading code (0/1 chips), one period; copied internally.code_lenCode length (chips per period).spsSamples per chip (default 2).init_chipSeed code phase, chips (default 0.0).bnLoop noise bandwidth (default 0.01).zetaDamping factor (default 0.707).spacingEarly/late tap offset, chips (default 0.5).segmentsPartial correlations per code epoch (default 1). 1 = a coherent full-epoch integrate-and-dump (one prompt/period). >1 splits each epoch into that many sub-epoch partials: it emits that many partial prompts/period and tracks the code non-coherently across them (robust to an asynchronous data-symbol clock). segments/epoch ~ samples/symbol at a downstream SymbolSync when the symbol rate is near the code rate, so choose >= 2 for symbol-timing recovery.
Returns:
Heap-allocated state, or NULL on allocation failure.
Note:
Caller must call dll_destroy() when done.
function dll_destroy¶
Destroy a DLL instance and release all memory (incl. the code copy).
Parameters:
stateMay be NULL.
function dll_get_bn¶
function dll_get_code_phase¶
function dll_get_code_rate¶
function dll_get_last_error¶
function dll_get_lock_stat¶
Last lock test statistic R (compare against the configured eta).
function dll_get_locked¶
Last lock decision (1 = locked, 0 = not).
function dll_get_noise_est¶
Current CFAR noise-power estimate E|O|^2 (offset-tap EMA).
function dll_get_segments¶
function dll_get_state¶
function dll_init¶
Initialise a DLL in place (no allocation); BORROWS code .
void dll_init (
dll_state_t * s,
const uint8_t * code,
size_t code_len,
size_t sps,
double init_chip,
double bn,
double zeta,
double spacing
)
The by-value counterpart to dll_create(): a tracking channel that embeds a dll_state_t initialises it here and retains ownership of code (it is not copied or freed). code must hold code_len chips for the loop's lifetime.
Parameters:
sState to initialise. Must be non-NULL.codeSpreading code (0/1 chips), one period; borrowed.code_lenCode length (chips per period); must be >= 1.spsSamples per chip.init_chipSeed code phase, chips.bnLoop noise bandwidth, normalised to the code-period rate.zetaDamping factor (0.707 = critically damped).spacingEarly/late tap offset, chips (0.5 = half-chip).
function dll_replica¶
Sub-chip code replica at fractional code phase c (one tap).
Evaluates the ±1 code at chip phase c over the chip-phase extent [c, c + adv) swept by one input sample (adv = code_rate / sps). Away from a chip transition this is just sign(code[floor(c)]). When the sample's extent straddles the boundary into the next chip, it returns the overlap-weighted blend of the two chip signs — frac of the sample lies in chip floor(c), 1 - frac in the next chip. Because the chips are ±1 and constant away from a transition, this is the exact matched-filter integral over a window whose edge falls at a fractional sample position: it makes the correlation (hence the E-L discriminator) vary continuously with sub-sample code phase instead of stepping in integer-sample quanta, with no loss of despread SNR (the chip interior is still fully integrated). The blend is the linear (trapezoidal) interpolant of the correlation; for ±1 chips no signal interpolation is needed — only the lone straddling sample is reweighted.
Parameters:
sDLL state (for the code and period length).cCode phase of the tap, chips, in [0, sf).advChip-phase advance per input sample (code_rate / sps).
Returns:
Blended ±1 replica value for this tap and sample.
function dll_reset¶
Re-seed the loop to its create-time code phase; keep config.
Parameters:
stateMust be non-NULL.
function dll_set_bn¶
function dll_set_state¶
function dll_state_bytes¶
function dll_steps¶
size_t dll_steps (
dll_state_t * state,
const float complex * x,
size_t x_len,
float complex * out,
size_t max_out
)
function dll_steps_max_out¶
function dll_update¶
Per-period code discriminator + loop update + phase wrap.
Runs the non-coherent early-minus-late envelope discriminator on the dumped accumulators, filters it, updates the code rate, and wraps the prompt phase to the next period (plus a proportional phase nudge). Call at a period boundary after reading the prompt; the caller resets the accumulators. Inline.
Parameters:
sDLL state. Must be non-NULL.
Macro Definition Documentation¶
define DLL_EPS¶
define DLL_STATE_MAGIC¶
define DLL_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/dll/dll_core.h