Modal-Decomposition 0.0.4__tar.gz → 0.0.5__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 (32) hide show
  1. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/PKG-INFO +1 -1
  2. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/pyproject.toml +1 -1
  3. modal_decomposition-0.0.5/src/Modal_Decomposition/SSA.py +228 -0
  4. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/__init__.py +2 -1
  5. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition.egg-info/PKG-INFO +1 -1
  6. modal_decomposition-0.0.5/tests/test.py +87 -0
  7. modal_decomposition-0.0.4/src/Modal_Decomposition/SSA.py +0 -113
  8. modal_decomposition-0.0.4/tests/test.py +0 -12
  9. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/LICENSE +0 -0
  10. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/README.md +0 -0
  11. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/setup.cfg +0 -0
  12. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/CEEFD.py +0 -0
  13. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/CEEMD.py +0 -0
  14. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/COLOR/__init__.py +0 -0
  15. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/COLOR/color_define.py +0 -0
  16. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/COLOR/colorful_print.py +0 -0
  17. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/EEMD.py +0 -0
  18. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/EFD.py +0 -0
  19. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/EMD.py +0 -0
  20. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/EWT.py +0 -0
  21. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/FMD.py +0 -0
  22. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/ICEEMDAN.py +0 -0
  23. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/LMD.py +0 -0
  24. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/MEMD.py +0 -0
  25. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/RPSEMD.py +0 -0
  26. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/SVMD.py +0 -0
  27. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/VMD.py +0 -0
  28. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition/help_function.py +0 -0
  29. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition.egg-info/SOURCES.txt +0 -0
  30. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition.egg-info/dependency_links.txt +0 -0
  31. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/src/Modal_Decomposition.egg-info/requires.txt +0 -0
  32. {modal_decomposition-0.0.4 → modal_decomposition-0.0.5}/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.0.4
3
+ Version: 0.0.5
4
4
  Summary: a package for modal decomposition
5
5
  Author-email: Mao_HaoChuan <2215269365@qq.com>
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "Modal-Decomposition"
7
- version = "0.0.4"
7
+ version = "0.0.5"
8
8
  requires-python = ">=3.8"
9
9
 
