vivado fft实现结果和matlab结果对不上

在做32点fft vivado实现时,对比matlab结果,发现对不上,是我代码有问题吗

IP核配置

img

img

img

俩出来的结果

img

img

matlab 代码

Fs = 1e9 ;                
t = 0:1/Fs:31/Fs ;        
length = 32 ;
n = 1:length ;
f1 = 31.25e6 ;
f2 = 300e6 ;
s1 = cos(2*pi*f1*t) ;
s2 = cos(2*pi*f2*t) ;
signalN = s1 + s2 ;
data_before_fft = 100* signalN ; %系数放大100倍
figure;hold on ; 
plot(n, s1) ; 
plot(n, s2) ;
hold off ; 
figure;plot(n(1:32), signalN(1:32)) ;
title('输入信号') ; 
fp = fopen('data_before_fft.txt','w') ; 
for i = 1:length
    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
%       temp = s_bin(i,:);
    for j = 1:16
        fprintf(fp,'%s',temp(j)) ;
    end
    fprintf(fp,'\r\n') ;
end
fclose(fp) ; 
data_after_fft1 = fft(data_before_fft) ;
data_after_fft = data_after_fft1.' ; 
data_real = real(data_after_fft) ;
data_imag = imag(data_after_fft) ; 
data_r_i = [data_real, data_imag];

vivado 代码

module fft(
    input   wire    clk,
    input   wire    [15:0]  din,
    input   wire    last,
    input   wire    s_axis_data_tvalid,
 
    output  wire     [15:0]  m_axis_data_tdata_r,
    output  wire     [15:0]  m_axis_data_tdata_i,
    output  wire     [7:0]   index
);
 
    
    wire [31:0]s_axis_data_tdata;
    wire [7:0]s_axis_config_tdata = {7'b0,1'b1};//NO need run time change length!
    wire s_axis_config_tvalid = 1;
    wire s_axis_config_tready ;
    wire            s_axis_data_tready ;
    //wire            s_axis_data_tlast = 0;
    //wire            s_axis_data_tvalid = 1 ;
    
    //wire    [7:0]  index;
    wire            m_axis_data_tvalid;
    wire            m_axis_data_tready = 1;
    wire            m_axis_data_tlast=0;
    
    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;
    
    wire    [31:0]    m_axis_data_tdata;
    
    assign  s_axis_data_tdata  = {16'b0,din};
    assign  m_axis_data_tdata_r = m_axis_data_tdata[15:0];
    assign  m_axis_data_tdata_i = m_axis_data_tdata[31:16];
  

xfft_0 fft_test (
  .aclk(clk),                                                // input wire aclk
  .s_axis_config_tdata(s_axis_config_tdata),                  // input wire [7 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid),                // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready),                // output wire s_axis_config_tready
  .s_axis_data_tdata(s_axis_data_tdata),                      // input wire [31 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid),                    // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),                    // output wire s_axis_data_tready
  .s_axis_data_tlast(last),                                   // input wire s_axis_data_tlast
  .m_axis_data_tdata(m_axis_data_tdata),                      // output wire [31 : 0] m_axis_data_tdata
  .m_axis_data_tuser(index),                                  // output wire [7 : 0] m_axis_data_tuser
  .m_axis_data_tvalid(m_axis_data_tvalid),                    // output wire m_axis_data_tvalid
  .m_axis_data_tready(m_axis_data_tready),                    // input wire m_axis_data_tready
  .m_axis_data_tlast(m_axis_data_tlast),                      // output wire m_axis_data_tlast
  .event_frame_started(event_frame_started),                  // output wire event_frame_started
  .event_tlast_unexpected(event_tlast_unexpected),            // output wire event_tlast_unexpected
  .event_tlast_missing(event_tlast_missing),                  // output wire event_tlast_missing
  .event_status_channel_halt(event_status_channel_halt),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt)  // output wire event_data_out_channel_halt
);
endmodule

tb

