Request preparation
What would you like?
AM Co-Channel Canceller (client-side DSP for MW/SW DX)
Labels: feature, dsp, audio
What
An AM Co-Channel Canceller is a client-side DSP processing stage that, when
enabled in AM or SAM (Synchronous AM) mode, estimates and subtracts the carrier
and modulated audio of a dominant interfering station from the received I/Q
stream — leaving the weaker buried station audible underneath. The user tunes
to the channel of interest, identifies the offset of the interfering carrier,
and the algorithm suppresses it in real time.
A secondary (simpler) variant of this concept is sideband nulling in SAM
mode: selecting only the LSB or USB half of the demodulated audio to avoid
the sideband where co-channel interference dominates. KiwiSDR implements this
as a SAM mode option ("null LSB" / "null USB").
Why
Medium wave (MW) and shortwave (SW) DXers frequently encounter two or more
stations occupying the same or nearly the same channel:
- Regional co-channel allocation — many countries share the same MW
frequency, relying on antenna directivity and power limits that break down at
long range.
- DX propagation — a distant weak station arrives directly beneath a strong
local that normally dominates.
- Jamming — e.g. broadband noise jamming or deliberate carrier injection.
With standard AM or SAM demodulation both stations mix together and the weaker
one is unintelligible. A co-channel canceller can make the weaker signal fully
readable, which is otherwise impossible regardless of AGC, filter bandwidth, or
noise reduction settings.
For amateur radio operators, this applies equally to 60 m (5 MHz band) and
other frequencies shared with broadcast services, as well as cross-band
interference on HF.
The FLEX-8600's onboard DSP does not offer this feature. It must be implemented
client-side in the audio post-processing pipeline, downstream of the radio's
demodulator output.
How Other Clients Do It
SDR# (AirSpy)
SDR# introduced an AM Co-Channel Canceller plugin in late 2020 (around build
1770). Key implementation details:
- Works in DSB (double-sideband) or RAW mode — not in USB/LSB/AM mode.
The algorithm needs access to both sidebands simultaneously.
- A companion Micro Tuner plugin displays a ±15 Hz zoomed spectrum around
the tuned carrier, making sub-Hz carrier offset visible.
- The user clicks a carrier peak in the Micro Tuner to set the IF offset —
the exact fractional-Hz difference between the wanted and interfering carriers.
- Controls exposed:
- IF Offset (Hz, fractional) — frequency of the interfering carrier
relative to the tuned center
- Channel Bandwidth (Hz) — how wide a band around that carrier to model
and subtract
- Auto Tune — attempts automatic carrier peak detection (often best left
off)
- Lock Carrier — phase-locks to the selected carrier peak
- Enable toggle
The underlying algorithm estimates the interfering carrier's complex amplitude
and phase via a narrow PLL or Goertzel-style tone tracker, then reconstructs
and subtracts the full AM signal (carrier + both sidebands) from the baseband
I/Q. Multiple carriers can theoretically be suppressed by running the algorithm
iteratively.
KiwiSDR (SAM mode sideband nulling)
KiwiSDR's web client offers a simpler but practical variant in SAM mode:
- SAM — standard synchronous AM (phase-locked carrier, both sidebands)
- SAL — SAM, null LSB (only upper sideband is used after synchronous
detection)
- SAU — SAM, null USB (only lower sideband is used)
This does not cancel the interferer's carrier — it simply discards one sideband.
If the interfering station's modulation is stronger in one sideband than the
other (common when the two carriers have slightly different frequencies and
phasing), nulling the affected sideband gives a clean audio output from the
remaining one.
This is a much simpler implementation but useful in many real-world cases.
Suggested Behavior in AetherSDR
Phase 1 — SAM sideband nulling (simpler, implement first)
Implement a SAM mode (or sub-modes of AM) with three options, matching
KiwiSDR:
| Mode button |
Behavior |
SAM |
Synchronous AM: PLL locks carrier, demodulates both sidebands |
SAL |
SAM, null LSB — output only USB half after sync detection |
SAU |
SAM, null USB — output only LSB half after sync detection |
The radio's AM mode would be used at the protocol level; the sync detection and
sideband selection happen entirely client-side in AudioEngine
after the float32 audio is received via PCC 0x03E3.
The mode selector buttons in the VFO widget would gain SAM / SAL / SAU
options, or a sub-selector that appears when AM is active.
Phase 2 — Full co-channel canceller (harder, higher impact)
Implement a CoChannelCanceller class in src/core/, analogous to
SpectralNR and RNNoiseFilter:
// src/core/CoChannelCanceller.h
class CoChannelCanceller {
public:
void setEnabled(bool on);
void setIfOffsetHz(double offsetHz); // interferer carrier offset from center
void setBandwidthHz(double bwHz); // cancellation bandwidth
void setSampleRate(int rate); // 24000 Hz from radio
// processes stereo float32 buffer in-place
void process(float* samples, int frameCount);
private:
// PLL or Goertzel tone tracker + adaptive subtraction
};
User workflow:
- Tune to the desired AM station in AM or DSB mode.
- Open RX Applet → new CCC (Co-Channel Canceller) section (alongside
existing NB/NR/ANF toggles).
- Click CCC toggle to enable.
- A small offset dial appears (range ±500 Hz, resolution 0.1 Hz) — user
sets the carrier offset of the interfering station. Optionally an Auto
button attempts to find the strongest nearby carrier automatically.
- A BW slider controls cancellation bandwidth (default ~9 kHz for a
standard AM channel).
- The DSP runs in the existing
AudioEngine post-processing chain, after
NR/NB and before the audio sink.
The canceller state should be persisted per-slice via AppSettings:
CoChannelCancellerEnabled_0 = True
CoChannelCancellerOffset_0 = 12.3
CoChannelCancellerBW_0 = 9000
Protocol Hints
No new FlexLib API calls are required. The co-channel canceller operates
entirely client-side on the received audio stream (PCC 0x03E3, float32 stereo
at 24 kHz) and does not interact with the radio firmware.
The only protocol-adjacent concern is that the radio should be in AM or
DSB mode (not USB/LSB) so that both sidebands are present in the audio
stream. The mode set command is:
For Phase 1 SAM sideband nulling, the AetherSDR mode selector would send
mode=AM to the radio regardless of whether SAM/SAL/SAU is selected (the
distinction is purely client-side post-processing).
DSP algorithm references for implementation:
- Goertzel algorithm for precise tone detection at fractional-Hz resolution
- Complex LMS/RLS adaptive filter for carrier + sideband subtraction
- Simple PLL (phase-locked loop) for carrier phase tracking
No upstream firmware changes needed. No optimistic updates. All processing is
in the client audio pipeline.
Request preparation
What would you like?
AM Co-Channel Canceller (client-side DSP for MW/SW DX)
Labels:
feature,dsp,audioWhat
An AM Co-Channel Canceller is a client-side DSP processing stage that, when
enabled in AM or SAM (Synchronous AM) mode, estimates and subtracts the carrier
and modulated audio of a dominant interfering station from the received I/Q
stream — leaving the weaker buried station audible underneath. The user tunes
to the channel of interest, identifies the offset of the interfering carrier,
and the algorithm suppresses it in real time.
A secondary (simpler) variant of this concept is sideband nulling in SAM
mode: selecting only the LSB or USB half of the demodulated audio to avoid
the sideband where co-channel interference dominates. KiwiSDR implements this
as a SAM mode option ("null LSB" / "null USB").
Why
Medium wave (MW) and shortwave (SW) DXers frequently encounter two or more
stations occupying the same or nearly the same channel:
frequency, relying on antenna directivity and power limits that break down at
long range.
local that normally dominates.
With standard AM or SAM demodulation both stations mix together and the weaker
one is unintelligible. A co-channel canceller can make the weaker signal fully
readable, which is otherwise impossible regardless of AGC, filter bandwidth, or
noise reduction settings.
For amateur radio operators, this applies equally to 60 m (5 MHz band) and
other frequencies shared with broadcast services, as well as cross-band
interference on HF.
The FLEX-8600's onboard DSP does not offer this feature. It must be implemented
client-side in the audio post-processing pipeline, downstream of the radio's
demodulator output.
How Other Clients Do It
SDR# (AirSpy)
SDR# introduced an AM Co-Channel Canceller plugin in late 2020 (around build
1770). Key implementation details:
The algorithm needs access to both sidebands simultaneously.
the tuned carrier, making sub-Hz carrier offset visible.
the exact fractional-Hz difference between the wanted and interfering carriers.
relative to the tuned center
and subtract
off)
The underlying algorithm estimates the interfering carrier's complex amplitude
and phase via a narrow PLL or Goertzel-style tone tracker, then reconstructs
and subtracts the full AM signal (carrier + both sidebands) from the baseband
I/Q. Multiple carriers can theoretically be suppressed by running the algorithm
iteratively.
KiwiSDR (SAM mode sideband nulling)
KiwiSDR's web client offers a simpler but practical variant in SAM mode:
detection)
This does not cancel the interferer's carrier — it simply discards one sideband.
If the interfering station's modulation is stronger in one sideband than the
other (common when the two carriers have slightly different frequencies and
phasing), nulling the affected sideband gives a clean audio output from the
remaining one.
This is a much simpler implementation but useful in many real-world cases.
Suggested Behavior in AetherSDR
Phase 1 — SAM sideband nulling (simpler, implement first)
Implement a SAM mode (or sub-modes of AM) with three options, matching
KiwiSDR:
SAMSALSAUThe radio's AM mode would be used at the protocol level; the sync detection and
sideband selection happen entirely client-side in
AudioEngineafter the float32 audio is received via PCC
0x03E3.The mode selector buttons in the VFO widget would gain
SAM/SAL/SAUoptions, or a sub-selector that appears when AM is active.
Phase 2 — Full co-channel canceller (harder, higher impact)
Implement a
CoChannelCancellerclass insrc/core/, analogous toSpectralNRandRNNoiseFilter:User workflow:
existing NB/NR/ANF toggles).
sets the carrier offset of the interfering station. Optionally an Auto
button attempts to find the strongest nearby carrier automatically.
standard AM channel).
AudioEnginepost-processing chain, afterNR/NB and before the audio sink.
The canceller state should be persisted per-slice via
AppSettings:Protocol Hints
No new FlexLib API calls are required. The co-channel canceller operates
entirely client-side on the received audio stream (PCC
0x03E3, float32 stereoat 24 kHz) and does not interact with the radio firmware.
The only protocol-adjacent concern is that the radio should be in AM or
DSB mode (not USB/LSB) so that both sidebands are present in the audio
stream. The mode set command is:
For Phase 1 SAM sideband nulling, the AetherSDR mode selector would send
mode=AMto the radio regardless of whether SAM/SAL/SAU is selected (thedistinction is purely client-side post-processing).
DSP algorithm references for implementation:
No upstream firmware changes needed. No optimistic updates. All processing is
in the client audio pipeline.