10
10
  authors = [
@@ -0,0 +1,228 @@
1
+ """
2
+
3
+ Python version: (must)
4
+ 3.10.11
5
+
6
+ Lib and Version: (if None write None)
7
+ numpy - 2.2.6
8
+ numba - 0.64.0
9
+
10
+ Only accessed by: (must)
11
+ Only __init__.py
12
+
13
+ Description: (if None write None)
14
+ Realize SSA, and optimize the use of numba and SSAfast(function).
15
+
16
+ Modify: (must)
17
+ 2026.3.25 - I forgot.
18
+ 2026.3.29 - Optimize the SSA.decompose function, it's faster now. Please use SSA() which means SSA.decompose_fast().
19
+ """
20
+
21
+ import numpy as np
22
+ from typing import Union
23
+
24
+ class SSA:
25
+ def __init__(self, window_size=None):
26
+ """
27
+ :param:
28
+ window_size: size of windows, default 1/3 of sequence
29
+ """
30
+ self.window_size = window_size
31
+ self.components_ = None
32
+ self.sigma_ = None
33
+ self.U_ = None
34
+ self.V_ = None
35
+
36
+
37
+ def __call__(self, S, groups=None, faster=False):
38
+ return self.decompose_fast(S, groups, faster)
39
+
40
+
41
+ def hankel(self, S, L):
42
+ N = len(S)
43
+ K = N - L + 1
44
+
45
+ _S = np.asarray(S)
46
+ strides = (_S.strides[0], _S.strides[0])
47
+ return np.lib.stride_tricks.as_strided(_S, shape=(L, K), strides=strides)
48
+
49
+ @staticmethod
50
+ def diagonal_average(X_rec: Union[list, np.ndarray], L: int, K: int) -> np.ndarray:
51
+ """
52
+ :param X_rec: 2-dim
53
+ :param L: int
54
+ :param K: int
55
+ :return: rc (2-dim)
56
+ """
57
+ if not isinstance(X_rec, np.ndarray):
58
+ X_rec = np.array(X_rec)
59
+
60
+ N = L + K - 1
61
+ rc = np.zeros(N)
62
+ for n in range(N):
63
+ i_min = max(0, n - K + 1)
64
+ i_max = min(L - 1, n)
65
+
66
+ total = 0.0
67
+ count = 0
68
+ for i in range(i_min, i_max + 1):
69
+ j = n - i
70
+ total += X_rec[i, j]
71
+ count += 1
72
+ rc[n] = total / count
73
+
74
+ return rc
75
+
76
+ @staticmethod
77
+ def diagonal_average_fast(X_rec: Union[list, np.ndarray], L: int, K:int) -> np.ndarray:
78
+ """
79
+ like 'diagonal_average'
80
+ :param X_rec:
81
+ :param L:
82
+ :param K:
83
+ :return: rc (2-dim)
84
+ """
85
+ N = L + K - 1
86
+ n_idx = np.add.outer(np.arange(L), np.arange(K)).flatten()
87
+ values = X_rec.flatten()
88
+
89
+ Sum = np.bincount(n_idx, weights=values, minlength=N)
90
+
91
+ counts = np.bincount(n_idx, minlength=N)
92
+
93
+ counts[counts == 0] = 1
94
+
95
+ rc = Sum / counts
96
+
97
+ return rc
98
+
99
+ def decompose(self, S: Union[list, np.ndarray], groups=None) -> np.ndarray:
100
+ """
101
+ :param S: Signal (1-dim)
102
+ :param L:
103
+ :param groups: group information, such as: [[0], [1,2], [3,4]] means which components will be merged. If None, return all
104
+
105
+ :return: IMFs (2-dim)
106
+ """
107
+ if not isinstance(S, np.ndarray):
108
+ S = np.array(S)
109
+
110
+ series = np.asarray(S).flatten()
111
+ N = len(S)
112
+
113
+ if self.window_size is None:
114
+ L = N // 3
115
+ else:
116
+ L = min(self.window_size, N // 2)
117
+
118
+ K = N - L + 1
119
+
120
+ X = np.zeros((L, K))
121
+ for i in range(K):
122
+ X[:, i] = series[i:i + L]
123
+
124
+ U, sigma, VT = np.linalg.svd(X, full_matrices=False)
125
+
126
+ idx = np.argsort(-sigma)
127
+ sigma = sigma[idx]
128
+ U = U[:, idx]
129
+ VT = VT[idx, :]
130
+
131
+ if groups is None:
132
+ groups = [[i] for i in range(len(sigma))]
133
+
134
+ RCs = []
135
+
136
+ for group in groups:
137
+ x_group = np.zeros((L, K))
138
+
139
+ for i in group:
140
+ x_group += sigma[i] * np.outer(U[:, i], VT[i, :])
141
+
142
+ rc = np.zeros(N)
143
+ count = np.zeros(N)
144
+ for i in range(L):
145
+ for j in range(K):
146
+ d = i + j
147
+ rc[d] += x_group[i, j]
148
+ count[d] += 1
149
+
150
+ rc = rc / count
151
+ RCs.append(rc)
152
+
153
+ self.components_ = np.array(RCs)
154
+ self.sigma_ = sigma
155
+ self.U_ = U
156
+ self.V_ = VT
157
+
158
+ return self.components_
159
+
160
+ def decompose_fast(self, S: Union[list, np.ndarray], groups=None, faster: bool=False) -> np.ndarray:
161
+ """
162
+ :param S: Signal (1-dim)
163
+ :param L:
164
+ :param groups: group information, such as: [[0], [1,2], [3,4]] means which components will be merged. If None, return all
165
+ :param faster: if you choose True, function will be faster with wasting memory.
166
+ :return: IMFs (2-dim)
167
+ """
168
+
169
+ if not isinstance(S, np.ndarray):
170
+ S = np.array(S)
171
+
172
+ N = len(S)
173
+
174
+ if self.window_size is None:
175
+ L = N // 3
176
+ else:
177
+ L = min(self.window_size, N // 2)
178
+
179
+ K = N - L + 1
180
+
181
+ x = self.hankel(S, L)
182
+
183
+ U, s, Vt = np.linalg.svd(x, full_matrices=False)
184
+
185
+ if groups is None:
186
+ groups = [[i] for i in range(len(s))]
187
+
188
+ RCs = []
189
+ for group in groups:
190
+ X_rec = np.zeros((L, K))
191
+
192
+ # X_rec = np.sum(s[group] * np.outer(U[:, group], Vt[group, :]), keepdims=True)
193
+ def f(i) -> np.ndarray:
194
+ temp = s[i] * np.outer(U[:, i], Vt[i, :])
195
+ return temp
196
+
197
+ if faster:
198
+ X_rec = np.add.reduce([f(i) for i in group]) # but, you should consider the memory with this code.
199
+
200
+ else:
201
+ for i in group:
202
+ X_rec += f(i) # also, you can use code above:
203
+
204
+ rc = self.diagonal_average_fast(X_rec, L, K)
205
+
206
+ RCs.append(rc)
207
+
208
+ return np.array(RCs)
209
+
210
+
211
+ # def give_fast_SSA() -> Callable:
212
+ # from numba import njit
213
+ #
214
+ # @njit
215
+ # def SSAfast(series, L):
216
+ # N = len(series)
217
+ # K = N - L + 1
218
+ #
219
+ # X = np.zeros((L, K))
220
+ # for i in range(K):
221
+ # X[:, i] = series[i:i + L]
222
+ #
223
+ # # SVD decomposition
224
+ # U, s, VT = np.linalg.svd(X, full_matrices=False)
225
+ #
226
+ # return U, s, VT
227
+ #
228
+ # return SSAfast
@@ -26,6 +26,7 @@ Description: (if None write None)
26
26
  Modify:
27
27
  2026.3.25 - Optimize the cost of import, from 5.001s to 0.747s. Put some heavy lib into internal of the function
28
28
  2026.3.26 - Optimize the description of the type of input and output. now, the dim of input and output is more clear.
29
+ 2026.3.29 - Optimize the SSA.decompose function, time changed from 40min averagely to 2s averagely.
29
30
  """
30
31
  from .help_function import is_increasing
31
32
 
@@ -75,7 +76,7 @@ class Function:
75
76
  EEMD = eemd
76
77
  FMD = fmd
77
78
  EWT = ewt
78
- SSA = ssa_cls.decompose
79
+ SSA = ssa_cls
79
80
  RPSEMD = rpsemd
80
81
  CEEMD = ceemd
81
82
  MEMD = memd
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Modal-Decomposition
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: a package for modal decomposition
5
5
  Author-email: Mao_HaoChuan <2215269365@qq.com>
6
6
  License: Apache-2.0
@@ -0,0 +1,87 @@
1
+ import time
2
+ from typing import Callable, Any
3
+ import numpy as np
4
+
5
+
6
+ def time_show(f: Callable) -> Callable:
7
+ def F(*args, **kwargs):
8
+ this = time.time()
9
+ f(*args, **kwargs)
10
+ now = time.time()
11
+ delta = now - this
12
+ print(f"this function use {delta}s")
13
+
14
+ return F
15
+
16
+ def check_result(**kwargs):
17
+ IMFs: np.ndarray = kwargs.get("IMFs", None) # IMFs
18
+ Res: np.ndarray = kwargs.get("Res", None) # Res
19
+ S: np.ndarray = kwargs.get("S", None) # origin signal
20
+
21
+ RMSE = None
22
+ OI = None
23
+ R = None
24
+ MSE = None
25
+
26
+ if IMFs is None or IMFs.size == 0:
27
+ print("this function doesn't decompose the useful IMFs. Exit...")
28
+ return
29
+
30
+ if IMFs.ndim == 1:
31
+ IMFs = IMFs.reshape(1, -1)
32
+
33
+ Res = np.asarray(Res).flatten()
34
+
35
+ reconstructed = np.sum(IMFs, axis=0) + Res
36
+ # 计算 RMSE 和 MSE
37
+ mse = np.mean((S - reconstructed) ** 2)
38
+ rmse = np.sqrt(mse)
39
+ RMSE = rmse
40
+ MSE = mse
41
+
42
+ K, N = IMFs.shape
43
+ if K <= 1:
44
+ OI = 0.0
45
+
46
+ else:
47
+ corr_matrix = np.corrcoef(IMFs)
48
+
49
+ upper_tri = np.triu_indices_from(corr_matrix, k=1)
50
+ OI = np.mean(np.abs(corr_matrix[upper_tri]))
51
+
52
+ R = corr_matrix
53
+
54
+ print(f"RMSE={RMSE} | MES={MSE} | OI={OI} | R={R}")
55
+
56
+ @time_show
57
+ def test_SSA(S):
58
+ from src.Modal_Decomposition import Function as F
59
+ SSA = F.SSA
60
+
61
+ RCs = SSA(S)
62
+
63
+ IMFs = RCs[:-1, :]
64
+ Res = RCs[-1, :]
65
+
66
+ check_result(IMFs=IMFs, Res=Res, S=S)
67
+
68
+ return RCs
69
+
70
+
71
+ if __name__ == '__main__':
72
+ t = np.arange(0, 1000, 1)
73
+ S = 1 + np.sin(t ** 2) + 4 * np.cos(3 * t - 1) - (np.sin(t + 3) * 9) ** 2
74
+
75
+ test_SSA(S)
76
+
77
+ # a = np.array \
78
+ # (
79
+ # [
80
+ # [1, 2, 3, 8],
81
+ # [2, 5, 7, 2],
82
+ # [3, 5, 1, 3],
83
+ # [1, 4, 5, 2]
84
+ # ]
85
+ # )
86
+ #
87
+ # print(a[[0, 1], 3])
@@ -1,113 +0,0 @@
1
- """
2
-
3
- Python version: (must)
4
- 3.10.11
5
-
6
- Lib and Version: (if None write None)
7
- numpy - 2.2.6
8
- numba - 0.64.0
9
-
10
- Only accessed by: (must)
11
- Only __init__.py
12
-
13
- Modify: (must)
14
- 2026.3.25
15
-
16
- Description: (if None write None)
17
- Realize SSA, and optimize the use of numba and SSAfast(function).
18
- """
19
-
20
- import numpy as np
21
- from typing import Union
22
-
23
- class SSA:
24
- def __init__(self, window_size=None):
25
- """
26
- :param:
27
- window_size: size of windows, default 1/3 of sequence
28
- """
29
- self.window_size = window_size
30
- self.components_ = None
31
- self.sigma_ = None
32
- self.U_ = None
33
- self.V_ = None
34
-
35
- def decompose(self, S: Union[list, np.ndarray], groups=None) -> np.ndarray:
36
- """
37
- :param S: Signal (1-dim)
38
- :param groups: group information, such as: [[0], [1,2], [3,4]] means which components will be merged. If None, return all
39
-
40
- :return: IMFs (2-dim)
41
- """
42
- if not isinstance(S, np.ndarray):
43
- S = np.array(S)
44
-
45
- series = np.asarray(S).flatten()
46
- N = len(series)
47
-
48
- if self.window_size is None:
49
- L = N // 3
50
- else:
51
- L = min(self.window_size, N // 2)
52
-
53
- K = N - L + 1
54
-
55
- X = np.zeros((L, K))
56
- for i in range(K):
57
- X[:, i] = series[i:i + L]
58
-
59
- U, sigma, VT = np.linalg.svd(X, full_matrices=False)
60
-
61
- idx = np.argsort(-sigma)
62
- sigma = sigma[idx]
63
- U = U[:, idx]
64
- VT = VT[idx, :]
65
-
66
- if groups is None:
67
- groups = [[i] for i in range(len(sigma))]
68
-
69
- RCs = []
70
-
71
- for group in groups:
72
- x_group = np.zeros((L, K))
73
-
74
- for i in group:
75
- x_group += sigma[i] * np.outer(U[:, i], VT[i, :])
76
-
77
- rc = np.zeros(N)
78
- count = np.zeros(N)
79
- for i in range(L):
80
- for j in range(K):
81
- d = i + j
82
- rc[d] += x_group[i, j]
83
- count[d] += 1
84
-
85
- rc = rc / count
86
- RCs.append(rc)
87
-
88
- self.components_ = np.array(RCs)
89
- self.sigma_ = sigma
90
- self.U_ = U
91
- self.V_ = VT
92
-
93
- return self.components_
94
-
95
-
96
- # def give_fast_SSA() -> Callable:
97
- # from numba import njit
98
- #
99
- # @njit
100
- # def SSAfast(series, L):
101
- # N = len(series)
102
- # K = N - L + 1
103
- #
104
- # X = np.zeros((L, K))
105
- # for i in range(K):
106
- # X[:, i] = series[i:i + L]
107
- #
108
- # # SVD decomposition
109
- # U, s, VT = np.linalg.svd(X, full_matrices=False)
110
- #
111
- # return U, s, VT
112
- #
113
- # return SSAfast
@@ -1,12 +0,0 @@
1
- import time
2
- now = time.time()
3
-
4
- now = time.time() - now
5
-
6
- print(f"{now:.3f} seconds")
7
-
8
- """
9
- 4.728
10
- 5.007
11
- 0.747
12
- """