acoular 25.4__py3-none-any.whl → 25.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/fbeamform.py CHANGED
@@ -1,7 +1,16 @@
1
1
  # ------------------------------------------------------------------------------
2
2
  # Copyright (c) Acoular Development Team.
3
3
  # ------------------------------------------------------------------------------
4
- """Implements beamformers in the frequency domain.
4
+ """
5
+ Implements beamformers in the frequency domain.
6
+
7
+ .. inheritance-diagram::
8
+ acoular.fbeamform.BeamformerBase
9
+ :include-subclasses:
10
+ :top-classes:
11
+ acoular.grids.Grid,
12
+ acoular.fbeamform.BeamformerBase
13
+ :parts: 1
5
14
 
6
15
  .. autosummary::
7
16
  :toctree: generated/
@@ -28,7 +37,6 @@
28
37
  PointSpreadFunction
29
38
  L_p
30
39
  integrate
31
-
32
40
  """
33
41
 
34
42
  # imports from other packages
@@ -36,53 +44,12 @@
36
44
  import warnings
37
45
  from warnings import warn
38
46
 
47
+ import numpy as np
48
+ import scipy.linalg as spla
49
+
39
50
  # check for sklearn version to account for incompatible behavior
40
51
  import sklearn
41
- from numpy import (
42
- absolute,
43
- arange,
44
- argsort,
45
- array,
46
- atleast_2d,
47
- clip,
48
- delete,
49
- diag,
50
- dot,
51
- einsum,
52
- einsum_path,
53
- eye,
54
- fill_diagonal,
55
- full,
56
- hsplit,
57
- hstack,
58
- index_exp,
59
- inf,
60
- integer,
61
- invert,
62
- isscalar,
63
- log10,
64
- ndarray,
65
- newaxis,
66
- ones,
67
- pi,
68
- real,
69
- reshape,
70
- round, # noqa: A004
71
- searchsorted,
72
- sign,
73
- size,
74
- sqrt,
75
- sum, # noqa: A004
76
- tile,
77
- trace,
78
- tril,
79
- unique,
80
- vstack,
81
- zeros,
82
- zeros_like,
83
- )
84
52
  from packaging.version import parse
85
- from scipy.linalg import eigh, eigvals, fractional_matrix_power, inv, norm
86
53
  from scipy.optimize import fmin_l_bfgs_b, linprog, nnls, shgo
87
54
  from sklearn.linear_model import LassoLars, LassoLarsCV, LassoLarsIC, LinearRegression, OrthogonalMatchingPursuitCV
88
55
  from traits.api import (
@@ -100,14 +67,13 @@ from traits.api import (
100
67
  Range,
101
68
  Tuple,
102
69
  cached_property,
103
- on_trait_change,
70
+ observe,
104
71
  property_depends_on,
105
72
  )
106
73
  from traits.trait_errors import TraitError
107
74
 
108
75
  # acoular imports
109
76
  from .configuration import config
110
- from .deprecation import deprecated_alias
111
77
  from .environments import Environment
112
78
  from .fastFuncs import beamformerFreq, calcPointSpreadFunction, calcTransfer, damasSolverGaussSeidel
113
79
  from .grids import Grid, Sector
@@ -126,7 +92,8 @@ BEAMFORMER_BASE_DIGEST_DEPENDENCIES = ['freq_data.digest', 'r_diag', 'r_diag_nor
126
92
 
127
93
 
128
94
  class SteeringVector(HasStrictTraits):
129
- """Basic class for implementing steering vectors with monopole source transfer models.
95
+ """
96
+ Basic class for implementing steering vectors with monopole source transfer models.
130
97
 
131
98
  Handles four different steering vector formulations. See :cite:`Sarradj2012` for details.
132
99
  """
@@ -154,7 +121,7 @@ class SteeringVector(HasStrictTraits):
154
121
  rm = Property(desc='all array mics to grid distances')
155
122
 
156
123
  # mirror trait for ref
157
- _ref = Any(array([0.0, 0.0, 0.0]), desc='reference position or distance')
124
+ _ref = Any(np.array([0.0, 0.0, 0.0]), desc='reference position or distance')
158
125
 
159
126
  #: Reference position or distance at which to evaluate the sound pressure
160
127
  #: of a grid point.
@@ -165,10 +132,10 @@ class SteeringVector(HasStrictTraits):
165
132
 
166
133
  _steer_funcs_freq = Dict(
167
134
  {
168
- 'classic': lambda x: x / absolute(x) / x.shape[-1],
135
+ 'classic': lambda x: x / np.abs(x) / x.shape[-1],
169
136
  'inverse': lambda x: 1.0 / x.conj() / x.shape[-1],
170
- 'true level': lambda x: x / einsum('ij,ij->i', x, x.conj())[:, newaxis],
171
- 'true location': lambda x: x / sqrt(einsum('ij,ij->i', x, x.conj()) * x.shape[-1])[:, newaxis],
137
+ 'true level': lambda x: x / np.einsum('ij,ij->i', x, x.conj())[:, np.newaxis],
138
+ 'true location': lambda x: x / np.sqrt(np.einsum('ij,ij->i', x, x.conj()) * x.shape[-1])[:, np.newaxis],
172
139
  },
173
140
  transient=True,
174
141
  desc='dictionary of frequency domain steering vector functions',
@@ -186,13 +153,13 @@ class SteeringVector(HasStrictTraits):
186
153
  )
187
154
 
188
155
  def _set_ref(self, ref):
189
- if isscalar(ref):
156
+ if np.isscalar(ref):
190
157
  try:
191
- self._ref = absolute(float(ref))
158
+ self._ref = np.abs(float(ref))
192
159
  except ValueError as ve:
193
160
  raise TraitError(args=self, name='ref', info='Float or CArray(3,)', value=ref) from ve
194
161
  elif len(ref) == 3:
195
- self._ref = array(ref, dtype=float)
162
+ self._ref = np.array(ref, dtype=float)
196
163
  else:
197
164
  raise TraitError(args=self, name='ref', info='Float or CArray(3,)', value=ref)
198
165
 
@@ -207,15 +174,15 @@ class SteeringVector(HasStrictTraits):
207
174
 
208
175
  @property_depends_on(['grid.digest', 'env.digest', '_ref'])
209
176
  def _get_r0(self):
210
- if isscalar(self.ref):
177
+ if np.isscalar(self.ref):
211
178
  if self.ref > 0:
212
- return full((self.grid.size,), self.ref)
179
+ return np.full((self.grid.size,), self.ref)
213
180
  return self.env._r(self.grid.pos())
214
- return self.env._r(self.grid.pos, self.ref[:, newaxis])
181
+ return self.env._r(self.grid.pos, self.ref[:, np.newaxis])
215
182
 
216
183
  @property_depends_on(['grid.digest', 'mics.digest', 'env.digest'])
217
184
  def _get_rm(self):
218
- return atleast_2d(self.env._r(self.grid.pos, self.mics.pos))
185
+ return np.atleast_2d(self.env._r(self.grid.pos, self.mics.pos))
219
186
 
220
187
  @cached_property
221
188
  def _get_digest(self):
@@ -226,7 +193,8 @@ class SteeringVector(HasStrictTraits):
226
193
  return digest(self)
227
194
 
228
195
  def transfer(self, f, ind=None):
229
- """Calculates the transfer matrix for one frequency.
196
+ """
197
+ Calculates the transfer matrix for one frequency.
230
198
 
231
199
  Parameters
232
200
  ----------
@@ -241,22 +209,22 @@ class SteeringVector(HasStrictTraits):
241
209
  -------
242
210
  array of complex128
243
211
  array of shape (ngridpts, nmics) containing the transfer matrix for the given frequency
244
-
245
212
  """
246
213
  # if self.cached:
247
214
  # warn('Caching of transfer function is not yet supported!', Warning)
248
215
  # self.cached = False
249
216
 
250
217
  if ind is None:
251
- trans = calcTransfer(self.r0, self.rm, array(2 * pi * f / self.env.c))
252
- elif not isinstance(ind, ndarray):
253
- trans = calcTransfer(self.r0[ind], self.rm[ind, :][newaxis], array(2 * pi * f / self.env.c)) # [0, :]
218
+ trans = calcTransfer(self.r0, self.rm, np.array(2 * np.pi * f / self.env.c))
219
+ elif not isinstance(ind, np.ndarray):
220
+ trans = calcTransfer(self.r0[ind], self.rm[ind, :][np.newaxis], np.array(2 * np.pi * f / self.env.c))
254
221
  else:
255
- trans = calcTransfer(self.r0[ind], self.rm[ind, :], array(2 * pi * f / self.env.c))
222
+ trans = calcTransfer(self.r0[ind], self.rm[ind, :], np.array(2 * np.pi * f / self.env.c))
256
223
  return trans
257
224
 
258
225
  def steer_vector(self, f, ind=None):
259
- """Calculates the steering vectors based on the transfer function.
226
+ """
227
+ Calculates the steering vectors based on the transfer function.
260
228
 
261
229
  See also :cite:`Sarradj2012`.
262
230
 
@@ -273,7 +241,6 @@ class SteeringVector(HasStrictTraits):
273
241
  -------
274
242
  array of complex128
275
243
  array of shape (ngridpts, nmics) containing the steering vectors for the given frequency
276
-
277
244
  """
278
245
  func = self._steer_funcs_freq[self.steer_type]
279
246
  return func(self.transfer(f, ind))
@@ -292,12 +259,12 @@ class LazyBfResult:
292
259
  self.bf = bf
293
260
 
294
261
  def __getitem__(self, key):
295
- # 'intelligent' [] operator checks if results are available and triggers calculation
296
- sl = index_exp[key][0]
297
- if isinstance(sl, (int, integer)):
262
+ """'intelligent' [] operator, checks if results are available and triggers calculation."""
263
+ sl = np.index_exp[key][0]
264
+ if isinstance(sl, (int, np.integer)):
298
265
  sl = slice(sl, sl + 1)
299
266
  # indices which are missing
300
- missingind = arange(*sl.indices(self.bf._numfreq))[self.bf._fr[sl] == 0]
267
+ missingind = np.arange(*sl.indices(self.bf._numfreq))[self.bf._fr[sl] == 0]
301
268
  # calc if needed
302
269
  if missingind.size:
303
270
  self.bf._calc(missingind)
@@ -362,9 +329,10 @@ class BeamformerBase(HasStrictTraits):
362
329
  return digest(self)
363
330
 
364
331
  def _get_filecache(self):
365
- """Function collects cached results from file depending on
366
- global/local caching behaviour. Returns (None, None) if no cachefile/data
367
- exist and global caching mode is 'readonly'.
332
+ """
333
+ Function collects cached results from file depending on global/local caching behaviour.
334
+
335
+ Returns (None, None) if no cachefile/data exist and global caching mode is 'readonly'.
368
336
  """
369
337
  # print("get cachefile:", self.freq_data.basename)
370
338
  H5cache.get_cache_file(self, self.freq_data.basename)
@@ -419,7 +387,9 @@ class BeamformerBase(HasStrictTraits):
419
387
 
420
388
  @property_depends_on(['digest'])
421
389
  def _get_result(self):
422
- """Implements the :attr:`result` getter routine.
390
+ """
391
+ Implements the :attr:`result` getter routine.
392
+
423
393
  The beamforming result is either loaded or calculated.
424
394
  """
425
395
  # store locally for performance
@@ -439,20 +409,22 @@ class BeamformerBase(HasStrictTraits):
439
409
  else:
440
410
  # no caching or not activated, init numpy arrays
441
411
  if isinstance(self, BeamformerAdaptiveGrid):
442
- self._gpos = zeros((3, self.size), dtype=self.precision)
443
- ac = zeros((self._numfreq, self.size), dtype=self.precision)
412
+ self._gpos = np.zeros((3, self.size), dtype=self.precision)
413
+ ac = np.zeros((self._numfreq, self.size), dtype=self.precision)
444
414
  elif isinstance(self, BeamformerSODIX):
445
- ac = zeros((self._numfreq, self.steer.grid.size * self.steer.mics.num_mics), dtype=self.precision)
415
+ ac = np.zeros((self._numfreq, self.steer.grid.size * self.steer.mics.num_mics), dtype=self.precision)
446
416
  else:
447
- ac = zeros((self._numfreq, self.steer.grid.size), dtype=self.precision)
448
- fr = zeros(self._numfreq, dtype='int8')
417
+ ac = np.zeros((self._numfreq, self.steer.grid.size), dtype=self.precision)
418
+ fr = np.zeros(self._numfreq, dtype='int8')
449
419
  self._ac = ac
450
420
  self._fr = fr
451
421
  return LazyBfResult(self)
452
422
 
453
423
  def sig_loss_norm(self):
454
- """If the diagonal of the CSM is removed one has to handle the loss
455
- of signal energy --> Done via a normalization factor.
424
+ """
425
+ If the diagonal of the CSM is removed one has to handle the loss of signal energy.
426
+
427
+ Done via a normalization factor.
456
428
  """
457
429
  if not self.r_diag: # Full CSM --> no normalization needed
458
430
  normfactor = 1.0
@@ -464,28 +436,29 @@ class BeamformerBase(HasStrictTraits):
464
436
  return normfactor
465
437
 
466
438
  def _beamformer_params(self):
467
- """Manages the parameters for calling of the core beamformer functionality.
468
- This is a workaround to allow faster calculation and may change in the
469
- future.
439
+ """
440
+ Manages the parameters for calling of the core beamformer functionality.
441
+
442
+ This is a workaround to allow faster calculation and may change in the future.
470
443
 
471
444
  Returns
472
445
  -------
473
446
  - String containing the steering vector type
474
447
  - Function for frequency-dependent steering vector calculation
475
-
476
448
  """
477
449
  if type(self.steer) is SteeringVector: # for simple steering vector, use faster method
478
450
  param_type = self.steer.steer_type
479
451
 
480
452
  def param_steer_func(f):
481
- return (self.steer.r0, self.steer.rm, 2 * pi * f / self.steer.env.c)
453
+ return (self.steer.r0, self.steer.rm, 2 * np.pi * f / self.steer.env.c)
482
454
  else:
483
455
  param_type = 'custom'
484
456
  param_steer_func = self.steer.steer_vector
485
457
  return param_type, param_steer_func
486
458
 
487
459
  def _calc(self, ind):
488
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
460
+ """
461
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
489
462
 
490
463
  This is an internal helper function that is automatically called when
491
464
  accessing the beamformer's :attr:`result` or calling
@@ -500,14 +473,13 @@ class BeamformerBase(HasStrictTraits):
500
473
  Returns
501
474
  -------
502
475
  This method only returns values through :attr:`_ac` and :attr:`_fr`
503
-
504
476
  """
505
477
  f = self._f
506
478
  normfactor = self.sig_loss_norm()
507
479
  param_steer_type, steer_vector = self._beamformer_params()
508
480
  for i in ind:
509
481
  # print(f'compute{i}')
510
- csm = array(self.freq_data.csm[i], dtype='complex128')
482
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
511
483
  beamformerOutput = beamformerFreq(
512
484
  param_steer_type,
513
485
  self.r_diag,
@@ -516,13 +488,14 @@ class BeamformerBase(HasStrictTraits):
516
488
  csm,
517
489
  )[0]
518
490
  if self.r_diag: # set (unphysical) negative output values to 0
519
- indNegSign = sign(beamformerOutput) < 0
491
+ indNegSign = np.sign(beamformerOutput) < 0
520
492
  beamformerOutput[indNegSign] = 0.0
521
493
  self._ac[i] = beamformerOutput
522
494
  self._fr[i] = 1
523
495
 
524
496
  def synthetic(self, f, num=0):
525
- """Evaluates the beamforming result for an arbitrary frequency band.
497
+ """
498
+ Evaluates the beamforming result for an arbitrary frequency band.
526
499
 
527
500
  Parameters
528
501
  ----------
@@ -550,7 +523,6 @@ class BeamformerBase(HasStrictTraits):
550
523
  represented by a single frequency line depends on
551
524
  the :attr:`sampling frequency<acoular.base.SamplesGenerator.sample_freq>` and
552
525
  used :attr:`FFT block size<acoular.spectra.PowerSpectra.block_size>`.
553
-
554
526
  """
555
527
  res = self.result # trigger calculation
556
528
  freq = self.freq_data.fftfreq()
@@ -559,14 +531,14 @@ class BeamformerBase(HasStrictTraits):
559
531
 
560
532
  if num == 0:
561
533
  # single frequency line
562
- ind = searchsorted(freq, f)
534
+ ind = np.searchsorted(freq, f)
563
535
  if ind >= len(freq):
564
536
  warn(
565
537
  f'Queried frequency ({f:g} Hz) not in resolved frequency range. Returning zeros.',
566
538
  Warning,
567
539
  stacklevel=2,
568
540
  )
569
- h = zeros_like(res[0])
541
+ h = np.zeros_like(res[0])
570
542
  else:
571
543
  if freq[ind] != f:
572
544
  warn(
@@ -585,8 +557,8 @@ class BeamformerBase(HasStrictTraits):
585
557
  else:
586
558
  f1 = f * 2.0 ** (-0.5 / num)
587
559
  f2 = f * 2.0 ** (+0.5 / num)
588
- ind1 = searchsorted(freq, f1)
589
- ind2 = searchsorted(freq, f2)
560
+ ind1 = np.searchsorted(freq, f1)
561
+ ind2 = np.searchsorted(freq, f2)
590
562
  if ind1 == ind2:
591
563
  warn(
592
564
  f'Queried frequency band ({f1:g} to {f2:g} Hz) does not '
@@ -595,9 +567,9 @@ class BeamformerBase(HasStrictTraits):
595
567
  Warning,
596
568
  stacklevel=2,
597
569
  )
598
- h = zeros_like(res[0])
570
+ h = np.zeros_like(res[0])
599
571
  else:
600
- h = sum(res[ind1:ind2], 0)
572
+ h = np.sum(res[ind1:ind2], 0)
601
573
  if isinstance(self, BeamformerAdaptiveGrid):
602
574
  return h
603
575
  if isinstance(self, BeamformerSODIX):
@@ -605,7 +577,8 @@ class BeamformerBase(HasStrictTraits):
605
577
  return h.reshape(self.steer.grid.shape)
606
578
 
607
579
  def integrate(self, sector, frange=None, num=0):
608
- """Integrates result map over a given sector.
580
+ """
581
+ Integrates result map over a given sector.
609
582
 
610
583
  Parameters
611
584
  ----------
@@ -662,45 +635,43 @@ class BeamformerBase(HasStrictTraits):
662
635
  msg,
663
636
  )
664
637
  gshape = self.steer.grid.shape
638
+ num_freqs = self.freq_data.fftfreq().shape[0]
665
639
  if num == 0 or frange is None:
666
640
  if frange is None:
667
641
  ind_low = self.freq_data.ind_low
668
642
  ind_high = self.freq_data.ind_high
669
643
  if ind_low is None:
670
644
  ind_low = 0
671
- if ind_low < 0:
672
- ind_low += self._numfreq
673
645
  if ind_high is None:
674
- ind_high = self._numfreq
675
- if ind_high < 0:
676
- ind_high += self._numfreq
646
+ ind_high = num_freqs
677
647
  irange = (ind_low, ind_high)
678
648
  num = 0
679
649
  elif len(frange) == 2:
680
- irange = (searchsorted(self._f, frange[0]), searchsorted(self._f, frange[1]))
650
+ irange = (np.searchsorted(self._f, frange[0]), np.searchsorted(self._f, frange[1]))
681
651
  else:
682
652
  msg = 'Only a tuple of length 2 is allowed for frange if num==0'
683
653
  raise TypeError(
684
654
  msg,
685
655
  )
686
- h = zeros(self._numfreq, dtype=float)
656
+ h = np.zeros(num_freqs, dtype=float)
687
657
  sl = slice(*irange)
688
658
  r = self.result[sl]
689
- for i in range(*irange):
659
+ for i in range(num_freqs)[sl]:
690
660
  # we do this per frequency because r might not have fancy indexing
691
661
  h[i] = r[i - sl.start].reshape(gshape)[ind].sum()
692
662
  if frange is None:
693
663
  return h
694
664
  return self._f[sl], h[sl]
695
665
 
696
- h = zeros(len(frange), dtype=float)
666
+ h = np.zeros(len(frange), dtype=float)
697
667
  for i, f in enumerate(frange):
698
668
  h[i] = self.synthetic(f, num).reshape(gshape)[ind].sum()
699
669
  return h
700
670
 
701
671
 
702
672
  class BeamformerFunctional(BeamformerBase):
703
- """Functional beamforming algorithm.
673
+ """
674
+ Functional beamforming algorithm.
704
675
 
705
676
  See :cite:`Dougherty2014` for details.
706
677
  """
@@ -726,7 +697,8 @@ class BeamformerFunctional(BeamformerBase):
726
697
  return digest(self)
727
698
 
728
699
  def _calc(self, ind):
729
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
700
+ """
701
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
730
702
 
731
703
  This is an internal helper function that is automatically called when
732
704
  accessing the beamformer's :attr:`result` or calling
@@ -741,7 +713,6 @@ class BeamformerFunctional(BeamformerBase):
741
713
  Returns
742
714
  -------
743
715
  This method only returns values through :attr:`_ac` and :attr:`_fr`
744
-
745
716
  """
