Skip to content

File wfm_core.h

FileList > inc > wfm > wfm_core.h

Go to the source code of this file

Wfmgen module — public C API.

  • #include "clib_common.h"

Public Functions

Type Name
void bpsk_map (const uint8_t * bits, size_t bits_len, float _Complex * out)
Map binary bits {0, 1} to BPSK constellation symbols (cf32). The mapping is: 0 -> +1 + 0j, 1 -> -1 + 0j. Output is unit-power (each symbol has magnitude 1). The imaginary component is always zero. Typically used before a carrier multiply and noise addition to build a BPSK burst without the full Synth engine.
uint16_t crc16 (const uint8_t * bits, size_t bits_len)
CRC-16-CCITT (poly 0x1021, init 0xFFFF) over a bit stream, MSB-first. The one frame CRC doppler's DSSS burst convention uses: the dsss waveform appends it over the payload bits on transmit andBurstDemod validates it asframe_valid on receive (both call the same C kernel,dp_crc16.h ). Each input byte carries one bit (0/1) in its LSB — an unpacked bit array, not a packed byte-stream CRC. Transmit the result MSB-first.
void dsss_spread (const float _Complex * syms, size_t syms_len, const uint8_t * code, size_t code_len, int sf, float _Complex * out)
uint64_t mls_poly (uint32_t n)
Maximal-length-sequence primitive polynomial for a length- n LFSR. Returns the tap mask (in the same bit convention the synth/PN engine uses forpn_poly = 0 ) that drives ann-stage Fibonacci LFSR through its full 2^n - 1 state period. Thin public alias over the synth engine's MLS table; valid forn in 2..64 and returns 0 otherwise.
void qpsk_map (const uint8_t * syms, size_t syms_len, float _Complex * out)
Map QPSK symbol indices {0, 1, 2, 3} to Gray-coded symbols (cf32). Gray coding: adjacent indices differ in exactly one bit, minimising BER at low SNR. Bit 0 (LSB) controls I, bit 1 controls Q: I = (1 - 2*b_i) / sqrt(2), Q = (1 - 2*b_q) / sqrt(2). Output is unit-power (|sym| = 1.0 exactly). The four constellation points lie at the cardinal diagonals of the IQ plane.
void rc_h (const double * t, size_t t_len, double * out, double beta)
void rrc_h (const double * t, size_t t_len, double * out, double beta)
void rrc_taps (double beta, int sps, int span, float * out)
float wfm_awgn_amplitude (float snr_db, float signal_power)
Compute the per-component AWGN amplitude for a target SNR. The AWGN engine uses equal-power I and Q noise: complex noise power is 2 * amplitude². This function inverts that relationship for a given signal_power andsnr_db (measured over the full sample-rate bandwidth): amplitude = sqrt(signal_power / (2 * 10^(snr_db / 10))). Pass the result directly toawgn_create to get the exact noise level that corresponds to the requested SNR.
float wfm_ebno_to_snr_db (float ebno_db, int bits_per_symbol, float samples_per_symbol)
Convert Eb/No (dB) to SNR (dB) over the full sample-rate band. Digital communication systems are typically specified in Eb/No; doppler uses an fs-band SNR internally. The conversion is: SNR_fs = Eb/No + 10 log10(bits_per_symbol) - 10 log10(samples_per_symbol) For BPSK (bits_per_symbol=1, sps=8) at Eb/No=10 dB this gives ~0.97 dB. For QPSK (bits_per_symbol=2, sps=8) at Eb/No=10 dB this gives ~3.98 dB.

Public Functions Documentation

function bpsk_map

Map binary bits {0, 1} to BPSK constellation symbols (cf32). The mapping is: 0 -> +1 + 0j, 1 -> -1 + 0j. Output is unit-power (each symbol has magnitude 1). The imaginary component is always zero. Typically used before a carrier multiply and noise addition to build a BPSK burst without the full Synth engine.

void bpsk_map (
    const uint8_t * bits,
    size_t bits_len,
    float _Complex * out
) 

Parameters:

  • bits Array of uint8 values; only the LSB of each byte is used.
  • bits_len Number of elements in bits.
  • out Output buffer of at least bits_len cf32 elements.
    >>> from doppler.wfm import bpsk_map
    >>> import numpy as np
    >>> bits = np.array([0, 1, 0, 1], dtype=np.uint8)
    >>> bpsk_map(bits).tolist()
    [(1+0j), (-1+0j), (1+0j), (-1+0j)]
    

function crc16

CRC-16-CCITT (poly 0x1021, init 0xFFFF) over a bit stream, MSB-first. The one frame CRC doppler's DSSS burst convention uses: the dsss waveform appends it over the payload bits on transmit andBurstDemod validates it asframe_valid on receive (both call the same C kernel,dp_crc16.h ). Each input byte carries one bit (0/1) in its LSB — an unpacked bit array, not a packed byte-stream CRC. Transmit the result MSB-first.

uint16_t crc16 (
    const uint8_t * bits,
    size_t bits_len
) 

Parameters:

  • bits Array of 0/1 bit values (one per byte).
  • bits_len Number of bits in bits.

Returns:

The 16-bit CRC.

>>> import numpy as np
>>> from doppler.wfm import crc16
>>> ascii_bits = np.unpackbits(np.frombuffer(b"123456789", np.uint8))
>>> hex(crc16(ascii_bits))   # the standard CCITT check vector
'0x29b1'


function dsss_spread

void dsss_spread (
    const float _Complex * syms,
    size_t syms_len,
    const uint8_t * code,
    size_t code_len,
    int sf,
    float _Complex * out
) 

function mls_poly

Maximal-length-sequence primitive polynomial for a length- n LFSR. Returns the tap mask (in the same bit convention the synth/PN engine uses forpn_poly = 0 ) that drives ann-stage Fibonacci LFSR through its full 2^n - 1 state period. Thin public alias over the synth engine's MLS table; valid forn in 2..64 and returns 0 otherwise.

uint64_t mls_poly (
    uint32_t n
) 

Parameters:

  • n LFSR length in stages (2..64).

Returns:

Primitive-polynomial tap mask, or 0 if n is out of range.

>>> from doppler.wfm import mls_poly
>>> hex(mls_poly(7))
'0x41'


function qpsk_map

Map QPSK symbol indices {0, 1, 2, 3} to Gray-coded symbols (cf32). Gray coding: adjacent indices differ in exactly one bit, minimising BER at low SNR. Bit 0 (LSB) controls I, bit 1 controls Q: I = (1 - 2*b_i) / sqrt(2), Q = (1 - 2*b_q) / sqrt(2). Output is unit-power (|sym| = 1.0 exactly). The four constellation points lie at the cardinal diagonals of the IQ plane.

void qpsk_map (
    const uint8_t * syms,
    size_t syms_len,
    float _Complex * out
) 

Parameters:

  • syms Array of uint8 symbol indices; values must be in {0,1,2,3}. Bits above position 1 are ignored.
  • syms_len Number of elements in syms.
  • out Output buffer of at least syms_len cf32 elements.
    >>> from doppler.wfm import qpsk_map
    >>> import numpy as np
    >>> idx = np.array([0, 1, 2, 3], dtype=np.uint8)
    >>> out = qpsk_map(idx)
    >>> [round(float(v.real), 4) for v in out]
    [0.7071, -0.7071, 0.7071, -0.7071]
    >>> [round(float(v.imag), 4) for v in out]
    [0.7071, 0.7071, -0.7071, -0.7071]
    

function rc_h

void rc_h (
    const double * t,
    size_t t_len,
    double * out,
    double beta
) 

function rrc_h

void rrc_h (
    const double * t,
    size_t t_len,
    double * out,
    double beta
) 

function rrc_taps

void rrc_taps (
    double beta,
    int sps,
    int span,
    float * out
) 

function wfm_awgn_amplitude

Compute the per-component AWGN amplitude for a target SNR. The AWGN engine uses equal-power I and Q noise: complex noise power is 2 * amplitude². This function inverts that relationship for a given signal_power andsnr_db (measured over the full sample-rate bandwidth): amplitude = sqrt(signal_power / (2 * 10^(snr_db / 10))). Pass the result directly toawgn_create to get the exact noise level that corresponds to the requested SNR.

float wfm_awgn_amplitude (
    float snr_db,
    float signal_power
) 

Parameters:

  • snr_db Target SNR in dB, referenced to the full sample rate.
  • signal_power RMS power of the signal (e.g. 1.0 for unit-power complex tones or unit-energy BPSK/QPSK symbols).

Returns:

Per-component AWGN amplitude (sigma for one I or Q channel).

>>> from doppler.wfm import wfm_awgn_amplitude
>>> round(float(wfm_awgn_amplitude(10.0, 1.0)), 6)
0.223607
>>> round(float(wfm_awgn_amplitude(0.0, 1.0)), 6)
0.707107


function wfm_ebno_to_snr_db

Convert Eb/No (dB) to SNR (dB) over the full sample-rate band. Digital communication systems are typically specified in Eb/No; doppler uses an fs-band SNR internally. The conversion is: SNR_fs = Eb/No + 10 log10(bits_per_symbol) - 10 log10(samples_per_symbol) For BPSK (bits_per_symbol=1, sps=8) at Eb/No=10 dB this gives ~0.97 dB. For QPSK (bits_per_symbol=2, sps=8) at Eb/No=10 dB this gives ~3.98 dB.

float wfm_ebno_to_snr_db (
    float ebno_db,
    int bits_per_symbol,
    float samples_per_symbol
) 

Parameters:

  • ebno_db Eb/No in dB (energy per bit over noise spectral density).
  • bits_per_symbol Bits carried per modulation symbol: 1 for BPSK, 2 for QPSK.
  • samples_per_symbol Oversampling ratio (sps), e.g. 8.0.

Returns:

SNR in dB measured over the full sample-rate bandwidth.

>>> from doppler.wfm import wfm_ebno_to_snr_db
>>> round(float(wfm_ebno_to_snr_db(10.0, 2, 8.0)), 4)
3.9794
>>> round(float(wfm_ebno_to_snr_db(10.0, 1, 8.0)), 4)
0.9691



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