acoular 24.7__py3-none-any.whl → 24.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acoular/__init__.py +17 -8
- acoular/base.py +312 -0
- acoular/configuration.py +3 -3
- acoular/demo/acoular_demo.py +1 -1
- acoular/environments.py +7 -5
- acoular/fbeamform.py +221 -58
- acoular/fprocess.py +368 -0
- acoular/grids.py +31 -17
- acoular/process.py +464 -0
- acoular/sdinput.py +14 -3
- acoular/signals.py +6 -6
- acoular/sources.py +20 -7
- acoular/spectra.py +29 -48
- acoular/tbeamform.py +264 -141
- acoular/tools/__init__.py +2 -0
- acoular/tools/aiaa.py +3 -3
- acoular/tools/helpers.py +2 -2
- acoular/tools/metrics.py +1 -1
- acoular/tools/utils.py +210 -0
- acoular/tprocess.py +89 -453
- acoular/traitsviews.py +5 -3
- acoular/version.py +2 -2
- {acoular-24.7.dist-info → acoular-24.10.dist-info}/METADATA +28 -7
- {acoular-24.7.dist-info → acoular-24.10.dist-info}/RECORD +27 -23
- {acoular-24.7.dist-info → acoular-24.10.dist-info}/WHEEL +0 -0
- {acoular-24.7.dist-info → acoular-24.10.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.7.dist-info → acoular-24.10.dist-info}/licenses/LICENSE +0 -0
acoular/tbeamform.py
CHANGED
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
# imports from other packages
|
|
21
|
-
import contextlib
|
|
22
21
|
from warnings import warn
|
|
23
22
|
|
|
24
23
|
from numpy import (
|
|
@@ -26,7 +25,6 @@ from numpy import (
|
|
|
26
25
|
argmax,
|
|
27
26
|
array,
|
|
28
27
|
ceil,
|
|
29
|
-
concatenate,
|
|
30
28
|
dot,
|
|
31
29
|
empty,
|
|
32
30
|
float32,
|
|
@@ -45,17 +43,18 @@ from numpy import (
|
|
|
45
43
|
where,
|
|
46
44
|
zeros,
|
|
47
45
|
)
|
|
48
|
-
from
|
|
46
|
+
from scipy.linalg import norm
|
|
49
47
|
from traits.api import Bool, CArray, Delegate, Enum, Float, Instance, Int, List, Property, Range, Trait, cached_property
|
|
50
48
|
from traits.trait_errors import TraitError
|
|
51
49
|
|
|
50
|
+
from .base import SamplesGenerator, TimeOut
|
|
52
51
|
from .fbeamform import SteeringVector
|
|
53
52
|
from .grids import RectGrid
|
|
54
53
|
|
|
55
54
|
# acoular imports
|
|
56
55
|
from .internal import digest
|
|
57
|
-
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays
|
|
58
|
-
from .
|
|
56
|
+
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays
|
|
57
|
+
from .tools.utils import SamplesBuffer
|
|
59
58
|
from .trajectory import Trajectory
|
|
60
59
|
|
|
61
60
|
|
|
@@ -93,11 +92,14 @@ def const_power_weight(bf):
|
|
|
93
92
|
possible_weights = {'none': None, 'power': const_power_weight}
|
|
94
93
|
|
|
95
94
|
|
|
96
|
-
class BeamformerTime(
|
|
95
|
+
class BeamformerTime(TimeOut):
|
|
97
96
|
"""Provides a basic time domain beamformer with time signal output
|
|
98
97
|
for a spatially fixed grid.
|
|
99
98
|
"""
|
|
100
99
|
|
|
100
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
101
|
+
source = Instance(SamplesGenerator)
|
|
102
|
+
|
|
101
103
|
# Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
|
|
102
104
|
# that contains information about the steering vector. This is a private trait.
|
|
103
105
|
# Do not set this directly, use `steer` trait instead.
|
|
@@ -116,9 +118,14 @@ class BeamformerTime(TimeInOut):
|
|
|
116
118
|
self._steer_obj = steer
|
|
117
119
|
elif steer in ('true level', 'true location', 'classic', 'inverse'):
|
|
118
120
|
# Type of steering vectors, see also :ref:`Sarradj, 2012<Sarradj2012>`.
|
|
121
|
+
msg = (
|
|
122
|
+
"Deprecated use of 'steer' trait. Please use the 'steer' with an object of class "
|
|
123
|
+
"'SteeringVector'. Using a string to specify the steer type will be removed in "
|
|
124
|
+
'version 25.01.'
|
|
125
|
+
)
|
|
119
126
|
warn(
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
msg,
|
|
128
|
+
DeprecationWarning,
|
|
122
129
|
stacklevel=2,
|
|
123
130
|
)
|
|
124
131
|
self._steer_obj.steer_type = steer
|
|
@@ -136,7 +143,11 @@ class BeamformerTime(TimeInOut):
|
|
|
136
143
|
return self._steer_obj.env
|
|
137
144
|
|
|
138
145
|
def _set_env(self, env):
|
|
139
|
-
|
|
146
|
+
msg = (
|
|
147
|
+
"Deprecated use of 'env' trait. Please use the 'steer' trait with an object of class "
|
|
148
|
+
"'SteeringVector'. The 'env' trait will be removed in version 25.01."
|
|
149
|
+
)
|
|
150
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
140
151
|
self._steer_obj.env = env
|
|
141
152
|
|
|
142
153
|
# The speed of sound.
|
|
@@ -148,7 +159,11 @@ class BeamformerTime(TimeInOut):
|
|
|
148
159
|
return self._steer_obj.env.c
|
|
149
160
|
|
|
150
161
|
def _set_c(self, c):
|
|
151
|
-
|
|
162
|
+
msg = (
|
|
163
|
+
"Deprecated use of 'c' trait. Please use the 'steer' trait with an object of class "
|
|
164
|
+
"'SteeringVector'. The 'c' trait will be removed in version 25.01."
|
|
165
|
+
)
|
|
166
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
152
167
|
self._steer_obj.env.c = c
|
|
153
168
|
|
|
154
169
|
# :class:`~acoular.grids.Grid`-derived object that provides the grid locations.
|
|
@@ -160,7 +175,11 @@ class BeamformerTime(TimeInOut):
|
|
|
160
175
|
return self._steer_obj.grid
|
|
161
176
|
|
|
162
177
|
def _set_grid(self, grid):
|
|
163
|
-
|
|
178
|
+
msg = (
|
|
179
|
+
"Deprecated use of 'grid' trait. Please use the 'steer' trait with an object of class "
|
|
180
|
+
"'SteeringVector'. The 'grid' trait will be removed in version 25.01."
|
|
181
|
+
)
|
|
182
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
164
183
|
self._steer_obj.grid = grid
|
|
165
184
|
|
|
166
185
|
# :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
|
|
@@ -172,7 +191,11 @@ class BeamformerTime(TimeInOut):
|
|
|
172
191
|
return self._steer_obj.mics
|
|
173
192
|
|
|
174
193
|
def _set_mpos(self, mpos):
|
|
175
|
-
|
|
194
|
+
msg = (
|
|
195
|
+
"Deprecated use of 'mpos' trait. Please use the 'steer' trait with an object of class "
|
|
196
|
+
"'SteeringVector' which has an attribute 'mics'. The 'mpos' trait will be removed in version 25.01."
|
|
197
|
+
)
|
|
198
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
176
199
|
self._steer_obj.mics = mpos
|
|
177
200
|
|
|
178
201
|
# Sound travel distances from microphone array center to grid points (r0)
|
|
@@ -182,11 +205,21 @@ class BeamformerTime(TimeInOut):
|
|
|
182
205
|
r0 = Property()
|
|
183
206
|
|
|
184
207
|
def _get_r0(self):
|
|
208
|
+
msg = (
|
|
209
|
+
"Deprecated use of 'r0' trait. Please use the 'steer' trait with an object of class "
|
|
210
|
+
"'SteeringVector'. The 'r0' trait will be removed in version 25.01."
|
|
211
|
+
)
|
|
212
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
185
213
|
return self._steer_obj.r0
|
|
186
214
|
|
|
187
215
|
rm = Property()
|
|
188
216
|
|
|
189
217
|
def _get_rm(self):
|
|
218
|
+
msg = (
|
|
219
|
+
"Deprecated use of 'rm' trait. Please use the 'steer' trait with an object of class "
|
|
220
|
+
"'SteeringVector'. The 'rm' trait will be removed in version 25.01."
|
|
221
|
+
)
|
|
222
|
+
warn(msg, DeprecationWarning, stacklevel=2)
|
|
190
223
|
return self._steer_obj.rm
|
|
191
224
|
|
|
192
225
|
# --- End of backwards compatibility traits --------------------------------------
|
|
@@ -198,12 +231,6 @@ class BeamformerTime(TimeInOut):
|
|
|
198
231
|
weights = Trait('none', possible_weights, desc='spatial weighting function')
|
|
199
232
|
# (from timedomain.possible_weights)
|
|
200
233
|
|
|
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
234
|
# internal identifier
|
|
208
235
|
digest = Property(
|
|
209
236
|
depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__'],
|
|
@@ -216,40 +243,28 @@ class BeamformerTime(TimeInOut):
|
|
|
216
243
|
def _get_weights(self):
|
|
217
244
|
return self.weights_(self)[newaxis] if self.weights_ else 1.0
|
|
218
245
|
|
|
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
246
|
def result(self, num=2048):
|
|
232
|
-
"""Python generator that yields the
|
|
233
|
-
|
|
247
|
+
"""Python generator that yields the time-domain beamformer output.
|
|
248
|
+
|
|
249
|
+
The output time signal starts for source signals that were emitted from
|
|
250
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
234
251
|
|
|
235
252
|
Parameters
|
|
236
253
|
----------
|
|
237
|
-
num :
|
|
254
|
+
num : int
|
|
238
255
|
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
|
-
|
|
256
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
257
|
+
|
|
258
|
+
Yields
|
|
259
|
+
------
|
|
260
|
+
numpy.ndarray
|
|
261
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
262
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
263
|
+
large (number of grid points).
|
|
264
|
+
The last block returned by the generator may be shorter than num.
|
|
251
265
|
"""
|
|
252
266
|
# initialize values
|
|
267
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
253
268
|
fdtype = float64
|
|
254
269
|
idtype = int64
|
|
255
270
|
numMics = self.steer.mics.num_mics
|
|
@@ -259,33 +274,29 @@ class BeamformerTime(TimeInOut):
|
|
|
259
274
|
# delays = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
260
275
|
d_index = empty((1, self.grid.size, numMics), dtype=idtype)
|
|
261
276
|
d_interp2 = empty((1, self.grid.size, numMics), dtype=fdtype)
|
|
262
|
-
|
|
263
|
-
_delays(self.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
277
|
+
steer_func(self.steer.rm[newaxis, :, :], self.steer.r0[newaxis, :], amp)
|
|
278
|
+
_delays(self.steer.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
264
279
|
amp.shape = amp.shape[1:]
|
|
265
280
|
# delays.shape = delays.shape[1:]
|
|
266
281
|
d_index.shape = d_index.shape[1:]
|
|
267
282
|
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)
|
|
283
|
+
max_sample_delay = int((self.steer.rm / c).max()) + 2
|
|
284
|
+
weights = self._get_weights()
|
|
276
285
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
286
|
+
buffer = SamplesBuffer(
|
|
287
|
+
source=self.source,
|
|
288
|
+
length=int(ceil((num + max_sample_delay) / num)) * num,
|
|
289
|
+
result_num=num + max_sample_delay,
|
|
290
|
+
shift_index_by='num',
|
|
291
|
+
dtype=fdtype,
|
|
292
|
+
)
|
|
293
|
+
for p_res in buffer.result(num):
|
|
294
|
+
p_res *= weights
|
|
295
|
+
if p_res.shape[0] < buffer.result_num: # last block shorter
|
|
296
|
+
num = p_res.shape[0] - max_sample_delay
|
|
284
297
|
n_index = arange(0, num + 1)[:, newaxis]
|
|
285
|
-
flag = False
|
|
286
298
|
# init step
|
|
287
|
-
|
|
288
|
-
Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
299
|
+
Phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
289
300
|
if 'Cleant' not in self.__class__.__name__:
|
|
290
301
|
if 'Sq' not in self.__class__.__name__:
|
|
291
302
|
yield Phi[:num]
|
|
@@ -294,6 +305,7 @@ class BeamformerTime(TimeInOut):
|
|
|
294
305
|
else:
|
|
295
306
|
yield Phi[:num] ** 2
|
|
296
307
|
else:
|
|
308
|
+
p_res_copy = p_res.copy()
|
|
297
309
|
Gamma = zeros(Phi.shape)
|
|
298
310
|
Gamma_autopow = zeros(Phi.shape)
|
|
299
311
|
J = 0
|
|
@@ -305,12 +317,12 @@ class BeamformerTime(TimeInOut):
|
|
|
305
317
|
t_float = d_interp2[imax] + d_index[imax] + n_index
|
|
306
318
|
t_ind = t_float.astype(int64)
|
|
307
319
|
for m in range(numMics):
|
|
308
|
-
|
|
320
|
+
p_res_copy[t_ind[: num + 1, m], m] -= self.damp * interp(
|
|
309
321
|
t_ind[: num + 1, m],
|
|
310
322
|
t_float[:num, m],
|
|
311
|
-
Phi[:num, imax] * self.r0[imax] / self.rm[imax, m],
|
|
323
|
+
Phi[:num, imax] * self.steer.r0[imax] / self.steer.rm[imax, m],
|
|
312
324
|
)
|
|
313
|
-
nextPhi, nextAutopow = self.
|
|
325
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res_copy, d_interp2, d_index, amp)
|
|
314
326
|
if self.r_diag:
|
|
315
327
|
pownextPhi = (nextPhi[:num] ** 2 - nextAutopow).sum(0).clip(min=0)
|
|
316
328
|
else:
|
|
@@ -331,11 +343,8 @@ class BeamformerTime(TimeInOut):
|
|
|
331
343
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
332
344
|
else:
|
|
333
345
|
yield Gamma[:num] ** 2
|
|
334
|
-
self.bufferIndex += num
|
|
335
|
-
with contextlib.suppress(StopIteration):
|
|
336
|
-
next(fill_buffer_generator)
|
|
337
346
|
|
|
338
|
-
def
|
|
347
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
339
348
|
"""Standard delay-and-sum method."""
|
|
340
349
|
result = empty((num, self.grid.size), dtype=float) # output array
|
|
341
350
|
autopow = empty((num, self.grid.size), dtype=float) # output array
|
|
@@ -361,6 +370,28 @@ class BeamformerTimeSq(BeamformerTime):
|
|
|
361
370
|
def _get_digest(self):
|
|
362
371
|
return digest(self)
|
|
363
372
|
|
|
373
|
+
def result(self, num=2048):
|
|
374
|
+
"""Python generator that yields the **squared** time-domain beamformer output.
|
|
375
|
+
|
|
376
|
+
The squared output time signal starts for source signals that were emitted from
|
|
377
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
378
|
+
|
|
379
|
+
Parameters
|
|
380
|
+
----------
|
|
381
|
+
num : int
|
|
382
|
+
This parameter defines the size of the blocks to be yielded
|
|
383
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
384
|
+
|
|
385
|
+
Yields
|
|
386
|
+
------
|
|
387
|
+
numpy.ndarray
|
|
388
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
389
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
390
|
+
large (number of grid points).
|
|
391
|
+
The last block returned by the generator may be shorter than num.
|
|
392
|
+
"""
|
|
393
|
+
return super().result(num)
|
|
394
|
+
|
|
364
395
|
|
|
365
396
|
class BeamformerTimeTraj(BeamformerTime):
|
|
366
397
|
"""Provides a basic time domain beamformer with time signal output
|
|
@@ -398,7 +429,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
398
429
|
def _get_digest(self):
|
|
399
430
|
return digest(self)
|
|
400
431
|
|
|
401
|
-
def
|
|
432
|
+
def _get_moving_gpos(self):
|
|
402
433
|
"""Python generator that yields the moving grid coordinates samplewise."""
|
|
403
434
|
|
|
404
435
|
def cross(a, b):
|
|
@@ -408,7 +439,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
408
439
|
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
440
|
|
|
410
441
|
start_t = 0.0
|
|
411
|
-
gpos = self.grid.
|
|
442
|
+
gpos = self.grid.gpos
|
|
412
443
|
trajg = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq)
|
|
413
444
|
trajg1 = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq, der=1)
|
|
414
445
|
rflag = (self.rvec == 0).all() # flag translation vs. rotation
|
|
@@ -430,7 +461,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
430
461
|
# print(loc[:])
|
|
431
462
|
yield tpos
|
|
432
463
|
|
|
433
|
-
def
|
|
464
|
+
def _get_macostheta(self, g1, tpos, rm):
|
|
434
465
|
vvec = array(g1) # velocity vector
|
|
435
466
|
ma = norm(vvec) / self.steer.env.c # machnumber
|
|
436
467
|
fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
|
|
@@ -443,30 +474,25 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
443
474
|
return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
|
|
444
475
|
return self.env._r(tpos)
|
|
445
476
|
|
|
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
|
|
450
|
-
|
|
451
477
|
def result(self, num=2048):
|
|
452
|
-
"""Python generator that yields the
|
|
478
|
+
"""Python generator that yields the time-domain beamformer output.
|
|
479
|
+
|
|
480
|
+
The output time signal starts for source signals that were emitted from
|
|
481
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
453
482
|
|
|
454
483
|
Parameters
|
|
455
484
|
----------
|
|
456
|
-
num :
|
|
485
|
+
num : int
|
|
457
486
|
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
|
-
|
|
487
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
488
|
+
|
|
489
|
+
Yields
|
|
490
|
+
------
|
|
491
|
+
numpy.ndarray
|
|
492
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
493
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
494
|
+
large (number of grid points).
|
|
495
|
+
The last block returned by the generator may be shorter than num.
|
|
470
496
|
"""
|
|
471
497
|
# initialize values
|
|
472
498
|
if self.precision == 64:
|
|
@@ -488,25 +514,17 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
488
514
|
d_index = empty((num, self.grid.size, numMics), dtype=idtype)
|
|
489
515
|
d_interp2 = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
490
516
|
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
|
|
517
|
+
movgpos = self._get_moving_gpos() # create moving grid pos generator
|
|
494
518
|
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)
|
|
519
|
+
weights = self._get_weights()
|
|
498
520
|
|
|
499
521
|
# 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]
|
|
522
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
506
523
|
|
|
507
524
|
# start processing
|
|
508
525
|
flag = True
|
|
509
|
-
|
|
526
|
+
buffer = SamplesBuffer(source=self.source, length=num * 2, shift_index_by='num', dtype=fdtype)
|
|
527
|
+
buffered_result = buffer.result(num)
|
|
510
528
|
while flag:
|
|
511
529
|
for i in range(num):
|
|
512
530
|
tpos = next(movgpos).astype(fdtype)
|
|
@@ -515,30 +533,27 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
515
533
|
blockrm[i, :, :] = rm
|
|
516
534
|
if self.conv_amp:
|
|
517
535
|
ht = next(movgspeed)
|
|
518
|
-
blockrmconv[i, :, :] = rm * (1 - self.
|
|
536
|
+
blockrmconv[i, :, :] = rm * (1 - self._get_macostheta(ht, tpos, rm)) ** 2
|
|
519
537
|
if self.conv_amp:
|
|
520
538
|
steer_func(blockrmconv, blockr0, amp)
|
|
521
539
|
else:
|
|
522
540
|
steer_func(blockrm, blockr0, amp)
|
|
523
541
|
_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)
|
|
542
|
+
max_sample_delay = (d_index.max((1, 2)) + 2).max() # + because of interpolation
|
|
543
|
+
buffer.result_num = num + max_sample_delay
|
|
544
|
+
|
|
545
|
+
try:
|
|
546
|
+
time_block = next(buffered_result)
|
|
547
|
+
time_block *= weights
|
|
548
|
+
except StopIteration:
|
|
549
|
+
break
|
|
550
|
+
if time_block.shape[0] < buffer.result_num: # last block shorter
|
|
551
|
+
num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < time_block.shape[0])
|
|
537
552
|
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
538
553
|
flag = False
|
|
539
554
|
# init step
|
|
540
|
-
p_res =
|
|
541
|
-
Phi, autopow = self.
|
|
555
|
+
p_res = time_block.copy()
|
|
556
|
+
Phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
542
557
|
if 'Cleant' not in self.__class__.__name__:
|
|
543
558
|
if 'Sq' not in self.__class__.__name__:
|
|
544
559
|
yield Phi[:num]
|
|
@@ -577,7 +592,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
577
592
|
t_float[:num, m],
|
|
578
593
|
h / blockrm1[:num, imax, m],
|
|
579
594
|
)
|
|
580
|
-
nextPhi, nextAutopow = self.
|
|
595
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
581
596
|
if self.r_diag:
|
|
582
597
|
pownextPhi = (nextPhi[:num] * nextPhi[:num] - nextAutopow).sum(0).clip(min=0)
|
|
583
598
|
else:
|
|
@@ -598,13 +613,8 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
598
613
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
599
614
|
else:
|
|
600
615
|
yield Gamma[:num] ** 2
|
|
601
|
-
self.bufferIndex += num
|
|
602
|
-
try:
|
|
603
|
-
next(fill_buffer_generator)
|
|
604
|
-
except StopIteration:
|
|
605
|
-
dflag = False
|
|
606
616
|
|
|
607
|
-
def
|
|
617
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
608
618
|
"""Standard delay-and-sum method."""
|
|
609
619
|
fdtype = float64 if self.precision == 64 else float32
|
|
610
620
|
result = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
@@ -638,12 +648,34 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
638
648
|
def _get_digest(self):
|
|
639
649
|
return digest(self)
|
|
640
650
|
|
|
651
|
+
def result(self, num=2048):
|
|
652
|
+
"""Python generator that yields the **squared** time-domain beamformer output.
|
|
653
|
+
|
|
654
|
+
The squared output time signal starts for source signals that were emitted from
|
|
655
|
+
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
656
|
+
|
|
657
|
+
Parameters
|
|
658
|
+
----------
|
|
659
|
+
num : int
|
|
660
|
+
This parameter defines the size of the blocks to be yielded
|
|
661
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
662
|
+
|
|
663
|
+
Yields
|
|
664
|
+
------
|
|
665
|
+
numpy.ndarray
|
|
666
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
667
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
668
|
+
large (number of grid points).
|
|
669
|
+
The last block returned by the generator may be shorter than num.
|
|
670
|
+
"""
|
|
671
|
+
return super().result(num)
|
|
672
|
+
|
|
641
673
|
|
|
642
674
|
class BeamformerCleant(BeamformerTime):
|
|
643
|
-
"""CLEANT deconvolution method
|
|
675
|
+
"""CLEANT deconvolution method.
|
|
644
676
|
|
|
645
677
|
An implementation of the CLEAN method in time domain. This class can only
|
|
646
|
-
be used for static sources.
|
|
678
|
+
be used for static sources. See :cite:`Cousson2019` for details.
|
|
647
679
|
"""
|
|
648
680
|
|
|
649
681
|
#: Boolean flag, always False
|
|
@@ -665,13 +697,34 @@ class BeamformerCleant(BeamformerTime):
|
|
|
665
697
|
def _get_digest(self):
|
|
666
698
|
return digest(self)
|
|
667
699
|
|
|
700
|
+
def result(self, num=2048):
|
|
701
|
+
"""Python generator that yields the deconvolved time-domain beamformer output.
|
|
702
|
+
|
|
703
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at `t=0`.
|
|
704
|
+
|
|
705
|
+
Parameters
|
|
706
|
+
----------
|
|
707
|
+
num : int
|
|
708
|
+
This parameter defines the size of the blocks to be yielded
|
|
709
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
710
|
+
|
|
711
|
+
Yields
|
|
712
|
+
------
|
|
713
|
+
numpy.ndarray
|
|
714
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
715
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
716
|
+
large (number of grid points).
|
|
717
|
+
The last block returned by the generator may be shorter than num.
|
|
718
|
+
"""
|
|
719
|
+
return super().result(num)
|
|
720
|
+
|
|
668
721
|
|
|
669
722
|
class BeamformerCleantSq(BeamformerCleant):
|
|
670
|
-
"""CLEANT deconvolution method
|
|
671
|
-
with optional removal of autocorrelation.
|
|
723
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
672
724
|
|
|
673
725
|
An implementation of the CLEAN method in time domain. This class can only
|
|
674
|
-
be used for static sources.
|
|
726
|
+
be used for static sources. See :cite:`Cousson2019` for details on the method
|
|
727
|
+
and :cite:`Kujawski2020` for details on the autocorrelation removal.
|
|
675
728
|
"""
|
|
676
729
|
|
|
677
730
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -686,12 +739,35 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
686
739
|
def _get_digest(self):
|
|
687
740
|
return digest(self)
|
|
688
741
|
|
|
742
|
+
def result(self, num=2048):
|
|
743
|
+
"""Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
744
|
+
|
|
745
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at `t=0`.
|
|
746
|
+
Per default, block-wise removal of autocorrelation is performed, which can be turned of by setting
|
|
747
|
+
:attr:`r_diag` to `False`.
|
|
748
|
+
|
|
749
|
+
Parameters
|
|
750
|
+
----------
|
|
751
|
+
num : int
|
|
752
|
+
This parameter defines the size of the blocks to be yielded
|
|
753
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
754
|
+
|
|
755
|
+
Yields
|
|
756
|
+
------
|
|
757
|
+
numpy.ndarray
|
|
758
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
759
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
760
|
+
large (number of grid points).
|
|
761
|
+
The last block returned by the generator may be shorter than num.
|
|
762
|
+
"""
|
|
763
|
+
return super().result(num)
|
|
764
|
+
|
|
689
765
|
|
|
690
766
|
class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
691
|
-
"""CLEANT deconvolution method
|
|
767
|
+
"""CLEANT deconvolution method.
|
|
692
768
|
|
|
693
769
|
An implementation of the CLEAN method in time domain for moving sources
|
|
694
|
-
with known trajectory.
|
|
770
|
+
with known trajectory. See :cite:`Cousson2019` for details.
|
|
695
771
|
"""
|
|
696
772
|
|
|
697
773
|
#: Floating point and integer precision
|
|
@@ -717,13 +793,34 @@ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
|
717
793
|
def _get_digest(self):
|
|
718
794
|
return digest(self)
|
|
719
795
|
|
|
796
|
+
def result(self, num=2048):
|
|
797
|
+
"""Python generator that yields the deconvolved time-domain beamformer output.
|
|
798
|
+
|
|
799
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at `t=0`.
|
|
800
|
+
|
|
801
|
+
Parameters
|
|
802
|
+
----------
|
|
803
|
+
num : int
|
|
804
|
+
This parameter defines the size of the blocks to be yielded
|
|
805
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
806
|
+
|
|
807
|
+
Yields
|
|
808
|
+
------
|
|
809
|
+
numpy.ndarray
|
|
810
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
811
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
812
|
+
large (number of grid points).
|
|
813
|
+
The last block returned by the generator may be shorter than num.
|
|
814
|
+
"""
|
|
815
|
+
return super().result(num)
|
|
816
|
+
|
|
720
817
|
|
|
721
818
|
class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
722
|
-
"""CLEANT deconvolution method
|
|
723
|
-
with optional removal of autocorrelation.
|
|
819
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
724
820
|
|
|
725
821
|
An implementation of the CLEAN method in time domain for moving sources
|
|
726
|
-
with known trajectory.
|
|
822
|
+
with known trajectory. See :cite:`Cousson2019` for details on the method and
|
|
823
|
+
:cite:`Kujawski2020` for details on the autocorrelation removal.
|
|
727
824
|
"""
|
|
728
825
|
|
|
729
826
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -750,10 +847,36 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
750
847
|
def _get_digest(self):
|
|
751
848
|
return digest(self)
|
|
752
849
|
|
|
850
|
+
def result(self, num=2048):
|
|
851
|
+
"""Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
852
|
+
|
|
853
|
+
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at `t=0`.
|
|
854
|
+
Per default, block-wise removal of autocorrelation is performed, which can be turned of by setting
|
|
855
|
+
:attr:`r_diag` to `False`.
|
|
753
856
|
|
|
754
|
-
|
|
857
|
+
Parameters
|
|
858
|
+
----------
|
|
859
|
+
num : int
|
|
860
|
+
This parameter defines the size of the blocks to be yielded
|
|
861
|
+
(i.e. the number of samples per block). Defaults to 2048.
|
|
862
|
+
|
|
863
|
+
Yields
|
|
864
|
+
------
|
|
865
|
+
numpy.ndarray
|
|
866
|
+
Samples in blocks of shape (num, :attr:`~BeamformerTime.numchannels`).
|
|
867
|
+
:attr:`~BeamformerTime.numchannels` is usually very \
|
|
868
|
+
large (number of grid points).
|
|
869
|
+
The last block returned by the generator may be shorter than num.
|
|
870
|
+
"""
|
|
871
|
+
return super().result(num)
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
class IntegratorSectorTime(TimeOut):
|
|
755
875
|
"""Provides an Integrator in the time domain."""
|
|
756
876
|
|
|
877
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
878
|
+
source = Instance(SamplesGenerator)
|
|
879
|
+
|
|
757
880
|
#: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
|
|
758
881
|
grid = Trait(RectGrid, desc='beamforming grid')
|
|
759
882
|
|