File symsync_core.h¶
File List > inc > symsync > symsync_core.h
Go to the documentation of this file
#ifndef SYMSYNC_CORE_H
#define SYMSYNC_CORE_H
#include "clib_common.h"
#include "dp_state.h"
#include "farrow/farrow_core.h"
#include "jm_perf.h"
#include "loop_filter/loop_filter_core.h"
#include "nco/nco_core.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
nco_state_t timing;
farrow_state_t farrow;
loop_filter_state_t lf;
size_t sps;
uint32_t base_inc;
int have_ontime;
float complex prev_ontime;
float complex mid;
double bn;
double zeta;
double last_error;
double rate_est;
double pwr_avg;
} symsync_state_t;
JM_FORCEINLINE JM_HOT int
symsync_step (symsync_state_t *s, float complex x, float complex *y_out)
{
const uint32_t HALF = 0x80000000u;
farrow_push (&s->farrow, x);
uint32_t old = s->timing.phase;
uint64_t sum = (uint64_t)old + s->timing.phase_inc;
s->timing.phase = (uint32_t)sum;
int wrapped = sum >> 32 != 0;
int mid_evt = !wrapped && old < HALF && (uint32_t)sum >= HALF;
if (!wrapped && !mid_evt)
return 0;
double inc = (double)s->timing.phase_inc;
if (mid_evt)
{
float mu = (float)(1.0 - ((double)((uint32_t)sum - HALF)) / inc);
s->mid = farrow_eval (&s->farrow, mu);
return 0;
}
float mu = (float)(1.0 - (double)s->timing.phase / inc);
float complex y = farrow_eval (&s->farrow, mu);
int emit = 0;
if (s->have_ontime)
{
float complex diff = y - s->prev_ontime;
double num = (double)(crealf (s->mid) * crealf (diff)
+ cimagf (s->mid) * cimagf (diff));
double inst_pwr
= (double)(crealf (y) * crealf (y) + cimagf (y) * cimagf (y));
s->pwr_avg += 0.01 * (inst_pwr - s->pwr_avg);
double e = num / (s->pwr_avg + 1e-6);
s->last_error = e;
double control = loop_filter_step (&s->lf, e);
s->timing.phase_inc
= (uint32_t)((double)s->base_inc * (1.0 + control));
double inst = (double)s->sps / (1.0 + control);
double lo_r = 0.5 * (double)s->sps, hi_r = 1.5 * (double)s->sps;
if (inst < lo_r)
inst = lo_r;
else if (inst > hi_r)
inst = hi_r;
s->rate_est += 0.02 * (inst - s->rate_est);
*y_out = y;
emit = 1;
}
else
s->have_ontime = 1;
s->prev_ontime = y;
return emit;
}
void symsync_init (symsync_state_t *s, size_t sps, double bn, double zeta,
int order);
symsync_state_t *symsync_create (size_t sps, double bn, double zeta,
int order);
void symsync_destroy (symsync_state_t *state);
void symsync_reset (symsync_state_t *state);
size_t symsync_steps_max_out (symsync_state_t *state);
size_t symsync_steps (symsync_state_t *state, const float complex *x,
size_t x_len, float complex *out, size_t max_out);
void symsync_configure (symsync_state_t *state, double bn, double zeta);
double symsync_get_bn (const symsync_state_t *state);
void symsync_set_bn (symsync_state_t *state, double val);
double symsync_get_timing_error (const symsync_state_t *state);
double symsync_get_rate (const symsync_state_t *state);
/* ── Serializable state (standard bytes interface; see dp_state.h) ──────────
* pointer-free composition: nco + farrow + loop_filter embedded by value
* (all POD) + scalar timing state — a whole-struct snapshot. */
#define SYMSYNC_STATE_MAGIC DP_FOURCC ('S','Y','N','C')
#define SYMSYNC_STATE_VERSION 1u
size_t symsync_state_bytes (const symsync_state_t *state);
void symsync_get_state (const symsync_state_t *state, void *blob);
int symsync_set_state (symsync_state_t *state, const void *blob);
#ifdef __cplusplus
}
#endif
#endif /* SYMSYNC_CORE_H */