基带与中频的FPGA实现:从数字下变频到定时同步的完整指南

发布时间:2026/9/8 7:13:31
基带与中频的FPGA实现:从数字下变频到定时同步的完整指南 1. 怎么理解“基带与中频的FPGA实现”这回事先说个亲身经历。早几年我接手过一个无线数传项目板卡上射频前端用的是零中频方案ADC出来直接就是基带I/Q刚开始觉得省事省掉了中频那一大堆变频和滤波电路。结果调试时才发现模拟零中频的直流偏置、I/Q失配、本振泄漏全压在基带算法头上光靠数字域补偿就折腾了好几周。后面再做另一个项目果断回到“射频-中频-数字中频-基带”的经典架构虽然前端多了几级模拟混频和滤波但数字侧的处理链路反而清爽了很多。这里要先理清一个很多人容易含糊的概念基带和中频在通信链路里到底各管哪一段。基带信号承载有效信息的低频信号频率范围通常从直流到几MHz到几十MHz。在数字域里基带I/Q就是调制解调、同步、均衡这些核心算法的主场。中频信号把射频信号搬移到几十MHz到几百MHz的固定频率上方便ADC采样和后续数字处理。比如常见的70MHz、140MHz中频或者L波段接收机里的某个高中频。FPGA在这个领域的位置特别微妙。CPU适合跑复杂协议栈但并行度有限DSP适合跑流式算法但乘加吞吐和接口灵活性不如FPGA而FPGA天然是并行处理机器几百个乘法器可以同时开工数据通路一拍一拍往下流延迟可以做到微秒甚至纳秒级。对于基带和中频这种“吞吐量大、算法固定、实时性硬”的处理任务FPGA就是最顺手的工具。我现在做这类项目基本流程都是这样先用Matlab或者Python把浮点算法验证一遍拿到理想的误码率和频谱指标再把算法模块按FPGA资源去切分确定位宽和定点格式然后用Verilog或者System Verilog去实现Vivado或Quartus里做仿真和时序收敛最后上板用信号源和频谱仪联调。整套链路的难点不在某个单一模块而在“每一级都要考虑资源、时序、性能三者的平衡”。2. 基带算法核心成形滤波、定时同步和载波同步2.1 发射端成形滤波为什么不能省基带发送链路里成形滤波是第一道门槛。它的作用是限制信号带宽同时减少码间串扰。理想情况下我们用升余弦滤波器实际工程中收发双方各用一个根升余弦滤波器合起来正好是升余弦响应。FPGA里实现成形滤波器我一般直接搭一个对称FIR。常用的参数组合是滚降系数0.2到0.35之间取决于系统带宽约束。滚降系数越小带宽越窄但脉冲拖尾更长对定时误差越敏感。过采样率每符号采样点数常用4或者8。点数越多滤波后信号波形越细腻但数据率越高。滤波器阶数一般取4到8个符号周期长度也就是16到64阶不等。举一个实际计算例子。假设符号速率是2Msps过采样率取4那数据率就是8MHz。用根升余弦滤波器滚降系数0.25符号周期长度取6滤波器总长度就是6乘4加1等于25个抽头。系数用Matlab的firrcos函数生成量化到16bit有符号数。Verilog实现里我习惯用移位寄存器把数据流串起来再调DSP48原语做乘累加。对称FIR可以先做加法再乘系数能省一半乘法器。比如25个抽头对称之后只需要13个乘法器。注意发射端成形滤波的过采样率决定了后面DAC的更新率也要考虑DAC镜像抑制。如果有模拟重构滤波器过采样率太低会导致镜像频率离主瓣太近模拟滤波很难压住。2.2 定时同步用Gardner算法简单又实用接收端基带处理最关键的一环是定时同步。信号经过信道和ADC采样之后采样时钟和发射端符号时钟不完全一致必须从信号里提取出最佳采样时刻。做定时同步我最常用的是Gardner算法。它的好处是不依赖载波同步即使存在残余频偏也能完成定时恢复而且每个符号只需要两个采样点。Gardner算法核心是定时误差检测公式error (x(n) - x(n-1)) * x(n-1/2)这里x(n)是当前符号采样点x(n-1)是前一个符号采样点x(n-1/2)是两个采样点中间时刻的采样值。误差信号经过环路滤波器去控制数控振荡器和插值滤波器从而调整最佳采样时刻。FPGA实现里插值滤波器我用Farrow结构三阶或者二阶就够了。Farrow结构的好处是插值系数可以通过小数间隔动态计算避免存储大量查找表。环路滤波器的参数设计要费点心思。典型的二阶环路有三个参数带宽、阻尼系数、增益。工程上我习惯这样估算归一化环路带宽设为符号速率的1%到2%兼顾捕获速度和抖动。阻尼系数取0.707滤除高频噪声同时保持收敛稳定。环路增益根据鉴相器增益和NCO增益综合算最后在仿真里微调。2.3 载波同步Costas环实现QPSK解调载波同步解决的是接收端本地载波和发送载波之间的频率偏移和相位偏移问题。对QPSK这类抑制载波的调制方式推荐用Costas环。Costas环的鉴相器在FPGA里就是一个反正切近似计算。QPSK的误差信号可以写成error sign(I) * Q - sign(Q) * I这个公式在星座图四个象限上都能正确收敛而且实现起来只需要比较器、乘法器和加法器资源开销很小。我做过一个典型实例符号速率1Msps载波频偏5kHz以内用二阶环路环路带宽200Hz捕获时间能做到几十毫秒量级。环路滤波器系数用定点化之后I路和Q路的乘法位宽要留足不然接近收敛时误差信号会抖动导致误码。基带这块还有一个容易踩的坑I/Q增益不平衡和正交不平衡。如果在设计中频部分用了模拟混频I路的ADC增益和Q路ADC增益不一致或者本振的I/Q两路相位差不是严格的90度星座图就会变成椭圆或者平行四边形。补偿通常在基带做用一个简单的LMS自适应滤波器就可以实时估计并补偿但前提是FPGA里要把这个模块放在定时同步和载波同步后面而且最好在捕获阶段先收敛。3. 中频算法的重头戏DDC与DUC3.1 数字下变频的整体架构从天线进来的射频信号经过模拟前端变频到中频后ADC以较高的采样率采样。比如一个典型配置是ADC采样率122.88MHz中频频率30.72MHz信号带宽20MHz这时候信号还是中频实信号数据率太高基带处理跑不动而且也不需要这么高的速率。DDC的任务就是完成频谱搬移、抽取滤波把高采样率的中频信号变成低采样率的基带I/Q信号。DDC的标准流程是数字混频把中频信号乘以NCO产生的正弦和余弦把频谱搬移到零频附近。低通滤波滤掉混频产生的高频分量同时作为抗混叠滤波器。抽取降低采样率。通常是CIC加半带加FIR的多级抽取结构。增益调整补偿CIC的增益保证信号幅度在后续处理范围内。3.2 频率规划与NCO设计NCO是DDC的“本地本振”用来产生数字正弦和余弦信号。我常用的架构是直接数字频率合成器核心是相位累加器加相位到幅度的查找表。相位累加器位宽一般做32bit频率控制字计算方法是频率控制字 目标频率 * 2^32 / 采样率比如采样率122.88MHz目标本振频率30.72MHz那频率控制字就是30.72e6 * 2^32 / 122.88e6 2^30 1073741824这个数正好是2的幂次NCO输出频率就非常准确。但相位累加器位宽32bit查找表不可能做4G深度必须截断。我一般截断到16bit也就是查找表深度65536这样无杂散动态范围能做到90dBc以上。如果要求更高可以再加一个小的补偿表或者用两个查找表做线性插值。经验NCO输出用查表方式实现比直接用CORDIC节省LUT但消耗BRAM。Xilinx和Intel都有现成的DDS IP核内部已经优化过相位截断杂散工程上直接调用比自己写省心。3.3 CIC滤波器抽取率大的首选CIC滤波器在数字下变频里是个非常实用的角色。它不需要乘法器只用积分器和梳状器适合做高倍率抽取。CIC的幅频特性是带通形状效果不好通带内有倾斜所以要和后面的补偿滤波器配合使用。一个三阶CIC抽取倍率32微分延迟1那么带内容差在信号通带边缘可能超过好几个dB必须在后级FIR里补偿。CIC的增益计算也很重要。每级积分器的增益是R抽取倍数如果阶数是N总增益就是R的N次方。举个例子R32N3总增益就是32的三次方等于3276815bit的增益。如果输入信号16bitCIC输出位宽需要置到输出位宽 输入位宽 N * ceil(log2(R))也就是16 3 * 5 31bit。如果不留足这个余量信号在里面就溢出了。3.4 半带滤波器与FIR补偿滤波器CIC做完高倍率抽取后采样率降低了很多但还需要进一步抽取。这时候半带滤波器就派上用场了。半带滤波器是一种特殊的FIR滤波器它有一半的系数是零所以乘法器数量只有普通FIR的一半特别适合FPGA实现。半带滤波器的频率响应特点是通带和阻带关于四分之一采样率对称。每一级半带完成2倍抽取不会造成频谱混叠因为抽取前已经把高频分量压掉了。实际工程里抽取链路常见分配是CIC32倍抽取第一级半带2倍抽取第二级半带2倍抽取FIR2倍抽取总抽取率128倍。信号进来是122.88MHz出来是960kHz20MHz带宽信号到960kHz采样率刚好够再往下就太紧张了。最后的FIR滤波器主要做三件事补偿CIC和半带的通带倾斜、提供精确的带外抑制、完成整形让信号进入基带处理时信噪比最优。FIR补偿滤波器的系数我在Matlab里用firls或者firpm设计带内纹波目标0.1dB以内阻带抑制60dB以上。3.5 数字上变频DUCDUC是DDC的镜像操作流程是基带I/Q信号先内插再滤波最后混频到中频。内插过程里零值插入会产生镜像频谱必须用滤波器滤除。同样用半带和CIC的级联结构只是方向反过来了。DUC的CIC要设计成插值型而不是抽取型。插值型CIC在梳状器和积分器的顺序上是反的先梳状再积分这样避免在插值过程中数据速率过早升高。NCO在DUC里也是必不可少的它产生混频载波把基带信号频谱搬移到中频频率上。我用过一个项目基带信号带宽10MHz中频70MHz采样率112MHz。DUC输出直接接到DAC信号出来后经过一个简单的带通滤波器就能送进上变频混频器。3.6 中频检波的几种典型方法中频信号除了走DDC变成基带I/Q之外有时还需要做包络检波或者同步检波用于AGC控制、信号检测或者非相干解调。常用的几种方法我整理如下包络检波最简单的方法对中频信号取绝对值后低通滤波得到的就是信号包络。FPGA实现就是abs加滑动平均或者一阶IIR。优点是资源少、没有载波同步要求缺点是抗噪声能力弱信噪比低时包络估计偏差大。同步检波先用Costas环或平方环恢复出相干载波然后和中频信号相乘再低通滤波得到基带信号。同步检波对微弱信号检测能力明显优于非相干检波但实现复杂度高必须有载波同步模块。乘积检波把中频信号分别和正交本振相乘得到I/Q两路然后取模得到包络。这种方法相当于简化版的DDC不用完整抽取滤波也能获得较好的包络精度。对数检波对包络取对数压缩动态范围。常用于雷达接收机的灵敏度时间控制或者通信系统的AGC自动增益控制。我实际做接收机时AGC环路里用的就是对数检波因为输入信号动态范围可以达到80dB以上线性包络处理不了这么大的动态。FPGA里实现对数可以用查找表分段线性拟合也可以精度要求不高时用查表最方便。4. 从算法到FPGA的关键设计细节4.1 定点量化浮点算法落地第一关Matlab里算法验证完最痛苦也最关键的环节就是定点化。浮点转定点不只是简单把小数换成整数而是要逐级分析信号动态范围确定位宽和小数点位置。我常用的做法是在Matlab里把信号按16bit量化逐级仿真统计每一级输出的最大峰值和噪声底确定位宽。一般规律是输入ADC数据16bit按照ADC满量程设计。NCO输出16bit正弦和余弦小数点在符号位后面。混频器输出16bit乘16bit得到32bit然后截断到合适位宽。滤波器内部累加器根据滤波器增益额外留4到8bit余量。最终基带输出16bit到24bit不等取决于后端算法要求。截断的坑特别多。直接截断会产生直流偏置最好用带符号舍入虽然多几个LUT的资源但能避免频谱上出现多余的分量。我吃过亏有一次省略了舍入直接截断结果星座图偏了一个方向误码率怎么都降不下去最后用频谱仪看到直流分量异常才排查出来。4.2 资源与性能的权衡CIC、半带、FIR选型多级抽取滤波器的组合不同方案资源差异能到好几倍。我做性能评估时列过一张对比表方案乘法器数量逻辑资源带内容差阻带抑制全FIR抽取多直接级联中等小易控制高CICFIR很少低中等需补偿中CICHBFIR少低小补偿量小高实际项目我基本都用CICHBFIR组合原因很简单乘法器是FPGA里最宝贵的资源直接决定能不能在目标芯片上布局布线。Xilinx 7系列的中端芯片比如XC7K325T有840个DSP slice看似很多但一路DDC如果不加CIC直接用FIR做32倍抽取可能就要消耗两三百个DSP四个通道就爆了。用CIC降到4倍采样率再给FIR做整形FIR阶数可以直接减少一个数量级。4.3 时序收敛的工程经验FPGA做中频算法时钟频率往往在100MHz到300MHz之间。这个频率不夸张但算法链路长容易在时序上出问题。我修时序收敛的常用招数把大FIR滤波器拆成多个小滤波器级联中间打一拍寄存器虽然延迟增加几拍但路径变短fmax能明显提升。CIC滤波器内部本身就是流水线结构注意积分器回路的反馈路径这里容易成为关键路径。三阶CIC的话可以拆成三个积分器串联每个之间插入寄存器。DDC处理多通道时尽量让不同通道共享滤波器系数数据按通道时分复用资源省了但要注意控制逻辑不能成为瓶颈。跨时钟域处理必须用异步FIFO或者打两拍同步尤其是ADC采样时钟和FPGA内部处理时钟不同源时一个亚稳态就可能把整条链路的数据搞坏。4.4 IP核和手写RTL怎么选Xilinx和Intel都提供了大量数字信号处理IP核比如FIR Compiler、CIC Compiler、DDS Compiler。我的经验是标准模块优先用IP核比如FIR和CICIP核在资源优化和时序收敛上比大多数手写代码做得好。NCO可以用IP核但要注意输出格式和FIFO接口的配合。控制器、状态机、同步逻辑这些完全手写。特殊算法模块比如非标准的定时同步环路、自定义位宽变换逻辑IP核覆盖不了必须手写。IP核的问题在于它像个黑盒子调试时不好定位内部问题。所以我的建议是先用Matlab算出每级输出的参考数据存成文本文件然后用Testbench读进IP核和手写模块逐级对比输出。这一步在仿真阶段就能过滤掉大部分接口不匹配的问题。5. 调试过程中的常见问题和排查方法5.1 同步环路锁不住定时同步环或者载波同步环锁不住先说结论九成以上是环路增益设置不对。我排查环路问题的步骤是先断开环路把误差信号和理论值对比确认鉴相器符号对不对。如果符号反了环路肯定发散。把小信号响应计算值打印出来和仿真对比确认滤波器系数在定点化后没有溢出。把环路滤波器输出的位宽调出来看如果逐拍增大就是正反馈了。最后再看初始频偏是不是超出了环路的捕获范围超了就先用FFT估计频偏做补偿再交给环路。另外插值滤波器Farrow结构的输出位宽要足够不然误差信号在小幅度时被量化噪声淹没环路永远在抖动。5.2 CIC滤波器增益溢出CIC滤波器增益大位宽不够就会溢出表现为频谱上出现异常高次分量信号波形削顶。排查方法很简单用单音信号打到DDC里逐级检查CIC输出信号的峰值。如果峰值刚好在最大位宽边界反复跳动那就是溢出直接加大位宽。记住那个公式输入位宽加N乘log2(R乘M)任何一款教科书里都是这么算的。5.3 NCO杂散过大NCO相位截断会引入杂散如果杂散落在信号带内就无法滤除直接影响信噪比。我的经验是相位累加器32bit查表地址16bit无杂散动态范围基本能到90dBc。如果发现杂散还是高先检查查找表是不是用了正弦对称性优化对称查找表如果符号处理不当会产生偶次谐波。还有就是输出端加了幅度抖动dither虽然能展宽噪声基底但能压掉很明显的杂散分量前提是系统可接受噪声底略微抬升。5.4 多通道数据错位多通道DDC或者DDC加DUC同时使用时容易出现通道间数据错位导致波束或者分集合并效果变差。我在设计中会在数据帧头打一个同步标记字每个通道都带着这个标记走完整条链路在基带输出端检查标记是否对齐。这个方法虽然土但特别有效。还有一种做法是定时输出测试序列在基带端比对。5.5 Vivado仿真和上板结果不一致这个问题很让人头疼。仿真一切正常上板就乱。最先是检查时钟仿真里时钟都是理想时钟上板后时钟抖动和相位噪声会影响ADC采样尤其是高速ADC。其次是检查复位异步复位释放时的时序如果没有约束好寄存器可能出现亚稳态。第三是检查未初始化的RAMBRAM上电初值未必是零有可能随机值需要显式初始化。我有个习惯仿真工程师在Testbench里故意把复位往后延迟几拍并且给时钟加一个正弦抖动这样能提前暴露不少问题。6. 使用FPGA和STM32H743配合实现FMC通信的选型参考最近有不少朋友问到FPGA和STM32的配合这块虽然不是基带中频算法本身但在很多验证平台里都会用到。常见组合是STM32H743做控制和数据分发FPGA做信号处理两者通过FMC总线通信。FMC的并行接口数据率可以跑到几十MB/s对控制命令下发和状态回报来说完全够用。设计时要特别注意时序约束STM32H743的FMC有独立的读时序和写时序参数FPGA侧需要根据手册配置建立时间和保持时间。FPGA侧一般做成异步SRAM接口即可使用双口RAM做跨时钟域缓冲。如果做的是数据采集系统FPGA把DDC后的基带数据写入双口RAMSTM32通过FMC读出如果做的是信号源STM32写入波形参数FPGA根据参数生成DDS数据。两种方向我都做过关键都是定好双方约定的寄存器地址映射和数据帧格式避免协议纠缠不清。7. 最后分享一个心得基带与中频的FPGA实现我做了不少项目踩过很多坑。如果只给一个建议那就是不要一上来就照着算法理论推公式先把手里的信号拉出来看用Matlab写一个端到端的浮点模型跑通之后再做定点化。整个过程里最耗时间的往往不是写RTL而是定点化调试和时序收敛。再一个是工程习惯的问题。每级滤波器、每个混频器、每个环路都要在Testbench里单独做一级验证再连链路。跳级联调一旦出错定位问题的时间会是逐步联调的十倍以上。信号处理链路的排错靠的是“分而治之”FPGA的优势是每一级都有明确的输入输出利用好这个特性整个设计就没那么玄乎。