前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT。在网上找了很多这方面的资料做实验并进行比较,最终选择了使用STM32提供的DSP库这种方法。 本文将以一个实例来介绍如何使用STM32提供的DSP库函数进行FFT。
% x1 h" i+ v" ]- ]% V3 q1.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。 : N" {: N# g3 b2 l/ K
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库函数,需要传入的参数规定了必须是这样的数据格式。 下面是具体的实现代码: - /******************************************************************. v1 V+ N" h( D3 V
- 函数名称:InitBufInArray()
1 v- J2 ] M. F) Y' D8 D4 h0 j - 函数功能:模拟采样数据,采样数据中包含3种频率正弦波(350Hz,8400Hz,18725Hz)2 K1 n" U+ F: V' J* l/ F7 m
- 参数说明:
m+ A! S* m: y& i! v - 备 注:在lBufInArray数组中,每个数据的高16位存储采样数据的实部,
" r/ H/ }; ` s' D" r5 ~3 o - 低16位存储采样数据的虚部(总是为0)8 T4 [& |: e. h
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)
( c' A# i: w1 J2 b - *******************************************************************// M) d" {' ?2 h; d
- void InitBufInArray()
- Y# E3 C# o/ {9 l/ @% Z - {
; i) n9 M9 u H0 }$ T$ i# Y - unsigned short i;
& D. j. U2 y7 @2 l2 M1 S - float fx;1 T2 }; `$ f& N- n7 i
- for(i=0; i<NPT; i++)
! v: H0 m! {7 u7 U. q5 P: q - {1 q: }) r- D0 L
- fx = 1500 * sin(PI2 * i * 350.0 / Fs) +
9 P; i9 o7 E; Q3 y0 f% r0 I - 2700 * sin(PI2 * i * 8400.0 / Fs) + B% J+ f4 l) y' ?: V* H" V# F
- 4000 * sin(PI2 * i * 18725.0 / Fs);5 b% m3 V2 j7 O' d
- lBufInArray[i] = ((signed short)fx) << 16;- U% ]5 n B/ P% s$ x
- }
' k* X$ K! q, V D( M - }
复制代码 7 l$ u7 D2 X5 g; i8 h/ v. f
其中,NPT是采样点数256,PI2是2π(即6.28318530717959),Fs是采样频率44800。可以看到采样数据中包含了3种频率的正弦波,分别为350Hz,8400Hz和18725Hz。 , @0 K5 o5 h, u s7 O; N" n
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位存储实部。
6 F) F' \! \. A1 `% n5 h
2.5计算各次谐波幅值 得到FFT运算之后的结果数据之后,就可以计算各次谐波的幅值了。 下面是具体的实现代码: - /******************************************************************# X$ m3 c4 B9 ~ ]8 G7 S9 B
- 函数名称:GetPowerMag()
5 S _8 l4 X6 s - 函数功能:计算各次谐波幅值
& e7 c) \7 x& M" I0 R! _- G* b - 参数说明:
+ e9 J4 k7 L- d. t' z( ]$ l - 备 注:先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)) G4 N0 m E" e# h6 o `9 H
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/). Z! T! Y( B/ F; |$ D% P) F' t
- *******************************************************************/
' D. n: |0 l# H6 @! l - void GetPowerMag()
' O! \5 H+ x8 u& g$ N& t - {# W; d$ {/ K' C
- signed short lX,lY;" k5 _5 {/ v9 M1 m8 n
- float X,Y,Mag;, Y% X( U: |, }9 R- p
- unsigned short i;6 v0 R' L$ b1 ^4 G. M
- for(i=0; i<NPT/2; i++)% |5 L. C" G( ?; r3 \4 M
- {& G; [. t4 K. B+ D G/ ^: K& @- P
- lX = (lBufOutArray[i] << 16) >> 16;
# I, x9 [) K: _6 }+ n. B' l7 g - lY = (lBufOutArray[i] >> 16);; q |+ S" S4 I; Z! `" X* H
- X = NPT * ((float)lX) / 32768;7 ]1 ?8 f% m2 n0 Z% N$ B
- Y = NPT * ((float)lY) / 32768;. C1 S: G" E5 W# b7 w; m0 z- q/ t
- Mag = sqrt(X * X + Y * Y) / NPT;
: H# j$ C( x d) u - if(i == 0)6 c$ i9 y! ]. \
- lBufMagArray[i] = (unsigned long)(Mag * 32768);3 @/ z7 M! w: [+ b" F3 d6 k
- else2 o+ N9 v) a# W- a2 ?. e
- lBufMagArray[i] = (unsigned long)(Mag * 65536);% ^# l1 t" C; {- |6 s
- }: ]( ]8 X5 B" x7 ?) M5 B
- }
复制代码
% c/ G' e% M. m; V7 v) T1 _0 t4 | 其中,数组lBufMagArray存储了各次谐波的幅值。 2.6实验结果 通过串口,我们可以将lBufMagArray数组中各次谐波的幅值(即各个频率分量的幅值)输出打印出来,具体实验数据如下所示: - i, P, Mag, X, Y8 W" G5 P4 i! g. |
- 0, 0, 4, 0, -4, b" \0 n d! t5 ~; E" f1 \- l$ p
- 1, 175, 14, -6, -4
7 q. A- q: E8 ^7 T! {$ |- e4 y+ I' { - 2, 350, 1492, 746, -3
2 p- c' {- I0 U - 3, 525, 11, -5, -3) s% t" s7 v0 A; F6 B. |5 D7 B
- 4, 700, 8, -3, -30 R' o G1 E9 r) J) t
- 5, 875, 8, -4, -22 W/ R/ D7 z& k! r, n
- 6, 1050, 6, -3, 0
' C8 v% ^$ t+ \4 G7 p; H2 G6 {- a8 F - 7, 1225, 6, -3, 0
* f. S/ S5 @" N, p - 8, 1400, 8, -4, -2* c$ I o5 o& \$ F. l* F
- 9, 1575, 8, -4, 0; |* G/ K, k" l/ n& X" y( s, Q
- 10, 1750, 4, -2, 0# F1 [ A$ o; h9 \9 ?9 L# b
- 11, 1925, 8, -4, -16 b4 S5 |' [+ I- f( n1 o
- 12, 2100, 6, -3, 05 A8 f2 @0 p; s! a1 n0 |3 ?. |
- 13, 2275, 5, -2, -2
{: d! g' _% y/ B- h1 }+ a - 14, 2450, 6, -3, -1- V0 }8 h$ x+ ^8 N
- 15, 2625, 8, -3, -3
6 i4 E, `: Z9 Y0 G9 W" ?7 { - 16, 2800, 4, -2, 0- s7 Y9 e( |' L, q1 R- i' ?
- 17, 2975, 6, -3, -1
# q4 K3 \- ~% i: w7 X+ v - 18, 3150, 6, -3, 0# W% u7 k0 O: ~) T, y, F* ~
- 19, 3325, 6, -3, 0
0 [9 r8 c% [# ?4 ~5 t& z - 20, 3500, 2, -1, 0- C$ H; c J" b4 t( U" G
- 21, 3675, 4, -2, 0$ }9 Y+ ?' _8 d% N3 D+ Q
- 22, 3850, 4, -2, 0: V5 L5 K. g# G
- 23, 4025, 4, -2, 0
6 Z7 Z6 s( ~% N; @0 r8 y - 24, 4200, 6, -3, 0
4 h% R: L; w) ~2 b* i& a - 25, 4375, 6, -3, 0
5 }6 K& u- I) @' a( V) x) q. y - 26, 4550, 4, -2, 0# a9 i! F; K5 e' i# }
- 27, 4725, 6, -3, 0( u3 H6 `7 G0 b1 E9 m( e& j
- 28, 4900, 2, -1, 0
! I: ^* F% d; |1 _: G/ V) m$ I+ ? - 29, 5075, 4, -2, -1
5 ~! b; p* O9 r1 H6 u( b - 30, 5250, 4, -2, 04 u3 ]& E+ c, D' v& ] ]
- 31, 5425, 2, -1, 0
0 R* h( ~ f5 S( k. l" w - 32, 5600, 4, -2, -1
7 A9 e5 Z' _! a) G - 33, 5775, 6, -3, -1
+ z) @( L" N5 u" n - 34, 5950, 2, -1, -1* u6 O2 C+ d; x: j0 o
- 35, 6125, 6, -3, -1- X+ A. }7 o1 t) q3 w
- 36, 6300, 2, -1, 06 y6 D1 J' h5 f# D2 r8 b, J+ h
- 37, 6475, 6, -3, 0
/ X8 z2 |* b" j1 `7 D$ a* p - 38, 6650, 4, -2, 0
! ?. ], u$ {% J0 U7 A - 39, 6825, 4, -2, -1
& n( B4 d- `$ e8 @4 b1 v1 D - 40, 7000, 2, -1, 0- i& ]' [6 L2 L/ _- Y) h- j
- 41, 7175, 6, -3, 03 W- `' M6 z6 y' }: |6 A
- 42, 7350, 2, -1, 0
# }1 `+ b7 ^: f: _3 ?3 p; z# m - 43, 7525, 2, -1, 0
1 j m- M$ `$ Z# A - 44, 7700, 2, -1, 0
* ^+ F& B6 X! Q2 t9 y1 X9 N* _0 W - 45, 7875, 2, -1, 0
( M+ d) Z6 B) r# e3 { ^ - 46, 8050, 4, -2, 0, {4 a/ c5 z/ L
- 47, 8225, 2, -1, 0
$ _. v9 }5 H+ n1 m( B - 48, 8400, 2696, 1348, 0
6 Y. |7 _' Q# n' p( T - 49, 8575, 2, -1, -1
, s3 I4 W9 s. ]& u0 G - 50, 8750, 0, 0, 0
/ |; G4 I" d l. a- T7 F, V/ ~8 P - 51, 8925, 4, -2, -1 |% A4 Z1 ]( i" ^$ ^2 y6 N8 k' G% E
- 52, 9100, 2, 0, -1( H% Z- |( [2 y; ]/ w
- 53, 9275, 0, 0, 0
% [5 |6 t. A* Z* {8 D \+ U - 54, 9450, 2, -1, -1: R! v# E' y `+ n! m3 A
- 55, 9625, 2, -1, 0
1 R; I+ H0 m. n) \) d" G - 56, 9800, 2, -1, 0
' r- f# w/ A- z% H9 e; p, e - 57, 9975, 2, -1, -1
: }- T; J- n0 K4 X& O - 58, 10150, 2, -1, -1- Q" j3 X) o; Y6 ~7 s' {
- 59, 10325, 2, -1, 03 O, p5 B* k/ w
- 60, 10500, 0, 0, 0
( G2 }2 N2 B) D - 61, 10675, 2, -1, 0+ |% R0 g' v b/ E. z6 s+ C
- 62, 10850, 4, -2, -1- @; u; x C2 n, x; d4 [7 w+ ~
- 63, 11025, 2, -1, -16 b7 x( t' i" f+ F0 q
- 64, 11200, 0, 0, 0
: m% n% _3 a0 Q0 c! y! D$ ~; C/ q - 65, 11375, 2, -1, 0
% f7 }$ q6 ]7 O# i/ r. z7 ? - 66, 11550, 0, 0, 0
9 }3 Y' l+ x, _ - 67, 11725, 2, -1, -1& E2 U* v4 m# X, e5 S: ^
- 68, 11900, 2, -1, -1" g( q4 Q( h4 N$ q
- 69, 12075, 2, -1, 15 \; E! s; o& n+ f
- 70, 12250, 2, -1, 1
$ z1 M$ g P9 [% m* b - 71, 12425, 4, -2, 1/ g9 p' \- X% a: K. t$ n
- 72, 12600, 4, -2, -1
" ?: h8 x7 Q- @7 N - 73, 12775, 2, -1, 1
2 p! z) W9 V- B. J - 74, 12950, 0, 0, 0
) m+ N" M) T1 d; d. N# v$ S - 75, 13125, 4, -2, 0; `8 y# w) T1 o* p- ^, U4 L
- 76, 13300, 4, -2, 0
+ i1 s2 z; ~7 h' Q5 \6 k1 R, c - 77, 13475, 2, -1, 0
P* g5 w$ E" G6 k) k - 78, 13650, 2, -1, 09 Q$ d) k. r2 \1 P; X& M+ x8 m) {
- 79, 13825, 4, -2, -1
, A, }# {5 k# \7 ]& | - 80, 14000, 2, -1, 0
1 ?. w- b9 k6 u- F @4 c. ~2 _ - 81, 14175, 4, -2, 0
# t$ b( w. t" i: {+ Y( E/ _ - 82, 14350, 2, -1, 13 z5 E' x: p# ? H8 t
- 83, 14525, 4, -2, 10 x2 T. [3 y& ]
- 84, 14700, 4, -2, 19 M3 G3 ~* V& X5 M
- 85, 14875, 2, -1, 1" a+ |; F' f% O% @% R! v
- 86, 15050, 4, -2, 0$ Z; q) a$ I( K9 w: w
- 87, 15225, 2, -1, 0! V9 a; b4 ], ^# j' x
- 88, 15400, 4, -2, 1) f( h$ Q, }& w! f8 A! ~0 r
- 89, 15575, 4, -2, 1- ], s- p9 v) G0 N
- 90, 15750, 2, -1, 00 n2 e) v' m; Q, S: l) }
- 91, 15925, 2, -1, 1
; L7 q. N8 [1 N6 ~( n2 M$ S - 92, 16100, 2, -1, 1: K( `8 |8 J) ]0 N
- 93, 16275, 2, -1, 1 A; U, ]/ k& g
- 94, 16450, 4, -2, 1
% G& ], A1 C$ w - 95, 16625, 2, -1, 1
5 Q% F/ x- I' U, a - 96, 16800, 2, -1, -1# P# ?7 |- d% b9 ]; Z
- 97, 16975, 4, -2, 0
! ~* W* D/ ^* a& E' r0 v; _6 D6 N - 98, 17150, 2, -1, 0
$ M- y) c% Y7 u. [6 z! k5 |# R - 99, 17325, 4, -2, 0 F4 E# b+ h. G; M3 Z# s+ k
- 100, 17500, 4, -2, 1
! \* y5 s8 m* f" V - 101, 17675, 4, -2, 0
5 r' h. D X! `7 X5 m - 102, 17850, 4, -2, 1
* b* R0 [$ N0 c# | - 103, 18025, 4, -2, -17 Y. e/ J1 Q, i$ U5 e8 f* c) |
- 104, 18200, 2, -1, 1
( K! I9 ^2 G- ^4 q2 S4 a5 ? - 105, 18375, 4, -2, 0
6 v+ f# E4 d: a- o) e k - 106, 18550, 2, -1, 19 F1 W" S9 a0 F" N
- 107, 18725, 3996, 1998, 1
1 y) K( ~6 r! u! F: v# g" B% s - 108, 18900, 2, -1, 0
) p" s8 B. [" ^! U% ` - 109, 19075, 2, -1, 1
# X% w5 a9 g6 z2 l3 V - 110, 19250, 4, -2, 1
' O3 D: B3 y, j! h - 111, 19425, 4, -2, 1( j5 W7 n" T1 }/ \
- 112, 19600, 2, 0, 1% |0 O) T$ j5 i, `9 C
- 113, 19775, 2, -1, 0
5 `% H& ]% V8 s8 ]: d; i0 Q - 114, 19950, 0, 0, 0/ D6 e/ m* x6 D) ]$ f
- 115, 20125, 4, -2, 1
6 G8 S8 u/ _8 \$ t1 {+ {* c - 116, 20300, 2, 0, 1
( c+ S, P( K* j! K - 117, 20475, 2, 0, 1' j$ l0 ]7 H: m$ W
- 118, 20650, 2, -1, 11 N4 j3 W; O d) k: u* S
- 119, 20825, 2, -1, 1
/ @" p; A q& H' ]+ g+ I% t- w - 120, 21000, 2, -1, 1' \ u+ Z* q7 H g( U: t3 Z, w
- 121, 21175, 2, -1, 0
' s& P ~0 f& k* g, ^7 V: S - 122, 21350, 2, 0, 1( R4 ?( ^ e% F% {
- 123, 21525, 2, -1, 0
2 F0 u1 N2 o% \; S - 124, 21700, 0, 0, 07 p6 v7 s& b$ L9 H. H
- 125, 21875, 2, -1, 1
: i2 w4 }5 B, m, K; f" d9 m! S - 126, 22050, 2, -1, 1
; ~- q, R- C7 M, j4 t- C0 j) q - 127, 22225, 2, 0, 1
复制代码
5 F+ a" `8 V n8 E* O7 F 在以上的实验数据中,我们分别打印出来了点数、频率、幅值、实部、虚部信息。 由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1492、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。
9 R# C( _- h! K# M. Y$ H/ r t |