acoular 24.7__py3-none-any.whl → 25.1__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 +21 -9
- acoular/aiaa/__init__.py +12 -0
- acoular/{tools → aiaa}/aiaa.py +26 -31
- acoular/base.py +332 -0
- acoular/calib.py +129 -34
- acoular/configuration.py +13 -11
- acoular/demo/__init__.py +1 -0
- acoular/demo/acoular_demo.py +30 -17
- acoular/deprecation.py +85 -0
- acoular/environments.py +38 -24
- acoular/fastFuncs.py +90 -84
- acoular/fbeamform.py +342 -387
- acoular/fprocess.py +376 -0
- acoular/grids.py +122 -150
- acoular/h5cache.py +29 -40
- acoular/h5files.py +2 -6
- acoular/microphones.py +50 -59
- acoular/process.py +771 -0
- acoular/sdinput.py +35 -21
- acoular/signals.py +120 -113
- acoular/sources.py +208 -234
- acoular/spectra.py +59 -254
- acoular/tbeamform.py +280 -280
- acoular/tfastfuncs.py +21 -21
- acoular/tools/__init__.py +3 -7
- acoular/tools/helpers.py +218 -4
- acoular/tools/metrics.py +5 -5
- acoular/tools/utils.py +116 -0
- acoular/tprocess.py +416 -741
- acoular/traitsviews.py +15 -13
- acoular/trajectory.py +7 -10
- acoular/version.py +2 -2
- {acoular-24.7.dist-info → acoular-25.1.dist-info}/METADATA +63 -21
- acoular-25.1.dist-info/RECORD +56 -0
- {acoular-24.7.dist-info → acoular-25.1.dist-info}/WHEEL +1 -1
- acoular-24.7.dist-info/RECORD +0 -50
- {acoular-24.7.dist-info → acoular-25.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.7.dist-info → acoular-25.1.dist-info}/licenses/LICENSE +0 -0
acoular/tbeamform.py
CHANGED
|
@@ -18,15 +18,12 @@
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
# imports from other packages
|
|
21
|
-
import contextlib
|
|
22
|
-
from warnings import warn
|
|
23
21
|
|
|
24
22
|
from numpy import (
|
|
25
23
|
arange,
|
|
26
24
|
argmax,
|
|
27
25
|
array,
|
|
28
26
|
ceil,
|
|
29
|
-
concatenate,
|
|
30
27
|
dot,
|
|
31
28
|
empty,
|
|
32
29
|
float32,
|
|
@@ -40,22 +37,22 @@ from numpy import (
|
|
|
40
37
|
r_,
|
|
41
38
|
s_,
|
|
42
39
|
sqrt,
|
|
43
|
-
sum,
|
|
40
|
+
sum, # noqa: A004
|
|
44
41
|
unique,
|
|
45
42
|
where,
|
|
46
43
|
zeros,
|
|
47
44
|
)
|
|
48
|
-
from
|
|
49
|
-
from traits.api import Bool, CArray,
|
|
50
|
-
from traits.trait_errors import TraitError
|
|
45
|
+
from scipy.linalg import norm
|
|
46
|
+
from traits.api import Bool, CArray, Enum, Float, Instance, Int, List, Map, Property, Range, cached_property
|
|
51
47
|
|
|
48
|
+
from .base import SamplesGenerator, TimeOut
|
|
52
49
|
from .fbeamform import SteeringVector
|
|
53
50
|
from .grids import RectGrid
|
|
54
51
|
|
|
55
52
|
# acoular imports
|
|
56
53
|
from .internal import digest
|
|
57
|
-
from .
|
|
58
|
-
from .
|
|
54
|
+
from .process import SamplesBuffer
|
|
55
|
+
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays
|
|
59
56
|
from .trajectory import Trajectory
|
|
60
57
|
|
|
61
58
|
|
|
@@ -75,9 +72,8 @@ def const_power_weight(bf):
|
|
|
75
72
|
-------
|
|
76
73
|
array of floats
|
|
77
74
|
The weight factors.
|
|
78
|
-
|
|
79
75
|
"""
|
|
80
|
-
r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.
|
|
76
|
+
r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.pos) # distances to center
|
|
81
77
|
# round the relative distances to one decimal place
|
|
82
78
|
r = (r / r.max()).round(decimals=1)
|
|
83
79
|
ru, ind = unique(r, return_inverse=True)
|
|
@@ -93,199 +89,94 @@ def const_power_weight(bf):
|
|
|
93
89
|
possible_weights = {'none': None, 'power': const_power_weight}
|
|
94
90
|
|
|
95
91
|
|
|
96
|
-
class BeamformerTime(
|
|
92
|
+
class BeamformerTime(TimeOut):
|
|
97
93
|
"""Provides a basic time domain beamformer with time signal output
|
|
98
94
|
for a spatially fixed grid.
|
|
99
95
|
"""
|
|
100
96
|
|
|
97
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
98
|
+
source = Instance(SamplesGenerator)
|
|
99
|
+
|
|
101
100
|
# Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
|
|
102
101
|
# that contains information about the steering vector. This is a private trait.
|
|
103
102
|
# Do not set this directly, use `steer` trait instead.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
#: :class:`~acoular.fbeamform.SteeringVector` or derived object.
|
|
107
|
-
#: Defaults to :class:`~acoular.fbeamform.SteeringVector` object.
|
|
108
|
-
steer = Property(desc='steering vector object')
|
|
109
|
-
|
|
110
|
-
def _get_steer(self):
|
|
111
|
-
return self._steer_obj
|
|
112
|
-
|
|
113
|
-
def _set_steer(self, steer):
|
|
114
|
-
if type(steer) == SteeringVector:
|
|
115
|
-
# This condition may be replaced at a later time by: isinstance(steer, SteeringVector): -- (derived classes allowed)
|
|
116
|
-
self._steer_obj = steer
|
|
117
|
-
elif steer in ('true level', 'true location', 'classic', 'inverse'):
|
|
118
|
-
# Type of steering vectors, see also :ref:`Sarradj, 2012<Sarradj2012>`.
|
|
119
|
-
warn(
|
|
120
|
-
"Deprecated use of 'steer' trait. Please use object of class 'SteeringVector' in the future.",
|
|
121
|
-
Warning,
|
|
122
|
-
stacklevel=2,
|
|
123
|
-
)
|
|
124
|
-
self._steer_obj.steer_type = steer
|
|
125
|
-
else:
|
|
126
|
-
raise (TraitError(args=self, name='steer', info='SteeringVector', value=steer))
|
|
127
|
-
|
|
128
|
-
# --- List of backwards compatibility traits and their setters/getters -----------
|
|
129
|
-
|
|
130
|
-
# :class:`~acoular.environments.Environment` or derived object.
|
|
131
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
132
|
-
# Now governed by :attr:`steer` trait.
|
|
133
|
-
env = Property()
|
|
134
|
-
|
|
135
|
-
def _get_env(self):
|
|
136
|
-
return self._steer_obj.env
|
|
137
|
-
|
|
138
|
-
def _set_env(self, env):
|
|
139
|
-
warn("Deprecated use of 'env' trait. ", Warning, stacklevel=2)
|
|
140
|
-
self._steer_obj.env = env
|
|
141
|
-
|
|
142
|
-
# The speed of sound.
|
|
143
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
144
|
-
# Now governed by :attr:`steer` trait.
|
|
145
|
-
c = Property()
|
|
146
|
-
|
|
147
|
-
def _get_c(self):
|
|
148
|
-
return self._steer_obj.env.c
|
|
149
|
-
|
|
150
|
-
def _set_c(self, c):
|
|
151
|
-
warn("Deprecated use of 'c' trait. ", Warning, stacklevel=2)
|
|
152
|
-
self._steer_obj.env.c = c
|
|
153
|
-
|
|
154
|
-
# :class:`~acoular.grids.Grid`-derived object that provides the grid locations.
|
|
155
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
156
|
-
# Now governed by :attr:`steer` trait.
|
|
157
|
-
grid = Property()
|
|
158
|
-
|
|
159
|
-
def _get_grid(self):
|
|
160
|
-
return self._steer_obj.grid
|
|
161
|
-
|
|
162
|
-
def _set_grid(self, grid):
|
|
163
|
-
warn("Deprecated use of 'grid' trait. ", Warning, stacklevel=2)
|
|
164
|
-
self._steer_obj.grid = grid
|
|
165
|
-
|
|
166
|
-
# :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
|
|
167
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
168
|
-
# Now governed by :attr:`steer` trait
|
|
169
|
-
mpos = Property()
|
|
170
|
-
|
|
171
|
-
def _get_mpos(self):
|
|
172
|
-
return self._steer_obj.mics
|
|
173
|
-
|
|
174
|
-
def _set_mpos(self, mpos):
|
|
175
|
-
warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
|
|
176
|
-
self._steer_obj.mics = mpos
|
|
177
|
-
|
|
178
|
-
# Sound travel distances from microphone array center to grid points (r0)
|
|
179
|
-
# and all array mics to grid points (rm). Readonly.
|
|
180
|
-
# Deprecated! Only kept for backwards compatibility.
|
|
181
|
-
# Now governed by :attr:`steer` trait
|
|
182
|
-
r0 = Property()
|
|
183
|
-
|
|
184
|
-
def _get_r0(self):
|
|
185
|
-
return self._steer_obj.r0
|
|
186
|
-
|
|
187
|
-
rm = Property()
|
|
188
|
-
|
|
189
|
-
def _get_rm(self):
|
|
190
|
-
return self._steer_obj.rm
|
|
191
|
-
|
|
192
|
-
# --- End of backwards compatibility traits --------------------------------------
|
|
103
|
+
steer = Instance(SteeringVector, args=())
|
|
193
104
|
|
|
194
105
|
#: Number of channels in output (=number of grid points).
|
|
195
|
-
|
|
106
|
+
num_channels = Property()
|
|
196
107
|
|
|
197
108
|
#: Spatial weighting function.
|
|
198
|
-
weights =
|
|
109
|
+
weights = Map(possible_weights, default_value='none', desc='spatial weighting function')
|
|
199
110
|
# (from timedomain.possible_weights)
|
|
200
111
|
|
|
201
|
-
# buffer with microphone time signals used for processing. Internal use
|
|
202
|
-
buffer = CArray(desc='buffer containing microphone signals')
|
|
203
|
-
|
|
204
|
-
# index indicating position of current processing sample. Internal use.
|
|
205
|
-
bufferIndex = Int(desc='index indicating position in buffer') # noqa: N815
|
|
206
|
-
|
|
207
112
|
# internal identifier
|
|
208
113
|
digest = Property(
|
|
209
|
-
depends_on=['
|
|
114
|
+
depends_on=['steer.digest', 'source.digest', 'weights'],
|
|
210
115
|
)
|
|
211
116
|
|
|
212
|
-
|
|
117
|
+
def _get_num_channels(self):
|
|
118
|
+
return self.steer.grid.size
|
|
119
|
+
|
|
213
120
|
def _get_digest(self):
|
|
214
121
|
return digest(self)
|
|
215
122
|
|
|
216
123
|
def _get_weights(self):
|
|
217
124
|
return self.weights_(self)[newaxis] if self.weights_ else 1.0
|
|
218
125
|
|
|
219
|
-
def _fill_buffer(self, num):
|
|
220
|
-
"""Generator that fills the signal buffer."""
|
|
221
|
-
weights = self._get_weights()
|
|
222
|
-
for block in self.source.result(num):
|
|
223
|
-
block *= weights
|
|
224
|
-
ns = block.shape[0]
|
|
225
|
-
bufferSize = self.buffer.shape[0]
|
|
226
|
-
self.buffer[0 : (bufferSize - ns)] = self.buffer[-(bufferSize - ns) :]
|
|
227
|
-
self.buffer[-ns:, :] = block
|
|
228
|
-
self.bufferIndex -= ns
|
|
229
|
-
yield
|
|
230
|
-
|
|
231
126
|
def result(self, num=2048):
|
|
232
|
-
"""Python generator that yields the
|
|
233
|
-
|
|
127
|
+
"""Python generator that yields the time-domain beamformer output.
|
|
128
|
+
|
|
129
|
+
The output time signal starts for source signals that were emitted from
|
|
130
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
234
131
|
|
|
235
132
|
Parameters
|
|
236
133
|
----------
|
|
237
|
-
num :
|
|
134
|
+
num : int
|
|
238
135
|
This parameter defines the size of the blocks to be yielded
|
|
239
|
-
(i.e. the number of samples per block).
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
The output starts for signals that were emitted
|
|
249
|
-
from the grid at `t=0`.
|
|
250
|
-
|
|
136
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
137
|
+
|
|
138
|
+
Yields
|
|
139
|
+
------
|
|
140
|
+
numpy.ndarray
|
|
141
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
142
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
143
|
+
large (number of grid points).
|
|
144
|
+
The last block returned by the generator may be shorter than num.
|
|
251
145
|
"""
|
|
252
146
|
# initialize values
|
|
147
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
253
148
|
fdtype = float64
|
|
254
149
|
idtype = int64
|
|
255
|
-
|
|
150
|
+
num_mics = self.steer.mics.num_mics
|
|
256
151
|
n_index = arange(0, num + 1)[:, newaxis]
|
|
257
152
|
c = self.steer.env.c / self.source.sample_freq
|
|
258
|
-
amp = empty((1, self.grid.size,
|
|
259
|
-
# delays = empty((1,self.grid.size,
|
|
260
|
-
d_index = empty((1, self.grid.size,
|
|
261
|
-
d_interp2 = empty((1, self.grid.size,
|
|
262
|
-
|
|
263
|
-
_delays(self.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
153
|
+
amp = empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
154
|
+
# delays = empty((1,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
155
|
+
d_index = empty((1, self.steer.grid.size, num_mics), dtype=idtype)
|
|
156
|
+
d_interp2 = empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
157
|
+
steer_func(self.steer.rm[newaxis, :, :], self.steer.r0[newaxis, :], amp)
|
|
158
|
+
_delays(self.steer.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
264
159
|
amp.shape = amp.shape[1:]
|
|
265
160
|
# delays.shape = delays.shape[1:]
|
|
266
161
|
d_index.shape = d_index.shape[1:]
|
|
267
162
|
d_interp2.shape = d_interp2.shape[1:]
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
bufferSize = initialNumberOfBlocks * num
|
|
271
|
-
self.buffer = zeros((bufferSize, numMics), dtype=float)
|
|
272
|
-
self.bufferIndex = bufferSize # indexing current time sample in buffer
|
|
273
|
-
fill_buffer_generator = self._fill_buffer(num)
|
|
274
|
-
for _ in range(initialNumberOfBlocks):
|
|
275
|
-
next(fill_buffer_generator)
|
|
163
|
+
max_sample_delay = int((self.steer.rm / c).max()) + 2
|
|
164
|
+
weights = self._get_weights()
|
|
276
165
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
166
|
+
buffer = SamplesBuffer(
|
|
167
|
+
source=self.source,
|
|
168
|
+
length=int(ceil((num + max_sample_delay) / num)) * num,
|
|
169
|
+
result_num=num + max_sample_delay,
|
|
170
|
+
shift_index_by='num',
|
|
171
|
+
dtype=fdtype,
|
|
172
|
+
)
|
|
173
|
+
for p_res in buffer.result(num):
|
|
174
|
+
p_res *= weights
|
|
175
|
+
if p_res.shape[0] < buffer.result_num: # last block shorter
|
|
176
|
+
num = p_res.shape[0] - max_sample_delay
|
|
284
177
|
n_index = arange(0, num + 1)[:, newaxis]
|
|
285
|
-
flag = False
|
|
286
178
|
# init step
|
|
287
|
-
|
|
288
|
-
Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
179
|
+
Phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
289
180
|
if 'Cleant' not in self.__class__.__name__:
|
|
290
181
|
if 'Sq' not in self.__class__.__name__:
|
|
291
182
|
yield Phi[:num]
|
|
@@ -294,6 +185,7 @@ class BeamformerTime(TimeInOut):
|
|
|
294
185
|
else:
|
|
295
186
|
yield Phi[:num] ** 2
|
|
296
187
|
else:
|
|
188
|
+
p_res_copy = p_res.copy()
|
|
297
189
|
Gamma = zeros(Phi.shape)
|
|
298
190
|
Gamma_autopow = zeros(Phi.shape)
|
|
299
191
|
J = 0
|
|
@@ -304,13 +196,13 @@ class BeamformerTime(TimeInOut):
|
|
|
304
196
|
imax = argmax(powPhi)
|
|
305
197
|
t_float = d_interp2[imax] + d_index[imax] + n_index
|
|
306
198
|
t_ind = t_float.astype(int64)
|
|
307
|
-
for m in range(
|
|
308
|
-
|
|
199
|
+
for m in range(num_mics):
|
|
200
|
+
p_res_copy[t_ind[: num + 1, m], m] -= self.damp * interp(
|
|
309
201
|
t_ind[: num + 1, m],
|
|
310
202
|
t_float[:num, m],
|
|
311
|
-
Phi[:num, imax] * self.r0[imax] / self.rm[imax, m],
|
|
203
|
+
Phi[:num, imax] * self.steer.r0[imax] / self.steer.rm[imax, m],
|
|
312
204
|
)
|
|
313
|
-
nextPhi, nextAutopow = self.
|
|
205
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res_copy, d_interp2, d_index, amp)
|
|
314
206
|
if self.r_diag:
|
|
315
207
|
pownextPhi = (nextPhi[:num] ** 2 - nextAutopow).sum(0).clip(min=0)
|
|
316
208
|
else:
|
|
@@ -331,14 +223,11 @@ class BeamformerTime(TimeInOut):
|
|
|
331
223
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
332
224
|
else:
|
|
333
225
|
yield Gamma[:num] ** 2
|
|
334
|
-
self.bufferIndex += num
|
|
335
|
-
with contextlib.suppress(StopIteration):
|
|
336
|
-
next(fill_buffer_generator)
|
|
337
226
|
|
|
338
|
-
def
|
|
227
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
339
228
|
"""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
|
|
229
|
+
result = empty((num, self.steer.grid.size), dtype=float) # output array
|
|
230
|
+
autopow = empty((num, self.steer.grid.size), dtype=float) # output array
|
|
342
231
|
_delayandsum4(p_res, d_index, d_interp2, amp, result, autopow)
|
|
343
232
|
return result, autopow
|
|
344
233
|
|
|
@@ -354,13 +243,35 @@ class BeamformerTimeSq(BeamformerTime):
|
|
|
354
243
|
|
|
355
244
|
# internal identifier
|
|
356
245
|
digest = Property(
|
|
357
|
-
depends_on=['
|
|
246
|
+
depends_on=['steer.digest', 'source.digest', 'r_diag', 'weights'],
|
|
358
247
|
)
|
|
359
248
|
|
|
360
249
|
@cached_property
|
|
361
250
|
def _get_digest(self):
|
|
362
251
|
return digest(self)
|
|
363
252
|
|
|
253
|
+
def result(self, num=2048):
|
|
254
|
+
"""Python generator that yields the **squared** time-domain beamformer output.
|
|
255
|
+
|
|
256
|
+
The squared output time signal starts for source signals that were emitted from
|
|
257
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
num : int
|
|
262
|
+
This parameter defines the size of the blocks to be yielded
|
|
263
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
264
|
+
|
|
265
|
+
Yields
|
|
266
|
+
------
|
|
267
|
+
numpy.ndarray
|
|
268
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
269
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
270
|
+
large (number of grid points).
|
|
271
|
+
The last block returned by the generator may be shorter than num.
|
|
272
|
+
"""
|
|
273
|
+
return super().result(num)
|
|
274
|
+
|
|
364
275
|
|
|
365
276
|
class BeamformerTimeTraj(BeamformerTime):
|
|
366
277
|
"""Provides a basic time domain beamformer with time signal output
|
|
@@ -369,7 +280,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
369
280
|
|
|
370
281
|
#: :class:`~acoular.trajectory.Trajectory` or derived object.
|
|
371
282
|
#: Start time is assumed to be the same as for the samples.
|
|
372
|
-
trajectory =
|
|
283
|
+
trajectory = Instance(Trajectory, desc='trajectory of the grid center')
|
|
373
284
|
|
|
374
285
|
#: Reference vector, perpendicular to the y-axis of moving grid.
|
|
375
286
|
rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0)), desc='reference vector')
|
|
@@ -378,19 +289,18 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
378
289
|
conv_amp = Bool(False, desc='determines if convective amplification of source is considered')
|
|
379
290
|
|
|
380
291
|
#: Floating point and integer precision
|
|
381
|
-
precision =
|
|
292
|
+
precision = Enum(64, 32, desc='numeric precision')
|
|
382
293
|
|
|
383
294
|
# internal identifier
|
|
384
295
|
digest = Property(
|
|
385
296
|
depends_on=[
|
|
386
|
-
'
|
|
297
|
+
'steer.digest',
|
|
387
298
|
'source.digest',
|
|
388
299
|
'weights',
|
|
389
300
|
'precision',
|
|
390
301
|
'rvec',
|
|
391
302
|
'conv_amp',
|
|
392
303
|
'trajectory.digest',
|
|
393
|
-
'__class__',
|
|
394
304
|
],
|
|
395
305
|
)
|
|
396
306
|
|
|
@@ -398,7 +308,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
398
308
|
def _get_digest(self):
|
|
399
309
|
return digest(self)
|
|
400
310
|
|
|
401
|
-
def
|
|
311
|
+
def _get_moving_gpos(self):
|
|
402
312
|
"""Python generator that yields the moving grid coordinates samplewise."""
|
|
403
313
|
|
|
404
314
|
def cross(a, b):
|
|
@@ -408,7 +318,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
408
318
|
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]])
|
|
409
319
|
|
|
410
320
|
start_t = 0.0
|
|
411
|
-
gpos = self.grid.pos
|
|
321
|
+
gpos = self.steer.grid.pos
|
|
412
322
|
trajg = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq)
|
|
413
323
|
trajg1 = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq, der=1)
|
|
414
324
|
rflag = (self.rvec == 0).all() # flag translation vs. rotation
|
|
@@ -430,43 +340,38 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
430
340
|
# print(loc[:])
|
|
431
341
|
yield tpos
|
|
432
342
|
|
|
433
|
-
def
|
|
343
|
+
def _get_macostheta(self, g1, tpos, rm):
|
|
434
344
|
vvec = array(g1) # velocity vector
|
|
435
345
|
ma = norm(vvec) / self.steer.env.c # machnumber
|
|
436
346
|
fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
|
|
437
|
-
mpos = self.steer.mics.
|
|
347
|
+
mpos = self.steer.mics.pos[:, newaxis, :]
|
|
438
348
|
rmv = tpos[:, :, newaxis] - mpos
|
|
439
349
|
return (ma * sum(rmv.reshape((3, -1)) * fdv, 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
440
350
|
|
|
441
351
|
def get_r0(self, tpos):
|
|
442
352
|
if isscalar(self.steer.ref) and self.steer.ref > 0:
|
|
443
353
|
return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
|
|
444
|
-
return self.env._r(tpos)
|
|
445
|
-
|
|
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)
|
|
449
|
-
self.bufferIndex += num
|
|
354
|
+
return self.steer.env._r(tpos)
|
|
450
355
|
|
|
451
356
|
def result(self, num=2048):
|
|
452
|
-
"""Python generator that yields the
|
|
357
|
+
"""Python generator that yields the time-domain beamformer output.
|
|
358
|
+
|
|
359
|
+
The output time signal starts for source signals that were emitted from
|
|
360
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
453
361
|
|
|
454
362
|
Parameters
|
|
455
363
|
----------
|
|
456
|
-
num :
|
|
364
|
+
num : int
|
|
457
365
|
This parameter defines the size of the blocks to be yielded
|
|
458
|
-
(i.e. the number of samples per block).
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
The output starts for signals that were emitted
|
|
468
|
-
from the grid at `t=0`.
|
|
469
|
-
|
|
366
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
367
|
+
|
|
368
|
+
Yields
|
|
369
|
+
------
|
|
370
|
+
numpy.ndarray
|
|
371
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
372
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
373
|
+
large (number of grid points).
|
|
374
|
+
The last block returned by the generator may be shorter than num.
|
|
470
375
|
"""
|
|
471
376
|
# initialize values
|
|
472
377
|
if self.precision == 64:
|
|
@@ -477,36 +382,28 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
477
382
|
idtype = int32
|
|
478
383
|
w = self._get_weights()
|
|
479
384
|
c = self.steer.env.c / self.source.sample_freq
|
|
480
|
-
|
|
481
|
-
mpos = self.steer.mics.
|
|
482
|
-
m_index = arange(
|
|
385
|
+
num_mics = self.steer.mics.num_mics
|
|
386
|
+
mpos = self.steer.mics.pos.astype(fdtype)
|
|
387
|
+
m_index = arange(num_mics, dtype=idtype)
|
|
483
388
|
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
484
|
-
blockrm = empty((num, self.grid.size,
|
|
485
|
-
blockrmconv = empty((num, self.grid.size,
|
|
486
|
-
amp = empty((num, self.grid.size,
|
|
487
|
-
# delays = empty((num,self.grid.size,
|
|
488
|
-
d_index = empty((num, self.grid.size,
|
|
489
|
-
d_interp2 = empty((num, self.grid.size,
|
|
490
|
-
blockr0 = empty((num, self.grid.size), dtype=fdtype)
|
|
491
|
-
|
|
492
|
-
self.bufferIndex = self.buffer.shape[0]
|
|
493
|
-
movgpos = self.get_moving_gpos() # create moving grid pos generator
|
|
389
|
+
blockrm = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
390
|
+
blockrmconv = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
391
|
+
amp = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
392
|
+
# delays = empty((num,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
393
|
+
d_index = empty((num, self.steer.grid.size, num_mics), dtype=idtype)
|
|
394
|
+
d_interp2 = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
395
|
+
blockr0 = empty((num, self.steer.grid.size), dtype=fdtype)
|
|
396
|
+
movgpos = self._get_moving_gpos() # create moving grid pos generator
|
|
494
397
|
movgspeed = self.trajectory.traj(0.0, delta_t=1 / self.source.sample_freq, der=1)
|
|
495
|
-
|
|
496
|
-
for _i in range(2):
|
|
497
|
-
next(fill_buffer_generator)
|
|
398
|
+
weights = self._get_weights()
|
|
498
399
|
|
|
499
400
|
# preliminary implementation of different steering vectors
|
|
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]
|
|
401
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
506
402
|
|
|
507
403
|
# start processing
|
|
508
404
|
flag = True
|
|
509
|
-
|
|
405
|
+
buffer = SamplesBuffer(source=self.source, length=num * 2, shift_index_by='num', dtype=fdtype)
|
|
406
|
+
buffered_result = buffer.result(num)
|
|
510
407
|
while flag:
|
|
511
408
|
for i in range(num):
|
|
512
409
|
tpos = next(movgpos).astype(fdtype)
|
|
@@ -515,30 +412,27 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
515
412
|
blockrm[i, :, :] = rm
|
|
516
413
|
if self.conv_amp:
|
|
517
414
|
ht = next(movgspeed)
|
|
518
|
-
blockrmconv[i, :, :] = rm * (1 - self.
|
|
415
|
+
blockrmconv[i, :, :] = rm * (1 - self._get_macostheta(ht, tpos, rm)) ** 2
|
|
519
416
|
if self.conv_amp:
|
|
520
417
|
steer_func(blockrmconv, blockr0, amp)
|
|
521
418
|
else:
|
|
522
419
|
steer_func(blockrm, blockr0, amp)
|
|
523
420
|
_delays(blockrm, c, d_interp2, d_index)
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
# last block may be shorter
|
|
535
|
-
if samplesleft - maxdelay <= 0:
|
|
536
|
-
num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < samplesleft)
|
|
421
|
+
max_sample_delay = (d_index.max((1, 2)) + 2).max() # + because of interpolation
|
|
422
|
+
buffer.result_num = num + max_sample_delay
|
|
423
|
+
|
|
424
|
+
try:
|
|
425
|
+
time_block = next(buffered_result)
|
|
426
|
+
time_block *= weights
|
|
427
|
+
except StopIteration:
|
|
428
|
+
break
|
|
429
|
+
if time_block.shape[0] < buffer.result_num: # last block shorter
|
|
430
|
+
num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < time_block.shape[0])
|
|
537
431
|
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
538
432
|
flag = False
|
|
539
433
|
# init step
|
|
540
|
-
p_res =
|
|
541
|
-
Phi, autopow = self.
|
|
434
|
+
p_res = time_block.copy()
|
|
435
|
+
Phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
542
436
|
if 'Cleant' not in self.__class__.__name__:
|
|
543
437
|
if 'Sq' not in self.__class__.__name__:
|
|
544
438
|
yield Phi[:num]
|
|
@@ -570,14 +464,14 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
570
464
|
ind_min = t_float.min(0).astype(idtype)
|
|
571
465
|
# store time history at max power focus point
|
|
572
466
|
h = Phi[:num, imax] * blockr0[:num, imax]
|
|
573
|
-
for m in range(
|
|
467
|
+
for m in range(num_mics):
|
|
574
468
|
# subtract interpolated time history from microphone signals
|
|
575
469
|
p_res[ind_min[m] : ind_max[m], m] -= self.damp * interp(
|
|
576
470
|
t_ind[ind_min[m] : ind_max[m]],
|
|
577
471
|
t_float[:num, m],
|
|
578
472
|
h / blockrm1[:num, imax, m],
|
|
579
473
|
)
|
|
580
|
-
nextPhi, nextAutopow = self.
|
|
474
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
581
475
|
if self.r_diag:
|
|
582
476
|
pownextPhi = (nextPhi[:num] * nextPhi[:num] - nextAutopow).sum(0).clip(min=0)
|
|
583
477
|
else:
|
|
@@ -598,17 +492,12 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
598
492
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
599
493
|
else:
|
|
600
494
|
yield Gamma[:num] ** 2
|
|
601
|
-
self.bufferIndex += num
|
|
602
|
-
try:
|
|
603
|
-
next(fill_buffer_generator)
|
|
604
|
-
except StopIteration:
|
|
605
|
-
dflag = False
|
|
606
495
|
|
|
607
|
-
def
|
|
496
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
608
497
|
"""Standard delay-and-sum method."""
|
|
609
498
|
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
|
|
499
|
+
result = empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
500
|
+
autopow = empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
612
501
|
_delayandsum5(p_res, d_index, d_interp2, amp, result, autopow)
|
|
613
502
|
return result, autopow
|
|
614
503
|
|
|
@@ -622,7 +511,7 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
622
511
|
# internal identifier
|
|
623
512
|
digest = Property(
|
|
624
513
|
depends_on=[
|
|
625
|
-
'
|
|
514
|
+
'steer.digest',
|
|
626
515
|
'source.digest',
|
|
627
516
|
'r_diag',
|
|
628
517
|
'weights',
|
|
@@ -630,7 +519,6 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
630
519
|
'rvec',
|
|
631
520
|
'conv_amp',
|
|
632
521
|
'trajectory.digest',
|
|
633
|
-
'__class__',
|
|
634
522
|
],
|
|
635
523
|
)
|
|
636
524
|
|
|
@@ -638,12 +526,34 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
638
526
|
def _get_digest(self):
|
|
639
527
|
return digest(self)
|
|
640
528
|
|
|
529
|
+
def result(self, num=2048):
|
|
530
|
+
"""Python generator that yields the **squared** time-domain beamformer output.
|
|
531
|
+
|
|
532
|
+
The squared output time signal starts for source signals that were emitted from
|
|
533
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
534
|
+
|
|
535
|
+
Parameters
|
|
536
|
+
----------
|
|
537
|
+
num : int
|
|
538
|
+
This parameter defines the size of the blocks to be yielded
|
|
539
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
540
|
+
|
|
541
|
+
Yields
|
|
542
|
+
------
|
|
543
|
+
numpy.ndarray
|
|
544
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
545
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
546
|
+
large (number of grid points).
|
|
547
|
+
The last block returned by the generator may be shorter than num.
|
|
548
|
+
"""
|
|
549
|
+
return super().result(num)
|
|
550
|
+
|
|
641
551
|
|
|
642
552
|
class BeamformerCleant(BeamformerTime):
|
|
643
|
-
"""CLEANT deconvolution method
|
|
553
|
+
"""CLEANT deconvolution method.
|
|
644
554
|
|
|
645
555
|
An implementation of the CLEAN method in time domain. This class can only
|
|
646
|
-
be used for static sources.
|
|
556
|
+
be used for static sources. See :cite:`Cousson2019` for details.
|
|
647
557
|
"""
|
|
648
558
|
|
|
649
559
|
#: Boolean flag, always False
|
|
@@ -658,20 +568,42 @@ class BeamformerCleant(BeamformerTime):
|
|
|
658
568
|
|
|
659
569
|
# internal identifier
|
|
660
570
|
digest = Property(
|
|
661
|
-
depends_on=['
|
|
571
|
+
depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter'],
|
|
662
572
|
)
|
|
663
573
|
|
|
664
574
|
@cached_property
|
|
665
575
|
def _get_digest(self):
|
|
666
576
|
return digest(self)
|
|
667
577
|
|
|
578
|
+
def result(self, num=2048):
|
|
579
|
+
"""Python generator that yields the deconvolved time-domain beamformer output.
|
|
580
|
+
|
|
581
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
582
|
+
`t=0`.
|
|
583
|
+
|
|
584
|
+
Parameters
|
|
585
|
+
----------
|
|
586
|
+
num : int
|
|
587
|
+
This parameter defines the size of the blocks to be yielded
|
|
588
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
589
|
+
|
|
590
|
+
Yields
|
|
591
|
+
------
|
|
592
|
+
numpy.ndarray
|
|
593
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
594
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
595
|
+
large (number of grid points).
|
|
596
|
+
The last block returned by the generator may be shorter than num.
|
|
597
|
+
"""
|
|
598
|
+
return super().result(num)
|
|
599
|
+
|
|
668
600
|
|
|
669
601
|
class BeamformerCleantSq(BeamformerCleant):
|
|
670
|
-
"""CLEANT deconvolution method
|
|
671
|
-
with optional removal of autocorrelation.
|
|
602
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
672
603
|
|
|
673
604
|
An implementation of the CLEAN method in time domain. This class can only
|
|
674
|
-
be used for static sources.
|
|
605
|
+
be used for static sources. See :cite:`Cousson2019` for details on the method
|
|
606
|
+
and :cite:`Kujawski2020` for details on the autocorrelation removal.
|
|
675
607
|
"""
|
|
676
608
|
|
|
677
609
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -679,32 +611,54 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
679
611
|
|
|
680
612
|
# internal identifier
|
|
681
613
|
digest = Property(
|
|
682
|
-
depends_on=['
|
|
614
|
+
depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter', 'r_diag'],
|
|
683
615
|
)
|
|
684
616
|
|
|
685
617
|
@cached_property
|
|
686
618
|
def _get_digest(self):
|
|
687
619
|
return digest(self)
|
|
688
620
|
|
|
621
|
+
def result(self, num=2048):
|
|
622
|
+
"""Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
623
|
+
|
|
624
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
625
|
+
`t=0`. Per default, block-wise removal of autocorrelation is performed, which can be turned
|
|
626
|
+
of by setting :attr:`r_diag` to `False`.
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
num : int
|
|
631
|
+
This parameter defines the size of the blocks to be yielded
|
|
632
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
633
|
+
|
|
634
|
+
Yields
|
|
635
|
+
------
|
|
636
|
+
numpy.ndarray
|
|
637
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
638
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
639
|
+
large (number of grid points).
|
|
640
|
+
The last block returned by the generator may be shorter than num.
|
|
641
|
+
"""
|
|
642
|
+
return super().result(num)
|
|
643
|
+
|
|
689
644
|
|
|
690
645
|
class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
691
|
-
"""CLEANT deconvolution method
|
|
646
|
+
"""CLEANT deconvolution method.
|
|
692
647
|
|
|
693
648
|
An implementation of the CLEAN method in time domain for moving sources
|
|
694
|
-
with known trajectory.
|
|
649
|
+
with known trajectory. See :cite:`Cousson2019` for details.
|
|
695
650
|
"""
|
|
696
651
|
|
|
697
652
|
#: Floating point and integer precision
|
|
698
|
-
precision =
|
|
653
|
+
precision = Enum(32, 64, desc='numeric precision')
|
|
699
654
|
|
|
700
655
|
# internal identifier
|
|
701
656
|
digest = Property(
|
|
702
657
|
depends_on=[
|
|
703
|
-
'
|
|
658
|
+
'steer.digest',
|
|
704
659
|
'source.digest',
|
|
705
660
|
'weights',
|
|
706
661
|
'precision',
|
|
707
|
-
'__class__',
|
|
708
662
|
'damp',
|
|
709
663
|
'n_iter',
|
|
710
664
|
'rvec',
|
|
@@ -717,13 +671,35 @@ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
|
717
671
|
def _get_digest(self):
|
|
718
672
|
return digest(self)
|
|
719
673
|
|
|
674
|
+
def result(self, num=2048):
|
|
675
|
+
"""Python generator that yields the deconvolved time-domain beamformer output.
|
|
676
|
+
|
|
677
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
678
|
+
`t=0`.
|
|
679
|
+
|
|
680
|
+
Parameters
|
|
681
|
+
----------
|
|
682
|
+
num : int
|
|
683
|
+
This parameter defines the size of the blocks to be yielded
|
|
684
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
685
|
+
|
|
686
|
+
Yields
|
|
687
|
+
------
|
|
688
|
+
numpy.ndarray
|
|
689
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
690
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
691
|
+
large (number of grid points).
|
|
692
|
+
The last block returned by the generator may be shorter than num.
|
|
693
|
+
"""
|
|
694
|
+
return super().result(num)
|
|
695
|
+
|
|
720
696
|
|
|
721
697
|
class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
722
|
-
"""CLEANT deconvolution method
|
|
723
|
-
with optional removal of autocorrelation.
|
|
698
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
724
699
|
|
|
725
700
|
An implementation of the CLEAN method in time domain for moving sources
|
|
726
|
-
with known trajectory.
|
|
701
|
+
with known trajectory. See :cite:`Cousson2019` for details on the method and
|
|
702
|
+
:cite:`Kujawski2020` for details on the autocorrelation removal.
|
|
727
703
|
"""
|
|
728
704
|
|
|
729
705
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -732,11 +708,10 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
732
708
|
# internal identifier
|
|
733
709
|
digest = Property(
|
|
734
710
|
depends_on=[
|
|
735
|
-
'
|
|
711
|
+
'steer.digest',
|
|
736
712
|
'source.digest',
|
|
737
713
|
'weights',
|
|
738
714
|
'precision',
|
|
739
|
-
'__class__',
|
|
740
715
|
'damp',
|
|
741
716
|
'n_iter',
|
|
742
717
|
'rvec',
|
|
@@ -750,25 +725,51 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
750
725
|
def _get_digest(self):
|
|
751
726
|
return digest(self)
|
|
752
727
|
|
|
728
|
+
def result(self, num=2048):
|
|
729
|
+
"""Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
730
|
+
|
|
731
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
732
|
+
`t=0`. Per default, block-wise removal of autocorrelation is performed, which can be turned
|
|
733
|
+
of by setting :attr:`r_diag` to `False`.
|
|
734
|
+
|
|
735
|
+
Parameters
|
|
736
|
+
----------
|
|
737
|
+
num : int
|
|
738
|
+
This parameter defines the size of the blocks to be yielded
|
|
739
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
740
|
+
|
|
741
|
+
Yields
|
|
742
|
+
------
|
|
743
|
+
numpy.ndarray
|
|
744
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.num_channels`).
|
|
745
|
+
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
746
|
+
large (number of grid points).
|
|
747
|
+
The last block returned by the generator may be shorter than num.
|
|
748
|
+
"""
|
|
749
|
+
return super().result(num)
|
|
750
|
+
|
|
753
751
|
|
|
754
|
-
class IntegratorSectorTime(
|
|
752
|
+
class IntegratorSectorTime(TimeOut):
|
|
755
753
|
"""Provides an Integrator in the time domain."""
|
|
756
754
|
|
|
755
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
756
|
+
source = Instance(SamplesGenerator)
|
|
757
|
+
|
|
757
758
|
#: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
|
|
758
|
-
grid =
|
|
759
|
+
grid = Instance(RectGrid, desc='beamforming grid')
|
|
759
760
|
|
|
760
761
|
#: List of sectors in grid
|
|
761
762
|
sectors = List()
|
|
762
763
|
|
|
763
|
-
#: Clipping, in
|
|
764
|
+
#: Clipping, in Decibel relative to maximum (negative values)
|
|
764
765
|
clip = Float(-350.0)
|
|
765
766
|
|
|
766
767
|
#: Number of channels in output (= number of sectors).
|
|
767
|
-
|
|
768
|
+
num_channels = Property(depends_on=['sectors'])
|
|
768
769
|
|
|
769
770
|
# internal identifier
|
|
770
771
|
digest = Property(
|
|
771
|
-
depends_on=['sectors', 'clip', 'grid.digest', 'source.digest'
|
|
772
|
+
depends_on=['sectors', 'clip', 'grid.digest', 'source.digest'],
|
|
772
773
|
)
|
|
773
774
|
|
|
774
775
|
@cached_property
|
|
@@ -776,7 +777,7 @@ class IntegratorSectorTime(TimeInOut):
|
|
|
776
777
|
return digest(self)
|
|
777
778
|
|
|
778
779
|
@cached_property
|
|
779
|
-
def
|
|
780
|
+
def _get_num_channels(self):
|
|
780
781
|
return len(self.sectors)
|
|
781
782
|
|
|
782
783
|
def result(self, num=1):
|
|
@@ -791,14 +792,13 @@ class IntegratorSectorTime(TimeInOut):
|
|
|
791
792
|
|
|
792
793
|
Returns
|
|
793
794
|
-------
|
|
794
|
-
Samples in blocks of shape (num, :attr:`
|
|
795
|
-
:attr:`
|
|
795
|
+
Samples in blocks of shape (num, :attr:`num_channels`).
|
|
796
|
+
:attr:`num_channels` is the number of sectors.
|
|
796
797
|
The last block may be shorter than num.
|
|
797
|
-
|
|
798
798
|
"""
|
|
799
799
|
inds = [self.grid.indices(*sector) for sector in self.sectors]
|
|
800
800
|
gshape = self.grid.shape
|
|
801
|
-
o = empty((num, self.
|
|
801
|
+
o = empty((num, self.num_channels), dtype=float) # output array
|
|
802
802
|
for r in self.source.result(num):
|
|
803
803
|
ns = r.shape[0]
|
|
804
804
|
mapshape = (ns,) + gshape
|