FFT原理与实现(代码)

来源:互联网 发布:手机登陆淘宝卖家后台 编辑:程序博客网 时间:2024/04/29 16:18
#define N           128#define POWER       6//该值代表了输入数据首先被放大的倍数,放大倍数为2^POWER#define P_COEF      8//该值代表了旋转因子被放大的倍数,放大倍数为2^POWER#if (N == 4)#define L           2//L的定义满足L = log2(N)#elif (N == 8)#define L           3//L的定义满足L = log2(N)#elif (N == 16)#define L           4//L的定义满足L = log2(N)#elif (N == 32)#define L           5//L的定义满足L = log2(N)#elif (N == 64)#define L           6//L的定义满足L = log2(N)#elif (N == 128)#define L           7//L的定义满足L = log2(N)#endif//AD采样位数为12位,本可以采用s16 x[N]定义数据空间,但是为了节省存储空间,fft结果也将存储在该变量空间。由于受//fft影响变量需要重新定义,定义的方式及具体原因如下://fft过程会乘以较大旋转因子,因此需要32位定义//fft过程会产生负数,因此需要有符号定义//fft过程会出现复数,因此需要定义二维数组,[][0]存放实部,[][1]存放虚部s32 x[N][2] = {};//定义*p[N]是为了在第一次指针初始化以后,该数组指针按照位倒序指向数据变量x//p[i][0]代表了指向数据的实部,p[i][1]代表了指向数据的虚部s32 *p[N];//定义旋转因子矩阵//旋转因子矩阵存储了wn^0,wn^1,wn^2...wn^(N/2-1)这N/2个复数旋转因子 s16 w[N>>1][2] = {256,0,256,-13,255,-25,253,-38,251,-50,248,-62,245,-74,241,-86,237,-98,231,-109,226,                  -121,220,-132,213,-142,206,-152,198,-162,190,-172,181,-181,172,-190,162,-198,152,                  -206,142,-213,132,-220,121,-226,109,-231,98,-237,86,-241,74,-245,62,-248,50,-251,38,                  -253,25,-255,13,-256,0,-256,-13,-256,-25,-255,-38,-253,-50,-251,-62,-248,-74,-245,-86,                  -241,-98,-237,-109,-231,-121,-226,-132,-220,-142,-213,-152,-206,-162,-198,-172,-190,-181,                  -181,-190,-172,-198,-162,-206,-152,-213,-142,-220,-132,-226,-121,-231,-109,-237,-98,-241,                  -86,-245,-74,-248,-62,-251,-50,-253,-38,-255,-25,-256,-13};void init_pointer(void){     unsigned char i = 0;   unsigned char j = 0;   unsigned char k = 0;     for(i = 0; i < N; i++)   {  j = 0;      for(k = 0; k < L; k++)      {  j |= (((i >> k)&0x01)<<(L-k-1));      }      p[i] = &x[j][0];   }}/**description:基2fft主函数,该函数将借助指针数组p对全局变量数组x进行fft计算*            并将结果存储在数组x中*global var:rw->x; r->p,w。(r表示读,w表示写,rw表示读写)*/void fft2(void){  u8 i;//i用于表示蝶形图级联的阶数  u8 j;//表示蝶形分组起始点序列,蝶形分组跨度为2^i  u8 k;//k表示蝶形组内偶数分支序列点号  u8 gp_distance = 1;//蝶形分组跨度  u8 temp;//temp用于记录当前组间距离的一半,同时也表示了同一碟形两分支间的距离  u8 gp_hf = 0;//记录当前组的中间点序号  u8 delta = N;//旋转因子下标增量,本来下标初始值应该为N/2,但是。。  s16 *pw = &(w[0][0]);  int tp_result[2];       //用于临时存放旋转因子和奇数分组的乘积  //输入信号序列放大  for(i = 0; i < N; i++)  {  x[i][0] <<= POWER;     x[i][1] <<= POWER;  }  for(i = 0; i < L; i++)  {  temp = gp_distance;     gp_distance <<= 1;     for(j = 0; j < N; j+=gp_distance)     {  gp_hf = temp + j;        pw = &(w[0][0]);        for(k = j; k < gp_hf; k++)//完成一组内的所有蝶形运算        {  //蝶形运算中的一组复数乘法过程           tp_result[0] = pw[0] * (p[k+temp][0]) - pw[1] * (p[k+temp][1]);           tp_result[1] = pw[0] * (p[k+temp][1]) + pw[1] * (p[k+temp][0]);           tp_result[0] >>= P_COEF;           tp_result[1] >>= P_COEF;           //蝶形运算中的2组复数加法过程           p[k+temp][0] = p[k][0] - tp_result[0];           p[k+temp][1] = p[k][1] - tp_result[1];           p[k][0] += tp_result[0];           p[k][1] += tp_result[1];                       pw += delta;        }          }     delta >>= 1;  }}