ARTICLE DETAIL

资讯详情

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

Vivado CIC与FIR IP核仿真翻车?7个关键配置参数避坑指南

Vivado CIC与FIR IP核仿真翻车?7个关键配置参数避坑指南 1. 为什么CIC和FIR的IP核配置总在仿真阶段翻车做数字信号处理这块的FPGA工程师十个里有八个在Vivado仿真阶段被CIC和FIR的IP核坑过。综合能过、实现能过、时序也能收敛偏偏仿真波形一跑出来输出全是零、满量程饱和、或者干脆冒出一堆不定态。这种情况我遇到过太多次了每次排查下来问题几乎都出在IP核配置参数和仿真环境的匹配上而不是代码逻辑本身。CIC滤波器和FIR滤波器在Vivado里分别对应两个独立的IP核前者叫CIC Compiler后者叫FIR Compiler。这两个核的配置界面参数加起来有几十个但真正决定仿真能不能跑通、结果对不对的其实就那么几个关键项。我打算把我在实际项目里反复踩过的坑整理出来重点讲清楚7个最容易出问题的配置参数以及它们为什么会在仿真阶段引发异常。这篇文章适合已经会用Vivado建工程、跑过基本仿真的朋友。如果你刚开始接触FPGA信号处理建议先把Vivado的仿真流程走通一遍再来看不然有些概念会比较吃力。全文会围绕参数背后的原理、配置时的取舍逻辑、以及仿真排查的具体手法展开尽量做到看完就能直接对照自己的工程改配置。2. 先搞清楚CIC和FIR在仿真里的行为差异2.1 CIC滤波器的积分梳状结构为什么对初值敏感CIC滤波器的结构说白了就是积分器加梳状器中间夹一个抽取或插值环节。积分器本质上是一个累加器它对输入的每一个样点做累加输出是历史所有输入的累积和。这个特性决定了CIC对初值极其敏感——如果仿真开始时积分器的寄存器没有被正确复位或者输入数据里混入了不定态累加结果会迅速发散波形上表现为输出直接冲到最大值然后卡住不动。我在一个抽取倍数为8、差分延迟为1、级数为5的CIC设计里遇到过这种情况仿真跑了两百个时钟周期输出一直是满量程。查了半天代码没问题最后发现是IP核配置里没有勾选输出端口的数据有效指示导致我在测试平台里采样的时机不对采到的全是积分器中间态的垃圾值。CIC还有一个特点是它的增益跟抽取倍数、级数、差分延迟都有关系。增益公式是(G × R × M)^N其中G是抽取或插值倍数R是差分延迟M是级数N是滤波器级数。这个增益如果不做归一化处理输出位宽会膨胀得很快。仿真的时候如果输出位宽截断位置不对波形看起来就会像是滤波器没工作。2.2 FIR滤波器在仿真中的资源与精度权衡FIR滤波器的仿真问题跟CIC不太一样。FIR Compiler的配置项更多涉及系数位宽、数据位宽、累加器位宽、输出位宽、以及各种量化模式。仿真阶段最常见的问题是输出精度不够导致波形失真或者系数没有正确加载导致输出恒为零。FIR滤波器的实现结构有全并行、半并行、串行等多种不同结构在仿真时的行为差异很大。全并行结构每个时钟周期输出一个结果仿真波形看起来最直观串行结构需要多个时钟周期才能算出一个输出如果测试平台没有按照IP核的握手信号来采样就会采到无效数据。我印象比较深的一次是做一个多相滤波的抽取系统FIR核配置成半并行结构仿真时输出一直不对。后来发现是IP核的通道数配置和我的多相分解方式不匹配导致系数被错误地分配到了不同的相位上。这个问题在综合报告里完全看不出来只有仿真波形才能暴露。3. 七个关键配置参数的逐项拆解3.1 参数一抽取或插值倍数的设置与仿真采样率匹配CIC Compiler里第一个要填的就是抽取倍数或者插值倍数。这个参数直接决定了输出采样率相对于输入采样率的变化。仿真的时候测试平台产生的输入数据速率必须和这个倍数匹配否则波形看起来就是乱的。举个例子你配置了一个抽取倍数为4的CIC输入采样率假设是100MHz那么输出采样率就是25MHz。在仿真里如果你还是按照100MHz的节奏去采样输出端口就会在每个输出样点之间采到三个无效值。正确的做法是在测试平台里用一个计数器每四个输入时钟周期采样一次输出。这个参数还有一个容易忽略的地方抽取倍数和插值倍数在IP核里的配置位置不同。抽取模式在CIC Compiler的第一个页面设置插值模式需要先切换模式再设置。我有一次帮人排查问题他一直在抽取模式的页面找插值倍数的设置找了半天没找到最后发现是模式选错了。注意抽取倍数和插值倍数不能同时大于1。CIC核要么做抽取要么做插值不支持同时进行。如果你需要同时做抽取和插值得用两个CIC核级联。3.2 参数二差分延迟的选择对频率响应的影响差分延迟这个参数在CIC核里通常只有1和2两个选项。很多人觉得随便选一个就行反正影响不大。但实际上差分延迟会改变CIC滤波器的频率响应形状尤其是在高频段的衰减特性。差分延迟为1的时候CIC的零点位置在采样率的整数倍处差分延迟为2的时候零点位置会偏移。这个差异在仿真里表现为输出波形的频谱成分不同。如果你做的是一个窄带信号提取差分延迟选错了会导致带外抑制不够仿真出来的波形上会看到明显的混叠成分。我在一个无线通信的接收链路里用过差分延迟为2的CIC当时是为了匹配一个特定的采样率转换比。仿真的时候发现输出信号的星座图明显比预期要散排查了很久才意识到是差分延迟改变了滤波器的通带边缘导致部分有用信号被衰减了。后来改成差分延迟为1问题就解决了。这个参数的选择依据是你的系统对通带边缘和阻带衰减的具体要求。如果没有特殊要求默认选1就行因为差分延迟为1时CIC的频率响应最规整仿真结果也最容易预测。3.3 参数三级数的确定与输出位宽的计算CIC的级数决定了滤波器的阶数也直接决定了增益的大小。级数越多滤波效果越好但增益也越大输出位宽需求也越高。仿真的时候如果输出位宽不够就会发生截断波形上表现为削顶失真。输出位宽的计算有一个标准公式B_out B_in ceil(N × log2(G × R))其中B_in是输入位宽N是级数G是抽取或插值倍数R是差分延迟。这个公式算出来的位宽是保证不溢出的最小位宽。实际配置的时候可以在这个基础上再留一点余量。我一般会在仿真之前先用这个公式算一遍然后跟IP核自动计算出来的位宽对比。如果IP核给的位宽比公式算出来的小那就要手动改大否则仿真一定会溢出。有一次我做一个级数为5、抽取倍数为16的CIC输入位宽是12位公式算出来输出至少需要12 ceil(5 × log2(16)) 12 20 32位。IP核默认给了28位仿真跑出来果然在信号幅度大的时候出现了削顶。提示CIC的输出位宽宁大勿小。多出来的位宽在后续处理里可以截掉但位宽不够导致的溢出是不可逆的。3.4 参数四FIR系数位宽与数据位宽的匹配FIR Compiler里系数位宽和数据位宽是两个独立的参数。系数位宽决定了滤波器系数的量化精度数据位宽决定了输入信号的量化精度。这两个参数如果不匹配仿真结果会明显偏离预期。系数位宽一般建议在12到18位之间。太低了会导致滤波器频率响应失真太高了会浪费资源。数据位宽则取决于你的ADC或者前级处理输出的实际位宽。我见过有人把数据位宽设成8位系数位宽设成16位仿真出来的滤波器阻带衰减只有30dB远低于设计的60dB要求。后来把数据位宽改成12位阻带衰减就上去了。这里有一个经验性的匹配原则系数位宽至少要比数据位宽大4到6位。因为滤波器系数的动态范围通常比信号本身要大系数需要更多的位宽来保证量化噪声不成为主导因素。仿真的时候可以先用这个原则配一组参数然后看输出频谱是否满足要求不满足再微调。3.5 参数五累加器位宽与输出位宽的截断策略FIR Compiler的累加器位宽是一个容易被忽视但非常关键的参数。累加器负责把所有的乘积累加起来如果位宽不够中间结果就会溢出。仿真的时候溢出表现为输出波形上出现随机的尖峰或者阶跃。累加器位宽的计算跟滤波器的阶数有关。最坏情况下累加器的最大绝对值是系数绝对值之和乘以输入数据的最大绝对值。对于N阶FIR累加器位宽至少要是数据位宽加上log2(N)再加上系数位宽的超额部分。Vivado的IP核通常会自动计算一个推荐值但这个推荐值有时候偏保守有时候又偏激进。输出位宽的截断策略有几种全精度输出、截断、四舍五入。全精度输出不会引入额外误差但位宽最大。截断会引入直流偏置四舍五入的误差最小但资源消耗稍高。仿真的时候如果发现输出有固定的直流偏移多半是截断策略选成了直接截断。我一般会在仿真阶段先用全精度输出跑一遍确认滤波器逻辑本身没问题然后再切换到实际的截断策略观察精度损失是否可接受。这样可以把滤波器设计的问题和位宽截断的问题分开排查。3.6 参数六通道数与多相滤波的配置对应关系FIR Compiler支持多通道配置这个功能在多相滤波或者多天线系统里很有用。但通道数的配置必须和你的多相分解方式严格对应否则仿真出来的波形就是错的。多相滤波的基本思路是把一个高速率的FIR滤波器分解成多个低速率的子滤波器每个子滤波器处理一个相位的数据。在FIR Compiler里通道数应该等于多相分解的相位数。如果你做了4相分解通道数就要设成4。如果设成了2那么每个通道会拿到两个相位的数据系数分配就乱了。我在一个多相抽取系统里犯过这个错误。当时做了8相分解但IP核的通道数忘了改还是默认的1。仿真的时候输出数据的速率是对的但波形完全不对像是被随机调制过一样。后来把通道数改成8并且按照IP核要求的通道顺序重新排列了输入数据波形立刻就正常了。注意多通道模式下输入数据的排列顺序有特定要求。通常是按通道号交替排列具体要看IP核的文档说明。仿真的时候如果发现输出不对先检查输入数据的排列顺序。3.7 参数七时钟使能与复位信号的仿真行为CIC和FIR的IP核都有时钟使能和复位端口。这两个信号在仿真里的行为直接影响到IP核是否正常工作。复位信号如果是高有效仿真开始时必须给一个足够宽的复位脉冲否则IP核的内部状态机可能没有正确初始化。时钟使能信号在仿真里经常被忽略。有些人图省事直接把时钟使能拉高觉得这样IP核就会一直工作。但实际上时钟使能如果一直有效IP核会以最大速率处理数据可能跟你测试平台的数据速率不匹配。正确的做法是用时钟使能来控制IP核的处理节奏让它跟输入数据的有效周期对齐。我遇到过一次仿真输出全是零的情况查了很久发现是复位信号在仿真开始时没有给IP核一直处于复位状态。Vivado的IP核在复位释放之前是不会输出有效数据的这个行为在仿真里表现得特别明显。后来在测试平台里加了一个复位初始化过程问题就解决了。4. 仿真环境搭建与参数验证的完整流程4.1 测试平台的数据源设计仿真CIC和FIR的时候测试平台的数据源设计很关键。我一般会用两种数据源一种是简单的正弦波或者扫频信号用来观察滤波器的频率响应另一种是随机噪声或者实际采集的数据用来验证滤波器在真实场景下的行为。正弦波数据源的频率要选在滤波器的通带内幅度要接近满量程但不能溢出。扫频信号可以从直流扫到奈奎斯特频率用来观察滤波器的整个频率响应曲线。随机噪声则用来检查滤波器对带外成分的抑制能力。数据源的位宽要和IP核配置的数据位宽一致。如果数据源是浮点数需要先量化成定点数再送入IP核。量化的过程中要注意不要引入额外的截断误差否则仿真结果会不准确。4.2 参数配置的交叉验证方法配置完IP核之后不要急着跑长仿真。先用一个短时间的仿真比如几百个时钟周期观察输出波形的基本形态。如果输出全是零或者全是最大值那肯定是配置有问题不用往下跑了。短仿真通过之后再用一个较长的仿真比如几万个时钟周期观察输出波形的稳定性和精度。这个时候可以打开Vivado的仿真波形窗口用测量工具看一下输出的频谱或者信噪比。如果频谱不符合预期就回到IP核配置页面调整参数。我习惯在仿真之前先用MATLAB或者Python算一遍理想滤波器的输出然后跟Vivado的仿真结果对比。如果两者差异很大说明IP核配置有问题如果差异在合理范围内说明配置基本正确剩下的就是精度优化的问题。4.3 仿真速度的优化技巧Vivado的仿真速度是出了名的慢尤其是涉及到IP核的时候。我一般会用以下几个方法来加速仿真第一个方法是减少仿真时间。不要一上来就跑几十毫秒的仿真先用微秒级的仿真验证功能功能对了再跑长仿真看性能。第二个方法是关闭不必要的波形记录。Vivado默认会记录所有信号的波形这会消耗大量的内存和时间。可以在仿真设置里只记录关键信号比如输入输出和几个内部状态信号。第三个方法是使用Vivado的编译式仿真流程。把IP核和测试平台编译成库后续仿真就不用重新编译了速度会快很多。第四个方法是降低时钟频率。仿真的时候不需要跑实际的工作频率把时钟周期设大一点仿真速度会明显提升。只要时钟使能和握手信号的时序关系正确低频仿真和高频仿真的功能验证结果是一样的。5. 常见仿真异常与排查速查5.1 输出恒为零的排查路径输出恒为零是CIC和FIR仿真里最常见的问题。排查的时候按照以下顺序来先检查复位信号。确认复位在仿真开始时已经给过并且已经释放。如果复位一直有效IP核不会输出任何数据。再检查时钟使能。确认时钟使能在仿真过程中有正确的翻转。如果时钟使能一直为低IP核不会工作。然后检查输入数据。确认输入数据在仿真过程中有变化并且不是全零。如果输入数据本身就是零输出自然也是零。最后检查IP核的配置。确认抽取或插值倍数、通道数、系数加载方式等参数都正确。特别是FIR核如果系数没有正确加载输出也会是零。5.2 输出饱和或削顶的排查路径输出饱和通常是因为位宽不够或者增益没有归一化。排查的时候先算一遍理论增益然后跟IP核配置的输出位宽对比。如果输出位宽小于理论需求那就是位宽不够。CIC的增益公式前面已经说过了FIR的增益是系数绝对值之和。如果增益大于1输出就会放大需要相应的位宽来容纳。如果增益远大于1可能需要在IP核里开启增益归一化或者在后续处理里做缩放。还有一种可能是输入数据的幅度太大。仿真的时候如果输入数据的幅度接近满量程经过滤波器放大后就会溢出。可以先把输入幅度降一半再跑仿真如果输出正常了那就是输入幅度的问题。5.3 输出波形畸变的排查路径输出波形畸变的表现是波形形状不对比如正弦波变成了方波或者出现了明显的谐波成分。这种情况通常是滤波器的频率响应不符合预期。先检查系数。FIR核的系数如果量化精度不够频率响应会失真。可以试着把系数位宽加大几位看波形是否改善。再检查数据位宽。数据位宽不够会导致量化噪声增大波形上表现为毛刺或者随机抖动。可以试着把数据位宽加大看波形是否变干净。然后检查累加器位宽和输出截断策略。累加器位宽不够会导致中间结果溢出输出截断策略不当会引入直流偏置或者额外噪声。最后检查多相配置。如果用了多通道或者多相滤波通道数和数据排列顺序必须严格匹配否则波形会完全乱掉。5.4 仿真速度过慢的排查路径仿真速度慢的原因有很多排查的时候先看仿真时间是不是设得太长。如果仿真时间设了几十毫秒那慢是正常的缩短仿真时间就行。再看波形记录是不是开得太多。Vivado默认记录所有信号可以在仿真设置里关掉不必要的信号记录。然后看是不是用了行为级仿真。行为级仿真比编译式仿真慢很多可以切换到编译式仿真流程。最后看IP核的配置是不是太复杂。比如FIR核如果配成了全并行结构仿真时的计算量会很大。可以先用串行或者半并行结构验证功能功能对了再切换到全并行结构看性能。6. 几个我踩过的坑和对应的解法6.1 系数文件格式不对导致FIR输出异常FIR Compiler支持从文件加载系数文件格式有COE和MIF两种。我遇到过好几次系数文件格式不对导致仿真输出异常的情况。COE文件的格式是两行第一行是radix第二行是系数列表。MIF文件的格式更复杂一些需要指定深度和位宽。有一次我用了一个从MATLAB导出的系数文件格式是COE但radix写成了十进制而系数本身是浮点数。Vivado读取的时候把浮点数当成了整数系数全变成了零仿真输出自然也是零。后来把系数先量化成定点数再按照正确的radix导出问题就解决了。提示导出系数文件之前先在MATLAB或者Python里把系数量化成定点数并且确认量化后的系数跟原始系数的频率响应差异在可接受范围内。6.2 多通道配置下数据顺序错乱多通道FIR的输入数据排列顺序有特定要求。我一开始以为是把所有通道的数据打包成一个宽位数据然后按顺序送入。实际上IP核要求的是按通道号交替排列每个时钟周期送入一个通道的数据。这个错误导致仿真输出完全不对波形看起来像是被随机调制过。后来仔细看了IP核的文档发现输入数据的排列方式在配置页面有说明只是我之前没注意。按照文档要求重新排列数据之后波形立刻就正常了。6.3 复位释放时机不对导致输出延迟CIC和FIR的IP核在复位释放之后需要几个时钟周期才能输出有效数据。这个延迟在仿真里表现为输出端口在前几个周期是不定态或者零。如果测试平台没有考虑到这个延迟就会采到无效数据。我一般会在测试平台里加一个计数器复位释放之后等足够多的周期再开始采样输出。等待的周期数可以从IP核的文档里查到通常是级数加上几个额外的流水线周期。6.4 时钟使能频率过高导致数据丢失时钟使能信号的频率决定了IP核的处理速率。如果时钟使能的频率高于输入数据的有效速率IP核会在没有新数据的时候重复处理旧数据导致输出异常。我有一次把时钟使能设成了每个时钟周期都有效但输入数据的有效速率只有时钟频率的四分之一。结果IP核对每个输入样点处理了四次输出数据的速率变成了预期的四倍波形完全乱了。后来把时钟使能的频率降到跟输入数据速率一致问题就解决了。7. 仿真通过之后还要做什么仿真通过只是第一步接下来还要做综合、实现、时序收敛、上板验证。仿真阶段暴露的问题如果能在配置层面解决后续的流程会顺利很多。我一般会在仿真通过之后把IP核的配置参数导出成一个配置文件方便后续工程复用。还有一点是仿真通过不代表上板一定没问题。仿真环境是理想化的没有考虑时钟抖动、电源噪声、温度变化等因素。上板之后如果发现输出异常可以先用Vivado的在线逻辑分析仪抓一下实际波形跟仿真波形对比看看差异在哪里。我个人在实际操作中的体会是CIC和FIR的IP核配置没有想象中那么复杂关键是要理解每个参数背后的物理意义而不是死记硬背配置步骤。理解了抽取倍数和采样率的关系、级数和增益的关系、位宽和精度的关系配置的时候自然就知道该怎么选了。仿真出问题的时候也能快速定位到是哪个参数配错了而不是盲目地试来试去。
返回列表