Skip to content

File dsss_receiver_core.h

FileList > doppler > dsss_receiver > dsss_receiver_core.h

Go to the source code of this file

Composed continuous DSSS receiver: Acquisition -> Costas(bn_fll) pre-despread carrier wipeoff -> Dll(segments) -> RateConverter -> MpskReceiver, one object. More...

  • #include "doppler/RateConverter/RateConverter_core.h"
  • #include "doppler/acq/acq_core.h"
  • #include "doppler/cic/cic_core.h"
  • #include "doppler/dll/dll_core.h"
  • #include "doppler/dp_state.h"
  • #include "doppler/hbdecim/hbdecim_core.h"
  • #include "doppler/mpsk_receiver/mpsk_receiver_core.h"
  • #include "doppler/resamp/resamp_core.h"
  • #include "doppler/resample/resample_core.h"
  • #include "doppler/dp_complex.h"
  • #include <stddef.h>
  • #include "doppler/costas/costas_core.h"
  • #include "doppler/snr/snr_core.h"
  • #include "doppler/ber/ber_core.h"

Classes

Type Name
struct dp_dsss_receiver_state_t
Composed receiver state.
struct dsss_receiver_extra_t

Public Functions

Type Name
int dp_dsss_receiver_configure_chain_raw (dp_dsss_receiver_state_t * state, size_t segments, size_t sps, int n)
Pin the despread/resample/demod grid directly, bypassing the create-time segments /sps defaults.
void dp_dsss_receiver_configure_lock_raw (dp_dsss_receiver_state_t * state, double up_thresh, double down_thresh, size_t n_looks, double alpha, uint32_t n_up, uint32_t n_down)
Re-tune the embedded Dll's code-lock detector directly. Forwards to dp_dll_configure_lock_raw() . Only meaningful once tracking has begun (dll is NULL before then); a no-op while searching. The detector is the hysteretic lockdet over the DLL's per-N-look CFAR statistic —up_thresh /down_thresh set the declare/drop levels andn_up /n_down the consecutive-look verify counts, trading declare latency against false-alarm rate.
int dp_dsss_receiver_configure_search_raw (dp_dsss_receiver_state_t * state, size_t doppler_bins, size_t n_noncoh)
Pin the embedded Acquisition's search grid directly. Forwards to dp_acq_configure_search_raw() — the escape hatch under this object's ownsymbol_rate -driven auto-sizing, for a power user who wants a specific(doppler_bins, n_noncoh) instead. Only meaningful while searching (a no-op has already happened once tracking has begun; the acquisition search doesn't run again until the nextreset() ).
dp_dsss_receiver_state_t * dp_dsss_receiver_create (const uint8_t * code, size_t code_len, double chip_rate, double symbol_rate, size_t spc, int m, double cn0_dbhz, double pfa, double pd, double doppler_uncertainty, size_t segments, size_t sps, int differential)
Create a DSSS receiver in the searching state.
void dp_dsss_receiver_destroy (dp_dsss_receiver_state_t * state)
Destroy a receiver and release all four children.
double dp_dsss_receiver_get_chip_phase (const dp_dsss_receiver_state_t * state)
Dll's live tracked code phase (chips); 0.0 while searching.
double dp_dsss_receiver_get_cn0_dbhz_est (const dp_dsss_receiver_state_t * state)
double dp_dsss_receiver_get_code_rate (const dp_dsss_receiver_state_t * state)
Dll's own tracking-quality indicator; 1.0 while searching.
double dp_dsss_receiver_get_doppler_hz (const dp_dsss_receiver_state_t * state)
double dp_dsss_receiver_get_lock (const dp_dsss_receiver_state_t * state)
MpskReceiver's carrier lock EMA; 0.0 while searching.
int dp_dsss_receiver_get_n (const dp_dsss_receiver_state_t * state)
double dp_dsss_receiver_get_norm_freq (const dp_dsss_receiver_state_t * state)
MpskReceiver's tracked carrier frequency; 0.0 while searching.
size_t dp_dsss_receiver_get_segments (const dp_dsss_receiver_state_t * state)
size_t dp_dsss_receiver_get_sps (const dp_dsss_receiver_state_t * state)
void dp_dsss_receiver_get_state (const dp_dsss_receiver_state_t * state, void * blob)
int dp_dsss_receiver_get_tracking (const dp_dsss_receiver_state_t * state)
void dp_dsss_receiver_reset (dp_dsss_receiver_state_t * state)
Return to the searching state. Resets the embedded Acquisition and frees dll /rc /rx (rebuilt from scratch on the next hit) — a receiver that has locked cannot be "reset back to tracking the same signal," only back to searching, matching every other object's reset() semantics in this codebase.
int dp_dsss_receiver_set_state (dp_dsss_receiver_state_t * state, const void * blob)
size_t dp_dsss_receiver_state_bytes (const dp_dsss_receiver_state_t * state)
size_t dp_dsss_receiver_steps (dp_dsss_receiver_state_t * state, const float _Complex * x, size_t x_len, float _Complex * out, size_t max_out)
Stream raw cf32 samples; emit demodulated symbols once locked.
size_t dp_dsss_receiver_steps_max_out (dp_dsss_receiver_state_t * state)

Macros

Type Name
define DSSS_RECEIVER_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('D', 'S', 'R', 'X')
define DSSS_RECEIVER_STATE_VERSION /* multi line expression */
define DSSS_RX_BN_CARRIER 0.01
define DSSS_RX_BN_FLL 0.03

Detailed Description

The single-object form of the chain validated across this repo's "continuous async-DSSS receiver" story (docs/gallery/async-dsss-receiver-spec.md, docs/gallery/dsss-acq-characterization.md, docs/gallery/dsss-receiver.md): a continuous, non-bursty spreading code whose data-symbol clock need not be synchronous to the code-epoch clock. steps() streams raw samples through whichever child is currently active:

  • searching (tracking() == 0): samples feed the embedded Acquisition. Nothing is emitted. On a hit, the carrier loop/ Dll/RateConverter/MpskReceiver are built from the hit's code phase and Doppler estimate (the exact acq_result_t::chip_phase hand-off phase and RateConverter-bridged sample-rate hand-off this repo's gallery pages validated by hand), and the unconsumed tail of the same steps() call is handed straight to them — no samples are dropped at the transition.
  • tracking (tracking() == 1): samples are first derotated by a pre-despread carrier loop (costas_wipeoff/costas_update, one update per code period, bn_fll-assisted removes BULK Doppler and its RATE OF CHANGE before the code loop ever sees it; a fixed/ bounded residual alone is fine downstream-only, per docs/design/async-dsss-receiver.md §3.4, but an unbounded Doppler RATE is not), one code period at a time (a small internal carry buffer holds any leftover partial-period tail across calls steps() still accepts any block size), then feed Dll -> RateConverter -> MpskReceiver in sequence the C-level equivalent of hand-composing those four objects (plus the new carrier stage) and demodulated symbols are emitted. This is a NEW composition living entirely in this object deliberately NOT a swap to the existing Despreader object (which fuses Costas+Dll per-sample), because Despreader embeds Dll via dp_dll_init(), hardcoded to segments==1; it cannot carry this object's own segments>1 async-lookback tracking. dp_dll_steps() itself is called completely unmodified.

Per [[feedback_despread_resample_demod_separation]] (this story's own hard-won lesson): segments (the despreader's own tracking parameter) and sps (the demodulator's own sample-rate need) are independently configurable and bridged by an explicit RateConverter, never coupled to each other.

// "Just works": only the signal's own physical parameters are required.
dp_dsss_receiver_state_t *rx = dp_dsss_receiver_create(
    code, code_len, 3.0e6, 2100.0,   // chip_rate, symbol_rate
    2, 2,                            // spc, m (BPSK)
    55.0, 1e-3, 0.9, 100.0,          // cn0_dbhz, pfa, pd,
                                     // doppler_uncertainty
    4, 8,                            // segments, sps
    0);                              // differential
float _Complex syms[4096];
size_t n = dp_dsss_receiver_steps(rx, x, x_len, syms, 4096);
dp_dsss_receiver_destroy(rx);

Public Functions Documentation

function dp_dsss_receiver_configure_chain_raw

Pin the despread/resample/demod grid directly, bypassing the create-time segments /sps defaults.

int dp_dsss_receiver_configure_chain_raw (
    dp_dsss_receiver_state_t * state,
    size_t segments,
    size_t sps,
    int n
) 

The escape hatch for the one composition-specific knob this object adds beyond its children's own: segments (Dll's tracking parameter) and sps/n (MpskReceiver's samples and terminal outputs per symbol) are independently overridable here, still bridged by a freshly-sized RateConverter never coupled to each other (see the module docstring). It rebuilds dll/rc/rx at once, allocating every replacement before freeing the old ones (Acquisition's acq_regrid() discipline), and the pinned grid is the one every later chain is built on: the next hit's hand-off and reset() both rebuild at it.

