sidescanpy.analysis.tvg_fit#

TVG model fit: which spreading and absorption law the data still carries.

  • fit_tvg_models() — fit fixed TVG models (no TVG, absorption only, 20/30/40 log R, each with and without absorption) and a free spreading coefficient to the median level of raw data, over a window from past the profile peak to the noise knee (TVGFitResult).

  • check_tvg() — apply a TVG recipe to the data and measure how flat the corrected median level is over a window (TVGCheckResult).

The model is the sonar equation’s range dependence, L(R) = L0 - n log10 R - 2 alpha R, with the constant L0 (source level, gain and seabed strength together) fitted by least squares. The best model is the TVG to apply: its n and alpha are the spreading_loss_db and absorption_db_per_m of apply_tvg().

Contents

tvg_model_name

Display name of a TVG model: "flat", "absorption only", "30 log R", "30 log R + abs", ...

TVGModelFit

One fixed TVG model fitted to the median level.

TVGSideFit

The model fit of one side alone, over the pooled fit window.

TVGFitResult

TVG models fitted to the median level of raw data.

TVGCheckResult

How flat the median level is after a TVG recipe.

fit_tvg_models

Fit TVG models to the median level of raw backscatter.

check_tvg

Apply a TVG recipe and measure how flat the median level is.

sidescanpy.analysis.tvg_fit.tvg_model_name(spreading_loss_db, with_absorption)#

Display name of a TVG model: "flat", "absorption only", "30 log R", "30 log R + abs", …

class sidescanpy.analysis.tvg_fit.TVGModelFit(name, spreading_loss_db, absorption_db_per_m, offset_db, rms_db)#

Bases:

One fixed TVG model fitted to the median level.

The model level is offset_db - spreading_loss_db * log10(R) - 2 * absorption_db_per_m * R; offset_db is the least-squares constant and rms_db the RMS residual over the fit window. absorption_db_per_m is 0 for a model without absorption.

level_db(range_m)#

Model level (dB) at range_m.

class sidescanpy.analysis.tvg_fit.TVGSideFit(side, best=None, rms_db=None, free_n=None, pooled_best_rms_db=None, offset_db=None)#

Bases:

The model fit of one side alone, over the pooled fit window.

best and rms_db are that side’s best model; free_n its free spreading coefficient (with absorption); pooled_best_rms_db the RMS of the pooled best model’s shape on this side (constant refitted); offset_db the side’s median level minus the pooled median level, averaged over the window.

class sidescanpy.analysis.tvg_fit.TVGFitResult(range_m=None, level_db=None, level_db_sides=None, bin_width_m=None, window_m=None, window_source=None, n_bins=0, peak_m=None, knee_m=None, knee_found=False, contrast_db=None, low_contrast=False, rises_at_far_range=False, start_margin_m=None, knee_db=None, altitude_m=None, models=<factory>, best=None, runner_up=None, free_n=None, free_n_rms_db=None, free_n_no_absorption=None, free_n_no_absorption_rms_db=None, side_best=<factory>, sides_disagree=False, absorption_db_per_m=None, freq_hz=None, dithered=False, value_var=None, range_var=None, channel=None, notes=<factory>)#

Bases:

TVG models fitted to the median level of raw data.

Profile: range_m (bin centers), level_db (both sides pooled, or the requested channel) and level_db_sides (port, starboard), the median of linear amplitude in dB re 1 recorded unit.

Window: window_m is (start, end); window_source is "knee" (peak plus start_margin_m to the noise knee), "end_of_record" (no knee found, fit to the end) or "given". peak_m, knee_m, knee_found, contrast_db, low_contrast and rises_at_far_range come from find_noise_knee().

Models: models maps each name to its TVGModelFit; best and runner_up are names, ranked by RMS in the window. free_n is the least-squares spreading coefficient with absorption (free_n_rms_db its RMS), free_n_no_absorption the same without. side_best holds each side’s fit (TVGSideFit) and sides_disagree flags sides whose levels or shapes differ.

Use: tvg_params is the best model as TVGParams (the TVG to apply); tvg_status names what the recorder has already removed ("none", "spreading_only", "absorption_only", "full"), derived from the best model. Both are None without a fit, and both are included in to_dict().

property best_model#

The best TVGModelFit, or None.

property runner_up_model#

The runner-up TVGModelFit, or None.

property tvg_params#

The best model as TVGParams (absorption 0 when it has none).

property tvg_status#

What the recorder has already removed, derived from the best model.

to_dict()#

JSON-serializable dict of the fields plus tvg_params and tvg_status.

class sidescanpy.analysis.tvg_fit.TVGCheckResult(range_m=None, level_db=None, window_m=None, crop_m=None, spread_db=None, trend_db_per_10m=None, end_to_end_db=None, window_mean_db=None, n_bins=0, params=<factory>, notes=<factory>)#

Bases:

How flat the median level is after a TVG recipe.

level_db is the median level per bin (range_m) after apply_tvg(), on data cropped at crop_m. Over window_m: spread_db is its standard deviation, trend_db_per_10m the slope of a straight-line fit and end_to_end_db last bin minus first. window_mean_db is its mean there (relative_db subtracts it). params holds the spreading_loss_db and absorption_db_per_m applied.

property relative_db#

level_db minus its mean over the window.

property model_name#

Display name of the applied recipe (see tvg_model_name()).

sidescanpy.analysis.tvg_fit.fit_tvg_models(ds, value_var='backscatter_intensity', range_var='slant_range_m', *, bin_width_m=1.0, start_margin_m=5.0, knee_db=3.0, window_m=None, min_window_m=8.0, low_contrast_db=6.0, spreading=(0.0, 20.0, 30.0, 40.0), absorption=(False, True), absorption_db_per_m=None, freq_hz=None, channel=None, dither='auto', seed=0, min_count=50, min_bins=3, side_difference_db=15.0, side_rms_tol_db=1.0, altitude_factor=2.5)#

Fit TVG models to the median level of raw backscatter.

  1. Profile: the median of linear amplitude in bin_width_m bins of range_var, past the median altitude (or, without altitude_m, outside the water column), both sides pooled (or channel), in dB re 1 (median_level_profile(); integer samples are dithered first).

  2. Window: from start_margin_m past the profile peak (searched in the near half of the range) to the noise knee, the first range within knee_db of the lowest level (find_noise_knee()). When no knee leaves min_window_m, the window runs to the end of the record, with a note; window_m overrides both ends.

  3. Models: every combination of spreading (n log R, 0 = none) and absorption (Francois-Garrison at the channel’s center frequency, or absorption_db_per_m), each with a least-squares constant, ranked by RMS residual in the window. A free n is fitted with and without absorption.

  4. Each side is fitted alone on the same window; sides_disagree is set (WARNING) when the two sides’ mean levels differ by more than side_difference_db, or the pooled best model’s shape fits a side side_rms_tol_db worse than that side’s own best.

A good fit is a hypothesis: confirm it with check_tvg() on the same window. Over short windows (under ~20 m) 20 log R with absorption, 30 log R and 40 log R differ by tenths of a dB; read free_n and the runner-up before trusting the label.

Parameters:
dsxr.Dataset

One channel with range_var (see compute_geometric_ranges()), value_var in linear amplitude and no radiometric step applied (undo one with invert()). ground_range_m, when present, marks the water column.

value_varstr, default “backscatter_intensity”
range_varstr, default “slant_range_m”

Slant range matches apply_tvg’s gain.

bin_width_mfloat, default 1.0
start_margin_mfloat, default 5.0
knee_dbfloat, default 3.0
window_m(float, float), optional

Fit window (start, end) in m instead of the automatic one.

min_window_mfloat, default 8.0
low_contrast_dbfloat, default 6.0

Peak-to-floor contrast below which low_contrast is set.

spreadingtuple of float, default (0, 20, 30, 40)
absorptiontuple of bool, default (False, True)
absorption_db_per_mfloat, optional

Absorption of the models with absorption. Default: Francois-Garrison at freq_hz.

freq_hzfloat, optional

Default: the channel’s center frequency.

channelint or str, optional

Fit one side (index or channel_id) instead of both pooled.

ditherbool or “auto”, default “auto”
seedint, default 0
min_countint, default 50

Samples a bin needs for a level.

min_binsint, default 3

Bins the window needs for a fit.

side_difference_dbfloat, default 15.0
side_rms_tol_dbfloat, default 1.0

Thresholds of sides_disagree.

altitude_factorfloat, default 2.5

A WARNING is logged when the profile peak lies beyond altitude_factor * altitude + 5 m or the profile starts more than 5 m past the altitude.

Returns:
TVGFitResult
Raises:
ValueError

If range_var is missing or a radiometric step (TVG, range correction) is already applied.

sidescanpy.analysis.tvg_fit.check_tvg(ds, tvg_params, window_m, value_var='backscatter_intensity', range_var='slant_range_m', *, crop_m=None, bin_width_m=1.0, channel=None, dither='auto', seed=0, min_count=50)#

Apply a TVG recipe and measure how flat the median level is.

The data are cropped at crop_m (default: the window’s far end; beyond it TVG only amplifies noise) with slice_by_range(), corrected with apply_tvg(), and binned like fit_tvg_models() (median of linear amplitude, dB). If the recipe is right the corrected level is flat across the window: spread_db near the fit’s RMS and trend_db_per_10m near zero. Validate on the same window the fit used.

Parameters:
dsxr.Dataset

Raw channel, as for fit_tvg_models().

tvg_paramsTVGParams or mapping

The recipe, e.g. fit.tvg_params or a config’s tvg block (spreading_loss_db, absorption_db_per_m; an absent absorption means Francois-Garrison, as in apply_tvg).

window_m(float, float)

Where to measure flatness (normally fit.window_m).

value_var, range_varstr
crop_mfloat, optional
bin_width_mfloat, default 1.0
channelint or str, optional

Measure one side only.

ditherbool or “auto”, default “auto”

Applied before the TVG, as in the fit.

seedint, default 0
min_countint, default 50
Returns:
TVGCheckResult