Skip to content

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.

JM_FORCEINLINE  JM_HOT void dll_accumulate (
    dll_state_t * s,
    float complex d
) 

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:

  • s DLL state. Must be non-NULL.
  • d One carrier-wiped input sample.

function dll_chip_sign

JM_FORCEINLINE float dll_chip_sign (
    uint8_t c
) 

0/1 chip -> +1/-1 BPSK sign.


function dll_configure

void dll_configure (
    dll_state_t * state,
    double bn,
    double zeta
) 

function dll_configure_lock

Configure the always-on code-lock detector.

void dll_configure_lock (
    dll_state_t * state,
    double threshold,
    size_t n_looks,
    double alpha
) 

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:

  • state DLL state. Must be non-NULL.
  • threshold CFAR threshold eta on the statistic R.
  • n_looks Non-coherent integration depth N (looks); clamped to >= 1.
  • alpha EMA 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:

  • code Spreading code (0/1 chips), one period; copied internally.
  • code_len Code length (chips per period).
  • sps Samples per chip (default 2).
  • init_chip Seed code phase, chips (default 0.0).
  • bn Loop noise bandwidth (default 0.01).
  • zeta Damping factor (default 0.707).
  • spacing Early/late tap offset, chips (default 0.5).
  • segments Partial 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).

void dll_destroy (
    dll_state_t * state
) 

Parameters:

  • state May be NULL.

function dll_get_bn

double dll_get_bn (
    const dll_state_t * state
) 

function dll_get_code_phase

double dll_get_code_phase (
    const dll_state_t * state
) 

function dll_get_code_rate

double dll_get_code_rate (
    const dll_state_t * state
) 

function dll_get_last_error

double dll_get_last_error (
    const dll_state_t * state
) 

function dll_get_lock_stat

Last lock test statistic R (compare against the configured eta).

double dll_get_lock_stat (
    const dll_state_t * state
) 


function dll_get_locked

Last lock decision (1 = locked, 0 = not).

int dll_get_locked (
    const dll_state_t * state
) 


function dll_get_noise_est

Current CFAR noise-power estimate E|O|^2 (offset-tap EMA).

double dll_get_noise_est (
    const dll_state_t * state
) 


function dll_get_segments

size_t dll_get_segments (
    const dll_state_t * state
) 

function dll_get_state

void dll_get_state (
    const dll_state_t * state,
    void * blob
) 

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:

  • s State to initialise. Must be non-NULL.
  • code Spreading code (0/1 chips), one period; borrowed.
  • code_len Code length (chips per period); must be >= 1.
  • sps Samples per chip.
  • init_chip Seed code phase, chips.
  • bn Loop noise bandwidth, normalised to the code-period rate.
  • zeta Damping factor (0.707 = critically damped).
  • spacing Early/late tap offset, chips (0.5 = half-chip).

function dll_replica

Sub-chip code replica at fractional code phase c (one tap).

JM_FORCEINLINE float dll_replica (
    const dll_state_t * s,
    double c,
    double adv
) 

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:

  • s DLL state (for the code and period length).
  • c Code phase of the tap, chips, in [0, sf).
  • adv Chip-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.

void dll_reset (
    dll_state_t * state
) 

Parameters:

  • state Must be non-NULL.

function dll_set_bn

void dll_set_bn (
    dll_state_t * state,
    double val
) 

function dll_set_state

int dll_set_state (
    dll_state_t * state,
    const void * blob
) 

function dll_state_bytes

size_t dll_state_bytes (
    const dll_state_t * state
) 

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

size_t dll_steps_max_out (
    dll_state_t * state
) 

function dll_update

Per-period code discriminator + loop update + phase wrap.

JM_FORCEINLINE  JM_HOT void dll_update (
    dll_state_t * s
) 

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:

  • s DLL state. Must be non-NULL.

Macro Definition Documentation

define DLL_EPS

#define DLL_EPS `1e-12`

define DLL_STATE_MAGIC

#define DLL_STATE_MAGIC `DP_FOURCC ('D','L','L',' ')`

define DLL_STATE_VERSION

#define DLL_STATE_VERSION `1u`


The documentation for this class was generated from the following file native/inc/dll/dll_core.h