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.
Files changed (45) hide show
  1. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/PKG-INFO +29 -28
  2. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/README.md +28 -27
  3. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/pyproject.toml +1 -1
  4. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEFD.py +5 -26
  5. modal_decomposition-0.1.4/src/Modal_Decomposition/CEEMD.py +103 -0
  6. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEMDAN.py +23 -26
  7. modal_decomposition-0.1.4/src/Modal_Decomposition/EEMD.py +58 -0
  8. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EFD.py +11 -34
  9. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EMD.py +7 -28
  10. modal_decomposition-0.1.4/src/Modal_Decomposition/EWT.py +62 -0
  11. modal_decomposition-0.1.4/src/Modal_Decomposition/Error/RealizationError.py +2 -0
  12. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/FMD.py +17 -19
  13. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/ICEEMDAN.py +40 -65
  14. modal_decomposition-0.1.4/src/Modal_Decomposition/LMD.py +236 -0
  15. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/MEMD.py +27 -26
  16. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/RPSEMD.py +5 -10
  17. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SSA.py +16 -17
  18. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SVMD.py +28 -15
  19. modal_decomposition-0.1.4/src/Modal_Decomposition/Utils/Check.py +39 -0
  20. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/Monotonicity.py +16 -16
  21. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/__init__.py +1 -1
  22. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/VMD.py +16 -8
  23. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/__init__.py +12 -19
  24. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/PKG-INFO +29 -28
  25. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/SOURCES.txt +2 -5
  26. modal_decomposition-0.1.4/tests/test.py +216 -0
  27. modal_decomposition-0.1.2/src/Modal_Decomposition/CEEMD.py +0 -135
  28. modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/__init__.py +0 -18
  29. modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/color_define.py +0 -30
  30. modal_decomposition-0.1.2/src/Modal_Decomposition/COLOR/colorful_print.py +0 -66
  31. modal_decomposition-0.1.2/src/Modal_Decomposition/EEMD.py +0 -130
  32. modal_decomposition-0.1.2/src/Modal_Decomposition/EWT.py +0 -76
  33. modal_decomposition-0.1.2/src/Modal_Decomposition/LMD.py +0 -178
  34. modal_decomposition-0.1.2/src/Modal_Decomposition/Utils/OneDimArray.py +0 -27
  35. modal_decomposition-0.1.2/src/Modal_Decomposition/help_function.py +0 -64
  36. modal_decomposition-0.1.2/tests/test.py +0 -74
  37. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/LICENSE +0 -0
  38. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/setup.cfg +0 -0
  39. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/CycleError.py +0 -0
  40. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/EnvironmentMemory.py +0 -0
  41. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/LazyImport.py +0 -0
  42. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/NumpyNdarray_MemoryCalculator.py +0 -0
  43. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
  44. {modal_decomposition-0.1.2 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
  45. {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.2
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.MEMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
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 | Sequential Variational Mode Decomposition | `Function.SVMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
65
- | VMD | Variational Mode Decomposition | `Function.VMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
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/Motal-Decomposition.git
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
- ## 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
+ *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.MEMD(signal)` | [10.1109/TIE.2022.3156156](https://ieeexplore.ieee.org/document/9732251) |
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 | Sequential Variational Mode Decomposition | `Function.SVMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
33
- | VMD | Variational Mode Decomposition | `Function.VMD(signal)` | [10.1016/j.sigpro.2020.107610](https://www.sciencedirect.com/science/article/abs/pii/S0165168420301535) |
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/Motal-Decomposition.git
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
- ## 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
+ *Please pip `EMD-signal`, not `PyEMD`*
85
86
 
86
87
  ## Url
87
88
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "Modal-Decomposition"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  requires-python = ">=3.8"
9
9
 
10
10
  authors = [
@@ -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
- if not isinstance(S, np.ndarray):
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
- if not isinstance(S, np.ndarray):
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
- :return: IMFs (n_IMFs, N), Res: (N,)
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
- if not isinstance(S, np.ndarray):
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 arr
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
- local_maximum_points = argrelmax(edge_magnitude)
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