前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT。在网上找了很多这方面的资料做实验并进行比较,最终选择了使用STM32提供的DSP库这种方法。 本文将以一个实例来介绍如何使用STM32提供的DSP库函数进行FFT。 6 v" |, E/ {' O5 p* J
1.FFT运算效率 使用STM32官方提供的DSP库进行FFT,虽然在使用上有些不灵活(因为它是基4的FFT,所以FFT的点数必须是4^n),但其执行效率确实非常高效,看图1所示的FFT运算效率测试数据便可见一斑。该数据来自STM32 DSP库使用文档。 图1 FFT运算效率测试数据 由图1可见,在STM32F10x系列处理器上,如果使用72M的系统主频,进行64点的FFT运算,仅仅需要0.078ms而已。如果是进行1024点的FFT运算,也才需要2.138ms。 : {$ H% @, f+ \/ w* ~7 p
2.如何使用STM32提供的DSP库函数 2.1下载STM32的DSP库 2.2添加DSP库到自己的工程项目中 下载得到STM32的DSP库之后,就可以将其添加到自己的工程项目中了。 其中,inc文件夹下的stm32_dsp.h和table_fft.h两个文件是必须添加的。stm32_dsp.h是STM32的DSP库的头文件。 src文件夹下的文件可以有选择的添加(用到那个添加那个即可)。因为我只用到了256点的FFT,所以这里我只添加了cr4_fft_256_stm32.s文件。添加完成后的项目框架如图2所示。 图2 项目框架 2.3模拟采样数据 根据采样定理,采样频率必须是被采样信号最高频率的2倍。这里,我要采集的是音频信号,音频信号的频率范围是20Hz到20KHz,所以我使用的采用频率是44800Hz。那么在进行256点FFT时,将得到44800Hz / 256 = 175Hz的频率分辨率。 为了验证FFT运算结果的正确性,这里我模拟了一组采样数据,并将该采样数据存放到了long类型的lBufInArray数组中,且该数组中每个元素的高16位存储采样数据的实部,低16位存储采样数据的虚部(总是为0)。 为什么要这样做呢?是因为后面要调用STM32的DSP库函数,需要传入的参数规定了必须是这样的数据格式。 下面是具体的实现代码: - /******************************************************************
+ j. I+ i8 g5 A - 函数名称:InitBufInArray()
/ w: c7 z3 D. |8 {/ P2 s! o - 函数功能:模拟采样数据,采样数据中包含3种频率正弦波(350Hz,8400Hz,18725Hz)
% t; Z, \1 y' V+ l3 k1 J" k' @ - 参数说明:
( s, @% O, f" s - 备 注:在lBufInArray数组中,每个数据的高16位存储采样数据的实部,
. b% `/ n! C0 I9 P9 ?/ P - 低16位存储采样数据的虚部(总是为0)1 ~6 h* L6 \) k, P3 U' `6 R) {# X
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)2 _$ k# Y6 W' F+ e9 L
- *******************************************************************/
% X2 N; c/ h3 R* N. V - void InitBufInArray()
0 Q( x7 y: x3 L- q6 S - {
x, J- A$ z2 G9 ^8 i& L1 b7 A - unsigned short i;
( q; Q- ~2 |4 `4 x8 Q) q7 ~7 j - float fx;
! i( S! l' Z' D0 Q) M( C2 N0 W - for(i=0; i<NPT; i++)0 V( I4 L. g9 k7 j! t. p
- {% j# n6 G+ D) o8 s b" J9 y- T
- fx = 1500 * sin(PI2 * i * 350.0 / Fs) +, ~+ s& I N# A0 s6 l6 `+ q9 m! z
- 2700 * sin(PI2 * i * 8400.0 / Fs) +$ q2 p) b2 Z& V+ h/ P3 A3 o
- 4000 * sin(PI2 * i * 18725.0 / Fs);0 O1 A- ^( p1 f& d
- lBufInArray[i] = ((signed short)fx) << 16;6 A( p& F/ ?) f! Q# v( T- _
- }8 \. @0 y+ r% e- W. V
- }
复制代码
. s! p V, o! s- H 其中,NPT是采样点数256,PI2是2π(即6.28318530717959),Fs是采样频率44800。可以看到采样数据中包含了3种频率的正弦波,分别为350Hz,8400Hz和18725Hz。 * {1 M, I8 Z8 B5 `7 _1 ]! u
2.4调用DSP库函数进行FFT 进行256点的FFT,只需要调用STM32 DSP库函数中的cr4_fft_256_stm32()函数即可。该函数的原型为: void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); 其中,参数pssOUT表示FFT输出数组指针,参数pssIN表示要进行FFT运算的输入数组指针,参数Nbin表示了点数。至于该函数的具体实现,因为是用汇编语言编写的,我也不懂,这里就不妄谈了。 下面是具体的调用实例: cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT); 其中,参数lBufOutArray同样是一个long类型的数组,参数lBufInArray就是存放模拟采样数据的采样数组,NPT为采样点数256。 调用该函数之后,在lBufOutArray数组中就存放了进行FFT运算之后的结果数据。该数组中每个元素的数据格式为;高16位存储虚部,低16位存储实部。
4 W( }5 f" P- k+ t
2.5计算各次谐波幅值 得到FFT运算之后的结果数据之后,就可以计算各次谐波的幅值了。 下面是具体的实现代码: - /******************************************************************
( @3 u- L) O0 L, t - 函数名称:GetPowerMag()- [* |8 B/ U. V# p9 B. f2 E
- 函数功能:计算各次谐波幅值
' _3 _+ |4 ~& c% \8 v4 D# K - 参数说明:& s1 t. z& Q4 m" f2 b3 |) o0 h
- 备 注:先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)
8 ^( R2 {0 z5 v8 ?, ^% `' x0 m - 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)0 e0 k# Z2 \* o' G9 U) p& h v7 a
- *******************************************************************/4 R: C( r" S; i' ?( j
- void GetPowerMag()
, T3 c8 [7 f" j) G - {8 C7 [: N2 d7 C) T0 e/ A
- signed short lX,lY;* P! p! j2 o+ I5 L
- float X,Y,Mag;: G, T2 u# f1 J! B' r) q
- unsigned short i;
* Y' v; ^2 C- H! X/ }. b - for(i=0; i<NPT/2; i++)8 |8 t: a6 I& x+ [" v- |' v# r. T0 s
- {& |; U1 [$ P0 y
- lX = (lBufOutArray[i] << 16) >> 16;
/ [8 I6 }! C& g - lY = (lBufOutArray[i] >> 16);
6 A& s+ m: i/ f* |# M - X = NPT * ((float)lX) / 32768;6 d' O: b& W, s- ^9 x, c7 T
- Y = NPT * ((float)lY) / 32768;( ^$ I3 y# ]- k
- Mag = sqrt(X * X + Y * Y) / NPT;5 @4 a; K" Q5 s
- if(i == 0)
0 k4 J, d& d" B/ Y0 z8 O5 i - lBufMagArray[i] = (unsigned long)(Mag * 32768);
5 e' x1 m6 f3 Q* ^# f l( B, R - else$ j$ {* Z% |3 [
- lBufMagArray[i] = (unsigned long)(Mag * 65536);
6 G n$ b7 b5 v: v - }
, X! K3 `9 _; w. ?" a! X - }
复制代码
8 r# U9 ^9 X3 F; X8 j+ _$ g3 O 其中,数组lBufMagArray存储了各次谐波的幅值。 2.6实验结果 通过串口,我们可以将lBufMagArray数组中各次谐波的幅值(即各个频率分量的幅值)输出打印出来,具体实验数据如下所示: - i, P, Mag, X, Y
. P3 h3 g( f+ C% ^6 j1 g/ f - 0, 0, 4, 0, -42 N# z: g2 U% H6 @ r
- 1, 175, 14, -6, -4
; d* {5 J/ U% P+ Y5 B6 N - 2, 350, 1492, 746, -3
) S: M/ o- s, T0 L8 q - 3, 525, 11, -5, -3
6 t/ B2 V8 |' r# ~, L7 r - 4, 700, 8, -3, -3% l* w. ~$ J1 H2 t; J* Y* k5 {
- 5, 875, 8, -4, -2
+ X8 Z4 D0 H. Y( w( [ t - 6, 1050, 6, -3, 0. @9 ~: `' G9 G, k" \) v$ M
- 7, 1225, 6, -3, 0. n* K! |# a3 @# x, b
- 8, 1400, 8, -4, -2; M( L1 f- F8 }# }% U: x4 Q: l) k
- 9, 1575, 8, -4, 0& |: P& B, [# D8 p" j: U8 S
- 10, 1750, 4, -2, 0
2 L7 r+ H7 \# `- w# y - 11, 1925, 8, -4, -1( B% E+ ]; t1 G0 X0 @% y( B8 z! u
- 12, 2100, 6, -3, 0
( }/ G1 _- e$ I7 @6 X7 V$ f3 H. ` - 13, 2275, 5, -2, -2! {2 l1 l2 }( q
- 14, 2450, 6, -3, -1
o" v& g$ c# R2 ]" q0 Q3 A8 S# F7 `$ v - 15, 2625, 8, -3, -3
5 f) h5 @& l6 G" B7 H) ]* t - 16, 2800, 4, -2, 0( h0 f- O9 i1 k i
- 17, 2975, 6, -3, -1
# \( K2 U n9 o" l' }2 I% E - 18, 3150, 6, -3, 0
# ?+ }' e) c! _ I1 g! W/ t - 19, 3325, 6, -3, 0
3 v" J2 @$ w. G - 20, 3500, 2, -1, 0& C6 [9 |; n6 j% g2 `8 G, ^& x
- 21, 3675, 4, -2, 0
2 Q) a8 P# X k% e - 22, 3850, 4, -2, 0
- N& ~/ [/ O+ v - 23, 4025, 4, -2, 0/ K% z" X$ j6 W$ f
- 24, 4200, 6, -3, 0
- X% t+ |; q* l3 n - 25, 4375, 6, -3, 0
6 ?% B+ l* s! N7 e0 Z - 26, 4550, 4, -2, 0
8 G( P4 p/ z+ ^6 d |. n - 27, 4725, 6, -3, 0
. I' G+ [2 s7 k" T/ _ - 28, 4900, 2, -1, 0
$ k6 k9 a7 G& y+ S - 29, 5075, 4, -2, -1/ k- R* O' u' Z9 h; ?
- 30, 5250, 4, -2, 0
' t' ?0 C" _: H0 j* \, u& S - 31, 5425, 2, -1, 01 A7 |& k C3 q" ~
- 32, 5600, 4, -2, -1" z m( C- M6 w1 g, a# V
- 33, 5775, 6, -3, -1" L3 L6 g* R$ _/ \' u
- 34, 5950, 2, -1, -1
" g0 [6 l4 _) F. z - 35, 6125, 6, -3, -1
4 C! G/ Q& j& M' U - 36, 6300, 2, -1, 0; u7 _6 r: m/ C& ]2 a4 u/ B( r u
- 37, 6475, 6, -3, 0& W6 c$ w h. Y7 J0 J7 ]
- 38, 6650, 4, -2, 0' U/ F$ U/ M6 _0 r% u7 b
- 39, 6825, 4, -2, -1
) h# ~5 v ]1 m: n4 w/ g% f B2 ~* ? - 40, 7000, 2, -1, 0
8 O4 w- f! @( M' u - 41, 7175, 6, -3, 0% L, l/ y9 C& p' D+ t- U) |
- 42, 7350, 2, -1, 0# R0 F3 [- S8 j3 i; f6 v0 q: L
- 43, 7525, 2, -1, 0& Q4 I x4 N% T" A$ s
- 44, 7700, 2, -1, 0
7 m) |* ?6 N8 j& I5 a% v. g) j - 45, 7875, 2, -1, 0! x. d) N2 {/ J, j3 {! z0 l. r
- 46, 8050, 4, -2, 0
2 A0 G- A$ w" c5 V0 J: r - 47, 8225, 2, -1, 0
. o2 x" Y& Z) U% D - 48, 8400, 2696, 1348, 0
' A( m: C/ W( U6 s. ^4 |6 _7 m - 49, 8575, 2, -1, -1& t: f# C! a, ~8 h! j: q5 s% d
- 50, 8750, 0, 0, 0
- v( }, y2 V, O9 ? - 51, 8925, 4, -2, -1
* ^4 z( u4 Z+ k" L) C% t T - 52, 9100, 2, 0, -1* p8 [) R5 h' U( }) r
- 53, 9275, 0, 0, 0, V. c! [( \% D) w; Q, g) `
- 54, 9450, 2, -1, -1
! {% E j) O i/ ?- P8 N7 z4 v - 55, 9625, 2, -1, 0 s$ F( m9 ^* O1 X7 L
- 56, 9800, 2, -1, 0
5 M, b# A+ {- h4 H - 57, 9975, 2, -1, -1
, o O* ]0 j8 h7 J - 58, 10150, 2, -1, -1+ C+ m; }% f! P J
- 59, 10325, 2, -1, 0
8 b# V& }/ g& k0 K6 d8 @ - 60, 10500, 0, 0, 0
2 c* V. `8 g& f8 r - 61, 10675, 2, -1, 0: q0 \3 f# f$ ~4 `
- 62, 10850, 4, -2, -1
) _) T7 u7 i7 `6 J3 K9 S; s9 T - 63, 11025, 2, -1, -1: I. b) G4 h9 ~7 U$ s
- 64, 11200, 0, 0, 0
' d9 D3 I/ _" z6 |. Q - 65, 11375, 2, -1, 0
+ L L8 a( W- S+ d: p5 t9 R; M" M - 66, 11550, 0, 0, 0
% {7 }* W$ Z" l5 R: p' B* L$ @ - 67, 11725, 2, -1, -1
( ^0 M6 P# E. m% M3 {( h - 68, 11900, 2, -1, -1
6 n$ S8 }2 t) e - 69, 12075, 2, -1, 1) _3 M( M0 E+ n( a# n+ F
- 70, 12250, 2, -1, 1
* @- u/ | T+ } - 71, 12425, 4, -2, 1
' D C6 V! \' V; a - 72, 12600, 4, -2, -1
8 r2 U+ y! f4 N( [ - 73, 12775, 2, -1, 1
; d# m U9 o- l% Z" v% t7 x - 74, 12950, 0, 0, 0
" D' j1 \8 G7 S m' y2 Z$ s - 75, 13125, 4, -2, 02 X2 C( C! P9 Z9 Q$ e7 x. F
- 76, 13300, 4, -2, 0) Q* H1 O; M) \9 A! r
- 77, 13475, 2, -1, 0% m( m0 ]) l9 z
- 78, 13650, 2, -1, 04 y& N5 O4 A5 a6 H# L- c* n: `& \
- 79, 13825, 4, -2, -1
7 Y: _: X! A- W* `0 h - 80, 14000, 2, -1, 0
- T- W$ w7 N2 c: _ - 81, 14175, 4, -2, 0' E5 T1 h& }) W6 I
- 82, 14350, 2, -1, 1( N" f+ @9 S7 [- {0 V
- 83, 14525, 4, -2, 1' z _$ S: \" Z/ ^
- 84, 14700, 4, -2, 1$ i+ G, J; C, T* j& k0 h
- 85, 14875, 2, -1, 1
! w- z3 P& O. H8 b6 f9 ~0 m$ ?0 { - 86, 15050, 4, -2, 0
; I6 B. L3 P3 |! o - 87, 15225, 2, -1, 0( _: e! y/ u6 w4 k( p
- 88, 15400, 4, -2, 19 C4 W4 F% Z* ^' x+ t. }. G( S
- 89, 15575, 4, -2, 17 \* \& C& R- p- H; z
- 90, 15750, 2, -1, 0
9 G& n# A, T0 d& \ - 91, 15925, 2, -1, 16 Z# ~ [5 o/ D9 Y% A5 p2 p1 [
- 92, 16100, 2, -1, 1' ^ ` O9 J* s: f5 y- a* Q8 J5 {
- 93, 16275, 2, -1, 1
- B" \1 p" V. H/ H, N# G - 94, 16450, 4, -2, 1" Z; c2 _4 ?% k- P8 T2 a& h
- 95, 16625, 2, -1, 1
' q0 b, Q! o1 [) `# j- m5 y. L - 96, 16800, 2, -1, -1
' [/ l$ `$ m" Z6 L, T - 97, 16975, 4, -2, 0& |. {, {+ W/ @( w2 W! L
- 98, 17150, 2, -1, 0: x, F5 J0 L' s
- 99, 17325, 4, -2, 0
2 D3 R' W) v/ z5 x5 N) { - 100, 17500, 4, -2, 1
6 S/ z8 v3 n2 K- }- @+ Q1 G - 101, 17675, 4, -2, 0
[- W/ X" H# U' z - 102, 17850, 4, -2, 1
( s" K6 k: X( v9 t3 v+ y - 103, 18025, 4, -2, -1+ d4 e: d; }9 c# F9 G
- 104, 18200, 2, -1, 1& _! n1 L% t8 S. k% U' o$ D
- 105, 18375, 4, -2, 07 S+ K% L. {# c& m0 Y
- 106, 18550, 2, -1, 1
1 N0 n; X9 k8 i& j8 \) L - 107, 18725, 3996, 1998, 1
- e+ l7 u- N/ l( G) q& T& V - 108, 18900, 2, -1, 0
% \6 `8 R& C1 @) C - 109, 19075, 2, -1, 1
, \4 u2 a2 t' A9 k- N1 T2 u3 c - 110, 19250, 4, -2, 1
) h' w- V& ~: [, r0 m8 Q - 111, 19425, 4, -2, 1+ y4 j2 K6 J& _3 r2 G4 A) G9 g
- 112, 19600, 2, 0, 1
+ X- P8 t: P+ L) Q3 |% B. ^! Y - 113, 19775, 2, -1, 08 c( d9 r% u, I/ z% `3 V" E$ u
- 114, 19950, 0, 0, 0; T* x3 J; Y& E5 N. Q7 s( d9 K
- 115, 20125, 4, -2, 1
4 J' [' O: n5 {+ m7 F6 H - 116, 20300, 2, 0, 1
/ d" W9 |# H2 V% O- I6 T' G8 ~ - 117, 20475, 2, 0, 1
: ^0 O9 A/ s- o' @) I2 Q - 118, 20650, 2, -1, 11 L2 n; j# w9 q; y. a
- 119, 20825, 2, -1, 12 c5 n4 R. [ g1 [
- 120, 21000, 2, -1, 1. L+ u9 P( R& o& ^9 m X% O9 X
- 121, 21175, 2, -1, 0
; K" x/ g5 c8 X5 T* d/ F3 j - 122, 21350, 2, 0, 10 \; o0 F; a; Q' ]0 u( R; R
- 123, 21525, 2, -1, 0
2 f, g) ?3 M4 b3 W' m$ \ - 124, 21700, 0, 0, 0, T5 A4 l- D( V) X0 H
- 125, 21875, 2, -1, 1, C8 B7 [1 w, N1 t* c. m! G2 F$ n& ?
- 126, 22050, 2, -1, 19 W9 K3 T% Y3 h l: A
- 127, 22225, 2, 0, 1
复制代码 , J4 r- I$ }$ d2 ?6 T2 |
在以上的实验数据中,我们分别打印出来了点数、频率、幅值、实部、虚部信息。 由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1492、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。 ; w( b( w+ f# h/ A) d* s. z6 J' X
|