746
717
  f = self._f
747
718
  normfactor = self.sig_loss_norm()
@@ -759,8 +730,8 @@ class BeamformerFunctional(BeamformerBase):
759
730
  # WATCH OUT: This doesn't really produce good results.
760
731
  # ==============================================================================
761
732
  csm = self.freq_data.csm[i]
762
- fill_diagonal(csm, 0)
763
- csmRoot = fractional_matrix_power(csm, 1.0 / self.gamma)
733
+ np.fill_diagonal(csm, 0)
734
+ csmRoot = spla.fractional_matrix_power(csm, 1.0 / self.gamma)
764
735
  beamformerOutput, steerNorm = beamformerFreq(
765
736
  param_steer_type,
766
737
  self.r_diag,
@@ -771,11 +742,11 @@ class BeamformerFunctional(BeamformerBase):
771
742
  beamformerOutput /= steerNorm # take normalized steering vec
772
743
 
773
744
  # set (unphysical) negative output values to 0
774
- indNegSign = sign(beamformerOutput) < 0
745
+ indNegSign = np.sign(beamformerOutput) < 0
775
746
  beamformerOutput[indNegSign] = 0.0
776
747
  else:
777
- eva = array(self.freq_data.eva[i], dtype='float64') ** (1.0 / self.gamma)
778
- eve = array(self.freq_data.eve[i], dtype='complex128')
748
+ eva = np.array(self.freq_data.eva[i], dtype='float64') ** (1.0 / self.gamma)
749
+ eve = np.array(self.freq_data.eve[i], dtype='complex128')
779
750
  beamformerOutput, steerNorm = beamformerFreq(
780
751
  param_steer_type,
781
752
  self.r_diag,
@@ -791,7 +762,8 @@ class BeamformerFunctional(BeamformerBase):
791
762
 
792
763
 
793
764
  class BeamformerCapon(BeamformerBase):
794
- """Beamforming using the Capon (Mininimum Variance) algorithm.
765
+ """
766
+ Beamforming using the Capon (Mininimum Variance) algorithm.
795
767
 
796
768
  See :cite:`Capon1969` for details.
797
769
  """
@@ -808,7 +780,8 @@ class BeamformerCapon(BeamformerBase):
808
780
  )
809
781
 
810
782
  def _calc(self, ind):
811
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
783
+ """
784
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
812
785
 
813
786
  This is an internal helper function that is automatically called when
814
787
  accessing the beamformer's :attr:`result` or calling
@@ -823,21 +796,21 @@ class BeamformerCapon(BeamformerBase):
823
796
  Returns
824
797
  -------
825
798
  This method only returns values through :attr:`_ac` and :attr:`_fr`
826
-
827
799
  """
828
800
  f = self._f
829
801
  nMics = self.freq_data.num_channels
830
802
  normfactor = self.sig_loss_norm() * nMics**2
831
803
  param_steer_type, steer_vector = self._beamformer_params()
832
804
  for i in ind:
833
- csm = array(inv(array(self.freq_data.csm[i], dtype='complex128')), order='C')
805
+ csm = np.array(spla.inv(np.array(self.freq_data.csm[i], dtype='complex128')), order='C')
834
806
  beamformerOutput = beamformerFreq(param_steer_type, self.r_diag, normfactor, steer_vector(f[i]), csm)[0]
835
807
  self._ac[i] = 1.0 / beamformerOutput
836
808
  self._fr[i] = 1
837
809
 
838
810
 
839
811
  class BeamformerEig(BeamformerBase):
840
- """Beamforming using eigenvalue and eigenvector techniques.
812
+ """
813
+ Beamforming using eigenvalue and eigenvector techniques.
841
814
 
842
815
  See :cite:`Sarradj2005` for details.
843
816
  """
@@ -866,7 +839,8 @@ class BeamformerEig(BeamformerBase):
866
839
  return min(nm - 1, na)
867
840
 
868
841
  def _calc(self, ind):
869
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
842
+ """
843
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
870
844
 
871
845
  This is an internal helper function that is automatically called when
872
846
  accessing the beamformer's :attr:`result` or calling
@@ -881,15 +855,14 @@ class BeamformerEig(BeamformerBase):
881
855
  Returns
882
856
  -------
883
857
  This method only returns values through :attr:`_ac` and :attr:`_fr`
884
-
885
858
  """
886
859
  f = self._f
887
860
  na = int(self.na) # eigenvalue taken into account
888
861
  normfactor = self.sig_loss_norm()
889
862
  param_steer_type, steer_vector = self._beamformer_params()
890
863
  for i in ind:
891
- eva = array(self.freq_data.eva[i], dtype='float64')
892
- eve = array(self.freq_data.eve[i], dtype='complex128')
864
+ eva = np.array(self.freq_data.eva[i], dtype='float64')
865
+ eve = np.array(self.freq_data.eve[i], dtype='complex128')
893
866
  beamformerOutput = beamformerFreq(
894
867
  param_steer_type,
895
868
  self.r_diag,
@@ -898,14 +871,15 @@ class BeamformerEig(BeamformerBase):
898
871
  (eva[na : na + 1], eve[:, na : na + 1]),
899
872
  )[0]
900
873
  if self.r_diag: # set (unphysical) negative output values to 0
901
- indNegSign = sign(beamformerOutput) < 0
874
+ indNegSign = np.sign(beamformerOutput) < 0
902
875
  beamformerOutput[indNegSign] = 0
903
876
  self._ac[i] = beamformerOutput
904
877
  self._fr[i] = 1
905
878
 
906
879
 
907
880
  class BeamformerMusic(BeamformerEig):
908
- """Beamforming using the MUSIC algorithm.
881
+ """
882
+ Beamforming using the MUSIC algorithm.
909
883
 
910
884
  See :cite:`Schmidt1986` for details.
911
885
  """
@@ -926,7 +900,8 @@ class BeamformerMusic(BeamformerEig):
926
900
  n = Int(1, desc='assumed number of sources')
927
901
 
928
902
  def _calc(self, ind):
929
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
903
+ """
904
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
930
905
 
931
906
  This is an internal helper function that is automatically called when
932
907
  accessing the beamformer's :attr:`result` or calling
@@ -941,7 +916,6 @@ class BeamformerMusic(BeamformerEig):
941
916
  Returns
942
917
  -------
943
918
  This method only returns values through :attr:`_ac` and :attr:`_fr`
944
-
945
919
  """
946
920
  f = self._f
947
921
  nMics = self.freq_data.num_channels
@@ -949,8 +923,8 @@ class BeamformerMusic(BeamformerEig):
949
923
  normfactor = self.sig_loss_norm() * nMics**2
950
924
  param_steer_type, steer_vector = self._beamformer_params()
951
925
  for i in ind:
952
- eva = array(self.freq_data.eva[i], dtype='float64')
953
- eve = array(self.freq_data.eve[i], dtype='complex128')
926
+ eva = np.array(self.freq_data.eva[i], dtype='float64')
927
+ eve = np.array(self.freq_data.eve[i], dtype='complex128')
954
928
  beamformerOutput = beamformerFreq(
955
929
  param_steer_type,
956
930
  self.r_diag,
@@ -963,7 +937,8 @@ class BeamformerMusic(BeamformerEig):
963
937
 
964
938
 
965
939
  class PointSpreadFunction(HasStrictTraits):
966
- """The point spread function.
940
+ """
941
+ The point spread function.
967
942
 
968
943
  This class provides tools to calculate the PSF depending on the used
969
944
  microphone geometry, focus grid, flow environment, etc.
@@ -979,7 +954,7 @@ class PointSpreadFunction(HasStrictTraits):
979
954
  #: Indices of grid points to calculate the PSF for.
980
955
  grid_indices = CArray(
981
956
  dtype=int,
982
- value=array([]),
957
+ value=np.array([]),
983
958
  desc='indices of grid points for psf',
984
959
  ) # value=array([]), value=self.steer.grid.pos(),
985
960
 
@@ -1016,9 +991,10 @@ class PointSpreadFunction(HasStrictTraits):
1016
991
  return digest(self)
1017
992
 
1018
993
  def _get_filecache(self):
1019
- """Function collects cached results from file depending on
1020
- global/local caching behaviour. Returns (None, None) if no cachefile/data
1021
- exist and global caching mode is 'readonly'.
994
+ """
995
+ Function collects cached results from file depending on global/local caching behaviour.
996
+
997
+ Returns (None, None) if no cachefile/data exist and global caching mode is 'readonly'.
1022
998
  """
1023
999
  filename = 'psf' + self.digest
1024
1000
  nodename = (f'Hz_{self.freq:.2f}').replace('.', '_')
@@ -1050,12 +1026,14 @@ class PointSpreadFunction(HasStrictTraits):
1050
1026
  return (ac, gp)
1051
1027
 
1052
1028
  def _get_psf(self):
1053
- """Implements the :attr:`psf` getter routine.
1029
+ """
1030
+ Implements the :attr:`psf` getter routine.
1031
+
1054
1032
  The point spread function is either loaded or calculated.
1055
1033
  """
1056
1034
  gs = self.steer.grid.size
1057
1035
  if not self.grid_indices.size:
1058
- self.grid_indices = arange(gs)
1036
+ self.grid_indices = np.arange(gs)
1059
1037
 
1060
1038
  if config.global_caching != 'none':
1061
1039
  # print("get filecache..")
@@ -1078,13 +1056,13 @@ class PointSpreadFunction(HasStrictTraits):
1078
1056
  # print("cached results are complete! return.")
1079
1057
  return ac[:, self.grid_indices]
1080
1058
  # print("no caching, calculate result")
1081
- ac = zeros((gs, gs), dtype=self.precision)
1082
- gp = zeros((gs,), dtype='int8')
1059
+ ac = np.zeros((gs, gs), dtype=self.precision)
1060
+ gp = np.zeros((gs,), dtype='int8')
1083
1061
  self.calc_psf(ac, gp)
1084
1062
  else: # no caching activated
1085
1063
  # print("no caching activated, calculate result")
1086
- ac = zeros((gs, gs), dtype=self.precision)
1087
- gp = zeros((gs,), dtype='int8')
1064
+ ac = np.zeros((gs, gs), dtype=self.precision)
1065
+ gp = np.zeros((gs,), dtype='int8')
1088
1066
  self.calc_psf(ac, gp)
1089
1067
  return ac[:, self.grid_indices]
1090
1068
 
@@ -1093,7 +1071,7 @@ class PointSpreadFunction(HasStrictTraits):
1093
1071
  if self.calcmode != 'full':
1094
1072
  # calc_ind has the form [True, True, False, True], except
1095
1073
  # when it has only 1 entry (value True/1 would be ambiguous)
1096
- calc_ind = [0] if self.grid_indices.size == 1 else invert(gp[:][self.grid_indices])
1074
+ calc_ind = [0] if self.grid_indices.size == 1 else np.invert(gp[:][self.grid_indices])
1097
1075
 
1098
1076
  # get indices which have the value True = not yet calculated
1099
1077
  g_ind_calc = self.grid_indices[calc_ind]
@@ -1104,7 +1082,7 @@ class PointSpreadFunction(HasStrictTraits):
1104
1082
  gp[ind] = 1
1105
1083
  elif self.calcmode == 'full': # calculate all psfs in one go
1106
1084
  gp[:] = 1
1107
- ac[:] = self._psf_call(arange(self.steer.grid.size))
1085
+ ac[:] = self._psf_call(np.arange(self.steer.grid.size))
1108
1086
  else: # 'block' # calculate selected psfs in one go
1109
1087
  hh = self._psf_call(g_ind_calc)
1110
1088
  for indh, ind in enumerate(g_ind_calc):
@@ -1113,7 +1091,8 @@ class PointSpreadFunction(HasStrictTraits):
1113
1091
  indh += 1
1114
1092
 
1115
1093
  def _psf_call(self, ind):
1116
- """Manages the calling of the core psf functionality.
1094
+ """
1095
+ Manages the calling of the core psf functionality.
1117
1096
 
1118
1097
  Parameters
1119
1098
  ----------
@@ -1130,32 +1109,25 @@ class PointSpreadFunction(HasStrictTraits):
1130
1109
  self.steer.steer_type,
1131
1110
  self.steer.r0,
1132
1111
  self.steer.rm,
1133
- 2 * pi * self.freq / self.steer.env.c,
1112
+ 2 * np.pi * self.freq / self.steer.env.c,
1134
1113
  ind,
1135
1114
  self.precision,
1136
1115
  )
1137
1116
  else:
1138
1117
  # for arbitrary steering sectors, use general calculation. there is a version of this in
1139
1118
  # fastFuncs, may be used later after runtime testing and debugging
1140
- product = dot(self.steer.steer_vector(self.freq).conj(), self.steer.transfer(self.freq, ind).T)
1119
+ product = np.dot(self.steer.steer_vector(self.freq).conj(), self.steer.transfer(self.freq, ind).T)
1141
1120
  result = (product * product.conj()).real
1142
1121
  return result
1143
1122
 
1144
1123
 
1145
1124
  class BeamformerDamas(BeamformerBase):
1146
- """DAMAS deconvolution algorithm.
1125
+ """
1126
+ DAMAS deconvolution algorithm.
1147
1127
 
1148
1128
  See :cite:`Brooks2006` for details.
1149
1129
  """
1150
1130
 
1151
- #: (only for backward compatibility) :class:`BeamformerBase` object
1152
- #: if set, provides :attr:`freq_data`, :attr:`steer`, :attr:`r_diag`
1153
- #: if not set, these have to be set explicitly.
1154
- beamformer = Property(transient=True)
1155
-
1156
- # private storage of beamformer instance
1157
- _beamformer = Instance(BeamformerBase)
1158
-
1159
1131
  #: The floating-number-precision of the PSFs. Default is 64 bit.
1160
1132
  psf_precision = Enum('float64', 'float32', desc='precision of PSF')
1161
1133
 
@@ -1174,34 +1146,13 @@ class BeamformerDamas(BeamformerBase):
1174
1146
  depends_on=BEAMFORMER_BASE_DIGEST_DEPENDENCIES + ['n_iter', 'damp', 'psf_precision'],
1175
1147
  )
1176
1148
 
1177
- def _get_beamformer(self):
1178
- return self._beamformer
1179
-
1180
- def _set_beamformer(self, beamformer):
1181
- msg = (
1182
- f"Deprecated use of 'beamformer' trait in class {self.__class__.__name__}. "
1183
- 'Please set :attr:`freq_data`, :attr:`steer`, :attr:`r_diag` directly. '
1184
- "Using the 'beamformer' trait will be removed in version 25.07."
1185
- )
1186
- warn(
1187
- msg,
1188
- DeprecationWarning,
1189
- stacklevel=2,
1190
- )
1191
- self._beamformer = beamformer
1192
-
1193
1149
  @cached_property
1194
1150
  def _get_digest(self):
1195
1151
  return digest(self)
1196
1152
 
1197
- @on_trait_change('_beamformer.digest')
1198
- def delegate_beamformer_traits(self):
1199
- self.freq_data = self.beamformer.freq_data
1200
- self.r_diag = self.beamformer.r_diag
1201
- self.steer = self.beamformer.steer
1202
-
1203
1153
  def _calc(self, ind):
1204
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1154
+ """
1155
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1205
1156
 
1206
1157
  This is an internal helper function that is automatically called when
1207
1158
  accessing the beamformer's :attr:`result` or calling
@@ -1216,14 +1167,13 @@ class BeamformerDamas(BeamformerBase):
1216
1167
  Returns
1217
1168
  -------
1218
1169
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1219
-
1220
1170
  """
1221
1171
  f = self._f
1222
1172
  normfactor = self.sig_loss_norm()
1223
1173
  p = PointSpreadFunction(steer=self.steer, calcmode=self.calcmode, precision=self.psf_precision)
1224
1174
  param_steer_type, steer_vector = self._beamformer_params()
1225
1175
  for i in ind:
1226
- csm = array(self.freq_data.csm[i], dtype='complex128')
1176
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1227
1177
  y = beamformerFreq(
1228
1178
  param_steer_type,
1229
1179
  self.r_diag,
@@ -1232,7 +1182,7 @@ class BeamformerDamas(BeamformerBase):
1232
1182
  csm,
1233
1183
  )[0]
1234
1184
  if self.r_diag: # set (unphysical) negative output values to 0
1235
- indNegSign = sign(y) < 0
1185
+ indNegSign = np.sign(y) < 0
1236
1186
  y[indNegSign] = 0.0
1237
1187
  x = y.copy()
1238
1188
  p.freq = f[i]
@@ -1242,12 +1192,13 @@ class BeamformerDamas(BeamformerBase):
1242
1192
  self._fr[i] = 1
1243
1193
 
1244
1194
 
1245
- @deprecated_alias({'max_iter': 'n_iter'})
1246
1195
  class BeamformerDamasPlus(BeamformerDamas):
1247
- """DAMAS deconvolution :cite:`Brooks2006` for solving the system of equations, instead of the
1248
- original Gauss-Seidel iterations, this class employs the NNLS or linear programming solvers from
1249
- scipy.optimize or one of several optimization algorithms from the scikit-learn module. Needs
1250
- a-priori delay-and-sum beamforming (:class:`BeamformerBase`).
1196
+ """
1197
+ DAMAS deconvolution :cite:`Brooks2006` for solving the system of equations.
1198
+
1199
+ Instead of the original Gauss-Seidel iterations, this class employs the NNLS or linear
1200
+ programming solvers from scipy.optimize or one of several optimization algorithms from the
1201
+ scikit-learn module. Needs a-priori delay-and-sum beamforming (:class:`BeamformerBase`).
1251
1202
  """
1252
1203
 
1253
1204
  #: Type of fit method to be used ('LassoLars',
@@ -1283,7 +1234,8 @@ class BeamformerDamasPlus(BeamformerDamas):
1283
1234
  return digest(self)
1284
1235
 
1285
1236
  def _calc(self, ind):
1286
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1237
+ """
1238
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1287
1239
 
1288
1240
  This is an internal helper function that is automatically called when
1289
1241
  accessing the beamformer's :attr:`result` or calling
@@ -1298,7 +1250,6 @@ class BeamformerDamasPlus(BeamformerDamas):
1298
1250
  Returns
1299
1251
  -------
1300
1252
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1301
-
1302
1253
  """
1303
1254
  f = self._f
1304
1255
  p = PointSpreadFunction(steer=self.steer, calcmode=self.calcmode, precision=self.psf_precision)
@@ -1306,7 +1257,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1306
1257
  normfactor = self.sig_loss_norm()
1307
1258
  param_steer_type, steer_vector = self._beamformer_params()
1308
1259
  for i in ind:
1309
- csm = array(self.freq_data.csm[i], dtype='complex128')
1260
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1310
1261
  y = beamformerFreq(
1311
1262
  param_steer_type,
1312
1263
  self.r_diag,
@@ -1315,7 +1266,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1315
1266
  csm,
1316
1267
  )[0]
1317
1268
  if self.r_diag: # set (unphysical) negative output values to 0
1318
- indNegSign = sign(y) < 0
1269
+ indNegSign = np.sign(y) < 0
1319
1270
  y[indNegSign] = 0.0
1320
1271
  y *= unit
1321
1272
  p.freq = f[i]
@@ -1346,7 +1297,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1346
1297
  # pipeline approach with StandardScaler does scale in a different way, thus we
1347
1298
  # monkeypatch the code and normalize ourselves to make results the same over
1348
1299
  # different sklearn versions
1349
- norms = norm(psf, axis=0)
1300
+ norms = spla.norm(psf, axis=0)
1350
1301
  # get rid of annoying sklearn warnings that appear
1351
1302
  # for sklearn<1.2 despite any settings
1352
1303
  with warnings.catch_warnings():
@@ -1359,23 +1310,16 @@ class BeamformerDamasPlus(BeamformerDamas):
1359
1310
 
1360
1311
 
1361
1312
  class BeamformerOrth(BeamformerBase):
1362
- """Orthogonal deconvolution algorithm.
1313
+ """
1314
+ Orthogonal deconvolution algorithm.
1363
1315
 
1364
1316
  See :cite:`Sarradj2010` for details.
1365
1317
  New faster implementation without explicit (:class:`BeamformerEig`).
1366
1318
  """
1367
1319
 
1368
- #: (only for backward compatibility) :class:`BeamformerEig` object
1369
- #: if set, provides :attr:`freq_data`, :attr:`steer`, :attr:`r_diag`
1370
- #: if not set, these have to be set explicitly.
1371
- beamformer = Property(transient=True)
1372
-
1373
- # private storage of beamformer instance
1374
- _beamformer = Instance(BeamformerEig)
1375
-
1376
1320
  #: List of components to consider, use this to directly set the eigenvalues
1377
1321
  #: used in the beamformer. Alternatively, set :attr:`n`.
1378
- eva_list = CArray(dtype=int, value=array([-1]), desc='components')
1322
+ eva_list = CArray(dtype=int, value=np.array([-1]), desc='components')
1379
1323
 
1380
1324
  #: Number of components to consider, defaults to 1. If set,
1381
1325
  #: :attr:`eva_list` will contain
@@ -1388,39 +1332,18 @@ class BeamformerOrth(BeamformerBase):
1388
1332
  depends_on=BEAMFORMER_BASE_DIGEST_DEPENDENCIES + ['eva_list'],
1389
1333
  )
1390
1334
 
1391
- def _get_beamformer(self):
1392
- return self._beamformer
1393
-
1394
- def _set_beamformer(self, beamformer):
1395
- msg = (
1396
- f"Deprecated use of 'beamformer' trait in class {self.__class__.__name__}. "
1397
- 'Please set :attr:`freq_data`, :attr:`steer`, :attr:`r_diag` directly. '
1398
- "Using the 'beamformer' trait will be removed in version 25.07."
1399
- )
1400
- warn(
1401
- msg,
1402
- DeprecationWarning,
1403
- stacklevel=2,
1404
- )
1405
- self._beamformer = beamformer
1406
-
1407
1335
  @cached_property
1408
1336
  def _get_digest(self):
1409
1337
  return digest(self)
1410
1338
 
1411
- @on_trait_change('_beamformer.digest')
1412
- def delegate_beamformer_traits(self):
1413
- self.freq_data = self.beamformer.freq_data
1414
- self.r_diag = self.beamformer.r_diag
1415
- self.steer = self.beamformer.steer
1416
-
1417
- @on_trait_change('n')
1418
- def set_eva_list(self):
1339
+ @observe('n')
1340
+ def _update_eva_list(self, event): # noqa ARG002
1419
1341
  """Sets the list of eigenvalues to consider."""
