FFT-C快速傅里叶变换超级详细的原代码

合集下载

快速傅里叶变换fft的c程序代码实现

快速傅里叶变换fft的c程序代码实现

快速傅里叶变换fft的c程序代码实现标题:一种高效实现快速傅里叶变换(FFT)的C语言程序代码导言:快速傅里叶变换(Fast Fourier Transform,FFT)是一种在信号处理、图像处理、通信系统等领域广泛应用的重要算法。

它通过将输入信号从时域转换到频域,实现了对信号的频谱分析和频率成分提取。

在实际应用中,为了获得高效的FFT计算过程,我们需要使用合适的算法和优化技巧,并将其转化为高质量的C语言代码。

本文将介绍一种基于Cooley-Tukey算法的快速傅里叶变换的C语言程序代码实现。

我们将从原理开始详细讲解FFT算法,然后逐步引入代码实现的步骤,并进行相关优化。

我们将总结整个实现过程,并分享一些个人对FFT算法的理解和观点。

一、快速傅里叶变换(FFT)的原理(1)傅里叶级数与离散傅里叶变换傅里叶级数是将一个周期函数分解为一系列正弦和余弦函数的和的方法。

然而,实际数字信号往往是离散的。

我们需要离散傅里叶变换(Discrete Fourier Transform,DFT)来对离散信号进行频谱分析。

(2)DFT的定义及其计算复杂度离散傅里叶变换通过对离散信号的变换矩阵进行乘法运算,得到其频谱表示。

然而,直接使用定义式计算DFT的时间复杂度为O(N^2),其中N为信号长度,这对于大规模信号计算是不可接受的。

(3)引入快速傅里叶变换 (FFT)Cooley-Tukey算法是一种最常用的FFT算法,通过将DFT分解为多个较小规模的DFT计算来降低计算复杂度。

FFT的时间复杂度为O(NlogN),大大提高了计算效率。

二、快速傅里叶变换(FFT)的C语言实现(1)算法流程和数据结构设计以一维FFT为例,我们需要定义合适的数据结构来表示复数和存储输入输出信号,同时设计实现FFT的主要流程。

(2)递归实现方法递归实现是最直观的FFT实现方法,基于Cooley-Tukey算法的思想。

将输入信号分为偶数和奇数两部分,然后递归计算它们的FFT。

快速傅里叶变换FFT算法源码经典

快速傅里叶变换FFT算法源码经典

快速傅里叶变换FFT算法源码经典以下是一个经典的快速傅里叶变换(FFT)算法的源码,包含详细的注释解释每个步骤的作用。

```pythonimport cmath#递归实现快速傅里叶变换def fft(x):N = len(x)#基本情况:如果输入向量只有一个元素,则直接返回该向量if N <= 1:return x#递归步骤:#将输入向量分成两半even = fft(x[0::2]) # 偶数索引的元素odd = fft(x[1::2]) # 奇数索引的元素T = [cmath.exp(-2j * cmath.pi * k / N) * odd[k] for k in range(N // 2)]#组合结果return [even[k] + T[k] for k in range(N // 2)] + \[even[k] - T[k] for k in range(N // 2)]#逆傅里叶变换def ifft(X):N = len(X)#将输入向量取共轭X_conj = [x.conjugate( for x in X]#应用快速傅里叶变换x_conj = fft(X_conj)#将结果取共轭并归一化return [(x.conjugate( / N).real for x in x_conj]#示例测试if __name__ == "__main__":x=[1,2,3,4]X = fft(x)print("快速傅里叶变换结果:", X)print("逆傅里叶变换恢复原始向量:", ifft(X))```这个源码实现了一个经典的快速傅里叶变换(FFT)算法。

首先,`fft`函数实现了递归的快速傅里叶变换,接收一个输入向量`x`作为参数,返回傅里叶变换后的结果`X`。

如果输入向量只有一个元素,则直接返回。

否则,将输入向量分成两半,分别对偶数索引和奇数索引的元素递归应用FFT。

C语言实现FFT(快速傅里叶变换)

C语言实现FFT(快速傅里叶变换)

#include <iom128.h>#include <intrinsics.h>/*********************************************************************快速福利叶变换C函数函数简介:此函数是通用的快速傅里叶变换C语言函数,移植性强,以下部分不依赖硬件。

