acoular 25.7__py3-none-any.whl → 25.10__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.
- acoular/aiaa/aiaa.py +7 -9
- acoular/base.py +6 -9
- acoular/calib.py +19 -18
- acoular/configuration.py +2 -2
- acoular/environments.py +102 -113
- acoular/fbeamform.py +296 -301
- acoular/fprocess.py +7 -4
- acoular/grids.py +98 -111
- acoular/h5cache.py +5 -1
- acoular/h5files.py +96 -9
- acoular/microphones.py +22 -27
- acoular/process.py +7 -11
- acoular/sdinput.py +0 -5
- acoular/signals.py +29 -27
- acoular/sources.py +189 -322
- acoular/spectra.py +33 -44
- acoular/tbeamform.py +217 -199
- acoular/tools/helpers.py +25 -33
- acoular/tools/metrics.py +5 -10
- acoular/tprocess.py +173 -209
- acoular/trajectory.py +5 -5
- acoular/version.py +2 -2
- {acoular-25.7.dist-info → acoular-25.10.dist-info}/METADATA +6 -2
- {acoular-25.7.dist-info → acoular-25.10.dist-info}/RECORD +27 -27
- {acoular-25.7.dist-info → acoular-25.10.dist-info}/WHEEL +0 -0
- {acoular-25.7.dist-info → acoular-25.10.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.7.dist-info → acoular-25.10.dist-info}/licenses/LICENSE +0 -0
acoular/tprocess.py
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
"""
|
|
5
5
|
Implement blockwise processing in the time domain.
|
|
6
6
|
|
|
7
|
+
.. inheritance-diagram::
|
|
8
|
+
acoular.tprocess
|
|
9
|
+
:top-classes:
|
|
10
|
+
acoular.base.TimeOut
|
|
11
|
+
:parts: 1
|
|
12
|
+
|
|
7
13
|
.. autosummary::
|
|
8
14
|
:toctree: generated/
|
|
9
15
|
|
|
@@ -39,46 +45,9 @@ from warnings import warn
|
|
|
39
45
|
|
|
40
46
|
import numba as nb
|
|
41
47
|
import numpy as np
|
|
42
|
-
|
|
43
|
-
append,
|
|
44
|
-
arange,
|
|
45
|
-
argmax,
|
|
46
|
-
argmin,
|
|
47
|
-
argsort,
|
|
48
|
-
array,
|
|
49
|
-
array_equal,
|
|
50
|
-
asarray,
|
|
51
|
-
ceil,
|
|
52
|
-
concatenate,
|
|
53
|
-
cumsum,
|
|
54
|
-
delete,
|
|
55
|
-
empty,
|
|
56
|
-
empty_like,
|
|
57
|
-
exp,
|
|
58
|
-
flatnonzero,
|
|
59
|
-
float64,
|
|
60
|
-
identity,
|
|
61
|
-
inf,
|
|
62
|
-
interp,
|
|
63
|
-
linspace,
|
|
64
|
-
mean,
|
|
65
|
-
nan,
|
|
66
|
-
newaxis,
|
|
67
|
-
pi,
|
|
68
|
-
polymul,
|
|
69
|
-
sin,
|
|
70
|
-
sinc,
|
|
71
|
-
split,
|
|
72
|
-
sqrt,
|
|
73
|
-
stack,
|
|
74
|
-
sum, # noqa: A004
|
|
75
|
-
tile,
|
|
76
|
-
unique,
|
|
77
|
-
zeros,
|
|
78
|
-
)
|
|
48
|
+
import scipy.linalg as spla
|
|
79
49
|
from scipy.fft import irfft, rfft
|
|
80
50
|
from scipy.interpolate import CloughTocher2DInterpolator, CubicSpline, LinearNDInterpolator, Rbf, splev, splrep
|
|
81
|
-
from scipy.linalg import norm
|
|
82
51
|
from scipy.signal import bilinear, butter, sosfilt, sosfiltfilt, tf2sos
|
|
83
52
|
from scipy.spatial import Delaunay
|
|
84
53
|
from traits.api import (
|
|
@@ -101,13 +70,11 @@ from traits.api import (
|
|
|
101
70
|
Union,
|
|
102
71
|
cached_property,
|
|
103
72
|
observe,
|
|
104
|
-
on_trait_change,
|
|
105
73
|
)
|
|
106
74
|
|
|
107
75
|
# acoular imports
|
|
108
76
|
from .base import SamplesGenerator, TimeOut
|
|
109
77
|
from .configuration import config
|
|
110
|
-
from .deprecation import deprecated_alias
|
|
111
78
|
from .environments import cartToCyl, cylToCart
|
|
112
79
|
from .h5files import _get_h5file_class
|
|
113
80
|
from .internal import digest, ldigest
|
|
@@ -116,9 +83,6 @@ from .process import Cache
|
|
|
116
83
|
from .tools.utils import find_basename
|
|
117
84
|
|
|
118
85
|
|
|
119
|
-
@deprecated_alias(
|
|
120
|
-
{'numchannels_total': 'num_channels_total', 'numsamples_total': 'num_samples_total'}, removal_version='25.10'
|
|
121
|
-
)
|
|
122
86
|
class MaskedTimeOut(TimeOut):
|
|
123
87
|
"""
|
|
124
88
|
A signal processing block that allows for the selection of specific channels and time samples.
|
|
@@ -199,7 +163,7 @@ class MaskedTimeOut(TimeOut):
|
|
|
199
163
|
if len(self.invalid_channels) == 0:
|
|
200
164
|
return slice(0, None, None)
|
|
201
165
|
allr = [i for i in range(self.num_channels_total) if i not in self.invalid_channels]
|
|
202
|
-
return array(allr)
|
|
166
|
+
return np.array(allr)
|
|
203
167
|
|
|
204
168
|
@cached_property
|
|
205
169
|
def _get_num_channels(self):
|
|
@@ -251,7 +215,7 @@ class MaskedTimeOut(TimeOut):
|
|
|
251
215
|
offset = -start % num
|
|
252
216
|
if offset == 0:
|
|
253
217
|
offset = num
|
|
254
|
-
buf = empty((num + offset, self.num_channels), dtype=float)
|
|
218
|
+
buf = np.empty((num + offset, self.num_channels), dtype=float)
|
|
255
219
|
bsize = 0
|
|
256
220
|
i = 0
|
|
257
221
|
fblock = True
|
|
@@ -360,7 +324,7 @@ class ChannelMixer(TimeOut):
|
|
|
360
324
|
weights = 1
|
|
361
325
|
|
|
362
326
|
for block in self.source.result(num):
|
|
363
|
-
yield sum(weights * block, 1, keepdims=True)
|
|
327
|
+
yield np.sum(weights * block, 1, keepdims=True)
|
|
364
328
|
|
|
365
329
|
|
|
366
330
|
class Trigger(TimeOut): # pragma: no cover
|
|
@@ -472,15 +436,15 @@ class Trigger(TimeOut): # pragma: no cover
|
|
|
472
436
|
threshold = self._threshold(num)
|
|
473
437
|
|
|
474
438
|
# get all samples which surpasse the threshold
|
|
475
|
-
peakLoc = array([], dtype='int') # all indices which surpasse the threshold
|
|
476
|
-
trigger_data = array([])
|
|
439
|
+
peakLoc = np.array([], dtype='int') # all indices which surpasse the threshold
|
|
440
|
+
trigger_data = np.array([])
|
|
477
441
|
x0 = []
|
|
478
442
|
dSamples = 0
|
|
479
443
|
for triggerSignal in self.source.result(num):
|
|
480
|
-
localTrigger = flatnonzero(triggerFunc(x0, triggerSignal, threshold))
|
|
444
|
+
localTrigger = np.flatnonzero(triggerFunc(x0, triggerSignal, threshold))
|
|
481
445
|
if len(localTrigger) != 0:
|
|
482
|
-
peakLoc = append(peakLoc, localTrigger + dSamples)
|
|
483
|
-
trigger_data = append(trigger_data, triggerSignal[localTrigger])
|
|
446
|
+
peakLoc = np.append(peakLoc, localTrigger + dSamples)
|
|
447
|
+
trigger_data = np.append(trigger_data, triggerSignal[localTrigger])
|
|
484
448
|
dSamples += num
|
|
485
449
|
x0 = triggerSignal[-1]
|
|
486
450
|
if len(peakLoc) <= 1:
|
|
@@ -494,24 +458,24 @@ class Trigger(TimeOut): # pragma: no cover
|
|
|
494
458
|
# which peak is the correct one -> delete the other one.
|
|
495
459
|
# if there are no multiple peaks in any hunk left -> leave the while
|
|
496
460
|
# loop and continue with program
|
|
497
|
-
multiplePeaksWithinHunk = flatnonzero(peakDist < self.hunk_length * maxPeakDist)
|
|
461
|
+
multiplePeaksWithinHunk = np.flatnonzero(peakDist < self.hunk_length * maxPeakDist)
|
|
498
462
|
while len(multiplePeaksWithinHunk) > 0:
|
|
499
463
|
peakLocHelp = multiplePeaksWithinHunk[0]
|
|
500
464
|
indHelp = [peakLocHelp, peakLocHelp + 1]
|
|
501
465
|
if self.multiple_peaks_in_hunk == 'extremum':
|
|
502
466
|
values = trigger_data[indHelp]
|
|
503
|
-
deleteInd = indHelp[argmin(abs(values))]
|
|
467
|
+
deleteInd = indHelp[np.argmin(abs(values))]
|
|
504
468
|
elif self.multiple_peaks_in_hunk == 'first':
|
|
505
469
|
deleteInd = indHelp[1]
|
|
506
|
-
peakLoc = delete(peakLoc, deleteInd)
|
|
507
|
-
trigger_data = delete(trigger_data, deleteInd)
|
|
470
|
+
peakLoc = np.delete(peakLoc, deleteInd)
|
|
471
|
+
trigger_data = np.delete(trigger_data, deleteInd)
|
|
508
472
|
peakDist = peakLoc[1:] - peakLoc[:-1]
|
|
509
|
-
multiplePeaksWithinHunk = flatnonzero(peakDist < self.hunk_length * maxPeakDist)
|
|
473
|
+
multiplePeaksWithinHunk = np.flatnonzero(peakDist < self.hunk_length * maxPeakDist)
|
|
510
474
|
|
|
511
475
|
# check whether distances between peaks are evenly distributed
|
|
512
|
-
meanDist = mean(peakDist)
|
|
476
|
+
meanDist = np.mean(peakDist)
|
|
513
477
|
diffDist = abs(peakDist - meanDist)
|
|
514
|
-
faultyInd = flatnonzero(diffDist > self.max_variation_of_duration * meanDist)
|
|
478
|
+
faultyInd = np.flatnonzero(diffDist > self.max_variation_of_duration * meanDist)
|
|
515
479
|
if faultyInd.size != 0:
|
|
516
480
|
warn(
|
|
517
481
|
f'In Trigger-Identification: The distances between the peaks (and therefore the lengths of the \
|
|
@@ -527,7 +491,7 @@ class Trigger(TimeOut): # pragma: no cover
|
|
|
527
491
|
|
|
528
492
|
def _trigger_rect(self, x0, x, threshold):
|
|
529
493
|
# x0 stores the last value of the the last generator cycle
|
|
530
|
-
xNew = append(x0, x)
|
|
494
|
+
xNew = np.append(x0, x)
|
|
531
495
|
# indPeakHunk = abs(xNew[1:] - xNew[:-1]) > abs(threshold)
|
|
532
496
|
# with above line, every edge would be located
|
|
533
497
|
return self._trigger_value_comp(xNew[1:] - xNew[:-1], threshold)
|
|
@@ -538,8 +502,8 @@ class Trigger(TimeOut): # pragma: no cover
|
|
|
538
502
|
def _threshold(self, num):
|
|
539
503
|
if self.threshold is None: # take a guessed threshold
|
|
540
504
|
# get max and min values of whole trigger signal
|
|
541
|
-
maxVal = -inf
|
|
542
|
-
minVal = inf
|
|
505
|
+
maxVal = -np.inf
|
|
506
|
+
minVal = np.inf
|
|
543
507
|
meanVal = 0
|
|
544
508
|
cntMean = 0
|
|
545
509
|
for trigger_data in self.source.result(num):
|
|
@@ -551,7 +515,7 @@ class Trigger(TimeOut): # pragma: no cover
|
|
|
551
515
|
|
|
552
516
|
# get 75% of maximum absolute value of trigger signal
|
|
553
517
|
maxTriggerHelp = [minVal, maxVal] - meanVal
|
|
554
|
-
argInd = argmax(abs(maxTriggerHelp))
|
|
518
|
+
argInd = np.argmax(abs(maxTriggerHelp))
|
|
555
519
|
thresh = maxTriggerHelp[argInd] * 0.75 # 0.75 for 75% of max trigger signal
|
|
556
520
|
warn(f'No threshold was passed. An estimated threshold of {thresh} is assumed.', Warning, stacklevel=2)
|
|
557
521
|
else: # take user defined threshold
|
|
@@ -670,7 +634,7 @@ class AngleTracker(MaskedTimeOut):
|
|
|
670
634
|
|
|
671
635
|
# helperfunction for trigger index detection
|
|
672
636
|
def _find_nearest_idx(self, peakarray, value):
|
|
673
|
-
peakarray = asarray(peakarray)
|
|
637
|
+
peakarray = np.asarray(peakarray)
|
|
674
638
|
return (abs(peakarray - value)).argmin()
|
|
675
639
|
|
|
676
640
|
def _to_rpm_and_angle(self):
|
|
@@ -688,8 +652,8 @@ class AngleTracker(MaskedTimeOut):
|
|
|
688
652
|
rotDirection = self.rot_direction
|
|
689
653
|
num = self.source.num_samples
|
|
690
654
|
samplerate = self.source.sample_freq
|
|
691
|
-
self._rpm = zeros(num)
|
|
692
|
-
self._angle = zeros(num)
|
|
655
|
+
self._rpm = np.zeros(num)
|
|
656
|
+
self._angle = np.zeros(num)
|
|
693
657
|
# number of spline points
|
|
694
658
|
InterpPoints = self.interp_points
|
|
695
659
|
|
|
@@ -701,7 +665,7 @@ class AngleTracker(MaskedTimeOut):
|
|
|
701
665
|
peakloc[self._find_nearest_idx(peakarray=peakloc, value=ind) + 1]
|
|
702
666
|
- peakloc[self._find_nearest_idx(peakarray=peakloc, value=ind)]
|
|
703
667
|
)
|
|
704
|
-
splineData = stack(
|
|
668
|
+
splineData = np.stack(
|
|
705
669
|
(range(InterpPoints), peakloc[ind // peakdist : ind // peakdist + InterpPoints]),
|
|
706
670
|
axis=0,
|
|
707
671
|
)
|
|
@@ -711,7 +675,7 @@ class AngleTracker(MaskedTimeOut):
|
|
|
711
675
|
peakloc[self._find_nearest_idx(peakarray=peakloc, value=ind)]
|
|
712
676
|
- peakloc[self._find_nearest_idx(peakarray=peakloc, value=ind) - 1]
|
|
713
677
|
)
|
|
714
|
-
splineData = stack(
|
|
678
|
+
splineData = np.stack(
|
|
715
679
|
(range(InterpPoints), peakloc[ind // peakdist - InterpPoints : ind // peakdist]),
|
|
716
680
|
axis=0,
|
|
717
681
|
)
|
|
@@ -719,16 +683,16 @@ class AngleTracker(MaskedTimeOut):
|
|
|
719
683
|
Spline = splrep(splineData[:, :][1], splineData[:, :][0], k=3)
|
|
720
684
|
self._rpm[ind] = splev(ind, Spline, der=1, ext=0) * 60 * samplerate
|
|
721
685
|
self._angle[ind] = (
|
|
722
|
-
splev(ind, Spline, der=0, ext=0) * 2 * pi * rotDirection / TriggerPerRevo + self.start_angle
|
|
723
|
-
) % (2 * pi)
|
|
686
|
+
splev(ind, Spline, der=0, ext=0) * 2 * np.pi * rotDirection / TriggerPerRevo + self.start_angle
|
|
687
|
+
) % (2 * np.pi)
|
|
724
688
|
# next sample
|
|
725
689
|
ind += 1
|
|
726
690
|
# calculation complete
|
|
727
691
|
self._calc_flag = True
|
|
728
692
|
|
|
729
693
|
# reset calc flag if something has changed
|
|
730
|
-
@
|
|
731
|
-
def _reset_calc_flag(self):
|
|
694
|
+
@observe('digest')
|
|
695
|
+
def _reset_calc_flag(self, event): # noqa ARG002
|
|
732
696
|
self._calc_flag = False
|
|
733
697
|
|
|
734
698
|
# calc rpm from trigger data
|
|
@@ -856,7 +820,7 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
856
820
|
#:
|
|
857
821
|
#: where :math:`Q` is the transformation matrix and :math:`(x', y', z')` are the modified
|
|
858
822
|
#: coordinates. If no transformation is needed, :math:`Q` defaults to the identity matrix.
|
|
859
|
-
Q = CArray(dtype=float64, shape=(3, 3), value=identity(3))
|
|
823
|
+
Q = CArray(dtype=np.float64, shape=(3, 3), value=np.identity(3))
|
|
860
824
|
|
|
861
825
|
#: Number of neighboring microphones used in IDW interpolation. This parameter determines how
|
|
862
826
|
#: many physical microphones contribute to the weighted sum in inverse distance weighting (IDW)
|
|
@@ -919,7 +883,7 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
919
883
|
:class:`numpy.ndarray`
|
|
920
884
|
Evaluated sinc function values at the given radial distances.
|
|
921
885
|
"""
|
|
922
|
-
return sinc((r * self.mics_virtual.mpos.shape[1]) / (pi))
|
|
886
|
+
return np.sinc((r * self.mics_virtual.mpos.shape[1]) / (np.pi))
|
|
923
887
|
|
|
924
888
|
def _virtNewCoord_func(self, mpos, mpos_virt, method, array_dimension): # noqa N802
|
|
925
889
|
# Core functionality for getting the interpolation.
|
|
@@ -966,23 +930,23 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
966
930
|
|
|
967
931
|
# init positions of virtual mics in cyl coordinates
|
|
968
932
|
nVirtMics = mpos_virt.shape[1]
|
|
969
|
-
virtNewCoord = zeros((3, nVirtMics))
|
|
970
|
-
virtNewCoord.fill(nan)
|
|
933
|
+
virtNewCoord = np.zeros((3, nVirtMics))
|
|
934
|
+
virtNewCoord.fill(np.nan)
|
|
971
935
|
# init real positions in cyl coordinates
|
|
972
936
|
nMics = mpos.shape[1]
|
|
973
|
-
newCoord = zeros((3, nMics))
|
|
974
|
-
newCoord.fill(nan)
|
|
937
|
+
newCoord = np.zeros((3, nMics))
|
|
938
|
+
newCoord.fill(np.nan)
|
|
975
939
|
# empty mesh object
|
|
976
940
|
mesh = []
|
|
977
941
|
|
|
978
942
|
if self.array_dimension == '1D' or self.array_dimension == 'ring':
|
|
979
943
|
# get projections onto new coordinate, for real mics
|
|
980
944
|
projectionOnNewAxis = cartToCyl(mpos, self.Q)[0]
|
|
981
|
-
indReorderHelp = argsort(projectionOnNewAxis)
|
|
945
|
+
indReorderHelp = np.argsort(projectionOnNewAxis)
|
|
982
946
|
mesh.append([projectionOnNewAxis[indReorderHelp], indReorderHelp])
|
|
983
947
|
|
|
984
948
|
# new coordinates of real mics
|
|
985
|
-
indReorderHelp = argsort(cartToCyl(mpos, self.Q)[0])
|
|
949
|
+
indReorderHelp = np.argsort(cartToCyl(mpos, self.Q)[0])
|
|
986
950
|
newCoord = (cartToCyl(mpos, self.Q).T)[indReorderHelp].T
|
|
987
951
|
|
|
988
952
|
# and for virtual mics
|
|
@@ -993,7 +957,7 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
993
957
|
virtNewCoord = cartToCyl(mpos_virt, self.Q)
|
|
994
958
|
|
|
995
959
|
# new coordinates of real mics
|
|
996
|
-
indReorderHelp = argsort(cartToCyl(mpos, self.Q)[0])
|
|
960
|
+
indReorderHelp = np.argsort(cartToCyl(mpos, self.Q)[0])
|
|
997
961
|
newCoord = cartToCyl(mpos, self.Q)
|
|
998
962
|
|
|
999
963
|
# scipy delauney triangulation
|
|
@@ -1002,29 +966,29 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1002
966
|
|
|
1003
967
|
if self.interp_at_zero:
|
|
1004
968
|
# add a point at zero
|
|
1005
|
-
tri.add_points(array([[0], [0]]).T)
|
|
969
|
+
tri.add_points(np.array([[0], [0]]).T)
|
|
1006
970
|
|
|
1007
971
|
# extend mesh with closest boundary points of repeating mesh
|
|
1008
|
-
pointsOriginal = arange(tri.points.shape[0])
|
|
972
|
+
pointsOriginal = np.arange(tri.points.shape[0])
|
|
1009
973
|
hull = tri.convex_hull
|
|
1010
|
-
hullPoints = unique(hull)
|
|
974
|
+
hullPoints = np.unique(hull)
|
|
1011
975
|
|
|
1012
976
|
addRight = tri.points[hullPoints]
|
|
1013
|
-
addRight[:, 0] += 2 * pi
|
|
977
|
+
addRight[:, 0] += 2 * np.pi
|
|
1014
978
|
addLeft = tri.points[hullPoints]
|
|
1015
|
-
addLeft[:, 0] -= 2 * pi
|
|
979
|
+
addLeft[:, 0] -= 2 * np.pi
|
|
1016
980
|
|
|
1017
|
-
indOrigPoints = concatenate((pointsOriginal, pointsOriginal[hullPoints], pointsOriginal[hullPoints]))
|
|
981
|
+
indOrigPoints = np.concatenate((pointsOriginal, pointsOriginal[hullPoints], pointsOriginal[hullPoints]))
|
|
1018
982
|
# add all hull vertices to original mesh and check which of those
|
|
1019
983
|
# are actual neighbors of the original array. Cancel out all others.
|
|
1020
|
-
tri.add_points(concatenate([addLeft, addRight]))
|
|
984
|
+
tri.add_points(np.concatenate([addLeft, addRight]))
|
|
1021
985
|
indices, indptr = tri.vertex_neighbor_vertices
|
|
1022
|
-
hullNeighbor = empty((0), dtype='int32')
|
|
986
|
+
hullNeighbor = np.empty((0), dtype='int32')
|
|
1023
987
|
for currHull in hullPoints:
|
|
1024
988
|
neighborOfHull = indptr[indices[currHull] : indices[currHull + 1]]
|
|
1025
|
-
hullNeighbor = append(hullNeighbor, neighborOfHull)
|
|
1026
|
-
hullNeighborUnique = unique(hullNeighbor)
|
|
1027
|
-
pointsNew = unique(append(pointsOriginal, hullNeighborUnique))
|
|
989
|
+
hullNeighbor = np.append(hullNeighbor, neighborOfHull)
|
|
990
|
+
hullNeighborUnique = np.unique(hullNeighbor)
|
|
991
|
+
pointsNew = np.unique(np.append(pointsOriginal, hullNeighborUnique))
|
|
1028
992
|
tri = Delaunay(tri.points[pointsNew]) # re-meshing
|
|
1029
993
|
mesh.append([tri, indOrigPoints[pointsNew]])
|
|
1030
994
|
|
|
@@ -1032,36 +996,36 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1032
996
|
# get virtual mic projections on new coord system
|
|
1033
997
|
virtNewCoord = cartToCyl(mpos_virt, self.Q)
|
|
1034
998
|
# get real mic projections on new coord system
|
|
1035
|
-
indReorderHelp = argsort(cartToCyl(mpos, self.Q)[0])
|
|
999
|
+
indReorderHelp = np.argsort(cartToCyl(mpos, self.Q)[0])
|
|
1036
1000
|
newCoord = cartToCyl(mpos, self.Q)
|
|
1037
1001
|
# Delaunay
|
|
1038
1002
|
tri = Delaunay(newCoord.T, incremental=True) # , incremental=True,qhull_options = "Qc QJ Q12"
|
|
1039
1003
|
|
|
1040
1004
|
if self.interp_at_zero:
|
|
1041
1005
|
# add a point at zero
|
|
1042
|
-
tri.add_points(array([[0], [0], [0]]).T)
|
|
1006
|
+
tri.add_points(np.array([[0], [0], [0]]).T)
|
|
1043
1007
|
|
|
1044
1008
|
# extend mesh with closest boundary points of repeating mesh
|
|
1045
|
-
pointsOriginal = arange(tri.points.shape[0])
|
|
1009
|
+
pointsOriginal = np.arange(tri.points.shape[0])
|
|
1046
1010
|
hull = tri.convex_hull
|
|
1047
|
-
hullPoints = unique(hull)
|
|
1011
|
+
hullPoints = np.unique(hull)
|
|
1048
1012
|
|
|
1049
1013
|
addRight = tri.points[hullPoints]
|
|
1050
|
-
addRight[:, 0] += 2 * pi
|
|
1014
|
+
addRight[:, 0] += 2 * np.pi
|
|
1051
1015
|
addLeft = tri.points[hullPoints]
|
|
1052
|
-
addLeft[:, 0] -= 2 * pi
|
|
1016
|
+
addLeft[:, 0] -= 2 * np.pi
|
|
1053
1017
|
|
|
1054
|
-
indOrigPoints = concatenate((pointsOriginal, pointsOriginal[hullPoints], pointsOriginal[hullPoints]))
|
|
1018
|
+
indOrigPoints = np.concatenate((pointsOriginal, pointsOriginal[hullPoints], pointsOriginal[hullPoints]))
|
|
1055
1019
|
# add all hull vertices to original mesh and check which of those
|
|
1056
1020
|
# are actual neighbors of the original array. Cancel out all others.
|
|
1057
|
-
tri.add_points(concatenate([addLeft, addRight]))
|
|
1021
|
+
tri.add_points(np.concatenate([addLeft, addRight]))
|
|
1058
1022
|
indices, indptr = tri.vertex_neighbor_vertices
|
|
1059
|
-
hullNeighbor = empty((0), dtype='int32')
|
|
1023
|
+
hullNeighbor = np.empty((0), dtype='int32')
|
|
1060
1024
|
for currHull in hullPoints:
|
|
1061
1025
|
neighborOfHull = indptr[indices[currHull] : indices[currHull + 1]]
|
|
1062
|
-
hullNeighbor = append(hullNeighbor, neighborOfHull)
|
|
1063
|
-
hullNeighborUnique = unique(hullNeighbor)
|
|
1064
|
-
pointsNew = unique(append(pointsOriginal, hullNeighborUnique))
|
|
1026
|
+
hullNeighbor = np.append(hullNeighbor, neighborOfHull)
|
|
1027
|
+
hullNeighborUnique = np.unique(hullNeighbor)
|
|
1028
|
+
pointsNew = np.unique(np.append(pointsOriginal, hullNeighborUnique))
|
|
1065
1029
|
tri = Delaunay(tri.points[pointsNew]) # re-meshing
|
|
1066
1030
|
mesh.append([tri, indOrigPoints[pointsNew]])
|
|
1067
1031
|
|
|
@@ -1094,20 +1058,20 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1094
1058
|
# mesh and projection onto polar Coordinates
|
|
1095
1059
|
meshList, virtNewCoord, newCoord = self._get_virtNewCoord()
|
|
1096
1060
|
# pressure interpolation init
|
|
1097
|
-
pInterp = zeros((nTime, nVirtMics))
|
|
1061
|
+
pInterp = np.zeros((nTime, nVirtMics))
|
|
1098
1062
|
# Coordinates in cartesian CO - for IDW interpolation
|
|
1099
1063
|
newCoordCart = cylToCart(newCoord)
|
|
1100
1064
|
|
|
1101
1065
|
if self.interp_at_zero:
|
|
1102
1066
|
# interpolate point at 0 in Kartesian CO
|
|
1103
1067
|
interpolater = LinearNDInterpolator(
|
|
1104
|
-
cylToCart(newCoord[:, argsort(newCoord[0])])[:2, :].T,
|
|
1105
|
-
p[:, (argsort(newCoord[0]))].T,
|
|
1068
|
+
cylToCart(newCoord[:, np.argsort(newCoord[0])])[:2, :].T,
|
|
1069
|
+
p[:, (np.argsort(newCoord[0]))].T,
|
|
1106
1070
|
fill_value=0,
|
|
1107
1071
|
)
|
|
1108
1072
|
pZero = interpolater((0, 0))
|
|
1109
1073
|
# add the interpolated pressure at origin to pressure channels
|
|
1110
|
-
p = concatenate((p, pZero[:, newaxis]), axis=1)
|
|
1074
|
+
p = np.concatenate((p, pZero[:, np.newaxis]), axis=1)
|
|
1111
1075
|
|
|
1112
1076
|
# helpfunction reordered for reordered pressure values
|
|
1113
1077
|
pHelp = p[:, meshList[0][1]]
|
|
@@ -1115,31 +1079,31 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1115
1079
|
# Interpolation for 1D Arrays
|
|
1116
1080
|
if self.array_dimension == '1D' or self.array_dimension == 'ring':
|
|
1117
1081
|
# for rotation add phi_delay
|
|
1118
|
-
if not array_equal(phi_delay, []):
|
|
1119
|
-
xInterpHelp = tile(virtNewCoord[0, :], (nTime, 1)) + tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1120
|
-
xInterp = ((xInterpHelp + pi) % (2 * pi)) - pi # shifting phi
|
|
1082
|
+
if not np.array_equal(phi_delay, []):
|
|
1083
|
+
xInterpHelp = np.tile(virtNewCoord[0, :], (nTime, 1)) + np.tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1084
|
+
xInterp = ((xInterpHelp + np.pi) % (2 * np.pi)) - np.pi # shifting phi into feasible area [-pi, pi]
|
|
1121
1085
|
# if no rotation given
|
|
1122
1086
|
else:
|
|
1123
|
-
xInterp = tile(virtNewCoord[0, :], (nTime, 1))
|
|
1087
|
+
xInterp = np.tile(virtNewCoord[0, :], (nTime, 1))
|
|
1124
1088
|
# get ordered microphone positions in radiant
|
|
1125
1089
|
x = newCoord[0]
|
|
1126
1090
|
for cntTime in range(nTime):
|
|
1127
1091
|
if self.method == 'linear':
|
|
1128
1092
|
# numpy 1-d interpolation
|
|
1129
|
-
pInterp[cntTime] = interp(
|
|
1093
|
+
pInterp[cntTime] = np.interp(
|
|
1130
1094
|
xInterp[cntTime, :],
|
|
1131
1095
|
x,
|
|
1132
1096
|
pHelp[cntTime, :],
|
|
1133
1097
|
period=period,
|
|
1134
|
-
left=nan,
|
|
1135
|
-
right=nan,
|
|
1098
|
+
left=np.nan,
|
|
1099
|
+
right=np.nan,
|
|
1136
1100
|
)
|
|
1137
1101
|
|
|
1138
1102
|
elif self.method == 'spline':
|
|
1139
1103
|
# scipy cubic spline interpolation
|
|
1140
1104
|
SplineInterp = CubicSpline(
|
|
1141
|
-
append(x, (2 * pi) + x[0]),
|
|
1142
|
-
append(pHelp[cntTime, :], pHelp[cntTime, :][0]),
|
|
1105
|
+
np.append(x, (2 * np.pi) + x[0]),
|
|
1106
|
+
np.append(pHelp[cntTime, :], pHelp[cntTime, :][0]),
|
|
1143
1107
|
axis=0,
|
|
1144
1108
|
bc_type='periodic',
|
|
1145
1109
|
extrapolate=None,
|
|
@@ -1173,16 +1137,18 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1173
1137
|
# Interpolation for arbitrary 2D Arrays
|
|
1174
1138
|
elif self.array_dimension == '2D':
|
|
1175
1139
|
# check rotation
|
|
1176
|
-
if not array_equal(phi_delay, []):
|
|
1177
|
-
xInterpHelp = tile(virtNewCoord[0, :], (nTime, 1)) + tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1178
|
-
xInterp = ((xInterpHelp + pi) % (2 * pi)) - pi # shifting phi
|
|
1140
|
+
if not np.array_equal(phi_delay, []):
|
|
1141
|
+
xInterpHelp = np.tile(virtNewCoord[0, :], (nTime, 1)) + np.tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1142
|
+
xInterp = ((xInterpHelp + np.pi) % (2 * np.pi)) - np.pi # shifting phi into feasible area [-pi, pi]
|
|
1179
1143
|
else:
|
|
1180
|
-
xInterp = tile(virtNewCoord[0, :], (nTime, 1))
|
|
1144
|
+
xInterp = np.tile(virtNewCoord[0, :], (nTime, 1))
|
|
1181
1145
|
|
|
1182
1146
|
mesh = meshList[0][0]
|
|
1183
1147
|
for cntTime in range(nTime):
|
|
1184
1148
|
# points for interpolation
|
|
1185
|
-
newPoint = concatenate(
|
|
1149
|
+
newPoint = np.concatenate(
|
|
1150
|
+
(xInterp[cntTime, :][:, np.newaxis], virtNewCoord[1, :][:, np.newaxis]), axis=1
|
|
1151
|
+
)
|
|
1186
1152
|
# scipy 1D interpolation
|
|
1187
1153
|
if self.method == 'linear':
|
|
1188
1154
|
interpolater = LinearNDInterpolator(mesh, pHelp[cntTime, :], fill_value=0)
|
|
@@ -1215,7 +1181,7 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1215
1181
|
function='cubic',
|
|
1216
1182
|
) # radial basis function interpolator instance
|
|
1217
1183
|
|
|
1218
|
-
virtshiftcoord = array([xInterp[cntTime, :], virtNewCoord[1], virtNewCoord[2]])
|
|
1184
|
+
virtshiftcoord = np.array([xInterp[cntTime, :], virtNewCoord[1], virtNewCoord[2]])
|
|
1219
1185
|
pInterp[cntTime] = rbfi(virtshiftcoord[0], virtshiftcoord[1], virtshiftcoord[2])
|
|
1220
1186
|
|
|
1221
1187
|
elif self.method == 'rbf-multiquadric':
|
|
@@ -1228,40 +1194,40 @@ class SpatialInterpolator(TimeOut): # pragma: no cover
|
|
|
1228
1194
|
function='multiquadric',
|
|
1229
1195
|
) # radial basis function interpolator instance
|
|
1230
1196
|
|
|
1231
|
-
virtshiftcoord = array([xInterp[cntTime, :], virtNewCoord[1], virtNewCoord[2]])
|
|
1197
|
+
virtshiftcoord = np.array([xInterp[cntTime, :], virtNewCoord[1], virtNewCoord[2]])
|
|
1232
1198
|
pInterp[cntTime] = rbfi(virtshiftcoord[0], virtshiftcoord[1], virtshiftcoord[2])
|
|
1233
1199
|
# using inverse distance weighting
|
|
1234
1200
|
elif self.method == 'IDW':
|
|
1235
1201
|
newPoint2_M = newPoint.T
|
|
1236
|
-
newPoint3_M = append(newPoint2_M, zeros([1, self.num_channels]), axis=0)
|
|
1202
|
+
newPoint3_M = np.append(newPoint2_M, np.zeros([1, self.num_channels]), axis=0)
|
|
1237
1203
|
newPointCart = cylToCart(newPoint3_M)
|
|
1238
|
-
for ind in arange(len(newPoint[:, 0])):
|
|
1239
|
-
newPoint_Rep = tile(newPointCart[:, ind], (len(newPoint[:, 0]), 1)).T
|
|
1204
|
+
for ind in np.arange(len(newPoint[:, 0])):
|
|
1205
|
+
newPoint_Rep = np.tile(newPointCart[:, ind], (len(newPoint[:, 0]), 1)).T
|
|
1240
1206
|
subtract = newPoint_Rep - newCoordCart
|
|
1241
|
-
normDistance = norm(subtract, axis=0)
|
|
1242
|
-
index_norm = argsort(normDistance)[: self.num_IDW]
|
|
1207
|
+
normDistance = spla.norm(subtract, axis=0)
|
|
1208
|
+
index_norm = np.argsort(normDistance)[: self.num_IDW]
|
|
1243
1209
|
pHelpNew = pHelp[cntTime, index_norm]
|
|
1244
1210
|
normNew = normDistance[index_norm]
|
|
1245
1211
|
if normNew[0] < 1e-3:
|
|
1246
1212
|
pInterp[cntTime, ind] = pHelpNew[0]
|
|
1247
1213
|
else:
|
|
1248
|
-
wholeD = sum(1 / normNew**self.p_weight)
|
|
1214
|
+
wholeD = np.sum(1 / normNew**self.p_weight)
|
|
1249
1215
|
weight = (1 / normNew**self.p_weight) / wholeD
|
|
1250
|
-
pInterp[cntTime, ind] = sum(pHelpNew * weight)
|
|
1216
|
+
pInterp[cntTime, ind] = np.sum(pHelpNew * weight)
|
|
1251
1217
|
|
|
1252
1218
|
# Interpolation for arbitrary 3D Arrays
|
|
1253
1219
|
elif self.array_dimension == '3D':
|
|
1254
1220
|
# check rotation
|
|
1255
|
-
if not array_equal(phi_delay, []):
|
|
1256
|
-
xInterpHelp = tile(virtNewCoord[0, :], (nTime, 1)) + tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1257
|
-
xInterp = ((xInterpHelp + pi) % (2 * pi)) - pi # shifting phi
|
|
1221
|
+
if not np.array_equal(phi_delay, []):
|
|
1222
|
+
xInterpHelp = np.tile(virtNewCoord[0, :], (nTime, 1)) + np.tile(phi_delay, (virtNewCoord.shape[1], 1)).T
|
|
1223
|
+
xInterp = ((xInterpHelp + np.pi) % (2 * np.pi)) - np.pi # shifting phi into feasible area [-pi, pi]
|
|
1258
1224
|
else:
|
|
1259
|
-
xInterp = tile(virtNewCoord[0, :], (nTime, 1))
|
|
1225
|
+
xInterp = np.tile(virtNewCoord[0, :], (nTime, 1))
|
|
1260
1226
|
|
|
1261
1227
|
mesh = meshList[0][0]
|
|
1262
1228
|
for cntTime in range(nTime):
|
|
1263
1229
|
# points for interpolation
|
|
1264
|
-
newPoint = concatenate((xInterp[cntTime, :][:, newaxis], virtNewCoord[1:, :].T), axis=1)
|
|
1230
|
+
newPoint = np.concatenate((xInterp[cntTime, :][:, np.newaxis], virtNewCoord[1:, :].T), axis=1)
|
|
1265
1231
|
|
|
1266
1232
|
if self.method == 'linear':
|
|
1267
1233
|
interpolater = LinearNDInterpolator(mesh, pHelp[cntTime, :], fill_value=0)
|
|
@@ -1391,7 +1357,7 @@ class SpatialInterpolatorRotation(SpatialInterpolator): # pragma: no cover
|
|
|
1391
1357
|
a multiple of ``num``.
|
|
1392
1358
|
"""
|
|
1393
1359
|
# period for rotation
|
|
1394
|
-
period = 2 * pi
|
|
1360
|
+
period = 2 * np.pi
|
|
1395
1361
|
# get angle
|
|
1396
1362
|
angle = self.angle_source.angle()
|
|
1397
1363
|
# counter to track angle position in time for each block
|
|
@@ -1464,12 +1430,12 @@ class SpatialInterpolatorConstantRotation(SpatialInterpolator): # pragma: no co
|
|
|
1464
1430
|
The last block may contain fewer samples if the total number of samples is not
|
|
1465
1431
|
a multiple of ``num``.
|
|
1466
1432
|
"""
|
|
1467
|
-
omega = 2 * pi * self.rotational_speed
|
|
1468
|
-
period = 2 * pi
|
|
1433
|
+
omega = 2 * np.pi * self.rotational_speed
|
|
1434
|
+
period = 2 * np.pi
|
|
1469
1435
|
phiOffset = 0.0
|
|
1470
1436
|
for timeData in self.source.result(num):
|
|
1471
1437
|
nTime = timeData.shape[0]
|
|
1472
|
-
phi_delay = phiOffset + linspace(0, nTime / self.sample_freq * omega, nTime, endpoint=False)
|
|
1438
|
+
phi_delay = phiOffset + np.linspace(0, nTime / self.sample_freq * omega, nTime, endpoint=False)
|
|
1473
1439
|
interpVal = self._result_core_func(timeData, phi_delay, period, self.Q, interp_at_zero=False)
|
|
1474
1440
|
phiOffset = phi_delay[-1] + omega / self.sample_freq
|
|
1475
1441
|
yield interpVal
|
|
@@ -1521,16 +1487,18 @@ class Mixer(TimeOut):
|
|
|
1521
1487
|
return digest(self)
|
|
1522
1488
|
|
|
1523
1489
|
def validate_sources(self):
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1490
|
+
"""
|
|
1491
|
+
Validate whether the additional sources are compatible with the primary source.
|
|
1492
|
+
|
|
1493
|
+
This method checks if all sources have the same sampling frequency and the same number of
|
|
1494
|
+
channels. If a mismatch is detected, a :obj:`ValueError` is raised.
|
|
1495
|
+
|
|
1496
|
+
Raises
|
|
1497
|
+
------
|
|
1498
|
+
:obj:`ValueError`
|
|
1499
|
+
If any source in :attr:`sources` has a different sampling frequency or
|
|
1500
|
+
number of channels than :attr:`source`.
|
|
1501
|
+
"""
|
|
1534
1502
|
if self.source:
|
|
1535
1503
|
for s in self.sources:
|
|
1536
1504
|
if self.sample_freq != s.sample_freq:
|
|
@@ -1681,12 +1649,12 @@ class TimeCumAverage(TimeOut):
|
|
|
1681
1649
|
recalculated by summing the previous cumulative value and the new samples, then dividing by
|
|
1682
1650
|
the total number of samples up to that point.
|
|
1683
1651
|
"""
|
|
1684
|
-
count = (arange(num) + 1)[:, newaxis]
|
|
1652
|
+
count = (np.arange(num) + 1)[:, np.newaxis]
|
|
1685
1653
|
for i, temp in enumerate(self.source.result(num)):
|
|
1686
1654
|
ns, nc = temp.shape
|
|
1687
1655
|
if not i:
|
|
1688
|
-
accu = zeros((1, nc))
|
|
1689
|
-
temp = (accu * (count[0] - 1) + cumsum(temp, axis=0)) / count[:ns]
|
|
1656
|
+
accu = np.zeros((1, nc))
|
|
1657
|
+
temp = (accu * (count[0] - 1) + np.cumsum(temp, axis=0)) / count[:ns]
|
|
1690
1658
|
accu = temp[-1]
|
|
1691
1659
|
count += ns
|
|
1692
1660
|
yield temp
|
|
@@ -1724,7 +1692,7 @@ class TimeReverse(TimeOut):
|
|
|
1724
1692
|
------
|
|
1725
1693
|
:class:`numpy.ndarray`
|
|
1726
1694
|
An array containing the time-reversed version of the signal for the current block.
|
|
1727
|
-
Each block will have the shape (``num``, :attr
|
|
1695
|
+
Each block will have the shape (``num``, :attr:`~acoular.base.TimeOut.num_channels`),
|
|
1728
1696
|
where :attr:`~acoular.base.TimeOut.num_channels` is inherited from the :attr:`source`.
|
|
1729
1697
|
The last block may contain fewer samples if the total number of samples is not
|
|
1730
1698
|
a multiple of ``num``.
|
|
@@ -1739,7 +1707,7 @@ class TimeReverse(TimeOut):
|
|
|
1739
1707
|
"""
|
|
1740
1708
|
result_list = []
|
|
1741
1709
|
result_list.extend(self.source.result(num))
|
|
1742
|
-
temp = empty_like(result_list[0])
|
|
1710
|
+
temp = np.empty_like(result_list[0])
|
|
1743
1711
|
h = result_list.pop()
|
|
1744
1712
|
nsh = h.shape[0]
|
|
1745
1713
|
temp[:nsh] = h[::-1]
|
|
@@ -1803,7 +1771,7 @@ class Filter(TimeOut):
|
|
|
1803
1771
|
a multiple of ``num``.
|
|
1804
1772
|
"""
|
|
1805
1773
|
sos = self.sos
|
|
1806
|
-
zi = zeros((sos.shape[0], 2, self.source.num_channels))
|
|
1774
|
+
zi = np.zeros((sos.shape[0], 2, self.source.num_channels))
|
|
1807
1775
|
for block in self.source.result(num):
|
|
1808
1776
|
sos = self.sos # this line is useful in case of changes
|
|
1809
1777
|
# to self.sos during generator lifetime
|
|
@@ -1880,12 +1848,12 @@ class FiltOctave(Filter):
|
|
|
1880
1848
|
# adjust filter edge frequencies for correct power bandwidth (see ANSI 1.11 1987
|
|
1881
1849
|
# and Kalb,J.T.: "A thirty channel real time audio analyzer and its applications",
|
|
1882
1850
|
# PhD Thesis: Georgia Inst. of Techn., 1975
|
|
1883
|
-
beta = pi / (2 * self.order)
|
|
1851
|
+
beta = np.pi / (2 * self.order)
|
|
1884
1852
|
alpha = pow(2.0, 1.0 / (2.0 * self.fraction_))
|
|
1885
|
-
beta = 2 * beta / sin(beta) / (alpha - 1 / alpha)
|
|
1886
|
-
alpha = (1 + sqrt(1 + beta * beta)) / beta
|
|
1853
|
+
beta = 2 * beta / np.sin(beta) / (alpha - 1 / alpha)
|
|
1854
|
+
alpha = (1 + np.sqrt(1 + beta * beta)) / beta
|
|
1887
1855
|
fr = 2 * self.band / fs
|
|
1888
|
-
if fr > 1 / sqrt(2):
|
|
1856
|
+
if fr > 1 / np.sqrt(2):
|
|
1889
1857
|
msg = f'band frequency too high:{self.band:f},{fs:f}'
|
|
1890
1858
|
raise ValueError(msg)
|
|
1891
1859
|
om1 = fr / alpha
|
|
@@ -1946,16 +1914,16 @@ class FiltFiltOctave(FiltOctave):
|
|
|
1946
1914
|
# filter design
|
|
1947
1915
|
fs = self.sample_freq
|
|
1948
1916
|
# adjust filter edge frequencies for correct power bandwidth (see FiltOctave)
|
|
1949
|
-
beta = pi / (2 * self.order)
|
|
1917
|
+
beta = np.pi / (2 * self.order)
|
|
1950
1918
|
alpha = pow(2.0, 1.0 / (2.0 * self.fraction_))
|
|
1951
|
-
beta = 2 * beta / sin(beta) / (alpha - 1 / alpha)
|
|
1952
|
-
alpha = (1 + sqrt(1 + beta * beta)) / beta
|
|
1919
|
+
beta = 2 * beta / np.sin(beta) / (alpha - 1 / alpha)
|
|
1920
|
+
alpha = (1 + np.sqrt(1 + beta * beta)) / beta
|
|
1953
1921
|
# additional bandwidth correction for double-pass
|
|
1954
1922
|
alpha = alpha * {6: 1.01, 5: 1.012, 4: 1.016, 3: 1.022, 2: 1.036, 1: 1.083}.get(self.order, 1.0) ** (
|
|
1955
1923
|
3 / self.fraction_
|
|
1956
1924
|
)
|
|
1957
1925
|
fr = 2 * self.band / fs
|
|
1958
|
-
if fr > 1 / sqrt(2):
|
|
1926
|
+
if fr > 1 / np.sqrt(2):
|
|
1959
1927
|
msg = f'band frequency too high:{self.band:f},{fs:f}'
|
|
1960
1928
|
raise ValueError(msg)
|
|
1961
1929
|
om1 = fr / alpha
|
|
@@ -1990,7 +1958,7 @@ class FiltFiltOctave(FiltOctave):
|
|
|
1990
1958
|
- Filtering is performed separately for each channel to optimize memory usage.
|
|
1991
1959
|
"""
|
|
1992
1960
|
sos = self.sos
|
|
1993
|
-
data = empty((self.source.num_samples, self.source.num_channels))
|
|
1961
|
+
data = np.empty((self.source.num_samples, self.source.num_channels))
|
|
1994
1962
|
j = 0
|
|
1995
1963
|
for block in self.source.result(num):
|
|
1996
1964
|
ns, nc = block.shape
|
|
@@ -2073,7 +2041,7 @@ class TimeExpAverage(Filter):
|
|
|
2073
2041
|
#
|
|
2074
2042
|
# This implementation ensures that the filter adapts dynamically
|
|
2075
2043
|
# based on the source's sampling frequency.
|
|
2076
|
-
alpha = 1 - exp(-1 / self.weight_ / self.sample_freq)
|
|
2044
|
+
alpha = 1 - np.exp(-1 / self.weight_ / self.sample_freq)
|
|
2077
2045
|
a = [1, alpha - 1]
|
|
2078
2046
|
b = [alpha]
|
|
2079
2047
|
return tf2sos(b, a)
|
|
@@ -2163,38 +2131,37 @@ class FiltFreqWeight(Filter):
|
|
|
2163
2131
|
f2 = 107.65265
|
|
2164
2132
|
f3 = 737.86223
|
|
2165
2133
|
f4 = 12194.217
|
|
2166
|
-
a = polymul([1, 4 * pi * f4, (2 * pi * f4) ** 2], [1, 4 * pi * f1, (2 * pi * f1) ** 2])
|
|
2134
|
+
a = np.polymul([1, 4 * np.pi * f4, (2 * np.pi * f4) ** 2], [1, 4 * np.pi * f1, (2 * np.pi * f1) ** 2])
|
|
2167
2135
|
if self.weight == 'A':
|
|
2168
|
-
a = polymul(polymul(a, [1, 2 * pi * f3]), [1, 2 * pi * f2])
|
|
2169
|
-
b = [(2 * pi * f4) ** 2 * 10 ** (1.9997 / 20), 0, 0, 0, 0]
|
|
2136
|
+
a = np.polymul(np.polymul(a, [1, 2 * np.pi * f3]), [1, 2 * np.pi * f2])
|
|
2137
|
+
b = [(2 * np.pi * f4) ** 2 * 10 ** (1.9997 / 20), 0, 0, 0, 0]
|
|
2170
2138
|
b, a = bilinear(b, a, self.sample_freq)
|
|
2171
2139
|
elif self.weight == 'C':
|
|
2172
|
-
b = [(2 * pi * f4) ** 2 * 10 ** (0.0619 / 20), 0, 0]
|
|
2140
|
+
b = [(2 * np.pi * f4) ** 2 * 10 ** (0.0619 / 20), 0, 0]
|
|
2173
2141
|
b, a = bilinear(b, a, self.sample_freq)
|
|
2174
|
-
b = append(b, zeros(2)) # make 6th order
|
|
2175
|
-
a = append(a, zeros(2))
|
|
2142
|
+
b = np.append(b, np.zeros(2)) # make 6th order
|
|
2143
|
+
a = np.append(a, np.zeros(2))
|
|
2176
2144
|
else:
|
|
2177
|
-
b = zeros(7)
|
|
2145
|
+
b = np.zeros(7)
|
|
2178
2146
|
b[0] = 1.0
|
|
2179
2147
|
a = b # 6th order flat response
|
|
2180
2148
|
return tf2sos(b, a)
|
|
2181
2149
|
|
|
2182
2150
|
|
|
2183
|
-
@deprecated_alias({'numbands': 'num_bands'}, read_only=True, removal_version='25.10')
|
|
2184
2151
|
class FilterBank(TimeOut):
|
|
2185
2152
|
"""
|
|
2186
2153
|
Abstract base class for IIR filter banks based on :mod:`scipy.signal.lfilter`.
|
|
2187
2154
|
|
|
2188
2155
|
Implements a bank of parallel filters. This class should not be instantiated by itself.
|
|
2189
2156
|
|
|
2190
|
-
Inherits from :class
|
|
2157
|
+
Inherits from :class:`~acoular.base.TimeOut`, and defines the structure for working with filter
|
|
2191
2158
|
banks for processing multi-channel time series data, such as time signal signals.
|
|
2192
2159
|
|
|
2193
2160
|
See Also
|
|
2194
2161
|
--------
|
|
2195
|
-
:class
|
|
2162
|
+
:class:`~acoular.base.TimeOut` :
|
|
2196
2163
|
ABC for signal processing blocks that interact with data from a source.
|
|
2197
|
-
:class
|
|
2164
|
+
:class:`~acoular.base.SamplesGenerator` :
|
|
2198
2165
|
Interface for any generating multi-channel time domain signal processing block.
|
|
2199
2166
|
:mod:`scipy.signal` :
|
|
2200
2167
|
SciPy module for signal processing.
|
|
@@ -2260,12 +2227,13 @@ class FilterBank(TimeOut):
|
|
|
2260
2227
|
numbands = self.num_bands
|
|
2261
2228
|
snumch = self.source.num_channels
|
|
2262
2229
|
sos = self.sos
|
|
2263
|
-
zi = [zeros((sos[0].shape[0], 2, snumch)) for _ in range(numbands)]
|
|
2264
|
-
res = zeros((num, self.num_channels), dtype='float')
|
|
2230
|
+
zi = [np.zeros((sos[0].shape[0], 2, snumch)) for _ in range(numbands)]
|
|
2231
|
+
res = np.zeros((num, self.num_channels), dtype='float')
|
|
2265
2232
|
for block in self.source.result(num):
|
|
2233
|
+
len_block = block.shape[0]
|
|
2266
2234
|
for i in range(numbands):
|
|
2267
|
-
res[
|
|
2268
|
-
yield res
|
|
2235
|
+
res[:len_block, i * snumch : (i + 1) * snumch], zi[i] = sosfilt(sos[i], block, axis=0, zi=zi[i])
|
|
2236
|
+
yield res[:len_block]
|
|
2269
2237
|
|
|
2270
2238
|
|
|
2271
2239
|
class OctaveFilterBank(FilterBank):
|
|
@@ -2280,7 +2248,7 @@ class OctaveFilterBank(FilterBank):
|
|
|
2280
2248
|
--------
|
|
2281
2249
|
:class:`FilterBank` :
|
|
2282
2250
|
The base class for implementing IIR filter banks.
|
|
2283
|
-
:class
|
|
2251
|
+
:class:`~acoular.base.SamplesGenerator` :
|
|
2284
2252
|
Interface for generating multi-channel time domain signal processing blocks.
|
|
2285
2253
|
:mod:`scipy.signal` :
|
|
2286
2254
|
SciPy module for signal processing.
|
|
@@ -2347,7 +2315,6 @@ class OctaveFilterBank(FilterBank):
|
|
|
2347
2315
|
return sos
|
|
2348
2316
|
|
|
2349
2317
|
|
|
2350
|
-
@deprecated_alias({'name': 'file'}, removal_version='25.10')
|
|
2351
2318
|
class WriteWAV(TimeOut):
|
|
2352
2319
|
"""
|
|
2353
2320
|
Saves time signal from one or more channels as mono, stereo, or multi-channel ``.wav`` file.
|
|
@@ -2358,9 +2325,9 @@ class WriteWAV(TimeOut):
|
|
|
2358
2325
|
|
|
2359
2326
|
See Also
|
|
2360
2327
|
--------
|
|
2361
|
-
:class
|
|
2328
|
+
:class:`~acoular.base.TimeOut` :
|
|
2362
2329
|
ABC for signal processing blocks that interact with data from a source.
|
|
2363
|
-
:class
|
|
2330
|
+
:class:`~acoular.base.SamplesGenerator` :
|
|
2364
2331
|
Interface for generating multi-channel time domain signal processing blocks.
|
|
2365
2332
|
:mod:`wave` :
|
|
2366
2333
|
Python module for handling WAV files.
|
|
@@ -2485,7 +2452,7 @@ class WriteWAV(TimeOut):
|
|
|
2485
2452
|
wf.setnchannels(nc)
|
|
2486
2453
|
wf.setsampwidth(sw)
|
|
2487
2454
|
wf.setframerate(fs)
|
|
2488
|
-
ind = array(self.channels)
|
|
2455
|
+
ind = np.array(self.channels)
|
|
2489
2456
|
if self.max_val is None:
|
|
2490
2457
|
# compute maximum and remember result to avoid calling source twice
|
|
2491
2458
|
if not isinstance(self.source, Cache):
|
|
@@ -2495,7 +2462,7 @@ class WriteWAV(TimeOut):
|
|
|
2495
2462
|
if dtype == np.dtype('uint8'):
|
|
2496
2463
|
mx = 0
|
|
2497
2464
|
for data in self.source.result(num):
|
|
2498
|
-
mx = max(abs(data).max(), mx)
|
|
2465
|
+
mx = max(np.abs(data).max(), mx)
|
|
2499
2466
|
elif dtype in (np.dtype('int16'), np.dtype('int32')):
|
|
2500
2467
|
# for signed integers, we need special treatment because of asymmetry
|
|
2501
2468
|
negmax, posmax = 0, 0
|
|
@@ -2528,9 +2495,6 @@ class WriteWAV(TimeOut):
|
|
|
2528
2495
|
pass
|
|
2529
2496
|
|
|
2530
2497
|
|
|
2531
|
-
@deprecated_alias(
|
|
2532
|
-
{'name': 'file', 'numsamples_write': 'num_samples_write', 'writeflag': 'write_flag'}, removal_version='25.10'
|
|
2533
|
-
)
|
|
2534
2498
|
class WriteH5(TimeOut):
|
|
2535
2499
|
"""
|
|
2536
2500
|
Saves time signal data as a ``.h5`` (HDF5) file.
|
|
@@ -2541,9 +2505,9 @@ class WriteH5(TimeOut):
|
|
|
2541
2505
|
|
|
2542
2506
|
See Also
|
|
2543
2507
|
--------
|
|
2544
|
-
:class
|
|
2508
|
+
:class:`~acoular.base.TimeOut` :
|
|
2545
2509
|
ABC for signal processing blocks interacting with data from a source.
|
|
2546
|
-
:class
|
|
2510
|
+
:class:`~acoular.base.SamplesGenerator` :
|
|
2547
2511
|
Interface for generating multi-channel time-domain signal processing blocks.
|
|
2548
2512
|
h5py :
|
|
2549
2513
|
Python library for reading and writing HDF5 files.
|
|
@@ -2646,7 +2610,7 @@ class WriteH5(TimeOut):
|
|
|
2646
2610
|
f5h.create_new_group('metadata', '/')
|
|
2647
2611
|
for key, value in self.metadata.items():
|
|
2648
2612
|
if isinstance(value, str):
|
|
2649
|
-
value = array(value, dtype='S')
|
|
2613
|
+
value = np.array(value, dtype='S')
|
|
2650
2614
|
f5h.create_array('/metadata', key, value)
|
|
2651
2615
|
|
|
2652
2616
|
def result(self, num):
|
|
@@ -2716,9 +2680,9 @@ class TimeConvolve(TimeOut):
|
|
|
2716
2680
|
|
|
2717
2681
|
See Also
|
|
2718
2682
|
--------
|
|
2719
|
-
:class
|
|
2683
|
+
:class:`~acoular.base.TimeOut` :
|
|
2720
2684
|
The parent class for signal processing blocks.
|
|
2721
|
-
:class
|
|
2685
|
+
:class:`~acoular.base.SamplesGenerator` :
|
|
2722
2686
|
The interface for generating multi-channel time-domain signals.
|
|
2723
2687
|
"""
|
|
2724
2688
|
|
|
@@ -2786,16 +2750,16 @@ class TimeConvolve(TimeOut):
|
|
|
2786
2750
|
# A 3D array of complex values representing the frequency-domain blocks of the kernel.
|
|
2787
2751
|
[L, N] = self.kernel.shape
|
|
2788
2752
|
num = self._block_size
|
|
2789
|
-
P = int(ceil(L / num))
|
|
2753
|
+
P = int(np.ceil(L / num))
|
|
2790
2754
|
trim = num * (P - 1)
|
|
2791
|
-
blocks = zeros([P, num + 1, N], dtype='complex128')
|
|
2755
|
+
blocks = np.zeros([P, num + 1, N], dtype='complex128')
|
|
2792
2756
|
|
|
2793
2757
|
if P > 1:
|
|
2794
|
-
for i, block in enumerate(split(self.kernel[:trim], P - 1, axis=0)):
|
|
2795
|
-
blocks[i] = rfft(concatenate([block, zeros([num, N])], axis=0), axis=0)
|
|
2758
|
+
for i, block in enumerate(np.split(self.kernel[:trim], P - 1, axis=0)):
|
|
2759
|
+
blocks[i] = rfft(np.concatenate([block, np.zeros([num, N])], axis=0), axis=0)
|
|
2796
2760
|
|
|
2797
2761
|
blocks[-1] = rfft(
|
|
2798
|
-
concatenate([self.kernel[trim:], zeros([2 * num - L + trim, N])], axis=0),
|
|
2762
|
+
np.concatenate([self.kernel[trim:], np.zeros([2 * num - L + trim, N])], axis=0),
|
|
2799
2763
|
axis=0,
|
|
2800
2764
|
)
|
|
2801
2765
|
return blocks
|
|
@@ -2832,15 +2796,15 @@ class TimeConvolve(TimeOut):
|
|
|
2832
2796
|
L = self.kernel.shape[0]
|
|
2833
2797
|
N = self.source.num_channels
|
|
2834
2798
|
M = self.source.num_samples
|
|
2835
|
-
numblocks_kernel = int(ceil(L / num)) # number of kernel blocks
|
|
2836
|
-
Q = int(ceil(M / num)) # number of signal blocks
|
|
2837
|
-
R = int(ceil((L + M - 1) / num)) # number of output blocks
|
|
2799
|
+
numblocks_kernel = int(np.ceil(L / num)) # number of kernel blocks
|
|
2800
|
+
Q = int(np.ceil(M / num)) # number of signal blocks
|
|
2801
|
+
R = int(np.ceil((L + M - 1) / num)) # number of output blocks
|
|
2838
2802
|
last_size = (L + M - 1) % num # size of final block
|
|
2839
2803
|
|
|
2840
2804
|
idx = 0
|
|
2841
|
-
fdl = zeros([numblocks_kernel, num + 1, N], dtype='complex128')
|
|
2842
|
-
buff = zeros([2 * num, N]) # time-domain input buffer
|
|
2843
|
-
spec_sum = zeros([num + 1, N], dtype='complex128')
|
|
2805
|
+
fdl = np.zeros([numblocks_kernel, num + 1, N], dtype='complex128')
|
|
2806
|
+
buff = np.zeros([2 * num, N]) # time-domain input buffer
|
|
2807
|
+
spec_sum = np.zeros([num + 1, N], dtype='complex128')
|
|
2844
2808
|
|
|
2845
2809
|
signal_blocks = self.source.result(num)
|
|
2846
2810
|
temp = next(signal_blocks)
|
|
@@ -2859,8 +2823,8 @@ class TimeConvolve(TimeOut):
|
|
|
2859
2823
|
_append_to_fdl(fdl, idx, numblocks_kernel, rfft(buff, axis=0))
|
|
2860
2824
|
spec_sum = _spectral_sum(spec_sum, fdl, self._kernel_blocks)
|
|
2861
2825
|
yield irfft(spec_sum, axis=0)[num:]
|
|
2862
|
-
buff = concatenate(
|
|
2863
|
-
[buff[num:], zeros([num, N])],
|
|
2826
|
+
buff = np.concatenate(
|
|
2827
|
+
[buff[num:], np.zeros([num, N])],
|
|
2864
2828
|
axis=0,
|
|
2865
2829
|
) # shift input buffer to the left
|
|
2866
2830
|
buff[num : num + temp.shape[0]] = temp # append new time-data
|
|
@@ -2869,8 +2833,8 @@ class TimeConvolve(TimeOut):
|
|
|
2869
2833
|
_append_to_fdl(fdl, idx, numblocks_kernel, rfft(buff, axis=0))
|
|
2870
2834
|
spec_sum = _spectral_sum(spec_sum, fdl, self._kernel_blocks)
|
|
2871
2835
|
yield irfft(spec_sum, axis=0)[num:]
|
|
2872
|
-
buff = concatenate(
|
|
2873
|
-
[buff[num:], zeros([num, N])],
|
|
2836
|
+
buff = np.concatenate(
|
|
2837
|
+
[buff[num:], np.zeros([num, N])],
|
|
2874
2838
|
axis=0,
|
|
2875
2839
|
) # shift input buffer to the left
|
|
2876
2840
|
|