Skip to content

Commit eb2fc9c

Browse files
updated documentation
1 parent 2500804 commit eb2fc9c

11 files changed

+194
-90
lines changed

docs/pages/quick_recall.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ those discussion links will likely go away in the not very distant future.
5656
* [gpsweek](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.gpsweek.html)
5757
* [installexe](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.installexe.html)
5858
* [llh2xyz](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.llh2xyz.html)
59-
* [max_resolve_RH](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.max_resolve_cl.html)
59+
* [max_resolve_RH](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.max_resolve_RH_cl.html)
6060
* [mjd](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.mjd.html)
6161
* [query_unr](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.query_unr.html)
6262
* [quickplt](https://gnssrefl.readthedocs.io/en/latest/api/gnssrefl.quickplt.html)

docs/pages/understand.md

+13-20
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
11
# Understanding
22

3-
4-
## Overview
5-
63
**gnssrefl** is an open source/python version of my GNSS interferometric reflectometry (GNSS-IR) code.
74

8-
*If you would like to try out reflectometry without installing the code*
9-
10-
I recommend you use [the GNSS-IR web app](https://gnss-reflections.org/api). It
11-
can show you representative results in less than 10 seconds. There are also some
12-
[examples](https://gnss-reflections.org/overview).
13-
145
## Goals
156

167
The goal of the gnssrefl python repository is to help you compute (and evaluate) GNSS-based
17-
reflectometry parameters using geodetic data. This method is often
18-
called GNSS-IR, or GNSS Interferometric Reflectometry. There are three main modules:
8+
reflectometry parameters using standard GNSS data. This method is often
9+
called GNSS-IR, or GNSS Interferometric Reflectometry. There are three main sections:
1910

20-
* [**rinex2snr**](rinex2snr.md) translates RINEX files into SNR files needed for analysis.
11+
* Translation: Use either [**rinex2snr**] or [**nmea2snr**] to translate native
12+
GNSS formats to what gnssrefl needs. The output is called a *SNR* file.
2113

22-
* [**quickLook**](quickLook.md) gives you a quick (visual) assessment of SNR file without dealing
14+
* [**quickLook**] gives you a quick (visual) assessment of a SNR file without dealing
2315
with the details associated with **gnssir**. It is not meant to be used for routine analysis.
2416
It also helps you pick an appropriate azimuth mask and quality control settings.
2517

26-
* [**gnssir**](gnssir.md) computes reflector heights (RH) from SNR files.
18+
* [**gnssir**] computes reflector heights (RH) from SNR files.
2719

2820
There are also various [utilities](quick_recall.md) you might find to be useful.
2921
If you are unsure about why various restrictions are being applied, it is really useful
@@ -104,8 +96,8 @@ are not violating the Nyquist frequency (**Maximum Resolvable Reflector Height**
10496

10597
## Quality Control
10698

107-
This code uses a Lomb Scargle periodogram. This type of periodogram allows the input
108-
data to be sampled at uneven periods. The primary inputs are
99+
This code uses a Lomb Scargle periodogram (LSP). This type of periodogram allows the input
100+
data to be sampled at uneven periods. The primary inputs are :
109101

110102
* how precise (in reflector height units) do you want the periodogram calculated at?
111103

@@ -117,11 +109,9 @@ makes no sense (i.e. so small the code takes forever to run). In this code the s
117109
parameter is the max reflector height (h2). The minimum reflector height is always zero, and then
118110
the values lower than the minimum reflector height (h1) are thrown out.
119111

120-
121112
It is easy to compute a periodogram and pick the maximum value so as to find the reflector height. It is
122113
more difficult to determine whether it is one you should trust.
123114

124-
125115
* is the peak larger than a user-defined value (amplitude of the dominant peak in your periodogram)
126116

127117
* is the peak divided by a "noise" metric larger than a user-defined value. This noise metric is defined
@@ -252,8 +242,8 @@ D. Reflection zones for GPS satellites at
252242
elevation angles of 5-15 degrees for a reflector height of 4 meters.
253243

254244
Again using the reflection zone web app, we can plot up the appropriate reflection zones for various options.
255-
Since <code>ross</code> has been around a long time, [http://gnss-reflections.org](https://gnss-reflections.org) has its coordinates in a
256-
database. You can just plug in <code>ross</code> for the station name and leave
245+
Since <code>ross</code> has been around a long time, [http://gnss-reflections.org](https://gnss-reflections.org)
246+
has its coordinates in a database. You can just plug in <code>ross</code> for the station name and leave
257247
latitude/longitude/height blank. You *do* need to plug in a
258248
RH of 4 since mean sea level would not be an appropriate
259249
reflector height value for this
@@ -444,3 +434,6 @@ Note that the names of the columns (and units) are provided
444434
When multiplied by RHdot (meters/hour), you will get a correction in units of meters. For further
445435
information, see the <code>subdaily</code> code.
446436

437+
Kristine M. Larson
438+
439+
January 11, 2024

gnssrefl/download_noaa.py

+74
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# -*- coding: utf-8 -*-
22
import argparse
33
import datetime
4+
import numpy as np
45
import os
56
import requests
67
import subprocess
78
import sys
9+
import wget
810
import gnssrefl.gps as g
911

1012
#from gnssrefl.utils import validate_input_datatypes, str2bool
@@ -402,6 +404,78 @@ def pickup_from_noaa(station,date1,date2,datum, printmeta):
402404

403405
return data, error
404406

407+
def download_qld(station,year,plt):
408+
"""
409+
Parameters
410+
----------
411+
station : str
412+
tide gauge station name
413+
year : int
414+
calendar year
415+
plt : bool
416+
whether you want a plot to the screen
417+
"""
418+
# unfortunately hardwired for 2022 now
419+
#https://www.qld.gov.au/environment/coasts-waterways/beach/storm/storm-sites
420+
# last seven days
421+
# https://www.data.qld.gov.au/dataset/coastal-data-system-near-real-time-storm-tide-data
422+
if year is None:
423+
print('Year is required for the Queensland option')
424+
sys.exit()
425+
else:
426+
url = 'https://www.data.qld.gov.au/dataset/179c7cc5-26a7-4f57-9e1e-3ec2ed5dd4de/resource/cacc9e98-be38-44f7-a535-07acd22a3b91/'
427+
url2 = 'download/h071004a_' + str(year) + '_' + station + '_10min.csv'
428+
tmpfile = station + '_' + str(year) + '_10min.csv'
429+
wget.download(url+url2, tmpfile)
430+
431+
xdir = os.environ['REFL_CODE']
432+
outdir = xdir + '/Files/'
433+
if not os.path.exists(outdir) :
434+
subprocess.call(['mkdir', outdir])
435+
outfile = outdir + station + '_' + str(year) + '.txt'
436+
437+
fout = open(outfile, 'w+')
438+
print('Queensland Tide file written to :', outfile)
439+
440+
obstimes=[]
441+
sl = []
442+
fout.write("{0:s} \n".format('%' + ' QLD Station: ' + station ))
443+
fout.write("%YYYY MM DD HH MM SS Water(m) DOY MJD \n")
444+
fout.write("% 1 2 3 4 5 6 7 8 9\n")
445+
446+
if os.path.isfile(tmpfile):
447+
x=np.loadtxt(tmpfile,usecols=(0,1,3),skiprows=40,dtype='str',delimiter=',')
448+
nr,nc=np.shape(x)
449+
for i in range(0,nr):
450+
sealevel = float(x[i,2])
451+
sl.append(sealevel)
452+
d = int(x[i,0][0:2]) ; m = int(x[i,0][3:5])
453+
y = int(x[i,0][6:10])
454+
hr = int(x[i,1][1:3]); mm = int(x[i,1][4:6])
455+
bigT = datetime.datetime(year=y, month=m, day=d,hour=hr,minute=mm,second=0)
456+
obstimes.append(bigT)
457+
modjul, fr = g.mjd(y,m,d,hr,mm,0)
458+
mjd = modjul+fr
459+
doy,cdoy,cyyyy,cyy = g.ymd2doy(y, m, d )
460+
fout.write(" {0:4.0f} {1:2.0f} {2:2.0f} {3:2.0f} {4:2.0f} {5:2.0f} {6:7.3f} {7:3.0f} {8:15.6f} \n".format(y, m, d, hr, mm, 0, sealevel, doy, mjd))
461+
462+
fout.close()
463+
else:
464+
print('No file was downloaded')
465+
sys.exit()
466+
467+
if plt:
468+
g.quickp(station,obstimes,sl)
469+
470+
# clean up - remove csv file
471+
subprocess.call(['rm','-f',tmpfile])
472+
473+
# this is more direct API call for last seven days ... I think
474+
#urlL = 'https://www.data.qld.gov.au/api/3/action/datastore_search?resource_id=7afe7233-fae0-4024-bc98-3a72f05675bd'
475+
#endL = '&q=' + station + '&limit=' + str(NV)
476+
477+
# https://www.data.qld.gov.au/dataset/coastal-data-system-near-real-time-storm-tide-data
478+
405479

406480
if __name__ == "__main__":
407481
main()

gnssrefl/download_tides.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
import argparse
33
import datetime
4+
import wget
45
import os
56
import requests
67
import subprocess
@@ -17,14 +18,15 @@
1718
def parse_arguments():
1819
parser = argparse.ArgumentParser()
1920
parser.add_argument("station", help="station name, e.g. 8768094", type=str)
20-
parser.add_argument("network", help="tidegauge network (noaa,ioc,psmsl,wsv)", type=str)
21+
parser.add_argument("network", help="tidegauge network (noaa,ioc,psmsl,wsv,qld)", type=str)
2122
parser.add_argument("-date1", help="start-date, 20150101", type=str, default=None)
2223
parser.add_argument("-date2", help="end-date, 20150110", type=str, default=None)
2324
parser.add_argument("-output", default=None, help="Optional output filename", type=str)
2425
parser.add_argument("-plt", default=None, help="quick plot to screen", type=str)
2526
parser.add_argument("-datum", default=None, help="datum for NOAA", type=str)
2627
parser.add_argument("-sensor", default=None, help="sensor type for IOC", type=str)
2728
parser.add_argument("-subdir", default=None, help="optional subdirectory name for output", type=str)
29+
parser.add_argument("-year", default=None, help="year for archive QLD data", type=str)
2830
args = parser.parse_args().__dict__
2931

3032
# convert all expected boolean inputs from strings to booleans
@@ -35,7 +37,7 @@ def parse_arguments():
3537
# only return a dictionary of arguments that were added from the user - all other defaults will be set in code below
3638
return {key: value for key, value in args.items() if value is not None}
3739

38-
def download_tides(station: str, network : str, date1: str = None, date2: str = None, output: str = None, plt: bool = False, datum: str = 'mllw', subdir: str = None):
40+
def download_tides(station: str, network : str, date1: str = None, date2: str = None, output: str = None, plt: bool = False, datum: str = 'mllw', subdir: str = None, year: int=None):
3941
"""
4042
Downloads tide gauge data from four different networks (see below)
4143
@@ -114,9 +116,12 @@ def download_tides(station: str, network : str, date1: str = None, date2: str =
114116
download_wsv.download_wsv(station, plt, output)
115117
elif network == 'psmsl':
116118
download_psmsl.download_psmsl(station, output,plt )
119+
elif network == 'qld':
120+
download_noaa.download_qld(station,year,plt)
117121
else:
118122
print('I do not recognize your tide gauge network')
119123

124+
120125
def main():
121126
args = parse_arguments()
122127
download_tides(**args)

gnssrefl/gps.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -5303,7 +5303,8 @@ def rinex_jp(station, year, month, day):
53035303

53045304
def queryUNR_modern(station):
53055305
"""
5306-
Queries the UNR database for station coordinates that has been stored in sql. downloads it if necessary
5306+
Queries the UNR database for station coordinates that has been stored in sql. downloads
5307+
the sql file and stores it locally if necessary
53075308
53085309
Parameters
53095310
-----------
@@ -5374,6 +5375,8 @@ def queryUNR_modern(station):
53745375

53755376
# close the database
53765377
conn.close()
5378+
# some of the Nevada Reno stations have the same names as stations used in GNSS-IR.
5379+
53775380
if (station == 'moss'):
53785381
lat= -16.434464800 ;lon = 145.403622520 ; ht = 71.418
53795382
elif (station == 'mnis'):

gnssrefl/max_resolve_RH_cl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def max_resolve_RH(station: str, lat: float=None, lon: float=None, el_height: fl
4646
typical case for most geodetic sites, 30 seconds, elevation angles 5-15 degrees
4747
4848
max_resolve_RH sc02 -samplerate 15 -system galileo
49-
receiver sampling rate of 15 seconds and galileo
49+
Assume receiver sampling rate of 15 seconds and the Galileo constellation
5050
5151
Parameters
5252
----------

gnssrefl/nyquist_libs.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,29 @@ def ny_plot(station,allN, info,hires_figs):
108108
109109
"""
110110
# wavelengths in meters, being lazy
111+
l1 = 0.19029360
111112
l2 = 0.24421
112113
l5 = 0.254828048
113-
l1 = 0.19029360
114+
# defaults
115+
plot_l2 = True
116+
plot_l5 = True
117+
if 'GALILEO' in info:
118+
plot_l2 = False
119+
if 'GLONASS' in info:
120+
plot_l5 = False
121+
if 'BEIDOU' in info:
122+
# the beidou signal names are all messed up
123+
# but that is how they are stored in the RINEX files...
124+
plot_l5 = False
125+
114126
#fig = Figure(figsize=(8,4),dpi=360)
115127
#fig,ax = fig.subplots()
116128
fig, ax = plt.subplots(figsize=(10,6))
117129
ax.plot(allN[:,0],allN[:,1],'bo',label='L1')
118-
ax.plot(allN[:,0],l2*allN[:,1]/l1,'ro',label='L2')
119-
ax.plot(allN[:,0],l5*allN[:,1]/l1,'co',label='L5')
130+
if plot_l2:
131+
ax.plot(allN[:,0],l2*allN[:,1]/l1,'ro',label='L2')
132+
if plot_l5:
133+
ax.plot(allN[:,0],l5*allN[:,1]/l1,'co',label='L5')
120134
ax.set_title(station + ': Maximum Resolvable RH /' + info, fontsize=14)
121135
ax.grid()
122136
ax.set_xlabel('Azimuth (deg)')

gnssrefl/quicklib.py

+13-14
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import gnssrefl.gps as g
1111

12-
def trans_time(tvd, ymd, convert_mjd, ydoy ,xcol,ycol,utc_offset):
12+
def trans_time(tvd, ymd, ymdhm, convert_mjd, ydoy ,xcol,ycol,utc_offset):
1313
"""
1414
translates time for quickplt
1515
@@ -20,6 +20,8 @@ def trans_time(tvd, ymd, convert_mjd, ydoy ,xcol,ycol,utc_offset):
2020
ymd : bool
2121
first three columns are year,month,day, hour,
2222
minute,second
23+
ymdhm : bool
24+
first five columns are year,month,day, hour, minut,
2325
convert_mjd : bool
2426
convert from MJD (column 1 designation)
2527
time is datetime obj
@@ -54,19 +56,17 @@ def trans_time(tvd, ymd, convert_mjd, ydoy ,xcol,ycol,utc_offset):
5456
print('You asked to plot column', xcol+1, ' and that column does not exist in the file')
5557
sys.exit()
5658

57-
if ymd == True:
58-
year = tvd[:,0]; month = tvd[:,1]; day = tvd[:,2];
59-
hour = tvd[:,3] ; minute = tvd[:,4]
59+
if ymd :
6060
for i in range(0,len(tvd)):
61-
if (tvd[i, 4]) > 0:
62-
y = int(year[i]); m = int(month[i]); d = int(day[i])
63-
# i am sure there is a better way to do this
64-
today=datetime.datetime(y,m,d)
65-
doy = (today - datetime.datetime(today.year, 1, 1)).days + 1
66-
h = int(hour[i])
67-
mi = int(minute[i])
68-
tval.append(y + (doy + h/24 + mi/24/60)/365.25);
69-
yval.append( tvd[i,ycol]/1000)
61+
bigT = datetime.datetime(year=int(tvd[i,0]), month=int(tvd[i,1]), day=int(tvd[i,2]) )
62+
tval.append(bigT)
63+
yval.append( tvd[i,ycol])
64+
elif ymdhm:
65+
for i in range(0,len(tvd)):
66+
bigT = datetime.datetime(year=int(tvd[i,0]), month=int(tvd[i,1]),
67+
day=int(tvd[i,2]), hour=int(tvd[i,3]), minute=int(tvd[i,4]), second=0)
68+
tval.append(bigT)
69+
yval.append( tvd[i,ycol])
7070
else:
7171
if convert_mjd:
7272
mm = tvd[:,xcol]
@@ -90,7 +90,6 @@ def trans_time(tvd, ymd, convert_mjd, ydoy ,xcol,ycol,utc_offset):
9090
tval = tvd[:,xcol] ; yval = tvd[:,ycol]
9191
x1 = min(tval) ; x2 = max(tval)
9292

93-
9493
return tval, yval
9594

9695
def set_xlimits_ydoy(xlimits):

0 commit comments

Comments
 (0)