web-dev-qa-db-ja.com

時間の経過に伴う値の平滑化:移動平均か、それともより良いものか?

私は、ハードウェアコンパスから時間の経過とともに多くの値を取得する瞬間に何かをコーディングしています。このコンパスは非常に正確で、非常に頻繁に更新されるため、わずかに揺れると、隣人とはかなり矛盾した奇妙な値になります。これらの値を滑らかにしたいです。

少し読んでみると、私が欲しいのはハイパスフィルター、ローパスフィルター、または移動平均だと思われます。移動平均を取得するには、最後の5つの値などの履歴を保持し、最新の値を使用していたコードの下流でそれらの値の平均を使用します。

それは、これらの揺れをうまく滑らかにするはずですが、おそらく非常に非効率的であり、これはおそらく適切なプログラマーにとって既知の問題の1つであり、本当にきちんとした数学ソリューションがあります。

しかし、私は、CompSciやMathに漠然と関連しているものでさえも、正式な教育を受けていない、ひどい独学のプログラマの1人です。少し読んでみると、これはハイパスまたはローパスフィルターかもしれないが、これらのアルゴリズムの効果が値の配列にどのように影響するか、私のようなハックに理解できる用語で説明するものは見つけられない数学は機能します。たとえば、 here の答えは技術的に私の質問に答えますが、おそらく問題を解決する方法をすでに知っている人にわかりやすい用語でのみです。

芸術の卒業生が理解できる用語で、これがどんな種類の問題であり、解決策がどのように機能するかを説明できるのは、実にとても素敵で賢い人でしょう。

46
Henry Cooke

必要な平滑化を実現するために移動平均を長くする必要があり、カーネルの特定の形状が実際に必要ない場合、指数関数的に減衰する移動平均を使用する方が良いでしょう。

a(i+1) = tiny*data(i+1) + (1.0-tiny)*a(i)

tinyを適切な定数として選択します(たとえば、tiny = 1- 1/Nを選択した場合、サイズNのウィンドウと同じ量の平均化が行われますが、古いポイントで異なる分布になります)。

とにかく、移動平均の次の値は前の値とデータにのみ依存するため、キューなどを保持する必要はありません。これは、「新しいポイントがありますが、私はそれを本当に信用していないので、測定の以前の推定値の80%を保持し、この新しいデータポイントを20%信頼します。これは、「この新しいポイントを20%だけ信頼し、同じ量を信頼する他の4つのポイントを使用します」と言うのとほとんど同じです。ただし、他の4つのポイントを明示的に取得する代わりに、前回行った平均化は賢明であり、以前の作業を使用できると想定しています。

38
Rex Kerr

偶発的な奇数値を削除しようとしている場合、特定した3つのオプションのうち、ローパスフィルターが最適です。ローパスフィルターを使用すると、コンパスを手で回転させるなどの低速の変更が可能になり、道路の凹凸などによる高速の変更は拒否されます。

移動平均ウィンドウのサイズに応じて、データ内の単一の「ブリップ」の影響がその後のいくつかの値に影響するため、移動平均ではおそらく十分ではありません。

奇数値が簡単に検出される場合は、それらを完全に無視するグリッチ除去アルゴリズムを使用することをお勧めします。

if (abs(thisValue - averageOfLast10Values) > someThreshold)
{
    thisValue = averageOfLast10Values;
}

以下に、グラフを示します:

graph comparison

最初のグラフは入力信号で、不快なグリッチが1つあります。 2番目のグラフは、10サンプルの移動平均の効果を示しています。最終的なグラフは、10サンプルの平均と上記の単純なグリッチ検出アルゴリズムの組み合わせです。グリッチが検出されると、実際の値の代わりに10サンプルの平均が使用されます。

58
e.James

移動平均でうまくいくことができます...しかし、それはおそらく非常に非効率的だと思います。

移動平均が非効率的である理由はまったくありません。必要なデータポイントの数をいくつかのバッファー(循環キューなど)に保持します。新しいデータポイントごとに、最も古い値をポップして合計から減算し、最新の値をプッシュして合計に追加します。したがって、新しいデータポイントはすべて、実際にはポップ/プッシュ、加算、減算のみを必要とします。移動平均は常に、このシフト合計をバッファー内の値の数で割ったものです。

複数のスレッドから同時にデータを受信して​​いる場合はlittleのトリッキーになりますが、データはハードウェアデバイスからのものであるため、非常に疑わしいと思われます。

また、ひどい独学のプログラマーが団結します! ;)

6
Dan Tao

適切に値を使用すると、トレンドのみを使用して指数関数的に減衰する移動平均を「手動で」計算できます。 「 http://www.fourmilab.ch/hackdiet/e4/ 」を参照してください。「10%平滑化による指数平滑化移動平均」。しかし、あなたはコンピューターを持っているので、おそらく10進シフトではなく2進シフトを行いたいと思うでしょう;)

この方法で必要なのは、現在の値の変数と平均の変数だけです。次の平均は、それから計算できます。

2
Daren Thomas

低発生スプリアスサンプルでうまく機能するレンジゲートと呼ばれる手法があります。上記のフィルター手法(移動平均、指数)のいずれかを使用すると仮定すると、「十分な」履歴(1つの時定数)が得られたら、新しい着信データサンプルの妥当性をテストできますbefore計算に追加されます。

信号の最大合理的な変化率の知識が必要です。生のサンプルは最新の平滑化された値と比較され、その差の絶対値が許容範囲よりも大きい場合、そのサンプルは破棄されます(または、勾配に基づく予測、微分、または二重指数平滑法による「トレンド」予測値)

1
tom jennings