Skip to content

Noise Blanker–Gated Waterfall Impulse Suppression #277

Description

@boydsoftprez

What

When the Noise Blanker (NB/NB2) or Wideband Noise Blanker (WNB) is enabled,
apply client-side impulse detection and suppression to incoming waterfall tiles
before rendering, so that wideband horizontal streaks caused by impulse
noise sources (electric fences, power-line interference, automotive ignition,
etc.) are blanked from the waterfall visualization as well as from the audio
chain.


Why

Persistent impulse noise — a classic example being an electric livestock fence —
produces repetitive full-width horizontal bright lines across the waterfall.
These lines:

  • Make it very difficult to read band activity visually (signals are obscured
    by the stripes)
  • Make it hard to judge propagation conditions at a glance
  • Give a false impression of wideband interference even when the audio is
    already being cleaned up by the NB

The NB already cleans the audio chain, but the waterfall rendering pipeline
is independent: waterfall tiles arrive pre-generated by the radio via VITA-49
(PCC 0x8004) and are rendered as-is. The result is a paradox where the
operator hears clean audio but watches a waterfall full of noise stripes —
defeating the visual utility of the display while NB is active.

This is especially relevant for operators in rural/agricultural environments
(electric fence controllers, grain dryers, pump motors) and near power
infrastructure.


How Other Clients Do It

Thetis (OpenHPSDR/ANAN G2 client)

Thetis implements this as "NB Waterfall Blanking" linked to the NB enable
state. When NB is on, Thetis inspects each incoming waterfall row and computes
a per-row brightness metric. Rows whose aggregate energy exceeds a threshold
above the rolling noise floor baseline are identified as impulse rows and either:

  • Blanked (replaced with the estimated noise-floor colour), or
  • Interpolated (replaced with an average of the immediately preceding and
    following non-blanked rows)

The threshold and blanking mode are configurable. The feature is described in
the ANAN G2 community as dramatically improving the visual experience on farms
and near power infrastructure, where electric fence controllers fire at 1–3 Hz
and would otherwise produce a steady horizontal stripe pattern.

The key insight in Thetis is that the detection is done entirely client-side
on the rendered tile data — no protocol changes are required and no radio-side
DSP is involved. The NB toggle state simply gates whether the suppression
algorithm is applied.

Screenshot reference: The Thetis waterfall blanking discussion can be found
in the Apache Labs / ANAN community forums. A before/after comparison shows
the fence stripes present when NB is off, and cleanly suppressed when NB +
waterfall blanking is enabled.

SmartSDR for Windows

SmartSDR does not appear to implement client-side waterfall blanking. The
WNB (Wideband Noise Blanker, toggled via display pan X wnb=1) is applied
radio-side and affects the panadapter FFT bins sent to the client, which does
partially suppress wide impulses in both the spectrum and waterfall. However
WNB only addresses the panadapter stream — the per-slice NB/NB2 (audio chain)
has no coupling to waterfall rendering in SmartSDR. This gap is exactly what
Thetis solved.


Suggested Behavior

NB / NB2 Coupling (slice-level)

  1. When the user enables NB or NB2 for a slice in the RX applet, a
    new "NB Waterfall Blanking" checkbox/toggle becomes active in the
    PanadapterApplet (Display settings panel, alongside AVG / FPS / fill /
    gain / black level).

  2. When both NB (or NB2) and "NB Waterfall Blanking" are enabled, each
    incoming waterfall tile row passes through a per-row impulse detector in
    SpectrumWidget::updateWaterfallRow() before the pixel buffer is written:

   // Pseudocode — per-row detection
   float rowEnergy = mean(tile_row[0..width]);
   float baseline  = rollingMedian(lastN_rowEnergies, N=32);
   float threshold = baseline * blankerMultiplier;   // e.g. 1.15×

   if (NB_enabled && WaterfallBlanking_enabled && rowEnergy > threshold) {
       // Replace row with baseline-energy synthetic row (noise colour)
       fill(tile_row, baseline_value);
       // OR: interpolate from previous good row
   }
  1. The blanker multiplier / threshold is exposed as a slider in the
    PanadapterApplet (range 1.05–2.0, default 1.15), labeled "NB WF Threshold".
    This lets the user tune sensitivity — a tighter threshold blanks more rows
    (good for heavy fences), a looser one avoids false-blanking strong signals.

  2. The blanking mode is selectable: Fill (noise-floor colour) vs
    Interpolate (average adjacent rows). Interpolate looks more natural but
    introduces a small latency artifact.

WNB Coupling (pan-level)

  1. The existing WNB toggle in PanadapterModel / PanadapterApplet (display pan X wnb=1) already suppresses impulses radio-side in the FFT stream. The
    waterfall blanking above is additive — it catches impulses that slip through
    WNB or are only present in the waterfall tile stream.

  2. Optionally: when WNB is enabled, automatically enable waterfall blanking
    as well (user-configurable default in AppSettings:
    WaterfallBlanking_AutoWithWNB).

Settings Persistence

All new settings use AppSettings (not QSettings):

WaterfallBlankingEnabled     = "True"/"False"
WaterfallBlankingMode        = "Fill"/"Interpolate"
WaterfallBlankingThreshold   = "1.15"   (float as string)
WaterfallBlankingAutoWithWNB = "False"

Visual Indicator

  1. When waterfall blanking fires (rows are suppressed), a subtle indicator
    (e.g. a brief flash of the "NB" label in the RX applet, or a small "WF●"
    indicator in the spectrum status bar) lets the operator know blanking is
    active and working — useful for threshold tuning.

Protocol Hints

Feature Protocol Involvement
Per-slice NB enable slice set X nb=1 / nb=0 (already implemented)
Per-slice NB2 enable slice set X nb2=1 / nb2=0 (already implemented)
Panadapter WNB display pan X wnb=1 / wnb=0 (already in PanadapterModel)
Waterfall tile stream VITA-49 PCC 0x8004 — no protocol changes needed
Waterfall blanking itself Pure client-side post-processing on tile data — no new protocol commands required

The blanking algorithm operates entirely within SpectrumWidget::updateWaterfallRow()
on the already-decoded uint16 tile payload, after the intensity conversion
(static_cast<int16>(raw) / 128.0f) and before the colour-mapping step.
No radio-side protocol changes are required.


Implementation Notes for Contributors

  • The rolling baseline for impulse detection should be computed on the raw
    pre-colourmap intensity values (post / 128.0f conversion), not on pixel
    colours, to keep it display-setting–independent.
  • Guard the detection with a #if defined(ENABLE_WATERFALL_BLANKING) compile
    flag initially so it can be disabled if it causes regressions.
  • The N=32 rolling buffer for baseline tracking adds ~32 rows × width floats
    of memory (e.g. 32 × 1024 × 4 bytes ≈ 128 KB per pan) — acceptable.
  • Flag any threshold tuning as needing field testing with actual electric fence
    hardware; the default multiplier (1.15×) is a starting point only.

Labels: feature, spectrum, DSP, priority: medium
Related: #66 (Relative Noise Floor Scaling — baseline tracking code may be shareable)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions