Skip to main content

Overview

Receive mode (--rx) is the default operating mode of minimodem. It captures audio input (from a microphone, line-in, or audio file), analyzes the FSK (Frequency-Shift Keying) tones, and decodes them back into the original data.

Basic Receive Usage

1

Start minimodem

Simply specify the baud rate (—rx is the default):
minimodem 1200
Or explicitly use the receive flag:
minimodem --rx 1200
2

Present audio signal

Play the FSK audio through your speakers or provide an audio file:
minimodem --rx 1200 --file recording.wav
3

View decoded output

Decoded data appears on stdout, status messages on stderr:
### CARRIER 1200 @ 1200.0 Hz ###
HELLO WORLD
### NOCARRIER ndata=11 confidence=2.456 ampl=0.892 bps=1199.98 (rate perfect) ###

Command-Line Options

Receive mode is the default, but can be explicitly specified:
minimodem 1200

Carrier Detection

minimodem automatically detects when FSK carrier signals are present in the audio stream.

Carrier Acquisition

When a valid signal is detected, minimodem displays (src/minimodem.c:1336-1348):
### CARRIER 1200 @ 1200.0 Hz ###
This indicates:
  • Baud rate: 1200 bps
  • Mark frequency: 1200.0 Hz (the detected carrier frequency)

Carrier Loss

When the signal ends or becomes too weak, minimodem reports (src/minimodem.c:1469-1473):
### NOCARRIER ndata=45 confidence=2.234 ampl=0.756 bps=1199.92 (rate perfect) ###
ndata
integer
Number of data frames successfully decoded
confidence
float
Average signal-to-noise confidence level (higher is better)
ampl
float
Average signal amplitude (0.0 to 1.0 range)
bps
float
Actual measured data rate in bits per second
rate status
string
  • (rate perfect): Transmitter clock matches exactly
  • (0.5% fast): Transmitter clock is slightly fast
  • (1.2% slow): Transmitter clock is slightly slow

Auto-Carrier Detection

By default, minimodem uses fixed frequencies for the mark and space tones. Use --auto-carrier to automatically detect the carrier frequency:
# Automatically find the carrier frequency
minimodem --rx 1200 --auto-carrier

# Short form
minimodem --rx 1200 -a
When to use auto-carrier: Useful when the transmitter uses non-standard frequencies or when the signal is off-frequency due to radio tuning, Doppler shift, or transmitter drift.
Auto-carrier detection increases CPU usage and may take longer to acquire the signal. It’s not recommended for callerid mode.

Receive Processing Algorithm

minimodem uses a sophisticated FSK demodulation algorithm (src/minimodem.c:1014-1463):
1

Sample buffering

Reads audio samples into a circular buffer. Buffer size is automatically calculated based on frame length:
size_t samplebuf_size = ceilf(nsamples_per_bit) * (nbits+1) * 2;
2

FFT analysis

Uses Fast Fourier Transform to analyze frequency content and measure mark/space tone amplitudes at expected frequencies.
3

Frame detection

Scans for valid data frames by correlating the expected bit pattern (start bits, data bits, stop bits) with the received signal.
4

Confidence scoring

Each detected frame receives a confidence score based on signal-to-noise ratio:
  • Score > confidence_threshold (default 1.5): Valid frame
  • Score < confidence_threshold: Ignored as noise
5

Frame refinement

When carrier is first acquired or confidence drops, performs a fine-grained scan with 8 steps instead of 3 to find the optimal frame position.
6

Data extraction

Extracts data bits from the validated frame and passes them to the decoder (ASCII, Baudot, binary, etc.).

Confidence Threshold

The confidence threshold controls the receive sensitivity and noise rejection:
# Default threshold (1.5)
minimodem --rx 1200

# More sensitive (lower threshold) - accepts weaker signals
minimodem --rx 1200 --confidence 1.0

# Less sensitive (higher threshold) - rejects more noise
minimodem --rx 1200 -c 2.0

Low Threshold (< 1.5)

Pros: Decodes weaker signalsCons: More false decodes from noiseUse case: Marginal signals, distant stations

High Threshold (> 1.5)

Pros: Fewer false decodesCons: May miss valid weak signalsUse case: Strong signals, noisy environments

Confidence Search Limit

Controls the performance vs. quality tradeoff:
# Default limit (2.3)
minimodem --rx 1200

# Higher quality (slower, searches for best frame)
minimodem --rx 1200 --limit 5.0

# Higher performance (faster, accepts first good frame)
minimodem --rx 1200 -l 1.8
Performance Impact: The search limit dramatically affects CPU usage. Higher values search more thoroughly for the best frame position, improving quality on difficult signals at the cost of performance.

Practical Examples

Basic Reception

# Receive from microphone
minimodem 1200

# Save to file
minimodem 1200 > received.txt

# Quiet mode (no status messages)
minimodem 1200 --quiet > received.txt 2>/dev/null

Binary Data Reception

Receive and decode binary data:
# Receive binary data
minimodem --rx 1200 --binary-output > received.bin

# Receive Base64 encoded data and decode
minimodem 1200 | base64 -d > file.bin

# Receive and decompress
minimodem 1200 | gunzip > file.txt

Custom Frequencies

# Specify exact mark and space frequencies
minimodem --rx 1200 --mark 1200 --space 2200

# Inverted frequencies (for LSB/USB mode switching)
minimodem --rx 1200 --inverted

# Custom frequencies for non-standard modems
minimodem --rx 1200 --mark 1000 --space 2000

Bandwidth Control

Adjust the receive bandwidth for better performance:
# Narrow bandwidth (better noise rejection)
minimodem --rx 1200 --bandwidth 100

# Wide bandwidth (better for frequency-unstable signals)
minimodem --rx 1200 -b 300

# Very narrow (RTTY default is 10 Hz)
minimodem rtty --bandwidth 10
Bandwidth Selection: Narrower bandwidths provide better noise rejection but require more stable transmitter frequency. Wider bandwidths are more forgiving of frequency drift but allow more noise.

Advanced Receive Options

Decode Only One Carrier

Exit after decoding a single carrier:
# Receive one transmission and exit
minimodem --rx 1200 --rx-one
Useful in scripts where you want to capture a single transmission:
#!/bin/bash
data=$(timeout 30 minimodem --rx 1200 --rx-one --quiet 2>/dev/null)
if [ $? -eq 0 ]; then
    echo "Received: $data"
fi

Custom Data Formats

# 7-bit ASCII (rare)
minimodem --rx 1200 -7

# 5-bit Baudot
minimodem --rx 45.45 --baudot
minimodem --rx 45.45 -5

# Raw binary (custom bit count)
minimodem --rx 1200 --binary-raw 12

Filter Non-Printable Characters

Replace non-printable characters with periods:
minimodem --rx 1200 --print-filter

Sync Byte Detection

For protocols that use sync bytes:
# NOAA SAME format (weather radio)
minimodem --rx same

# Custom sync byte
minimodem --rx 1200 --sync-byte 0x55

Sample Rate Configuration

Higher sample rates provide better frequency resolution:
# Default 48 kHz
minimodem --rx 1200

# 96 kHz (better for weak signals)
minimodem --rx 1200 --samplerate 96000

# 8 kHz (minimum, faster processing)
minimodem --rx 1200 -R 8000
Minimum Sample Rate: The sample rate must be at least 2× the highest frequency component (Nyquist theorem). For Bell 202 (2200 Hz space tone), use at least 4400 Hz, but 48000 Hz is recommended.

Technical Details

Frame Scanning

minimodem scans the audio buffer looking for valid frames (src/minimodem.c:1236-1274):
// Scan with 3 steps across the try_max_nsamples range
#define FSK_ANALYZE_NSTEPS 3
unsigned int try_step_nsamples = try_max_nsamples / FSK_ANALYZE_NSTEPS;

// Fine-grained refinement with 8 steps
#define FSK_ANALYZE_NSTEPS_FINE 8

Amplitude Tracking

minimodem tracks signal amplitude with hysteresis (src/minimodem.c:1286-1288):
// No-confidence if amplitude drops to < 25% of tracked amplitude
if ( amplitude < track_amplitude * 0.25f ) {
    confidence = 0;
}

No-Confidence Counter

Carrier is declared lost after 20 consecutive frames with insufficient confidence (src/minimodem.c:1290-1313):
#define FSK_MAX_NOCONFIDENCE_BITS 20

if ( confidence <= fsk_confidence_threshold ) {
    if ( ++noconfidence > FSK_MAX_NOCONFIDENCE_BITS ) {
        // Carrier lost
    }
}

Output Format

Standard Output (stdout)

Decoded data bytes are written to stdout:
minimodem 1200 > output.txt

Standard Error (stderr)

Status messages appear on stderr:
# Capture only decoded data
minimodem 1200 2>/dev/null > data.txt

# Capture only status messages
minimodem 1200 > data.txt 2> status.log

# Suppress all status messages
minimodem 1200 --quiet > data.txt 2>/dev/null

Troubleshooting

Symptoms: No ### CARRIER ### message appearsSolutions:
  • Increase volume: Check input mixer levels
  • Lower confidence threshold: --confidence 1.0
  • Enable auto-carrier: --auto-carrier
  • Check frequencies: --mark 1200 --space 2200
  • Verify audio input: Test with audio file first
Symptoms: Random characters or binary garbageSolutions:
  • Verify baud rate matches transmitter
  • Check for frequency inversion: try --inverted
  • Reduce noise: --confidence 2.0
  • Adjust bandwidth: --bandwidth 100
  • Check sample rate: Use 48000 Hz
Symptoms: Carrier detected but data drops outSolutions:
  • Lower confidence threshold: --confidence 1.2
  • Increase search limit: --limit 3.0
  • Check audio buffer: CPU may be overloaded
  • Reduce noise at source
  • Use narrower bandwidth
Symptoms: NOCARRIER shows “2% fast” or “slow”Solutions:
  • Small deviations (< 2%) are normal and handled automatically
  • Large deviations indicate clock mismatch between transmitter/receiver
  • Verify both use same sample rate
  • Check for audio device timing issues
Symptoms: Process uses excessive CPUSolutions:
  • Reduce search limit: --limit 2.0
  • Use lower sample rate: --samplerate 48000
  • Disable auto-carrier if enabled
  • Use faster baudrate if possible

See Also

Build docs developers (and LLMs) love