此函数采用联合体的形式表示一个复数,输入为自然顺序的复数(输入实数是可令复数虚部为0),输出为经过FFT变换的自然顺序的复数使用说明:使用此函数只需更改宏定义FFT_N的值即可实现点数的改变,FFT_N的应该为2的N次方,不满足此条件时应在后面补0函数调用:FFT(s);时间:2010-2-20版本:Ver1.0参考文献:**********************************************************************/#include<math.h>#define PI 3.1415926535897932384626433832795028841971 //定义圆周率值#define FFT_N 128 //定义福利叶变换的点数struct compx {float real,imag;}; //定义一个复数结构struct compx s[FFT_N]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义/*******************************************************************函数原型:struct compx EE(struct compx b1,struct compx b2)函数功能:对两个复数进行乘法运算输入参数:两个以联合体定义的复数a,b输出参数:a和b的乘积,以联合体的形式输出*******************************************************************/struct compx EE(struct compx a,struct compx b){struct compx c;c.real=a.real*b.real-a.imag*b.imag;c.imag=a.real*b.imag+a.imag*b.real;return(c);}/*****************************************************************函数原型:void FFT(struct compx *xin,int N)函数功能:对输入的复数组进行快速傅里叶变换(FFT)输入参数:*xin复数结构体组的首地址指针,struct型*****************************************************************/void FFT(struct compx *xin){int f,m,nv2,nm1,i,k,l,j=0;struct compx u,w,t;nv2=FFT_N/2; //变址运算,即把自然顺序变成倒位序,采用雷德算法nm1=FFT_N-1;for(i=0;i<nm1;i++){if(i<j) //如果i<j,即进行变址{t=xin[j];xin[j]=xin[i];xin[i]=t;}k=nv2; //求j的下一个倒位序while(k<=j) //如果k<=j,表示j的最高位为1{j=j-k; //把最高位变成0k=k/2; //k/2,比较次高位,依次类推,逐个比较,直到某个位为0 }j=j+k; //把0改为1}{int le,lei,ip; //FFT运算核,使用蝶形运算完成FFT运算f=FFT_N;for(l=1;(f=f/2)!=1;l++) //计算l的值,即计算蝶形级数;for(m=1;m<=l;m++) // 控制蝶形结级数{ //m表示第m级蝶形,l为蝶形级总数l=log(2)Nle=2<<(m-1); //le蝶形结距离,即第m级蝶形的蝶形结相距le点lei=le/2; //同一蝶形结中参加运算的两点的距离u.real=1.0; //u为蝶形结运算系数,初始值为1u.imag=0.0;w.real=cos(PI/lei); //w为系数商,即当前系数与前一个系数的商w.imag=-sin(PI/lei);for(j=0;j<=lei-1;j++) //控制计算不同种蝶形结,即计算系数不同的蝶形结{for(i=j;i<=FFT_N-1;i=i+le) //控制同一蝶形结运算,即计算系数相同蝶形结{ip=i+lei; //i,ip分别表示参加蝶形运算的两个节点t=EE(xin[ip],u); //蝶形运算,详见公式xin[ip].real=xin[i].real-t.real;xin[ip].imag=xin[i].imag-t.imag;xin[i].real=xin[i].real+t.real;xin[i].imag=xin[i].imag+t.imag;}u=EE(u,w); //改变系数,进行下一个蝶形运算}}}}/************************************************************函数原型:void main()函数功能:测试FFT变换,演示函数使用方法输入参数:无输出参数:无************************************************************/void main(){int i;for(i=0;i<FFT_N;i++) //给结构体赋值{s[i].real=sin(2*3.141592653589793*i/FFT_N); //实部为正弦波FFT_N点采样,赋值为1 s[i].imag=0; //虚部为0}FFT(s); //进行快速福利叶变换for(i=0;i<FFT_N;i++) //求变换后结果的模值,存入复数的实部部分s[i].real=sqrt(s[i].real*s[i].real+s[i].imag*s[i].imag);while(1);}#include <iom128.h>#include <intrinsics.h>/*********************************************************************快速福利叶变换C程序包函数简介:此程序包是通用的快速傅里叶变换C语言函数,移植性强,以下部分不依赖硬件。

FFT-C快速傅里叶变换超级详细的原代码

FFT-C快速傅里叶变换超级详细的原代码

快速傅立叶变换(FFT)的C++实现收藏标准的离散傅立叶DFT 变换形式如:y k=Σj=0n-1a jωn-kj = A (ωn-k).(ωn k为复数1 的第k 个n 次方根,且定义多项式A (x)=Σj=0n-1a j x j)而离散傅立叶逆变换IDFT (Inverse DFT)形式如:a j=(Σk=0n-1y kωn kj)/n .yk=Σj=0n-1 ajωn-kj = A (ωn-k).(ωnk 为复数1 的第k 个n 次方根,且定义多项式 A (x) = Σj=0n-1 ajxj )而离散傅立叶逆变换IDFT (Inverse DFT)形式如:aj=(Σk=0n-1 ykωnkj)/n .以下不同颜色内容为引用并加以修正:快速傅立叶变换(Fast Fourier Transform,FFT)是离散傅立叶变换(Discrete Fourier transform,DFT)的快速算法,它是根据离散傅立叶变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。

它对傅立叶变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。

设Xn 为N 项的复数序列,由DFT 变换,任一Xi 的计算都需要N 次复数乘法和N -1 次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N 项复数序列的Xi ,即N 点DFT 变换大约就需要N2 次运算。

当N =1024 点甚至更多的时候,需要N2 = 1048576 次运算,在FFT 中,利用ωn 的周期性和对称性,把一个N 项序列(设N 为偶数),分为两个N / 2 项的子序列,每个N / 2点DFT 变换需要(N / 2)2 次运算,再用N 次运算把两个N / 2点的DFT 变换组合成一个N 点的DFT 变换。

FFT算法C语言程序代码(可打印修改)

FFT算法C语言程序代码(可打印修改)

//wLen——FFT 的长度 Struct complexData{
//定义一个复数结构
float re;
float im;
};
Void gen_w_r2(struct complexData *twiFactor,int wLen)
{
int iFactor;
float stepFactor;
stepFactor=2.0*pi/wLen;
short n2,ie,ia,i,j,k,m; float rtemp,itemp,c,s;
n2=n; ie=1; for(k=n;k>1;k>>=1) //loop c
{ n2>>=1;ia=0; for(j=0;j<ie;j++) //loop b { c=w[2*j]; s=w[2*j+1]; for(i=0;i<n2;i++) //loop a { m=ia+n2; rtemp=c*x[2*m]+s*x[2*m+1]; itemp= c*x[2*m+1]-s*x[2*m]; x[2*m]=x[2*ia]-rtemp; x[2*m+1]=x[2*ia+1]-itemp; x[2*ia]=x[2*ia]+rtemp; x[2*ia+1]=x[2*ia+1]+itemp; ia++; } ia+=n2; } ie<<=1; }
}
}
2、在运行 FFT 之前,对输入序列进行倒序变换,代码如下:
//bitRevData——指向位变换序列的指针
//revLen——FFT 长度 Void bit_rev(struct complexData *bitRevData,int revLen)

fft算法c语言实现

fft算法c语言实现

fft算法c语言实现快速傅里叶变换(FFT)是一种高效的离散傅里叶变换算法,用于计算信号在频域的表示。

下面是一个简单的使用 C 语言实现的 FFT 算法示例,它可以用于对输入的时域信号进行离散傅里叶变换。

```c#include <stdio.h>#include <stdlib.h>#include <math.h>#define N 16// 复数结构体typedef struct {double real;double imag;} Complex;// 初始化复数void initComplex(Complex *c, double real, double imag) {c->real = real;c->imag = imag;}// FFT 算法void fft(Complex *c, int n) {int i, j, k;Complex w, u, v;// 层次遍历for (i = 1; i < n; i <<= 1) {// 旋转因子w.real = cos(2 * M_PI * i / n);w.imag = -sin(2 * M_PI * i / n);for (j = 0; j < n; j += i) {for (k = 0; k < i / 2; k++) {u.real = c[j + k].real;u.imag = c[j + k].imag;v.real = c[j + i / 2 + k].real;v.imag = c[j + i / 2 + k].imag;c[j + k].real = u.real + w.real * v.real - w.imag * v.imag; c[j + k].imag = u.imag + w.real * v.imag + w.imag * v.real; c[j + i / 2 + k].real = u.real - w.real * v.real + w.imag * v.imag; c[j + i / 2 + k].imag = u.imag - w.real * v.imag - w.imag * v.real; }}}}// 打印复数void printComplex(Complex c) {printf("%f + %fi\n", c.real, c.imag);}int main() {Complex c[N];// 输入的时域信号for (int i = 0; i < N; i++) {c[i].real = rand() / RAND_MAX;c[i].imag = rand() / RAND_MAX;}printf("输入的时域信号:\n");// 打印输入的时域信号for (int i = 0; i < N; i++) {printComplex(c[i]);}fft(c, N);printf("经过 FFT 变换后的频域信号:\n");// 打印经过 FFT 变换后的频域信号for (int i = 0; i < N; i++) {printComplex(c[i]);}return 0;}```上述代码是一个简单的 C 语言实现的 FFT 算法示例。

快速傅里叶变换FFT的C程序代码实现

快速傅里叶变换FFT的C程序代码实现

快速傅⾥叶变换FFT的C程序代码实现标签:傅⾥叶变换(27)C程序(60) ⼀、彻底理解傅⾥叶变换 快速傅⾥叶变换(Fast Fourier Transform)是离散傅⾥叶变换的⼀种快速算法,简称FFT,通过FFT可以将⼀个信号从时域变换到频域。

模拟信号经过A/D转换变为数字信号的过程称为采样。

为保证采样后信号的频谱形状不失真,采样频率必须⼤于信号中最⾼频率成分的2倍,这称之为采样定理。

假设采样频率为fs,采样点数为N,那么FFT结果就是⼀个N点的复数,每⼀个点就对应着⼀个频率点,某⼀点n(n从1开始)表⽰的频率为:fn=(n-1)*fs/N。

举例说明:⽤1kHz的采样频率采样128点,则FFT结果的128个数据即对应的频率点分别是0,1k/128,2k/128,3k/128,…,127k/128 Hz。

这个频率点的幅值为:该点复数的模值除以N/2(n=1时是直流分量,其幅值是该点的模值除以N)。

⼆、傅⾥叶变换的C语⾔编程 1、对于快速傅⾥叶变换FFT,第⼀个要解决的问题就是码位倒序。

假设⼀个N点的输⼊序列,那么它的序号⼆进制数位数就是t=log2N. 码位倒序要解决两个问题:①将t位⼆进制数倒序;②将倒序后的两个存储单元进⾏交换。

如果输⼊序列的⾃然顺序号i⽤⼆进制数表⽰,例如若最⼤序号为15,即⽤4位就可表⽰n3n2n1n0,则其倒序后j对应的⼆进制数就是n0n1n2n3,那么怎样才能实现倒序呢?利⽤C语⾔的移位功能! 程序如下,我不多说,看不懂者智商⼀定在180以下! 复数类型定义及其运算 #define N 64 //64点 #define log2N 6 //log2N=6 /*复数类型*/ typedef struct { float real; float img; }complex; complex xdata x[N]; //输⼊序列 /*复数加法*/ complex add(complex a,complex b) { complex c; c.real=a.real+b.real; c.img=a.img+b.img; return c; } /*复数减法*/ complex sub(complex a,complex b) { complex c; c.real=a.real-b.real; c.img=a.img-b.img; return c; } /*复数乘法*/ complex mul(complex a,complex b) { complex c; c.real=a.real*b.real - a.img*b.img; c.img=a.real*b.img + a.img*b.real; return c; } /***码位倒序函数***/ void Reverse(void) { unsigned int i,j,k; unsigned int t; complex temp;//临时交换变量 for(i=0;i<N;i++)//从第0个序号到第N-1个序号 { k=i;//当前第i个序号 j=0;//存储倒序后的序号,先初始化为0 for(t=0;t<log2N;t++)//共移位t次,其中log2N是事先宏定义算好的 { j<<=1; j|=(k&1);//j左移⼀位然后加上k的最低位 k>>=1;//k右移⼀位,次低位变为最低位 } if(j>i)//如果倒序后⼤于原序数,就将两个存储单元进⾏交换(判断j>i是为了防⽌重复交换) { temp=x; x=x[j]; x[j]=temp; } } } 2、第⼆个要解决的问题就是蝶形运算 ①第1级(第1列)每个蝶形的两节点“距离”为1,第2级每个蝶形的两节点“距离”为2,第3级每个蝶形的两节点“距离”为4,第4级每个蝶形的两节点“距离”为8。

fft快速傅里叶变换c语言实现

fft快速傅里叶变换c语言实现

fft快速傅里叶变换c语言实现#include#include#include#define N 1000/*定义复数类型*/typedef struct{double real;double img;}complex;complex x[N], *W; /*输入序列,变换核*/int size_x=0; /*输入序列的大小,在本程序中仅限2的次幂*/ double PI; /*圆周率*/void fft(); /*快速傅里叶变换*/void initW(); /*初始化变换核*/void change(); /*变址*/void add(complex ,complex ,complex *); /*复数加法*/void mul(complex ,complex ,complex *); /*复数乘法*/void sub(complex ,complex ,complex *); /*复数减法*/void output();int main(){int i; /*输出结果*/system("cls");PI=atan(1)*4;printf("Please input the size of x:\n");scanf("%d",&size_x);printf("Please input the data in x[N]:\n");for(i=0;i<size_x;i++)< p="">scanf("%lf%lf",&x[i].real,&x[i].img);initW();fft();output();return 0;}/*快速傅里叶变换*/void fft(){int i=0,j=0,k=0,l=0;complex up,down,product;change();for(i=0;i< log(size_x)/log(2) ;i++){ /*一级蝶形运算*/ l=1<<i;< p="">for(j=0;j<="" p="">for(k=0;k<="" p="">mul(x[j+k+l],W[size_x*k/2/l],&product);add(x[j+k],product,&up);sub(x[j+k],product,&down);x[j+k]=up;x[j+k+l]=down;}}}}/*初始化变换核*/void initW(){int i;W=(complex *)malloc(sizeof(complex) * size_x); for(i=0;i<size_x;i++){< p="">W[i].real=cos(2*PI/size_x*i);W[i].img=-1*sin(2*PI/size_x*i);}}/*变址计算,将x(n)码位倒置*/void change(){complex temp;unsigned short i=0,j=0,k=0;double t;for(i=0;i<size_x;i++){< p="">k=i;j=0;t=(log(size_x)/log(2));while( (t--)>0 ){j=j<<1;j|=(k & 1);k=k>>1;}if(j>i){temp=x[i];x[i]=x[j];x[j]=temp;}}}/*输出傅里叶变换的结果*/void output(){int i;printf("The result are as follows\n");for(i=0;i<size_x;i++){< p="">printf("%.4f",x[i].real);if(x[i].img>=0.0001)printf("+%.4fj\n",x[i].img); else if(fabs(x[i].img)<0.0001)printf("\n");else printf("%.4fj\n",x[i].img);}}void add(complex a,complex b,complex *c){ c->real=a.real+b.real;c->img=a.img+b.img;}void mul(complex a,complex b,complex *c){ c->real=a.real*b.real - a.img*b.img;c->img=a.real*b.img + a.img*b.real;}void sub(complex a,complex b,complex *c){ c->real=a.real-b.real;c->img=a.img-b.img;}</size_x;i++){<></size_x;i++){<></size_x;i++){<></i;<></size_x;i++)<>。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

快速傅立叶变换(FFT)的C++实现收藏标准的离散傅立叶DFT 变换形式如:y k=Σj=0n-1a jωn-kj = A (ωn-k).(ωn k为复数1 的第k 个n 次方根,且定义多项式A (x)=Σj=0n-1a j x j)而离散傅立叶逆变换IDFT (Inverse DFT)形式如:a j=(Σk=0n-1y kωn kj)/n .yk=Σj=0n-1 ajωn-kj = A (ωn-k).(ωnk 为复数1 的第k 个n 次方根,且定义多项式 A (x) = Σj=0n-1 ajxj )而离散傅立叶逆变换IDFT (Inverse DFT)形式如:aj=(Σk=0n-1 ykωnkj)/n .以下不同颜色内容为引用并加以修正:快速傅立叶变换(Fast Fourier Transform,FFT)是离散傅立叶变换(Discrete Fourier transform,DFT)的快速算法,它是根据离散傅立叶变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。

它对傅立叶变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。

设Xn 为N 项的复数序列,由DFT 变换,任一Xi 的计算都需要N 次复数乘法和N -1 次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N 项复数序列的Xi ,即N 点DFT 变换大约就需要N2 次运算。

