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采樣率應遵循奈奎斯特采樣定理!采樣率不是越高越好!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM