Modal-Decomposition 0.1.3__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.3 → modal_decomposition-0.1.4}/PKG-INFO +29 -4
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/README.md +28 -3
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/pyproject.toml +1 -1
- {modal_decomposition-0.1.3 → 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.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEMDAN.py +23 -26
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EEMD.py +10 -16
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EFD.py +6 -31
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EMD.py +7 -27
- modal_decomposition-0.1.4/src/Modal_Decomposition/EWT.py +62 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/FMD.py +17 -19
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/ICEEMDAN.py +40 -65
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/LMD.py +12 -19
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/MEMD.py +15 -16
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/RPSEMD.py +5 -10
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SSA.py +14 -15
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SVMD.py +20 -12
- modal_decomposition-0.1.4/src/Modal_Decomposition/Utils/Check.py +39 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/Monotonicity.py +16 -16
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/__init__.py +1 -1
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/VMD.py +16 -8
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/__init__.py +4 -4
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/PKG-INFO +29 -4
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/SOURCES.txt +1 -4
- modal_decomposition-0.1.4/tests/test.py +216 -0
- modal_decomposition-0.1.3/src/Modal_Decomposition/CEEMD.py +0 -135
- modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/__init__.py +0 -18
- modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/color_define.py +0 -30
- modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/colorful_print.py +0 -66
- modal_decomposition-0.1.3/src/Modal_Decomposition/EWT.py +0 -76
- modal_decomposition-0.1.3/src/Modal_Decomposition/Utils/OneDimArray.py +0 -27
- modal_decomposition-0.1.3/tests/test.py +0 -74
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/LICENSE +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/setup.cfg +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/CycleError.py +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/RealizationError.py +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/EnvironmentMemory.py +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/LazyImport.py +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/NumpyNdarray_MemoryCalculator.py +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
- {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
- {modal_decomposition-0.1.3 → 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) |
|
|
@@ -61,14 +84,14 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
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
|
```
|
|
@@ -91,6 +114,8 @@ This lib's dependence are:
|
|
|
91
114
|
|
|
92
115
|
*Other dependence please read "requirements.txt"*
|
|
93
116
|
|
|
117
|
+
*Please pip `EMD-signal`, not `PyEMD`*
|
|
118
|
+
|
|
94
119
|
## Url
|
|
95
120
|
|
|
96
121
|
This lib's url is: https://github.com/a-raining-day/Modal-Decomposition
|
|
@@ -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) |
|
|
@@ -29,14 +52,14 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
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
|
```
|
|
@@ -59,6 +82,8 @@ This lib's dependence are:
|
|
|
59
82
|
|
|
60
83
|
*Other dependence please read "requirements.txt"*
|
|
61
84
|
|
|
85
|
+
*Please pip `EMD-signal`, not `PyEMD`*
|
|
86
|
+
|
|
62
87
|
## Url
|
|
63
88
|
|
|
64
89
|
This lib's url is: https://github.com/a-raining-day/Modal-Decomposition
|
|
@@ -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
|
|
@@ -3,7 +3,7 @@ Python version: (must)
|
|
|
3
3
|
3.10.11
|
|
4
4
|
|
|
5
5
|
Lib and Version: (if None write None)
|
|
6
|
-
|
|
6
|
+
numpy - 2.2.6
|
|
7
7
|
|
|
8
8
|
Only accessed by: (must)
|
|
9
9
|
Only __init__.py
|
|
@@ -20,6 +20,8 @@ Modify: (must)
|
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
from typing import Union, Tuple, Optional
|
|
23
|
+
from .Utils import Check_Time_and_Signal
|
|
24
|
+
|
|
23
25
|
|
|
24
26
|
def eemd(
|
|
25
27
|
S: Union[list, np.ndarray],
|
|
@@ -27,8 +29,9 @@ def eemd(
|
|
|
27
29
|
trials: int = 100,
|
|
28
30
|
noise_width: float = 0.05,
|
|
29
31
|
max_imf: int = -1,
|
|
32
|
+
parallel: bool = False,
|
|
30
33
|
**kwargs
|
|
31
|
-
) -> Tuple[np.ndarray, np.ndarray]:
|
|
34
|
+
) -> Tuple[np.ndarray, np.ndarray, None]:
|
|
32
35
|
"""
|
|
33
36
|
EEMD: Ensemble Empirical Mode Decomposition
|
|
34
37
|
(Standard implementation via PyEMD)
|
|
@@ -36,29 +39,20 @@ def eemd(
|
|
|
36
39
|
:param S: Signal (1-dim)
|
|
37
40
|
:param T: Time axis (1-dim). Default uniform.
|
|
38
41
|
:param trials: Number of white noise realizations (ensemble size).
|
|
39
|
-
:param noise_width: Standard deviation of added white noise relative to
|
|
42
|
+
:param noise_width: Standard deviation of added white noise relative to S std.
|
|
40
43
|
:param max_imf: Max number of IMFs to extract. -1 for all.
|
|
44
|
+
:param parallel: Parallelize the EEMD.
|
|
41
45
|
:param kwargs: Additional parameters passed to PyEMD.EEMD.
|
|
42
46
|
:return: IMFs (n_IMFs, N), Res (N,)
|
|
43
47
|
"""
|
|
44
48
|
from PyEMD import EEMD
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
S = np.array(S, dtype=np.float64).ravel()
|
|
48
|
-
else:
|
|
49
|
-
S = S.ravel().astype(np.float64)
|
|
50
|
-
|
|
51
|
-
N = len(S)
|
|
52
|
-
|
|
53
|
-
if T is None:
|
|
54
|
-
T = np.arange(N, dtype=np.float64)
|
|
55
|
-
else:
|
|
56
|
-
T = np.asarray(T, dtype=np.float64)
|
|
50
|
+
S, T, N = Check_Time_and_Signal(S, T)
|
|
57
51
|
|
|
58
|
-
decomposer = EEMD(trials=trials, noise_width=noise_width, **kwargs)
|
|
52
|
+
decomposer = EEMD(trials=trials, noise_width=noise_width, parallel=parallel, **kwargs)
|
|
59
53
|
result = decomposer.eemd(S, T, max_imf=max_imf)
|
|
60
54
|
|
|
61
55
|
IMFs = result[:-1, :] # shape [n_imfs, N]
|
|
62
56
|
Res = result[-1, :] # shape [N,]
|
|
63
57
|
|
|
64
|
-
return IMFs, Res
|
|
58
|
+
return IMFs, Res, None
|
|
@@ -21,11 +21,11 @@ Modify: (must)
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
|
-
from .COLOR import printc
|
|
25
24
|
from typing import Union, Tuple
|
|
25
|
+
from .Utils import Check_Time_and_Signal
|
|
26
26
|
|
|
27
27
|
|
|
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]:
|
|
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]:
|
|
29
29
|
"""
|
|
30
30
|
EFD: Empirical Fourier Decomposition
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
33
33
|
:param T: Time axis (1-dim)
|
|
34
34
|
:param max_IMFs: the num of the IMFs. -1 means return all IMFs
|
|
35
35
|
:param verbose: if print the info?
|
|
36
|
-
:return: IMFs (n_IMFs, N), Res: (N,)
|
|
36
|
+
:return: IMFs (n_IMFs, N), Res: (N,), None
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
39
|
from scipy.signal import argrelmax
|
|
@@ -45,32 +45,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
45
45
|
if max_IMFs <= 0:
|
|
46
46
|
raise ValueError("Invalid value! Do you want use -1?")
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
S = np.array(S)
|
|
50
|
-
|
|
51
|
-
if S.ndim == 0:
|
|
52
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
53
|
-
|
|
54
|
-
elif S.ndim > 1:
|
|
55
|
-
if 1 in S.shape:
|
|
56
|
-
S = S.reshape(-1)
|
|
57
|
-
|
|
58
|
-
else:
|
|
59
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
60
|
-
|
|
61
|
-
N = len(S)
|
|
62
|
-
|
|
63
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
64
|
-
T = np.arange(N) # default fs = 1
|
|
65
|
-
if verbose:
|
|
66
|
-
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
67
|
-
|
|
68
|
-
else:
|
|
69
|
-
if not isinstance(T, np.ndarray):
|
|
70
|
-
T = np.array(T)
|
|
71
|
-
|
|
72
|
-
if len(T) != N:
|
|
73
|
-
raise ValueError(f"len of T: ({len(T)}) doesn't match ({N})")
|
|
48
|
+
S, T, N = Check_Time_and_Signal(S, T, verbose)
|
|
74
49
|
|
|
75
50
|
dt = np.diff(T)
|
|
76
51
|
if not np.allclose(dt, dt[0], rtol=1e-10, atol=1e-14):
|
|
@@ -81,7 +56,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
81
56
|
S: np.ndarray = S - np.mean(S)
|
|
82
57
|
|
|
83
58
|
F = np.fft.fft(S)
|
|
84
|
-
# 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
|
|
85
60
|
magnitude = np.abs(F)
|
|
86
61
|
phase = np.angle(F)
|
|
87
62
|
|
|
@@ -142,4 +117,4 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
142
117
|
IMFs.append(np.fft.ifft(full_spectrum).real)
|
|
143
118
|
|
|
144
119
|
IMFs = np.array(IMFs)
|
|
145
|
-
return IMFs, S - np.sum(IMFs, axis=0) + MEAN
|
|
120
|
+
return IMFs, S - np.sum(IMFs, axis=0) + MEAN, None
|
|
@@ -14,15 +14,15 @@ Description: (if None write None)
|
|
|
14
14
|
|
|
15
15
|
Modify: (must)
|
|
16
16
|
2026.3.25 - Create.
|
|
17
|
+
2026.5.1 - Change the position of import PyEMD.
|
|
17
18
|
"""
|
|
18
19
|
|
|
19
|
-
from PyEMD import EMD
|
|
20
20
|
import numpy as np
|
|
21
21
|
from typing import Tuple, Union
|
|
22
|
-
|
|
22
|
+
from .Utils import Check_Time_and_Signal
|
|
23
23
|
|
|
24
24
|
def emd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, spline_kind: str = "cubic", nbsym: int = 2, max_imf=-1, verbose: bool=False)\
|
|
25
|
-
-> Tuple[np.ndarray, np.ndarray]:
|
|
25
|
+
-> Tuple[np.ndarray, np.ndarray, None]:
|
|
26
26
|
"""
|
|
27
27
|
EMD: Empirical Mode Decomposition
|
|
28
28
|
|
|
@@ -32,31 +32,11 @@ def emd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, spline_kind
|
|
|
32
32
|
:param nbsym:
|
|
33
33
|
:param max_imf: the max num of IMFs
|
|
34
34
|
:param verbose: True will print info, else no.
|
|
35
|
-
:return: IMFs (
|
|
35
|
+
:return: IMFs (n_IMFs, N), Res (N,), None
|
|
36
36
|
"""
|
|
37
|
-
|
|
38
|
-
S = np.array(S)
|
|
39
|
-
|
|
40
|
-
if S.ndim == 0:
|
|
41
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
42
|
-
|
|
43
|
-
elif S.ndim > 1:
|
|
44
|
-
if 1 in S.shape:
|
|
45
|
-
S = S.reshape(-1)
|
|
46
|
-
|
|
47
|
-
else:
|
|
48
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
49
|
-
|
|
50
|
-
N = len(S)
|
|
51
|
-
|
|
52
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
53
|
-
T = np.arange(N) # default fs = 1
|
|
54
|
-
if verbose:
|
|
55
|
-
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
37
|
+
from PyEMD import EMD
|
|
56
38
|
|
|
57
|
-
|
|
58
|
-
if not isinstance(T, np.ndarray):
|
|
59
|
-
T = np.array(T)
|
|
39
|
+
S, T, N = Check_Time_and_Signal(S, T, verbose)
|
|
60
40
|
|
|
61
41
|
EMD_cls = EMD(spline_kind, nbsym)
|
|
62
42
|
|
|
@@ -71,4 +51,4 @@ def emd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, spline_kind
|
|
|
71
51
|
elif IMFs.ndim == 0:
|
|
72
52
|
IMFs = np.zeros((1, Res.shape[1]))
|
|
73
53
|
|
|
74
|
-
return IMFs, Res
|
|
54
|
+
return IMFs, Res, None
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
ewtpy - 0.2
|
|
7
|
+
numpy - 2.2.6
|
|
8
|
+
|
|
9
|
+
Only accessed by: (must)
|
|
10
|
+
Only __init__.py
|
|
11
|
+
|
|
12
|
+
Description: (if None write None)
|
|
13
|
+
Realize the EWT
|
|
14
|
+
|
|
15
|
+
Modify: (must)
|
|
16
|
+
2026.3.25 - Create.
|
|
17
|
+
2026.5.1 - Use dict to store other informations.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Any, Union
|
|
21
|
+
import numpy as np
|
|
22
|
+
from .Utils import Check_Time_and_Signal
|
|
23
|
+
|
|
24
|
+
def ewt \
|
|
25
|
+
(
|
|
26
|
+
S: Union[list, np.ndarray],
|
|
27
|
+
N: int = 5,
|
|
28
|
+
log: int = 0,
|
|
29
|
+
detect: str = "locmax",
|
|
30
|
+
completion: int = 0,
|
|
31
|
+
reg: str = 'average',
|
|
32
|
+
lengthFilter: int = 10,
|
|
33
|
+
sigmaFilter: int = 5,
|
|
34
|
+
) -> Union[np.ndarray, np.ndarray, dict[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
EWT: Empirical Wavelet Transform
|
|
37
|
+
|
|
38
|
+
:param S: Signal (1-dim)
|
|
39
|
+
:param N:
|
|
40
|
+
:param log:
|
|
41
|
+
:param detect:
|
|
42
|
+
:param completion:
|
|
43
|
+
:param reg:
|
|
44
|
+
:param lengthFilter:
|
|
45
|
+
:param sigmaFilter:
|
|
46
|
+
:return: IMFs(N, len(S)), Res(N,), Info(dict)
|
|
47
|
+
"""
|
|
48
|
+
from ewtpy import EWT1D
|
|
49
|
+
|
|
50
|
+
S, _, _ = Check_Time_and_Signal(S)
|
|
51
|
+
|
|
52
|
+
ewt, mfb, boundaries = EWT1D(S, N, log, detect, completion, reg, lengthFilter, sigmaFilter)
|
|
53
|
+
ewt: np.ndarray = ewt.T
|
|
54
|
+
mfb = mfb.T
|
|
55
|
+
|
|
56
|
+
Info = \
|
|
57
|
+
{
|
|
58
|
+
"MFB": mfb,
|
|
59
|
+
"Boundaries": boundaries
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return ewt[:-1, :], ewt[-1, :], Info
|