1420
- self.eva_list = arange(-1, -1 - self.n, -1)
1342
+ self.eva_list = np.arange(-1, -1 - self.n, -1)
1421
1343
 
1422
1344
  def _calc(self, ind):
1423
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1345
+ """
1346
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1424
1347
 
1425
1348
  This is an internal helper function that is automatically called when
1426
1349
  accessing the beamformer's :attr:`result` or calling
@@ -1435,30 +1358,29 @@ class BeamformerOrth(BeamformerBase):
1435
1358
  Returns
1436
1359
  -------
1437
1360
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1438
-
1439
1361
  """
1440
1362
  f = self._f
1441
1363
  num_channels = self.freq_data.num_channels
1442
1364
  normfactor = self.sig_loss_norm()
1443
1365
  param_steer_type, steer_vector = self._beamformer_params()
1444
1366
  for i in ind:
1445
- eva = array(self.freq_data.eva[i], dtype='float64')
1446
- eve = array(self.freq_data.eve[i], dtype='complex128')
1367
+ eva = np.array(self.freq_data.eva[i], dtype='float64')
1368
+ eve = np.array(self.freq_data.eve[i], dtype='complex128')
1447
1369
  for n in self.eva_list:
1448
1370
  beamformerOutput = beamformerFreq(
1449
1371
  param_steer_type,
1450
1372
  self.r_diag,
1451
1373
  normfactor,
1452
1374
  steer_vector(f[i]),
1453
- (ones(1), eve[:, n].reshape((-1, 1))),
1375
+ (np.ones(1), eve[:, n].reshape((-1, 1))),
1454
1376
  )[0]
1455
1377
  self._ac[i, beamformerOutput.argmax()] += eva[n] / num_channels
1456
1378
  self._fr[i] = 1
1457
1379
 
1458
1380
 
1459
- @deprecated_alias({'n': 'n_iter'})
1460
1381
  class BeamformerCleansc(BeamformerBase):
1461
- """CLEAN-SC deconvolution algorithm.
1382
+ """
1383
+ CLEAN-SC deconvolution algorithm.
1462
1384
 
1463
1385
  See :cite:`Sijtsma2007` for details.
1464
1386
  Classic delay-and-sum beamforming is already included.
@@ -1485,7 +1407,8 @@ class BeamformerCleansc(BeamformerBase):
1485
1407
  return digest(self)
1486
1408
 
1487
1409
  def _calc(self, ind):
1488
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1410
+ """
1411
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1489
1412
 
1490
1413
  This is an internal helper function that is automatically called when
1491
1414
  accessing the beamformer's :attr:`result` or calling
@@ -1500,18 +1423,17 @@ class BeamformerCleansc(BeamformerBase):
1500
1423
  Returns
1501
1424
  -------
1502
1425
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1503
-
1504
1426
  """
1505
1427
  f = self._f
1506
1428
  normfactor = self.sig_loss_norm()
1507
1429
  num_channels = self.freq_data.num_channels
1508
- result = zeros((self.steer.grid.size), 'f')
1430
+ result = np.zeros((self.steer.grid.size), 'f')
1509
1431
  J = num_channels * 2 if not self.n_iter else self.n_iter
1510
- powers = zeros(J, 'd')
1432
+ powers = np.zeros(J, 'd')
1511
1433
 
1512
1434
  param_steer_type, steer_vector = self._beamformer_params()
1513
1435
  for i in ind:
1514
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1436
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1515
1437
  # h = self.steer._beamformerCall(f[i], self.r_diag, normfactor, (csm,))[0]
1516
1438
  h = beamformerFreq(param_steer_type, self.r_diag, normfactor, steer_vector(f[i]), csm)[0]
1517
1439
  # CLEANSC Iteration
@@ -1522,25 +1444,25 @@ class BeamformerCleansc(BeamformerBase):
1522
1444
  result[xi_max] += self.damp * hmax
1523
1445
  if j > self.stopn and hmax > powers[j - self.stopn]:
1524
1446
  break
1525
- wmax = self.steer.steer_vector(f[i], xi_max) * sqrt(normfactor)
1447
+ wmax = self.steer.steer_vector(f[i], xi_max) * np.sqrt(normfactor)
1526
1448
  wmax = wmax[0].conj() # as old code worked with conjugated csm..should be updated
1527
1449
  hh = wmax.copy()
1528
- D1 = dot(csm.T - diag(diag(csm)), wmax) / hmax
1450
+ D1 = np.dot(csm.T - np.diag(np.diag(csm)), wmax) / hmax
1529
1451
  ww = wmax.conj() * wmax
1530
- for _m in range(20):
1452
+ for _ in range(20):
1531
1453
  H = hh.conj() * hh
1532
- hh = (D1 + H * wmax) / sqrt(1 + dot(ww, H))
1533
- hh = hh[:, newaxis]
1454
+ hh = (D1 + H * wmax) / np.sqrt(1 + np.dot(ww, H))
1455
+ hh = hh[:, np.newaxis]
1534
1456
  csm1 = hmax * (hh * hh.conj().T)
1535
1457
 
1536
1458
  # h1 = self.steer._beamformerCall(f[i], self.r_diag, normfactor, \
1537
- # (array((hmax, ))[newaxis, :], hh[newaxis, :].conjugate()))[0]
1459
+ # (np.array((hmax, ))[np.newaxis, :], hh[np.newaxis, :].conjugate()))[0]
1538
1460
  h1 = beamformerFreq(
1539
1461
  param_steer_type,
1540
1462
  self.r_diag,
1541
1463
  normfactor,
1542
1464
  steer_vector(f[i]),
1543
- (array((hmax,)), hh.conj()),
1465
+ (np.array((hmax,)), hh.conj()),
1544
1466
  )[0]
1545
1467
  h -= self.damp * h1
1546
1468
  csm -= self.damp * csm1.T # transpose(0,2,1)
@@ -1549,19 +1471,12 @@ class BeamformerCleansc(BeamformerBase):
1549
1471
 
1550
1472
 
1551
1473
  class BeamformerClean(BeamformerBase):
1552
- """CLEAN deconvolution algorithm.
1474
+ """
1475
+ CLEAN deconvolution algorithm.
1553
1476
 
1554
1477
  See :cite:`Hoegbom1974` for details.
1555
1478
  """
1556
1479
 
1557
- #: (only for backward compatibility) :class:`BeamformerBase` object
1558
- #: if set, provides :attr:`freq_data`, :attr:`steer`, :attr:`r_diag`
1559
- #: if not set, these have to be set explicitly.
1560
- beamformer = Property(transient=True)
1561
-
1562
- # private storage of beamformer instance
1563
- _beamformer = Instance(BeamformerBase)
1564
-
1565
1480
  #: The floating-number-precision of the PSFs. Default is 64 bit.
1566
1481
  psf_precision = Enum('float64', 'float32', desc='precision of PSF.')
1567
1482
 
@@ -1584,28 +1499,6 @@ class BeamformerClean(BeamformerBase):
1584
1499
  def _get_digest(self):
1585
1500
  return digest(self)
1586
1501
 
1587
- def _get_beamformer(self):
1588
- return self._beamformer
1589
-
1590
- def _set_beamformer(self, beamformer):
1591
- msg = (
1592
- f"Deprecated use of 'beamformer' trait in class {self.__class__.__name__}. "
1593
- 'Please set :attr:`freq_data`, :attr:`steer`, :attr:`r_diag` directly. '
1594
- "Using the 'beamformer' trait will be removed in version 25.07."
1595
- )
1596
- warn(
1597
- msg,
1598
- DeprecationWarning,
1599
- stacklevel=2,
1600
- )
1601
- self._beamformer = beamformer
1602
-
1603
- @on_trait_change('_beamformer.digest')
1604
- def delegate_beamformer_traits(self):
1605
- self.freq_data = self.beamformer.freq_data
1606
- self.r_diag = self.beamformer.r_diag
1607
- self.steer = self.beamformer.steer
1608
-
1609
1502
  def _calc(self, ind):
1610
1503
  """Calculates the result for the frequencies defined by :attr:`freq_data`.
1611
1504
 
@@ -1622,7 +1515,6 @@ class BeamformerClean(BeamformerBase):
1622
1515
  Returns
1623
1516
  -------
1624
1517
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1625
-
1626
1518
  """
1627
1519
  f = self._f
1628
1520
  gs = self.steer.grid.size
@@ -1638,7 +1530,7 @@ class BeamformerClean(BeamformerBase):
1638
1530
  param_steer_type, steer_vector = self._beamformer_params()
1639
1531
  for i in ind:
1640
1532
  p.freq = f[i]
1641
- csm = array(self.freq_data.csm[i], dtype='complex128')
1533
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1642
1534
  dirty = beamformerFreq(
1643
1535
  param_steer_type,
1644
1536
  self.r_diag,
@@ -1647,16 +1539,16 @@ class BeamformerClean(BeamformerBase):
1647
1539
  csm,
1648
1540
  )[0]
1649
1541
  if self.r_diag: # set (unphysical) negative output values to 0
1650
- indNegSign = sign(dirty) < 0
1542
+ indNegSign = np.sign(dirty) < 0
1651
1543
  dirty[indNegSign] = 0.0
1652
1544
 
1653
- clean = zeros(gs, dtype=dirty.dtype)
1545
+ clean = np.zeros(gs, dtype=dirty.dtype)
1654
1546
  i_iter = 0
1655
1547
  flag = True
1656
1548
  while flag:
1657
1549
  dirty_sum = abs(dirty).sum(0)
1658
1550
  next_max = dirty.argmax(0)
1659
- p.grid_indices = array([next_max])
1551
+ p.grid_indices = np.array([next_max])
1660
1552
  psf = p.psf.reshape(gs)
1661
1553
  new_amp = self.damp * dirty[next_max] # / psf[next_max]
1662
1554
  clean[next_max] += new_amp
@@ -1668,9 +1560,9 @@ class BeamformerClean(BeamformerBase):
1668
1560
  self._fr[i] = 1
1669
1561
 
1670
1562
 
1671
- @deprecated_alias({'max_iter': 'n_iter'})
1672
1563
  class BeamformerCMF(BeamformerBase):
1673
- """Covariance Matrix Fitting algorithm.
1564
+ """
1565
+ Covariance Matrix Fitting algorithm.
1674
1566
 
1675
1567
  This is not really a beamformer, but an inverse method.
1676
1568
  See :cite:`Yardibi2008` for details.
@@ -1737,8 +1629,8 @@ class BeamformerCMF(BeamformerBase):
1737
1629
  def _get_digest(self):
1738
1630
  return digest(self)
1739
1631
 
1740
- @on_trait_change('method')
1741
- def _validate(self):
1632
+ @observe('method')
1633
+ def _validate(self, event): # noqa ARG002
1742
1634
  if self.method in ['FISTA', 'Split_Bregman'] and not config.have_pylops:
1743
1635
  msg = (
1744
1636
  'Cannot import Pylops package. No Pylops installed.'
@@ -1747,7 +1639,8 @@ class BeamformerCMF(BeamformerBase):
1747
1639
  raise ImportError(msg)
1748
1640
 
1749
1641
  def _calc(self, ind):
1750
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1642
+ """
1643
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1751
1644
 
1752
1645
  This is an internal helper function that is automatically called when
1753
1646
  accessing the beamformer's :attr:`result` or calling
@@ -1762,13 +1655,12 @@ class BeamformerCMF(BeamformerBase):
1762
1655
  Returns
1763
1656
  -------
1764
1657
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1765
-
1766
1658
  """
1767
1659
  f = self._f
1768
1660
 
1769
1661
  # function to repack complex matrices to deal with them in real number space
1770
1662
  def realify(matrix):
1771
- return vstack([matrix.real, matrix.imag])
1663
+ return np.vstack([matrix.real, matrix.imag])
1772
1664
 
1773
1665
  # prepare calculation
1774
1666
  nc = self.freq_data.num_channels
@@ -1776,29 +1668,29 @@ class BeamformerCMF(BeamformerBase):
1776
1668
  unit = self.unit_mult
1777
1669
 
1778
1670
  for i in ind:
1779
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1671
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1780
1672
 
1781
1673
  h = self.steer.transfer(f[i]).T
1782
1674
 
1783
1675
  # reduced Kronecker product (only where solution matrix != 0)
1784
- Bc = (h[:, :, newaxis] * h.conjugate().T[newaxis, :, :]).transpose(2, 0, 1)
1676
+ Bc = (h[:, :, np.newaxis] * h.conjugate().T[np.newaxis, :, :]).transpose(2, 0, 1)
1785
1677
  Ac = Bc.reshape(nc * nc, num_points)
1786
1678
 
1787
- # get indices for upper triangular matrices (use tril b/c transposed)
1788
- ind = reshape(tril(ones((nc, nc))), (nc * nc,)) > 0
1679
+ # get indices for upper triangular matrices (use np.tril b/c transposed)
1680
+ ind = np.reshape(np.tril(np.ones((nc, nc))), (nc * nc,)) > 0
1789
1681
 
1790
- ind_im0 = (reshape(eye(nc), (nc * nc,)) == 0)[ind]
1682
+ ind_im0 = (np.reshape(np.eye(nc), (nc * nc,)) == 0)[ind]
1791
1683
  if self.r_diag:
1792
1684
  # omit main diagonal for noise reduction
1793
- ind_reim = hstack([ind_im0, ind_im0])
1685
+ ind_reim = np.hstack([ind_im0, ind_im0])
1794
1686
  else:
1795
1687
  # take all real parts -- also main diagonal
1796
- ind_reim = hstack([ones(size(ind_im0)) > 0, ind_im0])
1688
+ ind_reim = np.hstack([np.ones(np.size(ind_im0)) > 0, ind_im0])
1797
1689
  ind_reim[0] = True # why this ?
1798
1690
 
1799
1691
  A = realify(Ac[ind, :])[ind_reim, :]
1800
1692
  # use csm.T for column stacking reshape!
1801
- R = realify(reshape(csm.T, (nc * nc, 1))[ind, :])[ind_reim, :] * unit
1693
+ R = realify(np.reshape(csm.T, (nc * nc, 1))[ind, :])[ind_reim, :] * unit
1802
1694
  # choose method
1803
1695
  if self.method == 'LassoLars':
1804
1696
  model = LassoLars(alpha=self.alpha * unit, max_iter=self.n_iter, positive=True, **sklearn_ndict)
@@ -1852,13 +1744,13 @@ class BeamformerCMF(BeamformerBase):
1852
1744
  # function
1853
1745
  func = x.T @ A.T @ A @ x - 2 * R.T @ A @ x + R.T @ R
1854
1746
  # derivitaive
1855
- der = 2 * A.T @ A @ x.T[:, newaxis] - 2 * A.T @ R
1747
+ der = 2 * A.T @ A @ x.T[:, np.newaxis] - 2 * A.T @ R
1856
1748
  return func[0].T, der[:, 0]
1857
1749
 
1858
1750
  # initial guess
1859
- x0 = ones([num_points])
1751
+ x0 = np.ones([num_points])
1860
1752
  # boundaries - set to non negative
1861
- boundaries = tile((0, +inf), (len(x0), 1))
1753
+ boundaries = np.tile((0, np.inf), (len(x0), 1))
1862
1754
 
1863
1755
  # optimize
1864
1756
  self._ac[i], yval, dicts = fmin_l_bfgs_b(
@@ -1872,10 +1764,8 @@ class BeamformerCMF(BeamformerBase):
1872
1764
  factr=10000000.0,
1873
1765
  pgtol=1e-05,
1874
1766
  epsilon=1e-08,
1875
- iprint=-1,
1876
1767
  maxfun=15000,
1877
1768
  maxiter=self.n_iter,
1878
- disp=None,
1879
1769
  callback=None,
1880
1770
  maxls=20,
1881
1771
  )
@@ -1886,7 +1776,7 @@ class BeamformerCMF(BeamformerBase):
1886
1776
  # pipeline approach with StandardScaler does scale in a different way, thus we
1887
1777
  # monkeypatch the code and normalize ourselves to make results the same over
1888
1778
  # different sklearn versions
1889
- norms = norm(A, axis=0)
1779
+ norms = spla.norm(A, axis=0)
1890
1780
  # get rid of sklearn warnings that appear for sklearn<1.2 despite any settings
1891
1781
  with warnings.catch_warnings():
1892
1782
  warnings.simplefilter('ignore', category=FutureWarning)
@@ -1897,9 +1787,9 @@ class BeamformerCMF(BeamformerBase):
1897
1787
  self._fr[i] = 1
1898
1788
 
1899
1789
 
1900
- @deprecated_alias({'max_iter': 'n_iter'})
1901
1790
  class BeamformerSODIX(BeamformerBase):
1902
- """Source directivity modeling in the cross-spectral matrix (SODIX) algorithm.
1791
+ """
1792
+ Source directivity modeling in the cross-spectral matrix (SODIX) algorithm.
1903
1793
 
1904
1794
  See :cite:`Funke2017` and :cite:`Oertwig2019` for details.
1905
1795
  """
@@ -1949,7 +1839,8 @@ class BeamformerSODIX(BeamformerBase):
1949
1839
  return digest(self)
1950
1840
 
1951
1841
  def _calc(self, ind):
1952
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1842
+ """
1843
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1953
1844
 
1954
1845
  This is an internal helper function that is automatically called when
1955
1846
  accessing the beamformer's :attr:`result` or calling
@@ -1964,7 +1855,6 @@ class BeamformerSODIX(BeamformerBase):
1964
1855
  Returns
1965
1856
  -------
1966
1857
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1967
-
1968
1858
  """
1969
1859
  # prepare calculation
1970
1860
  f = self._f
@@ -1979,14 +1869,17 @@ class BeamformerSODIX(BeamformerBase):
1979
1869
  for i in range(1, ind.max() + 1):
1980
1870
  if not self._fr[i]:
1981
1871
  # measured csm
1982
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1872
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1983
1873
  # transfer function
1984
1874
  h = self.steer.transfer(f[i]).T
1985
1875
 
1986
1876
  if self.method == 'fmin_l_bfgs_b':
1987
1877
  # function to minimize
1988
1878
  def function(directions):
1989
- """Parameters
1879
+ """
1880
+ Calculates SODIX objective function and derivatives for optimization.
1881
+
1882
+ Parameters
1990
1883
  ----------
1991
1884
  directions
1992
1885
  [num_points*num_mics]
@@ -1997,41 +1890,43 @@ class BeamformerSODIX(BeamformerBase):
1997
1890
  [1]
1998
1891
  derdrl - derivitaives in direction of D
1999
1892
  [num_mics*num_points].
