Skip to content

DAX IQ streaming — raw I/Q data for SDR apps #124

Description

@ten9876

Overview

Implement DAX IQ streaming to provide raw I/Q sample data to third-party SDR applications (SDR#, SDR Console, GQRX, GNU Radio, SpectraVue). Unlike regular DAX which carries demodulated audio, DAX IQ provides the unprocessed complex signal directly from the radio's DDC before any mode/filter/AGC processing.

Use Cases

  • SDR software: Run SDR# or GQRX alongside AetherSDR for independent demodulation
  • IQ recording: Record raw IQ for later playback and analysis
  • Signal analysis: Feed GNU Radio or custom DSP pipelines
  • Wide-band monitoring: Capture up to 192 kHz of spectrum

Protocol Details (from FlexLib DAXIQStream.cs)

VITA-49 Packet Class Codes

PCC Sample Rate Bandwidth Payload
0x02E3 24 kHz ~24 kHz float32 I/Q interleaved, big-endian
0x02E4 48 kHz ~48 kHz float32 I/Q interleaved, big-endian
0x02E5 96 kHz ~96 kHz float32 I/Q interleaved, big-endian
0x02E6 192 kHz ~192 kHz float32 I/Q interleaved, big-endian

Payload format: [I0, Q0, I1, Q1, ...] — each sample is two float32 values (8 bytes per I/Q pair). Values are big-endian and scaled by 1.0 / 2^15.

Commands

# Create IQ stream on channel 1
stream create type=dax_iq daxiq_channel=1

# Change sample rate (after creation)
stream set 0x<streamid> daxiq_rate=96000

# Remove stream
stream remove 0x<streamid>

Status Messages

S<handle>|stream <streamid> type=dax_iq daxiq_channel=1 pan=0x40000000 daxiq_rate=24000 client_handle=0x1234 active=1

Key fields: daxiq_channel (1-4), pan (associated panadapter), daxiq_rate (current sample rate), active (streaming).

Implementation Plan

Phase 1: Core IQ Stream Support

New: src/models/DaxIqModel.h/.cpp

  • Per-channel IQ stream state: stream ID, channel (1-4), sample rate, pan ID, active
  • createStream(int channel)stream create type=dax_iq daxiq_channel=N
  • setSampleRate(int rate)stream set ... daxiq_rate=N
  • removeStream()stream remove ...
  • Parses status updates for type=dax_iq streams
  • Signals: iqDataReady(int channel, const QByteArray& iqData, int sampleRate)

Modified: src/core/PanadapterStream.cpp

  • Add PCC 0x02E3–0x02E6 to the packet router
  • Register IQ stream IDs (similar to existing registerDaxStream)
  • Byte-swap float32 pairs and emit iqDataReady(channel, data, rate)
  • Multi-Flex filtering: only process IQ streams matching our client_handle

Modified: src/models/RadioModel.cpp

  • Parse stream status for type=dax_iq → route to DaxIqModel
  • Create/remove IQ streams on DAX IQ enable/disable
  • Track IQ stream IDs for VITA-49 routing

Phase 2: Virtual Audio Devices (IQ output)

Modified: src/core/PipeWireAudioBridge.h/.cpp (Linux)

  • Add 4 IQ pipe sources: "AetherSDR IQ 1-4"
  • IQ channels use stereo (I=left, Q=right) — this is the one valid use of stereo in DAX
  • Variable sample rate per channel (24k/48k/96k/192k) — set at pipe creation time
  • Format: float32 stereo (not int16 mono like audio DAX)

macOS: src/core/VirtualAudioBridge.cpp

  • Same pattern: 4 IQ virtual devices via CoreAudio HAL plugin

Phase 3: GUI

Modified: src/gui/CatApplet.cpp

  • Add "DAX IQ" section below existing DAX channels
  • 4 IQ channel enable/disable buttons
  • Sample rate dropdown per channel: 24k / 48k / 96k / 192k
  • Level meters showing IQ signal activity

Modified: src/gui/VfoWidget.cpp or RxApplet.cpp

  • Add dax_iq_channel selector (which IQ channel this slice feeds)
  • Separate from the existing dax channel selector

Phase 4: Compatibility

  • SDR# / SDR Console: Expect audio devices with I=left, Q=right at specified sample rate. Our PipeWire stereo IQ source provides exactly this.
  • GNU Radio: Can use audio.source block pointing at the PipeWire device
  • GQRX: Supports PulseAudio input with I/Q format

Data Flow

Radio DDC → VITA-49 UDP (PCC 0x02E3-0x02E6)
  → PanadapterStream: byte-swap float32, route by stream ID
    → DaxIqModel: emit iqDataReady(channel, data, rate)
      → PipeWireAudioBridge: write float32 stereo to IQ pipe
        → SDR app reads from "AetherSDR IQ N" capture device

Files Summary

File Action
src/models/DaxIqModel.h/.cpp NEW — IQ stream state, commands, status parsing
src/core/PanadapterStream.h/.cpp Modify — add PCC 0x02E3-0x02E6 routing
src/core/PipeWireAudioBridge.h/.cpp Modify — add 4 IQ stereo float32 pipe sources
src/core/VirtualAudioBridge.h/.cpp Modify — add 4 IQ devices (macOS)
src/models/RadioModel.cpp Modify — IQ stream lifecycle
src/gui/CatApplet.cpp Modify — IQ channel controls
CMakeLists.txt Modify — add DaxIqModel

Capacity Considerations

The radio has a fixed number of DAX IQ channels (daxiq_capacity and daxiq_available reported in radio status). Higher sample rates consume more radio DDC resources. At 192 kHz, each IQ channel uses significant USB/network bandwidth (~1.5 MB/s per channel).

Dependencies

  • Regular DAX (audio) must be working first (done)
  • Multi-Flex IQ stream filtering by client_handle (reuse existing pattern)
  • No external library dependencies — all VITA-49 parsing is in-house

Metadata

Metadata

Assignees

No one assigned

    Labels

    audioAudio engine and streamingenhancementImprovement to existing featurehelp wantedExtra attention neededpriority: lowLow priority

    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