Arduino异常数据的剔除——莱特、格拉布斯准则

莱特准则

简介

莱特准则是一种正态分布情况下判别异常值的方法。具体内容如下:
假设在一列等精度测量结果中,第 i i i个测量值 x i x_i xi所对应的残差 v i = x i − x ˉ v_i=x_i-\bar{x} vi=xixˉ的绝对值满足 ∣ v i ∣ m a x > 3 σ x ˉ |v_i|_{max}>3\sigma_{\bar{x}} vimax>3σxˉ则该误差为粗差,所对应的测量值 x i x_i xi为异常数值,应剔出不用。

其中标准偏差估计: σ = 1 n − 1 ∑ i = 1 n v i 2 (贝塞尔公式) \sigma=\sqrt{\frac{1}{n-1}\sum_{i=1}^{n}v_i^2}(贝塞尔公式) σ=n11i=1nvi2 (贝塞尔公式)莱特准则使用方便,比较适用于测量次数 n n n较大时 ( n > 10 ) (n>10) n>10)

格拉布斯准则

简介

格拉布斯准则是在未知总体标准差情况下,对正态样本或接近正态样本异常值的一种判别方法。
某个测量值的残差 v i = x i − x ˉ > T 0 ( n , α ) v_i=x_i-\bar{x}>T_0(n,\alpha) vi=xixˉ>T0(n,α)则判断此值中含有粗大误差, 应予剔除。

T T T值与重复测量次数 n n n和置信概率 α \alpha α均有关,因此格拉布斯准则是比较好的判定准则。

T T T值通过查表获得。

格拉布斯准则理论较严密,概率意义明确,可用于严格要求的场合,当 20 < n < 100 20<n<100 20<n<100时,判别效果较 好。
附表: T 0 ( n , α ) T_0(n,\alpha) T0(n,α)
在这里插入图片描述

Arduino代码实现

// 误差数据剔除程序,返回有效数据的平均值
// 参数data输入为原始测量数据,返回时,前datanum个为有效数据
// 参数baddata无输入数据,输出为被剔除的数据
// 参数datanum输入为原始测量数据个数
// 参数badnum无输入数据,输出为剔除的数据个数
// 参数rule为莱特or格拉布斯准则选择,3为莱特准则,4为格拉布斯95%,5为格拉布斯99%,小于3为自定义准则
double Detection(double data[], double baddata[], int datanum, int &badnum, int rule)
{
    double data_b[datanum];                                                                                                                                                                  // 临时存放保留的数据
    double v[datanum];                                                                                                                                                                       // 残差
    double g95[] = {1.15, 1.46, 1.67, 1.82, 1.94, 2.03, 2.11, 2.18, 2.23, 2.29, 2.33, 2.37, 2.41, 2.44, 2.47, 2.50, 2.53, 2.56, 2.58, 2.60, 2.62, 2.64, 2.66, 2.74, 2.81, 2.87, 2.96, 3.17}; // 格拉布斯95%
    double g99[] = {1.16, 1.49, 1.75, 1.94, 2.10, 2.22, 2.32, 2.41, 2.48, 2.55, 2.61, 2.66, 2.71, 2.75, 2.79, 2.82, 2.85, 2.88, 2.91, 2.94, 2.96, 2.99, 3.01, 3.10, 3.18, 3.24, 3.34, 3.58}; // 格拉布斯99%
    double bsl;                                                                                                                                                                              // 贝塞尔公式结果
    double maxdev;                                                                                                                                                                           // 有效的莱特 or 格拉布斯准则的最大偏差
    double sum;                                                                                                                                                                              // 累加临时存储
    double average;                                                                                                                                                                          // 平均值
    int badindex;                                                                                                                                                                            // 某次剔除数据数
    int validNum = 0;                                                                                                                                                                        // 有效数据数
    int proindex = 0;                                                                                                                                                                        // 循环的次数
    double lg;                                                                                                                                                                               // 莱特 or 格拉布斯准则的系数
    int i;
    if (rule <= 3) // 当rule小于等于3时,直接用莱特系数3或自定义的rule值
        lg = rule;
    else if (rule > 5) // 当rule大于5时,强制设为莱特准则
        lg = 3;
    badnum = 0; // 初始化坏数据数
                // 循环,直到有效数据个数小于等于5或没有坏数据为止
    while (1)
    {
        // 根据rule值选择不同的格拉布斯准则
        if (rule == 4) // 格拉布斯95%
        {
            if (datanum >= 100)
                lg = g95[27]; // 数据个数大于100个时
            else if (datanum >= 50)
                lg = g95[26];
            else if (datanum >= 40)
                lg = g95[25];
            else if (datanum >= 35)
                lg = g95[24];
            else if (datanum >= 30)
                lg = g95[23];
            else if (datanum >= 25) // 数据个数大于25个但小于30个时
                lg = g95[22];
            else // 数据个数小于25个时
                lg = g95[datanum - 3];
        }
        // 当rule为5时,使用格拉布斯99%准则
        else if (rule == 5) // 格拉布斯99%
        {
            if (datanum >= 100) // 数据个数大于100个时
                lg = g99[27];
            else if (datanum >= 50)
                lg = g99[26];
            else if (datanum >= 40)
                lg = g99[25];
            else if (datanum >= 35)
                lg = g99[24];
            else if (datanum >= 30)
                lg = g99[23];
            else if (datanum >= 25) // 数据个数大于25个但小于30个时
                lg = g99[22];
            else // 数据个数小于25个时
                lg = g99[datanum - 3];
        }
        proindex++; // 更新循环次数

        sum = 0;
        for (i = 0; i < datanum; i++)
            sum += data[i];
        average = sum / datanum; // 计算平均值

        sum = 0;
        for (i = 0; i < datanum; i++)
        {
            v[i] = data[i] - average; // 计算残差
            sum += v[i] * v[i];       // 计算残差平方和
        }

        bsl = sqrt(sum / (datanum - 1)); // 计算贝塞尔公式标准差
        maxdev = lg * bsl;               // 计算最大偏差

        // 剔除坏值,即剔除粗差数据
        validNum = 0;
        badindex = 0;
        for (i = 0; i < datanum; i++)
            if (fabs(v[i]) >= maxdev && maxdev != 0) // 当|Vi|>准则偏差值时
            {
                baddata[badnum++] = data[i]; // 将该Xi作为粗差数据,放入坏数据数组
                badindex++;
            }
            else
                data_b[validNum++] = data[i]; // 否则将效数数据暂存到data_b数组
        for (i = 0; i < validNum; i++)        // 将暂存的效数数据送回数据数组data
            data[i] = data_b[i];
        datanum = validNum; // 将当前有效数据个数作为数据个数
        // 判断是否满足停止条件
        if (datanum > 5) // 有效数据大于5个,则继续进行处理
        {
            if (badindex == 0) // 若没有可剔除的粗差数据
                break;         // 跳出循环,即粗差数据处理完毕
        }
        else
            break; // 有效数据小于等于5个,直接跳出循环
    }
    return average; // 子程序返回有效数据的均值
}

参考资料

[1]Arduino用超声波测距模块HC-SR04获得精确测量值——误差数据的排除.https://blog.youkuaiyun.com/m0_61543203/article/details/127185686
[2]Arduino测量误差数据的处理——莱特、格拉布斯准则剔除异常数据.https://blog.youkuaiyun.com/m0_61543203/article/details/126780804
[3]统计学 莱特准则是什么.https://zhidao.baidu.com/question/144962833.html
[4]异常数据及偏离数据处理原则.https://zhuanlan.zhihu.com/p/93855259

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值