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/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 numpy.linalg import norm
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, _steer_I, _steer_II, _steer_III, _steer_IV
58
- from .tprocess import TimeInOut
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(TimeInOut):
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
- "Deprecated use of 'steer' trait. Please use object of class 'SteeringVector' in the future.",
121
- Warning,
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
- warn("Deprecated use of 'env' trait. ", Warning, stacklevel=2)
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
- warn("Deprecated use of 'c' trait. ", Warning, stacklevel=2)
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
- warn("Deprecated use of 'grid' trait. ", Warning, stacklevel=2)
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
- warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
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 *squared* deconvolved beamformer
233
- output with optional removal of autocorrelation block-wise.
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 : integer, defaults to 2048
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
- Returns
242
- -------
243
- Samples in blocks of shape \
244
- (num, :attr:`~BeamformerTime.numchannels`).
245
- :attr:`~BeamformerTime.numchannels` is usually very \
246
- large (number of grid points).
247
- The last block may be shorter than num. \
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
- _steer_III(self.rm[newaxis, :, :], self.r0[newaxis, :], amp)
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
- maxdelay = int((self.rm / c).max()) + 2 + num # +2 because of interpolation
269
- initialNumberOfBlocks = int(ceil(maxdelay / num))
270
- bufferSize = initialNumberOfBlocks * num
271
- self.buffer = zeros((bufferSize, numMics), dtype=float)
272
- self.bufferIndex = bufferSize # indexing current time sample in buffer
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
- # start processing
278
- flag = True
279
- while flag:
280
- samplesleft = self.buffer.shape[0] - self.bufferIndex
281
- if samplesleft - maxdelay <= 0:
282
- num += samplesleft - maxdelay
283
- maxdelay += samplesleft - maxdelay
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
- p_res = array(self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :])
288
- Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
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
- p_res[t_ind[: num + 1, m], m] -= self.damp * interp(
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.delay_and_sum(num, p_res, d_interp2, d_index, amp)
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 delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
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 get_moving_gpos(self):
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.pos()
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 get_macostheta(self, g1, tpos, rm):
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 deconvolved output block-wise.
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 : integer, defaults to 2048
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
- Returns
461
- -------
462
- Samples in blocks of shape \
463
- (num, :attr:`~BeamformerTime.numchannels`).
464
- :attr:`~BeamformerTime.numchannels` is usually very \
465
- large (number of grid points).
466
- The last block may be shorter than num. \
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
- self.buffer = zeros((2 * num, numMics), dtype=fdtype)
492
- self.bufferIndex = self.buffer.shape[0]
493
- movgpos = self.get_moving_gpos() # create moving grid pos generator
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
- fill_buffer_generator = self._fill_buffer(num)
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
- dflag = True # data is available
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.get_macostheta(ht, tpos, rm)) ** 2
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
- # _modf(delays, d_interp2, d_index)
525
- maxdelay = (d_index.max((1, 2)) + arange(0, num)).max() + 2 # + because of interpolation
526
- # increase buffer size because of greater delays
527
- while maxdelay > self.buffer.shape[0] and dflag:
528
- self.increase_buffer(num)
529
- try:
530
- next(fill_buffer_generator)
531
- except StopIteration:
532
- dflag = False
533
- samplesleft = self.buffer.shape[0] - self.bufferIndex
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 = self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :].copy()
541
- Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
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.delay_and_sum(num, p_res, d_interp2, d_index, amp)
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 delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
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, see :ref:`Cousson et al., 2019<Cousson2019>`.
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, see :ref:`Cousson et al., 2019<Cousson2019>`
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, see :ref:`Cousson et al., 2019<Cousson2019>`.
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, see :ref:`Cousson et al., 2019<Cousson2019>`
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
- class IntegratorSectorTime(TimeInOut):
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