C语言编写FFT程序
- 格式:doc
- 大小:336.06 KB
- 文档页数:10
fft傅立叶变换C语言#include "stdio.h"#include <math.h> //調用源(頭)文件struct compx /*定義一個複數結構*/{float real;float imag;};struct compx s[ 257 ]; //FFT輸入輸出均從是s[1]開始存入struct compx EE(struct compx,struct compx); //定義複數相乘結構void FFT(struct compx xin,int N); /*定義FFT函數*/struct compx EE(struct compx a1,struct compx b2) //兩複數相乘的程序{struct compx b3; //b3保存兩複數間的結果b3.real=a1.real*b2.real-a1.imag*b2.imag; //兩複數間的運算b3.imag=a1.real*b2.imag+a1.imag*b2.real;return(b3); /*返回結果*/}void FFT(struct compx xin,int N) /*FFT函數體*/{int f,m,nv2,nm1,i,k,j=1,l; /*定義變量*/struct compx v,w,t; /*定義結構變量*/nv2=N/2; /*最高位值的權值*/f=N; /*f為中間變量*/for(m=1;(f=f/2)!=1;m++){;} /*求級數m*/nm1=N-1; /*nm1為數組長度*/for(i=1;i<=nm1;i++) /*倒序*/{if(i<j) {t=xin[ j ];xin[j]=xin[ i ];xin[ i ] =t;} /*i<j則換位*/k=nv2; /*k為倒序中相應位置的權值*/while(k<j) {j=j-k;k=k/2;} /*k<j時最高為變為0*/j=j+k; /* j為數組中的位數,是一個十進制數*/}{int le,lei,ip; //變量初始化,le為序列長度float pi;for(l=1;l<=m;l++) /*l控制級數*/{le=pow(2,l); /*le等於2的l次方*/lei=le/2; /*蝶形兩節點間的距離*/pi=3.14159265;v.real=1.0; // 此次的v運於複數的初始化v.imag=0.0; w.real=cos(pi/lei); /*旋轉因子*/w.imag=-sin(pi/lei);for(j=1;j<=lei;j++) //外循環控制蝶行運算的級數{for(i=j;i<=N;i=i+le) //內循環控制每級間的運算次數{ip=i+lei; /*蝶形運算的下一個節點*/t=EE(xin[ ip ],v); /*第一個旋轉因子*/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;}v=EE(v,w); //調用EE複數相乘程序,結果給下次的循環}}}}main() /*定義主函數*/{int N,i; //變量初始化,N為總點數,i為每點數printf("shu ru N de ge shu N="); /*提示輸入*/scanf("%d",&N); /*輸入N*/ for(i=1;i<=N;i++) /*輸入*/{printf("di %d ge shu real=",i);getchar();scanf("%f",&s[ i ].real);getchar();printf("\n");printf("di %d ge shu imag=",i);scanf("%f",&s[ i ].imag);printf("\n");}FFT(s,N); /*調用FFt*/for(i=1;i<=N;i++) /*輸出*/{printf("%f",s[ i ].real);printf(" + ");printf("%f",s[ i ].imag);printf("j");printf("\n");}}。
FFT及IFFTC语言实现FFT(快速傅里叶变换)和IFFT(快速傅里叶逆变换)是傅里叶变换在计算机科学和信号处理中的高效实现方法。
它们广泛应用于图像处理、音频处理、通信系统等领域。
下面将详细介绍FFT和IFFT的C语言实现。
首先,让我们了解一下DFT(离散傅里叶变换)。
DFT将一个离散的时间域序列转换为离散的频域序列,其定义如下:其中,N表示序列的长度,x(n)是输入序列,X(k)是输出序列。
FFT是DFT的一种高效实现方法,它利用了序列的对称性质,将操作的复杂度从O(N^2)降低到O(NlogN)。
IFFT则是FFT的逆过程,可以将频域序列恢复为时间域序列。
以下是FFT的C语言实现代码:```c#include <stdio.h>#include <math.h>typedef structdouble real;double imag;result.real = a.real * b.real - a.imag * b.imag;result.imag = a.real * b.imag + a.imag * b.real;return result;result.real = a.real + b.real; result.imag = a.imag + b.imag; return result;result.real = a.real - b.real; result.imag = a.imag - b.imag; return result;if (N <= 1)return;}for (int i = 0; i < N / 2; i++) even[i] = x[2 * i];odd[i] = x[2 * i + 1];}fft(even, N / 2);fft(odd, N / 2);for (int k = 0; k < N / 2; k++)x[k] = add(even[k], t);x[k + N / 2] = subtract(even[k], t); }//完整的IFFT实现代码略,与FFT相似int mai//输入序列x(n)int N = sizeof(x) / sizeof(x[0]);//调用FFTfft(x, N);//输出频域序列X(k)for (int k = 0; k < N; k++)printf("X(%d) = %.2f + %.2fi\n", k, x[k].real, x[k].imag);}//调用IFFT//...return 0;```IFFT的实现与FFT类似,只需将其中几处计算公式略作变换即可。
#include "myapp.h"#include "ICETEK-VC5509-EDU.h"#include "scancode.h"#include <math.h>#define PI 3.1415926#define SAMPLENUMBER 128voidInitForFFT();void MakeWave();int INPUT[SAMPLENUMBER],DATA[SAMPLENUMBER];floatfWaveR[SAMPLENUMBER],fWaveI[SAMPLENUMBER],w[SAMPLENUMBER ];float sin_tab[SAMPLENUMBER],cos_tab[SAMPLENUMBER];main(){int i;InitForFFT();MakeWave();for ( i=0;i<SAMPLENUMBER;i++ ){fWaveR[i]=INPUT[i];fWaveI[i]=0.0f;w[i]=0.0f;}FFT(fWaveR,fWaveI);for ( i=0;i<SAMPLENUMBER;i++ ){DATA[i]=w[i];}while ( 1 ); // break point}void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER]) {int x0,x1,x2,x3,x4,x5,x6,xx;inti,j,k,b,p,L;float TR,TI,temp;/********** following code invert sequence ************/for ( i=0;i<SAMPLENUMBER;i++ ){x0=x1=x2=x3=x4=x5=x6=0;x0=i&0x01; x1=(i/2)&0x01; x2=(i/4)&0x01; x3=(i/8)&0x01;x4=(i/16)&0x01; x5=(i/32)&0x01; x6=(i/64)&0x01;xx=x0*64+x1*32+x2*16+x3*8+x4*4+x5*2+x6;dataI[xx]=dataR[i];}for ( i=0;i<SAMPLENUMBER;i++ ){dataR[i]=dataI[i]; dataI[i]=0;}/************** following code FFT *******************/for ( L=1;L<=7;L++ ){ /* for(1) */b=1; i=L-1;while ( i>0 ){b=b*2; i--;} /* b= 2^(L-1) */for ( j=0;j<=b-1;j++ ) /* for (2) */{p=1; i=7-L;while ( i>0 ) /* p=pow(2,7-L)*j; */{p=p*2; i--;}p=p*j;for ( k=j;k<128;k=k+2*b ) /* for (3) */{TR=dataR[k]; TI=dataI[k]; temp=dataR[k+b];dataR[k]=dataR[k]+dataR[k+b]*cos_tab[p]+dataI[k+b]*sin_tab[p]; dataI[k]=dataI[k]-dataR[k+b]*sin_tab[p]+dataI[k+b]*cos_tab[p]; dataR[k+b]=TR-dataR[k+b]*cos_tab[p]-dataI[k+b]*sin_tab[p]; dataI[k+b]=TI+temp*sin_tab[p]-dataI[k+b]*cos_tab[p];} /* END for (3) */} /* END for (2) */} /* END for (1) */for ( i=0;i<SAMPLENUMBER/2;i++ ){w[i]=sqrt(dataR[i]*dataR[i]+dataI[i]*dataI[i]);}} /* END FFT */void InitForFFT(){int i;for ( i=0;i<SAMPLENUMBER;i++ ){sin_tab[i]=sin(PI*2*i/SAMPLENUMBER);cos_tab[i]=cos(PI*2*i/SAMPLENUMBER);}}void MakeWave(){int i;for ( i=0;i<SAMPLENUMBER;i++ ){INPUT[i]=sin(PI*2*i/SAMPLENUMBER*3)*1024;}}#include"myapp.h"voidCLK_init(){ioport unsigned int *clkmd;clkmd=(unsigned int *)0x1c00;*clkmd =0x2033; // 0x2033;//0x2413;// 200MHz=0x2513}voidSetDSPPLL(unsigned intuPLL){ioport unsigned int *clkmd;clkmd=(unsigned int *)0x1c00;*clkmd =uPLL;}voidTMCR_reset( void ){ioport unsigned int *TMCR_MGS3=(unsigned int *)0x07FE; ioport unsigned int *TMCR_MM =(unsigned int *)0x07FF; *TMCR_MGS3 =0x510;*TMCR_MM =0x000;}。
/********************************************************************正弦函数快速傅立叶变换C程序函数简介:输入正弦函数的频率FC,然后由采样定理进行采样,采样频率为FS,采样后进行M点快速傅立叶变换,最后输出结果并画图。
使用说明:FS>=2FC,M为2的整数次幂。
********************************************************************/ #include "stdafx.h"#include "stdio.h"#include "math.h"#include "stdlib.h"#include "graphics.h"#include "conio.h"#define N 1000/*定义复数类型*/typedef struct{double real;double img;}complex;void fft(); /*快速傅里叶变换*/void initW(); /*初始化旋转因子*/void change(); /*变址*/void add(complex ,complex ,complex *); /*复数加法*/void mul(complex ,complex ,complex *); /*复数乘法*/void sub(complex ,complex ,complex *); /*复数减法*/void divi(complex ,complex ,complex *); /*复数除法*/void output();complex x[N], *W; /*输入序列,旋转因子*/int M=0;double PI;int main(){int i, FC, FS;int gd=DETECT,gm;system("cls");PI=atan(1)*4;printf("输入正弦频率FC:\n");scanf("%d",&FC);printf("输入采样频率FS(FS>=FC):\n");scanf("%d",&FS);printf("输入采样点数M(2的整数次幂):\n");scanf("%d",&M);for(i=0;i<M;i++){x[i].real=sin(2*PI*FC*i/FS);x[i].img=0;}initW();fft();output();for(i=0;i<M;i++){x[i].real=sqrt(x[i].real*x[i].real+x[i].img*x[i].img);}initgraph(&gd,&gm,"");cleardevice();setcolor(GREEN);line(300,400,300,50);line(300,50,295,55);line(300,50,305,55);line(40,400,600,400);line(600,400,595,395);line(600,400,595,405);setcolor(WHITE);for(i=0;i<M;i++)line(i*5+300-M*5/2,400,i*5+300-M*5/2,400-(int)x[i].real*5); getch();closegraph();return 0;}/*快速傅里叶变换*/void fft(){int i=0,j=0,k=0,l=0;complex up,down,product;change();for(i=0;i< log(M)/log(2) ;i++){l=1<<i;for(j=0;j<M;j+= 2*l ){for(k=0;k<l;k++){mul(x[j+k+l],W[M*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) * M); for(i=0;i<M;i++){W[i].real=cos(2*PI/M*i);W[i].img=-1*sin(2*PI/M*i);}}/*变址计算,将x(n)码位倒置*/void change(){complex temp;unsigned short i=0,j=0,k=0;double t;for(i=0;i<M;i++){k=i;j=0;t=(log(M)/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("FFT结果如下:\n");for(i=0;i<M;i++){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");elseprintf("%.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;}void divi(complex a,complex b,complex *c){c->real=( a.real*b.real+a.img*b.img )/( b.real*b.real+b.img*b.img); c->img=( a.img*b.real-a.real*b.img)/(b.real*b.real+b.img*b.img);}。
#include<math.h>#include<iostream.h>#include<iomanip.h>#define swap(a,b) {float T; T=(a);(a)=b;(b)=T;}void fft(float A[],float B[],unsigned M) //蝶形运算程序,A存实部,B存虚部,M是级数{unsigned long N,I,J,K,L,LE,LE1,P,Q,R;float Wr,Wi,Wlr,Wli,WTr,WTi,theta,Tr,Ti;N=1<<M;//N=1<<M表示N=2^MJ=0;for (I=0;I<N-1;I++)//for循环负责码位倒置存储{if(J<I){swap(A[I],A[J]);swap(B[I],B[J]);}K=N>>1;// K=N>>1表示K=N/2while (K>=2&&J>=K)//while循环表示须向次高位进一位{J-=K;K>>=1;//K>>=1表示K=K/2}J+=K;}for(L=1;L<=M;L++)//for循环为M级FFT运算,外层循环由级数L控制,执行M次{LE=1<<L;// LE=1<<L表示2^L,是群间隔LE1=LE/2; //每个群的系数W数目Wr=1.0;Wi=0.0;theta=(-1)*3.1415926536/LE1;Wlr=cos(theta);Wli=sin(theta);for(R=0;R<LE1;R++)//中层循环由群系数控制{for(P=R;P<N-1;P+=LE)//R是群系数的编号,P、Q是基本蝶形运算两个输入数据在数组中的编号,循环每次完成同一个系数的蝶形运算{Q=P+LE1;Tr=Wr*A[Q]-Wi*B[Q];Ti=Wr*B[Q]+Wi*A[Q];A[Q]=A[P]-Tr;B[Q]=B[P]-Ti;A[P]+=Tr;B[P]+=Ti;}WTr=Wr;WTi=Wi;Wr=WTr*Wlr-WTi*Wli;Wi=WTr*Wli+WTi*Wlr;}}return;}}void main()//主程序{int i,M,N,lb;cout<<"请输入转换类别(若为FFT,请输入1;若为IFFT,请输入0)"<<endl;//确定转换类别cin>>lb;cout<<"请输入序列长度N"<<endl;cin>>N;float *A= new float[N];float *B= new float[N];M=log(N)/log(2);cout<<"请输入序列的实部"<<endl;//输入序列实部for(i=0;i<N;i++){cin>>A[i];}cout<<"请输入序列的虚部"<<endl;//输入序列虚部for(i=0;i<N;i++){cin>>B[i];}cout << setiosflags(ios::fixed);//输出格式控制cout<<"您输入的序列为"<<endl;cout << setiosflags(ios::fixed);for(i=0;i<N;i++)cout<<A[i]<<"+j"<<B[i]<<endl;cout<<endl;if(lb==0){for(i=0;i<N;i++){B[i]=B[i]*(-1);}fft(A,B,M);for(i=0;i<N;i++){B[i]=B[i]*(-1);}for(i=0;i<N;i++){A[i]=A[i]/N;B[i]=B[i]/N;}}if(lb==1)fft(A,B,M);cout<<"转换后的序列为"<<endl;//输出序列for(i=0;i<N;i++)cout<<A[i]<<"+j("<<B[i]<<")"<<endl;cout<<endl;delete []A;delete []B;}。
一、头文件FFT.h#ifndef FFT_H#define FFT_H#include <math.h>//得到FFT结果宏定义#define FFT_RESULT(x) (sqrt(data_of_N_FFT[x].real*data_of_N_FFT[x].real+data_of_N_FFT[x].imag*data_of_N_FFT[x].i mag))//得到IFFT宏定义#define IFFT_RESULT(x) (data_of_N_FFT[x].real/N_FFT)#define PI 3.14159265358979323846264338327950288419716939937510 //圆周率,50位小数#define PI2 6.28318530717958647692528676655900576839433879875021#define N_FFT 1024 //傅里叶变换的点数#define M_of_N_FFT 10 //蝶形运算的级数,N = 2^M#define Npart2_of_N_FFT 512 //创建正弦函数表时取PI的1/2#define Npart4_of_N_FFT 256 //创建正弦函数表时取PI的1/4typedef float ElemType; //原始数据序列的数据类型,可以在这里设置typedef struct //定义复数结构体{ElemType real,imag;}complex_of_N_FFT,*ptr_complex_of_N_FFT;typedef struct //定义结构体,存储FFT变换后结果信息,复数结果及点所在位置,通过位置能够获得频率信息{complex_of_N_FFT comp; //FFT变换后复数ElemType mod; //复数模值int pos; //位置信息,FFT变换后点所在位置}point_Message;complex_of_N_FFT data_of_N_FFT[N_FFT]; //定义存储单元,原始数据与负数结果均使用之ElemType SIN_TABLE_of_N_FFT[Npart4_of_N_FFT+1];/***声明函数*///创建正弦函数表void CREATE_SIN_TABLE(void);ElemType Sin_find(ElemType x);ElemType Cos_find(ElemType x);//变址void ChangeSeat(complex_of_N_FFT *DataInput);//FFT运算函数void FFT(void);//IFFT运算函数void IFFT(void);//初始化FFT程序void Init_FFT();//结束FFT运算,释放相关内存void Close_FFT(void);//产生模拟原始数据输入,在实际应用时替换为AD采样数据void InputData(void);/********读取现有txt数据到数组*/void readtxt(char *str,int len);/*写数据到txtstr:txt文件路径(含文件名)len:读取长度*/void writetxt(char *str,int len);/************************************************************************** *********//* 取复数模函数getMod()功能:取复数a+bi 的模:sqrt(a*a + b*b)输入:输入:complex_of_N_FFT结构体输出:ElemType (float)*/ElemType getMod(complex_of_N_FFT data);/* 获得最大频率分量模值对应转换结果,含复数信息,复数模值,位置信息输入:complex_of_N_FFT 结构体,FFT转换后结果数组输出:point_Message 结构体,包含复数信息,点位置信息(FFT转换后点的位置)*/point_Message getMaxMod(void); //直接使用数组:data_of_N_FFT#endif //FFT_H二、头文件中函数的具体实现:FFT.c#include <stdio.h>#include <math.h>#include "FFT.h"//创建正弦函数表void CREATE_SIN_TABLE(void){int i=0;for(i=0; i<=Npart4_of_N_FFT; i++){SIN_TABLE_of_N_FFT[i] = sin(PI*i/Npart2_of_N_FFT);//SIN_TABLE[i] = sin(PI2*i/N);}}ElemType Sin_find(ElemType x){int i = (int)(N_FFT*x);//注意:i已经转化为0~N之间的整数了!i = i>>1;// i = i / 2;if(i>Npart4_of_N_FFT){//根据FFT相关公式,sin()参数不会超过PI,即i不会超过N/2i = Npart2_of_N_FFT - i;//i = i - 2*(i-Npart4);}return SIN_TABLE_of_N_FFT[i];}ElemType Cos_find(ElemType x){int i = (int)(N_FFT*x);//注意:i已经转化为0~N之间的整数了!i = i>>1;if(i < Npart4_of_N_FFT ){ //不会超过N/2//i = Npart4 - i;return SIN_TABLE_of_N_FFT[Npart4_of_N_FFT - i];}else //i > Npart4 && i < N/2{//i = i - Npart4;return -SIN_TABLE_of_N_FFT[i - Npart4_of_N_FFT];}}//变址void ChangeSeat(complex_of_N_FFT *DataInput){int nextValue,nextM,i,k,j=0;complex_of_N_FFT temp;nextValue=N_FFT/2; //变址运算,即把自然顺序变成倒位序,采用雷德算法nextM=N_FFT-1;for (i=0;i<nextM;i++){if (i<j) //如果i<j,即进行变址{temp=DataInput[j];DataInput[j]=DataInput[i];DataInput[i]=temp;}k=nextValue; //求j的下一个倒位序while (k<=j) //如果k<=j,表示j的最高位为1{j=j-k; //把最高位变成0k=k/2; //k/2,比较次高位,依次类推,逐个比较,直到某个位为0}j=j+k; //把0改为1}}//复数乘法/*complex XX_complex(complex a, complex b){complex temp;temp.real = a.real * b.real-a.imag*b.imag;temp.imag = b.imag*a.real + a.imag*b.real;return temp;}*///FFT运算函数void FFT(void){int L=0,B=0,J=0,K=0;//ElemType P=0;ElemType angle;complex_of_N_FFT W,Temp_XX;ChangeSeat(data_of_N_FFT);//变址//CREATE_SIN_TABLE();for(L=1; L<=M_of_N_FFT; L++){step = 1<<L;//2^LB = step>>1;//B=2^(L-1)for(J=0; J<B; J++){//P = (1<<(M-L))*J;//P=2^(M-L) *Jangle = (double)J/B; //这里还可以优化W.imag = -Sin_find(angle); //用C++该函数课声明为inlineW.real = Cos_find(angle); //用C++该函数课声明为inline//W.real = cos(angle*PI);//W.imag = -sin(angle*PI);for(K=J; K<N_FFT; K=K+step){KB = K + B;//Temp_XX = XX_complex(data[KB],W);//用下面两行直接计算复数乘法,省去函数调用开销Temp_XX.real = data_of_N_FFT[KB].real * W.real-data_of_N_FFT[KB].imag*W.imag;Temp_XX.imag = W.imag*data_of_N_FFT[KB].real + data_of_N_FFT[KB].imag*W.real;data_of_N_FFT[KB].real = data_of_N_FFT[K].real - Temp_XX.real;data_of_N_FFT[KB].imag = data_of_N_FFT[K].imag - Temp_XX.imag;data_of_N_FFT[K].real = data_of_N_FFT[K].real + Temp_XX.real;data_of_N_FFT[K].imag = data_of_N_FFT[K].imag + Temp_XX.imag;}}}}//IFFT运算函数void IFFT(void){int L=0,B=0,J=0,K=0;//ElemType P=0;ElemType angle;complex_of_N_FFT W,Temp_XX;ChangeSeat(data_of_N_FFT);//变址//CREATE_SIN_TABLE();for(L=1; L<=M_of_N_FFT; L++){step = 1<<L;//2^LB = step>>1;//B=2^(L-1)for(J=0; J<B; J++){//P = (1<<(M-L))*J;//P=2^(M-L) *Jangle = (double)J/B; //这里还可以优化W.imag = Sin_find(angle); //用C++该函数课声明为inlineW.real = Cos_find(angle); //用C++该函数课声明为inline//W.real = cos(angle*PI);//W.imag = -sin(angle*PI);for(K=J; K<N_FFT; K=K+step){KB = K + B;//Temp_XX = XX_complex(data[KB],W);//用下面两行直接计算复数乘法,省去函数调用开销Temp_XX.real = data_of_N_FFT[KB].real * W.real-data_of_N_FFT[KB].imag*W.imag;Temp_XX.imag = W.imag*data_of_N_FFT[KB].real + data_of_N_FFT[KB].imag*W.real;data_of_N_FFT[KB].real = data_of_N_FFT[K].real - Temp_XX.real;data_of_N_FFT[KB].imag = data_of_N_FFT[K].imag - Temp_XX.imag;data_of_N_FFT[K].real = data_of_N_FFT[K].real + Temp_XX.real;data_of_N_FFT[K].imag = data_of_N_FFT[K].imag + Temp_XX.imag;}}}}//初始化FFT程序void Init_FFT(){CREATE_SIN_TABLE(); //创建正弦函数表}//结束FFT运算,释放相关内存void Close_FFT(void){}//产生模拟原始数据输入,在实际应用时替换为AD采样数据void InputData(void){int i;for(i=0; i<N_FFT; i++)//制造输入序列{// data_of_N_FFT[i].real = 2 + sin(2*PI*i/N_FFT) + 3*sin(2*PI*10*i/N_FFT); //这么写会出现Segmentation fault (core dumped))data_of_N_FFT[i].real = 1 + sin(2*PI*i/N_FFT) + 3*sin(2*PI*10*i/N_FFT); //这么写不会出现上面错误data_of_N_FFT[i].imag = 0;}}/********读取现有txt数据到数组*/void readtxt(char *str,int len){int i;FILE *fp;fp=fopen(str,"r");if(fp == NULL)return;for(i=0;i<len;i++){fscanf(fp,"%f",&data_of_N_FFT[i].real);data_of_N_FFT[i].imag = 0;}fclose(fp);}/**写入数据到txt*/void writetxt(char *str,int len){int i;FILE *fp;if((fp=fopen(str,"w")) == NULL){return;}for(i=0; i<len; i++)fprintf(fp,"%8.4f ",FFT_RESULT(i)*2/len);fclose(fp);}/************************************************************************** *********//* 取复数模函数getMod()功能:取复数a+bi 的模:sqrt(a*a + b*b)输入:输入:complex_of_N_FFT结构体输出:ElemType (float)*/ElemType getMod(complex_of_N_FFT data){return (sqrt(data.real*data.real + data.imag*data.imag));}/* 获得最大频率分量模值对应转换结果,含复数信息,复数模值,位置信息输入:complex_of_N_FFT 结构体,FFT转换后结果数组输出:point_Message 结构体,包含复数信息,点位置信息(FFT转换后点的位置)*///complex_of_N_FFT getMaxMod(complex_of_N_FFT *Data_FFT)//point_Message getMaxMod(complex_of_N_FFT Data_FFT[]) //complex_of_N_FFT *Data_FFT出现了野指针,Data_FFT没有分配空间?还是不行point_Message getMaxMod(void) //直接使用数组:data_of_N_FFT{int i,max;ElemType mod;point_Message pointMsg; //返回结构体ElemType MaxMod = getMod(data_of_N_FFT[0]); //第一个点模值for(i=1; i<(N_FFT/2); i++) //FFT转换结果对称,取一半比较{mod = getMod(data_of_N_FFT[i]);if(MaxMod < mod){MaxMod = mod; //取最大模max = i;}}p = data_of_N_FFT[max];// p.real = data_of_N_FFT[max].real; //复数信息// p.imag = data_of_N_FFT[max].imag;pointMsg.mod = MaxMod; //复数模值pointMsg.pos = max; //位置信息return pointMsg; //返回点结构体}三、主函数main.c#include "FFT.h"#include <stdio.h>//主函数,示例如何调用FFT运算int main(int argc, char *argv[]){int i = 0;point_Message maxMod; //模值最大点信息结构体Init_FFT(); //①初始化各项参数,此函数只需执行一次; 修改FFT的点数去头文件的宏定义处修改//模拟输入数据// InputData(); //②输入原始数据,此处在实际应用时替换为AD采样数据//读取txt数据readtxt(“d:\\a.txt”,1024); //读取原始数据FFT(); //③进行FFT计算//for(i=0; i<N_FFT; i++)//④输出FFT频谱结果sqrt(data_of_N_FFT[i].real*data_of_N_FFT[i].real+data_of_N_FFT[i].imag*data_of_N_FFT[i].imag )//{printf("%f ",FFT_RESULT(i));}//最大模值对应信息,复数,复数模,点maxMod = getMaxMod();printf("mod=%8.4f, pos=%d\n",maxMod.mod,maxMod.pos); //打印最大模值//IFFT();//进行IFFT计算writetxt("d:\\c.txt",1024); //写结果到c.txtgetchar();return 0;}。
以下是使用C语言实现快速傅里叶变换(FFT)的示例代码:c复制代码#include<stdio.h>#include<math.h>#define PI 3.14void fft(double* x, double* out, int n) {if (n == 1) {out[0] = x[0];return;}double w_n = 2 * PI / n;double w_m = exp(-1j * w_n / 2);double w = 1.0;for (int k = 0; k < n / 2; k++) {double t = w * x[2 * k];out[k] = t + x[2 * k + 1];out[k + n / 2] = t - x[2 * k + 1];w *= w_m;}fft(x, out, n / 2);fft(&x[n / 2], &out[n / 2], n / 2);}int main() {int n = 8; // 输入序列长度为8double x[] = {1, 1, 1, 1, 0, 0, 0, 0}; // 输入序列double out[n]; // 输出序列fft(x, out, n); // 进行FFT变换for (int i = 0; i < n; i++) {printf("%f ", out[i]); // 输出FFT变换结果}printf("\n");return0;}以上代码中,fft函数实现了快速傅里叶变换,main函数用于测试。
在fft函数中,首先判断序列长度是否为1,如果是则直接返回序列本身;否则,将序列分为奇数位和偶数位两个子序列,分别进行FFT变换,然后将两个子序列的FFT结果进行合并。
在循环中,使用w表示旋转因子,w_n表示旋转角度,w_m表示旋转因子的乘积因子。
fft c语言程序以下是一个基于C语言的FFT(快速傅里叶变换)程序示例:```c#include <stdio.h>#include <math.h>#define PI 3.14159265void FFT(double complex *x, int n ) {if ( n <= 1 ) return;double complex even ( n /2 );double complex odd ( n /2 );for ( int i =0 ; i < n / 2 ; i++) {even (i) = x[2 * i];odd (i) = x[2 * i + 1 ];FFT(even , n /2 );FFT(odd , n /2 );}for ( int i =0 ; i < n / 2 ; i++) {double complex t = cexp(-I *2 *PI * i / n ) * odd (i); x[i] = even (i) + t ;x[i + n /2 ] = even (i) - t ;}}int main() {double complex x[] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 };int n = sizeof(x) / sizeof(double complex );FFT(x, n );for ( int i =0 ; i < n ; i++) {printf( "%f + %fi\n" , creal(x[i]), cimag(x[i]));}return 0 ;}```这个程序使用了递归的方法来实现快速傅里叶变换。
它接受一个复数数组`x`作为输入,并计算其傅里叶变换。
在主函数中,定义了一个复数数组`x`,并调用`FFT`函数对其进行变换。
最后,输出变换后的结果。
sdft傅里叶 c语言代码实现以下是C语言实现一维离散傅里叶变换(DFT)和逆变换(IDFT)的示例代码:```cinclude <>include <>define PI// 计算复数乘积void complex_multiply(double complex a, double complex b, double complex c) {double real = a creal(b) - a cimag(b);double imag = a cimag(b) + a creal(b);c = real + imag I;}// 计算复数加法void complex_add(double complex a, double complex b, double complex c) {c = a + b;}// 计算复数减法void complex_subtract(double complex a, double complex b, double complex c) {c = a - b;}// 计算复数共轭void complex_conjugate(double complex a, double complex c) {c = a - imag(a) I;}// 计算复数模长double complex_magnitude(double complex a) {return sqrt(creal(a) creal(a) + cimag(a) cimag(a));}// 计算复数角度double complex_angle(double complex a) {return atan2(cimag(a), creal(a));}// 计算一维离散傅里叶变换(DFT)void dft(int n, double complex x[]) {for (int k = 0; k < n; k++) {x[k] = 0;for (int t = 0; t < n; t++) {double complex w = cexp(-I PI k t / n) / n;complex_multiply(x[t], w, &x[k]);}}}// 计算一维离散傅里叶逆变换(IDFT)void idft(int n, double complex x[], double complex y[]) { for (int k = 0; k < n; k++) {y[k] = 0;for (int t = 0; t < n; t++) {double complex w = cexp(I PI k t / n) / n; complex_multiply(x[t], w, &y[k]);}}}```。
DSP 课程作业用C 语言编写FFT 程序1,快速傅里叶变换FFT 简介快速傅氏变换(FFT ),是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。
它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。
我们假设 x(n)为N 项的复数序列,由DFT 变换,任一X (m )的计算都需要N 次复数乘法和N-1次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N 项复数序列的X (m ),即N 点DFT 变换大约就需要N^2次运算。
当N=1024点甚至更多的时候,需要N2=1048576次运算,在FFT 中,利用WN 的周期性和对称性,把一个N 项序列(设N=2k,k 为正整数),分为两个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 变换就只需要Nlog2N 次的运算,N 在1024点时,运算量仅有10240次,是先前的直接算法的1%,点数越多,运算量的节约就越大,这就是FFT 的优越性。
2,FFT 算法的基本原理FFT 算法的基本思想:利用DFT 系数的特性,合并DFT 运算中的某些项,吧长序列的DFT —>短序列的DFT ,从而减少其运算量。
FFT 算法分类:时间抽选法DIT: Decimation-In-Time ;频率抽选法DIF: Decimation-In-Frequency按时间抽选的基-2FFT 算法1、算法原理设序列点数 N = 2L ,L 为整数。
若不满足,则补零。
N 为2的整数幂的FFT 算法称基-2FFT 算法。
将序列x(n)按n 的奇偶分成两组:则x(n)的DFT: ()()()()12221x r x r x r x r=+=0,1,...,12N r =-()()()()111000N N N nk nk nk N N N n n n X k x n W x n W x n W ---=====+∑∑∑其中再利用周期性求X(k)的后半部分:n 为奇数n 为偶数()()()221121200221N N r k rk N N r r x r W x r W --+===++∑∑()()()()2211221200N N rk rkk N N N r r x r W W x r W --===+∑∑()()22111/22/200N N rk k rk N N N r r x r W W x r W --===+∑∑(,0,1,...1)2N r k =-()()12k N X k W X k =+2222111100()()(2)N N N N rk rk r r X k x r W x r W --====∑∑2222111100()()(2)N N N N rk rk r r X k x r W x r W --====∑∑(0,1,...1)2N k =-()()()()121122,222N X k X k N N X k X k X k X k ⎛⎫⎛⎫∴+=+= ⎪ ⎪⎝⎭⎝⎭是以为周期的1212()()()()()()2k N k N X k X k W X k N X k X k W X k ⎧=+⎪∴⎨+=-⎪⎩22N N k k k N N N N W W W W +==-又2)、运算量当N = 2L 时,共有L 级蝶形,每级N / 2个蝶形,每 222()2()log log 2F F m DFT N N N m FFT N N ==比较DFT 2log F a NL N N == 复数加法: 2log 22F N N m L N == 复数乘法:3)、算法特点 原位计算 1111()()()()()()r m m m N r m m m N X k X k X j W X j X k X j W ----⎧=+⎨=-⎩2102()()x n n n n n = 蝶形运算两节点的第一个节点为k 值,表示成L 位二进制数,左移L – m 位,把右边空出的位置补零,结果为r 的二进制数。
倒位序对N = 2L 点FFT ,输入倒位序,输出自然序, 第m 级运算每个蝶形的两节点距离为 2m –1蝶形运算输入序列x(n) : N 个存储单元 系数 :N / 2个存储单元 3,快速傅立叶变换的C 语言实现方法我们要衡量一个处理器有没有足够的能力来运行FFT 算法,根据以上的简单介绍可以得出以下两点:1. 处理器要在一个指令周期能完成乘和累加的工作,因为复数运算要多次查表相乘才能实现。
2. 间接寻址,可以实现增/减1个变址量,方便各种查表方法。
FFT 要对原始序列进行反序排列,处理器要有反序间接寻址的能力。
#include <stdio.h>#include <math.h>#include <stdlib.h>#define N 1000typedef struct{double real;double img;}complex;1111111()()(2)(2)()(2)m r m m m N m m r m m m N X k X k X k W X k X k X k W -------⎧=++⎨+=-+⎩r N W 的确定r N W蝶形运算两节点的第一个节点为k 值,表示成L 位二进制数,左移L – m 位,把右边空出的位置补零,结果为r 的二进制数。
存储单元void fft();void ifft();void initW(); /*初始化变化核*/void change();void add(complex ,complex ,complex *);void mul(complex ,complex ,complex *);void sub(complex ,complex ,complex *);void divi(complex ,complex ,complex *);void output();complex x[N], *W;/*输出序列的值*/int size_x=0;/*输入序列的长度,只限2的N次方*/double PI;int main(){int i,method;system("cls");PI=atan(1)*4;/*pi等于4乘以1.0的正切值*/printf("Please input the size of x:\n");/*输入序列的长度*/scanf("%d",&size_x);printf("Please input the data in x[N]:(such as:5 6)\n"); /*输入序列对应的值*/for(i=0;i<size_x;i++)scanf("%lf %lf",&x[i].real,&x[i].img);initW();/*选择FFT或逆FFT运算*/printf("Use FFT(0) or IFFT(1)?\n");scanf("%d",&method);if(method==0)fft();elseifft();output();return 0;}/*进行基-2 FFT运算*/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;for(j=0;j<size_x;j+= 2*l ) /*一组蝶形运算*/{for(k=0;k<l;k++) /*一个蝶形运算*/{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 ifft(){int i=0,j=0,k=0,l=size_x;complex up,down;for(i=0;i< (int)( log(size_x)/log(2) );i++) /*一级蝶形运算*/ {l/=2;for(j=0;j<size_x;j+= 2*l ) /*一组蝶形运算*/{for(k=0;k<l;k++) /*一个蝶形运算*/{add(x[j+k],x[j+k+l],&up);up.real/=2;up.img/=2;sub(x[j+k],x[j+k+l],&down);down.real/=2;down.img/=2;divi(down,W[size_x*k/2/l],&down);x[j+k]=up;x[j+k+l]=down;}}}change();}/*初始化变化核*/void initW(){int i;W=(complex *)malloc(sizeof(complex) * size_x); for(i=0;i<size_x;i++){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++){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++){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");elseprintf("%.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;}void divi(complex a,complex b,complex *c){c->real=( a.real*b.real+a.img*b.img )/(b.real*b.real+b.img*b.img);c->img=( a.img*b.real-a.real*b.img)/(b.real*b.real+b.img*b.img); }。