当前位置:   article > 正文

FPGA学习专题-FFT IP核的使用_使用quartus的fft只输出第一帧变换数据

使用quartus的fft只输出第一帧变换数据

之前从来没有接触过FFT,但是工作需求,让我不得不对它下手。
具体的FFT的原理我不做过多说明,大概说下是做什么用的。简单说就是频谱分析,说的通俗点就是:一个50Hz的正弦波,对它进行FFT计算,可以得到以下一些信息: 1.该正弦波的频率 2.该正弦波的幅值
你可能会觉得这有什么用?但是你要知道,我输入进FFT的正弦波,事先你是不知道它的任何信息的,包括频率和幅值。FFT就相当于一个盲盒,你给我一杯水我还你一片湖泊。

好,你大概知道了FFT是干嘛的就好了,接下来说怎么用?本文是基于ALTERA的Quartus 18.0版本设计。
step1:产生正弦波
当然,如果你有信号发生器,那就简单多了,不必像我这么麻烦的调DAC,我是使用的查表法,利用ROM中存放的mif文件,依次通过DAC输出,产生的正弦波。(DAC部分的内容会单独给一个专题)
step2:采样正弦波
这个也是一个关键步骤,你需要足够了解ADC的工作时序,采样频率。将上一步产生的正弦波输入进ADC进行采样,转化后的数据保存到一个RAM中,供FFT调用。(ADC部分的内容同样会单独给一个专题)
step3:FFT计算
如果上面比较顺利,那么这里估计会耽误一点时间。因为调用FFT IP核的时候,会有很多的参数,需要很清楚这些参数的功能以及工作时序。

假设你现在已经采样到正弦波数据并且保存到RAM中,准备给FFT使用了,我们开始配置。
①找到FFT IP核

在这里插入图片描述
②配置相关参数
主要参数包括采样点数 数据模式 位宽等。这里需要注意,红框中的两个选项都要执行,不然运行会有报错。

在这里插入图片描述

IP核的配置基本就这些了,然后会生成可以例化的代码,如下

module fft3 (
		input  wire        clk,          //    clk.clk IP核的参考时钟
		input  wire        reset_n,      //    rst.reset_n  复位线
		input  wire        sink_valid,   //   sink.sink_valid  输入数据有效信号
		output wire        sink_ready,   //       .sink_ready  表示FFT IP核准备好接收数据了,实测的时候该信号一直是高电平
		input  wire [1:0]  sink_error,   //       .sink_error  输入报错标志 输入手动置0,不会有影响
		input  wire        sink_sop,     //       .sink_sop    输入数据起始
		input  wire        sink_eop,     //       .sink_eop		输入数据终止
		input  wire [15:0] sink_real,    //       .sink_real	输入数据的实部
		input  wire [15:0] sink_imag,    //       .sink_imag	输入数据的虚部 一般都会直接置0
		input  wire [0:0]  inverse,      //       .inverse		FFT模式选择 正计算置0 逆运算置1
		output wire        source_valid, // source.source_valid		输出数据有效
		input  wire        source_ready, //       .source_ready		准备好输出数据 一般直接拉高,表示一直准备着,随时可以输出数据
		output wire [1:0]  source_error, //       .source_error		输出报错
		output wire        source_sop,   //       .source_sop		输出数据的起始
		output wire        source_eop,   //       .source_eop		输出数据终止
		output wire [15:0] source_real,  //       .source_real		输出数据实部
		output wire [15:0] source_imag,  //       .source_imag		输出数据虚部
		output wire [5:0]  source_exp    //       .source_exp		输出数据缩放因子,实际输出的实部和虚部需要乘以2^source_exp
	);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

还是再上个图看看吧
在这里插入图片描述
这些就是在FFT计算的时候需要考虑的一些变量,需要做的就是控制几个输入的信号,来完成整个的FFT计算过程,那么这个就是需要参考各个信号的时序图了。

