GPSのPPS信号を使うと非常に高精度なNTPサーバが作れるそうなので、実際にRaspberry Pi 2を使ってやってみました。GPSモジュールは測位計算をする時に非常に正確な時刻を得ることができます。これを利用してGPSモジュールの中にはPPS信号を出力するものがあります。PPSはPulse Per Secondの略で、正確に1秒間隔で出力されるパルス信号のことです。
詳細な手順は後回しにして、まずはどれくらい正確な時刻が得られたのかをお見せします。Internet上のNTPサーバを使うと数ms程度の精度だったのがRaspberry Piに接続したGPSのPPSを使うと数μs程度の精度が得られました。
以下のグラフはRaspberry Pi と TS-109(NAS)のそれぞれでNTPサーバを動かし、上位のNTPサーバとの時刻オフセットをMRTGを使って表したグラフです。MRTGがマイナスの値を扱えないので、5ms のオフセットをかけてあります。つまり、中央の5msのラインより上がプラスのオフセット、下がマイナスのオフセットです。
まず、NTPサーバとして、ntp.nict.jp を指定した時の時刻オフセットです(TS-109はサーバとしてntp.nict.jpとRaspberry Piと両方を指定していました)。だいたい数ms程度のオフセットに収まっていることがわかります。
ネット上のNTPサーバを使っても百分の一秒程度の精度が得られるのですが、PPSを使うとさらに高精度な時刻同期をすることができます。
以下のグラフはNTPの参照クロックとしてNICTのサーバからPPSへと変更したときの時刻オフセットです。
22時30分頃にNTPサーバを入れ替えたり、ntp.conf を書き換えたりの作業をしたせいでオフセットが突出している箇所がありますが、それより右の平らな部分ではPPSを使った時刻同期に変わっています。
これはPPS使用時の時刻オフセットを別のスケールで測定したグラフです。
Raspberry Piの方は 20μsのオフセット、TSー109の方は500μsのオフセットをかけてあります。Raspberry Piは直接PPSを使用しているので数μsのオフセット値が得られています。TS-109の方はRaspberry Pi を上位サーバとして参照していますが、こちらは100μs程度の精度です。
GPSモジュールのPPS信号を使うと、ほぼ数μs程度の精度で時刻同期をすることができました。
以下が詳細な手順です。
概要
・使用したGPSモジュールは、Adafruit Ultimate GPS Breakoutというものです。これにGPS外部アンテナ を接続して使っています。以下のページを見て設定します。
https://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi
・GPSモジュールのシリアル出力はUARTに入力しています。Raspberry Piでは/dev/ttyAMA0からデータを取り込みます。シリアルコンソールを無効にしてUARTを有効にする設定が必要です。
・GPSモジュールのPPS信号はRaspberry PiのGPIO 18につなげています。
・以下のページを参考にしました。(書いてあることをほぼなぞるだけでできてしまいました)
http://www.satsignal.eu/ntp/Raspberry-Pi-NTP.html
GPS無しでNTPサーバを動かす
まず、GPS無しでNTPサーバを動かしてみます。ntp.conf を編集します。
$ sudo nano /etc/ntp.conf
次の1行を加えるだけです。
server ntp.nict.jp iburst
NTPサーバを再起動します。
$ sudo /etc/init.d/ntp restart
NTPサーバの動作をチェックします。
$ ntpq -p
remote refid st t when poll reach delay offset jitter
============================================
*ntp-a2.nict.go. .NICT. 1 u 17 64 377 6.547 0.940 0.894
こんなような出力がでればOK.
この状態で1日動かしてMRTGでデータをとりました。
PPS無しのGPSを使ってNTPサーバを動かす
次に、PPSは使わずにGPSを接続してNTPサーバを動かします。GPSモジュールは通常、NMEA0183というフォーマットで時刻や位置などの測位結果をテキストのメッセージとして出力しています。これを使ってNTPの同期をとることができます。
PPSは1秒おきのパルスに過ぎないのでPPSだけでは時刻はわかりません。GPS+PPS(またはインターネットのNTPサーバ+PPS)という組合せによって、GPSで秒単位の時刻を取得し、それとの差分をPPSのパルスで知ることによって正確な時刻同期を行うことができます。
まず、GPS関連のツールをインストールします。
$ sudo apt-get install gpsd gpsd-clients python-gps
上述のように、私はGPSの出力をUARTに入力しているので、Raspberry PiではGPSの入力が /dev/ttyAMA0 になります。
gpsd を以下のように起動します。
$ sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock
GPSが動いているか確認します。
$ cgps -s
GPSの動作確認は gpsmon でもOK。
ntp.conf の編集をします。
$ sudo nano /etc/ntp.conf
以下の2行を追加します。
server 127.127.28.0 minpoll 4 maxpoll 4
fudge 127.127.28.0 refid GPS stratum 15
NTPを再起動して、確認します。
$ sudo /etc/init.d/ntp restart
$ ntpq -p
remote refid st t when poll reach delay offset jitter
=============================================
SHM(0) .GPS. 15 l 4 16 377 0.000 330.130 354.492
*ntp-a2.nict.go. .NICT. 1 u 58 64 377 6.504 0.867 0.404
こんなような出力ならOK.
SHMはShared Memoryの略です。127.127.28.0 というのはNTPの参照クロックとしてPPSを使用するという意味です。他にどのような参照クロックがあるのかは以下のページでわかります。ちなみに後でPPSを使う時にType22を追加します。
http://www.eecis.udel.edu/~mills/ntp/html/refclock.html
ついでに gpsd の設定をしておきます。
$ sudo nano /etc/default/gpsd
以下のようにします。
START_DAEMON=”true”
USBAUTO=”true”
DEVICES=””
GPSD_OPTIONS=”/dev/ttyAMA0″
GPSD_SOCKET=”/var/run/gpsd.sock”
PPSを使ったNTPサーバを動かす
/etc/modules に次の1行を追加します。
pps-gpio
/boot/config.txt に次の1行を加えます。
dtoverlay=pps-gpio,gpiopin=18
Raspberry Pi を再起動します。
モジュールがロードされたことを確認します。
$ lsmod | grep pps
pps_gpio 2993 1
pps_core 8756 2 pps_gpio
PPSが有効になったかどうか確認します。
$ dmesg |grep pps
[ 4.384297] pps_core: LinuxPPS API ver. 1 registered
[ 4.386474] pps_core: Software ver. 5.3.6 – Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 4.416234] pps pps0: new PPS source pps.-1
[ 4.418431] pps pps0: Registered IRQ 178 as PPS source </giometti@linux.it>
pps tools をインストールします。
$ sudo apt-get install pps-tools
PPS をテストします。
$ sudo ppstest /dev/pps0
trying PPS source “/dev/pps0”
found PPS source “/dev/pps0″
ok, found 1 source(s), now start fetching data…
source 0 – assert 1388146614.000084899, sequence: 381 – clear 0.000000000, sequence: 0
source 0 – assert 1388146615.000082106, sequence: 382 – clear 0.000000000, sequence: 0
source 0 – assert 1388146616.000084314, sequence: 383 – clear 0.000000000, sequence: 0
source 0 – assert 1388146617.000081521, sequence: 384 – clear 0.000000000, sequence: 0
source 0 – assert 1388146618.000081728, sequence: 385 – clear 0.000000000, sequence: 0
source 0 – assert 1388146619.000080936, sequence: 386 – clear 0.000000000, sequence: 0
source 0 – assert 1388146620.000081143, sequence: 387 – clear 0.000000000, sequence: 0
…
/etc/ntp.conf に以下の2行を追加します。
server 127.127.22.0 minpoll 4 maxpoll 4
fudge 127.127.22.0 flag3 1 refid PPS
それから、PPSを使うためには他のサーバーに prefer 指定が必要とのことなので、NICTのサーバの後ろに prefer を付けます。
server ntp.nict.jp iburst prefer
NTPサーバを再起動して ntpq -p してみるとこんなふうになっているはずです。
remote refid st t when poll reach delay offset jitter
============================================
SHM(0) .GPS. 15 l 15 16 377 0.000 11.207 21.121
oPPS(0) .PPS. 0 l 14 16 377 0.000 -0.002 0.002
*ntp-a2.nict.go. .NICT. 1 u 21 64 377 6.501 0.258 0.914
さらに、ntpq -c rv の出力はこんな感じ。
associd=0 status=0115 leap_none, sync_pps, 1 event, clock_sync,
version=”ntpd 4.2.8p3@1.3265 Mon Jul 13 11:28:54 UTC 2015 (3)”,
processor=”armv6l”, system=”Linux/3.18.11+”, leap=00, stratum=1,
precision=-18, rootdelay=0.000, rootdisp=1.075, refid=PPS,
reftime=d94e2d5d.88677330 Mon, Jul 13 2015 21:28:13.532,
clock=d94e2d62.c11182ca Mon, Jul 13 2015 21:28:18.754, peer=19590, tc=4,
mintc=3, offset=0.008924, frequency=-19.734, sys_jitter=0.003815,
clk_jitter=0.319, clk_wander=0.017
この場合、オフセットは 約9µs です。PPSを参照しているので、stratum=1 になっています。
3件のコメント
PPSカーネルの設定について
こんにちは、既知のことかも知れませんが、kernelのデフォルと設定の
影響で、PPSハンドリングが正しく有効化されていなくて精度がでてい
ないケースとお見受けしました。Tickless System (Dynamic Ticks) を
OFFにすると精度が一段とあがります。
http://bugs.ntp.org/show_bug.cgi?id=2314
更に
echo “performance” > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
setserial /dev/ttyAMA0 low_latency
をいれるとppbの世界となります。 お試しを。
PPSカーネルの設定について
のべろさん、ありがとうございました。
いただいた情報に基づいてKernelを作り直して試しています。
なんと、精度が20倍くらい向上し、ナノ秒のオーダーになりました。
ナノ(ppb)の世界へようこそ!
ナノ(ppb)の世界へようこそ! うまく行かれたようで何よりです。
/boot/cmdline.txtに下記を追加するとRPIをNTPサーバとして
参照される方達がちょっとだけ幸せになるかもです。
smsc95xx.turbo_mode=0
disable_pvt=1
コメントは受け付けていません。