The new grid is checked before anything is rebuilt, and refused with the receiver left on its prior grid: segments >= 1, sps >= 2, a symbol no faster than a chip and a resampling ratio that is a normal double (doppler#2103), and an n MpskReceiver would accept (doppler#2426). Still an abort: an allocation failure in the rebuild, which runs under dp_xnn (doppler#2112).

Parameters:

  • state The receiver.
  • segments Dll tracking segments per code period, >= 1.
  • sps MpskReceiver samples per symbol (the resample target), >= 2.
  • n MpskReceiver's terminal outputs per symbol (m_out): inside dp_ratesync_m_ok() (even, 2..8), and dividing sps.

Returns:

0 on success, -1 on a grid refused as above (the receiver keeps its prior grid).

>>> import numpy as np
>>> from doppler.dsss import DsssReceiver
>>> from doppler.wfm import Gold
>>> code = np.asarray(Gold().generate(1023)).astype(np.uint8)
>>> rx = DsssReceiver(code, chip_rate=3.0e6, symbol_rate=2100.0, spc=2)
>>> rx.configure_chain_raw(segments=6, sps=8, n=8)  # re-pin the chain
>>> rx.segments                       # tracking grid updated in place
6


function dp_dsss_receiver_configure_lock_raw

Re-tune the embedded Dll's code-lock detector directly. Forwards to dp_dll_configure_lock_raw() . Only meaningful once tracking has begun (dll is NULL before then); a no-op while searching. The detector is the hysteretic lockdet over the DLL's per-N-look CFAR statistic —up_thresh /down_thresh set the declare/drop levels andn_up /n_down the consecutive-look verify counts, trading declare latency against false-alarm rate.

void dp_dsss_receiver_configure_lock_raw (
    dp_dsss_receiver_state_t * state,
    double up_thresh,
    double down_thresh,
    size_t n_looks,
    double alpha,
    uint32_t n_up,
    uint32_t n_down
) 

Parameters:

  • state Must be non-NULL.
  • up_thresh CFAR-statistic level to declare code lock (hit when the statistic exceeds it).
  • down_thresh Level below which a look is a miss; choose <= up_thresh for level hysteresis.
  • n_looks Looks per decision — the DLL's non-coherent integration depth feeding one statistic.
  • alpha EMA smoothing coefficient on the lock statistic (0..1); smaller is smoother/slower.
  • n_up Consecutive hits required to declare lock.
  • n_down Consecutive misses required to drop lock.
    >>> import numpy as np
    >>> from doppler.dsss import DsssReceiver
    >>> from doppler.wfm import Gold
    >>> code = np.asarray(Gold().generate(1023)).astype(np.uint8)
    >>> rx = DsssReceiver(code, chip_rate=3.0e6, symbol_rate=2100.0, spc=2)
    >>> rx.configure_lock_raw(up_thresh=0.4, down_thresh=0.2, n_looks=20,
    ...                       alpha=0.1, n_up=5, n_down=3)
    >>> rx.tracking                # a no-op until a hit builds the Dll
    0
    

function dp_dsss_receiver_configure_search_raw

Pin the embedded Acquisition's search grid directly. Forwards to dp_acq_configure_search_raw() — the escape hatch under this object's ownsymbol_rate -driven auto-sizing, for a power user who wants a specific(doppler_bins, n_noncoh) instead. Only meaningful while searching (a no-op has already happened once tracking has begun; the acquisition search doesn't run again until the nextreset() ).

int dp_dsss_receiver_configure_search_raw (
    dp_dsss_receiver_state_t * state,
    size_t doppler_bins,
    size_t n_noncoh
) 

Parameters:

  • state Must be non-NULL.
  • doppler_bins Number of Doppler window tiles to search (>= 1); capped by the create-time doppler_uncertainty span (one tile per code-epoch Doppler bin width).
  • n_noncoh Non-coherent looks accumulated per grid cell (1..256); more looks buys sensitivity at the cost of dwell, replacing the auto-sized count.

Returns:

0 on success, -1 on invalid grid (see dp_acq_configure_search_raw).

>>> import numpy as np
>>> from doppler.dsss import DsssReceiver
>>> from doppler.wfm import Gold
>>> code = np.asarray(Gold().generate(1023)).astype(np.uint8)
>>> rx = DsssReceiver(code, chip_rate=3.0e6, symbol_rate=2100.0, spc=2)
>>> rx.configure_search_raw(doppler_bins=1, n_noncoh=16)  # pin it
>>> rx.tracking                # still searching, on the pinned grid
0


function dp_dsss_receiver_create

Create a DSSS receiver in the searching state.

dp_dsss_receiver_state_t * dp_dsss_receiver_create (
    const uint8_t * code,
    size_t code_len,
    double chip_rate,
    double symbol_rate,
    size_t spc,
    int m,
    double cn0_dbhz,
    double pfa,
    double pd,
    double doppler_uncertainty,
    size_t segments,
    size_t sps,
    int differential
) 

Only code/chip_rate/symbol_rate describe the signal itself — everything else is a physically-motivated default a caller can override, not a requirement. Internally: the embedded Acquisition is built via dp_acq_create_continuous() (this receiver is inherently continuous/streaming) always window-tiles, never coherently combines across epochs, sensitivity purely from an internally auto-sized non-coherent look count (see acq_core.h's file doc comment); Dll always uses bn=0.002 (this story's own validated stable loop bandwidth for a one-update-per-code-epoch geometry, not dp_dll_create()'s own default of 0.01, which this story found unstable here) and zeta=0.707, spacing=0.5; MpskReceiver always uses pulse=iandd, bn_carrier=bn_timing=0.01, zeta=0.707 and lock_thresh=0.3 — this story's own validated values throughout. It also passed acq_to_track=1 and warmup_syms=30 until those were deleted (doppler#877, 1f417e97); the composed receiver now runs its one NDA discriminator here as everywhere else. lock_thresh=0.3 predates the lock statistic becoming a calibrated detector and is retained because it is validated here, but it now has a derivable reading: the carrier lock EMA's noise-only sd is 0.1132 at every M, so 0.3 is 2.65 noise sigmas, a per-look Pfa of ~4e-3 — looser than MpskReceiver's own 0.5 default (4.42 sigma, 5e-6) and still ~6 sigma clear of the +0.99 a locked BPSK constellation reads, which is why it holds. See carrier_nda_core.h. n (MpskReceiver's carrier-arm count) is derived from sps: the largest divisor of sps in {4, 2, 1}.

Parameters:

  • code Spreading code, one 0/1 chip per element (0 -> +1, 1 -> -1 BPSK; only the low bit is used, so pass 0/1, not +/-1).
  • code_len Chips in code (the spreading factor).
  • chip_rate Chip rate, Hz. Required.
  • symbol_rate Data-symbol rate, Hz. Required — passed straight to the embedded Acquisition's own symbol_rate (diagnostic there; see dp_acq_create_continuous()).
  • spc Samples/chip (front-end oversample); default 2 (fs = 2x chip_rate).
  • m PSK order, 2/4/8; default 2 (BPSK).
  • cn0_dbhz Design C/N0 for acquisition sizing, dB-Hz; default 55.0.
  • pfa Acquisition false-alarm target; default 1e-3.
  • pd Acquisition detection-probability target; default 0.9.
  • doppler_uncertainty One-sided Doppler search half-range, Hz; default 100.0.
  • segments Dll's partial correlations per code epoch: its despread output rate and the grain of its look-back window, independent of sps (see the module docstring); default 4.
  • sps MpskReceiver's samples/symbol, reached by an internal RateConverter bridging the despreader's own partial rate to this rate; default 8, MpskReceiver's own constructor default.
  • differential MpskReceiver's differential (rotation- invariant) demap; default 0 (coherent).
    >>> import numpy as np
    >>> from doppler.dsss import DsssReceiver
    >>> from doppler.wfm import Gold
    >>> sf, chip, sym, spc = 1023, 3.0e6, 2100.0, 2
    >>> fs, te, tsym = chip * spc, sf * spc, chip * spc / sym
    >>> code = np.asarray(Gold().generate(sf)).astype(np.uint8)
    >>> csign = np.where(code & 1, -1.0, 1.0)
    >>> rng = np.random.default_rng(6)
    >>> n = int(400 * tsym) + 2 * te            # 400 BPSK data symbols
    >>> idx = np.arange(n)
    >>> data = (rng.integers(0, 2, 404) * 2 - 1).astype(float)
    >>> si = np.clip((idx / tsym).astype(int), 0, 403)
    >>> spread = data[si] * csign[(idx // spc) % sf]        # DSSS chips
    >>> sig = spread * np.exp(2j * np.pi * (50.0 / fs) * idx)  # +50 Hz
    >>> pre = 3 * te                     # noise-only lead-in, pre-signal
    >>> sigma = np.sqrt(fs / 10 ** (90.0 / 10))            # ~90 dB-Hz C/N0
    >>> noise = (sigma / np.sqrt(2)) * (rng.standard_normal(pre + n)
    ...          + 1j * rng.standard_normal(pre + n))
    >>> x = (np.concatenate([np.zeros(pre), sig]).astype(np.complex64)
    ...      + noise.astype(np.complex64))
    >>> rx = DsssReceiver(code, chip_rate=chip, symbol_rate=sym, spc=spc,
    ...                   cn0_dbhz=55.0, doppler_uncertainty=100.0)
    >>> syms = [rx.steps(x[p:p + te]) for p in range(0, len(x) - te, te)]
    >>> syms = np.concatenate([s for s in syms if len(s)])
    >>> rx.tracking                  # acquired, now demodulating
    1
    >>> len(syms) > 300              # a few hundred symbols recovered
    True
    
    Nearly all the energy lands on I, so the BPSK phase is resolved:
    
    >>> bool(np.mean(syms.real**2) > 10 * np.mean(syms.imag**2))
    True
    

function dp_dsss_receiver_destroy

Destroy a receiver and release all four children.

void dp_dsss_receiver_destroy (
    dp_dsss_receiver_state_t * state
) 

Parameters:

  • state May be NULL.

function dp_dsss_receiver_get_chip_phase

Dll's live tracked code phase (chips); 0.0 while searching.

double dp_dsss_receiver_get_chip_phase (
    const dp_dsss_receiver_state_t * state
) 


function dp_dsss_receiver_get_cn0_dbhz_est

double dp_dsss_receiver_get_cn0_dbhz_est (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_get_code_rate

Dll's own tracking-quality indicator; 1.0 while searching.

double dp_dsss_receiver_get_code_rate (
    const dp_dsss_receiver_state_t * state
) 


function dp_dsss_receiver_get_doppler_hz

double dp_dsss_receiver_get_doppler_hz (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_get_lock

MpskReceiver's carrier lock EMA; 0.0 while searching.

double dp_dsss_receiver_get_lock (
    const dp_dsss_receiver_state_t * state
) 


function dp_dsss_receiver_get_n

int dp_dsss_receiver_get_n (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_get_norm_freq

MpskReceiver's tracked carrier frequency; 0.0 while searching.

double dp_dsss_receiver_get_norm_freq (
    const dp_dsss_receiver_state_t * state
) 


function dp_dsss_receiver_get_segments

size_t dp_dsss_receiver_get_segments (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_get_sps

size_t dp_dsss_receiver_get_sps (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_get_state

void dp_dsss_receiver_get_state (
    const dp_dsss_receiver_state_t * state,
    void * blob
) 

function dp_dsss_receiver_get_tracking

int dp_dsss_receiver_get_tracking (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_reset

Return to the searching state. Resets the embedded Acquisition and frees dll /rc /rx (rebuilt from scratch on the next hit) — a receiver that has locked cannot be "reset back to tracking the same signal," only back to searching, matching every other object's reset() semantics in this codebase.

void dp_dsss_receiver_reset (
    dp_dsss_receiver_state_t * state
) 

Parameters:

  • state Must be non-NULL.
    >>> import numpy as np
    >>> from doppler.dsss import DsssReceiver
    >>> from doppler.wfm import Gold
    >>> code = np.asarray(Gold().generate(1023)).astype(np.uint8)
    >>> rx = DsssReceiver(code, chip_rate=3.0e6, symbol_rate=2100.0, spc=2)
    >>> rx.reset()                 # abort any lock, hunt from scratch
    >>> (rx.tracking, rx.chip_phase)   # back to searching, all cleared
    (0, 0.0)
    

function dp_dsss_receiver_set_state

int dp_dsss_receiver_set_state (
    dp_dsss_receiver_state_t * state,
    const void * blob
) 

function dp_dsss_receiver_state_bytes

size_t dp_dsss_receiver_state_bytes (
    const dp_dsss_receiver_state_t * state
) 

function dp_dsss_receiver_steps

Stream raw cf32 samples; emit demodulated symbols once locked.

size_t dp_dsss_receiver_steps (
    dp_dsss_receiver_state_t * state,
    const float _Complex * x,
    size_t x_len,
    float _Complex * out,
    size_t max_out
) 

While searching, samples feed the embedded Acquisition and nothing is emitted (0 return is normal, not an error). The moment a hit fires, Dll/RateConverter/MpskReceiver are built and seeded from it, and the rest of THIS call from where the hit's frame ended — the hit's own samples_consumed, so no samples are dropped or double-fed — is handed straight to them in the same call. While tracking, samples feed Dll -> RateConverter -> MpskReceiver in sequence. Accepts any block size; state carries across calls (Acquisition/Dll/ RateConverter/MpskReceiver are all already block-size invariant, so this object needs no ring-buffering of its own).

Parameters:

  • 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 (0 while searching, or while tracking with not yet a full symbol's worth of input).

>>> import numpy as np
>>> from doppler.dsss import DsssReceiver
>>> from doppler.wfm import Gold
>>> sf, chip, sym, spc = 1023, 3.0e6, 2100.0, 2
>>> fs, te, tsym = chip * spc, sf * spc, chip * spc / sym
>>> code = np.asarray(Gold().generate(sf)).astype(np.uint8)
>>> csign = np.where(code & 1, -1.0, 1.0)
>>> rng = np.random.default_rng(6)
>>> n = int(400 * tsym) + 2 * te            # 400 BPSK data symbols
>>> idx = np.arange(n)
>>> data = (rng.integers(0, 2, 404) * 2 - 1).astype(float)
>>> si = np.clip((idx / tsym).astype(int), 0, 403)
>>> spread = data[si] * csign[(idx // spc) % sf]        # DSSS chips
>>> sig = spread * np.exp(2j * np.pi * (50.0 / fs) * idx)  # +50 Hz
>>> pre = 3 * te                     # noise-only lead-in, pre-signal
>>> sigma = np.sqrt(fs / 10 ** (90.0 / 10))            # ~90 dB-Hz C/N0
>>> noise = (sigma / np.sqrt(2)) * (rng.standard_normal(pre + n)
...          + 1j * rng.standard_normal(pre + n))
>>> x = (np.concatenate([np.zeros(pre), sig]).astype(np.complex64)
...      + noise.astype(np.complex64))
>>> rx = DsssReceiver(code, chip_rate=chip, symbol_rate=sym, spc=spc,
...                   cn0_dbhz=55.0, doppler_uncertainty=100.0)
>>> syms = [rx.steps(x[p:p + te]) for p in range(0, len(x) - te, te)]
>>> syms = np.concatenate([s for s in syms if len(s)])
>>> rx.tracking                  # acquired and now demodulating
1
>>> len(syms) > 300              # a few hundred symbols recovered
True

Nearly all the energy lands on I, so the BPSK phase is resolved:

>>> bool(np.mean(syms.real**2) > 10 * np.mean(syms.imag**2))
True


function dp_dsss_receiver_steps_max_out

size_t dp_dsss_receiver_steps_max_out (
    dp_dsss_receiver_state_t * state
) 

Macro Definition Documentation

define DSSS_RECEIVER_STATE_MAGIC

#define DSSS_RECEIVER_STATE_MAGIC `DP_FOURCC ('D', 'S', 'R', 'X')`

define DSSS_RECEIVER_STATE_VERSION

#define DSSS_RECEIVER_STATE_VERSION `/* multi line expression */`

define DSSS_RX_BN_CARRIER

#define DSSS_RX_BN_CARRIER `0.01`

define DSSS_RX_BN_FLL

#define DSSS_RX_BN_FLL `0.03`


The documentation for this class was generated from the following file native/inc/doppler/dsss_receiver/dsss_receiver_core.h