XILINX FFT IP核使用IFFT,并实现流水线计算IFFT

最近在学习宽带数字接收机的一些东西,其中多相滤波是属于其中比较关键的一环,笔者在matlab上成功仿真了多相滤波这一环节后,便想着在FPGA上实现多相滤波,多相滤波的最后一个环节是IFFT运算,在vivado上实现IFFT还是比较简单的,使用FFT IP核的config通道配置为IFFT模式即可,但在具体运算上,还是有一些细节需要考虑,比如IFFT运算的实时性,吞吐量。
ADC采集的数据是流模式,不间断的,所以在进行IFFT运算时,便需要考虑使用FFT IP核的流水线结构,以实现数据的实时计算,如果使用非实时模式,且不采用流水线结构,因FFT计算的延迟过大,数据缓存存在极大压力,所以在本文中,笔者使用FFT的流水线架构,实时模式,实现IFFT计算。
FFT IP配置如下图所示,本文中采用32点FFT,也即经过配置后,32点IFFT。

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

在进行IFFT的使用时,笔者发现了一个问题,在实时模式下,FFT ip核的数据通道的s_axis_tdata_ready信号会出现拉低情况,并固定出现在数据开始传输之后的几个周期内,如下图所示,此时IFFT的配置也尚未完成
在这里插入图片描述
笔者一开始以为是没有勾选FFT IP核的复位配置,在添加了复位控制后其仍然出现这类情况。
那么如何解决这个问题,因为AXI_STREAM协议是在tready和tvalid信号同时为高时才缓存当前数据,如果不解决这个问题,必然会对IFFT运算结果产生影响,故可以在IFFT运算与数据输入之间,添加一级FIFO缓存,当tready信号为高时才进行数据的传输,这样就可以保证每一个数据成功缓存,而为了保证tvalid与当前时刻的tready信号同步为高,对于FIFO的读数据模式选择First Word Fall Through模式,即将最先写入的数据,直接放在输出端口上,此时的读延迟为0
在这里插入图片描述
同时,对于FIFO的读控制也使用组合逻辑,保证没有周期延迟,即当tready信号为高且fifo的empty信号不为1时进行FIFO的读使能,修改逻辑后的仿真如下。
在这里插入图片描述
可以看出,成功实现了数据的不丢失写入,接下来进行IFFT运算结果的查看
笔者是传输了1~32这32个数据进行第一次IFFT运算,同样在matlab中,进行这32点数据的IFFT运算,并且需要注意的是vivado的IFFT运算结果需要除以运算点数才是真实的运算结果,可以直接在代码中将运算结果进行移位即可,需要注意有符号数据的移位要考虑符号位的保持,在本文中,直接在MATLAB的运算结果上乘以32,进行数据查看。对于有符号数据,二进制补码的移位,笔者会在以后的文章中进行详细介绍。
在这里插入图片描述
在这里插入图片描述
还需要注意一点,在实际仿真中发现,如果FFT IP核添加了复位逻辑,在进行IFFT运算时,会出现运算结果的虚部与实际结果呈相反数的情况,目前只能将复位关闭,未能找到其他的解决办法。如果有同学知道如何解决这一问题,欢迎在评论区进行指正。
verilog代码如下

module ifft_test(
    input               i_clk       ,
    input               i_rst       ,
    input   [11:0]      i_data      ,
    input               i_valid     ,
    output              o_active    
    );

reg     [7 :0]          s_axis_config_tdata         ;
reg                     s_axis_config_tvalid        ;
wire                    s_axis_config_tready        ;
wire    [47:0]          m_axis_data_tdata           ;
wire                    m_axis_data_tvalid          ;
wire                    m_axis_data_tlast           ;
wire                    s_axis_data_tready          ;
wire                    event_frame_started         ;
wire                    event_tlast_unexpected      ;
wire                    event_tlast_missing         ;
wire                    event_data_in_channel_halt  ;
wire                    w_config_activate           ;
wire    signed[17:0]    w_ifft_re                   ;
wire    signed[17:0]    w_ifft_im                   ;
wire                    w_fifo_rd_en                ;
wire    [11:0]          w_fifo_dout                 ;
wire                    w_fifo_full                 ;
wire                    w_fifo_empty                ;
wire                    s_axis_data_tvalid          ;

FIFO_12X64 FIFO_12X64_U0 (
    .clk                            (i_clk                      ),
    .din                            (i_data                     ),
    .wr_en                          (i_valid                    ),
    .rd_en                          (w_fifo_rd_en               ),
    .dout                           (w_fifo_dout                ), 
    .full                           (w_fifo_full                ),
    .empty                          (w_fifo_empty               )
);

ifft_32 ifft_32_u0 (
    .aclk                           (i_clk                      ),
    // .aresetn                        (~i_rst                     ), 
    .s_axis_config_tdata            (s_axis_config_tdata        ),
    .s_axis_config_tvalid           (s_axis_config_tvalid       ),
    .s_axis_config_tready           (s_axis_config_tready       ),
    .s_axis_data_tdata              ({4'd0,12'd0,4'd0,w_fifo_dout}),
    .s_axis_data_tvalid             (s_axis_data_tvalid         ),
    .s_axis_data_tready             (s_axis_data_tready         ),
    .s_axis_data_tlast              (0),
    .m_axis_data_tdata              (m_axis_data_tdata          ),
    .m_axis_data_tvalid             (m_axis_data_tvalid         ),
    .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_data_in_channel_halt     (event_data_in_channel_halt )
);

assign  w_ifft_re = m_axis_data_tdata[17 :0]        ;
assign  w_ifft_im = m_axis_data_tdata[41:24]        ;
assign  w_config_activate = s_axis_config_tvalid & s_axis_config_tready;
assign  w_fifo_rd_en = s_axis_data_tready & !w_fifo_empty;
assign  o_active = w_config_activate;
assign  s_axis_data_tvalid = w_fifo_rd_en;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        s_axis_config_tdata <= 'd0;
    else
        s_axis_config_tdata <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        s_axis_config_tvalid <= 'b1;
    else if(s_axis_config_tvalid & s_axis_config_tready)
        s_axis_config_tvalid <= 'b0;
    else
        s_axis_config_tvalid <= s_axis_config_tvalid;
end

endmodule

整体来说,这个功能实现起来还是比较简单的,笔者也是个萌新,在学习过程中探索,如果有什么问题,欢迎大家在评论区批评指正。

如果觉得笔者的文章对您有些帮助,希望点个赞,激励下笔者的创作,不胜感激!

关于本文的完整matlab代码与vivado工程,可以私信博主免费领取!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值