Skip to content

File mpsk_receiver_core.h

FileList > inc > mpsk_receiver > mpsk_receiver_core.h

Go to the source code of this file

Pulse-shaped M-PSK receiver: NDA-acquired carrier + Gardner timing. More...

  • #include "carrier_nda/carrier_nda_core.h"
  • #include "clib_common.h"
  • #include "dp_state.h"
  • #include "fir/fir_core.h"
  • #include "jm_perf.h"
  • #include "mpsk/mpsk_core.h"
  • #include "symsync/symsync_core.h"
  • #include <complex.h>
  • #include "lo/lo_core.h"
  • #include "loop_filter/loop_filter_core.h"
  • #include "farrow/farrow_core.h"

Classes

Type Name
struct mpsk_receiver_state_t
M-PSK receiver state.

Public Types

Type Name
enum mpsk__receiver__core_8h_1adf764cbdea00d65edcd07bb9953ad2b7
Matched-filter pulse shape selector.

Public Functions

Type Name
size_t mpsk_receiver_bits (mpsk_receiver_state_t * state, const float complex * x, size_t x_len, uint8_t * out, size_t max_out)
Demodulate a cf32 block and emit hard Gray-coded bits.
size_t mpsk_receiver_bits_max_out (mpsk_receiver_state_t * state)
mpsk_receiver_state_t * mpsk_receiver_create (int m, size_t sps, int n, int pulse, double rrc_beta, int rrc_span, double bn_carrier, double zeta, double bn_timing, int auto_handover, double lock_thresh, double init_norm_freq, size_t warmup_syms, int differential)
Create an M-PSK receiver.
void mpsk_receiver_destroy (mpsk_receiver_state_t * state)
Destroy an M-PSK receiver and release all memory.
double mpsk_receiver_get_lock (const mpsk_receiver_state_t * state)
int mpsk_receiver_get_m (const mpsk_receiver_state_t * state)
int mpsk_receiver_get_n (const mpsk_receiver_state_t * state)
double mpsk_receiver_get_norm_freq (const mpsk_receiver_state_t * state)
size_t mpsk_receiver_get_sps (const mpsk_receiver_state_t * state)
void mpsk_receiver_get_state (const mpsk_receiver_state_t * state, void * blob)
double mpsk_receiver_get_timing_rate (const mpsk_receiver_state_t * state)
int mpsk_receiver_get_tracking (const mpsk_receiver_state_t * state)
void mpsk_receiver_reset (mpsk_receiver_state_t * state)
Re-seed the carrier/timing loops to their create-time state.
void mpsk_receiver_set_norm_freq (mpsk_receiver_state_t * state, double val)
int mpsk_receiver_set_state (mpsk_receiver_state_t * state, const void * blob)
size_t mpsk_receiver_state_bytes (const mpsk_receiver_state_t * state)
size_t mpsk_receiver_steps (mpsk_receiver_state_t * state, const float complex * x, size_t x_len, float complex * out, size_t max_out)
Demodulate a cf32 block and emit the recovered symbols.
size_t mpsk_receiver_steps_max_out (mpsk_receiver_state_t * state)

Macros

Type Name
define MPSK_RECEIVER_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('M','P','S','K')
define MPSK_RECEIVER_STATE_VERSION 1u

Detailed Description

A complete per-sample inline modem for a continuous (unspread) M-PSK signal. It composes the project's tracking primitives on one shared sample loop:

  • carrier_nda_state_t — per-sample carrier wipe-off with the integer NCO, plus a non-data-aided M-th-power discriminator on an I/Q arm integrate-and-dump (n dumps/symbol). This acquires the carrier with no symbol timing and no data present (cold start), which is what lets the receiver pull in before the matched filter / timing loop have settled.
  • a matched filter (fir_state_t, owned) on the de-rotated stream: either an integrate-and-dump boxcar (MPSK_RX_PULSE_IANDD, default) or a root-raised-cosine (MPSK_RX_PULSE_RRC) for band-limited links.
  • symsync_state_t — a carrier-blind Gardner symbol-timing loop on the matched-filter output, emitting one symbol per recovered symbol period.

Carrier recovery follows the project rule: predetection de-rotation (per-sample wipe, always) and postdetection discrimination. Two discriminators steer one shared NCO: * acquisition — the NDA M-th-power error, n times/symbol, with no data or timing required (tracking == 0). * tracking — once auto_handover is enabled and the loop has locked, a decision-directed error e = Im(y·conj(â))/|y| on the recovered symbols (lower jitter, naturally lower loop bandwidth at symbol rate). The same NCO/loop filter carries the frequency estimate across handover. Handover is opt-in (auto_handover, default off): by default the receiver stays in robust NDA tracking the whole time.

The loop locks to one of M phases — an M-fold ambiguity on absolute phase. Resolve it with differential demapping (bits(..., differential=1)) or a sync word downstream. A DSSS-MPSK receiver is Dll(segments) -> MpskReceiver: despread to symbol-rate soft chips, then this modem.

Lifecycle: mpsk_receiver_create -> [steps / bits / reset]* -> _destroy.

// QPSK, 8 samples/symbol, I&D matched filter, NDA acquisition
mpsk_receiver_state_t *rx = mpsk_receiver_create(
    4, 8, 4, MPSK_RX_PULSE_IANDD, 0.35, 8,
    0.01, 0.707, 0.01, 0, 0.5, 0.0, 100, 0);
float complex sym[256];
size_t k = mpsk_receiver_steps(rx, rx_in, rx_len, sym, 256);
double f = mpsk_receiver_get_norm_freq(rx);  // tracked residual carrier
mpsk_receiver_destroy(rx);

