下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、哈!经过连续几个晚上的奋战,终于弄懂了FFT推导过程及实现!Happy基2FFT总的思想是将输入信号对半分割,再对半分割,再再对半分割(以下省略10000个再再.)直至分割到2点.两点DFT简化假设输入为x0,x1;输出为X0,X1.伪代码如下:/#defineN2#definePI3.1415926/inti,jfor(i=0,Xi=0.0;i<N;i+)for(j=0;j<N;j+)Xi+=xj*(cos(2*PI*i*j/N)-sin(2*PI*i*j/N);注意到(我想Audio编解码很多时候都是对cos,sin进行优化!)j=0j=1cos1cos1i=0sin0sin0
2、tw1tw1cos1cos-1i=1Sin0sin0tw1tw-1X0=x0*(1-0)+x1*(1-0)=x0+1*x1;X1=x0*(1-0)+x1*(-1-0)=x0-1*x1;这就是单个2点蝶形算法.FFT实现流程图分析(N=8,以8点信号为例)FFTimplementationofan8-pointDFTastwo4-pointDFTsandfour2-pointDFTs*4)一x(0)*3)i-A8点FFT流程图(Layer表示层,gr表示当前层的颗粒)F面以Layer1为例.Layer1部分,具有4个颗粒,每个颗粒2个输入(注意2个输入的来源,由时域信号友情提供,感谢感谢)我们将
3、输入xk分为两部分x_rk,x_ik.具有实部和虚部,时域信号本没有虚部的,因此可以让x_ik为0.那么为什么还要画蛇添足分为实部和虚部呢?这是因为Layerll,Layerlll的输入是复数,为了编码统一而强行分的.当然你编码时可以判断当前层是否为1来决定是否分.但是我想每个人最后都会倾向分的.旋转因子tw=cos(2*PI*k/N)-j*sin(2*PI*k/N);也可以分为实部和虚部,令其为tw_r,tw_i;贝ijtw=tw_r-j*tw_i;Xk=(x_rk+j*x_ik)+(tw_r*tw_i)*(x_rk+N/2+j*x_ik+N/2)则X_Rk=x_rk+tw_r*x_rk+N
4、/2+tw_i*x_ik+N/2;X_Ik=x_ik-tw_i*x_rk+N/2+tw_r*x_ik+N/2;Layerll部分,具有2个颗粒,每个颗粒4个输入(注意4个输入的来源,由Layerl友情提供,感谢感谢)Layerlll部分具有1个颗粒,每个颗粒8个输入(注意8个输入的来源,由Layerll友情提供,感谢感谢)Layerl,Layerll,Layerlll从左往右,蝶形信号运算流非常明显假令输入为xk,xk+N/2,输出为Xk,Xk+N.xk分解为x_rk,x_ik部分则该蝶形运算为Xk=(x_rk-j*x_ik)+(x_rk+N/2-j*x_ik+N/2)*(cos(2*PI*k
5、/N)-j*sin(2*PI*k/N);再令cos(2*PI*k/N)为tw1,sin(2*PI*k/N)为tw2则Xk=(x_rk-j*x_ik)+(x_rk+N/2-j*x_ik+N/2)*(tw1-j*tw2);X_Rk=x_rk+x_rk+N/2*tw1-x_ik+N/2*tw2;X_IK=x_ikx_rk=x_rk+x_rk+b*tw1+x_ik+b*tw2;x_ik=x_ik-x_rk+b*tw2+x_ik+b*tw1;譬如8点输入x81 .先分割成2部分:x0,x2,x4,x62 .信号x0,x2,x4,x6再分割成信号x1,x3,x5,x7再分割成3 .无法分割了,已经分割成2
6、点了.和x1,x3,x5,x7x0,x4和x2,x6x1,x5和x3,x7如上图:在LayerI输入为输出为的时候,我们是对2点进行DFT.(一共4次x0&x4;x2&x6;x1&x5;y0,y1;Y2,y3;Y4,y5;Y6,y7;DFT)x3&x7流程:I.希望将输入直接转换为x0,x4,x2,x6,x1,x5,x3,x7的顺序II.对转换顺序后的信号进行4次DFT步骤I代码实现/*反转算法.这个算法效率比较低!先用起来在说,之后需要进行优化.*/staticvoidbitrev(void)intintfloatp=1,q,i;bit_revN;xx_rN;
7、bit_rev0=0;while(p<N)(for(q=0;q<p;q+)(bit_revq=bit_revq*2;bit_revq+p=bit_revq+1;)p*=2;)for(i=0;i<N;i+)xx_ri=x_ri;for(i=0;i<N;i+)x_ri=xx_rbit_revi;)/此刻序列x重排完毕步骤II代码实现intj;floatTR;临时变量floattw1;/旋转因子/*两点DFT*/for(k=0;k<N;k+=2)(/两点DFT简化告诉我们tw1=1TR=x_rk;/TR就是A,x_rk+b就是B.x_rk=TR+tw1*x_rk+b;x
8、_rk+b=TR-tw1*x_rk+b;)在LayerII的时候,我们希望得到z就需要对y进行DFT.y0,y2;y1,y3;y4,y6;y5,y7;z0,z1;z2,z3;z4,z5;z6,z7;在LayerIII的时候,我们希望得到v,就需要对z进彳DDFT.z0,z4;z1,z5;z2,z6;z3,z7;v0,v1;v2,v3;v4,v5;v6,v7;准备令输入为xs,xs+N/2,输出为ys,ys+N/2这个N绝对不是上面的8,这个N是当前颗粒的输入样本总量对于Layerl而言N是2;对于Layerll而言N是4;对于Layerlll而言N是8复数乘法:(a+j*b)*(c+j*d)实
9、部=a*c-bd;虚部=ad+bc;旋转因子:实现(C描述)#include<stdio.h>#include<math.h>#include<stdlib.h>/#include"complex.h"/#defineN8/64#defineM3/6/2Am=N#definePl3.1415926/floattwiddleN/2=1.0,0.707,0.0,-0.707;floatx_rN=1,1,1,1,0,0,0,0;floatx_iN;/N=8/*floattwiddleN/2=1,0.9951,0.9808,0.9570,0.92
10、39,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.4721,-0.5561,-0.6349,-0.7075,-0.7733,0.8317,-0.8820,-0.9239,-0.9570,-0.9808,-0.9951;/N=64floatx_rN=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
11、,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,;floatx_iN;*/FILE*fp;/func/* 初始化输出虚部* /staticvoidfft_init(void)inti;for(i=0;i<N;i+)x_ii=0.0;/* 反转算法.将时域信号重新排序.* 这个算法有改进的空间* /staticvoidbitrev(void)intp=1,q,i;intbit_revN;/floatxx_rN;/bit_rev0=0;while(p<N)for(q=0;q<p;q+)bit_revq=bit_revq*2;bit
12、_revq+p=bit_revq+1;p*=2;for(i=0;i<N;i+)xx_ri=x_ri;for(i=0;i<N;i+)x_ri=xx_rbit_revi;*/*addbysshc625staticvoidbitrev2(void)(return;)/*/voiddisplay(void)(printf("nn");inti;for(i=0;i<N;i+)printf("%ft%fn",x_ri,x_ii);)/*/voidfft1(void)fp=fopen("log1.txt","a+&quo
13、t;);intL,i,b,j,p,k,tx1,tx2;floatTR,TI,temp;临时变量floattw1,tw2;/*深M.对层进彳f循环.L为当前层,总层数为M.*/for(L=1;L<=M;L+)fprintf(fp,"Layer=%dn",L);*/*b的意义非常重大,b表示当前层的颗粒具有的输入样本点数b=1;1 =L-1;while(i>0)b*=2;i-;)/是否外层对颗粒循环,内层对样本点循环逻辑性更强一些呢/* outter对参与DFT的样本点进行循环* L=1,循环了1次(4个颗粒,每个颗粒2个样本点)* L=2,循环了2次(2个颗粒,每
14、个颗粒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)?-twiddletx1-N/2:twiddletx1;tw2=(tx2>=N/2)?-twiddletx2-(N/2):twiddletx2;/* inner对颗粒进行循环* L=1,循环了4次
15、(4个颗粒,每个颗粒2个输入)* L=2,循环了2次(2个颗粒,每个颗粒4个输入)* L=3,循环了1次(1个颗粒,每个颗粒外输入)*/for(k=j;k<N;k=k+2*b)(TR=x_rk;/TR就是A,x_rk+b就是B.TI=x_ik;temp=x_rk+b;/* 如果复习一下(a+j*b)(c+j*d)两个复数相乘后的实部虚部分别是什么* 就能理解为什么会如下运算了,只有在L=1时候输入才是实数,之后层的* 输入都是复数,为了让所有的层的输入都是复数,我们只好让L=1时候的* 输入虚部为0* x_ik+b*tw2是两个虚数相乘*/fprintf(fp,"tw1=%f,
16、tw2=%fn",tw1,tw2);x_rk=TR+x_rk+b*tw1+x_ik+b*tw2;x_ik=TI-x_rk+b*tw2+x_ik+b*tw1;x_rk+b=TR-x_rk+b*tw1-x_ik+b*tw2;x_ik+b=TI+temp*tw2-x_ik+b*tw1;fprintf(fp,"k=%d,x_rk=%f,x_ik=%fn",k,x_rk,x_ik);fprintf(fp,"k=%d,x_rk=%f,x_ik=%fn",k+b,x_rk+b,x_ik+b);)/)/)/*)/addbysshc625* 该实现的流程为* f
17、or(Layer)* for(Granule)* for(Sample)*/voidfft2(void)fp=fopen("log2.txt","a+");intcur_layer,gr_num,i,k,p;floattmp_real,tmp_imag,temp;临时变量,记录实部floattw1,tw2;/旋转因子,tw1为旋转因子的实部cos部分,tw2为旋转因子的虚部sin部分.intstep;/步进intsample_num;/颗粒的样本总数(各层不同,因为各层颗粒的输入不同)/*对层循环*/for(cur_layer=1;cur_layer&l
18、t;=M;cur_layer+)/*求当前层拥有多少个颗粒(gr_num)*/gr_num=1;1 =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;/*对颗粒进彳f循环*/for(i=0;i<gr_num;i+)(/*对样本点进行循环,注意上限和步进*/for(p=0;p<sample_num/2;p+)(/旋转因子,需要优化tw1=cos(2*PI*p/pow
19、(2,cur_layer);tw2=-sin(2*PI*p/pow(2,cur_layer);tmp_real=x_rk+p;tmp_imag=x_ik+p;temp=x_rk+p+step;/*(tw1+jtw2)(x_rk+jx_ik)* real:tw1*x_rk-tw2*x_ik* imag:tw1*x_ik+tw2*x_rk* 我想不抽象出一个* typedefstruct* doublereal;/实部* doubleimag;/虚部* complex;以及针对complex的操作* 来简化复数运算是否是因为效率上的考虑!* /*蝶形算法*/x_rk+p=tmp_real+(tw1
20、*x_rk+p+step-tw2*x_ik+p+step);x_ik+p=tmp_imag+(tw2*x_rk+p+step+tw1*x_ik+p+step);/*Xk=A(k)+WB(k)*Xk+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_rk+p+step=tmp_real+(tw1*temp-tw2*x_ik+p+step);x_ik+p+step=tmp_imag+(tw2*temp+tw1*x_ik+
21、p+step);printf("k=%d,x_rk=%f,x_ik=%fn",k+p,x_rk+p,x_ik+p);printf("k=%d,x_rk=%f,x_ik=%fn",k+p+step,x_rk+p+step,x_ik+p+step);)/*开跳!:)*/k+=2*step;)/* 后记:* 究竟是颗粒在外层循环还是样本输入在外层,好象也差不多,复杂度完全一样.* 但以我资质愚钝花费了不少时间才弄明白这数十行代码* 从中我发现一个于我非常有帮助的教训,很久以前我写过一部分算法,其中绝大多数都是递归* 将数据量减少,减少再减少,用归纳的方式来找出数据量加大代码的规律* 比如FFT* 1.先写死Layerl的代码;然后再把Layerl的输出作为Layerll的输入,又写死代码;* 大约3层就可以统计出规律来.这和递归也是一样,先写死一两层,自然就出来了!* 2.有
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
 - 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
 - 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
 - 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
 - 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
 - 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
 - 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
 
最新文档
- 2025年内审员课程考试题及答案
 - 2025年认识算盘教学题库及答案
 - 2025年宠物殡葬师考试题及答案
 - 2025年安全监测车租赁合同协议(2025年)
 - 2025年河北八大员考试考试试题及答案
 - 2025-2030量子点标记显微镜技术商业化进程与投资回报分析
 - 2025-2030远程医疗系统性能评估与市场扩张策略研究
 - 2025-2030辣椒行业ESG评价体系构建与可持续发展路径研究
 - 2025年教师招聘美术试卷及答案
 - 2025年技校升专考试试题及答案
 - 苏教版小学英语单词汇总译林版级完整版
 - 交管12123学法减分试题题库及参考答案
 - Q-CR 783.1-2021 铁路通信网络安全技术要求 第1部分:总体技术要求
 - YY/T 0308-2015医用透明质酸钠凝胶
 - 华北理工大学材料力学刘文增第五版第5章 弯曲应力
 - 急性药物中毒的急救与护理课件
 - 幼儿园绘本+《不要随便亲我》
 - 1到100的英文单词
 - GB∕T 19078-2016 铸造镁合金锭
 - 工作计划与时间管理培训课件
 - 七年级上学期期中考试数学试题
 
            
评论
0/150
提交评论