1. 项目缘起与整体设计思路
PLFM_RADAR 这个名字拆开看,PLFM 大概率指代的是Pulse Linear Frequency Modulation,也就是脉冲线性调频信号,业内更习惯叫它 LFM 或者“啁啾信号”。RADAR 不用多说,就是雷达。合在一起,这是一个围绕线性调频脉冲雷达展开的工程项目,核心工作大概率落在信号生成、回波采集、数字下变频、脉冲压缩这几个环节上。而热搜词里同时出现了 phased array、FPGA、STM32,基本可以判断出这套系统的分工:FPGA 负责高速信号链——DAC 打波形、ADC 采回波、做实时相关处理;STM32 负责系统控制、人机交互、数据打包上传;相控阵部分则涉及多通道的相位控制与波束合成。
我之所以对这个标题感兴趣,是因为它踩中了几个非常典型的工程交叉点。纯做 FPGA 的人往往不碰射频前端,纯做 STM32 的人又搞不定高速采样,而雷达项目恰好要求你把这两端串起来,中间还得处理时钟同步、触发对齐、数据吞吐这些脏活累活。这套架构在高校实验室、小型科研院所、以及一些工业测距测速场景里非常常见,属于“麻雀虽小五脏俱全”的典型。
先说整体设计思路。雷达系统的第一性原理其实很朴素:发一个已知的信号出去,接收它碰到目标后返回的波形,通过比对收发之间的差异,反推出目标的距离、速度、角度信息。LFM 信号之所以被广泛采用,是因为它有一个极其优雅的性质——大时宽带宽积。简单讲,你可以让脉冲持续足够长以获得足够的能量,同时通过频率调制让它的等效带宽很大,从而在脉冲压缩后得到极高的距离分辨率。用生活化的类比:你喊一嗓子,如果只是短促的一声“嘿”,能量小、听得近,但时间上很精确;如果你拉长成一声“嘿——”,能量大了传得远,但时间上就模糊了。LFM 相当于让你喊出一声音调不断升高的长音,接收端知道这个升调规律,就能把长音“压缩”回一个尖锐的脉冲,既远又准。
在这个项目里,FPGA 承担的角色是确定性时序的执行者。雷达对时序的要求是硬性的,发射触发、ADC 采样窗、脉冲压缩的流水线延迟,这些都不能有抖动。STM32 虽然也有定时器和 DMA,但在纳秒级同步和持续高吞吐场景下力不从心,所以它退居二线做控制面。这个“FPGA 做数据面、STM32 做控制面”的分工,和现在边缘网关、通信测试终端的架构思路是一致的,也是热搜词里“arm/fpga边缘网关”频繁出现的原因。
相控阵的引入则把问题从一维距离探测扩展到了角度维度。多个天线单元按一定间距排列,通过控制每个通道的发射/接收相位差,可以让波束在空间上扫描而不需要机械转动。FPGA 在这里的价值更加突出,因为多通道相位控制本质上是多路 DDS 或者多路延时线的并行管理,通道数一多,MCU 根本忙不过来。
提示:如果你只是想做入门级的雷达测距,单通道 LFM 加 FPGA 就够跑通全链路了。相控阵建议作为第二阶段目标,否则前期调试复杂度会指数级上升。
2. 核心细节解析与关键参数设计
2.1 LFM 波形参数怎么定
波形参数是整个雷达系统的地基,定错了后面全白搭。核心参数有四个:载频、带宽、脉宽、脉冲重复周期。
载频决定了天线尺寸和穿透能力。频率越高,波长越短,天线可以做得越小,但大气衰减也越严重。常见的 24GHz、77GHz 用于短距测距,而几百 MHz 到几 GHz 的频段则用于更远距离的探测。假设你选的是 1GHz 载频,波长约 30cm,天线尺寸在十几厘米量级,适合桌面级实验。
带宽直接决定距离分辨率。公式很简单:
距离分辨率 = 光速 / (2 × 带宽)
如果你要分辨 15cm 的两个目标,带宽需要达到 1GHz。这个数字很吓人,实际实验中通常不会一上来就做这么大。我建议入门阶段先用 10MHz 到 50MHz 带宽,分辨率在米级,方便验证链路。等全链路跑通了再逐步加带宽。
脉宽和带宽共同决定时宽带宽积。脉宽越长,发射能量越大,探测距离越远,但盲区也越大——因为雷达在发射时无法接收。典型值取 10us 到 100us。脉冲重复周期则决定了最大不模糊距离:
最大不模糊距离 = 光速 × 脉冲重复周期 / 2
如果重复周期是 100us,最大不模糊距离就是 15km,远超实验需求。但重复周期也不能太长,否则单位时间内的脉冲数太少,影响信噪比积累。
2.2 FPGA 内部数据通路设计
FPGA 里的信号处理链路,我习惯按“发射链”和“接收链”分开规划。
发射链相对简单:DDS 或查找表生成 LFM 基带波形 → 上变频(数字域或模拟域)→ DAC 输出。如果采样率足够高,可以直接在数字域生成带通信号,省去模拟混频。比如 DAC 采样率 1GSPS,你直接在数字域生成 100MHz 到 200MHz 的扫频信号,DAC 输出后加一个带通滤波器就能送到天线。
接收链是重头戏:ADC 采样 → 数字下变频(DDC)→ 抽取滤波 → 脉冲压缩 → 检波与门限判决。
数字下变频的目的是把信号从载频搬回基带,同时降低采样率。做法是和本地振荡器(NCO)产生的正交本振相乘,得到 I/Q 两路。这里有个细节:NCO 的频率必须和发射载频严格一致,否则会产生固定的多普勒偏移,测速时会引入误差。实际工程中,发射和接收通常共用同一个时钟源,这样能保证相干性。
脉冲压缩本质上是匹配滤波,在频域做就是接收信号 FFT × 发射波形 FFT 的共轭 → IFFT。FPGA 里实现 FFT 一般调用 IP 核,但要注意 IP 核的吞吐率和延迟是否满足实时性要求。如果脉冲重复周期是 100us,而一次 FFT 加 IFFT 的流水线延迟是 20us,那完全来得及。但如果重复周期缩短到 10us,就得考虑用多相滤波或者时域卷积的替代方案。
2.3 STM32 的控制面职责
STM32 在这个项目里不是打杂的,它负责的事情很关键:
- 系统初始化与自检:上电后配置 FPGA 寄存器、检查 ADC/DAC 状态、校准时钟。
- 参数下发:根据上位机指令,动态修改 LFM 的带宽、脉宽、重复周期等参数。
- 数据汇聚与上传:FPGA 处理完的检测结果(距离、速度、幅度)通过 SPI 或 FSMC 传给 STM32,STM32 再通过 USB 或串口上传到 PC。
- 人机交互:驱动 OLED 或 LCD 显示实时探测结果,处理按键输入。
这里有个容易踩的坑:STM32 和 FPGA 之间的通信接口选择。SPI 简单但速率有限,FSMC 快但布线复杂。如果数据量不大(比如每帧只有几十个检测点),SPI 跑 10MHz 完全够用。但如果要把原始 ADC 数据传给 STM32 做二次处理,那必须上 FSMC 或者高速 SPI,否则会成为瓶颈。
提示:STM32 的 USB 设备开发是个独立话题。如果你打算用 USB 上传数据,建议直接用 CubeMX 生成 CDC 类设备,不要从零写描述符,否则枚举阶段就能耗掉你两天。
3. 实操过程与核心环节实现
3.1 硬件平台搭建与时钟规划
先列一下我建议的最小系统配置:
| 模块 | 选型建议 | 备注 |
|---|---|---|
| FPGA | Xilinx Artix-7 或 Altera Cyclone IV | 资源够用,开发工具成熟 |
| ADC | 双通道 12bit 100MSPS 以上 | 采样率至少是带宽的 2.5 倍 |
| DAC | 单通道 14bit 200MSPS 以上 | 生成 LFM 波形 |
| MCU | STM32F407 或 F429 | 带 FSMC 和 USB OTG |
| 时钟 | 温补晶振 50MHz | 作为全局参考时钟 |
时钟规划是硬件设计里最容易被忽视但最致命的部分。整个系统最好只有一个时钟源,FPGA 内部用 PLL 生成各模块所需频率,同时输出一路时钟给 ADC/DAC 和 STM32。如果 ADC 和 DAC 各自用独立的晶振,哪怕标称频率相同,实际频差也会导致相干性下降,脉冲压缩后的主瓣展宽、旁瓣抬高。
PCB 布局上,ADC 的模拟输入和时钟线要远离数字信号线,尤其是 DDR 和高速差分对。我见过一个案例,ADC 采样数据里始终有周期性毛刺,查了三天才发现是时钟线走在了 FPGA 的 DDR 数据线旁边,串扰导致的。
3.2 FPGA 端 LFM 波形生成
用 DDS IP 核生成 LFM 是最省事的做法。以 Xilinx 的 DDS Compiler 为例,配置要点如下:
- 相位宽度:建议 32bit,频率分辨率 = 时钟频率 / 2^32。如果时钟 200MHz,分辨率约 0.047Hz,绰绰有余。
- 输出宽度:14bit 匹配 DAC。
- 频率控制字更新:LFM 的本质是频率随时间线性变化,所以需要每个时钟周期或每 N 个时钟周期更新一次频率控制字。
频率控制字的增量计算公式:
Δf = 带宽 / 脉宽 × 时钟周期
假设带宽 50MHz,脉宽 50us,时钟 200MHz(周期 5ns),则每个时钟周期频率增加 50MHz / 50us × 5ns = 5kHz。对应的频率控制字增量 = Δf × 2^32 / 200MHz。
如果你不想用 DDS IP,也可以用查找表方式:预先算好一个完整 LFM 周期的波形数据存入 Block RAM,然后循环读出。这种方式简单直接,但参数不灵活,改带宽就得重新生成 ROM 数据。
// 简化的 LFM 相位累加器逻辑 reg [31:0] phase_acc; reg [31:0] freq_word; always @(posedge clk) begin if (pulse_start) phase_acc <= 32'd0; else phase_acc <= phase_acc + freq_word; end // freq_word 由外部根据时间步进更新3.3 接收链的脉冲压缩实现
脉冲压缩在 FPGA 里通常走频域路线。流程是:
- ADC 数据先做数字下变频,得到 I/Q 基带。
- 对 I/Q 数据加窗(Hamming 或 Kaiser),抑制旁瓣。
- 做 N 点 FFT,N 取 1024 或 2048。
- 与预存的匹配滤波器频域系数复数相乘。
- 做 IFFT,取模值输出。
匹配滤波器的频域系数就是发射 LFM 波形 FFT 的共轭。这个系数可以在 MATLAB 里预先算好,量化后存入 FPGA 的 ROM。
这里有个实操细节:FFT 的定点位宽选择。位宽太窄,量化噪声大,旁瓣压不下去;位宽太宽,消耗的 DSP 资源和 Block RAM 太多。我的经验是输入 12bit,中间运算保留 16bit 到 18bit,输出截取到 16bit,基本能兼顾精度和资源。
另一个坑是帧对齐。ADC 采样窗必须和发射脉冲严格对齐,否则脉冲压缩后的峰值位置会偏移,测距就不准了。做法是用发射触发信号同步 ADC 的采样启动,FPGA 内部用状态机控制采样窗的开启和关闭。
3.4 STM32 与 FPGA 的接口实现
我推荐用 FSMC 做并行通信,STM32 把 FPGA 当作外部 SRAM 来访问。FPGA 端实现一个简单的双端口 RAM 或者寄存器组,STM32 通过地址线选通不同的寄存器。
地址映射示例:
| 地址偏移 | 功能 |
|---|---|
| 0x00 | 系统控制寄存器 |
| 0x04 | LFM 带宽设置 |
| 0x08 | 脉宽设置 |
| 0x0C | 脉冲重复周期设置 |
| 0x10 | 检测结果数量 |
| 0x14~ | 检测结果数据区 |
STM32 端用指针直接读写:
#define FPGA_BASE 0x60000000 #define REG_CTRL (*(volatile uint32_t *)(FPGA_BASE + 0x00)) #define REG_BW (*(volatile uint32_t *)(FPGA_BASE + 0x04)) #define REG_PW (*(volatile uint32_t *)(FPGA_BASE + 0x08)) void radar_set_params(uint32_t bw, uint32_t pw) { REG_BW = bw; REG_PW = pw; REG_CTRL |= 0x01; // 触发参数更新 }FSMC 的时序配置很关键。如果建立时间和保持时间设得太短,读写会出错;设得太长,通信速率上不去。建议先用示波器抓 FSMC 的读写波形,确认时序余量后再优化。
提示:STM32 的 FSMC 访问 FPGA 时,FPGA 端的信号最好做同步处理,用 STM32 的写信号打两拍再使用,避免亚稳态。
4. 常见问题与排查技巧实录
4.1 脉冲压缩后主瓣展宽或旁瓣过高
这是最常见的现象。原因通常有三个:一是发射和接收时钟不相干,导致相位误差累积;二是加窗函数选择不当;三是 FFT 位宽不足引入量化噪声。
排查顺序:先用信号源直接给 ADC 输入一个单频信号,看脉冲压缩后的峰值是否尖锐。如果单频信号正常,说明问题在发射链或时钟同步;如果单频信号也不正常,那就是接收链本身的问题。
加窗方面,Hamming 窗能把旁瓣压到 -40dB 以下,但主瓣会展宽约 1.3 倍。如果你对分辨率要求极高,可以用 Kaiser 窗调整参数折中。
4.2 STM32 读 FPGA 数据偶尔出错
先查 FSMC 时序。用示波器同时抓 STM32 的读写选通信号和 FPGA 的数据输出,看数据建立时间是否满足。如果时序没问题,再查电源和地线,FPGA 和 STM32 的 IO 电平是否匹配,3.3V 对 3.3V 一般没问题,但如果是 1.8V 对 3.3V 就必须加电平转换。
还有一个隐蔽的原因:FPGA 端寄存器没有做跨时钟域处理。如果 FPGA 内部逻辑跑 100MHz,而 FSMC 访问是异步的,直接读写会导致数据不稳定。正确做法是用双触发器同步或者异步 FIFO。
4.3 测距结果有固定偏差
固定偏差通常来自链路延迟。从 FPGA 发出触发到 DAC 实际输出波形,中间有 DAC 建立时间、滤波器群延迟、PCB 走线延迟。接收链同样有 ADC 延迟、数字滤波延迟。这些延迟加起来可能达到几十纳秒,对应几米的距离误差。
解决办法是做一次“零距离校准”:把一个目标放在已知距离上,记录测量值,算出偏差,然后在软件里减掉。更严谨的做法是测量每个环节的延迟并累加,但工程上直接校准更省事。
4.4 常见问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 无回波信号 | 发射链路未工作 | 用频谱仪测 DAC 输出 |
| 回波幅度极低 | 天线匹配差 | 测天线驻波比 |
| 距离分辨率差 | 带宽不足 | 检查 LFM 实际带宽 |
| 测速不准 | 时钟不相干 | 检查收发时钟源 |
| 数据上传丢包 | 接口速率不足 | 降低上传频率或换接口 |
| FPGA 综合报时序违例 | 逻辑层级过深 | 插入流水线寄存器 |
提示:调试雷达系统时,建议先用一个简单的金属板作为目标,放在固定距离上。金属板反射强,回波明显,比用复杂目标容易定位问题。
5. 系统联调与性能验证
5.1 分阶段联调策略
我强烈建议不要一次性把整个系统搭好再调试,而是分阶段验证:
第一阶段,只调发射链。用示波器或频谱仪确认 DAC 输出的 LFM 波形频率范围、脉宽、重复周期都符合设计。如果这一步有问题,后面全是白费。
第二阶段,接通接收链但不开发射,用信号源模拟回波输入 ADC,验证数字下变频和脉冲压缩是否正常。这一步可以脱离射频前端,纯数字域调试。
第三阶段,接通收发全链路,用实际目标验证。先测固定距离的金属板,确认测距误差在可接受范围内,再测运动目标验证测速。
第四阶段,如果做相控阵,先调单通道,再逐步增加通道数,每增加一个通道就验证一次波束方向图。
5.2 性能验证指标
测距精度可以用多次测量的标准差来衡量。在信噪比足够的情况下,LFM 雷达的测距精度可以做到分辨率的三分之一到五分之一。比如 15cm 分辨率,测距精度约 3cm 到 5cm。
测速精度取决于相干积累时间和波长。公式是:
速度分辨率 = 波长 / (2 × 相干积累时间)
如果波长 30cm,积累时间 1ms,速度分辨率约 150m/s,这个数字很大,说明单脉冲测速精度有限。实际中通常用多脉冲相干积累来提高测速精度。
波束扫描范围取决于阵元间距和移相器位数。阵元间距通常取半波长,避免栅瓣。移相器位数越多,波束指向越精确,但成本和复杂度也越高。
5.3 实测经验分享
我在实际调试中发现,雷达系统最耗时的不是算法实现,而是排查各种非理想因素。比如电源纹波导致 ADC 底噪抬高,比如连接器接触不良导致信号时有时无,比如温度变化导致时钟漂移。这些问题在仿真阶段完全看不到,只有上电实测才会暴露。
另一个体会是,测试用例的设计比调试本身更重要。如果你能设计出一组逐步增加复杂度的测试用例,从单频信号到单目标再到多目标,每一步都有明确的预期结果,排查效率会高很多。反之,如果一上来就测复杂场景,出了问题根本不知道从哪查起。
最后分享一个小技巧:在 FPGA 里预留一个数据抓取模块,可以把 ADC 原始数据或者脉冲压缩后的数据存入 Block RAM,然后通过 STM32 读出来上传到 PC 用 MATLAB 分析。这个模块在调试阶段的价值极高,相当于给你装了一个片内示波器。等系统稳定后,这个模块可以关掉或者缩小深度以节省资源。