FFT最详细的源代码和解释

合集下载

python fft参数解释

python fft参数解释

python fft参数解释Python FFT 参数解释。

在Python中,FFT(快速傅立叶变换)是一种用于信号处理和频谱分析的重要工具。

通过使用FFT,你可以将一个信号从时间域转换为频域,从而可以分析信号的频率成分和能量分布。

在Python 中,你可以使用NumPy库来进行FFT分析,下面我们来解释一下Python中FFT函数的参数。

首先,让我们来看看FFT函数的基本语法:python.numpy.fft.fft(a, n=None, axis=-1, norm=None)。

参数解释:`a`,要进行FFT变换的输入数组。

`n`,FFT的长度,如果不指定,则默认为输入数组的长度。

如果指定的长度小于输入数组的长度,则输入数组将被截断,如果指定的长度大于输入数组的长度,则输入数组将被填充0。

`axis`,指定进行FFT变换的轴,默认为最后一个轴。

`norm`,归一化选项,可以为"ortho"或者None,默认为None。

如果为"ortho",则进行归一化处理,使得傅立叶变换满足能量守恒定律。

使用FFT函数进行频谱分析时,通常会使用一维或者二维数组作为输入,然后指定FFT的长度和归一化选项。

通过调整这些参数,你可以对不同长度的信号进行频谱分析,并且可以根据需要进行归一化处理。

除了基本的FFT函数之外,NumPy库还提供了许多其他与FFT相关的函数,如傅立叶逆变换、频谱转换等,这些函数可以帮助你更好地进行信号处理和频谱分析。

总之,Python中的FFT函数是一个强大的工具,可以帮助你进行信号处理和频谱分析。

通过合理地设置参数,你可以对不同长度和类型的信号进行频谱分析,并且可以根据需要进行归一化处理,从而得到准确的频谱信息。

希望本文对你理解Python中FFT函数的参数有所帮助。

快速傅立叶变换(FFT)源程序

快速傅立叶变换(FFT)源程序

//实验用的头文件MYFFT.H//作用:为帮助小虎子做实验,这个头文件提供了完整的一维与二维FFT算法,我想应改是够你折腾了吧!#include <complex> // complex<float>using namespace std;typedef complex<float> 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; i<N; i++)new_x = x[BitReverse(i, M)];// 重新存入原数据中(已经是二进制整序过了的数据)for (i=0; i<N; i++)x = 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<N/2; i++){if (flag == 1)W = exp(Comp(0, -_2PI_ * i / N)); // 正FFT变换elseW = 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 正逆变换标记以下本应由自己完成。

快速傅里叶变换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。

FFT最详细的源代码和解释

FFT最详细的源代码和解释

