华大半导体HC32F4A0笔记(五),使用CMSIS-DSP库进行FFT运算

本文介绍如何在HC32F4A0微控制器上启用FPU功能并利用DSP库进行快速傅里叶变换(FFT)。内容包括配置FPU、生成正弦波采样序列、执行Q15定点FFT及计算结果的幅值。

一、开启FPU功能

点这个麻将牌四筒,展开CMSIS,把DSP勾了。
在这里插入图片描述
在这里插入图片描述
点开后
在这里插入图片描述

然后点这个锤子在这里插入图片描述

在这里插入图片描述
No Auto Includes的勾不要打,让它自动include,因为CMSIS-DSP库在KEIL的安装目录中已经存在了,工程里面不需要另外添加这些库文件,自动include会帮你找到它们。

在Target标签页选上这个Use Single Precision,有些版本上面显示的是use FPU
在这里插入图片描述
打开hc32f4a0.h文件,搜索__FPU_PRESENT,确定其在宏定义处定义为1
在这里插入图片描述
至此FPU功能就开启完毕了,我们可以使用官方库函数进行多种数学和信号运算,这些官方函数在实现这些高级运算时调用了FPU的指令,这样运算速度大幅提升!
在这里插入图片描述

当我们使用FFT时,需要引入两个头文件,由于允许Auto Includes,KEIL MDK会自动在它的安装目录里面找到它们

#include "arm_math.h"
#include "arm_const_structs.h"

在这里插入图片描述

二、使用库函数q15_t arm_sin_q15(q15_t x);生成正弦采样序列

在使用外部信号源经AD采样获取真实信号继而FFT之前,我们先模拟一个正弦波采样序列来试验测试FFT功能。

根据实际使用需求,我们模拟一个50hz的正弦信号,采样率为1600Hz,即每个周波32采样,共采样1024个点,每个点都使用Q15定点数 (-1 ~ 0.9999695)。

Fs = 1600 Hz (采样率)
N = 1024个点 (采样数)
n = 0,1,2,… N-1 (采样点序列)
t = 0,1/Fs,2/Fs,…(N-1)/Fs (采样时刻序列)
x = sin(2π x 50 x t) (采样信号序列)

#define TEST_LENGTH_SAMPLES 1024 
static q15_t testInput_q15_50hz[TEST_LENGTH_SAMPLES];
uint32_t fftSize = TEST_LENGTH_SAMPLES ; 
uint32_t Fs = 1600; 

数学上 y = sin(x) 的定义域是是(-∞,+∞),但是DSP库中的q15_t arm_sin_q15(q15_t x);的参数数值范围是[0,2^15),对应于弧度[0,2π)。

所以我们需要按照每周波32采样的采样率通过取余运算适配这个定义域

	for(uint16_t n=0; n<fftSize; n++)
	{
		j = n % 32;
 		testInput_q15_50hz[n] = arm_sin_q15(k*j);
	}
    systickStart = SysTick->VAL;

其中k为:

	k = 32768 * 50 / Fs;

这样我们就配置好了50Hz正弦波在1600Hz采样率下采集1024个点的信号采样序列。
在这里插入图片描述

三、Q15定点FFT运算

参照DSP库函数说明

  /**
   * @brief Instance structure for the Q15 RFFT/RIFFT function.
   */
  typedef struct
  {
    uint32_t fftLenReal;                      /**< length of the real FFT. */
    uint8_t ifftFlagR;                        /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */
    uint8_t bitReverseFlagR;                  /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */
    uint32_t twidCoefRModifier;               /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */
    q15_t *pTwiddleAReal;                     /**< points to the real twiddle factor table. */
    q15_t *pTwiddleBReal;                     /**< points to the imag twiddle factor table. */
    const arm_cfft_instance_q15 *pCfft;       /**< points to the complex FFT instance. */
  } arm_rfft_instance_q15;

  arm_status arm_rfft_init_q15(
  arm_rfft_instance_q15 * S,
  uint32_t fftLenReal,
  uint32_t ifftFlagR,
  uint32_t bitReverseFlag);

  void arm_rfft_q15(
  const arm_rfft_instance_q15 * S,
  q15_t * pSrc,
  q15_t * pDst);

调用该函数运算FFT:

	static q15_t testOutput_q15_50hz[TEST_LENGTH_SAMPLES];
	arm_rfft_instance_q15 S;
	uint32_t ifftFlag = 0; 
	uint32_t doBitReverse = 1; 
	/* 初始化结构体S */
 	(void)arm_rfft_init_q15(&S, fftSize, ifftFlag, doBitReverse);
 	/* 实数FFT Q15运算 */
 	arm_rfft_q15(&S, testInput_q15_50hz, testOutput_q15_50hz);

