以 RTKLIB 與 RTCM SSR 訊息進行 real time PPP

這算是我論文的一部份,之前教授就說他想試, 我也糊里糊塗沒仔細評估就答應了,還好真的做的出來。 過程不難,但我自己耍蠢撞牆居多。 關鍵有幾個點:要用 rtkexplore 版本的 rtklib , RTCM 要選 products.igs-ip.net,天線要用雙頻。

無關技術的事情起緣

之前教授不知哪裡看到 real time ppp 的消息, 認為 rt-ppp 是未來的潮流, 知道現在 igs 之類的組織有在網路上提供 即時精密星曆 , 只要有網路就可以收,用接收儀做 即時精密單點定位

他主要是參考 rtkexplorer 的 rt ppp 文章, 就要我試試看,用平價的接收儀如 u-blox 的 f9p 晶片, 和行動網路或 wifi 接星曆做 rt-ppp。

他聯絡了另一個有 u-blox 長期使用、開發經驗的教授林修國, 要我去請教可行性之類的。 那時候我還搞不太清楚要幹麻, 想說應該一定做的起來,就沒有很認真參考。 事後想想那時就應該要拒絕,因為林修國那時是說他幾年前做過, 但他印像中 rtklib 接網路星曆的 rt-ppp 還不能直接用,要自己改 code。

這時候我就應該要拒絕了,因為我根本沒有改 code 的能力。 結果那時不知道是鬼遮眼,還是敷衍上級的老毛病又犯了, 回去後還是和教授說沒問題,可以買 f9p 了。 事後想想真是有驚無險,還好做出來了。

技術

教授買的是和 raspberry pi 接好的 f9p 晶片,和一顆雙頻的天線。 pi 開機後可以從 /dev/serial0 讀寫 f9p 的訊息, pi 本身沒有電池,可以從 micro usb 接電源, 所以接上手機用的行動電源就可以使用。

主要流程我也是參考 rtkexplorer 的 rt ppp 文章

ublox 晶片連結

ublox 的 f9p 晶片是用 serial port 連到 pi 上, windows 叫 com1,unix 則是會位在 /dev/serial0 。 (數字可能改變。) 實際上 serial0 是個指到 /dev/ttyS0 的符號連結, 總之可以動。

serial0 在 linux 下表現為 character special device, 但我一直不知道怎麼和這類裝置互動。 寫入就直接 echo foo >/dev/serial0 即可, 但讀取好像不能直接 cat /dev/serial0 ? cat 一下就讀取完就退出了,但我是需要不斷讀取他的輸出, 把他當成像標準輸入一樣的 stream 來讀。

str2str

還好 rtklib 可以直接處理這種細節, 提供了一個叫 str2str 的程式, 可以用來把一個 stream 轉到多個 stream 甚至轉存成檔案。 所以就把 serial 轉成 tcp stream 來處理; 也同時存成檔案,也就是 ubx 格式的原始記錄檔。

str2str -in serial://serial0:115200 \
        -out tcpsvr://:5566 \
        -out file:///home/pi/test.ubx

一個 str2str 可以從一個 stream 讀取,輸出到多個輸出。 這個指令可以把 /dev/serial0 以 115200 baud 讀取, 並在 localhost 5566 port 輸出, 並存成 /home/pi/test.ubx 的檔案。 rtklib 風格的 url 不用寫 /dev/ ,直接寫裝置名稱即可, 大概是從 windows 來的習慣; windows 下 com port 就直接叫 com1,也沒有所謂的完整路徑。

對 baud rate 我還是不太懂,要怎麼知道裝置的 baud rate, 我看之前測試的人留在 pi 裡面的設定檔才知道的。 如果不設的話,str2str 似乎會自己測?我看也是測對。

輸出除了tcpsvr, 也可以是tcpcli。 如果是 server,就是可以有多個 client 連上去讀取, 像用 nc localhost 5566 讀取; 如果是 client,就是會主動連到該 ip port 輸出資料, 類似 http post 到某一個 port 的概念。

重播用的 timetag

