日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【STM32F429的DSP教程】第47章 STM32F429的IIR带阻滤波器实现(支持逐个数据的实时滤波)

發布時間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【STM32F429的DSP教程】第47章 STM32F429的IIR带阻滤波器实现(支持逐个数据的实时滤波) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

完整版教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

第47章?????? STM32F429的IIR帶阻濾波器實現(支持逐個數據的實時濾波)

本章節講解IIR帶阻濾波器實現。

目錄

47.1 初學者重要提示

47.2 帶阻濾波器介紹

47.3 IIR濾波器介紹

47.4 Matlab工具箱filterDesigner生成IIR帶阻濾波器系數

47.5 IIR帶阻濾波器設計

47.5.1 函數arm_biquad_cascade_df1_init_f32

47.5.2 函數arm_biquad_cascade_df1_f32

47.5.3 filterDesigner獲取帶阻濾波器系數

47.5.4 帶阻濾波器實現

47.6 實驗例程說明(MDK)

47.7 實驗例程說明(IAR)

47.8 總結


47.1 初學者重要提示

? 1、本章節提供的帶阻濾波器支持實時濾波,每次可以濾波一個數據,也可以多個數據,不限制大小。但要注意以下兩點:

  • ? 所有數據是在同一個采樣率下依次采集的數據。
  • ? 每次過濾數據個數一旦固定下來,運行中不可再修改。

? 2、FIR濾波器的群延遲是一個重要的知識點,詳情在本教程第41章有詳細說明。IIR和FIR一樣,也有群延遲問題。

47.2 帶阻濾波器介紹

減弱一個范圍內的頻率信號通過,讓范圍之外的頻率信號通過。比如混合信號含有50Hz + 200Hz + 400Hz信號,我們可通過帶通濾波器,讓50Hz + 400Hz信號通過,而阻止200Hz信號通過。

47.3 IIR濾波器介紹

ARM官方提供的直接I型IIR庫支持Q7,Q15,Q31和浮點四種數據類型。其中Q15和Q31提供了快速版本。

直接I型IIR濾波器是基于二階Biquad級聯的方式來實現的。每個Biquad由一個二階的濾波器組成:

y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2]

直接I型算法每個階段需要5個系數和4個狀態變量。

這里有一點要特別的注意,有些濾波器系數生成工具是采用的下面公式實現:

y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]

比如matlab就是使用上面的公式實現的,所以在使用fdatool工具箱生成的a系數需要取反才能用于直接I型IIR濾波器的函數中。

高階IIR濾波器的實現是采用二階Biquad級聯的方式來實現的。其中參數numStages就是用來做指定二階Biquad的個數。比如8階IIR濾波器就可以采用numStages=4個二階Biquad來實現。

?

如果要實現9階IIR濾波器就需要將numStages=5,這時就需要其中一個Biquad配置成一階濾波器(也就是b2=0,a2=0)。

47.4 Matlab工具箱filterDesigner生成IIR帶阻濾波器系數

前面介紹FIR濾波器的時候,我們講解了如何使用filterDesigner生成C頭文件,從而獲得濾波器系數。這里不能再使用這種方法了,主要是因為通過C頭文件獲取的濾波器系數需要通過ARM官方的IIR函數調用多次才能獲得濾波結果,所以我們這里換另外一種方法。

下面我們講解如何通過filterDesigner工具箱生成濾波器系數。首先在matlab的命令窗口輸入filterDesigner就能打開這個工具箱:

filterDesigner界面打開效果如下:

IIR濾波器的低通,高通,帶通,帶阻濾波的設置會在下面一 一講解,這里說一下設置后相應參數后如何生成濾波器系數。參數設置好以后點擊如下按鈕:

點擊Design Filter之后,注意左上角生成的濾波器結構:

默認生成的IIR濾波器類型是Direct-Form II, Second-Order Sections(直接II型,每個Section是一個二階濾波器)。這里我們需要將其轉換成Direct-Form I, Second-Order Sections,因為本章使用的IIR濾波器函數是Direct-Form I的結構。

轉換方法,點擊Edit->Convert Structure,界面如下,這里我們選擇第一項,并點擊OK:

轉換好以后再點擊File-Export,第一項選擇Coefficient File(ASCII):

第一項選擇好以后,第二項選擇Decimal:

兩個選項都選擇好以后,點擊Export進行導出,導出后保存即可:

保存后Matlab會自動打開untitled.fcf文件,可以看到生成的系數:

% Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. % Generated on: 15-Aug-2021 23:05:39% Coefficient Format: Decimal% Discrete-Time IIR Filter (real) % ------------------------------- % Filter Structure : Direct-Form I, Second-Order Sections % Number of Sections : 2 % Stable : Yes % Linear Phase : No SOS Matrix: 1 -0.614001926383350049576392848393879830837 1 1 -1.145142787949775309286337687808554619551 0.502980071467214684410862446384271606803 1 -0.614001926383350049576392848393879830837 1 1 0.474587046588418992598690238082781434059 0.35305199748708809837083322236139792949 Scale Values: 0.583479203143786984142593610158655792475 0.583479203143786984142593610158655792475

由于前面選擇的是4階IIR濾波,生成的結果就是由兩組二階IIR濾波系數組成,系數的對應順序如下:

SOS Matrix: 1 -0.614001926383350049576392848393879830837 1 1 -1.145142787949775309286337687808554619551 0.502980071467214684410862446384271606803 b0 b1 b2 a0 a1 a2 1 -0.614001926383350049576392848393879830837 1 1 0.474587046588418992598690238082781434059 0.35305199748708809837083322236139792949 b0 b1 b2 a0 a1 a2

注意,實際使用ARM官方的IIR函數調用的時候要將a1和a2取反。另外下面兩組是每個二階濾波器的增益,濾波后的結果要乘以這兩個增益數值才是實際結果:

0.583479203143786984142593610158655792475 0.583479203143786984142593610158655792475

實際的濾波系數調用方法,看下面的例子即可。

47.5 IIR帶阻濾波器設計

本章使用的IIR濾波器函數是arm_biquad_cascade_df1_f32。使用此函數可以設計IIR低通,高通,帶通和帶阻濾波器

47.5.1 函數arm_biquad_cascade_df1_init_f32

函數原型:

void arm_biquad_cascade_df1_init_f32(arm_biquad_casd_df1_inst_f32 * S,uint8_t numStages,const float32_t * pCoeffs,float32_t * pState)

函數描述:

這個函數用于IIR初始化。

函數參數:

  • ? 第1個參數是arm_biquad_casd_df1_inst_f32類型結構體變量。
  • ? 第2個參數是2階濾波器的個數。
  • ? 第3個參數是濾波器系數地址。
  • ? 第4個參數是緩沖狀態地址。

注意事項:

結構體arm_biquad_casd_df1_inst_f32的定義如下(在文件filtering_functions.h文件):

