Skip to content
pschatzmann edited this page Oct 29, 2026 · 2 revisions

Binary phase shift keying of a single carrier like PSK31, the keyboard chat mode of amateur radio: a 0 bit is a phase reversal, a 1 bit keeps the phase. The amplitude of a phase reversal follows a cosine, so the signal is very narrow. The characters are sent with the Varicode of PSK31, in which frequent characters have short codes; the characters are separated by "00".

Two variants of fldigi are supported as well:

  • QPSK (qpsk31 to qpsk500): each bit is encoded by a convolutional code (rate 1/2, K=5) into one of 4 phase steps (0, 90, 180 or 270 degrees). Same speed as BPSK, but the receiver corrects errors with a soft decision Viterbi decoder.
  • 8PSK (8psk125 to 8psk1000): 3 bits per symbol as phase steps of 45 degrees, without error correction, with the MFSK Varicode. Three times as fast as BPSK at the same symbol rate, but it needs a much better signal.

Advantages

  • Very narrow band: about 60 Hz for PSK31, so many signals fit into one audio channel.
  • Very robust against noise, efficient for text.
  • The decoder needs little CPU.
  • The receiver tracks the frequency of the signal (automatic frequency control) and the symbol timing.
  • The format of PSK31 to PSK500, QPSK31 to QPSK500 and 8PSK125 to 8PSK1000 (without FEC) of fldigi. The tables, the constellations and the convolutional code are taken from fldigi's source code, but the interoperability has not been tested with fldigi itself.

Disadvantages

  • Slow: PSK31 transmits about 4 characters per second.
  • The Varicode is optimized for text: binary data is slower, because bytes above 127 have codes of up to 12 bits (fldigi's extension of the Varicode).
  • The receiver only finds a signal whose frequency is close to the carrier: ±10 Hz for PSK31 and ±30 Hz for PSK125 were tested, ±14 Hz and ±45 Hz failed.
  • Phase distortions of the audio path (e.g. strong echoes) cause errors.

Modes

Mode Symbols/s Bandwidth Text
psk31 31.25 about 60 Hz about 4 characters/s
psk63 62.5 about 125 Hz about 8 characters/s
psk125 125 about 250 Hz about 17 characters/s
psk250 250 about 500 Hz about 34 characters/s
psk500 500 about 1000 Hz about 68 characters/s
qpsk31 … qpsk500 31.25 … 500 like BPSK like BPSK, with error correction
8psk125 125 about 250 Hz about 40 characters/s
8psk250 250 about 500 Hz about 80 characters/s
8psk500 500 about 1000 Hz about 160 characters/s
8psk1000 1000 about 2000 Hz about 320 characters/s

The carrier is at 1000 Hz by default: 8psk500 and 8psk1000 raise it to twice the symbol rate (1000 and 2000 Hz). The 8PSK modes of fldigi with FEC (8psk125f etc.) are not supported: their K=16 Viterbi decoder needs too much CPU and memory for a microcontroller. In 8PSK the character 0 is the idle signal and is not provided by the receiver.

Usage

I2SStream i2s;
PSKStream modem(i2s, RXTX_MODE);

void setup() {
  PSKConfig cfg = modem.defaultConfig();  // psk31
  cfg.setMode("psk125");
  cfg.sample_rate = 8000;
  ...
  modem.begin(cfg);
}
echo "CQ CQ de N0CALL" | tinymodem --tx -f cq.wav psk31
tinymodem --rx -f cq.wav psk31

PSKConfig, PSKEncoder, PSKDecoder, PSKStream and PSKStreamRTOS are the PSK classes. On the command line, -R, -v, -M (carrier frequency), -q, --rx-one, --packets and --Xrxnoise are supported. --tx-carrier sends phase reversals, the idle signal of PSK31.

PSKConfig field Default
symbol_rate 31.25 Symbols per second
modulation BPSK BPSK, QPSK or PSK8 (set by the mode)
carrier_freq 1000 Carrier frequency (Hz)
volume 1.0 Transmit amplitude
preamble_symbols 32 Phase reversals before the data
postamble_symbols 32 After the data: steady carrier (BPSK, 8PSK), encoded 0 bits (QPSK)
afc true Receiver: automatic frequency control
min_amplitude 0.005 Receiver: minimum signal level
rx_one false Receiver: stop after the first transmission
channel 0 Receiver: input channel
sample_rate, channels, bits_per_sample 48000, 1, 16 Audio format

How it works

A transmission starts with phase reversals (the PSK31 idle signal), followed by the Varicode characters. It ends with a steady carrier (QPSK: encoded 0 bits, which flush the convolutional code) and a fade out. Each symbol is a phase step from fldigi's table (180 degrees + n × 22.5 degrees): the I/Q signal moves from the previous to the new constellation point with a cosine shaped transition, like fldigi.

The receiver mixes the signal to the baseband and integrates it over one symbol. The decision time is the center of the energy distribution over the symbol period (like fldigi), and exactly one decision is made per symbol. The bit is determined from the phase difference to the previous symbol. Before a transmission, the receiver expects phase reversals, which allows a frequency capture range of about ±0.37 × the symbol rate. During a transmission, the frequency is tracked with the decisions. The receiver starts after a run of 8 phase reversals and stops when the signal is lost or after 20 symbols without phase change (BPSK and 8PSK).

QPSK: the receiver correlates the phase difference with the 4 possible phase steps and feeds these soft metrics to a Viterbi decoder (16 states, 32 symbols trace back), whose output bits are Varicode decoded. 8PSK: the phase difference is rounded to the nearest of 8 positions, and the 3 bits are MFSK Varicode decoded (a character ends with "001"). The integration over half a symbol reduces the interference with the neighboring symbols. Characters which are received during a steady carrier are held back, so the postamble is not shown as spaces.

Measured performance

Loopback with the unit tests at 8000 Hz:

Without errors up to
Noise (PSK31, PSK125) 1.0 (about 1.8 dB signal-to-noise ratio)
Frequency offset ±10 Hz (PSK31), ±30 Hz (PSK125)
Clock difference of sender and receiver ±1%
QPSK (qpsk31, qpsk125) 8PSK (8psk125) 8PSK (8psk500)
Noise without errors 1.0 0.5 0.1
Frequency offset ±6 Hz (qpsk31) ±12 Hz
Clock difference ±0.5% ±0.5% (8psk250)

On a PC at 8000 Hz, the decoder ran 3000 to 7000 times faster than real time (8PSK 2000 times). The receiver's "signal present" check compares the signal with the total power of the input, which limits all PSK modes at about the same noise level: the advantage of the QPSK error correction is therefore small in these tests.

Clone this wiki locally