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

相关推荐
一只乔哇噻2 小时前
java后端工程师+AI大模型开发进修ing(研一版‖day60)
java·开发语言·人工智能·学习·语言模型
暗然而日章2 小时前
C++基础:Stanford CS106L学习笔记 4 容器(关联式容器)
c++·笔记·学习
盐焗西兰花3 小时前
鸿蒙学习实战之路:Tabs 组件开发场景最佳实践
学习·华为·harmonyos
_Kayo_3 小时前
Next.js 路由 简单学习笔记
笔记·学习·next.js
盐焗西兰花3 小时前
鸿蒙学习实战之路 - 瀑布流操作实现
学习·华为·harmonyos
酒尘&3 小时前
Hook学习-上篇
前端·学习·react.js·前端框架·react
qq_381454994 小时前
Python学习技巧
开发语言·python·学习
im_AMBER4 小时前
算法笔记 18 二分查找
数据结构·笔记·学习·算法
XINVRY-FPGA4 小时前
XC3S1000-4FGG320I Xilinx AMD Spartan-3 SRAM-based FPGA
嵌入式硬件·机器学习·计算机视觉·fpga开发·硬件工程·dsp开发·fpga
van久4 小时前
.Net Core 学习: Razor Pages -- EF Core简介
学习·.netcore