callcut.evaluation.HysteresisDecoderπŸ”—

class callcut.evaluation.HysteresisDecoder(enter_threshold=0.6, exit_threshold=0.4, min_duration_s=0.03, min_gap_s=0.02, pad_s=0.0)[source]πŸ”—

Decode probabilities using hysteresis thresholding.

Uses separate enter/exit thresholds to avoid rapid on/off switching when probabilities hover near a single threshold. After initial detection, nearby intervals are merged and short intervals are filtered out.

Parameters:
enter_thresholdfloat

Probability threshold to START a call. When not in a call, a call begins when probability rises above this value.

exit_thresholdfloat

Probability threshold to END a call. When in a call, the call ends when probability falls below this value. Must be <= enter_threshold.

min_duration_sfloat

Minimum call duration in seconds. Calls shorter than this are discarded.

min_gap_sfloat

Minimum gap between calls in seconds. Calls separated by less than this are merged into a single call.

pad_sfloat

Padding to add around each detected call in seconds. The onset is moved earlier and the offset is moved later by this amount.

Attributes

enter_threshold

Probability threshold to start a call.

exit_threshold

Probability threshold to end a call.

min_duration_s

Minimum call duration in seconds.

min_gap_s

Minimum gap between calls in seconds.

pad_s

Padding around calls in seconds.

Methods

decode(times, probabilities)

Convert frame probabilities to a list of time intervals.

Notes

The decoding pipeline has four stages:

  1. Hysteresis thresholding: Mark frames as β€œin call” using enter/exit thresholds. This creates a binary mask.

  2. Extract intervals: Find contiguous regions in the mask and convert to time intervals.

  3. Merge short gaps: If two calls are separated by less than min_gap_s, merge them into one.

  4. Filter and pad: Remove calls shorter than min_duration_s, then add pad_s padding to remaining calls.

Examples

>>> import torch
>>> decoder = HysteresisDecoder(
...     enter_threshold=0.6,
...     exit_threshold=0.4,
...     min_duration_s=0.05,
... )
>>> times = torch.linspace(0, 1, 100)
>>> probs = torch.zeros(100)
>>> probs[20:40] = 0.8  # a clear call region
>>> intervals = decoder.decode(times, probs)
>>> len(intervals)
1
decode(times, probabilities)[source]πŸ”—

Convert frame probabilities to a list of time intervals.

Parameters:
timesTensor of shape (n_frames,)

Time axis of shape (n_frames,) in seconds, from the feature extractor.

probabilitiesTensor of shape (n_frames,)

Per-frame probabilities of shape (n_frames,), values in [0, 1], from predict().

Returns:
intervalslist of Interval

Detected call intervals, sorted by onset time.

property enter_thresholdπŸ”—

Probability threshold to start a call.

Type:

float

property exit_thresholdπŸ”—

Probability threshold to end a call.

Type:

float

property min_duration_sπŸ”—

Minimum call duration in seconds.

Type:

float

property min_gap_sπŸ”—

Minimum gap between calls in seconds.

Type:

float

property pad_sπŸ”—

Padding around calls in seconds.

Type:

float