https://blog.csdn.net/qq_38410730/article/details/90116695

摘自:https://blog.csdn.net/qq_38410730/article/details/90116695

https://blog.csdn.net/weixin_33700350/article/details/85678076

最近,因爲項目需要在STM32F103系列處理器上,對採集的音頻信號進行FFT運算,然而STM32F103畢竟不是STM32F4系列的處理器,對於一般的FFT運算程序還是比較緩慢的。

幸虧官方提供了針對FFT的官方庫,但是去官網找了半天居然找不到那個庫的下載,好像官方早就把那個庫下架了,估計是爲了給帶DSP指令集的F4系列讓路。然後就只好從別人的項目中把這個官方庫給扒出來了……

下載地址:https://pan.baidu.com/s/1GiUJgEkQxDAk79iddXKsaA 提取碼: dn2d

FFT的意義

對於很多人來說,採樣頻率和FFT點數之間的關係可能還是不太清楚。下面就來簡單分析一下:

根據採樣定理,採樣頻率必須是被採樣信號最高頻率的2倍。比如,需要採集音頻信號,並且需要被觀察到的音頻頻率的頻率範圍是20Hz到20KHz,那麼使用的採樣頻率就必須大於40kHz。如果需要觀察到的音頻頻率範圍爲0Hz到600Hz,那麼使用的採樣頻率只需要大於1200Hz即可。

而FFT點數與採樣頻率之間有什麼關係呢?本質上並沒有什麼關係,但是FFT點數的大小直接關係到頻率分辨率。怎麼來說呢?

假設採樣頻率爲Fs,信號頻率F,採樣點數爲N。那麼FFT之後結果就是一個爲N點的複數。每一個點就對應着一個頻率點。這個點的模值,就是該頻率值下的幅度特性。同時,FFT後的N個點,開始的那個點表示直流分量(即0Hz),而最後的那個點的再下一個點表示採樣頻率Fs,這中間被N-1個點平均分成N等份,每個點的頻率依次增加。即,某點n所表示的頻率爲:Fn=(n-1)*Fs/N。這就表示,Fs/N就是頻率分辨率。

不太理解的,可以查看博客:FFT後的物理意義。

FFT官方庫的使用條件

    FFT官方庫在使用上並不靈活:屬於基4的FFT,即FFT點數必須是4^n。也就是說,如果要做512點或2048點的FFT,那麼對不起,沒法使用官方庫了;
    FFT官方庫的輸入輸出是等長的,即256點的FFT輸入也必須是256點,如果你的輸入小於這個長度,是沒有任何性能提升的。

FFT官方庫的使用
準備工作

下載得到STM32的DSP庫之後,就可以將其添加到自己的工程項目中了。

其中,stm32_dsp.h和table_fft.h兩個文件是必須添加的。stm32_dsp.h是STM32的DSP庫的頭文件。

另外,對於**.s文件可以有選擇的添加**(用到那個添加那個即可)。由於本文只用到了256點的FFT,所以這裏只添加了cr4_fft_256_stm32.s文件。
FFT函數說明

進行256點的FFT,只需要調用STM32 DSP庫函數中的cr4_fft_256_stm32()函數即可。該函數的原型爲:

void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin);

    1

其中,參數pssOUT表示FFT輸出數組指針,參數pssIN表示要進行FFT運算的輸入數組指針,參數Nbin表示了點數。至於該函數的具體實現,因爲是用匯編語言編寫的,我也不懂,這裏就不妄談了。

需要說明的是:按照FFT官方庫的說明,pssOUT和pssIN都必須是32位的數據類型,其中高16位存儲實部,低16位存儲虛部。對於pssIN來說,低16位存儲的虛部總是爲0。
代碼實例

假設ADC採樣的聲音數據爲adc_buf[NPT],FFT運算的輸入數組爲lBufInArray[NPT]。由於FFT計算出來的數據是對稱的,因此通常而言輸出數組取一半的數據,爲lBufOutArray[NPT/2]。除此之外,還定義各次諧波幅值lBufMagArray[NPT/2]。即:

#define NPT 256

uint32_t adc_buf[NPT]={0};
long lBufInArray[NPT];
long lBufOutArray[NPT/2];
long lBufMagArray[NPT/2];

    1
    2
    3
    4
    5
    6

調用FFT官方庫的代碼爲:

//填充數組
for(i=0;i<NPT;i++)
    //這裏因爲單片機的ADC只能測正的電壓 所以需要前級加直流偏執
    //加入直流偏執後,需要在軟件上減去2048即一半,達到負半週期測量的目的(需要根據具體情況來進行配置)
    lBufInArray[i] = ((signed short)(adc_buf[i]-2048)) << 16;
    
cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT);

    1
    2
    3
    4
    5
    6
    7

同時,計算各次諧波幅值的函數爲:

void GetPowerMag()
{
    signed short lX,lY;
    float X,Y,Mag;
    unsigned short i;
    for(i=0; i<NPT/2; i++)
    {
        lX  = (lBufOutArray[i] << 16) >> 16;
        lY  = (lBufOutArray[i] >> 16);
        
        //除以32768再乘65536是爲了符合浮點數計算規律
        X = NPT * ((float)lX) / 32768;
        Y = NPT * ((float)lY) / 32768;
        Mag = sqrt(X * X + Y * Y) / NPT;
        if(i == 0)
            lBufMagArray[i] = (unsigned long)(Mag * 32768);
        else
            lBufMagArray[i] = (unsigned long)(Mag * 65536);
    }
}

————————————————
版權聲明:本文爲CSDN博主「Yngz_Miao」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_38410730/article/details/90116695

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章