Skip to content

G1OJS/PyFT8

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PyFT8 PyPI Downloads

FT8 Decoding and Encoding in Python with CLI and test/loopback code

This repository contains Python code to decode and encode FT8, plus a minimal command line interface for reception.

Its primary purpose is as a personal project, but should also be useful if you want to browse the code or use the CLI.

CLI

PyFT8 can be installed using

pip install PyFT8

and you can use

PyFT8_cli "Keyword1, Keyword2" [-c]

to run the CLI where Keywords specify the input sound device (e.g. "Mic, CODEC") and -c means 'concise' output. Output will appear in the command window when audio is received via the specified sound device.

You can also transmit FT8 using PyFT8 as follows. When launching the program, use

PyFT8_cli "Keyword1, Keyword2" [-c] -o "Keyword3, Keyword4"

where "Keyword3, Keyword4" specify the output sound device. Then, when you want to transmit a message, dump a file called 'PyFT8_tx_msg.txt' in the directory you launched from. The contents of this file should be for example:

CQ G1OJS IO90

with, optionally, a second line to specify the Tx audio frequency:

CQ G1OJS IO90
888

PyFT8 will wait for the next cycle boundary, and the file will be deleted during the transmit cycle. If you want to transmit via a transceiver, you will have to organise your own method of controlling the PTT (e.g. [DATA]VOX, or sending your own CAT commands).

Test scripts

Below are some screenshots from test programs that can be used to look at how the protocols actually work, illustrated with a fairly ordinary waterfall and some zoomed-in depictions of captured signals with an overlay of the syncrhonisation tones that are used to search for the signals (Costas patterns). To try these scripts, download the Python from this repository (clone, download raw etc) and run in your chosen environment.

waterfall candidate detail

Approach

You won't find many comments in the code; I try to make things as obvious as possible via variable names and logical structure, to minimise the need for comments. Also - this is mainly my plaything, and I find bloated, sprawling code incredibly difficult to read, so I like to keep things very compact so that I can see the bigger picture. If you find an if-then-else spanning several paragraphs, it's probably a mistake.

Do feel free to get in touch and ask how anything works. I might add some diagrams etc at some point too - especially if I find an approach that seems to offer something improved and/or very compact (I'm very pleased for e.g. that the entire candidate search, synch, and demodulate process all works by refering to a single time-frequency grid; read the audio, FFT 5 times for each symbol duration, store it, and that's used for everything that follows.)

Limitations

In pursuit of tight code, I've concentrated on core standard messages, leaving out some of the less-used features. The receive part of the code doesn't (yet) have the full capability of the advanced decoders used in WSJT-x, and so gets only about 50% of the decodes that WSJT-x gets.

Here's my current understanding of the differences:

Step PyFT8 WSJT-X
Find candidate signals Search every possible time/frequency offset for match with the Costas pattern, excluding times where candidates would not complete before the next cycle (i.e. first few seconds of the grid) TBD
Syncronise signals in time See above TBD
Use of FFTs for the above A single time-frequency grid with 5 time samples per symbol and 3 frequency samples per tone Several FFTs per operation, details in VK3JPK's great write-up here
Demodulation Extract 1 sample per symbol, 1 sample per tone grid. Correlate each symbol with Gray code to create Log Likelyhood Ratios for each bit. Noncoherent block detection over 3 symbols - creates LLRs by correlating the 512 possible tone sequences (3 symbols with 8 possible tones each) with the actual received symbols. This is done in the frequency domain by combining the whole-symbol correlations already calculated.
Decoding the FEC code Belief Propagation LDPC decoder Belief Propagation LDPC decoder
Further decoding if LDPC fails None Ordered Statistics Decoding
Further signal extraction None Subtraction of the idealised power of the decoded signals, then rescanning the residual spectrum. Further synchronisation adjustments TBC

Acknowledgements

This project implements a decoder for the FT8 digital mode. FT8 was developed by Joe Taylor, K1JT, Steve Franke, K9AN, and others as part of the WSJT-X project. Protocol details are based on information publicly described by the WSJT-X authors and in related open documentation.

Some constants and tables (e.g. Costas synchronization sequence, LDPC structure, message packing scheme) are derived from the publicly available WSJT-X source code and FT8 protocol descriptions. Original WSJT-X source is © the WSJT Development Group and distributed under the GNU General Public License v3 (GPL-3.0), hence the use of GPL-3.0 in this repository.

Also thanks to Robert Morris for:

  • basicft8(*1) - the first code I properly read when I was wondering whether to start this journey
  • weakmon - much good information

(*1 note: applies to FT8 pre V2)

Other useful resources:

<script data-goatcounter="https://g1ojs-github.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>

About

Minimal Python code for processing FT8 - for understanding and re-use

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages