FPGA学习-FFT变换-解决频率低信号进行FFT运算的取点问题

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,完成对信号的采样。

相关推荐
hahaha60161 小时前
RK3588和FPGA桥片之间IO电平信号概率性不能通信原因
单片机·嵌入式硬件·fpga开发
拾忆-eleven2 小时前
NLP学习路线图(十四):词袋模型(Bag of Words)
人工智能·学习·自然语言处理·nlp
拾忆-eleven4 小时前
NLP学习路线图(十五):TF-IDF(词频-逆文档频率)
人工智能·学习·自然语言处理·nlp
viperrrrrrrrrr75 小时前
大数据学习(125)-hive数据分析
大数据·学习
moxiaoran57537 小时前
uni-app学习笔记十八--uni-app static目录简介
笔记·学习·uni-app
Studying 开龙wu7 小时前
机器学习有监督学习sklearn实战二:六种算法对鸢尾花(Iris)数据集进行分类和特征可视化
学习·算法·机器学习
Lester_11018 小时前
嵌入式学习笔记 - STM32 HAL库以及标准库内核以及外设头文件区别问题
笔记·stm32·单片机·学习
Moonnnn.9 小时前
2023年电赛C题——电感电容测量装置
笔记·学习·硬件工程
拾忆-eleven10 小时前
NLP学习路线图(十六):N-gram模型
人工智能·学习·自然语言处理
hahaha601610 小时前
常见相机的ISP算法
数码相机·fpga开发