首页 > 其他分享 >【STM32】使用STM32提供的DSP库进行FFT(附详细代码)

【STM32】使用STM32提供的DSP库进行FFT(附详细代码)

时间:2023-07-21 09:01:25浏览次数:43  
标签:采样 FFT DSP STM32 频率 NPT 256

最近,因为项目需要在STM32F103系列处理器上,对采集的音频信号进行FFT运算,然而STM32F103毕竟不是STM32F4系列的处理器,对于一般的FFT运算程序还是比较缓慢的。

幸亏官方提供了针对FFT的官方库,但是去官网找了半天居然找不到那个库的下载,好像官方早就把那个库下架了,估计是为了给带DSP指令集的F4系列让路。然后就只好从别人的项目中把这个官方库给扒出来了……

下载地址:https://pan.baidu.com/s/1GiUJgEkQxDAk79iddXKsaA 提取码: dn2d

FFT的意义

对于很多人来说,采样频率FFT点数之间的关系可能还是不太清楚。下面就来简单分析一下:

根据采样定理,采样频率必须是被采样信号最高频率的2倍。比如,需要采集音频信号,并且需要被观察到的音频频率的频率范围是20Hz到20KHz,那么使用的采样频率就必须大于40kHz。如果需要观察到的音频频率范围为0Hz到600Hz,那么使用的采样频率只需要大于1200Hz即可。

而FFT点数与采样频率之间有什么关系呢?本质上并没有什么关系,但是FFT点数的大小直接关系到频率分辨率。怎么来说呢?

假设采样频率为Fs,信号频率F,采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。同时,FFT后的N个点,开始的那个点表示直流分量(即0Hz),而最后的那个点的再下一个点表示采样频率Fs,这中间被N-1个点平均分成N等份,每个点的频率依次增加。即,某点n所表示的频率为:Fn=(n-1)*Fs/N。这就表示,Fs/N就是频率分辨率

不太理解的,可以查看博客:FFT后的物理意义

FFT官方库的使用条件

  • FFT官方库在使用上并不灵活:属于基4的FFT,即FFT点数必须是4^n。也就是说,如果要做512点或2048点的FFT,那么对不起,没法使用官方库了;
  • FFT官方库的输入输出是等长的,即256点的FFT输入也必须是256点,如果你的输入小于这个长度,是没有任何性能提升的。

FFT官方库的使用

准备工作

下载得到STM32的DSP库之后,就可以将其添加到自己的工程项目中了。

其中,stm32_dsp.h和table_fft.h两个文件是必须添加的。stm32_dsp.h是STM32的DSP库的头文件。

另外,对于**.s文件可以有选择的添加**(用到那个添加那个即可)。由于本文只用到了256点的FFT,所以这里只添加了cr4_fft_256_stm32.s文件。

FFT函数说明

进行256点的FFT,只需要调用STM32 DSP库函数中的cr4_fft_256_stm32()函数即可。该函数的原型为:

void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin);
  • 1

其中,参数pssOUT表示FFT输出数组指针,参数pssIN表示要进行FFT运算的输入数组指针,参数Nbin表示了点数。至于该函数的具体实现,因为是用汇编语言编写的,我也不懂,这里就不妄谈了。

需要说明的是:按照FFT官方库的说明,pssOUT和pssIN都必须是32位的数据类型,其中高16位存储实部,低16位存储虚部。对于pssIN来说,低16位存储的虚部总是为0

代码实例

假设ADC采样的声音数据为adc_buf[NPT],FFT运算的输入数组为lBufInArray[NPT]。由于FFT计算出来的数据是对称的,因此通常而言输出数组取一半的数据,为lBufOutArray[NPT/2]。除此之外,还定义各次谐波幅值lBufMagArray[NPT/2]。即:

#define NPT 256

uint32_t adc_buf[NPT]={0};
long lBufInArray[NPT];
long lBufOutArray[NPT/2];
long lBufMagArray[NPT/2];

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

调用FFT官方库的代码为:

//填充数组
for(i=0;i<NPT;i++)
	//这里因为单片机的ADC只能测正的电压 所以需要前级加直流偏执
	//加入直流偏执后,需要在软件上减去2048即一半,达到负半周期测量的目的(需要根据具体情况来进行配置)
	lBufInArray[i] = ((signed short)(adc_buf[i]-2048)) << 16;

cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

同时,计算各次谐波幅值的函数为:

