首页 > 解决方案 > 优化频繁平均计算

问题描述

我正在计算浮点数的平均值。更具体地说,以弧度为单位的方位角值。这些浮点数位于最大大小为 40 的数组中。

每次从传感器收到新的方位角值时,我都会将新值添加到历史数组并计算平均值。我的目标是计算平均值,而不必每 5 毫秒对所有 40 个元素求和。有没有办法做到这一点?谢谢

我当前的代码:


public void addAzimuthToHist(float azimuth){
        if (azimuthHist.size() >= 40) {
           // If history exceeds 40, then remove first item in queue.
            azimuthLastPoll = azimuthHist.poll();
        } else {
            azimuthLastPoll = 0;
        }

        lastAddedToAzimuthHist = azimuth;
        azimuthHist.offer(azimuth); // Add new azimuth value to history
    }

/**
     * Get average of azimuth history
     */
    private float averageAzimuthHist(){
        if (azimuthHist.size() < 40) {
            Iterator<Float> iterator = azimuthHist.iterator();
            float sum = 0;
            while(iterator.hasNext()){
                float aziumth = iterator.next();
                sum += aziumth;
            }
            lastAvg = sum / azimuthHist.size();
        } else {
            lastAvg = (lastAvg - azimuthLastPoll + lastAddedToAzimuthHist) / azimuthHist.size();
        }

        return lastAvg;
    }
// Callback when the senosors emit a new Value(each 5 milliseconds)
gravityMag.setOnAzimuthChange(azimuth -> {
            addAzimuthToHist(azimuth);
            float currentAverage = averageAzimuthHist();

            double deg = Math.toDegrees(currentAverage);
            getReactApplicationContext()
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit("HeadingUpdated", (int) Math.round((deg + 360) % 360));

        });

通过下面的代码片段,我试图“增加”平均值,但结果是错误的。

lastAvg = (lastAvg - azimuthLastPoll + lastAddedToAzimuthHist) / azimuthHist.size();

标签: javamath

解决方案


我会将新值的添加移动到您的addAzimuthToHist方法中,并在从数组中删除时减去旧值。这可以帮助您摆脱循环averageAzimuthHist并额外简化平均值的计算。未经测试的示例只是为了让您了解我想说的内容:

假设您已定义字段

float sum = 0f;
Queue<Float> azimuthHist = ...

然后

public void addAzimuthToHist(float azimuth){
    sum += azimuth;
    azimuthHist.offer(azimuth);  //azimuthHist.add(azimuth);
    if (azimuthHist.size() > 40) {
        sum -= azimuthHist.poll();
    }
}

private float averageAzimuthHist(){
    if (azimuthHist.isEmpty()) return 0f;
    int divisor = azimuthHist.size();
    return  sum /divisor;
}

推荐阅读