Skip to content

Commit

Permalink
Annotate logs with device names.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Diamond committed Apr 10, 2024
1 parent 5ef8c71 commit 14161c0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
44 changes: 29 additions & 15 deletions python/fusion_engine_client/analysis/pose_compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@

SolutionTypeInfo = namedtuple('SolutionTypeInfo', ['name', 'style'])

_LOG_NAMES = [
'Test',
'Reference',
]

_SOLUTION_TYPE_MAP = [{
SolutionType.Invalid: SolutionTypeInfo(name='Invalid', style={'color': 'black'}),
SolutionType.Integrate: SolutionTypeInfo(name='Integrated', style={'color': 'cyan'}),
Expand Down Expand Up @@ -122,7 +117,7 @@ def __init__(self,
file_test: Union[DataLoader, str], file_reference: Union[DataLoader, str], ignore_index: bool = False,
output_dir: str = None, prefix: str = '',
time_range: TimeRange = None, max_messages: int = None,
time_axis: str = 'relative'):
time_axis: str = 'relative', test_device_name=None, reference_device_name=None):
"""!
@brief Create an analyzer for the comparing the pose from two p1log files.
Expand All @@ -139,6 +134,8 @@ def __init__(self,
@param time_axis Specify the way in which time will be plotted:
- `absolute`, `abs` - Absolute P1 or system timestamps
- `relative`, `rel` - Elapsed time since the start of the log
@param test_device_name If set, label test data with this device name.
@param reference_device_name If set, label reference data with this device name.
"""
self.params = {
'time_range': time_range,
Expand Down Expand Up @@ -166,10 +163,22 @@ def __init__(self,
if len(self.reference_pose.p1_time) == 0:
raise ValueError('Reference log did not contain pose data.')

self.test_data_name = 'Test'
if test_device_name:
self.test_data_name += ' ' + test_device_name

self.reference_data_name = 'Reference'
if reference_device_name:
self.reference_data_name += ' ' + reference_device_name

self.data_names = [
self.test_data_name,
self.reference_data_name,
]

self.output_dir = output_dir
self.prefix = prefix


gps_time_test = self.test_pose.gps_time
valid_gps_time = gps_time_test[np.isfinite(gps_time_test)]
if len(valid_gps_time) == 0:
Expand Down Expand Up @@ -226,7 +235,7 @@ def plot_solution_type(self):
ticktext=['%s (%d)' % (e.name, e.value) for e in SolutionType],
tickvals=[e.value for e in SolutionType])

for name, pose_data in zip(_LOG_NAMES, (self.test_pose, self.reference_pose)):
for name, pose_data in zip(self.data_names, (self.test_pose, self.reference_pose)):
time = pose_data.gps_time - float(self.t0)

text = ["Time: %.3f sec (%.3f sec)" % (t, t + float(self.t0)) for t in time]
Expand Down Expand Up @@ -256,7 +265,7 @@ def plot_map(self, mapbox_token):
map_data = []

for i, pose_data in enumerate((self.test_pose, self.reference_pose)):
log_name = _LOG_NAMES[i]
log_name = self.data_names[i]

# Remove invalid solutions.
valid_idx = np.logical_and(~np.isnan(pose_data.p1_time), pose_data.solution_type != SolutionType.Invalid)
Expand Down Expand Up @@ -326,7 +335,8 @@ def _plot_pose_error(self, time, solution_type, error_enu_m, std_enu_m):

time_figure = make_subplots(rows=4, cols=1, print_grid=False, shared_xaxes=True,
subplot_titles=['3D', 'East', 'North', 'Up'])
time_figure['layout'].update(showlegend=True, modebar_add=['v1hovermode'])
time_figure['layout'].update(showlegend=True, modebar_add=['v1hovermode'],
title=f'{self.test_data_name} Vs. {self.reference_data_name}')
for i in range(4):
time_figure['layout']['xaxis%d' % (i + 1)].update(title=self.gps_time_label, showticklabels=True)
time_figure['layout']['yaxis1'].update(title="Error (m)")
Expand Down Expand Up @@ -515,13 +525,13 @@ def _set_data_summary(self):
log_b_end = log_b_p1_time[-1]

data = [[], []]
data[0].append('Test Log Start')
data[0].append(self.test_data_name + ' Log Start')
data[1].append(log_a_t0)
data[0].append('Reference Log Start')
data[0].append(self.reference_data_name + ' Log Start')
data[1].append(log_b_t0)
data[0].append('Test Log Duration')
data[0].append(self.test_data_name + ' Log Duration')
data[1].append(log_a_end - log_a_t0)
data[0].append('Reference Log Duration')
data[0].append(self.reference_data_name + ' Log Duration')
data[1].append(log_b_end - log_b_t0)
data[0].append('Matched GPS Epochs')
data[1].append(len(matched_p1_time_a))
Expand Down Expand Up @@ -550,6 +560,8 @@ def get_stats(label, values):
error_table = _data_to_table(columns, data, row_major=True, round_decimal_places=2)

self.summary += f"""
<h1>Comparison of {self.test_data_name} to {self.reference_data_name}</h1>
{time_table}
<h1>Solution Type CDF</h1>
Expand Down Expand Up @@ -736,6 +748,8 @@ def main():
"- The path to a FusionEngine log directory\n"
"- A pattern matching a FusionEngine log directory under the specified base directory "
"(see find_fusion_engine_log() and --log-base-dir)")
log_group.add_argument('--reference-device-name', default=None, help='Label to apply to reference data.')
log_group.add_argument('--test-device-name', default=None, help='Label to apply to test data.')

output_group = parser.add_argument_group('Output Control')
output_group.add_argument(
Expand Down Expand Up @@ -800,7 +814,7 @@ def main():
# Read pose data from the file.
analyzer = PoseCompare(file_test=input_path_test, file_reference=input_path_reference, output_dir=output_dir, ignore_index=options.ignore_index,
prefix=options.prefix + '.' if options.prefix is not None else '',
time_range=time_range, time_axis=options.time_axis)
time_range=time_range, time_axis=options.time_axis, test_device_name=options.test_device_name, reference_device_name=options.reference_device_name)

if not options.skip_plots:
analyzer.plot_solution_type()
Expand Down
26 changes: 19 additions & 7 deletions python/fusion_engine_client/applications/p1_drive_analysis.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3

import glob
import io
import sys
import os
Expand Down Expand Up @@ -52,6 +53,10 @@ def find_logs(prefix, log_guids) -> Dict[str, str]:
return resp


def get_device_name_from_path(log_path: Path) -> str:
return '_'.join(log_path.name.split('_')[1:-1])


def main():
parser = ArgumentParser(description="""\
Run p1_pose_compare for each device included in a drive test.
Expand Down Expand Up @@ -98,7 +103,8 @@ def main():
meta_key = options.key_for_log_in_drive + '/' + META_FILE
drive_meta_data = download_to_memory(options.key_for_log_in_drive + '/' + META_FILE)
except:
_logger.error(f'Could not find "S3://{S3_DEFAULT_INGEST_BUCKET}/{meta_key}". Make sure this log was taken as part of a drive test collection.')
_logger.error(
f'Could not find "S3://{S3_DEFAULT_INGEST_BUCKET}/{meta_key}". Make sure this log was taken as part of a drive test collection.')
exit(1)

drive_meta = json.loads(drive_meta_data.decode('utf-8'))
Expand All @@ -112,11 +118,12 @@ def main():
logs_to_download = []
log_paths = {}
for guid in [reference_guid] + test_guids:
log_paths[guid] = LOG_DIR / f'{guid}.p1log'
if not log_paths[guid].exists():
logs_to_download.append(guid)
else:
matches = glob.glob(str(LOG_DIR / f'*{guid}.p1log'))
if len(matches) > 0:
log_paths[guid] = Path(matches[0])
_logger.info(f'Using cached: {log_paths[guid]}')
else:
logs_to_download.append(guid)

if len(logs_to_download) > 0:
log_prefixes = find_logs(prefix, logs_to_download)
Expand All @@ -131,6 +138,8 @@ def main():
exit(1)

for guid, s3_prefix in log_prefixes.items():
file_name = s3_prefix.replace('/', '_') + '.p1log'
log_paths[guid] = LOG_DIR / file_name
_logger.info(f'Downloading: {log_paths[guid]}')
if reference_guid == guid:
reference_p1log_key = s3_prefix + '/' + REFERENCE_LOG_FILE
Expand All @@ -139,9 +148,12 @@ def main():

s3_client.download_file(S3_DEFAULT_INGEST_BUCKET, reference_p1log_key, log_paths[guid])

reference_device = get_device_name_from_path(log_paths[reference_guid])
for guid in test_guids:
_logger.info(f'Comparing log: {guid}')
sys.argv = ['pose_compare_main', str(log_paths[guid]), str(log_paths[reference_guid]), '--time-axis=rel']
_logger.info(f'Comparing log: {log_paths[guid]}')
test_device = get_device_name_from_path(log_paths[guid])
sys.argv = ['pose_compare_main', str(log_paths[guid]), str(
log_paths[reference_guid]), '--time-axis=rel', f'--test-device-name={test_device}', f'--reference-device-name={reference_device}']
try:
pose_compare_main()
except Exception as e:
Expand Down

0 comments on commit 14161c0

Please sign in to comment.