【玩转单片机系列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 ...
随机推荐
- ubuntu14.04下配置Java环境以及安装最新版本的eclipse
首先是配置JDK 步骤一:下载最新版本的JDK,链接:http://www.oracle.com/technetwork/java/javase/downloads/index.html 步骤二:首先 ...
- HDFS操作
HDFS操作 1.shell 1.1 创建目录 hadoop fs -mkdir 目录名(其中/为根目录) 1.2 遍历目录 hadoop fs -ls 目录名 1.3 删除目录 hadoop fs ...
- Nginx - Linux下按天分割日志
待完善. 可参考:https://www.iteblog.com/archives/1244
- Linux service命令
service命令(其实与其说是命令,不如说是脚本),因为service本身就是一个脚本,这个脚本在/sbin路径下,待后续shell脚本功底好了将去认真去看看这个脚本的内容(可不能被人忽悠了.) s ...
- css common 通用
/*common*/ body{ color:#666666; font-size:12px; margin:; padding:; font-family:"Arial",&qu ...
- 在HTML中使用JavaScript元素
script属性<script async = async charset="utf-8" defer="defer" src="index.h ...
- 原生JS 年月日、省市区 三级联动
这个算生日日期,因为是从100年前的到现年. <select id="sel_year"></select> <select id="sel ...
- phpstorm 10注释的双斜线位置不在缩进的位置:
22:07 2016/4/4phpstorm 10注释的双斜线位置不在缩进的位置:终于找到了(但是没有实现效果,不知道是什么原因 win10系统):File | Settings | Editor | ...
- pointer-events 使用场景
最近做一个简单移动web功能,可以左右滑动切换功能.如下图: 但是用户不知道可以滑动切换,所以需要提示用户可以滑动切换,那就添加了一个滑动动画. 滑动动画在最上层,所以当显示滑动提示显示的时候,用户切 ...
- java DOM4J 读取XML
最近学习Java,在处理XML文档的时候,查阅相关资料,发现了DOM4J这个jre库,相对C#的XML处理来说,功能还算是跟得上 下面展示一篇我自己写的一个XML读取测试 import java.ut ...