sidescanpy.processing.segments#
Survey segmentation: find clean, homogeneous ping ranges in one channel.
Aggregate analysis over a ping range that silently mixes a gap, a setting change, a dropout or a turn transient gives misleading numbers. These detectors find such stretches so they can be cut out first.
detect_gaps()— along-track distance or ping-time jumps.detect_setting_changes()—valid_samplesor sound-velocity steps.detect_garbage_runs()— sustained runs of all-NaN/zero pings.detect_unstable_spans()— altitude/pitch instability windows (scored byscore_stability()).
find_segments() combines them into Segment objects
labelled "clean" or "excluded" with the reasons that fired.
split_by_segments() slices a survey into one sub-survey per clean
segment; write_segments() writes each to its own .ss.h5.
Contents
One |
|
Per-ping boundary flags: |
|
Per-ping boundary flags for a likely acquisition-setting change. |
|
|
|
Stability score of |
|
|
|
Split |
|
One sub-survey per |
|
Write |
- class sidescanpy.processing.segments.Segment(label, start, stop, status, reasons=<factory>)#
Bases:
objectOne
[start, stop)ping range with its status and the reasons for it.- to_dict()#
JSON-serializable dict.
- sidescanpy.processing.segments.detect_gaps(ds, *, gap_factor=8.0, time_gap_factor=8.0)#
Per-ping boundary flags:
Trueatimarks a break between pingsi-1andi.Fires when the along-track step exceeds
gap_factortimes the median nonzero step, or the ping-time step exceedstime_gap_factortimes the median nonzero interval. Either signal alone can show a real discontinuity. Index 0 is never flagged.
- sidescanpy.processing.segments.detect_setting_changes(ds, *, sound_vel_rel_tol=0.05)#
Per-ping boundary flags for a likely acquisition-setting change.
Fires on any change in
valid_samples(when present) or a relative step insound_vel_mslarger thansound_vel_rel_tol. A sample-count change that the converter already padded away without recordingvalid_samplescan’t be detected here.
- sidescanpy.processing.segments.detect_garbage_runs(ds, value_var='backscatter_intensity', *, min_run_pings=20, degenerate_frac=0.999)#
[(start, stop), ...]runs of at leastmin_run_pingsdegenerate pings.A ping is degenerate when at least
degenerate_fracof its values (all channels and samples) are NaN or exactly zero — a mid-survey dropout, not the per-ping leading nadir blanking.
- sidescanpy.processing.segments.score_stability(altitude, pitch, start, span)#
Stability score of
[start, start + span); lower is calmer.Altitude coefficient of variation plus pitch standard deviation (degrees), weighted 1:1. A calm stretch scores a few hundredths to tenths; a turn or deployment transient scores one to two orders of magnitude higher.
infwith fewer than two finite values.
- sidescanpy.processing.segments.detect_unstable_spans(ds, *, window_pings=100, stability_threshold=1.0, min_run_pings=50)#
[(start, stop), ...]unstable stretches from altitude and pitch.Non-overlapping
window_pingswindows scoring abovestability_threshold(score_stability()) are unstable; adjacent ones merge, and a merged span shorter thanmin_run_pingsis dropped as noise. The default threshold is a coarse starting point, not a validated value. Empty withoutaltitude_mandpitch_deg.
- sidescanpy.processing.segments.find_segments(ds, *, gap_factor=8.0, time_gap_factor=8.0, sound_vel_rel_tol=0.05, garbage_value_var='backscatter_intensity', garbage_min_run_pings=20, garbage_degenerate_frac=0.999, stability_window_pings=100, stability_threshold=1.0, stability_min_run_pings=50, min_segment_pings=200)#
Split
[0, n_pings)into contiguousSegmentobjects.Gap and setting-change flags become boundaries; garbage and unstable spans become
"excluded"segments. Each segment’sreasonsnames every signal that fired inside it (["clean"]if none).Status is resolved per raw interval before merging. Only a clean interval shorter than
min_segment_pingsis merged, and only into a preceding clean neighbour, so a short excluded span never taints clean pings. A short clean interval with no clean neighbour is kept as is.
- sidescanpy.processing.segments.split_by_segments(survey, segments)#
One sub-survey per
"clean"segment, keyed by segment label.Every frequency channel is sliced to the segment’s ping range with
slice_by_pings(); all channels are assumed to share one ping axis. Excluded segments are skipped.
- sidescanpy.processing.segments.write_segments(survey, segments, output_dir)#
Write
<label>.ss.h5intooutput_dirfor every clean segment.Uses
split_by_segments(); existing files are overwritten. Returns the paths written, in segment order.