sidescanpy.io.sdf.converter#
Convert Klein SDF pages into a SideScanSurvey.
The converter takes pages (typically from read_sdf or read_sdf_iter) and builds a validated SideScanSurvey with:
One SideScanFrequencyChannel per distinct center_freq_hz
Per-ping fields (latitude, longitude, heading, pitch, roll, depth, altitude, fathometer_reading) extracted from each page’s header
Navigation aux record from per-page (timestamp, lat, lon)
Attitude aux record from per-page (timestamp, heading, pitch, roll)
Empty DVL record (Klein doesn’t have DVL)
No sensor records (Klein doesn’t have ancillary sensor streams)
cable_out_mper ping from field 50. SDF has no layback distance, so nolayback_m.position_sourceistowfishwhere the computed fish position (fields 39/40) is set and used forlatitude/longitude,shipwhere the reader fell back to the ship position (fields 37/38),mixedif both occur. The layback-computed fish position (fields 71/72) is not used.sdf_layback_methodrecords field 70 (0 Pythagorean, 1 hull mount). Not checked on a real file with a non-zero cable out.
The reader yields both SDFSonarPage (sonar versions 3501/3502) and SDFUnknownPage (everything else). The converter filters to sonar pages only with an info log; non-sonar pages are dropped silently.
Klein-specific design decisions:
depth_m is set to NaN. The spec stores depth in Volts (field 31), and conversion to meters requires calibration data from the INI file that we don’t currently parse. Users with calibration can override.
sound_vel_ms per ping is NaN (Klein doesn’t provide sound velocity).
heave_m per ping is NaN (Klein doesn’t provide heave).
altitude_m is currently a copy of fathometer_reading_m (no attitude correction yet).
sample_rate_hz is computed from the first page’s (num_samples, range_m) assuming 1500 m/s sound velocity.
pulse_length_us is 0.0 (not provided by Klein).
freq_hz_start == freq_hz_end == center_freq_hz.
Pages with different num_samples are padded to max with NaN, logged as a warning when it happens. Each ping’s true recorded sample count survives padding via the
valid_samples(ping, channel) variable, so downstream code (e.g.processing/farrange.py) can distinguish real short pings from padded filler rather than treating the padded array shape as if every ping genuinely recorded that many samples.convert()builds one array per call across every page it’s handed. Current callers (io/dispatch.py: read_and_convert()) invoke it once per source file (01_convert.pycallsread_and_convert([single_path], ...)in a loop), so in practice padding is currently scoped to pages within one physical.sdffile.read_and_convert()’s own multi-file-merge capability would pad across files too if a caller ever used it that way — worth knowing before doing so, not a hidden trap given the warning above, but a single outlier-length page anywhere in whatever set of pages reaches this function does inflate every other page’s stored array.
2026 rshomberg@uri.edu
Contents
Convert SDF pages into a validated SideScanSurvey. |
- sidescanpy.io.sdf.converter.convert(pages, *, source_files=None, survey_name=None)#
Convert SDF pages into a validated SideScanSurvey.
Pages can include both SDFSonarPage and SDFUnknownPage (as yielded by read_sdf). Non-sonar pages are filtered out with a debug log.
- Parameters:
- pagesIterable
SDF pages from read_sdf or read_sdf_iter.
- source_fileslist[Path], optional
Paths to the source SDF files.
- survey_namestr, optional
Survey name. Defaults to first source file’s stem.
- Returns:
- SideScanSurvey
Validated survey with one or more frequency channels and aux records.
- Raises:
- ValueError
If
pagescontains no sonar pages.