acoular 24.3__py3-none-any.whl → 24.7__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.
Files changed (139) hide show
  1. acoular/__init__.py +119 -54
  2. acoular/calib.py +29 -38
  3. acoular/configuration.py +132 -82
  4. acoular/demo/__init__.py +10 -4
  5. acoular/demo/acoular_demo.py +73 -55
  6. acoular/environments.py +270 -264
  7. acoular/fastFuncs.py +366 -196
  8. acoular/fbeamform.py +1797 -1934
  9. acoular/grids.py +504 -548
  10. acoular/h5cache.py +74 -83
  11. acoular/h5files.py +159 -142
  12. acoular/internal.py +13 -14
  13. acoular/microphones.py +57 -53
  14. acoular/sdinput.py +57 -53
  15. acoular/signals.py +180 -178
  16. acoular/sources.py +920 -724
  17. acoular/spectra.py +353 -363
  18. acoular/tbeamform.py +416 -416
  19. acoular/tfastfuncs.py +180 -104
  20. acoular/tools/__init__.py +25 -0
  21. acoular/tools/aiaa.py +185 -0
  22. acoular/tools/helpers.py +189 -0
  23. acoular/tools/metrics.py +165 -0
  24. acoular/tprocess.py +1240 -1182
  25. acoular/traitsviews.py +513 -501
  26. acoular/trajectory.py +50 -52
  27. acoular/version.py +5 -6
  28. acoular/xml/minidsp_uma-16.xml +20 -0
  29. acoular/xml/{minidsp_uma16.xml → minidsp_uma-16_mirrored.xml} +3 -0
  30. {acoular-24.3.dist-info → acoular-24.7.dist-info}/METADATA +58 -39
  31. acoular-24.7.dist-info/RECORD +50 -0
  32. {acoular-24.3.dist-info → acoular-24.7.dist-info}/WHEEL +1 -1
  33. acoular-24.7.dist-info/licenses/LICENSE +28 -0
  34. acoular/fileimport.py +0 -380
  35. acoular/nidaqimport.py +0 -273
  36. acoular/tests/reference_data/BeamformerBase.npy +0 -0
  37. acoular/tests/reference_data/BeamformerBaseFalse1.npy +0 -0
  38. acoular/tests/reference_data/BeamformerBaseFalse2.npy +0 -0
  39. acoular/tests/reference_data/BeamformerBaseFalse3.npy +0 -0
  40. acoular/tests/reference_data/BeamformerBaseFalse4.npy +0 -0
  41. acoular/tests/reference_data/BeamformerBaseTrue1.npy +0 -0
  42. acoular/tests/reference_data/BeamformerBaseTrue2.npy +0 -0
  43. acoular/tests/reference_data/BeamformerBaseTrue3.npy +0 -0
  44. acoular/tests/reference_data/BeamformerBaseTrue4.npy +0 -0
  45. acoular/tests/reference_data/BeamformerCMFLassoLarsBIC.npy +0 -0
  46. acoular/tests/reference_data/BeamformerCMFNNLS.npy +0 -0
  47. acoular/tests/reference_data/BeamformerCapon.npy +0 -0
  48. acoular/tests/reference_data/BeamformerClean.npy +0 -0
  49. acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
  50. acoular/tests/reference_data/BeamformerCleant.npy +0 -0
  51. acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
  52. acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
  53. acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
  54. acoular/tests/reference_data/BeamformerDamas.npy +0 -0
  55. acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
  56. acoular/tests/reference_data/BeamformerEig.npy +0 -0
  57. acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
  58. acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
  59. acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
  60. acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
  61. acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
  62. acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
  63. acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
  64. acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
  65. acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
  66. acoular/tests/reference_data/BeamformerGIB.npy +0 -0
  67. acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
  68. acoular/tests/reference_data/BeamformerMusic.npy +0 -0
  69. acoular/tests/reference_data/BeamformerOrth.npy +0 -0
  70. acoular/tests/reference_data/BeamformerSODIX.npy +0 -0
  71. acoular/tests/reference_data/BeamformerTime.npy +0 -0
  72. acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
  73. acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
  74. acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
  75. acoular/tests/reference_data/Environment.npy +0 -0
  76. acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
  77. acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
  78. acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  79. acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
  80. acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
  81. acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
  82. acoular/tests/reference_data/FiltOctave__.npy +0 -0
  83. acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  84. acoular/tests/reference_data/Filter__.npy +0 -0
  85. acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
  86. acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
  87. acoular/tests/reference_data/OpenJet.npy +0 -0
  88. acoular/tests/reference_data/PointSource.npy +0 -0
  89. acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
  90. acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
  91. acoular/tests/reference_data/RotatingFlow.npy +0 -0
  92. acoular/tests/reference_data/SlotJet.npy +0 -0
  93. acoular/tests/reference_data/TimeAverage__.npy +0 -0
  94. acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
  95. acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
  96. acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
  97. acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
  98. acoular/tests/reference_data/TimeInOut__.npy +0 -0
  99. acoular/tests/reference_data/TimePower__.npy +0 -0
  100. acoular/tests/reference_data/TimeReverse__.npy +0 -0
  101. acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
  102. acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
  103. acoular/tests/run_tests.sh +0 -18
  104. acoular/tests/run_tests_osx.sh +0 -16
  105. acoular/tests/test.npy +0 -0
  106. acoular/tests/test_beamformer_results.py +0 -213
  107. acoular/tests/test_classes.py +0 -60
  108. acoular/tests/test_digest.py +0 -125
  109. acoular/tests/test_environments.py +0 -73
  110. acoular/tests/test_example1.py +0 -124
  111. acoular/tests/test_grid.py +0 -92
  112. acoular/tests/test_integrate.py +0 -102
  113. acoular/tests/test_signals.py +0 -60
  114. acoular/tests/test_sources.py +0 -65
  115. acoular/tests/test_spectra.py +0 -38
  116. acoular/tests/test_timecache.py +0 -35
  117. acoular/tests/test_tprocess.py +0 -90
  118. acoular/tests/test_traj_beamformer_results.py +0 -164
  119. acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
  120. acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
  121. acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
  122. acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
  123. acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
  124. acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
  125. acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
  126. acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
  127. acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
  128. acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
  129. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
  130. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
  131. acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
  132. acoular/tests/unsupported/functionalBeamformer.py +0 -123
  133. acoular/tests/unsupported/precisionTest.py +0 -153
  134. acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
  135. acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
  136. acoular/tools.py +0 -422
  137. acoular-24.3.dist-info/RECORD +0 -148
  138. acoular-24.3.dist-info/licenses/LICENSE +0 -29
  139. {acoular-24.3.dist-info → acoular-24.7.dist-info}/licenses/AUTHORS.rst +0 -0
acoular/tbeamform.py CHANGED
@@ -1,8 +1,6 @@
1
- # -*- coding: utf-8 -*-
2
- #pylint: disable-msg=E0611, E1101, C0103, R0901, R0902, R0903, R0904, W0232
3
- #------------------------------------------------------------------------------
1
+ # ------------------------------------------------------------------------------
4
2
  # Copyright (c) Acoular Development Team.
5
- #------------------------------------------------------------------------------
3
+ # ------------------------------------------------------------------------------
6
4
  """Implements beamformers in the time domain.
7
5
 
8
6
  .. autosummary::
@@ -20,245 +18,258 @@
20
18
  """
21
19
 
22
20
  # imports from other packages
23
- from __future__ import print_function, division
24
- from numpy import array, newaxis, empty, sqrt, arange, r_, zeros, \
25
- histogram, unique, dot, where, s_ , sum, isscalar, full, ceil, argmax,\
26
- interp,concatenate, float32, float64, int32, int64
21
+ import contextlib
22
+ from warnings import warn
23
+
24
+ from numpy import (
25
+ arange,
26
+ argmax,
27
+ array,
28
+ ceil,
29
+ concatenate,
30
+ dot,
31
+ empty,
32
+ float32,
33
+ float64,
34
+ histogram,
35
+ int32,
36
+ int64,
37
+ interp,
38
+ isscalar,
39
+ newaxis,
40
+ r_,
41
+ s_,
42
+ sqrt,
43
+ sum,
44
+ unique,
45
+ where,
46
+ zeros,
47
+ )
27
48
  from numpy.linalg import norm
28
- from traits.api import Float, CArray, Property, Trait, Bool, Delegate, \
29
- cached_property, List, Instance, Range, Int, Enum
49
+ from traits.api import Bool, CArray, Delegate, Enum, Float, Instance, Int, List, Property, Range, Trait, cached_property
30
50
  from traits.trait_errors import TraitError
31
- from warnings import warn
51
+
52
+ from .fbeamform import SteeringVector
53
+ from .grids import RectGrid
32
54
 
33
55
  # acoular imports
34
56
  from .internal import digest
35
- from .grids import RectGrid
36
- from .trajectory import Trajectory
57
+ from .tfastfuncs import _delayandsum4, _delayandsum5, _delays, _steer_I, _steer_II, _steer_III, _steer_IV
37
58
  from .tprocess import TimeInOut
38
- from .fbeamform import SteeringVector, L_p
39
- from .tfastfuncs import _delayandsum4, _delayandsum5, \
40
- _steer_I, _steer_II, _steer_III, _steer_IV, _delays, _modf
59
+ from .trajectory import Trajectory
41
60
 
42
61
 
43
- def const_power_weight( bf ):
44
- """
45
- Internal helper function for :class:`BeamformerTime`
46
-
47
- Provides microphone weighting
62
+ def const_power_weight(bf):
63
+ """Internal helper function for :class:`BeamformerTime`.
64
+
65
+ Provides microphone weighting
48
66
  to make the power per unit area of the
49
67
  microphone array geometry constant.
50
-
68
+
51
69
  Parameters
52
70
  ----------
53
71
  bf: :class:`BeamformerTime` object
54
-
55
-
72
+
73
+
56
74
  Returns
57
75
  -------
58
76
  array of floats
59
77
  The weight factors.
60
- """
61
78
 
62
- r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.mpos) # distances to center
79
+ """
80
+ r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.mpos) # distances to center
63
81
  # round the relative distances to one decimal place
64
- r = (r/r.max()).round(decimals=1)
82
+ r = (r / r.max()).round(decimals=1)
65
83
  ru, ind = unique(r, return_inverse=True)
66
- ru = (ru[1:]+ru[:-1])/2
67
- count, bins = histogram(r, r_[0, ru, 1.5*r.max()-0.5*ru[-1]])
84
+ ru = (ru[1:] + ru[:-1]) / 2
85
+ count, bins = histogram(r, r_[0, ru, 1.5 * r.max() - 0.5 * ru[-1]])
68
86
  bins *= bins
69
- weights = sqrt((bins[1:]-bins[:-1])/count)
87
+ weights = sqrt((bins[1:] - bins[:-1]) / count)
70
88
  weights /= weights.mean()
71
89
  return weights[ind]
72
90
 
91
+
73
92
  # possible choices for spatial weights
74
- possible_weights = {'none':None,
75
- 'power':const_power_weight}
93
+ possible_weights = {'none': None, 'power': const_power_weight}
76
94
 
77
95
 
78
- class BeamformerTime( TimeInOut ):
79
- """
80
- Provides a basic time domain beamformer with time signal output
96
+ class BeamformerTime(TimeInOut):
97
+ """Provides a basic time domain beamformer with time signal output
81
98
  for a spatially fixed grid.
82
99
  """
83
100
 
84
-
85
101
  # Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
86
102
  # that contains information about the steering vector. This is a private trait.
87
103
  # Do not set this directly, use `steer` trait instead.
88
- _steer_obj = Instance(SteeringVector(), SteeringVector)
89
-
90
- #: :class:`~acoular.fbeamform.SteeringVector` or derived object.
104
+ _steer_obj = Instance(SteeringVector(), SteeringVector)
105
+
106
+ #: :class:`~acoular.fbeamform.SteeringVector` or derived object.
91
107
  #: Defaults to :class:`~acoular.fbeamform.SteeringVector` object.
92
- steer = Property(desc="steering vector object")
93
-
108
+ steer = Property(desc='steering vector object')
109
+
94
110
  def _get_steer(self):
95
111
  return self._steer_obj
96
-
112
+
97
113
  def _set_steer(self, steer):
98
114
  if type(steer) == SteeringVector:
99
115
  # This condition may be replaced at a later time by: isinstance(steer, SteeringVector): -- (derived classes allowed)
100
116
  self._steer_obj = steer
101
117
  elif steer in ('true level', 'true location', 'classic', 'inverse'):
102
118
  # Type of steering vectors, see also :ref:`Sarradj, 2012<Sarradj2012>`.
103
- warn("Deprecated use of 'steer' trait. "
104
- "Please use object of class 'SteeringVector' in the future.",
105
- Warning, stacklevel = 2)
119
+ warn(
120
+ "Deprecated use of 'steer' trait. Please use object of class 'SteeringVector' in the future.",
121
+ Warning,
122
+ stacklevel=2,
123
+ )
106
124
  self._steer_obj.steer_type = steer
107
125
  else:
108
- raise(TraitError(args=self,
109
- name='steer',
110
- info='SteeringVector',
111
- value=steer))
126
+ raise (TraitError(args=self, name='steer', info='SteeringVector', value=steer))
112
127
 
113
128
  # --- List of backwards compatibility traits and their setters/getters -----------
114
-
115
- # :class:`~acoular.environments.Environment` or derived object.
116
- # Deprecated! Only kept for backwards compatibility.
129
+
130
+ # :class:`~acoular.environments.Environment` or derived object.
131
+ # Deprecated! Only kept for backwards compatibility.
117
132
  # Now governed by :attr:`steer` trait.
118
133
  env = Property()
119
-
134
+
120
135
  def _get_env(self):
121
- return self._steer_obj.env
122
-
136
+ return self._steer_obj.env
137
+
123
138
  def _set_env(self, env):
124
- warn("Deprecated use of 'env' trait. ", Warning, stacklevel = 2)
139
+ warn("Deprecated use of 'env' trait. ", Warning, stacklevel=2)
125
140
  self._steer_obj.env = env
126
-
141
+
127
142
  # The speed of sound.
128
- # Deprecated! Only kept for backwards compatibility.
143
+ # Deprecated! Only kept for backwards compatibility.
129
144
  # Now governed by :attr:`steer` trait.
130
145
  c = Property()
131
-
146
+
132
147
  def _get_c(self):
133
148
  return self._steer_obj.env.c
134
-
149
+
135
150
  def _set_c(self, c):
136
- warn("Deprecated use of 'c' trait. ", Warning, stacklevel = 2)
151
+ warn("Deprecated use of 'c' trait. ", Warning, stacklevel=2)
137
152
  self._steer_obj.env.c = c
138
-
153
+
139
154
  # :class:`~acoular.grids.Grid`-derived object that provides the grid locations.
140
- # Deprecated! Only kept for backwards compatibility.
155
+ # Deprecated! Only kept for backwards compatibility.
141
156
  # Now governed by :attr:`steer` trait.
142
157
  grid = Property()
143
158
 
144
159
  def _get_grid(self):
145
160
  return self._steer_obj.grid
146
-
161
+
147
162
  def _set_grid(self, grid):
148
- warn("Deprecated use of 'grid' trait. ", Warning, stacklevel = 2)
163
+ warn("Deprecated use of 'grid' trait. ", Warning, stacklevel=2)
149
164
  self._steer_obj.grid = grid
150
-
165
+
151
166
  # :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
152
- # Deprecated! Only kept for backwards compatibility.
167
+ # Deprecated! Only kept for backwards compatibility.
153
168
  # Now governed by :attr:`steer` trait
154
169
  mpos = Property()
155
-
170
+
156
171
  def _get_mpos(self):
157
172
  return self._steer_obj.mics
158
-
173
+
159
174
  def _set_mpos(self, mpos):
160
- warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel = 2)
175
+ warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
161
176
  self._steer_obj.mics = mpos
162
-
163
-
177
+
164
178
  # Sound travel distances from microphone array center to grid points (r0)
165
179
  # and all array mics to grid points (rm). Readonly.
166
- # Deprecated! Only kept for backwards compatibility.
180
+ # Deprecated! Only kept for backwards compatibility.
167
181
  # Now governed by :attr:`steer` trait
168
182
  r0 = Property()
183
+
169
184
  def _get_r0(self):
170
185
  return self._steer_obj.r0
171
-
186
+
172
187
  rm = Property()
188
+
173
189
  def _get_rm(self):
174
190
  return self._steer_obj.rm
175
-
191
+
176
192
  # --- End of backwards compatibility traits --------------------------------------
177
193
 
178
194
  #: Number of channels in output (=number of grid points).
179
195
  numchannels = Delegate('grid', 'size')
180
196
 
181
197
  #: Spatial weighting function.
182
- weights = Trait('none', possible_weights,
183
- desc="spatial weighting function")
198
+ weights = Trait('none', possible_weights, desc='spatial weighting function')
184
199
  # (from timedomain.possible_weights)
185
200
 
186
- # buffer with microphone time signals used for processing. Internal use
187
- buffer = CArray(desc="buffer containing microphone signals")
188
-
201
+ # buffer with microphone time signals used for processing. Internal use
202
+ buffer = CArray(desc='buffer containing microphone signals')
203
+
189
204
  # index indicating position of current processing sample. Internal use.
190
- bufferIndex = Int(desc="index indicating position in buffer")
205
+ bufferIndex = Int(desc='index indicating position in buffer') # noqa: N815
191
206
 
192
207
  # internal identifier
193
- digest = Property(
194
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', '__class__'],
195
- )
208
+ digest = Property(
209
+ depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__'],
210
+ )
196
211
 
197
212
  @cached_property
198
- def _get_digest( self ):
213
+ def _get_digest(self):
199
214
  return digest(self)
200
-
215
+
201
216
  def _get_weights(self):
202
- if self.weights_:
203
- w = self.weights_(self)[newaxis]
204
- else:
205
- w = 1.0
206
- return w
217
+ return self.weights_(self)[newaxis] if self.weights_ else 1.0
207
218
 
208
- def _fill_buffer(self,num):
209
- """ generator that fills the signal buffer """
219
+ def _fill_buffer(self, num):
220
+ """Generator that fills the signal buffer."""
210
221
  weights = self._get_weights()
211
222
  for block in self.source.result(num):
212
223
  block *= weights
213
224
  ns = block.shape[0]
214
225
  bufferSize = self.buffer.shape[0]
215
- self.buffer[0:(bufferSize-ns)] = self.buffer[-(bufferSize-ns):]
216
- self.buffer[-ns:,:] = block
226
+ self.buffer[0 : (bufferSize - ns)] = self.buffer[-(bufferSize - ns) :]
227
+ self.buffer[-ns:, :] = block
217
228
  self.bufferIndex -= ns
218
229
  yield
219
-
220
- def result( self, num=2048 ):
221
- """
222
- Python generator that yields the *squared* deconvolved beamformer
230
+
231
+ def result(self, num=2048):
232
+ """Python generator that yields the *squared* deconvolved beamformer
223
233
  output with optional removal of autocorrelation block-wise.
224
-
234
+
225
235
  Parameters
226
236
  ----------
227
237
  num : integer, defaults to 2048
228
238
  This parameter defines the size of the blocks to be yielded
229
239
  (i.e. the number of samples per block).
230
-
240
+
231
241
  Returns
232
242
  -------
233
243
  Samples in blocks of shape \
234
- (num, :attr:`~BeamformerTime.numchannels`).
244
+ (num, :attr:`~BeamformerTime.numchannels`).
235
245
  :attr:`~BeamformerTime.numchannels` is usually very \
236
246
  large (number of grid points).
237
247
  The last block may be shorter than num. \
238
- The output starts for signals that were emitted
248
+ The output starts for signals that were emitted
239
249
  from the grid at `t=0`.
250
+
240
251
  """
241
252
  # initialize values
242
253
  fdtype = float64
243
254
  idtype = int64
244
255
  numMics = self.steer.mics.num_mics
245
- n_index = arange(0,num+1)[:,newaxis]
246
- c = self.steer.env.c/self.source.sample_freq
247
- amp = empty((1,self.grid.size,numMics),dtype=fdtype)
248
- #delays = empty((1,self.grid.size,numMics),dtype=fdtype)
249
- d_index = empty((1,self.grid.size,numMics),dtype=idtype)
250
- d_interp2 = empty((1,self.grid.size,numMics),dtype=fdtype)
251
- _steer_III(self.rm[newaxis,:,:],self.r0[newaxis,:],amp)
252
- _delays(self.rm[newaxis,:,:], c, d_interp2, d_index)
256
+ n_index = arange(0, num + 1)[:, newaxis]
257
+ c = self.steer.env.c / self.source.sample_freq
258
+ amp = empty((1, self.grid.size, numMics), dtype=fdtype)
259
+ # delays = empty((1,self.grid.size,numMics),dtype=fdtype)
260
+ d_index = empty((1, self.grid.size, numMics), dtype=idtype)
261
+ d_interp2 = empty((1, self.grid.size, numMics), dtype=fdtype)
262
+ _steer_III(self.rm[newaxis, :, :], self.r0[newaxis, :], amp)
263
+ _delays(self.rm[newaxis, :, :], c, d_interp2, d_index)
253
264
  amp.shape = amp.shape[1:]
254
- #delays.shape = delays.shape[1:]
265
+ # delays.shape = delays.shape[1:]
255
266
  d_index.shape = d_index.shape[1:]
256
267
  d_interp2.shape = d_interp2.shape[1:]
257
- maxdelay = int((self.rm/c).max())+2 + num # +2 because of interpolation
258
- initialNumberOfBlocks = int(ceil(maxdelay/num))
259
- bufferSize=initialNumberOfBlocks*num
260
- self.buffer = zeros((bufferSize,numMics), dtype=float)
261
- self.bufferIndex = bufferSize # indexing current time sample in buffer
268
+ maxdelay = int((self.rm / c).max()) + 2 + num # +2 because of interpolation
269
+ initialNumberOfBlocks = int(ceil(maxdelay / num))
270
+ bufferSize = initialNumberOfBlocks * num
271
+ self.buffer = zeros((bufferSize, numMics), dtype=float)
272
+ self.bufferIndex = bufferSize # indexing current time sample in buffer
262
273
  fill_buffer_generator = self._fill_buffer(num)
