@@ -80,10 +80,15 @@ def _parse_degrees(nmea_data):
80
80
# Where ddd is the degrees, mm.mmmm is the minutes.
81
81
if nmea_data is None or len (nmea_data ) < 3 :
82
82
return None
83
- raw = float (nmea_data )
84
- deg = raw // 100
85
- minutes = raw % 100
86
- return deg + minutes / 60
83
+ # To avoid losing precision handle degrees and minutes separately
84
+ # Return the final value as an integer. Further functions can parse
85
+ # this into a float or separate parts to retain the precision
86
+ raw = nmea_data .split ("." )
87
+ degrees = int (raw [0 ]) // 100 * 1000000 # the ddd
88
+ minutes = int (raw [0 ]) % 100 # the mm.
89
+ minutes += int (f"{ raw [1 ][:4 ]:0<4} " ) / 10000
90
+ minutes = int (minutes / 60 * 1000000 )
91
+ return degrees + minutes # return parsed string in the format dddmmmmmm
87
92
88
93
89
94
def _parse_int (nmea_data ):
@@ -105,12 +110,21 @@ def _parse_str(nmea_data):
105
110
106
111
107
112
def _read_degrees (data , index , neg ):
108
- x = data [index ]
113
+ # This function loses precision with float32
114
+ x = data [index ] / 1000000
109
115
if data [index + 1 ].lower () == neg :
110
116
x *= - 1.0
111
117
return x
112
118
113
119
120
+ def _read_int_degrees (data , index , neg ):
121
+ deg = data [index ] // 1000000
122
+ minutes = data [index ] % 1000000 / 10000
123
+ if data [index + 1 ].lower () == neg :
124
+ deg *= - 1
125
+ return (deg , minutes )
126
+
127
+
114
128
def _parse_talker (data_type ):
115
129
# Split the data_type into talker and sentence_type
116
130
if data_type [:1 ] == b"P" : # Proprietary codes
@@ -208,7 +222,11 @@ def __init__(self, uart, debug=False):
208
222
# Initialize null starting values for GPS attributes.
209
223
self .timestamp_utc = None
210
224
self .latitude = None
225
+ self .latitude_degrees = None
226
+ self .latitude_minutes = None # Use for full precision minutes
211
227
self .longitude = None
228
+ self .longitude_degrees = None
229
+ self .longitude_minutes = None # Use for full precision minutes
212
230
self .fix_quality = 0
213
231
self .fix_quality_3d = 0
214
232
self .satellites = None
@@ -424,9 +442,11 @@ def _parse_gll(self, data):
424
442
425
443
# Latitude
426
444
self .latitude = _read_degrees (data , 0 , "s" )
445
+ self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 0 , "s" )
427
446
428
447
# Longitude
429
448
self .longitude = _read_degrees (data , 2 , "w" )
449
+ self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 2 , "w" )
430
450
431
451
# UTC time of position
432
452
self ._update_timestamp_utc (data [4 ])
@@ -462,9 +482,11 @@ def _parse_rmc(self, data):
462
482
463
483
# Latitude
464
484
self .latitude = _read_degrees (data , 2 , "s" )
485
+ self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 2 , "s" )
465
486
466
487
# Longitude
467
488
self .longitude = _read_degrees (data , 4 , "w" )
489
+ self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 4 , "w" )
468
490
469
491
# Speed over ground, knots
470
492
self .speed_knots = data [6 ]
@@ -498,9 +520,11 @@ def _parse_gga(self, data):
498
520
499
521
# Latitude
500
522
self .latitude = _read_degrees (data , 1 , "s" )
523
+ self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 1 , "s" )
501
524
502
525
# Longitude
503
526
self .longitude = _read_degrees (data , 3 , "w" )
527
+ self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 3 , "w" )
504
528
505
529
# GPS quality indicator
506
530
# 0 - fix not available,
0 commit comments