关于xilinx的FFTIP的使用和仿真

工具:vivado2018.3,modelsim10.6d

场景:在进行数据进行频谱分析的时候,使用FPGA来完成FFT的计算可以加快数据的计算速度。

下面使用仿真完成DDS产生的数据的FFT以及IFFT。原始数据使用DDSIP产生,通过IP产生的波形数据直接输入到FFT进行傅里叶正变换。然后再使用FFT对数据进行IFFT傅里叶逆变换还原波形数据。过程中完成了fftshift(将零频分量搬移到频谱中心),以及使用cordic计算平方根的过程。

FFT端口说明

|------------------------------|----|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 端口名称 | 方向 | 描述 |
| aclk | I | 时钟 |
| aresetn | I | 复位 |
| s_axis_config_tvalid | I | 配置有效 |
| s_axis_config_tready | O | 配置准备好 |
| s_axis_config_tdata | I | 针对配置通道的TDATA。携带配置信息: CP_LEN、FWD/INV、NFFT和SCALE_SCH。关于FWD/INV为FFTIP的方式,1为FFT,0为IFFT。当选择FFT点数可配置时NFFT为点数。SCALE_SCH为缩放计划,以确保在计算过程中不溢出。对于不同的IO架构有不同的规则。 |
| s_axis_data_tdata | I | 输入数据 |
| s_axis_data_tvalid | I | 数据有效 |
| s_axis_data_tready | O | 数据准备好 |
| s_axis_data_tlast | I | 输入的一帧最后一个数据 |
| m_axis_data_tvalid | O | 输出数据有效 |
| m_axis_data_tready | I | 输出数据准备好 |
| m_axis_data_tdata | O | 输出数据 |
| m_axis_data_tuser | O | 输出数据状态参数。包含XK_INDEX, OVFLO, and BLK_EXP. XK_INDEX输出数据索引 OVFLO溢出标志 BLK_EXP块指数,字段中出现的值表示在转换过程中数据被缩放的比特总数。例如,如果BLK_EXP的值为00101 = 5,这意味着相关的输出数据(XK_RE,XK_IM)被缩放为5位(向右移5位),或者换句话说,被除以32,以充分利用输出数据路径的可用动态范围而不会溢出。 |
| m_axis_data_tlast | O | 输出的最后一个数据。 |
| m_axis_status_tvalid | O | 状态有效 |
| m_axis_status_tready | I | 状态准备好 |
| m_axis_status_tdata | O | 状态数据。包含每一帧的状态休息。 |
| event_frame_started | O | 事件帧开始 |
| event_tlast_unexpected | O | 当核心在不是帧中最后一个的数据样本上看到s_axis_data_tlast高时有效 |
| event_tlast_missing | O | 当一帧的最后一个数据样本上的s_axis_data_tlast为低时断言。 |
| event_fft_overflow | O | 当正在从数据输出通道卸载的数据样本中出现溢出时断言。仅在溢出是一个有效的选项时才会出现。 |
| event_data_in_channel_halt | O | 当核心从数据输入通道请求数据而没有数据可用时断言。 |
| event_data_out_channel_halt | O | 当核心从数据输入通道请求数据而没有数据可用时断言。 |
| event_status_in_channel_halt | O | 当核心试图将数据写入状态通道而无法这样做时,将被断言。仅在非实时模式下出现。 |

FFT IP的配置界面

Channels:从1到12中选择通道数。三种Burst I/O架构均可使用多通道操作。对于浮点格式,通道必须为1。

Transform Length: 选择一次处理所需点的大小。

The Pipelined Streaming I/O:运行连续处理。

Radix-4,Radix-2,Radix-2 Lite Burst I/O。几种不同的实现方式,延迟依次增大,资源依次减少。

Run time configurable Transform Length:允许运行的过程中改变点数。勾选此后注意,s_axis_config_tdata的字段的意义。

DataFormat:选择输入和输出数据样本是否为定点格式,或在IEEE-754单精度(32位)浮点格式中。浮点格式不是当核心处于多通道配置时可用。

Scaling Options:

Scaling:用户自定义缩放格式。注意s_axis_config_tdata的字段需要配置每个阶段的缩放信息。

Block Floating-Point:由核心来判断所需的缩放程度,以实现对可用动态范围的最佳利用,并以块指数的形式报告缩放因子。注意m_axis_data_tuser字段的块指数报告。

Output ordering:自然顺序和反转顺序。这里使用自然顺序。

Optional Output Fields:XK_INDEX,输出数据索引。

资源消耗设置界面。

关于matlab仿真,产生1MHZ的正弦波余弦波信号,采样率为100MHZ。共计1024个点。对其进行FFT。

matlab仿真程序

Matlab 复制代码
% 生成正弦波
fc = 1e6;               % 频率
fs = 100e6;             % 采样率
t1 = 0:1/fs:1e-3;       % 时间序列,1微秒
t = t1(1:1024);         %RW需要取整数计算出的频率是真实

sin_wave = sin(2 * pi * fc * t);
cos_wave = cos(2 * pi * fc * t);

% 复数
plural_wave = cos_wave+ 1i*sin_wave;

% 加噪声
data =awgn(cos_wave,100) ;
% data =awgn(plural_wave,100) ;

% 绘制原始正弦波数据
figure;
subplot(1,1,1);
plot(t*1e9, imag(plural_wave));
title('原始正弦波');
xlabel('时间 (ns)');
ylabel('幅值');


%%做FT变化,算平均功率谱,并画谱输出
FFT_data = data; N = length(FFT_data); w = blackman(N);Fs =100e6;
% Sf_I_Q_wave=fftshift(fft((FFT_data).*w',N)*2.381);
% w = gausswin(N);%高斯窗函数,窗长度为N
gauss_data = fft((FFT_data).*w',N)*2.396;%%做FFT变换,加窗并还原窗系数
Sf_I_Q_wave=fftshift(gauss_data);
Sf_I_Q_wave_dBm =(abs(Sf_I_Q_wave));
% Sf_I_Q_wave_dBm =20*log10(1/N*abs(Sf_I_Q_wave));
X_freq=Fs.*(-N/2:N/2-1)/N;figure(2);plot(X_freq,Sf_I_Q_wave_dBm);title('plural_wave原始数据普');

对实信号余弦波进行傅里叶变换,频谱图如下。

对复信号进行进行傅里叶变换频谱。

在逻辑中我们使用DDSIP来产生我们需要的波形数据。

DDS IP配置界面

可以看到我需要控制DDS的控制字来生成不同频率的波形数据,输出数据的格式为高16位为正弦,低16位为余弦。

输出频率计算公式。

其中X为频率控制字,Fs采样率,即系统时钟。N为多少位的控制字。要输出1MHZ的波形信号的控制字为X=655。

输出波形正好为一个周期1000ns。即1MHZ。

1024点FFT实信号输入。

FFTSHIFT频谱搬移模块

对于FFTSHIFT模块我们打开matlab帮助后可以发现,搬移的效果就是以频谱中心左右两端谱线互换。

ABS求平方根模块

求复数的模,定义为

复数

在逻辑中我们使用cordic来计算平方根。

cordicIP配置如下所示

模块仿真

Matlab 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/08/12 14:14:51
// Design Name: 
// Module Name: vtf_fft_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module vtf_fft_test;
//fft
//input
wire               [31:0] s_axis_data_tdata    ; 
wire                      s_axis_data_tvalid   ; 
wire                      s_axis_data_tready   ; 
wire                      s_axis_data_tlast    ; 
//output
wire               [31:0] m_axis_data_tdata    ; 
wire                      m_axis_data_tvalid   ; 
wire                      m_axis_data_tready   ; 
wire                      m_axis_data_tlast    ; 
wire               [23:0] m_axis_data_tuser    ; 

//dds
wire                      m_dds_tvalid         ; 
wire               [31:0] m_dds_tdata          ; 

//system signal
reg                       clk                  ; 
reg                       rst_n                ; 
reg                       data_gen             ; 
reg                       data_flog            ; 
reg                       douta_vld            ; 
reg                [15:0] cnt                  ; 

//fftshift
wire               [31:0] fftshift_data        ; // 
wire                      fftshift_data_valid  ; // 
wire                [9:0] fftshift_cnt         ; // 

//abs

wire               [15:0] abs_data             ; // (output)
wire                      abs_data_valid       ; // (output)
//system signal

//
assign  s_axis_data_tdata   = douta_vld ? m_dds_tdata : 32'h0;//给复信号
//assign  s_axis_data_tdata   = douta_vld ? {16'd0,m_dds_tdata[15:0]} : 32'h0;//实信号
assign  s_axis_data_tvalid  = douta_vld;
assign  s_axis_data_tlast   = (cnt == 16'd1023 );

assign  m_axis_data_tready  = 1'b1;

//FFT后数据
//取实部
wire               [15:0] f_imag               ; 
wire               [15:0] f_real               ; 
wire               [31:0] f_abs                ; 

assign  f_imag = m_axis_data_tdata[31:16];
assign  f_real = m_axis_data_tdata[15:0];
assign  f_abs  = f_imag + f_real;



//=========================================================
dds_compiler_0 u_dds (
    .aclk                         (clk                         ), // input wire aclk
    .s_axis_config_tvalid         (1'b1                         ), // input wire s_axis_config_tvalid
    .s_axis_config_tdata          (16'd655                      ), // input wire [15 : 0] s_axis_config_tdata
    .m_axis_data_tvalid           (m_dds_tvalid                 ), // output wire m_axis_data_tvalid
    .m_axis_data_tdata            (m_dds_tdata                  ), // output wire [31 : 0] m_axis_data_tdata
    .m_axis_phase_tvalid          (                             ), // output wire m_axis_phase_tvalid
    .m_axis_phase_tdata           (                             )// output wire [15 : 0] m_axis_phase_tdata
);

//=========================================================
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         (                             ), // 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            (s_axis_data_tlast            ), // 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            (m_axis_data_tuser            ), // output wire [23 : 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
    .m_axis_status_tdata          (                             ), // output wire [7 : 0] m_axis_status_tdata
    .m_axis_status_tvalid         (                             ), // output wire m_axis_status_tvalid
    .m_axis_status_tready         (1'b1                         ), // input wire m_axis_status_tready
    .event_frame_started          (                             ), // output wire event_frame_started
    .event_tlast_unexpected       (                             ), // output wire event_tlast_unexpected
    .event_tlast_missing          (                             ), // output wire event_tlast_missing
    .event_status_channel_halt    (                             ), // output wire event_status_channel_halt
    .event_data_in_channel_halt   (                             ), // output wire event_data_in_channel_halt
    .event_data_out_channel_halt  (                             )// output wire event_data_out_channel_halt
);

//==========================================================
fft_shift u_fft_shift(
//
    .fft_data                     (m_axis_data_tdata            ), // (input ) 
    .fft_cnt                      (m_axis_data_tuser[9:0]       ), // (input ) 
    .fft_last                     (m_axis_data_tlast            ), // (input ) 
    .fft_data_valid               (m_axis_data_tvalid           ), // (input ) 
    .fftshift_data                (fftshift_data                ), // (output) 
    .fftshift_data_valid          (fftshift_data_valid          ), // (output) 
    .fftshift_cnt                 (fftshift_cnt[9:0]            ), // (output) 
//system signal
    .sys_clk                      (clk                          ), // (input ) 
    .rst_n                        (rst_n                        )// (input ) 
    );

//==========================================================
abs_top u_abs_top(
//
    .plural_data                  (fftshift_data[31:0]            ), // (input ) (input )
    .plural_data_valid            (fftshift_data_valid            ), // (input ) (input )
    .abs_data                     (abs_data[15:0]               ), // (output) (output)
    .abs_data_valid               (abs_data_valid               ), // (output) (output)
//system signal
    .clk                          (clk                          ), // (input ) (input )
    .rst_n                        (rst_n                        )  // (input ) (input )
);

//==========================================================
xfft_0 u_ifft (
    .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         (                             ), // output wire s_axis_config_tready
    .s_axis_data_tdata            (m_axis_data_tdata            ), // input wire [31 : 0] s_axis_data_tdata
    .s_axis_data_tvalid           (m_axis_data_tvalid           ), // input wire s_axis_data_tvalid
    .s_axis_data_tready           (m_axis_data_tready           ), // output wire s_axis_data_tready
    .s_axis_data_tlast            (m_axis_data_tlast            ), // input wire s_axis_data_tlast
    .m_axis_data_tdata            (                             ), // output wire [31 : 0] m_axis_data_tdata
    .m_axis_data_tuser            (                             ), // output wire [23 : 0] m_axis_data_tuser
    .m_axis_data_tvalid           (                             ), // output wire m_axis_data_tvalid
    .m_axis_data_tready           (1'b1                         ), // input wire m_axis_data_tready
    .m_axis_data_tlast            (                             ), // output wire m_axis_data_tlast
    .m_axis_status_tdata          (                             ), // output wire [7 : 0] m_axis_status_tdata
    .m_axis_status_tvalid         (                             ), // output wire m_axis_status_tvalid
    .m_axis_status_tready         (1'b1                         ), // input wire m_axis_status_tready
    .event_frame_started          (                             ), // output wire event_frame_started
    .event_tlast_unexpected       (                             ), // output wire event_tlast_unexpected
    .event_tlast_missing          (                             ), // output wire event_tlast_missing
    .event_status_channel_halt    (                             ), // output wire event_status_channel_halt
    .event_data_in_channel_halt   (                             ), // output wire event_data_in_channel_halt
    .event_data_out_channel_halt  (                             )// output wire event_data_out_channel_halt
);

//================================================================
//================================================================
initial
begin
        clk = 0;
        rst_n=0;
        data_gen   =0;
        #100;
        rst_n      =1;
        #1000;
        data_gen   =1;
        #100;
        data_gen   =0;


end

always @ (posedge clk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin         
                data_flog   <= 1'b0;
        end
        else if(data_gen == 1'b1)begin
                data_flog   <= 1'b1;
        end 
        else if(cnt   >= 10'd1022)begin
                data_flog   <= 1'b0;
        end
end

always @ (posedge clk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin         
                douta_vld   <= 1'b0;
        end
        else begin
                douta_vld   <= data_flog;
        end 

end


always @ (posedge clk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin         
                cnt <= 16'd0;
        end
        else if(s_axis_data_tvalid == 1'b1 && s_axis_data_tready == 1'b1)begin
                cnt <= cnt + 1'b1;
        end 
        else begin
                cnt <= cnt;
        end

end

//================================================================
//================================================================

always #5 clk = ~clk;

endmodule

复信号输入。

实信号输入。

逆傅里叶变换结果

相关推荐
一口一口吃成大V2 小时前
FPGA随记——FPGA时序优化小经验
fpga开发
贾saisai3 小时前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发
redcocal7 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
思尔芯S2C1 天前
高密原型验证系统解决方案(下篇)
fpga开发·soc设计·debugging·fpga原型验证·prototyping·深度调试·多fpga 调试
坚持每天写程序1 天前
xilinx vivado PULLMODE 设置思路
fpga开发
redcocal2 天前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
邹莉斯3 天前
FPGA基本结构和简单原理
fpga开发·硬件工程
悲喜自渡7213 天前
易灵思FPGA开发(一)——软件安装
fpga开发
ZxsLoves3 天前
【【通信协议ARP的verilog实现】】
fpga开发
爱奔跑的虎子3 天前
FPGA与Matlab图像处理之伽马校正
图像处理·matlab·fpga开发·fpga·vivado·xilinx