当前位置:网站首页>Vivado FFT IP的使用说明

Vivado FFT IP的使用说明

2022-06-27 20:50:00 ML__LM

1 IP说明

1.1 Configuration Channel

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

1.2 管脚描述

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

2 例化IP

2.1 DDS IP

输出频率字的计算公式:deta_theta=f_out*(2^B)/f_clk
B:相位位宽,这里为32
/f_clk :125M。注意,例化DDS IP时,输入信号的频率也必须为125M。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 FFT IP

第一页配置(Configuration):
(1)Number of Channels:多通道输入。FFT转换通道的个数
(2)Transform Length :FFT的点数
(3)Architecture Configuration:
Target Clock Frequency:工作时钟;
Architecture choice:选择一种FFT结构。包括自动匹配、流水线Streaming、基4 Burst、基2 Burst和轻量级基2 Burst,它们的计算速度和消耗的资源依次减少,可根据工程实际进行选择。
(4)Run Time Configurable Transform Length:实时更改FFT的点数。

在这里插入图片描述
第二页配置(Implementation):
(1)Data Format:设置FFT的数据格式为定点Fixed Point或浮点Float Point;
(2)Scaling Option:输出截位方式选择。不截位(Unscaled),截位(Scaled),块浮点(Block Floating Point);
(3)Precision Option:设置输入数据的位宽和相位因子位宽;
(4)Control Signals:时钟使能(ACLKEN),复位信号(ARESETn,低有效);
(5)Output Ordering Option:用以选择FFT计算结果以自然顺序(Nature Order)或位倒序(Bit/Digit Reversed Order)输出。

在这里插入图片描述
第三页配置(Detailed Implementation):
可设置优化方式、存储的类型。
存储类型分为两种:Block RAM(块RAM)和Distributed RAM(分布式RAM)
优化方式可选择资源最优或者速度最优。

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

3 程序

3.1 程序结构

在这里插入图片描述

3.2 top模块

`timescale 1ns / 1ps

//模块功能:1024个点的FFT变换,并得到幅度谱
module top(
    input           clk              ,
    input           rst_n            
    

    );



 //----------2、根据频率字,利用DDS生成参考信号{RtI,RtQ}
wire [31:0]  m_axis_data_PINC;
dds_sin Inst_dds_sin (
  .aclk(clk),                                  // input wire aclk
  .s_axis_config_tvalid(1'b1),  // input wire s_axis_config_tvalid
  .s_axis_config_tdata(32'd343597384),    // 频率字 对应频率10M
 
 
  .m_axis_data_tvalid(),       // output wire m_axis_data_tvalid
  .m_axis_data_tdata(m_axis_data_PINC),        // output wire [31 : 0] m_axis_data_tdata
  .m_axis_phase_tvalid(),    // output wire m_axis_phase_tvalid
  .m_axis_phase_tdata()      // output wire [31 : 0] m_axis_phase_tdata
);
 
wire [15:0]    RtI ;//参考信号的实部 与频率字相对应
wire [15:0]    RtQ ;
assign RtI=m_axis_data_PINC[31:16];  
assign RtQ=m_axis_data_PINC[15:0];    
    
wire [31:0]   tdata_i   ; 
assign   tdata_i={
    16'd0,RtI}; 

   
//---------2、例化FFT,实现1024个点的FFT变换,并得到幅度谱
wire          fft_s_data_tready;      
wire [63:0]   fft_m_data_tdata ;
wire [63:0]   fft_abs          ;
wire          fft_abs_valid    ;
fft_test fft_test_inst(
    //input
    .clk               (clk               ),
    .rst_n             (rst_n             ),
    .tvalid_i          (1'b1              ),
    .tdata_i           (tdata_i           ),

    //output
    .fft_s_data_tready (fft_s_data_tready ),//必须有,否则第一次的数据无法进行FFT
    .fft_m_data_tdata  (fft_m_data_tdata  ),
    .fft_abs           (fft_abs           ),
    .fft_abs_valid     (fft_abs_valid     )//幅度谱结果有效
);   
 
 
 
wire [63:0]  data_max        ;
wire         DataMax_Vaild   ;
Max_Get Inst_Max_Get(
    //input
    .clk           (clk        ),
    .reset         (!rst_n        ),
    .En            (fft_abs_valid ),
    .data_in       (fft_abs      ),
     //output
    .data_max      (data_max     )  ,
    .DataMax_Vaild (DataMax_Vaild)
 );

 
 
      
endmodule




## 3.2 fft_test模块```

