acoular 25.10__py3-none-any.whl → 26.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/aiaa/aiaa.py +1 -1
- acoular/base.py +7 -7
- acoular/calib.py +6 -6
- acoular/demo/__init__.py +97 -9
- acoular/demo/__main__.py +37 -0
- acoular/environments.py +24 -24
- acoular/fbeamform.py +145 -142
- acoular/fprocess.py +11 -9
- acoular/grids.py +45 -211
- acoular/microphones.py +8 -8
- acoular/process.py +7 -14
- acoular/sdinput.py +9 -9
- acoular/signals.py +10 -10
- acoular/sources.py +84 -68
- acoular/spectra.py +27 -36
- acoular/tbeamform.py +26 -26
- acoular/tools/helpers.py +1 -1
- acoular/tools/utils.py +168 -0
- acoular/tprocess.py +76 -63
- acoular/trajectory.py +1 -2
- acoular/version.py +2 -2
- {acoular-25.10.dist-info → acoular-26.1.dist-info}/METADATA +53 -108
- {acoular-25.10.dist-info → acoular-26.1.dist-info}/RECORD +26 -26
- {acoular-25.10.dist-info → acoular-26.1.dist-info}/WHEEL +1 -1
- acoular/demo/acoular_demo.py +0 -135
- {acoular-25.10.dist-info → acoular-26.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.10.dist-info → acoular-26.1.dist-info}/licenses/LICENSE +0 -0
acoular/aiaa/aiaa.py
CHANGED
|
@@ -102,7 +102,7 @@ class CsmAIAABenchmark(PowerSpectraImport):
|
|
|
102
102
|
#: HDF5 file object
|
|
103
103
|
h5f = Instance(H5FileBase, transient=True)
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
#: A unique identifier for the CSM importer, based on its properties. (read-only)
|
|
106
106
|
digest = Property(depends_on=['basename', '_csmsum'])
|
|
107
107
|
|
|
108
108
|
@cached_property
|
acoular/base.py
CHANGED
|
@@ -55,7 +55,7 @@ class Generator(ABCHasStrictTraits):
|
|
|
55
55
|
"""
|
|
56
56
|
|
|
57
57
|
#: Sampling frequency of the signal, defaults to 1.0
|
|
58
|
-
sample_freq = Float(1.0
|
|
58
|
+
sample_freq = Float(1.0)
|
|
59
59
|
|
|
60
60
|
#: Number of signal samples
|
|
61
61
|
num_samples = CInt
|
|
@@ -63,7 +63,7 @@ class Generator(ABCHasStrictTraits):
|
|
|
63
63
|
#: Number of channels
|
|
64
64
|
num_channels = CInt
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
67
67
|
digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels'])
|
|
68
68
|
|
|
69
69
|
def _get_digest(self):
|
|
@@ -96,7 +96,7 @@ class SamplesGenerator(Generator):
|
|
|
96
96
|
|
|
97
97
|
"""
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
100
100
|
digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels'])
|
|
101
101
|
|
|
102
102
|
def _get_digest(self):
|
|
@@ -137,7 +137,7 @@ class SpectraGenerator(Generator):
|
|
|
137
137
|
#: The length of the block used to calculate the spectra
|
|
138
138
|
block_size = CInt
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
141
141
|
digest = Property(depends_on=['sample_freq', 'num_samples', 'num_channels', 'num_freqs', 'block_size'])
|
|
142
142
|
|
|
143
143
|
def _get_digest(self):
|
|
@@ -181,7 +181,7 @@ class TimeOut(SamplesGenerator):
|
|
|
181
181
|
#: Number of samples in output, as given by :attr:`source`.
|
|
182
182
|
num_samples = Delegate('source')
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
185
185
|
digest = Property(depends_on=['source.digest'])
|
|
186
186
|
|
|
187
187
|
@cached_property
|
|
@@ -237,7 +237,7 @@ class SpectraOut(SpectraGenerator):
|
|
|
237
237
|
#: The size of the block used to calculate the spectra
|
|
238
238
|
block_size = Delegate('source')
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
241
241
|
digest = Property(depends_on=['source.digest'])
|
|
242
242
|
|
|
243
243
|
@cached_property
|
|
@@ -285,7 +285,7 @@ class InOut(SamplesGenerator, SpectraGenerator):
|
|
|
285
285
|
#: Number of samples / snapshots in output, as given by :attr:`source`.
|
|
286
286
|
num_samples = Delegate('source')
|
|
287
287
|
|
|
288
|
-
|
|
288
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
289
289
|
digest = Property(depends_on=['source.digest'])
|
|
290
290
|
|
|
291
291
|
@cached_property
|
acoular/calib.py
CHANGED
|
@@ -78,26 +78,26 @@ class Calib(InOut):
|
|
|
78
78
|
"""
|
|
79
79
|
|
|
80
80
|
#: Name of the .xml file to be imported.
|
|
81
|
-
file = Union(None, File(filter=['*.xml'], exists=True)
|
|
81
|
+
file = Union(None, File(filter=['*.xml'], exists=True))
|
|
82
82
|
|
|
83
83
|
#: Number of microphones in the calibration data,
|
|
84
84
|
#: is set automatically when read from file or when data is set.
|
|
85
|
-
num_mics = CInt(0
|
|
85
|
+
num_mics = CInt(0)
|
|
86
86
|
|
|
87
87
|
#: Array of calibration factors,
|
|
88
88
|
#: is set automatically when read from file.
|
|
89
89
|
#: Can be set manually by specifying a NumPy array with shape (num_channels, ) if
|
|
90
90
|
#: :attr:`source` yields time domain signals. For frequency domain signals, the expected
|
|
91
91
|
#: shape is (num_channels * num_freqs).
|
|
92
|
-
data = CArray(
|
|
92
|
+
data = CArray()
|
|
93
93
|
|
|
94
94
|
#: Channels that are to be treated as invalid.
|
|
95
|
-
invalid_channels = List(int
|
|
95
|
+
invalid_channels = List(int)
|
|
96
96
|
|
|
97
97
|
#: Channel mask to serve as an index for all valid channels, is set automatically.
|
|
98
|
-
channels = Property(depends_on=['invalid_channels', 'num_mics']
|
|
98
|
+
channels = Property(depends_on=['invalid_channels', 'num_mics'])
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
#: A unique identifier for the object, based on its properties. (read-only)
|
|
101
101
|
digest = Property(depends_on=['source.digest', 'data'])
|
|
102
102
|
|
|
103
103
|
@observe('data')
|
acoular/demo/__init__.py
CHANGED
|
@@ -5,15 +5,103 @@
|
|
|
5
5
|
|
|
6
6
|
.. autosummary::
|
|
7
7
|
:toctree: generated/
|
|
8
|
+
"""
|
|
8
9
|
|
|
9
|
-
acoular_demo
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
def create_three_sources(mg, h5savefile='three_sources.h5'):
|
|
12
|
+
"""
|
|
13
|
+
Create three noise sources and return them as Mixer.
|
|
14
|
+
|
|
15
|
+
Alias for :func:`create_three_sources_2d`.
|
|
16
|
+
"""
|
|
17
|
+
return create_three_sources_2d(mg, h5savefile=h5savefile)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _create_three_sources(mg, locs, h5savefile='', sfreq=51200, duration=1):
|
|
21
|
+
"""Create three noise sources with custom locations and return them as Mixer."""
|
|
22
|
+
import acoular as ac
|
|
23
|
+
|
|
24
|
+
nsamples = duration * sfreq
|
|
25
|
+
|
|
26
|
+
n1 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=nsamples, seed=1)
|
|
27
|
+
n2 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=nsamples, seed=2, rms=0.7)
|
|
28
|
+
n3 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=nsamples, seed=3, rms=0.5)
|
|
29
|
+
|
|
30
|
+
noises = [n1, n2, n3]
|
|
31
|
+
ps = [ac.PointSource(signal=n, mics=mg, loc=loc) for n, loc in list(zip(noises, locs, strict=True))]
|
|
32
|
+
pa = ac.Mixer(source=ps[0], sources=ps[1:])
|
|
33
|
+
|
|
34
|
+
if h5savefile:
|
|
35
|
+
wh5 = ac.WriteH5(source=pa, file=h5savefile)
|
|
36
|
+
wh5.save()
|
|
37
|
+
return pa
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_three_sources_1d(mg, h5savefile='three_sources_1d.h5'):
|
|
41
|
+
"""Create three noise sources on a 1D line and return them as Mixer."""
|
|
42
|
+
locs = [(-0.1, 0, -0.3), (0.15, 0, -0.3), (0, 0, -0.3)]
|
|
43
|
+
return _create_three_sources(mg, locs, h5savefile=h5savefile)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def create_three_sources_2d(mg, h5savefile='three_sources_2d.h5'):
|
|
47
|
+
"""Create three noise sources in a 2D plane and return them as Mixer."""
|
|
48
|
+
locs = [(-0.1, -0.1, -0.3), (0.15, 0, -0.3), (0, 0.1, -0.3)]
|
|
49
|
+
return _create_three_sources(mg, locs, h5savefile=h5savefile)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def create_three_sources_3d(mg, h5savefile='three_sources_3d.h5'):
|
|
53
|
+
"""Create three noise sources in 3D space and return them as Mixer."""
|
|
54
|
+
locs = [(-0.1, -0.1, -0.3), (0.15, 0, -0.17), (0, 0.1, -0.25)]
|
|
55
|
+
return _create_three_sources(mg, locs, h5savefile=h5savefile)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def run():
|
|
59
|
+
"""Run the Acoular demo."""
|
|
60
|
+
from pathlib import Path
|
|
61
|
+
|
|
62
|
+
import acoular as ac
|
|
63
|
+
|
|
64
|
+
ac.config.global_caching = 'none'
|
|
65
|
+
|
|
66
|
+
# set up microphone geometry
|
|
67
|
+
|
|
68
|
+
micgeofile = Path(ac.__file__).parent / 'xml' / 'array_64.xml'
|
|
69
|
+
mg = ac.MicGeom(file=micgeofile)
|
|
70
|
+
|
|
71
|
+
# generate test data, in real life this would come from an array measurement
|
|
72
|
+
|
|
73
|
+
pa = create_three_sources(mg)
|
|
74
|
+
|
|
75
|
+
# analyze the data and generate map
|
|
76
|
+
|
|
77
|
+
ps = ac.PowerSpectra(source=pa, block_size=128, window='Hanning')
|
|
78
|
+
|
|
79
|
+
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)
|
|
80
|
+
st = ac.SteeringVector(grid=rg, mics=mg)
|
|
81
|
+
|
|
82
|
+
bb = ac.BeamformerBase(freq_data=ps, steer=st)
|
|
83
|
+
pm = bb.synthetic(8000, 3)
|
|
84
|
+
spl = ac.L_p(pm)
|
|
85
|
+
|
|
86
|
+
if ac.config.have_matplotlib:
|
|
87
|
+
from matplotlib.pyplot import axis, colorbar, figure, imshow, plot, show
|
|
88
|
+
|
|
89
|
+
# show map
|
|
90
|
+
imshow(spl.T, origin='lower', vmin=spl.max() - 10, extent=rg.extent, interpolation='bicubic')
|
|
91
|
+
colorbar()
|
|
92
|
+
|
|
93
|
+
# plot microphone geometry
|
|
94
|
+
figure(2)
|
|
95
|
+
plot(mg.pos[0], mg.pos[1], 'o')
|
|
96
|
+
axis('equal')
|
|
97
|
+
|
|
98
|
+
show()
|
|
12
99
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
100
|
+
else:
|
|
101
|
+
print('Matplotlib not found! Please install matplotlib if you want to plot the results.')
|
|
102
|
+
print('For consolation we do an ASCII map plot of the results here.')
|
|
103
|
+
grayscale = '@%#*+=-:. '[::-1]
|
|
104
|
+
ind = ((spl.T - spl.max() + 9).clip(0, 9)).astype(int)[::-1]
|
|
105
|
+
print(78 * '-')
|
|
106
|
+
print('|\n'.join([' '.join(['|'] + [grayscale[i] for i in row[2:-1]]) for row in ind]) + '|')
|
|
107
|
+
print(7 * '-', ''.join([f'{grayscale[i]}={int(spl.max()) - 9 + i}dB ' for i in range(1, 10)]), 6 * '-')
|
acoular/demo/__main__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Acoular Development Team.
|
|
3
|
+
# ------------------------------------------------------------------------------
|
|
4
|
+
"""Demo for Acoular.
|
|
5
|
+
|
|
6
|
+
To run the demo, execute the following commands:
|
|
7
|
+
|
|
8
|
+
.. code-block:: python
|
|
9
|
+
|
|
10
|
+
import acoular
|
|
11
|
+
|
|
12
|
+
acoular.demo.run()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Generates a test data set for three sources, analyzes them and generates a
|
|
16
|
+
map of the three sources.
|
|
17
|
+
|
|
18
|
+
The simulation generates the sound pressure at 64 microphones that are
|
|
19
|
+
arrangend in the 'array64' geometry, which is part of the package. The sound
|
|
20
|
+
pressure signals are sampled at 51200 Hz for a duration of 1 second.
|
|
21
|
+
|
|
22
|
+
Source location (relative to array center) and RMS in 1 m distance:
|
|
23
|
+
|
|
24
|
+
====== =============== ======
|
|
25
|
+
Source Location RMS
|
|
26
|
+
====== =============== ======
|
|
27
|
+
1 (-0.1,-0.1,0.3) 1.0 Pa
|
|
28
|
+
2 (0.15,0,0.3) 0.7 Pa
|
|
29
|
+
3 (0,0.1,0.3) 0.5 Pa
|
|
30
|
+
====== =============== ======
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
if __name__ == '__main__':
|
|
35
|
+
from . import run
|
|
36
|
+
|
|
37
|
+
run()
|
acoular/environments.py
CHANGED
|
@@ -182,7 +182,7 @@ class Environment(HasStrictTraits):
|
|
|
182
182
|
|
|
183
183
|
#: The speed of sound in the environment. Default is ``343.0``, which corresponds to the
|
|
184
184
|
#: approximate speed of sound at 20°C in dry air at sea level, if the unit is m/s.
|
|
185
|
-
c = Float(343.0
|
|
185
|
+
c = Float(343.0)
|
|
186
186
|
|
|
187
187
|
#: The region of interest (ROI) for calculations. (Not needed for most types of environment.)
|
|
188
188
|
#: Default is :obj:`None`.
|
|
@@ -250,11 +250,11 @@ class UniformFlowEnvironment(Environment):
|
|
|
250
250
|
|
|
251
251
|
#: The Mach number of the flow, defined as the ratio of the flow velocity to the speed of sound.
|
|
252
252
|
#: Default is ``0.0``, which corresponds to no flow.
|
|
253
|
-
ma = Float(0.0
|
|
253
|
+
ma = Float(0.0)
|
|
254
254
|
|
|
255
255
|
#: A unit vector specifying the direction of the flow in 3D Cartesian coordinates.
|
|
256
256
|
#: Default is ``(1.0, 0, 0)``, which corresponds to flow in the x-direction.
|
|
257
|
-
fdv = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0, 0))
|
|
257
|
+
fdv = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0, 0)))
|
|
258
258
|
|
|
259
259
|
#: A unique identifier based on the environment properties. (read-only)
|
|
260
260
|
digest = Property(
|
|
@@ -344,24 +344,24 @@ class SlotJet(FlowField):
|
|
|
344
344
|
"""
|
|
345
345
|
|
|
346
346
|
#: Exit velocity at the :attr:`slot jet origin<origin>` (nozzle). Default is ``0.0``.
|
|
347
|
-
v0 = Float(0.0
|
|
347
|
+
v0 = Float(0.0)
|
|
348
348
|
|
|
349
349
|
#: The location of the slot nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
350
|
-
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0))
|
|
350
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
351
351
|
|
|
352
352
|
#: Unit vector representing the flow direction. Default is ``(1.0, 0.0, 0.0)``.
|
|
353
|
-
flow = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0.0, 0.0))
|
|
353
|
+
flow = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0.0, 0.0)))
|
|
354
354
|
|
|
355
355
|
#: Unit vector parallel to the slot center plane, used to define the slot orientation.
|
|
356
356
|
#: Default is ``(0.0, 1.0, 0.0)``.
|
|
357
|
-
plane = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 1.0, 0.0))
|
|
357
|
+
plane = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 1.0, 0.0)))
|
|
358
358
|
|
|
359
359
|
#: Width of the slot (slot diameter). Default is ``0.2``.
|
|
360
|
-
B = Float(0.2
|
|
360
|
+
B = Float(0.2)
|
|
361
361
|
|
|
362
362
|
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
363
363
|
#: Default is ``5.2``.
|
|
364
|
-
l = Float(5.2
|
|
364
|
+
l = Float(5.2) # noqa: E741
|
|
365
365
|
|
|
366
366
|
#: A unique identifier based on the field properties. (read-only)
|
|
367
367
|
digest = Property(
|
|
@@ -465,17 +465,17 @@ class OpenJet(FlowField):
|
|
|
465
465
|
"""
|
|
466
466
|
|
|
467
467
|
#: Exit velocity at the jet origin (nozzle). Default is ``0.0``.
|
|
468
|
-
v0 = Float(0.0
|
|
468
|
+
v0 = Float(0.0)
|
|
469
469
|
|
|
470
470
|
#: The location of the nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
471
|
-
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0))
|
|
471
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
472
472
|
|
|
473
473
|
#: Diameter of the nozzle. Default is ``0.2``.
|
|
474
|
-
D = Float(0.2
|
|
474
|
+
D = Float(0.2)
|
|
475
475
|
|
|
476
476
|
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
477
477
|
#: Default is ``6.2``. :cite:`Albertson1950`
|
|
478
|
-
l = Float(6.2
|
|
478
|
+
l = Float(6.2) # noqa: E741
|
|
479
479
|
|
|
480
480
|
#: A unique identifier based on the field properties. (read-only)
|
|
481
481
|
digest = Property(
|
|
@@ -575,11 +575,11 @@ class RotatingFlow(FlowField):
|
|
|
575
575
|
[ 0. , 0. , 0. ]])
|
|
576
576
|
"""
|
|
577
577
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
rpm = Property(transient=True
|
|
578
|
+
#: Revolutions per minute (RPM). Default is ``0.0``.
|
|
579
|
+
#: Positive values indicate clockwise rotation of the flow.
|
|
580
|
+
#: This is contrary to the usual definition of the direction of rotation.
|
|
581
|
+
#: Deprecated! Please use the differently defined :attr:`rps` attribute instead.
|
|
582
|
+
rpm = Property(transient=True)
|
|
583
583
|
|
|
584
584
|
def _get_rpm(self):
|
|
585
585
|
warn(
|
|
@@ -601,14 +601,14 @@ class RotatingFlow(FlowField):
|
|
|
601
601
|
|
|
602
602
|
#: Rotational speed in revolutions per second. Negative values indicate clockwise
|
|
603
603
|
#: rigid-body-like rotation of the flow. Default is ``0.0``.
|
|
604
|
-
rps = Float(0.0
|
|
604
|
+
rps = Float(0.0)
|
|
605
605
|
|
|
606
606
|
#: Constant flow velocity in the z-direction. Default is ``0.0``.
|
|
607
|
-
v0 = Float(0.0
|
|
607
|
+
v0 = Float(0.0)
|
|
608
608
|
|
|
609
609
|
#: The location of the center of rotation.
|
|
610
610
|
#: Default is ``(0.0, 0.0, 0.0)``.
|
|
611
|
-
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0))
|
|
611
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
612
612
|
|
|
613
613
|
#: A unique identifier based on the field properties. (read-only)
|
|
614
614
|
digest = Property(
|
|
@@ -798,14 +798,14 @@ class GeneralFlowEnvironment(Environment):
|
|
|
798
798
|
|
|
799
799
|
#: The flow field object describing the velocity field,
|
|
800
800
|
#: which must be an instance of :class:`~acoular.environments.FlowField`.
|
|
801
|
-
ff = Instance(FlowField
|
|
801
|
+
ff = Instance(FlowField)
|
|
802
802
|
|
|
803
803
|
#: The number of rays used per solid angle :math:`\Omega`. Defaults to ``200``.
|
|
804
|
-
N = Int(200
|
|
804
|
+
N = Int(200)
|
|
805
805
|
|
|
806
806
|
#: The maximum solid angle (in steradians) used in the ray-tracing algorithm.
|
|
807
807
|
#: Default is :obj:`numpy.pi`.
|
|
808
|
-
Om = Float(np.pi
|
|
808
|
+
Om = Float(np.pi)
|
|
809
809
|
|
|
810
810
|
#: A unique identifier based on the environment properties. (read-only)
|
|
811
811
|
digest = Property(
|