我有一个应用程序需要在给定的数据集中找到峰值的位置分辨率必须远远高于数据点之间的间距(即,不足以找到最高数据点,相反,必须根据峰值形状估计“虚拟”峰值位置)峰值由大约4或5个数据点组成每隔几毫秒采集一个数据集,并实时进行峰值检测。
我比较了LabVIEW中的几种方法,发现LabVIEW PeakDetector.vi给出了最好的结果(在分辨率和速度方面),它使用一个移动窗口(>=3点宽度)扫描数据集,并对每个位置执行二次拟合由此产生的二次函数(抛物线)具有局部最大值,这又与附近点相比。
现在我想在C中实现同样的方法。多项式拟合的实现如下(使用高斯矩阵):

// Fits *y from x_start to (x_start + window) with a parabola and returns x_max and y_max
int polymax(uint16_t * y_data, int x_start, int window, double *x_max, double *y_max)
{
    float sum[10],mat[3][4],temp=0,temp1=0,a1,a2,a3;
    int i,j;

    float x[window];
    for(i = 0; i < window; i++)
        x[i] = (float)i;

    float y[window];
    for(i = 0; i < window; i++)
        y[i] = (float)(y_data[x_start + i] - y_data[x_start]);

    for(i = 0; i < window; i++)
    {
        temp=temp+x[i];
        temp1=temp1+y[i];
    }
    sum[0]=temp;
    sum[1]=temp1;
    sum[2]=sum[3]=sum[4]=sum[5]=sum[6]=0;

    for(i = 0;i < window;i++)
    {
        sum[2]=sum[2]+(x[i]*x[i]);
        sum[3]=sum[3]+(x[i]*x[i]*x[i]);
        sum[4]=sum[4]+(x[i]*x[i]*x[i]*x[i]);
        sum[5]=sum[5]+(x[i]*y[i]);
        sum[6]=sum[6]+(x[i]*x[i]*y[i]);
    }
    mat[0][0]=window;
    mat[0][1]=mat[1][0]=sum[0];
    mat[0][2]=mat[1][2]=mat[2][0]=sum[2];
    mat[1][2]=mat[2][3]=sum[3];
    mat[2][2]=sum[4];
    mat[0][3]=sum[1];
    mat[1][3]=sum[5];
    mat[2][3]=sum[6];

    temp=mat[1][0]/mat[0][0];
    temp1=mat[2][0]/mat[0][0];
    for(i = 0, j = 0; j < 3 + 1; j++)
    {
        mat[i+1][j]=mat[i+1][j]-(mat[i][j]*temp);
        mat[i+2][j]=mat[i+2][j]-(mat[i][j]*temp1);
    }

    temp=mat[2][4]/mat[1][5];
    temp1=mat[0][6]/mat[1][7];
    for(i = 1,j = 0; j < 3 + 1; j++)
    {
        mat[i+1][j]=mat[i+1][j]-(mat[i][j]*temp);
        mat[i-1][j]=mat[i-1][j]-(mat[i][j]*temp1);
    }

    temp=mat[0][2]/mat[2][2];
    temp1=mat[1][2]/mat[2][2];
    for(i = 0, j = 0; j < 3 + 1; j++)
    {
        mat[i][j]=mat[i][j]-(mat[i+2][j]*temp);
        mat[i+1][j]=mat[i+1][j]-(mat[i+2][j]*temp1);
    }

    a3 = mat[2][3]/mat[2][2];
    a2 = mat[1][3]/mat[1][8];
    a1 = mat[0][3]/mat[0][0];

    // zX^2 + yX + x

    if (a3 < 0)
    {
        temp = - a2 / (2*a3);
        *x_max = temp + x_start;
        *y_max = (a3*temp*temp + a2*temp + a1) + y_data[x_start];
        return 0;
    }
    else
       return -1;
}

扫描在外部函数中执行,该函数反复调用上述函数,然后选择最高的本地y_max。
上面的作品和高峰都找到了只有噪声比LabVIEW对应的要差得多(即,给定相同的输入数据集和相同的参数,我得到一个非常振荡的峰值位置)由于算法工作,上面的代码在概念上应该是正确的,所以我认为这可能是一个数值问题,因为我只是使用“float”而没有进一步提高数值精度这是可能的答案吗有没有人给我小费,我应该去哪里?
谢谢。
注:我已经做了我的搜索,发现这个非常good overviewthis question,类似于我的(不幸的是没有很多答案)我将进一步研究这些。
编辑:我发现我的问题在别处通过删除某些输出值(一种仅在结果位于移动窗口内时才接受结果的后验证)改进算法,解决了该问题现在我对结果感到满意,也就是说,它们与LabVIEW的结果相当不过,非常感谢你的评论。

最佳答案

很抱歉,这个部分很晚,但是如果你有C/C++,使用VS2013 Express(免费版本)将它移植到C代码非常简单,并且只需使用.NET工具集将它移植到LabVIEW中即可。

关于c - 通过二次拟合C峰检测,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26485295/

10-08 22:09
查看更多