關於中值濾波算法的幾點注意事項:
1.根據相關文獻報道[1],濾波窗口寬度設置在採樣率的80~90%[2],是爲合理寬度;
2.中值濾波之後的基線數據(濾波過程中,筆者初始化窗口值爲0),應左移半窗口寬度後,與原數據對應相減,所得數據爲去基線漂移後的數據;
3.對於原數據,在進行中值濾波前,需要進行尾部延拓半窗口寬度(與中值濾波延時對應),筆者將延拓部分取值0;
4.對應相減時,取基線數據從半窗口寬度處始,至結尾止,並按此順序與原數據(延拓前)對應相減。
實驗結果對比:
通過對比
origin_data[i] - med_data[i],
origin_data[i] - med_data[i + half_win_width]以及
origin_data[i + half_win_width] - med_data[i]三者圖像,
發現中值濾波效果最佳者
爲origin_data[i] - med_data[i + half_win_width],
origin_data[i] - med_data[i]次之,
origin_data[i + half_win_width] - med_data[i]最差。
此對比從一定程度上證明了上述的中值濾波延時結論。
順序中值濾波代碼:
中值獲取:
#ifndef __MEDIAN_H__
#define __MEDIAN_H__
class Wave_filter
{
public:
Wave_filter();
~Wave_filter();
void reset(void);
void get_median(int, int &);
void get_median(int *, int, int *&);
private:
#ifndef SAMPLARATE
#define SAMPLERATE 250
#endif // !SAMPLARATE
#ifndef MEDWIDTH
#define MEDWIDTH SAMPLERATE * 8 /10 + 1
#endif // !MEDWIDTH
int median(int), *value_pool, *time_pool, ers_pos, add_pos, running_time, time_pos;
};
#endif // ! __MEDIAN_H__
#include "Median.h"
Wave_filter::Wave_filter() :ers_pos(-1), add_pos(-2), time_pos(0)
{
value_pool = new int[MEDWIDTH]();
time_pool = new int[MEDWIDTH]();
running_time = 0;
for (int i = MEDWIDTH; i > 0; running_time++)
{
i >>= 1;
}
}
Wave_filter::~Wave_filter()
{
delete[] value_pool;
delete[] time_pool;
}
void Wave_filter::reset()
{
ers_pos = add_pos = -1;
time_pos = 0;
for (int i = 0; i < MEDWIDTH; i++)
{
time_pool[i] = value_pool[i] = 0;
}
}
int Wave_filter::median(int data)
{
if (time_pos >= MEDWIDTH)
{
time_pos = 0;
}
int left_bd = 0, mid_pos;
for (int i = 0; i < running_time; i++)
{
mid_pos = MEDWIDTH >> (i + 1);
if (time_pool[time_pos] == value_pool[left_bd + mid_pos])
{
ers_pos = left_bd + mid_pos;
break;
}
else if (time_pool[time_pos] > value_pool[left_bd + mid_pos])
{
left_bd += mid_pos;
}
if (mid_pos < 1)
{
while (time_pool[time_pos] > value_pool[left_bd + mid_pos])
{
mid_pos++;
}
ers_pos = left_bd + mid_pos;
}
}
left_bd = 0;
if (data < value_pool[0])
{
add_pos = -1;
}
else if (data >= value_pool[MEDWIDTH - 1])
{
add_pos = MEDWIDTH - 1;
}
else
{
for (int i = 0; i < running_time; i++)
{
mid_pos = MEDWIDTH >> (i + 1);
if (data >= value_pool[left_bd + mid_pos] && data < value_pool[left_bd + mid_pos + 1])
{
add_pos = left_bd + mid_pos;
break;
}
else if (data >= value_pool[left_bd + mid_pos])
{
left_bd += mid_pos;
}
if (mid_pos < 1)
{
while (data >= value_pool[left_bd + mid_pos])
{
mid_pos++;
}
add_pos = left_bd + mid_pos - 1;
}
}
}
if (ers_pos == add_pos || ers_pos - 1 == add_pos)
{
value_pool[ers_pos] = data;
}
else if (ers_pos < add_pos)
{
for (int i = ers_pos; i < add_pos; i++)
{
value_pool[i] = value_pool[i + 1];
}
value_pool[add_pos] = data;
}
else
{
add_pos++;
for (int i = ers_pos; i > add_pos; i--)
{
value_pool[i] = value_pool[i - 1];
}
value_pool[add_pos] = data;
}
time_pool[time_pos] = data;
time_pos++;
return *(value_pool + ((MEDWIDTH) >> 1));
}
void Wave_filter::get_median(int in_data, int &out_data)
{
out_data = median(in_data);
}
void Wave_filter::get_median(int *in_data, int length, int *&out_data)
{
for (int i = 0; i < length + (MEDWIDTH >> 1); i++)
{
if (i < MEDWIDTH >> 1)
{
*(out_data) = median(*(in_data + i));
}
else if (i >= length)
{
*(out_data + i - (MEDWIDTH >> 1)) = median(0);
}
else
{
*(out_data + i - (MEDWIDTH >> 1)) = median(*(in_data + i));
}
}
}
References:
[1] 蔡坤,陸堯勝. 基於中值濾波的心電基線校正方法的研究[J]. 醫療設備信息,2004,02:5-7.
[2] 劉文娜. 基於ECG信號進行心律失常及睡眠呼吸暫停綜合症診斷分析[D].南京郵電大學,2015.