当N =1024 点甚至更多的时候,需要N2 = 1048576 次运算,在FFT 中,利用ωn 的周期性和对称性,把一个N 项序列(设N 为偶数),分为两个N / 2 项的子序列,每个N / 2点DFT 变换需要(N / 2)2 次运算,再用N 次运算把两个N / 2点的DFT 变换组合成一个N 点的DFT 变换。

这样变换以后,总的运算次数就变成N + 2 * (N / 2)2 = N + N2 / 2。

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

而如果我们将这种“一分为二”的思想不断进行下去,直到分成两两一组的DFT 运算单元,那么N 点的DFT 变换就只需要N * log2N 次的运算,N = 1024 点时,运算量仅有10240 次,是先前的直接算法的1% ,点数越多,运算量的节约就越大,这就是FFT 的优越性。

FFT 的实现可以自顶而下,采用递归,但是对于硬件实现成本高,对于软件实现都不够高效,改用迭代较好,自底而上地解决问题。

感觉和归并排序的迭代版很类似,不过先要采用“位反转置换”的方法把Xi 放到合适的位置,设i 和j 互为s = log2N 位二进制的回文数,假设s = 3, i = (110)2 = 6, j = (011)2 = 3, 如果i ≠j , 那么Xi 和Xj 应该互换位置。

(关于这个回文数的生成,是很有趣而且是很基本的操作,想当初偶初学C++ 的时候就有这样的习题。

)当“位反转置换”完成后,先将每一个Xi 看作是独立的多项式,然后两个两个地将它们合并成一个多项式(每个多项式有2 项),合并实际上是“蝶形运算”(Butterfly Operation, 参考《算法导论》吧^_^),继续合并(第二次的每个多项式有4 项),直到只剩下一个多项式(有N 项),这样,合并的层数就是log2N ,每层都有N 次操作,所以总共有N * log2N 次操作。

迭代过程如下图所示,自底而上。

C++ 源程序,如下://// 快速傅立叶变换Fast Fourier Transform//********************.cn// 2007-07-20// 版本2.0// 改进了《算法导论》的算法,旋转因子取ωn-kj (ωnkj 的共轭复数)// 且只计算n / 2 次,而未改进前需要计算(n * lg n) / 2 次。

