Codec backends: native vs third-party¶
Every digital mode in Rafe now has a native encoder/decoder written in this repo (pure Python + numpy/scipy). The app defaults to native everywhere, so a stock install needs none of the external tools it used to shell out to:
| Was shelled out to | Replaced by (native) |
|---|---|
jt9 (WSJT-X) |
app/radio/jtx/ — JT9, JT4, JT65, FST4, FST4W, Q65 |
wsprd (WSJT-X) |
app/radio/wsprx/ — WSPR |
decode_ft8 / gen_ft8 (ft8_lib) |
app/radio/ftx/ — FT8, FT4 |
fldigi (+ pacat/parec) |
app/radio/mfsk|domino|thor|olivia|throb|feld.py |
You can still fall back to the original third-party code per family — e.g. if you
want wsprd's deeper weak-signal sensitivity, or a fldigi feature the native
modem doesn't cover yet.
The switch¶
Selection lives in app/radio/codec_backend.py and is driven entirely by
environment variables. All are optional; the default is native.
| Variable | Applies to | Values | Default |
|---|---|---|---|
RAFE_CODEC_BACKEND |
global default for every family | native | external |
native |
RAFE_FTX_BACKEND |
FT8 / FT4 | native | ft8_lib | both |
native |
RAFE_WSJTX_BACKEND |
JT9/JT4/JT65/FST4/FST4W/Q65/WSPR | native | external |
native |
RAFE_FLDIGI_BACKEND |
MFSK16/32, DominoEX, Thor, Olivia, Contestia, THROB, Feld Hell | native | external |
native |
Precedence: family variable → legacy variable → RAFE_CODEC_BACKEND → native.
Setting the global to external maps each family to its third-party option
(ft8_lib for FT8/FT4, external for the rest).
DIGIMODE_BACKEND (the original FT8-only variable: ft8_lib | native | both)
is still honoured for backward compatibility and takes precedence over
RAFE_FTX_BACKEND.
Examples¶
# Default: everything native, no external binaries needed.
# Use the WSJT-X binaries for the whole weak-signal family (needs jt9 + wsprd):
RAFE_WSJTX_BACKEND=external
# Just WSPR on wsprd but keep the JT/FST4/Q65 modes native? Not per-mode yet —
# RAFE_WSJTX_BACKEND is whole-family. (Per-mode override is a possible follow-up.)
# Fall the fldigi keyboard modes back to the fldigi XML-RPC bridge:
RAFE_FLDIGI_BACKEND=external # needs the headless fldigi sidecar running
# Run FT8 through both decoders and emit tagged, compared results (evaluation):
RAFE_FTX_BACKEND=both # (or legacy DIGIMODE_BACKEND=both)
# Force absolutely everything back to third-party:
RAFE_CODEC_BACKEND=external
Set these in the systemd unit / .env for the icom-remote service and restart.
What external needs installed¶
RAFE_WSJTX_BACKEND=external→jt9andwsprdonPATH(or setJT9_BIN/WSPRD_BIN). From thewsjtxpackage.RAFE_FTX_BACKEND=ft8_lib→decode_ft8/gen_ft8(setDECODE_FT8_BIN/GEN_FT8_BIN). From kgoba/ft8_lib.RAFE_FLDIGI_BACKEND=external→ the headlessfldigisidecar + PulseAudio (pacat/parec). See the deploy docs for the sidecar service.
Sensitivity notes (native vs third-party)¶
The native codecs are validated bit-/tone-exact on the encode side and decode their own and the reference tools' output. A few have a sensitivity gap worth knowing before you switch a weak-signal station to native:
- WSPR — native is ~2–3 dB shy of
wsprd(no OSD / calibrated LLR yet). For a dedicated WSPR spotter,RAFE_WSJTX_BACKEND=externalis still the stronger call. - JT65 — native uses hard-decision Reed-Solomon;
jt9's soft/deep-search reaches a few dB deeper. - Q65 — native is a solid single-shot decoder; WSJT-X's −26 dB figure needs multi-frame averaging + a-priori/deep search (unported).
- FT8/FT4, JT9, JT4, FST4/FST4W — native decode matches the reference on strong-to-moderate signals; the very deepest decodes may still favour the external tools' OSD.
- fldigi modes — native Thor/MFSK/Olivia include soft-decision + timing recovery and decode well below 0 dB; the exact overlap-add pulse shaping and fldigi's CWI/multipath refinements are the remaining differences.
See docs/native-digimodes.md for the full mode-by-mode status and validation.