<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>hans mayer&apos;s weblog</title>
    <description>here you can find this and that - probably most related to UNIX/Linux and network</description>
    <link>https://blog.mayer.tv/</link>
    <atom:link href="https://blog.mayer.tv/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Tue, 01 Sep 2026 22:46:32 +0200</pubDate>
    <lastBuildDate>Tue, 01 Sep 2026 22:46:32 +0200</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Update ZED-X20P with Debian on piHAT</title>
        <description>&lt;p&gt;Here I want to show you how to update a ZED-X20P without u-center2. This scenario is typically used if the X20P is mounted on a piHAT sitting on a Raspberry Pi running Linux like Debian. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;In my case, I’m use the pHAT from sparkfun. It is mounted on a Raspberry Pi5 with Debian 13 trixie. And of course there is no easy way to run u-center2 directly. I found information to connect the Linux box and the Windows box with “ser2net” on Debian and HW VSP (Virtual Serial Port) on Windows part. But this didn’t work for me.&lt;/p&gt;

&lt;p&gt;Luckily, I found a thread at &lt;a href=&quot;https://portal.u-blox.com/&quot; target=&quot;_blank&quot;&gt;https://portal.u-blox.com/&lt;/a&gt; where someone posted a binary file “ubxfwupdate” which runs perfect on 64-bit ARM platform.&lt;/p&gt;

&lt;p&gt;So I had to download the latest image which is available from the official U-blox website: UBX_20_HPG_210_ZED_X20P-01B.512369040097ce18fd3475e71e7c627f.bin&lt;/p&gt;

&lt;p&gt;Normally I run “gpsd” from the gpsd package. It’s important to stop this as we need the serial interface for the update.&lt;/p&gt;

&lt;pre&gt;
systemctl stop gpsd.service 
systemctl stop gpsd.socket 
&lt;/pre&gt;

&lt;p&gt;The next step is also important. Set the baud rate for UART1 to the same value as the first parameter of the “-b” option. In my case it is 460800 bd. Since I also have the &lt;a href=&quot;/2026/03/09/second-interface-for-u-blox-receiver-on-pi4-and-pi5.html&quot; target=&quot;_blank&quot;&gt;second interface&lt;/a&gt; available I could do this easily over the second interface for UART1.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubxtool3 -z CFG-UART1-BAUDRATE,460800&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now check the communication between X20P and tty of the Raspberry.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/ubxtool -f /dev/ttyAMA0 -s 460800 -p MON-VER&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should show the current (old) version.&lt;/p&gt;

&lt;p&gt;Now comes the magic moment. Run the update:&lt;/p&gt;

&lt;pre&gt;ubxfwupdate -p /dev/ttyAMA0  -v 1 --no-fis 1 -C 1 -s 1 -b 460800:9600:460800 UBX_20_HPG_210_ZED_X20P-01B.512369040097ce18fd3475e71e7c627f.bin&lt;/pre&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;----------CMD line arguments-----------
Image file:        UBX_20_HPG_210_ZED_X20P-01B.512369040097ce18fd3475e71e7c627f.bin
Flash:             &amp;lt;compiled-in&amp;gt;
Fis:               flash.xml
Port:              /dev/ttyAMA0
Baudrates:         460800/9600/460800
Safeboot:          1
Reset:             1
AutoBaud:          0
Verbose:           1
Erase all:         1
Erase only:        0
Training sequence: 1
Chip erase:        1
Merging FIS:       1
Update RAM:        0
Use USB alt:       0
---------------------------------------
  0.0 u-blox Firmware Update Tool version 24.11
  0.0 Updating Firmware &apos;UBX_20_HPG_210_ZED_X20P-01B.512369040097ce18fd3475e71e7c627f.bin&apos; of receiver over &apos;/dev/ttyAMA0&apos;
  0.0   - Opening and buffering image file
  0.0   - Verifying image
  0.0   - Got an encrypted image with footer info
  0.0   - CRC Value         	:    BC410967
  0.0   - Footer Version    	:    1
  0.0   - Number of Images  	:    2
  0.0   - Footer Size       	:    28
  0.0   - Image Config Size 	:    40
  0.0   - Image 0 Size     	:    716648
  0.0   - Image 1 Size     	:    444856
  0.0   - Trying to open port /dev/ttyAMA0
  0.0   - Setting baudrate to 460800
  0.2   - Received Version information
  0.2   - Receiver currently running SW &apos;EXT HPG 2.02 (43e74c)&apos;
  0.2   - Receiver HW &apos;000B0000&apos;, Generation 20.0
  0.2   - Sending ROM CRC Poll
  0.2 ROM CRC: 0x00A9D329
  0.2 u-blox20 ROM1.10 hardware detected (0x00A9D329)
  0.2  Getting Port connection to receiver
  1.6   - Connected port is: UART1
  1.6  Commanding Safeboot
  5.1   - Setting baudrate to 9600
  5.3   - Sending training sequence
  5.5  Detecting Flash manufacturer and device IDs
  5.5   - Flash ManId: 0x009D DevId: 0x6016
  5.7   - Not merging anything
  5.7   - Flash size:   4194304
  5.7   -  Flash block:  1024 x 4096
  5.7 Stable clock enabled successfully
  5.8   - Setting baudrate to 460800
  6.0  Start Flash retention
  6.0   - flash retention success
  6.0 Chip erase started
  6.0  Receiver info collected, downloading to flash...
 11.5 Chip erase complete
 37.0 FW download complete
 37.0  Verifying Image on hardware
 39.4  Firmware Verification and Flash update complete
 39.4  Verify Flash retention
 39.4  flash retention success
 39.4  Rebooting receiver
 39.4 Firmware Update SUCCESS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you check the MON_VER again, you should see:&lt;/p&gt;

&lt;pre&gt;
UBX-MON-VER:
  swVersion EXT HPG 2.10 (b0eda3)
  hwVersion 000B0000
  extension ROM BASE 0x00A9D329
  extension FWVER=HPG 2.10
  extension PROTVER=50.11
  extension MOD=ZED-X20P
  extension GPS;GLO;GAL;BDS
  extension SBAS;QZSS
  extension NAVIC;LBAND
&lt;/pre&gt;

&lt;p&gt;And what you can see here GLONASS is also available, at least in my geographic region.&lt;/p&gt;

&lt;p&gt;My &lt;a href=&quot;/2026/03/09/u-blox_ZED-X20P.html&quot; target=&quot;_blank&quot;&gt;ZED-X20P&lt;/a&gt; from sparkfun in action.&lt;/p&gt;

</description>
        <pubDate>Thu, 23 Jul 2026 13:32:00 +0200</pubDate>
        <link>https://blog.mayer.tv/2026/07/23/Update-ZED-X20P-with-Debian-on-piHAT.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/07/23/Update-ZED-X20P-with-Debian-on-piHAT.html</guid>
        
        
        <category>u-blox</category>
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>u-blox ZED-X20P initialization and GPSD</title>
        <description>&lt;p&gt;I use the gpsd tool set since a while. In Debian it is available as package or you can find it here: &lt;a href=&quot;https://gitlab.com/gpsd/gpsd&quot; target=&quot;_blank&quot;&gt;gpsd&lt;/a&gt; &lt;br /&gt; Several programs from the gpsd tool set worked as expected when I use it with a ZED-F9P. Not so with the newer ZED-X20P. The reason is simple. When starting the gpsd process it initialize the F9P and others u-blox devices with several messages, but not so with the X20P. The X20P stays in the factory default setup. 
&lt;br /&gt;So I saw that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpscsv -n 1 -c SAT&lt;/code&gt; didn’t work. With help of several resources I could initialize the X20P in way so that gpscsv is working. These are the parameters&lt;/p&gt;

&lt;pre&gt;
  ubxtool -z CFG-MSGOUT-UBX_NAV_PVT_UART1,1 
  ubxtool -z CFG-MSGOUT-UBX_NAV_SAT_UART1,1 
  ubxtool -z CFG-MSGOUT-UBX_NAV_SIG_UART1,1 
  ubxtool -z CFG-UART1OUTPROT-NMEA,0 
  ubxtool -z CFG-UART1OUTPROT-UBX,1 
  ubxtool -z CFG-MSGOUT-UBX_NAV_TIMEGPS_UART1,1 
&lt;/pre&gt;

&lt;p&gt;Of course I cannot say if these are all parameters which are set for F9P and others but at least for my gpscsv issue with ZED-X20P is it working. Currently I am using gpsd version 3.27.6. Maybe in later releases it will work.&lt;/p&gt;

&lt;p&gt;See also: &lt;a href=&quot;/2026/03/09/u-blox_ZED-X20P.html&quot; target=&quot;_blank&quot;&gt;ZED-X20P&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 31 May 2026 17:56:00 +0200</pubDate>
        <link>https://blog.mayer.tv/2026/05/31/u-blox-ZED-X20P-initialization-and-GPSD.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/05/31/u-blox-ZED-X20P-initialization-and-GPSD.html</guid>
        
        
        <category>u-blox</category>
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>The Austrian Cloud</title>
        <description>&lt;p&gt;Tap on the image to see details.&lt;/p&gt;

&lt;div class=&quot;image-switcher&quot;&gt;
  &lt;input type=&quot;checkbox&quot; id=&quot;cloud-switch&quot; class=&quot;switch-input&quot; /&gt;
  &lt;label for=&quot;cloud-switch&quot; class=&quot;switch-label&quot;&gt;
    &lt;img src=&quot;/images/austriacloud2026.png&quot; class=&quot;img-gif&quot; alt=&quot;Austria Cloud 2026&quot; /&gt;
    &lt;img src=&quot;/images/viennacloud2026.jpg&quot; class=&quot;img-static&quot; alt=&quot;Vienna Cloud 2026&quot; /&gt;
  &lt;/label&gt;
&lt;/div&gt;

&lt;style&gt;
/* Versteckt die eigentliche Checkbox */
.image-switcher .switch-input {
  display: none;
}

/* Container-Styling */
.image-switcher .switch-label {
  position: relative;
  display: inline-block;
  cursor: pointer;
  max-width: 100%;
}

/* Grundeinstellungen für beide Bilder */
.image-switcher img {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Das Zielbild (Vienna) wird exakt über das Startbild gelegt und unsichtbar gemacht */
.image-switcher .img-static {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  transition: opacity 2s ease-in-out; /* Hier sind die gewünschten 2 Sekunden eingestellt */
}

/* Das Startbild (Austria) bekommt ebenfalls die 2-Sekunden-Transition */
.image-switcher .img-gif {
  transition: opacity 2s ease-in-out;
}

/* Wenn geklickt wurde: Austria blendet aus, Vienna blendet ein */
.image-switcher .switch-input:checked ~ .switch-label .img-gif {
  opacity: 0;
}

.image-switcher .switch-input:checked ~ .switch-label .img-static {
  opacity: 1;
}
&lt;/style&gt;

&lt;p&gt;Aufgenommen in der Friedensstraße,  Wien Mauer &lt;br /&gt;
Im Zentrum unten die Sternbauten von Atzgersdorf, rechts die Tilgnergasse
&lt;br /&gt; 
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kreuzundquer2026.jpg&quot; alt=&quot;kreuz und quer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“Kreuz und Quer” Nicht alle Bilder sind mit KI manipuliert. &lt;br /&gt;
Aufgenommen in der Taglieberstraße&lt;/p&gt;

</description>
        <pubDate>Thu, 28 May 2026 14:32:00 +0200</pubDate>
        <link>https://blog.mayer.tv/2026/05/28/the-austrian-cloud.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/05/28/the-austrian-cloud.html</guid>
        
        
        <category>fake</category>
        
      </item>
    
      <item>
        <title>RTK - base/rover with U-blox GNSS receivers</title>
        <description>&lt;p&gt;After some tests with Precise Point Positioning ( see below 1-5 ) and in detailed with (4) I describe this time a setup with a base station sending RTCM (Radio Technical Commission for Maritime Services) data to a rover station. For both ( base and rover ) I use Raspberry Pi’s with a GNSS pi-hat with the latest Debian OS trixie Version 13 and the latest Version of &lt;a href=&quot;https://gitlab.com/gpsd/gpsd&quot; target=&quot;_blank&quot;&gt;https://gitlab.com/gpsd/gpsd&lt;/a&gt;. I also use &lt;a href=&quot;https://github.com/rtklibexplorer/RTKLIB&quot; target=&quot;_blank&quot;&gt;github.com/rtklibexplorer/RTKLIB&lt;/a&gt; written by Jens Reimann. It’s not necessary to have this tool on these servers. Most most of the time, I run it from a third server, using ‘ubxtool’ to interact with the gpsd instances remotely.&lt;/p&gt;

&lt;p&gt;Base station is a Raspberry Pi5 with a &lt;a href=&quot;/2026/03/09/u-blox_ZED-X20P.html&quot; target=&quot;_blank&quot;&gt;ZED-X20P&lt;/a&gt; from U-blox. The pi-hat is from sparkfun. &lt;br /&gt;
Rover is a Raspberry Pi4 with a &lt;a href=&quot;/2022/07/29/ublox-ZED-F9P.html&quot; target=&quot;_blank&quot;&gt;ZED-F9P&lt;/a&gt; from U-blox. The pi-hat is from uputronics. &lt;br /&gt;
OS is in both cases Debian 13 (trixie)&lt;/p&gt;

&lt;p&gt;Antennas &lt;br /&gt;
For X20P I use the antenna HAB-ANN-MB2 permanently roof-mounted with a clear sky view. &lt;br /&gt;
F9P uses the HAB-ANN-MB-00-00 antenna, which is moved mobile in the garden. To place it on a metal plate is an advantage.&lt;/p&gt;

&lt;p&gt;In both cases I use the second interface UART2 to communicate between base and rover for the RTCM traffic. How to setup I described in &lt;a href=&quot;/2026/03/09/second-interface-for-u-blox-receiver-on-pi4-and-pi5.html&quot; target=&quot;_blank&quot;&gt;second interface for u-blox receiver&lt;/a&gt; &lt;br /&gt;
I use str2str for communication between both systems. It is started in background with option “–deamon”, see below. &lt;br /&gt;
Note: In RTKLIB’s str2str, the parameter is literally spelled –deamon instead of –daemon. &lt;br /&gt; The data path for RTCM traffic looks like this: &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X20P/UART2 --- str2str --- TCP/IP --- str2str --- UART2/F9P&lt;/code&gt; &lt;br /&gt;
Bandwidth is about 12 Kb from base to rover and 1.5 Kb from rover to base&lt;/p&gt;

&lt;p&gt;In advance I want to say that this combination with ZED-X20P and ZED-F9P is not perfect but possible. The reasons are multiple: ZED-F9P can handle only the L1 and L2 band. ZED-X20P is designed for L1/L2/L5/E6/B3/L. Another reason is that ZED-X20P cannot handle GLONASS (Globalnaja nawigazionnaja sputnikowaja sistema) at the moment (and potentially never due to hardware/firmware focus or political situations). And the Navigation Indian Constellation (NavIC) can only be used by ZED-X20P. Independent of that I don’t see any Indian satellite here in Vienna ( 48N 16E ). Therefore, only 3 GNSS constellations remain: GPS, Galileo and BeiDou as lowest common denominator and common source.&lt;/p&gt;

&lt;p&gt;Below you can find 2 scripts: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_base_sh&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_rover_sh&lt;/code&gt;. The first one is to setup the base station which is a little bit more complex. The second one is for the rover. These scripts require certain prerequisites. For example there are servers with hostname “base” and “rover” or at least an DNS CNAME for it. SSH should be possible without password.&lt;/p&gt;

&lt;p&gt;functubxtool_ksh defines a function “ubxtool” like this&lt;/p&gt;

&lt;pre&gt;
    export UBXOPTS=&apos;-P 27.50&apos;
    /usr/local/bin/ubxtool $@ rover:gpsd:/dev/serial0 
&lt;/pre&gt;

&lt;p&gt;This is to avoid to add each time “rover:gpsd:/dev/serial0” as additional argument&lt;/p&gt;

&lt;h2 id=&quot;setup_base_sh&quot;&gt;setup_base_sh&lt;/h2&gt;

&lt;pre&gt;
#!/usr/bin/env bash 

# ident setup_base_sh 
# Wed May  6 05:26:22 PM CEST 2026 - mayer 

. functubxtool_ksh base

ntrip(){

  logger -p user.debug &quot;setup_base_sh ntrip with argument $1  &quot; 
  
  case &quot;$1&quot; in 
    stop ) 
        # kill a possible running str2str 
        ssh base pkill str2str 
        ;; 
    start ) 
        # start a new one - this is the communication to the rover for RTCM traffic 
        ssh base &quot;str2str -in serial://ttyAMA3:921600:8:n:1:off -out tcpsvr://:42101 --deamon&quot;
        ;;
    status ) 
        ssh base &apos;pgrep -a -f &quot;str2str -in serial://ttyAMA3:921600:8:n:1:off -out tcpsvr://:42101 --deamon&quot;&apos; 
        ;;
    &quot;&quot; ) 
        ntrip stop ; ntrip start 
        ;;
  esac 
}


setup_initial(){ 

  # Setup Script for u-blox (ZED-X20P) base station 
  logger -p user.debug &quot;setup_base_sh setup_initial &quot; 
  # this is the initial setup to prepare the base station for it&apos;s function 
  
  # make sure in advance that baudrate for uart1 is high enough 
  if test -z &quot;`ubxtool -g  CFG-UART1-BAUDRATE | grep UART1-BAUDRATE | head -1 | grep 921600`&quot; 
    then 
      echo $0: UART1-BAUDRATE,921600 failed 
      exit 1 
  fi 
  
  ubxtool -z  CFG-UART2-BAUDRATE,921600 | grep UBX-ACK-ACK: 
  
  if test $? -ne 0 
    then 
      echo $0: UART2-BAUDRATE,921600 failed 
      exit 1 
  fi 

  # make sure that no Survey-In is running 
  ubxtool -z CFG-TMODE-MODE,0 | grep UBX-ACK-ACK:
  
  # reference coordinates set to ECEF
  ubxtool -z CFG-TMODE-POS_TYPE,0 | grep UBX-ACK-ACK:
  
  # position of the base station , unit is cm 
  # 48.1493013022 16.2838442507 288.08 
  # make sure that there is the exact position of the base station 
  ubxtool -z CFG-TMODE-ECEF_X,409252331 | grep UBX-ACK-ACK:
  ubxtool -z CFG-TMODE-ECEF_Y,119548502 | grep UBX-ACK-ACK:
  ubxtool -z CFG-TMODE-ECEF_Z,472818312 | grep UBX-ACK-ACK:
  
  # set  High-Precision Register to zero 
  ubxtool -z CFG-TMODE-ECEF_X_HP,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-TMODE-ECEF_Y_HP,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-TMODE-ECEF_Z_HP,0 | grep UBX-ACK-ACK:
  
  # RTCM data (1 Hz Intervall )
  # activate RTCM3 output on UART2 (Port 2) , communication with str2str 
  # 1005: Station ID &amp;amp; Position, 
  # 1077: GPS MSM7 
  # 1097: Galileo GAL MSM7 
  # 1124: BeiDou BDS MSM4 included in 1127 
  # 1127: BeiDou BDS MSM7 
  for MSG in 1005 1077 1097 1127 # 1124 
    do
      ubxtool -z CFG-MSGOUT-RTCM_3X_TYPE${MSG}_UART2,1  | grep UBX-ACK-ACK:
    done

  # to check what the rover sees
  # rover# ubxtool -w 30 | grep -A 1 &quot;UBX-RXM-RTCM&quot; | sort -u 
  
  # FIXED MODE schalten
  ubxtool -z CFG-TMODE-MODE,2 | grep UBX-ACK-ACK:

  # necessary as the rover (ZED-F9P) can only bands L1 and L2 
  ubxtool -z CFG-SIGNAL-PLAN,1 | grep UBX-ACK-ACK:
    
  ubxtool -z CFG-SIGNAL-GPS_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-SBAS_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GAL_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-QZSS_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GLO_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-NAVIC_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_B2A_ENA,0 | grep UBX-ACK-ACK:
  
  ubxtool -z CFG-SIGNAL-GPS_L1CA_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GPS_L2C_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GPS_L5_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-SBAS_L1CA_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GAL_E1_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GAL_E5A_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GAL_E5B_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GAL_E6_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_B1_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_B2_ENA,1 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_B1C_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-BDS_B3_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-QZSS_L1CA_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-QZSS_L1S_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-QZSS_L2C_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-QZSS_L5_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GLO_L1_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-GLO_L2_ENA,0 | grep UBX-ACK-ACK:
  ubxtool -z CFG-SIGNAL-NAVIC_L5_ENA,0 | grep UBX-ACK-ACK:

  ntrip 

}  
  
help(){
  echo &quot;usage: $0 help | setup_initial | ntrip &quot; 
  echo &quot;          help  ...  this help &quot;
  echo &quot;          setup_initial ... this will initialise the base station &quot; 
  echo &apos;          ntrip start | stop | status | &quot;&quot; &apos;
  echo &quot;                to manage the communication with the base station with a str2str process &quot;
  echo &quot;                without argument it will restart the str2str process &quot; 
  exit 1 
}

usage(){ 
  echo &quot;usage: $0 help | setup_initial | ntrip &quot; 
  exit 1 
} 


case &quot;$1&quot; in 
  setup_initial ) setup_initial ;; 
  ntrip ) ntrip $2 ;; 
  help ) help ;; 
  * ) usage ;; 
esac 

&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Some hints on the base station setup. The unit of measurement for ECEF mode is centimeters. Note that most tools like mine &lt;a href=&quot;https://github.com/hans-mayer/transform_ecef_wgs84&quot; target=&quot;_blank&quot;&gt;transform ecef wgs84&lt;/a&gt; use meters instead. Another important setup is to disable CFG-SIGNAL-BDS_B1C_ENA and CFG-SIGNAL-BDS_B3_ENA. As long as these signals were enabled, I was unable to achieve BeiDou-based RTCM corrections.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;setup_rover_sh&quot;&gt;setup_rover_sh&lt;/h2&gt;

&lt;pre&gt;
#!/usr/bin/env bash 

# ident setup_rover_sh 
# Wed May  6 05:26:22 PM CEST 2026 - mayer 

. functubxtool_ksh rover


ntrip(){

  logger -p user.debug &quot;setup_rover_sh ntrip with argument $1  &quot; 
  case &quot;$1&quot; in 
    stop ) 
  	# kill a possible running str2str 
  	# ssh rover pkill str2str 
	ssh rover &apos;pkill -f &quot;str2str -in tcpcli://base:42101 -out serial://ttyAMA5:921600:8:n:1:off --deamon&quot;&apos;
	;; 
    start ) 
  	# start a new one - this is the communication to the base for RTCM traffic 
  	ssh rover &quot;str2str -in tcpcli://base:42101 -out serial://ttyAMA5:921600:8:n:1:off --deamon&quot;
	;;
    status ) 
	ssh rover &apos;pgrep -a -f &quot;str2str -in tcpcli://base:42101 -out serial://ttyAMA5:921600:8:n:1:off --deamon&quot;&apos;
	;;
    &quot;&quot; ) 
	ntrip stop ; ntrip start 
	;;
  esac 
}

setup_initial(){ 
  
  logger -p user.debug &quot;setup_rover_sh setup_initial &quot; 
  # this is the initial setup to prepare the rover sation for it function 

  # make sure in advance that baudrate for uart1 is high enough 
  if test -z &quot;`ubxtool -g  CFG-UART1-BAUDRATE | grep UART1-BAUDRATE | head -1 | grep 921600`&quot; 
    then 
      echo $0: UART1-BAUDRATE,921600 failed 
      exit 1 
  fi 
  
  ubxtool -z  CFG-UART2-BAUDRATE,921600 | grep UBX-ACK-ACK: 
  
  if test $? -ne 0 
    then 
      echo $0: UART2-BAUDRATE,921600 failed 
      exit 1 
  fi 
  
  # is set per default layer 7 
  ubxtool -z CFG-UART2INPROT-RTCM3X,1  | grep UBX-ACK-ACK: 
  
  # disable not usable GNSS 
  ubxtool -z  CFG-SIGNAL-SBAS_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-QZSS_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-GLO_ENA,0 | grep UBX-ACK-ACK: 
  
  ubxtool -z  CFG-SIGNAL-SBAS_L1CA_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-QZSS_L1CA_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-QZSS_L1S_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-QZSS_L2C_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-GLO_L1_ENA,0 | grep UBX-ACK-ACK: 
  ubxtool -z  CFG-SIGNAL-GLO_L2_ENA,0 | grep UBX-ACK-ACK: 

  ntrip 
  
  ubxtool -z CFG-MSGOUT-UBX_RXM_RTCM_UART1,1 | grep UBX-ACK-ACK:
  
  # set high precision mode 
  # The accuracy is only as good as that of the base station. 
  ubxtool -z CFG-NMEA-HIGHPREC,1 | grep UBX-ACK-ACK: 
  ubxtool -z CFG-MSGOUT-UBX_NAV_HPPOSLLH_UART1,1 | grep UBX-ACK-ACK: 

  # don&apos;t restart gpsd after initialization 
  # this is one of the parameters changed at start or use option -p --passive for gpsd restart 
  ubxtool -z CFG-MSGOUT-NMEA_ID_GGA_UART1,1  | grep UBX-ACK-ACK:  

}

nmea_pipe(){
  	
  logger -p user.debug &quot;setup_rover_sh nmea_pipe with argument $1  &quot; 
  # this pipe is for monitoring with rtkplot_q 

  case &quot;$1&quot; in 
    stop ) 
  	# kill a possible running gpspipe 
  	ssh rover &quot;pkill -f &apos;socat EXEC:gpspipe -r TCP-LISTEN:10001,reuseaddr,fork&apos;&quot;
	;; 
    start )  
  	# start a gpspipe for monitoring with rtkplot_qt / option -r is NMEA output 
  	ssh rover nohup &quot;socat EXEC:&apos;gpspipe -r&apos; TCP-LISTEN:10001,reuseaddr,fork  &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp; disown &quot; 
	echo pipe ready for rtkplot_qt as TCP Client , server rover at port 10001 and solution format NMEA0183 
 	;;
    status )  
	ssh rover &apos;pgrep -a -f &quot;socat EXEC:gpspipe -r TCP-LISTEN:10001,reuseaddr,fork&quot;&apos;
 	;;
    &quot;&quot; ) 
	nmea_pipe stop ; nmea_pipe start 
 	;;
  esac  
}

raw_pipe(){

  logger -p user.debug &quot;setup_rover_sh raw_pipe  with argument $1  &quot; 

  case &quot;$1&quot; in 
    stop ) 
  	# kill a possible running gpspipe
  	ssh rover &quot;pkill -f &apos;socat EXEC:gpspipe -RB TCP-LISTEN:10002,reuseaddr,fork&apos;&quot;
	;;
    start ) 
  	# start a gpspipe for logging with strsvr_qt or str2str 
  	ssh rover nohup &quot;socat EXEC:&apos;gpspipe -RB&apos; TCP-LISTEN:10002,reuseaddr,fork  &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp; disown &quot; 
  	echo for example its possible to start now: str2str -in tcpcli://rover:10002 -out file://log_%Y%m%d%h%M.ubx
	;;
    status ) 
  	ssh rover &quot;pgrep -a -f &apos;socat EXEC:gpspipe -RB TCP-LISTEN:10002,reuseaddr,fork&apos;&quot;
	;;
    &quot;&quot; )
	raw_pipe stop ; raw_pipe start 
	;;
  esac 
}


navpvt(){
  logger -p user.debug &quot;setup_rover_sh navpvt &quot; 
  ubxtool -p NAV-PVT -v 2 | sed -n -e &apos;/^UBX-NAV-PVT:/,/^$/ p&apos; | awk -v RS= &apos;NR==2&apos; 
}


sat_used(){

  logger -p user.debug &quot;setup_rover_sh sat_used &quot; 

  # NAVSAT=`ubxtool -p NAV-SAT -v 2 | sed -n -e &apos;/^UBX-NAV-SAT:/,/^$/ p&apos; | awk -v RS= &apos;NR==2&apos;  | grep -B 2 -A 2  -i rtcm | egrep &apos;flags&apos;`

  echo only GPS, Galileo and BeiDou are counted 
  echo -e -n Status: ; navpvt | grep carrSoln
  NAVSAT=`ubxtool -p NAV-SAT -v 2 | sed -n -e &apos;/^UBX-NAV-SAT:/,/^$/ p&apos; | awk -v RS= &apos;NR==2&apos; ` 

  echo &quot;                    satellites total seen : &quot; `echo &quot;$NAVSAT&quot; | grep -c gnssId `

  SYST=`echo &quot;$NAVSAT&quot; | grep gnssId  | awk &apos;{ print ( $2 ) }&apos; | sort | uniq -c`
  echo $SYST | awk &apos;{ print ( &quot;                                      GPS :  &quot;  $1 &quot;  Galileo: &quot; $3  &quot;  BeiDou: &quot; $5 ) }&apos; 

  echo &quot;                          satellites used : &quot; `echo &quot;$NAVSAT&quot; | grep &apos;flags(&apos; | grep -c svUsed `

  SYST=`echo &quot;$NAVSAT&quot; | grep  -B 2 svUsed | grep gnssId  | awk &apos;{ print ( $2 ) }&apos; | sort | uniq -c`
  echo $SYST | awk &apos;{ print ( &quot;                                      GPS :  &quot;  $1 &quot;  Galileo: &quot; $3  &quot;  BeiDou: &quot; $5 ) }&apos; 

  echo &quot;     satellites used with RTCM correction : &quot; `echo &quot;$NAVSAT&quot; | grep -c rtcm `
  echo &quot;  satellites with pseudorange corrections : &quot; `echo &quot;$NAVSAT&quot; | grep -c prCorrUsed `

  echo &quot;satellites with carrier range corrections : &quot; `echo &quot;$NAVSAT&quot; | grep -c crCorrUsed `
  SYST=`echo &quot;$NAVSAT&quot; | grep  -B 2 crCorrUsed | grep gnssId  | awk &apos;{ print ( $2 ) }&apos; | sort | uniq -c`
  echo $SYST | awk &apos;{ print ( &quot;                                      GPS :  &quot;  $1 &quot;  Galileo: &quot; $3  &quot;  BeiDou: &quot; $5 ) }&apos; 
}

help(){ 
  echo &quot;usage: $0 help | setup_initial | nmea_pipe | raw_pipe | sat_used | navpvt | ntrip &quot; 
  echo &quot;          help  ... this help &quot; 
  echo &quot;          setup_initial ... this will initialise the base station &quot; 
  echo &quot;          nmea_pipe ... this will create a gpspipe with NMEA protocol listen on port 10001 &quot;
  echo &quot;          raw_pipe ... this will create a gpspipe with raw data listen on port 10002 &quot;
  echo &quot;          sat_used ... will show the used satellites based on ubxtool -p NAV-SAT command &quot;
  echo &quot;          navpvt ... will show the status based on ubxtool -p NAV-PVT command &quot;
  echo &apos;          ntrip start | stop | status | &quot;&quot; &apos;
  echo &quot;                to manage communication between base station and rover with a str2str process &quot;
  echo &quot;                without argument it will restart the str2str process &quot; 
  exit 1 
} 

usage(){ 
  echo &quot;usage: $0 help | setup_initial | nmea_pipe | raw_pipe | sat_used | navpvt | ntrip &quot; 
  exit 1 
} 


case &quot;$1&quot; in 
  setup_initial ) setup_initial ;; 
  nmea_pipe ) nmea_pipe &quot;$2&quot; ;; 
  raw_pipe ) raw_pipe &quot;$2&quot; ;; 
  sat_used ) sat_used ;; 
  navpvt ) navpvt ;; 
  ntrip ) ntrip &quot;$2&quot; ;; 
  help ) help ;; 
  * ) usage ;; 
esac 

&lt;/pre&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;h3 id=&quot;setup_initial&quot;&gt;setup_initial&lt;/h3&gt;

&lt;p&gt;Both scripts setup_base_sh and setup_rover_sh has to be run with this option. If this is done a communication between setup_base_sh and setup_rover_sh is established and a “Fixed” solution should be reached within a short time.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The following options are just for the rover.&lt;/p&gt;

&lt;h3 id=&quot;nmea_pipe&quot;&gt;nmea_pipe&lt;/h3&gt;

