Decoding

dsp
FT8
Author

Rob Bryan

Published

June 29, 2026

First decoded string

Getting readable text can be easy.
ASCII has done this well since 1963, but FT8 is a special case.
Each FT8 transmission window sends 77 bits of information, so if they used the 7-bit ASCII standard, each transmission could include up to 11 characters of text, which is not enough for two HAM radio operators with 6-character call signs to prove they have contacted each other by including both call signs in a single transmission.

NoteThe principle of the thing

Because we went through a LOT of effort to transmit, receive, and mathematically verify the accuracy of these precious 77 bits of information, it’s worth the effort to get as much value as possible out of each bit.

Custom encoding

FT8 uses a binary-to-text system that isn’t used anywhere else in the world.
3 bits are used to define the “message type”.
One message type also has subtypes.
For each message type - subtype combination, there is a specific way the remaining bits are sliced into fields, and each field has it’s own custom binary-to-text decoding system.
There are 23 distinct fields in FT8, each of which has a different way to convert binary bits to text.

Time sink

I expected the 3 bits that define the message type to be at the start of the stream of 77 bits.
The paper is not specific about this.
As it turns out, they’re at the end.
That took me a long time to figure out.
I didn’t measure, so I don’t know exactly how much, but my guess is it was 6 to 8 hours of work time.

Manual decoding

After establishing the message type and subtype, I manually sliced the stream of bits and manually decoded one segment of those bits into a callsign that matched a callsign in the decoded reference.

That proved, for the first time, that my solution could work end-to-end.
That was Friday morning, June 26, 2026.

Automatic decoding

I spent the weekend automating the decoding and putting a few measures in place to track my progress.

In the 20-minute reference recording, there are 113 messages.
I correctly decode 8 of them. (7%)
I get partial, incorrect decodes on another 17 messages. (15%)
The rest (78%), I miss entirely.

Also, my code takes 7 minutes and 2 seconds (422 seconds) to process 20 minutes of audio.
That’s too slow by a factor of 2.
Since each 15-second transmission window includes 2.4 seconds of silence to allow for decoding, a 20-minute recording has 80 windows, and at 2.4 seconds each, that’s 192 seconds of processing time.

AI

Socratic mode is working well for me.
It hasn’t solved a single problem during this project, which is exactly what I wanted.
It hasn’t generated a single fragment of code at all, not one symbol.
When it reviews my code, it responds with questions, like: - “How many times does the inner loop run?” - “What different methods have you tried for finding the intersection of these sets?” - “How does Python ‘join’ convert lists to strings?”

I’m not even mad that it let me struggle all day with my incorrect assumption that the message type identifier was at the beginning of the bit stream before it finally asked, “Is the FT8 specific about where the message type identifier is?”