DSP 库运行环境搭建

在 MDK 里面搭建 STM32F4 的 DSP 运行环境(使用.lib 方式)是很简单的,分为 3 个步骤:
1, 添加文件。
首先,我们在例程工程目录下新建:DSP_LIB 文件夹,存放我们将要添加的文件:
arm_cortexM4lf_math.lib 和相关头文件(文件由官方提供),如图:


然后,打开工程,新建 DSP_LIB 分组,并将 arm_cortexM4lf_math.lib 添加到工程里面,如图:

2, 添加头文件包含路径
添加好.lib 文件后,我们要添加头文件包含路径,将第一步拷贝的 Include 文件夹和 DSP_LIB文件夹,加入头文件包含路径。
3, 添加全局宏定义
最后,为了使用 DSP 库的所有功能,我们还需要添加几个全局宏定义:
1,__FPU_USED
2,__FPU_PRESENT
3,ARM_MATH_CM4
4,__CC_ARM
5,ARM_MATH_MATRIX_CHECK
6,ARM_MATH_ROUNDING
添加方法:点击C/C++选项卡,然后在 Define 里面进行设置,如图


这里,两个宏之间用“,”隔开。并且,上面的全局宏里面,我们没有添加__FPU_USED,因为这个宏定义在 Target 选项卡设置 Code Generation 的时候,选择了:Use FPU(如果没有设置 Use FPU,则必须设置!!),故 MDK 会自动添加这个全局宏,因此不需要我们手动添加了。
至此,STM32F4 的 DSP 库运行环境就搭建完成了。

FFT介绍

FFT 即快速傅里叶变换,可以将一个时域信号变换到频域。因为有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了,这就是很多信号分析采用 FFT 变换的原因。另外,FFT 可以将一个信号的频谱提取出来,这在频谱分析方面也是经常用的。简而言之,FFT 就是将一个信号从时域变换到频域方便我们分析处理。

照一定大小采样频率 F 去采集信号,采集 N 个点,那么通过对这 N 个点进行 FFT 运算,就可以得到这个信号的频谱特性。 这里还涉及到一个采样定理的概念:在进行模拟/数字信号的转换过程中,当采样频率 F 大于信号中最高频率 fmax的 2 倍时(F>2*fmax),采样之后的数字信号完整地保留了原始信号中的信息,采样定理又称奈奎斯特定理。举个简单的例子:比如我们正常人发声,频率范围一般在 8KHz以内,那么我们要通过采样之后的数据来恢复声音,我们的采样频率必须为 8KHz 的 2 倍以上,也就是必须大于 16KHz 才行。

模拟信号经过 ADC 采样之后,就变成了数字信号,采样得到的数字信号,就可以做 FFT变换了。N 个采样点数据,在经过 FFT 之后,就可以得到 N 个点的 FFT 结果。为了方便进行FFT 运算,通常 N 取 2 的整数次方。

假设采样频率为 F,对一个信号采样,采样点数为 N,那么 FFT 之后结果就是一个 N 点的复数,每一个点就对应着一个频率点(以基波频率为单位递增),这个点的模值(sqrt(实部虚部2))就是该频点频率值下的幅度特性。具体跟原始信号的幅度有什么关系呢?假设原始信号的峰值为 A,那么 FFT 的结果的每个点(除了第一个点直流分量之外)的模值就是 A 的 N/2倍,而第一个点就是直流分量,它的模值就是直流分量的 N 倍。

这里还有个基波频率,也叫频率分辨率的概念,就是如果我们按照 F 的采样频率去采集一个信号,一共采集 N 个点,那么基波频率(频率分辨率)就是 fk=F/N。 这样,第 n 个点对应信号频率为:F*(n-1)/N;其中 n≥1,当 n=1 时为直流分量。
关于 FFT 就介绍到这。

官方FFT使用

如果我们要自己实现 FFT 算法,对于不懂数字信号处理的朋友来说,是比较难的,不过,ST 提供的 STM32F4 DSP 库里面就有 FFT 函数给我们调用,因此我们只需要知道如何使用这些函数,就可以迅速的完成 FFT 计算,而不需要自己学习数字信号处理,去编写代码了,大大方便了我们的开发。STM32F4 的 DSP 库里面,提供了定点和浮点 FFT 实现方式,并且有基 4的也有基 2 的,大家可以根据需要自由选择实现方式。注意:对于基 4 的 FFT 输入点数必须是 4n,而基 2 的FFT 输入点数则必须是 2n,并且基 4 的 FFT 算法要比基 2 的快。 本次我将采用 DSP 库里面的基 4 浮点 FFT 算法来实现 FFT 变换,并计算每个点的幅值、频率、相位。
所用到的函数有:

arm_status arm_cfft_radix4_init_f32(
arm_cfft_radix4_instance_f32 * S,
uint16_t fftLen,uint8_t ifftFlag,uint8_t bitReverseFlag)
void arm_cfft_radix4_f32(const arm_cfft_radix4_instance_f32 * S,float32_t * pSrc)
void arm_cmplx_mag_f32(float32_t * pSrc,float32_t * pDst,uint32_t numSamples)

第一个函数 arm_cfft_radix4_init_f32,用于初始化 FFT 运算相关参数,其中:fftLen 用于指定 FFT 长度(16/64/256/1024/4096),本章设置为1024;ifftFlag 用于指定是傅里叶变换(0)还是反傅里叶变换(1),本次设置为0;bitReverseFlag 用于设置是否按位取反,本章设置为 1;最后,所有这些参数存储在一个 arm_cfft_radix4_instance_f32 结构体指针 S 里面。

第二个函数 arm_cfft_radix4_f32 就是执行基 4 浮点 FFT 运算的,pSrc 传入采集到的输入信号数据(实部+虚部形式),同时 FFT 变换后的数据,也按顺序存放在 pSrc 里面,pSrc 必须大于等于 2 倍 fftLen 长度。另外,S 结构体指针参数是先由 arm_cfft_radix4_init_f32 函数设置好,然后传入该函数的。

第三个函数 arm_cmplx_mag_f32 用于计算复数模值,可以对 FFT 变换后的结果数据,执行取模操作。pSrc 为复数输入数组(大小为 2*numSamples)指针,指向 FFT 变换后的结果;pDst为输出数组(大小为 numSamples)指针,存储取模后的值;numSamples 就是总共有多少个数据需要取模。
通过这三个函数,我们便可以完成 FFT 计算,求出模值后便可以求出幅值、相位,知道采样率和FFT长度就可求出频率。

软件设计

fft.c 代码

