你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的快速傅里叶变换经验分享

[复制链接]
攻城狮Melo 发布时间:2024-5-29 19:08
快速傅里叶变换(FFT)是一种数字信号处理中常用的技术,用于将快速序列转换为频域表示。在嵌入式系统中,如基于STM32的微控制器,实现FFT可以帮助解决信号处理的需求,例如声音处理、图像处理等。本文将介绍基于STM32的离散傅里叶变换的原理、实现方法和应用。9 n8 \% x$ q3 a0 f
# k) j+ j) O+ ^  e
微信图片_20240529190800.png ! Z% y' J% S. C, m

4 D# e& W; L+ w* s. EFFT是一种将时域序列转换为频域表示的技术,它将一个序列的N个采样点映射到频域中N个频率分量。其数学表达式如下:
9 r- U  c0 P2 U. l- y) p5 t  c0 q- Z" v6 ?& T5 o
微信图片_20240529190757.png * n4 W" I6 k4 z: f8 T6 v
0 t  }& Y; U( @
其中,x(n) 是输入序列,X(k) 是输出的频域表示。
# h* d7 U  d3 k! M/ ^; g4 u; Q7 W3 l* d% w  l
准备工作:' b' z+ r1 Z/ `' G' @

' T: G* z; v0 O% K) j* ~$ M$ R' ]
" Y& H0 Z* c  K# t( `
微信图片_20240529190754.png # [9 X( c( x* S, r2 d9 @  B5 E# w
# Y2 N/ o0 L! M: H. W9 w
微信图片_20240529190750.png
: d+ G. Q6 Y) N+ M& Z( b) d# }. N

; o& `# D# s1 m( {/ H+ ?Keil中的DSP库(Digital Signal Processing Library,数字信号处理库)是针对ARM Cortex-M处理器系列的一组软件库,用于提供各种数字信号处理功能的支持。这些库提供了一系列优化过的算法,可以帮助开发人员在嵌入式系统中高效地实现音频处理、图像处理、通信系统等各种信号处理应用。
: g% c8 o8 [8 j& m' K9 U! L+ d6 ?. B0 A
因此我们需要在Keil中安装我们的DSP库。3 [$ q3 t( Z& n" N' v
  1. #include "arm_math.h" // 包含DSP库
复制代码
% x4 d' F( \' A  j+ V
首先包含我们的DSP库。

7 t- @/ U2 l1 B" Y+ C7 c3 d1 I( P2 k4 W: b6 Q

  [  x) |2 V6 {* a8 s7 g0 _" V3 T% s
  1. #define FFT_LENGTH 100
    ( T/ E' G5 p. N3 G! Q7 f
  2. // 输入序列
    8 c/ }0 {9 E3 q9 d  O  Q
  3. float32_t inputSignal[FFT_LENGTH*2];4 B  N, {3 K1 I
  4. $ G4 K. d  I! F2 `$ M6 O
  5. // 输出序列,存储变换后的结果0 z/ O, u5 Z! n. F
  6. float32_t outputSignal[FFT_LENGTH];
复制代码
4 N' R! [8 p0 U% [, Z
定义FFT的的输入和输出数组还有数组长度
: ~2 u0 T* |" K% T/ I
  1. arm_status status;
    7 i8 U: p% m* A+ l9 |4 e/ S
  2.     arm_cfft_radix4_instance_f32 fft_inst;, I4 e5 |% T8 y! X. B* A. T7 y
  3.     status = arm_cfft_radix4_init_f32(&fft_inst, FFT_LENGTH,0,1);
复制代码
  1. void arm_cfft_radix4_init_f32(; J$ f# K1 v$ h0 K) K$ |
  2.   arm_cfft_radix4_instance_f32 * S,9 V9 J/ v% c# [% g- J/ j
  3.   uint16_t fftLen,7 f: [4 m: {( F& a
  4.   uint8_t ifftFlag,) V' @8 U7 X+ f
  5.   uint8_t bitReverseFlag
    2 P& G& O: K1 L! q7 v
  6. );
复制代码

& y% w1 K' q3 a+ f4 L. O8 y定义一个状态变量用来显示FFT的初始化是否成功。
) }1 p0 L3 D: h. l. f定义一个FFT的配置变量。
( F$ j' `: `+ X  m8 w) x, G初始化FFT。

/ R. S' |$ q( i" i- }S:指向 arm_cfft_radix4_instance_f32 结构体的指针,该结构体定义了 FFT 实例的状态信息。% V2 o0 O" ]* [- f9 O

9 b" h1 c8 h. mfftLen:FFT 的长度。% R$ Z* \: P9 l/ n' A2 }& o7 \. x
! q6 P: u5 x) H6 }( r0 _
ifftFlag:指定是否进行逆变换。如果为 1,则表示初始化的是逆变换的 FFT;如果为 0,则表示初始化的是正变换的 FFT。
% J/ V, M, |3 V% Y- x- Y: X9 t8 I+ Q3 ]$ I9 K, D4 [' C; i& b
bitReverseFlag:指定是否进行比特翻转。如果为 1,则表示进行比特翻转;如果为 0,则表示不进行比特翻转。$ x; B! O  m  i' U8 O

8 g& }  C4 \5 [" C在FFT算法中,比特(bit)反转是一种关键的步骤,用于将输入数据重新排列为正确的顺序,以便在后续的计算中进行有效处理。9 O& A$ H  |; m, }2 }# b( p

: ~8 E- U# u. ~  N5 z3 F当进行快速傅立叶变换时,算法要求输入数据的顺序是按照特定的方式排列的。特别是在使用基于分治法的算法(如Cooley-Tukey算法)时,输入数据的顺序必须满足按照一定规律的排列。; M- W0 J# G; h8 O) E- H
; y% W' B# b3 F
在实际的FFT实现中,最常见的方式是通过比特反转来重新排列输入数据。比特反转就是将输入数据的比特位(二进制位)的顺序进行颠倒。这是因为在FFT算法中,数据会被分组,并按照一定规则进行反转,以便在每个阶段的运算中,数据可以正确地与其它组合进行配对。3 W* @. q7 b$ F6 F" Z9 l* C
8 E& j* S9 U( l% B9 }
举个简单的例子,假设有一个长度为8的数据序列,按照0到7的顺序排列:
; l. G  F3 Y0 q/ T7 }; b3 w  |' r/ w) X, k
0 1 2 3 4 5 6 7/ ~( p0 ?, M) e% F4 Z: i  H' c9 T0 m/ H

+ P7 j: L+ M' Z  T1 a在进行FFT时,需要按照一定规则重新排列这些数据。比特反转操作将会对这个数据序列进行如下的重新排列:8 r4 }  I: ~, L2 k$ A

