彷徨えるフジワラ

年がら年中さまよってます

周回所要時間予想

引き続き光残像キットの往復所要時間の予測を試行錯誤する日々。

とりあえず、以下の様なスケッチを Japanino に upload した上で、IDE のシリアルモニタ機能を使用して、Japanino から送られて来た回転検出時刻(ミリ秒)を監視。

#include <WProgram.h>

#define JAPANINO_PIN_SWITCH 6

void
setup()
{
    pinMode(JAPANINO_PIN_SWITCH, INPUT);
    digitalWrite(JAPANINO_PIN_SWITCH, HIGH);
    Serial.begin(9600);
}

unsigned long last_time = 0;
unsigned int bounce_ = 50;

void
loop()
{
    if(digitalRead(JAPANINO_PIN_SWITCH) != LOW){ return; }

    unsigned long cur_time = millis();

    if(bounce_ <= (cur_time - last_time)){
        char buf[40];
        sprintf(buf, "%08lx\n", cur_time);
        Serial.write(buf);
    }

    last_time = cur_time;
}

入手した時刻情報を元に、PC 側で予測式の評価を試みる。
とりあえず、周回所要時間(Lap time)値として、今回の周回所要時間(Lcur)と、前回の周回所要時間(Lprev)を元に、次回周回所要時間(Lnext)を導出するための以下の様な式を立ててみた。

Lnext = Lcur + (Lcur - Lprev)

"Lcur - Lprev" は1周毎の周回所要時間の増加度合いなので、厳密に言うなら加度ではなく加度なんだけど、面倒なので加速度と言うことに(笑)。表記は "Acur" で。

で、この算出式だと、色々なパターンで机上検討した段階で加速度の影響が強過ぎることがわかったので、加速度の影響をマイルドにするために、以下の様に微調整。

Lnext = Lcur + (Acur / 2)

安直だ!(笑) > 1/2

周回所要時間が一定加速度で増加/減少し続けることは稀=現状相対で安定回転する方向で振舞う、という方針。

更なる変化量という意味では「加速度の増減を考慮する」という事も考えられたけど、やっぱりこれも加速度の影響がキツくなってしまうため、そこまで頑張る必要は無さそう。

実測値を元に、この式で周回所要時間を予想してみると、平均 23.3 msec 程度の誤差の範囲で予測できる感じだけど、これって精度的にはどうなんだろ?

試しに「なんでも作っちゃう、かも。」で公開されている予想方式と比較してみることに。

前回の「予想(forecast)周回所要時間」= Lnext を Fprev で表記した場合、「なんでも作っちゃう、かも。」方式は以下の様な感じ。

Lnext = (Lcur >> 1) + (Lcur >> 2) + (Fprev >> 2)

値としては「前回の予想周回所要時間」と同一ではあるけれど、元ソース中の名前(ave_time)等から見える意図としては、「平均周回所要時間の近似算出」的なニュアンスじゃなかろうか? > Fprev

算出方法では(性能確保のため)ビットシフトを使用しているけど、要するに「今回の周回所要時間 * 3/4」+「平均周回所要時間 * 1/4」ということで、「安定回転する(= 平均に近づく)方向で振舞う」という仮定自体は、こちらも共通しているものと思われる。

で、同じ実測値を元に、こちらの式で周回所要時間を予想してみると、平均誤差 19.3 msec !すげー!

予想状況を細かく見ていくと、周回所要時間の増減が大きいケースだと加速度(Acur)要素を加味している分、こちらの方式の方が誤差が少ないのだけど、全般的に見ていくと、回転が変動しても周回所要時間が一定範囲に収まる、という光残像キットのデバイス特性によって、平均値(の近似値)を加味している「なんでも作っちゃう、かも。」方式の方が優れている、という状況の模様。

試しに直近 8 回分の周回所要時間を元に算出した平均値(Lavg)を加味した以下の式で予想を実施。

Lnext = (Lcur >> 1)  + (Lcur >> 2) + (Lavg  >> 2) + (Acur >> 2)

お! 19.8 msec とほぼ同等の精度だ!

でも、Lavg の算出は計算量が多いから、あまり嬉しくないなぁ。平均値算出用のデータを直近 4 回分に限定したら、精度が落ちるみたいだし....

試しに Lavg 算出を「なんでも作っちゃう、かも。」方式の Fprev で代替してみることに。

Lnext = (Lcur >> 1)  + (Lcur >> 2) + (Fprev  >> 2) + (Acur >> 2)

お!平均誤差 18.0 msec だ!これはいけるかも!?

上記の精度に関しては、算出に使用する元実測値によって結構変動するので、他のデバイスに応用するような場合は、デバイスの特性に応じて色々微調整する必要がありそう。

予想算出式の組み立て/解釈も我流なので、あんまり上記の結果を鵜呑みにしないでね。

ちなみに式要素のそれぞれは、@IT の制御入門記事で言うところの:

  • "(Lcur >> 1) + (Lcur >> 2)" → 比例制御
  • "(Fprev >> 2)" → 積分制御
  • "(Acur >> 2)" → 微分制御

に相当する、という理解でよいのかな?有識者ノ見解求ム。

追伸:

周回あたり 18.0 msec の誤差だとしても、普通に回した際の周回所要時間が 120msec 〜 150msec 前後であることを考えると、POV の解像度から言えば 5 〜 10 ライン程度に相当するので、全然精度が出てないことに気付く。っていうか、もっと早く気付けよ! > 自分