一维快速傅里叶变换代码

时间:2022-06-15 02:32:46

上一篇随笔,简要写了一下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'<<'\t';
  cout.unsetf(ios::showpos);
  if((i+1)%3==0) cout<<endl;

 }
 cout<<endl;
}