FPGA基带与中频处理全解析:从DDC到定点化的工程实践
2026/9/7 5:15:18 网站建设 项目流程

1. 基带与中频在FPGA里的分工:先把整条链路说清楚

干FPGA通信方向这些年,我发现自己经常要跟刚转过来的同事解释一个看似基础、其实特别容易绕晕的问题:基带和中频,到底在FPGA里各干了什么活?为什么有些项目明明叫“基带板”,里面却塞了一堆数字上变频的逻辑?有些项目叫“中频处理”,却又在跑解调、译码的算法?

我个人的理解是,用一句话切分:中频部分负责“换乘”,基带部分负责“算账”。“换乘”指的是把信号在不同频率载波之间搬来搬去,让射频前端送下来的信号变成低速、干净的零中频或低中频数据,或者反过来把要发射的基带数据搬到中频载波上;“算账”则是真正跟信息内容打交道的活——同步、解调、译码、测量、识别,全是基带的事。

以我最近在Xilinx XC7K325T上做的一个宽带接收机项目为例,射频前端送进来的中频信号是140MHz,ADC采样率是245.76MSPS,FPGA拿到数据之后,第一步就是数字下变频(DDC),把140MHz的载波搬到零频附近,再把采样率从245.76MSPS降到比如38.4MSPS,这样后面的解调、分析模块才能用相对低的时钟把数据处理完。而最终输出给上位机的,是I/Q两路基带数据流,带宽大概在20MHz左右。

这里就有一个新手特别容易踩的坑:很多人以为DDC做完信号就“变成基带”了,其实不是。DDC只是把频谱搬到了零中频,信号本身仍然残留着载波偏频、符号定时偏差、信道畸变,这些“装修”问题都得在基带算法里去解决。换句话说,中频处理是把信号从“高频粗糙状态”搬回“低频可处理状态”,基带处理才是让它变成“干净可用的数据”。

还有一个容易忽略的点:发射链路和接收链路的处理顺序刚好是镜像的。接收是从中频到基带,发射是从基带到中频。很多项目组做接收链路做得非常熟练,一转到发射就卡壳——DAC前面为什么要插插值滤波器?为什么要做数字上变频?其实就是把接收链路的步骤反过来走一遍,但在工程实现上有个本质区别:接收链路是“减少数据量”,发射链路是“增加数据量”,这对FPGA的处理时序和缓存设计提出了完全不同的要求。后面我会专门展开说。

2. 数字下变频模块拆解:NCO、CIC、FIR这三板斧的选型逻辑

这一节是整个中频处理的核心,也对应着搜索引擎上很高的那个词——“中频检波有几种方法”。其实检波(或者说频谱搬移)在数字域里就是混频,方法上分类并不复杂,关键在工程实现时怎么选、怎么配。

2.1 混频器与NCO:相位累加器才是最容易被忽视的地方

数字混频的原理很简单,就是用本地产生的正弦/余弦序列乘上输入信号。FPGA里实现本地振荡器(NCO)最常用的方法是相位累加器:一个N位的累加器,每个时钟周期加上一个频率控制字,累加结果的高位查查找表(ROM),输出正弦和余弦值。

这里我要强调一个细节,相位累加器的位数直接决定了频率分辨率和无杂散动态范围(SFDR)。比如用32位累加器,工作在245.76MHz时钟下,频率分辨率是245.76MHz / 2^32,大概是0.057Hz,这个精度绰绰有余。但查找表的地址位数不能直接用32位,太浪费ROM资源了,一般会截取高16位或者经过抖动处理再查表。很多芯片手册上标称SFDR能到120dB以上,实际工程里如果不做抖动处理,直接用截位后的相位查表,SFDR可能只有70~80dB,白白浪费了ADC的动态范围。

