Modal-Decomposition 0.1.2__tar.gz → 0.1.4__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.
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/PKG-INFO +29 -28
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/README.md +28 -27
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/pyproject.toml +1 -1
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEFD.py +5 -26
- modal_decomposition-0.1.4/src/Modal_Decomposition/CEEMD.py +103 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEMDAN.py +23 -26
- modal_decomposition-0.1.4/src/Modal_Decomposition/EEMD.py +58 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EFD.py +11 -34
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EMD.py +7 -28
- modal_decomposition-0.1.4/src/Modal_Decomposition/EWT.py +62 -0
- modal_decomposition-0.1.4/src/Modal_Decomposition/Error/RealizationError.py +2 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/FMD.py +17 -19
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/ICEEMDAN.py +40 -65
- modal_decomposition-0.1.4/src/Modal_Decomposition/LMD.py +236 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/MEMD.py +27 -26
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/RPSEMD.py +5 -10
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SSA.py +16 -17
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SVMD.py +28 -15
- modal_decomposition-0.1.4/src/Modal_Decomposition/Utils/Check.py +39 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/Monotonicity.py +16 -16
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/__init__.py +1 -1
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/VMD.py +16 -8
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/__init__.py +12 -19
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/PKG-INFO +29 -28
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/SOURCES.txt +2 -5
- modal_decomposition-0.1.4/tests/test.py +216 -0
- modal_decomposition-0.1.2/src/Modal_Decomposition/CEEMD.py +0 -135
- modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/__init__.py +0 -18
- modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/color_define.py +0 -30
- modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/colorful_print.py +0 -66
- modal_decomposition-0.1.2/src/Modal_Decomposition/EEMD.py +0 -130
- modal_decomposition-0.1.2/src/Modal_Decomposition/EWT.py +0 -76
- modal_decomposition-0.1.2/src/Modal_Decomposition/LMD.py +0 -178
- modal_decomposition-0.1.2/src/Modal_Decomposition/Utils/OneDimArray.py +0 -27
- modal_decomposition-0.1.2/src/Modal_Decomposition/help_function.py +0 -64
- modal_decomposition-0.1.2/tests/test.py +0 -74
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/LICENSE +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/setup.cfg +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/CycleError.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/EnvironmentMemory.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/LazyImport.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/NumpyNdarray_MemoryCalculator.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Modal-Decomposition
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: a package for modal decomposition
|
|
5
5
|
Author-email: Mao_HaoChuan <2215269365@qq.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -44,6 +44,29 @@ Hope my lib can help you.
|
|
|
44
44
|
|
|
45
45
|
All entrance of functions or class are stored in `Modal_Decomposition/__init__.py`
|
|
46
46
|
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
There two classification in `__init__.py`: `Class` and `Function`.
|
|
50
|
+
|
|
51
|
+
- ### Function:
|
|
52
|
+
|
|
53
|
+
Use `Function.method` to choose the following mode decomposition method.
|
|
54
|
+
|
|
55
|
+
- ### Class:
|
|
56
|
+
|
|
57
|
+
Use `Class.class` will give you a class. `Class.class.decompose` will decompose the signal.
|
|
58
|
+
|
|
59
|
+
### Quick Start
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from Modal_Decomposition import Function as f
|
|
63
|
+
import numpy as np
|
|
64
|
+
|
|
65
|
+
S = np.random.random(10)
|
|
66
|
+
|
|
67
|
+
IMFs, Res, Info = f.EMD(S)
|
|
68
|
+
```
|
|
69
|
+
|
|
47
70
|
## Modal Decomposition
|
|
48
71
|
|
|
49
72
|
| method | description | use | resource(doi and link) |
|
|
@@ -55,20 +78,20 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
55
78
|
| EFD | Empirical Fourier Decomposition | `Function.EFD(signal)` | [10.1016/j.ymssp.2021.108155](https://www.sciencedirect.com/science/article/abs/pii/S0888327021005355?via%3Dihub) |
|
|
56
79
|
| EMD | Empirical Mode Decomposition | `Function.EMD(signal)` | [10.1098/rspa.1998.0193](https://www.semanticscholar.org/paper/The-empirical-mode-decomposition-and-the-Hilbert-Huang-Shen/3842d81b0375dae8ae92734aa2a5d4aeed7a91d1) |
|
|
57
80
|
| EWT | Empirical Wavelet Transform | `Function.EWT(signal)` | [10.48550/arXiv.2304.06274](https://arxiv.org/abs/2304.06274) |
|
|
58
|
-
| FMD | Filtered Mode Decomposition | `Function.
|
|
81
|
+
| FMD | Filtered Mode Decomposition | `Function.FMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
|
|
59
82
|
| ICEEMDAN | Improved Complete Ensemble Empirical Mode Decomposition with Adaptive Noise | `Function.ICEEMDAN(signal)` | [10.1007/s10470-021-01901-3](https://link.springer.com/article/10.1007/s10470-021-01901-3#citeas) |
|
|
60
83
|
| LMD | Local Mean Decomposition | `Function.LMD(signal)` | [10.1098/rsif.2005.0058](https://royalsocietypublishing.org/doi/10.1098/rsif.2005.0058) |
|
|
61
84
|
| MEMD | Multivariate Empirical Mode Decomposition | `Function.MEMD(signal)` | [10.48550/arXiv.2206.00926](https://arxiv.org/abs/2206.00926) |
|
|
62
85
|
| RPSEMD | Random Phase Sinusoidal Assisted Empirical Mode Decomposition | `Function.RPSEMD(signal)` | [10.1109/LSP.2016.2537376](https://ieeexplore.ieee.org/document/7423702) |
|
|
63
86
|
| SSA | Singular Spectrum Analysis | `Function.SSA(signal)` | [10.1016/j.mex.2020.101015](https://www.sciencedirect.com/science/article/pii/S2215016120302351) |
|
|
64
|
-
| SVMD |
|
|
65
|
-
| VMD | Variational Mode Decomposition | `Function.VMD(signal)` |
|
|
87
|
+
| SVMD | Successive Variational Mode Decomposition | `Function.SVMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
|
|
88
|
+
| VMD | Variational Mode Decomposition | `Function.VMD(signal)` | [10.1109/TSP.2013.2288675](https://ieeexplore.ieee.org/document/6655981) |
|
|
66
89
|
|
|
67
90
|
## Install
|
|
68
91
|
|
|
69
92
|
You can install by:
|
|
70
93
|
```shell
|
|
71
|
-
git clone https://github.com/a-raining-day/
|
|
94
|
+
git clone https://github.com/a-raining-day/Modal-Decomposition.git
|
|
72
95
|
cd Motal-Decomposition
|
|
73
96
|
pip install -r requirements.txt
|
|
74
97
|
```
|
|
@@ -79,41 +102,19 @@ pip install -r requirements.txt
|
|
|
79
102
|
pip install Modal-Decomposition
|
|
80
103
|
```
|
|
81
104
|
|
|
82
|
-
*Well, some libs should be installed by yourself, don't use `pip install -r requirements.txt`, because `Triton` need installed by GitHub.*
|
|
83
|
-
|
|
84
|
-
*`Triton` please visite this url: https://github.com/woct0rdho/triton-windows/releases*
|
|
85
|
-
|
|
86
105
|
## Dependence
|
|
87
106
|
|
|
88
107
|
This lib's dependence are:
|
|
89
108
|
|
|
90
109
|
***Python: 3.10***
|
|
91
110
|
|
|
92
|
-
- [antropy](https://github.com/raphaelvallat/antropy)
|
|
93
|
-
- [colorama](https://github.com/tartley/colorama)
|
|
94
|
-
- [einops](https://github.com/arogozhnikov/einops)
|
|
95
111
|
- [EMD-signal](https://github.com/laszukdawid/PyEMD)
|
|
96
112
|
- [ewtpy](https://github.com/vrcarva/ewtpy)
|
|
97
|
-
- [numba](https://github.com/numba/numba)
|
|
98
|
-
- [numpy](https://github.com/numpy/numpy)
|
|
99
|
-
- [scipy](https://github.com/scipy/scipy)
|
|
100
113
|
- [vmdpy](https://github.com/vrcarva/vmdpy)
|
|
101
|
-
- [psutil](https://github.com/giampaolo/psutil)
|
|
102
114
|
|
|
103
115
|
*Other dependence please read "requirements.txt"*
|
|
104
116
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
All codes from :
|
|
108
|
-
|
|
109
|
-
- Github:
|
|
110
|
-
- EMD-signal -> EMD, CEEFD, CEEMDAN, EEMD
|
|
111
|
-
- ewtpy -> EWT
|
|
112
|
-
- vmdpy -> VMD
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- Myself:
|
|
116
|
-
- CEEMD, EFD, FMD, ICEEMDAN, LMD, MEMD, RPSEMD, SSA, SVMD
|
|
117
|
+
*Please pip `EMD-signal`, not `PyEMD`*
|
|
117
118
|
|
|
118
119
|
## Url
|
|
119
120
|
|
|
@@ -12,6 +12,29 @@ Hope my lib can help you.
|
|
|
12
12
|
|
|
13
13
|
All entrance of functions or class are stored in `Modal_Decomposition/__init__.py`
|
|
14
14
|
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
There two classification in `__init__.py`: `Class` and `Function`.
|
|
18
|
+
|
|
19
|
+
- ### Function:
|
|
20
|
+
|
|
21
|
+
Use `Function.method` to choose the following mode decomposition method.
|
|
22
|
+
|
|
23
|
+
- ### Class:
|
|
24
|
+
|
|
25
|
+
Use `Class.class` will give you a class. `Class.class.decompose` will decompose the signal.
|
|
26
|
+
|
|
27
|
+
### Quick Start
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from Modal_Decomposition import Function as f
|
|
31
|
+
import numpy as np
|
|
32
|
+
|
|
33
|
+
S = np.random.random(10)
|
|
34
|
+
|
|
35
|
+
IMFs, Res, Info = f.EMD(S)
|
|
36
|
+
```
|
|
37
|
+
|
|
15
38
|
## Modal Decomposition
|
|
16
39
|
|
|
17
40
|
| method | description | use | resource(doi and link) |
|
|
@@ -23,20 +46,20 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
23
46
|
| EFD | Empirical Fourier Decomposition | `Function.EFD(signal)` | [10.1016/j.ymssp.2021.108155](https://www.sciencedirect.com/science/article/abs/pii/S0888327021005355?via%3Dihub) |
|
|
24
47
|
| EMD | Empirical Mode Decomposition | `Function.EMD(signal)` | [10.1098/rspa.1998.0193](https://www.semanticscholar.org/paper/The-empirical-mode-decomposition-and-the-Hilbert-Huang-Shen/3842d81b0375dae8ae92734aa2a5d4aeed7a91d1) |
|
|
25
48
|
| EWT | Empirical Wavelet Transform | `Function.EWT(signal)` | [10.48550/arXiv.2304.06274](https://arxiv.org/abs/2304.06274) |
|
|
26
|
-
| FMD | Filtered Mode Decomposition | `Function.
|
|
49
|
+
| FMD | Filtered Mode Decomposition | `Function.FMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
|
|
27
50
|
| ICEEMDAN | Improved Complete Ensemble Empirical Mode Decomposition with Adaptive Noise | `Function.ICEEMDAN(signal)` | [10.1007/s10470-021-01901-3](https://link.springer.com/article/10.1007/s10470-021-01901-3#citeas) |
|
|
28
51
|
| LMD | Local Mean Decomposition | `Function.LMD(signal)` | [10.1098/rsif.2005.0058](https://royalsocietypublishing.org/doi/10.1098/rsif.2005.0058) |
|
|
29
52
|
| MEMD | Multivariate Empirical Mode Decomposition | `Function.MEMD(signal)` | [10.48550/arXiv.2206.00926](https://arxiv.org/abs/2206.00926) |
|
|
30
53
|
| RPSEMD | Random Phase Sinusoidal Assisted Empirical Mode Decomposition | `Function.RPSEMD(signal)` | [10.1109/LSP.2016.2537376](https://ieeexplore.ieee.org/document/7423702) |
|
|
31
54
|
| SSA | Singular Spectrum Analysis | `Function.SSA(signal)` | [10.1016/j.mex.2020.101015](https://www.sciencedirect.com/science/article/pii/S2215016120302351) |
|
|
32
|
-
| SVMD |
|
|
33
|
-
| VMD | Variational Mode Decomposition | `Function.VMD(signal)` |
|
|
55
|
+
| SVMD | Successive Variational Mode Decomposition | `Function.SVMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
|
|
56
|
+
| VMD | Variational Mode Decomposition | `Function.VMD(signal)` | [10.1109/TSP.2013.2288675](https://ieeexplore.ieee.org/document/6655981) |
|
|
34
57
|
|
|
35
58
|
## Install
|
|
36
59
|
|
|
37
60
|
You can install by:
|
|
38
61
|
```shell
|
|
39
|
-
git clone https://github.com/a-raining-day/
|
|
62
|
+
git clone https://github.com/a-raining-day/Modal-Decomposition.git
|
|
40
63
|
cd Motal-Decomposition
|
|
41
64
|
pip install -r requirements.txt
|
|
42
65
|
```
|
|
@@ -47,41 +70,19 @@ pip install -r requirements.txt
|
|
|
47
70
|
pip install Modal-Decomposition
|
|
48
71
|
```
|
|
49
72
|
|
|
50
|
-
*Well, some libs should be installed by yourself, don't use `pip install -r requirements.txt`, because `Triton` need installed by GitHub.*
|
|
51
|
-
|
|
52
|
-
*`Triton` please visite this url: https://github.com/woct0rdho/triton-windows/releases*
|
|
53
|
-
|
|
54
73
|
## Dependence
|
|
55
74
|
|
|
56
75
|
This lib's dependence are:
|
|
57
76
|
|
|
58
77
|
***Python: 3.10***
|
|
59
78
|
|
|
60
|
-
- [antropy](https://github.com/raphaelvallat/antropy)
|
|
61
|
-
- [colorama](https://github.com/tartley/colorama)
|
|
62
|
-
- [einops](https://github.com/arogozhnikov/einops)
|
|
63
79
|
- [EMD-signal](https://github.com/laszukdawid/PyEMD)
|
|
64
80
|
- [ewtpy](https://github.com/vrcarva/ewtpy)
|
|
65
|
-
- [numba](https://github.com/numba/numba)
|
|
66
|
-
- [numpy](https://github.com/numpy/numpy)
|
|
67
|
-
- [scipy](https://github.com/scipy/scipy)
|
|
68
81
|
- [vmdpy](https://github.com/vrcarva/vmdpy)
|
|
69
|
-
- [psutil](https://github.com/giampaolo/psutil)
|
|
70
82
|
|
|
71
83
|
*Other dependence please read "requirements.txt"*
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
All codes from :
|
|
76
|
-
|
|
77
|
-
- Github:
|
|
78
|
-
- EMD-signal -> EMD, CEEFD, CEEMDAN, EEMD
|
|
79
|
-
- ewtpy -> EWT
|
|
80
|
-
- vmdpy -> VMD
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- Myself:
|
|
84
|
-
- CEEMD, EFD, FMD, ICEEMDAN, LMD, MEMD, RPSEMD, SSA, SVMD
|
|
85
|
+
*Please pip `EMD-signal`, not `PyEMD`*
|
|
85
86
|
|
|
86
87
|
## Url
|
|
87
88
|
|
|
@@ -19,7 +19,7 @@ Modify: (must)
|
|
|
19
19
|
|
|
20
20
|
import numpy as np
|
|
21
21
|
from typing import Union, Tuple
|
|
22
|
-
|
|
22
|
+
from .Utils import Check_Time_and_Signal
|
|
23
23
|
|
|
24
24
|
class ceefd:
|
|
25
25
|
"""CEEFD: Cyclic Envelop Empirical Fourier Decomposition"""
|
|
@@ -60,39 +60,18 @@ class ceefd:
|
|
|
60
60
|
|
|
61
61
|
return imf, mask
|
|
62
62
|
|
|
63
|
-
def decompose(self, S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None) -> Tuple[np.ndarray, np.ndarray]:
|
|
63
|
+
def decompose(self, S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None) -> Tuple[np.ndarray, np.ndarray, None]:
|
|
64
64
|
"""
|
|
65
65
|
CEEFD: Cyclic Envelope Empirical Fourier Decomposition
|
|
66
66
|
|
|
67
67
|
:param S: Signal
|
|
68
68
|
:param T: Time-axis, accepted formation is Unix array. Default uniformly sample.
|
|
69
|
-
:return: IMFs (2-dim), Res (1-dim)
|
|
69
|
+
:return: IMFs (2-dim), Res (1-dim), None
|
|
70
70
|
"""
|
|
71
71
|
|
|
72
72
|
from scipy.signal import find_peaks
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
S = np.array(S)
|
|
76
|
-
|
|
77
|
-
if S.ndim == 0:
|
|
78
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
79
|
-
|
|
80
|
-
elif S.ndim > 1:
|
|
81
|
-
if 1 in S.shape:
|
|
82
|
-
S = S.reshape(-1)
|
|
83
|
-
|
|
84
|
-
else:
|
|
85
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
86
|
-
|
|
87
|
-
N = len(S)
|
|
88
|
-
|
|
89
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
90
|
-
T = np.arange(N) # default fs = 1
|
|
91
|
-
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
92
|
-
|
|
93
|
-
else:
|
|
94
|
-
if not isinstance(T, np.ndarray):
|
|
95
|
-
T = np.array(T)
|
|
74
|
+
S, T, N = Check_Time_and_Signal(S, T)
|
|
96
75
|
|
|
97
76
|
fft_signal = np.fft.fft(S)
|
|
98
77
|
mag_spectrum = np.abs(fft_signal[:N // 2 + 1])
|
|
@@ -132,4 +111,4 @@ class ceefd:
|
|
|
132
111
|
if np.abs(residual).max() > 1e-10:
|
|
133
112
|
imfs.append(residual)
|
|
134
113
|
|
|
135
|
-
return np.array(imfs), residual
|
|
114
|
+
return np.array(imfs), residual, None
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
numpy - 2.2.6
|
|
7
|
+
time - 1.39.2
|
|
8
|
+
tqdm - 4.67.3
|
|
9
|
+
|
|
10
|
+
Only accessed by: (must)
|
|
11
|
+
Only __init__.py
|
|
12
|
+
|
|
13
|
+
Description: (if None write None)
|
|
14
|
+
Realize the CEEMD.
|
|
15
|
+
|
|
16
|
+
Modify: (must)
|
|
17
|
+
2026.3.25 - Create
|
|
18
|
+
2026.4.2 - Finish the Optimization of the CEEMD.
|
|
19
|
+
2026.5.1 - Fix the error of the decomposition.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from typing import Union, Tuple, Optional
|
|
23
|
+
import numpy as np
|
|
24
|
+
from .EMD import emd
|
|
25
|
+
from .Utils import monotonic_increasing, monotonic_decreasing, Check_Time_and_Signal
|
|
26
|
+
from warnings import warn
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ceemd(S: Union[list, np.ndarray], T: Union[list, np.ndarray] = None, N_whitenoise=37, beta=0.2, max_imf: Optional[int] = None, dead_line: int = 10, verbose: bool = False) \
|
|
30
|
+
-> Tuple[np.ndarray, np.ndarray, None]:
|
|
31
|
+
"""
|
|
32
|
+
CEEMD: Complementary Ensemble Empirical Mode Decomposition
|
|
33
|
+
|
|
34
|
+
:param S: Signal (1-dim)
|
|
35
|
+
:param T: the time axis.
|
|
36
|
+
:param N_whitenoise: the num of the added whitenoise.
|
|
37
|
+
:param beta:
|
|
38
|
+
:param max_imf: -1, None or other int | -1 means decompose completely, None means give a int auto, other int means the num of the IMFs
|
|
39
|
+
:param dead_line: Sometime it'll be in unuseful cycle, when the average of the N's sequence with added whitenoise is empty([]). It'll be forced exit when the time of the cycle above the deadline.
|
|
40
|
+
:param verbose:
|
|
41
|
+
:return: IMFs (n_IMFs, N), Res (N,), None
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
if beta <= 0:
|
|
45
|
+
raise ValueError("The beta should > 0")
|
|
46
|
+
|
|
47
|
+
if N_whitenoise <= 0 or not isinstance(N_whitenoise, int):
|
|
48
|
+
raise TypeError("N_whitenoise must be int type or > 0")
|
|
49
|
+
|
|
50
|
+
S, T, N = Check_Time_and_Signal(S, T, verbose)
|
|
51
|
+
|
|
52
|
+
if not np.all(np.diff(T) > 0):
|
|
53
|
+
raise ValueError("T should be monotonic increasing!")
|
|
54
|
+
|
|
55
|
+
if np.any(np.allclose(np.diff(np.diff(T)), 2)):
|
|
56
|
+
warn("The T is not uniform! Some error may happen.")
|
|
57
|
+
|
|
58
|
+
if max_imf is None:
|
|
59
|
+
max_imf = int(np.log2(len(S))) + 2
|
|
60
|
+
|
|
61
|
+
imfs = []
|
|
62
|
+
residual = S.copy()
|
|
63
|
+
k = 0
|
|
64
|
+
dead_cycle = 0
|
|
65
|
+
|
|
66
|
+
while True:
|
|
67
|
+
if max_imf != -1 and k >= max_imf:
|
|
68
|
+
break
|
|
69
|
+
|
|
70
|
+
imf_candidates = []
|
|
71
|
+
std_dev = np.std(residual)
|
|
72
|
+
|
|
73
|
+
for i in range(N_whitenoise):
|
|
74
|
+
white_noise = np.random.normal(0, std_dev * beta, N)
|
|
75
|
+
S_plus = residual + white_noise
|
|
76
|
+
S_minus = residual - white_noise
|
|
77
|
+
|
|
78
|
+
imfs_plus, _, _ = emd(S_plus, T, max_imf=1)
|
|
79
|
+
imfs_minus, _, _ = emd(S_minus, T, max_imf=1)
|
|
80
|
+
|
|
81
|
+
if len(imfs_plus) > 0 and len(imfs_minus) > 0:
|
|
82
|
+
imf_candidate = (imfs_plus[0] + imfs_minus[0]) / 2.0
|
|
83
|
+
imf_candidates.append(imf_candidate)
|
|
84
|
+
|
|
85
|
+
if not imf_candidates:
|
|
86
|
+
dead_cycle += 1
|
|
87
|
+
if dead_cycle >= dead_line:
|
|
88
|
+
raise RuntimeError("Trapped in a vicious cycle")
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
imf = np.mean(imf_candidates, axis=0)
|
|
92
|
+
imfs.append(imf)
|
|
93
|
+
residual = residual - imf
|
|
94
|
+
k += 1
|
|
95
|
+
|
|
96
|
+
from scipy.signal import argrelextrema
|
|
97
|
+
peaks = argrelextrema(residual, np.greater)[0]
|
|
98
|
+
valleys = argrelextrema(residual, np.less)[0]
|
|
99
|
+
|
|
100
|
+
if monotonic_increasing(residual) or monotonic_decreasing(residual) or len(peaks) + len(valleys) < 3:
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
return np.array(imfs), np.array(residual), None
|
|
@@ -1,5 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
numpy - 2.2.6
|
|
7
|
+
|
|
8
|
+
Only accessed by: (must)
|
|
9
|
+
Only __init__.py
|
|
10
|
+
|
|
11
|
+
Description: (if None write None)
|
|
12
|
+
Realize the CEEMDAN.
|
|
13
|
+
|
|
14
|
+
Modify: (must)
|
|
15
|
+
2026.3.25 - Create.
|
|
16
|
+
"""
|
|
17
|
+
|
|
1
18
|
from typing import Union, Tuple
|
|
2
19
|
import numpy as np
|
|
20
|
+
from .Utils import Check_Time_and_Signal
|
|
21
|
+
|
|
3
22
|
|
|
4
23
|
def ceemdan \
|
|
5
24
|
(
|
|
@@ -18,7 +37,7 @@ def ceemdan \
|
|
|
18
37
|
noise_kind='normal', # noise kind: 'normal', 'uniform'
|
|
19
38
|
range_thr=0.01, # Stop threshold
|
|
20
39
|
total_power_thr=0.005
|
|
21
|
-
) -> Tuple[np.ndarray, np.ndarray]:
|
|
40
|
+
) -> Tuple[np.ndarray, np.ndarray, None]:
|
|
22
41
|
|
|
23
42
|
"""
|
|
24
43
|
CEEMDAN: Complete Ensemble Empirical Mode Decomposition with Adaptive Noise
|
|
@@ -39,33 +58,11 @@ def ceemdan \
|
|
|
39
58
|
:param noise_kind:
|
|
40
59
|
:param range_thr:
|
|
41
60
|
:param total_power_thr:
|
|
42
|
-
:return: IMFs (n_IMFs, N), Res (N,)
|
|
61
|
+
:return: IMFs (n_IMFs, N), Res (N,), None
|
|
43
62
|
"""
|
|
44
|
-
|
|
45
63
|
from PyEMD import CEEMDAN
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
S = np.array(S)
|
|
49
|
-
|
|
50
|
-
if S.ndim == 0:
|
|
51
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
52
|
-
|
|
53
|
-
elif S.ndim > 1:
|
|
54
|
-
if 1 in S.shape:
|
|
55
|
-
S = S.reshape(-1)
|
|
56
|
-
|
|
57
|
-
else:
|
|
58
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
59
|
-
|
|
60
|
-
N = len(S)
|
|
61
|
-
|
|
62
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
63
|
-
T = np.arange(N) # default fs = 1
|
|
64
|
-
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
65
|
-
|
|
66
|
-
else:
|
|
67
|
-
if not isinstance(T, np.ndarray):
|
|
68
|
-
T = np.array(T)
|
|
65
|
+
S, T, N = Check_Time_and_Signal(S, T)
|
|
69
66
|
|
|
70
67
|
CEEMDAN = CEEMDAN \
|
|
71
68
|
(
|
|
@@ -89,4 +86,4 @@ def ceemdan \
|
|
|
89
86
|
IMFs = IMF_Residue[:-1, :] # shape [n_imfs, len(S)]
|
|
90
87
|
Res = IMF_Residue[-1, :]
|
|
91
88
|
|
|
92
|
-
return IMFs, Res
|
|
89
|
+
return IMFs, Res, None
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
numpy - 2.2.6
|
|
7
|
+
|
|
8
|
+
Only accessed by: (must)
|
|
9
|
+
Only __init__.py
|
|
10
|
+
|
|
11
|
+
Description: (if None write None)
|
|
12
|
+
Realize the EEMD.
|
|
13
|
+
|
|
14
|
+
Modify: (must)
|
|
15
|
+
2026.3.25 - Create.
|
|
16
|
+
2026.3.27 - Change the EEMD class' usage. EEMD(parallel=True) (default) -> EEMD(parallel=False). Now, it will not use parallel default.
|
|
17
|
+
2026.4.2 - Finish the Optimization of the EEMD. Correct the logic.
|
|
18
|
+
2026.5.1 - Fix: use PyEMD.EEMD to ensure standard algorithm.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
from typing import Union, Tuple, Optional
|
|
23
|
+
from .Utils import Check_Time_and_Signal
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def eemd(
|
|
27
|
+
S: Union[list, np.ndarray],
|
|
28
|
+
T: Optional[Union[list, np.ndarray]] = None,
|
|
29
|
+
trials: int = 100,
|
|
30
|
+
noise_width: float = 0.05,
|
|
31
|
+
max_imf: int = -1,
|
|
32
|
+
parallel: bool = False,
|
|
33
|
+
**kwargs
|
|
34
|
+
) -> Tuple[np.ndarray, np.ndarray, None]:
|
|
35
|
+
"""
|
|
36
|
+
EEMD: Ensemble Empirical Mode Decomposition
|
|
37
|
+
(Standard implementation via PyEMD)
|
|
38
|
+
|
|
39
|
+
:param S: Signal (1-dim)
|
|
40
|
+
:param T: Time axis (1-dim). Default uniform.
|
|
41
|
+
:param trials: Number of white noise realizations (ensemble size).
|
|
42
|
+
:param noise_width: Standard deviation of added white noise relative to S std.
|
|
43
|
+
:param max_imf: Max number of IMFs to extract. -1 for all.
|
|
44
|
+
:param parallel: Parallelize the EEMD.
|
|
45
|
+
:param kwargs: Additional parameters passed to PyEMD.EEMD.
|
|
46
|
+
:return: IMFs (n_IMFs, N), Res (N,)
|
|
47
|
+
"""
|
|
48
|
+
from PyEMD import EEMD
|
|
49
|
+
|
|
50
|
+
S, T, N = Check_Time_and_Signal(S, T)
|
|
51
|
+
|
|
52
|
+
decomposer = EEMD(trials=trials, noise_width=noise_width, parallel=parallel, **kwargs)
|
|
53
|
+
result = decomposer.eemd(S, T, max_imf=max_imf)
|
|
54
|
+
|
|
55
|
+
IMFs = result[:-1, :] # shape [n_imfs, N]
|
|
56
|
+
Res = result[-1, :] # shape [N,]
|
|
57
|
+
|
|
58
|
+
return IMFs, Res, None
|
|
@@ -17,21 +17,23 @@ Description: (if None write None)
|
|
|
17
17
|
Modify: (must)
|
|
18
18
|
2026.3.25 - Create
|
|
19
19
|
2026.4.2 - Finish the Optimization of the EFD. Del the origin efd function.
|
|
20
|
+
2026.4.7 - Correct the error of the use of the np.concentrate and the construction of the wn.
|
|
20
21
|
"""
|
|
21
22
|
|
|
22
23
|
import numpy as np
|
|
23
|
-
from .COLOR import printc
|
|
24
24
|
from typing import Union, Tuple
|
|
25
|
+
from .Utils import Check_Time_and_Signal
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: int=-1) -> Tuple[np.ndarray, np.ndarray]:
|
|
28
|
+
def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: int=-1, verbose: bool=False) -> Tuple[np.ndarray, np.ndarray, None]:
|
|
28
29
|
"""
|
|
29
30
|
EFD: Empirical Fourier Decomposition
|
|
30
31
|
|
|
31
32
|
:param S: Signal (1-dim)
|
|
32
33
|
:param T: Time axis (1-dim)
|
|
33
34
|
:param max_IMFs: the num of the IMFs. -1 means return all IMFs
|
|
34
|
-
:
|
|
35
|
+
:param verbose: if print the info?
|
|
36
|
+
:return: IMFs (n_IMFs, N), Res: (N,), None
|
|
35
37
|
"""
|
|
36
38
|
|
|
37
39
|
from scipy.signal import argrelmax
|
|
@@ -43,31 +45,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
43
45
|
if max_IMFs <= 0:
|
|
44
46
|
raise ValueError("Invalid value! Do you want use -1?")
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
S = np.array(S)
|
|
48
|
-
|
|
49
|
-
if S.ndim == 0:
|
|
50
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
51
|
-
|
|
52
|
-
elif S.ndim > 1:
|
|
53
|
-
if 1 in S.shape:
|
|
54
|
-
S = S.reshape(-1)
|
|
55
|
-
|
|
56
|
-
else:
|
|
57
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
58
|
-
|
|
59
|
-
N = len(S)
|
|
60
|
-
|
|
61
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
62
|
-
T = np.arange(N) # default fs = 1
|
|
63
|
-
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
64
|
-
|
|
65
|
-
else:
|
|
66
|
-
if not isinstance(T, np.ndarray):
|
|
67
|
-
T = np.array(T)
|
|
68
|
-
|
|
69
|
-
if len(T) != N:
|
|
70
|
-
raise ValueError(f"len of T: ({len(T)}) doesn't match ({N})")
|
|
48
|
+
S, T, N = Check_Time_and_Signal(S, T, verbose)
|
|
71
49
|
|
|
72
50
|
dt = np.diff(T)
|
|
73
51
|
if not np.allclose(dt, dt[0], rtol=1e-10, atol=1e-14):
|
|
@@ -78,7 +56,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
78
56
|
S: np.ndarray = S - np.mean(S)
|
|
79
57
|
|
|
80
58
|
F = np.fft.fft(S)
|
|
81
|
-
# fs = np.fft.fftfreq(N // 2 + 1, d=T[1]-T[0]) # only positive freq
|
|
59
|
+
# fs = np.fft.fftfreq(N // 2 + 1, d=T[1]-T[0]) # only positive freq S
|
|
82
60
|
magnitude = np.abs(F)
|
|
83
61
|
phase = np.angle(F)
|
|
84
62
|
|
|
@@ -86,14 +64,13 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
86
64
|
uniform_freq = np.linspace(0, np.pi, N // 2)
|
|
87
65
|
freq_N = len(uniform_freq)
|
|
88
66
|
|
|
89
|
-
|
|
67
|
+
local_maximum_points_tuple = argrelmax(edge_magnitude)
|
|
68
|
+
local_maximum_points = local_maximum_points_tuple[0]
|
|
90
69
|
local_maximum = edge_magnitude[local_maximum_points]
|
|
91
70
|
|
|
92
71
|
if max_IMFs != -1:
|
|
93
72
|
local_maximum_zip = [(point, value) for point, value in zip(local_maximum_points, local_maximum)]
|
|
94
|
-
|
|
95
73
|
local_maximum_zip = sorted(local_maximum_zip, reverse=True, key=lambda x: x[1])
|
|
96
|
-
|
|
97
74
|
local_maximum_points = list(map(lambda x: x[0], local_maximum_zip[:max_IMFs]))
|
|
98
75
|
|
|
99
76
|
local_maximum_points = np.concatenate(([0], local_maximum_points, [freq_N - 1]))
|
|
@@ -112,7 +89,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
112
89
|
else:
|
|
113
90
|
# wn.append(np.argmin(edge_magnitude[current_point:next_point + 1]))
|
|
114
91
|
wn.append(current_point + np.argmin(edge_magnitude[current_point:next_point + 1]))
|
|
115
|
-
wn = np.concatenate(([0], wn, freq_N - 1))
|
|
92
|
+
wn = np.concatenate(([0], wn, [freq_N - 1]))
|
|
116
93
|
|
|
117
94
|
filters_arr = []
|
|
118
95
|
for edge in range(1, len(wn)):
|
|
@@ -140,4 +117,4 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
140
117
|
IMFs.append(np.fft.ifft(full_spectrum).real)
|
|
141
118
|
|
|
142
119
|
IMFs = np.array(IMFs)
|
|
143
|
-
return IMFs, S - np.sum(IMFs, axis=0) + MEAN
|
|
120
|
+
return IMFs, S - np.sum(IMFs, axis=0) + MEAN, None
|