acoular 24.5__py3-none-any.whl → 24.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acoular/__init__.py +17 -11
- acoular/base.py +312 -0
- acoular/configuration.py +23 -16
- acoular/demo/acoular_demo.py +28 -35
- acoular/environments.py +20 -15
- acoular/fastFuncs.py +40 -40
- acoular/fbeamform.py +1100 -1130
- acoular/fprocess.py +368 -0
- acoular/grids.py +36 -22
- acoular/h5cache.py +34 -34
- acoular/h5files.py +13 -13
- acoular/internal.py +3 -3
- acoular/process.py +464 -0
- acoular/sdinput.py +24 -4
- acoular/signals.py +20 -6
- acoular/sources.py +140 -56
- acoular/spectra.py +34 -53
- acoular/tbeamform.py +264 -142
- acoular/tfastfuncs.py +17 -18
- acoular/tools/__init__.py +2 -0
- acoular/tools/aiaa.py +7 -8
- acoular/tools/helpers.py +2 -2
- acoular/tools/metrics.py +1 -1
- acoular/tools/utils.py +210 -0
- acoular/tprocess.py +168 -532
- acoular/traitsviews.py +5 -3
- acoular/version.py +2 -2
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/METADATA +49 -8
- acoular-24.10.dist-info/RECORD +54 -0
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/WHEEL +1 -1
- acoular-24.5.dist-info/RECORD +0 -50
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.5.dist-info → acoular-24.10.dist-info}/licenses/LICENSE +0 -0
acoular/__init__.py
CHANGED
|
@@ -4,15 +4,21 @@
|
|
|
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
|
+
# config must be imported before any submodules containing numpy, see #322.
|
|
9
10
|
from .configuration import config
|
|
10
|
-
from .version import __author__, __date__, __version__
|
|
11
|
-
|
|
12
|
-
if config.have_sounddevice:
|
|
13
|
-
from .sdinput import SoundDeviceSamplesGenerator
|
|
14
11
|
|
|
15
12
|
from . import demo, tools
|
|
13
|
+
from .base import (
|
|
14
|
+
Generator,
|
|
15
|
+
InOut,
|
|
16
|
+
SamplesGenerator,
|
|
17
|
+
SpectraGenerator,
|
|
18
|
+
SpectraOut,
|
|
19
|
+
TimeInOut,
|
|
20
|
+
TimeOut,
|
|
21
|
+
)
|
|
16
22
|
from .calib import Calib
|
|
17
23
|
from .environments import (
|
|
18
24
|
Environment,
|
|
@@ -46,6 +52,7 @@ from .fbeamform import (
|
|
|
46
52
|
SteeringVector,
|
|
47
53
|
integrate,
|
|
48
54
|
)
|
|
55
|
+
from .fprocess import IRFFT, RFFT, AutoPowerSpectra, CrossPowerSpectra, FFTSpectra
|
|
49
56
|
from .grids import (
|
|
50
57
|
CircSector,
|
|
51
58
|
ConvexSector,
|
|
@@ -62,6 +69,8 @@ from .grids import (
|
|
|
62
69
|
Sector,
|
|
63
70
|
)
|
|
64
71
|
from .microphones import MicGeom
|
|
72
|
+
from .process import Average, Cache, SampleSplitter, TimeAverage, TimeCache
|
|
73
|
+
from .sdinput import SoundDeviceSamplesGenerator
|
|
65
74
|
from .signals import (
|
|
66
75
|
FiltWNoiseGenerator,
|
|
67
76
|
GenericSignalGenerator,
|
|
@@ -84,7 +93,7 @@ from .sources import (
|
|
|
84
93
|
TimeSamples,
|
|
85
94
|
UncorrelatedNoiseSource,
|
|
86
95
|
)
|
|
87
|
-
from .spectra import BaseSpectra,
|
|
96
|
+
from .spectra import BaseSpectra, PowerSpectra, PowerSpectraImport, synthetic
|
|
88
97
|
from .spectra import PowerSpectra as EigSpectra
|
|
89
98
|
from .tbeamform import (
|
|
90
99
|
BeamformerCleant,
|
|
@@ -106,19 +115,15 @@ from .tprocess import (
|
|
|
106
115
|
FiltFreqWeight,
|
|
107
116
|
FiltOctave,
|
|
108
117
|
MaskedTimeInOut,
|
|
118
|
+
MaskedTimeOut,
|
|
109
119
|
Mixer,
|
|
110
120
|
OctaveFilterBank,
|
|
111
|
-
SamplesGenerator,
|
|
112
|
-
SampleSplitter,
|
|
113
121
|
SpatialInterpolator,
|
|
114
122
|
SpatialInterpolatorConstantRotation,
|
|
115
123
|
SpatialInterpolatorRotation,
|
|
116
|
-
TimeAverage,
|
|
117
|
-
TimeCache,
|
|
118
124
|
TimeConvolve,
|
|
119
125
|
TimeCumAverage,
|
|
120
126
|
TimeExpAverage,
|
|
121
|
-
TimeInOut,
|
|
122
127
|
TimePower,
|
|
123
128
|
TimeReverse,
|
|
124
129
|
Trigger,
|
|
@@ -126,3 +131,4 @@ from .tprocess import (
|
|
|
126
131
|
WriteWAV,
|
|
127
132
|
)
|
|
128
133
|
from .trajectory import Trajectory
|
|
134
|
+
from .version import __author__, __date__, __version__
|
acoular/base.py
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
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 that generate an
|
|
7
|
+
output via the generator :meth:`result` in block-wise manner. They are not intended to be used directly, but to be
|
|
8
|
+
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 traits.api import (
|
|
23
|
+
CArray,
|
|
24
|
+
CLong,
|
|
25
|
+
Delegate,
|
|
26
|
+
Float,
|
|
27
|
+
HasPrivateTraits,
|
|
28
|
+
Instance,
|
|
29
|
+
Property,
|
|
30
|
+
cached_property,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from acoular.internal import digest
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Generator(HasPrivateTraits):
|
|
37
|
+
"""Interface for any generating signal processing block.
|
|
38
|
+
|
|
39
|
+
It provides a common interface for all classes, which generate an output via the generator :meth:`result`
|
|
40
|
+
in block-wise manner. It has a common set of traits that are used by all classes that implement this interface.
|
|
41
|
+
This includes the sampling frequency of the signal (:attr:`sample_freq`) and the number of samples (:attr:`numsamples`).
|
|
42
|
+
A private trait :attr:`digest` is used to store the internal identifier of the object, which is a hash of the object's
|
|
43
|
+
attributes. This is used to check if the object's internal state has changed.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
#: Sampling frequency of the signal, defaults to 1.0
|
|
47
|
+
sample_freq = Float(1.0, desc='sampling frequency')
|
|
48
|
+
|
|
49
|
+
#: Number of signal samples
|
|
50
|
+
numsamples = CLong
|
|
51
|
+
|
|
52
|
+
# internal identifier
|
|
53
|
+
digest = Property(depends_on=['sample_freq', 'numsamples'])
|
|
54
|
+
|
|
55
|
+
def _get_digest(self):
|
|
56
|
+
return digest(self)
|
|
57
|
+
|
|
58
|
+
def result(self, num):
|
|
59
|
+
"""Python generator that yields the output block-wise.
|
|
60
|
+
|
|
61
|
+
This method needs to be implemented by the derived classes.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
num : int
|
|
66
|
+
The size of the first dimension of the blocks to be yielded
|
|
67
|
+
|
|
68
|
+
Yields
|
|
69
|
+
------
|
|
70
|
+
numpy.ndarray
|
|
71
|
+
Two-dimensional output data block of shape (num, ...)
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SamplesGenerator(Generator):
|
|
76
|
+
"""Interface for any generating multi-channel time domain signal processing block.
|
|
77
|
+
|
|
78
|
+
It provides a common interface for all SamplesGenerator classes, which generate an output via the generator :meth:`result`
|
|
79
|
+
in block-wise manner. This class has no real functionality on its own and should not be used directly.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
#: Number of channels
|
|
83
|
+
numchannels = CLong
|
|
84
|
+
|
|
85
|
+
# internal identifier
|
|
86
|
+
digest = Property(depends_on=['sample_freq', 'numchannels', 'numsamples'])
|
|
87
|
+
|
|
88
|
+
def _get_digest(self):
|
|
89
|
+
return digest(self)
|
|
90
|
+
|
|
91
|
+
def result(self, num):
|
|
92
|
+
"""Python generator that yields the output block-wise.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
num : int
|
|
97
|
+
This parameter defines the size of the blocks to be yielded
|
|
98
|
+
(i.e. the number of samples per block)
|
|
99
|
+
|
|
100
|
+
Yields
|
|
101
|
+
------
|
|
102
|
+
numpy.ndarray
|
|
103
|
+
The two-dimensional time-data block of shape (num, numchannels).
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SpectraGenerator(Generator):
|
|
108
|
+
"""Interface for any generating multi-channel signal frequency domain processing block.
|
|
109
|
+
|
|
110
|
+
It provides a common interface for all SpectraGenerator classes, which generate an output via the generator :meth:`result`
|
|
111
|
+
in block-wise manner. This class has no real functionality on its own and should not be used directly.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
#: Number of channels
|
|
115
|
+
numchannels = CLong
|
|
116
|
+
|
|
117
|
+
#: Number of frequencies
|
|
118
|
+
numfreqs = CLong
|
|
119
|
+
|
|
120
|
+
#: 1-D array of frequencies
|
|
121
|
+
freqs = CArray
|
|
122
|
+
|
|
123
|
+
#: The length of the block used to calculate the spectra
|
|
124
|
+
block_size = CLong
|
|
125
|
+
|
|
126
|
+
# internal identifier
|
|
127
|
+
digest = Property(depends_on=['sample_freq', 'numchannels', 'numsamples', 'numfreqs', 'block_size'])
|
|
128
|
+
|
|
129
|
+
def _get_digest(self):
|
|
130
|
+
return digest(self)
|
|
131
|
+
|
|
132
|
+
def result(self, num=1):
|
|
133
|
+
"""Python generator that yields the output block-wise.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
num : integer
|
|
138
|
+
This parameter defines the size of the number of snapshots to be yielded.
|
|
139
|
+
Defaults to 1.
|
|
140
|
+
|
|
141
|
+
Yields
|
|
142
|
+
------
|
|
143
|
+
numpy.ndarray
|
|
144
|
+
A two-dimensional block of shape (num, numchannels*numfreqs).
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class TimeOut(SamplesGenerator):
|
|
149
|
+
"""Abstract base class for any signal processing block that receives data from any :attr:`source` domain and returns
|
|
150
|
+
time domain signals.
|
|
151
|
+
|
|
152
|
+
It provides a base class that can be used to create signal processing blocks that receive data from any
|
|
153
|
+
generating :attr:`source` and generates a time signal output via the generator :meth:`result` in block-wise manner.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
#: Data source; :class:`~acoular.base.Generator` or derived object.
|
|
157
|
+
source = Instance(Generator)
|
|
158
|
+
|
|
159
|
+
#: Sampling frequency of output signal, as given by :attr:`source`.
|
|
160
|
+
sample_freq = Delegate('source')
|
|
161
|
+
|
|
162
|
+
#: Number of channels in output, as given by :attr:`source`.
|
|
163
|
+
numchannels = Delegate('source')
|
|
164
|
+
|
|
165
|
+
#: Number of samples in output, as given by :attr:`source`.
|
|
166
|
+
numsamples = Delegate('source')
|
|
167
|
+
|
|
168
|
+
# internal identifier
|
|
169
|
+
digest = Property(depends_on=['source.digest'])
|
|
170
|
+
|
|
171
|
+
@cached_property
|
|
172
|
+
def _get_digest(self):
|
|
173
|
+
return digest(self)
|
|
174
|
+
|
|
175
|
+
def result(self, num):
|
|
176
|
+
"""Python generator that processes the source data and yields the time-signal block-wise.
|
|
177
|
+
|
|
178
|
+
This method needs to be implemented by the derived classes.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
num : int
|
|
183
|
+
This parameter defines the size of the blocks to be yielded
|
|
184
|
+
(i.e. the number of samples per block)
|
|
185
|
+
|
|
186
|
+
Yields
|
|
187
|
+
------
|
|
188
|
+
numpy.ndarray
|
|
189
|
+
Two-dimensional output data block of shape (num, numchannels)
|
|
190
|
+
"""
|
|
191
|
+
yield from self.source.result(num)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class SpectraOut(SpectraGenerator):
|
|
195
|
+
"""Abstract base class for any signal processing block that receives data from any :attr:`source` domain and
|
|
196
|
+
returns frequency domain signals.
|
|
197
|
+
|
|
198
|
+
It provides a base class that can be used to create signal processing blocks that receive data from any
|
|
199
|
+
generating :attr:`source` domain and generates a frequency domain output via the generator :meth:`result`
|
|
200
|
+
in block-wise manner.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
#: Data source; :class:`~acoular.base.Generator` or derived object.
|
|
204
|
+
source = Instance(Generator)
|
|
205
|
+
|
|
206
|
+
#: Sampling frequency of output signal, as given by :attr:`source`.
|
|
207
|
+
sample_freq = Delegate('source')
|
|
208
|
+
|
|
209
|
+
#: Number of channels in output, as given by :attr:`source`.
|
|
210
|
+
numchannels = Delegate('source')
|
|
211
|
+
|
|
212
|
+
#: Number of snapshots in output, as given by :attr:`source`.
|
|
213
|
+
numsamples = Delegate('source')
|
|
214
|
+
|
|
215
|
+
#: Number of frequencies in output, as given by :attr:`source`.
|
|
216
|
+
numfreqs = Delegate('source')
|
|
217
|
+
|
|
218
|
+
#: 1-D array of frequencies, as given by :attr:`source`.
|
|
219
|
+
freqs = Delegate('source')
|
|
220
|
+
|
|
221
|
+
#: The size of the block used to calculate the spectra
|
|
222
|
+
block_size = Delegate('source')
|
|
223
|
+
|
|
224
|
+
# internal identifier
|
|
225
|
+
digest = Property(depends_on=['source.digest'])
|
|
226
|
+
|
|
227
|
+
@cached_property
|
|
228
|
+
def _get_digest(self):
|
|
229
|
+
return digest(self)
|
|
230
|
+
|
|
231
|
+
def result(self, num=1):
|
|
232
|
+
"""Python generator that processes the source data and yields the output block-wise.
|
|
233
|
+
|
|
234
|
+
This method needs to be implemented by the derived classes.
|
|
235
|
+
|
|
236
|
+
num : integer
|
|
237
|
+
This parameter defines the the number of snapshots to be yielded.
|
|
238
|
+
Defaults to 1.
|
|
239
|
+
|
|
240
|
+
Yields
|
|
241
|
+
------
|
|
242
|
+
numpy.ndarray
|
|
243
|
+
A two-dimensional block of shape (num, numchannels*numfreqs).
|
|
244
|
+
"""
|
|
245
|
+
yield from self.source.result(num)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class InOut(SamplesGenerator, SpectraGenerator):
|
|
249
|
+
"""Abstract base class for any signal processing block that receives data from any :attr:`source` domain and returns
|
|
250
|
+
signals in the same domain.
|
|
251
|
+
|
|
252
|
+
It provides a base class that can be used to create signal processing blocks that receive data from any
|
|
253
|
+
generating :attr:`source` and generates an output via the generator :meth:`result` in block-wise manner.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
#: Data source; :class:`~acoular.base.Generator` or derived object.
|
|
257
|
+
source = Instance(Generator)
|
|
258
|
+
|
|
259
|
+
#: Sampling frequency of output signal, as given by :attr:`source`.
|
|
260
|
+
sample_freq = Delegate('source')
|
|
261
|
+
|
|
262
|
+
#: Number of channels in output, as given by :attr:`source`.
|
|
263
|
+
numchannels = Delegate('source')
|
|
264
|
+
|
|
265
|
+
#: Number of samples / snapshots in output, as given by :attr:`source`.
|
|
266
|
+
numsamples = Delegate('source')
|
|
267
|
+
|
|
268
|
+
# internal identifier
|
|
269
|
+
digest = Property(depends_on=['source.digest'])
|
|
270
|
+
|
|
271
|
+
@cached_property
|
|
272
|
+
def _get_digest(self):
|
|
273
|
+
return digest(self)
|
|
274
|
+
|
|
275
|
+
def result(self, num):
|
|
276
|
+
"""Python generator that processes the source data and yields the output block-wise.
|
|
277
|
+
|
|
278
|
+
This method needs to be implemented by the derived classes.
|
|
279
|
+
|
|
280
|
+
Parameters
|
|
281
|
+
----------
|
|
282
|
+
num : int
|
|
283
|
+
The size of the first dimension of the blocks to be yielded
|
|
284
|
+
|
|
285
|
+
Yields
|
|
286
|
+
------
|
|
287
|
+
numpy.ndarray
|
|
288
|
+
Two-dimensional output data block of shape (num, ...)
|
|
289
|
+
"""
|
|
290
|
+
yield from self.source.result(num)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class TimeInOut(TimeOut):
|
|
294
|
+
"""Deprecated alias for :class:`~acoular.base.TimeOut`.
|
|
295
|
+
|
|
296
|
+
.. deprecated:: 24.10
|
|
297
|
+
Using :class:`~acoular.base.TimeInOut` is deprecated and will be removed in Acoular 25.07.
|
|
298
|
+
Use :class:`~acoular.base.TimeOut` instead.
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
302
|
+
source = Instance(SamplesGenerator)
|
|
303
|
+
|
|
304
|
+
def __init__(self, *args, **kwargs):
|
|
305
|
+
super().__init__(*args, **kwargs)
|
|
306
|
+
import warnings
|
|
307
|
+
|
|
308
|
+
warnings.warn(
|
|
309
|
+
'TimeInOut is deprecated and will be removed in Acoular 25.07. Use TimeOut instead.',
|
|
310
|
+
DeprecationWarning,
|
|
311
|
+
stacklevel=2,
|
|
312
|
+
)
|
acoular/configuration.py
CHANGED
|
@@ -35,7 +35,7 @@ if 'numpy' in sys.modules:
|
|
|
35
35
|
np.show_config()
|
|
36
36
|
sys.stdout = orig_stdout
|
|
37
37
|
# check if it uses OpenBLAS or another library
|
|
38
|
-
if 'openblas' in temp_stdout.getvalue().lower():
|
|
38
|
+
if 'openblas' in temp_stdout.getvalue().lower() and environ.get('OPENBLAS_NUM_THREADS') != '1':
|
|
39
39
|
# it's OpenBLAS, set numba threads=1 to avoid overcommittment
|
|
40
40
|
import numba
|
|
41
41
|
|
|
@@ -54,7 +54,7 @@ else:
|
|
|
54
54
|
environ['OPENBLAS_NUM_THREADS'] = '1'
|
|
55
55
|
|
|
56
56
|
# this loads numpy, so we have to defer loading until OpenBLAS check is done
|
|
57
|
-
from traits.api import Bool,
|
|
57
|
+
from traits.api import Bool, Enum, HasStrictTraits, Property, Str, Trait, cached_property
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class Config(HasStrictTraits):
|
|
@@ -70,9 +70,9 @@ class Config(HasStrictTraits):
|
|
|
70
70
|
--------
|
|
71
71
|
For using Acoular with h5py package and overwrite existing cache:
|
|
72
72
|
|
|
73
|
-
>>>
|
|
74
|
-
>>>
|
|
75
|
-
>>>
|
|
73
|
+
>>> import acoular
|
|
74
|
+
>>> acoular.config.h5library = 'h5py'
|
|
75
|
+
>>> acoular.config.global_caching = 'overwrite'
|
|
76
76
|
|
|
77
77
|
"""
|
|
78
78
|
|
|
@@ -97,7 +97,7 @@ class Config(HasStrictTraits):
|
|
|
97
97
|
#: If 'pytables' can not be imported, 'h5py' is used.
|
|
98
98
|
h5library = Property()
|
|
99
99
|
|
|
100
|
-
_h5library =
|
|
100
|
+
_h5library = Enum('pytables', 'tables', 'h5py')
|
|
101
101
|
|
|
102
102
|
#: Defines the path to the directory containing Acoulars cache files.
|
|
103
103
|
#: If the specified :attr:`cache_dir` directory does not exist,
|
|
@@ -134,25 +134,28 @@ class Config(HasStrictTraits):
|
|
|
134
134
|
#: Boolean Flag that determines whether sounddevice is installed.
|
|
135
135
|
have_sounddevice = Property()
|
|
136
136
|
|
|
137
|
+
#: Boolean Flag that determines whether the package is installed.
|
|
138
|
+
have_traitsui = Property()
|
|
139
|
+
|
|
137
140
|
def _get_global_caching(self):
|
|
138
141
|
return self._global_caching
|
|
139
142
|
|
|
140
|
-
def _set_global_caching(self,
|
|
141
|
-
self._global_caching =
|
|
143
|
+
def _set_global_caching(self, value):
|
|
144
|
+
self._global_caching = value
|
|
142
145
|
|
|
143
146
|
def _get_h5library(self):
|
|
144
147
|
return self._h5library
|
|
145
148
|
|
|
146
|
-
def _set_h5library(self,
|
|
147
|
-
self._h5library =
|
|
149
|
+
def _set_h5library(self, name):
|
|
150
|
+
self._h5library = name
|
|
148
151
|
|
|
149
152
|
def _get_use_traitsui(self):
|
|
150
153
|
return self._use_traitsui
|
|
151
154
|
|
|
152
155
|
def _set_use_traitsui(self, use_tui):
|
|
153
|
-
if use_tui:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
if use_tui and not self.have_traitsui:
|
|
157
|
+
error_msg = 'TraitsUI package is not installed!'
|
|
158
|
+
raise ImportError(error_msg)
|
|
156
159
|
self._use_traitsui = use_tui
|
|
157
160
|
|
|
158
161
|
def _assert_h5library(self):
|
|
@@ -205,6 +208,10 @@ class Config(HasStrictTraits):
|
|
|
205
208
|
def _get_have_h5py(self):
|
|
206
209
|
return self._have_module('h5py')
|
|
207
210
|
|
|
211
|
+
@cached_property
|
|
212
|
+
def _get_have_traitsui(self):
|
|
213
|
+
return self._have_module('traitsui')
|
|
214
|
+
|
|
208
215
|
|
|
209
216
|
config = Config()
|
|
210
217
|
"""
|
|
@@ -232,7 +239,7 @@ Note: this is independent from the GUI tools implemented in the spectAcoular pac
|
|
|
232
239
|
Example:
|
|
233
240
|
For using Acoular with h5py package and overwrite existing cache:
|
|
234
241
|
|
|
235
|
-
>>>
|
|
236
|
-
>>>
|
|
237
|
-
>>>
|
|
242
|
+
>>> import acoular
|
|
243
|
+
>>> acoular.config.h5library = "h5py"
|
|
244
|
+
>>> acoular.config.global_caching = "overwrite"
|
|
238
245
|
"""
|
acoular/demo/acoular_demo.py
CHANGED
|
@@ -19,10 +19,10 @@ The simulation generates the sound pressure at 64 microphones that are
|
|
|
19
19
|
arrangend in the 'array64' geometry, which is part of the package. The sound
|
|
20
20
|
pressure signals are sampled at 51200 Hz for a duration of 1 second.
|
|
21
21
|
|
|
22
|
-
Source location (relative to array center) and
|
|
22
|
+
Source location (relative to array center) and RMS in 1 m distance:
|
|
23
23
|
|
|
24
24
|
====== =============== ======
|
|
25
|
-
Source Location
|
|
25
|
+
Source Location RMS
|
|
26
26
|
====== =============== ======
|
|
27
27
|
1 (-0.1,-0.1,0.3) 1.0 Pa
|
|
28
28
|
2 (0.15,0,0.3) 0.7 Pa
|
|
@@ -36,58 +36,45 @@ def run():
|
|
|
36
36
|
"""Run the Acoular demo."""
|
|
37
37
|
from pathlib import Path
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
MicGeom,
|
|
43
|
-
Mixer,
|
|
44
|
-
PointSource,
|
|
45
|
-
PowerSpectra,
|
|
46
|
-
RectGrid,
|
|
47
|
-
SteeringVector,
|
|
48
|
-
TimeSamples,
|
|
49
|
-
WNoiseGenerator,
|
|
50
|
-
WriteH5,
|
|
51
|
-
config,
|
|
52
|
-
)
|
|
53
|
-
from acoular import __file__ as bpath
|
|
39
|
+
import acoular as ac
|
|
40
|
+
|
|
41
|
+
ac.config.global_caching = 'none'
|
|
54
42
|
|
|
55
43
|
# set up the parameters
|
|
56
44
|
sfreq = 51200
|
|
57
45
|
duration = 1
|
|
58
46
|
nsamples = duration * sfreq
|
|
59
|
-
micgeofile = Path(
|
|
47
|
+
micgeofile = Path(ac.__file__).parent / 'xml' / 'array_64.xml'
|
|
60
48
|
h5savefile = 'three_sources.h5'
|
|
61
49
|
|
|
62
50
|
# generate test data, in real life this would come from an array measurement
|
|
63
|
-
mg = MicGeom(from_file=micgeofile)
|
|
64
|
-
n1 = WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=1)
|
|
65
|
-
n2 = WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=2, rms=0.7)
|
|
66
|
-
n3 = WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=3, rms=0.5)
|
|
67
|
-
p1 = PointSource(signal=n1, mics=mg, loc=(-0.1, -0.1, 0.3))
|
|
68
|
-
p2 = PointSource(signal=n2, mics=mg, loc=(0.15, 0, 0.3))
|
|
69
|
-
p3 = PointSource(signal=n3, mics=mg, loc=(0, 0.1, 0.3))
|
|
70
|
-
pa = Mixer(source=p1, sources=[p2, p3])
|
|
71
|
-
wh5 = WriteH5(source=pa, name=h5savefile)
|
|
51
|
+
mg = ac.MicGeom(from_file=micgeofile)
|
|
52
|
+
n1 = ac.WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=1)
|
|
53
|
+
n2 = ac.WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=2, rms=0.7)
|
|
54
|
+
n3 = ac.WNoiseGenerator(sample_freq=sfreq, numsamples=nsamples, seed=3, rms=0.5)
|
|
55
|
+
p1 = ac.PointSource(signal=n1, mics=mg, loc=(-0.1, -0.1, 0.3))
|
|
56
|
+
p2 = ac.PointSource(signal=n2, mics=mg, loc=(0.15, 0, 0.3))
|
|
57
|
+
p3 = ac.PointSource(signal=n3, mics=mg, loc=(0, 0.1, 0.3))
|
|
58
|
+
pa = ac.Mixer(source=p1, sources=[p2, p3])
|
|
59
|
+
wh5 = ac.WriteH5(source=pa, name=h5savefile)
|
|
72
60
|
wh5.save()
|
|
73
61
|
|
|
74
62
|
# analyze the data and generate map
|
|
75
63
|
|
|
76
|
-
|
|
77
|
-
ps = PowerSpectra(time_data=ts, block_size=128, window='Hanning')
|
|
64
|
+
ps = ac.PowerSpectra(source=pa, block_size=128, window='Hanning')
|
|
78
65
|
|
|
79
|
-
rg = RectGrid(x_min=-0.2, x_max=0.2, y_min=-0.2, y_max=0.2, z=0.3, increment=0.01)
|
|
80
|
-
st = SteeringVector(grid=rg, mics=mg)
|
|
66
|
+
rg = ac.RectGrid(x_min=-0.2, x_max=0.2, y_min=-0.2, y_max=0.2, z=0.3, increment=0.01)
|
|
67
|
+
st = ac.SteeringVector(grid=rg, mics=mg)
|
|
81
68
|
|
|
82
|
-
bb = BeamformerBase(freq_data=ps, steer=st)
|
|
69
|
+
bb = ac.BeamformerBase(freq_data=ps, steer=st)
|
|
83
70
|
pm = bb.synthetic(8000, 3)
|
|
84
|
-
|
|
71
|
+
spl = ac.L_p(pm)
|
|
85
72
|
|
|
86
|
-
if config.have_matplotlib:
|
|
73
|
+
if ac.config.have_matplotlib:
|
|
87
74
|
from pylab import axis, colorbar, figure, imshow, plot, show
|
|
88
75
|
|
|
89
76
|
# show map
|
|
90
|
-
imshow(
|
|
77
|
+
imshow(spl.T, origin='lower', vmin=spl.max() - 10, extent=rg.extend(), interpolation='bicubic')
|
|
91
78
|
colorbar()
|
|
92
79
|
|
|
93
80
|
# plot microphone geometry
|
|
@@ -99,6 +86,12 @@ def run():
|
|
|
99
86
|
|
|
100
87
|
else:
|
|
101
88
|
print('Matplotlib not found! Please install matplotlib if you want to plot the results.')
|
|
89
|
+
print('For consolation we do an ASCII map plot of the results here.')
|
|
90
|
+
grayscale = '@%#*+=-:. '[::-1]
|
|
91
|
+
ind = ((spl.T - spl.max() + 9).clip(0, 9)).astype(int)[::-1]
|
|
92
|
+
print(78 * '-')
|
|
93
|
+
print('|\n'.join([' '.join(['|'] + [grayscale[i] for i in row[2:-1]]) for row in ind]) + '|')
|
|
94
|
+
print(7 * '-', ''.join([f'{grayscale[i]}={int(spl.max())-9+i}dB ' for i in range(1, 10)]), 6 * '-')
|
|
102
95
|
|
|
103
96
|
|
|
104
97
|
if __name__ == '__main__':
|