1. 项目缘起:为什么我要用FPGA+STM32搭一套相控阵雷达原型
PLFM_RADAR 这个标题,第一次看到的人大概率会愣一下。PLFM 是 Pulse Linear Frequency Modulation 的缩写,也就是脉冲线性调频信号,业内更习惯叫它 LFM 或者 chirp 信号。RADAR 就不用解释了。合起来,这个项目本质上是一套基于脉冲压缩体制的相控阵雷达原型验证系统。它要干的事情很明确:发射一个频率随时间线性变化的脉冲,接收回波后做匹配滤波(脉冲压缩),把宽脉冲的能量压缩成一个窄尖峰,从而同时拿到远作用距离和高距离分辨率。
我之所以盯上这个方向,是因为它把几个当下最热的技术点全串起来了:相控阵(phased array)负责波束电扫描,FPGA 负责高速 ADC 采样、数字下变频、匹配滤波和波束形成,STM32 负责系统控制、时序调度、上位机通信和状态机管理。这套组合几乎是现代小型雷达、通信测试终端、边缘网关类产品的标准架构。热词里出现的“arm/fpga边缘网关、通信测试终端”正好印证了这个趋势——ARM 做控制面,FPGA 做数据面,分工清晰。
这套东西适合谁?如果你正在做基于 STM32 的毕业设计想往雷达信号处理方向拔高,或者你是 FPGA 入门后想找一个能真正练手的项目实战,又或者你在做相控阵、通信测试终端相关的预研,那 PLFM_RADAR 这个题目值得你花时间啃下来。它不像纯 FPGA 图像处理那样对视频接口依赖重,也不像纯 STM32 项目那样算力捉襟见肘,它是一个软硬协同、能让你把“采样—处理—控制—通信”整条链路走通的综合性项目。
我下面要讲的,不是一份照本宣科的说明书,而是我自己在搭这套系统时踩过的坑、做过的取舍、以及那些文档里不会写的经验。核心关键词 phased array、RADAR、FPGA、STM32 会贯穿始终,你跟着思路走,基本能复现出一套可用的原型。
2. 整体架构设计与方案选型:为什么这么分工
2.1 系统级框图与数据流走向
先把整个系统的骨架说清楚。PLFM_RADAR 原型大致分四块:天线与射频前端、高速采集与信号处理(FPGA 域)、系统控制与调度(STM32 域)、上位机显示与交互。
数据流是这样的:STM32 发出一个发射触发信号,同时把 chirp 参数(带宽、脉宽、PRF)通过 SPI 或并口下发给 FPGA 内部的 DDS 或直接送给外部 DAC;射频前端把 LFM 信号上变频、放大后经相控阵天线辐射出去。回波经天线接收、低噪放、下变频到中频,送入高速 ADC。FPGA 抓取 ADC 数据,做数字下变频(DDC)、抽取、匹配滤波(脉冲压缩)、以及多通道的波束形成加权求和。处理完的距离-多普勒数据通过高速接口(比如千兆网或 USB)传给 STM32 或直接上传上位机。STM32 这边负责整个时序:PRF 定时、收发切换、通道增益控制、温度监控、以及与上位机的协议解析。
为什么这么分?因为 FPGA 擅长的是确定性、并行、流水线式的数据处理,你让它去跑一个复杂的协议栈或者人机交互逻辑,那是折磨它。STM32 擅长的是控制流、中断响应、外设管理,你让它去做 100MHz 采样率的实时匹配滤波,它算不过来。所以“FPGA 做数据面,STM32 做控制面”是这类系统最经济也最稳妥的分工。
2.2 为什么选 LFM 脉冲压缩而不是简单脉冲
很多人入门雷达喜欢用简单脉冲测距,发一个窄脉冲,测回波延时。问题是窄脉冲能量低,作用距离上不去;想加大能量就得加宽脉冲,但宽脉冲的距离分辨率又差。LFM 脉冲压缩就是来解决这个矛盾的:发射一个宽脉冲(能量大,作用距离远),但脉冲内部频率在扫,接收端用一个匹配滤波器(本质是卷积一个共轭翻转的参考 chirp),把宽脉冲压缩成窄尖峰。压缩后的脉宽约等于 1/B(B 是带宽),所以距离分辨率由带宽决定,跟发射脉宽解耦了。
这个选择直接决定了 FPGA 里必须实现一个匹配滤波器。匹配滤波在频域做就是 FFT—复乘—IFFT,在时域做就是卷积。对于中小规模 FPGA,时域卷积用 FIR 结构更省资源,尤其是当参考 chirp 点数不多的时候。我实测下来,如果带宽 10MHz、采样率 40MHz、脉宽 20us,参考信号大约 800 点,用分布式算法(DA)或者对称系数的 FIR 核都能吃下来。
2.3 相控阵通道数与波束形成的取舍
相控阵的核心是多个天线单元,通过控制每个通道的相位(移相器)来实现波束指向的电扫描。原型阶段不可能一上来就做 64 通道,成本和技术难度都扛不住。我的建议是先从 4 通道或者 8 通道做起,验证波束形成算法和通道间幅相一致性校准。
波束形成在 FPGA 里就是加权求和:每个通道的数据乘以一个复数权重(幅度+相位),然后累加。权重由 STM32 根据目标波束指向计算好,通过寄存器写入 FPGA。这里有个关键点:通道间的相位一致性必须校准,否则波束会畸变。校准方法后面会细讲。
选 4 通道的理由很实际:ADC 通道数少,FPGA 的 IO 和逻辑资源压力小;天线阵列尺寸可控,暗室测试或者近场测试都方便;算法验证够了,扩展到大阵列只是复制通道的事。
3. 核心细节解析:FPGA 与 STM32 各自的关键技术点
3.1 FPGA 侧:高速 ADC 采样与 LVDS 接收
热词里“fpga 高速 ADC 采样”和“fpga 的 lvds 接收”是绕不开的。雷达中频采样一般用 40MHz 到 125MHz 的 ADC,输出接口常见的是 LVDS 或者 CMOS。LVDS 的好处是抗干扰强、速率高,但代价是 FPGA 端要做源同步接收,得处理随路时钟和数据对齐。
具体做法:ADC 输出一对随路时钟(DCO)和数据(D0...Dn),FPGA 用 IDDR 原语或者 ISERDES 把双沿数据拆成单沿,再用 DCO 的相位去采样。这里最容易翻车的地方是时序约束没写对。你必须给 DCO 和数据的输入延迟做约束,否则综合出来的采样点可能落在数据跳变沿上,误码率飙升。我一般会在 Vivado 里用 set_input_delay 配合 ADC 手册给的 tsu/th 参数来算,然后跑时序报告确认建立保持余量。
采样率的选择也有讲究。根据奈奎斯特,采样率至少是信号最高频率的两倍。但雷达中频通常有带宽,比如中频 60MHz、带宽 10MHz,那信号频率范围是 55~65MHz。这时候可以用带通采样,采样率只要大于 2B(20MHz)就能无混叠恢复,我常用 40MHz 或 50MHz。这样 FPGA 的处理时钟压力小很多。
3.2 FPGA 侧:数字下变频与匹配滤波实现
ADC 采回来的是实信号,做脉冲压缩前一般要先数字下变频(DDC)变成复基带。DDC 就是乘以一个本地振荡的复指数 e^(-j2πf0n),然后低通滤波抽取。FPGA 里实现就是两路乘法器(I/Q),本振用 DDS 产生,低通用 CIC 或者半带滤波器。
匹配滤波我倾向用频域做,尤其是参考信号点数多的时候。流程是:对接收数据做 FFT,对参考 chirp 做 FFT 并取共轭,两者复乘,再 IFFT。Xilinx 和 Altera 都有 FFT IP 核,配置成流水线模式,吞吐率能跟上。但要注意 FFT 的点数必须是 2 的幂,如果数据长度不是,得补零。补零会带来处理增益损失,但影响可控。
如果资源紧张,时域 FIR 也行。参考 chirp 是对称的(实部对称),可以用折叠结构省一半乘法器。我试过用 16 位系数、800 阶的 FIR,在 Artix-7 上跑 40MHz 时钟,DSP48 用了大概 60 个,还能接受。
3.3 STM32 侧:系统时序与 USB 设备通信
STM32 在这个项目里是“大脑”,不是“肌肉”。它要干的事包括:产生 PRF 定时中断、控制收发开关、通过 SPI 配置 FPGA 寄存器、读取温度/功率检波、以及和上位机通信。
热词里“stm32 如何做 usb 设备”很关键。上位机要实时看雷达回波,用串口太慢,USB 全速 12Mbps 勉强,USB 高速 480Mbps 才够。STM32F4/F7/H7 系列自带 USB OTG,可以配置成 CDC 或者自定义 Bulk 设备。我一般用 CubeMX 生成 USB Device 框架,选 CDC 类做调试,数据量大时改成自定义 Bulk 端点,配合双缓冲。
这里有个坑:USB 中断优先级和 PRF 定时中断的优先级要排好。PRF 定时是硬实时的,不能被 USB 传输阻塞。我的做法是 PRF 中断里只置标志、触发 FPGA 采集,数据处理和 USB 发送放到主循环或者低优先级任务里。用 DMA 搬 USB 数据,CPU 少掺和。
3.4 STM32 侧:定时器模式与精确 PRF 生成
“stm32 定时器模式”这个热词用在这里太贴切了。PRF 的精度直接影响雷达测距和测速的准确性。我用 TIM 的高级定时器,配置成 PWM 输出模式,周期由 ARR 决定,占空比由 CCR 决定。比如要 10kHz PRF,定时器时钟 168MHz,预分频 0,ARR 就是 16800-1。
更讲究一点,可以用定时器的单脉冲模式(One Pulse Mode)配合外部触发,这样每个 PRF 周期只发一个脉冲,收发切换更干净。收发切换用另一个定时器通道控制射频开关,注意留够切换死区时间,一般几百纳秒,防止发射泄漏烧掉接收前端。
4. 实操过程:从零搭建 PLFM_RADAR 原型
4.1 硬件选型与连接清单
先说硬件。FPGA 我选的是 Xilinx Artix-7 或者安路 EG4 系列,逻辑资源够用,价格友好。热词里“黑金 fpga”“安路 fpga 仿真”说明这两家在国内入门圈很流行,资料也多。ADC 用 AD9226 或者 AD9238,12 位、40~65MSPS,LVDS 或 CMOS 输出。STM32 用 F407 或者 H743,带 USB OTG 和足够多的定时器。
射频前端这块,原型阶段可以用现成的混频器(比如 AD8347)加 PLL(ADF4351)搭。天线用 4 单元微带贴片阵列,间距半波长。移相器如果预算有限,可以用 FPGA 控制 DAC 去调 I/Q 调制器的偏置,实现相位控制,虽然精度不如专用移相器,但验证算法够了。
连接上要注意:ADC 的时钟必须和 FPGA 的采样时钟同源,否则会有采样抖动。我一般用一个时钟芯片(比如 LMK 系列)同时给 ADC 和 FPGA 供时钟,保证相位确定。
4.2 FPGA 工程搭建:从 testbench 到综合
“fpga 如何正确写 testbench”是入门者的高频问题。我的经验是,testbench 不要一上来就写复杂的激励,先把时钟和复位跑起来,确认模块能正常复位。然后给一个已知的 chirp 输入,看匹配滤波输出是不是在预期位置出现尖峰。
具体步骤:先用 MATLAB 生成参考 chirp 和回波数据,量化成 12 位,存成 .txt 或者 .coe 文件。testbench 里用 $readmemh 读入,打一拍一拍喂给 DUT。输出用 $fwrite 写到文件,再回 MATLAB 画图对比。这样能快速定位是算法问题还是 RTL 问题。
综合时注意时序约束。除了前面说的 ADC 输入延迟,还要给跨时钟域的信号加 set_false_path 或者 set_max_delay。DDC 里从 ADC 时钟域到处理时钟域的切换,一定要用异步 FIFO,别直接打两拍就完事,数据位宽大时打拍会丢数据。
4.3 STM32 工程搭建:从芯片包安装到调试
“stm32 芯片包安装”“vscode 配置 stm32 开发环境”“keil5 兼容 c51 和 stm32 安装”这些热词说明很多人卡在环境搭建上。我的建议是,如果你用 Keil,装好 MDK 后再装对应的 Device Family Pack,别用太老的版本。如果用 VSCode,装 Cortex-Debug 插件,配合 OpenOCD 和 ST-Link,launch.json 里配好 svd 文件路径,调试时能看寄存器。
“vscode stm32 调试 powerlink 如何设置 launch.json”这个具体问题,核心是 servertype 选 openocd 还是 stlink,interface 选 swd,device 填你的芯片型号。我一般用 ST-Link 加 OpenOCD,配置文件里指定 target/stm32f4x.cfg,速度设 4000kHz,稳。
工程结构上,我习惯把 FPGA 驱动、USB 协议、定时器控制分成独立 .c 文件,头文件里用宏定义寄存器地址。这样换 FPGA 型号时只改驱动层,上层逻辑不动。
4.4 联调与波束形成校准实操
联调是最考验耐心的环节。先把发射链路单独测:用频谱仪看 LFM 信号的带宽和脉宽对不对。再把接收链路单独测:信号源给一个已知延迟的脉冲,看 FPGA 输出的压缩峰值位置对不对。
波束形成校准是相控阵的命门。方法:在远场放一个信号源,所有通道同时接收,采集各通道的 I/Q 数据,算通道间的相位差。然后把这个相位差作为补偿值写入 FPGA 的权重寄存器。幅度校准类似,用各通道幅度归一化。校准后,波束指向应该和理论计算一致,副瓣电平也要看,一般要求低于主瓣 13dB 以上。
我踩过的坑:校准用的信号源频率必须和雷达工作频率一致,否则移相器的相位响应非线性会导致校准失效。还有,校准要在温度稳定后进行,射频器件的相位随温度漂移,冷机校准热机用,波束会偏。
5. 常见问题与排查技巧实录
5.1 FPGA 侧典型问题速查
| 现象 | 可能原因 | 排查方法 | 解决 |
|---|---|---|---|
| ADC 采样数据全 0 或全 1 | LVDS 时钟未对齐 | 用 ILA 抓 DCO 和数据 | 调整 IDELAY 或改约束 |
| 匹配滤波输出无尖峰 | 参考信号共轭没取 | 对比 MATLAB 中间结果 | 检查 FFT 后是否 conj |
| 时序不收敛 | 跨时钟域路径未约束 | 看时序报告 | 加异步 FIFO 或 false_path |
| FFT IP 核输出乱序 | 没按自然顺序输出 | 查 IP 配置 | 选自然顺序或加排序模块 |
| 资源不够 | FIR 阶数太高 | 看综合报告 | 改频域实现或降采样 |
“fpga 有固定的复位脚吗”这个问题也常被问。答案是没有,FPGA 的复位是逻辑复位,你可以在任意引脚上定义复位输入,也可以在内部用 PLL 锁定信号生成复位。我一般用外部按键加内部上电复位电路,保证可靠。
5.2 STM32 侧典型问题速查
“stm32 延时函数 delay 卡死”是新手重灾区。原因通常是 SysTick 中断优先级被其他中断抢占,或者 delay 里用了未初始化的变量。我的做法是 delay 用 DWT 周期计数器实现,不依赖中断,绝对不卡。
“stm32 禁用 jtag”是为了释放 PA13/PA14/PA15/PB3/PB4 做普通 IO。用 HAL 库的话,在 GPIO 初始化前调用 __HAL_AFIO_REMAP_SWJ_DISABLE() 或者配置选项字节。注意禁用 JTAG 后只能用 SWD 下载,别把自己锁外面。
“stm32 定时器捕获测频率”和“stm32 定时器模式”相关。测外部信号频率用输入捕获模式,配置成 PWM 输入模式能同时测频率和占空比。注意捕获中断里别做耗时操作,否则高频信号会丢捕获。
5.3 系统级联调避坑心得
第一个坑:电源噪声。FPGA 和 ADC 的电源必须干净,尤其是 ADC 的模拟电源,要用 LDO 单独供,数字地和模拟地单点连接。我见过因为电源纹波导致 ADC 有效位数掉 2 位的案例。
第二个坑:收发隔离。发射时接收前端必须关断或者加限幅器,否则强信号灌进 LNA 会烧。收发切换开关的响应时间要算进时序,别 PRF 周期太短导致开关来不及动作。
第三个坑:时钟抖动。雷达对时钟相位噪声敏感,尤其是相参积累时。晶振选低相噪的,PLL 环路带宽别设太宽。
第四个坑:上位机数据吞吐。USB 传雷达原始数据量很大,如果上位机处理不过来会丢包。我的做法是 FPGA 里先做一级抽取或者门限检测,只传过门限的点,数据量降一个数量级。
6. 写在最后:一些个人体会和扩展方向
这套 PLFM_RADAR 原型我从画板子到联调跑通,断断续续花了小半年。最大的体会是,雷达这东西,算法仿真和硬件实现之间隔着一道鸿沟。MATLAB 里脉冲压缩干净利落,到了 FPGA 里,量化噪声、时钟抖动、通道不一致全冒出来。所以别指望一次成功,留足调试时间。
如果后续要扩展,我建议往几个方向走:一是增加通道数到 8 或 16,验证数字波束形成的自适应算法;二是把 STM32 换成带以太网的型号,用 UDP 传数据,带宽比 USB 大;三是在 FPGA 里加 CFAR 检测,把检测结果而不是原始数据传给上位机,减轻后端压力。热词里“fpga 网卡测速程序”“arm/fpga 边缘网关”其实和这个思路一脉相承——把智能往边缘推。
最后分享一个小技巧:调试匹配滤波时,先在 FPGA 里做一个简单的峰值检测,把峰值位置和幅度通过串口打印出来,比抓 ILA 波形快得多。等算法验证通过了,再上 ILA 看细节。这个顺序能帮你省下大量时间。