( T* p. j) w5 W4 ]1 r6 c: \% }. {  m0 4 2 6 1 5 3 7& s# z9 Y/ r0 O( e7 N. u
( R. W3 W, J3 Z' E/ [* g8 Y
在FFT算法的每个阶段中,这种重新排列都会使得数据正确地与其它组合进行配对,从而实现快速傅立叶变换的计算。
: s. J0 c" V% K$ Y* Y5 ?/ \' D: s" A/ K8 |$ T
进行FFT并转换为模值/ m% [' i3 x& Q3 x# z+ b6 c+ f  m
  1. arm_cfft_radix4_f32(&fft_inst,inputSignal);          //FFT计算
    5 ?4 z, @1 B4 O, H6 O
  2.     arm_cmplx_mag_f32(inputSignal,outputSignal,FFT_LENGTH);  //取模得幅值
复制代码

9 s6 o0 T" }* T  D0 A$ b/ f对输入数组进行FFT变换,并将FFT的结果转化为模值。/ u" ~/ F/ f* E

7 C$ ^; D7 F1 P: B+ |. J: A  u* x
测试
4 Y4 j4 Z, T; Z' l& b' Y我们进行一个简单的测试! g# n; f3 B7 y. t1 B
  1. #define FFT_SIZE 1024
    + P* s3 W+ D% ~5 T: \  E' c
  2. #define SAMPLE_RATE 1000
    5 F; y% J- S* I% L" b0 T
  3. #define NUM_SAMPLES 1000
    8 h* y, u- @, J( L$ U
  4. #define FREQ_OF_INTEREST 100
    . s' {# s8 D6 w4 ~, V
  5. for (int i = 0; i < NUM_SAMPLES; i++) {
    0 u2 [7 ^7 j) p# h- y: A
  6.         float32_t t = (float32_t)i / SAMPLE_RATE;6 |2 e# H. Z# l% ?  L. M" [& h# ~
  7.         float32_t sin_value = sinf(2 * PI * FREQ_OF_INTEREST * t); // 计算正弦波值% E* g5 Y3 C. T" `# F- W3 R! _
  8.         inputSignal[i * 2] = sin_value; // 实部
    1 ?/ B2 V! \; Z0 t% q1 m- A
  9.         inputSignal[i * 2 + 1] = 0; // 虚部9 e- Z7 ]+ K6 [
  10.     }
复制代码

$ O5 `1 i/ r# |( r& d+ f一千个点的采样值,频率假设为100HZ作为输入信号。
  n" V/ A9 E) |" R/ [& S
  1. for (int i = 0; i < FFT_SIZE; i++) {
    % r* W4 h2 k, Q4 u
  2.         // 计算复数的模值( \8 I" a' n. N! D
  3.         float32_t real = inputSignal[2 * i];+ O9 L% n0 A2 @8 E
  4.         float32_t imag = inputSignal[2 * i + 1];% j0 f3 B2 j5 p! Q
  5.         float32_t magnitude = sqrtf(real * real + imag * imag);; J1 v7 T8 I  I' ]1 `1 z- B% {
  6.         + L6 t3 _( u. e1 e2 v+ Z$ e$ P
  7.         // 打印每个频率分量的模值; t) A  e7 }$ b9 y6 I
  8.         printf("Magnitude: %f\n", magnitude);
    ' b6 H5 `6 d; m. Y* i
  9.     }
复制代码

; `, ]3 u3 y9 I  }  M进行傅里叶变换后打印模值。
- ^% J( p% {+ O0 u2 _
( [4 w9 \. \8 }6 e 微信图片_20240529190744.png
8 e6 A7 {4 s0 G) ]$ U7 Z
2 q9 A0 L( y% @7 b- |" C0 v( z
可以看到傅里叶变换执行成功。& \1 f# d& Q  ~# k$ a/ T
  1. for (int i = 0; i < NUM_SAMPLES; i++) {
      s! H: g3 G" u: u
  2.         float32_t t = (float32_t)i / SAMPLE_RATE;
    1 t% a& N7 U3 a$ v5 L
  3.         float32_t sin_value = sinf(2 * PI * FREQ_OF_INTEREST * t)+sinf(2 * PI * FREQ_OF_INTEREST * t*2)+sinf(3*2 * PI * FREQ_OF_INTEREST * t); // 计算正弦波值
    ; `7 ~/ m: k7 |
  4.         inputSignal[i * 2] = sin_value; // 实部2 Y8 y5 m7 f/ S7 X. T
  5.         inputSignal[i * 2 + 1] = 0; // 虚部
      U0 D, M5 q7 m6 {3 j
  6.     }
复制代码

( y! \5 Y$ U" f. P我们将信号制作成100HZ+200HZ+300HZ的信号。
! J5 ]1 C0 B2 A7 m9 [: B" t% X- e1 S; g) z  ]4 w( p6 s% G
微信图片_20240529190740.png 1 X8 r; l- B2 _

% o" U9 k% Q6 K( u8 W- Y, q, h; e7 j) }# G& N

1 ]6 g" m/ h: `6 B$ ?转载自:电路小白: q, i' S' z& K: }& n& V( m
如有侵权请联系删除% m" T+ J4 ?* ?, e

( A" L- t. l7 u3 I) p
1 收藏 1 评论1 发布时间:2024-5-29 19:08

举报

1个回答
STMWoodData 回答时间:2024-5-29 22:03:20

这个FFT不错,学习参考一下

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版