Xilinx
HLS
Block Preview

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

IN_I Input InputSize bit BIT VECTOR
In-phase (I) input sample. Signed, Input Bit Width bits.
Default: Must be connected
IN_Q Input InputSize bit BIT VECTOR
Quadrature (Q) input sample. Signed, Input Bit Width bits.
Default: Must be connected
CLK Input 1 bit BIT
System clock input. Default: Acquisition clock.
Default: Default Board Clock
RESET Input 1 bit BIT
HLS synchronous reset (ap_rst). Default: Global reset. Clears the delay line and the running sum; the window must re-fill over N samples.
Default: Default Board Reset
OUT_I Output InputSize + ceil(log2(N)) bit BIT VECTOR
Running sum of the last N I samples. Signed, InputSize + ceil(log2(N)) bits.
OUT_Q Output InputSize + ceil(log2(N)) bit BIT VECTOR
Running sum of the last N Q samples. Signed, InputSize + ceil(log2(N)) bits.

Properties

Property window

Input Bit Width InputSize

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

Window Length N WindowLen

Number of samples in the running-sum window. Output width = InputSize + ceil(log2(N)).

Window length N (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 : signed InputSize bits.
  • OUT_I, OUT_Q : signed InputSize + 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.