acoular 23.11__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 (137) 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 +1478 -1407
  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-23.11.dist-info → acoular-24.5.dist-info}/METADATA +47 -40
  31. acoular-24.5.dist-info/RECORD +50 -0
  32. {acoular-23.11.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/BeamformerCMF.npy +0 -0
  46. acoular/tests/reference_data/BeamformerCapon.npy +0 -0
  47. acoular/tests/reference_data/BeamformerClean.npy +0 -0
  48. acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
  49. acoular/tests/reference_data/BeamformerCleant.npy +0 -0
  50. acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
  51. acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
  52. acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
  53. acoular/tests/reference_data/BeamformerDamas.npy +0 -0
  54. acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
  55. acoular/tests/reference_data/BeamformerEig.npy +0 -0
  56. acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
  57. acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
  58. acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
  59. acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
  60. acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
  61. acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
  62. acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
  63. acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
  64. acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
  65. acoular/tests/reference_data/BeamformerGIB.npy +0 -0
  66. acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
  67. acoular/tests/reference_data/BeamformerMusic.npy +0 -0
  68. acoular/tests/reference_data/BeamformerOrth.npy +0 -0
  69. acoular/tests/reference_data/BeamformerTime.npy +0 -0
  70. acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
  71. acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
  72. acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
  73. acoular/tests/reference_data/Environment.npy +0 -0
  74. acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
  75. acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
  76. acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  77. acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
  78. acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
  79. acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
  80. acoular/tests/reference_data/FiltOctave__.npy +0 -0
  81. acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  82. acoular/tests/reference_data/Filter__.npy +0 -0
  83. acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
  84. acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
  85. acoular/tests/reference_data/OpenJet.npy +0 -0
  86. acoular/tests/reference_data/PointSource.npy +0 -0
  87. acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
  88. acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
  89. acoular/tests/reference_data/RotatingFlow.npy +0 -0
  90. acoular/tests/reference_data/SlotJet.npy +0 -0
  91. acoular/tests/reference_data/TimeAverage__.npy +0 -0
  92. acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
  93. acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
  94. acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
  95. acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
  96. acoular/tests/reference_data/TimeInOut__.npy +0 -0
  97. acoular/tests/reference_data/TimePower__.npy +0 -0
  98. acoular/tests/reference_data/TimeReverse__.npy +0 -0
  99. acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
  100. acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
  101. acoular/tests/run_tests.sh +0 -18
  102. acoular/tests/run_tests_osx.sh +0 -16
  103. acoular/tests/test.npy +0 -0
  104. acoular/tests/test_beamformer_results.py +0 -204
  105. acoular/tests/test_classes.py +0 -60
  106. acoular/tests/test_digest.py +0 -125
  107. acoular/tests/test_environments.py +0 -73
  108. acoular/tests/test_example1.py +0 -124
  109. acoular/tests/test_grid.py +0 -92
  110. acoular/tests/test_integrate.py +0 -102
  111. acoular/tests/test_signals.py +0 -60
  112. acoular/tests/test_sources.py +0 -65
  113. acoular/tests/test_spectra.py +0 -38
  114. acoular/tests/test_timecache.py +0 -35
  115. acoular/tests/test_tprocess.py +0 -90
  116. acoular/tests/test_traj_beamformer_results.py +0 -164
  117. acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
  118. acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
  119. acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
  120. acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
  121. acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
  122. acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
  123. acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
  124. acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
  125. acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
  126. acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
  127. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
  128. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
  129. acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
  130. acoular/tests/unsupported/functionalBeamformer.py +0 -123
  131. acoular/tests/unsupported/precisionTest.py +0 -153
  132. acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
  133. acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
  134. acoular/tools.py +0 -418
  135. acoular-23.11.dist-info/RECORD +0 -146
  136. acoular-23.11.dist-info/licenses/LICENSE +0 -29
  137. {acoular-23.11.dist-info → acoular-24.5.dist-info}/licenses/AUTHORS.rst +0 -0
acoular/sources.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
  """Measured multichannel data managment and simulation of acoustic sources.
7
5
 
8
6
  .. autosummary::
@@ -24,56 +22,166 @@
24
22
 
25
23
  # imports from other packages
26
24
 
27
- from numpy import array, sqrt, ones, empty, newaxis, uint32, arange, dot, int64 ,real, pi, tile,\
28
- cross, zeros, ceil, repeat
29
- from numpy import min as npmin
30
- from numpy import any as npany
31
-
32
- from numpy.fft import ifft, fft
33
- from numpy.linalg import norm
34
-
35
- import numba as nb
36
-
37
- from traits.api import Float, Int, Property, Trait, Delegate, \
38
- cached_property, Tuple, CLong, File, Instance, Any, Str, \
39
- on_trait_change, observe, List, ListInt, CArray, Bool, Dict, Enum
40
25
  from os import path
41
26
  from warnings import warn
42
27
 
28
+ import numba as nb
29
+ from numpy import any as npany
30
+ from numpy import (
31
+ arange,
32
+ arctan2,
33
+ array,
34
+ ceil,
35
+ complex128,
36
+ cross,
37
+ dot,
38
+ empty,
39
+ int64,
40
+ mod,
41
+ newaxis,
42
+ ones,
43
+ pi,
44
+ real,
45
+ repeat,
46
+ sqrt,
47
+ tile,
48
+ uint32,
49
+ zeros,
50
+ )
51
+ from numpy import min as npmin
52
+ from numpy.fft import fft, ifft
53
+ from numpy.linalg import norm
54
+ from scipy.special import sph_harm, spherical_jn, spherical_yn
55
+ from traits.api import (
56
+ Any,
57
+ Bool,
58
+ CArray,
59
+ CLong,
60
+ Delegate,
61
+ Dict,
62
+ Enum,
63
+ File,
64
+ Float,
65
+ Instance,
66
+ Int,
67
+ List,
68
+ ListInt,
69
+ Property,
70
+ Str,
71
+ Trait,
72
+ Tuple,
73
+ cached_property,
74
+ observe,
75
+ on_trait_change,
76
+ )
77
+
43
78
  # acoular imports
44
79
  from .calib import Calib
45
- from .trajectory import Trajectory
80
+ from .environments import Environment
81
+ from .h5files import H5FileBase, _get_h5file_class
46
82
  from .internal import digest, ldigest
47
83
  from .microphones import MicGeom
48
- from .environments import Environment
49
- from .tprocess import SamplesGenerator, TimeConvolve
50
84
  from .signals import SignalGenerator
51
- from .h5files import H5FileBase, _get_h5file_class
52
- from .tools import get_modes
85
+ from .tprocess import SamplesGenerator, TimeConvolve
86
+ from .trajectory import Trajectory
53
87
 
54
88
 
55
- @nb.njit(cache=True, error_model="numpy") # jit with nopython
56
- def _fill_mic_signal_block(out,signal,rm,ind,blocksize,numchannels,up,prepadding):
89
+ @nb.njit(cache=True, error_model='numpy') # jit with nopython
90
+ def _fill_mic_signal_block(out, signal, rm, ind, blocksize, numchannels, up, prepadding):
57
91
  if prepadding:
58
92
  for b in range(blocksize):
59
93
  for m in range(numchannels):
60
- if ind[0,m]<0:
61
- out[b,m] = 0
94
+ if ind[0, m] < 0:
95
+ out[b, m] = 0
62
96
  else:
63
- out[b,m] = signal[int(0.5+ind[0,m])]/rm[0,m]
97
+ out[b, m] = signal[int(0.5 + ind[0, m])] / rm[0, m]
64
98
  ind += up
65
99
  else:
66
100
  for b in range(blocksize):
67
101
  for m in range(numchannels):
68
- out[b,m] = signal[int(0.5+ind[0,m])]/rm[0,m]
102
+ out[b, m] = signal[int(0.5 + ind[0, m])] / rm[0, m]
69
103
  ind += up
70
104
  return out
71
105
 
72
106
 
73
- class TimeSamples( SamplesGenerator ):
107
+ def spherical_hn1(n, z, derivativearccos=False):
108
+ """Spherical Hankel Function of the First Kind."""
109
+ return spherical_jn(n, z, derivative=False) + 1j * spherical_yn(n, z, derivative=False)
110
+
111
+
112
+ def get_radiation_angles(direction, mpos, sourceposition):
113
+ """Returns azimuthal and elevation angles between the mics and the source.
114
+
115
+ Parameters
116
+ ----------
117
+ direction : array of floats
118
+ Spherical Harmonic orientation
119
+ mpos : array of floats
120
+ x, y, z position of microphones
121
+ sourceposition : array of floats
122
+ position of the source
123
+
124
+ Returns
125
+ -------
126
+ azi, ele : array of floats
127
+ the angle between the mics and the source
128
+
129
+ """
130
+ # direction of the Spherical Harmonics
131
+ direc = array(direction, dtype=float)
132
+ direc = direc / norm(direc)
133
+ # distances
134
+ source_to_mic_vecs = mpos - array(sourceposition).reshape((3, 1))
135
+ source_to_mic_vecs[2] *= -1 # invert z-axis (acoular) #-1
136
+ # z-axis (acoular) -> y-axis (spherical)
137
+ # y-axis (acoular) -> z-axis (spherical)
138
+ # theta
139
+ ele = arctan2(sqrt(source_to_mic_vecs[0] ** 2 + source_to_mic_vecs[2] ** 2), source_to_mic_vecs[1])
140
+ ele += arctan2(sqrt(direc[0] ** 2 + direc[2] ** 2), direc[1])
141
+ ele += pi * 0.5 # convert from [-pi/2, pi/2] to [0,pi] range
142
+ # phi
143
+ azi = arctan2(source_to_mic_vecs[2], source_to_mic_vecs[0])
144
+ azi += arctan2(direc[2], direc[0])
145
+ azi = mod(azi, 2 * pi)
146
+ return azi, ele
147
+
148
+
149
+ def get_modes(lOrder, direction, mpos, sourceposition=None):
150
+ """Returns Spherical Harmonic Radiation Pattern at the Microphones.
151
+
152
+ Parameters
153
+ ----------
154
+ lOrder : int
155
+ Maximal order of spherical harmonic
156
+ direction : array of floats
157
+ Spherical Harmonic orientation
158
+ mpos : array of floats
159
+ x, y, z position of microphones
160
+ sourceposition : array of floats
161
+ position of the source
162
+
163
+ Returns
164
+ -------
165
+ modes : array of floats
166
+ the radiation values at each microphone for each mode
167
+
74
168
  """
75
- Container for time data in `*.h5` format.
76
-
169
+ sourceposition = sourceposition if sourceposition is not None else array([0, 0, 0])
170
+ azi, ele = get_radiation_angles(direction, mpos, sourceposition) # angles between source and mics
171
+ modes = zeros((azi.shape[0], (lOrder + 1) ** 2), dtype=complex128)
172
+ i = 0
173
+ for l in range(lOrder + 1):
174
+ for m in range(-l, l + 1):
175
+ modes[:, i] = sph_harm(m, l, azi, ele)
176
+ if m < 0:
177
+ modes[:, i] = modes[:, i].conj() * 1j
178
+ i += 1
179
+ return modes
180
+
181
+
182
+ class TimeSamples(SamplesGenerator):
183
+ """Container for time data in `*.h5` format.
184
+
77
185
  This class loads measured data from h5 files and
78
186
  and provides information about this data.
79
187
  It also serves as an interface where the data can be accessed
@@ -81,286 +189,267 @@ class TimeSamples( SamplesGenerator ):
81
189
  """
82
190
 
83
191
  #: Full name of the .h5 file with data.
84
- name = File(filter=['*.h5'],
85
- desc="name of data file")
192
+ name = File(filter=['*.h5'], desc='name of data file')
86
193
 
87
194
  #: Basename of the .h5 file with data, is set automatically.
88
- basename = Property( depends_on = 'name', #filter=['*.h5'],
89
- desc="basename of data file")
90
-
195
+ basename = Property(
196
+ depends_on='name', # filter=['*.h5'],
197
+ desc='basename of data file',
198
+ )
199
+
91
200
  #: Calibration data, instance of :class:`~acoular.calib.Calib` class, optional .
92
- calib = Trait( Calib,
93
- desc="Calibration data")
94
-
201
+ calib = Trait(Calib, desc='Calibration data')
202
+
95
203
  #: Number of channels, is set automatically / read from file.
96
- numchannels = CLong(0,
97
- desc="number of input channels")
204
+ numchannels = CLong(0, desc='number of input channels')
98
205
 
99
206
  #: Number of time data samples, is set automatically / read from file.
100
- numsamples = CLong(0,
101
- desc="number of samples")
207
+ numsamples = CLong(0, desc='number of samples')
102
208
 
103
209
  #: The time data as array of floats with dimension (numsamples, numchannels).
104
- data = Any( transient = True,
105
- desc="the actual time data array")
210
+ data = Any(transient=True, desc='the actual time data array')
106
211
 
107
212
  #: HDF5 file object
108
- h5f = Instance(H5FileBase, transient = True)
109
-
213
+ h5f = Instance(H5FileBase, transient=True)
214
+
110
215
  #: Provides metadata stored in HDF5 file object
111
- metadata = Dict(
112
- desc="metadata contained in .h5 file")
113
-
216
+ metadata = Dict(desc='metadata contained in .h5 file')
217
+
114
218
  # Checksum over first data entries of all channels
115
219
  _datachecksum = Property()
116
-
220
+
117
221
  # internal identifier
118
- digest = Property( depends_on = ['basename', 'calib.digest', '_datachecksum'])
222
+ digest = Property(depends_on=['basename', 'calib.digest', '_datachecksum'])
223
+
224
+ def _get__datachecksum(self):
225
+ return self.data[0, :].sum()
119
226
 
120
- def _get__datachecksum( self ):
121
- return self.data[0,:].sum()
122
-
123
227
  @cached_property
124
- def _get_digest( self ):
228
+ def _get_digest(self):
125
229
  return digest(self)
126
-
230
+
127
231
  @cached_property
128
- def _get_basename( self ):
232
+ def _get_basename(self):
129
233
  return path.splitext(path.basename(self.name))[0]
130
-
234
+
131
235
  @on_trait_change('basename')
132
- def load_data( self ):
133
- """
134
- Open the .h5 file and set attributes.
135
- """
236
+ def load_data(self):
237
+ """Open the .h5 file and set attributes."""
136
238
  if not path.isfile(self.name):
137
239
  # no file there
138
240
  self.numsamples = 0
139
241
  self.numchannels = 0
140
242
  self.sample_freq = 0
141
- raise IOError("No such file: %s" % self.name)
142
- if self.h5f != None:
243
+ raise OSError('No such file: %s' % self.name)
244
+ if self.h5f is not None:
143
245
  try:
144
246
  self.h5f.close()
145
- except IOError:
247
+ except OSError:
146
248
  pass
147
249
  file = _get_h5file_class()
148
250
  self.h5f = file(self.name)
149
251
  self.load_timedata()
150
252
  self.load_metadata()
151
253
 
152
- def load_timedata( self ):
153
- """ loads timedata from .h5 file. Only for internal use. """
154
- self.data = self.h5f.get_data_by_reference('time_data')
155
- self.sample_freq = self.h5f.get_node_attribute(self.data,'sample_freq')
254
+ def load_timedata(self):
255
+ """Loads timedata from .h5 file. Only for internal use."""
256
+ self.data = self.h5f.get_data_by_reference('time_data')
257
+ self.sample_freq = self.h5f.get_node_attribute(self.data, 'sample_freq')
156
258
  (self.numsamples, self.numchannels) = self.data.shape
157
259
 
158
- def load_metadata( self ):
159
- """ loads metadata from .h5 file. Only for internal use. """
260
+ def load_metadata(self):
261
+ """Loads metadata from .h5 file. Only for internal use."""
160
262
  self.metadata = {}
161
263
  if '/metadata' in self.h5f:
162
- for nodename, nodedata in self.h5f.get_child_nodes('/metadata'):
163
- self.metadata[nodename] = nodedata
264
+ self.metadata = self.h5f.node_to_dict('/metadata')
164
265
 
165
266
  def result(self, num=128):
166
- """
167
- Python generator that yields the output block-wise.
168
-
267
+ """Python generator that yields the output block-wise.
268
+
169
269
  Parameters
170
270
  ----------
171
271
  num : integer, defaults to 128
172
272
  This parameter defines the size of the blocks to be yielded
173
273
  (i.e. the number of samples per block) .
174
-
274
+
175
275
  Returns
176
276
  -------
177
- Samples in blocks of shape (num, numchannels).
277
+ Samples in blocks of shape (num, numchannels).
178
278
  The last block may be shorter than num.
279
+
179
280
  """
180
281
  if self.numsamples == 0:
181
- raise IOError("no samples available")
182
- self._datachecksum # trigger checksum calculation
282
+ msg = 'no samples available'
283
+ raise OSError(msg)
284
+ self._datachecksum # trigger checksum calculation # noqa: B018
183
285
  i = 0
184
286
  if self.calib:
185
287
  if self.calib.num_mics == self.numchannels:
186
288
  cal_factor = self.calib.data[newaxis]
187
289
  else:
188
- raise ValueError("calibration data not compatible: %i, %i" % \
189
- (self.calib.num_mics, self.numchannels))
290
+ raise ValueError('calibration data not compatible: %i, %i' % (self.calib.num_mics, self.numchannels))
190
291
  while i < self.numsamples:
191
- yield self.data[i:i+num]*cal_factor
292
+ yield self.data[i : i + num] * cal_factor
192
293
  i += num
193
294
  else:
194
295
  while i < self.numsamples:
195
- yield self.data[i:i+num]
296
+ yield self.data[i : i + num]
196
297
  i += num
197
298
 
198
- class MaskedTimeSamples( TimeSamples ):
199
- """
200
- Container for time data in `*.h5` format.
201
-
202
- This class loads measured data from h5 files
299
+
300
+ class MaskedTimeSamples(TimeSamples):
301
+ """Container for time data in `*.h5` format.
302
+
303
+ This class loads measured data from h5 files
203
304
  and provides information about this data.
204
305
  It supports storing information about (in)valid samples and (in)valid channels
205
306
  It also serves as an interface where the data can be accessed
206
307
  (e.g. for use in a block chain) via the :meth:`result` generator.
207
-
308
+
208
309
  """
209
-
310
+
210
311
  #: Index of the first sample to be considered valid.
211
- start = CLong(0,
212
- desc="start of valid samples")
213
-
312
+ start = CLong(0, desc='start of valid samples')
313
+
214
314
  #: Index of the last sample to be considered valid.
215
- stop = Trait(None, None, CLong,
216
- desc="stop of valid samples")
217
-
315
+ stop = Trait(None, None, CLong, desc='stop of valid samples')
316
+
218
317
  #: Channels that are to be treated as invalid.
219
- invalid_channels = ListInt(
220
- desc="list of invalid channels")
221
-
318
+ invalid_channels = ListInt(desc='list of invalid channels')
319
+
222
320
  #: Channel mask to serve as an index for all valid channels, is set automatically.
223
- channels = Property(depends_on = ['invalid_channels', 'numchannels_total'],
224
- desc="channel mask")
225
-
321
+ channels = Property(depends_on=['invalid_channels', 'numchannels_total'], desc='channel mask')
322
+
226
323
  #: Number of channels (including invalid channels), is set automatically.
227
- numchannels_total = CLong(0,
228
- desc="total number of input channels")
324
+ numchannels_total = CLong(0, desc='total number of input channels')
229
325
 
230
326
  #: Number of time data samples (including invalid samples), is set automatically.
231
- numsamples_total = CLong(0,
232
- desc="total number of samples per channel")
327
+ numsamples_total = CLong(0, desc='total number of samples per channel')
233
328
 
234
329
  #: Number of valid channels, is set automatically.
235
- numchannels = Property(depends_on = ['invalid_channels', \
236
- 'numchannels_total'], desc="number of valid input channels")
330
+ numchannels = Property(depends_on=['invalid_channels', 'numchannels_total'], desc='number of valid input channels')
237
331
 
238
332
  #: Number of valid time data samples, is set automatically.
239
- numsamples = Property(depends_on = ['start', 'stop', 'numsamples_total'],
240
- desc="number of valid samples per channel")
333
+ numsamples = Property(depends_on=['start', 'stop', 'numsamples_total'], desc='number of valid samples per channel')
241
334
 
242
335
  # internal identifier
243
- digest = Property( depends_on = ['basename', 'start', 'stop', \
244
- 'calib.digest', 'invalid_channels','_datachecksum'])
336
+ digest = Property(depends_on=['basename', 'start', 'stop', 'calib.digest', 'invalid_channels', '_datachecksum'])
245
337
 
246
338
  @cached_property
247
- def _get_digest( self ):
339
+ def _get_digest(self):
248
340
  return digest(self)
249
-
341
+
250
342
  @cached_property
251
- def _get_basename( self ):
343
+ def _get_basename(self):
252
344
  return path.splitext(path.basename(self.name))[0]
253
-
345
+
254
346
  @cached_property
255
- def _get_channels( self ):
256
- if len(self.invalid_channels)==0:
347
+ def _get_channels(self):
348
+ if len(self.invalid_channels) == 0:
257
349
  return slice(0, None, None)
258
- allr=[i for i in range(self.numchannels_total) if i not in self.invalid_channels]
350
+ allr = [i for i in range(self.numchannels_total) if i not in self.invalid_channels]
259
351
  return array(allr)
260
-
352
+
261
353
  @cached_property
262
- def _get_numchannels( self ):
263
- if len(self.invalid_channels)==0:
354
+ def _get_numchannels(self):
355
+ if len(self.invalid_channels) == 0:
264
356
  return self.numchannels_total
265
357
  return len(self.channels)
266
-
358
+
267
359
  @cached_property
268
- def _get_numsamples( self ):
360
+ def _get_numsamples(self):
269
361
  sli = slice(self.start, self.stop).indices(self.numsamples_total)
270
- return sli[1]-sli[0]
362
+ return sli[1] - sli[0]
271
363
 
272
364
  @on_trait_change('basename')
273
- def load_data( self ):
274
- #""" open the .h5 file and set attributes
275
- #"""
365
+ def load_data(self):
366
+ # """ open the .h5 file and set attributes
367
+ # """
276
368
  if not path.isfile(self.name):
277
369
  # no file there
278
370
  self.numsamples_total = 0
279
371
  self.numchannels_total = 0
280
372
  self.sample_freq = 0
281
- raise IOError("No such file: %s" % self.name)
282
- if self.h5f != None:
373
+ raise OSError('No such file: %s' % self.name)
374
+ if self.h5f is not None:
283
375
  try:
284
376
  self.h5f.close()
285
- except IOError:
377
+ except OSError:
286
378
  pass
287
379
  file = _get_h5file_class()
288
380
  self.h5f = file(self.name)
289
381
  self.load_timedata()
290
382
  self.load_metadata()
291
383
 
292
- def load_timedata( self ):
293
- """ loads timedata from .h5 file. Only for internal use. """
294
- self.data = self.h5f.get_data_by_reference('time_data')
295
- self.sample_freq = self.h5f.get_node_attribute(self.data,'sample_freq')
384
+ def load_timedata(self):
385
+ """Loads timedata from .h5 file. Only for internal use."""
386
+ self.data = self.h5f.get_data_by_reference('time_data')
387
+ self.sample_freq = self.h5f.get_node_attribute(self.data, 'sample_freq')
296
388
  (self.numsamples_total, self.numchannels_total) = self.data.shape
297
389
 
298
390
  def result(self, num=128):
299
- """
300
- Python generator that yields the output block-wise.
301
-
391
+ """Python generator that yields the output block-wise.
392
+
302
393
  Parameters
303
394
  ----------
304
395
  num : integer, defaults to 128
305
396
  This parameter defines the size of the blocks to be yielded
306
397
  (i.e. the number of samples per block).
307
-
398
+
308
399
  Returns
309
400
  -------
310
- Samples in blocks of shape (num, numchannels).
401
+ Samples in blocks of shape (num, numchannels).
311
402
  The last block may be shorter than num.
403
+
312
404
  """
313
405
  sli = slice(self.start, self.stop).indices(self.numsamples_total)
314
406
  i = sli[0]
315
407
  stop = sli[1]
316
408
  cal_factor = 1.0
317
409
  if i >= stop:
318
- raise IOError("no samples available")
319
- self._datachecksum # trigger checksum calculation
410
+ msg = 'no samples available'
411
+ raise OSError(msg)
412
+ self._datachecksum # trigger checksum calculation # noqa: B018
320
413
  if self.calib:
321
414
  if self.calib.num_mics == self.numchannels_total:
322
415
  cal_factor = self.calib.data[self.channels][newaxis]
323
416
  elif self.calib.num_mics == self.numchannels:
324
417
  cal_factor = self.calib.data[newaxis]
325
418
  elif self.calib.num_mics == 0:
326
- warn("No calibration data used.", Warning, stacklevel = 2)
419
+ warn('No calibration data used.', Warning, stacklevel=2)
327
420
  else:
328
- raise ValueError("calibration data not compatible: %i, %i" % \
329
- (self.calib.num_mics, self.numchannels))
421
+ raise ValueError('calibration data not compatible: %i, %i' % (self.calib.num_mics, self.numchannels))
330
422
  while i < stop:
331
- yield self.data[i:min(i+num, stop)][:, self.channels]*cal_factor
423
+ yield self.data[i : min(i + num, stop)][:, self.channels] * cal_factor
332
424
  i += num
333
425
 
334
426
 
335
- class PointSource( SamplesGenerator ):
336
- """
337
- Class to define a fixed point source with an arbitrary signal.
427
+ class PointSource(SamplesGenerator):
428
+ """Class to define a fixed point source with an arbitrary signal.
338
429
  This can be used in simulations.
339
-
430
+
340
431
  The output is being generated via the :meth:`result` generator.
341
432
  """
342
-
433
+
343
434
  #: Emitted signal, instance of the :class:`~acoular.signals.SignalGenerator` class.
344
435
  signal = Trait(SignalGenerator)
345
-
436
+
346
437
  #: Location of source in (`x`, `y`, `z`) coordinates (left-oriented system).
347
- loc = Tuple((0.0, 0.0, 1.0),
348
- desc="source location")
349
-
350
- #: Number of channels in output, is set automatically /
438
+ loc = Tuple((0.0, 0.0, 1.0), desc='source location')
439
+
440
+ #: Number of channels in output, is set automatically /
351
441
  #: depends on used microphone geometry.
352
442
  numchannels = Delegate('mics', 'num_mics')
353
443
 
354
444
  #: :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
355
- mics = Trait(MicGeom,
356
- desc="microphone geometry")
445
+ mics = Trait(MicGeom, desc='microphone geometry')
357
446
 
358
447
  def _validate_locations(self):
359
448
  dist = self.env._r(array(self.loc).reshape((3, 1)), self.mics.mpos)
360
449
  if npany(dist < 1e-7):
361
- warn("Source and microphone locations are identical.", Warning, stacklevel = 2)
362
-
363
- #: :class:`~acoular.environments.Environment` or derived object,
450
+ warn('Source and microphone locations are identical.', Warning, stacklevel=2)
451
+
452
+ #: :class:`~acoular.environments.Environment` or derived object,
364
453
  #: which provides information about the sound propagation in the medium.
365
454
  env = Trait(Environment(), Environment)
366
455
 
@@ -369,68 +458,73 @@ class PointSource( SamplesGenerator ):
369
458
  # Microphone locations.
370
459
  # Deprecated! Use :attr:`mics` trait instead.
371
460
  mpos = Property()
372
-
461
+
373
462
  def _get_mpos(self):
374
463
  return self.mics
375
-
464
+
376
465
  def _set_mpos(self, mpos):
377
- warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel = 2)
466
+ warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
378
467
  self.mics = mpos
379
-
468
+
380
469
  # The speed of sound.
381
- # Deprecated! Only kept for backwards compatibility.
470
+ # Deprecated! Only kept for backwards compatibility.
382
471
  # Now governed by :attr:`env` trait.
383
472
  c = Property()
384
-
473
+
385
474
  def _get_c(self):
386
475
  return self.env.c
387
-
476
+
388
477
  def _set_c(self, c):
389
- warn("Deprecated use of 'c' trait. ", Warning, stacklevel = 2)
478
+ warn("Deprecated use of 'c' trait. ", Warning, stacklevel=2)
390
479
  self.env.c = c
391
480
 
392
481
  # --- End of backwards compatibility traits --------------------------------------
393
-
482
+
394
483
  #: Start time of the signal in seconds, defaults to 0 s.
395
- start_t = Float(0.0,
396
- desc="signal start time")
397
-
398
- #: Start time of the data aquisition at microphones in seconds,
484
+ start_t = Float(0.0, desc='signal start time')
485
+
486
+ #: Start time of the data aquisition at microphones in seconds,
399
487
  #: defaults to 0 s.
400
- start = Float(0.0,
401
- desc="sample start time")
488
+ start = Float(0.0, desc='sample start time')
402
489
 
403
490
  #: Signal behaviour for negative time indices, i.e. if :attr:`start` < :attr:start_t.
