【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT
前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT。在网上找了很多这方面的资料做实验并进行比较,最终选择了使用STM32提供的DSP库这种方法。
本文将以一个实例来介绍如何使用STM32提供的DSP库函数进行FFT。
1.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。
2.如何使用STM32提供的DSP库函数
2.1下载STM32的DSP库
大家可以从网上搜索下载得到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库函数,需要传入的参数规定了必须是这样的数据格式。
下面是具体的实现代码:
/******************************************************************
函数名称:InitBufInArray()
函数功能:模拟采样数据,采样数据中包含3种频率正弦波(350Hz,8400Hz,18725Hz)
参数说明:
备 注:在lBufInArray数组中,每个数据的高16位存储采样数据的实部,
低16位存储采样数据的虚部(总是为0)
作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)
*******************************************************************/
void InitBufInArray()
{
unsigned short i;
float fx;
for(i=; i<NPT; i++)
{
fx = * sin(PI2 * i * 350.0 / Fs) +
* sin(PI2 * i * 8400.0 / Fs) +
* sin(PI2 * i * 18725.0 / Fs);
lBufInArray[i] = ((signed short)fx) << ;
}
}
其中,NPT是采样点数256,PI2是2π(即6.28318530717959),Fs是采样频率44800。可以看到采样数据中包含了3种频率的正弦波,分别为350Hz,8400Hz和18725Hz。
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位存储实部。
2.5计算各次谐波幅值
得到FFT运算之后的结果数据之后,就可以计算各次谐波的幅值了。
下面是具体的实现代码:
/******************************************************************
函数名称:GetPowerMag()
函数功能:计算各次谐波幅值
参数说明:
备 注:先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)
作 者:博客园 依旧淡然(http://www.cnblogs.com/menlsh/)
*******************************************************************/
void GetPowerMag()
{
signed short lX,lY;
float X,Y,Mag;
unsigned short i;
for(i=; i<NPT/; i++)
{
lX = (lBufOutArray[i] << ) >> ;
lY = (lBufOutArray[i] >> );
X = NPT * ((float)lX) / ;
Y = NPT * ((float)lY) / ;
Mag = sqrt(X * X + Y * Y) / NPT;
if(i == )
lBufMagArray[i] = (unsigned long)(Mag * );
else
lBufMagArray[i] = (unsigned long)(Mag * );
}
}
其中,数组lBufMagArray存储了各次谐波的幅值。
2.6实验结果
通过串口,我们可以将lBufMagArray数组中各次谐波的幅值(即各个频率分量的幅值)输出打印出来,具体实验数据如下所示:
i, P, Mag, X, Y
, , , , -
, , , -, -
, , , , -
, , , -, -
, , , -, -
, , , -, -
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -, -
, , , -, -
, , , -, -
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -, -
, , , -, -
, , , -, -
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , ,
, , , -, -
, , , ,
, , , -, -
, , , , -
, , , ,
, , , -, -
, , , -,
, , , -,
, , , -, -
, , , -, -
, , , -,
, , , ,
, , , -,
, , , -, -
, , , -, -
, , , ,
, , , -,
, , , ,
, , , -, -
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , ,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -,
, , , -, -
, , , -,
, , , -,
, , , -,
, , , ,
, , , -,
, , , -,
, , , -,
, , , -,
, , , ,
, , , -,
, , , ,
, , , -,
, , , ,
, , , ,
, , , -,
, , , -,
, , , -,
, , , -,
, , , ,
, , , -,
, , , ,
, , , -,
, , , -,
, , , ,
在以上的实验数据中,我们分别打印出来了点数、频率、幅值、实部、虚部信息。
由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1492、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。
【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT的更多相关文章
- 【玩转单片机系列001】 08接口双色LED显示屏驱动方式探索
前些日子,从淘宝上购得一块08接口的双色LED显示屏(打算做个音乐频谱显示器),捣鼓了好几天,终于搞清楚了其控制原理,在这里做个总结,算是备忘吧. 1.LED显示屏的扫描方式 LED显示屏的扫描方式有 ...
- 第40章 CAN—通讯实验—零死角玩转STM32-F429系列
第40章 CAN—通讯实验—零死角玩转STM32-F429系列 第40章 CAN—通讯实验 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视 ...
- 第25章 串行FLASH文件系统FatFs—零死角玩转STM32-F429系列
第25章 串行FLASH文件系统FatFs 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.c ...
- [Linux] PHP程序员玩转Linux系列-lnmp环境的搭建
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 在平常的工作中,我作为PHP程序员经常要搭建一下环境,这个环境就是Linux系统下安装nginx,php,mysql这三个软件,对软件进行 ...
- [Linux] PHP程序员玩转Linux系列-搭建代码开发环境
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 有些同学可能觉得我写的都是啥yum安装的,随便配置一下而已,没啥技术含量,我的目的 ...
- [Linux] PHP程序员玩转Linux系列-备份还原MySQL
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 前几天有个新闻,说是g ...
- [Linux] PHP程序员玩转Linux系列-自动备份与SVN
我的代码经常在开发修改,为了代码的安全性,比如哪天误删了文件,或者哪天改错东西了,可以恢复回来,我要搞代码备份.备份代码,我先做最简单的,使用linux的定时机制加shell命令打包文件,每天按日期保 ...
- [Linux] PHP程序员玩转Linux系列-nginx初学者引导
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...
- [Linux] PHP程序员玩转Linux系列-Linux和Windows安装nginx
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...
随机推荐
- Kafka vs RocketMQ—— Topic数量对单机性能的影响-转自阿里中间件
引言 上一期我们对比了三类消息产品(Kafka.RabbitMQ.RocketMQ)单纯发送小消息的性能,受到了程序猿们的广泛关注,其中大家对这种单纯的发送场景感到并不过瘾,因为没有任何一个网站的业务 ...
- Service and controller in angularJs
Separation of concern is at the heart while designing an AngularJS application. Your controller must ...
- 11大Java开源中文分词器的使用方法和分词效果对比
本文的目标有两个: 1.学会使用11大Java开源中文分词器 2.对比分析11大Java开源中文分词器的分词效果 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那 ...
- 一些关于 checkbox的前台 jquery 操作 记录
$(function() { //页面载入函数 var partList = jQuery.parseJSON( '${KeyWordsList}'); $.each(partList,functio ...
- getComputedStyle 方法
一:getComputedStyle getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值.返回的是一个CSS样式声明对象([object CSSStyleDeclarat ...
- Java EE之servlet处理表单提交的请求
1.在源包下新建一个Servlet页,取名为LoginServlet: package weinidingServlet; //该Servlet所 ...
- PDA手持机 移动开单进销存系统 现场出打印凭据和扫码 新的亮点
传统车销模式弊端:1.手写开单,效率低,动作慢2.现场手写开单明细不能打印,产品明细不规范3.电脑办公人员及车销人员对车上的库存情况掌握不清楚,销售人员对每种产品销售价格不清楚4.老板对员工工作的管控 ...
- 条码固定资产管理PDA应用
条码固定资产管理解决方案 一.客户挑战与需求 随着企业经营管理的不断升级,固定资产管理的高效化.智能化管理越来越受到企业管理人员的重视.然而,固定资产具有数量大.种类多.价值高.使用周期长.使用地点分 ...
- gradle下载地址
gradle下载:http://services.gradle.org/distributions
- Mac osx 安装PIL出现Some externally hosted files were ignored (use --allow-external PIL to allow).
出现这个问题Some externally hosted files were ignored (use --allow-external PIL to allow)的主要原因是PIL的一些依赖库还没 ...