计算可变参数的移动平均值

时间:2011-12-09 15:39:30

标签: objective-c ios average moving-average

我有一个整数属性,每秒更新一次,信号强度值范围为0 - 100。

我希望能够在过去的10次,25次,50次测量中持续测量移动平均值。

最有效的方法是什么?

我正在考虑使用NSMutableArray实现一组FIFO队列,并在每次在阵列具有必需数量的条目时在末尾添加新值时弹出前导值。但是,我不确定是否有更有效的方法。

3 个答案:

答案 0 :(得分:6)

我写了一个名为MovingAverage的简单类来处理这个问题。您使用要维护的周期数启动方法,并使用样本计数的模数跟踪其余部分,以了解要将其放入哪个静态插槽。

使用

初始化
MovingAverage *avg5periods = [[MovingAverage alloc] initWithSize:5];

添加项目:

[avg5periods addSample:1.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //1.0
[avg5periods addSample:2.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //1.5
[avg5periods addSample:3.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //2.0
[avg5periods addSample:4.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //2.5
[avg5periods addSample:5.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //3.0
[avg5periods addSample:6.0];
NSLog(@"1.2f",[avg5periods movingAverage]); //4.0

标题文件:

#import <Foundation/Foundation.h>

@interface MovingAverage : NSObject {
    NSMutableArray *samples;
    int sampleCount;
    int averageSize;
}
-(id)initWithSize:(int)size;
-(void)addSample:(double)sample;
-(double)movingAverage;
@end

和实施文件:

#import "MovingAverage.h"

@implementation MovingAverage
-(id)initWithSize:(int)size {
    if (self = [super init]) {
        samples = [[NSMutableArray alloc] initWithCapacity:size];
        sampleCount = 0;
        averageSize = size;
    }
    return self;
}
-(void)addSample:(double)sample {
    int pos = fmodf(sampleCount++, (float)averageSize);
    [samples setObject:[NSNumber numberWithDouble:sample] atIndexedSubscript:pos];
}
-(double)movingAverage {
    return [[samples valueForKeyPath:@"@sum.doubleValue"] doubleValue]/(sampleCount > averageSize-1?averageSize:sampleCount);
}
@end

答案 1 :(得分:4)

队列是正确的方法。真正的效率来自你如何重新计算平均值。

应该用:

完成
avg = avg + newSample/N - [queue dequeue]/N
[queue enqueue:newSample]

即。新的运行平均值只是旧的平均值减去您丢弃的最旧值的权重,加上您排队的最新值的权重。

答案 2 :(得分:1)

我认为你有正确的解决方案。

如果您真的关心性能,而不是将内容移入和移出动态调整大小的数组,您可以使用静态大小的数组并跟踪当前索引。

即。如果N是数组的大小,%是模运算符(我不是一个客观的C程序员):

values[current] = get_current_sample()
previous = (current + N - 1) % N
sum = sum + values[current] - values[previous]
current = (current + 1) % N

平均值=总和/ N.您必须单独处理预热期(在您有N个样本之前)。

这可能会更快,具体取决于NSMutableArray如何处理内存分配。