Skip to content
Snippets Groups Projects

Implement a dialog to plot and export GPS data

Merged Kien Le requested to merge feature-#19-gps_plotter_q330 into master
Files
5
"""
MSeed object to hold and process MSeed data
"""
import functools
import operator
import os
from pathlib import Path
from typing import Dict, Tuple, List, Set
@@ -12,7 +11,6 @@ from obspy.core import Stream
from sohstationviewer.conf import constants
from sohstationviewer.controller.util import validateFile
from sohstationviewer.model.data_type_model import DataTypeModel, ThreadStopped
from sohstationviewer.model.gps_point import GPSPoint
from sohstationviewer.model.handling_data import (
readWaveformMSeed, squash_gaps, checkWFChan, sortData, readSOHTrace,
)
@@ -58,8 +56,6 @@ class MSeed(DataTypeModel):
if len(self.reqWFChans) != 0:
self.readWFFiles(self.selectedKey)
self.get_gps_data_q330()
def read_soh_and_index_waveform(self, folder: str):
"""
+ read waveform data for filename associate with time range
@@ -313,119 +309,3 @@ class MSeed(DataTypeModel):
f'Read {count} waveform files', LogType.INFO)
sortData(self.waveformData)
def get_gps_data_q330(self):
"""
Read LOG channel and extract GPS data stored in Q330 data set.
"""
for station in self.logData:
if station == 'TEXT':
continue
# Q330 log data is composed of a list of string, so we combine them
# into one big string for ease of processing.
log_str = functools.reduce(
operator.iconcat, self.logData[station]['LOG'], ''
)
log_lines = [line for line in log_str.splitlines() if line != '']
for idx, line in enumerate(log_lines):
if line == "GPS Status":
# We are assuming that a GPS status report is 12 lines
# long, has a specific format, and is followed by a PLL
# status report. This method call checks if these
# preconditions hold and raise an error if not.
self.check_gps_status_format_q330(log_lines[idx:idx + 13])
point = self.extract_gps_point_q330(
log_lines[idx:idx + 12]
)
self.gps_points.append(point)
def extract_gps_point_q330(self, gps_status_lines: List[str]) -> GPSPoint:
# Last timemark and fix type are always available, so we have to get
# them before doing anything else.
last_timemark = gps_status_lines[11][19:]
fix_type = gps_status_lines[3][10:]
# If location data is missing, we set them to 0.
if gps_status_lines[5] == 'Latitude: ':
return GPSPoint(last_timemark, fix_type, 0, 0, 0, 0)
num_sats_used = int(gps_status_lines[8].split(': ')[1])
# Height is encoded as a float followed by the unit. We
# don't know how many characters the unit is composed of,
# so we have to loop through the height string backward
# until we can detect the end of the height value.
height_str: str = gps_status_lines[4].split(': ')[1]
# Start pass the end of the string and look backward one
# index every iteration so we don't have to add 1 to the
# final index.
i = len(height_str)
current_char = height_str[i - 1]
while current_char != '.' and not current_char.isnumeric():
i -= 1
current_char = height_str[i - 1]
height = float(height_str[:i])
# Latitude and longitude are encoded in the format
# <degree><decimal minute><cardinal direction>. For
# latitude, <degree> has two characters, while for longitude, <degree>
# has three.
# To make the GPS points easier to plot, we convert the latitude and
# longitude to decimal degree.
raw_latitude = gps_status_lines[5].split(': ')[1]
lat_degree = int(raw_latitude[:2])
lat_minute = float(raw_latitude[2:-1]) / 60
latitude = lat_degree + lat_minute
if raw_latitude[-1].lower() == 's':
latitude = -latitude
raw_longitude = gps_status_lines[6].split(': ')[1]
long_degree = int(raw_longitude[:3])
long_minute = float(raw_longitude[3:-1]) / 60
longitude = long_degree + long_minute
if raw_longitude[-1].lower() == 'w':
longitude = -longitude
gps_point = GPSPoint(last_timemark, fix_type, num_sats_used,
latitude, longitude, height)
return gps_point
@staticmethod
def check_gps_status_format_q330(gps_status_lines: List[str]):
if gps_status_lines[12].lower() != 'pll status':
raise ValueError(
'Q330 log data is malformed. '
'PLL status does not follow GPS status.'
)
if 'fix type' not in gps_status_lines[3].lower():
raise ValueError(
'Q330 log data is malformed. '
'Fix type is not at expected position.'
)
if 'height' not in gps_status_lines[4].lower():
raise ValueError(
'Q330 log data is malformed. '
'Height is not at expected position.'
)
if 'latitude' not in gps_status_lines[5].lower():
raise ValueError(
'Q330 log data is malformed. '
'Latitude is not at expected position.'
)
if 'longitude' not in gps_status_lines[6].lower():
raise ValueError(
'Q330 log data is malformed. '
'Longitude is not at expected position.'
)
if 'sat. used' not in gps_status_lines[8].lower():
raise ValueError(
'Q330 log data is malformed. '
'Sat. Used is not at expected position.'
)
if 'last gps timemark' not in gps_status_lines[11].lower():
raise ValueError(
'Q330 log data is malformed. '
'Last GPS timemark is not at expected position.'
)
Loading