安安富富莱莱电电子子UUMM440033日日版版本本::11..00第第11页页共共2211页页安安富富莱莱SSTTMM3322--VV55开开发发板板数数字字信信号号处处理理教教程程文档版本:V1.0安安富富莱莱电电子子日日版版本本::11..00第第22页页共共2211页页声声明明本本文文档档的的版版权权归归武武汉汉安安富富莱莱电电子子有有限限公公司司所所有有。。任任何何公公司司或或者者个个人人未未经经许许可可,,不不得得将将本本文文档档用用于于商商业业目目的的。。本本文文档档由由安安富富莱莱电电子子原原创创,,非非我我们们原原创创的的资资料料已已经经在在章章节节的的开开头头进进行行申申明明((特特别别是是FFFFTT部部分分))。。教教程程中中使使用用的的DDSSPP库库是是来来自自AARRMM公公司司。。教教程程参参考考资资料料如如下下::CCoorrtteexx--MM44权权威威指指南南。。数数字字信信号号处处理理理理论论、、算算法法与与实实现现第第二二版版((作作者者::胡胡广广书书))。。信信号号与与系系统统第第二二版版((作作者者::奥奥本本海海姆姆))。。MMaattllaabb的的hheellpp文文档档。。力力科科示示波波器器基基础础应应用用系系列列文文档档。。百百度度百百科科,,wwiikkii百百科科。。网网络络资资源源。。SSTT官官方方相相关关文文档档。。安安富富莱莱电电子子UUMM440033日日版版本本::11..00第第33页页共共2211页页第第3300章章复复数数FFFFTT的的实实现现本章主要讲解复数FFT的浮点和定点Q31,Q15的实现。本章节使用的复数FFT函数来自ARM官方库的TransformFunctions部分30.1复数FFT30.2复数FFT-基2算法30.3复数FFT-基4算法30.4总结3300..11复复数数FFFFTT3300..11..11描描述述当前复数FFT函数支持三种数据类型,分别是浮点,Q31和Q15。这些FFT函数有一个共同的特点,就是用于输入信号的缓冲,在转化结束后用来存储输出结果。这样做的好处是节省了RAM空间,不需要为输入和输出结果分别设置缓存。由于是复数FFT,所以输入和输出缓存要存储实部和虚部。存储顺序如下:{real[0],imag[0],real[1],imag[1],………………},在使用中切记不要搞错。3300..11..22浮浮点点浮点复数FFT使用了一个混合基数算法,通过多个基8与单个基2或基4算法实现。根据需要,该算法支持的长度[16,32,64,...,4096]和每个长度使用不同的旋转因子表。浮点复数FFT使用了标准的FFT定义,FFT正变换的输出结果会被放大fftLen倍数,计算FFT逆变换的时候会缩小到1/fftLen。这样就与教科书中的定义一致了。定义好的旋转因子和位反转表已经在头文件arm_const_structs.h中定义好了,调用浮点FFT函数arm_cfft_f32时,包含相应的头文件即可。比如:arm_cfft_f32(arm_cfft_sR_f32_len64,pSrc,1,1)上式就是计算一个64点的FFT逆变换包括位反转。数据结构arm_cfft_sR_f32_len64可以认为是常数,计算的过程中是不能修改的。同样是这种数据结构还能用于混合基的FFT正变换和逆变换。早期发布的浮点复数FFT函数版本包含基2和基4两种方法实现的,但是不推荐大家再使用了。现在全部用arm_cfft_f32代替了。安安富富莱莱电电子子UUMM440033日日版版本本::11..00第第44页页共共2211页页3300..11..33定定点点QQ3311和和QQ1155定点库提供了基2和基4两种算法,基2算法支持的数据长度[16,32,64,...,4096],基4算法支持的数据长度[16,32,64,...,4096]。一般情况下,建议使用基4算法,基4算法比基2算法执行速度要快一些。为了防止计算结果溢出,定点FFT每个蝶形运算的结果都要做放缩处理。对于基2算法,每次蝶形运算的结果要做0.5倍的放缩。对于基4算法,每次蝶形运算的结果要做0.25倍的放缩。FFT逆变换也要做相同的处理。相对于标准教科书式的FFT定义,定点FFT的计算结果放缩了1/fftLen(数据)倍。定点FFT的逆变也要做放缩处理,但是跟教科书式的FFT定义是相符的。每个FFT变换都需要一个单独的结构体,但结构体中的旋转因子和位反转表可以被重新使用。每个数据类型都有一个相关的初始化函数,初始化函数主要完成如下操作:初始化结构体成员。初始化旋转因子和位反转表指针。使用初始化函数是可选的。尽管如此,如果使用了初始化函数,那么结构体不能放在constdata段,如果要放在constdata段,应当按照如下方法进行初始化:*arm_cfft_radix2_instance_q31S={fftLen,ifftFlag,bitReverseFlag,pTwiddle,pBitRevTable,twidCoefModifier,bitRevFactor};*arm_cfft_radix2_instance_q15S={fftLen,ifftFlag,bitReverseFlag,pTwiddle,pBitRevTable,twidCoefModifier,bitRevFactor};*arm_cfft_radix4_instance_q31S={fftLen,ifftFlag,bitReverseFlag,pTwiddle,pBitRevTable,twidCoefModifier,bitRevFactor};*arm_cfft_radix4_instance_q15S={fftLen,ifftFlag,bitReverseFlag,pTwiddle,pBitRevTable,twidCoefModifier,bitRevFactor};*arm_cfft_instance_f32S={fftLen,pTwiddle,pBitRevTable,bitRevLength};Q15和Q31FFT使用了一个比较大的旋转因数和位反转表。这个表定义了一个最大长度的变换,表的子集可以用于短的变化。3300..11..44aarrmm__ccfffftt__ff3322函数定义如下:voidarm_cfft_f32(constarm_cfft_instance_f32*S,float32_t*p1,uint8_tifftFlag,uint8_tbitReverseFlag)参数定义:[in]*Spointstoaninstanceofthefloating-pointCFFTstructure.[in,out]*p1pointstothecomplexdatabufferofsizecode2*fftLen/code.Processingoccursin-place.[in]ifftFlagflagthatselectsforward(ifftFlag=0)orinverse(ifftFlag=1)transform.[in]bitReverseFlagflagthatenables(bitReverseFlag=1)ordisables(bitReverseFlag=0)bit安安富富莱莱电电子子UUMM440033日日版版本本::11..00第第55页页共共2211页页reversalofoutput.注意事项:结构constarm_cfft_instance_f32的定义如下(在文件arm_math.h文件):typedefstruct{uint16_tfftLen;constfloat32_t*pTwiddle;constuint16_t*pBitRevTable;uint16_tbitRevLength;}arm_cfft_instance_f32;下面通过在开发板上运行这个函数并计算幅频相应,然后再与Matlab计算的结果做对比。#defineTEST_LENGTH_SAMPLES2048/*输入和输出缓冲*/staticfloat32_ttestOutput[TEST_LENGTH_SAMPLES/2];staticfloat32_ttestInput_f32_10khz[TEST_LENGTH_SAMPLES];/*变量*/uint32_tfftSize=1024;uint32_tifftFlag=0;uint32_tdoBitReverse=1;/***********************************************************************************************************函数名:arm_cfft_f32_app*功能说明:调用函数arm_cfft_f32_app计算幅频。*形参:无*返回值:无**********************************************************************************************************/voidarm_cfft_f32_app(void){uint16_ti;/*按照实部,虚部,实部,虚部.....的顺序存储数据*/for(i=0;i1024;i++){/*虚部全部置零*/testInput_f32_10khz[i*2+1]=0;/*50Hz正弦波,采样率1KHz,作为实部*/testInput_f32_10khz[i*2]=arm_sin_f32(2*3.1415926f*50*i/1000);}/*CFFT变换*/arm_cfft_f32(&arm_cfft_sR_f32_len1024,testInput_f32_10khz,ifftFlag,doBitReverse);/*求解模值*/arm_cmplx_mag_f32(testInput_f32_10khz,testOutput,fftSize);/*串口打印求解的模值*/for(i=0;i1024;i++){printf(%f\r\n,testOutput[i]);}安安富富莱莱电电子子UUMM440033日日版版本本::11..00第第66页页共共2211页页}运行如上函数可以通过串口打印出计算的模值,下面我们就通过Matlab计算的模值跟arm_cfft_f32计算的模值做对比。对比前需要先将串口打印出的数据加载到Matlab中,并给这个数组起名sampledata,加载方法在前面的