完整版教程下載下傳位址: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庫沒有提供中值濾波器,是以本章的實作是根據中值濾波器原理做了兩個函數,一個函數是一塊資料的濾波器實作,另一個函數是實時的逐點濾波實作。
中值濾波器是一種非線性數字過濾技術,通常用于消除圖像或信号中的噪聲。中值濾波器在數字圖像進行中被廣泛使用。在信号進行中也有應用,通過丢棄所有可疑測量結果來抑制脈沖幹擾。有幾個輸入資料,篩選器計算中值值。

這裡我們通過一個執行個體來了解中值濾波器。比如我們要對如下五個資料求中值:
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運作效果:
本章的實作是根據中值濾波器原理做了兩個函數,一個函數是一塊資料的濾波器實作,另一個函數是實時的逐點濾波實作。
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]);
}
}
濾波器效果,紅色是原始波形,杏黃色是濾波後效果:
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]);
}
}
配套例子:
V5-233_中值濾波器實作,适用于噪聲和脈沖過濾(支援逐點實時濾波)
實驗目的:
- 學習中值濾波器 。
實驗内容:
- 啟動一個自動重裝軟體定時器,每100ms翻轉一次LED2。
- K1鍵按下,整塊資料濾波測試。
- K2鍵按下,逐個資料濾波器測試。
使用AC6注意事項
特别注意附件章節C的問題
上電後序列槽列印的資訊:
波特率 115200,資料位 8,奇偶校驗位無,停止位 1。
RTT方式列印資訊:
程式設計:
系統棧大小配置設定:
硬體外設初始化
硬體外設的初始化是在 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;
}
}
}
}
/*
*********************************************************************************************************
* 函 數 名: 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