基於HAL庫的STM32的DSP庫詳解(附FFT應用)

廖偉偉發表於2020-11-30
1 . 建立工程,生成程式碼時選擇包含所有庫。
 
2. 開啟 option for target 選擇 Target 標籤,在code generatio中,將floating point hardware 選擇 USE Single Precision。
 
3.  開啟 option for target 選擇 C/C++ 標籤
在define後新增:__TARGET_FPU_VFP,ARM_MATH_MATRIX_CHECK,ARM_MATH_ROUNDING,ARM_MATH_CM4,__CC_ARM,由於使用HAL的庫,所以前面有USE_HAL_DRIVER,STM32F429xx的全域性巨集定義,如果使用的不是HAL庫,而是使用韌體庫的話,一般會有韌體庫的一個全域性巨集定義USE_STDPERIPH_DRIVER和STM32F4XXxx在裡面。所以當前只需要新增
__TARGET_FPU_VFP,
ARM_MATH_MATRIX_CHECK,
ARM_MATH_ROUNDING,
ARM_MATH_CM4,
__CC_ARM
注意中間用英文逗號分開。其中ARM_MATH_MATRIX_CHECK是庫函式的引數檢查開關。ARM_MATH_ROUNDING這個是庫函式在運算是是否開啟四捨五入的功能,可以根據實際需要進行配置。ARM_MATH_CM4這個就非常重要,必須要配置進去,否則在編譯之後,會預設使用math.h的庫函式,而不會用到硬體的FPU的。__CC_ARM是不同編譯器的編譯配置巨集定義,__CC_ARM就是代表MDK開發環境。
 4. 新增浮點庫(.lib)檔案到工程(或者新增原始碼庫檔案)。
如果用的是 uv4,開啟 C:\Keil\ARM\CMSIS\Lib\ARM 目錄,複製“arm_cortexM4lf_math.lib”檔案到你的工程下,並加入工程。
如果用的是 uv5,開啟 C:\Keil_v5\ARM\Pack\ARM\CMSIS\4.2.0\CMSIS\Lib\ARM 目錄,複製“arm_cortexM4lf_math.lib”檔案到工程下,並加入工程,4.2.0是庫的版本,每個版本可能不一樣。
也可以從官方下載韌體庫程式包中複製也行,  \STM32F4xx_DSP_StdPeriph_Lib\Libraries\CMSIS\Lib\ARM
如果檢視DSP庫的各個函式的原型,可以新增原始碼庫檔案, 則當前工程目錄下的Drivers\CMSIS\DSP_Lib\Source目錄可以檢視,當然安裝目錄下也有該庫原始檔。
BasicMathFunctions
基本數學函式:提供浮點數的各種基本運算函式,如向量加減乘除等運算。 
CommonTables
arm_common_tables.c檔案提供位翻轉或相關參數列。
ComplexMathFunctions
複雜數學功能,如向量處理,求模運算的。
ControllerFunctions
控制功能函式。包括正弦餘弦,PID電機控制,向量Clarke變換,向量Clarke逆變換等。
FastMathFunctions
快速數學功能函式。提供了一種快速的近似正弦,餘弦和平方根等相比CMSIS計算庫要快的數學函式。
FilteringFunctions
濾波函式功能,主要為FIR和LMS(最小均方根)等濾波函式。 
MatrixFunctions
矩陣處理函式。包括矩陣加法、矩陣初始化、矩陣反、矩陣乘法、矩陣規模、矩陣減法、矩陣轉置等函式。
StatisticsFunctions
統計功能函式。如求平均值、最大值、最小值、計算均方根RMS、計算方差/標準差等。
SupportFunctions
支援功能函式,如資料拷貝,Q格式和浮點格式相互轉換,Q任意格式相互轉換。
TransformFunctions
變換功能。包括複數FFT(CFFT)/複數FFT逆運算(CIFFT)、實數FFT(RFFT)/實數FFT逆運算(RIFFT)、和DCT(離散餘弦變換)和配套的初始化函式。
相關函式說明以及示例也可在安裝路徑Keil_v5\ARM\PACK\ARM\CMSIS\4.5.0\CMSIS\Documentation\DSP\html下獲得,自行查閱。
5. DSP庫的FFT變換示例。
在工程的main.c檔案中新增如下程式碼
說明:取樣頻率為1024Hz,fft點數為1024點,則頻率解析度,計算公式:解析度=取樣頻率/取樣點數 = 1Hz,此時能看到0Hz,1Hz,2Hz,3Hz,.....512Hz的頻率分量。
FFTOutput這個陣列中,下標0對應的元素就是0Hz(也就是直流分量)的幅度,下標1對應的就是1Hz的幅度,下標2對應2Hz的幅度......,依次類推。
此點非常重要,例如取樣率為2048Hz,那麼頻率解析度為2Hz,那麼能看到0Hz,2Hz,4Hz,6Hz,.....1024Hz的頻率分量
FFTOutput這個陣列中,下標0對應的元素就是0Hz(也就是直流分量)的幅度,下標1對應的就是2Hz的幅度,下標2對應4Hz的幅度......,依次類推。此時去看1Hz,3Hz,則會出現誤差比較大的情況。
#include "arm_math.h"                  //新增標頭檔案
#define  FFT_LENGTH        1024        //FFT長度,預設是1024點FFT
#define SAMPLE_FREQ 1024 //取樣頻率
float fft_inputbuf[FFT_LENGTH*2];      //FFT輸入輸出陣列,此陣列為arm_cfft_radix4_f32的輸入輸出陣列,前一個元素為實部,後一個為虛部,每兩個元素代表一個點.
float fft_outputbuf[FFT_LENGTH];    //arm_cmplx_mag_f32()幅度輸出陣列
arm_cfft_radix4_instance_f32 scfft; //fft變換的初始化引數

在主函式進入while(1)之前新增如下程式碼

說明:arm_sin_f32函式生成取樣點,取樣訊號為DC訊號,100Hz,150Hz訊號的疊加,此時解析度為1Hz,剛好能夠看到DC, 100Hz,150Hz頻率分量的幅度,分別對應fft幅度輸出陣列的下標0,100,150

arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//初始化scfft結構體,設定FFT相關引數
for(int i=0;i<FFT_LENGTH;i++)//生成訊號序列
{
fft_inputbuf[2*i]=15 + 10*arm_sin_f32(2*PI*i*100/SAMPLE_FREQ) + \
5.5*arm_sin_f32(2*PI*i*150/SAMPLE_FREQ); //生成實部
fft_inputbuf[2*i+1]=0;//虛部全部為0
}
arm_cfft_radix4_f32(&scfft,fft_inputbuf); //FFT計算(基4(即fft長度22*n),FFT長度只能為64,256,1024,4096目前測試過這幾個長度,)
arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH); //把運算結果複數求模得幅值

DC分量值為15360.001,則對應的直流分量為15360.001/FFT點數 = 15360.001/1024=15

100Hz分量值為5119.99658,則對應的100Hz幅度為5119.99658*2/FFT點數 = 5119.99658*2/1024=10

150Hz分量值為2815.99976,則對應的150Hz幅度為2815.99976*2/FFT點數 = 2815.99976*2/1024=5.5

其餘的頻率的幅度近似為0。

若要檢視某一頻率分量的實部與虛部,則可以檢視fft_inputbuf陣列。下標對應乘以2,因為實部和虛部存在。

當把取樣頻率改為2048Hz,生成訊號頻率其中一路改為151Hz,讀者可以自行測試該頻率分量的幅度,肯定會存在誤差。



相關文章