ARTICLE DETAIL

资讯详情

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

FPGA基带与中频算法实现:从DDC到同步均衡的工程实践

FPGA基带与中频算法实现:从DDC到同步均衡的工程实践 跟很多做FPGA的兄弟聊天时发现一个普遍现象数字信号处理的理论课都学过但一到“基带”和“中频”这些词在FPGA工程里落地就很容易懵。中频算法到底是谁在管基带算法又该放在哪一级为什么板子上同时接了ADC、LVDS、PCIe、MIPI算法链路一复杂资源和时序就开始打架这些问题我在不同项目里反复遇到过所以这篇把基带与中频的FPGA算法实现与应用技术做一个系统梳理。内容会涵盖整体设计思路、DDC/DUC、同步、均衡、信道估计、编解码等核心算法的FPGA落地方案以及FMC通信、PCIe、LVDS这些实际工程中离不开的接缝技术。无论你是刚入门FPGA通信开发还是已经在做软件无线电、雷达信号处理这篇文章应该都能帮你把脑子里那团算法云变成一张可以施工的图纸。这个领域最讨巧的地方在于FPGA的并行性和算法的高吞吐需求天生合拍。中频侧的信号速率动辄上百Msps靠DSP串行处理往往捉襟见肘FPGA则可以把抽取、混频、滤波拆成多个并行支路用面积换速度。基带侧的同步和均衡虽然算法复杂但符号速率相对低给FPGA留出了大量流水线调优空间。所以说中频和基带在FPGA上其实各有各的难题理解清楚它们的分工后面实现起来才能有的放矢。1. 基带与中频算法在FPGA上的整体设计思路1.1 先分清分工中频处理的是“波形”基带处理的是“符号”很多项目一上来就铺开整个收发链路结果大家讨论问题时驴唇不对马嘴。我习惯先画一条红线中频处理的是实信号波形基带处理的是复基带符号流。这条线画清楚了模块划分就顺了。中频侧的典型任务包括DDC数字下变频、DUC数字上变频、中频检波、AGC、CIC滤波、半带滤波、IQ不平衡校正等。这些模块处理的都是“点”也就是ADC采样出来的一个个数据点采样率越高每秒过的点数越多对并行度要求就越苛刻。基带侧的典型任务则是符号同步、载波同步、均衡、信道估计、解映射、信道编解码等处理的是“符号”符号速率远低于采样率每个符号对应多个采样点数据率更友好但算法逻辑更复杂状态更多。FPGA平台上的经典结构是ADC进来的射频/中频信号先经过数字下变频变成零中频的I/Q基带信号经过抽取降速交给基带算法。发射侧反过来基带I/Q数据经过成型滤波、插值、数字上变频变成中频实信号送给DAC。这条链路的每个环节都可以在FPGA里用Verilog或SystemVerilog实现难点不在单个模块而在相邻模块之间怎么握手、怎么对齐延迟、怎么控制增益和溢出。这里有个工程细节容易被忽略中频侧模块的位宽设计要非常小心。ADC输出通常是14位或16位但经过混频、滤波、抽取后中间节点的位宽如果只按理论信噪比去设计往往在强信号下直接溢出。我一般建议每经过一个固定增益级至少增加2比特余量直到数据率降下来之后再通过移位或截位恢复满幅度。1.2 方案选型的三个关键判断FPGA上实现基带中频算法方案选型决定了后面八成的工作量。我总结了三个最关键的判断点基本每个项目都绕不开。第一是采样结构的选择。是实采样还是正交采样直接决定中频链路的复杂度。实采样只需要一路ADC但带通采样之后频谱会有镜像必须靠希尔伯特滤波器或者混频器来恢复复信号后续处理比较绕。正交采样需要两路ADC和一整套I/Q通道校准硬件成本高但频谱干净基带算法实现起来直观很多。现在主流的高速ADC和射频收发芯片多半内置了正交采样开关FPGA侧重点反而是IQ校准和镜像抑制这个选型一定要提前看硬件不能光从算法角度拍脑袋。第二是数据流组织的选择。FPGA里没有“按需取数”这种事所有数据都是流式处理。同一个FIR滤波器是做成串行MAC结构共用DSP48还是做成多相并行结构用BRAM存数据直接决定了吞吐率和资源占用。举个例子一个128阶FIR采样率250Msps如果用串行结构单周期做一个乘法累加那几乎不可能跑到250MHz反过来把它拆成8路多相子滤波器每路子滤波器工作在31.25MHz资源开销增加但时序压力小得多。选哪个取决于你手里是什么型号的FPGA以及板卡留给FPGA的时钟资源。第三是资源和功耗的平衡。基带侧算法里信道编解码和均衡往往是资源大户而中频侧的滤波和混频则是DSP48消耗大户。我见过不少项目在中频滤波上下了血本结果基带的LDPC译码器没有BRAM放软信息最后不得不返工。正确做法是先估算整个算法链路的DSP48、BRAM、FF资源需求留出20%余量再决定滤波器阶数和并行度。这点在Xilinx的Vivado和Intel的Quartus里都有资源评估工具千万别偷懒。2. 中频侧核心算法DDC/DUC、中频检波与AGC2.1 DDC为什么绕不开CIC加补偿FIR这套组合DDC就是把中频实信号搬到零中频再抽取降速。很多新手上来就写一个混频器再加一个大阶FIR抽取结果算一下乘法器开销直接傻眼。实际工程里最常用的组合是CIC滤波器和补偿FIR配合原因很简单抽取滤波器需要的阶数太高单独用FIR做不现实。CIC级联积分梳状滤波器的最大优势是没有乘法器只有加法器和延迟很适合放在抽取链路的最前面。它的频率响应是经典的Sinc形状通带不够平坦旁瓣衰减也一般所以不能单独用。标准做法是CIC负责降速把它后面的普通FIR设计成补偿滤波器把CIC的通带滚降补回来。我做一个具体项目时的参数供参考ADC采样率245.76Msps中频信号70MHz目标是输出30.72Msps的基带I/Q数据总抽取倍数为8。我选用4级CIC抽取4倍加上后面的半带滤波器抽取2倍。CIC的微分延迟取1归一化增益需要仔细计算。4级CIC的增益是4的4次方也就是256输出位宽比输入要增加8位。如果ADC输出是14位CIC输出至少22位。很多人在这块截位太激进信号动态范围直接损失星座图糊成一团。补偿FIR设计成63阶通带边缘按照信号带宽的1.2倍设置用来补偿CIC的Sinc跌落。这里有个小技巧Vivado的FIR Compiler里可以直接导入CIC补偿系数MATLAB里用fdesign.ciccomp函数生成一组系数再量化为16位定点导入IP核。补偿FIR放在抽取后工作时钟只有61.44Msps单路串行MAC就够DSP48消耗并不多。整套DDC用下来资源消耗不超过一块中等FPGA的百分之十五。2.2 中频检波的几种方法及FPGA实现差异中频检波这个概念在雷达和通信里经常出现本质是从中频信号里提取幅度、相位或者频率信息。最常见的几种方法包括包络检波、乘积检波同步检波、以及基于数字锁相环的相干检波。三者适用场景完全不同放在FPGA上的实现代价也差很多。包络检波最简单就是取绝对值再加低通滤波适合AM解调和简单的幅度检测。FPGA里甚至不需要DSP48用加法器和移位就能做一个递归平均低通。缺点是它丢掉了相位信息如果后续需要做相干处理就没法用。同步检波是工程里最实用的方案。它的核心是本地产生一个与输入中频载波同频同相的参考信号然后用乘法器把中频信号搬回基带再通过低通滤波得到I/Q分量。FPGA实现时需要一个NCO数控振荡器做本地载波NCO的频率控制字由中频频率和系统时钟决定相位则通过锁相环或者Costas环来锁定。热词里提到“中频检波有几种方法如同步检波”在这个语境下点一下同步检波的优点是能够同时获得I/Q幅度灵敏度高缺点是必须在频偏范围内维持相位锁定否则解调误差直线上升。还有一种数字相干检波本质是带锁频功能的同步检波。它在同步检波的基础上把频差检测也加进来通过频率控制字自动跟踪输入信号的载波漂移。FPGA里实现通常用一个二阶环路频率字和相位字各自用一个积分器控制。这套结构在卫星通信和雷达多普勒测量里非常常见参数调起来比Costas环复杂一些但只要环路带宽设计合理长期稳定性很好。2.3 AGC的实现要防“阶梯感”AGC的作用是把波动很大的中频信号幅度拉到ADC满量程附近让后面的基带算法有足够比特数去表现信号细节。FPGA里的数字AGC一般不直接控制硬件增益而是通过时变增益乘子对数据流做幅度缩放。听起来简单实际做的时候有个很头疼的问题如果增益调整步长太大输出波形会出现明显的“阶梯感”星座图上一圈一圈的散点。我的做法是分级处理。第一级用较慢的时间常数做平均幅度检测平滑系数取0.001左右负责跟踪长时间衰落第二级用较快的包络检测做瞬时保护防止强干扰把后续滤波器推饱和。两级综合出一个增益控制字用查表法映射成浮点增益的定点近似。这里必须提醒一点AGC增益更新频率不能太高否则会引入额外的频谱扩展。通常增益字每符号周期更新一次就够了不要在每采样点都跳。实测下来这个方案在20MHz带宽信号下能把输入动态范围60dB的信号压到±0.5dB的输出波动范围后面的同步和均衡工作压力能小很多。3. 基带侧核心算法同步、均衡、信道估计与编解码3.1 符号同步Gardner定时恢复的FPGA实现要点符号同步是基带处理里出Bug最多的地方。接收端采样时钟和发送端存在频偏相偏必须靠插值滤波器在任意时刻重新采样才能在每个符号的最佳点取数。工程中最常见的架构是Gardner定时恢复环它由定时误差检测器、环路滤波器和内插滤波器三部分组成好处是每个符号只需要两个采样点中间点和边缘点实现代价低。FPGA里做Gardner环的核心模块是内插器。最常用的是Farrow结构的立方插值器它用四阶多项式拟合采样点之间的任意时刻值。Farrow结构的优点是不需要存放大量插值系数而是用固定系数加当前位置μ值来计算非常适合流水线实现。我做过一个8路并行的Gardner环每路子通道独立计算误差再用平均误差去调整全局的插值位置。这样做的原因很简单并行路数多了之后单路误差抖动很大平均之后环路才稳定。环路滤波器的系数决定了同步的速度和抖动。我通常用二阶环路比例系数决定跟踪带宽积分系数决定对频偏的补偿能力。一个经验值是把环路等效噪声带宽设到符号速率的0.1%左右既能跟上晶振的ppm级频偏又不会被噪声带偏。实测下来一个16QAM的调制信号在SNR约25dB时Gardner环的定时抖动可以做到符号周期的1%以内。3.2 载波同步QPSK/QAM解调绕不开Costas环基带信号如果存在残余频偏和相偏星座图会旋转任何判决都没有意义。所以载波同步是解调器里必须有的模块。低速场景可以用帧头做数据辅助估计但连续流解调几乎都用判决反馈环比如QPSK的Costas环以及QAM用的通用DDDecision-Directed环。QPSK的Costas环实现比较巧妙它用解调后的I/Q符号极性乘出来一个误差信号误差信号经过环路滤波器控制NCO最终让本地载波相位锁定到输入信号。FPGA里实现时乘法器和环路滤波器都不难难的是锁相环的启动流程。冷启动时频偏可能达到数kHz这时候需要先用频率扫描或FFT粗估频偏把误差压到环路捕获范围内再切到Costas细跟踪。我吃过亏的地方就在这里直接上Costas环捕获大频偏环路要么失锁要么锁定在错误相位上。QAM高阶调制不能用简单的极性判决做误差标准做法是用最近星座点做硬判决然后计算判决误差。这个误差可以同时驱动载波环和均衡器组成联合盲均衡结构。FPGA里的DSP48实现一个复数乘法需要4个实数乘法设计时一定要预先估算好乘法器资源。128阶均衡器加符号率30Msps的QAM信号很容易吃掉几百个DSP48选型阶段就要留够余量。3.3 均衡与信道估计LMS、RLS和卡尔曼滤波的FPGA选型无线信道难免有多径多径带来时延扩展符号间干扰就会冒出来。均衡器的作用就是用一个自适应滤波器去逼近信道逆响应把符号间干扰压下去。最常用的自适应算法有LMS和RLS。LMS实现简单每个系数更新只需要一次乘加FPGA里一个DSP48可以做多个系数的时分复用更新但收敛慢信噪比低时表现一般。RLS收敛快但涉及协方差矩阵更新和矩阵求逆FPGA实现复杂得多通常只在OFDM系统的频域均衡里用。另一个热词“卡尔曼滤波FPGA”也值得说几句。卡尔曼滤波在FPGA上的常见应用是信道估计和联合跟踪但它本身需要矩阵运算和状态协方差更新传统上更偏DSP处理。现在很多新架构把卡尔曼滤波用在时变信道的预测上与LMS构成两级联合均衡卡尔曼预测信道变化趋势LMS负责细调。这种组合在高速移动场景下效果不错但代价是资源和时序压力都上去了。我的建议是如果信道变化速率不高直接用LMS加少量训练序列就够了没必要为了“技术先进”硬上卡尔曼。均衡器拆分时还要注意符号速率与采样率的关系。常用的均衡器结构是符号间隔均衡器T-spaced和分数间隔均衡器T/2-spaced后者对采样相位不敏感性能更好代价是滤波器长度翻倍。FPGA里处理T/2间隔均衡常见做法是把奇数时刻和偶数时刻拆成两条子滤波器再组合输出。这个拆分技巧在很多基带解调器里都能复用。3.4 信道编解码是真正的资源大户基带侧最吃资源的往往不是同步和均衡而是信道编解码。尤其LDPC译码器需要大量BRAM存放软信息迭代次数和块长决定时延。对于通信基带SoC来说LDPC一般是单独核甚至放在专用硬件加速器里。FPGA上做LDPC也有成熟IP但项目中的传输块大小和码率经常变化IP配置灵活性会是一大痛点。相比之下卷积码加Viterbi译码在FPGA里实现传统且稳定。约束长度7的卷积码(2,1,7)结构Viterbi译码器需要64个状态每个状态做加比选运算整体并行展开后大概占用不到500个FF和几百个LUT在FPGA里非常轻量。RS码则常用于突发错误纠正场景比如存储和深空通信FPGA里可以做成有限域乘法器阵列但逻辑规模取决于生成多项式的复杂度。信道编解码这块最大的坑是帧同步和软信息位宽。很多项目在仿真时用浮点模型跑得挺好一上硬件就变差问题多半出在软信息量化位宽。我一般把软信息至少量化为6比特低于这个数值LDPC性能损失就会超过0.5dB。Viterbi译码的软判决输入建议用8比特配合适当的归一化因子性能损失可以控制在零点几dB以内。4. 实操过程完整链路搭建与关键模块代码实现4.1 一个可落地的基带加中频FPGA处理链路拿一个具体的通信接收机链路来举例可以让大家更直观看到各模块是怎么串起来的射频前端输出中频信号进入ADCADC的采样数据和随路时钟通过LVDS送到FPGA。FPGA内部先做LVDS转并行数据再由DDC做数字下变频把中频实信号变成零中频I/Q复信号经过CIC和半带抽取降到基带。基带信号接下来进入符号同步模块用Farrow内插器恢复最佳采样点经过匹配滤波和均衡器后完成载波同步和相位补偿得到干净的星座点。最后通过符号判决、解交织、信道译码恢复出比特流再通过PCIe DMA或以太网口输出到上位机。发射路径反过来走基带比特经过信道编码、符号映射再经过成型滤波根升余弦得到基带I/Q波形通过半带插值和CIC滤波把数据率拉高最后经过DUC数字上变频到中频送给DAC输出。这套收发链路中最容易出问题的地方是接收路径的DDC输出位宽和符号同步之间的接口。CIC/HB/FIR多级滤波都做了抽取每级如果都规范化低位数据很容易被丢掉。我提供了一个经验法则在FPGA内部保留定点小数位直到最后一步符号判决前再截位中间尽量保持高精度。这个做法虽然增加一点BRAM消耗但能避免动态范围损失。如果板卡里MCU是STM32H743这类器件FPGA和MCU之间的FMC通信也是常见的接缝工程。FMC本质上是一个并行内存接口FPGA可以把基带解调后的数据块映射到某个地址区间MCU直接以总线读取。配置时要注意FMC的读写时序参数比如ADDST和数据建立保持时间必须和FPGA内部状态机匹配。我通常在FPGA里把FMC接口设计成伪双口RAMMCU通过FMC地址总线访问FPGA逻辑通过AXI接口写入两边用乒乓缓冲避免读写冲突。4.2 NCO、混频器和Farrow内插器的关键代码结构中频链路的核心基础模块是NCO。NCO相位累加器本质上就是一个不断累加频率控制字的寄存器// 相位累加器 always (posedge clk) begin if (rst) begin phase_acc 0; end else begin phase_acc phase_acc phase_inc; end end // 通过查表输出正余弦 assign sin_out sin_rom[phase_acc[PHASE_WIDTH-1 : PHASE_WIDTH-ADDR_WIDTH]]; assign cos_out cos_rom[phase_acc[PHASE_WIDTH-1 : PHASE_WIDTH-ADDR_WIDTH]];相位累加器位宽决定了频率分辨率。系统时钟245.76MHzNCO位宽32位频率分辨率可以做到0.057Hz完全满足大多数载波跟踪需求。为了改善SFDR可以在低位加抖动dithering把量化杂散摊平到整个频带。工程中建议加上这个抖动代价只是几个寄存器和一张小的LUT表。混频器就是两个实数乘法器组合成复乘// I/Q混频 assign i_mix i_in * cos_out - q_in * sin_out; assign q_mix i_in * sin_out q_in * cos_out;这里的重点是DSP48的流水线寄存器一定要打深一些。我习惯在乘法器输出加两级寄存器再做加减这样时序会好很多。Vivado综合时把宏定义成DSP48映射资源利用率会明显改善。Farrow内插器的核心是一个四阶多项式用μ值做当前插值位置。简化代码如下// 一阶加权版本 assign y (1 - mu) * d1 mu * d2; // 立方Farrow需要四个相邻采样点通过子滤波器组实现 // c0 -0.5*x1 1.5*x2 - 1.5*x3 0.5*x4 // c1 x1 - 2.5*x2 2*x3 - 0.5*x4 // c2 -0.5*x1 0.5*x3 // c3 x2 // y ((c0*mu c1)*mu c2)*mu c3这段代码是立方Farrow的简化实现实际工程中还需要对μ值做溢出保护因为环路滤波器输出的μ可能略微超出0到1范围。我通常对μ做饱和处理超过1就回绕为0并给定时误差检测器一个“调整完成”的脉冲。4.3 仿真验证与上板调试的衔接FPGA开发中仿真和上板往往是两套思路。仿真时用MATLAB或Python生成带有频偏、相偏、噪声和衰落的测试向量导入Verilog testbench作为激励源上板后则通过ILA集成逻辑分析仪或SignalTap抓取中间节点数据在电脑上对波形和星座图。我建议在RTL设计阶段就预留几个调试探针端口。比如DDC的I/Q输出、Gardner误差信号、AGC增益字、均衡器抽头系数这些信号不用都接到外部引脚但要在模块顶层引出。上板调试时不要光盯着星座图看先把环路的误差信号波形抓下来。环路参数是否振荡、锁定时间是否过长误差信号的波形里都写得明明白白比瞎调系数高效得多。仿真模型和RTL实现之间最容易出现偏差的是CIC滤波器的增益控制。MATLAB里的浮点模型不会溢出但定点RTL在强信号时可能饱和。所以仿真测试向量里一定要加入满量程信号验证CIC的中间位宽和截位是否合理。这一步没做好上板之后信号稍强一点星座图会在某个固定位置撕裂排查起来相当费劲。5. 常见问题排查技巧与工程经验总结5.1 典型问题速查表我把这些年项目里碰到的高频问题整理成一个速查表按这个顺序排查基本能解决八成基带中频FPGA的疑难杂症。异常现象可能原因排查手段解决思路星座图整体旋转载波频偏未消除ILA抓Costas误差信号看是否收敛增设粗频偏估计扩大捕获范围星座图发散但有规则圆环定时相位抖动过大检查Gardner误差输出调整环路滤波器带宽减少积分系数信号带宽内出现明显杂散NCO SFDR不足抓混频前/FFT观察增加NCO抖动提高输出位宽CIC输出强信号时星座图撕裂中间节点溢出定点仿真加入满量程信号增加CIC输出位宽提前留出增益余量均衡器不收敛训练序列与数据错位检查训练序列同步状态机先验证训练序列检测再开自适应更新FMC读回数据全是FF/00读写时序不匹配示波器抓FMC总线时序调整FMC读周期等待状态数LDPC译码性能急剧下降软信息位宽不足或归一化错误对比定点与浮点仿真软信息统计提升软信息位宽并校准LUT归一化系数板卡功耗异常偏高DSP48翻转率过高查看功耗报告定位高频翻转模块增加流水线级数降低单周期逻辑深度5.2 基带中频FPGA调试的几条硬经验调试这套系统最忌讳一上来就开所有模块的仿真然后把波形窗口铺满整个屏幕。经验做法是先让各模块“孤立可测”。每个算法模块独立成IP外部能输入测试向量内部有探针输出这样做的好处是出问题时能立刻定位到具体模块而不是在两个模块的接口处扯皮。第二个经验是环路参数一定要在仿真里先用定点模型扫一遍边界。比如Gardner环的比例系数从1/16扫到1/128积分系数从1/1024扫到1/4096找出锁定时间和抖动都能接受的区间。上板后再根据实际信道特征在这个区间里微调不要指望一次半调就能最优。第三个经验跟时序收敛有关系。中频侧的高采样率时钟域和基带侧的低速时钟域之间必须用异步FIFO做隔离绝不能用同一时钟硬跑到底。很多工程师为了让设计简单把所有模块都挂在同一个时钟树上结果基带侧的组合逻辑把中频侧的时序拖到崩溃。正确做法是“中频时钟域只管采样点级处理基带时钟域只管符号级处理”时钟域交叉处用异步FIFO加AXI-Stream握手。5.3 工具链与学习路线的建议Xilinx平台建议用Vivado加ModelSim/Questa做联合仿真Vivado自带的ILA调试工具配合VIO可以实时修改环路参数非常实用。Intel平台则推荐Quartus加SignalTap两者调试思路一致差异在IP核配置界面。仿真阶段强烈建议在MATLAB里完成浮点模型和定点模型的完整对照RTL代码先不急着写先把算法级验证彻底后面改RTL的时间会大幅缩短。关于学习路线我建议新入行的朋友先从中频链路入手把NCO、CIC、半带滤波器、FIR补偿这套“搬移和降速”的功夫练扎实再进入基带的同步和均衡。因为有太多项目的失败原因是中频链路设计不合理导致基带模块一直面对质量很差的输入信号。中频链路质量上去了基带算法的调试难度会降低一个量级。等这两块都熟练了可以再看LDPC、RS这类纠错码的硬件实现那时你已经具备完整的系统观念再复杂的编解码模块也不会觉得无从下手。最后再补充一个小技巧。如果你的项目里同时涉及多个不同采样率的数据流我建议在RTL代码里用宏定义把所有采样率、抽取倍数、滤波器阶数都参数化。不要直接写死数字。每次改参数只需要改一处仿真和综合都能快速验证。这件事看似不起眼但在项目后期调整信号带宽时能帮你省下大量来回查找的时间。基带和中频的FPGA实现说到底是一个系统工程参数管理、时钟规划和调试手段决定了你能否从“调通一个模块”走向“调通一张网”。
返回列表