Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PYNQ-Z2 FMCW Radar Signal Processing Pipeline

Hardware-accelerated FMCW (Frequency-Modulated Continuous-Wave) radar signal processing on the PYNQ-Z2 (Xilinx Zynq XC7Z020) FPGA platform. The full range-Doppler processing chain is implemented as a streaming AXI4-Stream pipeline in programmable logic, driven from Python via the PYNQ framework.

Signal Processing Pipeline

AXI DMA ──► Windowing ──► Range FFT ──► 2D Corner-Turn Buffer ──► Windowing ──► Doppler FFT ──► AXI DMA
 (MM2S)      (Hanning)    (256-pt)        (256×256 BRAM)           (Hanning)    (256-pt)        (S2MM)
              fast-time    Radix-2 DIT     Row→Column transpose     slow-time    Radix-2 DIT

All IPs are connected via 32-bit AXI4-Stream and controlled through AXI4-Lite registers. Data flows through the chain without processor intervention—only the DMA transfers at the endpoints touch DDR memory.

Radar Parameters

Parameter Value
Carrier frequency 77 GHz
Chirp bandwidth 150 MHz
Sampling rate 100 MHz
Fast-time samples per chirp 256
Slow-time chirps per frame 256
Chirp duration 2.56 µs
Max unambiguous range ~100 m
Range resolution 1.0 m
Max unambiguous velocity ~±128 m/s

Data Format

All IPs use a unified 32-bit packed complex format:

Bit [31:16]  →  16-bit signed real  (Q8.8 fixed-point, ap_fixed<16,8>)
Bit [15: 0]  →  16-bit signed imag  (Q8.8 fixed-point, ap_fixed<16,8>)

TLAST is asserted on the last sample of each 256-sample vector.

Repository Structure

PYNQ_Z2_FMCW_Radar/
├── Windowing/           # 256-point Hanning Window HLS IP
│   ├── src/
│   │   ├── windowing.h
│   │   ├── windowing.cpp
│   │   └── windowing_tb.cpp
│   ├── run_hls.tcl
│   └── Windowing/       # Vitis HLS project outputs (solution1/)
│
├── FFT/                 # 256-point Radix-2 DIT FFT HLS IP
│   ├── src/
│   │   ├── fft.h
│   │   ├── fft.cpp
│   │   └── fft_tb.cpp
│   ├── run_hls.tcl
│   └── FFT/             # Vitis HLS project outputs (solution1/)
│
├── Buffer/              # 256×256 2D Corner-Turn Buffer HLS IP
│   ├── src/
│   │   ├── buffer.h
│   │   ├── buffer.cpp
│   │   └── buffer_tb.cpp
│   ├── run_hls.tcl
│   └── Buffer/          # Vitis HLS project outputs (solution1/)
│
├── python/              # Beat-signal generation & Python-only processing
│   ├── fmcw_generate.py    # Simulates 3-target FMCW beat signal
│   ├── fmcw_process.py     # Range-Doppler processing + CA-CFAR detection
│   ├── beat_signal_complex.npy
│   ├── beat_signal_ddr.npy
│   ├── beat_signal_ddr_q8.npy
│   └── radar_params.npy
│
├── notebooks/           # PYNQ Jupyter notebooks & overlay driver
│   ├── fmcw_radar.ipynb     # End-to-end demo on PYNQ-Z2
│   └── fmcw_pipeline.py     # Overlay driver (DMA, IP control, post-processing)
│
└── README.md

HLS IP Cores

All three IPs target the xc7z020clg400-1 at 100 MHz and are built with Vitis HLS 2025.1/2025.2. Each exposes:

  • AXI4-Stream slave (in_stream) and master (out_stream) — 32-bit TDATA
  • AXI4-Lite (s_axi_control) — AP_CTRL, interrupt registers

Windowing — Hanning Window

Top function windowing
Operation Multiplies each complex sample by a precomputed 256-point Hanning coefficient
Coefficients ap_fixed<16,2> stored in ROM (14 fractional bits for [0, 1])
Optimization DATAFLOW (read → apply_window → write)
Latency 778 cycles (7.78 µs) per 256-sample vector
Resources 5 BRAM (1%), 2 DSP (<1%), 335 LUT (<1%), 229 FF (<1%)

FFT — 256-Point Radix-2 DIT

Top function fft
Operation Bit-reversal permutation → 8 butterfly stages with precomputed twiddle factors
Twiddle factors ap_fixed<16,2> ROM tables (cos/sin), 128 entries each
Internal precision ap_fixed<24,12> accumulator (4-bit headroom over Q8.8)
Scaling 1/2 per stage → 1/256 (1/N) total
Optimization DATAFLOW (read → bit_reverse → fft_stages → write)
Latency 3,355 cycles (33.55 µs) per 256-sample vector
Resources 12 BRAM (4%), 4 DSP (1%), 1,525 LUT (2%), 839 FF (<1%)

Buffer — 256×256 2D Corner-Turn (Matrix Transpose)

