DASPy-toolbox 1.1.6__tar.gz → 1.2.1__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.
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/PKG-INFO +1 -1
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/SOURCES.txt +2 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/PKG-INFO +1 -1
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/denoising.py +2 -2
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/basic_tools/freqattributes.py +34 -2
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/basic_tools/preprocessing.py +166 -36
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/basic_tools/visualization.py +10 -7
- daspy_toolbox-1.2.1/daspy/core/collection.py +480 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/core/dasdatetime.py +11 -5
- daspy_toolbox-1.2.1/daspy/core/make_example.py +32 -0
- daspy_toolbox-1.2.1/daspy/core/read.py +654 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/core/section.py +186 -133
- daspy_toolbox-1.2.1/daspy/core/util.py +140 -0
- daspy_toolbox-1.2.1/daspy/core/write.py +675 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/setup.py +3 -3
- daspy_toolbox-1.1.6/daspy/core/collection.py +0 -362
- daspy_toolbox-1.1.6/daspy/core/read.py +0 -590
- daspy_toolbox-1.1.6/daspy/core/write.py +0 -304
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/requires.txt +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/top_level.txt +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/LICENSE +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/README.md +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/__init__.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/__init__.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/channel.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/decomposition.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/fdct.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/advanced_tools/strain2vel.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/basic_tools/__init__.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/basic_tools/filter.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/core/__init__.py +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/daspy/core/example.pkl +0 -0
- {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: DASPy is an open-source project dedicated to provide a python package for DAS (Distributed Acoustic Sensing) data processing, which comprises classic seismic data processing techniques and Specialized algorithms for DAS applications.
|
|
5
5
|
Home-page: https://github.com/HMZ-03/DASPy
|
|
6
6
|
Author: Minzhe Hu, Zefeng Li
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: DASPy is an open-source project dedicated to provide a python package for DAS (Distributed Acoustic Sensing) data processing, which comprises classic seismic data processing techniques and Specialized algorithms for DAS applications.
|
|
5
5
|
Home-page: https://github.com/HMZ-03/DASPy
|
|
6
6
|
Author: Minzhe Hu, Zefeng Li
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Remove noise from data
|
|
2
2
|
# Author: Minzhe Hu, Zefeng Li
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.9.18
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
from copy import deepcopy
|
|
@@ -57,7 +57,7 @@ def common_mode_noise_removal(data, method='median'):
|
|
|
57
57
|
common = np.mean(data, 0)
|
|
58
58
|
|
|
59
59
|
xx = np.sum(common ** 2)
|
|
60
|
-
data_dn = np.zeros((nch, nt))
|
|
60
|
+
data_dn = np.zeros((nch, nt), dtype=data.dtype)
|
|
61
61
|
for i in range(nch):
|
|
62
62
|
xc = np.sum(common * data[i])
|
|
63
63
|
data_dn[i] = data[i] - xc / xx * common
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Purpose: Analyze frequency attribute and transform in frequency domain
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2024.6.
|
|
3
|
+
# Date: 2024.6.17
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
from numpy.fft import rfft, rfft2, fftshift, fftfreq, rfftfreq
|
|
7
|
-
from scipy.signal import stft
|
|
7
|
+
from scipy.signal import stft, welch
|
|
8
8
|
from daspy.basic_tools.preprocessing import demeaning, detrending, cosine_taper
|
|
9
9
|
|
|
10
10
|
|
|
@@ -47,6 +47,38 @@ def spectrum(data, fs, taper=0.05, nfft='default'):
|
|
|
47
47
|
return spec, f
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
def psd(data, fs, nperseg=256, noverlap=None, nfft=None, detrend=False,
|
|
51
|
+
average='mean'):
|
|
52
|
+
"""
|
|
53
|
+
Computes the power spectral density of the given data.
|
|
54
|
+
|
|
55
|
+
:param data: numpy.ndarray. Data to make spectrum of.
|
|
56
|
+
:param fs: Sampling rate in Hz.
|
|
57
|
+
:param nperseg: int. Length of each segment. Defaults to None, but if window
|
|
58
|
+
is str or tuple, is set to 256, and if window is array_like, is set to
|
|
59
|
+
the length of the window.
|
|
60
|
+
:param noverlap: int. Number of points to overlap between segments. If None,
|
|
61
|
+
noverlap = nperseg // 2. Defaults to None.
|
|
62
|
+
:param nfft: int. Length of the FFT used, if a zero padded FFT is desired.
|
|
63
|
+
If None, the FFT length is nperseg. Defaults to None.
|
|
64
|
+
:param detrend: str or bool. Specifies whether and how to detrend each
|
|
65
|
+
segment. 'linear' or 'detrend' or True = detrend, 'constant' or
|
|
66
|
+
'demean' = demean.
|
|
67
|
+
:param average: 'mean' or 'median. Method to use when averaging
|
|
68
|
+
periodograms. Defaults to 'mean'.
|
|
69
|
+
:return: Power spectral density or power spectrum and array of sample
|
|
70
|
+
frequencies.
|
|
71
|
+
"""
|
|
72
|
+
if len(data.shape) == 1:
|
|
73
|
+
data = data.reshape(1, len(data))
|
|
74
|
+
elif len(data.shape) != 2:
|
|
75
|
+
raise ValueError("Data should be 1-D or 2-D array")
|
|
76
|
+
|
|
77
|
+
f, psd = welch(data, fs=fs, nperseg=nperseg, noverlap=noverlap,
|
|
78
|
+
nfft=nfft, detrend=detrend, axis=1, average=average)
|
|
79
|
+
return psd, f
|
|
80
|
+
|
|
81
|
+
|
|
50
82
|
def spectrogram(data, fs, nperseg=256, noverlap=None, nfft=None, detrend=False,
|
|
51
83
|
boundary='zeros'):
|
|
52
84
|
"""
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Purpose: Some preprocess methods
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.10.30
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
|
+
import warnings
|
|
5
6
|
import numpy as np
|
|
7
|
+
from numpy.fft import rfft, irfft, rfftfreq
|
|
6
8
|
from scipy.signal import detrend
|
|
7
9
|
from scipy.signal.windows import tukey
|
|
8
10
|
from daspy.basic_tools.filter import lowpass_cheby_2
|
|
@@ -89,11 +91,11 @@ def stacking(data: np.ndarray, N: int, step: int = None, average: bool = True):
|
|
|
89
91
|
return data
|
|
90
92
|
if step is None:
|
|
91
93
|
step = N
|
|
92
|
-
nch,
|
|
94
|
+
nch, nsp = data.shape
|
|
93
95
|
begin = np.arange(0, nch - N + 1, step)
|
|
94
96
|
end = begin + N
|
|
95
97
|
nx1 = len(begin)
|
|
96
|
-
data_stacked = np.zeros((nx1,
|
|
98
|
+
data_stacked = np.zeros((nx1, nsp))
|
|
97
99
|
for i in range(nx1):
|
|
98
100
|
data_stacked[i, :] = np.sum(data[begin[i]:end[i], :], axis=0)
|
|
99
101
|
if average:
|
|
@@ -115,9 +117,9 @@ def cosine_taper(data, p=0.1, side='both'):
|
|
|
115
117
|
"""
|
|
116
118
|
if data.ndim == 1:
|
|
117
119
|
data = data.reshape(1, -1)
|
|
118
|
-
nch,
|
|
120
|
+
nch, nsp = data.shape
|
|
119
121
|
if not isinstance(p, (tuple, list, np.ndarray)):
|
|
120
|
-
win = tukey(
|
|
122
|
+
win = tukey(nsp, p)
|
|
121
123
|
if side == 'left':
|
|
122
124
|
win[round(nch/2):] = 1
|
|
123
125
|
elif side == 'right':
|
|
@@ -125,7 +127,7 @@ def cosine_taper(data, p=0.1, side='both'):
|
|
|
125
127
|
return data * np.tile(win, (nch, 1))
|
|
126
128
|
else:
|
|
127
129
|
if p[0] > 0:
|
|
128
|
-
data = data * np.tile(tukey(nch, p[0]), (
|
|
130
|
+
data = data * np.tile(tukey(nch, p[0]), (nsp, 1)).T
|
|
129
131
|
return cosine_taper(data, p[1], side=side)
|
|
130
132
|
|
|
131
133
|
|
|
@@ -156,32 +158,144 @@ def downsampling(data, xint=None, tint=None, stack=True, lowpass_filter=True):
|
|
|
156
158
|
return data_ds
|
|
157
159
|
|
|
158
160
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
+
def _trimming_index(nch, nsp, dx=None, fs=None, start_channel=0,
|
|
162
|
+
start_distance=0, start_time=0, xmin=None, xmax=None,
|
|
163
|
+
chmin=None, chmax=None, tmin=None, tmax=None, spmin=None,
|
|
164
|
+
spmax=None):
|
|
165
|
+
assert None in [tmin, spmin], \
|
|
166
|
+
"Please do not set tmin and spmin at the same time."
|
|
167
|
+
assert None in [tmax, spmax], \
|
|
168
|
+
"Please do not set tmax and spmax at the same time."
|
|
169
|
+
assert None in [xmin, chmin], \
|
|
170
|
+
"Please do not set xmin and chmin at the same time."
|
|
171
|
+
assert None in [xmax, chmax], \
|
|
172
|
+
"Please do not set xmax and chmax at the same time."
|
|
173
|
+
if dx is None:
|
|
174
|
+
assert xmin is None and xmax is None, "Please set dx"
|
|
175
|
+
if fs is None:
|
|
176
|
+
assert tmin is None and tmax is None, "Please set fs"
|
|
177
|
+
|
|
178
|
+
if xmin is None:
|
|
179
|
+
if chmin is None:
|
|
180
|
+
i0 = 0
|
|
181
|
+
else:
|
|
182
|
+
i0 = int(chmin - start_channel)
|
|
183
|
+
if i0 < 0:
|
|
184
|
+
warnings.warn('chmin < start_channel . Set chmin to '
|
|
185
|
+
'start_channel.')
|
|
186
|
+
i0 = 0
|
|
187
|
+
elif i0 >= nch:
|
|
188
|
+
raise ValueError('chmin >= end_channel.')
|
|
189
|
+
else:
|
|
190
|
+
i0 = round((xmin - start_distance) / dx)
|
|
191
|
+
if i0 < 0:
|
|
192
|
+
warnings.warn('xmin is smaller than start_distance. Set xmin '
|
|
193
|
+
'to 0.')
|
|
194
|
+
i0 = 0
|
|
195
|
+
elif i0 >= nch:
|
|
196
|
+
raise ValueError('xmin is later than end_distance.')
|
|
197
|
+
|
|
198
|
+
if xmax is None:
|
|
199
|
+
if chmax is None:
|
|
200
|
+
i1 = nch
|
|
201
|
+
else:
|
|
202
|
+
i1 = int(chmax - start_channel)
|
|
203
|
+
if i1 <= 0:
|
|
204
|
+
raise ValueError('chmax <= start_channel.')
|
|
205
|
+
elif i1 > nch:
|
|
206
|
+
warnings.warn('chmax > end_channel. Set chmax to '
|
|
207
|
+
'end_channel.')
|
|
208
|
+
i1 = nch
|
|
209
|
+
else:
|
|
210
|
+
i1 = round((xmax - start_distance) / dx)
|
|
211
|
+
if i1 <= 0:
|
|
212
|
+
raise ValueError('xmax is smaller than start_distance.')
|
|
213
|
+
if i1 > nch:
|
|
214
|
+
warnings.warn('xmax is later than end_distance. Set xmax '
|
|
215
|
+
'to the array length.')
|
|
216
|
+
i1 = nch
|
|
217
|
+
|
|
218
|
+
if tmin is None:
|
|
219
|
+
if spmin is None:
|
|
220
|
+
j0 = 0
|
|
221
|
+
else:
|
|
222
|
+
j0 = int(spmin)
|
|
223
|
+
if j0 < 0:
|
|
224
|
+
warnings.warn('spmin < 0. Set spmin to 0.')
|
|
225
|
+
j0 = 0
|
|
226
|
+
elif j0 >= nsp:
|
|
227
|
+
raise ValueError('spmin > nsp.')
|
|
228
|
+
else:
|
|
229
|
+
try:
|
|
230
|
+
j0 = round((tmin - start_time) * fs)
|
|
231
|
+
except TypeError:
|
|
232
|
+
j0 = round(tmin * fs)
|
|
233
|
+
if j0 < 0:
|
|
234
|
+
warnings.warn('tmin is earlier than start_time. Set tmin '
|
|
235
|
+
'to start_time.')
|
|
236
|
+
j0 = 0
|
|
237
|
+
elif j0 >= nsp:
|
|
238
|
+
raise ValueError('tmin is later than end_time.')
|
|
239
|
+
|
|
240
|
+
if tmax is None:
|
|
241
|
+
if spmax is None:
|
|
242
|
+
j1 = nsp
|
|
243
|
+
else:
|
|
244
|
+
j1 = int(spmax)
|
|
245
|
+
if j1 <= 0:
|
|
246
|
+
raise ValueError('spmax < 0.')
|
|
247
|
+
elif j1 > nsp:
|
|
248
|
+
warnings.warn('spmax > nsp. Set spmax to nsp.')
|
|
249
|
+
j1 = nsp
|
|
250
|
+
else:
|
|
251
|
+
try:
|
|
252
|
+
j1 = round((tmax - start_time) * fs)
|
|
253
|
+
except TypeError:
|
|
254
|
+
j1 = round(tmax * fs)
|
|
255
|
+
if j1 <= 0:
|
|
256
|
+
raise ValueError('tmax is earlier than start_time.')
|
|
257
|
+
if j1 > nsp:
|
|
258
|
+
warnings.warn('tmax is later than end_time. Set tmax to the'
|
|
259
|
+
' end_time.')
|
|
260
|
+
j1 = nsp
|
|
261
|
+
return i0, i1, j0, j1
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def trimming(data, dx=None, fs=None, xmin=None, xmax=None, chmin=None,
|
|
265
|
+
chmax=None, tmin=None, tmax=None, spmin=None, spmax=None,
|
|
266
|
+
**kwargs):
|
|
161
267
|
"""
|
|
162
268
|
Cut data to given start and end distance/channel or time/sampling points.
|
|
163
269
|
|
|
164
270
|
:param data: numpy.ndarray. Data to trim can be 1-D or 2-D.
|
|
165
271
|
:param dx: Channel interval in m.
|
|
166
272
|
:param fs: Sampling rate in Hz.
|
|
167
|
-
:param xmin, xmax
|
|
168
|
-
:param
|
|
169
|
-
|
|
273
|
+
:param xmin, xmax: float. Range of distance.
|
|
274
|
+
:param chmin, chmax: int. Channel number range.
|
|
275
|
+
:param tmin, tmax: float or DASDateTime. Range of time.
|
|
276
|
+
:param spmin, spmax: int. Sampling point range.
|
|
170
277
|
:return: Trimmed data.
|
|
171
278
|
"""
|
|
172
|
-
|
|
173
|
-
if mode
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
279
|
+
# Compatible with old interfaces and remind users
|
|
280
|
+
if 'mode' in kwargs:
|
|
281
|
+
warnings.warn('In future versions, the mode parameter will be '
|
|
282
|
+
'deprecated. xmin/xmax will only control the distance'
|
|
283
|
+
' range, tmin/tmax will only control the time range; '
|
|
284
|
+
'please use chmin/chmax to control the channel number'
|
|
285
|
+
' range, and spmin/spmax to control the sampling '
|
|
286
|
+
'point range', FutureWarning)
|
|
287
|
+
if kwargs['mode'] == 0:
|
|
288
|
+
chmin, chmax = xmin, xmax
|
|
289
|
+
xmin, xmax = None, None
|
|
290
|
+
spmin, spmax = tmin, tmax
|
|
291
|
+
tmin, tmax = None, None
|
|
292
|
+
nch, nsp = data.shape
|
|
293
|
+
i0, i1, j0, j1 = _trimming_index(nch, nsp, dx=dx, fs=fs, xmin=xmin,
|
|
294
|
+
xmax=xmax, chmin=chmin, chmax=chmax,
|
|
295
|
+
tmin=tmin, tmax=tmax, spmin=spmin,
|
|
296
|
+
spmax=spmax)
|
|
297
|
+
|
|
298
|
+
return data[i0:i1, j0:j1].copy()
|
|
185
299
|
|
|
186
300
|
|
|
187
301
|
def padding(data, dn, reverse=False):
|
|
@@ -194,20 +308,20 @@ def padding(data, dn, reverse=False):
|
|
|
194
308
|
:param reverse: bool. Set True to reverse the operation.
|
|
195
309
|
:return: Padded data.
|
|
196
310
|
"""
|
|
197
|
-
nch,
|
|
311
|
+
nch, nsp = data.shape
|
|
198
312
|
if isinstance(dn, int):
|
|
199
313
|
dn = (dn, dn)
|
|
200
314
|
|
|
201
315
|
pad = (dn[0] // 2, dn[0] - dn[0] // 2, dn[1] // 2, dn[1] - dn[1] // 2)
|
|
202
316
|
if reverse:
|
|
203
|
-
return data[pad[0]:nch - pad[1], pad[2]:
|
|
317
|
+
return data[pad[0]:nch - pad[1], pad[2]:nsp - pad[3]]
|
|
204
318
|
else:
|
|
205
|
-
data_pd = np.zeros((nch + dn[0],
|
|
206
|
-
data_pd[pad[0]:nch + pad[0], pad[2]:
|
|
319
|
+
data_pd = np.zeros((nch + dn[0], nsp + dn[1]))
|
|
320
|
+
data_pd[pad[0]:nch + pad[0], pad[2]:nsp + pad[2]] = data
|
|
207
321
|
return data_pd
|
|
208
322
|
|
|
209
323
|
|
|
210
|
-
def time_integration(data, fs, c=0):
|
|
324
|
+
def time_integration(data, fs, domain='time', c=0):
|
|
211
325
|
"""
|
|
212
326
|
Integrate DAS data in time.
|
|
213
327
|
|
|
@@ -216,10 +330,19 @@ def time_integration(data, fs, c=0):
|
|
|
216
330
|
:param c: float. A constant added to the result.
|
|
217
331
|
:return: Integrated data.
|
|
218
332
|
"""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
333
|
+
if domain == 'time':
|
|
334
|
+
return np.cumsum(data, axis=1) / fs + c
|
|
335
|
+
elif domain in ['frequency', 'freq']:
|
|
336
|
+
nsp = data.shape[1]
|
|
337
|
+
freqs = rfftfreq(nsp, d=1/fs)
|
|
338
|
+
spectrum = rfft(data, axis=1)
|
|
339
|
+
H = np.zeros_like(freqs, dtype=complex)
|
|
340
|
+
nonzero = freqs != 0
|
|
341
|
+
H[nonzero] = 1 / (1j * 2 * np.pi * freqs[nonzero])
|
|
342
|
+
return np.real(irfft(spectrum * H))
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def time_differential(data, fs, domain='time', prepend=0):
|
|
223
346
|
"""
|
|
224
347
|
Differentiate DAS data in time.
|
|
225
348
|
|
|
@@ -229,9 +352,16 @@ def time_differential(data, fs, prepend=0):
|
|
|
229
352
|
performing the difference.
|
|
230
353
|
:return: Differentiated data.
|
|
231
354
|
"""
|
|
232
|
-
if
|
|
233
|
-
prepend
|
|
234
|
-
|
|
355
|
+
if domain == 'time':
|
|
356
|
+
if prepend == 'mean':
|
|
357
|
+
prepend = np.mean(data, axis=1).reshape((-1, 1))
|
|
358
|
+
return np.diff(data, axis=1, prepend=prepend) * fs
|
|
359
|
+
elif domain in ['frequency', 'freq']:
|
|
360
|
+
nsp = data.shape[1]
|
|
361
|
+
freqs = rfftfreq(nsp, d=1./fs)
|
|
362
|
+
spectrum = rfft(data, axis=1)
|
|
363
|
+
H = 1j * 2 * np.pi * freqs
|
|
364
|
+
return np.real(irfft(spectrum * H))
|
|
235
365
|
|
|
236
366
|
|
|
237
367
|
def distance_integration(data, dx, c=0):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Plot data
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.6.17
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
import matplotlib.pyplot as plt
|
|
@@ -24,7 +24,7 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
24
24
|
figsize. If not specified, the function will directly display the image
|
|
25
25
|
using matplotlib.pyplot.show().
|
|
26
26
|
:param obj: str. Type of data to plot. It should be one of 'waveform',
|
|
27
|
-
'phasepick', 'spectrum', 'spectrogram', 'fk', or 'dispersion'.
|
|
27
|
+
'phasepick', 'spectrum', 'psd', 'spectrogram', 'fk', or 'dispersion'.
|
|
28
28
|
:param dpi: int. The resolution of the figure in dots-per-inch.
|
|
29
29
|
:param title: str. The title of this axes.
|
|
30
30
|
:param transpose: bool. Transpose the figure or not.
|
|
@@ -33,7 +33,7 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
33
33
|
P phase, 'S' for S phase and 'N' for unknown phase type. Required if
|
|
34
34
|
obj=='phasepick'.
|
|
35
35
|
:param f: Sequence of frequency. Required if obj is one of 'spectrum',
|
|
36
|
-
'spectrogram', 'fk' or 'dispersion'.
|
|
36
|
+
'psd', 'spectrogram', 'fk' or 'dispersion'.
|
|
37
37
|
:param k: Wavenumber sequence. Required if obj=='fk'.
|
|
38
38
|
:param t: Time sequence. Required if obj=='spectrogram'.
|
|
39
39
|
:param c: Phase velocity sequence. Required if obj=='dispersion'.
|
|
@@ -99,14 +99,17 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
99
99
|
if tmode.lower() == 'sampling':
|
|
100
100
|
pck[:, 1] = pck[:, 1] / fs
|
|
101
101
|
ax.scatter(pck[:,0], t0 + pck[:,1], marker=',', s=0.1,
|
|
102
|
-
|
|
102
|
+
c=pick_color[phase])
|
|
103
103
|
|
|
104
|
-
elif obj in ['spectrum', 'spectrogram', 'fk', 'dispersion']:
|
|
104
|
+
elif obj in ['spectrum', 'spectrogram', 'psd', 'fk', 'dispersion']:
|
|
105
105
|
if np.iscomplex(data).any():
|
|
106
106
|
data = abs(data)
|
|
107
107
|
if dB:
|
|
108
108
|
data = 20 * np.log10(data)
|
|
109
|
-
|
|
109
|
+
if obj == 'psd':
|
|
110
|
+
cmap = 'viridis' if cmap is None else cmap
|
|
111
|
+
else:
|
|
112
|
+
cmap = 'jet' if cmap is None else cmap
|
|
110
113
|
|
|
111
114
|
if vmax is None:
|
|
112
115
|
vmax_per = 80 if vmax_per is None else vmax_per
|
|
@@ -115,7 +118,7 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
115
118
|
vmin_per = 20 if vmin_per is None else vmin_per
|
|
116
119
|
vmin = np.percentile(data, vmin_per)
|
|
117
120
|
|
|
118
|
-
if obj
|
|
121
|
+
if obj in ['spectrum', 'psd']:
|
|
119
122
|
origin = 'lower'
|
|
120
123
|
if dx is None or xmode.lower() == 'channel':
|
|
121
124
|
xlabel_default = 'Channel'
|