| name | wefax-codec |
| description | Encode images into WEFAX (Weather Facsimile) HF radiofax audio WAV files and decode WEFAX recordings back into images. Supports IOC 576/288 at 120/60 RPM per WMO standards. Use this skill whenever the user mentions WEFAX, weather fax, radiofax, HF fax, weather map transmission, marine weather charts, NOAA radiofax, JMH, or wants to convert images to/from the FM audio format used for HF weather chart broadcasts. Also trigger when the user has a WAV file recorded from a shortwave weather fax broadcast and wants to extract the weather map image. Distinct from the fax-codec skill which handles telephone Group 3 fax — WEFAX uses FM modulation on HF radio, not DPSK on telephone lines. Covers encoding (image to WAV) and decoding (WAV to image).
|
WEFAX Codec Skill
Quick Reference
What is WEFAX?
HF Weather Facsimile (radiofax) is an international standard for broadcasting weather maps and charts over shortwave radio. Used by NOAA, Japan Meteorological Agency (JMH), Deutscher Wetterdienst (DWD), and many others. Images are transmitted as FM-modulated audio signals.
Key specs:
- IOC (Index of Cooperation): 576 standard, 288 low-resolution
- RPM: 120 standard, 60 slow
- Frequencies: 1500 Hz (black), 2300 Hz (white), 1900 Hz (center)
- Sample rate: 44,100 Hz (CD quality)
- Line period: 0.5 seconds at 120 RPM, 1 second at 60 RPM
Encode: Image → WEFAX WAV
python3 wefax_encode.py weather_map.png output.wav [--ioc 576] [--rpm 120]
Decode: WEFAX WAV → Image
python3 wefax_decode.py recording.wav weather_map.png [--ioc 576] [--rpm 120]
Signal Structure
A complete WEFAX transmission has five parts:
-
Start tone (300 Hz, 5 seconds)
- Signals the beginning of the transmission
-
Phasing signal (30 seconds)
- Alternating black/white bars (2.5% black, 97.5% white)
- Allows receiving equipment to synchronize line start position
-
Image data (variable duration)
- FM-modulated scan lines (pixels)
- Each scan line transmitted left to right, top to bottom
- Frequency → Pixel value: 1500 Hz = black (0), 2300 Hz = white (255)
-
Stop tone (450 Hz, 5 seconds)
- Signals the end of transmission
-
Guard band (optional)
- Silence or filler before next transmission
Signal diagram:
Time →
[300Hz] [Black/White] [FM Image Data] [450Hz]
5s 30 sec variable 5s
FM Modulation:
- Center frequency: 1900 Hz
- Black pixels (0): 1500 Hz
- White pixels (255): 2300 Hz
- Continuous-phase frequency modulation
- Deviation: ±400 Hz from center
How to Use This Skill
Encoding: Image to WEFAX WAV
Basic usage:
python3 wefax_encode.py weather_map.png output.wav -v
Common options:
python3 wefax_encode.py map.jpg output.wav
python3 wefax_encode.py map.jpg output.wav --ioc 288
python3 wefax_encode.py map.jpg output.wav --rpm 60
python3 wefax_encode.py map.jpg output.wav --no-start-stop
python3 wefax_encode.py map.jpg output.wav -v
Image requirements:
- Any PIL-supported format (PNG, JPEG, GIF, BMP, etc.)
- Converted to grayscale (0-255 per pixel)
- Resized to IOC-appropriate width (1809 pixels for IOC 576)
Decoding: WEFAX WAV to Image
Basic usage:
python3 wefax_decode.py recording.wav weather_map.png -v
Common options:
python3 wefax_decode.py recording.wav output.png
python3 wefax_decode.py recording.wav output.png --ioc 288
python3 wefax_decode.py recording.wav output.png --rpm 60
python3 wefax_decode.py recording.wav output.png --no-auto-detect
python3 wefax_decode.py recording.wav output.png -v
Detection features:
- Auto-detects and skips start tone (300 Hz)
- Auto-detects and skips phasing signal (30 sec)
- Auto-detects and skips stop tone (450 Hz)
- Can be disabled with
--no-auto-detect
Encoding
Step-by-step
- Load image — Any PIL format (PNG, JPEG, etc.)
- Convert to grayscale — 0 (black) to 255 (white)
- Resize — Match IOC resolution
- IOC 576 @ 120 RPM: 1809 pixels wide
- IOC 288 @ 120 RPM: 904 pixels wide
- Generate audio:
- Start tone: pure 300 Hz sine wave, 5 seconds
- Phasing: repeating black/white line, 30 seconds
- Image: FM modulate pixel → frequency, one line per 0.5s (120 RPM)
- Stop tone: pure 450 Hz sine wave, 5 seconds
- Write WAV — 16-bit mono, 44,100 Hz sample rate
FM Modulation Details
Each pixel value is mapped to a frequency:
Frequency = 1500 Hz + (pixel_value / 255) × 800 Hz
pixel 0 (black) → 1500 Hz
pixel 127 (gray) → 1900 Hz (center)
pixel 255 (white) → 2300 Hz
The FM signal maintains continuous phase (no phase discontinuities) as the frequency changes, simulating the smooth waveform of analog radio transmission.
Decoding
Step-by-step
- Read WAV file — Automatically resamples to 44,100 Hz if needed
- Auto-detect boundaries (optional)
- Detect start tone end
- Skip phasing signal (30 sec)
- Detect stop tone start
- FM demodulate
- Compute instantaneous frequency from phase derivative
- Low-pass filter to smooth estimates
- Downsample to pixel rate
- Recover pixel values
- Map frequency back to pixel:
pixel = (freq - 1500) / 800 × 255
- Clamp to 0–255 range
- Reconstruct image
- Reshape pixel array into (height, width)
- Convert to grayscale PNG
FM Demodulation Details
- Uses analytic signal (Hilbert transform) to extract phase
- Computes phase derivative to get instantaneous frequency
- Low-pass filtering to reduce noise and smooth frequency estimates
- Downsampling to pixel rate (based on IOC and line period)
- Frequency → pixel mapping:
pixel = (freq - 1500) / 800 × 255
Typical Workflow
Scenario 1: Encode a weather map
python3 wefax_encode.py weather_map.png output.wav -v
Scenario 2: Decode a shortwave recording
python3 wefax_decode.py recording.wav weather_map.png -v
python3 wefax_decode.py recording.wav weather_map.png --no-auto-detect
Scenario 3: Batch processing
for img in weather_maps/*.png; do
python3 wefax_encode.py "$img" "${img%.png}.wav"
done
for wav in recordings/*.wav; do
python3 wefax_decode.py "$wav" "${wav%.wav}.png" -v
done
Scenario 4: Custom resolution/speed
python3 wefax_encode.py detailed_chart.png output.wav --ioc 288
python3 wefax_encode.py map.png output_slow.wav --rpm 60
python3 wefax_decode.py output.wav decoded_standard.png
python3 wefax_decode.py output_slow.wav decoded_slow.png --rpm 60
Dependencies
Python packages:
numpy — Numeric computation, signal processing
scipy — Scientific computing (Hilbert transform for FM demodulation)
Pillow (PIL) — Image loading/saving
wave — Standard library WAV I/O
Install:
pip install numpy scipy Pillow
System requirements:
- Python 3.6+
- CD-quality audio playback/recording (44,100 Hz)
Technical Details
Index of Cooperation (IOC)
IOC defines the horizontal resolution (pixels per line):
IOC × Line Period = Pixels Per Line × π
IOC 576 @ 120 RPM (0.5s line): 1809 pixels/line
IOC 288 @ 120 RPM (0.5s line): 904 pixels/line
IOC 576 @ 60 RPM (1.0s line): 3618 pixels/line
Higher IOC = more pixels per line = finer detail, but longer transmission time.
RPM and Line Period
Line Period = 60 / RPM seconds
120 RPM: 0.5 seconds per line
60 RPM: 1.0 second per line
Line period determines how long each scan line takes to transmit.
Frequency Mapping
WEFAX uses linear frequency mapping:
Frequency = 1500 + (Pixel / 255) × 800
or, inverted:
Pixel = (Frequency - 1500) / 800 × 255
This simplicity (vs. complex modulation schemes) makes WEFAX robust to noise and frequency drift.
WMO Standards
WEFAX is defined by the World Meteorological Organization (WMO):
- ITU-R Rec. 625: Analog picture transmission standard
- WMO 49 (Vol. II.1): Manual on Codes — Radiofax services
The standard includes timing, synchronization, and frequency specifications to ensure international interoperability.
Troubleshooting
Problem: Decoded image is blank or all noise
- Check audio sample rate (should be 44,100 Hz, or decoder will resample)
- Verify IOC and RPM match the transmission
- Try
--no-auto-detect if tone detection is failing
- Ensure audio is loud enough (not too quiet or clipping)
Problem: Image is stretched or wrong aspect ratio
- The encoder resizes to IOC width; height is proportional
- If your original image is 1:1, output will be 1809:1809 (IOC 576)
- Crop or resize your source image before encoding
Problem: Decoding takes a long time
- Large audio files will take proportionally longer
- Frequency estimation involves Fourier transforms
- Normal: 30 second transmission = 10–30 seconds decode time
Problem: Audio quality is poor on playback
- WEFAX expects mono, 44,100 Hz WAV
- Some radios/software expect different levels (adjust if clipping)
- FM deviation is standard (±400 Hz); check SSB filter width
Related Projects
- APT Codec — NOAA satellite pictures (APT format)
- SSTV Codec — Amateur radio image transmission (Martin/Scottie/Robot modes)
- RTTY Codec — Amateur radio text (radioteletype)
- Data Modem — FSK binary data over audio
License
MIT License — Use freely, modify, and distribute.