关于中值滤波算法的几点注意事项:
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.