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