搜索
bottom↓
回复: 183

[-玩转FFT算法-]-FFT算法单片机任你移植-个人总结篇

  [复制链接]

出0入0汤圆

发表于 2014-3-30 11:27:25 | 显示全部楼层 |阅读模式
本帖最后由 chaily 于 2014-3-30 13:35 编辑

之前有过不少的玩家发过许多关于FFT的贴了,但关于可随意移植到任意单片机的FFT算法个人感觉并不是很完善,尤其对于初学者和一些玩51的,大神看了不要笑话,嘿嘿。
这里对网上流传的其中一类FFT算法进行了个人测试和总结,在这里分享给大家。所有的资料都在附件里面了,这里贴出主要源代码和详细注释,里面也还有一些本人不清楚的问题,有待大神一起探讨。

/********************************************************************
这里讲讲傅立叶快速变换FFT算法的C例程,不恰当的地方还请探讨。
此例程可以移植到任何的单片机,但前提是单片机内存要够大(如果做32点的应该256字节内存就足够了,256字节内存的51机做64点好像也够),至于速度快或慢,只要你能承受那些慢速的就无所谓。
这里以128点采样作为例子。要注意的是,采样点数N和采样率Fs还有信号频率F的关系。
FFT算法可以把对波形采样回来的数据进行转换,比如有一个模拟信号过来,假设对其以某个采样率采样了128个点的数据,经过FFT换算以后,就可以获得这段波形里面含有的不同频率的特征,也就是变成频谱。换算的结果是以复数的形式表现的,比如某个频率的信息以a+bi的形式表示,这里a是实部,b是虚部。而例程中会以数组s16 Fft_Real[128]来表示128个频率的实部,以s16 Fft_Image[128]来表示128个频率的虚部。
采样点数N和采样率Fs还有信号频率F的关系是这样的,在一个模拟信号中,采样率至少应该是这个信号中需要分析的最高频率的2倍,而这个信号中需要分析的最低频率Fl=Fs/N,也就是采样率除以采样点数,同时这个频率也是fft换算过程的频率分辩率。可能有点晕了,这里举例说明。
假设我们有一个信号里面含有100Hz的信号和含有1000Hz的信号叠加在一起,用示波器是很难分清的,通过对这信号进行采样和FFT转换就可以得到这组信号的频谱特征,因为需要分析的最低信号为100Hz,我们假设现在对信号要进行128点的采样,那么我们至少要能分辨100Hz的信号,采样率可以是100Hzx128点=12800Hz,也就是我们需要以每秒采集12800点的速度来采集1/100秒的时间(因为只采集128点,所以时间上是1/100秒),当然也可以使用6400Hz的采样率,这样分辩率是50Hz,这里就以12800Hz为例。
采集回来的数据要怎么处理呢?首先对于FFT算法,需要有数组数据输入,经过FFT换算以后会以数组数据输出。我们可以直接定义两个数组s16 Fft_Real[128]和s16 Fft_Image[128],我们把采集来的128个数据按一个特殊的顺序输入到s16 Fft_Real[128]这个数组里面(当作实部输入),而s16 Fft_Image[128]则全部输入0,然后运行fft算法转换。转换过后,s16 Fft_Real[128]里面的128个数会变成128个频率的实部,而s16 Fft_Image[128]里面的128个数会变成128个频率的虚部。哪128个频率呢,实际上只能获得64个频率。在这两个输出的数组里面,数组s16 Fft_Real[128]的第一个数(第一个数是s16 Fft_Real[0])和s16 Fft_Image[128]的第一个数(第一个数是s16 Fft_Image[0])分别是0Hz这个频率(直流分量)的复数形式结果里面的实部和虚部,而第二个数是100Hz的复数形式的结果,第三个数是200Hz的结果,依此类推,第64个数是6300Hz的结果。假如我们想知道信号中是否含有100Hz这个频率存在,那么我们需要查看s16 Fft_Real[1]和s16 Fft_Image[1]这两个数,把实部和虚部分别进行平方求和以后再开平方,就是100Hz信号的模,把模值除以采样点数N的1/2就得到100Hz的信号的峰值。同理,要知道信号里面是否含有1000Hz,我们需要取出s16 Fft_Real[10]和s16 Fft_Image[10]来计算。这128组数据里面,只有前面64组是有用的,后面的都是镜像数据,我们不理会。因为采样率是12800Hz,我们能查看的最高频率是6400Hz,也就是需要拿s16 Fft_Real[64]和s16 Fft_Image[64]出来算,但这两个值很可能不再准确,因为是极限的问题。

以下我们来看看相关的例程,这个例程可以用于移植到任何的单片机中,只要单片机的速度不太慢(太慢你愿意慢慢等也没关系),内存足够就可以运行。这个例程可以修改为256点和512点或者1024点甚至更高点数的fft,下面会讲到需要修改一些什么参数。增加采样点数可以在采样率不变的情况下增加分辩率,如果点数增加一倍,采样率也提高一倍,那么分辩率不变,但能识别的最高频率将提高一倍,这是采样点数增加的好处,但同时会减慢运算速度。此例程使用stm32f103在72M主频下测试256点fft,运算时间为10mS左右,官方的函数库不知道会不会经过优化而更快,但考虑到许多人不喜欢使用函数库,也考虑这个例程的可移植性,这里直接使用fft函数而不讲函数库的内容。

*********************************************************************/



