JTDX_CONTEST · CE3TSKSuperFox decoder · experimental
derivative work of the SuperFox decoder of WSJT-X 3.0.2 by K1JT, K9AN and IV3NWV
What WSJT-X's SuperFox decoder does. What JTDX_contest does differently.
A DXpedition in SuperFox mode answers up to nine Hounds with one signal. Until now JTDX could not read it: the Fox's period simply stayed empty. JTDX_contest receives it. Its decoder starts from WSJT-X's, ported line by line, and then goes further: it looks for the Fox under QRM, remembers what it has heard, and decodes messages it can partly foresee. This page first explains the decoder as WSJT-X wrote it, and then lists everything JTDX_contest does differently.
Experimental — and why this page shows no figures
SuperFox support in JTDX_contest is experimental. Every measurement made so far comes from simulated transmissions and a handful of short recordings, not from DXpeditions on the air. Simulations are good for comparing two versions of a decoder, but not for promising what it will do on a real band. So this page describes what each step does and why, and deliberately gives no sensitivity, decode count or timing figures.
Once a reasonable number of real SuperFox recordings exist, they will be used to measure every step described here, and the figures will be added. Recordings made with Save all, both periods, while a SuperFox DXpedition is working are the most useful thing a reader can contribute. Ideally about an hour's worth of WAV files - but less is welcome too, even a few minutes: jtdx_contest@ce3tsk.com.
WSJT-X marks WSJT-X's decoder · JTDX_contest marks what this program does differently
Part IWSJT-X 3.0.2
SuperFox was designed by the WSJT-X team; its code, a q-ary polar code, is the work of Nico Palermo IV3NWV. Everything in Part I is how WSJT-X 3.0.2 receives it, and it is also the starting point of JTDX_contest's decoder.
Why SuperFox exists, and how a SuperFox QSO runs.
In the old Fox-and-Hound mode the DXpedition answered up to five Hounds by transmitting five ordinary FT8 signals at once. Five signals share the transmitter's power, and their sum no longer has a constant envelope, so the amplifier has to be backed off as well. SuperFox replaces them with one constant-envelope signal whose single codeword carries up to nine Hound messages. Every Hound hears the Fox at full power.
The timing is FT8's. The Fox transmits in the even 15-second period, starting half a second in; the Hounds call and answer in the odd period with plain FT8, anywhere in the audio passband. The QSO is the usual exchange (call, report, R+report, RR73) and is logged as FT8. What the Hound decodes in the even period must be on the screen before the odd period begins, or the reply has to wait a whole cycle.
A SuperFox cycle
The Fox's transmission fills the even period; the Hound's decode begins after it ends and has until the start of the odd period to put the Fox's lines on the screen.
329 bits, a 21-bit CRC, a polar code over 128 symbols, 128 tones.
A SuperFox transmission carries 329 bits: the Fox's call, up to nine Hound calls with an RR73 or a report each, a flag for "CQ", and a 20-bit one-time code that lets a Hound check that the transmission really comes from the DXpedition. The last three bits say which of four layouts is used:
| type | content |
|---|---|
| standard | the Fox's call, nine Hounds: five RR73s and four reports |
| compound Fox call | the Fox's full compound call, eight Hounds |
| free text | the Fox's call, four Hounds with reports, 26 characters of text |
| CQ | "CQ" with the Fox's call and grid, and text |
The 329 bits are read as 47 symbols of seven bits, and a 21-bit CRC fills three more. These 50 symbols are encoded with a polar code (127,50) over GF(128): 127 symbols, each one of 128 values, of which only 50 carry information — the rest is redundancy that lets the decoder correct errors. Each code symbol is sent as one of 128 tones, and 24 more symbols carry a sync tone, the lowest one: 151 symbols in all, 1500 Hz wide, from 750 Hz upwards.
The 151 symbols of one transmission
The sync symbols (the positions are fixed by the protocol) are dense at the start and thin out, so the decoder can use them for both frequency and time.
From 15 seconds of audio to the Fox's lines.
Try again, slightly differently, until the CRC agrees.
The polar decoder always returns a word; only the CRC says whether it is the right one. So a failed attempt costs nothing but time, and the decoder makes many. At the sync estimate it tries four smoothings of the spectra, each with a series of randomly perturbed copies of the probabilities (the random stream is seeded, so the decoder is deterministic). Then it spirals outwards over a grid of small frequency and time offsets, trying the four smoothings at each. The first attempt whose CRC checks is taken. A period with a sync peak but no Fox in it runs every attempt.
Where the search looks, and in which order
The hundred time and frequency offsets of WSJT-X's search, drawn in the order they are tried.
One decision per symbol, the least reliable first, and no way back.
WSJT-X's polar decoder is a successive-cancellation decoder. It decides the message symbols one after another, each decision building on the ones before, and it happens to settle its least reliable symbols first. A wrong early decision cannot be undone: the rest of the word is decoded on top of it, and the CRC fails. This matters for Part II, where JTDX_contest adds a decoder that keeps more than one path open.
The one-time code, checked on a server.
A DXpedition can sign its transmissions: the Fox computes a six-digit one-time code from a secret key issued by the NCDXF, and every SuperFox transmission carries it. A Hound needs no key: WSJT-X sends the Fox's call, the time and the code to a verification server, which answers verified or invalid, and shows the answer. An unsigned transmission carries an all-zero code.
Part IIJTDX_contest
Everything below is this program's own. The rule throughout: whatever WSJT-X's decoder decodes is decoded here too, and in the same way — the additions come after WSJT-X's search, or leave its result untouched. Every addition can be switched off (the settings are listed at the end of this part).
The same chain, with the steps that are new or changed marked.
*, as
FT8's a-priori decodes are. A compound Fox call typed into DX Call is resolved (section 17).The one step of the demodulator that is not WSJT-X's.
The likelihoods weigh all 128 tone bins with a single noise level. An FT8 caller inside the Fox's band breaks that twice: in its own bins it is far stronger than the Fox, so it wins every symbol it is keyed in; and the symbol FFT leaks it over the whole band, so every other bin's noise level is wrong as well. So a bin whose mean power over the whole transmission clearly exceeds the noise is divided by that mean. A caller's bins come back to the order of the noise; a bin that only carries leakage comes back to exactly the noise. The Fox's own bins may qualify too, but the polar code spreads even the barest message over many tones, so its cells still stand out after the division. On a band without QRM no bin qualifies, and nothing changes.
The SNR estimate is taken from the spectra without the step, so a strong Fox is not reported weaker than it is.
Before and after, schematically
The dashed line is the noise level the likelihoods assume.
Nothing about what is tried changes — only how long it takes.
WSJT-X demodulates the signal again for each of the four smoothings at every offset; here it is demodulated once per offset, and the median it needs is found by selection instead of a full sort. Then the attempts are decoded in parallel on as many threads as the FT8 decoder uses, under the rules JTDX_contest's FT8, FT4 and FT2 threads already follow:
So the decoder prints the same lines at any thread count, and the same lines as without threads. That is checked, not assumed: the tests compare the threaded decoder line by line with the serial one and with the version before the threads, on simulated, faded, noisy, QRM-laden and recorded periods, repeated to catch any run-to-run difference. Each thread's FFT buffer is also checked once, bit for bit, against the serial demodulation, and should it ever differ the steps fall back to the serial demodulation.
Why the thread count cannot change the result
Threads finish in any order; the rule picks by position in the search, not by time.
Taken out by JTDX_contest's own FT8 decoder, and only when it is needed.
A DXpedition works on a frequency of its own, so what lies on top of a SuperFox is mostly Hounds calling in the wrong period. WSJT-X and MSHV remove FT8 signals before they look for the Fox; this decoder looks first, and only when the Fox is not found does JTDX_contest's own FT8 decoder go over the Fox's band — silently, nothing of it is printed:
The FT8 decodes of these rounds fill FT8's hint memory like any others, so the next Fox period's quick round already knows the stations that were there. The QRM step and the bin normalisation are complements: the normalisation deals with a few callers at once and with what a subtraction leaves behind, the FT8 step with a band full of them.
What keeps chance decodes off the screen, set per case.
WSJT-X's floor rejects a word with a good CRC when its SNR estimate is too low. Two changes:
"The Fox it last decoded" is remembered for a few Fox periods without a decode of it, and forgotten at once on a band or mode change, as the FT8 hint lists are. Its grid, from its last CQ, is remembered with it.
The a-priori pass: tell the decoder what it already knows. Lines marked *.
FT8 decoders state MyCall DxCall in advance and let the decoder find the rest. The same
works for SuperFox: a symbol whose value is known is handed to the polar decoder as one more fixed
position. When the search has found nothing, the decoder tries — for a Fox it knows — the
messages it can state almost whole:
As in FT8, what concerns your own call is tried only while a transmission of yours is recent and the QSO expects that answer, and only from the Fox in DX Call. Every stated bit must stand in the decoded word, and its SNR estimate must reach a floor of its own. It has to be whole messages: the Hound slots hold most of the code's least reliable positions (section 04), and with one of them left open the rest of what is known is worth little — which is what the list decoder is for.
CRC-aided successive-cancellation list decoding, written for this program.
Where WSJT-X's decoder keeps one path, a list decoder keeps the L most probable ones at every decision, and at the end the CRC chooses among them. A wrong early decision is no longer final: the right path survives in the list. With a list of one it takes exactly WSJT-X's decisions, and the tests check that decision for decision. It can also be told candidates for a slot: "this Hound slot holds one of these calls, or nothing". The next two passes use it; the ordinary search does not — it stays WSJT-X's.
CRC-aided successive-cancellation list decoding (CA-SCL) is the decoding technique of 5G mobile networks: state of the art, now in amateur radio.
One path against a list of paths
Schematic. On the left a wrong early decision dooms the word; on the right the list keeps the right path alive and the CRC picks it.
A busy Fox's message is full of calls — often calls you have heard. Lines marked *.
In S-Hound mode the odd periods go to the FT8 decoder, so the program hears who calls and who answers the Fox in DX Call — and those are the stations the Fox's next messages will name. Their calls form a pool. When the search and the a-priori pass have found nothing, the list decoder runs with the Fox told and every Hound slot held to one of the pool, your own call while your QSO runs, or empty. No order, no placement and no guess at the message are needed.
From the odd period to the next Fox period
Schematic: the calls heard become the candidates of every Hound slot.
Only the Fox told — and then nothing at all.
Often the Fox's Hounds are not in the pool: you hear the DX and not its pile-up, or you have just
arrived on the frequency. One thing is still known — the Fox. So the list decoder runs once more
with only the Fox told and the Hound slots free (its lines are marked *), and then a
round with nothing told, under MSHV's floor, for a Fox the decoder does not know yet (those
lines are ordinary decodes). The pass states nothing about you: if it prints RR73 to your call, the
decoder found it in free slots and the 21-bit CRC vouches for it. Against false lines only the best
few paths are tried against the CRC, only the message types that carry the Fox's call are accepted,
and the SNR estimate must reach a floor of its own.
The decoder finds the Fox by itself.
It looks for the Fox's sync tone at 750 Hz, and then follows the frequency where it last decoded it. After a few Fox periods without a decode it tries 750 Hz and the last place in turn, and when you move the dial it starts again at 750 Hz. A Fox that announces another frequency can be set in the ini file. The decoder never reads the RX frequency, but two things in the program do — the Rx Frequency window shows the lines near it, and in the odd period Filter keeps the decode around it — so while the mode is on the RX frequency box follows the Fox: greyed, set where the decoder last decoded it. Your own RX frequency comes back when you leave the mode.
A last step, when nothing else has decoded.
MSHV looks for the Fox in three places — the receive frequency, a window around 750 Hz and the
whole band — and searches each one it finds. Here that is the last step of a Fox period: only
when everything above has found nothing, the search and the passes run again on each of MSHV's
candidates, each one only if it can end inside the RX budget, so that nothing decoded today comes any
later: a period that decodes without it costs exactly what it did. Since the search runs in threads the step
is cheap enough to be on by default; JTDX_SFOX_SYNC3=0 switches it off. The first real
recordings will say what it is worth on the air.
What the program does around the decoder.
K1ABC <VP2X/K1JT> RR73 from the next transmission on. A line with two long hashed calls keeps its report whole rather than cutting it.CALL.123456 free text, through the program's own network layer (which works without OpenSSL on Windows): VP8PJ verified on green or VP8PJ invalid on red. What is sent: the Fox's call, the time and the code — switch it off with DXpedition → Verify Fox online (OTP). More than one server can be listed, best first: a later one is asked only when every earlier one said it does not know the call, so no weaker server can overrule a better one.The same code, defined without the restricted table.
In WSJT-X the polar code's definition — which 50 of the 128 positions carry the message — sits in a file whose licence notice restricts it to WSJT-X. JTDX_contest does not ship that file. Its definition was measured from transmissions of WSJT-X's own transmit tool, and the tests rebuild it from nothing and check it against WSJT-X's decoder. It is the same code: every transmission decodes exactly as before.
Every addition is a setting until real recordings decide.
The decoder's recipe was worked out on simulated transmissions, so each of its choices is a setting, read from the environment when the decoder starts; the defaults are provisional and will be revisited with the first real recordings. A value that cannot be read stops the decoder with a message that names it — a setting is never silently ignored.
| setting | what it controls | default |
|---|---|---|
| JTDX_SFOX_NORM | the normalisation of tone bins that hold QRM (07); JTDX_SFOX_NORMX its threshold | on |
| JTDX_SFOX_THREADS | threads of the search (08): 0 = as many as the FT8 decoder, 1 = serial | as FT8 |
| JTDX_SFQRM | the FT8 step (09): 0 off, 1 the quick round only | both rounds |
| JTDX_SFOX_FLOOR | the floor for a Fox that is not known (10) | MSHV's |
| JTDX_SFOX_KNOWN | no floor for a known Fox (10) | on |
| JTDX_SFOX_AP | the a-priori pass (11); APFAM the message families, APFLOOR1/2 its floors, APLOOKS the forms of the spectra tried, APAGE how long a Fox is remembered | on |
| JTDX_SFOX_POOL | the pool pass (13); POOLL list size, POOLLOOKS, POOLCRC paths tried against the CRC, POOLFLOOR, POOLAGE how long a Hound stays | on |
| JTDX_SFOX_LIST | the list pass with the Fox told (14); LISTL, LISTLOOKS, LISTCRC, LISTFLOOR | on |
| JTDX_SFOX_LISTANY | its round with nothing told (14); LISTANYFLOOR, LISTANYLOOKS | on |
| JTDX_SFOX_SYNC3 | MSHV's three sync windows as the last step (16) | on |
Real signals.
Everything above has been tested against WSJT-X's own decoder, against MSHV's, and by a regression suite, on simulated transmissions and a few recordings. What it still lacks is the air: a reasonable number of recordings of real SuperFox operations, both periods, with Hounds calling. They will decide the defaults, what each step is worth, and the figures this page will then show.