繁体   English   中英

测量线上数据点的变化; 赶上浸

[英]Measure variation of data points from a line; To Catch a Dip

如何在C ++中测量该区域?

(更新:我发布了解决方案和代码作为答案,而不是再次编辑问题)

如何量化理想曲线和测量曲线之间的蓝色区域
理想线(红色虚线)是从起点开始的图,每个测量角度均加上平均上升; 我通过平均获得。 我用黑色测量了测试数据。 如何量化蓝色浸入区域? 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小于AVG2x 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分以上的测试感觉上乘,但是该测试对这些下降并不了解。

处所

  • 一组数据的平均值具有数学性质,即与平均值的偏差之和为0。
    • 这解释了为什么坏数据集和好的数据集都给出几乎为零的原因。
    • 基本上,当结果不同于零时,本质上是差异中舍入误差的累积,这就是为什么不幸地无法保存有用信息的原因
  • 最清楚地定义您正在寻找的东西是您的图像:您正在寻找一个区域 ,这就是为什么您不能以这种方式找到解决方案的原因:
    • 在单点上寻找指标太本地化而无法提取该信息
    • 寻求全局累积或参数(全局标准偏差)过于笼统,您将丢失太多信息和变异源中的数据
    • 峰度(您已经告诉我,但出于完整性考虑)不在其应用范围内,因为这不是概率分布
    • 最后,您已经尝试过的方法中更合适的方法是“自制倾角检测器”,因为它以本地方式思考,但不会过多。
  • 最后但并非最不重要的:
    • 您要选择的任何算法都有其默认点。
      • 因此,也许有人正在寻找一种超级聪明的算法,该算法无需进行参数化和调整即可自动适应问题,并可以自定义问题。
      • 另一方面,存在一种算法,它将基于作者对典型数据行为(好的和坏的)的知识,并且该算法本身很愚蠢,即如果存在另一种不同的和无法预期的行为,则结果是不可预测的
      • 好的,正确的方法是这两种方法之一,或介于两者之间,具体取决于应用程序。 因此,如果它也可以使用“自制倾角检测器”可以解决。 没有理由将其定义为粗略的,但是根据应用程序的需求可能还不够,这是另一回事。

如何寻找地区

  • 获得数据后,首先要做的就是清楚地定义“理论直线”。 我提供一些选择:
    • 使用RANSAC算法( 正式上是IMHO的最佳选择)
      • 这使您最适合对齐点,而不管未对齐点
      • 这项工作相当困难,甚至可能过大(恕我直言)
    • 考虑由第一点和最后一点定义的线
      • 您告诉我们,逢低点几乎总是在不靠近边界的同一位置,因此可以认为第一点和最后一点是负担得起的
      • 非常容易实现
      • 这是使用我之前讲过的有关预期行为的知识的示例,因此您需要考虑您是否以及对该假设有多大的信心
    • 考虑前10个点和后10个点的线性拟合
      • 只是以前版本的更实惠的版本,因为使用更多的点,您可以不必担心仅第一个点或最后一个点会受到任何度量问题的影响,因此所有操作都会因此失败
      • 也很容易实现
      • 如果我是你,我将使用这个或启发这个的东西
  • 计算每个X的直线给出的Y值
  • 使用以下过程计算两条曲线之间的面积(或函数Y_dev = Y_data - Y_straight在数学上相同的Y_dev = Y_data - Y_straight ):
    • PositiveMax = 0; NegativeMax = 0;
    • 从第一个点开始(值可以为正或负),然后放入临时区域累加器tmp_Area
    • 对于每个下一个点
      • 如果符号相同,则累加值
      • 如果不同
        • 停止积累
        • 检查累计值是否大于PositiveMax或小于NegativeMax,以及是否大于等于存储为新的PositiveMax或NegativeMax
        • 无论如何,用tmp_Area = Y_dev;复位累加器tmp_Area = Y_dev; 到以这种方式开始的当前值的新积累
    • 最后,您将获得最大高估的连续区域和最大低估的连续区域的值,我认为这是您想要的分数。
    • 如果需要,您只能根据观察到的和预期的数据行为来管理NegativeMax
    • 您可能会发现放置阈值很有用,因此,如果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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM