EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
一、快速傅里叶变换! v+ h$ N! \) L5 L0 C
快速傅里叶变换 (fast Fourier transform), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少,特别是被变换的抽样点数N越多,FFT算法计算量的节省就越显著。: k: I0 G" i) X5 g* Q
例程以, ?# [5 `: o N5 ^3 d+ e! q
y=1.6+sin(100πt)+0.3sin(300πt)+0.5sin(700πt)3 _( p* }' I* s: m$ T! `) o
为测试序列,采样率为6400Hz,基波频率为工频50Hz,采样点数为128点, M9 a" l3 x, [
二、CMSIS-DSP
, s+ o2 {; F' {6 b; j+ ~CMSIS-DSP库是 ARM针对各种Arm Cortex-M处理器(例如Cortex-M4,Cortex-M7,Cortex-M33,Cortex-M35和Cortex-M55处理器)优化的丰富的DSP函数的集合。Arm Developer网站包含有关这些处理器的更多信息和支持资源。 CMSIS-DSP在行业中得到了广泛使用,并能够通过各种第三方工具优化C代码生成。 例程所使用的是dsp开发包中的TransformFunctions实数快速傅里叶变换。 % }1 [$ z& `' A2 F0 [
三、关键代码
# N( x1 a& K6 I ?" o# w2 r; e# z. M7 c+ m, r
0 _* }$ C. e9 a4 R: F: \' J/ @* D, ~$ |& I- #include "RFft_test.h"
- arm_rfft_instance_f32 S;
- arm_cfft_radix4_instance_f32 S_CFFT;
- static float32_t pSrc[128]={0.0};
- static float32_t pDst[256]={0.0};
- static float32_t out[64]={0};
- void rfft_test(void)
- {
- u8 i=0,j=0;
- for(i=0;i<128;i++)
- {
- pSrc=1.6f+arm_sin_f32(100*PI*i/6400)+0.3f*arm_sin_f32(300*PI*i/6400)+0.5f*arm_sin_f32(700*PI*i/6400);
- }
- arm_rfft_init_f32(&S,&S_CFFT,128,0,1);
- arm_rfft_f32(&S,pSrc,pDst);
- for(j=0;j<63;j++)
- {
- arm_sqrt_f32(pDst[2*j]*pDst[2*j]+pDst[2*j+1]*pDst[2*j+1],&out[j]);
- if(j==0)
- {
- out[j]=out[j]/128;//直流分量需要特殊处理
- }
- else
- {
- out[j]=out[j]/64;//交流分量
- }
- }
- for(j=0;j<64;j++)
- {
- printf("%f
- ",out[j]);
- }
- }
- ! s2 n5 I5 D6 r: K0 ]- H" a
! o2 ]* d; K R) i s2 |" n
; m) Z5 N3 F2 l+ m% [
0 Z# o" g; j8 w& e由于arm_rfft_f32函数的输出结果分为实部和虚部,在arm_rfft_init_f32函数采用位反转时,输出结果数组为:6 n7 w# {1 s! f4 j8 ?7 k
直流实部、直流虚部、基波实部、基波虚部、2次谐波实部、2次谐波虚部...........
' s2 O% k- D: [" Z4 S7 a2 Parm_rfft_init_f32函数不采用位反转时直接打印输出结果如下:0 t( p) D0 W Q* \
4 w4 a- c7 @: i/ D- q. j
arm_rfft_init_f32函数采用位反转时直接打印输出结果如下:
0 |( {4 S, }" T0 D6 C3 U![]()
5 G) I; G ~' C3 |8 z3 N
8 {- b$ ~5 a6 l/ e+ E* K. A9 m- C
- ?9 E& [7 H3 _8 r- D由于快速傅里叶变换的真实幅值需要特殊处理,需要将各次分量的实部和虚部进行求模运算,即
4 k& y+ {2 T R/ D, H' \采用arm_sqrt_f32函数实现对实部和虚部的平方和开跟,即可获得真实的幅值结果如图(未加直流分量)
- ?/ e- n1 P# i# U/ T. ^( w: l: K0 R![]()
% I. b. E; y( k6 |/ n' Q; `可见与我们设定的测试序列y=sin(100πt)+0.3sin(300πt)+0.5sin(700πt)
& g" }- Q8 j& d0 V- |吻合,基波幅值为1,3次谐波分量幅值为0.3,7次谐波分量幅值为0.57 ^1 n, {: w6 Z! C
$ x: d! U; ?% A: t" D9 g( d为完整测试,加入1.6的直流分量,即测试序列为:
) z; d" p; C7 | ey=1.6+sin(100πt)+0.3sin(300πt)+0.5sin(700πt)' Z& `& j! l( ] z# d8 @6 e7 X! O6 L
测试结果为:; E* r7 e0 m; S; g& I! H7 ?
. ?7 \* H) i7 L5 Y
可以看到直流分量变为了真实的两倍,原因是傅里叶变换幅值还原需要除上采样点数的1半,
9 C- {9 O" n/ O2 y7 p+ c! j+ v变换结果分布在正频和负频,负频在物理上无意义,但其确实含有能量,物理上能量一般与
5 r1 M1 R" B. W% ~: S幅值对应,因此傅里叶变换幅值还原需要除上采样点数的1半,而直流分量既不属于正频也
- p5 S- E) L/ q0 G) k0 v不属于负频,也不区分正直流和负直流,因此直流分量幅值还原需除上采样点数,
" P" @0 k5 T; t处理结果如图:* u5 h' g+ D! R
![]()
( @7 Q; o# T# ?! Q/ Z: s9 p至此完整的实数傅里叶变换完成
* \, x0 l$ O# ?% @, g) w" p四、结果6 H3 |5 c1 Z" U
采用gd32F450ZIT6和CMSIS-DSP开发包对实数傅里叶变换进行测试,并与matlab测试结果进行对比* J! P" \; }, Y7 H8 t: g
实际结果如下:
6 y5 ]. d% W# c$ N: b
7 y! `; v! p1 M4 g9 q1 {! {& U* k8 S8 T! J" r8 T
9 X* ^0 Q9 p+ O1 e! H4 d
# }9 t4 t& ` n: ~
, R1 h( s' d2 Z2 G, A* o2 W
; n' W7 t5 J: S# `7 ]
' p! S- {1 C9 m. [& H
, ^" j2 Y4 O8 R: w1 x4 _9 k |