DASPy-toolbox 1.2.0__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.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/PKG-INFO +1 -1
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/SOURCES.txt +1 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/PKG-INFO +1 -1
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/denoising.py +2 -2
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/basic_tools/preprocessing.py +26 -9
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/collection.py +28 -28
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/dasdatetime.py +1 -1
- daspy_toolbox-1.2.1/daspy/core/make_example.py +32 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/read.py +18 -21
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/section.py +31 -18
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/write.py +9 -4
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/setup.py +3 -3
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/requires.txt +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/DASPy_toolbox.egg-info/top_level.txt +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/LICENSE +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/README.md +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/__init__.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/__init__.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/channel.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/decomposition.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/fdct.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/advanced_tools/strain2vel.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/basic_tools/__init__.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/basic_tools/filter.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/basic_tools/freqattributes.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/basic_tools/visualization.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/__init__.py +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/example.pkl +0 -0
- {daspy_toolbox-1.2.0 → daspy_toolbox-1.2.1}/daspy/core/util.py +0 -0
- {daspy_toolbox-1.2.0 → 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.2.
|
|
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.2.
|
|
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,9 +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
5
|
import warnings
|
|
6
6
|
import numpy as np
|
|
7
|
+
from numpy.fft import rfft, irfft, rfftfreq
|
|
7
8
|
from scipy.signal import detrend
|
|
8
9
|
from scipy.signal.windows import tukey
|
|
9
10
|
from daspy.basic_tools.filter import lowpass_cheby_2
|
|
@@ -320,7 +321,7 @@ def padding(data, dn, reverse=False):
|
|
|
320
321
|
return data_pd
|
|
321
322
|
|
|
322
323
|
|
|
323
|
-
def time_integration(data, fs, c=0):
|
|
324
|
+
def time_integration(data, fs, domain='time', c=0):
|
|
324
325
|
"""
|
|
325
326
|
Integrate DAS data in time.
|
|
326
327
|
|
|
@@ -329,10 +330,19 @@ def time_integration(data, fs, c=0):
|
|
|
329
330
|
:param c: float. A constant added to the result.
|
|
330
331
|
:return: Integrated data.
|
|
331
332
|
"""
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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):
|
|
336
346
|
"""
|
|
337
347
|
Differentiate DAS data in time.
|
|
338
348
|
|
|
@@ -342,9 +352,16 @@ def time_differential(data, fs, prepend=0):
|
|
|
342
352
|
performing the difference.
|
|
343
353
|
:return: Differentiated data.
|
|
344
354
|
"""
|
|
345
|
-
if
|
|
346
|
-
prepend
|
|
347
|
-
|
|
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))
|
|
348
365
|
|
|
349
366
|
|
|
350
367
|
def distance_integration(data, dx, c=0):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling Collection objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.9.
|
|
3
|
+
# Date: 2025.9.18
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
6
|
import warnings
|
|
@@ -277,10 +277,11 @@ class Collection(object):
|
|
|
277
277
|
if len(flist) == 1:
|
|
278
278
|
sec = read(flist[0], tmin=tmin, tmax=tmax, **kwargs)
|
|
279
279
|
else:
|
|
280
|
-
sec = read(flist[0], tmin=tmin, **kwargs)
|
|
280
|
+
sec = read(flist[0], tmin=tmin-tolerance, **kwargs)
|
|
281
281
|
for f in flist[1:-1]:
|
|
282
282
|
sec += read(f, **kwargs)
|
|
283
|
-
sec += read(flist[-1], tmax=tmax, **kwargs)
|
|
283
|
+
sec += read(flist[-1], tmax=tmax+tolerance, **kwargs)
|
|
284
|
+
sec.trimming(tmin=tmin, tmax=tmax)
|
|
284
285
|
return sec
|
|
285
286
|
else:
|
|
286
287
|
self.flist = flist
|
|
@@ -326,8 +327,8 @@ class Collection(object):
|
|
|
326
327
|
kwargs_list[j]['zi'] = 0
|
|
327
328
|
|
|
328
329
|
def process(self, operations, savepath='./processed', merge=1,
|
|
329
|
-
suffix='_pro', ftype=None, dtype=None,
|
|
330
|
-
tolerance=0.5, **read_kwargs):
|
|
330
|
+
suffix='_pro', ftype=None, dtype=None, file_format='auto',
|
|
331
|
+
save_operations=False, tolerance=0.5, **read_kwargs):
|
|
331
332
|
"""
|
|
332
333
|
:param operations: list or None. Each element of operations list
|
|
333
334
|
should be [str of method name, dict of kwargs]. None for read
|
|
@@ -339,6 +340,8 @@ class Collection(object):
|
|
|
339
340
|
:param ftype: None or str. File format for saving. None for automatic
|
|
340
341
|
detection, or 'pkl', 'pickle', 'tdms', 'h5', 'hdf5', 'segy', 'sgy',
|
|
341
342
|
'npy'.
|
|
343
|
+
:param file_format: Format in which the file is saved.
|
|
344
|
+
:type file_format: str or function
|
|
342
345
|
:param dtype: str. The data type of the saved data.
|
|
343
346
|
:parma save_operations: bool. If True, save the operations to
|
|
344
347
|
method_list.pkl and kwargs_list.pkl in savepath.
|
|
@@ -369,7 +372,8 @@ class Collection(object):
|
|
|
369
372
|
warnings.warn(f'{f} is an empty file. Continuous data is '
|
|
370
373
|
'interrupted here.')
|
|
371
374
|
if m > 0:
|
|
372
|
-
sec_merge.save(filepath,
|
|
375
|
+
sec_merge.save(filepath, file_format=file_format,
|
|
376
|
+
dtype=dtype)
|
|
373
377
|
m = 0
|
|
374
378
|
self._kwargs_initialization(method_list, kwargs_list)
|
|
375
379
|
continue
|
|
@@ -377,7 +381,8 @@ class Collection(object):
|
|
|
377
381
|
sec = read(f, ftype=self.ftype, **read_kwargs)
|
|
378
382
|
if sec.data.size == 0:
|
|
379
383
|
if m > 0:
|
|
380
|
-
sec_merge.save(filepath,
|
|
384
|
+
sec_merge.save(filepath, ftype=ftype,
|
|
385
|
+
file_format=file_format, dtype=dtype)
|
|
381
386
|
m = 0
|
|
382
387
|
self._kwargs_initialization(method_list, kwargs_list)
|
|
383
388
|
continue
|
|
@@ -385,23 +390,24 @@ class Collection(object):
|
|
|
385
390
|
warnings.warn(f'Error reading {f}: {e}. Continuous data is '
|
|
386
391
|
'interrupted here.')
|
|
387
392
|
if m > 0:
|
|
388
|
-
sec_merge.save(filepath,
|
|
393
|
+
sec_merge.save(filepath, ftype=ftype,
|
|
394
|
+
file_format=file_format, dtype=dtype)
|
|
389
395
|
m = 0
|
|
390
396
|
self._kwargs_initialization(method_list, kwargs_list)
|
|
391
397
|
continue
|
|
392
398
|
for j, method in enumerate(method_list):
|
|
393
399
|
if method in ['taper', 'cosine_taper']:
|
|
394
400
|
if not ((i==0 and kwargs_list[j]['side'] != 'right') or
|
|
395
|
-
(i == len(self) - 1 and kwargs_list[j]['side']
|
|
396
|
-
|
|
401
|
+
(i == len(self) - 1 and kwargs_list[j]['side']
|
|
402
|
+
!= 'left')):
|
|
397
403
|
continue
|
|
398
404
|
out = getattr(sec, method)(**kwargs_list[j])
|
|
399
405
|
if method == 'time_integration':
|
|
400
406
|
kwargs_list[j]['c'] = sec.data[:, -1].copy()
|
|
401
407
|
elif method == 'time_differential':
|
|
402
408
|
kwargs_list[j]['prepend'] = sec.data[:, -1].copy()
|
|
403
|
-
elif method in ['bandpass', 'bandstop', 'lowpass',
|
|
404
|
-
'lowpass_cheby_2']:
|
|
409
|
+
elif method in ['bandpass', 'bandstop', 'lowpass',
|
|
410
|
+
'highpass', 'lowpass_cheby_2']:
|
|
405
411
|
kwargs_list[j]['zi'] = out
|
|
406
412
|
|
|
407
413
|
if m == 0:
|
|
@@ -415,7 +421,8 @@ class Collection(object):
|
|
|
415
421
|
warnings.warn(f'The start time of {f} does not correspond '
|
|
416
422
|
'to the end time of the previous file. '
|
|
417
423
|
'Continuous data is interrupted here.')
|
|
418
|
-
sec_merge.save(filepath,
|
|
424
|
+
sec_merge.save(filepath, ftype=ftype,
|
|
425
|
+
file_format=file_format, dtype=dtype)
|
|
419
426
|
sec_merge = sec
|
|
420
427
|
f0, f1 = os.path.splitext(os.path.basename(f))
|
|
421
428
|
f1 = f1 if ftype is None else ftype
|
|
@@ -423,10 +430,12 @@ class Collection(object):
|
|
|
423
430
|
m = 0
|
|
424
431
|
m += 1
|
|
425
432
|
if m == merge:
|
|
426
|
-
sec_merge.save(filepath,
|
|
433
|
+
sec_merge.save(filepath, ftype=ftype,
|
|
434
|
+
file_format=file_format, dtype=dtype)
|
|
427
435
|
m = 0
|
|
428
436
|
if m > 0:
|
|
429
|
-
sec_merge.save(filepath,
|
|
437
|
+
sec_merge.save(filepath, ftype=ftype, file_format=file_format,
|
|
438
|
+
dtype=dtype)
|
|
430
439
|
except KeyboardInterrupt as e:
|
|
431
440
|
with open(method_file, 'wb') as f:
|
|
432
441
|
pickle.dump(method_list, f)
|
|
@@ -452,25 +461,16 @@ class Collection(object):
|
|
|
452
461
|
def _create_cascade_method(method_name):
|
|
453
462
|
def cascade_method(self, savepath='./processed', merge=1,
|
|
454
463
|
suffix=f'_{method_name}', ftype=None, dtype=None,
|
|
455
|
-
save_operations=False,
|
|
464
|
+
file_format='auto', save_operations=False, tolerance=0.5,
|
|
465
|
+
**kwargs):
|
|
456
466
|
"""
|
|
457
467
|
Automatically generated method for {method_name}.
|
|
458
468
|
Applies the {method_name} operation to the data and saves the result.
|
|
459
|
-
|
|
460
|
-
:param savepath: str. Path to save processed files.
|
|
461
|
-
:param merge: int or str. int for merge several processed files into 1.
|
|
462
|
-
'all' for merge all files.
|
|
463
|
-
:param suffix: str. Suffix for processed files.
|
|
464
|
-
:param ftype: None or str. None for automatic detection, or 'pkl',
|
|
465
|
-
'pickle', 'tdms', 'h5', 'hdf5', 'segy', 'sgy', 'npy'.
|
|
466
|
-
:param dtype: str. The data type of the saved data.
|
|
467
|
-
:parma save_operations: bool. If True, save the operations to
|
|
468
|
-
method_list.pkl and kwargs_list.pkl in savepath.
|
|
469
|
-
:param kwargs: dict. Parameters for the {method_name} operation.
|
|
470
469
|
"""
|
|
471
470
|
operations = [[method_name, kwargs]]
|
|
472
471
|
self.process(operations, savepath=savepath, merge=merge, suffix=suffix,
|
|
473
|
-
ftype=ftype, dtype=dtype,
|
|
472
|
+
ftype=ftype, dtype=dtype, file_format=file_format,
|
|
473
|
+
save_operations=save_operations, tolerance=tolerance)
|
|
474
474
|
return cascade_method
|
|
475
475
|
|
|
476
476
|
|
|
@@ -84,7 +84,7 @@ class DASDateTime(datetime):
|
|
|
84
84
|
match = re.match(r'(.*)(UTC|GMT)([+-]?\d{1,2})(.*)', date_string,
|
|
85
85
|
re.IGNORECASE)
|
|
86
86
|
if match:
|
|
87
|
-
dt1,
|
|
87
|
+
dt1, _, offset, dt2 = match.groups()
|
|
88
88
|
offset_hours = int(offset)
|
|
89
89
|
tz = timezone(timedelta(hours=offset_hours))
|
|
90
90
|
return cls.strptime(dt1 + dt2, format.replace('%Z', '')).\
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import h5py
|
|
2
|
+
import numpy as np
|
|
3
|
+
from daspy import read, Section, DASDateTime
|
|
4
|
+
from daspy.core.dasdatetime import utc
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
origin_time = DASDateTime(2016, 3, 21, 7, 37, 10, 535000, tzinfo=utc)
|
|
8
|
+
|
|
9
|
+
# read DAS data
|
|
10
|
+
dx, fs = 1, 1000
|
|
11
|
+
sec = Section(np.zeros((8721, 0)), dx, fs, data_type='Strain rate')
|
|
12
|
+
filename = ['PoroTomo_iDAS16043_160321073651.h5',
|
|
13
|
+
'PoroTomo_iDAS16043_160321073721.h5',
|
|
14
|
+
'PoroTomo_iDAS16043_160321073751.h5',
|
|
15
|
+
'PoroTomo_iDAS16043_160321073821.h5']
|
|
16
|
+
|
|
17
|
+
first = True
|
|
18
|
+
for fn in filename:
|
|
19
|
+
with h5py.File(fn,'r') as fp:
|
|
20
|
+
if first:
|
|
21
|
+
sec.start_time = DASDateTime.fromtimestamp(fp['t'][0]).astimezone(utc)
|
|
22
|
+
sec.start_channel = fp['channel'][0]
|
|
23
|
+
first = False
|
|
24
|
+
sec += fp['das'][()].T
|
|
25
|
+
|
|
26
|
+
sec.origin_time = origin_time
|
|
27
|
+
sec.trimming(mode=0, xmin=2500, xmax=3000)
|
|
28
|
+
sec.trimming(tmin=origin_time, tmax=origin_time+90)
|
|
29
|
+
sec.downsampling(tint=10)
|
|
30
|
+
sec.trimming(tmin=origin_time+20, tmax=origin_time+70)
|
|
31
|
+
|
|
32
|
+
sec.save('example.py')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for reading DAS data.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.10.30
|
|
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
|
|
@@ -188,7 +188,8 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
188
188
|
start_time = DASDateTime.fromisoformat(h5_file[data_key].
|
|
189
189
|
attrs['start_time'])
|
|
190
190
|
else:
|
|
191
|
-
start_time = DASDateTime.fromtimestamp(float(header[100]))
|
|
191
|
+
start_time = DASDateTime.fromtimestamp(float(header[100])).\
|
|
192
|
+
utc()
|
|
192
193
|
transpose = True
|
|
193
194
|
metadata = {'dx': header[1],
|
|
194
195
|
'fs': header[6] / header[15] / header[98],
|
|
@@ -216,13 +217,9 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
216
217
|
fs = float(attrs['FreqRes'])
|
|
217
218
|
except KeyError:
|
|
218
219
|
try:
|
|
219
|
-
fs = (attrs['
|
|
220
|
-
attrs['SamplingRes'][0]) / 1000
|
|
220
|
+
fs = float(1000 / attrs['Spacing'][1])
|
|
221
221
|
except KeyError:
|
|
222
|
-
|
|
223
|
-
fs = 1000 / attrs['Spacing'][1]
|
|
224
|
-
except KeyError:
|
|
225
|
-
fs = attrs['SamplingRate'][0]
|
|
222
|
+
fs = attrs['PulseRateFreq'][0]
|
|
226
223
|
time = h5_file[f'{group}/Source1/time']
|
|
227
224
|
if len(time.shape) == 2: # Febus A1-R
|
|
228
225
|
start_time = DASDateTime.fromtimestamp(time[0, 0]).utc()
|
|
@@ -260,11 +257,9 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
260
257
|
'Smart Earth ZD-DAS', 'Unknown']:
|
|
261
258
|
dataset = h5_file['Acquisition/Raw[0]/RawData/']
|
|
262
259
|
attrs = h5_file['Acquisition'].attrs
|
|
263
|
-
|
|
260
|
+
if 'NumberOfLoci' in attrs.keys():
|
|
264
261
|
if dataset.shape[0] != attrs['NumberOfLoci']:
|
|
265
262
|
transpose = True
|
|
266
|
-
except KeyError:
|
|
267
|
-
pass
|
|
268
263
|
|
|
269
264
|
try:
|
|
270
265
|
fs = h5_file['Acquisition/Raw[0]'].attrs['OutputDataRate']
|
|
@@ -282,7 +277,7 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
282
277
|
stime = h5_file['Acquisition/Raw[0]/RawDataTime/'][0]
|
|
283
278
|
except KeyError:
|
|
284
279
|
stime = 0
|
|
285
|
-
|
|
280
|
+
|
|
286
281
|
if isinstance(stime, bytes):
|
|
287
282
|
stime = stime.decode('ascii')
|
|
288
283
|
|
|
@@ -415,11 +410,14 @@ def _read_h5(fname, headonly=False, file_format='auto', chmin=None, chmax=None,
|
|
|
415
410
|
elif transpose:
|
|
416
411
|
if len(dataset.shape) == 3:
|
|
417
412
|
fs = int(metadata['fs'])
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
413
|
+
fs_b = attrs.get('BlockRate', [1000])[0] / 1e3
|
|
414
|
+
nsp_b = round(fs/fs_b)
|
|
415
|
+
half_ol = round((dataset.shape[1] - nsp_b) / 2)
|
|
416
|
+
j0, k0 = divmod(sj.start, nsp_b)
|
|
417
|
+
j1, k1 = divmod(sj.stop, nsp_b)
|
|
418
|
+
k1 = (j1 - j0) * nsp_b + k1
|
|
421
419
|
j1 += 1
|
|
422
|
-
data = dataset[j0:j1,
|
|
420
|
+
data = dataset[j0:j1, half_ol:half_ol+nsp_b, si]
|
|
423
421
|
data = data.reshape((-1, data.shape[-1]))[k0:k1, :].T
|
|
424
422
|
else:
|
|
425
423
|
data = dataset[sj, si].T
|
|
@@ -444,9 +442,9 @@ def _read_tdms(fname, headonly=False, file_format='auto', chmin=None,
|
|
|
444
442
|
version = float(properties['iDASVersion'][:3])
|
|
445
443
|
if version < 2.3:
|
|
446
444
|
file_format = 'Silixa iDAS'
|
|
447
|
-
elif 2.3 <= version < 2.
|
|
445
|
+
elif 2.3 <= version < 2.7:
|
|
448
446
|
file_format = 'Silixa iDAS-v2'
|
|
449
|
-
elif version >= 2.
|
|
447
|
+
elif version >= 2.7:
|
|
450
448
|
file_format = 'Silixa iDAS-v3'
|
|
451
449
|
elif group_name == ['DAS']:
|
|
452
450
|
key = 'DAS'
|
|
@@ -483,12 +481,11 @@ def _read_tdms(fname, headonly=False, file_format='auto', chmin=None,
|
|
|
483
481
|
if isinstance(properties[time_key], str):
|
|
484
482
|
start_time = DASDateTime.fromisoformat(
|
|
485
483
|
properties[time_key])
|
|
484
|
+
break
|
|
486
485
|
elif isinstance(properties[time_key], np.datetime64):
|
|
487
486
|
start_time = DASDateTime.from_datetime(
|
|
488
487
|
properties[time_key].item())
|
|
489
|
-
|
|
490
|
-
continue
|
|
491
|
-
break
|
|
488
|
+
break
|
|
492
489
|
metadata['start_time'] = start_time
|
|
493
490
|
if 'GaugeLength' in properties.keys():
|
|
494
491
|
metadata['gauge_length'] = properties['GaugeLength']
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling Section objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.10.31
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import warnings
|
|
6
6
|
import os
|
|
@@ -150,15 +150,15 @@ class Section(object):
|
|
|
150
150
|
else:
|
|
151
151
|
raise TypeError('The input should be Section or np.ndarray.')
|
|
152
152
|
|
|
153
|
-
if
|
|
154
|
-
if len(data[0]) == self.nch:
|
|
155
|
-
data = data.T
|
|
156
|
-
else:
|
|
157
|
-
raise ValueError('These two Sections have different number of '
|
|
158
|
-
'channels, please check.')
|
|
159
|
-
if out.data is None:
|
|
153
|
+
if (out.data is None) or (out.nch * out.nsp == 0):
|
|
160
154
|
out.data = data
|
|
161
155
|
else:
|
|
156
|
+
if len(data) != self.nch:
|
|
157
|
+
if len(data[0]) == self.nch:
|
|
158
|
+
data = data.T
|
|
159
|
+
else:
|
|
160
|
+
raise ValueError('These two Sections have different number '
|
|
161
|
+
'of channels, please check.')
|
|
162
162
|
out.data = np.hstack((out.data, data))
|
|
163
163
|
|
|
164
164
|
return out
|
|
@@ -548,7 +548,7 @@ class Section(object):
|
|
|
548
548
|
self.start_distance += channel[0] * self.dx
|
|
549
549
|
return self
|
|
550
550
|
else:
|
|
551
|
-
return data
|
|
551
|
+
return data * self.scale
|
|
552
552
|
|
|
553
553
|
def plot(self, xmode='distance', tmode='origin', obj='waveform',
|
|
554
554
|
kwargs_pro={}, **kwargs):
|
|
@@ -645,7 +645,10 @@ class Section(object):
|
|
|
645
645
|
if tmode == 'origin':
|
|
646
646
|
if hasattr(self, 'origin_time'):
|
|
647
647
|
kwargs['t0'] -= self.origin_time
|
|
648
|
-
|
|
648
|
+
if ('transpose' in kwargs.keys()) and kwargs['transpose']:
|
|
649
|
+
kwargs.setdefault('xlabel', 'Times(s) after occurance')
|
|
650
|
+
else:
|
|
651
|
+
kwargs.setdefault('ylabel', 'Times(s) after occurance')
|
|
649
652
|
else:
|
|
650
653
|
tmode == 'start'
|
|
651
654
|
if tmode == 'start':
|
|
@@ -765,18 +768,26 @@ class Section(object):
|
|
|
765
768
|
self.data = cosine_taper(self.data, p=p, side=side)
|
|
766
769
|
return self
|
|
767
770
|
|
|
768
|
-
def downsampling(self, xint=None, tint=None, stack=True,
|
|
771
|
+
def downsampling(self, xint=None, tint=None, fs=None, dx=None, stack=True,
|
|
769
772
|
lowpass_filter=True):
|
|
770
773
|
"""
|
|
771
774
|
Downsample DAS data.
|
|
772
775
|
|
|
773
776
|
:param xint: int. Spatial downsampling factor.
|
|
774
777
|
:param tint: int. Time downsampling factor.
|
|
778
|
+
:param fs: float. Target sampling rate after downsampling. It is used
|
|
779
|
+
if tint is None.
|
|
780
|
+
:param dx: float. Target channel interval after downsampling. It is
|
|
781
|
+
used if xint is None.
|
|
775
782
|
:param stack: bool. If True, stacking will replace decimation.
|
|
776
783
|
:param lowpass_filter: bool. Lowpass cheby2 filter before time
|
|
777
784
|
downsampling or not.
|
|
778
785
|
:return: Downsampled data.
|
|
779
786
|
"""
|
|
787
|
+
if xint is None and dx is not None:
|
|
788
|
+
xint = round(dx / self.dx)
|
|
789
|
+
if tint is None and fs is not None:
|
|
790
|
+
tint = round(self.fs / fs)
|
|
780
791
|
self.data = downsampling(self.data, xint=xint, tint=tint, stack=stack,
|
|
781
792
|
lowpass_filter=lowpass_filter)
|
|
782
793
|
if xint and xint > 1:
|
|
@@ -851,25 +862,26 @@ class Section(object):
|
|
|
851
862
|
return self
|
|
852
863
|
warnings.warn('Unable to convert data type.')
|
|
853
864
|
|
|
854
|
-
def time_integration(self, c=0):
|
|
865
|
+
def time_integration(self, domain='time', c=0):
|
|
855
866
|
"""
|
|
856
867
|
Integrate DAS data in time.
|
|
857
868
|
|
|
858
869
|
:param c: float. A constant added to the result.
|
|
859
870
|
"""
|
|
860
|
-
self.data = time_integration(self.data, self.fs, c=c)
|
|
871
|
+
self.data = time_integration(self.data, self.fs, domain=domain, c=c)
|
|
861
872
|
if hasattr(self, 'data_type'):
|
|
862
873
|
self._time_int_dif_attr(mode=1)
|
|
863
874
|
return self
|
|
864
875
|
|
|
865
|
-
def time_differential(self, prepend=0):
|
|
876
|
+
def time_differential(self, domain='time', prepend=0):
|
|
866
877
|
"""
|
|
867
878
|
Differentiate DAS data in time.
|
|
868
879
|
|
|
869
|
-
:param prepend: 'mean' or values to prepend to `data` along axis prior
|
|
870
|
-
performing the difference.
|
|
880
|
+
:param prepend: 'mean' or values to prepend to `data` along axis prior
|
|
881
|
+
to performing the difference.
|
|
871
882
|
"""
|
|
872
|
-
self.data = time_differential(self.data, self.fs,
|
|
883
|
+
self.data = time_differential(self.data, self.fs, domain=domain,
|
|
884
|
+
prepend=prepend)
|
|
873
885
|
if hasattr(self, 'data_type'):
|
|
874
886
|
self._time_int_dif_attr(mode=-1)
|
|
875
887
|
return self
|
|
@@ -901,7 +913,8 @@ class Section(object):
|
|
|
901
913
|
None.
|
|
902
914
|
"""
|
|
903
915
|
if zi is None:
|
|
904
|
-
self.data = bandpass(self.data, self.fs, freqmin, freqmax,
|
|
916
|
+
self.data = bandpass(self.data, self.fs, freqmin, freqmax,
|
|
917
|
+
**kwargs)
|
|
905
918
|
return self
|
|
906
919
|
else:
|
|
907
920
|
self.data, zf = bandpass(self.data, self.fs, freqmin, freqmax,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for writing DAS data.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.9.
|
|
3
|
+
# Date: 2025.9.18
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
6
|
import warnings
|
|
@@ -168,7 +168,6 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
168
168
|
start_time = sec.start_time.utc() if \
|
|
169
169
|
isinstance(sec.start_time, datetime) else \
|
|
170
170
|
DASDateTime.fromtimestamp(sec.start_time)
|
|
171
|
-
|
|
172
171
|
if file_format in ['OptaSense ODH4+', 'OptaSense QuantX',
|
|
173
172
|
'Unknown']:
|
|
174
173
|
h5_file.get('Acquisition/Raw[0]/').create_dataset('RawData',
|
|
@@ -186,6 +185,7 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
186
185
|
attrs['PartStartTime'] = stime_str
|
|
187
186
|
h5_file['Acquisition'].attrs['MeasurementStartTime'] = \
|
|
188
187
|
stime_str
|
|
188
|
+
h5_file['Acquisition'].attrs['NumberOfLoci'] = sec.nch
|
|
189
189
|
stimestamp = start_time.timestamp()
|
|
190
190
|
datatime = (np.arange(stimestamp, stimestamp + sec.nsp /
|
|
191
191
|
sec.fs, 1 / sec.fs) * 1e6).astype(int)
|
|
@@ -434,9 +434,14 @@ def _write_h5(sec, fname, raw_fname=None, file_format='auto'):
|
|
|
434
434
|
elif file_format in ['OptaSense ODH4+', 'OptaSense QuantX',
|
|
435
435
|
'Silixa iDAS-MG', 'Sintela Onyx v1.0',
|
|
436
436
|
'Smart Earth ZD-DAS', 'Unknown']:
|
|
437
|
+
if file_format in ['Silixa iDAS-MG', 'Sintela Onyx v1.0',
|
|
438
|
+
'Smart Earth ZD-DAS']:
|
|
439
|
+
_update_h5_dataset(h5_file, 'Acquisition/Raw[0]/',
|
|
440
|
+
'RawData', sec.data.T)
|
|
441
|
+
else:
|
|
442
|
+
_update_h5_dataset(h5_file, 'Acquisition/Raw[0]/',
|
|
443
|
+
'RawData', sec.data)
|
|
437
444
|
h5_file['Acquisition'].attrs['NumberOfLoci'] = sec.nch
|
|
438
|
-
_update_h5_dataset(h5_file, 'Acquisition/Raw[0]/', 'RawData',
|
|
439
|
-
sec.data)
|
|
440
445
|
if isinstance(sec.start_time, datetime):
|
|
441
446
|
if isinstance(h5_file['Acquisition/Raw[0]/RawData'].
|
|
442
447
|
attrs['PartStartTime'], bytes):
|
|
@@ -2,14 +2,14 @@ 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.1',
|
|
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 '
|
|
9
9
|
'comprises classic seismic data processing techniques and Specialized '
|
|
10
10
|
'algorithms for DAS applications.'
|
|
11
11
|
),
|
|
12
|
-
long_description=open('README.md').read(),
|
|
12
|
+
long_description=open('README.md', encoding="utf-8").read(),
|
|
13
13
|
author='Minzhe Hu, Zefeng Li',
|
|
14
14
|
author_email='hmz2018@mail.ustc.edu.cn',
|
|
15
15
|
maintainer='Minzhe Hu',
|
|
@@ -17,7 +17,7 @@ setup(
|
|
|
17
17
|
license='MIT License',
|
|
18
18
|
url='https://github.com/HMZ-03/DASPy',
|
|
19
19
|
packages=find_packages(),
|
|
20
|
-
entry_points={
|
|
20
|
+
entry_points={
|
|
21
21
|
'console_scripts': [
|
|
22
22
|
'daspy = daspy.main:main',
|
|
23
23
|
]
|
|
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
|