• stm32F103RCT6使用FFT运算分析波形详解(非常新手)


    最近学校电赛院队招新,出的招新题就是低频示波器的。之前一直没有弄懂FFT,借着这次机会实现了一下。

    • FFT原理详解

      FFT,就是快速傅里叶变换,这个操作能够将时域信号转化成频域信号,然后对信号进行分析

      这样说可能有点抽象。讲细点就是指能够直观的看出来目标信号的频率是多少。x轴坐标本来是表示时间,FFT之后变成了表示频率,就是这个意思

      对于信号处理,FFT之后的结果,波峰一般会出现在我们希望测得信号的频率附近(十分相近)

    • 官方文件解释

    stm32官方给了几个用于处理FFT的文件,如图所示:

     

     

     其中有两个汇编文件两个头文件:汇编文件是定义了FFT的计算函数,我们直接调用即可

    cr4_fft_1024_stm32.s是包含了计算1024个点的FFT的函数的汇编文件,另一个汇编文件同理

    stm32_dsp.h里面有关于FFT处理函数的声明,我们包含了这个头文件之后直接调用函数即可

    补充:stm32_dsp.h当中有一个include的头文件,需要根据情况进行修改,比如说用其他型号板子或者其他库开发的记得要修改,不然编译时会报错

    • 算法解释
    复制代码
     1 //进行FFT运算等操作
     2 void FFT_Wave(void)
     3 {
     4   u16 i;
     5   float mid_value;
     6   while(!ADC_flag)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
     7   {
     8     LED1 = !LED1;
     9     delay_ms(100);
    10   }
    11   ADC_flag = 0;
    12   
    13   //获取最大值最小值
    14   adc_value_max = adc_value_min = ADC_buff[1];
    15   for(i = 0;i < NPT;i++)
    16   {
    17     //寻找最大值最小值
    18     if(ADC_buff[i] >= adc_value_max)
    19     {
    20       adc_value_max = ADC_buff[i];
    21     }
    22     if(ADC_buff[i] <= adc_value_min)
    23     {
    24       adc_value_min = ADC_buff[i];
    25     }
    26     //先清空数组
    27     fftin[i] = 0;
    28     //移位,让后面16位为虚部
    29     fftin[i] = ((s16)ADC_buff[i] << 16);
    30   }
    31   cr4_fft_1024_stm32(fftout,fftin,1024);//FFT
    32   GetPowerMag();
    33   //计算电压值
    34   Vpp_true = (adc_value_max - adc_value_min) * 3.3 / 4096.0;//获得Vpp值
    35   mid_value = (adc_value_max + adc_value_min) / 2;
    36   for(int i = 0;i < NPT;i++)
    37   {
    38     if(ADC_buff[i] > mid_value)
    39     {
    40       rect_duty++;
    41     }
    42   }
    43   rect_duty = rect_duty / 1024 * 100;
    44 }
    复制代码

    这是FFT的主体函数

    第一步我们先要等待ADC采集完成,将数据存入数组当中准备进行处理

     第二步是在采样值当中寻找最大值和最小值(遍历数组即可)

    第三步是对数组进行移位处理(前面的是实部,后面的是虚部,由于我们采集到的电压都是实数,所以虚部都置0)

    第四步是使用ST官方提供的函数进行FFT运算,得到运算之后的数组

    第五步是根据频谱查找我们信号所对应的频率,也就是对频谱图当中所有的频率进行幅值的比较,找出幅值最大时所对应的频率,即为我们所需要测量的频率,其他的都可以看作噪声

    在我们找到该频率之后,不能立刻输出,要与ADC的采样率相乘再除以1024,之后才能得到我们想要的信号频率

    GetPowerMag函数定义如下:

    复制代码
     1 void GetPowerMag(void)
     2 {
     3   s16 lX,lY;
     4   u32 i;
     5   float maxmag;
     6   for(i = 0;i < NPT / 2;i++)
     7   {
     8     lX = (fftout[i] << 16) >> 16;
     9     lY = (fftout[i] >> 16);
    10     float X = 1024 * ((float)lX) / 32768;
    11     float Y = 1024 * ((float)lY) / 32768;
    12     float mag = sqrt(X * X + Y * Y) / 1024;
    13     FFT_Mag[i] = (u32)(mag * 65536);
    14   }
    15   FFT_Mag[0] >>= 1;//频谱图第一个是直流分量,无需乘2
    16   for(int i = 0;i < NPT / 2;i++)
    17   {
    18     if((maxmag < FFT_Mag[i]) && (i != 0))
    19     {
    20       maxmag = FFT_Mag[i];
    21       temp = i;
    22     }
    23   }
    24   F_hz = temp * sampling_rate / 1024.0;
    25 }
    复制代码

    至此,我们就得到了我们所需信号的频率

    鉴于本小白能力有限,如果有纰漏或改进之处,欢迎指正

    特别提醒:ADC采样率应遵循奈奎斯特采样定理!采样率不是越高越好!

  • 相关阅读:
    梨花声音研修院,严肃与刚毅是音色核心
    Unity 从0开始编写一个技能编辑器_01_分析需求
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java星光之夜香水网站的设计与开发bfmcr
    2020年7月大学英语六级作文
    实现二叉树先序,中序和后序遍历
    康威定律对于系统架构很重要吗?
    电脑扬声器未插入?4个方法帮你恢复声音!
    flutter逆向 ACTF native app
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    2023大数据挑战赛全国六强团队获奖经验+ppt分享(二)
  • 原文地址:https://www.cnblogs.com/Edwardssss/p/16151668.html