【STM32HF429的DSP教程】第40章 STM32F429的FIR带阻滤波器实现(支持逐个数据的实时滤波)
完整版教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547
第40章?????? STM32F429的FIR帶阻濾波器實(shí)現(xiàn)(支持逐個(gè)數(shù)據(jù)的實(shí)時(shí)濾波)
本本章節(jié)講解FIR帶阻濾波器實(shí)現(xiàn)。
目錄
40.1 初學(xué)者重要提示
40.2 帶阻濾波器介紹
40.3 FIR濾波器介紹
40.4 Matlab工具箱filterDesinger生成帶阻濾波器C頭文件
40.5 FIR帶通濾波器設(shè)計(jì)
40.5.1??????? 函數(shù)arm_fir_init_f32
40.5.2 函數(shù)arm_fir_f32
40.5.3 filterDesigner獲取帶阻濾波器系數(shù)
40.5.4 帶阻濾波器實(shí)現(xiàn)
40.6 實(shí)驗(yàn)例程說(shuō)明(MDK)
40.7 實(shí)驗(yàn)例程說(shuō)明(IAR)
40.8 總結(jié)
40.1 初學(xué)者重要提示
?1、 本章節(jié)提供的帶阻濾波器支持實(shí)時(shí)濾波,每次可以濾波一個(gè)數(shù)據(jù),也可以多個(gè)數(shù)據(jù),不限制大小。但要注意以下兩點(diǎn):
- ? 所有數(shù)據(jù)是在同一個(gè)采樣率下依次采集的數(shù)據(jù)。
- ? 每次過(guò)濾數(shù)據(jù)個(gè)數(shù)一旦固定下來(lái),運(yùn)行中不可再修改。
2、? FIR濾波器的群延遲是一個(gè)重要的知識(shí)點(diǎn),詳情在本教程第41章有詳細(xì)說(shuō)明。
40.2 帶阻濾波器介紹
減弱一個(gè)范圍內(nèi)的頻率信號(hào)通過(guò),讓范圍之外的頻率信號(hào)通過(guò)。比如混合信號(hào)含有50Hz + 200Hz + 400Hz信號(hào),我們可通過(guò)帶通濾波器,讓50Hz + 400Hz信號(hào)通過(guò),而阻止200Hz信號(hào)通過(guò)。
40.3 FIR濾波器介紹
ARM官方提供的FIR庫(kù)支持Q7,Q15,Q31和浮點(diǎn)四種數(shù)據(jù)類型。其中Q15和Q31提供了快速算法版本。
FIR濾波器的基本算法是一種乘法-累加(MAC)運(yùn)行,輸出表達(dá)式如下:
y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[numTaps-1] * x[n-numTaps+1]
結(jié)構(gòu)圖如下:
?
這種網(wǎng)絡(luò)結(jié)構(gòu)就是在35.2.1小節(jié)所講的直接型結(jié)構(gòu)。
40.4 Matlab工具箱filterDesinger生成帶阻濾波器C頭文件
下面我們講解下如何通過(guò)filterDesigner工具生成C頭文件,也就是生成濾波器系數(shù)。首先在matlab的命窗口輸入filterDesigner就能打開這個(gè)工具箱:
filterDesigner界面打開效果如下:
FIR濾波器的低通,高通,帶通,帶阻濾波的設(shè)置會(huì)在后面逐個(gè)講解,這里重點(diǎn)介紹設(shè)置后相應(yīng)參數(shù)后如何生成濾波器系數(shù)。參數(shù)設(shè)置好以后點(diǎn)擊如下按鈕:
點(diǎn)擊Design Filter按鈕以后就生成了所需的濾波器系數(shù),生成濾波器系數(shù)以后點(diǎn)擊filterDesigner界面上的菜單Targets->Generate C header ,打開后顯示如下界面:
然后點(diǎn)擊Generate,生成如下界面:
再點(diǎn)擊保存,并打開fdatool.h文件,可以看到生成的系數(shù):
/** Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool* Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0.* Generated on: 20-Jul-2021 12:19:30*//** Discrete-Time FIR Filter (real)* -------------------------------* Filter Structure : Direct-Form FIR* Filter Length : 51* Stable : Yes* Linear Phase : Yes (Type 1)*//* General type conversion for MATLAB generated C-code */ #include "tmwtypes.h" /* * Expected path to tmwtypes.h * D:\Program Files\MATLAB\R2018a\extern\include\tmwtypes.h */ /** Warning - Filter coefficients were truncated to fit specified data type. * The resulting response may not match generated theoretical response.* Use the Filter Design & Analysis Tool to design accurate* single-precision filter coefficients.*/ const int BL = 51; const real32_T B[51] = {-0.0009190982091, -0.00271769613,-0.002486952813, 0.003661438357, 0.0136509249,0.01735116541, 0.00766530633,-0.006554719061,-0.007696784101, 0.006105459295,0.01387391612,0.0003508617228, -0.01690892503,-0.008905642666, 0.01744112931,0.02074504457, -0.0122964941, -0.03424086422,-0.001034529647, 0.04779030383,0.02736303769, -0.05937951803, -0.08230702579, 0.06718690693, 0.3100151718,0.4300478697, 0.3100151718, 0.06718690693, -0.08230702579, -0.05937951803,0.02736303769, 0.04779030383,-0.001034529647, -0.03424086422, -0.0122964941,0.02074504457, 0.01744112931,-0.008905642666, -0.01690892503,0.0003508617228,0.01387391612, 0.006105459295,-0.007696784101,-0.006554719061, 0.00766530633,0.01735116541, 0.0136509249, 0.003661438357,-0.002486952813, -0.00271769613,-0.0009190982091 };上面數(shù)組B[51]中的數(shù)據(jù)就是濾波器系數(shù)。下面小節(jié)講解如何使用filterDesigner配置FIR低通,高通,帶通和帶阻濾波。關(guān)于Filter Designer的其它用法,大家可以在matlab命令窗口中輸入help filterDesigner打開幫助文檔進(jìn)行學(xué)習(xí)。
?
40.5 FIR帶通濾波器設(shè)計(jì)
本章使用的FIR濾波器函數(shù)是arm_fir_f32。使用此函數(shù)可以設(shè)計(jì)FIR低通,高通,帶通和帶阻
濾波器。
40.5.1??????? 函數(shù)arm_fir_init_f32
函數(shù)原型:
void arm_fir_init_f32(arm_fir_instance_f32 * S,uint16_t numTaps,const float32_t * pCoeffs,float32_t * pState,uint32_t blockSize);函數(shù)描述:
這個(gè)函數(shù)用于FIR初始化。
函數(shù)參數(shù):
- ? 第1個(gè)參數(shù)是arm_fir_instance_f32類型結(jié)構(gòu)體變量。
- ? 第2個(gè)參數(shù)是濾波器系數(shù)的個(gè)數(shù)。
- ? 第3個(gè)參數(shù)是濾波器系數(shù)地址。
- ? 第4個(gè)參數(shù)是緩沖狀態(tài)地址。
- ? 第5個(gè)參數(shù)是每次處理的數(shù)據(jù)個(gè)數(shù),最小可以每次處理1個(gè)數(shù)據(jù),最大可以每次全部處理完。
注意事項(xiàng):
結(jié)構(gòu)體arm_fir_instance_f32的定義如下(在文件arm_math.h文件):
typedef struct{uint16_t numTaps; /**< number of filter coefficients in the filter. */ float32_t *pState; /**< points to the state variable array. The array is of length */numTaps+blockSize-1. float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */} arm_fir_instance_f32;1、參數(shù)pCoeffs指向?yàn)V波因數(shù),濾波因數(shù)數(shù)組長(zhǎng)度為numTaps。但要注意pCoeffs指向的濾波因數(shù)應(yīng)該按照如下的逆序進(jìn)行排列:
{b[numTaps-1], ?b[numTaps-2], ?b[N-2], ?..., ?b[1], ?b[0]}?
但滿足線性相位特性的FIR濾波器具有奇對(duì)稱或者偶對(duì)稱的系數(shù),偶對(duì)稱時(shí)逆序排列還是他本身。
2、pState指向狀態(tài)變量數(shù)組,這個(gè)數(shù)組用于函數(shù)內(nèi)部計(jì)算數(shù)據(jù)的緩存。
3、blockSize 這個(gè)參數(shù)的大小沒有特殊要求,最小可以每次處理1個(gè)數(shù)據(jù),最大可以每次全部處理完。
40.5.2 函數(shù)arm_fir_f32
函數(shù)原型:
void arm_fir_f32( const arm_fir_instance_f32 * S, const float32_t * pSrc, float32_t * pDst, uint32_t blockSize)函數(shù)描述:
這個(gè)函數(shù)用于FIR濾波。
函數(shù)參數(shù):
- ? 第1個(gè)參數(shù)是arm_fir_instance_f32類型結(jié)構(gòu)體變量。
- ? 第2個(gè)參數(shù)是源數(shù)據(jù)地址。
- ? 第3個(gè)參數(shù)是濾波后的數(shù)據(jù)地址。
- ? 第4個(gè)參數(shù)是每次調(diào)用處理的數(shù)據(jù)個(gè)數(shù),最小可以每次處理1個(gè)數(shù)據(jù),最大可以每次全部處理完。
40.5.3 filterDesigner獲取帶阻濾波器系數(shù)
設(shè)計(jì)一個(gè)如下的例子:
信號(hào)由50Hz正弦波和200Hz正弦波組成,采樣率1Kbps,現(xiàn)設(shè)計(jì)一個(gè)帶阻濾波器,截止頻率125Hz和300Hz,采樣1024個(gè)數(shù)據(jù),采用函數(shù)fir1進(jìn)行設(shè)計(jì)(注意這個(gè)函數(shù)是基于窗口的方法設(shè)計(jì)FIR濾波,默認(rèn)是hamming窗),濾波器階數(shù)設(shè)置為28。filterDesigner的配置如下:
配置好帶阻濾波器后,具體濾波器系數(shù)的生成大家參考本章第4小節(jié)的方法即可。
40.5.4 帶阻濾波器實(shí)現(xiàn)
通過(guò)工具箱filterDesigner獲得低通濾波器系數(shù)后在開發(fā)板上運(yùn)行函數(shù)arm_fir_f32 來(lái)測(cè)試帶阻濾波器的效果。
#define TEST_LENGTH_SAMPLES 1024 /* 采樣點(diǎn)數(shù) */ #define BLOCK_SIZE 1 /* 調(diào)用一次arm_fir_f32處理的采樣點(diǎn)個(gè)數(shù) */ #define NUM_TAPS 29 /* 濾波器系數(shù)個(gè)數(shù) */uint32_t blockSize = BLOCK_SIZE; uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要調(diào)用arm_fir_f32的次數(shù) */static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 采樣點(diǎn) */ static float32_t testOutput[TEST_LENGTH_SAMPLES]; /* 濾波后的輸出 */ static float32_t firStateF32[BLOCK_SIZE + NUM_TAPS - 1]; /* 狀態(tài)緩存,大小numTaps + blockSize - 1*//* 帶阻濾波器系數(shù) 通過(guò)fadtool獲取*/ const float32_t firCoeffs32BS[NUM_TAPS] = {-0.003560454352f, -0.0002683042258f, 0.001964005642f, -0.001277366537f, 0.008085897192f,0.02002927102f, -0.01026879996f, -0.03190089762f, -0.001673383522f, -0.0334023945f,-0.06278027594f, 0.1240097657f, 0.2419839799f, -0.07700803876f, 0.6521340013f,-0.07700803876f, 0.2419839799f, 0.1240097657f, -0.06278027594f, -0.0334023945f,-0.001673383522f, -0.03190089762f, -0.01026879996f, 0.02002927102f, 0.008085897192f,-0.001277366537f, 0.001964005642f, -0.0002683042258f, -0.003560454352f };/* ********************************************************************************************************* * 函 數(shù) 名: arm_fir_f32_lp * 功能說(shuō)明: 調(diào)用函數(shù)arm_fir_f32_lp實(shí)現(xiàn)低通濾波器 * 形 參:無(wú) * 返 回 值: 無(wú) ********************************************************************************************************* */ static void arm_fir_f32_lp(void) {uint32_t i;arm_fir_instance_f32 S;float32_t *inputF32, *outputF32;/* 初始化輸入輸出緩存指針 */inputF32 = &testInput_f32_50Hz_200Hz[0];outputF32 = &testOutput[0];/* 初始化結(jié)構(gòu)體S */arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32BS[0], &firStateF32[0], blockSize);/* 實(shí)現(xiàn)FIR濾波,這里每次處理1個(gè)點(diǎn) */for(i=0; i < numBlocks; i++){arm_fir_f32(&S, inputF32 + (i * blockSize), outputF32 + (i * blockSize), blockSize);}/* 打印濾波后結(jié)果 */for(i=0; i<TEST_LENGTH_SAMPLES; i++){printf("%f, %f\r\n", testOutput[i], inputF32[i]);}}運(yùn)行如上函數(shù)可以通過(guò)串口打印出函數(shù)arm_fir_f32濾波后的波形數(shù)據(jù),下面通過(guò)Matlab繪制波形來(lái)對(duì)比Matlab計(jì)算的結(jié)果和ARM官方庫(kù)計(jì)算的結(jié)果。
對(duì)比前需要先將串口打印出的一組數(shù)據(jù)加載到Matlab中, arm_fir_f32的計(jì)算結(jié)果起名sampledata,加載方法在前面的教程中已經(jīng)講解過(guò),這里不做贅述了。Matlab中運(yùn)行的代碼如下:
%**************************************************************************************** % FIR帶阻濾波器設(shè)計(jì) %*************************************************************************************** fs=1000; %設(shè)置采樣頻率 1K N=1024; %采樣點(diǎn)數(shù) n=0:N-1; t=n/fs; %時(shí)間序列 f=n*fs/N; %頻率序列x=sin(2*pi*50*t)+sin(2*pi*200*t); %50Hz和200Hz正弦波混合 b=fir1(28, [125/500 300/500], 'stop'); %獲得濾波器系數(shù),截止頻率125Hz和300,帶阻濾波。 y=filter(b, 1, x); %獲得濾波后的波形 subplot(211); plot(t, y); title('Matlab FIR濾波后的實(shí)際波形'); grid on;subplot(212); plot(t, sampledata); %繪制ARM官方庫(kù)濾波后的波形。 title('ARM官方庫(kù)濾波后的實(shí)際波形'); grid on;Matlab運(yùn)行結(jié)果如下:
從上面的波形對(duì)比來(lái)看,matlab和函數(shù)arm_fir_f32計(jì)算的結(jié)果基本是一致的。為了更好的說(shuō)明濾波效果,下面從頻域的角度來(lái)說(shuō)明這個(gè)問(wèn)題,Matlab上面運(yùn)行如下代碼:
%**************************************************************************************** % FIR帶阻濾波器設(shè)計(jì) %*************************************************************************************** fs=1000; %設(shè)置采樣頻率 1K N=1024; %采樣點(diǎn)數(shù) n=0:N-1; t=n/fs; %時(shí)間序列 f=n*fs/N; %頻率序列x=sin(2*pi*50*t)+sin(2*pi*200*t); %50Hz和200Hz正弦波混合 subplot(221); plot(t, x); %繪制信號(hào)x的波形 xlabel('時(shí)間'); ylabel('幅值'); title('原始信號(hào)'); grid on;subplot(222); y=fft(x, N); %對(duì)信號(hào)x做FFT plot(f,abs(y)); xlabel('頻率/Hz'); ylabel('振幅'); title('原始信號(hào)FFT'); grid on;y3=fft(sampledata, N); %經(jīng)過(guò)FIR濾波器后得到的信號(hào)做FFT subplot(223); plot(f,abs(y3)); xlabel('頻率/Hz'); ylabel('振幅'); title('濾波后信號(hào)FFT'); grid on;b=fir1(28, [125/500 300/500], 'stop'); %獲得濾波器系數(shù),截止頻率125Hz和300Hz,帶阻濾波。 [H,F]=freqz(b,1,160); %通過(guò)fir1設(shè)計(jì)的FIR系統(tǒng)的頻率響應(yīng) subplot(224); plot(F/pi,abs(H)); %繪制幅頻響應(yīng) xlabel('歸一化頻率'); title(['Order=',int2str(28)]); grid on;Matlab顯示效果如下:
上面波形變換前的FFT和變換后FFT可以看出,200Hz的正弦波基本被濾除。
40.6 實(shí)驗(yàn)例程說(shuō)明(MDK)
配套例子:
V6-228_FIR帶阻濾波器設(shè)計(jì)(支持逐個(gè)數(shù)據(jù)的實(shí)時(shí)濾波)
實(shí)驗(yàn)?zāi)康?#xff1a;
實(shí)驗(yàn)內(nèi)容:
使用AC6注意事項(xiàng)
特別注意附件章節(jié)C的問(wèn)題
上電后串口打印的信息:
波特率 115200,數(shù)據(jù)位 8,奇偶校驗(yàn)位無(wú),停止位 1。
RTT方式打印信息:
程序設(shè)計(jì):
? 系統(tǒng)棧大小分配:
? 硬件外設(shè)初始化
硬件外設(shè)的初始化是在 bsp.c 文件實(shí)現(xiàn):
/* ********************************************************************************************************* * 函 數(shù) 名: bsp_Init * 功能說(shuō)明: 初始化所有的硬件設(shè)備。該函數(shù)配置CPU寄存器和外設(shè)的寄存器并初始化一些全局變量。只需要調(diào)用一次 * 形 參:無(wú) * 返 回 值: 無(wú) ********************************************************************************************************* */ void bsp_Init(void) {/* STM32F429 HAL 庫(kù)初始化,此時(shí)系統(tǒng)用的還是F429自帶的16MHz,HSI時(shí)鐘:- 調(diào)用函數(shù)HAL_InitTick,初始化滴答時(shí)鐘中斷1ms。- 設(shè)置NVIC優(yōu)先級(jí)分組為4。*/HAL_Init();/* 配置系統(tǒng)時(shí)鐘到168MHz- 切換使用HSE。- 此函數(shù)會(huì)更新全局變量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/* Event Recorder:- 可用于代碼執(zhí)行時(shí)間測(cè)量,MDK5.25及其以上版本才支持,IAR不支持。- 默認(rèn)不開啟,如果要使能此選項(xiàng),務(wù)必看V5開發(fā)板用戶手冊(cè)第8章*/ #if Enable_EventRecorder == 1 /* 初始化EventRecorder并開啟 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); #endifbsp_InitKey(); /* 按鍵初始化,要放在滴答定時(shí)器之前,因?yàn)榘粹o檢測(cè)是通過(guò)滴答定時(shí)器掃描 */bsp_InitTimer(); /* 初始化滴答定時(shí)器 */bsp_InitUart(); /* 初始化串口 */bsp_InitExtIO(); /* 初始化擴(kuò)展IO */bsp_InitLed(); /* 初始化LED */ }? 主功能:
主程序?qū)崿F(xiàn)如下操作:
- ? 啟動(dòng)一個(gè)自動(dòng)重裝軟件定時(shí)器,每100ms翻轉(zhuǎn)一次LED2。
- ? 按下按鍵K1,打印原始波形數(shù)據(jù)和濾波后的波形數(shù)據(jù)。
40.7 實(shí)驗(yàn)例程說(shuō)明(IAR)
配套例子:
V6-228_FIR帶阻濾波器設(shè)計(jì)(支持逐個(gè)數(shù)據(jù)的實(shí)時(shí)濾波)
實(shí)驗(yàn)?zāi)康?#xff1a;
實(shí)驗(yàn)內(nèi)容:
上電后串口打印的信息:
波特率 115200,數(shù)據(jù)位 8,奇偶校驗(yàn)位無(wú),停止位 1。
RTT方式打印信息:
程序設(shè)計(jì):
? 系統(tǒng)棧大小分配:
? 硬件外設(shè)初始化
硬件外設(shè)的初始化是在 bsp.c 文件實(shí)現(xiàn):
/* ********************************************************************************************************* * 函 數(shù) 名: bsp_Init * 功能說(shuō)明: 初始化所有的硬件設(shè)備。該函數(shù)配置CPU寄存器和外設(shè)的寄存器并初始化一些全局變量。只需要調(diào)用一次 * 形 參:無(wú) * 返 回 值: 無(wú) ********************************************************************************************************* */ void bsp_Init(void) {/* STM32F429 HAL 庫(kù)初始化,此時(shí)系統(tǒng)用的還是F429自帶的16MHz,HSI時(shí)鐘:- 調(diào)用函數(shù)HAL_InitTick,初始化滴答時(shí)鐘中斷1ms。- 設(shè)置NVIC優(yōu)先級(jí)分組為4。*/HAL_Init();/* 配置系統(tǒng)時(shí)鐘到168MHz- 切換使用HSE。- 此函數(shù)會(huì)更新全局變量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/* Event Recorder:- 可用于代碼執(zhí)行時(shí)間測(cè)量,MDK5.25及其以上版本才支持,IAR不支持。- 默認(rèn)不開啟,如果要使能此選項(xiàng),務(wù)必看V5開發(fā)板用戶手冊(cè)第8章*/ #if Enable_EventRecorder == 1 /* 初始化EventRecorder并開啟 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); #endifbsp_InitKey(); /* 按鍵初始化,要放在滴答定時(shí)器之前,因?yàn)榘粹o檢測(cè)是通過(guò)滴答定時(shí)器掃描 */bsp_InitTimer(); /* 初始化滴答定時(shí)器 */bsp_InitUart(); /* 初始化串口 */bsp_InitExtIO(); /* 初始化擴(kuò)展IO */bsp_InitLed(); /* 初始化LED */ }? 主功能:
主程序?qū)崿F(xiàn)如下操作:
- ? 啟動(dòng)一個(gè)自動(dòng)重裝軟件定時(shí)器,每100ms翻轉(zhuǎn)一次LED2。
- ? 按下按鍵K1,打印原始波形數(shù)據(jù)和濾波后的波形數(shù)據(jù)。
40.8 總結(jié)
本章節(jié)主要講解了FIR濾波器的帶阻實(shí)現(xiàn),同時(shí)一定要注意線性相位FIR濾波器的群延遲問(wèn)題,詳見本教程的第41章。
總結(jié)
以上是生活随笔為你收集整理的【STM32HF429的DSP教程】第40章 STM32F429的FIR带阻滤波器实现(支持逐个数据的实时滤波)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【硬见小百科】PCB多层板各层含义与设计
- 下一篇: Altium Designer——PCB