我有每秒更新一次與信號強度值範圍爲0-5的整數屬性 - 100運動平均
我想能夠保持的一個正在進行的測量在過去的10,25,50次測量中移動均線。
這樣做的最有效方法是什麼?
我目前正在考慮使用NSMutableArray實現一組FIFO隊列,並且每當我在結尾添加一個新隊列時彈出主鍵值,一旦陣列具有必需的條目數量。但是,我不確定是否有更有效的方法來做到這一點。
我有每秒更新一次與信號強度值範圍爲0-5的整數屬性 - 100運動平均
我想能夠保持的一個正在進行的測量在過去的10,25,50次測量中移動均線。
這樣做的最有效方法是什麼?
我目前正在考慮使用NSMutableArray實現一組FIFO隊列,並且每當我在結尾添加一個新隊列時彈出主鍵值,一旦陣列具有必需的條目數量。但是,我不確定是否有更有效的方法來做到這一點。
隊列是正確的。真正的效率來自您如何重新計算平均值。
它應該做到:
avg = avg + newSample/N - [queue dequeue]/N
[queue enqueue:newSample]
即新的運行平均簡直是舊平均減去你放棄了最早的值的權重,再加上你排隊的最新值的權重。
我認爲你有正確的解決方案。
如果你真的關心性能,而不是移動和移出動態調整大小的數組,你可以使用一個靜態大小的數組並且跟蹤當前的索引。
I.e.如果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如何處理內存分配,這可能會更快。
我寫了一個名爲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
和小鬼lementation file:
#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
嗨!我剛剛嘗試過你的解決方案。這隻有在樣本大小等於5的情況下才能正常工作。設置值大於此值(如10,20左右)會導致值減小。例如:我每次都添加一個const == 10。只有當樣本大小等於5時,移動平均值纔會返回10.10爲5,20 - 2.5。那是對的嗎? –
我剛剛編輯了答案: int pos = fmodf(sampleCount ++,5.0); 至 int pos = fmodf(sampleCount ++,(float)averageSize); 基本上,fmodf應該根據移動平均中的樣本數進行修改。讓senese? – earnshavian
這非常合理!謝謝。 –
''[queue dequeue]'是什麼意思? – progrmr
@progrmr:我的Objective-C語法很生疏。我打算將「出列」消息發送給對象「隊列」。即我假設他以某種方式實現了一個隊列,或者使用現有的一個隊列類(如果有的話)。 – ArjunShankar