Xilinx FPGA FFT 应用笔记

Posted yijingjing17

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xilinx FPGA FFT 应用笔记相关的知识,希望对你有一定的参考价值。

这个是2012年写的,现在给放上来了,其实百度文库也有。

系统工作环境:

    芯片为:xilinxSpartan 6

    软件:ise 12.2

    IP coreFFT版本:7.1  

目标:完成对放大板的标定


一、标定的过程简单介绍:

放大板包含3级程控放大器的放大电路、4个可选择的高频滤波器、1个50Hz的工频滤波器,放大板主要是针对低频信号,放大频率范围:0-20KHz,

标定示意图:


         ◎offset 调节:控制放大板的输入接地,将放大器的放大倍数设置为1000倍,测试AD 的输出电压是否为0V,如果不是,则说明放大器内部有直流偏置,通过调节DA的offset输出电压,使得放大板在输入为0v时,输出也为0v。

          ◎直流标定:直流标定挺简单的,让DA输出固定的电位,设置放大器的倍数,看看输出是否与理论值一致。

例:输入为0.1mv,放大倍数为1000倍,检查输出是否为:0.1V ,目的主要是为了检查放大板对直流的响应。


          ◎交流标定:交流标定比较复杂,为了测量放大板对交流信号的响应,主要体现在放大器对信号的相频与幅频特性。


          ◎具体的做法:FPGA控制DA产生一个正弦波,再通过AD采集放大后的数据,并对其做FFT(快速傅里叶变换),计算出信号的相位与幅度,与输入的波形对比,检测放大板的对交流信号的响应。

     例:①输入f=1Hz,A=10mv,Phase = 0°的正弦波,测量输出的

信号的A、Phase、f。

              ②输入f=2Hz,A=10mv,Phase = 0°的正弦波,测量输出的

 信号的A、Phase、f

        ③输入f =3Hz……

………

⑩输入f =2000Hz……

其实简单点,就是一个频谱分析仪,求放大板的频谱图,看看放大器对交流信号有没有产生频移与幅度的衰减。

二、FGPA的工作

◎控制放大器,简单的IO应用

◎驱动ADS1274

◎驱动AD5664r

◎在内部生成一个DDS(直接数字频率合成器),输出频率、相位可调的正弦波。

◎对AD采集的数据进行FFT的转换。

三、DFT(离散傅里叶变换)的理解

3.1傅里叶变换的基础知识

其实,大学的时候几乎每个童鞋都学过傅里叶变换,应该算是必修的课程,但是当时我也就为考试,背背公式,不知道大家是什么心情,但是没有想过有一天居然真的用到了,表示很无力啊。

  在网上找了一下资料,也看了一些书。把一些感觉好的东西记录一下,加上自己的一些理解。

傅立叶是一位法国数学家和物理学家的名字,英语原名是:Jean Baptiste Joseph Fourier(1768-1830)Fourier对热传递很感兴趣,于1807年在法国科学学会上发表了一篇论文,运用正弦曲线来描述温度分布,论文里有个在当时具有争议性的决断:任何连续周期信号可以由一组适当的正弦曲线组合而成。

举个的例子理解下

在数学上,关于一个信号最基本的问题在于如何将它表示和描述出来。按照上面所说的办法,把一个信号理解成一个定义在时间或空间上的函数是一种自然而然的表示方式,但是它对理解这一信号的内容来说常常不够。例如一段声音,如果单纯按照定义在时间上的函数来表示,它画出来是这个样子的:



这通常被称为波形图。毫无疑问,它包含了关于这段声音的全部信息。但是同样毫无疑问的是,这些信息几乎没法从上面这个「函数」中直接看出来,事实上,它只不过是巴赫的小提琴无伴奏 Partita No.3 的序曲开头几个小节。下面是巴赫的手稿,从某种意义上说来,它也构成了对上面那段声音的一个「描述」:


这两种描述之间的关系是怎样的呢?第一种描述刻划的是具体的信号数值,第二种描述刻划的是声音的高低(即声音震动的频率)。人们直到十九世纪才渐渐意识到,在这两种描述之间,事实上存在着一种对偶的关系,而这一点并不显然。 

根据原信号的不同类型,我们可以把傅立叶变换分为四种类别:

  四种不同信号的变换结果:


摘自《数字信号处理》 王世一

。提问数字信号处理只能处理离散的信号,所以在以上的4种情况中,只有第4种是可行的,但是同时也参生了一个问题,就是信号必须是周期的,但是在实际的数据中,不一定都是周期的啊,这个怎么办呢!以下是在《Digitalsignal processing》(一个老外写的特别好的书)的图,看完图后应该就能明白了。


就是把有限长的信号进行复制,让其变成一个周期信号进行处理。

说到这,上一下离散傅里叶级数的公式:


上面是DFT的公式,至于怎么来的,我也尝试过搞明白,但是一头雾水,大致的情况是:

(连续周期信号的傅里叶变换)

    通过对连续的周期的信号的公式进行抽样处理,然后推到出来的,推的过程就很复杂了,也不太好理解。

3.2这样理解DFT的公式(不知道对不对??)

当我看到离散傅里叶级数的公式:


我的第一个感觉就是,他代表的是什么意思啊,凭什么这个公式就是对的啊,怎么样理解这个公式呢。

⑴先说说公式各项:

◎x[i]:表示待处理的离散数据序列,其中i的范围为0,N-1   

:Re是Real的缩写,表示实部(复数), 表示离散的频率序列, 表示周期信号,K的范围为0,N-1

:cos函数

⑵公式的意义任何连续周期信号可以由一组适当的正弦曲线组合而成

把连续改成离散的:任何离散周期信号可以由一组适当的离散正弦曲线组合而成。

为什么可以算就是对的呢???

在网上看到了这样一段话,感觉挺好的:

    傅立叶变换是一个数学上极为精美的对象:

Ø  它是完全可逆的,任何能量有限的时域或空域信号都存在唯一的频域表达,反之亦然;它完全不损伤信号的内在结构;

Ø  任何两个信号之间有多少相关程度(即内积);它们的频域表达之间也一定有同样多的相关程度;

Ø  它不改变信号之间的关联性:一组信号收敛到一个特定的极限,它们的频域表达也一定收敛到那个极限函数的频域表达。

那怎么计算相关性呢,在网上看见了一个很不错的例子:

http://blog.csdn.net/v_JULY_v/article/details/6196862

以下是他举的例子

利用第一种方法、信号的相关性(correlation)可以从噪声背景中检测出已知的信号,我们也可以利用这个方法检测信号波中是否含有某个频率的信号波:把一个待检测信号波乘以另一个信号波,得到一个新的信号波,再把这个新的信号波所有的点进行相加,从相加的结果就可以判断出这两个信号的相似程度。如下图:


上面a和 b两个图是待检测信号波,图a很明显可以看出是个3个周期的正弦信号波,图b的信号波则看不出是否含有正弦或余弦信号,图c和d都是个3个周期的正弦信号波,图e和f分别是a、b两图跟c、d两图相乘后的结果,图e所有点的平均值是0.5,说明信号a含有振幅为1的正弦信号c,但图f所有点的平均值是0,则说明信号b不含有信号d。这个就是通过信号相关性来检测是否含有某个信号的方法。

通过上面的例子,可以进一步确定:任何两个信号之间有多少相关程度(即内积),它们的频域表达之间也一定有同样多的相关程度。

再来个实际的例子:

这个是圈圈写的,在此引用:

一个模拟信号,经过ADC采样之后,就变成了数字信号。采样定理告诉我们,采样频率要大于信号频率的两倍,这些我就不在此罗嗦了。

采样得到的数字信号,就可以做FFT变换了。N个采样点,经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N取2的整数次方。

