xilinix FFT IP核使用核仿真

xilinix 的IP核 FFT功能强大

IP核设置

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,计算速度和消耗的资源依次减少。我们一般选用基4 Burst,单次固定输入128个点,输入完成后,开始进行FFT运算,如果数据输入个数错误,或者没有输入完成,FFT是不会输出结果。另外,输入的数据类型为有符号数,仿真数据可以由matlab生成,matlab代码参考本人的另一篇文章 https://blog.csdn.net/baidu_25816669/article/details/119820293

Implementation标签卡下设置FFT的数据格式为定点Fixed Point或浮点Float Point;设置输入数据的位宽和相位因子位宽(相当于旋转因子)。还有一些可选的附加信号。“Output Ordering”设置FFT计算结果以自然顺序(Nature Order)或位/数值反序(Bit/Digit Reversed Order)输出。

Detailed Implementation这个Tab中设置优化方式、存储的类型、是否使用DSP单元等与综合、实现有关的信息,比如可以选择复数乘法器和蝶形运算单元的实现结构。

 在IP核右侧,如下图,可以看到设置后,占用的资源,各个接口的功能,以及延时。

这里需要注意S_AXIS_CONFIG_TDATDA,

  S_AXIS_CONFIG_TDATDA包含下图数据内容,根据IP核设置的选项,S_AXIS_CONFIG_TDATDA,的位宽核内容有所不同,下图为完整的数据内容,实线框里的内容是始终有,其他会根据IP核设置增加或减少。

 

如果在configurationaa界面设置没有勾选下Run Time ........,则S_AXIS_CONFIG_TDATDA位宽为八,内D_INV,只需要设置运算类型为FFT还是IFFT。

 如果勾选了 Run Time ........,则S_AXIS_CONFIG_TDATDA位宽为十六,在implement detial中可以看到下图的设置位宽对应内容

下图为NFFT设置内容,和运算点数有关。

 最麻烦的设置则是和是否截尾、压缩有关的设置,在implement界面选择unscaled,则不需要设置结尾,但资源占用较多,输出数据位宽大,实际工程选择scaled,此时S_AXIS_CONFIG_TDATDA在implement detial中可以看到下图,

 对于截尾压缩的设置,参考下图内容,有点复杂。

关于FFT具体配置,可以参考https://blog.csdn.net/gslscyx/article/details/107073799,介绍的很详细。

完整的仿真工程代码如下。

module FFT_TB(

    ); 
    reg clk;
    reg rst_n;
    reg signed [15:0]  Time_data_I [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 [47:0] fft_m_data_tdata;
//    wire signed [31: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 [15:0]  fft_i_out;
//    reg signed [15:0]  fft_q_out;
    reg signed [23:0]  fft_i_out;
    reg signed [23:0]  fft_q_out;
    reg signed [47:0]  fft_abs;
    integer  fid1;
    integer i;
    integer s;
    initial begin
        clk = 1'b1;
        rst_n = 1'b1;
        #5 rst_n = 1'b0;
//        #5 rst_n = 1'b1;
        fft_m_data_tready = 1'b1;
//        $readmemh("C:/Users/HP/Desktop/sin_data1.txt",Time_data_I);//无符号数导入
        fid1 = $fopen("C:/Users/HP/Desktop/sin_data.txt","r");//这里的斜杠与计算机里面的斜杠不一样
        //有符号数导入                                                   
        for(i=0;i<=127;i=i+1)
           begin
            s= $fscanf(fid1,"%d",Time_data_I[i]);
           end
        $fclose(fid1);
        #50 rst_n = 1'b1;;
    end
     
    always #5 clk = ~clk;
    reg [3:0]   state; 
    //发送时域数据到FFT IP核,主->从
    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;
            count <= 8'd0;
            state<=0;
        end
        else 
            case(state)
            4'b0:begin
                if (fft_s_data_tready) begin//FFT IP核(从设备)已经准备好接收数据,主设备开始发送有效数据
                    if(count == 8'd127)begin
                        fft_s_data_tvalid <= 1'b1;
                        fft_s_data_tlast<=1'b1;//tlast置1
                        fft_s_data_tdata <= {16'd0,Time_data_I[count]};
                        count <= 8'd0;
                        state<=4'b1;
                    end
                    else begin
                        fft_s_data_tvalid <= 1'b1;
                        fft_s_data_tlast<=1'b0;//tlast置0
                        fft_s_data_tdata <= {16'd0,Time_data_I[count]};
                        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
            4'b1:begin
                 fft_s_data_tvalid <= 1'b0;
                 fft_s_data_tlast <= 1'b0;
                 if(fft_m_data_tlast)
                    state<=4'b0;   
            end
            endcase
   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];  
//            fft_i_out<=fft_m_data_tdata[15:0];
//            fft_q_out<=fft_m_data_tdata[31:16];  
        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(16'b1_0000_0111),                     // 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
      );

仿真图形如下,注意有符号和无符号显示的模拟波形不同,应选用有符号显示。下图的频率是镜像的显示。

 另外,如果给虚部的最高位写入1,则显示的频谱出现直流分量。

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝阳群众&热心市民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值