PySDKit 0.4.17__tar.gz → 0.4.18__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 (127) hide show
  1. {pysdkit-0.4.17 → pysdkit-0.4.18}/PKG-INFO +1 -1
  2. {pysdkit-0.4.17 → pysdkit-0.4.18}/PySDKit.egg-info/PKG-INFO +1 -1
  3. {pysdkit-0.4.17 → pysdkit-0.4.18}/PySDKit.egg-info/SOURCES.txt +3 -0
  4. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/__init__.py +85 -42
  5. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/__init__.py +2 -0
  6. pysdkit-0.4.18/pysdkit/_emd/hht/__init__.py +7 -0
  7. pysdkit-0.4.18/pysdkit/_emd/hht/frequency.py +105 -0
  8. pysdkit-0.4.18/pysdkit/_emd/hht/hht.py +251 -0
  9. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vncmd/incmd.py +1 -0
  10. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vncmd/vncmd.py +5 -2
  11. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/__init__.py +4 -1
  12. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/_generator.py +19 -1
  13. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/__init__.py +7 -5
  14. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/_fourier_spectra.py +80 -1
  15. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/__init__.py +8 -0
  16. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_hilbert.py +90 -1
  17. {pysdkit-0.4.17 → pysdkit-0.4.18}/setup.py +1 -1
  18. {pysdkit-0.4.17 → pysdkit-0.4.18}/LICENSE +0 -0
  19. {pysdkit-0.4.17 → pysdkit-0.4.18}/PySDKit.egg-info/dependency_links.txt +0 -0
  20. {pysdkit-0.4.17 → pysdkit-0.4.18}/PySDKit.egg-info/requires.txt +0 -0
  21. {pysdkit-0.4.17 → pysdkit-0.4.18}/PySDKit.egg-info/top_level.txt +0 -0
  22. {pysdkit-0.4.17 → pysdkit-0.4.18}/README.md +0 -0
  23. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/_find_extrema.py +0 -0
  24. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/_prepare_points.py +0 -0
  25. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/_splines.py +0 -0
  26. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/ceemdan.py +0 -0
  27. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/eemd.py +0 -0
  28. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/efd.py +0 -0
  29. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/emd.py +0 -0
  30. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/memd.py +0 -0
  31. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/remd.py +0 -0
  32. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd/tvf_emd.py +0 -0
  33. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd2d/__init__.py +0 -0
  34. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd2d/bemd.py +0 -0
  35. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd2d/bmemd.py +0 -0
  36. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_emd2d/emd2d.py +0 -0
  37. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_esmd/__init__.py +0 -0
  38. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_esmd/esmd.py +0 -0
  39. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ewt/__init__.py +0 -0
  40. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ewt/ewt.py +0 -0
  41. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ewt/ewt2d.py +0 -0
  42. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/__init__.py +0 -0
  43. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/extrema.py +0 -0
  44. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/faemd.py +0 -0
  45. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/faemd2d.py +0 -0
  46. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/faemd3d.py +0 -0
  47. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_faemd/filter.py +0 -0
  48. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_fmd/__init__.py +0 -0
  49. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_fmd/fmd.py +0 -0
  50. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_fmd/nfmd.py +0 -0
  51. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_hvd/__init__.py +0 -0
  52. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_hvd/hvd.py +0 -0
  53. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ifd/__init__.py +0 -0
  54. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_itd/__init__.py +0 -0
  55. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_itd/itd.py +0 -0
  56. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_jmd/__init__.py +0 -0
  57. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_jmd/jmd.py +0 -0
  58. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_jmd/mjmd.py +0 -0
  59. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_lmd/__init__.py +0 -0
  60. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_lmd/lmd.py +0 -0
  61. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_lmd/rlmd.py +0 -0
  62. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_osd/__init__.py +0 -0
  63. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ssa/__init__.py +0 -0
  64. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_ssa/ssa.py +0 -0
  65. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/__init__.py +0 -0
  66. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/acmd.py +0 -0
  67. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/avmd.py +0 -0
  68. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/ba_acmd.py +0 -0
  69. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/base.py +0 -0
  70. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/mvmd.py +0 -0
  71. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/svmd.py +0 -0
  72. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/vmd_c.py +0 -0
  73. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/vmd_f.py +0 -0
  74. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd/vme.py +0 -0
  75. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd2d/__init__.py +0 -0
  76. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd2d/cvmd2d.py +0 -0
  77. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vmd2d/vmd2d.py +0 -0
  78. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vncmd/__init__.py +0 -0
  79. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vncmd/anvcmd.py +0 -0
  80. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/_vncmd/mncmd.py +0 -0
  81. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/_add_noise.py +0 -0
  82. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/_cube.py +0 -0
  83. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/_image.py +0 -0
  84. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/_time_series.py +0 -0
  85. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/data/texture.txt +0 -0
  86. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/entropy/__init__.py +0 -0
  87. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/entropy/_approxiamte_entropy.py +0 -0
  88. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/entropy/_permutation_entropy.py +0 -0
  89. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/entropy/_sample_entropy.py +0 -0
  90. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/hht/__init__.py +0 -0
  91. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/hht/hht.py +0 -0
  92. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/_functions.py +0 -0
  93. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/_plot_images.py +0 -0
  94. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/_plot_imfs.py +0 -0
  95. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/plot/_plot_signal.py +0 -0
  96. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/__init__.py +0 -0
  97. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_all.py +0 -0
  98. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_ceemdan.py +0 -0
  99. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_emd.py +0 -0
  100. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_ewt.py +0 -0
  101. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_faemd.py +0 -0
  102. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_faemd2d.py +0 -0
  103. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_faemd3d.py +0 -0
  104. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_generator_cube.py +0 -0
  105. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_generator_image.py +0 -0
  106. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_generator_signal.py +0 -0
  107. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_moving_decomp.py +0 -0
  108. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_vmd.py +0 -0
  109. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tests/test_vmd2d.py +0 -0
  110. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/__init__.py +0 -0
  111. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/_dtw.py +0 -0
  112. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/_knn.py +0 -0
  113. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/_moving_decomp.py +0 -0
  114. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/_mstl.py +0 -0
  115. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/tsa/_stl.py +0 -0
  116. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_cite.py +0 -0
  117. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_correlation.py +0 -0
  118. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_diagnalization.py +0 -0
  119. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_differ.py +0 -0
  120. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_fft.py +0 -0
  121. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_function.py +0 -0
  122. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_instantaneous.py +0 -0
  123. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_kernel_matrix.py +0 -0
  124. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_mirror.py +0 -0
  125. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_process.py +0 -0
  126. {pysdkit-0.4.17 → pysdkit-0.4.18}/pysdkit/utils/_smooth1d.py +0 -0
  127. {pysdkit-0.4.17 → pysdkit-0.4.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PySDKit
3
- Version: 0.4.17
3
+ Version: 0.4.18
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PySDKit
3
- Version: 0.4.17
3
+ Version: 0.4.18
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
@@ -22,6 +22,9 @@ pysdkit/_emd2d/__init__.py
22
22
  pysdkit/_emd2d/bemd.py
23
23
  pysdkit/_emd2d/bmemd.py
24
24
  pysdkit/_emd2d/emd2d.py
25
+ pysdkit/_emd/hht/__init__.py
26
+ pysdkit/_emd/hht/frequency.py
27
+ pysdkit/_emd/hht/hht.py
25
28
  pysdkit/_esmd/__init__.py
26
29
  pysdkit/_esmd/esmd.py
27
30
  pysdkit/_ewt/__init__.py
@@ -2,43 +2,7 @@
2
2
  A Python library for signal decomposition algorithms.
3
3
  """
4
4
 
5
- __version__ = "0.4.16"
6
-
7
- __all__ = [
8
- "EMD",
9
- "EEMD",
10
- "CEEMDAN",
11
- "REMD",
12
- "MEMD",
13
- "TVF_EMD",
14
- "EFD",
15
- "FAEMD",
16
- "EMD2D",
17
- "HVD",
18
- "ITD",
19
- "LMD",
20
- "RLMD",
21
- "SSA",
22
- "vmd",
23
- "VMD",
24
- "ACMD",
25
- "MVMD",
26
- "VME",
27
- "CVMD2D",
28
- "VNCMD",
29
- "INCMD",
30
- "ewt",
31
- "EWT",
32
- "JMD",
33
- "Moving_Decomp",
34
- "data",
35
- "entropy",
36
- "hht",
37
- "plot",
38
- "tsa",
39
- "utils",
40
- "__version__",
41
- ]
5
+ __version__ = "0.4.18"
42
6
 
43
7
  # Empirical Mode Decomposition
44
8
  from ._emd import EMD
@@ -79,16 +43,16 @@ from ._lmd import LMD
79
43
  # Robust Local Mean Decomposition
80
44
  from ._lmd import RLMD
81
45
 
82
- # Singular Spectral Analysis (SSA) algorithm
46
+ # Singular Spectral Analysis
83
47
  from ._ssa import SSA
84
48
 
85
- # Variational mode decomposition
49
+ # Variational Mode Decomposition
86
50
  from ._vmd import vmd, VMD
87
51
 
88
52
  # Adaptive Chirp Mode Decomposition
89
53
  from ._vmd import ACMD
90
54
 
91
- # Multivariate Variational mode decomposition
55
+ # Multivariate Variational Mode Decomposition
92
56
  from ._vmd import MVMD
93
57
 
94
58
  # Variational Mode Extraction, to extract a specific mode from the signal
@@ -103,7 +67,7 @@ from ._vmd2d import CVMD2D
103
67
  # Variational Nonlinear Chirp Mode Decomposition
104
68
  from ._vncmd import VNCMD
105
69
 
106
- # Iterative nonlinear chirp mode decomposition
70
+ # Iterative Nonlinear Chirp Mode Decomposition
107
71
  from ._vncmd import INCMD
108
72
 
109
73
  # Empirical Wavelet Transform
@@ -112,9 +76,12 @@ from ._ewt import ewt, EWT
112
76
  # Jump Plus AM-FM Mode Decomposition
113
77
  from ._jmd import JMD
114
78
 
115
- # Moving Average decomposition
79
+ # Moving Average Decomposition
116
80
  from .tsa import Moving_Decomp
117
81
 
82
+ # Hilbert-Huang Transform
83
+ from ._emd import HHT
84
+
118
85
 
119
86
  def greet():
120
87
  print(
@@ -130,3 +97,79 @@ A Python library for signal decomposition algorithms.
130
97
  https://github.com/wwhenxuan/PySDKit
131
98
  """
132
99
  )
100
+
101
+
102
+ def print_functions():
103
+ """"""
104
+ print(
105
+ """
106
+ _______________________________________________________________
107
+ Algorithm Name | Abbreviation
108
+ _______________________________________________________________
109
+ Empirical Mode Decomposition | EMD
110
+ Ensemble Empirical Mode Decomposition | EEMD
111
+ Complete Ensemble EMD with Adaptive Noise | CEEMDAN
112
+ Robust Empirical Mode Decomposition | REMD
113
+ Multivariate Empirical Mode Decomposition | MEMD
114
+ Time Varying Filter based EMD | TVF_EMD
115
+ Empirical Fourier Decomposition | EFD
116
+ Fast and Adaptive Empirical Mode Decomposition | FAEMD
117
+ Empirical Mode Decomposition 2D for images | EMD2D
118
+ Hilbert Vibration Decomposition | HVD
119
+ Intrinsic Time-Scale Decomposition | ITD
120
+ Local Mean Decomposition | LMD
121
+ Robust Local Mean Decomposition | RLMD
122
+ Singular Spectral Analysis | SSA
123
+ Variational Mode Decomposition | VMD
124
+ Multivariate Variational Mode Decomposition | MVMD
125
+ Variational Mode Extraction | VME
126
+ Variational Mode Decomposition for 2D Image | VMD2D
127
+ Compact VMD for 2D Image | CVMD2D
128
+ Variational Nonlinear Chirp Mode Decomposition | VNCMD
129
+ Iterative Nonlinear Chirp Mode Decomposition | INCMD
130
+ Empirical Wavelet Transform | EWT
131
+ Jump Plus AM-FM Mode Decomposition | JMD
132
+ Moving Average Decomposition | Moving
133
+ Hilbert-Huang Transform | HHT
134
+ _______________________________________________________________
135
+ """
136
+ )
137
+
138
+
139
+ __all__ = [
140
+ "EMD",
141
+ "EEMD",
142
+ "CEEMDAN",
143
+ "REMD",
144
+ "MEMD",
145
+ "TVF_EMD",
146
+ "EFD",
147
+ "FAEMD",
148
+ "EMD2D",
149
+ "HVD",
150
+ "ITD",
151
+ "LMD",
152
+ "RLMD",
153
+ "SSA",
154
+ "vmd",
155
+ "VMD",
156
+ "ACMD",
157
+ "MVMD",
158
+ "VME",
159
+ "CVMD2D",
160
+ "VNCMD",
161
+ "INCMD",
162
+ "ewt",
163
+ "EWT",
164
+ "JMD",
165
+ "Moving_Decomp",
166
+ "data",
167
+ "entropy",
168
+ "HHT",
169
+ "plot",
170
+ "tsa",
171
+ "utils",
172
+ "greet",
173
+ "print_functions",
174
+ "__version__",
175
+ ]
@@ -23,3 +23,5 @@ from .memd import MEMD
23
23
  from .tvf_emd import TVF_EMD
