|
前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT。在网上找了很多这方面的资料做实验并进行比较,最终选择了使用STM32提供的DSP库这种方法。 本文将以一个实例来介绍如何使用STM32提供的DSP库函数进行FFT。
- Y- I$ h7 f( N5 ^5 a) P& ]* ~- C. q% r1.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。
! w7 D" [" R0 j# W& Z- |0 r2.如何使用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库函数,需要传入的参数规定了必须是这样的数据格式。 下面是具体的实现代码: - /******************************************************************: Q0 b- u, L7 C5 o0 O/ t, X! h
- 函数名称:InitBufInArray(): W( G6 }6 Z" {+ l1 n5 S- {
- 函数功能:模拟采样数据,采样数据中包含3种频率正弦波(350Hz,8400Hz,18725Hz)
, f: T7 P/ y2 n, b" b/ W( a - 参数说明:
" p$ P- q# b. u! ^( z - 备 注:在lBufInArray数组中,每个数据的高16位存储采样数据的实部,
; w* E3 u3 q4 ? - 低16位存储采样数据的虚部(总是为0)
& x6 k' c) {/ ]$ E- ^/ M. J - 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)
0 Y4 h2 W0 Z7 ?0 p2 o - *******************************************************************/
" L! n) i- [% E/ i4 [ - void InitBufInArray()4 c) V+ {0 D+ y$ ~0 C" d3 S
- {
( k& C+ |/ m6 d$ n: m' h/ V, l - unsigned short i;6 M3 p* O6 t2 G9 Z3 Z; g3 ^# f0 O
- float fx;+ X- f* X" c) S
- for(i=0; i<NPT; i++)! J4 }" A" z. L3 i
- {2 p) H# W! V& m: X* q/ e1 C
- fx = 1500 * sin(PI2 * i * 350.0 / Fs) +: @9 m; B; z6 u9 o& t) y+ ]
- 2700 * sin(PI2 * i * 8400.0 / Fs) +
* b$ l5 R6 \8 Y6 W y - 4000 * sin(PI2 * i * 18725.0 / Fs);
2 d) ?& u7 Z. V( s' W - lBufInArray[i] = ((signed short)fx) << 16;
0 s' V m$ Y; R2 T4 C. L - }1 ~3 ] y. F! R
- }
复制代码
5 ~1 n) Q/ |- B' G3 p 其中,NPT是采样点数256,PI2是2π(即6.28318530717959),Fs是采样频率44800。可以看到采样数据中包含了3种频率的正弦波,分别为350Hz,8400Hz和18725Hz。
: M! C; z$ m- _) Q2 V
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 L' h9 Z- I+ x& q$ a
2.5计算各次谐波幅值 得到FFT运算之后的结果数据之后,就可以计算各次谐波的幅值了。 下面是具体的实现代码: - /******************************************************************
, {5 E5 _& d7 t - 函数名称:GetPowerMag()8 l# v+ s: R4 m+ D& T, R
- 函数功能:计算各次谐波幅值* p8 X. U& v9 O a! @2 }7 h8 K0 u8 {3 b
- 参数说明:
+ }& L+ c1 ?) i - 备 注:先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)" Q; A% s5 l# j5 p1 Z9 _% V
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)
7 l) ?, C6 g. X/ l. P e K0 o c - *******************************************************************/ v6 W2 p; a; O9 l5 I
- void GetPowerMag()) X. z( ]+ `( x- u% K% B" n
- {
, I& f9 W) I+ q8 h% ?7 ^ - signed short lX,lY;0 a$ ^$ ]( Y* y. C; k- L1 H
- float X,Y,Mag;
+ Z$ ]5 s+ h; `4 l% T! T - unsigned short i;
$ y0 k3 M$ t6 p - for(i=0; i<NPT/2; i++); f' b6 Z8 z( ~; q1 V+ h6 U
- {
% i) r! y2 d- m - lX = (lBufOutArray[i] << 16) >> 16;: m' ^ s. ~8 \4 T
- lY = (lBufOutArray[i] >> 16);
Z, y' S' ~, {% a6 n* z - X = NPT * ((float)lX) / 32768;
8 y1 K1 C7 R5 ?- V$ D2 g - Y = NPT * ((float)lY) / 32768;
0 |2 f0 K- e! A. u: Z1 C' U - Mag = sqrt(X * X + Y * Y) / NPT;
, c: T3 I# o9 a2 S; ` - if(i == 0)0 b9 P+ o, Q r
- lBufMagArray[i] = (unsigned long)(Mag * 32768);
4 Z X" b( i7 z; u) p - else3 @0 M" o9 U- \ a, g
- lBufMagArray[i] = (unsigned long)(Mag * 65536);
! h9 l$ h) R( K- f - }* |$ \1 z- m/ a' Q! j& k8 b0 z
- }
复制代码 $ O/ A0 F! C' Z5 ]- V! J
其中,数组lBufMagArray存储了各次谐波的幅值。 2.6实验结果 通过串口,我们可以将lBufMagArray数组中各次谐波的幅值(即各个频率分量的幅值)输出打印出来,具体实验数据如下所示: - i, P, Mag, X, Y/ j9 ?, M1 `' \+ X; o% T
- 0, 0, 4, 0, -4/ l0 s3 j0 N* T9 Q- M# b) Y
- 1, 175, 14, -6, -4
~; P# X: l$ S. w0 O; X/ Y/ I* G/ T - 2, 350, 1492, 746, -3& s/ S8 x; F; b% `9 e/ r
- 3, 525, 11, -5, -3
, y- l! X2 I- C' Z8 M- a - 4, 700, 8, -3, -37 E% K. M: g" y3 S( ?, [3 {
- 5, 875, 8, -4, -2
/ c/ Q U. {; x) u' N - 6, 1050, 6, -3, 0: m7 U" b2 g# k: y% c& U4 F
- 7, 1225, 6, -3, 09 I4 |: m3 |+ H, I
- 8, 1400, 8, -4, -2. Q( X' O7 i5 b; p; S q8 N& W
- 9, 1575, 8, -4, 0
/ w @3 i) i4 a8 R3 |$ x, E - 10, 1750, 4, -2, 0
. @6 L4 W9 d5 h. w" Z+ B - 11, 1925, 8, -4, -10 v+ T2 e# u1 F) t! ]6 n
- 12, 2100, 6, -3, 0
( |4 B; a0 d) F- p3 i" @. _ - 13, 2275, 5, -2, -2
W; M3 K6 {) h' q - 14, 2450, 6, -3, -15 W) |+ ]6 L" v( F
- 15, 2625, 8, -3, -3/ ^, p$ G7 K8 Q
- 16, 2800, 4, -2, 01 G. x6 _( `3 x+ \* _
- 17, 2975, 6, -3, -1
0 B9 T) x& t! f9 `. v - 18, 3150, 6, -3, 0
* `( O# ]0 ^9 A - 19, 3325, 6, -3, 0
0 z7 A% e: I" B& s+ }3 Q; X g6 j - 20, 3500, 2, -1, 0
) G# n" c4 g6 M9 a$ h$ S3 o - 21, 3675, 4, -2, 0( `, g+ n% Z: @4 w% Z/ p2 Z
- 22, 3850, 4, -2, 09 d& q0 O9 P. f( |9 K7 V! H
- 23, 4025, 4, -2, 04 S5 x/ v* [6 I9 R5 D# l$ M
- 24, 4200, 6, -3, 0( R, y i% {% r$ W8 U
- 25, 4375, 6, -3, 0
/ K g( K) \5 { - 26, 4550, 4, -2, 07 w/ K# h% V6 j6 `9 {
- 27, 4725, 6, -3, 05 x) [6 |4 K# r. Z0 R, E) F' u
- 28, 4900, 2, -1, 0
1 `9 L9 V. N9 y# r - 29, 5075, 4, -2, -16 j7 j ^3 \' j$ Q
- 30, 5250, 4, -2, 0
" x! N! S* e0 v - 31, 5425, 2, -1, 0
8 \( K$ L y- z, n8 T - 32, 5600, 4, -2, -1
3 r; ^. k( ?7 C r - 33, 5775, 6, -3, -17 n0 q8 A2 x- W h
- 34, 5950, 2, -1, -1
Q& x& s Y/ h7 D4 M# }2 M! E - 35, 6125, 6, -3, -1
+ v! W0 ?5 ?* ^& N- A' L9 q - 36, 6300, 2, -1, 0
1 d% g3 y+ \0 ?" Y& ~& ~: t - 37, 6475, 6, -3, 0
* }! G* Y) B5 A P J. r - 38, 6650, 4, -2, 0
- F. z7 x, h' q' @) c3 C, D* U - 39, 6825, 4, -2, -1: J" e# N7 P; y5 W! ?, w# i& ]
- 40, 7000, 2, -1, 0
& ]/ @* A4 g! e s0 U4 R - 41, 7175, 6, -3, 0
6 _" r( s/ ` s - 42, 7350, 2, -1, 0
' c) b3 s: d; I8 j: e( u. G - 43, 7525, 2, -1, 0& f! j" w/ u4 J; D! O: t+ o
- 44, 7700, 2, -1, 0
' K' I! f; A; y: R4 ^ - 45, 7875, 2, -1, 0
+ R0 V3 V2 D4 o7 P - 46, 8050, 4, -2, 0
+ F+ U3 k% E7 F& s6 \6 B! p - 47, 8225, 2, -1, 0$ B0 i ?' K/ v( z
- 48, 8400, 2696, 1348, 0
/ d7 |* ?, j8 n6 d - 49, 8575, 2, -1, -13 }/ h! e+ I! j1 p
- 50, 8750, 0, 0, 0
. D$ d; h8 |4 e& {5 r: I - 51, 8925, 4, -2, -1* Q0 @4 @5 a3 u* P4 Q7 G
- 52, 9100, 2, 0, -1
. }0 v2 C4 X) d3 U: ~% y - 53, 9275, 0, 0, 0
4 F/ q+ F# |9 T ~' u9 m" j - 54, 9450, 2, -1, -1
+ X* F, Y: [9 ~ - 55, 9625, 2, -1, 0+ E8 _( i. w% `) _$ l3 V
- 56, 9800, 2, -1, 0% K" w7 x% ~: ? J- z9 L. P7 D
- 57, 9975, 2, -1, -1+ m/ ]$ b, Y4 u9 ]2 O; B" w
- 58, 10150, 2, -1, -18 D6 H* S( l9 Y. X
- 59, 10325, 2, -1, 08 y* A% `0 p1 m' M" [2 r
- 60, 10500, 0, 0, 0
2 [" m3 H5 c1 h+ Z* X0 m8 H - 61, 10675, 2, -1, 0% l. P+ p* o# r3 R
- 62, 10850, 4, -2, -11 }8 Q$ k3 d8 E+ H% w
- 63, 11025, 2, -1, -1, u9 l# L" X% Z* ]6 q
- 64, 11200, 0, 0, 0" o3 D5 {. i5 K+ |) Y1 y. x
- 65, 11375, 2, -1, 0
( y1 a7 {% T; j8 C8 W$ k - 66, 11550, 0, 0, 0
2 O5 Y6 I6 v" o6 T8 V8 W7 ? - 67, 11725, 2, -1, -1
. ], u6 j* H! i* I W7 A - 68, 11900, 2, -1, -1: }# v; w' f2 s4 e. A) Y
- 69, 12075, 2, -1, 1' J0 U. r9 O4 k8 `& c0 w; d% G
- 70, 12250, 2, -1, 1
' T/ m" j# Y+ V5 E! a - 71, 12425, 4, -2, 1
: a: r) Z1 |, E& c, u" T - 72, 12600, 4, -2, -1* U. G3 }" b" l4 i) b/ K, _
- 73, 12775, 2, -1, 1
. { S5 x) `3 H# z) r t - 74, 12950, 0, 0, 0& `: d1 U* N u2 u
- 75, 13125, 4, -2, 01 h [3 j: s) G1 I! D
- 76, 13300, 4, -2, 0$ x/ j9 ]6 e' b0 f2 |
- 77, 13475, 2, -1, 0
4 K1 z6 j: ~( T; F, Y5 t - 78, 13650, 2, -1, 0
/ ]. d% K X, [3 C! B8 D, T - 79, 13825, 4, -2, -1 Z# |0 y. D+ q9 X4 k0 e5 a
- 80, 14000, 2, -1, 02 q8 V! W( v* m
- 81, 14175, 4, -2, 0 G5 R4 D0 P7 S5 h- ^8 n$ H/ S
- 82, 14350, 2, -1, 1
* v0 n7 l4 _8 B+ g - 83, 14525, 4, -2, 1& c9 ?+ ~; m7 p( m
- 84, 14700, 4, -2, 1# S9 W% P5 Y: g7 Q1 V5 Z
- 85, 14875, 2, -1, 15 F# A7 Q1 L5 b& M; ~. J( q. y
- 86, 15050, 4, -2, 0
/ G2 E5 Q/ {9 a' ? - 87, 15225, 2, -1, 02 t. g: ^0 F# P) u! `- g
- 88, 15400, 4, -2, 1
& V3 l& n/ |; b7 t# J$ G - 89, 15575, 4, -2, 1
; V+ }/ r" N. ` - 90, 15750, 2, -1, 0( Z9 u7 z) L+ U. w
- 91, 15925, 2, -1, 1 K3 W2 `+ Z4 V* W2 Q `
- 92, 16100, 2, -1, 1' a, u; ~2 t o3 V/ d- o7 f7 J1 i! H
- 93, 16275, 2, -1, 1
# @( |) H8 E# x - 94, 16450, 4, -2, 10 ]: P/ G& a, j" v. ]
- 95, 16625, 2, -1, 1
+ U) ^* N2 J6 C8 B7 R% }3 f8 { - 96, 16800, 2, -1, -12 P r" `/ s. Z0 v% J
- 97, 16975, 4, -2, 0; i# r. c; x4 k) d0 N
- 98, 17150, 2, -1, 0+ }; j/ B3 L# y" b' \ Q. n
- 99, 17325, 4, -2, 0
/ O+ {7 `" P, o - 100, 17500, 4, -2, 1# I4 Y/ k/ h! ~% R* m0 m5 x \, j
- 101, 17675, 4, -2, 04 U8 g! t) d$ P
- 102, 17850, 4, -2, 11 Q) T& u. F1 i. r2 N
- 103, 18025, 4, -2, -1
8 t3 u K' u, V- x - 104, 18200, 2, -1, 1
' z3 L8 m! h! s7 k$ c - 105, 18375, 4, -2, 0; `' S( I) f; z) Z2 Z) W
- 106, 18550, 2, -1, 1
5 U7 w$ V4 O* B# Z - 107, 18725, 3996, 1998, 19 F' i4 q) D0 V! v% Z
- 108, 18900, 2, -1, 0
* P2 K' C) I+ J" r/ { - 109, 19075, 2, -1, 1
- F# J( a p1 J6 L/ p0 g2 z) H - 110, 19250, 4, -2, 10 ?6 A8 a( K/ k# P% g
- 111, 19425, 4, -2, 1
; u; ~" o3 X6 q F4 K - 112, 19600, 2, 0, 1
8 l d7 u! Y) l - 113, 19775, 2, -1, 0
$ V3 @& @. ?3 [- S$ Z - 114, 19950, 0, 0, 03 C3 ]; i+ E, G) d& Q
- 115, 20125, 4, -2, 1
, Y, r7 E7 T5 V+ ?* \2 }$ E - 116, 20300, 2, 0, 13 h' J6 s* B6 k; |8 G; d' p
- 117, 20475, 2, 0, 15 b: G$ R" [1 V( T/ B
- 118, 20650, 2, -1, 1' K2 l9 T q* ?% B8 [1 h
- 119, 20825, 2, -1, 1$ D! p; E8 f5 D, {! Z
- 120, 21000, 2, -1, 1 [2 @/ ?: ]" [, f5 X8 E
- 121, 21175, 2, -1, 0
- U7 H# h% I& q. P - 122, 21350, 2, 0, 1
# Y: H2 W* J& O4 @, a - 123, 21525, 2, -1, 0
/ h6 `7 i8 |- u/ B - 124, 21700, 0, 0, 0
' \: o5 t, @9 n9 j0 e1 X& s8 u - 125, 21875, 2, -1, 1- z1 E- ^$ g% E( e& G e7 G
- 126, 22050, 2, -1, 1& Q! D- y. L( }2 [ h
- 127, 22225, 2, 0, 1
复制代码 : T2 _/ d8 J. N0 m! j2 E! d
在以上的实验数据中,我们分别打印出来了点数、频率、幅值、实部、虚部信息。 由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1492、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。 8 Z) R a2 n: Q! e6 j. ?& X2 P" l
|