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

相关推荐
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
ZPC82106 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82106 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习