一部のセンサーデータを平滑化するプログラムを作成しようとしています。
センサーは 0 ~ 100 のしきい値入力を提供します。通常は 2 単位程度の精度ですが、読み取りごとに不安定です。
1 秒間に何度も入力を取得し、このデータからそれほど急激ではない動的平均を作成したいと考えています。
最近の入力を平均化して、滑らかに変化する数値、より正確な数値 (測定値にリアルタイムで対応する) をインターフェイスに表示するにはどうすればよいでしょうか?
助けてくれてありがとう。
データに応じて、平均を計算して測定値を平準化できます。
一定数の以前の結果を使用する
int values[BUFLEN];
value = // your new raw measured value
index = index++ % BUFLEN;
values[index] = value;
avg = 0;
for(int i=0; i<BUFLEN; i++) {
avg = avg + values[i] / BUFLEN; // evenly weighted
}
必要に応じて、不均一なウェイトを使用することもできます。また、同じ重みを使用している場合は、このループを最適化できます。
変動平均の使用
avg = (avg * 0.9) + (value * 0.1) // slow response
avg = (avg * 0.5) + (value * 0.5) // fast response
float q = // new ratio
avg = (avg * (1.0 - q)) + (value * q) // general solution
浮動平均 (数学的に) は、すべての要素の重み付き合計です。ここで、重みは q N-iです。ここN
で、 は測定値の合計i
で、 は要素の連続インデックスです。限られた数の要素だけでなく、すべての要素が平均に含まれます。
誤った測定の頻度、平均からの距離、(計算された) 測定が実際のプロセスに従うためにどのような反応を期待するかなどを確認できます。
また、離散値 (整数) がある場合は、丸めの使用に注意する必要があります。すべての計算を浮動小数点で行い、結果を最も近い整数に丸めることをお勧めします。ただし、次のラウンドのために、計算された平均を浮動小数点に格納します。
アップデート:
最新かつ正確であることについての質問を反映するには、次のようにします。
問題は、最新のデータが傾向を示しているのか、それとも読み間違いの結果なのか、わからないことです。例を示します。
SEQ1: 15 15 14 15 15 [10] 6 6 5 6 6
SEQ2: 15 15 14 15 15 [10] 20 15 14 15 15
では、[10]
各シーケンスの意味は次のとおりです。最初のシーケンスでは、深刻な動き、トレンドを表しています。2番目のものでは、それは単なる読み違いです。しかし、あなたが読んだばかりのとき[10]
、あなたは次に何が起こるか分かりません. したがって、その読み取りの効果を遅らせる必要があります。そのため、最新ではありません。
同様に、計算値である平均値を使用しています。したがって、正確ではありません。
バランスのとれた状況です。値が最新であるほど、精度が低くなります (読み間違いが発生しやすくなります)。データが正確であるほど、遅延は大きくなります。データ系列に基づいて、賢明に選択する必要があります。
2 番目の (変動平均) アルゴリズムを使用して、3 つのシナリオを計算しました。の値は、 lazy、normal、またはeagerq
に設定されています。
SEQ1: 15 15 14 15 15 10 6 6 5 6 6
// q=0.25, "lazy"
Avg 15.00 15.00 14.75 14.81 14.86 13.64 11.73 10.30 8.98 8.23 7.67
Rounded 15 15 15 15 15 14 12 10 9 8 7
// q=0.5, "normal"
Avg 15.00 15.00 14.50 14.75 14.88 12.44 9.22 7.61 6.30 6.15 6.08
Rounded 15 15 15 15 15 12 9 7 6 6 6
// q=0.75, "eager"
Avg 15.00 15.00 14.25 14.81 14.95 11.23 7.31 6.33 5.33 5.83 5.96
Rounded 15 15 14 15 15 11 7 6 5 5 6
遅延6
計算は5 回の繰り返し後もまだ到達していないことがわかります。おそらくあと 3 回必要です。
法線はほとんどエラーを起こしにくいものではありませんでしたが (14.5 は端数を切り上げただけです)、すぐに傾向を追うことができました。
熱心な人は熱心に対策をたどり、曲線にわずかな緩和を追加しました. 15-14-15 の誤読も検出できませんでした。
上記のシリーズの最高の価値は約でしょう0.4
-0.45
私は思います. 実際の測定データのサンプルを試して、どのパラメーター値の動作がどのようなものかを確認することは価値があります。
実際、私のお気に入りは浮動平均アルゴリズムです。実装が簡単で、適切にパラメータ化されていれば、良い結果が得られます。
免責事項:これにより、非常にスムーズな結果が得られます。この間に値が大幅に上下しても、直線が表示されるだけです。これは、時間の経過に伴う平均の変化を示します。これが望ましくない場合、この回答はおそらくあなたが望んでいるものではありません。
k
最後の入力値を平均するとしましょう。
最初に注意すべきことは次のとおりです。
Average at time i = (value[i] + value[i-1] + ... + value[i-k+1]) / k
= value[i]/k + value[i-1]/k + ... + value[i-k+1]/k
and
Average at time i-1 = value[i-1]/k + value[i-2]/k + ... + value[i-k+2]/k
thus, cancelling out common terms...
Average at time i = Average at time i-1 + value[i]/k - value[i-k+2]/k
そして、潜在的な丸めの問題を回避するためにk
、これによる除算を行わないようにしてください - 平均が得られたときにそれを行ってください (これを行っても数学が無効になることはありません)。
それでは、アルゴリズムに進みます。
k
。この配列のすべての値を 0 に初期化します。average = newValue - overriddenValue
k
。