uwacomm: Underwater Communications Codec

Jay Patel

May 6, 2026

uwacomm: Underwater Communications Codec

🌊 Introducing uwacomm

uwacomm is a Python library for schema-based compact binary encoding designed for bandwidth-constrained communications, particularly underwater acoustic modems. Inspired by DCCL (Dynamic Compact Control Language) from GobySoft, uwacomm uses Pydantic models for message definition and provides DCCL-style bounded field optimization to minimize transmitted bytes.

Underwater acoustic modems typically operate at 80-5000 bits per secondβ€”orders of magnitude slower than terrestrial networks. With limited transmission windows and high per-byte costs, every bit counts. uwacomm addresses this challenge by providing highly optimized serialization in a Python-native, Pydantic-first approach!


πŸ”§ Installation

Getting started with uwacomm is simple. You can install it directly via pip:

pip install uwacomm

If you need Protobuf schema generation capabilities, install with the optional dependency:

pip install uwacomm[protobuf]

πŸš€ How to Use uwacomm

uwacomm uses a schema-first design. You define messages using Pydantic’s intuitive field syntax, which brings type safety and autocompletion to your communications stack.

1. Defining a Message

You define a message by inheriting from BaseMessage and using bounded types like BoundedInt and BoundedFloat. This is where the magic happens: by providing bounds, uwacomm knows exactly how many bits are required to encode your field.

from uwacomm import BaseMessage, BoundedInt, BoundedFloat

class VehicleStatus(BaseMessage):
    """Underwater vehicle status with efficient float encoding."""

    # Position (GPS coordinates with 6 decimal places = ~11cm accuracy)
    position_lat: float = BoundedFloat(min=-90.0, max=90.0, precision=6)   # 28 bits vs 64 bits!
    position_lon: float = BoundedFloat(min=-180.0, max=180.0, precision=6)  # 29 bits

    # Depth in meters (centimeter precision)
    depth_m: float = BoundedFloat(min=0.0, max=5000.0, precision=2)  # 20 bits

    # Vehicle state
    heading_deg: float = BoundedFloat(min=0.0, max=360.0, precision=1)  # 12 bits
    battery_pct: int = BoundedInt(ge=0, le=100)  # 7 bits

    uwacomm_id: int = 10
    uwacomm_max_bytes: int = 64

2. Multi-Mode Encoding

uwacomm supports multiple encoding modes depending on your mission requirements.

Mode 1: Point-to-Point (Maximum Compression)

For single vehicle-to-topside communication where every bit is critical:

from uwacomm import encode, decode

# Create a message
msg = VehicleStatus(
    position_lat=42.358894,
    position_lon=-71.063611,
    depth_m=125.75,
    heading_deg=45.5,
    battery_pct=78
)

# Encode (Mode 1 - no ID, minimal overhead)
data = encode(msg)  # ~14 bytes (8.2% smaller than DCCL!)

# Decode
decoded = decode(VehicleStatus, data)
assert decoded.depth_m == msg.depth_m

Mode 3: Multi-Vehicle Routing (Swarm Robotics)

For swarm deployments, you often need source/destination addressing and priority flags:

from uwacomm import encode_with_routing, decode_with_routing

# Vehicle 3 sends high-priority status to topside (ID 0)
data = encode_with_routing(
    msg,
    source_id=3,
    dest_id=0,
    priority=2,          # 0=low, 3=high
    ack_requested=True
)

# Topside receives and processes
routing, decoded = decode_with_routing(VehicleStatus, data)
print(f"From vehicle {routing.source_id}, priority {routing.priority}")

πŸ“‘ Testing with the Mock Modem Driver

Testing acoustic modem communication usually requires expensive hardware in a tank or open water. uwacomm includes a Mock Modem Driver that lets you simulate acoustic channels with delay, packet loss, and bit errors directly in your CI/CD pipelines!

from uwacomm.modem import MockModemDriver, MockModemConfig

# Configure realistic underwater channel
config = MockModemConfig(
    transmission_delay=1.5,      # 1.5 second round-trip (1 km range)
    packet_loss_probability=0.1,  # 10% packet loss
    bit_error_rate=0.0005,        # 0.05% BER (acoustic noise)
    max_frame_size=64,            # 64 byte max (typical modem limit)
    data_rate=80,                 # 80 bps (long range, low frequency)
)

# Create and connect mock modem
modem = MockModemDriver(config)
modem.connect("/dev/null", 19200)  # Fake port

def on_receive(data: bytes, src_id: int):
    msg = decode(VehicleStatus, data)
    print(f"Received from {src_id}: depth={msg.depth_m}m")

modem.attach_rx_callback(on_receive)

# Send frame (will echo back after transmission_delay seconds)
modem.send_frame(encode(msg), dest_id=0)

πŸ“Š Analyzing Bandwidth Overhead

You can visualize exactly how many bits your schema is utilizing directly from the terminal (inspired by dccl --analyze):

uwacomm --analyze message.py

This ensures you have fine-grained control and visibility into your payload size before deployment.


πŸ’» Extensive Examples

The uwacomm repository contains a rich set of runnable examples under the examples/ directory to help you quickly integrate the library into your projects:


πŸ”— Get Involved

uwacomm is open source under the MIT License! You can find the full documentation, examples, and source code on the GitHub Repository: πŸ‘‰ github.com/patel999jay/uwacomm

You can also find the official package on PyPI: πŸ“¦ pypi.org/project/uwacomm/

If you use uwacomm in your research, please consider citing the project:

@software{uwacomm2026,
  author = {Patel, Jay},
  title = {uwacomm: Python DCCL-inspired compact binary encoding for underwater communications},
  year = {2026},
  url = {https://github.com/patel999jay/uwacomm}
}
Underwater Acoustic Communication Python Codec DCCL Pydantic
Jay Patel

Jay Patel

OFI Postdoctoral Fellow in Underwater Communication Systems

My research interests include electronics & communications, distributed underwater robotics, mobile computing and programmable matter.