VIVADO中FFT核的使用(FPGA计算FFT和IFFT)

这篇具有很好参考价值的文章主要介绍了VIVADO中FFT核的使用(FPGA计算FFT和IFFT)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

         关于这方面的内容,有些文章已经写的很好很详细了。不过我在使用的过程中,还是踩了一些坑,我在这里详细的介绍了IP核每一个设置的作用,然后写了个fft计算和ifft计算的环路的测试程序。应该可以帮大家学会使用fft的同时,也对它有个较为全面的理解。

FPGA计算FFT和MATLAB计算FFT

        利用FPGA计算FFT和MATLAB的结果是一样的,可以获得同样的实部和虚部,还可以获得相应的频率坐标,虽然由于字节有限长的影响,精度会差些,但可以设置32位,一般也够用了。

        下面是我用matlab和fpga分布做fft和ifft得到的一些结果,原始信号是一个正弦一个余弦的单频信号,时域如下图

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

        下面是分别利用matlab和fpga做fft的结果,可以看到形状是一致的,然后最大值的数值也基本一致。具体哪个点对应哪个频率可以通过,点数(m_axis_data_tuser)/N*fs来计算,和matlab是一致的,不过fpga中没有fftshift函数可以用。

        VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

对其做ifft,结果如下:

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

         这是我画这些图对应的matlab程序,大家后面做测试的时候可以直接用,fpga部分在讲完IP核后再给出。

N=128;    %FFT的点数
f1=30;
f2=70;
fs=600;
t=(1:N)/fs;
s=cos(2*pi*f2*t)+sin(2*pi*f1*t);
% s=sin(2*pi*f1*t);
data_fft_before=floor(s*100);
figure;plot(t,data_fft_before);
title('时域原始信号')
f=linspace(0,fs,N);
fft_s=fft(data_fft_before);

figure;plot(f,real(fft_s),'r');hold;plot(f,imag(fft_s),'b')
title('频域');
legend('实部','虚部');

figure;plot(f,abs(fft_s));
title('频域幅值');
ifft_s=ifft(fft_s);

absffts=real(ifft_s);
figure;plot(absffts)
title('反傅里叶变换还原的信号');

%下面是把数据转换为16位的2进制数,如果后面选择不同位宽,把这里的16改成相应位宽就行

fp=fopen('D:\Matlab2016\bin\fft\data_fft_before.txt','w');%这里改成你自己需要的文件路径
for i=1:N
    if(data_fft_before(i)>=0)
        temp=dec2bin(data_fft_before(i),16);  %这里的16是FPGA输入数据位宽
    else
        temp=dec2bin(data_fft_before(i)+2^16,16);
    end
    for j=1:16
        fprintf(fp,'%s',temp(j));
    end
    fprintf(fp,'\r\n');
end
fclose(fp);

VIVADO的FFT核详解

        如果不想看说明,可以直接按我图上的进行配置就行。

        ip核的调出,选FFT就行。

        下面这个是LTE(Long-Term Evolution)无线通信技术的标准而设计。该IP核是为了满足LTE系统中特殊的FFT大小(如LTE信道带宽所需的FFT点数),以及URE(资源元素)或子载波间隔等LTE参数优化的,一般不需要用这个。VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

 1.第一页设置

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

(1)Number of Channels:这个参数可以选择做FFT的通道数,也就是这个IP核同时对几组数据做FFT/IFFT。我在其他地方用的时候需要做两组FFT,然后把它们相乘后做IFFT,设置通道为2,这还方便我解决数据同步的问题。

(2)Transform Length:FFT的点数,一般输入的信号长度要和这个数值相同,不足的情况下,IP核会在末尾自动补零.

(3)Target Clock Frequency (目标时钟频率):按我的理解这是IP核的工作频率,它得和下面的数据吞吐量相适应。

(4)Target Data Throughput (目标数据吞吐量):这个参数指的是FFT IP核期望处理的数据吞吐量,表明IP核应该能够每秒处理多少样本数,从而保证FFT变换的输出与输入能够按照一定速率进行,以匹配系统其他部分的处理速率,如ADC(Digital-to-Analog Converter)数据捕捉率或后续数据处理模块。(3)和(4)是给自动选择架构时计算时延做参考的,IP核不能保证达到相应的吞吐率。

(5)Architecture Choice(FPAG架构的选择):从上面到下面的架构,速度依次降低,复杂度也依次降低。选好后可以在左上角的选项卡里看到一次FFT的计算时间。VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

