[fix](trx-wefax): remove idle phasing fallback detection

Phasing-only signals (no APT start tone) should not trigger image
decoding. Only APT start tones and signal-level variance detection
can start reception.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-04-04 07:54:31 +02:00
parent e467ba0537
commit 69e00a8245
+1 -35
View File
@@ -65,9 +65,6 @@ pub struct WefaxDecoder {
demodulator: FmDiscriminator, demodulator: FmDiscriminator,
tone_detector: ToneDetector, tone_detector: ToneDetector,
phasing: Option<PhasingDetector>, phasing: Option<PhasingDetector>,
/// Fallback phasing detector that runs in Idle state to catch ongoing
/// transmissions when the APT start tone was missed.
idle_phasing: Option<PhasingDetector>,
slicer: Option<LineSlicer>, slicer: Option<LineSlicer>,
image: Option<ImageAssembler>, image: Option<ImageAssembler>,
/// Total sample counter for timestamps. /// Total sample counter for timestamps.
@@ -87,7 +84,6 @@ pub struct WefaxDecoder {
impl WefaxDecoder { impl WefaxDecoder {
pub fn new(input_sample_rate: u32, config: WefaxConfig) -> Self { pub fn new(input_sample_rate: u32, config: WefaxConfig) -> Self {
let default_lpm = config.lpm.unwrap_or(120);
Self { Self {
resampler: Resampler::new(input_sample_rate), resampler: Resampler::new(input_sample_rate),
demodulator: FmDiscriminator::new( demodulator: FmDiscriminator::new(
@@ -96,7 +92,6 @@ impl WefaxDecoder {
config.deviation_hz, config.deviation_hz,
), ),
tone_detector: ToneDetector::new(INTERNAL_RATE), tone_detector: ToneDetector::new(INTERNAL_RATE),
idle_phasing: Some(PhasingDetector::new(default_lpm, INTERNAL_RATE)),
config, config,
state: State::Idle, state: State::Idle,
phasing: None, phasing: None,
@@ -155,20 +150,15 @@ impl WefaxDecoder {
match self.state.clone() { match self.state.clone() {
State::Idle => { State::Idle => {
// Look for APT start tone first. // Look for APT start tone first.
let mut got_start = false;
for result in &tone_results { for result in &tone_results {
if let Some(tone) = result.tone { if let Some(tone) = result.tone {
match tone { match tone {
AptTone::Start576 => { AptTone::Start576 => {
self.idle_phasing = None;
events.push(self.transition_to_start_detected(576)); events.push(self.transition_to_start_detected(576));
got_start = true;
break; break;
} }
AptTone::Start288 => { AptTone::Start288 => {
self.idle_phasing = None;
events.push(self.transition_to_start_detected(288)); events.push(self.transition_to_start_detected(288));
got_start = true;
break; break;
} }
AptTone::Stop => {} // Ignore stop in idle. AptTone::Stop => {} // Ignore stop in idle.
@@ -176,26 +166,7 @@ impl WefaxDecoder {
} }
} }
// Fallback 1: try phasing detection on luminance to catch // Fallback: detect active WEFAX signal by luminance variance.
// ongoing transmissions where the start tone was missed.
if !got_start {
if let Some(ref mut idle_ph) = self.idle_phasing {
if let Some(offset) = idle_ph.process(&luminance) {
let ioc = self.config.ioc.unwrap_or(576);
let lpm = self.config.lpm.unwrap_or(120);
self.reception_start_ms = Some(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64,
);
self.idle_phasing = None;
events.push(self.transition_to_receiving(ioc, lpm, offset));
}
}
}
// Fallback 2: detect active WEFAX signal by luminance variance.
// Like fldigi's "strong image signal" detection — if we see // Like fldigi's "strong image signal" detection — if we see
// sustained modulated signal, auto-start receiving with defaults. // sustained modulated signal, auto-start receiving with defaults.
if self.state == State::Idle { if self.state == State::Idle {
@@ -230,7 +201,6 @@ impl WefaxDecoder {
.unwrap_or_default() .unwrap_or_default()
.as_millis() as i64, .as_millis() as i64,
); );
self.idle_phasing = None;
self.signal_detect_buf.clear(); self.signal_detect_buf.clear();
events.push(self.transition_to_receiving(ioc, lpm, 0)); events.push(self.transition_to_receiving(ioc, lpm, 0));
break; break;
@@ -334,13 +304,11 @@ impl WefaxDecoder {
} }
_ => Vec::new(), _ => Vec::new(),
}; };
let default_lpm = self.config.lpm.unwrap_or(120);
self.state = State::Idle; self.state = State::Idle;
self.resampler.reset(); self.resampler.reset();
self.demodulator.reset(); self.demodulator.reset();
self.tone_detector.reset(); self.tone_detector.reset();
self.phasing = None; self.phasing = None;
self.idle_phasing = Some(PhasingDetector::new(default_lpm, INTERNAL_RATE));
self.slicer = None; self.slicer = None;
self.image = None; self.image = None;
self.sample_count = 0; self.sample_count = 0;
@@ -409,13 +377,11 @@ impl WefaxDecoder {
} }
fn transition_to_idle(&mut self) { fn transition_to_idle(&mut self) {
let default_lpm = self.config.lpm.unwrap_or(120);
self.state = State::Idle; self.state = State::Idle;
self.phasing = None; self.phasing = None;
self.slicer = None; self.slicer = None;
// image is kept until finalize_image is called or next reception starts. // image is kept until finalize_image is called or next reception starts.
self.tone_detector.reset(); self.tone_detector.reset();
self.idle_phasing = Some(PhasingDetector::new(default_lpm, INTERNAL_RATE));
self.signal_detect_count = 0; self.signal_detect_count = 0;
self.signal_detect_buf.clear(); self.signal_detect_buf.clear();
} }