You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I used the AI-assisted bug report tool (Help → Support → File an Issue)
I have attached a support bundle or log file
What happened?
Labels:bug, audio, dsp, nr2, parity
What happened
When NR2 is enabled with the default Gamma (MMSE-LSA) gain method, strong signals produce audible crackling, pops, and clicks. Users coming from Thetis/WDSP expect NR2 to behave like the well-known OpenHPSDR emnr.c reference — this implementation does not.
Important: this is NOT the Thetis NR2
Despite the shared name, the NR2 currently shipping in AetherSDR is not a faithful port of the WDSP NR2 (emnr.c) that Thetis, PowerSDR-mRX, and the wider OpenHPSDR community have used for years. It is an independent reimplementation inspired by WDSP NR2 but deviating from the reference in ways that directly affect behavior and stability:
Bessel helpers diverge from WDSP. WDSP emnr.c uses exponentially-scaled Bessel functions (bessI0e, bessI1e — computing exp(-|x|) × Iₙ(x)) precisely to avoid overflow. The AetherSDR version uses the unscaled form exp(|x|/2) × Iₙ(x) at src/core/SpectralNR.cpp:559-561, which is the direct cause of the crackling in this report.
Gain-method catalog differs. AetherSDR exposes 4 gain methods (Linear / Log-Spectral / Gamma / Trained LUT) and 3 noise estimators (OSMS / MMSE / NSTAT). WDSP NR2 in Thetis exposes a narrower canonical set; the mapping between AetherSDR's radio buttons and the Thetis dropdown labels is not 1:1.
Default behavior differs. In Thetis, users are used to NR2 being robust on strong signals out of the box. On AetherSDR 0.8.15 with defaults (Gamma + OSMS + GainMax 1.50) strong signals trigger the overflow path.
Sample rate / block structure differs. AetherSDR runs NR2 at 24 kHz, FFT=256, hop=128 (src/core/AudioEngine.cpp:52, src/core/SpectralNR.cpp). WDSP NR2 in Thetis typically runs at 48 kHz with different block geometry, so convergence time, musical-noise characteristics, and the "feel" of the sliders are not directly comparable.
Users should not assume that enabling "NR2" in AetherSDR gives them the same algorithm, tuning, or stability envelope as "NR2" in Thetis. The name is shared; the implementation is not.
Root cause (the crackling)
src/core/SpectralNR.cpp:559-561 — bessI0() / bessI1(), used by computeGainGamma() at src/core/SpectralNR.cpp:540-582, internally compute exp(|x|/2) × I(x). When the combined SNR term v exceeds ~1420, exp(710) overflows to +inf, and the gain expression collapses to NaN. The NaN mask is clamped to 0.01 downstream, producing full-suppression bursts. At the 128-sample hop (~5.33 ms at 24 kHz) these bursts are heard as crackling/pops.
Gain methods 0 (Linear Wiener), 1 (Log-Spectral), and 3 (Trained LUT) do not call the Bessel helpers and are not affected.
Suggested fix
Short term (the crackling): merge PR Audio crackling on SSB when NR2 is enabled #1464 (commit 5395a79, 2026-04-10), which replaces bessI0 / bessI1 with the exponentially-scaled bessI0e / bessI1e used by WDSP. For the large-x branch, use the asymptotic form 1 / √(2πx) instead of exp(x) × series.
Longer term (parity): decide whether "NR2" in AetherSDR should converge toward a faithful WDSP/Thetis port or be rebranded (e.g. "Spectral NR" / "NR2-Aether") so user expectations are not mis-set. If the goal is Thetis parity, an audit pass against emnr.c covering block size, window, SPP weighting, and default gain method should follow.
lower the GainMax slider below 2.0 in DSP Settings, or
switch the NR2 gain method to Log-Spectral Amplitude (LSA) or Linear Wiener (neither calls the overflowing Bessel path).
What did you expect?
NR2 should either (a) match the WDSP/Thetis NR2 that the amateur radio community already knows, or (b) be clearly labeled as a distinct algorithm. In both cases, the default configuration must not produce NaN gains and audible artifacts on ordinary strong HF signals.
Steps to reproduce
Launch AetherSDR 0.8.15 and connect to a FLEX-8600 on firmware v1.4.0.0.
Tune to a quiet HF band (e.g. 80 m at night).
Open DSP Settings and confirm defaults: Gain Method = Gamma (MMSE-LSA), NPE = OSMS, GainMax = 1.50, AE Filter = on.
Enable NR2 on the slice via the VFO DSP panel.
Inject a strong signal (e.g. −10 dBm test tone near the slice passband, or tune to a strong local broadcast).
Listen to PC Audio output — intermittent crackling/pops appear on signal peaks.
Switch gain method to Linear Wiener — crackling disappears.
For comparison, enable NR2 in Thetis under equivalent conditions — no crackling, and the overall character of the noise reduction differs noticeably from AetherSDR's.
Report preparation
What happened?
Labels:
bug,audio,dsp,nr2,parityWhat happened
When NR2 is enabled with the default Gamma (MMSE-LSA) gain method, strong signals produce audible crackling, pops, and clicks. Users coming from Thetis/WDSP expect NR2 to behave like the well-known OpenHPSDR
emnr.creference — this implementation does not.Important: this is NOT the Thetis NR2
Despite the shared name, the NR2 currently shipping in AetherSDR is not a faithful port of the WDSP NR2 (
emnr.c) that Thetis, PowerSDR-mRX, and the wider OpenHPSDR community have used for years. It is an independent reimplementation inspired by WDSP NR2 but deviating from the reference in ways that directly affect behavior and stability:emnr.cuses exponentially-scaled Bessel functions (bessI0e,bessI1e— computingexp(-|x|) × Iₙ(x)) precisely to avoid overflow. The AetherSDR version uses the unscaled formexp(|x|/2) × Iₙ(x)atsrc/core/SpectralNR.cpp:559-561, which is the direct cause of the crackling in this report.src/core/AudioEngine.cpp:52,src/core/SpectralNR.cpp). WDSP NR2 in Thetis typically runs at 48 kHz with different block geometry, so convergence time, musical-noise characteristics, and the "feel" of the sliders are not directly comparable.Users should not assume that enabling "NR2" in AetherSDR gives them the same algorithm, tuning, or stability envelope as "NR2" in Thetis. The name is shared; the implementation is not.
Root cause (the crackling)
src/core/SpectralNR.cpp:559-561—bessI0()/bessI1(), used bycomputeGainGamma()atsrc/core/SpectralNR.cpp:540-582, internally computeexp(|x|/2) × I(x). When the combined SNR termvexceeds ~1420,exp(710)overflows to+inf, and the gain expression collapses toNaN. The NaN mask is clamped to0.01downstream, producing full-suppression bursts. At the 128-sample hop (~5.33 ms at 24 kHz) these bursts are heard as crackling/pops.Call path:
src/core/AudioEngine.cpp:789-799→SpectralNR::process()src/core/SpectralNR.cpp:540-582(computeGainGamma)src/core/SpectralNR.cpp:559-561(bessI0/bessI1)Gain methods 0 (Linear Wiener), 1 (Log-Spectral), and 3 (Trained LUT) do not call the Bessel helpers and are not affected.
Suggested fix
5395a79, 2026-04-10), which replacesbessI0/bessI1with the exponentially-scaledbessI0e/bessI1eused by WDSP. For the large-x branch, use the asymptotic form1 / √(2πx)instead ofexp(x) × series.emnr.ccovering block size, window, SPP weighting, and default gain method should follow.Workaround
Until #1464 is merged, either:
What did you expect?
NR2 should either (a) match the WDSP/Thetis NR2 that the amateur radio community already knows, or (b) be clearly labeled as a distinct algorithm. In both cases, the default configuration must not produce NaN gains and audible artifacts on ordinary strong HF signals.
Steps to reproduce
Radio model & firmware
FLEX-8600 v1.4.0.0
Linux distro & Qt version
Arch Linux, Qt 6.8.2