PySDKit 0.4__py3-none-any.whl → 0.4.2__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.
- {PySDKit-0.4.dist-info → PySDKit-0.4.2.dist-info}/METADATA +5 -8
- {PySDKit-0.4.dist-info → PySDKit-0.4.2.dist-info}/RECORD +12 -12
- pysdkit/__init__.py +1 -1
- pysdkit/emd/EMD.py +2 -1
- pysdkit/ewt/__init__.py +2 -2
- pysdkit/ewt/ewt.py +500 -0
- pysdkit/utils/__init__.py +35 -34
- pysdkit/vmd/_vmd_c.py +3 -5
- pysdkit/vmd/_vmd_f.py +2 -3
- pysdkit/ewt/_ewt.py +0 -449
- {PySDKit-0.4.dist-info → PySDKit-0.4.2.dist-info}/LICENSE +0 -0
- {PySDKit-0.4.dist-info → PySDKit-0.4.2.dist-info}/WHEEL +0 -0
- {PySDKit-0.4.dist-info → PySDKit-0.4.2.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PySDKit
|
|
3
|
-
Version: 0.4
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python library for signal decomposition algorithms with a unified interface
|
|
5
5
|
Home-page: https://github.com/wwhenxuan/PySDKit
|
|
6
6
|
Author: whenxuan
|
|
@@ -31,9 +31,7 @@ Requires-Dist: matplotlib (>=3.7.2)
|
|
|
31
31
|
|
|
32
32
|
A Python library for signal decomposition algorithms
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
<img src=".\images\Logo_sd.png" alt="Logo_sd" width="500"/>
|
|
36
|
-
</div>
|
|
34
|
+

|
|
37
35
|
|
|
38
36
|
## Installation
|
|
39
37
|
|
|
@@ -67,7 +65,7 @@ IMFs = emd.fit_transform(signal, max_imf=2)
|
|
|
67
65
|
plot_IMFs(signal, IMFs)
|
|
68
66
|
~~~
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+

|
|
71
69
|
|
|
72
70
|
The EMD in the above example is the most classic `empirical mode decomposition` algorithm in signal decomposition. For more complex signals, you can try other algorithms such as variational mode decomposition ([`VMD`](https://ieeexplore.ieee.org/abstract/document/6655981)).
|
|
73
71
|
|
|
@@ -85,7 +83,7 @@ print(IMFs.shape)
|
|
|
85
83
|
vmd.plot_IMFs(save_figure=True)
|
|
86
84
|
~~~
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+

|
|
89
87
|
|
|
90
88
|
Better observe the characteristics of the decomposed intrinsic mode function in the frequency domain.
|
|
91
89
|
|
|
@@ -96,5 +94,4 @@ from pysdkit.plot import plot_IMFs_amplitude_spectra
|
|
|
96
94
|
plot_IMFs_amplitude_spectra(IMFs, smooth="exp") # use exp smooth
|
|
97
95
|
~~~
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+

|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
pysdkit/__init__.py,sha256=
|
|
1
|
+
pysdkit/__init__.py,sha256=dHeg5ai9k1iznEr0OdtVkKTQLmeOOTsDa9AynzOOPXA,262
|
|
2
2
|
pysdkit/data/__init__.py,sha256=i_ZMKR_FcLq8wWXJ0MyLA4S41iXTMWbpf9sGpoLWdpw,621
|
|
3
3
|
pysdkit/data/_add_noise.py,sha256=8cGzAquIPlf0hzTMUOBj8R1SEjGd2-JveWyzPPII05M,949
|
|
4
4
|
pysdkit/data/_generator.py,sha256=gW7D9A8OTKJ5CBQ40oTbowu9PMZx-WiyN43oz42OAL4,12119
|
|
5
5
|
pysdkit/emd/BEMD.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
pysdkit/emd/EMD.py,sha256=
|
|
6
|
+
pysdkit/emd/EMD.py,sha256=dvhfOT_qfZnKJywQpSQSsiCNcMYF7hC9Pau4GJezcL8,18092
|
|
7
7
|
pysdkit/emd/__init__.py,sha256=HdOfha6kuiKz2sdTENF_7bHTN2BT2Qtr5i1xXc9dOm8,22
|
|
8
8
|
pysdkit/emd/_find_extrema.py,sha256=EnUZB9Z4uUaVTfuH2J2hERUR6cmsWQ890gQt8BpE1f0,5368
|
|
9
9
|
pysdkit/emd/_prepare_points.py,sha256=XwEkwRPmHTZZcHhjiBx2lv_Qvj-gx2lw76locyOBf-8,10528
|
|
10
10
|
pysdkit/emd/_splines.py,sha256=aaAULcznyn6mSciDeht4hdKZx1MhvKTvd0Z-bQVpd9E,2575
|
|
11
11
|
pysdkit/emd2d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
pysdkit/ewt/__init__.py,sha256=
|
|
13
|
-
pysdkit/ewt/
|
|
12
|
+
pysdkit/ewt/__init__.py,sha256=DPk4dSLaTyelSoqZ4xCSWpGA1R3jSoNrzP-oIJG_MTQ,42
|
|
13
|
+
pysdkit/ewt/ewt.py,sha256=dNPp7-nEqSZS1ZAk6ul7SDjWqo33hrh1OAvA-iYZOPg,21330
|
|
14
14
|
pysdkit/metrics/_Index_of_Orthogonality.py,sha256=nmUEP56TVeZqKogP0QqylJwLL3QMxUNLup273PM1yV4,1128
|
|
15
15
|
pysdkit/metrics/__init__.py,sha256=4TgRjJuOxNMCEloP-Vnq-z5VnrzYKQCypUaAMJb_nkI,169
|
|
16
16
|
pysdkit/plot/__init__.py,sha256=_SklnKYnFm42Yso9R_UGkzwyyi98tTngkHhgQ4JrIug,92
|
|
@@ -18,7 +18,7 @@ pysdkit/plot/_fourier_spectra.py,sha256=7HzjHf6EeZ2DScgvMvveIQYSPVhXLfQSL6sGSUJm
|
|
|
18
18
|
pysdkit/plot/_functions.py,sha256=rakosRbEg6KgdQJB26x6DGO6On3Ht9KD2MR2Wu7gSyc,4040
|
|
19
19
|
pysdkit/plot/_plot_imfs.py,sha256=YsVyazrSwBzQ3EmLj7pzZqVmxolTbSljYnAP-sIJRdQ,4239
|
|
20
20
|
pysdkit/plot/main.py,sha256=O_CKGAPPVaNBOqZwA7FrWcGJJEz76bbL_PomNJMtO7w,102
|
|
21
|
-
pysdkit/utils/__init__.py,sha256=
|
|
21
|
+
pysdkit/utils/__init__.py,sha256=1EyfVWKV6cMXPapt9lYE0pHlgAaxAhphNEo56K8GVz0,1759
|
|
22
22
|
pysdkit/utils/_differ.py,sha256=q0AoYecFLOlPsFcbjV7G_r4AGfp8WfVJ3aD9rbHIdJo,866
|
|
23
23
|
pysdkit/utils/_fft.py,sha256=VgluJaLeuuJ333_kJH1CKDbnlc6m_KX60pNfdRbv73Q,472
|
|
24
24
|
pysdkit/utils/_function.py,sha256=dBF4gSjEBavAZjx0PrnZ8Z_iBk5T-zLmU3XEC1XvwTE,1436
|
|
@@ -30,13 +30,13 @@ pysdkit/vmd/__init__.py,sha256=nNmNpo65_SlqZhqQXsYj-FRkCO-KHSRY2XeGp5vmzPo,73
|
|
|
30
30
|
pysdkit/vmd/_avmd.py,sha256=xUtmiyFOqkol7Oqh_yDPzGAr6b7FrfVXG6AlDOnTvr8,473
|
|
31
31
|
pysdkit/vmd/_mvmd.py,sha256=ANXqmfJA0Y5Ib80Yw0URzqHIIFFiJfg5p1CswTXiM1o,9109
|
|
32
32
|
pysdkit/vmd/_svmd.py,sha256=JDoR0BrocbsHn-zeg2fJ4wkuykEVh700yZKdgPk5M2o,384
|
|
33
|
-
pysdkit/vmd/_vmd_c.py,sha256=
|
|
34
|
-
pysdkit/vmd/_vmd_f.py,sha256=
|
|
33
|
+
pysdkit/vmd/_vmd_c.py,sha256=gLhUC4PTHm2pPQI6l-Plumzm1flUJ_sYhgx79MOAEeY,8756
|
|
34
|
+
pysdkit/vmd/_vmd_f.py,sha256=S0ucWz_KDsiXwmRlt6lVPRBOurXOE05WSOgggT0lqP0,5390
|
|
35
35
|
pysdkit/vmd/base.py,sha256=frcDhMadR2WHM6UTnjGgufAiZhweqrNti9E71h7zUQI,3442
|
|
36
36
|
pysdkit/vncmd/__init__.py,sha256=n9grWZ12fpbtfAtiQO50Bkg1sB0eiUDXbiMmbWk_i8c,25
|
|
37
37
|
pysdkit/vncmd/vncmd.py,sha256=digpTAUGRsddbS3bM-9p6-5tENq-__AT7aonYgVHEzA,12362
|
|
38
|
-
PySDKit-0.4.dist-info/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
|
|
39
|
-
PySDKit-0.4.dist-info/METADATA,sha256=
|
|
40
|
-
PySDKit-0.4.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
|
41
|
-
PySDKit-0.4.dist-info/top_level.txt,sha256=wN_Yil0woB5Tu_WrIRt4_T4eoRyXljCYvH0dL6-7ei0,8
|
|
42
|
-
PySDKit-0.4.dist-info/RECORD,,
|
|
38
|
+
PySDKit-0.4.2.dist-info/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
|
|
39
|
+
PySDKit-0.4.2.dist-info/METADATA,sha256=Ea1kcbITEGZVAdixzCTO1ZUsCz1Sej_yaoOCi2Te1fQ,4376
|
|
40
|
+
PySDKit-0.4.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
|
41
|
+
PySDKit-0.4.2.dist-info/top_level.txt,sha256=wN_Yil0woB5Tu_WrIRt4_T4eoRyXljCYvH0dL6-7ei0,8
|
|
42
|
+
PySDKit-0.4.2.dist-info/RECORD,,
|
pysdkit/__init__.py
CHANGED
pysdkit/emd/EMD.py
CHANGED
|
@@ -449,8 +449,9 @@ class EMD(object):
|
|
|
449
449
|
|
|
450
450
|
if __name__ == '__main__':
|
|
451
451
|
from matplotlib import pyplot as plt
|
|
452
|
+
|
|
452
453
|
x = np.linspace(0, 1, 1024)
|
|
453
454
|
f = np.cos(22 * np.pi * x ** 2) + 6 * x ** 2
|
|
454
455
|
emd = EMD(spline_kind="akima")
|
|
455
456
|
IMFs = emd.fit_transform(f, max_imf=2)
|
|
456
|
-
print(IMFs.shape)
|
|
457
|
+
print(IMFs.shape)
|
pysdkit/ewt/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from .
|
|
1
|
+
from .ewt import ewt
|
|
2
|
+
from .ewt import EWT
|
pysdkit/ewt/ewt.py
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on 2024/7/12 13:41
|
|
4
|
+
@author: Whenxuan Wang
|
|
5
|
+
@email: wwhenxuan@gmail.com
|
|
6
|
+
Empirical Wavelet Transform for 1D signals
|
|
7
|
+
Original paper:
|
|
8
|
+
Gilles, J., 2013. Empirical Wavelet Transform. IEEE Transactions on Signal Processing, 61(16), pp.3999–4010.
|
|
9
|
+
Available at: http://ieeexplore.ieee.org/lpdocs/epic03/wrapper.htm?arnumber=6522142.
|
|
10
|
+
Original Matlab toolbox: https://www.mathworks.com/matlabcentral/fileexchange/42141-empirical-wavelet-transforms
|
|
11
|
+
Original Code from: https://github.com/vrcarva/ewtpy
|
|
12
|
+
"""
|
|
13
|
+
import numpy as np
|
|
14
|
+
from scipy.ndimage.filters import gaussian_filter
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EWT(object):
|
|
19
|
+
"""Empirical Wavelet Transform with Class Interface."""
|
|
20
|
+
|
|
21
|
+
def __init__(self,
|
|
22
|
+
N: Optional[int] = 5,
|
|
23
|
+
log: Optional[float] = 0,
|
|
24
|
+
detect: Optional[str] = "locmax",
|
|
25
|
+
completion: Optional[float] = 0,
|
|
26
|
+
reg: Optional[str] = 'average',
|
|
27
|
+
lengthFilter: Optional[float] = 10,
|
|
28
|
+
sigmaFilter: Optional[float] = 5) -> None:
|
|
29
|
+
"""
|
|
30
|
+
:param N: Maximum number of modes (signal components) to detect and extract.
|
|
31
|
+
:param log: Set to 0 or 1 to indicate whether to operate in the logarithmic spectrum.
|
|
32
|
+
:param detect: Method for detecting boundaries in the Fourier domain ('locmax' or other detection methods).
|
|
33
|
+
:param completion: Set to 0 or 1 to indicate whether to complete the number of modes to N if fewer are detected.
|
|
34
|
+
:param reg: Regularization method applied to the filter bank ('none', 'gaussian', or 'average').
|
|
35
|
+
:param lengthFilter: Width of the filters used in regularization (for Gaussian or average filters).
|
|
36
|
+
:param sigmaFilter: Standard deviation for the Gaussian filter in the regularization step.
|
|
37
|
+
"""
|
|
38
|
+
self.N = N
|
|
39
|
+
self.log = log
|
|
40
|
+
self.detect = detect
|
|
41
|
+
self.completion = completion
|
|
42
|
+
self.reg = reg
|
|
43
|
+
self.lengthFilter = lengthFilter
|
|
44
|
+
self.sigmaFilter = sigmaFilter
|
|
45
|
+
|
|
46
|
+
def fit_transform(self, signal: np.ndarray, N: Optional[int] = None, return_all: Optional[bool] = False):
|
|
47
|
+
"""
|
|
48
|
+
Perform Empirical Wavelet Transform on the input signal.
|
|
49
|
+
|
|
50
|
+
:param signal: Input signal array to be decomposed.
|
|
51
|
+
:param N: Number of modes to extract. Defaults to the value specified during initialization.
|
|
52
|
+
:param return_all: If True, return the EWT decomposition, the filter bank, and the boundaries.
|
|
53
|
+
If False, return only the EWT decomposition.
|
|
54
|
+
|
|
55
|
+
:returns:
|
|
56
|
+
- ewt: The extracted modes from the signal.
|
|
57
|
+
- mfb: The filter bank applied in the Fourier domain (only if return_all is True).
|
|
58
|
+
- boundaries: Boundaries detected in the Fourier spectrum (only if return_all is True).
|
|
59
|
+
"""
|
|
60
|
+
N = self.N if N is None else N
|
|
61
|
+
# Compute the one-sided magnitude of the signal's Fourier transform
|
|
62
|
+
signal_ff = np.fft.fft(signal)
|
|
63
|
+
signal_ff = abs(signal_ff[0:int(np.ceil(signal_ff.size / 2))]) # one-sided magnitude
|
|
64
|
+
|
|
65
|
+
# Detect boundaries in the Fourier domain
|
|
66
|
+
boundaries = EWT_Boundaries_Detect(signal_ff, self.log, self.detect, N, self.reg,
|
|
67
|
+
self.lengthFilter, self.sigmaFilter)
|
|
68
|
+
boundaries = boundaries * np.pi / round(signal_ff.size)
|
|
69
|
+
|
|
70
|
+
# If fewer boundaries are detected, complete to reach N-1 if completion is enabled
|
|
71
|
+
if self.completion == 1 and len(boundaries) < N - 1:
|
|
72
|
+
boundaries = EWT_Boundaries_Completion(boundaries, N - 1)
|
|
73
|
+
|
|
74
|
+
# Extend the signal by mirroring to avoid boundary effects during filtering
|
|
75
|
+
ltemp = int(np.ceil(signal.size / 2))
|
|
76
|
+
fMirr = fmirror(ts=signal, sym=ltemp, end=1)
|
|
77
|
+
ffMirr = np.fft.fft(fMirr)
|
|
78
|
+
|
|
79
|
+
# Build the filter bank based on the detected boundaries
|
|
80
|
+
mfb = EWT_Meyer_FilterBank(boundaries, ffMirr.size)
|
|
81
|
+
|
|
82
|
+
# Filter the signal to extract each subband
|
|
83
|
+
ewt = np.zeros(mfb.shape)
|
|
84
|
+
for k in range(mfb.shape[1]):
|
|
85
|
+
ewt[:, k] = np.real(np.fft.ifft(np.conjugate(mfb[:, k]) * ffMirr))
|
|
86
|
+
ewt = ewt[ltemp - 1:-ltemp, :].T
|
|
87
|
+
|
|
88
|
+
# Return the requested data
|
|
89
|
+
if return_all is True:
|
|
90
|
+
return ewt, mfb, boundaries
|
|
91
|
+
else:
|
|
92
|
+
return ewt
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def ewt(signal, N: Optional[int] = 5,
|
|
96
|
+
log: Optional[float] = 0,
|
|
97
|
+
detect: Optional[str] = "locmax",
|
|
98
|
+
completion: Optional[float] = 0,
|
|
99
|
+
reg: Optional[str] = 'average',
|
|
100
|
+
lengthFilter: Optional[float] = 10,
|
|
101
|
+
sigmaFilter: Optional[float] = 5,
|
|
102
|
+
return_all: Optional[bool] = False):
|
|
103
|
+
"""
|
|
104
|
+
Empirical Wavelet Transform with Function Interface.
|
|
105
|
+
|
|
106
|
+
:param signal: The input signal to be decomposed.
|
|
107
|
+
:param N: Maximum number of modes (signal components) to detect and extract.
|
|
108
|
+
:param log: Set to 0 or 1 to indicate whether to work with the logarithmic spectrum.
|
|
109
|
+
:param detect: Method for detecting boundaries in the Fourier domain ('locmax' or other methods).
|
|
110
|
+
:param completion: Set to 0 or 1 to indicate whether to complete the number of modes to N if fewer are detected.
|
|
111
|
+
:param reg: Regularization method applied to the filter bank ('none', 'gaussian', or 'average').
|
|
112
|
+
:param lengthFilter: Width of the filters used in regularization (for Gaussian or average filters).
|
|
113
|
+
:param sigmaFilter: Standard deviation for the Gaussian filter in the regularization step.
|
|
114
|
+
:param return_all: If True, return the EWT decomposition, the filter bank, and the boundaries.
|
|
115
|
+
If False, return only the EWT decomposition.
|
|
116
|
+
|
|
117
|
+
:returns:
|
|
118
|
+
- ewt: The extracted modes from the signal.
|
|
119
|
+
- mfb: The filter bank in the Fourier domain (only if return_all is True).
|
|
120
|
+
- boundaries: Boundaries detected in the Fourier spectrum (only if return_all is True).
|
|
121
|
+
"""
|
|
122
|
+
# Compute the one-sided magnitude of the signal's Fourier transform
|
|
123
|
+
ff = np.fft.fft(signal)
|
|
124
|
+
ff = abs(ff[0:int(np.ceil(ff.size / 2))]) # one-sided magnitude
|
|
125
|
+
|
|
126
|
+
# Detect boundaries in the Fourier domain
|
|
127
|
+
boundaries = EWT_Boundaries_Detect(ff, log, detect, N, reg, lengthFilter, sigmaFilter)
|
|
128
|
+
boundaries = boundaries * np.pi / round(ff.size)
|
|
129
|
+
|
|
130
|
+
# If fewer boundaries are detected, complete to reach N-1 if completion is enabled
|
|
131
|
+
if completion == 1 and len(boundaries) < N - 1:
|
|
132
|
+
boundaries = EWT_Boundaries_Completion(boundaries, N - 1)
|
|
133
|
+
|
|
134
|
+
# Extend the signal by mirroring to avoid boundary effects during filtering
|
|
135
|
+
ltemp = int(np.ceil(signal.size / 2)) # Similar to MATLAB's round function
|
|
136
|
+
fMirr = fmirror(ts=signal, sym=ltemp, end=1)
|
|
137
|
+
ffMirr = np.fft.fft(fMirr)
|
|
138
|
+
|
|
139
|
+
# Build the filter bank based on the detected boundaries
|
|
140
|
+
mfb = EWT_Meyer_FilterBank(boundaries, ffMirr.size)
|
|
141
|
+
|
|
142
|
+
# Filter the signal to extract each subband
|
|
143
|
+
ewt = np.zeros(mfb.shape)
|
|
144
|
+
for k in range(mfb.shape[1]):
|
|
145
|
+
ewt[:, k] = np.real(np.fft.ifft(np.conjugate(mfb[:, k]) * ffMirr))
|
|
146
|
+
ewt = ewt[ltemp - 1:-ltemp, :].T
|
|
147
|
+
|
|
148
|
+
# Return the requested data
|
|
149
|
+
if return_all is True:
|
|
150
|
+
return ewt, mfb, boundaries
|
|
151
|
+
else:
|
|
152
|
+
return ewt
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def fmirror(ts: np.ndarray, sym: int, end: int):
|
|
156
|
+
"""Implements a signal mirroring expansion function."""
|
|
157
|
+
fMirr = np.append(np.flip(ts[0:sym - end], axis=0), ts)
|
|
158
|
+
fMirr = np.append(fMirr, np.flip(ts[-sym - end:-end], axis=0))
|
|
159
|
+
return fMirr
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def EWT_Boundaries_Detect(ff, log, detect, N, reg, lengthFilter, sigmaFilter):
|
|
163
|
+
"""
|
|
164
|
+
Segments the input function `ff` into a certain number of supports (frequency bands)
|
|
165
|
+
using different techniques for boundary detection and regularization.
|
|
166
|
+
|
|
167
|
+
:param ff: The function (signal) to segment (typically in the frequency domain).
|
|
168
|
+
:param log: 0 or 1, indicating whether to apply logarithmic transformation to the spectrum.
|
|
169
|
+
:param detect: The method used for boundary detection. Options include:
|
|
170
|
+
- 'locmax': Mid-point between consecutive local maxima (default).
|
|
171
|
+
- 'locmaxmin': Lowest minima between consecutive local maxima.
|
|
172
|
+
- 'locmaxminf': Lowest minima between consecutive local maxima of the original spectrum.
|
|
173
|
+
:param N: Maximum number of supports (modes or signal components) to detect.
|
|
174
|
+
:param reg: The regularization method to apply to the spectrum. Options include:
|
|
175
|
+
- 'none': No regularization.
|
|
176
|
+
- 'gaussian': Gaussian filtering with width `lengthFilter` and standard deviation `sigmaFilter`.
|
|
177
|
+
- 'average': Average filtering with width `lengthFilter`.
|
|
178
|
+
:param lengthFilter: The width of the Gaussian or average filter for regularization.
|
|
179
|
+
:param sigmaFilter: The standard deviation of the Gaussian filter for regularization.
|
|
180
|
+
|
|
181
|
+
:returns:
|
|
182
|
+
- boundaries: A list of detected boundaries (in terms of indices).
|
|
183
|
+
|
|
184
|
+
This function detects boundaries in the frequency domain based on different detection
|
|
185
|
+
methods. The spectrum can be regularized using Gaussian or average filters, which smooths
|
|
186
|
+
out the spectrum before detection.
|
|
187
|
+
|
|
188
|
+
- The 'locmax' method detects the mid-points between consecutive local maxima.
|
|
189
|
+
- The 'locmaxmin' method extracts the lowest minima between consecutive maxima.
|
|
190
|
+
- The 'locmaxminf' method uses the regularized spectrum for maxima detection and the original spectrum for minima.
|
|
191
|
+
|
|
192
|
+
"""
|
|
193
|
+
# Apply log transformation if needed
|
|
194
|
+
if log == 1:
|
|
195
|
+
ff = np.log(ff)
|
|
196
|
+
|
|
197
|
+
# Apply regularization if needed
|
|
198
|
+
if reg == 'average':
|
|
199
|
+
regFilter = np.ones(lengthFilter) / lengthFilter
|
|
200
|
+
presig = np.convolve(ff, regFilter, mode='same') # Averaging filter
|
|
201
|
+
|
|
202
|
+
elif reg == 'gaussian':
|
|
203
|
+
regFilter = np.zeros(lengthFilter)
|
|
204
|
+
regFilter[regFilter.size // 2] = 1 # Ensure center is set for Gaussian filtering
|
|
205
|
+
presig = np.convolve(ff, gaussian_filter(regFilter, sigmaFilter), mode='same') # Gaussian filter
|
|
206
|
+
else:
|
|
207
|
+
presig = ff # No regularization applied
|
|
208
|
+
|
|
209
|
+
# Boundary detection based on the selected method
|
|
210
|
+
if detect == "locmax":
|
|
211
|
+
boundaries = LocalMax(presig, N) # Mid-point between consecutive local maxima
|
|
212
|
+
|
|
213
|
+
elif detect == "locmaxmin":
|
|
214
|
+
boundaries = LocalMaxMin(presig, N) # Lowest local minima between selected maxima
|
|
215
|
+
|
|
216
|
+
elif detect == "locmaxminf":
|
|
217
|
+
boundaries = LocalMaxMin(presig, N, fm=ff) # Minima on the original spectrum between maxima on regularized spectrum
|
|
218
|
+
|
|
219
|
+
else:
|
|
220
|
+
raise ValueError("Invalid detection method provided.")
|
|
221
|
+
|
|
222
|
+
return boundaries + 1 # Increment indices by 1 to account for zero-based indexing
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def LocalMax(ff, N):
|
|
227
|
+
"""
|
|
228
|
+
Segments the input function `ff` into a maximum of `N` bands by locating
|
|
229
|
+
the N largest local maxima and calculating the middle points between them.
|
|
230
|
+
|
|
231
|
+
:param ff: The input function (signal) to segment.
|
|
232
|
+
:param N: The maximum number of bands (supports) to detect.
|
|
233
|
+
|
|
234
|
+
:returns:
|
|
235
|
+
- bound: A list of indices representing the detected boundaries between bands.
|
|
236
|
+
|
|
237
|
+
This function works by identifying local maxima in the input function `ff`,
|
|
238
|
+
selecting the `N` largest maxima, and then computing the midpoint between each
|
|
239
|
+
consecutive maximum to define the segment boundaries.
|
|
240
|
+
"""
|
|
241
|
+
N = N - 1
|
|
242
|
+
locmax = np.zeros(ff.size) # Initialize array to store local maxima
|
|
243
|
+
locmin = max(ff) * np.ones(ff.size) # Initialize array for local minima
|
|
244
|
+
|
|
245
|
+
# Loop through the signal to find local maxima and minima
|
|
246
|
+
for i in np.arange(1, ff.size - 1):
|
|
247
|
+
if ff[i - 1] < ff[i] and ff[i] > ff[i + 1]:
|
|
248
|
+
locmax[i] = ff[i] # Mark local maxima
|
|
249
|
+
if ff[i - 1] > ff[i] and ff[i] <= ff[i + 1]:
|
|
250
|
+
locmin[i] = ff[i] # Mark local minima
|
|
251
|
+
|
|
252
|
+
N = min(N, locmax.size) # Ensure N does not exceed the number of available maxima
|
|
253
|
+
# Find the indices of the N largest maxima
|
|
254
|
+
maxidxs = np.sort(locmax.argsort()[::-1][:N])
|
|
255
|
+
|
|
256
|
+
# Calculate the midpoints between consecutive maxima to define the boundaries
|
|
257
|
+
bound = np.zeros(N)
|
|
258
|
+
for i in range(N):
|
|
259
|
+
if i == 0:
|
|
260
|
+
a = 0
|
|
261
|
+
else:
|
|
262
|
+
a = maxidxs[i - 1]
|
|
263
|
+
bound[i] = (a + maxidxs[i]) / 2 # Calculate midpoint
|
|
264
|
+
|
|
265
|
+
return bound
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def LocalMaxMin(f, N, fm=0):
|
|
269
|
+
"""
|
|
270
|
+
Segments the input function `f` into a maximum of `N` bands by detecting
|
|
271
|
+
the lowest local minima between the `N` largest local maxima. If `fm` is provided,
|
|
272
|
+
local maxima are computed on `f` and local minima are computed on `fm`. Otherwise,
|
|
273
|
+
both maxima and minima are computed on `f`.
|
|
274
|
+
|
|
275
|
+
This is useful when you want to compute the maxima on a regularized version of
|
|
276
|
+
your signal (f) while detecting the "true" minima on a different version (fm).
|
|
277
|
+
|
|
278
|
+
:param f: The function (signal) to segment.
|
|
279
|
+
:param N: The maximum number of bands (supports) to detect.
|
|
280
|
+
:param fm: (Optional) The function on which local minima will be computed.
|
|
281
|
+
If not provided, local minima will be computed on `f`.
|
|
282
|
+
|
|
283
|
+
:returns:
|
|
284
|
+
- bound: A list of indices representing the detected boundaries between bands.
|
|
285
|
+
|
|
286
|
+
This function detects local maxima and minima in the signal and then calculates
|
|
287
|
+
boundaries based on the N largest maxima and the lowest minima between them.
|
|
288
|
+
"""
|
|
289
|
+
# Initialize array to store local maxima
|
|
290
|
+
locmax = np.zeros(f.size)
|
|
291
|
+
|
|
292
|
+
# If fm is not provided, use f for both maxima and minima detection
|
|
293
|
+
if type(fm) == int:
|
|
294
|
+
f2 = f
|
|
295
|
+
else:
|
|
296
|
+
f2 = fm
|
|
297
|
+
|
|
298
|
+
# Initialize array for local minima
|
|
299
|
+
locmin = max(f2) * np.ones(f2.size)
|
|
300
|
+
|
|
301
|
+
# Detect local minima and maxima in the signal
|
|
302
|
+
for i in np.arange(1, f.size - 1):
|
|
303
|
+
if (f[i - 1] < f[i]) and (f[i] > f[i + 1]):
|
|
304
|
+
locmax[i] = f[i] # Mark local maxima
|
|
305
|
+
if (f2[i - 1] > f2[i]) and (f2[i] < f2[i + 1]):
|
|
306
|
+
locmin[i] = f2[i] # Mark local minima
|
|
307
|
+
|
|
308
|
+
# Initialize the boundaries array
|
|
309
|
+
bound = np.zeros(N)
|
|
310
|
+
|
|
311
|
+
if N != -1:
|
|
312
|
+
N = N - 1
|
|
313
|
+
# Keep the N largest maxima
|
|
314
|
+
Imax = np.sort(locmax.argsort()[::-1][:N])
|
|
315
|
+
|
|
316
|
+
# Detect the lowest minima between two consecutive maxima
|
|
317
|
+
for i in range(N):
|
|
318
|
+
if i == 0:
|
|
319
|
+
a = 1
|
|
320
|
+
else:
|
|
321
|
+
a = Imax[i - 1]
|
|
322
|
+
|
|
323
|
+
# Sort minima between the current and previous maxima
|
|
324
|
+
lmin = np.sort(locmin[a:Imax[i]])
|
|
325
|
+
ind = np.argsort(locmin[a:Imax[i]])
|
|
326
|
+
|
|
327
|
+
# Find the true minimum
|
|
328
|
+
tmpp = lmin[0]
|
|
329
|
+
n = 0
|
|
330
|
+
if n < len(lmin):
|
|
331
|
+
n = 1
|
|
332
|
+
while (n < len(lmin)) and (tmpp == lmin[n]):
|
|
333
|
+
n += 1
|
|
334
|
+
|
|
335
|
+
# Set the boundary to the midpoint of the smallest minima
|
|
336
|
+
bound[i] = a + ind[n // 2] - 1
|
|
337
|
+
else:
|
|
338
|
+
# Case when N is set to -1, meaning no limit on the number of bands
|
|
339
|
+
k = 0
|
|
340
|
+
for i in range(locmin.size):
|
|
341
|
+
if locmin[i] < max(f2):
|
|
342
|
+
bound[k] = i - 1
|
|
343
|
+
k += 1
|
|
344
|
+
|
|
345
|
+
return bound
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def EWT_Boundaries_Completion(boundaries, NT):
|
|
349
|
+
"""
|
|
350
|
+
Completes the boundaries vector to ensure a total of `NT` boundaries by
|
|
351
|
+
equally splitting the last band (highest frequencies) between the final boundary
|
|
352
|
+
and π.
|
|
353
|
+
|
|
354
|
+
:param boundaries: The initial boundaries vector to be completed.
|
|
355
|
+
:param NT: The total number of boundaries desired.
|
|
356
|
+
|
|
357
|
+
:returns:
|
|
358
|
+
- boundaries: The completed boundaries vector.
|
|
359
|
+
|
|
360
|
+
This function adds additional boundaries by uniformly dividing the highest frequency
|
|
361
|
+
band (i.e., the region from the last boundary to π) into equal parts, such that the total
|
|
362
|
+
number of boundaries reaches `NT`.
|
|
363
|
+
"""
|
|
364
|
+
# Calculate the number of additional boundaries needed
|
|
365
|
+
Nd = NT - len(boundaries)
|
|
366
|
+
|
|
367
|
+
# Calculate the width of each new segment to be added
|
|
368
|
+
deltaw = (np.pi - boundaries[-1]) / (Nd + 1)
|
|
369
|
+
|
|
370
|
+
# Add the new boundaries to the vector
|
|
371
|
+
for k in range(Nd):
|
|
372
|
+
boundaries = np.append(boundaries, boundaries[-1] + deltaw)
|
|
373
|
+
|
|
374
|
+
return boundaries
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def EWT_Meyer_FilterBank(boundaries, Nsig):
|
|
378
|
+
"""
|
|
379
|
+
Generates the filter bank (scaling function + wavelets) corresponding to the
|
|
380
|
+
provided set of frequency segments.
|
|
381
|
+
|
|
382
|
+
:param boundaries: A vector containing the boundaries of frequency segments.
|
|
383
|
+
Note that 0 and π should NOT be included in this vector.
|
|
384
|
+
:param Nsig: The length of the input signal.
|
|
385
|
+
|
|
386
|
+
:returns:
|
|
387
|
+
- mfb: A matrix where each column represents a filter in the Fourier domain.
|
|
388
|
+
The first column corresponds to the scaling function, and the
|
|
389
|
+
subsequent columns represent the successive wavelets.
|
|
390
|
+
|
|
391
|
+
This function generates a set of Meyer wavelets and a scaling function in the
|
|
392
|
+
Fourier domain based on the provided frequency boundaries.
|
|
393
|
+
"""
|
|
394
|
+
Npic = len(boundaries) # Number of frequency boundaries
|
|
395
|
+
# Compute gamma, which controls the transition width of the wavelets
|
|
396
|
+
gamma = 1
|
|
397
|
+
for k in range(Npic - 1):
|
|
398
|
+
r = (boundaries[k + 1] - boundaries[k]) / (boundaries[k + 1] + boundaries[k])
|
|
399
|
+
if r < gamma:
|
|
400
|
+
gamma = r
|
|
401
|
+
r = (np.pi - boundaries[Npic - 1]) / (np.pi + boundaries[Npic - 1])
|
|
402
|
+
if r < gamma:
|
|
403
|
+
gamma = r
|
|
404
|
+
gamma = (1 - 1 / Nsig) * gamma # Ensure gamma is strictly less than the minimum
|
|
405
|
+
|
|
406
|
+
# Initialize the filter bank matrix
|
|
407
|
+
mfb = np.zeros([Nsig, Npic + 1])
|
|
408
|
+
|
|
409
|
+
# EWT_Meyer_Scaling - Generate the scaling function
|
|
410
|
+
Mi = int(np.floor(Nsig / 2)) # Half the signal length
|
|
411
|
+
w = np.fft.fftshift(np.linspace(0, 2 * np.pi - 2 * np.pi / Nsig, num=Nsig)) # Frequency grid
|
|
412
|
+
w[0:Mi] = -2 * np.pi + w[0:Mi] # Shift the negative frequencies
|
|
413
|
+
aw = abs(w) # Absolute frequency values
|
|
414
|
+
yms = np.zeros(Nsig) # Initialize the scaling function
|
|
415
|
+
an = 1. / (2 * gamma * boundaries[0])
|
|
416
|
+
pbn = (1. + gamma) * boundaries[0]
|
|
417
|
+
mbn = (1. - gamma) * boundaries[0]
|
|
418
|
+
|
|
419
|
+
# Generate the scaling function based on the first boundary
|
|
420
|
+
for k in range(Nsig):
|
|
421
|
+
if aw[k] <= mbn:
|
|
422
|
+
yms[k] = 1
|
|
423
|
+
elif ((aw[k] >= mbn) and (aw[k] <= pbn)):
|
|
424
|
+
yms[k] = np.cos(np.pi * EWT_beta(an * (aw[k] - mbn)) / 2)
|
|
425
|
+
|
|
426
|
+
yms = np.fft.ifftshift(yms) # Shift the scaling function back
|
|
427
|
+
mfb[:, 0] = yms # Store the scaling function in the filter bank
|
|
428
|
+
|
|
429
|
+
# Generate the wavelets for the remaining boundaries
|
|
430
|
+
for k in range(Npic - 1):
|
|
431
|
+
mfb[:, k + 1] = EWT_Meyer_Wavelet(boundaries[k], boundaries[k + 1], gamma, Nsig)
|
|
432
|
+
|
|
433
|
+
# Generate the final wavelet for the last boundary segment (up to π)
|
|
434
|
+
mfb[:, Npic] = EWT_Meyer_Wavelet(boundaries[Npic - 1], np.pi, gamma, Nsig)
|
|
435
|
+
|
|
436
|
+
return mfb
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def EWT_beta(x):
|
|
440
|
+
"""
|
|
441
|
+
Beta = EWT_beta(x)
|
|
442
|
+
function used in the construction of Meyer's wavelet
|
|
443
|
+
"""
|
|
444
|
+
if x < 0:
|
|
445
|
+
bm = 0
|
|
446
|
+
elif x > 1:
|
|
447
|
+
bm = 1
|
|
448
|
+
else:
|
|
449
|
+
bm = (x ** 4) * (35. - 84. * x + 70. * (x ** 2) - 20. * (x ** 3))
|
|
450
|
+
return bm
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def EWT_Meyer_Wavelet(wn, wm, gamma, Nsig):
|
|
454
|
+
"""
|
|
455
|
+
Generates the 1D Meyer wavelet in the Fourier domain associated with the
|
|
456
|
+
scale segment [wn, wm] with a transition ratio `gamma`.
|
|
457
|
+
|
|
458
|
+
:param wn: The lower boundary of the frequency segment.
|
|
459
|
+
:param wm: The upper boundary of the frequency segment.
|
|
460
|
+
:param gamma: The transition ratio that controls the width of the transition zones
|
|
461
|
+
between frequency bands.
|
|
462
|
+
:param Nsig: The number of points in the signal.
|
|
463
|
+
|
|
464
|
+
:returns:
|
|
465
|
+
- ymw: The Fourier transform of the wavelet for the frequency band [wn, wm].
|
|
466
|
+
|
|
467
|
+
This function creates a Meyer wavelet in the Fourier domain with smooth transitions
|
|
468
|
+
between frequency bands defined by `wn` and `wm`.
|
|
469
|
+
"""
|
|
470
|
+
# Compute the frequency grid
|
|
471
|
+
Mi = int(np.floor(Nsig / 2)) # Half the signal length
|
|
472
|
+
w = np.fft.fftshift(np.linspace(0, 2 * np.pi - 2 * np.pi / Nsig, num=Nsig)) # Frequency grid
|
|
473
|
+
w[0:Mi] = -2 * np.pi + w[0:Mi] # Shift the negative frequencies
|
|
474
|
+
aw = abs(w) # Absolute frequency values
|
|
475
|
+
|
|
476
|
+
# Initialize the wavelet in the Fourier domain
|
|
477
|
+
ymw = np.zeros(Nsig)
|
|
478
|
+
|
|
479
|
+
# Parameters for the Meyer wavelet transitions
|
|
480
|
+
an = 1. / (2 * gamma * wn)
|
|
481
|
+
am = 1. / (2 * gamma * wm)
|
|
482
|
+
pbn = (1. + gamma) * wn
|
|
483
|
+
mbn = (1. - gamma) * wn
|
|
484
|
+
pbm = (1. + gamma) * wm
|
|
485
|
+
mbm = (1. - gamma) * wm
|
|
486
|
+
|
|
487
|
+
# Construct the wavelet in the Fourier domain based on the segment boundaries
|
|
488
|
+
for k in range(Nsig):
|
|
489
|
+
if (aw[k] >= pbn) and (aw[k] <= mbm): # Main passband
|
|
490
|
+
ymw[k] = 1
|
|
491
|
+
elif (aw[k] >= mbm) and (aw[k] <= pbm): # Smooth transition in upper boundary
|
|
492
|
+
ymw[k] = np.cos(np.pi * EWT_beta(am * (aw[k] - mbm)) / 2)
|
|
493
|
+
elif (aw[k] >= mbn) and (aw[k] <= pbn): # Smooth transition in lower boundary
|
|
494
|
+
ymw[k] = np.sin(np.pi * EWT_beta(an * (aw[k] - mbn)) / 2)
|
|
495
|
+
|
|
496
|
+
# Shift the wavelet back to the normal order
|
|
497
|
+
ymw = np.fft.ifftshift(ymw)
|
|
498
|
+
|
|
499
|
+
return ymw
|
|
500
|
+
|
pysdkit/utils/__init__.py
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
#
|
|
2
|
-
from ._fft import fft, ifft, fftshift, ifftshift
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
from .mirror import fmirror
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
from .hilbert import hilbert_transform, hilbert_real, hilbert_imaginary
|
|
9
|
-
from .hilbert import plot_hilbert, plot_hilbert_complex_plane
|
|
10
|
-
|
|
11
|
-
from .process import normalize_signal
|
|
12
|
-
from .process import common_dtype
|
|
13
|
-
from .process import not_duplicate
|
|
14
|
-
|
|
15
|
-
from .process import find_zero_crossings
|
|
16
|
-
from .process import get_timeline
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
from ._differ import differ
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
from ._smooth1d import simple_moving_average, weighted_moving_average
|
|
23
|
-
from ._smooth1d import gaussian_smoothing, savgol_smoothing, exponential_smoothing
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
from ._function import max_min_normalization
|
|
27
|
-
# Z-score
|
|
28
|
-
from ._function import z_score_normalization
|
|
29
|
-
#
|
|
30
|
-
from ._function import max_absolute_normalization
|
|
31
|
-
#
|
|
32
|
-
from ._function import log_transformation
|
|
33
|
-
#
|
|
34
|
-
from ._function import decimal_scaling_normalization
|
|
1
|
+
# Fourier Transform
|
|
2
|
+
from ._fft import fft, ifft, fftshift, ifftshift # 傅里叶变换的正变换、逆变换、频谱移动和逆移动
|
|
3
|
+
|
|
4
|
+
# Signal mirroring extension
|
|
5
|
+
from .mirror import fmirror # 信号的镜像扩展
|
|
6
|
+
|
|
7
|
+
# Various functions for Hilbert Transform
|
|
8
|
+
from .hilbert import hilbert_transform, hilbert_real, hilbert_imaginary # 希尔伯特变换的相关函数,包括获取实部和虚部
|
|
9
|
+
from .hilbert import plot_hilbert, plot_hilbert_complex_plane # 绘制希尔伯特变换结果的相关函数
|
|
10
|
+
|
|
11
|
+
from .process import normalize_signal # 归一化信号
|
|
12
|
+
from .process import common_dtype # 检查数据的通用数据类型
|
|
13
|
+
from .process import not_duplicate # 检查数据是否没有重复
|
|
14
|
+
|
|
15
|
+
from .process import find_zero_crossings # 查找信号的零交叉点
|
|
16
|
+
from .process import get_timeline # 获取信号的时间轴
|
|
17
|
+
|
|
18
|
+
# Algorithm for discrete signal differencing
|
|
19
|
+
from ._differ import differ # 实现离散信号差分的算法
|
|
20
|
+
|
|
21
|
+
# Functions for 1D signal smoothing
|
|
22
|
+
from ._smooth1d import simple_moving_average, weighted_moving_average # 实现一维信号的简单移动平均和平滑移动平均
|
|
23
|
+
from ._smooth1d import gaussian_smoothing, savgol_smoothing, exponential_smoothing # 高斯平滑、Savitzky-Golay平滑和指数平滑
|
|
24
|
+
|
|
25
|
+
# Min-max normalization
|
|
26
|
+
from ._function import max_min_normalization # 最大最小归一化
|
|
27
|
+
# Z-score standardization
|
|
28
|
+
from ._function import z_score_normalization # Z-score 标准化
|
|
29
|
+
# Max-absolute normalization
|
|
30
|
+
from ._function import max_absolute_normalization # 最大绝对值标准化
|
|
31
|
+
# Logarithmic transformation
|
|
32
|
+
from ._function import log_transformation # 对数变换
|
|
33
|
+
# Decimal scaling normalization
|
|
34
|
+
from ._function import decimal_scaling_normalization # 小数定标标准化
|
|
35
|
+
|
pysdkit/vmd/_vmd_c.py
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
Created on Sat Mar 4 11:59:21 2024
|
|
4
4
|
@author: Whenxuan Wang
|
|
5
5
|
@email: wwhenxuan@gmail.com
|
|
6
|
+
Original paper: Dragomiretskiy, K. and Zosso, D. (2014) ‘Variational Mode Decomposition’,
|
|
7
|
+
IEEE Transactions on Signal Processing, 62(3), pp. 531–544. doi: 10.1109/TSP.2013.2288675.
|
|
6
8
|
"""
|
|
7
9
|
import numpy as np
|
|
8
10
|
from typing import Optional, List
|
|
@@ -12,11 +14,7 @@ from ..plot import plot_IMFs
|
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class VMD(Base):
|
|
15
|
-
"""
|
|
16
|
-
Variational mode decomposition, object-oriented interface.
|
|
17
|
-
Dragomiretskiy, K. and Zosso, D. (2014) ‘Variational Mode Decomposition’,
|
|
18
|
-
IEEE Transactions on Signal Processing, 62(3), pp. 531–544. doi: 10.1109/TSP.2013.2288675.
|
|
19
|
-
"""
|
|
17
|
+
"""Variational mode decomposition, object-oriented interface."""
|
|
20
18
|
|
|
21
19
|
def __init__(self, alpha: int, K: int, tau: float, init: str = 'uniform', DC: bool = False,
|
|
22
20
|
max_iter: int = 500, tol: float = 1e-6):
|
pysdkit/vmd/_vmd_f.py
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
Created on Sat Mar 4 11:59:21 2024
|
|
4
4
|
@author: Whenxuan Wang
|
|
5
5
|
@email: wwhenxuan@gmail.com
|
|
6
|
+
Original paper: Dragomiretskiy, K. and Zosso, D. (2014) ‘Variational Mode Decomposition’,
|
|
7
|
+
IEEE Transactions on Signal Processing, 62(3), pp. 531–544. doi: 10.1109/TSP.2013.2288675.
|
|
6
8
|
"""
|
|
7
9
|
import numpy as np
|
|
8
10
|
from ..utils import fft, ifft, fftshift, ifftshift, fmirror
|
|
@@ -12,9 +14,6 @@ def vmd(signal: np.array, alpha: int, K: int, tau: float, init: str = 'uniform',
|
|
|
12
14
|
max_iter: int = 500, tol: float = 1e-6):
|
|
13
15
|
"""
|
|
14
16
|
Variational mode decomposition, object-oriented interface.
|
|
15
|
-
Original paper:
|
|
16
|
-
Dragomiretskiy, K. and Zosso, D. (2014) ‘Variational Mode Decomposition’,
|
|
17
|
-
IEEE Transactions on Signal Processing, 62(3), pp. 531–544. doi: 10.1109/TSP.2013.2288675.
|
|
18
17
|
:param signal: the time domain signal (1D numpy array) to be decomposed
|
|
19
18
|
:param alpha: the balancing parameter of the data-fidelity constraint
|
|
20
19
|
:param K: the number of modes to be recovered
|
pysdkit/ewt/_ewt.py
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
Created on Tue Dec 18 11:45:32 2018
|
|
4
|
-
Empirical Wavelet Transform implementation for 1D signals
|
|
5
|
-
Original paper:
|
|
6
|
-
Gilles, J., 2013. Empirical Wavelet Transform. IEEE Transactions on Signal Processing, 61(16), pp.3999–4010.
|
|
7
|
-
Available at: http://ieeexplore.ieee.org/lpdocs/epic03/wrapper.htm?arnumber=6522142.
|
|
8
|
-
Original Matlab toolbox: https://www.mathworks.com/matlabcentral/fileexchange/42141-empirical-wavelet-transforms
|
|
9
|
-
|
|
10
|
-
@author: Vinícius Rezende Carvalho
|
|
11
|
-
Programa de pós graduação em engenharia elétrica - PPGEE UFMG
|
|
12
|
-
Universidade Federal de Minas Gerais - Belo Horizonte, Brazil
|
|
13
|
-
Núcleo de Neurociências - NNC
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
import numpy as np
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# %EWT functions
|
|
20
|
-
def EWT1D(f, N=5, log=0, detect="locmax", completion=0, reg='average', lengthFilter=10, sigmaFilter=5):
|
|
21
|
-
"""
|
|
22
|
-
=========================================================================
|
|
23
|
-
ewt, mfb ,boundaries = EWT1D(f, N = 5, log = 0,detect = "locmax", completion = 0, reg = 'average', lengthFilter = 10,sigmaFilter = 5):
|
|
24
|
-
|
|
25
|
-
Perform the Empirical Wavelet Transform of f over N scales. See
|
|
26
|
-
also the documentation of EWT_Boundaries_Detect for more details about
|
|
27
|
-
the available methods and their parameters.
|
|
28
|
-
|
|
29
|
-
Inputs:
|
|
30
|
-
-f: the 1D input signal
|
|
31
|
-
Optional Inputs:
|
|
32
|
-
-log: 0 or 1 to indicate if we want to work with
|
|
33
|
-
the log spectrum
|
|
34
|
-
-method: 'locmax','locmaxmin','locmaxminf'
|
|
35
|
-
-reg: 'none','gaussian','average'
|
|
36
|
-
-lengthFilter: width of the above filters (Gaussian or average)
|
|
37
|
-
-sigmaFilter: standard deviation of the above Gaussian filter
|
|
38
|
-
-N: maximum number of supports (modes or signal components)
|
|
39
|
-
-completion: 0 or 1 to indicate if we try to complete
|
|
40
|
-
or not the number of modes if the detection
|
|
41
|
-
find a lower number of mode than N
|
|
42
|
-
Outputs:
|
|
43
|
-
-ewt: contains first the low frequency component and
|
|
44
|
-
then the successives frequency subbands
|
|
45
|
-
-mfb: contains the filter bank (in the Fourier domain)
|
|
46
|
-
-boundaries: vector containing the set of boundaries corresponding
|
|
47
|
-
to the Fourier line segmentation (normalized between
|
|
48
|
-
0 and Pi)
|
|
49
|
-
Original MATLAB Version:
|
|
50
|
-
Author: Jerome Gilles
|
|
51
|
-
Institution: UCLA - Department of Mathematics
|
|
52
|
-
Year: 2013
|
|
53
|
-
Version: 2.0
|
|
54
|
-
|
|
55
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
56
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
57
|
-
Núcleo de Neurociências
|
|
58
|
-
% =========================================================================
|
|
59
|
-
"""
|
|
60
|
-
# signal spectrum
|
|
61
|
-
ff = np.fft.fft(f)
|
|
62
|
-
ff = abs(ff[0:int(np.ceil(ff.size / 2))]) # one-sided magnitude
|
|
63
|
-
# extract boundaries of Fourier Segments
|
|
64
|
-
boundaries = EWT_Boundaries_Detect(ff, log, detect, N, reg, lengthFilter, sigmaFilter)
|
|
65
|
-
boundaries = boundaries * np.pi / round(ff.size)
|
|
66
|
-
|
|
67
|
-
if completion == 1 and len(boundaries) < N - 1:
|
|
68
|
-
boundaries = EWT_Boundaries_Completion(boundaries, N - 1)
|
|
69
|
-
# Filtering
|
|
70
|
-
# extend the signal by mirroring to deal with boundaries
|
|
71
|
-
ltemp = int(np.ceil(f.size / 2)) # to behave the same as matlab's round
|
|
72
|
-
fMirr = np.append(np.flip(f[0:ltemp - 1], axis=0), f)
|
|
73
|
-
fMirr = np.append(fMirr, np.flip(f[-ltemp - 1:-1], axis=0))
|
|
74
|
-
ffMirr = np.fft.fft(fMirr)
|
|
75
|
-
|
|
76
|
-
# build the corresponding filter bank
|
|
77
|
-
mfb = EWT_Meyer_FilterBank(boundaries, ffMirr.size)
|
|
78
|
-
|
|
79
|
-
# filter the signal to extract each subband
|
|
80
|
-
ewt = np.zeros(mfb.shape)
|
|
81
|
-
for k in range(mfb.shape[1]):
|
|
82
|
-
ewt[:, k] = np.real(np.fft.ifft(np.conjugate(mfb[:, k]) * ffMirr))
|
|
83
|
-
ewt = ewt[ltemp - 1:-ltemp, :]
|
|
84
|
-
|
|
85
|
-
return ewt, mfb, boundaries
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def EWT_Boundaries_Detect(ff, log, detect, N, reg, lengthFilter, sigmaFilter):
|
|
89
|
-
"""This function segments f into a certain amount of supports by using different technics:
|
|
90
|
-
- middle point between consecutive local maxima (default),
|
|
91
|
-
- lowest minima between consecutive local maxima (locmaxmin),
|
|
92
|
-
- lowest minima between consecutive local maxima of original spectrum (locmaxminf),
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Regularized version of the spectrum can be obtained by the
|
|
96
|
-
following methods:
|
|
97
|
-
- Gaussian filtering (its parameters are filter of width
|
|
98
|
-
lengthFilter and standard deviation sigmaFilter)scalesp
|
|
99
|
-
- Average filtering (its parameters are filter of width
|
|
100
|
-
lengthFilter)
|
|
101
|
-
|
|
102
|
-
Note: the detected boundaries are given in term of indices
|
|
103
|
-
|
|
104
|
-
Inputs:
|
|
105
|
-
-f: the function to segment
|
|
106
|
-
Optional parameters:
|
|
107
|
-
-log: 0 or 1 to indicate if we want to work with
|
|
108
|
-
the log of the ff
|
|
109
|
-
-reg: 'none','gaussian','average'
|
|
110
|
-
-lengthFilter: width of the above filters (Gaussian or average)
|
|
111
|
-
-sigmaFilter: standard deviation of the above Gaussian filter
|
|
112
|
-
-N: maximum number of supports (modes or signal components)
|
|
113
|
-
-completion: 0 or 1 to indicate if we try to complete
|
|
114
|
-
or not the number of modes if the detection
|
|
115
|
-
find a lower number of mode than N
|
|
116
|
-
|
|
117
|
-
Outputs:
|
|
118
|
-
-boundaries: list of detected boundaries
|
|
119
|
-
|
|
120
|
-
TODO Preprocessing steps not yet implemented
|
|
121
|
-
"""
|
|
122
|
-
from scipy.ndimage.filters import gaussian_filter
|
|
123
|
-
# apply log if needed
|
|
124
|
-
if log == 1:
|
|
125
|
-
ff = np.log(ff)
|
|
126
|
-
|
|
127
|
-
# Global trend removal - TODO
|
|
128
|
-
|
|
129
|
-
# Regularization
|
|
130
|
-
if reg == 'average':
|
|
131
|
-
regFilter = np.ones(lengthFilter) / lengthFilter
|
|
132
|
-
presig = np.convolve(ff, regFilter,
|
|
133
|
-
mode='same') # for even lenght, numpy's convolve is shifted when compared with MATLAB's
|
|
134
|
-
|
|
135
|
-
elif reg == 'gaussian':
|
|
136
|
-
regFilter = np.zeros(lengthFilter)
|
|
137
|
-
regFilter[regFilter.size // 2] = 1 # prefer odd filter lengths - otherwise the gaussian is skewed
|
|
138
|
-
presig = np.convolve(ff, gaussian_filter(regFilter, sigmaFilter), mode='same')
|
|
139
|
-
else:
|
|
140
|
-
presig = ff
|
|
141
|
-
|
|
142
|
-
# Boundaries detection
|
|
143
|
-
if detect == "locmax": # Mid-point between two consecutive local maxima computed on the regularized spectrum
|
|
144
|
-
boundaries = LocalMax(presig, N)
|
|
145
|
-
|
|
146
|
-
elif detect == "locmaxmin": # extract the lowest local minima between two selected local maxima
|
|
147
|
-
boundaries = LocalMaxMin(presig, N)
|
|
148
|
-
|
|
149
|
-
elif detect == "locmaxminf": # We extract the lowest local minima on the original spectrum between
|
|
150
|
-
# two local maxima selected on the regularized signal
|
|
151
|
-
boundaries = LocalMaxMin(presig, N, fm=ff)
|
|
152
|
-
|
|
153
|
-
# elif detect == "adaptivereg": #TODO
|
|
154
|
-
|
|
155
|
-
return boundaries + 1
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def LocalMax(ff, N):
|
|
159
|
-
"""
|
|
160
|
-
================================================================
|
|
161
|
-
bound = LocalMax(f,N)
|
|
162
|
-
|
|
163
|
-
This function segments f into a maximum of N supports by taking
|
|
164
|
-
the middle point between the N largest local maxima.
|
|
165
|
-
Note: the detected boundaries are given in term of indices
|
|
166
|
-
|
|
167
|
-
Inputs:
|
|
168
|
-
-f: the function to segment
|
|
169
|
-
-N: maximal number of bands
|
|
170
|
-
|
|
171
|
-
Outputs:
|
|
172
|
-
-bound: list of detected boundaries
|
|
173
|
-
|
|
174
|
-
Original MATLAB version:
|
|
175
|
-
Author: Jerome Gilles + Kathryn Heal
|
|
176
|
-
Institution: UCLA - Department of Mathematics
|
|
177
|
-
Year: 2013
|
|
178
|
-
Version: 1.0
|
|
179
|
-
|
|
180
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
181
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
182
|
-
Núcleo de Neurociências
|
|
183
|
-
%===============================================================
|
|
184
|
-
"""
|
|
185
|
-
N = N - 1
|
|
186
|
-
locmax = np.zeros(ff.size)
|
|
187
|
-
locmin = max(ff) * np.ones(ff.size)
|
|
188
|
-
for i in np.arange(1, ff.size - 1):
|
|
189
|
-
if ff[i - 1] < ff[i] and ff[i] > ff[i + 1]:
|
|
190
|
-
locmax[i] = ff[i]
|
|
191
|
-
if ff[i - 1] > ff[i] and ff[i] <= ff[i + 1]:
|
|
192
|
-
locmin[i] = ff[i]
|
|
193
|
-
N = min(N, locmax.size)
|
|
194
|
-
# keep the N-th highest maxima
|
|
195
|
-
maxidxs = np.sort(locmax.argsort()[::-1][:N])
|
|
196
|
-
# middle point between consecutive maxima
|
|
197
|
-
bound = np.zeros(N)
|
|
198
|
-
for i in range(N):
|
|
199
|
-
if i == 0:
|
|
200
|
-
a = 0
|
|
201
|
-
else:
|
|
202
|
-
a = maxidxs[i - 1]
|
|
203
|
-
bound[i] = (a + maxidxs[i]) / 2
|
|
204
|
-
|
|
205
|
-
return bound
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def LocalMaxMin(f, N, fm=0):
|
|
209
|
-
"""
|
|
210
|
-
===================================================================
|
|
211
|
-
bound = LocalMaxMin(f,N,fm)
|
|
212
|
-
|
|
213
|
-
This function segments f into a maximum of N supports by detecting
|
|
214
|
-
the lowest local minima between the N largest local maxima. If the
|
|
215
|
-
input fm is provided then the local maxima are computed on f and
|
|
216
|
-
the local minima on fm otherwise both are computed on f (this is
|
|
217
|
-
useful if you want to compute the maxima on a regularized version
|
|
218
|
-
of your signal while detecting the "true" minima).
|
|
219
|
-
|
|
220
|
-
Note: the detected boundaries are given in term of indices
|
|
221
|
-
|
|
222
|
-
Inputs:
|
|
223
|
-
-f: the function to segment
|
|
224
|
-
-N: maximal number of bands
|
|
225
|
-
|
|
226
|
-
Optional input:
|
|
227
|
-
-fm: function on which the local minima will be computed
|
|
228
|
-
|
|
229
|
-
Outputs:
|
|
230
|
-
-bound: list of detected boundaries
|
|
231
|
-
|
|
232
|
-
Author: Jerome Gilles
|
|
233
|
-
Institution: UCLA - Department of Mathematics
|
|
234
|
-
Year: 2013
|
|
235
|
-
Version: 2.0
|
|
236
|
-
|
|
237
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
238
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
239
|
-
Núcleo de Neurociências
|
|
240
|
-
===================================================================
|
|
241
|
-
"""
|
|
242
|
-
locmax = np.zeros(f.size)
|
|
243
|
-
if type(fm) == int:
|
|
244
|
-
f2 = f
|
|
245
|
-
else:
|
|
246
|
-
f2 = fm
|
|
247
|
-
locmin = max(f2) * np.ones(f2.size)
|
|
248
|
-
# detect local minima and maxima
|
|
249
|
-
for i in np.arange(1, f.size - 1):
|
|
250
|
-
if (f[i - 1] < f[i]) and (f[i] > f[i + 1]):
|
|
251
|
-
locmax[i] = f[i]
|
|
252
|
-
if (f2[i - 1] > f2[i]) and (f2[i] < f2[i + 1]):
|
|
253
|
-
locmin[i] = f2[i]
|
|
254
|
-
# keep the N-th highest maxima and their index
|
|
255
|
-
bound = np.zeros(N)
|
|
256
|
-
if N != -1:
|
|
257
|
-
N = N - 1
|
|
258
|
-
# keep the N-th highest maxima
|
|
259
|
-
Imax = np.sort(locmax.argsort()[::-1][:N])
|
|
260
|
-
# detect the lowest minima between two consecutive maxima
|
|
261
|
-
for i in range(N):
|
|
262
|
-
if i == 0:
|
|
263
|
-
a = 1
|
|
264
|
-
else:
|
|
265
|
-
a = Imax[i - 1]
|
|
266
|
-
lmin = np.sort(locmin[a:Imax[i]])
|
|
267
|
-
ind = np.argsort(locmin[a:Imax[i]])
|
|
268
|
-
tmpp = lmin[0]
|
|
269
|
-
n = 0
|
|
270
|
-
if n < len(lmin):
|
|
271
|
-
n = 1
|
|
272
|
-
while ((n < len(lmin)) and (tmpp == lmin[n])):
|
|
273
|
-
n = n + 1
|
|
274
|
-
bound[i] = a + ind[n // 2] - 1
|
|
275
|
-
else:
|
|
276
|
-
k = 0
|
|
277
|
-
for i in range(locmin):
|
|
278
|
-
if locmin[i] < max(f2):
|
|
279
|
-
bound[k] = i - 1
|
|
280
|
-
k = k + 1
|
|
281
|
-
return bound
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
# TODO def Adaptive_Bounds_Adapt():
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def EWT_Boundaries_Completion(boundaries, NT):
|
|
288
|
-
"""
|
|
289
|
-
======================================================================
|
|
290
|
-
boundaries=EWT_Boundaries_Completion(boundaries,NT)
|
|
291
|
-
|
|
292
|
-
This function permits to complete the boundaries vector to get a
|
|
293
|
-
total of NT boundaries by equally splitting the last band (highest
|
|
294
|
-
frequencies)
|
|
295
|
-
|
|
296
|
-
Inputs:
|
|
297
|
-
-boundaries: the boundaries vector you want to complete
|
|
298
|
-
-NT: the total number of boundaries wanted
|
|
299
|
-
|
|
300
|
-
Output:
|
|
301
|
-
-boundaries: the completed boundaries vector
|
|
302
|
-
|
|
303
|
-
Author: Jerome Gilles
|
|
304
|
-
Institution: UCLA - Department of Mathematics
|
|
305
|
-
Year: 2013
|
|
306
|
-
Version: 1.0
|
|
307
|
-
|
|
308
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
309
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
310
|
-
Núcleo de Neurociências
|
|
311
|
-
%======================================================================
|
|
312
|
-
"""
|
|
313
|
-
Nd = NT - len(boundaries)
|
|
314
|
-
deltaw = (np.pi - boundaries[-1]) / (Nd + 1)
|
|
315
|
-
for k in range(Nd):
|
|
316
|
-
boundaries = np.append(boundaries, boundaries[-1] + deltaw)
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
def EWT_Meyer_FilterBank(boundaries, Nsig):
|
|
320
|
-
"""
|
|
321
|
-
=========================================================================
|
|
322
|
-
function mfb=EWT_Meyer_FilterBank(boundaries,Nsig)
|
|
323
|
-
|
|
324
|
-
This function generate the filter bank (scaling function + wavelets)
|
|
325
|
-
corresponding to the provided set of frequency segments
|
|
326
|
-
|
|
327
|
-
Input parameters:
|
|
328
|
-
-boundaries: vector containing the boundaries of frequency segments (0
|
|
329
|
-
and pi must NOT be in this vector)
|
|
330
|
-
-Nsig: signal length
|
|
331
|
-
|
|
332
|
-
Output:
|
|
333
|
-
-mfb: cell containing each filter (in the Fourier domain), the scaling
|
|
334
|
-
function comes first and then the successive wavelets
|
|
335
|
-
|
|
336
|
-
Author: Jerome Gilles
|
|
337
|
-
Institution: UCLA - Department of Mathematics
|
|
338
|
-
Year: 2012
|
|
339
|
-
Version: 1.0
|
|
340
|
-
|
|
341
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
342
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
343
|
-
Núcleo de Neurociências
|
|
344
|
-
=========================================================================
|
|
345
|
-
"""
|
|
346
|
-
Npic = len(boundaries)
|
|
347
|
-
# compute gamma
|
|
348
|
-
gamma = 1
|
|
349
|
-
for k in range(Npic - 1):
|
|
350
|
-
r = (boundaries[k + 1] - boundaries[k]) / (boundaries[k + 1] + boundaries[k])
|
|
351
|
-
if r < gamma:
|
|
352
|
-
gamma = r
|
|
353
|
-
r = (np.pi - boundaries[Npic - 1]) / (np.pi + boundaries[Npic - 1])
|
|
354
|
-
if r < gamma:
|
|
355
|
-
gamma = r
|
|
356
|
-
gamma = (1 - 1 / Nsig) * gamma # this ensure that gamma is chosen as strictly less than the min
|
|
357
|
-
|
|
358
|
-
mfb = np.zeros([Nsig, Npic + 1])
|
|
359
|
-
|
|
360
|
-
# EWT_Meyer_Scaling
|
|
361
|
-
Mi = int(np.floor(Nsig / 2))
|
|
362
|
-
w = np.fft.fftshift(np.linspace(0, 2 * np.pi - 2 * np.pi / Nsig, num=Nsig))
|
|
363
|
-
w[0:Mi] = -2 * np.pi + w[0:Mi]
|
|
364
|
-
aw = abs(w)
|
|
365
|
-
yms = np.zeros(Nsig)
|
|
366
|
-
an = 1. / (2 * gamma * boundaries[0])
|
|
367
|
-
pbn = (1. + gamma) * boundaries[0]
|
|
368
|
-
mbn = (1. - gamma) * boundaries[0]
|
|
369
|
-
for k in range(Nsig):
|
|
370
|
-
if aw[k] <= mbn:
|
|
371
|
-
yms[k] = 1
|
|
372
|
-
elif ((aw[k] >= mbn) and (aw[k] <= pbn)):
|
|
373
|
-
yms[k] = np.cos(np.pi * EWT_beta(an * (aw[k] - mbn)) / 2)
|
|
374
|
-
yms = np.fft.ifftshift(yms)
|
|
375
|
-
mfb[:, 0] = yms
|
|
376
|
-
|
|
377
|
-
# generate rest of the wavelets
|
|
378
|
-
for k in range(Npic - 1):
|
|
379
|
-
mfb[:, k + 1] = EWT_Meyer_Wavelet(boundaries[k], boundaries[k + 1], gamma, Nsig)
|
|
380
|
-
|
|
381
|
-
mfb[:, Npic] = EWT_Meyer_Wavelet(boundaries[Npic - 1], np.pi, gamma, Nsig)
|
|
382
|
-
|
|
383
|
-
return mfb
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
def EWT_beta(x):
|
|
387
|
-
"""
|
|
388
|
-
Beta = EWT_beta(x)
|
|
389
|
-
function used in the construction of Meyer's wavelet
|
|
390
|
-
"""
|
|
391
|
-
if x < 0:
|
|
392
|
-
bm = 0
|
|
393
|
-
elif x > 1:
|
|
394
|
-
bm = 1
|
|
395
|
-
else:
|
|
396
|
-
bm = (x ** 4) * (35. - 84. * x + 70. * (x ** 2) - 20. * (x ** 3))
|
|
397
|
-
return bm
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
def EWT_Meyer_Wavelet(wn, wm, gamma, Nsig):
|
|
401
|
-
"""
|
|
402
|
-
=========================================================
|
|
403
|
-
ymw=EWT_Meyer_Wavelet(wn,wm,gamma,N)
|
|
404
|
-
|
|
405
|
-
Generate the 1D Meyer wavelet in the Fourier
|
|
406
|
-
domain associated to scale segment [wn,wm]
|
|
407
|
-
with transition ratio gamma
|
|
408
|
-
|
|
409
|
-
Input parameters:
|
|
410
|
-
-wn : lower boundary
|
|
411
|
-
-wm : upper boundary
|
|
412
|
-
-gamma : transition ratio
|
|
413
|
-
-N : number of point in the vector
|
|
414
|
-
|
|
415
|
-
Output:
|
|
416
|
-
-ymw: Fourier transform of the wavelet on the band [wn,wm]
|
|
417
|
-
|
|
418
|
-
Author: Jerome Gilles
|
|
419
|
-
Institution: UCLA - Department of Mathematics
|
|
420
|
-
Year: 2012
|
|
421
|
-
Version: 1.0
|
|
422
|
-
|
|
423
|
-
Python Version: Vinícius Rezende Carvalho - vrcarva@ufmg.br
|
|
424
|
-
Universidade Federal de Minas Gerais - Brasil
|
|
425
|
-
Núcleo de Neurociências
|
|
426
|
-
==========================================================
|
|
427
|
-
"""
|
|
428
|
-
Mi = int(np.floor(Nsig / 2))
|
|
429
|
-
w = np.fft.fftshift(np.linspace(0, 2 * np.pi - 2 * np.pi / Nsig, num=Nsig))
|
|
430
|
-
w[0:Mi] = -2 * np.pi + w[0:Mi]
|
|
431
|
-
aw = abs(w)
|
|
432
|
-
ymw = np.zeros(Nsig)
|
|
433
|
-
an = 1. / (2 * gamma * wn)
|
|
434
|
-
am = 1. / (2 * gamma * wm)
|
|
435
|
-
pbn = (1. + gamma) * wn
|
|
436
|
-
mbn = (1. - gamma) * wn
|
|
437
|
-
pbm = (1. + gamma) * wm
|
|
438
|
-
mbm = (1. - gamma) * wm
|
|
439
|
-
|
|
440
|
-
for k in range(Nsig):
|
|
441
|
-
if ((aw[k] >= pbn) and (aw[k] <= mbm)):
|
|
442
|
-
ymw[k] = 1
|
|
443
|
-
elif ((aw[k] >= mbm) and (aw[k] <= pbm)):
|
|
444
|
-
ymw[k] = np.cos(np.pi * EWT_beta(am * (aw[k] - mbm)) / 2)
|
|
445
|
-
elif ((aw[k] >= mbn) and (aw[k] <= pbn)):
|
|
446
|
-
ymw[k] = np.sin(np.pi * EWT_beta(an * (aw[k] - mbn)) / 2)
|
|
447
|
-
|
|
448
|
-
ymw = np.fft.ifftshift(ymw)
|
|
449
|
-
return ymw
|
|
File without changes
|
|
File without changes
|
|
File without changes
|