Modal-Decomposition 0.1.2__tar.gz → 0.1.3__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.3}/PKG-INFO +2 -26
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/README.md +1 -25
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/pyproject.toml +1 -1
- modal_decomposition-0.1.3/src/Modal_Decomposition/EEMD.py +64 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/EFD.py +8 -6
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/EMD.py +0 -1
- modal_decomposition-0.1.3/src/Modal_Decomposition/Error/RealizationError.py +2 -0
- modal_decomposition-0.1.3/src/Modal_Decomposition/LMD.py +243 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/MEMD.py +13 -11
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/SSA.py +2 -2
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/SVMD.py +9 -4
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/__init__.py +8 -15
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/PKG-INFO +2 -26
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/SOURCES.txt +1 -1
- modal_decomposition-0.1.2/src/Modal_Decomposition/EEMD.py +0 -130
- modal_decomposition-0.1.2/src/Modal_Decomposition/LMD.py +0 -178
- modal_decomposition-0.1.2/src/Modal_Decomposition/help_function.py +0 -64
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/LICENSE +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/setup.cfg +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/CEEFD.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/CEEMD.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/CEEMDAN.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/COLOR/__init__.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/COLOR/color_define.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/COLOR/colorful_print.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/EWT.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Error/CycleError.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/FMD.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/ICEEMDAN.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/RPSEMD.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/EnvironmentMemory.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/LazyImport.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/Monotonicity.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/NumpyNdarray_MemoryCalculator.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/OneDimArray.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/__init__.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/VMD.py +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/top_level.txt +0 -0
- {modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/tests/test.py +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.3
|
|
4
4
|
Summary: a package for modal decomposition
|
|
5
5
|
Author-email: Mao_HaoChuan <2215269365@qq.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -55,7 +55,7 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
55
55
|
| 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
56
|
| 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
57
|
| EWT | Empirical Wavelet Transform | `Function.EWT(signal)` | [10.48550/arXiv.2304.06274](https://arxiv.org/abs/2304.06274) |
|
|
58
|
-
| FMD | Filtered Mode Decomposition | `Function.
|
|
58
|
+
| FMD | Filtered Mode Decomposition | `Function.FMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
|
|
59
59
|
| 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
60
|
| LMD | Local Mean Decomposition | `Function.LMD(signal)` | [10.1098/rsif.2005.0058](https://royalsocietypublishing.org/doi/10.1098/rsif.2005.0058) |
|
|
61
61
|
| MEMD | Multivariate Empirical Mode Decomposition | `Function.MEMD(signal)` | [10.48550/arXiv.2206.00926](https://arxiv.org/abs/2206.00926) |
|
|
@@ -79,42 +79,18 @@ pip install -r requirements.txt
|
|
|
79
79
|
pip install Modal-Decomposition
|
|
80
80
|
```
|
|
81
81
|
|
|
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
82
|
## Dependence
|
|
87
83
|
|
|
88
84
|
This lib's dependence are:
|
|
89
85
|
|
|
90
86
|
***Python: 3.10***
|
|
91
87
|
|
|
92
|
-
- [antropy](https://github.com/raphaelvallat/antropy)
|
|
93
|
-
- [colorama](https://github.com/tartley/colorama)
|
|
94
|
-
- [einops](https://github.com/arogozhnikov/einops)
|
|
95
88
|
- [EMD-signal](https://github.com/laszukdawid/PyEMD)
|
|
96
89
|
- [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
90
|
- [vmdpy](https://github.com/vrcarva/vmdpy)
|
|
101
|
-
- [psutil](https://github.com/giampaolo/psutil)
|
|
102
91
|
|
|
103
92
|
*Other dependence please read "requirements.txt"*
|
|
104
93
|
|
|
105
|
-
## Codes Resource
|
|
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
|
-
|
|
118
94
|
## Url
|
|
119
95
|
|
|
120
96
|
This lib's url is: https://github.com/a-raining-day/Modal-Decomposition
|
|
@@ -23,7 +23,7 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
23
23
|
| 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
24
|
| 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
25
|
| EWT | Empirical Wavelet Transform | `Function.EWT(signal)` | [10.48550/arXiv.2304.06274](https://arxiv.org/abs/2304.06274) |
|
|
26
|
-
| FMD | Filtered Mode Decomposition | `Function.
|
|
26
|
+
| FMD | Filtered Mode Decomposition | `Function.FMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
|
|
27
27
|
| 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
28
|
| LMD | Local Mean Decomposition | `Function.LMD(signal)` | [10.1098/rsif.2005.0058](https://royalsocietypublishing.org/doi/10.1098/rsif.2005.0058) |
|
|
29
29
|
| MEMD | Multivariate Empirical Mode Decomposition | `Function.MEMD(signal)` | [10.48550/arXiv.2206.00926](https://arxiv.org/abs/2206.00926) |
|
|
@@ -47,42 +47,18 @@ pip install -r requirements.txt
|
|
|
47
47
|
pip install Modal-Decomposition
|
|
48
48
|
```
|
|
49
49
|
|
|
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
50
|
## Dependence
|
|
55
51
|
|
|
56
52
|
This lib's dependence are:
|
|
57
53
|
|
|
58
54
|
***Python: 3.10***
|
|
59
55
|
|
|
60
|
-
- [antropy](https://github.com/raphaelvallat/antropy)
|
|
61
|
-
- [colorama](https://github.com/tartley/colorama)
|
|
62
|
-
- [einops](https://github.com/arogozhnikov/einops)
|
|
63
56
|
- [EMD-signal](https://github.com/laszukdawid/PyEMD)
|
|
64
57
|
- [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
58
|
- [vmdpy](https://github.com/vrcarva/vmdpy)
|
|
69
|
-
- [psutil](https://github.com/giampaolo/psutil)
|
|
70
59
|
|
|
71
60
|
*Other dependence please read "requirements.txt"*
|
|
72
61
|
|
|
73
|
-
## Codes Resource
|
|
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
|
-
|
|
86
62
|
## Url
|
|
87
63
|
|
|
88
64
|
This lib's url is: https://github.com/a-raining-day/Modal-Decomposition
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
EMD-S - 1.9.0
|
|
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
|
+
|
|
24
|
+
def eemd(
|
|
25
|
+
S: Union[list, np.ndarray],
|
|
26
|
+
T: Optional[Union[list, np.ndarray]] = None,
|
|
27
|
+
trials: int = 100,
|
|
28
|
+
noise_width: float = 0.05,
|
|
29
|
+
max_imf: int = -1,
|
|
30
|
+
**kwargs
|
|
31
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
32
|
+
"""
|
|
33
|
+
EEMD: Ensemble Empirical Mode Decomposition
|
|
34
|
+
(Standard implementation via PyEMD)
|
|
35
|
+
|
|
36
|
+
:param S: Signal (1-dim)
|
|
37
|
+
:param T: Time axis (1-dim). Default uniform.
|
|
38
|
+
:param trials: Number of white noise realizations (ensemble size).
|
|
39
|
+
:param noise_width: Standard deviation of added white noise relative to signal std.
|
|
40
|
+
:param max_imf: Max number of IMFs to extract. -1 for all.
|
|
41
|
+
:param kwargs: Additional parameters passed to PyEMD.EEMD.
|
|
42
|
+
:return: IMFs (n_IMFs, N), Res (N,)
|
|
43
|
+
"""
|
|
44
|
+
from PyEMD import EEMD
|
|
45
|
+
|
|
46
|
+
if not isinstance(S, np.ndarray):
|
|
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)
|
|
57
|
+
|
|
58
|
+
decomposer = EEMD(trials=trials, noise_width=noise_width, **kwargs)
|
|
59
|
+
result = decomposer.eemd(S, T, max_imf=max_imf)
|
|
60
|
+
|
|
61
|
+
IMFs = result[:-1, :] # shape [n_imfs, N]
|
|
62
|
+
Res = result[-1, :] # shape [N,]
|
|
63
|
+
|
|
64
|
+
return IMFs, Res
|
|
@@ -17,6 +17,7 @@ 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
|
|
@@ -24,13 +25,14 @@ from .COLOR import printc
|
|
|
24
25
|
from typing import Union, Tuple
|
|
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]:
|
|
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
|
|
35
|
+
:param verbose: if print the info?
|
|
34
36
|
:return: IMFs (n_IMFs, N), Res: (N,)
|
|
35
37
|
"""
|
|
36
38
|
|
|
@@ -60,7 +62,8 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
60
62
|
|
|
61
63
|
if T is None: # if T is None, default generate uniform T-axis.
|
|
62
64
|
T = np.arange(N) # default fs = 1
|
|
63
|
-
|
|
65
|
+
if verbose:
|
|
66
|
+
print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
|
|
64
67
|
|
|
65
68
|
else:
|
|
66
69
|
if not isinstance(T, np.ndarray):
|
|
@@ -86,14 +89,13 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
86
89
|
uniform_freq = np.linspace(0, np.pi, N // 2)
|
|
87
90
|
freq_N = len(uniform_freq)
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
local_maximum_points_tuple = argrelmax(edge_magnitude)
|
|
93
|
+
local_maximum_points = local_maximum_points_tuple[0]
|
|
90
94
|
local_maximum = edge_magnitude[local_maximum_points]
|
|
91
95
|
|
|
92
96
|
if max_IMFs != -1:
|
|
93
97
|
local_maximum_zip = [(point, value) for point, value in zip(local_maximum_points, local_maximum)]
|
|
94
|
-
|
|
95
98
|
local_maximum_zip = sorted(local_maximum_zip, reverse=True, key=lambda x: x[1])
|
|
96
|
-
|
|
97
99
|
local_maximum_points = list(map(lambda x: x[0], local_maximum_zip[:max_IMFs]))
|
|
98
100
|
|
|
99
101
|
local_maximum_points = np.concatenate(([0], local_maximum_points, [freq_N - 1]))
|
|
@@ -112,7 +114,7 @@ def efd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, max_IMFs: i
|
|
|
112
114
|
else:
|
|
113
115
|
# wn.append(np.argmin(edge_magnitude[current_point:next_point + 1]))
|
|
114
116
|
wn.append(current_point + np.argmin(edge_magnitude[current_point:next_point + 1]))
|
|
115
|
-
wn = np.concatenate(([0], wn, freq_N - 1))
|
|
117
|
+
wn = np.concatenate(([0], wn, [freq_N - 1]))
|
|
116
118
|
|
|
117
119
|
filters_arr = []
|
|
118
120
|
for edge in range(1, len(wn)):
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python version: (must)
|
|
3
|
+
3.10.11
|
|
4
|
+
|
|
5
|
+
Lib and Version: (if None write None)
|
|
6
|
+
numpy - 2.2.6
|
|
7
|
+
scipy - 1.15.3
|
|
8
|
+
|
|
9
|
+
Only accessed by: (must)
|
|
10
|
+
Only __init__.py
|
|
11
|
+
|
|
12
|
+
Modify: (must)
|
|
13
|
+
2026.3.25
|
|
14
|
+
|
|
15
|
+
Description: (if None write None)
|
|
16
|
+
Realize the LMD
|
|
17
|
+
|
|
18
|
+
Modify:
|
|
19
|
+
2026.3.25 - Optimize the use of scipy
|
|
20
|
+
2026.4.3 - Finish the Optimization of the LMD.
|
|
21
|
+
2026.4.7 - LMD can support the decompose completely now.
|
|
22
|
+
2026.4.9 - Change some hardcode parameters to args.
|
|
23
|
+
2026.5.1 - Fix the dependence of "help_function.py".
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
from .Utils import is_monotonic
|
|
28
|
+
from typing import Union, Tuple
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def lmd(
|
|
32
|
+
S: Union[list, np.ndarray],
|
|
33
|
+
max_pf: Union[int, None] = None,
|
|
34
|
+
max_iter: int = 37,
|
|
35
|
+
eps: float = 0.05,
|
|
36
|
+
eps_stable: float = 1e-12,
|
|
37
|
+
min_amp: float = 1e-12,
|
|
38
|
+
max_amp: float = 1e12,
|
|
39
|
+
converge_mean: float = 1e-3,
|
|
40
|
+
smooth_window: int = 5
|
|
41
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
42
|
+
"""
|
|
43
|
+
LMD: Local mean decomposition
|
|
44
|
+
|
|
45
|
+
:param S: Signal (1-dim)
|
|
46
|
+
:param max_pf: the max num of the PFs. Default log2(N), -1 means decompose completely.
|
|
47
|
+
:param max_iter: max iteration for each iter of decomposing the PFs. Default 37, according the paper.
|
|
48
|
+
:param eps: Envelope convergence threshold
|
|
49
|
+
:param eps_stable:
|
|
50
|
+
:param min_amp:
|
|
51
|
+
:param max_amp:
|
|
52
|
+
:param converge_mean:
|
|
53
|
+
:param smooth_window:
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
PFs: (n_pf, N), Res: (N,)
|
|
57
|
+
"""
|
|
58
|
+
from scipy.signal import argrelextrema, savgol_filter
|
|
59
|
+
|
|
60
|
+
if S.ndim == 0:
|
|
61
|
+
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
62
|
+
|
|
63
|
+
elif S.ndim > 1:
|
|
64
|
+
if 1 in S.shape:
|
|
65
|
+
S = S.reshape(-1)
|
|
66
|
+
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
69
|
+
|
|
70
|
+
if not isinstance(S, np.ndarray):
|
|
71
|
+
S = np.asarray(S, dtype=np.float64).ravel()
|
|
72
|
+
n_samples = S.size
|
|
73
|
+
|
|
74
|
+
if n_samples < 8:
|
|
75
|
+
raise ValueError("LMD requires signal length ≥ 8 (Smith 2005 standard)")
|
|
76
|
+
|
|
77
|
+
t = np.arange(n_samples, dtype=np.float64)
|
|
78
|
+
max_pf = int(np.log2(n_samples)) if max_pf is None else max_pf
|
|
79
|
+
residue = S.copy()
|
|
80
|
+
PFs: list[np.ndarray] = []
|
|
81
|
+
|
|
82
|
+
if max_pf != -1:
|
|
83
|
+
for _ in range(max_pf):
|
|
84
|
+
h = residue.copy()
|
|
85
|
+
a_total = np.ones(n_samples, dtype=np.float64)
|
|
86
|
+
converged = False
|
|
87
|
+
|
|
88
|
+
for __ in range(max_iter):
|
|
89
|
+
max_loc = argrelextrema(h, np.greater)[0]
|
|
90
|
+
min_loc = argrelextrema(h, np.less)[0]
|
|
91
|
+
ext_idx = np.unique(np.concatenate([max_loc, min_loc]))
|
|
92
|
+
|
|
93
|
+
if len(ext_idx) < 3:
|
|
94
|
+
break
|
|
95
|
+
|
|
96
|
+
ext_idx, ext_vals = _mirror_extend_real(h, ext_idx, n_samples)
|
|
97
|
+
ext_idx = np.sort(ext_idx)
|
|
98
|
+
|
|
99
|
+
t_mid = (ext_idx[:-1] + ext_idx[1:]) / 2.0
|
|
100
|
+
m_vals = (ext_vals[:-1] + ext_vals[1:]) / 2.0
|
|
101
|
+
a_vals = np.abs(ext_vals[:-1] - ext_vals[1:]) / 2.0
|
|
102
|
+
|
|
103
|
+
m_t = _safe_interpolate(t_mid, m_vals, t)
|
|
104
|
+
a_t = _safe_interpolate(t_mid, a_vals, t)
|
|
105
|
+
|
|
106
|
+
a_t = np.clip(a_t, min_amp, max_amp)
|
|
107
|
+
a_t = savgol_filter(a_t, smooth_window, 2)
|
|
108
|
+
|
|
109
|
+
if _check_convergence(m_t, a_t, eps, converge_mean):
|
|
110
|
+
converged = True
|
|
111
|
+
break
|
|
112
|
+
|
|
113
|
+
s_new = (h - m_t) / a_t
|
|
114
|
+
a_total = np.clip(a_total * a_t, min_amp, max_amp)
|
|
115
|
+
h = s_new
|
|
116
|
+
|
|
117
|
+
if not converged:
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
current_pf = np.clip(a_total * s_new, -max_amp, max_amp)
|
|
121
|
+
|
|
122
|
+
if np.any(np.isnan(current_pf)) or np.any(np.isinf(current_pf)):
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
if np.sum(current_pf ** 2) < eps_stable:
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
PFs.append(current_pf)
|
|
129
|
+
residue -= current_pf
|
|
130
|
+
|
|
131
|
+
if (
|
|
132
|
+
is_monotonic(residue) or
|
|
133
|
+
np.sum(residue ** 2) < eps_stable or
|
|
134
|
+
len(argrelextrema(residue, np.greater)[0]) + len(argrelextrema(residue, np.less)[0]) <= 2
|
|
135
|
+
):
|
|
136
|
+
break
|
|
137
|
+
|
|
138
|
+
else:
|
|
139
|
+
while True:
|
|
140
|
+
h = residue.copy()
|
|
141
|
+
a_total = np.ones(n_samples, dtype=np.float64)
|
|
142
|
+
converged = False
|
|
143
|
+
|
|
144
|
+
for __ in range(max_iter):
|
|
145
|
+
max_loc = argrelextrema(h, np.greater)[0]
|
|
146
|
+
min_loc = argrelextrema(h, np.less)[0]
|
|
147
|
+
ext_idx = np.unique(np.concatenate([max_loc, min_loc]))
|
|
148
|
+
|
|
149
|
+
if len(ext_idx) < 3:
|
|
150
|
+
break
|
|
151
|
+
|
|
152
|
+
ext_idx, ext_vals = _mirror_extend_real(h, ext_idx, n_samples)
|
|
153
|
+
ext_idx = np.sort(ext_idx)
|
|
154
|
+
|
|
155
|
+
t_mid = (ext_idx[:-1] + ext_idx[1:]) / 2.0
|
|
156
|
+
m_vals = (ext_vals[:-1] + ext_vals[1:]) / 2.0
|
|
157
|
+
a_vals = np.abs(ext_vals[:-1] - ext_vals[1:]) / 2.0
|
|
158
|
+
|
|
159
|
+
m_t = _safe_interpolate(t_mid, m_vals, t)
|
|
160
|
+
a_t = _safe_interpolate(t_mid, a_vals, t)
|
|
161
|
+
|
|
162
|
+
a_t = np.clip(a_t, min_amp, max_amp)
|
|
163
|
+
a_t = savgol_filter(a_t, smooth_window, 2)
|
|
164
|
+
|
|
165
|
+
if _check_convergence(m_t, a_t, eps, converge_mean):
|
|
166
|
+
converged = True
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
s_new = (h - m_t) / a_t
|
|
170
|
+
a_total = np.clip(a_total * a_t, min_amp, max_amp)
|
|
171
|
+
h = s_new
|
|
172
|
+
|
|
173
|
+
if not converged:
|
|
174
|
+
break
|
|
175
|
+
|
|
176
|
+
current_pf = np.clip(a_total * s_new, -max_amp, max_amp)
|
|
177
|
+
|
|
178
|
+
if np.any(np.isnan(current_pf)) or np.any(np.isinf(current_pf)):
|
|
179
|
+
break
|
|
180
|
+
|
|
181
|
+
if np.sum(current_pf ** 2) < eps_stable:
|
|
182
|
+
break
|
|
183
|
+
|
|
184
|
+
PFs.append(current_pf)
|
|
185
|
+
residue -= current_pf
|
|
186
|
+
|
|
187
|
+
if (is_increasing(residue) or is_increasing(-residue) or
|
|
188
|
+
np.sum(residue ** 2) < eps_stable or
|
|
189
|
+
len(argrelextrema(residue, np.greater)[0]) + len(argrelextrema(residue, np.less)[0]) <= 2):
|
|
190
|
+
break
|
|
191
|
+
|
|
192
|
+
del h, a_total, t
|
|
193
|
+
return np.array(PFs, dtype=np.float64), residue
|
|
194
|
+
|
|
195
|
+
def _mirror_extend_real(signal: np.ndarray, ext_idx: np.ndarray, n_samples: int) -> Tuple[np.ndarray, np.ndarray]:
|
|
196
|
+
ext = ext_idx.copy()
|
|
197
|
+
vals = signal[ext].copy()
|
|
198
|
+
last_idx = n_samples - 1
|
|
199
|
+
|
|
200
|
+
if ext[0] > 0:
|
|
201
|
+
mirror_pos = 0
|
|
202
|
+
mirror_val = 2 * signal[0] - vals[0]
|
|
203
|
+
ext = np.insert(ext, 0, mirror_pos)
|
|
204
|
+
vals = np.insert(vals, 0, mirror_val)
|
|
205
|
+
|
|
206
|
+
if ext[-1] < last_idx:
|
|
207
|
+
mirror_pos = last_idx
|
|
208
|
+
mirror_val = 2 * signal[-1] - vals[-1]
|
|
209
|
+
ext = np.append(ext, mirror_pos)
|
|
210
|
+
vals = np.append(vals, mirror_val)
|
|
211
|
+
|
|
212
|
+
return ext, vals
|
|
213
|
+
|
|
214
|
+
def _safe_interpolate(x: np.ndarray, y: np.ndarray, x_new: np.ndarray) -> np.ndarray:
|
|
215
|
+
from scipy import interpolate
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
interp = interpolate.CubicSpline(x, y, bc_type="natural")
|
|
219
|
+
res = interp(x_new)
|
|
220
|
+
except:
|
|
221
|
+
res = np.interp(x_new, x, y)
|
|
222
|
+
|
|
223
|
+
left_mask = x_new < x[0]
|
|
224
|
+
right_mask = x_new > x[-1]
|
|
225
|
+
if np.any(left_mask):
|
|
226
|
+
slope = (y[1] - y[0]) / (x[1] - x[0])
|
|
227
|
+
res[left_mask] = y[0] + slope * (x_new[left_mask] - x[0])
|
|
228
|
+
if np.any(right_mask):
|
|
229
|
+
slope = (y[-1] - y[-2]) / (x[-1] - x[-2])
|
|
230
|
+
res[right_mask] = y[-1] + slope * (x_new[right_mask] - x[-1])
|
|
231
|
+
|
|
232
|
+
return res
|
|
233
|
+
|
|
234
|
+
def _check_convergence(m_t: np.ndarray, a_t: np.ndarray, eps: float, converge_mean) -> bool:
|
|
235
|
+
mean_ok = np.max(np.abs(m_t)) < converge_mean
|
|
236
|
+
envelope_ok = np.max(np.abs(a_t - 1.0)) < eps
|
|
237
|
+
return mean_ok and envelope_ok
|
|
238
|
+
|
|
239
|
+
def compute_envelope(signal: Union[list, np.ndarray]) -> np.ndarray:
|
|
240
|
+
from scipy.linalg import hilbert
|
|
241
|
+
|
|
242
|
+
signal = np.asarray(signal, dtype=np.float64).ravel()
|
|
243
|
+
return np.abs(hilbert(signal))
|
|
@@ -9,20 +9,21 @@ Lib and Version: (if None write None)
|
|
|
9
9
|
Only accessed by: (must)
|
|
10
10
|
Only __init__.py
|
|
11
11
|
|
|
12
|
-
Modify: (must)
|
|
13
|
-
2026.3.25
|
|
14
|
-
|
|
15
12
|
Description: (if None write None)
|
|
16
13
|
Realize the MEMD
|
|
14
|
+
|
|
15
|
+
Modify: (must)
|
|
16
|
+
2026.3.25 - Create.
|
|
17
|
+
2026.5.1 - Fix the problem when calculating projections.
|
|
17
18
|
"""
|
|
18
19
|
|
|
19
20
|
import numpy as np
|
|
20
21
|
from typing import Union, Tuple
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def memd(S: Union[list, np.ndarray], d=None, k=None, max_imf=None, sd_thresh=0.2, max_iter=10) -> Tuple[np.ndarray, np.ndarray]:
|
|
24
|
+
def memd(S: Union[list, np.ndarray], d=None, k=None, max_imf=None, sd_thresh=0.2, max_iter=10, spline_kind: str="linear") -> Tuple[np.ndarray, np.ndarray]:
|
|
24
25
|
"""
|
|
25
|
-
MEMD: Multimodal
|
|
26
|
+
MEMD: Multimodal Empirical Mode Decomposition
|
|
26
27
|
|
|
27
28
|
:param S: Signal (2-dim), (d, N) | d -> channels,N -> time points
|
|
28
29
|
:param d: channels or dimensions
|
|
@@ -30,7 +31,8 @@ def memd(S: Union[list, np.ndarray], d=None, k=None, max_imf=None, sd_thresh=0.2
|
|
|
30
31
|
:param max_imf: max num of IMFs
|
|
31
32
|
:param sd_thresh: therahold
|
|
32
33
|
:param max_iter: max iterations of each IMF
|
|
33
|
-
:
|
|
34
|
+
:param spline_kind: spline kind.
|
|
35
|
+
:return: IMFs (IMFs_num, d, N), Res (2-dim)
|
|
34
36
|
"""
|
|
35
37
|
|
|
36
38
|
if not isinstance(S, np.ndarray):
|
|
@@ -56,7 +58,7 @@ def memd(S: Union[list, np.ndarray], d=None, k=None, max_imf=None, sd_thresh=0.2
|
|
|
56
58
|
|
|
57
59
|
vectors = generate_hammersley_points(k, d) # dhape: (d, k)
|
|
58
60
|
|
|
59
|
-
projections = np.dot(S.T, vectors) # shape: (N, k)
|
|
61
|
+
# projections = np.dot(S.T, vectors) # shape: (N, k)
|
|
60
62
|
|
|
61
63
|
imfs = []
|
|
62
64
|
residue = S.copy()
|
|
@@ -66,7 +68,7 @@ def memd(S: Union[list, np.ndarray], d=None, k=None, max_imf=None, sd_thresh=0.2
|
|
|
66
68
|
|
|
67
69
|
for iter_num in range(max_iter):
|
|
68
70
|
h_old = h
|
|
69
|
-
mean_envelope = compute_local_mean(h, vectors,
|
|
71
|
+
mean_envelope = compute_local_mean(h, vectors, T, spline_kind=spline_kind)
|
|
70
72
|
|
|
71
73
|
h_new = h - mean_envelope
|
|
72
74
|
sd = np.sum((h_old - h_new) ** 2) / np.sum(h_old ** 2)
|
|
@@ -153,7 +155,7 @@ def generate_primes(n):
|
|
|
153
155
|
return primes
|
|
154
156
|
|
|
155
157
|
|
|
156
|
-
def compute_local_mean(signal, vectors, T):
|
|
158
|
+
def compute_local_mean(signal, vectors, T, spline_kind: str="linear"):
|
|
157
159
|
"""
|
|
158
160
|
S: now S (d, N)
|
|
159
161
|
vectors: directional vector (d, k)
|
|
@@ -196,7 +198,7 @@ def compute_local_mean(signal, vectors, T):
|
|
|
196
198
|
max_values = signal[ch, max_indices]
|
|
197
199
|
if len(max_indices) >= 4:
|
|
198
200
|
try:
|
|
199
|
-
max_spline = interp1d(max_indices, max_values, kind=
|
|
201
|
+
max_spline = interp1d(max_indices, max_values, kind=spline_kind,fill_value='extrapolate')
|
|
200
202
|
max_env = max_spline(T)
|
|
201
203
|
except:
|
|
202
204
|
max_env = np.interp(T, max_indices, max_values)
|
|
@@ -206,7 +208,7 @@ def compute_local_mean(signal, vectors, T):
|
|
|
206
208
|
min_values = signal[ch, min_indices]
|
|
207
209
|
if len(min_indices) >= 4:
|
|
208
210
|
try:
|
|
209
|
-
min_spline = interp1d(min_indices, min_values, kind=
|
|
211
|
+
min_spline = interp1d(min_indices, min_values, kind=spline_kind,fill_value='extrapolate')
|
|
210
212
|
min_env = min_spline(T)
|
|
211
213
|
except:
|
|
212
214
|
min_env = np.interp(T, min_indices, min_values)
|
|
@@ -15,7 +15,7 @@ Description: (if None write None)
|
|
|
15
15
|
|
|
16
16
|
Modify: (must)
|
|
17
17
|
2026.3.25 - Create.
|
|
18
|
-
2026.3.29 - Optimize the SSA.decompose function, it's
|
|
18
|
+
2026.3.29 - Optimize the SSA.decompose function, it's use_JIT now. Please use SSA() which means SSA.decompose_fast().
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
@@ -165,7 +165,7 @@ class SSA:
|
|
|
165
165
|
:param S: Signal (1-dim)
|
|
166
166
|
:param L:
|
|
167
167
|
:param groups: group information, such as: [[0], [1,2], [3,4]] means which components will be merged. If None, return all
|
|
168
|
-
:param faster: if you choose True, function will be
|
|
168
|
+
:param faster: if you choose True, function will be use_JIT with wasting memory.
|
|
169
169
|
:return: IMFs (2-dim)
|
|
170
170
|
"""
|
|
171
171
|
|
|
@@ -15,6 +15,7 @@ Description: (if None write None)
|
|
|
15
15
|
Modify: (must)
|
|
16
16
|
2026.3.25 - Create.
|
|
17
17
|
2026.4.3 - Finish the Optimization of the SVMD. Give two kind of SVMD.
|
|
18
|
+
2026.5.1 - The decomposition with JIT is Error.
|
|
18
19
|
"""
|
|
19
20
|
|
|
20
21
|
import numpy as np
|
|
@@ -134,6 +135,9 @@ class SVMD:
|
|
|
134
135
|
return modes, residual
|
|
135
136
|
|
|
136
137
|
def give_svmd_JIT():
|
|
138
|
+
from .Error.RealizationError import RealizationError
|
|
139
|
+
raise RealizationError("this method' realization is error.")
|
|
140
|
+
|
|
137
141
|
from scipy.fft import fft, ifft, fftfreq
|
|
138
142
|
from numba import jit, prange, complex128, float64
|
|
139
143
|
import numba as nb
|
|
@@ -204,7 +208,7 @@ def give_svmd_JIT():
|
|
|
204
208
|
for n in range(N):
|
|
205
209
|
re = np.real(sum_modes_hat[n]) - prev_recon[n]
|
|
206
210
|
recon_error += re * re
|
|
207
|
-
sig_norm += signal_hat
|
|
211
|
+
sig_norm += np.sum(np.abs(signal_hat)**2) / N
|
|
208
212
|
|
|
209
213
|
if it > 1 and np.sqrt(recon_error) / (np.sqrt(sig_norm) + eps) < tol:
|
|
210
214
|
break
|
|
@@ -225,6 +229,7 @@ def give_svmd_JIT():
|
|
|
225
229
|
residual[n] = np.real(signal_hat[n]) - recon_val
|
|
226
230
|
|
|
227
231
|
return modes, residual
|
|
232
|
+
|
|
228
233
|
class NumbaSVMD(SVMD):
|
|
229
234
|
|
|
230
235
|
def decompose(self, signal: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
|
|
@@ -254,7 +259,7 @@ def give_svmd_JIT():
|
|
|
254
259
|
def svmd \
|
|
255
260
|
(
|
|
256
261
|
S: Union[list, np.ndarray],
|
|
257
|
-
|
|
262
|
+
use_JIT: bool = False,
|
|
258
263
|
num_modes: int = 3,
|
|
259
264
|
alpha: float = 2000,
|
|
260
265
|
tau: float = 0.0,
|
|
@@ -264,7 +269,7 @@ def svmd \
|
|
|
264
269
|
"""
|
|
265
270
|
|
|
266
271
|
:param S: Signal (N,)
|
|
267
|
-
:param
|
|
272
|
+
:param use_JIT: if True, use Numba version.
|
|
268
273
|
:param num_modes: the num of modes
|
|
269
274
|
:param alpha:
|
|
270
275
|
:param tau:
|
|
@@ -273,7 +278,7 @@ def svmd \
|
|
|
273
278
|
:return: IMFs(num_modes, N), Res(N,)
|
|
274
279
|
"""
|
|
275
280
|
|
|
276
|
-
if not
|
|
281
|
+
if not use_JIT:
|
|
277
282
|
Cls = SVMD(num_modes=num_modes, alpha=alpha, tau=tau, tol=tol, max_iter=max_iter)
|
|
278
283
|
IMFs, Res = Cls(S)
|
|
279
284
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Modal Decomposition:
|
|
3
|
-
LMD
|
|
3
|
+
LMD, CEEMDAN, EFD, CEEFD, VMD, EEMD, FMD, EWT, SSA, RPSEMD, CEEMD, MEMD, ICEEMDAN, EMD
|
|
4
4
|
|
|
5
5
|
GitHub url: https://github.com/a-raining-day/Modal-Decomposition
|
|
6
6
|
|
|
@@ -17,9 +17,6 @@ Lib and Version: (if None write None)
|
|
|
17
17
|
Only accessed by: (must)
|
|
18
18
|
All
|
|
19
19
|
|
|
20
|
-
Modify: (must)
|
|
21
|
-
2026.3.25
|
|
22
|
-
|
|
23
20
|
Description: (if None write None)
|
|
24
21
|
As the entrance of the lib
|
|
25
22
|
|
|
@@ -43,12 +40,14 @@ Modify:
|
|
|
43
40
|
2026.4.3 - Finish the Optimization of the modal decomposition method. Except the MEMD method.
|
|
44
41
|
2026.4.4 - Add the parameter to describe lib.
|
|
45
42
|
2026.4.6 - Change the position of the entrance of importing 'threading'. Try to reduce the cost of the import.
|
|
43
|
+
2026.4.9 - Fix the import error of Class.VMD. From "vmdpy.EWT1D" to "vmdpy.VMD".
|
|
44
|
+
2026.5.1 - Delete the "help_function.py". Stop use decomposition with JIT in "SVMD.py". EEMD use PyEMD now. Fix the MEMD.
|
|
46
45
|
"""
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
__version__ = "0.1.
|
|
48
|
+
__version__ = "0.1.3"
|
|
50
49
|
__author__ = "a-raining-day(Mao)"
|
|
51
|
-
__email__ = "
|
|
50
|
+
__email__ = "2215269365@qq.com"
|
|
52
51
|
__license__ = "Apache 2.0"
|
|
53
52
|
__url__ = "https://github.com/a-raining-day/Modal-Decomposition"
|
|
54
53
|
__description__ = "A comprehensive modal decomposition library"
|
|
@@ -72,11 +71,6 @@ from .SSA import SSA, ssa
|
|
|
72
71
|
from .SVMD import svmd
|
|
73
72
|
from .VMD import vmd
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
import warnings
|
|
77
|
-
warnings.warn("The MEMD is rebuilding...")
|
|
78
|
-
|
|
79
|
-
|
|
80
74
|
__all__ = \
|
|
81
75
|
[
|
|
82
76
|
"Function", "Class",
|
|
@@ -129,7 +123,7 @@ class Class:
|
|
|
129
123
|
def VMD(cls, **kwargs):
|
|
130
124
|
if "EWT1D" not in cls.__cache:
|
|
131
125
|
try:
|
|
132
|
-
Module = import_module("vmdpy").
|
|
126
|
+
Module = import_module("vmdpy").VMD
|
|
133
127
|
cls.__cache["VMD"] = Module
|
|
134
128
|
return Module(**kwargs)
|
|
135
129
|
except ImportError:
|
|
@@ -139,9 +133,8 @@ class Class:
|
|
|
139
133
|
return cls.__cache["VMD"](**kwargs)
|
|
140
134
|
|
|
141
135
|
class Function:
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
# CEEFD = ceefd_real_cls.ceefd
|
|
136
|
+
""" function | default function for modal decomposition
|
|
137
|
+
the IMFs (2-dim) means: (K, len(Signal)) (K is the num of IMFs)"""
|
|
145
138
|
|
|
146
139
|
CEEFD = Class.CEEFD(fs=1.0, min_peak_distance=10, envelop_iter=3)
|
|
147
140
|
CEEMD = ceemd
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Modal-Decomposition
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: a package for modal decomposition
|
|
5
5
|
Author-email: Mao_HaoChuan <2215269365@qq.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -55,7 +55,7 @@ All entrance of functions or class are stored in `Modal_Decomposition/__init__.p
|
|
|
55
55
|
| 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
56
|
| 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
57
|
| EWT | Empirical Wavelet Transform | `Function.EWT(signal)` | [10.48550/arXiv.2304.06274](https://arxiv.org/abs/2304.06274) |
|
|
58
|
-
| FMD | Filtered Mode Decomposition | `Function.
|
|
58
|
+
| FMD | Filtered Mode Decomposition | `Function.FMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
|
|
59
59
|
| 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
60
|
| LMD | Local Mean Decomposition | `Function.LMD(signal)` | [10.1098/rsif.2005.0058](https://royalsocietypublishing.org/doi/10.1098/rsif.2005.0058) |
|
|
61
61
|
| MEMD | Multivariate Empirical Mode Decomposition | `Function.MEMD(signal)` | [10.48550/arXiv.2206.00926](https://arxiv.org/abs/2206.00926) |
|
|
@@ -79,42 +79,18 @@ pip install -r requirements.txt
|
|
|
79
79
|
pip install Modal-Decomposition
|
|
80
80
|
```
|
|
81
81
|
|
|
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
82
|
## Dependence
|
|
87
83
|
|
|
88
84
|
This lib's dependence are:
|
|
89
85
|
|
|
90
86
|
***Python: 3.10***
|
|
91
87
|
|
|
92
|
-
- [antropy](https://github.com/raphaelvallat/antropy)
|
|
93
|
-
- [colorama](https://github.com/tartley/colorama)
|
|
94
|
-
- [einops](https://github.com/arogozhnikov/einops)
|
|
95
88
|
- [EMD-signal](https://github.com/laszukdawid/PyEMD)
|
|
96
89
|
- [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
90
|
- [vmdpy](https://github.com/vrcarva/vmdpy)
|
|
101
|
-
- [psutil](https://github.com/giampaolo/psutil)
|
|
102
91
|
|
|
103
92
|
*Other dependence please read "requirements.txt"*
|
|
104
93
|
|
|
105
|
-
## Codes Resource
|
|
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
|
-
|
|
118
94
|
## Url
|
|
119
95
|
|
|
120
96
|
This lib's url is: https://github.com/a-raining-day/Modal-Decomposition
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition.egg-info/SOURCES.txt
RENAMED
|
@@ -17,7 +17,6 @@ src/Modal_Decomposition/SSA.py
|
|
|
17
17
|
src/Modal_Decomposition/SVMD.py
|
|
18
18
|
src/Modal_Decomposition/VMD.py
|
|
19
19
|
src/Modal_Decomposition/__init__.py
|
|
20
|
-
src/Modal_Decomposition/help_function.py
|
|
21
20
|
src/Modal_Decomposition.egg-info/PKG-INFO
|
|
22
21
|
src/Modal_Decomposition.egg-info/SOURCES.txt
|
|
23
22
|
src/Modal_Decomposition.egg-info/dependency_links.txt
|
|
@@ -27,6 +26,7 @@ src/Modal_Decomposition/COLOR/__init__.py
|
|
|
27
26
|
src/Modal_Decomposition/COLOR/color_define.py
|
|
28
27
|
src/Modal_Decomposition/COLOR/colorful_print.py
|
|
29
28
|
src/Modal_Decomposition/Error/CycleError.py
|
|
29
|
+
src/Modal_Decomposition/Error/RealizationError.py
|
|
30
30
|
src/Modal_Decomposition/Utils/EnvironmentMemory.py
|
|
31
31
|
src/Modal_Decomposition/Utils/LazyImport.py
|
|
32
32
|
src/Modal_Decomposition/Utils/Monotonicity.py
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Python version: (must)
|
|
3
|
-
3.10.11
|
|
4
|
-
|
|
5
|
-
Lib and Version: (if None write None)
|
|
6
|
-
EMD-S - 1.9.0
|
|
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
|
-
"""
|
|
19
|
-
|
|
20
|
-
import numpy as np
|
|
21
|
-
from typing import Union, Tuple, Optional
|
|
22
|
-
from .Utils import monotonic_increasing, monotonic_decreasing
|
|
23
|
-
from .Error import CycleError
|
|
24
|
-
from time import sleep
|
|
25
|
-
from warnings import warn
|
|
26
|
-
from .EMD import emd
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def eemd(S: Union[list, np.ndarray], T: Union[list, np.ndarray]=None, N_whitenoise=300, beta=0.3, max_imf: Optional[int]=None, dead_line: int=10, verbose: bool=False) \
|
|
30
|
-
-> Tuple[np.ndarray, np.ndarray]:
|
|
31
|
-
"""
|
|
32
|
-
EEMD: 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,)
|
|
42
|
-
"""
|
|
43
|
-
if beta <= 0:
|
|
44
|
-
raise ValueError("The beta should > 0")
|
|
45
|
-
|
|
46
|
-
if N_whitenoise <= 0 or not isinstance(N_whitenoise, int):
|
|
47
|
-
raise TypeError("N_whitenoise must be int type or > 0")
|
|
48
|
-
|
|
49
|
-
if not isinstance(S, np.ndarray):
|
|
50
|
-
S = np.array(S)
|
|
51
|
-
|
|
52
|
-
if S.ndim == 0:
|
|
53
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
54
|
-
|
|
55
|
-
elif S.ndim > 1:
|
|
56
|
-
if 1 in S.shape:
|
|
57
|
-
S = S.reshape(-1)
|
|
58
|
-
|
|
59
|
-
else:
|
|
60
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
61
|
-
|
|
62
|
-
N = len(S)
|
|
63
|
-
|
|
64
|
-
if T is None: # if T is None, default generate uniform T-axis.
|
|
65
|
-
T = np.arange(N) # default fs = 1
|
|
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) != len(S):
|
|
73
|
-
raise ValueError("The length of T must be equal to Signal.")
|
|
74
|
-
|
|
75
|
-
if not np.all(np.diff(T) > 0):
|
|
76
|
-
raise ValueError("T should be monotonic increasing!")
|
|
77
|
-
|
|
78
|
-
if np.any(np.allclose(np.diff(np.diff(T)))):
|
|
79
|
-
warn("The T is not uniform! Some error may happen.")
|
|
80
|
-
|
|
81
|
-
if max_imf is None:
|
|
82
|
-
max_imf = int(np.log2(len(S))) + 2
|
|
83
|
-
|
|
84
|
-
Res = S
|
|
85
|
-
IMFs = []
|
|
86
|
-
|
|
87
|
-
# std_dev = np.std(S)
|
|
88
|
-
|
|
89
|
-
count = 0
|
|
90
|
-
dead_cycle = 0
|
|
91
|
-
while True:
|
|
92
|
-
std_dev = np.std(Res)
|
|
93
|
-
|
|
94
|
-
_IMFs = []
|
|
95
|
-
for n in range(N_whitenoise):
|
|
96
|
-
white_noise = np.random.normal(0, std_dev * beta, N)
|
|
97
|
-
_S = Res + white_noise
|
|
98
|
-
_IMFs_, _ = emd(_S, T, max_imf=1)
|
|
99
|
-
if not _IMFs_:
|
|
100
|
-
continue
|
|
101
|
-
_IMFs.append(_IMFs_[0])
|
|
102
|
-
|
|
103
|
-
if not _IMFs:
|
|
104
|
-
dead_cycle += 1
|
|
105
|
-
continue
|
|
106
|
-
|
|
107
|
-
if dead_cycle >= dead_line:
|
|
108
|
-
raise RuntimeError("Trapped in a vicious cycle")
|
|
109
|
-
else:
|
|
110
|
-
dead_cycle = 0
|
|
111
|
-
|
|
112
|
-
IMF = np.mean(_IMFs, axis=0)
|
|
113
|
-
|
|
114
|
-
IMFs.append(IMF)
|
|
115
|
-
|
|
116
|
-
Res -= IMF
|
|
117
|
-
count += 1
|
|
118
|
-
|
|
119
|
-
if verbose:
|
|
120
|
-
if count % 10 == 0:
|
|
121
|
-
print(f"has get {count} IMFs...")
|
|
122
|
-
sleep(1)
|
|
123
|
-
|
|
124
|
-
if max_imf != -1:
|
|
125
|
-
if count >= max_imf or monotonic_increasing(Res) or monotonic_decreasing(Res):
|
|
126
|
-
return np.array(IMFs), np.array(Res)
|
|
127
|
-
|
|
128
|
-
else:
|
|
129
|
-
if monotonic_increasing(Res) or monotonic_decreasing(Res):
|
|
130
|
-
return np.array(IMFs), np.array(Res)
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Python version: (must)
|
|
3
|
-
3.10.11
|
|
4
|
-
|
|
5
|
-
Lib and Version: (if None write None)
|
|
6
|
-
numpy - 2.2.6
|
|
7
|
-
scipy - 1.15.3
|
|
8
|
-
|
|
9
|
-
Only accessed by: (must)
|
|
10
|
-
Only __init__.py
|
|
11
|
-
|
|
12
|
-
Modify: (must)
|
|
13
|
-
2026.3.25
|
|
14
|
-
|
|
15
|
-
Description: (if None write None)
|
|
16
|
-
Realize the LMD
|
|
17
|
-
|
|
18
|
-
Modify:
|
|
19
|
-
2026.3.25 - Optimize the use of scipy
|
|
20
|
-
2026.4.3 - Finish the Optimization of the LMD.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
import numpy as np
|
|
24
|
-
from .help_function import is_increasing
|
|
25
|
-
from typing import Union, Tuple
|
|
26
|
-
|
|
27
|
-
EPS_STABLE = 1e-12
|
|
28
|
-
MIN_AMP = 1e-12
|
|
29
|
-
MAX_AMP = 1e12
|
|
30
|
-
CONVERGE_MEAN = 1e-3
|
|
31
|
-
SMOOTH_WINDOW = 5
|
|
32
|
-
|
|
33
|
-
def lmd(
|
|
34
|
-
S: Union[list, np.ndarray],
|
|
35
|
-
max_pf: int | None = None,
|
|
36
|
-
max_iter: int = 37,
|
|
37
|
-
eps: float = 0.05
|
|
38
|
-
) -> Tuple[np.ndarray, np.ndarray]:
|
|
39
|
-
"""
|
|
40
|
-
LMD: Local mean decomposition
|
|
41
|
-
|
|
42
|
-
:param S: Signal (1-dim)
|
|
43
|
-
:param max_pf: the max num of the PFs. Default log2(N)
|
|
44
|
-
:param max_iter: max iteration for each iter of decomposing the PFs. Default 37, according the paper.
|
|
45
|
-
:param eps: Envelope convergence threshold
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
PFs: (n_pf, N), Res: (N,)
|
|
49
|
-
"""
|
|
50
|
-
from scipy.signal import argrelextrema, hilbert, savgol_filter
|
|
51
|
-
|
|
52
|
-
if S.ndim == 0:
|
|
53
|
-
raise ValueError("The dim of the S must be 1-dim, not 0")
|
|
54
|
-
|
|
55
|
-
elif S.ndim > 1:
|
|
56
|
-
if 1 in S.shape:
|
|
57
|
-
S = S.reshape(-1)
|
|
58
|
-
|
|
59
|
-
else:
|
|
60
|
-
raise ValueError(f"The dim of S must be 1-dim, not {S.ndim}")
|
|
61
|
-
|
|
62
|
-
if not isinstance(S, np.ndarray):
|
|
63
|
-
S = np.asarray(S, dtype=np.float64).ravel()
|
|
64
|
-
n_samples = S.size
|
|
65
|
-
|
|
66
|
-
if n_samples < 8:
|
|
67
|
-
raise ValueError("LMD requires signal length ≥ 8 (Smith 2005 standard)")
|
|
68
|
-
|
|
69
|
-
t = np.arange(n_samples, dtype=np.float64)
|
|
70
|
-
max_pf = int(np.log2(n_samples)) if max_pf is None else max_pf
|
|
71
|
-
residue = S.copy()
|
|
72
|
-
PFs: list[np.ndarray] = []
|
|
73
|
-
|
|
74
|
-
for _ in range(max_pf):
|
|
75
|
-
h = residue.copy()
|
|
76
|
-
a_total = np.ones(n_samples, dtype=np.float64)
|
|
77
|
-
converged = False
|
|
78
|
-
|
|
79
|
-
for __ in range(max_iter):
|
|
80
|
-
max_loc = argrelextrema(h, np.greater)[0]
|
|
81
|
-
min_loc = argrelextrema(h, np.less)[0]
|
|
82
|
-
ext_idx = np.unique(np.concatenate([max_loc, min_loc]))
|
|
83
|
-
|
|
84
|
-
if len(ext_idx) < 3:
|
|
85
|
-
break
|
|
86
|
-
|
|
87
|
-
ext_idx, ext_vals = _mirror_extend_real(h, ext_idx, n_samples)
|
|
88
|
-
ext_idx = np.sort(ext_idx)
|
|
89
|
-
|
|
90
|
-
t_mid = (ext_idx[:-1] + ext_idx[1:]) / 2.0
|
|
91
|
-
m_vals = (ext_vals[:-1] + ext_vals[1:]) / 2.0
|
|
92
|
-
a_vals = np.abs(ext_vals[:-1] - ext_vals[1:]) / 2.0
|
|
93
|
-
|
|
94
|
-
m_t = _safe_interpolate(t_mid, m_vals, t)
|
|
95
|
-
a_t = _safe_interpolate(t_mid, a_vals, t)
|
|
96
|
-
|
|
97
|
-
a_t = np.clip(a_t, MIN_AMP, MAX_AMP)
|
|
98
|
-
a_t = savgol_filter(a_t, SMOOTH_WINDOW, 2)
|
|
99
|
-
|
|
100
|
-
if _check_convergence(m_t, a_t, eps):
|
|
101
|
-
converged = True
|
|
102
|
-
break
|
|
103
|
-
|
|
104
|
-
s_new = (h - m_t) / a_t
|
|
105
|
-
a_total = np.clip(a_total * a_t, MIN_AMP, MAX_AMP)
|
|
106
|
-
h = s_new
|
|
107
|
-
|
|
108
|
-
if not converged:
|
|
109
|
-
break
|
|
110
|
-
|
|
111
|
-
current_pf = np.clip(a_total * s_new, -MAX_AMP, MAX_AMP)
|
|
112
|
-
|
|
113
|
-
if np.any(np.isnan(current_pf)) or np.any(np.isinf(current_pf)):
|
|
114
|
-
break
|
|
115
|
-
|
|
116
|
-
if np.sum(current_pf ** 2) < EPS_STABLE:
|
|
117
|
-
break
|
|
118
|
-
|
|
119
|
-
PFs.append(current_pf)
|
|
120
|
-
residue -= current_pf
|
|
121
|
-
|
|
122
|
-
if (is_increasing(residue) or is_increasing(-residue) or
|
|
123
|
-
np.sum(residue ** 2) < EPS_STABLE or
|
|
124
|
-
len(argrelextrema(residue, np.greater)[0]) + len(argrelextrema(residue, np.less)[0]) <= 2):
|
|
125
|
-
break
|
|
126
|
-
|
|
127
|
-
del h, a_total, t
|
|
128
|
-
return np.array(PFs, dtype=np.float64), residue
|
|
129
|
-
|
|
130
|
-
def _mirror_extend_real(signal: np.ndarray, ext_idx: np.ndarray, n_samples: int) -> Tuple[np.ndarray, np.ndarray]:
|
|
131
|
-
ext = ext_idx.copy()
|
|
132
|
-
vals = signal[ext].copy()
|
|
133
|
-
last_idx = n_samples - 1
|
|
134
|
-
|
|
135
|
-
if ext[0] > 0:
|
|
136
|
-
mirror_pos = 0
|
|
137
|
-
mirror_val = 2 * signal[0] - vals[0]
|
|
138
|
-
ext = np.insert(ext, 0, mirror_pos)
|
|
139
|
-
vals = np.insert(vals, 0, mirror_val)
|
|
140
|
-
|
|
141
|
-
if ext[-1] < last_idx:
|
|
142
|
-
mirror_pos = last_idx
|
|
143
|
-
mirror_val = 2 * signal[-1] - vals[-1]
|
|
144
|
-
ext = np.append(ext, mirror_pos)
|
|
145
|
-
vals = np.append(vals, mirror_val)
|
|
146
|
-
|
|
147
|
-
return ext, vals
|
|
148
|
-
|
|
149
|
-
def _safe_interpolate(x: np.ndarray, y: np.ndarray, x_new: np.ndarray) -> np.ndarray:
|
|
150
|
-
from scipy import interpolate
|
|
151
|
-
|
|
152
|
-
try:
|
|
153
|
-
interp = interpolate.CubicSpline(x, y, bc_type="natural")
|
|
154
|
-
res = interp(x_new)
|
|
155
|
-
except:
|
|
156
|
-
res = np.interp(x_new, x, y)
|
|
157
|
-
|
|
158
|
-
left_mask = x_new < x[0]
|
|
159
|
-
right_mask = x_new > x[-1]
|
|
160
|
-
if np.any(left_mask):
|
|
161
|
-
slope = (y[1] - y[0]) / (x[1] - x[0])
|
|
162
|
-
res[left_mask] = y[0] + slope * (x_new[left_mask] - x[0])
|
|
163
|
-
if np.any(right_mask):
|
|
164
|
-
slope = (y[-1] - y[-2]) / (x[-1] - x[-2])
|
|
165
|
-
res[right_mask] = y[-1] + slope * (x_new[right_mask] - x[-1])
|
|
166
|
-
|
|
167
|
-
return res
|
|
168
|
-
|
|
169
|
-
def _check_convergence(m_t: np.ndarray, a_t: np.ndarray, eps: float) -> bool:
|
|
170
|
-
mean_ok = np.max(np.abs(m_t)) < CONVERGE_MEAN
|
|
171
|
-
envelope_ok = np.max(np.abs(a_t - 1.0)) < eps
|
|
172
|
-
return mean_ok and envelope_ok
|
|
173
|
-
|
|
174
|
-
def compute_envelope(signal: Union[list, np.ndarray]) -> np.ndarray:
|
|
175
|
-
from scipy.linalg import hilbert
|
|
176
|
-
|
|
177
|
-
signal = np.asarray(signal, dtype=np.float64).ravel()
|
|
178
|
-
return np.abs(hilbert(signal))
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Python version: (must)
|
|
3
|
-
3.10.11
|
|
4
|
-
|
|
5
|
-
Lib and Version: (if None write None)
|
|
6
|
-
numpy - 2.2.6
|
|
7
|
-
numba - 0.64.0
|
|
8
|
-
|
|
9
|
-
Only accessed by: (must)
|
|
10
|
-
All(for modal decomposition more)
|
|
11
|
-
|
|
12
|
-
Modify: (must)
|
|
13
|
-
2026.3.25
|
|
14
|
-
|
|
15
|
-
Description: (if None write None)
|
|
16
|
-
This file stored the helpful function which can be used in other modal decomposition methods.
|
|
17
|
-
|
|
18
|
-
Modify:
|
|
19
|
-
Optimize the use of numba, accelerate the speed of import
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
import numpy as np
|
|
23
|
-
from typing import Literal, Callable
|
|
24
|
-
|
|
25
|
-
def is_increasing_1(S) -> bool:
|
|
26
|
-
diff = np.ediff1d(S)
|
|
27
|
-
epsilon = 1e-8
|
|
28
|
-
return np.all(diff > epsilon)
|
|
29
|
-
|
|
30
|
-
def give_is_increasing_2() -> Callable:
|
|
31
|
-
from numba import njit
|
|
32
|
-
|
|
33
|
-
@njit
|
|
34
|
-
def is_increasing_2(S, rtol=1e-8, atol=1e-8):
|
|
35
|
-
for i in range(len(S)-1):
|
|
36
|
-
diff = S[i+1] - S[i]
|
|
37
|
-
if diff <= atol + rtol * abs(S[i]):
|
|
38
|
-
return False
|
|
39
|
-
return True
|
|
40
|
-
|
|
41
|
-
return is_increasing_2
|
|
42
|
-
|
|
43
|
-
def is_increasing(S, threshold=2, tolerance: Literal["high", "mid", "low"]="high") -> bool:
|
|
44
|
-
def count_extrema(x):
|
|
45
|
-
interior = x[1:-1]
|
|
46
|
-
left = x[:-2]
|
|
47
|
-
right = x[2:]
|
|
48
|
-
maxima = (interior > left) & (interior > right)
|
|
49
|
-
minima = (interior < left) & (interior < right)
|
|
50
|
-
return np.sum(maxima) + np.sum(minima)
|
|
51
|
-
|
|
52
|
-
if tolerance == "high":
|
|
53
|
-
ans_3 = count_extrema(S) <= threshold
|
|
54
|
-
return ans_3
|
|
55
|
-
|
|
56
|
-
elif tolerance == "mid":
|
|
57
|
-
diff = np.diff(S)
|
|
58
|
-
|
|
59
|
-
sign_changes = np.diff(np.sign(diff))
|
|
60
|
-
|
|
61
|
-
count = np.sum(np.abs(sign_changes) == 2)
|
|
62
|
-
|
|
63
|
-
ans_1 = count <= threshold # one way to check
|
|
64
|
-
return ans_1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/COLOR/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Error/CycleError.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/LazyImport.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/OneDimArray.py
RENAMED
|
File without changes
|
{modal_decomposition-0.1.2 → modal_decomposition-0.1.3}/src/Modal_Decomposition/Utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|