2000
-
2001
1893
  """
2002
1894
  #### the sodix function ####
2003
1895
  Djm = directions.reshape([num_points, num_mics])
2004
1896
  p = h.T * Djm
2005
- csm_mod = dot(p.T, p.conj())
1897
+ csm_mod = np.dot(p.T, p.conj())
2006
1898
  Q = csm - csm_mod
2007
- func = sum((absolute(Q)) ** 2)
1899
+ func = np.sum((np.abs(Q)) ** 2)
2008
1900
 
2009
1901
  # subscripts and operands for numpy einsum and einsum_path
2010
1902
  subscripts = 'rl,rm,ml->rl'
2011
1903
  operands = (h.T, h.T.conj() * Djm, Q)
2012
- es_path = einsum_path(subscripts, *operands, optimize='greedy')[0]
1904
+ es_path = np.einsum_path(subscripts, *operands, optimize='greedy')[0]
2013
1905
 
2014
1906
  #### the sodix derivative ####
2015
- derdrl = einsum(subscripts, *operands, optimize=es_path)
2016
- derdrl = -4 * real(derdrl)
1907
+ derdrl = np.einsum(subscripts, *operands, optimize=es_path)
1908
+ derdrl = -4 * np.real(derdrl)
2017
1909
  return func, derdrl.ravel()
2018
1910
 
2019
1911
  ##### initial guess ####
2020
1912
  if not self._fr[(i - 1)]:
2021
- D0 = ones([num_points, num_mics])
1913
+ D0 = np.ones([num_points, num_mics])
2022
1914
  else:
2023
- D0 = sqrt(
1915
+ D0 = np.sqrt(
2024
1916
  self._ac[(i - 1)]
2025
- * real(trace(csm) / trace(array(self.freq_data.csm[i - 1], dtype='complex128', copy=1))),
1917
+ * np.real(
1918
+ np.trace(csm)
1919
+ / np.trace(np.array(self.freq_data.csm[i - 1], dtype='complex128', copy=True))
1920
+ ),
2026
1921
  )
2027
1922
 
2028
1923
  # boundaries - set to non negative [2*(num_points*num_mics)]
2029
- boundaries = tile((0, +inf), (num_points * num_mics, 1))
1924
+ boundaries = np.tile((0, np.inf), (num_points * num_mics, 1))
2030
1925
 
2031
1926
  # optimize with gradient solver
2032
1927
  # see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_l_bfgs_b.html
2033
1928
 
2034
- qi = ones([num_points, num_mics])
1929
+ qi = np.ones([num_points, num_mics])
2035
1930
  qi, yval, dicts = fmin_l_bfgs_b(
2036
1931
  function,
2037
1932
  D0,
@@ -2042,10 +1937,8 @@ class BeamformerSODIX(BeamformerBase):
2042
1937
  factr=100.0,
2043
1938
  pgtol=1e-12,
2044
1939
  epsilon=1e-08,
2045
- iprint=-1,
2046
1940
  maxfun=1500000,
2047
1941
  maxiter=self.n_iter,
2048
- disp=-1,
2049
1942
  callback=None,
2050
1943
  maxls=20,
2051
1944
  )
@@ -2056,9 +1949,9 @@ class BeamformerSODIX(BeamformerBase):
2056
1949
  self._fr[i] = 1
2057
1950
 
2058
1951
 
2059
- @deprecated_alias({'max_iter': 'n_iter'})
2060
1952
  class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2061
- """Beamforming GIB methods with different normalizations.
1953
+ """
1954
+ Beamforming GIB methods with different normalizations.
2062
1955
 
2063
1956
  See :cite:`Suzuki2011` for details.
2064
1957
  """
@@ -2149,7 +2042,8 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2149
2042
  return min(nm - 1, na)
2150
2043
 
2151
2044
  def _calc(self, ind):
2152
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
2045
+ """
2046
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
2153
2047
 
2154
2048
  This is an internal helper function that is automatically called when
2155
2049
  accessing the beamformer's :attr:`result` or calling
@@ -2164,14 +2058,13 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2164
2058
  Returns
2165
2059
  -------
2166
2060
  This method only returns values through :attr:`_ac` and :attr:`_fr`
2167
-
2168
2061
  """
2169
2062
  f = self._f
2170
2063
  n = int(self.na) # number of eigenvalues
2171
2064
  m = int(self.m) # number of first eigenvalue
2172
2065
  num_channels = self.freq_data.num_channels # number of channels
2173
2066
  num_points = self.steer.grid.size
2174
- hh = zeros((1, num_points, num_channels), dtype='D')
2067
+ hh = np.zeros((1, num_points, num_channels), dtype='D')
2175
2068
 
2176
2069
  # Generate a cross spectral matrix, and perform the eigenvalue decomposition
2177
2070
  for i in ind:
@@ -2180,79 +2073,83 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2180
2073
  hh = self.steer.transfer(f[i])
2181
2074
  A = hh.T
2182
2075
  # eigenvalues and vectors
2183
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
2184
- eva, eve = eigh(csm)
2076
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
2077
+ eva, eve = spla.eigh(csm)
2185
2078
  eva = eva[::-1]
2186
2079
  eve = eve[:, ::-1]
2187
2080
  # set small values zo 0, lowers numerical errors in simulated data
2188
2081
  eva[eva < max(eva) / 1e12] = 0
2189
2082
  # init sources
2190
- qi = zeros([n + m, num_points], dtype='complex128')
2083
+ qi = np.zeros([n + m, num_points], dtype='complex128')
2191
2084
  # Select the number of coherent modes to be processed referring to the eigenvalue
2192
2085
  # distribution.
2193
2086
  for s in list(range(m, n + m)):
2194
2087
  if eva[s] > 0:
2195
2088
  # Generate the corresponding eigenmodes
2196
- emode = array(sqrt(eva[s]) * eve[:, s], dtype='complex128')
2089
+ emode = np.array(np.sqrt(eva[s]) * eve[:, s], dtype='complex128')
2197
2090
  # choose method for computation
2198
2091
  if self.method == 'Suzuki':
2199
2092
  leftpoints = num_points
2200
- locpoints = arange(num_points)
2201
- weights = diag(ones(num_points))
2202
- epsilon = arange(self.n_iter)
2203
- for it in arange(self.n_iter):
2093
+ locpoints = np.arange(num_points)
2094
+ weights = np.diag(np.ones(num_points))
2095
+ epsilon = np.arange(self.n_iter)
2096
+ for it in np.arange(self.n_iter):
2204
2097
  if num_channels <= leftpoints:
