VMD Decomposition
foretools/emd_like 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]"
```python
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.emd_like 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"]
```toml
## Common controls
`FastVMD.decompose(...)` forwards most tuning arguments into `VMDParameters`.
Common overrides:
| Argument | Why you would change it |
| --- | --- |
| `auto_params` | disable heuristics and use explicit parameter overrides |
| `n_trials` | control the Optuna search budget |
| `max_K` | cap the number of modes considered |
| `alpha_min`, `alpha_max` | narrow or widen the bandwidth-penalty search range |
| `k_selection` | choose `penalized`, `fbd`, or `entropy` preselection logic |
| `search_method` | choose `optuna` or `entropy` for the search path |
| `boundary_method` | control edge extension such as `mirror`, `reflect`, `linear`, `constant`, or `none` |
| `apply_tapering` | taper mode boundaries before returning them |
| `refine_modes` | enable neural post-refinement |
| `refine_method` | switch between `informer` and `cross_mode` refinement |
| `fft_backend`, `fft_device` | choose 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,
)
```python
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,
)
```text
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.emd_like 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,
)