263
274
  for _ in range(initialNumberOfBlocks):
264
275
  next(fill_buffer_generator)
@@ -266,495 +277,486 @@ class BeamformerTime( TimeInOut ):
266
277
  # start processing
267
278
  flag = True
268
279
  while flag:
269
- samplesleft = self.buffer.shape[0]-self.bufferIndex
270
- if samplesleft-maxdelay <= 0:
271
- num += samplesleft-maxdelay
272
- maxdelay += samplesleft-maxdelay
273
- n_index = arange(0,num+1)[:,newaxis]
274
- flag=False
280
+ samplesleft = self.buffer.shape[0] - self.bufferIndex
281
+ if samplesleft - maxdelay <= 0:
282
+ num += samplesleft - maxdelay
283
+ maxdelay += samplesleft - maxdelay
284
+ n_index = arange(0, num + 1)[:, newaxis]
285
+ flag = False
275
286
  # init step
276
- p_res = array(
277
- self.buffer[self.bufferIndex:self.bufferIndex+maxdelay,:])
278
- Phi, autopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
287
+ p_res = array(self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :])
288
+ Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
279
289
  if 'Cleant' not in self.__class__.__name__:
280
290
  if 'Sq' not in self.__class__.__name__:
281
291
  yield Phi[:num]
282
- elif self.r_diag:
283
- yield (Phi[:num]**2 - autopow[:num]).clip(min=0)
292
+ elif self.r_diag:
293
+ yield (Phi[:num] ** 2 - autopow[:num]).clip(min=0)
284
294
  else:
285
- yield Phi[:num]**2
295
+ yield Phi[:num] ** 2
286
296
  else:
287
297
  Gamma = zeros(Phi.shape)
288
298
  Gamma_autopow = zeros(Phi.shape)
289
299
  J = 0
290
- # deconvolution
291
- while (J < self.n_iter):
300
+ # deconvolution
301
+ while self.n_iter > J:
292
302
  # print(f"start clean iteration {J+1} of max {self.n_iter}")
293
- if self.r_diag:
294
- powPhi = (Phi[:num]**2-autopow).sum(0).clip(min=0)
295
- else:
296
- powPhi = (Phi[:num]**2).sum(0)
303
+ powPhi = (Phi[:num] ** 2 - autopow).sum(0).clip(min=0) if self.r_diag else (Phi[:num] ** 2).sum(0)
297
304
  imax = argmax(powPhi)
298
305
  t_float = d_interp2[imax] + d_index[imax] + n_index
299
306
  t_ind = t_float.astype(int64)
300
- for m in range(numMics):
301
- p_res[t_ind[:num+1,m],m] -= self.damp*interp(t_ind[:num+1,m],
302
- t_float[:num,m],
303
- Phi[:num,imax]*self.r0[imax]/self.rm[imax,m],
304
- )
305
- nextPhi, nextAutopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
307
+ for m in range(numMics):
308
+ p_res[t_ind[: num + 1, m], m] -= self.damp * interp(
309
+ t_ind[: num + 1, m],
310
+ t_float[:num, m],
311
+ Phi[:num, imax] * self.r0[imax] / self.rm[imax, m],
312
+ )
313
+ nextPhi, nextAutopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
306
314
  if self.r_diag:
307
- pownextPhi = (nextPhi[:num]**2-nextAutopow).sum(0).clip(min=0)
315
+ pownextPhi = (nextPhi[:num] ** 2 - nextAutopow).sum(0).clip(min=0)
308
316
  else:
309
- pownextPhi = (nextPhi[:num]**2).sum(0)
317
+ pownextPhi = (nextPhi[:num] ** 2).sum(0)
310
318
  # print(f"total signal power: {powPhi.sum()}")
311
- if pownextPhi.sum() < powPhi.sum(): # stopping criterion
312
- Gamma[:num,imax] += self.damp*Phi[:num,imax]
313
- Gamma_autopow[:num,imax] = autopow[:num,imax].copy()
314
- Phi=nextPhi
315
- autopow=nextAutopow
319
+ if pownextPhi.sum() < powPhi.sum(): # stopping criterion
320
+ Gamma[:num, imax] += self.damp * Phi[:num, imax]
321
+ Gamma_autopow[:num, imax] = autopow[:num, imax].copy()
322
+ Phi = nextPhi
323
+ autopow = nextAutopow
316
324
  # print(f"clean max: {L_p((Gamma**2).sum(0)/num).max()} dB")
317
325
  J += 1
318
326
  else:
319
327
  break
320
328
  if 'Sq' not in self.__class__.__name__:
321
329
  yield Gamma[:num]
322
- elif self.r_diag:
323
- yield Gamma[:num]**2 - (self.damp**2)*Gamma_autopow[:num]
330
+ elif self.r_diag:
331
+ yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
324
332
  else:
325
- yield Gamma[:num]**2
333
+ yield Gamma[:num] ** 2
326
334
  self.bufferIndex += num
327
- try:
335
+ with contextlib.suppress(StopIteration):
328
336
  next(fill_buffer_generator)
329
- except:
330
- pass
331
337
 
332
- def delay_and_sum(self,num,p_res,d_interp2,d_index,amp):
333
- ''' standard delay-and-sum method '''
334
- result = empty((num, self.grid.size), dtype=float) # output array
335
- autopow = empty((num, self.grid.size), dtype=float) # output array
338
+ def delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
339
+ """Standard delay-and-sum method."""
340
+ result = empty((num, self.grid.size), dtype=float) # output array
341
+ autopow = empty((num, self.grid.size), dtype=float) # output array
336
342
  _delayandsum4(p_res, d_index, d_interp2, amp, result, autopow)
337
- return result, autopow
338
-
343
+ return result, autopow
339
344
 
340
- class BeamformerTimeSq( BeamformerTime ):
341
- """
342
- Provides a time domain beamformer with time-dependend
345
+
346
+ class BeamformerTimeSq(BeamformerTime):
347
+ """Provides a time domain beamformer with time-dependend
343
348
  power signal output and possible autopower removal
344
349
  for a spatially fixed grid.
345
350
  """
346
-
351
+
347
352
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
348
- r_diag = Bool(True,
349
- desc="removal of diagonal")
353
+ r_diag = Bool(True, desc='removal of diagonal')
350
354
 
351
355
  # internal identifier
352
- digest = Property(
353
- depends_on = ['_steer_obj.digest', 'source.digest', 'r_diag', \
354
- 'weights', '__class__'],
355
- )
356
+ digest = Property(
357
+ depends_on=['_steer_obj.digest', 'source.digest', 'r_diag', 'weights', '__class__'],
358
+ )
356
359
 
357
360
  @cached_property
358
- def _get_digest( self ):
361
+ def _get_digest(self):
359
362
  return digest(self)
360
-
361
363
 
362
- class BeamformerTimeTraj( BeamformerTime ):
363
- """
364
- Provides a basic time domain beamformer with time signal output
364
+
365
+ class BeamformerTimeTraj(BeamformerTime):
366
+ """Provides a basic time domain beamformer with time signal output
365
367
  for a grid moving along a trajectory.
366
368
  """
367
369
 
