基于STM32F407实现离散傅里叶变换(FFT、DFT),计算指定频率的幅值

这篇具有很好参考价值的文章主要介绍了基于STM32F407实现离散傅里叶变换(FFT、DFT),计算指定频率的幅值。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:本人的课题是关于EIT采集系统设计,所谓的EIT,简单的说就是往人体注入特定频率的电流信号,通过采集反馈的电压信号,进而使用成像算法重构人体内部的阻抗分布。由于采集到的电压包含其它频率的热噪声,为了只保留注入频率的信号成分,需要对采集到的电压信号进行FFT处理。

在本文应用中,FFT相当于一个带通滤波器,用于获取指定频率的信号信息。关于快速傅里叶变化这里不做过多的介绍,具体可参考别人写的博客:

如何 FFT(快速傅里叶变换) 求幅度、频率(超详细 含推导过程)_Xav Zewen的博客

本文主要介绍如何在STM32F407上实现对特定频率进行FFT。重新更新并完善了一下,将代码整理为函数,方便读者调用。

一、使用DSP库进行FFT计算

1.1 DSP库开启

我们知道,相比于整形运算,浮点运算会大量消耗算力,若直接让STM32强行计算,难以满足实时性的需求。好在STM32F407是具有浮点运算(FPU)功能,可以通过MDK配置:target->Roating Point Hardware->Use Single Precison中打开。

stm32快速傅里叶变换,电阻抗成像,单片机,stm32,嵌入式硬件,Powered by 金山文档

在进行FFT计算时,我们还需要用到三角计算,因此我们还需要添加dsp数学库,调用库中的函数进行数学运算。DSP库的开启如下所示。

stm32快速傅里叶变换,电阻抗成像,单片机,stm32,嵌入式硬件,Powered by 金山文档

同时在MDK配置中添加头文件:ARM_MATH_CM4

stm32快速傅里叶变换,电阻抗成像,单片机,stm32,嵌入式硬件,Powered by 金山文档

 通过上述操作,我们便可进入编程环节。

1.2 调用DSP库进行FFT计算

那么,如何通过FFT变换,获取指定频率的幅值信息呢?下面举个例子:

目的:获取电压数据中10kHz的幅值分量

要求:待计算的频率、ADC的采样频率、采集样本量、数据点N 应该满足以下等式:

stm32快速傅里叶变换,电阻抗成像,单片机,stm32,嵌入式硬件,Powered by 金山文档

在STM32程序中,我们可以通过中断设定ADC的采样频率,进而配平上述等式。如定义一个1us定时器中断,在中断任务中执行一次ADC采集(此时采样频率为1MHz),一共采集1000次。

此时FFT的参数为:

        待计算的频率——10kHz

        ADC的采样频率——1MHz

        采集样本量——1000

配平上述式子,求得数据点 N = 10。

【注】 1. 若等式配不平,会导致频谱泄露,造成数据失真;

            2. 采样依旧要满足采样定理,即:ADC的采样频率 >2*电压数据中最大的频率分量;

            3. 由于FFT变换的特点,采集样本量为2的指数倍能提高计算速度。 

使用DSP库进行FFT变换的函数如下:


// FFT计算函数
// *DATA: 导入待FFT计算的原始数组指针
// num:采集样本量
// N:需要保存的第几个数据点
float FFT_Calculation(float *DATA, int num, int N)
{
    float array_FFT_output[num];        //储存FFT变换后的512个数据
    float array_arm_cmplx_mag[num];     //储存FFT变换后的512个数据的幅值信息

    arm_rfft_fast_instance_f32 S;
    arm_rfft_fast_init_f32(&S, fftSize);        //初始化结构体S中的参数
    arm_rfft_fast_f32(&S, array_f32, array_FFT_output, 0);          //fft正变换 
    arm_cmplx_mag_f32(array_FFT_output, array_arm_cmplx_mag, num);  //计算幅值  

    return array_arm_cmplx_mag[N];  
}    

下面简单的示范一下这个函数怎么使用:


float Data_FFT[1000];        // 待FFT计算的原始数据(读者自行赋值)
float result;

result = FFT_Calculation(Data_FFT,1000,10);    // 1000个采样点数,需要保存第10个频点

二、FFT算法的优化:使用DFT计算单一频点信息

虽然FFT计算十分方便,但是,当我们只需要单一频点数据时,FFT由于计算了大量的无效数据,消耗了算力。在上面的例子中,我们只需要获得10kHz的电压幅值,这时代码可以优化为离散型傅里叶变化(DFT)。离散型傅里叶变化的计算公式如下:

stm32快速傅里叶变换,电阻抗成像,单片机,stm32,嵌入式硬件,Powered by 金山文档

离散型傅里叶变换(DFT)的计算代码如下:


#include "arm_math.h"   // 代码中涉及了sin cos 计算, 需按1.1小节开启DSP库

// *Data: 导入待DFT计算的原始数组指针
// num:采集样本量
// N:需要保存的第几个数据点
float DFT_Calculation(float *Data, int num, int N)
{
        unsigned int i;
        float SUM_Re = 0;        //实频数值
        float SUM_Im = 0;        //虚频数值
        float result = 0;            // 计算结果
        
        //FFT展开式
        for(i=0;i<num;i++)
        {
            SUM_Re = SUM_Re + Data[i]*cos(2*3.1415926*N*i/num);
            SUM_Im = SUM_Im - Data[i]*sin(2*3.1415926*N*i/num);
        }

        //计算幅值
        result = sqrt(SUM_Re*SUM_Re + SUM_Im*SUM_Im);

        return result;
}

