acoular 24.5__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 -11
- acoular/base.py +312 -0
- acoular/configuration.py +23 -16
- acoular/demo/acoular_demo.py +28 -35
- acoular/environments.py +20 -15
- acoular/fastFuncs.py +40 -40
- acoular/fbeamform.py +1100 -1130
- acoular/fprocess.py +368 -0
- acoular/grids.py +36 -22
- acoular/h5cache.py +34 -34
- acoular/h5files.py +13 -13
- acoular/internal.py +3 -3
- acoular/process.py +464 -0
- acoular/sdinput.py +24 -4
- acoular/signals.py +20 -6
- acoular/sources.py +140 -56
- acoular/spectra.py +34 -53
- acoular/tbeamform.py +264 -142
- acoular/tfastfuncs.py +17 -18
- acoular/tools/__init__.py +2 -0
- acoular/tools/aiaa.py +7 -8
- acoular/tools/helpers.py +2 -2
- acoular/tools/metrics.py +1 -1
- acoular/tools/utils.py +210 -0
- acoular/tprocess.py +168 -532
- acoular/traitsviews.py +5 -3
- acoular/version.py +2 -2
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/METADATA +49 -8
- acoular-24.10.dist-info/RECORD +54 -0
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/WHEEL +1 -1
- acoular-24.5.dist-info/RECORD +0 -50
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/licenses/LICENSE +0 -0
acoular/tbeamform.py
CHANGED
|
@@ -25,7 +25,6 @@ from numpy import (
|
|
|
25
25
|
argmax,
|
|
26
26
|
array,
|
|
27
27
|
ceil,
|
|
28
|
-
concatenate,
|
|
29
28
|
dot,
|
|
30
29
|
empty,
|
|
31
30
|
float32,
|
|
@@ -44,17 +43,18 @@ from numpy import (
|
|
|
44
43
|
where,
|
|
45
44
|
zeros,
|
|
46
45
|
)
|
|
47
|
-
from
|
|
46
|
+
from scipy.linalg import norm
|
|
48
47
|
from traits.api import Bool, CArray, Delegate, Enum, Float, Instance, Int, List, Property, Range, Trait, cached_property
|
|
49
48
|
from traits.trait_errors import TraitError
|
|
50
49
|
|
|
50
|
+
from .base import SamplesGenerator, TimeOut
|
|
51
51
|
from .fbeamform import SteeringVector
|
|
52
52
|
from .grids import RectGrid
|
|
53
53
|
|
|
54
54
|
# acoular imports
|
|
55
55
|
from .internal import digest
|
|
56
|
-
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays
|
|
57
|
-
from .
|
|
56
|
+
from .tfastfuncs import _delayandsum4, _delayandsum5, _delays
|
|
57
|
+
from .tools.utils import SamplesBuffer
|
|
58
58
|
from .trajectory import Trajectory
|
|
59
59
|
|
|
60
60
|
|
|
@@ -92,11 +92,14 @@ def const_power_weight(bf):
|
|
|
92
92
|
possible_weights = {'none': None, 'power': const_power_weight}
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
class BeamformerTime(
|
|
95
|
+
class BeamformerTime(TimeOut):
|
|
96
96
|
"""Provides a basic time domain beamformer with time signal output
|
|
97
97
|
for a spatially fixed grid.
|
|
98
98
|
"""
|
|
99
99
|
|
|
100
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
101
|
+
source = Instance(SamplesGenerator)
|
|
102
|
+
|
|
100
103
|
# Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
|
|
101
104
|
# that contains information about the steering vector. This is a private trait.
|
|
102
105
|
# Do not set this directly, use `steer` trait instead.
|
|
@@ -115,9 +118,14 @@ class BeamformerTime(TimeInOut):
|
|
|
115
118
|
self._steer_obj = steer
|
|
116
119
|
elif steer in ('true level', 'true location', 'classic', 'inverse'):
|
|
117
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
|
+
)
|
|
118
126
|
warn(
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
msg,
|
|
128
|
+
DeprecationWarning,
|
|
121
129
|
stacklevel=2,
|
|
122
130
|
)
|
|
123
131
|
self._steer_obj.steer_type = steer
|
|
@@ -135,7 +143,11 @@ class BeamformerTime(TimeInOut):
|
|
|
135
143
|
return self._steer_obj.env
|
|
136
144
|
|
|
137
145
|
def _set_env(self, env):
|
|
138
|
-
|
|
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)
|
|
139
151
|
self._steer_obj.env = env
|
|
140
152
|
|
|
141
153
|
# The speed of sound.
|
|
@@ -147,7 +159,11 @@ class BeamformerTime(TimeInOut):
|
|
|
147
159
|
return self._steer_obj.env.c
|
|
148
160
|
|
|
149
161
|
def _set_c(self, c):
|
|
150
|
-
|
|
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)
|
|
151
167
|
self._steer_obj.env.c = c
|
|
152
168
|
|
|
153
169
|
# :class:`~acoular.grids.Grid`-derived object that provides the grid locations.
|
|
@@ -159,7 +175,11 @@ class BeamformerTime(TimeInOut):
|
|
|
159
175
|
return self._steer_obj.grid
|
|
160
176
|
|
|
161
177
|
def _set_grid(self, grid):
|
|
162
|
-
|
|
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)
|
|
163
183
|
self._steer_obj.grid = grid
|
|
164
184
|
|
|
165
185
|
# :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
|
|
@@ -171,7 +191,11 @@ class BeamformerTime(TimeInOut):
|
|
|
171
191
|
return self._steer_obj.mics
|
|
172
192
|
|
|
173
193
|
def _set_mpos(self, mpos):
|
|
174
|
-
|
|
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)
|
|
175
199
|
self._steer_obj.mics = mpos
|
|
176
200
|
|
|
177
201
|
# Sound travel distances from microphone array center to grid points (r0)
|
|
@@ -181,11 +205,21 @@ class BeamformerTime(TimeInOut):
|
|
|
181
205
|
r0 = Property()
|
|
182
206
|
|
|
183
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)
|
|
184
213
|
return self._steer_obj.r0
|
|
185
214
|
|
|
186
215
|
rm = Property()
|
|
187
216
|
|
|
188
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)
|
|
189
223
|
return self._steer_obj.rm
|
|
190
224
|
|
|
191
225
|
# --- End of backwards compatibility traits --------------------------------------
|
|
@@ -197,12 +231,6 @@ class BeamformerTime(TimeInOut):
|
|
|
197
231
|
weights = Trait('none', possible_weights, desc='spatial weighting function')
|
|
198
232
|
# (from timedomain.possible_weights)
|
|
199
233
|
|
|
200
|
-
# buffer with microphone time signals used for processing. Internal use
|
|
201
|
-
buffer = CArray(desc='buffer containing microphone signals')
|
|
202
|
-
|
|
203
|
-
# index indicating position of current processing sample. Internal use.
|
|
204
|
-
bufferIndex = Int(desc='index indicating position in buffer')
|
|
205
|
-
|
|
206
234
|
# internal identifier
|
|
207
235
|
digest = Property(
|
|
208
236
|
depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__'],
|
|
@@ -215,40 +243,28 @@ class BeamformerTime(TimeInOut):
|
|
|
215
243
|
def _get_weights(self):
|
|
216
244
|
return self.weights_(self)[newaxis] if self.weights_ else 1.0
|
|
217
245
|
|
|
218
|
-
def _fill_buffer(self, num):
|
|
219
|
-
"""Generator that fills the signal buffer."""
|
|
220
|
-
weights = self._get_weights()
|
|
221
|
-
for block in self.source.result(num):
|
|
222
|
-
block *= weights
|
|
223
|
-
ns = block.shape[0]
|
|
224
|
-
bufferSize = self.buffer.shape[0]
|
|
225
|
-
self.buffer[0 : (bufferSize - ns)] = self.buffer[-(bufferSize - ns) :]
|
|
226
|
-
self.buffer[-ns:, :] = block
|
|
227
|
-
self.bufferIndex -= ns
|
|
228
|
-
yield
|
|
229
|
-
|
|
230
246
|
def result(self, num=2048):
|
|
231
|
-
"""Python generator that yields the
|
|
232
|
-
|
|
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`.
|
|
233
251
|
|
|
234
252
|
Parameters
|
|
235
253
|
----------
|
|
236
|
-
num :
|
|
254
|
+
num : int
|
|
237
255
|
This parameter defines the size of the blocks to be yielded
|
|
238
|
-
(i.e. the number of samples per block).
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
The output starts for signals that were emitted
|
|
248
|
-
from the grid at `t=0`.
|
|
249
|
-
|
|
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.
|
|
250
265
|
"""
|
|
251
266
|
# initialize values
|
|
267
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
252
268
|
fdtype = float64
|
|
253
269
|
idtype = int64
|
|
254
270
|
numMics = self.steer.mics.num_mics
|
|
@@ -258,33 +274,29 @@ class BeamformerTime(TimeInOut):
|
|
|
258
274
|
# delays = empty((1,self.grid.size,numMics),dtype=fdtype)
|
|
259
275
|
d_index = empty((1, self.grid.size, numMics), dtype=idtype)
|
|
260
276
|
d_interp2 = empty((1, self.grid.size, numMics), dtype=fdtype)
|
|
261
|
-
|
|
262
|
-
_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)
|
|
263
279
|
amp.shape = amp.shape[1:]
|
|
264
280
|
# delays.shape = delays.shape[1:]
|
|
265
281
|
d_index.shape = d_index.shape[1:]
|
|
266
282
|
d_interp2.shape = d_interp2.shape[1:]
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
bufferSize = initialNumberOfBlocks * num
|
|
270
|
-
self.buffer = zeros((bufferSize, numMics), dtype=float)
|
|
271
|
-
self.bufferIndex = bufferSize # indexing current time sample in buffer
|
|
272
|
-
fill_buffer_generator = self._fill_buffer(num)
|
|
273
|
-
for _ in range(initialNumberOfBlocks):
|
|
274
|
-
next(fill_buffer_generator)
|
|
283
|
+
max_sample_delay = int((self.steer.rm / c).max()) + 2
|
|
284
|
+
weights = self._get_weights()
|
|
275
285
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
|
283
297
|
n_index = arange(0, num + 1)[:, newaxis]
|
|
284
|
-
flag = False
|
|
285
298
|
# init step
|
|
286
|
-
|
|
287
|
-
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)
|
|
288
300
|
if 'Cleant' not in self.__class__.__name__:
|
|
289
301
|
if 'Sq' not in self.__class__.__name__:
|
|
290
302
|
yield Phi[:num]
|
|
@@ -293,6 +305,7 @@ class BeamformerTime(TimeInOut):
|
|
|
293
305
|
else:
|
|
294
306
|
yield Phi[:num] ** 2
|
|
295
307
|
else:
|
|
308
|
+
p_res_copy = p_res.copy()
|
|
296
309
|
Gamma = zeros(Phi.shape)
|
|
297
310
|
Gamma_autopow = zeros(Phi.shape)
|
|
298
311
|
J = 0
|
|
@@ -304,12 +317,12 @@ class BeamformerTime(TimeInOut):
|
|
|
304
317
|
t_float = d_interp2[imax] + d_index[imax] + n_index
|
|
305
318
|
t_ind = t_float.astype(int64)
|
|
306
319
|
for m in range(numMics):
|
|
307
|
-
|
|
320
|
+
p_res_copy[t_ind[: num + 1, m], m] -= self.damp * interp(
|
|
308
321
|
t_ind[: num + 1, m],
|
|
309
322
|
t_float[:num, m],
|
|
310
|
-
Phi[:num, imax] * self.r0[imax] / self.rm[imax, m],
|
|
323
|
+
Phi[:num, imax] * self.steer.r0[imax] / self.steer.rm[imax, m],
|
|
311
324
|
)
|
|
312
|
-
nextPhi, nextAutopow = self.
|
|
325
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res_copy, d_interp2, d_index, amp)
|
|
313
326
|
if self.r_diag:
|
|
314
327
|
pownextPhi = (nextPhi[:num] ** 2 - nextAutopow).sum(0).clip(min=0)
|
|
315
328
|
else:
|
|
@@ -330,13 +343,8 @@ class BeamformerTime(TimeInOut):
|
|
|
330
343
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
331
344
|
else:
|
|
332
345
|
yield Gamma[:num] ** 2
|
|
333
|
-
self.bufferIndex += num
|
|
334
|
-
try:
|
|
335
|
-
next(fill_buffer_generator)
|
|
336
|
-
except:
|
|
337
|
-
pass
|
|
338
346
|
|
|
339
|
-
def
|
|
347
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
340
348
|
"""Standard delay-and-sum method."""
|
|
341
349
|
result = empty((num, self.grid.size), dtype=float) # output array
|
|
342
350
|
autopow = empty((num, self.grid.size), dtype=float) # output array
|
|
@@ -362,6 +370,28 @@ class BeamformerTimeSq(BeamformerTime):
|
|
|
362
370
|
def _get_digest(self):
|
|
363
371
|
return digest(self)
|
|
364
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
|
+
|
|
365
395
|
|
|
366
396
|
class BeamformerTimeTraj(BeamformerTime):
|
|
367
397
|
"""Provides a basic time domain beamformer with time signal output
|
|
@@ -399,7 +429,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
399
429
|
def _get_digest(self):
|
|
400
430
|
return digest(self)
|
|
401
431
|
|
|
402
|
-
def
|
|
432
|
+
def _get_moving_gpos(self):
|
|
403
433
|
"""Python generator that yields the moving grid coordinates samplewise."""
|
|
404
434
|
|
|
405
435
|
def cross(a, b):
|
|
@@ -409,7 +439,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
409
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]])
|
|
410
440
|
|
|
411
441
|
start_t = 0.0
|
|
412
|
-
gpos = self.grid.
|
|
442
|
+
gpos = self.grid.gpos
|
|
413
443
|
trajg = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq)
|
|
414
444
|
trajg1 = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq, der=1)
|
|
415
445
|
rflag = (self.rvec == 0).all() # flag translation vs. rotation
|
|
@@ -431,7 +461,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
431
461
|
# print(loc[:])
|
|
432
462
|
yield tpos
|
|
433
463
|
|
|
434
|
-
def
|
|
464
|
+
def _get_macostheta(self, g1, tpos, rm):
|
|
435
465
|
vvec = array(g1) # velocity vector
|
|
436
466
|
ma = norm(vvec) / self.steer.env.c # machnumber
|
|
437
467
|
fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
|
|
@@ -444,30 +474,25 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
444
474
|
return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
|
|
445
475
|
return self.env._r(tpos)
|
|
446
476
|
|
|
447
|
-
def increase_buffer(self, num):
|
|
448
|
-
ar = zeros((num, self.steer.mics.num_mics), dtype=self.buffer.dtype)
|
|
449
|
-
self.buffer = concatenate((ar, self.buffer), axis=0)
|
|
450
|
-
self.bufferIndex += num
|
|
451
|
-
|
|
452
477
|
def result(self, num=2048):
|
|
453
|
-
"""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`.
|
|
454
482
|
|
|
455
483
|
Parameters
|
|
456
484
|
----------
|
|
457
|
-
num :
|
|
485
|
+
num : int
|
|
458
486
|
This parameter defines the size of the blocks to be yielded
|
|
459
|
-
(i.e. the number of samples per block).
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
The output starts for signals that were emitted
|
|
469
|
-
from the grid at `t=0`.
|
|
470
|
-
|
|
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.
|
|
471
496
|
"""
|
|
472
497
|
# initialize values
|
|
473
498
|
if self.precision == 64:
|
|
@@ -489,25 +514,17 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
489
514
|
d_index = empty((num, self.grid.size, numMics), dtype=idtype)
|
|
490
515
|
d_interp2 = empty((num, self.grid.size, numMics), dtype=fdtype)
|
|
491
516
|
blockr0 = empty((num, self.grid.size), dtype=fdtype)
|
|
492
|
-
|
|
493
|
-
self.bufferIndex = self.buffer.shape[0]
|
|
494
|
-
movgpos = self.get_moving_gpos() # create moving grid pos generator
|
|
517
|
+
movgpos = self._get_moving_gpos() # create moving grid pos generator
|
|
495
518
|
movgspeed = self.trajectory.traj(0.0, delta_t=1 / self.source.sample_freq, der=1)
|
|
496
|
-
|
|
497
|
-
for _i in range(2):
|
|
498
|
-
next(fill_buffer_generator)
|
|
519
|
+
weights = self._get_weights()
|
|
499
520
|
|
|
500
521
|
# preliminary implementation of different steering vectors
|
|
501
|
-
steer_func =
|
|
502
|
-
'classic': _steer_I,
|
|
503
|
-
'inverse': _steer_II,
|
|
504
|
-
'true level': _steer_III,
|
|
505
|
-
'true location': _steer_IV,
|
|
506
|
-
}[self.steer.steer_type]
|
|
522
|
+
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
507
523
|
|
|
508
524
|
# start processing
|
|
509
525
|
flag = True
|
|
510
|
-
|
|
526
|
+
buffer = SamplesBuffer(source=self.source, length=num * 2, shift_index_by='num', dtype=fdtype)
|
|
527
|
+
buffered_result = buffer.result(num)
|
|
511
528
|
while flag:
|
|
512
529
|
for i in range(num):
|
|
513
530
|
tpos = next(movgpos).astype(fdtype)
|
|
@@ -516,30 +533,27 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
516
533
|
blockrm[i, :, :] = rm
|
|
517
534
|
if self.conv_amp:
|
|
518
535
|
ht = next(movgspeed)
|
|
519
|
-
blockrmconv[i, :, :] = rm * (1 - self.
|
|
536
|
+
blockrmconv[i, :, :] = rm * (1 - self._get_macostheta(ht, tpos, rm)) ** 2
|
|
520
537
|
if self.conv_amp:
|
|
521
538
|
steer_func(blockrmconv, blockr0, amp)
|
|
522
539
|
else:
|
|
523
540
|
steer_func(blockrm, blockr0, amp)
|
|
524
541
|
_delays(blockrm, c, d_interp2, d_index)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
# last block may be shorter
|
|
536
|
-
if samplesleft - maxdelay <= 0:
|
|
537
|
-
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])
|
|
538
552
|
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
539
553
|
flag = False
|
|
540
554
|
# init step
|
|
541
|
-
p_res =
|
|
542
|
-
Phi, autopow = self.
|
|
555
|
+
p_res = time_block.copy()
|
|
556
|
+
Phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
543
557
|
if 'Cleant' not in self.__class__.__name__:
|
|
544
558
|
if 'Sq' not in self.__class__.__name__:
|
|
545
559
|
yield Phi[:num]
|
|
@@ -578,7 +592,7 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
578
592
|
t_float[:num, m],
|
|
579
593
|
h / blockrm1[:num, imax, m],
|
|
580
594
|
)
|
|
581
|
-
nextPhi, nextAutopow = self.
|
|
595
|
+
nextPhi, nextAutopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
582
596
|
if self.r_diag:
|
|
583
597
|
pownextPhi = (nextPhi[:num] * nextPhi[:num] - nextAutopow).sum(0).clip(min=0)
|
|
584
598
|
else:
|
|
@@ -599,13 +613,8 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
599
613
|
yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
|
|
600
614
|
else:
|
|
601
615
|
yield Gamma[:num] ** 2
|
|
602
|
-
self.bufferIndex += num
|
|
603
|
-
try:
|
|
604
|
-
next(fill_buffer_generator)
|
|
605
|
-
except:
|
|
606
|
-
dflag = False
|
|
607
616
|
|
|
608
|
-
def
|
|
617
|
+
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
609
618
|
"""Standard delay-and-sum method."""
|
|
610
619
|
fdtype = float64 if self.precision == 64 else float32
|
|
611
620
|
result = empty((num, self.grid.size), dtype=fdtype) # output array
|
|
@@ -639,12 +648,34 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
639
648
|
def _get_digest(self):
|
|
640
649
|
return digest(self)
|
|
641
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
|
+
|
|
642
673
|
|
|
643
674
|
class BeamformerCleant(BeamformerTime):
|
|
644
|
-
"""CLEANT deconvolution method
|
|
675
|
+
"""CLEANT deconvolution method.
|
|
645
676
|
|
|
646
677
|
An implementation of the CLEAN method in time domain. This class can only
|
|
647
|
-
be used for static sources.
|
|
678
|
+
be used for static sources. See :cite:`Cousson2019` for details.
|
|
648
679
|
"""
|
|
649
680
|
|
|
650
681
|
#: Boolean flag, always False
|
|
@@ -666,13 +697,34 @@ class BeamformerCleant(BeamformerTime):
|
|
|
666
697
|
def _get_digest(self):
|
|
667
698
|
return digest(self)
|
|
668
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
|
+
|
|
669
721
|
|
|
670
722
|
class BeamformerCleantSq(BeamformerCleant):
|
|
671
|
-
"""CLEANT deconvolution method
|
|
672
|
-
with optional removal of autocorrelation.
|
|
723
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
673
724
|
|
|
674
725
|
An implementation of the CLEAN method in time domain. This class can only
|
|
675
|
-
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.
|
|
676
728
|
"""
|
|
677
729
|
|
|
678
730
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -687,12 +739,35 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
687
739
|
def _get_digest(self):
|
|
688
740
|
return digest(self)
|
|
689
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
|
+
|
|
690
765
|
|
|
691
766
|
class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
692
|
-
"""CLEANT deconvolution method
|
|
767
|
+
"""CLEANT deconvolution method.
|
|
693
768
|
|
|
694
769
|
An implementation of the CLEAN method in time domain for moving sources
|
|
695
|
-
with known trajectory.
|
|
770
|
+
with known trajectory. See :cite:`Cousson2019` for details.
|
|
696
771
|
"""
|
|
697
772
|
|
|
698
773
|
#: Floating point and integer precision
|
|
@@ -718,13 +793,34 @@ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
|
718
793
|
def _get_digest(self):
|
|
719
794
|
return digest(self)
|
|
720
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
|
+
|
|
721
817
|
|
|
722
818
|
class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
723
|
-
"""CLEANT deconvolution method
|
|
724
|
-
with optional removal of autocorrelation.
|
|
819
|
+
"""CLEANT deconvolution method with optional removal of autocorrelation.
|
|
725
820
|
|
|
726
821
|
An implementation of the CLEAN method in time domain for moving sources
|
|
727
|
-
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.
|
|
728
824
|
"""
|
|
729
825
|
|
|
730
826
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
@@ -751,10 +847,36 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
751
847
|
def _get_digest(self):
|
|
752
848
|
return digest(self)
|
|
753
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`.
|
|
754
856
|
|
|
755
|
-
|
|
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):
|
|
756
875
|
"""Provides an Integrator in the time domain."""
|
|
757
876
|
|
|
877
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
878
|
+
source = Instance(SamplesGenerator)
|
|
879
|
+
|
|
758
880
|
#: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
|
|
759
881
|
grid = Trait(RectGrid, desc='beamforming grid')
|
|
760
882
|
|