Skip to content
Snippets Groups Projects

Add support for Q8 datalogger

Merged Kien Le requested to merge feature-#290-add_Q8_support into build-2025.1.0.0
1 file
+ 78
0
Compare changes
  • Side-by-side
  • Inline
@@ -306,6 +306,82 @@ def extract_gps_data_pegasus_centaur(data_obj: MSeed, data_type: str
return extracted_gps_points
def extract_gps_data_q8(data_obj: MSeed, data_type: str) -> List[GPSPoint]:
"""
Extract GPS data of the current data set and store it in self.gps_points.
Only applicable to Q8 data sets.
:param data_obj: the data object that stores the read data
:param data_type: data type of the current data set
"""
GPS_CHANS = {'LAT', 'LON', 'LEV', 'LFT', 'LSU'}
channels = data_obj.soh_data[data_obj.selected_data_set_id].keys()
if not GPS_CHANS.issubset(channels):
missing_gps_chans = GPS_CHANS - channels
missing_gps_chans_string = ', '.join(missing_gps_chans)
raise ValueError(f"Some GPS channels are missing: "
f"{missing_gps_chans_string}.")
# Caching GPS data in dictionaries for faster access. In the algorithm
# below, we need to access the data associated with a time. If we leave
# the times and data in arrays, we will need to search for the index of
# the specified time in the times array, which takes O(N) time. The
# algorithm then repeats this step n times, which gives us a total
# complexity of O(n^2). Meanwhile, if we cache the times and data in
# a dictionary, we only need to spend O(n) time building the cache and
# O(n) time accessing the cache, which amounts to O(n) time in total.
ns_dict = get_chan_soh_trace_as_dict(data_obj, 'LSU')
la_dict = get_chan_soh_trace_as_dict(data_obj, 'LAT')
lo_dict = get_chan_soh_trace_as_dict(data_obj, 'LON')
el_dict = get_chan_soh_trace_as_dict(data_obj, 'LEV')
extracted_gps_points = []
for time, num_sats_used in ns_dict.items():
# We currently don't know how to translate the data in the LFT channel
# into the actual fix type, so we are giving it a dummy value until we
# can do so.
fix_type = 'N/A'
current_lat = la_dict.get(time, None)
current_long = lo_dict.get(time, None)
current_height = el_dict.get(time, None)
# We are ignoring any point that does not have complete location data.
# It might be possible to only ignore points with missing latitude or
# longitude, seeing as height is not required to plot a GPS point.
if (current_lat is None or
current_long is None or
current_height is None):
continue
for i, num_sats in enumerate(num_sats_used):
try:
# Convert the location data to the appropriate unit. Q8 stores
# latitude and longitude in microdegrees, and we want them to
# be in degrees. The unit of the elevation is m, which is what
# we want so there is no conversion done.
lat = current_lat[i] / 1e6
long = current_long[i] / 1e6
height = current_height[i]
height_unit = 'M'
formatted_time = UTCDateTime(time).strftime(
'%Y-%m-%d %H:%M:%S'
)
gps_point = GPSPoint(formatted_time, fix_type, num_sats, lat,
long, height, height_unit)
extracted_gps_points.append(gps_point)
except IndexError:
break
# We only need to loop through one dictionary. If a time is not
# available for a channel, the GPS data point at that time would be
# invalid (it is missing a piece of data). Once we loop through a
# channel's dictionary, we know that any time not contained in that
# dictionary is not available for the channel. As a result, any time
# we pass through in the other channels after the first loop would
# result in an invalid GPS data point. Because we discard any invalid
# point, there is no point in looping through the dictionary of other
# channels.
return extracted_gps_points
def extract_gps_data_rt130(data_obj: RT130) -> List[GPSPoint]:
"""
Retrieve the GPS of the current data set. Works by looking into the log
@@ -450,6 +526,8 @@ def gps_data_mseed(data_obj: MSeed) -> List[GPSPoint]:
return extract_gps_data_q330(data_obj)
elif data_type == 'Centaur' or data_type == 'Pegasus':
return extract_gps_data_pegasus_centaur(data_obj, data_type)
elif data_type == 'Q8':
return extract_gps_data_q8(data_obj, data_type)
else:
# data_type = "Unknown"
try:
Loading