1. 项目概述与设计思路
1.1 核心需求解析
基带与中频的FPGA算法实现,这个标题看起来挺学院派,但它本质上讲的是通信系统里最核心的一条信号链路:从天线接收到的射频信号,经过模拟前端下变频到中频,再由ADC数字化,最后进入FPGA完成从中频到基带的处理以及基带侧的各种算法。
我在一线做FPGA通信信号处理也有不少年头了,接触过的项目从卫星通信、雷达信号处理到软件无线电平台都有。说实话,基带和中频这两个词虽然经常被放在一起提,但它们解决的完全是不同层面的问题。中频处理解决的是“怎么把信号从载波上搬下来、怎么滤掉干扰、怎么让数据速率降到后端能处理的水平”,而基带处理解决的是“拿到这些数据之后,怎么完成同步、解调、译码、协议解析”。把这两块都放在一个FPGA里实现,既省掉了板卡上额外的DSP芯片,又能获得极低的延迟,这也是现在很多高性能通信设备和软件无线电平台的主流做法。
这个项目适合谁参考?如果你正在做通信物理层相关的FPGA开发,比如DDC/DUC、数字下变频、调制解调、突发通信、遥测遥控,或者你想搞懂Xilinx和Intel FPGA里那些与通信相关的IP核到底怎么用,这篇文章应该能给你省不少摸索的时间。
1.2 方案选型背后的思考
一个常见的误区是把“基带与中频处理”理解成“把算法调到能跑就行”。实际工程里,FPGA资源是有限的,时钟频率是有上限的,数据吞吐是实时的,这三座大山决定了你不能像在PC上写C程序那样随心所欲。
举个例子,一个带宽为20MHz的LTE信号,如果用通常的带通采样或零中频方案,ADC采样率可能要跑到122.88MHz甚至更高,每个采样点用16bit量化,那一路数据的速率就是122.88×16,接近2Gbps。这个速率对FPGA内部的逻辑时钟来说并不算高,但如果后面接的不是硬核DSP而是可编程逻辑来实现FIR滤波器,那就得考虑乘法器够不够用、时序能不能收敛的问题。
我当时给这个项目定的设计原则是三条:
- 在算法性能满足指标的前提下,优先选择资源占用少的实现方式,而不是理论最优但实现代价高的方式。
- 能用IP核解决问题就不自己造轮子,Xilinx的FIR Compiler、NCO、FFT这些IP都是经过验证的,性能和资源都比我手写的模块要好,除非有特殊需求(比如非对称滤波器、非标准插值倍数),否则没必要重新发明轮子。
- 把数据流和控制流分开设计,数据通道保持流水线架构,控制通道用状态机管理参数配置和模式切换。这样后期调试和系统集成会省很多事。
1.3 应用场景地图
基带与中频的FPGA算法并不是某一单一行业的专用技术,它几乎覆盖了所有需要实时无线信号处理的领域。比较典型的包括:
- 软件无线电平台和通用信号处理板卡
- 卫星通信的调制解调器、遥测遥控收发信机
- 雷达信号处理中的多通道中频数字化和脉冲压缩前处理
- 电子对抗与频谱监测中的宽带信号分析
- 5G基站和终端原型验证系统
我挑这个项目来做,也恰好是因为它跨了其中两个领域。整个设计过程中踩了不少坑,后面几节我会把遇到过的典型问题原原本本写出来。
2. 中频处理链路的关键算法拆解
2.1 数字下变频(DDC)的完整框架
中频处理的核心是数字下变频。很多人把DDC简单理解成“混频+滤波”,这个说法没错,但实际工程里细节远没有这么简单。
一套完整的DDC链路一般包括:
- NCO产生本地载波,完成I/Q两路混频
- CIC滤波器做第一级抽取,快速把采样率降下来
- 补偿FIR滤波器修正CIC的通带衰减
- FIR低通滤波器做最后的信道选择和整形
- 必要时还有增益控制、直流偏置校正、I/Q不平衡校正等辅助模块
这里面每一步都有可以深挖的细节。比如NCO的频率字计算,你如果用系统时钟100MHz,想要产生一个10.7MHz的中频载波,频率控制字的计算公式是:
频率控制字 = 目标频率 × 2^N / 系统时钟频率
N是NCO的相位累加器位宽。如果N=32,那频率控制字就是 10.7e6 × 4294967296 / 100e6 ≈ 459742804。注意这里要做四舍五入,否则会有固定的频率误差。这种误差在小数点后几位可能看不出来,但如果你做的是相干解调或长时间积分,误差积累起来就麻烦了。
混频之后信号中心频率被搬到零频附近,这时候采样率远远高于信号带宽,数据冗余很大,所以要抽取降速。CIC滤波器在抽取倍数大的时候非常高效,它只有加减法没有乘法器,资源占用极低,但代价是通带会有较大的下降,所以后面必须接一个补偿滤波器把通带拉平。这个“CIC+补偿FIR”的组合几乎是所有DDC的标配。
2.2 CIC滤波器参数设计与计算
CIC滤波器的设计核心是三个参数:级数N、差分延迟M和抽取因子R。差分延迟在大多数应用里取1,少数宽带应用中取2,级数N通常在3到5之间。
我举个例子,假设系统采样率100MHz,中频载波10.7MHz,信号带宽5MHz,主采样率不需要太高,我们想把数据率降到10MSPS,那么抽取因子R=10。这时候CIC的幅频响应接近sinc函数的形状,在信号边缘(距离中心2.5MHz)处的衰减大概是多少呢?
CIC的传递函数是:
H(f) = [sin(πMf/R) / sin(πf/R)]^N
f是相对于输出采样率的归一化频率。算下来,N=4、R=10的时候,在有用信号带宽边缘大概有1.2dB左右的通带衰减,N=5可能到1.5dB。这个衰减如果不补偿,会导致带宽内幅度不平坦,对星座图的影响是边界星座点往内收缩,对解调性能有一定影响。所以补偿FIR的设计不是可选项,是必选项。
我自己习惯用MATLAB的fdatool或者filterDesigner来设计补偿FIR,目标响应就是这个sinc函数的倒数,然后限制一下带外增益别太大以免噪声被放大。补偿FIR的阶数一般控制在32到64之间,再高效果提升有限但资源消耗翻倍。
2.3 NCO相位截断与无杂散动态范围
NCO看起来只是“相位累加器加查找表”,但它有个非常关键的陷阱:相位截断带来的杂散。
如果你把32位相位累加器的所有位都拿来查ROM表,那ROM容量是2^32×相位位宽,根本做不出来。所以实际实现里通常只取高16位甚至高14位去查表,低位直接截断。这个截断操作会产生杂散,幅度和相位位宽的关系大概如下:
无杂散动态范围 ≈ 6.02 × B dB,其中B是查表使用的相位位数
也就是说14位相位查表大概能提供84dB的无杂散动态范围,16位是96dB。如果你的系统要求80dB以上的无杂散动态范围,那14位够用;如果要求更高,就得用抖动(dithering)技术或者更大的查找表,再或者直接用Xilinx的DDS IP,它内部已经处理了这些优化。
我在项目中直接采用了Xilinx DDS Compiler IP核来产生载波,输出精度设成16bit,相位精度设成14bit,实测无杂散动态范围在85dB左右,满足设计要求。DDS IP可以同时输出正弦和余弦,正好给I/Q两路混频用,省掉了用希尔伯特变换产生正交信号这档子事。
2.4 中频检波方法的工程取舍
ADC之后、DDC之前,通常还需要对信号做检波处理,用来判断信号有没有来、什么时候开始。网络热词里也提到了中频检波有几种方法,这确实是实际工程里绕不开的一个环节。
常见的中频检波方法包括:
- 幅度检波(包络检波),实现最简单,直接平方或者求绝对值再低通滤波,但抗噪声差,信噪比低的时候门限检测不准。
- 同步检波,需要恢复载波参考,对QPSK这类信号适用,方法更复杂但检波灵敏度更高。
- 正交检波(基于I/Q功率计算),把DDC出来的I/Q两路算 v = I² + Q²,再做滑窗积分和门限比较,这是在数字域里最常用也最稳的方案。
我实际用下来,推荐优先用正交检波。它和DDC天然配合,I/Q数据已经存在,只需要几个乘加器就能算出瞬时功率,再做滑动平均滤掉包络波动,门限判决也稳定可靠。包络检波在模拟域里好用,但到了数字域里反而不如正交检波直接。
3. 基带算法实现与优化实践
3.1 同步算法的工程实现路径
基带处理里最考验功力的模块是同步算法。同步分为载波同步和定时同步两块。载波同步负责把残余频偏和相偏消除掉,常见的实现有Costas环、判决反馈环和基于FFT的频偏估计,定时同步负责找到符号的最佳采样点,常见实现有Gardner算法、Muller-Muller算法和基于内插的匹配滤波定时。
我在这个项目里做的是QPSK调制信号,采样率降到10MSPS后,符号速率是2.5Msps(每符号4个采样点),这给定时同步留了足够的余量。
载波同步我用的是Costas环,环路滤波器参数设计是直接决定锁定速度和稳态抖动的关系。环路带宽太宽,锁定快但抖动大;太窄,抖动小但收敛慢。工程上一般用阻尼因子0.707,环路带宽按符号速率的1%~2%来取。2.5Msps的符号速率,环路带宽取30kHz左右比较合适。实际需要调的话,可以先把环路滤波器比例系数和积分系数分开调,比较容易定位问题出在哪个环节。
定时同步我用了Gardner算法。Gardner的好处是对载波相位不敏感,可以先做定时同步再做载波同步,两个环路之间的相互影响会小很多。实现时每个符号需要两个采样点,但我们有四个,所以先做一个2倍抽取把采样率从2倍符号率转到2倍,再进入Gardner环路。这个抽取虽然简单,但如果滤波不对会造成频谱混叠,所以抽取前放了一个简单的半带滤波器做抗混叠。
3.2 卡尔曼滤波在基带中的应用
网络热搜词里出现了卡尔曼滤波和FPGA的组合,这个确实值得多说几句。卡尔曼滤波在很多人的印象里是导航定位里的东西,但它在基带处理里同样有用。比如对多普勒频移做实时估计和预测,或者在突发通信里用卡尔曼滤波做信号到达时间估计。
不过我得说句实话,卡尔曼滤波在FPGA里的实现比在CPU上要麻烦得多。核心原因是卡尔曼滤波有大量的矩阵运算和除法。FPGA做矩阵乘法并不难,难的是求逆和除法。所以实际工程里,大多数情况下会做两个简化:
- 系统模型是线性时不变的,状态协方差矩阵可以离线算好,直接用稳态增益,省掉在线递推。
- 把矩阵求逆退化成标量除法,或者用CORDIC算法实现定点除法,再用移位近似代替真正的小数除法。
如果要求必须在FPGA里跑完整的自适应卡尔曼滤波,我建议至少把维度控制在2阶或3阶以内,再多资源压力会非常大。从我的经验来说,先花一个晚上在MATLAB里把模型调好、确定哪些量可以离线预计算,比直接上手写RTL要节省三到五倍的开发时间。
3.3 RTL实现中的定点量化策略
算法验证通常在MATLAB或Python里用浮点完成,但FPGA里必然是定点运算。定点量化策略是否合理,直接决定BER性能损失有多大。
我的量化策略一般是这样。ADC出来是16bit有符号数,混频后我保持16bit,FIR滤波器内部累加器扩展到24bit或32bit,最后输出时再截到合适的位宽。截断操作要用饱和加舍入,不能直接截断低位,否则会产生直流偏置和信号功率损失。
具体来说,FIR Compiler IP核的输出位宽要提前算好。假设输入16bit,系数也用16bit,抽头数64,那乘法结果最坏情况是16+16+ceil(log2(64)) = 41bit。虽然实际上80%的滤波器不会跑满最坏情况,但IP核的配置就是按最坏情况分配资源的。所以如果你对资源敏感,最好先用MATLAB生成定点模型,算一算实际需要的位宽,再回填到IP核配置里。
3.4 从算法流程图到可综合代码的转换
这个项目里我把每个核心算法的流程图先画清楚再写代码。原因很简单:FPGA开发不像软件,代码写完才发现逻辑问题,回头改的代价太大。RTL代码写的本质就是在描述硬件结构,思路不清晰的情况下硬写,综合出来的电路很可能是跑不通的。
以Costas环为例,它的流程图大概是:
- I/Q输入乘以本地载波,得到I'和Q'
- 用I'×Q'作为相位误差信号
- 相位误差经过环路滤波器(比例+积分)
- 输出控制NCO的频率字
- 回到步骤1
把这个流程映射到FPGA里,就是一个典型的闭环控制回路。每个周期内信号从混频器出发,经过环路滤波器、NCO、再回到混频器,这中间的组合逻辑延迟和寄存器打拍延迟直接决定了环路能否收敛。我一般会在NCO频率字更新那里加一组寄存器延迟匹配,确保时序收敛的同时不破坏环路稳定性。
4. 基带与中频联调的完整实操记录
4.1 硬件平台与工具链准备
这个项目的硬件平台用的是Xilinx Zynq UltraScale+系列(ZU7EV),板卡上自带一片AD9361射频收发器和一片ADC/ DAC子卡。Zynq本身集成了ARM处理器和FPGA逻辑,正好把控制和数据处理分开,ARM跑Linux做上位机交互,FPGA跑实时信号处理链路。
工具链方面用了Vivado 2021.2做综合布线,Vitis做ARM端软件编译,调试用的是Vivado自带的ILA逻辑分析仪。MATLAB 2022b负责算法仿真和滤波器设计,通过MATLAB HDL Coder做了一部分自动代码生成与原手动RTL的对比验证。
准备工具链这一步有一个经验想分享:Vivado工程的IP版本管理一定要用git。FPGA工程里IP核的配置信息分散在好几个文件里,手动复制工程特别容易漏掉,要么工程打不开,要么IP配置对不上。统一用脚本化方式创建工程,再把所有源文件和约束文件提交到版本管理,后续迁移和回溯都省心。
4.2 信号源与测试条件
为了验证链路正确性,我使用了Rohde & Schwarz SMBV100A信号源作为发射端。信号源配置为:载波频率70MHz(中频),符号速率2.5Msps,QPSK调制,根升余弦成形滤波,滚降系数0.35。信号源输出经过一段同轴电缆直接接到接收板卡的射频输入口。
这么设置的好处是信号源本身产生的信号质量非常干净,方便我们单独验证FPGA算法的解调性能,而不会把射频前端的失真和噪声混淆进来。
另外还有一个关键测试工具是Xilinx的IBERT IP核,可以用来测试板载SerDes高速链路质量,确保ADC采集回来的数据和FPGA逻辑之间的MIPI接口或LVDS接口没有bit error。调试过程中我遇到过几次数据错位问题,最后发现都是接口时序不满足导致的,用IBERT排查比拿ILA盲抓波形高效得多。
4.3 信号监测与逐步联调过程
联调过程我习惯分成六个步骤走,每一步都验证过再进下一步,避免问题一下子爆发出来找不到根因:
第一步:跑ILA抓ADC原始波形,验证采样数据是否正确。在ILA里观察波形幅度、噪声底、以及有无削顶失真。这一步通过后再做其他处理。
第二步:验证NCO混频结果。给信号源一个单音正弦波,频率设在10.7MHz,NCO也设置到10.7MHz,混频后输出应该是一个接近直流的信号(频率接近0)。在ILA里观察I路波形应该基本恒定,Q路波形也基本恒定(幅度为0),说明混频方向正确且频率字无误。
第三步:验证CIC和FIR抽取滤波后的时域波形。给一个带宽内的调制信号,观察抽取后的信号包络应该和星座图对应。这一步一旦波形出现异常卷绕或者频谱混叠,基本都是抽取倍数配置或滤波器系数加载有问题。
第四步:接调制信号,验证定时同步环路。观察Gardner误差信号是否收敛到0附近,如果误差信号波动很大且符号采样点明显偏离最大眼图张开处,需要调整定时环路的环路滤波器增益。
第五步:验证载波同步环路。在信号源上加一个固定的频偏(比如+20kHz),看Costas环能否把I/Q星座图旋转校正回来。锁定后星座图应该是四个清晰的点簇,每个点对应的相位间距90度。
第六步:整体误码率测试。把解调出来的比特流和信号源的PRBS伪随机序列做对比,计算BER。实测下来SNR在20dB左右时BER可以到1e-6以下,和MATLAB仿真值基本吻合,差了大概0.3~0.5dB,这个损失主要来自定点量化。
4.4 参数计算实例:从指标到寄存器配置
我经常被问到一个问题:算法参数和代码寄存器配置之间到底怎么对应起来?这里用一个具体的实例说明。
假设我们要产生10.7MHz的中频载波,系统时钟100MHz,DDS IP相位累加器位宽32。频率控制字按前面的公式:
FTW = 10.7e6 × 4294967296 / 100e6 = 459742800.26
四舍五入取整得到459742800,十六进制是0x1B67AD50。把这个值写进DDS IP的配置寄存器,实测输出频率是10.69999999MHz,频率误差约0.1mHz,完全可忽略。
再从频率字反推实测输出频率:
f_out = 459742800 × 100e6 / 2^32 = 10699999.998 Hz
反向验证无误。这类计算必须有记录习惯,我在项目里专门建了一个参数计算表,把每个模块的指标、计算公式、结果、寄存器地址都列出来,跟代码里的参数定义一一对应。后期调试或换芯片平台时,这个表节省了大量的重新核算时间。
5. 常见问题排查与工程经验速查
5.1 时钟与跨时钟域问题
FPGA通信系统几乎不可避免遇到多时钟域问题。ADC采样的时钟、FPGA内部逻辑的主时钟、MAC层或传输层接口的时钟,这些时钟未必同源,频率也可能完全不同。跨时钟域处理不当,轻则偶发误码,重则系统不稳定。
我的原则是:所有跨时钟域的数据,一律先经过异步FIFO或寄存器打两拍同步。数据总线宽、吞吐高的走异步FIFO(Xilinx的FIFO IP核配置为independent clock模式),单bit控制信号走两级寄存器同步,多bit控制信号尽量先格雷码编码再同步。
有一个我踩过的坑:两路不同来源的ADC数据,各自有自己的采样时钟,但我在FPGA内部默认它们同源,把两个时钟域的数据直接送到同一个处理模块。结果就是误码率在测试中忽高忽低,最后通过分析ILA波形才发现两路采样时钟的相位差在缓慢漂移。后来改成先把两路数据异步FIFO同步到同一个全局时钟域,问题就消失了。
5.2 时序收敛问题与资源优化
中频链路里的FIR滤波器如果阶数高、采样率高,时序收敛是个大问题。我遇到过100MHz时钟下,一个64阶FIR滤波器综合布线后时序违例0.5ns的情况,根本跑不到目标频率。
排查后发现瓶颈在乘法器链路上。解决方案是把FIR Compiler IP核的架构模式设置为“Mutil-channel”加“Pipeline级联”,或者在IP配置里打开“Flow Control”选项中的“Reloadable”相关的寄存器重定时优化。更直接的办法是把滤波器分解成两个半带滤波器级联,每个32阶,这样两级之间插入寄存器,时序问题就化解了。
时序优化的优先级顺序是:先选型FPGA时看速度等级,-2和-3的速度等级直接决定基础性能;再来用面积换速度,流水线拆长组合逻辑;最后才考虑改算法架构降复杂度。反过来优化往往事倍功半。
5.3 问题排查实录与避坑技巧
问题一:NCO输出频率不准,误差在几十赫兹量级。排查过程先检查频率控制字是否正确,发现计算时用错了系统时钟频率(把100MHz写成了102.4MHz),修正后频率准确。这个问题的教训是:参数计算时一定要对照产品手册复查时钟源频率。
问题二:CIC抽取后信号幅度比预期低了6dB。原因是CIC滤波器增益被补偿FIR拉平后,整体增益没有归一化。解决方法是重新设计补偿FIR时把目标增益调到0dB,或者在CIC输出做一次位宽截取时保留足够的整数位。
问题三:Gardner定时同步环路在低信噪比下不收敛。观察环路误差信号,发现环路带宽太宽导致噪声引入过大。把环路滤波器系数调小后,收敛速度变慢但稳定了。后面添加了一个快速捕获/慢速跟踪双模式切换,先大带宽快速锁定,锁定后再切换到小带宽低抖动,效果很好。
问题四:ILA采集出来的波形总是和MATLAB仿真差一拍。最后发现是ILA的采集窗口没设置好,或者ILA的采样深度不够,采样窗口只覆盖了链路前级从而漏掉了后续模块的处理结果。ILA深度尽量设成最大的几分之一,并且用marker在关键信号上打标记,方便定位。
5.4 团队协作与代码管理
FPGA项目和软件项目在工程管理上有很大不同。软件工程讲究模块化和接口契约,FPGA工程更强调时钟架构、复位架构和位宽匹配。我曾经接手过一个别人写的模块,没有统一的复位策略,部分寄存器用异步复位部分用同步复位,连上系统后总出现偶发状态错乱。后来的规范是:所有模块统一用全局低电平异步复位,复位释放经过同步器后再分发到各个模块。
版本管理方面,建议除了代码和约束文件,IP配置文件也要纳入版本管理。Xilinx的.xci文件里包含了IP核的全部配置信息,如果不跟踪,换一台机器或者恢复旧版本时往往就编译不过了。我们在实践中用Git做版本管理,配合CI脚本自动化跑综合,每天下班前自动构建一次,第二天上班检查报告。这套流程让团队整体开发效率提升了不少。
6. 应用扩展与进一步优化的思考
6.1 从QPSK到更高阶调制
这个项目第一步做的是QPSK解调链路,但整个架构天然支持扩展到16QAM、32APSK等更高阶调制。高阶调制对幅度信息更敏感,所以AGC(自动增益控制)就变得重要了。QPSK只对相位敏感,AGC慢一点甚至没有都行,但16QAM如果幅度没归一化好,星座点之间的判决边界就会错乱。
从QPSK升级到16QAM,主要改动点包括:定时误差检测算法可能需要从Gardner换成基于功率梯度的方式,载波同步环路的鉴相器要换成判决辅助模式,AGC补偿从简单乘以常数变成真正的闭环控制。这些改动在现有架构里都不用推倒重来,只需要在数据处理链路里增加新的模块和模式切换逻辑。
6.2 多通道同步处理的资源规划
多通道中频处理是电子侦察和相控阵雷达里常见的需求。比如8通道的阵列信号,如果每通道都配独立的DDC链和基带处理链,FPGA的资源消耗会成倍增长。更合理的方案是分时复用:ADC多路数据先进FIFO缓冲,DDC和滤波部分用时分复用的方式共享同一套硬件资源,只是在不同时隙处理不同通道的数据。
这种方式资源利用率高,但需要精确控制流水线的时序安排,确保上一个通道的数据在下一通道到来之前处理完毕。Vivado里可以利用AXI4-Stream接口的tlast信号来标记每一帧数据的结束,数据调度逻辑根据通道号做轮询仲裁。实测下来,8通道的DDC链路资源占用大概只比单通道多50%左右,而不是8倍,效果非常明显。
6.3 软硬件协同的边界划分
随着Zynq这类SoC平台的普及,基带和中频算法到底跑在PL(可编程逻辑)还是PS(处理器)里,成了架构设计首先要回答的问题。
我的划分原则是:实时性要求高、数据吞吐大、对确定性延迟敏感的功能放PL,比如DDC、滤波、同步环路的反馈支路。实时性要求一般但算法复杂度高的功能放PS,比如LDPC译码的前期处理,信道估计的矩阵计算。自由度比较高的功能也可以放PS跑Linux,比如协议栈的MAC层调度。
这种软硬件协同设计带来的好处是在不牺牲实时性的前提下,把FPGA资源留给真正关键的信号链路,同时获得ARM生态里成熟的协议栈和调试工具支持。在最新的项目里,我甚至把一个简单的QPSK解调器完全用PS端的NEON指令集跑通了,虽然实时性不如PL方案,但作为备份解调链路或者算法验证平台绰绰有余。
6.4 一个值得留意的趋势:高动态范围与宽频数字化
现在的ADC性能越来越强,比如JESD204B接口的ADC采样率已经跑到几吉赫兹,一次采样就能覆盖几百MHz的瞬时带宽。这种情况下“中频”这个概念正在被淡化,传统的中频处理可以整体前移,甚至直接从射频采样开始。
但这并不意味着基带算法变简单了,恰恰相反,宽带信号给基带算法带来了更大的动态范围要求和新挑战。大量干扰信号和有用信号在同一个宽带里共存,抗干扰算法(比如自适应滤波、通道校正)反而变得更重要。如果你现在开始做FPGA通信算法,我建议多关注超宽带数字化后的信号预处理技术,比如通道均衡、非线性校正、干扰对消,这些方向在未来的系统设计里会越来越吃香。
我在这个项目里最后实现的功能已经超出了最初设计的中频+基带处理链路本身,还加入了一个简单的多通道功率检测与频谱监测模块,算是给后续扩展预留了一个探测口。整个项目做下来最深的体会是:FPGA算法实现没有一个统一的银弹,每个模块的设计都要结合具体指标、平台资源和系统约束反复权衡。多花时间在设计前期的参数论证和仿真上,后面调试才能少走弯路。
最后再分享一个小经验:在FPGA里做基带中频算法,代码写得好不好是一回事,但调试工具用得6不6同样重要。ILA的触发条件设计、分支判断、数据窗口深度的设置,这些细节做得好,定位一个bug可能只需要十分钟,否则可能折腾一整天。遇到异步问题不要着急改代码,先抓波形看清楚现象,再考虑是逻辑错误、时序问题还是配置问题。养成这个习惯之后,你会发现FPGA调试这件事,其实是可以被管理的。