iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Modern Web

教練看不到的那六天|從 FIT 檔到 3D 軌跡,馬拉松訓練資料 Dashboard系列 第 4

Day 4|開箱 FIT 檔(上):record / lap / session 訊息結構

  • 分享至 

  • xImage
  •  

昨天拿到登入憑證了,今天正式打開 Garmin 錶同步上去的那個東西—FIT 檔案

我們可以知道 FIT 不是 JSON,打開來看不到任何一個你認得的字。它是 Garmin 自己的二進位格式,一整包全是位元組。好消息是不用自己手拆—Python 的 fitdecode 已經幫忙做完解碼,我們要做的是搞懂解出來之後裡面到底裝了什麼


先來盤點有什麼資料

拿一份不大的檔案練手—8 月 13 日那場 1600m×3 的間歇,跑起來 28 分鐘。把裡面所有的訊息類型跟出現次數印出來:

record                          1685
unknown_534                     1685
unknown_325                      294
time_in_zone                      52
split                             36
unknown_326                       36
lap                                15
device_info                        12
unknown_104                         6
unknown_327                         5

28 分鐘的訓練,record 出現了 1685 次—差不多每秒一筆,這是整份檔案的主軸,逐秒紀錄了自己跑步當下的每一個瞬間。lap 有 15 筆,對應這場訓練被切成的 15 個分段(暖身、三趟間歇、每趟之間的恢復跑,各自算一段,其實就是按錶的按鈕 Lap 的切割)。

比較嚇人的是那排 unknown_*unknown_534 出現次數跟 record一模一樣(1685 次),代表它也是逐秒紀錄的—但這邊無法知道裡面裝什麼。這些是 Garmin 自己裝置的私有欄位,公開的 FIT SDK 沒收錄定義,連 fitdecode 都只能標成「無法辨識」,原封不動印出代號。

呼應昨天那個查不到型號的裝置代碼:這份檔案裡部分的訊息,是連公開文件都無法確認的內容。能用的只有那些有明確定義的訊息類型,剩下的就先放著。


三個真正要用的訊息

好消息是,要重建一場訓練的樣貌,不需要搞懂全部—只要抓住三種:

record—每秒一筆的原始紀錄。 這場間歇裡,一筆 record 長這樣(拿掉了其餘 22 個值是 None 的欄位):

timestamp             2026-08-13 12:03:53
position_lat          298858368
position_long         1450173354
distance              0.0
heart_rate             117
enhanced_speed          0.0
enhanced_altitude      6.8
power                    32

這遠比昨天貼過的摘要 API 豐富—完整版的 record 有 30 個欄位,除了心率配速,還有功率、垂直振幅、觸地時間這些跑步動態數據。這些指標 Garmin Connect App 都看得到,但看到的是整理過的圖表跟平均值;FIT 檔給你的是每一秒的原始數字

差別在於,原始數字是可以拿去用的:上面這筆裡的 heart_rateenhanced_speed,Day 22 會變成復盤圖上疊在一起的兩條曲線,用來看心率怎麼在配速不變的情況下一路往上爬。至於功率、垂直振幅這些,目前雖然沒用上—但它們都在,之後可以再看看怎麼呈現在儀表板上。

lap—分段摘要。 每一次你按錶分段(或系統自動分段),就是一筆 lap,裡面存著這一段的距離、時間、平均心率。

session—整場總結。 一份檔案通常只有一筆,裝的是這整場訓練的總覽:

sport                    running
total_distance           5220.0
total_timer_time         1683.943
avg_heart_rate            170
max_heart_rate            191

這三種訊息疊起來,就是一場訓練從頭到尾的完整故事:session 就是「跑了什麼」、lap 就是「分段在哪」、record 告訴你「每一秒發生了什麼」。


經緯度的單位差異

上面那筆 record 裡,position_lat 的值是 298858368。欄位名稱寫著 lat,所以它確實是緯度,但緯度的範圍就是 -90 到 +90,兩億九千萬顯然不在裡面。

這邊是單位上的差異。FIT 存座標用的是 semicircle(半圓),不是我們熟悉的度數。換算公式是:

degrees = raw_value * (180 / 2**31)

拿真實數字驗證:

>>> 298858368 * (180 / 2**31)
25.050019
>>> 1450173354 * (180 / 2**31)
121.552126

換出來是 25.050019, 121.552126 即是這個訓練的地點—松山區田徑場的座標。不知道這個公式的話,直接拿 298858368 去畫地圖,應該會滿頭問號^0^


明天:把整場全馬撈出來

今天用的是一份 28 分鐘的小檔案,訊息種類的分佈一眼看得完。明天要換上真正的大檔案—一場 3 小時 22 分的全馬,一萬兩千多筆 record。這篇建立的框架(三種訊息、座標換算)會直接拿去用,重建出完整的分段配速表-來看這場全馬到底是在哪一公里開始崩潰的...



上一篇
Day 3|取得 Garmin 資料:官方 API vs garminconnect 套件實測
下一篇
Day 5|開箱 FIT 檔(下):解析一場全馬,還原每秒心率與配速
系列文
教練看不到的那六天|從 FIT 檔到 3D 軌跡,馬拉松訓練資料 Dashboard5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言