平台:Vivado2021.1
芯片:xcku115-flva1517-2-i (active)
语言:VerilogHDL
参考文件:pg149.下载地址
FIR Compiler LogiCORE IP Product Guide • FIR Compiler (PG149) • 阅读器 • AMD 自适应计算文档门户 (xilinx.com)
最近准备研究以下滤波器。还是从xilinx的官方IP出发,来学习以下这部分。
使用matlab直观的感受以下。输入信号为5khz,和10mhz正弦波叠加。
设置FIR滤波器参数。采样率为50mhz,通带起始频率为100KHz,阻带起始频率为1MHz。
使用matlab打开滤波器设计小工具。产生COE文件。
直接输入filterDesigner。
打开后的界面如下图所示。
我们按照设计参数对滤波器进行设置。
选择响应类型为低通。选择为FIR滤波器。采样率为50mhz,通带起始频率为100KHz,阻带起始频率为1MHz。设置好后选择设置量化参数。
滤波器算法选择定点。分子字长选择16位。设置完成后点击应用。
选择目标。Xilinx系数(.coe)文件。保存在你选定的文件夹中。
这样就生成了需要的FIR滤波器参数。可以在IP设计阶段直接导入到xilinx的IP中。
同时还需要将生成的波形数据进行归一化处理。在量化到2^16次方上去。
所以需要使用matlab产生用于IP核仿真的数据。
- %对数据进行归一化
- max_abs_value = max(abs(x)); % 获取数据的最大绝对值
- normalized_data = x / max_abs_value; % 归一化数据
-
- % 量化为16位数据
- simdata = normalized_data;
- quantized_data = round(simdata * (2^15 - 1));
-
- % 转换为十六进制数据
- hex_data = dec2hex(quantized_data, 4);
-
- %保存数据文件
- fileID = fopen('E:\simdata.txt','w');%将数据写入txt。
- % fprintf(fileID,'%d\n',quantized_data );%保存为十进制数据
- for i = 1:length(hex_data)
- fprintf(fileID, '%s\n', hex_data(i, :)); % 将每行的十六进制数据写入文件
- end
- fclose(fileID);
这里对产生的波形数据进行过归一化后。转换为16进制数据写入到文件simdata.txt中。
下面是整体的matlab代码。
- fs = 50000000; % 采样率为50MHz
- t = 0:1/fs:0.01; % 时间向量,采样时间为0.01秒
-
- f1 = 5000; % 5kHz正弦波频率
- f2 = 10000000; % 10mHz正弦波频率
-
- x = sin(2*pi*f1*t) + sin(2*pi*f2*t) ; % 输入信号,多个正弦波叠加
-
- %对数据进行归一化
- max_abs_value = max(abs(x)); % 获取数据的最大绝对值
- normalized_data = x / max_abs_value; % 归一化数据
-
- % 量化为16位数据
- simdata = normalized_data;
- quantized_data = round(simdata * (2^15 - 1));
-
- % 转换为十六进制数据
- hex_data = dec2hex(quantized_data, 4);
-
- %保存数据文件
- fileID = fopen('E:\CODE\Vivado\KU_TEST\ku_test_sim\flash_test\coe\simdata.txt','w');%将数据写入txt。
- % fprintf(fileID,'%d\n',quantized_data );%保存为十进制数据
- for i = 1:length(hex_data)
- fprintf(fileID, '%s\n', hex_data(i, :)); % 将每行的十六进制数据写入文件
- end
- fclose(fileID);
-
- order = 10; % FIR滤波器阶数
- cutoff = [100000]; % 截止频率
-
- b = fir1(order, cutoff/(fs/2)); % 设计FIR低通滤波器系数
-
- y = filter(b, 1, x); % 应用FIR滤波器
-
- % 时域波形绘制
- subplot(2, 2, 1);
- plot(t, x);
- title('滤波前的时域波形');
- xlabel('时间');
- ylabel('幅值');
-
- subplot(2, 2, 3);
- plot(t, y);
- title('滤波后的时域波形');
- xlabel('时间');
- ylabel('幅值');
-
- % 频域波形绘制
- X = fft(x);
- Y = fft(y);
- f = linspace(0, fs, length(t));
-
- subplot(2, 2, 2);
- plot(f, abs(X));
- title('滤波前的频域波形');
- xlabel('频率');
- ylabel('幅值');
-
- subplot(2, 2, 4);
- plot(f, abs(Y));
- title('滤波后的频域波形');
- xlabel('频率');
- ylabel('幅值');
使用matlab产生两个波形叠加。通过FIR滤波器后,画出了滤波前后的时域频域波形。
下面是FPGA部分。
IP核的资料是PG149,里面详细的介绍了这个IP资源。这里我们从应用的角度出发来使用这个IP。
接口方面。还是使用了熟悉的AXI接口。
接口非常的简单。只需要输入valid核数据即可。输出端有valid和数据有效。
此IP核的主界面。
在左侧部分分别是,IP核的接口。频率响应曲线。以及详细信息。和系数重载功能。
选择系数源,分别为coefile(COE文件)和Vector(系数矢量)。
这里我们选择coe文件,我们直接从matlab中生成的coe文件。直接选定到文件夹。
Number of Coefficient Sets多个系数集,对于多系数过滤器,单个.coe文件用于指定系数集。 每个系数集应附加到前一组系数。我们这里没有使用。
Number of Coefficients (per set)系数数量(每组):每个滤波器组的滤波器系数数量。自动计算。
Use Reloadable Coefficients使用可重新加载的系数:当选择重新加载选项时,在核心上提供一个系数重新加载接口。这里我们不使用。
Filter Type滤波器类型:支持五种滤波器类型:单速率FIR(有限脉冲响应滤波器)、插值FIR、抽取FIR、Hilbert变换和插值FIR。
我们选择为单速率。
下面的速率变化类型和插值速率抽值速率。分别对应于不同类型的滤波器设置。
下面是通道规范页。
Channel Sequence支持基本的和高级的。我们选择基本的即可。
Number of Channels通道数我们选择一通道。
下面的Select Sequence和Sequence ID List在高级模式中使用。
Select format选择格式。
Sample Period采样周期。
Input Sampling Frequency采样频率。跟你设置的采样频率一致。
Clock Frequency时钟频率。
Coefficient Type系数数据可以指定为有符号或无符号。
Quantization量化方式指定为整数。
Coefficient Width系数位宽,这里选择为16位模式。选择后在matlab中生成coe文件时选择一致。
Coefficient Structure系数结构:支持五种系数结构:非对称、对称、负对称、半带和希尔伯特。
数据路径选择。
同样的,选择输入数类型,数据位宽。这里选择后需要在模拟产生输入数据时,产生一致。
Output Rounding Mode输出数据的精度。默认为全精度。后面的选择可以选择输出数据位宽。
详细页
Goal优化选项。使用最下面积最快速度和custom定制。
Select Optimization和List选择分别定制优化。
下面的Memory Options就是选择缓存的类型。这里可以根据你的需求自己选择或者自动。
DSP Slice Column Options:DSP选择。
Multi-column Support可以选择为自动和定制。
Interface Tab接口页。
Data Channel Options选择AXI接口相关的参数。
TLAST指示AXI需要支持TLAST位不。以及是否使用tuser,tready等。
Configuration Channel Options
CONFIG通道用于选择活动的滤波器系数集。该通道还用于应用重新加载的滤波器系数。
Reload Channel Options和重加载相关。
Control Signals控制信号。选择复位时钟等等。
总结界面。
我们在顶层例化该IP核。
下面我们对该IP核进行仿真。
下面分别是例化代码和仿真tb。
- // *********************************************************************************/
- // Project Name :
- // Author : i_huyi
- // Email : i_huyi@qq.com
- // Creat Time : 2023/10/20 16:46:10
- // File Name : .v
- // Module Name :
- // Called By :
- // Abstract :
- //
- // CopyRight(c) 2020, xxx xxx xxx Co., Ltd..
- // All Rights Reserved
- //
- // *********************************************************************************/
- // Modification History:
- // 1. initial
- // *********************************************************************************/
- // *************************
- // MODULE DEFINITION
- // *************************
- `timescale 1 ns / 1 ps
- module fir#(
- parameter U_DLY = 1
- )
- (
- //
- input wire[15:0] fir_data_in ,
- input wire fir_data_inen ,
- output wire[39:0] fir_data_out ,
- output wire fir_data_outvalid ,
- //
- input wire clk ,
- input wire rst_n
- );
- //--------------------------------------
- // localparam
- //--------------------------------------
-
- //--------------------------------------
- // register
- //--------------------------------------
-
- //--------------------------------------
- // wire
- //--------------------------------------
- wire s_axis_data_tvalid ;
- wire[15:0] s_axis_data_tdata ;
- wire s_axis_data_tready ;
- wire m_axis_data_tvalid ;
- wire[39:0] m_axis_data_tdata ;
-
- //--------------------------------------
- // assign
- //--------------------------------------
- assign s_axis_data_tvalid = fir_data_inen;
- assign s_axis_data_tdata = fir_data_in;
- assign fir_data_out = m_axis_data_tdata;
- assign fir_data_outvalid = m_axis_data_tvalid;
-
-
- //------------------------------------------------------------
- //------------------------------------------------------------
- fir_compiler_0 u_fir_compiler_0 (
- .aresetn (rst_n ),// input wire aresetn
- .aclk (clk ),// input wire aclk
- .s_axis_data_tvalid (s_axis_data_tvalid ),// input wire s_axis_data_tvalid
- .s_axis_data_tready (s_axis_data_tready ),// output wire s_axis_data_tready
- .s_axis_data_tdata (s_axis_data_tdata ),// input wire [15 : 0] s_axis_data_tdata
- .m_axis_data_tvalid (m_axis_data_tvalid ),// output wire m_axis_data_tvalid
- .m_axis_data_tdata (m_axis_data_tdata )// output wire [39 : 0] m_axis_data_tdata
- );
- //------------------------------------------------------------
- //------------------------------------------------------------
-
- //------------------------------------------------------------
- //------------------------------------------------------------
- endmodule
仿真tb
- `timescale 1ns / 1ps
- //
- // Company:
- // Engineer:
- //
- // Create Date: 2023/10/23 09:33:40
- // Design Name:
- // Module Name: fir_tb
- // Project Name:
- // Target Devices:
- // Tool Versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- //
-
-
- module fir_tb;
- //input
- reg [15:0] fir_data_in;
- reg fir_data_inen;
-
- reg clk;
- reg rst_n;
- reg [15:0] simdata [0:32767];
- reg [15:0] read_data;
-
- //output
- wire[39:0] fir_data_out;
- wire fir_data_outvalid;
-
-
- fir u_fir(
- .fir_data_in (fir_data_in ),
- .fir_data_inen (fir_data_inen ),
- .fir_data_out (fir_data_out ),
- .fir_data_outvalid (fir_data_outvalid ),
- //
- .clk (clk ),
- .rst_n (rst_n )
- );
-
-
-
-
- //------------------------------------------------------
- //复位参数
- //------------------------------------------------------
- integer i;
- //设置复位参数
- initial
- begin
- $display("[%t] : reset begin...", $realtime);
- rst_n = 0;
- for( i=0 ; i<100 ; i=i+1)
- begin
- @(posedge clk );
- end
- $display("[%t] : reset stop...", $realtime);
- rst_n = 1;
- end
-
-
-
- initial
- begin
- clk = 0;
- read_data = 0;
- fir_data_in = 0;
- fir_data_inen = 0;
- wait(rst_n == 1);
- fir_data_inen = 1;
- $display("[%t] : read data begin...", $realtime);
- repeat(32767)
- begin
- @(posedge clk);
- read_data = read_data + 16'd1;
- fir_data_in = simdata[read_data];
- end
- repeat(100)@(posedge clk);
- $display("[%t] : read data stop...", $realtime);
- $finish(0);
-
-
- end
-
-
-
- initial
- begin
- $readmemh("E:/CODE/Vivado/KU_TEST/ku_test_sim/flash_test/coe/simdata.txt",simdata);
-
- end
-
-
- always #2 clk = ~clk;
-
-
-
-
- endmodule
在经过一段时间的仿真后,我们看到通过模拟产生的正弦波数据的高频分量在FIR滤波器的作用下只保留了低频部分。
今天的FIR滤波器就学习到这里。