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