404
491
  #: `loop` take values from the end of :attr:`signal.signal()` array.
405
492
  #: `zeros` set source signal to zero, advisable for deterministic signals.
406
493
  #: defaults to `loop`.
407
- prepadding = Trait('loop','zeros', desc="Behaviour for negative time indices.")
494
+ prepadding = Trait('loop', 'zeros', desc='Behaviour for negative time indices.')
408
495
 
409
496
  #: Upsampling factor, internal use, defaults to 16.
410
- up = Int(16,
411
- desc="upsampling factor")
412
-
413
- #: Number of samples, is set automatically /
497
+ up = Int(16, desc='upsampling factor')
498
+
499
+ #: Number of samples, is set automatically /
414
500
  #: depends on :attr:`signal`.
415
501
  numsamples = Delegate('signal')
416
-
417
- #: Sampling frequency of the signal, is set automatically /
502
+
503
+ #: Sampling frequency of the signal, is set automatically /
418
504
  #: depends on :attr:`signal`.
419
- sample_freq = Delegate('signal')
505
+ sample_freq = Delegate('signal')
420
506
 
421
507
  # internal identifier
422
- digest = Property(
423
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
424
- 'env.digest', 'start_t', 'start', 'up', 'prepadding', '__class__'],
425
- )
426
-
508
+ digest = Property(
509
+ depends_on=[
510
+ 'mics.digest',
511
+ 'signal.digest',
512
+ 'loc',
513
+ 'env.digest',
514
+ 'start_t',
515
+ 'start',
516
+ 'up',
517
+ 'prepadding',
518
+ '__class__',
519
+ ],
520
+ )
521
+
427
522
  @cached_property
428
- def _get_digest( self ):
523
+ def _get_digest(self):
429
524
  return digest(self)
430
525
 
431
526
  def result(self, num=128):
432
- """
433
- Python generator that yields the output at microphones block-wise.
527
+ """Python generator that yields the output at microphones block-wise.
434
528
 
435
529
  Parameters
436
530
  ----------
@@ -440,542 +534,588 @@ class PointSource( SamplesGenerator ):
440
534
 
441
535
  Returns
442
536
  -------
443
- Samples in blocks of shape (num, numchannels).
537
+ Samples in blocks of shape (num, numchannels).
444
538
  The last block may be shorter than num.
539
+
445
540
  """
446
-
447
541
  self._validate_locations()
448
- N = int(ceil(self.numsamples/num)) # number of output blocks
542
+ N = int(ceil(self.numsamples / num)) # number of output blocks
449
543
  signal = self.signal.usignal(self.up)
450
544
  out = empty((num, self.numchannels))
451
545
  # distances
452
- rm = self.env._r(array(self.loc).reshape((3, 1)), self.mics.mpos).reshape(1,-1)
546
+ rm = self.env._r(array(self.loc).reshape((3, 1)), self.mics.mpos).reshape(1, -1)
453
547
  # emission time relative to start_t (in samples) for first sample
454
- ind = (-rm/self.env.c-self.start_t+self.start)*self.sample_freq*self.up
548
+ ind = (-rm / self.env.c - self.start_t + self.start) * self.sample_freq * self.up
455
549
 
456
550
  if self.prepadding == 'zeros':
457
551
  # number of blocks where signal behaviour is amended
458
- pre = -int(npmin(ind[0])//(self.up*num))
552
+ pre = -int(npmin(ind[0]) // (self.up * num))
459
553
  # amend signal for first blocks
460
554
  # if signal stops during prepadding, terminate
461
- if N <= pre:
462
- for nb in range(N-1):
463
- out = _fill_mic_signal_block(out,signal,rm,ind,num,self.numchannels,self.up,True)
555
+ if pre >= N:
556
+ for _nb in range(N - 1):
557
+ out = _fill_mic_signal_block(out, signal, rm, ind, num, self.numchannels, self.up, True)
464
558
  yield out
465
559
 
466
- blocksize = self.numsamples%num or num
467
- out = _fill_mic_signal_block(out,signal,rm,ind,blocksize,self.numchannels,self.up,True)
560
+ blocksize = self.numsamples % num or num
561
+ out = _fill_mic_signal_block(out, signal, rm, ind, blocksize, self.numchannels, self.up, True)
468
562
  yield out[:blocksize]
469
563
  return
470
564
  else:
471
- for nb in range(pre):
472
- out = _fill_mic_signal_block(out,signal,rm,ind,num,self.numchannels,self.up,True)
565
+ for _nb in range(pre):
566
+ out = _fill_mic_signal_block(out, signal, rm, ind, num, self.numchannels, self.up, True)
473
567
  yield out
474
568
 
475
569
  else:
476
570
  pre = 0
477
571
 
478
572
  # main generator
479
- for nb in range(N-pre-1):
480
- out = _fill_mic_signal_block(out,signal,rm,ind,num,self.numchannels,self.up,False)
573
+ for _nb in range(N - pre - 1):
574
+ out = _fill_mic_signal_block(out, signal, rm, ind, num, self.numchannels, self.up, False)
481
575
  yield out
482
576
 
483
577
  # last block of variable size
484
- blocksize = self.numsamples%num or num
485
- out = _fill_mic_signal_block(out,signal,rm,ind,blocksize,self.numchannels,self.up,False)
578
+ blocksize = self.numsamples % num or num
579
+ out = _fill_mic_signal_block(out, signal, rm, ind, blocksize, self.numchannels, self.up, False)
486
580
  yield out[:blocksize]
487
581
 
488
582
 
489
- class SphericalHarmonicSource( PointSource ):
490
- """
491
- Class to define a fixed Spherical Harmonic Source with an arbitrary signal.
583
+ class SphericalHarmonicSource(PointSource):
584
+ """Class to define a fixed Spherical Harmonic Source with an arbitrary signal.
492
585
  This can be used in simulations.
493
-
586
+
494
587
  The output is being generated via the :meth:`result` generator.
495
588
  """
496
-
589
+
497
590
  #: Order of spherical harmonic source
498
- lOrder = Int(0,
499
- desc ="Order of spherical harmonic")
500
-
501
- alpha = CArray(desc="coefficients of the (lOrder,) spherical harmonic mode")
502
-
503
-
504
- #: Vector to define the orientation of the SphericalHarmonic.
505
- direction = Tuple((1.0, 0.0, 0.0),
506
- desc="Spherical Harmonic orientation")
507
-
508
- prepadding = Enum('loop', desc="Behaviour for negative time indices.")
509
-
591
+ lOrder = Int(0, desc='Order of spherical harmonic')
592
+
593
+ alpha = CArray(desc='coefficients of the (lOrder,) spherical harmonic mode')
594
+
595
+ #: Vector to define the orientation of the SphericalHarmonic.
596
+ direction = Tuple((1.0, 0.0, 0.0), desc='Spherical Harmonic orientation')
597
+
598
+ prepadding = Enum('loop', desc='Behaviour for negative time indices.')
599
+
510
600
  # internal identifier
511
- digest = Property(
512
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
513
- 'env.digest', 'start_t', 'start', 'up', '__class__', 'alpha','lOrder', 'prepadding'],
514
- )
515
-
601
+ digest = Property(
602
+ depends_on=[
603
+ 'mics.digest',
604
+ 'signal.digest',
605
+ 'loc',
606
+ 'env.digest',
607
+ 'start_t',
608
+ 'start',
609
+ 'up',
610
+ '__class__',
611
+ 'alpha',
612
+ 'lOrder',
613
+ 'prepadding',
614
+ ],
615
+ )
616
+
516
617
  @cached_property
517
- def _get_digest( self ):
618
+ def _get_digest(self):
518
619
  return digest(self)
519
620
 
520
- def transform(self,signals):
521
- Y_lm = get_modes(lOrder = self.lOrder, direction= self.direction, mpos = self.mics.mpos,sourceposition = array(self.loc))
522
- return real(ifft(fft(signals,axis=0) * (Y_lm @ self.alpha),axis=0))
621
+ def transform(self, signals):
622
+ Y_lm = get_modes(
623
+ lOrder=self.lOrder,
624
+ direction=self.direction,
625
+ mpos=self.mics.mpos,
626
+ sourceposition=array(self.loc),
627
+ )
628
+ return real(ifft(fft(signals, axis=0) * (Y_lm @ self.alpha), axis=0))
523
629
 
524
630
  def result(self, num=128):
525
- """
526
- Python generator that yields the output at microphones block-wise.
527
-
631
+ """Python generator that yields the output at microphones block-wise.
632
+
528
633
  Parameters
529
634
  ----------
530
635
  num : integer, defaults to 128
531
636
  This parameter defines the size of the blocks to be yielded
532
637
  (i.e. the number of samples per block) .
533
-
638
+
534
639
  Returns
535
640
  -------
536
- Samples in blocks of shape (num, numchannels).
641
+ Samples in blocks of shape (num, numchannels).
537
642
  The last block may be shorter than num.
643
+
538
644
  """
539
- #If signal samples are needed for te < t_start, then samples are taken
540
- #from the end of the calculated signal.
541
-
645
+ # If signal samples are needed for te < t_start, then samples are taken
646
+ # from the end of the calculated signal.
647
+
542
648
  signal = self.signal.usignal(self.up)
543
649
  # emission time relative to start_t (in samples) for first sample
544
650
  rm = self.env._r(array(self.loc).reshape((3, 1)), self.mics.mpos)
545
- ind = (-rm/self.env.c-self.start_t+self.start)*self.sample_freq + pi/30
651
+ ind = (-rm / self.env.c - self.start_t + self.start) * self.sample_freq + pi / 30
546
652
  i = 0
547
653
  n = self.numsamples
548
654
  out = empty((num, self.numchannels))
549
655
  while n:
550
656
  n -= 1
551
657
  try:
552
- out[i] = signal[array(0.5+ind*self.up, dtype=int64)]/rm
658
+ out[i] = signal[array(0.5 + ind * self.up, dtype=int64)] / rm
553
659
  ind += 1
554
660
  i += 1
555
661
  if i == num:
556
662
  yield self.transform(out)
557
663
  i = 0
558
- except IndexError: #if no more samples available from the source
664
+ except IndexError: # if no more samples available from the source
559
665
  break
560
- if i > 0: # if there are still samples to yield
666
+ if i > 0: # if there are still samples to yield
561
667
  yield self.transform(out[:i])
562
-
563
- class MovingPointSource( PointSource ):
564
- """
565
- Class to define a point source with an arbitrary
668
+
669
+
670
+ class MovingPointSource(PointSource):
671
+ """Class to define a point source with an arbitrary
566
672
  signal moving along a given trajectory.
567
673
  This can be used in simulations.
568
-
674
+
569
675
  The output is being generated via the :meth:`result` generator.
570
676
  """
571
677
 
572
678
  #: Considering of convective amplification
573
- conv_amp = Bool(False,
574
- desc="determines if convective amplification is considered")
679
+ conv_amp = Bool(False, desc='determines if convective amplification is considered')
575
680
 
576
- #: Trajectory of the source,
681
+ #: Trajectory of the source,
577
682
  #: instance of the :class:`~acoular.trajectory.Trajectory` class.
578
683
  #: The start time is assumed to be the same as for the samples.
579
- trajectory = Trait(Trajectory,
580
- desc="trajectory of the source")
684
+ trajectory = Trait(Trajectory, desc='trajectory of the source')
581
685
 
582
- prepadding = Enum('loop', desc="Behaviour for negative time indices.")
686
+ prepadding = Enum('loop', desc='Behaviour for negative time indices.')
583
687
 
584
688
  # internal identifier
585
- digest = Property(
586
- depends_on = ['mics.digest', 'signal.digest', 'loc', 'conv_amp', \
587
- 'env.digest', 'start_t', 'start', 'trajectory.digest', 'prepadding', '__class__'],
588
- )
589
-
689
+ digest = Property(
690
+ depends_on=[
691
+ 'mics.digest',
692
+ 'signal.digest',
693
+ 'loc',
694
+ 'conv_amp',
695
+ 'env.digest',
696
+ 'start_t',
697
+ 'start',
698
+ 'trajectory.digest',
699
+ 'prepadding',
700
+ '__class__',
701
+ ],
702
+ )
703
+
590
704
  @cached_property
591
- def _get_digest( self ):
705
+ def _get_digest(self):
592
706
  return digest(self)
593
707
 
594
708
  def result(self, num=128):
595
- """
596
- Python generator that yields the output at microphones block-wise.
597
-
709
+ """Python generator that yields the output at microphones block-wise.
710
+
598
711
  Parameters
599
712
  ----------
600
713
  num : integer, defaults to 128
601
714
  This parameter defines the size of the blocks to be yielded
602
715
  (i.e. the number of samples per block).
603
-
716
+
604
717
  Returns
605
718
  -------
606
- Samples in blocks of shape (num, numchannels).
719
+ Samples in blocks of shape (num, numchannels).
607
720
  The last block may be shorter than num.
608
- """
609
- #If signal samples are needed for te < t_start, then samples are taken
610
- #from the end of the calculated signal.
611
-
721
+
722
+ """
723
+ # If signal samples are needed for te < t_start, then samples are taken
724
+ # from the end of the calculated signal.
725
+
612
726
  signal = self.signal.usignal(self.up)
613
727
  out = empty((num, self.numchannels))
614
728
  # shortcuts and intial values
615
729
  m = self.mics
616
- t = self.start*ones(m.num_mics)
730
+ t = self.start * ones(m.num_mics)
617
731
  i = 0
618
- epslim = 0.1/self.up/self.sample_freq
732
+ epslim = 0.1 / self.up / self.sample_freq
619
733
  c0 = self.env.c
620
734
  tr = self.trajectory
621
735
  n = self.numsamples
622
736
  while n:
623
737
  n -= 1
624
738
  eps = ones(m.num_mics)
625
- te = t.copy() # init emission time = receiving time
739
+ te = t.copy() # init emission time = receiving time
626
740
  j = 0
627
741
  # Newton-Rhapson iteration
628
- while abs(eps).max()>epslim and j<100:
742
+ while abs(eps).max() > epslim and j < 100:
629
743
  loc = array(tr.location(te))
630
- rm = loc-m.mpos# distance vectors to microphones
631
- rm = sqrt((rm*rm).sum(0))# absolute distance
632
- loc /= sqrt((loc*loc).sum(0))# distance unit vector
744
+ rm = loc - m.mpos # distance vectors to microphones
745
+ rm = sqrt((rm * rm).sum(0)) # absolute distance
746
+ loc /= sqrt((loc * loc).sum(0)) # distance unit vector
633
747
  der = array(tr.location(te, der=1))
634
- Mr = (der*loc).sum(0)/c0# radial Mach number
635
- eps = (te + rm/c0 - t)/(1+Mr)# discrepancy in time
748
+ Mr = (der * loc).sum(0) / c0 # radial Mach number
749
+ eps = (te + rm / c0 - t) / (1 + Mr) # discrepancy in time
636
750
  te -= eps
637
- j += 1 #iteration count
638
- t += 1./self.sample_freq
751
+ j += 1 # iteration count
752
+ t += 1.0 / self.sample_freq
639
753
  # emission time relative to start time
640
- ind = (te-self.start_t+self.start)*self.sample_freq
641
- if self.conv_amp: rm *= (1-Mr)**2
754
+ ind = (te - self.start_t + self.start) * self.sample_freq
755
+ if self.conv_amp:
756
+ rm *= (1 - Mr) ** 2
642
757
  try:
643
- out[i] = signal[array(0.5+ind*self.up, dtype=int64)]/rm
758
+ out[i] = signal[array(0.5 + ind * self.up, dtype=int64)] / rm
644
759
  i += 1
645
760
  if i == num:
646
761
  yield out
647
762
  i = 0
648
- except IndexError: #if no more samples available from the source
763
+ except IndexError: # if no more samples available from the source
649
764
  break
650
- if i > 0: # if there are still samples to yield
765
+ if i > 0: # if there are still samples to yield
651
766
  yield out[:i]
652
-
653
767
 
654
- class PointSourceDipole ( PointSource ):
655
- """
656
- Class to define a fixed point source with an arbitrary signal and
768
+
769
+ class PointSourceDipole(PointSource):
770
+ """Class to define a fixed point source with an arbitrary signal and
657
771
  dipole characteristics via superposition of two nearby inversely
658
772
  phased monopoles.
659
773
  This can be used in simulations.
660
-
774
+
661
775
  The output is being generated via the :meth:`result` generator.
662
776
  """
663
-
777
+
664
778
  #: Vector to define the orientation of the dipole lobes. Its magnitude
665
779
  #: governs the distance between the monopoles
666
780
  #: (dist = [lowest wavelength in spectrum] x [magnitude] x 1e-5).
667
- #: Note: Use vectors with order of magnitude around 1.0 or less
781
+ #: Note: Use vectors with order of magnitude around 1.0 or less
668
782
  #: for good results.
669
- direction = Tuple((0.0, 0.0, 1.0),
670
- desc="dipole orientation and distance of the inversely phased monopoles")
783
+ direction = Tuple((0.0, 0.0, 1.0), desc='dipole orientation and distance of the inversely phased monopoles')
784
+
785
+ prepadding = Enum('loop', desc='Behaviour for negative time indices.')
671
786
 
672
- prepadding = Enum('loop', desc="Behaviour for negative time indices.")
673
-
674
787
  # internal identifier
675
- digest = Property(
676
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
677
- 'env.digest', 'start_t', 'start', 'up', 'direction', 'prepadding', '__class__'],
678
- )
679
-
788
+ digest = Property(
789
+ depends_on=[
790
+ 'mics.digest',
791
+ 'signal.digest',
792
+ 'loc',
793
+ 'env.digest',
794
+ 'start_t',
795
+ 'start',
796
+ 'up',
797
+ 'direction',
798
+ 'prepadding',
799
+ '__class__',
800
+ ],
801
+ )
802
+
680
803
  @cached_property
681
- def _get_digest( self ):
804
+ def _get_digest(self):
682
805
  return digest(self)
683
-
684
-
806
+
685
807
  def result(self, num=128):
686
- """
687
- Python generator that yields the output at microphones block-wise.
688
-
808
+ """Python generator that yields the output at microphones block-wise.
809
+
689
810
  Parameters
690
811
  ----------
691
812
  num : integer, defaults to 128
692
813
  This parameter defines the size of the blocks to be yielded
693
814
  (i.e. the number of samples per block) .
694
-
815
+
695
816
  Returns
696
817
  -------
697
- Samples in blocks of shape (num, numchannels).
818
+ Samples in blocks of shape (num, numchannels).
698
819
  The last block may be shorter than num.
820
+
699
821
  """
