當你打開任何一款 GNSS 接收機的串口監控軟體,看到的第一個畫面通常是一串串以 $GP 開頭的文字訊息,不斷地滾動更新,有一種很洗畫面的感覺。這就是 NMEA 協定,幾乎所有 GNSS 接收機都支援的標準輸出格式。
在我剛開始開發 GNSS 應用時,面對這像火星文的字串完全摸不著頭緒。但當我慢慢理解了 NMEA 的結構後,才發現它其實沒那麼難懂,而且包含了定位所需的幾乎所有資訊。今天就來完整解析 NMEA 協定,讓你也能輕鬆讀懂衛星的「語言」。
一、什麼是 NMEA?
NMEA(National Marine Electronics Association,美國國家海洋電子協會)是一個制定海洋電子設備通訊標準的組織。NMEA-0183 是其在 1983 年發布的串列通訊協定標準,原本用於船舶導航設備,後來成為 GNSS 接收機的事實標準。
為什麼 NMEA 這麼流行?
- ✅ 文字格式:人類可讀,方便除錯
- ✅ 簡單易解析:用逗號分隔,不需複雜的解碼
- ✅ 廣泛支援:幾乎所有 GNSS 接收機都支援
- ✅ 跨平台:不依賴特定硬體或作業系統
- ✅ 標準化:不同廠商的接收機輸出格式一致
主要特點
- 串列通訊:RS-232 或 USB 虛擬串口
- 波特率:常見 4800、9600、38400、115200 bps
- 資料格式:ASCII 文字,每行一條訊息
- 更新率:通常 1 Hz,部分接收機支援 5-10 Hz
二、NMEA 訊息的基本格式
每條 NMEA 訊息都遵循固定的結構:
$GPGGA,123519,2503.1234,N,12100.5678,E,1,08,0.9,545.4,M,46.9,M,,*47
↑ ↑ ↑ ↑
| | | 校驗碼
| | 資料欄位(用逗號分隔)
| 訊息類型(Sentence ID)
對話者 ID(Talker ID)
結構說明
$:訊息開始符號- Talker ID(2 字元):
GP= GPSGL= GLONASSGA= GalileoGB= BeiDouGN= 多 GNSS 組合
- Sentence ID(3 字元):訊息類型(如 GGA、RMC)
- 資料欄位:用
,分隔,空欄位表示無資料 *:校驗碼分隔符- 校驗碼(2 位元組十六進位):XOR 校驗
\r\n:換行符號(結束)
校驗碼計算
校驗碼是 $ 和 * 之間所有字元的 XOR 運算:
範例:
$GPGGA,123519,2503.1234,N,12100.5678,E,1,08,0.9,545.4,M,46.9,M,,*47
計算步驟:
1. 取出 $ 和 * 之間的字串:
GPGGA,123519,2503.1234,N,12100.5678,E,1,08,0.9,545.4,M,46.9,M,,
2. 對每個字元的 ASCII 碼做 XOR 運算:
'G' XOR 'P' XOR 'G' XOR 'G' XOR 'A' XOR ',' XOR ...
3. 結果轉成十六進位:47
為什麼需要校驗碼?
– 檢測傳輸錯誤
– 確保資料完整性
– 串列通訊可能有雜訊干擾
三、常用 NMEA 訊息詳解
$GPGGA – 定位資訊(最重要)
包含完整的 3D 定位資訊,是最常用的訊息。
$GPGGA,123519,2503.1234,N,12100.5678,E,1,08,0.9,545.4,M,46.9,M,,*47
欄位解析:
| 欄位 | 內容 | 說明 |
|---|---|---|
| 0 | $GPGGA |
訊息類型 |
| 1 | 123519 |
UTC 時間(12:35:19) |
| 2 | 2503.1234 |
緯度(25°03.1234’) |
| 3 | N |
北緯(N)或南緯(S) |
| 4 | 12100.5678 |
經度(121°00.5678’) |
| 5 | E |
東經(E)或西經(W) |
| 6 | 1 |
定位品質(0=無效, 1=GPS, 2=DGPS, 4=RTK固定解, 5=RTK浮點解) |
| 7 | 08 |
使用的衛星數量 |
| 8 | 0.9 |
HDOP(水平精度因子,無單位) |
| 9 | 545.4 |
海拔高度(公尺) |
| 10 | M |
高度單位(公尺) |
| 11 | 46.9 |
大地水準面高度(公尺) |
| 12 | M |
單位(公尺) |
| 13 | “ | DGPS 資料齡期(空=無 DGPS) |
| 14 | “ | DGPS 基站 ID |
| 15 | *47 |
校驗碼 |
定位品質指標詳解:
| 值 | 說明 | 精度 |
|---|---|---|
| 0 | 無效定位 | – |
| 1 | GPS 單點定位(SPS) | 5-15 公尺 |
| 2 | 差分 GPS(DGPS) | 1-5 公尺 |
| 4 | RTK 固定解 | 1-3 公分 |
| 5 | RTK 浮點解 | 10-50 公分 |
| 6 | 推算定位 | 依賴慣性導航 |
經緯度格式轉換:
NMEA 使用「度分」格式(DDMM.MMMM),需要轉換成十進位度:
範例:2503.1234,N
步驟:
1. 前兩位是度:25°
2. 後面是分:03.1234'
3. 轉換公式:度 + 分/60
4. 計算:25 + 03.1234/60 = 25.052056°
如果是南緯(S)或西經(W),結果要加負號
實際範例:
– 緯度 2503.1234,N → 25.052056°N
– 經度 12100.5678,E → 121.009463°E
– 緯度 3351.8765,S → -33.864608°S
– 經度 15112.3456,W → -151.205760°W
💡 實務經驗: 我們曾經遇過一個 bug,在南半球測試時,緯度一直是正值。原因是忘記檢查 N/S 標記,導致所有位置都被定位到北半球。這個錯誤提醒我們,永遠不要假設資料格式,要嚴格按照協定解析。
$GPRMC – 推薦最小資料
包含時間、日期、位置、速度、航向,是最精簡但完整的訊息。
$GPRMC,123519,A,2503.1234,N,12100.5678,E,022.4,084.4,230394,003.1,W*6A
欄位解析:
| 欄位 | 內容 | 說明 |
|---|---|---|
| 0 | $GPRMC |
訊息類型 |
| 1 | 123519 |
UTC 時間(12:35:19) |
| 2 | A |
狀態(A=有效, V=無效) |
| 3 | 2503.1234 |
緯度 |
| 4 | N |
北/南緯 |
| 5 | 12100.5678 |
經度 |
| 6 | E |
東/西經 |
| 7 | 022.4 |
地面速率(節,knots) |
| 8 | 084.4 |
地面航向(度,真北為 0°) |
| 9 | 230394 |
UTC 日期(23/03/1994,DD/MM/YY) |
| 10 | 003.1 |
磁偏角(度) |
| 11 | W |
磁偏角方向(E/W) |
| 12 | *6A |
校驗碼 |
速度單位轉換:
1 節(knot)= 1.852 公里/小時
1 節(knot)= 0.514444 公尺/秒
範例:022.4 節
→ 22.4 × 1.852 = 41.5 公里/小時
→ 22.4 × 0.514444 = 11.5 公尺/秒
航向說明:
– 0° = 正北
– 90° = 正東
– 180° = 正南
– 270° = 正西
RMC 的優勢:
– 包含日期(GGA 沒有)
– 包含速度和航向
– 資料最精簡
– 適合記錄軌跡
$GPGSA – 衛星狀態與 DOP 值
顯示定位模式、使用的衛星、DOP 值。
$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
欄位解析:
| 欄位 | 內容 | 說明 |
|---|---|---|
| 0 | $GPGSA |
訊息類型 |
| 1 | A |
模式(M=手動選擇 2D/3D, A=自動選擇) |
| 2 | 3 |
定位類型(1=無定位, 2=2D, 3=3D) |
| 3-14 | 04,05,... |
使用的衛星 PRN 編號(最多 12 顆) |
| 15 | 2.5 |
PDOP(位置精度因子,無單位) |
| 16 | 1.3 |
HDOP(水平精度因子,無單位) |
| 17 | 2.1 |
VDOP(垂直精度因子,無單位) |
| 18 | *39 |
校驗碼 |
定位類型說明:
| 值 | 說明 | 需要衛星數 |
|---|---|---|
| 1 | 無定位 | < 3 顆 |
| 2 | 2D 定位(固定高度) | 3 顆 |
| 3 | 3D 定位 | ≥ 4 顆 |
DOP 值的關係:
\text{PDOP}^2 = \text{HDOP}^2 + \text{VDOP}^2
範例驗證:
– HDOP = 1.3
– VDOP = 2.1
– PDOP = √(1.3² + 2.1²) = √(1.69 + 4.41) = √6.1 ≈ 2.47 ≈ 2.5 ✓
DOP 值判讀:
| DOP 值 | 評級 | 衛星幾何 | 定位精度估計 |
|---|---|---|---|
| < 1 | 理想 | 極佳 | 極少達到 |
| 1-2 | 優秀 | 很好 | 誤差 < 5 公尺 |
| 2-5 | 良好 | 好 | 誤差 5-15 公尺 |
| 5-10 | 中等 | 普通 | 誤差 15-50 公尺 |
| 10-20 | 差 | 不佳 | 誤差 > 50 公尺 |
| > 20 | 極差 | 很差 | 不建議使用 |
為什麼 DOP 很重要?
因為 DOP 值反映衛星的幾何分布:
– DOP 低:衛星分布均勻,定位精度高
– DOP 高:衛星聚集在某個方向,定位精度低
實際定位誤差 = DOP × 測距誤差
$GPGSV – 可見衛星詳細資訊
顯示所有可見衛星的仰角、方位角、訊噪比。
$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74
$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D
欄位解析(第一條訊息):
| 欄位 | 內容 | 說明 |
|---|---|---|
| 0 | $GPGSV |
訊息類型 |
| 1 | 3 |
總訊息數(需要 3 條訊息) |
| 2 | 1 |
當前訊息編號(第 1 條) |
| 3 | 11 |
可見衛星總數(11 顆) |
| 4-7 | 03,03,111,00 |
衛星 1:PRN=03, 仰角=3°, 方位角=111°, C/N0=00 |
| 8-11 | 04,15,270,00 |
衛星 2:PRN=04, 仰角=15°, 方位角=270°, C/N0=00 |
| 12-15 | 06,01,010,00 |
衛星 3:PRN=06, 仰角=1°, 方位角=10°, C/N0=00 |
| 16-19 | 13,06,292,00 |
衛星 4:PRN=13, 仰角=6°, 方位角=292°, C/N0=00 |
| 20 | *74 |
校驗碼 |
每條 GSV 訊息最多包含 4 顆衛星資訊,所以 11 顆衛星需要 3 條訊息(4+4+3)。
衛星參數說明:
1. PRN(Pseudo-Random Noise)編號:
– GPS:1-32
– GLONASS:65-96
– Galileo:1-36(Talker ID 為 GA)
– BeiDou:1-63(Talker ID 為 GB)
2. 仰角(Elevation):
– 範圍:0-90°
– 0° = 地平線
– 90° = 天頂(正上方)
– 仰角越高,訊號品質通常越好
3. 方位角(Azimuth):
– 範圍:0-359°
– 0° = 正北
– 90° = 正東
– 180° = 正南
– 270° = 正西
4. C/N0(訊噪比,Carrier-to-Noise Ratio):
| C/N0 值 | 訊號品質 | 環境 | 可用性 |
|---|---|---|---|
| > 45 dB-Hz | 優秀 | 空曠戶外 | ✅ 定位精度高 |
| 40-45 dB-Hz | 良好 | 一般戶外 | ✅ 可靠定位 |
| 35-40 dB-Hz | 中等 | 有遮蔽 | ⚠️ 可用但精度降低 |
| 30-35 dB-Hz | 差 | 嚴重遮蔽 | ⚠️ 精度很低 |
| < 30 dB-Hz | 極差 | 室內/峽谷 | ❌ 通常無法定位 |
| 00 | 無訊號 | – | ❌ 可見但未追蹤 |
💡 實務經驗: 在開發定位品質監控功能時,我們發現單看衛星數量不夠,還要看 C/N0。曾經在室內測試,接收機顯示 8 顆衛星,但 C/N0 都低於 25 dB-Hz,定位結果完全不可用。後來我們加入 C/N0 門檻過濾(> 30 dB-Hz),定位品質明顯改善。
GSV 的應用:
– 診斷訊號品質問題
– 判斷天線安裝是否正確
– 分析遮蔽物影響
– 選擇最佳觀測時段
$GPGST – 精度統計(選配)
部分高階接收機支援,提供定位精度估計。
$GPGST,123519,3.2,6.6,4.7,47.3,5.8,5.6,22.6*58
欄位解析:
| 欄位 | 內容 | 說明 |
|---|---|---|
| 0 | $GPGST |
訊息類型 |
| 1 | 123519 |
UTC 時間 |
| 2 | 3.2 |
RMS 誤差(公尺) |
| 3 | 6.6 |
誤差橢圓長軸標準差(公尺) |
| 4 | 4.7 |
誤差橢圓短軸標準差(公尺) |
| 5 | 47.3 |
誤差橢圓方位角(度) |
| 6 | 5.8 |
緯度誤差標準差(公尺) |
| 7 | 5.6 |
經度誤差標準差(公尺) |
| 8 | 22.6 |
高度誤差標準差(公尺) |
| 9 | *58 |
校驗碼 |
水平精度估計:
\text{水平精度} \approx \sqrt{\text{緯度誤差}^2 + \text{經度誤差}^2}
範例:√(5.8² + 5.6²) = √(33.64 + 31.36) = √65 ≈ 8.1 公尺
GST 的價值:
– 接收機自己估計的精度
– 比 DOP 更直接
– 可用於品質控制
– 不是所有接收機都支援
四、實務應用建議
1. 選擇需要的訊息
不要輸出所有訊息,只啟用需要的:
| 應用場景 | 建議訊息組合 | 說明 |
|---|---|---|
| 基本定位 | GGA + RMC | 位置、時間、日期、速度 |
| 品質監控 | GGA + GSA + GSV | 加上 DOP 和衛星資訊 |
| 精度評估 | GGA + GSA + GST | 需要接收機支援 GST |
| 軌跡記錄 | RMC | 最精簡,包含所有基本資訊 |
| 最小配置 | RMC | 一條訊息包含最多資訊 |
2. 波特率設定
根據更新率和訊息數量選擇合適的波特率:
| 更新率 | 訊息組合 | 每秒資料量 | 建議波特率 |
|---|---|---|---|
| 1 Hz | GGA + RMC | ~160 bytes | 9600 bps |
| 1 Hz | GGA + RMC + GSA + GSV | ~400 bytes | 9600 bps |
| 5 Hz | GGA + RMC | ~800 bytes | 19200 bps |
| 5 Hz | GGA + RMC + GSA | ~1000 bytes | 38400 bps |
| 10 Hz | GGA + RMC | ~1600 bytes | 38400 bps |
| 10 Hz | GGA + RMC + GSA | ~2000 bytes | 115200 bps |
計算公式:
每條 NMEA 訊息約 70-100 字元
加上換行符號約 80-110 bytes
範例:5 Hz,輸出 GGA + RMC + GSA
每秒資料量 = (80 + 80 + 60) bytes × 5 Hz = 1100 bytes/s
需要頻寬 = 1100 × 10 bits = 11000 bps
建議波特率 = 19200 bps(留 2 倍餘裕)
3. 錯誤處理檢查清單
解析 NMEA 時,務必檢查:
✅ 基本格式檢查:
– 訊息開頭是否為 $
– 是否包含 * 和校驗碼
– 校驗碼是否正確
✅ 資料有效性檢查:
– 欄位數量是否足夠
– 數值欄位是否為空
– 定位狀態是否有效(GGA quality ≥ 1, RMC status = A)
✅ 格式轉換檢查:
– 經緯度格式轉換(度分 → 十進位度)
– 南緯/西經要加負號
– 時間是 UTC 需轉換
✅ 合理性檢查:
– 緯度範圍:-90° 到 +90°
– 經度範圍:-180° 到 +180°
– 高度是否合理
– 速度是否合理
4. 多 GNSS 處理
現代接收機會輸出多個系統的訊息:
$GPGGA,... (GPS 定位)
$GLGGA,... (GLONASS 定位)
$GAGGA,... (Galileo 定位)
$GBGGA,... (BeiDou 定位)
$GNGGA,... (多系統組合定位) ← 推薦使用
處理策略:
| 策略 | 說明 | 優點 | 缺點 |
|---|---|---|---|
| 只用 GN | 只解析 $GN 開頭的訊息 |
簡單,已是最佳結果 | 無法分析各系統 |
| 分別解析 | 解析所有系統的訊息 | 可比較各系統性能 | 複雜,資料量大 |
| 優先順序 | GN > GP > GL > GA > GB | 有備援機制 | 需要更多邏輯 |
推薦做法:
– 定位應用:只用 $GN 訊息
– 診斷分析:解析所有系統的 GSV 訊息
– 研究開發:記錄所有訊息供後續分析
5. 效能優化建議
減少資料量:
– 只啟用必要的訊息類型
– GSV 訊息資料量大,不需要時可關閉
– 降低更新率(如果應用允許)
提高解析效率:
– 先檢查訊息類型,只解析需要的
– 使用查表法而非字串比較
– 快取經常使用的計算結果
記憶體管理:
– 使用固定大小的緩衝區
– 避免動態記憶體分配
– 及時清理過期資料
五、常見陷阱與解決方案
❌ 陷阱 1:時間是 UTC 不是本地時間
問題:
GGA 時間:123519
直接顯示:12:35:19(誤以為是台北時間)
正確做法:
GGA 時間:123519(UTC)
台北時間(UTC+8):123519 + 8 小時 = 20:35:19
注意跨日問題:
UTC 時間:235959(23:59:59)
台北時間:235959 + 8 小時 = 次日 07:59:59
❌ 陷阱 2:空欄位處理
問題:
$GPGGA,123519,,,,,0,00,,,M,,M,,*XX
↑ 無效定位時,經緯度等欄位是空的
正確做法:
– 先檢查定位品質(欄位 6)
– 檢查欄位是否為空再解析
– 設定預設值或錯誤標記
❌ 陷阱 3:經緯度格式混淆
錯誤理解:
緯度:2503.1234
誤以為:2503.1234 度
正確理解:
2503.1234 = 25°03.1234'(度分格式)
轉換:25 + 03.1234/60 = 25.052056 度
❌ 陷阱 4:忘記檢查定位品質
問題:
只要收到 GGA 訊息就使用位置資料
→ 可能使用無效的定位結果
正確做法:
檢查 GGA 欄位 6(定位品質):
- 0 = 無效,不使用 ❌
- 1 = GPS 單點定位,可用 ✅
- 2 = DGPS,精度更高 ✅
- 4 = RTK 固定解,公分級 ✅
- 5 = RTK 浮點解,分米級 ✅
或檢查 RMC 欄位 2(狀態):
- A = 有效 ✅
- V = 無效 ❌
❌ 陷阱 5:HDOP 當成公尺
錯誤理解:
HDOP = 1.5
誤以為:水平誤差 1.5 公尺
正確理解:
HDOP = 1.5(無單位,是一個倍數)
測距誤差 = 5 公尺(假設)
實際水平誤差 ≈ 1.5 × 5 = 7.5 公尺
HDOP 只是幾何因子,不是誤差本身
❌ 陷阱 6:忽略校驗碼
問題:
為了簡化,不驗證校驗碼
→ 可能使用損壞的資料
正確做法:
– 永遠驗證校驗碼
– 校驗碼錯誤時丟棄整條訊息
– 記錄錯誤率用於診斷
💡 實務經驗: 在一個車載專案中,我們發現定位偶爾會「跳動」到奇怪的位置。後來發現是電磁干擾導致串口資料損壞,但我們沒有驗證校驗碼。加入校驗碼驗證後,這些異常資料被過濾掉,定位穩定性大幅提升。永遠不要跳過校驗碼驗證。
六、總結
NMEA-0183 是 GNSS 接收機最通用的輸出格式:
✅ 優點
- 人類可讀:方便除錯和理解
- 廣泛支援:幾乎所有接收機都支援
- 簡單易解析:用逗號分隔,結構清晰
- 跨平台:不依賴特定硬體
- 標準化:不同廠商格式一致
⚠️ 注意事項
- 資料量大:文字格式佔用頻寬
- 精度有限:小數位數固定
- 需要轉換:經緯度、速度等格式
- 時間是 UTC:需轉換成本地時間
- 高更新率受限:10 Hz 以上效率低
🎯 關鍵要點
- 永遠驗證校驗碼
- 正確轉換經緯度格式(度分 → 十進位度)
- 處理空欄位(無效定位時很多欄位是空的)
- 檢查定位品質(GGA quality, RMC status)
- 時間是 UTC(需轉換成本地時間)
- DOP 是無單位的(不是公尺,是倍數)
- C/N0 很重要(判斷訊號品質)
- 多 GNSS 用 GN(組合定位結果最佳)
📊 快速參考表
| 訊息 | 更新率 | 用途 | 關鍵欄位 |
|---|---|---|---|
| GGA | 1 Hz | 3D 定位 | 時間、經緯度、高度、HDOP、衛星數、定位品質 |
| RMC | 1 Hz | 最小資料 | 時間、日期、經緯度、速度、航向、狀態 |
| GSA | 1 Hz | DOP 值 | 定位模式、使用的衛星、PDOP/HDOP/VDOP |
| GSV | 5 秒 | 衛星資訊 | 衛星編號、仰角、方位角、C/N0 |
| GST | 1 Hz | 精度估計 | RMS 誤差、各軸誤差標準差(選配) |
💬 討論
你在解析 NMEA 時遇過什麼問題?歡迎留言討論!