This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

User's Guide

Instructions for downloading the channel library, replaying a signal through a channel, adding site-specific noise, and visualizing a decompressed channel.

The channels stored in this library can be used in two ways: a channel can be (1) applied directly to a user-generated signal, or (2) decompressed for visualization. Ready-to-use code for performing these functions is available on GitHub.

Installation

matlab.addons.install(websave([tempname '.mltbx'], 'https://github.com/uwa-channels/matlab/releases/latest/download/uwa-channels.mltbx'))
pip install uwa-channels

The MATLAB command downloads the latest release and installs it as an add-on, so replay, noisegen, and unpack are on your path in every session afterwards. Running it again later upgrades the toolbox in place. To remove it, run matlab.addons.uninstall('uwa-channels'), or use Home > Add-Ons > Manage Add-Ons.

Installing from a clone, and under Octave

If you want to read or modify the source, or if you are running Octave (which cannot read .mltbx files), add the repository folders to the search path instead:

git clone https://github.com/uwa-channels/matlab.git
cd matlab

Then, from that folder, in MATLAB or Octave:

install

This adds src and examples to the search path and saves the path for later sessions, so edits to src take effect immediately. Avoid combining the two routes: if the packaged add-on is also installed, both copies sit on the path and the winner depends on path order.

Requirements

The MATLAB package requires R2021a or later with the Signal Processing Toolbox. Under Octave, it requires version 9.0 or later with the signal and statistics packages.

Julia support is provided by the UnderwaterAcoustics.jl package, maintained separately. See that package’s documentation for installation and usage instructions.

Once a package is installed, download the channel MAT-files from Zenodo and place them where MATLAB, Octave, or Python can find them. The channel files are distributed separately from the code because of their size.

Applying a channel to an arbitrary signal

  • To pass a signal of your choice through a channel, generate the desired signal in passband, respecting the bandwidth and sampling-rate limits of the chosen channel (see the Channels tab).
  • Run replay on the signal.
  • Scale the output of noisegen and add it to the output of replay to obtain the desired signal-to-noise ratio. That is, form rout(t)=rˉout(t)+σnn^(t)r_{\text{out}}(t) = \bar{r}_{\text{out}}(t) + \sigma_n \hat{n}(t), where rˉout(t)\bar{r}_{\text{out}}(t) is the noiseless replay output, n^(t)\hat{n}(t) is the generated noise, and σn\sigma_n is the noise level that sets the SNR. In the example below, σn\sigma_n is 0.05.
channel = load('blue_1.mat');
noise = load('blue_1_noise.mat');
array_index = [1, 2, 3];
y = replay(input, fs, array_index, channel);
w = noisegen(size(y), fs, array_index, noise);
r = y + 0.05 * w;
import h5py
from uwa_channels import replay, noisegen
channel = h5py.File("blue_1.mat", "r")
noise = h5py.File("blue_1_noise.mat", "r")
array_index = [0, 1, 2]
y = replay(input, fs, array_index, channel)
w = noisegen(y.shape, fs, array_index, noise)
r = y + 0.05 * w

A simple example of this process is given in MATLAB and Python. Before running the example code, please read the corresponding README file.

Visualizing a channel

To visualize a channel as a collection of impulse responses evolving over time, you will need to decompress the channel impulse responses via unpack. This will produce the decompressed impulse response h^(τ,t)\hat{h}(\tau, t), which is larger than the stored original and contains all the physical effects of delay drift. The output is a K×M×TK \times M \times T array, where KK is the number of delay taps, MM is the number of array elements, and TT is the number of time snapshots. This array can be generated at an arbitrary sampling rate in time, provided that rate does not exceed the sampling rate in delay.

A simple example of this process is given in MATLAB and Python. Before running the example code, please read the corresponding README file.

1 - Channel file format specifications

Specification of the required and optional fields in the channel and noise .mat files, including the impulse response, phase/delay tracking, and metadata formats.

The uwa-channels-compatible .mat files must be saved with the following flags:

  • -v7.3 to support large variables and the HDF5 file format.
  • -nocompression to speed up loading.

Required fields

Each .mat file must include the following variables:

h_hat

  • Type: Multi-dimensional complex tensor.
  • Dimensions: [delay, receiver, time]
  • Units:
    • Delay axis: sampled at params.fs_delay [Hz], denoted fs=1/Tsf_s = 1/T_s
    • Time axis: sampled at params.fs_time [Hz]
    • Amplitude: complex baseband impulse response (unitless)
  • Description: The estimated time-varying channel impulse response (TVIR) as a function of delay τ\tau and time tt. When delay tracking is used, this is the drift-free response h^(τ,t)\hat{\underline{h}}(\tau, t); otherwise it is the drifting response h^(τ,t)\hat{h}(\tau, t). For a given receiver and time index nn, the slice along the delay axis is the channel vector h^[n]\hat{\underline{\mathbf{h}}}[n], or h^[n]\hat{\mathbf{h}}[n] in the drifting case.

params

A structure with the following scalar fields:

FieldTypeUnitDescription
fs_delayscalarHzSampling rate fsf_s along the delay axis.
fs_timescalarHzSampling rate along the time axis.
fcscalarHzCenter frequency fcf_c of the signal used during channel estimation.

version

  • Type: Numeric scalar.
  • Description: Dataset format version number (currently 1.0).

Phase/delay tracking fields (optional)

phi_hat, theta_hat, and f_resamp may coexist; the replay engine applies them according to the following precedence:

  • If none of the three is present, no Doppler correction is applied.
  • phi_hat takes precedence over theta_hat: if phi_hat is present, it is used and theta_hat is ignored; if only theta_hat is present, it is used instead.
  • f_resamp (see Optional fields) is applied independently of the two phase/delay fields, whether or not either of them is present.

phi_hat (delay tracking)

  • Type: Numeric matrix, size [receiver, time]

  • Units: Radians

  • Sampling rate: params.fs_delay

  • Description: The phase estimate φ^(nTs)\hat\varphi(nT_s), a time-varying phase that encodes both phase rotation and delay drift. In this mode, h_hat holds the drift-free response h^(τ,t)\hat{\underline{h}}(\tau, t). Let Δτ\Delta\tau denote the delay drift common to all propagation paths. It is related to the phase by

    φ^(nTs)=2πfcΔτ(nTs)\hat\varphi(nT_s) = -2\pi f_c\, \Delta\tau(nT_s)

    Unpacking first reinserts the phase, multiplying the drift-free response by ejφ^(nTs)e^{j\hat\varphi(nT_s)} to obtain the signal yˉr(nTs)\bar y_{\text{r}}(nT_s). It then reinserts the delay drift by evaluating that signal at shifted instants,

    vˉr(nTs)=I[yˉr(nTs+φ^(nTs)2πfc)]\bar v_{\text{r}}(nT_s) = \mathcal{I}\left[\bar y_{\text{r}}\left(nT_s + \frac{\hat\varphi(nT_s)}{2\pi f_c}\right)\right]

    where I[]\mathcal{I}[\cdot] denotes interpolation, implemented here as spline interpolation.

theta_hat (phase tracking only)

  • Type: Numeric matrix, size [receiver, time]

  • Units: Radians

  • Sampling rate: params.fs_delay

  • Description: The phase estimate θ^(nTs)\hat\theta(nT_s), a time-varying phase correction. In this mode, h_hat contains the drifting impulse response h^(τ,t)\hat{h}(\tau, t) (delay drift is embedded in the taps). Only the phase is tracked separately. The baseband received signal is modeled as:

    v(t)=nd(n)h(tnT,t)ejθ(t)+w(t)v(t) = \sum_n d(n)\, h(t - nT, t)\, e^{j\theta(t)} + w(t)

    where d(n)d(n) are the transmitted data symbols, h(τ,t)h(\tau, t) is the time-varying impulse response at delay τ\tau and time tt with drifting taps, TT is the symbol interval, θ(t)\theta(t) is the channel phase, and w(t)w(t) is the additive complex baseband noise.

Duration constraint

The time dimension of theta_hat or phi_hat and the third dimension of h_hat must span the same duration. The check is written below for theta_hat; the same applies to phi_hat:

size(theta_hat, 2) / params.fs_delay == size(h_hat, 3) / params.fs_time

Optional fields

f_resamp

  • Type: Scalar (double precision)
  • Units: Unitless resampling factor
  • Description: A time-invariant resampling factor applied to the output signal. This is typically the inverse of a resampling operation applied to remove the nominal Doppler frequency offset before channel estimation. It is applied after the time-varying convolution.

