FPGA学习-FFT变换-解决频率低信号进行FFT运算的取点问题
前言
首次接触FFT变换是在OFDM中,QAM后的实部信号与虚部信号需要进行FFT转化,将频域信号转化为时域信号,最终通过DA接口转化为模拟信号。当时对于FFT的理解比较浅,对离散傅里叶的变化了解也少之又少。
通过结合MTALAB进行了FFT变化操作,了解了直流分量以及FFT的基本计算。后期在vivado中调用fft的ip核遇到了很多问题。踩过的坑一一写在下面,希望能给路过的各位提供一点点价值:
1.fft ip核的配置,端口含义
config相关数据的配置、ifft、fft对应0和1。
输入端口不要产生高阻态,也就是说reg相关变量要有初始值,否则ip核不能运行起来。
2.fft点数问题
对信号作fft变换,取点最好大于2-3个周期,为了保障fft变换的可靠性。后来遇到一个问题,由于信号频率太低,因此信号一个周期的点数很多,所以我想取够周期数就导致fft的ip核的点数配置很高。后来通过控制vilad,定点抽样信号,大大降低了fft 的配置点数。
3.fft与FIFO的配合
fft计算有时候会限制时间,因此信号需要先提速,fft本身也需要提速,因此可以通过FIFO转换。
一、FFT输入
调用ROM ip核8*256生成sin信号,频率为30k 系统clk 50mhz 该信号作为后面FFT的数据输入
c
`timescale 1ns / 1ps
module DDS(
input clk,
input rst_n,
output wire [7:0] douta
);
//50000000/256=195312 根据clk增加地址 就产生195k的正弦波
//产生30k的正弦波 30000/195312=0.1536 0.1536*2^22=644,245
parameter Fre_I = 32'd644245;
//8*256 rom
wire [7:0] addra;
reg [29:0] addrI;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
addrI<=30'd0;
end
else begin
addrI<=addrI+Fre_I;
end
end
assign addra =addrI[29:22];
blk_mem_gen_0 u_sin (
.clka(clk), // input wire clka
.addra(addra), // input wire [7 : 0] addra
.douta(douta) // output wire [7 : 0] douta
);
endmodule
二、FFT配置
FFT的ip核配置以及FIFO的配置,FFT点512
c
`timescale 1ns / 1ps
module FFT(
input clk,
input rst_n,
input [7:0] signal,
output reg [7:0] signal_ddc
);
reg [7:0] count;
reg [9:0] ddc_count;
wire [7:0] signal_fifo;
//wire [8:0] rd_data_count;
//wire [8:0] wr_data_count;
wire [8:0] rd_data_count1;
wire [8:0] wr_data_count1;
//reg wr_en;
//reg rd_en;
//wire full;
//wire empty;
reg rd_en1;
wire full1;
wire empty1;
wire [15:0] fft_fifo;
wire s_axis_config_tvalid = 1;
wire s_axis_config_tready ;
reg signed [15:0] s_axis_data_tdata;
wire s_axis_data_tready ;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
wire m_axis_data_tvalid;
wire m_axis_data_tready = 1;
wire m_axis_data_tlast=0;
wire signed [15:0] m_axis_data_tdata;
wire [15:0] m_axis_data_tuser;
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 clk or negedge rst_n)begin
if(!rst_n)begin
count<=8'd0;
end
else if(count<8'd10)begin
count<=count+1;
end
else begin
count<=3'd0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
s_axis_data_tlast<=1'd0;
end
else if(ddc_count=='d512 && count==8'd10)begin
s_axis_data_tlast<=1'b1;
end
else begin
s_axis_data_tlast<=1'b0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ddc_count<=8'd0;
signal_ddc<=8'd0;
s_axis_data_tvalid<=1'b0;
// wr_en<=1'b0;
s_axis_data_tdata<=16'd0;
end
else if(count==8'd10 && ddc_count<512)begin
signal_ddc<=signal;
// wr_en<=1'b1;
s_axis_data_tvalid<=1'b1;
ddc_count<=ddc_count+1;
s_axis_data_tdata<={8'd0,signal};
end
else if(count==8'd10 && ddc_count==512)begin
ddc_count<=8'd0;
end
else begin
// wr_en<=1'b0;
s_axis_data_tvalid<=1'b0;
signal_ddc<=signal_ddc;
s_axis_data_tdata<=s_axis_data_tdata;
end
end
//always @(posedge clk or negedge rst_n)begin
// if(!rst_n)begin
// rd_en<=1'd0;
// end
// else if(wr_data_count==9'd511)begin
// rd_en<=1'b1;
// end
// else if(rd_data_count==9'd1)begin
// rd_en<=1'd0;
// end
//end
//fifo_generator_0 u_fifo(
// .wr_clk(clk), // input wire wr_clk
// .rd_clk(clk), // input wire rd_clk
// .din(signal_ddc), // input wire [7 : 0] din
// .wr_en(wr_en), // input wire wr_en
// .rd_en(rd_en), // input wire rd_en
// .dout(signal_fifo), // output wire [7 : 0] dout
// .full(full), // output wire full
// .empty(empty), // output wire empty
// .rd_data_count(rd_data_count), // output wire [8 : 0] rd_data_count
// .wr_data_count(wr_data_count) // output wire [8 : 0] wr_data_count
//);
xfft_0 u_fft (
.aclk(clk), // input wire aclk
.s_axis_config_tdata(16'd0), // 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 [15 : 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_tuser(m_axis_data_tuser), // output wire [15 : 0] m_axis_data_tuser
.m_axis_data_tdata(m_axis_data_tdata), // output wire [15 : 0] m_axis_data_tdata
.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
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rd_en1<=1'd0;
end
else if(rd_data_count1==10'd511)begin
rd_en1<=1'b1;
end
else if(rd_data_count1==9'd1)begin
rd_en1<=1'd0;
end
end
fifo_generator_1 u_fft1 (
.wr_clk(clk), // input wire wr_clk
.rd_clk(clk), // input wire rd_clk
.din(m_axis_data_tdata), // input wire [15 : 0] din
.wr_en(m_axis_data_tvalid), // input wire wr_en
.rd_en(rd_en1), // input wire rd_en
.dout(fft_fifo), // output wire [15 : 0] dout
.full(full1), // output wire full
.empty(empty1), // output wire empty
.rd_data_count(rd_data_count1), // output wire [9 : 0] rd_data_count
.wr_data_count(wr_data_count1) // output wire [9 : 0] wr_data_count
);
endmodule
波形分析

通过控制count控制s_axis_data_tvalid,完成对信号的采样。