Accuracy of timer

自作GPSロガーを作っていますが、☆board Orange スタック基板に取り付けたGPSモジュール(GM-316)は、1PPS信号が出ているので、それと mbed の Timer の精度を比べてみることにしました。

GPSモジュール(GM-316)のURLとドキュメントです。Time accuracy は 1μs or less とあります。

http://www.aitendo.co.jp/product/1321

http://aitendo2.sakura.ne.jp/aitendo_data/product_img2/product_img/aitendo-kit/gps/gm316/GM-316_DS-080704.pdf

1PPS信号は、mbed p15ピンに接続しました。

PPS(pulse per second)とは?

「(ほぼ)正確な秒周期」を表します。1PPSは、(ほぼ)正確な1秒周期のパルスを出力するもので、GPSモジュールにはこの出力信号がついているものがあります(ついていないものもあります)。

GPS時刻はナノ秒レベルで正確ですが、GPS時刻をNTPサーバとして使うには、時刻情報(何時何分何秒)と、それを同期するための信号(PPS)の二つが必要です。

GM-316 の資料を信じれば、GM-316は1マイクロ未満の1秒周期パルスを出しているはずです。

Timer の精度を測ってみる

二通りの方法で試してみました。

  1. InterruptIn を使い、p15 の立ち上がりで割り込みをかけて、Timer の差分を計算する。
  2. main() で while() でポーリングして、p15 の立ち上がりを見つけて Timer の差分を計算する。

考え方は、両方とも、1秒((1,000,000マイクロ秒)パルスの立ち上がりを掴まえて、Timer を読んだ時の値を調べると言う考え方です。

結果

  1. InterruptIn を使う方法→約3マイクロ~4マイクロの誤差がありました。
  2. main() で while() でポーリングする方法→これも約3マイクロ~4マイクロの誤差がありました。

テストコード

ソースは一つで、条件コンパイルで InterruptIn を使うかポーリングするかを切り分けています。
#include "mbed.h"

Serial debug(USBTX,USBRX);

#if 1
InterruptIn PPS(p15);
Timer tim;
int tim_val[5];
int tim_r = 0;
int tim_w = 0;
int tim_pre = 0;

void pps_rise()
{
    int tim_now = tim.read_us();
    tim_val[tim_r] = tim_now - tim_pre;
    tim_r = (tim_r + 1) & 0x03;
    tim_pre = tim_now;
}

int main(void) {
    debug.format(8,Serial::None,1);
    debug.baud(115200);
    printf("*** GPS 1PPS Test (Interrupt) ***\n");
    tim.start();
    PPS.rise(pps_rise);
    while(1){
        if(tim_r != tim_w){
            debug.printf("%d\n",tim_val[tim_w]);
            tim_w = (tim_w + 1) & 0x03;
        }
    }
}
#else
DigitalIn PPS(p15);
Timer tim;
int main(void) {
    int pre = 0;
    int tim_pre = 0;
    int tim_now = 0;
    debug.format(8,Serial::None,1);
    debug.baud(115200);
    printf("*** GPS 1PPS Test (polling) ***\n");
    tim.start();
    while(1){
        int now = PPS.read();
        if((pre == 0) && (now != 0)){
            tim_now = tim.read_us();
            debug.printf("%d\n",tim_now - tim_pre);
            tim_pre = tim_now;
        }
        pre = now;
    }
}
#endif

テストプログラムの出力結果(抜粋)

*** GPS 1PPS Test (Interrupt) ***
250647
1000003
1000004
1000004
1000004
1000004
1000004
1000004
1000003
1000004
1000004
... 

 

*** GPS 1PPS Test (polling) ***
5057
1000004
1000004
1000004
1000004
1000004
1000004
1000004
1000004
1000003
1000004
1000004
1000004
...

細かく平均は取っていませんが、1秒(1,000,000マイクロ秒)の周期に対し、3マイクロ~4マイクロの差が出ています。

 

考察

気になるのは、InterruptIn の方法でも、ポーリングの方法でも、結果に殆ど差が見受けられないと言う事です。

InterruptIn を使うと、割り込みハンドラとしての処理があるので、ポーリングの方が若干でも誤差が縮まるかと思いましたが、あまり差は感じられません。

Timer クラスの read_us() 自身が、もしかすると遅いのかもしれません。もちろん、GPS モジュール側の誤差も考えられます。

また時間を見つけて、調べてみたいと考えています。

一番良いのは、校正済みのオシロを使って測定することかと思います(汗。もし、測定された方がいましたら、教えて頂けたら嬉しいです。

追記

mbed が使用しているクロックオシレータは,下記の URL にある回路図を見ると,
ASE-12-D-C-T と言うクロックオシレータを使っています.
http://mbed.org/media/uploads/chris/mbed-005.1.pdf

ASE-12-D-C-T は,下記から仕様が分かります.
http://www.abracon.com/Oscillators/ASEseries.pdf

  • 12MHz
  • -10度~+60度
  • +/- 50ppm

12MHz のクロックで 50ppm の精度です.これは,クロック数(12MHz)に関係なく,1秒に対して 50ppm の精度であると言う事から,50マイクロ秒(0.000050秒)の誤差を含む場合があると言う事です.
実際の測定では,概ね3マイクロ~4マイクロなので,今回の測定(2010年10月6日)では,良い成績だったと言えます.
温度が変われば,誤差はもっと変わるかもしれません.

なお,正確な時間が必要なために高精度なクロックオシレータを入れない限り,通常のクロックオシレータは,調べると大体 25ppm ~ 100ppm の精度です.
したがって,mbed のクロックオシレータが低い訳ではありません.通常利用の範囲内と考えています.



1 comment

20 Jul 2011
InterruptIn で使用する入力ピンを p9(P0.0)に変更したら、どうでしょうか。

You need to log in to post a comment