&lt;p&gt;After setting up base and rover it will take some time to get a precision position with status &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fixed&lt;/code&gt;. Worst case is one hour in my situation. But typically it takes 10 minutes or a little bit more. Running command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_rover_sh nmea_pipe&lt;/code&gt; will create a gpspipe with &lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socat EXEC:gpspipe -r TCP-LISTEN:10001,reuseaddr,fork&lt;/code&gt;. Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkplot_qt &amp;amp;&lt;/code&gt; and connecting to this port 10001 at server rover will show you the current position at the rover.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rover_short_2026.png&quot; alt=&quot;rover for a short period&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The graph above shows the measurement for a short period of time. Each data point represents a one-second interval. As we can see almost all dots are within a circle of 5 mm radius. Moving the rover antenna by 3 cm results in a distinct new cluster of points, precisely reflecting the displacement. If the antenna is moved further away - for example one meter - then the status “Fixed” is lost and falls back to “Floating”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rover_long_2026.png&quot; alt=&quot;rover for a longer period&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The example above shows a longer period of time and we can see that all dots are in a square of 3 x 3 cm. &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;sat_used&quot;&gt;sat_used&lt;/h3&gt;

&lt;p&gt;With option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sat_used&lt;/code&gt; will give you the information how many satellites are used. A typical output could be this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;only GPS, Galileo and BeiDou are counted
Status:    carrSoln (Fixed)
                    satellites total seen :  38
                                      GPS :  11  Galileo: 11  BeiDou: 16
                          satellites used :  26
                                      GPS :  10  Galileo: 6  BeiDou: 10
     satellites used with RTCM correction :  26
  satellites with pseudorange corrections :  26
satellites with carrier range corrections :  21
                                      GPS :  7  Galileo: 6  BeiDou: 8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the example above we see a status fixed. I have never seen more than 25 satellites with carrier range corrections. Maybe this is a limitation from the U-blox receiver or there are never more than 25 satellites available with the needed requirements. &lt;br /&gt;
There are 3 states possible&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    carrSoln (None)
    carrSoln (Floating)
    carrSoln (Fixed)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Status “None” is only visible short time after power on. Fixed is of course our goal. &lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;raw_pipe&quot;&gt;raw_pipe&lt;/h3&gt;

&lt;p&gt;Using option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw_pipe&lt;/code&gt; will create a second gpspipe. This will allow to use &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str2str -in tcpcli://rover:10002 -out file://log_%Y%m%d%h%M.ubx&lt;/code&gt; which logs the data to file. Then it’s possible to extract data in a future process.&lt;/p&gt;

&lt;h3 id=&quot;navpvt&quot;&gt;navpvt&lt;/h3&gt;

&lt;p&gt;navpvt show the output of command “ubxtool -p NAV-PVT”&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;UBX-NAV-PVT:
  iTOW 576850000 time 2026/05/02 16:13:52 valid x37
  tAcc 24 nano 341196 fixType 3 flags x83 flags2 xea
  numSV 29 lon 162837865 lat 481492049 height 277494
  hMSL 235357 hAcc 15 vAcc 24
  velNED 2 2 16 gSpeed 3 headMot 24410926
  sAcc 131 headAcc 18000000 pDOP 119 flags3 x4 reserved0 x334c2e2c
  headVeh 0 magDec 0 magAcc 0
    valid (validDate ValidTime fullyResolved)
    fixType (3D)
    flags (gnssFixOK, diffSoln, Carrier Phase fixed,)
    flags2 (confirmedAvai confirmedDate confirmedTime)
    psmState (Not Active)
    carrSoln (Fixed)
    flags3 () lastCorrectionAge 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;help&quot;&gt;help&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;usage: ./setup_rover_sh help | setup_initial | nmea_pipe | raw_pipe | sat_used | navpvt | ntrip 
          help  ... this help 
          setup_initial ... this will initialise the base station 
          nmea_pipe ... this will create a gpspipe with NMEA protocol listen on port 10001 
          raw_pipe ... this will create a gpspipe with raw data listen on port 10002 
          sat_used ... will show the used satellites based on ubxtool -p NAV-SAT command 
          navpvt ... will show the status based on ubxtool -p NAV-PVT command 
          ntrip start | stop | status | &quot;&quot; 
                to manage communication between base station and rover with a str2str process 
                without argument it will restart the str2str process 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;some-internal-links&quot;&gt;some internal links&lt;/h2&gt;

&lt;p&gt;These are some possibilities to look for a precise point position. Definitelly one needs to have one exact position for the base station in a rover/base setup.&lt;/p&gt;

&lt;p&gt;(1) &lt;a href=&quot;/2023/06/03/PPP-Precise-Point-Positioning.html&quot; target=&quot;_blank&quot;&gt;PPP - Precise Point Positioning with averaging&lt;/a&gt; &lt;br /&gt;
(2) &lt;a href=&quot;/2026/01/21/PPP-with-gpsrinex.html&quot; target=&quot;_blank&quot;&gt;PPP with gpsrinex, CSRS-PPP and ECTT&lt;/a&gt; &lt;br /&gt;
(3) &lt;a href=&quot;/2026/02/21/PPP-with-RTKLIB.html&quot; target=&quot;_blank&quot;&gt;PPP with RTKlib and local correction&lt;/a&gt; &lt;br /&gt;
(4) &lt;a href=&quot;/2026/02/28/PPP-with-NTRIP-source.html&quot; target=&quot;_blank&quot;&gt;PPP with NTRIP source for u-blox GNSS receiver over gpsd&lt;/a&gt; &lt;br /&gt;
(5) &lt;a href=&quot;/2026/03/15/PPP-with-NTRIP-source-and-rtknavi_qt.html&quot; target=&quot;_blank&quot;&gt;High Precision Positioning with RTK and rtknavi_qt&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Tools at github: &lt;br /&gt;
A commandline tool to &lt;a href=&quot;https://github.com/hans-mayer/transform_ecef_wgs84&quot; target=&quot;_blank&quot;&gt;transform ecef wgs84&lt;/a&gt; data. &lt;br /&gt;&lt;/p&gt;

</description>
        <pubDate>Sun, 03 May 2026 17:47:00 +0200</pubDate>
        <link>https://blog.mayer.tv/2026/05/03/RTK-base-rover-with-Ublox-GNSS-receivers.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/05/03/RTK-base-rover-with-Ublox-GNSS-receivers.html</guid>
        
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>Comparison Precise Point Positioning (PPP) and RTK Methods</title>
        <description>&lt;h1 id=&quot;comprehensive-comparison-precise-point-positioning-ppp-methods&quot;&gt;Comprehensive Comparison: Precise Point Positioning (PPP) Methods&lt;/h1&gt;

&lt;p&gt;This report documents the evolution of GNSS measurement techniques from basic statistical averaging to professional-grade post-processing and real-time RTK solutions. All experiments were conducted using a fixed roof-mounted antenna and u-blox ZED-F9P/ZED-X20P receivers.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;1-overview-of-evaluated-methods&quot;&gt;1. Overview of Evaluated Methods&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Title&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Core Technique&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Data Source&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Statistical Averaging&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Long-term mean calculation (24h)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Autonomous GNSS&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;CSRS-PPP Service&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cloud-based post-processing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Global Ephemerides&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;RTKLIB (Local)&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Manual post-processing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Local Base (APOS)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;NTRIP (Hardware)&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Internal RTK Engine&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Real-time NTRIP Stream&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;RTKNAV (Software)&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;External RTK processing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Real-time NTRIP Stream&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2-detailed-method-analysis&quot;&gt;2. Detailed Method Analysis&lt;/h2&gt;