Public Types Documentation

enum mpsk__receiver__core_8h_1adf764cbdea00d65edcd07bb9953ad2b7

Matched-filter pulse shape selector.

enum mpsk__receiver__core_8h_1adf764cbdea00d65edcd07bb9953ad2b7 {
    MPSK_RX_PULSE_IANDD = 0,
    MPSK_RX_PULSE_RRC = 1
};


Public Functions Documentation

function mpsk_receiver_bits

Demodulate a cf32 block and emit hard Gray-coded bits.

size_t mpsk_receiver_bits (
    mpsk_receiver_state_t * state,
    const float complex * x,
    size_t x_len,
    uint8_t * out,
    size_t max_out
) 

Like mpsk_receiver_steps(), but each recovered symbol is sliced to its nearest M-PSK point and unpacked to log2(M) hard bits (LSB-first). With the differential option set at create time, the Gray label is taken from the phase difference between consecutive symbols (rotation-invariant — it resolves the M-fold carrier ambiguity), else from the absolute (coherent) decision.

Parameters:

  • state Receiver state. Must be non-NULL.
  • x Input cf32 samples.
  • x_len Number of input samples.
  • out Output bytes (0/1); caller provides max_out capacity.
  • max_out Output capacity.

Returns:

Number of bits written.


function mpsk_receiver_bits_max_out

size_t mpsk_receiver_bits_max_out (
    mpsk_receiver_state_t * state
) 

function mpsk_receiver_create

Create an M-PSK receiver.

mpsk_receiver_state_t * mpsk_receiver_create (
    int m,
    size_t sps,
    int n,
    int pulse,
    double rrc_beta,
    int rrc_span,
    double bn_carrier,
    double zeta,
    double bn_timing,
    int auto_handover,
    double lock_thresh,
    double init_norm_freq,
    size_t warmup_syms,
    int differential
) 

Parameters:

  • m Constellation order M, 2/4/8 (default 4 = QPSK).
  • sps Samples per symbol (default 8).
  • n Carrier arm dumps per symbol (default 4; sps % n == 0).
  • pulse Matched-filter shape (default MPSK_RX_PULSE_IANDD).
  • rrc_beta RRC roll-off in [0, 1] (default 0.35; RRC only).
  • rrc_span RRC one-sided span in symbols (default 8; RRC only).
  • bn_carrier Carrier loop noise bandwidth (default 0.01).
  • zeta Damping factor for both loops (default 0.707).
  • bn_timing Symbol-timing loop noise bandwidth (default 0.01).
  • auto_handover Enable NDA->decision-directed handover (default 0).
  • lock_thresh Lock metric required for handover (default 0.5).
  • init_norm_freq Seed carrier frequency, cycles/sample (default 0.0).
  • warmup_syms Symbols before handover is allowed (default 100).
  • differential bits(): differential (rotation-invariant) demap (default 0 = coherent).

Returns:

Heap-allocated state, or NULL on invalid args / allocation failure.

Note:

Caller must call mpsk_receiver_destroy() when done.


function mpsk_receiver_destroy

Destroy an M-PSK receiver and release all memory.

void mpsk_receiver_destroy (
    mpsk_receiver_state_t * state
) 

Parameters:

  • state May be NULL.

function mpsk_receiver_get_lock

double mpsk_receiver_get_lock (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_m

int mpsk_receiver_get_m (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_n

int mpsk_receiver_get_n (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_norm_freq

double mpsk_receiver_get_norm_freq (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_sps

size_t mpsk_receiver_get_sps (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_state

void mpsk_receiver_get_state (
    const mpsk_receiver_state_t * state,
    void * blob
) 

function mpsk_receiver_get_timing_rate

double mpsk_receiver_get_timing_rate (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_get_tracking

int mpsk_receiver_get_tracking (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_reset

Re-seed the carrier/timing loops to their create-time state.

void mpsk_receiver_reset (
    mpsk_receiver_state_t * state
) 

Parameters:

  • state Must be non-NULL.

function mpsk_receiver_set_norm_freq

void mpsk_receiver_set_norm_freq (
    mpsk_receiver_state_t * state,
    double val
) 

function mpsk_receiver_set_state

int mpsk_receiver_set_state (
    mpsk_receiver_state_t * state,
    const void * blob
) 

function mpsk_receiver_state_bytes

size_t mpsk_receiver_state_bytes (
    const mpsk_receiver_state_t * state
) 

function mpsk_receiver_steps

Demodulate a cf32 block and emit the recovered symbols.

size_t mpsk_receiver_steps (
    mpsk_receiver_state_t * state,
    const float complex * x,
    size_t x_len,
    float complex * out,
    size_t max_out
) 

Runs the per-sample loop (carrier wipe-off + NDA arm + matched filter + Gardner timing) over x and writes one cf32 symbol per recovered symbol period. Fewer outputs than inputs (~ x_len / sps). Read norm_freq for the tracked carrier and lock for the carrier lock metric.

Parameters:

  • state Receiver state. Must be non-NULL.
  • x Input cf32 samples.
  • x_len Number of input samples.
  • out Output symbols; caller provides max_out capacity.
  • max_out Output capacity.

Returns:

Number of symbols written.


function mpsk_receiver_steps_max_out

size_t mpsk_receiver_steps_max_out (
    mpsk_receiver_state_t * state
) 

Macro Definition Documentation

define MPSK_RECEIVER_STATE_MAGIC

#define MPSK_RECEIVER_STATE_MAGIC `DP_FOURCC ('M','P','S','K')`

define MPSK_RECEIVER_STATE_VERSION

#define MPSK_RECEIVER_STATE_VERSION `1u`


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