基于FPGA利用FFT,CORDIC分析数据频谱

  • Post author:
  • Post category:其他




前言

FFT在数字信号处理用得非常普遍,对此我专门做了一个数字信号入门级的题目。而且也是很重要的一个题目,涉及的知识点非常多,有信号生成,FFT分析,CORDIC计算也包括Matlab软件,ISE软件,Modelsim,Debussy的使用等。对于想要做数字信号处理相关的同学,可以以此为基础,展开深入学习,定能取得事办功倍的效果。



专题说明

首先利用Matlab软件,生成两组信号,然后将两组信号以coe文件的形式存在FPGA的ROM中,按一定的时钟频率读出再送入FFT IPCORE,经过FFT分析以后,得到信号的实部和虚部,再将实部数据和虚部数据送入CORDIC IPCORE,经过计算便可以得到两个信号的幅度和相位。将两个相位相减即可得到相位差。



准备工作

  1. Matlab软件
  2. ISE 14.6软件
  3. Modelsim仿真软件
  4. Debussy波形查看软件



理论分析



Matlab代码分析

%%%%%%%%%%%%%生成两路被测信号%%%%%%%%%%
N=1024;%采样点数
w=pi/4;%采样角频率
n=0:1:N-1;
s=wgn(1,1024,-20)%高斯白噪声
y0=0.5*cos(w.*n);
y1=0.4*cos(w.*n+pi/2);
z0=y0+s;%生成第一路信号
z1=y1+s;%生成第二路信号
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%在实际项目中,我们都是用的AD去采集外部信号,为了尽可能模拟真实环境,我们做一下AD量化
v0=round(z0*1000/0.366);%量化成AD
v1=round(z1*1000/0.366);%量化成AD
%%由于Cos波形有正有负,FPGA只能利用补码的形式来处理负数,所以还需要进行补码的转换
k=1;
i=1;
M=12;
ad_data0=zeros(1,1024)
ad_data1=zeros(1,1024)
for k=1:N
	if(v0(k)>=0)
		ad_data0(k)=v(k);
	else
		ad_data0(k)=2^M+v(k);
	end
end
for i=1:N
	if(v1(i)>=0)
		ad_data1(i)=v1(i);
	else
		ad_data1(i)=2^M+v1(i);
	end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
将ad_data0,ad_data1以mif的格式存储起来,因为我们用的是ISE,
在给ROM添加文件的时候,只能是COE文件,所以,我们还要将
生成的mif文件手动改成COE文件,并保存
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fild=fopen('data0.mif','wt');
fprintf(fild,'%s\n','WIDTH=8;');
fprintf(fild,'%s\n\n','DEPTH=1024;');
fprintf(fild,'%s\n','ADDRESS_RADIX=UNS;');
fprintf(fild,'%s\n\n','DATA_RADIX=HEX;');
fprintf(fild,'%s\t','CONTENT');
fprintf(fild,'%s\n','BEGIN');
for i=1:1024
	fprintf(fild,'\t%g\t',i);
	fprintf(fild,'%s\t',':');
	fprintf(fild,'%d',ad_data0(i));
	fprintf(fild,'%s\n',' ');
end
fprintf(fild,'%s\n','END');
fclose(fild);

fild=fopen('data1.mif','wt');
fprintf(fild,'%s\n','WIDTH=8;');
fprintf(fild,'%s\n\n','DEPTH=1024;');
fprintf(fild,'%s\n','ADDRESS_RADIX=UNS;');
fprintf(fild,'%s\n\n','DATA_RADIX=HEX;');
fprintf(fild,'%s\t','CONTENT');
fprintf(fild,'%s\n','BEGIN');
for i=1:1024
	fprintf(fild,'\t%g\t',i);
	fprintf(fild,'%s\t',':');
	fprintf(fild,'%d',ad_data1(i));
	fprintf(fild,'%s\n',' ');
end
fprintf(fild,'%s\n','END');
fclose(fild);
%%%%%%%%%%%计算相位差%%%%%%%%%%%%%
abs_max0=max(abs(f0))%f0是幅度
abs_max1=max(abs(f1))%f1是幅度
flag0=find(abs(f0)==abs_max0)
flag1=find(abs(f1)==abs_max1)
phase_0=angle(f(flag0))%得到幅度最大的相位
phase_1=angle(f(flag1))%得到幅度最大的相位
diff_phase=phase_1-phase_0;%两个相位相减,得到相位差



Matlab实现效果

在这里插入图片描述

用Matalb生成的两路加了高斯噪声的信号

在这里插入图片描述

在Matlab中利用FFT分析出了两路信号的频率和幅值

在这里插入图片描述

最终计算出两路信号的相位差(diff_phase)



FPGA代码分析



FPGA仿真波形分析

在这里插入图片描述

两路信号,在Debussy中选择用analog显示

在这里插入图片描述

将信号灌入FFT IPCORE,经过计算我们可以看出fft_out_real在fft_out_dvld为高电平时,有一个脉冲,即在该点的能量最大,接下来,我们将波形放大,看这个能量最大的点具体在xk_index的哪个位置。

在这里插入图片描述

我们可以看到在xk_index=128时,fft_out_real的幅值最大。与理论相符

FFT只能分析信号的频率,如果想要得到信号的相位,那么我们还需要用到CORDIC这个IPCORE。接着看仿真波形,如下:

在这里插入图片描述

我们可以看到,在CORDIC输出(x_out),依然有一个能量最大值,该最大值对应的phase_out便是该信号的相位,单单说一个信号的相位是没有任何意义的,必须要有一个参考,所以我们在分析相位时,通常是分析两个信号或者多个信号的相位差。我们将波形放大,读出相位值。

在这里插入图片描述

从图中可以看出,第一路信号的相位值是12’hfff。然后,我们看一下第二路信号的相位值,如下图:

在这里插入图片描述

第二路的相位值是12’h31f,此时看到这两个相位值一脸懵逼,这个差值到底是多少呢?怎么和Matlab计算出来的相位差不一致呢?哈哈,这个问题当时也困扰了我很久,后来看CORDIC IPCORE的数据手册,终于找到了答案。具体的计算过程,我稍后再做分析,写这篇博客也花了太长时间了,休息一下,加上最近也比较忙,等手上事情忙完了,再做仔细分析,读者朋友也可自行分析,多看看数据手册,答案就出来了。希望能给各位起到抛砖引玉的作用!如有不正确之处,望指出,大家一起学习,一起进步,谢谢!



结语

读者朋友可以先看一下整体的思路,具体的分析过程还未整理,未完待续。。。。



版权声明:本文为Moon_3181961725原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。