Skip to article frontmatterSkip to article content

Exercise 3: GNSS-Acoustic Metadata

University of Washington

Introduction

GNSS-A is a powerful tool for positioning the seafloor, but it requires precise information from a number of outside sources in order to properly function. This exercise is meant to help users explore the metadata required to position a GNSS-A array, and will cover the following topics:

  • Time delays of the seafloor transponders and sea surface transducer
  • The sound velocity profile of the water column
  • Transponder a priori positions

Files Present

Data files for this exercise may be found in the directory ../data/exercise-3, including:

  • A configuration file NCB1_2024_config.yaml
  • An output folder output with the GNATSS solution for this survey
  • A folder ctd with sound velocity input

The data we will operate on is the 2024 survey of the GNSS-A array NCB1 offshore Coos Bay, OR, collected as part of the Near Trench Community Geodesy Experiment. This exercise will have multiple sections where users are expected to modify the metadata of this survey. A convenient way to do this while following along with the exercise instructions is to open NCB1_2024_config.yaml in a split screen on the VSCode interface in the Codespace. We have provided a backup copy of the configuration file, NCB1_2024_reference_config.yaml, so that any changes users make throughout this exercise may be easily reverted. In addition, a backup of the initial solution is available in a separate directory ../data/exercise-3/reference_solution. Since many examples will involve comparing residuals, we also recommend opening the file ../data/exercise-3/reference_solution/residuals.png for an easy comparison.

Review of GNATSS Processing

As a quick review, you can easily process data in the community standard GNSS-A data format using the --solver module of GNATSS. GNATSS automatically generates data in this format with the --posfilter module during pre-processing and saves it as the file gps_solution.csv in the user-specified output directory. In order to process a gps_solution.csv file given a configuration file and ctd, run the following commands:

from gnatss.main import run_gnatss
# Set input variables

config_yaml = "../data/exercise-3/NCB1_2024_config.yaml"
skip_posfilter = True

# Run GNATSS solver

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1481.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1481.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 121.16 cm, error factor = 70.028
NCB1-3
D_x = -8.340716e-02 m, Sigma(x) = 5.903304e-05 m
D_y = -6.230696e-01 m, Sigma(y) = 5.907595e-05 m
D_z = 4.571199e-01 m, Sigma(z) = 5.480098e-05 m
NCB1-2
D_x = -8.340716e-02 m, Sigma(x) = 5.903304e-05 m
D_y = -6.230696e-01 m, Sigma(y) = 5.907595e-05 m
D_z = 4.571199e-01 m, Sigma(z) = 5.480098e-05 m
NCB1-1
D_x = -8.340716e-02 m, Sigma(x) = 5.903304e-05 m
D_y = -6.230696e-01 m, Sigma(y) = 5.907595e-05 m
D_z = 4.571199e-01 m, Sigma(z) = 5.480098e-05 m

After iteration: 2, rms residual = 42.02 cm, error factor = 24.341
NCB1-3
D_x = -1.42115e-04 m, Sigma(x) = 5.901226e-05 m
D_y = -4.702208e-08 m, Sigma(y) = 5.906742e-05 m
D_z = 9.600661e-05 m, Sigma(z) = 5.479155e-05 m
NCB1-2
D_x = -1.42115e-04 m, Sigma(x) = 5.901226e-05 m
D_y = -4.702208e-08 m, Sigma(y) = 5.906742e-05 m
D_z = 9.600661e-05 m, Sigma(z) = 5.479155e-05 m
NCB1-1
D_x = -1.42115e-04 m, Sigma(x) = 5.901226e-05 m
D_y = -4.702208e-08 m, Sigma(y) = 5.906742e-05 m
D_z = 9.600661e-05 m, Sigma(z) = 5.479155e-05 m

After iteration: 3, rms residual = 42.02 cm, error factor = 24.341
NCB1-3
D_x = 3.275505e-11 m, Sigma(x) = 5.901226e-05 m
D_y = 4.586362e-10 m, Sigma(y) = 5.906742e-05 m
D_z = 1.724785e-10 m, Sigma(z) = 5.479155e-05 m
NCB1-2
D_x = 3.275469e-11 m, Sigma(x) = 5.901226e-05 m
D_y = 4.586358e-10 m, Sigma(y) = 5.906742e-05 m
D_z = 1.724784e-10 m, Sigma(z) = 5.479155e-05 m
NCB1-1
D_x = 3.275469e-11 m, Sigma(x) = 5.901226e-05 m
D_y = 4.586358e-10 m, Sigma(y) = 5.906742e-05 m
D_z = 1.724789e-10 m, Sigma(z) = 5.479155e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660361.4551 +/- 5.901226e-05 m del_e = 0.2899 +/- 6.292098e-05 m
y = -3785656.3628 +/- 5.906742e-05 m del_n = -0.0533 +/- 6.478935e-05 m
z = 4373657.0192 +/- 5.479155e-05 m del_u = 0.7193 +/- 4.262406e-05 m
Lat. = 43.580175349912544 deg, Long. = -125.09754421629697, Hgt.msl = -1075.9369203950735 m
NCB1-2
x = -2660958.2975 +/- 5.901226e-05 m del_e = 0.2899 +/- 6.292099e-05 m
y = -3786495.9812 +/- 5.906742e-05 m del_n = -0.0532 +/- 6.478910e-05 m
z = 4372517.1292 +/- 5.479155e-05 m del_u = 0.7193 +/- 4.262443e-05 m
Lat. = 43.56634903447311 deg, Long. = -125.0976131200877, Hgt.msl = -1115.326107800054 m
NCB1-1
x = -2661822.704 +/- 5.901226e-05 m del_e = 0.2901 +/- 6.292183e-05 m
y = -3785267.4541 +/- 5.906742e-05 m del_n = -0.0532 +/- 6.478858e-05 m
z = 4373014.9447 +/- 5.479155e-05 m del_u = 0.7192 +/- 4.262398e-05 m
Lat. = 43.57274750129832 deg, Long. = -125.1151158405841, Hgt.msl = -1140.2246779177544 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

This solution will serve as the baseline for the exercises below. We have also provided a copy of this solution in the ../data/exercise-3/reference_solution folder. We recommend opening the residual plots reference_solution/residuals.png and reference_solution/residuals_enu_components.png in the sidebar so that you can make a quick comparison as we change the metadata.

Travel time delays

Perhaps the most critical piece of metadata required for GNSS-A processing is information about the timing delays introduced into the measurements by the instruments, since if these delays are not properly accounted for the user is liable to significantly overestimate the range to the transponders. While these time delays may not be larger than a few dozen milliseconds, consider that 1) the transducer records two-way travel times with microsecond precision, and 2) the speed of sound in seawater is large enough that 1 ms corresponds to approximately 1.5 meters travelled by an acoustic pulse. As a result, even minute discrepencies in the time delays assumed can lead to significant biases in the final solution.

There are two time delays we will consider, the time delay in the transponders (called the turn-around time or TAT) and the time delay in the transducer on the sea surface (also called the trigger delay).

Turn-around Time

The TAT is a user-defined internal delay present in the seafloor transponders. It’s purpose is to stagger the transponder replies so that they do not interfere when being recorded by the sea surface transducer. If you inspect the configuration file ../data/exercise-3/NCB1_2024_config.yaml you will find the TATs logged for each transponder under the key internal_delay.

transponders: # list out all transponder and info, each entry is a different transponder (default: 3 transponders)
  - lat: 43.580175830 #decimal latitude
    lon: -125.097547806 #decimal longitude
    height: -1076.6562 #transponder depth (m, positive up)
    internal_delay: 0.08 #Transponder Turn-Around Time (s)
    sv_mean: 1481.683 #Estimate of mean sound velocity (m/s)
    pxp_id: NCB1-3
  - lat: 43.566349513 #decimal latitude
    lon: -125.097616709 #decimal longitude
    height: -1116.0454 #transponder depth (m, positive up)
    internal_delay: 0.36 #Transponder Turn-Around Time (s)
    sv_mean: 1486.696 #Estimate of mean sound velocity (m/s)
    pxp_id: NCB1-2
  - lat: 43.572747980 #decimal latitude
    lon: -125.115119432 #decimal longitude
    height: -1140.9439 #transponder depth (m, positive up)
    internal_delay: 0.64 #Transponder Turn-Around Time (s)
    sv_mean: 1481.705 #Estimate of mean sound velocity (m/s)
    pxp_id: NCB1-1

The TAT is assumed to be included in the acoustic TWTT measurements in the gps_solution.csv file since they occur in between the transducer sending an interrogation ping and receiving a reply, and GNATSS will automatically remove it before modelling the ray path between the transducer and transponder.

Let’s go ahead and modify the configuration file NCB1_2024_config.yaml. Set the TAT of the first transponder (NCB1-3) to 0.20, the TAT of the second transponder (NCB1-2) to 0.32, and the TAT of the third transponder (NCB1-1) to 0.44. These delays have only been changed by a small fraction of a second, but if we re-run the solver we can see that this has made a large difference in the residual plot.

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.2 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.32 sv_mean=1481.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.44 sv_mean=1481.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 20191.96 cm, error factor = 11697.032
NCB1-3
D_x = -1.719658e+02 m, Sigma(x) = 5.903304e-05 m
D_y = 6.481243e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.046278e+02 m, Sigma(z) = 5.480098e-05 m
NCB1-2
D_x = -1.719658e+02 m, Sigma(x) = 5.903304e-05 m
D_y = 6.481243e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.046278e+02 m, Sigma(z) = 5.480098e-05 m
NCB1-1
D_x = -1.719658e+02 m, Sigma(x) = 5.903304e-05 m
D_y = 6.481243e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.046278e+02 m, Sigma(z) = 5.480098e-05 m

After iteration: 2, rms residual = 2554.71 cm, error factor = 1482.597
NCB1-3
D_x = -1.135377e+01 m, Sigma(x) = 6.321949e-05 m
D_y = -4.459625e+00 m, Sigma(y) = 5.993688e-05 m
D_z = 1.234504e+01 m, Sigma(z) = 5.323035e-05 m
NCB1-2
D_x = -1.135377e+01 m, Sigma(x) = 6.321949e-05 m
D_y = -4.459625e+00 m, Sigma(y) = 5.993688e-05 m
D_z = 1.234504e+01 m, Sigma(z) = 5.323035e-05 m
NCB1-1
D_x = -1.135377e+01 m, Sigma(x) = 6.321949e-05 m
D_y = -4.459625e+00 m, Sigma(y) = 5.993688e-05 m
D_z = 1.234504e+01 m, Sigma(z) = 5.323035e-05 m

After iteration: 3, rms residual = 616.99 cm, error factor = 355.629
NCB1-3
D_x = 1.703389e-02 m, Sigma(x) = 6.300109e-05 m
D_y = -7.156692e-02 m, Sigma(y) = 5.951103e-05 m
D_z = 3.118457e-02 m, Sigma(z) = 5.303439e-05 m
NCB1-2
D_x = 1.703389e-02 m, Sigma(x) = 6.300109e-05 m
D_y = -7.156692e-02 m, Sigma(y) = 5.951103e-05 m
D_z = 3.118457e-02 m, Sigma(z) = 5.303439e-05 m
NCB1-1
D_x = 1.703389e-02 m, Sigma(x) = 6.300109e-05 m
D_y = -7.156692e-02 m, Sigma(y) = 5.951103e-05 m
D_z = 3.118457e-02 m, Sigma(z) = 5.303439e-05 m

After iteration: 4, rms residual = 616.99 cm, error factor = 355.581
NCB1-3
D_x = -3.477087e-06 m, Sigma(x) = 6.299847e-05 m
D_y = 2.529299e-06 m, Sigma(y) = 5.95109e-05 m
D_z = 2.178263e-06 m, Sigma(z) = 5.303345e-05 m
NCB1-2
D_x = -3.477087e-06 m, Sigma(x) = 6.299847e-05 m
D_y = 2.529299e-06 m, Sigma(y) = 5.95109e-05 m
D_z = 2.178263e-06 m, Sigma(z) = 5.303345e-05 m
NCB1-1
D_x = -3.477087e-06 m, Sigma(x) = 6.299847e-05 m
D_y = 2.529299e-06 m, Sigma(y) = 5.95109e-05 m
D_z = 2.178263e-06 m, Sigma(z) = 5.303345e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660544.6741 +/- 6.299847e-05 m del_e = -184.6333 +/- 6.64786e-05 m
y = -3785595.4585 +/- 5.95109e-05 m del_n = -105.4829 +/- 6.380095e-05 m
z = 4373564.3104 +/- 5.303345e-05 m del_u = -22.9755 +/- 4.281279e-05 m
Lat. = 43.579226231864055 deg, Long. = -125.09983410076767, Hgt.msl = -1099.6282070674918 m
NCB1-2
x = -2661141.5165 +/- 6.299847e-05 m del_e = -184.6333 +/- 6.647860e-05 m
y = -3786435.0769 +/- 5.95109e-05 m del_n = -105.4886 +/- 6.380021e-05 m
z = 4372424.4204 +/- 5.303345e-05 m del_u = -22.9499 +/- 4.281389e-05 m
Lat. = 43.56539985543453 deg, Long. = -125.0999024940436, Hgt.msl = -1138.9917908086309 m
NCB1-1
x = -2662005.923 +/- 6.299847e-05 m del_e = -184.6161 +/- 6.647865e-05 m
y = -3785206.5498 +/- 5.95109e-05 m del_n = -105.5249 +/- 6.379946e-05 m
z = 4372922.2359 +/- 5.303345e-05 m del_u = -22.9209 +/- 4.281493e-05 m
Lat. = 43.57179799290875 deg, Long. = -125.1174052557141, Hgt.msl = -1163.8612097222974 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

The residuals here are nearly illegible and the array offset is comically large, so it is clear that even though the changed time delays seemed small, their impact was significant.

To drive this point home, let us execute another example in which we only modify one of the TATs and by a smaller amount. Change the TAT values in the configuration file to 0.12 for NCB1-3, 0.36 for NCB1-2, and 0.64 for NCB1-1. These are the actual values for NCB1-2 and NCB1-1, which you can verify in the reference configuration file, and the TAT for NCB1-3 has only been increased by 0.04s (the smallest possible increment allowed by the Sonardyne transponders) from its actual value of 0.08s

Now, execute the solver again on this mostly corrected configuration file.

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.12 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1481.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1481.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 3479.41 cm, error factor = 2015.448
NCB1-3
D_x = -2.779727e+01 m, Sigma(x) = 5.903304e-05 m
D_y = -1.570377e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.043835e+01 m, Sigma(z) = 5.480098e-05 m
NCB1-2
D_x = -2.779727e+01 m, Sigma(x) = 5.903304e-05 m
D_y = -1.570377e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.043835e+01 m, Sigma(z) = 5.480098e-05 m
NCB1-1
D_x = -2.779727e+01 m, Sigma(x) = 5.903304e-05 m
D_y = -1.570377e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -1.043835e+01 m, Sigma(z) = 5.480098e-05 m

After iteration: 2, rms residual = 132.64 cm, error factor = 76.983
NCB1-3
D_x = 7.367611e-02 m, Sigma(x) = 5.890691e-05 m
D_y = -1.325699e-01 m, Sigma(y) = 5.924680e-05 m
D_z = 4.560862e-01 m, Sigma(z) = 5.407418e-05 m
NCB1-2
D_x = 7.367611e-02 m, Sigma(x) = 5.890691e-05 m
D_y = -1.325699e-01 m, Sigma(y) = 5.924680e-05 m
D_z = 4.560862e-01 m, Sigma(z) = 5.407418e-05 m
NCB1-1
D_x = 7.367611e-02 m, Sigma(x) = 5.890691e-05 m
D_y = -1.325699e-01 m, Sigma(y) = 5.924680e-05 m
D_z = 4.560862e-01 m, Sigma(z) = 5.407418e-05 m

After iteration: 3, rms residual = 116.7 cm, error factor = 67.435
NCB1-3
D_x = -5.649571e-05 m, Sigma(x) = 5.889708e-05 m
D_y = -4.998963e-05 m, Sigma(y) = 5.923576e-05 m
D_z = 5.868157e-06 m, Sigma(z) = 5.407446e-05 m
NCB1-2
D_x = -5.649571e-05 m, Sigma(x) = 5.889708e-05 m
D_y = -4.998963e-05 m, Sigma(y) = 5.923576e-05 m
D_z = 5.868157e-06 m, Sigma(z) = 5.407446e-05 m
NCB1-1
D_x = -5.649571e-05 m, Sigma(x) = 5.889708e-05 m
D_y = -4.998963e-05 m, Sigma(y) = 5.923576e-05 m
D_z = 5.868157e-06 m, Sigma(z) = 5.407446e-05 m

After iteration: 4, rms residual = 116.7 cm, error factor = 67.435
NCB1-3
D_x = 2.800582e-10 m, Sigma(x) = 5.889708e-05 m
D_y = 5.237396e-10 m, Sigma(y) = 5.923576e-05 m
D_z = -1.195382e-10 m, Sigma(z) = 5.407445e-05 m
NCB1-2
D_x = 2.800604e-10 m, Sigma(x) = 5.889708e-05 m
D_y = 5.237446e-10 m, Sigma(y) = 5.923576e-05 m
D_z = -1.195346e-10 m, Sigma(z) = 5.407445e-05 m
NCB1-1
D_x = 2.80064e-10 m, Sigma(x) = 5.889708e-05 m
D_y = 5.237339e-10 m, Sigma(y) = 5.923576e-05 m
D_z = -1.195346e-10 m, Sigma(z) = 5.407445e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660389.0952 +/- 5.889708e-05 m del_e = -13.5773 +/- 6.278549e-05 m
y = -3785671.5761 +/- 5.923576e-05 m del_n = -27.1521 +/- 6.425795e-05 m
z = 4373646.5798 +/- 5.407445e-05 m del_u = 14.052 +/- 4.278651e-05 m
Lat. = 43.57993140364415 deg, Long. = -125.09771593358191, Hgt.msl = -1062.604145030256 m
NCB1-2
x = -2660985.9376 +/- 5.889708e-05 m del_e = -13.5773 +/- 6.278549e-05 m
y = -3786511.1945 +/- 5.923576e-05 m del_n = -27.1487 +/- 6.425752e-05 m
z = 4372506.6897 +/- 5.407445e-05 m del_u = 14.0585 +/- 4.278715e-05 m
Lat. = 43.56610511497002 deg, Long. = -125.09778479872921, Hgt.msl = -1101.9867814244292 m
NCB1-1
x = -2661850.3441 +/- 5.889708e-05 m del_e = -13.5685 +/- 6.278639e-05 m
y = -3785282.6674 +/- 5.923576e-05 m del_n = -27.1531 +/- 6.425697e-05 m
z = 4373004.5052 +/- 5.407445e-05 m del_u = 14.0585 +/- 4.278667e-05 m
Lat. = 43.57250354142948 deg, Long. = -125.11528743087243, Hgt.msl = -1126.885309370653 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

Perhaps amazingly, even though the metadata of only one transponder was modified the residuals for each transponder have still been pretty dramatically affected. And once again, the change was the smallest possible increment allowed by the transponders.

