Source code for suboptimumg.log_analysis.preprocess_gps

import numpy as np
from perda.core_data_structures import (
    DataInstance,
    SingleRunData,
    left_join_data_instances,
)
from perda.plotting.plotting_constants import GpsMapConfig
from perda.utils import filter_gps_cartesian, gps_to_enu

GPS_LATITUDE = "latitudeFiltered"
GPS_LONGITUDE = "longitudeFiltered"
POS_X = "posX"
POS_Y = "posY"


[docs] def preprocess_gps_data_instances( data: SingleRunData, ins_lat_col: str = "pcm.vnav.posLla.latitude", ins_lon_col: str = "pcm.vnav.posLla.longitude", fix_col: str | None = "pcm.vnav.gpsFix", ) -> SingleRunData: """Extract GPS position DataInstances and inject them into SingleRunData. Filters invalid samples (no GPS fix, zero lat/lon pairs), projects to local East/North Cartesian coordinates, and stores the results as ``gps.latitude``, ``gps.longitude``, ``posE``, and ``posN`` in ``data``. Parameters ---------- data : SingleRunData ins_lat_col : str Key for the INS latitude signal. ins_lon_col : str Key for the INS longitude signal. fix_col : str or None Key for the GPS fix-status signal. ``None`` skips the fix check. Returns ------- SingleRunData The same ``data`` object with ``gps.latitude``, ``gps.longitude``, ``posN``, and ``posE`` added. """ lat_di = data[ins_lat_col] lon_di = data[ins_lon_col] # Join lon (and optionally fix) onto the lat timestamp grid deps = [lon_di] if fix_col is not None and fix_col in data: deps.append(data[fix_col]) joined = left_join_data_instances(lat_di, deps) lat_di_aligned = joined[0] lon_di_aligned = joined[1] # Filter invalid samples: zero pairs, out-of-physical-range, or non-finite valid = ( np.isfinite(lat_di_aligned.value_np) & np.isfinite(lon_di_aligned.value_np) & ~((lat_di_aligned.value_np == 0.0) & (lon_di_aligned.value_np == 0.0)) & (np.abs(lat_di_aligned.value_np) <= 90.0) & (np.abs(lon_di_aligned.value_np) <= 180.0) ) if fix_col is not None and fix_col in data: fix_di_aligned = joined[2] valid = valid & (fix_di_aligned.value_np != 0.0) lat_filtered = lat_di_aligned.value_np[valid].copy() lon_filtered = lon_di_aligned.value_np[valid].copy() ts_filtered = lat_di_aligned.timestamp_np[valid].copy() valid_pts = filter_gps_cartesian( lat_filtered, lon_filtered, GpsMapConfig(max_radius_m=1500.0, max_jump_m=30.0) ) lat_filtered = lat_filtered[valid_pts] lon_filtered = lon_filtered[valid_pts] ts_filtered = ts_filtered[valid_pts] x_m, y_m = gps_to_enu(lat_filtered, lon_filtered) data[GPS_LATITUDE] = DataInstance( timestamp_np=ts_filtered, value_np=lat_filtered, label="GPS Latitude (deg)", cpp_name=GPS_LATITUDE, ) data[GPS_LONGITUDE] = DataInstance( timestamp_np=ts_filtered, value_np=lon_filtered, label="GPS Longitude (deg)", cpp_name=GPS_LONGITUDE, ) data[POS_X] = DataInstance( timestamp_np=ts_filtered, value_np=x_m, label="X-axis/East Position (m)", cpp_name=POS_X, ) data[POS_Y] = DataInstance( timestamp_np=ts_filtered, value_np=y_m, label="Y-axis/North Position (m)", cpp_name=POS_Y, ) return data