sidescanpy.processing.track#
Survey track: per-ping nadir positions plus strided port/starboard swath-edge positions, for a multi-file survey.
build_survey_track() returns a SurveyTrack of WGS84
lat/lon arrays; sidescanpy.viz.track.plot_track_and_scanlines and
sidescanpy.viz.targets.plot_track_with_targets draw it.
2026 rshomberg@uri.edu
Contents
Nadir track and scan-line endpoints for one frequency (WGS84 degrees). |
|
Nadir track + strided port/starboard scan-line endpoints for one frequency, across every file that has it, in time order. |
- class sidescanpy.processing.track.SurveyTrack(track_lat, track_lon, scan_port_lat, scan_port_lon, scan_stbd_lat, scan_stbd_lon, scan_nadir_lat=None, scan_nadir_lon=None)#
Bases:
objectNadir track and scan-line endpoints for one frequency (WGS84 degrees).
track_*arrays have one entry per ping across every file, in time order.scan_*arrays are index-aligned port/starboard swath-edge positions at everyscanline_stride-th ping of each file.scan_nadir_*is the nadir position at those same pings, where each rung splits into its port and starboard halves (None when not known).
- sidescanpy.processing.track.build_survey_track(surveys, freq_key, *, scanline_stride, heading='compass')#
Nadir track + strided port/starboard scan-line endpoints for one frequency, across every file that has it, in time order.
Cheap by design, but not by slicing the sample axis down to one sample before georeferencing — that’s tempting (we only want the farthest-range sample per ping) but wrong:
compute_geometric_rangescomputes each sample’s position from the absolutesamplecoordinate when present (processing.sample_axis. sample_index), so slicing samples is safe for datasets that carry it. For legacy datasets without that coordinate it falls back to a local index (arange(ds.sizes["sample"])): pre-slicing tosample=[-1]then makes the function see “sample 0” (point-blank range) instead of the true far-range edge — silently producing NaN via the water-column mask instead of a real position.The safe optimization instead pre-selects the strided pings (slicing the ping axis doesn’t touch
ds.sizes["sample"], so it doesn’t affect the sample-index math) while keeping each selected ping’s full sample axis intact through georeferencing, and only slices to the last sample afterward. This still avoids georeferencing every ping — just the ones actually needed for a rung — while staying correct.- Parameters:
- surveysdict[Path, SideScanSurvey]
- freq_keystr
e.g.
"hz_1495000".- scanline_strideint
Draw a scan-line rung every Nth ping.
- heading{“compass”, “course”}, default “compass”
Heading used to place the swath edges: the recorded
heading_deg, or the GPS course over ground (sidescanpy.processing.navigation.course_over_ground) for a towfish whose compass is not trusted.
- Returns:
- SurveyTrack or None
None if no file has
freq_key. Track arrays cover every ping; scan arrays cover everyscanline_stride-th ping.