Dbscan:聚类滤波,通过聚类区分内点与外点进行滤波。
/**
* @brief My_Dbscan
* @param data_ori 待滤波数据,最终滤波后数据
* @param Eps 核心点搜索半径
* @param MinPts 核心点半径内点数阈值
* @return
*/
bool My_Dbscan(vector<float> &data_ori,float Eps,int MinPts)
{
data_Dbscan data_Dbscan_temp;
vector<data_Dbscan> data, data_swp;
// 数据迁移
for(int i=0; i<data_ori.size(); i++)
{
data_Dbscan_temp.id = i;
data_Dbscan_temp.data = data_ori.at(i);
data.push_back(data_Dbscan_temp);
}
// 搜索核心点
for(int i=0; i<data.size(); i++)
{
for(int j=i+1; j<data.size(); j++)
{
if(abs(data.at(i).data - data.at(j).data) < Eps)
{
data.at(i).num++;
data.at(j).core_id = i;
data.at(j).dataType = 2;
}
}
}
// 判断核心点
for(int i=0; i<data.size(); i++)
{
if(data.at(i).num > MinPts)
{
data.at(i).dataType = 3;
}
data.at(i).num = 0;
}
// 核心点所属核心id合并
int num = 0;
for(int i=0; i<data.size(); i++)
{
if(data.at(i).dataType == 3 && data.at(i).num == 0)
{
num++;
data.at(i).num = num;
for(int j=i+1; j<data.size(); j++)
{
if(data.at(j).dataType == 3)
{
if(abs(data.at(i).data - data.at(j).data) < Eps)
{
data.at(j).num = num;
}
}
}
}
}
// 核心区域内点id合并
for(int i=0; i<data.size(); i++)
{
if(data.at(i).dataType == 2)
{
data.at(i).num = data.at(data.at(i).core_id).num;
}
}
// 滤波数据更新
data_ori.clear();
for(int i=0; i<data.size(); i++)
{
if(data.at(i).num > 0)
{
data_ori.push_back(data.at(i).data);
}
}
if(!data.empty())
{
data.clear();
vector<data_Dbscan> tmp;
data.swap(tmp); // 进行交换
}
return true;
}
Gaussian:高斯滤波,将时域转为频域进行滤波。
/**
* @brief My_Gaussianfilter 一维高斯滤波
* @param data 输入一维数据
* @param filter_size 滤波器大小,推荐使用奇数
* @param sigma 标准差
* @return
*/
bool My_Gaussianfilter(vector<float> &data, int filter_size, double sigma)
{
double GaussTemp[2*filter_size - 1];
for(int i=0; i<2*filter_size - 1; i++)
{
GaussTemp[i] = exp(-pow((i+1-filter_size), 2)/pow(sigma, 2)/2)/sqrt(2*3.1415)/sigma;
}
double data_filter[data.size()];
for(int i=filter_size-1; i<data.size()-filter_size; i++)
{
data_filter[i] = 0;
for(int j=0; j<2*filter_size - 1; j++)
{
data_filter[i] = data_filter[i] + data.at(i-filter_size+1+j) * GaussTemp[j];
}
}
for(int i=0; i<data.size(); i++)
{
if(i>=filter_size && i<=data.size()-filter_size-1)
{
data.at(i) = data_filter[i];
}
}
return true;
}
Grubbs:原理
// 格拉布斯表
double table[] = { 0.0,0.0,0.0,1.153,1.463,1.672,1.822,1.938,2.032,2.110,2.176,
2.234,2.285,2.331,2.371,2.409,2.443,2.475,2.501,2.532,2.557,
2.580,2.603,2.624,2.644,2.663,2.681,2.698,2.714,2.730,2.745,
2.759,2.773,2.786,2.799,2.811,2.823,2.835,2.846,2.857,2.866,
2.877,2.887,2.896,2.905,2.914,2.923,2.931,2.940,2.948,2.956,
2.943,2.971,2.978,2.986,2.992,3.000,3.006,3.013,3.019,3.025,
3.032,3.037,3.044,3.049,3.055,3.061,3.066,3.071,3.076,3.082,
3.087,3.092,3.098,3.102,3.107,3.111,3.117,3.121,3.125,3.130,
3.134,3.139,3.143,3.147,3.151,3.155,3.160,3.163,3.167,3.171,
3.174,3.179,3.182,3.186,3.189,3.193,3.196,3.201,3.204,3.207 };
// 排序法则,其中:< 升序 >降序
bool comparison(data_sort a,data_sort b)
{
return a.data < b.data ;
}
/**
* @brief My_Grubbs 格拉布斯剔除法
* @param data 待处理数据
* @return
*/
bool My_Grubbs_(vector<data_sort> &data)
{
sort(data.begin(), data.end(), comparison);
// 计算平均值
double data_sum = 0;
for(int i=0; i<data.size(); i++)
{
data_sum += data.at(i).data;
}
double data_ave = data_sum/data.size(); // 平均值
// 计算标准差
data_sum = 0;
for(int i=0; i<data.size(); i++)
{
data_sum += pow((data.at(i).data - data_ave), 2);
}
double data_s = sqrt(data_sum/(data.size() - 1)); // 标准差
if(abs(data_ave - data.at(0).data) > abs(data.at(data.size()-1).data - data_ave)) // 当最小值与均值大于最大值与均值
{
if(abs(data.at(0).data - data_ave)/data_s > table[3]) // 满足Gn大于Gp(n)时,为异常值,剔除最小值
{
data.erase(data.begin()); // 剔除最小值
My_Grubbs_(data); // 进行递归处理
}
else // 条件满足,可以结束
{
return true;
}
}
else if(abs(data_ave - data.at(0).data) < abs(data.at(data.size()-1).data - data_ave)) // 当最大值与均值大于最小值与均值
{
if(abs(data.at(data.size()-1).data - data_ave)/data_s > table[data.size()-1]) // 满足Gn大于Gp(n)时,为异常值,剔除最大值
{
data.erase(data.begin()+data.size()-1); // 剔除最大值
My_Grubbs_(data); // 进行递归处理
}
else // 条件满足,可以结束
{
return true;
}
}
else // 当最大值与均值等于最小值与均值
{
if(abs(data.at(0).data - data_ave)/data_s > table[3]) // 满足Gn大于Gp(n)时,为异常值,剔除最大值和最小值
{
data.erase(data.begin()); // 剔除最小值
data.erase(data.begin() + data.size()-1); // 剔除最大值
My_Grubbs_(data); // 进行递归处理
}
else // 条件满足,可以结束
{
return true;
}
}
return true;
}
bool My_Grubbs(vector<float> &data_ori)
{
vector<data_sort> data;
for(int i=0; i<data_ori.size(); i++)
{
data_sort data_temp;
data_temp.data = data_ori.at(i);
data_temp.id = i;
data.push_back(data_temp);
}
My_Grubbs_(data);
data_ori.clear();
for(int i=0; i<data.size(); i++)
{
data_ori.push_back(data.at(i).data);
}
if(!data.empty())
{
data.clear();
vector<data_sort> tmp;
data.swap(tmp); // 进行交换
}
return true;
}
Ransac:随机抽样迭代判断内点与外点。
/**
* @brief My_Ransac 随机抽样一致性滤波算法
* @param data_ori 待滤波数据,最终滤波后数据
* @param sigma 距离阈值
* @param iters 迭代次数
* @param P 外点占比比率
* @return
*/
bool My_Ransac(vector<float> &data_ori, double sigma, int iters, double P)
{
double best_k, best_b, pretotal = 0;
vector<bool> data_reslut, data_reslut_temp;
// 数据迁移
vector<float> data;
for(int i=0; i<data_ori.size(); i++)
{
data.push_back(data_ori.at(i));
data_reslut.push_back(false);
data_reslut_temp.push_back(false);
}
for(int N=0; N<iters; N++)
{
// 随机计算两点斜率及截距
int dot_ind1 = rand() % (data.size()-1);
int dot_ind2 = rand() % (data.size()-1);
while(dot_ind1 == dot_ind2)
{
dot_ind2 = rand() % (data.size()-1);
}
double k = (data.at(dot_ind1) - data.at(dot_ind2))/(dot_ind1 - dot_ind2);
double b = data.at(dot_ind1) - k*dot_ind1;
// 计算内外点
int total_inlier = 0;
for(int i=0; i<data.size(); i++)
{
double reslut_temp = k*i + b;
if(abs(reslut_temp - data.at(i)) < sigma) // 判断是否为内点
{
data_reslut_temp.at(i) = true;
total_inlier++;
}
else
{
data_reslut_temp.at(i) = false;
}
}
// 更新迭代次数
if(total_inlier > pretotal)
{
iters = log(1.0 - P)/log(1.0-pow(1.0 - double(double(total_inlier)/double(data.size())), 2));
pretotal = total_inlier;
// best_k= k;
// best_b = b;
for(int i=0; i<data.size(); i++)
{
data_reslut.at(i) = data_reslut_temp.at(i);
}
}
}
// 滤波数据更新
data_ori.clear();
for(int i=0; i<data.size(); i++)
{
if(data_reslut.at(i) == true)
{
data_ori.push_back(data.at((i)));
}
}
if(!data.empty())
{
data.clear();
vector<float> tmp;
data.swap(tmp); // 进行交换
}
if(!data_reslut.empty())
{
data_reslut.clear();
vector<bool> tmp;
data_reslut.swap(tmp); // 进行交换
}
if(!data_reslut_temp.empty())
{
data_reslut_temp.clear();
vector<bool> tmp;
data_reslut_temp.swap(tmp); // 进行交换
}
return true;
}
使用中可以根据实际需求,选择相应的算法,或者直接尝试不同滤波方案的效果。