天天看點

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

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

第48章       STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

本章節講解中值濾波器實作,适用于噪聲和脈沖的過濾。

48.1 初學者重要提示

48.2 中值濾波器介紹

48.3 中值濾波器原理

48.4 Matlab中值濾波器實作

48.5 中值濾波器設計

48.6 實驗例程說明(MDK)

48.7 實驗例程說明(IAR)

48.8 總結

1、  ARM DSP庫沒有提供中值濾波器,是以本章的實作是根據中值濾波器原理做了兩個函數,一個函數是一塊資料的濾波器實作,另一個函數是實時的逐點濾波實作。

中值濾波器是一種非線性數字過濾技術,通常用于消除圖像或信号中的噪聲。中值濾波器在數字圖像進行中被廣泛使用。在信号進行中也有應用,通過丢棄所有可疑測量結果來抑制脈沖幹擾。有幾個輸入資料,篩選器計算中值值。

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

這裡我們通過一個執行個體來了解中值濾波器。比如我們要對如下五個資料求中值:

x = [14  18  16  21  11]

我們将濾波階數設定為5,即y = medfilt1(x, 5),表示每5個采樣值求一次中值。原理和實作如下:

函數是取x(k-2),x(k-1),  x(k),  x(k+1),  x(k+2)的中值作為輸出y(k)。對于y(1),隻有x(1), x(2), x(3)存在數值,之前的不存在,對于不存在的補0。每5個數按從小到大排列後取中值有:

y(1)的計算是從[0 0 14 16 18]中取中值是14。

y(2)的計算是從[0 14 16 18 21]中取中值是16。

y(3)的計算是從[11 14 16 18 21]中取中值是16。

y(4)的計算是從0 11 16 18 21]中取中值是16。

y(5)的計算是從[0 0 11 16 21]中取中值是11。

首先建立兩個混合信号,便于更好測試濾波器效果。

混合信号Mix_Signal_1 = 信号Signal_Original_1+白噪聲。

混合信号Mix_Signal_2 = 信号Signal_Original_2+白噪聲。

Fs = 1000;                                                          %采樣率
N  = 1000;                                                          %采樣點數
n  = 0:N-1;
t   = 0:1/Fs:1-1/Fs;                                                %時間序列
Signal_Original_1 =sin(2*pi*10*t)+sin(2*pi*20*t)+sin(2*pi*30*t);
Noise_White_1    = [0.3*randn(1,500), rand(1,500)]; %前500點高斯分部白噪聲,後500點均勻分布白噪聲
Mix_Signal_1   = Signal_Original_1 + Noise_White_1; %構造的混合信号

Signal_Original_2  =  [zeros(1,100), 20*ones(1,20), -2*ones(1,30), 5*ones(1,80), -5*ones(1,30), 9*ones(1,140), -4*ones(1,40), 3*ones(1,220), 
12*ones(1,100), 5*ones(1,20), 25*ones(1,30), 7 *ones(1,190)];

Noise_White_2     =  0.5*randn(1,1000);                             %高斯白噪聲
Mix_Signal_2        =  Signal_Original_2 + Noise_White_2;           %構造的混合信号      

濾波代碼實作如下:

%****************************************************************************************
%  
%                信号Mix_Signal_1 和 Mix_Signal_2  分别作中值濾波
%
%***************************************************************************************

%混合信号 Mix_Signal_1  中值濾波
Signal_Filter=medfilt1(Mix_Signal_1,10);

subplot(4,1,1);                                          %Mix_Signal_1 原始信号                 
plot(Mix_Signal_1);
axis([0,1000,-5,5]);
title('原始信号 ');

subplot(4,1,2);                                          %Mix_Signal_1 中值濾波後信号  
plot(Signal_Filter);
axis([0,1000,-5,5]);
title('中值濾波後的信号');

%混合信号 Mix_Signal_2  中值濾波
Signal_Filter=medfilt1(Mix_Signal_2,10);
subplot(4,1,3);                                          %Mix_Signal_2 原始信号                 
plot(Mix_Signal_2);
axis([0,1000,-10,30]);
title('原始信号 ');

subplot(4,1,4);                                          %Mix_Signal_2 中值濾波後信号  
plot(Signal_Filter);
axis([0,1000,-10,30]);
title('中值濾波後的信号');      

Matlab運作效果:

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

本章的實作是根據中值濾波器原理做了兩個函數,一個函數是一塊資料的濾波器實作,另一個函數是實時的逐點濾波實作。

48.5.1        函數MidFilterBlock

函數原型:

void MidFilter(float32_t *pSrc, float32_t *pDst, uint32_t blockSize, uint32_t order)

函數描述:

這個函數用于一段資料的中值濾波。

函數參數:

  •   第1個參數是源資料位址。
  •   第2個參數是目的資料位址。
  •   第3個參數是濾波資料個數,至少為2。
  •   第4個參數是濾波階數,至少為2。

48.5.2 函數MidFilterRT

函數定義如下:

void MidFilterRT(float32_t *pSrc, float32_t *pDst, uint8_t ucFlag, uint32_t order)