700
- #If signal samples are needed for te < t_start, then samples are taken
701
- #from the end of the calculated signal.
702
-
822
+ # If signal samples are needed for te < t_start, then samples are taken
823
+ # from the end of the calculated signal.
824
+
703
825
  mpos = self.mics.mpos
704
826
  # position of the dipole as (3,1) vector
705
- loc = array(self.loc, dtype = float).reshape((3, 1))
827
+ loc = array(self.loc, dtype=float).reshape((3, 1))
706
828
  # direction vector from tuple
707
- direc = array(self.direction, dtype = float) * 1e-5
708
- direc_mag = sqrt(dot(direc,direc))
709
-
829
+ direc = array(self.direction, dtype=float) * 1e-5
830
+ direc_mag = sqrt(dot(direc, direc))
831
+
710
832
  # normed direction vector
711
833
  direc_n = direc / direc_mag
712
-
834
+
713
835
  c = self.env.c
714
-
836
+
715
837
  # distance between monopoles as function of c, sample freq, direction vector
716
838
  dist = c / self.sample_freq * direc_mag
717
-
839
+
718
840
  # vector from dipole center to one of the monopoles
719
841
  dir2 = (direc_n * dist / 2.0).reshape((3, 1))
720
-
842
+
721
843
  signal = self.signal.usignal(self.up)
722
844
  out = empty((num, self.numchannels))
723
-
845
+
724
846
  # distance from dipole center to microphones
725
847
  rm = self.env._r(loc, mpos)
726
-
848
+
727
849
  # distances from monopoles to microphones
728
850
  rm1 = self.env._r(loc + dir2, mpos)
729
851
  rm2 = self.env._r(loc - dir2, mpos)
730
-
852
+
731
853
  # emission time relative to start_t (in samples) for first sample
732
- ind1 = (-rm1 / c - self.start_t + self.start) * self.sample_freq
854
+ ind1 = (-rm1 / c - self.start_t + self.start) * self.sample_freq
733
855
  ind2 = (-rm2 / c - self.start_t + self.start) * self.sample_freq
734
-
856
+
735
857
  i = 0
736
- n = self.numsamples
858
+ n = self.numsamples
737
859
  while n:
738
860
  n -= 1
739
861
  try:
740
862
  # subtract the second signal b/c of phase inversion
741
- out[i] = rm / dist * \
742
- (signal[array(0.5 + ind1 * self.up, dtype=int64)] / rm1 - \
743
- signal[array(0.5 + ind2 * self.up, dtype=int64)] / rm2)
744
- ind1 += 1.
745
- ind2 += 1.
746
-
863
+ out[i] = (
864
+ rm
865
+ / dist
866
+ * (
867
+ signal[array(0.5 + ind1 * self.up, dtype=int64)] / rm1
868
+ - signal[array(0.5 + ind2 * self.up, dtype=int64)] / rm2
869
+ )
870
+ )
871
+ ind1 += 1.0
872
+ ind2 += 1.0
873
+
747
874
  i += 1
748
875
  if i == num:
749
876
  yield out
750
877
  i = 0
751
878
  except IndexError:
752
879
  break
753
-
880
+
754
881
  yield out[:i]
755
882
 
883
+
756
884
  class MovingPointSourceDipole(PointSourceDipole, MovingPointSource):
757
-
758
885
  # internal identifier
759
- digest = Property(
760
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
761
- 'env.digest', 'start_t', 'start', 'up', 'direction', '__class__'],
762
- )
763
-
886
+ digest = Property(
887
+ depends_on=[
888
+ 'mics.digest',
889
+ 'signal.digest',
890
+ 'loc',
891
+ 'env.digest',
892
+ 'start_t',
893
+ 'start',
894
+ 'up',
895
+ 'direction',
896
+ '__class__',
897
+ ],
898
+ )
899
+
764
900
  #: Reference vector, perpendicular to the x and y-axis of moving source.
765
901
  #: rotation source directivity around this axis
766
- rvec = CArray( dtype=float, shape=(3, ), value=array((0, 0, 0)),
767
- desc="reference vector")
768
-
902
+ rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0)), desc='reference vector')
903
+
769
904
  @cached_property
770
- def _get_digest( self ):
771
- return digest(self)
905
+ def _get_digest(self):
906
+ return digest(self)
772
907
 
773
- def get_emission_time(self,t,direction):
908
+ def get_emission_time(self, t, direction):
774
909
  eps = ones(self.mics.num_mics)
775
- epslim = 0.1/self.up/self.sample_freq
776
- te = t.copy() # init emission time = receiving time
910
+ epslim = 0.1 / self.up / self.sample_freq
911
+ te = t.copy() # init emission time = receiving time
777
912
  j = 0
778
913
  # Newton-Rhapson iteration
779
- while abs(eps).max()>epslim and j<100:
914
+ while abs(eps).max() > epslim and j < 100:
780
915
  xs = array(self.trajectory.location(te))
781
916
  loc = xs.copy()
782
917
  loc += direction
783
- rm = loc-self.mics.mpos# distance vectors to microphones
784
- rm = sqrt((rm*rm).sum(0))# absolute distance
785
- loc /= sqrt((loc*loc).sum(0))# distance unit vector
918
+ rm = loc - self.mics.mpos # distance vectors to microphones
919
+ rm = sqrt((rm * rm).sum(0)) # absolute distance
920
+ loc /= sqrt((loc * loc).sum(0)) # distance unit vector
786
921
  der = array(self.trajectory.location(te, der=1))
787
- Mr = (der*loc).sum(0)/self.env.c# radial Mach number
788
- eps = (te + rm/self.env.c - t)/(1+Mr)# discrepancy in time
922
+ Mr = (der * loc).sum(0) / self.env.c # radial Mach number
923
+ eps = (te + rm / self.env.c - t) / (1 + Mr) # discrepancy in time
789
924
  te -= eps
790
- j += 1 #iteration count
925
+ j += 1 # iteration count
791
926
  return te, rm, Mr, xs
792
-
793
-
794
- def get_moving_direction(self,direction,time=0):
795
- """
796
- function that yields the moving coordinates along the trajectory
797
- """
798
927
 
799
- trajg1 = array(self.trajectory.location( time, der=1))[:,0][:,newaxis]
800
- rflag = (self.rvec == 0).all() #flag translation vs. rotation
928
+ def get_moving_direction(self, direction, time=0):
929
+ """Function that yields the moving coordinates along the trajectory."""
930
+ trajg1 = array(self.trajectory.location(time, der=1))[:, 0][:, newaxis]
931
+ rflag = (self.rvec == 0).all() # flag translation vs. rotation
801
932
  if rflag:
802
- return direction
803
- else:
804
- dx = array(trajg1.T) #direction vector (new x-axis)
805
- dy = cross(self.rvec, dx) # new y-axis
806
- dz = cross(dx, dy) # new z-axis
807
- RM = array((dx, dy, dz)).T # rotation matrix
808
- RM /= sqrt((RM*RM).sum(0)) # column normalized
809
- newdir = dot(RM, direction)
810
- return cross(newdir[:,0].T,self.rvec.T).T
933
+ return direction
934
+ dx = array(trajg1.T) # direction vector (new x-axis)
935
+ dy = cross(self.rvec, dx) # new y-axis
936
+ dz = cross(dx, dy) # new z-axis
937
+ RM = array((dx, dy, dz)).T # rotation matrix
938
+ RM /= sqrt((RM * RM).sum(0)) # column normalized
939
+ newdir = dot(RM, direction)
940
+ return cross(newdir[:, 0].T, self.rvec.T).T
811
941
 
812
942
  def result(self, num=128):
813
- """
814
- Python generator that yields the output at microphones block-wise.
815
-
943
+ """Python generator that yields the output at microphones block-wise.
944
+
816
945
  Parameters
817
946
  ----------
818
947
  num : integer, defaults to 128
819
948
  This parameter defines the size of the blocks to be yielded
820
949
  (i.e. the number of samples per block) .
821
-
950
+
822
951
  Returns
823
952
  -------
824
- Samples in blocks of shape (num, numchannels).
953
+ Samples in blocks of shape (num, numchannels).
825
954
  The last block may be shorter than num.
955
+
826
956
  """
827
- #If signal samples are needed for te < t_start, then samples are taken
828
- #from the end of the calculated signal.
957
+ # If signal samples are needed for te < t_start, then samples are taken
958
+ # from the end of the calculated signal.
829
959
  mpos = self.mics.mpos
830
-
960
+
831
961
  # direction vector from tuple
832
- direc = array(self.direction, dtype = float) * 1e-5
833
- direc_mag = sqrt(dot(direc,direc))
962
+ direc = array(self.direction, dtype=float) * 1e-5
963
+ direc_mag = sqrt(dot(direc, direc))
834
964
  # normed direction vector
835
965
  direc_n = direc / direc_mag
836
966
  c = self.env.c
837
967
  # distance between monopoles as function of c, sample freq, direction vector
838
968
  dist = c / self.sample_freq * direc_mag * 2
839
-
969
+
840
970
  # vector from dipole center to one of the monopoles
841
971
  dir2 = (direc_n * dist / 2.0).reshape((3, 1))
842
-
972
+
843
973
  signal = self.signal.usignal(self.up)
844
974
  out = empty((num, self.numchannels))
845
975
  # shortcuts and intial values
846
976
  m = self.mics
847
- t = self.start*ones(m.num_mics)
977
+ t = self.start * ones(m.num_mics)
848
978
 
849
979
  i = 0
850
- n = self.numsamples
980
+ n = self.numsamples
851
981
  while n:
852
982
  n -= 1
853
- te, rm, Mr, locs = self.get_emission_time(t,0)
854
- t += 1./self.sample_freq
855
- #location of the center
856
- loc = array(self.trajectory.location(te), dtype = float)[:,0][:,newaxis]
857
- #distance of the dipoles from the center
858
- diff = self.get_moving_direction(dir2,te)
859
-
983
+ te, rm, Mr, locs = self.get_emission_time(t, 0)
984
+ t += 1.0 / self.sample_freq
985
+ # location of the center
986
+ loc = array(self.trajectory.location(te), dtype=float)[:, 0][:, newaxis]
987
+ # distance of the dipoles from the center
988
+ diff = self.get_moving_direction(dir2, te)
989
+
860
990
  # distance of sources
861
- rm1 = self.env._r(loc + diff, mpos)
991
+ rm1 = self.env._r(loc + diff, mpos)
862
992
  rm2 = self.env._r(loc - diff, mpos)
863
-
864
- ind = (te-self.start_t+self.start)*self.sample_freq
865
- if self.conv_amp:
866
- rm *= (1-Mr)**2
867
- rm1 *= (1-Mr)**2 # assume that Mr is the same for both poles
868
- rm2 *= (1-Mr)**2
993
+
994
+ ind = (te - self.start_t + self.start) * self.sample_freq
995
+ if self.conv_amp:
996
+ rm *= (1 - Mr) ** 2
997
+ rm1 *= (1 - Mr) ** 2 # assume that Mr is the same for both poles
998
+ rm2 *= (1 - Mr) ** 2
869
999
  try:
870
1000
  # subtract the second signal b/c of phase inversion
871
- out[i] = rm / dist * \
872
- (signal[array(0.5 + ind * self.up, dtype=int64)] / rm1 - \
873
- signal[array(0.5 + ind * self.up, dtype=int64)] / rm2)
1001
+ out[i] = (
1002
+ rm
1003
+ / dist
1004
+ * (
1005
+ signal[array(0.5 + ind * self.up, dtype=int64)] / rm1
1006
+ - signal[array(0.5 + ind * self.up, dtype=int64)] / rm2
1007
+ )
1008
+ )
874
1009
  i += 1
875
1010
  if i == num:
876
1011
  yield out
877
1012
  i = 0
878
1013
  except IndexError:
879
1014
  break
880
- yield out[:i]
881
-
1015
+ yield out[:i]
882
1016
 
883
1017
 
884
- class LineSource( PointSource ):
885
- """
886
- Class to define a fixed Line source with an arbitrary signal.
1018
+ class LineSource(PointSource):
1019
+ """Class to define a fixed Line source with an arbitrary signal.
887
1020
  This can be used in simulations.
888
-
1021
+
889
1022
  The output is being generated via the :meth:`result` generator.
890
1023
  """
891
-
1024
+
892
1025
  #: Vector to define the orientation of the line source
893
- direction = Tuple((0.0, 0.0, 1.0),
894
- desc="Line orientation ")
895
-
1026
+ direction = Tuple((0.0, 0.0, 1.0), desc='Line orientation ')
1027
+
896
1028
  #: Vector to define the length of the line source in m
897
- length = Float(1,desc="length of the line source")
898
-
1029
+ length = Float(1, desc='length of the line source')
1030
+
899
1031
  #: number of monopol sources in the line source
900
1032
  num_sources = Int(1)
901
-
1033
+
902
1034
  #: source strength for every monopole
903
- source_strength = CArray(desc="coefficients of the source strength")
904
-
1035
+ source_strength = CArray(desc='coefficients of the source strength')
1036
+
905
1037
  #:coherence
906
- coherence = Trait( 'coherent', 'incoherent',
907
- desc="coherence mode")
908
-
1038
+ coherence = Trait('coherent', 'incoherent', desc='coherence mode')
1039
+
909
1040
  # internal identifier
910
- digest = Property(
911
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
912
- 'env.digest', 'start_t', 'start', 'up', 'direction',\
913
- 'source_strength','coherence','__class__'],
1041
+ digest = Property(
1042
+ depends_on=[
1043
+ 'mics.digest',
1044
+ 'signal.digest',
1045
+ 'loc',
1046
+ 'env.digest',
1047
+ 'start_t',
1048
+ 'start',
1049
+ 'up',
1050
+ 'direction',
1051
+ 'source_strength',
1052
+ 'coherence',
1053
+ '__class__',
1054
+ ],
1055
+ )
914
1056
 
915
- )
916
-
917
1057
  @cached_property
918
- def _get_digest( self ):
1058
+ def _get_digest(self):
919
1059
  return digest(self)
920
1060
 
921
1061
  def result(self, num=128):
922
- """
923
- Python generator that yields the output at microphones block-wise.
924
-
1062
+ """Python generator that yields the output at microphones block-wise.
1063
+
925
1064
  Parameters
926
1065
  ----------
927
1066
  num : integer, defaults to 128
928
1067
  This parameter defines the size of the blocks to be yielded
929
1068
  (i.e. the number of samples per block) .
930
-
1069
+
931
1070
  Returns
932
1071
  -------
933
- Samples in blocks of shape (num, numchannels).
1072
+ Samples in blocks of shape (num, numchannels).
934
1073
  The last block may be shorter than num.
1074
+
935
1075
  """
936
- #If signal samples are needed for te < t_start, then samples are taken
937
- #from the end of the calculated signal.
1076
+ # If signal samples are needed for te < t_start, then samples are taken
1077
+ # from the end of the calculated signal.
938
1078
 
939
1079
  mpos = self.mics.mpos
940
-
1080
+
941
1081
  # direction vector from tuple
942
- direc = array(self.direction, dtype = float)
1082
+ direc = array(self.direction, dtype=float)
943
1083
  # normed direction vector
944
- direc_n = direc/norm(direc)
1084
+ direc_n = direc / norm(direc)
945
1085
  c = self.env.c
946
-
947
- # distance between monopoles in the line
948
- dist = self.length / self.num_sources
949
-
950
- #blocwise output
1086
+
1087
+ # distance between monopoles in the line
1088
+ dist = self.length / self.num_sources
1089
+
1090
+ # blocwise output
951
1091
  out = zeros((num, self.numchannels))
952
-
953
- # distance from line start position to microphones
954
- loc = array(self.loc, dtype = float).reshape((3, 1))
955
-
1092
+
1093
+ # distance from line start position to microphones
1094
+ loc = array(self.loc, dtype=float).reshape((3, 1))
1095
+
956
1096
  # distances from monopoles in the line to microphones
957
- rms = empty(( self.numchannels,self.num_sources))
958
- inds = empty((self.numchannels,self.num_sources))
1097
+ rms = empty((self.numchannels, self.num_sources))
1098
+ inds = empty((self.numchannels, self.num_sources))
959
1099
  signals = empty((self.num_sources, len(self.signal.usignal(self.up))))
960
- #for every source - distances
1100
+ # for every source - distances
961
1101
  for s in range(self.num_sources):
962
- rms[:,s] = self.env._r((loc.T+direc_n*dist*s).T, mpos)
963
- inds[:,s] = (-rms[:,s] / c - self.start_t + self.start) * self.sample_freq
964
- #new seed for every source
1102
+ rms[:, s] = self.env._r((loc.T + direc_n * dist * s).T, mpos)
1103
+ inds[:, s] = (-rms[:, s] / c - self.start_t + self.start) * self.sample_freq
1104
+ # new seed for every source
965
1105
  if self.coherence == 'incoherent':
966
- self.signal.seed = s + abs(int(hash(self.digest)//10e12))
1106
+ self.signal.seed = s + abs(int(hash(self.digest) // 10e12))
967
1107
  self.signal.rms = self.signal.rms * self.source_strength[s]
968
1108
  signals[s] = self.signal.usignal(self.up)
969
1109
  i = 0
970
- n = self.numsamples
1110
+ n = self.numsamples
971
1111
  while n:
972
1112
  n -= 1
973
1113
  try:
974
1114
  for s in range(self.num_sources):
975
- # sum sources
976
- out[i] += (signals[s,array(0.5 + inds[:,s].T * self.up, dtype=int64)] / rms[:,s])
977
-
978
- inds += 1.
1115
+ # sum sources
1116
+ out[i] += signals[s, array(0.5 + inds[:, s].T * self.up, dtype=int64)] / rms[:, s]
1117
+
1118
+ inds += 1.0
979
1119
  i += 1
980
1120
  if i == num:
981
1121
  yield out
@@ -983,139 +1123,141 @@ class LineSource( PointSource ):
983
1123
  i = 0
984
1124
  except IndexError:
985
1125
  break
986
-
1126
+
987
1127
  yield out[:i]
988
-
989
- class MovingLineSource(LineSource,MovingPointSource):
990
-
1128
+
1129
+
1130
+ class MovingLineSource(LineSource, MovingPointSource):
991
1131
  # internal identifier
992
- digest = Property(
993
- depends_on = ['mics.digest', 'signal.digest', 'loc', \
994
- 'env.digest', 'start_t', 'start', 'up', 'direction', '__class__'],
995
- )
996
-
1132
+ digest = Property(
1133
+ depends_on=[
1134
+ 'mics.digest',
1135
+ 'signal.digest',
1136
+ 'loc',
1137
+ 'env.digest',
1138
+ 'start_t',
1139
+ 'start',
1140
+ 'up',
1141
+ 'direction',
1142
+ '__class__',
1143
+ ],
1144
+ )
997
1145
 
998
1146
  #: Reference vector, perpendicular to the x and y-axis of moving source.
999
1147
  #: rotation source directivity around this axis
1000
- rvec = CArray( dtype=float, shape=(3, ), value=array((0, 0, 0)),
1001
- desc="reference vector")
1002
-
1148
+ rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0)), desc='reference vector')
1149
+
1003
1150
  @cached_property
1004
- def _get_digest( self ):
1005
- return digest(self)
1006
-
1007
- def get_moving_direction(self,direction,time=0):
1008
- """
1009
- function that yields the moving coordinates along the trajectory
1010
- """
1011
-
1012
- trajg1 = array(self.trajectory.location( time, der=1))[:,0][:,newaxis]
1013
- rflag = (self.rvec == 0).all() #flag translation vs. rotation
1151
+ def _get_digest(self):
1152
+ return digest(self)
1153
+
1154
+ def get_moving_direction(self, direction, time=0):
1155
+ """Function that yields the moving coordinates along the trajectory."""
1156
+ trajg1 = array(self.trajectory.location(time, der=1))[:, 0][:, newaxis]
1157
+ rflag = (self.rvec == 0).all() # flag translation vs. rotation
1014
1158
  if rflag:
1015
- return direction
1016
- else:
1017
- dx = array(trajg1.T) #direction vector (new x-axis)
1018
- dy = cross(self.rvec, dx) # new y-axis
1019
- dz = cross(dx, dy) # new z-axis
1020
- RM = array((dx, dy, dz)).T # rotation matrix
1021
- RM /= sqrt((RM*RM).sum(0)) # column normalized
1022
- newdir = dot(RM, direction)
1023
- return cross(newdir[:,0].T,self.rvec.T).T
1024
-
1025
- def get_emission_time(self,t,direction):
1159
+ return direction
1160
+ dx = array(trajg1.T) # direction vector (new x-axis)
1161
+ dy = cross(self.rvec, dx) # new y-axis
1162
+ dz = cross(dx, dy) # new z-axis
1163
+ RM = array((dx, dy, dz)).T # rotation matrix
1164
+ RM /= sqrt((RM * RM).sum(0)) # column normalized
1165
+ newdir = dot(RM, direction)
1166
+ return cross(newdir[:, 0].T, self.rvec.T).T
1167
+
1168
+ def get_emission_time(self, t, direction):
1026
1169
  eps = ones(self.mics.num_mics)
1027
- epslim = 0.1/self.up/self.sample_freq
1028
- te = t.copy() # init emission time = receiving time
1170
+ epslim = 0.1 / self.up / self.sample_freq
1171
+ te = t.copy() # init emission time = receiving time
1029
1172
  j = 0
1030
1173
  # Newton-Rhapson iteration
1031
- while abs(eps).max()>epslim and j<100:
1174
+ while abs(eps).max() > epslim and j < 100:
1032
1175
  xs = array(self.trajectory.location(te))
1033
1176
  loc = xs.copy()
1034
1177
  loc += direction
1035
- rm = loc-self.mics.mpos# distance vectors to microphones
1036
- rm = sqrt((rm*rm).sum(0))# absolute distance
1037
- loc /= sqrt((loc*loc).sum(0))# distance unit vector
1178
+ rm = loc - self.mics.mpos # distance vectors to microphones
1179
+ rm = sqrt((rm * rm).sum(0)) # absolute distance
1180
+ loc /= sqrt((loc * loc).sum(0)) # distance unit vector
1038
1181
  der = array(self.trajectory.location(te, der=1))
1039
- Mr = (der*loc).sum(0)/self.env.c# radial Mach number
1040
- eps = (te + rm/self.env.c - t)/(1+Mr)# discrepancy in time
1182
+ Mr = (der * loc).sum(0) / self.env.c # radial Mach number
1183
+ eps = (te + rm / self.env.c - t) / (1 + Mr) # discrepancy in time
1041
1184
  te -= eps
1042
- j += 1 #iteration count
1185
+ j += 1 # iteration count
1043
1186
  return te, rm, Mr, xs
1044
-
1187
+
1045
1188
  def result(self, num=128):
1046
- """
1047
- Python generator that yields the output at microphones block-wise.
1048
-
1189
+ """Python generator that yields the output at microphones block-wise.
1190
+
1049
1191
  Parameters
1050
1192
  ----------
1051
1193
  num : integer, defaults to 128
1052
1194
  This parameter defines the size of the blocks to be yielded
1053
1195
  (i.e. the number of samples per block) .
1054
-
1196
+
1055
1197
  Returns
1056
1198
  -------
1057
- Samples in blocks of shape (num, numchannels).
1199
+ Samples in blocks of shape (num, numchannels).
1058
1200
  The last block may be shorter than num.
1201
+
1059
1202
  """
1060
-
1061
- #If signal samples are needed for te < t_start, then samples are taken
1062
- #from the end of the calculated signal.
1203
+ # If signal samples are needed for te < t_start, then samples are taken
1204
+ # from the end of the calculated signal.
1063
1205
  mpos = self.mics.mpos
1064
-
1206
+
1065
1207
  # direction vector from tuple
1066
- direc = array(self.direction, dtype = float)
1208
+ direc = array(self.direction, dtype=float)
1067
1209
  # normed direction vector
1068
- direc_n = direc/norm(direc)
1069
-
1070
- # distance between monopoles in the line
1071
- dist = self.length / self.num_sources
1210
+ direc_n = direc / norm(direc)
1211
+
1212
+ # distance between monopoles in the line
1213
+ dist = self.length / self.num_sources
1072
1214
  dir2 = (direc_n * dist).reshape((3, 1))
1073
-
1074
- #blocwise output
1215
+
1216
+ # blocwise output
1075
1217
  out = zeros((num, self.numchannels))
1076
-
1218
+
1077
1219
  # distances from monopoles in the line to microphones
1078
- rms = empty(( self.numchannels,self.num_sources))
1079
- inds = empty((self.numchannels,self.num_sources))
1220
+ rms = empty((self.numchannels, self.num_sources))
1221
+ inds = empty((self.numchannels, self.num_sources))
1080
1222
  signals = empty((self.num_sources, len(self.signal.usignal(self.up))))
1081
- #coherence
1223
+ # coherence
1082
1224
  for s in range(self.num_sources):
1083
- #new seed for every source
1225
+ # new seed for every source
1084
1226
  if self.coherence == 'incoherent':
