资讯动态

FPGA+STM32打造相位雷达:从LFM波形到波束扫描的工程实践

发布时间:2026/10/4 1:31:03 来源:尧图企业网站定制
1. 项目缘起为什么我要用FPGASTM32折腾一台相位雷达PLFM_RADAR这个标题拆开来看就是Phased array LFM Radar——相控阵线性调频雷达。说白了就是用电控方式控制天线阵列里每个单元的发射/接收相位让波束在空间里“扫”起来同时发射LFM线性调频信号来做距离维的脉冲压缩。这东西听起来像是军工院所才碰的但实际上只要你把指标降下来——比如X波段以下、阵元数控制在4到16个、带宽几十兆——用两块FPGA加一片STM32在自家工作台上完全能跑通。我做这个项目的出发点很朴素想搞明白相控阵雷达从基带波形生成、多通道相位控制、回波采集到测距测角这一整条链路到底是怎么串起来的。市面上现成的雷达模块要么太贵要么把核心算法封在黑盒里学不到东西。而PLFM_RADAR这个架构的好处在于它把实时性要求最高的部分波形生成、ADC采样、数字下变频、脉冲压缩放在FPGA里把控制流、人机交互、数据打包上传这些事交给STM32。两者各干各擅长的事中间用FSMC或SPI总线通信。这套东西适合谁看如果你已经玩过STM32的常规外设想往高速信号处理方向走或者你写过FPGA的点灯和串口想找一个能把这些碎片知识串起来的综合项目再或者你在做雷达、超声、无线通信相关的课题需要一套可复现的多通道收发验证平台——那这篇内容就是给你准备的。我会把架构选型的理由、关键参数的计算过程、FPGA内部模块的划分、STM32端的控制逻辑以及我在调试中踩过的坑全部摊开来讲。需要提前说明的是雷达系统涉及射频前端和天线这部分我采用的是成品收发前端模块加自制微带贴片阵列重点放在数字基带和波束控制逻辑上。所有代码和配置思路都是通用的你换成其他频段或阵元数逻辑照样成立。2. 系统架构拆解FPGA与STM32到底怎么分工2.1 为什么不是一颗芯片全包很多人第一反应是既然FPGA这么快为什么不全用FPGA做或者STM32现在主频也不低能不能一颗MCU扛下来我一开始也这么想过但实际算一下数据流就明白了。假设雷达发射带宽B20MHz根据奈奎斯特采样定理ADC采样率至少40MSPS。如果是8阵元接收每个阵元一路ADC那就是8×40M320MSPS的总采样率。每个采样点16bit数据率就是320M×165.12Gbps。这个量级的数据STM32的FSMC总线就算跑满也吞不下更别说做实时脉冲压缩了。FPGA的优势就在于它能并行处理——8个阵元的数据可以同时进8个DDC数字下变频通道同时做滤波和抽取这是MCU的串行架构做不到的。反过来说为什么不全用FPGA因为FPGA做控制流和人机交互太痛苦了。你要在FPGA里实现一个状态机来管理整个雷达的时序、处理按键输入、驱动LCD显示、打包数据通过串口上传不是不能做而是开发效率极低改一个显示逻辑就要重新综合布线。STM32这边用C语言写控制逻辑半天就能调通而且生态成熟什么屏幕、什么通信接口都有现成库。所以我的分工原则很明确数据面走FPGA控制面走STM32。具体来说FPGA负责LFM波形DDS生成、多通道ADC接口时序、数字下变频、CIC抽取滤波、匹配滤波脉冲压缩、波束形成所需的复数乘法累加STM32负责系统上电时序管理、波束扫描角度计算与相位码下发、FPGA寄存器配置、回波数据接收与上位机通信、温度监控与保护逻辑。2.2 板级互联方案的选择FPGA和STM32之间怎么连我对比过三种方案。第一种是SPI。优点是引脚少STM32端驱动简单。缺点是速率上不去就算跑到50MHz SCLK实际有效数据率也就几MB/s传雷达回波数据根本不够用。而且SPI是串行的FPGA端要做一个SPI从机时序约束麻烦。第二种是FSMC灵活静态存储控制器。STM32可以把FPGA当成一个外部SRAM来读写16位数据总线加若干地址线读写速率可以跑到几十MB/s。这个方案的好处是STM32端编程极其简单直接指针访问就行FPGA端实现一个双口RAM映射到总线即可。我最终选的就是这个方案。第三种是高速差分对比如LVDS。速率最高但STM32端没有原生LVDS接口需要外加转换芯片而且PCB布线要求高。对于我这种阵元数不多、数据率在几十MB/s级别的应用属于杀鸡用牛刀。FSMC方案的具体连接是STM32的FSMC_NE1接FPGA的片选FSMC_NOE和FSMC_NWE接读写使能16根FSMC_D[15:0]接FPGA的IO地址线用FSMC_A[10:0]接FPGA。FPGA内部例化一个双口Block RAM一端接FSMC总线逻辑另一端接雷达数据流。STM32往特定地址写数据就是下发控制字读特定地址就是取回波数据。实测下来FSMC在72MHz HCLK下16位总线的连续读写速率能到30MB/s以上传一帧1024点的复数回波8KB也就不到0.3ms完全够用。2.3 时钟树与同步设计雷达系统里时钟的相位噪声直接决定测距精度所以时钟方案不能马虎。我的做法是板上放一颗50MHz的温补晶振作为全局参考FPGA内部用PLL倍频到200MHz作为系统主时钟再分频出DAC采样时钟比如100MHz和ADC采样时钟比如40MHz。STM32这边用独立的8MHz晶振通过PLL倍频到72MHz它不需要和FPGA严格同源因为控制流对时钟相位不敏感。但有一个地方必须严格同步发射触发脉冲和ADC采样起始时刻。如果这两个有时钟域交叉的亚稳态问题测距就会有固定偏差。我的处理方式是STM32通过FSMC写一个“发射使能”寄存器FPGA收到后不是立刻发射而是等自己的时钟域同步两拍然后在DAC采样时钟的整数分频点上产生发射触发同时启动ADC采样计数器。这样发射和接收就在同一个时钟域里确定性好。注意跨时钟域信号一定要做同步处理至少打两拍。我一开始图省事直接用了组合逻辑跨域结果测距值偶尔跳变几十厘米查了两天才定位到是亚稳态导致的触发抖动。3. 核心细节解析从LFM波形到波束扫描的关键参数3.1 LFM波形生成的参数计算线性调频信号是雷达的距离分辨基础。它的数学表达是s(t)exp(j·2π·(f0·t 0.5·K·t²))其中f0是载频KB/T是调频斜率B是带宽T是脉宽。在FPGA里我不用直接算这个公式而是用DDS直接数字合成的方式相位累加器每个时钟周期加一个步进值步进值随时间线性变化就自然产生了频率扫描。具体参数怎么定假设我要的距离分辨率是1.5米。距离分辨率公式是ΔRc/(2B)c是光速3e8。反推B3e8/(2×1.5)100MHz。这个带宽有点大对ADC和DAC要求高。我把分辨率放宽到7.5米那B20MHz这就友好多了。脉宽T我选10微秒那调频斜率K20MHz/10us2e12 Hz/s。在FPGA里DDS的相位累加器位宽我选32位系统时钟200MHz。频率控制字FTW的计算是FTW f_out × 2^32 / f_clk。对于起始频率f010MHzFTW_start 10e6 × 2^32 / 200e6 214748364.8取整214748365。终止频率f130MHzFTW_end 30e6 × 2^32 / 200e6 644245094.4取整644245094。在10微秒脉宽内200MHz时钟对应2000个时钟周期所以每个周期的FTW增量是(644245094-214748365)/2000 ≈ 214748。用一个累加器每个时钟加214748再叠加到起始FTW上就得到了线性变化的频率控制字。这里有个细节DDS的相位累加器是32位但实际用来查正弦表的只有高12位或14位。我用的是高14位查表表深16384每个点16bit。这样无杂散动态范围大概能到80dB左右对于教学和一般探测够用了。3.2 多通道相位控制与波束扫描相控阵的核心就是通过控制每个阵元发射/接收信号的相位差让波束指向特定方向。对于均匀线阵相邻阵元之间的相位差Δφ 2π·d·sin(θ)/λ其中d是阵元间距θ是波束指向角λ是波长。我用的阵元间距dλ/2这是为了避免栅瓣。假设工作频率20MHz对应波长15米那d7.5米——这显然不现实所以实际我用的是射频前端把频率搬到了2.4GHz附近波长0.125米d0.0625米。但基带处理部分相位控制是在中频做的我用的中频是20MHz对应的相位计算还是用基带频率来算。具体到实现STM32负责计算每个阵元的相位码。以8阵元为例波束指向θ那第n个阵元的相位是φ_n n·2π·d·sin(θ)/λ。STM32算出这个值后量化成FPGA里相位累加器的偏移量。FPGA里每个通道有一个独立的DDS共享同一个频率控制字但相位累加器的初始值不同这个初始值就是STM32下发的相位码。波束扫描的步进我设为1度从-45度扫到45度共91个角度。每个角度驻留时间100微秒其中10微秒发射90微秒接收。STM32在每个驻留周期开始前通过FSMC把8个相位码写入FPGA的相位寄存器组然后触发发射。这样波束就一步一步扫过去形成扇形扫描。实操心得相位码的量化位数很关键。我用的是12位量化也就是360度分成4096份每份约0.088度。实测波束指向误差在0.5度以内够用了。如果你用8位量化误差会到1.4度旁瓣也会明显抬高。3.3 数字下变频与脉冲压缩的FPGA实现ADC采样回来的信号是实信号中心频率在20MHz中频上。要把它搬到基带需要做数字下变频乘以一个20MHz的复本振然后低通滤波。FPGA里我用的是查表法生成复本振的I/Q两路然后和ADC数据做复数乘法。复数乘法消耗的DSP资源不少。8个通道每个通道一个复数乘法器就是8个DSP48。Xilinx Artix-7或者Altera Cyclone IV的DSP数量都够。乘法结果经过一个CIC抽取滤波器把采样率从40MSPS降到5MSPS这样后续脉冲压缩的运算量就小了。脉冲压缩本质上是匹配滤波就是把回波信号和发射波形的共轭做卷积。在频域做更快把回波做FFT乘以发射波形的FFT共轭再做IFFT。但FFT资源消耗大我用的替代方案是时域卷积因为我的脉宽只有10微秒对应2000个点卷积核长度2000用FIR滤波器结构做抽头数2000消耗的乘法器不少但还能接受。如果脉宽更长建议还是上FFT IP核。匹配滤波后的峰值位置就对应目标的距离。距离计算公式是Rc·t/2t是发射到接收的时间差。FPGA里我做一个峰值检测逻辑找到匹配滤波输出模值的最大值和对应的索引把索引传给STM32STM32再换算成距离。4. 实操过程从零搭建PLFM_RADAR的完整步骤4.1 硬件选型与板级搭建主控FPGA我选的是Xilinx Artix-7 XC7A35T理由是DSP48 slice有90个Block RAM有1800Kb够我用。开发板用的是常见的黑金AX7035上面有FMC接口方便接ADC/DAC子板。STM32这边用的是STM32F407ZGT6FSMC接口引出来了主频168MHz性能够。ADC我选的是AD922612bit65MSPS并行输出接口简单。DAC用的是AD976714bit125MSPS。射频前端用的是成品收发模块中频接口直接接ADC/DAC。天线是我自己用FR4板做的4×2微带贴片阵列每个贴片后面接一个移相器芯片移相器由STM32通过SPI控制。板级连接上ADC的12位数据线接FPGA的IO时钟接FPGA的全局时钟引脚。DAC的14位数据线和时钟同样接FPGA。STM32和FPGA之间的FSMC总线我用了16位数据线和11位地址线片选和读写使能各一根。另外STM32还有几根GPIO接FPGA的中断输出用来通知STM32“一帧数据准备好了”。注意ADC和DAC的时钟一定要用FPGA的全局时钟缓冲器BUFG驱动不要用普通IO。我一开始用普通IO输出时钟抖动大采样信噪比差了十几个dB。4.2 FPGA工程的关键模块划分FPGA工程我分成这几个模块时钟管理模块MMCM/PLL、DDS波形生成模块、ADC接口模块、多通道DDC模块、CIC抽取模块、匹配滤波模块、峰值检测模块、FSMC从机接口模块、相位寄存器组。时钟管理模块产生200MHz系统时钟、100MHz DAC时钟、40MHz ADC时钟。DDS模块在200MHz时钟下运行每个时钟输出一个14bit的波形样点送到DAC接口。ADC接口模块用40MHz时钟采样12bit数据做串并转换后送到DDC。DDC模块里复本振用DDS生成频率20MHz。ADC数据先减去直流偏置因为AD9226输出有偏置然后和复本振的I/Q相乘。乘法结果经过一个31阶的FIR低通滤波器截止频率2.5MHz然后做8倍抽取输出5MSPS的基带I/Q数据。匹配滤波模块接收基带I/Q和预存的发射波形共轭做卷积。我用的是转置型FIR结构2000个抽头分4个时钟周期完成一个输出点的计算这样200MHz时钟下等效5000万次乘加每秒8个通道并行就是4亿次Artix-7的DSP够用。峰值检测模块对匹配滤波输出的模值I²Q²做滑动窗口最大值检测窗口长度256找到最大值和索引后把索引和模值写入结果寄存器同时拉高中断线通知STM32。FSMC从机接口模块实现了一个双口RAM地址空间映射为0x000-0x0FF是控制寄存器0x100-0x1FF是相位寄存器组0x200-0x2FF是结果寄存器0x300-0x3FF是回波数据缓冲区。STM32通过FSMC读写这些地址FPGA内部逻辑响应。4.3 STM32端控制逻辑与上位机通信STM32的工程用Keil MDK或者VSCodePlatformIO都行我用的是VSCode加STM32CubeMX生成底层初始化代码。主要逻辑是一个状态机上电初始化FSMC、配置FPGA寄存器、进入扫描循环。扫描循环里STM32先计算当前角度的8个相位码通过FSMC写入FPGA相位寄存器组。然后写发射使能寄存器FPGA开始发射和接收。STM32等待FPGA的中断中断来了之后从结果寄存器读取峰值索引和模值换算成距离和幅度存到数组里。一个角度完成后角度加1度继续下一个。所有角度扫完后STM32把距离-角度-幅度数据打包通过串口或者USB上传到上位机。上位机我用Python写了一个简单的可视化界面用matplotlib画极坐标图实时显示目标的位置。STM32和FPGA的FSMC通信代码很直接用指针访问就行#define FPGA_BASE_ADDR 0x60000000 #define FPGA_CTRL_REG (*(volatile uint16_t *)(FPGA_BASE_ADDR 0x000)) #define FPGA_PHASE_REG (*(volatile uint16_t *)(FPGA_BASE_ADDR 0x100)) #define FPGA_RESULT_REG (*(volatile uint16_t *)(FPGA_BASE_ADDR 0x200)) void radar_set_phase(uint8_t channel, uint16_t phase_code) { FPGA_PHASE_REG (channel 12) | (phase_code 0x0FFF); } void radar_trigger(void) { FPGA_CTRL_REG 0x0001; }实操心得FSMC的时序参数要调对。我一开始用默认配置读写偶尔出错。后来把地址建立时间设为2个HCLK数据保持时间设为1个HCLK就稳定了。具体值要看FPGA端逻辑的响应速度建议用示波器抓FSMC的读写波形来调。4.4 系统联调与校准硬件和代码都准备好之后联调是最耗时的。我的步骤是先单独测FPGA的DDS输出用示波器看波形是不是线性调频。然后单独测ADC采样给一个已知频率的正弦波看DDC输出的I/Q是不是正确的直流。再测匹配滤波用信号源给一个和发射波形一样的脉冲看峰值检测能不能找到正确位置。全部单独测通之后接上射频前端和天线在暗室或者空旷场地做外场测试。我是在一个长走廊里做的尽头放一个角反射器作为目标。发射功率很低大概10dBm作用距离也就十几米但足够验证测距和测角功能。校准主要是两个一是通道间幅度和相位一致性校准。因为8个接收通道的模拟前端不可能完全一致需要在FPGA里加补偿系数。我的做法是用一个信号源等幅同相馈入8个通道采集基带数据算出每个通道相对于参考通道的幅度比和相位差把补偿系数写入FPGA的乘法器。二是距离零点校准用一个已知距离的目标看测出来的距离和实际差多少把这个差值作为固定偏移减掉。5. 常见问题与排查技巧实录5.1 测距值跳变或固定偏差这是最常见的问题。如果测距值偶尔跳变几十厘米大概率是跨时钟域信号没同步。检查发射触发信号和ADC采样启动信号是不是在同一个时钟域如果不是加两级触发器同步。如果测距值有固定偏差比如总是差1.5米那可能是匹配滤波的群延迟没补偿。FIR滤波器的群延迟是(N-1)/2个采样点N是抽头数。我的2000抽头滤波器群延迟999.5个采样点在5MSPS采样率下就是199.9微秒对应距离偏差约30公里——当然实际不会这么大因为我是用卷积不是滤波但类似的延迟补偿一定要做。5.2 波束指向不准或旁瓣高先检查相位码的计算公式。d·sin(θ)/λ这个公式里d和λ的单位要统一。如果d用米λ也要用米。另外相位码的量化误差会直接影响旁瓣电平。12位量化理论旁瓣在-72dB左右但实际因为通道间不一致能到-30dB就不错了。如果旁瓣明显偏高先做通道一致性校准再检查相位码是不是有截断误差。5.3 FSMC通信不稳定症状是STM32读回来的数据偶尔全0或全F。原因通常是FSMC时序和FPGA逻辑不匹配。用示波器同时抓FSMC的片选、读写使能和数据线看数据有效窗口是不是在FPGA采样窗口内。如果FPGA端用的是FSMC时钟的上升沿采样而STM32在下降沿改变数据那就要调整FSMC的保持时间。另外FPGA端的双口RAM要加输出寄存器避免组合逻辑直接输出导致毛刺。5.4 ADC采样信噪比差先看时钟质量。ADC时钟的抖动直接恶化信噪比。用频谱仪看时钟的相位噪声如果100kHz偏移处相位噪声差于-100dBc/Hz那信噪比好不了。换用FPGA的专用时钟输出引脚或者在PCB上做时钟走线的阻抗匹配。另外ADC的模拟电源要干净数字电源和模拟电源用磁珠隔离地平面要完整。5.5 常见问题速查表问题现象可能原因排查方法解决措施测距值跳变跨时钟域亚稳态检查同步触发器加两级同步测距固定偏差群延迟未补偿计算滤波器延迟减去固定偏移波束指向不准相位码计算错误核对公式和单位重新计算相位码旁瓣偏高通道不一致采集各通道幅度相位加补偿系数FSMC读回全0时序不匹配示波器抓总线波形调整FSMC时序参数ADC信噪比差时钟抖动大测时钟相位噪声换专用时钟引脚峰值检测不到匹配滤波输出太小看匹配滤波输出模值增大发射功率或增益扫描不同步中断丢失看STM32中断计数加中断标志清除逻辑避坑技巧调试雷达系统一定要有一个“信号源示波器”的闭环验证环境。不要一上来就接天线做外场先在桌面上用信号源模拟回波把基带链路全部调通。我见过太多人直接上外场结果连问题是出在射频还是基带都分不清。6. 后续扩展与个人体会这套PLFM_RADAR平台跑通之后能扩展的方向很多。比如把阵元数从8个增加到16个波束宽度能窄一半角分辨率从约12度提升到6度。或者把LFM带宽从20MHz加到50MHz距离分辨率从7.5米提升到3米。再或者把匹配滤波从时域卷积换成频域FFT能支持更长的脉宽和更大的时宽带宽积。我个人在实际操作中的体会是雷达系统最难的从来不是单个模块的实现而是系统级的同步和校准。FPGA里写一个DDS很简单STM32里算一个相位码也很简单但要让8个通道在时间上对齐、在相位上一致需要反复调试和验证。我建议每个模块都单独做测试桩用已知信号验证输出确认无误后再级联。级联的时候先两两联调再全部联调不要一次性把所有模块接起来。另外PCB布局对雷达性能影响极大。ADC的模拟输入走线要尽量短远离数字信号线。DAC的输出要加低通滤波器滤掉采样时钟的谐波。电源层要分割数字电源和模拟电源分开供电。这些在原理图阶段就要考虑好等到板子打回来再改就麻烦了。最后分享一个小技巧在FPGA里加一个ILA集成逻辑分析仪核把关键信号引出来比如发射触发、ADC采样有效、匹配滤波输出有效、峰值检测标志。这样调试的时候不用外接示波器直接在Vivado里看波形效率高很多。STM32这边可以用SWO输出调试信息或者用串口打时间戳和FPGA的ILA波形对照着看能快速定位是哪个环节出了问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