该代码与V2(ECG压缩V2)的代码相比,主要有以下一个区别:
- 在计算输出值时,使用了线性插值的方法。
算法逻辑如下:
初始化:
- 设置
count
为 0,用于记录输出元素的数量。- 设置
n
为 0,用于记录当前历史值的索引。- 初始化
history
数组,用于存储最近的两个输入值。- 设置
last[0]
为 0,表示上一次输出的值。- 设置
last[1]
为 0,表示上一次输出值的前一个值。遍历输入数据:
- 依次读取每个输入值
inValues[i]
。- 将输入值存储到
history
数组中,并更新n
的值。- 如果
n
不为 0,则跳过下一次迭代,因为还没有收集到足够的历史值。- 如果
n
为 0:
- 计算两次输入值的斜率差值
k1 - k2
。- 找到斜率差值最大的元素的索引
k
。- 将
history[k]
的值赋给last[1]
。- 计算
last[1]
的线性插值值last[1] + k * rate
。- 将
last[1] + k * rate
的值输出到outValues
数组中。- 将
last[0]
赋值为last[1]
。- 将
count
加 1,表示输出了一个元素。返回输出元素的数量:
- 返回
count
,表示输出元素的数量。
算法目的:
该算法与上面的算法类似,也是一种下采样方法,用于降低 ECG 信号的采样率。它通过在每个采样周期内选择与上一次输出值的斜率差值最大的历史值作为新的输出值,来保留 ECG 信号的形态特征,同时减少数据量。
比较分析:
与第二种算法相比,第三种算法使用了线性插值的方法来计算输出值。线性插值可以减少输出值的跳变,从而提高输出值的平滑度。
具体选择哪种算法,需要根据具体的应用场景来决定。
#define abs(x) (x) < 0 ? -(x) : (x)
class ECGDownSampler
{
int rate; // 多少个点采集一个值
int n; // 距离上一次采样过了多久
int history[100]; // 缓存的数据
int last[2]; // 前2个采集点
public:
ECGDownSampler(int r=8); // 8 倍下采样
int applay(int inLenght, float *inValues, float *outValues); // 返回采样后的数据长度
};
ECGDownSampler::ECGDownSampler(int r)
{
this->rate = r; // 多少个点采集一个值
this->n = 0; // 距离上一次采样过了多久
for (int i = 0; i < 2; i++)
{
this->last[i] = 0;
}
}
int ECGDownSampler::applay(int inLenght, float *inValues, float *outValues)
{
int i, j;
float max_loss;
float temp;
float k1, k2, k;
int count = 0;
for (i = 0, count = 0; i < inLenght; i++)
{
history[n] = inValues[i];
n = (n + 1) % rate; // 计算新的 n
if (n != 0)
continue;
for (j = 0, max_loss = -1, k1 = (last[1] - last[0]) / rate, k=0;
j < n;
j++)
{
k2 = (last[1] - history[j]) / (rate / 2 + j); // 求斜率
temp = abs(k1 - k2); // 求斜率差
if (temp > max_loss) // 最差大差异的斜率
{
max_loss = temp;
k = k2; // 记录当前的k
}
}
last[0] = last[1]; // 删除
last[1] = last[0] + k*rate; // 添加
outValues[count] = last[1];
count++;
}
return count;
}