//以下为FFT傅立叶转换算法用到的相关定义
u8 ADC_Count=0;
/********注意,这里u8就是8位的unsigned char类型数据,在51里面就是unsigned char。以下的数组s16 Fft_Real[128]就是16位signed类型的数组,相当于signed int,而Fft_Real只是一个数组的名字,随便起也可以的,Fft_Image也一样**********/

u8 i,j,k,b,p; //这是用到的一些寄存器,注意这里如果要算256点以上的fft的话,需改成16位的u16。

s16 Temp_Real,Temp_Imag,temp; //中间临时变量,名称也是自己定义的,但要与fft函数里面的对应
u16 TEMP1; //用于求功率的,可不需要
s16 Fft_Real[128]; //fft实部,128数组
s16 Fft_Image[128]; //fft虚部,128数组

/*****以下为放大128倍后的sin正弦函数数组表格,这个表格可以用“正弦波表生成”这个软件来生成,要注意需要做多少点的fft,就需要生成多少点的。数据类型要选择整形,不要选择正整型,生成位数都为8位,这里为了能在普通单片机快速运行,不使用浮点数,使用查表法以达到最快的运算。如果是256点以上的,数组数据类型也是使用s8,但数组数量增加,那就要求更大的内存,注意这里相当于指针用法,如果内存足够的,最好把表格写入内存,那样运行速度快,如果内存资源紧的,就把表格写入程序区,对于51就是一个signed char code table[N]和signed char table[N]的区别,带了code就告诉编译器我这个表格要放在ROM程序存储区,不带code就直接放入内存,其他单片机不同写法自己研究研究  ******/
s8 SIN_TAB[128]={0x00, 0x06, 0x0c, 0x12, 0x18, 0x1e, 0x24, 0x2a,
0x30, 0x36, 0x3b, 0x41, 0x46, 0x4b, 0x50, 0x55,
0x59, 0x5e, 0x62, 0x66, 0x69, 0x6c, 0x70, 0x72,
0x75, 0x77, 0x79, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e,
0x7f, 0x7e, 0x7e, 0x7d, 0x7c, 0x7b, 0x79, 0x77,
0x75, 0x72, 0x70, 0x6c, 0x69, 0x66, 0x62, 0x5e,
0x59, 0x55, 0x50, 0x4b, 0x46, 0x41, 0x3b, 0x36,
0x30, 0x2a, 0x24, 0x1e, 0x18, 0x12, 0x0c, 0x06,
0x00, -0x06, -0x0c, -0x12, -0x18, -0x1e, -0x24, -0x2a,
-0x30, -0x36, -0x3b, -0x41, -0x46, -0x4b, -0x50, -0x55,
-0x59, -0x5e, -0x62, -0x66, -0x69, -0x6c, -0x70, -0x72,
-0x75, -0x77, -0x79, -0x7b, -0x7c, -0x7d, -0x7e, -0x7e,
-0x7f, -0x7e, -0x7e, -0x7d, -0x7c, -0x7b, -0x79, -0x77,
-0x75, -0x72, -0x70, -0x6c, -0x69, -0x66, -0x62, -0x5e,
-0x59, -0x55, -0x50, -0x4b, -0x46, -0x41, -0x3b, -0x36,
-0x30, -0x2a, -0x24, -0x1e, -0x18, -0x12, -0x0c, -0x06};

//以下是放大128倍后的cos余弦函数数组表格,这里注意事项与上面相同,只不过选择余弦来生成
s8 COS_TAB[128]={0x7f, 0x7e, 0x7e, 0x7d, 0x7c, 0x7b, 0x79, 0x77,
0x75, 0x72, 0x70, 0x6c, 0x69, 0x66, 0x62, 0x5e,
0x59, 0x55, 0x50, 0x4b, 0x46, 0x41, 0x3b, 0x36,
0x30, 0x2a, 0x24, 0x1e, 0x18, 0x12, 0x0c, 0x06,
0x00, -0x06, -0x0c, -0x12, -0x18, -0x1e, -0x24, -0x2a,
-0x30, -0x36, -0x3b, -0x41, -0x46, -0x4b, -0x50, -0x55,
-0x59, -0x5e, -0x62, -0x66, -0x69, -0x6c, -0x70, -0x72,
-0x75, -0x77, -0x79, -0x7b, -0x7c, -0x7d, -0x7e, -0x7e,
-0x7f, -0x7e, -0x7e, -0x7d, -0x7c, -0x7b, -0x79, -0x77,
-0x75, -0x72, -0x70, -0x6c, -0x69, -0x66, -0x62, -0x5e,
-0x59, -0x55, -0x50, -0x4b, -0x46, -0x41, -0x3b, -0x36,
-0x30, -0x2a, -0x24, -0x1e, -0x18, -0x12, -0x0c, -0x06,
0x00, 0x06, 0x0c, 0x12, 0x18, 0x1e, 0x24, 0x2a,
0x30, 0x36, 0x3b, 0x41, 0x46, 0x4b, 0x50, 0x55,
0x59, 0x5e, 0x62, 0x66, 0x69, 0x6c, 0x70, 0x72,
0x75, 0x77, 0x79, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e};

/***********以下是采样存储序列表,这个表格可以在FFT_Code_Tables.h这个文件里面找到,更多点的FFT也在里面找,就是里面的unsigned int code BRTable[N]的那些,是用来控制采样点数据输入到实部数组s16 Fft_Real[128]里面的***************/
u8 LIST_TAB[128]={0,64,32,96,16,80,48,112,
8,72,40,104,24,88,56,120,
4,68,36,100,20,84,52,116,
12,76,44,108,28,92,60,124,
2,66,34,98,18,82,50,114,
10,74,42,106,26,90,58,122,
6,70,38,102,22,86,54,118,
14,78,46,110,30,94,62,126,
1,65,33,97,17,81,49,113,
9,73,41,105,25,89,57,121,
5,69,37,101,21,85,53,117,
13,77,45,109,29,93,61,125,
3,67,35,99,19,83,51,115,
11,75,43,107,27,91,59,123,
7,71,39,103,23,87,55,119,
15,79,47,111,31,95,63,127};


//以下为fft算法主体部分
void FFT(void)
{
u8 N=7; //这里因为128是2的7次方,如果是计算256点,则是2的8次方,N就是8,如果是512点则N=9,如此类推
u16 NUM_FFT=128; //这里要算多少点的fft就赋值多少,值只能是2的N次方
    for( i=1; i<=N; i++)             /* for(1) */
    {
        b=1;
        b <<=(i-1);                 //蝶式运算,用于计算 隔多少行计算。例如第一级 1和2行计算,,,第二级
        for( j=0; j<=b-1; j++)       /* for (2) */
        {
            p=1;
            p <<= (N-i);            
            p = p*j;
            for( k=j; k<NUM_FFT; k=k+2*b)   /* for (3) 基二fft */
            {
                Temp_Real = Fft_Real[k]; Temp_Imag = Fft_Image[k]; temp = Fft_Real[k+b];
                Fft_Real[k] = Fft_Real[k] + ((Fft_Real[k+b]*COS_TAB[p])>>7) + ((Fft_Image[k+b]*SIN_TAB[p])>>7);
                Fft_Image[k] = Fft_Image[k] - ((Fft_Real[k+b]*SIN_TAB[p])>>7) + ((Fft_Image[k+b]*COS_TAB[p])>>7);
                Fft_Real[k+b] = Temp_Real - ((Fft_Real[k+b]*COS_TAB[p])>>7) - ((Fft_Image[k+b]*SIN_TAB[p])>>7);
                Fft_Image[k+b] = Temp_Imag + ((temp*SIN_TAB[p])>>7) - ((Fft_Image[k+b]*COS_TAB[p])>>7);     
                //移位,防止溢出。结果已经是本值的1/64               
              Fft_Real[k] >>= 1;            
                Fft_Image[k] >>= 1;
               Fft_Real[k+b]  >>= 1;                 
                Fft_Image[k+b]  >>= 1;
            }     
        }
    }
//         Fft_Real[0]=Fft_Image[0]=0;  //去掉直流分量,也可以不去掉
//   Fft_Real[63]=Fft_Image[63]=0;
/********以上已经把128点的实部和虚部求完,下一次运算前需要把所有虚部重新清零
要求某个频率点的模,则模值=根号(实部平方+虚部平方),即sqrt((Fft_Real[n]*Fft_Real[n])+(Fft_Image[n]*Fft_Image[n]))
第n个频率点的值是数组上的Fft_Real[n]和Fft_Image[n],而Fft_Real[0]是直流分量。Fft_Real[1]是最低频率点,也是最小频率分辩率值,等于采样率/采样点数N
波形峰值大小=模值/(N/2), N为采样点数
注意,由于上面把求得的值已经移位除法,相当于缩小了64倍(移位7位好像是128倍吧??后面为什么还要移动一位?这里待高手指点,本人也不是很清楚,这里只做移植总结)
得到的那些实部虚部的结果爱怎么处理怎么处理,可以做音频频谱强度显示啦什么的******************/
}




void Fft_Imagclear(void) //fft虚部清零函数,在运行FFT函数之前需要先运行这个
{
        u8 a;  //注意这里如果是256点以上要改成u16,下面的a<128条件也要相应的修改
        for(a=0;a<128;a++)
                {
                        Fft_Image[a]=0;
                }
}



/********采样程序如下,这是stm32里面的采样函数而已,别的单片机该怎么写自己搞定,反正是采集够点数了,就停止采样,采样的数据输入到实部的时候是按那个LIST_TAB[128]表格顺序的,这里函数已经写好一个模型了,也就是Fft_Real[LIST_TAB[ADC_Count]]=你的采样数据,注意只输入到实部,虚部全部输入为0,所以运行FFT前虚部需要清零******/
void TIM2_IRQHandler(void)   //时间中断服务函数, 这里控制自动定时采样
{
        TIM_ClearFlag(TIM2, TIM_FLAG_Update); //该服务函数定时时间的倒数就是采样率
        //stm32里面所有中断都不会自动清零,需要返回前清零标志位,否则会一直无限产生中断,其他单片机自己考虑实际情况

        Fft_Real[LIST_TAB[ADC_Count]]=ADC_GetConversionValue(ADC1); //这里ADC_GetConversionValue(ADC1)是获得ADC的采样值,这里不同的单片机可能处理不同
                        if(ADC_Count<127) //采样计数条件判断
                                        {ADC_Count++;}
                        else
                                        {TIM_Cmd(TIM2,DISABLE);ADC_Count=128;} //采样够了就把控制中断的定时器关闭,这里写法可以自己发挥
               
}





关于主函数可以大概这样写:
int main(void)
{
        while(1)
           {
                ADC_Count=0;
                TIM_Cmd(TIM2,ENABLE); //打开控制采样的定时器中断的定时器,至于你的ADC是怎么采样的自己搞定
                while(ADC_Count<128); //当采样点达到128点前循环等待,达到128点后跳过,这个点数随着需要的点数修改,需要配合采样时间中断的写法
                FFT(); //运行FFT换算
                Fft_Imagclear(); //运行虚部清零
          }

}



附件里面的内容有:
FFT_Code_Tables.h 文件
FFT变换的实际意义
正弦波表生成软件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-3-30 11:32:26 | 显示全部楼层
既然用了STM32,干嘛不用DSPLib呢。

出0入0汤圆

 楼主| 发表于 2014-3-30 11:38:44 | 显示全部楼层
笑笑我笑了 发表于 2014-3-30 11:32
既然用了STM32,干嘛不用DSPLib呢。

额。。。这里是主要针对可移植的问题,哈~

出0入0汤圆

发表于 2014-3-30 11:59:40 | 显示全部楼层
正在学习当中

出0入0汤圆

发表于 2014-3-30 12:01:41 | 显示全部楼层
记号,收藏

出0入0汤圆

发表于 2014-3-30 12:04:43 | 显示全部楼层
再做linux上的fft,本来想自己写
但是后来发现fftw库....

出0入0汤圆

发表于 2014-3-30 12:09:14 | 显示全部楼层
上过数字信号处理的课,现在只记得IIR,FIR,还都不会用  有空看看FFT

出0入0汤圆

发表于 2014-3-30 13:17:10 | 显示全部楼层
很好的资源帖,谢谢楼主贡献~~让我研究研究去~

出0入0汤圆

发表于 2014-3-30 13:34:26 | 显示全部楼层
那我要分析音频,那应该怎么取值,对单片机有什么要求呢?我想了解做一个音频频谱要什么要求

出0入0汤圆

 楼主| 发表于 2014-3-30 14:05:41 | 显示全部楼层
enovo2468 发表于 2014-3-30 13:34
那我要分析音频,那应该怎么取值,对单片机有什么要求呢?我想了解做一个音频频谱要什么要求 ...

如果是做音乐频谱,考虑到我们大部分音乐的实际音频一般不超过16Khz,实际上绝大部分都不超过10KHz的,大于10KHz的声音是很少在我们普通音乐里面出现的。
如果单片机速度比较慢,则建议使用64点fft来做音乐频谱。这样可以分辨32段频谱,采样率可以设定为20KHz,这样最高分辨的频率是10KHz,而分辩率也就是最低一段的频率点是312.5Hz。
如果单片机速度还可以,可以使用128点FFT,这样可以分辨64段频谱,但我们一般只做32段就完全足够了,我们仍然可以使用20KHz的采样率,当然你想显示超过10KHz以上的频谱可以提高这个采样率。以20K采样率算的话,最低段的频率就变成了156Hz了,而32段是足够显示的了。当然如果你想耍耍酷,搞个64段或者128段也成~

对于单片机的要求,就以最普通的51单片机来说,如果是12MHz晶振,12T的话,主频只有1MHz,内存只有128字节怎么办呢,那只能把正弦余弦和存储顺序表格放入ROM中,勉强运行32点fft,因为实部虚部就占了64字节,剩余的资源非常紧张。对于许多STC的1T单片机估计还是可以胜任的,就12系列带AD的单片机,运行64点完全没问题,运行128点也有人做过,128点运算一次大概不超过50ms吧,这是估算,本人没实测,因为已经有不少人做出来了。

出0入0汤圆

发表于 2014-3-30 14:14:47 来自手机 | 显示全部楼层
讲的很详细,谢谢分享。

出0入0汤圆

发表于 2014-3-30 14:17:29 | 显示全部楼层
chaily 发表于 2014-3-30 14:05
如果是做音乐频谱,考虑到我们大部分音乐的实际音频一般不超过16Khz,实际上绝大部分都不超过10KHz的,大 ...

那就是说平常看到的频谱没到20K,所以就比较平均,好看些,那频谱的dB怎么分?

出0入0汤圆

 楼主| 发表于 2014-3-30 14:25:17 | 显示全部楼层
本帖最后由 chaily 于 2014-3-30 14:29 编辑
enovo2468 发表于 2014-3-30 14:17
那就是说平常看到的频谱没到20K,所以就比较平均,好看些,那频谱的dB怎么分? ...


对,看起来比较平均的频谱很多最高一段都是不超过10KHz的,也好看。如果把最高设计成16KHz,那一般的音乐播放的时候,高段的部分基本上都不出现音柱了。
频谱的db就是每个对应频率的功率值,因为频谱实际上大多数都是功率谱,至于音频谱具体的换算关系,有些我也说不清楚哈~
而对于频谱仪,上面有标dbm的,比如某一个频率显示-10dbm,那这个输入进去的信号里面这个对应的频率的信号功率已经达到0.1W。

我们做音乐频谱的时候,为了表现效果,其实可以直接取模的值按一定比例放大或缩小来驱动点阵LED屏来做就行。论坛上有不少发的贴有参考的,可以搜索一下就知道了~

出0入0汤圆

发表于 2014-3-30 14:32:15 | 显示全部楼层
fft就是根据dft变下形式而已。
dft就一个公式。如果实时性不做要求,dft已经够用了、、、

出0入0汤圆

发表于 2014-3-30 14:41:27 | 显示全部楼层
好好学习天天向上,我也刚好做了一个玩玩

出0入0汤圆

发表于 2014-3-30 15:00:09 | 显示全部楼层
顶一下,MARK...

出0入0汤圆

发表于 2014-3-30 15:00:48 | 显示全部楼层
好东东,fft对这个一直没弄懂。多谢分享了

出0入0汤圆

发表于 2014-3-30 16:29:40 | 显示全部楼层
本帖最后由 1988_coolboy 于 2014-3-30 16:32 编辑

帮楼主顶一下,谢谢分享

出0入0汤圆

发表于 2014-3-30 20:27:19 | 显示全部楼层
多谢楼主分享

出0入0汤圆

发表于 2014-3-30 23:33:58 | 显示全部楼层
我找过一个滤波的,算啊算的,4,5秒才完事····

出0入0汤圆

 楼主| 发表于 2014-3-31 08:09:33 | 显示全部楼层
kalo425 发表于 2014-3-30 23:33
我找过一个滤波的,算啊算的,4,5秒才完事····

滤波的?4,5秒?怎么说?

出0入0汤圆

发表于 2014-3-31 08:23:53 | 显示全部楼层
学习,以后用的到。

出0入0汤圆

发表于 2014-3-31 08:54:47 来自手机 | 显示全部楼层
很好的入门,fft频谱,顶顶楼主 !

出0入0汤圆

发表于 2014-3-31 09:03:38 | 显示全部楼层
不错,很好的帖子,学习一下,谢谢楼主分享

出0入0汤圆

发表于 2014-3-31 09:21:59 来自手机 | 显示全部楼层
学习学习,谢谢

出0入0汤圆

发表于 2014-3-31 09:53:12 | 显示全部楼层
正需要这方面的资料,mark

出0入0汤圆

发表于 2014-3-31 14:07:02 | 显示全部楼层
讲得不错,赞一个。

出0入0汤圆

发表于 2014-3-31 14:22:11 | 显示全部楼层
先mark 等下看

出0入0汤圆

发表于 2014-3-31 14:29:07 | 显示全部楼层
这个写得比较清楚,好好

出0入0汤圆

发表于 2014-3-31 15:03:09 | 显示全部楼层
收藏,谢谢这样的好资料。。。

出0入0汤圆

 楼主| 发表于 2014-3-31 15:11:45 | 显示全部楼层
添加一个1024点的BRTable表格

unsigned int code BRTable[1024] ={0,512,256,768,128,640,384,896,64,576,320,832,192,704,448,960,

32,544,288,800,160,672,416,928,96,608,352,864,224,736,480,992,

16,528,272,784,144,656,400,912,80,592,336,848,208,720,464,976,

48,560,304,816,176,688,432,944,112,624,368,880,240,752,496,1008,

8,520,264,776,136,648,392,904,72,584,328,840,200,712,456,968,

40,552,296,808,168,680,424,936,104,616,360,872,232,744,488,1000,

24,536,280,792,152,664,408,920,88,600,344,856,216,728,472,984,

56,568,312,824,184,696,440,952,120,632,376,888,248,760,504,1016,

4,516,260,772,132,644,388,900,68,580,324,836,196,708,452,964,

36,548,292,804,164,676,420,932,100,612,356,868,228,740,484,996,

20,532,276,788,148,660,404,916,84,596,340,852,212,724,468,980,

52,564,308,820,180,692,436,948,116,628,372,884,244,756,500,1012,

12,524,268,780,140,652,396,908,76,588,332,844,204,716,460,972,

44,556,300,812,172,684,428,940,108,620,364,876,236,748,492,1004,

28,540,284,796,156,668,412,924,92,604,348,860,220,732,476,988,

60,572,316,828,188,700,444,956,124,636,380,892,252,764,508,1020,

2,514,258,770,130,642,386,898,66,578,322,834,194,706,450,962,

34,546,290,802,162,674,418,930,98,610,354,866,226,738,482,994,

18,530,274,768,146,658,402,914,82,594,338,850,210,722,466,978,

50,562,306,818,178,690,434,946,114,626,370,882,242,754,498,1010,

10,522,266,778,138,650,394,906,74,586,330,842,202,714,458,970,

42,554,298,810,170,682,426,938,106,618,362,874,234,746,490,1002,

26,538,282,794,154,666,410,922,90,602,346,858,218,730,474,986,

58,570,314,826,186,698,442,954,122,634,378,890,250,762,506,1018,

6,518,262,774,134,646,390,902,70,582,326,838,198,710,454,966,

38,550,294,806,166,678,422,934,102,614,358,870,230,742,486,998,

22,534,278,790,150,662,406,918,86,598,342,854,214,726,470,982,

54,566,310,822,182,694,438,950,118,630,374,886,246,758,502,1014,

14,526,270,782,142,654,398,910,78,590,334,846,206,718,462,974,

46,558,302,814,174,686,430,942,110,622,366,878,238,750,494,1006,

30,542,286,798,158,670,414,926,94,606,350,862,222,734,478,990,

62,574,318,830,190,702,446,958,126,638,382,894,254,766,510,1022,

1,513,257,769,129,641,385,897,65,577,321,833,193,705,449,961,

33,545,289,801,161,673,417,929,97,609,353,865,225,737,481,993,

17,529,273,785,145,657,401,913,81,593,337,849,209,721,465,977,

49,561,305,817,177,689,433,945,113,625,369,881,241,753,497,1009,

9,521,265,777,137,649,393,905,73,585,329,841,201,713,457,969,

41,553,297,809,169,681,425,937,105,617,361,873,233,745,489,1001,

25,537,281,793,153,665,409,921,89,601,345,857,217,729,473,985,

57,569,313,825,185,697,441,953,121,633,377,889,249,761,505,1017,

5,517,261,773,133,645,389,901,69,581,325,837,197,709,453,965,

37,549,293,805,165,677,421,933,101,613,357,869,229,741,485,997,

21,533,277,789,149,661,405,917,85,597,341,853,213,725,469,981,

53,565,309,821,181,693,437,949,117,629,373,885,245,757,501,1013,

13,525,269,781,141,653,397,909,77,589,333,845,205,717,461,973,

45,557,301,813,173,685,429,941,109,621,365,877,237,749,493,1005,

29,541,285,797,157,669,413,925,93,605,349,861,221,733,477,989,

61,573,317,829,189,701,445,957,125,637,381,893,253,765,509,1021,

3,515,259,771,131,643,387,899,67,579,323,835,195,707,451,963,

35,547,291,803,163,675,419,931,99,611,355,867,227,739,483,995,

19,531,275,787,147,659,403,915,83,595,339,851,211,723,467,979,

51,563,307,819,179,691,435,947,115,627,371,883,243,755,499,1011,

11,523,267,779,139,651,395,907,75,587,331,843,203,715,459,971,

43,555,299,811,171,683,427,939,107,619,363,875,235,747,491,1003,

27,539,283,795,155,667,411,923,91,603,347,859,219,731,475,987,

59,571,315,827,187,699,443,955,123,635,379,891,251,763,507,1019,

7,519,263,775,135,647,391,903,71,583,327,839,199,711,455,967,

39,551,295,807,167,679,423,935,103,615,359,871,231,743,487,999,

23,535,279,791,151,663,407,919,87,599,343,855,215,727,471,983,

55,567,311,823,183,695,439,951,119,631,375,887,247,759,503,1015,

15,527,271,783,143,655,399,911,79,591,335,847,207,719,463,975,

47,559,303,815,175,687,431,943,111,623,367,879,239,751,495,1007,

31,543,287,799,159,671,415,927,95,607,351,863,223,735,479,991,

63,575,319,831,191,703,447,959,127,639,383,895,255,767,511,1023}

出0入0汤圆

发表于 2014-3-31 16:21:03 | 显示全部楼层
好贴,正在搞FFT。

出0入618汤圆

发表于 2014-3-31 16:35:14 | 显示全部楼层
STM32F1 DSP库的FFT性能是这样滴,撸主加把劲……

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-3-31 20:56:21 | 显示全部楼层
gzhuli 发表于 2014-3-31 16:35
STM32F1 DSP库的FFT性能是这样滴,撸主加把劲……

汉。。。。。32f103是达不到这个速度的,这好像是f3还是f4的。。。。。。。

出0入0汤圆

发表于 2014-3-31 21:18:52 | 显示全部楼层
谢谢, 写的通俗易懂~

出0入0汤圆

发表于 2014-3-31 21:30:49 | 显示全部楼层

出0入0汤圆

发表于 2014-3-31 21:38:32 | 显示全部楼层
学习了,谢谢

出0入618汤圆

发表于 2014-4-1 00:10:36 | 显示全部楼层
chaily 发表于 2014-3-31 20:56
汉。。。。。32f103是达不到这个速度的,这好像是f3还是f4的。。。。。。。  ...

截图来自:UM0585: STM32F10x DSP library
看那24/48/72MHz的频率都知道不是F4啦……

出0入0汤圆

 楼主| 发表于 2014-4-1 12:16:59 | 显示全部楼层
gzhuli 发表于 2014-4-1 00:10
截图来自:UM0585: STM32F10x DSP library
看那24/48/72MHz的频率都知道不是F4啦……

查了一下,貌似F103确实也可以优化得很快,看来我得加把劲了

出0入13汤圆

发表于 2014-4-1 16:03:37 | 显示全部楼层
写的真不错,一直想用来着

出0入0汤圆

发表于 2014-4-2 10:22:18 | 显示全部楼层
小弟问一下p  <<= (N-i);这一句有没有问题呀,如果没有问题的话得到的p值为何是
第一次:i = 1; N-i = 6; j = 0; p = 0;
第二次:i = 2; N-ip = 5;j = 0; p = 0;
                                 j = 1; p = 64;     感觉这里p应该是等于2的呀

现在彻底蒙圈了,到底咋回事儿呢

出0入0汤圆

发表于 2014-4-2 11:02:20 | 显示全部楼层
急求楼主解答呀……我实在搞不懂了

出0入0汤圆

 楼主| 发表于 2014-4-2 12:08:34 | 显示全部楼层
zhengensong 发表于 2014-4-2 11:02
急求楼主解答呀……我实在搞不懂了

没有问题的,具体这里面怎么兜圈我也很多疑问,但我就是直接拿来用,现在已经在做1024点FFT对模拟信号进行频谱成分分析了,效果超级好。至于这个算法核心,我也不明所以。。。。。

出0入0汤圆

发表于 2014-4-2 12:16:33 | 显示全部楼层
for( k=j; k<NUM_FFT; k=k+2*b)

看到这个,LZ没怎么优化啊。。。。

出0入0汤圆

 楼主| 发表于 2014-4-2 12:20:43 | 显示全部楼层

是没有优化,我没去管FFT函数部分的东西。那部分只是摘抄的和修改成可以做任意点数的函数而已,主要是为了方便移植的啦,肯定比不上官方函数库的~~

出0入0汤圆

发表于 2014-4-2 12:56:28 | 显示全部楼层
楼主高人啊

出0入0汤圆

发表于 2014-4-2 13:22:24 | 显示全部楼层
过来学习一下

出0入0汤圆

发表于 2014-4-2 13:45:11 | 显示全部楼层
chaily 发表于 2014-4-2 12:20
是没有优化,我没去管FFT函数部分的东西。那部分只是摘抄的和修改成可以做任意点数的函数而已,主要是为 ...

好吧,我已经明白咋回事儿了,不过谢谢你啊,这个代码还有赶紧的余地,等我确定了再说

出0入0汤圆

 楼主| 发表于 2014-4-2 16:18:10 | 显示全部楼层
zhengensong 发表于 2014-4-2 13:45
好吧,我已经明白咋回事儿了,不过谢谢你啊,这个代码还有赶紧的余地,等我确定了再说 ...

好的

出0入0汤圆

发表于 2014-4-2 16:53:09 | 显示全部楼层
很详细的资料

出0入0汤圆

发表于 2014-4-2 17:03:27 | 显示全部楼层
楼主的资料很详细

出0入12汤圆

发表于 2014-4-2 23:04:55 | 显示全部楼层
很好的资源帖,谢谢楼主贡献

出10入0汤圆

发表于 2014-4-3 00:16:32 来自手机 | 显示全部楼层
mark!!有空学习学习!

出100入101汤圆

发表于 2014-4-3 07:47:07 | 显示全部楼层
写得不错!

出0入0汤圆

发表于 2014-4-3 09:27:43 | 显示全部楼层

我觉着正弦和余弦两个表格中的64-127的数似乎没有用到,然后就移位七次又来一次这个问题,我想半天也没有想明白,如果非得要一个合理的解释的话,似乎他是将实部和虚部都除以了256,这样平方相加开根号之后的幅值也相当于除以了256,是不是将数字量转化为了以V为单位的电压了呢?仅仅是猜想

出0入0汤圆

 楼主| 发表于 2014-4-3 12:00:07 | 显示全部楼层
zhengensong 发表于 2014-4-3 09:27
我觉着正弦和余弦两个表格中的64-127的数似乎没有用到,然后就移位七次又来一次这个问题,我想半天也没有 ...

我也不清楚,所以这部分也是我的疑问,哈~

出0入0汤圆

发表于 2014-4-3 12:04:25 | 显示全部楼层
果断收藏

出0入0汤圆

发表于 2014-4-3 22:04:14 | 显示全部楼层
本帖最后由 zhengensong 于 2014-4-4 08:20 编辑
chaily 发表于 2014-4-3 12:00
我也不清楚,所以这部分也是我的疑问,哈~


楼主看看余弦的表格中的第一个值COS(0)本应该等于1的,但是他取的是127,8位的有符号整数是从-128到+127的,这样他后边在计算完成之后只要用到COS和SIN的地方都要除以128的,这样也是为了防止溢出的,如果COS和SIN的值,最大的是1,如果取浮点数据,运算特别慢不说,占内存,结果也不精确,他这样扩大倍数计算,计算完成之后再把倍数降下来,这样就使得数据在整数范围内有较快的准确的运算了,后边的移位,也就是又除以了2,我猜测可能是怕得到的结果溢出,他在这里除以2,得到的相当于实部和虚部都除以2,这样就相当于实部和虚部的平方和开放除以2,如果计算模值,他只需要再除以32就可以了,不过他的表格中的数据128个他就用了64个我真心猜不到为啥,如果楼主能验证的话,还请楼主帮忙验证一下能否把正弦和余弦两个数组中的64-127删除,看看结果是否正确,我能想到的就这么多,希望对大家有帮助,不足之处希望大家再次纠正……

出0入0汤圆

发表于 2014-4-3 23:45:38 | 显示全部楼层
很好的入门,fft频谱,顶顶楼主 !

出0入0汤圆

 楼主| 发表于 2014-4-4 00:17:45 | 显示全部楼层
zhengensong 发表于 2014-4-3 22:04
楼主看看余弦的表格中的第一个值COS(0)本应该等于1的,但是他取的是127,8为的有符号整数是从-128到+127 ...

你说的这个我迟些找时间测试一下。

出0入0汤圆

发表于 2014-4-4 08:20:47 | 显示全部楼层
chaily 发表于 2014-4-4 00:17
你说的这个我迟些找时间测试一下。

谢楼主

出0入0汤圆

 楼主| 发表于 2014-4-4 08:55:53 | 显示全部楼层
zhengensong 发表于 2014-4-3 22:04
楼主看看余弦的表格中的第一个值COS(0)本应该等于1的,但是他取的是127,8位的有符号整数是从-128到+127 ...

有一点不是很明白你说的,就是把正弦和余弦两个数组中的64-127删除,是直接删除然后数组数量变为64,还是说后面删除那些全部补0而保持数组数据还是128个呢?

出0入0汤圆

发表于 2014-4-4 09:35:57 | 显示全部楼层
漂亮啊,一直想弄个音乐频谱呢,还没抽时间看FFT算法……通用版,perfect

出0入0汤圆

发表于 2014-4-4 13:36:20 | 显示全部楼层
chaily 发表于 2014-4-4 08:55
有一点不是很明白你说的,就是把正弦和余弦两个数组中的64-127删除,是直接删除然后数组数量变为64,还是 ...

直接变成64个元素的数组

出0入4汤圆

发表于 2014-4-6 18:36:34 | 显示全部楼层
果断收藏!!!!!!

出0入0汤圆

发表于 2014-4-6 18:41:12 | 显示全部楼层
必须收藏

出0入0汤圆

发表于 2014-4-6 18:42:34 | 显示全部楼层
腻害

出0入0汤圆

发表于 2014-4-8 15:28:35 | 显示全部楼层
收藏先!!

出0入0汤圆

发表于 2014-5-22 11:13:57 | 显示全部楼层
zhengensong 发表于 2014-4-3 22:04
楼主看看余弦的表格中的第一个值COS(0)本应该等于1的,但是他取的是127,8位的有符号整数是从-128到+127 ...

针对这楼,实部和虚部都除以2,这样就相当于实部和虚部的平方和开放除以2,计算模值,为什么需要再除以32?而不是除以2?(还有就是代码刚开始说移位7位完就得到本值的1/64,按你的逻辑他只是先把SIN COS的值放大 在缩小,最后等得到的值应该是个正常的值。)层主能交流交流么?
我的Q:527507568。方便的话可以加Q一起交流,谢谢!

出0入0汤圆

发表于 2014-5-22 13:51:50 | 显示全部楼层
谢谢了 ,果断收藏下

出0入0汤圆

发表于 2014-6-12 11:49:59 | 显示全部楼层
mark一下,打算做个东西

出0入0汤圆

发表于 2014-6-12 13:39:46 | 显示全部楼层
很好。。。。

出0入0汤圆

发表于 2014-6-12 14:37:41 | 显示全部楼层

出0入0汤圆

发表于 2014-6-16 12:41:50 | 显示全部楼层
正在学习,谢谢楼主分享

出0入0汤圆

发表于 2014-7-23 13:44:10 | 显示全部楼层
多谢分享

出0入0汤圆

发表于 2014-7-23 14:01:19 | 显示全部楼层
多谢分享,支持一个。

出0入0汤圆

发表于 2014-7-26 10:37:09 | 显示全部楼层
好东西,谢谢分享了。

出0入0汤圆

发表于 2014-7-26 10:44:13 | 显示全部楼层
久违的名词  

出0入0汤圆

发表于 2014-7-26 11:27:54 | 显示全部楼层
MARK一下

出0入0汤圆

发表于 2014-7-31 09:49:16 | 显示全部楼层
嗯。楼主的心得挺好的

出0入0汤圆

发表于 2014-8-1 16:38:53 | 显示全部楼层
谢谢楼主 正需要这个

出0入0汤圆

发表于 2014-8-2 00:43:53 | 显示全部楼层
收藏了再慢慢消化

出0入0汤圆

发表于 2014-8-3 12:23:28 | 显示全部楼层
好东西啊,先收藏了

出0入0汤圆

发表于 2014-8-3 22:16:04 | 显示全部楼层
楼主很热心哈 这个必须收藏下

出0入0汤圆

发表于 2014-8-7 13:46:01 | 显示全部楼层
收藏了,

出0入0汤圆

发表于 2014-8-7 16:17:58 | 显示全部楼层
很好的帖子

出0入17汤圆

发表于 2014-8-7 20:08:17 | 显示全部楼层
学习学习了···!

出0入0汤圆

发表于 2014-8-7 22:43:49 | 显示全部楼层
mark 收藏了嘻嘻

出0入0汤圆

发表于 2014-8-13 16:10:41 | 显示全部楼层
学习了,亲测十分有效啊···

出0入0汤圆

发表于 2014-8-13 18:52:28 | 显示全部楼层
多谢分享,收藏了

出0入0汤圆

发表于 2014-8-15 10:02:50 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2014-8-20 16:59:38 | 显示全部楼层
真的是好东西

出0入0汤圆

发表于 2014-8-20 18:44:57 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2014-8-26 16:37:02 | 显示全部楼层
请教楼主,各频率的功率值以及总的功率值怎么求啊?本人小白

出5入10汤圆

发表于 2014-8-26 16:51:13 | 显示全部楼层
必须mark一下!~

出0入0汤圆

发表于 2014-12-4 18:15:40 | 显示全部楼层
谢谢楼主,好深奥的算法,一时还看不懂。

出0入0汤圆

发表于 2014-12-5 00:41:41 来自手机 | 显示全部楼层
很好的帖子,先记号慢慢看

出0入0汤圆

发表于 2014-12-5 08:30:16 | 显示全部楼层
FFT,算法...谢谢楼主分享~

出0入0汤圆

发表于 2014-12-5 08:34:20 | 显示全部楼层
不错,学习了。

出0入0汤圆

发表于 2014-12-5 08:46:34 来自手机 | 显示全部楼层
竟然看懂了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 09:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表