安富莱DSP教程 第32章实数FFT的实现 dsp zoofft

特别说明:完整45期数字信号处理教程,原创高性能示波器代码全开源地址:链接

第32章实数FFT的实现

本章主要讲解实数的浮点和定点Q31,Q15的实现。关于这部分的知识点和函数的计算结果上,官方的文档有一些小错误,在章节中会跟大家详细讲述,还有一个要注意的问题,调用实数FFT函数一定要使用CMSIS-DSPV1.4.4及其以上版本,以前的版本有bug。

本章节使用的复数FFT函数来自ARM官方库的TransformFunctions部分

32.1复数FFT

32.2复数FFT-基2算法

32.3复数FFT-基4算法

32.4总结

32.1实数FFT

32.1.1描述

CMSISDSP库里面包含一个专门用于计算实数序列的FFT库,很多情况下,用户只需要计算实数序列即可。计算同样点数FFT的实数序列要比计算同样点数的虚数序列有速度上的优势。

快速的rfft算法是基于混合基cfft算法实现的。

一个N点的实数序列FFT正变换采用下面的步骤实现:

由上面的框图可以看出,实数序列的FFT是先计算N/2个实数的CFFT,然后再重塑数据进行处理从而获得半个FFT频谱即可(利用了FFT变换后频谱的对称性)。

一个N点的实数序列FFT逆变换采用下面的步骤实现:

实数FFT支持浮点,Q31和Q15三种数据类型。

32.2实数FFT

32.2.1arm_rfft_fast_f32

函数定义如下:

voidarm_rfft_fast_f32(

arm_rfft_fast_instance_f32*S,

float32_t*p,float32_t*pOut,

uint8_tifftFlag)

参数定义:

[in]*Spointstoanarm_rfft_fast_instance_f32structure.

[in]*ppointstotheinputbuffer.

[in]*pOutpointstotheoutputbuffer.

[in]ifftFlagRFFTifflagis0,RIFFTifflagis1

注意事项:

结构arm_rfft_fast_instance_f32的定义如下(在文件arm_math.h文件):

typedefstruct

{

arm_cfft_instance_f32Sint;

uint16_tfftLenRFFT;

float32_t*pTwiddleRFFT;

}arm_rfft_fast_instance_f32;

下面通过在开发板上运行函数arm_rfft_fast_f32和arm_cfft_f32计算幅频响应,然后将相应的频率响应结果在Matlab上面绘制出来。

staticvoidarm_rfft_fast_f32_app(void)

{

uint16_ti;

arm_rfft_fast_instance_f32S;

【安富莱DSP教程】第32章实数FFT的实现 dsp zoofft

fftSize=1024;

ifftFlag=0;

arm_rfft_fast_init_f32(&S,fftSize);

for(i=0;i<1024;i++)

{

testInput_f32_10khz[i]=1.2f*arm_sin_f32(2*3.1415926f*50*i/1000)+1;

}

arm_rfft_fast_f32(&S,testInput_f32_10khz,testOutput_f32_10khz,ifftFlag);

arm_cmplx_mag_f32(testOutput_f32_10khz,testOutput,fftSize);

for(i=0;i

{

printf("%frn",testOutput[i]);

}

printf("****************************分割线***************************************rn");

for(i=0;i<1024;i++)

{

testInput_f32_10khz[i*2+1]=0;

testInput_f32_10khz[i*2]=1.2f*arm_sin_f32(2*3.1415926f*50*i/1000)+1;

}

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;i

{

printf("%frn",testOutput[i]);

}

}

运行如上函数可以通过串口打印出函数arm_rfft_fast_f32和arm_cfft_f32计算的幅频模值,下面通过Matlab绘制波形来对比这两种模值。

对比前需要先将串口打印出的两组数据加载到Matlab中,arm_rfft_fast_f32的计算结果起名signal,arm_cfft_f32的计算结果起名sampledata,加载方法在前面的教程中已经讲解过,这里不做赘述了。Matlab中运行的代码如下:

Fs=1000;%采样率

N=1024;%采样点数

n=0:N-1;%采样序列

f=n*Fs/N;%真实的频率

subplot(3,1,1);

plot(f,signal);%绘制RFFT结果

title('实数FFT');

xlabel('时间');

ylabel('幅值');

subplot(3,1,2);

plot(f,sampledata);�FT结果

title('复数FFT');

xlabel('时间');

ylabel('幅值');

Matlab运行结果如下:

从上面的前512点对比中,我们可以看出两者的计算结果是相符的。这里有一点要特别注意,官方文档中对于函数arm_rfft_fast_f32输出结果的实部,虚部排列顺序说明是错误的。函数arm_rfft_fast_f32的输出结果仍然是实部,虚部,实部,虚部…..依次排列下去。

函数arm_rfft_fast_f32在计算直流分量(也就是频率为0的值)的虚部上是有错误的。关于这点大家可以将实际的实部和虚部输出结果打印出来做对比,但差别很小,基本可以忽略。

32.2.2arm_rfft_q15

函数定义如下:

voidarm_rfft_q15(

constarm_rfft_instance_q15*S,

q15_t*pSrc,

q15_t*pDst)

参数定义:

[in]*SpointstoaninstanceoftheQ15RFFT/RIFFTstructure.

[in]*pSrcpointstotheinputbuffer.

[out]*pDstpointstotheoutputbuffer.

returnnone.

注意事项:

结构arm_rfft_instance_q15的定义如下(在文件arm_math.h文件):

typedefstruct

{

uint32_tfftLenReal;

uint8_tifftFlagR;

uint8_tbitReverseFlagR;

uint32_ttwidCoefRModifier;

q15_t*pTwiddleAReal;

q15_t*pTwiddleBReal;

constarm_cfft_instance_q15*pCfft;

}arm_rfft_instance_q15;

下面通过在开发板上运行函数arm_rfft_q15和arm_cfft_f32计算幅频响应,然后将相应的频率响应结果在Matlab上面绘制出来。

staticvoidarm_rfft_q15_app(void)

{

uint16_ti,j;

arm_rfft_instance_q15S;

fftSize=1024;

ifftFlag=0;

doBitReverse=1;

arm_rfft_init_q15(&S,fftSize,ifftFlag,doBitReverse);

for(i=0;i<1024;i++)

{

j=i%20;

testInput_q15_50hz[i]=arm_sin_q15(1638*j);

}

arm_rfft_q15(&S,testInput_q15_50hz,testOutput_q15_50hz);

for(i=0;i<fftSize;i++)

{

testOutput_f32_10khz[i]=(float32_t)testOutput_q15_50hz[i]/32;

}

arm_cmplx_mag_f32(testOutput_f32_10khz,testOutput,fftSize);

for(i=0;i

{

printf("%frn",testOutput[i]);

}

printf("****************************分割线***************************************rn");

for(i=0;i<1024;i++)

{

j=i%20;

testInput_f32_10khz[i*2]=(float32_t)arm_sin_q15(1638*j)/32768;

testInput_f32_10khz[i*2+1]=0;

}

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;i

{

printf("%frn",testOutput[i]);

}

}

运行如上函数可以通过串口打印出函数arm_rfft_q15和arm_cfft_f32计算的幅频模值,下面通过Matlab绘制波形来对比这两种模值。

对比前需要先将串口打印出的两组数据加载到Matlab中,arm_rfft_q15的计算结果起名signal,arm_cfft_f32的计算结果起名sampledata,加载方法在前面的教程中已经讲解过,这里不做赘述了。Matlab中运行的代码如下:

Fs=1000;%采样率

N=1024;%采样点数

n=0:N-1;%采样序列

f=n*Fs/N;%真实的频率

subplot(3,1,1);

plot(f,signal);%绘制RFFT结果

title('实数FFT');

xlabel('时间');

ylabel('幅值');

subplot(3,1,2);

plot(f,sampledata);�FT结果

title('复数FFT');

xlabel('时间');

ylabel('幅值');

Matlab运行结果如下:

从上面的前512点对比中,我们可以看出两者的计算结果是相符的。这里有一点要特别注意,官方文档中对于函数arm_rfft_q31输出结果的实部,虚部排列顺序说明是错误的。函数arm_rfft_q31的输出结果仍然是实部,虚部,实部,虚部…..依次排列下去。

32.2.3arm_rfft_q31

函数定义如下:

voidarm_rfft_q31(

constarm_rfft_instance_q31*S,

q31_t*pSrc,

q31_t*pDst)

参数定义:

[in]*SpointstoaninstanceoftheQ31RFFT/RIFFTstructure.

[in]*pSrcpointstotheinputbuffer.

[out]*pDstpointstotheoutputbuffer.

returnnone.

注意事项:

结构arm_rfft_instance_q31的定义如下(在文件arm_math.h文件):

typedefstruct

{

uint32_tfftLenReal;

uint8_tifftFlagR;

uint8_tbitReverseFlagR;

uint32_ttwidCoefRModifier;

q31_t*pTwiddleAReal;

q31_t*pTwiddleBReal;

constarm_cfft_instance_q31*pCfft;

}arm_rfft_instance_q31;

下面通过在开发板上运行函数arm_rfft_q31和arm_cfft_f32计算幅频响应,然后将相应的频率响应结果在Matlab上面绘制出来。

staticvoidarm_rfft_q31_app(void)

{

uint16_ti,j;

arm_rfft_instance_q31S;

fftSize=1024;

ifftFlag=0;

doBitReverse=1;

arm_rfft_init_q31(&S,fftSize,ifftFlag,doBitReverse);

for(i=0;i<1024;i++)

{

j=i%20;

testInput_q31_50hz[i]=arm_sin_q31(107374182*j);

}

arm_rfft_q31(&S,testInput_q31_50hz,testOutput_q31_50hz);

for(i=0;i<fftSize;i++)

{

testOutput_f32_10khz[i]=(float32_t)testOutput_q31_50hz[i]/2097152;

}

arm_cmplx_mag_f32(testOutput_f32_10khz,testOutput,fftSize);

for(i=0;i

{

printf("%frn",testOutput[i]);

}

printf("****************************分割线***************************************rn");

for(i=0;i<1024;i++)

{

j=i%20;

testInput_f32_10khz[i*2]=(float32_t)arm_sin_q31(107374182*j)/2147483648;

testInput_f32_10khz[i*2+1]=0;

}

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;i

{

printf("%frn",testOutput[i]);

}

}

运行如上函数可以通过串口打印出函数arm_rfft_q15和arm_cfft_f32计算的幅频模值,下面通过Matlab绘制波形来对比这两种模值。

对比前需要先将串口打印出的两组数据加载到Matlab中,arm_rfft_q15的计算结果起名signal,arm_cfft_f32的计算结果起名sampledata,加载方法在前面的教程中已经讲解过,这里不做赘述了。Matlab中运行的代码如下:

Fs=1000;%采样率

N=1024;%采样点数

n=0:N-1;%采样序列

f=n*Fs/N;%真实的频率

subplot(3,1,1);

plot(f,signal);%绘制RFFT结果

title('实数FFT');

xlabel('时间');

ylabel('幅值');

subplot(3,1,2);

plot(f,sampledata);�FT结果

title('复数FFT');

xlabel('时间');

ylabel('幅值');

Matlab运行结果如下:

从上面的前512点对比中,我们可以看出两者的计算结果是相符的。这里有一点要特别注意,官方文档中对于函数arm_rfft_q31输出结果的实部,虚部排列顺序说明是错误的。函数arm_rfft_q31的输出结果仍然是实部,虚部,实部,虚部…..依次排列下去。

32.3总结

使用实数FFT计算的时候要特别的注意本章节提到的几个错误点。

  

爱华网本文地址 » http://www.aihuau.com/a/25101012/143469.html

更多阅读

华为的成功之道 第26节:第2章 π型人的成功之道(1)

系列专题:《做左右逢源的职场达人:π型人》  第2章 π型人的成功之道  1 成功就业的两大工作支柱  ——英特尔格鲁夫的成功之约  “如果你想要成功,就要开辟新的路径,这会比走已知的成功路径更好。”——洛克菲勒  π型人就

声明:《安富莱DSP教程 第32章实数FFT的实现 dsp zoofft》为网友豹纹男子狠潮分享!如侵犯到您的合法权益请联系我们删除