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

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

[复制链接]
攻城狮Melo 发布时间:2024-5-29 19:08
快速傅里叶变换(FFT)是一种数字信号处理中常用的技术,用于将快速序列转换为频域表示。在嵌入式系统中,如基于STM32的微控制器,实现FFT可以帮助解决信号处理的需求,例如声音处理、图像处理等。本文将介绍基于STM32的离散傅里叶变换的原理、实现方法和应用。
$ i* c) v3 R2 x
' }$ T: O2 N, m( u- A( F! [2 ~ 微信图片_20240529190800.png - p+ @9 Z0 I) [+ a, Y; L$ c
5 h! S) h8 O$ l+ i# V- {
FFT是一种将时域序列转换为频域表示的技术,它将一个序列的N个采样点映射到频域中N个频率分量。其数学表达式如下:) F% o* n! v: W% `
* O) O" A5 s3 y# F! J$ s* i- v
微信图片_20240529190757.png 3 {9 A8 O; Q+ `+ D

6 I9 k. ~+ F. J8 i+ Z2 G其中,x(n) 是输入序列,X(k) 是输出的频域表示。
7 ~0 ?# F9 |, C/ e2 |* {" @/ K9 c; v/ g4 _4 D9 k4 Y8 B
准备工作:; ]' M) S1 w4 H. M" e

/ Q) w+ u0 k( D. l9 H5 m

3 D1 r( Y/ k" S# R0 Q 微信图片_20240529190754.png 7 l8 d  U  G, e

' y6 a+ J0 h  J+ N" G 微信图片_20240529190750.png 2 a. ^& a2 Y% v  w) B* a$ q
  `2 N* ~, o! x. s% N( `- b0 @
Keil中的DSP库(Digital Signal Processing Library,数字信号处理库)是针对ARM Cortex-M处理器系列的一组软件库,用于提供各种数字信号处理功能的支持。这些库提供了一系列优化过的算法,可以帮助开发人员在嵌入式系统中高效地实现音频处理、图像处理、通信系统等各种信号处理应用。6 n1 g% `+ y6 [4 N* b9 A4 y# J7 Q2 w+ X

+ x$ x. |  o  q4 T( e* {  v- |0 ?6 G. p
因此我们需要在Keil中安装我们的DSP库。
, o- L8 G! Z5 O8 Y  i) {
  1. #include "arm_math.h" // 包含DSP库
复制代码
8 v! p, G- S7 L! |' v: g+ ~2 g3 n
首先包含我们的DSP库。
# I2 X7 m% J9 p: p3 u9 ~1 M1 Q
7 T8 \5 t, k6 t) P8 `# s
. U! \* P, x. i
  1. #define FFT_LENGTH 1008 O; H$ n, @# u) t; n0 d
  2. // 输入序列
    " d3 j& S, l3 s) ?2 l
  3. float32_t inputSignal[FFT_LENGTH*2];
    9 B" h5 R, i, d# X  ?
  4.   R0 B- m% n9 v- \
  5. // 输出序列,存储变换后的结果/ c' ^, ^! ^% Z/ t8 ~
  6. float32_t outputSignal[FFT_LENGTH];
复制代码
) }/ t  G- j6 `) Z5 _
定义FFT的的输入和输出数组还有数组长度
) F0 r4 |% z& c$ t' {% U3 E
  1. arm_status status;
    ' G$ [2 G0 G2 L' Q
  2.     arm_cfft_radix4_instance_f32 fft_inst;
    ) p$ s) `3 m1 f
  3.     status = arm_cfft_radix4_init_f32(&fft_inst, FFT_LENGTH,0,1);
复制代码
  1. void arm_cfft_radix4_init_f32(! A- R; V  u$ T" Q
  2.   arm_cfft_radix4_instance_f32 * S,
    / |( U8 d6 Z5 q5 f. U
  3.   uint16_t fftLen,
    5 _4 T- [; }8 g3 T
  4.   uint8_t ifftFlag,
    % m- n5 R; @2 z
  5.   uint8_t bitReverseFlag7 p) l: I/ H. W4 E: r( ~( m# s) h
  6. );
复制代码

7 D# l4 Y3 ]8 y# P定义一个状态变量用来显示FFT的初始化是否成功。
, d$ g0 S# v  _! v( G定义一个FFT的配置变量。( P9 ?0 {9 `& }, b0 D
初始化FFT。
. r0 N+ `1 D1 i' W9 O0 E8 g
S:指向 arm_cfft_radix4_instance_f32 结构体的指针,该结构体定义了 FFT 实例的状态信息。
' c; y8 a) e: t+ N# z
. f! s+ D8 t9 s) H& jfftLen:FFT 的长度。6 b7 n5 k/ W# u* `
3 J, _0 s! e2 H# |0 Q, K
ifftFlag:指定是否进行逆变换。如果为 1,则表示初始化的是逆变换的 FFT;如果为 0,则表示初始化的是正变换的 FFT。
2 F2 S3 `8 O0 F  f2 p5 R  M, f) c+ M6 w
bitReverseFlag:指定是否进行比特翻转。如果为 1,则表示进行比特翻转;如果为 0,则表示不进行比特翻转。
* j5 `- Y0 Y4 u; O, p2 H+ y' R3 I- @* V! Q3 P
在FFT算法中,比特(bit)反转是一种关键的步骤,用于将输入数据重新排列为正确的顺序,以便在后续的计算中进行有效处理。
/ ~( _# Z3 n" V6 Q
+ k- N6 W; Z$ z4 v0 Z  G& c- Y
当进行快速傅立叶变换时,算法要求输入数据的顺序是按照特定的方式排列的。特别是在使用基于分治法的算法(如Cooley-Tukey算法)时,输入数据的顺序必须满足按照一定规律的排列。
9 x! d# x" m3 \
' K; f4 ]) f* ~* {- Z5 G2 D
在实际的FFT实现中,最常见的方式是通过比特反转来重新排列输入数据。比特反转就是将输入数据的比特位(二进制位)的顺序进行颠倒。这是因为在FFT算法中,数据会被分组,并按照一定规则进行反转,以便在每个阶段的运算中,数据可以正确地与其它组合进行配对。5 W6 y1 e6 a8 `+ E9 g! Z
3 t6 K% h5 }- ?" G2 `
举个简单的例子,假设有一个长度为8的数据序列,按照0到7的顺序排列:
3 H/ n6 c1 o- W$ T4 S0 d8 {5 a5 W; O  n8 b+ N9 N
0 1 2 3 4 5 6 7, f- l; x; }( b5 C, C7 q' X* L

; ^  w1 [3 g4 R! R1 x$ q  B. B在进行FFT时,需要按照一定规则重新排列这些数据。比特反转操作将会对这个数据序列进行如下的重新排列:& ]1 \8 L8 U- P. ^

/ X9 M4 \6 V8 [, K* x1 z0 4 2 6 1 5 3 7) X4 D; c  i1 E2 Q2 e8 ~' j

- o7 ^  L0 m  ~& _在FFT算法的每个阶段中,这种重新排列都会使得数据正确地与其它组合进行配对,从而实现快速傅立叶变换的计算。* o  N) R0 R+ \1 ^* v+ {

4 M4 q: x& M' f% z进行FFT并转换为模值
/ E/ _* t; y: ]& g" ?3 }
  1. arm_cfft_radix4_f32(&fft_inst,inputSignal);          //FFT计算
    % c; Z) Z, W+ z4 ?% \/ J; z
  2.     arm_cmplx_mag_f32(inputSignal,outputSignal,FFT_LENGTH);  //取模得幅值
复制代码
2 [+ ]$ {' L( D$ ~6 |5 n8 B
对输入数组进行FFT变换,并将FFT的结果转化为模值。/ Y6 T- m% W6 I7 V8 }; `# O

$ s' Q" l$ ?4 \! `, O
测试  f: z! g$ ~! W5 ~- n
我们进行一个简单的测试
& p! S9 N4 d5 L* Y
  1. #define FFT_SIZE 1024
    + r9 V% N3 K8 h' g+ S$ w6 B7 l
  2. #define SAMPLE_RATE 1000: q; y+ A6 |6 ?/ r
  3. #define NUM_SAMPLES 10008 k  \0 Z" h& r# G
  4. #define FREQ_OF_INTEREST 1007 R: x2 [3 J5 V% e. {* @
  5. for (int i = 0; i < NUM_SAMPLES; i++) {4 {+ _& H8 d( H. `
  6.         float32_t t = (float32_t)i / SAMPLE_RATE;
    1 e! W. k3 [4 F" x  }0 Y: ]
  7.         float32_t sin_value = sinf(2 * PI * FREQ_OF_INTEREST * t); // 计算正弦波值
    : C$ H0 X  E; ?. Q6 d
  8.         inputSignal[i * 2] = sin_value; // 实部, d( {* r3 A9 n" l1 s. x
  9.         inputSignal[i * 2 + 1] = 0; // 虚部; ?/ l; F9 S4 A, ~# J5 J
  10.     }
复制代码

' C- k9 h3 C0 k* Q' I3 R5 _一千个点的采样值,频率假设为100HZ作为输入信号。
, i8 V; x6 _, L: K$ g) }
  1. for (int i = 0; i < FFT_SIZE; i++) {
    " r% z6 c4 a  o7 N
  2.         // 计算复数的模值4 T6 f- K# c  ]: N. {9 e
  3.         float32_t real = inputSignal[2 * i];
    4 u7 x& s" N1 g8 l. V* S4 S
  4.         float32_t imag = inputSignal[2 * i + 1];5 J* X" d$ U8 Y5 e& k
  5.         float32_t magnitude = sqrtf(real * real + imag * imag);
    , o. M- I; y& |& `4 t. F" P& R" M
  6.         
    % U7 B% J5 P1 t
  7.         // 打印每个频率分量的模值
    6 E2 y' }& B" N: L$ q
  8.         printf("Magnitude: %f\n", magnitude);
    9 u& c4 O0 p. f1 u; C9 s7 q! Y
  9.     }
复制代码

* h7 L( D: \, T8 }% N进行傅里叶变换后打印模值。. ^" b; }- @. @) W
5 R4 {( C3 Z: i+ t
微信图片_20240529190744.png 4 I) f+ H/ p7 S& D5 J" s8 [
& E2 ^, y5 n1 l" x% P+ b
可以看到傅里叶变换执行成功。
5 h8 [; h/ f9 S
  1. for (int i = 0; i < NUM_SAMPLES; i++) {; V2 }  w- P, A. x  \
  2.         float32_t t = (float32_t)i / SAMPLE_RATE;+ y  V8 x& G0 f4 ^5 H
  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); // 计算正弦波值
    ( F3 x" _. B* E0 i6 t
  4.         inputSignal[i * 2] = sin_value; // 实部
    # t0 w% V2 N- j  T4 \8 M
  5.         inputSignal[i * 2 + 1] = 0; // 虚部
    , t3 r2 `" S" [7 N' c! k! j0 w
  6.     }
复制代码

0 a5 X9 x8 X5 P5 N8 ]6 j我们将信号制作成100HZ+200HZ+300HZ的信号。
- l, z1 s2 j9 s% F5 m$ f: }4 F/ u8 i
微信图片_20240529190740.png
7 [7 n: i2 b- I1 P' n
! x+ v% ^. {% }( ]( w. P; k  |8 _1 ~( d* s% n, h

  Y- E1 S, u& |转载自:电路小白
0 E  T# n. Q% V2 s1 ~5 m如有侵权请联系删除: @2 B9 V( Y3 z
1 Q/ W5 ^) f$ W/ `
1 收藏 1 评论1 发布时间:2024-5-29 19:08

举报

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

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

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版