PySDKit 0.4.31__tar.gz → 0.4.32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PKG-INFO +3 -3
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PySDKit.egg-info/PKG-INFO +3 -3
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PySDKit.egg-info/SOURCES.txt +1 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/README.md +2 -2
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/__init__.py +7 -1
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/__init__.py +2 -0
- pysdkit-0.4.32/pysdkit/_vmd/svmd.py +486 -0
- pysdkit-0.4.32/pysdkit/tests/test_svmd.py +118 -0
- pysdkit-0.4.31/pysdkit/_vmd/svmd.py +0 -401
- {pysdkit-0.4.31 → pysdkit-0.4.32}/LICENSE +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PySDKit.egg-info/dependency_links.txt +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PySDKit.egg-info/requires.txt +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/PySDKit.egg-info/top_level.txt +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pyproject.toml +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_alif/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_alif/alif.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_alif/data/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_alif/data/prefixed_double_filter.npy +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_alif/iterative_filtering.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_apmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_apmd/apmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/_find_extrema.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/_prepare_points.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/_splines.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/ceemdan.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/eemd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/efd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/emd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/hht/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/hht/frequency.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/hht/hht.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/memd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/remd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd/tvf_emd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd2d/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd2d/bemd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd2d/bmemd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_emd2d/emd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_esmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_esmd/esmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_ewt/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_ewt/ewt.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_ewt/ewt2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/extrema.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/faemd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/faemd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/faemd3d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_faemd/filter.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_fmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_fmd/fmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_fmd/nfmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_hvd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_hvd/hvd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_itd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_itd/itd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_jmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_jmd/jmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_jmd/mjmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_jmd/sjmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_lmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_lmd/lmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_lmd/rlmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_osd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_ssa/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_ssa/ssa.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/acmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/avmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/ba_acmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/base.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/mvmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/ovmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/vmd_c.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/vmd_f.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd/vme.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd2d/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd2d/cvmd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vmd2d/vmd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vncmd/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vncmd/avncmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vncmd/incmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vncmd/mncmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/_vncmd/vncmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_add_noise.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_cube.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_generator.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_image.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_models.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_test_univariate.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/_time_series.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/data/texture.txt +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/entropy/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/entropy/_approxiamte_entropy.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/entropy/_permutation_entropy.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/entropy/_sample_entropy.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/models/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/models/_base.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/models/_kmeans.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/models/_knn.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/models/_pca.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/_fourier_spectra.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/_functions.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/_plot_images.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/_plot_imfs.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/plot/_plot_signal.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/data/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/data/test_generator_cube.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/data/test_generator_image.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/data/test_generator_signal.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/data/test_generator_univariate_signal.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/models/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/models/test_knn.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/models/test_pca.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/run_all.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_alif.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_apmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_avncmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_ceemdan.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_emd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_ewt.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_ewt2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_faemd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_faemd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_faemd3d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_itd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_jmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_lmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_moving_decomp.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_ovmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_rlmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_sjmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_stl.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_vmd.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tests/test_vmd2d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tsa/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tsa/_dtw.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tsa/_moving_decomp.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tsa/_mstl.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/tsa/_stl.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/__init__.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_cite.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_correlation.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_diagnalization.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_differ.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_fft.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_function.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_hilbert.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_instantaneous.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_kernel_matrix.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_mirror.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_process.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/pysdkit/utils/_smooth1d.py +0 -0
- {pysdkit-0.4.31 → pysdkit-0.4.32}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PySDKit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.32
|
|
4
4
|
Summary: A Python library for signal decomposition algorithms with a unified interface.
|
|
5
5
|
Author: josefinez, Deeksha Manjunath, Yuan Feng, JacktheFowler
|
|
6
6
|
Author-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>, WenTong Zhao <23049200290@stu.xidian.edu.cn>
|
|
@@ -167,14 +167,14 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
167
167
|
| [`NFMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_fmd/nfmd.py) (Non-stationary Feature Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/9732251) | [[code]](https://github.com/sheadan/NFMD-ExtractionInstantaneous/blob/master/nfmd/NFMD.py) | ✖️ |
|
|
168
168
|
| [`SSA`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ssa/ssa.py) (Singular Spectral Analysis) | [[paper]](https://orca.cardiff.ac.uk/id/eprint/15208/1/Zhiglavsky_SSA_encyclopedia.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/58967-singular-spectrum-analysis-beginners-guide) | ✔️ |
|
|
169
169
|
| [`EWT`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt.py) (Empirical Wavelet Transform) | [[paper]](https://ieeexplore.ieee.org/document/6522142) | [[code]](https://www.mathworks.com/help/wavelet/ug/empirical-wavelet-transform.html) | ✔️ |
|
|
170
|
-
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) |
|
|
170
|
+
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) | ✔️ |
|
|
171
171
|
| [`VMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vmd_c.py) (Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/6655981) | [[code]](https://github.com/vrcarva/vmdpy) | ✔️ |
|
|
172
172
|
| [`MVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/mvmd.py) (Multivariate Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/8890883) | [[code]](https://github.com/yunyueye/MVMD) | ✔️ |
|
|
173
173
|
| [`VMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/vmd2d.py) (Two-Dimensional Variational Mode Decomposition) | [[paper]](https://ww3.math.ucla.edu/camreport/cam14-16.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/45918-two-dimensional-variational-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
174
174
|
| [`CVMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/cvmd2d.py) (Two-Dimensional Compact Variational Mode Decomposition) | [[paper]](https://link.springer.com/article/10.1007/s10851-017-0710-z) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/67285-two-dimensional-compact-variational-mode-decomposition-2d-tv-vmd?s_tid=FX_rc2_behav) | ✔️ |
|
|
175
175
|
| [`VME`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vme.py) (Variational Mode Extraction) | [[paper]](https://ieeexplore.ieee.org/document/7997854) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/76003-variational-mode-extraction-vme-m?s_tid=srchtitle) | ✔️ |
|
|
176
176
|
| [`OVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) (Orthogonalized Variational Mode Decomposition) | [[paper]](https://doi.org/10.1016/j.sigpro.2025.110251) | [[code]](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) | ✔️ |
|
|
177
|
-
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) |
|
|
177
|
+
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) | ✔️ |
|
|
178
178
|
| [`VNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/vncmd.py) (Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/7990179) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/64292-variational-nonlinear-chirp-mode-decomposition) | ✔️ |
|
|
179
179
|
| [`INCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/incmd.py) (Iterative Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X2030403X?via%3Dihub) | [[code]](https://github.com/sheadan/IterativeNCMD) | ✔️ |
|
|
180
180
|
| [`MNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/mncmd.py) (Multivariate Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0165168420302103) | [[code]]() | ✖️ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PySDKit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.32
|
|
4
4
|
Summary: A Python library for signal decomposition algorithms with a unified interface.
|
|
5
5
|
Author: josefinez, Deeksha Manjunath, Yuan Feng, JacktheFowler
|
|
6
6
|
Author-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>, WenTong Zhao <23049200290@stu.xidian.edu.cn>
|
|
@@ -167,14 +167,14 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
167
167
|
| [`NFMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_fmd/nfmd.py) (Non-stationary Feature Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/9732251) | [[code]](https://github.com/sheadan/NFMD-ExtractionInstantaneous/blob/master/nfmd/NFMD.py) | ✖️ |
|
|
168
168
|
| [`SSA`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ssa/ssa.py) (Singular Spectral Analysis) | [[paper]](https://orca.cardiff.ac.uk/id/eprint/15208/1/Zhiglavsky_SSA_encyclopedia.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/58967-singular-spectrum-analysis-beginners-guide) | ✔️ |
|
|
169
169
|
| [`EWT`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt.py) (Empirical Wavelet Transform) | [[paper]](https://ieeexplore.ieee.org/document/6522142) | [[code]](https://www.mathworks.com/help/wavelet/ug/empirical-wavelet-transform.html) | ✔️ |
|
|
170
|
-
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) |
|
|
170
|
+
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) | ✔️ |
|
|
171
171
|
| [`VMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vmd_c.py) (Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/6655981) | [[code]](https://github.com/vrcarva/vmdpy) | ✔️ |
|
|
172
172
|
| [`MVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/mvmd.py) (Multivariate Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/8890883) | [[code]](https://github.com/yunyueye/MVMD) | ✔️ |
|
|
173
173
|
| [`VMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/vmd2d.py) (Two-Dimensional Variational Mode Decomposition) | [[paper]](https://ww3.math.ucla.edu/camreport/cam14-16.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/45918-two-dimensional-variational-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
174
174
|
| [`CVMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/cvmd2d.py) (Two-Dimensional Compact Variational Mode Decomposition) | [[paper]](https://link.springer.com/article/10.1007/s10851-017-0710-z) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/67285-two-dimensional-compact-variational-mode-decomposition-2d-tv-vmd?s_tid=FX_rc2_behav) | ✔️ |
|
|
175
175
|
| [`VME`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vme.py) (Variational Mode Extraction) | [[paper]](https://ieeexplore.ieee.org/document/7997854) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/76003-variational-mode-extraction-vme-m?s_tid=srchtitle) | ✔️ |
|
|
176
176
|
| [`OVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) (Orthogonalized Variational Mode Decomposition) | [[paper]](https://doi.org/10.1016/j.sigpro.2025.110251) | [[code]](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) | ✔️ |
|
|
177
|
-
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) |
|
|
177
|
+
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) | ✔️ |
|
|
178
178
|
| [`VNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/vncmd.py) (Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/7990179) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/64292-variational-nonlinear-chirp-mode-decomposition) | ✔️ |
|
|
179
179
|
| [`INCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/incmd.py) (Iterative Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X2030403X?via%3Dihub) | [[code]](https://github.com/sheadan/IterativeNCMD) | ✔️ |
|
|
180
180
|
| [`MNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/mncmd.py) (Multivariate Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0165168420302103) | [[code]]() | ✖️ |
|
|
@@ -113,14 +113,14 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
113
113
|
| [`NFMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_fmd/nfmd.py) (Non-stationary Feature Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/9732251) | [[code]](https://github.com/sheadan/NFMD-ExtractionInstantaneous/blob/master/nfmd/NFMD.py) | ✖️ |
|
|
114
114
|
| [`SSA`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ssa/ssa.py) (Singular Spectral Analysis) | [[paper]](https://orca.cardiff.ac.uk/id/eprint/15208/1/Zhiglavsky_SSA_encyclopedia.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/58967-singular-spectrum-analysis-beginners-guide) | ✔️ |
|
|
115
115
|
| [`EWT`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt.py) (Empirical Wavelet Transform) | [[paper]](https://ieeexplore.ieee.org/document/6522142) | [[code]](https://www.mathworks.com/help/wavelet/ug/empirical-wavelet-transform.html) | ✔️ |
|
|
116
|
-
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) |
|
|
116
|
+
| [`EWT2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_ewt/ewt2d.py) (2D Empirical Wavelet Transform) | [[paper]](https://arxiv.org/abs/2405.06188) | [[code]](https://github.com/bhurat/EWT-Python) | ✔️ |
|
|
117
117
|
| [`VMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vmd_c.py) (Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/6655981) | [[code]](https://github.com/vrcarva/vmdpy) | ✔️ |
|
|
118
118
|
| [`MVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/mvmd.py) (Multivariate Variational Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/8890883) | [[code]](https://github.com/yunyueye/MVMD) | ✔️ |
|
|
119
119
|
| [`VMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/vmd2d.py) (Two-Dimensional Variational Mode Decomposition) | [[paper]](https://ww3.math.ucla.edu/camreport/cam14-16.pdf) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/45918-two-dimensional-variational-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
120
120
|
| [`CVMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd2d/cvmd2d.py) (Two-Dimensional Compact Variational Mode Decomposition) | [[paper]](https://link.springer.com/article/10.1007/s10851-017-0710-z) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/67285-two-dimensional-compact-variational-mode-decomposition-2d-tv-vmd?s_tid=FX_rc2_behav) | ✔️ |
|
|
121
121
|
| [`VME`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/vme.py) (Variational Mode Extraction) | [[paper]](https://ieeexplore.ieee.org/document/7997854) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/76003-variational-mode-extraction-vme-m?s_tid=srchtitle) | ✔️ |
|
|
122
122
|
| [`OVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) (Orthogonalized Variational Mode Decomposition) | [[paper]](https://doi.org/10.1016/j.sigpro.2025.110251) | [[code]](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/ovmd.py) | ✔️ |
|
|
123
|
-
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) |
|
|
123
|
+
| [`SVMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vmd/svmd.py) (Successive Variational Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168420301535) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/98649-successive-variational-mode-decomposition-svmd-m?s_tid=FX_rc3_behav) | ✔️ |
|
|
124
124
|
| [`VNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/vncmd.py) (Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/document/7990179) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/64292-variational-nonlinear-chirp-mode-decomposition) | ✔️ |
|
|
125
125
|
| [`INCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/incmd.py) (Iterative Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X2030403X?via%3Dihub) | [[code]](https://github.com/sheadan/IterativeNCMD) | ✔️ |
|
|
126
126
|
| [`MNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/mncmd.py) (Multivariate Nonlinear Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0165168420302103) | [[code]]() | ✖️ |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
A Python library for signal decomposition algorithms.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.4.
|
|
5
|
+
__version__ = "0.4.32"
|
|
6
6
|
|
|
7
7
|
# Empirical Mode Decomposition
|
|
8
8
|
from ._emd import EMD
|
|
@@ -61,6 +61,9 @@ from ._vmd import VME
|
|
|
61
61
|
# Orthogonalized Variational Mode Decomposition
|
|
62
62
|
from ._vmd import OVMD
|
|
63
63
|
|
|
64
|
+
# Successive Variational Mode Decomposition
|
|
65
|
+
from ._vmd import svmd, SVMD
|
|
66
|
+
|
|
64
67
|
# Variational Mode Decomposition for 2D Image
|
|
65
68
|
from ._vmd2d import VMD2D
|
|
66
69
|
|
|
@@ -151,6 +154,7 @@ Variational Mode Decomposition | VMD
|
|
|
151
154
|
Multivariate Variational Mode Decomposition | MVMD
|
|
152
155
|
Variational Mode Extraction | VME
|
|
153
156
|
Orthogonalized Variational Mode Decomposition | OVMD
|
|
157
|
+
Successive Variational Mode Decomposition | SVMD
|
|
154
158
|
Variational Mode Decomposition for 2D Image | VMD2D
|
|
155
159
|
Compact VMD for 2D Image | CVMD2D
|
|
156
160
|
Variational Nonlinear Chirp Mode Decomposition | VNCMD
|
|
@@ -193,6 +197,8 @@ __all__ = [
|
|
|
193
197
|
"MVMD",
|
|
194
198
|
"VME",
|
|
195
199
|
"OVMD",
|
|
200
|
+
"svmd",
|
|
201
|
+
"SVMD",
|
|
196
202
|
"VMD2D",
|
|
197
203
|
"CVMD2D",
|
|
198
204
|
"VNCMD",
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on 2024/6/2 17:54
|
|
4
|
+
@author: Whenxuan Wang
|
|
5
|
+
@email: wwhenxuan@gmail.com
|
|
6
|
+
|
|
7
|
+
Successive Variational Mode Decomposition (SVMD).
|
|
8
|
+
|
|
9
|
+
Unlike classical VMD, which extracts K modes concurrently and therefore
|
|
10
|
+
requires a known mode count, SVMD extracts compact-spectrum modes
|
|
11
|
+
**one by one**. At each stage the residual / previously extracted modes
|
|
12
|
+
are discouraged from overlapping the mode of interest, and a stopping
|
|
13
|
+
criterion decides when to halt.
|
|
14
|
+
|
|
15
|
+
Mojtaba Nazari, Sayed Mahmoud Sakhaei.
|
|
16
|
+
Successive Variational Mode Decomposition,
|
|
17
|
+
Signal Processing 174 (2020) 107610.
|
|
18
|
+
https://doi.org/10.1016/j.sigpro.2020.107610
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import List, Optional, Tuple, Union
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
from numpy.linalg import norm
|
|
26
|
+
from scipy.signal import savgol_filter
|
|
27
|
+
|
|
28
|
+
from .base import Base
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SVMD(Base):
|
|
32
|
+
"""
|
|
33
|
+
Successive Variational Mode Decomposition.
|
|
34
|
+
|
|
35
|
+
SVMD extends the variational framework of VMD by extracting modes
|
|
36
|
+
successively. Each new mode ``u_L`` is obtained by solving a constrained
|
|
37
|
+
optimization problem that enforces:
|
|
38
|
+
|
|
39
|
+
1. a compact spectrum around a center frequency ``ω_L`` (as in VMD);
|
|
40
|
+
2. little spectral overlap with previously extracted modes;
|
|
41
|
+
3. little spectral overlap with the residual signal.
|
|
42
|
+
|
|
43
|
+
Because modes are obtained one after another, the algorithm does **not**
|
|
44
|
+
require the number of modes ``K`` a priori. Several stopping criteria
|
|
45
|
+
(noise power, exact reconstruction, BIC, power of the last mode) are
|
|
46
|
+
available.
|
|
47
|
+
|
|
48
|
+
Nazari & Sakhaei, Signal Processing, 174:107610, 2020.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
max_alpha: float = 20000,
|
|
54
|
+
tau: float = 0.0,
|
|
55
|
+
tol: float = 1e-6,
|
|
56
|
+
stopc: int = 4,
|
|
57
|
+
init_omega: int = 0,
|
|
58
|
+
max_iter: int = 300,
|
|
59
|
+
max_modes: int = 30,
|
|
60
|
+
poly_order: int = 8,
|
|
61
|
+
window_length: int = 25,
|
|
62
|
+
random_seed: int = 42,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""
|
|
65
|
+
:param max_alpha: balancing parameter of the data-fidelity constraint
|
|
66
|
+
(compactness of each mode). Typical values: 1e3–2e4.
|
|
67
|
+
:param tau: dual-ascent time step. Set to 0 under high-level noise.
|
|
68
|
+
:param tol: relative convergence tolerance for each mode (≈ 1e-6).
|
|
69
|
+
:param stopc: stopping-criterion type
|
|
70
|
+
1 – residual power vs. estimated noise (compact spectra / EEG);
|
|
71
|
+
2 – exact reconstruction (clean signals);
|
|
72
|
+
3 – Bayesian information criterion (BIC);
|
|
73
|
+
4 – power of the last mode (default, as in the MATLAB toolbox).
|
|
74
|
+
:param init_omega: center-frequency initialisation
|
|
75
|
+
0 – start each mode at DC (default, usually sufficient);
|
|
76
|
+
1 – random initialisation avoiding previously found frequencies.
|
|
77
|
+
:param max_iter: maximum ADMM iterations used to refine each mode.
|
|
78
|
+
:param max_modes: hard upper bound on the number of extracted modes
|
|
79
|
+
(safety guard against non-termination).
|
|
80
|
+
:param poly_order: Savitzky–Golay polynomial order used for noise
|
|
81
|
+
estimation (stopc = 1).
|
|
82
|
+
:param window_length: Savitzky–Golay window length (must be odd).
|
|
83
|
+
:param random_seed: RNG seed for ``init_omega = 1``.
|
|
84
|
+
"""
|
|
85
|
+
super().__init__()
|
|
86
|
+
self.max_alpha = float(max_alpha)
|
|
87
|
+
self.tau = float(tau)
|
|
88
|
+
self.tol = float(tol)
|
|
89
|
+
self.stopc = int(stopc)
|
|
90
|
+
self.init_omega = int(init_omega)
|
|
91
|
+
self.max_iter = int(max_iter)
|
|
92
|
+
self.max_modes = int(max_modes)
|
|
93
|
+
self.poly_order = int(poly_order)
|
|
94
|
+
self.window_length = int(window_length)
|
|
95
|
+
self.eps = np.finfo(np.float64).eps
|
|
96
|
+
self.rng = np.random.RandomState(seed=random_seed)
|
|
97
|
+
|
|
98
|
+
if self.stopc not in (1, 2, 3, 4):
|
|
99
|
+
raise ValueError("stopc must be one of {1, 2, 3, 4}")
|
|
100
|
+
if self.init_omega not in (0, 1):
|
|
101
|
+
raise ValueError("init_omega must be 0 or 1")
|
|
102
|
+
|
|
103
|
+
self.signal: Optional[np.ndarray] = None
|
|
104
|
+
self.u: Optional[np.ndarray] = None
|
|
105
|
+
self.u_hat: Optional[np.ndarray] = None
|
|
106
|
+
self.omega: Optional[np.ndarray] = None
|
|
107
|
+
|
|
108
|
+
def __call__(
|
|
109
|
+
self, signal: np.ndarray, return_all: bool = False
|
|
110
|
+
) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray]]:
|
|
111
|
+
"""Allow instances to be called like functions."""
|
|
112
|
+
return self.fit_transform(signal=signal, return_all=return_all)
|
|
113
|
+
|
|
114
|
+
def __str__(self) -> str:
|
|
115
|
+
return "Successive Variational Mode Decomposition (SVMD)"
|
|
116
|
+
|
|
117
|
+
# ------------------------------------------------------------------ #
|
|
118
|
+
# Helpers
|
|
119
|
+
# ------------------------------------------------------------------ #
|
|
120
|
+
def _sgolay(
|
|
121
|
+
self,
|
|
122
|
+
signal: np.ndarray,
|
|
123
|
+
poly_order: Optional[int] = None,
|
|
124
|
+
window_length: Optional[int] = None,
|
|
125
|
+
) -> np.ndarray:
|
|
126
|
+
"""Savitzky–Golay smoother used to estimate the noise floor."""
|
|
127
|
+
poly_order = self.poly_order if poly_order is None else int(poly_order)
|
|
128
|
+
window_length = (
|
|
129
|
+
self.window_length if window_length is None else int(window_length)
|
|
130
|
+
)
|
|
131
|
+
if window_length % 2 == 0:
|
|
132
|
+
window_length += 1
|
|
133
|
+
if window_length > signal.size:
|
|
134
|
+
window_length = signal.size if signal.size % 2 == 1 else signal.size - 1
|
|
135
|
+
if window_length < poly_order + 2:
|
|
136
|
+
poly_order = max(1, window_length - 2)
|
|
137
|
+
return savgol_filter(signal, window_length=window_length, polyorder=poly_order)
|
|
138
|
+
|
|
139
|
+
def _init_omega_scalar(self, fs: float) -> float:
|
|
140
|
+
"""Return the initial center frequency for a new mode."""
|
|
141
|
+
if self.init_omega == 0:
|
|
142
|
+
return 0.0
|
|
143
|
+
return float(np.exp(np.log(fs) + (np.log(0.5) - np.log(fs)) * self.rng.rand()))
|
|
144
|
+
|
|
145
|
+
def _reinit_omega(self, fs: float, omega_d: List[float]) -> Tuple[float, int]:
|
|
146
|
+
"""
|
|
147
|
+
Draw a random ω that is at least ≈ 0.02 (normalised Hz) away from
|
|
148
|
+
previously extracted center frequencies. Returns ``(omega, n2)``.
|
|
149
|
+
"""
|
|
150
|
+
n2 = 0
|
|
151
|
+
omega = 0.0
|
|
152
|
+
while n2 < 300:
|
|
153
|
+
omega = float(
|
|
154
|
+
np.exp(np.log(fs) + (np.log(0.5) - np.log(fs)) * self.rng.rand())
|
|
155
|
+
)
|
|
156
|
+
if len(omega_d) == 0 or np.min(np.abs(np.asarray(omega_d) - omega)) >= 0.02:
|
|
157
|
+
return omega, n2 + 1
|
|
158
|
+
n2 += 1
|
|
159
|
+
return omega, n2
|
|
160
|
+
|
|
161
|
+
# ------------------------------------------------------------------ #
|
|
162
|
+
# Main API
|
|
163
|
+
# ------------------------------------------------------------------ #
|
|
164
|
+
def fit_transform(
|
|
165
|
+
self,
|
|
166
|
+
signal: np.ndarray,
|
|
167
|
+
return_all: bool = False,
|
|
168
|
+
poly_order: Optional[int] = None,
|
|
169
|
+
window_length: Optional[int] = None,
|
|
170
|
+
) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray]]:
|
|
171
|
+
"""
|
|
172
|
+
Decompose a 1-D signal with SVMD.
|
|
173
|
+
|
|
174
|
+
:param signal: real-valued 1-D array (even length preferred; odd
|
|
175
|
+
length is truncated by one sample, matching the MATLAB code).
|
|
176
|
+
:param return_all: if True, also return spectra and center frequencies.
|
|
177
|
+
:param poly_order: optional override of the Savitzky–Golay order.
|
|
178
|
+
:param window_length: optional override of the Savitzky–Golay window.
|
|
179
|
+
:return: modes ``(L, N)``, optionally ``(u, u_hat, omega)``.
|
|
180
|
+
"""
|
|
181
|
+
signal = np.asarray(signal, dtype=float).ravel()
|
|
182
|
+
if signal.size < 4:
|
|
183
|
+
raise ValueError("signal length must be at least 4 samples")
|
|
184
|
+
|
|
185
|
+
# MATLAB: discard the last sample if the length is odd
|
|
186
|
+
if signal.size % 2 == 1:
|
|
187
|
+
signal = signal[:-1]
|
|
188
|
+
save_T = signal.size
|
|
189
|
+
self.signal = signal
|
|
190
|
+
|
|
191
|
+
# ---- Part 1: initialisation -----------------------------------
|
|
192
|
+
y = self._sgolay(signal, poly_order=poly_order, window_length=window_length)
|
|
193
|
+
signoise = signal - y
|
|
194
|
+
fs = 1.0 / save_T
|
|
195
|
+
|
|
196
|
+
# Mirror extension of the signal and of the estimated noise
|
|
197
|
+
f = self.fmirror(signal, save_T // 2)
|
|
198
|
+
fnoise = self.fmirror(signoise, save_T // 2)
|
|
199
|
+
|
|
200
|
+
T = f.size
|
|
201
|
+
t = np.arange(1, T + 1, dtype=float) / T
|
|
202
|
+
omega_freqs = t - 0.5 - 1.0 / T
|
|
203
|
+
half = T // 2
|
|
204
|
+
|
|
205
|
+
# One-sided FFT (Hilbert concept used by VMD / SVMD)
|
|
206
|
+
f_hat = self.fftshift(self.fft(f))
|
|
207
|
+
f_hat_onesided = f_hat.copy()
|
|
208
|
+
f_hat_onesided[:half] = 0.0
|
|
209
|
+
|
|
210
|
+
f_hat_n = self.fftshift(self.fft(fnoise))
|
|
211
|
+
f_hat_n_onesided = f_hat_n.copy()
|
|
212
|
+
f_hat_n_onesided[:half] = 0.0
|
|
213
|
+
noisepe = float(norm(f_hat_n_onesided, ord=2) ** 2)
|
|
214
|
+
|
|
215
|
+
N = self.max_iter
|
|
216
|
+
min_alpha = 10.0
|
|
217
|
+
|
|
218
|
+
# Accumulated modes / filters / frequencies
|
|
219
|
+
modes_hat: List[np.ndarray] = [] # each: (T,) complex
|
|
220
|
+
omega_d: List[float] = []
|
|
221
|
+
alpha_hist: List[float] = []
|
|
222
|
+
h_rows: List[np.ndarray] = [] # filter rows for previously extracted modes
|
|
223
|
+
|
|
224
|
+
# Stopping-criterion auxiliaries
|
|
225
|
+
polm_list: List[float] = []
|
|
226
|
+
polm_temp = 1.0
|
|
227
|
+
bic_list: List[float] = []
|
|
228
|
+
sigerror_list: List[float] = []
|
|
229
|
+
normind_list: List[float] = []
|
|
230
|
+
|
|
231
|
+
SC2 = 0
|
|
232
|
+
mode_idx = 0 # 0-based mode counter (= MATLAB l-1)
|
|
233
|
+
|
|
234
|
+
# ---- Part 2–6: successive extraction --------------------------
|
|
235
|
+
while SC2 != 1 and mode_idx < self.max_modes:
|
|
236
|
+
# Fresh ADMM state for the new mode
|
|
237
|
+
Alpha = min_alpha
|
|
238
|
+
omega_L = np.zeros(N, dtype=float)
|
|
239
|
+
n2 = 0
|
|
240
|
+
if self.init_omega == 0 or mode_idx == 0:
|
|
241
|
+
omega_L[0] = self._init_omega_scalar(fs)
|
|
242
|
+
else:
|
|
243
|
+
omega_L[0], n2 = self._reinit_omega(fs, omega_d)
|
|
244
|
+
|
|
245
|
+
lambda_hat = np.zeros((N, T), dtype=complex)
|
|
246
|
+
u_hat_L = np.zeros((N, T), dtype=complex)
|
|
247
|
+
|
|
248
|
+
udiff = self.tol + self.eps
|
|
249
|
+
n = 0 # 0-based iteration index (MATLAB n starts at 1)
|
|
250
|
+
m = 0.0
|
|
251
|
+
bf = 0
|
|
252
|
+
|
|
253
|
+
h_sum = (
|
|
254
|
+
np.sum(np.vstack(h_rows), axis=0)
|
|
255
|
+
if len(h_rows) > 0
|
|
256
|
+
else np.zeros(T, dtype=float)
|
|
257
|
+
)
|
|
258
|
+
u_sum = (
|
|
259
|
+
np.sum(np.vstack(modes_hat), axis=0)
|
|
260
|
+
if len(modes_hat) > 0
|
|
261
|
+
else np.zeros(T, dtype=complex)
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Outer α-growth loop --------------------------------------
|
|
265
|
+
while Alpha < self.max_alpha + 1:
|
|
266
|
+
# Inner ADMM loop --------------------------------------
|
|
267
|
+
while udiff > self.tol and n < N - 1:
|
|
268
|
+
dw = omega_freqs - omega_L[n]
|
|
269
|
+
dw2 = dw**2
|
|
270
|
+
dw4 = dw2**2
|
|
271
|
+
A2 = Alpha**2
|
|
272
|
+
|
|
273
|
+
# Update mode spectrum û_L (Eq. derived via ADMM)
|
|
274
|
+
numer = (
|
|
275
|
+
f_hat_onesided + (A2 * dw4) * u_hat_L[n] + lambda_hat[n] / 2.0
|
|
276
|
+
)
|
|
277
|
+
denom = 1.0 + (A2 * dw4) * (1.0 + 2.0 * Alpha * dw2) + h_sum
|
|
278
|
+
u_hat_L[n + 1] = numer / denom
|
|
279
|
+
|
|
280
|
+
# Update center frequency ω_L (positive frequencies only)
|
|
281
|
+
power = np.abs(u_hat_L[n + 1, half:]) ** 2
|
|
282
|
+
power_sum = np.sum(power)
|
|
283
|
+
if power_sum > 0:
|
|
284
|
+
omega_L[n + 1] = float(
|
|
285
|
+
np.dot(omega_freqs[half:], power) / power_sum
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
omega_L[n + 1] = omega_L[n]
|
|
289
|
+
|
|
290
|
+
# Dual ascent for λ
|
|
291
|
+
if self.tau != 0.0:
|
|
292
|
+
filter_num = (
|
|
293
|
+
A2
|
|
294
|
+
* dw4
|
|
295
|
+
* (
|
|
296
|
+
f_hat_onesided
|
|
297
|
+
- u_hat_L[n + 1]
|
|
298
|
+
- u_sum
|
|
299
|
+
+ lambda_hat[n] / 2.0
|
|
300
|
+
)
|
|
301
|
+
- u_sum
|
|
302
|
+
)
|
|
303
|
+
filter_den = 1.0 + A2 * dw4
|
|
304
|
+
residual = f_hat_onesided - (
|
|
305
|
+
u_hat_L[n + 1] + filter_num / filter_den + u_sum
|
|
306
|
+
)
|
|
307
|
+
lambda_hat[n + 1] = lambda_hat[n] + self.tau * residual
|
|
308
|
+
else:
|
|
309
|
+
lambda_hat[n + 1] = lambda_hat[n]
|
|
310
|
+
|
|
311
|
+
# Relative spectral update
|
|
312
|
+
diff = u_hat_L[n + 1] - u_hat_L[n]
|
|
313
|
+
num = np.vdot(diff, diff).real / T
|
|
314
|
+
den = np.vdot(u_hat_L[n], u_hat_L[n]).real / T + self.eps
|
|
315
|
+
udiff = abs(num / den)
|
|
316
|
+
n += 1
|
|
317
|
+
|
|
318
|
+
# ---- Part 3: increase α toward max_alpha -------------
|
|
319
|
+
if abs(m - np.log(self.max_alpha)) > 1.0:
|
|
320
|
+
m = m + 1.0
|
|
321
|
+
else:
|
|
322
|
+
m = m + 0.05
|
|
323
|
+
bf = bf + 1
|
|
324
|
+
|
|
325
|
+
if bf >= 2:
|
|
326
|
+
Alpha = Alpha + 1.0
|
|
327
|
+
|
|
328
|
+
if Alpha <= (self.max_alpha - 1.0):
|
|
329
|
+
if bf == 1:
|
|
330
|
+
Alpha = self.max_alpha - 1.0
|
|
331
|
+
else:
|
|
332
|
+
Alpha = float(np.exp(m))
|
|
333
|
+
|
|
334
|
+
# Keep the current ω / spectrum and restart ADMM
|
|
335
|
+
omega_keep = float(omega_L[n])
|
|
336
|
+
temp_ud = u_hat_L[n].copy()
|
|
337
|
+
|
|
338
|
+
udiff = self.tol + self.eps
|
|
339
|
+
n = 0
|
|
340
|
+
lambda_hat = np.zeros((N, T), dtype=complex)
|
|
341
|
+
u_hat_L = np.zeros((N, T), dtype=complex)
|
|
342
|
+
u_hat_L[0] = temp_ud
|
|
343
|
+
omega_L = np.zeros(N, dtype=float)
|
|
344
|
+
omega_L[0] = omega_keep
|
|
345
|
+
|
|
346
|
+
# ---- Part 4: store the converged mode --------------------
|
|
347
|
+
# Last written iterate is index n (MATLAB uses u_hat_L(n,:)
|
|
348
|
+
# after the while, with ω from the previous step).
|
|
349
|
+
mode_spectrum = u_hat_L[n].copy()
|
|
350
|
+
omega_val = float(omega_L[max(n - 1, 0)])
|
|
351
|
+
if omega_val <= 0.0 and n > 0:
|
|
352
|
+
# Fall back to the last strictly positive ω, matching
|
|
353
|
+
# MATLAB ``omega_L = omega_L(omega_L > 0)``.
|
|
354
|
+
pos = omega_L[omega_L > 0]
|
|
355
|
+
omega_val = float(pos[-1]) if pos.size > 0 else float(omega_L[n])
|
|
356
|
+
|
|
357
|
+
modes_hat.append(mode_spectrum)
|
|
358
|
+
omega_d.append(omega_val)
|
|
359
|
+
alpha_hist.append(float(Alpha))
|
|
360
|
+
|
|
361
|
+
# Filter that suppresses this mode in subsequent extractions
|
|
362
|
+
gamma = 1.0
|
|
363
|
+
h_row = gamma / (
|
|
364
|
+
(alpha_hist[-1] ** 2) * (omega_freqs - omega_d[-1]) ** 4 + self.eps
|
|
365
|
+
)
|
|
366
|
+
h_rows.append(h_row)
|
|
367
|
+
|
|
368
|
+
# ---- Part 5: stopping criteria ---------------------------
|
|
369
|
+
u_stack = np.vstack(modes_hat)
|
|
370
|
+
residual = f_hat_onesided - np.sum(u_stack, axis=0)
|
|
371
|
+
|
|
372
|
+
if self.stopc == 1:
|
|
373
|
+
# Residual power vs. estimated noise power
|
|
374
|
+
sigerror = float(norm(residual, ord=2) ** 2)
|
|
375
|
+
sigerror_list.append(sigerror)
|
|
376
|
+
if n2 >= 300 or sigerror <= round(noisepe):
|
|
377
|
+
SC2 = 1
|
|
378
|
+
|
|
379
|
+
elif self.stopc == 2:
|
|
380
|
+
# Exact reconstruction (relative residual energy)
|
|
381
|
+
sum_u = np.sum(u_stack, axis=0)
|
|
382
|
+
ni = (norm(sum_u - f_hat_onesided) ** 2 / T) / (
|
|
383
|
+
norm(f_hat_onesided) ** 2 / T + self.eps
|
|
384
|
+
)
|
|
385
|
+
normind_list.append(float(ni))
|
|
386
|
+
if n2 >= 300 or ni < 0.005:
|
|
387
|
+
SC2 = 1
|
|
388
|
+
|
|
389
|
+
elif self.stopc == 3:
|
|
390
|
+
# Bayesian information criterion
|
|
391
|
+
sigerror = float(norm(residual, ord=2) ** 2)
|
|
392
|
+
sigerror_list.append(sigerror)
|
|
393
|
+
# MATLAB: BIC(l) = 2*T*log(sigerror) + (3*l)*log(2*T)
|
|
394
|
+
# with 1-based l = mode_idx + 1
|
|
395
|
+
bic = 2 * T * np.log(max(sigerror, self.eps)) + (
|
|
396
|
+
3 * (mode_idx + 1)
|
|
397
|
+
) * np.log(2 * T)
|
|
398
|
+
bic_list.append(float(bic))
|
|
399
|
+
if mode_idx >= 1 and bic_list[-1] > bic_list[-2]:
|
|
400
|
+
SC2 = 1
|
|
401
|
+
|
|
402
|
+
else:
|
|
403
|
+
# stopc == 4: power of the last mode (default)
|
|
404
|
+
mode_l = modes_hat[-1]
|
|
405
|
+
omega_l = omega_d[-1]
|
|
406
|
+
# After α-growth, Alpha sits near / above max_alpha
|
|
407
|
+
A = float(Alpha)
|
|
408
|
+
filt = (4.0 * A * mode_l) / (
|
|
409
|
+
1.0 + 2.0 * A * (omega_freqs - omega_l) ** 2
|
|
410
|
+
)
|
|
411
|
+
polm_val = float(norm(filt * np.conj(mode_l), ord=2))
|
|
412
|
+
if mode_idx < 1:
|
|
413
|
+
polm_temp = polm_val if polm_val != 0 else 1.0
|
|
414
|
+
polm_list.append(1.0)
|
|
415
|
+
else:
|
|
416
|
+
polm_list.append(polm_val / (polm_temp + self.eps))
|
|
417
|
+
if abs(polm_list[-1] - polm_list[-2]) < 0.001:
|
|
418
|
+
SC2 = 1
|
|
419
|
+
|
|
420
|
+
# ---- Part 6: prepare the next mode -----------------------
|
|
421
|
+
mode_idx += 1
|
|
422
|
+
|
|
423
|
+
if len(modes_hat) == 0:
|
|
424
|
+
raise RuntimeError("SVMD failed to extract any mode")
|
|
425
|
+
|
|
426
|
+
# ---- Part 7: signal reconstruction ---------------------------
|
|
427
|
+
L = len(modes_hat)
|
|
428
|
+
omega = np.asarray(omega_d, dtype=float)
|
|
429
|
+
|
|
430
|
+
u_hat_full = np.zeros((T, L), dtype=complex)
|
|
431
|
+
stacked = np.vstack(modes_hat).T # (T, L)
|
|
432
|
+
# Hermitian completion identical to VMD / MATLAB SVMD
|
|
433
|
+
idxs = np.flip(np.arange(1, half + 1), axis=0)
|
|
434
|
+
u_hat_full[half:T, :] = stacked[half:T, :]
|
|
435
|
+
u_hat_full[idxs, :] = np.conj(stacked[half:T, :])
|
|
436
|
+
u_hat_full[0, :] = np.conj(u_hat_full[-1, :])
|
|
437
|
+
|
|
438
|
+
u = np.zeros((L, T), dtype=float)
|
|
439
|
+
for ell in range(L):
|
|
440
|
+
u[ell, :] = np.real(self.ifft(self.ifftshift(u_hat_full[:, ell])))
|
|
441
|
+
|
|
442
|
+
# Sort by ascending center frequency
|
|
443
|
+
order = np.argsort(omega)
|
|
444
|
+
omega = omega[order]
|
|
445
|
+
u = u[order, :]
|
|
446
|
+
|
|
447
|
+
# Remove the mirrored borders
|
|
448
|
+
u = u[:, T // 4 : 3 * T // 4]
|
|
449
|
+
|
|
450
|
+
# Recompute spectra on the cropped modes
|
|
451
|
+
u_hat = np.zeros((save_T, L), dtype=complex)
|
|
452
|
+
for ell in range(L):
|
|
453
|
+
u_hat[:, ell] = self.fftshift(self.fft(u[ell, :]))
|
|
454
|
+
|
|
455
|
+
self.u = u
|
|
456
|
+
self.u_hat = u_hat
|
|
457
|
+
self.omega = omega
|
|
458
|
+
|
|
459
|
+
if return_all:
|
|
460
|
+
return u, u_hat, omega
|
|
461
|
+
return u
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def svmd(
|
|
465
|
+
signal: np.ndarray,
|
|
466
|
+
max_alpha: float = 20000,
|
|
467
|
+
tau: float = 0.0,
|
|
468
|
+
tol: float = 1e-6,
|
|
469
|
+
stopc: int = 4,
|
|
470
|
+
init_omega: int = 0,
|
|
471
|
+
max_iter: int = 300,
|
|
472
|
+
return_all: bool = False,
|
|
473
|
+
) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray]]:
|
|
474
|
+
"""
|
|
475
|
+
Functional interface to Successive Variational Mode Decomposition.
|
|
476
|
+
|
|
477
|
+
See :class:`SVMD` for parameter descriptions.
|
|
478
|
+
"""
|
|
479
|
+
return SVMD(
|
|
480
|
+
max_alpha=max_alpha,
|
|
481
|
+
tau=tau,
|
|
482
|
+
tol=tol,
|
|
483
|
+
stopc=stopc,
|
|
484
|
+
init_omega=init_omega,
|
|
485
|
+
max_iter=max_iter,
|
|
486
|
+
).fit_transform(signal=signal, return_all=return_all)
|