FFT移植心得

 

花了2个晚上, 总算把FFTMP3编码器中提取出来并在keil上跑通, 主要还是对keilC51不熟, 走了不少弯路

1 开始怎么都跑不过去, 总是报

MAIN.C(55): error C249: 'DATA': SEGMENT TOO LARGE

突然想起不是大模式编译

2 fft函数内想printf出来一些数据看看, 发现总是报

FFT.C(101): warning C206: 'printf': missing function-prototype

而在main函数中则没错, 并不是忘记#include 好奇怪, 还不明白为什么.

3  找时间烧到51里头去看看

// -------------------------------- main.c --------------------------------

/*

void fft(float x_real[BLKSIZE],

       float       x_imag[BLKSIZE],

       float       energy[BLKSIZE],

       float       phi[BLKSIZE],

       int      N);

*/

#include

#include

#include

#include "fft.h"

 

static short int i;

static float wsamp_r[BLKSIZE_S];  //={0, 0, 0, 0, 0, 0, 0, 0};

static float wsamp_i[BLKSIZE_S];//;={0, 0, 0, 0, 0, 0, 0, 0};

static float energy[BLKSIZE_S];//={0, 0, 0, 0, 0, 0, 0, 0};

static float phi[BLKSIZE_S];   //={0, 0, 0, 0, 0, 0, 0, 0};

 

//char code dx516[3] _at_ 0x003b;//这是为了仿真设置的

 

void main( void )

{

   SCON = 0x52;

   TMOD = 0x20;

   TH1 = 0xf3;

   TR1 = 1;

 

   // fft(float x_real[BLKSIZE], float x_imag[BLKSIZE], float energy[BLKSIZE], float phi[BLKSIZE], int N);

   // 566

   // fft( wsamp_r, wsamp_i, energy, phi, 1024 );

   // 620

   // short FFT, 576个样本点, 连续3FFT(192*3)

   // fft( wsamp_r, wsamp_i, &energy_s[sblock][0], &phi_s[sblock][0], 256 );

   // 造假数据

   for(i=0; i

   {

      wsamp_r[i] = (float)i;

      wsamp_i[i] = 0.0;  //(float)(BLKSIZE_S-i);

      energy[i] = 0.0;

      phi[i] = 0.0;

   }

  

   fft( wsamp_r, wsamp_i, energy, phi, BLKSIZE_S );

 

   for(i=0; i

   {

      printf( "B %d---r=%f, i=%f, e=%f, p=%f/n", i, wsamp_r[i], wsamp_i[i], energy[i], phi[i] );

   }

 

   while( 1 );

}

 

// -------------------------------- fft.h --------------------------------

//#include

//#include

//#include

//#include

//#include

 

 

// 注意到pow(2,8)=256. 这个是短窗FFT使用的.

#define   BLKSIZE_S    256

#define   LOGBLKSIZE_S    8

//

#define     BLKSIZE       1024  //

 

 

// 定义PI, PI4=PI/4, PI64=PI/64

#define PI          3.14159265358979

//#define PI4           PI/4

//#define PI64          PI/64

// sqrt(2)

//#define SQRT2       1.41421356237

//

#define LOGBLKSIZE    10

//

//#define LN_TO_LOG10    0.2302585093

 

void fft(float x_real[BLKSIZE],

       float       x_imag[BLKSIZE],

       float       energy[BLKSIZE],

       float       phi[BLKSIZE],

       int      N);

// -------------------------------- fft.c --------------------------------

//#include

#include

#include

#include

#include "fft.h"

 

/**

 * N FFT(原位FFT).

 * MP3编码中, 有两种FFT, 一种是长窗FFT, 就是1024FFT. 一种是短窗FFT, 就是256FFT.

 *

 * x_real[index]  输入的实部, 也是输出的实部

 * x_imag[index]  输入的虚部, 也是输出的虚部

 * energy[index]  能量, 输出的x_real[index]*x_real[index]+x_imag[index]*x_imag[index]

 *             能量的平方.

 *             经过FFT后会得到一个频域输出, 谓之out_real, out_imag.

 *             energy[i]实际是out_real[i]*out_real[i] + out_imag[i]*out_imag[i];

 *             那么可知对energy[i]开平方得到r[i]的就是以out_real[i]out_imag[i]为直角边的

 *             斜边, 或者r[i]称为半径.

 * phi[index]     相位. real[index], imag[index]的夹角.

 * N          NFFT

 */

void fft(float     x_real[BLKSIZE],

       float       x_imag[BLKSIZE],

       float       energy[BLKSIZE],

       float       phi[BLKSIZE],

       int      N)

{

   // M  可以分成多少个Layer. 如果是1024FFT, FFT计算分成了10Layer, pow(2,10)=1024.

   // MM1 0

   int M, MM1;

   // 全局数据. 0则表示第一次调用FFT, 需要初始化一些数据, 比如计算旋转因子.

   static int       init = 0;

   // NV2 0

   // NM1 0

   // MP 0

   int NV2, NM1, MP;

   // 旋转因子.  其中 :

   // w_real[0], w_imag[0] 存储的是 1024 FFT的旋转因子.

   // w_real[1], w_imag[1] 存储的是 256 FFT的旋转因子.

   static double w_real[2][LOGBLKSIZE], w_imag[2][LOGBLKSIZE];

   // i 0

   // j 0

   // k 0

   // L 当前Layer, 也就是现在在那个Layer上运算.

   int i, j, k, L;

   //

   int ip, le, le1;

   //

   double t_real, t_imag, u_real, u_imag;

  

   // 如果是第一次调用FFT则计算出旋转因子来, 其实旋转因子不需要计算, 采用查表方式会更快.

   if(init == 0)

   {

      // preset statics to 0

       memset( (char*)w_real, 0, sizeof(w_real) );

       memset( (char*)w_imag, 0, sizeof(w_imag) );

       /*

        * 计算旋转因子

        * 旋转因子, 需要优化...

        * Wn=cos(2*pi*n/N)+j*sin(2*pi*n/N)

        *

        * tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));

        * tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));

        */

       // 长窗FFT要使用的旋转因子, 1024FFT.

       M = LOGBLKSIZE;    // 10, 分成10Layer

       for(L=0; L // L, 表示当前Layer.

       {

           le = 1 << (M-L);   // (M-L)*2

           le1 = le >> 1;     // le1 = pow(2, cur_layer)/(2*(p+step))

           // 旋转因子.

           w_real[0][L] = cos(PI/le1);

           w_imag[0][L] = -sin(PI/le1);

       }

                        

       // 短窗FFT要使用的旋转因子, 256FFT.

       M = LOGBLKSIZE_S; //8

       for(L=0; L

       {

           le = 1 << (M-L);

           le1 = le >> 1;

           w_real[1][L] = cos(PI/le1);

         w_imag[1][L] = -sin(PI/le1);

       }

       init ++;

   }

  

   switch( N )

   {

      // 注意到pow(2,10)=1024

      case BLKSIZE :  //1024

         M = LOGBLKSIZE; //10

         MP = 0;

         break;

      // 注意到pow(2,8)=256 

      case BLKSIZE_S ://256

         M = LOGBLKSIZE_S;//8

         MP = 1;

         break;

      default : //

          //printf( "Error: Bad FFT Size in subs.c/n" );

         //exit( -1 );

         break;

   }

   MM1 = M - 1;

   NV2 = N >> 1;

   NM1 = N - 1;

  

 /* 这里就是FFT, 结构是

  * for(layer)

  *    for()

  *       for()

  */     

   for(L=0; L

   {

       le = 1 << (M-L);

       le1 = le >> 1;

       u_real = 1;

       u_imag = 0;

       for(j=0; j

       {

           for(i=j; i

         {

               ip = i + le1;

           

               t_real = x_real[i] + x_real[ip];

               t_imag = x_imag[i] + x_imag[ip];

           

               x_real[ip] = x_real[i] - x_real[ip];

               x_imag[ip] = x_imag[i] - x_imag[ip];

           

               x_real[i] = t_real;

               x_imag[i] = t_imag;

           

               t_real = x_real[ip];

           

               x_real[ip] = x_real[ip]*u_real - x_imag[ip]*u_imag;

               x_imag[ip] = x_imag[ip]*u_real + t_real*u_imag;

           }

           t_real = u_real;

           u_real = u_real*w_real[MP][L] - u_imag*w_imag[MP][L];

           u_imag = u_imag*w_real[MP][L] + t_real*w_imag[MP][L];

       }

   }

  

/*

 * special case: L = M-1; all Wn = 1

 * 求各点的能量和夹角

 */

   for(i=0; i

   {

      // i0, 2, 4, 6..., ip1, 3, 5...

       ip = i + 1;

      

    /* 为什么要做一下这样的处理? 没搞明白哦! 如果这里这样做, 那么上面一定

     * 是已经做好了二进制反转工作或下面要做二进制反转工作 */

       t_real = x_real[i] + x_real[ip];

       t_imag = x_imag[i] + x_imag[ip];

       x_real[ip] = x_real[i] - x_real[ip];// real[i] = real[i] - real[ip]

       x_imag[ip] = x_imag[i] - x_imag[ip];

       x_real[i] = t_real;   // real[i] = real[i] + real[ip]

       x_imag[i] = t_imag;

      

       /* 求能量和夹角(-PI/2 ~ PI/2 ) */

       energy[i] = x_real[i]*x_real[i] + x_imag[i]*x_imag[i];

       // 0.0005是否是静音门槛曲线上规定的? 还是作者根据经验得到?

       if(energy[i] <= 0.0005)

       {

          phi[i] = 0;

          energy[i] = 0.0005;

       }

       else

       {

          phi[i] = atan2( (double)x_imag[i], (double)x_real[i] );

       }

       /* 求能量和夹角(-PI/2 ~ PI/2 ) */

       energy[ip] = x_real[ip]*x_real[ip] + x_imag[ip]*x_imag[ip];

       // 这里为什么不和0.0005比较?

       if(energy[ip] == 0)

       {

          phi[ip] = 0;

       }

       else

       {

          phi[ip] = atan2((double) x_imag[ip],(double) x_real[ip]);

       }

   }

  

// this section reorders the data to the correct ordering 重新排序. 二进制反转

   j = 0;

   for(i=0; i

   {

       if(i < j)

       {

      // use this section only if you need the FFT in complex

      // number form (and in the correct ordering)

           t_real = x_real[j];

           t_imag = x_imag[j];

           x_real[j] = x_real[i];

           x_imag[j] = x_imag[i];

           x_real[i] = t_real;

           x_imag[i] = t_imag;

      // reorder the energy and phase, phi

           t_real = energy[j];

           energy[j] = energy[i];

           energy[i] = t_real;

           t_real = phi[j];

           phi[j] = phi[i];

           phi[i] = t_real;

      }

       k = NV2;

       while(k <= j)

       {

           j = j - k;

           k = k >> 1;

       }

       j = j + k;

   }

}

你可能感兴趣的:(FFT移植心得)