news 2026/9/12 1:38:14

高云FPGA FIR低通滤波器设计:系数生成、IP配置与仿真验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高云FPGA FIR低通滤波器设计:系数生成、IP配置与仿真验证

简介:面向FPGA开发学习者,这套基于高云FPGA的IP设计实现的FIR低通滤波器工程包,覆盖RTL源码编写、IP核配置、仿真验证到工程实现的全流程,适合通信工程、电子信息、自动化等专业用于课程设计、毕业设计或项目初期的方案演示。压缩包共125个文件,大小33.78MB,其中Verilog源文件、工程配置文件、仿真脚本与测试数据一应俱全,还附有HTML版报告和详细Word文档,方便对照工程结构和算法原理进行系统性学习。整个设计已在开发环境中测试通过,文档包含滤波器参数选取思路、IP核调用步骤、仿真波形分析方法与常见问题处理,能够帮助读者快速上手高云FPGA开发并独立完成同类数字信号处理设计。当前已有84人学习下载,适合需要完整工程参考和相关文档支撑的开发者直接使用或在此基础上扩展功能,作为课设、毕设的初始框架也很合适。

1. 从频谱混叠到高云FPGA:FIR低通滤波器为什么值得自己搭一遍

ADC采集真实信号时最容易翻车的是“时域看着干净、频域全是毛病”。50 MHz采样率下,前端电路引入20 MHz以上的自激振荡,示波器上只看到一条细线,FFT之后频谱里却多出一截完全不该有的毛刺。FIR低通滤波器的任务就是把这截窗外频谱压到噪声底以下。选高云FPGA而不是DSP方案,是因为滤波之后往往还挂着FFT、DDC、成型滤波等逻辑,在数据通路上直接内嵌FIR IP核,延迟固定、时钟可控,布局布线时的时序约束也好写得多。这份基于高云FPGA IP设计的FIR低通滤波器工程,内部包含coeff.dat系数文件、sin_wave.dat测试激励、lab_fft.cst物理约束以及详细设计文档,价值在于把“系数怎么算、IP怎么配、结果怎么验”整条链路串在一起。适合通信工程、电子信息、自动化专业的课设和毕设参考,也适合刚接触FPGA的工程师用来熟悉高云IP集成流程和工程文件体系。

2. FIR低通滤波器设计指标与coeff.dat系数生成的完整链路

2.1 采样率、截止频率与抽头数的换算逻辑

FIR滤波器最上层的三个参数是采样率、截止频率和抽头数,三者之间不是独立选取的关系。采样率决定奈奎斯特频率,截止频率定义通带与阻带的分界。以50 MHz采样率、5 MHz目标截止频率为例,数字域归一化频率就是5/50=0.1,直接代入滤波器设计函数得到的是以奈奎斯特频率为基准的比值,而不是把5 MHz直接当参数传进去。

抽头数决定过渡带的宽窄。Hamming窗的过渡带经验公式为3.3/N,这里N是抽头数,得到的值需要再乘采样率换算成实际频率宽度。64抽头对应过渡带约2.6 MHz,意味着从5 MHz开始滚降,到7.6 MHz左右阻带衰减才达到设计值。如果系统要求在6 MHz处就必须压到-50 dB,64阶就hold不住,需要上128甚至256阶。所以阶数不是拍脑袋定的,是从“过渡带多窄、阻带要多深”倒推出来的。

系数阶数还会直接影响硬件开销。高云FPGA里FIR IP核默认用乘加器实现卷积,每级阶数对应一组乘法器。64阶在GW1N系列这类入门级器件上资源余量充足,但如果后面还挂着FFT、CIC或成型滤波,就要注意乘法器资源是否被多个IP共用。一个容易被忽略的点是:输入的8 bit数据做乘加后,中间结果位宽会膨胀到几十bit,IP核内部会按配置的系数位宽和输入位宽自动截断,这部分行为要跟踪好,否则输出数据精度和仿真对不上。

2.2 理想低通滤波器的工程近似与窗函数选型

严格意义上的理想低通滤波器,单位脉冲响应是无限长的sinc函数,并且是非因果的,工程上只能通过截断来实现近似。截断就是给无限长脉冲响应乘一个有限长窗,FIR滤波器的本质就是“有限长度逼近理想幅频特性”。窗函数直接决定逼近的质量。

窗函数主瓣宽度阻带衰减过渡带宽度δf×N/fs适用场景
矩形窗最窄约21 dB0.9对阻带无要求
Hanning较窄约44 dB3.1通用滤波
Hamming中等约53 dB3.38 bit数据场景
Blackman较宽约74 dB5.5高精度计量

对这个项目来说,8 bit ADC的量化噪声本身约48 dB,Hamming窗的53 dB阻带衰减刚好比量化噪声高出一截。Blackman虽然阻带更深,但过渡带宽到5.5/N,同样的64阶会吃掉更多有效带宽,代价不划算。矩形窗衰减只有21 dB,在ADC场景里基本等于没滤波,可以用但不可用。

2.3 Python生成64阶Hamming窗系数并导出coeff.dat

系数生成用Python的scipy.signal.firwin,这个步骤在MATLAB里做也等价,但Python脚本更容易写进自动化流程,改参数重跑一遍也快。直接看生成代码:

import numpy as np from scipy.signal import firwin fs = 50e6 # ADC采样率 50 MHz fc = 5e6 # 截止频率 5 MHz taps = 64 # 抽头数 64 # firwin返回64个浮点系数,窗口类型用hamming coeff_f = firwin(taps, fc, fs=fs, window='hamming') # Q15定点化,映射到16bit有符号整数区间 coeff_q15 = np.round(coeff_f * 32767).astype(np.int16) # 导出为两列文本格式,第一列索引,第二列系数值 with open('coeff.dat', 'w') as f: for idx in range(taps): f.write(f"{idx:04d} {coeff_q15[idx]:6d}\n") print(f"完成,共导出{taps}个抽头到coeff.dat")

这段代码里firwin的第一个参数传taps,第二个传fc,但如果没有fs=50e6这个参数,scipy会把fc当作归一化频率处理,算出来的系数在信号链上完全错位。输出到coeff.dat的每一行是“索引 系数值”,索引占四位宽度,系数值占六位宽度。高云FIR IP核的系数导入界面支持直接读文本文件,按空格切分后逐行映射到抽头;如果你的高云版本要求.coe格式,把文件头改成Radix=10; Coefficient_Width=16;再导出即可。Q15定点化的含义是把范围在[-1,1)内的浮点系数乘32767后取整,让系数落在16 bit有符号整数的有效区间里,IP内部乘法器按这个位宽做对齐,量化后系数值如果超过32767,就说明系数计算有误。

2.4 Q15定点量化对阻带衰减的影响

定点量化不是无代价的。浮点系数转成Q15后,每个系数会引入约正负0.5的量化误差。如果相邻抽头的量化误差正负交替,折叠到频域后会在阻带形成起伏,严重时阻带衰减掉10 dB以上。所以在做IP核配置之前,建议先对比一次浮点和定点系数的幅频响应。

对比方法不复杂:用scipy.signal.freqz分别计算浮点系数和Q15系数的频率响应,取阻带起始频点比较衰减值。如果衰减差超过3 dB,就需要把系数位宽提升到18 bit或20 bit。对8 bit ADC输入来说,16 bit系数已经足够,因为系数量化噪声远低于ADC自身量化噪声,再增加位宽对系统SNR的提升非常有限,但综合面积却线性增长。

提示:系数一旦导入IP核并完成综合,再次修改就要重新走一遍布局布线。把定点量化检查放在生成阶段,比在硬件上反复试错省时间得多。

3. 高云FPGA的FIR IP核配置与lab_fft工程文件结构解析

3.1 云源软件里FIR Filter IP核的参数配置