meta

The meta structure is optional but strongly encouraged. The following fields are recognized by the toolbox:

FieldTypeDescription
descriptionstringFree-text description of the experiment.
nsdscalarSamples per symbol NsN_s in the delay domain.
nstscalarSamples per symbol in the time domain.
K_1scalarAnti-causal filter length [symbols].
K_2scalarCausal filter length [symbols].
fcscalarCenter frequency fcf_c [Hz].
element_spacingscalarArray element spacing \ell [m].
verticallogicaltrue if vertical array.
delay_trackinglogicaltrue if delay tracking is enabled (phi_hat present).
limitscalarLower dB limit for plotting.
optimscalarOptimizer used: 1 LMS, 2 RLS, 3 SFTF.
muscalarLMS step size μ\mu (when optim == 1).
lambdascalarForgetting factor λ\lambda (when optim == 2 or 3).
regularizationscalarRegularization factor (when optim == 2 or 3).
Kf_1scalarPLL loop filter coefficient Kf1K_{f_1}.
Kf_2scalarPLL loop filter coefficient Kf2K_{f_2}.
nslrscalarDelay tracking rate (when delay_tracking == true).
codenamestringShort identifier for the channel (e.g., "blue_1").

Users are free to add additional fields to meta to capture experiment-specific metadata.

Noise file format

Each noise .mat file contains the following fields:

FieldTypeDescription
FsscalarSampling rate fsf_s at which noise statistics were measured [Hz].
RscalarBandwidth BB of the recorded noise [Hz]. Despite the field name, this is not the symbol rate RR used on the channel pages.
alphascalarCharacteristic exponent α\alpha of the symmetric α\alpha-stable distribution: 2 Gaussian, < 2 impulsive.
betatensor [M, M, L+1]Mixing coefficients βij(kTs)\beta_{ij}(kT_s) for spatiotemporal noise coloring, where MM is the number of array elements and LL is the maximum lag (both defined below).
fcscalarCenter frequency fcf_c [Hz].
versionscalarNoise struct version number.

The noise generation function noisegen uses the mixing equation:

n^i(nTs)=j=0M1k=0Lβij(kTs)ηj(nTskTs)\hat{n}_i(nT_s) = \sum_{j=0}^{M-1}\sum_{k=0}^{L}\beta_{ij}(kT_s)\,\eta_j(nT_s - kT_s)

Here n^i\hat{n}_i is the synthetically generated noise on hydrophone ii, with the hydrophone indices running as i,j=0,,M1i, j = 0, \ldots, M-1. The sampling interval is Ts=1/fsT_s = 1/f_s, the sampling rate fsf_s being stored in the Fs field, and LL is the maximum discrete time lag with non-negligible covariance, so that βij(kTs)\beta_{ij}(kT_s) has L+1L+1 taps, k=0,,Lk = 0, \ldots, L. The innovations ηj(nTs)Sα(0,1/2)\eta_j(nT_s) \sim \mathcal{S}_\alpha(0, 1/\sqrt{2}) are i.i.d. symmetric α\alpha-stable variates with zero location and scale 1/21/\sqrt{2}; this scale ensures that the distribution reduces to the standard Gaussian N(0,1)\mathcal{N}(0, 1) when α=2\alpha = 2.

2 - Code Contribution Guide

A guide for contributing to the MATLAB and Python implementations of the channel replay library, covering setup, coding standards, and pull requests.

Thank you for considering a contribution to UWA-Channels. Bug reports, feature requests, documentation improvements, and code changes are all welcome.

This guide explains how to contribute effectively to the two companion repositories hosted at https://github.com/uwa-channels:

RepositoryLanguageMain BranchFolder Layout
uwa-channels/matlabMATLAB (R2021a+)mainsrc/, tests/, examples/
uwa-channels/pythonPython (≥ 3.10)mainsrc/uwa_channels/, tests/, examples/

The library’s Julia support is hosted separately, in the UnderwaterAcoustics.jl package maintained by the Acoustic Research Laboratory. Please refer to that repository’s own contribution guidelines for Julia-specific bug reports and pull requests.

Getting started

Prerequisites

  • Familiarity with Git, GitHub, Markdown, and either MATLAB or Python.
    Helpful references: GitHub Quickstart, Markdown Guide.

  • Development environment:

    MATLAB repository

    git clone https://github.com/uwa-channels/matlab.git
    

    To run example scripts:

    cd examples
    example_replay
    

    To run tests:

    cd tests
    addpath('../src')
    runtests('testReplay')
    

    Python repository: create a virtual environment and install dependencies:

    git clone https://github.com/uwa-channels/python.git
    cd python
    pip install numpy scipy matplotlib h5py pytest pre-commit
    

    To run example scripts:

    PYTHONPATH=src python examples/example_replay.py
    

    To run tests:

    PYTHONPATH=src pytest
    

    To initialize pre-commit:

    pre-commit install
    pre-commit run --all-files
    

Code of conduct

We expect all contributors to be professional, respectful, and constructive. By participating, you agree to uphold these standards.

Bug reports, feature requests, and discussions

Bug reports

  • Search existing issues and pull requests; your bug may already be reported or fixed.
  • Provide a minimal, reproducible example (MATLAB .m file or live script, or a Python snippet), along with:
    • Package versions (uwa_channels.__version__ or MATLAB ver)
    • OS and MATLAB/Python version, if relevant

Feature requests

Describe both the motivation and the proposed change. Sketch a possible API or workflow if applicable.

Discussions

General Q&A, design ideas, and roadmap conversations belong in GitHub Discussions, not in Issues.

Issue labels

LabelMeaning
high-priority / low-priorityRelative urgency
good first issueSuitable for newcomers
breaking-changeAPI/behavior change

Issues planned for release are tracked with a GitHub milestone rather than a label.

Workflow for code and documentation changes

  1. Fork the repository and clone your fork.
  2. Create a branch from main, named like topic-short-description (lowercase, hyphen-separated).
  3. Develop locally:
    • MATLAB: run runtests('tests') and address Code Analyzer (MLint) warnings.
    • Python: run PYTHONPATH=src pytest frequently.
  4. Write tests for new features or bug fixes.
  5. Document your changes:
    • Use NumPy-style docstrings in Python functions and classes.
    • Use MATLAB help text headers; add usage examples for public APIs.
  6. Commit with clear messages, then push to your fork.
  7. Open a pull request (PR) against main. Mark it as “Draft” if it’s not yet ready for review. Reference any related issues.
  8. Address reviewer feedback. Once all checks pass and approvals are received, a maintainer will merge.

Commit message style

We follow a simplified version of Conventional Commits:

<type>(<scope>): <summary>

<body>
  • type ∈ {feat, fix, docs, test, perf, refactor, style, chore, revert}
  • scope identifies the module or subsystem (e.g., io, replay, noisegen)
  • Use imperative mood for the summary (e.g., “add support for…” not “added support for…”)
  • Limit the summary to ≤ 50 characters; wrap the body at 72 characters
  • If the change is breaking, begin the body with BREAKING CHANGE:

Examples:

feat(replay): add resampling support for replay channels
fix(io): handle empty .mat files (issue #42)

Coding standards

MATLAB

Follow the MATLAB Style Guide:

  • 4-space indentation; snake_case for functions, PascalCase for classes
  • Each function/class in its own .m file
  • Use arguments blocks for input validation where possible
  • Add unit tests as flat files directly under tests/ using MATLAB Unit Test
  • Vectorize where possible; comment non-obvious logic

Python

  • Formatting is enforced via Black and Ruff (Ruff handles import sorting, so a separate isort pass is unnecessary)
  • Static analysis via Flake8, Ruff, mypy, and Bandit
  • Use NumPy-style docstrings with LaTeX equations where helpful
  • Keep functions short, prefer clarity to cleverness, and avoid premature optimization

Testing and continuous integration

RepositoryLocal Test CommandCI Matrix
MATLABruntests('tests')MATLAB R2021a and latest
PythonPYTHONPATH=src pytestPython 3.10–3.12

All CI checks must pass before a pull request is merged.

Release process (Python only)

Maintainers tag releases using git tag -s vX.Y.Z following Semantic Versioning (SemVer).

Merged PRs are reflected in CHANGELOG.md, with entries auto-generated from commit messages.

Acknowledgements

This guide was inspired by the excellent UnderwaterAcoustics.jl contributing guide, as well as the contribution guidelines of NumPy and SciPy, and the MATLAB Style Guide.

Happy hacking: may your channels be peaceful and your SNR high!