shipgrav 1.0.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ ################################################################################
2
+ # IXBlue PHINS III MRU GPS [from the ABX-Two], attitude, and heading
3
+ #
4
+ # See README.md in this directory
5
+ ######################################
6
+ IXBlueHydrins:
7
+ category: "device_type"
8
+ description: "IXBlue Hydrins MRU GPS"
9
+
10
+ format:
11
+ PHZDA: '${:.2}ZDA,{GPSTime:g},{GPSDay:d},{GPSMonth:d},{GPSYear:d},{LocalHours:od},{LocalZone:od}*{CheckSum:x}'
12
+ PHGGA: '${:.2}GGA,{GPSTime:g},{Latitude:nlat_dir},{Longitude:nlat_dir},{FixQuality:d},{NumSats:d},{HDOP:of},{AntennaHeight:of},M,{GeoidHeight:of},M,{LastDGPSUpdate:of},{DGPSStationID:od}*{CheckSum:x}'
13
+ PHVTG: '${:.2}VTG,{CourseTrue:of},T,{CourseMag:of},M,{SpeedKt:of},N,{SpeedKm:of},K,{Mode:w}*{CheckSum:x}'
14
+ PHGST: '${:.2}GST,{GPSTime:g},{ResidualRMS:g},{ErrorEllipseSemiMajor:g},{ErrorEllipseSemiMinor:g},{ErrorEllipseOrientation:g},{LatitudeError:g},{LongitudeError:g},{HeightError:g}*{CheckSum:x}'
15
+ HEHDT: '${:.2}HDT,{HeadingTrue:og},T*{CheckSum:x}'
16
+ PASHR: '$PASHR,{GPSTime:g},{HeadingTrue:g},T,{Pitch:g},{Roll:g},{Heave:g},{AccuracyPitch:g},{AccuracyRoll:g},{AccuracyHeave:g},{FlagAccuracyHeading:d},{FlagIMU:d}*{Checksum:x}'
17
+
18
+ ########
19
+ # Optional metadata to help make sense of the parsed values.
20
+ fields:
21
+ # GPZDA
22
+ GPSTime:
23
+ units: ""
24
+ description: "UTC of position fix in hhmmss.ss"
25
+ GPSDay:
26
+ units: ""
27
+ description: ""
28
+ GPSMonth:
29
+ units: ""
30
+ description: ""
31
+ GPSYear:
32
+ units: ""
33
+ description: ""
34
+ LocalHours:
35
+ units: ""
36
+ description: ""
37
+ LocalZone:
38
+ description: "Local time zone"
39
+
40
+ # GPGLL
41
+ Latitude:
42
+ units: "degrees"
43
+ description: "Latitude in degrees north; negative for south latitude"
44
+ Longitude:
45
+ units: "degrees"
46
+ description: "Longitude in degrees east; negative for west longitude"
47
+ FixTime:
48
+ description: "UTC of position fix in hhmmss.ss format"
49
+ DataValid:
50
+ description: "A = data valid V = data invalid"
51
+ Mode:
52
+ description: "Mode Indicator: A-Autonomous, M-Manual, D-Differential, S-Simulator, E-Dead Reckoning, N-Data Not Valid"
53
+
54
+ # $GPGGA
55
+ FixQuality:
56
+ Description: "GPS quality indicator: 0 = fix not available or invalid, 1 = GPS SPS mode, fix valid, 2 = differential GPS, SPS mode, fix valid, 3 = GPS PPS mode, fix valid, 4 = Real Time Kinematic. Satellite system used in RTK mode with fixed integers, 5 = Float RTK. Satellite system used in RTK mode with floating integers, 6 = Estimated (dead reckoning) mode, 7 = Manual input mode"
57
+ NumSats:
58
+ description: "Number of satellites in use (00-12)"
59
+ HDOP:
60
+ description: "Horizontal DOP"
61
+ AntennaHeight:
62
+ units: "Meters"
63
+ description: "Antenna height above/below MSL (mean sea level) reference"
64
+ GeoidHeight:
65
+ units: "Meters"
66
+ description: "Geoidal separation (e.g. -33.81 m)"
67
+ LastDGPSUpdate:
68
+ description: "Age of differential GPS data record"
69
+ DGPSStationID:
70
+ description: "Differential Reference Station ID (0000-1023)"
71
+
72
+ # GPRMC
73
+ SpeedKt:
74
+ units: "Knots"
75
+ description: "Speed over ground in knots"
76
+ CourseTrue:
77
+ units: "Degrees"
78
+ description: "Course over ground, True"
79
+ MagneticVar:
80
+ units: "Degrees"
81
+ description: "Magnetic variation"
82
+ MagneticVarEorW:
83
+ description: "Direction of magnetic variation (E - East, W - West)"
84
+
85
+ # GPVTG
86
+ CourseMag:
87
+ units: "Degrees"
88
+ description: "Course over ground, Magnetic"
89
+ SpeedKm:
90
+ units: "Km/hour"
91
+ description: "Speed over ground in Km/hour"
92
+
93
+ # GNGST
94
+ ResidualRMS:
95
+ units: ""
96
+ description: "RMS of pseudo-range residuals"
97
+ ErrorEllipseSemiMajor:
98
+ units: "Meters"
99
+ description: "Error ellipse semi-major axis 1 sigma error"
100
+ ErrorEllipseSemiMinor:
101
+ units: "Meters"
102
+ description: "Error ellipse semi-minor axis 1 sigma error"
103
+ ErrorEllipseOrientation:
104
+ units: "Degrees"
105
+ description: "Error ellipse orientation"
106
+ LatitudeError:
107
+ units: "Meters"
108
+ description: "Latitude 1 sigma error"
109
+ LongitudeError:
110
+ units: "Meters"
111
+ description: "Longitude 1 sigma error"
112
+ HeightError:
113
+ units: "Meters"
114
+ description: "Height 1 sigma error"
115
+
116
+ # GPHDT
117
+ HeadingTrue:
118
+ units: "Degrees"
119
+ description: "Heading, True"
120
+
121
+ # PASHR_VEL
122
+ EastingVelocity:
123
+ units: "Meters/sec"
124
+ description: "Easting velocity"
125
+ EastingVelocity:
126
+ units: "Meters/sec"
127
+ description: "Easting velocity"
128
+ NorthingVelocity:
129
+ units: "Meters/sec"
130
+ description: "Northing velocity"
131
+ VerticalVelocity:
132
+ units: "Meters/sec"
133
+ description: "Vertical velocity"
134
+ EastingVelocityRMS:
135
+ units: "MM/sec"
136
+ description: "Easting velocity RMS"
137
+ NorthingVelocityRMS:
138
+ units: "MM/sec"
139
+ description: "Northing velocity RMS"
140
+ VerticalVelocityRMS:
141
+ units: "MM/sec"
142
+ description: "Vertical velocityRMS"
143
+
144
+ # PASHR POSMV
145
+ Pitch:
146
+ units: "Degrees"
147
+ Roll:
148
+ units: "Degrees"
149
+ Heave:
150
+ units: "Meters"
151
+ AccuracyPitch:
152
+ units: "Degrees"
153
+ AccuracyRoll:
154
+ units: "Degrees"
155
+ AccuracyHeave:
156
+ units: "Meters"
157
+ FlagAccuracyHeading:
158
+ description: "0 = no aiding, 1 = GNSS aiding, 2 = GNSS & GAMS aiding"
159
+ FlagIMU:
160
+ description: "0 = IMU out, 1 = satisfactory"
@@ -0,0 +1,2 @@
1
+ 2023-06-16T00:00:00.857719Z $AT1M_3.64_198247,-218747,30292,-80876,4614745,236,483,200,7687710,711267,-1160673,-397137,330,11187500,0.0000000000,0.0000000000,0.0000,0.0000,1686873601
2
+ 2023-06-16T00:00:02.856681Z $AT1M_3.64_198249,211924,-115826,-224438,4609755,236,483,204,7960237,791445,-1288380,-864564,330,11081076,0.0000000000,0.0000000000,0.0000,0.0000,1686873603
@@ -0,0 +1,12 @@
1
+ 2023-06-16T00:00:00.089227Z $PHGGA,000000.08,4419.27616746,N,12500.33483564,W,2,10,0.828,-31.369,M,-27.243,M,4.000,0135*6D
2
+ 2023-06-16T00:00:00.089227Z $PHGST,000000.08,0.000,0.586,0.585,156.604,0.586,0.585,0.567*54
3
+ 2023-06-16T00:00:00.089227Z $PHVTG,150.616,T,150.616,M,0.160,N,0.297,K,D*22
4
+ 2023-06-16T00:00:00.089227Z $HEHDT,353.12,T*19
5
+ 2023-06-16T00:00:00.089227Z $PASHR,000000.085,353.12,T,-0.41,+2.03,-0.60,0.004,0.004,0.083,1,0*38
6
+ 2023-06-16T00:00:00.589236Z $PHGGA,000000.58,4419.27613524,N,12500.33480248,W,2,10,0.828,-31.275,M,-27.243,M,4.400,0135*69
7
+ 2023-06-16T00:00:00.589236Z $PHGST,000000.58,0.000,0.586,0.585,156.604,0.586,0.585,0.567*51
8
+ 2023-06-16T00:00:00.589236Z $PHVTG,140.298,T,140.298,M,0.413,N,0.766,K,D*28
9
+ 2023-06-16T00:00:00.589236Z $HEHDT,353.20,T*18
10
+ 2023-06-16T00:00:00.589236Z $PASHR,000000.585,353.20,T,+0.18,+1.59,-0.69,0.004,0.004,0.083,1,0*33
11
+ 2023-06-16T00:00:01.039256Z $PHZDA,000001.03,16,06,2023,00,00*69
12
+ 2023-06-16T00:00:01.089253Z $PHGGA,000001.08,4419.27608228,N,12500.33473623,W,2,10,0.828,-31.289,M,-27.243,M,5.000,0135*6F
@@ -0,0 +1,2 @@
1
+ 03/13/2022,00:00:02.449,04:025529 00
2
+ 03/13/2022,00:00:03.449,04:025706 00
@@ -0,0 +1,2 @@
1
+ 03/13/2022,00:00:02.105,$INGGA,000003.560,3217.33152,N,11839.14935,W,5,26,0.8,0.19,M,,,7,1015*06
2
+ 03/13/2022,00:00:02.652,$INGGA,000004.060,3217.33129,N,11839.14969,W,5,26,0.8,0.26,M,,,7,1015*0D
@@ -0,0 +1,75 @@
1
+ """
2
+ Tests for shipgrav.grav
3
+ These use 1000 seconds of sample data to calculate corrections and check values
4
+ ccp coeffs are not objectively good because the time series is short but it works for tests
5
+ Not bothering with the leveling correction here because exactly how to calculate it
6
+ is left to the user
7
+ """
8
+ import unittest
9
+ import numpy as np
10
+ import shipgrav.grav as sgg
11
+ import shipgrav.io as sgi
12
+ import shipgrav.nav as sgn
13
+ from glob import glob
14
+
15
+
16
+ class gravDataTestCase(unittest.TestCase):
17
+ def setUp(self): # actions to take before running each test: load in some test data
18
+ # test data is part of one of the files supplied by DGS (original file is 30M/86400
19
+ # lines for 24 hr; we cut to 1 hr?)
20
+ gfiles = glob('ex_files/DGStest*.dat')
21
+ data = sgi.read_dgs_laptop(gfiles, 'DGStest')
22
+ data['tsec'] = [e.timestamp()
23
+ for e in data['date_time']] # get posix timestamps
24
+ data['grav'] = data['rgrav'] + 969143
25
+ self.data = data
26
+
27
+ def test_longman(self):
28
+ lt = sgg.longman_tide_prediction(
29
+ self.data['lon'], self.data['lat'], self.data['date_time'])
30
+ self.assertTrue(lt[0] + 0.079599 < 0.001)
31
+
32
+ def test_eotvos(self):
33
+ eotvos = sgg.eotvos_full(self.data['lon'].values, self.data['lat'].values,
34
+ np.zeros(len(self.data)), 1)
35
+ self.assertTrue(eotvos[0] + 56.90367 < 0.001)
36
+
37
+ def test_fa2ord(self):
38
+ fa2 = sgg.free_air_second_order(
39
+ self.data['lat'], np.zeros(len(self.data)))
40
+ self.assertEqual(fa2.iloc[0], 0.)
41
+
42
+ def test_up_vecs(self):
43
+ lat_corr = sgg.wgs_grav(self.data['lat']) + sgg.free_air_second_order(self.data['lat'],
44
+ np.zeros(len(self.data)))
45
+ ve, vn = sgn.latlon_to_EN(
46
+ self.data['lon'].values, self.data['lat'].values)
47
+ eacc = 1e5*np.convolve(ve, sgn.tay10, 'same')
48
+ nacc = 1e5*np.convolve(vn, sgn.tay10, 'same')
49
+ crse, vel = sgn.ENvel_to_course_heading(ve, vn)
50
+ acrss, along = sgn.rotate_acceleration_EN_to_cl(crse, eacc, nacc)
51
+ up_vecs = sgg.up_vecs(1, lat_corr, acrss, along,
52
+ 0, 240, 0.7071, 240, 0.7071)
53
+ self.assertEqual(up_vecs[0, 0], 0.)
54
+ self.assertEqual(up_vecs[2, 0], 1.)
55
+
56
+ def test_ccpcalc(self):
57
+ lt = sgg.longman_tide_prediction(
58
+ self.data['lon'], self.data['lat'], self.data['date_time'])
59
+ eotvos = sgg.eotvos_full(self.data['lon'].values, self.data['lat'].values,
60
+ np.zeros(len(self.data)), 1)
61
+ lat_corr = sgg.wgs_grav(self.data['lat']) + sgg.free_air_second_order(self.data['lat'],
62
+ np.zeros(len(self.data)))
63
+ faa = self.data['grav'] - lat_corr + eotvos + lt
64
+ _, model = sgg.calc_cross_coupling_coefficients(faa, self.data['vcc'].values, self.data['ve'].values,
65
+ self.data['al'].values, self.data['ax'].values, np.zeros(len(self.data)))
66
+ self.assertTrue(model.params.ax + 3.428237 < 0.0001)
67
+ self.assertTrue(model.params.ve - 0.055732 < 0.0001)
68
+
69
+
70
+ def suite():
71
+ return unittest.makeSuite(gravDataTestCase, 'test')
72
+
73
+
74
+ if __name__ == '__main__':
75
+ unittest.main(defaultTest='suite')
@@ -0,0 +1,47 @@
1
+ """
2
+ Tests for shipgrav.grav
3
+ """
4
+ import unittest
5
+ import numpy as np
6
+ import shipgrav.grav as sgg
7
+
8
+
9
+ class gravNoDataTestCase(unittest.TestCase):
10
+ def test_grav1d(self):
11
+ # arbitrary numbers here, not real
12
+ test_grav = sgg.grav1d_padded(np.linspace(
13
+ 0, 100, 10), np.linspace(10, 15, 10), 1, 0.4)
14
+ self.assertTrue(test_grav[1] - 0.000157 < 0.001)
15
+
16
+ def test_halfspace_T(self):
17
+ T, W = sgg.therm_halfspace(np.array([20e3]), np.array([1e3]), u=0.02)
18
+ self.assertTrue(T[0] - 135.2263 < 0.001)
19
+ self.assertTrue(W[0] - 368.3393 < 0.001)
20
+
21
+ def test_halfspace_Z(self):
22
+ Z, W = sgg.therm_Z_halfspace(np.array([20e3]), 135.2263, u=0.02)
23
+ self.assertTrue(Z[0] - 1e3 < 0.001)
24
+ self.assertTrue(W[0] - 368.3393 < 0.001)
25
+
26
+ def test_plate_T(self):
27
+ T, W = sgg.therm_plate(np.array([20e3]), np.array([1e3]), u=0.02)
28
+ self.assertTrue(T[0] - 134.0867 < 0.001)
29
+ self.assertTrue(W[0] - 381.6513 < 0.001)
30
+
31
+ def test_plate_Z(self):
32
+ Z = sgg.therm_Z_plate(
33
+ np.array([20e3]), np.array([134.0867]), u=0.02)
34
+ self.assertEqual(Z[0], 1000.)
35
+
36
+ def test_crustalthickness(self):
37
+ rng = np.random.default_rng(123) # seeded
38
+ C = sgg.crustal_thickness_2D(10*rng.random(1000))
39
+ self.assertTrue(np.real(C[0])[0] - 0.04019 < 0.001)
40
+
41
+
42
+ def suite():
43
+ return unittest.makeSuite(gravNoDataTestCase, 'test')
44
+
45
+
46
+ if __name__ == '__main__':
47
+ unittest.main(defaultTest='suite')
@@ -0,0 +1,55 @@
1
+ """
2
+ Tests for shipgrav.io
3
+ This does not test every option for read (because there are many ships)
4
+ but for each overall read function it reads a snippet of an example file
5
+ and checks that the values in key columns are correct
6
+ """
7
+ import unittest
8
+ import shipgrav.io as sgi
9
+
10
+
11
+ class ioTestCase(unittest.TestCase):
12
+ def test_read_nav(self): # NOTE only tests one of the ship functions
13
+ # but it does include extracting clock time -> datetime -> posix
14
+ nav = sgi.read_nav('Thompson', 'ex_files/TN400_nav.Raw')
15
+ self.assertEqual(nav.iloc[0].time_sec, 1647129603)
16
+ self.assertTrue(nav.iloc[0].lon + 118.6524 < 0.001)
17
+
18
+ def test_read_bgm_rgs(self):
19
+ bgm = sgi.read_bgm_rgs('ex_files/AT05_01_bgm.RGS', 'Atlantis')
20
+ self.assertEqual(bgm.iloc[0]['date_time'].timestamp(), 1656633600.445)
21
+ self.assertEqual(bgm.iloc[0]['grav'], 980329.272)
22
+
23
+ def test_read_bgm_raw(self):
24
+ bgm = sgi.read_bgm_raw('ex_files/TN400_bgm.Raw', 'Thompson')
25
+ self.assertEqual(bgm.iloc[0]['date_time'].timestamp(), 1647129602.449)
26
+ self.assertEqual(bgm.iloc[0]['counts'], 25529)
27
+ self.assertEqual(bgm.iloc[0]['rgrav'], 127730.60800402702)
28
+
29
+ def test_read_dgs_dat(self):
30
+ dgs = sgi.read_dgs_laptop('ex_files/DGStest_laptop.dat', 'DGStest')
31
+ self.assertEqual(dgs.iloc[0]['date_time'].timestamp(), 1562803200.0)
32
+ self.assertEqual(dgs.iloc[0]['ve'], 0.81098)
33
+ self.assertTrue(dgs.iloc[0]['rgrav'] - 12295.691114 < 0.0001)
34
+
35
+ def test_read_dgs_raw(self):
36
+ dgs = sgi.read_dgs_raw('ex_files/SR2312_dgs_raw.txt', 'Ride')
37
+ self.assertEqual(
38
+ dgs.iloc[0]['date_time'].timestamp(), 1686873600.857719)
39
+ self.assertEqual(dgs.iloc[0]['Gravity'], -218747)
40
+ self.assertTrue(dgs.iloc[0]['vcc'] - 76.8771 < 0.0001)
41
+
42
+ def test_read_mru(self):
43
+ mru, cols = sgi.read_other_stuff(
44
+ 'ex_files/IXBlue.yaml', 'ex_files/SR2312_mru.txt', 'PASHR')
45
+ self.assertEqual(mru.iloc[0]['Pitch:g'], -0.41)
46
+ self.assertEqual(mru.iloc[0]['Roll:g'], 2.03)
47
+ self.assertEqual(mru.iloc[0]['Heave:g'], -0.6)
48
+
49
+
50
+ def suite():
51
+ return unittest.makeSuite(ioTestCase, 'test')
52
+
53
+
54
+ if __name__ == '__main__':
55
+ unittest.main(defaultTest='suite')
@@ -0,0 +1,41 @@
1
+ """
2
+ Tests for shipgrav.nav
3
+ """
4
+ import unittest
5
+ import shipgrav.nav as sgn
6
+ import numpy as np
7
+
8
+
9
+ class navTestCase(unittest.TestCase):
10
+ def setUp(self):
11
+ lons = np.ones(100)*70
12
+ lats = np.linspace(40, 41, 100)
13
+ # lat/lon to easting and northing *velocities*
14
+ ve, vn = sgn.latlon_to_EN(lons, lats)
15
+ self.ve = ve
16
+ self.vn = vn
17
+
18
+ def test_ll2en(self):
19
+ self.assertTrue(self.ve[5] - 1121.5717 < 0.001)
20
+ self.assertTrue(self.vn[5] < 1e-7)
21
+
22
+ def test_en2cv(self):
23
+ course, vel = sgn.ENvel_to_course_heading(self.ve, self.vn)
24
+ self.assertTrue(course[5] - 90. < 0.001)
25
+ self.assertEqual(vel[5], self.ve[5])
26
+
27
+ def test_rot_acc(self):
28
+ course, vel = sgn.ENvel_to_course_heading(self.ve, self.vn)
29
+ eacc = 1e5*np.convolve(self.ve, sgn.tay10, 'same')
30
+ nacc = 1e5*np.convolve(self.vn, sgn.tay10, 'same')
31
+ cross, long = sgn.rotate_acceleration_EN_to_cl(course, eacc, nacc)
32
+ self.assertTrue(cross[10] < 1e-7)
33
+ self.assertEqual(long[10], eacc[10])
34
+
35
+
36
+ def suite():
37
+ return unittest.makeSuite(navTestCase, 'test')
38
+
39
+
40
+ if __name__ == '__main__':
41
+ unittest.main(defaultTest='suite')
@@ -0,0 +1,33 @@
1
+ """
2
+ Tests for shipgrav.utils
3
+ """
4
+ import unittest
5
+ import shipgrav.utils as sgu
6
+ import numpy as np
7
+
8
+
9
+ class utilsTestCase(unittest.TestCase):
10
+ def test_gaussian_filter(self):
11
+ # make a spike, filtfilt for no shift, check amplitude
12
+ test = np.zeros(101)
13
+ test[50] = 1
14
+ test_fl = sgu.gaussian_filter(test, 10)
15
+ test_ffll = sgu.gaussian_filter(test_fl[::-1], 10)
16
+ self.assertTrue(test_ffll[50] - 0.12975 < 0.001)
17
+
18
+ def test_status_decode(self):
19
+ # make a code, decode it, check a few of the 16 status bits
20
+ stat = 12345
21
+ decoded = sgu.decode_dgs_status_bits(stat)
22
+ self.assertEqual(decoded['clamp status'], '0')
23
+ self.assertEqual(decoded['GPSsync'], '0')
24
+ self.assertEqual(decoded['GPStime'], '1')
25
+ self.assertEqual(decoded['feedback'], '1')
26
+
27
+
28
+ def suite():
29
+ return unittest.makeSuite(utilsTestCase, 'test')
30
+
31
+
32
+ if __name__ == '__main__':
33
+ unittest.main(defaultTest='suite')