Building a processing workflow#
sidescanpy is a library: it converts, corrects, grids and exports, but it
does not decide what your survey needs. That decision is made by looking
at the data, so the workflow lives in your own project, as scripts or
notebooks that call the library. This page describes the layout the
template in
examples/project_template/
implements: one script per step, one config per survey, and a report
after each step.
One script per step#
01_convert.py raw .jsf/.sdf/.xtf -> .ss.h5, target catalog -> targets.json
02_analyze.py measure the uncorrected data (TVG model fit and check)
03_correct.py apply the corrections chosen from step 2
04_export.py waterfalls, track, grids, GeoTIFF
05_dataset.py COCO/YOLO training dataset
Run them one at a time. Several steps take a long time on real data, and each one’s output decides the next one’s settings: the decay fit in step 2 tells you which TVG terms to apply in step 3; the corrected overview from step 3 tells you whether the export settings in step 4 make sense. Check each report before starting the next step.
Each step:
reads the same survey config (
config.yaml);writes its outputs under one output root, in its own folder;
writes QA figures next to them;
writes a report (
reports/<step>.mdand.json) with the numbers it measured, the figures to look at, anything that needs checking, and the command for the next step;logs to the console and to
logs/<step>_<timestamp>.log.
One config per survey#
Everything survey-specific lives in one YAML file: input and output paths, the frequencies to process, the TVG recipe, export settings and the dataset spec. A second survey gets its own copy, and nothing in the scripts changes.
correct:
steps: [tvg, geometric, georef]
chunk_pings: 2000
params:
tvg: {spreading_loss_db: 30.0}
frequency_params: # per-frequency overrides
hz_1495000: {tvg: {absorption_db_per_m: 0.2}}
hz_547500: {tvg: {absorption_db_per_m: 0.1}}
dataset: # a DatasetSpec; unknown keys are an error
styles: [chip, dual-swath]
render_level: geometric
size_px: 300
Recipes do not transfer between surveys, even from the same sonar. Run the analysis step on every new survey and check its report before correcting.
What the library gives each step#
Step |
Library calls |
|---|---|
convert |
|
analyze |
|
correct |
|
export |
|
dataset |
|
Iterating#
Corrections are recorded in each file’s processing_history and skipped
when already applied, so re-running step 3 only does what is missing. To
change a recipe, re-correct with force=True: radiometric steps are
inverted from their recorded parameters first, so new parameters replace
the old ones instead of stacking. processing.invert(ds) gives the
uncorrected signal back at any time; no raw copy is stored.
For work the steps don’t cover (cutting out a bad stretch, a different nadir mask, your own gain curve), pass your own function as a step:
from sidescanpy.processing import Step, correct
def drop_near_range(ds, max_sample=50):
return ds.isel(sample=slice(max_sample, None))
ds = correct(ds, [Step("drop_near_range", drop_near_range), "tvg"],
params={"drop_near_range": {"max_sample": 80}})
It is recorded in history like a built-in step.
Notebooks#
The same calls work interactively. Use a notebook to try recipes on one line, then put the recipe in the config and run the step scripts over the whole survey.