DASPy-toolbox 1.1.6__tar.gz → 1.2.0__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 (34) hide show
  1. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/PKG-INFO +1 -1
  2. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/SOURCES.txt +1 -0
  3. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/PKG-INFO +1 -1
  4. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/basic_tools/freqattributes.py +34 -2
  5. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/basic_tools/preprocessing.py +141 -28
  6. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/basic_tools/visualization.py +10 -7
  7. daspy_toolbox-1.2.0/daspy/core/collection.py +480 -0
  8. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/core/dasdatetime.py +11 -5
  9. daspy_toolbox-1.2.0/daspy/core/read.py +657 -0
  10. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/core/section.py +156 -116
  11. daspy_toolbox-1.2.0/daspy/core/util.py +140 -0
  12. daspy_toolbox-1.2.0/daspy/core/write.py +670 -0
  13. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/setup.py +1 -1
  14. daspy_toolbox-1.1.6/daspy/core/collection.py +0 -362
  15. daspy_toolbox-1.1.6/daspy/core/read.py +0 -590
  16. daspy_toolbox-1.1.6/daspy/core/write.py +0 -304
  17. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
  18. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
  19. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/requires.txt +0 -0
  20. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/DASPy_toolbox.egg-info/top_level.txt +0 -0
  21. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/LICENSE +0 -0
  22. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/README.md +0 -0
  23. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/__init__.py +0 -0
  24. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/__init__.py +0 -0
  25. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/channel.py +0 -0
  26. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/decomposition.py +0 -0
  27. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/denoising.py +0 -0
  28. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/fdct.py +0 -0
  29. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/advanced_tools/strain2vel.py +0 -0
  30. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/basic_tools/__init__.py +0 -0
  31. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/basic_tools/filter.py +0 -0
  32. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/core/__init__.py +0 -0
  33. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/daspy/core/example.pkl +0 -0
  34. {daspy_toolbox-1.1.6 → daspy_toolbox-1.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DASPy-toolbox
3
- Version: 1.1.6
3
+ Version: 1.2.0
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
@@ -25,4 +25,5 @@ daspy/core/dasdatetime.py
25
25
  daspy/core/example.pkl
26
26
  daspy/core/read.py
27
27
  daspy/core/section.py
28
+ daspy/core/util.py
28
29
  daspy/core/write.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DASPy-toolbox
3
- Version: 1.1.6
3
+ Version: 1.2.0
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,10 +1,10 @@
1
1
  # Purpose: Analyze frequency attribute and transform in frequency domain
2
2
  # Author: Minzhe Hu
3
- # Date: 2024.6.8
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,7 +1,8 @@
1
1
  # Purpose: Some preprocess methods
2
2
  # Author: Minzhe Hu
3
- # Date: 2025.3.10
3
+ # Date: 2025.6.25
4
4
  # Email: hmz2018@mail.ustc.edu.cn
5
+ import warnings
5
6
  import numpy as np
6
7
  from scipy.signal import detrend
7
8
  from scipy.signal.windows import tukey
@@ -89,11 +90,11 @@ def stacking(data: np.ndarray, N: int, step: int = None, average: bool = True):
89
90
  return data
90
91
  if step is None:
91
92
  step = N
92
- nch, nt = data.shape
93
+ nch, nsp = data.shape
93
94
  begin = np.arange(0, nch - N + 1, step)
94
95
  end = begin + N
95
96
  nx1 = len(begin)
96
- data_stacked = np.zeros((nx1, nt))
97
+ data_stacked = np.zeros((nx1, nsp))
97
98
  for i in range(nx1):
98
99
  data_stacked[i, :] = np.sum(data[begin[i]:end[i], :], axis=0)
99
100
  if average:
@@ -115,9 +116,9 @@ def cosine_taper(data, p=0.1, side='both'):
115
116
  """
116
117
  if data.ndim == 1:
117
118
  data = data.reshape(1, -1)
118
- nch, nt = data.shape
119
+ nch, nsp = data.shape
119
120
  if not isinstance(p, (tuple, list, np.ndarray)):
120
- win = tukey(nt, p)
121
+ win = tukey(nsp, p)
121
122
  if side == 'left':
122
123
  win[round(nch/2):] = 1
123
124
  elif side == 'right':
@@ -125,7 +126,7 @@ def cosine_taper(data, p=0.1, side='both'):
125
126
  return data * np.tile(win, (nch, 1))
126
127
  else:
127
128
  if p[0] > 0:
128
- data = data * np.tile(tukey(nch, p[0]), (nt, 1)).T
129
+ data = data * np.tile(tukey(nch, p[0]), (nsp, 1)).T
129
130
  return cosine_taper(data, p[1], side=side)
130
131
 
131
132
 
@@ -156,32 +157,144 @@ def downsampling(data, xint=None, tint=None, stack=True, lowpass_filter=True):
156
157
  return data_ds
157
158
 
158
159
 
159
- def trimming(data, dx=None, fs=None, xmin=0, xmax=None, tmin=0, tmax=None,
160
- mode=0):
160
+ def _trimming_index(nch, nsp, dx=None, fs=None, start_channel=0,
161
+ start_distance=0, start_time=0, xmin=None, xmax=None,
162
+ chmin=None, chmax=None, tmin=None, tmax=None, spmin=None,
163
+ spmax=None):
164
+ assert None in [tmin, spmin], \
165
+ "Please do not set tmin and spmin at the same time."
166
+ assert None in [tmax, spmax], \
167
+ "Please do not set tmax and spmax at the same time."
168
+ assert None in [xmin, chmin], \
169
+ "Please do not set xmin and chmin at the same time."
170
+ assert None in [xmax, chmax], \
171
+ "Please do not set xmax and chmax at the same time."
172
+ if dx is None:
173
+ assert xmin is None and xmax is None, "Please set dx"
174
+ if fs is None:
175
+ assert tmin is None and tmax is None, "Please set fs"
176
+
177
+ if xmin is None:
178
+ if chmin is None:
179
+ i0 = 0
180
+ else:
181
+ i0 = int(chmin - start_channel)
182
+ if i0 < 0:
183
+ warnings.warn('chmin < start_channel . Set chmin to '
184
+ 'start_channel.')
185
+ i0 = 0
186
+ elif i0 >= nch:
187
+ raise ValueError('chmin >= end_channel.')
188
+ else:
189
+ i0 = round((xmin - start_distance) / dx)
190
+ if i0 < 0:
191
+ warnings.warn('xmin is smaller than start_distance. Set xmin '
192
+ 'to 0.')
193
+ i0 = 0
194
+ elif i0 >= nch:
195
+ raise ValueError('xmin is later than end_distance.')
196
+
197
+ if xmax is None:
198
+ if chmax is None:
199
+ i1 = nch
200
+ else:
201
+ i1 = int(chmax - start_channel)
202
+ if i1 <= 0:
203
+ raise ValueError('chmax <= start_channel.')
204
+ elif i1 > nch:
205
+ warnings.warn('chmax > end_channel. Set chmax to '
206
+ 'end_channel.')
207
+ i1 = nch
208
+ else:
209
+ i1 = round((xmax - start_distance) / dx)
210
+ if i1 <= 0:
211
+ raise ValueError('xmax is smaller than start_distance.')
212
+ if i1 > nch:
213
+ warnings.warn('xmax is later than end_distance. Set xmax '
214
+ 'to the array length.')
215
+ i1 = nch
216
+
217
+ if tmin is None:
218
+ if spmin is None:
219
+ j0 = 0
220
+ else:
221
+ j0 = int(spmin)
222
+ if j0 < 0:
223
+ warnings.warn('spmin < 0. Set spmin to 0.')
224
+ j0 = 0
225
+ elif j0 >= nsp:
226
+ raise ValueError('spmin > nsp.')
227
+ else:
228
+ try:
229
+ j0 = round((tmin - start_time) * fs)
230
+ except TypeError:
231
+ j0 = round(tmin * fs)
232
+ if j0 < 0:
233
+ warnings.warn('tmin is earlier than start_time. Set tmin '
234
+ 'to start_time.')
235
+ j0 = 0
236
+ elif j0 >= nsp:
237
+ raise ValueError('tmin is later than end_time.')
238
+
239
+ if tmax is None:
240
+ if spmax is None:
241
+ j1 = nsp
242
+ else:
243
+ j1 = int(spmax)
244
+ if j1 <= 0:
245
+ raise ValueError('spmax < 0.')
246
+ elif j1 > nsp:
247
+ warnings.warn('spmax > nsp. Set spmax to nsp.')
248
+ j1 = nsp
249
+ else:
250
+ try:
251
+ j1 = round((tmax - start_time) * fs)
252
+ except TypeError:
253
+ j1 = round(tmax * fs)
254
+ if j1 <= 0:
255
+ raise ValueError('tmax is earlier than start_time.')
256
+ if j1 > nsp:
257
+ warnings.warn('tmax is later than end_time. Set tmax to the'
258
+ ' end_time.')
259
+ j1 = nsp
260
+ return i0, i1, j0, j1
261
+
262
+
263
+ def trimming(data, dx=None, fs=None, xmin=None, xmax=None, chmin=None,
264
+ chmax=None, tmin=None, tmax=None, spmin=None, spmax=None,
265
+ **kwargs):
161
266
  """
162
267
  Cut data to given start and end distance/channel or time/sampling points.
163
268
 
164
269
  :param data: numpy.ndarray. Data to trim can be 1-D or 2-D.
165
270
  :param dx: Channel interval in m.
166
271
  :param fs: Sampling rate in Hz.
167
- :param xmin, xmax, tmin, tmax: Boundary for trimming.
168
- :param mode: 0 means the unit of boundary is channel number and sampling
169
- points; 1 means the unit of boundary is meters and seconds.
272
+ :param xmin, xmax: float. Range of distance.
273
+ :param chmin, chmax: int. Channel number range.
274
+ :param tmin, tmax: float or DASDateTime. Range of time.
275
+ :param spmin, spmax: int. Sampling point range.
170
276
  :return: Trimmed data.
171
277
  """
172
- nch, nt = data.shape
173
- if mode == 0:
174
- if xmax is None:
175
- xmax = nch
176
- if tmax is None:
177
- tmax = nt
178
- elif mode == 1:
179
- xmin = round(xmin / dx)
180
- xmax = (round(xmax / dx), nch)[xmax is None]
181
- tmin = round(tmin * fs)
182
- tmax = (round(tmax * fs), nt)[tmax is None]
183
-
184
- return data[xmin:xmax, tmin:tmax]
278
+ # Compatible with old interfaces and remind users
279
+ if 'mode' in kwargs:
280
+ warnings.warn('In future versions, the mode parameter will be '
281
+ 'deprecated. xmin/xmax will only control the distance'
282
+ ' range, tmin/tmax will only control the time range; '
283
+ 'please use chmin/chmax to control the channel number'
284
+ ' range, and spmin/spmax to control the sampling '
285
+ 'point range', FutureWarning)
286
+ if kwargs['mode'] == 0:
287
+ chmin, chmax = xmin, xmax
288
+ xmin, xmax = None, None
289
+ spmin, spmax = tmin, tmax
290
+ tmin, tmax = None, None
291
+ nch, nsp = data.shape
292
+ i0, i1, j0, j1 = _trimming_index(nch, nsp, dx=dx, fs=fs, xmin=xmin,
293
+ xmax=xmax, chmin=chmin, chmax=chmax,
294
+ tmin=tmin, tmax=tmax, spmin=spmin,
295
+ spmax=spmax)
296
+
297
+ return data[i0:i1, j0:j1].copy()
185
298
 
186
299
 
187
300
  def padding(data, dn, reverse=False):
@@ -194,16 +307,16 @@ def padding(data, dn, reverse=False):
194
307
  :param reverse: bool. Set True to reverse the operation.
195
308
  :return: Padded data.
196
309
  """
197
- nch, nt = data.shape
310
+ nch, nsp = data.shape
198
311
  if isinstance(dn, int):
199
312
  dn = (dn, dn)
200
313
 
201
314
  pad = (dn[0] // 2, dn[0] - dn[0] // 2, dn[1] // 2, dn[1] - dn[1] // 2)
202
315
  if reverse:
203
- return data[pad[0]:nch - pad[1], pad[2]:nt - pad[3]]
316
+ return data[pad[0]:nch - pad[1], pad[2]:nsp - pad[3]]
204
317
  else:
205
- data_pd = np.zeros((nch + dn[0], nt + dn[1]))
206
- data_pd[pad[0]:nch + pad[0], pad[2]:nt + pad[2]] = data
318
+ data_pd = np.zeros((nch + dn[0], nsp + dn[1]))
319
+ data_pd[pad[0]:nch + pad[0], pad[2]:nsp + pad[2]] = data
207
320
  return data_pd
208
321
 
209
322
 
@@ -1,6 +1,6 @@
1
1
  # Purpose: Plot data
2
2
  # Author: Minzhe Hu
3
- # Date: 2025.5.20
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
- c=pick_color[phase])
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
- cmap = 'jet' if cmap is None else cmap
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 == 'spectrum':
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'