(6)Run time configurable Transform length(FPGA长度实时改变):选这个意味着可以在运行过程中改变FFT的计算长度。例如,你可能有一个无线通信系统,在其中需要针对不同的信道带宽进行FFT操作,这会要求FFT变换的长度根据情况进行调整。若FFT IP核支持运行时配置,那么可以在软件控制下更改其变换长度,如从1024点切换到2048点或其他任何支持的长度。

2.第二页设置

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

(1)Data Format:选择输入输出数据采样是采用定点格式(Fixed point),还是采用IEEE-754单精度(Floating point)(32位)浮点格式。当内核处于多通道配置中时,浮点格式不可用。

下面两个选项是用来解决FPGA计算的有限字符问题,指数字系统中数值的表示、操作和运算由于位宽限制导致的问题。由于FPGA中的资源有限,对于数字电路设计而言,我们不能使用无限位宽来表示一个数,而是需要根据应用需求和资源限制使用固定的位数。

(2)Scaling Opitons:

       Unscaled: 所有的整数位增长都携带到输出中,会使用更多的FPGA资源。这里我踩过一个坑:因为我的测试程序是把fft得到的数据直接给到ifft的输入端,因为选择了这个选项,数据位扩展了,所以输入的数据有问题,但这种问题vivado是不会报错的。

        Scaled:用户定义的缩放计划决定数据如何在FFT阶段之间缩放,通过寄存机s_axis_config_data进行配置。

        Block Floating-Point:内核确定需要多少缩放才能充分利用可用的动态范围,并将缩放因子报告为块指数。

(3)Rounding Model(一般如果你使用的位宽足够时也不用纠结这个)

        截断(Truncation):这是最简单的舍入模式,直接舍弃掉所有多余的LSBs,不添加任何额外的逻辑来处理这些位。这意味着数据始终向下舍入至最接近的值,可能会导致系统性偏差或误差累积,特别是在处理大量数据时这种误差的效果可能会被放大。

        收敛舍入(Convergent Rounding):收敛舍入也被称之为向偶数舍入(round-to-even)或银行家舍入法(Bankers Rounding)。这种舍入方法相对公平,并且无偏。当一个数字的小数部分正好等于0.5(即一半)时,根据数字的奇偶性来决定是向上还是向下舍入。如果该数字是奇数,那么结果将向上舍入到下一个偶数;如果是偶数,则舍入到最近的偶数。这种方法可以消除随机舍入误差累积的偏差,更平均地分布上舍和下舍的情况,并且在统计上是无偏的。

(4) Precision Options:输入数据和相位因子可以独立配置宽度从8到34位,包括。当数据格式为浮点时,输入数据宽度固定为32位,相位因子宽度可设置为24或25位,具体取决于所需的噪声性能和可用资源。

(5)Control Signals:时钟使能(aclken)和同步清除(aresetn)是可选引脚。如果两者都被选中,同步清除将覆盖时钟启用。如果不选择某个选项,则可以节省一些逻辑资源,并且可以实现更高的时钟频率。

(6)Output Ordering:这个决定数据是按什么顺序输出的,一般选natural order就行。

(7)optional output fileds :选项输出字段

      xk_index:FFT 变幻的结果索引,在m_axis_data_user中有相应的字段。

      OVFLO是变换中溢出的指示信号,对应event_fft_overflow。

(8)Throttle Schemes: 在性能和数据定时需求之间进行权衡。实时模式通常提供更小、更快的设计,但对必须提供和使用数据的时间有严格的限制。非实时模式没有这样的限制,但设计可能更大更慢。

3.第三页设置

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发

这一页是关于数据存储的设置,一般默认就行。

IP核实例化

        IP核使用的是AXI协议,它的主要特点是不管是发配置还是数据都会有个握手的过程,通过valid和ready这两个信号,其中发送方控制valid信号,接收方控制ready信号,这两个信号同时拉高时,也就是双方都准备好了,传输的内容才有效。

        实例化之前,先对IP核使用的通信协议的引脚进行介绍 ,主要是配置通道,数据输入通道,数据输出通道

.aclk(aclk),   输入时钟                                             
.aresetn(aresetn),   复位 

配置通道

Input[N:0]:  s_axis_config_tdata:

