morse: fix SNR threshold for real CW and stop timeout

Widen noise detector offset from ±100Hz to ±200Hz to reduce spectral
leakage into the noise reference, and scale threshold_multiplier for
SNR space (2.8 → 1.54) so real CW signals reliably trigger tone
detection instead of producing all-E's at 60 WPM.

Fix misleading "decoder startup" timeout message on stop requests and
increase stop timeout from 2.2s to 5s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-26 21:30:43 +00:00
parent be522d4dfe
commit 97b10b3ac9
2 changed files with 8 additions and 7 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ var MorseMode = (function () {
var SETTINGS_KEY = 'intercept.morse.settings.v3';
var STATUS_POLL_MS = 5000;
var LOCAL_STOP_TIMEOUT_MS = 2200;
var LOCAL_STOP_TIMEOUT_MS = 5000;
var START_TIMEOUT_MS = 60000;
var state = {
@@ -87,7 +87,7 @@ var MorseMode = (function () {
});
}).catch(function (err) {
if (err && err.name === 'AbortError') {
throw new Error('Request timed out while waiting for decoder startup');
throw new Error('Request timed out');
}
throw err;
}).finally(function () {
+6 -5
View File
@@ -165,12 +165,12 @@ class MorseDecoder:
self._detector = GoertzelFilter(self._active_tone_freq, self.sample_rate, self._block_size)
self._noise_detector_low = GoertzelFilter(
_clamp(self._active_tone_freq - max(60.0, self.bandwidth_hz * 0.5), 150.0, 2000.0),
_clamp(self._active_tone_freq - max(150.0, self.bandwidth_hz), 150.0, 2000.0),
self.sample_rate,
self._block_size,
)
self._noise_detector_high = GoertzelFilter(
_clamp(self._active_tone_freq + max(60.0, self.bandwidth_hz * 0.5), 150.0, 2000.0),
_clamp(self._active_tone_freq + max(150.0, self.bandwidth_hz), 150.0, 2000.0),
self.sample_rate,
self._block_size,
)
@@ -249,7 +249,7 @@ class MorseDecoder:
def _rebuild_detectors(self) -> None:
"""Rebuild target/noise Goertzel filters after tone updates."""
self._detector = GoertzelFilter(self._active_tone_freq, self.sample_rate, self._block_size)
ref_offset = max(60.0, self.bandwidth_hz * 0.5)
ref_offset = max(150.0, self.bandwidth_hz)
self._noise_detector_low = GoertzelFilter(
_clamp(self._active_tone_freq - ref_offset, 150.0, 2000.0),
self.sample_rate,
@@ -457,8 +457,9 @@ class MorseDecoder:
# gain-invariant — fixes stuck-ON tone when AGC amplifies
# inter-element silence above the raw magnitude threshold.
snr = level / max(noise_ref, 1e-6)
snr_on = self.threshold_multiplier * (1.0 + self._hysteresis)
snr_off = self.threshold_multiplier * (1.0 - self._hysteresis)
snr_mult = max(1.3, self.threshold_multiplier * 0.55)
snr_on = snr_mult * (1.0 + self._hysteresis)
snr_off = snr_mult * (1.0 - self._hysteresis)
if self._tone_on:
tone_detected = gate_ok and snr >= snr_off