If there is a takeaway here, it is that it is critical to keep good notes on these metadata. The TAT is also logged in the raw data files recorded by the Wave Glider, so if for some reason you think a TAT value may be wrong in a configuration file and you don’t have access to a field log with that metadata recorded, it is possible to recover the needed information. However, acessing those raw data files is beyond the scope of this exercise.

Before moving on to the next exercise, be sure to correct the TAT input to their original values, those being 0.08 for NCB1-3, 0.36 for NCB1-2, and 0.64 for NCB1-1. If you are having trouble, refer to the sample text from the configuration file above or the NCB1_2024_reference_config.yaml file.

Trigger Delay

The “trigger delay” refers to a transducer delay time that occurs between the surface platform’s onboard computer sending a command to the transducer to emit an interrogation ping and the ping being emitted. This delay varies by surface platform, for the model SV-3 Wave Gliders used in the Near-trench Community Geodesy Experiment the trigger delay is 0.13 seconds. Although this time difference is minute, it is enough to ruin a GNSS-A inversion if not accounted for.

Since the trigger delay occurs before the interrogation ping is emitted, by convention GNATSS expects it to already be removed from TWTT measurements prior to any processing. If you inspect a configuration file, you will see that there is an entry within the metadata block for the trigger delay:

transducer_delay_time: 0.0 #Default value

If you have already removed the trigger delay from your TWTT measurements and have the proper epochs identified for ping send and receive, then you can leave this value set to 0.0 seconds. (Indeed, this is the standard for the community experiment data currently archived at EarthScope Consortium.) However, some data sets may not have the correct start times logged in the input acoustics data, in which case you can adjust this value. It won’t actually change the TWTT measurement, but rather add the trigger delay to the start time. Note that GNATSS performs a cross check to make sure that TWTT = Reply_Time - (Start_Time + Trigger_Delay), so if you modify this value recklessly GNATSS is liable to return a ValueError when this check fails.

To keep things simple, we recommend doing any adjustments related to the trigger delay before processing data with GNATSS. If you do so, then you can leave the value in the configuration file set to 0.0 and trigger no errors.

However, for the sake of argument let’s investigate what would happen if the trigger delay were not removed from the TWTT measurements. We have provided an altered input data file ../data/exercise-3/output/gps_solution_trigger_delay.csv that is identical to the gps_solution.csv file for the actual data set except that the trigger delay of 0.13s has been added to both the T_receive and TravelTime values. Because both values have been modified, the cross check described in the above paragraph will still pass even though we haven’t actually changed the transducer_delay_time value in the configuration file. This isn’t quite an exact representation of how a real data set may fail but it will give us an idea of how the added delay may alter the solution if it somehow made it past all of the internal GNATSS checks.

To run this example, modify the configuration file ../data/exercise-3/NCB1_2024_config.yaml so that the path to the gps_solution file is:

    gps_solution: #/path/to/gps_solution.csv #Path to pre-processed input data in standard GNSS-A data format, this skips the Posfilter step
      path: ../data/exercise-3/output/gps_solution_trigger_delay.csv

Now we can run the solver.

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution_trigger_delay.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading gps_solution from ../data/exercise-3/output/gps_solution_trigger_delay.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1481.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1481.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 19151.6 cm, error factor = 11094.31
NCB1-3
D_x = 5.232147e+01 m, Sigma(x) = 5.903304e-05 m
D_y = 7.414316e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -8.470863e+01 m, Sigma(z) = 5.480098e-05 m
NCB1-2
D_x = 5.232147e+01 m, Sigma(x) = 5.903304e-05 m
D_y = 7.414316e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -8.470863e+01 m, Sigma(z) = 5.480098e-05 m
NCB1-1
D_x = 5.232147e+01 m, Sigma(x) = 5.903304e-05 m
D_y = 7.414316e+01 m, Sigma(y) = 5.907595e-05 m
D_z = -8.470863e+01 m, Sigma(z) = 5.480098e-05 m

After iteration: 2, rms residual = 457.38 cm, error factor = 264.558
NCB1-3
D_x = -1.125311e+00 m, Sigma(x) = 6.19046e-05 m
D_y = -1.500658e+00 m, Sigma(y) = 6.146690e-05 m
D_z = 1.692603e+00 m, Sigma(z) = 5.676982e-05 m
NCB1-2
D_x = -1.125311e+00 m, Sigma(x) = 6.19046e-05 m
D_y = -1.500658e+00 m, Sigma(y) = 6.146690e-05 m
D_z = 1.692603e+00 m, Sigma(z) = 5.676982e-05 m
NCB1-1
D_x = -1.125311e+00 m, Sigma(x) = 6.19046e-05 m
D_y = -1.500658e+00 m, Sigma(y) = 6.146690e-05 m
D_z = 1.692603e+00 m, Sigma(z) = 5.676982e-05 m

After iteration: 3, rms residual = 213.13 cm, error factor = 122.805
NCB1-3
D_x = -3.493274e-04 m, Sigma(x) = 6.184496e-05 m
D_y = -5.914508e-04 m, Sigma(y) = 6.14159e-05 m
D_z = 6.639472e-04 m, Sigma(z) = 5.672589e-05 m
NCB1-2
D_x = -3.493274e-04 m, Sigma(x) = 6.184496e-05 m
D_y = -5.914508e-04 m, Sigma(y) = 6.14159e-05 m
D_z = 6.639472e-04 m, Sigma(z) = 5.672589e-05 m
NCB1-1
D_x = -3.493274e-04 m, Sigma(x) = 6.184496e-05 m
D_y = -5.914508e-04 m, Sigma(y) = 6.14159e-05 m
D_z = 6.639472e-04 m, Sigma(z) = 5.672589e-05 m

