伪代码:
输入参数:xi,c
输出参数:yi,c
初始化过程:
l1 ← 51
l2 ← 351
c.n ← 0
c.r1 ← {0,…}//length=l1
c.t1 ← {0,…}//length=l1
c.r2 ← {0,…}//length=l2
c.t2 ← {0,…}//length=l2
c.rtd ← {0,…}//length(l2-1)//2
迭代过程:
yi ← xi // 设置默认返回值
t1_0 ← c.t1[0] // 队列t1,提取队头元素
c.n ← c.n + 1 // 计数器 + 1
如果 c.n > c.l1 + c.l2 // 超过队列长度
c.n ← c.l1 + c.l2 + 10 // 计数器变更
c.t1 ← c.t1[1:] ∪{xi} // 循环左移,并右侧插入xi
如果c.n == c.l1
c.r1 ← 排序(c.t1) // 小的在前,大的在后面
b ← c.r1[(c.l1-1)/2] // 获取中值
否则 如果 c.n > c.l1
c.r1 ← 删除并插入 (c.r1, t1_0, xi) // 删除t1_0,插入xi
b ← c.r1[(c.l1-1)/2 -1] // 获取中值前一个的位置
否则
返回 yi
t2_1 ← c.t2[1] // 队列t2,提取队头元素,这里的队头是1不是0
c.t2 ← c.t2[1:] ∪{b} // 循环左移,并右侧插入b
如果 c.n == c.l1 + c.l2 – 1
c.r2 ← 排序(c.t2) // 小的在前,大的在后面
b ← c.r2[(c.l2-1)/2] // 获取中值
yi ← c.rtd[1] - b
否则
c.rtd ← c.rtd [1:] ∪{xi} // 循环左移,并右侧插入b
如果 c.n >= c.l1+c.l2
c.r2 ← 删除并插入 (c.r1, t2_1, b) // 删除t2_1,插入b
b ← c.r2[(c.l2-1)/2] // 获取中值前一个的位置
yi ← c.rtd[1] - b
返回 yi
二分查找算法:
int binarySearch(float *array, float target, int length)
{/**
二分查找算法,查找 target 在 array 中的索引。
@param array 待查找数组,升序排列
@param target 待查找元素
@param length 数组长度
@return 元素索引,如果不存在,返回最近的元素
**/
// 初始化变量
int low = 0, high = length - 1, mid;
// 循环查找
while (low <= high)
{ // 计算中间位置
mid = (low + high) / 2;
// 找到目标元素,返回索引
if (array[mid] == target)
return mid;
// 中间元素小于目标元素,继续在后半部分查找
else if (array[mid] < target)
low = mid + 1;
// 中间元素大于目标元素,继续在前半部分查找
else
high = mid - 1;
}
// 没有找到目标元素,返回最近的元素
if (mid > 0 && target - array[mid - 1] < array[mid] - target)
return mid - 1;
else
return mid;
}
删除+插入排序:
void deleteInsert(float *dataArray, float delete_data, float insert_data, int length)
{/**
该函数用于删除一个元素并插入另一个元素,并保持数组有序。
@param dataArray 待操作的数组,输入和输出都默认从小到大排序
@param delete_data 要删除的元素
@param insert_data 要插入的元素
@param length 数组的长度
**/
// 如果要删除的元素和要插入的元素相同,则直接返回
if (delete_data == insert_data)
return;
// 使用二分查找找到要删除元素的位置
int index = binarySearch(dataArray, delete_data, length);
// 未找到删除的元素的时候直接结束
if (index == -1)
return;
// 如果要删除的元素小于要插入的元素,则从左向右移动元素
if (delete_data < insert_data)
for (; index < length - 1 && dataArray[index] < insert_data; index++)
dataArray[index] = dataArray[index + 1];
// 否则,从右向左移动元素
else
for (; index > 0 && dataArray[index] > insert_data; index--)
dataArray[index] = dataArray[index - 1];
// 将要插入的元素插入到找到的位置
dataArray[index] = insert_data;
}
完整ECG去除基线漂移的代码:
#define lengthLevelOne 51
#define lengthLevelTwo 351
typedef struct
{
float resultOne[lengthLevelOne];
float templateOne[lengthLevelOne];
float resultTwo[lengthLevelTwo];
float templateTwo[lengthLevelTwo];
float realTimeData[(lengthLevelTwo - 1) / 2];
int count;
int l1 = lengthLevelOne;
int l2 = lengthLevelTwo;
} baseLineRemoval_CTX;
void move_left(float *data, int n)
{
// 向左移动数据,data[0] = data[1],...
int i = 0;
for (i = 0; i < (n - 1); i++)
data[i] = data[i + 1];
}
void move_left(float *data, int n, float new_data)
{
// 向左移动数据,data[0] = data[1],...
move_left(data, n);
data[n - 1] = new_data; // 更新最后一个元素
}
void move_right(float *data, int n)
{
// 向右移动数据,data[n] = data[n-1],...
int i = 0;
for (i = n - 1; i > 0; i--)
{
data[i] = data[i - 1];
}
}
void move_right(float *data, int n, float new_data)
{
move_right(data, n);
data[0] = new_data; // 更新第一个一个元素
}
int binarySearch(float *array, float target, int length)
{/**
二分查找算法,查找 target 在 array 中的索引。
@param array 待查找数组,升序排列
@param target 待查找元素
@param length 数组长度
@return 元素索引,如果不存在,返回最近的元素
**/
// 初始化变量
int low = 0, high = length - 1, mid;
// 循环查找
while (low <= high)
{ // 计算中间位置
mid = (low + high) / 2;
// 找到目标元素,返回索引
if (array[mid] == target)
return mid;
// 中间元素小于目标元素,继续在后半部分查找
else if (array[mid] < target)
low = mid + 1;
// 中间元素大于目标元素,继续在前半部分查找
else
high = mid - 1;
}
// 没有找到目标元素,返回最近的元素
if (mid > 0 && target - array[mid - 1] < array[mid] - target)
return mid - 1;
else
return mid;
}
void deleteInsert(float *dataArray, float delete_data, float insert_data, int length)
{/**
该函数用于删除一个元素并插入另一个元素,并保持数组有序。
@param dataArray 待操作的数组,输入和输出都默认从小到大排序
@param delete_data 要删除的元素
@param insert_data 要插入的元素
@param length 数组的长度
**/
// 如果要删除的元素和要插入的元素相同,则直接返回
if (delete_data == insert_data)
return;
// 使用二分查找找到要删除元素的位置
int index = binarySearch(dataArray, delete_data, length);
// 未找到删除的元素的时候直接结束
if (index == -1)
return;
// 如果要删除的元素小于要插入的元素,则从左向右移动元素
if (delete_data < insert_data)
for (; index < length - 1 && dataArray[index] < insert_data; index++)
dataArray[index] = dataArray[index + 1];
// 否则,从右向左移动元素
else
for (; index > 0 && dataArray[index] > insert_data; index--)
dataArray[index] = dataArray[index - 1];
// 将要插入的元素插入到找到的位置
dataArray[index] = insert_data;
}
// 初始化基线漂移滤波器
void baseLineRemoval_init(baseLineRemoval_CTX *ctx)
{
// 初始化计数器
ctx->count = 0;
// 初始化遍历索引
int i = 0;
// 初始化静态数组
for (i = 0; i < ctx->l1; i++)
{
ctx->resultOne[i] = 0;
ctx->templateOne[i] = 0;
}
for (i = 0; i < ctx->l2; i++)
{
ctx->resultTwo[i] = 0;
ctx->templateTwo[i] = 0;
}
// 初始化动态数组
for (i = 0; (ctx->l2 - 1) / 2; i++)
{
ctx->realTimeData[i] = 0;
}
}
// 函数baseLineRemoval用于计算基线移除的输出数据
float baseLineRemoval(baseLineRemoval_CTX *ctx, float inputdata)
{
// 定义结果数组
float *resultOne = ctx->resultOne;
float *templateOne = ctx->templateOne;
float *resultTwo = ctx->resultTwo;
float *templateTwo = ctx->templateTwo;
float *realTimeData = ctx->realTimeData;
int *ctx_count = &(ctx->count);
// 更新静态数组
(*ctx_count) = (*ctx_count) + 1;
if ((*ctx_count) > (lengthLevelTwo + lengthLevelOne))
{
(*ctx_count) = (lengthLevelTwo + lengthLevelOne) + 10;
}
float tempBuffer;
float outputdata = 0;
int i = 0;
tempBuffer = templateOne[i];
float baseWanderData;
// 移动到下一个模板 templateOne
move_left(templateOne, lengthLevelOne, inputdata);
// 判断当前插入点的位置
if ((*ctx_count) == lengthLevelOne)
{
// 插入排序,刚好满足长度的时候直接排序全部数据
dataSort(templateOne, resultOne, lengthLevelOne);
baseWanderData = resultOne[(lengthLevelOne - 1) / 2];
}
else if ((*ctx_count) > lengthLevelOne)
{
// 插入排序,满足长度的时候直接插入到指定位置
deleteInsert(resultOne, tempBuffer, inputdata, lengthLevelOne);
baseWanderData = resultOne[(lengthLevelOne - 1) / 2 - 1];
}
// 更新动态数组
if ((*ctx_count) >= lengthLevelOne)
{
// 复制模板2中的第一个元素到模板2中
tempBuffer = templateTwo[1];
// 移动到下一个模板 templateOne
move_left(templateTwo, lengthLevelTwo, baseWanderData);
// 更新动态数组
if ((*ctx_count) == (lengthLevelTwo + lengthLevelOne - 1))
{
dataSort(templateTwo, resultTwo, lengthLevelTwo);
baseWanderData = resultTwo[(lengthLevelTwo - 1) / 2];
outputdata = realTimeData[1] - baseWanderData;
}
else
{
// 移动到下一个模板 realTimeData
move_left(realTimeData, (lengthLevelTwo - 1) / 2 - 1, inputdata);
if ((*ctx_count) >= (lengthLevelTwo + lengthLevelOne))
{
deleteInsert(resultTwo, tempBuffer, baseWanderData, lengthLevelTwo);
baseWanderData = resultTwo[(lengthLevelTwo - 1) / 2];
outputdata = realTimeData[1] - baseWanderData;
}
else
outputdata = 0;
}
}
return outputdata;
}