Xilinx
Block Preview

Introduction

The FIR Filter block implements a general-purpose finite impulse response filter:

$$ y[n] = \sum_{k=0}^{N-1} h[k] \cdot x[n-k] $$

where:

  • h[k] are the filter coefficients (taps)
  • N is the number of taps
  • x[n-k] are delayed input samples

Coefficients are entered directly in the properties as a comma-separated list, supporting both decimal values (e.g., 0.25, 0.5, 0.25) and integer values. The filter automatically converts decimal coefficients to fixed-point format based on the configured coefficient fractional bits.

Pin Description

X Input Variable bit BIT VECTOR
Input data stream to be filtered. Width: Input Data Bits. Fixed-point format: Q(InDataBits-InFractBits).InFractBits. Signed (two’s complement).
Default: Must be connected
CLK Input 1 bit BIT
System clock. Rising edge triggers filter computation.
Default: Default Board Clock
RESET Input 1 bit BIT
Synchronous reset, active high. Clears delay line and resets warmup counter.
Default: Default Board Reset
Y Output Variable bit BIT VECTOR
Filtered output signal. Width: Output Data Bits. Fixed-point format: Q(OutDataBits-OutFractBits).OutFractBits. Includes rounding and saturation.
DV Output 1 bit BIT
Data valid output, active high. Goes high after the delay line is filled (N samples processed). Indicates Y contains valid filtered data.

Properties

Property window

Input Data Bits InDataBits

Total bit width of input data (8-32 bits)

Total bit width of input data X. Range: 8-32 bits. Includes both integer and fractional parts.

Default: 16

Options: 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

Input Fractional Bits InFractBits

Number of fractional bits in input data (0-16)

Number of fractional bits in input data. Range: 0-16 bits. Integer bits = InDataBits - InFractBits.

Default: 0

Options: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Output Data Bits OutDataBits

Total bit width of output data (8-64 bits)

Total bit width of output data Y. Range: 8-64 bits. Should be large enough to avoid overflow. Recommended: InDataBits + CoefDataBits + ceil(log2(NumTaps)).

Default: 32

Options: 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

Output Fractional Bits OutFractBits

Number of fractional bits in output data (0-32)

Number of fractional bits in output data. Range: 0-32 bits. Should match: InFractBits + CoefFractBits for no precision loss.

Default: 16

Options: 0 1 2 3 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

Coefficient Data Bits CoefDataBits

Total bit width of coefficients (8-32 bits)

Total bit width of filter coefficients. Range: 8-32 bits. Higher values improve coefficient precision.

Default: 16

Options: 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

Coefficient Fractional Bits CoefFractBits

Number of fractional bits in coefficients (0-31)

Number of fractional bits in coefficients. Range: 0-31 bits. For normalized coefficients (|h| < 1), use CoefFractBits = CoefDataBits - 1. Example: 16-bit coefficients with 15 fractional bits -> Q1.15 format.

Default: 15

Options: 0 1 2 3 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

FIR Coefficients Coefficients

Comma-separated list of FIR coefficients (e.g., 0.25, 0.5, 0.25 or as integers: 8192, 16384, 8192)

Comma-separated list of FIR filter coefficients. Supports 1 to 64 coefficients. Values can be:

  • Decimal (e.g., 0.25, 0.5, -0.125): Automatically converted to fixed-point
  • Integer (e.g., 8192, 16384): Used directly as fixed-point values

The coefficients define the filter impulse response. For symmetric coefficients, the filter has linear phase.

Examples:

  • Moving average (4 taps): 0.25, 0.25, 0.25, 0.25
  • Simple low-pass: 0.25, 0.5, 0.25
  • Differentiator: 1, -1

Default: 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125

Functional description

The FIR filter implements discrete convolution of the input signal with the impulse response defined by the coefficients:

$$ y[n] = h_0 \cdot x[n] + h_1 \cdot x[n-1] + h_2 \cdot x[n-2] + \ldots + h_{N-1} \cdot x[n-N+1] $$

where:

  • x[n] -> X (input signal)
  • y[n] -> Y (filtered output)
  • h[k] -> coefficients from the FIR Coefficients property

Transfer function

In the z-domain, the FIR filter has the transfer function:

$$ H(z) = \sum_{k=0}^{N-1} h[k] \cdot z^{-k} $$

FIR filters have only zeros (no poles), guaranteeing:

  • Unconditional stability
  • Linear phase (if coefficients are symmetric)
  • Finite impulse response (output settles after N samples)

Coefficient entry

Coefficients are entered as a comma-separated list in the FIR Coefficients property:

Input format Example Description
Decimal 0.25, 0.5, 0.25 Normalized coefficients
Integer 8192, 16384, 8192 Pre-scaled fixed-point values

Decimal coefficients are automatically converted to fixed-point using:

$$ \text{fixed_value} = \text{round}(\text{decimal} \times 2^{\text{CoefFractBits}}) $$

Example with CoefFractBits = 15:

  • 0.5 -> 16384
  • 0.25 -> 8192
  • 1.0 -> 32768

Fixed-point format

All data paths use configurable fixed-point arithmetic:

Parameter Format Description
Input Q(I-F).F I = InDataBits, F = InFractBits
Output Q(O-F).F O = OutDataBits, F = OutFractBits
Coefficients Q(C-F).F C = CoefDataBits, F = CoefFractBits

The output uses rounding (AP_RND) and saturation (AP_SAT) to prevent overflow.

Filter design examples

Low-pass filter (8 taps, moving average):

  0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125
  

High-pass filter (3 taps, differentiator):

  -0.5, 1.0, -0.5
  

Band-pass filter (symmetric, 7 taps):

  -0.05, -0.1, 0.25, 0.6, 0.25, -0.1, -0.05
  

Resource usage

The filter uses:

  • N delay registers (one per tap)
  • N multipliers (fully parallel for II=1)
  • Adder tree for accumulation

Resources scale linearly with the number of taps.

Latency

Fixed latency of 4 clock cycles (HLS pipeline) plus delay line fill time. The DV output goes high after N samples have been processed.

Typical use cases

  • Low-pass filtering (noise reduction, anti-aliasing)
  • High-pass filtering (DC removal, edge detection)
  • Band-pass filtering (frequency selection)
  • Matched filtering (pulse detection)
  • Interpolation and decimation filters
  • Custom frequency response shaping

Python examples for coefficient generation

The following Python examples show how to design FIR filters and generate quantized coefficients ready to paste into the FIR Coefficients property.

Low-pass filter using scipy.signal

python
  import numpy as np
from scipy import signal

# Filter parameters
order = 16          # Number of taps - 1
cutoff = 0.2        # Normalized cutoff frequency (0 to 1, where 1 = Nyquist)
coef_fract_bits = 15  # Fractional bits for quantization

# Design filter using window method
coefficients = signal.firwin(order + 1, cutoff, window='hamming')

# Quantize to fixed-point
scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

