Background
Phase 7 of the client-side DSP roadmap. Tracks pulling in liquid-dsp (MIT) as the foundation library for future client-side DSP work that the current ad-hoc + FFTW3 + r8brain stack doesn't cover well.
Why now is the right time to plan, not to implement
The library is genuinely good (mature, MIT-licensed, designed for embedded/real-time use, zero external deps). We've correctly held off so far because adding a large dependency for "we might use it someday" reasons violates Principle X (no premature dependencies).
But the right moment to pull it in is when we have a specific concrete feature that justifies the cost. This issue exists to:
- Document what liquid-dsp would unlock so future feature discussions can reference it.
- List the triggers that would justify the pull-in — so when we hit one of those triggers, the decision is fast.
- Sketch the integration shape so the eventual implementation PR doesn't start from scratch.
What liquid-dsp would unlock
| Capability |
liquid-dsp primitives |
Currently |
| Modems |
PSK, QAM, FSK, GMSK, OFDM (modem objects + symbol-rate-agnostic demod) |
Zero native modem support — we delegate to firmware or external apps |
| Forward error correction |
Hamming, Golay, Reed-Solomon, convolutional codes |
None — would be needed for any native FT8/FT4/PSK31 decoder |
| Adaptive filters |
LMS, RLS, normalized variants |
None — useful for HF channel equalization on poor paths |
| AGC |
Multiple algorithms (squelch-aware, hangover, etc.) |
Delegated to radio firmware |
| NCO / mixers |
Numerically-controlled oscillators, frequency translators |
Inline in a few places |
| Polyphase resampling |
Multi-stage decimators/interpolators |
r8brain covers our resampling needs |
| Equalizers |
Decision-feedback, LMS-based |
None |
| Synchronization |
Symbol-rate, frame-rate, carrier-phase recovery |
None |
Triggers that would justify pull-in
In rough order of likelihood:
1. Native FT8 / FT4 decode (Phase 4 of #85)
Would need FEC (Reed-Solomon or LDPC) + GMSK demod primitives. Could potentially be served by ft8_lib alone, but liquid-dsp gives us the toolkit to also handle adjacent modes (FT4, JT65, etc.) without a separate library per mode. Strongest single trigger.
2. Native PSK31 / RTTY / Olivia decoder
Each of these is a tractable demod task with liquid-dsp's modem primitives + symbol synchronization. Without liquid-dsp we'd write each demodulator from scratch. With it: ~200 LOC per mode vs. ~2000.
3. HF channel equalization for digital voice
RADE is shipped. Codec2 and similar future digital voice modes might benefit from adaptive equalization on poor HF paths. liquid-dsp's LMS/RLS adaptive filters are the right primitives.
4. Sophisticated client-side AGC
Currently we let the radio firmware handle AGC. If a future use case (e.g., DAX-IQ post-processing, or a mode where we receive raw IQ) needs client-side AGC, liquid-dsp has multiple algorithms with different attack/release shapes.
5. Native CW skimmer / multi-decoder pan
ggmorse decodes one frequency at a time. A "decode every CW signal on the panadapter at once" feature (a la CW Skimmer) would benefit from liquid-dsp's NCO + symbol-rate recovery primitives for parallel decoders.
Why we shouldn't pull it in yet
- No current feature consumes any of the unlocked primitives.
- Adding ~5 MB of compiled code + a vendor dir for "future use" is exactly the kind of dependency creep that bites us during cross-platform CI debugging.
- The library's surface area is huge — without a specific consumer driving the integration, we'd be vendoring it without a clear API surface.
- Each potential consumer (FT8, PSK31, etc.) is its own architectural decision point — bundling them into one "add the toolkit" PR conflates concerns.
Integration sketch (for the eventual pull-in PR)
- Vendor liquid-dsp under
third_party/liquid-dsp/ following the same pattern as third_party/rnnoise/, third_party/fftw3/, etc.
- CMake target:
add_subdirectory(third_party/liquid-dsp) after configuring its options to disable simulation/benchmark targets we don't need.
- Cross-platform build verification: liquid-dsp is autotools-native; verify the CMake wrapper (existing community fork or upstream) builds clean on Linux/Windows/macOS via the project's existing third_party CMake conventions.
- The first PR that integrates liquid-dsp also implements the trigger feature — they ship together, so the integration is justified by an immediate consumer.
- Subsequent features consume the existing vendored copy.
Scope decisions to make before starting
When we hit a trigger and pull this in, decide:
- Vendor full library or subset? liquid-dsp is modular but the source tree is monolithic. Full vendor is simpler; subset is leaner.
- Build as static lib or object lib? Static keeps the main binary self-contained; object lib avoids dual-compile of headers.
- SIMD usage? liquid-dsp has hand-tuned SSE/NEON paths — verify they don't conflict with our existing AVX2 RTCD pattern (used in rnnoise).
- Threading? liquid-dsp objects are not thread-safe by default — same constraint as rnnoise. Per-slice instance pattern is the right model.
Acceptance criteria (for the eventual integration PR)
Parent
Tracks Phase 7 of #85. Holding open until a Phase 4 / future digital-mode trigger justifies pull-in.
Background
Phase 7 of the client-side DSP roadmap. Tracks pulling in liquid-dsp (MIT) as the foundation library for future client-side DSP work that the current ad-hoc + FFTW3 + r8brain stack doesn't cover well.
Why now is the right time to plan, not to implement
The library is genuinely good (mature, MIT-licensed, designed for embedded/real-time use, zero external deps). We've correctly held off so far because adding a large dependency for "we might use it someday" reasons violates Principle X (no premature dependencies).
But the right moment to pull it in is when we have a specific concrete feature that justifies the cost. This issue exists to:
What liquid-dsp would unlock
Triggers that would justify pull-in
In rough order of likelihood:
1. Native FT8 / FT4 decode (Phase 4 of #85)
Would need FEC (Reed-Solomon or LDPC) + GMSK demod primitives. Could potentially be served by ft8_lib alone, but liquid-dsp gives us the toolkit to also handle adjacent modes (FT4, JT65, etc.) without a separate library per mode. Strongest single trigger.
2. Native PSK31 / RTTY / Olivia decoder
Each of these is a tractable demod task with liquid-dsp's modem primitives + symbol synchronization. Without liquid-dsp we'd write each demodulator from scratch. With it: ~200 LOC per mode vs. ~2000.
3. HF channel equalization for digital voice
RADE is shipped. Codec2 and similar future digital voice modes might benefit from adaptive equalization on poor HF paths. liquid-dsp's LMS/RLS adaptive filters are the right primitives.
4. Sophisticated client-side AGC
Currently we let the radio firmware handle AGC. If a future use case (e.g., DAX-IQ post-processing, or a mode where we receive raw IQ) needs client-side AGC, liquid-dsp has multiple algorithms with different attack/release shapes.
5. Native CW skimmer / multi-decoder pan
ggmorse decodes one frequency at a time. A "decode every CW signal on the panadapter at once" feature (a la CW Skimmer) would benefit from liquid-dsp's NCO + symbol-rate recovery primitives for parallel decoders.
Why we shouldn't pull it in yet
Integration sketch (for the eventual pull-in PR)
third_party/liquid-dsp/following the same pattern asthird_party/rnnoise/,third_party/fftw3/, etc.add_subdirectory(third_party/liquid-dsp)after configuring its options to disable simulation/benchmark targets we don't need.Scope decisions to make before starting
When we hit a trigger and pull this in, decide:
Acceptance criteria (for the eventual integration PR)
third_party/liquid-dsp/with documented version pinnm/bloaty)docs/architecture-pipelines.mdnotes what subset of liquid-dsp is used + by which featuresParent
Tracks Phase 7 of #85. Holding open until a Phase 4 / future digital-mode trigger justifies pull-in.