void GetPowerMag()
{
    signed short lX,lY;
    float X,Y,Mag;
    unsigned short i;
    for(i=0; i<NPT/2; i++)
    {
        lX  = (lBufOutArray[i] << 16) >> 16;
        lY  = (lBufOutArray[i] >> 16);
    <span class="token comment">//除以32768再乘65536是为了符合浮点数计算规律</span>
    X <span class="token operator">=</span> NPT <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>lX<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">32768</span><span class="token punctuation">;</span>
    Y <span class="token operator">=</span> NPT <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>lY<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">32768</span><span class="token punctuation">;</span>
    Mag <span class="token operator">=</span> <span class="token function">sqrt</span><span class="token punctuation">(</span>X <span class="token operator">*</span> X <span class="token operator">+</span> Y <span class="token operator">*</span> Y<span class="token punctuation">)</span> <span class="token operator">/</span> NPT<span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>i <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
        lBufMagArray<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span><span class="token punctuation">)</span><span class="token punctuation">(</span>Mag <span class="token operator">*</span> <span class="token number">32768</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">else</span>
        lBufMagArray<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span><span class="token punctuation">)</span><span class="token punctuation">(</span>Mag <span class="token operator">*</span> <span class="token number">65536</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

标签:采样,FFT,DSP,STM32,频率,NPT,256
From: https://www.cnblogs.com/SymPny/p/17570283.html

相关文章

  • STM32CubeMx LL库BUG之一
    STM32CubeMx是目前最新的V5.5STM32F407,输出LL库,使用FreeRTOS,任务堆栈大小错误:在STM32CubeMx上任务堆栈的单位是word,即4个byte。但是实际上这里的单位是byte,就是说你设置256的话(即1024bytes),实际上给你生成的代码只有256byte,这可能导致任务堆栈溢出,发生各种各样的问题,最常......
  • 使用 STM32 测量频率和占空比的几种方法
    这几天在论坛上面解答了好几个询问STM32测量频率的贴子,觉得这种需求还是存在的(示波器、电机控制等等)。而简单搜索了一下论坛,这方面的贴子有但是不全。正好今年参加比赛做过这方面的题目(最后是一等奖嘿嘿),所以把我们当时尝试过的各种方案都列出来,方便以后大家使用,也是作为一个长期在......
  • STM32 F103 高效与入门
     1 入门写法 2高效写法 #defineOS_LED_ONGPIO_SetBits(GPIOA,GPIO_Pin_11)#defineOS_LED_OFF GPIO_ResetBits(GPIOA,GPIO_Pin_11)//(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_11)==SET)?OS_LED_ON:OS_LED_OFF;//(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_11)==SE......
  • STM32中包含的c语言基础知识(2023/7/19)
     关键字为c语言中的应用,表示的范围根据使用的范围不同,也发生了相应的变化,比如char本来是用来表示字符的,现在也可以用来表述数字;int在c中是16位的,在32中表示32位,long和int的长度相同,longlong基本不使用。stdint关键字的库文件给我们提供的,ST文件是以前的库文件用的命名方式,现在......
  • 03. STM32的HAL库结构
    一、什么是HAL库  HAL,英文全称HardwareAbstractionLayer,即硬件抽象层。HAL库是ST公司提供的外设驱动代码的驱动库,用户只需要调用库的API函数,便可间接配置寄存器。我们要写程序控制STM32芯片,其实最终就是控制它的寄存器,使之工作在我们需要的模式下,HAL库将大部分寄存......
  • STM32蜂鸣器
    1.接线图(蜂鸣器低电平发声,高电平不发声) 2.程序编写#include"stm32f10x.h"//Deviceheader#include"Delay.h"intmain(void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDefGPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_O......
  • STM32流水灯(2023/7/19)
    1.接线图 2.程序编写#include"stm32f10x.h"//Deviceheader#include"Delay.h"intmain(void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDefGPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitS......
  • STM32闪烁灯(2023/7/19)
     1.添加Delay库文件,新建文件夹,增加Delay的.c和.h文件2.编写代码#include"stm32f10x.h"//Deviceheader#include"Delay.h"intmain(void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDefGPIO_InitStructure; GPIO_InitStructure.GPIO_Mode......
  • STM32定时器PWM
    个人估计理解这个图片就差不多明白PWM了。用定时器的加减也一样使用PWM的时候要看PWM的相关IO引脚。CH1-CH4对应OC配置的OC1-OC4频率计算可以看前面的定时器文章。PWM配置过程:1:初始化相关的PWM引脚2:初始化配置定时器   TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseInitStruct);3:配置O......
  • stm32片上资源(2023/7/18)
     *NVIC &SysTick为片内资源 *NVIC:内核里面用于管理中断的设备,比如配置中断优先级这些东西 *SysTick:内核里面是一个定时器,主要用来给操作系统提供定时服务的。STM32可以加入操作系统的,比如FreeRTOS、UCOS等,如果用了这些操作系统,就需要用SysTick提供定时来进行任务切换功......