我们在配置IP核的时候,选择的模式是streaming,因此,找到官方文档查看时序图,如下:
在这里插入图片描述
将输入的波形放大,如下:
在这里插入图片描述
简单分析一下数据输入的时序流程: 当reset拉高后,sink_valid和sink_ready都被直接拉高,sink_valid是需要自己拉高的,sink_ready是IP核自己拉高的,这个值我实测好像是一直是高电平;inverse需要手动拉低;然后给sink_sop一个高脉冲,这时候数据就会开始往FFT中传输了;但是图中没有给出什么时候停止,当sink_eop拉高一个脉冲时,这一帧数据输入完成。FFT就会对sink_sop和sink_eop两个高脉冲之间输入的数据进行FFT计算。这之间的数据点数就是上面设置的1024,当然这个点数由你自己定,数据越多,精度会越高,占用内存也就越高。

然后看一下数据输出的时序图,如下:
在这里插入图片描述
和输入数据类似的:source_ready和sink_valid拉高,表示可以输出了,注意这里的source_ready是手动拉高的,默认一直是高,sink_valid是FFT核拉高的,实测好像一直是高;然后当数据可以输出时,FFT核会将source_sop拉高一个高脉冲,当输出完成1024个数据时,FFT核会将source_eop拉高一个高脉冲,表示一帧数据完成输出。这样就完成了对一帧数据的FFT计算,请注意,这里的一帧数据实际是要计算1024次的,因为有1024个点啊。

最终需要用到的数据就是source_real和source_imag。将这两个值进行平方和计算,然后再开根号,得到的结果我们暂时记作fft_out吧,就是我们需要使用的值。

具体怎么用呢?一开始我们设置了对1024个输入的点进行FFT计算,每一点都会计算得到一组source_real和source_imag,对应的就可以计算出一个fft_out;那么最终就会有1024个fft_out,我们需要在这1024个数据中找到fft_out最大的那个点,假设是第n个点(点号从0-1023计算),那么采样的这个波形的频率就是Fout=(n-1)*Fs/N;其中,Fout是需要测量的信号的频率,n是计算的点号,Fs是ADC的采样频率(这个会在ADC专题中说明),N是采样点数,就是这里的1024。

简单的流程说完了,上示例:


module FFT_Control_Module
(
	//输入端口
	CLK_50M,RST_N,data_real_in_int,
	//输出端口
	fft_bit_cnt,fft_x_cnt,
	vga_freq,vga_fengzhi,
	fft_out,sink_sop,
	sink_ready,sink_valid,
	sink_eop,fft_start,source_error,source_sop,source_eop,source_valid,max_cnt,position,data_max
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input					CLK_50M;
input					RST_N;
input 	[ 15:0]	data_real_in_int;//[ 9:0]
output   [10:0] 	fft_bit_cnt;
output   [10:0] 	fft_x_cnt;
output 	[31:0] 	vga_freq;
output 	[31:0] 	vga_fengzhi;
output 	[ 15:0] 	fft_out;//
output sink_sop;
output sink_ready;
output reg sink_valid;
output sink_eop;
output reg fft_start;
output [1:0] source_error;
output source_sop;
output source_eop;
output source_valid;
output reg [10:0] max_cnt;
output reg [10:0] position;
output reg [15:0] data_max;
//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
wire					inverse;
wire 		[ 15:0] 	data_imag_in_int;//[ 9:0]
wire 		[ 9:0] 	fftpts_array;
wire		[ 1:0]	sink_error;
//wire					sink_ready;
//reg					sink_valid;
reg					sink_valid_n;
wire					fft_ready_valid;
reg		[10:0]	fft_bit_cnt;
reg		[10:0]	fft_bit_cnt_n;
//wire					sink_sop;
//wire					sink_eop;
reg		[ 15:0]	sink_real;
reg		[ 15:0]	sink_real_n;
reg		[ 15:0]	sink_imag;
reg		[ 15:0]	sink_imag_n;
wire 					end_input;
reg					end_test;
reg					end_test_n;
wire					source_ready;
wire					source_valid;
wire	 	[ 15:0]	source_real;
reg 		[ 15:0] 	fft_real_out_int;
reg 		[ 15:0] 	fft_real_out_int_n;
wire	 	[ 15:0]	source_imag;
reg 		[ 15:0]	fft_imag_out_int;
reg 		[ 15:0] 	fft_imag_out_int_n;
wire		[ 5:0]	source_exp;
reg 		[ 5:0]	exponent_out_int;	
reg 		[ 5:0]	exponent_out_int_n;
reg 		[31:0] 	fft_real_image_data;
reg 		[31:0] 	fft_real_image_data_n;
wire		[15:0] 	sqrt_data_out;
wire					fft_read;
//wire					source_sop;
reg   	[ 10:0] 	fft_x_cnt;
reg  		[ 10:0] 	fft_x_cnt_n;
//reg 		[ 15:0] 	data_max;
reg 		[ 15:0] 	data_max_n;
reg 		[ 15:0] 	data_max2;
reg 		[ 15:0] 	data_max2_n;
//reg 		[ 10:0] 	max_cnt;
reg 		[ 10:0] 	max_cnt_n;
reg 		[ 10:0] 	max_cnt2;
reg 		[ 10:0] 	max_cnt2_n;
reg 		[15:0] 	fengzhi_max;
reg 		[15:0] 	fengzhi_max_n;
reg 		[15:0] 	fengzhi_min;
reg 		[15:0] 	fengzhi_min_n;
wire 		[31:0] 	vga_freq;
wire 		[31:0] 	vga_fengzhi;
wire 		[ 10:0] 	fft_out;

reg  [15:0] frames_in_index;
reg  [15:0] frames_out_index;

reg [9:0] position_r;


//reg fft_start;
reg fft_start_n;
//---------------------------------------------------------------------------
//--	逻辑功能实现	
//---------------------------------------------------------------------------
/* FFT控制信号,1:IFFT,0:FFT */
assign 	inverse = 1'b0;

/* FFT输入数据信号 */
assign	data_imag_in_int = 16'b0;

/* FFT数据的个数为1024 */
assign	fftpts_array = 10'd1023;

/* 输入错误信号 */
assign 	sink_error = 2'b0;

//start valid for first cycle to indicate that the file reading should start.
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fft_start <= 1'b1;
	else 
		fft_start <= fft_start_n;
end

always@(*)
begin
	if(fft_ready_valid)//sink_valid为1时该式成立,则fft_start_n变为0,也就是两个信号同时会有脉冲信号产生
		fft_start_n = 1'b0;
	else
		fft_start_n = 1'b1;
end

//输入数据帧数
  // count the input frames and increment the index
  always @(posedge CLK_50M or negedge RST_N)
    begin
       if (RST_N == 1'b0)
         frames_in_index <= 'd0;
       else
         begin
            if (sink_eop == 1'b1 & sink_valid == 1'b1 & sink_ready == 1'b1 & frames_in_index < 3000)输入数据的次数,即输入进1024个点就算一帧数据
              frames_in_index <= frames_in_index + 1'b1;
         end
   end 
	
	   // count the output frames and increment the index 这个定义的是输入数据帧数,实际我没使用,而是一直输入进行FFT计算
   always @(posedge CLK_50M or negedge RST_N)
    begin
       if (RST_N == 1'b0)
        frames_out_index <= 'd0;
       else
         begin
            if (source_eop == 1'b1 &  source_valid == 1'b1 & source_ready == 1'b1 & frames_out_index < 3000)
              frames_out_index <= frames_out_index + 1'b1;
         end
    end 

/* 时序电路,用来给sink_valid寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		sink_valid <= 1'b0;
	else
		sink_valid <= sink_valid_n;
end

/* 组合电路,输入的有效信号 */
//***********************无效
always @ (*)
begin
	if(end_test || end_input)//end_input = (sink_eop && fft_ready_valid) ? 1'b1 : 1'b0;

		sink_valid_n = 1'b0;
	else if(fft_ready_valid || (fft_start == 1'b1 & !(sink_valid == 1'b1 & sink_ready == 1'b0)) )//(fft_start & !(sink_valid && sink_ready == 1'b0)))
		sink_valid_n <= 1'b1;
	else
		sink_valid_n = 1'b1;
end
//*********************************/

//always@(*)//组合逻辑一般用阻塞赋值
//begin	
//		if(end_test || end_input)
//			sink_valid_n = 1'b1;
//		else
//			sink_valid_n = 1'b1;
//end


/* 输入开始进行FFT转换运算 */
assign	fft_ready_valid = (sink_valid && sink_ready);//sink_ready貌似都是正的

/* 时序电路,用来给fft_bit_cnt寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fft_bit_cnt <= 10'b0;
	else
		fft_bit_cnt <= fft_bit_cnt_n;
end

/* 组合电路,FFT位计数器 */
always @ (*)
begin
	if(fft_ready_valid && (fft_bit_cnt == fftpts_array))
		fft_bit_cnt_n = 1'b0;		
	else if(fft_ready_valid)//这个判断,一开始这里因为sink_valid为0进不来
		fft_bit_cnt_n = fft_bit_cnt + 1'b1;
	else
		fft_bit_cnt_n = fft_bit_cnt;
end

/* 输入流的开始 */
assign sink_sop = (fft_bit_cnt == 1'b0) ? 1'b1 : 1'b0 ;

/* 输入流的结束 */
assign sink_eop = (fft_bit_cnt == fftpts_array) ? 1'b1 : 1'b0;

/* 时序电路,用来给sink_real寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		sink_real <= 10'b0;
	else
		sink_real <= sink_real_n;
end

/* 组合电路,输入的实部信号 */
always @ (*)
begin
	if(end_test || end_input)//1024个数据已经输入完成了
		sink_real_n = 10'b0;
	else if (fft_ready_valid)//(sink_valid && sink_ready)
		sink_real_n = data_real_in_int;
	else
		sink_real_n = sink_real;
end

/* 时序电路,用来给sink_imag寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		sink_imag <= 10'b0;
	else
		sink_imag <= sink_imag_n;
end

/* 组合电路,输入的虚部信号 */
always @ (*)
begin
	if(end_test || end_input)
		sink_imag_n = 10'b0;
	else if (fft_ready_valid)
		sink_imag_n = data_imag_in_int;
	else
		sink_imag_n = sink_imag;
end

/* 停止输入信号 */ //signal when all of the input data has been sent to the DUT
assign	end_input = (sink_eop && fft_ready_valid&& frames_in_index == 3000) ? 1'b0 : 1'b0;

/* 时序电路,用来给end_test寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		end_test <= 1'b0;
	else
		end_test <= end_test_n;
end

/* 组合电路,结束测试信号 */
always @ (*)
begin
	if(end_input)
		end_test_n = 1'b1;
	else
		end_test_n = end_test;
end

/* 源准备信号 */
assign	source_ready  = 1'b1; 

/* 时序电路,用来给fft_real_out_int寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fft_real_out_int <= 10'b0;
	else
		fft_real_out_int <= fft_real_out_int_n;
end

/* 组合电路,FFT输出的实部信号 */
always @ (*)
begin
	if(source_valid && source_ready)
		fft_real_out_int_n = source_real[15] ? (~source_real[15:0]+1) : source_real;
	else
		fft_real_out_int_n = fft_real_out_int; 
end

/* 时序电路,用来给fft_imag_out_int寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fft_imag_out_int <= 10'b0;
	else
		fft_imag_out_int <= fft_imag_out_int_n;
end

/* 组合电路,FFT输出的虚部信号 */
always @ (*)
begin
	if(source_valid && source_ready)
		fft_imag_out_int_n = source_imag[15] ? (~source_imag[15:0]+1) : source_imag;
	else
		fft_imag_out_int_n = fft_imag_out_int;
end

/* 时序电路,用来给exponent_out_int寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		exponent_out_int <= 10'b0;
	else
		exponent_out_int <= exponent_out_int_n;
end

/* 组合电路,用于生成FFT输出的指数信号 */
always @ (*)
begin
	if(source_valid && source_ready)
		exponent_out_int_n = source_exp;
	else
		exponent_out_int_n = exponent_out_int;
end

/* 时序电路,用来给fft_real_image_data寄存器赋值 */
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fft_real_image_data <= 32'b0;
	else
		fft_real_image_data <= fft_real_image_data_n;
end

/* 组合电路,用于生成FFT输出的数据信号 */
always @ (*)
begin
	if(source_valid && source_ready)
		fft_real_image_data_n = fft_real_out_int*fft_real_out_int + fft_imag_out_int*fft_imag_out_int;
	else
		fft_real_image_data_n = fft_real_image_data;
end

/* 平方根模块 */
SQRT_Module		SQRT_Init 
(
	.radical 	(fft_real_image_data ),
	.q 			(sqrt_data_out 		)
);

/* 开始进行FFT转换运算 */
assign fft_read = (source_valid && source_ready);



/* 时序电路,用来给fft_x_cnt寄存器赋值 */
//***************找最大值可以用,但是最大位置值会复位累计 
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N) begin
		position <= 1'b0;
		fft_x_cnt <= 1'b0;
		data_max <= 1'b0;
		end
	else begin
		position <= position_r;
		data_max <= data_max_n;
		fft_x_cnt <= fft_x_cnt_n;
		end
end
//********/

/* 组合电路,用于生成FFT输出数据的计数器 */
//**********找最大值可以用,但是最大位置值会复位累计
always @ (*)
begin
	
	if(fft_ready_valid && (source_sop || (fft_x_cnt == fftpts_array)))begin//输出完成后
		fft_x_cnt_n = 1'b0;	
		position_r = 1'b0;
		data_max_n= 1'b0;
		end
	else if(fft_read) begin  //assign fft_read = (source_valid && source_ready);
	
		fft_x_cnt_n = fft_x_cnt + 1'b1;
		
		if(sqrt_data_out > data_max && fft_x_cnt > 2 && fft_x_cnt < 512) begin
		data_max_n= sqrt_data_out;
		position_r= fft_x_cnt -2'd2;
			end
			
		else
		data_max_n= data_max_n;
		position_r= position_r;
		
		end
		
	else
		
		fft_x_cnt_n = fft_x_cnt;
end
//****************/


*//
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fengzhi_max <= 16'b0;
	else
		fengzhi_max <= fengzhi_max_n;
end

always @ (*)
begin
	if(data_real_in_int > fengzhi_max)
		fengzhi_max_n = data_real_in_int;
	else
		fengzhi_max_n = fengzhi_max;
end

always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		fengzhi_min <= 16'd255;
	else
		fengzhi_min <= fengzhi_min_n;
end

always @ (*)
begin
	if(fengzhi_min > data_real_in_int)
		fengzhi_min_n = data_real_in_int;
	else
		fengzhi_min_n = fengzhi_min;
end

assign	vga_freq = (position) * 32'd147000 >> 8'd10;//ADC的采样频率147KHz F=Fs*n/N;Fs是采样频率,n是第几个点,N是采样点数,本例中是1024

assign	vga_fengzhi = ((fengzhi_max - fengzhi_min) * 10'd50) >> 8'd8; 

assign 	fft_out = sqrt_data_out;


fft3 fft_init
(
	.clk					(CLK_50M			),//
	.reset_n				(RST_N			),//
	.inverse				(inverse			),//
	.sink_valid			(sink_valid		),//input
	.sink_sop			(sink_sop		),//	
	.sink_eop			(sink_eop		),//
	.sink_real			(sink_real		),//
	.sink_imag			(sink_imag		),//
	.sink_error			(sink_error		),//
	.source_ready		(source_ready	),//
	.sink_ready			(sink_ready		),//output
	.source_error		(source_error	),//
	.source_sop			(source_sop		),//
	.source_eop			(source_eop		),//
	.source_valid		(source_valid	),//
	.source_exp			(source_exp		),//
	.source_real		(source_real	),//
	.source_imag		(source_imag	)//
);


endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480

代码中有很多的测试代码也放在里面了,也是自己调试过程中的记录,当然,这个是FFT部分的代码,并不是整个工程的,也仅供参考。在计算最大值方面还存在一些问题,就是每次有新的数据帧输入的时候,上一步中计算出来的最大值会被复位,导致输出不会一直稳定,所以在输入一个稳定正弦波的时候,无法一直输出稳定的频率,而是一直在查找过程,不过基本是验证了该方法的可行性,高手可以帮修改一下。

下面是测试波形图:
在这里插入图片描述
我输入的是2000Hz的正弦波,计算出来的值是2009,允许误差。可以增加采样点数,提高精度。
以上就是FFT调试过程的记录,供以后查阅。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/913020
推荐阅读
相关标签
  

闽ICP备14008679号