sidescanpy.processing.navigation#
Navigation-derived ping geometry: along-track distance and nav-stall repair.
along_track_distance_m()– cumulative along-track distance (m) from per-ping latitude/longitude, optionally with short navigation stalls filled.fill_nav_stalls()– replace short runs of stalled position steps with the local median ping step.course_over_ground()– per-ping course (degrees true) from the positions a few seconds before and after each ping, for use as the heading when a towfish compass is unreliable.smooth_navigation()– running mean of the per-ping positions over a time window, for recorders whose positions carry a periodic error between fixes.
Pure array/dataset functions; no plotting.
2026 rshomberg@uri.edu
Contents
Cumulative along-track distance (meters) from per-ping lat/lon. |
|
Replace short navigation stalls with the local median ping step. |
|
Per-ping course over ground, degrees true (compass bearing, [0, 360)). |
|
History step name written by |
|
Replace per-ping positions with their running mean over |
- sidescanpy.processing.navigation.along_track_distance_m(ds, *, fill_nav_stalls=False)#
Cumulative along-track distance (meters) from per-ping lat/lon.
Public wrapper around the same computation used internally for
y_axis="along_track"— exposed for callers (e.g. distance-based segmentation) that need the coordinate array without going throughplot_waterfall.fill_nav_stalls: navigation can stall – several consecutive pings keep (nearly) the same position while the vessel keeps moving, and it resumes without catching up. The raw distance is then flat across those pings, and geometric resampling stacks their seafloor into a single along-track line (seen on one real survey: ~7 pings at each checked target, 42ms apart with distinct data, advanced only ~0.07m in total instead of ~0.5m – a hard seam through the target at fine resolution). WithTrue, each stalled step is replaced by the local median step (seefill_nav_stalls). Off by default so gap/stationarity detection still sees the raw navigation.
- sidescanpy.processing.navigation.fill_nav_stalls(along, *, stall_fraction=0.5, max_stall_pings=20, window_pings=25)#
Replace short navigation stalls with the local median ping step.
A step is stalled when it is below
stall_fractionof the median step withinwindow_pingseither side. Only runs of at mostmax_stall_pingsstalled steps with moving steps on both sides are filled – a longer run, or one at the window edge, is treated as the vessel really stopping and left as is.
- sidescanpy.processing.navigation.course_over_ground(ds, *, half_window_s=4.0)#
Per-ping course over ground, degrees true (compass bearing, [0, 360)).
The bearing from the ping’s position
half_window_searlier to its positionhalf_window_slater (WGS84 geodesic), taken from the per-pinglatitude/longitudeandtime. Near the ends of the dataset the window is cut short. Pings without a finite position, or whose window has no movement, get the course interpolated from their neighbours (on the unwrapped angle, so no jump at north).Use it in place of
heading_degwhen the towfish compass is not trusted, e.g. a heading-dependent compass deviation that shears the georeferenced swath. It assumes the towfish follows the vessel track (no crab angle), and it lags in tight turns by abouthalf_window_s.- Parameters:
- dsxr.Dataset
Frequency-channel dataset with per-ping
time,latitudeandlongitude, pings in time order.- half_window_sfloat, default 4.0
Half the time window over which the course is measured. Longer smooths GPS noise; shorter follows turns more closely.
- Returns:
- np.ndarray
Course in degrees, one per ping; all NaN when fewer than two pings have distinct finite positions.
- sidescanpy.processing.navigation.STEP_SMOOTH_NAVIGATION = 'smooth_navigation'#
History step name written by
smooth_navigation().
- sidescanpy.processing.navigation.smooth_navigation(ds, *, window_s=5.0)#
Replace per-ping positions with their running mean over
window_s.Each ping’s
latitudeandlongitudecome from a straight-line fit (least squares, against time) to the finite positions withinwindow_s / 2of its time; with evenly spaced pings that is their mean. The fit rather than the mean keeps pings next to missing positions unbiased. Near the ends of the dataset the window shrinks symmetrically, so the first and last pings keep their positions. A straight track at constant speed is unchanged (no lag).For positions that change at every entry but carry an error between GPS fixes, which interpolating between fixes cannot remove. Some recorders run the position ahead of each fix and jump back when the next one arrives: a sawtooth along track with the fix period. A window spanning a whole number of fix periods removes it (and leaves a constant along-track offset of about half its amplitude). Check the track first (
aux_update_events(), and the residual from a straight line); on sample-and-hold navigation, interpolate between fixes instead (interpolate_aux_onto_pings()).The mean is taken in degrees, which is accurate for windows of seconds to minutes; turns tighter than the distance covered in
window_sare cut short. Heading is not changed: derive it from the smoothed track withcourse_over_ground()if the compass is not used.- Parameters:
- dsxr.Dataset or SideScanSurvey
Frequency channel dataset with per-ping
time,latitudeandlongitude, pings in time order. ASideScanSurveyis smoothed frequency by frequency; a new survey is returned.- window_sfloat, default 5.0
Width of the time window (s), centred on each ping.
- Returns:
- xr.Dataset or SideScanSurvey
Same type as
ds: a new dataset with float64latitudeandlongitudeand asmooth_navigationhistory record. Pings without a finite position keep NaN.
- Raises:
- ValueError
If
window_sis not positive, orgeorefwas already applied (its per-sample positions would go stale; invert it first).