我自己的一些详细标注,有利于深入了解FFT,后面附加几位网友对FFT的理解及源代码,让广大朋友更迅速的掌握FFT#include "DSP281x_Device.h" // DSP281x Headerfile Include File,添加所有头文件#include "DSP281x_Examples.h" // DSP281x Examples Include File,条件编译而已#include "f2812a.h" //一些变量的宏定义而已#include"math.h"#define PI 3.1415926 //前变后常#define SAMPLENUMBER 128//#define SAMPLENUMBER 512void InitForFFT();void MakeWave();//void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER]);int INPUT[SAMPLENUMBER],DATA[SAMPLENUMBER];float fWaveR[SAMPLENUMBER],fWaveI[SAMPLENUMBER],w[SAMPLENUMBER];float sin_tab[SAMPLENUMBER],cos_tab[SAMPLENUMBER];//逐级计算FFT,一级一级递推void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER]){int x0,x1,x2,x3,x4,x5,x6,xx;int i,j,k,b,p,L;float TR,TI,temp;/********** following code invert sequence ************///倒序for ( i=0;i<SAMPLENUMBER;i++ )//就是码位倒置嘛,二进制各个位独立出来再反向{ //128七位二进制表示,/号代表右移嘛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;/* b的意义非常重大,b表示当前层不同旋转因子的个数*/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 */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);//输入波形进行FFT变换,此处引入起始实参即可递推下去for ( i=0;i<SAMPLENUMBER;i++ ){DATA[i]=w[i];//变换后的波形转换到输出接口}while ( 1 );// break point}//旋转因子事先初始化好,方便调用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++ )//1024是相应的幅值嘛,只要弄出个基波,以之为标准即可{INPUT[i]=sin(PI*2*i/SAMPLENUMBER)*1024+sin(PI*2*i/SAMPLENUMBER*3)*1024/3+sin(PI*2*i/SAMPLENUMBER*5)*1024/5+sin(PI*2*i/SAMPLENUMBER*7)*1024/7+sin(PI*2*i/SAMPLENUMBER*9)*1024/9;//INPUT[i]=sin(PI*2*i/SAMPLENUMBER*3)*1024;}}X[0] = x[0]*(1-0) + x[1]*(1-0) = x[0] + 1*x[1]; X[1] = x[0]*(1-0) + x[1]*(-1-0) = x[0] - 1*x[1];这就是单个2点蝶形算法.FFT实现流程图分析(N=8, 以8点信号为例)FFT implementation of an 8-point DFT as two 4-point DFTs and four 2-pointDFTs8点FFT流程图(Layer表示层, gr表示当前层的颗粒)下面以LayerI为例.LayerI部分, 具有4个颗粒, 每个颗粒2个输入(注意2个输入的来源, 由时域信号友情提供, 感谢感谢☺)我们将输入x[k]分为两部分x_r[k], x_i[k]. 具有实部和虚部, 时域信号本没有虚部的, 因此可以让x_i[k]为0. 那么为什么还要画蛇添足分为实部和虚部呢? 这是因为LayerII, LayerIII的输入是复数, 为了编码统一而强行分的.当然你编码时可以判断当前层是否为1来决定是否分. 但是我想每个人最后都会倾向分的.旋转因子 tw = cos(2*PI*k/N)-j*sin(2*PI*k/N); 也可以分为实部和虚部, 令其为tw_r, tw_i;则tw = tw_r - j*tw_i;X[k] = (x_r[k] + j*x_i[k]) + (tw_r–j*tw_i) * (x_r[k+N/2]+j*x_i[k+N/2])则X_R[k] = x_r[k] + tw_r*x_r[k+N/2] + tw_i*x_i[k+N/2];X_I[k] = x_i[k] - tw_i*x_r[k+N/2] + tw_r*x_i[k+N/2];LayerII部分, 具有2个颗粒, 每个颗粒4个输入(注意4个输入的来源, 由LayerI友情提供, 感谢感谢☺)LayerIII部分, 具有1个颗粒, 每个颗粒8个输入(注意8个输入的来源, 由LayerII友情提供, 感谢感谢☺)LayerI, LayerII, LayerIII从左往右, 蝶形信号运算流非常明显!假令输入为x[k], x[k+N/2], 输出为X[k], X[k+N/2]. x[k]分解为x_r[k], x_i[k]部分则该蝶形运算为X[k]= (x_r[k]-j*x_i[k]) +(x_r[k+N/2]-j*x_i[k+N/2])*(cos(2*PI*k/N)-j*sin(2*PI*k/N));再令cos(2*PI*k/N)为tw1, sin(2*PI*k/N)为tw2 则X[k] = (x_r[k]-j*x_i[k]) + (x_r[k+N/2]-j*x_i[k+N/2])*(tw1-j*tw2);X_R[k] = x_r[k] + x_r[k+N/2]*tw1 - x_i[k+N/2]*tw2;X_I[K] = x_i[k]x_r[k] = x_r[k] + x_r[k+b]*tw1 + x_i[k+b]*tw2;x_i[k] = x_i[k] - x_r[k+b]*tw2 + x_i[k+b]*tw1;譬如8点输入x[8]1. 先分割成2部分: x[0], x[2], x[4], x[6] 和 x[1], x[3], x[5], x[7]2. 信号x[0], x[2], x[4], x[6]再分割成x[0], x[4] 和 x[2], x[6]信号x[1], x[3], x[5], x[7]再分割成x[1], x[5] 和 x[3], x[7]3. 无法分割了, 已经分割成2点了☺.如上图:在LayerI的时候, 我们是对2点进行DFT.( 一共4次DFT )输入为 x[0]&x[4]; x[2]&x[6]; x[1]&x[5]; x[3]&x[7]输出为 y[0],y[1]; Y[2],y[3]; Y[4],y[5]; Y[6],y[7];流程:I. 希望将输入直接转换为x[0], x[4], x[2], x[6], x[1], x[5], x[3], x[7]的顺序II. 对转换顺序后的信号进行4次DFT步骤I代码实现/*** 反转算法.这个算法效率比较低!先用起来在说, 之后需要进行优化.*/static void bitrev( void ){int p=1, q, i;int bit_rev[ N ];float xx_r[ N ];bit_rev[ 0 ] = 0;while( p < N ){for(q=0; q<p; q++){bit_rev[ q ] = bit_rev[ q ] * 2;bit_rev[ q + p ] = bit_rev[ q ] + 1;}p *= 2;}for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ];}// ------------------------ 此刻序列x重排完毕------------------------步骤II代码实现int j;float TR; // 临时变量float tw1; // 旋转因子/* 两点DFT */for(k=0; k<N; k+=2){// 两点DFT简化告诉我们tw1=1TR = x_r[k]; // TR就是A, x_r[k+b]就是B.x_r[k] = TR + tw1*x_r[k+b];x_r[k+b] = TR - tw1*x_r[k+b];}在LayerII的时候, 我们希望得到z, 就需要对y进行DFT.y[0],y[2]; y[1],y[3]; y[4],y[6]; y[5],y[7];z[0], z[1]; z[2],z[3]; z[4],z[5]; z[6],z[7];在LayerIII的时候, 我们希望得到v, 就需要对z进行DFT.z[0],z[4]; z[1],z[5]; z[2],z[6]; z[3],z[7];v[0],v[1]; v[2],v[3]; v[4],v[5]; v[6],v[7];准备令输入为x[s], x[s+N/2], 输出为y[s], y[s+N/2]这个N绝对不是上面的8, 这个N是当前颗粒的输入样本总量对于LayerI而言N是2; 对于LayerII而言N是4; 对于LayerIII而言N是8复数乘法:(a+j*b) * (c+j*d)实部 = a*c – bd;虚部 = ad + bc;旋转因子:实现(C描述)#include <stdio.h>#include <math.h>#include <stdlib.h>//#include "complex.h"//--------------------------------------------------------------------------#define N 8 //64#define M 3 //6 //2^m=N#define PI 3.1415926//--------------------------------------------------------------------------float twiddle[N/2] = {1.0, 0.707, 0.0, -0.707};float x_r[N] = {1, 1, 1, 1, 0, 0, 0, 0};float x_i[N]; //N=8/*float twiddle[N/2] = {1, 0.9951, 0.9808, 0.9570, 0.9239, 0.8820, 0.8317, 0.7733,0.7075,0.6349, 0.5561, 0.4721, 0.3835, 0.2912, 0.1961, 0.0991 ,0.0000,-0.0991,-0.1961,-0.2912,-0.3835,-0.472 1,-0.5561,-0.6349,-0.7075,-0.7733,0.8317,-0.8820,-0.9239,-0.9570,-0.9808,-0.9951}; //N=64float x_r[N]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,}; float x_i[N];*/FILE *fp;// ----------------------------------- func-----------------------------------/*** 初始化输出虚部*/static void fft_init( void ){int i;for(i=0; i<N; i++) x_i[i] = 0.0;}/*** 反转算法.将时域信号重新排序.* 这个算法有改进的空间*/static void bitrev( void ){int p=1, q, i;int bit_rev[ N ]; //float xx_r[ N ]; //bit_rev[ 0 ] = 0;while( p < N ){for(q=0; q<p; q++){bit_rev[ q ] = bit_rev[ q ] * 2;bit_rev[ q + p ] = bit_rev[ q ] + 1;}p *= 2;}for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ]; }/* ------------ add by sshc625 ------------ */static void bitrev2( void ){return ;}/* */void display( void ){printf("/n/n");int i;for(i=0; i<N; i++)printf("%f/t%f/n", x_r[i], x_i[i]);}/****/void fft1( void ){ fp = fopen("log1.txt", "a+");int L, i, b, j, p, k, tx1, tx2;float TR, TI, temp; // 临时变量float tw1, tw2;/* 深M. 对层进行循环. L为当前层, 总层数为M. */for(L=1; L<=M; L++){fprintf(fp,"----------Layer=%d----------/n", L);/* b的意义非常重大,b表示当前层的颗粒具有的输入样本点数 */b = 1;i = L - 1;while(i > 0){b *= 2;i--;}// -------------- 是否外层对颗粒循环, 内层对样本点循环逻辑性更强一些呢! --------------/** outter对参与DFT的样本点进行循环* L=1, 循环了1次(4个颗粒, 每个颗粒2个样本点)* L=2, 循环了2次(2个颗粒, 每个颗粒4个样本点)* L=3, 循环了4次(1个颗粒, 每个颗粒8个样本点)*/for(j=0; j<b; j++){/* 求旋转因子tw1 */p = 1;i = M - L; // M是为总层数, L为当前层.while(i > 0){p = p*2;i--;}p = p * j;tx1 = p % N;tx2 = tx1 + 3*N/4;tx2 = tx2 % N;// tw1是cos部分, 实部; tw2是sin部分, 虚数部分.tw1 = ( tx1>=N/2)? -twiddle[tx1-N/2] : twiddle[ tx1 ]; tw2 = ( tx2>=N/2)? -twiddle[tx2-(N/2)] : twiddle[tx2];/** inner对颗粒进行循环* L=1, 循环了4次(4个颗粒, 每个颗粒2个输入)* L=2, 循环了2次(2个颗粒, 每个颗粒4个输入)* L=3, 循环了1次(1个颗粒, 每个颗粒8个输入)*/for(k=j; k<N; k=k+2*b){TR = x_r[k]; // TR就是A, x_r[k+b]就是B.TI = x_i[k];temp = x_r[k+b];/** 如果复习一下 (a+j*b)(c+j*d)两个复数相乘后的实部虚部分别是什么* 就能理解为什么会如下运算了, 只有在L=1时候输入才是实数, 之后层的* 输入都是复数, 为了让所有的层的输入都是复数, 我们只好让L=1时候的* 输入虚部为0* x_i[k+b]*tw2是两个虚数相乘*/fprintf(fp, "tw1=%f, tw2=%f/n", tw1, tw2);x_r[k] = TR + x_r[k+b]*tw1 + x_i[k+b]*tw2;x_i[k] = TI - x_r[k+b]*tw2 + x_i[k+b]*tw1;x_r[k+b] = TR - x_r[k+b]*tw1 - x_i[k+b]*tw2;x_i[k+b] = TI + temp*tw2 - x_i[k+b]*tw1;fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f/n", k, x_r[k],x_i[k]);fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f/n", k+b, x_r[k+b], x_i[k+b]);} //} //} //}/*** ------------ add by sshc625 ------------* 该实现的流程为* for( Layer )* for( Granule )* for( Sample )*****/void fft2( void ){ fp = fopen("log2.txt", "a+");int cur_layer, gr_num, i, k, p;float tmp_real, tmp_imag, temp; // 临时变量, 记录实部float tw1, tw2;// 旋转因子,tw1为旋转因子的实部cos部分, tw2为旋转因子的虚部sin部分.int step; // 步进int sample_num; // 颗粒的样本总数(各层不同, 因为各层颗粒的输入不同)/* 对层循环 */for(cur_layer=1; cur_layer<=M; cur_layer++){/* 求当前层拥有多少个颗粒(gr_num) */gr_num = 1;i = M - cur_layer;while(i > 0){i--;gr_num *= 2;}/* 每个颗粒的输入样本数N' */sample_num = (int)pow(2, cur_layer);/* 步进. 步进是N'/2 */step = sample_num/2;/* */k = 0;/* 对颗粒进行循环 */for(i=0; i<gr_num; i++){/** 对样本点进行循环, 注意上限和步进*/for(p=0; p<sample_num/2; p++){// 旋转因子, 需要优化...tw1 = cos(2*PI*p/pow(2, cur_layer)); tw2 = -sin(2*PI*p/pow(2, cur_layer));tmp_real = x_r[k+p];tmp_imag = x_i[k+p];temp = x_r[k+p+step];/*(tw1+jtw2)(x_r[k]+jx_i[k])** real : tw1*x_r[k] - tw2*x_i[k]* imag : tw1*x_i[k] + tw2*x_r[k]* 我想不抽象出一个* typedef struct {* double real; // 实部* double imag; // 虚部* } complex; 以及针对complex的操作* 来简化复数运算是否是因为效率上的考虑!*//* 蝶形算法 */x_r[k+p] = tmp_real + ( tw1*x_r[k+p+step] -tw2*x_i[k+p+step] );x_i[k+p] = tmp_imag + ( tw2*x_r[k+p+step] +tw1*x_i[k+p+step] );/* X[k] = A(k)+WB(k)* X[k+N/2] = A(k)-WB(k) 的性质可以优化这里*/// 旋转因子, 需要优化...tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));x_r[k+p+step] = tmp_real + ( tw1*temp -tw2*x_i[k+p+step] );x_i[k+p+step] = tmp_imag + ( tw2*temp +tw1*x_i[k+p+step] );printf("k=%d, x_r[k]=%f, x_i[k]=%f/n", k+p, x_r[k+p], x_i[k+p]);printf("k=%d, x_r[k]=%f, x_i[k]=%f/n", k+p+step,x_r[k+p+step], x_i[k+p+step]);}/* 开跳!:) */k += 2*step;}}}/** 后记:* 究竟是颗粒在外层循环还是样本输入在外层, 好象也差不多, 复杂度完全一样.* 但以我资质愚钝花费了不少时间才弄明白这数十行代码.* 从中我发现一个于我非常有帮助的教训, 很久以前我写过一部分算法, 其中绝大多数都是递归.* 将数据量减少, 减少再减少, 用归纳的方式来找出数据量加大代码的规律* 比如FFT* 1. 先写死LayerI的代码; 然后再把LayerI的输出作为LayerII的输入, 又写死代码; ......* 大约3层就可以统计出规律来. 这和递归也是一样, 先写死一两层, 自然就出来了! * 2. 有的功能可以写伪代码, 不急于求出结果, 降低复杂性, 把逻辑结果定出来后再添加. * 比如旋转因子就可以写死, 就写1.0. 流程出来后再写旋转因子.* 寥寥数语, 我可真是流了不少汗! Happy!*/void dft( void ){int i, n, k, tx1, tx2;float tw1,tw2;float xx_r[N],xx_i[N];/** clear any data in Real and Imaginary result arrays prior to DFT */for(k=0; k<=N-1; k++)xx_r[k] = xx_i[k] = x_i[k] = 0.0;// caculate the DFTfor(k=0; k<=(N-1); k++){for(n=0; n<=(N-1); n++){tx1 = (n*k);tx2 = tx1+(3*N)/4;tx1 = tx1%(N);tx2 = tx2%(N);if(tx1 >= (N/2))tw1 = -twiddle[tx1-(N/2)];elsetw1 = twiddle[tx1];if(tx2 >= (N/2))tw2 = -twiddle[tx2-(N/2)];elsetw2 = twiddle[tx2];xx_r[k] = xx_r[k]+x_r[n]*tw1;xx_i[k] = xx_i[k]+x_r[n]*tw2;}xx_i[k] = -xx_i[k];}// displayfor(i=0; i<N; i++)printf("%f/t%f/n", xx_r[i], xx_i[i]);}//---------------------------------------------------------------------------int main( void ){fft_init( );bitrev( );// bitrev2( );//fft1( );fft2( );display( );system( "pause" );// dft();return 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)

DSP实现FFT的代码

DSP实现FFT的代码

DSP实现FFT的代码FFT(快速傅里叶变换)是一种用于高效计算离散傅里叶变换(DFT)的算法。

在数字信号处理(DSP)中,FFT常被用来进行频域分析、滤波和信号压缩等操作。

下面是一个使用C语言实现FFT的代码示例:```c#include <stdio.h>#include <math.h>//基于蝴蝶算法的FFT实现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] = even[k] + t;x[k + N/2] = even[k] - t;}free(even);free(odd);//对输入信号进行FFT变换fft(x, N);//打印复数数组for (int i = 0; i < N; i++)printf("(%f,%f) ", creal(arr[i]), cimag(arr[i]));}printf("\n");int maiint N = 8; // 信号长度printf("原始信号为:\n");fft_transform(x, N);printf("FFT变换后的结果为:\n");return 0;```在这个代码示例中,我们首先定义了一个基于蝴蝶算法的FFT实现函数,然后使用该函数对输入信号进行傅里叶变换。

最后,我们通过打印的方式输出了原始信号和经过FFT变换后的结果。

需要注意的是,FFT是一个复杂的算法,需要理解较多的数学知识和算法原理。

在实际应用中,可以使用现成的DSP库或者软件工具来进行FFT计算,以提高效率和准确性。

(完整word版)fft算法代码注释及流程框图

(完整word版)fft算法代码注释及流程框图
add(x[j+k],product,&up);
sub(x[j+k],product,&down);
x[j+k]=up; //up为蝶形单元右上方的值
x[j+k+l]=down; //down为蝶形单元右下方的值
}
}
}
}
void initW() //计算W的实现函数
{
int i;
W=(complex *)malloc(sizeof(complex) * size_x); /*申请size_x个复数W的空间(这部申请的空间有点多,实际上只要申请size_x/2个即可)*/
{
l=1<<i;
for(j=0;j<size_x;j+=2*l)
//算出第m=i级的结果【i从0到(log(size_x)/log(2))-1】
{
for(k=0;k<l;k++) //算出第i级内j组蝶形单元的结果
{ //算出j组中第k个蝶形单元
mul(x[j+k+l],W[(size_x/2/l)*k],&product); /*size/2/l是该级W的相邻上标差,l是该级该组取的W总个数*/
fft(); //利用fft快速算法进行DFT变化
output(); //顺序输出size_x个fft的结果
return 0;
}
/*进行基-2 FFT运算,蝶形算法。这个算法的思路就是,
先把计算过程分为log(size_x)/log(2)-1级(用i控制级数);
然后把每一级蝶形单元分组(用j控制组的第一个元素起始下标);
scanf("%d",&size_x);

fft算法代码注释及流程框图

fft算法代码注释及流程框图

基2的DIT蝶形算法源代码及注释如下:/************FFT***********/ //整个程序输入和输出利用同一个空间x[N],节约空间#include <stdio.h>#include <math.h>#include <stdlib.h>#define N 1000 //定义输入或者输出空间的最大长度typedef struct{double real;double img;}complex; //定义复数型变量的结构体void fft(); //快速傅里叶变换函数声明void initW(); //计算W(0)~W(size_x-1)的值函数声明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; //pi的值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]:(such as:5 6)\n"); /*输入序列对应的值*/for(i=0;i<size_x;i++)scanf("%lf %lf",&x[i].real,&x[i].img);initW(); //计算W(0)~W(size_x-1)的值fft(); //利用fft快速算法进行DFT变化output(); //顺序输出size_x个fft的结果return 0;}/*进行基-2 FFT运算,蝶形算法。

FFT(DSP应用源代码)

FFT(DSP应用源代码)

/**************************************************************************** **文件名:AD02.c**功能:T1周期中断启动ADC,实现ADC模块16路通道的采样**说明:AD采样频率为10K,序列发生器SEQ1和SEQ2级联成一个16通道的序列发生器,* 采样模式采用顺序采样。

利用通用定时器T1的周期中断来触发AD转换。

**作者: likyo from hellodsp**版本: V1.0*****************************************************************************/#include "DSP28_Device.h"#include "math.h"#include "comm.h"#include "fft.h"unsigned int Sampling[1024];//float Sampling[1024];unsigned int ad_convcount = 0;unsigned int ad_convover = 0 ;/****************************************************************************** ***/#define FFTN512 512#define FFTN256 256#define FFTN128 128#pragma DATA_SECTION(ipcb, "FFTipcb");#pragma DATA_SECTION(mag , "FFTmag");long ipcb[FFTN512+2];long mag [FFTN512/2+2];RFFT32 fft512=RFFT32_512P_DEFAULTS;RFFT32 fft256=RFFT32_256P_DEFAULTS;RFFT32 fft128=RFFT32_128P_DEFAULTS;////////////////////float temp,mag_sqrt[128];double n;double p,q;//////////////////////unsigned int i,j;/****************************************************************************** ***//**************************************************************************** **名称:main()**功能:完成系统初始化工作,实现AD16通道的采样**入口参数:无**出口参数:无*****************************************************************************/void main(void){InitSysCtrl(); //初始化系统函数DINT;IER = 0x0000; //禁止CPU中断IFR = 0x0000; //清除CPU中断标志InitPieCtrl(); //初始化PIE控制寄存器InitPieVectTable(); //初始化PIE中断向量表InitPeripherals(); //初始化EV和AD模块PieCtrl.PIEIER1.bit.INTx6 =1; //使能PIE模块中的AD采样中断PieCtrl.PIEIER2.bit.INTx4=1; //使能PIE模块中的T1周期中断IER|=M_INT1; //开CPU中断IER|=M_INT2;EINT; //使能全局中断ERTM; //使能实时中断EvaRegs.T1CON.bit.TENABLE=1; //启动T1计数for(;;){if (ad_convover==1){/*AD采样结束fft转换开始*/fft256.ipcbptr=ipcb;fft256.magptr =mag ;fft256.init(&fft256);for(i=0;i<256;i++) {temp=((float)(Sampling[i]>>4))*3.0/4096.0;ipcb[i] =(long)(temp/3.0*2147483648);}RFFT32_brev(ipcb,ipcb,FFTN256);fft256.calc(&fft256);fft256.split(&fft256);fft256.mag(&fft256);}/*for(i=0;i<128;i++){mag_sqrt[i]=2*sqrt(mag[i]/1073741824.0);}*/ad_convover=0;}}//===================================================================== ======// No more.//===================================================================== ======。

C语言写的FFT代码

C语言写的FFT代码
x_r[k+p+step] = tmp_real + ( tw1*temp - tw2*x_i[k+p+step] );
x_i[k+p+step] = tmp_imag + ( tw2*temp + tw1*x_i[k+p+step] );*/
x_r[k+p+step] = tmp_real-( tw1*temp- tw2*x_i[k+p+step] );
x_i[k+p+step] = tmp_imag-( tw2*temp+ tw1*x_i[k+p+step] );
printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p, x_r[k+p], x_i[k+p]);
printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p+step, x_r[k+p+step], x_i[k+p+step]);
*这个算法有改进的空间
*/
static voidbitrev(void)
{
intp=1, q, i;
intbit_rev[ N ];
floatxx_r[ N ];
bit_rev[ 0 ] = 0;
while( p < N )
{
for(q=0; q<p; q++)
{
bit_rev[ q ] = bit_rev[ q ] * 2;
fft( );//进行FFT计算

fft python 代码

fft python 代码

fft python 代码FFT(快速傅里叶变换)是一种数学运算,用于将信号从时域转换为频域。

在信号处理和数字信号处理中,FFT是一种常见的技术,它可以用于音频和图像处理,以及一些其他的应用。

Python中有许多FFT的实现,其中最流行的是NumPy库中的实现。

以下是一个简单的示例代码,演示了如何在Python中使用NumPy 进行FFT。

```import numpy as np# Create a sample signalsignal = np.array([0, 1, 0, -1, 0, 1, 0, -1])# Perform the FFTfft = np.fft.fft(signal)# Print the resultsprint('Signal: ', signal)print('FFT: ', fft)```在上面的代码中,我们首先创建了一个示例信号。

然后使用NumPy 的fft函数将信号转换为频域。

最后,我们将结果打印出来以进行观察。

输出应该如下所示:```Signal: [ 0 1 0 -1 0 1 0 -1]FFT: [ 0.+0.j 0.-4.j 8.+0.j 0.+0.j 0.+0.j 0.+0.j 8.+0.j 0.+4.j]```上述结果显示了FFT变换后的结果,其中第一个元素为0(即直流分量)。

其余的值代表了频率分量。

实部和虚部分别表示相位和振幅。

可以通过将实部和虚部平方,然后相加并取平方根来计算每个频率分量的幅度。

这是一个简单的例子,但FFT还有很多其他用途,例如音频和图像处理、信号处理等。

Python中的NumPy库使FFT的实现变得容易,可以让开发人员在应用程序中方便地使用FFT。

快速傅里叶变换(FFT)原理及源程序

快速傅里叶变换(FFT)原理及源程序

《测试信号分析及处理》课程作业快速傅里叶变换一、程序设计思路快速傅里叶变换的目的是减少运算量,其用到的方法是分级进行运算。

全部计算分解为M 级,其中N M 2log =;在输入序列()i x 中是按码位倒序排列的,输出序列()k X 是按顺序排列;每级包含2N 个蝶形单元,第i 级有i N 2个群,每个群有12-i 个蝶形单元; 每个蝶形单元都包含乘r N W 和r N W -系数的运算,每个蝶形单元数据的间隔为12-i ,i 为第i 级; 同一级中各个群的系数W 分布规律完全相同。

将输入序列()i x 按码位倒序排列时,用到的是倒序算法——雷德算法。

自然序排列的二进制数,其下面一个数总比上面的数大1,而倒序二进制数的下面一个数是上面一个数在最高位加1并由高位向低位仅为而得到的。

若已知某数的倒序数是J ,求下一个倒序数,应先判断J 的最高位是否为0,与2N k =进行比较即可得到结果。

如果J k >,说明最高位为0,应把其变成1,即2N J +,这样就得到倒序数了。

如果J k ≤,即J 的最高位为1,将最高位化为0,即2N J -,再判断次高位;与4N k =进行比较,若为0,将其变位1,即4N J +,即得到倒序数,如果次高位为1,将其化为0,再判断下一位……即从高位到低位依次判断其是否为1,为1将其变位0,若这一位为0,将其变位1,即可得到倒序数。

若倒序数小于顺序数,进行换位,否则不变,防治重复交换,变回原数。

注:因为0的倒序数为0,所以可从1开始进行求解。

二、程序设计框图(1)倒序算法——雷德算法流程图(2)FFT算法流程三、FFT源程序void fft(x,n)int n;double x[];{int i,j,k,l,m,n1,n2;double c,c1,e,s,s1,t,tr;for(j=1,i=1;i<n/2;i++){ m=i;j=2*j;if(j==n)break;} //得到流程图的共几级n1=n-1;for(j=0,i=0;i<n1;i++){if(i<j) //如果i<j,即进行变址{tr=x[j];x[j]=x[i];x[i]=tr;k=n/2; //求j的下一个倒位序while(k<(j+1)) //如果k<(j+1),表示j的最高位为1{j=j-k; //把最高位变成0 k=k/2; //k/2,比较次高位,依次类推,逐个比较,直到某个位为0}j=j+k; //把0改为1 }for(i=0;i<n;i+=2){tr=x[i];x[i]=tr+x[i+1];x[i+1]=tr-x[i+1];}n2=1;for(l=1;l<=m;l++) // 控制蝶形结级数{n4=n2;n2=2*n4;n1=2*n2;e=6.28318530718/n1;for(i=0;i<n;i+=n1) //控制同一蝶形结运算,即计算系数相同蝶形结{tr=x[i];x[i]=tr+x[i+n2];x[i+n2]=tr-x[i+n2];x[i+n2+n4]=-x[i+n2+n4];a=e;for(j=2;j<=(n4-1);j++) //控制计算不同种蝶形结,即计算系数不同的蝶形结{i1=i+j;i2=i-j+n2;i3=i+j+n2;i4=i-j+n1;cc=cos(a);ss=sin(a);a=a+e;t1=cc*x[i3]+ss*x[i4];t2=ss*x[i3]-cc*x[i4];x[i4]=x[i2]-t2;x[i3]=-x[i2]-t2;x[i2]=x[i1]-t1;x[i1]=x[i1]+t1;}}}四、计算实例及运行结果设输入序列)(i x 为)1,...,2,1,0(,200sin )(-=∆=n i t i i x π其离散傅里叶变换为)1,...,2,1,0(,)()(10-==∑-=n k W i x k X N i ik N 这里n j e W π2-=。

快速傅里叶变换(FFT)算法原理及代码解析

快速傅里叶变换(FFT)算法原理及代码解析

快速傅里叶变换(FFT)算法原理及代码解析•FFT与DFT关系:快速傅里叶变换(Fast Fourier Transform)是离散傅里叶(DFT)变换的一种快速算法,简称FFT,通过FFT可以将一个信号从时域变换到频域;FFT(快速傅里叶变换)其本质就是DFT,只不过可以快速的计算出DFT结果,它只是傅立叶变换算法实现过程的一种改进。

要弄懂FFT,必须先弄懂DFT,DFT(DiscreteFourier Transform) 离散傅里叶变换的缩写,咱们先来简单讨论一下DFT。

DFT(FFT)的作用:可以将信号从时域变换到频域,而且时域和频域都是离散的,通俗的说,可以求出一个信号由哪些正弦波叠加而成,求出的结果就是这些正弦波的幅度和相位。

•DFT的公式:其中X(k)表示DFT变换后的数据,x(n)为采样的模拟信号,公式中的x(n)可以为复信号,实际当中x(n)都是实信号,即虚部为0,此时公式可以展开为:那么,对于一个的序列进行不断分解,就可以得出如下所谓的蝶形图:•FFT处理蝶形运算蝶形运算的规律:同一级中所有蝶形的输入点在同一竖直线上,意味着我们可以按级来运算,对于M级的蝶形,编个M次循环就好了;所有数据点在运算后不会窜位,即计算后可以将结果存入原来的地址空间。

每级N/2个蝶都需要用到系数WN,这里称它为旋转因子。

我们来观察旋转因子WN的规律。

以8点的蝶形图为例:可见,第L级的旋转因子为:可以看到,每个蝶的两个输入点下标跨度是不一样的。

比如第一级中是相邻两个数据作蝶运算,第二级中是两个输入点隔开一个点,而第三级隔开三个点。

不难找到规律:第L级中,第二个输入点的坐标是第一个点的坐标+space,space=Math.Pow(2, L)=num。

FFT的算法是写一个三重循环:•第一重循环对每一级运算(每级含num=Math.Pow(2, L)个蝶形);•第二重对每一个旋转因子对应的蝶运算,那么有几个蝶呢?很简单,每级都应该有N/2个蝶,而每个因子对应N/2 / num个蝶;•第三重循环对每个蝶进行计算,需要注意的一是循环下标起始点的位置,二是每次计算需要申明临时变量来保存输入数据点。

全相位fft代码

全相位fft代码

全相位FFT(All-Phase FFT)是一种在频域分析中同时保留幅度信息和相位信息的算法。

以下是一个使用Python 和NumPy 库实现全相位FFT 的示例代码:```pythonimport numpy as np# 创建一个包含频率信息的二维数组freq_data = np.array([[np.sin(2 * np.pi * 50 * t) for t in np.linspace(0, 1, 1000)] for _ in range(1000)])# 计算全相位FFTfft_data = np.fft.fft(freq_data)# 提取幅度和相位信息amplitude = np.abs(fft_data)phase = np.angle(fft_data)# 绘制幅度谱和相位谱plt.figure()plt.subplot(2, 1, 1)plt.plot(np.linspace(0, 1, 1000), amplitude)plt.title("Amplitude Spectrum")plt.xlabel("Frequency (Hz)")plt.ylabel("Amplitude")plt.subplot(2, 1, 2)plt.plot(np.linspace(0, 1, 1000), phase)plt.title("Phase Spectrum")plt.xlabel("Frequency (Hz)")plt.ylabel("Phase (rad)")plt.tight_layout()plt.show()```这个代码首先生成一个包含频率信息的二维数组,然后对其进行全相位FFT 计算。

接下来,从FFT 结果中提取幅度和相位信息,并绘制幅度谱和相位谱。

fft python 代码

fft python 代码

fft python 代码Python是一种高级编程语言,它具有简单易学、易于阅读和编写的特点。

Python中有许多强大的库和工具,其中之一就是FFT库。

FFT库是Python中用于快速傅里叶变换的库,它可以帮助我们快速地计算傅里叶变换,从而在信号处理、图像处理、音频处理等领域中发挥重要作用。

FFT库的使用非常简单,只需要导入库并调用相应的函数即可。

下面是一个简单的FFT Python代码示例:```pythonimport numpy as npfrom scipy.fft import fft# 生成一个信号t = np.linspace(0, 2*np.pi, 1000)signal = np.sin(5*t) + np.sin(10*t)# 计算信号的傅里叶变换fft_signal = fft(signal)# 绘制信号和傅里叶变换的图像import matplotlib.pyplot as pltfig, (ax0, ax1) = plt.subplots(2, 1)ax0.plot(t, signal)ax0.set_xlabel('Time (s)')ax0.set_ylabel('A mplitude')ax1.plot(np.abs(fft_signal))ax1.set_xlabel('Frequency (Hz)')ax1.set_ylabel('Magnitude')plt.show()```在这个示例中,我们首先生成了一个信号,然后使用FFT库中的fft函数计算了信号的傅里叶变换。

最后,我们使用matplotlib库绘制了信号和傅里叶变换的图像。

在实际应用中,FFT库可以用于许多领域,例如音频处理、图像处理、信号处理等。

例如,在音频处理中,我们可以使用FFT库来计算音频信号的频谱,从而实现音频的频谱分析、滤波等功能。

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

我自己的一些详细标注,有利于深入了解FFT,后面附加几位网友对FFT的理解及源代码,让广大朋友更迅速的掌握FFT#include "DSP281x_Device.h" // DSP281x Headerfile Include File,添加所有头文件#include "DSP281x_Examples.h" // DSP281x Examples Include File,条件编译而已#include "f2812a.h" //一些变量的宏定义而已#include"math.h"#define PI 3.1415926 //前变后常#define SAMPLENUMBER 128//#define SAMPLENUMBER 512void InitForFFT();void MakeWave();//void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER]);int INPUT[SAMPLENUMBER],DATA[SAMPLENUMBER];float fWaveR[SAMPLENUMBER],fWaveI[SAMPLENUMBER],w[SAMPLENUMBER];float sin_tab[SAMPLENUMBER],cos_tab[SAMPLENUMBER];//逐级计算FFT,一级一级递推void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER]){int x0,x1,x2,x3,x4,x5,x6,xx;int i,j,k,b,p,L;float TR,TI,temp;/********** following code invert sequence ************///倒序for ( i=0;i<SAMPLENUMBER;i++ )//就是码位倒置嘛,二进制各个位独立出来再反向{ //128七位二进制表示,/号代表右移嘛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;/* b的意义非常重大,b表示当前层不同旋转因子的个数*/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 */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);//输入波形进行FFT变换,此处引入起始实参即可递推下去for ( i=0;i<SAMPLENUMBER;i++ ){DATA[i]=w[i];//变换后的波形转换到输出接口}while ( 1 );// break point}//旋转因子事先初始化好,方便调用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++ )//1024是相应的幅值嘛,只要弄出个基波,以之为标准即可{INPUT[i]=sin(PI*2*i/SAMPLENUMBER)*1024+sin(PI*2*i/SAMPLENUMBER*3)*1024/3+sin(PI*2*i/SAMPLENUMBER*5)*1024/5+sin(PI*2*i/SAMPLENUMBER*7)*1024/7+sin(PI*2*i/SAMPLENUMBER*9)*1024/9;//INPUT[i]=sin(PI*2*i/SAMPLENUMBER*3)*1024;}}X[0] = x[0]*(1-0) + x[1]*(1-0) = x[0] + 1*x[1]; X[1] = x[0]*(1-0) + x[1]*(-1-0) = x[0] - 1*x[1];这就是单个2点蝶形算法.FFT实现流程图分析(N=8, 以8点信号为例)FFT implementation of an 8-point DFT as two 4-point DFTs and four 2-pointDFTs8点FFT流程图(Layer表示层, gr表示当前层的颗粒)下面以LayerI为例.LayerI部分, 具有4个颗粒, 每个颗粒2个输入(注意2个输入的来源, 由时域信号友情提供, 感谢感谢☺)我们将输入x[k]分为两部分x_r[k], x_i[k]. 具有实部和虚部, 时域信号本没有虚部的, 因此可以让x_i[k]为0. 那么为什么还要画蛇添足分为实部和虚部呢? 这是因为LayerII, LayerIII的输入是复数, 为了编码统一而强行分的.当然你编码时可以判断当前层是否为1来决定是否分. 但是我想每个人最后都会倾向分的.旋转因子 tw = cos(2*PI*k/N)-j*sin(2*PI*k/N); 也可以分为实部和虚部, 令其为tw_r, tw_i;则tw = tw_r - j*tw_i;X[k] = (x_r[k] + j*x_i[k]) + (tw_r–j*tw_i) * (x_r[k+N/2]+j*x_i[k+N/2])则X_R[k] = x_r[k] + tw_r*x_r[k+N/2] + tw_i*x_i[k+N/2];X_I[k] = x_i[k] - tw_i*x_r[k+N/2] + tw_r*x_i[k+N/2];LayerII部分, 具有2个颗粒, 每个颗粒4个输入(注意4个输入的来源, 由LayerI友情提供, 感谢感谢☺)LayerIII部分, 具有1个颗粒, 每个颗粒8个输入(注意8个输入的来源, 由LayerII友情提供, 感谢感谢☺)LayerI, LayerII, LayerIII从左往右, 蝶形信号运算流非常明显!假令输入为x[k], x[k+N/2], 输出为X[k], X[k+N/2]. x[k]分解为x_r[k], x_i[k]部分则该蝶形运算为X[k]= (x_r[k]-j*x_i[k]) +(x_r[k+N/2]-j*x_i[k+N/2])*(cos(2*PI*k/N)-j*sin(2*PI*k/N));再令cos(2*PI*k/N)为tw1, sin(2*PI*k/N)为tw2 则X[k] = (x_r[k]-j*x_i[k]) + (x_r[k+N/2]-j*x_i[k+N/2])*(tw1-j*tw2);X_R[k] = x_r[k] + x_r[k+N/2]*tw1 - x_i[k+N/2]*tw2;X_I[K] = x_i[k]x_r[k] = x_r[k] + x_r[k+b]*tw1 + x_i[k+b]*tw2;x_i[k] = x_i[k] - x_r[k+b]*tw2 + x_i[k+b]*tw1;譬如8点输入x[8]1. 先分割成2部分: x[0], x[2], x[4], x[6] 和 x[1], x[3], x[5], x[7]2. 信号x[0], x[2], x[4], x[6]再分割成x[0], x[4] 和 x[2], x[6]信号x[1], x[3], x[5], x[7]再分割成x[1], x[5] 和 x[3], x[7]3. 无法分割了, 已经分割成2点了☺.如上图:在LayerI的时候, 我们是对2点进行DFT.( 一共4次DFT )输入为 x[0]&x[4]; x[2]&x[6]; x[1]&x[5]; x[3]&x[7]输出为 y[0],y[1]; Y[2],y[3]; Y[4],y[5]; Y[6],y[7];流程:I. 希望将输入直接转换为x[0], x[4], x[2], x[6], x[1], x[5], x[3], x[7]的顺序II. 对转换顺序后的信号进行4次DFT步骤I代码实现/*** 反转算法.这个算法效率比较低!先用起来在说, 之后需要进行优化.*/static void bitrev( void ){int p=1, q, i;int bit_rev[ N ];float xx_r[ N ];bit_rev[ 0 ] = 0;while( p < N ){for(q=0; q<p; q++){bit_rev[ q ] = bit_rev[ q ] * 2;bit_rev[ q + p ] = bit_rev[ q ] + 1;}p *= 2;}for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ];}// ------------------------ 此刻序列x重排完毕------------------------步骤II代码实现int j;float TR; // 临时变量float tw1; // 旋转因子/* 两点DFT */for(k=0; k<N; k+=2){// 两点DFT简化告诉我们tw1=1TR = x_r[k]; // TR就是A, x_r[k+b]就是B.x_r[k] = TR + tw1*x_r[k+b];x_r[k+b] = TR - tw1*x_r[k+b];}在LayerII的时候, 我们希望得到z, 就需要对y进行DFT.y[0],y[2]; y[1],y[3]; y[4],y[6]; y[5],y[7];z[0], z[1]; z[2],z[3]; z[4],z[5]; z[6],z[7];在LayerIII的时候, 我们希望得到v, 就需要对z进行DFT.z[0],z[4]; z[1],z[5]; z[2],z[6]; z[3],z[7];v[0],v[1]; v[2],v[3]; v[4],v[5]; v[6],v[7];准备令输入为x[s], x[s+N/2], 输出为y[s], y[s+N/2]这个N绝对不是上面的8, 这个N是当前颗粒的输入样本总量对于LayerI而言N是2; 对于LayerII而言N是4; 对于LayerIII而言N是8复数乘法:(a+j*b) * (c+j*d)实部 = a*c – bd;虚部 = ad + bc;旋转因子:实现(C描述)#include <stdio.h>#include <math.h>#include <stdlib.h>//#include "complex.h"//--------------------------------------------------------------------------#define N 8 //64#define M 3 //6 //2^m=N#define PI 3.1415926//--------------------------------------------------------------------------float twiddle[N/2] = {1.0, 0.707, 0.0, -0.707};float x_r[N] = {1, 1, 1, 1, 0, 0, 0, 0};float x_i[N]; //N=8/*float twiddle[N/2] = {1, 0.9951, 0.9808, 0.9570, 0.9239, 0.8820, 0.8317, 0.7733,0.7075,0.6349, 0.5561, 0.4721, 0.3835, 0.2912, 0.1961, 0.0991 ,0.0000,-0.0991,-0.1961,-0.2912,-0.3835,-0.472 1,-0.5561,-0.6349,-0.7075,-0.7733,0.8317,-0.8820,-0.9239,-0.9570,-0.9808,-0.9951}; //N=64float x_r[N]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};float x_i[N];*/FILE *fp;// ----------------------------------- func-----------------------------------/*** 初始化输出虚部*/static void fft_init( void ){int i;for(i=0; i<N; i++) x_i[i] = 0.0;}/*** 反转算法.将时域信号重新排序.* 这个算法有改进的空间*/static void bitrev( void ){int p=1, q, i;int bit_rev[ N ]; //float xx_r[ N ]; //bit_rev[ 0 ] = 0;while( p < N ){for(q=0; q<p; q++){bit_rev[ q ] = bit_rev[ q ] * 2;bit_rev[ q + p ] = bit_rev[ q ] + 1;}p *= 2;}for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ]; }/* ------------ add by sshc625 ------------ */static void bitrev2( void ){return ;}/* */void display( void ){printf("/n/n");int i;for(i=0; i<N; i++)printf("%f/t%f/n", x_r[i], x_i[i]);}/****/void fft1( void ){ fp = fopen("log1.txt", "a+");int L, i, b, j, p, k, tx1, tx2;float TR, TI, temp; // 临时变量float tw1, tw2;/* 深M. 对层进行循环. L为当前层, 总层数为M. */for(L=1; L<=M; L++){fprintf(fp,"----------Layer=%d----------/n", L);/* b的意义非常重大,b表示当前层的颗粒具有的输入样本点数 */b = 1;i = L - 1;while(i > 0){b *= 2;i--;}// -------------- 是否外层对颗粒循环, 内层对样本点循环逻辑性更强一些呢! --------------/** outter对参与DFT的样本点进行循环* L=1, 循环了1次(4个颗粒, 每个颗粒2个样本点)* L=2, 循环了2次(2个颗粒, 每个颗粒4个样本点)* L=3, 循环了4次(1个颗粒, 每个颗粒8个样本点)*/for(j=0; j<b; j++){/* 求旋转因子tw1 */p = 1;i = M - L; // M是为总层数, L为当前层.while(i > 0){p = p*2;i--;}p = p * j;tx1 = p % N;tx2 = tx1 + 3*N/4;tx2 = tx2 % N;// tw1是cos部分, 实部; tw2是sin部分, 虚数部分.tw1 = ( tx1>=N/2)? -twiddle[tx1-N/2] : twiddle[ tx1 ]; tw2 = ( tx2>=N/2)? -twiddle[tx2-(N/2)] : twiddle[tx2];/** inner对颗粒进行循环* L=1, 循环了4次(4个颗粒, 每个颗粒2个输入)* L=2, 循环了2次(2个颗粒, 每个颗粒4个输入)* L=3, 循环了1次(1个颗粒, 每个颗粒8个输入)*/for(k=j; k<N; k=k+2*b){TR = x_r[k]; // TR就是A, x_r[k+b]就是B.TI = x_i[k];temp = x_r[k+b];/** 如果复习一下 (a+j*b)(c+j*d)两个复数相乘后的实部虚部分别是什么* 就能理解为什么会如下运算了, 只有在L=1时候输入才是实数, 之后层的* 输入都是复数, 为了让所有的层的输入都是复数, 我们只好让L=1时候的* 输入虚部为0* x_i[k+b]*tw2是两个虚数相乘*/fprintf(fp, "tw1=%f, tw2=%f/n", tw1, tw2);x_r[k] = TR + x_r[k+b]*tw1 + x_i[k+b]*tw2;x_i[k] = TI - x_r[k+b]*tw2 + x_i[k+b]*tw1;x_r[k+b] = TR - x_r[k+b]*tw1 - x_i[k+b]*tw2;x_i[k+b] = TI + temp*tw2 - x_i[k+b]*tw1;fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f/n", k, x_r[k],x_i[k]);fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f/n", k+b, x_r[k+b], x_i[k+b]);} //} //} //}/*** ------------ add by sshc625 ------------* 该实现的流程为* for( Layer )* for( Granule )* for( Sample )*****/void fft2( void ){ fp = fopen("log2.txt", "a+");int cur_layer, gr_num, i, k, p;float tmp_real, tmp_imag, temp; // 临时变量, 记录实部float tw1, tw2;// 旋转因子,tw1为旋转因子的实部cos部分, tw2为旋转因子的虚部sin部分.int step; // 步进int sample_num; // 颗粒的样本总数(各层不同, 因为各层颗粒的输入不同)/* 对层循环 */for(cur_layer=1; cur_layer<=M; cur_layer++){/* 求当前层拥有多少个颗粒(gr_num) */gr_num = 1;i = M - cur_layer;while(i > 0){i--;gr_num *= 2;}/* 每个颗粒的输入样本数N' */sample_num = (int)pow(2, cur_layer);/* 步进. 步进是N'/2 */step = sample_num/2;/* */k = 0;/* 对颗粒进行循环 */for(i=0; i<gr_num; i++){/** 对样本点进行循环, 注意上限和步进*/for(p=0; p<sample_num/2; p++){// 旋转因子, 需要优化...tw1 = cos(2*PI*p/pow(2, cur_layer)); tw2 = -sin(2*PI*p/pow(2, cur_layer));tmp_real = x_r[k+p];tmp_imag = x_i[k+p];temp = x_r[k+p+step];/*(tw1+jtw2)(x_r[k]+jx_i[k])** real : tw1*x_r[k] - tw2*x_i[k]* imag : tw1*x_i[k] + tw2*x_r[k]* 我想不抽象出一个* typedef struct {* double real; // 实部* double imag; // 虚部* } complex; 以及针对complex的操作* 来简化复数运算是否是因为效率上的考虑!*//* 蝶形算法 */x_r[k+p] = tmp_real + ( tw1*x_r[k+p+step] -tw2*x_i[k+p+step] );x_i[k+p] = tmp_imag + ( tw2*x_r[k+p+step] +tw1*x_i[k+p+step] );/* X[k] = A(k)+WB(k)* X[k+N/2] = A(k)-WB(k) 的性质可以优化这里*/// 旋转因子, 需要优化...tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));x_r[k+p+step] = tmp_real + ( tw1*temp -tw2*x_i[k+p+step] );x_i[k+p+step] = tmp_imag + ( tw2*temp +tw1*x_i[k+p+step] );printf("k=%d, x_r[k]=%f, x_i[k]=%f/n", k+p, x_r[k+p], x_i[k+p]);printf("k=%d, x_r[k]=%f, x_i[k]=%f/n", k+p+step,x_r[k+p+step], x_i[k+p+step]);}/* 开跳!:) */k += 2*step;}}}/** 后记:* 究竟是颗粒在外层循环还是样本输入在外层, 好象也差不多, 复杂度完全一样.* 但以我资质愚钝花费了不少时间才弄明白这数十行代码.* 从中我发现一个于我非常有帮助的教训, 很久以前我写过一部分算法, 其中绝大多数都是递归.* 将数据量减少, 减少再减少, 用归纳的方式来找出数据量加大代码的规律* 比如FFT* 1. 先写死LayerI的代码; 然后再把LayerI的输出作为LayerII的输入, 又写死代码; ......* 大约3层就可以统计出规律来. 这和递归也是一样, 先写死一两层, 自然就出来了! * 2. 有的功能可以写伪代码, 不急于求出结果, 降低复杂性, 把逻辑结果定出来后再添加. * 比如旋转因子就可以写死, 就写1.0. 流程出来后再写旋转因子.* 寥寥数语, 我可真是流了不少汗! Happy!*/void dft( void ){int i, n, k, tx1, tx2;float tw1,tw2;float xx_r[N],xx_i[N];/** clear any data in Real and Imaginary result arrays prior to DFT */for(k=0; k<=N-1; k++)xx_r[k] = xx_i[k] = x_i[k] = 0.0;// caculate the DFTfor(k=0; k<=(N-1); k++){for(n=0; n<=(N-1); n++){tx1 = (n*k);tx2 = tx1+(3*N)/4;tx1 = tx1%(N);tx2 = tx2%(N);if(tx1 >= (N/2))tw1 = -twiddle[tx1-(N/2)];elsetw1 = twiddle[tx1];if(tx2 >= (N/2))tw2 = -twiddle[tx2-(N/2)];elsetw2 = twiddle[tx2];xx_r[k] = xx_r[k]+x_r[n]*tw1;xx_i[k] = xx_i[k]+x_r[n]*tw2;}xx_i[k] = -xx_i[k];}// displayfor(i=0; i<N; i++)printf("%f/t%f/n", xx_r[i], xx_i[i]);}//---------------------------------------------------------------------------int main( void ){fft_init( );bitrev( );// bitrev2( );//fft1( );fft2( );display( );system( "pause" );// dft();return 1;}#include <iom128.h>#include <intrinsics.h>/*********************************************************************快速福利叶变换C函数函数简介:此函数是通用的快速傅里叶变换C语言函数,移植性强,以下部分不依赖硬件。

相关文档
最新文档