VIVADO中FFT核的使用(FPGA计算FFT和IFFT),fpga开发一般用到最低位控制。1fft   0ifft。如果我们只需要FFT就直接设置N'b1就ok。前面几位的配置可以去参考手册,是关于缩放和循环前缀的配置。

Input:  s_axis_config_tvalid:配置数据有效。这是是我们给IP核输入配置数据,没有特殊要求一直拉高就行拉高两个时钟周期之后,将端口s_axis_data_tvalid和s_axis_data_tready拉高。 
Output:  s_axis_config_tready:可以接收配置数据了。复位两个时钟周期后,该口给1输出;若干个时钟周期后,自动归零。没有特殊需要直接出去wire就好。

数据输入通道

Input:  s_axis_data_tvalid:输入数据有效。当IP核准备好接收数据,也就是s_axis_data_tready高电平后,将s_axis_data_tvalid拉高N个周期,输入N个数据进行fft;N是FFT的点数。

Output:   s_axis_data_tready:复位两个时钟周期后,该引脚;此时ip核初始化完成,可进行数据输入。 我们可以通过这个信号来拉高valid信号。

Input[M:0]:  s_axis_data_tdata:将数据输入进行FFT运算。高一半的位是虚部,低一半的位是实部。输入实数的时候可以把虚部全部置零,注意这里输入的是有符合的二进制数。

Input:  s_axis_data_tlast:输入最后一个数据时拉高,停止数据输入。TLAST是起到一个输入数据末端指示作用。但根据我的测试,就算不配置这个引脚也不影响fft的计算,看手册上说它会影响后面的event信号,也都是一些指示信号。
 

数据输出通道

Output[M1:0]:m_axis_data_tdata:高位为虚部,低位为实部。想看幅值的话,在FPGA里不好开方,我们一般看的是幅值的平方,也就是功率谱。

Output:  m_axis_data_tvalid:当ip核计算完以后会拉高,输出N个点的数据后拉低。

Output[M2:0]:m_axis_data_tuser:输出值*fs/L为对应频点。这里和matlab是一样的,第一个点也是直流的值。

Input:    m_axis_data_tready:这是告诉ip核我们准备好接收数据了,我们当然时刻准备着,一直拉高就行。

还有一些引脚相对来说没那么重要,这里就不一一介绍了。

