├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── usage_feedback.md └── workflows │ ├── build.yml │ ├── pip-install.yml │ ├── pylint.yml │ └── pypi-release.yml ├── .gitignore ├── .python-version ├── .readthedocs.yaml ├── CITATION.bib ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── build_docs.sh ├── data └── unit_test │ ├── android │ ├── measurements │ │ ├── all_sensors.txt │ │ ├── filter_test.txt │ │ └── pixel6.txt │ ├── nmea │ │ └── pixel6.nmea │ └── rinex_obs │ │ └── pixel6.23o │ ├── clk │ ├── COD0MGXFIN_20211180000_01D_30S_CLK.CLK │ ├── COD0OPSRAP_20230730000_01D_30S_CLK.CLK │ ├── GFZ0MGXRAP_20201380000_01D_30S_CLK.CLK │ ├── WUM0MGXFIN_20190730000_01D_30S_CLK.CLK │ ├── com19402.clk │ ├── gbm20340.clk │ ├── grg21553.clk │ ├── grg21553_nodata.clk │ └── wum19923.clk │ ├── fde │ ├── no_suspects.csv │ └── nothing_removed.csv │ ├── google_decimeter_2021 │ ├── Pixel4XL_derived.csv │ ├── Pixel4_GnssLog.txt │ ├── Pixel4_derived.csv │ ├── Pixel4_derived_clkdiscnt.csv │ ├── Pixel4_ground_truth.csv │ └── Pixel4_ground_truth_clkdiscnt.csv │ ├── google_decimeter_2022 │ ├── alt_nan_ground_truth.csv │ ├── device_gnss.csv │ └── ground_truth.csv │ ├── google_decimeter_2023 │ └── 2023-09-07-18-59-us-ca │ │ └── pixel7pro │ │ ├── device_gnss.csv │ │ ├── gnss_log.txt │ │ └── ground_truth.csv │ ├── navdata │ ├── navdata_only_header.csv │ ├── navdata_test_dtypes.csv │ ├── navdata_test_headless.csv │ ├── navdata_test_inf.csv │ ├── navdata_test_int_first.csv │ ├── navdata_test_missing.csv │ ├── navdata_test_mixed.csv │ ├── navdata_test_nan.csv │ └── navdata_test_simple.csv │ ├── nmea │ ├── nmea_no_checksum.nmea │ ├── nmea_w_correct_checksum.nmea │ └── nmea_w_wrong_checksum.nmea │ ├── rinex │ ├── nav │ │ ├── BRDC00WRD_S_20230730000_01D_MN.rnx │ │ ├── BRDM00DLR_R_20130010000_01D_MN.rnx │ │ ├── BRDM00DLR_S_20230730000_01D_MN.rnx │ │ ├── BRDM00DLR_S_20230730000_01D_MN_no_gps_iono.rnx │ │ ├── GOLD00USA_R_20201370000_01D_EN.rnx │ │ ├── VOIM00MDG_R_20140010000_01D_MN.rnx │ │ ├── WTZS00DEU_R_20230800000_01D_MN.rnx │ │ ├── ZIM200CHE_R_20201390000_01D_GN.rnx │ │ ├── ZIM200CHE_R_20201390000_01D_RN.rnx │ │ ├── brdc0730.17n │ │ ├── brdc1180.21n │ │ ├── brdc1190.21n │ │ ├── brdc1200.21n │ │ ├── brdc1360.20n │ │ ├── brdc1370.20g │ │ ├── brdc1370.20n │ │ ├── brdc1370_no_leapseconds.20n │ │ ├── zim21380.20g │ │ └── zim21380.20n │ └── obs │ │ ├── rinex_obs_mixed_types.20o │ │ ├── rinex_obs_single_type_only.22o │ │ └── z_tracking.rnx │ ├── smartloc │ └── tu_chemnitz_berlin_1_raw.csv │ ├── sp3 │ ├── COD0MGXFIN_20211180000_01D_05M_ORB.SP3 │ ├── COD0OPSRAP_20230730000_01D_05M_ORB.SP3 │ ├── GFZ0MGXRAP_20201380000_01D_05M_ORB.SP3 │ ├── com19402.sp3 │ ├── grg21553.sp3 │ └── grg21553_nodata.sp3 │ └── vis │ └── sp3_g05.csv ├── dev └── .gitkeep ├── docs ├── Makefile ├── make.bat └── source │ ├── conf.py │ ├── contributing │ ├── contributing.rst │ ├── development.rst │ ├── documentation.rst │ └── testing.rst │ ├── img │ ├── glp_architecture.svg │ ├── gnss_logger_app.jpg │ ├── nav_lab_fav.ico │ ├── nav_lab_logo.png │ └── skyplot.png │ ├── index.rst │ ├── install.rst │ ├── reference │ ├── algorithms │ │ ├── fde.rst │ │ ├── gnss_filters.rst │ │ ├── modules.rst │ │ ├── residuals.rst │ │ └── snapshot.rst │ ├── navdata │ │ ├── modules.rst │ │ ├── navdata.rst │ │ └── operations.rst │ ├── parsers │ │ ├── android.rst │ │ ├── clk.rst │ │ ├── google_decimeter.rst │ │ ├── modules.rst │ │ ├── nmea.rst │ │ ├── rinex_nav.rst │ │ ├── rinex_obs.rst │ │ ├── smartloc.rst │ │ └── sp3.rst │ ├── reference.rst │ ├── test_algorithms │ │ ├── modules.rst │ │ ├── test_fde.rst │ │ ├── test_gnss_filters.rst │ │ ├── test_residuals.rst │ │ └── test_snapshot.rst │ ├── test_navdata │ │ ├── modules.rst │ │ ├── test_navdata.rst │ │ └── test_operations.rst │ ├── test_parsers │ │ ├── modules.rst │ │ ├── test_android.rst │ │ ├── test_clk.rst │ │ ├── test_google_decimeter.rst │ │ ├── test_nmea.rst │ │ ├── test_rinex_nav.rst │ │ ├── test_rinex_obs.rst │ │ ├── test_smartloc.rst │ │ └── test_sp3.rst │ ├── test_utils │ │ ├── modules.rst │ │ ├── test_coordinates.rst │ │ ├── test_dop.rst │ │ ├── test_ephemeris_downloader.rst │ │ ├── test_file_operations.rst │ │ ├── test_filters.rst │ │ ├── test_gnss_models.rst │ │ ├── test_sv_models.rst │ │ └── test_time_conversions.rst │ ├── test_visualizations │ │ ├── modules.rst │ │ ├── test_plot_map.rst │ │ ├── test_plot_metric.rst │ │ ├── test_plot_skyplot.rst │ │ └── test_style.rst │ ├── timing_comparisons_notebook.nblink │ ├── utils │ │ ├── constants.rst │ │ ├── coordinates.rst │ │ ├── dop.rst │ │ ├── ephemeris_downloader.rst │ │ ├── file_operations.rst │ │ ├── filters.rst │ │ ├── gnss_models.rst │ │ ├── modules.rst │ │ ├── sv_models.rst │ │ └── time_conversions.rst │ └── visualizations │ │ ├── modules.rst │ │ ├── plot_map.rst │ │ ├── plot_metric.rst │ │ ├── plot_skyplot.rst │ │ └── style.rst │ ├── requirements.txt │ ├── troubleshooting.rst │ └── tutorials │ ├── algorithms │ ├── tutorials_fde_notebook.nblink │ ├── tutorials_gnss_filters_notebook.nblink │ ├── tutorials_residuals_notebook.nblink │ └── tutorials_snapshot_notebook.nblink │ ├── navdata │ ├── tutorials_navdata_notebook.nblink │ └── tutorials_operations_notebook.nblink │ ├── parsers │ ├── tutorials_android_notebook.nblink │ ├── tutorials_clk_notebook.nblink │ ├── tutorials_google_decimeter_notebook.nblink │ ├── tutorials_new_parsers_notebook.nblink │ ├── tutorials_nmea_notebook.nblink │ ├── tutorials_rinex_nav_notebook.nblink │ ├── tutorials_rinex_obs_notebook.nblink │ ├── tutorials_smartloc_notebook.nblink │ └── tutorials_sp3_notebook.nblink │ ├── tutorials.rst │ ├── utils │ ├── tutorials_constants_notebook.nblink │ ├── tutorials_coordinates_notebook.nblink │ ├── tutorials_dop_notebook.nblink │ ├── tutorials_ephemeris_downloader_notebook.nblink │ ├── tutorials_file_operations_notebook.nblink │ ├── tutorials_filters_notebook.nblink │ ├── tutorials_gnss_models_notebook.nblink │ ├── tutorials_sv_models_notebook.nblink │ └── tutorials_time_conversions_notebook.nblink │ └── visualizations │ ├── tutorials_plot_map_notebook.nblink │ ├── tutorials_plot_metric_notebook.nblink │ ├── tutorials_plot_skyplot_notebook.nblink │ └── tutorials_style_notebook.nblink ├── gnss_lib_py ├── __init__.py ├── algorithms │ ├── fde.py │ ├── gnss_filters.py │ ├── residuals.py │ └── snapshot.py ├── navdata │ ├── navdata.py │ └── operations.py ├── parsers │ ├── android.py │ ├── clk.py │ ├── google_decimeter.py │ ├── nmea.py │ ├── rinex_nav.py │ ├── rinex_obs.py │ ├── smartloc.py │ └── sp3.py ├── utils │ ├── constants.py │ ├── coordinates.py │ ├── dop.py │ ├── ephemeris_downloader.py │ ├── file_operations.py │ ├── filters.py │ ├── gnss_models.py │ ├── sv_models.py │ └── time_conversions.py └── visualizations │ ├── plot_map.py │ ├── plot_metric.py │ ├── plot_skyplot.py │ └── style.py ├── notebooks ├── timing_comparisons.ipynb └── tutorials │ ├── algorithms │ ├── fde.ipynb │ ├── gnss_filters.ipynb │ ├── residuals.ipynb │ └── snapshot.ipynb │ ├── data │ └── myreceiver.csv │ ├── navdata │ ├── navdata.ipynb │ └── operations.ipynb │ ├── parsers │ ├── android.ipynb │ ├── clk.ipynb │ ├── google_decimeter.ipynb │ ├── new_parsers.ipynb │ ├── nmea.ipynb │ ├── rinex_nav.ipynb │ ├── rinex_obs.ipynb │ ├── smartloc.ipynb │ └── sp3.ipynb │ ├── utils │ ├── constants.ipynb │ ├── coordinates.ipynb │ ├── dop.ipynb │ ├── ephemeris_downloader.ipynb │ ├── file_operations.ipynb │ ├── filters.ipynb │ ├── gnss_models.ipynb │ ├── sv_models.ipynb │ └── time_conversions.ipynb │ └── visualizations │ ├── plot_map.ipynb │ ├── plot_metric.ipynb │ ├── plot_skyplot.ipynb │ └── style.ipynb ├── poetry.lock ├── pyproject.toml ├── pytest.ini ├── requirements.txt ├── results └── .gitkeep └── tests ├── algorithms ├── test_fde.py ├── test_gnss_filters.py ├── test_residuals.py └── test_snapshot.py ├── conftest.py ├── navdata ├── test_navdata.py └── test_operations.py ├── parsers ├── .gitkeep ├── test_android.py ├── test_clk.py ├── test_google_decimeter.py ├── test_nmea.py ├── test_rinex_nav.py ├── test_rinex_obs.py ├── test_smartloc.py └── test_sp3.py ├── utils ├── .gitkeep ├── test_coordinates.py ├── test_dop.py ├── test_ephemeris_downloader.py ├── test_file_operations.py ├── test_filters.py ├── test_gnss_models.py ├── test_sv_models.py └── test_time_conversions.py └── visualizations ├── test_plot_map.py ├── test_plot_metric.py ├── test_plot_skyplot.py └── test_style.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **System Information (please complete the following information):** 27 | - OS: [e.g. Ubuntu] 28 | - OS Version: [e.g. 20.04] 29 | - Python Version: [e.g. 3.9.10] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Propose a new feature 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the proposed feature** 11 | Explain in detail the intended feature, its purpose and how it would work. 12 | Keep the scope as narrow as possible, which will make it easier to implement. 13 | 14 | **Motivate the proposed feature** 15 | Help us understand why the proposed feature would help you and/or make `gnss_lib_py` easier to use. 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/usage_feedback.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Usage feedback 3 | about: Let us know if gnss_lib_py has been helpful to you! 4 | title: '' 5 | labels: usage feedback 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Functionality Usage** 11 | What specific functionalities of `gnss_lib_py ` do you use the most? 12 | 13 | **Application Usage** 14 | Are you using `gnss_lib_py` for a specific application or course? 15 | 16 | **Suggested Changes** 17 | Is there anything about `gnss_lib_py` that you would change? 18 | 19 | **Usage Intuition** 20 | Is there anything you find particular confusing about how to use `gnss_lib_py`? 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: build 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - v*.*.* 11 | pull_request: 12 | branches: 13 | - main 14 | - v*.*.* 15 | workflow_dispatch: 16 | 17 | jobs: 18 | build: 19 | name: Python ${{ matrix.python-version }}, OS ${{ matrix.os }} 20 | runs-on: ${{ matrix.os }} 21 | strategy: 22 | matrix: 23 | python-version: ["3.9","3.10","3.11","3.12"] 24 | os: [ubuntu-latest, macos-latest, windows-latest] 25 | fail-fast : false 26 | defaults: 27 | run: 28 | shell: bash 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: Set up Python ${{ matrix.python-version }} 33 | id: setup-python 34 | uses: actions/setup-python@v5 35 | with: 36 | python-version: ${{ matrix.python-version }} 37 | - name: Install Poetry 38 | uses: snok/install-poetry@v1 39 | with: 40 | virtualenvs-create: true 41 | virtualenvs-in-project: true 42 | installer-parallel: true # default option selected currently 43 | # Load cached environment, if it exists 44 | - name: Load cached poetry environment 45 | id: cached-poetry-dependencies 46 | uses: actions/cache@v4 47 | with: 48 | path: .venv 49 | key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} 50 | - name: Install dependencies and root package 51 | if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' 52 | run: | 53 | poetry install --no-interaction --no-root 54 | poetry install --no-interaction 55 | # Install pandoc for building docs 56 | - name: Install pandoc for Ubuntu 57 | if: matrix.os == 'ubuntu-latest' 58 | run: sudo apt install pandoc 59 | - name: Install pandoc for Windows 60 | if: matrix.os == 'windows-latest' 61 | run: choco install pandoc --no-progress 62 | - name: Install pandoc for MacOS 63 | if: matrix.os == 'macos-latest' 64 | run: brew install pandoc 65 | 66 | - name: Test with pytest 67 | run: | 68 | source $VENV 69 | poetry run pytest --cov=gnss_lib_py/algorithms --cov=gnss_lib_py/navdata --cov=gnss_lib_py/parsers --cov=gnss_lib_py/utils --cov=gnss_lib_py/visualizations --cov-report=xml 70 | - name: Upload coverage report to code-cov 71 | uses: codecov/codecov-action@v4 72 | with: 73 | fail_ci_if_error: true 74 | token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos 75 | - name: Test if docs are building 76 | run: | 77 | ./build_docs.sh 78 | readme: 79 | runs-on: ubuntu-latest 80 | name: Check if index.rst and README.md weren't changed together 81 | steps: 82 | - uses: actions/checkout@v4 83 | with: 84 | fetch-depth: 0 85 | 86 | - name: Get changed files since last remote commit 87 | id: changed-files 88 | uses: tj-actions/changed-files@v46.0.1 89 | 90 | - name: Check if index.rst changed when README.md file changes 91 | if: contains(steps.changed-files.outputs.modified_files, 'README.md') && !contains(steps.changed-files.outputs.modified_files, 'docs/source/index.rst') 92 | run: | 93 | echo "README.md has changed but index.rst has not!" 94 | exit 1 95 | 96 | - name: Check if README.md changed when index.rst file changes 97 | if: contains(steps.changed-files.outputs.modified_files, 'docs/source/index.rst') && !contains(steps.changed-files.outputs.modified_files, 'README.md') 98 | run: | 99 | echo "index.rst has changed but README.md has not!" 100 | exit 1 101 | -------------------------------------------------------------------------------- /.github/workflows/pip-install.yml: -------------------------------------------------------------------------------- 1 | name: pip-install 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - v*.*.* 8 | workflow_dispatch: 9 | 10 | 11 | jobs: 12 | build: 13 | name: Testing pip install, updating requirements.txt 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | python-version: ["3.9"] 18 | os: [ubuntu-latest] 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install using pip 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install -r requirements.txt 30 | pip install -e . 31 | - name: Test on pytest 32 | run: 33 | pytest 34 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: pylint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - v*.*.* 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | name: Linting code 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: ["3.9"] 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up Python ${{ matrix.python-version }} 20 | id: setup-python 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Install Poetry 25 | uses: snok/install-poetry@v1 26 | with: 27 | virtualenvs-create: true 28 | virtualenvs-in-project: true 29 | installer-parallel: true # default option selected currently 30 | - name: Load cached poetry environment 31 | id: cached-poetry-dependencies 32 | uses: actions/cache@v4 33 | with: 34 | path: .venv 35 | key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} 36 | - name: Install dependencies 37 | if: steps.cached-poetry-dependencies.outputs.catch-hit != 'true' 38 | run: | 39 | poetry install --no-interaction --no-root 40 | poetry install --no-interaction 41 | - name: Analysing the code with pylint 42 | run: | 43 | poetry run pylint $(git ls-files 'gnss_lib_py/*.py') || poetry run pylint-exit --error-fail $? 44 | -------------------------------------------------------------------------------- /.github/workflows/pypi-release.yml: -------------------------------------------------------------------------------- 1 | # workflow copied from combination of 2 | # 1) https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ 3 | # 2) https://www.caktusgroup.com/blog/2021/02/11/automating-pypi-releases/ 4 | 5 | name: pypi-release 6 | 7 | on: 8 | release: 9 | types: [created] 10 | workflow_dispatch: 11 | 12 | jobs: 13 | deploy: 14 | name: Build and publish Python distribution to PyPI 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up Python 3.10 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: "3.10" 23 | 24 | - name: Install pypa/build 25 | run: >- 26 | python -m 27 | pip install 28 | build 29 | --user 30 | - name: Build a binary wheel and a source tarball 31 | run: >- 32 | python -m 33 | build 34 | --sdist 35 | --wheel 36 | --outdir dist/ 37 | . 38 | - name: Publish distribution to PyPI 39 | uses: pypa/gh-action-pypi-publish@release/v1 40 | with: 41 | password: ${{ secrets.PYPI_API_TOKEN }} 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ######################################## 2 | ####### Project specific folders ####### 3 | ######################################## 4 | data/* 5 | # Including small datasets used for unit testing NavData objects 6 | !data/unit_test/ 7 | 8 | # development folder 9 | dev/* 10 | !dev/.gitkeep 11 | gnss_lib_py_dev/ 12 | 13 | # results folder 14 | results/* 15 | !results/.gitkeep 16 | 17 | ######################################## 18 | ##### Project specific file types ###### 19 | ######################################## 20 | 21 | # ignore downloaded csv files in notebook tutorials 22 | *.csv 23 | !data/unit_test/**/*.csv 24 | !notebooks/tutorials/data/myreceiver.csv 25 | 26 | # ignore txt files in notebook tutorials 27 | *.txt 28 | !docs/source/requirements.txt 29 | !requirements.txt 30 | !data/unit_test/**/*.txt 31 | 32 | # Ignore downloaded precise ephimerides files by default 33 | *.sp3 34 | *.SP3 35 | *.clk 36 | *.CLK 37 | 38 | # Include unit test files for precise ephimerides 39 | !data/unit_test/*/*.sp3 40 | !data/unit_test/*/*.SP3 41 | !data/unit_test/*/*.clk 42 | !data/unit_test/*/*.CLK 43 | 44 | # Ignore NMEA files by default 45 | *.nmea 46 | # Include unit test NMEA files 47 | !data/unit_test/**/*.nmea 48 | 49 | # Ignore downloaded broadcast ephimerides files by default 50 | *.*n 51 | *.*o 52 | *.*g 53 | *.rnx 54 | # Include unit test files for broadcast ephemerides 55 | !data/unit_test/**/*.*n 56 | !data/unit_test/**/*.*o 57 | !data/unit_test/**/*.*g 58 | !data/unit_test/**/*.rnx 59 | 60 | ######################################## 61 | ##### Common Python and IDE files ###### 62 | ######################################## 63 | 64 | #Excluding VS Code files 65 | .vscode/* 66 | */.vscode/ 67 | 68 | #Excluding PyCharm files 69 | .idea/ 70 | 71 | # Byte-compiled / optimized / DLL files 72 | __pycache__/ 73 | *.py[cod] 74 | *$py.class 75 | 76 | # C extensions 77 | *.so 78 | 79 | # Distribution / packaging 80 | .Python 81 | build/ 82 | develop-eggs/ 83 | dist/ 84 | downloads/ 85 | eggs/ 86 | .eggs/ 87 | lib/ 88 | lib64/ 89 | parts/ 90 | sdist/ 91 | var/ 92 | wheels/ 93 | pip-wheel-metadata/ 94 | share/python-wheels/ 95 | *.egg-info/ 96 | .installed.cfg 97 | *.egg 98 | MANIFEST 99 | 100 | # PyInstaller 101 | # Usually these files are written by a python script from a template 102 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 103 | *.manifest 104 | *.spec 105 | 106 | # Installer logs 107 | pip-log.txt 108 | pip-delete-this-directory.txt 109 | 110 | # Unit test / coverage reports 111 | htmlcov/ 112 | .tox/ 113 | .nox/ 114 | .coverage 115 | .coverage.* 116 | .cache 117 | nosetests.xml 118 | coverage.xml 119 | *.cover 120 | *.py,cover 121 | .hypothesis/ 122 | .pytest_cache/ 123 | 124 | # Translations 125 | *.mo 126 | *.pot 127 | 128 | # Django stuff: 129 | *.log 130 | local_settings.py 131 | db.sqlite3 132 | db.sqlite3-journal 133 | 134 | # Flask stuff: 135 | instance/ 136 | .webassets-cache 137 | 138 | # Scrapy stuff: 139 | .scrapy 140 | 141 | # Sphinx documentation 142 | docs/build/ 143 | 144 | # PyBuilder 145 | target/ 146 | 147 | # Jupyter Notebook 148 | .ipynb_checkpoints 149 | 150 | # IPython 151 | profile_default/ 152 | ipython_config.py 153 | 154 | # pipenv 155 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 156 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 157 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 158 | # install all needed dependencies. 159 | #Pipfile.lock 160 | 161 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 162 | __pypackages__/ 163 | 164 | # Celery stuff 165 | celerybeat-schedule 166 | celerybeat.pid 167 | 168 | # SageMath parsed files 169 | *.sage.py 170 | 171 | # Environments 172 | .env 173 | .venv 174 | env/ 175 | venv/ 176 | ENV/ 177 | env.bak/ 178 | venv.bak/ 179 | 180 | # Spyder project settings 181 | .spyderproject 182 | .spyproject 183 | 184 | # Rope project settings 185 | .ropeproject 186 | 187 | # mkdocs documentation 188 | /site 189 | 190 | # mypy 191 | .mypy_cache/ 192 | .dmypy.json 193 | dmypy.json 194 | 195 | # Pyre type checker 196 | .pyre/ 197 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.9.19 2 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Version of the configuration file (Required) 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/source/conf.py 17 | 18 | # Optionally declare the Python requirements required to build your docs 19 | python: 20 | install: 21 | - requirements: docs/source/requirements.txt 22 | - method: pip 23 | path: . 24 | -------------------------------------------------------------------------------- /CITATION.bib: -------------------------------------------------------------------------------- 1 | @inproceedings{knowlesmodular2022, 2 | title = {A Modular and Extendable GNSS Python Library}, 3 | author={Knowles, Derek and Kanhere, Ashwin V and Bhamidipati, Sriramya and Gao, Grace}, 4 | booktitle={Proceedings of the 35th International Technical Meeting of the Satellite Division of The Institute of Navigation (ION GNSS+ 2022)}, 5 | institution = {Stanford University}, 6 | year = {2022 [Online]}, 7 | url = {https://github.com/Stanford-NavLab/gnss_lib_py}, 8 | } 9 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Ashwin Kanhere 2 | Derek Knowles 3 | Shubh Gupta 4 | Adam Dai 5 | Bradley Collicott 6 | Shivam Soni 7 | Sriramya Bhamidipati 8 | Dalton Vega 9 | Daniel Neamati 10 | Sandro Klarer 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Stanford-NavLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # export requirements.txt for buildings docs 3 | poetry config warnings.export false 4 | poetry export -f requirements.txt --output ./docs/source/requirements.txt --with dev --without-hashes 5 | # export requirements.txt for Conda environment setup 6 | poetry export -f requirements.txt --output ./requirements.txt --without-hashes 7 | cd docs 8 | 9 | echo "Rebuilding References" 10 | rm -r ./source/reference/algorithms/* 11 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/algorithms/ ./../gnss_lib_py/algorithms/ 12 | rm -r ./source/reference/navdata/* 13 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/navdata/ ./../gnss_lib_py/navdata/ 14 | rm -r ./source/reference/parsers/* 15 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/parsers/ ./../gnss_lib_py/parsers/ 16 | rm -r ./source/reference/utils/* 17 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/utils/ ./../gnss_lib_py/utils/ 18 | rm -r ./source/reference/visualizations/* 19 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/visualizations/ ./../gnss_lib_py/visualizations/ 20 | rm -r ./source/reference/test_algorithms/* 21 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/test_algorithms/ ./../tests/algorithms/ 22 | rm -r ./source/reference/test_navdata/* 23 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/test_navdata/ ./../tests/navdata/ 24 | rm -r ./source/reference/test_parsers/* 25 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/test_parsers/ ./../tests/parsers/ 26 | rm -r ./source/reference/test_utils/* 27 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/test_utils/ ./../tests/utils/ 28 | rm -r ./source/reference/test_visualizations/* 29 | poetry run sphinx-apidoc -f -M -q -o ./source/reference/test_visualizations/ ./../tests/visualizations/ 30 | 31 | # remove previously downloaded .csv files if they exist 32 | rm ./source/*/*.csv 33 | 34 | echo "Cleaning existing make" 35 | poetry run make clean 36 | 37 | echo "Building docs in html" 38 | poetry run make html 39 | 40 | cd .. 41 | -------------------------------------------------------------------------------- /data/unit_test/android/measurements/all_sensors.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Header Description: 3 | # 4 | # Version: v3.0.6.4 Platform: 14 Manufacturer: Google Model: Pixel 7 5 | # 6 | # Raw,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos,BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond,HardwareClockDiscontinuityCount,Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos,ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond,PseudorangeRateUncertaintyMetersPerSecond,AccumulatedDeltaRangeState,AccumulatedDeltaRangeMeters,AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz,CarrierCycles,CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb,ConstellationType,AgcDb,BasebandCn0DbHz,FullInterSignalBiasNanos,FullInterSignalBiasUncertaintyNanos,SatelliteInterSignalBiasNanos,SatelliteInterSignalBiasUncertaintyNanos,CodeType,ChipsetElapsedRealtimeNanos 7 | # 8 | # UncalAccel,utcTimeMillis,elapsedRealtimeNanos,UncalAccelXMps2,UncalAccelYMps2,UncalAccelZMps2,BiasXMps2,BiasYMps2,BiasZMps2 9 | # 10 | # Accel,utcTimeMillis,elapsedRealtimeNanos,AccelXMps2,AccelYMps2,AccelZMps2 11 | # 12 | # UncalGyro,utcTimeMillis,elapsedRealtimeNanos,UncalGyroXRadPerSec,UncalGyroYRadPerSec,UncalGyroZRadPerSec,DriftXRadPerSec,DriftYRadPerSec,DriftZRadPerSec 13 | # 14 | # Gyro,utcTimeMillis,elapsedRealtimeNanos,GyroXRadPerSec,GyroYRadPerSec,GyroZRadPerSec 15 | # 16 | # UncalMag,utcTimeMillis,elapsedRealtimeNanos,UncalMagXMicroT,UncalMagYMicroT,UncalMagZMicroT,BiasXMicroT,BiasYMicroT,BiasZMicroT 17 | # 18 | # Mag,utcTimeMillis,elapsedRealtimeNanos,MagXMicroT,MagYMicroT,MagZMicroT 19 | # 20 | # OrientationDeg,utcTimeMillis,elapsedRealtimeNanos,yawDeg,rollDeg,pitchDeg 21 | # 22 | # Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees,elapsedRealtimeNanos,VerticalAccuracyMeters,MockLocation,NumberOfUsedSignals,VerticalSpeedAccuracyMps,SolutionType 23 | # 24 | #, 25 | 26 | # Nav,Svid,Type,Status,MessageId,Sub-messageId,Data(Bytes) 27 | # 28 | # Status,UnixTimeMillis,SignalCount,SignalIndex,ConstellationType,Svid,CarrierFrequencyHz,Cn0DbHz,AzimuthDegrees,ElevationDegrees,UsedInFix,HasAlmanacData,HasEphemerisData,BasebandCn0DbHz 29 | # 30 | # Agc,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos,BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond,HardwareClockDiscontinuityCount,AgcDb,CarrierFrequencyHz,ConstellationType 31 | # 32 | UncalMag,1699400576748,16118834125931,-54.1436,-88.937996,-147.3638,-79.950134,-76.57953,-113.967804 33 | UncalGyro,1699400576750,16118836475732,-0.06261369,-0.09315695,0.036651913,-0.0020643917,-0.0038384064,-0.0013324362 34 | UncalAccel,1699400576750,16118836475732,0.17288144,0.44925246,9.886545,0.065623306,0.002461203,-0.031848617 35 | 36 | Mag,1699400576748,16118834125931,-54.1436,-88.937996,-147.3638 37 | Gyro,1699400576750,16118836475732,-0.06261369,-0.09315695,0.036651913 38 | Accel,1699400576750,16118836475732,0.17288144,0.44925246,9.886545 39 | OrientationDeg,1699400576750,16118836475732,245.0,0.0,-2.0 40 | -------------------------------------------------------------------------------- /data/unit_test/fde/nothing_removed.csv: -------------------------------------------------------------------------------- 1 | gnss_id,sv_id,x_rx_m,y_rx_m,z_rx_m,b_rx_m,gps_millis,gnss_sv_id,x_sv_m,y_sv_m,z_sv_m,vx_sv_mps,vy_sv_mps,vz_sv_mps,b_sv_m,b_dot_sv_mps,el_sv_deg,az_sv_deg,corr_pr_m,raw_pr_m,fault_gt 2 | beidou,19,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,C19,11393312.437632836,-17170481.673205025,18859922.40554178,2060.069349804306,-607.1515716541315,-1798.2469330284068,-268589.7241701188,-0.0003636368244325,34.24943599679211,288.8110497946775,23856050.43792817,24124640.16209829,0 3 | beidou,20,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,C20,24991577.16737436,-11481778.118580334,4843495.100212388,551.4350597216028,-82.7671242534204,-3051.060542013859,203932.5771388628,-0.0057194538568113,32.16877015261522,227.79779989965465,24000952.700463142,23797020.12332428,0 4 | beidou,37,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,C37,14643285.015170367,8157227.608609372,22320162.760330945,-570.2925756391209,2486.661412005685,-532.58364567905,-240832.15753002604,0.0018775948703379,71.54429250313177,58.78078170336106,21804128.046690997,22044960.204221018,0 5 | beidou,46,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,C46,16087964.73197824,-14360483.328999406,17682559.291692972,-337.8558542983301,1998.830410614847,1933.3914776805836,-11928.743415917244,-0.0007662356362999,43.77307899038751,276.3243336692347,23103106.476501703,23115035.21991762,0 6 | galileo,1,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,E01,23631522.61949869,-15015136.554079166,9585608.011522744,-723.9692409793578,639.0105218849462,2784.763407903365,-4897.640728768326,0.0013125709052984,36.25642671400479,243.70631064854632,25373180.056663334,25378077.697392102,0 7 | galileo,4,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,E04,6727687.906148172,-15803698.804318905,24117182.358258035,2349.1610045395514,565.7115417522109,-284.84123145085005,-23389.15955745533,-0.0025121610051188,34.01251174178781,308.37516292323977,25582634.995051835,25606024.15460929,0 8 | galileo,19,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,E19,26006164.918806933,-3412013.33311436,13725082.713085037,1348.4245797560725,275.9387321600103,-2488.6635298637343,-903358.9763394548,0.0278982594054645,60.570439155440646,217.9582926430376,23885590.73853945,24788949.714878906,0 9 | galileo,21,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,E21,19714352.156374738,1280881.55373046,22033104.53200818,-1557.144979342935,1571.1494667795891,1302.0595424491585,-155111.81594089273,-0.0006561505344981,85.79270671138487,284.93765248208666,23240361.34768649,23395473.163627382,0 10 | galileo,27,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,E27,4295454.424753777,18226209.121134598,22923527.405864533,-1571.7187737288164,1679.4955548840346,-1039.453466996536,-160193.41959589918,-0.0027909782852553,36.8715851067519,59.06069042880392,25345622.665889207,25505816.08548511,0 11 | gps,12,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,G12,22354175.414516192,-7842827.446927055,11629208.6947203,-1029.197947015508,1148.0208901060537,2697.0279263143334,-105323.334800153,-0.0011573698382963,50.74097040066133,235.75154985210105,21145399.794912435,21250723.12971259,0 12 | gps,15,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,G15,26452062.219067466,3373405.9582735733,1025426.459380111,126.3243011259438,374.6471750943844,-3089.709780156056,6423.322268772287,0.0009902054963027,33.3066167175584,181.73808945412708,22638756.224311523,22632332.90204275,0 13 | gps,19,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,G19,10334610.059800854,17160542.395005886,17350507.96705407,-2111.052923659021,-744.8243938797527,1941.0510362037144,86888.76545355405,0.0014890339110656,43.90803451915259,81.26965792705752,21688248.05576549,21601359.29031194,0 14 | gps,24,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,G24,16459275.004208166,1553944.3126191664,20505837.22751532,765.5594501041718,2576.3110794521067,-754.5442738757467,-33288.813813874294,-0.0046386071920594,84.36772672468055,332.8320730809228,19998467.677661438,20031756.491475303,0 15 | glonass,7,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,R07,3171455.641574261,-11218960.677935416,22727400.642420106,3072.825701585963,-414.86104193285365,-639.3119281242675,15497.251899051662,8.503568154246041e-05,31.699923002163604,321.0657050694632,21629153.43559832,21613656.183699265,1 16 | glonass,15,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,R15,4090801.497377511,15285981.804850908,20019090.019973285,-979.2764299469076,2557.095359869846,-1753.632651214674,27120.53539079166,-0.0003416594396896,36.56532522638332,58.40239081737761,21215043.939897142,21187923.40450636,0 17 | glonass,16,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,R16,12250814.3965819,-2337521.453522725,22258840.54638837,-1181.1788380626383,2808.99356429005,942.3914120282386,3695.2879552977774,0.0006264067264287,67.01273174177334,327.29323674094354,19537706.87334701,19534011.58539171,0 18 | glonass,17,4276936.989842105,639250.223239567,4672543.160806354,0.0,1362818118000.0,R17,5349601.552255271,19198709.23852283,15947401.552168978,-1178.5508292582156,-1845.3801005167652,2615.15982985716,183601.0937754479,0.0005394946006097,30.01211449005524,75.13524774619569,21742287.13651519,21558686.04273974,0 19 | -------------------------------------------------------------------------------- /data/unit_test/google_decimeter_2021/Pixel4_ground_truth_clkdiscnt.csv: -------------------------------------------------------------------------------- 1 | collectionName,phoneName,millisSinceGpsEpoch,latDeg,lngDeg,heightAboveWgs84EllipsoidM,timeSinceFirstFixSeconds,hDop,vDop,speedMps,courseDegree 2 | 2021-04-28-US-SJC-1,Pixel4,1303675237438,37.3351052538,-121.8983280611,55.04,410.44,3.14,0.00,10.38,60.26 3 | 2021-04-28-US-SJC-1,Pixel4,1303675238438,37.3351481952,-121.8982357584,55.00,411.44,4.20,0.00,8.48,59.42 4 | 2021-04-28-US-SJC-1,Pixel4,1303675239438,37.3351831871,-121.8981623107,54.96,412.44,4.20,0.00,6.83,59.14 5 | 2021-04-28-US-SJC-1,Pixel4,1303675240438,37.3352103637,-121.8981049653,54.93,413.44,4.74,0.00,4.77,59.30 6 | 2021-04-28-US-SJC-1,Pixel4,1303675241438,37.3352261605,-121.8980710846,54.91,414.44,5.50,0.00,2.62,59.70 7 | 2021-04-28-US-SJC-1,Pixel4,1303675242438,37.3352389465,-121.8980422713,54.91,415.44,3.75,0.00,3.58,60.91 8 | 2021-04-28-US-SJC-1,Pixel4,1303675243438,37.3352578644,-121.8979926902,54.88,416.44,1.26,0.00,6.15,64.97 9 | 2021-04-28-US-SJC-1,Pixel4,1303675244438,37.3352786005,-121.8979153355,54.73,417.44,1.00,0.00,8.24,73.68 10 | 2021-04-28-US-SJC-1,Pixel4,1303675245438,37.3352909782,-121.8978172871,54.77,418.44,1.74,0.00,9.33,83.74 11 | 2021-04-28-US-SJC-1,Pixel4,1303675246438,37.3352917459,-121.8977066383,54.85,419.44,1.49,0.00,10.28,91.59 12 | 2021-04-28-US-SJC-1,Pixel4,1303675247438,37.3352870824,-121.8975862683,54.96,420.44,0.00,0.00,11.03,92.29 13 | 2021-04-28-US-SJC-1,Pixel4,1303675250438,37.3353062520,-121.8972039985,55.09,423.44,0.00,0.00,10.84,83.16 14 | 2021-04-28-US-SJC-1,Pixel4,1303675251438,37.3353181826,-121.8970873147,55.15,424.44,0.00,0.00,9.92,82.50 15 | 2021-04-28-US-SJC-1,Pixel4,1303675252438,37.3353286902,-121.8969849600,55.21,425.44,0.00,0.00,8.28,82.80 16 | 2021-04-28-US-SJC-1,Pixel4,1303675253438,37.3353363575,-121.8969044308,55.25,426.44,0.00,0.00,6.10,83.24 17 | 2021-04-28-US-SJC-1,Pixel4,1303675254438,37.3353413797,-121.8968490928,55.28,427.44,0.00,0.00,3.81,83.50 18 | 2021-04-28-US-SJC-1,Pixel4,1303675255438,37.3353442503,-121.8968176088,55.30,428.44,0.00,0.00,2.31,83.50 19 | 2021-04-28-US-SJC-1,Pixel4,1303675256438,37.3353467949,-121.8967892075,55.33,429.44,0.00,0.00,3.04,83.74 20 | 2021-04-28-US-SJC-1,Pixel4,1303675257438,37.3353487758,-121.8967437877,55.37,430.44,0.00,0.00,5.05,87.27 21 | 2021-04-28-US-SJC-1,Pixel4,1303675258438,37.3353411400,-121.8966775875,55.40,431.44,32.75,0.00,6.69,101.90 22 | 2021-04-28-US-SJC-1,Pixel4,1303675259438,37.3353098019,-121.8966059999,55.46,432.44,87.16,0.00,7.76,123.97 23 | -------------------------------------------------------------------------------- /data/unit_test/google_decimeter_2022/alt_nan_ground_truth.csv: -------------------------------------------------------------------------------- 1 | MessageType,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,AccuracyMeters,BearingDegrees,UnixTimeMillis 2 | Fix,GT,37.4166186,-122.082065,,0.002044282,0.1,92.96875,1.58957E+12 3 | Fix,GT,37.4166186,-122.082065,,0.002198359,0.1,92.969666,1.58957E+12 4 | Fix,GT,37.4166186,-122.082065,,0.001414214,0.1,92.96985,1.58957E+12 5 | -------------------------------------------------------------------------------- /data/unit_test/google_decimeter_2023/2023-09-07-18-59-us-ca/pixel7pro/ground_truth.csv: -------------------------------------------------------------------------------- 1 | MessageType,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees,elapsedRealtimeNanos,VerticalAccuracyMeters 2 | Fix,GT,37.692231,-122.0884199,20.9736302800885,0.0028273123,0.1,288.27866,1694113198000,,,, 3 | Fix,GT,37.692231,-122.0884199,20.9736314471981,0.002236068,0.1,288.2789,1694113199000,,,, 4 | Fix,GT,37.692231,-122.0884199,20.9736303240382,0.0022360678,0.099,288.2788,1694113200000,,,, 5 | Fix,GT,37.692231,-122.0884199,20.9736306609862,0.0022371816,0.1,288.2795,1694113201000,,,, 6 | Fix,GT,37.692231,-122.0884199,20.9736312079162,0.0031605368,0.1,288.27997,1694113202000,,,, 7 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_only_header.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_dtypes.csv: -------------------------------------------------------------------------------- 1 | int,float,datetime,string 2 | 4,4.321,2022-11-14,testing 3 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_headless.csv: -------------------------------------------------------------------------------- 1 | ab,10,0.5,gps 2 | cde,2,0.4,glonass 3 | alpha,45,0.3,galileo 4 | epsilon,67,0.99,gps 5 | gamma,98,0.45,gps 6 | xyzuvw,300,0.74,galileo 7 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_inf.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | ab,np.inf,0.5,gps 3 | cde,2,-np.inf,glonass 4 | alpha,45,0.3,galileo 5 | epsilon,-np.inf,0.99,gps 6 | gamma,98,0.45,gps 7 | xyzuvw,300,np.inf,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_int_first.csv: -------------------------------------------------------------------------------- 1 | integers,names,floats,strings 2 | 10,ab,0.5,gps 3 | 2,cde,0.4,glonass 4 | 45,alpha,0.3,galileo 5 | 67,epsilon,0.99,gps 6 | 98,gamma,0.45,gps 7 | 300,xyzuvw,0.74,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_missing.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | ab,10,0.5,gps 3 | cde,2,0.4, 4 | alpha,45,0.3,galileo 5 | epsilon,,0.99,gps 6 | gamma,98,0.45,gps 7 | ,300,0.74,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_mixed.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | ab,10,0.5,100 3 | cde,beta,0.4,glonass 4 | alpha,45,0.3,galileo 5 | epsilon,67,0.99,gps 6 | gamma,98,0.45,100 7 | xyzuvw,300,0.74,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_nan.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | ab,10,0.5,NaN 3 | cde,nan,nan,glonass 4 | alpha,45,0.3,galileo 5 | epsilon,nan,0.99,gps 6 | nan,nan,0.45,nan 7 | xyzuvw,300,0.74,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/navdata/navdata_test_simple.csv: -------------------------------------------------------------------------------- 1 | names,integers,floats,strings 2 | ab,10,0.5,gps 3 | cde,2,0.4,glonass 4 | alpha,45,0.3,galileo 5 | epsilon,67,0.99,gps 6 | gamma,98,0.45,gps 7 | xyzuvw,300,0.74,galileo 8 | -------------------------------------------------------------------------------- /data/unit_test/nmea/nmea_no_checksum.nmea: -------------------------------------------------------------------------------- 1 | $GPGGA,220134.00,3725.4168121,N,12205.6498009,W,1,14,1.0,2.70,M,-32.64,M,, 2 | $GPRMC,220134.00,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A 3 | $GPGGA,220134.10,3725.4168119,N,12205.6498010,W,1,14,1.0,2.70,M,-32.64,M,, 4 | $GPRMC,220134.10,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A 5 | -------------------------------------------------------------------------------- /data/unit_test/nmea/nmea_w_correct_checksum.nmea: -------------------------------------------------------------------------------- 1 | $GPGGA,220134.00,3725.4168121,N,12205.6498009,W,1,14,1.0,2.70,M,-32.64,M,,*53 2 | $GPRMC,220134.00,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A*4C 3 | $GPGGA,220134.10,3725.4168119,N,12205.6498010,W,1,14,1.0,2.70,M,-32.64,M,,*51 4 | $GPRMC,220134.10,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A*4D 5 | -------------------------------------------------------------------------------- /data/unit_test/nmea/nmea_w_wrong_checksum.nmea: -------------------------------------------------------------------------------- 1 | $GPGGA,220134.00,3725.4168121,N,12205.6498009,W,1,14,1.0,2.70,M,-32.64,M,,*53 2 | $GPRMC,220134.00,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A*10 3 | $GPGGA,220134.10,3725.4168119,N,12205.6498010,W,1,14,1.0,2.70,M,-32.64,M,,*51 4 | $GPRMC,220134.10,A,3725.417,N,12205.650,W,0.0,192.8,140520,,,A*11 5 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/BRDM00DLR_S_20230730000_01D_MN_no_gps_iono.rnx: -------------------------------------------------------------------------------- 1 | 3.04 NAVIGATION DATA M RINEX VERSION / TYPE 2 | BCEmerge congo 20230315 004605 GMT PGM / RUN BY / DATE 3 | Merged GPS/GLO/GAL/BDS/QZS/SBAS/IRNSS navigation file COMMENT 4 | based on CONGO and IGS tracking data COMMENT 5 | DLR/GSOC: O. Montenbruck; P. Steigenberger COMMENT 6 | GAL 1.3875e+02 1.2891e-01 1.8494e-02 IONOSPHERIC CORR 7 | BDSA 3.3528e-08 6.7055e-08 -1.0133e-06 1.6093e-06 IONOSPHERIC CORR 8 | BDSB 1.1878e+05 3.2768e+04 7.8643e+05 -7.8643e+05 IONOSPHERIC CORR 9 | QZSA 2.9802e-08 -2.2352e-08 -3.5763e-07 -2.3842e-07 IONOSPHERIC CORR 10 | QZSB 1.2083e+05 -6.5536e+04 9.8304e+05 3.2113e+06 IONOSPHERIC CORR 11 | IRNA 7.6368e-08 5.0664e-07 -4.7684e-07 -7.5102e-06 IONOSPHERIC CORR 12 | IRNB 1.4131e+05 7.8643e+05 -7.2090e+05 -8.3231e+06 IONOSPHERIC CORR 13 | BDUT -9.3132257462e-10 0.000000000e+00 14 2253 TIME SYSTEM CORR 14 | GAGP 8.3527993411e-09-6.217248938e-15 259200 2253 TIME SYSTEM CORR 15 | GAUT 0.0000000000e+00 0.000000000e+00 172800 2253 TIME SYSTEM CORR 16 | GLGP -4.4703483582e-08 0.000000000e+00 259200 2253 TIME SYSTEM CORR 17 | GLUT -9.3132257462e-10 0.000000000e+00 259200 2253 TIME SYSTEM CORR 18 | GPUT 2.7939677238e-09 1.687538997e-14 503808 2253 TIME SYSTEM CORR 19 | IRGL 5.6490534917e-08 7.904787935e-14 173088 2253 TIME SYSTEM CORR 20 | IRGP 3.5215634853e-09-1.731947918e-14 173088 2253 TIME SYSTEM CORR 21 | IRUT -2.5611370802e-09 6.661338148e-15 173088 2253 TIME SYSTEM CORR 22 | QZUT -4.6566128731e-09 0.000000000e+00 442368 2253 TIME SYSTEM CORR 23 | 18 18 1929 7 LEAP SECONDS 24 | END OF HEADER 25 | G01 2023 03 14 00 00 00 2.030883915722e-04-3.865352482535e-12 0.000000000000e+00 26 | 1.200000000000e+01-7.940625000000e+01 3.783729036073e-09 2.407791404577e+00 27 | -4.297122359276e-06 1.251155254431e-02 6.118789315224e-06 5.153655818939e+03 28 | 1.728000000000e+05-5.587935447693e-09-2.637111594763e+00-1.918524503708e-07 29 | 9.897955881821e-01 2.768750000000e+02 9.405539660537e-01-7.681391389355e-09 30 | -1.153619481453e-10 1.000000000000e+00 2.253000000000e+03 0.000000000000e+00 31 | 2.000000000000e+00 0.000000000000e+00 4.656612873077e-09 1.200000000000e+01 32 | 1.656180000000e+05 4.000000000000e+00 33 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/GOLD00USA_R_20201370000_01D_EN.rnx: -------------------------------------------------------------------------------- 1 | 3.04 N: GNSS NAV DATA E: Galileo RINEX VERSION / TYPE 2 | JPS2RIN v.2.0.191 JAVAD GNSS 20200517 011939 UTC PGM / RUN BY / DATE 3 | 18 LEAP SECONDS 4 | GAL 3.8250D+01 1.2891D-01 6.6833D-03 0.0000D+00 IONOSPHERIC CORR 5 | GOLD MARKER NAME COMMENT 6 | 40405S031 MARKER NUMBER COMMENT 7 | -2353614.3160 -4641385.3523 3676976.4340 COMMENT 8 | END OF HEADER 9 | E03 2020 05 15 23 10 00-2.990722423419D-04-4.206412995700D-12 0.000000000000D+00 10 | 9.100000000000D+01-6.006250000000D+01 3.142273745457D-09-1.387355668704D-01 11 | -2.995133399963D-06 3.344889264554D-04 9.872019290924D-06 5.440624649048D+03 12 | 5.154000000000D+05 1.676380634308D-08-1.142051654601D+00 3.725290298462D-09 13 | 9.533357373229D-01 1.266250000000D+02-5.922059728073D-01-5.526658778950D-09 14 | -2.328668426958D-10 5.130000000000D+02 2.105000000000D+03 0.000000000000D+00 15 | 3.119999885559D+00 0.000000000000D+00 9.313225746155D-10 9.313225746155D-10 16 | 5.185150000000D+05 17 | E02 2020 05 15 23 50 00 1.336038112640D-04 2.685851541173D-12 0.000000000000D+00 18 | 9.500000000000D+01 2.084375000000D+01 2.882262914962D-09-3.090079600984D+00 19 | 1.018866896629D-06 2.221763134003D-04 4.695728421211D-06 5.440604221344D+03 20 | 5.178000000000D+05-5.774199962616D-08 9.536967591724D-01 2.793967723846D-08 21 | 9.829673858629D-01 2.511875000000D+02 5.627177004795D-01-5.577732334940D-09 22 | -1.400058318049D-10 5.130000000000D+02 2.105000000000D+03 0.000000000000D+00 23 | 3.119999885559D+00 0.000000000000D+00-3.492459654808D-09-4.423782229424D-09 24 | 5.184850000000D+05 25 | E15 2020 05 15 23 50 00 8.669391390868D-04-1.435296326235D-12 0.000000000000D+00 26 | 9.500000000000D+01 4.203125000000D+01 2.784401695793D-09 1.617398386815D+00 27 | 1.838430762291D-06 2.368856221437D-04 5.999580025673D-06 5.440607067108D+03 28 | 5.178000000000D+05 6.146728992462D-08 3.032635986742D+00 2.235174179077D-08 29 | 9.914864976552D-01 2.265625000000D+02-7.189675815314D-01-5.507729419038D-09 30 | 3.110843864848D-10 5.130000000000D+02 2.105000000000D+03 0.000000000000D+00 31 | 3.119999885559D+00 0.000000000000D+00 4.190951585770D-09 4.423782229424D-09 32 | 5.184850000000D+05 33 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/VOIM00MDG_R_20140010000_01D_MN.rnx: -------------------------------------------------------------------------------- 1 | 3.02 NAVIGATION DATA M (MIXED) RINEX VERSION / TYPE 2 | MAKERINEX 2.0.15124 GFZ 2014-01-01 00:16 PGM / RUN BY / DATE 3 | END OF HEADER 4 | R03 2014 1 1 0 15 0 6.048940122128D-06 0.000000000000D+00 0.000000000000D+00 5 | -1.101601269531D+04-3.023138046265D-01-4.656612873077D-09 0.000000000000D+00 6 | 2.225677099609D+04 7.595195770264D-01-1.862645149231D-09 5.000000000000D+00 7 | -5.827034667969D+03 3.452306747437D+00-1.862645149231D-09 0.000000000000D+00 8 | R04 2014 1 1 0 15 0 5.619227886200D-05 9.094947017729D-13 0.000000000000D+00 9 | 1.158776367187D+03-1.408649444580D+00-2.793967723846D-09 0.000000000000D+00 10 | 1.580590087891D+04 2.348831176758D+00-1.862645149231D-09 6.000000000000D+00 11 | -1.997874023438D+04 1.775586128235D+00 1.862645149231D-09 0.000000000000D+00 12 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/ZIM200CHE_R_20201390000_01D_GN.rnx: -------------------------------------------------------------------------------- 1 | 3.02 N: GNSS NAV DATA G: GPS NAV DATA RINEX VERSION / TYPE 2 | NetR9 5.37 Receiver Operator 20200518 000001 UTC PGM / RUN BY / DATE 3 | GPSA .7451D-08 .2235D-07 -.5960D-07 -.1192D-06 IONOSPHERIC CORR 4 | GPSB .8602D+05 .8192D+05 -.1311D+06 -.5243D+06 IONOSPHERIC CORR 5 | GPUT .0000000000D+00 .621724894D-14 233472 2106 TIME SYSTEM CORR 6 | 18 18 2185 7 LEAP SECONDS 7 | END OF HEADER 8 | G05 2020 05 18 00 00 00 -.128676183522D-04 -.682121026330D-12 .000000000000D+00 9 | .210000000000D+02 -.239062500000D+02 .516414367874D-08 .118411737536D+00 10 | -.110268592834D-05 .585496623535D-02 .428594648838D-05 .515365635681D+04 11 | .864000000000D+05 -.204890966415D-07 -.207386434427D+01 -.745058059692D-08 12 | .952225034326D+00 .288281250000D+03 .792294398722D+00 -.855142762986D-08 13 | -.165364030933D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 14 | .200000000000D+01 .000000000000D+00 -.111758708954D-07 .210000000000D+02 15 | .852060000000D+05 .400000000000D+01 16 | G06 2020 05 18 00 00 00 -.273362267762D-03 -.682121026330D-11 .000000000000D+00 17 | .450000000000D+02 .266250000000D+02 .419946063868D-08 -.267193952686D+01 18 | .148266553879D-05 .192686438095D-02 .835955142975D-05 .515354308510D+04 19 | .864000000000D+05 -.782310962677D-07 -.309066588735D+01 .428408384323D-07 20 | .979938579289D+00 .229437500000D+03 -.105611700271D+01 -.781568269741D-08 21 | .422517599554D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 22 | .200000000000D+01 .000000000000D+00 .419095158577D-08 .450000000000D+02 23 | .792180000000D+05 .400000000000D+01 24 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/ZIM200CHE_R_20201390000_01D_RN.rnx: -------------------------------------------------------------------------------- 1 | 3.02 N: GNSS NAV DATA R: GLONASS RINEX VERSION / TYPE 2 | NetR9 5.37 Receiver Operator 20200518 000001 UTC PGM / RUN BY / DATE 3 | 18 18 2185 7 LEAP SECONDS 4 | END OF HEADER 5 | R12 2020 05 17 23 45 00 .131594017148D-03 .272848410532D-11 .863700000000D+05 6 | .214851333008D+05 .521809577942D+00 .931322574615D-09 .000000000000D+00 7 | .131871376953D+05 .172472000122D+00 -.186264514923D-08 -.100000000000D+01 8 | -.380323681641D+04 .352500343323D+01 .000000000000D+00 .000000000000D+00 9 | R17 2020 05 17 23 45 00 .325657427311D-03 .272848410532D-11 .863700000000D+05 10 | .158010195312D+05 .170931434631D+01 .186264514923D-08 .000000000000D+00 11 | -.140973720703D+05 -.948531150818D+00 -.931322574615D-09 .400000000000D+01 12 | .142026870117D+05 -.284693336487D+01 -.931322574615D-09 .000000000000D+00 13 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/brdc0730.17n: -------------------------------------------------------------------------------- 1 | 2 NAVIGATION DATA RINEX VERSION / TYPE 2 | CCRINEXN V1.6.0 UX CDDIS 15-MAR-17 17:31 PGM / RUN BY / DATE 3 | IGS BROADCAST EPHEMERIS FILE COMMENT 4 | 0.1118D-07 0.7451D-08 -0.5960D-07 -0.5960D-07 ION ALPHA 5 | 0.9011D+05 0.0000D+00 -0.1966D+06 -0.6554D+05 ION BETA 6 | -0.372529029846D-08-0.976996261670D-14 319488 1940 DELTA-UTC: A0,A1,T,W 7 | 18 LEAP SECONDS 8 | END OF HEADER 9 | 1 17 3 14 0 0 0.0 0.512395054102D-04 0.795807864051D-12 0.000000000000D+00 10 | 0.230000000000D+02-0.271250000000D+02 0.490270421731D-08-0.221079756974D+00 11 | -0.147707760334D-05 0.633093772922D-02 0.309757888317D-05 0.515368457413D+04 12 | 0.172800000000D+06 0.298023223877D-07-0.113764559404D+01 0.987201929092D-07 13 | 0.966497238238D+00 0.319562500000D+03 0.536244426241D+00-0.856321383509D-08 14 | -0.275368613065D-09 0.100000000000D+01 0.194000000000D+04 0.000000000000D+00 15 | 0.200000000000D+01 0.000000000000D+00 0.512227416039D-08 0.230000000000D+02 16 | 0.172770000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 17 | 2 17 3 14 0 0 0.0 0.459419563413D-03-0.704858393874D-11 0.000000000000D+00 18 | 0.850000000000D+02-0.155937500000D+02 0.539343894410D-08 0.149906023113D+00 19 | -0.733882188797D-06 0.167286765063D-01 0.315345823765D-05 0.515374245453D+04 20 | 0.172800000000D+06-0.186264514923D-06-0.118944185003D+01 0.199303030968D-06 21 | 0.945369795818D+00 0.313656250000D+03-0.200533997114D+01-0.896644491699D-08 22 | -0.239652839646D-09 0.100000000000D+01 0.194000000000D+04 0.000000000000D+00 23 | 0.200000000000D+01 0.000000000000D+00-0.204890966415D-07 0.850000000000D+02 24 | 0.172800000000D+06 0.000000000000D+00 0.000000000000D+00 0.000000000000D+00 25 | 2 17 3 14 1 59 44.0 0.459367409348D-03-0.716227077646D-11 0.000000000000D+00 26 | 0.700000000000D+01-0.148750000000D+02 0.543165482165D-08 0.119771564509D+01 27 | -0.920146703720D-06 0.167288604425D-01 0.346265733242D-05 0.515374276161D+04 28 | 0.179984000000D+06-0.316649675369D-06-0.118950611749D+01 0.223517417908D-07 29 | 0.945367788694D+00 0.312031250000D+03-0.200533807959D+01-0.890965683726D-08 30 | -0.268939773850D-09 0.100000000000D+01 0.194000000000D+04 0.000000000000D+00 31 | 0.200000000000D+01 0.000000000000D+00-0.204890966415D-07 0.700000000000D+01 32 | 0.174468000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 33 | 1 17 3 14 2 0 0.0 0.512455590069D-04 0.795807864051D-12 0.000000000000D+00 34 | 0.300000000000D+02-0.253750000000D+02 0.494663461862D-08 0.829089190527D+00 35 | -0.115297734737D-05 0.633117463440D-02 0.311806797981D-05 0.515368503380D+04 36 | 0.180000000000D+06-0.186264514923D-07-0.113770710975D+01 0.912696123123D-07 37 | 0.966495235503D+00 0.319687500000D+03 0.536252434255D+00-0.854999899892D-08 38 | -0.299655338990D-09 0.100000000000D+01 0.194000000000D+04 0.000000000000D+00 39 | 0.200000000000D+01 0.000000000000D+00 0.512227416039D-08 0.300000000000D+02 40 | 0.172818000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 41 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/brdc1370.20g: -------------------------------------------------------------------------------- 1 | 2.01 GLONASS NAV DATA RINEX VERSION / TYPE 2 | CCRINEXG V1.4 UX CDDIS 17-MAY-20 19:33 PGM / RUN BY / DATE 3 | IGS BROADCAST EPHEMERIS FILE COMMENT 4 | teqc 2019Feb25 UNAVCO Archive Ops 20200517 0:15: COMMENT 5 | 2020 5 16 -0.465661287308D-09 CORR TO SYSTEM TIME 6 | 18 LEAP SECONDS 7 | END OF HEADER 8 | 1 20 5 16 0 15 0.0 0.615818426013D-04 0.000000000000D+00 0.000000000000D+00 9 | 0.692037744141D+04-0.802021026611D-01 0.931322574616D-09 0.000000000000D+00 10 | -0.195624306641D+05 0.203045272827D+01-0.186264514923D-08 0.100000000000D+01 11 | 0.148312026367D+05 0.271844768524D+01-0.000000000000D+00 0.000000000000D+00 12 | 2 20 5 16 0 15 0.0 0.426834449172D-03 0.181898940355D-11 0.000000000000D+00 13 | -0.236655517578D+04-0.159380912781D+00 0.931322574616D-09 0.000000000000D+00 14 | -0.248062177734D+05-0.765732765198D+00-0.931322574616D-09-0.400000000000D+01 15 | -0.553752294922D+04 0.346456432342D+01 0.931322574616D-09 0.000000000000D+00 16 | 1 20 5 16 0 45 0.0 0.615827739239D-04 0.000000000000D+00 0.180000000000D+04 17 | 0.709525048828D+04 0.298349380493D+00 0.000000000000D+00 0.000000000000D+00 18 | -0.153627866211D+05 0.259553527832D+01-0.186264514923D-08 0.100000000000D+01 19 | 0.190877480469D+05 0.198039245605D+01-0.931322574616D-09 0.000000000000D+00 20 | 2 20 5 16 0 45 0.0 0.426839105785D-03 0.181898940355D-11 0.180000000000D+04 21 | -0.268976904297D+04-0.158758163452D+00 0.931322574616D-09 0.000000000000D+00 22 | -0.253833154297D+05 0.127460479736D+00-0.186264514923D-08-0.400000000000D+01 23 | 0.831883789062D+03 0.356670188904D+01 0.000000000000D+00 0.000000000000D+00 24 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/brdc1370.20n: -------------------------------------------------------------------------------- 1 | 2 NAVIGATION DATA RINEX VERSION / TYPE 2 | CCRINEXN V1.6.0 UX CDDIS 17-MAY-20 19:31 PGM / RUN BY / DATE 3 | IGS BROADCAST EPHEMERIS FILE COMMENT 4 | 0.7451D-08 0.2235D-07 -0.5960D-07 -0.1192D-06 ION ALPHA 5 | 0.8602D+05 0.8192D+05 -0.1311D+06 -0.5243D+06 ION BETA 6 | -0.931322574615D-09 0.355271367880D-14 61440 2106 DELTA-UTC: A0,A1,T,W 7 | 18 LEAP SECONDS 8 | END OF HEADER 9 | 2 20 5 16 0 0 0.0-0.456487294287D-03-0.613908923697D-11 0.000000000000D+00 10 | 0.720000000000D+02 0.202187500000D+02 0.465483674978D-08-0.263574807904D+01 11 | 0.117719173431D-05 0.197065009270D-01 0.538304448128D-05 0.515369996452D+04 12 | 0.518400000000D+06 0.292435288429D-06-0.303666075087D+01 0.204890966415D-06 13 | 0.959315887495D+00 0.270343750000D+03-0.162990811091D+01-0.792390149087D-08 14 | 0.371444043564D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 15 | 0.200000000000D+01 0.000000000000D+00-0.176951289177D-07 0.720000000000D+02 16 | 0.511218000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 17 | 3 20 5 16 0 0 0.0-0.176951754838D-03-0.121644916362D-10 0.000000000000D+00 18 | 0.440000000000D+02-0.655312500000D+02 0.457269047091D-08 0.236763479777D+01 19 | -0.352598726749D-05 0.280326884240D-02 0.598281621933D-05 0.515355792427D+04 20 | 0.518400000000D+06-0.335276126862D-07-0.192026551362D+01-0.298023223877D-07 21 | 0.965321695786D+00 0.265812500000D+03 0.699791417281D+00-0.810712340852D-08 22 | -0.191436545529D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 23 | 0.200000000000D+01 0.000000000000D+00 0.186264514923D-08 0.440000000000D+02 24 | 0.511218000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 25 | 2 20 5 16 2 0 0.0-0.456531997770D-03-0.613908923697D-11 0.000000000000D+00 26 | 0.730000000000D+02 0.289687500000D+02 0.470483883257D-08-0.158564094568D+01 27 | 0.200234353542D-05 0.197071307339D-01 0.582449138165D-05 0.515369749641D+04 28 | 0.525600000000D+06 0.130385160446D-06-0.303671765399D+01 0.495463609695D-06 29 | 0.959317724920D+00 0.266093750000D+03-0.162984902073D+01-0.812605276843D-08 30 | 0.322513433979D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 31 | 0.200000000000D+01 0.000000000000D+00-0.176951289177D-07 0.730000000000D+02 32 | 0.518418000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 33 | 3 20 5 16 2 0 0.0-0.177039299160D-03-0.121644916362D-10 0.000000000000D+00 34 | 0.970000000000D+02-0.688437500000D+02 0.466698011274D-08-0.286514252402D+01 35 | -0.356510281563D-05 0.280411727727D-02 0.621005892754D-05 0.515355618286D+04 36 | 0.525600000000D+06 0.111758708954D-07-0.192032416932D+01-0.949949026108D-07 37 | 0.965320235794D+00 0.259156250000D+03 0.699636723935D+00-0.814962517889D-08 38 | -0.159649507186D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 39 | 0.200000000000D+01 0.000000000000D+00 0.186264514923D-08 0.970000000000D+02 40 | 0.518418000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 41 | 2 20 5 16 4 0 0.0-0.456576701254D-03-0.613908923697D-11 0.000000000000D+00 42 | 0.740000000000D+02 0.240625000000D+02 0.484413034890D-08-0.535517007782D+00 43 | 0.124238431454D-05 0.197066630935D-01 0.654719769955D-05 0.515369555855D+04 44 | 0.532800000000D+06-0.266358256340D-06-0.303677936719D+01 0.108033418655D-06 45 | 0.959318418343D+00 0.261406250000D+03-0.162980337914D+01-0.862500212310D-08 46 | 0.444304221340D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 47 | 0.200000000000D+01 0.000000000000D+00-0.176951289177D-07 0.740000000000D+02 48 | 0.525618000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 49 | 3 20 5 16 4 0 0.0-0.177127309144D-03-0.121644916362D-10 0.000000000000D+00 50 | 0.990000000000D+02-0.648125000000D+02 0.473519723997D-08-0.181507032222D+01 51 | -0.332668423653D-05 0.280419050250D-02 0.621750950813D-05 0.515355539322D+04 52 | 0.532800000000D+06 0.577419996262D-07-0.192038354624D+01 0.428408384323D-07 53 | 0.965319501409D+00 0.262687500000D+03 0.699818800182D+00-0.816391148825D-08 54 | -0.407159816984D-10 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 55 | 0.200000000000D+01 0.000000000000D+00 0.186264514923D-08 0.990000000000D+02 56 | 0.525618000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 57 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/brdc1370_no_leapseconds.20n: -------------------------------------------------------------------------------- 1 | 2 NAVIGATION DATA RINEX VERSION / TYPE 2 | CCRINEXN V1.6.0 UX CDDIS 17-MAY-20 19:31 PGM / RUN BY / DATE 3 | IGS BROADCAST EPHEMERIS FILE COMMENT 4 | 0.7451D-08 0.2235D-07 -0.5960D-07 -0.1192D-06 ION ALPHA 5 | 0.8602D+05 0.8192D+05 -0.1311D+06 -0.5243D+06 ION BETA 6 | -0.931322574615D-09 0.355271367880D-14 61440 2106 DELTA-UTC: A0,A1,T,W 7 | END OF HEADER 8 | 1 20 5 16 2 0 0.0-0.380465760827D-03-0.636646291241D-11 0.000000000000D+00 9 | 0.600000000000D+01 0.158437500000D+02 0.431946563737D-08-0.182851267122D+01 10 | 0.702217221260D-06 0.984688347671D-02 0.511482357979D-05 0.515362370300D+04 11 | 0.525600000000D+06 0.121071934700D-06-0.296069622070D+01-0.987201929092D-07 12 | 0.980322073024D+00 0.288375000000D+03 0.775692031098D+00-0.795640284469D-08 13 | 0.418588864478D-09 0.100000000000D+01 0.210500000000D+04 0.000000000000D+00 14 | 0.200000000000D+01 0.000000000000D+00 0.512227416039D-08 0.600000000000D+01 15 | 0.518418000000D+06 0.400000000000D+01 0.000000000000D+00 0.000000000000D+00 16 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/zim21380.20g: -------------------------------------------------------------------------------- 1 | 2.11 G: GLONASS NAV DATA RINEX VERSION / TYPE 2 | NetR9 5.37 Receiver Operator 17-MAY-20 00:00:01 PGM / RUN BY / DATE 3 | 18 LEAP SECONDS 4 | END OF HEADER 5 | 1 20 5 16 23 45 0.0 .616256147623D-04 .000000000000D+00 .863700000000D+05 6 | .112883037109D+05 -.343304634094D+00 .931322574615D-09 .000000000000D+00 7 | -.703167480469D+04 .295871639252D+01 -.186264514923D-08 .100000000000D+01 8 | .217709248047D+05 .113555812836D+01 -.186264514923D-08 .000000000000D+00 9 | 2 20 5 16 23 45 0.0 .427004881203D-03 .181898940355D-11 .863700000000D+05 10 | .622387207031D+04 -.279311180115D+00 .186264514923D-08 .000000000000D+00 11 | -.238167133789D+05 .900502204895D+00 -.931322574615D-09 -.400000000000D+01 12 | .683709716797D+04 .340876007080D+01 .000000000000D+00 .000000000000D+00 13 | 1 20 5 17 0 15 0.0 .616265460849D-04 .000000000000D+00 .000000000000D+00 14 | .110521406250D+05 .901031494141D-01 .000000000000D+00 .000000000000D+00 15 | -.150000781250D+04 .313748359680D+01 -.931322574615D-09 .100000000000D+01 16 | .229475048828D+05 .163331031799D+00 -.186264514923D-08 .000000000000D+00 17 | 2 20 5 17 0 15 0.0 .427009537816D-03 .181898940355D-11 .000000000000D+00 18 | .581808789062D+04 -.133269309998D+00 .186264514923D-08 .000000000000D+00 19 | -.214400468750D+05 .172041034698D+01 -.186264514923D-08 -.400000000000D+01 20 | .126309594727D+05 .298733425140D+01 -.931322574615D-09 .000000000000D+00 21 | -------------------------------------------------------------------------------- /data/unit_test/rinex/nav/zim21380.20n: -------------------------------------------------------------------------------- 1 | 2.11 N: GPS NAV DATA RINEX VERSION / TYPE 2 | NetR9 5.37 Receiver Operator 17-MAY-20 00:00:01 PGM / RUN BY / DATE 3 | .7451D-08 .2235D-07 -.5960D-07 -.1192D-06 ION ALPHA 4 | .8602D+05 .8192D+05 -.1311D+06 -.5243D+06 ION BETA 5 | -.279396772385D-08 -.266453525910D-14 147456 2106 DELTA-UTC: A0,A1,T,W 6 | 18 LEAP SECONDS 7 | END OF HEADER 8 | 2 20 5 17 0 0 0.0 -.457024201751D-03 -.613908923697D-11 .000000000000D+00 9 | .180000000000D+02 .325937500000D+02 .461090634847D-08 -.260042883469D+01 10 | .180490314960D-05 .197022944922D-01 .671669840813D-05 .515370035362D+04 11 | .000000000000D+00 .268220901489D-06 .312540076761D+01 .201165676117D-06 12 | .959340030032D+00 .244656250000D+03 -.162958729151D+01 -.784961268216D-08 13 | .437875382124D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 14 | .200000000000D+01 .000000000000D+00 -.176951289177D-07 .180000000000D+02 15 | .597618000000D+06 .400000000000D+01 16 | 3 20 5 17 0 0 0.0 -.178004615009D-03 -.121644916362D-10 .000000000000D+00 17 | .210000000000D+02 -.464687500000D+02 .468555231492D-08 .240423916006D+01 18 | -.255368649960D-05 .280644930899D-02 .513531267643D-05 .515355457878D+04 19 | .000000000000D+00 -.335276126862D-07 -.204138601514D+01 -.242143869400D-07 20 | .965312245335D+00 .282000000000D+03 .699865110317D+00 -.817855495536D-08 21 | -.182864759908D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 22 | .200000000000D+01 .000000000000D+00 .186264514923D-08 .210000000000D+02 23 | .597618000000D+06 .400000000000D+01 24 | 2 20 5 17 2 0 0.0 -.457068905234D-03 -.613908923697D-11 .000000000000D+00 25 | .190000000000D+02 .366250000000D+02 .464626496416D-08 -.155029717843D+01 26 | .239349901676D-05 .197025361704D-01 .716932117939D-05 .515369905090D+04 27 | .720000000000D+04 .968575477600D-07 .312534436627D+01 .491738319397D-06 28 | .959342215631D+00 .241000000000D+03 -.162955374680D+01 -.806997900416D-08 29 | .381801617856D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 30 | .200000000000D+01 .000000000000D+00 -.176951289177D-07 .190000000000D+02 31 | .180000000000D+02 .400000000000D+01 32 | 3 20 5 17 2 0 0.0 -.178092624992D-03 -.122781784739D-10 .000000000000D+00 33 | .370000000000D+02 -.509062500000D+02 .478234206089D-08 -.282858849928D+01 34 | -.263564288616D-05 .280729506630D-02 .528804957867D-05 .515355291367D+04 35 | .720000000000D+04 .130385160446D-07 -.204144524285D+01 -.912696123123D-07 36 | .965310835082D+00 .277156250000D+03 .699763468232D+00 -.822784272268D-08 37 | -.147148986489D-09 .100000000000D+01 .210600000000D+04 .000000000000D+00 38 | .200000000000D+01 .000000000000D+00 .186264514923D-08 .370000000000D+02 39 | .180000000000D+02 .400000000000D+01 40 | -------------------------------------------------------------------------------- /data/unit_test/sp3/grg21553_nodata.sp3: -------------------------------------------------------------------------------- 1 | + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 | + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 | ++ 6 5 4 5 6 5 5 6 5 6 5 6 6 5 6 6 6 4 | ++ 5 7 4 5 5 4 4 4 5 4 3 4 4 4 3 4 4 5 | ++ 4 4 5 5 3 5 4 4 5 4 3 4 4 5 5 4 4 6 | ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 | ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 | %c M cc GPS ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc 9 | %c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc 10 | %f 0.0000000 0.000000000 0.00000000000 0.000000000000000 11 | %f 0.0000000 0.000000000 0.00000000000 0.000000000000000 12 | %i 0 0 0 0 0 0 0 0 0 13 | %i 0 0 0 0 0 0 0 0 0 14 | /* CNES/CLS/GRGS - TOULOUSE,FRANCE - Contact : igs-ac@cls.fr 15 | /* PCV:IGS14_2148 OL/AL:FES2014 NONE NN ORB:CoN CLK:CoN 16 | /* CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 17 | /* CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC -------------------------------------------------------------------------------- /dev/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/dev/.gitkeep -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/contributing/contributing.rst: -------------------------------------------------------------------------------- 1 | .. _contributing: 2 | 3 | Contributing 4 | ============ 5 | 6 | We welcome and appreciate all contributions! 7 | Every little bit helps, and credit will always be given. 8 | 9 | Bug Reports 10 | ----------- 11 | 12 | To report a bug, please submit an issue on 13 | `GitHub `__. 14 | In your issue, please include: 15 | 16 | * Your operating system name and version. 17 | * Any details about your local setup that might be helpful in 18 | troubleshooting. 19 | * A minimal working example (MWE) to reproduce the bug. An MWE 20 | helps us reproduce the bug and troubleshoot the problem. 21 | For more details on how to create an MWE, see 22 | `this Stack Overflow guide `. 23 | 24 | Feature requests and feedback 25 | ----------------------------- 26 | 27 | The best way to any send feedback is to file an issue on 28 | `GitHub `__. 29 | 30 | If you are proposing a feature: 31 | 32 | * Explain in detail the intended feature, its purpose and how it 33 | would work. 34 | * Keep the scope as narrow as possible, which will make it easier to 35 | implement. 36 | * This is a volunteer driven project and most contributions are a 37 | result of other research projects. We welcome outside implementations 38 | of additional features. If you implement your requested feature 39 | and submit a pull request, we will incorporate it. 40 | 41 | Additional Contributing Pages 42 | ----------------------------- 43 | 44 | We have a set of detailed :ref:`development guides` depending 45 | on whether you are a public user, Stanford NAV Lab member, or a project 46 | maintainer. 47 | 48 | For increased user confidence, we have implemented unit tests for our 49 | code. We have pages on how to :ref:`write and run tests` and 50 | how to create and analyze :ref:`coverage reports`. 51 | 52 | The :ref:`Documentation` section includes a detailed 53 | guide on how to write and build documentation. 54 | 55 | .. toctree:: 56 | development 57 | testing 58 | documentation 59 | :maxdepth: 1 60 | -------------------------------------------------------------------------------- /docs/source/contributing/testing.rst: -------------------------------------------------------------------------------- 1 | Testing and Coverage Reports 2 | ============================ 3 | 4 | To ensure that newly added code behaves as expected and that 5 | modifications or new additions do not change previously written code, 6 | :code:`gnss_lib_py` uses unit testing, implemented using :code:`pytest`. 7 | 8 | The module :code:`pytest-cov` is also used to generate code coverage 9 | reports. 10 | Code coverage reports detail which lines are run and which are missed 11 | during the execution of the tests. 12 | Higher coverage indicates that the code was run during unit tests and we 13 | aim to keep the code coverage above 90%. 14 | 15 | .. _testing: 16 | 17 | Testing 18 | ------- 19 | 20 | The following is a description of how tests are structured and placed 21 | in the repository. 22 | We use :code:`pytest` to write and run tests. 23 | A brief description of the naming convention and commonly used features 24 | is also included below. 25 | For more details, refer to the `pytest documentation `__. 26 | 27 | 28 | Running tests 29 | +++++++++++++ 30 | 31 | * To run tests, go to the parent directory and run 32 | 33 | .. code-block:: bash 34 | 35 | poetry run pytest 36 | 37 | * To run tests from a specific file run 38 | 39 | .. code-block:: bash 40 | 41 | poetry run tests/folder_name/test_file_name.py 42 | 43 | * To run a particular test, contained in a specific file, run 44 | 45 | .. code-block:: bash 46 | 47 | poetry run pytest tests/folder_name/test_file_name.py::test_function 48 | 49 | 50 | Naming convention and location of tests 51 | +++++++++++++++++++++++++++++++++++++++ 52 | 53 | * Tests are placed outside the source code, in the :code:`tests/` 54 | diretory 55 | * The structure of the tests directory is expected to mirror the source 56 | directory. Eg. tests for functions in :code:`gnss_lib_py/utils/file_name.py` 57 | must be placed in :code:`tests/utils/test_file_name.py` 58 | * Following the :code:`pytest` naming convention, test functions are 59 | named :code:`test_function` 60 | * Fixtures should be named as :code:`fixture_name` where :code:`name` is 61 | the name of the fixture, defined using the :code:`@pytest.fixture(name="name")` 62 | decorator before the fixture definition. More details on expected 63 | uses of fixtures can be found in the `fixtures`_ section. 64 | 65 | Conventions for writing tests 66 | +++++++++++++++++++++++++++++ 67 | 68 | * Most tests in :code:`gnss_lib_py` are unit tests. 69 | Unit tests use a known input-output pair to verify that the function 70 | being tested is working as expected. 71 | Unit tests should be used to verify nominal behaviour as well as any 72 | relevant edge cases 73 | 74 | * To verify that the function output matches the expected output, we 75 | recommend using the in-built :code:`assert` statement, numpy's 76 | testing functions, that are of the form :code:`np.testing.assert*` 77 | and any additional module level testing functions, like 78 | :code:`pd.testing.*assert*` for pandas. 79 | 80 | * Use _`fixtures` :code:`@pytest.fixture` to define certain fixed 81 | objects (tuples, strings etc.) that might be required by test functions. 82 | Fixtures can be named and these names can be used to access fixture 83 | outputs like regular variables 84 | 85 | * Fixtures can also be composed to create a fixture of a fixture. 86 | 87 | * :code:`gnss_lib_py` already uses numerous fixtures for testing. Fixtures 88 | that are relevant only to tests in a single file are defined in that file. 89 | Fixtures that are used across multiple files are defined in 90 | :code:`conftest.py` in the testing directory :code:`gnss_lib_py/tests/`. 91 | 92 | * Before defining a new fixture, check to see if the fixture exists in 93 | :code:`conftest.py`. If it does, you can refer to the fixture by name 94 | in your test function and use without having to define any additional 95 | methods. 96 | 97 | * Existing fixtures from :code:`conftest.py` also define locations of 98 | test files or common test data that can be used for your own fixtures. 99 | Please check these existing fixtures to enable quick development of 100 | your own. 101 | 102 | * If you want to test the same function beheaviour for multiple 103 | input-output pairs, you can use the :code:`pytest.mark.parameterize` 104 | function decorator before the test 105 | 106 | * When creating plots in a test, if you want to visually verify the 107 | plots,ensure that all plots are saved for checking later on. 108 | Plots that are created must be closed using :code:`plt.close()` 109 | before the tests stop running 110 | 111 | For additional details on :code:`pytest` functionality mentioned above, 112 | check the `pytest documentation `__. 113 | 114 | .. _coverage: 115 | 116 | Coverage Reports 117 | ---------------- 118 | In general, you should not submit new functionality without also 119 | providing corresponding tests for the code. 120 | Visual testing coverage reports can be found at the top of the GitHub 121 | repository. 122 | Similar reports can be generated locally, in terminal, with the 123 | following commands: 124 | 125 | .. code-block:: bash 126 | 127 | poetry run pytest --cov=gnss_lib_py/algorithms --cov=gnss_lib_py/parsers --cov=gnss_lib_py/utils --cov-report=html 128 | poetry run coverage report 129 | 130 | The total percentage of code covered (bottom right percentage) is the 131 | main number of priority. 132 | 133 | To generate the coverage report and view as a webpage, use the following 134 | command: 135 | 136 | .. code-block:: bash 137 | 138 | poetry run pytest --cov=gnss_lib_py/algorithms --cov=gnss_lib_py/parsers --cov=gnss_lib_py/utils --cov-report=html 139 | 140 | The generated coverage report can be accessed from the directory :code:`htmlcov/` 141 | -------------------------------------------------------------------------------- /docs/source/img/gnss_logger_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/docs/source/img/gnss_logger_app.jpg -------------------------------------------------------------------------------- /docs/source/img/nav_lab_fav.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/docs/source/img/nav_lab_fav.ico -------------------------------------------------------------------------------- /docs/source/img/nav_lab_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/docs/source/img/nav_lab_logo.png -------------------------------------------------------------------------------- /docs/source/img/skyplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/docs/source/img/skyplot.png -------------------------------------------------------------------------------- /docs/source/install.rst: -------------------------------------------------------------------------------- 1 | .. _install: 2 | 3 | Install 4 | ======= 5 | 6 | Prerequisites 7 | ------------- 8 | 9 | | **Python:** >=3.9, <3.13 10 | | **Operating System:** Linux, Windows, MacOS 11 | 12 | All :code:`gnss_lib_py` classes and methods are tested in Python 3.9, 13 | and 3.12 in the latest Ubuntu, MacOS and Windows versions. 14 | :code:`gnss_lib_py` was originally developed in Python 3.8.9 in 15 | Ubuntu 20/22 and Ubuntu 20 for WSL2. 16 | 17 | Use on Google Colab 18 | ------------------- 19 | 20 | |colab| 21 | 22 | .. |colab| image:: https://colab.research.google.com/assets/colab-badge.svg 23 | :target: https://colab.research.google.com/drive/1DYfuiM5ipz0B-lgjKYcL1Si-V4jNBEac?usp=sharing 24 | 25 | We provide support to run :code:`gnss_lib_py` on Google Colab. To run on 26 | Google Colab, use the following command to install :code:`gnss_lib_py`: 27 | 28 | .. code-block:: bash 29 | 30 | %pip install gnss-lib-py --quiet --progress-bar off 31 | 32 | To include :code:`gnss_lib_py` in the Google Colab environment, use the following 33 | command 34 | 35 | .. code-block:: python 36 | 37 | import gnss_lib_py as glp 38 | 39 | To use :code:`gnss_lib_py` from a specific branch, use the following code block 40 | to clone :code:`gnss_lib_py`, checkout the desired branch, and install: 41 | 42 | .. code-block:: bash 43 | 44 | import os 45 | os.makedirs("/content/lib", exist_ok=True) 46 | %cd /content/lib 47 | !pip install --upgrade pip --quiet --progress-bar off 48 | !git clone https://github.com/Stanford-NavLab/gnss_lib_py.git --quiet 49 | %cd gnss_lib_py 50 | !git checkout desired-branch-name-here CHANGE TO DESIRED BRANCH 51 | !git pull 52 | !pip install -e . --quiet --progress-bar off 53 | 54 | Standard Installation 55 | --------------------- 56 | 57 | 1. :code:`gnss_lib_py` is available through :code:`pip` installation 58 | with: 59 | 60 | .. code-block:: bash 61 | 62 | pip install gnss-lib-py 63 | 64 | Editable Installation 65 | --------------------- 66 | 67 | 1. Clone the GitHub repository: 68 | 69 | .. code-block:: bash 70 | 71 | git clone https://github.com/Stanford-NavLab/gnss_lib_py.git 72 | 73 | 2. Install dependencies with pip: 74 | 75 | .. code-block:: bash 76 | 77 | pip3 install -r requirements.txt 78 | 79 | 3. Update pip version. 80 | 81 | a. For Linux and MacOS: 82 | 83 | .. code-block:: bash 84 | 85 | pip install -U pip 86 | 87 | b. For Windows: 88 | 89 | .. code-block:: bash 90 | 91 | python -m pip install -U pip 92 | 93 | 4. Install :code:`gnss_lib_py` locally from directory containing :code:`pyproject.toml` 94 | 95 | .. code-block:: bash 96 | 97 | pip install -e . 98 | 99 | 5. Verify installation by running :code:`pytest`. 100 | A successful installation will be indicated by all tests passing. 101 | 102 | .. code-block:: bash 103 | 104 | pytest 105 | 106 | .. _developer install: 107 | 108 | Developer Installation 109 | ---------------------- 110 | 111 | This project is being developed using :code:`pyenv` and :code:`poetry` 112 | for python version and environment control respectively. 113 | 114 | Linux/WSL2 and MacOS 115 | ++++++++++++++++++++ 116 | 117 | 1. Install :code:`pyenv` using the installation instructions 118 | `here `__. The steps are 119 | briefly summarized below: 120 | 121 | a. Install the `Python build dependencies `__. 122 | 123 | b. Either use the `automatic installer `__ 124 | or the `Basic GitHub Checkout `__. 125 | 126 | c. In either case, you will need to configure your shell's 127 | environment variables for :code:`pyenv` as indicated in the install 128 | instructions. For example, for :code:`bash`, you can add the 129 | following lines to the end of your :code:`.bashrc` 130 | 131 | .. code-block:: bash 132 | 133 | export PATH="$HOME/.pyenv/bin:$PATH" 134 | eval "$(pyenv init --path)" 135 | eval "$(pyenv virtualenv-init -)" 136 | 137 | 2. Install Python 3.9.0 or above with :code:`pyenv`. For example, 138 | :code:`pyenv install 3.9.19`. 139 | 140 | 3. Clone the :code:`gnss_lib_py` repository. 141 | 142 | 4. Inside the :code:`gnss_lib_py` run :code:`pyenv local 3.9.19` (switching 143 | out with the version of Python you installed in the previous step 144 | if different than 3.9.19) to set the Python version that code in the 145 | repository will run. 146 | 147 | 5. Install :code:`poetry>=1.2` using the instructions 148 | `here `__. 149 | 150 | 6. Install Python dependencies using :code:`poetry install`. 151 | 152 | .. _install_pandoc: 153 | 154 | 7. Install pandoc to be able to build documentation. See details 155 | `here `__. 156 | 157 | a. For Linux :code:`sudo apt install pandoc` 158 | 159 | b. For Windows :code:`choco install pandoc` 160 | 161 | c. For MacOS :code:`brew install pandoc` 162 | 163 | 164 | 8. Verify that the code is working by running tests on the code using 165 | 166 | .. code-block:: bash 167 | 168 | poetry run pytest 169 | 170 | Check the :ref:`Testing` section in the Contribution guide 171 | for more details 172 | 173 | 9. Verify that the documentation is building locally using 174 | 175 | .. code-block:: bash 176 | 177 | ./build_docs.sh 178 | 179 | Windows 180 | +++++++ 181 | 182 | 1. Currently, full support is not offered for Windows, but :code:`pyenv` 183 | can be installed following instructions 184 | `here `__. 185 | 186 | 2. The workflow for installing :code:`poetry` and :code:`gnss_lib_py` is 187 | similar once :code:`pyenv` has been set up. 188 | 189 | 190 | Refer to the :ref:`Documentation` section once you add 191 | code/documentation and want to build and view the documentation locally. 192 | -------------------------------------------------------------------------------- /docs/source/reference/algorithms/fde.rst: -------------------------------------------------------------------------------- 1 | fde module 2 | ========== 3 | 4 | .. automodule:: fde 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/algorithms/gnss_filters.rst: -------------------------------------------------------------------------------- 1 | gnss\_filters module 2 | ==================== 3 | 4 | .. automodule:: gnss_filters 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/algorithms/modules.rst: -------------------------------------------------------------------------------- 1 | algorithms 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | fde 8 | gnss_filters 9 | residuals 10 | snapshot 11 | -------------------------------------------------------------------------------- /docs/source/reference/algorithms/residuals.rst: -------------------------------------------------------------------------------- 1 | residuals module 2 | ================ 3 | 4 | .. automodule:: residuals 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/algorithms/snapshot.rst: -------------------------------------------------------------------------------- 1 | snapshot module 2 | =============== 3 | 4 | .. automodule:: snapshot 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/navdata/modules.rst: -------------------------------------------------------------------------------- 1 | navdata 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | navdata 8 | operations 9 | -------------------------------------------------------------------------------- /docs/source/reference/navdata/navdata.rst: -------------------------------------------------------------------------------- 1 | navdata module 2 | ============== 3 | 4 | .. automodule:: navdata 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/navdata/operations.rst: -------------------------------------------------------------------------------- 1 | operations module 2 | ================= 3 | 4 | .. automodule:: operations 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/android.rst: -------------------------------------------------------------------------------- 1 | android module 2 | ============== 3 | 4 | .. automodule:: android 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/clk.rst: -------------------------------------------------------------------------------- 1 | clk module 2 | ========== 3 | 4 | .. automodule:: clk 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/google_decimeter.rst: -------------------------------------------------------------------------------- 1 | google\_decimeter module 2 | ======================== 3 | 4 | .. automodule:: google_decimeter 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/modules.rst: -------------------------------------------------------------------------------- 1 | parsers 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | android 8 | clk 9 | google_decimeter 10 | nmea 11 | rinex_nav 12 | rinex_obs 13 | smartloc 14 | sp3 15 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/nmea.rst: -------------------------------------------------------------------------------- 1 | nmea module 2 | =========== 3 | 4 | .. automodule:: nmea 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/rinex_nav.rst: -------------------------------------------------------------------------------- 1 | rinex\_nav module 2 | ================= 3 | 4 | .. automodule:: rinex_nav 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/rinex_obs.rst: -------------------------------------------------------------------------------- 1 | rinex\_obs module 2 | ================= 3 | 4 | .. automodule:: rinex_obs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/smartloc.rst: -------------------------------------------------------------------------------- 1 | smartloc module 2 | =============== 3 | 4 | .. automodule:: smartloc 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/parsers/sp3.rst: -------------------------------------------------------------------------------- 1 | sp3 module 2 | ========== 3 | 4 | .. automodule:: sp3 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_algorithms/modules.rst: -------------------------------------------------------------------------------- 1 | algorithms 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | test_fde 8 | test_gnss_filters 9 | test_residuals 10 | test_snapshot 11 | -------------------------------------------------------------------------------- /docs/source/reference/test_algorithms/test_fde.rst: -------------------------------------------------------------------------------- 1 | test\_fde module 2 | ================ 3 | 4 | .. automodule:: test_fde 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_algorithms/test_gnss_filters.rst: -------------------------------------------------------------------------------- 1 | test\_gnss\_filters module 2 | ========================== 3 | 4 | .. automodule:: test_gnss_filters 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_algorithms/test_residuals.rst: -------------------------------------------------------------------------------- 1 | test\_residuals module 2 | ====================== 3 | 4 | .. automodule:: test_residuals 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_algorithms/test_snapshot.rst: -------------------------------------------------------------------------------- 1 | test\_snapshot module 2 | ===================== 3 | 4 | .. automodule:: test_snapshot 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_navdata/modules.rst: -------------------------------------------------------------------------------- 1 | navdata 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | test_navdata 8 | test_operations 9 | -------------------------------------------------------------------------------- /docs/source/reference/test_navdata/test_navdata.rst: -------------------------------------------------------------------------------- 1 | test\_navdata module 2 | ==================== 3 | 4 | .. automodule:: test_navdata 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_navdata/test_operations.rst: -------------------------------------------------------------------------------- 1 | test\_operations module 2 | ======================= 3 | 4 | .. automodule:: test_operations 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/modules.rst: -------------------------------------------------------------------------------- 1 | parsers 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | test_android 8 | test_clk 9 | test_google_decimeter 10 | test_nmea 11 | test_rinex_nav 12 | test_rinex_obs 13 | test_smartloc 14 | test_sp3 15 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_android.rst: -------------------------------------------------------------------------------- 1 | test\_android module 2 | ==================== 3 | 4 | .. automodule:: test_android 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_clk.rst: -------------------------------------------------------------------------------- 1 | test\_clk module 2 | ================ 3 | 4 | .. automodule:: test_clk 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_google_decimeter.rst: -------------------------------------------------------------------------------- 1 | test\_google\_decimeter module 2 | ============================== 3 | 4 | .. automodule:: test_google_decimeter 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_nmea.rst: -------------------------------------------------------------------------------- 1 | test\_nmea module 2 | ================= 3 | 4 | .. automodule:: test_nmea 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_rinex_nav.rst: -------------------------------------------------------------------------------- 1 | test\_rinex\_nav module 2 | ======================= 3 | 4 | .. automodule:: test_rinex_nav 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_rinex_obs.rst: -------------------------------------------------------------------------------- 1 | test\_rinex\_obs module 2 | ======================= 3 | 4 | .. automodule:: test_rinex_obs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_smartloc.rst: -------------------------------------------------------------------------------- 1 | test\_smartloc module 2 | ===================== 3 | 4 | .. automodule:: test_smartloc 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_parsers/test_sp3.rst: -------------------------------------------------------------------------------- 1 | test\_sp3 module 2 | ================ 3 | 4 | .. automodule:: test_sp3 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/modules.rst: -------------------------------------------------------------------------------- 1 | utils 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | test_coordinates 8 | test_dop 9 | test_ephemeris_downloader 10 | test_file_operations 11 | test_filters 12 | test_gnss_models 13 | test_sv_models 14 | test_time_conversions 15 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_coordinates.rst: -------------------------------------------------------------------------------- 1 | test\_coordinates module 2 | ======================== 3 | 4 | .. automodule:: test_coordinates 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_dop.rst: -------------------------------------------------------------------------------- 1 | test\_dop module 2 | ================ 3 | 4 | .. automodule:: test_dop 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_ephemeris_downloader.rst: -------------------------------------------------------------------------------- 1 | test\_ephemeris\_downloader module 2 | ================================== 3 | 4 | .. automodule:: test_ephemeris_downloader 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_file_operations.rst: -------------------------------------------------------------------------------- 1 | test\_file\_operations module 2 | ============================= 3 | 4 | .. automodule:: test_file_operations 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_filters.rst: -------------------------------------------------------------------------------- 1 | test\_filters module 2 | ==================== 3 | 4 | .. automodule:: test_filters 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_gnss_models.rst: -------------------------------------------------------------------------------- 1 | test\_gnss\_models module 2 | ========================= 3 | 4 | .. automodule:: test_gnss_models 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_sv_models.rst: -------------------------------------------------------------------------------- 1 | test\_sv\_models module 2 | ======================= 3 | 4 | .. automodule:: test_sv_models 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_utils/test_time_conversions.rst: -------------------------------------------------------------------------------- 1 | test\_time\_conversions module 2 | ============================== 3 | 4 | .. automodule:: test_time_conversions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_visualizations/modules.rst: -------------------------------------------------------------------------------- 1 | visualizations 2 | ============== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | test_plot_map 8 | test_plot_metric 9 | test_plot_skyplot 10 | test_style 11 | -------------------------------------------------------------------------------- /docs/source/reference/test_visualizations/test_plot_map.rst: -------------------------------------------------------------------------------- 1 | test\_plot\_map module 2 | ====================== 3 | 4 | .. automodule:: test_plot_map 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_visualizations/test_plot_metric.rst: -------------------------------------------------------------------------------- 1 | test\_plot\_metric module 2 | ========================= 3 | 4 | .. automodule:: test_plot_metric 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_visualizations/test_plot_skyplot.rst: -------------------------------------------------------------------------------- 1 | test\_plot\_skyplot module 2 | ========================== 3 | 4 | .. automodule:: test_plot_skyplot 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/test_visualizations/test_style.rst: -------------------------------------------------------------------------------- 1 | test\_style module 2 | ================== 3 | 4 | .. automodule:: test_style 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/timing_comparisons_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../notebooks/timing_comparisons.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/reference/utils/constants.rst: -------------------------------------------------------------------------------- 1 | constants module 2 | ================ 3 | 4 | .. automodule:: constants 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/coordinates.rst: -------------------------------------------------------------------------------- 1 | coordinates module 2 | ================== 3 | 4 | .. automodule:: coordinates 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/dop.rst: -------------------------------------------------------------------------------- 1 | dop module 2 | ========== 3 | 4 | .. automodule:: dop 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/ephemeris_downloader.rst: -------------------------------------------------------------------------------- 1 | ephemeris\_downloader module 2 | ============================ 3 | 4 | .. automodule:: ephemeris_downloader 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/file_operations.rst: -------------------------------------------------------------------------------- 1 | file\_operations module 2 | ======================= 3 | 4 | .. automodule:: file_operations 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/filters.rst: -------------------------------------------------------------------------------- 1 | filters module 2 | ============== 3 | 4 | .. automodule:: filters 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/gnss_models.rst: -------------------------------------------------------------------------------- 1 | gnss\_models module 2 | =================== 3 | 4 | .. automodule:: gnss_models 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/modules.rst: -------------------------------------------------------------------------------- 1 | utils 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | constants 8 | coordinates 9 | dop 10 | ephemeris_downloader 11 | file_operations 12 | filters 13 | gnss_models 14 | sv_models 15 | time_conversions 16 | -------------------------------------------------------------------------------- /docs/source/reference/utils/sv_models.rst: -------------------------------------------------------------------------------- 1 | sv\_models module 2 | ================= 3 | 4 | .. automodule:: sv_models 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/utils/time_conversions.rst: -------------------------------------------------------------------------------- 1 | time\_conversions module 2 | ======================== 3 | 4 | .. automodule:: time_conversions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/visualizations/modules.rst: -------------------------------------------------------------------------------- 1 | visualizations 2 | ============== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | plot_map 8 | plot_metric 9 | plot_skyplot 10 | style 11 | -------------------------------------------------------------------------------- /docs/source/reference/visualizations/plot_map.rst: -------------------------------------------------------------------------------- 1 | plot\_map module 2 | ================ 3 | 4 | .. automodule:: plot_map 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/visualizations/plot_metric.rst: -------------------------------------------------------------------------------- 1 | plot\_metric module 2 | =================== 3 | 4 | .. automodule:: plot_metric 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/visualizations/plot_skyplot.rst: -------------------------------------------------------------------------------- 1 | plot\_skyplot module 2 | ==================== 3 | 4 | .. automodule:: plot_skyplot 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/reference/visualizations/style.rst: -------------------------------------------------------------------------------- 1 | style module 2 | ============ 3 | 4 | .. automodule:: style 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | .. _troubleshooting: 2 | 3 | Troubleshooting 4 | =============== 5 | 6 | Notebooks Won't Run with VS Code 7 | -------------------------------- 8 | 9 | Run :code:`poetry shell` to activate the environment. Then run 10 | :code:`code .` in order to open VS Code within the environment. At the 11 | top right of VS Code select the poetry environment (should be something 12 | like :code:`~\AppData\local\pypoetry\Cache\virtualenvs\gnss_lib-` under the 68 | :ref:`developer installation instructions`. 69 | -------------------------------------------------------------------------------- /docs/source/tutorials/algorithms/tutorials_fde_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/algorithms/fde.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/algorithms/tutorials_gnss_filters_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/algorithms/gnss_filters.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/algorithms/tutorials_residuals_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/algorithms/residuals.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/algorithms/tutorials_snapshot_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/algorithms/snapshot.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/navdata/tutorials_navdata_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/navdata/navdata.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/navdata/tutorials_operations_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/navdata/operations.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_android_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/android.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_clk_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/clk.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_google_decimeter_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/google_decimeter.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_new_parsers_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/new_parsers.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_nmea_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/nmea.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_rinex_nav_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/rinex_nav.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_rinex_obs_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/rinex_obs.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_smartloc_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/smartloc.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/parsers/tutorials_sp3_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/parsers/sp3.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/tutorials.rst: -------------------------------------------------------------------------------- 1 | .. _tutorials: 2 | 3 | Tutorials 4 | ========= 5 | 6 | 7 | The goal of this library is to easily interact with standard GNSS 8 | datasets and file types and run baseline algorithms on measurements 9 | in these datasets/data types. 10 | 11 | The :code:`gnss_lib_py` library is divided into submodles, as 12 | described :ref:`here` and the tutorials are similarly 13 | organized. 14 | 15 | These tutorials are in interactive Jupyter notebooks and have been rendered 16 | as part of the documentation. 17 | You can run the code yourself by running the notebooks in the 'tutorials' 18 | directory `here `__. 19 | The notebooks can also be run in Google Colab without downloading the 20 | repository by selecting the 'Open in Colab' option at the top of each 21 | notebook. 22 | 23 | The tutorials below show you how to load datasets, interact with our 24 | standard :Code:`NavData` class, run baseline algorithms, generate metrics 25 | for the resultant estimates, and visualize results and data. 26 | 27 | All of this can be accomplished with a few lines of code and modularly. 28 | 29 | 30 | NavData Tutorials 31 | ----------------- 32 | 33 | These tutorials show how to initialize and use our standard :code:`NavData` 34 | class and its corresponding operations. 35 | 36 | .. toctree:: 37 | :maxdepth: 2 38 | 39 | navdata/tutorials_navdata_notebook 40 | navdata/tutorials_operations_notebook 41 | 42 | Parser Tutorials 43 | ---------------- 44 | 45 | These tutorials explain existing parsers and how to create a new 46 | parser that inherits from :code:`NavData` to handle new measurement types 47 | and/or files. 48 | 49 | .. toctree:: 50 | :maxdepth: 2 51 | 52 | parsers/tutorials_android_notebook 53 | parsers/tutorials_clk_notebook 54 | parsers/tutorials_google_decimeter_notebook 55 | parsers/tutorials_nmea_notebook 56 | parsers/tutorials_rinex_nav_notebook 57 | parsers/tutorials_rinex_obs_notebook 58 | parsers/tutorials_smartloc_notebook 59 | parsers/tutorials_sp3_notebook 60 | parsers/tutorials_new_parsers_notebook 61 | 62 | Algorithm Tutorials 63 | ------------------- 64 | 65 | These tutorials demonstrate existing algorithms for state estimation 66 | and fault detection and estimation. 67 | 68 | .. toctree:: 69 | :maxdepth: 2 70 | 71 | algorithms/tutorials_fde_notebook 72 | algorithms/tutorials_residuals_notebook 73 | algorithms/tutorials_gnss_filters_notebook 74 | algorithms/tutorials_snapshot_notebook 75 | 76 | 77 | Utility Tutorials 78 | ----------------- 79 | 80 | These tutorials illustrate some of the utility functions available in 81 | the :code:`utils` directory. 82 | 83 | .. toctree:: 84 | :maxdepth: 2 85 | 86 | utils/tutorials_constants_notebook 87 | utils/tutorials_coordinates_notebook 88 | utils/tutorials_dop_notebook 89 | utils/tutorials_ephemeris_downloader_notebook 90 | utils/tutorials_file_operations_notebook 91 | utils/tutorials_filters_notebook 92 | utils/tutorials_gnss_models_notebook 93 | utils/tutorials_sv_models_notebook 94 | utils/tutorials_time_conversions_notebook 95 | 96 | Visualization Tutorials 97 | ----------------------- 98 | 99 | These tutorials illustrate most commonly used plotting functions 100 | available in the :code:`visualizations` directory. 101 | 102 | .. toctree:: 103 | :maxdepth: 2 104 | 105 | visualizations/tutorials_plot_metric_notebook 106 | visualizations/tutorials_plot_map_notebook 107 | visualizations/tutorials_plot_skyplot_notebook 108 | visualizations/tutorials_style_notebook 109 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_constants_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/constants.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_coordinates_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/coordinates.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_dop_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/dop.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_ephemeris_downloader_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/ephemeris_downloader.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_file_operations_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/file_operations.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_filters_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/filters.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_gnss_models_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/gnss_models.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_sv_models_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/sv_models.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/utils/tutorials_time_conversions_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/utils/time_conversions.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/visualizations/tutorials_plot_map_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/visualizations/plot_map.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/visualizations/tutorials_plot_metric_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/visualizations/plot_metric.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/visualizations/tutorials_plot_skyplot_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/visualizations/plot_skyplot.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/tutorials/visualizations/tutorials_style_notebook.nblink: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../../../../notebooks/tutorials/visualizations/style.ipynb" 3 | } 4 | -------------------------------------------------------------------------------- /gnss_lib_py/__init__.py: -------------------------------------------------------------------------------- 1 | """Handle version and add submodules to gnss_lib_py namesppace.""" 2 | 3 | from importlib import metadata 4 | 5 | # import submodules into gnss_lib_py namespace 6 | from gnss_lib_py.algorithms.fde import * 7 | from gnss_lib_py.algorithms.gnss_filters import * 8 | from gnss_lib_py.algorithms.residuals import * 9 | from gnss_lib_py.algorithms.snapshot import * 10 | 11 | from gnss_lib_py.navdata.navdata import * 12 | from gnss_lib_py.navdata.operations import * 13 | 14 | from gnss_lib_py.parsers.android import * 15 | from gnss_lib_py.parsers.clk import * 16 | from gnss_lib_py.parsers.google_decimeter import * 17 | from gnss_lib_py.parsers.nmea import * 18 | from gnss_lib_py.parsers.rinex_nav import * 19 | from gnss_lib_py.parsers.rinex_obs import * 20 | from gnss_lib_py.parsers.smartloc import * 21 | from gnss_lib_py.parsers.sp3 import * 22 | 23 | from gnss_lib_py.utils.constants import * 24 | from gnss_lib_py.utils.coordinates import * 25 | from gnss_lib_py.utils.dop import * 26 | from gnss_lib_py.utils.ephemeris_downloader import * 27 | from gnss_lib_py.utils.file_operations import * 28 | from gnss_lib_py.utils.filters import * 29 | from gnss_lib_py.utils.gnss_models import * 30 | from gnss_lib_py.utils.sv_models import * 31 | from gnss_lib_py.utils.time_conversions import * 32 | 33 | from gnss_lib_py.visualizations.plot_map import * 34 | from gnss_lib_py.visualizations.plot_metric import * 35 | from gnss_lib_py.visualizations.plot_skyplot import * 36 | from gnss_lib_py.visualizations.style import * 37 | 38 | # single location of version exists in pyproject.toml 39 | __version__ = metadata.version("gnss-lib-py") 40 | -------------------------------------------------------------------------------- /gnss_lib_py/algorithms/residuals.py: -------------------------------------------------------------------------------- 1 | """Calculate residuals 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "25 Jan 2022" 7 | 8 | import numpy as np 9 | 10 | from gnss_lib_py.navdata.navdata import NavData 11 | from gnss_lib_py.navdata.operations import loop_time, find_wildcard_indexes 12 | 13 | def solve_residuals(measurements, receiver_state, inplace=True): 14 | """Calculates residuals given pseudoranges and receiver position. 15 | 16 | Parameters 17 | ---------- 18 | measurements : gnss_lib_py.navdata.navdata.NavData 19 | Instance of the NavData class which must include ``gps_millis`` 20 | and ``corr_pr_m``. 21 | receiver_state : gnss_lib_py.navdata.navdata.NavData 22 | Either estimated or ground truth receiver position in ECEF frame 23 | in meters and the estimated or ground truth receiver clock bias 24 | also in meters as an instance of the NavData class with the 25 | following rows: x_rx*_m, y_rx*_m, z_rx*_m, b_rx*_m. 26 | inplace : bool 27 | If False, will return new NavData instance with gps_millis and 28 | reisuals. If True, will add a "residuals_m" rows in the 29 | current NavData instance. 30 | 31 | Returns 32 | ------- 33 | new_navdata : gnss_lib_py.navdata.navdata.NavData or None 34 | If inplace is False, returns new NavData instance containing 35 | "gps_millis" and residual rows. If inplace is True, returns 36 | None. 37 | 38 | """ 39 | 40 | # verify corrected pseudoranges exist in inputs 41 | measurements.in_rows(["gps_millis","corr_pr_m"]) 42 | receiver_state.in_rows(["gps_millis"]) 43 | 44 | 45 | rx_idxs = find_wildcard_indexes(receiver_state,["x_rx*_m", 46 | "y_rx*_m", 47 | "z_rx*_m", 48 | "b_rx*_m"], 49 | max_allow=1) 50 | 51 | residuals = [] 52 | for timestamp, _, measurement_subset in loop_time(measurements,"gps_millis"): 53 | 54 | pos_sv_m = measurement_subset[["x_sv_m","y_sv_m","z_sv_m"]].T 55 | pos_sv_m = np.atleast_2d(pos_sv_m) 56 | 57 | num_svs = pos_sv_m.shape[0] 58 | 59 | corr_pr_m = measurement_subset["corr_pr_m"].reshape(-1,1) 60 | 61 | # find time index for receiver_state NavData instance 62 | rx_t_idx = np.argmin(np.abs(receiver_state["gps_millis"] - timestamp)) 63 | 64 | rx_pos = receiver_state[[rx_idxs["x_rx*_m"][0], 65 | rx_idxs["y_rx*_m"][0], 66 | rx_idxs["z_rx*_m"][0]], 67 | rx_t_idx].reshape(1,-1) 68 | pos_rx_m = np.tile(rx_pos, (num_svs, 1)) 69 | 70 | # assumes the use of corrected pseudoranges with the satellite 71 | # clock bias already removed 72 | gt_pr_m = np.linalg.norm(pos_rx_m - pos_sv_m, axis = 1, 73 | keepdims = True) \ 74 | + receiver_state[rx_idxs["b_rx*_m"][0],rx_t_idx] 75 | 76 | # calculate residual 77 | residuals_epoch = corr_pr_m - gt_pr_m 78 | residuals += residuals_epoch.reshape(-1).tolist() 79 | 80 | if inplace: 81 | # add measurements to measurement class 82 | measurements["residuals_m"] = residuals 83 | return None 84 | 85 | # if not inplace, create new NavData instance to return 86 | residual_navdata = NavData() 87 | residual_navdata["residuals_m"] = residuals 88 | residual_navdata["gps_millis"]= measurements["gps_millis"] 89 | for row in ["gnss_id","sv_id","signal_type"]: 90 | if row in measurements.rows: 91 | residual_navdata[row] = measurements[row] 92 | 93 | return residual_navdata 94 | -------------------------------------------------------------------------------- /gnss_lib_py/utils/constants.py: -------------------------------------------------------------------------------- 1 | """Constants for GPS navigation and coordinate transforms. 2 | 3 | Based on the UIUC ECE 456 implementation [1]_. 4 | 5 | References 6 | ---------- 7 | .. [1] Makela, Jonathan, ECE 456, Global Nav Satellite Systems, 8 | Fall 2017. University of Illinois Urbana-Champaign. Coding Assignments. 9 | .. [2] International GNSS Service (IGS), RINEX Working Group and Radio 10 | Technical Commission for Maritime Servies Special Committee. RINEX 11 | Version 3.04. http://acc.igs.org/misc/rinex304.pdf 12 | .. [3] https://developer.android.com/reference/android/location/GnssStatus#constants_1 13 | .. [4] https://developer.android.com/reference/android/location/GnssMeasurement#getCodeType() 14 | .. [5] https://sys.qzss.go.jp/dod/en/constellation.html 15 | 16 | """ 17 | 18 | __authors__ = "Ashwin Kanhere" 19 | __date__ = "13 July 2021" 20 | 21 | from datetime import datetime, timezone 22 | from numpy import sqrt 23 | 24 | 25 | A = 6378137. 26 | """float : Semi-major axis (radius) of the Earth [m].""" 27 | 28 | B = 6356752.3145 29 | """float : Semi-minor axis (radius) of the Earth [m].""" 30 | 31 | E = sqrt(1.-(B**2)/(A**2)) # 0.08181919035596 32 | """float : Eccentricity of the shape (not orbit) of the Earth.""" 33 | 34 | E1SQ = 6.69437999014 * 0.001 35 | """float : First esscentricity squared of Earth (not orbit).""" 36 | 37 | E2SQ = 6.73949674228 * 0.001 38 | """float : Second eccentricity squared of Earth (not orbit).""" 39 | 40 | LAT_ACC_THRESH = 1.57e-6 41 | """ float : 10 meter latitude accuracy.""" 42 | 43 | MU_EARTH = 398600.5e9 44 | """float : :math:`G*M_E`, the "gravitational constant" for orbital 45 | motion about the Earth [m^3/s^2].""" 46 | 47 | OMEGA_E_DOT = 7.2921151467e-5 48 | """float : The sidereal rotation rate of the Earth (WGS-84) [rad/s].""" 49 | 50 | C = 299792458. 51 | """float : Speed of light [m/s].""" 52 | 53 | F = -4.442807633e-10 54 | """float : Relativistic correction term [s/m^(1/2)].""" 55 | 56 | F1 = 1.57542e9 57 | """float : GPS L1 frequency [Hz].""" 58 | 59 | F2 = 1.22760e9 60 | """float : GPS L2 frequency [Hz].""" 61 | 62 | T_TRANS = 70*0.001 63 | """float : Average time taken for signal transmission from GPS sats to 64 | receivers.""" 65 | 66 | GRAV = -9.80665 67 | """float : Acceleration due to gravity ENU frame of reference [m/s].""" 68 | 69 | WEEKSEC = 604800 70 | """ int : Number of seconds in a week [s].""" 71 | 72 | GPS_EPOCH_0 = datetime(1980, 1, 6, 0, 0, 0, 0, tzinfo=timezone.utc) 73 | """ datetime.datetime: Starting time for GPS epoch""" 74 | 75 | MILLIS_PER_DAY = 86400000 76 | 77 | TROPO_DELAY_C1 = 2.47 78 | """float : First coefficient of simplified tropospheric delay model developed in [1]_.""" 79 | 80 | TROPO_DELAY_C2 = 0.0121 81 | """float : Second coefficient of simplified tropospheric delay model developed in [1]_.""" 82 | 83 | TROPO_DELAY_C3 = 1.33e-4 84 | """float : Third coefficient of simplified tropospheric delay model developed in [1]_.""" 85 | 86 | CONSTELLATION_CHARS = {'G' : 'gps', 87 | 'R' : 'glonass', 88 | 'S' : 'sbas', 89 | 'C' : 'beidou', 90 | 'E' : 'galileo', 91 | 'J' : 'qzss', 92 | 'I' : 'irnss', 93 | } 94 | """dict : Satellite System identifier from Rinex specification p13 in [2]_.""" 95 | 96 | CONSTELLATION_ANDROID = {1 : 'gps', 97 | 3 : 'glonass', 98 | 2 : 'sbas', 99 | 5 : 'beidou', 100 | 6 : 'galileo', 101 | 4 : 'qzss', 102 | 7 : 'irnss', 103 | 0 : 'unknown', 104 | } 105 | """dict : Satellite System identifier from GNSSStatus specification [3]_.""" 106 | 107 | CODE_TYPE_ANDROID = { 108 | 'gps' : { 109 | 'C' : "l1", 110 | 'Q' : "l5", 111 | 'X' : "l5", 112 | }, 113 | 'glonass' : { 114 | 'C' : "l1", 115 | }, 116 | 'qzss' : { 117 | 'C' : "l1", 118 | 'X' : "l5", 119 | }, 120 | 'galileo' : { 121 | 'C' : "e1", 122 | 'X' : "e5a", 123 | 'Q' : "e5a", 124 | }, 125 | 'beidou' : { 126 | 'I' : "b1", 127 | 'X' : "l5", 128 | }, 129 | } 130 | """dict : GNSS code type identifier from GnssMeasurement specification [4]_.""" 131 | 132 | QZSS_PRN_SVN = {193 : 1, 133 | 194 : 2, 134 | 199 : 3, 135 | 195 : 4, 136 | 196 : 5, 137 | } 138 | """dict : Translation from PRN to SVN for the QZSS constellation [5]_.""" 139 | -------------------------------------------------------------------------------- /gnss_lib_py/utils/file_operations.py: -------------------------------------------------------------------------------- 1 | """Simple file operation utilities. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "01 Jul 2022" 7 | 8 | import os 9 | import time 10 | 11 | def make_dir(directory): # pragma: no cover 12 | """Create a file directory if it doesn't yet exist. 13 | 14 | Parameters 15 | ---------- 16 | directory : string 17 | Filepath of directory to create if it does not exist. 18 | 19 | """ 20 | 21 | # create directory if it doesn't yet exist 22 | if not os.path.isdir(directory): 23 | try: 24 | os.makedirs(directory) 25 | except OSError as error: 26 | raise OSError("Unable to create directory " + directory) from error 27 | 28 | def _get_timestamp(): 29 | """Returns timestamp of the current time. 30 | 31 | Returns 32 | ------- 33 | timestamp : string 34 | Timestamp in order of year, month, day, hour, minute, second 35 | without spaces or puncuation 36 | 37 | """ 38 | timestamp = time.strftime("%Y%m%d%H%M%S") 39 | return timestamp 40 | 41 | TIMESTAMP = _get_timestamp() 42 | -------------------------------------------------------------------------------- /notebooks/timing_comparisons.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "965edd03", 6 | "metadata": {}, 7 | "source": [ 8 | "# Basic Get/Set Time Comparisons" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "80419852", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/timing_comparisons.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "e5f1b914", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import timeit\n", 27 | "\n", 28 | "import numpy as np\n", 29 | "\n", 30 | "# load Android Google Challenge data\n", 31 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -O \"Pixel4XL_derived.csv\"" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "id": "6e513772", 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "REPEAT_COUNT = 10\n", 42 | "ITERATION_COUNT = 1000" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "id": "9eb412fb", 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "SETUP_CODE = '''\n", 53 | "from gnss_lib_py import AndroidDerived2021\n", 54 | "\n", 55 | "# load Android Google Challenge data\n", 56 | "navdata = AndroidDerived2021(\"Pixel4XL_derived.csv\", remove_timing_outliers=False)\n", 57 | "'''\n", 58 | "\n", 59 | "TEST_CODE = '''\n", 60 | "navdata[\"corr_pr_m\"] = navdata['raw_pr_m'] \\\n", 61 | " + navdata['b_sv_m'] \\\n", 62 | " - navdata['intersignal_bias_m'] \\\n", 63 | " - navdata['tropo_delay_m'] \\\n", 64 | " - navdata['iono_delay_m']\n", 65 | " '''\n", 66 | "# timeit.repeat statement\n", 67 | "times = timeit.repeat(setup = SETUP_CODE,\n", 68 | " stmt = TEST_CODE,\n", 69 | " repeat = REPEAT_COUNT,\n", 70 | " number = ITERATION_COUNT)\n", 71 | "\n", 72 | "print(f'NavData avg time: {np.round(1E3*np.mean(times)/ITERATION_COUNT,5)} ms')" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "id": "f98dbe28", 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "SETUP_CODE = '''\n", 83 | "import pandas as pd\n", 84 | "\n", 85 | "from gnss_lib_py import AndroidDerived2021\n", 86 | "\n", 87 | "# load Android Google Challenge data\n", 88 | "df = pd.read_csv(\"Pixel4XL_derived.csv\")\n", 89 | "df.rename(columns=AndroidDerived2021._row_map(), inplace=True)\n", 90 | "'''\n", 91 | "\n", 92 | "TEST_CODE = '''\n", 93 | "df[\"corr_pr_m\"] = df['raw_pr_m'] \\\n", 94 | " + df['b_sv_m'] \\\n", 95 | " - df['intersignal_bias_m'] \\\n", 96 | " - df['tropo_delay_m'] \\\n", 97 | " - df['iono_delay_m']\n", 98 | " '''\n", 99 | "# timeit.repeat statement\n", 100 | "times = timeit.repeat(setup = SETUP_CODE,\n", 101 | " stmt = TEST_CODE,\n", 102 | " repeat = REPEAT_COUNT,\n", 103 | " number = ITERATION_COUNT)\n", 104 | "\n", 105 | "print(f'Pandas avg time: {np.round(1E3*np.mean(times)/ITERATION_COUNT,5)} ms')" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "id": "d77afec7", 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "SETUP_CODE = '''\n", 116 | "import pandas as pd\n", 117 | "\n", 118 | "from gnss_lib_py import AndroidDerived2021\n", 119 | "\n", 120 | "# load Android Google Challenge data\n", 121 | "df = pd.read_csv(\"Pixel4XL_derived.csv\")\n", 122 | "df.rename(columns=AndroidDerived2021._row_map(), inplace=True)\n", 123 | "\n", 124 | "raw_pr_m = df['raw_pr_m'].to_numpy()\n", 125 | "b_sv_m = df['b_sv_m'].to_numpy()\n", 126 | "intersignal_bias_m = df['intersignal_bias_m'].to_numpy()\n", 127 | "tropo_delay_m = df['tropo_delay_m'].to_numpy()\n", 128 | "iono_delay_m = df['iono_delay_m'].to_numpy()\n", 129 | "\n", 130 | "'''\n", 131 | "\n", 132 | "TEST_CODE = '''\n", 133 | "corr_pr_m = raw_pr_m \\\n", 134 | " + b_sv_m \\\n", 135 | " - intersignal_bias_m \\\n", 136 | " - tropo_delay_m \\\n", 137 | " - iono_delay_m\n", 138 | " '''\n", 139 | "# timeit.repeat statement\n", 140 | "times = timeit.repeat(setup = SETUP_CODE,\n", 141 | " stmt = TEST_CODE,\n", 142 | " repeat = REPEAT_COUNT,\n", 143 | " number = ITERATION_COUNT)\n", 144 | "\n", 145 | "print(f'Numpy avg time: {np.round(1E3*np.mean(times)/ITERATION_COUNT,5)} ms')" 146 | ] 147 | } 148 | ], 149 | "metadata": { 150 | "kernelspec": { 151 | "display_name": "Python 3", 152 | "language": "python", 153 | "name": "python3" 154 | }, 155 | "language_info": { 156 | "codemirror_mode": { 157 | "name": "ipython", 158 | "version": 3 159 | }, 160 | "file_extension": ".py", 161 | "mimetype": "text/x-python", 162 | "name": "python", 163 | "nbconvert_exporter": "python", 164 | "pygments_lexer": "ipython3", 165 | "version": "3.8.9" 166 | } 167 | }, 168 | "nbformat": 4, 169 | "nbformat_minor": 5 170 | } 171 | -------------------------------------------------------------------------------- /notebooks/tutorials/algorithms/gnss_filters.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "28b068e2", 6 | "metadata": {}, 7 | "source": [ 8 | "# GNSS Filters" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "8693ca9b", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/algorithms/gnss_filters.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "60e040a3", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import gnss_lib_py as glp" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "id": "d50a7bf9-1eda-4365-9f2c-3185b9ce7ef5", 32 | "metadata": {}, 33 | "source": [ 34 | "## Extended Kalman Filter" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "id": "814228fe-5658-479d-82f8-1e2f872cf76e", 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "# load Android Google Challenge data\n", 45 | "glp.make_dir(\"../data\")\n", 46 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -nc -O \"../data/Pixel4XL_derived.csv\"\n", 47 | "derived_data = glp.AndroidDerived2021(\"../data/Pixel4XL_derived.csv\", remove_timing_outliers=False)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "id": "9089e51c-b9cc-4011-bdf6-056c1404965a", 53 | "metadata": {}, 54 | "source": [ 55 | "Solve for the extended Kalman filter position estimate simply by passing the measurement data." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "id": "1b0e30f0-8eec-41ed-9c7e-663a97ec1af1", 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "state_ekf = glp.solve_gnss_ekf(derived_data)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "id": "9ea58ba3-c69b-4982-ba89-115b8e6909ad", 71 | "metadata": {}, 72 | "source": [ 73 | "Plot the ECEF x and ECEF y computed position estimate of the receiver" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "id": "c1a07fd5-8a51-4d3f-971f-a858f4f99f9e", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "glp.plot_map(state_ekf)" 84 | ] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "Python 3 (ipykernel)", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.8.9" 104 | }, 105 | "vscode": { 106 | "interpreter": { 107 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 108 | } 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 5 113 | } 114 | -------------------------------------------------------------------------------- /notebooks/tutorials/algorithms/residuals.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "28b068e2", 6 | "metadata": {}, 7 | "source": [ 8 | "# Residuals" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "026e1e05", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/algorithms/residuals.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "60e040a3", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import gnss_lib_py as glp" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "id": "12285e7e", 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "# load Android Google Challenge data\n", 37 | "glp.make_dir(\"../data\")\n", 38 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -nc -O \"../data/Pixel4XL_derived.csv\"\n", 39 | "derived_data = glp.AndroidDerived2021(\"../data/Pixel4XL_derived.csv\", remove_timing_outliers=False)" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "id": "33f7cc62-cd1a-4c2d-9f97-78eb0134bcdb", 45 | "metadata": {}, 46 | "source": [ 47 | "## Calculating GNSS Pseudorange Residuals" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "id": "e92db703", 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "galileo_data = derived_data.where(\"gnss_id\",\"galileo\")" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "id": "a4ff4bdc", 63 | "metadata": {}, 64 | "source": [ 65 | "Solve for residuals using the estimated state. A new \"residuals_m\" row is added to derived_data. This function requires that the measurements (first input) include a ``gps_millis`` and ``corr_pr_m`` row." 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "id": "7ab38367", 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "state_wls = glp.solve_wls(derived_data)\n", 76 | "glp.solve_residuals(galileo_data, state_wls, inplace=True)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "id": "6def9fe1", 82 | "metadata": {}, 83 | "source": [ 84 | "Plot the residuals using the `plot_metric_by_constellation()` function. The residuals are broken up constellation and signal type and plotted on separate figures." 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "id": "e12ccd20", 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "figs = glp.plot_metric_by_constellation(galileo_data, \"gps_millis\", \"residuals_m\")" 95 | ] 96 | } 97 | ], 98 | "metadata": { 99 | "kernelspec": { 100 | "display_name": "Python 3 (ipykernel)", 101 | "language": "python", 102 | "name": "python3" 103 | }, 104 | "language_info": { 105 | "codemirror_mode": { 106 | "name": "ipython", 107 | "version": 3 108 | }, 109 | "file_extension": ".py", 110 | "mimetype": "text/x-python", 111 | "name": "python", 112 | "nbconvert_exporter": "python", 113 | "pygments_lexer": "ipython3", 114 | "version": "3.8.9" 115 | }, 116 | "vscode": { 117 | "interpreter": { 118 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 119 | } 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 5 124 | } 125 | -------------------------------------------------------------------------------- /notebooks/tutorials/data/myreceiver.csv: -------------------------------------------------------------------------------- 1 | myTimestamp,mySatId,myPseudorange 2 | 10,10,270000001 3 | 10,14,270000007 4 | 10,7,270000004 5 | 10,3,270000005 6 | 11,10,270000002 7 | 11,14,270000008 8 | 11,7,270000003 9 | 11,3,270000004 10 | -------------------------------------------------------------------------------- /notebooks/tutorials/parsers/clk.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c351c2eb", 6 | "metadata": {}, 7 | "source": [ 8 | "# CLK File Parsing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "7e7f2cce", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/parsers/clk.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "d5632d85", 22 | "metadata": {}, 23 | "source": [ 24 | "Load `gnss_lib_py` into the Python workspace" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "f7468fd3", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import gnss_lib_py as glp" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "9519121f", 40 | "metadata": {}, 41 | "source": [ 42 | "This tutorial shows how to load CLK files." 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "id": "102f55d9", 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "# download an example .clk data file\n", 53 | "glp.make_dir(\"../data\")\n", 54 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/clk/COD0MGXFIN_20211180000_01D_30S_CLK.CLK --quiet -nc -O \"../data/COD0MGXFIN_20211180000_01D_30S_CLK.CLK\"\n", 55 | "# Specify .clk file path to extract precise ephemerides\n", 56 | "clk_path = \"../data/COD0MGXFIN_20211180000_01D_30S_CLK.CLK\"" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "id": "b90a33e5", 62 | "metadata": {}, 63 | "source": [ 64 | "Use the Clk class loader to load in the CLK file. The class can also optionally take multiple files as a list." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "id": "6ab5eb6c", 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "clk = glp.Clk(clk_path)\n", 75 | "clk" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "id": "b87c055c", 81 | "metadata": {}, 82 | "source": [ 83 | "To visualize the results, we'll plot the clock bias of the first BeiDou satellites." 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "id": "b1a1b9b7", 90 | "metadata": { 91 | "scrolled": true 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "clk_first_beidou = clk.where(\"gnss_id\",\"beidou\").where(\"sv_id\",16,\"leq\")\n", 96 | "fig = glp.plot_metric_by_constellation(clk_first_beidou,\"b_sv_m\")" 97 | ] 98 | } 99 | ], 100 | "metadata": { 101 | "kernelspec": { 102 | "display_name": "Python 3 (ipykernel)", 103 | "language": "python", 104 | "name": "python3" 105 | }, 106 | "language_info": { 107 | "codemirror_mode": { 108 | "name": "ipython", 109 | "version": 3 110 | }, 111 | "file_extension": ".py", 112 | "mimetype": "text/x-python", 113 | "name": "python", 114 | "nbconvert_exporter": "python", 115 | "pygments_lexer": "ipython3", 116 | "version": "3.8.9" 117 | }, 118 | "vscode": { 119 | "interpreter": { 120 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 121 | } 122 | } 123 | }, 124 | "nbformat": 4, 125 | "nbformat_minor": 5 126 | } 127 | -------------------------------------------------------------------------------- /notebooks/tutorials/parsers/nmea.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "b0a917b6", 6 | "metadata": {}, 7 | "source": [ 8 | "# NMEA File Parsing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "e27fd80e", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/parsers/nmea.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "f7468fd3", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import gnss_lib_py as glp" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "id": "f166df97", 32 | "metadata": {}, 33 | "source": [ 34 | "NMEA is a file standard for storing and transferring position data and GPS measurements.\n", 35 | "`gnss_lib_py` has functionality for reading NMEA files and loading the data into a `NavData`, which we demonstrate next." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "aa0ea320", 41 | "metadata": {}, 42 | "source": [ 43 | "Each NMEA sentence has a header eg. `$GPGGA` which describes whether the message is propreitary or general purpose and the type of message.\n", 44 | "In this case, the message is `GGA`. `gnss_lib_py` currently supports `GGA` and `RMC` message types.\n", 45 | "\n", 46 | "Each NMEA sentence also comes with a checksum, which may appear after the '*' in each sentence.\n", 47 | "In case the checksums are to be checked, pass the parameter `check=True` to the `Nmea` initialization." 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "id": "cbae66a6", 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "# download NMEA data and load it into NavData instance\n", 58 | "glp.make_dir(\"../data\")\n", 59 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/nmea/nmea_w_correct_checksum.nmea --quiet -nc -O \"../data/nmea_w_correct_checksum.nmea\"\n", 60 | "# Load the NMEA file into a NavData structure\n", 61 | "nmea_navdata = glp.Nmea('../data/nmea_w_correct_checksum.nmea')\n", 62 | "print('Loaded NMEA data\\n', nmea_navdata)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "6606e32a", 68 | "metadata": {}, 69 | "source": [ 70 | "If the checksum is not to be checked, pass the parameter `check=False` to the initialization." 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "id": "81034771", 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "glp.make_dir(\"../data\")\n", 81 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/nmea/nmea_no_checksum.nmea --quiet -nc -O \"../data/nmea_w_no_checksum.nmea\"\n", 82 | "# Load the NMEA file into a NavData structure\n", 83 | "nmea_navdata = glp.Nmea('../data/nmea_w_no_checksum.nmea', check=False)\n", 84 | "print('Loaded NMEA data\\n', nmea_navdata)" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "id": "a87c37c2", 90 | "metadata": {}, 91 | "source": [ 92 | "NMEA GGA and RMC sentences store latitude and longitude coordinates in a `ddmm.mmmmmmm` format along with a cardinal direction like `N` or `W`.\n", 93 | "\n", 94 | "By default, these coordinates are transformed into decimal degrees but the original data format can be retained in the final loaded `NavData`.\n", 95 | "Also, the LLH coordinates can be transformed to ECEF coordinates." 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "id": "a74a2f16", 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "nmea_navdata = glp.Nmea('../data/nmea_w_correct_checksum.nmea', keep_raw=True, include_ecef=True)\n", 106 | "print('Loaded NMEA data with raw data and ECEF coordinates\\n', nmea_navdata)" 107 | ] 108 | } 109 | ], 110 | "metadata": { 111 | "kernelspec": { 112 | "display_name": "Python 3 (ipykernel)", 113 | "language": "python", 114 | "name": "python3" 115 | }, 116 | "language_info": { 117 | "codemirror_mode": { 118 | "name": "ipython", 119 | "version": 3 120 | }, 121 | "file_extension": ".py", 122 | "mimetype": "text/x-python", 123 | "name": "python", 124 | "nbconvert_exporter": "python", 125 | "pygments_lexer": "ipython3", 126 | "version": "3.8.9" 127 | }, 128 | "vscode": { 129 | "interpreter": { 130 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 131 | } 132 | } 133 | }, 134 | "nbformat": 4, 135 | "nbformat_minor": 5 136 | } 137 | -------------------------------------------------------------------------------- /notebooks/tutorials/parsers/rinex_nav.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8f1f2cd2", 6 | "metadata": {}, 7 | "source": [ 8 | "# Rinex Navigation File Parsing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "e07e2118", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/parsers/rinex_nav.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "d5632d85", 22 | "metadata": {}, 23 | "source": [ 24 | "Load `gnss_lib_py` into the Python workspace" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "f7468fd3", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import gnss_lib_py as glp" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "63352eb8", 40 | "metadata": {}, 41 | "source": [ 42 | "Rinex Navigation files can be loaded using `RinexNav`" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "id": "b034c805", 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "# download example Rinex navigation file\n", 53 | "glp.make_dir(\"../data\")\n", 54 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/rinex/nav/brdc1370.20n --quiet -nc -O \"../data/brdc1370.20n\"" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "id": "f14e71ef", 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "# load into NavData instance\n", 65 | "rinex_nav = glp.RinexNav(\"../data/brdc1370.20n\")\n", 66 | "rinex_nav" 67 | ] 68 | } 69 | ], 70 | "metadata": { 71 | "kernelspec": { 72 | "display_name": "Python 3 (ipykernel)", 73 | "language": "python", 74 | "name": "python3" 75 | }, 76 | "language_info": { 77 | "codemirror_mode": { 78 | "name": "ipython", 79 | "version": 3 80 | }, 81 | "file_extension": ".py", 82 | "mimetype": "text/x-python", 83 | "name": "python", 84 | "nbconvert_exporter": "python", 85 | "pygments_lexer": "ipython3", 86 | "version": "3.8.9" 87 | }, 88 | "vscode": { 89 | "interpreter": { 90 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 91 | } 92 | } 93 | }, 94 | "nbformat": 4, 95 | "nbformat_minor": 5 96 | } 97 | -------------------------------------------------------------------------------- /notebooks/tutorials/parsers/rinex_obs.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "fe8e8d6a", 6 | "metadata": {}, 7 | "source": [ 8 | "# Rinex Observation File Parsing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "eba6fd5d", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/parsers/rinex_obs.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "d5632d85", 22 | "metadata": {}, 23 | "source": [ 24 | "Load `gnss_lib_py` into the Python workspace" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "f7468fd3", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import gnss_lib_py as glp" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "af135db1", 40 | "metadata": {}, 41 | "source": [ 42 | "Rinex is another file standard that is used in the GNSS community to store and transmit navigation information.\n", 43 | "Files with the extension `.yyo`, where `yy` is the year in which the measurement was made, are used to store and transmit\n", 44 | "measurements.\n", 45 | "These measurement files can contain any constellation and each measurement usually contains the pseudorange, carrier phase (or difference from carrier frequency),\n", 46 | "doppler, and signal-to-noise ratio measurements.\n", 47 | "In the following lines, we show how to load a ``.o`` file into a NavData instance.\n", 48 | "\n", 49 | "Our `RinexObs` class uses the `georinex` module to load Rinex files.\n", 50 | "`georinex` reads through files line by line and so loading large Rinex files with a lot of measurements can be slow." 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "id": "9f279032", 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "# download Rinex obs file and load it into NavData instance\n", 61 | "glp.make_dir(\"../data\")\n", 62 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/rinex/obs/rinex_obs_mixed_types.20o --quiet -nc -O \"../data/rinex_obs_mixed_types.20o\"\n", 63 | "rinex_obs_3 = glp.RinexObs(\"../data/rinex_obs_mixed_types.20o\")\n", 64 | "print('Loaded Rinex Obs 3 data for the first time instant\\n', \\\n", 65 | " rinex_obs_3.where('gps_millis', rinex_obs_3['gps_millis', 0], 'eq'))" 66 | ] 67 | } 68 | ], 69 | "metadata": { 70 | "kernelspec": { 71 | "display_name": "Python 3 (ipykernel)", 72 | "language": "python", 73 | "name": "python3" 74 | }, 75 | "language_info": { 76 | "codemirror_mode": { 77 | "name": "ipython", 78 | "version": 3 79 | }, 80 | "file_extension": ".py", 81 | "mimetype": "text/x-python", 82 | "name": "python", 83 | "nbconvert_exporter": "python", 84 | "pygments_lexer": "ipython3", 85 | "version": "3.8.9" 86 | }, 87 | "vscode": { 88 | "interpreter": { 89 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 90 | } 91 | } 92 | }, 93 | "nbformat": 4, 94 | "nbformat_minor": 5 95 | } 96 | -------------------------------------------------------------------------------- /notebooks/tutorials/parsers/sp3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "e93e4676", 6 | "metadata": {}, 7 | "source": [ 8 | "# SP3 File Parsing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "82fe014d", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/parsers/sp3.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "d5632d85", 22 | "metadata": {}, 23 | "source": [ 24 | "Load `gnss_lib_py` into the Python workspace" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "f7468fd3", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import gnss_lib_py as glp" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "d1ce069f", 40 | "metadata": {}, 41 | "source": [ 42 | "This tutorial shows how to load SP3 files." 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "id": "c0756386", 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "# download an example .sp3 data file\n", 53 | "glp.make_dir(\"../data\")\n", 54 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/sp3/COD0MGXFIN_20211180000_01D_05M_ORB.SP3 --quiet -nc -O \"../data/COD0MGXFIN_20211180000_01D_05M_ORB.SP3\"\n", 55 | "# Specify .sp3 file path to extract precise ephemerides\n", 56 | "sp3_path = \"../data/COD0MGXFIN_20211180000_01D_05M_ORB.SP3\"" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "id": "2ad4d614", 62 | "metadata": {}, 63 | "source": [ 64 | "Use the SP3 class loader to load in the SP3 file. The class can also optionally take multiple files as a list." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "id": "5906e3cb", 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "sp3 = glp.Sp3(sp3_path)\n", 75 | "sp3" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "id": "73352028", 81 | "metadata": {}, 82 | "source": [ 83 | "To visualize the results, we'll plot the ECEF x position of the first 10 GPS satellites." 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "id": "76834337", 90 | "metadata": {}, 91 | "outputs": [], 92 | "source": [ 93 | "sp3_first_ten_gps = sp3.where(\"gnss_id\",\"gps\").where(\"sv_id\",10,\"leq\")\n", 94 | "fig = glp.plot_metric_by_constellation(sp3_first_ten_gps,\"gps_millis\",\"x_sv_m\")" 95 | ] 96 | } 97 | ], 98 | "metadata": { 99 | "kernelspec": { 100 | "display_name": "Python 3 (ipykernel)", 101 | "language": "python", 102 | "name": "python3" 103 | }, 104 | "language_info": { 105 | "codemirror_mode": { 106 | "name": "ipython", 107 | "version": 3 108 | }, 109 | "file_extension": ".py", 110 | "mimetype": "text/x-python", 111 | "name": "python", 112 | "nbconvert_exporter": "python", 113 | "pygments_lexer": "ipython3", 114 | "version": "3.8.9" 115 | }, 116 | "vscode": { 117 | "interpreter": { 118 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 119 | } 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 5 124 | } 125 | -------------------------------------------------------------------------------- /notebooks/tutorials/utils/constants.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# GNSS Constants" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/utils/constants.ipynb)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "import gnss_lib_py as glp" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "Standard values for constants required to process GNSS measurements are available in `utils/constants.py`.\n", 31 | "These constant values are as recommended by Interface Control Documents for constellations\n", 32 | "or by dataset specific documentation." 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "To use any of these constants, you can refer to them as `glp.CONSTANT`.\n", 40 | "For example, to use the speed of light use:" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "print(f'The speed of light is {glp.C} m/s')" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "For more control and to prevent accidentally loading other values or methods, you can also import the constants module and access values from it directly" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "from gnss_lib_py.utils import constants as consts\n", 66 | "print(f'The speed of light is {consts.C} m/s')" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "A list of all available constants has been rendered below for easy reference" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "from IPython.display import Code\n", 83 | "import os\n", 84 | "parent_directory = os.path.split(os.getcwd())[0]\n", 85 | "consts_path = os.path.join(os.path.split(glp.__file__)[0], 'utils/constants.py')\n", 86 | "\n", 87 | "Code(filename=consts_path, language='python')" 88 | ] 89 | } 90 | ], 91 | "metadata": { 92 | "kernelspec": { 93 | "display_name": "Python 3 (ipykernel)", 94 | "language": "python", 95 | "name": "python3" 96 | }, 97 | "language_info": { 98 | "codemirror_mode": { 99 | "name": "ipython", 100 | "version": 3 101 | }, 102 | "file_extension": ".py", 103 | "mimetype": "text/x-python", 104 | "name": "python", 105 | "nbconvert_exporter": "python", 106 | "pygments_lexer": "ipython3", 107 | "version": "3.8.9" 108 | }, 109 | "vscode": { 110 | "interpreter": { 111 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 112 | } 113 | } 114 | }, 115 | "nbformat": 4, 116 | "nbformat_minor": 4 117 | } 118 | -------------------------------------------------------------------------------- /notebooks/tutorials/utils/ephemeris_downloader.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "a1126926", 6 | "metadata": {}, 7 | "source": [ 8 | "# Ephemeris Downloader" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "42d320d8", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/utils/ephemeris_downloader.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "929486f6", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import numpy as np\n", 27 | "import gnss_lib_py as glp\n", 28 | "from datetime import datetime, timezone" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "8ea72a0c", 34 | "metadata": {}, 35 | "source": [ 36 | "The `load_ephemeris` function from the `utils/ephemeris_downloader.py` file can be used to automatically download ephemeris files and check whether the correct ephemeris files have already been downloaded.\n", 37 | "\n", 38 | "As an example, say we want to find satellite positions for a specific location and time. We will use `load_ephemeris` to download the correct ephemeris files." 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "id": "2bbfabff", 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "lat, lon, alt = 37.42984154652992, -122.16946303566934, 0.\n", 49 | "timestamp_start = datetime(year=2023, month=3, day=14, hour=12, tzinfo=timezone.utc)\n", 50 | "timestamp_end = datetime(year=2023, month=3, day=14, hour=13, tzinfo=timezone.utc)" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "id": "32390f44", 56 | "metadata": {}, 57 | "source": [ 58 | "To download ephemeris simply pass in the file type you want to download (either `sp3`, `clk`, or `rinex_nav` and the time at which you want the ephemeris in units of GPS milliseconds. The output of the `load_ephemeris` function is the path to the ephemeris files." 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "id": "13e826e6", 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "gps_millis = glp.datetime_to_gps_millis(np.array([timestamp_start,timestamp_end]))\n", 69 | "sp3_path = glp.load_ephemeris(file_type=\"sp3\",\n", 70 | " gps_millis=gps_millis,\n", 71 | " verbose=True)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "fb631ff0", 77 | "metadata": {}, 78 | "source": [ 79 | "To visualize the data, we can then plot the satellite positions using a skyplot from our receiver's location we input above. For the skyplot we need to parse the sp3 file we downloaded using the `Sp3` class and then create a `NavData` instance to pass in our receiver's position." 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "id": "a09816e3", 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "# load the sp3 file\n", 90 | "sp3 = glp.Sp3(sp3_path)\n", 91 | "\n", 92 | "# create receiver state NavData instance to pass into skyplot function\n", 93 | "x_rx_m, y_rx_m, z_rx_m = glp.geodetic_to_ecef(np.array([[lat,lon,alt]]))[0]\n", 94 | "receiver_state = glp.NavData()\n", 95 | "receiver_state[\"gps_millis\"] = glp.datetime_to_gps_millis(timestamp_start)\n", 96 | "receiver_state[\"x_rx_m\"] = x_rx_m\n", 97 | "receiver_state[\"y_rx_m\"] = y_rx_m\n", 98 | "receiver_state[\"z_rx_m\"] = z_rx_m" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "id": "bcfe81aa", 104 | "metadata": {}, 105 | "source": [ 106 | "Now we can plot the skyplot from the downloaded data. For readability, we crop the sp3 data to only include satellite positions between the start and end timestamp from above." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "id": "cd23bf03", 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "cropped_sp3 = sp3.where(\"gps_millis\",gps_millis[0],\"geq\").where(\"gps_millis\",gps_millis[1],\"leq\")\n", 117 | "fig = glp.plot_skyplot(cropped_sp3,receiver_state)" 118 | ] 119 | } 120 | ], 121 | "metadata": { 122 | "kernelspec": { 123 | "display_name": "Python 3 (ipykernel)", 124 | "language": "python", 125 | "name": "python3" 126 | }, 127 | "language_info": { 128 | "codemirror_mode": { 129 | "name": "ipython", 130 | "version": 3 131 | }, 132 | "file_extension": ".py", 133 | "mimetype": "text/x-python", 134 | "name": "python", 135 | "nbconvert_exporter": "python", 136 | "pygments_lexer": "ipython3", 137 | "version": "3.8.9" 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 5 142 | } 143 | -------------------------------------------------------------------------------- /notebooks/tutorials/utils/file_operations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# File Operations" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/utils/file_operations.ipynb)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Load `gnss_lib_py` into the Python workspace" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "import gnss_lib_py as glp" 31 | ] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "Python 3 (ipykernel)", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.8.9" 51 | }, 52 | "vscode": { 53 | "interpreter": { 54 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 55 | } 56 | } 57 | }, 58 | "nbformat": 4, 59 | "nbformat_minor": 4 60 | } 61 | -------------------------------------------------------------------------------- /notebooks/tutorials/utils/filters.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Filters" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/utils/filters.ipynb)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Load `gnss_lib_py` into the Python workspace" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "import gnss_lib_py as glp" 31 | ] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "Python 3 (ipykernel)", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.8.9" 51 | }, 52 | "vscode": { 53 | "interpreter": { 54 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 55 | } 56 | } 57 | }, 58 | "nbformat": 4, 59 | "nbformat_minor": 4 60 | } 61 | -------------------------------------------------------------------------------- /notebooks/tutorials/utils/gnss_models.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# GNSS Models" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/utils/gnss_models.ipynb)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Load `gnss_lib_py` into the Python workspace" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "import gnss_lib_py as glp" 31 | ] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "Python 3 (ipykernel)", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.8.9" 51 | }, 52 | "vscode": { 53 | "interpreter": { 54 | "hash": "c7717b1dd2ec65abd747d44a25869d062db68d19263f8e701e26dddb0b153342" 55 | } 56 | } 57 | }, 58 | "nbformat": 4, 59 | "nbformat_minor": 4 60 | } 61 | -------------------------------------------------------------------------------- /notebooks/tutorials/visualizations/plot_map.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "de1216b7-0dd0-4347-82ef-70ef24894508", 6 | "metadata": {}, 7 | "source": [ 8 | "# Plot Map" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "3d5ad162", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/visualizations/plot_map.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "cce0e69e", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import gnss_lib_py as glp\n", 27 | "\n", 28 | "# load Android Google Challenge data\n", 29 | "glp.make_dir(\"../data\")\n", 30 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -nc -O \"../data/Pixel4XL_derived.csv\"\n", 31 | "derived_data = glp.AndroidDerived2021(\"../data/Pixel4XL_derived.csv\", remove_timing_outliers=False)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "f5065f2b-9773-483e-bdac-3b6f36f11090", 37 | "metadata": {}, 38 | "source": [ 39 | "**Note:** In this case, the example data is filtered to be seconds apart, in the regular\n", 40 | "setting, such measurements would be removed. To prevent this from happening,\n", 41 | "we set remove_timing_outliers to False here. For the full dataset, set this flag to True" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "id": "9f18ae5a", 47 | "metadata": {}, 48 | "source": [ 49 | "The `plot_map` function allows you to plot latitude and longitude rows of data on a map. The rows must match the standard naming style of `lat_*_deg` and `lon_*_deg` where `*` can be replaced with an arbitrary string." 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "id": "7849bf4d", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "state_estimate = glp.solve_wls(derived_data)\n", 60 | "fig = glp.plot_map(state_estimate)\n", 61 | "fig.show()" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "id": "287beec9", 67 | "metadata": {}, 68 | "source": [ 69 | "You can plot multiple data traces on the same graph as long as the `*` in the `lat_*_deg` and `lon_*_deg` fields is different for each data trace." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "id": "bd7fbb4b", 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "# load a separate data file\n", 80 | "glp.make_dir(\"../data\")\n", 81 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4_ground_truth.csv --quiet -nc -O \"../data/Pixel4_truth.csv\"\n", 82 | "truth_data_second_trace = glp.AndroidGroundTruth2021(\"../data/Pixel4_truth.csv\")\n", 83 | "\n", 84 | "fig = glp.plot_map(state_estimate, truth_data_second_trace)\n", 85 | "fig.show()" 86 | ] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3 (ipykernel)", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.8.9" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 5 110 | } 111 | -------------------------------------------------------------------------------- /notebooks/tutorials/visualizations/plot_skyplot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "49ad4ff3", 6 | "metadata": {}, 7 | "source": [ 8 | "# Plot Skyplot" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "479d6c17", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/visualizations/plot_skyplot.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "id": "cce0e69e", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import gnss_lib_py as glp\n", 27 | "\n", 28 | "# load Android Google Challenge data\n", 29 | "glp.make_dir(\"../data\")\n", 30 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -nc -O \"../data/Pixel4XL_derived.csv\"\n", 31 | "derived_data = glp.AndroidDerived2021(\"../data/Pixel4XL_derived.csv\", remove_timing_outliers=False)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "952766c1", 37 | "metadata": {}, 38 | "source": [ 39 | "**Note:** In this case, the example data is filtered to be seconds apart, in the regular\n", 40 | "setting, such measurements would be removed. To prevent this from happening,\n", 41 | "we set remove_timing_outliers to False here. For the full dataset, set this flag to True" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "id": "f3c75306", 47 | "metadata": {}, 48 | "source": [ 49 | "The `plot_skyplot` function plots the satellite skyplot using the satellite positions and estimate receiver position." 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "id": "56a5e4c8", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "state_estimate = glp.solve_wls(derived_data)\n", 60 | "\n", 61 | "fig = glp.plot_skyplot(derived_data, state_estimate)" 62 | ] 63 | } 64 | ], 65 | "metadata": { 66 | "kernelspec": { 67 | "display_name": "Python 3 (ipykernel)", 68 | "language": "python", 69 | "name": "python3" 70 | }, 71 | "language_info": { 72 | "codemirror_mode": { 73 | "name": "ipython", 74 | "version": 3 75 | }, 76 | "file_extension": ".py", 77 | "mimetype": "text/x-python", 78 | "name": "python", 79 | "nbconvert_exporter": "python", 80 | "pygments_lexer": "ipython3", 81 | "version": "3.8.9" 82 | } 83 | }, 84 | "nbformat": 4, 85 | "nbformat_minor": 5 86 | } 87 | -------------------------------------------------------------------------------- /notebooks/tutorials/visualizations/style.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "9e484cdf-e507-4ad2-ada0-1df5c2914275", 6 | "metadata": {}, 7 | "source": [ 8 | "# Plotting Style" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "2fbebbd3", 14 | "metadata": {}, 15 | "source": [ 16 | "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Stanford-NavLab/gnss_lib_py/blob/main/notebooks/tutorials/visualizations/style.ipynb)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "952766c1", 22 | "metadata": {}, 23 | "source": [ 24 | "The `visualizations.py` file contains several plotting functionalities. We'll use some existing data to demonstrate their functionality.\n", 25 | "\n", 26 | "**Note:** In this case, the example data is filtered to be seconds apart, in the regular\n", 27 | "setting, such measurements would be removed. To prevent this from happening,\n", 28 | "we set remove_timing_outliers to False here. For the full dataset, set this flag to True" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "id": "cce0e69e", 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "import gnss_lib_py as glp\n", 39 | "\n", 40 | "# load Android Google Challenge data\n", 41 | "glp.make_dir(\"../data\")\n", 42 | "!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2021/Pixel4XL_derived.csv --quiet -nc -O \"../data/Pixel4XL_derived.csv\"\n", 43 | "derived_data = glp.AndroidDerived2021(\"../data/Pixel4XL_derived.csv\", remove_timing_outliers=False)" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "id": "3673683a", 49 | "metadata": {}, 50 | "source": [ 51 | "Since `NavData` is simply a data structure, you can still pull values from it and use standard Python plotting tools like `matplotlib`." 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "id": "47b4753e", 58 | "metadata": { 59 | "scrolled": true 60 | }, 61 | "outputs": [], 62 | "source": [ 63 | "import matplotlib.pyplot as plt\n", 64 | "plt.scatter(derived_data[\"gps_millis\"],derived_data[\"raw_pr_m\"])\n", 65 | "plt.xlabel(\"GPS Milliseconds\")\n", 66 | "plt.ylabel(\"Raw Pseudorange [m]\")\n", 67 | "plt.title(\"Matplotlib Plotting Example\")\n", 68 | "plt.show()" 69 | ] 70 | } 71 | ], 72 | "metadata": { 73 | "kernelspec": { 74 | "display_name": "Python 3 (ipykernel)", 75 | "language": "python", 76 | "name": "python3" 77 | }, 78 | "language_info": { 79 | "codemirror_mode": { 80 | "name": "ipython", 81 | "version": 3 82 | }, 83 | "file_extension": ".py", 84 | "mimetype": "text/x-python", 85 | "name": "python", 86 | "nbconvert_exporter": "python", 87 | "pygments_lexer": "ipython3", 88 | "version": "3.8.9" 89 | } 90 | }, 91 | "nbformat": 4, 92 | "nbformat_minor": 5 93 | } 94 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "gnss-lib-py" 3 | version = "1.0.4" 4 | description = "Modular Python tool for parsing, analyzing, and visualizing Global Navigation Satellite Systems (GNSS) data and state estimates" 5 | authors = ["Derek Knowles ", 6 | "Ashwin Kanhere ", 7 | ] 8 | license = "MIT" 9 | readme = "README.md" 10 | homepage = "https://github.com/Stanford-NavLab/gnss_lib_py" 11 | documentation = "https://gnss-lib-py.readthedocs.io/en/latest/" 12 | keywords = ["gnss"] 13 | classifiers = [ 14 | "Programming Language :: Python :: 3", 15 | "License :: OSI Approved :: MIT License", 16 | "Operating System :: OS Independent", 17 | ] 18 | 19 | [tool.poetry.dependencies] 20 | python = ">=3.9, < 3.13" 21 | numpy = "^2.0.0" 22 | pandas = "^2.0.0" 23 | georinex = "<=1.16.1" 24 | unlzw3 = "^0.2.1" 25 | pynmea2 = "^1.18.0" 26 | pytest = ">=7.2" 27 | scipy = "^1.7.3" 28 | jupyter = "^1.0.0" 29 | notebook = ">=6.0.0" 30 | ipykernel = "^6.0.3" 31 | matplotlib = "^3.5.1" 32 | plotly = "^5.8.0" 33 | kaleido = "0.2.1" 34 | requests = "^2.29.0" 35 | 36 | [tool.poetry.group.dev.dependencies] 37 | Sphinx = "^7.0.0" 38 | sphinx-rtd-theme = "^1.0.0" 39 | sphinxcontrib-napoleon = "^0.7" 40 | pylint-exit = "^1.2.0" 41 | nbsphinx = "^0.8.9" 42 | nbsphinx-link = "^1.3.0" 43 | tqdm = "^4.65.0" 44 | pylint = "^2.11.1" 45 | pytest-cov = "^4.0.0" 46 | sphinx-copybutton = "^0.5.2" 47 | poetry-plugin-export = "^1.8.0" 48 | 49 | [build-system] 50 | requires = ["poetry-core>=1.0.0"] 51 | build-backend = "poetry.core.masonry.api" 52 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | filterwarnings = 3 | ignore:distutils:DeprecationWarning 4 | -------------------------------------------------------------------------------- /results/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/results/.gitkeep -------------------------------------------------------------------------------- /tests/algorithms/test_fde.py: -------------------------------------------------------------------------------- 1 | """Tests for fault detection and exclusion methods. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "11 Jul 2023" 7 | 8 | import os 9 | 10 | import pytest 11 | import numpy as np 12 | 13 | from gnss_lib_py.navdata.navdata import NavData 14 | from gnss_lib_py.algorithms.fde import solve_fde, evaluate_fde 15 | 16 | @pytest.mark.parametrize('method', 17 | [ 18 | "residual", 19 | "edm", 20 | ]) 21 | def test_solve_fde(derived_2022, method): 22 | """Test residual-based FDE. 23 | 24 | Parameters 25 | ---------- 26 | derived_2022 : AndroidDerived2022 27 | Instance of AndroidDerived2022 for testing. 28 | method : string 29 | Method for fault detection and exclusion. 30 | 31 | """ 32 | 33 | # test without removing outliers 34 | navdata = derived_2022.copy() 35 | navdata = solve_fde(navdata, method=method) 36 | assert "fault_" + method in navdata.rows 37 | 38 | # max thresholds shouldn't remove any 39 | navdata = derived_2022.copy() 40 | navdata = solve_fde(navdata, threshold=np.inf, method=method) 41 | assert sum(navdata.where("fault_" + method,1)["fault_" + method]) == 0 42 | 43 | # min threshold should remove most all 44 | navdata = derived_2022.copy() 45 | navdata = solve_fde(navdata, threshold=-np.inf, method=method) 46 | print(sum(navdata.where("fault_" + method,1)["fault_" + method])) 47 | assert len(navdata.where("fault_" + method,0)) == 24 48 | num_unknown = len(navdata.where("fault_" + method,2)) 49 | 50 | navdata = derived_2022.copy() 51 | original_length = len(navdata) 52 | navdata = solve_fde(navdata, 53 | threshold=-np.inf, 54 | max_faults=1, 55 | method=method, 56 | remove_outliers=True, 57 | verbose=True) 58 | assert "fault_" + method in navdata.rows 59 | np.testing.assert_array_equal(np.unique(navdata["fault_" + method]), 60 | np.array([0])) 61 | assert len(navdata) == original_length - num_unknown - 6 62 | 63 | def test_fde_fails(derived_2022): 64 | """Test that solve_fde fails when it should. 65 | 66 | Parameters 67 | ---------- 68 | derived_2022 : AndroidDerived2022 69 | Instance of AndroidDerived2022 for testing. 70 | 71 | """ 72 | 73 | with pytest.raises(ValueError) as excinfo: 74 | solve_fde(derived_2022, method="perfect_method") 75 | assert "invalid method" in str(excinfo.value) 76 | 77 | @pytest.mark.parametrize('method', 78 | [ 79 | "residual", 80 | "edm", 81 | ]) 82 | def test_evaluate_fde(derived_2022, method): 83 | """Evaluate FDE methods. 84 | 85 | Parameters 86 | ---------- 87 | derived_2022 : AndroidDerived2022 88 | Instance of AndroidDerived2022 for testing. 89 | method : string 90 | Method for fault detection and exclusion. 91 | 92 | """ 93 | 94 | navdata = derived_2022.copy() 95 | evaluate_fde(navdata, 96 | method=method, 97 | fault_truth_row="MultipathIndicator", 98 | verbose=True, 99 | time_fde=True, 100 | ) 101 | 102 | if method == "edm": 103 | evaluate_fde(navdata, 104 | method=method, 105 | fault_truth_row="MultipathIndicator", 106 | verbose=False, 107 | time_fde=False, 108 | ) 109 | 110 | def test_edm_breakouts(): 111 | """Test places when EDM FDE should breakout. 112 | 113 | """ 114 | root_path = os.path.dirname( 115 | os.path.dirname( 116 | os.path.dirname( 117 | os.path.realpath(__file__)))) 118 | 119 | # test case when there should be nothing removed 120 | csv_path = os.path.join(root_path, 'data','unit_test','fde', 121 | 'nothing_removed.csv') 122 | navdata = NavData(csv_path=csv_path) 123 | solve_fde(navdata,"edm",threshold=0) 124 | 125 | # test case when there are no fault suspects 126 | csv_path = os.path.join(root_path, 'data','unit_test','fde', 127 | 'no_suspects.csv') 128 | navdata = NavData(csv_path=csv_path) 129 | solve_fde(navdata,"edm",threshold=0) 130 | -------------------------------------------------------------------------------- /tests/algorithms/test_residuals.py: -------------------------------------------------------------------------------- 1 | """Tests for residuals 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "22 Jun 2022" 7 | 8 | import os 9 | import pytest 10 | 11 | import numpy as np 12 | 13 | from gnss_lib_py.algorithms.snapshot import solve_wls 14 | from gnss_lib_py.parsers.google_decimeter import AndroidDerived2021 15 | from gnss_lib_py.navdata.navdata import NavData 16 | from gnss_lib_py.algorithms.residuals import solve_residuals 17 | 18 | def test_residuals_inplace(derived_2021): 19 | """Test that solving for residuals doesn't fail 20 | 21 | Parameters 22 | ---------- 23 | derived_2021 : AndroidDerived2021 24 | Instance of AndroidDerived2021 for testing. 25 | 26 | """ 27 | 28 | derived_original = derived_2021.copy() 29 | 30 | state_estimate = solve_wls(derived_2021) 31 | 32 | solve_residuals(derived_2021, state_estimate) 33 | 34 | # result should still be a NavData Class instance 35 | assert isinstance(derived_2021,type(NavData())) 36 | 37 | # derived should have one more row but same number of cols 38 | assert len(derived_2021.rows) == len(derived_original.rows) + 1 39 | assert len(derived_2021) == len(derived_original) 40 | 41 | # derived should include new residuals rows but not its copy 42 | assert "residuals_m" in derived_2021.rows 43 | assert "residuals_m" not in derived_original.rows 44 | 45 | assert not np.any(np.isinf(derived_2021["residuals_m"])) 46 | 47 | # max is 47.814594604074955 48 | assert max(derived_2021["residuals_m"]) < 50. 49 | 50 | def test_residuals(derived_2021): 51 | """Test that solving for residuals doesn't fail 52 | 53 | Parameters 54 | ---------- 55 | derived_2021 : AndroidDerived2021 56 | Instance of AndroidDerived2021 for testing. 57 | 58 | """ 59 | 60 | state_estimate = solve_wls(derived_2021) 61 | 62 | residuals = solve_residuals(derived_2021, state_estimate, inplace=False) 63 | 64 | # result should still be a NavData Class instance 65 | assert isinstance(residuals,type(NavData())) 66 | 67 | # derived should have one more row but same number of cols 68 | for row in ["residuals_m","gps_millis","gnss_id","sv_id","signal_type"]: 69 | assert row in residuals.rows 70 | assert len(residuals) == len(derived_2021) 71 | 72 | # derived should not include new residuals row 73 | assert "residuals_m" not in derived_2021.rows 74 | 75 | assert not np.any(np.isinf(residuals["residuals_m"])) 76 | 77 | # max is 47.814594604074955 78 | assert max(residuals["residuals_m"]) < 50. 79 | 80 | def test_residuals_fails(derived_2021): 81 | """Test that solving for residuals fails when it should 82 | 83 | Parameters 84 | ---------- 85 | derived_2021 : AndroidDerived2021 86 | Instance of AndroidDerived2021 for testing. 87 | 88 | """ 89 | 90 | state_estimate = solve_wls(derived_2021) 91 | 92 | for inplace in [True,False]: 93 | 94 | for row in ["gps_millis","corr_pr_m"]: 95 | derived_removed = derived_2021.remove(rows=row) 96 | with pytest.raises(KeyError) as excinfo: 97 | _ = solve_residuals(derived_removed, state_estimate, 98 | inplace=inplace) 99 | assert row in str(excinfo.value) 100 | 101 | for row in ["gps_millis"]: 102 | state_estimate_removed = state_estimate.remove(rows=row) 103 | with pytest.raises(KeyError) as excinfo: 104 | _ = solve_residuals(derived_2021, 105 | state_estimate_removed, 106 | inplace=inplace) 107 | assert row in str(excinfo.value) 108 | 109 | for row in ["x_rx_wls_m", "y_rx_wls_m", "z_rx_wls_m", "b_rx_wls_m"]: 110 | duplicated = state_estimate.copy() 111 | new_name = row.split("_") 112 | new_name[2] = "gt" 113 | new_name = "_".join(new_name) 114 | error_name = row[:4] + '*' + row[-2:] 115 | duplicated[new_name] = duplicated[row] 116 | with pytest.raises(KeyError) as excinfo: 117 | _ = solve_residuals(derived_2021, 118 | duplicated, 119 | inplace=inplace) 120 | assert error_name in str(excinfo.value) 121 | 122 | for row in ["x_rx_wls_m", "y_rx_wls_m", "z_rx_wls_m", "b_rx_wls_m"]: 123 | state_estimate_removed = state_estimate.remove(rows=row) 124 | error_name = row[:4] + '*' + row[-2:] 125 | with pytest.raises(KeyError) as excinfo: 126 | _ = solve_residuals(derived_2021, 127 | state_estimate_removed, 128 | inplace=inplace) 129 | assert error_name in str(excinfo.value) 130 | -------------------------------------------------------------------------------- /tests/parsers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/tests/parsers/.gitkeep -------------------------------------------------------------------------------- /tests/parsers/test_clk.py: -------------------------------------------------------------------------------- 1 | """Tests for Clk data loader. 2 | """ 3 | 4 | __authors__ = "Sriramya Bhamidipati" 5 | __date__ = "25 August 2022" 6 | 7 | import os 8 | import random 9 | 10 | import pytest 11 | import numpy as np 12 | 13 | from gnss_lib_py.parsers.clk import Clk 14 | import gnss_lib_py.utils.constants as consts 15 | 16 | # Define the no. of samples to test functions:test_gps_sp3_funcs, 17 | # test_gps_clk_funcs, test_glonass_sp3_funcs, test_glonass_clk_funcs 18 | NUMSAMPLES = 4 19 | 20 | # Define the keys relevant for satellite information 21 | SV_KEYS = ['x_sv_m', 'y_sv_m', 'z_sv_m', \ 22 | 'vx_sv_mps','vy_sv_mps','vz_sv_mps', \ 23 | 'b_sv_m', 'b_dot_sv_mps'] 24 | 25 | @pytest.fixture(name="clk_path") 26 | def fixture_clk_path(root_path): 27 | """Filepath of valid .clk measurements 28 | 29 | Parameters 30 | ---------- 31 | root_path : string 32 | Folder location containing measurements 33 | 34 | Returns 35 | ------- 36 | clk_path : string 37 | String with location for the unit_test clk measurements 38 | 39 | Notes 40 | ----- 41 | Downloaded the relevant .clk files from either CORS website [1]_ or 42 | CDDIS website [2]_ 43 | 44 | References 45 | ---------- 46 | .. [1] https://geodesy.noaa.gov/UFCORS/ Accessed as of August 2, 2022 47 | .. [2] https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/gnss_mgex.html 48 | Accessed as of August 2, 2022 49 | 50 | """ 51 | clk_path = os.path.join(root_path, 'clk/grg21553.clk') 52 | return clk_path 53 | 54 | @pytest.fixture(name="clkdata") 55 | def fixture_load_clkdata(clk_path): 56 | """Load instance of clk data. 57 | 58 | Parameters 59 | ---------- 60 | clk_path : pytest.fixture 61 | String with location for the unit_test clk measurements 62 | 63 | Returns 64 | ------- 65 | clkdata : list 66 | Instances of Clk class for each satellite 67 | """ 68 | clkdata = Clk(clk_path) 69 | 70 | return clkdata 71 | 72 | @pytest.fixture(name="clk_path_missing") 73 | def fixture_clk_path_missing(root_path): 74 | """Filepath of invalid/missing .clk measurements 75 | 76 | Parameters 77 | ---------- 78 | root_path : string 79 | Folder location containing measurements 80 | 81 | Returns 82 | ------- 83 | clk_path_missing : string 84 | String with location for the unit_test clk measurements 85 | 86 | """ 87 | clk_path_missing = os.path.join(root_path, 'clk/grg21553_missing.clk') 88 | return clk_path_missing 89 | 90 | def test_load_clkdata_missing(clk_path_missing): 91 | """Load instance of clk for GPS constellation from missing file 92 | 93 | Parameters 94 | ---------- 95 | clk_path_missing : pytest.fixture 96 | String with invalid location for unit_test clk 97 | measurements 98 | 99 | """ 100 | # Create a sp3 class for each expected satellite 101 | with pytest.raises(FileNotFoundError): 102 | Clk(clk_path_missing) 103 | 104 | # raises exception if input not string or path-like 105 | with pytest.raises(TypeError): 106 | Clk([1]) 107 | 108 | @pytest.fixture(name="clk_path_nodata") 109 | def fixture_clk_path_nodata(root_path): 110 | """Filepath for .clk measurements with no data 111 | 112 | Parameters 113 | ---------- 114 | root_path : string 115 | Folder location containing measurements 116 | 117 | Returns 118 | ------- 119 | clk_path_nodata : string 120 | String with location for the empty clk measurements 121 | 122 | """ 123 | clk_path_nodata = os.path.join(root_path, 'clk/grg21553_nodata.clk') 124 | return clk_path_nodata 125 | 126 | def test_load_clkdata_nodata(clk_path_nodata): 127 | """Load clk instance from file with no data 128 | 129 | Parameters 130 | ---------- 131 | clk_path_nodata : pytest.fixture 132 | String with no available data for unit_test clk 133 | measurements 134 | """ 135 | 136 | clkdata_nodata = Clk(clk_path_nodata) 137 | 138 | assert len(clkdata_nodata) == 0 139 | 140 | @pytest.mark.parametrize('row_name, prn, index, exp_value', 141 | [('b_sv_m', 'G15', 0, -0.00015303409205*consts.C), 142 | ('gps_millis', 'G05', 5, 1303668150000.0), 143 | ('b_sv_m', 'R08', 16, -5.87550990462e-05*consts.C), 144 | ('gps_millis', 'R14', 10, 1303668300000.0), 145 | ] 146 | ) 147 | def test_clkgps_value_check(clkdata, prn, row_name, index, exp_value): 148 | """Check Clk array entries of GPS constellation against 149 | known/expected values using test matrix 150 | 151 | Parameters 152 | ---------- 153 | clkdata : gnss_lib_py.parsers.clk.Clk 154 | CLK data. 155 | prn : int 156 | Satellite PRN for test example 157 | row_name : string 158 | Row key for test example 159 | index : int 160 | Index to query data at 161 | exp_value : float/datetime 162 | Expected value at queried indices 163 | """ 164 | 165 | assert len(np.unique(clkdata.where("gnss_id","gps")["sv_id"])) == 31 166 | assert len(np.unique(clkdata.where("gnss_id","glonass")["sv_id"])) == 20 167 | 168 | curr_value = clkdata.where("gnss_sv_id",prn)[row_name][index] 169 | np.testing.assert_equal(curr_value, exp_value) 170 | -------------------------------------------------------------------------------- /tests/parsers/test_sp3.py: -------------------------------------------------------------------------------- 1 | """Tests for SP3 data loader. 2 | """ 3 | 4 | __authors__ = "Sriramya Bhamidipati" 5 | __date__ = "25 August 2022" 6 | 7 | import os 8 | import random 9 | 10 | import pytest 11 | import numpy as np 12 | 13 | from gnss_lib_py.parsers.sp3 import Sp3 14 | 15 | # Define the no. of samples to test functions:test_gps_sp3_funcs, 16 | # test_gps_clk_funcs, test_glonass_sp3_funcs, test_glonass_clk_funcs 17 | NUMSAMPLES = 4 18 | 19 | # Define the keys relevant for satellite information 20 | SV_KEYS = ['x_sv_m', 'y_sv_m', 'z_sv_m', \ 21 | 'vx_sv_mps','vy_sv_mps','vz_sv_mps', \ 22 | 'b_sv_m', 'b_dot_sv_mps'] 23 | 24 | 25 | @pytest.fixture(name="sp3_path") 26 | def fixture_sp3_path(root_path): 27 | """Filepath of valid .sp3 measurements 28 | 29 | Parameters 30 | ---------- 31 | root_path : string 32 | Folder location containing measurements 33 | 34 | Returns 35 | ------- 36 | sp3_path : string 37 | String with location for the unit_test sp3 measurements 38 | 39 | Notes 40 | ----- 41 | Downloaded the relevant .sp3 files from either CORS website [1]_ or 42 | CDDIS website [2]_ 43 | 44 | References 45 | ---------- 46 | .. [1] https://geodesy.noaa.gov/UFCORS/ Accessed as of August 2, 2022 47 | .. [2] https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/gnss_mgex.html 48 | Accessed as of August 2, 2022 49 | """ 50 | sp3_path = os.path.join(root_path, 'sp3/grg21553.sp3') 51 | return sp3_path 52 | 53 | @pytest.fixture(name="sp3data") 54 | def fixture_load_sp3data(sp3_path): 55 | """Load instance of sp3 data. 56 | 57 | Parameters 58 | ---------- 59 | sp3_path : pytest.fixture 60 | String with location for the unit_test sp3 measurements 61 | 62 | Returns 63 | ------- 64 | sp3data : gnss_lib_py.parsers.sp3.Sp3 65 | Instance of Sp3 class. 66 | """ 67 | sp3data = Sp3(sp3_path) 68 | 69 | return sp3data 70 | 71 | @pytest.fixture(name="sp3_path_missing") 72 | def fixture_sp3_path_missing(root_path): 73 | """Invalid filepath for .sp3 measurements 74 | 75 | Parameters 76 | ---------- 77 | root_path : string 78 | Folder location containing measurements 79 | 80 | Returns 81 | ------- 82 | sp3_path_missing : string 83 | String with location for the unit_test sp3 measurements 84 | """ 85 | 86 | sp3_path_missing = os.path.join(root_path, 'sp3/grg21553_missing.sp3') 87 | return sp3_path_missing 88 | 89 | def test_load_sp3data_missing(sp3_path_missing): 90 | """Load instance of sp3 for GPS constellation from missing file 91 | 92 | Parameters 93 | ---------- 94 | sp3_path_missing : pytest.fixture 95 | String with invalid location for unit_test sp3 96 | measurements 97 | """ 98 | # Create a sp3 class for each expected satellite 99 | with pytest.raises(FileNotFoundError): 100 | Sp3(sp3_path_missing) 101 | 102 | # raises exception if input not string or path-like 103 | with pytest.raises(TypeError): 104 | Sp3([1]) 105 | 106 | @pytest.fixture(name="sp3_path_nodata") 107 | def fixture_sp3_path_nodata(root_path): 108 | """Filepath for .sp3 measurements with no data 109 | 110 | Parameters 111 | ---------- 112 | root_path : string 113 | Folder location containing measurements 114 | 115 | Returns 116 | ------- 117 | sp3_path_nodata : string 118 | String with location for the unit_test sp3 measurements 119 | """ 120 | sp3_path_nodata = os.path.join(root_path, 'sp3/grg21553_nodata.sp3') 121 | return sp3_path_nodata 122 | 123 | def test_load_sp3data_nodata(sp3_path_nodata): 124 | """Load sp3 instance from file with no data 125 | 126 | Parameters 127 | ---------- 128 | sp3_path_nodata : pytest.fixture 129 | String with no available data for unit_test sp3 130 | measurements 131 | """ 132 | 133 | sp3data_nodata = Sp3(sp3_path_nodata) 134 | 135 | assert len(sp3data_nodata) == 0 136 | 137 | @pytest.mark.parametrize('row_name, prn, index, exp_value', 138 | [('x_sv_m', 'G01', 2, 13222742.845), 139 | ('y_sv_m', 'G12', 5, 9753305.474000001), 140 | ('z_sv_m', 'G32', 25, 21728484.688), 141 | ('gps_millis', 'G08', 8, 1303670400000.0), 142 | ('x_sv_m', 'R24', 1, 13383401.364), 143 | ('y_sv_m', 'R02', 7, 3934479.152), 144 | ('z_sv_m', 'R18', 45, 10107376.674999999), 145 | ('gps_millis', 'R12', 17, 1303673100000.0), 146 | ] 147 | ) 148 | def test_sp3gps_value_check(sp3data, prn, row_name, index, exp_value): 149 | """Check array of Sp3 entries for GPS against known values 150 | 151 | Parameters 152 | ---------- 153 | sp3data : pytest.fixture 154 | Instance of Sp3 class 155 | prn : int 156 | Satellite PRN for test example 157 | row_name : string 158 | Row key for test example 159 | index : int 160 | Index to query data at 161 | exp_value : float/datetime 162 | Expected value at queried indices 163 | """ 164 | 165 | assert len(np.unique(sp3data.where("gnss_id","gps")["sv_id"])) == 31 166 | assert len(np.unique(sp3data.where("gnss_id","glonass")["sv_id"])) == 20 167 | 168 | curr_value = sp3data.where("gnss_sv_id",prn)[row_name][index] 169 | np.testing.assert_equal(curr_value, exp_value) 170 | -------------------------------------------------------------------------------- /tests/utils/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/73a819879fe2c26b3eea7e95be9f2761b34802ad/tests/utils/.gitkeep -------------------------------------------------------------------------------- /tests/utils/test_file_operations.py: -------------------------------------------------------------------------------- 1 | """Test file operation utilities. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "01 Jul 2022" 7 | 8 | import gnss_lib_py.utils.file_operations as fo 9 | 10 | # test_make_dir 11 | 12 | def test_get_timestamp(): 13 | """Test for getting timestamp. 14 | 15 | """ 16 | timestamp = fo._get_timestamp() 17 | 18 | # timestamp should be of length 14, YYYYMMDDHHMMSS 19 | assert len(timestamp) == 14 20 | 21 | # timestamp should all be numeric characters 22 | assert timestamp.isnumeric() 23 | -------------------------------------------------------------------------------- /tests/visualizations/test_plot_map.py: -------------------------------------------------------------------------------- 1 | """Tests for visualizations. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "22 Jun 2022" 7 | 8 | import pytest 9 | 10 | import plotly.graph_objects as go 11 | from gnss_lib_py.visualizations import plot_map 12 | 13 | def test_plot_map(gtruth, state_estimate): 14 | """Test for plotting map. 15 | 16 | Parameters 17 | ---------- 18 | gtruth : AndroidGroundTruth2021 19 | Instance of AndroidGroundTruth2021 for testing 20 | state_estimate : gnss_lib_py.navdata.navdata.NavData 21 | Estimated receiver position in ECEF frame in meters and the 22 | estimated receiver clock bias also in meters as an instance of 23 | the NavData class with shape (4 x # unique timesteps) and 24 | the following rows: x_rx_m, y_rx_m, z_rx_m, b_rx_m. 25 | 26 | """ 27 | 28 | fig = plot_map.plot_map(gtruth, state_estimate, save=False) 29 | assert isinstance(fig, go.Figure) 30 | 31 | figs = plot_map.plot_map(gtruth, state_estimate,sections=3, save=False) 32 | for fig in figs: 33 | assert isinstance(fig, go.Figure) 34 | 35 | with pytest.raises(TypeError) as excinfo: 36 | plot_map.plot_map([], state_estimate, save=False) 37 | assert "NavData" in str(excinfo.value) 38 | assert "Input" in str(excinfo.value) 39 | 40 | for row in ["lat_rx_wls_deg","lon_rx_wls_deg"]: 41 | state_removed = state_estimate.remove(rows=row) 42 | with pytest.raises(KeyError) as excinfo: 43 | plot_map.plot_map(gtruth, state_removed, save=False) 44 | assert row.replace("rx_wls","*") in str(excinfo.value) 45 | assert "Missing" in str(excinfo.value) 46 | 47 | for row in ["lat_rx_wls_deg","lon_rx_wls_deg"]: 48 | state_double = state_estimate.copy() 49 | state_double[row.replace("rx","2")] = state_double[row] 50 | with pytest.raises(KeyError) as excinfo: 51 | plot_map.plot_map(gtruth, state_double, save=False) 52 | assert row.replace("rx_wls","*") in str(excinfo.value) 53 | assert "More than 1" in str(excinfo.value) 54 | -------------------------------------------------------------------------------- /tests/visualizations/test_plot_metric.py: -------------------------------------------------------------------------------- 1 | """Tests for visualizations. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "22 Jun 2022" 7 | 8 | import pytest 9 | import matplotlib.pyplot as plt 10 | 11 | from gnss_lib_py.visualizations import style 12 | import gnss_lib_py.visualizations.plot_metric as metric 13 | 14 | def test_plot_metrics(derived_2021): 15 | """Test for plotting metrics. 16 | 17 | Parameters 18 | ---------- 19 | derived_2021 : AndroidDerived2021 20 | Instance of AndroidDerived2021 for testing. 21 | 22 | """ 23 | test_rows = [ 24 | "raw_pr_m", 25 | ] 26 | 27 | for row in derived_2021.rows: 28 | if not derived_2021.is_str(row): 29 | if row in test_rows: 30 | fig = plt.figure() 31 | for groupby in ["gnss_id",None]: 32 | fig = metric.plot_metric(derived_2021, row, 33 | groupby = groupby, 34 | save=False) 35 | style.close_figures(fig) 36 | else: 37 | # string rows should cause a KeyError 38 | with pytest.raises(KeyError) as excinfo: 39 | fig = metric.plot_metric(derived_2021, row, save=False) 40 | style.close_figures(fig) 41 | assert "non-numeric row" in str(excinfo.value) 42 | 43 | with pytest.raises(TypeError) as excinfo: 44 | metric.plot_metric(derived_2021, "raw_pr_m", save=True, prefix=1) 45 | assert "Prefix" in str(excinfo.value) 46 | 47 | for row in derived_2021.rows: 48 | if not derived_2021.is_str(row): 49 | if row in test_rows: 50 | for groupby in ["gnss_id",None]: 51 | fig = metric.plot_metric(derived_2021, "raw_pr_m", row, 52 | groupby=groupby, save=False) 53 | style.close_figures(fig) 54 | else: 55 | # string rows should cause a KeyError 56 | with pytest.raises(KeyError) as excinfo: 57 | fig = metric.plot_metric(derived_2021, "raw_pr_m", row, save=False) 58 | style.close_figures(fig) 59 | with pytest.raises(KeyError) as excinfo: 60 | fig = metric.plot_metric(derived_2021, row, "raw_pr_m", save=False) 61 | style.close_figures(fig) 62 | assert "non-numeric row" in str(excinfo.value) 63 | 64 | style.close_figures() 65 | 66 | # test repeating figure and average y 67 | fig = plt.figure() 68 | fig = metric.plot_metric(derived_2021, "gps_millis", "raw_pr_m", 69 | fig = fig, 70 | groupby = "gnss_id", 71 | save=False) 72 | fig = metric.plot_metric(derived_2021, "gps_millis", "raw_pr_m", 73 | fig = fig, 74 | groupby = "gnss_id", 75 | avg_y = True, 76 | linestyle="dotted", 77 | save=False, 78 | ) 79 | style.close_figures(fig) 80 | 81 | with pytest.raises(TypeError) as excinfo: 82 | metric.plot_metric(derived_2021, "raw_pr_m", save=True, prefix=1) 83 | assert "Prefix" in str(excinfo.value) 84 | 85 | with pytest.raises(ValueError) as excinfo: 86 | metric.plot_metric(derived_2021, 'raw_pr_m', row, row, save=False) 87 | 88 | with pytest.raises(TypeError) as excinfo: 89 | metric.plot_metric("derived", 'raw_pr_m', save=False) 90 | assert "NavData" in str(excinfo.value) 91 | 92 | def test_plot_metrics_by_constellation(derived_2021): 93 | """Test for plotting metrics by constellation. 94 | 95 | Parameters 96 | ---------- 97 | derived_2021 : AndroidDerived2021 98 | Instance of AndroidDerived2021 for testing. 99 | 100 | """ 101 | 102 | test_rows = [ 103 | "raw_pr_m", 104 | ] 105 | 106 | for row in derived_2021.rows: 107 | if not derived_2021.is_str(row): 108 | if row in test_rows: 109 | for prefix in ["","test"]: 110 | fig = metric.plot_metric_by_constellation(derived_2021, row, 111 | prefix=prefix,save=False) 112 | style.close_figures() 113 | else: 114 | # string rows should cause a KeyError 115 | with pytest.raises(KeyError) as excinfo: 116 | fig = metric.plot_metric_by_constellation(derived_2021, row, 117 | save=False) 118 | style.close_figures(fig) 119 | assert "non-numeric row" in str(excinfo.value) 120 | 121 | with pytest.raises(TypeError) as excinfo: 122 | metric.plot_metric_by_constellation(derived_2021, "raw_pr_m", save=True, 123 | prefix=1) 124 | assert "Prefix" in str(excinfo.value) 125 | 126 | with pytest.raises(TypeError) as excinfo: 127 | metric.plot_metric_by_constellation("derived", "raw_pr_m", save=True) 128 | assert "NavData" in str(excinfo.value) 129 | 130 | derived_no_gnss_id = derived_2021.remove(rows="gnss_id") 131 | with pytest.raises(KeyError) as excinfo: 132 | metric.plot_metric_by_constellation(derived_no_gnss_id, "raw_pr_m", 133 | save=False) 134 | assert "gnss_id" in str(excinfo.value) 135 | 136 | for optional_row in ["sv_id","signal_type",["sv_id","signal_type"]]: 137 | derived_partial = derived_2021.remove(rows=optional_row) 138 | figs = metric.plot_metric_by_constellation(derived_partial, 139 | "raw_pr_m", save=False) 140 | style.close_figures(figs) 141 | -------------------------------------------------------------------------------- /tests/visualizations/test_plot_skyplot.py: -------------------------------------------------------------------------------- 1 | """Tests for visualizations. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "22 Jun 2022" 7 | 8 | import os 9 | 10 | import pytest 11 | import numpy as np 12 | import matplotlib as mpl 13 | 14 | from conftest import lazy_fixture 15 | from gnss_lib_py.navdata.navdata import NavData 16 | from gnss_lib_py.navdata.operations import find_wildcard_indexes 17 | from gnss_lib_py.visualizations import style 18 | from gnss_lib_py.visualizations import plot_skyplot 19 | from gnss_lib_py.utils.coordinates import geodetic_to_ecef 20 | from gnss_lib_py.parsers.google_decimeter import AndroidDerived2022 21 | 22 | @pytest.mark.parametrize('navdata',[ 23 | # lazy_fixture('derived_2022'), 24 | lazy_fixture('derived_2021'), 25 | ]) 26 | def test_plot_skyplot(navdata, state_estimate): 27 | """Test for plotting skyplot. 28 | 29 | Parameters 30 | ---------- 31 | navdata : AndroidDerived 32 | Instance of AndroidDerived for testing. 33 | state_estimate : gnss_lib_py.navdata.navdata.NavData 34 | Estimated receiver position in ECEF frame in meters and the 35 | estimated receiver clock bias also in meters as an instance of 36 | the NavData class with shape (4 x # unique timesteps) and 37 | the following rows: x_rx_m, y_rx_m, z_rx_m, b_rx_m. 38 | 39 | """ 40 | 41 | if isinstance(navdata, AndroidDerived2022): 42 | state_estimate = navdata.copy(rows=["gps_millis","x_rx_m","y_rx_m","z_rx_m"]) 43 | 44 | sv_nan = np.unique(navdata["sv_id"])[0] 45 | for col_idx, col in enumerate(navdata): 46 | if col["sv_id"] == sv_nan: 47 | navdata["x_sv_m",col_idx] = np.nan 48 | 49 | # don't save figures 50 | fig = plot_skyplot.plot_skyplot(navdata.copy(), state_estimate, save=False) 51 | style.close_figures(fig) 52 | 53 | with pytest.raises(TypeError) as excinfo: 54 | plot_skyplot.plot_skyplot(navdata.copy(), state_estimate, save=True, prefix=1) 55 | assert "Prefix" in str(excinfo.value) 56 | 57 | with pytest.raises(TypeError) as excinfo: 58 | plot_skyplot.plot_skyplot("derived", "raw_pr_m", save=True) 59 | assert "NavData" in str(excinfo.value) 60 | 61 | for row in ["x_sv_m","y_sv_m","z_sv_m","gps_millis"]: 62 | derived_removed = navdata.remove(rows=row) 63 | with pytest.raises(KeyError) as excinfo: 64 | plot_skyplot.plot_skyplot(derived_removed, state_estimate, save=False) 65 | assert row in str(excinfo.value) 66 | 67 | for row in ["x_rx_m","y_rx_m","z_rx_m"]: 68 | row_idx = find_wildcard_indexes(state_estimate,row[:4]+'*'+row[4:])[row[:4]+'*'+row[4:]][0] 69 | state_removed = state_estimate.remove(rows=row_idx) 70 | with pytest.raises(KeyError) as excinfo: 71 | plot_skyplot.plot_skyplot(navdata, state_removed, save=False) 72 | assert row[:4]+'*'+row[4:] in str(excinfo.value) 73 | assert "Missing" in str(excinfo.value) 74 | 75 | for row in ["x_rx_m","y_rx_m","z_rx_m"]: 76 | state_double = state_estimate.copy() 77 | row_idx = find_wildcard_indexes(state_estimate,row[:4]+'*'+row[4:])[row[:4]+'*'+row[4:]][0] 78 | state_double[row_idx.replace("rx_","rx_gt_")] = state_double[row_idx] 79 | with pytest.raises(KeyError) as excinfo: 80 | plot_skyplot.plot_skyplot(navdata, state_double, save=False) 81 | assert row[:4]+'*'+row[4:] in str(excinfo.value) 82 | assert "More than 1" in str(excinfo.value) 83 | 84 | def test_skyplot_trim(root_path): 85 | """Test trimming separate time instances for same SV. 86 | 87 | Parameters 88 | ---------- 89 | root_path : string 90 | Folder location containing unit test data 91 | 92 | """ 93 | 94 | sp3_path = os.path.join(root_path,"vis","sp3_g05.csv") 95 | sp3 = NavData(csv_path=sp3_path) 96 | 97 | lat, lon, alt = -77.87386688990695, -34.62755517700375, 0. 98 | x_rx_m, y_rx_m, z_rx_m = geodetic_to_ecef(np.array([[lat,lon,alt]]))[0] 99 | receiver_state = NavData() 100 | receiver_state["gps_millis"] = 0. 101 | receiver_state["x_rx_m"] = x_rx_m 102 | receiver_state["y_rx_m"] = y_rx_m 103 | receiver_state["z_rx_m"] = z_rx_m 104 | 105 | fig = plot_skyplot.plot_skyplot(sp3,receiver_state) 106 | # verify that two line segments were removed. Should be 57 not 59 107 | # after trimming the two separated ones. 108 | for child in fig.get_children(): 109 | if isinstance(child,mpl.projections.polar.PolarAxes): 110 | for grandchild in child.get_children(): 111 | if isinstance(grandchild,mpl.collections.LineCollection): 112 | assert len(grandchild.get_array()) == 57 113 | style.close_figures() 114 | 115 | fig = plot_skyplot.plot_skyplot(sp3,receiver_state,trim_options={"az" : 95.}) 116 | # verify that only one line segment was removed. Should be 58 not 59 117 | # after trimming the one larger than 95 degrees in azimuth separated ones. 118 | for child in fig.get_children(): 119 | if isinstance(child,mpl.projections.polar.PolarAxes): 120 | for grandchild in child.get_children(): 121 | if isinstance(grandchild,mpl.collections.LineCollection): 122 | assert len(grandchild.get_array()) == 58 123 | style.close_figures() 124 | 125 | fig = plot_skyplot.plot_skyplot(sp3,receiver_state,trim_options={"gps_millis" : 3.5E6}) 126 | # verify that only one line segment was removed. Should be 58 not 59 127 | # after trimming the one larger than 95 degrees in azimuth separated ones. 128 | for child in fig.get_children(): 129 | if isinstance(child,mpl.projections.polar.PolarAxes): 130 | for grandchild in child.get_children(): 131 | if isinstance(grandchild,mpl.collections.LineCollection): 132 | assert len(grandchild.get_array()) == 57 133 | style.close_figures() 134 | 135 | 136 | with pytest.raises(TypeError) as excinfo: 137 | plot_skyplot.plot_skyplot(sp3, receiver_state, step=20.1) 138 | assert "step" in str(excinfo.value) 139 | -------------------------------------------------------------------------------- /tests/visualizations/test_style.py: -------------------------------------------------------------------------------- 1 | """Tests for visualizations. 2 | 3 | """ 4 | 5 | __authors__ = "D. Knowles" 6 | __date__ = "22 Jun 2022" 7 | 8 | import random 9 | 10 | import pytest 11 | import numpy as np 12 | 13 | from gnss_lib_py.visualizations import style 14 | 15 | # pylint: disable=protected-access 16 | 17 | def testget_label(): 18 | """Test for getting nice labels. 19 | 20 | """ 21 | 22 | assert style.get_label({"signal_type" : "l1"}) == "L1" 23 | assert style.get_label({"signal_type" : "g1"}) == "G1" 24 | assert style.get_label({"signal_type" : "b1i"}) == "B1i" 25 | # shouldn't do lowercase 'i' trick if not signal_type 26 | assert style.get_label({"random" : "BDS_B1I"}) == "BDS B1I" 27 | 28 | assert style.get_label({"gnss_id" : "beidou"}) == "BeiDou" 29 | assert style.get_label({"gnss_id" : "gps"}) == "GPS" 30 | assert style.get_label({"gnss_id" : "galileo"}) == "Galileo" 31 | 32 | assert style.get_label({"gnss_id" : "galileo", 33 | "signal_type" : "b1i"}) == "Galileo B1i" 34 | 35 | assert style.get_label({"row" : "x_rx_m"}) == "X RX [m]" 36 | assert style.get_label({"row" : "lat_rx_deg"}) == "LAT RX [deg]" 37 | assert style.get_label({"row" : "vx_sv_mps"}) == "VX SV [m/s]" 38 | 39 | with pytest.raises(TypeError) as excinfo: 40 | style.get_label(["should","fail"]) 41 | assert "dictionary" in str(excinfo.value) 42 | 43 | def testsort_gnss_ids(): 44 | """Test sorting GNSS IDs. 45 | 46 | """ 47 | 48 | unsorted_ids = ["galileo","beta","beidou","irnss","gps","unknown","glonass", 49 | "alpha","qzss","sbas"] 50 | sorted_ids = ["gps","glonass","galileo","beidou","qzss","irnss","sbas", 51 | "unknown", "alpha", "beta"] 52 | 53 | assert style.sort_gnss_ids(unsorted_ids) == sorted_ids 54 | assert style.sort_gnss_ids(np.array(unsorted_ids)) == sorted_ids 55 | assert style.sort_gnss_ids(set(unsorted_ids)) == sorted_ids 56 | assert style.sort_gnss_ids(tuple(unsorted_ids)) == sorted_ids 57 | 58 | for _ in range(100): 59 | random.shuffle(unsorted_ids) 60 | assert style.sort_gnss_ids(unsorted_ids) == sorted_ids 61 | assert style.sort_gnss_ids(np.array(unsorted_ids)) == sorted_ids 62 | assert style.sort_gnss_ids(set(unsorted_ids)) == sorted_ids 63 | assert style.sort_gnss_ids(tuple(unsorted_ids)) == sorted_ids 64 | 65 | def test_close_figures_fail(): 66 | """Test expected fail conditions. 67 | 68 | """ 69 | 70 | style.close_figures([]) 71 | 72 | with pytest.raises(TypeError) as excinfo: 73 | style.close_figures(0.) 74 | assert "figure" in str(excinfo.value) 75 | --------------------------------------------------------------------------------