高云云源软件的IP Core Generator里,FIR滤波器IP一般归类在DSP目录下。新建工程后从IP核生成器进入FIR Filter,配置界面里需要重点关注的参数项如下:

参数项推荐值说明
Filter TypeLow Pass低通滤波器
Input Data Width8匹配ADC输出位宽
Coefficient Width16与coeff.dat的Q15格式对应
Coefficient Filecoeff.dat从文件导入系数
Number of Taps64与系数文件的行数一致
Decimation Rate1不抽取,保持原始采样率

配置时两个地方最容易出错。第一是Coefficient Width选成8 bit,IP核会按8 bit解析coeff.dat中的数据,做大数截断后系数全部溢出,综合时直接报数据宽度不匹配。第二是Number of Taps必须和coeff.dat里的系数行数完全一致,多一行或少一行都会在IP生成时提示文件格式错误。高云IP核没有自动感知系数数量的功能,导入之前先对系数文件做一次行数检查是值得养成的习惯。

3.2 lab_fft.db、device.cfg与lab_fft.bin的文件职责

解压工程压缩包后看到一堆后缀陌生的文件,容易让人觉得工程损坏了,实际上每个文件都有明确职责。

lab_fft.db是高云软件的工程数据库,保存综合、布局、布线之后的完整网表与约束信息。修改Verilog代码后靠这个文件做增量编译,能省掉全量综合的时间;如果工程被复制到别的机器上,缺少.db文件并不会导致无法打开工程,只是必须从头Run一遍完整流程。

device.cfg是下载器用的目标器件配置文件,里面记录目标FPGA型号、封装、烧写接口和擦除选项。烧录工具先读device.cfg确认芯片匹配,再加载bitstream,芯片型号不对会直接拒绝烧写。

lab_fft.bin是布局布线后导出的比特流文件,真正下载到FPGA里的就是它。高云FPGA的配置SRAM是易失的,每次上电都要重新写bin文件。lab_fft.binx是伴随bin生成的辅助二进制文件,存的是编译时间和工程版本之类的元数据,高云IDE重新打开工程时会拿它做版本校验,但烧录流程用不到。整个依赖链可以概括为:cst约束和Verilog源码经过综合布局布线生成db,再由db导出bin和binx,而device.cfg只服务于最终下载环节。

3.3 Verilog顶层例化与IP核复位时序

IP核生成后,高云会同时生成一个例化模板。把FIR滤波器放进顶层数据通路,代码比用Xilinx时的等价代码短不少:

// lab_fft_top.v module lab_fft_top( input wire clk_50m, input wire rst_n, input wire [7:0] adc_din, output wire [15:0] fir_dout ); // Gowin FIR低通滤波器IP核例化 Gowin_FIR_LP u_fir_lp( .clk (clk_50m), .reset (~rst_n), .clken (1'b1), .din (adc_din), .dout (fir_dout) ); endmodule

逻辑说明:adc_din是ADC采样输入,fir_dout是滤波后的16 bit输出。reset信号用了低有效向高有效转换的方式,对外部rst_n取反后送入IP核。实际调试中需要注意,reset必须完成一次有效的低脉冲再释放,高云FIR IP在启动时如果不复位,内部系数加载状态机可能停留在未知状态,前几个时钟周期的输出会出现不确定值。clken时钟使能端在这里固定拉高,如果后续需要低功耗控制,可以通过拉低clken来停止数据计算,但输出不会保持,需要注意下游模块的空闲处理。

4. 从sin_wave.dat到lab_fft.cst:仿真激励、物理约束与在线验证

4.1 Testbench回放sin_wave.dat采样数据

sin_wave.dat里存放的是预先生成的正弦波采样点。仿真时用系统函数读取文件回放采样点,比在testbench里用signal generator实时生成更高效,因为数据在仿真开始时一次性装载,可以精确控制每个时钟周期喂给IP核的值。

