[fix](trx-cw): fix window size, dot/dash threshold, and cleanup

- Reduce analysis window from 50ms to 10ms so the decoder can detect
  dits at 25+ WPM (at 25 WPM a dit is 48ms, shorter than the old window)
- Fix dot/dash classification threshold from 2.0× to 1.5× unit_ms;
  ITU Morse dah = 3× dit, so the midpoint boundary is 1.5×
- Replace O(n) on_durations.remove(0) with drain() to trim the window
- Remove pointless emit_text() wrapper; callers now call emit_event()
  directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-06 21:30:58 +01:00
parent 4d22fa964d
commit 91562b2a4b
+7 -11
View File
@@ -153,7 +153,7 @@ pub struct CwDecoder {
impl CwDecoder { impl CwDecoder {
pub fn new(sample_rate: u32) -> Self { pub fn new(sample_rate: u32) -> Self {
let window_ms = 50; let window_ms = 10;
let window_size = (sample_rate as usize * window_ms) / 1000; let window_size = (sample_rate as usize * window_ms) / 1000;
let default_tone = 700u32; let default_tone = 700u32;
let k = (default_tone as f32 * window_size as f32 / sample_rate as f32).round(); let k = (default_tone as f32 * window_size as f32 / sample_rate as f32).round();
@@ -347,15 +347,15 @@ impl CwDecoder {
// Word gap // Word gap
if !self.current_symbol.is_empty() { if !self.current_symbol.is_empty() {
let ch = morse_lookup(&self.current_symbol).unwrap_or('?'); let ch = morse_lookup(&self.current_symbol).unwrap_or('?');
self.emit_text(&ch.to_string()); self.emit_event(&ch.to_string());
self.current_symbol.clear(); self.current_symbol.clear();
} }
self.emit_text(" "); self.emit_event(" ");
} else if off_duration > u * 2.0 { } else if off_duration > u * 2.0 {
// Character gap // Character gap
if !self.current_symbol.is_empty() { if !self.current_symbol.is_empty() {
let ch = morse_lookup(&self.current_symbol).unwrap_or('?'); let ch = morse_lookup(&self.current_symbol).unwrap_or('?');
self.emit_text(&ch.to_string()); self.emit_event(&ch.to_string());
self.current_symbol.clear(); self.current_symbol.clear();
} }
} }
@@ -367,7 +367,7 @@ impl CwDecoder {
self.tone_on = false; self.tone_on = false;
let on_duration = now - self.tone_on_at; let on_duration = now - self.tone_on_at;
let u = self.unit_ms(); let u = self.unit_ms();
if on_duration > u * 2.0 { if on_duration > u * 1.5 {
self.current_symbol.push('-'); self.current_symbol.push('-');
} else { } else {
self.current_symbol.push('.'); self.current_symbol.push('.');
@@ -378,7 +378,7 @@ impl CwDecoder {
// Collect for auto WPM // Collect for auto WPM
self.on_durations.push(on_duration); self.on_durations.push(on_duration);
if self.on_durations.len() > 30 { if self.on_durations.len() > 30 {
self.on_durations.remove(0); self.on_durations.drain(..self.on_durations.len() - 30);
} }
self.auto_detect_wpm(); self.auto_detect_wpm();
} }
@@ -391,7 +391,7 @@ impl CwDecoder {
let silence = now - self.tone_off_at; let silence = now - self.tone_off_at;
if silence > self.unit_ms() * 5.0 { if silence > self.unit_ms() * 5.0 {
let ch = morse_lookup(&self.current_symbol).unwrap_or('?'); let ch = morse_lookup(&self.current_symbol).unwrap_or('?');
self.emit_text(&ch.to_string()); self.emit_event(&ch.to_string());
self.current_symbol.clear(); self.current_symbol.clear();
} }
} }
@@ -406,10 +406,6 @@ impl CwDecoder {
}); });
} }
fn emit_text(&mut self, text: &str) {
self.emit_event(text);
}
pub fn process_samples(&mut self, samples: &[f32]) -> Vec<CwEvent> { pub fn process_samples(&mut self, samples: &[f32]) -> Vec<CwEvent> {
for &s in samples { for &s in samples {
self.sample_buf[self.sample_idx] = s; self.sample_buf[self.sample_idx] = s;