File dll_core.h¶
File List > dll > dll_core.h
Go to the documentation of this file
#ifndef DLL_CORE_H
#define DLL_CORE_H
#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"
#ifdef __cplusplus
extern "C" {
#endif
/* Numerical guard on the early+late envelope sum (not tunable). */
#define DLL_EPS 1e-12
typedef struct {
loop_filter_state_t lf;
const uint8_t *code;
size_t sf;
size_t sps;
double inv_sps;
double spacing;
double chip_pos;
double code_rate;
double seed_chip;
double bn;
double zeta;
float complex acc_e;
float complex acc_p;
float complex acc_l;
double last_error;
size_t segments;
double seg_chips;
double seg_norm;
size_t seg_idx;
double sum_e;
double sum_l;
/* ── lock detector (always on): offset-tap CFAR noise ref + N-look test */
float complex acc_o;
double off_chips;
double noise_guard;
uint32_t rng;
double noise_ema;
double lock_alpha;
double lock_sum;
size_t lock_count;
size_t n_looks;
double lock_thresh;
double lock_stat;
size_t lock_nz;
int locked;
int owns_code;
} dll_state_t;
JM_FORCEINLINE float
dll_chip_sign(uint8_t c)
{
return (c & 1u) ? -1.0f : 1.0f;
}
JM_FORCEINLINE float
dll_replica(const dll_state_t *s, double c, double adv)
{
size_t i = (size_t)c;
if (i >= s->sf)
i = s->sf - 1;
/* Distance from this sample to the next chip boundary. When it is at least
one sample (adv), no transition falls inside the sample and the replica
is a clean single chip sign — the common path, no divide. */
double rem = (double)(i + 1) - c;
if (rem >= adv)
return dll_chip_sign(s->code[i]);
/* Rare: the sample straddles the boundary; blend by the in-chip fraction. */
double frac = rem / adv;
size_t j = (i + 1 >= s->sf) ? 0 : i + 1; /* next chip, wraps the period */
return (float)(frac * dll_chip_sign(s->code[i])
+ (1.0 - frac) * dll_chip_sign(s->code[j]));
}
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);
JM_FORCEINLINE JM_HOT void
dll_accumulate(dll_state_t *s, float complex d)
{
double adv = s->code_rate * s->inv_sps;
double cp = s->chip_pos;
double sfd = (double)s->sf;
double ce = cp + s->spacing;
if (ce >= sfd)
ce -= sfd;
double cl = cp - s->spacing;
if (cl < 0.0)
cl += sfd;
/* Fractional-boundary integrate-and-dump: each tap's replica blends across a
chip transition that falls inside the sample (dll_replica), so the E/P/L
correlations vary continuously with sub-sample code phase. */
s->acc_p += d * dll_replica(s, cp, adv);
s->acc_e += d * dll_replica(s, ce, adv);
s->acc_l += d * dll_replica(s, cl, adv);
s->chip_pos += adv;
}
JM_FORCEINLINE JM_HOT void
dll_update(dll_state_t *s)
{
float me = cabsf(s->acc_e), ml = cabsf(s->acc_l);
double e = (double)(me - ml) / ((double)(me + ml) + DLL_EPS);
s->last_error = e;
loop_filter_step(&s->lf, e);
s->code_rate = 1.0 + s->lf.integ;
s->chip_pos -= (double)s->sf;
s->chip_pos += s->lf.kp * e; /* proportional phase nudge, chips */
}
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);
void dll_destroy(dll_state_t *state);
void dll_reset(dll_state_t *state);
size_t dll_steps_max_out(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);
void dll_configure(dll_state_t *state, double bn, double zeta);
double dll_get_bn(const dll_state_t *state);
void dll_set_bn(dll_state_t *state, double val);
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);
size_t dll_get_segments(const dll_state_t *state);
void dll_configure_lock(dll_state_t *state, double threshold, size_t n_looks,
double alpha);
int dll_get_locked(const dll_state_t *state);
double dll_get_lock_stat(const dll_state_t *state);
double dll_get_noise_est(const dll_state_t *state);
/* ── Serializable state (standard bytes interface; see dp_state.h) ──────────
* composition+field-wise: loop_filter child (POD-embedded) + running
* correlators/loop/lock state; borrowed `code` pointer restored by create. */
#define DLL_STATE_MAGIC DP_FOURCC ('D','L','L',' ')
#define DLL_STATE_VERSION 1u
size_t dll_state_bytes (const dll_state_t *state);
void dll_get_state (const dll_state_t *state, void *blob);
int dll_set_state (dll_state_t *state, const void *blob);
#ifdef __cplusplus
}
#endif
#endif /* DLL_CORE_H */