2205
- AWA = dot(dot(A[:, locpoints], weights), A[:, locpoints].conj().T)
2206
- epsilon[it] = max(absolute(eigvals(AWA))) * self.eps_perc
2207
- qi[s, locpoints] = dot(
2208
- dot(
2209
- dot(weights, A[:, locpoints].conj().T),
2210
- inv(AWA + eye(num_channels) * epsilon[it]),
2098
+ AWA = np.dot(np.dot(A[:, locpoints], weights), A[:, locpoints].conj().T)
2099
+ epsilon[it] = max(np.abs(spla.eigvals(AWA))) * self.eps_perc
2100
+ qi[s, locpoints] = np.dot(
2101
+ np.dot(
2102
+ np.dot(weights, A[:, locpoints].conj().T),
2103
+ spla.inv(AWA + np.eye(num_channels) * epsilon[it]),
2211
2104
  ),
2212
2105
  emode,
2213
2106
  )
2214
2107
  elif num_channels > leftpoints:
2215
- AA = dot(A[:, locpoints].conj().T, A[:, locpoints])
2216
- epsilon[it] = max(absolute(eigvals(AA))) * self.eps_perc
2217
- qi[s, locpoints] = dot(
2218
- dot(inv(AA + inv(weights) * epsilon[it]), A[:, locpoints].conj().T),
2108
+ AA = np.dot(A[:, locpoints].conj().T, A[:, locpoints])
2109
+ epsilon[it] = max(np.abs(spla.eigvals(AA))) * self.eps_perc
2110
+ qi[s, locpoints] = np.dot(
2111
+ np.dot(spla.inv(AA + spla.inv(weights) * epsilon[it]), A[:, locpoints].conj().T),
2219
2112
  emode,
2220
2113
  )
2221
2114
  if self.beta < 1 and it > 1:
2222
2115
  # Reorder from the greatest to smallest magnitude to define a
2223
2116
  # reduced-point source distribution, and reform a reduced transfer
2224
2117
  # matrix
2225
- leftpoints = int(round(num_points * self.beta ** (it + 1)))
2226
- idx = argsort(abs(qi[s, locpoints]))[::-1]
2118
+ leftpoints = int(np.round(num_points * self.beta ** (it + 1)))
2119
+ idx = np.argsort(abs(qi[s, locpoints]))[::-1]
2227
2120
  # print(it, leftpoints, locpoints, idx )
2228
- locpoints = delete(locpoints, [idx[leftpoints::]])
2229
- qix = zeros([n + m, leftpoints], dtype='complex128')
2121
+ locpoints = np.delete(locpoints, [idx[leftpoints::]])
2122
+ qix = np.zeros([n + m, leftpoints], dtype='complex128')
2230
2123
  qix[s, :] = qi[s, locpoints]
2231
2124
  # calc weights for next iteration
2232
- weights = diag(absolute(qix[s, :]) ** (2 - self.pnorm))
2125
+ weights = np.diag(np.abs(qix[s, :]) ** (2 - self.pnorm))
2233
2126
  else:
2234
- weights = diag(absolute(qi[s, :]) ** (2 - self.pnorm))
2127
+ weights = np.diag(np.abs(qi[s, :]) ** (2 - self.pnorm))
2235
2128
 
2236
2129
  elif self.method == 'InverseIRLS':
2237
- weights = eye(num_points)
2238
- locpoints = arange(num_points)
2239
- for _it in arange(self.n_iter):
2130
+ weights = np.eye(num_points)
2131
+ locpoints = np.arange(num_points)
2132
+ for _it in np.arange(self.n_iter):
2240
2133
  if num_channels <= num_points:
2241
- wtwi = inv(dot(weights.T, weights))
2134
+ wtwi = spla.inv(np.dot(weights.T, weights))
2242
2135
  aH = A.conj().T
2243
- qi[s, :] = dot(dot(wtwi, aH), dot(inv(dot(A, dot(wtwi, aH))), emode))
2244
- weights = diag(absolute(qi[s, :]) ** ((2 - self.pnorm) / 2))
2245
- weights = weights / sum(absolute(weights))
2136
+ qi[s, :] = np.dot(
2137
+ np.dot(wtwi, aH), np.dot(spla.inv(np.dot(A, np.dot(wtwi, aH))), emode)
2138
+ )
2139
+ weights = np.diag(np.abs(qi[s, :]) ** ((2 - self.pnorm) / 2))
2140
+ weights = weights / np.sum(np.abs(weights))
2246
2141
  elif num_channels > num_points:
2247
- wtw = dot(weights.T, weights)
2248
- qi[s, :] = dot(dot(inv(dot(dot(A.conj.T, wtw), A)), dot(A.conj().T, wtw)), emode)
2249
- weights = diag(absolute(qi[s, :]) ** ((2 - self.pnorm) / 2))
2250
- weights = weights / sum(absolute(weights))
2142
+ wtw = np.dot(weights.T, weights)
2143
+ qi[s, :] = np.dot(
2144
+ np.dot(spla.inv(np.dot(np.dot(A.conj.T, wtw), A)), np.dot(A.conj().T, wtw)), emode
2145
+ )
2146
+ weights = np.diag(np.abs(qi[s, :]) ** ((2 - self.pnorm) / 2))
2147
+ weights = weights / np.sum(np.abs(weights))
2251
2148
  else:
2252
- locpoints = arange(num_points)
2149
+ locpoints = np.arange(num_points)
2253
2150
  unit = self.unit_mult
2254
- AB = vstack([hstack([A.real, -A.imag]), hstack([A.imag, A.real])])
2255
- R = hstack([emode.real.T, emode.imag.T]) * unit
2151
+ AB = np.vstack([np.hstack([A.real, -A.imag]), np.hstack([A.imag, A.real])])
2152
+ R = np.hstack([emode.real.T, emode.imag.T]) * unit
2256
2153
  if self.method == 'LassoLars':
2257
2154
  model = LassoLars(alpha=self.alpha * unit, max_iter=self.n_iter, positive=True)
2258
2155
  elif self.method == 'LassoLarsBIC':
@@ -2270,7 +2167,7 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2270
2167
  # way, thus we monkeypatch the code and normalize
2271
2168
  # ourselves to make results the same over different
2272
2169
  # sklearn versions
2273
- norms = norm(AB, axis=0)
2170
+ norms = spla.norm(AB, axis=0)
2274
2171
  # get rid of annoying sklearn warnings that appear
2275
2172
  # for sklearn<1.2 despite any settings
2276
2173
  with warnings.catch_warnings():
@@ -2278,7 +2175,7 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2278
2175
  # normalized A
2279
2176
  model.fit(AB / norms, R)
2280
2177
  # recover normalization in the coef's
2281
- qi_real, qi_imag = hsplit(model.coef_[:] / norms / unit, 2)
2178
+ qi_real, qi_imag = np.hsplit(model.coef_[:] / norms / unit, 2)
2282
2179
  # print(s,qi.size)
2283
2180
  qi[s, locpoints] = qi_real + qi_imag * 1j
2284
2181
  else:
@@ -2289,8 +2186,8 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2289
2186
  )
2290
2187
  # Generate source maps of all selected eigenmodes, and superpose source intensity
2291
2188
  # for each source type.
2292
- temp = zeros(num_points)
2293
- temp[locpoints] = sum(absolute(qi[:, locpoints]) ** 2, axis=0)
2189
+ temp = np.zeros(num_points)
2190
+ temp[locpoints] = np.sum(np.abs(qi[:, locpoints]) ** 2, axis=0)
2294
2191
  self._ac[i] = temp
2295
2192
  self._fr[i] = 1
2296
2193
 
@@ -2308,7 +2205,8 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2308
2205
  return self._gpos
2309
2206
 
2310
2207
  def integrate(self, sector):
2311
- """Integrates result map over a given sector.
2208
+ """
2209
+ Integrates result map over a given sector.
2312
2210
 
2313
2211
  Parameters
2314
2212
  ----------
@@ -2319,7 +2217,6 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2319
2217
  -------
2320
2218
  array of floats
2321
2219
  The spectrum (all calculated frequency bands) for the integrated sector.
2322
-
2323
2220
  """
2324
2221
  if not isinstance(sector, Sector):
2325
2222
  msg = (
@@ -2332,21 +2229,22 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2332
2229
 
2333
2230
  ind = self.subdomain(sector)
2334
2231
  r = self.result
2335
- h = zeros(r.shape[0])
2232
+ h = np.zeros(r.shape[0])
2336
2233
  for i in range(r.shape[0]):
2337
2234
  h[i] = r[i][ind].sum()
2338
2235
  return h
2339
2236
 
2340
2237
 
2341
2238
  class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2342
- """Orthogonal beamforming without predefined grid.
2239
+ """
2240
+ Orthogonal beamforming without predefined grid.
2343
2241
 
2344
2242
  See :cite:`Sarradj2022` for details.
2345
2243
  """
2346
2244
 
2347
2245
  #: List of components to consider, use this to directly set the eigenvalues
2348
2246
  #: used in the beamformer. Alternatively, set :attr:`n`.
2349
- eva_list = CArray(dtype=int, value=array([-1]), desc='components')
2247
+ eva_list = CArray(dtype=int, value=np.array([-1]), desc='components')
2350
2248
 
2351
2249
  #: Number of components to consider, defaults to 1. If set,
2352
2250
  #: :attr:`eva_list` will contain
@@ -2383,17 +2281,18 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2383
2281
  def _get_digest(self):
2384
2282
  return digest(self)
2385
2283
 
2386
- @on_trait_change('n')
2387
- def set_eva_list(self):
2284
+ @observe('n')
2285
+ def _update_eva_list(self, event): # noqa ARG002
2388
2286
  """Sets the list of eigenvalues to consider."""
2389
- self.eva_list = arange(-1, -1 - self.n, -1)
2287
+ self.eva_list = np.arange(-1, -1 - self.n, -1)
2390
2288
 
2391
2289
  @property_depends_on('n')
2392
2290
  def _get_size(self):
2393
2291
  return self.n * self.freq_data.fftfreq().shape[0]
2394
2292
 
2395
2293
  def _calc(self, ind):
2396
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
2294
+ """
2295
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
2397
2296
 
2398
2297
  This is an internal helper function that is automatically called when
2399
2298
  accessing the beamformer's :attr:`result` or calling
@@ -2408,13 +2307,12 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2408
2307
  Returns
2409
2308
  -------
2410
2309
  This method only returns values through :attr:`_ac` and :attr:`_fr`
2411
-
2412
2310
  """
2413
2311
  f = self._f
2414
2312
  normfactor = self.sig_loss_norm()
2415
2313
  num_channels = self.freq_data.num_channels
2416
2314
  # eigenvalue number list in standard form from largest to smallest
2417
- eva_list = unique(self.eva_list % self.steer.mics.num_mics)[::-1]
2315
+ eva_list = np.unique(self.eva_list % self.steer.mics.num_mics)[::-1]
2418
2316
  steer_type = self.steer.steer_type
2419
2317
  if steer_type == 'custom':
2420
2318
  msg = 'custom steer_type is not implemented'
@@ -2433,27 +2331,27 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2433
2331
  for y in self.bounds[1]:
2434
2332
  for z in self.bounds[2]:
2435
2333
  roi.append((x, y, z))
2436
- self.steer.env.roi = array(roi).T
2437
- bmin = array(tuple(map(min, self.bounds)))
2438
- bmax = array(tuple(map(max, self.bounds)))
2334
+ self.steer.env.roi = np.array(roi).T
2335
+ bmin = np.array(tuple(map(min, self.bounds)))
2336
+ bmax = np.array(tuple(map(max, self.bounds)))
2439
2337
  for i in ind:
2440
- eva = array(self.freq_data.eva[i], dtype='float64')
2441
- eve = array(self.freq_data.eve[i], dtype='complex128')
2442
- k = 2 * pi * f[i] / env.c
2338
+ eva = np.array(self.freq_data.eva[i], dtype='float64')
2339
+ eve = np.array(self.freq_data.eve[i], dtype='complex128')
2340
+ k = 2 * np.pi * f[i] / env.c
2443
2341
  for j, n in enumerate(eva_list):
2444
2342
  # print(f[i],n)
2445
2343
 
2446
2344
  def func(xy):
2447
2345
  # function to minimize globally
2448
- xy = clip(xy, bmin, bmax)
2449
- r0 = env._r(xy[:, newaxis])
2450
- rm = env._r(xy[:, newaxis], mpos)
2346
+ xy = np.clip(xy, bmin, bmax)
2347
+ r0 = env._r(xy[:, np.newaxis])
2348
+ rm = env._r(xy[:, np.newaxis], mpos)
2451
2349
  return -beamformerFreq(
2452
2350
  steer_type,
2453
2351
  self.r_diag,
2454
2352
  normfactor,
2455
2353
  (r0, rm, k),
2456
- (ones(1), eve[:, n : n + 1]),
2354
+ (np.ones(1), eve[:, n : n + 1]),
2457
2355
  )[0][0] # noqa: B023
2458
2356
 
2459
2357
  # simplical global homotopy optimizer
@@ -2469,7 +2367,8 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2469
2367
 
2470
2368
 
2471
2369
  def L_p(x): # noqa: N802
2472
- r"""Calculates the sound pressure level from the squared sound pressure.
2370
+ r"""
2371
+ Calculates the sound pressure level from the squared sound pressure.
2473
2372
 
2474
2373
  :math:`L_p = 10 \lg ( x / 4\cdot 10^{-10})`
2475
2374
 
@@ -2483,17 +2382,17 @@ def L_p(x): # noqa: N802
2483
2382
  array of floats
2484
2383
  The corresponding sound pressure levels in dB.
2485
2384
  If `x<0`, -350.0 dB is returned.
2486
-
2487
2385
  """
2488
2386
  # new version to prevent division by zero warning for float32 arguments
2489
- return 10 * log10(clip(x / 4e-10, 1e-35, None))
2387
+ return 10 * np.log10(np.clip(x / 4e-10, 1e-35, None))
2490
2388
 
2491
2389
 
2492
- # return where(x>0, 10*log10(x/4e-10), -1000.)
2390
+ # return where(x>0, 10*np.log10(x/4e-10), -1000.)
2493
2391
 
2494
2392
 
2495
2393
  def integrate(data, grid, sector):
2496
- """Integrates a sound pressure map over a given sector.
2394
+ """
2395
+ Integrates a sound pressure map over a given sector.
2497
2396
 
2498
2397
  This function can be applied on beamforming results to
2499
2398
  quantitatively analyze the sound pressure in a given sector.
@@ -2521,8 +2420,8 @@ def integrate(data, grid, sector):
2521
2420
  of a :class:`~acoular.grids.Grid`-derived class
2522
2421
  (e.g. :meth:`RectGrid.indices<acoular.grids.RectGrid.indices>`
2523
2422
  or :meth:`RectGrid3D.indices<acoular.grids.RectGrid3D.indices>`).
2524
- Possible sectors would be `array([xmin, ymin, xmax, ymax])`
2525
- or `array([x, y, radius])`.
2423
+ Possible sectors would be `np.array([xmin, ymin, xmax, ymax])`
2424
+ or `np.array([x, y, radius])`.
2526
2425
  Alternatively, a :class:`~acoular.grids.Sector`-derived object
2527
2426
  can be used.
2528
2427
 
@@ -2530,7 +2429,6 @@ def integrate(data, grid, sector):
2530
2429
  -------
2531
2430
  array of floats
2532
2431
  The spectrum (all calculated frequency bands) for the integrated sector.
2533
-
2534
2432
  """
2535
2433
  if isinstance(sector, Sector):
2536
2434
  ind = grid.subdomain(sector)
@@ -2548,10 +2446,10 @@ def integrate(data, grid, sector):
2548
2446
 
2549
2447
  gshape = grid.shape
2550
2448
  gsize = grid.size
2551
- if size(data) == gsize: # one value per grid point
2449
+ if np.size(data) == gsize: # one value per grid point
2552
2450
  h = data.reshape(gshape)[ind].sum()
2553
2451
  elif data.ndim == 2 and data.shape[1] == gsize:
2554
- h = zeros(data.shape[0])
2452
+ h = np.zeros(data.shape[0])
2555
2453
  for i in range(data.shape[0]):
2556
2454
  h[i] = data[i].reshape(gshape)[ind].sum()
2557
2455
  return h