Skip to content

VMD Decomposition ​

foretools/decomposition/emd provides a decomposition toolkit covering Variational Mode Decomposition (VMD), empirical mode decomposition variants, hierarchical decomposition, multivariate support, and Optuna-based parameter search.

Use it when you want to split a signal into interpretable oscillatory modes before forecasting, diagnostics, denoising, or downstream feature extraction.

Installation ​

The VMD module requires the vmd extra:

bash
pip install "foreblocks[vmd]"

Other useful exports:

  • VMDOptimizer for the lower-level optimization pipeline
  • SignalAnalyzer for auto-parameter heuristics
  • ModeProcessor for post-processing and mode ordering
  • VMDCore for the low-level solver

Fast path ​

FastVMD is the main entry point.

python
import numpy as np
from foretools.decomposition.emd import FastVMD

fs = 100.0
t = np.arange(0, 10, 1 / fs)
signal = (
    np.sin(2 * np.pi * 3.0 * t)
    + 0.6 * np.sin(2 * np.pi * 11.0 * t)
    + 0.15 * np.random.default_rng(0).normal(size=t.shape[0])
)

vmd = FastVMD()
raw_modes, raw_freqs, optinfo = vmd.decompose(
    signal,
    fs=fs,
    method="standard",
    auto_params=True,
    refine_modes=False,
    return_raw_modes=True,
)

post_modes = optinfo["post_modes"]
post_freqs = optinfo["post_freqs"]
best_K, best_alpha, best_cost = optinfo["best"]

Common controls ​

FastVMD.decompose(...) forwards most tuning arguments into VMDParameters.

Common overrides:

ArgumentWhy you would change it
auto_paramsdisable heuristics and use explicit parameter overrides
n_trialscontrol the Optuna search budget
max_Kcap the number of modes considered
alpha_min, alpha_maxnarrow or widen the bandwidth-penalty search range
k_selectionchoose penalized, fbd, or entropy preselection logic
search_methodchoose optuna or entropy for the search path
boundary_methodcontrol edge extension such as mirror, reflect, linear, constant, or none
apply_taperingtaper mode boundaries before returning them
refine_modesenable neural post-refinement
refine_methodswitch between informer and cross_mode refinement
fft_backend, fft_devicechoose FFT backend and device routing

Example with explicit overrides:

python
modes, freqs, best = vmd.decompose(
    signal,
    fs=fs,
    return_raw_modes=False,
    auto_params=False,
    n_trials=20,
    max_K=5,
    alpha_min=800,
    alpha_max=4000,
    k_selection="penalized",
    boundary_method="mirror",
    apply_tapering=True,
)

Important parameter groups:

  • Search: n_trials, max_K, search_method, k_selection
  • Solver: tol, max_iter, tau, DC, init
  • Boundary handling: boundary_method, use_soft_junction, window_alpha
  • Stabilization: admm_over_relax, omega_momentum, omega_shrinkage, omega_max_step
  • Advanced bandwidth handling: adaptive_alpha, related adaptive_alpha_* fields
  • Backend selection: fft_backend, fft_device
  • Special modes: if_tracking, use_mvmd

Automatic parameter selection ​

With auto_params=True, the pipeline uses SignalAnalyzer.assess_complexity(...) to pick a search budget and alpha range from spectral entropy, frequency spread, variability, kurtosis, and an SNR estimate.

This is a good first step when:

  • you do not know a reasonable K range yet
  • signals vary a lot across datasets
  • you want a usable baseline before manual tuning

Prefer auto_params=False when you are doing ablations or want strict reproducibility of the search space.

Hierarchical decomposition ​

Use method="hierarchical" when you want multi-scale decomposition across progressively downsampled residuals.

python
vmd = FastVMD()

modes, freqs, level_info = vmd.decompose(
    signal,
    fs=fs,
    method="hierarchical",
    max_levels=3,
    energy_threshold=0.01,
    min_samples_per_level=100,
    use_emd_hybrid=False,
    refine_modes=False,
)

Notes:

  • MVMD expects a 2D array shaped [channels, samples]
  • the raw return is flattened for convenience, while optinfo["mv_shape"] preserves the original multivariate mode layout
  • entropy-based search currently falls back to Optuna for MVMD in this pipeline

Low-level optimizer ​

If you want more control than FastVMD, use VMDOptimizer directly.

python
from foretools.decomposition.emd import FFTWManager, VMDOptimizer

fftw = FFTWManager()
optimizer = VMDOptimizer(fftw)

raw_modes, raw_freqs, optinfo = optimizer.optimize(
    signal,
    fs=fs,
    auto_params=True,
    refine_modes=False,
    return_raw_modes=True,
)

MIT License