FEATURED · 精选文章

FPGA基带与中频信号处理实战:从DDC到定点量化的完整链路解析

发布时间 / 2026/9/7 1:11:09
来源 / 创域科博编辑部
栏目 / 资讯中心
FPGA基带与中频信号处理实战:从DDC到定点量化的完整链路解析 上个月帮别人调一块双通道中频采集板算法在仿真软件里跑得干干净净一上板输出就乱跳排查了三天最后发现问题出在DDC后级抽取滤波器的截位策略上——为了省一个DSP48把本该保留的2bit保护位直接砍掉了。这种事情在FPGA通信信号处理里太常见了不是算法原理错而是对FPGA上的位宽、时序、接口细节理解不够。这篇文章就围绕基带与中频的FPGA算法实现展开把从信号链定位、核心算法到定点量化、接口调试的完整链路讲透适合正在做FPGA通信/信号处理项目或者在学FPGA但不知道基带中频到底该做什么的读者参考。1. 基带与中频的边界感先搞清楚FPGA在信号链里的位置1.1 基带、中频、射频各自负责什么一个典型的超外差收发链路里射频、中频、基带三者各管一段。射频是天线口的信号频率最高比如2.4GHz或者5.8GHz中频是射频通过混频器搬移下来的中间频率常见的有70MHz、140MHz、450MHz这些值基带则是最终承载调制信息的低速信号频率最低带宽也最窄。FPGA在中间的定位很有意思。它既能处理中频采样后的高速数据流也能做基带的调制解调和同步。前端ADC把中频模拟信号变成数字信号后FPGA通过数字下变频DDC把信号从中频搬到基带反过来发射方向则是通过数字上变频DUC把基带信号搬移到中频再交给DAC。这种数字化中频软件化基带的架构其实就是软件无线电的核心思路而FPGA是这套架构里最灵活的载体。1.2 哪些算法适合放FPGA哪些该留给ARM和DSP很多刚接触FPGA的人会问我是不是应该把整个通信协议栈都写进FPGA答案是否定的。我自己的判断标准有三条数据率极高比如ADC工作在250MSPS16bit采样一路数据就是4Gbps这种吞吐CPU根本接不住算法结构天然并行比如FIR滤波、FFT、CIC抽取、相关运算这些本质是乘累加特别适合FPGA的DSP48和流水线对时延要求极其严格比如锁相环、功率控制环、同步环路延迟抖动会直接导致系统发散。反过来低速率、控制逻辑复杂、协议栈厚重的任务比如TCP/IP协议栈、文件系统、复杂的调度策略这些更适合交给ARM或者DSP。Zynq这类异构SoC之所以流行就是因为它把ARM和FPGA放在同一颗芯片里各干各擅长的事。1.3 一个典型收发链路里FPGA承担的任务清单接收方向FPGA接到ADC数据后依次做DDC混频、CIC抽取、FIR补偿滤波、匹配滤波、AGC增益控制、定时同步、载波同步、均衡、解映射。发射方向则反过来信源比特映射成IQ符号、脉冲成形滤波、内插、DUC数字上变频、送DAC。这个任务链里每一步都对应着明确的资源消耗。比如一个32阶FIR滤波器如果数据和系数都是16bit做全并行实现需要32个DSP48如果改用多相分解加时分复用可以把DSP48数量降下来但代价是控制逻辑变复杂。做系统设计时先把这个任务链写清楚再估算资源和时序比直接打开EDA工具写代码要靠谱得多。2. 基带算法上板成形滤波、同步环路和调制解调的工程化思路2.1 脉冲成形与匹配滤波为什么要放在一起设计基带的脉冲成形滤波器通常用根升余弦RRC接收端也要一个匹配的RRC两个级联等效成升余弦滤波器保证抽样点上没有码间串扰。这个问题在原理上很干净但工程实现有几个坑。第一个坑是阶数选择。RRC滤波器的阶数越高频带越干净但延迟也越大DSP48消耗成正比上升。我的做法是先定滚降系数αα越小频谱利用率越高但时域拖尾越长对定时误差越敏感。0.2到0.35是常用区间。第二个坑是滤波器的实现结构。FPGA里FIR最常用的是转置型结构因为流水线天然打散时序更好收敛。如果是多符号并行处理比如一个时钟出4个符号那就需要多相分解把单个滤波器拆成4个子滤波器并行跑每个子滤波器工作在1/4时钟频率下DSP48数量不变但对时钟要求大幅下降。第三个坑是系数定点化。Matlab设计出的浮点系数直接塞进FPGA必然性能劣化。一般先做系数定点化仿真观察EVM或者误码率劣化程度我以前习惯把系数放大到16bit整数定点再做归一化处理这样在FPGA里乘法器直接有符号数相乘不需要额外处理小数点的偏移。2.2 Costas环与Gardner定时同步的FPGA落地载波同步在FPGA里最常见的是Costas环它对BPSK、QPSK这种抑制载波的信号尤其有效。Costas环的组成是误差鉴相器、环路滤波器、NCO。误差计算有几种形式最简单的BPSK用I*QQPSK用sign(I)*Q sign(Q)*I。环路滤波器是典型的比例积分结构两个系数Kp和Ki决定了环路的带宽和捕获速度。这里的工程细节很值得说NCO的相位累加器位宽直接决定频率分辨率。假设系统时钟100MHzNCO累加器32bit那么频率分辨率是100MHz除以2的32次方约0.023Hz这对基带同步完全够用。但如果为了省资源把累加器砍到16bit分辨率变成1.5kHz环路就可能永远锁不到准确频率上。定时同步方面Gardner算法是我用得最多的因为它对载波相位不敏感可以在载波同步之前先做。它的误差公式是(x(n) - x(n-2)) * x(n-1)的符号相关形式抽取点在两个符号中间。FPGA实现时要注意这个误差计算本身是组合逻辑需要做流水线寄存否则可能成为时序瓶颈。2.3 调制映射与解调判决的细节坑调制映射本质是查表QPSK就是根据2bit查I、Q两路的符号和幅度16QAM则是查4bit对应到16个星座点。这个模块逻辑很简单但两个细节值得注意比特序的定义必须和协议一致大端小端搞反了整个系统的星座图会发生镜像或者旋转I/Q两路的极性定义也要统一否则解调出来I路变成Q路符号全乱。解调判决的边界问题常被忽视。ADC进来的信号幅度会随信道变化如果不做AGC归一化固定判决门限就会失效。AGC在FPGA里的实现通常是计算I/Q幅度或者功率和参考值比较通过环路调整前级可变增益。工程上有个经验AGC环路带宽要远低于符号速率通常取符号速率的1/100到1/1000否则会把信号自身的幅度波动也压掉导致星座点畸变。3. 中频检波算法同步检波、正交检波和包络检波怎么选3.1 三种检波方法的原理差异中频检波是把中频信号里的幅度、相位信息提取出来的过程常见方法包括包络检波、同步检波和正交检波三者适用场景差别很大。包络检波只提取幅度信息。FPGA里最简单的做法是对信号取绝对值再做低通滤波也可以用CORDIC直接计算瞬时幅度。它的优点是不需要恢复载波实现资源极少一个ABS加一个FIR就能跑适合AM解调、信号检测这类场景。缺点是拿不到相位信息QPSK、QAM这类相位调制的信号没法解。同步检波也叫相干检波要求本地参考载波与信号载波同频同相相乘后经过低通滤波得到基带信号。这种方案必须配一个载波恢复电路工程上常用PLL或者Costas环。它的好处是输出信噪比高适合低信噪比环境下的弱信号解调。正交检波是最通用的方案本地NCO同时产生cos和-sin两路正交本振分别和输入相乘得到I、Q两路基带信号。它本质上也是相干检波但把信号分解为正交分量后续做幅度、相位、频谱分析都非常方便。软件无线电里的DDC核心就是这个结构。3.2 正交检波的数学推导和FPGA实现结构这里我把正交检波的数学过程展开写一下。设中频信号为s(t) A(t)cos[2πf_IF t φ(t)]本地NCO产生两路正交本振LO_I cos(2πf_IF t) LO_Q -sin(2πf_IF t)中频信号分别与两路本振相乘得到I_raw s(t)cos(2πf_IF t) 0.5A(t)[cosφ(t) cos(4πf_IF t φ(t))] Q_raw -s(t)sin(2πf_IF t) 0.5A(t)[sinφ(t) - sin(4πf_IF t φ(t))]经过低通滤波器把2f_IF的高频分量滤除后得到I 0.5A(t)cosφ(t) Q 0.5A(t)sinφ(t)幅度和相位分别是A(t) 2√(I² Q²) φ(t) atan2(Q, I)FPGA实现时混频器就是两个有符号乘法器低通滤波器是两级级联的抽取滤波。幅度计算里开根号用CORDIC的SQRT模式反正切用CORDIC的atan2模式。Xilinx的CORDIC IP核直接支持这两种功能配置的时候注意输入输出位宽要和前级匹配迭代次数多一档精度好一点但延迟也会变大。3.3 中频采样率选择与带通采样的实际权衡中频信号采样有一个带通采样定理对于中心频率f0、带宽B的带通信号采样率不需要高于2f0只要保证频谱混叠后不重叠就可以。具体计算要满足2f_H / n ≤ fs ≤ 2f_L / (n-1)其中f_L和f_H是信号频带的上下边界n是正整数。举个例子70MHz中频、10MHz带宽的信号理论最低采样率可以做到20MSPS附近但实际工程我很少卡着理论值做。原因有两个一是卡边采样对模拟抗混叠滤波器要求极高滚降不够陡的话边缘频谱会折叠进来二是后续DDC的抽取倍数和滤波器阶数需要综合考虑。工程上更常见的做法是取80MSPS或者140MSPS留足频谱保护带ADC前端的抗混叠滤波器就很好设计。3.4 检波方案选型对照表检波方法是否需要载波恢复输出信息FPGA资源消耗典型应用包络检波不需要幅度低AM解调、信号检测、AGC辅助同步检波需要PLL/Costas基带I/Q中弱信号相干解调正交检波需要NCO本振I/Q及幅相中低DDC、软件无线电、通用架构实际项目里如果是做一个通用的中频采集板我建议直接上正交检波因为硬件结构不变后续通过改NCO频率就能适配不同中频灵活很多。如果只是做一个简单的AM信号检测器包络检波就够了没必要把CORDIC和NCO都用上降低成本也降低调试难度。4. 绕不开的定点量化所有FPGA信号处理成败的关键4.1 为什么FPGA上不主用浮点FPGA完全可以实现浮点运算Xilinx和Intel都有浮点IP核但代价很大一个浮点乘法器占用的DSP和LUT资源数倍于定点乘法器延迟也高很多。在基带和中频处理这种深流水线、高吞吐的场景里浮点的面积和功耗开销很难接受。更关键的是定点并不是牺牲精度。一个16bit定点数的信噪比大约96dB这对绝大多数通信链路已经足够了。真正的问题在于定点数运算位数有限乘法加法之后位宽增长必须设计截位和饱和策略。如果这个策略设计错了EVM劣化、误码率上升、环路失锁就会接踵而至。4.2 Q格式与位宽计算的核心逻辑定点数一般用Q格式表示比如Q1.15表示1位整数位加15位小数位数值范围在-1到1之间。12bit ADC的输出可以看成Q1.1116bit滤波器系数可以看成Q1.15。两个Q格式数相乘整数位数相加小数位数相加结果位宽是两者之和。实际处理链路里位宽增长是逐级累积的。乘一次两个原始位宽相加加一次多1bit。比如12bit数据和16bit系数相乘乘积需要28bit一个128阶FIR做全并行累加累加结果还需要多出约7bit来容纳128个数的和。这就是为什么DSP处理的中间级位宽动辄35bit起步最终再根据输出精度要求统一截位。4.3 CIC滤波器的位宽增长预估算例CIC滤波器在DDC里应用极广因为不需要乘法器只做加减法资源特别省。但CIC有个特性让新手非常容易翻车积分器内部的位宽会持续增长如果不预留足够位宽就会溢出。工程上有一个明确的计算公式B_out ≥ B_in N × log2(R × M)其中B_in是输入位宽N是CIC级数R是抽取因子M是微分延迟通常取1或2。举个例子输入12bit抽取因子R16级数N4M1那么位宽至少需要12 4×log2(16) 12 16 28bit。如果只看输出以为16bit就够了直接在CIC中间截断那信号必然被削顶或者产生严重失真。4.4 截位饱和策略的经验总结我的习惯是每个处理级之间保留2到4bit保护位全部运算完成后再做饱和截位到目标位宽。饱和的意思是如果截位后数值超出范围就钳制到最大值或最小值而不是简单丢弃高位。这个逻辑需要用有符号数仔细设计写不好的话正数溢出会变成负数产生剧烈的非线性失真。另外强烈建议在做RTL之前先用Python或者Matlab把定点量化行为建模出来和浮点模型做对比。我在项目里常用的流程是浮点模型验证算法正确性定点模型验证位宽和截位策略最后才写Verilog/SystemVerilog。定点模型的仿真结果可以作为后续FPGA板级调试的黄金对比参考值这个价值在排错时无可替代。5. 接口与时序FMC、LVDS、PCIE和跨时钟域实战5.1 FMC总线通信STM32与FPGA的数据交换细节FMC这个词有两层含义一个是STM32的Flexible Memory Controller一个是FPGA板卡上连接AD/DA子卡的高速连接器。工程里经常看到两者的组合STM32通过FMC总线挂一个FPGA作为外部存储器实现寄存器读写和数据交换。FPGA端在这种架构下要模拟一个SRAM-like从设备。总线的核心逻辑是STM32发起片选CS、写使能WE、读使能OE和地址AFPGA用状态机解析这些信号把写时序变成内部寄存器写入把读请求变成数据输出。STM32的FMC时序寄存器需要配置地址建立时间、数据建立时间、地址保持时间这几个参数要和FPGA内部状态机的时序对齐。一个常见问题是FPGA采样FMC控制信号引入亚稳态。我的做法是控制信号先通过两级同步器打拍但数据总线不能简单打拍因为数据采样的时间窗口要求更严格。最好用FPGA内部时钟对FMC时序做约束通过IO delay或者其他方式保证在数据有效的窗口中心采样。5.2 LVDS、MIPI、Biss-C这类协议的正确打开方式FPGA经常要处理各种高速串行接口协议LVDS接收、MIPI摄像头、Biss-C绝对值编码器都是典型场景。这些协议的共同逻辑非常相似物理层用FPGA的高速IO和专用硬核比如ISERDES/OSERDES逻辑层通过移位寄存器解析比特流协议层用状态机完成组帧、去帧和CRC校验。我的经验是这类协议调试时一定要把时钟恢复与字节对齐作为一个独立阶段验证不要一上来就调整条链路。比如MIPI CSI-2的接收如果LP/HS状态切换、SoT包起始码对齐没做对后面解析数据没有任何意义。Biss-C编码器更是如此它的时钟和数据方向会切换时序参数和CRC多项式都要逐项核对每项都可能成为链路不通的原因。5.3 跨时钟域处理与基带数据缓存基带和中频链路天然是多时钟域系统ADC采样时钟、DDC处理时钟、PCIE/DDR总线时钟、ARM侧时钟每个时钟域之间都要安全传递数据。跨时钟域的三板斧单bit脉冲用两级触发器同步多bit数据用异步FIFO流控用AXI-Stream的ready/valid握手。涉及基带数据的连续性缓存时乒乓缓存是经典方案。两块缓冲区交替工作一块被写入数据的同时另一块可以被DMA读出。这样数据流不会中断代价是缓冲区需要两倍容量。如果缓存量很大比如多通道长时间IQ数据缓冲BRAM就不够了必须用DDR3/DDR4FPGA只实现DMA读写引擎和地址管理。这种场景下仲裁逻辑和突发传输效率往往比缓存本身更值得优化。5.4 时序收敛的几个实际问题基带中频设计里时序不收敛是家常便饭但多数违例的原因高度集中。最常见的是乘法器后直接跟长累加链组合逻辑路径过长其次是扇出过大一个复位信号接了上千个触发器还有IP核之间握手信号没有正确流水导致数据通路上出现组合逻辑环。解决办法也相对套路把长累加链切成各级流水用retiming来自动平衡寄存器位置复位信号做全局同步按模块分级复位关键握手路径上插入寄存器级通过AXI-Stream协议本身的valid/ready不限制延迟的特性可以灵活插入流水。时序分析工具报违例时先看是跨时钟域路径还是纯组合逻辑路径两者对策完全不同不要拿到报告就盲目插寄存器。6. 进阶玩法卡尔曼滤波、自适应算法和Zynq动态重配置6.1 卡尔曼滤波在FPGA上到底能干什么卡尔曼滤波在FPGA上应用越来越多场景包括目标跟踪、传感器融合、信道估计、参数辨识等。很多人的第一反应是卡尔曼滤波涉及矩阵运算和求逆FPGA实现会不会很难。其实分情况看。对于一维标量的卡尔曼滤波公式非常简洁比如对距离测量值做滤波状态预测、协方差预测、增益计算、状态更新。FPGA实现时真正麻烦的是除法增益K的计算里有一个除法可以用CORDIC除法器或者查表近似。如果状态量只有一两个维度硬件资源占用很小流水线设计也不复杂。多维状态卡尔曼滤波就复杂多了涉及矩阵乘法和矩阵求逆。工程上能用解析公式求逆就尽量用解析公式避免在FPGA里做通用矩阵求逆。3x3以下的矩阵求逆可以直接写出公式展开再用定点运算实现。6.2 LMS自适应滤波的流水线化实现自适应滤波在均衡、噪声对消、回声消除里都用得上。LMS算法的核心是两步滤波器输出权值更新。FLMS的问题在于权值更新依赖当前误差而误差又依赖滤波器输出这个反馈环路天然难以深度流水。工程上常用延迟LMSDelayed LMS来破解允许权值更新延迟几个时钟周期把反馈路径切断让乘累加链路可以流水化。延迟一定周期后算法收敛性能略有下降但换来的是时钟频率大幅提升。FPGA里做实时自适应滤波这个取舍几乎总是值得的。NLMS算法相比LMS增加了能量归一化性能更稳定但多了求倒数除法。FPGA里可以用查找表做倒数近似或者使用CORDIC除法。如果收敛速度要求高而LMS步长难以确定NLMS往往是更省心的选择。6.3 Zynq软硬件协同与动态加载bitstreamZynq是ARM加FPGA的异构平台典型的软件无线电、雷达信号处理、运动控制方案都会用到。ARM侧可以跑Linux系统负责网络通信、人机交互、任务调度FPGA侧做高速信号处理两边通过AXI总线交换数据。更进阶的玩法是动态部分重配置Linux运行期间通过FPGA Manager框架或者直接操作devcfg寄存器把新的bitstream加载到FPGA里实现运行时切换算法。同一块板卡早上跑DDC加解调下午切换成频谱感知或者新的调制方式只需要重新加载bitstream不需要重新启动系统。使用时需要注意动态重配置过程中FPGA内部的状态会全部丢失DDR、DMA、中断这些共享资源必须事先干净地暂停。还有一个容易忽略的点部分重配置的bitstream生成流程和全量配置不一样设计时必须提前划分动态区和静态区不是随便一个工程都能在运行时重配。6.4 这类系统适合的业务场景卡尔曼滤波加自适应算法加动态重配置这套组合最典型的场景是软件无线电和智能仪器信号带宽、调制方式、工作频点经常切换并且需要高实时性处理。另外一个典型场景是精密运动控制和机器人FPGA处理编码器反馈和电流环卡尔曼滤波做传感器融合ARM做轨迹规划和交互。这些场景的共同点是算法维度不固定、实时性要求高、资源受限FPGA几乎是唯一能同时满足的载体。7. FPGA选型与调试从仿真通过到上板跑稳的经验7.1 选型先算资源再对型号做基带中频项目选FPGA型号我的建议是不要从哪个型号比较高级开始而是先把自己的资源需求算清楚。下面这个清单基本够用乘加运算量滤波器阶数乘通道数对应DSP48/乘法器单元数量存储需求FIFO深度、系数表、数据缓存对应BRAM/URAM容量高速接口PCIE、SRIO、千兆网需要的高速收发器数量普通IOLVDS通道数量、ADC/DAC接口位宽、Bank电压分组时钟资源MMCM/PLL数量是否够多时钟域使用。把这五个方面算出来再去主流厂商官网按资源筛选型号效率高很多。入门级项目用Artix-7或者国产同等规模芯片就够了Kintex级别主要用于多通道高速收发器或者大容量DDR缓存场景Zynq则适合需要ARM跑Linux做上层任务的项目。7.2 IP核、自研RTL和仿真验证的关系基带中频链路里的通用模块比如FIR、CORDIC、FFT、DDC/DUC我建议尽量使用IP核而不是自己写RTL。IP核经过充分验证接口规范时序也优化过自己写RTL反而容易踩坑。关键是要先跑IP核的官方示例工程把接口时序摸清楚再接入自己的设计。自己写RTL的部分推荐统一采用AXI-Stream接口风格。这套协议就两个核心信号valid表示数据有效ready表示接收端准备好数据在两者同时为高时传输。模块之间用AXI-Stream连接以后要插入DMA、FIFO、跨时钟域模块都非常方便不需要频繁改接口逻辑。调试基带中频链路时ILA逻辑分析仪抓取的信号点选择很有讲究。我通常优先在DDC输出、同步环路误差信号、定时同步的抽样点、FIFO计数这几个位置放探针。这些点能把链路的健康状态直接反映出来比漫无目的地刷所有中间信号高效得多。7.3 上板调试的关键检查项最后分享一份检查清单是我反复踩坑之后整理出来的每次项目上板之前走一遍能省下大量排查时间逐级确认数据位宽和饱和策略特别关注CIC这类位宽增长极大的模块确认所有IP核的时钟、复位是否同源且连接正确检查AD采样时钟到处理时钟的跨时钟域FIFO是否有溢出或空读NCO混频频率的计算要重新核对是否考虑了采样率和相位累加器位宽板级抓取关键节点数据与定点模型的输出做逐点对比同步环路的初值、环路带宽、锁定指示信号是否正常上电后等待锁相环锁定、复位释放顺序正确后再开数据流大资源设计注意功耗和散热高速收发器区域温度往往比预想高。我自己的体会是大多数仿真通过但上板失败的问题都能在上述清单里找到对应项。尤其是截位策略和跨时钟域这两类看起来很基础但它们才是基带中频FPGA项目里最难排查、也最影响成败的环节。把基础环节做扎实算法本身反而很少成为瓶颈。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