@e04/ft8ts
v0.0.12
Published
FT8 encoder/decoder in pure TypeScript
Downloads
770
Readme
ft8ts
FT8/FT4 encoder and decoder in pure TypeScript. A port of the Fortran implementation from WSJT-X v2.7.0.
Overview
FT8/FT4 are digital amateur radio modes designed for weak-signal communication, developed by Joe Taylor (K1JT) and Steve Franke (K9AN).
This library provides pure TypeScript implementations of both encoding and decoding for FT8/FT4, suitable for use in Node.js or the browser.
Demo
Browser
https://e04.github.io/ft8ts/example/browser/index.html
CLI
# Decode WAV file (FT8 or FT4)
npx @e04/ft8ts decode foo.wav [--mode ft8|ft4] [--low 200] [--high 3000] [--depth 2]
# Encode message to WAV file
npx @e04/ft8ts encode "CQ JK1IFA PM95" [--out output.wav] [--df 1000]Benchmark
The benchmark below was compiled with reference to Comparing PyFT8 with WSJT-x and FT8_lib.
| Call a | Call b | Message | WSJT-x(default) | WSJT-x (fast) | PyFT8 | ft8_lib | ft8ts (depth=3) | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | W1FC | F5BZB | -8 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | WM3PEN | EA6VQ | -9 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | CQ | F5RXL | IN94 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | N1JFU | EA6EE | R-07 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | A92EE | F5PSR | -14 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | K1BZM | EA3GP | -9 | ☑️ | ☑️ | ☑️ | | ☑️ | | W0RSJ | EA3BMU | RR73 | ☑️ | ☑️ | ☑️ | | ☑️ | | K1JT | HA0DU | KN07 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | W1DIG | SV9CVY | -14 | ☑️ | ☑️ | ☑️ | | ☑️ | | K1JT | EA3AGB | -15 | ☑️ | ☑️ | ☑️ | | ☑️ | | XE2X | HA2NP | RR73 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | N1PJT | HB9CQK | -10 | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | | K1BZM | EA3CJ | JN01 | ☑️ | ☑️ | | | | | KD2UGC | F6GCP | R-23 | ☑️ | ☑️ | | | | | WA2FZW | DL5AXX | RR73 | ☑️ | | | | | | N1API | HA6FQ | -23 | ☑️ | | | | ☑️ | | N1API | F2VX | 73 | ☑️ | | | | ☑️ | | K1JT | HA5WA | 73 | ☑️ | | | | ☑️ | | CQ | EA2BFM | IN83 | ☑️ | | | | | | K1BZM | DK8NE | -10 | | | | | ☑️ |
At its maximum depth mode (Depth 3), it successfully decodes 16 messages on this sample (including 16/20 rows in the table above), outperforming both PyFT8 (12), FT8_lib (8), and WSJT-x FAST mode (14).
Installation
npm i @e04/ft8ts
Usage
API
import { encodeFT8, decodeFT8, encodeFT4, decodeFT4, HashCallBook } from "@e04/ft8ts";
// Encode a message to audio samples (Float32Array)
const samples = encodeFT8("CQ JK1IFA PM95", {
sampleRate: 12000,
baseFrequency: 1000,
});
// Create a HashCallBook to resolve hashed callsigns.
// Reuse the same instance across multiple decode calls so that
// callsigns learned from earlier frames can resolve hashes in later ones.
const book = new HashCallBook();
// Decode audio samples to messages
const decoded = decodeFT8(samples, {
sampleRate: 12000,
freqLow: 200,
freqHigh: 3000,
depth: 2,
hashCallBook: book,
});
for (const d of decoded) {
console.log(`${d.freq} Hz SNR ${d.snr} dB ${d.msg}`);
}FT4
import { encodeFT4, decodeFT4, HashCallBook } from "@e04/ft8ts";
// Encode FT4 message
const samples = encodeFT4("CQ JK1IFA PM95", {
sampleRate: 12000,
baseFrequency: 1000,
});
// Decode FT4
const book = new HashCallBook();
const decoded = decodeFT4(samples, {
sampleRate: 12000,
freqLow: 200,
freqHigh: 3000,
depth: 2,
hashCallBook: book,
});Decode Options
| Option | Default | Description |
|--------|---------|-------------|
| sampleRate | 12000 | Input audio sample rate (Hz) |
| freqLow | 200 | Lower frequency bound (Hz) |
| freqHigh | 3000 | Upper frequency bound (Hz) |
| syncMin | 1.2 | Minimum sync threshold |
| depth | 2 | Decoding depth: 1=fast BP only, 2=BP+OSD, 3=deep |
| maxCandidates | 300 (FT8) / 100 (FT4) | Maximum candidates to process |
| hashCallBook | — | HashCallBook instance for resolving hashed callsigns |
Build
npm run buildLicense
GPL-3.0
