此程序是以前做双色点阵音乐频谱时参考数字信号处理写的。相对于网上的一些代码,我这里对一些特殊的旋转因子做了特别处理程度稍微快了些,当然相对了基2,使用分裂基、基4肯定会更快。
//cr2_fft.h
#ifndef _CR_2_FFT_H_
#define _CR_2_FFT_H_
#define FFT_N 256 //输入序列的点数,要求FFT_N=2^FFT_M
#define FFT_M 8 //快速傅里叶变换蝶形运算的级数,满足FFT_N=2^FFT_M,即当FFT_N=16时,FFT_M=4
//特殊旋转因子的系数,预先计算出来
#define N__2 FFT_N/2
#define N__4 FFT_N/4
#define N__8 FFT_N/8
#define sqrt2_2 181 //sqrt2_2*256
typedef struct
{
long real;//实部
long image;//虚部
}Complex_Typedef;
void FFT_CR2(Complex_Typedef *SampleData);
#endif
//cr2_fft.c
/*************FFT旋转因子查找表,上位机生成**********************
*cos_tab:cos(2*pi*r/FFT_N) * 256 ,放大256倍
*sin_tab:sin(2*pi*r/FFT_N) * 256 ,放大256倍
*其中pi为常数:3.141592;FFT_N:傅里叶变换的点数;r:0~N/2-1;**/
#if FFT_N==256
const int sin_tab[FFT_N/2]=
{
00,06,13,19,25,31,
38,44,50,56,62,68,
74,80,86,92,98,104,
109,115,121,126,132,137,
142,147,152,157,162,167,
172,177,181,185,190,194,
198,202,206,209,213,216,
220,223,226,229,231,234,
237,239,241,243,245,247,
248,250,251,252,253,254,
255,255,256,256,256,256,
256,255,255,254,253,252,
251,250,248,247,245,243,
241,239,237,234,231,229,
226,223,220,216,213,209,
206,202,198,194,190,185,
181,177,172,167,162,157,
152,147,142,137,132,126,
121,115,109,104,98,92,
86,80,74,68,62,56,
50,44,38,31,25,19,
13,06
};
const int cos_tab[FFT_N/2]=
{
256,256,256,255,255,254,
253,252,251,250,248,247,
245,243,241,239,237,234,
231,229,226,223,220,216,
213,209,206,202,198,194,
190,185,181,177,172,167,
162,157,152,147,142,137,
132,126,121,115,109,104,
98,92,86,80,74,68,
62,56,50,44,38,31,
25,19,13,06,00,-06,
-13,-19,-25,-31,-38,-44,
-50,-56,-62,-68,-74,-80,
-86,-92,-98,-104,-109,-115,
-121,-126,-132,-137,-142,-147,
-152,-157,-162,-167,-172,-177,
-181,-185,-190,-194,-198,-202,
-206,-209,-213,-216,-220,-223,
-226,-229,-231,-234,-237,-239,
-241,-243,-245,-247,-248,-250,
-251,-252,-253,-254,-255,-255,
-256,-256
};
#else
#error "查找表的长度必须是256"
#endif
/******************************************************************
*函数名:ReverseAddr
*函数功能:对有限采样序列进行倒序运算
*输入参数:SampleData:采样数据序列
*返回值:指向变址后的复数序列
******************************************************************/
static Complex_Typedef *ReverseAddr(Complex_Typedef *SampleData)
{
int N = FFT_N;
int M = FFT_M;
u16 half_N;//用于存储序列点数的一半,可以减少运算次数,
u16 N_2;//减少运算次数用
u16 i=0,j=0,k=0;//计数用
Complex_Typedef tempotary;//临时数据
half_N = N/2;
j = half_N;
N_2 = N-2;
//雷德算法
for(i = 1;i <= N_2;i ++)
{
if(i < j)
{
tempotary = SampleData[j];
SampleData[j] = SampleData[i];//码位交换
SampleData[i] = tempotary;
}
k = half_N;//求j的下一个倒位序
while(k <= j)//
{
j = j - k;//把最高位变成0
k = k>>1;//K/2,比较次高位,依次类推,逐个比较,直到某个位为0
}
j = j + k;//把0改为1
}
return (SampleData);
}
/***********************************************************
*函数名:FFT_CR2:基2时选FFT
*函数功能:对采样有限序列进行快速傅里叶变换
*输入参数:SampleData- 采样序列
*输出参数: SampleData- 变换后的频谱序列
*返回值:无
***********************************************************/
void FFT_CR2(Complex_Typedef *SampleData)
{
int N = FFT_N; //N:有限序列的点数
int M = FFT_M; //满足N=2^M
u16 L;//蝶形结的长度
u16 p,k;//第L级各蝶形的复数结点
int r=0;//旋转因子的指数
int B=0;//第L级,每个蝶形的2个输入数据相距的点数=2^(L-1)
u16 Interval;//第L级,同一旋转因子对应着的间隔=2^L
long TR,TI,tmp;//临时变量
ReverseAddr(&SampleData);//变址运算
for(L = 1;L<= M;L ++)//最外层循环,用以完成N/2L个蝶形运算
{
B=1;
B = B<<(L-1);//用移位替代乘法,相当于2^(L-1)
Interval = B<<1;//相当于2^L
for(p = 0;p <= B - 1;p ++)//)中间层循环完成每一级的N/2 个蝶形运算
{
r=1;
r = (r<<(M-L)) * p;//求旋转因子指数r=(2^(M-L))*j
for(k = p;k < N;k += Interval)//求出相同旋转因子的蝶形
{
/***********暂存临时数据*************/
TR = SampleData[k].real;
TI = SampleData[k].image;
tmp = SampleData[k+B].real;
/*****优化计算量:先完成特殊蝶形运算,为第四类蝶形单元运算*****/
/*******先利用欧拉公式将旋转因子转换为三角函数*****/
switch(r)
{
case 0://旋转因子的值为1,不用计算乘法
{
SampleData[k].real = SampleData[k].real + SampleData[k+B].real;
SampleData[k].image = SampleData[k].image + SampleData[k+B].image;
SampleData[k+B].real = TR - SampleData[k+B].real;
SampleData[k+B].image = TI - SampleData[k+B].image;
}break;
case N__2://幅角为-PI
{
SampleData[k].real = SampleData[k].real - SampleData[k+B].real;
SampleData[k].image = SampleData[k].image - SampleData[k+B].image;
SampleData[k+B].real = TR + SampleData[k+B].real;
SampleData[k+B].image = TI + SampleData[k+B].image;
}break;
case N__4://幅角为PI/2
{
SampleData[k].real = SampleData[k].real + SampleData[k+B].image;
SampleData[k].image = SampleData[k].image - SampleData[k+B].real;
SampleData[k+B].real = TR - SampleData[k+B].image;
SampleData[k+B].image = TI + tmp ;
}break;
case N__8://幅角为PI/4,可以减少2次乘法
{
SampleData[k].real = SampleData[k].real + ( ( SampleData[k+B].real + SampleData[k+B].image) * sqrt2_2 >>8) ;//由于之前放大了256倍,故最后结果应缩小256倍
SampleData[k].image = SampleData[k].image + ( ( SampleData[k+B].image - SampleData[k+B].real ) * sqrt2_2 >>8) ;
SampleData[k+B].real = TR - ( ( SampleData[k+B].real + SampleData[k+B].image) * sqrt2_2 >>8) ;
SampleData[k+B].image = TI + ( ( tmp - SampleData[k+B].image) * sqrt2_2 >>8) ;
}break;
default://普通蝶形
{
SampleData[k].real = SampleData[k].real + ((SampleData[k+B].real * cos_tab[r]) >> 8) + ((SampleData[k+B].image * sin_tab[r]) >> 8);
SampleData[k].image = SampleData[k].image - ((SampleData[k+B].real * sin_tab[r]) >> 8) + ((SampleData[k+B].image * cos_tab[r]) >> 8);
SampleData[k+B].real = TR - ((SampleData[k+B].real * cos_tab[r]) >> 8) - ((SampleData[k+B].image * sin_tab[r]) >> 8);
SampleData[k+B].image = TI + ((tmp * sin_tab[r]) >> 8) - ((SampleData[k+B].image * cos_tab[r]) >> 8);
}
}
}
}
}
}
http://download.csdn.net/detail/jieffantfyan/9707975