# Print as comma-separated list (for SCI-Compiler)
print("Decimal coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
print("\nQuantized coefficients (integer):")
print(", ".join(str(c) for c in quantized))
  

High-pass filter

python
  import numpy as np
from scipy import signal

order = 32
cutoff = 0.3        # Normalized cutoff
coef_fract_bits = 15

# High-pass: pass_zero=False
coefficients = signal.firwin(order + 1, cutoff, window='hamming', pass_zero=False)

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("High-pass coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Band-pass filter

python
  import numpy as np
from scipy import signal

order = 64
low_cutoff = 0.1    # Lower normalized frequency
high_cutoff = 0.4   # Upper normalized frequency
coef_fract_bits = 15

# Band-pass filter
coefficients = signal.firwin(order + 1, [low_cutoff, high_cutoff],
                              window='hamming', pass_zero=False)

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Band-pass coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Custom frequency response using firwin2

python
  import numpy as np
from scipy import signal

order = 48
coef_fract_bits = 15

# Define arbitrary frequency response
# freq: normalized frequencies (0 to 1)
# gain: desired gain at each frequency
freq = [0, 0.1, 0.2, 0.3, 0.5, 1.0]
gain = [1, 1, 0.5, 0.1, 0, 0]

coefficients = signal.firwin2(order + 1, freq, gain)

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Custom response coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Raised cosine filter (for communications)

python
  import numpy as np

def raised_cosine(num_taps, beta, sps):
    """
    Raised cosine filter for pulse shaping.
    beta: roll-off factor (0 to 1)
    sps: samples per symbol
    """
    t = np.arange(num_taps) - (num_taps - 1) / 2
    t = t / sps

    coefficients = np.zeros(num_taps)
    for i, ti in enumerate(t):
        if ti == 0:
            coefficients[i] = 1
        elif abs(ti) == 1 / (2 * beta) and beta != 0:
            coefficients[i] = np.pi / 4 * np.sinc(1 / (2 * beta))
        else:
            num = np.sinc(ti) * np.cos(np.pi * beta * ti)
            den = 1 - (2 * beta * ti) ** 2
            coefficients[i] = num / den

    # Normalize
    coefficients /= np.sum(coefficients)
    return coefficients

# Parameters
num_taps = 33
beta = 0.35         # Roll-off factor
sps = 4             # Samples per symbol
coef_fract_bits = 15

coefficients = raised_cosine(num_taps, beta, sps)

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Raised cosine coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Gaussian filter (for smoothing)

python
  import numpy as np
from scipy.ndimage import gaussian_filter1d

def gaussian_fir(num_taps, sigma):
    """Generate Gaussian FIR filter coefficients."""
    # Create impulse
    impulse = np.zeros(num_taps * 10)
    impulse[len(impulse) // 2] = 1

    # Apply Gaussian filter to get impulse response
    response = gaussian_filter1d(impulse, sigma)

    # Extract center portion
    center = len(response) // 2
    half = num_taps // 2
    coefficients = response[center - half : center + half + 1]

    # Normalize
    coefficients /= np.sum(coefficients)
    return coefficients

num_taps = 17
sigma = 2.0         # Standard deviation in samples
coef_fract_bits = 15

coefficients = gaussian_fir(num_taps, sigma)

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Gaussian coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Differentiator filter

python
  import numpy as np
from scipy import signal

order = 16
coef_fract_bits = 15

# Differentiator (type III FIR)
coefficients = signal.remez(order + 1, [0.05, 0.95], [1],
                            type='differentiator')

# Normalize to max = 1
coefficients /= np.max(np.abs(coefficients))

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Differentiator coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Hilbert transformer (90-degree phase shift)

python
  import numpy as np
from scipy import signal

order = 32  # Must be even for Hilbert
coef_fract_bits = 15

coefficients = signal.remez(order + 1, [0.05, 0.95], [1],
                            type='hilbert')

scale = 2 ** coef_fract_bits
quantized = np.round(coefficients * scale).astype(int)

print("Hilbert transformer coefficients:")
print(", ".join(f"{c:.6f}" for c in coefficients))
  

Quantization analysis helper

python
  import numpy as np

def analyze_quantization(coefficients, coef_fract_bits):
    """Analyze quantization error for FIR coefficients."""
    scale = 2 ** coef_fract_bits
    quantized = np.round(coefficients * scale).astype(int)
    reconstructed = quantized / scale

    # Errors
    abs_error = np.abs(coefficients - reconstructed)
    rel_error = abs_error / (np.abs(coefficients) + 1e-10)

    print(f"Coefficient Fractional Bits: {coef_fract_bits}")
    print(f"Max absolute error: {np.max(abs_error):.2e}")
    print(f"Mean absolute error: {np.mean(abs_error):.2e}")
    print(f"Max relative error: {np.max(rel_error) * 100:.2f}%")
    print(f"Sum of original: {np.sum(coefficients):.6f}")
    print(f"Sum of quantized: {np.sum(reconstructed):.6f}")

    return quantized

# Example usage
from scipy import signal
coefficients = signal.firwin(17, 0.3, window='hamming')
quantized = analyze_quantization(coefficients, coef_fract_bits=15)
print("\nQuantized coefficients:")
print(", ".join(str(c) for c in quantized))