精华内容
下载资源
问答
  • Xilinx FPGA FFT IP核完整的Vivado工程,用于实现FFT算法,可直接进行波形仿真,测试过没问题,另外还包含matlab仿真文件,时序波形仿真结果和matlab结果一致。
  • 快速傅里叶变换v9.0 IP核指南 ——Vivado设计套件 介绍:Xilinx FFT IP核是一种计算DFT的有效方式。 特点:•前向变换(FFT)和反向变换(IFFT)在复数空间,并且可以在运行的同时进行选择配置 •变换点数范围:N...
  • IP核手册,需要的自行下载吧。这个手册详细解释了FFT的使用方法,非常详细。
  • 详细介绍了vivado FFT 9.0版本AXIS总线 IP核的使用过程,附测试仿真代码
  • 参考这篇博客:https://blog.csdn.net/weixin_37182342/article/details/88916904,利用Vivado2017.4软件实现仿真,并在MATLAB软件中进行结果验证。
  • 此资源为VIVADO的工程文件,语言使用的是VHDL语言,其中包括FFT IP核的使用,ROM的IP核使用,时钟IP核的使用。实现了8定点的FFT功能。
  • VivadoFFT IP核的使用

    千次阅读 多人点赞 2020-05-03 17:42:37
    FFT(快速傅里叶变换)作为数字信号处理的核心算法具有重要的研究价值,可应用于傅里叶变换所能涉及的任何领域,如图像处理、音频编码、频谱分析、雷达信号脉冲压缩等数字信号处理领域。FFT的鲜明特征之一是计算离散...

    FFT(快速傅里叶变换)作为数字信号处理的核心算法具有重要的研究价值,可应用于傅里叶变换所能涉及的任何领域,如图像处理、音频编码、频谱分析、雷达信号脉冲压缩等数字信号处理领域。FFT的鲜明特征之一是计算离散傅里叶变换(DFT)的高效算法,把计算N点DFT的乘法运算量从N2次降低到N/2*log2N次。而采用FPGA实现FFT的缘由在于:FPGA具有并行处理、流水线处理、易编程、片上资源丰富等方面特点,用于实现高速、大点数的FFT优势明显。

    本设计使用的软件编程环境是Xilinx公司的Vivado 2018.3,笔者将从FFT IP核的创建,模块文件的编写,波形仿真等方面来具体讲解FFT在Xilinx FPGA上的实现。

    1.FFT IP核的创建

    (1)在Vivado软件主界面,打开IP Catalog,在搜索框内输入FFT,然后找到Digital Signal Processing->Transforms->FFTs目录下的Fast Fourier Transform,双击进入配置界面。
    在这里插入图片描述(2)进入到配置界面,左边是IP核的接口图、实现的一些细节信息和FFT的延迟,右边是Configuration、Implementation和Detailed Implementation三个标签卡。

    Vivado的FFT IP核支持多通道输入(Number of Channels)和实时更改FFT的点数(Run Time Configurable Transform Length)。Configuration标签下可设置FFT的点数(Transform Length)和工作时钟(Target Clock Frequency),以及选择一种FFT结构。FFT的结构包括流水线Streaming、基4 Burst、基2 Burst和轻量级基2 Burst,它们的计算速度和消耗的资源依次减少,可根据工程实际进行选择。
    在这里插入图片描述 Implementation标签卡下可设置FFT的数据格式为定点Fixed Point或浮点Float Point;输出截位方式选择:不截位(Unscaled),截位(Scaled),块浮点(Block Floating Point);设置输入数据的位宽和相位因子位宽。还有一些可选的附加信号,如时钟使能(ACLKEN),复位信号(ARESETn,低有效)等。“Output Ordering”用以选择FFT计算结果以自然顺序(Nature Order)或位倒序(Bit/Digit Reversed Order)输出。
    在这里插入图片描述 Detailed Implementation里可设置优化方式、存储的类型。存储类型分为两种:Block RAM(块RAM)和Distributed RAM(分布式RAM);优化方式可选择资源最优或者速度最优。
    在这里插入图片描述(3)配置完成后,可在Latency下看到计算fft所需的时间,可以以此衡量设计是否满足实时处理的要求。如不满足,可选择性能更好的FFT结构或选择可以提高运算速度的优化选项
    在这里插入图片描述

    2.模块文件的编写

    IP核工作必须要满足一定的时序要求,所以需要将数据按照一定时序送入IP核。IP核交互是用AXI-Stream接口,关于AXI-Stream接口的时序可自行查一些相关资料,这里不做详细介绍。简言之,AXI-Stream接口分为主机(master)和从机(slave),主机为发起端,从机为响应端,只有ready信号和valid信号同时为高时数据才能被有效写入或读出。举个例子,主机检测从机发出的ready信号,当为高时将valid信号拉高即可从从机读出或向从机写入数据。

    module fft_test(
    input clk,
    input rst_n,
    input  tvalid_i,
    input  [31:0] tdata_i,
    //input  fft_s_data_tlast,
    output fft_s_config_tready,
    
    output          fft_s_data_tready,
    output [47:0] fft_m_data_tdata,
    output          fft_m_data_tvalid,
    output          fft_m_data_tlast,
    output [7:0]    fft_m_data_tuser,
    output          fft_event_frame_started,
    output          fft_event_tlast_unexpected,
    output          fft_event_tlast_missing,
    output          fft_event_status_channel_halt,
    output          fft_event_data_in_channel_halt,
    output          fft_event_data_out_channel_halt
    );
    
    reg  fft_s_data_tvalid=1'b0;
    reg  [31:0] fft_s_data_tdata=32'd0;
    reg  fft_s_data_tlast=1'b0;
    reg[7:0]  count=8'd0;
    
    always @(posedge  clk)  begin
      if(!rst_n) begin
        fft_s_data_tvalid<=1'b0;
        fft_s_data_tdata<=32'd0;
        fft_s_data_tlast<=1'b0;
        count<=8'd0;
      end
      else if (tvalid_i && fft_s_data_tready) begin
        if(count==127)begin
           fft_s_data_tvalid<=1'b1;
    	   fft_s_data_tlast<=1'b1;
    	   fft_s_data_tdata<=tdata_i;
           count<=0;	 
    	 end
         else begin
           fft_s_data_tvalid=1'b1;
           count<=count+1;
    	   fft_s_data_tlast<=1'b0;
    	   fft_s_data_tdata<=tdata_i;
         end
      end
      else begin
        fft_s_data_tvalid<=1'b0;
    	fft_s_data_tlast<=1'b0;
    	fft_s_data_tdata<=fft_s_data_tdata;
      end
    end
    
      xfft_0 u_fft(
        .aclk(clk),                                                // input wire aclk
        .aresetn(rst_n),                                           // input wire aresetn
        .s_axis_config_tdata(8'd1),                                // input wire [7 : 0] s_axis_config_tdata
        .s_axis_config_tvalid(1'b1),                               // input wire s_axis_config_tvalid
        .s_axis_config_tready(fft_s_config_tready),                // output wire s_axis_config_tready
        .s_axis_data_tdata(fft_s_data_tdata),                      // input wire [31 : 0] s_axis_data_tdata
        .s_axis_data_tvalid(fft_s_data_tvalid),                    // input wire s_axis_data_tvalid
        .s_axis_data_tready(fft_s_data_tready),                    // output wire s_axis_data_tready
        .s_axis_data_tlast(fft_s_data_tlast),                      // input wire s_axis_data_tlast
        .m_axis_data_tdata(fft_m_data_tdata),                      // output wire [47 : 0] m_axis_data_tdata
        .m_axis_data_tuser(fft_m_data_tuser),                      // output wire [7 : 0] m_axis_data_tuser
        .m_axis_data_tvalid(fft_m_data_tvalid),                    // output wire m_axis_data_tvalid
        .m_axis_data_tready(1'b1),                                 // input wire m_axis_data_tready
        .m_axis_data_tlast(fft_m_data_tlast),                      // output wire m_axis_data_tlast
        .event_frame_started(fft_event_frame_started),                  // output wire event_frame_started
        .event_tlast_unexpected(fft_event_tlast_unexpected),            // output wire event_tlast_unexpected
        .event_tlast_missing(fft_event_tlast_missing),                  // output wire event_tlast_missing
        .event_status_channel_halt(fft_event_status_channel_halt),      // output wire event_status_channel_halt
        .event_data_in_channel_halt(fft_event_data_in_channel_halt),    // output wire event_data_in_channel_halt
        .event_data_out_channel_halt(fft_event_data_out_channel_halt)   // output wire event_data_out_channel_halt
      );
      
    
    endmodule
    

    3.功能仿真

    模块编写完成后,需要通过功能仿真来验证我们设计逻辑的正确性。进行仿真之前,我们需要编写仿真测试文件(testbench)。

    module testbench;
    
    reg  clk;
    reg  rst_n;
    reg [15:0] dati_in;
    reg [15:0] datq_in;
    reg [23:0]  dati_out;
    reg [23:0]  datq_out;
    reg [15:0]   dataI [127:0];
    reg [47:0]  fft_abs;
    
    reg  fft_s_data_tvalid;
    wire  [31:0] fft_s_data_tdata;
    //reg  fft_s_data_tlast;
    wire fft_s_config_tready;
    wire          fft_s_data_tready;
    wire [47:0] fft_m_data_tdata;
    wire          fft_m_data_tvalid;
    wire          fft_m_data_tlast;
    wire [7:0]    fft_m_data_tuser;
    wire          fft_event_frame_started;
    wire          fft_event_tlast_unexpected;
    wire          fft_event_tlast_missing;
    wire          fft_event_status_channel_halt;
    wire          fft_event_data_in_channel_halt;
    wire          fft_event_data_out_channel_halt;
    
    initial  begin
    clk=1;
    rst_n=0;
    //fft_s_data_tlast=1'b0;
    fft_s_data_tvalid=1'b0;
    dati_in=0;
    datq_in=0;
    dati_out=0;
    datq_out=0;
    fft_abs=0;
    
    $readmemb("C:/Users/radar/Desktop/Science/FPGA/FFT/y1.txt",dataI);
    #100
    rst_n=1;
    end
    
    always #5  clk=~clk;
    reg[7:0]  count=0;
    
    always @(posedge  clk)  begin
       if (fft_s_data_tready) begin
         if(count==128) begin
           fft_s_data_tvalid=1'b0;
    	   	   //fft_s_data_tlast=1'b0;
    	   #10000
           count=0;
         end
    	 else if(count==127)begin
           dati_in<= dataI[count];
           datq_in<=16'd0;
           fft_s_data_tvalid<=1'b1;
    	   //fft_s_data_tlast<=1'b1;
           count<=count+1;	 
    	 end
         else begin
           dati_in<= dataI[count];
           datq_in<=16'd0;
           fft_s_data_tvalid=1'b1;
           count<=count+1;
    	   //fft_s_data_tlast<=1'b0;
         end
       end
    
    end
    
    assign fft_s_data_tdata = {datq_in,dati_in};
    
    fft_test u_fft_test(
    .clk(clk),
    .rst_n(rst_n),
    .tvalid_i(fft_s_data_tvalid),
    .tdata_i(fft_s_data_tdata),
    //.fft_s_data_tlast(fft_s_data_tlast),
    .fft_s_config_tready(fft_s_config_tready),
    .fft_s_data_tready(fft_s_data_tready),
    .fft_m_data_tdata(fft_m_data_tdata),
    .fft_m_data_tvalid(fft_m_data_tvalid),
    .fft_m_data_tlast(fft_m_data_tlast),
    .fft_m_data_tuser(fft_m_data_tuser),
    .fft_event_frame_started(fft_event_frame_started),
    .fft_event_tlast_unexpected(fft_event_tlast_unexpected),
    .fft_event_tlast_missing(fft_event_tlast_missing),
    .fft_event_status_channel_halt(fft_event_status_channel_halt),
    .fft_event_data_in_channel_halt(fft_event_data_in_channel_halt),
    .fft_event_data_out_channel_halt(fft_event_data_out_channel_halt)
    );
    
    always @(posedge clk) begin
      if(fft_m_data_tvalid) begin
        dati_out<=fft_m_data_tdata[23:0];
        datq_out<=fft_m_data_tdata[47:24];    
      end
    end
    
    always @(posedge clk) begin
      fft_abs<=$signed(dati_out)* $signed(dati_out)+ $signed(datq_out)* $signed(datq_out);
    end
    
    endmodule
    
    

    testbench中输入的时域波形数据是我们通过matlab生成的,在matlab中我们仿真的是采样率为2kHz情况下,频率分别为50Hz和200Hz的两正弦波叠加后的信号。

    N=128;
    n=1:N;
    f0=50;
    f1=200;
    fs=2e3;
    y=sin(2*pi*f0.*n/fs)+2*sin(2*pi*f1.*n/fs);
    figure;
    plot(y);
    Y=fft(y);
    figure;
    plot(abs(Y));
    y1=y';
    q=quantizer([16 12]);
    y2=num2bin(q,y1);
    fid1=fopen('C:/Users/radar/Desktop/y1.txt','wt');
    for i=1:N
        fwrite(fid1,y2(i,:));
        fprintf(fid1,'\n');
    end
    fclose(fid1);
    

    利用modelsim进行功能仿真时我们将仿真时长设置为20us。为了直观验证fft是否正确,可将输入的时域数据的实部和做完fft后信号功率值的数据格式均设置为anolog(模拟),如下图,可以看到fft后的功率谱为两根独立的谱线,分别代表50Hz和200Hz两个频率点,和matlab仿真结果一致。
    在这里插入图片描述
    在这里插入图片描述
    对于该IP核更复杂的应用,大家可以阅读Xilinx官方提供的文档,根据自己的实际需要进行设计。

    4.拓展

    在一些FFT点数较大或多FFT计算的实时性要求较高的场合,直接计算FFT往往无法满足工程实际的要求,这时需要将数据分段做FFT,即我们所说的2D-FFT(基于二维矩阵的FFT),这方面的知识可参考我的另一篇博客https://blog.csdn.net/qq_43622265/article/details/105904570

    展开全文
  • Xilinx vivado FFT IP核v9.0官方手册 pg109
  • vivado FFT IP核中文翻译版本,是有道翻译的版本。Fast Fourier Transform v9.1
  • VIVADO FFT IP核简单使用、8点FFT的实现

    千次阅读 2020-12-03 09:31:17
    VIVADO(VHDL语言) FFT IP核简单使用、8点FFT的实现一、VIVADO FFT IP核的调用、配置和生成二、个人配置示例三、个人对IP核的使用,以及引脚含义的理解四、收获仿真 一、VIVADO FFT IP核的调用、配置和生成 点击...

    一、VIVADO FFT IP核的调用、配置和生成

    1. 点击IP Catalog查找到vivado的fft IP核Fast Fourier Transform,双击进入配置界面。
      在这里插入图片描述

    2. 界面介绍,主要分为两大块,左边区域为IP核整体信息介绍部分,右边为详细配置部分。按照自己需求进行配置后可查看左边生成的IP核信息。具体的IP核配置界面介绍和参数分析可查看以下链接中大佬们阐述的内容。
      在这里插入图片描述
      !!!!!!☟☟☟不懂必看系列☟☟☟!!!!!!
      vivado 的IFFT/FFT IP核的配置及调用
      Vivado中FFT9.1 IP核的使用(1)

    看完上面的链接后,可根据自己需求配置IP核
    这里有三个需要注意的点:
    ①:时钟要设置正确,并且仿真或者硬件输入要匹配。如果硬件输入时钟与你的FFT IP核时钟不一致,可以使用MMCM时钟IP核进行转换。仿真时也要记得给对正确的时钟。
    ②:FFT IP核的复位引脚(ARESETn)最好使用,怎么使用?–把时钟IP核输出的locked引脚赋给FFT的复位引脚,并且在locked引脚为低时给FFT IP核一系列输入引脚均赋予初值。时钟IP核locked引脚代表意义:时钟IP核输出的时钟是否稳定有效,低时不稳定,高时表明时钟IP核输出时钟稳定
    ③:FFT IP核的输出模式,依据自己需要进行选择,默认为倒序输出,一般选择为自然输出。

    二、个人配置示例

    还有什么对FFT IP核不懂的均可直接查看官方数据手册,毕竟官方的东西就是牛逼!!
    网上找不到可以进入赛灵思官网,搜索pg109。那里有你最需要的东西!!

    以我调用的FFT IP核配置供大家参考,我定义的FFT IP核时钟为10MHZ,数据通道个数为1,变换点数N=8,输入数据为16位定点可截断数据,并使用了复位引脚(ARESETn),输出模式为自然输出模式(Natural Output),以下是配置截图。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    三、个人对IP核的使用,以及引脚含义的理解

    • 首先从FFT IP核引脚分布来分析,大约可分为五大块
      ①:寄存器配置部分(S_AXIS_CONFIG):它包含三个引脚,分别为TDATA,TREADY,TVALID。配置信息包含在tdata里面,tdata的位宽以及位定义在你配置好IP核后就已经确定,查看IP核信息部分中的IP Symbol栏即可按照正确配置方式在代码中进行寄存器配置。tready,tvaild两兄弟的作用可参考上面链接中详细阐述。

    在这里插入图片描述
    ②:输入数据部分(S_AXIS_DATA):四个引脚TDATA,TREADY,TVALID,TLAST。首先说的是S_AXIS_DATA_TDATA的位宽是你配置FFT IP核时输入数据位宽的两倍,同样位定义可以在IP Symbol查看,为什么是两倍?因为FFT IP核既可以做顺序运算也可做逆运算→也就是IFFT,意思就是给你准备了虚数部分的位定义。S_AXIS_DATA_TDATA低位为实数部分,高位为虚数部分。在哪里配置?在S_AXIS_CONFIG_TDATA里面配置。TREADY,TVALID两兄弟不说了,TLAST是起到一个输入数据末端指示作用,比如你作8点FFT运算,你要给8个数据给IP核吧,在最后一个数据期间你把TLAST拉高就行了,意思是告诉IP核,这一组的8个数据都给你带过来了,这是最后一个。IP核一验算,整整齐齐8个,就不会找你麻烦了。
    ③:输出数据部分(M_AXIS_DATA):输出和输入差不多,使用时将M_AXIS_DATA_TREADY一直拉高即可。
    ④:时钟和复位(aclk/aresetn):时钟和复位正常使用,注意事项上面(一、2、②)已经阐述,遇到问题可参考。
    ⑤:事件报告部分总共七个引脚,具体含义可直接查看手册,一般高有效,主要报告芯片工作状态以及出错情况。

    在这里插入图片描述

    • FFT IP核使用说明及注意事项
      ①:**关于复位引脚的使用,建议大家都用上,保证电路稳点可靠。**如上面(一、2、②)所说,复位引脚可使用时钟IP核输出引脚locked作为复位信号,locked为低时,可以使FFT IP核复位;为高时,时钟输出稳定,并且FFT IP核也正常运行。至于赋FFT IP核输入信号的初值,也可以在locked为低时赋值,这样保证输入信号也达到一个初始化的稳定状态。
      ②:FFT IP核输入数据赋值:当IP核的S_AXIS_DATA_TREADY引脚拉高时,表示核本身已经准备好接收数据,这时,你把S_AXIS_DATA_TDATA拉高N个时钟周期来传N个数据,并同时在每个时钟里都塞入数据,到达数据输入终点时的最后一个数据传输时钟里将S_AXIS_DATA_TDATA拉高一个时钟周期,即完成数据输入。
      ③:始终均可拉高的引脚:S_AXIS_CONFIG_TVALID,S_AXIS_DATA_TREADY。别问,问就是不知道。

    四、收获仿真

    • 我的是8个点的FFT IP核,输入数据简单点,就弄了序列X=[1,2,3,4,5,6,7,8];
      matlab的fft数据如下:

    在这里插入图片描述

    • 我的仿真结果如下:
      输入为8点数据,分别为1-8,使用的是ROM IP核输出的,有关ROM IP核的使用请自行学习,也很简单哦!
      输出自然也为8点,我的FFT IP核输出的是32位数据,低16位为实部,高16位为实部,程序中我已分开输出。
      整体波形
      重点:FFT输入数据波形
      重点:FFT输入、输出数据波形
      ![重点:real_out:输出数据实部、imag_out:输出数据虚部

    五、总结

    • 关于实现代码:希望大家都能从理论上论证学习再到实操实践,自己动手远比拿着别人的结果看一看会收获得多。这里附上vivado VHDL语言的工程文件,有需要的可以下载!
      VIVADO VHDL 8点FFT的简单实现project文件
    • 此文章介绍的FFT IP核内容有限,还不够详细!帮助自己总结,也希望能稍微帮到你们一点,网上论坛和博客中均含有使用FFT IP核的类似文章,我也是一边看网上实操加上看官网提供的IP核数据手册-pg109(这玩意是最准确有效的法宝)才慢慢摸索出来的,不是很难,但也绝非容易。
    • 再强调一下,迷茫的时候大家根据需求多看数据手册,看懂了就没太大问题了。
    • 怕大家没看到,这两篇链接再放出来一下,很好的文章。
      vivado 的IFFT/FFT IP核的配置及调用
      Vivado中FFT9.1 IP核的使用(1)
    • 最后,欢迎大家指正讨论!哔哔完*&……¥撒花✿✿ヽ(°▽°)ノ✿!
    展开全文
  • 这是vivado里面付费LTE-FFT IP核的技术文档,在xilinx官网上只能下载到此IP核的简略文档,此版本是详细文档,望有购买需求或者使用需求的开发人员能看到文档之后进一步对此IP核有多了解。
  • 举个例子,我设置fft ip核点数N=1024,当我输入的数据个数小于1024和大于1024时,ip核输出的数据个数分别是多少?</p>
  • FPGA数字信号处理(九)Vivado FFT IP核实现

    万次阅读 多人点赞 2018-06-14 16:27:45
    该篇是FPGA数字信号处理的第9篇,选题为DSP系统中极其常用的FFT运算。上篇介绍了Quartus环境下FFT IP核的使用“FPGA数字信号处理(八)...本文将介绍在Vivado开发环境下使用Xilinx提供的FFT IP核进行FFT运算的设...

    该篇是FPGA数字信号处理的第9篇,选题为DSP系统中极其常用的FFT运算。上篇介绍了Quartus环境下FFT IP核的使用“FPGA数字信号处理(八)Quartus FFT IP核实现https://blog.csdn.net/fpgadesigner/article/details/80690345 ”。本文将介绍在Vivado开发环境下使用Xilinx提供的FFT IP核进行FFT运算的设计。


    IP核概述

    这里写图片描述
    Xilinx的FFT IP核属于收费IP,但是不需要像 Quartus那样通过修改license文件来破解。如果是个人学习,现在网络上流传的license破解文件在破解Vivado的同时也破解了绝大多数可以破解的IP核。只要在IP Catalog界面中Fast Fourier Transform的License状态为“Included”即可正常使用。


    IP核参数设置

    与Quartus中FFT IP核相比,Vivado的FFT IP核配置起来更复杂,功能也更强大。 打开主界面,左边是IP核的接口图(IP Symbol)、实现消耗的资源等信息(Implementation Details)和计算FFT所需的时间(Latency),右边是Configuration、Implementation和Detailed Implementation三个标签卡。

    这里写图片描述
    Vivado的FFT IP核支持多通道输入(Number of Channels)和实时更改FFT的点数(Run Time Configurable Transform Length)。Configuration标签下设置FFT的点数(Transform Length)和工作时钟(Target Clock Frequency),选择一种FFT结构,包括流水线Streaming、基4 Burst、基2 Burst和轻量级基2 Burst,计算速度和消耗的资源依次减少。
    这里写图片描述
    Implementation标签卡下设置FFT的数据格式为定点Fixed Point或浮点Float Point;设置输入数据的位宽和相位因子位宽(相当于旋转因子)。还有一些可选的附加信号。“Output Ordering”设置FFT计算结果以自然顺序(Nature Order)或位/数值反序(Bit/Digit Reversed Order)输出。
    这里写图片描述
    Detailed Implementation这个Tab中设置优化方式、存储的类型、是否使用DSP单元等与综合、实现有关的信息,比如可以选择复数乘法器和蝶形运算单元的实现结构。

    设置完成后,系统会在Latency中显示出计算FFT所需的时间,如下图所示:
    这里写图片描述
    可以据此衡量计算速度是否满足设计需求,如不满足可以使用更好性能的FFT结构或选择可以提高计算速度的优化选项,消耗更多的资源来缩短计算周期。


    FPGA设计

    IP核的接口在Verilog HDL中进行设计时,一定要参考官方文档中给出的时序图。在IP核的配置界面点击“documentation”,可以找到IP核的user guide。 也可以在Xilinx官网或DocNav工具中搜索pg109,查阅FFT IP核的说明。Burst模式、自然顺序输出的时序图如下:
    这里写图片描述
    驱动接口时序的Verilog HDL示例代码如下所示:

    `timescale 1ns / 1ps
    //--------------------------------------------------------
    //  使用Xilinx FFT IP核完成FFT运算
    //--------------------------------------------------------
    module Xilinx_FFT_Guide_liuqi(      
    
            input aclk,
            input aresetn,
    
            input [11:0]    input_data_ch1,
            output [23:0]   fft_real,
            output [23:0]   fft_imag,
            output reg [46:0]   amp,
            output fft_out_valid
    );
        reg [11:0] input_data_ch1_reg;    
        wire [7:0] s_axis_config_tdata;
        reg s_axis_config_tvalid;
    
        wire s_axis_data_tready;
        reg [31:0] s_axis_data_tdata;
        reg s_axis_data_tvalid;
        reg s_axis_data_tlast;
    
        wire [47:0] m_axis_data_tdata;
        wire [15:0] m_axis_data_tuser;
        wire m_axis_data_tvalid;
        wire m_axis_data_tlast;
        reg [7:0]   cfg_cnt;
        reg [13:0]  sink_ctl_cnt;   
        reg [23:0]  fft_real,fft_imag; 
        reg fft_out_valid;
        wire    event_frame_started;
        wire    event_tlast_unexpected;
        wire    event_tlast_missing;
        wire    event_status_channel_halt;
        wire    event_data_in_channel_halt;
        wire    event_data_out_channel_halt;
    
        xfft_0 usr_FFT(
    
                .aclk(aclk),
                .aresetn(aresetn),
    
                .s_axis_config_tdata(s_axis_config_tdata),
                .s_axis_config_tvalid(s_axis_config_tvalid),
                .s_axis_config_tready(),
    
                .s_axis_data_tdata(s_axis_data_tdata),
                .s_axis_data_tvalid(s_axis_data_tvalid),
                .s_axis_data_tready(),
                .s_axis_data_tlast(s_axis_data_tlast),
    
                .m_axis_data_tdata(m_axis_data_tdata),
                .m_axis_data_tuser(m_axis_data_tuser),
                .m_axis_data_tvalid(m_axis_data_tvalid),
                .m_axis_data_tready(1'b1),
                .m_axis_data_tlast(m_axis_data_tlast),
    
                .event_frame_started(event_frame_started),
                .event_tlast_unexpected(event_tlast_unexpected),
                .event_tlast_missing(event_tlast_missing),
                .event_status_channel_halt(event_status_channel_halt),
                .event_data_in_channel_halt(event_data_in_channel_halt),
                .event_data_out_channel_halt(event_data_out_channel_halt)
        );   
    
    //fft core config
        always@(posedge aclk or negedge aresetn)
        begin
            if(!aresetn)
                cfg_cnt <= 8'd0;
            else
            begin
                if(cfg_cnt < 8'd200)
                    cfg_cnt <= cfg_cnt + 1'b1;
                else
                    cfg_cnt <= cfg_cnt;
            end
        end
    
        always@(posedge aclk or negedge aresetn)
        begin
            if(!aresetn)
                s_axis_config_tvalid <= 1'b0;
            else
            begin
                if(cfg_cnt < 8'd200)
                    s_axis_config_tvalid <= 1'b1;
                else
                    s_axis_config_tvalid <= 1'b0;
            end
        end
    assign s_axis_config_tdata = 8'd1;
    
    /fft sink_in ctl/
        always@(posedge aclk or negedge aresetn)
        begin
            if(!aresetn)
                s_axis_data_tdata <= 32'b0;
            else
                s_axis_data_tdata <= {20'd0,input_data_ch1};
        end
    
        always@(posedge aclk or negedge aresetn)
        begin
            if(!aresetn)
                sink_ctl_cnt <= 14'd8194;
            else if(s_axis_config_tvalid)
                sink_ctl_cnt <= 14'd0;
            else if(sink_ctl_cnt == 14'd8192)
                sink_ctl_cnt <= 14'd1;
            else
                sink_ctl_cnt <= sink_ctl_cnt + 1'b1;
        end 
    
        //s_axis_data_tvalid
        always@(posedge aclk or negedge aresetn)
        begin
            if(!aresetn)
                s_axis_data_tvalid <= 1'b0;
            else if(sink_ctl_cnt < 14'd1)
                s_axis_data_tvalid <= 1'b0;
            else if(sink_ctl_cnt < 14'd2049)
                s_axis_data_tvalid <= 1'b1;
            else
                s_axis_data_tvalid <= 1'b0;
        end
    
        //s_axis_data_tlast
        always@(posedge aclk or negedge aresetn)
            begin
            if(!aresetn)
                s_axis_data_tlast <= 1'b0;
            else
            begin
                if(sink_ctl_cnt == 14'd2048)
                    s_axis_data_tlast <= 1'b1;
                else
                    s_axis_data_tlast <= 1'b0;
            end
        end
    /fft sink_in ctl/    
        always@(posedge aclk)
        begin
            fft_real <= m_axis_data_tdata[23:0];
        end
    
        always@(posedge aclk)
        begin
            fft_imag <= m_axis_data_tdata[47:24];
        end
    
        always@(posedge aclk)
        begin
            fft_out_valid <= m_axis_data_tvalid;
        end
    
        /********** 计算频谱的幅值信号 **********/
    
        wire signed [45:0] xkre_square, xkim_square;
        assign xkre_square = fft_real * fft_real;
        assign xkim_square = fft_imag * fft_imag;
    
        always @(posedge aclk)
          amp <= xkre_square + xkim_square;
    
    endmodule

    注意FFT计算结果输出的实部和虚部供用m_axis_data_tdata数据总线,因此在代码中需要截位分别得到实部和虚部。FFT计算结果的分析可以参考“FPGA数字信号处理(八)Quartus FFT IP核实现https://blog.csdn.net/fpgadesigner/article/details/80690345 ”中的内容。


    仿真与工程下载

    系统时钟(即FFT计算时钟)为50MHz,因此频谱范围为0~25MHz。使用MATLAB生成2MHz与15MHz的正弦波信号,分别写入txt文件。编写Testbench分别读取两个txt文件对两个单频信号做FFT分析,文件操作方法参考“Testbench编写指南(一)文件的读写操作”https://blog.csdn.net/fpgadesigner/article/details/80470972

    首先仿真对2MHz信号的FFT分析。根据上文Latency中的估计,计算时间需要145μs,因此仿真需要运行到大约150μs以上。结果如下:
    这里写图片描述
    整个频谱的持续时间恰好是out_valid信号保持高电平的时间,很明显可以看到2MHz信号在频谱中对应的一个频率点。将txt文件替换为15MHz的信号,结果如下:
    这里写图片描述
    观察到15Mhz信号的频谱峰值位置明显比2MHz频率靠中,符合事实。

    完整的Vivado工程(含testbench仿真)可以在这里下载:https://download.csdn.net/download/fpgadesigner/10478838

    展开全文
  • Vivado Xilinx FFT IP核v9.0 使用详解(附仿真实例)

    千次阅读 多人点赞 2021-01-16 00:34:16
    Vivado Xilinx FFT IP核v9.0 使用详解(附仿真实例) 前几天我导让我研究研究在FPGA上做FFT,作为一个迈进FPGA大门的小白,摸索之旅相当艰难~,现把学习FFT IP核的过程记录下来,为各位同胞提供参考。 一 傅里叶变换...

    Vivado Xilinx FFT IP核v9.0 使用详解(附仿真实例)

    前几天我导让我研究研究在FPGA上做FFT,作为一个迈进FPGA大门的小白,摸索之旅相当艰难~,现把学习FFT IP核的过程记录下来,为各位同胞提供参考。

    一 傅里叶变换FFT

    想必大家对傅里叶老人家都不陌生了,网上也有这方面的很多资料。通过FFT将时域信号转换到频域,从而对一些在时域上难以分析的信号在频域上进行处理。在这里,我们需要注意采样频率、FFT采样点数这两个参数:

    1. 根据奈奎斯特采样定理,采样频率需大于信号频率的两倍;
    2. FFT采样点数,代表对信号在频域的采样数;

    采样频率Fs和采样点数N决定了信号的频域分辨力,即分辨力=Fs/N,即N越大,频域分辨力越好,反之频域分辨力越差。

    二 Xilinx FFT v9.0

    1.输入输出端口

    在这里插入图iii描述
    如上图所示,左侧的端口均为输入端口,右侧端口均为输出端口,其中,S_AXIS_DATA为输入数据端口我们要进行FFT的数据需要通过这根线输入给IP核S_AXIS_CONFIG为输入配置端口,这个信号包含了对数据进行FFT还是IFFT、缩放因子、FFT变换点数等信息;FFT变换后的数据从M_AXIS_DATA端口输出。这些端口的具体功能可以参见pg109手册。

    2.Vivado中IP核的配置

    打开Vivado软件,我的版本是2018.04
    在这里插入图片描述
    找到FFT IP核后,双击,弹出如下对话框:
    在这里插入图片描述
    第二页implementation
    在这里插入图片描述
    第三页
    在这里插入图片描述
    配置完成后,我们可以点击左侧的implementation detail选项卡,看到IP核的具体信息:
    在这里插入图片描述
    其中包含了S_AXIS_DATA_TDATA、S_AXIS_CONFIG_TDATA以及M_AXIS_DATA_TDATA的数据格式,我们需要加以关注:

    1. S_AXIS_DATA_TDATA:共32位,其中低16位为输入数据的实部,高16位为输入数据的虚部(但在实际使用中,高16位才是实部,低16位是虚部,如果有大神明白是咋回事儿,欢迎留言)
    2. S_AXIS_CONFIG_TDATA:最低位第0位,决定对数据进行FFT还是IFFT,置1时FFT,清零时IIFT,由于要进行补零操作,因此在最终写入S_AXIS_CONFIG_TDATA时,除了最低位以外,还要再补七个零,补到8位
    3. M_AXIS_DATA_TDATA:48位数据输出,低24位为实部,高24位为虚部

    3.软件仿真

    IP核配置完成后,下面开始编写我们的TestBench文件。
    我们通过matlab对F(t) = 200 + 100cos(2pi10t) + 100cos(2pi30t) 这个信号以Fs = 100HZ进行采样,采样点数N = 128,采样完成后,将数据转换为16位二进制,并存入txt文件中。matlab程序如下:

    clear
    
    Fs=100;                         %采样率1ns一个点
    %t=0:1/Fs:63/Fs;                 %数据时长:64个采样周期
    N = 128;
    n = 1:N;
    t = n/Fs;
    % 生成测试信号
    f1 = 10;                   %
    f2 = 30;                     %
    s1 = cos(2*pi*f1*t);    
    s2 = cos(2*pi*f2*t);
    signalN = 2 + s1 + s2 ;
    data_before_fft = 100*signalN;  %系数放大100倍
    
    
    fp = fopen('D:\Zynq_Core\data_before_fft.txt','w');
    for i = 1:N
       if(data_before_fft(i)>=0)
           temp= dec2bin(data_before_fft(i),16);
       else
           temp= dec2bin(data_before_fft(i)+2^16+1, 16);
       end
        for j=1:16
            fprintf(fp,'%s',temp(j));
        end
        fprintf(fp,'\r\n');
    end
    fclose(fp);
    
    y = fft(data_before_fft,N);
    y = abs(y);
    f = n*Fs/N;
    plot(f,y);
    
    

    程序执行结束后,我们可以看到在指定目录下新建了一个txt文件,内容如下所示:
    在这里插入图片描述
    由于我们在配置IP核的时候配置了数据位宽为16位,因此我们存入的数据也要设置为16位的。采样点数N=128,因此一共有128个这样的数据。

    得到采样数据后,在vivado中新建一个sim文件:
    在这里插入图片描述

    TB文件代码如下:

    `timescale 1ns / 1ps
    module FFT_test2();
    
    reg clk;
    reg rst_n;
    reg signed [15:0] Time_data_I[127:0];
    reg data_finish_flag;
    
    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 [47:0] fft_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;
    
    wire          fft_event_frame_started;
    wire          fft_event_tlast_unexpected;
    wire          fft_event_tlast_missing;
    wire          fft_event_status_channel_halt;
    wire          fft_event_data_in_channel_halt;
    wire          fft_event_data_out_channel_halt;
    
    reg [7:0]     count;
    
    reg signed [23:0] fft_i_out;
    reg signed [23:0] fft_q_out;
    reg signed [47:0] fft_abs;
    
    initial begin
        clk = 1'b1;
        rst_n = 1'b0;
        fft_m_data_tready = 1'b1;
        $readmemb("D:/Zynq_Core/data_before_fft.txt",Time_data_I);
    end
    
    always #5 clk = ~clk;
    
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            fft_s_data_tvalid <= 1'b0;
            fft_s_data_tdata  <= 32'd0;
            fft_s_data_tlast  <= 1'b0;
            data_finish_flag  <= 1'b0;
            count <= 8'd0;
            rst_n = 1'b1;
        end
        else if (fft_s_data_tready) begin 
            if(count == 8'd127) begin
                fft_s_data_tvalid <= 1'b1;
                fft_s_data_tlast  <= 1'b1;
                fft_s_data_tdata  <= {Time_data_I[count],16'd0};
                count <= 8'd0;
                data_finish_flag <= 1'b1;
            end
            else begin
                fft_s_data_tvalid <= 1'b1;
                fft_s_data_tlast  <= 1'b0;
                fft_s_data_tdata  <= {Time_data_I[count],16'd0};   
                count <= count + 1'b1;
            end
        end
        else begin
            fft_s_data_tvalid <= 1'b0;
            fft_s_data_tlast  <= 1'b0;
            fft_s_data_tdata <= fft_s_data_tdata;
        end
    end
    
    always @ (posedge clk) begin
        if(fft_m_data_tvalid) begin
            fft_i_out <= fft_m_data_tdata[23:0];
            fft_q_out <= fft_m_data_tdata[47:24];
        end
    end
    
    always @ (posedge clk) begin
        fft_abs <= $signed(fft_i_out)* $signed(fft_i_out)+ $signed(fft_q_out)* $signed(fft_q_out);
    end
    
    
    //fft ip核例化
    xfft_0 u_fft(
        .aclk(clk),                                                // 时钟信号(input)
        .aresetn(rst_n),                                           // 复位信号,低有效(input)
        .s_axis_config_tdata(8'd1),                                // ip核设置参数内容,为1时做FFT运算,为0时做IFFT运算(input)
        .s_axis_config_tvalid(1'b1),                               // ip核配置输入有效,可直接设置为1(input)
        .s_axis_config_tready(fft_s_config_tready),                // output wire s_axis_config_tready
        //作为接收时域数据时是从设备
        .s_axis_data_tdata(fft_s_data_tdata),                      // 把时域信号往FFT IP核传输的数据通道,[31:16]为虚部,[15:0]为实部(input,主->从)
        .s_axis_data_tvalid(fft_s_data_tvalid),                    // 表示主设备正在驱动一个有效的传输(input,主->从)
        .s_axis_data_tready(fft_s_data_tready),                    // 表示从设备已经准备好接收一次数据传输(output,从->主),当tvalid和tready同时为高时,启动数据传输
        .s_axis_data_tlast(fft_s_data_tlast),                      // 主设备向从设备发送传输结束信号(input,主->从,拉高为结束)
        //作为发送频谱数据时是主设备
        .m_axis_data_tdata(fft_m_data_tdata),                      // FFT输出的频谱数据,[47:24]对应的是虚部数据,[23:0]对应的是实部数据(output,主->从)。
        .m_axis_data_tuser(fft_m_data_tuser),                      // 输出频谱的索引(output,主->从),该值*fs/N即为对应频点;
        .m_axis_data_tvalid(fft_m_data_tvalid),                    // 表示主设备正在驱动一个有效的传输(output,主->从)
        .m_axis_data_tready(fft_m_data_tready),                    // 表示从设备已经准备好接收一次数据传输(input,从->主),当tvalid和tready同时为高时,启动数据传输
        .m_axis_data_tlast(fft_m_data_tlast),                      // 主设备向从设备发送传输结束信号(output,主->从,拉高为结束)
        //其他输出数据
        .event_frame_started(fft_event_frame_started),                  // output wire event_frame_started
        .event_tlast_unexpected(fft_event_tlast_unexpected),            // output wire event_tlast_unexpected
        .event_tlast_missing(fft_event_tlast_missing),                  // output wire event_tlast_missing
        .event_status_channel_halt(fft_event_status_channel_halt),      // output wire event_status_channel_halt
        .event_data_in_channel_halt(fft_event_data_in_channel_halt),    // output wire event_data_in_channel_halt
        .event_data_out_channel_halt(fft_event_data_out_channel_halt)   // output wire event_data_out_channel_halt
      );
        
        
    endmodule
    

    由于我们设置程序一直保持正向FFT模式,因此将s_axis_config_tdata始终写入1即可。

    同时我们还要注意文件读入函数readmemb(),这一函数是以二进制格式读入数据,而readmemh() 是以16进制读入数据,大家不要搞混了。我就是用readmemh() 弄了半天,结果数据一个也不对,找了半天才发现那是h不是b…[cry][cry][cry]

    4.仿真分析

    运行仿真后,时序图如下所示:
    在这里插入图片描述
    如图所示,首先判断fft_s_data_tready信号是否为高电平,即IP核是否准备好了接收数据,当检测到该信号有效后,将fft_s_data_tvalid信号拉高,准备向IP核写入数据,并开启count计数。在fft_s_data_tvalid有效期间内,读出指定txt文件中的数据,并在低16位进行补零处理后,按顺序写入到fft_s_data_tdata信号线中。当count计数到127,即最后一个数据时,将fft_s_data_tlast信号拉高,代表数据写入完成。

    可以看到,在数据写入完成后(fft_s_data_tlast出现脉冲),fft_s_data_tready变为低电平,则代表IP核此时变为忙状态,不能再继续写入数据。
    在这里插入图片描述
    延时一段时间后,fft_m_data_tvalid变为高电平,代表fft_m_data_tdata中将输出有效数据,即128点FFT的计算结果。结果的实部和虚部分别见上图中的fft_q_out和fft_i_out。将IP核的计算结果与matlab的计算结果相对比,发现实部数据基本正确,虚部数据略有偏差。
    在这里插入图片描述
    通过对IP核的计算结果进行分析,发现数据在第0个、第14个和34个数据的位置出现峰值,对应0HZ、10HZ和30HZ,正代表着原始信号中的这三个频率分量,因此FFT IP核计算结果正确无误。

    同时,从仿真中还可以看出,当FFT计算结果输出完成后,信号fft_m_data_tlast变为高电平,代表数据输出结束,并在延时一小段时间后,fft_s_data_tready重新变为低电平,代表IP核重新进入到空闲状态。可以进行对IP核下一组数据的输入。

    以上就是FFT IP核仿真调试的全部内容,其他复杂的功能在使用到后再进行后续更新~~~



    2021/3/23 更新

    有人问用文中的代码跑出来的结果怎么全是XXXX,在这里大家一定要注意,在“3.软件仿真”中,分别有matlab生成仿真数据和编写vivado TestBench文件两部分内容,在TB代码中读入的仿真数据文件路径一定要与matlab生成仿真数据文件的路径相同,也就是要确定你的数据文件在哪个位置,然后在TB文件代码的readmemb语句中按照那个路径读入数据,不然路径都不对,根本没读到数据,肯定出不来正确的结果啦

    展开全文
  • Vivado FFT IP核配置:从入门到熟练

    千次阅读 2020-11-17 09:37:57
    前言 fpga初学者,在vivado软件上调用fft IP核时,一头雾水。参考了部分博文,总结出FFT调用的流程,并更新了部分端口的说明 (https://www.cnblogs.com/lgy-gdeu/p/11590626.html 中有两个端口说明可能有误解)。 ...
  • 基于vivado 2015.4 的FFT IP核仿真

    千次阅读 2020-08-04 16:38:07
    小弟最近毕业论文在做OFDM方面的研究,用到了vivado中的FFT IP核,发现网上现有的也只是介绍了一些接口,而且大部分给的代码跑不出来,所以对自己使用该IP核做一些总结,并附上代码和matlab的仿真结果,欢迎大家批评...
  • 在这里我将使用vivado软件实例化一个长度为64的快速傅里叶变换IP核,并将运算结果和matlab中的运算结果相比较。 二、使用步骤 1.新建工程 新建工程没啥好说的,如果有开发板,那就按照对应的型号芯片来创建,...
  • Xilinx vivado FFT IP v9.0 详解

    万次阅读 多人点赞 2018-08-16 15:36:29
    Xilinx FFT IP v9.0 在线设置变换长度详解 IP介绍 FFT IP核支持三种数据类型: 1. 定点全精度 1. 定点缩减位宽 1. 块浮点 有四种可选择的FFT运算方式: 1. PipelinedStreaming I/O 1. Radix-4Burst I/O 1...
  • 简介: 结合VIVADOFFT IP核的使用,编写Verilog 代码进行配置和相应的testbench文件的编写,并结合MATLAB软件产生测试数据并进行后续的计算结果误差分析。有详细的源代码以及注释。
  • Vivado FFT IP核实现

    2019-09-26 16:05:36
    VIVADO中建立一个FFT核,只要依下图步骤就可以开始配置一个FFT核: 需要配置的参数有三个标签页,需要一一配置 第一个标签页里主要配置通道数,点数,时钟,吞吐量,结构,以及是否可以运行时配置,需要注意的是...
  • 2、将数据存入rom ip核中 rom核的应用见:https://blog.csdn.net/qq_39005414/article/details/109552835 3、FFT ip核配置 `timescale 1ns / 1ps module rom_fft( input sys_clk_n, input sys_clk_p, input rst_n, ...
  • 【超详细】VIVADO FFT IP v9.0 进阶

    千次阅读 2020-02-27 12:27:58
    第一次用FFT IP的时候,被吓到了,用过三四次以后基本摸清了使用方法,但是也只是简单的使用,这里写个指南,希望指导小白。 FFT界面 这里以4096为例,图中红圈内可以改点数,一般我下面都是...
  • 持续一个时钟 event_fft_overflow 当变换结果溢出时,持续每个时钟,仅当使用了缩放算法时才有此端口 event_status_channel_halt 当ip核需要输出状态信息时,输出缓冲器却满了的时候,此时ip核的所有活动都会停止...
  • FFT9.1 IP核使用笔记.zip

    2020-04-21 15:57:06
    内含自己使用过程中的笔记,包含配置界面的每个选项和参数的讲解,以及ip核的每个引脚的解释。笔者是参考了官方的product guide,以及各种网络资源而总结而成,部分引用标出了原博客来源。压缩包中还有官方给出的英文...
  • vivado FFT IP模块datasheet

    2017-10-07 16:15:35
    fft技术文档;详细介绍FFT模块的端口以及一些功能等;
  • VIVADO FFT核的实现

    万次阅读 多人点赞 2018-09-04 17:57:14
    VIVADO中建立一个FFT核,只要依下图步骤就可以开始配置一个FFT核: 需要配置的参数有三个标签页,需要一一配置 第一个标签页里主要配置通道数,点数,时钟,吞吐量,结构,以及是否可以运行时配置,需要注意的...
  • VIVADO中实现FFT/IFFT

    千次阅读 热门讨论 2019-05-24 15:36:08
    例化两个FFTIP核分别用作FFT核IFFT变换 将DDS信号输入到FFT,再将FFT的信号输出到IFFT中 1. dds生乘固定频率正弦信号 调用DDS IP核,进行如下设置,生成10MHz正弦信号: 2.调用FFT IP核 进行如下设置 3....
  • Xilinx公司在Vivado开发工具中提供了FFT/IFFT的 IP核,供开发人员很方便的调用和使用,因此,本文主要对Vivado中的Xilinx FFT/IFFT IP核使用流程展开详细介绍。 1、FFT/IFFT IP核的创建 在使用FFT/IFFT IP核之前...
  • IP核主要用于完成FFT或者IFFT等功能,接口信号也分为几个类型:IP核基本信号(配置信号、时钟信号等)、接收信号部分(AXI从端口,用于接收需要处理的信号)、发送信号部分(AXI主端口,用于发送FFT/IFFT后的结果)...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 341
精华内容 136
关键字:

fftipvivado