1085
- self.signal.seed = s + abs(int(hash(self.digest)//10e12))
1227
+ self.signal.seed = s + abs(int(hash(self.digest) // 10e12))
1086
1228
  self.signal.rms = self.signal.rms * self.source_strength[s]
1087
1229
  signals[s] = self.signal.usignal(self.up)
1088
1230
  mpos = self.mics.mpos
1089
-
1231
+
1090
1232
  # shortcuts and intial values
1091
1233
  m = self.mics
1092
- t = self.start*ones(m.num_mics)
1234
+ t = self.start * ones(m.num_mics)
1093
1235
  i = 0
1094
- n = self.numsamples
1236
+ n = self.numsamples
1095
1237
  while n:
1096
- n -= 1
1097
- t += 1./self.sample_freq
1098
- te1, rm1, Mr1, locs1 = self.get_emission_time(t,0)
1099
- #trajg1 = array(self.trajectory.location( te1, der=1))[:,0][:,newaxis]
1100
-
1238
+ n -= 1
1239
+ t += 1.0 / self.sample_freq
1240
+ te1, rm1, Mr1, locs1 = self.get_emission_time(t, 0)
1241
+ # trajg1 = array(self.trajectory.location( te1, der=1))[:,0][:,newaxis]
1242
+
1101
1243
  # get distance and ind for every source in the line
1102
1244
  for s in range(self.num_sources):
1103
- diff = self.get_moving_direction(dir2,te1)
1104
- te, rm, Mr, locs = self.get_emission_time(t,tile((diff*s).T,(self.numchannels,1)).T)
1105
- loc = array(self.trajectory.location(te), dtype = float)[:,0][:,newaxis]
1106
- diff = self.get_moving_direction(dir2,te)
1107
- rms[:,s] = self.env._r((loc+diff*s), mpos)
1108
- inds[:,s] = (te-self.start_t+self.start)*self.sample_freq
1109
-
1110
- if self.conv_amp:
1111
- rm *= (1-Mr)**2
1112
- rms[:,s] *= (1-Mr)**2 # assume that Mr is the same
1245
+ diff = self.get_moving_direction(dir2, te1)
1246
+ te, rm, Mr, locs = self.get_emission_time(t, tile((diff * s).T, (self.numchannels, 1)).T)
1247
+ loc = array(self.trajectory.location(te), dtype=float)[:, 0][:, newaxis]
1248
+ diff = self.get_moving_direction(dir2, te)
1249
+ rms[:, s] = self.env._r((loc + diff * s), mpos)
1250
+ inds[:, s] = (te - self.start_t + self.start) * self.sample_freq
1251
+
1252
+ if self.conv_amp:
1253
+ rm *= (1 - Mr) ** 2
1254
+ rms[:, s] *= (1 - Mr) ** 2 # assume that Mr is the same
1113
1255
  try:
1114
1256
  # subtract the second signal b/c of phase inversion
1115
1257
  for s in range(self.num_sources):
1116
- # sum sources
1117
- out[i] += (signals[s,array(0.5 + inds[:,s].T * self.up, dtype=int64)] / rms[:,s])
1118
-
1258
+ # sum sources
1259
+ out[i] += signals[s, array(0.5 + inds[:, s].T * self.up, dtype=int64)] / rms[:, s]
1260
+
1119
1261
  i += 1
1120
1262
  if i == num:
1121
1263
  yield out
@@ -1126,212 +1268,201 @@ class MovingLineSource(LineSource,MovingPointSource):
1126
1268
  yield out[:i]
1127
1269
 
1128
1270
 
1129
- class UncorrelatedNoiseSource( SamplesGenerator ):
1130
- """
1131
- Class to simulate white or pink noise as uncorrelated signal at each
1271
+ class UncorrelatedNoiseSource(SamplesGenerator):
1272
+ """Class to simulate white or pink noise as uncorrelated signal at each
1132
1273
  channel.
1133
-
1274
+
1134
1275
  The output is being generated via the :meth:`result` generator.
1135
1276
  """
1136
-
1137
- #: Type of noise to generate at the channels.
1138
- #: The `~acoular.signals.SignalGenerator`-derived class has to
1277
+
1278
+ #: Type of noise to generate at the channels.
1279
+ #: The `~acoular.signals.SignalGenerator`-derived class has to
1139
1280
  # feature the parameter "seed" (i.e. white or pink noise).
1140
- signal = Trait(SignalGenerator,
1141
- desc = "type of noise")
1281
+ signal = Trait(SignalGenerator, desc='type of noise')
1142
1282
 
1143
1283
  #: Array with seeds for random number generator.
1144
- #: When left empty, arange(:attr:`numchannels`) + :attr:`signal`.seed
1284
+ #: When left empty, arange(:attr:`numchannels`) + :attr:`signal`.seed
1145
1285
  #: will be used.
1146
- seed = CArray(dtype = uint32,
1147
- desc = "random seed values")
1148
-
1149
- #: Number of channels in output; is set automatically /
1286
+ seed = CArray(dtype=uint32, desc='random seed values')
1287
+
1288
+ #: Number of channels in output; is set automatically /
1150
1289
  #: depends on used microphone geometry.
1151
1290
  numchannels = Delegate('mics', 'num_mics')
1152
1291
 
1153
1292
  #: :class:`~acoular.microphones.MicGeom` object that provides the microphone locations.
1154
- mics = Trait(MicGeom,
1155
- desc="microphone geometry")
1293
+ mics = Trait(MicGeom, desc='microphone geometry')
1156
1294
 
1157
1295
  # --- List of backwards compatibility traits and their setters/getters -----------
1158
1296
 
1159
1297
  # Microphone locations.
1160
1298
  # Deprecated! Use :attr:`mics` trait instead.
1161
1299
  mpos = Property()
1162
-
1300
+
1163
1301
  def _get_mpos(self):
1164
1302
  return self.mics
1165
-
1303
+
1166
1304
  def _set_mpos(self, mpos):
1167
- warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel = 2)
1305
+ warn("Deprecated use of 'mpos' trait. ", Warning, stacklevel=2)
1168
1306
  self.mics = mpos
1169
1307
 
1170
1308
  # --- End of backwards compatibility traits --------------------------------------
1171
-
1309
+
1172
1310
  #: Start time of the signal in seconds, defaults to 0 s.
1173
- start_t = Float(0.0,
1174
- desc="signal start time")
1175
-
1176
- #: Start time of the data aquisition at microphones in seconds,
1311
+ start_t = Float(0.0, desc='signal start time')
1312
+
1313
+ #: Start time of the data aquisition at microphones in seconds,
1177
1314
  #: defaults to 0 s.
1178
- start = Float(0.0,
1179
- desc="sample start time")
1315
+ start = Float(0.0, desc='sample start time')
1180
1316
 
1181
-
1182
- #: Number of samples is set automatically /
1317
+ #: Number of samples is set automatically /
1183
1318
  #: depends on :attr:`signal`.
1184
1319
  numsamples = Delegate('signal')
1185
-
1186
- #: Sampling frequency of the signal; is set automatically /
1320
+
1321
+ #: Sampling frequency of the signal; is set automatically /
1187
1322
  #: depends on :attr:`signal`.
1188
- sample_freq = Delegate('signal')
1189
-
1323
+ sample_freq = Delegate('signal')
1324
+
1190
1325
  # internal identifier
1191
- digest = Property(
1192
- depends_on = ['mics.digest', 'signal.rms', 'signal.numsamples', \
1193
- 'signal.sample_freq', 'signal.__class__' , 'seed', 'loc', \
1194
- 'start_t', 'start', '__class__'],
1195
- )
1326
+ digest = Property(
1327
+ depends_on=[
1328
+ 'mics.digest',
1329
+ 'signal.rms',
1330
+ 'signal.numsamples',
1331
+ 'signal.sample_freq',
1332
+ 'signal.__class__',
1333
+ 'seed',
1334
+ 'loc',
1335
+ 'start_t',
1336
+ 'start',
1337
+ '__class__',
1338
+ ],
1339
+ )
1196
1340
 
1197
1341
  @cached_property
1198
- def _get_digest( self ):
1342
+ def _get_digest(self):
1199
1343
  return digest(self)
1200
-
1201
- def result ( self, num=128 ):
1202
- """
1203
- Python generator that yields the output at microphones block-wise.
1204
-
1344
+
1345
+ def result(self, num=128):
1346
+ """Python generator that yields the output at microphones block-wise.
1347
+
1205
1348
  Parameters
1206
1349
  ----------
1207
1350
  num : integer, defaults to 128
1208
1351
  This parameter defines the size of the blocks to be yielded
1209
1352
  (i.e. the number of samples per block) .
1210
-
1353
+
1211
1354
  Returns
1212
1355
  -------
1213
- Samples in blocks of shape (num, numchannels).
1356
+ Samples in blocks of shape (num, numchannels).
1214
1357
  The last block may be shorter than num.
1215
- """
1216
1358
 
1359
+ """
1217
1360
  Noise = self.signal.__class__
1218
1361
  # create or get the array of random seeds
1219
- if not self.seed:
1362
+ if not self.seed:
1220
1363
  seed = arange(self.numchannels) + self.signal.seed
1221
1364
  elif self.seed.shape == (self.numchannels,):
1222
1365
  seed = self.seed
1223
1366
  else:
1224
- raise ValueError(\
1225
- "Seed array expected to be of shape (%i,), but has shape %s." \
1226
- % (self.numchannels, str(self.seed.shape)) )
1227
-
1228
- # create array with [numchannels] noise signal tracks
1229
- signal = array([Noise(seed = s,
1230
- numsamples = self.numsamples,
1231
- sample_freq = self.sample_freq,
1232
- rms = self.signal.rms).signal() \
1233
- for s in seed]).T
1367
+ raise ValueError(
1368
+ 'Seed array expected to be of shape (%i,), but has shape %s.'
1369
+ % (self.numchannels, str(self.seed.shape)),
1370
+ )
1234
1371
 
1235
- n = num
1372
+ # create array with [numchannels] noise signal tracks
1373
+ signal = array(
1374
+ [
1375
+ Noise(seed=s, numsamples=self.numsamples, sample_freq=self.sample_freq, rms=self.signal.rms).signal()
1376
+ for s in seed
1377
+ ],
1378
+ ).T
1379
+
1380
+ n = num
1236
1381
  while n <= self.numsamples:
1237
- yield signal[n-num:n,:]
1382
+ yield signal[n - num : n, :]
1238
1383
  n += num
1239
1384
  else:
1240
- if (n-num) < self.numsamples:
1241
- yield signal[n-num:,:]
1385
+ if (n - num) < self.numsamples:
1386
+ yield signal[n - num :, :]
1242
1387
  else:
1243
1388
  return
1244
1389
 
1245
1390
 
1246
-
1247
- class SourceMixer( SamplesGenerator ):
1248
- """
1249
- Mixes the signals from several sources.
1250
- """
1391
+ class SourceMixer(SamplesGenerator):
1392
+ """Mixes the signals from several sources."""
1251
1393
 
1252
1394
  #: List of :class:`~acoular.tprocess.SamplesGenerator` objects
1253
1395
  #: to be mixed.
1254
- sources = List( Instance(SamplesGenerator, ()) )
1396
+ sources = List(Instance(SamplesGenerator, ()))
1255
1397
 
1256
1398
  #: Sampling frequency of the signal.
1257
- sample_freq = Property( depends_on=['sdigest'] )
1258
-
1399
+ sample_freq = Property(depends_on=['sdigest'])
1400
+
1259
1401
  #: Number of channels.
1260
- numchannels = Property( depends_on=['sdigest'] )
1261
-
1402
+ numchannels = Property(depends_on=['sdigest'])
1403
+
1262
1404
  #: Number of samples.
1263
- numsamples = Property( depends_on=['sdigest'] )
1264
-
1265
- #: Amplitude weight(s) for the sources as array. If not set,
1405
+ numsamples = Property(depends_on=['sdigest'])
1406
+
1407
+ #: Amplitude weight(s) for the sources as array. If not set,
1266
1408
  #: all source signals are equally weighted.
1267
1409
  #: Must match the number of sources in :attr:`sources`.
1268
- weights = CArray(desc="channel weights")
1410
+ weights = CArray(desc='channel weights')
1269
1411
 
1270
- # internal identifier
1412
+ # internal identifier
1271
1413
  sdigest = Str()
1272
1414
 
1273
1415
  @observe('sources.items.digest')
1274
- def _set_sources_digest( self, event ):
1275
- self.sdigest = ldigest(self.sources)
1416
+ def _set_sources_digest(self, event): # noqa ARG002
1417
+ self.sdigest = ldigest(self.sources)
1276
1418
 
1277
1419
  # internal identifier
1278
- digest = Property( depends_on = ['sdigest', 'weights'])
1420
+ digest = Property(depends_on=['sdigest', 'weights'])
1279
1421
 
1280
1422
  @cached_property
1281
- def _get_digest( self ):
1423
+ def _get_digest(self):
1282
1424
  return digest(self)
1283
1425
 
1284
1426
  @cached_property
1285
- def _get_sample_freq( self ):
1286
- if self.sources:
1287
- sample_freq = self.sources[0].sample_freq
1288
- else:
1289
- sample_freq = 0
1290
- return sample_freq
1427
+ def _get_sample_freq(self):
1428
+ return self.sources[0].sample_freq if self.sources else 0
1291
1429
 
1292
1430
  @cached_property
1293
- def _get_numchannels( self ):
1294
- if self.sources:
1295
- numchannels = self.sources[0].numchannels
1296
- else:
1297
- numchannels = 0
1298
- return numchannels
1431
+ def _get_numchannels(self):
1432
+ return self.sources[0].numchannels if self.sources else 0
1299
1433
 
1300
1434
  @cached_property
1301
- def _get_numsamples( self ):
1302
- if self.sources:
1303
- numsamples = self.sources[0].numsamples
1304
- else:
1305
- numsamples = 0
1306
- return numsamples
1435
+ def _get_numsamples(self):
1436
+ return self.sources[0].numsamples if self.sources else 0
1307
1437
 
1308
- def validate_sources( self ):
1309
- """ Validates if sources fit together. """
1438
+ def validate_sources(self):
1439
+ """Validates if sources fit together."""
1310
1440
  if len(self.sources) < 1:
1311
- raise ValueError("Number of sources in SourceMixer should be at least 1.")
1441
+ msg = 'Number of sources in SourceMixer should be at least 1.'
1442
+ raise ValueError(msg)
1312
1443
  for s in self.sources[1:]:
1313
1444
  if self.sample_freq != s.sample_freq:
1314
- raise ValueError("Sample frequency of %s does not fit" % s)
1445
+ raise ValueError('Sample frequency of %s does not fit' % s)
1315
1446
  if self.numchannels != s.numchannels:
1316
- raise ValueError("Channel count of %s does not fit" % s)
1447
+ raise ValueError('Channel count of %s does not fit' % s)
1317
1448
  if self.numsamples != s.numsamples:
1318
- raise ValueError("Number of samples of %s does not fit" % s)
1449
+ raise ValueError('Number of samples of %s does not fit' % s)
1319
1450
 
1320
1451
  def result(self, num):
1321
- """
1322
- Python generator that yields the output block-wise.
1452
+ """Python generator that yields the output block-wise.
1323
1453
  The outputs from the sources in the list are being added.
1324
-
1454
+
1325
1455
  Parameters
1326
1456
  ----------
1327
1457
  num : integer
1328
1458
  This parameter defines the size of the blocks to be yielded
1329
1459
  (i.e. the number of samples per block).
1330
-
1460
+
1331
1461
  Returns
1332
1462
  -------
1333
- Samples in blocks of shape (num, numchannels).
1463
+ Samples in blocks of shape (num, numchannels).
1334
1464
  The last block may be shorter than num.
1465
+
1335
1466
  """
1336
1467
  # check whether all sources fit together
1337
1468
  self.validate_sources()
@@ -1339,63 +1470,58 @@ class SourceMixer( SamplesGenerator ):
1339
1470
  gens = [i.result(num) for i in self.sources[1:]]
1340
1471
  weights = self.weights.copy()
1341
1472
  if weights.size == 0:
1342
- weights = array([1. for j in range(len( self.sources))])
1473
+ weights = array([1.0 for j in range(len(self.sources))])
1343
1474
  assert weights.shape[0] == len(self.sources)
1344
1475
  for temp in self.sources[0].result(num):
1345
1476
  temp *= weights[0]
1346
1477
  sh = temp.shape[0]
1347
- for j,g in enumerate(gens):
1348
- temp1 = next(g)*weights[j+1]
1478
+ for j, g in enumerate(gens):
1479
+ temp1 = next(g) * weights[j + 1]
1349
1480
  if temp.shape[0] > temp1.shape[0]:
1350
- temp = temp[:temp1.shape[0]]
1351
- temp += temp1[:temp.shape[0]]
1481
+ temp = temp[: temp1.shape[0]]
1482
+ temp += temp1[: temp.shape[0]]
1352
1483
  yield temp
1353
1484
  if sh > temp.shape[0]:
1354
1485
  break
1355
1486
 
1356
1487
 
1357
- class PointSourceConvolve( PointSource ):
1358
- """
1359
- Class to blockwise convolve an arbitrary source signal with a spatial room impulse response
1360
- """
1488
+ class PointSourceConvolve(PointSource):
1489
+ """Class to blockwise convolve an arbitrary source signal with a spatial room impulse response."""
1361
1490
 
1362
1491
  #: Convolution kernel in the time domain.
1363
1492
  #: The second dimension of the kernel array has to be either 1 or match :attr:`~SamplesGenerator.numchannels`.
1364
1493
  #: If only a single kernel is supplied, it is applied to all channels.
1365
- kernel = CArray(dtype=float, desc="Convolution kernel.")
1494
+ kernel = CArray(dtype=float, desc='Convolution kernel.')
1366
1495
 
1367
1496
  # ------------- overwrite traits that are not supported by this class -------------
1368
-
1497
+
1369
1498
  #: Start time of the signal in seconds, defaults to 0 s.
1370
- start_t = Enum(0.0,
1371
- desc="signal start time")
1372
-
1373
- #: Start time of the data aquisition at microphones in seconds,
1499
+ start_t = Enum(0.0, desc='signal start time')
1500
+
1501
+ #: Start time of the data aquisition at microphones in seconds,
1374
1502
  #: defaults to 0 s.
1375
- start = Enum(0.0,
1376
- desc="sample start time")
1503
+ start = Enum(0.0, desc='sample start time')
1377
1504
 
1378
1505
  #: Signal behaviour for negative time indices, i.e. if :attr:`start` < :attr:start_t.
1379
1506
  #: `loop` take values from the end of :attr:`signal.signal()` array.
1380
1507
  #: `zeros` set source signal to zero, advisable for deterministic signals.
1381
1508
  #: defaults to `loop`.
1382
- prepadding = Enum(None, desc="Behaviour for negative time indices.")
1509
+ prepadding = Enum(None, desc='Behaviour for negative time indices.')
1383
1510
 
1384
1511
  #: Upsampling factor, internal use, defaults to 16.
1385
- up = Enum(None, desc="upsampling factor")
1386
-
1512
+ up = Enum(None, desc='upsampling factor')
1513
+
1387
1514
  # internal identifier
1388
- digest = Property(
1389
- depends_on = ['mics.digest', 'signal.digest', 'loc', 'kernel', '__class__'],
1390
- )
1391
-
1515
+ digest = Property(
1516
+ depends_on=['mics.digest', 'signal.digest', 'loc', 'kernel', '__class__'],
1517
+ )
1518
+
1392
1519
  @cached_property
1393
- def _get_digest( self ):
1520
+ def _get_digest(self):
1394
1521
  return digest(self)
1395
1522
 
1396
1523
  def result(self, num=128):
1397
- """
1398
- Python generator that yields the output at microphones block-wise.
1524
+ """Python generator that yields the output at microphones block-wise.
1399
1525
 
1400
1526
  Parameters
1401
1527
  ----------
@@ -1405,11 +1531,11 @@ class PointSourceConvolve( PointSource ):
1405
1531
 
1406
1532
  Returns
1407
1533
  -------
1408
- Samples in blocks of shape (num, numchannels).
1534
+ Samples in blocks of shape (num, numchannels).
1409
1535
  The last block may be shorter than num.
1536
+
1410
1537
  """
1411
- data = repeat(
1412
- self.signal.signal()[:,newaxis],self.mics.num_mics,axis=1)
1538
+ data = repeat(self.signal.signal()[:, newaxis], self.mics.num_mics, axis=1)
1413
1539
  source = TimeSamples(
1414
1540
  data=data,
1415
1541
  sample_freq=self.sample_freq,
@@ -1417,8 +1543,7 @@ class PointSourceConvolve( PointSource ):
1417
1543
  numchannels=self.mics.num_mics,
1418
1544
  )
1419
1545
  time_convolve = TimeConvolve(
1420
- source = source,
1421
- kernel = self.kernel,
1546
+ source=source,
1547
+ kernel=self.kernel,
1422
1548
  )
1423
- for block in time_convolve.result(num):
1424
- yield block
1549
+ yield from time_convolve.result(num)