File carrier_mpsk_core.h¶
FileList > carrier_mpsk > carrier_mpsk_core.h
Go to the source code of this file
M-PSK carrier-tracking loop (integer-NCO de-rotation + decision PLL). More...
#include "clib_common.h"#include "dp_state.h"#include "jm_perf.h"#include "lo/lo_core.h"#include "loop_filter/loop_filter_core.h"#include "mpsk/mpsk_core.h"#include <math.h>
Classes¶
| Type | Name |
|---|---|
| struct | carrier_mpsk_state_t M-PSK carrier loop state. |
Public Functions¶
| Type | Name |
|---|---|
| void | carrier_mpsk_configure (carrier_mpsk_state_t * state, double bn, double zeta) |
| carrier_mpsk_state_t * | carrier_mpsk_create (double bn, double zeta, double init_norm_freq, size_t tsamps, double bn_fll, int m) Create an M-PSK carrier loop instance. |
| void | carrier_mpsk_destroy (carrier_mpsk_state_t * state) Destroy an M-PSK carrier loop instance and release all memory. |
| double | carrier_mpsk_get_bn (const carrier_mpsk_state_t * state) |
| double | carrier_mpsk_get_bn_fll (const carrier_mpsk_state_t * state) |
| double | carrier_mpsk_get_last_error (const carrier_mpsk_state_t * state) |
| double | carrier_mpsk_get_lock_metric (const carrier_mpsk_state_t * state) |
| int | carrier_mpsk_get_m (const carrier_mpsk_state_t * state) |
| double | carrier_mpsk_get_norm_freq (const carrier_mpsk_state_t * state) |
| void | carrier_mpsk_get_state (const carrier_mpsk_state_t * state, void * blob) Serialize the full loop state into blob . |
| void | carrier_mpsk_init (carrier_mpsk_state_t * s, double bn, double zeta, double init_norm_freq, size_t tsamps, double bn_fll, int m) Initialise an M-PSK carrier loop in place (no allocation). |
| void | carrier_mpsk_reset (carrier_mpsk_state_t * state) Re-seed the loop to its create-time frequency/phase; keep config. |
| void | carrier_mpsk_set_bn (carrier_mpsk_state_t * state, double val) |
| void | carrier_mpsk_set_bn_fll (carrier_mpsk_state_t * state, double val) |
| void | carrier_mpsk_set_norm_freq (carrier_mpsk_state_t * state, double val) |
| int | carrier_mpsk_set_state (carrier_mpsk_state_t * state, const void * blob) Restore state; DP_OK, or DP_ERR_INVALID if the envelope rejects. |
| size_t | carrier_mpsk_state_bytes (const carrier_mpsk_state_t * state) Serialized-state byte size. |
| size_t | carrier_mpsk_steps (carrier_mpsk_state_t * state, const float complex * x, size_t x_len, float complex * out, size_t max_out) |
| size_t | carrier_mpsk_steps_max_out (carrier_mpsk_state_t * state) |
| JM_FORCEINLINE JM_HOT void | carrier_mpsk_update (carrier_mpsk_state_t * s, float complex P) Per-symbol carrier update: decision discriminator -> loop -> NCO. |
| JM_FORCEINLINE JM_HOT float complex | carrier_mpsk_wipeoff (carrier_mpsk_state_t * s, float complex x) Per-sample carrier wipe-off: de-rotate x by the NCO, advance it. |
Macros¶
| Type | Name |
|---|---|
| define | CARRIER_MPSK_EPS 1e-12f |
| define | CARRIER_MPSK_LOCK_ALPHA 0.1 |
| define | CARRIER_MPSK_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc)('C', 'M', 'P', 'K') |
| define | CARRIER_MPSK_STATE_VERSION 1u |
Detailed Description¶
The M-ary generalization of the Costas loop (costas_core.h): per sample it de-rotates the input with the integer-phase lo NCO (carrier wipe-off); every tsamps samples it dumps the coherent integrate-and-dump prompt, runs a decision-directed M-PSK phase discriminator, filters the error through an embedded 2nd-order loop_filter_state_t, and steers the NCO frequency + phase. It tracks a small residual carrier (bulk Doppler is removed upstream by acquisition); the steering NCO is lo, so the phase is bounded and exactly reproducible.
The discriminator slices the prompt to the nearest constellation point ahat = mpsk_slice(P, m) and uses e = Im(P * conj(ahat)) / |P| (= sin of the phase error near lock). At m = 2 this reduces exactly to the BPSK Costas discriminator. An optional decision-directed cross-product FLL assist (bn_fll > 0) widens the frequency pull-in.
The loop locks to one of m phases — an M-fold ambiguity on absolute phase. Resolve it downstream with differential demapping (mpsk_diff_demap) or a sync word; this loop only recovers the carrier and emits the prompts.
The block API (carrier_mpsk_steps) is the Python face; the JM_FORCEINLINE carrier_mpsk_wipeoff()/carrier_mpsk_update() are the C composition API a receiver inlines into its own sample loop.
// QPSK carrier loop, 64 samples/symbol, FLL-assisted
carrier_mpsk_state_t *c = carrier_mpsk_create(0.05, 0.707, 0.0, 64, 0.01, 4);
float complex sym[16];
size_t k = carrier_mpsk_steps(c, rx, rx_len, sym, 16);
double f = c->nco.norm_freq; // tracked residual carrier
carrier_mpsk_destroy(c);
Public Functions Documentation¶
function carrier_mpsk_configure¶
function carrier_mpsk_create¶
Create an M-PSK carrier loop instance.
carrier_mpsk_state_t * carrier_mpsk_create (
double bn,
double zeta,
double init_norm_freq,
size_t tsamps,
double bn_fll,
int m
)
Parameters:
bnLoop noise bandwidth (default 0.05).zetaDamping factor (default 0.707).init_norm_freqSeed carrier frequency, cycles/sample (default 0.0).tsampsSamples per symbol (default 64).bn_fllFLL-assist bandwidth (default 0.0 = pure PLL).mConstellation order M, 2/4/8 (default 4 = QPSK).
Returns:
Heap-allocated state, or NULL on allocation failure.
Note:
Caller must call carrier_mpsk_destroy() when done.
function carrier_mpsk_destroy¶
Destroy an M-PSK carrier loop instance and release all memory.
Parameters:
stateMay be NULL.
function carrier_mpsk_get_bn¶
function carrier_mpsk_get_bn_fll¶
function carrier_mpsk_get_last_error¶
function carrier_mpsk_get_lock_metric¶
function carrier_mpsk_get_m¶
function carrier_mpsk_get_norm_freq¶
function carrier_mpsk_get_state¶
Serialize the full loop state into blob .
function carrier_mpsk_init¶
Initialise an M-PSK carrier loop in place (no allocation).
void carrier_mpsk_init (
carrier_mpsk_state_t * s,
double bn,
double zeta,
double init_norm_freq,
size_t tsamps,
double bn_fll,
int m
)
Seeds the NCO at init_norm_freq and the loop integrator to the matching per-symbol frequency so de-rotation is correct from the first sample.
Parameters:
sState to initialise. Must be non-NULL.bnLoop noise bandwidth, normalised to the symbol rate.zetaDamping factor (0.707 = critically damped).init_norm_freqSeed carrier frequency, cycles/sample.tsampsSamples per symbol (the integrate-and-dump period).bn_fllFLL-assist bandwidth (0 = pure PLL).mConstellation order M (2, 4, 8).
function carrier_mpsk_reset¶
Re-seed the loop to its create-time frequency/phase; keep config.
Parameters:
stateMust be non-NULL.
function carrier_mpsk_set_bn¶
function carrier_mpsk_set_bn_fll¶
function carrier_mpsk_set_norm_freq¶
function carrier_mpsk_set_state¶
Restore state; DP_OK, or DP_ERR_INVALID if the envelope rejects.
function carrier_mpsk_state_bytes¶
Serialized-state byte size.
function carrier_mpsk_steps¶
size_t carrier_mpsk_steps (
carrier_mpsk_state_t * state,
const float complex * x,
size_t x_len,
float complex * out,
size_t max_out
)
function carrier_mpsk_steps_max_out¶
function carrier_mpsk_update¶
Per-symbol carrier update: decision discriminator -> loop -> NCO.
Slices the prompt P to the nearest M-PSK point ahat, forms the decision-directed phase error e = Im(P conj(ahat)) / |P|, optionally runs a decision-directed cross-product FLL on the data-wiped prompts, filters, and steers the NCO frequency + a proportional phase nudge. Updates the lock metric (decision-aligned Re(P conj(ahat))/|P|) and last_error. Inline.
Parameters:
sCarrier loop state. Must be non-NULL.PThe dumped integrate-and-dump prompt for this symbol.
function carrier_mpsk_wipeoff¶
Per-sample carrier wipe-off: de-rotate x by the NCO, advance it.
JM_FORCEINLINE JM_HOT float complex carrier_mpsk_wipeoff (
carrier_mpsk_state_t * s,
float complex x
)
x * conj(lo_step(nco)) — strips the (tracked) carrier ahead of the matched-filter integrate-and-dump. Inline, zero call overhead.
Parameters:
sCarrier loop state. Must be non-NULL.xOne input sample.
Returns:
The de-rotated sample to feed the integrator.
Macro Definition Documentation¶
define CARRIER_MPSK_EPS¶
define CARRIER_MPSK_LOCK_ALPHA¶
define CARRIER_MPSK_STATE_MAGIC¶
define CARRIER_MPSK_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/carrier_mpsk/carrier_mpsk_core.h