C语言 数据流平均值

yvfmudvl  于 2022-12-17  发布在  其他
关注(0)|答案(1)|浏览(147)

我有一个输入的模拟值流,需要在1000个样本的移动窗口内对它进行一些基本统计。我不希望每次添加样本时都遍历并汇总整个窗口(没有处理时间)。我写了下面的代码,它的工作,但当索引回滚到零,我显然需要做些什么,这样我就不会在数据中有一个很大的不连续性,但我不能为我的生活弄清楚我错过了什么。

void stats(double in, stat_s *out)
{
    static uint32_t index = 1;
    double sum = 0, sum1 = 0;
    double differential = 0;
    double newDSquared = 0;
    double newMean = 0;
    
    out->arr[index%wnd_sz] = in;//array index values cycle within window size

   if(index!=0) differential = (in - out->mean) / index;
    else {
        //Do something here since we rolled back to the head of the index
    }

   newMean = out->mean + differential;

   double dSquaredIncrement = (in - newMean) * (in - out->mean);
   if(dSquaredIncrement>0) newDSquared = out->dSquared + dSquaredIncrement;

   out->mean = newMean;
    out->dSquared = newDSquared;
    if(index!=0) out->variance = out->dSquared / index;
    
    out->std_dev = sqrt(out->variance);

    out->max = out->mean + out->std_dev;
    out->min = out->mean - out->std_dev;    

    //prevent overflow for long running sessions.
    if(index < 3*wnd_sz) index++;
    else {
        index = 0;
    }
}

运行时,数据如下所示:

您可以看到,当索引重置为0时,最后一个波形上有一个较大的跳跃。

k97glaaz

k97glaaz1#

好吧,我自己算出来了。@Nelfeal关于只需要当前计算所基于的值的数量的评论是我所遗漏的。下面是使其工作的两个函数:
首先是循环缓冲区:

double append(double in) {
    double poppedValue = 0;
    if (out.elements == wnd_sz) {
        poppedValue = out.arr[out.count];
    } else {
        out.elements++;
    }
        out.arr[out.count] = in;
        out.count = (out.count+1) % wnd_sz;
        return poppedValue;
}

其次是实际的统计工作。这需要分为三个状态:
1.缓冲区中无数据的启动
1.缓冲区有数据但未满
1.缓冲区已满

void stats(double in)
{
    //append element to circular buffer
    double poppedValue = append(in); //append process should return popped value or null if not full, also update out->count

    if (emptyBuffer) { //Buffer not full yet
        // initialize when the first value is added
        out.mean = in;
        out.dSquared = 0;
        emptyBuffer = false;
        out.std_dev = sqrt(out.dSquared/out.count);
        out.max = out.mean + out.std_dev;
        out.min = out.mean - out.std_dev; 
    } 
    
    if (!emptyBuffer && out.elements < wnd_sz) {
        // if the buffer is not full yet, use standard Welford method
        double meanIncrement = (in - out.mean) / out.count;
        double newMean = out.mean + meanIncrement;
        double dSquaredIncrement = (in - newMean);
        dSquaredIncrement *= (in - out.mean);
        double newDSquared = out.dSquared + dSquaredIncrement;
        out.mean = newMean;
        out.dSquared = newDSquared;
        out.std_dev = sqrt(out.dSquared/out.count);
        out.max = out.mean + out.std_dev;
        out.min = out.mean - out.std_dev; 
    } else {
        // once the buffer is full, adjust Welford Method for window size
        double meanIncrement = (in - poppedValue);
        meanIncrement /= 100.0;
        double newMean = out.mean + meanIncrement;
        double dSquaredIncrement = (in - poppedValue);
        dSquaredIncrement *= (in - newMean + poppedValue - out.mean);
        double newDSquared = out.dSquared + dSquaredIncrement;
        out.mean = newMean;
        out.dSquared = newDSquared;
        out.std_dev = sqrt(out.dSquared/wnd_sz);
        out.max = out.mean + out.std_dev;
        out.min = out.mean - out.std_dev; 
    }
}

相关问题