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
1PPS信号は、mbed p15ピンに接続しました。
PPS(pulse per second)とは?
「(ほぼ)正確な秒周期」を表します。1PPSは、(ほぼ)正確な1秒周期のパルスを出力するもので、GPSモジュールにはこの出力信号がついているものがあります(ついていないものもあります)。
GPS時刻はナノ秒レベルで正確ですが、GPS時刻をNTPサーバとして使うには、時刻情報(何時何分何秒)と、それを同期するための信号(PPS)の二つが必要です。
GM-316 の資料を信じれば、GM-316は1マイクロ未満の1秒周期パルスを出しているはずです。
Timer の精度を測ってみる
二通りの方法で試してみました。
- InterruptIn を使い、p15 の立ち上がりで割り込みをかけて、Timer の差分を計算する。
- main() で while() でポーリングして、p15 の立ち上がりを見つけて Timer の差分を計算する。
考え方は、両方とも、1秒((1,000,000マイクロ秒)パルスの立ち上がりを掴まえて、Timer を読んだ時の値を調べると言う考え方です。
結果
- InterruptIn を使う方法→約3マイクロ~4マイクロの誤差がありました。
- main() で while() でポーリングする方法→これも約3マイクロ~4マイクロの誤差がありました。
テストコード
#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
You need to log in to post a comment