24
24
 
25
25
  from .efd import EFD
26
+
27
+ from .hht import HHT
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on 2025/02/06 10:28:59
4
+ @author: Whenxuan Wang
5
+ @email: wwhenxuan@gmail.com
6
+ """
7
+ from .hht import HHT
@@ -0,0 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on 2025/02/06 10:30:01
4
+ @author: Whenxuan Wang
5
+ @email: wwhenxuan@gmail.com
6
+ Hilbert-transform for demodulation
7
+ """
8
+ import numpy as np
9
+ from pysdkit.utils import fft, ifft
10
+
11
+
12
+ def hilbert(signal: np.ndarray) -> np.ndarray:
13
+ """
14
+ Perform Hilbert transform along the last axis of input signal.
15
+
16
+ :param signal: The Hilbert transform is performed along last dimension.
17
+
18
+ :return: A complex tensor with the same shape of the input signal, representing its analytic signal.
19
+ """
20
+ signal = np.asarray(signal, dtype=np.float64)
21
+
22
+ # Get the length of input signal
23
+ N = signal.shape[-1]
24
+
25
+ # Perform a Fast Fourier Transform
26
+ Xf = fft(signal)
27
+
28
+ # Get the spectrum of the analytical signal
29
+ if N % 2 == 0:
30
+ Xf[..., 1 : N // 2] *= 2
31
+ Xf[..., N // 2 + 1 :] = 0
32
+ else:
33
+ Xf[..., 1 : (N + 1) // 2] *= 2
34
+ Xf[..., (N + 1) // 2 :] = 0
35
+ return ifft(Xf)
36
+
37
+
38
+ def get_envelope_frequency(signal: np.ndarray, fs: float, ret_analytic: bool = False):
39
+ """
40
+ Compute the envelope and instantaneous frequency function of the given signal using Hilbert transform.
41
+ The transformation is done along the last axis.
42
+
43
+ Parameters:
44
+ -------------
45
+ x : array_like
46
+ Signal data. The last dimension of `x` is considered the temporal dimension.
47
+ fs : float
48
+ Sampling frequency in Hz.
49
+ ret_analytic : bool, optional
50
+ Whether to return the analytic signal. (Default: False)
51
+
52
+ Returns:
53
+ -------------
54
+ (envelope, freq) if `ret_analytic` is False
55
+ (envelope, freq, analytic) if `ret_analytic` is True
56
+
57
+ envelope : ndarray
58
+ The envelope function with the same shape as `x`.
59
+ freq : ndarray
60
+ The instantaneous frequency function in Hz with the same shape as `x`.
61
+ analytic : ndarray
62
+ The analytic (complex) signal with the same shape as `x`.
63
+ :param signal: Signal data. The last dimension is considered the temporal dimension.
64
+ :param fs: Sampling frequency in Hz.
65
+ :param ret_analytic: Whether to return the analytic signal. (Default: False)
66
+
67
+ :return: (envelope, freq) if `ret_analytic` is False
68
+ (envelope, freq, analytic) if `ret_analytic` is True
69
+ - envelope : ndarray, the envelope function with the same shape as `x`.
70
+ freq : ndarray
71
+ The instantaneous frequency function in Hz with the same shape as `x`.
72
+ analytic : ndarray
73
+ The analytic (complex) signal with the same shape as `x`.
74
+ """
75
+ signal = np.asarray(signal, dtype=np.float64)
76
+ analytic = hilbert(signal) # Scipy's hilbert returns analytic signal
77
+
78
+ envelope = np.abs(analytic)
79
+
80
+ # Compute sub (discrete derivative with edge extension)
81
+ sub = np.empty_like(analytic)
82
+ diff = np.diff(analytic, axis=-1)
83
+ sub[..., :-1] = diff
84
+ # Handle last element (repeat last difference)
85
+ sub[..., -1] = (
86
+ analytic[..., -1] - analytic[..., -2] if analytic.shape[-1] >= 2 else 0.0
87
+ )
88
+
89
+ # Compute add (discrete sum with edge extension)
90
+ add = np.empty_like(analytic)
91
+ summed = analytic[..., 1:] + analytic[..., :-1]
92
+ add[..., :-1] = summed
93
+ # Handle last element (2 * last value)
94
+ add[..., -1] = 2 * analytic[..., -1]
95
+
96
+ # Calculate instantaneous frequency (handle division safely)
97
+ with np.errstate(divide="ignore", invalid="ignore"):
98
+ freq = 2 * fs * np.imag(sub / add)
99
+ freq[np.isinf(freq)] = 0 # Replace infs
100
+ freq /= 2 * np.pi # Convert to Hz
101
+
102
+ if ret_analytic:
103
+ return envelope, freq, analytic
104
+ else:
105
+ return envelope, freq
@@ -0,0 +1,251 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on 2025/02/06 10:29:05
4
+ @author: Whenxuan Wang
5
+ @email: wwhenxuan@gmail.com
6
+ """
7
+ import numpy as np
8
+ from matplotlib import pyplot as plt
9
+
10
+ from typing import Optional, Tuple, Any
11
+
12
+ from pysdkit.plot import plot_IMFs, plot_HilbertSpectrum
13
+ from pysdkit.utils import (
14
+ hilbert_real,
15
+ hilbert_imaginary,
16
+ hilbert_transform,
17
+ hilbert_spectrum,
18
+ )
19
+ from pysdkit._emd import EMD, REMD, EEMD, CEEMDAN
20
+ from pysdkit._emd.hht.frequency import get_envelope_frequency
21
+
22
+
23
+ class HHT(object):
24
+ """Perform Hilbert-Huang transform on the input signal"""
25
+
26
+ def __init__(
27
+ self,
28
+ algorithm: Optional[str] = "EMD",
29
+ max_imfs: Optional[int] = -1,
30
+ ) -> None:
31
+ """
32
+ :param algorithm: Type of Empirical Mode Decomposition algorithm used, (EMD, REMD, CEEMDAN)
33
+ :param max_imfs: maximum number of the IMFs to be decomposed.
34
+ """
35
+ self.algorithm = algorithm
36
+ self.max_imfs = max_imfs
37
+
38
+ self.emd = self._get_emd()
39
+
40
+ # Store original signal and sampling frequency
41
+ self.signal, self.fs = None, None
42
+ # Storing decomposition results
43
+ self.imfs, self.imfs_env, self.imfs_freq = None, None, None
44
+
45
+ def __call__(
46
+ self,
47
+ signal: np.ndarray,
48
+ fs: Optional[float] = None,
49
+ return_all: Optional[bool] = False,
50
+ ) -> np.ndarray | Tuple[np.ndarray, np.ndarray, np.ndarray]:
51
+ """
52
+ Perform Hilbert-Huang transform on the signal `x`, and return the amplitude and
53
+ instantaneous frequency function of each intrinsic mode.
54
+
55
+ :param signal: the input signal of Numpy 1D array.
56
+ :param fs: Sampling frequencies in Hz.
57
+ :param return_all: Whether to return all results
58
+
59
+ :return: The intrinsic mode function and other information obtained by Hilbert-Huang transform
60
+ """
61
+ return self.fit_transform(signal, fs, return_all=return_all)
62
+
63
+ def __str__(self) -> str:
64
+ """Get the full name and abbreviation of the algorithm"""
65
+ return "Hilbert-Huang Transform (HHT)"
66
+
67
+ def _get_emd(self) -> EMD | REMD | EEMD | CEEMDAN:
68
+ """选择对应的经验模态分解算法"""
69
+ if self.algorithm == "EMD":
70
+ return EMD(max_imfs=self.max_imfs)
71
+ elif self.algorithm == "REMD":
72
+ return REMD(max_imfs=self.max_imfs)
73
+ elif self.algorithm == "EEMD":
74
+ return EEMD(self.max_imfs)
75
+ elif self.algorithm == "CEEMDAN":
76
+ return CEEMDAN(self.max_imfs)
77
+ else:
78
+ raise ValueError("algorithm must be EMD, REMD, EEMD or CEEMDAN!")
79
+
80
+ def save_decompsition(
81
+ self,
82
+ signal: np.ndarray,
83
+ fs: float,
84
+ imfs: np.ndarray,
85
+ imfs_env: np.ndarray,
86
+ imfs_freq: np.ndarray,
87
+ ) -> None:
88
+ """
89
+ Record the results of this Hilbert-Huang transform
90
+
91
+ :param imfs: The intrinsic mode functions obtained by decomposing the signal.
92
+ :param signal: Input Numpy signal.
93
+ :param fs: Sampling frequency of the input signal.
94
+ :param imfs_env: Envelope spectrum of the intrinsic mode function.
95
+ :param imfs_freq: Frequency of the intrinsic mode function.
96
+
97
+ :return: None
98
+ """
99
+ self.signal = signal
100
+ self.fs = fs
101
+ self.imfs = imfs
102
+ self.imfs_freq = imfs_freq
103
+ self.imfs_env = imfs_env
104
+
105
+ def fit_transform(
106
+ self,
107
+ signal: np.ndarray,
108
+ fs: Optional[float] = None,
109
+ return_all: Optional[bool] = False,
110
+ ) -> np.ndarray | Tuple[np.ndarray, np.ndarray, np.ndarray]:
111
+ """
112
+ Perform Hilbert-Huang transform on the signal `x`, and return the amplitude and
113
+ instantaneous frequency function of each intrinsic mode.
114
+
115
+ :param signal: the input signal of Numpy 1D array.
116
+ :param fs: Sampling frequencies in Hz.
117
+ :param return_all: Whether to return all results
118
+
119
+ :return: The intrinsic mode function and other information obtained by Hilbert-Huang transform
120
+ """
121
+ # Using the empirical mode decomposition algorithm to obtain the intrinsic mode function
122
+ imfs = self.emd.fit_transform(signal)
123
+ # Analyze the envelope spectrum frequency characteristics of each mode
124
+ imfs_env, imfs_freq = get_envelope_frequency(imfs, fs=fs)
125
+
126
+ # Save the result of this Hilbert-Huang transform
127
+ self.save_decompsition(
128
+ signal=signal, fs=fs, imfs=imfs, imfs_env=imfs_env, imfs_freq=imfs_freq
129
+ )
130
+
131
+ if return_all is True:
132
+ return imfs, imfs_env, imfs_freq
133
+ return imfs
134
+
135
+ def plot_IMFs(
136
+ self, signal: Optional[np.ndarray] = None, imfs: Optional[np.ndarray] = None
137
+ ) -> plt.Figure:
138
+ """
139
+ Visualize the decomposition results.
140
+
141
+ :param signal: The NumPy signal to be visualized.
142
+ :param imfs: The intrinsic mode functions obtained by decomposing the signal to be visualized.
143
+
144
+ :return: Pyplot drawing Figure object in Matplotlib
145
+ """
146
+
147
+ # Get the original signal and the decomposed result
148
+ signal = signal if signal is not None else self.signal
149
+ imfs = imfs if imfs is not None else self.imfs
150
+
151
+ # Handling exception information
152
+ if signal is None:
153
+ raise ValueError(
154
+ "Please input the result after Hilbert-Huang transform or execute the `fit_transform` method once to record the decomposition result!"
155
+ )
156
+
157
+ # Visualize the decomposed intrinsic mode functions
158
+ figure = plot_IMFs(signal, imfs, return_figure=True)
159
+
160
+ return figure
161
+
162
+ def hilbert_spectrum(
163
+ self,
164
+ imfs_env: Optional[np.ndarray] = None,
165
+ imfs_freq: Optional[np.ndarray] = None,
166
+ fs: Optional[float] = None,
167
+ freq_lim: Optional[tuple[float, float]] = None,
168
+ freq_res: Optional[float] = None,
169
+ time_scale: int = 1,
170
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
171
+ """
172
+ Compute the Hilbert spectrum H(t, f) using numpy.
173
+
174
+ :param imfs_env: The envelope functions of all IMFs.
175
+ :param imfs_freq: The instantaneous frequency functions.
176
+ :param fs: Sampling frequency in Hz.
177
+ :param freq_lim: Frequency range (min, max). Defaults to (0, fs/2).
178
+ :param time_scale: Frequency resolution. Defaults to (freq_max - freq_min)/200.
179
+ :param freq_res: Temporal scaling factor (Default: 1).
180
+
181
+ :return: (spectrum, time_axis, freq_axis)
182
+ - spectrum : ndarray, shape (..., time_bins, freq_bins), Hilbert spectrum matrix
183
+ - time_axis : ndarray, 1D, Time axis labels
184
+ - freq_axis : ndarray, 1D, Frequency axis labels
185
+ """
186
+ # Read the results saved during the decomposition process
187
+ imfs_env = imfs_env if imfs_env is not None else self.imfs_env
188
+ imfs_freq = imfs_freq if imfs_freq is not None else self.imfs_freq
189
+ fs = fs if fs is not None else self.fs
190
+
191
+ # Compute the Hilbert spectrum
192
+ spectrum, t, f = hilbert_spectrum(
193
+ imfs_env=imfs_env,
194
+ imfs_freq=imfs_freq,
195
+ fs=fs,
196
+ freq_lim=freq_lim,
197
+ time_scale=time_scale,
198
+ freq_res=freq_res,
199
+ )
200
+ return spectrum, t, f
201
+
202
+ def plot_spectrum(
203
+ self,
204
+ imfs_env: Optional[np.ndarray] = None,
205
+ imfs_freq: Optional[np.ndarray] = None,
206
+ fs: Optional[float] = None,
207
+ freq_lim: Optional[tuple[float, float]] = None,
208
+ freq_res: Optional[float] = None,
209
+ time_scale: int = 1,
210
+ ) -> tuple[list[Any] | Any, list[Any]] | list[Any] | Any:
211
+ """
212
+ Obtaining and visualizing the Hilbert spectrum.
213
+
214
+ :param imfs_env: The envelope functions of all IMFs.
215
+ :param imfs_freq: The instantaneous frequency functions.
216
+ :param fs: Sampling frequency in Hz.
217
+ :param freq_lim: Frequency range (min, max). Defaults to (0, fs/2).
218
+ :param freq_res: Frequency resolution. Defaults to (freq_max - freq_min)/200.
219
+ :param time_scale: Temporal scaling factor (Default: 1).
220
+
221
+ :return: The plotting results.
222
+ """
223
+ # Read the results saved during the decomposition process
224
+ imfs_env = imfs_env if imfs_env is not None else self.imfs_env
225
+ imfs_freq = imfs_freq if imfs_freq is not None else self.imfs_freq
226
+
227
+ # Get the Hilbert spectrum
228
+ spectrum, t, f = self.hilbert_spectrum(
229
+ imfs_env=imfs_env,
230
+ imfs_freq=imfs_freq,
231
+ fs=fs,
232
+ freq_lim=freq_lim,
233
+ time_scale=time_scale,
234
+ freq_res=freq_res,
235
+ )
236
+ return plot_HilbertSpectrum(spectrum, t, f)
237
+
238
+
239
+ if __name__ == "__main__":
240
+ from pysdkit.data import test_hht
241
+
242
+ t, s = test_hht()
243
+ fs = 1000
244
+
245
+ hht = HHT(max_imfs=4)
246
+
247
+ imfs, imfs_env, imfs_freq = hht.fit_transform(s, fs=fs, return_all=True)
248
+ plot_IMFs(s, imfs)
249
+ hht.hilbert_spectrum()
250
+ hht.plot_spectrum(imfs_env=imfs_env, imfs_freq=imfs_freq)
251
+ plt.show()
@@ -6,6 +6,7 @@ Created on 2025/02/12 12:31:39
6
6
  """
7
7
  import numpy as np
8
8
  from scipy import linalg
9
+
9
10
  try:
10
11
  from scipy.integrate import cumulative_trapezoid
11
12
  except ImportError:
@@ -9,6 +9,7 @@ MATLAB code source https://www.mathworks.com/matlabcentral/fileexchange/64292-va
9
9
  import numpy as np
10
10
  from numpy.linalg import solve, norm
11
11
  from scipy.sparse import diags, eye
12
+
12
13
  try:
13
14
  from scipy.integrate import cumulative_trapezoid
14
15
  except ImportError:
@@ -199,10 +200,12 @@ class VNCMD(Base):
199
200
  # Initialize the variables defined above through loops
200
201
  for i in range(K):
201
202
  sinm[i, :] = np.sin(
202
- 2 * np.pi * cumulative_trapezoid(eIF[i, :], t, initial=0), dtype=self.DTYPE
203
+ 2 * np.pi * cumulative_trapezoid(eIF[i, :], t, initial=0),
204
+ dtype=self.DTYPE,
203
205
  )
204
206
  cosm[i, :] = np.cos(
205
- 2 * np.pi * cumulative_trapezoid(eIF[i, :], t, initial=0), dtype=self.DTYPE
207
+ 2 * np.pi * cumulative_trapezoid(eIF[i, :], t, initial=0),
208
+ dtype=self.DTYPE,
206
209
  )
207
210
 
208
211
  Bm = diags(
@@ -17,9 +17,12 @@ from ._generator import generate_am_signal, generate_exponential_signal
17
17
  # Generator for 1D univariate time series data
18
18
  from ._time_series import generate_time_series
19
19
 
20
- # Generates the main test sample signal
20
+ # Generate the main test sample signal
21
21
  from ._generator import test_emd
22
22
 
23
+ # Generate the test function for HHT
24
+ from ._generator import test_hht
25
+
23
26
  # Generator for 1D univariate
24
27
  from ._generator import test_univariate_signal
25
28
 
@@ -5,7 +5,7 @@ Created on Sat Mar 8 21:45:02 2024
5
5
  @email: wwhenxuan@gmail.com
6
6
  """
7
7
  import numpy as np
8
- from scipy.signal import sawtooth
8
+ from scipy.signal import sawtooth, chirp
9
9
  from matplotlib import pyplot as plt
10
10
 
11
11
  from typing import Tuple, Optional
@@ -338,6 +338,24 @@ def test_emd(
338
338
  return t, noise_signal
339
339
 
340
340
 
341
+ def test_hht(duration: float = 2.0, sampling_rate: int = 1000):
342
+ """
343
+ Generate data generation function to verify Hilbert-Huang transform.
344
+
345
+ :param duration: Length of the signal in seconds.
346
+ :param sampling_rate: Number of samples per second.
347
+
348
+ :return: Tuple of time array and signal for hht testing.
349
+ """
350
+ # Generate a sequence of time-stamped samples
351
+ time = np.arange(sampling_rate * duration) / sampling_rate
352
+ # Generate the signal to be decomposed
353
+ signal = chirp(time, 5, 0.8, 10, method="quadratic", phi=100) * np.exp(
354
+ -4 * (time - 1) ** 2
355
+ ) + chirp(time, 40, 1.2, 50, method="linear") * np.exp(-4 * (time - 1) ** 2)
356
+ return time, signal
357
+
358
+
341
359
  def test_multivariate_signal(
342
360
  case: int = 1,
343
361
  duration: float = 1.0,
@@ -5,17 +5,19 @@ Created on Sat Mar 4 21:31:05 2024
5
5
  @email: wwhenxuan@gmail.com
6
6
  Some auxiliary function modules for data visualization in the PySDKit library
7
7
  """
8
- # 在二维平面上可视化原输入信号和分解得到的本征模态函数
8
+ # Visualize the original input signal and the decomposed IMFs on a 2D plane
9
9
  from ._plot_imfs import plot_IMFs
10
10
 
11
- # 单独绘制分解得到的每个本征模态函数的频谱
11
+ # Plot the spectrum of each decomposed IMF separately
12
12
  from ._fourier_spectra import plot_IMFs_amplitude_spectra
13
13
 
14
- # 用于可视化二维灰度图
14
+ # Plotting the Hilbert spectrum
15
+ from ._fourier_spectra import plot_HilbertSpectrum
16
+
17
+ # Used to visualize two-dimensional grayscale images
15
18
  from ._plot_images import plot_grayscale_image, plot_grayscale_spectrum
16
19
 
17
- # 通用的图像可视化函数
18
- # 可以选择是否绘制频域图谱以及是否添加颜色条
20
+ # General image visualization functions
19
21
  from ._plot_images import plot_images
20
22
 
21
23
  # Functions that generate signal visualizations