368
-
369
370
  #: :class:`~acoular.trajectory.Trajectory` or derived object.
370
371
  #: Start time is assumed to be the same as for the samples.
371
- trajectory = Trait(Trajectory,
372
- desc="trajectory of the grid center")
372
+ trajectory = Trait(Trajectory, desc='trajectory of the grid center')
373
373
 
374
374
  #: Reference vector, perpendicular to the y-axis of moving grid.
375
- rvec = CArray( dtype=float, shape=(3, ), value=array((0, 0, 0)),
376
- desc="reference vector")
377
-
375
+ rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0)), desc='reference vector')
376
+
378
377
  #: Considering of convective amplification in beamforming formula.
379
- conv_amp = Bool(False,
380
- desc="determines if convective amplification of source is considered")
378
+ conv_amp = Bool(False, desc='determines if convective amplification of source is considered')
381
379
 
382
380
  #: Floating point and integer precision
383
- precision = Trait(64, [32,64],
384
- desc="numeric precision")
381
+ precision = Trait(64, [32, 64], desc='numeric precision')
385
382
 
386
383
  # internal identifier
387
- digest = Property(
388
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', 'precision',\
389
- 'rvec','conv_amp','trajectory.digest', '__class__'],
390
- )
384
+ digest = Property(
385
+ depends_on=[
386
+ '_steer_obj.digest',
387
+ 'source.digest',
388
+ 'weights',
389
+ 'precision',
390
+ 'rvec',
391
+ 'conv_amp',
392
+ 'trajectory.digest',
393
+ '__class__',
394
+ ],
395
+ )
391
396
 
392
397
  @cached_property
393
- def _get_digest( self ):
398
+ def _get_digest(self):
394
399
  return digest(self)
395
-
400
+
396
401
  def get_moving_gpos(self):
397
- """
398
- Python generator that yields the moving grid coordinates samplewise
399
- """
402
+ """Python generator that yields the moving grid coordinates samplewise."""
403
+
400
404
  def cross(a, b):
401
- """ cross product for fast computation
402
- because numpy.cross is ultra slow in this case
405
+ """Cross product for fast computation
406
+ because numpy.cross is ultra slow in this case.
403
407
  """
404
- return array([a[1]*b[2] - a[2]*b[1],
405
- a[2]*b[0] - a[0]*b[2],
406
- a[0]*b[1] - a[1]*b[0]])
408
+ return array([a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]])
407
409
 
408
410
  start_t = 0.0
409
411
  gpos = self.grid.pos()
410
- trajg = self.trajectory.traj( start_t, delta_t=1/self.source.sample_freq)
411
- trajg1 = self.trajectory.traj( start_t, delta_t=1/self.source.sample_freq,
412
- der=1)
413
- rflag = (self.rvec == 0).all() #flag translation vs. rotation
412
+ trajg = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq)
413
+ trajg1 = self.trajectory.traj(start_t, delta_t=1 / self.source.sample_freq, der=1)
414
+ rflag = (self.rvec == 0).all() # flag translation vs. rotation
414
415
  if rflag:
415
416
  for g in trajg:
416
417
  # grid is only translated, not rotated
417
418
  tpos = gpos + array(g)[:, newaxis]
418
419
  yield tpos
419
420
  else:
420
- for (g,g1) in zip(trajg,trajg1):
421
+ for g, g1 in zip(trajg, trajg1):
421
422
  # grid is both translated and rotated
422
- loc = array(g) #translation array([0., 0.4, 1.])
423
- dx = array(g1) #direction vector (new x-axis)
424
- dy = cross(self.rvec, dx) # new y-axis
425
- dz = cross(dx, dy) # new z-axis
426
- RM = array((dx, dy, dz)).T # rotation matrix
427
- RM /= sqrt((RM*RM).sum(0)) # column normalized
428
- tpos = dot(RM, gpos)+loc[:, newaxis] # rotation+translation
429
- # print(loc[:])
423
+ loc = array(g) # translation array([0., 0.4, 1.])
424
+ dx = array(g1) # direction vector (new x-axis)
425
+ dy = cross(self.rvec, dx) # new y-axis
426
+ dz = cross(dx, dy) # new z-axis
427
+ RM = array((dx, dy, dz)).T # rotation matrix
428
+ RM /= sqrt((RM * RM).sum(0)) # column normalized
429
+ tpos = dot(RM, gpos) + loc[:, newaxis] # rotation+translation
430
+ # print(loc[:])
430
431
  yield tpos
431
432
 
432
- def get_macostheta(self,g1,tpos,rm):
433
- vvec = array(g1) # velocity vector
434
- ma = norm(vvec)/self.steer.env.c # machnumber
435
- fdv = (vvec/sqrt((vvec*vvec).sum()))[:, newaxis] # unit vecor velocity
433
+ def get_macostheta(self, g1, tpos, rm):
434
+ vvec = array(g1) # velocity vector
435
+ ma = norm(vvec) / self.steer.env.c # machnumber
436
+ fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
436
437
  mpos = self.steer.mics.mpos[:, newaxis, :]
437
- rmv = tpos[:, :, newaxis]-mpos
438
- return (ma*sum(rmv.reshape((3, -1))*fdv, 0)\
439
- /rm.reshape(-1)).reshape(rm.shape)
438
+ rmv = tpos[:, :, newaxis] - mpos
439
+ return (ma * sum(rmv.reshape((3, -1)) * fdv, 0) / rm.reshape(-1)).reshape(rm.shape)
440
440
 
441
- def get_r0( self, tpos ):
441
+ def get_r0(self, tpos):
442
442
  if isscalar(self.steer.ref) and self.steer.ref > 0:
443
- return self.steer.ref#full((self.steer.grid.size,), self.steer.ref)
444
- else:
445
- return self.env._r(tpos)
443
+ return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
444
+ return self.env._r(tpos)
446
445
 
447
- def increase_buffer( self, num ):
448
- ar = zeros((num,self.steer.mics.num_mics), dtype=self.buffer.dtype)
449
- self.buffer = concatenate((ar,self.buffer), axis=0)
446
+ def increase_buffer(self, num):
447
+ ar = zeros((num, self.steer.mics.num_mics), dtype=self.buffer.dtype)
448
+ self.buffer = concatenate((ar, self.buffer), axis=0)
450
449
  self.bufferIndex += num
451
450
 
452
- def result( self, num=2048 ):
453
- """
454
- Python generator that yields the deconvolved output block-wise.
455
-
451
+ def result(self, num=2048):
452
+ """Python generator that yields the deconvolved output block-wise.
453
+
456
454
  Parameters
457
455
  ----------
458
456
  num : integer, defaults to 2048
459
457
  This parameter defines the size of the blocks to be yielded
460
458
  (i.e. the number of samples per block).
461
-
459
+
462
460
  Returns
463
461
  -------
464
462
  Samples in blocks of shape \
465
- (num, :attr:`~BeamformerTime.numchannels`).
463
+ (num, :attr:`~BeamformerTime.numchannels`).
466
464
  :attr:`~BeamformerTime.numchannels` is usually very \
467
465
  large (number of grid points).
468
466
  The last block may be shorter than num. \
469
- The output starts for signals that were emitted
467
+ The output starts for signals that were emitted
470
468
  from the grid at `t=0`.
469
+
471
470
  """
472
471
  # initialize values
473
- if self.precision==64:
472
+ if self.precision == 64:
474
473
  fdtype = float64
475
474
  idtype = int64
476
475
  else:
477
476
  fdtype = float32
478
477
  idtype = int32
479
478
  w = self._get_weights()
480
- c = self.steer.env.c/self.source.sample_freq
479
+ c = self.steer.env.c / self.source.sample_freq
481
480
  numMics = self.steer.mics.num_mics
482
481
  mpos = self.steer.mics.mpos.astype(fdtype)
483
482
  m_index = arange(numMics, dtype=idtype)
484
- n_index = arange(num,dtype=idtype)[:,newaxis]
485
- blockrm = empty((num,self.grid.size,numMics),dtype=fdtype)
486
- blockrmconv = empty((num,self.grid.size,numMics),dtype=fdtype)
487
- amp = empty((num,self.grid.size,numMics),dtype=fdtype)
488
- #delays = empty((num,self.grid.size,numMics),dtype=fdtype)
489
- d_index = empty((num,self.grid.size,numMics),dtype=idtype)
490
- d_interp2 = empty((num,self.grid.size,numMics),dtype=fdtype)
491
- blockr0 = empty((num,self.grid.size),dtype=fdtype)
492
- self.buffer = zeros((2*num,numMics), dtype=fdtype)
493
- self.bufferIndex = self.buffer.shape[0]
494
- movgpos = self.get_moving_gpos() # create moving grid pos generator
495
- movgspeed = self.trajectory.traj(0.0, delta_t=1/self.source.sample_freq,
496
- der=1)
483
+ n_index = arange(num, dtype=idtype)[:, newaxis]
484
+ blockrm = empty((num, self.grid.size, numMics), dtype=fdtype)
485
+ blockrmconv = empty((num, self.grid.size, numMics), dtype=fdtype)
486
+ amp = empty((num, self.grid.size, numMics), dtype=fdtype)
487
+ # delays = empty((num,self.grid.size,numMics),dtype=fdtype)
488
+ d_index = empty((num, self.grid.size, numMics), dtype=idtype)
489
+ d_interp2 = empty((num, self.grid.size, numMics), dtype=fdtype)
490
+ blockr0 = empty((num, self.grid.size), dtype=fdtype)
491
+ self.buffer = zeros((2 * num, numMics), dtype=fdtype)
492
+ self.bufferIndex = self.buffer.shape[0]
493
+ movgpos = self.get_moving_gpos() # create moving grid pos generator
494
+ movgspeed = self.trajectory.traj(0.0, delta_t=1 / self.source.sample_freq, der=1)
497
495
  fill_buffer_generator = self._fill_buffer(num)
498
- for i in range(2):
496
+ for _i in range(2):
499
497
  next(fill_buffer_generator)
500
-
498
+
501
499
  # preliminary implementation of different steering vectors
502
- steer_func = {'classic' : _steer_I,
503
- 'inverse' : _steer_II,
504
- 'true level' : _steer_III,
505
- 'true location' : _steer_IV
506
- }[self.steer.steer_type]
500
+ steer_func = {
501
+ 'classic': _steer_I,
502
+ 'inverse': _steer_II,
503
+ 'true level': _steer_III,
504
+ 'true location': _steer_IV,
505
+ }[self.steer.steer_type]
507
506
 
508
507
  # start processing
509
508
  flag = True
510
- dflag = True # data is available
509
+ dflag = True # data is available
511
510
  while flag:
512
511
  for i in range(num):
513
512
  tpos = next(movgpos).astype(fdtype)
514
- rm = self.steer.env._r( tpos, mpos )#.astype(fdtype)
515
- blockr0[i,:] = self.get_r0(tpos)
516
- blockrm[i,:,:] = rm
513
+ rm = self.steer.env._r(tpos, mpos) # .astype(fdtype)
514
+ blockr0[i, :] = self.get_r0(tpos)
515
+ blockrm[i, :, :] = rm
517
516
  if self.conv_amp:
518
517
  ht = next(movgspeed)
519
- blockrmconv[i,:,:] = rm*(1-self.get_macostheta(ht,tpos,rm))**2
518
+ blockrmconv[i, :, :] = rm * (1 - self.get_macostheta(ht, tpos, rm)) ** 2
520
519
  if self.conv_amp:
521
520
  steer_func(blockrmconv, blockr0, amp)
522
521
  else:
523
522
  steer_func(blockrm, blockr0, amp)
524
523
  _delays(blockrm, c, d_interp2, d_index)
525
- #_modf(delays, d_interp2, d_index)
526
- maxdelay = (d_index.max((1,2)) + arange(0,num)).max()+2 # + because of interpolation
524
+ # _modf(delays, d_interp2, d_index)
525
+ maxdelay = (d_index.max((1, 2)) + arange(0, num)).max() + 2 # + because of interpolation
527
526
  # increase buffer size because of greater delays
528
527
  while maxdelay > self.buffer.shape[0] and dflag:
529
528
  self.increase_buffer(num)
530
529
  try:
531
530
  next(fill_buffer_generator)
532
- except:
531
+ except StopIteration:
533
532
  dflag = False
534
- samplesleft = self.buffer.shape[0]-self.bufferIndex
533
+ samplesleft = self.buffer.shape[0] - self.bufferIndex
535
534
  # last block may be shorter
536
- if samplesleft-maxdelay <= 0:
537
- num = sum((d_index.max((1,2))+1+arange(0,num)) < samplesleft)
538
- n_index = arange(num,dtype=idtype)[:,newaxis]
539
- flag=False
535
+ if samplesleft - maxdelay <= 0:
536
+ num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < samplesleft)
537
+ n_index = arange(num, dtype=idtype)[:, newaxis]
538
+ flag = False
540
539
  # init step
541
- p_res = self.buffer[self.bufferIndex:self.bufferIndex+maxdelay,:].copy()
542
- Phi, autopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
540
+ p_res = self.buffer[self.bufferIndex : self.bufferIndex + maxdelay, :].copy()
541
+ Phi, autopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
543
542
  if 'Cleant' not in self.__class__.__name__:
544
543
  if 'Sq' not in self.__class__.__name__:
545
544
  yield Phi[:num]
546
- elif self.r_diag:
547
- yield (Phi[:num]**2 - autopow[:num]).clip(min=0)
545
+ elif self.r_diag:
546
+ yield (Phi[:num] ** 2 - autopow[:num]).clip(min=0)
548
547
  else:
549
- yield Phi[:num]**2
548
+ yield Phi[:num] ** 2
550
549
  else:
551
550
  # choose correct distance
552
- if self.conv_amp:
553
- blockrm1 = blockrmconv
554
- else:
555
- blockrm1 = blockrm
556
- Gamma = zeros(Phi.shape,dtype=fdtype)
557
- Gamma_autopow = zeros(Phi.shape,dtype=fdtype)
551
+ blockrm1 = blockrmconv if self.conv_amp else blockrm
552
+ Gamma = zeros(Phi.shape, dtype=fdtype)
553
+ Gamma_autopow = zeros(Phi.shape, dtype=fdtype)
558
554
  J = 0
559
- t_ind = arange(p_res.shape[0],dtype=idtype)
560
- # deconvolution
561
- while (J < self.n_iter):
555
+ t_ind = arange(p_res.shape[0], dtype=idtype)
556
+ # deconvolution
557
+ while self.n_iter > J:
562
558
  # print(f"start clean iteration {J+1} of max {self.n_iter}")
563
559
  if self.r_diag:
564
- powPhi = (Phi[:num]*Phi[:num]-autopow).sum(0).clip(min=0)
560
+ powPhi = (Phi[:num] * Phi[:num] - autopow).sum(0).clip(min=0)
565
561
  else:
566
- powPhi = (Phi[:num]*Phi[:num]).sum(0)
562
+ powPhi = (Phi[:num] * Phi[:num]).sum(0)
567
563
  # find index of max power focus point
568
564
  imax = argmax(powPhi)
569
565
  # find backward delays
570
- t_float = (d_interp2[:num,imax,m_index] + \
571
- d_index[:num,imax,m_index] + \
572
- n_index).astype(fdtype)
566
+ t_float = (d_interp2[:num, imax, m_index] + d_index[:num, imax, m_index] + n_index).astype(fdtype)
573
567
  # determine max/min delays in sample units
574
568
  # + 2 because we do not want to extrapolate behind the last sample
575
- ind_max = t_float.max(0).astype(idtype)+2
569
+ ind_max = t_float.max(0).astype(idtype) + 2
576
570
  ind_min = t_float.min(0).astype(idtype)
577
571
  # store time history at max power focus point
578
- h = Phi[:num,imax]*blockr0[:num,imax]
572
+ h = Phi[:num, imax] * blockr0[:num, imax]
579
573
  for m in range(numMics):
580
574
  # subtract interpolated time history from microphone signals
581
- p_res[ind_min[m]:ind_max[m],m] -= self.damp*interp(
582
- t_ind[ind_min[m]:ind_max[m]],
583
- t_float[:num,m],
584
- h/blockrm1[:num,imax,m],
585
- )
586
- nextPhi, nextAutopow = self.delay_and_sum(num,p_res,d_interp2,d_index,amp)
575
+ p_res[ind_min[m] : ind_max[m], m] -= self.damp * interp(
576
+ t_ind[ind_min[m] : ind_max[m]],
577
+ t_float[:num, m],
578
+ h / blockrm1[:num, imax, m],
579
+ )
580
+ nextPhi, nextAutopow = self.delay_and_sum(num, p_res, d_interp2, d_index, amp)
587
581
  if self.r_diag:
588
- pownextPhi = (nextPhi[:num]*nextPhi[:num]-nextAutopow).sum(0).clip(min=0)
582
+ pownextPhi = (nextPhi[:num] * nextPhi[:num] - nextAutopow).sum(0).clip(min=0)
589
583
  else:
590
- pownextPhi = (nextPhi[:num]*nextPhi[:num]).sum(0)
584
+ pownextPhi = (nextPhi[:num] * nextPhi[:num]).sum(0)
591
585
  # print(f"total signal power: {powPhi.sum()}")
592
- if pownextPhi.sum() < powPhi.sum(): # stopping criterion
593
- Gamma[:num,imax] += self.damp*Phi[:num,imax]
594
- Gamma_autopow[:num,imax] = autopow[:num,imax].copy()
595
- Phi=nextPhi
596
- autopow=nextAutopow
586
+ if pownextPhi.sum() < powPhi.sum(): # stopping criterion
587
+ Gamma[:num, imax] += self.damp * Phi[:num, imax]
588
+ Gamma_autopow[:num, imax] = autopow[:num, imax].copy()
589
+ Phi = nextPhi
590
+ autopow = nextAutopow
597
591
  # print(f"clean max: {L_p((Gamma**2).sum(0)/num).max()} dB")
598
592
  J += 1
599
593
  else:
600
594
  break
601
595
  if 'Sq' not in self.__class__.__name__:
602
596
  yield Gamma[:num]
603
- elif self.r_diag:
604
- yield Gamma[:num]**2 - (self.damp**2)*Gamma_autopow[:num]
597
+ elif self.r_diag:
598
+ yield Gamma[:num] ** 2 - (self.damp**2) * Gamma_autopow[:num]
605
599
  else:
606
- yield Gamma[:num]**2
600
+ yield Gamma[:num] ** 2
607
601
  self.bufferIndex += num
608
602
  try:
609
603
  next(fill_buffer_generator)
610
- except:
604
+ except StopIteration:
611
605
  dflag = False
612
- pass
613
606
 
614
- def delay_and_sum(self,num,p_res,d_interp2,d_index,amp):
615
- ''' standard delay-and-sum method '''
616
- if self.precision==64:
617
- fdtype = float64
618
- else:
619
- fdtype = float32
620
- result = empty((num, self.grid.size), dtype=fdtype) # output array
621
- autopow = empty((num, self.grid.size), dtype=fdtype) # output array
607
+ def delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
608
+ """Standard delay-and-sum method."""
609
+ fdtype = float64 if self.precision == 64 else float32
610
+ result = empty((num, self.grid.size), dtype=fdtype) # output array
611
+ autopow = empty((num, self.grid.size), dtype=fdtype) # output array
622
612
  _delayandsum5(p_res, d_index, d_interp2, amp, result, autopow)
623
- return result, autopow
624
-
625
-
626
- class BeamformerTimeSqTraj( BeamformerTimeSq, BeamformerTimeTraj ):
627
- """
628
- Provides a time domain beamformer with time-dependent
613
+ return result, autopow
614
+
615
+
616
+ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
617
+ """Provides a time domain beamformer with time-dependent
629
618
  power signal output and possible autopower removal
630
619
  for a grid moving along a trajectory.
631
620
  """
632
-
621
+
633
622
  # internal identifier
634
- digest = Property(
635
- depends_on = ['_steer_obj.digest', 'source.digest', 'r_diag', 'weights', 'precision',\
636
- 'rvec','conv_amp','trajectory.digest', '__class__'],
637
- )
623
+ digest = Property(
624
+ depends_on=[
625
+ '_steer_obj.digest',
626
+ 'source.digest',
627
+ 'r_diag',
628
+ 'weights',
629
+ 'precision',
630
+ 'rvec',
631
+ 'conv_amp',
632
+ 'trajectory.digest',
633
+ '__class__',
634
+ ],
635
+ )
638
636
 
639
637
  @cached_property
640
- def _get_digest( self ):
638
+ def _get_digest(self):
641
639
  return digest(self)
642
-
643
640
 
644
- class BeamformerCleant( BeamformerTime ):
645
- """
646
- CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
647
-
648
- An implementation of the CLEAN method in time domain. This class can only
641
+
642
+ class BeamformerCleant(BeamformerTime):
643
+ """CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
644
+
645
+ An implementation of the CLEAN method in time domain. This class can only
649
646
  be used for static sources.
650
647
  """
651
648
 
652
649
  #: Boolean flag, always False
653
- r_diag = Enum(False,
654
- desc="False, as we do not remove autopower in this beamformer")
650
+ r_diag = Enum(False, desc='False, as we do not remove autopower in this beamformer')
655
651
 
656
- #: iteration damping factor also referred as loop gain in Cousson et al.
652
+ #: iteration damping factor also referred as loop gain in Cousson et al.
657
653
  #: defaults to 0.6
658
- damp = Range(0.01, 1.0, 0.6,
659
- desc="damping factor (loop gain)")
654
+ damp = Range(0.01, 1.0, 0.6, desc='damping factor (loop gain)')
660
655
 
661
656
  #: max number of iterations
662
- n_iter = Int(100,
663
- desc="maximum number of iterations")
664
-
657
+ n_iter = Int(100, desc='maximum number of iterations')
658
+
665
659
  # internal identifier
666
- digest = Property(
667
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', \
668
- '__class__','damp','n_iter'],
669
- )
660
+ digest = Property(
661
+ depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__', 'damp', 'n_iter'],
662
+ )
670
663
 
671
664
  @cached_property
