FFT初解(转)
来源:互联网 发布:java返回值为泛型 编辑:程序博客网 时间:2024/05/16 23:41
原文地址:FFT初解
FFT初解
谨以此文纪念过往的岁月
一.前言
首先申明俺不是一个算法工程师,俺是一个底层驱动工程师,有人会发问一个底层驱动工程师需要这个吗?但是我不幸的告诉你,确实是需要的,不过我们不要像算法工程师那样搞得很精通,但是还是需要去了解这是个什么东西。说实话,这个东西在大学时候学过,还好好的去理解了一样,不过到现在忘的差不多了,这愈发的让我明白一句话,好记性不如烂笔头,如果以前有好好记录的好习惯,那现在只要把以前的东西拿出来看看再印证一下就可以了。不过历史不可以如果。为了不让明天继续懊悔今天,在这里记录下本人学习的一些记录。
二.FFT的数学基础
FFT是什么,额,说白了就是一种时域和频域变换的手段。什么是时域什么是频域,额,你google吧,鄙视百度!
这里说明一下,相比较FFT而言,我们更加关心离散傅里叶变换(DTF),因为我们底层驱动工程师面对的是一个一个离散的数据。也许大家还是对FFT的变换的概念还不理解,那我们举个例子来说吧:
1 AD在一个1Hz正弦波周期采集了1024个数据(即你的采样频率为1024Hz),从时域上看1s内采集了1024数据,那1024个数据做1024点的FFT变换。我们以数据的下标作为横轴,而数据的值作为纵轴,你会发现第一个点的值最大,我们可以从该值计算出我们被采样的频率为1Hz,值是这样算出来的1024(Hz)/1024*1 = 1Hz,如果最大的值点是第8个点,那被采样频率是8Hz。不过要满足乃奎斯定律,即采样频率大于被采样频率的两倍。
为什么会有东西出现呢,主要是时域的信号好采样,至于频域的信号难以采样,于是傅里叶这个天才就发明了这个东东,不过这可是现代数字信号处理的基础。
闲话不说了,还是来看DFT的数学基础(下面的内容不少拷贝wiki的):
对于复数序列,离散傅里叶变换公式为:下面,我们用N次单位根WN来表示。
WN的性质:
- 周期性,WN具有周期N。
- 对称性:。
为了简单起见,我们下面设待变换序列长度n
Fodd(k)
- 。
这样,一个N点变换就分解成了两个N/2点变换。照这样可继续分解下去。这就是库利-图基快速傅里叶变换算法的基本原理。根据主定理不难分析出此时算法的时间复杂度为O(NlogN)
三.8点快速傅里叶变换
主要是蝶形算法
FFT算法图
__no_init float fft_r[FFT_N];//FFT输入实数序列,保存变换后的频域实部
__no_init float fft_i[FFT_N]; //保存变换后的频域虚部
__no_init float harm[HARM_M+1]; //各次谐波幅值
const Uint8 FFT_BIT[8]={ //供完成倒位序排列使用的位定义
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
- void fft(void)
- {
-
Uint16i,j,k,L; -
Uint16b,c,p,n; -
Uint8x,xc; -
floatGr,Gi,Wr,Wi; for(i=0;i<FFT_N;i++) -
{ -
x =i; -
xc=0; -
for(j=0;j<FFT_M;j++) -
{ -
if((x&0x01)!=0) -
{ -
xc|=FFT_BIT[(FFT_M-1)-j]; -
} -
x>>=1; -
} -
fft_i[xc]=fft_r[i]; -
} -
for(i=0;i<FFT_N;i++) -
{ -
fft_r[i]=fft_i[i]; -
fft_i[i]=0; -
} - //以上是倒叙就是将数组中的数据进行倒叙,即将数组序号倒序,如FFT_BIT[5]存储到FFT_BIT[3],为什么呢?5
=0x110,进行二进制倒转变为0x011,变为3. -
for(L=1;L<=FFT_M;L++) -
{ -
b=1; -
p=FFT_N>>1; -
for(i=0;i<L-1;i++) -
{ -
b<<=1; //b=2^(L-1) -
p>>=1; //p=N/(2^L) -
} -
c=b<<1; //c=b*2 -
for(j=0;j<b;j++) -
{ -
n=p*j; -
for(k=j;k<FFT_N;k+=c) -
{ -
Gr = fft_r[k]; -
Gi = fft_i[k]; -
Wr = Sinf[n+FFT_N/4]*fft_r[k+b] + Sinf[n]*fft_i[k+b]; -
Wi = Sinf[n+FFT_N/4]*fft_i[k+b] - Sinf[n]*fft_r[k+b]; -
fft_r[k] = Gr + Wr; -
fft_i[k] = Gi + Wi; -
fft_r[k+b] = Gr - Wr; -
fft_i[k+b] = Gi - Wi; -
} -
} -
} - }
//以上循环分为三个一个根据变换点的阶数循环,即上图中level1->level2->level3。第二个循环是group步进,level1为2
关于旋转因子,就是cos和sin的值,不过这两者之间是可以互相转换的。
也许到此大家对于快速傅里叶有了大概的理解,下面数C++的code,也是源于网上。这段code更好的描述的FFT的蝶形算法,值得参考。
- void FFT(unsignedlong
& ulN, vector<complex<double> >& vecList) - {
-
//得到幂数 -
unsignedlong ulPower = 0; //幂数 -
unsignedlong ulN1 = ulN - 1; -
while(ulN1 > 0) -
{ -
ulPower++; -
ulN1 /= 2; -
} -
//反序 -
bitset<sizeof(unsignedlong) * 8> bsIndex; //二进制容器 -
unsignedlong ulIndex; //反转后的序号 -
unsignedlong ulK; -
for(unsignedlong p = 0; p < ulN; p++) -
{ -
ulIndex = 0; -
ulK = 1; -
bsIndex = bitset<sizeof(unsignedlong) * 8>(p); -
for(unsignedlong j = 0; j < ulPower; j++) -
{ -
ulIndex += bsIndex.test(ulPower - j - 1) ? ulK : 0; -
ulK *= 2; -
} -
-
if(ulIndex > p) -
{ -
complex<double> c = vecList[p]; -
vecList[p] = vecList[ulIndex]; -
vecList[ulIndex] = c; -
} -
} -
//计算旋转因子 -
vector<complex<double> > vecW; -
for(unsignedlong i = 0; i < ulN / 2; i++) -
{ -
vecW.push_back(complex<double>(cos(2 * i * PI / ulN) , -1 * sin(2 * i * PI / ulN))); -
} -
-
for(unsignedlong m = 0; m < ulN / 2; m++) -
{ -
cout<< "\nvW[" << m << "]=" << vecW[m]; -
} -
-
//计算FFT -
unsignedlong ulGroupLength = 1; //段的长度 -
unsignedlong ulHalfLength = 0; //段长度的一半 -
unsignedlong ulGroupCount = 0; //段的数量 -
complex<double> cw; //WH(x) -
complex<double> c1; //G(x) + WH(x) -
complex<double> c2; //G(x) - WH(x) -
for(unsignedlong b = 0; b < ulPower; b++) -
{ -
ulHalfLength = ulGroupLength; -
ulGroupLength *= 2; -
for(unsignedlong j = 0; j < ulN; j += ulGroupLength) -
{ -
for(unsignedlong k = 0; k < ulHalfLength; k++) -
{ -
cw = vecW[k * ulN / ulGroupLength] * vecList[j + k + ulHalfLength]; -
c1 = vecList[j + k] + cw; -
c2 = vecList[j + k] - cw; -
vecList[j + k] = c1; -
vecList[j + k + ulHalfLength] = c2; -
} -
} -
} - }
四.总结
FFT数字信号处理的重中之重。
- FFT初解(转)
- FFT初解(转)
- FFT初解
- (转)FFT结果的物理意义
- FFT结果的物理意义(转)
- bzoj 2179: FFT快速傅立叶 (FFT)
- [BZOJ2179]FFT快速傅立叶(FFT)
- FFT黑科技(拆系数FFT)
- BZOJ 2179 FFT快速傅立叶(FFT)
- bzoj2179 FFT快速傅立叶 (FFT)
- 快速傅里叶变换(FFT)
- 快速傅里叶变换(FFT)
- 快速傅里叶变换(FFT)
- 快速傅里叶(FFT)
- FFT(c语言)
- 快速傅里叶变换(FFT)
- bzoj2179(fft模板)
- 快速傅里叶变换(FFT)
- Linux下ARM汇编教程
- linux面试题参考答案
- linux面试题参考答案
- 长数相乘
- FFT初解(转)
- FFT初解(转)
- 进程间通信之消息队列
- 进程间通信之消息队列
- 深入分析 Linux 内核链表 (转载)
- 深入分析 Linux 内核链表 (转载)
- OpenGL ES & SDL(转载)
- OpenGL ES & SDL(转载)
- 网络专家 – 2005 年 6 月(转载)
- 网络专家 – 2005 年 6 月(转载)