ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Artix7 FPGA的相位干涉仪测向系统设计与FFT IP核配置实战

基于Artix7 FPGA的相位干涉仪测向系统设计与FFT IP核配置实战 1. 先搞懂相位干涉仪测向的原理与项目目标1.1 一句话讲清楚测向的核心思路相位干涉仪测向说白了就是利用两个不同位置的天线收到同一信号的相位差反推信号来向。电磁波传播时到达两个天线的路程不同走的距离越长相位滞后越多。只要精确测出两个通道之间的相位差再结合天线间距和信号波长就能算出信号的到达角。这个技术在无线电监测、无人机探测、雷达告警、汽车雷达等领域用得非常多。和传统的幅度测向相比相位干涉仪测向的测向精度更高、响应速度更快而且不需要天线大口径地转动扫描属于被动测向方案很适合做小型化、实时性要求高的系统。FPGA在这个项目里的角色是把天线下来、ADC采进来的数字中频信号做FFT从频域里提取每个通道的相位值再计算通道间相位差最后完成测角解算。换句话说FFT是这套系统的“眼睛”测向算法本身不复杂真正的复杂度全在信号链路上的精度控制和时序配合上。1.2 为什么选Artix7而不是其他FPGAArtix7在Xilinx 7系列里属于低成本、低功耗、小封装的选手但对这种中等规模的信号处理任务来说资源完全够用。以我常用的XC7A35T为例它有大约5万个逻辑单元、90个DSP Slice、5个时钟管理模块跑一个两通道1024点FFT加角度解算绰绰有余板上功耗还能控制在两三瓦以内。7系列还有一个很友好的点Vivado的生态非常成熟FFT IP核、CORDIC IP核、Block RAM这些现成的资源拿来即用不需要像用纯逻辑去手写FFT那样从头折腾。如果你没用过Artix7直接拿它做这个项目学习成本会比用Zynq低不少——Zynq还牵扯ARM端和PL端的协同调试起来多一层麻烦。另外Artix7的GTX高速收发器、LVDS接口能力也能满足高速ADC的数据接入。实际项目中采样率如果是100MSPS以内双通道并行LVDS直接接进FPGA就行不需要额外加串并转换芯片。这也是这个项目能保持“低成本、高集成”的关键。1.3 测向精度、测量范围与模糊问题测向精度的核心公式很直观相位差 φ 2π × d × sin(θ) / λ其中d是两天线间距λ是信号波长θ是信号来向与法线的夹角。将公式变形就能由测出的相位差反推角度θ arcsin(φ × λ / (2π × d))这里有个关键点相位差φ的范围只有[-π, π]一旦真实相位差超过这个范围就会出现“模糊”——你测出来的角度不再唯一。所以如果要求测向范围是±90°天线间距必须满足d ≤ λ/2如果想提高测向精度通常希望d做得大一些但d大了模糊又来了。工程上的标准解法是采用多基线设计用短基线解模糊、长基线提精度。比如一根天线间距取λ/2左右保证大范围不模糊另一对天线间距取几个波长用来提高角度分辨率。FPGA内部的解算单元只需要同时处理两组基线再用余数定理把角度解出来。选择Artix7做这个项目还有一个隐性优势7系列FPGA内部逻辑可以直接做高精度的定点运算配合Vivado的IP核相位差解算的误差可以控制在零点几度以内前提是FFT提取的相位本身别出问题——这就引出了这篇博文最想吐槽的部分FFT IP核配置。2. 系统硬件方案与关键器件选型2.1 整体架构怎么搭相位干涉仪测向系统从天线到输出角度链路大概是这样的天线阵至少两路天线工程上常用三到四路构成多基线组合。射频前端低噪声放大器、滤波器、混频器把射频信号搬到中频。如果做零中频方案也可以直接I/Q下变频。ADC双通道同步采样把中频模拟信号变成数字信号送给FPGA。FPGA完成FFT、通道间相位差计算、模糊解算、角度输出。后级处理可以是串口、网口或者自定义接口把角度结果发给显控终端。我这里做的方案是中频数字化ADC采样率定在80MSPS中频频率20MHz信号带宽500kHz以内。之所以选这个参数是因为FFT点数取1024时频率分辨率约78kHz对窄带信号测向足够用同时FFT计算量也不会太大。2.2 射频前端与ADC的选型思路天线下来之后信号要先做带通滤波和放大把微弱信号拉到一个ADC输入范围比较舒服的幅度。这里建议在射频前端加一个AGC自动增益控制环路防止信号忽大忽小导致ADC饱和或者太小淹没在噪声里。ADC的选择上我建议优先考虑双通道同步采样芯片比如AD9653、ADS62P49这类两个通道的采样时钟来自同一个时钟源从硬件层面保证两路采样的同步性。如果你手里的ADC是单通道型号那就得在FPGA里专门处理两个ADC的时钟对齐问题比较麻烦不推荐新手一开始就这么干。采样时钟的质量对这个项目影响极大。ADC采样时钟的抖动会直接转化为相位噪声而相位干涉仪测的恰恰是相位所以采样时钟一定要用低抖动的晶振加时钟分配芯片来做。我在项目里用的是50MHz的恒温晶振通过AD9516时钟芯片分配出两路同步时钟给ADC抖动控制在1ps以内实测相位稳定性比用普通晶振好了不少。2.3 为什么采样时钟与FFT时钟不能混为一谈这是很多第一次调相位干涉仪的人最容易犯的错把ADC采样时钟直接接到FFT IP核的aclk上。ADC采样时钟是整个系统的时间基准它的频率由中频频率和信号带宽决定而FFT IP核的aclk是FPGA内部逻辑的工作时钟它只需要满足IP核的时序要求频率可以高一些也没有关系。两者之间通过AXI4-Stream接口做数据传递采样率和工作时钟频率完全可以不一样。我在这个项目里把FFT的工作时钟定在100MHzADC采样率是80MSPS数据经跨时钟域FIFO后以100MHz送入FFT。这样做的理由是100MHz对Artix7的逻辑来说非常稳妥时序收敛很容易同时FFT的吞吐余量足够不会因为处理不过来而丢数据。如果你硬要让FFT时钟跟着ADC采样率走一旦采样率是个非整数频率IP核的时序约束和时钟生成都会非常别扭——下面第三部分细说。3. Vivado FFT IP核配置实操这些坑一定躲开3.1 重要参数怎么填Vivado里的FFT IP核版本不同界面略有差异但核心配置项就那几个Transform Length、Sampling Rate、Architecture、Data Format、Scaling Option。第一Transform Length。我选1024点理由前面说过频率分辨率够了算力开销适中。如果你要测的信号带宽更窄可以上4096点但Block RAM占用会翻倍。第二Architecture选项。这里有Pipelined Streaming和Radix-4 Burst I/O等选择。Pipelined Streaming是流水线结构可以连续不停顿地处理数据但资源占用多Radix-4 Burst I/O是分块处理数据输入完才开始算资源少一些。对测向这种需要“攒一帧、算一帧”的模式Radix-4 Burst I/O完全够用资源还省我实测下来XC7A35T的利用率能控制在40%左右。第三Data Format。如果你是从ADC直接进来的是实数信号FFT输入类型选Real如果有I/Q两路复数信号选Complex。要注意的是即使输入是实数FFT输出的负频率部分也有信息只是关于0频对称。相位提取时只需要取目标信号所在的正频率bin就行。第四Scaling Option。这里极其关键我单独用一个小节展开。3.2 缩放与定点数配置上来就选Full Precision的人后来都哭了FFT IP核的Scaling Option里有几个选项UnscaledFull Precision、ScaledFixed Point或Floating Point等。新手图省事会直接选Unscaled觉得这样不会损失精度但实际一跑就发现输出数据位宽暴涨——每级蝶形运算都会扩展位数1024点FFT有10级输入16位输出能到36位。数据位宽一大后面的相位计算、存储、传输全都跟着变慢变贵。正确的做法是选Scaled让IP核在每一级输出时自动截位把输出位宽控制在一个合理范围内。但截位本身会带来量化误差如果缩放比例配置得不好信噪比下降相位抖动就会变大。我的实践结论是输入数据宽度取16位缩放策略选Scaled并且把每一级缩放的位向量N/A到N/A之间由IP核根据输入数据动态计算设置为中间值然后在实际信号下观察输出幅度微调缩放参数使FFT输出的目标信号峰值幅度尽量接近满量程而又不溢出。这样做既保证相位分辨率又能把输出位宽控制在20位以内后面的CORDIC计算负担小很多。这里还要多说一句定点数的事。FPGA里算相位最怕小数处理不当。我的习惯是FFT输出的实部虚部直接用定点补码送入CORDIC IP核让CORDIC输出用Q格式定点角度。比如用Q1.15格式表示-1到1的归一化弧度值或者用整数0到65535表示0°到360°关键是把格式统一后面做差、查表才不会乱。3.3 吐槽最多的点FFT IP核无法设置小数时钟输入怎么办这个坑我在论坛上看到无数人问过。现象通常是在IP核配置界面里填时钟频率填一个50.5MHz、80MSPS这样的数字系统报错或者时序收敛不了有人就认为是IP核不支持小数时钟输入。先说结论FFT IP核本身没有“必须整数时钟”这种限制真正的问题是时钟树设计。如果你用的是MMCM/PLL很多PLL的输出频率并不是能任意设置的它由VCO频率和分频系数决定。8OPLL想要精确产生50.5MHz可能可以但想精确产生80.3MHz这种数字分频系数不一定能整除最后出来的频率和预期就有偏差时序约束自然对不上。更稳妥的方案是绕开这个麻烦让FFT始终跑在一个整数、好生成的固定时钟上比如100MHz或125MHz。ADC的采样时钟单独由板载晶振产生采样数据通过异步FIFO跨时钟域进入FFT。这样FFT的aclk和数据的采样率完全解耦IP核配置时的时钟频率填100MHz就行了再也不会遇到“小数时钟输入”的报错。如果你确实想让FFT处理一个非整数采样率的数据也可以这么做在XDC里对aclk创建一个create_generated_clock或set_clock_uncertainty约束把约束余量放宽一点然后确保时序报告里没有hold violation。但这个方法对新手不友好而且板子一换可能又要重新调。老老实实用异步FIFO解耦是最省心、最通用的做法。3.4 复位信号、时序约束和AXI接口FFT IP核的复位信号必须慎重对待。FPGA内部逻辑复位如果用异步复位、异步释放很容易在时钟沿附近产生亚稳态导致FFT启动状态错乱——表现就是输出数据偶尔错一帧特别难排查。建议做法在顶层模块里对全局复位信号做一次同步用两个触发器打拍把同步后的复位信号接到IP核的aresetn上。如果实际调试中发现复位时序敏感还可以直接用Vivado的同步复位模板生成一个复位模块。我在这个项目里实际测试过直接接异步复位时跑十分钟会出现一次输出异常改成同步复位后连续跑几十个小时都没再复现。AXI4-Stream接口方面重点是s_axis_data_tvalid和s_axis_data_tready的握手时序。FFT IP核在Radix-4 Burst I/O架构下输入数据空闲时tvalid要拉低否则IP核会一直等待。另外输入数据是分帧的每帧的最后一个数据要拉高tlast表示帧结束。很多刚开始用IP核的人忘了拉tlast导致FFT处理完一帧之后不输出结果卡在那里。4. 相位提取与角度解算的FPGA实现4.1 从FFT结果到相位差完整流程FFT输出的结果对应频域上各个频率bin的复数值。假设目标信号落在第k个bin那么该bin的输出是一个复数实部为I、虚部为Q。信号的相位就是atan2(Q, I)的结果。算法流程上是这样通道1做1024点FFT取目标频点bin的I1、Q1。通道2做同样的FFT取相同频点bin的I2、Q2。分别计算两个通道的相位角φ1和φ2。相位差Δφ φ1 - φ2换算到[-π, π]区间。根据公式θ arcsin(Δφ × λ / (2π × d))得到来向角。如果你用Xilinx的FFT IP核多通道模式IP核里可以配置2通道、4通道复用同一个FFT引擎输出时分复用这样能省掉一个FFT IP核的资源和功耗。但要注意这时候数据的输入顺序和输出顺序要和通道号对齐——配置成2通道时数据流是channel0一帧、channel1一帧交替进入。我在第一次调的时候就是没注意这个顺序把通道0和通道1的数据算反了角度输出直接偏了90多度排查了好一阵。4.2 CORDIC算atan2的实现要点既然要算atan2最方便的办法是调Xilinx的CORDIC IP核。配置时Functional Selection选“Arc Tan”输入是I和Q两路输出是角度。这里很容易踩一个坑CORDIC输出的角度格式是带缩放因子的定点数需要搞清楚它表示的是弧度还是某种整数量化以及正负范围对应关系。我在项目里的用法是CORDIC输出20位定点数最高位为符号位其余19位表示归一化到[-1, 1)的弧度值。也就是说输出值乘以π才是真实的弧度。换算成角度时再做一个定点乘法转成度数。如果你的工程对资源极其抠门也可以自己写一个基于流水线CORDIC的atan2模块网上有现成代码。但说实话Xilinx的CORDIC IP核质量很高、IP核接口又简单自己写未必能比它稳开发时间还长。能用现成IP核就用现成IP核这是个老工程师的忠告。CORDIC还有一个需要注意的点输入如果太小角度计算会受噪声影响很大。所以送入CORDIC之前最好先对I、Q值做一个幅度判断低于某个门限就认为该帧没有有效信号不上送角度。这个门限我通常设为满量程的5%10%能有效避免没有信号时输出随机角度。4.3 整周模糊的实时解算前面提到多基线设计具体在FPGA里怎么解模糊我用两个基线的例子说明。设短基线的间距d1 λ/2长基线间距d2 4 × d1 2λ。短基线测出的相位差在±π范围内对应角度是唯一的。长基线测出来相位差可能是φ_raw 2π×N其中N是未知的模糊整数。解模糊的方法有两步。第一步用短基线测出的角度θ_coarse反推长基线应该得到的相位差φ_pred 2π × d2 × sin(θ_coarse) / λ。第二步将长基线实测相位差和φ_pred比较算出最接近的整数N再用N修正长基线的相位差最终代入公式算出精确角度。这个过程在FPGA里用定点数做完全没问题。需要注意的地方是短基线测角本身有误差当长基线的间距很大、模糊间隔很近的时候可能解错模糊级。工程上一般要求短基线测角误差小于半个“模糊周期”对应的角度这又反过来约束了短基线的信噪比和相位噪声。4.4 角度输出的数据通路角度解算完之后我习惯把结果打包成一个固定格式的消息帧通过UART发出去方便在电脑上实时看。帧格式大概是帧头0xAA55、时间戳、两个通道的相位差、解算后的角度值、帧尾和校验。这样在调试时只需要一个USB转串口模块插上电脑就能用串口助手看到结果非常方便。如果你有更复杂的后续处理需求比如做多目标测向、跟踪滤波也可以把角度数据送到Zynq的ARM端或者接一个网口芯片。但就这个项目本身而言UART是最简单可靠的调试手段。5. 实测、校准与常见问题排查5.1 双通道一致性校准流程相位干涉仪的精度很大程度上取决于两个射频通道的相位一致性。实际硬件上两根天线到两个ADC的线路长度不可能完全一样混频器、滤波器、放大器的相位特性也会有细微差异这些都会以固定相位偏移的形式叠加到测量结果上。所以系统做好之后必须先做一次校准。我的做法是用一个信号源直接输出一个已知频率的连续波信号通过功分器分成两路分别送入两个接收通道。这时理论上两个通道收到的信号相位差为零但测出来往往会有一个固定的偏移值。把这个偏移值记录下来在后面的测量中减去即可。校准需要多频点做。因为滤波器、电缆的相位响应是随频率变化的只校准一个频点的话其他频点仍然会有残余误差。我在项目里做了7个频点的校准存成一张查找表运行时根据目标信号的频率自动查表插值补偿相位偏移。实测下来校准前测角误差可能有4到5度校准后能压到1度以内。5.2 我踩过的三个最明显的坑第一坑FFT输出数据顺序。Xilinx FFT IP核在Radix-4 Burst架构下默认输出是bit-reversed顺序不是自然的0、1、2……顺序。如果你不勾选“Natural Order”输出选项那你取的bin号就是乱的相位自然全错。我自己第一次调的时候直接按自然序取bin结果角度输出完全是噪声无论如何都看不出规律折腾了一天才发现是输出序的问题。第二坑DC分量没有滤除。ADC输入的信号如果带有直流偏置FFT的0频bin会有一个很大的分量而且这个直流分量如果超过一定幅度会通过泄漏影响邻近的bin把目标信号的相位拉偏。解决方法是在ADC数据进FFT之前先做一次直流扣除运算或者在配置FFT IP核时选择加窗。我在设计里用的是Hamming窗主瓣稍微宽一点但旁瓣压低之后相邻bin的干扰明显减少测角稳定度提升明显。第三坑FFT的tready信号没处理。在AXI4-Stream接口下如果你只拉tvalid而不看tready数据可能被丢弃。Xilinx官方推荐的做法是用一个简单的状态机控制数据输入。我图省事直接拉了一堆常量结果前几帧数据全是错的后面又花了很长时间去查。这个错误其实很低级但很多刚接触AXI接口的人都会犯。5.3 常见问题速查表问题现象可能原因排查与解决办法FFT IP核配置时报时钟频率错误配置了非整数且无法由PLL精确生成的时钟改用固定整数时钟如100MHz用异步FIFO做跨时钟域FFT输出结果是噪声ADC输入信号幅度太小或位数配错检查ADC输出数据格式、信号幅度、FFT输入位宽FFT输出bin序号对不上IP核输出是bit-reversed顺序勾选Natural Order或在软件侧做bit-reversed重映射双通道相位始终差一个固定值硬件通道存在固定相位偏移做多频点校准补偿相位偏移表角度输出抖动大信号太弱、FFT截位过大、噪声偏大提高信号幅度或AGC门限调整FFT缩放参数加窗偶发角度突变复位亚稳态或整周模糊解算错误同步复位信号优化模糊解算判决门限数据偶尔丢一帧AXI握手信号处理不规范检查tready/tvalid/tlast时序用状态机控制帧输入FFT IP核不启动aresetn复位信号一直低检查同步复位逻辑确认复位释放正常以上这些问题基本都是我在这个项目上遇到过并且逐一解决的。相位干涉仪测向的FPGA实现原理上并不复杂但工程实现中涉及信号链路的每一个环节任何一环不到位最后测出来的角度都会不对。希望这篇实操记录能帮你少走一些弯路。最后再分享一个小经验调试这类系统别急着上FPGA先用信号源加示波器把射频、ADC链路摸清楚再进FPGA调FFT——硬件干净了软件才调得明白。
返回列表