Skip to content

jbirby/WEFAX-Codec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WEFAX Codec

Encode images into WEFAX (Weather Facsimile) HF radiofax audio WAV files, and decode WEFAX recordings back into images per WMO standards.

WEFAX is fundamentally different from telephone fax (Group 3 ITU-T T.4). While Group 3 fax uses DPSK (Differential Phase Shift Keying) modulation over telephone lines at 2400 bps with complex Huffman compression, WEFAX uses simple FM (Frequency Modulation) over HF radio with no compression—each pixel's value is directly encoded as a frequency.

Features

  • Encode: Convert images (PNG, JPEG, etc.) to WEFAX WAV files
  • Decode: Recover images from WEFAX transmissions (recordings)
  • Standard compliant: WMO standards, IOC 576/288, RPM 120/60
  • FM modulation/demodulation: Continuous-phase FM with proper frequency mapping
  • Auto-detection: Automatically detects and skips start/stop tones and phasing signal
  • Flexible: CLI tools for integration into workflows or GUIs

Who Uses WEFAX?

  • NOAA (National Oceanic and Atmospheric Administration) — Broadcasts synoptic weather charts on HF
  • JMH (Japan Meteorological Agency / Kishōchō) — Japanese maritime weather charts
  • DWD (Deutscher Wetterdienst) — German weather service
  • Other national meteorological services — China, Russia, Australia, etc.

Quick Start

Installation

pip install numpy Pillow
cd scripts/

Encoding: Image to WEFAX WAV

python3 wefax_encode.py weather_map.png output.wav -v

Options:

  • --ioc 576 (default) or --ioc 288 — Resolution (Index of Cooperation)
  • --rpm 120 (default) or --rpm 60 — Transmission speed
  • --no-start-stop — Omit start/stop tones and phasing (image data only)
  • -v / --verbose — Print progress

Decoding: WEFAX WAV to Image

python3 wefax_decode.py recording.wav weather_map.png -v

Options:

  • --ioc 576 (default) or --ioc 288 — Must match encoding
  • --rpm 120 (default) or --rpm 60 — Must match encoding
  • --no-auto-detect — Don't auto-detect start/stop tones (use all audio)
  • -v / --verbose — Print progress

Signal Structure

A complete WEFAX transmission:

[300 Hz]     [Black/White Bars]    [FM Image Data]       [450 Hz]
  5 sec          30 sec            variable duration      5 sec
  (Start)       (Phasing signal)    (Scan lines)          (Stop)

FM Modulation:

Frequency (Hz) = 1500 + (PixelValue / 255) × 800

Black (0)     → 1500 Hz
Gray (127)    → 1900 Hz (center)
White (255)   → 2300 Hz

Technical Parameters

Parameter Standard Alternative
IOC 576 (1809 px/line) 288 (904 px/line)
RPM 120 60
Line Period 0.5 sec 1.0 sec
Black Freq 1500 Hz
Center Freq 1900 Hz
White Freq 2300 Hz
FM Deviation ±400 Hz
Start Tone 300 Hz (5 sec)
Stop Tone 450 Hz (5 sec)
Phasing 30 sec (black/white)
Sample Rate 44,100 Hz

Examples

Basic Encoding

# Standard settings (IOC 576, 120 RPM)
python3 wefax_encode.py weather_map.png output.wav

# Low resolution (half the detail, shorter transmission)
python3 wefax_encode.py weather_map.png output_lowres.wav --ioc 288

# Slow transmission (better for weak signals)
python3 wefax_encode.py weather_map.png output_slow.wav --rpm 60

# Just the image data, no tones
python3 wefax_encode.py weather_map.png output_noheader.wav --no-start-stop

Basic Decoding

# Standard settings
python3 wefax_decode.py recording.wav decoded_map.png

# With full debugging
python3 wefax_decode.py recording.wav decoded_map.png -v

# Don't auto-detect tones (use all audio as image)
python3 wefax_decode.py recording.wav decoded_map.png --no-auto-detect

# Match encoding parameters
python3 wefax_decode.py recording_lowres.wav map.png --ioc 288
python3 wefax_decode.py recording_slow.wav map.png --rpm 60

Batch Processing

# Encode all PNGs in a folder
for img in weather/*.png; do
  python3 wefax_encode.py "$img" "${img%.png}.wav"
done

# Decode all WAV files
for wav in broadcasts/*.wav; do
  python3 wefax_decode.py "$wav" "${wav%.wav}.png" -v
done

How It Works

Encoding

  1. Load image (any PIL format) and convert to grayscale (0–255)
  2. Resize to IOC-appropriate width:
    • IOC 576 @ 120 RPM: 1809 pixels wide
    • IOC 288 @ 120 RPM: 904 pixels wide
  3. Generate audio stream:
    • Start tone: Pure 300 Hz sine, 5 seconds
    • Phasing signal: Repeating black/white pattern, ~30 seconds
    • Image data: FM-modulate each pixel to a frequency, one line per 0.5 seconds
    • Stop tone: Pure 450 Hz sine, 5 seconds
  4. Write 16-bit mono WAV file at 44,100 Hz sample rate

FM Modulation Detail:

  • Each pixel value is mapped linearly to a frequency (0→1500 Hz, 255→2300 Hz)
  • The modulation maintains continuous phase (no jumps), simulating real FM radio
  • Phase is integrated from instantaneous frequency: phase(n) = 2π ∑ freq[i] / fs

Decoding

  1. Read WAV file (automatically resamples to 44,100 Hz if needed)
  2. Auto-detect transmission boundaries (optional):
    • Locate start tone (300 Hz) and skip
    • Skip phasing signal (~30 sec)
    • Locate stop tone (450 Hz) and truncate
  3. FM demodulate to recover instantaneous frequency:
    • Use analytic signal (Hilbert transform) to extract phase
    • Compute phase derivative: freq[n] = phase'[n] × fs / (2π)
    • Low-pass filter to reduce noise
    • Downsample to pixel rate
  4. Map frequencies back to pixel values: pixel = (freq − 1500) / 800 × 255
  5. Reshape into image and save as PNG

Dependencies

  • numpy — Signal processing, numeric arrays
  • scipy — Scientific computing (Hilbert transform for FM demodulation)
  • Pillow (PIL) — Image loading/saving
  • wave — Standard library WAV file I/O (no install needed)

Install:

pip install numpy scipy Pillow

WEFAX vs. Other Codecs

Aspect WEFAX Group 3 Fax APT SSTV
Domain HF Radio Telephone Satellites Amateur Radio
Modulation FM DPSK AM FM
Compression None Huffman (Modified) None Various
Resolution 1809×N px 1728×2376 px 480×2400 px Mode-dependent
Speed ~0.5 sec/line ~3 sec/page 12.5 min (full pass) ~3 min (Martin M1)
Use Case Weather charts Office documents Satellite imagery Amateur images

Standards and References

Known Limitations

  1. Single-image only — WEFAX transmits one image per transmission (no multiple images per WAV)
  2. Grayscale only — WEFAX is inherently monochrome
  3. Line synchronization — Assumes perfect timing; very long lines may drift
  4. Noise sensitivity — FM demodulation requires reasonable SNR; very noisy recordings may decode poorly
  5. Frequency drift — Real HF transmissions may drift slightly; decoder assumes stable frequency

Testing

A roundtrip test is included in wefax_common.py:

python3 wefax_common.py

This tests:

  • FM modulation and demodulation
  • Pixel recovery accuracy
  • Configuration parsing

Example output:

Roundtrip test results:
  Test pixels: 1809
  MSE: 45.23 (0.07%)
  Max error: 3 levels
  PASS

File Structure

wefax/
├── scripts/
│   ├── wefax_common.py    # Shared constants, FM modulation/demodulation, utilities
│   ├── wefax_encode.py    # CLI encoder: image → WAV
│   └── wefax_decode.py    # CLI decoder: WAV → image
├── SKILL.md               # Skill description (for Claude integration)
└── README.md              # This file

Troubleshooting

Q: Decoded image is all black or all white

  • The FM demodulation may not be finding the right frequency range
  • Verify the audio sample rate (should be 44,100 Hz)
  • Check IOC and RPM settings
  • Try --no-auto-detect to skip tone detection

Q: Image is stretched or wrong dimensions

  • IOC determines width; height is determined by how many lines of audio you have
  • If you want a specific aspect ratio, pre-crop your source image

Q: Audio playback sounds like "wavy" tones

  • That's correct! FM of 1500–2300 Hz will sound like a descending or ascending tone as the frequency changes
  • If you play the audio on an SSB (single-sideband) radio, it will demodulate back to the image

Q: Decoding is slow

  • Frequency estimation involves Fourier transforms for each window
  • A 30-second transmission might take 10–30 seconds to decode
  • This is normal and depends on your CPU

License

MIT License — Feel free to use, modify, and distribute.

Related Projects

  • APT Codec — Decode NOAA satellite pictures (APT format)
  • SSTV Codec — Amateur radio image transmission (Martin/Scottie/Robot modes)
  • RTTY Codec — Radioteletype text (Baudot/ITA2)
  • Data Modem — FSK binary file transmission
  • Fax Codec — ITU-T T.4 telephone fax (Group 3)

Questions?

See SKILL.md for detailed usage, encoding/decoding steps, and technical details.

About

Encode images into WEFAX (Weather Facsimile) HF radiofax audio WAV files, and decode WEFAX recordings back into images per WMO standards.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages