小弟最近毕业论文在做OFDM方面的研究,用到了vivado中的FFT IP核,发现网上现有的也只是介绍了一些接口,而且大部分给的代码跑不出来,所以对自己使用该IP核做一些总结,并附上代码和matlab的仿真结果,欢迎大家批评指正一起学习进步。
关于OFDM这篇文章很详细可以看看
给"小白"图示讲解OFDM的原理
首先打开vivado找到FFT IP点击打开
之后弹出对话框,需要配置的参数有三个标签页,需要一一配置
关于一些端口的说明:
s_axis_config_tdata:控制输入模式,进行fft/ifft以及衰减因子的设置,第0位为1fft,为0做ifft,高位用于scale因子的设置。
s_axis_config_tvalid:拉高若干个时钟周期后归零,之后将s_axis_data_tvalid拉高
s_axis_config_tready:s_axis_config_tvalid拉高两个时钟周期后,该口给1输出;
s_axis_data_tready:s_axis_config_tvalid拉高两个时钟周期后,该口给1输出,ip核初始化完成,可进行数据输入必须进行赋值;
s_axis_data_tvalid:拉高64个周期,输入64个数据进行fft;
s_axis_data_tdata:输入32位数据
s_axis_data_tlast:输入64个数据后拉高,停止数据输入;
第一个标签页里主要配置通道数,点数,时钟,吞吐量,结构,以及是否可以运行时配置,需要注意的是结构的配置会影响调整因子。
有四种可选择的FFT运算方式:
-
PipelinedStreaming I/O
-
Radix-4Burst I/O
-
Radix-2Burst I/O
-
Radix-2 Lite Burst I/O
在这里我选择的是Radix-4Burst I/O(基4—突发式),64点,100Mhz
第二页下可设置FFT的数据格式为定点Fixed Point或浮点Float Point;输出截位方式选择:不截位(Unscaled),截位(Scaled),块浮点(Block Floating Point);设置输入数据的位宽和相位因子位宽。还有一些可选的附加信号,如时钟使能(ACLKEN),复位信号(ARESETn,低有效)等。“Output Ordering”用以选择FFT计算结果以自然顺序(Nature Order)或位倒序(Bit/Digit Reversed Order)输出。
在这里我选择的是不截位,自然顺序
第三配置页主要配置内部数据块的使用和优化的方式。
所有这些配置完成后,可以左侧一列中察看配置的结果,IP Symbol中主要察看各种接口,Implementation Detals 中有较多的信息,比如结构,长度,数据宽度等,需要注的是CONFIG TDATA这一项,与配置接口的参数有关,在使用中需要正确配置。在当前的配置, FWD_INV使用1bit,为1时,做FFT;为0时做IFFT;由于选取的是不截位所以也不需要设置缩放因子,如果选取截位则不同的结构调整因子不同,详细的可以参看FFT的核文献。
在左侧有Latency这一栏,切忌如果你有多组64个数据,每一组的输入间隔务必大于这个数据处理时间(2.450us),否则仿真会出错。
最后附上代码(完全可以运行):仿真采用1~64循环输入间隔要大于数据处理时间
FFT代码:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/08/04 14:33:42
// Design Name:
// Module Name: FFT1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module FFT1(
input aclk,
input aresetn,
input en,
output [15:0]Out_Re,
output [15:0]Out_Im,
output out_En
);
reg [7:0] s_axis_config_tdata=8'b00000001;
reg s_axis_config_tvalid;
wire s_axis_config_tready;
reg [31 : 0] s_axis_data_tdata=0;
reg s_axis_data_tvalid;
wire s_axis_data_tready;
reg s_axis_data_tlast;
wire [47 : 0] m_axis_data_tdata;
wire [7 : 0] m_axis_data_tuser;
wire m_axis_data_tvalid;
reg m_axis_data_tready;
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;
always @(posedge aclk)
begin
if(en)
begin
s_axis_config_tvalid = 0;
s_axis_data_tlast = 0;
m_axis_data_tready = 0;
end
else
begin
m_axis_data_tready = 1;
s_axis_config_tvalid = 1;
s_axis_data_tlast = 1;
end
end
reg [9:0] cntttt=0;
always @(posedge aclk)
begin
if((cntttt >= 200)&&(cntttt <= 262))
begin
s_axis_data_tvalid <= 1;
s_axis_data_tdata <=s_axis_data_tdata+1;
s_axis_data_tlast <= 0;
cntttt<= cntttt+1;
end
else if( (cntttt>=0)&&(cntttt<=199))
begin
s_axis_data_tvalid <= 0;
s_axis_data_tdata <=0;
s_axis_data_tlast <= 0;
cntttt<= cntttt+1;
end
else if(cntttt == 263)
begin
s_axis_data_tvalid <= 1;
s_axis_data_tdata <=s_axis_data_tdata+1;
s_axis_data_tlast <= 1;
cntttt<= cntttt+1;
end
else if((cntttt>=264)&&(cntttt<=480))//为了比数据处理时间高
begin
s_axis_data_tvalid <= 0;
s_axis_data_tdata <=0;
s_axis_data_tlast <= 0;
cntttt<= cntttt+1;
end
else
begin
cntttt<=200;
s_axis_data_tvalid <= 0;
s_axis_data_tdata <=0;
s_axis_data_tlast <= 0;
end
end
xfft_0 uut (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tdata(s_axis_config_tdata), // input wire [15 : 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 [63 : 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 [79 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output wire [7 : 0] m_axis_data_tuser
.m_axis_data_tvalid(out_En), // 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
);
assign Out_Re = m_axis_data_tdata[15:0];
assign Out_Im = m_axis_data_tdata[39:24];
endmodule
测试代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/08/04 14:14:07
// Design Name:
// Module Name: tset
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tset;
reg clk1=1;
reg aresetn;
reg en;
wire [15:0] Out_Re;
wire [15:0] Out_Im;
wire out_En;
initial begin
aresetn=0;
en=1;
#150
aresetn=1;
en=0;
end
always#5 clk1=!clk1;
FFT1 FFT(clk1,aresetn,en,Out_Re,Out_Im,out_En);
endmodule
仿真结果:
Matlab仿真程序:
N=64;
X=zeros(1,N);
for i=1:N;
X(i)=i;
end
Y=fft(X)
X_real=real(Y)
X_imag=imag(Y)
Matlab仿真结果:
可以看出仿真结果几乎一致
最后本文只介绍了FFT的结果,自己在做IFFT时结果和matlab结果差距很大也不知道问题在哪,欢迎各位大佬讨论补充。