ARTICLE DETAIL

资讯详情

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

System Generator多速率信号处理:从原理到DDC链路实现

System Generator多速率信号处理:从原理到DDC链路实现 做FPGA信号处理的工程师迟早会碰到一类需求系统里不同模块跑在不同的采样率上。比如ADC进来是245.76M的采样流DDC之后数据率降到几十M再接均衡、AGC、解调每一级的速率都不一样。这种**多速率系统Multi-Rate Systems**用传统RTL硬写不是不行但改参数、调结构、做仿真验证来回折腾的功夫足够让人怀疑人生。Xilinx System GeneratorSysGen把DSP设计搬进了Simulink的图形化环境抽取、插值、多相滤波这些多速率处理都能拖拽成模型仿真波形直接看最后还能打包成IP核扔进Vivado做时序收敛和板级验证。这篇文章我就从原理到实操把System Generator里做多速率系统这套流程完整拆一遍。1. 多速率信号处理到底在解决什么问题1.1 为什么系统会存在多速率通信和雷达系统里不同处理环节对采样率的需求差别很大。ADC的采样率往往由中频频率和信号带宽决定比如LTE基站里常见的122.88M采样率是为了覆盖20M带宽的载波信号。但基带端的符号速率通常只有几十M甚至几M如果整条链路都跑在122.88M上后面的均衡器、定时同步、译码器全是白算的没用的样本点也在消耗DSP资源、寄存器和动态功耗。所以处理思路就一句话能用低速率处理的部分就不要让数据在高速率里空转。在ADC之后立刻做数字下变频把数据率一步一步降下来直到基带处理能够承受的程度。反过来发射链路需要把基带的低速率信号逐步内插到DAC的采样率这就是数字上变频。这一降一升的过程就是多速率信号处理的核心场景。SysGen做这类系统有天然优势。它本身就是Simulink的一个工具箱Simulink模型天生有采样时间的概念每个信号都可以带不同的采样率。SysGen在此基础上把Xilinx的DSP硬核——DSP48、Block RAM、CIC硬核——封装成了一个一个的模块你在模型里拖出来的滤波器生成RTL以后对应的就是FPGA里真实的逻辑资源不是黑箱仿真。1.2 多速率建模的核心难点很多人第一次用SysGen做多速率就卡在同一个地方Simulink模型跑起来了波形也出来了但结果跟理论对不上或者干脆仿真挂起。问题多半出在你没搞明白SysGen的速率机制和Simulink的速率机制是两套东西。Simulink本身是多速率求解器它允许不同的子系统跑不同的采样时间系统会自动调度。但SysGen生成的硬件逻辑是单一时钟域的除非你显式用多时钟模块FPGA里所有逻辑跑在同一个时钟上多速率是靠每N个周期有效一次的方式实现的对应的就是SysGen里的Sample Rate、采样周期倍数这些参数。换句话说你在SysGen里看到的多速率本质上是单一时钟下的门控时钟使能clock enable机制。这个理解很关键因为你在Simulink里可以随便连不同速率的信号但到了硬件里每一条链路都得有明确的速率转换关系。SysGen在生成RTL之前会做一次全模型的速率检查发现速率不匹配会直接报错。另外SysGen的仿真时间是基于FPGA时钟周期的模型里设一个20ns的时钟周期Simulink的仿真步长就跟这个绑定。你在SysGen token里设的FPGA采样时间和Simulink里各个模块的采样时间必须构成一个严格的倍数关系否则仿真结果就是错的。2. 动手前先搞懂速率转换的数学本质2.1 抽取、插值与频谱的关系多速率系统绕不开两个基本操作抽取decimation也叫下采样和插值interpolation也叫上采样。抽取就是在连续M个样本里取一个数据率降为原来的M分之一。这件事在时域看是丢点在频域看是频谱被展宽了M倍。原来在-midfs到fs/2范围内的频谱抽取后被压缩到新的奈奎斯特区间时会把带外的信号折叠到带内——这就是混叠aliasing。所以抽取之前必须先经过一个低通滤波器把带外信号滤干净这个滤波器叫抗混叠滤波器。插值则相反在两个真实样本之间插入M-1个零数据率变成原来的M倍。时域上插零并不改变原始信号形状但频域上会产生一串镜像频谱以新的采样率为周期重复。这些镜像必须用低通滤波器滤掉叫镜像抑制滤波器。2.2 多相分解是效率的关键抽取和插值其实都能用滤波器实现但如果你直接在FPGA里把滤波器放在抽取/插值之前那滤波器仍然跑在高速率上等于多速率省白省。真正的效率提升来自多相分解polyphase decomposition。多相分解的基本思路是把一个低通滤波器的系数按相位分成M组每组系数构成一个子滤波器。抽取的时候你只需要在M个相位分支上各放一个子滤波器每个子滤波器都跑在低速率上运算量直接降到原来的M分之一。CIC、半带、FIR抽取/插值器硬件实现上都离不开多相分解。SysGen里这些你不用自己写模块都封装好了。但你要懂背后的逻辑才能理解为什么FIR编译器里Decimation Rate4的时候内部实际计算量比单速率模式小得多也才能理解为什么CIC Compiler级数设置不同输出位宽会差那么多。2.3 SysGen多速率模块对照SysGen提供的多速率模块我整理了一个对照表方便按场景选型模块速率转换类型适用场景资源消耗Down Sample直接抽取快速验证、整数倍抽取极低Up Sample直接插零快速验证、整数倍插值极低FIR Compiler单速率/抽取/插值可配中低倍数抽取插值、通道滤波使用DSP48系数可配CIC Compiler高倍数抽取/插值DDC/DUC前端、带宽较宽的信号无乘法器加法器为主CIC补偿滤波器与CIC搭配CIC通带下垂补偿DSP48FIR Decimation抽取滤波器低延迟、简单用途中等FIR Interpolation插值滤波器低延迟、简单用途中等Polyphase Filter Bank信道化多通道DFT滤波器组高选型建议就一条经验CIC适合高倍数转换因为不需要乘法器但通带会有下垂后面必须补补偿滤波器FIR Compiler适合中低倍数的精细滤波频率响应好控制。实际DDC链路里高倍数抽取用CIC低倍数精调再用FIR这是最常见的组合。3. 完整实操DDC多速率链路设计3.1 设计指标与链路规划我拿一个典型的中频数字化接收机DDC链路来演示。假设ADC采样率是122.88M中频频率30.72M信号带宽10M基带处理需要的符号速率是15.36M。设计目标把122.88M的ADC数据经过混频、抽取、滤波最终输出15.36M的IQ基带信号。链路规划如下第一级NCO混频DDS Compiler把30.72M中频搬移到基带第二级CIC抽取滤波器4倍抽取把122.88M降到30.72M第三级CIC补偿FIR 半带FIR2倍抽取把30.72M降到15.36M第四级Convert位宽转换输出定点IQ数据。总抽取倍数是4×28输出速率122.88/815.36M满足基带处理需求。3.2 参数计算的完整推导CIC抽取器参数CIC的增益峰值可以用公式估算级数N、微分延迟M、抽取倍数R的情况下最大增益是(R×M)^N。本设计R4M1N4最大增益4^4256换算成功率增益约48dB。CIC输出位宽B_out B_in ceil(N×log2(R×M))如果输入16位输出就是16 ceil(4×2)24位。SysGen的CIC Compiler模块会自动算好位宽但你要明白这个数是怎么来的才能判断自动计算结果是否合理。这里有一个我在实际项目里踩过的坑CIC的高增益不止体现在通带处理宽带信号时带外噪声会被一起放大。CIC后端如果不加AGC或者增益控制很容易把后级FIR打满。所以CIC的输出不要直接进FIR建议先给一个Scale或者用Convert截位保证进入FIR的数据在合理动态范围内。半带FIR参数半带滤波器有个特性通带和阻带关于fs/4对称所以只能做2倍抽取/插值。它的运算量比普通FIR省一半因为一半系数是0。本设计用半带完成最后一级2倍抽取系数阶数我选了32阶过渡带从4M到5.5M。SysGen里可以直接调用fdatool生成系数然后再通过FDATool模块导入也可以在MATLAB里用firhalfband函数直接生成然后填到FIR Compiler的系数向量里。NCO参数DDS Compiler里设置Phase Width32位输出位宽16位频率字计算方式是2^32×30.72/122.88 2^31正好是半个量程对应fs/4的频率。这里从数学上看是干净的信号但实际中频如果不在fs/4相位累加器会引入杂散需要根据SFDR要求选择抖动dithering配置。3.3 Simulink模型搭建逐步拆解打开Simulink新建模型先拖一个System Generatortoken进来双击配置目标器件选你板卡上的型号比如Kintex-7 325TFPGA时钟周期设成8.138ns122.88M的倒数硬件描述语言选Verilog采样周期保持默认。注意这个FPGA时钟周期后面所有模块的采样时间都跟它挂钩。模型整体分三段。第一段用DDS Compiler产生正交本振信号输出接两个乘法器把输入的实中频信号和cos/sin相乘得到正交混频后的I、Q两路。混频输出Q路会有2倍频分量按道理要先滤一下但因为我们紧接着就接CIC抽取CIC的前置抗混叠滤波器会一并处理高频分量链路可以简化。第二段接CIC Compiler双击进去设置滤波类型选Interpolation还是Decimation这里选Decimation抽取因子填4差分延迟填1级数填4CIC的级数决定阻带衰减级数越高阻带衰减越大但通带下垂也越严重。输入端类型选有符号定点输入位宽16位。输出端会自动算出25位16ceil(log2(4^4))16824? 我前面推的是24SysGen实际计算可能多1位的无符号进位以实际模型显示为准。第三段接FIR Compiler。双击进入之后在Filter Type里选Half-band Decimation抽取因子设2系数来自firhalfband(32,0.28)生成的向量。采样时间方面的配置要特别注意CIC输出端的采样时间是122.88M/430.72M在SysGen里表现为采样周期倍数是4FIR输入端采样时间必须与CIC输出端一致而在FIR内部配置的抽取因子会让输出端自动变成采样周期倍数8对应15.36M。最后接Convert模块把FIR输出位宽截位到16位。后续如果要对接外部接口可以再接一个Gateway Out它会生成一个FPGA引脚对应的输出信号。整个模型里各个模块的采样时间倍数分别是混频前1122.88MCIC后430.72MFIR后815.36M。你可以双击任意信号线在Simulink的格式设置里查看采样时间确认链路速率关系正确。3.4 仿真验证与频谱分析仿真前先检查一下求解器设置这点我每次都要提醒Simulink配置参数里求解器必须选Fixed-step、discrete步长跟System Generator token里的FPGA时钟周期一致。如果选了可变步长求解器SysGen会警告而且仿真结果大概率不对。激励源的生成有个小技巧。用SysGen自带的Signal Generator不行因为它输出的不是定点数。正确做法是用MATLAB工作区生成一个包含中频信号的激励数组比如fs 122.88e6; t (0:4096-1)./fs; % 构造中频30.72M信号用double表示幅度控制在±0.5 sig 0.5 * cos(2*pi*30.72e6*t pi/4);然后用From Workspace模块导入接一个Gateway In转换成定点。这样可以直接复用MATLAB里做好的仿真数据后面做硬件在环HIL或者上板实测的时候激励也可以保持一致。跑完仿真以后在FIR输出端接一个Scope同时把数据导回MATLAB做FFT分析。验证点有三个输出信号频率应该是0附近基带峰值幅度在输入信号幅度折算后基本合理30.72M中频信号混频到基带后如果CIC和FIR链路设计正确输出频谱的主峰干净没有明显镜像分量。镜像分量出现在输出频谱的非零频处如果太大说明滤波器的阻带衰减不够IQ两路幅度一致性要好差太多说明混频或滤波器链路的位宽截断有问题。数值上可以用max(abs(fft( ... )))看主峰用20*log10(max(abs(fft(...))) / max(abs(fft(...,tail))))估算信噪比。实测链路信噪比如果低于60dB先排查位宽截断是否过于激进再看滤波器系数是否需要提高阶数。4. SysGen开发的深水区时钟域、流水线与硬件部署4.1 采样率标注机制与硬件行为SysGen的采样率标注机制我花了好长时间才完全搞明白。Simulink对信号线的采样时间是有自动推断的你连一条线如果上游是1对应122.88M下游模块期望的输入采样时间是4对应30.72MSimulink会报错。然而SysGen的模块特殊性在于它们都支持Sample Rate参数模块本身往往会声明我接受采样时间倍数为N的输入并输出采样时间倍数为M的结果。这个机制是好事也是坑。好处是你不必手动在每个模块里指定采样时间Simulink会自动传播坏处是如果你连错了模块比如把CIC的输入接到了FIR Compiler采样时间倍数为4的输出端口SysGen会报sample time mismatch错误。排查方法是双击报错的信号线看它的采样时间标注再反向追踪上游模块的输出设置。有一个更隐蔽的问题Down Sample模块和CIC Compiler都把速率降下来了但它们的硬件行为不同。Down Sample只是简单的数据选择器它不包含抗混叠滤波你要自己保证输入信号带宽已经满足抽取后的奈奎斯特定理而CIC Compiler内部自带滤波级联它输出的数据已经过滤掉了抽取产生的镜像。所以在模型设计时不要把这两类模块混用而不加滤波器。4.2 插入流水线从仿真正确到时序收敛SysGen模型仿真正确不代表生成的RTL在FPGA上一定能跑到目标时钟频率。原因是Simulink模型里模块之间的组合逻辑延迟是零但FPGA上的路径延迟是真实的。特别是多速率系统中数据率高的部分路径较长组合逻辑层级多很容易出现时序不收敛。解决办法是在关键路径上插入Delay模块这个操作也叫流水线化。SysGen里直接拖Delay模块Xilinx Block集里有双击设置Latency往上加1、2个周期。插入Delay后模型的功能不会变因为DSP链路是线性时不变的但会破坏模块间的时序依赖帮助综合工具做时序收敛。我的习惯是这样先在Simulink里用Resource Estimator看一下每条链路用了多少LUT、DSP48和BRAM如果DSP48用得很多或者LUT逻辑层级很深就在乘法器前后各插一个Delay。插完后重新跑一遍仿真确认没有引入位宽变化或者数据对齐问题——Delay如果插在了IQ两路中的一路另一路也要对应插相同的延迟否则IQ相位会错开。SysGen有一个FDATool模块不能插Delay但FIR Compiler内部有Output Latency参数可以直接调不用额外插外部模块。4.3 生成IP核并集成到VivadoSysGen设计完成的最终产物是IP核。在System Generator token里点Generate它会生成对应的Vivado IP工程文件.xci或.xpr包含RTL代码、约束文件和仿真模型。生成之后在Vivado的IP Catalog里能找到这个自定义IP可以像使用官方IP一样把它例化到工程里。这里有个要点SysGen生成的IP核默认没有AXI接口只是一个纯组合/时序逻辑模块输入输出对应模型里的Gateway In和Gateway Out。如果你想挂到Zynq的AXI总线上要么自己在模型里加AXI4-Stream接口模块要么在Vivado里包一层AXI外设封装。SysGen新版提供了AXI4-Stream Interface相关的模块可以直接拖到模型里作为输入输出端口。集成进Vivado以后记得把SysGen生成的约束文件里关于时钟的约束检查一遍。SysGen默认假定只有一个时钟也就是你mmodel里设置的FPGA时钟。如果你的设计里有多时钟域SysGen不会自动处理跨时钟域逻辑你需要自己在Vivado里添加异步FIFO或者XPM_CDC原语。不要图省事直接用两个时钟驱动SysGen IP的端口跑上板测试的时候数据会偶发错乱排查起来极其折磨。板级调试还有一个容易忽略的问题下载器和驱动。Xilinx的Platform Cable USB在Windows上偶尔会出现无法加载设备的驱动这个经典报错表现为设备管理器里一个带黄色感叹号的未知设备。这通常不是下载器坏了而是驱动版本没配对或者之前装过旧版ISE/Vivado留下了残留驱动。解决方法是卸载旧驱动后安装当前Vivado自带的Cable Drivers安装完再重插USB注意插拔顺序先装驱动再插cable然后打开Vivado Hardware Manager。这个顺序反了照样可能识别不到。5. 多速率建模的典型坑与调试心得5.1 仿真挂起、速度慢Simulink模型点运行以后仿真卡在一个时间点不动或者慢到像死机。这是多速率SysGen最常见的问题原因大概率是求解器配置错误。SysGen模型必须用固定步长离散求解器步长等于FPGA时钟周期。如果你用auto求解器Simulink会在连续/离散之间反复切换采样时间推断也会混乱仿真直接没法收敛。另外一个原因是模型里有无穷循环或代数环Simulink会为了求解代数环反复迭代。SysGen生成的DSP链路理论上不会有代数环但如果你接了From Workspace再通过Gateway Out回环到输入就会造成组合逻辑自环仿真就会挂起。解决办法是给回环路径加一个Delay哪怕延迟1拍破坏组合环。仿真耗时太长的另一个大坑是仿真步长太细。SysGen模型里FPGA时钟周期设成1ns的话仿真1ms需要100万个步长。实际调试时我习惯在System Generator token里临时把时钟周期改大一点比如从8.138ns改成100ns这样仿真速度能快接近10倍。注意这么做之后模型里的速率关系不变因为所有模块的采样时间都基于同一个时钟周期但仿真时数据有效节奏会变慢适合功能验证不适合时序性能评估。5.2 数据结果与理论不一致如果你确认滤波器系数和结构都没错但仿真输出频谱跟理论对不上优先检查位宽截断。多速率链路里每一级数据位宽都在变化CIC输出宽FIR输出宽到了Convert截位截断方式直接决定信噪比。SysGen的Convert模块有Quantization设置Truncate是直接截断Round是四舍五入。FPGA上Round比Truncate多消耗一点点逻辑但信噪比好很多一般建议用Round加Saturate防止溢出产生大的毛刺。如果你导出的定点数和MATLAB浮点仿真对不上先确认定点格式是不是选对了。整数位宽不够信号一满量程就溢出了小数位宽太宽动态范围就窄了。SysGen里有Hardware Assistant会自动检测数据范围提示你哪些信号有溢出风险这个功能一定要开。开的位置在System Generator token的Advanced选项卡里。5.3 FIR编译器多速率配置的几个雷FIR Compiler是SysGen里用得多也最容易出问题的模块。配置抽取/插值模式时有两个地方特别容易犯错。第一Filter Type选Decimation后下面还有一个Decimation Rate如果你写的是4模块输出端的数据率是输入端的1/4但滤波器计算频率是不变的。如果滤波器的阶数很高输出端会出现数据来不及算的情况SysGen会插入pipeline stall输出端会多出一个rdy信号指示数据什么时候有效。硬件上这个rdy信号很重要你后续模块必须等待rdy有效才采样数据。好多人在验证时只接数据线不接rdy出来的数全是乱的。第二滤波器系数导入的格式。SysGen的FIR Compiler要求系数是向量形式而且必须是行向量不能用列向量。有时候你在MATLAB里用fir1生成的是行向量没问题但如果你从Excel导入系数或者用字符串拼接很容易变成列向量SysGen不会报错但滤波器会全部变成0。排查方法是在工作区里用isa(coeff,double)检查类型用size(coeff)确认维度。5.4 硬件验证与仿真结果不一致上板以后实测数据跟仿真对不上是另一个高发问题。先别急着怀疑SysGen的模型大概率是下面几种情况之一没有等时钟稳定就释放复位。SysGen的IP复位是高电平有效还是低电平有效在生成的时候可以选。如果复位极性配错了整个链路可能会一直处于复位状态输出自然是0。输入数据的对齐问题。SysGen生成的IP如果输入是并行多路比如4路122.88M合并成1路491.52M那数据是按什么顺序排列的必须严格参照生成的RTL代码里的注释。在Vivado仿真里先跑一遍生成的网表确认输入输出时序关系再上板接真实数据。时钟使能信号没有正确连接。多速率IP内部是靠时钟使能来控制数据有效率的如果你在Vivado里把时钟使能引脚悬空或者接成了恒定高电平所有数据都会变成每个时钟都有效速率关系直接被破坏输出频谱自然错乱。查这个问题的时候直接在Vivado里找到IP实例看ce信号的来源多半能找到根源。调试强烈建议用Vivado的ILA插入几个内部信号同时抓混频前和CIC后的数据。抓下来以后把ILA导出的数据在MATLAB里做个FFT和Simulink仿真波形放在一起对比如果频谱特征一致说明链路基本对了只是后面某个环节处理不当如果完全不一样优先排查时钟和复位配置再回头检查采样时间设置。5.5 系统级选型的一些参考最后延伸一个话题。多速率系统的模块选型和FPGA选型是有强关联的。同样是做4倍抽取CIC方案几乎不吃DSP48但速率很高的时候对逻辑资源加法器的需求会涨多相FIR方案消耗DSP48但对逻辑资源友好。选型的时候建议查一下手头芯片的资源表再掂量你的设计里DSP48数量够不够。Xilinx的选型手册里每个型号的DSP48、BRAM和LUT数量都有明确标注DDC这种链路建议先粗算DSP48用量再选型。还有一个容易忽略的点Zynq平台做多速率系统时片内PS侧和PL侧的接口速率也是瓶颈PL侧的AXI-Stream接口位宽和时钟决定了数据吞吐上限这块要记得留充裕余量不要卡着理论极限选型。我个人在实际操作里的体会是SysGen的多速率建模能力很强但它要求你对两件事有清晰的认识一是信号处理的基本原理抽取插值背后的频谱变化二是FPGA底层的实现机制时钟使能、流水线、位宽截断。这两块一旦通了做多速率系统基本就是张飞吃豆芽。如果只把SysGen当作一个自动生成代码的黑盒子遇到问题就只能瞎试效率反而不如直接用Verilog写。最后再分享一个小技巧每次跑仿真前把System Generator token里的Simulation Mode设置成Hardware Co-Simulation先在Simulink里做纯仿真通过之后再切到板级硬件协同仿真。这样每一轮的调试周期会缩短很多板上抓回来的数据可以直接和模型里的波形做逐点对比定位问题的时间至少省一半。
返回列表