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 countCFAR_TRAIN (0x22)— training cell countCFAR_ALPHA (0x23)— Q4.4 fixed-point scaling factorCFAR_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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →