温度センサと移動平均のアルゴリズム

No Image

温度センサを使って温度を測りたいと思ってArduinoでMCP9700というセンサを使ってみました。
秋月で売っているMCP9700はLM35DZなんかよりも格安です。
ただ、±4℃(最大)という精度なので実際に使えるかどうか・・・

スポンサーリンク

温度は次の式で求めることができます。

温度 = (センサ出力電圧 - 0℃の時のセンサ出力電圧) / 温度係数

MCP9700の温度係数は10mV/℃で0℃の時のセンサ出力電圧は500mVとなっています。
ArduinoのanalogReadは0~5Vを0~1023で返すので、センサの出力電圧を求めるには、

センサの出力電圧 = ADCの値 * 5000 / 1024

とすることで温度を求めることができます。
またArduinoのARefピンに3.3Vを与えることで0~3.3Vを0~1023で返すので、より精度を上げることができます。

で、実際に読み取った値を計算式に当てはめて、1分間の温度の推移を見てみました。
100msごとに温度を測定してグラフにするとこんな感じ。
温度60秒計測
変動しすぎて、どこを見ればいいのかわかりません。

そこでエクセルで10個ずつの移動平均をとってみます。
温度60秒計測移動平均
赤が以前ので、青が移動平均したものです。
そのままの数値より安定しているものの、まだまだ変動しています。

スポンサーリンク

7セグとかの表示器に温度を表示するにはより平滑化した温度を表示するほうがいいと思いますので、プログラムで移動平均を実装します。
そこで私が一番最初に考えた移動平均のプログラムはこんな感じです(100個の移動平均)。

for (i = 99; i > 0; i--) {
  temp[i] = temp[i-1];
}
temp[0] = temp_receive();  // 温度を格納
for (i = 0; i < 100;i++) {
  sum += temp[i];
}
average = sum / 100;

Arduinoなのでプログラムは無限ループしています。
配列を1つずらして平均を取る、という誰でも思いつきそうなプログラムです。
しかし、これをArduinoで7セグなんかでダイナミック点灯しながら処理していると、処理が間に合わず表示されないのです。
移動平均して表示できたのは6個まででした。

そこで違うアルゴリズムでできないかと考えてできたのがこんなプログラムです。

if (cnt == 100) {
  cnt = 0;
}
temp[cnt] = temp_receive();
cnt++;
for (i = 0; i < 100;i++) {
  sum += temp[i];
}
average = sum / 100;

ずらすのではなくて、上書きしていくというプログラムです。
思いつかなくて友達に聞いてなるほどと思いました。
こんな感じのプログラムを使うことで400個まで移動平均をとることが可能になりました。

まだ1000個じゃ処理が間に合わないので、さらに高速なアルゴリズムが必要なのですが、もうサンプル数は十分かな・・・
でも、もっと高速にする方法があったらそれはそれでいいかなと思います。

温度センサと移動平均のアルゴリズム

スポンサーリンク

Leave a Comment

  • 2013/06/21

    こんにちは,ニキシー管をArduinoで操作する記事を探していてたどり着きました.

    移動平均をとることについてですが,
    init()にて
    init(){
    int t = temp_receive();

    for(int i=0;i<100;i++)
    temp[i] = t;

    }
    などと,初期化し,loop()は
    if(cnt == 100)
    cnt = 0;

    sum -= temp[cnt];
    temp[cnt] = temp_receive();
    sum += temp[cnt];
    cnt++;

    average = sum / 100;

    としてやれば大分高速化できる気がします.
    あとは,カルマンフィルタなんかを使って平滑化するのも有効かもしれません.

    横槍失礼しました.

    Reply
  • 2016/02/23

    上の方が書いているように
    積算値から一番古い値を引いて新しい値を足していく方式が
    計算量が少なくて済みます。

    ただし、浮動小数点数では誤差が累積していくためお勧めできません。

    Reply