PySDKit 0.4.35__tar.gz → 0.4.37__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.35 → pysdkit-0.4.37}/PKG-INFO +3 -3
- {pysdkit-0.4.35 → pysdkit-0.4.37}/PySDKit.egg-info/PKG-INFO +3 -3
- {pysdkit-0.4.35 → pysdkit-0.4.37}/PySDKit.egg-info/SOURCES.txt +4 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/README.md +2 -2
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/__init__.py +16 -2
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/__init__.py +2 -0
- pysdkit-0.4.37/pysdkit/_emd/semd.py +344 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd2d/__init__.py +2 -0
- pysdkit-0.4.37/pysdkit/_emd2d/bmemd.py +413 -0
- pysdkit-0.4.37/pysdkit/_faemd/faemd.py +200 -0
- pysdkit-0.4.37/pysdkit/_faemd/faemd2d.py +151 -0
- pysdkit-0.4.37/pysdkit/_faemd/faemd3d.py +148 -0
- pysdkit-0.4.37/pysdkit/_faemd/filter.py +318 -0
- pysdkit-0.4.37/pysdkit/tests/test_bmemd.py +102 -0
- pysdkit-0.4.37/pysdkit/tests/test_ceemdan.py +202 -0
- pysdkit-0.4.37/pysdkit/tests/test_eemd.py +175 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_faemd.py +14 -0
- pysdkit-0.4.37/pysdkit/tests/test_faemd2d.py +68 -0
- pysdkit-0.4.37/pysdkit/tests/test_faemd3d.py +60 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_mstl.py +8 -4
- pysdkit-0.4.37/pysdkit/tests/test_semd.py +143 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tsa/_mstl.py +3 -1
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tsa/_stl.py +11 -4
- pysdkit-0.4.35/pysdkit/_emd2d/bmemd.py +0 -24
- pysdkit-0.4.35/pysdkit/_faemd/faemd.py +0 -461
- pysdkit-0.4.35/pysdkit/_faemd/faemd2d.py +0 -36
- pysdkit-0.4.35/pysdkit/_faemd/faemd3d.py +0 -33
- pysdkit-0.4.35/pysdkit/_faemd/filter.py +0 -46
- pysdkit-0.4.35/pysdkit/tests/test_ceemdan.py +0 -286
- pysdkit-0.4.35/pysdkit/tests/test_faemd2d.py +0 -11
- pysdkit-0.4.35/pysdkit/tests/test_faemd3d.py +0 -11
- {pysdkit-0.4.35 → pysdkit-0.4.37}/LICENSE +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/PySDKit.egg-info/dependency_links.txt +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/PySDKit.egg-info/requires.txt +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/PySDKit.egg-info/top_level.txt +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pyproject.toml +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_alif/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_alif/alif.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_alif/data/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_alif/data/prefixed_double_filter.npy +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_alif/iterative_filtering.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_apmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_apmd/apmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/_find_extrema.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/_prepare_points.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/_splines.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/ceemdan.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/eemd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/efd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/emd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/hht/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/hht/frequency.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/hht/hht.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/memd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/remd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd/tvf_emd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd2d/bemd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_emd2d/emd2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_esmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_esmd/esmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_ewt/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_ewt/ewt.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_ewt/ewt2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_faemd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_faemd/extrema.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_fmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_fmd/fmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_fmd/nfmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_gdmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_gdmd/gdmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_hvd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_hvd/hvd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_itd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_itd/itd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_jmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_jmd/jmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_jmd/mjmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_jmd/sjmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_lmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_lmd/lmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_lmd/rlmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_osd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_osd/swd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_ssa/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_ssa/ssa.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/acmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/avmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/ba_acmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/base.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/mvmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/ovmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/stvmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/svmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/vmd_c.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/vmd_f.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd/vme.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd2d/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd2d/cvmd2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vmd2d/vmd2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vncmd/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vncmd/avncmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vncmd/incmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/_vncmd/vncmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_add_noise.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_cube.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_generator.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_image.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_models.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_test_univariate.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/_time_series.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/data/texture.txt +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/entropy/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/entropy/_approxiamte_entropy.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/entropy/_permutation_entropy.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/entropy/_sample_entropy.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/models/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/models/_base.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/models/_kmeans.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/models/_knn.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/models/_pca.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/_fourier_spectra.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/_functions.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/_plot_images.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/_plot_imfs.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/plot/_plot_signal.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/data/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/data/test_generator_cube.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/data/test_generator_image.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/data/test_generator_signal.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/data/test_generator_univariate_signal.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/models/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/models/test_knn.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/models/test_pca.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/run_all.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_alif.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_apmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_avncmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_emd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_ewt.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_ewt2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_gdmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_itd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_jmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_lmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_moving_decomp.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_ovmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_rlmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_sjmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_ssa.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_stl.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_stvmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_svmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_swd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_vmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_vmd2d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tests/test_vncmd.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tsa/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tsa/_dtw.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/tsa/_moving_decomp.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/__init__.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_cite.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_correlation.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_diagnalization.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_differ.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_fft.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_function.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_hilbert.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_instantaneous.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_kernel_matrix.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_mirror.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_process.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/pysdkit/utils/_smooth1d.py +0 -0
- {pysdkit-0.4.35 → pysdkit-0.4.37}/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.37
|
|
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>
|
|
@@ -155,8 +155,8 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
155
155
|
| [`TVF_EMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/tvf_emd.py) (Time Varying Filter Based EMD) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168417301135) | [[code]](https://github.com/stfbnc/pytvfemd/tree/master) | ✔️ |
|
|
156
156
|
| [`EFD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/efd.py) (Empirical Fourier Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327021005355) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/97747-empirical-fourier-decomposition-efd) | ✔️ |
|
|
157
157
|
| [`FAEMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd.py) (Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
158
|
-
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
159
|
-
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
158
|
+
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
159
|
+
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
160
160
|
| [`HVD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_hvd/hvd.py) (Hilbert Vibration Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X06001556) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/178804-hilbert-vibration-decomposition?s_tid=FX_rc1_behav) | ✔️ |
|
|
161
161
|
| [`ITD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_itd/itd.py) (Intrinsic Time-Scale Decomposition) | [[paper]](https://royalsocietypublishing.org/doi/10.1098/rspa.2006.1761) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/69380-intrinsic-time-scale-decomposition-itd) | ✔️ |
|
|
162
162
|
| [`ALIF`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_alif/alif.py) (Adaptive Local Iterative Filtering) | [[paper]](https://arxiv.org/abs/1411.6051) | [[code]](https://github.com/Cicone/ALIF) | ✔️ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PySDKit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.37
|
|
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>
|
|
@@ -155,8 +155,8 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
155
155
|
| [`TVF_EMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/tvf_emd.py) (Time Varying Filter Based EMD) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168417301135) | [[code]](https://github.com/stfbnc/pytvfemd/tree/master) | ✔️ |
|
|
156
156
|
| [`EFD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/efd.py) (Empirical Fourier Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327021005355) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/97747-empirical-fourier-decomposition-efd) | ✔️ |
|
|
157
157
|
| [`FAEMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd.py) (Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
158
|
-
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
159
|
-
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
158
|
+
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
159
|
+
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
160
160
|
| [`HVD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_hvd/hvd.py) (Hilbert Vibration Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X06001556) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/178804-hilbert-vibration-decomposition?s_tid=FX_rc1_behav) | ✔️ |
|
|
161
161
|
| [`ITD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_itd/itd.py) (Intrinsic Time-Scale Decomposition) | [[paper]](https://royalsocietypublishing.org/doi/10.1098/rspa.2006.1761) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/69380-intrinsic-time-scale-decomposition-itd) | ✔️ |
|
|
162
162
|
| [`ALIF`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_alif/alif.py) (Adaptive Local Iterative Filtering) | [[paper]](https://arxiv.org/abs/1411.6051) | [[code]](https://github.com/Cicone/ALIF) | ✔️ |
|
|
@@ -24,6 +24,7 @@ pysdkit/_emd/efd.py
|
|
|
24
24
|
pysdkit/_emd/emd.py
|
|
25
25
|
pysdkit/_emd/memd.py
|
|
26
26
|
pysdkit/_emd/remd.py
|
|
27
|
+
pysdkit/_emd/semd.py
|
|
27
28
|
pysdkit/_emd/tvf_emd.py
|
|
28
29
|
pysdkit/_emd/hht/__init__.py
|
|
29
30
|
pysdkit/_emd/hht/frequency.py
|
|
@@ -111,7 +112,9 @@ pysdkit/tests/run_all.py
|
|
|
111
112
|
pysdkit/tests/test_alif.py
|
|
112
113
|
pysdkit/tests/test_apmd.py
|
|
113
114
|
pysdkit/tests/test_avncmd.py
|
|
115
|
+
pysdkit/tests/test_bmemd.py
|
|
114
116
|
pysdkit/tests/test_ceemdan.py
|
|
117
|
+
pysdkit/tests/test_eemd.py
|
|
115
118
|
pysdkit/tests/test_emd.py
|
|
116
119
|
pysdkit/tests/test_ewt.py
|
|
117
120
|
pysdkit/tests/test_ewt2d.py
|
|
@@ -126,6 +129,7 @@ pysdkit/tests/test_moving_decomp.py
|
|
|
126
129
|
pysdkit/tests/test_mstl.py
|
|
127
130
|
pysdkit/tests/test_ovmd.py
|
|
128
131
|
pysdkit/tests/test_rlmd.py
|
|
132
|
+
pysdkit/tests/test_semd.py
|
|
129
133
|
pysdkit/tests/test_sjmd.py
|
|
130
134
|
pysdkit/tests/test_ssa.py
|
|
131
135
|
pysdkit/tests/test_stl.py
|
|
@@ -101,8 +101,8 @@ plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
|
101
101
|
| [`TVF_EMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/tvf_emd.py) (Time Varying Filter Based EMD) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0165168417301135) | [[code]](https://github.com/stfbnc/pytvfemd/tree/master) | ✔️ |
|
|
102
102
|
| [`EFD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_emd/efd.py) (Empirical Fourier Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327021005355) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/97747-empirical-fourier-decomposition-efd) | ✔️ |
|
|
103
103
|
| [`FAEMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd.py) (Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
104
|
-
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
105
|
-
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) |
|
|
104
|
+
| [`FAEMD2D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd2d.py) (Two-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
105
|
+
| [`FAEMD3D`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_faemd/faemd3d.py) (Three-Dimensional Fast and Adaptive EMD) | [[paper]](https://ieeexplore.ieee.org/document/8447300) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/71270-fast-and-adaptive-multivariate-and-multidimensional-emd) | ✔️ |
|
|
106
106
|
| [`HVD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_hvd/hvd.py) (Hilbert Vibration Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X06001556) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/178804-hilbert-vibration-decomposition?s_tid=FX_rc1_behav) | ✔️ |
|
|
107
107
|
| [`ITD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_itd/itd.py) (Intrinsic Time-Scale Decomposition) | [[paper]](https://royalsocietypublishing.org/doi/10.1098/rspa.2006.1761) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/69380-intrinsic-time-scale-decomposition-itd) | ✔️ |
|
|
108
108
|
| [`ALIF`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_alif/alif.py) (Adaptive Local Iterative Filtering) | [[paper]](https://arxiv.org/abs/1411.6051) | [[code]](https://github.com/Cicone/ALIF) | ✔️ |
|
|
@@ -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.37"
|
|
6
6
|
|
|
7
7
|
# Empirical Mode Decomposition
|
|
8
8
|
from ._emd import EMD
|
|
@@ -19,6 +19,9 @@ from ._emd import REMD
|
|
|
19
19
|
# Multivariate Empirical Mode Decomposition
|
|
20
20
|
from ._emd import MEMD
|
|
21
21
|
|
|
22
|
+
# Serial Empirical Mode Decomposition
|
|
23
|
+
from ._emd import SEMD
|
|
24
|
+
|
|
22
25
|
# Time Varying Filter based Empirical Mode Decomposition
|
|
23
26
|
from ._emd import TVF_EMD
|
|
24
27
|
|
|
@@ -26,11 +29,14 @@ from ._emd import TVF_EMD
|
|
|
26
29
|
from ._emd import EFD
|
|
27
30
|
|
|
28
31
|
# Fast and Adaptive Empirical Mode Decomposition
|
|
29
|
-
from ._faemd import FAEMD
|
|
32
|
+
from ._faemd import FAEMD, FAEMD2D, FAEMD3D
|
|
30
33
|
|
|
31
34
|
# Empirical Mode Decomposition 2D for images
|
|
32
35
|
from ._emd2d import EMD2D
|
|
33
36
|
|
|
37
|
+
# Bidimensional Multivariate Empirical Mode Decomposition
|
|
38
|
+
from ._emd2d import BMEMD
|
|
39
|
+
|
|
34
40
|
# Hilbert Vibration Decomposition
|
|
35
41
|
from ._hvd import HVD
|
|
36
42
|
|
|
@@ -153,10 +159,14 @@ Ensemble Empirical Mode Decomposition | EEMD
|
|
|
153
159
|
Complete Ensemble EMD with Adaptive Noise | CEEMDAN
|
|
154
160
|
Robust Empirical Mode Decomposition | REMD
|
|
155
161
|
Multivariate Empirical Mode Decomposition | MEMD
|
|
162
|
+
Serial Empirical Mode Decomposition | SEMD
|
|
156
163
|
Time Varying Filter based EMD | TVF_EMD
|
|
157
164
|
Empirical Fourier Decomposition | EFD
|
|
158
165
|
Fast and Adaptive Empirical Mode Decomposition | FAEMD
|
|
166
|
+
Bidimensional FAEMD | FAEMD2D
|
|
167
|
+
Tridimensional FAEMD | FAEMD3D
|
|
159
168
|
Empirical Mode Decomposition 2D for images | EMD2D
|
|
169
|
+
Bidimensional Multivariate EMD | BMEMD
|
|
160
170
|
Hilbert Vibration Decomposition | HVD
|
|
161
171
|
Intrinsic Time-Scale Decomposition | ITD
|
|
162
172
|
Local Mean Decomposition | LMD
|
|
@@ -198,10 +208,14 @@ __all__ = [
|
|
|
198
208
|
"CEEMDAN",
|
|
199
209
|
"REMD",
|
|
200
210
|
"MEMD",
|
|
211
|
+
"SEMD",
|
|
201
212
|
"TVF_EMD",
|
|
202
213
|
"EFD",
|
|
203
214
|
"FAEMD",
|
|
215
|
+
"FAEMD2D",
|
|
216
|
+
"FAEMD3D",
|
|
204
217
|
"EMD2D",
|
|
218
|
+
"BMEMD",
|
|
205
219
|
"HVD",
|
|
206
220
|
"ITD",
|
|
207
221
|
"LMD",
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on 2026/08/01
|
|
4
|
+
@author: Whenxuan Wang
|
|
5
|
+
@email: wwhenxuan@gmail.com
|
|
6
|
+
|
|
7
|
+
Serial-EMD (SEMD): fast multi-signal EMD via 1-D serialization.
|
|
8
|
+
|
|
9
|
+
Zhang, J., Feng, F., Marti-Puig, P., Caiafa, C. F., Sun, Z., Duan, F.,
|
|
10
|
+
and Solé-Casals, J. (2021).
|
|
11
|
+
Serial-EMD: Fast Empirical Mode Decomposition Method for Multi-dimensional
|
|
12
|
+
Signals Based on Serialization. Information Sciences.
|
|
13
|
+
https://doi.org/10.1016/j.ins.2021.09.033
|
|
14
|
+
|
|
15
|
+
Reference code: https://github.com/ffbear1993/serial-emd
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Optional, Tuple, Union
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
from .emd import EMD
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def concatenate_signals(matrix_x: np.ndarray, num_interval: int) -> np.ndarray:
|
|
28
|
+
"""
|
|
29
|
+
Serialize multi-channel signals with smooth transition bridges.
|
|
30
|
+
|
|
31
|
+
Follows Zhang et al. (2021) / the official ``serial-emd`` Python reference.
|
|
32
|
+
|
|
33
|
+
:param matrix_x: Array of shape ``(M, N)`` — ``M`` samples (rows),
|
|
34
|
+
``N`` channels (columns).
|
|
35
|
+
:param num_interval: Transition length ``D`` (``1 <= D < M``).
|
|
36
|
+
:return: 1-D serialized signal of length ``M*N + D*(N-1)``.
|
|
37
|
+
"""
|
|
38
|
+
matrix_x = np.asarray(matrix_x, dtype=float)
|
|
39
|
+
if matrix_x.ndim != 2:
|
|
40
|
+
raise ValueError(
|
|
41
|
+
"matrix_x must be a 2-D array of shape (n_samples, n_channels)"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
n_length, n_signal = matrix_x.shape
|
|
45
|
+
if n_signal < 1:
|
|
46
|
+
raise ValueError("matrix_x must contain at least one channel")
|
|
47
|
+
if n_signal == 1:
|
|
48
|
+
return matrix_x[:, 0].copy()
|
|
49
|
+
|
|
50
|
+
d = int(num_interval)
|
|
51
|
+
if d < 1 or d >= n_length:
|
|
52
|
+
raise ValueError(
|
|
53
|
+
f"num_interval must satisfy 1 <= D < M; got D={d}, M={n_length}"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Heads of channels 2..N and tails of channels 1..N-1
|
|
57
|
+
matrix_a = matrix_x[:d, 1:]
|
|
58
|
+
matrix_b = matrix_x[-d:, :-1]
|
|
59
|
+
|
|
60
|
+
# Ramp weights a_i = i / (D+1), i = 1..D (endpoints 0 and 1 excluded)
|
|
61
|
+
vector_a = np.linspace(0.0, 1.0, d + 2)[1:-1].reshape(-1, 1)
|
|
62
|
+
vector_u = np.ones((n_signal - 1, 1))
|
|
63
|
+
|
|
64
|
+
# Transition: flip(head_{i+1}) ⊙ a + flip(tail_i) ⊙ flip(a)
|
|
65
|
+
matrix_t_a = np.flipud(matrix_a) * (vector_a @ vector_u.T)
|
|
66
|
+
matrix_t_b = np.flipud(matrix_b) * (np.flipud(vector_a) @ vector_u.T)
|
|
67
|
+
matrix_t = matrix_t_a + matrix_t_b
|
|
68
|
+
|
|
69
|
+
# Append a dummy zero column so Fortran flattening yields the desired layout
|
|
70
|
+
matrix_z = np.zeros((d, 1))
|
|
71
|
+
matrix_t = np.concatenate([matrix_t, matrix_z], axis=1)
|
|
72
|
+
|
|
73
|
+
# Stack transitions under the original block, then column-major vectorize
|
|
74
|
+
matrix_r = np.concatenate([matrix_x, matrix_t], axis=0)
|
|
75
|
+
matrix_r = matrix_r.flatten(order="F")
|
|
76
|
+
return matrix_r[:-d]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def deconcatenate_imfs(
|
|
80
|
+
matrix_r: np.ndarray,
|
|
81
|
+
num_interval: int,
|
|
82
|
+
num_signal: int,
|
|
83
|
+
num_length: Optional[int] = None,
|
|
84
|
+
) -> np.ndarray:
|
|
85
|
+
"""
|
|
86
|
+
Split serialized IMFs back into per-channel IMF tensors.
|
|
87
|
+
|
|
88
|
+
:param matrix_r: Serialized IMFs of shape ``(L, K)`` (or ``(L,)`` for one IMF).
|
|
89
|
+
:param num_interval: Transition length ``D`` used during concatenation.
|
|
90
|
+
:param num_signal: Number of original channels ``N``.
|
|
91
|
+
:param num_length: Original per-channel length ``M``. Inferred from ``L``
|
|
92
|
+
when omitted via ``L = M*N + D*(N-1)``.
|
|
93
|
+
:return: Array of shape ``(M, K, N)``.
|
|
94
|
+
"""
|
|
95
|
+
matrix_r = np.asarray(matrix_r, dtype=float)
|
|
96
|
+
if matrix_r.ndim == 1:
|
|
97
|
+
matrix_r = matrix_r.reshape(-1, 1)
|
|
98
|
+
if matrix_r.ndim != 2:
|
|
99
|
+
raise ValueError("matrix_r must have shape (L, K)")
|
|
100
|
+
|
|
101
|
+
d = int(num_interval)
|
|
102
|
+
n_signal = int(num_signal)
|
|
103
|
+
if n_signal < 1:
|
|
104
|
+
raise ValueError("num_signal must be >= 1")
|
|
105
|
+
|
|
106
|
+
length_ser, num_mode = matrix_r.shape
|
|
107
|
+
if n_signal == 1:
|
|
108
|
+
m = length_ser if num_length is None else int(num_length)
|
|
109
|
+
if m != length_ser:
|
|
110
|
+
raise ValueError("num_length does not match serialized length for N=1")
|
|
111
|
+
return matrix_r.reshape(m, num_mode, 1)
|
|
112
|
+
|
|
113
|
+
if d < 1:
|
|
114
|
+
raise ValueError("num_interval must be >= 1")
|
|
115
|
+
|
|
116
|
+
if num_length is None:
|
|
117
|
+
# L = M*N + D*(N-1) ⇒ M = (L - D*(N-1)) / N
|
|
118
|
+
numer = length_ser - d * (n_signal - 1)
|
|
119
|
+
if numer % n_signal != 0:
|
|
120
|
+
raise ValueError(
|
|
121
|
+
"Cannot infer num_length from serialized IMF length; "
|
|
122
|
+
"please pass num_length explicitly"
|
|
123
|
+
)
|
|
124
|
+
m = numer // n_signal
|
|
125
|
+
else:
|
|
126
|
+
m = int(num_length)
|
|
127
|
+
|
|
128
|
+
expected = m * n_signal + d * (n_signal - 1)
|
|
129
|
+
if length_ser != expected:
|
|
130
|
+
raise ValueError(
|
|
131
|
+
f"Serialized length {length_ser} incompatible with "
|
|
132
|
+
f"M={m}, N={n_signal}, D={d} (expected {expected})"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Pad D zeros, reshape Fortran-order to (M+D, N, K), drop transitions
|
|
136
|
+
matrix_z = np.zeros((d, num_mode))
|
|
137
|
+
matrix_pad = np.concatenate([matrix_r, matrix_z], axis=0)
|
|
138
|
+
matrix_imf = matrix_pad.reshape([-1, n_signal, num_mode], order="F")
|
|
139
|
+
matrix_imf = matrix_imf[:-d, :, :]
|
|
140
|
+
return matrix_imf.transpose((0, 2, 1))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def transition_bridge(
|
|
144
|
+
tail: np.ndarray, head: np.ndarray, num_interval: Optional[int] = None
|
|
145
|
+
) -> np.ndarray:
|
|
146
|
+
"""
|
|
147
|
+
Build the linear cross-fade bridge between two adjacent channels.
|
|
148
|
+
|
|
149
|
+
Useful for visualizing how SEMD constructs the transition that keeps the
|
|
150
|
+
mean envelope continuous across channel joins.
|
|
151
|
+
|
|
152
|
+
:param tail: Last ``D`` samples of channel ``i`` (or a longer suffix).
|
|
153
|
+
:param head: First ``D`` samples of channel ``i+1`` (or a longer prefix).
|
|
154
|
+
:param num_interval: Bridge length; defaults to ``min(len(tail), len(head))``.
|
|
155
|
+
:return: Bridge segment of length ``D``.
|
|
156
|
+
"""
|
|
157
|
+
tail = np.asarray(tail, dtype=float).ravel()
|
|
158
|
+
head = np.asarray(head, dtype=float).ravel()
|
|
159
|
+
d = int(num_interval) if num_interval is not None else min(len(tail), len(head))
|
|
160
|
+
if d < 1 or d > len(tail) or d > len(head):
|
|
161
|
+
raise ValueError("num_interval exceeds available head/tail length")
|
|
162
|
+
|
|
163
|
+
a = np.linspace(0.0, 1.0, d + 2)[1:-1]
|
|
164
|
+
return np.flipud(head[:d]) * a + np.flipud(tail[-d:]) * np.flipud(a)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class SEMD(object):
|
|
168
|
+
"""
|
|
169
|
+
Serial Empirical Mode Decomposition (Serial-EMD / SEMD)
|
|
170
|
+
|
|
171
|
+
Zhang et al., Information Sciences, 2021.
|
|
172
|
+
|
|
173
|
+
SEMD concatenates multi-channel signals into one long 1-D series with
|
|
174
|
+
smooth transition bridges, runs a standard 1-D EMD (or a compatible
|
|
175
|
+
variant), then splits the IMFs back to each original channel. This
|
|
176
|
+
avoids expensive multivariate envelope interpolation (MEMD / BEMD)
|
|
177
|
+
while reusing any existing univariate EMD backend.
|
|
178
|
+
|
|
179
|
+
Input layout (PySDKit convention)
|
|
180
|
+
---------------------------------
|
|
181
|
+
- univariate: ``(seq_len,)``
|
|
182
|
+
- multivariate: ``(n_channels, seq_len)``
|
|
183
|
+
|
|
184
|
+
Output layout
|
|
185
|
+
-------------
|
|
186
|
+
- univariate: ``(K, seq_len)``
|
|
187
|
+
- multivariate: ``(K, seq_len, n_channels)``
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def __init__(
|
|
191
|
+
self,
|
|
192
|
+
num_interval: Optional[int] = None,
|
|
193
|
+
interval_ratio: float = 0.2,
|
|
194
|
+
max_imfs: int = -1,
|
|
195
|
+
emd: Optional[EMD] = None,
|
|
196
|
+
**emd_kwargs,
|
|
197
|
+
) -> None:
|
|
198
|
+
"""
|
|
199
|
+
:param num_interval: Transition length ``D``. If ``None``, uses
|
|
200
|
+
``max(1, round(interval_ratio * seq_len))``.
|
|
201
|
+
:param interval_ratio: Fraction of each channel length used for ``D``
|
|
202
|
+
when ``num_interval`` is not given (paper default ≈ 0.2).
|
|
203
|
+
:param max_imfs: Maximum number of IMFs forwarded to the EMD backend
|
|
204
|
+
(``-1`` means no hard limit).
|
|
205
|
+
:param emd: Optional pre-configured univariate decomposer. Must
|
|
206
|
+
expose ``fit_transform(signal, max_imfs=...)`` returning
|
|
207
|
+
``(K, L)``. Defaults to :class:`pysdkit._emd.emd.EMD`.
|
|
208
|
+
:param emd_kwargs: Extra keyword arguments used when constructing the
|
|
209
|
+
default :class:`EMD` instance.
|
|
210
|
+
"""
|
|
211
|
+
if num_interval is not None and int(num_interval) < 1:
|
|
212
|
+
raise ValueError("num_interval must be a positive integer or None")
|
|
213
|
+
if not (0.0 < float(interval_ratio) <= 1.0):
|
|
214
|
+
raise ValueError("interval_ratio must lie in (0, 1]")
|
|
215
|
+
|
|
216
|
+
self.num_interval = None if num_interval is None else int(num_interval)
|
|
217
|
+
self.interval_ratio = float(interval_ratio)
|
|
218
|
+
self.max_imfs = int(max_imfs)
|
|
219
|
+
self.emd = emd if emd is not None else EMD(max_imfs=self.max_imfs, **emd_kwargs)
|
|
220
|
+
|
|
221
|
+
# Cached intermediates for inspection / plotting
|
|
222
|
+
self.serialized_signal: Optional[np.ndarray] = None
|
|
223
|
+
self.serialized_imfs: Optional[np.ndarray] = None
|
|
224
|
+
self.imfs: Optional[np.ndarray] = None
|
|
225
|
+
self._last_shape: Optional[Tuple[int, int]] = None # (N, M)
|
|
226
|
+
self._last_D: Optional[int] = None
|
|
227
|
+
|
|
228
|
+
def __str__(self) -> str:
|
|
229
|
+
return "Serial Empirical Mode Decomposition (SEMD)"
|
|
230
|
+
|
|
231
|
+
def __call__(
|
|
232
|
+
self, signal: np.ndarray, max_imfs: Optional[int] = None
|
|
233
|
+
) -> np.ndarray:
|
|
234
|
+
return self.fit_transform(signal=signal, max_imfs=max_imfs)
|
|
235
|
+
|
|
236
|
+
def resolve_interval(self, seq_len: int) -> int:
|
|
237
|
+
"""Resolve the transition length ``D`` for a given channel length."""
|
|
238
|
+
if self.num_interval is not None:
|
|
239
|
+
d = self.num_interval
|
|
240
|
+
else:
|
|
241
|
+
d = max(1, int(round(self.interval_ratio * seq_len)))
|
|
242
|
+
if d >= seq_len:
|
|
243
|
+
d = max(1, seq_len - 1)
|
|
244
|
+
return d
|
|
245
|
+
|
|
246
|
+
def serialize(self, signal: np.ndarray) -> Tuple[np.ndarray, int]:
|
|
247
|
+
"""
|
|
248
|
+
Convert a PySDKit multivariate array into the serialized 1-D series.
|
|
249
|
+
|
|
250
|
+
:param signal: ``(n_channels, seq_len)`` or ``(seq_len,)``
|
|
251
|
+
:return: ``(serialized_1d, D)``
|
|
252
|
+
"""
|
|
253
|
+
x = np.asarray(signal, dtype=float)
|
|
254
|
+
if x.ndim == 1:
|
|
255
|
+
return x.copy(), 0
|
|
256
|
+
if x.ndim != 2:
|
|
257
|
+
raise ValueError(
|
|
258
|
+
"signal must be 1-D (seq_len,) or 2-D (n_channels, seq_len)"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
n_channels, seq_len = x.shape
|
|
262
|
+
d = self.resolve_interval(seq_len)
|
|
263
|
+
# Paper / reference layout: time in rows, channels in columns
|
|
264
|
+
serialized = concatenate_signals(x.T, d)
|
|
265
|
+
return serialized, d
|
|
266
|
+
|
|
267
|
+
def fit_transform(
|
|
268
|
+
self, signal: np.ndarray, max_imfs: Optional[int] = None
|
|
269
|
+
) -> np.ndarray:
|
|
270
|
+
"""
|
|
271
|
+
Decompose uni-/multi-channel signals with Serial-EMD.
|
|
272
|
+
|
|
273
|
+
:param signal: ``(seq_len,)`` or ``(n_channels, seq_len)``
|
|
274
|
+
:param max_imfs: Optional override for the maximum number of IMFs
|
|
275
|
+
:return: IMFs with shape ``(K, seq_len)`` or ``(K, seq_len, n_channels)``
|
|
276
|
+
"""
|
|
277
|
+
x = np.asarray(signal, dtype=float)
|
|
278
|
+
if max_imfs is None:
|
|
279
|
+
max_imfs = self.max_imfs
|
|
280
|
+
# Only forward a hard cap when it is positive; otherwise let the backend decide
|
|
281
|
+
emd_kwargs = (
|
|
282
|
+
{}
|
|
283
|
+
if (max_imfs is None or int(max_imfs) < 0)
|
|
284
|
+
else {"max_imfs": int(max_imfs)}
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if x.ndim == 1:
|
|
288
|
+
imfs = self.emd.fit_transform(x, **emd_kwargs)
|
|
289
|
+
self.serialized_signal = x.copy()
|
|
290
|
+
self.serialized_imfs = np.asarray(imfs).T # (L, K)
|
|
291
|
+
self.imfs = np.asarray(imfs)
|
|
292
|
+
self._last_shape = (1, x.size)
|
|
293
|
+
self._last_D = 0
|
|
294
|
+
return self.imfs
|
|
295
|
+
|
|
296
|
+
if x.ndim != 2:
|
|
297
|
+
raise ValueError(
|
|
298
|
+
"signal must be 1-D (seq_len,) or 2-D (n_channels, seq_len)"
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
n_channels, seq_len = x.shape
|
|
302
|
+
if n_channels < 1 or seq_len < 2:
|
|
303
|
+
raise ValueError("Invalid multivariate signal shape")
|
|
304
|
+
|
|
305
|
+
d = self.resolve_interval(seq_len)
|
|
306
|
+
serialized = concatenate_signals(x.T, d)
|
|
307
|
+
self.serialized_signal = serialized
|
|
308
|
+
self._last_shape = (n_channels, seq_len)
|
|
309
|
+
self._last_D = d
|
|
310
|
+
|
|
311
|
+
# Univariate EMD on the long series → (K, L)
|
|
312
|
+
ser_imfs = np.asarray(self.emd.fit_transform(serialized, **emd_kwargs))
|
|
313
|
+
if ser_imfs.ndim != 2:
|
|
314
|
+
raise RuntimeError("EMD backend must return a 2-D IMF array (K, L)")
|
|
315
|
+
self.serialized_imfs = ser_imfs.T # (L, K)
|
|
316
|
+
|
|
317
|
+
# (M, K, N)
|
|
318
|
+
imfs_mkn = deconcatenate_imfs(
|
|
319
|
+
self.serialized_imfs,
|
|
320
|
+
num_interval=d,
|
|
321
|
+
num_signal=n_channels,
|
|
322
|
+
num_length=seq_len,
|
|
323
|
+
)
|
|
324
|
+
# PySDKit multivariate layout: (K, seq_len, n_channels)
|
|
325
|
+
self.imfs = np.transpose(imfs_mkn, (1, 0, 2))
|
|
326
|
+
return self.imfs
|
|
327
|
+
|
|
328
|
+
def reconstruct(self, imfs: Optional[np.ndarray] = None) -> np.ndarray:
|
|
329
|
+
"""
|
|
330
|
+
Sum IMFs to reconstruct the original channel(s).
|
|
331
|
+
|
|
332
|
+
:param imfs: Optional IMF tensor; defaults to the last ``fit_transform`` result.
|
|
333
|
+
:return: ``(seq_len,)`` or ``(n_channels, seq_len)``
|
|
334
|
+
"""
|
|
335
|
+
if imfs is None:
|
|
336
|
+
if self.imfs is None:
|
|
337
|
+
raise RuntimeError("Call fit_transform before reconstruct()")
|
|
338
|
+
imfs = self.imfs
|
|
339
|
+
imfs = np.asarray(imfs)
|
|
340
|
+
if imfs.ndim == 2:
|
|
341
|
+
return np.sum(imfs, axis=0)
|
|
342
|
+
if imfs.ndim == 3:
|
|
343
|
+
return np.sum(imfs, axis=0).T # (N, M)
|
|
344
|
+
raise ValueError("imfs must be 2-D or 3-D")
|