672
- def _get_digest( self ):
665
+ def _get_digest(self):
673
666
  return digest(self)
674
667
 
675
668
 
676
- class BeamformerCleantSq( BeamformerCleant ):
677
- """
678
- CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
669
+ class BeamformerCleantSq(BeamformerCleant):
670
+ """CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
679
671
  with optional removal of autocorrelation.
680
-
681
- An implementation of the CLEAN method in time domain. This class can only
672
+
673
+ An implementation of the CLEAN method in time domain. This class can only
682
674
  be used for static sources.
683
675
  """
684
676
 
685
677
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
686
- r_diag = Bool(True,
687
- desc="removal of diagonal")
678
+ r_diag = Bool(True, desc='removal of diagonal')
688
679
 
689
680
  # internal identifier
690
- digest = Property(
691
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', \
692
- '__class__','damp','n_iter','r_diag'],
693
- )
681
+ digest = Property(
682
+ depends_on=['_steer_obj.digest', 'source.digest', 'weights', '__class__', 'damp', 'n_iter', 'r_diag'],
683
+ )
694
684
 
695
685
  @cached_property
696
- def _get_digest( self ):
686
+ def _get_digest(self):
697
687
  return digest(self)
698
-
699
-
700
688
 
701
- class BeamformerCleantTraj( BeamformerCleant, BeamformerTimeTraj ):
702
- """
703
- CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
704
-
689
+
690
+ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
691
+ """CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`.
692
+
705
693
  An implementation of the CLEAN method in time domain for moving sources
706
- with known trajectory.
694
+ with known trajectory.
707
695
  """
696
+
708
697
  #: Floating point and integer precision
709
- precision = Trait(32, [32,64],
710
- desc="numeric precision")
698
+ precision = Trait(32, [32, 64], desc='numeric precision')
711
699
 
712
700
  # internal identifier
713
- digest = Property(
714
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', 'precision', \
715
- '__class__','damp','n_iter', 'rvec','conv_amp',
716
- 'trajectory.digest'],
717
- )
701
+ digest = Property(
702
+ depends_on=[
703
+ '_steer_obj.digest',
704
+ 'source.digest',
705
+ 'weights',
706
+ 'precision',
707
+ '__class__',
708
+ 'damp',
709
+ 'n_iter',
710
+ 'rvec',
711
+ 'conv_amp',
712
+ 'trajectory.digest',
713
+ ],
714
+ )
718
715
 
719
716
  @cached_property
720
- def _get_digest( self ):
717
+ def _get_digest(self):
721
718
  return digest(self)
722
-
723
719
 
724
- class BeamformerCleantSqTraj( BeamformerCleantTraj, BeamformerTimeSq ):
725
- """
726
- CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
720
+
721
+ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
722
+ """CLEANT deconvolution method, see :ref:`Cousson et al., 2019<Cousson2019>`
727
723
  with optional removal of autocorrelation.
728
-
724
+
729
725
  An implementation of the CLEAN method in time domain for moving sources
730
- with known trajectory.
726
+ with known trajectory.
731
727
  """
732
728
 
733
729
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
734
- r_diag = Bool(True,
735
- desc="removal of diagonal")
730
+ r_diag = Bool(True, desc='removal of diagonal')
736
731
 
737
732
  # internal identifier
738
- digest = Property(
739
- depends_on = ['_steer_obj.digest', 'source.digest', 'weights', 'precision', \
740
- '__class__','damp','n_iter', 'rvec','conv_amp',
741
- 'trajectory.digest','r_diag'],
742
- )
733
+ digest = Property(
734
+ depends_on=[
735
+ '_steer_obj.digest',
736
+ 'source.digest',
737
+ 'weights',
738
+ 'precision',
739
+ '__class__',
740
+ 'damp',
741
+ 'n_iter',
742
+ 'rvec',
743
+ 'conv_amp',
744
+ 'trajectory.digest',
745
+ 'r_diag',
746
+ ],
747
+ )
743
748
 
744
749
  @cached_property
745
- def _get_digest( self ):
750
+ def _get_digest(self):
746
751
  return digest(self)
747
-
748
752
 
749
- class IntegratorSectorTime( TimeInOut ):
750
- """
751
- Provides an Integrator in the time domain.
752
- """
753
+
754
+ class IntegratorSectorTime(TimeInOut):
755
+ """Provides an Integrator in the time domain."""
753
756
 
754
757
  #: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
755
- grid = Trait(RectGrid,
756
- desc="beamforming grid")
757
-
758
+ grid = Trait(RectGrid, desc='beamforming grid')
759
+
758
760
  #: List of sectors in grid
759
761
  sectors = List()
760
762
 
@@ -762,51 +764,49 @@ class IntegratorSectorTime( TimeInOut ):
762
764
  clip = Float(-350.0)
763
765
 
764
766
  #: Number of channels in output (= number of sectors).
765
- numchannels = Property( depends_on = ['sectors', ])
767
+ numchannels = Property(depends_on=['sectors'])
766
768
 
767
769
  # internal identifier
768
- digest = Property(
769
- depends_on = ['sectors', 'clip', 'grid.digest', 'source.digest', \
770
- '__class__'],
771
- )
770
+ digest = Property(
771
+ depends_on=['sectors', 'clip', 'grid.digest', 'source.digest', '__class__'],
772
+ )
772
773
 
773
774
  @cached_property
774
- def _get_digest( self ):
775
+ def _get_digest(self):
775
776
  return digest(self)
776
-
777
+
777
778
  @cached_property
778
- def _get_numchannels ( self ):
779
+ def _get_numchannels(self):
779
780
  return len(self.sectors)
780
781
 
781
- def result( self, num=1 ):
782
- """
783
- Python generator that yields the source output integrated over the given
782
+ def result(self, num=1):
783
+ """Python generator that yields the source output integrated over the given
784
784
  sectors, block-wise.
785
-
785
+
786
786
  Parameters
787
787
  ----------
788
788
  num : integer, defaults to 1
789
789
  This parameter defines the size of the blocks to be yielded
790
790
  (i.e. the number of samples per block).
791
-
791
+
792
792
  Returns
793
793
  -------
794
- Samples in blocks of shape (num, :attr:`numchannels`).
794
+ Samples in blocks of shape (num, :attr:`numchannels`).
795
795
  :attr:`numchannels` is the number of sectors.
796
796
  The last block may be shorter than num.
797
+
797
798
  """
798
799
  inds = [self.grid.indices(*sector) for sector in self.sectors]
799
800
  gshape = self.grid.shape
800
- o = empty((num, self.numchannels), dtype=float) # output array
801
+ o = empty((num, self.numchannels), dtype=float) # output array
801
802
  for r in self.source.result(num):
802
803
  ns = r.shape[0]
803
804
  mapshape = (ns,) + gshape
804
805
  rmax = r.max()
805
- rmin = rmax * 10**(self.clip/10.0)
806
- r = where(r>rmin, r, 0.0)
807
- i = 0
808
- for ind in inds:
809
- h = r[:].reshape(mapshape)[ (s_[:],) + ind ]
806
+ rmin = rmax * 10 ** (self.clip / 10.0)
807
+ r = where(r > rmin, r, 0.0)
808
+ for i, ind in enumerate(inds):
809
+ h = r[:].reshape(mapshape)[(s_[:],) + ind]
810
810
  o[:ns, i] = h.reshape(h.shape[0], -1).sum(axis=1)
811
811
  i += 1
812
- yield o[:ns]
812
+ yield o[:ns]