這個函數用于逐個資料的實時濾波。

  •   第3個參數設定為1表示首次濾波,後面繼續濾波,需将其設定為0。

48.5.3 宏定義設定 (重要)

用到兩個宏定義,大家根據自己的應用進行設定:

#define TEST_LENGTH_SAMPLES  1024    /* 采樣點數 */

#define MidFilterOrder  16           /* 濾波階數 */

第1個宏定義:采樣點數用于整塊資料濾波,一次性濾波的點數。

第2個宏定義:設定濾波階數。

48.5.4 整塊資料中值濾波測試

适用于分段資料濾波,測試波形是由原始信号+高斯白噪聲+均勻白噪聲。

/*
*********************************************************************************************************
*    函 數 名: MidFilterBlockTest
*    功能說明: 整塊資料濾波測試
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void MidFilterBlockTest(void)
{

    MidFilterBlock((float32_t *)&testdata[0], &DstDate[0], TEST_LENGTH_SAMPLES, MidFilterOrder);

    for(int i = 0; i < TEST_LENGTH_SAMPLES; i++)
    {
        printf("%f, %f\r\n", testdata[i], DstDate[i]);
    }
}      

濾波器效果,紅色是原始波形,杏黃色是濾波後效果:

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

48.5.5 逐個資料中值濾波測試 (支援實時濾波)

适用于逐個資料的實時濾波,測試波形是由原始信号+高斯白噪聲+均勻白噪聲。

/*
*********************************************************************************************************
*    函 數 名: MidFilterOneByOneTest
*    功能說明: 逐個資料濾波測試
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void MidFilterOneByOneTest(void)
{
    float32_t  *inputF32, *outputF32;
    
    inputF32 = (float32_t  *)&testdata[0];
    outputF32 = &DstDate[0];
    
    /* 從頭開始,先濾第1個資料 */
    MidFilterRT(inputF32 , outputF32, 1, MidFilterOrder);
    
    /* 逐次濾波後續資料 */
    for(int i = 1; i < TEST_LENGTH_SAMPLES; i++)
    {
        MidFilterRT(inputF32 + i , outputF32 + i, 0, MidFilterOrder);
    }
    
    for(int i = 0; i < TEST_LENGTH_SAMPLES; i++)
    {
        printf("%f, %f\r\n", testdata[i], DstDate[i]);
    }
}      
【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

配套例子:

V5-233_中值濾波器實作,适用于噪聲和脈沖過濾(支援逐點實時濾波)

實驗目的:

  1. 學習中值濾波器 。

實驗内容:

  1. 啟動一個自動重裝軟體定時器,每100ms翻轉一次LED2。
  2. K1鍵按下,整塊資料濾波測試。
  3. K2鍵按下,逐個資料濾波器測試。

使用AC6注意事項

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

上電後序列槽列印的資訊:

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

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

RTT方式列印資訊:

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

程式設計:

  系統棧大小配置設定:

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)

  硬體外設初始化

硬體外設的初始化是在 bsp.c 檔案實作:

/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬體裝置。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。隻需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F407 HAL 庫初始化,此時系統用的還是F407自帶的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();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();    /* 初始化序列槽 */
    bsp_InitLed();        /* 初始化LED */        
}      

  主功能:

主程式實作如下操作:

  •   啟動一個自動重裝軟體定時器,每100ms翻轉一次LED2。
  •   K1鍵按下,整塊資料濾波測試。
  •   K2鍵按下,逐個資料濾波器測試。
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程式入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按鍵代碼 */
    uint16_t i;

    bsp_Init();        /* 硬體初始化 */
    PrintfLogo();    /* 列印例程資訊到序列槽1 */

    PrintfHelp();    /* 列印操作提示資訊 */
        

    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鍵按下,整塊資料濾波測試 */
                    MidFilterBlockTest();
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下,逐個資料濾波器測試 */
                    MidFilterOneByOneTest();
                    break;                
    
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }

    }
}      

【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)
【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)
【STM32F407的DSP教程】第48章 STM32F407的中值濾波器實作,适合噪聲和脈沖過濾(支援逐個資料的實時濾波)
/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬體裝置。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。隻需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F407 HAL 庫初始化,此時系統用的還是F407自帶的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();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();    /* 初始化序列槽 */
    bsp_InitLed();        /* 初始化LED */        
}      
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程式入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按鍵代碼 */
    uint16_t i;

    bsp_Init();        /* 硬體初始化 */
    PrintfLogo();    /* 列印例程資訊到序列槽1 */

    PrintfHelp();    /* 列印操作提示資訊 */
        

    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鍵按下,整塊資料濾波測試 */
                    MidFilterBlockTest();
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下,逐個資料濾波器測試 */
                    MidFilterOneByOneTest();
                    break;                
    
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }

    }
}      

本章節主要講解了中值濾波器的實作,非常時候噪聲濾除場景。

微信公衆号:armfly_com

安富萊論壇:www.armbbs.cn

安富萊淘寶:https://armfly.taobao.com