RF Complex Moving Average
Sliding running sum of the last N complex I/Q samples, updated in O(1) per clock with an add/subtract and an N-tap delay line. Typical use: a cheap boxcar low-pass / smoother on a baseband stream.
Introduction
The Complex Moving Average block outputs the running sum of the most
recent N complex samples:
OUT[n] = sum_{k=0..N-1} IN[n-k]
It updates the sum in constant time using the classic recursive boxcar: add
the new sample and subtract the sample that just left the window, rather
than re-summing N taps every clock:
sum <- sum + IN[n] - IN[n-N]
A boxcar of length N is a linear-phase low-pass filter with a sinc
magnitude response (first null at Fs/N); it is the cheapest way to smooth
or decimate-in-place a baseband envelope.
N is fixed at synthesis time by the Window Length N property, which
sizes both the delay line and the output word.
Pin Description
Properties
Bit width of each I/Q input (signed).
Bit width of each signed I / Q input sample. Range 4 to 32, default 16.Default: 16
Options: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Number of samples in the running-sum window. Output width = InputSize + ceil(log2(N)).
Window lengthN (number of samples in the running sum). Selectable
from 4, 8, 16, 32, 64, 128, 256, 512, default 64. Output width =
InputSize + ceil(log2(N)). Larger N = more smoothing and a narrower
passband (first null at Fs/N), at the cost of a longer delay line.
Default: 64
Options: 4 8 16 32 64 128 256 512
Usage
Stateful / feedback behaviour
This is a stateful block. The C++ core keeps static state across
samples:
static in_t dly_i[N], dly_q[N]; // N-sample delay line (shift register)
static acc_t sum_i, sum_q; // running complex sum
Each clock the oldest entry dly[N-1] is read out, the delay line shifts by
one, the new sample is written to dly[0], and the sum is updated as
sum += IN - oldest. The delay line shift is fully unrolled
(#pragma HLS UNROLL) so the whole update completes in one clock.
Running sum vs. average
The block emits the sum, not the mean. Because N is a power of two for
every selectable value, divide by N with a simple >> log2(N) right-shift
downstream if you need the true average. Keeping the sum avoids a divider and
preserves the extra log2(N) bits of precision.
Reset behaviour
RESET is the HLS synchronous reset (ap_rst). On assertion the delay line
and the running sum are cleared to zero. After reset the sum ramps up over
the first N samples as the window fills (it is only a true N-sample
average once N samples have been seen).
Bit widths
IN_I,IN_Q: signedInputSizebits.OUT_I,OUT_Q: signedInputSize + ceil(log2(N))bits.
The ceil(log2(N)) growth guarantees the sum of N full-scale samples
cannot overflow.
Latency and throughput
#pragma HLS PIPELINE II=1: one sample pair per clock.- 1-clock latency.
- All ports use
ap_none. #pragma HLS INTERFACE ap_ctrl_none port=return: no block-level control.
Typical applications
- Boxcar low-pass / smoothing of a noisy I/Q envelope.
- Anti-alias pre-filter before a downstream rate reducer.
- Cheap channel filter where a full FIR is overkill.
Resources & Timing
-
Latency: 1 clock cycle
-
Throughput: 1 sample per clock (II=1)
O(1) update: one add and one subtract per channel regardless of N. Cost is the N-sample delay line (2*N registers or a shift-RAM). No multipliers. Stateful (static delay line + running sum). Divide the output by N downstream (» log2(N)) for the true mean.