sidescanpy.processing.geometric#
Geometric range computation for SideScan sonar data.
Computes per-sample geometric variables as data variables attached to the dataset. Does NOT resample backscatter — original sample positions and values are preserved. Downstream tools (xarray.interp, rioxarray, etc.) handle resampling onto regular grids on demand.
Outputs (all shape (ping, channel, sample)):
slant_range_m attitude-invariant time-of-flight range
ground_range_m sqrt(slant^2 - altitude^2), unsigned: horizontal
distance from the nadir point (flat bottom; the
same with or without pitch)
across_track_m signed Y component in the platform frame
(negative = port, positive = starboard)
along_track_m signed X component in the platform frame, the
pitch-induced offset (positive = forward of nadir)
vertical_offset_m Z component from platform = altitude_m for flat
bottom (broadcast). Future: extends to bathymetry.
depth_per_sample_m absolute water depth at sample location
= depth_m + altitude_m
- Sign conventions:
across_track_m: port channel negative, starboard positive
along_track_m: positive forward of nadir (nose up puts samples forward)
- Pitch model (flat bottom, fan beam perpendicular to the body x-axis):
With the vehicle pitched by theta (positive nose up) at vertical altitude h, the fan plane tilts forward by theta. A sample at slant range R hits the seafloor at
along_track_m = h * tan(theta) (every sample of the ping) across_track_m = ±sqrt(R^2 - (h / cos(theta))^2)
and is on the seafloor only when R > h / cos(theta); nearer samples are water column and NaN in across_track_m and along_track_m. The horizontal distance from nadir, sqrt(along^2 + across^2), equals sqrt(R^2 - h^2) = ground_range_m. Pitch therefore shifts the whole ping forward or aft by a constant and shortens the across-track distance slightly; it does not rotate the swath.
NaN pitch_deg is treated as 0 (no pitch correction) with a warning, as NaN sound velocity falls back to 1500 m/s.
Roll’s effect on altitude is intentionally not modeled here. Future work: when DVL altitude is available it’s pre-corrected; when only fathometer_reading_m is available, attitude correction is applied to derive altitude_m.
processing_history is appended with a "geometric" record.
2026 rshomberg@uri.edu
Contents
Recorded in the |
|
Attach per-sample geometric variables to the dataset. |
- sidescanpy.processing.geometric.PITCH_MODEL = 'fan_beam_flat_bottom'#
Recorded in the
geometrichistory record. Records without this key (sidescanpy 0.9.0 and earlier) were made by a model that rotated the ground vector by pitch (along = ground·sin θ), wrong for pitched pings.
- sidescanpy.processing.geometric.compute_geometric_ranges(ds, *, expose_unmasked_z=False)#
Attach per-sample geometric variables to the dataset.
- Parameters:
- dsxr.Dataset or SideScanSurvey
Validated sidescan dataset. A
SideScanSurveyis corrected frequency by frequency with the same arguments; a new survey is returned and the input is not modified.- expose_unmasked_zbool, default False
If True, vertical_offset_m and depth_per_sample_m are written as per-ping values broadcast to (ping, channel, sample) without masking the water column. The Z-axis variables become well-defined per-ping constants for every sample. The default (False) masks them with the same NaN mask as ground_range_m for consistency.
- Returns:
- xr.Dataset or SideScanSurvey
Same type as
ds: a new dataset (input not modified) with six added per-sample data variables and a"geometric"processing_history record.
Notes
- NaN handling:
NaN altitude_m for a ping → all per-sample geometry NaN for that ping (slant_range_m is unaffected; it’s altitude-independent).
NaN sound_vel_ms for a ping → falls back to 1500 m/s with warning.
NaN pitch_deg for a ping → taken as 0 with warning.
Water-column samples (slant <= altitude) → NaN in ground_range_m and (by default) vertical_offset_m and depth_per_sample_m. across_track_m and along_track_m use the pitched-fan limit slant <= altitude / cos(pitch), so on pitched pings a few samples just past the altitude have a ground range but no across/along position.