CFAR Detection Algorithms (CA, GO, SO) in FPGA vs Software: A Complete Implementation Guide

The PLFM_RADAR project implements Cell-Averaging (CA), Greatest-Of (GO), and Smallest-Of (SO) CFAR detectors in both fixed-point FPGA hardware and floating-point Python software, with bit-accurate matching between the two.

Constant-False-Alarm-Rate (CFAR) detection is essential for reliable target detection in radar systems. The NawfalMotii79/PLFM_RADAR repository provides a production-ready dual implementation that lets engineers run real-time detection on FPGA hardware while developing and validating algorithms in Python.


Signal Chain Integration

Both implementations process the same radar signal chain, but at different stages:

Stage FPGA Implementation Software Implementation
Location Integrated in RTL pipeline after DC-notch Post-processing on Power (
Chain quantize → range_fft → decimator → MTI → doppler_fft → dc_notch → **CFAR** → RadarFrame Same chain via cfar_2d call after optional MTI/DC-notch

In software_fpga.py lines 9-11, the FPGA pipeline shows CFAR as a fixed hardware stage. The software equivalent in processing.py lines 62-78 allows optional insertion of CFAR as a configurable post-processing step.


Configurable Parameters and Register Map

Both implementations share identical configuration parameters, exposed through memory-mapped registers in the FPGA and Python attributes in software.

FPGA Register Addresses

Defined in radar_protocol.py and exposed via UART:

  • CFAR_GUARD (0x21) — guard cell count
  • CFAR_TRAIN (0x22) — training cell count
  • CFAR_ALPHA (0x23) — Q4.4 fixed-point scaling factor
  • CFAR_MODE (0x24) — mode selector (0=CA, 1=GO, 2=SO)
  • CFAR_ENABLE (0x25) — on/off flag

Reference: dashboard.py lines 759-762.

Software Configuration Object

The same parameters in Python (software_fpga.py lines 62-84):

cfar_guard_cells      # matches CFAR_GUARD

cfar_training_cells   # matches CFAR_TRAIN

cfar_alpha_q44        # matches CFAR_ALPHA (Q4.4 format)

cfar_mode             # 0/1/2 for CA/GO/SO

cfar_enabled          # boolean flag

This parity ensures that register writes to hardware and attribute changes in software produce identical detection behavior.


Algorithmic Core: Three CFAR Modes

The repository implements three classical CFAR variants:

Mode Algorithm Best For
CA-CFAR Cell-Averaging: mean of all training cells Homogeneous clutter
GO-CFAR Greatest-Of: maximum of leading/trailing window means Multiple targets, clutter edges
SO-CFAR Smallest-Of: minimum of leading/trailing window means Interfering targets

FPGA Implementation

The bit-accurate model in software_fpga.py uses _CFAR_MODE_MAP to select between run_cfar_ca, run_cfar_go, and run_cfar_so (lines 62-64). These functions replicate the fixed-point RTL arithmetic using Q-format scaling.

Software Implementation

The processing.cfar_1d function supports all three modes plus OS-CFAR (Ordered Statistic) via a simple if/elif cascade at lines 91-98:


# From processing.py lines 91-98

if cfar_type == "CA-CFAR":
    noise_est = np.mean(training_cells)
elif cfar_type == "GO-CFAR":
    noise_est = max(np.mean(leading), np.mean(trailing))
elif cfar_type == "SO-CFAR":
    noise_est = min(np.mean(leading), np.mean(trailing))

Numerical Precision and Performance

Aspect FPGA Software
Data type Fixed-point Q-format float64 NumPy arrays
Timing Deterministic, <100 µs per frame Unconstrained, host-dependent
Resource use Optimized for Xilinx fabric Unlimited memory/processing
Use case Real-time embedded radar Development, validation, prototyping

The FPGA's fixed-point arithmetic is cycle-accurate to the RTL and processes one frame per clock cycle per pipeline stage. The software version prioritizes clarity and debugging flexibility over real-time performance.


Practical Code Examples

Running Software CFAR Pipeline

from processing import RadarProcessor

# Configure detection parameters

proc = RadarProcessor(
    cfar_enabled=True,
    cfar_guard_cells=2,
    cfar_training_cells=8,
    cfar_alpha_q44=0x30,          # Q4.4 = 3.0

    cfar_type="GO-CFAR",          # "CA-CFAR", "GO-CFAR", "SO-CFAR", "OS-CFAR"

)

# Process 2-D range-Doppler map

processed_rdm, detections = proc.process_frame(raw_frame)

# detections: boolean mask for target locations

Programming FPGA-Equivalent Model

from software_fpga import SoftwareFPGA

fpga = SoftwareFPGA()

# Write equivalent of UART register settings

fpga.set_cfar_enable(True)
fpga.set_cfar_guard(2)
fpga.set_cfar_train(8)
fpga.set_cfar_alpha(0x30)       # Q4.4 fixed-point

fpga.set_cfar_mode(2)           # 2 → SO-CFAR

# Generate frame identical to hardware output

frame = fpga.process_chirps(iq_i, iq_q, frame_number=0)

Mode Comparison in Software


# CA-CFAR: average of all training cells

proc.cfar_type = "CA-CFAR"
r1, d1 = proc.process_frame(raw_frame)

# GO-CFAR: maximum noise estimate (better for clutter edges)

proc.cfar_type = "GO-CFAR"
r2, d2 = proc.process_frame(raw_frame)

# d1 and d2 differ: CA is more sensitive in uniform clutter,

# GO reduces false alarms at clutter boundaries

Key Source Files

File Purpose Critical Functions/Lines
9_Firmware/9_3_GUI/v7/software_fpga.py Bit-accurate FPGA model _CFAR_MODE_MAP, run_cfar_*, lines 62-84
9_Firmware/9_3_GUI/v7/processing.py Host-side CFAR implementation cfar_1d, mode selection lines 91-98
9_Firmware/9_3_GUI/radar_protocol.py Register address definitions CFAR_GUARD, CFAR_MODE, etc.
9_Firmware/9_2_FPGA/tb/cosim/real_data/golden_reference.py RTL verification reference Hardware-accurate CFAR functions
9_Firmware/9_3_GUI/v7/dashboard.py Real-time GUI control Register write interface, lines 759-762

When to Use Each Implementation

  • FPGA hardware: Deployed systems requiring guaranteed latency, low power, and continuous operation in embedded environments

  • Software model (software_fpga.py): Pre-hardware verification, cosimulation with RTL, regression testing against golden references

  • Host processing (processing.py): Algorithm research, rapid iteration on CFAR variants, offline data analysis, generating training datasets

The dual implementation strategy allows the PLFM_RADAR project to maintain a single source of truth for CFAR parameters while optimizing for completely different execution environments.


Summary

  • The PLFM_RADAR repository provides bit-accurate matching between FPGA and Python CFAR implementations
  • Three modes (CA, GO, SO) are selectable via unified configuration parameters across both platforms
  • Fixed-point Q-format arithmetic in the FPGA ensures deterministic real-time performance
  • Floating-point NumPy operations in software enable rapid prototyping and algorithm development
  • Shared register map (CFAR_GUARD, CFAR_TRAIN, CFAR_ALPHA, CFAR_MODE, CFAR_ENABLE) guarantees identical behavior between hardware and simulation

Frequently Asked Questions

How do I switch between CA-CFAR and GO-CFAR in the PLFM_RADAR implementation?

Set the cfar_mode register to 0 for CA-CFAR or 1 for GO-CFAR. In Python, use fpga.set_cfar_mode(1) or assign proc.cfar_type = "GO-CFAR". The mode change takes effect immediately on the next processed frame.

What is the Q4.4 format used for cfar_alpha_q44?

Q4.4 is a fixed-point representation with 4 integer bits and 4 fractional bits. The value 0x30 equals 3.0 (0x30 >> 4 = 3). This format allows efficient hardware multiplication without floating-point units.

Can the software implementation process data in real time like the FPGA?

No. The Python implementation uses float64 NumPy arrays for clarity and is not optimized for real-time performance. For real-time operation, use the FPGA hardware or implement the fixed-point logic in a compiled language.

Why does the FPGA implementation use smallest-of (SO) CA-CFAR as an option?

SO-CFAR selects the minimum of leading and trailing window noise estimates. This prevents target suppression when an interfering target appears in only one side of the training window—particularly valuable in dense target environments with the PLFM_RADAR hardware.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →