Skip to content

Feature Request: CQUAM AM Stereo Decoder #176

Description

@k9mq

What

Add a client-side CQUAM (Compatible Quadrature Amplitude Modulation) AM Stereo decoder
to AetherSDR, enabling the radio to receive and decode AM Stereo broadcasts — those
transmitted using the Motorola C-QUAM standard — and output them as proper stereo audio.

When tuned to an AM station that is broadcasting C-QUAM stereo, the user would enable
the decoder (e.g. via a toggle in the RX Applet or VFO widget AM tab), and the audio
output would change from mono to stereo, with audible left/right channel separation
and a stereo indicator displayed in the UI.


Why

AM Stereo via C-QUAM is a real and still-active broadcast standard. A number of AM
stations worldwide (particularly in the US, Canada, Japan, and Australia) continue to
transmit C-QUAM stereo today. Conventional SDR clients receive AM as mono and discard
the stereo subcarrier entirely.

FlexRadio hardware is well-suited for AM Stereo reception — it has sufficient ADC
dynamic range and bandwidth, and delivers raw IQ-derived audio to the client. However,
SmartSDR for Windows has no C-QUAM decoder, so AetherSDR would have a genuine
capability advantage here. This is a feature that has long been requested by
broadcast-band listeners and vintage radio enthusiasts in the SDR community.

The problem being solved: AM Stereo audio is collapsed to mono by the current
AudioEngine pipeline. The stereo information encoded in the quadrature component
of the C-QUAM signal is simply discarded.


How Other Clients Do It

SDR# (SDRsharp) — Windows

SDR# supports AM Stereo via a community plugin that implements C-QUAM decoding
on the raw IQ baseband. It exposes a plugin panel with a stereo/mono lock indicator
and a pilot detection LED. When the decoder locks, audio switches to stereo
automatically.

GQRX — Linux/macOS

GQRX does not natively support C-QUAM as of writing. AM mode outputs mono only.
This is a known gap in the Linux SDR ecosystem — implementing this in AetherSDR
would be a meaningful differentiator.

Airspy HF+ Discovery / Spy Server

The Airspy ecosystem (via SDR#) supports C-QUAM natively when used with compatible
plugins. Documented in the Airspy community forums.

Vintage hardware reference

The Motorola MC13028A and MC13020P chips were the canonical C-QUAM decoder ICs.
Their datasheets describe the demodulation algorithm precisely and are freely
available — they are an excellent implementation reference for software decoding.


Suggested Behavior

Mode trigger

  • The decoder activates only when the slice mode is AM or SAM — it is
    irrelevant in USB/LSB/FM/CW/etc.
  • A "AM Stereo" toggle button appears in the RX Applet (or the VFO AM tab,
    similar to how CW decode options appear in the CW tab).

Signal flow

The C-QUAM signal is received as stereo float32 audio (PCC 0x03E3) at 24 kHz.
C-QUAM encodes stereo as:

L+R  →  AM envelope  (standard AM demodulation, already decoded by the radio DSP)
L-R  →  quadrature (Q) component of the composite carrier

The radio's AM mode demodulates only the envelope (L+R). To recover the Q
component (L-R difference signal), the decoder would need access to the IQ
baseband before AM envelope detection — or operate on the raw audio delivered
in the VITA-49 stream if the radio provides the full complex baseband.

Note: This may require requesting a DAX IQ stream (issue #124) rather
than the standard remote audio stream, since envelope-detected AM audio has
already discarded the Q component. Alternatively, if the radio can be put into
a wide USB/LSB mode centered on the AM carrier, the client could perform its
own envelope detection and recover both L+R and L-R from the IQ pair in the
audio stream. This needs investigation.

Decoding steps (software)

  1. Receive IQ pair from VITA-49 audio (float32 stereo, big-endian, 24 kHz)
  2. Envelope detect: mono = sqrt(I² + Q²) → L+R signal
  3. Phase-lock loop: lock onto the 25 Hz pilot (or the carrier itself) to
    establish the C-QUAM phase reference
  4. Multiply Q component by PLL reference → L-R difference signal
  5. Matrix: L = (L+R + L-R) / 2, R = (L+R - L-R) / 2
  6. Feed L and R to the stereo QAudioSink pipeline

UI indicators

  • "ST" indicator (cyan, similar to CwDecoder's confidence display) shown in
    the VFO widget or RX Applet when stereo lock is achieved
  • "MONO" fallback when pilot is not detected or SNR is too low
  • Optional: stereo separation meter (L-R level as a small horizontal gauge)

Settings persistence

// In AppSettings
s.setValue("AmStereoEnabled", "True");   // per-slice or global
s.setValue("AmStereoMinSnr", "15");      // dB threshold for auto-lock

New class: CquamDecoder

Modeled after CwDecoder — takes feedAudio(float* left, float* right, int frames)
and emits:

signals:
    void stereoLockChanged(bool locked);
    void audioReady(QVector<float> left, QVector<float> right);

Wired into AudioEngine::feedAudioData() when AM Stereo is enabled and mode is AM/SAM,
replacing the mono envelope output with the decoded stereo pair.


Protocol Hints

Standard remote audio (current)

stream create type=remote_audio_rx compression=none

PCC 0x03E3 delivers float32 stereo at 24 kHz — but in AM mode, the radio's own
DSP has already performed envelope detection, and both channels carry the same mono
audio. The Q component is lost at this point.

DAX IQ (needed — see issue #124)

stream create type=dax_iq daxIQ=1 pan=0x40000000

PCC unknown — needs Wireshark capture. This would deliver raw complex baseband IQ
before the radio's own demodulation, allowing full client-side C-QUAM decode.

Mode forcing workaround (to investigate)

Setting the slice to a narrow DSB or raw IQ mode while tuning to an AM carrier
may expose both I and Q components via the existing audio stream. Needs testing
with firmware v1.4.0.0.

Overall protocol status: Partially known — DAX IQ stream format needs research
(see #124). Standard remote audio stream is insufficient for full C-QUAM decode.


Labels

feature · audio · dsp · help wanted

Related Issues

Metadata

Metadata

Assignees

Labels

New FeatureNew feature requestVITA-49VITA-49 UDP streaming: FFT, waterfall, audio, metersaudioAudio engine and streamingdependenciesPull requests that update a dependency filehelp wantedExtra attention neededmaintainer-reviewRequires maintainer review before any action is takenpriority: lowLow priorityprotocolSmartSDR protocol

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