GPS データ (GPX) から移動距離を求める

GPS データから走行距離を計算したくて、緯度経度を用いた距離計算法を調べてみた。そしてスクリプト書いた。

2点間距離を求める

緯度経度を用いて距離を測定するには、ヒュベニの公式を使うのがわりとポピュラーそうだった。この式は、3D地図ソフトのカシミール3Dで使われていたりする。

カシミール / 計算式に載っている式を転載すると、

D=sqrt((M*dP)*(M*dP)+(N*cos(P)*dR)*(N*cos(P)*dR))

       D:  2点間の距離(m)
       P:  2点の平均緯度
       dP: 2点の緯度差
       dR: 2点の経度差
       M:  子午線曲率半径
       N:  卯酉線曲率半径
       M=6334834/sqrt((1-0.006674*sin(P)*sin(P))^3)
       N=6377397/sqrt(1-0.006674*sin(P)*sin(P))

こんな感じ。

もう少し詳しい解説はこのページにのってる。今回はここを参考にした。

二地点の緯度・経度からその距離を計算する(日本は山だらけ〜)

基本上ページ Fig.1 の通りにプログラムを書けばいいけど、ヒュベニの公式で用いる緯度経度はラジアンであるのに注意しなければならない(ハマった)。GPS で記録される緯度経度は勿論なので変換する必要がある。

# deg(度)から rad(ラジアン)を求める
rad = deg * Math::PI / 180

高校数学を思い出す。

あと、子午線曲率半径の算出に長半径(赤道半径)・卯酉線曲率半径を求めるのに短半径(極半径)が必要だけど、今回は GPS に使われるらしい WGS84 基準のパラメータを用いた。

測定誤差

地球は楕円体だしということで、やっぱり計算結果に誤差は出てくる。下のページで検証がなされている。

緯度経度から2点間の距離を求める | ぷちのいず

上のページによると、ヒュベニの公式を用いた場合は50km以上から誤差が大きくなるらしい。今回は自転車の走行距離を(主に)算出したいので、結果は高々200kmといったところ。まあ問題ないということにした。

GPX ファイルから移動距離を計算する

以上の計算を、GPX ファイル(GPS データを格納する XML)に記録されたトラックポイント間に対して行う。

GPX ファイルの中身は XML になっている。構造の説明は置いといて、トラックポイントの緯度経度は trkpt タグに属性値として記録されている。こんな感じ。

<trkpt lat="35.765263255" lon="139.867893811">

こっから lat (緯度)と lng (経度)を正規表現抽出して配列に格納。全部抽出し終わったら先頭から各要素間の距離を求めていく。ラジアン変換も忘れずに。その総和が移動距離になる。

そうしてできたのがこの Ruby スクリプト。

Gist: gpx_distance.rb

実行

昨日は東京から印旛沼の風車までロングライドした。そのときの走行距離を調べてみる。

$ grep "<trkpt lat=" 130608.gpx | wc -l
    8550

この GPX ファイルには8550個のトラックポイントが記録されている。記録された移動距離は、

$ time ./gpx_distance.rb 130608.gpx
129.792 km
./gpx_distance.rb 130608.gpx  0.63s user 0.07s system 99% cpu 0.701 total

こんな感じで求まった。

ちなみにサイコン (CC-RD200) では126.99kmとなっている。まあ測定誤差測定誤差・・・

あと、ルートラボの距離のは6kmくらい少ないのが表示されてるけど、これは GPX を投稿する際に最初と最後を削った影響である。個人情報的なアレと8000ポイント制限で。

最後に

自転車乗りで、ログ取りたいけどガーミンとか手が出せない・・・って人は秋月で売っとる3000円以下のロガー買ったら幸せになれる。このへん別に記事書きたい。

USB接続GPSモジュール(GPSデータロガー)GT-730F/L

ルートラボ、良いんだけど Silverlight いい加減取りやめてくれませんかね・・・それか JS 版をもっと使えるレベルにしろと・・・