我们在用各种测量模块或设备进行测量时,或多或少会受到各种干扰的影响,使得到的数据与真实情况有所偏差,甚至与正确的数值差之千里。通常我们采用统计学的方法来获得相对正确的值,最基本的就是用平均值方法,即将大量数据进行累加再除以数据个数而获得均值。不过这个方法的前提是大量数据,而我们用Arduino这类工控设备进行动态测量和控制时,会受到采样频率和响应时间的限制,不可能进行数万次的采样后再进行处理。

那如果我们采样几十个数据后就马上求取均值是不是可以呢?答案是肯定的,不过不能采用简单的直接求均值方法,因为在样本数据比较少的情况下,即使只有极少量的异常数据,都会造成均值与正确值的较大偏离。例如我们有10个人,其中一个是马云,另9人年薪在15万左右,结果一求平均年薪,我们每人的年薪都被平均到10亿了。在测量中,我们也会碰到这种情况,由于外界偶发的干扰以及测量设备内部产生的电子干扰等,都会出现异常的数据。那怎么办呢?我们自然想到先将这些异常数据剔除掉,然后再求均值。这种方法的基本思想是:给定一置信概率,确定相应的置信区间,凡超过置信区间的误差就认为是粗差,应予以剔除。用于粗大误差剔除的常见方法有莱特检验法和格拉布斯检验法。

我们先简单的了解下莱特检验法和格拉布斯检验法。首先我们假定测量获得的数据呈正态分布,通俗点讲,就是测量获得的数据基本散布在正确值(真值)的附近,越靠近中心数据个数越多。这里我们先导出一个“残差”的概念,设第i次获得的数据为Xi,它与真值的差,我们称之为“残差”,不过我们根本不知道真值是多少,因此我们就用均值Xbar来代替真值,利用残差和数据量N,我们可以用贝塞尔公式求得σ(x),请参看下图。莱特准则就是残差|Vi|>3σ(x)时就作为粗大误差数据,予以剔除。在测量数据分布不能确定,对测量次数没有太大要求的情况下,通常取2更有适用性。看下图:

我们再来看格拉布斯准则为:|Vi|>g(n,a)σ(x)时就作为粗差数据,格拉布斯准则中的g(n,a)是一个取决于测量次数n和置信概率a,置信概率就是测量数据落在这个区间中的概率,格拉布斯准则中最常用置信概率为95%和99%,即如果采用a=95%,意味着有95%的数据是落在可信的区间里。这里特别要注意的是,置信概率越大,则置信区间越大,似乎是大一点好,其实并不然,置信区间越大,最大偏差的范围也就越大,那异常数据落入这个区间的概率也越大,即置信概率大的情况下,异常数据就可能没有被排除掉,反而造成我们的平均值偏离了正确值。g(n,a)的值我们可以通过下面的表来查看:

下面说下程序的实现,本程序建立了一个Detection,包含了莱特准则、格拉布斯95%、格拉布斯99%准则,还可以自定义贝塞尔公式前的系数(我称之为准则量),我们只需提供必要的数据后,调用该子程序就可以获得剔除粗差数据后的均值:

double Detection(double data[],double baddata[],int datanum,int badnum,int rule)

Detection子程序返回的是剔除粗差数据后的平均值;参数data输入时为原始测量数据,返回时,前datanum个数据为有效数据(即剔除粗差数据后的数据);参数baddata无输入数据,输出为被剔除的数据;参数datanum输入为原始测量数据个数;参数datanum无输入数据,输出为剔除的数据个数;参数rule为莱特or格拉布斯准则选择,3为莱特准则,4为格拉布斯95%,5为格拉布斯99%,小于3为自定义准则量。

程序采用了循环检测方式,即选定某个准则后,根据该准则剔除粗差数据后,再进行检测,如果还有粗差数据,再次剔除该粗差数据,依次循环,直到没有可剔除的粗差数据为止(或有效数据不足6个)。

此外,子程序中的Serial.print和Serial.println语句是用于调试和观察粗差数据的处理过程用,在正式使用该子程序时,应该注解掉或直接删除这些Serial.print语句。

本程序在Arduino UNO板上测试运行过,只需直接下载到Arduino UNO板即可,下面是完整的程序:

/*
本程序建立了一个Detection子程序,包含了莱特准则、格拉布斯95%、格拉布斯99%准则,
还可以自定义贝塞尔公式前的系数(我称之为准则量),
我们只需提供必要的数据后,调用该子程序就可以获得剔除粗差数据后的均值*/const int DATAN=15; //原始测试数据的个数
double dt[DATAN]={21.35,20.36,20.37,20.34,20.31,20.2,20.32,20.4,20.33,20.38,20.36,20.29,20.40,20.41,20.95};//原始测试数据
double bdt[DATAN];//存放被剔除的数据
int dn=DATAN;//数据个数
int bdn;//被剔除的数据个数void setup() {Serial.begin(9600); //设置串口波特率9600Serial.println(Detection(dt,bdt,dn,bdn,4));//最后一个参数4,表示采用格拉布斯95%准则,可以用其他值进行测试
}void loop() {// put your main code here, to run repeatedly:}//误差数据剔除程序,返回有效数据的平均值
//参数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;while(1){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) lg=g95[22];else lg=g95[datanum-3];}else if(rule==5)//格拉布斯99%{if(datanum>=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) lg=g99[22];else lg=g99[datanum-3];}proindex++;Serial.println("**It is the times to cal.**");Serial.println(proindex);sum=0;for(i=0;i<datanum;i++)sum+=data[i];average=sum/datanum; //计算平均值Serial.println("Your data are: ");sum=0;for(i=0;i<datanum;i++){Serial.println(data[i]);v[i]=data[i]-average; //计算残差sum+=v[i]*v[i]; //计算残差平方和}Serial.println("the residual are:");for(i=0;i<datanum;i++)Serial.println(v[i]);bsl=sqrt(sum/(datanum-1)); //计算贝塞尔公式标准差maxdev=lg*bsl; //计算最大偏差//输出相关信息Serial.print("The average is: ");Serial.println(average);Serial.print("The Bessel Formula is: ");Serial.println(bsl);Serial.print("The Laite or Grubs level is:");Serial.println(lg);Serial.print("The Max deviation is: ");Serial.println(maxdev);//剔除坏值,即剔除粗差数据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++) //将暂存的效数数据送回数据数组datadata[i]=data_b[i];datanum=validNum;//将当前有效数据个数作为数据个数if(datanum>5)//有效数据大于5个,则继续进行处理{if(badindex==0) //若没有可剔除的粗差数据{Serial.print("There is no baddata , end.");Serial.println(proindex);break;//跳出循环,即粗差数据处理完毕}else//否则,即有粗差数据,继续循环处理{Serial.print("You have got baddata in the times cal!!!  ");Serial.println(proindex);Serial.print("You have got baddata number is: ");Serial.println(badindex);Serial.println("the bad data is ");for(i=0;i<badnum;i++)Serial.println(baddata[i]);}}else break;//有效数据小于等于5个,直接跳出循环}//误差数据处理完毕Serial.println("**Summary**");//输出剩余数据Serial.println("the valid data are: ");for(i=0;i<validNum;i++)Serial.println(data_b[i]);//输出所有坏值Serial.println("the bad data are: ");for(i=0;i<badnum;i++)Serial.println(baddata[i]);Serial.print("The last average is: ");Serial.println(average);Serial.print("The last Max deviation is: ");Serial.println(maxdev);return average;//子程序返回有效数据的均值
}

Arduino测量误差数据的处理——莱特、格拉布斯准则剔除异常数据相关推荐

  1. (转)格拉布斯准则(Grubbs Criterion)处理数据异常

    (转)格拉布斯准则(Grubbs Criterion)处理数据异常 参考文章: (1)(转)格拉布斯准则(Grubbs Criterion)处理数据异常 (2)https://www.cnblogs. ...

  2. java实现格拉布斯准则_格拉布斯准则(java代码)

    package rule; import java.util.HashMap; import java.util.List; import java.util.Map; //格拉布斯准则 public ...

  3. 【数据异常校验】拉依达准则( PauTa Criterion 或 3σ准则) 处理异常数据

    拉依达准则是指先假设一组检测数据只含有随机误差,对其进行计算处理得到标准偏差,按一定概率确定一个区间,认为凡超过这个区间的误差,就不属于随机误差而是粗大误差,含有该误差的数据应予以剔除. 这种判别处理 ...

  4. C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)

    1.问题的提出: 电池生产中,遇到一批电池的测量结果数据: 电压值 电池个数 电压值 电池个数 电压值 电池个数 电压值 电池个数 0.056 1   4.09 1   4.146 17   4.17 ...

  5. 怎样用excel剔除异常数据_excel如何去除异常值?(excel表格数据异常丢失)

    急!!!java用poi导出excel文件,打开导出的文件时报错"文件错误,数据可能丢失" 我遇到过这个问题后调查发现两个原因: 1.你的excel模版本身有问题,可以尝试新建一个 ...

  6. 怎样用excel剔除异常数据_(如何剔除excel表格中重复的数据)excel表格怎么剔除异常数据...

    请问 Excel 如何剔除与平均数偏差较大的数字再求平均数?谢谢. 把问题作为内容(邮件主定要包含"excel",本人以此据辨别非垃圾邮件,以免误删).excel样件(请特别注意: ...

  7. 拉依达准则去除异常数据

    1.Concept 拉依达准侧(Pau'ta Criteron)是先假设一组数据中只含有随机误差,首先按照一定准侧计算标准偏差,按照一定概率确定一定区间,认为不在这个区间的为异常值. 使用数据类型:数 ...

  8. 怎样用excel剔除异常数据_【Excel技巧】IFERROR函数,从结果中剔除不需要的值!...

    在Excel中使用IFERROR函数可以用来判断某些内容的正确与否,正确则返回正确结果,错误则返回需要显示的信息. IFERROR函数的语法为:IFERROR(value, value_if_erro ...

  9. 肖维勒准则matlab_莱因达 ( PauTa)准则、格拉布斯 ( Grubbs)准则、肖维纳 (Chauvenet)准则 三者的区别...

    展开全部 1.检测数量不同32313133353236313431303231363533e78988e69d8331333431363566 莱因达准则是以三倍测量列的标准偏差为极限取舍标准,其给定 ...

  10. python异常数据_python异常数据预警之3sigma

    3sigma原理一般在工程科学中比较常用,我们在故障预警中用过这个原理,数据是用传感器采集的数据,这些数据假定符合正态分布,然后在进行模型识别后用3sigma原则来对异常数据进行准确定位.在实际应用中 ...

最新文章

  1. 安装rebar时提示Uncaught error in rebar_core
  2. 查看linux系统性能
  3. python tk下拉列表的state_Python tkinter之ComboBox(下拉框)的使用简介
  4. Linux设备驱动--块设备(三)之程序设计(转)
  5. Linux查看CPU、内存、IO占用高的进程
  6. mysql pt-kill_percona-toolkit之pt-kill 杀掉mysql查询或连接的方法
  7. 人脸识别算法不可置疑?真相需要多重验证!
  8. jenkins的历史
  9. 升级阿里云主机系统镜像
  10. Eclipse中如何更改工作空间(之前一直不知道,几天终于知道了!)。
  11. 表格标签(HTML)
  12. 【算法】LeetCode算法题-Length Of Last Word
  13. docker工作原理、组成部分、特点优点
  14. emacs操作方法总结
  15. win10没有自带计算机,Win10没有自带游戏怎么办 Win10找回自带游戏方法
  16. 计算机python考试真题及答案新课标_CCF计算机职业资格认证考题答案详解(Python)...
  17. 12306 验证码代码分析
  18. Java Scanner常用用法
  19. C语言隐式类型转换(字符类型以及短整型的运算规则)
  20. if-else 语句优雅处理

热门文章

  1. 计算机应用技术中的c语言,C语言程序设计——Visual C++6.0(高等院校计算机应用技术系列教材)...
  2. 数学家刘徽李善兰陈景润华罗庚
  3. 安卓学习日志 Day15 — 数据库基础
  4. UCI数据集(论文常用数据集)
  5. Elf二进制文件解析
  6. 全国计算机一级word题库,2016全国计算机一级《MS Office》选择题题库
  7. 公式经纬度换算度分秒,度分秒换算经纬度
  8. 制作网页版Excel表
  9. App功能测试点总结
  10. windows10 专利申请客户端CPC