Top function corner_turn
Operation Fills a 256×256 frame row-by-row, then drains column-by-column
Storage Dual-port BRAM, 256 × 256 × 32-bit = 256 KB
Latency 131,082 cycles (1.31 ms) per frame — 65,536 fill + 65,536 drain
Resources 128 BRAM (45%), 0 DSP, 561 LUT (1%), 164 FF (<1%)

Python Software

Beat Signal Generator (python/fmcw_generate.py)

Simulates a complex baseband FMCW beat signal for three targets with configurable range, velocity, and RCS. Outputs:

File Format Description
beat_signal_complex.npy complex128 (256×256) Full-precision floating-point beat signal
beat_signal_ddr.npy uint64 (256×256) Q16.16 packed (32-bit real + 32-bit imag)
beat_signal_ddr_q8.npy uint32 (256×256) Q8.8 packed (16-bit real + 16-bit imag) — pipeline input
radar_params.npy dict All radar/signal parameters for reconstruction

Default simulated targets:

# Range Velocity RCS
1 30 m +10 m/s (approaching) 20 dB
2 75 m −25 m/s (receding) 15 dB
3 120 m +5 m/s (approaching) 10 dB

Signal Processing (python/fmcw_process.py)

Reference Python implementation of the full processing chain:

  1. Hanning windowing (2D: fast-time × slow-time)
  2. Range FFT (fast-time axis)
  3. Doppler FFT (slow-time axis) → Range-Doppler map
  4. 2D CA-CFAR detection with clustering and peak extraction
  5. Visualization — beat signal, range profile, range-Doppler map, CFAR detections (saved to PNG)

PYNQ Overlay Driver (notebooks/fmcw_pipeline.py)

Controls the hardware pipeline on the PYNQ-Z2 board:

  • Loads the bitstream overlay
  • Starts all five IPs in auto-restart mode (AP_START | AUTO_RESTART = 0x81)
  • Sends a full 256×256 frame via AXI DMA (MM2S)
  • Receives 256 × 256-sample chunks via S2MM (Doppler FFT asserts TLAST every 256 samples)
  • Post-processes output into a range-Doppler map with correct axis scaling

IP address map:

IP Base Address
windowing_0 (fast-time) 0x4000_0000
fft_0 (range FFT) 0x4001_0000
corner_turn_0 (2D buffer) 0x4002_0000
windowing_1 (slow-time) 0x4003_0000
fft_1 (Doppler FFT) 0x4004_0000
axi_dma_0 0x4040_0000

Getting Started

Prerequisites

  • PYNQ-Z2 board with PYNQ image
  • Vitis HLS 2025.1+ (for rebuilding IPs)
  • Vivado 2025.1+ (for block design integration)
  • Python 3 with numpy, matplotlib

1. Build HLS IPs

Each IP can be synthesized independently:

cd Windowing && vitis-run --tcl run_hls.tcl && cd ..
cd FFT       && vitis-run --tcl run_hls.tcl && cd ..
cd Buffer    && vitis-run --tcl run_hls.tcl && cd ..

The TCL scripts run the full flow: C simulation → C synthesis → C/RTL co-simulation → IP packaging.

Packaged IPs are exported under <Component>/<Component>/solution1/impl/ip/.

2. Generate Test Data

cd python
python fmcw_generate.py
python fmcw_process.py      # optional: verify processing in software

3. Create Vivado Block Design

  1. Import the three packaged IPs into a Vivado project targeting xc7z020clg400-1
  2. Instantiate the Zynq PS with an HP AXI port
  3. Connect the five processing IPs in a streaming chain via AXI4-Stream (Windowing → FFT → Buffer → Windowing → FFT)
  4. Attach an AXI DMA block (MM2S → first Windowing input, last FFT output → S2MM)
  5. Connect AXI-Lite interfaces to the GP AXI port
  6. Generate bitstream and export .bit / .hwh files

4. Run on PYNQ-Z2

  1. Copy the bitstream (.bit, .hwh) and beat_signal_ddr_q8.npy to the board
  2. Open the Jupyter notebook notebooks/fmcw_radar.ipynb or run:
from fmcw_pipeline import load_overlay, start_pipeline, process_frame, postprocess_range_doppler
import numpy as np

# Load overlay and start IPs
ol, ips = load_overlay("./overlays/fmcw_pipeline.bit")
start_pipeline(ips)

# Load Q8.8 beat signal and process
ddr_data = np.load("beat_signal_ddr_q8.npy")
output, elapsed = process_frame(ips, ddr_data.flatten().astype(np.uint32))

# Post-process into range-Doppler map
params = np.load("radar_params.npy", allow_pickle=True).item()
rd_map, rd_db, range_axis, vel_axis = postprocess_range_doppler(output, params)

Resource Summary (Full Pipeline)

Estimated total resource usage for all five streaming IPs (2× Windowing, 2× FFT, 1× Buffer) on XC7Z020:

Resource Used Available Utilization
BRAM_18K ~162 280 ~58%
DSP48E1 ~12 220 ~5%
LUT ~4,281 53,200 ~8%
FF ~2,210 106,400 ~2%

License

This project is provided for educational and research purposes.

About

Implementation of HIL FMCW Radar Signal Processing on PYNQ-Z2

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages