视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
快速傅立叶变换(FFT)源程序
2025-09-25 14:05:31 责编:小OO
文档
//实验用的头文件 MYFFT.H 

//作用:为帮助小虎子做实验,这个头文件提供了完整的一维与二维FFT算法,我想应改是够你折腾了吧! 

#include // complex

using namespace std; 

typedef complex Comp; // 复数类型定义 

const float _2PI_ = 2.0f * 3.14159265f; // 常数2PI定义 

const int MAX_N = 256; // 最大DFT点数 

/*----*----*----*----*----*----*----*----*----*----*----*----* 

FFT算法模块接口定义 

*----*----*----*----*----*----*----*----*----*----*----*----*/ 

/////////////////////////////////////////// 

// Function name : BitReverse 

// Description : 二进制倒序操作 

// Return type : int 

// Argument : int src 待倒读的数 

// Argument : int size 二进制位数 

int BitReverse(int src, int size) 

int tmp = src; 

int des = 0; 

for (int i=size-1; i>=0; i--)

des = ((tmp & 0x1) << i) | des;

tmp = tmp >> 1;

return des; 

////////////////////////////////////////////////// 

// Function name : Reorder 

// Description : 数据二进制整序 

// Return type : void 

// Argument : Comp x[MAX_N] 待整序数组 

// Argument : int N FFT点数 

// Argument : int M 点数的2的幂次 

void Reorder(Comp x[MAX_N], int N, int M) 

Comp new_x[MAX_N]; 

for (int i=0; inew_x = x[BitReverse(i, M)]; 

// 重新存入原数据中(已经是二进制整序过了的数据) 

for (i=0; ix = new_x; 

////////////////////////////////////////////////// 

// Function name : CalcW 

// Description : 计算旋转因子 

// Return type : void 

// Argument : Comp W[MAX_N] 存放因子的数组 

// Argument : int N FFT的点数 

// Argument : int flag 正逆变换标记 

void CalcW(Comp W[MAX_N], int N, int flag) 

for (int i=0; i

if (flag == 1) 

W = exp(Comp(0, -_2PI_ * i / N)); // 正FFT变换 

else 

W = exp(Comp(0, _2PI_ * i / N)); // 逆FFT变换 

///////////////////////////////////////////////// 

// Function name : FFT_1D_Kernel 

// Description : FFT算法核心 

// Return type : void 

// Argument : Comp* x 数据 

// Argument : int M 幂次 

// Argument : int flag 正逆变换标记 

以下本应由自己完成。 

void FFT_1D(Comp* x, int M, int flag) 

int N = (1 << M);

// 二进制整序 

Reorder(x, N, M); 

// 旋转因子计算 

Comp W[MAX_N]; 

CalcW(W, N, flag); 

// 级内群数 

int GroupNum = N/2; // 第一级的群数为N/2 

// 群内蝶形单元数 

int CellNum = 1; // 第一级的群内蝶形单元数为1 

// 处理各级 

for (int i=0; i

// 处理各群 

for (int j=0; j

// 处理各蝶形单元 

for (int k=0; k

// (1) 计算出当前蝶形单元所含元素在数据数组中的位置 

// 第一元素位置 

int Pos1 = CellNum * j * 2 + k ; // 已经处理了前 j 群,每群有 CellNum 个单元, 

每单元有 2 个元素 

// 第二元素位置 

int Pos2 = Pos1 + CellNum; 

// (2) 计算旋转因子与单元的第二元素的复数乘积 

Comp TMP = x[Pos2] * W[k * GroupNum] ; 

// (3) 计算最终结果, 并存入到数组的原先位置 

x[Pos2] = x[Pos1] - TMP ; 

x[Pos1] = x[Pos1] + TMP ; 

GroupNum >>= 1; // 级别增加, 则相应的群数减少一半 

CellNum <<= 1; // 级别增加, 则相应的群内单元数增加一倍 

// 如果是IFFT,各元素还要再除以N 

if (flag != 1) 

for (i=0; ix /= N; 

////////////////////////////////////////////////////// 

// Function name : FFT_2D_Kernel 

// Description : 2D FFT核心算法 

// Return type : void 

// Argument : Comp x[MAX_N][MAX_N] 二维数据 

// Argument : int M 幂次 

// Argument : int flag 正逆变换标记 

以下本应由自己完成。 

void FFT_2D(Comp x[MAX_N][MAX_N], int M, int flag) 

int N = (1 << M);

// 先逐行进行 1D-FFT 

for (int i=0; iFFT_1D(x, M, flag); // <--- 计算结果再存入矩阵x中 

// 再逐列进行 1D-FFT 

Comp col[MAX_N]; 

for (int j=0; j

// 取得第j列的数据 

for (int i=0; icol = x[j]; 

// 对第j列数据进行 1D-FFT 

FFT_1D(col, M, flag); // <--- 计算结果在数组col中 

// 将结果放回矩阵第j列中 

for (i=0; ix[j] = col; 

// <--- End of [FFT.H]

快速傅立叶变换的应用(转贴)

2008年11月24日 星期一 12:10

只要是理工科毕业的朋友,都学过傅立叶级数与傅立叶变换,但真正要与实际应用联系起来,用它来阐述应用中的各类问题,我们总会感觉概念模糊,似懂非懂,不 知从何说起。是的,作者和你一样,常常有这样的体会。现在,让我与你一起重新学习傅立叶的基本理论和应用,最后还给出一份FFT(快速傅立叶变换)的源码 (基于C)。希望对你有所帮助。Let’s go!

1. 历史回顾

谈傅立叶变换,不能不说三角函数。三角函数起源于18世纪,主要是与简谐振动的研究有关。当时的科学家傅立叶对三角函数作了深入研究,并用三角级数解决了很多热传导的问题。三角函数的展开式如下:

f(t) = (a0/2) + (a1·cos(x)+b1·sin(x)) + (a2·cos(2x)+b2·sin(2x)) + …

其中,系数a和b表示不同频率阶数下的幅度。

成立条件:

n 周期性条件,也就是说f(x)描述的波形必须每隔一段时间周期T就会重复出现;

n Dirichlet条件,周期T内,有限的最大最小值,有限的不连续点;

任何区间内绝对可积;

研究目的:

把一个基于时间变量t的函数展开成傅立叶级数的目的是分解为不同的频率分量,以便进行各种滤波算法。这些基本的组成部分是正弦函数SIN(nt)和余弦函数COS(nt)。

应用领域:

l 信号分析,包括滤波、数据压缩、电力系统的监控等;

l 研究偏微分方程,比如求解热力学方程的解时,把f(t)展开为三角级数最为关键。

l 概率与统计,量子力学等学科。

2. 傅立叶变换

H(w) = ∫h(t)·e^jwt·dt, (区间:-∽~+∽,w = 2πf)

讨论:这里为什么会选择复指数的形式而没有用正弦余弦表示?

答案:欧拉公式的引入使得这条经典的数学公式变得更简单,即e^jx = cos(x) + jsin(x)

3. 快速傅立叶变换(FFT)

常规的傅立叶变换算法并不适用于嵌入式控制系统,原因是运算量太大(涉及到复数运算),比如离散的傅立叶变换等同于用序列Y(n×1列矢量)乘以n×n 矩阵Fn,需要n×n次乘法。若n=1024,则是104,8576次乘法运算。哇,这么多呀!什么概念呢?如果你选用的CPU单周期指令为 25ns, 单周期也可以完成一次乘法运算,那么要计算1024点的傅立叶变换则需要26.2144ms,这还不包括加法或其它运算,对于大多数实时系 统,这个处理时间实在太长。于是寻找一个快速的傅立叶变换算法是人们所期望的。

本来我想把FFT的整个数学推导过程列完出来,但当自己硬着头 皮看完后,发现对我没有任何用处,我又不是专门研究数学算法的,哪有那么多时间跟着书本的公式去慢慢推导。我想,这些推导问题还是让数学家想去吧。我需要 的不过是理解它,然后学会应用它就行。有兴趣的读者可以参考相关的资料,这方面的资料实在太多了。

虽然FFT大幅度地降低了常规傅立叶变换的 运算量,但对于一般的单片机而言,处理FFT运算还是力不从心。主要原因是FFT计算过程中的蝶形运算是复数运算,要分开实部和虚部分别计算,想想这是多 么繁琐的事情。可能会有些初学者认为,有这么复杂吗?我在PC上使用C++一样可以对复数直接进行加、减、乘、除运算。你说得不错,可以这么做,但那是 C++封装了对复数处理的类,直接调用就行。在PC上运算这种类型的算法一般不考虑时间和空间,多一两秒的运行时间不会有什么灾难性的结果。

所以我们要衡量一个处理器有没有足够的能力来运行FFT算法,根据以上的简单介绍可以得出以下两点:

l 处理器要在一个指令周期能完成乘和累加的工作,因为复数运算要多次查表相乘才能实现。其二就是间接寻址,可以实现增/减1个变址量,方便各种查表方法。

2 FFT要对原始序列进行反序排列,处理器要有反序间接寻址的能力。

所以,在数字信号的分析处理应用中,DSP比其它的处理器有绝对的优势,因为DSP完全具备以上条件。这就是单片机(51系列,AVR,PIC等等)或ARM处理器很少用来进行数字信号分析的原因。

4. FFT的C实现方法

//**********************************************************

// 函数名: 快速傅立叶变换(来源《C常用算法集》)

// 本函数测试OK,可以在TC2.0,VC++6.0,Keil C51测试通过。

// 如果你的MCS51系统有足够的RAM时,可以验证一下用单片机处理FFT有多么的慢。

//

// 入口参数: 

// l: l = 0, 傅立叶变换; l = 1, 逆傅立叶变换

// il: il = 0,不计算傅立叶变换或逆变换模和幅角;il = 1,计算模和幅角

// n: 输入的点数,为偶数,一般为32,,128,...,1024等

// k: 满足n=2^k(k>0),实质上k是n个采样数据可以分解为偶次幂和奇次幂的次数

// pr[]: l=0时,存放N点采样数据的实部

// l=1时, 存放傅立叶变换的N个实部

// pi[]: l=0时,存放N点采样数据的虚部 

// l=1时, 存放傅立叶变换的N个虚部

//

// 出口参数:

// fr[]: l=0, 返回傅立叶变换的实部

// l=1, 返回逆傅立叶变换的实部

// fi[]: l=0, 返回傅立叶变换的虚部

// l=1, 返回逆傅立叶变换的虚部

// pr[]: il = 1,i = 0 时,返回傅立叶变换的模

// il = 1,i = 1 时,返回逆傅立叶变换的模

// pi[]: il = 1,i = 0 时,返回傅立叶变换的辐角

// il = 1,i = 1 时,返回逆傅立叶变换的辐角

// data: 2005.8.15,Mend Xin Dong

void kkfft(double pr[], double pi[], int n, int k, double fr[], double fi[], int l, int il)

{

int it,m,is,i,j,nv,l0;

double p,q,s,vr,vi,poddr,poddi;

for (it=0; it<=n-1; it++)

m = it; 

is = 0;

for(i=0; i<=k-1; i++)

j = m/2; 

is = 2*is+(m-2*j); 

m = j;

}

fr[it] = pr[is]; 

fi[it] = pi[is];

}

//----------------------------

pr[0] = 1.0; 

pi[0] = 0.0;

p = 6.283185306/(1.0*n);

pr[1] = cos(p); 

pi[1] = -sin(p);

if (l!=0) 

pi[1]=-pi[1];

for (i=2; i<=n-1; i++)

p = pr[i-1]*pr[1]; 

q = pi[i-1]*pi[1];

s = (pr[i-1]+pi[i-1])*(pr[1]+pi[1]);

pr[i] = p-q; 

pi[i] = s-p-q;

}

for (it=0; it<=n-2; it=it+2)

vr = fr[it]; 

vi = fi[it];

fr[it] = vr+fr[it+1]; 

fi[it] = vi+fi[it+1];

fr[it+1] = vr-fr[it+1]; 

fi[it+1] = vi-fi[it+1];

}

m = n/2; 

nv = 2;

for (l0=k-2; l0>=0; l0--)

m = m/2; 

nv = 2*nv;

for(it=0; it<=(m-1)*nv; it=it+nv)

for (j=0; j<=(nv/2)-1; j++)

p = pr[m*j]*fr[it+j+nv/2];

q = pi[m*j]*fi[it+j+nv/2];

s = pr[m*j]+pi[m*j];

s = s*(fr[it+j+nv/2]+fi[it+j+nv/2]);

poddr = p-q; 

poddi = s-p-q;

fr[it+j+nv/2] = fr[it+j]-poddr;

fi[it+j+nv/2] = fi[it+j]-poddi;

fr[it+j] = fr[it+j]+poddr;

fi[it+j] = fi[it+j]+poddi;

}

}

if(l!=0)

for(i=0; i<=n-1; i++)

fr[i] = fr[i]/(1.0*n);

fi[i] = fi[i]/(1.0*n);

}

if(il!=0)

for(i=0; i<=n-1; i++)

pr[i] = sqrt(fr[i]*fr[i]+fi[i]*fi[i]);

if(fabs(fr[i])<0.000001*fabs(fi[i]))

if ((fi[i]*fr[i])>0) 

pi[i] = 90.0;

else 

pi[i] = -90.0;

}

else

pi[i] = atan(fi[i]/fr[i])*360.0/6.283185306;

}

return;

//快速傅立叶变换的源代码

//------------------------------------

// fft.cpp

// The implementation of the

// Fast Fourier Transform algorithm

// (c) Reliable Software, 1996

//------------------------------------

#include "fft.h"

#include "recorder.h"

// log (1) = 0, log(2) = 1, log(3) = 2, log(4) = 2 ...

#define PI (2.0 * asin(1.0))

// Points must be a power of 2

Fft::Fft (int Points, long sampleRate)

: _Points (Points), _sampleRate (sampleRate)

{

_aTape = new double [_Points];

#if 0

// 1 kHz calibration wave

for (int i = 0; i < _Points; i++)

_aTape[i] = 1600 * sin (2 * PI * 1000. * i / _sampleRate);

#else

for (int i = 0; i < _Points; i++)

_aTape[i] = 0;

#endif

_sqrtPoints = sqrt((double)_Points);

// calculate binary log

_logPoints = 0;

Points--;

while (Points != 0)

{

Points >>= 1;

_logPoints++;

}

_aBitRev = new int [_Points];

_X = new Complex[_Points];

_W = new Complex* [_logPoints+1];

// Precompute complex exponentials

int _2_l = 2;

for (int l = 1; l <= _logPoints; l++)

{

_W[l] = new Complex [_Points];

for ( int i = 0; i < _Points; i++ )

{

double re = cos (2. * PI * i / _2_l);

double im = -sin (2. * PI * i / _2_l);

_W[l][i] = Complex (re, im);

}

_2_l *= 2;

}

// set up bit reverse mapping

int rev = 0;

int halfPoints = _Points/2;

for (i = 0; i < _Points - 1; i++)

{

_aBitRev[i] = rev;

int mask = halfPoints;

// add 1 backwards

while (rev >= mask)

{

rev -= mask; // turn off this bit

mask >>= 1;

}

rev += mask;

}

_aBitRev [_Points-1] = _Points-1;

}

Fft::~Fft()

{

delete []_aTape;

delete []_aBitRev;

for (int l = 1; l <= _logPoints; l++)

{

delete []_W[l];

}

delete []_W;

delete []_X;

}

void Fft::CopyIn (SampleIter& iter)

{

int cSample = iter.Count();

if (cSample > _Points)

return;

// make space for cSample samples at the end of tape

// shifting previous samples towards the beginning

memmove (_aTape, &_aTape[cSample],

(_Points - cSample) * sizeof(double));

// copy samples from iterator to tail end of tape

int iTail = _Points - cSample;

for (int i = 0; i < cSample; i++, iter.Advance())

{

_aTape [i + iTail] = (double) iter.GetSample();

}

// Initialize the FFT buffer

for (i = 0; i < _Points; i++)

PutAt (i, _aTape[i]);

}

//

// 0 1 2 3 4 5 6 7

// level 1

// step 1 0

// increm 2 W

// j = 0 <---> <---> <---> <---> 1

// level 2

// step 2

// increm 4 0

// j = 0 <-------> <-------> W 1

// j = 1 <-------> <-------> 2 W

// level 3 2

// step 4

// increm 8 0

// j = 0 <---------------> W 1

// j = 1 <---------------> 3 W 2

// j = 2 <---------------> 3 W 3

// j = 3 <---------------> 3 W

// 3

//

void Fft::Transform ()

{

// step = 2 ^ (level-1)

// increm = 2 ^ level;

int step = 1;

for (int level = 1; level <= _logPoints; level++)

{

int increm = step * 2;

for (int j = 0; j < step; j++)

{

// U = exp ( - 2 PI j / 2 ^ level )

Complex U = _W [level][j];

for (int i = j; i < _Points; i += increm)

{

// butterfly

Complex T = U;

T *= _X [i+step];

_X [i+step] = _X[i];

_X [i+step] -= T;

_X [i] += T;

}

}

step *= 2;

}

}下载本文

显示全文
专题