假设采样频率为Fs,信号频率F,采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。具体跟原始信号的幅度有什么关系呢?假设原始信号的峰值为A,那么FFT的结果的每个点(除了第一个点直流分量之外)的模值就是A的N/2倍。而第一个点就是直流分量,它的模值就是直流分量的N倍。而每个点的相位呢,就是在该频率下的信号的相位。第一个点表示直流分量(即0Hz),而最后一个点N的再下一个点(实际上这个点是不存在的,这里是假设的第N+1个点,也可以看做是将第一个点分做两半分,另一半移到最后)则表示采样频率Fs,这中间被N-1个点平均分成N等份,每个点的频率依次增加.n所表示的频率为:Fn=(n-1)*Fs/N。由上面的公式可以看出,Fn所能分辨到频率为为Fs/N,如果采样频率Fs为1024Hz,采样点数为1024点,则可以分辨到1Hz。1024Hz的采样率采样1024点,刚好是1秒,也就是说,采样1秒时间的信号并做FFT,则结果可以分析到1Hz,如果采样2秒时间的信号并做FFT,则结果可以分析到0.5Hz。如果要提高频率分辨力,则必须增加采样点数,也即采样时间。频率分辨率和采样时间是倒数关系。

假设FFT之后某点n用复数a+bi表示,那么这个复数的模就是An=根号a*a+b*b,相位就是Pn=atan2(b,a)。根据以上的结果,就可以计算出n点(n≠1,且n<=N/2)对应的信号的表达式为:An/(N/2)*cos(2*pi*Fn*t+Pn),即2*An/N*cos(2*pi*Fn*t+Pn)。对于n=1点的信号,是直流分量,幅度即为A1/N。由于FFT结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果。

好了,说了半天,看着公式也晕,下面圈圈以一个实际的信号来做说明。假设我们有一个信号,它含有2V的直流分量,频率为50Hz、相位为-30度、幅度为3V的交流信号,以及一个频率为75Hz、相位为90度、幅度为1.5V的交流信号。用数学表达式就是如下:

S=2+3*cos(2*pi*50*t-pi*30/180)+1.5*cos(2*pi*75*t+pi*90/180)

式中cos参数为弧度,所以-30度和90度要分别换算成弧度。我们以256Hz的采样率对这个信号进行采样,总共采样256点。按照我们上面的分析,Fn=(n-1)*Fs/N,我们可以知道,每两个点之间的间距就是1Hz,第n个点的频率就是n-1。我们的信号有3个频率:0Hz、50Hz、75Hz,应该分别在第1个点、第51个点、第76个点上出现峰值,其它各点应该接近0。实际情况如何呢?我们来看看FFT的结果的模值如图所示。

 

图1 FFT结果
从图中我们可以看到,在第1点、第51点、和第76点附近有比较大的值。我们分别将这三个点附近的数据拿上来细看:
1点: 512+0i
2点: -2.6195E-14 - 1.4162E-13i
3点: -2.8586E-14 - 1.1898E-13i

50点:-6.2076E-13 - 2.1713E-12i
51点:332.55 - 192i
52点:-1.6707E-12 - 1.5241E-12i

75点:-2.2199E-13 -1.0076E-12i
76点:3.4315E-12 + 192i
77点:-3.0263E-14 +7.5609E-13i
    很明显,1点、51点、76点的值都比较大,它附近的点值都很小,可以认为是0,即在那些频率点上的信号幅度为0。接着,我们来计算各点的幅度值。分别计算这三个点的模值,结果如下:
1点: 512
51点:384
76点:192
   按照公式,可以计算出直流分量为:512/N=512/256=2;50Hz信号的幅度为:384/(N/2)=384/(256/2)=3;75Hz信号的幅度为192/(N/2)=192/(256/2)=1.5。可见,从频谱分析出来的幅度是正确的。

附上自己对DFT的理解:

。假设采样率为N,输入点的个数也为N,

。根据奈奎斯特定理,DFT能分解出来的最高频率为:NHz,

。分辨率为:1Hz,

DFT的意义就是将:0Hz,1Hz,2Hz……N/2Hz的信号与输入的离散序列做内积,求每一个频率与输入的离散序列的相关程度。相关程度越大,表示这个频率的信号在组成输入序列的所有频率信号中占有的比重越大,他的幅值也越大。(不知道对不对??)

3.3  FFT与DFT

快速傅氏变换(FFT)是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。

设x(n)为N项的复数序列,由DFT变换,任一X(m)的计算都需要N次复数乘法和N-1次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N项复数序列的X(m),即N点DFT变换大约就需要 次运算。当N=1024点甚至更多的时候,需要 =1048576次运算,在FFT中,利用WN的周期性和对称性,把一个N项序列(设N=2k,k为正整数),分为两个N/2项的子序列,每个N/2点DFT变换需要(N/2)2次运算,再用N次运算把两个N/2点的DFT变换组合成一个N点的DFT变换。这样变换以后,总的运算次数就变成 。继续上面的例子,N=1024时,总的运算次数就变成了525312次,节省了大约50%的运算量。而如果我们将这种“一分为二”的思想不断进行下去,直到分成两两一组的DFT运算单元,那么N点的DFT变换就只需要 次的运算,N在1024点时,运算量仅有10240次,是先前的直接算法的1%,点数越多,运算量的节约就越大,这就是FFT的优越性。

四、用FPGA做FFT的仿真

芯片为:xilinxSpartan 6

软件:ise 12.2

IP core FFT版本:7.1  

在做FFT之前,读了一下IP core FFT的数据手册,他的输出端口比较简单,但是也有一些疑惑的地方。

ISE 提供了FFT/IFFT 的IP Core,可以完成实数、复数信号的FFT 以及IFFT 运算。FFT 的

IP Core 提供三种结构,分别为:

(1)            流水线,Streaming I/O 结构:允许连续的数据处理;

(2)基4,Burst I/O 结构:提供数据导入/导出阶段和处理阶段。此结构拥有较小的结构,但转换时间较长;

(3)基2,Burst I/O 结构:使用最少的逻辑资源,同Radix-4 相同,提供两阶段的过程。

其配置界面有3 页,第一页如图5-57所示,主要用于配置实现结构;第二页配置数据位宽以及数据处理操作;第三页配置数据缓存空间。在实际硬件操作中,模块的执行速度是很重要的参数,所以本文分析第一种结构,即流水线Streaming I/O结构,以进行连续的数据处理。在进行当前帧的N 点数据时,可加载下一帧的N 点数据,同时输出前一帧的N点数据。此结构由多个基2的蝶形处理单元构成,每个单元都有自己的存储单元来存储输入和中间处理的数据。FFT 的计算单元具有丰富的控制信号,其详细说明见下文。

XN_RE、XN_IM :输入操作数,分别为实部和虚部,以2 的补码输入。在使用时应当确定其位宽。

START:FFT 开始信号,高有效。当此信号变高时,开始输入数据,随后直接进行FFT 转换操作和数据输出。一个START 脉冲,允许对一帧进行FFT 转换。如果每N 个时钟有一个START 脉冲或者START 始终为高,,则都可以连续进行FFT 。如果在最初的START 前,还没有NFFT_WE ,FWD_INV_WE,SCALE_SCH_WE信号,则START 变高后就使用这些信号的默认值。由于此IP Core 支持非连续的数据流,因此在任何时间输入START,即可开始数据的加载。当加载N 个数据结束后,就开始FFT 转换运算。

UNLOAD:对于Burst I/O 结构,此信号将开始输出处理的结果。对于流水线结构和比特逆序输出的情况,此端口不是必要的。

NFFT :此端口只对实时可配置应用时有用。

NFFT_WE :此端口是NFFT 端口的使能信号。

FWD_INV :用以指示IP Core 为FFT 还是IFFT,其等于1 时IP Core 进行FFT 运算,否则进行IFFT 运算。至于采用哪种转换运算是可以逐帧变化的。这一端口给FFT 的使用提供了很大的方便。

FWD_INV_WE :作为FWD_INV 端口的使能信号。

SCALE_SCH:(1) 在IP Core 设计时,如果选择在计算过程中进行中间数据的缩减,那么此信号才可起作用;(2) 输入的位宽等于2*ceil(NFFT/2),其中NFFT = log2(point size)。(3) 流水线结构中,将每个基2 的蝶形处理单元视为一个阶段,每个阶段进行一次数据的缩减,缩减的比例以此输入中对应阶段的两比特表示。(4)每阶段的两比特数可以是3,2,1 或0 :它们表示了数据所需要移动的比特数。

SCALE_SCH_WE :作为SCALE_SCH 的使能信号。

SCLR :可选端口。

Reset :重置信号端口。Reset=1 时,所有工作都停止且初始化。但内部的帧缓存保留其内容。

CE :可选端口。

CLK :输入时钟。

XK_RE,XK_IM :输出数据总线,以2 的补码输出。SCALE_SCH_WE 有效时,输出位宽等于输入;否则,输出位宽= 输入位宽+NFFT+1。

XN_INDEX :位宽等于log2(point size),输入数据的下标。

XK_INDEX :位宽等于log2(point size),输出数据的下标。

RFD :数据有效信号,高有效,在加载数据时为高电平。

BUSY :IP Core 工作状态的指示信号,在计算FFT 转换时为高电平。

DV :数据有效指示信号,当输出端口存在有效数据时变高。

EDONE :高有效。在DONE 信号变高的前一个时钟变为高电平。

DONE :高有效。在FFT 完成后变高,且只存在一个时钟。在DONE 变高后,IP Core 开始输出计算结果。

BLK_EXP :当使用Burst I/O 结构时可用,若选择流水线,则此端口无效

OVFLO :算法溢出指示。在数据输出时,如每帧有溢出,此信号变高。在每帧开始处,此信号重置。

总体说这个核功能很强大,用的时候最重要的就是注意start 信号要早于输入信号4个周期,但是实际应用中并不需要4个周期就已经开始加载数据了,可以这样做:START 一直开,认为第一次加载数据是初始化,即从第二次开始正式工作,从而简化了设计。

Xilinx FFT IP核V7.1支持三种算法类型:全精度无压缩、块浮点型和定点压缩(压缩比由用户自定义)。

对于全精度无压缩结构,数据通道内任意一位有意义的整数都将被保留,在运算过程中产生的小数部分都被截断或者取整。此种结构,对于定点算法,经过多级乘法操作以后,数据位宽将加倍递增,其输出位宽为(输入位宽+log2(数据转换长度)+1)bits。

对于块浮点型,对于一帧数据里面的任何一数据点有相同的压缩比,这个压缩比值由块指数(Block Exponent)作为输出值显示,而且只有在FFT IP核检测到将会产生数据溢出的时候,才会进行压缩运算。

本文所采用的是定点压缩结构。该结构相对于全精度无压缩结构,能够大大减少FPGA内部资源Xtreme DSP Slices和块RAM的使用,而相对于块浮点型,可灵活调节压缩比。定点压缩结构的压缩比例表(Scale_SCH)完全由用户自定义得到。压缩比例是按照1、2、4或者8对每一阶进行压缩,即对应于分别向右移位0、1、2或者3。如果压缩不充分,则蝶形输出结果会超出其动态范围,引起数据溢出。对于Burst I/O结构,Scale_SCH的表示方法:对于每一阶的压缩比都由指定的一个2bits的数表示,零阶的2bits数为最低位,具体形式为[N4,N3,N2,N1,N0],每一个2bits数分别对应着相应阶数的压缩比。例:对于基4结构,数据转换长度N=1024,Scale_SCH=[0110 00 1110]则表示对阶0右移位2,对阶1右移位3,对阶2右移位0,对阶3右移位2,对阶4右移位1。经验总结(可以防止产生数据溢出):对于1024点的基4,Burst I/O结构,Scale_SCH=[10 10 10 10 11];而对于1024点的基2结构,Scale_SCH=[01 01 01 01 01 01 01 01 0110]。对于流水线,Streaming I/O结构,把临近的一对基2阶组在一起,即阶0和阶1为组0,阶2和阶3为组1,等等。Scale_SCH的表示方法:对于每一组的压缩比都由指定的一个2bits的数表示,零组的2bits数为最低位,具体形式为[N4,N3,N2,N1,N0],每一个2bits数分别对应着相应组的压缩比,表示同组内的两个基2阶有相同的压缩比。例:数据长度N=1024,Scale_SCH=[10 10 00 01 11]表示对组0(阶0和阶1)右移位3,对组1(阶2和阶3)右移位1,对组2(阶4和阶5)没有移位,对组3(阶6和阶7)右移位2,对组4(阶8和阶9)右移位2。若变换长度N不是4的幂次方的时候,最后一组只包含一个基2阶,只能用00或者01表示。经验总结(可以防止产生数据溢出):N=512时,Scale_SCH=[01 10 10 10 11];N=1024时,Scale_SCH=[1010 10 10 11]。压缩比例Scale_SCH的位宽,对于流水线,Streaming I/O结构和基4,Burst I/O结构,为2*ceil(0.5*log2(N));对于基2,Burst I/O结构和基2Lite Burst I/O结构,为2* log2(N),其中N为转换数据长度。

在仿真过程中遇到的问题:

1.  数据的输入:datasheet上写的是“two’s complement”,我看了许多的翻译,多是翻译为2的补码的形式,我就想2的补码的形式是什么形式,后来百度后才知道two’s complement就是补码的意思,而不是2的补码。

2.  还是输入的问题,数据输入分为实部和虚部,但是AD输出的信号为实数信号,怎么将实数转换成复数输入,网上有个哥们提出了相同的问题。

有的人回答:将实数做正交转换,但是怎么转换呢????

还有的回答是:实部与虚部都输入AD的输出值,说FFT的速度会加快,没有验证过。

我的理解应该:实部为AD的输出值,虚部为0,验证正确。

3.  设置Scale_SCH时,不确定设置多大数值时,可以将ovflo引脚引出,看看仿真的时候会不会溢出。

4.  数据的输入要在rfd为高时,才有效。

 

 

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

FFT的设置:

Transform length:16

R-2,Burest IO

datawidth 16, Phase factor16.

scaled,

convergentrounding,

naturalorder without cycle prefix insertion.

memoryblock ram,

complexmultiplier- 3 multiplier structure,

butterflyarithmetic ,

useCLB logic

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

仿真的程序:

