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.
Files changed (42) hide show
  1. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/PKG-INFO +29 -4
  2. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/README.md +28 -3
  3. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/pyproject.toml +1 -1
  4. {modal_decomposition-0.1.3 → 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.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/CEEMDAN.py +23 -26
  7. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EEMD.py +10 -16
  8. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EFD.py +6 -31
  9. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/EMD.py +7 -27
  10. modal_decomposition-0.1.4/src/Modal_Decomposition/EWT.py +62 -0
  11. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/FMD.py +17 -19
  12. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/ICEEMDAN.py +40 -65
  13. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/LMD.py +12 -19
  14. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/MEMD.py +15 -16
  15. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/RPSEMD.py +5 -10
  16. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SSA.py +14 -15
  17. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/SVMD.py +20 -12
  18. modal_decomposition-0.1.4/src/Modal_Decomposition/Utils/Check.py +39 -0
  19. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/Monotonicity.py +16 -16
  20. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/__init__.py +1 -1
  21. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/VMD.py +16 -8
  22. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/__init__.py +4 -4
  23. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/PKG-INFO +29 -4
  24. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/SOURCES.txt +1 -4
  25. modal_decomposition-0.1.4/tests/test.py +216 -0
  26. modal_decomposition-0.1.3/src/Modal_Decomposition/CEEMD.py +0 -135
  27. modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/__init__.py +0 -18
  28. modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/color_define.py +0 -30
  29. modal_decomposition-0.1.3/src/Modal_Decomposition/COLOR/colorful_print.py +0 -66
  30. modal_decomposition-0.1.3/src/Modal_Decomposition/EWT.py +0 -76
  31. modal_decomposition-0.1.3/src/Modal_Decomposition/Utils/OneDimArray.py +0 -27
  32. modal_decomposition-0.1.3/tests/test.py +0 -74
  33. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/LICENSE +0 -0
  34. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/setup.cfg +0 -0
  35. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/CycleError.py +0 -0
  36. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Error/RealizationError.py +0 -0
  37. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/EnvironmentMemory.py +0 -0
  38. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/LazyImport.py +0 -0
  39. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition/Utils/NumpyNdarray_MemoryCalculator.py +0 -0
  40. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
  41. {modal_decomposition-0.1.3 → modal_decomposition-0.1.4}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
  42. {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
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 | 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
  ```
@@ -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 | 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
  ```
@@ -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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "Modal-Decomposition"
7
- version = "0.1.3"
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
@@ -3,7 +3,7 @@ Python version: (must)
3
3
  3.10.11
4
4
 
5
5
  Lib and Version: (if None write None)
6
- EMD-S - 1.9.0
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 signal std.
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
- 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)
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
- if not isinstance(S, np.ndarray):
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 arr
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 (2-dim), Res (1-dim)
35
+ :return: IMFs (n_IMFs, N), Res (N,), None
36
36
  """
37
- if not isinstance(S, np.ndarray):
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
- else:
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