Skip to content

Commit b001230

Browse files
committed
DOP notebook completed
1 parent 845f65f commit b001230

5 files changed

Lines changed: 141 additions & 26 deletions

File tree

docs/source/tutorials/tutorials.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ available in the :code:`utils` directory.
6969

7070
utils/tutorials_constants_notebook
7171
utils/tutorials_coordinates_notebook
72+
utils/tutorials_dop_notebook
7273
utils/tutorials_ephemeris_downloader_notebook
7374
utils/tutorials_file_operations_notebook
7475
utils/tutorials_filters_notebook
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"path": "../../../../notebooks/tutorials/utils/dop.ipynb"
3+
}

gnss_lib_py/utils/dop.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Metrics to quantify quality of state estimates or GNSS measurements.
1+
"""
2+
Dillution of Precision (DOP) calculations and interface with NavData.
23
"""
34

45
__authors__ = "Ashwin Kanhere, Daniel Neamati"

notebooks/tutorials/utils/dop.ipynb

Lines changed: 134 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,26 @@
99
"Dillution of Precision (DOP) describes the effect of satellite geometry on the \n",
1010
"user's positioning accuracy. \n",
1111
"DOP can refer to multiple ideas:\n",
12-
"1. The full DOP matrix (or tensor),\n",
13-
"2. DOP in the horizontal or vertical direction,\n",
14-
"3. DOP on the time uncertainty, or\n",
12+
"1. DOP in the horizontal or vertical direction,\n",
13+
"2. DOP on the time uncertainty,\n",
14+
"3. The full DOP matrix, or\n",
1515
"4. DOP in a particular direction.\n",
1616
"\n",
17-
"Here we show how to make use of existing functionality."
17+
"Here we show how to make use of existing functionality. \n",
18+
"For more details on the underlying math, please see the [Navipedia page on \n",
19+
"positioning error](https://gssc.esa.int/navipedia/index.php?title=Positioning_Error)."
1820
]
1921
},
2022
{
2123
"cell_type": "code",
22-
"execution_count": 1,
24+
"execution_count": null,
2325
"metadata": {},
2426
"outputs": [],
2527
"source": [
2628
"import gnss_lib_py as glp\n",
29+
"import numpy as np\n",
2730
"\n",
31+
"# A library for url downloads that works regardless of `wget` command\n",
2832
"import urllib.request"
2933
]
3034
},
@@ -38,13 +42,13 @@
3842
},
3943
{
4044
"cell_type": "code",
41-
"execution_count": 2,
45+
"execution_count": null,
4246
"metadata": {},
4347
"outputs": [],
4448
"source": [
4549
"glp.make_dir(\"../data\")\n",
46-
"# %wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2022/device_gnss.csv --quiet -nc -O \"../data/device_gnss.csv\"\n",
4750
"\n",
51+
"# %wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2022/device_gnss.csv --quiet -nc -O \"../data/device_gnss.csv\"\n",
4852
"urllib.request.urlretrieve(\"https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/google_decimeter_2022/device_gnss.csv\", \"../data/device_gnss.csv\")\n",
4953
"\n",
5054
"navdata = glp.AndroidDerived2022(\"../data/device_gnss.csv\")"
@@ -55,32 +59,138 @@
5559
"metadata": {},
5660
"source": [
5761
"Since we already have elevation and azimuth data available to us, we can simply\n",
58-
"call the `get_dop` function."
62+
"call the `get_dop` function, which will only return the HDOP and VDOP values,\n",
63+
"by default.\n",
64+
"HDOP corresponds to the dilution of precision in the horizontal direction\n",
65+
"(i.e., East and North plane), and VDOP corresponds to the dilution of precision\n",
66+
"in the vertical direction (i.e., the Up axis)."
5967
]
6068
},
6169
{
6270
"cell_type": "code",
63-
"execution_count": 3,
71+
"execution_count": null,
6472
"metadata": {},
65-
"outputs": [
66-
{
67-
"name": "stdout",
68-
"output_type": "stream",
69-
"text": [
70-
" gps_millis HDOP VDOP\n",
71-
"0 1.303771e+12 0.558578 0.830517\n",
72-
"1 1.303771e+12 0.549160 0.829362\n",
73-
"2 1.303771e+12 0.558593 0.830452\n",
74-
"3 1.303771e+12 0.549176 0.829296\n",
75-
"4 1.303771e+12 0.549185 0.829263\n",
76-
"5 1.303771e+12 0.549193 0.829230\n"
77-
]
78-
}
79-
],
73+
"outputs": [],
8074
"source": [
8175
"dop_navdata = glp.get_dop(navdata)\n",
8276
"print(dop_navdata)"
8377
]
78+
},
79+
{
80+
"cell_type": "markdown",
81+
"metadata": {},
82+
"source": [
83+
"Some applications may care about the dilution of precision in time (TDOP), but\n",
84+
"may not be interested in the dilution of precision in position. \n",
85+
"Simply pass this information to the parser."
86+
]
87+
},
88+
{
89+
"cell_type": "code",
90+
"execution_count": null,
91+
"metadata": {},
92+
"outputs": [],
93+
"source": [
94+
"dop_navdata = glp.get_dop(navdata, HDOP=False, VDOP=False, TDOP=True)\n",
95+
"print(dop_navdata)"
96+
]
97+
},
98+
{
99+
"cell_type": "markdown",
100+
"metadata": {},
101+
"source": [
102+
"Below we illustrate all supported DOP types. The full DOP matrix (in ENU) is \n",
103+
"\n",
104+
"$$Q = \n",
105+
"\\begin{bmatrix}\n",
106+
" q_{ee} & q_{en} & q_{eu} & q_{et} \\\\\n",
107+
" q_{ne} & q_{nn} & q_{nu} & q_{nt} \\\\\n",
108+
" q_{ue} & q_{un} & q_{uu} & q_{ut} \\\\\n",
109+
" q_{te} & q_{tn} & q_{tu} & q_{tt} \\\\\n",
110+
"\\end{bmatrix}$$\n",
111+
"\n",
112+
"The matrix is symmetric (i.e., $q_{en} = q_{ne}$). \n",
113+
"Often the elements along the diagonal are of primary interest\n",
114+
"$$Q = \n",
115+
"\\begin{bmatrix} \n",
116+
" \\text{EDOP}^2 & \\cdot & \\cdot & \\cdot \\\\\n",
117+
" \\cdot & \\text{NDOP}^2 & \\cdot & \\cdot \\\\\n",
118+
" \\cdot & \\cdot & \\text{VDOP}^2 & \\cdot \\\\\n",
119+
" \\cdot & \\cdot & \\cdot & \\text{TDOP}^2\n",
120+
"\\end{bmatrix}$$\n",
121+
"\n",
122+
"\n",
123+
"To store the dop matrix $Q$ in `dop_navdata`, the upper triangle is\n",
124+
"splatted across columns to enable fast storage and access in the navdata using\n",
125+
"numpy."
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": null,
131+
"metadata": {},
132+
"outputs": [],
133+
"source": [
134+
"dop_navdata = glp.get_dop(navdata, GDOP= True, HDOP=True, VDOP=True, \n",
135+
" PDOP=True, TDOP=True, dop_matrix=True)\n",
136+
"print(dop_navdata)"
137+
]
138+
},
139+
{
140+
"cell_type": "markdown",
141+
"metadata": {},
142+
"source": [
143+
"We can recover the unsplatted versions of the DOP matrix as needed if we \n",
144+
"loop through time."
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": null,
150+
"metadata": {},
151+
"outputs": [],
152+
"source": [
153+
"for timestamp, _, dop_navdata_subset in glp.loop_time(dop_navdata, 'gps_millis'):\n",
154+
"\n",
155+
" labels = glp.get_enu_dop_labels()\n",
156+
"\n",
157+
" dop_matrix_splat = np.array(\n",
158+
" [dop_navdata_subset[f'dop_{label}'] for label in labels])\n",
159+
"\n",
160+
" print(f\"At time {timestamp} the DOP matrix is\")\n",
161+
" print(glp.unsplat_dop_matrix(dop_matrix_splat))"
162+
]
163+
},
164+
{
165+
"cell_type": "markdown",
166+
"metadata": {},
167+
"source": [
168+
"Lastly, we can compute the contribution in a particular direction with numpy."
169+
]
170+
},
171+
{
172+
"cell_type": "code",
173+
"execution_count": null,
174+
"metadata": {},
175+
"outputs": [],
176+
"source": [
177+
"direction_of_interest = np.array([-1, 1, 0, 0])\n",
178+
"# Normalize the direction of interest\n",
179+
"direction_of_interest = direction_of_interest / np.linalg.norm(direction_of_interest)\n",
180+
"\n",
181+
"for timestamp, _, dop_navdata_subset in glp.loop_time(dop_navdata, 'gps_millis'):\n",
182+
"\n",
183+
" labels = glp.get_enu_dop_labels()\n",
184+
"\n",
185+
" dop_matrix_splat = np.array(\n",
186+
" [dop_navdata_subset[f'dop_{label}'] for label in labels])\n",
187+
" dop_matrix_unsplat = glp.unsplat_dop_matrix(dop_matrix_splat)\n",
188+
"\n",
189+
" dop_in_direction = np.sqrt(\n",
190+
" direction_of_interest @ dop_matrix_unsplat @ direction_of_interest)\n",
191+
"\n",
192+
" print(f\"At time {timestamp} the DOP in the direction of interest is {dop_in_direction}\")"
193+
]
84194
}
85195
],
86196
"metadata": {

tests/utils/test_dop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Test for metrics, such as DOP calculations.
2+
Test for DOP calculations and manipulations.
33
44
"""
55

0 commit comments

Comments
 (0)