後來我發現,rtklib 有一個 重播 功能, 把串流存到檔案後,可以再從檔案串流出來,供事後反覆解算。 但這個功能除了原始串流資料, 還需要什麼時間串流了多少資料的時間資料。 要啟用這功能,在 rtklib 或 str2str 中的 file:// 路徑結尾加上 ::T 即可, 例如 file://ublox-f9p.ubx::T 。 rtklib 用雙冒號當作參數的語法。 (怎麼不是用 querystring 的風格?)

如果在儲存時加上 T 選項,除了原始檔案, 還會多儲存一個 *.*.tag 的 timetag 檔案來記錄時間戳。 (像 ublox-f9p.ubxublox-f9p.ubx.tag ) 在讀取時如果加上 T 選項,就會照 timetag 檔案裡記錄的時間重播。

如果不用 T 選項,基本上就無法正確的重播; rtklib 只會以最快速度一次把所有資料讀完, 而不同格式的檔案間也無法配合。 所以可能星曆讀到一半,但觀測量已經讀完了, 讀取到的時間點沒重疊,無法一起解算。

很可惜的是明明多數觀測量都已經有時間戳了, 但卻還是要額外記錄一個 timetag 檔案才能正確重播。 有想過自己寫一支程式讀觀測量產生 timetag 檔案, 但後來發現超出我的能力,幾乎看不懂 rtklib 的原始碼,就放棄了。 別人已經寫好就乖乖照他的框架走就好了。

時間戳的格式

麻煩的是時間戳還有二種格式, 似乎和 c 語言中的時間戳資料結構大小有關。 在 raspberry pi 中是 4 byte, 在一般 64 bit PC 是 8 byte。

在讀取時可以用 ::P=4::P=8 來指定, 在存儲時 P 選項好像沒有用,不能更改。 而且更麻煩的是一支 rtkrcv 程序在讀取二個檔案時, 不能指定不同格式的時間戳; 得要開二支 str2str 以不同大小讀取串流, 到 tcp 上就沒有時間戳問題了。

這個選項沒有寫在手冊裡, 我去翻 原始碼才在註解裡 找到的……。 不過原始碼還是超出我能力範圍,無法修改。

時間的同步

如果在腳本中,那數支 str2str 是在不同行命令中執行, 雖然 shell 不是很快的語言,約有數十 ms 等級的時差, 但對 gnss 的速度來說算是同步的。

但如果很不幸二份檔案是在不同時間開始記錄的, 那就需要讓二者播放時能 同步 。 可以用 ::+60 的選項來快轉 60 秒。 另外 rtkrcv 中如果讀取來源是有 timetag 的檔案, 就會自動將二者同步。 如果是 str2str,則需要手動算出誤差秒數來同步。

要算同步秒數,可以在 rtkrcv console 中, 用 observ 命令來看到目前的觀測量的時間, 用 ssr 可以看到星曆的時間。 rtk 的話,二者都會顯示在 observ 裡。

ser2net

str2str 是只能單向讀取 serial 輸出到其它串流, 但 serial 是雙向的,有時需要 config 晶片, 就會需要寫入資料。

ublox 提供的 u-center 程式就是用來連結晶片, 讀取、設定晶片的程式。 u-center 是在 windows 上執行的程式, 我用 wine 跑是沒問題的。 但我不可能在 pi 上跑 wine 再跑 u-center, 所以我 google 到一支 ser2net 的 linux 程式, 可以把 serial 轉到 tcp 連線,且可以供讀寫。 u-center 除了直接連 serial,也可以連轉成 tcp 的 serial。 所以問題就解決了。

u-center 設定

u-center 可以設定 f9p 要輸出哪些訊息。 receiver > connection 裡可以選要用 com port (serial) 或 tcp 連, 連上後在 view > configuration view 裡可以改設定。

f9p 本身可以進行基本的基於電碼的定位, 可以直接以 nmea 輸出定位結果座標、衛星顆數。 也可以讀取 rtcm 後進行 rtk 定位, 但這部份怎麼設定就沒研究了。

在 configuration view 的 MSG 分類下, 可以設定在哪些 port 要輸出哪些訊息, 我看得到有 i2c uart1 uart2 usb spi 五個 port。 serial 應該是 uart1 或 uart2,所以我都開了。 如果 f9p 是用 usb 連 pi,那可能要改成開 usb。 i2c 和 spi 就不知道了。

至少要開 rawx 和 sfrbx 才會輸出 gnss 觀測量, 方能以 rtklib 或其它程式定位。

nmea 的訊息開了之後,u-center 上的 儀表板 才看得到東西。 如果 nmea 有開,nmea 訊息會夾在 serial 輸出的二進位訊息裡, 但不會影響 ubx 二位進格式的解析。 只是檔案會變大,如果開 gngsv 的話會很大。

設定的方式是選好訊息後,在要輸出的 port 上打勾, 然後按視窗左下角的 send 按鈕,即會將設定發送到晶片上。 如果要永久保存設定,要切到 CFG, 選 save current configuration ,並選擇對應的裝置; 我選了 BBR 和 FLASH,這二個應該至少有一個是持久的, 詳細可能要讀手冊。

rtklib 版本

我本來是直接 clone rtklib github 上的 master branch, 在 raspberry pi 上編譯命令列版本的程式:

git clone https://github.com/tomojitakasu/RTKLIB rtklib.git
cd rtklib.git/app
sh makeall.sh
sudo find -type f -executable -exec install '{}' /usr/local/bin \;

但後來發現都解不出來,收下來的資料都只有單頻。 (而我選了雙頻,所以解不出來。) 後來發現 2.4.2 2.4.3 版的 rtklib, 用 convbin 轉出來的資料都只有 L1 波段, 也就是說這二版的 rtklib 都不支援 ublox 的 L2 波段資料。 我試 teqc 也是一樣的結果。

後來找到 rtkexplorer 談 f9p ppp 的文章 , 才看到 他釋出的支援 ublox f9p 的 rtklib 版本 。 因為他只有提供 windows 的執行檔, 而且 pi 不是 x64 要另外編譯,就直接 clone 他的 github 原始碼自己編譯。

git clone https://github.com/rtklibexplorer/RTKLIB rtklib-explorer.git
cd rtklib-explorer.git/app
make -j4 # 四核心編譯
sudo make install # 預設裝到 /usr/local/bin

之後 convbin 轉出來的就有 L2 了, 預設也從 rinex 2.11 變成 3.03。 也就代表 rtkrcv 程式可以解析 ublox 雙頻訊號。

雙頻天線問題

後來發現天線也有分雙頻單頻。 之前有從教授拿到一個單頻的 skytraq 接收儀, 有附一個小小的磁鐵天線,可以黏在車頂。 在宿舍頂樓測試時,因為 ublox 的天線接口在底部, 不能直接放在地上,所以想先用小天線頂著用; 結果收到的就只有單頻訊號。

rtcm ntrip 與 ssr 訊息

igs 即時精密星曆除了 15 分鐘發布一次的檔案外, 也有用 ntrip 協議發送。 ntrip 是 rtcm 協議在 http 上運行的版本, rtcm 則是用來傳輸 gnss 訊號的協議。 我印象中 rtcm2 只能用來傳輸 rtk 需要的差分訊號, 而 rtcm3 中定義了 ssr 訊息, 用來表示即時精密星曆。

我有找到一篇文章有提供 rtcm 訊息的意義 , rtkrcv 會顯示收到的訊息, 還有 ntrip source table 也會顯示該 mount point 提供哪些格式訊息, 可以用來粗略判斷運作正不正常。

要收 igs 的 ntrip 協議需要註冊 , 在連接時提供使用者名稱和密碼。 註冊時可以選要申請 igs 或 euref 的, 這個服務似乎很多國家或組織都有提供。

以 igs 來說,在 http://www.igs-ip.net/home 有說明, 而 http://www.igs-ip.net/ 則有以 ntrip 格式提供的 資源列表, 每行是一比記錄,其中以分號分隔不同欄位。 其中以 STR 開頭的記錄是一比可以用 ntrip 連上的站。 例如 STR;NIUM00NIU0;... , 就表示 www.igs-ip.net 有收集 NIUMOONIUO 站的 ntrip 資料, 可以透過 www.igs-ip.net/NIUMOONIUO 取得 niumooniuo 的資料。 (NIUMOONIUO 稱為 www.igs-ip.net 的一個 mount point。)

igs 下有 http://www.igs-ip.net/ http://mgex.igs-ip.net/ http://products.igs-ip.net/ 三個 server。 www 上可以串流所有所有 igs 收集的 gnss 測站資料, mgex 不知道, 而 products 就是依收集的所有 ntrip 資料, 計算出精密星曆並提供 ssr 訊息的 server。 可以透過 products.igs-ip.net/CLK93 取得即時精密星曆訊息。

ntrip 是以基礎的 http basic authentication 登入, 所以用 http 其實蠻危險的,密碼會以明碼傳送, 雖然多數 server 也提供在 https 上的 ntrip, 但目前 str2str 還不支援 https。 所以建議用 wget 或 curl 代理,再交給 str2str。

wget --user-agent 'NTRIP RTKLIB (wget)' --output-document - \
     https://username:password@products.igs-ip.net/CLK93 \
| str2str -out tcpsvr://:5567
curl --user-agent 'NTRIP RTKLIB (curl)' \
     https://username:password@products.igs-ip.net/CLK93 \
| str2str -out tcpsvr://:5567

rtkrcv 執行細節

因為我是 raspberry pi,所以是用命令列版本的 rtkrcv 定位, 就寫設定檔後執行,沒有 gui。

我在執行上因為需要比較 rtklib 和後處理的定位結果, 要把 ublox 的原始數據也存成檔案, 所以是用 str2str 從 serial 讀取, 一邊在 tcp 上送給 rtkrcv,另一邊則存成檔案。 ntrip 也可以比照辦理。

執行腳本

igs ntrip 的帳號密碼則寫在檔案 login 裡, 內容就一行帳號密碼,用冒號隔開, 像 username:password

有個小問題是 rtkexplorer 版本的 rtkrcv, -s 選項似乎不能自動執行。 預設 rtkrcv 是只會開啟一個終端, 可以開在 tcp port、指定的 terminal device 或 shell 所在的 tty 上, 要在終端中輸入 start 命令才會開始定位。 所以我加了個 nc 指令, 用來自動連進去後輸入 start 命令。 tcp console 下面的設定檔裡設密碼, 如果手動設為空就可以不用打密碼; 但不設的話會會用預設密碼 admin

執行後可以在其它 shell telnet localhost 5564 連進 rtkrcv 的介面, 原本的 shell 則會顯示 str2str 的狀況。 如果要結束,就在原本的 shell 按 ctrl-C, 或直接 kill 掉一開始執行時顯示的 pid。

rtkrcv 的終端中,exit 指令是指離開終端, 要結束 rtkrcv 則是要用 shutdown 指令, 或是直接 kill rtkrcv 程序。 但如果執行時不指定 port 或 terminal device, 就會直接把終端開在現在的終端上, 那就會無法 exit,(否則 exit 了就無法再連上終端了。) 要退出只能直接 shutdown。

#!/bin/sh

ntrip_igs_login=`cat login`

# port
port_real_time_ppp_console=5564 # igs ntrip real time ppp console
port_ublox=5566                 # ublox raw observation
port_igs_ssr_rtcm=5567          # igs real time clock orbit

# log=$(date -Is)-run.log
# exec 1>$log 2>&1

echo script pid $$

time_stamp=`date -Is`

str2str -in serial://serial0 \
    -out tcpsvr://:$port_ublox \
    -out file://$PWD/$time_stamp.ubx &
pid_ublox=$!

curl --user-agent 'NTRIP RTKLIB (curl)' \
     https://$ntrip_igs_login@products.igs-ip.net/CLK93 \
| str2str -out tcpsvr://:$port_igs_ssr_rtcm &
pid_ntrip=$!

rtkrcv -o igs-ntrip.conf -p $port_real_time_ppp_console &
pid_ppp=$!

nc -Ct localhost $port_real_time_ppp_console <<CONSOLE
start
exit
CONSOLE

on_exit() {
    echo exiting
    kill $pid_ublox $pid_ntrip $pid_ppp
    mv igs-ntrip.pos $time_stamp.ppp.pos
    mv single-dual-frequency.pos
    trap - EXIT # prevent calling exit again after term int hup
}
trap on_exit EXIT TERM INT HUP

wait

str2str 從 serial 讀取的 bug

碰到一個問題,用 str2str 把 serial 傳到 tcp 再傳到 rtkrcv 後,收到的資料很多是錯的。 原因大概是單一一支 str2str 程序, 如果同時要讀取 serial、寫入檔案、傳送到 tcp,負擔會太大。 雖然儲存的檔案會是正確的,但 tcp 上會缺資料。 我猜是因為 serial baud 設太高,cpu 來不及, 但也不確定 baud 和 str2str 內部的程式有沒有關係, 我太廢 str2str 的原始碼基本看不懂。

解決方法是啟動二支 str2str 程式, 一支只負責讀 serial 送到 stdout, 另一支再負責儲存到檔案和送到 tcp。

str2str -in serial://serial0#ubx \
| str2str -out file://ublox-f9p.ubx::T \
          -out tcpsvr://:5566

只用一支 str2str 同時讀取 serial 並儲存時, 存的 timetag 會變很大,幾乎比原始觀測量還大, 我猜可能是讀取頻率很高,所以要記錄很多次時間戳。 如果用二支 str2str 管道並在第二支 str2str 存, timetag 就比較正常,大小變原始檔的十分之一左右。

選項 logstr 儲存觀測量

原本我是啟動 str2str 和 rtkrcv, 才能同時把資料用來定位也儲存到檔案。 後來發現 rtkrcv 有一個 logstr 選項, 語法就和 str2str 的 -out 一樣, 可以直接把 inpstr 收到資料再轉發出去, 可以直接存成檔案,也可以用 tcp 再傳出去。

但之前用 str2str 讀 serial 同時存檔和 tcp 廣播就很吃力, 如果要用單一支 rtkrcv 做,因為還要定位,可能會更吃力。

之前有一次要在二個站收 network rtk, 本來就直接要了二組 egnss 帳號來連。 後來想到,其實可以只用一個帳號, 然後二個站距離很近,都和同一個 egnss 訊號差分就可以了。 就可以用 logstr 把收到訊號送出去給另一台機器。

network rtk 除了收資料, 還需要把測站所在的大略位置, 用 nmea 格式放在 ntrip 請求的 body 送給伺服器,以內插虛擬觀測量。 (對,就是有 body 的 http get。) 雖然用 str2str -p 選項也可以, 但要先知道大略座標比較麻煩。 如果用 rtkrcv 的話,直接在設定檔裡設 inpstr2-nmeareq=single ant2-postype=rtcm , 就會把 sps (single) 的定位結果用 nmea 傳到伺服器, 並把 rtcm 訊息中的座標當基站座標。

kill 終止 str2str 的問題

如果要終止 str2str,直接用 $! 和 kill 即可; 但如果 str2str 還串了管道和一堆有的沒的, 要一次終止就比較麻煩; 可能只能一次終止整個 process group。 詳細可以參考 下一篇專門談終止子程序的文章

重播時的時間戳來源

之前提過可以重播記錄的檔案,但在重播 rtcm 時有個問題, rtklib 似乎會解析某些資料的時間戳, 有些則不會,會直接拿現在時間。

我碰到的問題是我的 ublox 資料是 P=4 的, 但 rtcm 是 P=8 的,所以不能二個都在設定檔裡讀。 我就把 ublox 和 rtcm 都改用 str2str 播到 tcp, 然後在 rtkrcv 裡從 tcp 讀。 結果 tcp 讀進來的 ublox 時間是觀測時間, 但 rtcm 讀進來的則變成現在,造成二個不同步。 可能因為 ublox 帶時間戳,而 rtcm 沒有; 或是 rtkrcv 直接假定從 tcp 讀 rtcm 是即時。

