DASPy-toolbox 1.2.1__tar.gz → 1.2.2__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.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/PKG-INFO +1 -1
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/PKG-INFO +1 -1
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/strain2vel.py +19 -17
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/basic_tools/freqattributes.py +11 -1
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/basic_tools/preprocessing.py +2 -2
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/read.py +96 -12
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/section.py +11 -2
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/util.py +16 -5
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/write.py +105 -8
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/setup.py +1 -1
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/SOURCES.txt +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/requires.txt +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/DASPy_toolbox.egg-info/top_level.txt +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/LICENSE +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/README.md +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/__init__.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/__init__.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/channel.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/decomposition.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/denoising.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/advanced_tools/fdct.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/basic_tools/__init__.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/basic_tools/filter.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/basic_tools/visualization.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/__init__.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/collection.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/dasdatetime.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/example.pkl +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/daspy/core/make_example.py +0 -0
- {daspy_toolbox-1.2.1 → daspy_toolbox-1.2.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
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.2.
|
|
3
|
+
Version: 1.2.2
|
|
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
|
|
@@ -23,14 +23,14 @@ def fk_rescaling(data, dx, fs, taper=(0.02, 0.05), pad='default', fmax=None,
|
|
|
23
23
|
:param dx: Channel interval in m.
|
|
24
24
|
:param fs: Sampling rate in Hz.
|
|
25
25
|
:param taper: float or sequence of floats. Each float means decimal
|
|
26
|
-
percentage of Tukey taper for corresponding dimension (ranging from 0
|
|
27
|
-
1). Default is 0.1 which tapers 5% from the beginning and 5% from
|
|
28
|
-
end.
|
|
29
|
-
:param pad: Pad the data or not. It can be float or sequence of floats.
|
|
30
|
-
float means padding percentage before FFT for corresponding
|
|
31
|
-
If set to 0.1 will pad 5% before the beginning and after the
|
|
32
|
-
'default' means pad both dimensions to next power of 2. None or
|
|
33
|
-
means don't pad data before or during Fast Fourier Transform.
|
|
26
|
+
percentage of Tukey taper for corresponding dimension (ranging from 0
|
|
27
|
+
to 1). Default is 0.1 which tapers 5% from the beginning and 5% from
|
|
28
|
+
the end.
|
|
29
|
+
:param pad: Pad the data or not. It can be float or sequence of floats.
|
|
30
|
+
Each float means padding percentage before FFT for corresponding
|
|
31
|
+
dimension. If set to 0.1 will pad 5% before the beginning and after the
|
|
32
|
+
end. 'default' means pad both dimensions to next power of 2. None or
|
|
33
|
+
False means don't pad data before or during Fast Fourier Transform.
|
|
34
34
|
:param fmax, kmin, vmax: float or or sequence of 2 floats. Sequence of 2
|
|
35
35
|
floats represents the start and end of taper. Setting these parameters
|
|
36
36
|
can reduce artifacts.
|
|
@@ -71,7 +71,8 @@ def fk_rescaling(data, dx, fs, taper=(0.02, 0.05), pad='default', fmax=None,
|
|
|
71
71
|
kk = np.tile(k, (len(f), 1)).T
|
|
72
72
|
vv = - np.divide(ff, kk, out=np.ones_like(ff) * 1e10, where=kk != 0)
|
|
73
73
|
|
|
74
|
-
mask = fk_fan_mask(f, k, fmax=fmax, kmin=kmin, vmax=vmax, edge=edge)
|
|
74
|
+
mask = fk_fan_mask(f, k, fmax=fmax, kmin=kmin, vmax=vmax, edge=edge) \
|
|
75
|
+
* vv
|
|
75
76
|
mask[kk == 0] = 0
|
|
76
77
|
|
|
77
78
|
data_vel = irfft2(ifftshift(fk * mask, axes=0)).real[:nch, :nt]
|
|
@@ -91,12 +92,12 @@ def curvelet_conversion(data, dx, fs, pad=0.3, scale_begin=2, nbscales=None,
|
|
|
91
92
|
:param data: numpy.ndarray. Data to convert.
|
|
92
93
|
:param dx: Channel interval in m.
|
|
93
94
|
:param fs: Sampling rate in Hz.
|
|
94
|
-
:param pad: float or sequence of floats. Each float means padding
|
|
95
|
-
before FFT for corresponding dimension. If set to 0.1 will
|
|
96
|
-
the beginning and after the end.
|
|
95
|
+
:param pad: float or sequence of floats. Each float means padding
|
|
96
|
+
percentage before FFT for corresponding dimension. If set to 0.1 will
|
|
97
|
+
pad 5% before the beginning and after the end.
|
|
97
98
|
:param scale_begin: int. The beginning scale to do conversion.
|
|
98
|
-
:param nbscales: int. Number of scales including the coarsest wavelet
|
|
99
|
-
Default set to ceil(log2(min(M,N)) - 3).
|
|
99
|
+
:param nbscales: int. Number of scales including the coarsest wavelet
|
|
100
|
+
level. Default set to ceil(log2(min(M,N)) - 3).
|
|
100
101
|
:param nbangles: int. Number of angles at the 2nd coarsest level,
|
|
101
102
|
minimum 8, must be a multiple of 4.
|
|
102
103
|
:param turning: Sequence of int. Channel number of turning points.
|
|
@@ -110,7 +111,8 @@ def curvelet_conversion(data, dx, fs, pad=0.3, scale_begin=2, nbscales=None,
|
|
|
110
111
|
data_vel[s:e] = curvelet_conversion(data[s:e], dx, fs, pad=pad,
|
|
111
112
|
scale_begin=scale_begin,
|
|
112
113
|
nbscales=nbscales,
|
|
113
|
-
nbangles=nbangles,
|
|
114
|
+
nbangles=nbangles,
|
|
115
|
+
turning=None)
|
|
114
116
|
else:
|
|
115
117
|
if pad is None or pad is False:
|
|
116
118
|
pad = 0
|
|
@@ -227,8 +229,8 @@ def slant_stacking(data, dx, fs, L=None, slm=0.01,
|
|
|
227
229
|
for (s, e) in zip(start_ch, end_ch):
|
|
228
230
|
channel_seg = [ch-s for ch in range(s,e) if ch in channel]
|
|
229
231
|
if len(channel_seg):
|
|
230
|
-
d_vel = slant_stacking(data[s:e], dx, fs, L=L, slm=slm,
|
|
231
|
-
frqlow=frqlow, frqhigh=frqhigh,
|
|
232
|
+
d_vel = slant_stacking(data[s:e], dx, fs, L=L, slm=slm,
|
|
233
|
+
sls=sls, frqlow=frqlow, frqhigh=frqhigh,
|
|
232
234
|
turning=None, channel=channel_seg)
|
|
233
235
|
data_vel = np.vstack((data_vel, d_vel))
|
|
234
236
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Analyze frequency attribute and transform in frequency domain
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.11.12
|
|
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
|
|
@@ -147,3 +147,13 @@ def fk_transform(data, dx, fs, taper=(0, 0.05), nfft='default'):
|
|
|
147
147
|
f = rfftfreq(nfft[1], d=1. / fs)
|
|
148
148
|
k = fftshift(fftfreq(nfft[0], d=dx))
|
|
149
149
|
return fk, f, k
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def power(data):
|
|
153
|
+
"""
|
|
154
|
+
Calculate the power of each channel.
|
|
155
|
+
|
|
156
|
+
:param data: numpy.ndarray. Data to calculate the power.
|
|
157
|
+
:return: numpy.ndarray. Power of each channel.
|
|
158
|
+
"""
|
|
159
|
+
return np.sqrt(np.mean(data ** 2, axis=-1))
|
|
@@ -19,10 +19,10 @@ def phase2strain(data, lam, e, n, gl):
|
|
|
19
19
|
:param e: float. photo-slastic scaling factor for logitudinal strain in
|
|
20
20
|
isotropic material.
|
|
21
21
|
:param n: float. Refractive index of the sensing fiber.
|
|
22
|
-
:paran
|
|
22
|
+
:paran guage_length: float. Gauge length.
|
|
23
23
|
:return: Strain data.
|
|
24
24
|
"""
|
|
25
|
-
return data *
|
|
25
|
+
return data * lam / (e * 4 * np.pi * n * gl)
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def normalization(data, method='z-score'):
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# Purpose: Module for reading DAS data.
|
|
2
|
-
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
2
|
+
# Author: Minzhe Hu, Ji Zhang
|
|
3
|
+
# Date: 2025.11.19
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
# Partially modified from
|
|
6
6
|
# https://github.com/RobbinLuo/das-toolkit/blob/main/DasTools/DasPrep.py
|
|
7
7
|
import warnings
|
|
8
|
+
import inspect
|
|
8
9
|
import json
|
|
9
10
|
import pickle
|
|
10
11
|
import numpy as np
|
|
11
12
|
import h5py
|
|
12
13
|
import segyio
|
|
14
|
+
from functools import wraps
|
|
13
15
|
from typing import Union
|
|
14
16
|
from pathlib import Path
|
|
15
17
|
from nptdms import TdmsFile
|
|
@@ -73,13 +75,8 @@ def read(fname=None, output_type='section', ftype=None, file_format='auto',
|
|
|
73
75
|
kwargs['chmin'] = kwargs.pop('ch1', None)
|
|
74
76
|
kwargs['chmax'] = kwargs.pop('ch2', None)
|
|
75
77
|
if callable(ftype):
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
except TypeError:
|
|
79
|
-
data, metadata = ftype(fname)
|
|
80
|
-
si, sj, metadata = _trimming_slice_metadata(data.shape,
|
|
81
|
-
metadata=metadata, **kwargs)
|
|
82
|
-
data = data[si, sj]
|
|
78
|
+
ftype = with_trimming(ftype)
|
|
79
|
+
data, metadata = ftype(fname, headonly=headonly, **kwargs)
|
|
83
80
|
else:
|
|
84
81
|
for rtp in [('pickle', 'pkl'), ('hdf5', 'h5'), ('segy', 'sgy')]:
|
|
85
82
|
ftype = ftype.replace(*rtp)
|
|
@@ -97,6 +94,43 @@ def read(fname=None, output_type='section', ftype=None, file_format='auto',
|
|
|
97
94
|
return data, metadata
|
|
98
95
|
|
|
99
96
|
|
|
97
|
+
def with_trimming(func):
|
|
98
|
+
"""
|
|
99
|
+
Decorator that wraps a custom reader so it automatically supports
|
|
100
|
+
trimming parameters (chmin, chmax, dch, xmin, xmax, tmin, tmax, spmin, spmax).
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@wraps(func)
|
|
104
|
+
def wrapper(fname, headonly=False, **kwargs):
|
|
105
|
+
# trimming-related parameters
|
|
106
|
+
trim_keys = ['chmin', 'chmax', 'dch', 'xmin', 'xmax', 'tmin', 'tmax',
|
|
107
|
+
'spmin', 'spmax']
|
|
108
|
+
sig = inspect.signature(func)
|
|
109
|
+
reader_params = set(sig.parameters.keys())
|
|
110
|
+
trim_for_reader = {k: kwargs.pop(k) for k in trim_keys if k in kwargs \
|
|
111
|
+
and k in reader_params}
|
|
112
|
+
trim_for_trimming = {k: kwargs.pop(k) for k in trim_keys if k in \
|
|
113
|
+
kwargs and k not in reader_params}
|
|
114
|
+
try:
|
|
115
|
+
data, metadata = func(fname, headonly=headonly, **trim_for_reader,
|
|
116
|
+
**kwargs)
|
|
117
|
+
except TypeError:
|
|
118
|
+
headonly = False
|
|
119
|
+
data, metadata = func(fname, **trim_for_reader)
|
|
120
|
+
|
|
121
|
+
shape = data.shape
|
|
122
|
+
si, sj, metadata = _trimming_slice_metadata(shape, metadata=metadata,
|
|
123
|
+
**trim_for_trimming)
|
|
124
|
+
if headonly:
|
|
125
|
+
data = np.zeros(shape)[si, sj]
|
|
126
|
+
else:
|
|
127
|
+
data = data[si, sj]
|
|
128
|
+
|
|
129
|
+
return data, metadata
|
|
130
|
+
|
|
131
|
+
return wrapper
|
|
132
|
+
|
|
133
|
+
|
|
100
134
|
def _read_pkl(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
101
135
|
dch=1, xmin=None, xmax=None, tmin=None, tmax=None, spmin=None,
|
|
102
136
|
spmax=None):
|
|
@@ -290,6 +324,34 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
290
324
|
'start_time': stime,
|
|
291
325
|
'gauge_length': attrs['GaugeLength']}
|
|
292
326
|
|
|
327
|
+
elif file_format == 'Puniu Tech HiFi-DAS':
|
|
328
|
+
dataset = h5_file['default']
|
|
329
|
+
if 'time,channel' in attrs.get('row_major_order', 'time, channel')\
|
|
330
|
+
.replace(' ', '').lower():
|
|
331
|
+
transpose = True
|
|
332
|
+
|
|
333
|
+
attrs = {k: (v.decode() if isinstance(v, bytes) else v) for k, v
|
|
334
|
+
in dataset.attrs.items()}
|
|
335
|
+
step = int(attrs['step'])
|
|
336
|
+
dx = step * attrs.get('spatial_sampling_rate', 1.0)
|
|
337
|
+
start_channel = int(attrs['start_channel'])
|
|
338
|
+
if step != 1:
|
|
339
|
+
if chmin:
|
|
340
|
+
chmin = (chmin - start_channel) / step + start_channel
|
|
341
|
+
if chmax:
|
|
342
|
+
chmax = (chmin - start_channel) / step + start_channel
|
|
343
|
+
t0 = int(attrs.get('epoch', 0)) + int(attrs.get('ns', 0)) * 1e-9
|
|
344
|
+
data_type = 'strain rate' if attrs.get('format', '') == \
|
|
345
|
+
'differential' else 'strain',
|
|
346
|
+
metadata = {'dx': dx, 'fs': float(attrs['sampling_rate']),
|
|
347
|
+
'start_channel': start_channel,
|
|
348
|
+
'start_distance': start_channel * dx,
|
|
349
|
+
'start_time': DASDateTime.fromtimestamp(t0, tz=utc),
|
|
350
|
+
'scale': 110.37, 'data_type': data_type,
|
|
351
|
+
'cid': attrs.get('cid', '')}
|
|
352
|
+
if 'spatial_resolution' in attrs.keys():
|
|
353
|
+
metadata['gauge_length'] = float(attrs['spatial_resolution'])
|
|
354
|
+
|
|
293
355
|
elif file_format == 'Silixa iDAS':
|
|
294
356
|
dataset = h5_file['Acquisition/Raw[0]/RawData/']
|
|
295
357
|
attrs = h5_file['Acquisition/Raw[0]'].attrs
|
|
@@ -356,13 +418,36 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
356
418
|
metadata = {'dx': h5_file['Sampling_interval_in_space'][0],
|
|
357
419
|
'fs': 1 / h5_file['Sampling_interval_in_time'][0]}
|
|
358
420
|
|
|
421
|
+
elif file_format == 'NEC':
|
|
422
|
+
dataset = h5_file['data']
|
|
423
|
+
dx = dataset.attrs['Interval of monitor point']
|
|
424
|
+
fs = 1.0 / (dataset.attrs['Interval time of data'] / 1000.0) # Hz
|
|
425
|
+
if dataset.shape[0] != \
|
|
426
|
+
dataset.attrs['Number of requested location points']:
|
|
427
|
+
transpose = True
|
|
428
|
+
try:
|
|
429
|
+
scale = dataset.attrs['Radians peer digital value']
|
|
430
|
+
except KeyError:
|
|
431
|
+
try:
|
|
432
|
+
scale = dataset.attrs['Radians per digital value']
|
|
433
|
+
except KeyError:
|
|
434
|
+
scale = 1
|
|
435
|
+
# start_time = datetime(1970, 1, 1) + \
|
|
436
|
+
# timedelta(milliseconds=start_unix_epoch_in_ms)
|
|
437
|
+
start_time = DASDateTime.fromtimestamp(
|
|
438
|
+
np.float64(dataset.attrs['Time of sending request']) / 1e3
|
|
439
|
+
).utc()
|
|
440
|
+
metadata = {'fs': fs, 'dx': dx, 'start_time': start_time,
|
|
441
|
+
'gauge_length': dataset.attrs['Gauge length'],
|
|
442
|
+
'scale': scale, 'data_type':'strain rate'}
|
|
443
|
+
|
|
359
444
|
elif file_format == 'FORESEE':
|
|
360
445
|
dataset = h5_file['raw']
|
|
361
446
|
fs = round(1 / np.diff(h5_file['timestamp']).mean())
|
|
362
447
|
start_time = DASDateTime.fromtimestamp(
|
|
363
448
|
h5_file['timestamp'][0]).astimezone(utc)
|
|
364
|
-
warnings.warn('This data format doesn\'t include channel interval.
|
|
365
|
-
|
|
449
|
+
warnings.warn('This data format doesn\'t include channel interval.'
|
|
450
|
+
' Please set manually')
|
|
366
451
|
metadata = {'dx': None, 'fs': fs, 'start_time': start_time}
|
|
367
452
|
|
|
368
453
|
elif file_format == 'AI4EPS': # https://ai4eps.github.io/homepage/ml4earth/seismic_event_format_das/
|
|
@@ -500,7 +585,6 @@ def _read_tdms(fname, headonly=False, file_format='auto', chmin=None,
|
|
|
500
585
|
data = np.asarray([tdms_file[key][str(ch)][sj] for ch in
|
|
501
586
|
range(si.start, si.stop, si.step)])
|
|
502
587
|
elif file_format == 'Institute of Semiconductors, CAS':
|
|
503
|
-
|
|
504
588
|
try:
|
|
505
589
|
start_channel = int(properties['Initial Channel'])
|
|
506
590
|
except KeyError:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling Section objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.11.19
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import warnings
|
|
6
6
|
import os
|
|
@@ -21,7 +21,7 @@ from daspy.basic_tools.preprocessing import (phase2strain, normalization,
|
|
|
21
21
|
from daspy.basic_tools.filter import (bandpass, bandstop, lowpass,
|
|
22
22
|
lowpass_cheby_2, highpass, envelope)
|
|
23
23
|
from daspy.basic_tools.freqattributes import (spectrum, spectrogram, psd,
|
|
24
|
-
fk_transform)
|
|
24
|
+
fk_transform, power)
|
|
25
25
|
from daspy.advanced_tools.channel import channel_checking, turning_points
|
|
26
26
|
from daspy.advanced_tools.denoising import (curvelet_denoising,
|
|
27
27
|
common_mode_noise_removal,
|
|
@@ -68,6 +68,7 @@ class Section(object):
|
|
|
68
68
|
opt_attrs = ['origin_time', 'gauge_length', 'data_type', 'scale',
|
|
69
69
|
'geometry', 'turning_channels', 'headers', 'source',
|
|
70
70
|
'source_type', 'file_format']
|
|
71
|
+
kwargs.setdefault('scale', 1)
|
|
71
72
|
for attr in opt_attrs:
|
|
72
73
|
if attr in kwargs:
|
|
73
74
|
setattr(self, attr, kwargs.pop(attr))
|
|
@@ -1132,6 +1133,14 @@ class Section(object):
|
|
|
1132
1133
|
"""
|
|
1133
1134
|
return fk_transform(self.data, self.dx, self.fs, **kwargs)
|
|
1134
1135
|
|
|
1136
|
+
def power(self):
|
|
1137
|
+
"""
|
|
1138
|
+
Calculate the power of each channel.
|
|
1139
|
+
|
|
1140
|
+
:return: numpy.ndarray. Power of each channel.
|
|
1141
|
+
"""
|
|
1142
|
+
return power(self.data)
|
|
1143
|
+
|
|
1135
1144
|
def channel_checking(self, use=False, **kwargs):
|
|
1136
1145
|
"""
|
|
1137
1146
|
Use the energy of each channel to determine which channels are bad.
|
|
@@ -21,13 +21,16 @@ def _device_standardized_name(file_format: str) -> str:
|
|
|
21
21
|
'OptaSense ODH4+': ['optasenseodh4+', 'odh4+', 'optasenseodh4plus',
|
|
22
22
|
'odh4plus'],
|
|
23
23
|
'OptaSense QuantX': ['optasensequantx', 'quantx'],
|
|
24
|
+
'Puniu Tech HiFi-DAS': ['puniutechhifidas, puniu, puniutech, hifidas',
|
|
25
|
+
'puniuhifidas', 'puniudas'],
|
|
24
26
|
'Silixa iDAS': ['silixaidas', 'silixaidasv1', 'idasv1', 'idas'],
|
|
25
27
|
'Silixa iDAS-v2': ['silixaidasv2', 'idasv2'],
|
|
26
28
|
'Silixa iDAS-v3': ['silixaidasv3', 'idasv3'],
|
|
27
29
|
'Silixa iDAS-MG': ['silixaidasmg', 'idasmg'],
|
|
28
30
|
'Silixa Carina': ['silixacarina', 'carina'],
|
|
29
|
-
'Sintela Onyx v1.0': ['sintelaonyxv1.0', 'sintelaonyxv1',
|
|
30
|
-
'sintela', 'onyxv1.0', 'onyxv1',
|
|
31
|
+
'Sintela Onyx v1.0': ['sintelaonyxv1.0', 'sintelaonyxv1',
|
|
32
|
+
'sintalaonyx', 'sintela', 'onyxv1.0', 'onyxv1',
|
|
33
|
+
'onyx'],
|
|
31
34
|
'T8 Sensor': ['t8sensor', 't8'],
|
|
32
35
|
'Smart Earth ZD-DAS': ['smartearthzddas', 'smartearth', 'zddas',
|
|
33
36
|
'smartearthsensingzddas', 'smartearthsensing',
|
|
@@ -37,7 +40,9 @@ def _device_standardized_name(file_format: str) -> str:
|
|
|
37
40
|
'instituteofsemiconductorscas'],
|
|
38
41
|
'AI4EPS': ['ai4eps', 'daseventdata'],
|
|
39
42
|
'INGV': ['ingv', 'istitutonazionaledigeofisicaevulcanologia'],
|
|
40
|
-
'JAMSTEC': ['jamstec',
|
|
43
|
+
'JAMSTEC': ['jamstec',
|
|
44
|
+
'japanagencyformarineearthscienceandtechnology'],
|
|
45
|
+
'NEC': ['nec', 'nipponelectriccompany'],
|
|
41
46
|
'FORESEE': ['forsee', 'fiberopticforenvironmentsenseing'],
|
|
42
47
|
'Unknown0': ['unknown0'],
|
|
43
48
|
'Unknown': ['unknown', 'other']
|
|
@@ -88,16 +93,22 @@ def _h5_file_format(h5_file):
|
|
|
88
93
|
file_format = 'Sintela Onyx v1.0'
|
|
89
94
|
except KeyError:
|
|
90
95
|
pass
|
|
96
|
+
elif 'default' in keys:
|
|
97
|
+
file_format = 'Puniu Tech HiFi-DAS'
|
|
91
98
|
elif set(keys) == {'Mapping', 'Acquisition'}:
|
|
92
99
|
file_format = 'Silixa iDAS'
|
|
93
|
-
elif list(keys) == ['data']:
|
|
94
|
-
file_format == 'AI4EPS'
|
|
95
100
|
elif set(keys) == {'ChannelMap', 'Fiber', 'cm', 't', 'x'}:
|
|
96
101
|
file_format = 'INGV'
|
|
97
102
|
elif set(keys) == {'DAS_record', 'Sampling_interval_in_space',
|
|
98
103
|
'Sampling_interval_in_time', 'Sampling_points_in_space',
|
|
99
104
|
'Sampling_points_in_time'}:
|
|
100
105
|
file_format = 'JAMSTEC'
|
|
106
|
+
elif list(keys) == ['data']:
|
|
107
|
+
if 'Interval of monitor point' in \
|
|
108
|
+
list(h5_file['data'].attrs['Interval of monitor point'].keys()):
|
|
109
|
+
file_format = 'NEC'
|
|
110
|
+
else:
|
|
111
|
+
file_format = 'AI4EPS'
|
|
101
112
|
elif set(keys) == {'raw', 'timestamp'}:
|
|
102
113
|
file_format = 'FORESEE'
|
|
103
114
|
elif list(keys) == ['ProcessedData']:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for writing DAS data.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.11.19
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
6
|
import warnings
|
|
@@ -192,9 +192,39 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
192
192
|
h5_file.get('Acquisition/Raw[0]/').\
|
|
193
193
|
create_dataset('RawDataTime', data=datatime)
|
|
194
194
|
h5_file['Acquisition/Raw[0]'].attrs['OutputDataRate'] = sec.fs
|
|
195
|
-
h5_file['Acquisition'].attrs['SpatialSamplingInterval'] =
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
h5_file['Acquisition'].attrs['SpatialSamplingInterval'] = \
|
|
196
|
+
sec.dx
|
|
197
|
+
h5_file['Acquisition'].attrs['GaugeLength'] = \
|
|
198
|
+
sec.gauge_length if hasattr(sec, 'gauge_length') else -1
|
|
199
|
+
|
|
200
|
+
elif file_format == 'Puniu Tech HiFi-DAS':
|
|
201
|
+
h5_file.create_dataset('default', data=sec.data)
|
|
202
|
+
h5_file['default'].attrs['row_major_order'] = 'channel, time'
|
|
203
|
+
h5_file['default'].attrs['spatial_sampling_rate'] = sec.dx
|
|
204
|
+
h5_file['default'].attrs['step'] = 1
|
|
205
|
+
h5_file['default'].attrs['sampling_rate'] = sec.fs
|
|
206
|
+
h5_file['default'].attrs['start_channel'] = sec.start_channel
|
|
207
|
+
if isinstance(sec.start_time, datetime):
|
|
208
|
+
t0 = sec.start_time.timestamp()
|
|
209
|
+
else:
|
|
210
|
+
t0 = sec.start_time
|
|
211
|
+
epoch = int(t0)
|
|
212
|
+
h5_file['default'].attrs['epoch'] = epoch
|
|
213
|
+
h5_file['default'].attrs['ns'] = int(round((t0 - epoch) * 1e9))
|
|
214
|
+
if hasattr(sec, 'data_type'):
|
|
215
|
+
h5_file['default'].attrs['format'] = 'differential' if \
|
|
216
|
+
sec.data_type == 'strain rate' else sec.data_type
|
|
217
|
+
else:
|
|
218
|
+
h5_file['default'].attrs['format'] = 'unknown'
|
|
219
|
+
|
|
220
|
+
if hasattr(sec, 'gauge_length'):
|
|
221
|
+
h5_file['default'].attrs['spatial_resolution'] = \
|
|
222
|
+
sec.gauge_length
|
|
223
|
+
try:
|
|
224
|
+
h5_file['default'].attrs['cid'] = \
|
|
225
|
+
sec.headers['default']['attrs']['cid']
|
|
226
|
+
except KeyError:
|
|
227
|
+
h5_file['default'].attrs['cid'] = 'unknown'
|
|
198
228
|
|
|
199
229
|
elif file_format == 'Silixa iDAS':
|
|
200
230
|
h5_file.create_group('Acquisition/Raw[0]')
|
|
@@ -273,7 +303,6 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
273
303
|
h5_file.attrs['FilterGain'] = 116e-9 * sec.fs / gauge_length / \
|
|
274
304
|
8192 / scale
|
|
275
305
|
|
|
276
|
-
|
|
277
306
|
elif file_format in 'JAMSTEC':
|
|
278
307
|
h5_file.create_dataset('DAS_record', data=sec.data)
|
|
279
308
|
h5_file.create_dataset('Sampling_interval_in_space',
|
|
@@ -281,6 +310,23 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
281
310
|
h5_file.create_dataset('Sampling_interval_in_time',
|
|
282
311
|
data=[1/sec.fs])
|
|
283
312
|
|
|
313
|
+
elif file_format == 'NEC':
|
|
314
|
+
h5_file.create_dataset('data', data=sec.data)
|
|
315
|
+
h5_file['data'].attrs['Interval of monitor point'] = sec.dx
|
|
316
|
+
h5_file['data'].attrs['Number of requested location points'] \
|
|
317
|
+
= sec.nch
|
|
318
|
+
h5_file['data'].attrs['Interval time of data'] = \
|
|
319
|
+
1 / sec.fs * 1e3
|
|
320
|
+
h5_file['data'].attrs['Radians per digital value'] = \
|
|
321
|
+
sec.scale if hasattr(sec, 'scale') else 1
|
|
322
|
+
if isinstance(sec.start_time, datatime):
|
|
323
|
+
t0 = sec.start_time.timestamp()
|
|
324
|
+
else:
|
|
325
|
+
t0 = sec.start_time
|
|
326
|
+
h5_file['data'].attrs['Time of sending request'] = t0 * 1e3
|
|
327
|
+
h5_file['data'].attrs['Gauge length'] = sec.gauge_length if \
|
|
328
|
+
hasattr(sec, 'gauge_length') else -1
|
|
329
|
+
|
|
284
330
|
elif file_format == 'FORESEE':
|
|
285
331
|
h5_file.create_dataset('raw', data=sec.data)
|
|
286
332
|
start_time = sec.start_time.timestamp() if \
|
|
@@ -463,9 +509,42 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
463
509
|
_update_h5_dataset(h5_file, 'Acquisition/Raw[0]/',
|
|
464
510
|
'RawDataTime', DataTime)
|
|
465
511
|
h5_file['Acquisition/Raw[0]'].attrs['OutputDataRate'] = sec.fs
|
|
466
|
-
h5_file['Acquisition'].attrs['SpatialSamplingInterval'] =
|
|
467
|
-
|
|
468
|
-
|
|
512
|
+
h5_file['Acquisition'].attrs['SpatialSamplingInterval'] = \
|
|
513
|
+
sec.dx
|
|
514
|
+
h5_file['Acquisition'].attrs['GaugeLength'] = \
|
|
515
|
+
sec.gauge_length if hasattr(sec, 'gauge_length') else -1
|
|
516
|
+
|
|
517
|
+
elif file_format == 'Puniu Tech HiFi-DAS':
|
|
518
|
+
attrs = {k: (v.decode() if isinstance(v, bytes) else v) for k,
|
|
519
|
+
v in h5_file['default'].attrs.items()}
|
|
520
|
+
if 'time,channel' in attrs.get('row_major_order',
|
|
521
|
+
'time, channel').replace(' ', '').lower():
|
|
522
|
+
_update_h5_dataset(h5_file, '/', 'default', sec.data.T)
|
|
523
|
+
else:
|
|
524
|
+
_update_h5_dataset(h5_file, '/', 'default', sec.data)
|
|
525
|
+
|
|
526
|
+
h5_file['default'].attrs['spatial_sampling_rate'] = sec.dx / \
|
|
527
|
+
attrs['step']
|
|
528
|
+
h5_file['default'].attrs['sampling_rate'] = sec.fs
|
|
529
|
+
h5_file['default'].attrs['start_channel'] = sec.start_channel
|
|
530
|
+
if isinstance(sec.start_time, datetime):
|
|
531
|
+
t0 = sec.start_time.timestamp()
|
|
532
|
+
else:
|
|
533
|
+
t0 = sec.start_time
|
|
534
|
+
epoch = int(t0)
|
|
535
|
+
h5_file['default'].attrs['epoch'] = epoch
|
|
536
|
+
h5_file['default'].attrs['ns'] = int(round((t0 - epoch) * 1e9))
|
|
537
|
+
if hasattr(sec, 'data_type'):
|
|
538
|
+
h5_file['default'].attrs['format'] = 'differential' if \
|
|
539
|
+
sec.data_type == 'strain rate' else sec.data_type
|
|
540
|
+
if hasattr(sec, 'gauge_length'):
|
|
541
|
+
h5_file['default'].attrs['spatial_resolution'] = \
|
|
542
|
+
sec.gauge_length
|
|
543
|
+
try:
|
|
544
|
+
h5_file['default'].attrs['cid'] = \
|
|
545
|
+
sec.headers['default']['attrs']['cid']
|
|
546
|
+
except KeyError:
|
|
547
|
+
pass
|
|
469
548
|
|
|
470
549
|
elif file_format == 'Silixa iDAS':
|
|
471
550
|
if h5_file['Acquisition/Raw[0]/RawData/'].shape[0] != \
|
|
@@ -538,6 +617,24 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
538
617
|
_update_h5_dataset(h5_file, '/', 'Sampling_interval_in_time',
|
|
539
618
|
[1/sec.fs])
|
|
540
619
|
|
|
620
|
+
elif file_format == 'NEC':
|
|
621
|
+
_update_h5_dataset(h5_file, '/', 'data', sec.data)
|
|
622
|
+
h5_file['data'].attrs['Interval of monitor point'] = sec.dx
|
|
623
|
+
h5_file['data'].attrs['Number of requested location points'] \
|
|
624
|
+
= sec.nch
|
|
625
|
+
h5_file['data'].attrs['Interval time of data'] = \
|
|
626
|
+
1 / sec.fs * 1e3
|
|
627
|
+
if hasattr(sec, scale):
|
|
628
|
+
h5_file['data'].attrs['Radians per digital value'] = \
|
|
629
|
+
sec.scale
|
|
630
|
+
if isinstance(sec.start_time, datatime):
|
|
631
|
+
t0 = sec.start_time.timestamp()
|
|
632
|
+
else:
|
|
633
|
+
t0 = sec.start_time
|
|
634
|
+
h5_file['data'].attrs['Time of sending request'] = t0 * 1e3
|
|
635
|
+
if hasattr(sec, 'gauge_length'):
|
|
636
|
+
h5_file['data'].attrs['Gauge length'] = sec.gauge_length
|
|
637
|
+
|
|
541
638
|
elif file_format == 'FORESEE':
|
|
542
639
|
_update_h5_dataset(h5_file, '/', 'raw', sec.data)
|
|
543
640
|
DataTime = sec.start_time.timestamp() + \
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
|
-
name='DASPy-toolbox', version='1.2.
|
|
5
|
+
name='DASPy-toolbox', version='1.2.2',
|
|
6
6
|
description=(
|
|
7
7
|
'DASPy is an open-source project dedicated to provide a python package '
|
|
8
8
|
'for DAS (Distributed Acoustic Sensing) data processing, which '
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|