[英]Measure variation of data points from a line; To Catch a Dip
(更新:我发布了解决方案和代码作为答案,而不是再次编辑问题)
理想线(红色虚线)是从起点开始的图,每个测量角度均加上平均上升; 我通过平均获得。 我用黑色测量了测试数据。 如何量化蓝色浸入区域? X轴是统一的,因此简化了斜率和数学运算。
我可以确定像这样的区域大小的临界值,然后将其标记为重新测试或失败。 很少会出现一个更靠近右侧的倾斜,但是设置标准偏差的临界值通常会使这些零件失效。
迭戈的答案帮助我形象地看到了这一点。 现在,我可以看到要执行的操作,接下来将研究实现“自制倾斜检测器”的算法。 :)
我创建了一个测试台来测试我要销售的节气门位置传感器。 我正在尝试通过分析收集的数据以编程方式量化绘图的直线度。 这个特殊的模型让我很烦恼。
我不想出售的零件的样图:
X轴是节气门开度的均匀间隔角。 步进电机转动输入轴,每0.75°停止一次,以测量10位ADC上的输出,该输出转换为Y轴。 该图是data[idx]
到idx,value
映射到(x,y)
位图坐标。 然后,我使用Bresenham算法在位图中的点之间绘制线。
我的其他TPS产品产生令人惊讶的线性输出 。
该图的下部(左侧)对于任何汽车的正常使用都是至关重要的。 这是当您在城镇周围开车,进入停车场等时。该特定部分趋向于在15°的开度附近出现倾角,我希望使用该程序来量化曲线中的“倾角”,而不再依赖于测试人员的直觉。 在上面的示例中,地势有所下降,但并未恢复到理想的水平。
即使这是一个嵌入式应用程序,打印报告也需要10秒钟,因此我不认为多次遍历120个点的数据数组会浪费周期。 另外,由于我使用的是uC32 PIC32微控制器 ,因此有足够的内存,因此我能够在控制器内考虑此问题,这是我的荣幸 。
测试点之间的上升阵列:考虑到X轴是统一的,我将X轴完全消除,然后从一个读数到下一个读数进行一系列变化。 此数组有助于报表的“点之间的最小上升:0最大:14”。 我称这个数组为deltas 。
我尝试对增量使用标准偏差 ,但是,在测试期间,我发现对于这部分,低标准偏差不是可靠的度量。 如果跌落很快返回到早期数据点所暗示的原始线,则Std Dev可以说是低的(观察到低至2.3),但是该部分仍然是我不想使用的东西。 我尝试将临界值设置为2.6,但由于积压大,它使太多零件失效。 上面链接的另一个更线性的部分可以可靠地依靠Std Dev来保证质量。
峰态似乎根本不适合这种情况。 我今天了解了峰度 ,并找到了一个包含峰度和偏度的统计资料库 。 在继续测试期间,我发现在这两个度量中,没有与通过或失败相对应的正,负或振幅趋势。 这位先生共享一个线性回归库,但是我相信Lin Reg与我的情况无关,因为我很满意地认为增量 AVG是我的理想选择。 线性回归和R ^ 2更适合从不太理想的数据或更大的数据集中找到一条线。
每个三角洲AVG和标准偏差比较我设置了一个监控器所要检查的增量的数据的最终平均每个增量。 在这里,我也找不到可靠的指标。 太多合格零件将无法通过将任何差值限制在偏离平均值2倍标准偏差之内的测试。 最终,我可以确定的与AVG唯一的区别是与AVG本身的差异在AVG+Std Dev
之内。 任何更严格的限制都会使本来不错的部分失败。 大约15°的开度难以捉摸,可以通过此测试。
自制的倾角检测器当将增量提供给计算机的串行监视器时,我在倾角期间观察到连续的负增量 ,因此我在倾角检测器中进行了编程,但对我来说却非常粗糙。 如果连续存在5个或更多的负增量 ,则将它们相加。 我已经看到,如果我将这个总和与AVG的骤降之差相除,然后除以负增量的数量,则大于2.9或3的值可能表示失败。 我观察到跌幅持续6至15个三角洲。 容易观察到的下探值与AVG的总和之间的差值最多为-35。
AVG累积变化趋势的趋势上面的内容使我认为,观察偏离AVG的增量总和可能是答案。 意思是,我遍历数组并求和AVG中每个增量的差。 我以为我一直在研究某件事,直到很大一部分使这个理论破灭。 我看到一种趋势,即运行总和与AVG
小于AVG
的2x AVG
倍,则直线显示得越直。 许多理想零件只会显示8个或更少的增量点,而sumOfDiffs
将偏离AVG很远。
float sumOfDiffs=0.0;
for( int idx=0; idx<stop; idx++ ){
float spread = deltas[idx] - line->AdcAvgRise;
sumOfDiffs = sumOfDiffs + spread;
...
testVal = 2*line->AdcAvgRise;
if( sumOfDiffs > testVal || sumOfDiffs < -testVal ){
flag = 'S';
}
...
}
然后,通过58个数据点sumOfDiffs
了具有奇妙线性图的零件,其中sumOfDiffs
是AVG的两倍以上! 我发现这很棒,因为在sumOfDiffs
个数据点的末尾, sumOfDiffs
值为-0.000057。
在测试期间,最终的sumOfDiffs
结果通常会记录为0.000000,并且只有在异常情况下,该结果才大于.000100。 实际上,我发现这很令人惊讶:“不良零件”如何积累出很高的准确性。
监视sumOfDiffs的样本输出此下面的输出显示发生了下降。 该测试sumOfDiffs
,在整个测试过程中,运行的sumOfDiffs
距离AVG的距离是AVG的2 sumOfDiffs
以上。 此倾角持续从增量 idx
的23至49; 从17.25°开始,持续19.5°。
Avg rise: 6.75 Std dev: 2.577
idx: delta diff from avg sumOfDiffs Flag
23: 5 -1.75 -14.05 S
24: 6 -0.75 -14.80 S
25: 7 0.25 -14.55 S
26: 5 -1.75 -16.30 S
27: 3 -3.75 -20.06 S
28: 3 -3.75 -23.81 S
29: 7 0.25 -23.56 S
30: 4 -2.75 -26.31 S
31: 2 -4.75 -31.06 S
32: 8 1.25 -29.82 S
33: 6 -0.75 -30.57 S
34: 9 2.25 -28.32 S
35: 8 1.25 -27.07 S
36: 5 -1.75 -28.82 S
37: 15 8.25 -20.58 S
38: 7 0.25 -20.33 S
39: 5 -1.75 -22.08 S
40: 9 2.25 -19.83 S
41: 10 3.25 -16.58 S
42: 9 2.25 -14.34 S
43: 3 -3.75 -18.09 S
44: 6 -0.75 -18.84 S
45: 11 4.25 -14.59 S
47: 3 -3.75 -16.10 S
48: 8 1.25 -14.85 S
49: 8 1.25 -13.60 S
Final Sum of diffs: 0.000030
RunningStats analysis:
NumDataValues= 125
Mean= 6.752
StandardDeviation= 2.577
Skewness= 0.251
Kurtosis= -0.277
关于质量的清晰提示:我踏上这一旅程的第一步是学习主要的汽车OEM供应商如何将4点测试作为这些零件的标准度量。 我的第一个测试台使用的是Arduino,内存为8k,没有TFT显示屏,也没有打印机,机械分辨率仅为3°! 那时,我只是简单地测试了增量在任意总范围内,并选择了单个增量可能有多大的限制。 与之前的30点测试相比,我的120分以上的测试感觉上乘,但是该测试对这些下降并不了解。
Y_dev = Y_data - Y_straight
在数学上相同的Y_dev = Y_data - Y_straight
):
PositiveMax = 0; NegativeMax = 0;
tmp_Area
tmp_Area = Y_dev;
复位累加器tmp_Area = Y_dev;
到以这种方式开始的当前值的新积累 Y_dev
值小于阈值,则不会累加该值。 事实证明,这是我的直觉的结果,而Diego的方法是积分的平均值。 我仍然不喜欢该名称,因此我已经描述了算法,并在Math.SE上询问了该名称的含义,该名称已迁移到“交叉验证”(Stats.SE) 。
在对Math.SE问题进行大量编辑之后,我更新了图表。 事实证明,我正在获取数据导数的闭合积分的平均值。 :P首先,我们收集数据:
接下来是“导数”:逐步遍历原始数据数组以形成增量数组,这是ADC值从一个0.75°步进到下一个步进的增量 。 “上升”或“斜率”是派生词:dy / dx。
在“斜率”或平均水平趋于平稳的情况下,我可以连续找到多个负增量 ,将其相加,然后在下降结束时除以计数。 总和是平均值和增量之间面积的整数,当下降幅度返回正值时,我可以将总和除以下降幅度的计数。
在测试过程中,我得出了该平均值的平均值的截止值2.6。 这是衡量我的“直觉”来衡量部分认为好坏的好方法。
万一有人发现自己试图对此进行量化,这是我实现的代码。 请注意,它只是在寻找负跌幅。 另外,在其他地方将dipCountLimit定义为5。除了倾角检测器/累加器(即,数值积分器)之外,我还具有一个尖峰检测器,如果有任何数据点偏离平均值+平均值+标准,则可以任意将测试标记为不良。偏差。 根据观察到的可能会损坏的零件图,任意选择AVG + STD DEV作为峰值限制。
int dipdx=0;
// inDipFlag also counts the length of this dip
int inDipFlag=0;
float dips[140] = { 0.0 };
for( int idx=0; idx<stop; idx++ ){
const float diffFromAvg = deltas[idx] - line->AdcAvgRise;
// state machine to monitor dips
const int _stop = stop-1;
if( diffFromAvg < 0 && idx < _stop ) {
// check NEXT data point for negative diff & set dipFlag to put state in dip
const float nextDiff = deltas[idx+1] - line->AdcAvgRise;
if( nextDiff < 0 && inDipFlag == 0 )
inDipFlag = 1;
// already IN a dip, and next diff is negative
if( nextDiff < 0 && inDipFlag > 0 ) {
inDipFlag++;
}
// accumulate this dip
dips[dipdx]+= diffFromAvg;
// next data point ends this dip and we advance dipdx to next dip
if( inDipFlag > 0 && nextDiff > 0 ) {
if( inDipFlag < dipCountLimit ){
// reset the accumulator, do not advance dipdx to next entry
dips[dipdx]=0.0;
} else {
// change this entry's value from dip sum to its ratio
dips[dipdx] = -dips[dipdx]/inDipFlag;
// advance dipdx to next entry
dipdx++;
}
// Next diff isn't negative, so the dip is done
inDipFlag = 0;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.