總之這個麻煩的問題,我後來是分開讀取來源。 rtcm 直接用 file://ublox-f9p.ubx::T 從檔案讀,就會帶正確的時間戳了; ublox 則用另一支 str2str 串到 tcp 讀, 觀測量自帶時間戳所以沒問題。 只是這樣要算時差,手動在 str2str 加上去; 而且要用命令一次執行,不能一行一行打,時差會跑掉。

str2str -in file://ublox-f9p.ubx::T::+3600::x300 \
        -out tcpsvr://:5567 1>/dev/null 2>&1 &
rtkrcv -o post.conf -s

rtkrcv 自動開始只在終端機連結時啟動

rtkrcv 預設 rtkrcv 只會開啟終端介面, 要在介面裡下 start 命令才會開始讀取資料定位。 所以有設計一個 -s 選項,帶選項的話相當於自動輸入 start 命令。

問題是 s 選項的行為是在開啟終端時會自動執行 start, 如果結合另一個 -p 選項把終端開在 tcp 上, 就不會開啟預設開在 shell tty 上的終端了, 也就要等到有人用 telnet 連到 tcp 上的終端時, 才會 自動開始 定位。

於是就有人在 github issue 上報了這個 自動啟動選項 並不是真的自動啟動的詭異 issue 。 然後建議也五花八門,什麼在腳本內用 python 連進去後送出 start 命令; 我則是直接改原始碼,強制用 stdio 開一個假終端, 在假終端中執行 start 命令。 然後也有人給出另一個比較簡單的解法, 用 -d 選項指定一個終端,這樣就能自動開啟了; 如果沒有終端裝置能指定,指定在 /dev/null 也能自動執行。

設定檔

rtkexplorer 的文章 裡改來的。

# RTKNAVI options (2020/02/09 rtkexplorer/rtklib demo5 gholk)
pos1-posmode       =ppp-static # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed)
pos1-frequency     =l1+l2      # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l5)
pos1-soltype       =forward    # (0:forward,1:backward,2:combined)
pos1-elmask        =15         # (deg)
pos1-snrmask_r     =off        # (0:off,1:on)
pos1-snrmask_b     =off        # (0:off,1:on)
pos1-snrmask_L1    =0,0,0,0,0,0,0,0,0
pos1-snrmask_L2    =0,0,0,0,0,0,0,0,0
pos1-snrmask_L5    =0,0,0,0,0,0,0,0,0
pos1-dynamics      =off        # (0:off,1:on)
pos1-tidecorr      =off        # (0:off,1:on,2:otl)

## important ############################################
pos1-ionoopt       =dual-freq  # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec)
pos1-tropopt       =est-ztd    # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd)
pos1-sateph        =brdc+ssrapc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)

pos1-posopt1       =off        # (0:off,1:on)
pos1-posopt2       =off        # (0:off,1:on)
pos1-posopt3       =off        # (0:off,1:on,2:precise)
pos1-posopt4       =off        # (0:off,1:on)
pos1-posopt5       =off        # (0:off,1:on)
pos1-posopt6       =off        # (0:off,1:on)
pos1-exclsats      =           # (prn ...)
pos1-navsys        =1          # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp)
pos2-armode        =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
pos2-gloarmode     =off        # (0:off,1:on,2:autocal)
pos2-bdsarmode     =off        # (0:off,1:on)
pos2-arthres       =3
pos2-arthres1      =0.9999
pos2-arthres2      =0.25
pos2-arthres3      =0.1
pos2-arthres4      =0.05
pos2-arlockcnt     =0
pos2-arelmask      =0          # (deg)
pos2-arminfix      =10
pos2-armaxiter     =1
pos2-elmaskhold    =0          # (deg)
pos2-aroutcnt      =5
pos2-maxage        =30         # (s)
pos2-syncsol       =off        # (0:off,1:on)
pos2-slipthres     =0.05       # (m)
pos2-rejionno      =30         # (m)
pos2-rejgdop       =30
pos2-niter         =1
pos2-baselen       =0          # (m)
pos2-basesig       =0          # (m)
out-solformat      =llh        # (0:llh,1:xyz,2:enu,3:nmea)
out-outhead        =off        # (0:off,1:on)
out-outopt         =off        # (0:off,1:on)
out-outvel         =off        # (0:off,1:on)
out-timesys        =gpst       # (0:gpst,1:utc,2:jst)
out-timeform       =hms        # (0:tow,1:hms)
out-timendec       =3
out-degform        =deg        # (0:deg,1:dms)
out-fieldsep       =
out-outsingle      =off        # (0:off,1:on)
out-maxsolstd      =0          # (m)
out-height         =ellipsoidal # (0:ellipsoidal,1:geodetic)
out-geoid          =internal   # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
out-solstatic      =all        # (0:all,1:single)
out-nmeaintv1      =0          # (s)
out-nmeaintv2      =0          # (s)
out-outstat        =off        # (0:off,1:state,2:residual)
stats-eratio1      =100
stats-eratio2      =100
stats-errphase     =0.003      # (m)
stats-errphaseel   =0.003      # (m)
stats-errphasebl   =0          # (m/10km)
stats-errdoppler   =1          # (Hz)
stats-stdbias      =30         # (m)
stats-stdiono      =0.03       # (m)
stats-stdtrop      =0.3        # (m)
stats-prnaccelh    =10         # (m/s^2)
stats-prnaccelv    =10         # (m/s^2)
stats-prnbias      =0.0001     # (m)
stats-prniono      =0.001      # (m)
stats-prntrop      =0.0001     # (m)
stats-prnpos       =0          # (m)
stats-clkstab      =5e-12      # (s/s)
ant1-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant1-pos1          =90         # (deg|m)
ant1-pos2          =0          # (deg|m)
ant1-pos3          =-6335367.62849036 # (m|m)
ant1-anttype       =
ant1-antdele       =0          # (m)
ant1-antdeln       =0          # (m)
ant1-antdelu       =0          # (m)
ant2-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant2-pos1          =90         # (deg|m)
ant2-pos2          =0          # (deg|m)
ant2-pos3          =-6335367.62849036 # (m|m)
ant2-anttype       =
ant2-antdele       =0          # (m)
ant2-antdeln       =0          # (m)
ant2-antdelu       =0          # (m)
ant2-maxaveep      =3600
ant2-initrst       =on         # (0:off,1:on)
misc-timeinterp    =off        # (0:off,1:on)
misc-sbasatsel     =0          # (0:all)
misc-rnxopt1       =
misc-rnxopt2       =
misc-pppopt        =

## important ############################################
file-satantfile    =igs08.atx
file-rcvantfile    =igs08.atx
file-staposfile    =
file-geoidfile     =
file-ionofile      =
file-dcbfile       =
file-eopfile       =
file-blqfile       =

## important ############################################
# set empty password
console-passwd     =
file-tempdir       =/tmp
file-geexefile     =
file-solstatfile   =
file-tracefile     =

## important ############################################
inpstr1-type       =tcpcli     # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr2-type       =tcpcli     # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr1-path       =localhost:5566
inpstr2-path       =localhost:5567
inpstr3-path       =
inpstr1-format     =ubx        # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr2-format     =rtcm3      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr3-format     =rtcm2      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr2-nmeareq    =off        # (0:off,1:latlon,2:single)
inpstr2-nmealat    =0          # (deg)
inpstr2-nmealon    =0          # (deg)
outstr1-type       =file       # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
outstr2-type       =off #tcpsvr     # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)

## important ############################################
outstr1-path       =igs-ntrip.pos
outstr2-path       =
outstr1-format     =llh        # (0:llh,1:xyz,2:enu,3:nmea)
outstr2-format     =llh        # (0:llh,1:xyz,2:enu,3:nmea)
logstr1-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr1-path       =
logstr2-path       =
logstr3-path       =
misc-svrcycle      =10         # (ms)
misc-timeout       =10000      # (ms)
misc-reconnect     =10000      # (ms)
misc-nmeacycle     =5000       # (ms)
misc-buffsize      =32768      # (bytes)
misc-navmsgsel     =all        # (0:all,1:rover,2:base,3:corr)
misc-proxyaddr     =
misc-fswapmargin   =30         # (s)