Commit Graph

162 Commits

Author SHA1 Message Date
sjg 1001786a08 [fix](trx-backend-soapysdr): ensure IQ stream recovery after overflow
Two problems prevented reliable recovery after a persistent overflow:

1. Restart storm: once read_error_streak >= 3, every subsequent read
   failure triggered a deactivate/activate cycle, potentially preventing
   the hardware from stabilising. Fix: after a successful restart, reset
   read_error_streak to 1 so the stream gets 2 more failures before the
   next restart attempt.

2. Stuck-deactivated stream: if activate() failed after overflow, the
   stream was left deactivated. Subsequent reads returned non-overflow
   errors which handle_read_error ignored (Ok(false)), so the stream was
   never reactivated. Fix: add a high-streak fallback (>= 10 consecutive
   errors of any kind) that also attempts a full deactivate/activate
   restart, covering the stuck-deactivated case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:31:17 +01:00
sjg 3eb5a615b9 [feat](trx-backend-soapysdr): extend squelch and boost high denoise
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:19 +01:00
sjg 5dcc117e61 [fix](trx-backend-soapysdr): disable hidden AIS DSP outside AIS modes
Add per-channel processing gating and disable hidden AIS channel DSP unless mode is AIS or MARINE, reducing continuous IQ read-loop CPU load in normal operation.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:01:21 +01:00
sjg 8be3b273bc [fix](trx-backend-soapysdr): reduce sdr-iq-read CPU spin on idle reads
Skip IQ fanout buffer cloning when no subscribers exist and apply backoff on repeated zero-length reads to avoid hot-loop CPU spikes.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:50:17 +01:00
sjg a041dd4505 [fix](trx-backend-ft817): bound lock/unlock reads to prevent set_mode timeout 2026-03-05 20:44:32 +01:00
sjg ccef359034 [fix](trx): speed up web load and harden FT817/Soapy recovery 2026-03-05 20:36:46 +01:00
sjg e3a5fee666 [style](trx-backend-soapysdr): format WFM code
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 19:41:30 +01:00
sjg 087ebb33bb [style](trx-backend-ft817): format mode setup
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 19:41:20 +01:00
sjg acecaff810 [fix](trx-backend-ft817): reject unsupported modes
Make FT-817 mode setting fail for unsupported modes instead of silently mapping SDR-only modes onto FM.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:12:49 +01:00
sjg 564f25fc6d [fix](trx-backend-ft817): hide unsupported decode modes
Remove SDR-only decoder modes from the FT-817 supported mode list so they are not shown in that rig's mode picker.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:10:52 +01:00
sjg 7188d38610 [fix](trx-backend-soapysdr): boost AM audio further
Raise the AM audio AGC target and headroom again so the restored envelope demod path plays at a stronger level.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:02:15 +01:00
sjg 605531184b [fix](trx-backend-soapysdr): raise AM audio gain
Retune the AM audio AGC target, timing, and headroom so the restored envelope demod path plays back at a stronger level.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:59:50 +01:00
sjg c1ed936c2e [fix](trx-backend-soapysdr): restore simple AM demodulation
Revert the recent AM coherent detector experiment and restore the original envelope detector path.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:58:11 +01:00
sjg e2e4d34f30 [fix](trx-backend-soapysdr): reduce AM demod distortion
Remove half-wave clipping from the AM coherent detector output and slow the carrier-reference tracking to reduce audible distortion.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:55:30 +01:00
sjg 298b7247f8 [feat](trx-backend-soapysdr): improve AM coherent demodulation
Replace the raw AM envelope detector with a limiter-derived coherent detector and update backend tests for the current channel DSP constructor.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:48:22 +01:00
sjg 10f5a147dc [fix](trx-vdes): preserve higher SDR iq rate
Keep the SoapySDR VDES and MARINE IQ path at a much higher channel sample rate instead of collapsing toward the normal audio rate, so the decoder receives usable complex baseband for the 76.8 ksps VDES signal.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 01:13:06 +01:00
sjg 9fe293e056 [feat](trx-rs): expose marine mode and ft8 live bar
Add an FT8 live overlay bar, align APRS top controls with the other decoder tabs, advertise MARINE in the SoapySDR mode list, and make the VDES decoder emit raw unsynced diagnostic frames instead of dropping weak bursts outright.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 01:01:00 +01:00
sjg c8d81ed353 [feat](trx-rs): add marine mode scaffolding and VDES fallback
Keep weak VDES bursts visible by emitting unsynced diagnostic frames instead of dropping them, remove receiver badges from FT8 and WSPR history rows, and carry the current MARINE composite-mode scaffolding through the shared mode enums and backend mappings.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 00:54:31 +01:00
sjg 6e558303a7 [feat](trx-rs): split VDES frontend and decoder path
Add a dedicated VDES plugin tab and live bar, stop reusing the AIS vessel UI, and serve a separate VDES frontend script. Rework the SDR backend so VDES receives a single 100 kHz IQ tap, then replace the fake AIS-clone decoder path with an early M.2092-1 oriented complex-baseband scaffold using burst detection, coarse pi/4-QPSK slicing, and TER-MCS-1.100 frame heuristics.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 00:32:32 +01:00
sjg 92423f1e02 [feat](trx-rs): add VDES decoder mode support
Add a new trx-vdes decoder path alongside AIS, wire VDES through the server/frontend decode pipeline, and fix the web map so AIS vessel symbols load correctly and the TRX receiver marker appears when location data arrives.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 00:05:16 +01:00
sjg c778d4b9a8 [feat](trx-rs): add AIS decoder mode and frontend
Add dual-channel AIS decode support across the SoapySDR backend, server decode pipeline, and frontend plugins, including the new AIS tab, live bar, and map filtering.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-02 22:42:12 +01:00
sjg 832fac1d64 [fix](trx-rs): refine wfm denoise and favicon handling
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:26:04 +01:00
sjg 616ff1b79e [feat](trx-backend-soapysdr): add wfm denoise levels
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:22:02 +01:00
sjg 31238098ca [fix](trx-backend-soapysdr): raise wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:07:29 +01:00
sjg 623aad10d1 [fix](trx-backend-soapysdr): preserve more stereo under denoise
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:06:15 +01:00
sjg fb52558652 [feat](trx-backend-soapysdr): adapt wfm stereo separation gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:01:08 +01:00
sjg d569db6643 [fix](trx-backend-soapysdr): fine tune wfm phase trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:53:12 +01:00
sjg 2b1764b90e [fix](trx-backend-soapysdr): restore neutral wfm stereo trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:50:54 +01:00
sjg a1a8aaeb9d [fix](trx-backend-soapysdr): rebalance wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:48:51 +01:00
sjg 129c27548e [fix](trx-backend-soapysdr): reduce wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:46:49 +01:00
sjg ded6e2a1f8 [fix](trx-backend-soapysdr): widen wfm stereo image
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:43:07 +01:00
sjg aa367239de [fix](trx-rs): update PKT and AM default bandwidths
PKT: default 25 kHz, max 50 kHz (was 3 kHz / 25 kHz).
AM:  default 9 kHz,  max 20 kHz (was 6 kHz / 15 kHz).

Applied consistently across the UI mode-defaults table
(trx-frontend-http), server initial-mode logic (trx-server), and the
SoapySDR DSP channel (trx-backend-soapysdr).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 14:37:28 +01:00
sjg 56d6d12d9e [refactor](trx-backend-soapysdr): extract spectrum snapshot helper
Move the spectrum FFT snapshot logic into a dedicated dsp module so dsp.rs stays focused on pipeline orchestration.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 13:58:30 +01:00
sjg 08b8c80cc3 [refactor](workspace): split soapysdr demod and dsp modules
Split the SoapySDR backend demod and dsp code into focused modules while keeping behavior stable, and include the resulting formatting updates.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 13:55:48 +01:00
sjg 64bb9a0d42 [feat](trx-rs): expose WFM stereo denoise toggle in UI
Wire the StereoDenoise processor through the full stack:
- Add SetWfmDenoise command variant and RigCat trait method (trx-core)
- Add wfm_denoise field to RigFilterState with default true
- Add protocol command and bidirectional mapping (trx-protocol)
- Add rig_task command handler (trx-server)
- Implement set_wfm_denoise in SoapySdrRig backend
- Add /set_wfm_denoise API endpoint (trx-frontend-http)
- Add denoise checkbox in WFM controls with SSE sync and
  localStorage persistence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 13:29:02 +01:00
sjg 46bc96ddf2 [fix](workspace): resolve clippy warnings
Clean up the workspace so cargo clippy passes across all targets and features.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 13:22:44 +01:00
sjg 523f3992f5 [feat](trx-backend-soapysdr): add WFM stereo denoise processor
Add frequency-selective attenuation of the L-R difference signal to
reduce stereo hiss on weak FM broadcasts. Uses the quadrature component
(diff_q) as a noise reference per US7292694B2 (Wildhagen/Sony).

The algorithm splits sum, diff_i, and diff_q into 6 overlapping subbands,
estimates per-band SNR from smoothed |diff_q|² noise power, and applies
an energy-weighted broadband gain to the original diff signal. This
preserves clean stereo content (<4 dB loss) while attenuating noise-only
diff channels (>6 dB reduction).

Enabled by default; toggled via set_denoise_enabled() / set_wfm_denoise().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 13:17:30 +01:00
sjg cb5467ba34 [fix](trx-backend-soapysdr): retune wfm stereo gain
Increase the stereo matrix gain to 1.2 and trim the WFM output gain slightly to rebalance the decoded audio path.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 11:28:30 +01:00
sjg ca6b83c967 [fix](trx-backend-soapysdr): raise wfm stereo matrix gain to unity
Output gain clamp catches any peaks from full-deviation signals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 11:22:15 +01:00
sjg 313c9b39a6 [fix](trx-backend-soapysdr): increase wfm stereo matrix gain to 0.80
More stereo headroom for broadcast audio. With WFM_OUTPUT_GAIN at 0.35
the effective output is 0.28 peak, well within clipping margin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 11:19:50 +01:00
sjg f7c10a0185 [fix](trx-backend-soapysdr): remove agc from wfm chain, use fixed output gain
Replace both IQ AGC and audio AGC in the WFM path with a fixed output
gain of 0.35. AGC pumping on broadcast audio degrades stereo separation
and introduces audible artifacts. The IQ hard limiter already normalizes
input magnitude, and the WFM decoder's internal deemphasis + matrix gain
provides consistent output levels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 11:17:14 +01:00
sjg 626d5e2ec5 [perf](trx-backend-soapysdr): quadrature NCO and decimated stereo detection
Replace per-sample sin_cos(pilot_phase) with a quadrature NCO that
advances via complex rotation (4 muls + 2 adds vs transcendental).
Renormalize every 1024 samples to prevent magnitude drift.

Decimate stereo detection logic (pilot coherence, lock, drive,
hysteresis) to run every 16 composite samples instead of every sample.
Accumulate pilot_mag and pilot_abs over the window and process averaged
values, scaling the IIR coefficients accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 10:07:16 +01:00
sjg 0c35051630 [perf](trx-backend-soapysdr): eliminate per-sample sin_cos and atan2 calls
Derive sin/cos of PLL phase error directly from I/Q arms (q/mag, i/mag)
instead of calling atan2 + sin_cos. Use double-angle identity to compute
38 kHz carrier (sin2θ = 2·sinθ·cosθ, cos2θ = 2·cos²θ-1) from the
rotated pilot sin/cos, eliminating the second sin_cos call entirely.
Drop Butterworth from 6th to 4th order (resampler Blackman-Harris now
handles stopband). Use power-of-2 bitmask for ring buffer indexing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:52:51 +01:00
sjg 4f99c23e7a [perf](trx-backend-soapysdr): reduce polyphase resampler phases from 128 to 64
Halves the coefficient bank from 128×32 to 64×32 (16 KB → 8 KB) for
better L1 cache utilization while maintaining sufficient fractional
sample resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:47:13 +01:00
sjg 7eb88b6669 [perf](trx-backend-soapysdr): use circular buffer for wfm resampler history
Replace shift_append (O(N) rotate_left per sample) with a circular buffer
index for O(1) writes. The polyphase resampler now reads from the ring
buffer directly, eliminating 3 × 32-element memmoves per composite sample.
Remove unused dot_product functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:46:35 +01:00
sjg 132cd5b950 [perf](trx-backend-soapysdr): batch wfm discriminator with avx2 atan2
Pre-compute all FM discriminator outputs using demod_fm_with_prev which
processes 8 samples at a time via AVX2 atan2, then iterate the scalar
results through the rest of the stereo pipeline. Eliminates per-sample
f32::atan2 calls from the inner loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:42:49 +01:00
sjg 36d0e7e862 [perf](trx-backend-soapysdr): reduce wfm resampler taps from 64 to 32
With Blackman-Harris window and proper cutoff (~0.24), 32 taps still
provides 60+ dB stopband rejection. Halves the per-sample MAC count
from 192 to 96 across the three resampler channels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:41:26 +01:00
sjg 380231a68f [perf](trx-backend-soapysdr): improve wfm stereo resampler and pilot rejection
Increase polyphase resampler phases from 32 to 128 for finer fractional
sample positioning. Replace Hamming window with Blackman-Harris for ~92 dB
stopband rejection. Add pilot notch on composite signal before diff demod
to prevent 19 kHz × 38 kHz intermod products in the stereo difference
path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:37:11 +01:00
sjg 700e5c9fab [perf](trx-backend-soapysdr): increase wfm resampler taps and filter order
Increase polyphase resampler taps from 16 to 64 for sharper anti-alias
stopband rejection. Upgrade sum/diff lowpass filters from 4th-order to
6th-order Butterworth (three biquad stages) for ~36 dB/octave rolloff,
improving stereo separation by better rejecting the 38 kHz subcarrier
residuals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:19:11 +01:00
sjg 1ba9c9dd3e [fix](trx-backend-soapysdr): widen wfm audio bandwidth to 18 kHz
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 09:11:50 +01:00