xilinx fpga fft 应用笔记xilinx.eetrend.com/files-eetrend-xilinx/forum/201507/...2012/04/24  ·...

30
Xilinx FPGA FFT 应用笔记 系统工作环境: 芯片为:xilinxSpartan 6 软件:ise 12.2 IP core FFT 版本:7.1 目标:完成对放大板的标定

Upload: others

Post on 05-Jan-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

Xilinx FPGA FFT 应用笔记

系统工作环境:

芯片为:xilinxSpartan 6

软件:ise 12.2

IP core FFT 版本:7.1

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

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

放大板包含 3 级程控放大器的放大电路、4 个可选择的高频滤波器、1 个

50Hz 的工频滤波器,放大板主要是针对低频信号,放大频率范围:0-20KHz,

标定示意图:

放大器板ADS1274

24位ADSpartan 6

FPGA

AD5664r

16位DA

放大器控制

模拟输出数字输出

控制信号 电压输出

offset电压输出

低通滤波

◎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 种是可行的,但是同时也参生了一个问题,就是信号必须是周期的,但是

在实际的数据中,不一定都是周期的啊,这个怎么办呢!以下是在《Digital signal

processing》(一个老外写的特别好的书)的图,看完图后应该就能明白了。

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

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

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

致的情况是:

2

2

1( ) ( )

p

p

t

jm t

a

tp

X m x t e dtt

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

通过对连续的周期的信号的公式进行抽样处理,然后推到出来的,推的过程

就很复杂了,也不太好理解。

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

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

我的第一个感觉就是,他代表的是什么意思啊,凭什么这个公式就是对的啊,

怎么样理解这个公式呢。

⑴先说说公式各项:

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

◎Re [ ]X k :Re 是 Real 的缩写,表示实部(复数), [ ]X k 表示离散的频率序列,

X 表示周期信号,K 的范围为{0,N-1}

◎cos(2 / )ki N :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 变换大约就需要2N 次运算。当 N=1024 点甚至更多的时候,需要

2N

=1048576 次运算,在 FFT 中,利用 WN 的周期性和对称性,把一个 N 项序列(设

N=2k,k为正整数),分为两个N/2项的子序列,每个N/2点DFT变换需要(N/2)

2 次运算,再用 N 次运算把两个 N/2 点的 DFT 变换组合成一个 N 点的 DFT 变

换。这样变换以后,总的运算次数就变成

222( )

2 2

N NN N

。继续上面的例

子,N=1024 时,总的运算次数就变成了 525312 次,节省了大约 50%的运算量。

而如果我们将这种“一分为二”的思想不断进行下去,直到分成两两一组的DFT

运算单元,那么 N 点的 DFT 变换就只需要2logN N 次的运算,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=[01 10 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 01 10]。

对于流水线,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 结构和基 2 Lite 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

data width 16, Phase factor16.

scaled,

convergent rounding,

natural order without cycle prefix insertion.

memory block ram,

complex multiplier- 3 multiplier structure,

butterfly arithmetic ,

use CLB logic

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

仿真的程序:

`timescale 1ns / 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 to finish

#100;

end

always

begin

#10 clk<= 1;

#10 clk<= 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

。采样的函数为:

1100*sin(5.3*2 * ) 500*sin(18*2 * ) 9000*sin(2.2*2 * )P t t t

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

。输入的细节:

。FFT 后输出的数据:

1100*sin(5.3*2 * ) 500*sin(18*2 * ) 9000*sin(2.2*2 * )P t t t

在图中,可以看到:22Hz、5Hz、18Hz 时的幅值是非常高的。证明包含的

频率分量是对的,但是幅值是不对的,可能跟压缩比例有关系。

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

压缩比例:scale_sch= 12'b010101010101;

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

以下是 matlab 的输出结果

Calm_yi

EMEQ Group

2012.04.27