acoular 24.7__py3-none-any.whl → 25.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
acoular/__init__.py CHANGED
@@ -4,11 +4,22 @@
4
4
 
5
5
  """The Acoular library: several classes for the implementation of acoustic beamforming."""
6
6
 
7
- import os
7
+ import os # noqa: I001
8
8
 
9
- from . import demo, tools
10
- from .calib import Calib
9
+ # config must be imported before any submodules containing numpy, see #322.
11
10
  from .configuration import config
11
+
12
+ from . import demo, tools, aiaa
13
+ from .base import (
14
+ Generator,
15
+ InOut,
16
+ SamplesGenerator,
17
+ SpectraGenerator,
18
+ SpectraOut,
19
+ TimeInOut,
20
+ TimeOut,
21
+ )
22
+ from .calib import Calib
12
23
  from .environments import (
13
24
  Environment,
14
25
  FlowField,
@@ -41,6 +52,7 @@ from .fbeamform import (
41
52
  SteeringVector,
42
53
  integrate,
43
54
  )
55
+ from .fprocess import IRFFT, RFFT, AutoPowerSpectra, CrossPowerSpectra, FFTSpectra
44
56
  from .grids import (
45
57
  CircSector,
46
58
  ConvexSector,
@@ -57,10 +69,13 @@ from .grids import (
57
69
  Sector,
58
70
  )
59
71
  from .microphones import MicGeom
72
+ from .process import Average, Cache, SampleSplitter, TimeAverage, TimeCache
60
73
  from .sdinput import SoundDeviceSamplesGenerator
61
74
  from .signals import (
62
75
  FiltWNoiseGenerator,
63
76
  GenericSignalGenerator,
77
+ NoiseGenerator,
78
+ PeriodicSignalGenerator,
64
79
  PNoiseGenerator,
65
80
  SignalGenerator,
66
81
  SineGenerator,
@@ -80,7 +95,8 @@ from .sources import (
80
95
  TimeSamples,
81
96
  UncorrelatedNoiseSource,
82
97
  )
83
- from .spectra import BaseSpectra, FFTSpectra, PowerSpectra, PowerSpectraImport, synthetic
98
+ from .tools.helpers import synthetic
99
+ from .spectra import BaseSpectra, PowerSpectra, PowerSpectraImport
84
100
  from .spectra import PowerSpectra as EigSpectra
85
101
  from .tbeamform import (
86
102
  BeamformerCleant,
@@ -102,19 +118,15 @@ from .tprocess import (
102
118
  FiltFreqWeight,
103
119
  FiltOctave,
104
120
  MaskedTimeInOut,
121
+ MaskedTimeOut,
105
122
  Mixer,
106
123
  OctaveFilterBank,
107
- SamplesGenerator,
108
- SampleSplitter,
109
124
  SpatialInterpolator,
110
125
  SpatialInterpolatorConstantRotation,
111
126
  SpatialInterpolatorRotation,
112
- TimeAverage,
113
- TimeCache,
114
127
  TimeConvolve,
115
128
  TimeCumAverage,
116
129
  TimeExpAverage,
117
- TimeInOut,
118
130
  TimePower,
119
131
  TimeReverse,
120
132
  Trigger,
@@ -0,0 +1,12 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Copyright (c) Acoular Development Team.
3
+ # ------------------------------------------------------------------------------
4
+ """Provides classes for importing AIAA Array Benchmarks.
5
+
6
+ .. autosummary::
7
+ :toctree: generated/
8
+
9
+ aiaa
10
+ """
11
+
12
+ from .aiaa import CsmAIAABenchmark, MicAIAABenchmark, TimeSamplesAIAABenchmark, TriggerAIAABenchmark
@@ -1,8 +1,8 @@
1
1
  # ------------------------------------------------------------------------------
2
2
  # Copyright (c) Acoular Development Team.
3
3
  # ------------------------------------------------------------------------------
4
- """Classes for importing AIAA Array Benchmarks
5
- from . import aiaa
4
+ """Classes for importing AIAA Array Benchmarks.
5
+
6
6
  These classes allow importing data from HDF5 files following the specifications of
7
7
  the AIAA microphone array methods benchmarking effort:
8
8
  https://www-docs.b-tu.de/fg-akustik/public/veroeffentlichungen/ArrayMethodsFileFormatsR2P4Release.pdf .
@@ -12,8 +12,8 @@ the framework.
12
12
 
13
13
  Examples
14
14
  --------
15
- >>> micgeom = MicAIAABenchmark(name='some_benchmarkdata.h5') # doctest: +SKIP
16
- >>> timedata = TimeSamplesAIAABenchmark(name='some_benchmarkdata.h5') # doctest: +SKIP
15
+ >>> micgeom = MicAIAABenchmark(file='some_benchmarkdata.h5') # doctest: +SKIP
16
+ >>> timedata = TimeSamplesAIAABenchmark(file='some_benchmarkdata.h5') # doctest: +SKIP
17
17
 
18
18
 
19
19
  .. autosummary::
@@ -23,10 +23,9 @@ Examples
23
23
  TriggerAIAABenchmark
24
24
  CsmAIAABenchmark
25
25
  MicAIAABenchmark
26
- """
26
+ """ # noqa: W505
27
27
 
28
28
  import contextlib
29
- from os import path
30
29
 
31
30
  from numpy import array
32
31
  from traits.api import (
@@ -38,11 +37,13 @@ from traits.api import (
38
37
  property_depends_on,
39
38
  )
40
39
 
40
+ from acoular.deprecation import deprecated_alias
41
41
  from acoular.h5files import H5FileBase, _get_h5file_class
42
42
  from acoular.internal import digest
43
43
  from acoular.microphones import MicGeom
44
44
  from acoular.sources import TimeSamples
45
45
  from acoular.spectra import PowerSpectraImport
46
+ from acoular.tools.utils import get_file_basename
46
47
 
47
48
 
48
49
  class TimeSamplesAIAABenchmark(TimeSamples):
@@ -54,13 +55,13 @@ class TimeSamplesAIAABenchmark(TimeSamples):
54
55
  objects.
55
56
  """
56
57
 
57
- def load_timedata(self):
58
+ def _load_timedata(self):
58
59
  """Loads timedata from .h5 file. Only for internal use."""
59
60
  self.data = self.h5f.get_data_by_reference('MicrophoneData/microphoneDataPa')
60
61
  self.sample_freq = self.h5f.get_node_attribute(self.data, 'sampleRateHz')
61
- (self.numsamples, self.numchannels) = self.data.shape
62
+ (self.num_samples, self.num_channels) = self.data.shape
62
63
 
63
- def load_metadata(self):
64
+ def _load_metadata(self):
64
65
  """Loads metadata from .h5 file. Only for internal use."""
65
66
  self.metadata = {}
66
67
  if '/MetaData' in self.h5f:
@@ -76,27 +77,28 @@ class TriggerAIAABenchmark(TimeSamplesAIAABenchmark):
76
77
  and and provides information about this data.
77
78
  """
78
79
 
79
- def load_timedata(self):
80
+ def _load_timedata(self):
80
81
  """Loads timedata from .h5 file. Only for internal use."""
81
82
  self.data = self.h5f.get_data_by_reference('TachoData/tachoDataV')
82
83
  self.sample_freq = self.h5f.get_node_attribute(self.data, 'sampleRateHz')
83
- (self.numsamples, self.numchannels) = self.data.shape
84
+ (self.num_samples, self.num_channels) = self.data.shape
84
85
 
85
86
 
87
+ @deprecated_alias({'name': 'file'})
86
88
  class CsmAIAABenchmark(PowerSpectraImport):
87
89
  """Class to load the CSM that is stored in AIAA Benchmark HDF5 file."""
88
90
 
89
91
  #: Full name of the .h5 file with data
90
- name = File(filter=['*.h5'], desc='name of data file')
92
+ file = File(filter=['*.h5'], exists=True, desc='name of data file')
91
93
 
92
94
  #: Basename of the .h5 file with data, is set automatically.
93
95
  basename = Property(
94
- depends_on='name',
96
+ depends_on=['file'],
95
97
  desc='basename of data file',
96
98
  )
97
99
 
98
100
  #: number of channels
99
- numchannels = Property()
101
+ num_channels = Property()
100
102
 
101
103
  #: HDF5 file object
102
104
  h5f = Instance(H5FileBase, transient=True)
@@ -110,19 +112,16 @@ class CsmAIAABenchmark(PowerSpectraImport):
110
112
 
111
113
  @cached_property
112
114
  def _get_basename(self):
113
- return path.splitext(path.basename(self.name))[0]
115
+ return get_file_basename(self.file)
114
116
 
115
117
  @on_trait_change('basename')
116
118
  def load_data(self):
117
119
  """Open the .h5 file and set attributes."""
118
- if not path.isfile(self.name):
119
- # no file there
120
- raise OSError('No such file: %s' % self.name)
121
120
  if self.h5f is not None:
122
121
  with contextlib.suppress(OSError):
123
122
  self.h5f.close()
124
123
  file = _get_h5file_class()
125
- self.h5f = file(self.name)
124
+ self.h5f = file(self.file)
126
125
 
127
126
  # @property_depends_on( 'block_size, ind_low, ind_high' )
128
127
  def _get_indices(self):
@@ -131,15 +130,15 @@ class CsmAIAABenchmark(PowerSpectraImport):
131
130
  except IndexError:
132
131
  return range(0)
133
132
 
134
- @property_depends_on('digest')
135
- def _get_numchannels(self):
133
+ @property_depends_on(['digest'])
134
+ def _get_num_channels(self):
136
135
  try:
137
136
  attrs = self.h5f.get_data_by_reference('MetaData/ArrayAttributes')
138
137
  return self.h5f.get_node_attribute(attrs, 'microphoneCount')
139
138
  except IndexError:
140
139
  return 0
141
140
 
142
- @property_depends_on('digest')
141
+ @property_depends_on(['digest'])
143
142
  def _get_csm(self):
144
143
  """Loads cross spectral matrix from file."""
145
144
  csmre = self.h5f.get_data_by_reference('/CsmData/csmReal')[:].transpose((2, 0, 1))
@@ -167,19 +166,15 @@ class MicAIAABenchmark(MicGeom):
167
166
  file containing the measurement data.
168
167
  """
169
168
 
170
- #: Name of the .h5-file from wich to read the data.
171
- from_file = File(filter=['*.h5'], desc='name of the h5 file containing the microphone geometry')
169
+ #: Name of the .h5-file from which to read the data.
170
+ file = File(filter=['*.h5'], exists=True, desc='name of the h5 file containing the microphone geometry')
172
171
 
173
- @on_trait_change('basename')
172
+ @on_trait_change('file')
174
173
  def import_mpos(self):
175
174
  """Import the microphone positions from .h5 file.
176
175
  Called when :attr:`basename` changes.
177
176
  """
178
- if not path.isfile(self.from_file):
179
- # no file there
180
- raise OSError('No such file: %s' % self.from_file)
181
-
182
177
  file = _get_h5file_class()
183
- h5f = file(self.from_file, mode='r')
184
- self.mpos_tot = h5f.get_data_by_reference('MetaData/ArrayAttributes/microphonePositionsM')[:].swapaxes(0, 1)
178
+ h5f = file(self.file, mode='r')
179
+ self.pos_total = h5f.get_data_by_reference('MetaData/ArrayAttributes/microphonePositionsM')[:].swapaxes(0, 1)
185
180
  h5f.close()
acoular/base.py ADDED
@@ -0,0 +1,332 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Copyright (c) Acoular Development Team.
3
+ # ------------------------------------------------------------------------------
4
+ """Implements base classes for signal processing blocks in Acoular.
5
+
6
+ The classes in this module are abstract base classes that provide a common interface for all classes
7
+ that generate an output via the generator :meth:`result` in block-wise manner. They are not intended
8
+ to be used directly, but to be subclassed by classes that implement the actual signal processing.
9
+
10
+ .. autosummary::
11
+ :toctree: generated/
12
+
13
+ Generator
14
+ SamplesGenerator
15
+ SpectraGenerator
16
+ InOut
17
+ TimeOut
18
+ SpectraOut
19
+ TimeInOut
20
+ """
21
+
22
+ from abc import abstractmethod
23
+
24
+ from traits.api import (
25
+ ABCHasStrictTraits,
26
+ CArray,
27
+ CInt,
28
+ Delegate,
29
+ Float,
30
+ Instance,
31
+ Property,
32
+ cached_property,
33
+ )
34
+
35
+ # acoular imports
36
+ from .deprecation import deprecated_alias
37
+ from .internal import digest
38
+
39
+
40
+ @deprecated_alias({'numchannels': 'num_channels', 'numsamples': 'num_samples'})
41
+ class Generator(ABCHasStrictTraits):
42
+ """Interface for any generating signal processing block.
43
+
44
+ It provides a common interface for all classes, which generate an output via the generator
45
+ :meth:`result` in block-wise manner. It has a common set of traits that are used by all classes
46
+ that implement this interface. This includes the sampling frequency of the signal
47
+ (:attr:`sample_freq`), the number of samples (:attr:`num_samples`), and the number of channels
48
+ (:attr:`num_channels`). A private trait :attr:`digest` is used to store the internal identifier
49
+ of the object, which is a hash of the object's attributes.
50
+ This is used to check if the object's internal state has changed.
51
+
52
+ """
53
+
54
+ #: Sampling frequency of the signal, defaults to 1.0
55
+ sample_freq = Float(1.0, desc='sampling frequency')
56
+
57
+ #: Number of signal samples
58
+ num_samples = CInt
59
+
60
+ #: Number of channels
61
+ num_channels = CInt
62
+
63
+ # internal identifier
64
+ digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels'])
65
+
66
+ def _get_digest(self):
67
+ return digest(self)
68
+
69
+ @abstractmethod
70
+ def result(self, num):
71
+ """Python generator that yields the output block-wise.
72
+
73
+ This method needs to be implemented by the derived classes.
74
+
75
+ Parameters
76
+ ----------
77
+ num : int
78
+ The size of the first dimension of the blocks to be yielded
79
+
80
+ Yields
81
+ ------
82
+ numpy.ndarray
83
+ Two-dimensional output data block of shape (num, ...)
84
+ """
85
+
86
+
87
+ class SamplesGenerator(Generator):
88
+ """Interface for any generating multi-channel time domain signal processing block.
89
+
90
+ It provides a common interface for all SamplesGenerator classes, which generate an output via
91
+ the generator :meth:`result` in block-wise manner. This class has no real functionality on its
92
+ own and should not be used directly.
93
+
94
+ """
95
+
96
+ # internal identifier
97
+ digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels'])
98
+
99
+ def _get_digest(self):
100
+ return digest(self)
101
+
102
+ @abstractmethod
103
+ def result(self, num):
104
+ """Python generator that yields the output block-wise.
105
+
106
+ Parameters
107
+ ----------
108
+ num : int
109
+ This parameter defines the size of the blocks to be yielded
110
+ (i.e. the number of samples per block)
111
+
112
+ Yields
113
+ ------
114
+ numpy.ndarray
115
+ The two-dimensional time-data block of shape (num, num_channels).
116
+ """
117
+
118
+
119
+ class SpectraGenerator(Generator):
120
+ """Interface for any generating multi-channel signal frequency domain processing block.
121
+
122
+ It provides a common interface for all SpectraGenerator classes, which generate an output via
123
+ the generator :meth:`result` in block-wise manner. This class has no real functionality on its
124
+ own and should not be used directly.
125
+
126
+ """
127
+
128
+ #: Number of frequencies
129
+ num_freqs = CInt
130
+
131
+ #: 1-D array of frequencies
132
+ freqs = CArray
133
+
134
+ #: The length of the block used to calculate the spectra
135
+ block_size = CInt
136
+
137
+ # internal identifier
138
+ digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels', 'num_freqs', 'block_size'])
139
+
140
+ def _get_digest(self):
141
+ return digest(self)
142
+
143
+ @abstractmethod
144
+ def result(self, num=1):
145
+ """Python generator that yields the output block-wise.
146
+
147
+ Parameters
148
+ ----------
149
+ num : integer
150
+ This parameter defines the size of the number of snapshots to be yielded.
151
+ Defaults to 1.
152
+
153
+ Yields
154
+ ------
155
+ numpy.ndarray
156
+ A two-dimensional block of shape (num, num_channels * num_freqs).
157
+ """
158
+
159
+
160
+ @deprecated_alias({'numchannels': 'num_channels', 'numsamples': 'num_samples'}, read_only=True)
161
+ class TimeOut(SamplesGenerator):
162
+ """Abstract base class for any signal processing block that receives data from any
163
+ :attr:`source` domain and returns time domain signals.
164
+
165
+ It provides a base class that can be used to create signal processing blocks that receive data
166
+ from any generating :attr:`source` and generates a time signal output via the generator
167
+ :meth:`result` in block-wise manner.
168
+ """
169
+
170
+ #: Data source; :class:`~acoular.base.Generator` or derived object.
171
+ source = Instance(Generator)
172
+
173
+ #: Sampling frequency of output signal, as given by :attr:`source`.
174
+ sample_freq = Delegate('source')
175
+
176
+ #: Number of channels in output, as given by :attr:`source`.
177
+ num_channels = Delegate('source')
178
+
179
+ #: Number of samples in output, as given by :attr:`source`.
180
+ num_samples = Delegate('source')
181
+
182
+ # internal identifier
183
+ digest = Property(depends_on=['source.digest'])
184
+
185
+ @cached_property
186
+ def _get_digest(self):
187
+ return digest(self)
188
+
189
+ @abstractmethod
190
+ def result(self, num):
191
+ """Python generator that processes the source data and yields the time-signal block-wise.
192
+
193
+ This method needs to be implemented by the derived classes.
194
+
195
+ Parameters
196
+ ----------
197
+ num : int
198
+ This parameter defines the size of the blocks to be yielded
199
+ (i.e. the number of samples per block)
200
+
201
+ Yields
202
+ ------
203
+ numpy.ndarray
204
+ Two-dimensional output data block of shape (num, num_channels)
205
+ """
206
+
207
+
208
+ @deprecated_alias({'numchannels': 'num_channels', 'numsamples': 'num_samples', 'numfreqs': 'num_freqs'}, read_only=True)
209
+ class SpectraOut(SpectraGenerator):
210
+ """Abstract base class for any signal processing block that receives data from any
211
+ :attr:`source` domain and returns frequency domain signals.
212
+
213
+ It provides a base class that can be used to create signal processing blocks that receive data
214
+ from any generating :attr:`source` domain and generates a frequency domain output via the
215
+ generator :meth:`result` in block-wise manner.
216
+ """
217
+
218
+ #: Data source; :class:`~acoular.base.Generator` or derived object.
219
+ source = Instance(Generator)
220
+
221
+ #: Sampling frequency of output signal, as given by :attr:`source`.
222
+ sample_freq = Delegate('source')
223
+
224
+ #: Number of channels in output, as given by :attr:`source`.
225
+ num_channels = Delegate('source')
226
+
227
+ #: Number of snapshots in output, as given by :attr:`source`.
228
+ num_samples = Delegate('source')
229
+
230
+ #: Number of frequencies in output, as given by :attr:`source`.
231
+ num_freqs = Delegate('source')
232
+
233
+ #: 1-D array of frequencies, as given by :attr:`source`.
234
+ freqs = Delegate('source')
235
+
236
+ #: The size of the block used to calculate the spectra
237
+ block_size = Delegate('source')
238
+
239
+ # internal identifier
240
+ digest = Property(depends_on=['source.digest'])
241
+
242
+ @cached_property
243
+ def _get_digest(self):
244
+ return digest(self)
245
+
246
+ @abstractmethod
247
+ def result(self, num=1):
248
+ """Python generator that processes the source data and yields the output block-wise.
249
+
250
+ This method needs to be implemented by the derived classes.
251
+
252
+ num : integer
253
+ This parameter defines the the number of snapshots to be yielded.
254
+ Defaults to 1.
255
+
256
+ Yields
257
+ ------
258
+ numpy.ndarray
259
+ A two-dimensional block of shape (num, num_channels * num_freqs).
260
+ """
261
+
262
+
263
+ @deprecated_alias({'numchannels': 'num_channels', 'numsamples': 'num_samples'}, read_only=True)
264
+ class InOut(SamplesGenerator, SpectraGenerator):
265
+ """Abstract base class for any signal processing block that receives data from any
266
+ :attr:`source` domain and returns signals in the same domain.
267
+
268
+ It provides a base class that can be used to create signal processing blocks that receive data
269
+ from any generating :attr:`source` and generates an output via the generator :meth:`result` in
270
+ block-wise manner.
271
+ """
272
+
273
+ #: Data source; :class:`~acoular.base.Generator` or derived object.
274
+ source = Instance(Generator)
275
+
276
+ #: Sampling frequency of output signal, as given by :attr:`source`.
277
+ sample_freq = Delegate('source')
278
+
279
+ #: Number of channels in output, as given by :attr:`source`.
280
+ num_channels = Delegate('source')
281
+
282
+ #: Number of frequencies in output, as given by :attr:`source`.
283
+ num_freqs = Delegate('source')
284
+
285
+ #: Number of samples / snapshots in output, as given by :attr:`source`.
286
+ num_samples = Delegate('source')
287
+
288
+ # internal identifier
289
+ digest = Property(depends_on=['source.digest'])
290
+
291
+ @cached_property
292
+ def _get_digest(self):
293
+ return digest(self)
294
+
295
+ @abstractmethod
296
+ def result(self, num):
297
+ """Python generator that processes the source data and yields the output block-wise.
298
+
299
+ This method needs to be implemented by the derived classes.
300
+
301
+ Parameters
302
+ ----------
303
+ num : int
304
+ The size of the first dimension of the blocks to be yielded
305
+
306
+ Yields
307
+ ------
308
+ numpy.ndarray
309
+ Two-dimensional output data block of shape (num, ...)
310
+ """
311
+
312
+
313
+ class TimeInOut(TimeOut):
314
+ """Deprecated alias for :class:`~acoular.base.TimeOut`.
315
+
316
+ .. deprecated:: 24.10
317
+ Using :class:`~acoular.base.TimeInOut` is deprecated and will be removed in Acoular 25.07.
318
+ Use :class:`~acoular.base.TimeOut` instead.
319
+ """
320
+
321
+ #: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
322
+ source = Instance(SamplesGenerator)
323
+
324
+ def __init__(self, *args, **kwargs):
325
+ super().__init__(*args, **kwargs)
326
+ import warnings
327
+
328
+ warnings.warn(
329
+ 'TimeInOut is deprecated and will be removed in Acoular 25.07. Use TimeOut instead.',
330
+ DeprecationWarning,
331
+ stacklevel=2,
332
+ )