DASPy-toolbox 1.0.0__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.
Files changed (49) hide show
  1. DASPy_toolbox-1.0.0.dist-info/LICENSE.txt +1 -0
  2. DASPy_toolbox-1.0.0.dist-info/METADATA +85 -0
  3. DASPy_toolbox-1.0.0.dist-info/RECORD +49 -0
  4. DASPy_toolbox-1.0.0.dist-info/WHEEL +5 -0
  5. DASPy_toolbox-1.0.0.dist-info/entry_points.txt +2 -0
  6. DASPy_toolbox-1.0.0.dist-info/top_level.txt +1 -0
  7. daspy/__init__.py +4 -0
  8. daspy/advanced_tools/__init__.py +0 -0
  9. daspy/advanced_tools/channel.py +354 -0
  10. daspy/advanced_tools/decomposition.py +165 -0
  11. daspy/advanced_tools/denoising.py +276 -0
  12. daspy/advanced_tools/fdct.py +789 -0
  13. daspy/advanced_tools/strain2vel.py +245 -0
  14. daspy/basic_tools/__init__.py +0 -0
  15. daspy/basic_tools/filter.py +257 -0
  16. daspy/basic_tools/freqattributes.py +117 -0
  17. daspy/basic_tools/preprocessing.py +238 -0
  18. daspy/basic_tools/visualization.py +186 -0
  19. daspy/core/__init__.py +4 -0
  20. daspy/core/collection.py +279 -0
  21. daspy/core/dasdatetime.py +72 -0
  22. daspy/core/example.pkl +0 -0
  23. daspy/core/make_example.py +32 -0
  24. daspy/core/read.py +544 -0
  25. daspy/core/section.py +1319 -0
  26. daspy/core/write.py +282 -0
  27. daspy/seismic_detection/__init__.py +1 -0
  28. daspy/seismic_detection/calc_travel_time.py +23 -0
  29. daspy/seismic_detection/core.py +119 -0
  30. daspy/seismic_detection/detection.py +12 -0
  31. daspy/seismic_detection/gamma/__init__.py +13 -0
  32. daspy/seismic_detection/gamma/_base.py +549 -0
  33. daspy/seismic_detection/gamma/_bayesian_mixture.py +875 -0
  34. daspy/seismic_detection/gamma/_gaussian_mixture.py +866 -0
  35. daspy/seismic_detection/gamma/app.py +192 -0
  36. daspy/seismic_detection/gamma/seismic_ops.py +478 -0
  37. daspy/seismic_detection/gamma/utils.py +512 -0
  38. daspy/seismic_detection/location.py +266 -0
  39. daspy/seismic_detection/magnitude.py +43 -0
  40. daspy/seismic_detection/phase_picking.py +67 -0
  41. daspy/structure_imaging/__init__.py +0 -0
  42. daspy/structure_imaging/ambient_noise.py +4 -0
  43. daspy/structure_imaging/dispersion.py +27 -0
  44. daspy/structure_imaging/fault_zone.py +59 -0
  45. daspy/structure_imaging/inversion.py +6 -0
  46. daspy/traffic_monitoring/JamDetection.py +6 -0
  47. daspy/traffic_monitoring/SpeedMeasurement.py +6 -0
  48. daspy/traffic_monitoring/VehicleDetection.py +6 -0
  49. daspy/traffic_monitoring/__init__.py +0 -0
@@ -0,0 +1,238 @@
1
+ # Purpose: Some preprocess methods
2
+ # Author: Minzhe Hu
3
+ # Date: 2024.10.25
4
+ # Email: hmz2018@mail.ustc.edu.cn
5
+ import numpy as np
6
+ from scipy.signal import detrend
7
+ from scipy.signal.windows import tukey
8
+ from daspy.basic_tools.filter import lowpass_cheby_2
9
+
10
+
11
+ def phase2strain(data, lam, e, n, gl):
12
+ """
13
+ Convert the optical phase shift in radians to strain.
14
+
15
+ :param data: numpy.ndarray. Data to convert.
16
+ :param lam: float. Operational optical wavelength in vacuum.
17
+ :param e: float. photo-slastic scaling factor for logitudinal strain in
18
+ isotropic material.
19
+ :param n: float. Refractive index of the sensing fiber.
20
+ :paran gl: float. Gauge length.
21
+ :return: Strain data.
22
+ """
23
+ return data * (lam * 1e-9) / (e * 4 * np.pi * n * gl)
24
+
25
+
26
+ def normalization(data, method='z-score'):
27
+ """
28
+ Normalize for each individual channel using Z-score method.
29
+
30
+ :param data: numpy.ndarray. Data to normalize.
31
+ :param method: str. Method for normalization, should be one of 'max',
32
+ 'z-score', or 'one-bit'.
33
+ :return: Normalized data.
34
+ """
35
+ if data.ndim == 1:
36
+ data = data.reshape(1, len(data))
37
+ elif data.ndim != 2:
38
+ raise ValueError("Data should be 1-D or 2-D array")
39
+
40
+ if method == 'max':
41
+ amp = np.max(abs(data), 1, keepdims=True)
42
+ amp[amp == 0] = amp[amp > 0].min()
43
+ return data / amp
44
+
45
+ if method == 'z-score':
46
+ mean = np.mean(data, axis=1, keepdims=True)
47
+ std = np.std(data, axis=1, keepdims=True)
48
+ std[std == 0] = std[std > 0].min()
49
+ return (data - mean) / std
50
+
51
+ if method == 'one-bit':
52
+ return np.sign(data)
53
+
54
+
55
+ def demeaning(data):
56
+ """
57
+ Demean signal by subtracted mean of each channel.
58
+
59
+ :param data: numpy.ndarray. Data to demean.
60
+ :return: Detrended data.
61
+ """
62
+ return detrend(data, type='constant')
63
+
64
+
65
+ def detrending(data):
66
+ """
67
+ Detrend signal by subtracted a linear least-squares fit to data.
68
+
69
+ :param data: numpy.ndarray. Data to detrend.
70
+ :return: Detrended data.
71
+ """
72
+ return detrend(data, type='linear')
73
+
74
+
75
+ def stacking(data: np.ndarray, N: int, step: int = None, average: bool = False):
76
+ """
77
+ Stack several channels to increase the signal-noise ratio(SNR).
78
+
79
+ :param data: numpy.ndarray. Data to stack.
80
+ :param N: int. N adjacent channels stacked into 1.
81
+ :param step: int. Interval of data stacking.
82
+ :param average: bool. True for calculating the average.
83
+ :return: Stacked data.
84
+ """
85
+ if N == 1:
86
+ return data
87
+ if step is None:
88
+ step = N
89
+ nch, nt = data.shape
90
+ begin = np.arange(0, nch - N + 1, step)
91
+ end = begin + N
92
+ nx1 = len(begin)
93
+ data_stacked = np.zeros((nx1, nt))
94
+ for i in range(nx1):
95
+ data_stacked[i, :] = np.sum(data[begin[i]:end[i], :], axis=0)
96
+ if average:
97
+ data_stacked /= N
98
+ return data_stacked
99
+
100
+
101
+ def cosine_taper(data, p=0.1):
102
+ """
103
+ Taper using Tukey window.
104
+
105
+ :param data: numpy.ndarray. Data to taper.
106
+ :param p: float or sequence of floats. Each float means decimal percentage
107
+ of Tukey taper for corresponding dimension (ranging from 0 to 1).
108
+ Default is 0.1 which tapers 5% from the beginning and 5% from the end.
109
+ If only one float is given, it only do for time dimension.
110
+ :return: Tapered data.
111
+ """
112
+ if len(data.shape) == 1:
113
+ return data * tukey(len(data), p)
114
+ nch, nt = data.shape
115
+ win = np.ones_like(data)
116
+ if not isinstance(p, (tuple, list, np.ndarray)):
117
+ p = (0, p)
118
+
119
+ win *= np.tile(tukey(nch, p[0]), (nt, 1)).T
120
+ win *= np.tile(tukey(nt, p[1]), (nch, 1))
121
+ return data * win
122
+
123
+
124
+ def downsampling(data, xint=None, tint=None, stack=True, lowpass_filter=True):
125
+ """
126
+ Downsample DAS data.
127
+
128
+ :param data: numpy.ndarray. Data to downsample can be 1-D or 2-D.
129
+ :param xint: int. Spatial downsampling factor.
130
+ :param tint: int. Time downsampling factor.
131
+ :param lowpass_filter: bool. Lowpass cheby2 filter before time downsampling
132
+ or not.
133
+ :return: Downsampled data.
134
+ """
135
+ data_ds = data.copy()
136
+ if xint and xint > 1:
137
+ if stack:
138
+ data_ds = stacking(data, xint)
139
+ else:
140
+ data_ds = data_ds[::xint]
141
+ if tint and tint > 1:
142
+ if lowpass_filter:
143
+ data_ds = lowpass_cheby_2(data_ds, 1, 1 / 2 / tint)
144
+ if len(data_ds.shape) == 1:
145
+ data_ds = data_ds[::tint]
146
+ else:
147
+ data_ds = data_ds[:, ::tint]
148
+ return data_ds
149
+
150
+
151
+ def trimming(data, dx=None, fs=None, xmin=0, xmax=None, tmin=0, tmax=None,
152
+ mode=0):
153
+ """
154
+ Cut data to given start and end distance/channel or time/sampling points.
155
+
156
+ :param data: numpy.ndarray. Data to trim can be 1-D or 2-D.
157
+ :param dx: Channel interval in m.
158
+ :param fs: Sampling rate in Hz.
159
+ :param xmin, xmax, tmin, tmax: Boundary for trimming.
160
+ :param mode: 0 means the unit of boundary is channel number and sampling
161
+ points; 1 means the unit of boundary is meters and seconds.
162
+ :return: Trimmed data.
163
+ """
164
+ nch, nt = data.shape
165
+ if mode == 0:
166
+ if xmax is None:
167
+ xmax = nch
168
+ if tmax is None:
169
+ tmax = nt
170
+ elif mode == 1:
171
+ xmin = round(xmin / dx)
172
+ xmax = (round(xmax / dx), nch)[xmax is None]
173
+ tmin = round(tmin * fs)
174
+ tmax = (round(tmax * fs), nt)[tmax is None]
175
+
176
+ return data[xmin:xmax, tmin:tmax]
177
+
178
+
179
+ def padding(data, dn, reverse=False):
180
+ """
181
+ Pad DAS data with 0.
182
+
183
+ :param data: numpy.ndarray. 2D DAS data to pad.
184
+ :param dn: int or sequence of ints. Number of points to pad for both
185
+ dimensions.
186
+ :param reverse: bool. Set True to reverse the operation.
187
+ :return: Padded data.
188
+ """
189
+ nch, nt = data.shape
190
+ if isinstance(dn, int):
191
+ dn = (dn, dn)
192
+
193
+ pad = (dn[0] // 2, dn[0] - dn[0] // 2, dn[1] // 2, dn[1] - dn[1] // 2)
194
+ if reverse:
195
+ return data[pad[0]:nch - pad[1], pad[2]:nt - pad[3]]
196
+ else:
197
+ data_pd = np.zeros((nch + dn[0], nt + dn[1]))
198
+ data_pd[pad[0]:nch + pad[0], pad[2]:nt + pad[2]] = data
199
+ return data_pd
200
+
201
+
202
+ def time_integration(data, fs, c=0):
203
+ """
204
+ Integrate DAS data in time.
205
+
206
+ :param data: numpy.ndarray. 2D DAS data.
207
+ :param fs: Sampling rate in Hz.
208
+ :param c: float. A constant added to the result.
209
+ :return: Integrated data.
210
+ """
211
+ return np.cumsum(data, axis=1) / fs + c
212
+
213
+
214
+ def time_differential(data, fs, prepend=0):
215
+ """
216
+ Differentiate DAS data in time.
217
+
218
+ :param data: numpy.ndarray. 2D DAS data.
219
+ :param fs: Sampling rate in Hz.
220
+ :param prepend: 'mean' or values to prepend to `data` along axis prior to
221
+ performing the difference.
222
+ :return: Differentiated data.
223
+ """
224
+ if prepend == 'mean':
225
+ prepend = np.mean(data, axis=1).reshape((-1, 1))
226
+ return np.diff(data, axis=1, prepend=prepend) * fs
227
+
228
+
229
+ def distance_integration(data, dx, c=0):
230
+ """
231
+ Integrate DAS data in distance.
232
+
233
+ :param data: numpy.ndarray. 2D DAS data.
234
+ :param dx: Channel interval in m.
235
+ :param c: float. A constant added to the result.
236
+ :return: Integrated data.
237
+ """
238
+ return np.cumsum(data, axis=1) * dx + c
@@ -0,0 +1,186 @@
1
+ # Purpose: Plot data
2
+ # Author: Minzhe Hu
3
+ # Date: 2024.10.17
4
+ # Email: hmz2018@mail.ustc.edu.cn
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ from copy import deepcopy
8
+ from collections.abc import Sequence
9
+
10
+
11
+ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=150,
12
+ title=None, transpose=False, t0=0, x0=0, pick=None, f=None, k=None,
13
+ t=None, c=None, cmap=None, vmin=None, vmax=None, xmode='distance',
14
+ tmode='time', xlim=None, ylim=None, xlog=False, ylog=False, xinv=False,
15
+ yinv=False, xlabel=True, ylabel=True, xticklabels=True,
16
+ yticklabels=True, colorbar=True, colorbar_label=None, savefig=None):
17
+ """
18
+ Plot several types of 2-D seismological data.
19
+
20
+ :param data: numpy.ndarray. Data to plot.
21
+ :param dx: Channel interval in m.
22
+ :param fs: Sampling rate in Hz.
23
+ :param ax: Matplotlib.axes.Axes or tuple. Axes to plot. A tuple for new
24
+ figsize. If not specified, the function will directly display the image
25
+ using matplotlib.pyplot.show().
26
+ :param obj: str. Type of data to plot. It should be one of 'waveform',
27
+ 'phasepick', 'spectrum', 'spectrogram', 'fk', or 'dispersion'.
28
+ :param dpi: int. The resolution of the figure in dots-per-inch.
29
+ :param title: str. The title of this axes.
30
+ :param transpose: bool. Transpose the figure or not.
31
+ :param t0, x0: The beginning of time and space.
32
+ :param pick: Sequence of picked phases. Required if obj=='phasepick'.
33
+ :param f: Sequence of frequency. Required if obj is one of 'spectrum',
34
+ 'spectrogram', 'fk' or 'dispersion'.
35
+ :param k: Wavenumber sequence. Required if obj=='fk'.
36
+ :param t: Time sequence. Required if obj=='spectrogram'.
37
+ :param c: Phase velocity sequence. Required if obj=='dispersion'.
38
+ :param cmap: str or Colormap. The Colormap instance or registered colormap
39
+ name used to map scalar data to colors.
40
+ :param vmin, vmax: Define the data range that the colormap covers.
41
+ :param xmode: str. 'distance' or 'channel'.
42
+ :param tmode: str. 'time' or 'sampling'.
43
+ :param xlim, ylim: Set the x-axis and y-axis view limits.
44
+ :param xlog, ylog: bool. If True, set the x-axis' or y-axis' scale as log.
45
+ :param xlabel, yinv: bool. If True, invert x-axis or y-axis.
46
+ :param xlabel, ylabel: bool or str. Whether to plot a label or what label to
47
+ plot for x-axis or y-axis.
48
+ :param xticklabels, yticklabels: bool or sequence of str. Whether to plot
49
+ ticklabels or what ticklabels to plot for x-axis or y-axis.
50
+ :param colorbar: bool, str or Matplotlib.axes.Axes. Bool means plot colorbar
51
+ or not. Str means the location of colorbar. Axes means the Axes into
52
+ which the colorbar will be drawn.
53
+ :param savefig: str or bool. Figure name to save if needed. If True,
54
+ it will be set to parameter obj.
55
+ """
56
+ nch, nt = data.shape
57
+ if ax is None:
58
+ ax = (6, 5)
59
+ if isinstance(ax, tuple):
60
+ fig, ax = plt.subplots(1, figsize=ax, dpi=dpi)
61
+ show = True
62
+ else:
63
+ show = False
64
+
65
+ if obj in ['waveform', 'phasepick']:
66
+ cmap = 'RdBu' if cmap is None else cmap
67
+ vmax = np.percentile(abs(data), 80) if vmax is None else vmax
68
+ vmin = -vmax if vmin is None else vmin
69
+ origin = 'upper'
70
+ if fs is None or tmode == 'sampling':
71
+ ylabel_default = 'Sampling points'
72
+ fs = 1
73
+ elif tmode == 'time':
74
+ ylabel_default = 'Time (s)'
75
+
76
+ if dx is None or xmode.lower() == 'channel':
77
+ xlabel_default = 'Channel'
78
+ extent = [x0, x0 + nch, t0 + nt / fs, t0]
79
+ elif xmode.lower() == 'distance':
80
+ xlabel_default = 'Disitance (km)'
81
+ extent = [x0 * 1e-3, (x0 + nch * dx) * 1e-3, t0 + nt / fs, t0]
82
+
83
+ if obj == 'phasepick' and len(pick):
84
+ pck = np.array(pick).astype(float)
85
+ if xmode.lower() == 'distance':
86
+ pck[:, 0] = (x0 + pck[:, 0] * dx) * 1e-3
87
+ elif xmode.lower() == 'channel':
88
+ pck[:, 0] = x0 + pck[:, 0]
89
+ if tmode.lower() == 'sampling':
90
+ pck[:, 1] = pck[:, 1] / fs
91
+ ax.scatter(pck[:,0], t0 + pck[:,1], marker=',', s=0.1, c='black')
92
+
93
+ elif obj in ['spectrum', 'spectrogram', 'fk', 'dispersion']:
94
+ if isinstance(data[0,0], (complex, np.complex64)):
95
+ data = abs(data)
96
+ cmap = 'jet' if cmap is None else cmap
97
+ vmax = np.percentile(abs(data), 80) if vmax is None else vmax
98
+ vmin = np.percentile(abs(data), 20) if vmin is None else vmin
99
+ if obj == 'spectrum':
100
+ origin = 'lower'
101
+ if dx is None or xmode.lower() == 'channel':
102
+ xlabel_default = 'Channel'
103
+ extent = [x0, x0 + nch, min(f), max(f)]
104
+ elif xmode.lower() == 'distance':
105
+ xlabel_default = 'Disitance (km)'
106
+ extent = [x0 * 1e-3, (x0 + nch * dx) * 1e-3, min(f), max(f)]
107
+ ylabel_default = 'Frequency (Hz)'
108
+ elif obj == 'spectrogram':
109
+ data = data.T
110
+ origin = 'lower'
111
+ xlabel_default = 'Time (s)'
112
+ ylabel_default = 'Frequency (Hz)'
113
+ extent = [t0 + min(t), t0 + max(t), min(f), max(f)]
114
+ elif obj == 'fk':
115
+ origin = 'lower'
116
+ xlabel_default = 'Wavenumber (m$^{-1}$)'
117
+ ylabel_default = 'Frequency (Hz)'
118
+ extent = [min(k), max(k), min(f), max(f)]
119
+ elif obj == 'dispersion':
120
+ data = data.T
121
+ origin = 'lower'
122
+ xlabel_default = 'Frequency (Hz)'
123
+ ylabel_default = 'Phase Velocity (m/s)'
124
+ extent = [min(f), max(f), min(c), max(c)]
125
+
126
+ if transpose:
127
+ if origin == 'lower':
128
+ extent = [extent[2], extent[3], extent[0], extent[1]]
129
+ else:
130
+ origin = 'lower'
131
+ extent = [extent[3], extent[2], extent[0], extent[1]]
132
+ (xlabel_default, ylabel_default) = (ylabel_default, xlabel_default)
133
+ data = data.T
134
+
135
+ xlabel = xlabel if isinstance(xlabel, str) else \
136
+ xlabel_default if xlabel else None
137
+ ylabel = ylabel if isinstance(ylabel, str) else \
138
+ ylabel_default if ylabel else None
139
+
140
+ bar = ax.imshow(data.T, vmin=vmin, vmax=vmax, extent=extent, aspect='auto',
141
+ origin=origin, cmap=cmap)
142
+ if title:
143
+ ax.set_title(title)
144
+ ax.set_xlabel(xlabel)
145
+ ax.set_ylabel(ylabel)
146
+ if isinstance(xticklabels, Sequence):
147
+ ax.set_xticklabels(xticklabels)
148
+ elif not xticklabels:
149
+ ax.set_xticklabels([])
150
+
151
+ if isinstance(yticklabels, Sequence):
152
+ ax.set_yticklabels(yticklabels)
153
+ elif not yticklabels:
154
+ ax.set_yticklabels([])
155
+ if xinv:
156
+ ax.invert_xaxis()
157
+ if yinv:
158
+ ax.invert_yaxis()
159
+ if ylim:
160
+ ax.set_ylim(ylim)
161
+ if xlim:
162
+ ax.set_xlim(xlim)
163
+ if xlog:
164
+ ax.set_xscale('log')
165
+ if ylog:
166
+ ax.set_yscale('log')
167
+ if colorbar:
168
+ if colorbar is True:
169
+ cbar = plt.colorbar(bar, ax=ax, location='right')
170
+ elif isinstance(colorbar, str):
171
+ cbar = plt.colorbar(bar, ax=ax, location=colorbar)
172
+ else:
173
+ cbar = plt.colorbar(bar, cax=colorbar)
174
+ if colorbar_label is not None:
175
+ cbar.set_label(colorbar_label)
176
+
177
+ if savefig:
178
+ if not isinstance(savefig, str):
179
+ savefig = obj + '.png'
180
+ plt.tight_layout()
181
+ plt.savefig(savefig)
182
+ plt.close()
183
+ elif show:
184
+ plt.show()
185
+ else:
186
+ return ax
daspy/core/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from daspy.core.section import Section
2
+ from daspy.core.collection import Collection
3
+ from daspy.core.read import read
4
+ from daspy.core.dasdatetime import DASDateTime, local_tz, utc