[经验分享] FFT算法

[复制链接]
1443|0
 楼主| sdlls 发表于 2024-4-14 23:23 | 显示全部楼层 |阅读模式


  1. #include <math.h>
  2. #include "fft_fp.h"

  3. //#define FFT_N 64                                                   //定义福利叶变换的点数
  4. //#define PI 3.1415926535897932384626433832795028841971               //定义圆周率值
  5. //
  6. //struct compx {float real,imag;};                                    //定义一个复数结构
  7. struct compx s[FFT_N];                                              //FFT输入和输出:从S[0]开始存放,根据大小自己定义
  8. float SIN_TAB[FFT_N/4+1];                                             //定义正弦表的存放空间

  9. /*******************************************************************
  10. 函数原型:struct compx EE(struct compx b1,struct compx b2)  
  11. 函数功能:对两个复数进行乘法运算
  12. 输入参数:两个以联合体定义的复数a,b
  13. 输出参数:a和b的乘积,以联合体的形式输出
  14. *******************************************************************/
  15. struct compx EE(struct compx a,struct compx b)      
  16. {
  17. struct compx c;
  18. c.real=a.real*b.real-a.imag*b.imag;
  19. c.imag=a.real*b.imag+a.imag*b.real;
  20. return(c);
  21. }

  22. /******************************************************************
  23. 函数原型:void create_sin_tab(float *sin_t)
  24. 函数功能:创建一个正弦采样表,采样点数与福利叶变换点数相同
  25. 输入参数:*sin_t存放正弦表的数组指针
  26. 输出参数:无
  27. ******************************************************************/
  28. void create_sin_tab(float *sin_t)                     
  29. {
  30.   int i;
  31.   for(i=0;i<=FFT_N/4;i++)
  32.   sin_t[ i]=sin(2*PI*i/FFT_N);
  33. }
  34. /******************************************************************
  35. 函数原型:void sin_tab(float pi)
  36. 函数功能:采用查表的方法计算一个数的正弦值
  37. 输入参数:pi 所要计算正弦值弧度值,范围0--2*PI,不满足时需要转换
  38. 输出参数:输入值pi的正弦值
  39. ******************************************************************/
  40. float sin_tab(float pi)
  41. {
  42.   int n;
  43.   float a=0;
  44.    n=(int)(pi*FFT_N/2/PI);
  45.    
  46.   if(n>=0&&n<=FFT_N/4)
  47.     a=SIN_TAB[n];
  48.   else if(n>FFT_N/4&&n<FFT_N/2)
  49.     {
  50.      n-=FFT_N/4;
  51.      a=SIN_TAB[FFT_N/4-n];
  52.     }
  53.   else if(n>=FFT_N/2&&n<3*FFT_N/4)
  54.     {
  55.      n-=FFT_N/2;
  56.      a=-SIN_TAB[n];
  57.    }
  58.   else if(n>=3*FFT_N/4&&n<3*FFT_N)
  59.     {
  60.      n=FFT_N-n;
  61.      a=-SIN_TAB[n];
  62.    }
  63.   
  64.   return a;
  65. }
  66. /******************************************************************
  67. 函数原型:void cos_tab(float pi)
  68. 函数功能:采用查表的方法计算一个数的余弦值
  69. 输入参数:pi 所要计算余弦值弧度值,范围0--2*PI,不满足时需要转换
  70. 输出参数:输入值pi的余弦值
  71. ******************************************************************/
  72. float cos_tab(float pi)
  73. {
  74.    float a,pi2;
  75.    pi2=pi+PI/2;
  76.    if(pi2>2*PI)
  77.      pi2-=2*PI;
  78.    a=sin_tab(pi2);
  79.    return a;
  80. }
  81. /*****************************************************************
  82. 函数原型:void FFT(struct compx *xin,int N)
  83. 函数功能:对输入的复数组进行快速傅里叶变换(FFT)
  84. 输入参数:*xin复数结构体组的首地址指针,struct型
  85. 输出参数:无
  86. *****************************************************************/
  87. void FFT(struct compx *xin)
  88. {
  89.   register int f,m,nv2,nm1,i,k,l,j=0;
  90.   struct compx u,w,t;
  91.    
  92.    nv2=FFT_N/2;                  //变址运算,即把自然顺序变成倒位序,采用雷德算法
  93.    nm1=FFT_N-1;  
  94.    for(i=0;i<nm1;i++)        
  95.    {
  96.     if(i<j)                    //如果i<j,即进行变址
  97.      {
  98.       t=xin[j];           
  99.       xin[j]=xin[ i];
  100.       xin[ i]=t;
  101.      }
  102.     k=nv2;                    //求j的下一个倒位序
  103.     while(k<=j)               //如果k<=j,表示j的最高位为1   
  104.      {           
  105.       j=j-k;                 //把最高位变成0
  106.       k=k/2;                 //k/2,比较次高位,依次类推,逐个比较,直到某个位为0
  107.      }
  108.    j=j+k;                   //把0改为1
  109.   }
  110.                         
  111.   {
  112.    int le,lei,ip;                            //FFT运算核,使用蝶形运算完成FFT运算
  113.     f=FFT_N;
  114.    for(l=1;(f=f/2)!=1;l++)                  //计算l的值,即计算蝶形级数
  115.            ;
  116.   for(m=1;m<=l;m++)                         // 控制蝶形结级数
  117.    {                                        //m表示第m级蝶形,l为蝶形级总数l=log(2)N
  118.     le=2<<(m-1);                            //le蝶形结距离,即第m级蝶形的蝶形结相距le点
  119.     lei=le/2;                               //同一蝶形结中参加运算的两点的距离
  120.     u.real=1.0;                             //u为蝶形结运算系数,初始值为1
  121.     u.imag=0.0;
  122.     //w.real=cos(PI/lei);                  //不适用查表法计算sin值和cos值
  123.     // w.imag=-sin(PI/lei);
  124.     w.real=cos_tab(PI/lei);                //w为系数商,即当前系数与前一个系数的商
  125.     w.imag=-sin_tab(PI/lei);
  126.     for(j=0;j<=lei-1;j++)                  //控制计算不同种蝶形结,即计算系数不同的蝶形结
  127.      {
  128.       for(i=j;i<=FFT_N-1;i=i+le)           //控制同一蝶形结运算,即计算系数相同蝶形结
  129.        {
  130.         ip=i+lei;                          //i,ip分别表示参加蝶形运算的两个节点
  131.         t=EE(xin[ip],u);                   //蝶形运算,详见公式
  132.         xin[ip].real=xin[ i].real-t.real;
  133.         xin[ip].imag=xin[ i].imag-t.imag;
  134.         xin[ i].real=xin[ i].real+t.real;
  135.         xin[ i].imag=xin[ i].imag+t.imag;
  136.        }
  137.       u=EE(u,w);                          //改变系数,进行下一个蝶形运算
  138.      }
  139.    }
  140.   }
  141.   
  142. }


您需要登录后才可以回帖 登录 | 注册

本版积分规则

58

主题

5220

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部