fft_cepin

  fft测频模块是整个工程的最后一个模块,该模块实现了频率和幅值的测量,先说一下缩放因子source_exp(有符号).我看网上的

资料说如果缩放因子是负数则左移相应的位数,如果是整数则右移相应位数,实际测试发现缩放因子基本上围绕着固定的两个数变化,

而实际的幅值跟fft变换出来的数据和缩放因子成线性关系。因为测量的是单一频率,并且fft在频域里面具有PI的对称性,所以只需要测

前半段就可以了,通过比较大小,数据最大的值就是该频率所处在的位置。通过实测发现1hz,10Hz,100Hz是比较准确的,1KHZ测

出的幅值有很大误差,我感觉是课本上说的栅栏效应,频率分辨率太低导致的。

/*-----------------------------------------------------------------------

Date                :        2017-XX-XX
Description            :        Design for fft cepin.

-----------------------------------------------------------------------*/

module cepin
(
    //global clock
    input                    clk,            //system clock
    input                    rst_n,             //sync reset
    
    //samclk  interface
    input            [1:0]    key_data,
    
    //sqrt        interface
    
    input            [12:0]    q_sig,
    
    //fft      interface
    input            [5:0]    source_exp,      
//缩放因子,通过数据记录发现规律,如果source_exp = 53 则fuzhi(mv) = 4*source_exp
//source_exp = 54 则fuzhi(mv) = 2*source_exp
    
    //ram  interface    
    input            [10:0]    wr_ram,
    
    //pinlv interface

    output    reg        [31:0]    f1,        //
    output    reg        [11:0]    a1
    
); 




//--------------------------------
//Funtion :  pinlv1分辨率
reg            [15:0]        fp;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        fp <= 16'd0;
    else
        case(key_data)
        2'b00 : fp <= 16'd1;
        2'b01 : fp <= 16'd10;
        2'b10 : fp <= 16'd100;
        2'b11 : fp <= 16'd1000;
        default : ;
        endcase
end


//--------------------------------
//Funtion :  比较
reg            [12:0]        temp1;
reg            [12:0]        temp2;
reg            [12:0]        temp3;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        temp1 <= 13'd0;
        temp2 <= 13'd0;
        temp3 <= 13'd0;
    end
    else
    begin
        temp1 <= q_sig;
        temp2 <= temp1;
        temp3 <= temp2;
    end
end


//--------------------------------
//Funtion :  测频状态机

reg            [1:0]        state_fft;
reg            [12:0]        a_temp;
reg            [31:0]        f_temp;
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        state_fft <= 2'd0;
        a_temp    <= 12'd0;
        f_temp    <= 32'd0;
    end
    else
        case(state_fft)
    //因为FFT频域是对称分布的,所以只测正半周期即可
        
        3'd0 :
        begin
            if(wr_ram == 11'd1)
            begin
                state_fft <= 1'd1;
                f_temp    <= 32'd0;
                a_temp      <= 12'd0;
            end
            else
                state_fft <= 1'd0;
        end
        
        3'd1 :
        begin
            if(wr_ram < 11'd1024)
            begin
                state_fft <= 3'd1;
                if(temp2 - temp1 > 3'd2 && temp2 > temp3)
                begin
                    if(temp2 > a_temp)
                    begin
                        f_temp <= wr_ram;
                        a_temp <= temp2;
                    end
                end
            end
            else
                state_fft <= 3'd2;
        end
        
        3'd2 :
        begin
            state_fft <= 3'd0;
        end
        
        default : ;
        endcase
end


//--------------------------------
//Funtion :  0.5S稳定

/* parameter        HALF_S = 32'd25_000_000;

reg            [31:0]        cnt_s;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt_s <= 32'd0;
    else if(cnt_s == HALF_S - 1'b1)
        cnt_s <= 32'd0;
    else
        cnt_s <= cnt_s + 1'b1;
end

reg            [11:0]        a_temp1;
reg            [31:0]        f_temp1;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        a_temp1 <= 12'd0;
        f_temp1 <= 32'd0;
    end
    else if(cnt_s == HALF_S - 1'b1)
    begin
        a_temp1 <= a_temp;
        f_temp1 <= f_temp;
    end
end */

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        f1 <= 32'd0;
    else if(state_fft == 3'd2)
        f1 <= f_temp * fp;
end


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        a1 <= 12'd0;
    else if(source_exp == 6'd53 && state_fft == 3'd2)
        a1 <= a_temp << 2'd2;
    else if(source_exp == 6'd54 && state_fft == 3'd2)
        a1 <= a_temp << 1'd1;
end


endmodule 
原文地址:https://www.cnblogs.com/bixiaopengblog/p/7265187.html