链接:http://blog.csdn.net/zwlforever/archive/2008/03/14/2183049.aspx
一篇不错的FFT 文章,收藏一下。
 DFT的的正变换和反变换分别为(1)和(2)式。假设有N个数据,则计算一个频率点需要N次复数乘法和N-1次复数加法,整个DFT需要N*N次复数乘法和N(N-1)次复数加法;由于一次的复数乘法需要进行4次的实数乘法和2次的复数加法,一次的复数加法需要两次的实数加法,因此整个DFT需要4*N*N次的实数乘法和2*N(N-1)+2*N*N≈4*N*N次的复数加法。当N比较大时,所需的计算工作量相当大,例如N=1024时大约需要400万次乘法运算,对于实时信号处理来说,将对计算设备提出非常苛刻的要求,于是就提出如何能够减少计算DFT的运算量的问题。

1965年,库力和图基在《计算数学》杂志上发表《机器计算傅立叶级数的一种算法》,此文是最早提出FFT算法的。此后关于DFT的快速算法称为人们研究的热点课题,也正是FFT算法的出现,才使得数字信号处理能够应用于实时场合并进一步推动数字信号处理的发展和应用。

大多数的FFT算法都是利用(3)式的周期性、共轭对称性、可压缩和扩展性的特点来压缩计算量。。

1)、根据DFT定义进行计算的代码

//Data为输入数据指针,Log2N=log2(length),flag=-1时为正变换,flag=1时为反变换,变换结果同样由指针Data指向的空间返回
void dft(complex<double>*Data,int Log2N,int flag)
{
        int i,j,length;
        complex<double> wn;
        length=1<<Log2N;
        complex<double>*temp=new complex<double>(length);
    for(i=0;i<length;i++)
   {
               temp[i]=0;
               for(j=0;j<length;j++)
       {
                    wn=complex<double>(cos(2.0*pi/length*i*j),sin(flag*2.0*pi/length*i*j));
                    temp[i]+=Data[j]*wn;    
                }           
       }
       if(flag==1)
           for(i=0;i<length;i++)
               Data[i]=temp[i]/length;
        delete[] temp;
}  

2)、基2时间抽选FFT

把时域的数字信号序列按照奇偶进行分组计算,可以进行如下的变换,从变换结果可以知道,一个长度为N的DFT可以变换成长度为N/2的两个子序列的组合。依次类推,可以直到转为N/2个2点的傅立叶变化的组合。不过这时的输入应该为以2为基的倒位序。

由于经过多次的奇偶抽选,输入数据要按照基2倒序的原则进行重排,输出数据为正常顺序,倒序算法另外叙述。下面首先用递归的形式进行算法的描述,由于递归方法没有充分利用DIT2算法的优点---原位计算,因此递归形式只是为了描述的清晰。

void dit2rec(complex<double>*InData,complex<double>*OutData,int length,int sign)
{
   complex<double>*EvenData=new complex<double>(length/2);
   complex<double>*OddData  =new complex<double>(length/2);
   complex<double>*EvenResult=new complex<double>(length/2);
   complex<double>*OddResult=new complex<double>(length/2);
   int i,j;
   if(length==1)
   {
      OutData[0]=InData[0]/N;
      return;
   }
  for(i=0;i<length/2;i++)
  {
    EvenData[i]=InData[2*i];
    OddData[i]=InData[2*i+1];
  }
  dit2rec(EvenData,EvenResult,length/2,sign);
  dit2rec(OddData,EvenResult,length/2,sign);
  for(i=0;i<length/2;i++)
  {
    OutData[i]=EvenData+OddData*complex<double>(cos(2*pi*i/length),sin(sign*2*pi*i/length));
    OutData[i+length/2]=EvenData- OddData*complex<double>(cos(2*pi*i/length),sin(sign*2*pi*i/length));
  }
  delete[] EvenData,OddData,EvenResult,OddResult;
  return;
}
 
非递归实现如下(现不考虑输入的倒序数问题):
void dit2(complex<double>*Data,int Log2N,int sign)
{
   int i,j,k,step,length;
   complex<double> wn,temp,deltawn;
   length=1<<Log2N;
   for(i=1;i<=Log2N;i++)
   {
      wn=1;step=1<<i;deltawn=complex<double>(cos(2*pi/step),sin(sign*2.0*pi/step));
      for(j=0;j<step/2;j++)
      {        
        for(i=0;i<length/step;i++)
        {
           temp=Data[i*step+step/2+j]*wn;
           Data[i*step+step/2+j]=Data[i*step+j]-temp;
           Data[i*step+j]=Data[i*step+j]+temp;
         }
        wn=wn*deltawn;
      }
    }
    if(sign==-1)
       for(i=0;i<length;i++)
            Data[i]/=length;
 }
当i=1时,也就是第一次循环并没有必要进行复数运算,因为j只能取1,wn为实数,这个时间可以节省。因此可以改进为:
void dit2(complex<double>*Data,int Log2N,int sign)
{
   int i,j,k,step,length;
   complex<double> wn,temp,deltawn;
  length=1<<Log2N;
   for(i=0;i<length;i+=2)
   {
      temp=Data[i];
      Data[i]=Data[i]+Data[i+1];
      Data[i+1]=temp-Data[i+1];
   }
   for(i=2;i<=Log2N;i++)
   {
      wn=1;step=1<<i;deltawn=complex<double>(cos(2.0*pi/step),sin(sign*2.0*pi/step));;
      for(j=0;j<step/2;j++)
      {        
        for(i=0;i<length/step;i++)
        {
           temp=Data[i*step+step/2+j]*wn;
           Data[i*step+step/2+j]=Data[i*step+j]-temp;
           Data[i*step+j]=Data[i*step+j]+temp;
         }
         wn=wn*deltawn;
      }
   }
   if(sign==1)
   for(i=0;i<length;i++)
     Data[i]/=length;
}

3)、基2频率抽选FFT
//DIF2的递归版本实现:
void dif2rec(complex<double>*InData,complex<double>*OutData,int length,int sign)
{
   complex<double>* LData=new complex<double>(length/2);
   complex<double>* LResult=new complex<double>(length/2);
   complex<double>* RData=new complex<double>(length/2);
   complex<double>* RResult=new complex<double>(length/2);
   complex<double> temp;
   int i;
if(length==1)
   {
       OutData[0]=InData[0];
       return;
}
for(i=0;i<length/2;i++)
{
   LData[i]=InData[i];
   RData[i]=InData[i+length/2];
}
for(i=0;i<length/2;i++)
{
   temp=LData[i];
   LData[i]=LData[i]+RData[i];
   RData[i]=(temp-RData[i])* complex<double>(cos(2*pi*i/length),sin(sign*2*pi*i/length))
}
dit2rec(LData,LResult,length/2,sign);
dit2rec(RData,RResult,length/2,sign);
   for(i=0;i<length/2;i++)
   {
      OutData[2*i]=LResult[i];
      OutData[2*i+1]=RResult[i];
}
return;
}
 
 
//非递归实现如下(现不考虑输入的倒序数问题):
void dif2(complex<double>*InData,int r,int sign)
{
int length=1<<r;
int i,j,k,step;
complex<double> temp,wn;
for(i=1;i<=r;i++)
{
   step=1<<(r-i+1);
   wn=1;
   for(j=0;j<step/2;j++)
   {
      for(k=0;k<step/2;k++)
      {
         temp=InData[k*step+j];
         InData[k*step+j]=InData[k*step+j]-InData[k*step+step/2+j];
         InData[k*step+step/2+j]=(temp-InData[k*step+step/2+j])*wn;
}
wn=wn*complex<double>(cos(2*pi/step*j),sin(sign*2*pi/step*j));
}
}
}
 

和DIT一样,最外层的最后一个循环可以另外独立出来,因为最后一个循环没有必要进行复数运算,这样可以减少复数运算的次数。

基四时间抽选快速傅立叶算法

几种快速傅里叶变换(FFT)的C++实现的更多相关文章

  1. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

  2. 快速傅里叶变换FFT& 数论变换NTT

    相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...

  3. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

  4. 快速傅里叶变换(FFT)

    扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...

  5. 快速傅里叶变换(FFT)_转载

    FFTFFT·Fast  Fourier  TransformationFast  Fourier  Transformation快速傅立叶变换 P3803 [模板]多项式乘法(FFT) 参考上文 首 ...

  6. 基于python的快速傅里叶变换FFT(二)

    基于python的快速傅里叶变换FFT(二)本文在上一篇博客的基础上进一步探究正弦函数及其FFT变换. 知识点  FFT变换,其实就是快速离散傅里叶变换,傅立叶变换是数字信号处理领域一种很重要的算法. ...

  7. 【学习笔记】快速傅里叶变换(FFT)

    [学习笔记]快速傅里叶变换 学习之前先看懂这个 浅谈范德蒙德(Vandermonde)方阵的逆矩阵的求法以及快速傅里叶变换(FFT)中IDFT的原理--gzy hhh开个玩笑. 讲一下\(FFT\) ...

  8. Algorithm: 多项式乘法 Polynomial Multiplication: 快速傅里叶变换 FFT / 快速数论变换 NTT

    Intro: 本篇博客将会从朴素乘法讲起,经过分治乘法,到达FFT和NTT 旨在能够让读者(也让自己)充分理解其思想 模板题入口:洛谷 P3803 [模板]多项式乘法(FFT) 朴素乘法 约定:两个多 ...

  9. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

随机推荐

  1. ThinkPHP - 关联模型 - 多对多

    表结构: 映射关系: UserRelationModel会取UserRelation为表名称.所以要自定义表名称: //定义主表名称protected $tableName = 'User'; < ...

  2. java中将list、map对象写入文件

    链接地址:http://blog.sina.com.cn/s/blog_4a4f9fb50101p6jv.html     推荐:凤爪女瓜子男怪象该谁反思伦敦房价为什么持续暴涨 × wvqusrtg个 ...

  3. PHP缓存主要技术

    1.普遍缓存技术: 数据缓存:这里所说的数据缓存是指数据库查询PHP缓存机制,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中 ...

  4. nginx access_log 完全关闭

    最近在配置本地nginx开发环境时,发现一个问题,当server段不指定access_log时,并且http段中也未指定任何 access_log参数时,它会默认写到logs/access.log这个 ...

  5. 制作Linux(Fedora、Ubuntu、CentOS)优盘启动

    随着嵌入式技术的快速发展,Linux快速发展过一段时间.虽然现在不是很热,但是linux在现实社会的使用还是很有用处.而光盘有有些落伍,不仅浪费而且不环保,所以质优价廉的优盘就脱颖而出.所以,用优盘制 ...

  6. kingso_module - Taocode

    kingso_module - Taocode 模块介绍 Merger 功能介绍 Merger的功能: 合并多台Searcher机器的部分查询结果,得到最终的完整查询结果 向Detail集群请求最终展 ...

  7. 模拟红外协议C程序——接收模块

    目的:方便程序的调试,提供效率,减少工作累,可以不在线调试编程时显示实时数据,特别产品不带显示的或者MCU是OPT的,有很大的帮助. 过程:将要看的数据发送出来,另一个板(一个带有显示的就OK了,显示 ...

  8. line-height具体解释

    章:浏览器与Hack].7.3.5 应用:单行文字在垂直方向居中在网页设计中,往往为了突出标题而加入背景图案.如图7-31所看到的. watermark/2/text/aHR0cDovL2Jsb2cu ...

  9. .NET截断字符串

    /// <summary> /// 截断字符串 /// </summary> /// <param name="s">要截断的字符串</p ...

  10. 数据库神器:Navicat Premium

    Navicat premium是一款数据库管理工具.将此工具连接数据库,你可以从中看到各种数据库的详细信息.包括报错,等等.当然,你也可以通过他,登陆数据库,进行各种操作.Navicat Premiu ...