GNSS software for multipath analysis

paarnes paarnes Last update: Apr 16, 2024

GNSS Multipath Analysis

Python application PyPI version

GNSS_MultipathAnalysis is a software for analyzing the multipath effect on Global Navigation Satellite Systems (GNSS). This software is largely based on the MATLAB software GNSS_Receiver_QC_2020 made by Bjørn-Eirik Roald. Mainly it follows the same logic, just with Python syntax. However, there are added some other features like for instance:

  • Possible to use broadcasted ephemerides (not only SP3 files)
  • Also support RINEX v2.xx observation files
  • Makes polar plot of each satellite for each system
  • Makes polar plot that shows the multipath effect as function of azimuth and elevation angle.
  • Plots the Signal-To-Noise Ratio (SNR) wrt to time and elevation angle
  • Extracts GLONASS FCN from RINEX navigation file
  • Makes polar plot that shows the Signal-To-Noise Ratio (SNR) as function of azimuth and elevation angle
  • Possible to choose which navigation system to run analysis on (not hardcoded anymore)
  • Summary of the number of cycle slips detected in total (both ionospheric residuals and code- phase difference)

A considerable part of the results has been validated by comparing the results with estimates from RTKLIB. This software will be further developed, and feedback and suggestions are therefore gratefully received. Don't hesitate to report if you find bugs or missing functionality. Either by e-mail or by raising an issue here in GitHub.

The main function is called "GNSS_MultipathAnalysis.py" and takes in different arguments. Two arguments are mandatory:

  • A RINEX Observation file
  • A sp3/eph file containing precise satellite coordinates or a RINEX 3 navigation file

The rest of the arguments are optional. Their default values are described in the function description. By default, this software will provide the results in forms of plots and an analysis report as a text file. In addition, it exports the results as a pickle file which can be imported as a dictionary in python for instance.

Installation

The software can be installed using pip in the terminal:

$ pip install gnssmultipath

Note: In the example plots, TEX is used to get prettier text formatting. However, this requires TEX/LaTex to be installed on your computer. The program will first try to use TEX, and if it's not possible, standard text formatting will be used. So TEX/LaTex is not required to run the program and make plots.

The steps are:

  1. Reads in the RINEX observation file

  2. Reads the RINEX navigation file or the precise satellite coordinates in SP3-format (depends on what’s provided)

  3. If a navigation file is provided, the satellite coordinates will be transformed from Kepler-elements to ECEF for GPS, Galileo and BeiDou. For GLONASS the navigation file is containing a state vector. The coordinates then get interpolated to the current epoch by solving the differential equation using a 4th order Runge-Kutta. If a SP3 file is provided, the interpolation is done by a barycentric Lagrange interpolation.

  4. Satellites elevation and azimuth angles get computed.

  5. Cycle slip detection by using both ionospheric residuals and a code-phase combination. These linear combinations are given as $$\dot{I} = \frac{1}{\alpha-1}\left(\Phi_1 - \Phi_2\right)/\Delta t$$ $$d\Phi_1R_1 = \Phi_1 - R_1$$ The threshold values can be set by the user, and the default values are set to $0.0667 [\frac{m}{s}]$ and $6.67[\frac{m}{s}]$ for the ionospheric residuals and code-phase combination respectively.

  6. Multipath estimates get computed by making a linear combination of the code and phase observation. PS: A dual frequency receiver is necessary because observations from two different bands/frequency are needed. $$MP_1 = R_1 - \left(1+\frac{2}{\alpha - 1}\right)\Phi_1 + \left(\frac{2}{\alpha - 1}\right)\Phi_2$$ where $R_1$ is the code observation on band 1, $\Phi_1$ and $\Phi_2$ is phase observation on band 1 and band 2 respectively. Furthermore $\alpha$ is the ratio between the two frequency squared $\alpha=\frac{{f}^2_1}{{f}^2_2}$

  7. Based on the multipath estimates computed in step 6, both weighted and unweighted RMS-values get computed. The RMS value has unit meter, and is given by $$RMS=\sqrt{\frac{\sum\limits_{i=1}^{N_{sat}}\sum\limits_{j=1}^{N_{epohcs}} MP_{ij}}{N_{est}}}$$ For the weighted RMS value, the satellite elevation angle is used in a weighting function defined as $$w =\frac{1}{4sin^2\beta}$$ for every estimates with elevation angle $\beta$ is below $30^{\circ}$ and $w =1$ for $\beta > 30^{\circ}$.

  8. Several plot will be generated (if not set to FALSE):

    • Ionospheric delay wrt time and zenith mapped ionospheric delay (combined)

    • The Multipath effect plotted wrt time and elevation angle (combined)

    • Barplot showing RMS values for each signal and system

    • Polar plot of the multipath effect as function of elevation angle and azimuth

    • Polar plot of each observed satellite in the system

    • Signal-To-Noise Ratio (SNR) plotted wrt time and elevation angle (combine)

    • Polar plot of Signal-To-Noise Ratio (SNR)

  9. Exporting the results as a pickle file which easily can be imported into python as a dictionary

  10. The results in form of a report get written to a text file with the same name as the RINEX observation file.

How to run it

An example file on how to call the program is located here. This will show some examples on how to run the analysis with different user defined arguments, how to read in the resultfile (pickle file), and in addition it shows how to use only the RINEX reading routine.

Some simple examples on how to use the software:

Run a multipath analysis using a SP3 file and only mandatory arguments

from gnssmultipath import GNSS_MultipathAnalysis

rinObs_file = 'OPEC00NOR_S_20220010000_01D_30S_MO_3.04'
SP3_file    = 'SP3_20220010000.eph'
analysisResults = GNSS_MultipathAnalysis(rinex_obs_file, sp3NavFilename_1 = SP3_file)

Run a multipath analysis using a RINEX navigation file with SNR and a defined datarate for ephemerides

from gnssmultipath import GNSS_MultipathAnalysis

# Input arguments
rinObs_file = 'OPEC00NOR_S_20220010000_01D_30S_MO_3.04'
rinNav_file = 'BRDC00IGS_R_20220010000_01D_MN.rnx
output_folder = 'C:\Users\xxxx\Results_Multipath'
cutoff_elevation_angle = 10 # drop satellites lower than 10 degrees
nav_data_rate = 60 # desired datarate for ephemerides (to improve speed)

analysisResults = GNSS_MultipathAnalysis(rinex_obs_file,
					broadcastNav1=rinNav_file,
					include_SNR = True,
					outputDir = output_folder,
					nav_data_rate = nav_data_rate,
					cutoff_elevation_angle = cutoff_elevation_angle)

Read a RINEX observation file

from gnssmultipath import readRinexObs

rinObs_file = 'OPEC00NOR_S_20220010000_01D_30S_MO_3.04'
GNSS_obs, GNSS_LLI, GNSS_SS, GNSS_SVs, time_epochs, nepochs, GNSSsystems,\
		obsCodes, approxPosition, max_sat, tInterval, markerName, rinexVersion, recType, timeSystem, leapSec, gnssType,\
		rinexProgr, rinexDate, antDelta, tFirstObs, tLastObs, clockOffsetsON, GLO_Slot2ChannelMap, success = \
		readRinexObs(rinObs_file)

Read a RINEX navigation file (v.3)

from gnssmultipath import Rinex_v3_Reader

rinNav_file = 'BRDC00IGS_R_20220010000_01D_MN.rnx'
navdata = Rinex_v3_Reader().read_rinex_nav(rinNav_file, data_rate=60)

Read in the results from a uncompressed pickle file

from gnssmultipath import PickleHandler

path_to_picklefile = 'analysisResults.pkl'
result_dict = PickleHandler.read_pickle(path_to_picklefile)


Read in the results from a compressed pickle file

from gnssmultipath import PickleHandler

path_to_picklefile = 'analysisResults.pkl'
result_dict = PickleHandler.read_zstd_pickle(path_to_picklefile)

Subscribe to our newsletter