Modal-Decomposition 0.0.1__py3-none-any.whl

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.
@@ -0,0 +1,118 @@
1
+ """
2
+ Python version: (must)
3
+ 3.10.11
4
+
5
+ Lib and Version: (if None write None)
6
+ EMD-signal - 1.9.0
7
+
8
+ Only accessed by: (must)
9
+ Only __init__.py
10
+
11
+ Modify: (must)
12
+ 2026.3.25
13
+
14
+ Description: (if None write None)
15
+ Realize the CEEFD and CEEMDAN.
16
+ """
17
+
18
+ import numpy as np
19
+
20
+ class CEEFD:
21
+ """
22
+ CEEFD
23
+ """
24
+
25
+ def __init__ \
26
+ (
27
+ self,
28
+ trials=10,
29
+ noise_width=0.05, # default: 0.05-0.3
30
+ noise_seed=42, # seed
31
+ spline_kind='cubic',
32
+ nbsym=2, # Number of boundary symmetry points
33
+ extrema_detection='parabol',
34
+ parallel=False,
35
+ processes=None, # None = auto, int >= 1
36
+ random_state=42,
37
+ noise_scale=1.0, # scale factor of noise
38
+ noise_kind='normal', # noise kind: 'normal', 'uniform'
39
+ range_thr=0.01, # Stop threshold
40
+ total_power_thr=0.005
41
+ ):
42
+
43
+ self.trials = trials
44
+ self.noise_width = noise_width
45
+ self.noise_seed = noise_seed
46
+ self.spline_kind = spline_kind
47
+ self.nbsym = nbsym
48
+ self.extrema_detection = extrema_detection
49
+ self.parallel = parallel
50
+ self.processes = processes
51
+ self.random_state = random_state
52
+ self.noise_scale = noise_scale
53
+ self.noise_kind = noise_kind
54
+ self.range_thr = range_thr
55
+ self.total_power_thr = total_power_thr
56
+
57
+ def give_ceemdan(self):
58
+ from PyEMD import CEEMDAN
59
+
60
+ return CEEMDAN \
61
+ (
62
+ trials=self.trials,
63
+ noise_width=self.noise_width,
64
+ noise_seed=self.noise_seed,
65
+ spline_kind=self.spline_kind,
66
+ nbsym=self.nbsym,
67
+ extrema_detection=self.extrema_detection,
68
+ parallel=self.parallel,
69
+ processes=self.processes,
70
+ random_state=self.random_state,
71
+ noise_scale=self.noise_scale,
72
+ noise_kind=self.noise_kind,
73
+ range_thr=self.range_thr,
74
+ total_power_thr=self.total_power_thr
75
+ )
76
+
77
+ def ceemdan(self, S, T=None, max_imf=-1):
78
+ CEEMDAN = self.give_ceemdan()
79
+ IMF_Residue = CEEMDAN.ceemdan(S, T, max_imf)
80
+
81
+ IMFs = IMF_Residue[:-1, :] # shape [n_imfs, len(S)]
82
+ Res = IMF_Residue[-1, :]
83
+
84
+ return IMFs, Res
85
+
86
+ def ceefd(self, S, T=None, max_imf=-1):
87
+ """
88
+ :return: other_IMFs (ndarray-2D), IMF_ (np.ndarray-2D), Res (ndarray), Res_ (ndarray)
89
+ """
90
+ from .EFD import EFD
91
+ import antropy as ant
92
+
93
+ CEEMDAN = self.give_ceemdan()
94
+ IMF_Residue = CEEMDAN.ceemdan(S, T, max_imf)
95
+
96
+ IMFs = IMF_Residue[:-1, :] # shape [n_imfs, len(S)]
97
+ Res = IMF_Residue[-1, :]
98
+
99
+ # cal sample entropy of IMF
100
+ Entropy = [ant.sample_entropy(IMF) for IMF in IMFs]
101
+ max_entropy_mask = np.argmax(Entropy)
102
+ maxIMF = IMFs[max_entropy_mask]
103
+
104
+ # EMD for max antropy IMF
105
+ if T is None:
106
+ T_efd = np.arange(len(maxIMF))
107
+ else:
108
+ T_efd = T
109
+ IMF_, Res_ = EFD(maxIMF, T_efd)
110
+
111
+ # get other_IMFs
112
+ other_IMFs_list = [IMF for i, IMF in enumerate(IMFs) if i != max_entropy_mask]
113
+ if other_IMFs_list:
114
+ other_IMFs = np.stack(other_IMFs_list)
115
+ else:
116
+ other_IMFs = None
117
+
118
+ return other_IMFs, np.array(IMF_), Res, Res_
@@ -0,0 +1,129 @@
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
+ Modify: (must)
14
+ 2026.3.25
15
+
16
+ Description: (if None write None)
17
+ Realize the CEEMD.
18
+ """
19
+
20
+ from time import sleep
21
+ import numpy as np
22
+ from .EMD import emd
23
+ from .help_function import is_increasing
24
+ from tqdm import tqdm
25
+ import sys
26
+
27
+
28
+ def ceemd(S, T=None, fs=None, beta=0.3, max_imf=None, iterations=30, verbose: bool=False):
29
+ """
30
+
31
+ :param S:
32
+ :param T:
33
+ :param fs:
34
+ :param beta:
35
+ :param max_imf: -1 or other int | 100 is enough, if you choose -1, no one kown when it will finish(^_^)
36
+ :param iterations:
37
+ :param verbose:
38
+ :return:
39
+ """
40
+ N = len(S)
41
+
42
+ if max_imf is None:
43
+ max_imf = int(np.log2(len(S))) + 2
44
+
45
+ if T is None:
46
+ if fs is not None:
47
+ # smaple
48
+ dt = 1.0 / fs
49
+ T = np.arange(N) * dt
50
+ else:
51
+ # default smaple f = 1
52
+ T = np.arange(N)
53
+ print(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]")
54
+
55
+ # Standard
56
+ MEAN = np.mean(S)
57
+ S = S - MEAN
58
+ STD = np.std(S)
59
+ S = S / STD
60
+
61
+ Res = S
62
+ IMFs = []
63
+
64
+ std_dev = np.std(S)
65
+ mean = np.mean(S)
66
+
67
+ count = 0
68
+ while True:
69
+ IMF = np.zeros(N)
70
+
71
+ if verbose:
72
+ for i in tqdm(range(iterations // 2), position=0, file=sys.stdout, desc="iter: "):
73
+ white_noise = np.random.normal(mean, std_dev * beta, N)
74
+
75
+ S_plus = Res + white_noise
76
+ S_minus = Res - white_noise
77
+
78
+ IMFs_plus, _ = emd(S_plus, T)
79
+ IMFs_minus, _ = emd(S_minus, T)
80
+
81
+ if len(IMFs_plus) == 0 or len(IMFs_minus) == 0:
82
+ continue
83
+
84
+ IMFs_avg = (IMFs_plus[0, :] + IMFs_minus[0, :]) / 2
85
+
86
+ IMF += IMFs_avg
87
+
88
+ else:
89
+ for i in range(iterations // 2):
90
+ white_noise = np.random.normal(mean, std_dev * beta, N)
91
+
92
+ S_plus = Res + white_noise
93
+ S_minus = Res - white_noise
94
+
95
+ IMFs_plus, _ = emd(S_plus, T)
96
+ IMFs_minus, _ = emd(S_minus, T)
97
+
98
+ if len(IMFs_plus) == 0 or len(IMFs_minus) == 0:
99
+ continue
100
+
101
+ IMFs_avg = (IMFs_plus[0, :] + IMFs_minus[0, :]) / 2
102
+
103
+ IMF += IMFs_avg
104
+
105
+ IMF = IMF / (iterations / 2)
106
+ IMFs.append(IMF * STD + MEAN)
107
+ count += 1
108
+
109
+ if verbose:
110
+ if count % 10 == 0:
111
+ tqdm.write(f"has get {count} IMFs...")
112
+ sleep(1)
113
+
114
+ if max_imf != -1:
115
+ if count >= max_imf:
116
+ Res = Res - IMF
117
+ Res = Res * STD + MEAN
118
+ break
119
+
120
+ Res = Res - IMF
121
+
122
+ if np.std(Res) < 1e-10 * np.std(S):
123
+ break
124
+
125
+ if is_increasing(Res):
126
+ Res = Res * STD + MEAN
127
+ break
128
+
129
+ return np.array(IMFs), np.array(Res)
@@ -0,0 +1,18 @@
1
+ """
2
+ Python version: 3.11
3
+
4
+ Role:
5
+ the main entrance
6
+
7
+ Lib and Version:
8
+ colorama - 0.4.6
9
+
10
+ Only accessed by:
11
+ All
12
+
13
+ Modify:
14
+ 2026.3.4
15
+ """
16
+
17
+ from .color_define import Color
18
+ from .colorful_print import printc
@@ -0,0 +1,30 @@
1
+ """
2
+ Python version: 3.11
3
+
4
+ Lib and Version:
5
+ colorama - 0.4.6
6
+
7
+ Only accessed by:
8
+ __init__.py, colorful_print.py
9
+
10
+ Modify:
11
+ 2026.3.4
12
+ """
13
+
14
+ import colorama as cm
15
+
16
+ __all__ = ["Color"]
17
+
18
+ Fore = cm.Fore
19
+
20
+ Color = \
21
+ {
22
+ "black": Fore.BLACK,
23
+ "red": Fore.RED,
24
+ "green": Fore.GREEN,
25
+ "yellow": Fore.YELLOW,
26
+ "blue": Fore.BLUE,
27
+ "magenta": Fore.MAGENTA,
28
+ "cyan": Fore.CYAN,
29
+ "white": Fore.WHITE,
30
+ }
@@ -0,0 +1,66 @@
1
+ """
2
+ Python version: 3.11
3
+
4
+ Lib and Version:
5
+ colorama - 0.4.6
6
+
7
+ Only accessed by:
8
+ All
9
+
10
+ Modify:
11
+ 2026.3.4
12
+ """
13
+
14
+ import colorama as cm
15
+ from typing import Literal, Any
16
+
17
+ __all__ = ["printc"]
18
+
19
+ Fore = cm.Fore
20
+
21
+ Color = \
22
+ {
23
+ "black": Fore.BLACK,
24
+ "red": Fore.RED,
25
+ "green": Fore.GREEN,
26
+ "yellow": Fore.YELLOW,
27
+ "blue": Fore.BLUE,
28
+ "magenta": Fore.MAGENTA,
29
+ "cyan": Fore.CYAN,
30
+ "white": Fore.WHITE,
31
+ }
32
+
33
+ def printc(*values: Any, color: Literal["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] = None, sep: str = ' ', end: str = '\n') -> bool:
34
+ """
35
+ (don't think much, just use as print)\n
36
+ A function that can make output be colorful.\n
37
+ If the function is successful, will default return True. If 'R' parameter is not change, when fail will Raise.(make 'R'=False, will return False only)\n
38
+ If you don't choose color or input a error parameter, default white.\n
39
+ kwargs: you can input 'c' to cover the "color" parameter, and use 'R' to choose whether raise the error, default is raise(R=True).\n
40
+ Reference Lib: colorama
41
+
42
+ :param values: Any, like values in print
43
+ :param color: color for output
44
+ :param sep: print parameter
45
+ :param end: print parameter
46
+ :return: bool: the result of print
47
+ """
48
+
49
+ if not hasattr(printc, '_initialized'):
50
+ cm.init(autoreset=True)
51
+ printc._initialized = True
52
+
53
+ # deal color
54
+ if color is None:
55
+ print(*values, sep=sep, end=end)
56
+ return True
57
+
58
+ c = Color.get(color, Color["white"]) # check and appoint color
59
+
60
+ # for values' type
61
+ if len(values) == 1: # only one element been input
62
+ text: str = str(values[0])
63
+
64
+ text: str = sep.join(str(args) for args in values)
65
+
66
+ print(c + text, end=end)
@@ -0,0 +1,24 @@
1
+ """
2
+ Python version: (must)
3
+ 3.10.11
4
+
5
+ Lib and Version: (if None write None)
6
+ EMD-signal - 1.9.0
7
+
8
+ Only accessed by: (must)
9
+ Only __init__.py
10
+
11
+ Modify: (must)
12
+ 2026.3.25
13
+
14
+ Description: (if None write None)
15
+ Realize the EEMD.
16
+ """
17
+
18
+ from PyEMD import EEMD
19
+
20
+ Origin_EEMD = EEMD
21
+
22
+ EEMD = EEMD()
23
+ def eemd(S):
24
+ return EEMD.eemd(S)
@@ -0,0 +1,94 @@
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
+ matplotlib - 3.10.8
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 the EFD.
18
+ Optimize the use of scipy.signal
19
+ """
20
+
21
+ import numpy as np
22
+ from .COLOR import printc
23
+
24
+ def EFD(S, T=None, fs=None):
25
+ """
26
+ :param S: Signal (1-dim)
27
+ :param T: Time axis (uniform spacing)
28
+ :return: IMFs: np.ndarray (2-dim) | Res: np.ndarray (1-dim)
29
+ """
30
+ from scipy.signal import find_peaks
31
+
32
+ if not isinstance(S, np.ndarray):
33
+ S = np.array(S)
34
+
35
+ N = len(S)
36
+
37
+ if T is None:
38
+ if fs is not None:
39
+ dt = 1.0 / fs # smaple for time axis
40
+ T = np.arange(N) * dt
41
+ else:
42
+ T = np.arange(N) # default fs = 1
43
+ printc(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]", color="red")
44
+
45
+ if len(T) != N:
46
+ raise ValueError(f"len of T: ({len(T)}) doesn't match ({N})")
47
+
48
+ dt = np.diff(T)
49
+ if not np.allclose(dt, dt[0], rtol=1e-10, atol=1e-14):
50
+ raise ValueError("Time series should be uniform intervals")
51
+
52
+ # FFT
53
+ fft = np.fft.fft
54
+ F = fft(S)
55
+ freq = np.fft.fftfreq(len(T), d=T[1]-T[0])
56
+
57
+ f = np.abs(F)
58
+ idx = np.where(freq >= 0)[0]
59
+ freq_positive = freq[idx]
60
+ spectrum = f[idx]
61
+
62
+ # boundary
63
+ part_max, _ = find_peaks(spectrum)
64
+ part_min, _ = find_peaks(-spectrum)
65
+ boundary = np.concatenate([np.array([0]), part_min, part_max, np.array([len(freq_positive) - 1])])
66
+ boundary = np.unique(boundary)
67
+ boundary = np.sort(boundary)
68
+
69
+ IMFs = []
70
+
71
+ freq_set = []
72
+ spectrum_set = []
73
+
74
+ for b in range(1, len(boundary)):
75
+ down_bound = boundary[b - 1]
76
+ up_bound = boundary[b]
77
+
78
+ filter_mask = np.zeros(N)
79
+ filter_mask[N // 2 + down_bound : N // 2 + up_bound + 1] = 1
80
+ filter_mask[N // 2 - up_bound : N // 2 - down_bound + 1] = 1
81
+
82
+ if down_bound == 0:
83
+ filter_mask[N // 2 + 1 : N // 2 + up_bound + 1] = 1
84
+
85
+ F_band = F * filter_mask
86
+
87
+ IMF = np.fft.ifft(F_band)
88
+ IMFs.append(np.real(IMF))
89
+
90
+ sum_IMFs = np.sum(IMFs, axis=0)
91
+ Res: np.ndarray = np.array(S - sum_IMFs)
92
+ IMFs: np.ndarray = np.array(IMFs)
93
+
94
+ return IMFs, Res
@@ -0,0 +1,53 @@
1
+ """
2
+ Python version: (must)
3
+ 3.10.11
4
+
5
+ Lib and Version: (if None write None)
6
+ EMD-signal - 1.9.0
7
+ numpy - 2.2.6
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 EMD
17
+ """
18
+
19
+ from PyEMD import EMD
20
+ import numpy as np
21
+ from .COLOR.colorful_print import printc
22
+ from typing import Tuple
23
+
24
+ EMD_cls = EMD
25
+
26
+ def emd(S, T=None, spline_kind: str = "cubic", nbsym: int = 2, max_imf=-1, fs=None) -> Tuple[np.ndarray, np.ndarray]:
27
+ """
28
+ :param S:
29
+ :param T:
30
+ :param spline_kind:
31
+ :param nbsym:
32
+ :param max_imf:
33
+ :param fs:
34
+ :return: IMFs (2-dim), Res: None
35
+ """
36
+ if not isinstance(S, np.ndarray):
37
+ S = np.array(S)
38
+
39
+ N = len(S)
40
+
41
+ if T is None:
42
+ if fs is not None:
43
+ dt = 1.0 / fs # smaple for time axis
44
+ T = np.arange(N) * dt
45
+ else:
46
+ T = np.arange(N) # default fs = 1
47
+ printc(f"Warn: T is None,default T = [0, 1, 2, ..., {N - 1}]", color="red")
48
+
49
+ EMD_cls = EMD(spline_kind, nbsym)
50
+
51
+ IMFs = EMD_cls.emd(S, T, max_imf=max_imf)
52
+
53
+ return IMFs[:-1, :], IMFs[-1, :]
@@ -0,0 +1,61 @@
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
+ Modify: (must)
13
+ 2026.3.25
14
+
15
+ Description: (if None write None)
16
+ Realize the EWT
17
+ """
18
+
19
+ from typing import Tuple, Union
20
+ import numpy as np
21
+
22
+ def ewt \
23
+ (
24
+ S,
25
+ N: int = 5,
26
+ log: int = 0,
27
+ detect: str = "locmax",
28
+ completion: int = 0,
29
+ reg: str = 'average',
30
+ lengthFilter: int = 10,
31
+ sigmaFilter: int = 5,
32
+ need_mfd: bool = False,
33
+ need_boundaries: bool = False) -> Union[Tuple[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:
34
+ """
35
+ :param S: Signal
36
+ :param N:
37
+ :param log:
38
+ :param detect:
39
+ :param completion:
40
+ :param reg:
41
+ :param lengthFilter:
42
+ :param sigmaFilter:
43
+ :return: IMFs(N, len(S)) (2-dim)
44
+ """
45
+ from ewtpy import EWT1D
46
+
47
+ ewt, mfb, boundaries = EWT1D(S, N, log, detect, completion, reg, lengthFilter, sigmaFilter)
48
+ ewt = ewt.T
49
+ mfb = mfb.T
50
+
51
+ if need_mfd and not need_boundaries:
52
+ return ewt[:-1, :], ewt[-1, :], mfb
53
+
54
+ if need_boundaries and not need_mfd:
55
+ return ewt[:-1, :], ewt[-1, :], boundaries
56
+
57
+ if need_mfd and need_boundaries:
58
+ return ewt[:-1, :], ewt[-1, :], mfb, boundaries
59
+
60
+ if not need_mfd and not need_boundaries:
61
+ return ewt[:-1, :], ewt[-1, :]
@@ -0,0 +1,69 @@
1
+ """
2
+ Python version: (must)
3
+ 3.10.11
4
+
5
+ Lib and Version: (if None write None)
6
+ scipy - 1.15.3
7
+ matplotlib - 3.10.8
8
+ numpy - 2.2.6
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 the FMD
18
+ """
19
+
20
+ import numpy as np
21
+
22
+ def initialize_filters(L, K):
23
+ from scipy.signal import firwin
24
+
25
+ filters = []
26
+ for k in range(1, K + 1):
27
+ cutoff = 0.5 / k
28
+ filter = firwin(L, cutoff, window='hann')
29
+ filters.append(filter)
30
+ return filters
31
+
32
+ def estimate_period(signal):
33
+ from scipy.signal import correlate, find_peaks
34
+
35
+ correlation = correlate(signal, signal, mode='full')
36
+ correlation = correlation[len(correlation) // 2:]
37
+ peaks, _ = find_peaks(correlation)
38
+ if len(peaks) > 1:
39
+ period = peaks[1]
40
+ else:
41
+ period = len(signal)
42
+ return period
43
+
44
+ def fmd(S, n=10, L=100, max_iters=10):
45
+ """
46
+ :param S: Signal (2-dim)
47
+ :param n: store n IMFs
48
+ :param L:
49
+ :param max_iters:
50
+ :return:
51
+ """
52
+ from scipy.signal import lfilter
53
+
54
+ if not isinstance(S, np.ndarray):
55
+ S = np.array(S)
56
+
57
+ K = min(10, max(5, n))
58
+ filters = initialize_filters(L, K)
59
+ modes = []
60
+ S = np.array(S) if isinstance(S, list) else S
61
+ for i in range(max_iters):
62
+ for filter in filters:
63
+ filtered_signal = lfilter(filter, 1.0, S)
64
+ period = estimate_period(filtered_signal)
65
+ modes.append(filtered_signal)
66
+ if len(modes) >= n:
67
+ break
68
+
69
+ return modes[:n]