File farrow_core.h¶
FileList > farrow > farrow_core.h
Go to the source code of this file
Farrow fractional-delay interpolator — linear / parabolic / cubic. More...
#include "clib_common.h"#include "jm_perf.h"#include "dp_state.h"#include <complex.h>
Classes¶
| Type | Name |
|---|---|
| struct | farrow_state_t Farrow interpolator state (4-tap delay line + order). |
Public Types¶
| Type | Name |
|---|---|
| enum | farrow__core_8h_1a06fc87d81c62e9abb8790b6e5713c55b |
Public Functions¶
| Type | Name |
|---|---|
| farrow_state_t * | farrow_create (int order) Create a Farrow interpolator. |
| size_t | farrow_delay (farrow_state_t * state, const float _Complex * x, size_t x_len, double mu, float _Complex * out, size_t max_out) Apply a constant fractional delay of mu samples to a CF32 block. |
| size_t | farrow_delay_max_out (farrow_state_t * state) |
| void | farrow_destroy (farrow_state_t * state) Destroy a Farrow interpolator. |
| JM_FORCEINLINE JM_HOT float _Complex | farrow_eval (const farrow_state_t * s, float mu) Interpolate at fractional offset mu ∈[0,1) betweend[1] andd[2] . |
| size_t | farrow_get_group_delay (const farrow_state_t * state) |
| void | farrow_get_state (const farrow_state_t * state, void * blob) |
| JM_FORCEINLINE void | farrow_init (farrow_state_t * s, int order) Initialise in place: set order, clear the delay line. |
| JM_FORCEINLINE JM_HOT void | farrow_push (farrow_state_t * s, float _Complex x) Push one input sample into the delay line (oldest drops out). |
| void | farrow_reset (farrow_state_t * state) Clear the interpolator delay line; keep the order. |
| int | farrow_set_state (farrow_state_t * state, const void * blob) |
| size_t | farrow_state_bytes (const farrow_state_t * state) |
Macros¶
| Type | Name |
|---|---|
| define | FARROW_GROUP_DELAY 2u |
| define | FARROW_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('F', 'R', 'R', 'W') |
| define | FARROW_STATE_VERSION 1u |
Detailed Description¶
A selectable-order Lagrange interpolator in Farrow (Horner-in-µ) form — the lean alternative to a full polyphase resampler when all you need is a fractional-delay tap for a timing loop. All three orders share one 4-tap delay line and interpolate at the SAME point — between the two middle taps — so the group delay is 2 samples regardless of order, which keeps a driving symbol-timing loop order-agnostic. Push input samples with farrow_push(); evaluate the output at a fractional offset µ ∈ [0,1) with farrow_eval(). The fractional offset is meant to come from an integer timing NCO (the post-wrap accumulator value), so the timing stays drift-free while only the interpolation itself is floating point.
order: 0 = linear (2-tap Lagrange), 1 = parabolic (4-tap symmetric piecewise-parabolic Farrow, α = 0.5), 2 = cubic (4-tap cubic Lagrange). All three are symmetric about the interpolation point, so the phase (delay) response is linear — no timing bias. Linear and cubic are exact for degree 1 and 3 polynomials; the piecewise-parabolic trades exactness for a flatter magnitude response than linear at no delay cost.
Lifecycle: farrow_create -> (push / eval / reset)* -> farrow_destroy, or embed by value with farrow_init().
farrow_state_t f;
farrow_init(&f, FARROW_CUBIC);
for (size_t i = 0; i < n; i++) farrow_push(&f, x[i]);
float _Complex y = farrow_eval(&f, 0.3f); // x interpolated 0.3 past tap[1]
Public Types Documentation¶
enum farrow__core_8h_1a06fc87d81c62e9abb8790b6e5713c55b¶
enum farrow__core_8h_1a06fc87d81c62e9abb8790b6e5713c55b {
FARROW_LINEAR = 0,
FARROW_PARABOLIC = 1,
FARROW_CUBIC = 2
};
Public Functions Documentation¶
function farrow_create¶
Create a Farrow interpolator.
Parameters:
order0 = linear, 1 = parabolic, 2 = cubic.
Returns:
Heap-allocated state, or NULL on allocation failure.
Note:
Caller must call farrow_destroy() when done.
function farrow_delay¶
Apply a constant fractional delay of mu samples to a CF32 block.
size_t farrow_delay (
farrow_state_t * state,
const float _Complex * x,
size_t x_len,
double mu,
float _Complex * out,
size_t max_out
)
Pushes each input sample through the delay line and evaluates the interpolator at the same fixed offset, so the whole block is delayed by a constant, non-integer amount. Output sample i is the input interpolated at i - group_delay + mu, i.e. the stream shifted later by group_delay - mu samples; the first group_delay outputs are the delay-line filling transient and should be discarded. Because the offset is held constant this is the open-loop use of the interpolator — a timing loop instead steers mu per sample via farrow_push()/farrow_eval().
Parameters:
statePointer to a valid farrow_state_t.xCF32 input samples.x_lenNumber of input samples.muFractional delay in samples; the offset in[0,1)into the interpolation interval (values outside extrapolate).outOutput buffer; one output per input sample.max_outCapacity ofoutin samples.
Returns:
CF32 output array, same length as x, each sample delayed by group_delay - mu.
>>> from doppler.resample import Farrow
>>> import numpy as np
>>> f = Farrow(order="cubic")
>>> x = np.arange(8, dtype=np.complex64) # a ramp: exact interp
>>> y = f.delay(x, 0.5) # delay group_delay - 0.5
>>> [round(float(v.real), 4) for v in y] # first 2 are transient
[0.0, -0.0625, 0.4375, 1.5, 2.5, 3.5, 4.5, 5.5]
function farrow_delay_max_out¶
function farrow_destroy¶
Destroy a Farrow interpolator.
Parameters:
stateMay be NULL.
function farrow_eval¶
Interpolate at fractional offset mu ∈[0,1) betweend[1] andd[2] .
Horner-in-µ evaluation of the order's Lagrange polynomial. µ = 0 returns d[1] (= input at i - 2); µ → 1 returns d[2].
Parameters:
sState. Must be non-NULL.muFractional offset in[0,1).
Returns:
The interpolated sample.
function farrow_get_group_delay¶
function farrow_get_state¶
function farrow_init¶
Initialise in place: set order, clear the delay line.
function farrow_push¶
Push one input sample into the delay line (oldest drops out).
function farrow_reset¶
Clear the interpolator delay line; keep the order.
Zeroes the 4-tap delay line so the next block starts from a filling transient again, exactly as a freshly created interpolator would. The order (linear / parabolic / cubic) is preserved, so the same object can be reused across independent bursts without rebuilding the polynomial. Call it between unrelated signal segments to stop the tail of one leaking into the head of the next.
Parameters:
stateMust be non-NULL.
>>> from doppler.resample import Farrow
>>> import numpy as np
>>> f = Farrow(order="cubic")
>>> _ = f.delay(np.ones(8, dtype=np.complex64), 0.25) # leaves state
>>> f.reset() # back to pristine
>>> x = np.arange(8, dtype=np.complex64)
>>> f.delay(x, 0.5)[3:].real.tolist() # steady part: ramp - 1.5
[1.5, 2.5, 3.5, 4.5, 5.5]
function farrow_set_state¶
function farrow_state_bytes¶
Macro Definition Documentation¶
define FARROW_GROUP_DELAY¶
define FARROW_STATE_MAGIC¶
define FARROW_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/farrow/farrow_core.h