前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT。在网上找了很多这方面的资料做实验并进行比较,最终选择了使用STM32提供的DSP库这种方法。 本文将以一个实例来介绍如何使用STM32提供的DSP库函数进行FFT。
+ i( l* I* |& h. k' Q! c1.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。 . X9 w, t. T. k( h* 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库函数,需要传入的参数规定了必须是这样的数据格式。 下面是具体的实现代码: - /******************************************************************
# m' @: \. U$ J! H - 函数名称:InitBufInArray()( Y3 Y2 |% N, `2 x& x% ^; x r
- 函数功能:模拟采样数据,采样数据中包含3种频率正弦波(350Hz,8400Hz,18725Hz)
# k$ g8 v W ?1 [ - 参数说明:$ U! o6 x: i1 E$ j* b3 V% t5 k# T! N
- 备 注:在lBufInArray数组中,每个数据的高16位存储采样数据的实部,
2 F) D9 D, q: m( F, _% @% F! F - 低16位存储采样数据的虚部(总是为0)" P5 k# S% m4 p
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)3 W; W n+ X, Z+ }5 h0 W" B; v1 z
- *******************************************************************/
+ a5 G' D5 V* a' a7 Z Y2 D - void InitBufInArray()
: A U* | m6 F) x% C. z - {
: s \9 w. a: F6 o# s% | - unsigned short i;
+ ^8 |# o- h5 H0 ^% r9 Y - float fx;
& [% z1 {8 S: j9 h1 _7 k1 Y3 F% p - for(i=0; i<NPT; i++)
# ?" I) e0 S" _+ h" g% e' K - {
3 A8 C3 `0 H# _" ^% Z, g6 D - fx = 1500 * sin(PI2 * i * 350.0 / Fs) + \" k& I- C3 c8 u& Q
- 2700 * sin(PI2 * i * 8400.0 / Fs) +2 f: G! w: F& R1 k) q: M
- 4000 * sin(PI2 * i * 18725.0 / Fs);
) j( J$ J' k1 `0 X - lBufInArray[i] = ((signed short)fx) << 16;
+ H+ X, E6 _- \4 ^ - }
; y5 U' M4 @$ x C" L - }
复制代码 3 Q& [* Y+ w- |1 R a
其中,NPT是采样点数256,PI2是2π(即6.28318530717959),Fs是采样频率44800。可以看到采样数据中包含了3种频率的正弦波,分别为350Hz,8400Hz和18725Hz。 8 R/ A5 m O/ P4 [
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位存储实部。 ( s {1 V0 f( K1 W! b
2.5计算各次谐波幅值 得到FFT运算之后的结果数据之后,就可以计算各次谐波的幅值了。 下面是具体的实现代码: - /******************************************************************( l& M5 V* z# K1 a
- 函数名称:GetPowerMag()
+ o* c& F! ]/ G" ]$ @, t4 j0 ` - 函数功能:计算各次谐波幅值9 ]* d8 C& u8 J) ]
- 参数说明:3 {* ^ p5 w6 k9 [2 Z! e
- 备 注:先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)- Q0 K% \8 Q% u
- 作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)/ L( C z! z/ J" l' T
- *******************************************************************/, _# y+ d$ Y4 s$ ?
- void GetPowerMag()
, Q {( z, A7 ^, f! m5 r - {8 C" G& _" N1 O4 f4 z% o& c
- signed short lX,lY;: k9 c/ g4 O7 U
- float X,Y,Mag;
; d! A) W8 p' R+ e9 F7 d' V6 C - unsigned short i;
. c' E& j" T( \3 q" A/ X) R - for(i=0; i<NPT/2; i++)# ~8 e f; D1 {- u/ k
- {
% n& B5 U: g8 c0 L - lX = (lBufOutArray[i] << 16) >> 16;
# L0 }6 Y8 M0 ] - lY = (lBufOutArray[i] >> 16);
+ e* P/ q0 ], O/ ?/ }$ C; |" F - X = NPT * ((float)lX) / 32768;5 r7 c% q! o0 ^1 C% t$ `
- Y = NPT * ((float)lY) / 32768;
) v6 ^9 o+ B! k% D* s! d; ^ - Mag = sqrt(X * X + Y * Y) / NPT;7 P6 z H6 q3 ?. p9 D
- if(i == 0)
8 {) d0 a$ E" e; Q6 A* S/ o - lBufMagArray[i] = (unsigned long)(Mag * 32768);
$ V' H* O. h5 E# e$ w5 M5 R( w' y - else
" V g" X" d! c. O: g - lBufMagArray[i] = (unsigned long)(Mag * 65536);" F$ m( Z! \1 T# K4 o' U$ ~
- }- o, Y. [# Y) l/ j' R
- }
复制代码 ( P4 q6 R9 B2 I! M
其中,数组lBufMagArray存储了各次谐波的幅值。 2.6实验结果 通过串口,我们可以将lBufMagArray数组中各次谐波的幅值(即各个频率分量的幅值)输出打印出来,具体实验数据如下所示: - i, P, Mag, X, Y
g* X7 i w! n; t4 T! D/ t4 I - 0, 0, 4, 0, -4 |+ q( p' S& v# S& ?3 y
- 1, 175, 14, -6, -4+ E( N: }. q2 }- q3 z, ^: P
- 2, 350, 1492, 746, -3
9 ^( `. g/ T( e - 3, 525, 11, -5, -3
' E9 w. B6 h. W# \1 Z3 l* f" Y - 4, 700, 8, -3, -3
2 V! b0 R& c6 H5 u$ ~- s2 p - 5, 875, 8, -4, -2
6 |6 w: q6 ~ i - 6, 1050, 6, -3, 0
1 q$ V# w9 A/ x- Y4 d7 N$ X - 7, 1225, 6, -3, 0/ u7 _2 V6 q1 ~1 N' H0 {9 a" d8 O
- 8, 1400, 8, -4, -2/ h2 Y5 n; K- s1 R+ @: X8 q0 _
- 9, 1575, 8, -4, 0
( X' }. [4 s( p4 N5 _- v6 [/ ~/ H - 10, 1750, 4, -2, 0; g/ {0 r8 ?/ k: e3 W& n! Y8 g
- 11, 1925, 8, -4, -1% M0 v9 l. t+ h
- 12, 2100, 6, -3, 00 k0 u: G$ F' I" |2 F7 x# X
- 13, 2275, 5, -2, -24 y3 E+ C. S* B D4 n: G
- 14, 2450, 6, -3, -1/ I) a E% k/ N. Y; A
- 15, 2625, 8, -3, -3
- P& Y$ B0 W4 S A4 T - 16, 2800, 4, -2, 0
& q/ a: O; {7 q8 I - 17, 2975, 6, -3, -1
* J' M! _6 O! f - 18, 3150, 6, -3, 0# j, N, @8 [0 l+ {
- 19, 3325, 6, -3, 0, A O+ r8 i. m( Z$ j- |
- 20, 3500, 2, -1, 01 Z5 W w- u* W1 l/ E
- 21, 3675, 4, -2, 0- Y# l+ u6 ~: a g3 O, Q, k; Q% v
- 22, 3850, 4, -2, 02 A h% p4 z/ Q1 w5 p& l
- 23, 4025, 4, -2, 0
2 I9 O" Z# r' c, g - 24, 4200, 6, -3, 04 u! ~( N$ f1 a/ i# o
- 25, 4375, 6, -3, 0
* }# h4 `0 @9 I, }5 d - 26, 4550, 4, -2, 0
( J; W' A8 j- [5 k7 L' p6 e - 27, 4725, 6, -3, 0
( ]4 q( F4 X3 a0 r- I8 W - 28, 4900, 2, -1, 0/ o4 Y) Q! d& v- G
- 29, 5075, 4, -2, -1) ~3 a, t( ^/ H; I
- 30, 5250, 4, -2, 0" a2 @: i5 K1 R8 d& N1 V
- 31, 5425, 2, -1, 0& h2 u3 w. Y1 `8 ?: {; Z) B) k
- 32, 5600, 4, -2, -1
8 s: i8 j: d, k - 33, 5775, 6, -3, -1
0 g% I) U8 [' v5 ]0 E6 W - 34, 5950, 2, -1, -1
I9 w3 [5 E! \) @4 w - 35, 6125, 6, -3, -1
( V# ]( v9 T5 Y/ }! L% U7 m - 36, 6300, 2, -1, 0 Z& Q$ U6 I5 R$ v! v
- 37, 6475, 6, -3, 0
[; e" n0 v' j- I# t! _ - 38, 6650, 4, -2, 0
( [3 q2 W: E2 D2 {0 d; m - 39, 6825, 4, -2, -1
, ]! e- z T! G. c - 40, 7000, 2, -1, 0
" Q: Y1 x3 ~# m5 j3 E2 d, L - 41, 7175, 6, -3, 01 R' c ?/ t7 S9 A. }$ n. r
- 42, 7350, 2, -1, 02 v1 Y h1 j/ e9 m* Z9 a: y/ d
- 43, 7525, 2, -1, 0
) m m' R+ }, Z$ Y } - 44, 7700, 2, -1, 0
, a8 Y7 J% N8 U0 l; L1 z - 45, 7875, 2, -1, 06 j0 x" m7 F8 I# Q* n
- 46, 8050, 4, -2, 0. I) p9 ]8 k+ f% N. M) [( w
- 47, 8225, 2, -1, 03 l9 C- c# M* }1 ]+ G8 f
- 48, 8400, 2696, 1348, 0/ u6 q: j+ q, D$ X
- 49, 8575, 2, -1, -1
7 F& Q9 Z% l1 c5 z4 Z- N- z5 Z - 50, 8750, 0, 0, 0
4 n9 W3 v- p6 x9 T! r% t# Y8 @3 R - 51, 8925, 4, -2, -1
6 |, Q) s1 `4 P; t; d - 52, 9100, 2, 0, -1: w% q2 l7 k. |0 r
- 53, 9275, 0, 0, 0
) a+ o r3 g: h2 t - 54, 9450, 2, -1, -1
2 D7 C* i9 M: ]" G' k+ c - 55, 9625, 2, -1, 0) [# N0 Z$ J9 B6 r% v( R
- 56, 9800, 2, -1, 0
; ^* I: c. u5 \" {9 P# b - 57, 9975, 2, -1, -10 G3 Z% s% a; j6 U a; r
- 58, 10150, 2, -1, -10 R" ?6 Y& Z# K* V; X
- 59, 10325, 2, -1, 0# `. J/ M/ ^% Z& G) R l
- 60, 10500, 0, 0, 0
7 p( P% m$ f- @3 B0 ^ - 61, 10675, 2, -1, 0
5 J7 ? L$ ?" ^% o - 62, 10850, 4, -2, -1: ^0 K8 t6 H% m) G7 v4 k
- 63, 11025, 2, -1, -1# d2 j+ O! V4 ]
- 64, 11200, 0, 0, 09 h6 t( c) p: R
- 65, 11375, 2, -1, 0
: Y+ n, W# ]4 {$ S" G/ G; h$ J - 66, 11550, 0, 0, 09 C& [/ S+ _! u$ h6 {
- 67, 11725, 2, -1, -1
/ @+ F: w! w# Z; w3 }3 S - 68, 11900, 2, -1, -1) T9 m A; k% a
- 69, 12075, 2, -1, 1
% z& j. r5 d$ u; k - 70, 12250, 2, -1, 1
$ P1 Y" O0 s3 [ - 71, 12425, 4, -2, 1. j3 h" @3 ~# I7 P
- 72, 12600, 4, -2, -14 D3 B! g3 u$ n" Y; e' k5 ~
- 73, 12775, 2, -1, 1
/ d2 o6 Z% ]. F, q) k+ ]2 Q - 74, 12950, 0, 0, 0
' b) N/ R( u1 } - 75, 13125, 4, -2, 0
9 _3 i- A2 ^. z% x. f3 L" X - 76, 13300, 4, -2, 0% x: p j: B6 U* o7 K$ u. J1 a& m
- 77, 13475, 2, -1, 0/ n/ N1 j9 W! L3 L
- 78, 13650, 2, -1, 0
' m& a s2 ^& A8 J) \+ t1 I - 79, 13825, 4, -2, -10 n* a3 ]0 Q, |7 M: B: B" G# _
- 80, 14000, 2, -1, 0
0 u! E$ y- Z6 h( E; f' ^ O( U - 81, 14175, 4, -2, 0, U$ j r3 A( Y) d+ }
- 82, 14350, 2, -1, 1
* D" R+ ]( D8 Q) t2 ~; z2 r' l - 83, 14525, 4, -2, 1
' o: e3 \0 y& R! Y9 A - 84, 14700, 4, -2, 1! T" P9 @. Y0 L7 K: N0 B; l; v
- 85, 14875, 2, -1, 1) g1 z5 R/ \+ O2 R2 E- i( G' ^; h
- 86, 15050, 4, -2, 0
" Y. }. z5 M4 L - 87, 15225, 2, -1, 0
) `0 [& A- q& I" W1 L3 u: n - 88, 15400, 4, -2, 11 g# o }0 U! Z1 w7 K3 K
- 89, 15575, 4, -2, 1
- I. C' Q0 r) Q3 w/ D$ o - 90, 15750, 2, -1, 0
, i$ S& O$ b Q+ \4 n/ {8 Z - 91, 15925, 2, -1, 1
3 J2 Y; z# l7 e" R: } - 92, 16100, 2, -1, 1! ?+ j, ?% f& C9 X4 }& s
- 93, 16275, 2, -1, 1
" Q( {1 H6 Q; R% k& r- w& z - 94, 16450, 4, -2, 1
8 y2 u: T( V: m" Y - 95, 16625, 2, -1, 1' L5 |/ w [$ D# M e- t& d3 G
- 96, 16800, 2, -1, -1
8 C" H6 e6 J5 }2 L: d7 P/ L3 d - 97, 16975, 4, -2, 04 q) d$ }5 t8 i8 {( R p Z% H
- 98, 17150, 2, -1, 0# O3 e/ K% c/ a6 J" g
- 99, 17325, 4, -2, 0* f1 R7 T7 `+ h
- 100, 17500, 4, -2, 1
7 t4 Z/ a/ i! u' E9 v* S, [' M - 101, 17675, 4, -2, 0
+ j: Q2 V, I8 I5 `$ c - 102, 17850, 4, -2, 12 `" o% z: B/ N- ]
- 103, 18025, 4, -2, -1
- q9 j& h( d2 Q1 \! ~' ]3 k7 u - 104, 18200, 2, -1, 1
0 @4 L9 _6 \; \% o - 105, 18375, 4, -2, 0
$ l, |" h7 e4 o: w- z* s, n' q, L - 106, 18550, 2, -1, 14 O! v% j0 T/ L% C# Y6 E* \! `0 G
- 107, 18725, 3996, 1998, 1
% ^ q3 n$ V1 `* x - 108, 18900, 2, -1, 0
/ o6 a9 c- q0 b$ `, m- L" ? - 109, 19075, 2, -1, 1
9 ?0 V* S0 `2 {- d$ r4 N6 x( W0 l - 110, 19250, 4, -2, 1
0 g7 J+ Y ~6 | U& F( Q1 ? - 111, 19425, 4, -2, 1$ l$ P) m; M: p3 t8 H& J
- 112, 19600, 2, 0, 1
, K6 u% V# {( e2 q6 S - 113, 19775, 2, -1, 0
R! i7 ^4 _, c+ K% d - 114, 19950, 0, 0, 0
) L6 t$ {# {7 a* W/ J, I' H - 115, 20125, 4, -2, 1 l8 x3 z# p- \; ]* H5 j1 j3 o+ M
- 116, 20300, 2, 0, 1
, i6 x6 K% M" {& r - 117, 20475, 2, 0, 19 _( J4 G" V/ _ N
- 118, 20650, 2, -1, 10 U N/ ]. ^: v% c" A/ j
- 119, 20825, 2, -1, 1
( |0 X8 k, ^! w - 120, 21000, 2, -1, 1
( p0 q3 }* T. H \" T1 } - 121, 21175, 2, -1, 0
5 I% T. P" _' i, F& Q' Y - 122, 21350, 2, 0, 1
1 Y/ d5 d( P$ S - 123, 21525, 2, -1, 0
9 c/ E$ k+ N: z - 124, 21700, 0, 0, 0( h" A/ r& w X
- 125, 21875, 2, -1, 1. v m s( [" @7 m) K* @
- 126, 22050, 2, -1, 1
4 S8 m4 G$ h* ]7 e2 o, @5 ^: k - 127, 22225, 2, 0, 1
复制代码
5 |+ v7 p8 s% ~& C, u 在以上的实验数据中,我们分别打印出来了点数、频率、幅值、实部、虚部信息。 由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1492、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。
% G+ t( g/ d# h0 E |