//#include <stdio.h>#include <stdlib.h>#include <math.h>const int N = 1024;const float PI = 3.1416;inline void swap (float &a, float &b){float t;t = a;a = b;b = t;}void bitrp (float xreal [], float ximag [], int n){// 位反转置换Bit-reversal Permutationint i, j, a, b, p;for (i = 1, p = 0; i < n; i *= 2){p ++;}for (i = 0; i < n; i ++){a = i;b = 0;for (j = 0; j < p; j ++){b = (b << 1) + (a & 1); // b = b * 2 + a % 2;a >>= 1; // a = a / 2;}if ( b > i){swap (xreal [i], xreal [b]);swap (ximag [i], ximag [b]);}}}void FFT(float xreal [], float ximag [], int n){// 快速傅立叶变换,将复数x 变换后仍保存在x 中,xreal, ximag 分别是x 的实部和虚部float wreal [N / 2], wimag [N / 2], treal, timag, ureal, uimag, arg;int m, k, j, t, index1, index2;bitrp (xreal, ximag, n);// 计算1 的前n / 2 个n 次方根的共轭复数W'j = wreal [j] + i * wimag [j] , j = 0, 1, , n / 2 - 1arg = - 2 * PI / n;treal = cos (arg);timag = sin (arg);wreal [0] = 1.0;wimag [0] = 0.0;for (j = 1; j < n / 2; j ++){wreal [j] = wreal [j - 1] * treal - wimag [j - 1] * timag;wimag [j] = wreal [j - 1] * timag + wimag [j - 1] * treal;}for (m = 2; m <= n; m *= 2){for (k = 0; k < n; k += m){for (j = 0; j < m / 2; j ++){index1 = k + j;index2 = index1 + m / 2;t = n * j / m; // 旋转因子w 的实部在wreal [] 中的下标为ttreal = wreal [t] * xreal [index2] - wimag [t] * ximag [index2];timag = wreal [t] * ximag [index2] + wimag [t] * xreal [index2];ureal = xreal [index1];uimag = ximag [index1];xreal [index1] = ureal + treal;ximag [index1] = uimag + timag;xreal [index2] = ureal - treal;ximag [index2] = uimag - timag;}}}}void IFFT (float xreal [], float ximag [], int n){// 快速傅立叶逆变换float wreal [N / 2], wimag [N / 2], treal, timag, ureal, uimag, arg;int m, k, j, t, index1, index2;bitrp (xreal, ximag, n);// 计算1 的前n / 2 个n 次方根Wj = wreal [j] + i * wimag [j] , j = 0, 1, , n / 2 - 1 arg = 2 * PI / n;treal = cos (arg);timag = sin (arg);wreal [0] = 1.0;wimag [0] = 0.0;for (j = 1; j < n / 2; j ++){wreal [j] = wreal [j - 1] * treal - wimag [j - 1] * timag;wimag [j] = wreal [j - 1] * timag + wimag [j - 1] * treal;}for (m = 2; m <= n; m *= 2){for (k = 0; k < n; k += m){for (j = 0; j < m / 2; j ++){index1 = k + j;index2 = index1 + m / 2;t = n * j / m; // 旋转因子w 的实部在wreal [] 中的下标为ttreal = wreal [t] * xreal [index2] - wimag [t] * ximag [index2];timag = wreal [t] * ximag [index2] + wimag [t] * xreal [index2];ureal = xreal [index1];uimag = ximag [index1];xreal [index1] = ureal + treal;ximag [index1] = uimag + timag;xreal [index2] = ureal - treal;ximag [index2] = uimag - timag;}}}for (j=0; j < n; j ++){xreal [j] /= n;ximag [j] /= n;}}void FFT_test (){char inputfile [] = "input.txt"; // 从文件input.txt 中读入原始数据char outputfile [] = "output.txt"; // 将结果输出到文件output.txt 中float xreal [N] = {}, ximag [N] = {};int n, i;FILE *input, *output;if (!(input = fopen (inputfile, "r"))){printf ("Cannot open file. ");exit (1);}if (!(output = fopen (outputfile, "w"))){printf ("Cannot open file. ");exit (1);}i = 0;while ((fscanf (input, "%f%f", xreal + i, ximag + i)) != EOF){i ++;}n = i; // 要求n 为2 的整数幂while (i > 1){if (i % 2){fprintf (output, "%d is not a power of 2! ", n);exit (1);}i /= 2;}FFT (xreal, ximag, n);fprintf (output, "FFT: i real imag ");for (i = 0; i < n; i ++){fprintf (output, "%4d %8.4f %8.4f ", i, xreal [i], ximag [i]); }fprintf (output, "================================= ");IFFT (xreal, ximag, n);fprintf (output, "IFFT: i real imag ");for (i = 0; i < n; i ++){fprintf (output, "%4d %8.4f %8.4f ", i, xreal [i], ximag [i]); }if ( fclose (input)){printf ("File close error. ");exit (1);}if ( fclose (output)){printf ("File close error. ");exit (1);}}int main (){FFT_test ();return 0;}//////////////////////////////////////////////// // sample: input.txt////////////////////////////////////////////////0.5751 00.4514 00.0439 00.0272 00.3127 00.0129 00.3840 00.6831 00.0928 00.0353 00.6124 00.6085 00.0158 00.0164 00.1901 00.5869 0//////////////////////////////////////////////// // sample: output.txt//////////////////////////////////////////////// FFT:i real imag0 4.6485 0.00001 0.0176 0.31222 1.1114 0.04293 1.6776 -0.13534 -0.2340 1.38975 0.3652 -1.25896 -0.4325 0.20737 -0.1312 0.37638 -0.1949 0.00009 -0.1312 -0.376310 -0.4326 -0.207311 0.3652 1.258912 -0.2340 -1.389713 1.6776 0.135314 1.1113 -0.042915 0.0176 -0.3122================================= IFFT:i real imag0 0.5751 -0.00001 0.4514 0.00002 0.0439 -0.00003 0.0272 -0.00004 0.3127 -0.00005 0.0129 -0.00006 0.3840 -0.00007 0.6831 0.00008 0.0928 0.00009 0.0353 -0.000010 0.6124 0.000011 0.6085 0.000012 0.0158 0.000013 0.0164 0.000014 0.1901 0.000015 0.5869 -0.0000。

相关文档
最新文档