Overview
Phoenix Nest Modem
MIL-STD-188-110A HF Data Modem
Copyright © 2025 Phoenix Nest LLC
See EULA for license terms and conditions.
Overview
A complete software implementation of the MIL-STD-188-110A serial-tone HF data modem standard, supporting all 11 data modes from 75 bps to 4800 bps with advanced equalization, turbo processing, and comprehensive testing infrastructure.
Features
Data Modes
| Mode | Data Rate | Modulation | Interleave | FEC |
|---|---|---|---|---|
| M75S/L | 75 bps | Walsh-8 | Short/Long | Repetition |
| M150S/L | 150 bps | 8PSK | Short/Long | Rate 1/2 K=7 |
| M300S/L | 300 bps | 8PSK | Short/Long | Rate 1/2 K=7 |
| M600S/L | 600 bps | 8PSK | Short/Long | Rate 1/2 K=7 |
| M1200S/L | 1200 bps | 8PSK | Short/Long | Rate 1/2 K=7 |
| M2400S/L | 2400 bps | 8PSK | Short/Long | Rate 1/2 K=7 |
| M4800S | 4800 bps | 8PSK | Short | Uncoded |
Signal Processing
- Carrier: 1800 Hz center frequency
- Symbol Rate: 2400 baud
- Sample Rates: 8000, 9600, 44100, 48000 Hz supported
- Filtering: Root-raised-cosine with β=0.35
Equalizers
Seven equalizer implementations for different channel conditions:
| Equalizer | Best For | Complexity |
|---|---|---|
| NONE | Clean channels | Lowest |
| DFE | Light ISI, AWGN | Low |
| DFE_RLS | Time-varying channels | Medium |
| MLSE_L2 | Moderate ISI (L=2) | Medium |
| MLSE_L3 | Heavy ISI (L=3) | High |
| MLSE_ADAPTIVE | Unknown/changing ISI | High |
| TURBO | Severe conditions (default) | Highest |
Advanced Features
- Turbo Equalization: Iterative SISO decoding with 2-5 iterations
- Soft Demapping: SNR-weighted LLR computation
- Adaptive MLSE: Channel length estimation and tracking
- Automatic Mode Detection: Preamble correlation with D1/D2 decoding
- Frequency Offset Compensation: ±10 Hz acquisition range
- Parallel Test Execution: Multi-threaded test harness with up to 16 threads
- Web-Based GUI: Interactive test interface at
http://localhost:8080 - MS-DMT Compatible Server: Network interface on TCP ports 4998/4999/5000
Architecture
┌─────────────────────────────────────────────────────────────┐
│ API Layer │
│ modem.h modem_rx.h modem_tx.h modem_config.h │
├─────────────────────────────────────────────────────────────┤
│ Modem Components │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ m110a/ │ │ modem/ │ │equalizer/│ │ sync/ │ │
│ │ m110a_tx│ │ viterbi │ │ dfe │ │ preamble_detect │ │
│ │ m110a_rx│ │ siso │ │ mlse │ │ timing_recovery │ │
│ │ mode_* │ │ mapper │ │ turbo │ │ freq_estimator │ │
│ └─────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ DSP Primitives │
│ nco.h rrc_filter.h resampler.h agc.h fft.h │
├─────────────────────────────────────────────────────────────┤
│ I/O Layer │
│ pcm_file.h wav_file.h │
└─────────────────────────────────────────────────────────────┘
Project Structure
pennington_m110a_demod/
├── api/ # Public API headers
│ ├── modem.h # Main include
│ ├── modem_rx.cpp/h # Receiver implementation
│ ├── modem_tx.cpp/h # Transmitter implementation
│ ├── modem_config.h # Configuration structures
│ └── channel_sim.h # Channel simulation
├── src/ # Core modem implementation
│ ├── common/ # Shared types and constants
│ ├── dsp/ # DSP primitives (NCO, filters, AGC)
│ ├── equalizer/ # DFE, MLSE, Turbo equalizers
│ ├── io/ # File I/O (PCM, WAV)
│ ├── m110a/ # Protocol-specific (preamble, modes)
│ ├── modem/ # Codec chain (Viterbi, interleaver)
│ └── sync/ # Synchronization (timing, frequency)
├── test/ # Test suite and GUI
│ ├── exhaustive_test_unified.cpp # Main test executable
│ ├── test_gui_server.cpp # Web GUI server
│ └── test_framework.h # Test infrastructure
├── server/ # TCP/IP server interface
│ ├── msdmt_server.cpp # MS-DMT compatible server
│ └── main.cpp # Server entry point
├── docs/ # Documentation
├── refrence_pcm/ # MS-DMT reference test vectors
└── build.ps1 # PowerShell build script
Building
Requirements
- Compiler: MSVC with C++17 support (Visual Studio 2019+)
- Build System: PowerShell 5.1+ with build.ps1 script
- Runtime: Windows x64
Build All Components
.\build.ps1 -Target all
Build targets:
- all - Build all executables (modem, test suite, GUI, server)
- unified - Test suite only (exhaustive_test.exe)
- gui - Web GUI only (test_gui.exe)
- server - Modem server only (m110a_server.exe)
Quick Start
Run Server & GUI
# Start modem server (TCP ports 4998/4999/5000)
.\server\m110a_server.exe
# Start test GUI (opens browser to http://localhost:8080)
.\test\test_gui.exe
Run Tests from Command Line
# Single test
.\test\exhaustive_test.exe --mode 2400S --eq DFE -n 1
# Multiple modes and equalizers
.\test\exhaustive_test.exe --modes 2400S,1200S,600L --eqs DFE,TURBO,NONE -n 5
# Parallel execution with 4 threads
.\test\exhaustive_test.exe --modes 2400S,1200L,600S --parallel 4 -n 10
# Progressive test suite (all modes/equalizers)
.\test\exhaustive_test.exe --progressive -n 50
# Test with Server backend
.\test\exhaustive_test.exe --mode 1200S --backend server --server-host localhost --server-port 4998 -n 1
Usage
Direct API Usage
API Examples
The following examples demonstrate the C++ API. See api/README.md for complete API documentation.
Basic Transmission
#include "api/modem.h"
// Configure transmitter
m110a::TxConfig tx_cfg;
tx_cfg.mode = m110a::Mode::M2400S;
tx_cfg.sample_rate = 48000;
// Create and transmit
m110a::ModemTx tx(tx_cfg);
std::vector<uint8_t> data = {/* your data */};
auto pcm_samples = tx.transmit(data);
Basic Reception
#include "api/modem.h"
// Configure receiver
m110a::RxConfig rx_cfg;
rx_cfg.mode = m110a::Mode::AUTO; // Auto-detect mode
rx_cfg.equalizer = m110a::Equalizer::TURBO;
rx_cfg.sample_rate = 48000;
// Create and receive
m110a::ModemRx rx(rx_cfg);
auto result = rx.receive(pcm_samples);
if (result.success) {
// result.data contains decoded bytes
// result.detected_mode shows which mode was detected
// result.ber contains bit error rate estimate
}
Loopback Test
#include "api/modem.h"
m110a::TxConfig tx_cfg{.mode = m110a::Mode::M1200S};
m110a::RxConfig rx_cfg{.mode = m110a::Mode::AUTO};
m110a::ModemTx tx(tx_cfg);
m110a::ModemRx rx(rx_cfg);
std::vector<uint8_t> original = "Hello, HF World!";
auto samples = tx.transmit(original);
auto result = rx.receive(samples);
assert(result.data == original);
Equalizer Selection Guide
| Channel Condition | Recommended | Alternative |
|---|---|---|
| AWGN only | DFE | NONE |
| Light multipath | DFE_RLS | DFE |
| Moderate multipath | MLSE_L2 | MLSE_ADAPTIVE |
| Severe multipath | TURBO | MLSE_L3 |
| Unknown/varying | TURBO | MLSE_ADAPTIVE |
| Low CPU budget | DFE | NONE |
Performance
Test Results (11/11 modes passing)
All modes verified with loopback testing and MS-DMT reference sample compatibility.
Turbo Equalization Gains
| Condition | Without Turbo | With Turbo | Improvement |
|---|---|---|---|
| AWGN 9dB | 8.0% BER | 0.0% BER | +100% |
| Light ISI | 4.6% BER | 0.0% BER | +100% |
| Moderate ISI | 28.8% BER | 11.5% BER | +60% |
| Heavy ISI | 40.6% BER | 28.4% BER | +30% |
Resource Usage
- Memory: ~2-5 MB depending on equalizer and interleaver
- CPU: Runs real-time on Raspberry Pi 4 for all modes
- Latency: Mode-dependent (short interleave ~0.6s, long interleave ~4.8s)
Test Framework Performance
Parallel test execution performance (Windows, 8-core CPU):
- Sequential: ~42s for 22 tests
- Parallel (4 threads): ~11s for 22 tests (3.8x speedup)
- Bottleneck: Modem decode() processing time
Test backends: - Direct API Backend: In-process modem testing (supports parallel execution) - Server Backend: TCP/IP testing via MS-DMT compatible interface (sequential only)
Protocol Details
Frame Structure
[Preamble][Data Block 1][Probe][Data Block 2][Probe]...[EOM]
Preamble (variable length):
- Common sync: 288-320 symbols (scrambled known pattern)
- D1: 32 symbols (data rate identifier)
- D2: 32 symbols (interleaver setting)
- Count: 96 symbols (transmission duration)
Data Block: 32 symbols (mode-dependent bits)
Probe: 16 symbols (channel estimation)
Channel Coding
- Convolutional encoder: Rate 1/2, K=7, polynomials G1=0133, G2=0171
- Interleaver: Block interleaver, size depends on mode and short/long setting
- Scrambler: 9-stage LFSR, polynomial x⁹ + x⁴ + 1
Modulation
- 8PSK with Gray coding
- Differential encoding (optional)
- Symbol rate: 2400 baud fixed
MS-DMT Compatibility
Tested for interoperability with MS-DMT v3.00.2.22 reference implementation:
- All 10 standard modes verified (M150-M2400, short and long interleave)
- Reference test samples included in refrence_pcm/ directory for validation
- Known test message: "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 1234567890"
- Compatible TCP/IP server interface on ports 4998 (data), 4999 (control), 5000 (UDP discovery)
Note: This implementation was developed independently from the MIL-STD-188-110A specification. MS-DMT compatibility is for interoperability testing only.
Documentation
- API Documentation - Public API reference
- Implementation Plan - Development roadmap
- Test Matrix - Mode test coverage
- Project Status - Current status and milestones
- Development Journal - Session-by-session progress
- Protocol Details - MIL-STD-188-110A protocol specifics
- Equalizers - Equalizer theory and usage
- RX Chain - Receiver signal flow
- TX Chain - Transmitter signal flow
Testing
Web GUI Test Interface
.\test\test_gui.exe
Browser opens to http://localhost:8080 with:
- Multi-select mode and equalizer lists
- Backend selection (Direct API or Server)
- Parallel thread count (1-16 threads, Direct API only)
- Test type (Standard or Progressive)
- Real-time test output streaming
Command Line Testing
# Run all tests
.\test\exhaustive_test.exe --progressive -n 100
# Specific mode and equalizer
.\test\exhaustive_test.exe --mode 1200L --eq TURBO -n 10
# Multiple configurations in parallel
.\test\exhaustive_test.exe --modes 2400S,1200S,600S --eqs DFE,TURBO --parallel 4 -n 20
Test Backends
Direct API Backend (default): - In-process modem testing - Supports parallel execution - Faster execution - Full control over test parameters
Server Backend:
- Tests via TCP/IP (MS-DMT compatible)
- Validates server interface
- Sequential execution only
- Requires m110a_server.exe running
API Examples
Development History
This implementation was developed over 22+ sessions, progressing through: 1. Core modem (TX/RX chains, all 11 modes) 2. DFE equalizer with probe-based channel estimation 3. MLSE equalizer (L=2, L=3, adaptive) 4. RLS adaptive filtering 5. Turbo equalization with SISO Viterbi decoder 6. MS-DMT compatibility fixes 7. Parallel test execution framework 8. Web-based test GUI
Version
Current version: 1.2.0+build.57 (turbo branch)
See VERSION_ITERATION_INSTRUCTIONS.md for versioning details.
Known Limitations
- M75 (75 bps Walsh) mode: Basic implementation, may need tuning for weak signals
- No ALE (Automatic Link Establishment) integration
- Single-channel only (no diversity combining)
- File I/O based (no real-time audio device interface in current build)
- Windows-focused build system (PowerShell script)
Contributing
Contributions welcome! Areas of interest: - Additional equalizer algorithms - ALE integration - Real-time audio interface - Performance optimization - Additional test vectors - Cross-platform build support (CMake) - Linux/macOS compatibility
License
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
References
- MIL-STD-188-110A: Interoperability and Performance Standards for Data Modems (primary specification)
- MIL-STD-188-110B/C: Updated versions (partial compatibility)
- STANAG 4539: NATO equivalent standard
- MS-DMT v3.00.2.22: Used for interoperability validation
Acknowledgments
- U.S. Department of Defense for the MIL-STD-188-110A specification
- GNU Radio community for DSP insights
- Fldigi project for protocol documentation
Repository
- GitHub: pennington_m110a_demod
- Branch:
turbo(active development) - Default branch:
master