# FPGA Signal Processing Chain Architecture for Pulse Compression and CFAR Detection

> Explore the FPGA signal processing chain architecture for pulse compression and CFAR detection. Learn how the AERIS-10 radar achieves calibrated target detections with range-Doppler processing.

- Repository: [NawfalMotii79/PLFM_RADAR](https://github.com/NawfalMotii79/PLFM_RADAR)
- Tags: architecture
- Published: 2026-08-20

---

**The AERIS-10 radar implements a deterministic, register-controlled pipeline in its FPGA that converts raw 16-bit I/Q ADC samples into calibrated target detections via range-Doppler processing and constant-false-alarm-rate (CFAR) detection.**

This article examines the complete signal processing architecture implemented in the NawfalMotii79/PLFM_RADAR repository, which provides a bit-accurate Python replica of the FPGA signal chain alongside the VHDL hardware implementation. The design emphasizes deterministic latency and host configurability, with every processing stage—from quantization through CFAR detection—exposed via memory-mapped registers defined in the hardware abstraction layer.

## Deterministic Processing Pipeline Overview

The FPGA signal chain follows a strictly ordered pipeline defined in [`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py) (lines 9–12), processing each chirp through seven distinct stages before outputting a populated `RadarFrame`. This deterministic flow mirrors the exact RTL implementation in the AERIS-10 firmware.

### Quantization Stage

Processing begins with **16-bit signed I/Q samples** produced by the ADC-DDC (Analog-to-Digital Converter with Digital Down-Conversion) front end. The hardware expects this specific format, and the reference Python implementation uses `quantize_raw_iq()` to convert floating-point captures into the fixed-point representation required by the FPGA datapath.

### Range FFT and Pulse Compression

The **Range FFT** stage (`run_range_fft`) performs pulse compression via fast-Fourier-transform processing on each incoming chirp. The implementation uses pre-computed twiddle factors loaded from `fft_twiddle_1024.mem`, executing a 1024-point complex FFT that transforms time-domain samples into range-profile bins.

Following the FFT, the **Range Bin Decimator** (`run_range_bin_decimator`) reduces the 1024-point spectrum down to 64 range bins, effectively compressing the data volume while preserving target information across the desired unambiguous range.

### Clutter Suppression and Doppler Processing

Before extracting velocity information, the chain applies an **MTI Canceller** (`run_mti_canceller`) to remove stationary clutter via digital filtering. This two-pulse canceller (or equivalent high-pass filter) eliminates ground returns and stationary objects prior to Doppler analysis.

The **Doppler FFT** stage (`run_doppler_fft`) then computes the range-Doppler map using dual 16-point FFTs with Hamming windowing. The twiddle factors for this stage reside in `fft_twiddle_16.mem`, enabling coherent integration across chirps to resolve target velocity.

### DC Notch Filtering

Immediately following Doppler processing, the **DC Notch** stage (`run_dc_notch`) zero-writes bins around DC to suppress local oscillator leakage and direct current offsets that manifest as strong returns at zero Doppler.

## CFAR Detection Architecture

The final stage implements a **Constant-False-Alarm-Rate (CFAR) Detector** (`run_cfar_ca`) that adaptively thresholds the range-Doppler map to maintain consistent detection performance despite varying noise floors. This module is a bit-accurate replica of the VHDL module `cfar_ca.v`.

### Algorithm Implementation

As detailed in [`golden_reference.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/golden_reference.py) (lines 21–27), the CFAR processor operates on a column-wise basis with the following mathematical operations:

- **Magnitude Computation**: The algorithm computes the L1 norm (|I| + |Q|) to generate a 17-bit unsigned magnitude value for each cell under test (CUT), avoiding the resource cost of a full CORDIC-based magnitude calculation.

- **Cell Averaging Strategy**: The detector supports three configurable modes controlled by a 2-bit register field (0 = CA, 1 = GO, 2 = SO) mapped via `_CFAR_MODE_MAP` in [`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py) (lines 62–64):
  - **CA (Cell Averaging)**: Sums both leading and lagging training cells.
  - **GO (Greatest Of)**: Selects the side with the larger average.
  - **SO (Smallest Of)**: Selects the side with the smaller average.

- **Threshold Scaling**: The noise estimate undergoes multiplication by the **Q4.4 alpha factor** (α), followed by a 4-bit right shift. The result saturates to 17 bits to prevent overflow while maintaining precision.

- **Binary Detection**: The CUT is flagged as a target when its magnitude exceeds the computed adaptive threshold.

### Register Configuration Interface

Each processing stage is toggleable and configurable via the FPGA register map defined in [`radar_protocol.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/radar_protocol.py) (lines 85–89). This allows real-time parameter adjustment without re-synthesizing the bitstream.

```python

# Example: Running the full FPGA chain on a captured IQ file

import numpy as np
from 9_Firmware.9_3_GUI.v7.software_fpga import SoftwareFPGA, quantize_raw_iq

# Load a raw complex IQ capture (e.g., from an SDR)

raw_iq = np.load('capture.npy')           # shape (chirps, samples), complex64

# Quantize to the 16-bit format used by the FPGA

iq_i, iq_q = quantize_raw_iq(raw_iq)

# Instantiate the software replica and enable CFAR

fpga = SoftwareFPGA()
fpga.set_cfar_enable(True)               # turn on CFAR detection

fpga.set_cfar_mode(0)                    # CA-CFAR (mode code 0)

# Process the chirps – returns a RadarFrame with detections

frame = fpga.process_chirps(iq_i, iq_q, frame_number=1, timestamp=12.34)

print('Detections:', frame.detection_count)
print('CFAR mask shape:', frame.detections.shape)

```

The `SoftwareFPGA` class provides register-equivalent methods that mirror the hardware control interface, enabling bit-accurate simulation of the FPGA behavior before hardware deployment.

## Real-Time Parameter Adjustment

The architecture supports dynamic reconfiguration of detection parameters through the host interface exposed in [`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py). This capability is essential for adapting to changing clutter environments or target Radar Cross Section (RCS) characteristics.

```python

# Example: Adjusting CFAR parameters on-the-fly

fpga.set_cfar_guard(3)       # increase guard cells

fpga.set_cfar_train(12)      # increase training cells

fpga.set_cfar_alpha(0x40)    # α = 4.0 (Q4.4 format)

# Re-run processing with new parameters

frame2 = fpga.process_chirps(iq_i, iq_q)
print('New detection count:', frame2.detection_count)

```

The complete processing pipeline—from raw IQ quantization through the final CFAR detection mask—is encapsulated in [`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py) (lines 49–57). The resulting `RadarFrame` object contains the range-Doppler I/Q matrix, magnitude map, detection mask, range profile, and detection count, making it directly consumable by [`GUI_V7_PyQt.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/GUI_V7_PyQt.py) for visualization and further analytics.

## Summary

- The AERIS-10 FPGA implements a deterministic seven-stage signal processing chain: **Quantization → Range FFT → Decimation → MTI Canceller → Doppler FFT → DC Notch → CFAR Detector**.
- Pulse compression occurs in the **1024-point Range FFT** stage, followed by decimation to 64 range bins and Hamming-windowed **16-point Doppler FFT** processing.
- The **CFAR detector** supports CA, GO, and SO variants with configurable training cells, guard cells, and Q4.4 alpha scaling, implementing bit-accurate L1 magnitude detection as defined in [`golden_reference.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/golden_reference.py).
- The **Python software replica** in [`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py) provides a cycle-accurate mirror of the VHDL implementation, enabling offline algorithm verification and automated testing via the same register interface used by the hardware GUI.

## Frequently Asked Questions

### How does the FPGA handle the transition from pulse compression to target detection?

The pipeline transitions seamlessly from the Range FFT (pulse compression) through the MTI canceller and Doppler FFT stages to generate a range-Doppler map. The CFAR detector then processes this map column-wise, applying adaptive thresholding based on local noise estimates derived from configurable training and guard cells. Each stage is controlled via registers defined in [`radar_protocol.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/radar_protocol.py), allowing the host to enable or disable specific processing elements without interrupting the data flow.

### What is the significance of the Q4.4 format in the CFAR alpha parameter?

The **Q4.4 format** represents a fixed-point number with 4 integer bits and 4 fractional bits, providing a dynamic range of 0.0 to 15.9375 with 1/16 precision. In the CFAR implementation, the alpha scaling factor multiplies the summed training cell magnitudes (the noise estimate) before right-shifting by 4 bits to achieve the desired threshold scaling factor. This approach eliminates floating-point hardware requirements while maintaining sufficient granularity for typical radar detection applications.

### Can the processing chain operate without the MTI canceller enabled?

Yes, the **MTI canceller** is toggleable via FPGA registers. When disabled, the pipeline bypasses the clutter suppression stage and passes raw range-profile data directly to the Doppler FFT. This mode is useful for ground-based surveillance or when analyzing stationary target indication is required, though it increases the false alarm rate in environments with significant stationary clutter returns.

### Where is the bit-accurate golden reference for the VHDL modules located?

The reference implementations for all FPGA processing stages, including the cell-averaging CFAR detector with exact L1 magnitude computation and training cell logic, reside in [`golden_reference.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/golden_reference.py) within the cosimulation testbench directory (`9_Firmware/9_2_FPGA/tb/cosim/real_data/`). This file serves as the verification standard against which the synthesizable VHDL (`cfar_ca.v`) and the Python software model ([`software_fpga.py`](https://github.com/NawfalMotii79/PLFM_RADAR/blob/main/software_fpga.py)) are validated.