查阅资料得知其结果是Q5格式。

安富莱电子

根据公式x = (float)xq * 2-Q可以换算成浮点数

	static float32_t testOutput_f32_50hz[TEST_LENGTH_SAMPLES];
	for(uint16_t n = 0; n < fftSize; n++)
	{
		testOutput_f32_50hz[n] = (float32_t)testOutput_q15_50hz[n]/32;
	}

其运算结果为:
在这里插入图片描述
这是一个复数,偶数项为实部,其后的奇数项为虚部。这个复数为-0.03125-512j

再调用DSP库函数计算其幅值,其实由于实部很小,估算可知其幅值为512。

	static float32_t testOutput[TEST_LENGTH_SAMPLES];
 	arm_cmplx_mag_f32(testOutput_f32_50hz, testOutput, fftSize); 

求得其结果为:
在这里插入图片描述
由于本例是1600hz采样1024点,所以FFT后其频域响应在32 * 1600 / 1024 = 50Hz处出现极大值。
幅值计算公式为:An * 2 / N,即512 * 2 / 1024 = 1。
即得到正弦频率为50Hz,增益为1。结果与输入信号的相符。

四、实数Q15 1024FFT的运行时间

HC32F4AO主频设在200MHz,使用Systick记录Q15 1024FFT加上转换为浮点数最后算得幅值的总时间。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行耗时在900us左右。再分开查看
在这里插入图片描述
FFT耗时565us,1024个Q5定点复数转成浮点型耗时85us,算幅值耗时203us。这段时间内应该发生了几次中断,所以实际的耗时应该要比它更短。

由于实际需求中不一定需要关注全频域的幅频响应,所以算幅值的203us可以得到相当的节省。

### 三级标题:配置 CMSIS-DSP 在 STM32F4 系列单片机上使用 CMSIS-DSP 时,需要确保项目中包含必要的头文件和源文件。首先,从 ARM 官方资源下载 CMSIS-DSP ,并将 `arm_math.h` 和其他必需的头文件复制到项目的 `Inc` 文件夹。接着,将所需的 `.c` 文件(如 `arm_rfft_fast_f32.c`、`arm_cfft_radix4_f32.c` 等)复制到项目的 `Src` 文件夹。 在 STM32CubeIDE 中加入 DSP 时,可以参考官方提供的英文文档进行操作,以确保所有文件正确集成到项目中 [^1]。 ### 三级标题:启用 FPU 支持 为了充分利用硬件加速能力,必须启用浮点运算支持。在 STM32CubeMX 的 **"Pinout & Configuration"** 界面中,选择 **"System Core" > "NVIC"**,并在 **"FPU interrupt"** 部分勾选 **"Enable FPU"** 选项以启用浮点单元 [^3]。 ### 三级标题:定义宏 CMSIS-DSP 依赖于 `ARM_MATH_CM4` 宏定义来启用与 Cortex-M4 内核相关的优化功能。此宏定义应在项目中全局启用。在 STM32CubeMX 的 **"Project Manager"** 页面中,找到 **"Advanced Settings"**,并在 **"C/C++"** 部分下添加 `ARM_MATH_CM4` 到 **"Defined Symbols"** 列表中 。 ### 三级标题:实现滤波器 一旦完成了上述配置,就可以开始编写代码来实现滤波器功能。以下是一个简单的示例代码片段,展示了如何使用 CMSIS-DSP 中的函数来进行滤波处理: ```c #include "arm_math.h" // 滤波器系数和状态变量定义 #define NUM_TAPS 28 float32_t firCoeffs[NUM_TAPS] = { // 这里填入实际的滤波器系数 }; float32_t firStateF32[TEST_LENGTH_SAMPLES + NUM_TAPS - 1]; // 创建 FIR 滤波器实例 arm_rfft_fast_instance_f32 S; arm_rfft_fast_init_f32(&S, TEST_LENGTH_SAMPLES); // 执行 FIR 滤波 void apply_filter(float32_t *input, float32_t *output, uint32_t blockSize) { arm_fir_instance_f32 S; arm_fir_init_f32(&S, NUM_TAPS, firCoeffs, firStateF32, blockSize); arm_fir_f32(&S, input, output, blockSize); } ``` 这段代码演示了如何初始化一个 FIR 滤波器,并对输入信号应用该滤波器。用户需要根据具体的应用场景调整滤波器系数和其他参数。 ###
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值