基于FPGA的快速傅里叶变换加速(二) 蝶形运算模块介绍及matlab代码实现
蝶形运算模块介绍及matlab代码实现)
1. 基二FFT的基本原理
1.1 快速傅里叶变换
简单形式离散傅立叶变换(DFT)和逆离散傅立叶变换(IDFT)所需的复杂乘法和加法运算的数量为N2,因为有N个数据点要计算,每个数据点都需要N复杂的算术运算。
对于长度为n的输入向量x,DFT是长度为n的向量X,具有n个元素:
用计算机科学术语来说,我们可以说它们具有算法复杂度O(N2),因此不是一种非常有效的方法。如果我们不能做得更好,那么DFT对于大多数实际的DSP应用将不是很有用。但是,有许多不同的“快速傅立叶变换”(FFT)算法使计算信号的傅立叶变换的速度比DFT快得多。
顾名思义,FFT是用于快速计算数据矢量离散傅里叶变换的算法。 FFT是一种DFT算法,可将N点所需的计算次数从O(N2 )减少到O(N log N),其中log是以2为底的对数。如果要变换的函数与采样频率不是谐波相关,则FFT的响应看起来像是“ sinc”函数(sin x)/ x如果N为2的常规幂(N = 2p),则“基数2”算法很有用。如果我们假设算法复杂度提供了执行时间的直接量度,并且相关对数的底数是2,则如图1.1所示,(DFT)与(Radix 2 FFT)的执行时间之比(表示为“速度”改善因子’)随着N的增加而大大增加。
1.2 常用FFT算法
术语“ FFT”实际上有点含糊,因为有几种常用的“ FFT”算法。 Radix 2有两种不同的算法,即所谓的“时间抽取”(DIT)和“频率抽取”(DIF)算法。这两个都依赖于将N点变换递归分解为2(N / 2)点变换。此分解过程可以应用于任何复合(非素数)N。如果N可被2整除,并且N是2的幂,则该方法特别简单,可以重复应用分解,直到进行琐碎的“ 1点”变换为止到达了。
1.2.1 时域抽取
(1) 实现过程
将序列x(n)按n为奇、偶数分为x1(n)、x2(n)两组序列;用2个N/2点DFT来完成一个N点DFT的计算。
设序列x(n)的长度为N,且满足:N = 2**M,M是自然数;
(1) 按n的奇偶把x(n)分解为两个N/2点的子序列
X1 ( r ) = X(2r), X2 ( r ) = X(2r + 1), r = 0,…,N/2;
(2)用N/2点X1(k)和X2(k)表示序列x(n)的N点DFT X(k)
由于X1(k)和X2(k)均以N/2为周期,且由于旋转系数的性质, X(k)又可表示为:
对上式的运算用下图所示的流图符号来表示
一次分解结果如图:
二次分解
结果如图:
三次分解如图:
(2)运算规律及编程思想
原位计算
序列长为N=2**M点的FFT,有M级蝶形,每级有N/2个蝶形运算。
同一级中,每个蝶形的两个输入数据只对本蝶形有用,每个蝶形的输入、输出数据节点在用一条水平线上。这样,当计算完一个蝶形后,所得的输出数据可立即存入原输入数据所占用的存储单元。经过M级运算后,原来存放输入序列数据的N个存储单元中可依次存放X(k)的N个值。
原位计算:利用同一存储单元存储蝶形计算输入、输出数据的方法。
优点:节约存储空间、降低设备成本。
旋转因子
N点DIT―FFT运算流图中,每个蝶形都要乘以旋转因子WpN,p称为旋转因子的指数。N=8 =2**3 时各级的旋转因子
距离
同一级中,同一旋转因子对应蝶形数目
第L级FFT运算中,同一旋转因子用在2M-L个蝶形中;
同一级中,蝶形运算使用相同旋转因子之间相隔的“距离”
第L级中,蝶距:D=2L。
同一蝶形运算两输入数据的距离
在输入倒序,输出原序的FFT变换中,第L级的每一个蝶形的2个输入数据相距:B=2*L-1。
码位颠倒
输入序列x(n)经过M级时域奇、偶抽选后,输出序列X(k)的顺序和输入序列的顺序关系为倒位关系。
1.2.2 频域抽取
由于本项目未使用频域抽取,故不作实现介绍
(1) 运算规律比较
相同:
DIF-FFT算法也可采用原位计算;N=2M时,共有M级运算,每级共有N/2个蝶形,DIT与DIF算法的运算次数相同。
不同:
DIF-FFT算法输入序列为自然序列,输出为倒序序列。因此,在M级运算完成后,需对输出数据进行倒序才能得到自然顺序的X(k)。
蝶形运算符号不同:DIT-FFT蝶形是先相乘,后加/减;而DIF-FFT蝶形是先加/减,后相乘。
(2)运算量比较
DIF,DIR运算量相同
2. Matlab实现
由于matlab可直接使用fft函数进行运算,故matlab代码较简单,也只用来生成初始化数据及标准结果对比;
% 构建输入数据并写入文件用于verilog
width = 8;
depth = 64;
index = linspace(0, 2*pi, depth);
sin_value = sin(index);
sin_value = sin_value * (2^(width-1) -1 );
sin_value = fix(sin_value);
toVerilog = mod(sin_value+256, 256);
fid = fopen('Data_Input.txt', 'wt');
fprintf(fid, '%02x 00\n', toVerilog);
fclose(fid);
% 计算用于verilog的Wn的参数,均乘以255
fid = fopen('Data_Parameter.txt', 'wt');
for i = 1:6
N = 2^i;
for j = 0:N/2-1
real_f = cos(2*pi*j/N);
imag_f =-sin(2*pi*j/N);
real_d = fix(real_f * 127);
imag_d = fix(imag_f * 127);
real_d = mod(real_d + 256, 256);
imag_d = mod(imag_d + 256, 256);
%fprintf(fid, '(%02d.%02d) %02x %02x \t%1.4f %1.4f\n',i, j, real_d, imag_d, real_f, imag_f);
fprintf(fid, '%02x %02x\n',real_d, imag_d);
end
end
fclose(fid);
% 计算FFT
n = 0:depth-1;
y = fft(sin_value);
for i = 1 : depth
yreal(i) = fix(real(y(i)));
yimag(i) = fix(imag(y(i)));
end
yint = [yreal; yimag]'; % 最终比对用FFT结果