• 一维快速傅里叶变换代码


    上一篇随笔,简要写了一下FFT中数组重新排序的算法。现在把完整的FFT代码分享给大家(有比较详细的注释)。

    /*2015年11月10日于河北工业大学*/

    #include <complex>
    #include <iostream.h>
    #include <math.h>
    #include <stdlib.h>
    const int N=8;      //数组的长度
    const double PI=3.141592653589793; //圆周率
    const double ZERO= 1.0E-14;   //当绝对值小于这个数的时候认为是0
    typedef std::complex<double> complex;

    //函数原型声明

    void Reverse(complex src[],int n);

    void FFT(complex src[],int n);

    void Display(complex f[],int n);

    /* 主函数 */

    int main()
    {
     complex src[8];      //原始数组
     for(int i=0;i<8;i++)
     {
      src[i]=complex(   double(i),   0.0  );
     }
     cout<<"原始数组为:"<<endl;
     Display(src,N);

     //一维快速傅里叶变换
     FFT(src,N);

     cout<<"变换后的数组为:"<<endl;
     Display(src,N);
     
     
     return 0;

    /***********************************************
    *****  一维快速离散傅里叶变换 *************
    *****   输入:数组长度n      *************
    *****         虚部 imag      *************
    *****         实部real            *************
    ************************************************/
    void FFT(complex src[],int n)
    {

     //原始数组按位码倒序排列
     Reverse(src,n);

     cout<<"倒置后的数组为:"<<endl;

     Display(src,n);


     //计算M,M=log(2,n)表示共有M级蝶形运算
     for(int i=n,M=1;(i=i/2)!=1;M++);

     for(int L=1;L<=M;L++)
     {
     // int arrayNum=n/pow(2,L);  //被分成的小的数组的个数
     
      int elementNum=pow(2,L);  //每个小数组的元素的个数
      
      int uniteachArr=elementNum/2; //每个小数组中所包含的蝶形运算单元的个数
      
      int offset=pow(2,L-1);         //每个蝶形运算节点的距离

      //cout<<"偏移量为:"<<offset<<endl;

      for(int i=0;i<n;i=i+elementNum)
      {
       for(int j=i;j<=i+uniteachArr-1;j++)
       {
        double r=(j-i)*pow(2,M-L);  //W(r,N)中的r
        
       // complex W=complex(cos(2*PI*r/N),sin(2*PI*r/N));
        


        complex temp=src[j+offset]*complex(cos(2*PI*r/double(n)),-sin(2*PI*r/double(n)));
        src[j+offset]=src[j]-temp;
        src[j]=src[j]+temp;

       }
      }
      
     }
     
    }

    /***********************************************
    *****   函数功能:实现原始数组重新排序   *******
    *****             主要实现按位码倒序的排列 *****
    *****   函数输入:原数组     ****
    ************************************************/
    void Reverse(complex src[],int n)
    {
     /*
      p1和p2表示要进行交换的两个元素的索引
      其中p1从第二个元素到倒数第二个元素
      扫描,p2则是通过算法确定的与p1进行
      交换的另一个元素的索引

     */

     int p1; 
     int p2;
     int middle;  //表示中心点
     int offset;  //表示偏移量
     /*   中心点和偏移量是计算p2的重要参数  */
     
     p2=n/2;   //与p1=1时交换的元素的索引为N/2
     for(p1=1;p1<=n-2;/*第一个元素和最后一个元素不用交换*/p1++)
     {
      /*当p1<p2时交换,避免重复交换*/
      if(p1<p2)
      {
       /*交换*/
       complex temp=src[p1];
       src[p1]=src[p2];
       src[p2]=temp;

      }
      

      /*下面开始计算下一个p2*/


      middle=n/2;   //初始的中心点
      offset=p2;   //初试的偏移量
      
      //当中心点小于等于偏移量时要更新
      while(middle<=offset)
      {
       offset=offset-middle;
       middle=middle/2;
      }

      p2=middle+offset;//p2就等于新的中心点和偏移量的和
     
     }

    }

    /*显示数据*/
    void Display(complex f[],int n)
    {
     
     
     for(int i=0;i<n;i++)
     {
      cout.width(9);
      cout.setf(ios::fixed);
      cout.precision(4);
      cout<<f[i].real();
      cout.flags(ios::showpos);
      cout.width(9);
      cout.setf(ios::fixed);
      cout.precision(4);
      cout<<f[i].imag()<<'i'<<' ';
      cout.unsetf(ios::showpos);
      if((i+1)%3==0) cout<<endl;

     }
     cout<<endl;
    }

  • 相关阅读:
    IntelliJ IDEA AndroidStudio SVN无法使用
    三极管封装
    STC等单片机一开机就停电模式烧写程序办法
    CC2541设置中断输入模式
    C# WinForm 多线程 应用程序退出的方法 结束子线程
    CorelDrawX8安装时提示已安装另一个版本
    Win10下Prolific USB-to-Serial Comm Port驱动提示不能使用
    Keil5创建GPIO
    SQL行列转置
    Excel复制粘贴假死
  • 原文地址:https://www.cnblogs.com/qingergege/p/4954404.html
Copyright © 2020-2023  润新知