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的头文件,需要根据情况进行修改,比如说用其他型号板子或者其他库开发的记得要修改,不然编译时会报错

  • 算法解释
//进行FFT运算等操作
void FFT_Wave(void)
{
  u16 i;
  float mid_value;
  while(!ADC_flag)
  {
    LED1 = !LED1;
    delay_ms(100);
  }
  ADC_flag = 0;

  //获取最大值最小值
  adc_value_max = adc_value_min = ADC_buff[1];
  for(i = 0;i < NPT;i++)
  {
    //寻找最大值最小值
    if(ADC_buff[i] >= adc_value_max)
    {
      adc_value_max = ADC_buff[i];
    }
    if(ADC_buff[i] <= adc_value_min)
    {
      adc_value_min = ADC_buff[i];
    }
    //先清空数组
    fftin[i] = 0;
    //移位,让后面16位为虚部
    fftin[i] = ((s16)ADC_buff[i] << 16);
  }
  cr4_fft_1024_stm32(fftout,fftin,1024);//FFT
  GetPowerMag();
  //计算电压值
  Vpp_true = (adc_value_max - adc_value_min) * 3.3 / 4096.0;//获得Vpp值
  mid_value = (adc_value_max + adc_value_min) / 2;
  for(int i = 0;i < NPT;i++)
  {
    if(ADC_buff[i] > mid_value)
    {
      rect_duty++;
    }
  }
  rect_duty = rect_duty / 1024 * 100;
}

这是FFT的主体函数

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

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

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

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

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

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

GetPowerMag函数定义如下:

void GetPowerMag(void)
{
  s16 lX,lY;
  u32 i;
  float maxmag;
  for(i = 0;i < NPT / 2;i++)
  {
    lX = (fftout[i] << 16) >> 16;
    lY = (fftout[i] >> 16);
    float X = 1024 * ((float)lX) / 32768;
    float Y = 1024 * ((float)lY) / 32768;
    float mag = sqrt(X * X + Y * Y) / 1024;
    FFT_Mag[i] = (u32)(mag * 65536);
  }
  FFT_Mag[0] >>= 1;//频谱图第一个是直流分量,无需乘2
  for(int i = 0;i < NPT / 2;i++)
  {
    if((maxmag < FFT_Mag[i]) && (i != 0))
    {
      maxmag = FFT_Mag[i];
      temp = i;
    }
  }
  F_hz = temp * sampling_rate / 1024.0;
}

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

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

特别提醒:ADC采样率应遵循奈奎斯特采样定理!采样率不是越高越好(因为采样率太高会降低采样的精度,采样率太低会导致高频信号发生混叠现象)!

这个是上面用到的汇编文件的百度盘分享链接,失效了可以私聊cue我更新

链接:https://pan.baidu.com/s/1n8Hl09SmLhp963-vYbA2iw?pwd=1234 
提取码:1234 

  • 19
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

砕月之殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值