#include "arm_math.h"
#include "common.h"
#include "fft.h"/*********************************************************************************
************************STM32F407核心开发板******************************
**********************************************************************************
* 文件名称: fft.c                                                             *
* 文件简述:DSP FFT使用                                                           *
* 创建日期:2020.08.21                                                           *
* 版    本:V1.0                                                                 *
* 作    者:近视未看清人心                                                              *
* 说    明:完成FFT信号分析需要用到的函数集,包括求模,幅值、频率、相位
注意:FFT的长度,也就是采样点的个数在fft.h 宏定义中完成*
**********************************************************************************
*********************************************************************************/  arm_cfft_radix4_instance_f32 scfft; //设置FFT参数的结构体变量(基4)/****************************************************************************
* 名    称: void FFTx4_init(u8 ifftFlag,u8 bitReverseFlag)
* 功    能:FFT初始化函数(基4)
* 入口参数:ifftFlag:于指定是傅里叶变换(0)还是反傅里叶变换(1)bitReverseFlag:是否按位取反* 返回参数:无
* 说    明:
****************************************************************************/void FFTx4_init(u8 ifftFlag,u8 bitReverseFlag)
{arm_cfft_radix4_init_f32(&scfft,length,ifftFlag,bitReverseFlag);//初始化scfft结构体,设定FFT相关参数
}/****************************************************************************
* 名    称: void cFFTx4(float * pSrc)
* 功    能:FFT计算函数(基4)
* 入口参数:pSrc:pSrc 传入采集到的输入信号数据(实部+虚部形式),同时 FFT 变换后的数据,也按顺序存放在 pSrc 里面
* 返回参数:无
* 说    明:pSrc的长度必须>=2*length
****************************************************************************/void cFFTx4(float * pSrc)
{arm_cfft_radix4_f32(&scfft,pSrc);  //FFT计算(基4)
}/****************************************************************************
* 名    称: void cmplxFFTx4(float * pSrc,float * pDst)
* 功    能:对FFT结果求模值(基4)
* 入口参数:pSrc:需要求模的复数指针(实部+虚部形式)pDst:存放模值* 返回参数:无
* 说    明:pSrc的长度必须>=2*length
****************************************************************************/void cmplxFFTx4(float * pSrc,float * pDst)
{arm_cmplx_mag_f32(pSrc,pDst,length);   //计算复数模值}/****************************************************************************
* 名    称: void all_result_x4(float * pSrc,float * Amp,float * rate,float * Phase,u32 Fs)
* 功    能:计算各点幅值、频率、相位
* 入口参数:pSrc:原始信号的复数指针(实部+虚部形式)Amp:存放幅值rate:存放各点的频率Phase:存放各点的相位size:采样点的个数* 返回参数:无
* 说    明:pSrc的长度必须>=2*size
****************************************************************************/
void all_result_x4(float * pSrc,float * Amp,float * rate,float * Phase,u32 Fs)
{float pDst[length];u32 i;arm_cfft_radix4_f32(&scfft,pSrc); //FFT计算(基4)arm_cmplx_mag_f32(pSrc,pDst,length);   //计算复数模值//计算各点幅值、频率、相位for(i=0;i<length;i++){if(i==0)    Amp[0]=pDst[0]/length; //第一个点直接除以size(z直流分量)else Amp[i]=pDst[i]*2/length; //其他点除以size/2rate[i]=Fs/length*i;//    各点频率Phase[i]=atan2(pSrc[2*i+1], pSrc[2*i]); /* atan2求解的结果范围是(-pi, pi], 弧度制 */}}

fft.h 代码

#ifndef _FFT_H
#define _FFT_H
#include "arm_math.h"
#include "common.h"#define length 1024 //FFT长度(16/64/256/1024/4096),即采样点的个数void FFTx4_init(u8 ifftFlag,u8 bitReverseFlag);//FFT初始化函数(基4)
void cFFTx4(float * pSrc);//FFT计算函数(基4)
void cmplxFFTx4(float * pSrc,float * pDst);//对FFT结果求模值(基4)
void all_result_x4(float * pSrc,float * Amp,float * rate,float * Phase,u32 Fs);//计算各点幅值、频率、相位#endif

main.c 代码

#include "common.h"
#include "key.h"
#include "fft.h"
#include "usart3.h"/*********************************************************************************
********************** STM32F407应用开发板(高配版)*************************
**********************************************************************************
* 文件名称: DSP FFT使用                                                         *
* 文件简述:                                                                     *
* 创建日期:2020.8.21                                                          *
* 版    本:V1.0                                                                 *
* 作    者:近视未看清                                                               *
* 说    明:将时域序列信号FFT后幅值、频率、相位通过串口发送到PC                         *
*                                     *
**********************************************************************************
*********************************************************************************/float input[length*2];//前一个数表示实部,后一个表示虚部
float Amp[length];//存放幅值
float rate[length];//存放频率
float Phase[length];
int main(void)
{ u16 i;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2delay_init();       //初始化延时函数KEY_Init();        //IO初始化uart3_init(9600);FFTx4_init(0,1);//FFT初始化函数(基4)//生成信号序列for(i=0;i<length;i++){input[i*2]=100+10*arm_sin_f32(2*PI*i/length)+30*arm_sin_f32(2*PI*i*4/length)+50*arm_cos_f32(2*PI*i*8/length); //生成输入信号实部input[2*i+1]=0;//时域,虚部为零}while(1){key_scan(0);if(keydown_data==KEY0_DATA){all_result_x4(input, Amp, rate, Phase,1024);//计算各点幅值、频率、相位printf("A:       F;    P\n");for(i=0;i<length;i++)printf("%.2f: %.2f: %.2f\n",Amp[i],rate[i],Phase[i]);//向串口发送幅值、频率、相位}delay_ms(5);}
}

测试结果分析


由于 FFT 变换后的结果具有对称性,所以,实际上有用的数据,只有前半部分,后半部分和前半部分是对称关系,比如 第2个点和 最后一个点,5 和 1021,9和 1017 等,就是对称关系,因此我们只需要分析前半部分数据即可。这样,就只有第 1、2、5、9 这四个点幅值比较大,其他点的幅值几乎都是0,重点分析。
采样频率为 1024Hz,那么总共采集 1024 个点,频率分辨率就是 1Hz,对应到频谱上面,两个点之间的间隔就是 1Hz(跟图中第二列完全吻合)。第 1 点,即直流分量,幅值为100,第2、5、9点对应幅值分别为10,30,50,频率分别为1Hz,4Hz,8Hz。因此,可以看出跟上面生成的信号:
100+
10*sin(2*PI*i/1024)+
30*sin(2*PI*i*4/1024)+
50*cos(2*PI*i*8/1024)
几乎完全吻合。

STM32 FFT算法实现相关推荐

  1. STM32 FFT DMA ADC THD

    利用STM32 FFT算法计算THD 一.设备准备 -->粤嵌STM32F429IGT6开发板 1块 -->串口调试助手 二.FFT算法意义 使用FFT算法,是为了获取信号在频域的相关参数 ...

  2. FFT算法8点12位硬件实现 (verilog)

    FFT算法8点12位硬件实现 (verilog) 1 一.功能描述: 1 二.设计结构: 2 三.设计模块介绍 3 1.蝶形运算(第一级) 3 2.矢量角度旋转(W) 4 3.CORDIC 结果处理 ...

  3. FFT算法的完整DSP实现

    傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's Guide to Digita ...

  4. 大整数乘法---FFT算法

    //迭代FFT的乘法方法 // POJ 1405 Heritage /**  * input data mode:  *  the number array 1,2,3,4 use base U = ...

  5. matlab fft函数说明_【V2.0更新】基于FFT算法的MTALAB傅里叶级数3D可视化

    最近这份代码受到很多朋友关注,在此一并感谢!由于之前写1.0版本代码时的时间有限,当时的知识储备也不甚完善,所以只是做出了基本功能. 近期对这份代码进行了更新,优化了代码结构,并加入了FFT等算法让其 ...

  6. JavaScript实现快速傅立叶变换FFT算法(附完整源码)

    JavaScript实现快速傅立叶变换FFT算法(附完整源码) radianToDegree.js完整源代码 ComplexNumber.js完整源代码 bitLength.js完整源代码 fastF ...

  7. c代码实现 ifft运算_fft算法c语言_matlab fft算法_ifft c语言

    FFT快速算法C程序_工学_高等教育_教育专区.电子信息工程综合课程设计报告书 DSP 课程设计 报告 题学 目: 院: FFT 快速算法 C 程序 计算机与信息工程学院 09 ... fft算法代码 ...

  8. 模意义下的FFT算法

    //写在前面 单就FFT算法来说的话,下面只给出个人认为比较重要的推导,详细的介绍可参考 FFT算法学习笔记 令v[n]是长度为2N的实序列,V[k]表示该实序列的2N点DFT.定义两个长度为N的实序 ...

  9. FFT算法的完整DSP实现(转)

    源:FFT算法的完整DSP实现 傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's ...

  10. 基4fft算法的蝶形图_原地且自动整序的FFT算法

    传统的计算快速傅里叶变换的Cooley-Tukey算法效率极高,因其主要由蝶形运算构成,所以代码形式也非常简单,只是需要将输入或者输出按照位反转的方式重新排序. 这个重新排序的步骤并不是必须的.Cli ...

最新文章

  1. 我在兰亭这三年完结篇之离开
  2. mysql 打印_故障分析 | MySQL:5.6大事务show engine innodb status故障一例
  3. 点击输入框弹出文字html,jQuery实现点击文本框弹出热门标签的提示效果
  4. java main是多线程的吗_Java多线程之线程及其常用方法
  5. python持久化存储文件操作
  6. MAC OS上JAVA1.6 升级1.7,以及 maven3.2.1配置
  7. 深度学习的实用层面 —— 1.6 Dropout正则化
  8. QT Embedded二三事之QObject的元对象
  9. java --微信支付2
  10. 为什么null为对象,并且null和undefined有什么区别?
  11. Dxg——C# 开发笔记整理分类合集【所有的相关记录,都整理在此】
  12. 【转】程序员:如何写出杀手级简历
  13. 单片机流水单C语言程序,51单片机流水灯C语言源程序
  14. 反向题在测试问卷信效度_问卷信度效度检验
  15. ele input事件 输入后0.5秒触发
  16. 我要偷偷的学Python,然后惊呆所有人(第五天)
  17. java后端面试总结
  18. 机器学习——朴素贝叶斯分类
  19. js计算当前时间的为年的第几周,以及周对应的时间范围
  20. 计算机教师资格证难不难考,教师资格证 信息技术难考吗

热门文章

  1. RFID中的天线技术-应用及设计现状
  2. 一篇文章学会Yaml的语法超详细(建议收藏)
  3. 微波雷达智能感应模块,在智能面板上的技术应用
  4. ui自动化html模板,UI自动化学习分享ppt模板
  5. android 下载apk后如何安装程序,Android下载并安装APK
  6. win远程桌面连接服务器,WIN2016远程桌面服务器如何同时发布APP和桌面
  7. stm32连接热敏打印机
  8. 图书馆管理系统【SSM含SQL文件】
  9. STM32LED--基于HAL库(LCD与LED冲突?一文看懂如何精准劝架)
  10. linux 查看网口实时流速_Linux查看实时带宽流量情况