m-241のバイナリデータからトラックログを吸い出す

GPSロガー(Holux m-241)のメモリが破損しているのか、 実は6月30日と7月3日の軽井沢→直江津ツーリングと、9月の西九州→佐多岬ツーリングでは、 ログが破損していたため、Googleのロケーション履歴を代用している。

バイナリデータは一応吸い出せているようなので、その構造を調べると、 HOLUX m-241 LoggerUtility .trlファイル構造の覚書 より以下のような構造になっている。

  • 1レコード20バイトの固定長
  • 時刻4バイト
  • 緯度4バイト
  • 経度4バイト
  • 高度3バイト
  • 速度4バイト
  • チェックサム1バイト

また、m-241は時折書き込み先のメモリアドレスがずれることがあるようだ、との情報も見つかったため、 バイナリエディタで除いてみると、どうも4バイトずつずれて記録されたデータがあるようだった。

そこで

  • レコードの先頭バイトを4バイトずつオフセットさせて読み込んでみる
  • 緯度と経度が日本付近のものと思われるものを片っ端から拾う
  • 時刻は整数型なのでとりあえず読み込む
  • 高度、速度のデータは無視!

という方針でMathematicaのプログラムを書いてみた。

data = Table[Module[{str, ret},
    str = OpenRead["2016091200.bin", BinaryFormat -> True];
    (* 最初に余分にiバイト読み込んで先頭をずらす *)
    Do[
     BinaryRead[str, "Byte"],
     {i}
     ];
    (* バイナリ形式で読み込む *)
    ret = Cases[
      MapIndexed[
       {First[#2], Sequence @@ #1} &,
       BinaryReadList[
        str, {"Integer32", "Real32", "Real32", "Byte", "Byte", "Byte", "Real32", "Byte"}]
       ],
      {count_, d_Integer, lat_Real, lon_Real, __} /; (30 < lat < 40 && 125 < lon < 140) :>
      {count, DateString[DatePlus[{1970, 1, 1, 0, 0, 0}, {d, "Second"}], {"Year", "-", "Month", "-", "Day", "T", "Time", "Z"}], lat, lon}];
    Close[str];
    ret
    ],
   {i, 0, 19, 4}];

※ 2016091200.binというのがバイナリ形式のm-241ログファイル名。もとのデータ順を保存するように、MapIndexedを使用している。日本付近、というのは今回は緯度が30度から40度、経度が125度から140度とした。

読み込めた点数は下記の通り。

In[2]:= Length /@ data
Out[2]= {13083, 9326, 5019, 7715, 9721}

本来は「HOLUXGR241LOGGER」という文字列がレコード開始位置の基準になっているのを無視すると、 ずれを起こしていないログが13083点、4バイトずれて記録されたのが9326点、8バイトずれて記録されたのが5019点・・・という結果となった。

あとはこれをGPXファイルとして出力する。

data2 = Sort[Flatten[data, 1]];

str = OpenWrite["20160912_rescue.gpx"];
WriteString[str, 
  "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>
  <gpx
      version=\"1.1\"
      creator=\"330k.info\"
      xmlns=\"http://www.topografix.com/GPX/1/1\"
      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
      xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">
  <trk>
   <name>20160912</name>
   <number>0</number>
  <trkseg>"];
WriteString[str,
    ToString@
     StringForm[
      "<trkpt lat=\"``\" lon=\"``\"><time>``</time></trkpt>\n",
      NumberForm[#[[3]], 10], NumberForm[#[[4]], 10], #[[2]]
      ]
    ] & /@ data2;
WriteString[str, "</trkseg></trk></gpx>"];
Close[str]

GPSBabelを使用してGPXファイルに変換した場合と比べて、どの程度のログを救出できたか調べた。

日程 2016年6月30日→2016年7月3日 2016年9月6日→2016年9月11日
経路 東京→軽井沢→直江津 小倉→長崎→佐多岬
トラックポイント数(GPSBabel) 4039 19482 ※ 異常な点を手作業で削除
トラックポイント数(上記プログラム) 12442 24869 ※ 異常な点を手作業で削除
地図

赤線 : GPSBabelで変換したログ 青線 : 今回のプログラムで救出したログ

結果としては、東京→軽井沢→直江津は全部救出でき、 小倉→長崎→鹿児島間では

  • 3日目の福岡県柳川市付近
  • 4日目の熊本県宇城市→鹿児島県霧島市
  • 5日目の鹿児島県垂水市→南大隅町

のトラックポイントを合計5387点を救出できた。

福岡県糸島市→長崎県松浦市、福岡県柳川市→熊本県宇城市の区間はどうしようもなかった。

CATEYE製サイコンも3日目と4日目にトラブルを起こしているので、 今後はm-241の使用をとりやめ、Garminを購入する予定。