PySDKit 0.4.48__tar.gz → 0.4.49__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.48 → pysdkit-0.4.49}/PKG-INFO +2 -2
- {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/PKG-INFO +2 -2
- {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/SOURCES.txt +2 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/README.md +1 -1
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/__init__.py +5 -1
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/__init__.py +4 -1
- pysdkit-0.4.49/pysdkit/_acmd/dd_acmd.py +509 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_acmd.py +37 -1
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_baacmd.py +38 -0
- pysdkit-0.4.49/pysdkit/tests/test_ddacmd.py +246 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/LICENSE +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/dependency_links.txt +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/requires.txt +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/top_level.txt +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pyproject.toml +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/acmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/ba_acmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_find_extrema.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_prepare_points.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_splines.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/ceemdan.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/eemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/efd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/emd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/esmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/frequency.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/hht.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/memd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/remd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/semd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/tvf_emd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/bemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/bmemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/emd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/ewt.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/ewt2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/extrema.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd3d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/filter.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/agncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/gdmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/ivgnmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/vgnmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/apmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/data/gearbox_fault_snippet.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/data/input_sig.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/imd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/jmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/mjmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/sjmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/lmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/rlmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/components.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/osd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/swd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/dual_signal_noise.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/map2.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/single_nsignal.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/vtfmtd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/alif.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/data/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/data/prefixed_double_filter.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/fmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/hvd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/itd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/iterative_filtering.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/ssa.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/avmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/base.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/mvmd.py +0 -0
- /pysdkit-0.4.48/pysdkit/_acmd/dd_acmd.py → /pysdkit-0.4.49/pysdkit/_vmd/namvmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/ovmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/stvmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/svmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vmd_c.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vmd_f.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vme.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/cvmd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/vmd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/avncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/incmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/stnbmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/vncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_add_noise.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_cube.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_generator.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_image.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_models.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_test_univariate.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_time_series.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/fmd_demo.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/texture.txt +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/vmd_example.npy +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_approxiamte_entropy.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_permutation_entropy.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_sample_entropy.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_base.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_kmeans.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_knn.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_pca.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_fourier_spectra.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_functions.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_images.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_imfs.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_signal.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_cube.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_image.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_signal.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_univariate_signal.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/test_knn.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/test_pca.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/run_all.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_agncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_alif.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_apmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_avncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_bmemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ceemdan.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_cvmd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_eemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_emd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_esmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ewt.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ewt2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd3d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_fmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_gdmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_hvd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_imd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_itd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ivgnmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_jmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_lmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_moving_decomp.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_mstl.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_osd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ovmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_rlmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_semd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_sjmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ssa.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stl.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stnbmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stvmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_svmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_swd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vgnmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vmd2d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vncmd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vtfmtd.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_dtw.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_moving_decomp.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_mstl.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_stl.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/__init__.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_correlation.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_diagnalization.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_differ.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_fft.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_function.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_hilbert.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_instantaneous.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_kernel_matrix.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_mirror.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_process.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_smooth1d.py +0 -0
- {pysdkit-0.4.48 → pysdkit-0.4.49}/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.49
|
|
4
4
|
Summary: A Python library for signal decomposition algorithms with a unified interface.
|
|
5
5
|
Author: Whenxuan Wang, RuiZhe Wang, Rongkun Zhu, Kai Wu, Lei Wang, josefinez, Deeksha Manjunath, Yuan Feng, WenTong Zhao, JacktheFowler
|
|
6
6
|
Maintainer-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>
|
|
@@ -189,7 +189,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
|
|
|
189
189
|
| [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
|
|
190
190
|
| [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
191
191
|
| [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
|
|
192
|
-
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) |
|
|
192
|
+
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
|
|
193
193
|
| [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
|
|
194
194
|
| [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
|
|
195
195
|
| [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PySDKit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.49
|
|
4
4
|
Summary: A Python library for signal decomposition algorithms with a unified interface.
|
|
5
5
|
Author: Whenxuan Wang, RuiZhe Wang, Rongkun Zhu, Kai Wu, Lei Wang, josefinez, Deeksha Manjunath, Yuan Feng, WenTong Zhao, JacktheFowler
|
|
6
6
|
Maintainer-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>
|
|
@@ -189,7 +189,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
|
|
|
189
189
|
| [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
|
|
190
190
|
| [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
191
191
|
| [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
|
|
192
|
-
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) |
|
|
192
|
+
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
|
|
193
193
|
| [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
|
|
194
194
|
| [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
|
|
195
195
|
| [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
|
|
@@ -80,6 +80,7 @@ pysdkit/_vmd/__init__.py
|
|
|
80
80
|
pysdkit/_vmd/avmd.py
|
|
81
81
|
pysdkit/_vmd/base.py
|
|
82
82
|
pysdkit/_vmd/mvmd.py
|
|
83
|
+
pysdkit/_vmd/namvmd.py
|
|
83
84
|
pysdkit/_vmd/ovmd.py
|
|
84
85
|
pysdkit/_vmd/stvmd.py
|
|
85
86
|
pysdkit/_vmd/svmd.py
|
|
@@ -131,6 +132,7 @@ pysdkit/tests/test_baacmd.py
|
|
|
131
132
|
pysdkit/tests/test_bmemd.py
|
|
132
133
|
pysdkit/tests/test_ceemdan.py
|
|
133
134
|
pysdkit/tests/test_cvmd2d.py
|
|
135
|
+
pysdkit/tests/test_ddacmd.py
|
|
134
136
|
pysdkit/tests/test_eemd.py
|
|
135
137
|
pysdkit/tests/test_emd.py
|
|
136
138
|
pysdkit/tests/test_esmd.py
|
|
@@ -136,7 +136,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
|
|
|
136
136
|
| [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
|
|
137
137
|
| [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
|
|
138
138
|
| [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
|
|
139
|
-
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) |
|
|
139
|
+
| [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
|
|
140
140
|
| [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
|
|
141
141
|
| [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
|
|
142
142
|
| [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
|
|
@@ -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.49"
|
|
6
6
|
|
|
7
7
|
# Empirical Mode Decomposition
|
|
8
8
|
from ._emd import EMD
|
|
@@ -82,6 +82,9 @@ from ._acmd import ACMD
|
|
|
82
82
|
# Bandwidth-Aware Adaptive Chirp Mode Decomposition
|
|
83
83
|
from ._acmd import BA_ACMD
|
|
84
84
|
|
|
85
|
+
# Data-driven Adaptive Chirp Mode Decomposition
|
|
86
|
+
from ._acmd import DD_ACMD
|
|
87
|
+
|
|
85
88
|
# Multivariate Variational Mode Decomposition
|
|
86
89
|
from ._vmd import MVMD
|
|
87
90
|
|
|
@@ -272,6 +275,7 @@ __all__ = [
|
|
|
272
275
|
"VMD",
|
|
273
276
|
"ACMD",
|
|
274
277
|
"BA_ACMD",
|
|
278
|
+
"DD_ACMD",
|
|
275
279
|
"MVMD",
|
|
276
280
|
"VME",
|
|
277
281
|
"OVMD",
|
|
@@ -5,14 +5,17 @@ Adaptive Chirp Mode Decomposition (ACMD) and variants.
|
|
|
5
5
|
Includes:
|
|
6
6
|
- ACMD — Adaptive Chirp Mode Decomposition
|
|
7
7
|
- BA_ACMD — Bandwidth-aware Adaptive Chirp Mode Decomposition
|
|
8
|
-
- DD_ACMD — Data-driven Adaptive Chirp Mode Decomposition
|
|
8
|
+
- DD_ACMD — Data-driven Adaptive Chirp Mode Decomposition
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from .acmd import ACMD
|
|
12
12
|
from .ba_acmd import BA_ACMD, BAACMD
|
|
13
|
+
from .dd_acmd import DD_ACMD, DDACMD
|
|
13
14
|
|
|
14
15
|
__all__ = [
|
|
15
16
|
"ACMD",
|
|
16
17
|
"BA_ACMD",
|
|
17
18
|
"BAACMD",
|
|
19
|
+
"DD_ACMD",
|
|
20
|
+
"DDACMD",
|
|
18
21
|
]
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Data-driven Adaptive Chirp Mode Decomposition (DD-ACMD).
|
|
4
|
+
|
|
5
|
+
Wang H, Chen S, Zhai W. Data-driven adaptive chirp mode decomposition with
|
|
6
|
+
application to machine fault diagnosis under non-stationary conditions.
|
|
7
|
+
Mechanical Systems and Signal Processing, 2023.
|
|
8
|
+
|
|
9
|
+
MATLAB reference (File Exchange 121373):
|
|
10
|
+
https://www.mathworks.com/matlabcentral/fileexchange/121373
|
|
11
|
+
|
|
12
|
+
Relationship to ``pysdkit._acmd.acmd.ACMD``
|
|
13
|
+
------------------------------------------
|
|
14
|
+
DD-ACMD **reuses classical ACMD as the inner mode extractor**. What changes
|
|
15
|
+
is the *outer* recursion:
|
|
16
|
+
|
|
17
|
+
* **ACMD** needs a user-provided (or Fourier-peak / ridge) initial IF and a
|
|
18
|
+
fixed mode count ``K``.
|
|
19
|
+
* **DD-ACMD** (1) extracts a zero-IF trend first, (2) builds the next IF seed
|
|
20
|
+
by *derivative-normalization* (IF-DN) + iterative time-varying low-pass
|
|
21
|
+
(DDIFI), (3) calls ACMD with that seed, (4) filters the residual with TVLP,
|
|
22
|
+
and (5) stops when residual energy falls below a fraction of the original
|
|
23
|
+
signal — no STFT ridge or spectrum peak is required.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Optional, Tuple, Union
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
from scipy.integrate import cumulative_trapezoid
|
|
32
|
+
from scipy.signal import firwin, hilbert
|
|
33
|
+
|
|
34
|
+
from pysdkit._acmd.acmd import ACMD, curve_smooth, differ
|
|
35
|
+
from pysdkit._vmd.base import Base
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
# Low-level helpers (MATLAB: findev / arccos / low_filter / IF_DN / DDIFI / TVLP)
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def find_extrema(sig: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
44
|
+
"""
|
|
45
|
+
Local maxima, their indices, and a piecewise-constant upper envelope
|
|
46
|
+
(MATLAB ``findev``).
|
|
47
|
+
|
|
48
|
+
:return: ``(max_values, max_indices, upper_piecewise)``
|
|
49
|
+
"""
|
|
50
|
+
sig = np.asarray(sig, dtype=float).ravel()
|
|
51
|
+
L = sig.size
|
|
52
|
+
if L < 3:
|
|
53
|
+
idx = np.array([0], dtype=int) if L else np.array([], dtype=int)
|
|
54
|
+
vals = sig[idx] if L else np.array([], dtype=float)
|
|
55
|
+
up = np.full(L, float(sig[0]) if L else 0.0)
|
|
56
|
+
return vals, idx, up
|
|
57
|
+
|
|
58
|
+
# MATLAB: MaxVec = find(diff(diff(Sig) > 0) < 0) + 1
|
|
59
|
+
interior = np.where(np.diff((np.diff(sig) > 0).astype(int)) < 0)[0] + 1
|
|
60
|
+
max_vec = interior.astype(int)
|
|
61
|
+
|
|
62
|
+
if sig[0] > sig[1]:
|
|
63
|
+
max_vec = np.concatenate(([0], max_vec))
|
|
64
|
+
if sig[-1] > sig[-2]:
|
|
65
|
+
max_vec = np.concatenate((max_vec, [L - 1]))
|
|
66
|
+
|
|
67
|
+
# unique sorted (endpoints may duplicate rare plateaus)
|
|
68
|
+
max_vec = np.unique(max_vec)
|
|
69
|
+
maxima = sig[max_vec]
|
|
70
|
+
|
|
71
|
+
up = np.empty(L, dtype=float)
|
|
72
|
+
if max_vec.size == 1:
|
|
73
|
+
up[:] = maxima[0]
|
|
74
|
+
else:
|
|
75
|
+
for i in range(max_vec.size - 1):
|
|
76
|
+
up[max_vec[i] : max_vec[i + 1] + 1] = maxima[i]
|
|
77
|
+
up[: max_vec[0] + 1] = maxima[0]
|
|
78
|
+
up[max_vec[-1] :] = maxima[-1]
|
|
79
|
+
return maxima, max_vec, up
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def phase_arccos(g: np.ndarray) -> np.ndarray:
|
|
83
|
+
"""
|
|
84
|
+
Cumulative phase via piecewise ``acos`` with slope-based folding
|
|
85
|
+
(MATLAB custom ``arccos`` — *not* ``np.arccos`` alone).
|
|
86
|
+
|
|
87
|
+
Returns phase in units of cycles (already scaled by ``0.5/π · acos``).
|
|
88
|
+
"""
|
|
89
|
+
g = np.asarray(g, dtype=float).ravel()
|
|
90
|
+
s = g.size
|
|
91
|
+
if s == 0:
|
|
92
|
+
return g.copy()
|
|
93
|
+
g_clip = np.clip(g, -1.0, 1.0)
|
|
94
|
+
f1 = g_clip.copy()
|
|
95
|
+
theta = (0.5 / np.pi) * np.arccos(f1)
|
|
96
|
+
temp = 0.0
|
|
97
|
+
for i in range(2, s):
|
|
98
|
+
if np.sign(g[i] - g[i - 1]) != np.sign(g[i - 1] - g[i - 2]):
|
|
99
|
+
temp = float(theta[i - 1])
|
|
100
|
+
if g[i] - g[i - 1] > 0.0:
|
|
101
|
+
f1[i] = -g_clip[i]
|
|
102
|
+
else:
|
|
103
|
+
f1[i] = g_clip[i]
|
|
104
|
+
# keep acos domain
|
|
105
|
+
f1[i] = float(np.clip(f1[i], -1.0, 1.0))
|
|
106
|
+
theta[i] = (0.5 / np.pi) * np.arccos(f1[i]) + temp
|
|
107
|
+
return theta
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def low_filter(
|
|
111
|
+
sig: np.ndarray, cut_freq: float, samp_freq: float
|
|
112
|
+
) -> np.ndarray:
|
|
113
|
+
"""
|
|
114
|
+
Linear-phase FIR low-pass with delay compensation (MATLAB ``low_filter``).
|
|
115
|
+
|
|
116
|
+
Works for real or complex inputs (FIR applied via ``np.convolve``).
|
|
117
|
+
"""
|
|
118
|
+
sig = np.asarray(sig)
|
|
119
|
+
n0 = sig.size
|
|
120
|
+
if n0 < 4:
|
|
121
|
+
return sig.copy()
|
|
122
|
+
|
|
123
|
+
n = int(np.floor(n0 * 0.8))
|
|
124
|
+
L = n if (n % 2 == 0) else n + 1
|
|
125
|
+
# MATLAB fir1(L, Wn) with Wn = cut/(fs/2); L is filter *order*
|
|
126
|
+
nyq = 0.5 * float(samp_freq)
|
|
127
|
+
wn = float(cut_freq) / nyq
|
|
128
|
+
wn = float(np.clip(wn, 1e-6, 0.999999))
|
|
129
|
+
numtaps = L + 1
|
|
130
|
+
b = firwin(numtaps, wn, pass_zero="lowpass")
|
|
131
|
+
filtered = np.convolve(b, sig, mode="full")
|
|
132
|
+
start = L // 2
|
|
133
|
+
return filtered[start : start + n0]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def if_derivative_normalization(
|
|
137
|
+
sig: np.ndarray, samp_freq: float, beta: float = 1e-11
|
|
138
|
+
) -> np.ndarray:
|
|
139
|
+
"""
|
|
140
|
+
Instantaneous-frequency estimate via derivative normalization (MATLAB ``IF_DN``).
|
|
141
|
+
|
|
142
|
+
Steps: differentiate → normalize between consecutive extrema → custom
|
|
143
|
+
``arccos`` phase → differentiate → Tikhonov smooth.
|
|
144
|
+
"""
|
|
145
|
+
sig = np.asarray(sig, dtype=float).ravel()
|
|
146
|
+
ds = differ(sig, 1.0 / float(samp_freq))
|
|
147
|
+
_, max_vec, _ = find_extrema(ds)
|
|
148
|
+
_, min_vec, _ = find_extrema(-ds)
|
|
149
|
+
mv = np.sort(np.concatenate((max_vec, min_vec)))
|
|
150
|
+
mv = np.unique(mv)
|
|
151
|
+
g = np.zeros_like(ds)
|
|
152
|
+
for i in range(mv.size - 1):
|
|
153
|
+
i0, i1 = int(mv[i]), int(mv[i + 1])
|
|
154
|
+
lav = abs(ds[i0] - ds[i1]) / 2.0
|
|
155
|
+
lm = (ds[i0] + ds[i1]) / 2.0
|
|
156
|
+
if lav < np.finfo(float).eps:
|
|
157
|
+
g[i0 : i1 + 1] = 0.0
|
|
158
|
+
else:
|
|
159
|
+
g[i0 : i1 + 1] = (ds[i0 : i1 + 1] - lm) / lav
|
|
160
|
+
g = np.clip(g, -1.0, 1.0)
|
|
161
|
+
theta = phase_arccos(g)
|
|
162
|
+
inst_f = differ(theta, 1.0 / float(samp_freq))
|
|
163
|
+
inst_f = np.real(curve_smooth(inst_f, beta))
|
|
164
|
+
return inst_f
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def time_varying_lowpass(
|
|
168
|
+
sig: np.ndarray,
|
|
169
|
+
samp_freq: float,
|
|
170
|
+
e_if: np.ndarray,
|
|
171
|
+
c_pass: float,
|
|
172
|
+
cutoff_scale: float = 1.1,
|
|
173
|
+
) -> np.ndarray:
|
|
174
|
+
"""
|
|
175
|
+
Time-varying low-pass filter (MATLAB ``TVLP``).
|
|
176
|
+
|
|
177
|
+
Demodulate by ``exp(-j ∫ 2π (IF − Cpass) dt)``, FIR-lowpass at
|
|
178
|
+
``cutoff_scale * Cpass``, then remodulate. ``cutoff_scale=1.1`` matches
|
|
179
|
+
the fully open-source MATLAB package (``low_filter`` path).
|
|
180
|
+
"""
|
|
181
|
+
sig = np.asarray(sig, dtype=float).ravel()
|
|
182
|
+
e_if = np.asarray(e_if, dtype=float).ravel()
|
|
183
|
+
n = sig.size
|
|
184
|
+
fs = float(samp_freq)
|
|
185
|
+
t = np.arange(n, dtype=float) / fs
|
|
186
|
+
phase = 2.0 * np.pi * cumulative_trapezoid(e_if - float(c_pass), t, initial=0.0)
|
|
187
|
+
analytic = hilbert(sig)
|
|
188
|
+
shifted = analytic * np.exp(-1j * phase)
|
|
189
|
+
cut = max(float(cutoff_scale) * float(c_pass), 1e-6)
|
|
190
|
+
# keep cutoff below Nyquist
|
|
191
|
+
cut = min(cut, 0.49 * fs)
|
|
192
|
+
filtered = low_filter(shifted, cut, fs)
|
|
193
|
+
restored = filtered * np.exp(1j * phase)
|
|
194
|
+
return np.real(restored)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def data_driven_if_init(
|
|
198
|
+
sig: np.ndarray,
|
|
199
|
+
samp_freq: float,
|
|
200
|
+
beta: float = 1e-11,
|
|
201
|
+
max_iter: int = 10,
|
|
202
|
+
tol: float = 0.01,
|
|
203
|
+
) -> np.ndarray:
|
|
204
|
+
"""
|
|
205
|
+
Data-driven IF initialization (MATLAB ``DDIFI``).
|
|
206
|
+
|
|
207
|
+
Iterate IF-DN → TVLP until the IF-norm change falls below ``tol``.
|
|
208
|
+
"""
|
|
209
|
+
residual = np.asarray(sig, dtype=float).ravel().copy()
|
|
210
|
+
n = residual.size
|
|
211
|
+
iif = np.full(n, float(samp_freq), dtype=float)
|
|
212
|
+
last = iif.copy()
|
|
213
|
+
for _ in range(int(max_iter)):
|
|
214
|
+
inst_f = if_derivative_normalization(residual, samp_freq, beta=beta)
|
|
215
|
+
residual = time_varying_lowpass(
|
|
216
|
+
residual, samp_freq, inst_f, float(np.max(inst_f))
|
|
217
|
+
)
|
|
218
|
+
denom = norm_safe(iif)
|
|
219
|
+
delta = abs(norm_safe(inst_f) - denom) / denom
|
|
220
|
+
last = inst_f
|
|
221
|
+
if delta < tol:
|
|
222
|
+
break
|
|
223
|
+
iif = inst_f
|
|
224
|
+
return last
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def norm_safe(x: np.ndarray) -> float:
|
|
228
|
+
nrm = float(np.linalg.norm(np.asarray(x, dtype=float).ravel()))
|
|
229
|
+
return nrm if nrm > 0.0 else np.finfo(float).eps
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def add_noise(
|
|
233
|
+
n: int,
|
|
234
|
+
mean: float = 0.0,
|
|
235
|
+
std: float = 1.0,
|
|
236
|
+
rng: Optional[np.random.Generator] = None,
|
|
237
|
+
) -> np.ndarray:
|
|
238
|
+
"""Gaussian noise matching MATLAB ``addnoise``."""
|
|
239
|
+
rng = np.random.default_rng() if rng is None else rng
|
|
240
|
+
y = rng.standard_normal(int(n))
|
|
241
|
+
y = y / (np.std(y) + np.finfo(float).eps)
|
|
242
|
+
y = y - np.mean(y)
|
|
243
|
+
return mean + std * y
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def generate_stationary_demo(
|
|
247
|
+
fs: float = 300.0,
|
|
248
|
+
duration: float = 1.0,
|
|
249
|
+
noise_std: float = 0.3,
|
|
250
|
+
rng: Optional[np.random.Generator] = None,
|
|
251
|
+
) -> dict:
|
|
252
|
+
"""MATLAB Test (stationary signal) mixture."""
|
|
253
|
+
t = np.arange(0.0, duration, 1.0 / fs)
|
|
254
|
+
sig1 = 4.0 * t**2
|
|
255
|
+
sig2 = 0.5 * np.cos(40.0 * np.pi * t)
|
|
256
|
+
sig3 = 0.5 * np.cos(50.0 * np.pi * t)
|
|
257
|
+
sig4 = 0.5 * np.cos(60.0 * np.pi * t)
|
|
258
|
+
clean = sig1 + sig2 + sig3 + sig4
|
|
259
|
+
noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng)
|
|
260
|
+
return {
|
|
261
|
+
"t": t,
|
|
262
|
+
"fs": fs,
|
|
263
|
+
"clean": clean,
|
|
264
|
+
"signal": noisy,
|
|
265
|
+
"modes": np.vstack([sig1, sig2, sig3, sig4]),
|
|
266
|
+
"ifs": np.vstack(
|
|
267
|
+
[
|
|
268
|
+
np.zeros_like(t),
|
|
269
|
+
np.full_like(t, 20.0),
|
|
270
|
+
np.full_like(t, 25.0),
|
|
271
|
+
np.full_like(t, 30.0),
|
|
272
|
+
]
|
|
273
|
+
),
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def generate_nonstationary_demo(
|
|
278
|
+
fs: float = 1500.0,
|
|
279
|
+
duration: float = 3.0,
|
|
280
|
+
noise_std: float = 0.5,
|
|
281
|
+
rng: Optional[np.random.Generator] = None,
|
|
282
|
+
) -> dict:
|
|
283
|
+
"""MATLAB Test (noisy non-stationary) mixture."""
|
|
284
|
+
t = np.arange(0.0, duration, 1.0 / fs)
|
|
285
|
+
a1 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t)
|
|
286
|
+
sig1 = a1 * np.cos(2.0 * np.pi * (8 * t**3 + 16 * t**2 + 80 * t) + np.sin(10 * np.pi * t))
|
|
287
|
+
if1 = 24 * t**2 + 32 * t + 80 + 5 * np.cos(10 * np.pi * t)
|
|
288
|
+
a2 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t + np.pi / 4)
|
|
289
|
+
sig2 = a2 * np.cos(2.0 * np.pi * (6 * t**3 + 12 * t**2 + 60 * t) + np.sin(10 * np.pi * t))
|
|
290
|
+
if2 = 18 * t**2 + 24 * t + 60 + 5 * np.cos(10 * np.pi * t)
|
|
291
|
+
a3 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t + np.pi / 2)
|
|
292
|
+
sig3 = a3 * np.cos(2.0 * np.pi * (4 * t**3 + 8 * t**2 + 40 * t) + np.sin(10 * np.pi * t))
|
|
293
|
+
if3 = 12 * t**2 + 16 * t + 40 + 5 * np.cos(10 * np.pi * t)
|
|
294
|
+
clean = sig1 + sig2 + sig3
|
|
295
|
+
noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng)
|
|
296
|
+
return {
|
|
297
|
+
"t": t,
|
|
298
|
+
"fs": fs,
|
|
299
|
+
"clean": clean,
|
|
300
|
+
"signal": noisy,
|
|
301
|
+
"modes": np.vstack([sig1, sig2, sig3]),
|
|
302
|
+
"ifs": np.vstack([if1, if2, if3]),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def generate_close_modes_demo(
|
|
307
|
+
fs: float = 800.0,
|
|
308
|
+
duration: float = 2.0,
|
|
309
|
+
noise_std: float = 0.0,
|
|
310
|
+
rng: Optional[np.random.Generator] = None,
|
|
311
|
+
) -> dict:
|
|
312
|
+
"""MATLAB Test (close chirp modes) mixture."""
|
|
313
|
+
t = np.arange(0.0, duration, 1.0 / fs)
|
|
314
|
+
sig1 = np.exp(-0.1 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 100 * t))
|
|
315
|
+
if1 = -180 * t**2 + 360 * t + 100
|
|
316
|
+
sig2 = np.exp(-0.2 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 90 * t))
|
|
317
|
+
if2 = -180 * t**2 + 360 * t + 90
|
|
318
|
+
sig3 = np.exp(-0.3 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 80 * t))
|
|
319
|
+
if3 = -180 * t**2 + 360 * t + 80
|
|
320
|
+
clean = sig1 + sig2 + sig3
|
|
321
|
+
noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng) if noise_std > 0 else clean.copy()
|
|
322
|
+
return {
|
|
323
|
+
"t": t,
|
|
324
|
+
"fs": fs,
|
|
325
|
+
"clean": clean,
|
|
326
|
+
"signal": noisy,
|
|
327
|
+
"modes": np.vstack([sig1, sig2, sig3]),
|
|
328
|
+
"ifs": np.vstack([if1, if2, if3]),
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
# ---------------------------------------------------------------------------
|
|
333
|
+
# DD-ACMD class
|
|
334
|
+
# ---------------------------------------------------------------------------
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class DD_ACMD(Base):
|
|
338
|
+
"""
|
|
339
|
+
Data-driven Adaptive Chirp Mode Decomposition.
|
|
340
|
+
|
|
341
|
+
Outer loop around classical :class:`~pysdkit._acmd.acmd.ACMD`:
|
|
342
|
+
|
|
343
|
+
1. Extract a **trend** with zero initial IF.
|
|
344
|
+
2. Estimate the next IF by **DDIFI** (IF-DN + TVLP).
|
|
345
|
+
3. Run ACMD; subtract the mode; stop if
|
|
346
|
+
``‖residual‖² / ‖signal‖² < energy_tol``.
|
|
347
|
+
4. Otherwise apply TVLP to the residual and repeat.
|
|
348
|
+
|
|
349
|
+
MATLAB: ``DDACMD.m`` (File Exchange 121373).
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
def __init__(
|
|
353
|
+
self,
|
|
354
|
+
fs: float,
|
|
355
|
+
k_max: int = 20,
|
|
356
|
+
alpha0: float = 1e-7,
|
|
357
|
+
beta: float = 1e-10,
|
|
358
|
+
tol: float = 1e-30,
|
|
359
|
+
energy_tol: float = 0.01,
|
|
360
|
+
ddifi_beta: float = 1e-11,
|
|
361
|
+
ddifi_max_iter: int = 10,
|
|
362
|
+
ddifi_tol: float = 0.01,
|
|
363
|
+
max_iter: int = 300,
|
|
364
|
+
tvlp_cutoff_scale: float = 1.1,
|
|
365
|
+
) -> None:
|
|
366
|
+
"""
|
|
367
|
+
:param fs: sampling frequency (Hz)
|
|
368
|
+
:param k_max: maximum number of modes (incl. trend)
|
|
369
|
+
:param alpha0: ACMD bandwidth penalty (MATLAB DDACMD default ``1e-7``)
|
|
370
|
+
:param beta: ACMD IF-increment smoothness (MATLAB ``1e-10``)
|
|
371
|
+
:param tol: ACMD convergence tolerance (MATLAB ``1e-30`` → ~max_iter)
|
|
372
|
+
:param energy_tol: residual-energy stop ratio ``ε``
|
|
373
|
+
:param ddifi_beta: IF-DN smoothing penalty
|
|
374
|
+
:param ddifi_max_iter: max DDIFI iterations
|
|
375
|
+
:param ddifi_tol: DDIFI relative IF-norm stop
|
|
376
|
+
:param max_iter: max ACMD iterations per mode
|
|
377
|
+
:param tvlp_cutoff_scale: FIR cutoff = scale × max(IF)
|
|
378
|
+
"""
|
|
379
|
+
super().__init__()
|
|
380
|
+
if float(fs) <= 0:
|
|
381
|
+
raise ValueError("fs must be positive")
|
|
382
|
+
self.fs = float(fs)
|
|
383
|
+
self.k_max = int(k_max)
|
|
384
|
+
self.alpha0 = float(alpha0)
|
|
385
|
+
self.beta = float(beta)
|
|
386
|
+
self.tol = float(tol)
|
|
387
|
+
self.energy_tol = float(energy_tol)
|
|
388
|
+
self.ddifi_beta = float(ddifi_beta)
|
|
389
|
+
self.ddifi_max_iter = int(ddifi_max_iter)
|
|
390
|
+
self.ddifi_tol = float(ddifi_tol)
|
|
391
|
+
self.max_iter = int(max_iter)
|
|
392
|
+
self.tvlp_cutoff_scale = float(tvlp_cutoff_scale)
|
|
393
|
+
|
|
394
|
+
self.imfs_: Optional[np.ndarray] = None
|
|
395
|
+
self.ifs_: Optional[np.ndarray] = None
|
|
396
|
+
self.ias_: Optional[np.ndarray] = None
|
|
397
|
+
self.ini_ifs_: Optional[np.ndarray] = None
|
|
398
|
+
|
|
399
|
+
def __call__(
|
|
400
|
+
self, signal: np.ndarray, return_all: bool = False
|
|
401
|
+
) -> Union[np.ndarray, Tuple[np.ndarray, ...]]:
|
|
402
|
+
return self.fit_transform(signal, return_all=return_all)
|
|
403
|
+
|
|
404
|
+
def __str__(self) -> str:
|
|
405
|
+
return "Data-driven Adaptive Chirp Mode Decomposition (DD-ACMD)"
|
|
406
|
+
|
|
407
|
+
def _acmd_extractor(self) -> ACMD:
|
|
408
|
+
return ACMD(
|
|
409
|
+
K=1,
|
|
410
|
+
fs=self.fs,
|
|
411
|
+
alpha0=self.alpha0,
|
|
412
|
+
beta=self.beta,
|
|
413
|
+
tol=self.tol,
|
|
414
|
+
max_iter=self.max_iter,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
def extract_trend(
|
|
418
|
+
self, signal: np.ndarray
|
|
419
|
+
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
420
|
+
"""Mode 1: ACMD with zero initial IF (MATLAB trend step)."""
|
|
421
|
+
signal = np.asarray(signal, dtype=float).ravel()
|
|
422
|
+
init_if = np.zeros(signal.size, dtype=float)
|
|
423
|
+
sest, if_est, ia_est = self._acmd_extractor().extract_mode(signal, init_if)
|
|
424
|
+
return sest, if_est, ia_est, init_if
|
|
425
|
+
|
|
426
|
+
def estimate_init_if(self, signal: np.ndarray) -> np.ndarray:
|
|
427
|
+
"""Public wrapper for DDIFI."""
|
|
428
|
+
return data_driven_if_init(
|
|
429
|
+
signal,
|
|
430
|
+
self.fs,
|
|
431
|
+
beta=self.ddifi_beta,
|
|
432
|
+
max_iter=self.ddifi_max_iter,
|
|
433
|
+
tol=self.ddifi_tol,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
def fit_transform(
|
|
437
|
+
self,
|
|
438
|
+
signal: np.ndarray,
|
|
439
|
+
return_all: bool = False,
|
|
440
|
+
) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:
|
|
441
|
+
"""
|
|
442
|
+
Run DD-ACMD.
|
|
443
|
+
|
|
444
|
+
:param signal: 1-D real record
|
|
445
|
+
:param return_all: if True, also return ``(ini_IF, eIF, eIA)``
|
|
446
|
+
:return: ``IMF`` of shape ``(K, N)``, or
|
|
447
|
+
``(IMF, ini_IF, eIF, eIA)`` when ``return_all``
|
|
448
|
+
"""
|
|
449
|
+
sig0 = np.asarray(signal, dtype=float).ravel()
|
|
450
|
+
if sig0.size < 8:
|
|
451
|
+
raise ValueError("signal length must be >= 8")
|
|
452
|
+
|
|
453
|
+
n = sig0.size
|
|
454
|
+
residual = sig0.copy()
|
|
455
|
+
energy0 = float(np.sum(sig0**2)) + np.finfo(float).eps
|
|
456
|
+
|
|
457
|
+
ini_ifs = np.zeros((self.k_max, n), dtype=float)
|
|
458
|
+
e_ifs = np.zeros((self.k_max, n), dtype=float)
|
|
459
|
+
e_ias = np.zeros((self.k_max, n), dtype=float)
|
|
460
|
+
imfs = np.zeros((self.k_max, n), dtype=float)
|
|
461
|
+
|
|
462
|
+
acmd = self._acmd_extractor()
|
|
463
|
+
k_out = 0
|
|
464
|
+
|
|
465
|
+
for i in range(self.k_max):
|
|
466
|
+
if i == 0:
|
|
467
|
+
init_if = np.zeros(n, dtype=float)
|
|
468
|
+
else:
|
|
469
|
+
init_if = data_driven_if_init(
|
|
470
|
+
residual,
|
|
471
|
+
self.fs,
|
|
472
|
+
beta=self.ddifi_beta,
|
|
473
|
+
max_iter=self.ddifi_max_iter,
|
|
474
|
+
tol=self.ddifi_tol,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
sest, if_est, ia_est = acmd.extract_mode(residual, init_if)
|
|
478
|
+
ini_ifs[i] = init_if
|
|
479
|
+
e_ifs[i] = if_est
|
|
480
|
+
e_ias[i] = ia_est
|
|
481
|
+
imfs[i] = sest
|
|
482
|
+
residual = residual - sest
|
|
483
|
+
k_out = i + 1
|
|
484
|
+
|
|
485
|
+
if i >= 1:
|
|
486
|
+
epsilon = float(np.sum(residual**2)) / energy0
|
|
487
|
+
if epsilon < self.energy_tol:
|
|
488
|
+
break
|
|
489
|
+
c_pass = float(np.max(if_est))
|
|
490
|
+
residual = time_varying_lowpass(
|
|
491
|
+
residual,
|
|
492
|
+
self.fs,
|
|
493
|
+
if_est,
|
|
494
|
+
c_pass,
|
|
495
|
+
cutoff_scale=self.tvlp_cutoff_scale,
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
self.ini_ifs_ = ini_ifs[:k_out]
|
|
499
|
+
self.ifs_ = e_ifs[:k_out]
|
|
500
|
+
self.ias_ = e_ias[:k_out]
|
|
501
|
+
self.imfs_ = imfs[:k_out]
|
|
502
|
+
|
|
503
|
+
if return_all:
|
|
504
|
+
return self.imfs_, self.ini_ifs_, self.ifs_, self.ias_
|
|
505
|
+
return self.imfs_
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
# Alias matching MATLAB naming
|
|
509
|
+
DDACMD = DD_ACMD
|