关于查表还有个细节:如果你用的FPGA有DSP Slice(比如Xilinx的DSP48E1),可以考虑用CORDIC算法替代ROM查表。CORDIC的优势是不占块内存,适合需要同时输出多路本振、ROM资源吃紧的场景。缺点是有一定的流水延迟,而且位宽与精度的关系需要仔细算。我个人经验是:单通道、资源不紧张的用ROM查表,多通道、高并行的用CORDIC,两者实测性能差距并不大,关键看整体资源布局。

NCO的相位累加器还有一个容易被忽视的作用——产生精确的触发脉冲。比如你要做通道同步,可以让帧头到达时刻对应的NCO相位值作为一个可读寄存器,软件读到后就知道信号的精确到达时间。这在多通道测向、雷达测距项目里特别有用,比单纯用计数器做时间标记精度高得多。

2.2 CIC滤波器:抽取率大时的第一选择,但位宽一定要算清楚

混频之后,信号还在245.76MSPS的高速率上,直接做高精度FIR滤波虽然可行,但资源消耗很大。工程上的常规做法是先用CIC(级联积分梳状)滤波器做第一级抽取,把采样率降下来,再用FIR做第二级抽取和成形滤波。

CIC滤波器的优势在于不需要乘法器,只有加法器和延迟单元,结构极其规整。三阶CIC、抽取率4到16倍,是射频直采接收机里最经典的组合。以我之前那个项目为例,245.76MSPS经过4倍抽取变成61.44MSPS,再用半带滤波器和FIR降到38.4MSPS并完成信道成形。

CIC最大的坑在于增益。CIC的直流增益等于抽取率的N次方(N是级数),三阶4倍抽取的增益是4^3=64,也就是18dB。如果不在设计时就把这个增益算进去,后面的数据很容易溢出。正规的做法是在CIC每一级之后做合适的右移,或者在整个CIC模块输出端做一次统一的截位。

关于截位,我给一个能直接抄作业的经验公式:

假设CIC输入位宽为Bin,级数为N,抽取率为R,微分延迟为M(通常取1或2),那么内部寄存器位宽需要至少增加ceil(N * log2(R*M))位才能保证不溢出。三阶、4倍抽取、M=1时,增加位数为ceil(3 * log2(4)) = ceil(6) = 6位。如果你的ADC是16位输入,CIC内部至少要22位才能保证不饱和。

当然,这只是保证不溢出的理论下界,实际放量时可以再加1~2位冗余,给后面的信号波动留余地。这个冗余不是随便拍的,我算过,加上AGC留的6dB余量、成形滤波的过冲,22位基础上再补2位是比较稳的。

2.3 半带与FIR滤波器:抽取、成形、匹配各司其职

CIC之后,采样率已经降下来了,接下来就要考虑“整形”了。这里其实有两个任务:一是继续抽取降低速率,二是完成信道选择或者脉冲成形。

如果只是降速率,半带滤波器(Half-Band Filter)是性价比极高的方案——它有一半的系数是0,乘法器数量可以减半,通带和阻带又关于Fs/4对称,非常适合2倍抽取。如果还要同时完成信道选择和匹配滤波,就得用真正的FIR了。

FIR滤波器的系数设计,我一般直接用MATLAB的Filter Designer工具,目标函数根据系统要求来设。这里分享一个关键经验:不要只看通带纹波和阻带衰减这两个指标,还要看群延迟特性。通信系统里,匹配滤波器的群延迟不平坦会直接导致符号间干扰(ISI)变大。线性相位FIR天然保证群延迟恒定,所以通信系统里几乎不用IIR做信道滤波——除非你对相位完全不敏感(比如某些能量检测场景),否则IIR的相位非线性会让你后期做均衡做到怀疑人生。

系数量化也是个大坑。MATLAB里算出来的浮点系数看着很漂亮,转成16位定点后阻带衰减可能从-80dB恶化到-70dB,这个还能接受。但如果你为了省资源用12位甚至10位系数,阻带可能只剩-50dB出头,邻道抑制就废了。我的经验是:信道选择滤波器系数至少12位,最好16位;成形滤波器的系数精度直接影响EVM,建议直接给满16位,FPGA资源不够时优先优化别处,不要在这里抠。

3. 中频检波的五种实现方法与工程取舍

“中频检波有几种方法”这个问题在网上问的人特别多,因为它确实是中频处理的核心考点。检波的本质是从已调信号中提取出原始的调制信息。在FPGA里实现,常见的方法有这么几类:包络检波、乘积检波(同步检波)、正交检波、鉴频器检波,以及针对特定调制方式的专用检波(比如Costas环)。

3.1 包络检波与乘积检波:从模拟时代延续下来的两种思路

包络检波是历史最悠久的方法,结构也最简单——取绝对值,然后低通滤波。在FPGA里实现,甚至可以不用乘法器,绝对值加CIC低通滤波就够了。但是包络检波有两个明显的缺陷:一是它会把噪声的包络也检出来,信噪比差的时候性能急剧恶化;二是它对载波幅度敏感,必须配合AGC使用。所以它只适合AM解调、简单的信号检测等场景,不适合现代数字通信。

乘积检波,也就是同步检波,本质就是我前面讲的混频——本地恢复一个与载波同频同相的参考信号,乘上去,低通滤波,得到基带信号。它的优势在于可以获得更高的处理增益,而且对载波幅度不那么敏感。缺点是必须解决载波同步问题——本地参考信号的频率和相位必须跟输入载波对齐,否则解调出来的基带信号会带有残余频偏和相位旋转。这就引出了同步检波的核心技术:载波同步环路。

在工程上,我推荐一个实用的判别标准:输入信号信噪比高(比如>20dB)、且你对硬件成本敏感时,包络检波可以作为快速方案;但只要是正经的通信解调链路,老老实实上同步检波,后面接载波同步和符号同步环路,性能和鲁棒性都远超包络方案。

3.2 正交检波:现代软件无线电的基石,I/Q采样到底解决什么问题

正交检波和乘积检波在原理上是一回事,但工程上它特指把信号同时与余弦和正弦两路本振相乘,得到I/Q两路正交基带信号。这么做不是为了多此一举,而是为了保留信号的完整相位信息——单路乘积检波只能得到一个标量基带信号,丢失了相位正负的区分能力,而I/Q两路合在一起,就能完整保留信号的幅度和相位,任何调制方式都能处理。

FPGA里实现正交检波,一个很简明的模块划分是这样的:

  • 输入中频信号进两个乘法器;
  • 乘法器的另一个输入分别是NCO的余弦和正弦输出;
  • 两路乘法结果分别进两级抽取滤波(CIC/FIR组合);
  • 输出是低速的I/Q并行数据。

这里有个资源优化的技巧:如果输入信号本身就是窄带的,可以先做一次实信号的带通采样(欠采样),让信号“折返”到一个较低的IF频率,再进正交检波,这样前面的处理时钟可以降一档,整板的功耗和布局压力都会小很多。

3.3 直接利用相关运算和能量检测:面向检测任务的FPGA实现

除了常规的解调,中频检波在很多场景下其实是用于“检测”而非“解调”,比如雷达回波检测、频谱监测、突发信号捕获。这时候用同步检波就有点杀鸡用牛刀了,反而应该用相关运算或能量检测。

能量检测是最简单粗暴的:对中频信号做平方(或者取绝对值),然后积分,再与门限比较。FPGA实现时我会用滑动窗口积分,窗口长度取信号带宽的倒数。相关检测则更精密:本地存一个已知波形的副本,对接收信号做滑动相关,相关峰超过门限就判定检测到信号。FPGA里做相关检测可以用多个乘法器并行做滑动相关,也可以用FFT实现频域相关。

这里给一个实际的调参经验:门限设多少,不能拍脑袋。先采集一段只有噪声的数据,统计噪声功率的分布,把门限设为噪声均值的4~6倍(也就是噪声标准差的一个倍数),对应虚警概率通常在10^-3以下。你要追求更低的虚警,就按瑞利分布的尾部概率反推门限倍数,不要凭感觉往上加,否则检测灵敏度会损失得很厉害。

4. 基带算法的FPGA定点化:从浮点到定点的踩坑清单

这一节可能是全文里最“值钱”的部分。很多算法在MATLAB里跑得漂漂亮亮,一上FPGA就出各种怪问题,几乎都可以归结到定点化这个环节。

4.1 为什么不能直接在FPGA里跑浮点

FPGA里可以跑浮点,但大部分场景不建议。浮点运算在FPGA里的资源开销大约是定点的4~6倍,时序收敛难度也高出一截。通信链路的数据流基本上是流式的,定点化完全够用,浮点只有在做解矩阵、求逆等动态范围极大的算法时才值得考虑。

但这不代表定点化可以随便拍位宽。定点化的核心是给数据的“动态范围”和“精度”分别兜底。动态范围由整数位决定,精度由小数位决定。很多新手只看“精度够不够”,却忘了算“动态范围够不够”,结果信号一来大的就溢出,输出直接削波。

我的定点化流程是这样的:

  1. 先在MATLAB里把算法的浮点模型跑通,把中间各级信号的峰峰值和均方根值都打印出来;
  2. 根据峰峰值定整数位,留至少6dB裕量(一般多留1~2位);
  3. 根据信噪比要求定总位宽,减去整数位得到小数位;
  4. 在MATLAB里用fi对象模拟定点模型,对比浮点模型的EVM/SNR,不达标就调整位宽。

这里有个原则:不要在链路里随便截位。每截一次位,就引入一次量化噪声,截多了噪声会累积。宁可每级多保留1位,最后统一截一次。

4.2 增益管理与削波保护:AGC不是“可选项”

数字通信链路里,信号幅度波动是常态。AGC(自动增益控制)在中频和基带链路里的作用,是把信号幅度归一化到一个合适的范围内,让后级的解调器工作在最优点。

FPGA里实现AGC的经典结构是反馈环路:检测输出信号的功率,与参考电平比较,误差经过环路滤波器(通常是一阶IIR),去控制一个数字乘法器的增益。工程实现上有几个关键参数:

  • 检测窗口长度:决定AGC响应速度,窗口太短容易受调制信号本身的包络波动影响,太长则跟不上衰落;
  • 环路带宽:决定AGC的抗噪声能力,带宽越窄越稳,但响应越慢;
  • 增益更新步进:决定环路的收敛精度,步进太大在稳态时会有明显的增益抖动。

我给一个参考配置:对20MHz带宽的QAM信号,AGC检测窗口取256个采样点,环路带宽大约取符号速率的1/100,增益更新步进取0.001(用乘法器实现,相当于每次调整0.01dB左右),实测稳态增益抖动可以控制在0.05dB以内。

特别提醒:AGC一定要放在匹配滤波之前,否则滤波器的系数归一化会让AGC环路出现奇怪的耦合现象。别问我怎么知道的,但如果你已经踩过,应该懂我在说什么。

4.3 一个具体的定点化验证案例:16QAM解调链路的位宽分配

我拿一个自己调过的16QAM解调链路举例。符号速率10Msps,中频70MHz,带通采样率80MSPS,后端解调在FPGA内部完成。

链路各级的位宽分配是这样的:

链路节点位宽整数位小数位设计依据
ADC输入14211芯片给定,符号+幅度
混频输出18413在ADC基础上加增益裕量
CIC输出24815避免CIC增益溢出
FIR输出20415滤波后信噪比最佳点
AGC输出18215幅度归一化后动态范围压缩
匹配滤波输出16114后续解调仅需此精度

这套配置在MATLAB定点仿真里,EVM从浮点的0.8%恶化到1.5%左右,但仍在16QAM的3%指标要求内。如果我把FIR系数从16位降到12位,EVM会直接飙到4%以上,所以说系数精度真是不能省。

4.4 用MATLAB定点模型做“影子验证”

