acoular 24.3__py3-none-any.whl → 24.7__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/__init__.py +119 -54
- acoular/calib.py +29 -38
- acoular/configuration.py +132 -82
- acoular/demo/__init__.py +10 -4
- acoular/demo/acoular_demo.py +73 -55
- acoular/environments.py +270 -264
- acoular/fastFuncs.py +366 -196
- acoular/fbeamform.py +1797 -1934
- acoular/grids.py +504 -548
- acoular/h5cache.py +74 -83
- acoular/h5files.py +159 -142
- acoular/internal.py +13 -14
- acoular/microphones.py +57 -53
- acoular/sdinput.py +57 -53
- acoular/signals.py +180 -178
- acoular/sources.py +920 -724
- acoular/spectra.py +353 -363
- acoular/tbeamform.py +416 -416
- acoular/tfastfuncs.py +180 -104
- acoular/tools/__init__.py +25 -0
- acoular/tools/aiaa.py +185 -0
- acoular/tools/helpers.py +189 -0
- acoular/tools/metrics.py +165 -0
- acoular/tprocess.py +1240 -1182
- acoular/traitsviews.py +513 -501
- acoular/trajectory.py +50 -52
- acoular/version.py +5 -6
- acoular/xml/minidsp_uma-16.xml +20 -0
- acoular/xml/{minidsp_uma16.xml → minidsp_uma-16_mirrored.xml} +3 -0
- {acoular-24.3.dist-info → acoular-24.7.dist-info}/METADATA +58 -39
- acoular-24.7.dist-info/RECORD +50 -0
- {acoular-24.3.dist-info → acoular-24.7.dist-info}/WHEEL +1 -1
- acoular-24.7.dist-info/licenses/LICENSE +28 -0
- acoular/fileimport.py +0 -380
- acoular/nidaqimport.py +0 -273
- acoular/tests/reference_data/BeamformerBase.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseFalse1.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseFalse2.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseFalse3.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseFalse4.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseTrue1.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseTrue2.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseTrue3.npy +0 -0
- acoular/tests/reference_data/BeamformerBaseTrue4.npy +0 -0
- acoular/tests/reference_data/BeamformerCMFLassoLarsBIC.npy +0 -0
- acoular/tests/reference_data/BeamformerCMFNNLS.npy +0 -0
- acoular/tests/reference_data/BeamformerCapon.npy +0 -0
- acoular/tests/reference_data/BeamformerClean.npy +0 -0
- acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
- acoular/tests/reference_data/BeamformerCleant.npy +0 -0
- acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
- acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
- acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
- acoular/tests/reference_data/BeamformerDamas.npy +0 -0
- acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
- acoular/tests/reference_data/BeamformerEig.npy +0 -0
- acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
- acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
- acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
- acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
- acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
- acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
- acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
- acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
- acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
- acoular/tests/reference_data/BeamformerGIB.npy +0 -0
- acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
- acoular/tests/reference_data/BeamformerMusic.npy +0 -0
- acoular/tests/reference_data/BeamformerOrth.npy +0 -0
- acoular/tests/reference_data/BeamformerSODIX.npy +0 -0
- acoular/tests/reference_data/BeamformerTime.npy +0 -0
- acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
- acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
- acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
- acoular/tests/reference_data/Environment.npy +0 -0
- acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
- acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
- acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
- acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
- acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
- acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
- acoular/tests/reference_data/FiltOctave__.npy +0 -0
- acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
- acoular/tests/reference_data/Filter__.npy +0 -0
- acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
- acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
- acoular/tests/reference_data/OpenJet.npy +0 -0
- acoular/tests/reference_data/PointSource.npy +0 -0
- acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
- acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
- acoular/tests/reference_data/RotatingFlow.npy +0 -0
- acoular/tests/reference_data/SlotJet.npy +0 -0
- acoular/tests/reference_data/TimeAverage__.npy +0 -0
- acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
- acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
- acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
- acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
- acoular/tests/reference_data/TimeInOut__.npy +0 -0
- acoular/tests/reference_data/TimePower__.npy +0 -0
- acoular/tests/reference_data/TimeReverse__.npy +0 -0
- acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
- acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
- acoular/tests/run_tests.sh +0 -18
- acoular/tests/run_tests_osx.sh +0 -16
- acoular/tests/test.npy +0 -0
- acoular/tests/test_beamformer_results.py +0 -213
- acoular/tests/test_classes.py +0 -60
- acoular/tests/test_digest.py +0 -125
- acoular/tests/test_environments.py +0 -73
- acoular/tests/test_example1.py +0 -124
- acoular/tests/test_grid.py +0 -92
- acoular/tests/test_integrate.py +0 -102
- acoular/tests/test_signals.py +0 -60
- acoular/tests/test_sources.py +0 -65
- acoular/tests/test_spectra.py +0 -38
- acoular/tests/test_timecache.py +0 -35
- acoular/tests/test_tprocess.py +0 -90
- acoular/tests/test_traj_beamformer_results.py +0 -164
- acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
- acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
- acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
- acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
- acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
- acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
- acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
- acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
- acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
- acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
- acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
- acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
- acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
- acoular/tests/unsupported/functionalBeamformer.py +0 -123
- acoular/tests/unsupported/precisionTest.py +0 -153
- acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
- acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
- acoular/tools.py +0 -422
- acoular-24.3.dist-info/RECORD +0 -148
- acoular-24.3.dist-info/licenses/LICENSE +0 -29
- {acoular-24.3.dist-info → acoular-24.7.dist-info}/licenses/AUTHORS.rst +0 -0
acoular/tbeamform.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
#
|
|
2
|
-
#pylint: disable-msg=E0611, E1101, C0103, R0901, R0902, R0903, R0904, W0232
|
|
3
|
-
#------------------------------------------------------------------------------
|
|
1
|
+
# ------------------------------------------------------------------------------
|
|
4
2
|
# Copyright (c) Acoular Development Team.
|
|
5
|
-
|
|
3
|
+
# ------------------------------------------------------------------------------
|
|
6
4
|
"""Implements beamformers in the time domain.
|
|
7
5
|
|
|
8
6
|
.. autosummary::
|
|
@@ -20,245 +18,258 @@
|
|
|
20
18
|
"""
|
|
21
19
|
|
|
22
20
|
# imports from other packages
|
|
23
|
-
|
|
24
|
-
from
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
import contextlib
|
|
22
|
+
from warnings import warn
|
|
23
|
+
|
|
24
|
+
from numpy import (
|
|
25
|
+
arange,
|
|
26
|
+
argmax,
|
|
27
|
+
array,
|
|
28
|
+
ceil,
|
|
29
|
+
concatenate,
|
|
30
|
+
dot,
|
|
31
|
+
empty,
|
|
32
|
+
float32,
|
|
33
|
+
float64,
|
|
34
|
+
histogram,
|
|
35
|
+
int32,
|
|
36
|
+
int64,
|
|
37
|
+
interp,
|
|
38
|
+
isscalar,
|
|
39
|
+
newaxis,
|
|
40
|
+
r_,
|
|
41
|
+
s_,
|
|
42
|
+
sqrt,
|
|
43
|
+
sum,
|
|
44
|
+
unique,
|
|
45
|
+
where,
|
|
46
|
+
zeros,
|
|
47
|
+
)
|
|
27
48
|
from numpy.linalg import norm
|
|
28
|
-
from traits.api import
|
|
29
|
-
cached_property, List, Instance, Range, Int, Enum
|
|
49
|
+
from traits.api import Bool, CArray, Delegate, Enum, Float, Instance, Int, List, Property, Range, Trait, cached_property
|
|
30
50
|
from traits.trait_errors import TraitError
|
|
31
|
-
|
|
51
|
+
|
|
52
|
+
from .fbeamform import SteeringVector
|
|
53
|
+
from .grids import RectGrid
|
|
32
54
|
|
|
33
55
|
# acoular imports
|
|
34
56
|
from .internal import digest
|
|
35
|
-
from .
|
|
36
|
-
from .trajectory import Trajectory
|
|
57
|
+
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays, _steer_I, _steer_II, _steer_III, _steer_IV
|
|
37
58
|
from .tprocess import TimeInOut
|
|
38
|
-
from .
|
|
39
|
-
from .tfastfuncs import _delayandsum4, _delayandsum5, \
|
|
40
|
-
_steer_I, _steer_II, _steer_III, _steer_IV, _delays, _modf
|
|
59
|
+
from .trajectory import Trajectory
|
|
41
60
|
|
|
42
61
|
|
|
43
|
-
def const_power_weight(
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Provides microphone weighting
|
|
62
|
+
def const_power_weight(bf):
|
|
63
|
+
"""Internal helper function for :class:`BeamformerTime`.
|
|
64
|
+
|
|
65
|
+
Provides microphone weighting
|
|
48
66
|
to make the power per unit area of the
|
|
49
67
|
microphone array geometry constant.
|
|
50
|
-
|
|
68
|
+
|
|
51
69
|
Parameters
|
|
52
70
|
----------
|
|
53
71
|
bf: :class:`BeamformerTime` object
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
|
|
73
|
+
|
|
56
74
|
Returns
|
|
57
75
|
-------
|
|
58
76
|
array of floats
|
|
59
77
|
The weight factors.
|
|
60
|
-
"""
|
|
61
78
|
|
|
62
|
-
|
|
79
|
+
"""
|
|
80
|
+
r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.mpos) # distances to center
|
|
63
81
|
# round the relative distances to one decimal place
|
|
64
|
-
r = (r/r.max()).round(decimals=1)
|
|
82
|
+
r = (r / r.max()).round(decimals=1)
|
|
65
83
|
ru, ind = unique(r, return_inverse=True)
|
|
66
|
-
ru = (ru[1:]+ru[:-1])/2
|
|
67
|
-
count, bins = histogram(r, r_[0, ru, 1.5*r.max()-0.5*ru[-1]])
|
|
84
|
+
ru = (ru[1:] + ru[:-1]) / 2
|
|
85
|
+
count, bins = histogram(r, r_[0, ru, 1.5 * r.max() - 0.5 * ru[-1]])
|
|
68
86
|
bins *= bins
|
|
69
|
-
weights = sqrt((bins[1:]-bins[:-1])/count)
|
|
87
|
+
weights = sqrt((bins[1:] - bins[:-1]) / count)
|
|
70
88
|
weights /= weights.mean()
|
|
71
89
|
return weights[ind]
|
|
72
90
|
|
|
91
|
+
|
|
73
92
|
# possible choices for spatial weights
|
|
74
|
-
possible_weights = {'none':None,
|
|
75
|
-
'power':const_power_weight}
|
|
93
|
+
possible_weights = {'none': None, 'power': const_power_weight}
|
|
76
94
|
|
|
77
95
|
|
|
78
|
-
class BeamformerTime(
|
|
79
|
-
"""
|
|
80
|
-
Provides a basic time domain beamformer with time signal output
|
|
96
|
+
class BeamformerTime(TimeInOut):
|
|
97
|
+
"""Provides a basic time domain beamformer with time signal output
|
|
81
98
|
for a spatially fixed grid.
|
|
82
99
|
"""
|
|
83
100
|
|
|
84
|
-
|
|
85
101
|
# Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
|
|
86
102
|
# that contains information about the steering vector. This is a private trait.
|
|
87
103
|
# Do not set this directly, use `steer` trait instead.
|
|
88
|
-
_steer_obj = Instance(SteeringVector(), SteeringVector)
|
|
89
|
-
|
|
90
|
-
#: :class:`~acoular.fbeamform.SteeringVector` or derived object.
|
|
104
|
+
_steer_obj = Instance(SteeringVector(), SteeringVector)
|
|
105
|
+
|
|
106
|
+
#: :class:`~acoular.fbeamform.SteeringVector` or derived object.
|
|
91
107
|
#: Defaults to :class:`~acoular.fbeamform.SteeringVector` object.
|
|
92
|
-
steer = Property(desc=
|
|
93
|
-
|
|
108
|
+
steer = Property(desc='steering vector object')
|
|
109
|
+
|
|
94
110
|
def _get_steer(self):
|
|
95
111
|
return self._steer_obj
|
|
96
|
-
|
|
112
|
+
|
|
97
113
|
def _set_steer(self, steer):
|
|
98
114
|
if type(steer) == SteeringVector:
|
|
99
115
|
# This condition may be replaced at a later time by: isinstance(steer, SteeringVector): -- (derived classes allowed)
|
|
100
116
|
self._steer_obj = steer
|
|
101
117
|
elif steer in ('true level', 'true location', 'classic', 'inverse'):
|
|
102
118
|
# Type of steering vectors, see also :ref:`Sarradj, 2012<Sarradj2012>`.
|
|
103
|
-
warn(
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
warn(
|
|
120
|
+
"Deprecated use of 'steer' trait. Please use object of class 'SteeringVector' in the future.",
|
|
121
|
+
Warning,
|
|
122
|
+
stacklevel=2,
|
|
123
|
+
)
|
|
106
124
|
self._steer_obj.steer_type = steer
|
|
107
125
|
else:
|
|
108
|
-
raise(TraitError(args=self,
|
|
109
|
-
name='steer',
|
|
110
|
-
info='SteeringVector',
|
|
111
|
-
value=steer))
|
|
126
|
+
raise (TraitError(args=self, name='steer', info='SteeringVector', value=steer))
|
|
112
127
|
|
|
113
128
|
# --- List of backwards compatibility traits and their setters/getters -----------
|
|
114
|
-
|
|
115
|
-
# :class:`~acoular.environments.Environment` or derived object.
|
|
116
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
129
|
+
|
|
130
|
+
# :class:`~acoular.environments.Environment` or derived object.
|
|
131
|
+
# Deprecated! Only kept for backwards compatibility.
|
|
117
132
|
# Now governed by :attr:`steer` trait.
|
|
118
133
|
env = Property()
|
|
119
|
-
|
|
134
|
+
|
|
120
135
|
def _get_env(self):
|
|
121
|
-
return self._steer_obj.env
|
|
122
|
-
|
|
136
|
+
return self._steer_obj.env
|
|
137
|
+
|
|
123
138
|
def _set_env(self, env):
|
|
124
|
-
warn("Deprecated use of 'env' trait. ", Warning, stacklevel
|
|
139
|
+
warn("Deprecated use of 'env' trait. ", Warning, stacklevel=2)
|
|
125
140
|
self._steer_obj.env = env
|
|
126
|
-
|
|
141
|
+
|
|
127
142
|
# The speed of sound.
|
|
128
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
143
|
+
# Deprecated! Only kept for backwards compatibility.
|
|
129
144
|
# Now governed by :attr:`steer` trait.
|
|
130
145
|
c = Property()
|
|
131
|
-
|
|
146
|
+
|
|
132
147
|
def _get_c(self):
|
|
133
148
|
return self._steer_obj.env.c
|
|
134
|
-
|
|
149
|
+
|
|
135
150
|
def _set_c(self, c):
|
|
136
|
-
warn("Deprecated use of 'c' trait. ", Warning, stacklevel
|
|
151
|
+
warn("Deprecated use of 'c' trait. ", Warning, stacklevel=2)
|
|
137
152
|
self._steer_obj.env.c = c
|
|
138
|
-
|
|
153
|
+
|
|
139
154
|
# :class:`~acoular.grids.Grid`-derived object that provides the grid locations.
|
|
140
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
155
|
+
# Deprecated! Only kept for backwards compatibility.
|
|
141
156
|
# Now governed by :attr:`steer` trait.
|
|
142
157
|
grid = Property()
|
|
143
158
|
|
|
144
159
|
def _get_grid(self):
|
|
145
160
|
return self._steer_obj.grid
|
|
146
|
-
|
|
161
|
+
|
|
147
162
|
def _set_grid(self, grid):
|
|
148
|
-
warn("Deprecated use of 'grid' trait. ", Warning, stacklevel
|
|
163
|
+
warn("Deprecated use of 'grid' trait. ", Warning, stacklevel=2)
|
|
149
164
|
self._steer_obj.grid = grid
|
|
150
|
-
|
|
165
|
+
|
|
151
166
|
# :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
|
|
152
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
167
|
+
# Deprecated! Only kept for backwards compatibility.
|
|
153
168
|
# Now governed by :attr:`steer` trait
|
|
154
169
|
mpos = Property()
|
|
155
|
-
|
|
170
|
+
|
|
156
171
|
def _get_mpos(self):
|
|
157
172
|
return self._steer_obj.mics
|
|
158
|
-
|
|
173
|
+
|
|
159
174
|
def _set_mpos(self, mpos):
|
|
160
|
-
warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel
|
|
175
|
+
warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
|
|
161
176
|
self._steer_obj.mics = mpos
|
|
162
|
-
|
|
163
|
-
|
|
177
|
+
|
|
164
178
|
# Sound travel distances from microphone array center to grid points (r0)
|
|
165
179
|
# and all array mics to grid points (rm). Readonly.
|
|
166
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
180
|
+
# Deprecated! Only kept for backwards compatibility.
|
|
167
181
|
# Now governed by :attr:`steer` trait
|
|
168
182
|
r0 = Property()
|
|
183
|
+
|
|
169
184
|
def _get_r0(self):
|
|
170
185
|
return self._steer_obj.r0
|
|
171
|
-
|
|
186
|
+
|
|
172
187
|
rm = Property()
|
|
188
|
+
|
|
173
189
|
def _get_rm(self):
|
|
174
190
|
return self._steer_obj.rm
|
|
175
|
-
|
|
191
|
+
|
|
176
192
|
# --- End of backwards compatibility traits --------------------------------------
|
|
177
193
|
|
|
178
194
|
#: Number of channels in output (=number of grid points).
|
|
179
195
|
numchannels = Delegate('grid', 'size')
|
|
180
196
|
|
|
181
197
|
#: Spatial weighting function.
|
|
182
|
-
weights = Trait('none', possible_weights,
|
|
183
|
-
desc="spatial weighting function")
|
|
198
|
+
weights = Trait('none', possible_weights, desc='spatial weighting function')
|
|
184
199
|
# (from timedomain.possible_weights)
|
|
185
200
|
|
|
186
|
-
# buffer with microphone time signals used for processing. Internal use
|
|
187
|
-
buffer = CArray(desc=
|
|
188
|
-
|
|
201
|
+
# buffer with microphone time signals used for processing. Internal use
|
|
202
|
+
buffer = CArray(desc='buffer containing microphone signals')
|
|
203
|
+
|
|
189
204
|
# index indicating position of current processing sample. Internal use.
|
|
190
|
-
bufferIndex = Int(desc=
|
|
205
|
+
bufferIndex = Int(desc='index indicating position in buffer') # noqa: N815
|
|
191
206
|
|
|
192
207
|
# internal identifier
|
|
193
|
-
digest = Property(
|
|
194
|
-
depends_on
|
|
195
|
-
|
|
208
|
+
digest = Property(
|
|
209
|
+
depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__'],
|
|
210
|
+
)
|
|
196
211
|
|
|
197
212
|
@cached_property
|
|
198
|
-
def _get_digest(
|
|
213
|
+
def _get_digest(self):
|
|
199
214
|
return digest(self)
|
|
200
|
-
|
|
215
|
+
|
|
201
216
|
def _get_weights(self):
|
|
202
|
-
if self.weights_
|
|
203
|
-
w = self.weights_(self)[newaxis]
|
|
204
|
-
else:
|
|
205
|
-
w = 1.0
|
|
206
|
-
return w
|
|
217
|
+
return self.weights_(self)[newaxis] if self.weights_ else 1.0
|
|
207
218
|
|
|
208
|
-
def _fill_buffer(self,num):
|
|
209
|
-
"""
|
|
219
|
+
def _fill_buffer(self, num):
|
|
220
|
+
"""Generator that fills the signal buffer."""
|
|
210
221
|
weights = self._get_weights()
|
|
211
222
|
for block in self.source.result(num):
|
|
212
223
|
block *= weights
|
|
213
224
|
ns = block.shape[0]
|
|
214
225
|
bufferSize = self.buffer.shape[0]
|
|
215
|
-
self.buffer[0:(bufferSize-ns)] = self.buffer[-(bufferSize-ns):]
|
|
216
|
-
self.buffer[-ns
|
|
226
|
+
self.buffer[0 : (bufferSize - ns)] = self.buffer[-(bufferSize - ns) :]
|
|
227
|
+
self.buffer[-ns:, :] = block
|
|
217
228
|
self.bufferIndex -= ns
|
|
218
229
|
yield
|
|
219
|
-
|
|
220
|
-
def result(
|
|
221
|
-
"""
|
|
222
|
-
Python generator that yields the *squared* deconvolved beamformer
|
|
230
|
+
|
|
231
|
+
def result(self, num=2048):
|
|
232
|
+
"""Python generator that yields the *squared* deconvolved beamformer
|
|
223
233
|
output with optional removal of autocorrelation block-wise.
|
|
224
|
-
|
|
234
|
+
|
|
225
235
|
Parameters
|
|
226
236
|
----------
|
|
227
237
|
num : integer, defaults to 2048
|
|
228
238
|
This parameter defines the size of the blocks to be yielded
|
|
229
239
|
(i.e. the number of samples per block).
|
|
230
|
-
|
|
240
|
+
|
|
231
241
|
Returns
|
|
232
242
|
-------
|
|
233
243
|
Samples in blocks of shape \
|
|
234
|
-
(num, :attr:`~BeamformerTime.numchannels`).
|
|
244
|
+
(num, :attr:`~BeamformerTime.numchannels`).
|
|
235
245
|
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
236
246
|
large (number of grid points).
|
|
237
247
|
The last block may be shorter than num. \
|
|
238
|
-
The output starts for signals that were emitted
|
|
248
|
+
The output starts for signals that were emitted
|
|
239
249
|
from the grid at `t=0`.
|
|
250
|
+
|
|
240
251
|
"""
|
|
241
252
|
# initialize values
|
|
242
253
|
fdtype = float64
|
|
243
254
|
idtype = int64
|
|
244
255
|
numMics = self.steer.mics.num_mics
|
|
245
|
-
n_index = arange(0,num+1)[:,newaxis]
|
|
246
|
-
c = self.steer.env.c/self.source.sample_freq
|
|
247
|
-
amp = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
248
|
-
#delays = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
249
|
-
d_index = empty((1,self.grid.size,numMics),dtype=idtype)
|
|
250
|
-
d_interp2 = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
251
|
-
_steer_III(self.rm[newaxis
|
|
252
|
-
_delays(self.rm[newaxis
|
|
256
|
+
n_index = arange(0, num + 1)[:, newaxis]
|
|
257
|
+
c = self.steer.env.c / self.source.sample_freq
|
|
258
|
+
amp = empty((1, self.grid.size, numMics), dtype=fdtype)
|
|
259
|
+
# delays = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
260
|
+
d_index = empty((1, self.grid.size, numMics), dtype=idtype)
|
|
261
|
+
d_interp2 = empty((1, self.grid.size, numMics), dtype=fdtype)
|
|
262
|
+
_steer_III(self.rm[newaxis, :, :], self.r0[newaxis, :], amp)
|
|
263
|
+
_delays(self.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
253
264
|
amp.shape = amp.shape[1:]
|
|
254
|
-
#delays.shape = delays.shape[1:]
|
|
265
|
+
# delays.shape = delays.shape[1:]
|
|
255
266
|
d_index.shape = d_index.shape[1:]
|
|
256
267
|
d_interp2.shape = d_interp2.shape[1:]
|
|
257
|
-
maxdelay = int((self.rm/c).max())+2 + num
|
|
258
|
-
initialNumberOfBlocks = int(ceil(maxdelay/num))
|
|
259
|
-
bufferSize=initialNumberOfBlocks*num
|
|
260
|
-
self.buffer = zeros((bufferSize,numMics), dtype=float)
|
|
261
|
-
self.bufferIndex = bufferSize
|
|
268
|
+
maxdelay = int((self.rm / c).max()) + 2 + num # +2 because of interpolation
|
|
269
|
+
initialNumberOfBlocks = int(ceil(maxdelay / num))
|
|
270
|
+
bufferSize = initialNumberOfBlocks * num
|
|
271
|
+
self.buffer = zeros((bufferSize, numMics), dtype=float)
|
|
272
|
+
self.bufferIndex = bufferSize # indexing current time sample in buffer
|
|
262
273
|
fill_buffer_generator = self._fill_buffer(num)
|
|
263
274
|
for _ in range(initialNumberOfBlocks):
|
|
264
275
|
next(fill_buffer_generator)
|
|
@@ -266,495 +277,486 @@ class BeamformerTime( TimeInOut ):
|
|
|
266
277
|
# start processing
|
|
267
278
|
flag = True
|
|
268
279
|
while flag:
|
|
269
|
-
samplesleft = self.buffer.shape[0]-self.bufferIndex
|
|
270
|
-
if samplesleft-maxdelay <= 0:
|
|
271
|
-
num += samplesleft-maxdelay
|
|
272
|
-
maxdelay += samplesleft-maxdelay
|
|
273
|
-
n_index = arange(0,num+1)[:,newaxis]
|
|
274
|
-
flag=False
|
|
280
|
+
samplesleft = self.buffer.shape[0] - self.bufferIndex
|
|
281
|
+
if samplesleft - maxdelay <= 0:
|
|
282
|
+
num += samplesleft - maxdelay
|
|
283
|
+
maxdelay += samplesleft - maxdelay
|
|
284
|
+
n_index = arange(0, num + 1)[:, newaxis]
|
|
285
|
+
flag = False
|
|
275
286
|
# init step
|
|
276
|
-
p_res = array(
|
|
277
|
-
|
|
278
|
-
Phi, autopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
|
|
287
|
+
p_res = array(self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :])
|
|
288
|
+
Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
279
289
|
if 'Cleant' not in self.__class__.__name__:
|
|
280
290
|
if 'Sq' not in self.__class__.__name__:
|
|
281
291
|
yield Phi[:num]
|
|
282
|
-
elif self.r_diag:
|
|
283
|
-
yield (Phi[:num]**2 - autopow[:num]).clip(min=0)
|
|
292
|
+
elif self.r_diag:
|
|
293
|
+
yield (Phi[:num] ** 2 - autopow[:num]).clip(min=0)
|
|
284
294
|
else:
|
|
285
|
-
yield Phi[:num]**2
|
|
295
|
+
yield Phi[:num] ** 2
|
|
286
296
|
else:
|
|
287
297
|
Gamma = zeros(Phi.shape)
|
|
288
298
|
Gamma_autopow = zeros(Phi.shape)
|
|
289
299
|
J = 0
|
|
290
|
-
# deconvolution
|
|
291
|
-
while
|
|
300
|
+
# deconvolution
|
|
301
|
+
while self.n_iter > J:
|
|
292
302
|
# print(f"start clean iteration {J+1} of max {self.n_iter}")
|
|
293
|
-
if self.r_diag:
|
|
294
|
-
powPhi = (Phi[:num]**2-autopow).sum(0).clip(min=0)
|
|
295
|
-
else:
|
|
296
|
-
powPhi = (Phi[:num]**2).sum(0)
|
|
303
|
+
powPhi = (Phi[:num] ** 2 - autopow).sum(0).clip(min=0) if self.r_diag else (Phi[:num] ** 2).sum(0)
|
|
297
304
|
imax = argmax(powPhi)
|
|
298
305
|
t_float = d_interp2[imax] + d_index[imax] + n_index
|
|
299
306
|
t_ind = t_float.astype(int64)
|
|
300
|
-
for m in range(numMics):
|
|
301
|
-
p_res[t_ind[:num+1,m],m] -= self.damp*interp(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
307
|
+
for m in range(numMics):
|
|
308
|
+
p_res[t_ind[: num + 1, m], m] -= self.damp * interp(
|
|
309
|
+
t_ind[: num + 1, m],
|
|
310
|
+
t_float[:num, m],
|
|
311
|
+
Phi[:num, imax] * self.r0[imax] / self.rm[imax, m],
|
|
312
|
+
)
|
|
313
|
+
nextPhi, nextAutopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
306
314
|
if self.r_diag:
|
|
307
|
-
pownextPhi = (nextPhi[:num]**2-nextAutopow).sum(0).clip(min=0)
|
|
315
|
+
pownextPhi = (nextPhi[:num] ** 2 - nextAutopow).sum(0).clip(min=0)
|
|
308
316
|
else:
|
|
309
|
-
pownextPhi = (nextPhi[:num]**2).sum(0)
|
|
317
|
+
pownextPhi = (nextPhi[:num] ** 2).sum(0)
|
|
310
318
|
# print(f"total signal power: {powPhi.sum()}")
|
|
311
|
-
if pownextPhi.sum() < powPhi.sum():
|
|
312
|
-
Gamma[:num,imax] += self.damp*Phi[:num,imax]
|
|
313
|
-
Gamma_autopow[:num,imax] = autopow[:num,imax].copy()
|
|
314
|
-
Phi=nextPhi
|
|
315
|
-
autopow=nextAutopow
|
|
319
|
+
if pownextPhi.sum() < powPhi.sum(): # stopping criterion
|
|
320
|
+
Gamma[:num, imax] += self.damp * Phi[:num, imax]
|
|
321
|
+
Gamma_autopow[:num, imax] = autopow[:num, imax].copy()
|
|
322
|
+
Phi = nextPhi
|
|
323
|
+
autopow = nextAutopow
|
|
316
324
|
# print(f"clean max: {L_p((Gamma**2).sum(0)/num).max()} dB")
|
|
317
325
|
J += 1
|
|
318
326
|
else:
|
|
319
327
|
break
|
|
320
328
|
if 'Sq' not in self.__class__.__name__:
|
|
321
329
|
yield Gamma[:num]
|
|
322
|
-
elif self.r_diag:
|
|
323
|
-
yield Gamma[:num]**2 - (self.damp**2)*Gamma_autopow[:num]
|
|
330
|
+
elif self.r_diag:
|
|
331
|
+
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
324
332
|
else:
|
|
325
|
-
yield Gamma[:num]**2
|
|
333
|
+
yield Gamma[:num] ** 2
|
|
326
334
|
self.bufferIndex += num
|
|
327
|
-
|
|
335
|
+
with contextlib.suppress(StopIteration):
|
|
328
336
|
next(fill_buffer_generator)
|
|
329
|
-
except:
|
|
330
|
-
pass
|
|
331
337
|
|
|
332
|
-
def delay_and_sum(self,num,p_res,d_interp2,d_index,amp):
|
|
333
|
-
|
|
334
|
-
result = empty((num, self.grid.size), dtype=float)
|
|
335
|
-
autopow = empty((num, self.grid.size), dtype=float)
|
|
338
|
+
def delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
339
|
+
"""Standard delay-and-sum method."""
|
|
340
|
+
result = empty((num, self.grid.size), dtype=float) # output array
|
|
341
|
+
autopow = empty((num, self.grid.size), dtype=float) # output array
|
|
336
342
|
_delayandsum4(p_res, d_index, d_interp2, amp, result, autopow)
|
|
337
|
-
return result, autopow
|
|
338
|
-
|
|
343
|
+
return result, autopow
|
|
339
344
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
Provides a time domain beamformer with time-dependend
|
|
345
|
+
|
|
346
|
+
class BeamformerTimeSq(BeamformerTime):
|
|
347
|
+
"""Provides a time domain beamformer with time-dependend
|
|
343
348
|
power signal output and possible autopower removal
|
|
344
349
|
for a spatially fixed grid.
|
|
345
350
|
"""
|
|
346
|
-
|
|
351
|
+
|
|
347
352
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
348
|
-
r_diag = Bool(True,
|
|
349
|
-
desc="removal of diagonal")
|
|
353
|
+
r_diag = Bool(True, desc='removal of diagonal')
|
|
350
354
|
|
|
351
355
|
# internal identifier
|
|
352
|
-
digest = Property(
|
|
353
|
-
depends_on
|
|
354
|
-
|
|
355
|
-
)
|
|
356
|
+
digest = Property(
|
|
357
|
+
depends_on=['_steer_obj.digest', 'source.digest', 'r_diag', 'weights', '__class__'],
|
|
358
|
+
)
|
|
356
359
|
|
|
357
360
|
@cached_property
|
|
358
|
-
def _get_digest(
|
|
361
|
+
def _get_digest(self):
|
|
359
362
|
return digest(self)
|
|
360
|
-
|
|
361
363
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
Provides a basic time domain beamformer with time signal output
|
|
364
|
+
|
|
365
|
+
class BeamformerTimeTraj(BeamformerTime):
|
|
366
|
+
"""Provides a basic time domain beamformer with time signal output
|
|
365
367
|
for a grid moving along a trajectory.
|
|
366
368
|
"""
|
|
367
369
|
|
|
368
|
-
|
|
369
370
|
#: :class:`~acoular.trajectory.Trajectory` or derived object.
|
|
370
371
|
#: Start time is assumed to be the same as for the samples.
|
|
371
|
-
trajectory = Trait(Trajectory,
|
|
372
|
-
desc="trajectory of the grid center")
|
|
372
|
+
trajectory = Trait(Trajectory, desc='trajectory of the grid center')
|
|
373
373
|
|
|
374
374
|
#: Reference vector, perpendicular to the y-axis of moving grid.
|
|
375
|
-
rvec = CArray(
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0)), desc='reference vector')
|
|
376
|
+
|
|
378
377
|
#: Considering of convective amplification in beamforming formula.
|
|
379
|
-
conv_amp = Bool(False,
|
|
380
|
-
desc="determines if convective amplification of source is considered")
|
|
378
|
+
conv_amp = Bool(False, desc='determines if convective amplification of source is considered')
|
|
381
379
|
|
|
382
380
|
#: Floating point and integer precision
|
|
383
|
-
precision = Trait(64, [32,64],
|
|
384
|
-
desc="numeric precision")
|
|
381
|
+
precision = Trait(64, [32, 64], desc='numeric precision')
|
|
385
382
|
|
|
386
383
|
# internal identifier
|
|
387
|
-
digest = Property(
|
|
388
|
-
depends_on
|
|
389
|
-
|
|
390
|
-
|
|
384
|
+
digest = Property(
|
|
385
|
+
depends_on=[
|
|
386
|
+
'_steer_obj.digest',
|
|
387
|
+
'source.digest',
|
|
388
|
+
'weights',
|
|
389
|
+
'precision',
|
|
390
|
+
'rvec',
|
|
391
|
+
'conv_amp',
|
|
392
|
+
'trajectory.digest',
|
|
393
|
+
'__class__',
|
|
394
|
+
],
|
|
395
|
+
)
|
|
391
396
|
|
|
392
397
|
@cached_property
|
|
393
|
-
def _get_digest(
|
|
398
|
+
def _get_digest(self):
|
|
394
399
|
return digest(self)
|
|
395
|
-
|
|
400
|
+
|
|
396
401
|
def get_moving_gpos(self):
|
|
397
|
-
"""
|
|
398
|
-
|
|
399
|
-
"""
|
|
402
|
+
"""Python generator that yields the moving grid coordinates samplewise."""
|
|
403
|
+
|
|
400
404
|
def cross(a, b):
|
|
401
|
-
"""
|
|
402
|
-
|
|
405
|
+
"""Cross product for fast computation
|
|
406
|
+
because numpy.cross is ultra slow in this case.
|
|
403
407
|
"""
|
|
404
|
-
return array([a[1]*b[2] - a[2]*b[1],
|
|
405
|
-
a[2]*b[0] - a[0]*b[2],
|
|
406
|
-
a[0]*b[1] - a[1]*b[0]])
|
|
408
|
+
return array([a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]])
|
|
407
409
|
|
|
408
410
|
start_t = 0.0
|
|
409
411
|
gpos = self.grid.pos()
|
|
410
|
-
trajg = self.trajectory.traj(
|
|
411
|
-
trajg1 = self.trajectory.traj(
|
|
412
|
-
|
|
413
|
-
rflag = (self.rvec == 0).all() #flag translation vs. rotation
|
|
412
|
+
trajg = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq)
|
|
413
|
+
trajg1 = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq, der=1)
|
|
414
|
+
rflag = (self.rvec == 0).all() # flag translation vs. rotation
|
|
414
415
|
if rflag:
|
|
415
416
|
for g in trajg:
|
|
416
417
|
# grid is only translated, not rotated
|
|
417
418
|
tpos = gpos + array(g)[:, newaxis]
|
|
418
419
|
yield tpos
|
|
419
420
|
else:
|
|
420
|
-
for
|
|
421
|
+
for g, g1 in zip(trajg, trajg1):
|
|
421
422
|
# grid is both translated and rotated
|
|
422
|
-
loc = array(g)
|
|
423
|
-
dx = array(g1)
|
|
424
|
-
dy = cross(self.rvec, dx)
|
|
425
|
-
dz = cross(dx, dy)
|
|
426
|
-
RM = array((dx, dy, dz)).T
|
|
427
|
-
RM /= sqrt((RM*RM).sum(0))
|
|
428
|
-
tpos = dot(RM, gpos)+loc[:, newaxis]
|
|
429
|
-
# print(loc[:])
|
|
423
|
+
loc = array(g) # translation array([0., 0.4, 1.])
|
|
424
|
+
dx = array(g1) # direction vector (new x-axis)
|
|
425
|
+
dy = cross(self.rvec, dx) # new y-axis
|
|
426
|
+
dz = cross(dx, dy) # new z-axis
|
|
427
|
+
RM = array((dx, dy, dz)).T # rotation matrix
|
|
428
|
+
RM /= sqrt((RM * RM).sum(0)) # column normalized
|
|
429
|
+
tpos = dot(RM, gpos) + loc[:, newaxis] # rotation+translation
|
|
430
|
+
# print(loc[:])
|
|
430
431
|
yield tpos
|
|
431
432
|
|
|
432
|
-
def get_macostheta(self,g1,tpos,rm):
|
|
433
|
-
vvec = array(g1)
|
|
434
|
-
ma = norm(vvec)/self.steer.env.c
|
|
435
|
-
fdv = (vvec/sqrt((vvec*vvec).sum()))[:, newaxis]
|
|
433
|
+
def get_macostheta(self, g1, tpos, rm):
|
|
434
|
+
vvec = array(g1) # velocity vector
|
|
435
|
+
ma = norm(vvec) / self.steer.env.c # machnumber
|
|
436
|
+
fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
|
|
436
437
|
mpos = self.steer.mics.mpos[:, newaxis, :]
|
|
437
|
-
rmv = tpos[:, :, newaxis]-mpos
|
|
438
|
-
return (ma*sum(rmv.reshape((3, -1))*fdv, 0)
|
|
439
|
-
/rm.reshape(-1)).reshape(rm.shape)
|
|
438
|
+
rmv = tpos[:, :, newaxis] - mpos
|
|
439
|
+
return (ma * sum(rmv.reshape((3, -1)) * fdv, 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
440
440
|
|
|
441
|
-
def get_r0(
|
|
441
|
+
def get_r0(self, tpos):
|
|
442
442
|
if isscalar(self.steer.ref) and self.steer.ref > 0:
|
|
443
|
-
return self.steer.ref#full((self.steer.grid.size,), self.steer.ref)
|
|
444
|
-
|
|
445
|
-
return self.env._r(tpos)
|
|
443
|
+
return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
|
|
444
|
+
return self.env._r(tpos)
|
|
446
445
|
|
|
447
|
-
def increase_buffer(
|
|
448
|
-
ar = zeros((num,self.steer.mics.num_mics), dtype=self.buffer.dtype)
|
|
449
|
-
self.buffer = concatenate((ar,self.buffer), axis=0)
|
|
446
|
+
def increase_buffer(self, num):
|
|
447
|
+
ar = zeros((num, self.steer.mics.num_mics), dtype=self.buffer.dtype)
|
|
448
|
+
self.buffer = concatenate((ar, self.buffer), axis=0)
|
|
450
449
|
self.bufferIndex += num
|
|
451
450
|
|
|
452
|
-
def result(
|
|
453
|
-
"""
|
|
454
|
-
|
|
455
|
-
|
|
451
|
+
def result(self, num=2048):
|
|
452
|
+
"""Python generator that yields the deconvolved output block-wise.
|
|
453
|
+
|
|
456
454
|
Parameters
|
|
457
455
|
----------
|
|
458
456
|
num : integer, defaults to 2048
|
|
459
457
|
This parameter defines the size of the blocks to be yielded
|
|
460
458
|
(i.e. the number of samples per block).
|
|
461
|
-
|
|
459
|
+
|
|
462
460
|
Returns
|
|
463
461
|
-------
|
|
464
462
|
Samples in blocks of shape \
|
|
465
|
-
(num, :attr:`~BeamformerTime.numchannels`).
|
|
463
|
+
(num, :attr:`~BeamformerTime.numchannels`).
|
|
466
464
|
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
467
465
|
large (number of grid points).
|
|
468
466
|
The last block may be shorter than num. \
|
|
469
|
-
The output starts for signals that were emitted
|
|
467
|
+
The output starts for signals that were emitted
|
|
470
468
|
from the grid at `t=0`.
|
|
469
|
+
|
|
471
470
|
"""
|
|
472
471
|
# initialize values
|
|
473
|
-
if self.precision==64:
|
|
472
|
+
if self.precision == 64:
|
|
474
473
|
fdtype = float64
|
|
475
474
|
idtype = int64
|
|
476
475
|
else:
|
|
477
476
|
fdtype = float32
|
|
478
477
|
idtype = int32
|
|
479
478
|
w = self._get_weights()
|
|
480
|
-
c = self.steer.env.c/self.source.sample_freq
|
|
479
|
+
c = self.steer.env.c / self.source.sample_freq
|
|
481
480
|
numMics = self.steer.mics.num_mics
|
|
482
481
|
mpos = self.steer.mics.mpos.astype(fdtype)
|
|
483
482
|
m_index = arange(numMics, dtype=idtype)
|
|
484
|
-
n_index = arange(num,dtype=idtype)[:,newaxis]
|
|
485
|
-
blockrm = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
486
|
-
blockrmconv = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
487
|
-
amp = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
488
|
-
#delays = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
489
|
-
d_index = empty((num,self.grid.size,numMics),dtype=idtype)
|
|
490
|
-
d_interp2 = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
491
|
-
blockr0 = empty((num,self.grid.size),dtype=fdtype)
|
|
492
|
-
self.buffer = zeros((2*num,numMics), dtype=fdtype)
|
|
493
|
-
self.bufferIndex = self.buffer.shape[0]
|
|
494
|
-
movgpos = self.get_moving_gpos()
|
|
495
|
-
movgspeed = self.trajectory.traj(0.0, delta_t=1/self.source.sample_freq,
|
|
496
|
-
der=1)
|
|
483
|
+
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
484
|
+
blockrm = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
485
|
+
blockrmconv = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
486
|
+
amp = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
487
|
+
# delays = empty((num,self.grid.size,numMics),dtype=fdtype)
|
|
488
|
+
d_index = empty((num, self.grid.size, numMics), dtype=idtype)
|
|
489
|
+
d_interp2 = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
490
|
+
blockr0 = empty((num, self.grid.size), dtype=fdtype)
|
|
491
|
+
self.buffer = zeros((2 * num, numMics), dtype=fdtype)
|
|
492
|
+
self.bufferIndex = self.buffer.shape[0]
|
|
493
|
+
movgpos = self.get_moving_gpos() # create moving grid pos generator
|
|
494
|
+
movgspeed = self.trajectory.traj(0.0, delta_t=1 / self.source.sample_freq, der=1)
|
|
497
495
|
fill_buffer_generator = self._fill_buffer(num)
|
|
498
|
-
for
|
|
496
|
+
for _i in range(2):
|
|
499
497
|
next(fill_buffer_generator)
|
|
500
|
-
|
|
498
|
+
|
|
501
499
|
# preliminary implementation of different steering vectors
|
|
502
|
-
steer_func = {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
500
|
+
steer_func = {
|
|
501
|
+
'classic': _steer_I,
|
|
502
|
+
'inverse': _steer_II,
|
|
503
|
+
'true level': _steer_III,
|
|
504
|
+
'true location': _steer_IV,
|
|
505
|
+
}[self.steer.steer_type]
|
|
507
506
|
|
|
508
507
|
# start processing
|
|
509
508
|
flag = True
|
|
510
|
-
dflag = True
|
|
509
|
+
dflag = True # data is available
|
|
511
510
|
while flag:
|
|
512
511
|
for i in range(num):
|
|
513
512
|
tpos = next(movgpos).astype(fdtype)
|
|
514
|
-
rm = self.steer.env._r(
|
|
515
|
-
blockr0[i
|
|
516
|
-
blockrm[i
|
|
513
|
+
rm = self.steer.env._r(tpos, mpos) # .astype(fdtype)
|
|
514
|
+
blockr0[i, :] = self.get_r0(tpos)
|
|
515
|
+
blockrm[i, :, :] = rm
|
|
517
516
|
if self.conv_amp:
|
|
518
517
|
ht = next(movgspeed)
|
|
519
|
-
blockrmconv[i
|
|
518
|
+
blockrmconv[i, :, :] = rm * (1 - self.get_macostheta(ht, tpos, rm)) ** 2
|
|
520
519
|
if self.conv_amp:
|
|
521
520
|
steer_func(blockrmconv, blockr0, amp)
|
|
522
521
|
else:
|
|
523
522
|
steer_func(blockrm, blockr0, amp)
|
|
524
523
|
_delays(blockrm, c, d_interp2, d_index)
|
|
525
|
-
#_modf(delays, d_interp2, d_index)
|
|
526
|
-
maxdelay = (d_index.max((1,2)) + arange(0,num)).max()+2
|
|
524
|
+
# _modf(delays, d_interp2, d_index)
|
|
525
|
+
maxdelay = (d_index.max((1, 2)) + arange(0, num)).max() + 2 # + because of interpolation
|
|
527
526
|
# increase buffer size because of greater delays
|
|
528
527
|
while maxdelay > self.buffer.shape[0] and dflag:
|
|
529
528
|
self.increase_buffer(num)
|
|
530
529
|
try:
|
|
531
530
|
next(fill_buffer_generator)
|
|
532
|
-
except:
|
|
531
|
+
except StopIteration:
|
|
533
532
|
dflag = False
|
|
534
|
-
samplesleft = self.buffer.shape[0]-self.bufferIndex
|
|
533
|
+
samplesleft = self.buffer.shape[0] - self.bufferIndex
|
|
535
534
|
# last block may be shorter
|
|
536
|
-
if samplesleft-maxdelay <= 0:
|
|
537
|
-
num = sum((d_index.max((1,2))+1+arange(0,num)) < samplesleft)
|
|
538
|
-
n_index = arange(num,dtype=idtype)[:,newaxis]
|
|
539
|
-
flag=False
|
|
535
|
+
if samplesleft - maxdelay <= 0:
|
|
536
|
+
num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < samplesleft)
|
|
537
|
+
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
538
|
+
flag = False
|
|
540
539
|
# init step
|
|
541
|
-
p_res = self.buffer[self.bufferIndex:self.bufferIndex+maxdelay
|
|
542
|
-
Phi, autopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
|
|
540
|
+
p_res = self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :].copy()
|
|
541
|
+
Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
543
542
|
if 'Cleant' not in self.__class__.__name__:
|
|
544
543
|
if 'Sq' not in self.__class__.__name__:
|
|
545
544
|
yield Phi[:num]
|
|
546
|
-
elif self.r_diag:
|
|
547
|
-
yield (Phi[:num]**2 - autopow[:num]).clip(min=0)
|
|
545
|
+
elif self.r_diag:
|
|
546
|
+
yield (Phi[:num] ** 2 - autopow[:num]).clip(min=0)
|
|
548
547
|
else:
|
|
549
|
-
yield Phi[:num]**2
|
|
548
|
+
yield Phi[:num] ** 2
|
|
550
549
|
else:
|
|
551
550
|
# choose correct distance
|
|
552
|
-
if self.conv_amp
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
blockrm1 = blockrm
|
|
556
|
-
Gamma = zeros(Phi.shape,dtype=fdtype)
|
|
557
|
-
Gamma_autopow = zeros(Phi.shape,dtype=fdtype)
|
|
551
|
+
blockrm1 = blockrmconv if self.conv_amp else blockrm
|
|
552
|
+
Gamma = zeros(Phi.shape, dtype=fdtype)
|
|
553
|
+
Gamma_autopow = zeros(Phi.shape, dtype=fdtype)
|
|
558
554
|
J = 0
|
|
559
|
-
t_ind = arange(p_res.shape[0],dtype=idtype)
|
|
560
|
-
# deconvolution
|
|
561
|
-
while
|
|
555
|
+
t_ind = arange(p_res.shape[0], dtype=idtype)
|
|
556
|
+
# deconvolution
|
|
557
|
+
while self.n_iter > J:
|
|
562
558
|
# print(f"start clean iteration {J+1} of max {self.n_iter}")
|
|
563
559
|
if self.r_diag:
|
|
564
|
-
powPhi = (Phi[:num]*Phi[:num]-autopow).sum(0).clip(min=0)
|
|
560
|
+
powPhi = (Phi[:num] * Phi[:num] - autopow).sum(0).clip(min=0)
|
|
565
561
|
else:
|
|
566
|
-
powPhi = (Phi[:num]*Phi[:num]).sum(0)
|
|
562
|
+
powPhi = (Phi[:num] * Phi[:num]).sum(0)
|
|
567
563
|
# find index of max power focus point
|
|
568
564
|
imax = argmax(powPhi)
|
|
569
565
|
# find backward delays
|
|
570
|
-
t_float = (d_interp2[:num,imax,m_index] +
|
|
571
|
-
d_index[:num,imax,m_index] + \
|
|
572
|
-
n_index).astype(fdtype)
|
|
566
|
+
t_float = (d_interp2[:num, imax, m_index] + d_index[:num, imax, m_index] + n_index).astype(fdtype)
|
|
573
567
|
# determine max/min delays in sample units
|
|
574
568
|
# + 2 because we do not want to extrapolate behind the last sample
|
|
575
|
-
ind_max = t_float.max(0).astype(idtype)+2
|
|
569
|
+
ind_max = t_float.max(0).astype(idtype) + 2
|
|
576
570
|
ind_min = t_float.min(0).astype(idtype)
|
|
577
571
|
# store time history at max power focus point
|
|
578
|
-
h = Phi[:num,imax]*blockr0[:num,imax]
|
|
572
|
+
h = Phi[:num, imax] * blockr0[:num, imax]
|
|
579
573
|
for m in range(numMics):
|
|
580
574
|
# subtract interpolated time history from microphone signals
|
|
581
|
-
p_res[ind_min[m]:ind_max[m],m] -= self.damp*interp(
|
|
582
|
-
t_ind[ind_min[m]:ind_max[m]],
|
|
583
|
-
t_float[:num,m],
|
|
584
|
-
h/blockrm1[:num,imax,m],
|
|
585
|
-
|
|
586
|
-
nextPhi, nextAutopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
|
|
575
|
+
p_res[ind_min[m] : ind_max[m], m] -= self.damp * interp(
|
|
576
|
+
t_ind[ind_min[m] : ind_max[m]],
|
|
577
|
+
t_float[:num, m],
|
|
578
|
+
h / blockrm1[:num, imax, m],
|
|
579
|
+
)
|
|
580
|
+
nextPhi, nextAutopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
587
581
|
if self.r_diag:
|
|
588
|
-
pownextPhi = (nextPhi[:num]*nextPhi[:num]-nextAutopow).sum(0).clip(min=0)
|
|
582
|
+
pownextPhi = (nextPhi[:num] * nextPhi[:num] - nextAutopow).sum(0).clip(min=0)
|
|
589
583
|
else:
|
|
590
|
-
pownextPhi = (nextPhi[:num]*nextPhi[:num]).sum(0)
|
|
584
|
+
pownextPhi = (nextPhi[:num] * nextPhi[:num]).sum(0)
|
|
591
585
|
# print(f"total signal power: {powPhi.sum()}")
|
|
592
|
-
if pownextPhi.sum() < powPhi.sum():
|
|
593
|
-
Gamma[:num,imax] += self.damp*Phi[:num,imax]
|
|
594
|
-
Gamma_autopow[:num,imax] = autopow[:num,imax].copy()
|
|
595
|
-
Phi=nextPhi
|
|
596
|
-
autopow=nextAutopow
|
|
586
|
+
if pownextPhi.sum() < powPhi.sum(): # stopping criterion
|
|
587
|
+
Gamma[:num, imax] += self.damp * Phi[:num, imax]
|
|
588
|
+
Gamma_autopow[:num, imax] = autopow[:num, imax].copy()
|
|
589
|
+
Phi = nextPhi
|
|
590
|
+
autopow = nextAutopow
|
|
597
591
|
# print(f"clean max: {L_p((Gamma**2).sum(0)/num).max()} dB")
|
|
598
592
|
J += 1
|
|
599
593
|
else:
|
|
600
594
|
break
|
|
601
595
|
if 'Sq' not in self.__class__.__name__:
|
|
602
596
|
yield Gamma[:num]
|
|
603
|
-
elif self.r_diag:
|
|
604
|
-
yield Gamma[:num]**2 - (self.damp**2)*Gamma_autopow[:num]
|
|
597
|
+
elif self.r_diag:
|
|
598
|
+
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
605
599
|
else:
|
|
606
|
-
yield Gamma[:num]**2
|
|
600
|
+
yield Gamma[:num] ** 2
|
|
607
601
|
self.bufferIndex += num
|
|
608
602
|
try:
|
|
609
603
|
next(fill_buffer_generator)
|
|
610
|
-
except:
|
|
604
|
+
except StopIteration:
|
|
611
605
|
dflag = False
|
|
612
|
-
pass
|
|
613
606
|
|
|
614
|
-
def delay_and_sum(self,num,p_res,d_interp2,d_index,amp):
|
|
615
|
-
|
|
616
|
-
if self.precision==64
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
fdtype = float32
|
|
620
|
-
result = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
621
|
-
autopow = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
607
|
+
def delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
608
|
+
"""Standard delay-and-sum method."""
|
|
609
|
+
fdtype = float64 if self.precision == 64 else float32
|
|
610
|
+
result = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
611
|
+
autopow = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
622
612
|
_delayandsum5(p_res, d_index, d_interp2, amp, result, autopow)
|
|
623
|
-
return result, autopow
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
class BeamformerTimeSqTraj(
|
|
627
|
-
"""
|
|
628
|
-
Provides a time domain beamformer with time-dependent
|
|
613
|
+
return result, autopow
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
617
|
+
"""Provides a time domain beamformer with time-dependent
|
|
629
618
|
power signal output and possible autopower removal
|
|
630
619
|
for a grid moving along a trajectory.
|
|
631
620
|
"""
|
|
632
|
-
|
|
621
|
+
|
|
633
622
|
# internal identifier
|
|
634
|
-
digest = Property(
|
|
635
|
-
depends_on
|
|
636
|
-
|
|
637
|
-
|
|
623
|
+
digest = Property(
|
|
624
|
+
depends_on=[
|
|
625
|
+
'_steer_obj.digest',
|
|
626
|
+
'source.digest',
|
|
627
|
+
'r_diag',
|
|
628
|
+
'weights',
|
|
629
|
+
'precision',
|
|
630
|
+
'rvec',
|
|
631
|
+
'conv_amp',
|
|
632
|
+
'trajectory.digest',
|
|
633
|
+
'__class__',
|
|
634
|
+
],
|
|
635
|
+
)
|
|
638
636
|
|
|
639
637
|
@cached_property
|
|
640
|
-
def _get_digest(
|
|
638
|
+
def _get_digest(self):
|
|
641
639
|
return digest(self)
|
|
642
|
-
|
|
643
640
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
|
|
647
|
-
|
|
648
|
-
An implementation of the CLEAN method in time domain. This class can only
|
|
641
|
+
|
|
642
|
+
class BeamformerCleant(BeamformerTime):
|
|
643
|
+
"""CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
|
|
644
|
+
|
|
645
|
+
An implementation of the CLEAN method in time domain. This class can only
|
|
649
646
|
be used for static sources.
|
|
650
647
|
"""
|
|
651
648
|
|
|
652
649
|
#: Boolean flag, always False
|
|
653
|
-
r_diag = Enum(False,
|
|
654
|
-
desc="False, as we do not remove autopower in this beamformer")
|
|
650
|
+
r_diag = Enum(False, desc='False, as we do not remove autopower in this beamformer')
|
|
655
651
|
|
|
656
|
-
#: iteration damping factor also referred as loop gain in Cousson et al.
|
|
652
|
+
#: iteration damping factor also referred as loop gain in Cousson et al.
|
|
657
653
|
#: defaults to 0.6
|
|
658
|
-
damp = Range(0.01, 1.0, 0.6,
|
|
659
|
-
desc="damping factor (loop gain)")
|
|
654
|
+
damp = Range(0.01, 1.0, 0.6, desc='damping factor (loop gain)')
|
|
660
655
|
|
|
661
656
|
#: max number of iterations
|
|
662
|
-
n_iter = Int(100,
|
|
663
|
-
|
|
664
|
-
|
|
657
|
+
n_iter = Int(100, desc='maximum number of iterations')
|
|
658
|
+
|
|
665
659
|
# internal identifier
|
|
666
|
-
digest = Property(
|
|
667
|
-
depends_on
|
|
668
|
-
|
|
669
|
-
)
|
|
660
|
+
digest = Property(
|
|
661
|
+
depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__', 'damp', 'n_iter'],
|
|
662
|
+
)
|
|
670
663
|
|
|
671
664
|
@cached_property
|
|
672
|
-
def _get_digest(
|
|
665
|
+
def _get_digest(self):
|
|
673
666
|
return digest(self)
|
|
674
667
|
|
|
675
668
|
|
|
676
|
-
class BeamformerCleantSq(
|
|
677
|
-
"""
|
|
678
|
-
CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
|
|
669
|
+
class BeamformerCleantSq(BeamformerCleant):
|
|
670
|
+
"""CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
|
|
679
671
|
with optional removal of autocorrelation.
|
|
680
|
-
|
|
681
|
-
An implementation of the CLEAN method in time domain. This class can only
|
|
672
|
+
|
|
673
|
+
An implementation of the CLEAN method in time domain. This class can only
|
|
682
674
|
be used for static sources.
|
|
683
675
|
"""
|
|
684
676
|
|
|
685
677
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
686
|
-
r_diag = Bool(True,
|
|
687
|
-
desc="removal of diagonal")
|
|
678
|
+
r_diag = Bool(True, desc='removal of diagonal')
|
|
688
679
|
|
|
689
680
|
# internal identifier
|
|
690
|
-
digest = Property(
|
|
691
|
-
depends_on
|
|
692
|
-
|
|
693
|
-
)
|
|
681
|
+
digest = Property(
|
|
682
|
+
depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__', 'damp', 'n_iter', 'r_diag'],
|
|
683
|
+
)
|
|
694
684
|
|
|
695
685
|
@cached_property
|
|
696
|
-
def _get_digest(
|
|
686
|
+
def _get_digest(self):
|
|
697
687
|
return digest(self)
|
|
698
|
-
|
|
699
|
-
|
|
700
688
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
|
|
704
|
-
|
|
689
|
+
|
|
690
|
+
class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
691
|
+
"""CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
|
|
692
|
+
|
|
705
693
|
An implementation of the CLEAN method in time domain for moving sources
|
|
706
|
-
with known trajectory.
|
|
694
|
+
with known trajectory.
|
|
707
695
|
"""
|
|
696
|
+
|
|
708
697
|
#: Floating point and integer precision
|
|
709
|
-
precision = Trait(32, [32,64],
|
|
710
|
-
desc="numeric precision")
|
|
698
|
+
precision = Trait(32, [32, 64], desc='numeric precision')
|
|
711
699
|
|
|
712
700
|
# internal identifier
|
|
713
|
-
digest = Property(
|
|
714
|
-
depends_on
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
701
|
+
digest = Property(
|
|
702
|
+
depends_on=[
|
|
703
|
+
'_steer_obj.digest',
|
|
704
|
+
'source.digest',
|
|
705
|
+
'weights',
|
|
706
|
+
'precision',
|
|
707
|
+
'__class__',
|
|
708
|
+
'damp',
|
|
709
|
+
'n_iter',
|
|
710
|
+
'rvec',
|
|
711
|
+
'conv_amp',
|
|
712
|
+
'trajectory.digest',
|
|
713
|
+
],
|
|
714
|
+
)
|
|
718
715
|
|
|
719
716
|
@cached_property
|
|
720
|
-
def _get_digest(
|
|
717
|
+
def _get_digest(self):
|
|
721
718
|
return digest(self)
|
|
722
|
-
|
|
723
719
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
|
|
720
|
+
|
|
721
|
+
class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
722
|
+
"""CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
|
|
727
723
|
with optional removal of autocorrelation.
|
|
728
|
-
|
|
724
|
+
|
|
729
725
|
An implementation of the CLEAN method in time domain for moving sources
|
|
730
|
-
with known trajectory.
|
|
726
|
+
with known trajectory.
|
|
731
727
|
"""
|
|
732
728
|
|
|
733
729
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
734
|
-
r_diag = Bool(True,
|
|
735
|
-
desc="removal of diagonal")
|
|
730
|
+
r_diag = Bool(True, desc='removal of diagonal')
|
|
736
731
|
|
|
737
732
|
# internal identifier
|
|
738
|
-
digest = Property(
|
|
739
|
-
depends_on
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
733
|
+
digest = Property(
|
|
734
|
+
depends_on=[
|
|
735
|
+
'_steer_obj.digest',
|
|
736
|
+
'source.digest',
|
|
737
|
+
'weights',
|
|
738
|
+
'precision',
|
|
739
|
+
'__class__',
|
|
740
|
+
'damp',
|
|
741
|
+
'n_iter',
|
|
742
|
+
'rvec',
|
|
743
|
+
'conv_amp',
|
|
744
|
+
'trajectory.digest',
|
|
745
|
+
'r_diag',
|
|
746
|
+
],
|
|
747
|
+
)
|
|
743
748
|
|
|
744
749
|
@cached_property
|
|
745
|
-
def _get_digest(
|
|
750
|
+
def _get_digest(self):
|
|
746
751
|
return digest(self)
|
|
747
|
-
|
|
748
752
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
Provides an Integrator in the time domain.
|
|
752
|
-
"""
|
|
753
|
+
|
|
754
|
+
class IntegratorSectorTime(TimeInOut):
|
|
755
|
+
"""Provides an Integrator in the time domain."""
|
|
753
756
|
|
|
754
757
|
#: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
|
|
755
|
-
grid = Trait(RectGrid,
|
|
756
|
-
|
|
757
|
-
|
|
758
|
+
grid = Trait(RectGrid, desc='beamforming grid')
|
|
759
|
+
|
|
758
760
|
#: List of sectors in grid
|
|
759
761
|
sectors = List()
|
|
760
762
|
|
|
@@ -762,51 +764,49 @@ class IntegratorSectorTime( TimeInOut ):
|
|
|
762
764
|
clip = Float(-350.0)
|
|
763
765
|
|
|
764
766
|
#: Number of channels in output (= number of sectors).
|
|
765
|
-
numchannels = Property(
|
|
767
|
+
numchannels = Property(depends_on=['sectors'])
|
|
766
768
|
|
|
767
769
|
# internal identifier
|
|
768
|
-
digest = Property(
|
|
769
|
-
depends_on
|
|
770
|
-
|
|
771
|
-
)
|
|
770
|
+
digest = Property(
|
|
771
|
+
depends_on=['sectors', 'clip', 'grid.digest', 'source.digest', '__class__'],
|
|
772
|
+
)
|
|
772
773
|
|
|
773
774
|
@cached_property
|
|
774
|
-
def _get_digest(
|
|
775
|
+
def _get_digest(self):
|
|
775
776
|
return digest(self)
|
|
776
|
-
|
|
777
|
+
|
|
777
778
|
@cached_property
|
|
778
|
-
def _get_numchannels
|
|
779
|
+
def _get_numchannels(self):
|
|
779
780
|
return len(self.sectors)
|
|
780
781
|
|
|
781
|
-
def result(
|
|
782
|
-
"""
|
|
783
|
-
Python generator that yields the source output integrated over the given
|
|
782
|
+
def result(self, num=1):
|
|
783
|
+
"""Python generator that yields the source output integrated over the given
|
|
784
784
|
sectors, block-wise.
|
|
785
|
-
|
|
785
|
+
|
|
786
786
|
Parameters
|
|
787
787
|
----------
|
|
788
788
|
num : integer, defaults to 1
|
|
789
789
|
This parameter defines the size of the blocks to be yielded
|
|
790
790
|
(i.e. the number of samples per block).
|
|
791
|
-
|
|
791
|
+
|
|
792
792
|
Returns
|
|
793
793
|
-------
|
|
794
|
-
Samples in blocks of shape (num, :attr:`numchannels`).
|
|
794
|
+
Samples in blocks of shape (num, :attr:`numchannels`).
|
|
795
795
|
:attr:`numchannels` is the number of sectors.
|
|
796
796
|
The last block may be shorter than num.
|
|
797
|
+
|
|
797
798
|
"""
|
|
798
799
|
inds = [self.grid.indices(*sector) for sector in self.sectors]
|
|
799
800
|
gshape = self.grid.shape
|
|
800
|
-
o = empty((num, self.numchannels), dtype=float)
|
|
801
|
+
o = empty((num, self.numchannels), dtype=float) # output array
|
|
801
802
|
for r in self.source.result(num):
|
|
802
803
|
ns = r.shape[0]
|
|
803
804
|
mapshape = (ns,) + gshape
|
|
804
805
|
rmax = r.max()
|
|
805
|
-
rmin = rmax * 10**(self.clip/10.0)
|
|
806
|
-
r = where(r>rmin, r, 0.0)
|
|
807
|
-
i
|
|
808
|
-
|
|
809
|
-
h = r[:].reshape(mapshape)[ (s_[:],) + ind ]
|
|
806
|
+
rmin = rmax * 10 ** (self.clip / 10.0)
|
|
807
|
+
r = where(r > rmin, r, 0.0)
|
|
808
|
+
for i, ind in enumerate(inds):
|
|
809
|
+
h = r[:].reshape(mapshape)[(s_[:],) + ind]
|
|
810
810
|
o[:ns, i] = h.reshape(h.shape[0], -1).sum(axis=1)
|
|
811
811
|
i += 1
|
|
812
|
-
yield o[:ns]
|
|
812
|
+
yield o[:ns]
|