Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions python/examples/binary_message_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
if __name__ == "__main__":
parser = ArgumentParser(description="""\
Decode and print the contents of one or more FusionEngine messages contained
in a binary string. For example:
in a binary string or file. For example:

> python3 binary_message_decode.py \\
2e31 0000 0acf ee8f 0200 ca32 0000 0000 0400 0000 0000 0000 ff0f 0001
Expand All @@ -31,12 +31,16 @@
Source: 0
CRC: 0x8feecf0a
Payload: Reset Request [mask=0x01000fff]

or

> python3 binary_message_decode.py my_file.p1log
""")
parser.add_argument('-v', '--verbose', action='count', default=0,
help="Print verbose/trace debugging messages.")
parser.add_argument('contents', nargs='+',
help="Binary FusionEngine message contents, specified as a hex string. All spaces will be "
"ignored.")
help="Binary FusionEngine message contents, specified as a hex string, or the path to a binary "
"file to be read. All spaces in the hex string will be ignored.")
options = parser.parse_args()

# Configure logging.
Expand All @@ -54,13 +58,17 @@
logger = logging.getLogger('point_one.fusion_engine')

# Concatenate all hex characters and convert to bytes.
byte_str_array = [b if len(b) % 2 == 0 else f'0{b}' for b in options.contents]
contents_str = ''.join(byte_str_array).replace(' ', '')
if len(contents_str) % 2 != 0:
logger.error("Error: Contents must contain an even number of hex characters.")
sys.exit(1)
if len(options.contents) == 1 and os.path.exists(options.contents[0]):
with open(options.contents[0], 'rb') as f:
contents = f.read()
else:
byte_str_array = [b if len(b) % 2 == 0 else f'0{b}' for b in options.contents]
contents_str = ''.join(byte_str_array).replace(' ', '')
if len(contents_str) % 2 != 0:
logger.error("Error: Contents must contain an even number of hex characters.")
sys.exit(1)

contents = bytes.fromhex(contents_str)
contents = bytes.fromhex(contents_str)

# Decode the incoming data and print the contents of any complete messages.
decoder = FusionEngineDecoder(warn_on_error=FusionEngineDecoder.WarnOnError.ALL, warn_on_unrecognized=True)
Expand Down
32 changes: 23 additions & 9 deletions python/fusion_engine_client/analysis/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,16 +867,16 @@ def plot_stationary_position_error(self, truth_lla_deg):
@param truth_lla_deg The truth LLA location (in degrees/meters).
"""
truth_ecef_m = np.array(geodetic2ecef(*truth_lla_deg, deg=True))
return self._plot_pose_displacement(title='Position Error', center_ecef_m=truth_ecef_m)
return self._plot_pose_displacement(title='Position Error', reference=truth_ecef_m)

def plot_pose_displacement(self):
"""!
@brief Generate a topocentric (top-down) plot of position displacement, as well as plot of displacement over
time.
@brief Generate a topocentric (top-down) plot of position displacement vs the median position, as well as plot
of displacement over time.
"""
return self._plot_pose_displacement()
return self._plot_pose_displacement(reference='median')

def _plot_pose_displacement(self, title='Pose Displacement', center_ecef_m=None):
def _plot_pose_displacement(self, title='Pose Displacement', reference=None):
if self.output_dir is None:
return None

Expand All @@ -903,16 +903,30 @@ def _plot_pose_displacement(self, title='Pose Displacement', center_ecef_m=None)
# case there are one or two huge outliers).
position_ecef_m = np.array(geodetic2ecef(lat=lla_deg[0, :], lon=lla_deg[1, :], alt=lla_deg[2, :], deg=True))

if center_ecef_m is None:
center_ecef_m = np.median(position_ecef_m, axis=1)
if reference is None:
reference = 'median'

if isinstance(reference, str):
if reference == 'first':
reference_ecef_m = position_ecef_m[:, 0]
title_suffix = ' From First Position'
elif reference == 'median':
reference_ecef_m = position_ecef_m[:, 0]
title_suffix = ' From Median Position'
else:
raise ValueError('Unrecognized reference specifier.')
else:
reference_ecef_m = reference
title_suffix = ''

displacement_ecef_m = position_ecef_m - center_ecef_m.reshape(3, 1)
displacement_ecef_m = position_ecef_m - reference_ecef_m.reshape(3, 1)
c_enu_ecef = get_enu_rotation_matrix(*lla_deg[0:2, 0], deg=True)
displacement_enu_m = c_enu_ecef.dot(displacement_ecef_m)

axis_title = 'Error' if title == 'Position Error' else 'Displacement'

self._plot_displacement(source=title, title=axis_title, time=time, solution_type=solution_type,
self._plot_displacement(source=f'{title}{title_suffix}', title=axis_title,
time=time, solution_type=solution_type,
displacement_enu_m=displacement_enu_m, std_enu_m=std_enu_m)

return displacement_enu_m
Expand Down