&lt;h3 id=&quot;method-1-precise-point-positioning-with-averaging&quot;&gt;Method 1: Precise Point Positioning with Averaging&lt;/h3&gt;
&lt;p&gt;This “brute force” approach relies on the law of large numbers. By averaging data over 24 hours, local ionospheric fluctuations are partially smoothed out.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Achieved a precision within a &lt;strong&gt;20 cm radius&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dynModel&lt;/code&gt; to “stationary” did not significantly improve the result. The absolute offset compared to corrected methods remained over 1 meter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;method-2-csrs-ppp--ectt-transformation&quot;&gt;Method 2: CSRS-PPP &amp;amp; ECTT Transformation&lt;/h3&gt;
&lt;p&gt;Utilizes the Canadian Spatial Reference System (CSRS) for professional post-processing.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Workflow:&lt;/strong&gt; Collect RINEX data -&amp;gt; Upload to CSRS -&amp;gt; Wait for “Final” orbit products -&amp;gt; Transform coordinates.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The Transformation Factor:&lt;/strong&gt; Results are delivered in &lt;strong&gt;ITRF&lt;/strong&gt;. For European accuracy, the &lt;strong&gt;ECTT tool&lt;/strong&gt; must be used to convert to &lt;strong&gt;ETRF&lt;/strong&gt;, accounting for tectonic plate drift (approx. 2.5 cm/year).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;method-3-rtklib-with-local-correction-apos&quot;&gt;Method 3: RTKLIB with Local Correction (APOS)&lt;/h3&gt;
&lt;p&gt;The most precise “offline” method using local reference stations from the Austrian BEV (APOS service).&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Technique:&lt;/strong&gt; Manual calculation using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rnx2rtkp&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.obs&lt;/code&gt; files from both the rover and a nearby base station (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WIEN00AUT&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Results:&lt;/strong&gt; Extremely tight clustering with a maximum deviation of only &lt;strong&gt;26 mm&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Comparison:&lt;/strong&gt; After transformation, it aligned within &lt;strong&gt;11 cm&lt;/strong&gt; of the CSRS-PPP result.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;method-4-ntrip-over-gpsd-hardware-rtk&quot;&gt;Method 4: NTRIP over gpsd (Hardware RTK)&lt;/h3&gt;
&lt;p&gt;A real-time solution where the u-blox ZED-F9P processes RTCM3 correction data internally.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Workflow:&lt;/strong&gt; Direct NTRIP stream via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpsd&lt;/code&gt; to the receiver.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Stability:&lt;/strong&gt; High percentage of &lt;strong&gt;Status: FIXED&lt;/strong&gt; (Q=1).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Precision:&lt;/strong&gt; The average value was only &lt;strong&gt;3.9 cm&lt;/strong&gt; away from the high-precision results of Method 3.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;method-5-software-based-rtk-rtknavi_qt&quot;&gt;Method 5: Software-Based RTK (rtknavi_qt)&lt;/h3&gt;
&lt;p&gt;Utilizes the RTKlib software suite to perform the heavy lifting of RTK calculations on a host PC rather than the chip.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Hardware:&lt;/strong&gt; Conducted with the &lt;strong&gt;u-blox ZED-X20P&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Observations:&lt;/strong&gt; It required approximately &lt;strong&gt;30 minutes&lt;/strong&gt; to achieve a “FIX.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Control:&lt;/strong&gt; Offers the most granular control over navigation systems (GPS, Galileo, BDS) and satellite selection.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-comparison-table&quot;&gt;3. Comparison Table&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Feature&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method 1&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method 2&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method 3&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method 4&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method 5&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Real-Time&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Low&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Medium&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;High&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Medium&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Accuracy (Relative)&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;~20-40 cm&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&amp;lt; 5 cm&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;&amp;lt; 3 cm&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;~5 cm&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;~5-10 cm&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Ref. System&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;WGS84&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ITRF (Global)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ETRF (Local)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ETRF&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ETRF&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Data Effort&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Zero&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RINEX Upload&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RINEX + Base&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;NTRIP Login&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;NTRIP + Config&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;4-final-conclusion--recommendations&quot;&gt;4. Final Conclusion &amp;amp; Recommendations&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;For Static Surveying:&lt;/strong&gt; Method 3 (Post-processing with local APOS data) is the gold standard, providing the highest repeatability and millimeter-level precision.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;For Daily Use:&lt;/strong&gt; Method 4 (NTRIP into F9P) is the most efficient. It provides professional “Fixed” solutions in real-time with minimal software overhead.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Critical Factor:&lt;/strong&gt; When comparing results over time (e.g., 2023 vs 2026), always perform a &lt;strong&gt;coordinate transformation&lt;/strong&gt; (ITRF to ETRF). Without it, continental drift will be misinterpreted as measurement inaccuracy.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;5-links-to-this-5-methods&quot;&gt;5. Links to this 5 methods&lt;/h2&gt;

&lt;p&gt;(1) &lt;a href=&quot;/2023/06/03/PPP-Precise-Point-Positioning.html&quot; target=&quot;_blank&quot;&gt;PPP - Precise Point Positioning with averaging&lt;/a&gt; &lt;br /&gt;
(2) &lt;a href=&quot;/2026/01/21/PPP-with-gpsrinex.html&quot; target=&quot;_blank&quot;&gt;PPP with gpsrinex, CSRS-PPP and ECTT&lt;/a&gt; &lt;br /&gt;
(3) &lt;a href=&quot;/2026/02/21/PPP-with-RTKLIB.html&quot; target=&quot;_blank&quot;&gt;PPP with RTKlib and local correction&lt;/a&gt; &lt;br /&gt;
(4) &lt;a href=&quot;/2026/02/28/PPP-with-NTRIP-source.html&quot; target=&quot;_blank&quot;&gt;PPP with NTRIP source for u-blox GNSS receiver over gpsd&lt;/a&gt; &lt;br /&gt;
(5) &lt;a href=&quot;/2026/03/15/PPP-with-NTRIP-source-and-rtknavi_qt.html&quot; target=&quot;_blank&quot;&gt;High Precision Positioning with RTK and rtknavi_qt&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 16 Mar 2026 14:02:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/03/16/Comparison-Precise-Point-Positioning-PPP-Methods.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/03/16/Comparison-Precise-Point-Positioning-PPP-Methods.html</guid>
        
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>High Precision Positioning with RTK and rtknavi_qt</title>
        <description>&lt;p&gt;This is now my fifth attempt and probably the last one to get a high precision position (using RTK) of my stationary GNSS antenna on the roof of my house. 
You can find the methods I used previously in my blogs here: &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;(1) &lt;a href=&quot;/2023/06/03/PPP-Precise-Point-Positioning.html&quot; target=&quot;_blank&quot;&gt;PPP - Precise Point Positioning with averaging&lt;/a&gt; &lt;br /&gt;
(2) &lt;a href=&quot;/2026/01/21/PPP-with-gpsrinex.html&quot; target=&quot;_blank&quot;&gt;PPP with gpsrinex, CSRS-PPP and ECTT&lt;/a&gt; &lt;br /&gt;
(3) &lt;a href=&quot;/2026/02/21/PPP-with-RTKLIB.html&quot; target=&quot;_blank&quot;&gt;PPP with RTKlib and local correction&lt;/a&gt; &lt;br /&gt;
(4) &lt;a href=&quot;/2026/02/28/PPP-with-NTRIP-source.html&quot; target=&quot;_blank&quot;&gt;PPP with NTRIP source for u-blox GNSS receiver over gpsd&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;As GNSS receiver I used my brand new &lt;a href=&quot;/2026/03/09/u-blox_ZED-X20P.html&quot; target=&quot;_blank&quot;&gt;u-blox ZED-X20P&lt;/a&gt; &lt;br /&gt;
to manage this device I use the &lt;a href=&quot;https://gitlab.com/gpsd/gpsd&quot; target=&quot;_blank&quot;&gt;gpsd&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;The method is quite simple. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtknavi_qt&lt;/code&gt; to configure a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rover / base station&lt;/code&gt; setup. Rover is the own GNSS receiver with a stationary antenna. The base station is an external RTCM stream. So feed RTCM data as a NTRIP ( Networked Transport of RTCM via Internet Protocol ) stream to rtknavi_qt. rtknavi_qt is part of the package RTKlib which can be found here &lt;a href=&quot;https://github.com/rtklibexplorer/RTKLIB&quot; target=&quot;_blank&quot;&gt;github.com/rtklibexplorer/RTKLIB&lt;/a&gt;. I run it on Debian Linux.&lt;/p&gt;

&lt;p&gt;To do so, one must use any NTRIP caster. There are several available for free and of course also some commercial. In any case you have to register as you need username and password.&lt;/p&gt;

&lt;p&gt;This method doesn’t differ much from method (4). The main difference: processing is now handled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtknavi_qt&lt;/code&gt;, whereas in (4) it was calculated on-board by the u-blox receiver itself.&lt;/p&gt;

&lt;p&gt;To prepare my u-blox for this task, I run the following commands to enable RAWX and SFRBX messages:&lt;/p&gt;

&lt;pre&gt;
ubxtool -z CFG-MSGOUT-UBX_RXM_SFRBX_UART1,1 | grep ACK-ACK
ubxtool -g CFG-MSGOUT-UBX_RXM_SFRBX_UART1 | grep UART
ubxtool  | grep SFRBX

ubxtool -z CFG-MSGOUT-UBX_RXM_RAWX_UART1,1 | grep ACK-ACK
ubxtool -g CFG-MSGOUT-UBX_RXM_RAWX_UART1 | grep UART
ubxtool  | grep RAWX

# DYNMODEL stationary 
ubxtool -z CFG-NAVSPG-DYNMODEL,2 | grep ACK-ACK
ubxtool -g CFG-NAVSPG-DYNMODEL | grep CFG-NAVSPG-DYNMODEL
&lt;/pre&gt;

&lt;p&gt;Now configure rtknavi_qt&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtknavi_qt &amp;amp;&lt;/code&gt; and new window will appear. &lt;br /&gt;
Click on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Options...&lt;/code&gt; on the bottom left side there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Load...&lt;/code&gt; button. Load the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f9p_ppk.conf&lt;/code&gt; which comes with the source tree. Some of the settings I changed. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Positioning Mode&lt;/code&gt; I set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Static&lt;/code&gt; as my antenna is fix mounted. As &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Navigation Systems&lt;/code&gt; I selected GPS, Galileo and BDS. This should fit what the base station is delivering. In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Positions&lt;/code&gt; tab for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Base Station&lt;/code&gt; I selected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTCM/Raw Antenna Position&lt;/code&gt;. It is also possible to set Lat/Lon/height or X/Y/Z but as long as the base station is propagating its own position “RTCM/Raw Antenna Position” is the easy way. &lt;br /&gt;
Back in the main menu press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;I&lt;/code&gt; for input streams. Select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rover&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TCP Client&lt;/code&gt; as Stream Type. As Stream Options enter IP address and port number where you start the following process &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socat EXEC:&apos;gpspipe -RB&apos; TCP-LISTEN:10001,reuseaddr,fork  &amp;amp;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and Format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u-blox UBX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpspipe&lt;/code&gt; must be able to connect to the own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpsd&lt;/code&gt; process and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socat&lt;/code&gt; offers this data on port 10001 &lt;br /&gt;
It would be possible too to connect rtknavi_qt via the serial port to the X20P directly. But then the gpsd process has to be stoppped. I like to have still the possibility to communicate via ubxtool to the GNSS receiver even if another task is running.&lt;/p&gt;

&lt;p&gt;The base station is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NTRIP Client&lt;/code&gt;, in Stream Options enter Caster Address, port, mountpoint, user name and password what you want to use. Format is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTCM 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rtknavi_input.png&quot; alt=&quot;rtknavi input streams&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Press the “OK” button. Ideally save the new configuration with a new name in the options tab. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Now it’s time to press the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Start&lt;/code&gt; button.  Very soon I get as solution “float”. But it took almost every time up to 30 minutes to get status &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FIX&lt;/code&gt;. So take a coffee or do something useful in the meantime.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rtknavi_main.png&quot; alt=&quot;rtknavi main screen&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Even I can see 40 or more satellites normally only 14 of them are used for calculation. If not enough satellites are available a “FIX” could fail completely.&lt;/p&gt;

&lt;p&gt;Press the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O&lt;/code&gt; button to define an output stream if you want to document the results.&lt;/p&gt;

&lt;p&gt;I have done this several times and this is the result&lt;/p&gt;

&lt;style&gt;
.tablelines table, .tablelines td, .tablelines th {
        border: 1px solid black;
        padding: 2px;
        }
&lt;/style&gt;

&lt;table class=&quot;tablelines&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;  date  &lt;/th&gt;
      &lt;th&gt;  latitude  &lt;/th&gt;
      &lt;th&gt;  longitude  &lt;/th&gt;
      &lt;th&gt;  altitude  &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0309120300  &lt;/td&gt;
      &lt;td&gt;  48.14928606302  &lt;/td&gt;
      &lt;td&gt;  16.28383433228  &lt;/td&gt;
      &lt;td&gt;  286.40506914692  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0309134300  &lt;/td&gt;
      &lt;td&gt;  48.14928580935  &lt;/td&gt;
      &lt;td&gt;  16.28383415321  &lt;/td&gt;
      &lt;td&gt;  286.48471173372  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0309151800  &lt;/td&gt;
      &lt;td&gt;  48.14928595710  &lt;/td&gt;
      &lt;td&gt;  16.28383435701  &lt;/td&gt;
      &lt;td&gt;  286.45548243359  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0309183400  &lt;/td&gt;
      &lt;td&gt;  48.14928600921  &lt;/td&gt;
      &lt;td&gt;  16.28383449567  &lt;/td&gt;
      &lt;td&gt;  286.53004319113  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0310140400  &lt;/td&gt;
      &lt;td&gt;  48.14928578354  &lt;/td&gt;
      &lt;td&gt;  16.28383411977  &lt;/td&gt;
      &lt;td&gt;  286.46952323780  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  TRF200AUT0_0310172500  &lt;/td&gt;
      &lt;td&gt;  48.14928596503  &lt;/td&gt;
      &lt;td&gt;  16.28383407456  &lt;/td&gt;
      &lt;td&gt;  286.48586886361  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  average  &lt;/td&gt;
      &lt;td&gt;  48.14928593121  &lt;/td&gt;
      &lt;td&gt;  16.28383425542  &lt;/td&gt;
      &lt;td&gt;  286.47178310113  &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The points are all within 23 mm of the average value.&lt;/p&gt;

&lt;pre&gt;
4092523.7097    1195484.3619    4728180.7806
48.14928593121  16.28383425542  286.471
48 8 57.42935   16 17 1.80331
&lt;/pre&gt;

&lt;p&gt;Taking the average value and calculating the distance to method (2) we get an offset of 4.5 cm. Distance to method (3) is 12.4 cm. Distance to method (4) is 8.8 cm.&lt;/p&gt;

&lt;p&gt;Below the is a plot of one of these traces done with rtkplot_qt&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/plot20260310rtknavi.png&quot; alt=&quot;plot20260310rtknavi&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see there are 71.4% of all points with Q = 1 that is status “FIX”. I took only those point for the calculation of the average value. The area is about 
5 times 6 cm.&lt;/p&gt;

&lt;p&gt;Note: The quality of your RTK fix depends heavily on the quality and proximity of the NTRIP caster. If you experience inconsistent results, double-check the coordinates provided by the caster’s mountpoint.&lt;/p&gt;

&lt;p&gt;Tools at github: &lt;br /&gt;
A commandline tool to &lt;a href=&quot;https://github.com/hans-mayer/transform_ecef_wgs84&quot; target=&quot;_blank&quot;&gt;transform ecef wgs84&lt;/a&gt; data. &lt;br /&gt;&lt;/p&gt;

</description>
        <pubDate>Sun, 15 Mar 2026 11:13:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/03/15/PPP-with-NTRIP-source-and-rtknavi_qt.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/03/15/PPP-with-NTRIP-source-and-rtknavi_qt.html</guid>
        
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>second interface for u-blox GNSS receiver on Pi4 and Pi5</title>
        <description>&lt;p&gt;This post will just describe how to setup a second interface on a Raspberry Pi4 and Pi5 with Debian 13 (trixie) for the second interface on the GNSS receiver called UART2. &lt;br /&gt;
A detailed description how to prepare a Raspberry Pi4 and Pi5 for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpsd&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntpd&lt;/code&gt; can be found here: &lt;br /&gt;
&lt;a href=&quot;/2025/12/20/GPSD-NTP-on-Raspberry-PI5-with-Trixie.html&quot; target=&quot;_blank&quot;&gt;GPSD on Raspberry Pi5 with Debian Trixie&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;/2022/06/19/GPSD-NTP-on-Raspberry-PI4-with-Bullseye.html&quot; target=&quot;_blank&quot;&gt;GPSD on Raspberry Pi4 with Debian Bullseye&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I own a pHAT from uputronics with a ZED-F9P on Pi4 and a pHAT from sparkfun with a ZED-X20P on Pi5. &lt;br /&gt;
Both GNSS receivers have a second interface called UART2 and both systems are wired to GPIO pins of the Raspberry Pi.&lt;/p&gt;

&lt;p&gt;And sometimes it’s useful to have a second connection to the receiver. For example, if the interface speed of the primary interface is accidentally changed or misconfigured. Or if one wants to feed RTCM3 data over a different path. But there are also other use cases where it’s useful to have access over a second way.&lt;/p&gt;

&lt;h2 id=&quot;pi-4&quot;&gt;Pi 4&lt;/h2&gt;

&lt;p&gt;In my case the uputronics board UART2 is connected to GPIO12 for TXD5 and GPIO13 for RXD5. Don’t mix up the GPIO name with the pin number. For example GPIO12 is pin 32 and GPIO13 is pin 33 on the 40 pin connector.&lt;/p&gt;

&lt;p&gt;For the Pi 4 the modification is easy. Add a line in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/firmware/config.txt&lt;/code&gt; in the global section&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dtoverlay=uart5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and reboot. That’s it. Now you will find a new device &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/ttyAMA5&lt;/code&gt;. One can access this interface for example with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/ubxtool -f /dev/ttyAMA5 -s 38400&lt;/code&gt; and the command you want to submit.&lt;/p&gt;

&lt;h2 id=&quot;pi-5&quot;&gt;Pi 5&lt;/h2&gt;

&lt;p&gt;On the Raspberry Pi5 it was a little bit more tricky as there is a complete redesign. The pin usage was unchanged but the hardware below changed. &lt;br /&gt;
sparkfun connected UART2 of ZED-X20P to GPIO8 and GPIO9 which is UART3. I created a section &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[all]&lt;/code&gt; already for the first interface at the end of the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/firmware/config.txt&lt;/code&gt; and did add a new line with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dtoverlay=uart3-pi5&lt;/code&gt;. The complete change looks like this&lt;/p&gt;

&lt;pre&gt;
[all]
# iface 1: Standard-UART on GPIO 14 (TX) and 15 (RX)
enable_uart=1

# GPIO 8/9 (UART3)
dtoverlay=uart3-pi5
&lt;/pre&gt;

&lt;p&gt;Reboot. That’s it. Now you will find a new device &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/ttyAMA3&lt;/code&gt;. If you create a function like this&lt;/p&gt;

&lt;pre&gt;
ubxtool3(){
  /usr/local/bin/ubxtool -f /dev/ttyAMA3 -s 38400 $@ 
}
&lt;/pre&gt;

&lt;p&gt;you can easily access the u-blox device without adding each time device and speed. Just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubxtool3&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubxtool&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just another hint. I use this function for normal operation.&lt;/p&gt;

&lt;pre&gt;
ubxtool(){
  /usr/local/bin/ubxtool $@ localhost:gpsd:/dev/serial0 
}
&lt;/pre&gt;

&lt;p&gt;I compiled the gpsd source tree by myself. Therefore “ubxtool” and others are found in /usr/local/bin &lt;br /&gt;
If you install the delivered package you will find /usr/bin/ubxtool&lt;/p&gt;

</description>
        <pubDate>Mon, 09 Mar 2026 18:35:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/03/09/second-interface-for-u-blox-receiver-on-pi4-and-pi5.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/03/09/second-interface-for-u-blox-receiver-on-pi4-and-pi5.html</guid>
        
        
        <category>u-blox</category>
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>u-blox ZED-X20P</title>
        <description>&lt;p&gt;Some days ago I got the new ZED-X20P from manufacturer u-blox. &lt;br /&gt;
I bought this device from DigiKey as redistributor for sparkfun.&lt;/p&gt;

&lt;p&gt;In July I updated to the latest version. MON-VER gives now the following information&lt;/p&gt;

&lt;pre&gt;# ubxtool  -p MON-VER
  swVersion EXT HPG 2.10 (b0eda3)
  hwVersion 000B0000
  extension ROM BASE 0x00A9D329
  extension FWVER=HPG 2.10
  extension PROTVER=50.11
  extension MOD=ZED-X20P
  extension GPS;GLO;GAL;BDS
  extension SBAS;QZSS
  extension NAVIC;LBAND
&lt;/pre&gt;

&lt;p&gt;As you can see this pHAT from sparkfun has a submodul with the ZED-X20P&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/zed-x20p_2.png&quot; alt=&quot;zed-x20p_2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This pHat is mounted on a Raspberry Pi5. &lt;br /&gt;
The submodule is connect with a very short antenna cable to the pHAT. Below there is the 5V/3A USB power connector.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/zed-x20p_1.png&quot; alt=&quot;zed-x20p_1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since some years I own a &lt;a href=&quot;/2022/07/29/ublox-ZED-F9P.html&quot; target=&quot;_blank&quot;&gt;u-blox ZED-F9P&lt;/a&gt; too. But now I am happy that I can do some experiments with the latest family of GNSS receivers from u-blox. 
If you are missing GLONASS in version 2.02 the version 2.10 is the solution. 
Read here how to &lt;a href=&quot;/2026/07/23/Update-ZED-X20P-with-Debian-on-piHAT.html&quot; target=&quot;_blank&quot;&gt;update&lt;/a&gt; without u-center 2&lt;/p&gt;

</description>
        <pubDate>Mon, 09 Mar 2026 17:47:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/03/09/u-blox_ZED-X20P.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/03/09/u-blox_ZED-X20P.html</guid>
        
        
        <category>u-blox</category>
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>PPP with NTRIP source for u-blox GNSS receiver over gpsd</title>
        <description>&lt;p&gt;This is now my fourth attempt to get an exact position (Precise Point Positioning) of my fixed mounted GNSS antenna at the roof of my house. 
You can find the methods I used previously in my blogs here: &lt;br /&gt; 
(1) &lt;a href=&quot;/2023/06/03/PPP-Precise-Point-Positioning.html&quot; target=&quot;_blank&quot;&gt;PPP - Precise Point Positioning with averaging&lt;/a&gt; &lt;br /&gt;
(2) &lt;a href=&quot;/2026/01/21/PPP-with-gpsrinex.html&quot; target=&quot;_blank&quot;&gt;PPP with gpsrinex, CSRS-PPP and ECTT&lt;/a&gt; &lt;br /&gt;
(3) &lt;a href=&quot;/2026/02/21/PPP-with-RTKLIB.html&quot; target=&quot;_blank&quot;&gt;PPP with RTKlib and local correction&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;As GNSS receiver I used again my &lt;a href=&quot;/2022/07/29/ublox-ZED-F9P.html&quot; target=&quot;_blank&quot;&gt;u-blox ZED-F9P&lt;/a&gt; &lt;br /&gt;
to manage this device I use the &lt;a href=&quot;https://gitlab.com/gpsd/gpsd&quot; target=&quot;_blank&quot;&gt;gpsd&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;The method is quite simple. Feed RTCM date as a NTRIP ( Networked Transport of RTCM via Internet Protocol ) stream to the GNSS receiver. 
To do so, one must use any NTRIP caster. There are several available for free and of course also some commercial. In any case you have to register as you need username and password.&lt;/p&gt;

&lt;p&gt;As I am using the gpsd package I use the daemon gpsd itself to do this job. &lt;br /&gt;
This can be achieved by 2 different methods &lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;start gpsd with an additional argument like ntrip://my.user:my.passwd@157.90.249.44:2101/MOUNTPOINT &lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;run “gpsdctl add ntrip-URL”. This needs that gpsd was started with option “-F /run/gpsd.sock”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So what we need is username, password, the DNS name or IP address of the caster, the port number which is in almost all cases 2101 and the mountpoint. All mountpoints for a caster can be found at the caster itself and you should use one which is very close to you.&lt;/p&gt;

&lt;p&gt;To be sure that my ZED-F9P is well configured I run some checks.&lt;/p&gt;

&lt;pre&gt;
  ubxtool -g CFG-UART1INPROT-RTCM3X | grep CFG-UART1INPROT-RTCM3X 
  
  echo check if skipped frames count up 
  ubxtool -p MON-COMMS  | grep -A 7 UBX-MON-COMMS: | grep skipped
  sleep 10 
  ubxtool -p MON-COMMS  | grep -A 7 UBX-MON-COMMS: | grep skipped
  
  ubxtool  -g CFG-NAVSPG-DYNMODEL | grep CFG-NAVSPG-DYNMODEL | head -1 
  ubxtool  -z CFG-NAVSPG-DYNMODEL,2 | grep UBX-ACK-ACK: 
  
  if test -z &quot;`ubxtool -p NAV-PVT -v 2 | grep -i carrSoln | grep Fixed`&quot;
    then 
      echo state not fixed 
      ubxtool -p NAV-PVT -v 2 | grep -i carrSoln
      exit 1 
  fi 
 
  echo number of satellites with cno greater 40 
  ubxtool -p NAV-SIG -v 2 | grep cno | awk &apos;{ if ( $12 &amp;gt; 40 ) print ( $2, $4 ) }&apos; | sort -u | wc -l 
 
  echo accuracy in 0.1 mm 
  ubxtool -p NAV-RELPOSNED -v 2 | grep -i accN

  ubxtool -z CFG-MSGOUT-UBX_RXM_RTCM_UART1,1 | grep UBX-ACK-ACK:
  
  RESULT=`ubxtool -v 2 -w 10 | grep -i RTCM`
  
  if test -z &quot;$RESULT&quot; 
    then 
      echo we dont get RTCM data 
      exit 1 
  fi
    
  ubxtool -z CFG-NMEA-HIGHPREC,1  | grep UBX-ACK-ACK: # ist default 0 
  ubxtool -z CFG-MSGOUT-NMEA_ID_GGA_UART1,1 | grep UBX-ACK-ACK:  
  
  # for standard deviation 
  ubxtool -z CFG-MSGOUT-NMEA_ID_GST_UART1,1 | grep UBX-ACK-ACK: 
&lt;/pre&gt;

&lt;p&gt;I start gpspipe&lt;/p&gt;

&lt;pre&gt;nohup socat EXEC:&apos;gpspipe -rRB gpsdhost\:2947\:/dev/serial0&apos; &apos;TCP-LISTEN:10001,reuseaddr,fork&apos; &amp;amp; &lt;/pre&gt;

&lt;p&gt;and I collect the data with&lt;/p&gt;

&lt;pre&gt;
SEC=3600
DAT=`date &apos;+%j%H%M00&apos;`
timeout $SEC nc 127.0.0.1 10001 | grep --line-buffered -aE &quot;GGA|GST&quot; &amp;gt; $MP/messung_$DAT.nmea &lt;/pre&gt;

&lt;p&gt;$SEC is the time in seconds how long I want to collect the data. One hour is normally good enough. $MP is the mountpoint selected in the ntrip-URL. If all is fine I extract the position data from the file with this script&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nmea2pos.bash $MP/messung_$DAT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$MP/messung_$DAT.pos&lt;/code&gt; which can be viewed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkplot-qt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I run this scenario over several times. And this is the result&lt;/p&gt;

&lt;style&gt;
.tablelines table, .tablelines td, .tablelines th {
        border: 1px solid black;
        padding: 2px;
        }
&lt;/style&gt;

&lt;table class=&quot;tablelines&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;  date  &lt;/th&gt;
      &lt;th&gt;  latitude  &lt;/th&gt;
      &lt;th&gt;  longitude  &lt;/th&gt;
      &lt;th&gt;  altitude  &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_049220424  &lt;/td&gt;
      &lt;td&gt;  48.14928668858  &lt;/td&gt;
      &lt;td&gt;  16.28383489981  &lt;/td&gt;
      &lt;td&gt;  286.34149647059  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_049220558  &lt;/td&gt;
      &lt;td&gt;  48.14928651058  &lt;/td&gt;
      &lt;td&gt;  16.28383491739  &lt;/td&gt;
      &lt;td&gt;  286.34408541973  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_049224529  &lt;/td&gt;
      &lt;td&gt;  48.14928646948  &lt;/td&gt;
      &lt;td&gt;  16.28383476017  &lt;/td&gt;
      &lt;td&gt;  286.32093080357  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_051190411  &lt;/td&gt;
      &lt;td&gt;  48.14928674470  &lt;/td&gt;
      &lt;td&gt;  16.28383504772  &lt;/td&gt;
      &lt;td&gt;  286.35412230216  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053164800  &lt;/td&gt;
      &lt;td&gt;  48.14928685024  &lt;/td&gt;
      &lt;td&gt;  16.28383472580  &lt;/td&gt;
      &lt;td&gt;  286.29313600000  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053164900  &lt;/td&gt;
      &lt;td&gt;  48.14928721850  &lt;/td&gt;
      &lt;td&gt;  16.28383476294  &lt;/td&gt;
      &lt;td&gt;  286.34042372881  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053170600  &lt;/td&gt;
      &lt;td&gt;  48.14928712056  &lt;/td&gt;
      &lt;td&gt;  16.28383469769  &lt;/td&gt;
      &lt;td&gt;  286.35376422764  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053171700  &lt;/td&gt;
      &lt;td&gt;  48.14928646645  &lt;/td&gt;
      &lt;td&gt;  16.28383503276  &lt;/td&gt;
      &lt;td&gt;  286.33033740831  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053182000  &lt;/td&gt;
      &lt;td&gt;  48.14928761124  &lt;/td&gt;
      &lt;td&gt;  16.28383548462  &lt;/td&gt;
      &lt;td&gt;  286.31665768194  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_053184700  &lt;/td&gt;
      &lt;td&gt;  48.14928675778  &lt;/td&gt;
      &lt;td&gt;  16.28383470345  &lt;/td&gt;
      &lt;td&gt;  286.25878328474  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_056172800  &lt;/td&gt;
      &lt;td&gt;  48.14928653393  &lt;/td&gt;
      &lt;td&gt;  16.28383432340  &lt;/td&gt;
      &lt;td&gt;  286.44596396396  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_056173000  &lt;/td&gt;
      &lt;td&gt;  48.14928641814  &lt;/td&gt;
      &lt;td&gt;  16.28383453253  &lt;/td&gt;
      &lt;td&gt;  286.46528272251  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_056174600  &lt;/td&gt;
      &lt;td&gt;  48.14928641787  &lt;/td&gt;
      &lt;td&gt;  16.28383439221  &lt;/td&gt;
      &lt;td&gt;  286.44075187970  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_056174700  &lt;/td&gt;
      &lt;td&gt;  48.14928635164  &lt;/td&gt;
      &lt;td&gt;  16.28383422094  &lt;/td&gt;
      &lt;td&gt;  286.38687192983  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_056203500  &lt;/td&gt;
      &lt;td&gt;  48.14928663041  &lt;/td&gt;
      &lt;td&gt;  16.28383471765  &lt;/td&gt;
      &lt;td&gt;  286.38973867596  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_057102300  &lt;/td&gt;
      &lt;td&gt;  48.14928749432  &lt;/td&gt;
      &lt;td&gt;  16.28383523683  &lt;/td&gt;
      &lt;td&gt;  286.41764218009  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_057113100  &lt;/td&gt;
      &lt;td&gt;  48.14928616931  &lt;/td&gt;
      &lt;td&gt;  16.28383569321  &lt;/td&gt;
      &lt;td&gt;  286.21828049137  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_057172000  &lt;/td&gt;
      &lt;td&gt;  48.14928643937  &lt;/td&gt;
      &lt;td&gt;  16.28383441440  &lt;/td&gt;
      &lt;td&gt;  286.37522851677  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_064192300  &lt;/td&gt;
      &lt;td&gt;  48.14928611437  &lt;/td&gt;
      &lt;td&gt;  16.28383541068  &lt;/td&gt;
      &lt;td&gt;  286.39431147541  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_064193000  &lt;/td&gt;
      &lt;td&gt;  48.14928626123  &lt;/td&gt;
      &lt;td&gt;  16.28383493320  &lt;/td&gt;
      &lt;td&gt;  286.45333041958  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  messung_065185800  &lt;/td&gt;
      &lt;td&gt;  48.14928580792  &lt;/td&gt;
      &lt;td&gt;  16.28383442479  &lt;/td&gt;
      &lt;td&gt;  286.43519302326  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  average  &lt;/td&gt;
      &lt;td&gt;  48.14928662270  &lt;/td&gt;
      &lt;td&gt;  16.28383482534  &lt;/td&gt;
      &lt;td&gt;  286.36553964790  &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;pre&gt;
4092523.5748    1195484.3667    4728180.7527
48.14928662270  16.28383482534  286.3655
48 8 57.43184   16 17 1.80537
&lt;/pre&gt;

&lt;p&gt;The maximum distance to the average point is 13.5 cm. The maximum distance between 2 measuring points is 21.5 cm.&lt;/p&gt;

&lt;p&gt;Takeing the average value and calculating the distance to method (2) we get an offset of 6.8 cm. 
Distance to method (3) is 3.9 cm.&lt;/p&gt;

&lt;p&gt;Below the is a plot of one of these traces done with rtkplot_qt&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/plot20260226ublox.png&quot; alt=&quot;plot20260226ublox&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see there are 71.4% of all points with Q = 1 that is status “FIX”. I took only those point for the calculation of the average value. The area is about 
5 times 6 cm.&lt;/p&gt;

&lt;p&gt;Tools at github: &lt;br /&gt;
A commandline tool to &lt;a href=&quot;https://github.com/hans-mayer/transform_ecef_wgs84&quot; target=&quot;_blank&quot;&gt;transform ecef wgs84&lt;/a&gt; data. &lt;br /&gt;
A commandline tool which &lt;a href=&quot;https://github.com/hans-mayer/nmea2pos&quot; target=&quot;_blank&quot;&gt;converts NMEA to high-precision .pos position logs&lt;/a&gt; data. &lt;br /&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 28 Feb 2026 18:32:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/02/28/PPP-with-NTRIP-source.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/02/28/PPP-with-NTRIP-source.html</guid>
        
        
        <category>GNSS</category>
        
      </item>
    
      <item>
        <title>PPP with RTKLIB and local correction</title>
        <description>&lt;p&gt;This is now my third attempt to get an exact position of my fixed mounted GNSS antenna at the roof of my house. 
You can find the methods I used previously in my blogs here: &lt;br /&gt; 
(1) &lt;a href=&quot;/2023/06/03/PPP-Precise-Point-Positioning.html&quot; target=&quot;_blank&quot;&gt;PPP - Precise Point Positioning with averaging&lt;/a&gt; &lt;br /&gt;
(2) &lt;a href=&quot;/2026/01/21/PPP-with-gpsrinex.html&quot; target=&quot;_blank&quot;&gt;PPP with gpsrinex and CSRS-PPP and ECIT&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As GNSS receiver I used again my &lt;a href=&quot;/2022/07/29/ublox-ZED-F9P.html&quot; target=&quot;_blank&quot;&gt;u-blox ZED-F9P&lt;/a&gt; &lt;br /&gt;
to manage this device I use the &lt;a href=&quot;https://gitlab.com/gpsd/gpsd&quot; target=&quot;_blank&quot;&gt;gpsd&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;This time I used RTKlib to make the post-processing by myself. There are different versions available, I used this: &lt;a href=&quot;https://github.com/rtklibexplorer/RTKLIB&quot; target=&quot;_blank&quot;&gt;github.com/rtklibexplorer/RTKLIB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The method is about this: &lt;br /&gt;
1) create an UBX file over several hours. &lt;br /&gt;
2) apply the correction with a RINEX file offered from an external service provider.&lt;/p&gt;

&lt;p&gt;Within a shell script I prepared my ZED-F9P with the following settings:&lt;/p&gt;

&lt;p&gt;check if baud-rate is high enough&lt;/p&gt;
&lt;pre&gt;ubxtool -g CFG-UART1-BAUDRATE | grep CFG-UART1-BAUDRATE &lt;/pre&gt;
&lt;p&gt;I use 921600 bd. This is the highest value I can use. 38400 would be the default. &lt;br /&gt;
now disable NMEA protocol and check the response&lt;/p&gt;
&lt;pre&gt;ubxtool -d NMEA | grep UBX-ACK-ACK:
ubxtool -z CFG-UART1OUTPROT-NMEA,0 | grep UBX-ACK-ACK:
ubxtool -g CFG-UART1OUTPROT-NMEA | grep CFG-UART1OUTPROT-NMEA | head -1 &lt;/pre&gt;
&lt;p&gt;enable or disable different satellites &lt;br /&gt;
I disabled Michibiki, the japanese satellites as I can see them very rarely.&lt;/p&gt;
&lt;pre&gt;ubxtool -z CFG-SIGNAL-SBAS_L1CA_ENA,1 | grep UBX-ACK-ACK:
ubxtool -z CFG-SIGNAL-SBAS_ENA,1 | grep UBX-ACK-ACK:
ubxtool -z CFG-SIGNAL-QZSS_L1CA_ENA,0 | grep UBX-ACK-ACK:
ubxtool -z CFG-SIGNAL-QZSS_L1S_ENA,0 | grep UBX-ACK-ACK:
ubxtool -z CFG-SIGNAL-QZSS_L2C_ENA,0 | grep UBX-ACK-ACK:
ubxtool -z CFG-SIGNAL-QZSS_ENA,0 | grep UBX-ACK-ACK:
ubxtool -g CFG-SIGNAL | sed -n -e &apos;/^UBX-CFG-VALGET:/,/^$/ p&apos; | awk -v RS= &apos;NR==1&apos; &lt;/pre&gt;
&lt;p&gt;enable raw data&lt;/p&gt;
&lt;pre&gt;ubxtool -e RAWX | grep UBX-ACK-ACK:
ubxtool | grep RAWX &lt;/pre&gt;
&lt;p&gt;to get satellite track data&lt;/p&gt;
&lt;pre&gt;ubxtool -e SFRBX | grep UBX-ACK-ACK: 
ubxtool -z CFG-MSGOUT-UBX_RXM_SFRBX_UART1,1 | grep UBX-ACK-ACK: &lt;/pre&gt;

&lt;pre&gt;SECS=50400
DAT=`date &apos;+%Y%j%H%M00&apos;`
FILE=`echo result$DAT`
gpspipe -x $SECS -R gpsdhost:gpsd:/dev/serial0 &amp;gt; $FILE.ubx &lt;/pre&gt;

&lt;p&gt;This gpspipe job will run 14 hours. ( = 50400 seconds ) &lt;br /&gt;
Next is to generate $FILE.obs , $FILE.nav and $FILE.sbs To do this run convbin&lt;/p&gt;

&lt;pre&gt;convbin $FILE.ubx &lt;/pre&gt;

&lt;p&gt;Instead of convbin one can run the GUI &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkconv_qt &amp;amp;&lt;/code&gt; interactive.&lt;/p&gt;

&lt;p&gt;If files  $FILE.obs and $FILE.nav are available one can view some graphs with &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkplot_qt -r $FILE.obs $FILE.nav &amp;amp;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example the skyplot for Galileo for the period of 14 hours.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/skyplot_20260221.png&quot; alt=&quot;skyplot obs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now comes the part of preparing the correction.&lt;/p&gt;

&lt;p&gt;For this we need the RINEX (Receiver Independent Exchange Format) data from a reference station. I use the APOS-PP from BEV. BEV is the Federal Office of Metrology and Surveying ( Bundesamt für Eich- und Vermessungswesen ) in Austria and APOS-PP is a free service they offer. APOS-PP is the Austrian Position Service Post Processing. See &lt;a href=&quot;https://www.bev.gv.at/Services/Produkte/Grundlagenvermessung/APOS.html&quot; target=&quot;_blank&quot;&gt;APOS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The free available RINEX files are accessible short time after 00:00 UTC, so I fetched them next day. As there are about 60 reference stations one has to select a station which is near to the own position. In my case it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WIEN00AUT&lt;/code&gt;. As each file has only 1 hour of data therefore multiple files are needed. The files have type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.crx.gz&lt;/code&gt;. To get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rnx&lt;/code&gt; run first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gunzip&lt;/code&gt; and than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CRX2RNX&lt;/code&gt;.  CRX2RNX is also free available and should have at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version : ver.4.2.0&lt;/code&gt;. Older Versions are buggy. Finally all these files have to be combined to one file. This is done with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gfzrnx&lt;/code&gt; which is also free available. Current available &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VERSION: gfzrnx-2.2.0&lt;/code&gt; at &lt;a href=&quot;https://gnss.gfz.de/services/gfzrnx&quot; target=&quot;_blank&quot;&gt;GFZ.de&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now comes the real part of correction. There are 2 possibilities: &lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a GUI &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkpost_qt&lt;/code&gt; &lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;a command line tool: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rnx2rtkp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As first step I run the GUI. The reason is that some settings can be saved in a configuration file which can be used with the command line tool as argument. I configured under “Setting1” position mode “Static” and selected Navigation Systems: GPS, Galileo, Glonass and BDS. In selector “Positions” I entered below “Base Station” the position in X/Y/Z-ECEF format ( Earth-Centered, Earth-Fixed ). The values can be found in the final .rnx file in line marked with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APPROX POSITION XYZ&lt;/code&gt;. Don’t worry, it’s not approximately, it is exact. In case of WIEN00AUT it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4085097.7110 1200224.1682 4733306.7362&lt;/code&gt;. It’s important to enter the exact values, otherwise the calculated result is wrong. Now press the “Save” button and give the configuration file a name, e.g. “myconfig.conf”. Back to the main window enter the necessary file names. It is the .obs file for Rover, the .rnx file for the basestation and also needed .nav and .sbs file. In the solutions sections you get a proposal for the final position file name. Press the “Execute” button. After a while - maybe a minute - you get the result. Press the “Plot” button. It will start &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkplot_qt&lt;/code&gt; with the .pos file. If “Ground Track” is selected we can see that the position goes around only few centimeter during the last hours. Better to see using the “Position” tab.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/position_20260221.png&quot; alt=&quot;position&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see the curve swings in. As value I don’t use the last line of the result file, I use the average of the last 3 hours. Especially don’t use the first 2 lines for calculating the average.&lt;/p&gt;

&lt;p&gt;Instead of using the GUI with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtkpost_qt&lt;/code&gt; it’s also possible to use the command line tool &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rnx2rtkp&lt;/code&gt;. As we have now a config file we can apply this as argument with option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-k&lt;/code&gt; calling rnx2rtkp. A typical call looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rnx2rtkp -k myconfig.conf -o $FILE.pos $FILE.obs $FILE.rnx $FILE.nav $FILE.sbs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I run this scenario over several days. And this is the result&lt;/p&gt;

&lt;style&gt;
.tablelines table, .tablelines td, .tablelines th {
        border: 1px solid black;
        padding: 2px;
        }
&lt;/style&gt;

&lt;table class=&quot;tablelines&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;  date  &lt;/th&gt;
      &lt;th&gt;  longitude  &lt;/th&gt;
      &lt;th&gt;  latitude  &lt;/th&gt;
      &lt;th&gt;  altitude  &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026031081521.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928692997  &lt;/td&gt;
      &lt;td&gt;  16.28383533848  &lt;/td&gt;
      &lt;td&gt;  286.24190831482  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026035020026.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928677086  &lt;/td&gt;
      &lt;td&gt;  16.28383492415  &lt;/td&gt;
      &lt;td&gt;  286.22960926852  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026036020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928679808  &lt;/td&gt;
      &lt;td&gt;  16.28383546030  &lt;/td&gt;
      &lt;td&gt;  286.25004589815  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026037020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928691925  &lt;/td&gt;
      &lt;td&gt;  16.28383549683  &lt;/td&gt;
      &lt;td&gt;  286.25375274075  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026038020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928667076  &lt;/td&gt;
      &lt;td&gt;  16.28383506609  &lt;/td&gt;
      &lt;td&gt;  286.26456416667  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026039020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928684631  &lt;/td&gt;
      &lt;td&gt;  16.28383542232  &lt;/td&gt;
      &lt;td&gt;  286.27070575001  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026040020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928671316  &lt;/td&gt;
      &lt;td&gt;  16.28383543821  &lt;/td&gt;
      &lt;td&gt;  286.23612560186  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  result2026041020000.pos  &lt;/td&gt;
      &lt;td&gt;  48.14928684210  &lt;/td&gt;
      &lt;td&gt;  16.28383505095  &lt;/td&gt;
      &lt;td&gt;  286.26883948147  &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;  average  &lt;/td&gt;
      &lt;td&gt;  48.14928681131  &lt;/td&gt;
      &lt;td&gt;  16.28383527467  &lt;/td&gt;
      &lt;td&gt;  286.25194390275  &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;pre&gt;
4092523.4777    1195484.3731    4728180.6821
48.14928681131  16.28383527467  286.251
48 8 57.43252   16 17 1.80698
&lt;/pre&gt;

&lt;p&gt;All results are within a circle with a radius of 26 mm. The maximum distance between 2 points is 46 mm. &lt;br /&gt;
But when I compare this result with the result I got using gpsrinex (Method 2) then there is an offset of about 87 cm bevor the coordination transformation was applied but only 11 cm after the coordination transformation was applied. &lt;br /&gt;
Comparing this with the averaging method 1 I see an offset of 1.1 meters.&lt;/p&gt;

&lt;p&gt;A commandline tool to &lt;a href=&quot;https://github.com/hans-mayer/transform_ecef_wgs84&quot; target=&quot;_blank&quot;&gt;transform ecef wgs84&lt;/a&gt; data.&lt;/p&gt;

</description>
        <pubDate>Sat, 21 Feb 2026 13:43:00 +0100</pubDate>
        <link>https://blog.mayer.tv/2026/02/21/PPP-with-RTKLIB.html</link>
        <guid isPermaLink="true">https://blog.mayer.tv/2026/02/21/PPP-with-RTKLIB.html</guid>
        
        
        <category>GNSS</category>
        
      </item>
    
  </channel>
</rss>