测试程序如下,结合上面的matlab程序是可以直接用的。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/26 14:41:06
// Design Name: 
// Module Name: fft_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fft_test(

    );
    reg clk,rstn;
    reg signed [15:0]TIME_DATA[127:0];                            //存放输入数据
    wire fft_s_config_tready;

    reg signed[31:0]fft_s_data_tdata;
    reg fft_s_data_tvalid;
    wire fft_s_data_tready;
    reg fft_s_data_tlast;
    
    wire signed[31:0]fft_m_data_tdata;
    wire signed[31:0]ifft_m_data_tdata;
    wire signed[7:0]fft_m_data_tuser;
    wire fft_m_data_tvalid;
    reg fft_m_data_tready;
    wire fft_m_data_tlast;
    
    reg[10:0]  count;
    reg signed [15:0]fft_i_out;
    reg signed [15:0]fft_r_out;
    reg signed [15:0]ifft_i_out;
    reg signed [15:0]ifft_r_out;
    reg signed [31:0]fft_abs;
    reg signed [31:0]ifft_abs;


    initial begin
         clk=1'b1;
         rstn=1'b0;
         fft_m_data_tready=1'b1;
         #100;
         rstn<=1'b1;  
         $readmemb("D:/Matlab2016/bin/fft/data_fft_before.txt",TIME_DATA);

    //这里注意要改成matlab生成数据时的路径,而且注意不是\,而是/。
    end
    
    always #5 clk=~clk;

    
 //循环给fft核输入128位数据
    always @(posedge clk or negedge rstn)begin
    if(!rstn)begin
        fft_s_data_tvalid<=1'b0;
        count<=0;
       fft_s_data_tlast<=1'b0;
    end
    else if(fft_s_data_tready )begin
        if(count<8'd128)
        begin
            fft_s_data_tvalid<=1;
            fft_s_data_tdata<={16'b0,TIME_DATA[count]};      //这里虚部直接给的0
            count<=count+1;
         fft_s_data_tlast<=1'b0;

        end
        else begin
            fft_s_data_tvalid<=0;
            fft_s_data_tlast<=1'b1;
            #3000;                                          
            count<=0;
        end    
    end
    else begin
        fft_s_data_tvalid<=0;
    end
    end
    
    //高位赋值给虚部,低位赋值给实部
    always @(posedge clk)begin
        if(fft_m_data_tvalid)
        begin
            fft_i_out=fft_m_data_tdata[31:16];
            fft_r_out=fft_m_data_tdata[15:0];
        end
    end
    
   
    //求幅值,这里的值是没有开方的
    always @(posedge clk)begin
        fft_abs<=$signed(fft_i_out)*$signed(fft_i_out)+$signed(fft_r_out)*$signed(fft_r_out);
    end
   
    //实例化fft核
    xfft_0 fft0(
      .aclk                        (clk), 
      .aresetn                     (rstn),
      .s_axis_config_tdata         (8'b1),
      .s_axis_config_tvalid        (1'b1),
      .s_axis_config_tready        (fft_s_config_tready),
      
      .s_axis_data_tdata           (fft_s_data_tdata),
      .s_axis_data_tvalid          (fft_s_data_tvalid),
      .s_axis_data_tready          (fft_s_data_tready),
      .s_axis_data_tlast           (fft_s_data_tlast),
      
      .m_axis_data_tdata           (fft_m_data_tdata),
      .m_axis_data_tuser           (fft_m_data_tuser),
      .m_axis_data_tvalid          (fft_m_data_tvalid),
      .m_axis_data_tready          (fft_m_data_tready),
      .m_axis_data_tlast           (fft_m_data_tlast)
    );


    wire signed[31:0] ifft_s_data_tdata;
    assign ifft_s_data_tdata=fft_m_data_tdata;
    wire ifft_s_data_tready;
    wire ifft_s_data_tvalid;
    assign ifft_s_data_tvalid=fft_m_data_tvalid;
    wire ifft_s_data_tlast;
    assign ifft_s_data_tlast=fft_m_data_tlast;
    wire signed[7:0]ifft_m_data_tuser;
    wire ifft_m_data_tlast;
    wire ifft_m_data_tvalid;
    wire ifft_s_config_tready;
    
    //实例化ifft核,把fft核输出的数据直接作为它的输入
    xfft_0 ifft0(
      .aclk                        (clk), 
      .aresetn                     (rstn),
      .s_axis_config_tdata         (8'b0),  //因为是做iit,所以这里配置为0
      .s_axis_config_tvalid        (1'b1),  
      .s_axis_config_tready        (ifft_s_config_tready),
       .s_axis_data_tdata          (ifft_s_data_tdata),
      .s_axis_data_tvalid          (ifft_s_data_tvalid),
      .s_axis_data_tready          (ifft_s_data_tready),
      .s_axis_data_tlast           (ifft_s_data_tlast),
      
      .m_axis_data_tdata           (ifft_m_data_tdata),
      .m_axis_data_tuser           (ifft_m_data_tuser),
      .m_axis_data_tvalid          (ifft_m_data_tvalid),
      .m_axis_data_tready          (fft_m_data_tready),
      .m_axis_data_tlast           (ifft_m_data_tlast)
      
    );
    
    
     always @(posedge clk)begin
        if(ifft_m_data_tvalid)
        begin
            ifft_i_out=ifft_m_data_tdata[31:16];
            ifft_r_out=ifft_m_data_tdata[15:0];
        end
    end
    
    always @(posedge clk)begin
        ifft_abs<=$signed(ifft_i_out)*$signed(ifft_i_out)+$signed(ifft_r_out)*$signed(ifft_r_out);
    end
    
endmodule
 

写在最后

        写这篇文章还是花了挺多的时间的,希望能对大家有所帮助,有什么问题欢迎一起讨论~

奥利给

        文章来源地址https://www.toymoban.com/news/detail-801426.html

        

到了这里,关于VIVADO中FFT核的使用(FPGA计算FFT和IFFT)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Lattice FPGA 开发】IP核的调用

    本文介绍Diamond开发软件进行IP核调用与对应官方文档查找方法。 Diamond软件中,根据所选目标FPGA器件型号的不同,调用IP核的方式不同。共两种:一种是“IPexpress”;另一种是“Clarity Designer”。 IPexpress调用IP核: Clarity Designer调用IP核: 接下来分别对两种情况的调用进行说明

    2024年04月12日
    浏览(49)
  • FPGA开发 -- Vivado使用VSCode编译带图文(安装 语法校验 自动缩进 )

    目录 一 前言 Vivado 版本 Vivado 2018.03 芯片 ZYNQ-XC7Z010 VSCode 安装最新版本就行 二 Vivado 设置编译方式 Tools  Text Editor 设置 VSCode 地址 ​编辑三 VSCode 插件安装 1. Verilog HDL/SystemVerilog  打开vscode,打开拓展界面  环境变量设置 2. SystemVerilog ​编辑 设置为默认缩进软件(如图所示)

    2024年04月10日
    浏览(47)
  • FPGA 学习分享-- 04 FIFO核的使用(2)

    写在前面: 博主耗费了四天!!!完成了FIFO核的第二部分。 在这个部分,博主遇到了很多问题,对着代码不停修改,询问学长和老师,好在终于没有报错,可以向大家交作业了!当然,我会在本文详细的帮助大家学习FIFO核的代码编写,带着大家剖析每个部分,尽可能地通俗

    2024年02月03日
    浏览(42)
  • FPGA学习笔记(六): FIR IP核的使用

    1. 打开VIVADO,点击IP Catalog   2.搜索DDS,选择DDS Compiler,按照上节配置频率为3MHz和4MHz的DDS IP核。    这里注意不勾选Has Phase Out 这里注意不勾选Output TREADY     输出频率为3MHz 按照上述步骤,配置4MHz的DDS,同样不勾选Has Phase Out以及不勾选Output TREADY。 3. 点击IP Catalog,搜索mu

    2024年02月03日
    浏览(46)
  • FPGA学习笔记(五):DDS IP核的使用

     1. 打开VIVADO,点击IP Catalog    2.搜索DDS,选择DDS Compiler    3. 配置参数 (1) 设置主频频率 50MHz   (2) 选择sine,并且勾选Has Phase Out(相位输出)    (3) 勾选Output TREDAY  (4) 输入频率    (5) 同上述步骤,再加一个DDS IP核 4. 测试文件   5. 结果展示        

    2024年02月11日
    浏览(58)
  • FPGA学习笔记(二):clk IP核的使用

     1.打开VIVADO,点击IP Catalog   2. 搜索clk,选择Clocking Wizard   3. 配置参数 (1) 选择MMCM      (2) 设置主频50Mhz  (3) 设置输出的4个clk的参数,分别是50M,25M,100M,100M反相。Phase表示相位,0表示同相,180表示反相。      (3) 其他参数  4. 测试文件 其中clk_wiz的例化可参考模板。点击

    2024年02月12日
    浏览(51)
  • Xilinx 的FFT IP核使用方法(配置为FFT 、IFFT两种模式)

    Configuration 配置通道数和FFT长度 时钟频率以及数据吞吐速率 FFT的结构选择 Srteaming , 可以对数据进行流水处理 Radix-4 , 基4的迭代算法,使用资源比流水线结构多,但是转换时间长 Radix-2, Radix-2 lite 都为基2的迭代算法,Radix-2 lite的资源占用更少,但是转换时间也更长。 Run Time

    2024年02月04日
    浏览(42)
  • FPGA原理与结构——时钟IP核的使用与测试

    系列文章目录:FPGA原理与结构(0)——目录与传送门         本文介绍xilinx的时钟IP核 Clocking Wizard v6.0的具体使用与测试过程,在学习一个IP核的使用之前,首先需要对于IP核的具体参数和原理有一个基本的了解,具体可以参考: FPGA原理与结构——时钟IP核原理学习 https:/

    2024年02月09日
    浏览(38)
  • Vivado开发FPGA使用流程、教程 verilog(建立工程、编译文件到最终烧录的全流程)

    目录 一、概述 二、工程创建 三、添加设计文件并编译 四、线上仿真 五、布局布线 六、生成比特流文件 七、烧录 一、概述 vivado开发FPGA流程分为创建工程、添加设计文件、编译、线上仿真、布局布线(添加约束文件)、生成比特流文件、烧录等步骤,下文将按照这些步骤讲

    2024年02月09日
    浏览(37)
  • FPGA原理与结构(16)——时钟IP核的使用与测试

    系列文章目录:FPGA原理与结构(0)——目录与传送门         本文介绍xilinx的时钟IP核 Clocking Wizard v6.0的具体使用与测试过程,在学习一个IP核的使用之前,首先需要对于IP核的具体参数和原理有一个基本的了解,具体可以参考: FPGA原理与结构——时钟IP核原理学习 https:/

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包