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_threshold
float Probability threshold to START a call. When not in a call, a call begins when probability rises above this value.
- exit_threshold
float 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_s
float Minimum call duration in seconds. Calls shorter than this are discarded.
- min_gap_s
float Minimum gap between calls in seconds. Calls separated by less than this are merged into a single call.
- pad_s
float Padding to add around each detected call in seconds. The onset is moved earlier and the offset is moved later by this amount.
- enter_threshold
Attributes
Probability threshold to start a call.
Probability threshold to end a call.
Minimum call duration in seconds.
Minimum gap between calls in seconds.
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:
Hysteresis thresholding: Mark frames as βin callβ using enter/exit thresholds. This creates a binary mask.
Extract intervals: Find contiguous regions in the mask and convert to time intervals.
Merge short gaps: If two calls are separated by less than
min_gap_s, merge them into one.Filter and pad: Remove calls shorter than
min_duration_s, then addpad_spadding 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