2019年10月31日木曜日

カルマンフィルタ積むまでもない時のローパスフィルタ

最近HX711をつんだ重量計を買ってM5stackでつかっていたのですよ。
アマゾンとか売ってる安いやつね。Arduinoライブラリでは引数に(10)とか入れて10回積算値を入れてたりするのだけれども、それだと応答性が悪い。応答性は計り取り(製薬やお料理)に重要で、速度が求められる。ということで、普通はこの積算回数と応答性のトレードオフになるんだけど、少しだけ賢い方法を紹介。

具体的な処理は以下の通り

  float w=ここで重量だとかを入力;
  static float oldV=0;  //平均値となる出力を入れる変数
  const float minRate=0.01; //重さの変動がないときはIIR係数0.01にする
               (小さい程積算回数が増えたのと等価になる)
  const float maxRate=0.999;//重さの変動が大きい時はIIR係数を1未満で大きな数にする(あまり弄る必要はなし)
  const float  threshWeight=5; //この変動量ぐらいが「大きい」「小さい」の閾値
  //////////実質的な処理は以下2行/////////////
  float rate = minRate+  min( fabs(w-oldV)/threshWeight ,1.0f)*(maxRate-minRate);
  oldV=w*rate+oldV*(1-rate);


重量計だとかは雑に考えると角がかけた階段状に出力値が変化すると考えられる、
そんなときはカルマンフィルタが王道だけど、とりあえずやっつけで実装したいときは上の実装で十分な応答性と精度が得られる。

rateがカルマンゲインに相当してるんだけど、この解説サイトの説明で言えば「予測不確かさ」と「観測不確かさ」がこの系には存在して、そのうち「予測」不確かさの割合をrateに入れるのが良いとされています。

過去の平均値と現在の入力値の差が予測不確かさに比例すると考えると上のの(w-oldV)は予測不確かさに比例した何かです。本来予測不確かさに対してカルマンゲインは定数である観測不確かさaをつかって、rate=x/(a+x)のような形になるんですが、上ではy=ax+bの形に近似してる事になります。

ここで、真面目に観測誤差とは何かとか考えてもいいんだけど、ぶっちゃけ必要な精度にあわせてminRateを小さくしていって、あとは変動が「大きい」時に高速化するためにthreshWeightを調整すると考えて勘で調整しても十分気持ちよく動いてくれる。



0 件のコメント:

コメントを投稿