Xilinx Vivado (FFT IP核)

本文介绍了如何利用Vivado的FFT IP核进行傅里叶变换。首先解释了傅里叶变换的基本原理和采样要求,接着详细说明了在Vivado中配置IP核的过程,包括输入输出端口的功能。然后,通过MATLAB生成测试信号并进行傅里叶变换,将结果转换为二进制并写入文件。最后,使用Vivado的TB文件读取数据并驱动IP核进行FFT计算,展示仿真流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.傅里叶变换FFT
傅立叶变换是一种分析信号的方法,它可分析信号的成分,也可用这些成分合成信号。许多波形可作为信号的成分,比如正弦波、方波、锯齿波等,傅立叶变换用正弦波作为信号的成分。
通过FFT将时域信号转换到频域,从而对一些在时域上难以分析的信号在频域上进行处理。
其中,根据奈奎斯特采样定理,采样频率需大于信号频率的两倍;
1.N为FFT采样点数,代表对信号在频域的采样数;
2.采样频率Fs和采样点数N决定了信号的频域分辨力,即分辨力=Fs/N,即N越大,频域分辨力越好,反之频域分辨力越差。

2.Vivado中IP核的配置
打开Vivado2018.3:
在这里插入图片描述
配置IP核:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如图所示,其中,S_AXIS_DATA为输入数据端口,FFT的数据通过S_AXIS_DATA输入给IP核;S_AXIS_CONFIG为输入配置端口,对数据进行配置,FFT还是IFFT、缩放因子、FFT变换点数等信息;FFT变换后的数据从M_AXIS_DATA端口输出。
在这里插入图片描述
其中包含了S_AXIS_DATA_TDATA、S_AXIS_CONFIG_TDATA以及M_AXIS_DATA_TDATA的数据格式:
S_AXIS_DATA_TDATA:共32位,其中低16位为输入数据的实部,高16位为输入数据的虚部。
S_AXIS_CONFIG_TDATA:最低位第0位,决定对数据进行FFT还是IFFT,置1时FFT,清零时IIFT。
M_AXIS_DATA_TDATA:48位数据输出,低24位为实部,高24位为虚部。

3.仿真:
I通过matlab对F(t) = 100 + 100cos(2pi30t) + 100cos(2pi70t) 这个信号以Fs = 100HZ进行采样,采样点数N = 128,采样完成后,将数据转换为16位二进制,并存入txt文件中。matlab程序如下:

(源:CSDN—傅外叶)
clear

Fs=100;                         
N = 128;
n = 1:N;
t = n/Fs;
% 生成测试信号
f1 = 30;                   
f2 = 70;                     
s1 = cos(2*pi*f1*t);    
s2 = cos(2*pi*f2*t);
fft_signal = 1 + s1 + s2 ;
data_before_fft = 100*fft_signal;  %系数放大100倍


fp = fopen('C:\Users\lys\Desktop\fft\data_before_fft.txt','w');
for i = 1:N
   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
    for j=1:16
        fprintf(fp,'%s',temp(j));
    end
    fprintf(fp,'\r\n');
end
fclose(fp);

y = fft(data_before_fft,N);
y = abs(y);
f = n*Fs/N;
plot(f,y);


MATLAB中的信号做傅里叶变换:
在这里插入图片描述
建立tb文件:

(源:CSDN—傅外叶)
`timescale 1ns / 1ps
module fft_tb;

reg clk;
reg rst_n;
reg signed [15:0] Time_data_I[127:0];
reg data_finish_flag;

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 [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 [23:0] fft_i_out;
reg signed [23:0] fft_q_out;
reg signed [47:0] fft_abs;

initial begin
    clk = 1'b1;
    rst_n = 1'b0;
    fft_m_data_tready = 1'b1;
    $readmemb("C:/Users/lys/Desktop/fft/data_before_fft.txt",Time_data_I);
end

always #5 clk = ~clk;

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;
        data_finish_flag  <= 1'b0;
        count <= 8'd0;
        rst_n = 1'b1;
    end
    else if (fft_s_data_tready) begin 
        if(count == 8'd127) begin
            fft_s_data_tvalid <= 1'b1;
            fft_s_data_tlast  <= 1'b1;
            fft_s_data_tdata  <= {Time_data_I[count],16'd0};
            count <= 8'd0;
            data_finish_flag <= 1'b1;
        end
        else begin
            fft_s_data_tvalid <= 1'b1;
            fft_s_data_tlast  <= 1'b0;
            fft_s_data_tdata  <= {Time_data_I[count],16'd0};   
            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

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];
    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(8'd1),                                // 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
  );
    
    
endmodule

4.仿真结果:
在这里插入图片描述
首先判断fft_s_data_tready信号是否为高电平,即IP核是否准备好了接收数据,当检测到该信号有效后,将fft_s_data_tvalid信号拉高,准备向IP核写入数据,并开启count计数。在fft_s_data_tvalid有效期间内,读出指定txt文件中的数据,并在低16位进行补零处理后,按顺序写入到fft_s_data_tdata信号线中。当count计数到127,即最后一个数据时,将fft_s_data_tlast信号拉高,代表数据写入完成。可以看到,在数据写入完成后(fft_s_data_tlast出现脉冲),fft_s_data_tready变为低电平,则代表IP核此时变为忙状态,不能再继续写入数据。
延时一段时间后,fft_m_data_tvalid变为高电平,代表fft_m_data_tdata中将输出有效数据,即128点FFT的计算结果。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值