我在项目里的习惯是,FPGA每个模块的定点模型会在MATLAB里保留一份,用同一组测试向量分别跑MATLAB定点模型和FPGA仿真,两者输出做逐点对比。FPGA输出的数据可以通过ILA抓出来,导出成文件,然后在MATLAB里跟定点模型的输出做减法,看误差曲线。

这个“影子验证”的习惯帮我抓出过不少问题,比如某个截位位置错了、某个状态机在边界情况下多等了一个周期、某个符号位处理反了等等。如果你的项目还没建立这套验证流程,我强烈建议补上。这是一次性的投入,但省下的调试时间可能是几周的量。

5. 从算法到工程:锁相环、定时同步与高速接口的落地细节

5.1 Costas环与Gardner定时同步:基带同步的两座大山

同步检波的关键是载波同步。在FPGA里,最常用的载波同步结构是Costas环——它本质上是一个特殊的锁相环,通过鉴相器输出的误差信号驱动NCO,让本地载波持续跟踪输入载波。

Costas环的环路滤波器设计是重中之重。我习惯于用模拟域的经典二阶环参数换算到数字域:先根据捕获范围、噪声带宽确定环路自然频率ωn和阻尼系数ζ(通常取0.707),然后用双线性变换得到数字域的环路系数。环路滤波器的输出接到NCO的频率控制字上,形成二阶环。

实际调环路的经验:环路带宽太宽,收敛快但抖动大;太窄,抖动小但捕获慢。我一般先把环路带宽设成符号速率的1/100左右粗调,收敛后再切到1/500提升稳态精度。用Xilinx的FPGA实现时,NCO的频率控制字位宽和环路系数的定点字长都值得仔细推敲——环路系数太粗会让稳态相位误差出现明显的台阶抖动,在星座图上表现为“毛刺”。

跟载波同步同等重要的是符号定时同步。Gardner算法是FPGA里最常用的定时同步算法之一,它的优点是只需要每个符号两个采样点(每个符号取两个点就可以计算定时误差),而且对载波相位不敏感,可以跟Costas环级联。

Gardner算法在FPGA里的实现,我建议用Farrow结构的分数延时滤波器做插值,verilog实现比较方便。插值器的系数可以根据定时误差实时调整,形成定时同步环。这套架构在10Msps~100Msps的符号速率范围内都很稳定。

5.2 发射链路的数字上变频:反向思考数据量,三条心得避免卡壳

之前提过发射链路是接收链路的“镜像”,但它在FPGA工程上有一个显著的差异:数据流是扩张的。接收时数据量越来越少,发射时数据量指数级增多,这会导致:

第一,插值滤波器的每一级都会产生新的数据点,必须把时序规划清楚,否则高数据率侧的FIFO会瞬间溢出。我的做法是用AXI4-Stream总线的ready/valid握手来控制上下游速率,让每一级都能反压,这样即使上游暂时处理不过来,下游也不会丢数据。

第二,数字上变频之后的数据率通常很高,DAC接口经常要跑几百MSPS。Xilinx 7系列FPGA里,高速串行接口一般需要把多路并行数据拼成DDR输出,或者用OSERDES把并行数据串行化。这里最容易出问题的是位顺序和字节顺序搞混,一上板就是频谱反转或全乱码。建议在第一版设计里就加入一个固定的测试码型,上板之后先用它验证接口字节序,再跑真实信号。

第三,发射链路通常在最后一级加削峰(Crest Factor Reduction, CFR)和预失真(DPD)的预留位置。如果项目规划里有功放线性化需求,DUC输出就应该预留额外的增益调整位,否则后级DPD一开,动态范围瞬间不够。

5.3 AXIS、PCIe与FMC:FPGA和外部世界打交道的三种姿势

FPGA做基带中频处理,很少是独立存在的,总得跟CPU、ADC、DAC打交道。

我常用的接口方案强烈推荐AXI4-Stream(AXIS)。它是一种点对点的流式接口,用VALID/READY握手,非常契合通信链路“数据流”的特性。我的经验是:FPGA内部所有模块之间,一律用AXIS;模块之间禁止直接用内部使能信号传数据,否则时序一复杂,各种毛刺和粘滞问题就来了。

跟STM32这类MCU通信,FMC接口是很实用的选择。STM32H743的FMC接口可以作为FPGA的并行从设备接口,FPGA这边用简单的双端口RAM或者寄存器堆来对接。但要注意:FMC的总线时序是异步的,FPGA侧必须做同步处理,否则偶尔会出现数据读到一半被更新的情况。我踩过这个坑,最后的解决办法是给FMC分配一个专用的数据锁存寄存器,再用双缓冲机制确保读写不会互相干扰。

如果数据量更大,比如要往CPU传完整的频谱数据,PCIe是正路。Xilinx 7系列里集成PCIe硬核,用XDMA IP可以很方便地把AXIS数据搬运到主机内存。但PCIe的调试难度比FMC高出不少——链路训练、中断机制、DMA描述符管理,每一个环节都能卡很久。建议在FPGA工程里单独建立PCIe自测模块,回环验证通过之后再接入真实数据通路。

5.4 上板调试三板斧:ILA、离线回放、频谱对比

最后聊一下调试。前面讲了那么多设计和实现,但真正让FPGA工程落地的,是调试手段。我带项目的时候,一直强调“先让数据可见,再谈算法”,看不见数据,算法调得再好也白搭。

ILA(Integrated Logic Analyzer)是Xilinx FPGA里最常用的在线调试工具。但ILA也有局限:采样深度不够,只能抓到几千到几万个点,想看长时统计就抓瞎了。

我常用的替代方案是“离线回放”,把ADC的原始数据流持续写入DDR,需要时再通过PCIe或串口回传到上位机,用MATLAB离线做频谱分析、EVM统计。这个方法特别适合排查“间歇性”问题——比如某个突发干扰到底是怎么进来的,在线抓点抓不到,回放数据一统计,全清楚了。

还有一个调试维度容易被忽略:频率域的对比。有时候你在时域看信号波形完全是乱的,但频谱图一摆出来,立刻就知道问题出在混频还是滤波。我的习惯是,FPGA工程里把FFT模块作为常备IP,随时可以切换观察频域,这比只看ILA的时域波形高效得多。

6. 按场景选架构:不同项目里,基带中频的最优解不一样

最后想聊聊方案取舍。很多人问“FPGA选型有没有统一标准”,我的答案是没有,但可以根据场景确定优先级。

先看一个简单对照表:

项目类型指标重点常见架构难点FPGA选型倾向
软件无线电接收机带宽、动态范围、通道数DDC/DUC通道多、同步要求高中高端Kintex/Virtex,资源优先
雷达信号处理实时性、确定性、多级流水大点数FFT、脉冲压缩DSP资源丰富的器件
通信基带处理符号速率、EVM、时延同步环路定性、交织/均衡平衡型,逻辑+乘法器充足
小型化低功耗产品功耗、成本、尺寸单芯片集成RF+基带集成RF-ADC的Zynq RFSoC
科研教学验证快速原型、灵活性接口简单,重在算法验证主流Artix或Zynq入门即可

拿我之前做的一个多通道测向设备举例,8路中频信号并行采集,每路都走DDC下变频,最后汇聚到基带做相位比较。这种项目资源评估时,DSP Slice和Block RAM是真正的瓶颈,逻辑单元反而是次要的。当时估完资源,选择直接上了Kintex-7 325T,如果贪便宜用Artix-7,可能路由都跑不通。

反过来,如果你的项目只是做单通道的解调验证,一块Artix-7或者Zynq-7020完全够了,强行上高端器件只会增加BOM成本和设计难度。

还有一个建议:选型时把“未来可能的升级”也算进去。比如你现在的项目只需要100MSPS的ADC,但下一版可能要200MSPS,那FPGA选型时就尽量选支持这个速率接口的器件,至少留出GTH/GTX高速收发通道的余量。接口裕量不够的板子在项目后期是最痛苦的——算法改完了,硬件却上了一版又一版。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询