Skip to content

File lo_core.h

FileList > inc > lo > lo_core.h

Go to the source code of this file

Local oscillator: NCO phase accumulator + 2^16 sin/cos LUT. More...

  • #include "clib_common.h"

Classes

Type Name
struct lo_state_t

Public Functions

Type Name
lo_state_t * lo_create (float norm_freq)
Create a local oscillator.
void lo_destroy (lo_state_t * lo)
void lo_execute_cf32 (lo_state_t * lo, float _Complex * out, size_t n)
Generate n complex phasors (CF32).
void lo_execute_cf32_ctrl (lo_state_t * lo, const float * ctrl, float _Complex * out, size_t n)
Generate n complex phasors with per-sample FM control.
float lo_get_freq (const lo_state_t * lo)
uint32_t lo_get_phase (const lo_state_t * lo)
uint32_t lo_get_phase_inc (const lo_state_t * lo)
void lo_reset (lo_state_t * lo)
void lo_set_freq (lo_state_t * lo, float norm_freq)
void lo_set_phase (lo_state_t * lo, uint32_t phase)

Detailed Description

Lifted from dp_nco_t (c/src/nco.c) — LUT and complex-phasor section. The pure phase-accumulator output (u32/ovf) lives in nco_core.

A 2^16-entry float32 sine LUT is initialised once (lazy, guarded by a static flag) and shared across all lo_state_t instances. Memory: 256 KB (fits comfortably in L2 on all modern CPUs). SFDR: ~96 dBc (16-bit phase truncation → 6 × 16 dB rule).

LUT addressing: sin(θ) = lut[phase >> 16] cos(θ) = lut[(uint16_t)((phase >> 16) + LUT_QTR)] (LUT_QTR = 16384)

On x86 targets with AVX-512F, lo_execute_cf32 uses gather loads to compute 16 phasors per iteration. All other targets use the scalar path.

reset() zeroes phase only; norm_freq is unchanged.

lo_state_t *lo = lo_create(0.1f);
float _Complex out[256];
lo_execute_cf32(lo, out, 256);
lo_destroy(lo);

Public Functions Documentation

function lo_create

Create a local oscillator.

lo_state_t * lo_create (
    float norm_freq
) 

Triggers LUT initialisation on first call (one-time cost).

Parameters:

  • norm_freq Normalised frequency (cycles per sample). Any float; folded into [0, 1) internally.

Returns:

Heap-allocated state, or NULL on OOM.


function lo_destroy

void lo_destroy (
    lo_state_t * lo
) 

Free all resources. NULL is a no-op.


function lo_execute_cf32

Generate n complex phasors (CF32).

void lo_execute_cf32 (
    lo_state_t * lo,
    float _Complex * out,
    size_t n
) 

Each sample is cos(θ) + j·sin(θ) where θ advances by phase_inc per sample. On AVX-512F builds, processes 16 samples per loop iteration using i32gather from the float LUT.

Output buffer sizing: allocate at least n samples.

Parameters:

  • lo Must be non-NULL.
  • out CF32 output, length >= n.
  • n Number of samples.

function lo_execute_cf32_ctrl

Generate n complex phasors with per-sample FM control.

void lo_execute_cf32_ctrl (
    lo_state_t * lo,
    const float * ctrl,
    float _Complex * out,
    size_t n
) 

ctrl[i] is a normalised-frequency deviation added to the base phase_inc before each sample: inc_eff = phase_inc + (uint32_t)floor(ctrl[i] × 2^32)

Mirrors dp_nco_execute_cf32_ctrl. Used by the DDC chain for closed-loop frequency tracking.

Parameters:

  • lo Must be non-NULL.
  • ctrl Per-sample frequency deviations, float32, length >= n.
  • out CF32 output, length >= n.
  • n Number of samples.

function lo_get_freq

float lo_get_freq (
    const lo_state_t * lo
) 

function lo_get_phase

uint32_t lo_get_phase (
    const lo_state_t * lo
) 

function lo_get_phase_inc

uint32_t lo_get_phase_inc (
    const lo_state_t * lo
) 

function lo_reset

void lo_reset (
    lo_state_t * lo
) 

Zero phase accumulator. norm_freq is unchanged.


function lo_set_freq

void lo_set_freq (
    lo_state_t * lo,
    float norm_freq
) 

Update normalised frequency without disturbing the phase.


function lo_set_phase

void lo_set_phase (
    lo_state_t * lo,
    uint32_t phase
) 

Write phase accumulator (phase seek / sync).



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