module tb_fft();
   reg clk; 
   reg [15:0] din; 
   reg [15:0] stimulus[1:32];//32位
   integer count;
   integer i; 
   integer file;
   wire [15:0] data_real;
   wire [15:0] data_imag;
   wire [7:0] index;
   reg last;
   reg s_axis_data_tvalid;
   initial begin
        clk = 0;
        din = 0;
        count = 0;
        last = 0;
        s_axis_data_tvalid = 0;
        #10;
        $readmemb("C:/Users/hp/OneDrive/桌面/FFT/data_before_fft.txt", stimulus);
        file = $fopen("C:/Users/hp/OneDrive/桌面/FFT/data_before_fft.txt", "w");
        #10;
        for(i = 1;i<=32;i = i+1)begin
            s_axis_data_tvalid = 1;
            din = stimulus[i];
            #4;
        end
        last = 1;
        s_axis_data_tvalid = 0;
        din = 16'b0;
   end
   always # 2 clk =  ~clk;
        always @(posedge clk) begin
        $fwrite(file,"%h\n", data_real);  //data_o为需要保存的信号数据
        if(count > 2500)
            $fclose(file);
         count = count + 1;
    end
   
    fft fft_test(
        .clk(clk),
        .din(din),
        .last(last),
        .s_axis_data_tvalid(s_axis_data_tvalid),
        .m_axis_data_tdata_r(data_real),
        .m_axis_data_tdata_i(data_imag),
        .index(index)
    );  
endmodule

对于FPGA实现的FFT结果和Matlab结果不一致的情况,有以下几点需要检查:

  1. 检查FFT算法实现是否正确,特别是蝶形结构、位反转等关键部分。
  2. 检查位数设置是否匹配,Matlab使用双精度浮点数,而FPGA使用定点数实现,位数不匹配可能导致结果不同。
  3. 查看FPGA实现的定点数格式,是否存在截断或者溢出情况。调整位数和小数点位置,扩大位数范围。
  4. 对比FFT各个阶段的中间结果,定位误差产生的阶段。
  5. 检查仿真测试数据是否合理,修改为不同测试数据重现问题。
  6. 检查FPGA综合后RTL代码,是否与原算法描述一致,综合优化是否改变了算法。
  7. 尝试增加FFT输出结果的位数,观察结果是否接近,从而判断是否为精度问题。
  8. 检查时钟频率设置是否合理,FFT速度过快可能导致耗费更多资源。
  9. 尝试在Matlab中对输入信号添加噪声,使其更接近FPGA的定点表示,再比较结果。
    通过逐步排查,可以定位FFT结果不一致的具体原因,针对性地修改优化FPGA实现的FFT。

根据您提供的信息,目前无法确切判断代码是否有问题。但是,有几个方面可能会导致结果不匹配:

  1. Vivado的FFT IP核设置不正确。请确保您正确配置了FFT IP核,并与Matlab的FFT设置相匹配。例如,FFT的长度、窗函数等应该一致。

  2. Matlab的FFT函数和Vivado的FFT IP核的数据输入格式不匹配。请确认您在Vivado中正确处理了数据的格式,以便与Matlab的输入格式相匹配。

  3. 数据缩放不正确。根据您提供的代码,您将信号数据放大了100倍。请确保在Vivado中也进行了相同的缩放。

  4. 数据转换不正确。您在Matlab中使用了16位的二进制数据,但是没有提供Vivado中数据的处理方式。请确保您正确地转换了数据格式。

为了更好地帮助您解决问题,我建议您提供更多关于Vivado实现FFT的代码和设置的细节。同时,您可以尝试使用MATLAB验证FFT数据是否正确。下面是一种可能的解决方案:

首先,确保您的FFT设置正确。比如,FFT的长度应为32点。

N = 32; % FFT的长度
data_after_fft_matlab = fft(data_before_fft, N);

接下来,将MATLAB的FFT结果与Vivado的FFT结果进行比较,并输出不匹配的点。

diff = abs(data_after_fft_matlab - data_after_fft);
mismatch_idx = find(diff > 1e-6);
disp("不匹配的点:");
disp(mismatch_idx);

您可以使用以上代码查找不匹配的点,以确定问题所在。如果找不到问题,我建议您仔细检查Vivado设置和代码实现,确保与Matlab一致,并尝试调整参数和数据处理方法。

代码错误比较多,给你修改了一下。
注意:波形文件的路径我修改了。你要将波形文件复制到正确的文件夹
FFT IP 需要修改

img

img

img

代码也需要修改


module tb_fft();
   reg clk; 
   reg [15:0] din; 
   reg [15:0] stimulus[1:32];//32位
   integer count;
   integer i; 
   integer file_r,file_i;
   wire signed[15:0] data_real;
   wire signed[15:0] data_imag;
   wire [7:0] index;
   wire s_axis_data_tready;
   wire m_axis_data_tvalid;
   reg last;
   reg s_axis_data_tvalid;
   initial begin
        clk = 0;
        din = 0;
        count = 0;
        last = 0;
        s_axis_data_tvalid = 0;
        #10;
        $readmemb("d:/demo/data_before_fft.txt", stimulus);        //文件存放的路径别有中文
        file_r = $fopen("d:/demo/data_before_fftr.txt", "w+");
        file_i = $fopen("d:/demo/data_before_ffti.txt", "w+");
        
        if(s_axis_data_tready == 0)    //等到 AXIS 准备好
        #100;
        
        for(i = 1;i<=32;i = i+1)begin
            s_axis_data_tvalid = 1;
            din = stimulus[i];
            if(i==32) last = 1;
            else      last = 0;
            #4;
        end
        last = 0;
        s_axis_data_tvalid = 0;
        din = 16'b0;
   end
   always # 2 clk =  ~clk;
        always @(posedge clk) begin
        if(count >= 32)begin
            $fclose(file_r);
            $fclose(file_i);
        end
        else begin
            if(m_axis_data_tvalid == 1)    //输出数据有效才写文件
            begin
                $fwrite(file_r,"%d\n", data_real);
                $fwrite(file_i,"%d\n", data_imag);
                count <= count + 1;
            end
        end
    end
   
    fft fft_test(
        .clk(clk),
        .din(din),
        .last(last),
        .s_axis_data_tvalid(s_axis_data_tvalid),
        .s_axis_data_tready(s_axis_data_tready),
        .m_axis_data_tdata_r(data_real),
        .m_axis_data_tdata_i(data_imag),
        .m_axis_data_tvalid(m_axis_data_tvalid),
        .index(index)
    );  
endmodule


module fft(
    input   wire    clk,
    input   wire    [15:0]  din,
    input   wire    last,
    input   wire    s_axis_data_tvalid,
    output  wire    s_axis_data_tready,
 
    output  wire     [15:0]  m_axis_data_tdata_r,
    output  wire     [15:0]  m_axis_data_tdata_i,
    output  wire              m_axis_data_tvalid,
    output  wire     [7:0]   index
);
 
    reg            cfg_s=0;
    wire [31:0]    s_axis_data_tdata;
    wire [7:0]    s_axis_config_tdata = {7'b0,1'b0};//NO need run time change length!
    reg            s_axis_config_tvalid = 0;
    wire        s_axis_config_tready ;
    
    //wire    [7:0]  index;
    wire            m_axis_data_tvalid;
    wire            m_axis_data_tready = 1;
    wire            m_axis_data_tlast;
    
    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;
    
    wire    [31:0]    m_axis_data_tdata;
    
    assign  s_axis_data_tdata  = {16'b0,din};
    assign  m_axis_data_tdata_r = m_axis_data_tdata[15:0];
    assign  m_axis_data_tdata_i = m_axis_data_tdata[31:16];
    
    always@(posedge clk)
    begin
        if(s_axis_config_tready == 1 && cfg_s == 0)
        begin
            s_axis_config_tvalid    <= 1;
            cfg_s                    <= 1;
        end
        else
            s_axis_config_tvalid    <= 0;
    end
  
 
xfft_0 fft_test (
  .aclk(clk),                                                // input wire aclk
  .s_axis_config_tdata(s_axis_config_tdata),                  // input wire [7 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid),                // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready),                // output wire s_axis_config_tready
  .s_axis_data_tdata(s_axis_data_tdata),                      // input wire [31 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid),                    // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),                    // output wire s_axis_data_tready
  .s_axis_data_tlast(last),                                   // input wire s_axis_data_tlast
  .m_axis_data_tdata(m_axis_data_tdata),                      // output wire [31 : 0] m_axis_data_tdata
  .m_axis_data_tuser(index),                                  // output wire [7 : 0] m_axis_data_tuser
  .m_axis_data_tvalid(m_axis_data_tvalid),                    // output wire m_axis_data_tvalid
  .m_axis_data_tready(m_axis_data_tready),                    // input wire m_axis_data_tready
  .m_axis_data_tlast(m_axis_data_tlast),                      // output wire m_axis_data_tlast
  .event_frame_started(event_frame_started),                  // output wire event_frame_started
  .event_tlast_unexpected(event_tlast_unexpected),            // output wire event_tlast_unexpected
  .event_tlast_missing(event_tlast_missing),                  // output wire event_tlast_missing
  .event_status_channel_halt(event_status_channel_halt),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt)  // output wire event_data_out_channel_halt
);
endmodule