FPGA学习-FFT变换-解决频率低信号进行FFT运算的取点问题
- 前言
- 一、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的数据输入
`timescale 1ns / 1psmodule 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) beginif(!rst_n)beginaddrI<=30'd0;endelse beginaddrI<=addrI+Fre_I;endendassign 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
`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)beginif(!rst_n)begincount<=8'd0; end else if(count<8'd10)begincount<=count+1;endelse begincount<=3'd0;endend
always @(posedge clk or negedge rst_n)beginif(!rst_n)begins_axis_data_tlast<=1'd0; end else if(ddc_count=='d512 && count==8'd10)begins_axis_data_tlast<=1'b1;endelse begins_axis_data_tlast<=1'b0;endendalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginddc_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)beginsignal_ddc<=signal;
// wr_en<=1'b1;s_axis_data_tvalid<=1'b1;ddc_count<=ddc_count+1;s_axis_data_tdata<={8'd0,signal};endelse if(count==8'd10 && ddc_count==512)beginddc_count<=8'd0;endelse begin
// wr_en<=1'b0; s_axis_data_tvalid<=1'b0;signal_ddc<=signal_ddc;s_axis_data_tdata<=s_axis_data_tdata;endend
//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)beginif(!rst_n)beginrd_en1<=1'd0; end else if(rd_data_count1==10'd511)beginrd_en1<=1'b1;endelse if(rd_data_count1==9'd1)beginrd_en1<=1'd0;end
endfifo_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,完成对信号的采样。