`timescale1ns / 1ps

//Company:

//Engineer:calm_yi

//

//Create Date:   09:47:47 04/24/2012

//Design Name:   fft

//Module Name:  C:/Users/PC/Desktop/FFT/fft/fftt.v

//Project Name:  fft

//Target Device: 

//Tool versions: 

//Description:

//

//Verilog Test Fixture created by ISE for module: fft

//

//Dependencies:

//

//Revision:

//Revision 0.01 - File Created

//Additional Comments:

//

modulefftt;

 

    // Inputs

    reg start;

    regfwd_inv;

    regclk;

    regscale_sch_we;

    regfwd_inv_we;

    reg [7:0] scale_sch;

    wirerfd;

    wire [3:0] xn_index;

    reg [15:0] xn_re;

    reg [15:0] xn_im;

 

    // Outputs

    wire done;

    wire busy;

    wireedone;

    wireovflo;

    wire dv;

    wire [3:0] xk_index;

    wire [15:0] xk_im;

    wire [15:0] xk_re;

   

    // Instantiate the Unit Under Test (UUT)

    fftuut (

           .rfd(rfd),

           .start(start),

           .fwd_inv(fwd_inv),

           .dv(dv),

           .done(done),

           .clk(clk),

           .busy(busy),

           .scale_sch_we(scale_sch_we),

           .fwd_inv_we(fwd_inv_we),

           .edone(edone),

           .ovflo(ovflo),

           .xn_re(xn_re),

           .xk_im(xk_im),

           .xn_index(xn_index),

           .scale_sch(scale_sch),

           .xk_re(xk_re),

           .xn_im(xn_im),

           .xk_index(xk_index)

    );

 

    initial begin

           // Initialize Inputs

           start = 1;

           fwd_inv = 1;

           clk = 0;

           scale_sch_we =1;

           scale_sch = 8'b01010101;

           fwd_inv_we = 1;

           xn_re = 0;           

           xn_im = 0;

num= 0;

           // Wait 100 ns for global reset tofinish

           #100;   

    end

always

    begin

      #10 clk<= 1;

           #10clk<= 0;

    end

reg[3:0]num;

always@(posedgeclk)

begin

    if(rfd)

    begin

           num<= num + 1'b1;

           case(num)

                  4'd0: xn_re<= 10000;

                                       4'd1:xn_re<= 10000;

                                       4'd2:xn_re<= 10000;

                                       4'd3:xn_re<= 10000;

                                       4'd4:xn_re<= 10000;

                                       4'd5:xn_re<= 10000;

                                       4'd6:xn_re<= 10000;

                                       4'd7:xn_re<= 0;

                                       4'd8:xn_re<= 0;

                                       4'd9:xn_re<= 0;

                                       4'd10:xn_re<= 0;

                                       4'd11:xn_re<= 0;

                                       4'd12:xn_re<= 0;

                                       4'd13:xn_re<= 0;

                                       4'd14:xn_re<= 0;

                                       4'd15: xn_re<=10000;

                                default: ;

                         endcase

    end

end

endmodule

仿真的时序图

◎输入为16个点:

。实数部分:10000、10000、10000、10000、10000、10000、10000、10000、

              0、  0、     0、    0、    0、    0、    0、    0、

。虚实部分:0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0

其实就是一个幅值为10000,占空比为50%的方波在rfd为高电平时输入:

  

FFT输出的数据

dv为高电平时输出转换的数据:

Num

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Re

5000

625

0

625

0

625

0

625

0

625

0

625

0

625

0

625

Im

0

-3142

0

-936

0

-418

0

-124

0

124

0

418

0

936

0

3142

为了验证仿真的结果,用matlab做了一下相同的十六个点的仿真,结果如下:


 

在结果中,我们发现,matlab做出来的结果都是FPGA仿真的结果的两倍,为什么,(待解决)

但是可以看出,应该是仿真结果是对的,因为0Hz时,也就是直流分量FPGA的仿真结果为5000,而matlab的为10000,所以应该是matlab的结果不知道那出了问题!

◎下面是做的第二个仿真,FFT的点数为64,其他的参数与上面的一样。

。压缩比例:scale_sch =12'b000000010101;

。输入的数据采样率为:64Hz/s

。采样时间为:1s

。采样的函数为:

输入的数据就是对P的采样后的64个数据。


。输入的细节:


。FFT后输出的数据:




在图中,可以看到:22Hz、5Hz、18Hz时的幅值是非常高的。证明包含的频率分量是对的,但是幅值是不对的,可能跟压缩比例有关系。

以下是改变压缩比例后的结果:

压缩比例:scale_sch= 12'b010101010101;


两者之间有什么关系,需要进一步验证。

 

 

以下是matlab的输出结果


 

 

 

                    

                                                                                                  yi

                                                                                                  EMEQGroup

                                                                                                  2012.04.27


以上是关于Xilinx FPGA FFT 应用笔记的主要内容,如果未能解决你的问题,请参考以下文章

Simulink HDL Coder FPGA初级开发实践FFT以及CORDIC算法进行信号相位校正

Simulink HDL Coder FPGA初级开发实践FFT以及CORDIC算法进行信号相位校正

Simulink HDL Coder FPGA初级开发实践FFT以及CORDIC算法进行信号相位校正

玩转TensorFlow Lite:有道云笔记实操案例分享

xilinx /FPGA/ verilog HDL不同位数的数相加,如何进行?

FPGA教程案例72基础操作2——Xilinx原语学习及应用2