acoular 25.7__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))
@@ -293,11 +260,11 @@ class LazyBfResult:
293
260
 
294
261
  def __getitem__(self, key):
295
262
  """'intelligent' [] operator, checks if results are available and triggers calculation."""
296
- sl = index_exp[key][0]
297
- if isinstance(sl, (int, integer)):
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
  ----------
@@ -674,13 +647,13 @@ class BeamformerBase(HasStrictTraits):
674
647
  irange = (ind_low, ind_high)
675
648
  num = 0
676
649
  elif len(frange) == 2:
677
- 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]))
678
651
  else:
679
652
  msg = 'Only a tuple of length 2 is allowed for frange if num==0'
680
653
  raise TypeError(
681
654
  msg,
682
655
  )
683
- h = zeros(num_freqs, dtype=float)
656
+ h = np.zeros(num_freqs, dtype=float)
684
657
  sl = slice(*irange)
685
658
  r = self.result[sl]
686
659
  for i in range(num_freqs)[sl]:
@@ -690,14 +663,15 @@ class BeamformerBase(HasStrictTraits):
690
663
  return h
691
664
  return self._f[sl], h[sl]
692
665
 
693
- h = zeros(len(frange), dtype=float)
666
+ h = np.zeros(len(frange), dtype=float)
694
667
  for i, f in enumerate(frange):
695
668
  h[i] = self.synthetic(f, num).reshape(gshape)[ind].sum()
696
669
  return h
697
670
 
698
671
 
699
672
  class BeamformerFunctional(BeamformerBase):
700
- """Functional beamforming algorithm.
673
+ """
674
+ Functional beamforming algorithm.
701
675
 
702
676
  See :cite:`Dougherty2014` for details.
703
677
  """
@@ -723,7 +697,8 @@ class BeamformerFunctional(BeamformerBase):
723
697
  return digest(self)
724
698
 
725
699
  def _calc(self, ind):
726
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
700
+ """
701
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
727
702
 
728
703
  This is an internal helper function that is automatically called when
729
704
  accessing the beamformer's :attr:`result` or calling
@@ -738,7 +713,6 @@ class BeamformerFunctional(BeamformerBase):
738
713
  Returns
739
714
  -------
740
715
  This method only returns values through :attr:`_ac` and :attr:`_fr`
741
-
742
716
  """
743
717
  f = self._f
744
718
  normfactor = self.sig_loss_norm()
@@ -756,8 +730,8 @@ class BeamformerFunctional(BeamformerBase):
756
730
  # WATCH OUT: This doesn't really produce good results.
757
731
  # ==============================================================================
758
732
  csm = self.freq_data.csm[i]
759
- fill_diagonal(csm, 0)
760
- 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)
761
735
  beamformerOutput, steerNorm = beamformerFreq(
762
736
  param_steer_type,
763
737
  self.r_diag,
@@ -768,11 +742,11 @@ class BeamformerFunctional(BeamformerBase):
768
742
  beamformerOutput /= steerNorm # take normalized steering vec
769
743
 
770
744
  # set (unphysical) negative output values to 0
771
- indNegSign = sign(beamformerOutput) < 0
745
+ indNegSign = np.sign(beamformerOutput) < 0
772
746
  beamformerOutput[indNegSign] = 0.0
773
747
  else:
774
- eva = array(self.freq_data.eva[i], dtype='float64') ** (1.0 / self.gamma)
775
- 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')
776
750
  beamformerOutput, steerNorm = beamformerFreq(
777
751
  param_steer_type,
778
752
  self.r_diag,
@@ -788,7 +762,8 @@ class BeamformerFunctional(BeamformerBase):
788
762
 
789
763
 
790
764
  class BeamformerCapon(BeamformerBase):
791
- """Beamforming using the Capon (Mininimum Variance) algorithm.
765
+ """
766
+ Beamforming using the Capon (Mininimum Variance) algorithm.
792
767
 
793
768
  See :cite:`Capon1969` for details.
794
769
  """
@@ -805,7 +780,8 @@ class BeamformerCapon(BeamformerBase):
805
780
  )
806
781
 
807
782
  def _calc(self, ind):
808
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
783
+ """
784
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
809
785
 
810
786
  This is an internal helper function that is automatically called when
811
787
  accessing the beamformer's :attr:`result` or calling
@@ -820,21 +796,21 @@ class BeamformerCapon(BeamformerBase):
820
796
  Returns
821
797
  -------
822
798
  This method only returns values through :attr:`_ac` and :attr:`_fr`
823
-
824
799
  """
825
800
  f = self._f
826
801
  nMics = self.freq_data.num_channels
827
802
  normfactor = self.sig_loss_norm() * nMics**2
828
803
  param_steer_type, steer_vector = self._beamformer_params()
829
804
  for i in ind:
830
- 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')
831
806
  beamformerOutput = beamformerFreq(param_steer_type, self.r_diag, normfactor, steer_vector(f[i]), csm)[0]
832
807
  self._ac[i] = 1.0 / beamformerOutput
833
808
  self._fr[i] = 1
834
809
 
835
810
 
836
811
  class BeamformerEig(BeamformerBase):
837
- """Beamforming using eigenvalue and eigenvector techniques.
812
+ """
813
+ Beamforming using eigenvalue and eigenvector techniques.
838
814
 
839
815
  See :cite:`Sarradj2005` for details.
840
816
  """
@@ -863,7 +839,8 @@ class BeamformerEig(BeamformerBase):
863
839
  return min(nm - 1, na)
864
840
 
865
841
  def _calc(self, ind):
866
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
842
+ """
843
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
867
844
 
868
845
  This is an internal helper function that is automatically called when
869
846
  accessing the beamformer's :attr:`result` or calling
@@ -878,15 +855,14 @@ class BeamformerEig(BeamformerBase):
878
855
  Returns
879
856
  -------
880
857
  This method only returns values through :attr:`_ac` and :attr:`_fr`
881
-
882
858
  """
883
859
  f = self._f
884
860
  na = int(self.na) # eigenvalue taken into account
885
861
  normfactor = self.sig_loss_norm()
886
862
  param_steer_type, steer_vector = self._beamformer_params()
887
863
  for i in ind:
888
- eva = array(self.freq_data.eva[i], dtype='float64')
889
- 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')
890
866
  beamformerOutput = beamformerFreq(
891
867
  param_steer_type,
892
868
  self.r_diag,
@@ -895,14 +871,15 @@ class BeamformerEig(BeamformerBase):
895
871
  (eva[na : na + 1], eve[:, na : na + 1]),
896
872
  )[0]
897
873
  if self.r_diag: # set (unphysical) negative output values to 0
898
- indNegSign = sign(beamformerOutput) < 0
874
+ indNegSign = np.sign(beamformerOutput) < 0
899
875
  beamformerOutput[indNegSign] = 0
900
876
  self._ac[i] = beamformerOutput
901
877
  self._fr[i] = 1
902
878
 
903
879
 
904
880
  class BeamformerMusic(BeamformerEig):
905
- """Beamforming using the MUSIC algorithm.
881
+ """
882
+ Beamforming using the MUSIC algorithm.
906
883
 
907
884
  See :cite:`Schmidt1986` for details.
908
885
  """