该函数的使用方法同FFT一致:

float Data_DFT[1000];        // 待DFT计算的原始数据(读者自行赋值)
float result;

result = DFT_Calculation(Data_DFT,1000,10);    // 1000个采样点数,需要保存第10个频点

经过测试,计算单一频点信息时,使用DFT算法相比于FFT,时间节省了约51%。

进一步提升

如果代码对于实时性有要求,在内存和算力的寸土寸金的单片机上,可以通过查表法,代替耗时的三角函数计算。

如上面的代码, cos(2*3.1415926*N*i/num) 和 sin(2*3.1415926*N*i/num) 的计算结果是固定值,可以提前计算出N=1000,k=10,i取0~999时的cos和sin值,在DFT计算是查询预先计算好的三角函数值,以节省算力。文章来源地址https://www.toymoban.com/news/detail-592632.html

到了这里,关于基于STM32F407实现离散傅里叶变换(FFT、DFT),计算指定频率的幅值的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于STM32F407的智能门锁

            在消费升级渗透在各个领域的今天,国民消费发生着巨大的变化,与每个人息息相关的家居行业也是如此。现今,越来越多的智能家居产品出现在普通老百姓的生活中,智能照明、智能窗帘、智能扫地机器人等各种智能产品都给人们的生活带来了极大的便利。智能

    2024年02月11日
    浏览(57)
  • 搭建STM32F407的Freertos系统(基于STM32CubeMX)

           本人长期开发Linux、Windows上应用软件,一直以来MCU开发有所接触,但较少(最近项目需要,小公司么,都得会,被逼的),好在有STM32CubeMX这样工具,貌似就是我想要的工具。         本次demo目标立下:         1. 搭建或移植FreeRTOS到STM32上,毕竟对于长期在Linux环境

    2024年02月10日
    浏览(51)
  • 基于stm32f407的示波器+FFT频谱分析

    1 设计思路 2 DMA传输ADC采样值 使用DMA直接将ADC-DR中的数据传输到ADC数据缓存区,节省cpu资源,高速AD采集,代码如下: 3 ADC定时器触发(可修改ADC采样率) 为了实现ADC采样率可调,我将AD的出发方式设置为定时器触发,使用TIM3来触发adc采集,首先初始化定时器,先预设几种初

    2024年02月05日
    浏览(44)
  • STM32CubeMX生成C代码及时钟树配置(基于stm32f407)

    近来对于stm32单片机编程中,HAL库逐渐取代标准库成为主流的库。标准库支持的芯片型号有限,而且目前已经停止支持,而HAL库支持所有类型的芯片,可移植性也很高,再加上有神器STM32Cube可以生成工程模板,越来越多的编程开始从使用标准库转到使用HAL库。 新建工程后,在

    2024年02月15日
    浏览(51)
  • stm32f407探索者开发板(二)——新建工程(基于固件库)

    说实话,我非常不想这篇文章,因为太长太长了,我看视频写都写了一个下午(虽然我下午一直在摸鱼,啊啊啊啊啊)害,不管了,赶紧开始写吧,不然今晚是写不完了,呜呜呜…… 把这个里面的文件放先给下好,我这里是没有光盘的,所以需要从百度网盘上下载好,这里面

    2023年04月08日
    浏览(73)
  • 基于STM32F407的俄罗斯方块小游戏的设计

        本文讲述的是基于STM32F407的俄罗斯方块小游戏的设计思路和测试结果,具体的代码分析见文章 基于STM32F407的俄罗斯方块游戏代码分析_钻仰弥坚的博客-CSDN博客 1.1 可行性分析 可行性分析能够对新系统进行各方面的分析与研究,确定新系统是否具有开发的可行性和必要性

    2024年02月11日
    浏览(42)
  • STM32F407实现1588v2(ptpd)

    硬件: STM32F407ZGT6开发板 软件: VSCode arm-none-eabi-gcc openOCD st-link 在github搜到一个在NUCLEO-F429ZI开发板上移植ptpd的example,因为和F407差别很小,所以就打算用这个demo移植到手头的开发板上。因为目前只需要slave,所以只调试了slave。据介绍,master好像原作者没有充分测试过。 源项

    2024年02月08日
    浏览(32)
  • 从STM32F407到AT32F407(一)

    雅特力公司的MCU有着性能超群,价格优越的巨大优势,缺点是相关资料少一些,我们可以充分利用ST的现有资源来开发它。 我用雅特力的STM32F437开发板,使用原子 stm32f407的开发板自带程序,测试串口程序,原设定串口波特率为115200,但是输出乱码,波特率改成230400,串口输

    2024年02月02日
    浏览(50)
  • STM32F407普通IO口模拟串口实现不定长数据收发

    因为项目中用到的串口比较多,STM32F407VET6自带的串口不够用了,所以只能考虑用模拟串口来实现功能。普通的IO口来模拟串口需要先了解串口的时序图,需要用到两个IO引脚即收发引脚,两个定时器,一个用于发送延时使用,一个用于产生中断接收数据。代码的初始化主要用

    2024年02月07日
    浏览(32)
  • STM32F407硬件I2C实现MPU6050通讯(CUBEIDE)

    工程代码 https://download.csdn.net/download/weixin_52849254/87886714 I2C1通道可选择三种不同的通讯协议:I2C、SMBus-Alert-mode、SMBus-two-wire-Interface。 SMBus (System Management Bus,系统管理总线), 为系统和电源管理这样的任务提供了一条控制总线,SMBus与I2C总线之间在时序特性上存在一些差别 修改

    2024年02月09日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包