typedef struct {uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */float32_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */const float32_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages */ } arm_biquad_casd_df1_inst_f32;
  • numStages表示二階濾波器的個數,總階數是2*numStages。
  • pState指向狀態變量數組,這個數組用于函數內部計算數據的緩存,總大小4*numStages。
  • 參數pCoeffs指向濾波因數,濾波因數數組長度為5*numStages。但要注意pCoeffs指向的濾波因數應該按照如下的逆序進行排列:
  • {b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}

    先放第一個二階Biquad系數,然后放第二個,以此類推。

    47.5.2 函數arm_biquad_cascade_df1_f32

    函數定義如下:

    void arm_biquad_cascade_df1_f32(const arm_biquad_casd_df1_inst_f32 * S,float32_t * pSrc,float32_t * pDst,uint32_t blockSize)

    函數描述:

    這個函數用于IIR濾波。

    函數參數:

    • ? 第1個參數是arm_biquad_casd_df1_inst_f32類型結構體變量。
    • ? 第2個參數是源數據地址。
    • ? 第3個參數是濾波后的數據地址。
    • ? 第4個參數是每次調用處理的數據個數,最小可以每次處理1個數據,最大可以每次全部處理完。

    47.5.3 filterDesigner獲取帶阻濾波器系數

    設計一個如下的例子:

    信號由50Hz正弦波和200Hz正弦波組成,采樣率1Kbps,現設計一個巴特沃斯濾波器帶阻濾波器,采用直接I型,截止頻率100Hz和325Hz,采樣400個數據,濾波器階數設置為4。filterDesigner的配置如下:

    配置好帶通濾波器后,具體濾波器系數的生成大家參考本章第4小節的方法即可。

    47.5.4 帶阻濾波器實現

    通過工具箱filterDesigner獲得帶阻濾波器系數后在開發板上運行函數arm_biquad_cascade_df1_f32來測試低通濾波器的效果。

    #define numStages 2 /* 2階IIR濾波的個數 */ #define TEST_LENGTH_SAMPLES 400 /* 采樣點數 */ #define BLOCK_SIZE 1 /* 調用一次arm_biquad_cascade_df1_f32處理的采樣點個數 */uint32_t blockSize = BLOCK_SIZE; uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要調用arm_biquad_cascade_df1_f32的次數 */static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 采樣點 */ static float32_t testOutput[TEST_LENGTH_SAMPLES]; /* 濾波后的輸出 */ static float32_t IIRStateF32[4*numStages]; /* 狀態緩存 *//* 巴特沃斯帶阻濾波器系數100Hz 325Hz*/ const float32_t IIRCoeffs32BS[5*numStages] = {1.0f, -0.614001926383350049576392848393879830837f, 1.0f, 1.145142787949775309286337687808554619551f, -0.502980071467214684410862446384271606803f,1.0f, -0.614001926383350049576392848393879830837f, 1.0f, -0.474587046588418992598690238082781434059f, -0.35305199748708809837083322236139792949f }; /* ********************************************************************************************************* * 函 數 名: arm_iir_f32_bs * 功能說明: 調用函數arm_iir_f32_bs實現帶阻濾波器 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ static void arm_iir_f32_bs(void) {uint32_t i;arm_biquad_casd_df1_inst_f32 S;float32_t ScaleValue;float32_t *inputF32, *outputF32;/* 初始化輸入輸出緩存指針 */inputF32 = &testInput_f32_50Hz_200Hz[0];outputF32 = &testOutput[0];/* 初始化 */arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32BS[0], (float32_t *)&IIRStateF32[0]);/* 實現IIR濾波,這里每次處理1個點 */for(i=0; i < numBlocks; i++){arm_biquad_cascade_df1_f32(&S, inputF32 + (i * blockSize), outputF32 + (i * blockSize),blockSize);}/*放縮系數 */ScaleValue = 0.558156585760773649163013487850548699498f * 0.558156585760773649163013487850548699498f; /* 打印濾波后結果 */for(i=0; i<TEST_LENGTH_SAMPLES; i++){printf("%f, %f\r\n", testInput_f32_50Hz_200Hz[i], testOutput[i]*ScaleValue);} }

    運行如上函數可以通過串口打印出函數arm_biquad_cascade_df1_f32濾波后的波形數據,下面通過Matlab繪制波形來對比Matlab計算的結果和ARM官方庫計算的結果。

    對比前需要先將串口打印出的一組數據加載到Matlab中, arm_biquad_cascade_df1_f32的計算結果起名sampledata,加載方法在第13章13.6小結已經講解,這里不做贅述了。Matlab中運行的代碼如下:

    fs=1000; %設置采樣頻率 1K N=400; %采樣點數 n=0:N-1; t=n/fs; %時間序列 f=n*fs/N; %頻率序列x1=sin(2*pi*50*t); x2=sin(2*pi*200*t); %50Hz和200Hz正弦波 subplot(211); plot(t, x1); title('濾波后的理想波形'); grid on;subplot(212); plot(t, sampledata); title('ARM官方庫濾波后的波形'); grid on;

    Matlab計算結果如下:

    從上面的波形對比來看,matlab和函數arm_biquad_cascade_df1_f32計算的結果基本是一致的。為了更好的說明濾波效果,下面從頻域的角度來說明這個問題,Matlab上面運行如下代碼:

    fs=1000; %設置采樣頻率 1K N=400; %采樣點數 n=0:N-1; t=n/fs; %時間序列 f=n*fs/N; %頻率序列x = sin(2*pi*50*t) + sin(2*pi*200*t); %50Hz和200Hz正弦波合成subplot(211); y=fft(x, N); %對信號x做FFT plot(f,abs(y)); xlabel('頻率/Hz'); ylabel('振幅'); title('原始信號FFT'); grid on;y3=fft(sampledata, N); %經過IIR濾波器后得到的信號做FFT subplot(212); plot(f,abs(y3)); xlabel('頻率/Hz'); ylabel('振幅'); title('IIR濾波后信號FFT'); grid on;

    Matlab計算結果如下:

    上面波形變換前的FFT和變換后FFT可以看出,200Hz的正弦波基本被濾除。

    47.6 實驗例程說明(MDK)

    配套例子:

    V6-232_IIR帶阻濾波器(支持逐點實時濾波)

    實驗目的:

  • 學習IIR帶阻濾波器的實現,支持實時濾波
  • 實驗內容:

  • 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  • 按下按鍵K1,打印原始波形數據和濾波后的波形數據。
  • 使用AC6注意事項

    特別注意附件章節C的問題

    上電后串口打印的信息:

    波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

    RTT方式打印信息:

    程序設計:

    ? 系統棧大小分配:

    ? 硬件外設初始化

    硬件外設的初始化是在 bsp.c 文件實現:

    /* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) {/* STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鐘:- 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。- 設置NVIC優先級分組為4。*/HAL_Init();/* 配置系統時鐘到168MHz- 切換使用HSE。- 此函數會更新全局變量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/* Event Recorder:- 可用于代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。- 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章*/ #if Enable_EventRecorder == 1 /* 初始化EventRecorder并開啟 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); #endifbsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */bsp_InitTimer(); /* 初始化滴答定時器 */bsp_InitUart(); /* 初始化串口 */bsp_InitExtIO(); /* 初始化擴展IO */bsp_InitLed(); /* 初始化LED */ }

    ? 主功能:

    主程序實現如下操作:

    • ? 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
    • ? 按下按鍵K1,打印原始波形數據和濾波后的波形數據。
    /* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) {uint8_t ucKeyCode; /* 按鍵代碼 */uint16_t i;bsp_Init(); /* 硬件初始化 */PrintfLogo(); /* 打印例程信息到串口1 */PrintfHelp(); /* 打印操作提示信息 */for(i=0; i<TEST_LENGTH_SAMPLES; i++){/* 50Hz正弦波+200Hz正弦波,采樣率1KHz */testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + arm_sin_f32(2*3.1415926f*200*i/1000);}bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 *//* 進入主程序循環體 */while (1){bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */if (bsp_CheckTimer(0)) /* 判斷定時器超時時間 */{/* 每隔100ms 進來一次 */bsp_LedToggle(2); /* 翻轉LED的狀態 */}ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */if (ucKeyCode != KEY_NONE){switch (ucKeyCode){case KEY_DOWN_K1: /* K1鍵按下 */arm_iir_f32_bs();break;default:/* 其它的鍵值不處理 */break;}}} }

    47.7 實驗例程說明(IAR)

    配套例子:

    V6-232_IIR帶阻濾波器(支持逐點實時濾波)

    實驗目的:

  • 學習IIR帶阻濾波器的實現,支持實時濾波
  • 實驗內容:

  • 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  • 按下按鍵K1,打印原始波形數據和濾波后的波形數據。
  • 使用AC6注意事項

    特別注意附件章節C的問題

    上電后串口打印的信息:

    波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

    RTT方式打印信息:

    程序設計:

    ? 系統棧大小分配:

    ? 硬件外設初始化

    硬件外設的初始化是在 bsp.c 文件實現:

    /* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) {/* STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鐘:- 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。- 設置NVIC優先級分組為4。*/HAL_Init();/* 配置系統時鐘到168MHz- 切換使用HSE。- 此函數會更新全局變量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/* Event Recorder:- 可用于代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。- 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章*/ #if Enable_EventRecorder == 1 /* 初始化EventRecorder并開啟 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); #endifbsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */bsp_InitTimer(); /* 初始化滴答定時器 */bsp_InitUart(); /* 初始化串口 */bsp_InitExtIO(); /* 初始化擴展IO */bsp_InitLed(); /* 初始化LED */ }

    ? 主功能:

    主程序實現如下操作:

    • ? 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
    • ? 按下按鍵K1,打印原始波形數據和濾波后的波形數據。
    /* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) {uint8_t ucKeyCode; /* 按鍵代碼 */uint16_t i;bsp_Init(); /* 硬件初始化 */PrintfLogo(); /* 打印例程信息到串口1 */PrintfHelp(); /* 打印操作提示信息 */for(i=0; i<TEST_LENGTH_SAMPLES; i++){/* 50Hz正弦波+200Hz正弦波,采樣率1KHz */testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + arm_sin_f32(2*3.1415926f*200*i/1000);}bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 *//* 進入主程序循環體 */while (1){bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */if (bsp_CheckTimer(0)) /* 判斷定時器超時時間 */{/* 每隔100ms 進來一次 */bsp_LedToggle(2); /* 翻轉LED的狀態 */}ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */if (ucKeyCode != KEY_NONE){switch (ucKeyCode){case KEY_DOWN_K1: /* K1鍵按下 */arm_iir_f32_bs();break;default:/* 其它的鍵值不處理 */break;}}} }

    47.8 總結

    本章節主要講解了IIR濾波器的帶阻實現,同時一定要注意IIR濾波器的群延遲問題,詳見本教程的第41章。

    總結

    以上是生活随笔為你收集整理的【STM32F429的DSP教程】第47章 STM32F429的IIR带阻滤波器实现(支持逐个数据的实时滤波)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。