Fast constant-Q Morlet filter banks in PyTorch: scalable time-frequency analysis on CPU and GPU
Note
This project is under active development and may undergo significant changes.
This Python library provides an implementation of the Morlet wavelet transform
for time-frequency analysis. The implementation follows the original,
physically intuitive formulation by Jean Morlet
(French geophysicist and pioneer of wavelet theory), which defines wavelet shape
through a parameter called shape ratio,
Built entirely on PyTorch, Morvex runs on both GPU and CPU with no code changes required.
Install the uv Python package manager.
If you already have PyTorch installed and need only the core functionality of Morvex, run the following command:
uv add git+https://github.com/nimanzik/MorvexMorvex provides optional extras for different PyTorch configurations (CUDA
versions and CPU-only). If you do not already have PyTorch installed, choose
the build that matches your hardware and CUDA version, and pass the corresponding
name from the table below to uv's --extra option.
| Extra name | PyTorch build |
|---|---|
torch-cpu |
CPU |
torch-cu126 |
CUDA 12.6 |
torch-cu130 |
CUDA 13.0 |
torch-cu132 |
CUDA 13.2 |
Replace <extra-name> with an extra name from the table:
uv add git+https://github.com/nimanzik/Morvex \
--extra <extra-name>For example, to install with CPU-only PyTorch:
uv add git+https://github.com/nimanzik/Morvex --extra torch-cpuand to install with CUDA 13.0 enabled PyTorch:
uv add git+https://github.com/nimanzik/Morvex --extra torch-cu130Important
The units of time_duration and sampling_freq must be compatible
(e.g., seconds and Hz, milliseconds and kHz etc). Morvex does not enforce unit
consistency in the input parameters, and it is assumed that users will provide
compatible values.
import torch
from morvex import MorletFilterBank
# Build a constant-Q filter bank
fbank = MorletFilterBank(
n_octaves=4, # Number of octaves
resolution=8, # Number of filters per octave
shape_ratio=5.0, # Shape ratio (kappa)
time_duration=2.0, # Wavelet time duration (here in seconds)
sampling_freq=1000.0, # Sampling frequency (here in Hz)
)
# Compute the wavelet transform (scalogram) of an 8-second signal
signal = torch.randn(8000)
scalogram = fbank(signal, coeff_type="power")
scalogram.shape
# torch.Size([n_wavelets, 8000])The forward pass supports arbitrary leading dimensions for batch processing. For example, to compute the CWT of a batch of 16 stereo signals (3 channels, 8 seconds each):
signals = torch.randn(16, 3, 8000)
scalogram = fbank(signals, coeff_type="magnitude")
scalogram.shape
# torch.Size([16, 3, n_wavelets, 8000])Since Morvex is a standard torch.nn.Module, moving the filter bank and input
data to GPU is straightforward:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
fbank = fbank.to(device)
signal = signal.to(device)
scalogram = fbank(signal, coeff_type="power") # Computed on GPU if availableTo display the frequency responses of the filter bank:
import matplotlib.pyplot as plt
from morvex.plotting import plot_freq_resps
fig, ax = plt.subplots()
plot_freq_resps(fbank, plot_obj=ax, color="skyblue")
plt.show()To display the scalogram in the time-frequency plane:
import numpy as np
from morvex.plotting import plot_time_freq_plane
scalogram = scalogram.cpu().numpy() # Move to CPU for plotting
freqs = fbank.center_freqs.cpu().numpy()
times = np.arange(scalogram.shape[-1]) / fbank.sampling_freq
fig, ax = plt.subplots()
plot_time_freq_plane(ax, freqs, times, scalogram, log_scale=True)
plt.show()Report issues or bugs on GitHub Issues.