After iteration: 4, rms residual = 213.13 cm, error factor = 122.805
NCB1-3
D_x = -9.475599e-09 m, Sigma(x) = 6.184493e-05 m
D_y = -1.338286e-08 m, Sigma(y) = 6.141588e-05 m
D_z = 1.298815e-09 m, Sigma(z) = 5.672587e-05 m
NCB1-2
D_x = -9.47561e-09 m, Sigma(x) = 6.184493e-05 m
D_y = -1.338287e-08 m, Sigma(y) = 6.141588e-05 m
D_z = 1.298809e-09 m, Sigma(z) = 5.672587e-05 m
NCB1-1
D_x = -9.475599e-09 m, Sigma(x) = 6.184493e-05 m
D_y = -1.338287e-08 m, Sigma(y) = 6.141588e-05 m
D_z = 1.298812e-09 m, Sigma(z) = 5.672587e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660310.1757 +/- 6.184493e-05 m del_e = 0.1202 +/- 6.635700e-05 m
y = -3785583.0978 +/- 6.141588e-05 m del_n = 1.1269 +/- 6.845594e-05 m
z = 4373573.5467 +/- 5.672587e-05 m del_u = -121.6064 +/- 4.153387e-05 m
Lat. = 43.58018597465388 deg, Long. = -125.09754631797203, Hgt.msl = -1198.26262913379 m
NCB1-2
x = -2660907.0181 +/- 6.184493e-05 m del_e = 0.1201 +/- 6.635701e-05 m
y = -3786422.7162 +/- 6.141588e-05 m del_n = 1.0975 +/- 6.845572e-05 m
z = 4372433.6566 +/- 5.672587e-05 m del_u = -121.6067 +/- 4.153423e-05 m
Lat. = 43.56635939356306 deg, Long. = -125.0976152226264, Hgt.msl = -1237.6520976398876 m
NCB1-1
x = -2661771.4247 +/- 6.184493e-05 m del_e = 0.0929 +/- 6.635788e-05 m
y = -3785194.1891 +/- 6.141588e-05 m del_n = 1.1112 +/- 6.845515e-05 m
z = 4372931.4721 +/- 5.672587e-05 m del_u = -121.6066 +/- 4.153377e-05 m
Lat. = 43.57275798304824 deg, Long. = -125.11511828160623, Hgt.msl = -1262.5504978773197 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

Before moving on, make sure to revise the configuration file so that the path to the gps_solution points to the unaltered input data file ../data/exercise-3/output/gps_solution.csv.

Sound Velocity Profile

In order to generate an accurate GNSS-A position, it is imperitive that the sound velocity profile at the array is well-constrained. Currently, GNATSS is configured to accept a single sound velocity profile that is usually constrained by a CTD profile. During the inversion, the solver calculates the harmonic mean sound velocity above each transponder in the array using this profile, which is used to model the TWTT using a straight-ray approximation.

In general, the sound velocity structure of the water column is more complicated than this simplified approach, but as long as this structure approximates a horizontally layered medium the horizontal position generated by the inversion should be fairly stable.

However, it is still important to have as accurate sound velocity information as possible. To demonstrate this, we have provided a series of “dummy” sound velocity profiles that have been modified by increasing the sound velocity value by 5 m/s at specific depths. This is probably larger than the variation that may be observed in real data, but should highlight the dependence of the inversion on accurate sound velocity information.

In order to run these examples, modify the configuration file ../data/exercise-3/NCB1_2024_config.yaml so that the sound_speed path in the solver points to the modified sound velocity profile. We will examine three examples in which the sound velocity is modified throughout the entire profile, at shallow depths, and near the seafloor, respectively.

Full Profile

The first example we will examine is one in which the entire sound velocity profile is systematically increased by 5 m/s at all water depths. This profile is stored at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_fast. In order to run this example, edit the configuration file so that the sound_speed path points to this file as below:

    sound_speed: #Assume 2-column text file with depth (m), sound velocity (m/s)
      path: ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_fast
output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_fast
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_fast
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1486.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1486.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1486.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 862.83 cm, error factor = 498.711
NCB1-3
D_x = 2.360645e+00 m, Sigma(x) = 5.919331e-05 m
D_y = 3.210668e+00 m, Sigma(y) = 5.923658e-05 m
D_z = -3.910696e+00 m, Sigma(z) = 5.494522e-05 m
NCB1-2
D_x = 2.360645e+00 m, Sigma(x) = 5.919331e-05 m
D_y = 3.210668e+00 m, Sigma(y) = 5.923658e-05 m
D_z = -3.910696e+00 m, Sigma(z) = 5.494522e-05 m
NCB1-1
D_x = 2.360645e+00 m, Sigma(x) = 5.919331e-05 m
D_y = 3.210668e+00 m, Sigma(y) = 5.923658e-05 m
D_z = -3.910696e+00 m, Sigma(z) = 5.494522e-05 m

After iteration: 2, rms residual = 47.69 cm, error factor = 27.522
NCB1-3
D_x = -2.523445e-03 m, Sigma(x) = 5.931659e-05 m
D_y = -3.718532e-03 m, Sigma(y) = 5.934238e-05 m
D_z = 3.476458e-03 m, Sigma(z) = 5.502568e-05 m
NCB1-2
D_x = -2.523445e-03 m, Sigma(x) = 5.931659e-05 m
D_y = -3.718532e-03 m, Sigma(y) = 5.934238e-05 m
D_z = 3.476458e-03 m, Sigma(z) = 5.502568e-05 m
NCB1-1
D_x = -2.523445e-03 m, Sigma(x) = 5.931659e-05 m
D_y = -3.718532e-03 m, Sigma(y) = 5.934238e-05 m
D_z = 3.476458e-03 m, Sigma(z) = 5.502568e-05 m

After iteration: 3, rms residual = 47.68 cm, error factor = 27.518
NCB1-3
D_x = 1.835261e-08 m, Sigma(x) = 5.931646e-05 m
D_y = -9.959314e-09 m, Sigma(y) = 5.934229e-05 m
D_z = 1.202605e-08 m, Sigma(z) = 5.502559e-05 m
NCB1-2
D_x = 1.835261e-08 m, Sigma(x) = 5.931646e-05 m
D_y = -9.959312e-09 m, Sigma(y) = 5.934229e-05 m
D_z = 1.202605e-08 m, Sigma(z) = 5.502559e-05 m
NCB1-1
D_x = 1.835261e-08 m, Sigma(x) = 5.931646e-05 m
D_y = -9.959312e-09 m, Sigma(y) = 5.934229e-05 m
D_z = 1.202605e-08 m, Sigma(z) = 5.502559e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660359.0134 +/- 5.931646e-05 m del_e = 0.0855 +/- 6.327193e-05 m
y = -3785652.5328 +/- 5.934229e-05 m del_n = -0.087 +/- 6.515395e-05 m
z = 4373652.6548 +/- 5.502559e-05 m del_u = -5.5764 +/- 4.265430e-05 m
Lat. = 43.580175047235905 deg, Long. = -125.09754674781672, Hgt.msl = -1082.232647101114 m
NCB1-2
x = -2660955.8558 +/- 5.931646e-05 m del_e = 0.0854 +/- 6.327194e-05 m
y = -3786492.1512 +/- 5.934229e-05 m del_n = -0.0883 +/- 6.515371e-05 m
z = 4372512.7648 +/- 5.502559e-05 m del_u = -5.5764 +/- 4.265467e-05 m
Lat. = 43.56634871811571 deg, Long. = -125.09761565111151, Hgt.msl = -1121.6218260315313 m
NCB1-1
x = -2661820.2624 +/- 5.931646e-05 m del_e = 0.0842 +/- 6.327278e-05 m
y = -3785263.6241 +/- 5.934229e-05 m del_n = -0.0877 +/- 6.515318e-05 m
z = 4373010.5803 +/- 5.502559e-05 m del_u = -5.5765 +/- 4.265421e-05 m
Lat. = 43.57274719088041 deg, Long. = -125.11511838904805, Hgt.msl = -1146.5203546330015 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

This result is quite a bit more interesting than the results with modified delay times because much of the structure in the residuals present in the reference solution is still present despite the erroneous CTD. The primary difference is that the residuals are “fuzzier” due to a higher noise level.

We will reiterate that this is a somewhat extreme case, but do not be decieved into thinking this solution is accurate despite the identifiable structure in the residuals closely resembling the reference solution. If you were to inspect the array offsets of the reference solution and this run with the modified CTD profile you would find a difference in the final position that is >10 cm.

Upper Water Column

This example will process the data with a sound velocity profile modified that has increased velocities in the upper 300 m of the water column. Like the “Full Profile” example, velocities have been increased by 5 m/s. This is meant to simulate an extreme case of changing sound velocities in the shallow water above the thermocline, where we might nominally expect much of the oceanographic variation to occur.

This path to this profile is ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_upper. Modify the configuration file so that the sound_speed path points to this file, and then run the solver.

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_upper
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_upper
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1483.049 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1483.014 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1482.994 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 155.26 cm, error factor = 90.024
NCB1-3
D_x = 6.22742e-01 m, Sigma(x) = 5.907698e-05 m
D_y = 3.863308e-01 m, Sigma(y) = 5.911836e-05 m
D_z = -6.697425e-01 m, Sigma(z) = 5.483801e-05 m
NCB1-2
D_x = 6.22742e-01 m, Sigma(x) = 5.907698e-05 m
D_y = 3.863308e-01 m, Sigma(y) = 5.911836e-05 m
D_z = -6.697425e-01 m, Sigma(z) = 5.483801e-05 m
NCB1-1
D_x = 6.22742e-01 m, Sigma(x) = 5.907698e-05 m
D_y = 3.863308e-01 m, Sigma(y) = 5.911836e-05 m
D_z = -6.697425e-01 m, Sigma(z) = 5.483801e-05 m

After iteration: 2, rms residual = 42.43 cm, error factor = 24.56
NCB1-3
D_x = 2.732251e-05 m, Sigma(x) = 5.909342e-05 m
D_y = -1.973417e-04 m, Sigma(y) = 5.913971e-05 m
D_z = 1.170632e-04 m, Sigma(z) = 5.485327e-05 m
NCB1-2
D_x = 2.732251e-05 m, Sigma(x) = 5.909342e-05 m
D_y = -1.973417e-04 m, Sigma(y) = 5.913971e-05 m
D_z = 1.170632e-04 m, Sigma(z) = 5.485327e-05 m
NCB1-1
D_x = 2.732251e-05 m, Sigma(x) = 5.909342e-05 m
D_y = -1.973417e-04 m, Sigma(y) = 5.913971e-05 m
D_z = 1.170632e-04 m, Sigma(z) = 5.485327e-05 m

After iteration: 3, rms residual = 42.43 cm, error factor = 24.56
NCB1-3
D_x = -5.336772e-09 m, Sigma(x) = 5.909341e-05 m
D_y = 1.543366e-09 m, Sigma(y) = 5.913971e-05 m
D_z = -3.519034e-10 m, Sigma(z) = 5.485327e-05 m
NCB1-2
D_x = -5.336772e-09 m, Sigma(x) = 5.909341e-05 m
D_y = 1.543365e-09 m, Sigma(y) = 5.913971e-05 m
D_z = -3.519021e-10 m, Sigma(z) = 5.485327e-05 m
NCB1-1
D_x = -5.336772e-09 m, Sigma(x) = 5.909341e-05 m
D_y = 1.543365e-09 m, Sigma(y) = 5.913971e-05 m
D_z = -3.519021e-10 m, Sigma(z) = 5.485327e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660360.7488 +/- 5.909341e-05 m del_e = 0.2875 +/- 6.301432e-05 m
y = -3785655.3536 +/- 5.913971e-05 m del_n = -0.0205 +/- 6.488567e-05 m
z = 4373655.8924 +/- 5.485327e-05 m del_u = -0.9499 +/- 4.263171e-05 m
Lat. = 43.5801756459044 deg, Long. = -125.09754424564389, Hgt.msl = -1077.6060703689702 m
NCB1-2
x = -2660957.5912 +/- 5.909341e-05 m del_e = 0.2875 +/- 6.301432e-05 m
y = -3786494.972 +/- 5.913971e-05 m del_n = -0.0207 +/- 6.488543e-05 m
z = 4372516.0024 +/- 5.485327e-05 m del_u = -0.9499 +/- 4.263207e-05 m
Lat. = 43.56634932684149 deg, Long. = -125.09761314944643, Hgt.msl = -1116.9952656578082 m
NCB1-1
x = -2661821.9977 +/- 5.909341e-05 m del_e = 0.2873 +/- 6.301516e-05 m
y = -3785266.4449 +/- 5.913971e-05 m del_n = -0.0205 +/- 6.488491e-05 m
z = 4373013.8179 +/- 5.485327e-05 m del_u = -0.9499 +/- 4.263162e-05 m
Lat. = 43.57274779534068 deg, Long. = -125.11511587460518, Hgt.msl = -1141.8938315713335 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

Overall, the differences between this solution and the reference solution are much more subtle compared to the example where the entire water column was modified. This is probably to be expected since the sound velocity change is much more localized in this example. However, the final solution has still been shifted a few cm compared to the reference solution.

Lower Water Column

This final example features a profile where sound velocities were increased by 5 m/s if they were deeper than 1100m depth. The path to this profile is ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_lower. Update the sound_speed path in the configuration file to point to this profile and re-run the solver.

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_lower
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi_lower
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58017583 lon=-125.097547806 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.44 elevation=39.67
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1481.771 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1481.887 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 103.66 cm, error factor = 59.891
NCB1-3
D_x = -1.832477e-01 m, Sigma(x) = 5.903276e-05 m
D_y = -5.088456e-01 m, Sigma(y) = 5.907799e-05 m
D_z = 3.324073e-01 m, Sigma(z) = 5.480697e-05 m
NCB1-2
D_x = -1.832477e-01 m, Sigma(x) = 5.903276e-05 m
D_y = -5.088456e-01 m, Sigma(y) = 5.907799e-05 m
D_z = 3.324073e-01 m, Sigma(z) = 5.480697e-05 m
NCB1-1
D_x = -1.832477e-01 m, Sigma(x) = 5.903276e-05 m
D_y = -5.088456e-01 m, Sigma(y) = 5.907799e-05 m
D_z = 3.324073e-01 m, Sigma(z) = 5.480697e-05 m

After iteration: 2, rms residual = 42.06 cm, error factor = 24.364
NCB1-3
D_x = -1.666862e-05 m, Sigma(x) = 5.901675e-05 m
D_y = -2.475687e-05 m, Sigma(y) = 5.907111e-05 m
D_z = 7.571714e-05 m, Sigma(z) = 5.479711e-05 m
NCB1-2
D_x = -1.666862e-05 m, Sigma(x) = 5.901675e-05 m
D_y = -2.475687e-05 m, Sigma(y) = 5.907111e-05 m
D_z = 7.571714e-05 m, Sigma(z) = 5.479711e-05 m
NCB1-1
D_x = -1.666862e-05 m, Sigma(x) = 5.901675e-05 m
D_y = -2.475687e-05 m, Sigma(y) = 5.907111e-05 m
D_z = 7.571714e-05 m, Sigma(z) = 5.479711e-05 m

After iteration: 3, rms residual = 42.06 cm, error factor = 24.364
NCB1-3
D_x = 4.289964e-09 m, Sigma(x) = 5.901675e-05 m
D_y = -2.788679e-09 m, Sigma(y) = 5.907110e-05 m
D_z = -3.997226e-09 m, Sigma(z) = 5.479711e-05 m
NCB1-2
D_x = 4.289964e-09 m, Sigma(x) = 5.901675e-05 m
D_y = -2.78868e-09 m, Sigma(y) = 5.907110e-05 m
D_z = -3.997227e-09 m, Sigma(z) = 5.479711e-05 m
NCB1-1
D_x = 4.289965e-09 m, Sigma(x) = 5.901675e-05 m
D_y = -2.788680e-09 m, Sigma(y) = 5.907110e-05 m
D_z = -3.997227e-09 m, Sigma(z) = 5.479711e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660361.5548 +/- 5.901675e-05 m del_e = 0.1426 +/- 6.292609e-05 m
y = -3785656.2486 +/- 5.907110e-05 m del_n = -0.1188 +/- 6.479579e-05 m
z = 4373656.8945 +/- 5.479711e-05 m del_u = 0.6071 +/- 4.262519e-05 m
Lat. = 43.58017476053919 deg, Long. = -125.0975460396448, Hgt.msl = -1076.0490598774334 m
NCB1-2
x = -2660958.3972 +/- 5.901675e-05 m del_e = 0.1426 +/- 6.29261e-05 m
y = -3786495.867 +/- 5.907110e-05 m del_n = -0.1187 +/- 6.479555e-05 m
z = 4372517.0045 +/- 5.479711e-05 m del_u = 0.6072 +/- 4.262555e-05 m
Lat. = 43.56634844484999 deg, Long. = -125.0976149430302, Hgt.msl = -1115.438231350444 m
NCB1-1
x = -2661822.8037 +/- 5.901675e-05 m del_e = 0.1428 +/- 6.292694e-05 m
y = -3785267.3399 +/- 5.907110e-05 m del_n = -0.1187 +/- 6.479503e-05 m
z = 4373014.82 +/- 5.479711e-05 m del_u = 0.6071 +/- 4.26251e-05 m
Lat. = 43.57274691150716 deg, Long. = -125.11511766386315, Hgt.msl = -1140.3367761927166 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

If you were to only look at the residual plots, you may be tricked into thinking that this solution is similar to the reference solution. However, the transponder offsets are much different, even more so than was the case when the entire profile was modified. This is despite the fact that the segment of the profile that was modified spans <100m, far less than in either of the previous examples!

In a way we have cheated when creating this profile because the 1100m depth was chosen as a transition point specifically because one of the transponders in this array rests at a shallower depth and therefore would not see the effect of the altered sound velocity. This represents a “worst-case scenario” for the fixed-point GNSS-A processing that GNATSS performs whereby a deep body of water passes over one/some of the transponders and breaks the symmetry of the system we rely upon for the inversion.

Sound Velocity Summary

In the previous example we have seen that changing the sound velocity profile can lead to significant biases in the final GNSS-A solution even when there is not a noticeable change in the residuals. To make this point a little more obvious, we have summarized the transponder offsets obtained using the various sound velocity profiles in the table below.

East Offset (cm)North Offset (cm)
Reference Solution28.99-5.33
Full Column8.55-8.7
Upper Column28.75-2.05
Lower Column14.26-11.87

Note that this is likely site specific, but the main takeaway is that which part of the profile is changing is much more important than the change itself. GNATSS is particularly sensitive to changes in the lower water column. This segment of the water column is assumed to be fairly stable in most cases, but if that assumption were to break down it could lead to biased position estimate with no indication of anything wrong.

Before moving on, revise the configuration file so that the sound_speed path points to the correct sound velocity profile at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi.

Transponder Locations

The final metadata we shall examine in the exercise are the a priori transponder locations. We have prepared a configuration file for this purpose, ../data/exercise-3/NCB1_2024_shifted_transponder_config.yaml, which only differs from the reference configuration file by a small difference: the a priori location of the NCB1-3 transponder has been shifted north by 10m.

To see how this one small change has affected the final solution, run GNATSS as before but calling upon this altered configuration file.

# Set input variables

config_yaml = "../data/exercise-3/NCB1_2024_shifted_transponder_config.yaml"
skip_posfilter = True

# Run GNATSS solver

output = run_gnatss(
    config_yaml,
    skip_posfilter=skip_posfilter
)
Starting GNATSS ...
Gathering gps_solution at ../data/exercise-3/output/gps_solution.csv
Gathering sound_speed at ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading gps_solution from ../data/exercise-3/output/gps_solution.csv
Loading sound_speed from ../data/exercise-3/ctd/CTD_NCB1_Ch_Mi
Loading deletions from ../data/exercise-3/output/
Filtering out data outside of distance limit...
Pre-filtering data with fewer than 3 replies...
Computing harmonic mean...
lat=43.58026585 lon=-125.097547797 height=-1076.6562 alt=-1076.6562 internal_delay=0.08 sv_mean=1481.682 pxp_id='NCB1-3' azimuth=57.78 elevation=39.94
lat=43.566349513 lon=-125.097616709 height=-1116.0454 alt=-1116.0454 internal_delay=0.36 sv_mean=1481.695 pxp_id='NCB1-2' azimuth=-58.75 elevation=39.38
lat=43.57274798 lon=-125.115119432 height=-1140.9439 alt=-1140.9439 internal_delay=0.64 sv_mean=1481.704 pxp_id='NCB1-1' azimuth=-175.59 elevation=39.52
Finished computing harmonic mean
Preparing data inputs...
Perform solve...
--- 27243 epochs, 81729 measurements ---
After iteration: 1, rms residual = 696.04 cm, error factor = 402.966
NCB1-3
D_x = -5.185817e+00 m, Sigma(x) = 5.901051e-05 m
D_y = -3.401201e+00 m, Sigma(y) = 5.898141e-05 m
D_z = -1.551894e+00 m, Sigma(z) = 5.470355e-05 m
NCB1-2
D_x = -5.185817e+00 m, Sigma(x) = 5.901051e-05 m
D_y = -3.401201e+00 m, Sigma(y) = 5.898141e-05 m
D_z = -1.551894e+00 m, Sigma(z) = 5.470355e-05 m
NCB1-1
D_x = -5.185817e+00 m, Sigma(x) = 5.901051e-05 m
D_y = -3.401201e+00 m, Sigma(y) = 5.898141e-05 m
D_z = -1.551894e+00 m, Sigma(z) = 5.470355e-05 m

After iteration: 2, rms residual = 48.55 cm, error factor = 28.145
NCB1-3
D_x = 3.296731e-03 m, Sigma(x) = 5.897015e-05 m
D_y = -4.325129e-03 m, Sigma(y) = 5.900385e-05 m
D_z = 1.681691e-02 m, Sigma(z) = 5.456001e-05 m
NCB1-2
D_x = 3.296731e-03 m, Sigma(x) = 5.897015e-05 m
D_y = -4.325129e-03 m, Sigma(y) = 5.900385e-05 m
D_z = 1.681691e-02 m, Sigma(z) = 5.456001e-05 m
NCB1-1
D_x = 3.296731e-03 m, Sigma(x) = 5.897015e-05 m
D_y = -4.325129e-03 m, Sigma(y) = 5.900385e-05 m
D_z = 1.681691e-02 m, Sigma(z) = 5.456001e-05 m

After iteration: 3, rms residual = 48.49 cm, error factor = 28.109
NCB1-3
D_x = 6.236563e-08 m, Sigma(x) = 5.896981e-05 m
D_y = -9.056355e-08 m, Sigma(y) = 5.900345e-05 m
D_z = -2.149295e-08 m, Sigma(z) = 5.456004e-05 m
NCB1-2
D_x = 6.236563e-08 m, Sigma(x) = 5.896981e-05 m
D_y = -9.056355e-08 m, Sigma(y) = 5.900345e-05 m
D_z = -2.149295e-08 m, Sigma(z) = 5.456004e-05 m
NCB1-1
D_x = 6.236563e-08 m, Sigma(x) = 5.896981e-05 m
D_y = -9.056355e-08 m, Sigma(y) = 5.900345e-05 m
D_z = -2.149295e-08 m, Sigma(z) = 5.456004e-05 m

---- FINAL SOLUTION ----
NCB1-3
x = -2660362.5899 +/- 5.896981e-05 m del_e = -2.2821 +/- 6.293466e-05 m
y = -3785653.5055 +/- 5.900345e-05 m del_n = -5.087 +/- 6.444323e-05 m
z = 4373662.2709 +/- 5.456004e-05 m del_u = 3.1188 +/- 4.268421e-05 m
Lat. = 43.58022005609397 deg, Long. = -125.09757605670698, Hgt.msl = -1073.5374106952875 m
NCB1-2
x = -2660963.3965 +/- 5.896981e-05 m del_e = -2.2821 +/- 6.293467e-05 m
y = -3786498.7637 +/- 5.900345e-05 m del_n = -5.0863 +/- 6.444297e-05 m
z = 4372515.1369 +/- 5.456004e-05 m del_u = 3.12 +/- 4.26846e-05 m
Lat. = 43.566303725502216 deg, Long. = -125.09764496228885, Hgt.msl = -1112.9253732369477 m
NCB1-1
x = -2661827.803 +/- 5.896981e-05 m del_e = -2.2804 +/- 6.293552e-05 m
y = -3785270.2365 +/- 5.900345e-05 m del_n = -5.0871 +/- 6.444242e-05 m
z = 4373012.9524 +/- 5.456004e-05 m del_u = 3.12 +/- 4.268417e-05 m
Lat. = 43.5727021849141 deg, Long. = -125.11514766657928, Hgt.msl = -1137.8239363746823 m
------------------------

There are 0 outliers found during this run.

Exporting residuals to residuals.csv ...
Successfully exported data to ../data/exercise-3/output/residuals.csv
Exporting outliers to outliers.csv ...
No data found for outliers, skipping export!
Exporting distance_from_center to dist_center.csv ...
Successfully exported data to ../data/exercise-3/output/dist_center.csv
Exporting process_dataset to process_dataset.nc ...
Successfully exported data to ../data/exercise-3/output/process_dataset.nc
Successfully exported data to ../data/exercise-3/output/residuals.png
Successfully exported data to ../data/exercise-3/output/residuals_enu_components.png
Finished GNATSS.
<Figure size 1000x500 with 1 Axes><Figure size 1000x500 with 3 Axes>

We can see that the residuals have been somewhat affected, and the transponder offsets are meters from the a priori locations.

However, note how the offset is not 10m to the north! This is because GNATSS assumes a rigid array geometry and constrains each transponder to have the same offset. In this example, only one transponder’s a priori location was shifted and thus that was distributed to the other transponders as well.

The important thing to note here is that the error we introduced into the a priori location is small. The transponders can drift many tens of meters laterally from their drop points as they sink through the water column, so if you naively try to compute a GNSS-A position using the drop points as a priori you are liable to see much larger errors than occurred in this example. Because of this, it is incredibly important to triangulate the transponder locations as best as you can before running a GNSS-A survey so that you can approximate where the transponders actually are. Normally this is accomplished by directing the surface platform to conduct a “circle drive” around each transponder. This allows you to constrain the transponder location to the accuracy of a few decimeters, easily sufficient for GNSS-A positioning. From these triangulated transponder positions, you can compute the array center, defined not as the geometric array center but rather the point on the sea surface from which the TWTT to each transponder is equivalent.

Unfortunately, the full process for computing a priori transponder positions is beyond the scope of this exercise.