Skip to content

File doppler_channel_core.h

File List > doppler_channel > doppler_channel_core.h

Go to the documentation of this file

#ifndef DOPPLER_CHANNEL_CORE_H
#define DOPPLER_CHANNEL_CORE_H

#include "clib_common.h"
#include "dp_state.h"
#include "jm_perf.h"
#include "resamp/resamp_core.h"
#ifdef __cplusplus
extern "C" {
#endif

#define DOPPLER_CHANNEL_STATE_MAGIC DP_FOURCC('D', 'P', 'C', 'H')
#define DOPPLER_CHANNEL_STATE_VERSION 1u

#define DOPPLER_CHANNEL_MAX_BLOCK 65536u

typedef struct {
    double fs;                 /* receive sample rate, Hz                  */
    double carrier_hz;         /* RF carrier fc, Hz — drives the offset    */
    double doppler_ppm;        /* d0, ppm of nominal                       */
    double doppler_rate_ppm_s; /* d-dot, ppm/s                             */

    resamp_state_t *rs; /* the dilation — never hand-rolled here     */

    /* Two separate clocks, on purpose. The resampler's per-sample rate
       deviation is indexed by INPUT sample; the carrier phase is a function of
       receive time, which is the OUTPUT sample index. They differ by the
       dilation itself, so conflating them would fold a second copy of the
       Doppler into the carrier. */
    uint64_t n_in;  /* input samples consumed                    */
    uint64_t n_out; /* output samples produced                   */

    double *ctrl;         /* per-sample rate deviation scratch         */
    size_t ctrl_cap;
} doppler_channel_state_t;

static inline double
doppler_channel_excess(const doppler_channel_state_t *s, double t)
{
    return (s->doppler_ppm * t + 0.5 * s->doppler_rate_ppm_s * t * t) * 1e-6;
}

static inline double
doppler_channel_scale(const doppler_channel_state_t *s, double t)
{
    return 1.0 + (s->doppler_ppm + s->doppler_rate_ppm_s * t) * 1e-6;
}

static inline double
doppler_channel_phase(const doppler_channel_state_t *s, double t)
{
    return s->carrier_hz * doppler_channel_excess(s, t);
}

doppler_channel_state_t *doppler_channel_create(double fs, double carrier_hz, double doppler_ppm, double doppler_rate_ppm_s);

void doppler_channel_destroy(doppler_channel_state_t *state);

void doppler_channel_reset(doppler_channel_state_t *state);

size_t doppler_channel_state_bytes(const doppler_channel_state_t *state);

void doppler_channel_get_state(const doppler_channel_state_t *state, void *blob);

int doppler_channel_set_state(doppler_channel_state_t *state, const void *blob);

size_t doppler_channel_execute_max_out(doppler_channel_state_t *state);

size_t doppler_channel_execute(doppler_channel_state_t *state, const float _Complex *x, size_t x_len, float _Complex *out, size_t max_out);

double doppler_channel_get_elapsed_s(const doppler_channel_state_t *state);

double doppler_channel_get_offset_hz(const doppler_channel_state_t *state);

double doppler_channel_get_delay_samples(const doppler_channel_state_t *state);
#ifdef __cplusplus
}
#endif

#endif /* DOPPLER_CHANNEL_CORE_H */