`timescale 1ns/1ps module tb_fir_lp(); reg clk_50m = 1'b0; reg rst_n = 1'b0; reg [7:0] adc_din = 8'd0; wire [15:0] fir_dout; // 50 MHz时钟,周期20 ns always #10 clk_50m = ~clk_50m; reg [7:0] sample_mem [0:2047]; integer idx; initial begin // 读取十六进制格式采样数据 $readmemh("sin_wave.dat", sample_mem); #50 rst_n = 1'b1; for (idx = 0; idx < 2048; idx = idx + 1) begin @(posedge clk_50m); adc_din <= sample_mem[idx]; end repeat(64) @(posedge clk_50m); $finish; end lab_fft_top u_dut ( .clk_50m (clk_50m), .rst_n (rst_n), .adc_din (adc_din), .fir_dout(fir_dout) ); endmodule

这里需要特别关注$readmemh与文件格式的匹配关系。sin_wave.dat如果是十六进制文本,用$readmemh才正确;如果是二进制或十进制,则要用$readmemb或者自定义读文件逻辑。读取结束后额外跑64个周期,是为了让滤波器流水线把最后一批数据从寄存器里推出来,否则波形末尾会显示不完整。2048个采样点已经足够覆盖64阶滤波器从启动到稳定的完整瞬态,不需要把文件里所有数据都回放一遍。

4.2 lab_fft.cst物理约束:引脚、电平标准与时钟周期

lab_fft.cst是物理约束文件,高云的cst语法与Xilinx UCF明显不同,每条约束以分号结尾。引脚约束的写法如下:

IO_LOC "clk_50m" 24; IO_PORT "clk_50m" IO_TYPE=LVCMOS33 PULL_MODE=UP; IO_LOC "rst_n" 25; IO_PORT "rst_n" IO_TYPE=LVCMOS33 PULL_MODE=UP; IO_LOC "adc_din[0]" 26; IO_LOC "adc_din[1]" 27; IO_LOC "adc_din[2]" 28; IO_LOC "adc_din[3]" 29; IO_PORT "adc_din[0]" IO_TYPE=LVCMOS33; IO_PORT "adc_din[1]" IO_TYPE=LVCMOS33;

约束规则里的IO_LOC决定引脚编号,IO_PORT的IO_TYPE指定电平标准。上面的24、25、26这些引脚号要替换成实际PCB原理图里对应的FPGA引脚,直接照抄会导致管脚复用冲突。PULL_MODE=UP给复位按键提供默认上拉,如果板子上已经有外部上拉电阻,这个属性可以省略。电平标准是另一个容易踩的坑,LVCMOS33对应3.3 V IO,如果板子IO供电是2.5 V却配成3.3 V,时序报告不会报错,但实际采集信号时会出现偶发bit翻转。

时钟周期约束建议单独写在cst文件末尾:

create_clock -name clk_50m -period 20.000 [get_ports {clk_50m}]

这里period的值必须大于等于实际时钟周期,20 ns对应50 MHz。如果综合后时序不收敛,优先检查period是否被误写成了2 ns或者20 ns不带小数,这两个写法都可能让时序分析工具的时钟裕量计算错乱。

4.3 仿真结果判断:群延迟固定性与阻带抑制比

仿真播放波形后,同步观察adc_din和fir_dout两组信号。FIR滤波器有固定群延迟,64阶滤波器的群延迟是31.5个时钟周期,换算到50 MHz下就是630 ns。如果dout相对din的延时不是这个值的整数倍,说明IP核内部流水线插入了一级或多级附加寄存器,这是正常现象,只要延时在多次运行中保持不变,数据链路就是确定的。

验证滤波器性能时,建议在sin_wave.dat里混合两个频率分量,比如2 MHz有效信号叠加24 MHz干扰。滤波后2 MHz分量幅值应该基本不变,24 MHz分量衰减到原来的百分之一以下。如果阻带衰减达不到预期,优先检查coeff.dat导入时是否有系数位宽截断,以及IP核内部是否选择了错误的输入输出截断策略。另一个常见问题是输入接近满幅时溢出,8 bit输入给满量程127的正弦波,FIR输出16 bit也接近饱和,测试激励适当降低输入幅度,给滤波器留出至少6 dB余量。

5. lab_fft.bin烧录与调参技巧:把FIR工程改成多频信号滤波器

5.1 用cos_sin_lut.dat做片内正交信号源

cos_sin_lut.dat是预计算的cos和sin查找表数据,工程里很多人在用波形发生器扫频验证时才发现它的价值。把它加载到FPGA内部ROM,通过相位累加器就可以生成两路正交波形,不需要外部仪器灌信号。

reg [9:0] phase; reg [7:0] sin_out; reg [7:0] cos_out; always @(posedge clk_50m) begin phase <= phase + 10'd1; end always @(posedge clk_50m) begin sin_out <= sin_lut[phase]; cos_out <= cos_lut[phase]; end

这里相位增量控制输出频率,增量每加1,输出频率提升约48.8 kHz。这个数字来自50 MHz采样率除以1024点查找表深度。想要验证多频混合信号,把sin_out和cos_out分别乘上不同系数再相加,就得到两个频率叠加的测试信号,直接接在FIR输入端。比起外部信号发生器,这个方案的频率偏差全部来自晶振精度,和实际工作时钟完全同源,不会出现仿真和板上频率对不上的问题。

5.2 分布式算法结构替换与参数迭代顺序

如果目标是降低DSP资源占用,高云FPGA上的FIR还可以考虑分布式算法结构。分布式算法用查找表替代乘法器,在乘法器资源紧张但LUT富余的型号上,64阶FIR可以节省大量DSP块。代价是查找表位宽随阶数指数增长,需要按4 bit一组做拆分,控制逻辑会更复杂一点。这个对于资源评估非常有参考价值:先确认当前FPGA够不够放乘法器,不够再考虑DA结构,不必在一开始就为了省资源把设计搞复杂。

调参时不要同时动两个参数。先改截止频率:把fc从5 MHz改成8 MHz,观察通带边缘是否按预期右移;再改阶数:从64加到128,观察阻带衰减是否下降得更快。coeff.dat每修改一次,就需要重新生成lab_fft.bin,此时务必删除lab_fft.db后重新Run All,让工具走完整综合布局布线流程,避免增量编译时旧系数残留。验证通过后,把输入混频结果和滤波输出同时送到调试探针,对比两个端口的FFT频谱,确认阻带抑制比满足设计指标,再进入下一轮参数迭代。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 1:37:51

国产NFC芯片FSV9510与FSV9510E深度解析:低功耗设计、天线匹配与选型实战

这两年做物联网和智能硬件的朋友&#xff0c;应该能明显感觉到一个趋势&#xff1a;NFC相关的国产芯片越来越能打了。最近我一直在跟进的一款芯片迭代&#xff0c;就是FSV9510 和 FSV9510E 这对组合。标题信息很直接——小尺寸优化、性能全面进阶&#xff0c;但放到实际项目里&…

作者头像 李华
网站建设 2026/9/12 1:36:33

Proteus仿真PM2.5检测系统:单片机数据采集与显示设计

简介&#xff1a;基于单片机Proteus仿真的空气质量PM2.5检测系统资源包&#xff0c;面向单片机初、中级学习者和电子设计人员&#xff0c;主要用于课程设计、毕业设计及环境监测类项目验证。系统集成PM2.5粉尘检测与温湿度采集&#xff0c;具备空气质量等级判断、历史数据查询、…

作者头像 李华
网站建设 2026/9/12 1:36:32

完全二叉搜索树1064题详解:中序填充与递归建树

很多人第一次看到“Complete Binary Search Tree”这个题目时&#xff0c;大概率会像我一样愣一下。BST&#xff08;二叉搜索树&#xff09;我熟&#xff0c;完全二叉树我也熟&#xff0c;但这俩拼在一起&#xff0c;还要按层序遍历输出&#xff0c;总觉得哪里卡住了。最关键的…

作者头像 李华