This repository contains the source code for PyFT8, an all-Python open source FT8 transceiver that you can run as a basic GUI or from the command line to receive and transmit. Decoding performance (number of decodes) is about 70% of that achieved by WSJT-x in NORM mode, but (tbc) slightly above ft8_lib. At the time of writing (3-3-26) this new version 2.0.0 establishes the prior cli functionality plus an interesting GUI, on which I intend to build a transceiver function shortly.
PyFT8 is somewhat experimental, with a focus on demonstrating FT8 written in Python, but can be used as a standalone replacement for WSJT-x and other software. However, please see Rig control below.
- Doesn't try to do everything, so launches quickly (~2 seconds on my old Dell Optiplex 790)
- use with or without gui (receive and send messages via command line commands)
- GUI provides simultaneous views of odd and even cycles
- messages overlaid on waterfall signals that produce them
- automatically chooses clearest Tx frequency
- modern programming language throughout
- finds sound cards by keywords so follows them if windows moves them ...
This started out as me thinking "How hard can it be, really?" after some frustration with Windows moving sound devices around and wanting to get a minimal decoder running that I can fully control.
I didn’t want to produce yet another port of the original Fortran / C into another language: instead I wanted to see how far I could get following audio -> spectrogram -> symbols -> bits -> error correction without resyncs and special treatments, writing my own code from scratch as far as possible. Also this has been, more than I expected, an exercise in writing Python ‘Pythonically’ for speed, which means absolutely not duplicating the big nested loops of Fortran and C. It also means writing code that is wide and short rather than thin and long, which suits my thinking style perfectly!
If you want to install this software without getting into the code, you can install from PyPI using pip install, using
pip install PyFT8
Once installed, you can use the following commands to run it. Otherwise, please download or browse the code, or fork the repo and play with it! If you do fork it, please check back here as I'm constantly (as of Jan 2026) rewriting and improving.
| Usage | Command example | Notes |
|---|---|---|
| Basic Rx GUI | pyft8 -i "Keyword1, Keyword2" | Keywords identify the input sound device - partial match is fine, e.g. "Mic, CODEC" |
| GUI with transmit | pyft8 -i "Keyword1, Keyword2" -o "Keyword1, Keyword2" | Keywords identify the input (-i) and output (-o) sound devices. The transmit parts are under development. |
| Command line Rx without a GUI | pyft8 -i "Keyword1, Keyword2" -n | |
| Command line transmit | pyft8 -o "Keyword1, Keyword2" -m "CQ G1OJS IO90" | Tx on next cycle. You supply the PTT control method. |
| Command line create a wav file | pyft8 -w "Mywav.wav" -m "CQ G1OJS IO90" | -w "Mywav.wav" can be omitted |
| Launch configured GUI | pyft8 -i "Keyword1, Keyword2" -o "Keyword1, Keyword2" -c {config folder} | Config folder stores PyFT8.ini (your callsign, grid, buttons) and PyFT8.adi log file. Run this once to create default PyFT8.ini file. |
PyFT8 doesn't currently support CAT control for rigs in general. However, I've included the Python code that I use with my Icom IC-7100 in the file 'rigctrl.py'. You can modify this to control your own rig of course if you know Python.
Alternatively, you can run PyFT8 without rig control; if there is no rig found, PyFT8 defaults to running without a rig connected. In this case, you need to provide your own PTT method and note that the band buttons will only set the information used for logging QSOs to the PyFT8.adi file. Or you can use PyFT8 as Rx-only.
The image below shows the number of decodes from PyFT8, WSJT-x V2.7.0 running in NORM mode, and FT8_lib, using the same 10 minutes of busy 20m audio that is used to test ft8_lib.
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 fewer decodes than WSJT-x gets, depending on band conditions (on a quiet band with only good signals PyFT8 will get close to 100%).
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. (*1 note: applies to FT8 pre V2)
The QEX paper
Note - section 9 of the QEX paper states that the above two WSJT-X resources are in the public domain, with some restrictions. All other WSJT-X resources including the WSJT-X source code are protected by copyright but licensed under Version 3 of the GNU General Public License (GPLv3).
WSJTx - focussed:
- WSJT-X on Sourceforge
- W4KEK WSJT-x git mirror (searchable)
Other FT8 decoding repos:
- weakmon
- FT8_lib
- 'ft8modem - a command-line software modem for FT8' including source code (C++ and Python) (bottom of page)
FT8 decoding explorations / explanations
- VK3JPK's FT8 notes including comprehensive Python source code
- G4JNT notes on LDPC coding process
FT8 decoding in hardware
- Optimizing the (Web-888) FT8 Skimmer Experience (see also RX-888 project )
- 'DX-FT8-Transceiver' source code, the firmware part of the DX-FT8 Transceiver project
FT8 encode/decode simulators:
Browser-based decoder/encoders
- ft8js - source github, uses FT8_lib
- ChromeFT8 Browser Extension, decoder adapted from ft8js