```cpp
// I:实部 Q:虚部
// fft_m_data_tuser) 输出频谱的索引该值* fs/N,即为输入信号的频点
//fs(65M)和N(Transform Length)的值见FFT IP 设置 


/* 3、NFFT:可选,本次设计没有使用 位宽为5 Point size of the transform,NFFT can be the size of the maximum transform or any smaller point size. For example, a 1024-point FFT can compute point sizes 1024, 512, 256, and so on. The value of NFFT is log2 (point size). 如果是2048个采样点 NFFT=log2(2048)=11=01011 The transform point size can be set through the NFFT field in the Configuration channel if the run time configurable transform length option is selected. 只有选中run time configurable transform length这个选项,NFFT才可以配置。 2、CP_LEN:(Cyclic prefix length) 可选,本次设计没有使用 位宽为log2(采样点数) The number of samples from the end of the transform that are initially output as a cyclic prefix, before the whole transform is output. CP_LEN can be any number from zero to one less than the point size. This field is only present with cyclic prefix insertion. 只有选中 cyclic prefix insertion这个选项时,CP_LEN才可以配置。。 1、FWD_INV: 必须 位宽为:1 bit per FFT data channel Indicates if a forward FFT transform or an inverse FFT transform is performed. FWD_INV = 1, a forward transform is computed. FFT变换 FWD_INV = 0, an inverse transform is computed. IFFT变换 Each FFT data channel has an assigned FWD_INV field 0、SCALE_SCH: 可选,本次设计没有使用 for Pipelined Streaming I/O and Radix-4 Burst I/O architectures,位宽为:2*ceil(NFFT/2) for Radix-2, Burst I/O and Radix-2 Lite Burst I/O architectures 位宽为:2*NFFT This field is only available with scaled arithmetic (not unscaled, block floating-point or singleprecision floating-point). 只有选中scalingOption的 scaled 这个选项时,SCALE_SCH才可以配置。 All fields with padding should be extended to the next 8-bit boundary if they do not already finish on an 8-bit boundary. */


//模块功能:1024个点的FFT变换,并得到幅度谱
module fft_test(
        input               clk               ,// 时钟信号
        input               rst_n             ,// 复位信号
        input               tvalid_i          ,//表示外界输入数据有效,此时能够给FFT IP核提供数据
        input  [31:0]       tdata_i           ,//提供给FFT IP核的外界输入数据(时域信号)
      
             
        output              fft_s_data_tready ,// 表示FFT IP核准备好接受数据
        output [63:0]       fft_m_data_tdata  ,// FFT 变换后的结果(频域信号)
        output reg [63:0]   fft_abs           ,  // 幅度谱
        output              fft_abs_valid  
);



//----------FFT IP从端的输入数据和valid信号控制-----------//
// 控制什么时候给FFT IP给输入数据以及输入给FFT IP的数据是否有效
reg         fft_s_data_tvalid;
reg  [31:0] fft_s_data_tdata;
reg         fft_s_data_tlast;
reg  [10:0] count;

always @(posedge clk or negedge rst_n)  
begin
    if(!rst_n) 
        begin
            fft_s_data_tvalid<=1'b0;
            fft_s_data_tdata<=32'dx;
            fft_s_data_tlast<=1'b0;
            count<=11'd0;
        end
    else if (tvalid_i)
    //else if (tvalid_i && fft_s_data_tready) //外界输入数据有效,且FFT IP准备好接收数据,表示握手成功
        begin
            fft_s_data_tvalid<=1'b1;    //输入给FFT IP的数据有效
            fft_s_data_tdata<=tdata_i;  //给FFT IP灌数据 
            if(count==1024)  //最后一个数据
                begin            
	                fft_s_data_tlast<=1'b1;//last信号拉高
                    count<=11'd0;	       //计数器清零
	            end
            else 
                begin             
	               fft_s_data_tlast<=1'b0;//last信号拉低 
	               count<=count+1;         //计数器的值+1
                end
        end
    else //外界数据无效或者且FFT IP没有准备好接收数据,握手不成功
        begin
            fft_s_data_tvalid<=1'b0;   // FFT IP的从端数据无效
	        fft_s_data_tdata<=32'dx;   //数据保持,不给新数据
	        fft_s_data_tlast<=1'b0;
	        count<=count;
        end
end






//-----------------例化FFT IP--------------//
//wire fft_m_data_tvalid ;
wire       fft_m_data_tlast                ;
wire [15: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 ;

xfft_0 xfft_0_inst(
    //FFT的时钟、时钟使能、复位信号(注意复位信号要多给几个时钟)
    .aclk(clk),                        // input wire aclk
    .aresetn(rst_n),                   // input wire aresetn
   
    // FFT的重配置接口
    .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(),           // output wire s_axis_config_tready
    
    //FFT的数据输入接口,遵循AXI-Stream协议
    .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
  
    //FFT的数据输出接口,遵循AXI-Stream协议
    .m_axis_data_tdata(fft_m_data_tdata),     // output wire [63 : 0] m_axis_data_tdata
    .m_axis_data_tuser(fft_m_data_tuser),     // output wire [15 : 0] m_axis_data_tuser
    .m_axis_data_tvalid(fft_abs_valid),   // 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
   
   //可以输出一些FFT的错误信息,比如输入的last未知不正确或没有,数据溢出等等
    .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
  );
 
 
 
 
 //---------------得到信号的幅度谱---------------//
reg [31:0]  dati_out;
reg [31:0]  datq_out;
// I:实部 Q:虚部
always @(posedge clk) 
begin
  if(fft_abs_valid) 
      begin
          datq_out<=fft_m_data_tdata[63:32];//虚部 
          dati_out<=fft_m_data_tdata[31:0];//实部 
      end
end
always @(posedge clk) 
begin
// fft_abs<=$signed(dati_out)* $signed(dati_out)+ $signed(datq_out)* $signed(datq_out);
    fft_abs<=($signed(dati_out)* $signed(dati_out)+ $signed(datq_out)* $signed(datq_out))/1024;
end 



endmodule

3.3 Max_Get模块```

`timescale 1ns / 1ps

// 寻找寻找一串序列(1024个点)的最大值
module Max_Get(
    input               clk             ,
    input               reset           ,
    input               En              ,//寻找最大值模块开始工作的使能信号
    input [63:0]        data_in         ,// 输入数据
    
    output reg [63:0]   data_max        ,//搜索得到的最大值
    output reg          DataMax_Vaild   
 );
 
 
  
reg [63:0]   data_max_temp; //最大值寄存器 
reg [3:0]    ST_max_search;//状态机
reg [15:0]   count;//计数器
    
[email protected](posedge clk)
begin
   if(reset)
        begin
             data_max_temp<=64'd0;    
             ST_max_search<=4'd0;
             count<=16'd0;
             DataMax_Vaild<=1'b0;
        end
   else
        begin
              case(ST_max_search)
              0:
                    begin
                        if(En==1'b1)//使能有效,模块开始工作
                            begin
                                ST_max_search<=4'd1;
                            end
                       else
                            begin
                                ST_max_search<=4'd0;
                            end                             
                    end
                1:
                    begin
                        if(count<16'd1024)//还没有比较到1024个点
                            begin
                                count<=count+1'd1;
                                ST_max_search<=4'd1;//
                                if(data_in>data_max_temp)
                                    data_max_temp<=data_in;
                                else
                                    data_max_temp<=data_max_temp;
                            end
                        else//if(count==16'd1024) 
                             begin
                                count<=16'd0;
                                ST_max_search<=4'd0;                           
                                data_max<= data_max_temp;
                                data_max_temp<=64'd0;//最大值数据寄存器数据归零,避免影响下一次寻求最大值
                                DataMax_Vaild<=1'b1;
                            end                                    
                    end           
                default:         
                    ST_max_search<= 4'd0;//跳到状态0 end 
           endcase    
      end  
end      
      
     
      
endmodule

3.4 testbench

`timescale 1ns / 1ps


module sim_top;


//input
reg             clk;
wire            clk_125M;
reg             rst_n;

output
//wire fft_s_data_tready;
//wire [63:0] fft_m_data_tdata;
//wire [63:0] fft_abs ;

//-----------例化top模块----------//
top top_inst(
    //input
    .clk               (clk_125M                     ),
    .rst_n             (rst_n                   )

// //output
// .fft_s_data_tready (fft_s_data_tready ),
// .fft_m_data_tdata (fft_m_data_tdata ),
// .fft_abs (fft_abs )
    );


   initial  
    begin
        clk=0;
        rst_n=0;

    #50
        rst_n=1;
    end

always #5  clk=~clk;//10ns 100M


  clk_wiz_0 Inst_clk_wiz_0
   (
    // Clock out ports
    .clk_out1(clk_125M),     // output clk_out1 125M 
    // Status and control signals
    .reset(~rst_n), // input reset
    .locked(),       // output locked
   // Clock in ports
    .clk_in1(clk)//100M
    );      // input clk_in1



endmodule
  

4 仿真结果分析

DDS产生的信号频率为10M,T=100ns
在这里插入图片描述
FFT IP计算出来的信号频率:输出频谱的索引该值* fs/N=82*125M/1024=10.0097M.和DDS的输出信号频率一致
在这里插入图片描述

两次FFT估计出来的信号的幅度误差:(266210147231-256096801523)/256096801523=0.0395
在这里插入图片描述

原网站

版权声明
本文为[ML__LM]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_46136963/article/details/121379584