📄 fft_new_test.c
字号:
数组BRTable[]被用来查找哪个值要被交换,只有一半的值被存储在数组中,另一半通过镜像前一半
得到。
=================================================================================================*/
void BitReverse(int BR_Array[])
{
#if(NUM_FFT>=512)
unsigned int swapA,swapB,sw_cnt;
#endif
#if(NUM_FFT<=256)
unsigned char swapA,swapB,sw_cnt;
#endif
int TempStore;
for(sw_cnt=1;sw_cnt<NUM_FFT/2;sw_cnt++)//第一部分的交换
{
swapA=sw_cnt; //保存当前位置
swapB=BRTable[sw_cnt]*2; //找到位反向索引
if(swapB>swapA) //如果位反向索引值比当前值大则交换
{
TempStore=BR_Array[swapA];
BR_Array[swapA]=BR_Array[swapB];
BR_Array[swapB]=TempStore;
}
swapA+=NUM_FFT/2; //第二部分的交换
swapB++;
if (swapB>swapA)
{
TempStore=BR_Array[swapA];
BR_Array[swapA]=BR_Array[swapB];
BR_Array[swapB]=TempStore;
}
}
}
/*=================================================================================================
04.名称:IntFFT
入口:ReArray[]:
ImArray[]:
出口:无
功能:FFT函数,对输入数组ReArray[]执行时间抽取的基2的FFT算法。在FFT算法的每一步,都要执行蝶形
方程:
Re1=Re1+(Cos(x)*Re2+Sin(x)*Im2)
Re2=Re1-(Cos(x)*Re2+Sin(x)*Im2)
Im1=Im1+(Cos(x)*Im2-Sin(x)*Re2)
Im2=Im1-(Cos(x)*Im2-Sin(x)*Re2)
程序使用如下值计算上式:
Re1=ReArray[indexA],Re2=ReArray[indexB]
Im1=ImArray[indexA],Im2=ImArray[indexB]
x =角度: 2*pi*(sin_index/NUM_FFT)单位:弧度;存储在代码空间SinTable[]数组中
关键点:
1. 实部的数据在ReArray[]数组中,2的幂,以16-bit二进制格式存放,虚部假设全为0
存放在ImArray[]数组中。
2. 实部假设被以位反向格式存储。
3. 正弦和余弦值被事先计算好存放在表中,事实上,表中只保存了1/4周期的正弦值。
4. 为了优化代码,只用整形数计算(没有浮点操作),这样可以节省存储空间。FFT所
有的中间计算结果都以16-bit形式存储,故程序的精度有限。当输入数据少于16-bit
时,数据左对齐在执行FFT可产生最好的计算结果。
5. FFT的算法为基-2算法,所以,采样点的个数必须为2^N,N为整数。最少的采样点个数
为4,常数NUM_FFT定义了采样点的个数。
6. 对输入数据进行优化,只有实部输入,虚部全部设置为0。在这一步中,删除了不必要
的重复部分,对于角度0这一点的计算,所有的sin值都时0,所有的cos值都是1。另外
由于虚部为0,故计算时的值也都为等于0。
=================================================================================================*/
void IntFFT(int ReArray[],int ImArray[])
{
#if(NUM_FFT>=512)
unsigned int sin_index,g_cnt,s_cnt; // Keeps track of the proper index
unsigned int indexA,indexB; // locations for each calculation
#endif
#if(NUM_FFT<=256)
unsigned char sin_index,g_cnt,s_cnt; // Keeps track of the proper index
unsigned char indexA,indexB; // locations for each calculation
#endif
unsigned int group=NUM_FFT/4,stage=2;
long CosVal,SinVal;
long TempImA,TempImB,TempReA,TempReB,TempReA2,TempReB2;
IBALONG ReTwid,ImTwid,TempL;
indexA=0;
for(g_cnt=0;g_cnt<NUM_FFT/2;g_cnt++)
{
indexB=indexA+1;
TempReA=ReArray[indexA];
TempReB=ReArray[indexB];
TempL.l=(long)TempReA+TempReB; //计算新的ReArray[indexA]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempReA2=(TempL.l>>1)+1;
else TempReA2=TempL.l>>1;
TempL.l=(long)TempReA-TempReB; //计算新的ReArray[indexB]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) ReArray[indexB]=(TempL.l>>1)+1;
else ReArray[indexB]=TempL.l>>1;
ReArray[indexA]=TempReA2;
ImArray[indexA]=0; //将虚部设置为0
ImArray[indexB]=0;
indexA=indexB+1;
}
while(stage<=NUM_FFT/2)
{
indexA=0;
sin_index=0;
for(g_cnt=0;g_cnt<group;g_cnt++)
{
for(s_cnt=0;s_cnt<stage;s_cnt++)
{
indexB=indexA+stage;
TempReA=ReArray[indexA];
TempReB=ReArray[indexB];
TempImA=ImArray[indexA];
TempImB=ImArray[indexB];
if(sin_index==0) //"x"=0弧度
{
TempL.l=(long)TempReA+TempReB;//计算新的ReArray[indexA]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempReA2=(TempL.l>>1)+1;
else TempReA2=TempL.l>>1;
TempL.l=(long)TempReA-TempReB;//计算新的ReArray[indexB]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempReB2=(TempL.l>>1)+1;
else TempReB2=TempL.l>>1;
TempL.l=(long)TempImA-TempImB;//计算新的ImArray[indexB]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempImB=(TempL.l>>1)+1;
else TempImB=TempL.l>>1;
TempL.l=(long)TempImA+TempImB;//计算新的ImArray[indexA]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempImA=(TempL.l>>1)+1;
else TempImA=TempL.l>>1;
}
else if(sin_index==NUM_FFT/4) //"x"=pi/2弧度
{
TempL.l=(long)TempReA-TempImB;//计算新的ReArray[indexB]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempReB2=(TempL.l>>1)+1;
else TempReB2=TempL.l>>1;
TempL.l=(long)TempReA+TempImB;//计算新的ReArray[indexA]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempReA2=(TempL.l>>1)+1;
else TempReA2=TempL.l>>1;
TempL.l=(long)TempImA+TempReB;//计算新的ImArray[indexB]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempImB=(TempL.l>>1)+1;
else TempImB=TempL.l>>1;
TempL.l=(long)TempImA-TempReB;//计算新的ImArray[indexA]的值
if((TempL.l<0)&&(0x01&TempL.b[3])) TempImA=(TempL.l>>1)+1;
else TempImA=TempL.l>>1;
}
else
{
if(sin_index>NUM_FFT/4) //如果没有上述情况,蝶形运算中的sin和cos值将通过查表得到。
{
SinVal=SinTable[(NUM_FFT/2)-sin_index];
CosVal=-SinTable[sin_index -(NUM_FFT/4)];
}
else
{
SinVal=SinTable[sin_index];
CosVal=SinTable[(NUM_FFT/4)-sin_index];
} //蝶形运算方程通过sin值和cos值来计算
ReTwid.l=((long)TempReB*CosVal)+((long)TempImB*SinVal);
ImTwid.l=((long)TempImB*CosVal)-((long)TempReB*SinVal);
TempL.i[1]=0; //计算新的ReArray[indexA]的值
TempL.i[0]=TempReA;
TempL.l=TempL.l>>1;
ReTwid.l+=TempL.l;
if((ReTwid.l<0)&&(ReTwid.i[1])) TempReA2=ReTwid.i[0]+1;
else TempReA2=ReTwid.i[0];
TempL.l=TempL.l<<1; //计算新的ReArray[indexB]的值
TempL.l-=ReTwid.l;
if((TempL.l<0)&&(TempL.i[1])) TempReB2=TempL.i[0]+1;
else TempReB2=TempL.i[0];
TempL.i[1]=0; //计算新的ImArray[indexA]的值
TempL.i[0]=TempImA;
TempL.l=TempL.l>>1;
ImTwid.l+=TempL.l;
if((ImTwid.l<0)&&(ImTwid.i[1])) TempImA=ImTwid.i[0]+1;
else TempImA=ImTwid.i[0];
TempL.l= TempL.l<<1; //计算新的ImArray[indexB]的值
TempL.l-=ImTwid.l;
if((TempL.l<0)&&(TempL.i[1])) TempImB=TempL.i[0]+1;
else TempImB=TempL.i[0];
}
ReArray[indexA]=TempReA2;
ReArray[indexB]=TempReB2;
ImArray[indexA]=TempImA;
ImArray[indexB]=TempImB;
indexA++;
sin_index+=group;
}
indexA=indexB+1;
sin_index=0;
}
group/=2;
stage*=2;
}
}
/*=================================================================================================
12.名称:ADC0_ISR
入口:无
出口:无
功能:ADC0中断服务子程序
=================================================================================================*/
void ADC0_ISR(void) interrupt 15 using 3
{
ADCINT=0; //清ADC转换标志位
Real[ADC_Index]=ADC0; //存ADC的转换值
ADC_Index++; //采样次数加1
if (ADC_Index>=NUM_FFT) //达到采样数
{
Conversion_Set_Complete=1; //标志主程序
EIE2&=~0x02; //ADC中断禁能
}
}
/*-----------------------------------------------------------------------------------------------*/
//FFT_New_Test.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -