Xilinx的FIR滤波器IP的设计与仿真

平台:Vivado2021.1

芯片:xcku115-flva1517-2-i (active)

语言:VerilogHDL

参考文件:pg149.下载地址

FIR Compiler LogiCORE IP Product Guide • FIR Compiler (PG149) • 阅读器 • AMD 自适应计算文档门户 (xilinx.com)

FIR滤波器

最近准备研究以下滤波器。还是从xilinx的官方IP出发,来学习以下这部分。

使用matlab直观的感受以下。输入信号为5khz,和10mhz正弦波叠加。

设置FIR滤波器参数。采样率为50mhz,通带起始频率为100KHz,阻带起始频率为1MHz。

Xilinx的FIR滤波器IP的设计与仿真_第1张图片

使用matlab打开滤波器设计小工具。产生COE文件。

直接输入filterDesigner。

打开后的界面如下图所示。

Xilinx的FIR滤波器IP的设计与仿真_第2张图片

我们按照设计参数对滤波器进行设置。

选择响应类型为低通。选择为FIR滤波器。采样率为50mhz,通带起始频率为100KHz,阻带起始频率为1MHz。设置好后选择设置量化参数。

Xilinx的FIR滤波器IP的设计与仿真_第3张图片

滤波器算法选择定点。分子字长选择16位。设置完成后点击应用。

Xilinx的FIR滤波器IP的设计与仿真_第4张图片

选择目标。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, 1000000];  % 截止频率

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接口。

Xilinx的FIR滤波器IP的设计与仿真_第5张图片

接口非常的简单。只需要输入valid核数据即可。输出端有valid和数据有效。

此IP核的主界面。

Xilinx的FIR滤波器IP的设计与仿真_第6张图片

在左侧部分分别是,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

我们选择为单速率。

下面的速率变化类型和插值速率抽值速率。分别对应于不同类型的滤波器设置。

下面是通道规范页。

Xilinx的FIR滤波器IP的设计与仿真_第7张图片

Channel Sequence支持基本的和高级的。我们选择基本的即可。

Number of Channels通道数我们选择一通道。

下面的Select Sequence和Sequence ID List在高级模式中使用。

Select format选择格式。

Sample Period采样周期。

Input Sampling Frequency采样频率。跟你设置的采样频率一致。

Clock Frequency时钟频率。

Xilinx的FIR滤波器IP的设计与仿真_第8张图片

Coefficient Type系数数据可以指定为有符号或无符号。

Quantization量化方式指定为整数。

Coefficient Width系数位宽,这里选择为16位模式。选择后在matlab中生成coe文件时选择一致。

Coefficient Structure系数结构:支持五种系数结构:非对称、对称、负对称、半带和希尔伯特。

数据路径选择。

同样的,选择输入数类型,数据位宽。这里选择后需要在模拟产生输入数据时,产生一致。

Output Rounding Mode输出数据的精度。默认为全精度。后面的选择可以选择输出数据位宽。

详细页

Xilinx的FIR滤波器IP的设计与仿真_第9张图片

Goal优化选项。使用最下面积最快速度和custom定制。

Select Optimization和List选择分别定制优化。

下面的Memory Options就是选择缓存的类型。这里可以根据你的需求自己选择或者自动。

DSP Slice Column Options:DSP选择。

Multi-column Support可以选择为自动和定制。

Interface Tab接口页。

Xilinx的FIR滤波器IP的设计与仿真_第10张图片

Data Channel Options选择AXI接口相关的参数。

TLAST指示AXI需要支持TLAST位不。以及是否使用tuser,tready等。

Configuration Channel Options

CONFIG通道用于选择活动的滤波器系数集。该通道还用于应用重新加载的滤波器系数。

Reload Channel Options和重加载相关。

Control Signals控制信号。选择复位时钟等等。

Xilinx的FIR滤波器IP的设计与仿真_第11张图片

总结界面。

我们在顶层例化该IP核。

下面我们对该IP核进行仿真。

下面分别是例化代码和仿真tb。

// *********************************************************************************/
// Project Name :
// Author       : i_huyi
// Email        : [email protected]
// 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滤波器的作用下只保留了低频部分。

Xilinx的FIR滤波器IP的设计与仿真_第12张图片

今天的FIR滤波器就学习到这里。

你可能感兴趣的:(fpga开发,matlab)