@@ -923,7 +900,8 @@ class BeamformerMusic(BeamformerEig):
923
900
  n = Int(1, desc='assumed number of sources')
924
901
 
925
902
  def _calc(self, ind):
926
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
903
+ """
904
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
927
905
 
928
906
  This is an internal helper function that is automatically called when
929
907
  accessing the beamformer's :attr:`result` or calling
@@ -938,7 +916,6 @@ class BeamformerMusic(BeamformerEig):
938
916
  Returns
939
917
  -------
940
918
  This method only returns values through :attr:`_ac` and :attr:`_fr`
941
-
942
919
  """
943
920
  f = self._f
944
921
  nMics = self.freq_data.num_channels
@@ -946,8 +923,8 @@ class BeamformerMusic(BeamformerEig):
946
923
  normfactor = self.sig_loss_norm() * nMics**2
947
924
  param_steer_type, steer_vector = self._beamformer_params()
948
925
  for i in ind:
949
- eva = array(self.freq_data.eva[i], dtype='float64')
950
- 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')
951
928
  beamformerOutput = beamformerFreq(
952
929
  param_steer_type,
953
930
  self.r_diag,
@@ -960,7 +937,8 @@ class BeamformerMusic(BeamformerEig):
960
937
 
961
938
 
962
939
  class PointSpreadFunction(HasStrictTraits):
963
- """The point spread function.
940
+ """
941
+ The point spread function.
964
942
 
965
943
  This class provides tools to calculate the PSF depending on the used
966
944
  microphone geometry, focus grid, flow environment, etc.
@@ -976,7 +954,7 @@ class PointSpreadFunction(HasStrictTraits):
976
954
  #: Indices of grid points to calculate the PSF for.
977
955
  grid_indices = CArray(
978
956
  dtype=int,
979
- value=array([]),
957
+ value=np.array([]),
980
958
  desc='indices of grid points for psf',
981
959
  ) # value=array([]), value=self.steer.grid.pos(),
982
960
 
@@ -1013,9 +991,10 @@ class PointSpreadFunction(HasStrictTraits):
1013
991
  return digest(self)
1014
992
 
1015
993
  def _get_filecache(self):
1016
- """Function collects cached results from file depending on
1017
- global/local caching behaviour. Returns (None, None) if no cachefile/data
1018
- 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'.
1019
998
  """
1020
999
  filename = 'psf' + self.digest
1021
1000
  nodename = (f'Hz_{self.freq:.2f}').replace('.', '_')
@@ -1047,12 +1026,14 @@ class PointSpreadFunction(HasStrictTraits):
1047
1026
  return (ac, gp)
1048
1027
 
1049
1028
  def _get_psf(self):
1050
- """Implements the :attr:`psf` getter routine.
1029
+ """
1030
+ Implements the :attr:`psf` getter routine.
1031
+
1051
1032
  The point spread function is either loaded or calculated.
1052
1033
  """
1053
1034
  gs = self.steer.grid.size
1054
1035
  if not self.grid_indices.size:
1055
- self.grid_indices = arange(gs)
1036
+ self.grid_indices = np.arange(gs)
1056
1037
 
1057
1038
  if config.global_caching != 'none':
1058
1039
  # print("get filecache..")
@@ -1075,13 +1056,13 @@ class PointSpreadFunction(HasStrictTraits):
1075
1056
  # print("cached results are complete! return.")
1076
1057
  return ac[:, self.grid_indices]
1077
1058
  # print("no caching, calculate result")
1078
- ac = zeros((gs, gs), dtype=self.precision)
1079
- gp = zeros((gs,), dtype='int8')
1059
+ ac = np.zeros((gs, gs), dtype=self.precision)
1060
+ gp = np.zeros((gs,), dtype='int8')
1080
1061
  self.calc_psf(ac, gp)
1081
1062
  else: # no caching activated
1082
1063
  # print("no caching activated, calculate result")
1083
- ac = zeros((gs, gs), dtype=self.precision)
1084
- gp = zeros((gs,), dtype='int8')
1064
+ ac = np.zeros((gs, gs), dtype=self.precision)
1065
+ gp = np.zeros((gs,), dtype='int8')
1085
1066
  self.calc_psf(ac, gp)
1086
1067
  return ac[:, self.grid_indices]
1087
1068
 
@@ -1090,7 +1071,7 @@ class PointSpreadFunction(HasStrictTraits):
1090
1071
  if self.calcmode != 'full':
1091
1072
  # calc_ind has the form [True, True, False, True], except
1092
1073
  # when it has only 1 entry (value True/1 would be ambiguous)
1093
- 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])
1094
1075
 
1095
1076
  # get indices which have the value True = not yet calculated
1096
1077
  g_ind_calc = self.grid_indices[calc_ind]
@@ -1101,7 +1082,7 @@ class PointSpreadFunction(HasStrictTraits):
1101
1082
  gp[ind] = 1
1102
1083
  elif self.calcmode == 'full': # calculate all psfs in one go
1103
1084
  gp[:] = 1
1104
- ac[:] = self._psf_call(arange(self.steer.grid.size))
1085
+ ac[:] = self._psf_call(np.arange(self.steer.grid.size))
1105
1086
  else: # 'block' # calculate selected psfs in one go
1106
1087
  hh = self._psf_call(g_ind_calc)
1107
1088
  for indh, ind in enumerate(g_ind_calc):
@@ -1110,7 +1091,8 @@ class PointSpreadFunction(HasStrictTraits):
1110
1091
  indh += 1
1111
1092
 
1112
1093
  def _psf_call(self, ind):
1113
- """Manages the calling of the core psf functionality.
1094
+ """
1095
+ Manages the calling of the core psf functionality.
1114
1096
 
1115
1097
  Parameters
1116
1098
  ----------
@@ -1127,20 +1109,21 @@ class PointSpreadFunction(HasStrictTraits):
1127
1109
  self.steer.steer_type,
1128
1110
  self.steer.r0,
1129
1111
  self.steer.rm,
1130
- 2 * pi * self.freq / self.steer.env.c,
1112
+ 2 * np.pi * self.freq / self.steer.env.c,
1131
1113
  ind,
1132
1114
  self.precision,
1133
1115
  )
1134
1116
  else:
1135
1117
  # for arbitrary steering sectors, use general calculation. there is a version of this in
1136
1118
  # fastFuncs, may be used later after runtime testing and debugging
1137
- 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)
1138
1120
  result = (product * product.conj()).real
1139
1121
  return result
1140
1122
 
1141
1123
 
1142
1124
  class BeamformerDamas(BeamformerBase):
1143
- """DAMAS deconvolution algorithm.
1125
+ """
1126
+ DAMAS deconvolution algorithm.
1144
1127
 
1145
1128
  See :cite:`Brooks2006` for details.
1146
1129
  """
@@ -1168,7 +1151,8 @@ class BeamformerDamas(BeamformerBase):
1168
1151
  return digest(self)
1169
1152
 
1170
1153
  def _calc(self, ind):
1171
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1154
+ """
1155
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1172
1156
 
1173
1157
  This is an internal helper function that is automatically called when
1174
1158
  accessing the beamformer's :attr:`result` or calling
@@ -1183,14 +1167,13 @@ class BeamformerDamas(BeamformerBase):
1183
1167
  Returns
1184
1168
  -------
1185
1169
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1186
-
1187
1170
  """
1188
1171
  f = self._f
1189
1172
  normfactor = self.sig_loss_norm()
1190
1173
  p = PointSpreadFunction(steer=self.steer, calcmode=self.calcmode, precision=self.psf_precision)
1191
1174
  param_steer_type, steer_vector = self._beamformer_params()
1192
1175
  for i in ind:
1193
- csm = array(self.freq_data.csm[i], dtype='complex128')
1176
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1194
1177
  y = beamformerFreq(
1195
1178
  param_steer_type,
1196
1179
  self.r_diag,
@@ -1199,7 +1182,7 @@ class BeamformerDamas(BeamformerBase):
1199
1182
  csm,
1200
1183
  )[0]
1201
1184
  if self.r_diag: # set (unphysical) negative output values to 0
1202
- indNegSign = sign(y) < 0
1185
+ indNegSign = np.sign(y) < 0
1203
1186
  y[indNegSign] = 0.0
1204
1187
  x = y.copy()
1205
1188
  p.freq = f[i]
@@ -1209,12 +1192,13 @@ class BeamformerDamas(BeamformerBase):
1209
1192
  self._fr[i] = 1
1210
1193
 
1211
1194
 
1212
- @deprecated_alias({'max_iter': 'n_iter'}, removal_version='25.10')
1213
1195
  class BeamformerDamasPlus(BeamformerDamas):
1214
- """DAMAS deconvolution :cite:`Brooks2006` for solving the system of equations, instead of the
1215
- original Gauss-Seidel iterations, this class employs the NNLS or linear programming solvers from
1216
- scipy.optimize or one of several optimization algorithms from the scikit-learn module. Needs
1217
- 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`).
1218
1202
  """
1219
1203
 
1220
1204
  #: Type of fit method to be used ('LassoLars',
@@ -1250,7 +1234,8 @@ class BeamformerDamasPlus(BeamformerDamas):
1250
1234
  return digest(self)
1251
1235
 
1252
1236
  def _calc(self, ind):
1253
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1237
+ """
1238
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1254
1239
 
1255
1240
  This is an internal helper function that is automatically called when
1256
1241
  accessing the beamformer's :attr:`result` or calling
@@ -1265,7 +1250,6 @@ class BeamformerDamasPlus(BeamformerDamas):
1265
1250
  Returns
1266
1251
  -------
1267
1252
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1268
-
1269
1253
  """
1270
1254
  f = self._f
1271
1255
  p = PointSpreadFunction(steer=self.steer, calcmode=self.calcmode, precision=self.psf_precision)
@@ -1273,7 +1257,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1273
1257
  normfactor = self.sig_loss_norm()
1274
1258
  param_steer_type, steer_vector = self._beamformer_params()
1275
1259
  for i in ind:
1276
- csm = array(self.freq_data.csm[i], dtype='complex128')
1260
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1277
1261
  y = beamformerFreq(
1278
1262
  param_steer_type,
1279
1263
  self.r_diag,
@@ -1282,7 +1266,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1282
1266
  csm,
1283
1267
  )[0]
1284
1268
  if self.r_diag: # set (unphysical) negative output values to 0
1285
- indNegSign = sign(y) < 0
1269
+ indNegSign = np.sign(y) < 0
1286
1270
  y[indNegSign] = 0.0
1287
1271
  y *= unit
1288
1272
  p.freq = f[i]
@@ -1313,7 +1297,7 @@ class BeamformerDamasPlus(BeamformerDamas):
1313
1297
  # pipeline approach with StandardScaler does scale in a different way, thus we
1314
1298
  # monkeypatch the code and normalize ourselves to make results the same over
1315
1299
  # different sklearn versions
1316
- norms = norm(psf, axis=0)
1300
+ norms = spla.norm(psf, axis=0)
1317
1301
  # get rid of annoying sklearn warnings that appear
1318
1302
  # for sklearn<1.2 despite any settings
1319
1303
  with warnings.catch_warnings():
@@ -1326,7 +1310,8 @@ class BeamformerDamasPlus(BeamformerDamas):
1326
1310
 
1327
1311
 
1328
1312
  class BeamformerOrth(BeamformerBase):
1329
- """Orthogonal deconvolution algorithm.
1313
+ """
1314
+ Orthogonal deconvolution algorithm.
1330
1315
 
1331
1316
  See :cite:`Sarradj2010` for details.
1332
1317
  New faster implementation without explicit (:class:`BeamformerEig`).
@@ -1334,7 +1319,7 @@ class BeamformerOrth(BeamformerBase):
1334
1319
 
1335
1320
  #: List of components to consider, use this to directly set the eigenvalues
1336
1321
  #: used in the beamformer. Alternatively, set :attr:`n`.
1337
- eva_list = CArray(dtype=int, value=array([-1]), desc='components')
1322
+ eva_list = CArray(dtype=int, value=np.array([-1]), desc='components')
1338
1323
 
1339
1324
  #: Number of components to consider, defaults to 1. If set,
1340
1325
  #: :attr:`eva_list` will contain
@@ -1351,13 +1336,14 @@ class BeamformerOrth(BeamformerBase):
1351
1336
  def _get_digest(self):
1352
1337
  return digest(self)
1353
1338
 
1354
- @on_trait_change('n')
1355
- def set_eva_list(self):
1339
+ @observe('n')
1340
+ def _update_eva_list(self, event): # noqa ARG002
1356
1341
  """Sets the list of eigenvalues to consider."""
1357
- self.eva_list = arange(-1, -1 - self.n, -1)
1342
+ self.eva_list = np.arange(-1, -1 - self.n, -1)
1358
1343
 
1359
1344
  def _calc(self, ind):
1360
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1345
+ """
1346
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1361
1347
 
1362
1348
  This is an internal helper function that is automatically called when
1363
1349
  accessing the beamformer's :attr:`result` or calling
@@ -1372,30 +1358,29 @@ class BeamformerOrth(BeamformerBase):
1372
1358
  Returns
1373
1359
  -------
1374
1360
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1375
-
1376
1361
  """
1377
1362
  f = self._f
1378
1363
  num_channels = self.freq_data.num_channels
1379
1364
  normfactor = self.sig_loss_norm()
1380
1365
  param_steer_type, steer_vector = self._beamformer_params()
1381
1366
  for i in ind:
1382
- eva = array(self.freq_data.eva[i], dtype='float64')
1383
- 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')
1384
1369
  for n in self.eva_list:
1385
1370
  beamformerOutput = beamformerFreq(
1386
1371
  param_steer_type,
1387
1372
  self.r_diag,
1388
1373
  normfactor,
1389
1374
  steer_vector(f[i]),
1390
- (ones(1), eve[:, n].reshape((-1, 1))),
1375
+ (np.ones(1), eve[:, n].reshape((-1, 1))),
1391
1376
  )[0]
1392
1377
  self._ac[i, beamformerOutput.argmax()] += eva[n] / num_channels
1393
1378
  self._fr[i] = 1
1394
1379
 
1395
1380
 
1396
- @deprecated_alias({'n': 'n_iter'}, removal_version='25.10')
1397
1381
  class BeamformerCleansc(BeamformerBase):
1398
- """CLEAN-SC deconvolution algorithm.
1382
+ """
1383
+ CLEAN-SC deconvolution algorithm.
1399
1384
 
1400
1385
  See :cite:`Sijtsma2007` for details.
1401
1386
  Classic delay-and-sum beamforming is already included.
@@ -1422,7 +1407,8 @@ class BeamformerCleansc(BeamformerBase):
1422
1407
  return digest(self)
1423
1408
 
1424
1409
  def _calc(self, ind):
1425
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1410
+ """
1411
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1426
1412
 
1427
1413
  This is an internal helper function that is automatically called when
1428
1414
  accessing the beamformer's :attr:`result` or calling
@@ -1437,18 +1423,17 @@ class BeamformerCleansc(BeamformerBase):
1437
1423
  Returns
1438
1424
  -------
1439
1425
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1440
-
1441
1426
  """
1442
1427
  f = self._f
1443
1428
  normfactor = self.sig_loss_norm()
1444
1429
  num_channels = self.freq_data.num_channels
1445
- result = zeros((self.steer.grid.size), 'f')
1430
+ result = np.zeros((self.steer.grid.size), 'f')
1446
1431
  J = num_channels * 2 if not self.n_iter else self.n_iter
1447
- powers = zeros(J, 'd')
1432
+ powers = np.zeros(J, 'd')
1448
1433
 
1449
1434
  param_steer_type, steer_vector = self._beamformer_params()
1450
1435
  for i in ind:
1451
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1436
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1452
1437
  # h = self.steer._beamformerCall(f[i], self.r_diag, normfactor, (csm,))[0]
1453
1438
  h = beamformerFreq(param_steer_type, self.r_diag, normfactor, steer_vector(f[i]), csm)[0]
1454
1439
  # CLEANSC Iteration
@@ -1459,25 +1444,25 @@ class BeamformerCleansc(BeamformerBase):
1459
1444
  result[xi_max] += self.damp * hmax
1460
1445
  if j > self.stopn and hmax > powers[j - self.stopn]:
1461
1446
  break
1462
- wmax = self.steer.steer_vector(f[i], xi_max) * sqrt(normfactor)
1447
+ wmax = self.steer.steer_vector(f[i], xi_max) * np.sqrt(normfactor)
1463
1448
  wmax = wmax[0].conj() # as old code worked with conjugated csm..should be updated
1464
1449
  hh = wmax.copy()
1465
- D1 = dot(csm.T - diag(diag(csm)), wmax) / hmax
1450
+ D1 = np.dot(csm.T - np.diag(np.diag(csm)), wmax) / hmax
1466
1451
  ww = wmax.conj() * wmax
1467
- for _m in range(20):
1452
+ for _ in range(20):
1468
1453
  H = hh.conj() * hh
1469
- hh = (D1 + H * wmax) / sqrt(1 + dot(ww, H))
1470
- hh = hh[:, newaxis]
1454
+ hh = (D1 + H * wmax) / np.sqrt(1 + np.dot(ww, H))
1455
+ hh = hh[:, np.newaxis]
1471
1456
  csm1 = hmax * (hh * hh.conj().T)
1472
1457
 
1473
1458
  # h1 = self.steer._beamformerCall(f[i], self.r_diag, normfactor, \
1474
- # (array((hmax, ))[newaxis, :], hh[newaxis, :].conjugate()))[0]
1459
+ # (np.array((hmax, ))[np.newaxis, :], hh[np.newaxis, :].conjugate()))[0]
1475
1460
  h1 = beamformerFreq(
1476
1461
  param_steer_type,
1477
1462
  self.r_diag,
1478
1463
  normfactor,
1479
1464
  steer_vector(f[i]),
1480
- (array((hmax,)), hh.conj()),
1465
+ (np.array((hmax,)), hh.conj()),
1481
1466
  )[0]
1482
1467
  h -= self.damp * h1
1483
1468
  csm -= self.damp * csm1.T # transpose(0,2,1)
@@ -1486,7 +1471,8 @@ class BeamformerCleansc(BeamformerBase):
1486
1471
 
1487
1472
 
1488
1473
  class BeamformerClean(BeamformerBase):
1489
- """CLEAN deconvolution algorithm.
1474
+ """
1475
+ CLEAN deconvolution algorithm.
1490
1476
 
1491
1477
  See :cite:`Hoegbom1974` for details.
1492
1478
  """
@@ -1529,7 +1515,6 @@ class BeamformerClean(BeamformerBase):
1529
1515
  Returns
1530
1516
  -------
1531
1517
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1532
-
1533
1518
  """
1534
1519
  f = self._f
1535
1520
  gs = self.steer.grid.size
@@ -1545,7 +1530,7 @@ class BeamformerClean(BeamformerBase):
1545
1530
  param_steer_type, steer_vector = self._beamformer_params()
1546
1531
  for i in ind:
1547
1532
  p.freq = f[i]
1548
- csm = array(self.freq_data.csm[i], dtype='complex128')
1533
+ csm = np.array(self.freq_data.csm[i], dtype='complex128')
1549
1534
  dirty = beamformerFreq(
1550
1535
  param_steer_type,
1551
1536
  self.r_diag,
@@ -1554,16 +1539,16 @@ class BeamformerClean(BeamformerBase):
1554
1539
  csm,
1555
1540
  )[0]
1556
1541
  if self.r_diag: # set (unphysical) negative output values to 0
1557
- indNegSign = sign(dirty) < 0
1542
+ indNegSign = np.sign(dirty) < 0
1558
1543
  dirty[indNegSign] = 0.0
1559
1544
 
1560
- clean = zeros(gs, dtype=dirty.dtype)
1545
+ clean = np.zeros(gs, dtype=dirty.dtype)
1561
1546
  i_iter = 0
1562
1547
  flag = True
1563
1548
  while flag:
1564
1549
  dirty_sum = abs(dirty).sum(0)
1565
1550
  next_max = dirty.argmax(0)
1566
- p.grid_indices = array([next_max])
1551
+ p.grid_indices = np.array([next_max])
1567
1552
  psf = p.psf.reshape(gs)
1568
1553
  new_amp = self.damp * dirty[next_max] # / psf[next_max]
1569
1554
  clean[next_max] += new_amp
@@ -1575,9 +1560,9 @@ class BeamformerClean(BeamformerBase):
1575
1560
  self._fr[i] = 1
1576
1561
 
1577
1562
 
1578
- @deprecated_alias({'max_iter': 'n_iter'}, removal_version='25.10')
1579
1563
  class BeamformerCMF(BeamformerBase):
1580
- """Covariance Matrix Fitting algorithm.
1564
+ """
1565
+ Covariance Matrix Fitting algorithm.
1581
1566
 
1582
1567
  This is not really a beamformer, but an inverse method.
1583
1568
  See :cite:`Yardibi2008` for details.
@@ -1644,8 +1629,8 @@ class BeamformerCMF(BeamformerBase):
1644
1629
  def _get_digest(self):
1645
1630
  return digest(self)
1646
1631
 
1647
- @on_trait_change('method')
1648
- def _validate(self):
1632
+ @observe('method')
1633
+ def _validate(self, event): # noqa ARG002
1649
1634
  if self.method in ['FISTA', 'Split_Bregman'] and not config.have_pylops:
1650
1635
  msg = (
1651
1636
  'Cannot import Pylops package. No Pylops installed.'
@@ -1654,7 +1639,8 @@ class BeamformerCMF(BeamformerBase):
1654
1639
  raise ImportError(msg)
1655
1640
 
1656
1641
  def _calc(self, ind):
1657
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1642
+ """
1643
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1658
1644
 
1659
1645
  This is an internal helper function that is automatically called when
1660
1646
  accessing the beamformer's :attr:`result` or calling
@@ -1669,13 +1655,12 @@ class BeamformerCMF(BeamformerBase):
1669
1655
  Returns
1670
1656
  -------
1671
1657
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1672
-
1673
1658
  """
1674
1659
  f = self._f
1675
1660
 
1676
1661
  # function to repack complex matrices to deal with them in real number space
1677
1662
  def realify(matrix):
1678
- return vstack([matrix.real, matrix.imag])
1663
+ return np.vstack([matrix.real, matrix.imag])
1679
1664
 
1680
1665
  # prepare calculation
1681
1666
  nc = self.freq_data.num_channels
@@ -1683,29 +1668,29 @@ class BeamformerCMF(BeamformerBase):
1683
1668
  unit = self.unit_mult
1684
1669
 
1685
1670
  for i in ind:
1686
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1671
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1687
1672
 
1688
1673
  h = self.steer.transfer(f[i]).T
1689
1674
 
1690
1675
  # reduced Kronecker product (only where solution matrix != 0)
1691
- 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)
1692
1677
  Ac = Bc.reshape(nc * nc, num_points)
1693
1678
 
1694
- # get indices for upper triangular matrices (use tril b/c transposed)
1695
- 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
1696
1681
 
1697
- ind_im0 = (reshape(eye(nc), (nc * nc,)) == 0)[ind]
1682
+ ind_im0 = (np.reshape(np.eye(nc), (nc * nc,)) == 0)[ind]
1698
1683
  if self.r_diag:
1699
1684
  # omit main diagonal for noise reduction
1700
- ind_reim = hstack([ind_im0, ind_im0])
1685
+ ind_reim = np.hstack([ind_im0, ind_im0])
1701
1686
  else:
1702
1687
  # take all real parts -- also main diagonal
1703
- ind_reim = hstack([ones(size(ind_im0)) > 0, ind_im0])
1688
+ ind_reim = np.hstack([np.ones(np.size(ind_im0)) > 0, ind_im0])
1704
1689
  ind_reim[0] = True # why this ?
1705
1690
 
1706
1691
  A = realify(Ac[ind, :])[ind_reim, :]
1707
1692
  # use csm.T for column stacking reshape!
1708
- 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
1709
1694
  # choose method
1710
1695
  if self.method == 'LassoLars':
1711
1696
  model = LassoLars(alpha=self.alpha * unit, max_iter=self.n_iter, positive=True, **sklearn_ndict)
@@ -1759,13 +1744,13 @@ class BeamformerCMF(BeamformerBase):
1759
1744
  # function
1760
1745
  func = x.T @ A.T @ A @ x - 2 * R.T @ A @ x + R.T @ R
1761
1746
  # derivitaive
1762
- 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
1763
1748
  return func[0].T, der[:, 0]
1764
1749
 
1765
1750
  # initial guess
1766
- x0 = ones([num_points])
1751
+ x0 = np.ones([num_points])
1767
1752
  # boundaries - set to non negative
1768
- boundaries = tile((0, +inf), (len(x0), 1))
1753
+ boundaries = np.tile((0, np.inf), (len(x0), 1))
1769
1754
 
1770
1755
  # optimize
1771
1756
  self._ac[i], yval, dicts = fmin_l_bfgs_b(
@@ -1791,7 +1776,7 @@ class BeamformerCMF(BeamformerBase):
1791
1776
  # pipeline approach with StandardScaler does scale in a different way, thus we
1792
1777
  # monkeypatch the code and normalize ourselves to make results the same over
1793
1778
  # different sklearn versions
1794
- norms = norm(A, axis=0)
1779
+ norms = spla.norm(A, axis=0)
1795
1780
  # get rid of sklearn warnings that appear for sklearn<1.2 despite any settings
1796
1781
  with warnings.catch_warnings():
1797
1782
  warnings.simplefilter('ignore', category=FutureWarning)
@@ -1802,9 +1787,9 @@ class BeamformerCMF(BeamformerBase):
1802
1787
  self._fr[i] = 1
1803
1788
 
1804
1789
 
1805
- @deprecated_alias({'max_iter': 'n_iter'}, removal_version='25.10')
1806
1790
  class BeamformerSODIX(BeamformerBase):
1807
- """Source directivity modeling in the cross-spectral matrix (SODIX) algorithm.
1791
+ """
1792
+ Source directivity modeling in the cross-spectral matrix (SODIX) algorithm.
1808
1793
 
1809
1794
  See :cite:`Funke2017` and :cite:`Oertwig2019` for details.
1810
1795
  """
@@ -1854,7 +1839,8 @@ class BeamformerSODIX(BeamformerBase):
1854
1839
  return digest(self)
1855
1840
 
1856
1841
  def _calc(self, ind):
1857
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
1842
+ """
1843
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
1858
1844
 
1859
1845
  This is an internal helper function that is automatically called when
1860
1846
  accessing the beamformer's :attr:`result` or calling
@@ -1869,7 +1855,6 @@ class BeamformerSODIX(BeamformerBase):
1869
1855
  Returns
1870
1856
  -------
1871
1857
  This method only returns values through :attr:`_ac` and :attr:`_fr`
1872
-
1873
1858
  """
1874
1859
  # prepare calculation
1875
1860
  f = self._f
@@ -1884,14 +1869,17 @@ class BeamformerSODIX(BeamformerBase):
1884
1869
  for i in range(1, ind.max() + 1):
1885
1870
  if not self._fr[i]:
1886
1871
  # measured csm
1887
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
1872
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
1888
1873
  # transfer function
1889
1874
  h = self.steer.transfer(f[i]).T
1890
1875
 
1891
1876
  if self.method == 'fmin_l_bfgs_b':
1892
1877
  # function to minimize
1893
1878
  def function(directions):
1894
- """Parameters
1879
+ """
1880
+ Calculates SODIX objective function and derivatives for optimization.
1881
+
1882
+ Parameters
1895
1883
  ----------
1896
1884
  directions
1897
1885
  [num_points*num_mics]
@@ -1902,41 +1890,43 @@ class BeamformerSODIX(BeamformerBase):
1902
1890
  [1]
1903
1891
  derdrl - derivitaives in direction of D
1904
1892
  [num_mics*num_points].
1905
-
1906
1893
  """
1907
1894
  #### the sodix function ####
1908
1895
  Djm = directions.reshape([num_points, num_mics])
1909
1896
  p = h.T * Djm
1910
- csm_mod = dot(p.T, p.conj())
1897
+ csm_mod = np.dot(p.T, p.conj())
1911
1898
  Q = csm - csm_mod
1912
- func = sum((absolute(Q)) ** 2)
1899
+ func = np.sum((np.abs(Q)) ** 2)
1913
1900
 
1914
1901
  # subscripts and operands for numpy einsum and einsum_path
1915
1902
  subscripts = 'rl,rm,ml->rl'
1916
1903
  operands = (h.T, h.T.conj() * Djm, Q)
1917
- es_path = einsum_path(subscripts, *operands, optimize='greedy')[0]
1904
+ es_path = np.einsum_path(subscripts, *operands, optimize='greedy')[0]
1918
1905
 
1919
1906
  #### the sodix derivative ####
1920
- derdrl = einsum(subscripts, *operands, optimize=es_path)
1921
- derdrl = -4 * real(derdrl)
1907
+ derdrl = np.einsum(subscripts, *operands, optimize=es_path)
1908
+ derdrl = -4 * np.real(derdrl)
1922
1909
  return func, derdrl.ravel()
1923
1910
 
1924
1911
  ##### initial guess ####
1925
1912
  if not self._fr[(i - 1)]:
1926
- D0 = ones([num_points, num_mics])
1913
+ D0 = np.ones([num_points, num_mics])
1927
1914
  else:
1928
- D0 = sqrt(
1915
+ D0 = np.sqrt(
1929
1916
  self._ac[(i - 1)]
1930
- * 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
+ ),
1931
1921
  )
1932
1922
 
1933
1923
  # boundaries - set to non negative [2*(num_points*num_mics)]
1934
- boundaries = tile((0, +inf), (num_points * num_mics, 1))
1924
+ boundaries = np.tile((0, np.inf), (num_points * num_mics, 1))
1935
1925
 
1936
1926
  # optimize with gradient solver
1937
1927
  # see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_l_bfgs_b.html
1938
1928
 
1939
- qi = ones([num_points, num_mics])
1929
+ qi = np.ones([num_points, num_mics])
1940
1930
  qi, yval, dicts = fmin_l_bfgs_b(
1941
1931
  function,
1942
1932
  D0,
@@ -1959,9 +1949,9 @@ class BeamformerSODIX(BeamformerBase):
1959
1949
  self._fr[i] = 1
1960
1950
 
1961
1951
 
1962
- @deprecated_alias({'max_iter': 'n_iter'}, removal_version='25.10')
1963
1952
  class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
1964
- """Beamforming GIB methods with different normalizations.
1953
+ """
1954
+ Beamforming GIB methods with different normalizations.
1965
1955
 
1966
1956
  See :cite:`Suzuki2011` for details.
1967
1957
  """
@@ -2052,7 +2042,8 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2052
2042
  return min(nm - 1, na)
2053
2043
 
2054
2044
  def _calc(self, ind):
2055
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
2045
+ """
2046
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
2056
2047
 
2057
2048
  This is an internal helper function that is automatically called when
2058
2049
  accessing the beamformer's :attr:`result` or calling
@@ -2067,14 +2058,13 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2067
2058
  Returns
2068
2059
  -------
2069
2060
  This method only returns values through :attr:`_ac` and :attr:`_fr`
2070
-
2071
2061
  """
2072
2062
  f = self._f
2073
2063
  n = int(self.na) # number of eigenvalues
2074
2064
  m = int(self.m) # number of first eigenvalue
2075
2065
  num_channels = self.freq_data.num_channels # number of channels
2076
2066
  num_points = self.steer.grid.size
2077
- hh = zeros((1, num_points, num_channels), dtype='D')
2067
+ hh = np.zeros((1, num_points, num_channels), dtype='D')
2078
2068
 
2079
2069
  # Generate a cross spectral matrix, and perform the eigenvalue decomposition
2080
2070
  for i in ind:
@@ -2083,79 +2073,83 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2083
2073
  hh = self.steer.transfer(f[i])
2084
2074
  A = hh.T
2085
2075
  # eigenvalues and vectors
2086
- csm = array(self.freq_data.csm[i], dtype='complex128', copy=1)
2087
- eva, eve = eigh(csm)
2076
+ csm = np.array(self.freq_data.csm[i], dtype='complex128', copy=True)
2077
+ eva, eve = spla.eigh(csm)
2088
2078
  eva = eva[::-1]
2089
2079
  eve = eve[:, ::-1]
2090
2080
  # set small values zo 0, lowers numerical errors in simulated data
2091
2081
  eva[eva < max(eva) / 1e12] = 0
2092
2082
  # init sources
2093
- qi = zeros([n + m, num_points], dtype='complex128')
2083
+ qi = np.zeros([n + m, num_points], dtype='complex128')
2094
2084
  # Select the number of coherent modes to be processed referring to the eigenvalue
2095
2085
  # distribution.
2096
2086
  for s in list(range(m, n + m)):
2097
2087
  if eva[s] > 0:
2098
2088
  # Generate the corresponding eigenmodes
2099
- emode = array(sqrt(eva[s]) * eve[:, s], dtype='complex128')
2089
+ emode = np.array(np.sqrt(eva[s]) * eve[:, s], dtype='complex128')
2100
2090
  # choose method for computation
2101
2091
  if self.method == 'Suzuki':
2102
2092
  leftpoints = num_points
2103
- locpoints = arange(num_points)
2104
- weights = diag(ones(num_points))
2105
- epsilon = arange(self.n_iter)
2106
- 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):
2107
2097
  if num_channels <= leftpoints:
2108
- AWA = dot(dot(A[:, locpoints], weights), A[:, locpoints].conj().T)
2109
- epsilon[it] = max(absolute(eigvals(AWA))) * self.eps_perc
2110
- qi[s, locpoints] = dot(
2111
- dot(
2112
- dot(weights, A[:, locpoints].conj().T),
2113
- 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]),
2114
2104
  ),
2115
2105
  emode,
2116
2106
  )
2117
2107
  elif num_channels > leftpoints:
2118
- AA = dot(A[:, locpoints].conj().T, A[:, locpoints])
2119
- epsilon[it] = max(absolute(eigvals(AA))) * self.eps_perc
2120
- qi[s, locpoints] = dot(
2121
- 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),
2122
2112
  emode,
2123
2113
  )
2124
2114
  if self.beta < 1 and it > 1:
2125
2115
  # Reorder from the greatest to smallest magnitude to define a
2126
2116
  # reduced-point source distribution, and reform a reduced transfer
2127
2117
  # matrix
2128
- leftpoints = int(round(num_points * self.beta ** (it + 1)))
2129
- 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]
2130
2120
  # print(it, leftpoints, locpoints, idx )
2131
- locpoints = delete(locpoints, [idx[leftpoints::]])
2132
- qix = zeros([n + m, leftpoints], dtype='complex128')
2121
+ locpoints = np.delete(locpoints, [idx[leftpoints::]])
2122
+ qix = np.zeros([n + m, leftpoints], dtype='complex128')
2133
2123
  qix[s, :] = qi[s, locpoints]
2134
2124
  # calc weights for next iteration
2135
- weights = diag(absolute(qix[s, :]) ** (2 - self.pnorm))
2125
+ weights = np.diag(np.abs(qix[s, :]) ** (2 - self.pnorm))
2136
2126
  else:
2137
- weights = diag(absolute(qi[s, :]) ** (2 - self.pnorm))
2127
+ weights = np.diag(np.abs(qi[s, :]) ** (2 - self.pnorm))
2138
2128
 
2139
2129
  elif self.method == 'InverseIRLS':
2140
- weights = eye(num_points)
2141
- locpoints = arange(num_points)
2142
- 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):
2143
2133
  if num_channels <= num_points:
2144
- wtwi = inv(dot(weights.T, weights))
2134
+ wtwi = spla.inv(np.dot(weights.T, weights))
2145
2135
  aH = A.conj().T
2146
- qi[s, :] = dot(dot(wtwi, aH), dot(inv(dot(A, dot(wtwi, aH))), emode))
2147
- weights = diag(absolute(qi[s, :]) ** ((2 - self.pnorm) / 2))
2148
- 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))
2149
2141
  elif num_channels > num_points:
2150
- wtw = dot(weights.T, weights)
2151
- qi[s, :] = dot(dot(inv(dot(dot(A.conj.T, wtw), A)), dot(A.conj().T, wtw)), emode)
2152
- weights = diag(absolute(qi[s, :]) ** ((2 - self.pnorm) / 2))
2153
- 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))
2154
2148
  else:
2155
- locpoints = arange(num_points)
2149
+ locpoints = np.arange(num_points)
2156
2150
  unit = self.unit_mult
2157
- AB = vstack([hstack([A.real, -A.imag]), hstack([A.imag, A.real])])
2158
- 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
2159
2153
  if self.method == 'LassoLars':
2160
2154
  model = LassoLars(alpha=self.alpha * unit, max_iter=self.n_iter, positive=True)
2161
2155
  elif self.method == 'LassoLarsBIC':
@@ -2173,7 +2167,7 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2173
2167
  # way, thus we monkeypatch the code and normalize
2174
2168
  # ourselves to make results the same over different
2175
2169
  # sklearn versions
2176
- norms = norm(AB, axis=0)
2170
+ norms = spla.norm(AB, axis=0)
2177
2171
  # get rid of annoying sklearn warnings that appear
2178
2172
  # for sklearn<1.2 despite any settings
2179
2173
  with warnings.catch_warnings():
@@ -2181,7 +2175,7 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2181
2175
  # normalized A
2182
2176
  model.fit(AB / norms, R)
2183
2177
  # recover normalization in the coef's
2184
- qi_real, qi_imag = hsplit(model.coef_[:] / norms / unit, 2)
2178
+ qi_real, qi_imag = np.hsplit(model.coef_[:] / norms / unit, 2)
2185
2179
  # print(s,qi.size)
2186
2180
  qi[s, locpoints] = qi_real + qi_imag * 1j
2187
2181
  else:
@@ -2192,8 +2186,8 @@ class BeamformerGIB(BeamformerEig): # BeamformerEig #BeamformerBase
2192
2186
  )
2193
2187
  # Generate source maps of all selected eigenmodes, and superpose source intensity
2194
2188
  # for each source type.
2195
- temp = zeros(num_points)
2196
- 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)
2197
2191
  self._ac[i] = temp
2198
2192
  self._fr[i] = 1
2199
2193
 
@@ -2211,7 +2205,8 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2211
2205
  return self._gpos
2212
2206
 
2213
2207
  def integrate(self, sector):
2214
- """Integrates result map over a given sector.
2208
+ """
2209
+ Integrates result map over a given sector.
2215
2210
 
2216
2211
  Parameters
2217
2212
  ----------
@@ -2222,7 +2217,6 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2222
2217
  -------
2223
2218
  array of floats
2224
2219
  The spectrum (all calculated frequency bands) for the integrated sector.
2225
-
2226
2220
  """
2227
2221
  if not isinstance(sector, Sector):
2228
2222
  msg = (
@@ -2235,21 +2229,22 @@ class BeamformerAdaptiveGrid(BeamformerBase, Grid):
2235
2229
 
2236
2230
  ind = self.subdomain(sector)
2237
2231
  r = self.result
2238
- h = zeros(r.shape[0])
2232
+ h = np.zeros(r.shape[0])
2239
2233
  for i in range(r.shape[0]):
2240
2234
  h[i] = r[i][ind].sum()
2241
2235
  return h
2242
2236
 
2243
2237
 
2244
2238
  class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2245
- """Orthogonal beamforming without predefined grid.
2239
+ """
2240
+ Orthogonal beamforming without predefined grid.
2246
2241
 
2247
2242
  See :cite:`Sarradj2022` for details.
2248
2243
  """
2249
2244
 
2250
2245
  #: List of components to consider, use this to directly set the eigenvalues
2251
2246
  #: used in the beamformer. Alternatively, set :attr:`n`.
2252
- eva_list = CArray(dtype=int, value=array([-1]), desc='components')
2247
+ eva_list = CArray(dtype=int, value=np.array([-1]), desc='components')
2253
2248
 
2254
2249
  #: Number of components to consider, defaults to 1. If set,
2255
2250
  #: :attr:`eva_list` will contain
@@ -2286,17 +2281,18 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2286
2281
  def _get_digest(self):
2287
2282
  return digest(self)
2288
2283
 
2289
- @on_trait_change('n')
2290
- def set_eva_list(self):
2284
+ @observe('n')
2285
+ def _update_eva_list(self, event): # noqa ARG002
2291
2286
  """Sets the list of eigenvalues to consider."""
2292
- self.eva_list = arange(-1, -1 - self.n, -1)
2287
+ self.eva_list = np.arange(-1, -1 - self.n, -1)
2293
2288
 
2294
2289
  @property_depends_on('n')
2295
2290
  def _get_size(self):
2296
2291
  return self.n * self.freq_data.fftfreq().shape[0]
2297
2292
 
2298
2293
  def _calc(self, ind):
2299
- """Calculates the result for the frequencies defined by :attr:`freq_data`.
2294
+ """
2295
+ Calculates the result for the frequencies defined by :attr:`freq_data`.
2300
2296
 
2301
2297
  This is an internal helper function that is automatically called when
2302
2298
  accessing the beamformer's :attr:`result` or calling
@@ -2311,13 +2307,12 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2311
2307
  Returns
2312
2308
  -------
2313
2309
  This method only returns values through :attr:`_ac` and :attr:`_fr`
2314
-
2315
2310
  """
2316
2311
  f = self._f
2317
2312
  normfactor = self.sig_loss_norm()
2318
2313
  num_channels = self.freq_data.num_channels
2319
2314
  # eigenvalue number list in standard form from largest to smallest
2320
- 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]
2321
2316
  steer_type = self.steer.steer_type
2322
2317
  if steer_type == 'custom':
2323
2318
  msg = 'custom steer_type is not implemented'
@@ -2336,27 +2331,27 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2336
2331
  for y in self.bounds[1]:
2337
2332
  for z in self.bounds[2]:
2338
2333
  roi.append((x, y, z))
2339
- self.steer.env.roi = array(roi).T
2340
- bmin = array(tuple(map(min, self.bounds)))
2341
- 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)))
2342
2337
  for i in ind:
2343
- eva = array(self.freq_data.eva[i], dtype='float64')
2344
- eve = array(self.freq_data.eve[i], dtype='complex128')
2345
- 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
2346
2341
  for j, n in enumerate(eva_list):
2347
2342
  # print(f[i],n)
2348
2343
 
2349
2344
  def func(xy):
2350
2345
  # function to minimize globally
2351
- xy = clip(xy, bmin, bmax)
2352
- r0 = env._r(xy[:, newaxis])
2353
- 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)
2354
2349
  return -beamformerFreq(
2355
2350
  steer_type,
2356
2351
  self.r_diag,
2357
2352
  normfactor,
2358
2353
  (r0, rm, k),
2359
- (ones(1), eve[:, n : n + 1]),
2354
+ (np.ones(1), eve[:, n : n + 1]),
2360
2355
  )[0][0] # noqa: B023
2361
2356
 
2362
2357
  # simplical global homotopy optimizer
@@ -2372,7 +2367,8 @@ class BeamformerGridlessOrth(BeamformerAdaptiveGrid):
2372
2367
 
2373
2368
 
2374
2369
  def L_p(x): # noqa: N802
2375
- r"""Calculates the sound pressure level from the squared sound pressure.
2370
+ r"""
2371
+ Calculates the sound pressure level from the squared sound pressure.
2376
2372
 
2377
2373
  :math:`L_p = 10 \lg ( x / 4\cdot 10^{-10})`
2378
2374
 
@@ -2386,17 +2382,17 @@ def L_p(x): # noqa: N802
2386
2382
  array of floats
2387
2383
  The corresponding sound pressure levels in dB.
2388
2384
  If `x<0`, -350.0 dB is returned.
2389
-
2390
2385
  """
2391
2386
  # new version to prevent division by zero warning for float32 arguments
2392
- return 10 * log10(clip(x / 4e-10, 1e-35, None))
2387
+ return 10 * np.log10(np.clip(x / 4e-10, 1e-35, None))
2393
2388
 
2394
2389
 
2395
- # return where(x>0, 10*log10(x/4e-10), -1000.)
2390
+ # return where(x>0, 10*np.log10(x/4e-10), -1000.)
2396
2391
 
2397
2392
 
2398
2393
  def integrate(data, grid, sector):
2399
- """Integrates a sound pressure map over a given sector.
2394
+ """
2395
+ Integrates a sound pressure map over a given sector.
2400
2396
 
2401
2397
  This function can be applied on beamforming results to
2402
2398
  quantitatively analyze the sound pressure in a given sector.
@@ -2424,8 +2420,8 @@ def integrate(data, grid, sector):
2424
2420
  of a :class:`~acoular.grids.Grid`-derived class
2425
2421
  (e.g. :meth:`RectGrid.indices<acoular.grids.RectGrid.indices>`
2426
2422
  or :meth:`RectGrid3D.indices<acoular.grids.RectGrid3D.indices>`).
2427
- Possible sectors would be `array([xmin, ymin, xmax, ymax])`
2428
- or `array([x, y, radius])`.
2423
+ Possible sectors would be `np.array([xmin, ymin, xmax, ymax])`
2424
+ or `np.array([x, y, radius])`.
2429
2425
  Alternatively, a :class:`~acoular.grids.Sector`-derived object
2430
2426
  can be used.
2431
2427
 
@@ -2433,7 +2429,6 @@ def integrate(data, grid, sector):
2433
2429
  -------
2434
2430
  array of floats
2435
2431
  The spectrum (all calculated frequency bands) for the integrated sector.
2436
-
2437
2432
  """
2438
2433
  if isinstance(sector, Sector):
2439
2434
  ind = grid.subdomain(sector)
@@ -2451,10 +2446,10 @@ def integrate(data, grid, sector):
2451
2446
 
2452
2447
  gshape = grid.shape
2453
2448
  gsize = grid.size
2454
- if size(data) == gsize: # one value per grid point
2449
+ if np.size(data) == gsize: # one value per grid point
2455
2450
  h = data.reshape(gshape)[ind].sum()
2456
2451
  elif data.ndim == 2 and data.shape[1] == gsize:
2457
- h = zeros(data.shape[0])
2452
+ h = np.zeros(data.shape[0])
2458
2453
  for i in range(data.shape[0]):
2459
2454
  h[i] = data[i].reshape(gshape)[ind].sum()
2460
2455
  return h