acoular 25.4__py3-none-any.whl → 25.7__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 +2 -4
- acoular/aiaa/aiaa.py +4 -2
- acoular/base.py +14 -33
- acoular/calib.py +2 -2
- acoular/configuration.py +1 -1
- acoular/demo/__init__.py +6 -1
- acoular/demo/acoular_demo.py +34 -10
- acoular/deprecation.py +10 -1
- acoular/environments.py +5 -4
- acoular/fastFuncs.py +16 -10
- acoular/fbeamform.py +10 -107
- acoular/fprocess.py +3 -32
- acoular/grids.py +144 -37
- acoular/h5cache.py +5 -3
- acoular/h5files.py +10 -0
- acoular/internal.py +4 -0
- acoular/microphones.py +19 -2
- acoular/process.py +3 -45
- acoular/sdinput.py +12 -4
- acoular/signals.py +2 -2
- acoular/sources.py +27 -24
- acoular/spectra.py +3 -2
- acoular/tbeamform.py +3 -0
- acoular/tools/helpers.py +27 -0
- acoular/tprocess.py +1249 -468
- acoular/traitsviews.py +1 -3
- acoular/version.py +4 -3
- {acoular-25.4.dist-info → acoular-25.7.dist-info}/METADATA +3 -3
- acoular-25.7.dist-info/RECORD +56 -0
- acoular-25.4.dist-info/RECORD +0 -56
- {acoular-25.4.dist-info → acoular-25.7.dist-info}/WHEEL +0 -0
- {acoular-25.4.dist-info → acoular-25.7.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.4.dist-info → acoular-25.7.dist-info}/licenses/LICENSE +0 -0
acoular/fprocess.py
CHANGED
|
@@ -11,11 +11,8 @@ Implements blockwise processing methods in the frequency domain.
|
|
|
11
11
|
IRFFT
|
|
12
12
|
AutoPowerSpectra
|
|
13
13
|
CrossPowerSpectra
|
|
14
|
-
FFTSpectra
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
|
-
from warnings import warn
|
|
18
|
-
|
|
19
16
|
import numpy as np
|
|
20
17
|
from scipy import fft
|
|
21
18
|
from traits.api import Bool, CArray, Enum, Instance, Int, Property, Union, cached_property
|
|
@@ -29,7 +26,7 @@ from .process import SamplesBuffer
|
|
|
29
26
|
from .spectra import BaseSpectra
|
|
30
27
|
|
|
31
28
|
|
|
32
|
-
@deprecated_alias({'numfreqs': 'num_freqs', 'numsamples': 'num_samples'}, read_only=True)
|
|
29
|
+
@deprecated_alias({'numfreqs': 'num_freqs', 'numsamples': 'num_samples'}, read_only=True, removal_version='25.10')
|
|
33
30
|
class RFFT(BaseSpectra, SpectraOut):
|
|
34
31
|
"""
|
|
35
32
|
Compute the one-sided Fast Fourier Transform (FFT) for real-valued multichannel time data.
|
|
@@ -170,7 +167,7 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
170
167
|
yield fftdata[: j + 1]
|
|
171
168
|
|
|
172
169
|
|
|
173
|
-
@deprecated_alias({'numsamples': 'num_samples'}, read_only=True)
|
|
170
|
+
@deprecated_alias({'numsamples': 'num_samples'}, read_only=True, removal_version='25.10')
|
|
174
171
|
class IRFFT(TimeOut):
|
|
175
172
|
"""
|
|
176
173
|
Perform the inverse Fast Fourier Transform (IFFT) for one-sided multi-channel spectra.
|
|
@@ -350,7 +347,7 @@ class AutoPowerSpectra(SpectraOut):
|
|
|
350
347
|
yield ((temp * temp.conjugate()).real * scale).astype(self.precision)
|
|
351
348
|
|
|
352
349
|
|
|
353
|
-
@deprecated_alias({'numchannels': 'num_channels'}, read_only=True)
|
|
350
|
+
@deprecated_alias({'numchannels': 'num_channels'}, read_only=True, removal_version='25.10')
|
|
354
351
|
class CrossPowerSpectra(AutoPowerSpectra):
|
|
355
352
|
"""
|
|
356
353
|
Compute the complex-valued auto- and cross-power spectra from frequency-domain data.
|
|
@@ -450,29 +447,3 @@ class CrossPowerSpectra(AutoPowerSpectra):
|
|
|
450
447
|
csm_flat[i] = csm_lower[:, :nc].reshape(-1)
|
|
451
448
|
csm_upper[...] = 0 # calcCSM adds cumulative
|
|
452
449
|
yield csm_flat[: i + 1] * scale
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
class FFTSpectra(RFFT):
|
|
456
|
-
"""
|
|
457
|
-
Provide the one-sided Fast Fourier Transform (FFT) for multichannel time data.
|
|
458
|
-
|
|
459
|
-
.. deprecated:: 24.10
|
|
460
|
-
The :class:`~acoular.fprocess.FFTSpectra` class is deprecated and will be removed
|
|
461
|
-
in Acoular version 25.07. Please use :class:`~acoular.fprocess.RFFT` instead.
|
|
462
|
-
|
|
463
|
-
Alias for the :class:`~acoular.fprocess.RFFT` class, which computes the one-sided
|
|
464
|
-
Fast Fourier Transform (FFT) for multichannel time data.
|
|
465
|
-
|
|
466
|
-
Warnings
|
|
467
|
-
--------
|
|
468
|
-
This class remains temporarily available for backward compatibility but should not be used in
|
|
469
|
-
new implementations.
|
|
470
|
-
"""
|
|
471
|
-
|
|
472
|
-
def __init__(self, *args, **kwargs):
|
|
473
|
-
super().__init__(*args, **kwargs)
|
|
474
|
-
warn(
|
|
475
|
-
'Using FFTSpectra is deprecated and will be removed in Acoular version 25.07. Use class RFFT instead.',
|
|
476
|
-
DeprecationWarning,
|
|
477
|
-
stacklevel=2,
|
|
478
|
-
)
|
acoular/grids.py
CHANGED
|
@@ -28,6 +28,7 @@ Implement support for multidimensional grids and integration sectors.
|
|
|
28
28
|
# imports from other packages
|
|
29
29
|
import xml.dom.minidom
|
|
30
30
|
from abc import abstractmethod
|
|
31
|
+
from pathlib import Path
|
|
31
32
|
|
|
32
33
|
from numpy import (
|
|
33
34
|
absolute,
|
|
@@ -301,7 +302,7 @@ class Polygon:
|
|
|
301
302
|
return mindst
|
|
302
303
|
|
|
303
304
|
|
|
304
|
-
@deprecated_alias({'gpos': 'pos'})
|
|
305
|
+
@deprecated_alias({'gpos': 'pos'}, removal_version='25.10')
|
|
305
306
|
class Grid(ABCHasStrictTraits):
|
|
306
307
|
"""
|
|
307
308
|
Abstract base class for grid geometries.
|
|
@@ -309,6 +310,16 @@ class Grid(ABCHasStrictTraits):
|
|
|
309
310
|
This class defines a common interface for all grid geometries and provides tools to query grid
|
|
310
311
|
properties and related data. It is intended to serve as a base class for specialized grid
|
|
311
312
|
implementations and should not be instantiated directly as it lacks concrete functionality.
|
|
313
|
+
|
|
314
|
+
.. _units_note_grids:
|
|
315
|
+
|
|
316
|
+
Unit System
|
|
317
|
+
-----------
|
|
318
|
+
The source code is agnostic to the unit of length. The positions' coordinates are assumed to be
|
|
319
|
+
in meters. This is consistent with the standard :class:`~acoular.environments.Environment` class
|
|
320
|
+
which uses the speed of sound at 20°C at sea level under standard atmosphere pressure in m/s.
|
|
321
|
+
If the positions' coordinates are provided in a unit other than meter, it is advisable to change
|
|
322
|
+
the :attr:`~acoular.environments.Environment.c` attribute to match the given unit.
|
|
312
323
|
"""
|
|
313
324
|
|
|
314
325
|
#: The total number of grid points. This property is automatically calculated based on other
|
|
@@ -321,6 +332,7 @@ class Grid(ABCHasStrictTraits):
|
|
|
321
332
|
|
|
322
333
|
#: The grid positions represented as a (3, :attr:`size`) array of :class:`floats<float>`.
|
|
323
334
|
#: (read-only)
|
|
335
|
+
#: All positions' coordinates are in meters by default (see :ref:`notes <units_note_grids>`).
|
|
324
336
|
pos = Property(desc='x, y, z positions of grid points')
|
|
325
337
|
|
|
326
338
|
#: A unique identifier for the grid, based on its properties. (read-only)
|
|
@@ -375,8 +387,77 @@ class Grid(ABCHasStrictTraits):
|
|
|
375
387
|
# return indices of "True" entries
|
|
376
388
|
return where(xyi)
|
|
377
389
|
|
|
390
|
+
def export_gpos(self, filename):
|
|
391
|
+
"""
|
|
392
|
+
Export the grid positions to an XML file.
|
|
393
|
+
|
|
394
|
+
This method generates an XML file containing the positions of all grid points.
|
|
395
|
+
Each point is represented by a ``<pos>`` element with ``Name``, ``x``, ``y``, and ``z``
|
|
396
|
+
attributes. The generated XML is formatted to match the structure required for importing
|
|
397
|
+
into the :class:`ImportGrid` class.
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
----------
|
|
401
|
+
filename : :class:`str`
|
|
402
|
+
The path to the file to which the grid positions will be written. The file
|
|
403
|
+
extension must be ``.xml``.
|
|
404
|
+
|
|
405
|
+
Raises
|
|
406
|
+
------
|
|
407
|
+
:obj:`OSError`
|
|
408
|
+
If the file cannot be written due to permissions issues or invalid file paths.
|
|
409
|
+
|
|
410
|
+
Notes
|
|
411
|
+
-----
|
|
412
|
+
- The file will be saved in UTF-8 encoding.
|
|
413
|
+
- The ``Name`` attribute for each point is set as ``"Point {i+1}"``, where ``i`` is the
|
|
414
|
+
index of the grid point.
|
|
415
|
+
- If subgrids are defined, they will be included as the ``subgrid`` attribute.
|
|
416
|
+
|
|
417
|
+
Examples
|
|
418
|
+
--------
|
|
419
|
+
Export a grid with 100 points to an XML file:
|
|
420
|
+
|
|
421
|
+
>>> import acoular as ac
|
|
422
|
+
>>> import numpy as np
|
|
423
|
+
>>> grid = ac.ImportGrid()
|
|
424
|
+
>>> # Create some grid points
|
|
425
|
+
>>> points = np.arange(9).reshape(3, 3)
|
|
426
|
+
>>> grid.pos = points
|
|
427
|
+
>>> grid.export_gpos('grid_points.xml') # doctest: +SKIP
|
|
428
|
+
|
|
429
|
+
The generated ``grid_points.xml`` file will look like this:
|
|
430
|
+
|
|
431
|
+
.. code-block:: xml
|
|
378
432
|
|
|
379
|
-
|
|
433
|
+
<?xml version="1.1" encoding="utf-8"?><Grid name="grid_points">
|
|
434
|
+
<pos Name="Point 1" x="0" y="1" z="2"/>
|
|
435
|
+
<pos Name="Point 2" x="3" y="4" z="5"/>
|
|
436
|
+
<pos Name="Point 3" x="6" y="7" z="8"/>
|
|
437
|
+
</Grid>
|
|
438
|
+
"""
|
|
439
|
+
filepath = Path(filename)
|
|
440
|
+
basename = filepath.stem
|
|
441
|
+
with filepath.open('w', encoding='utf-8') as f:
|
|
442
|
+
f.write(f'<?xml version="1.1" encoding="utf-8"?><Grid name="{basename}">\n')
|
|
443
|
+
for i in range(self.pos.shape[-1]):
|
|
444
|
+
has_subgrids = hasattr(self, 'subgrids') and len(self.subgrids) > i
|
|
445
|
+
subgrid_attr = f'subgrid="{self.subgrids[i]}"' if has_subgrids else ''
|
|
446
|
+
pos_str = ' '.join(
|
|
447
|
+
[
|
|
448
|
+
' <pos',
|
|
449
|
+
f'Name="Point {i+1}"',
|
|
450
|
+
f'x="{self.pos[0, i]}"',
|
|
451
|
+
f'y="{self.pos[1, i]}"',
|
|
452
|
+
f'z="{self.pos[2, i]}"',
|
|
453
|
+
f'{subgrid_attr}/>\n',
|
|
454
|
+
]
|
|
455
|
+
)
|
|
456
|
+
f.write(pos_str)
|
|
457
|
+
f.write('</Grid>')
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
@deprecated_alias({'gpos': 'pos'}, read_only=True, removal_version='25.10')
|
|
380
461
|
class RectGrid(Grid):
|
|
381
462
|
"""
|
|
382
463
|
Provides a 2D Cartesian grid for beamforming results.
|
|
@@ -409,6 +490,9 @@ class RectGrid(Grid):
|
|
|
409
490
|
#: Number of grid points along y-axis. (read-only)
|
|
410
491
|
nysteps = Property(desc='number of grid points along y-axis')
|
|
411
492
|
|
|
493
|
+
#: The grid's extension in :obj:`matplotlib.pyplot.imshow` compatible form. (read-only)
|
|
494
|
+
extent = Property(desc='grid extent as (x_min, x_max, y_min, y_max)')
|
|
495
|
+
|
|
412
496
|
#: A unique identifier for the grid, based on its properties. (read-only)
|
|
413
497
|
digest = Property(
|
|
414
498
|
depends_on=['x_min', 'x_max', 'y_min', 'y_max', 'z', 'increment'],
|
|
@@ -450,6 +534,56 @@ class RectGrid(Grid):
|
|
|
450
534
|
bpos.resize((3, self.size))
|
|
451
535
|
return bpos
|
|
452
536
|
|
|
537
|
+
@property_depends_on(['x_min', 'x_max', 'y_min', 'y_max'])
|
|
538
|
+
def _get_extent(self):
|
|
539
|
+
# Return the grid's extension in :obj:`matplotlib.pyplot.imshow` compatible form.
|
|
540
|
+
#
|
|
541
|
+
# Returns
|
|
542
|
+
# -------
|
|
543
|
+
# :class:`tuple` of :class:`floats<float>`
|
|
544
|
+
# (:attr:`x_min`, :attr:`x_max`, :attr:`y_min`, :attr:`y_max`) representing the grid's
|
|
545
|
+
# extent.
|
|
546
|
+
#
|
|
547
|
+
# Notes
|
|
548
|
+
# -----
|
|
549
|
+
# This property is intended for use with the ``extent`` parameter of
|
|
550
|
+
# :obj:`matplotlib.pyplot.imshow`.
|
|
551
|
+
#
|
|
552
|
+
# Examples
|
|
553
|
+
# --------
|
|
554
|
+
# >>> from acoular import RectGrid
|
|
555
|
+
# >>> grid = RectGrid()
|
|
556
|
+
# >>> grid.y_min = -5
|
|
557
|
+
# >>> grid.y_max = 5
|
|
558
|
+
# >>> grid.extent
|
|
559
|
+
# (-1.0, 1.0, -5.0, 5.0)
|
|
560
|
+
return (self.x_min, self.x_max, self.y_min, self.y_max)
|
|
561
|
+
|
|
562
|
+
def extend(self):
|
|
563
|
+
"""
|
|
564
|
+
Return the grid's extension in :obj:`matplotlib.pyplot.imshow` compatible form.
|
|
565
|
+
|
|
566
|
+
Returns
|
|
567
|
+
-------
|
|
568
|
+
:class:`tuple` of :class:`floats<float>`
|
|
569
|
+
(:attr:`x_min`, :attr:`x_max`, :attr:`y_min`, :attr:`y_max`) representing the grid's
|
|
570
|
+
extent.
|
|
571
|
+
|
|
572
|
+
Notes
|
|
573
|
+
-----
|
|
574
|
+
This method is deprecated. Use the :attr:`extent` property instead.
|
|
575
|
+
"""
|
|
576
|
+
import warnings
|
|
577
|
+
|
|
578
|
+
msg = ' '.join(
|
|
579
|
+
[
|
|
580
|
+
"Deprecated use of 'extend' method (will be removed in version 26.04).",
|
|
581
|
+
"Please use the 'extent' trait instead.",
|
|
582
|
+
]
|
|
583
|
+
)
|
|
584
|
+
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
585
|
+
return self.extent
|
|
586
|
+
|
|
453
587
|
def index(self, x, y):
|
|
454
588
|
"""
|
|
455
589
|
Find the indices of a grid point near a given coordinate.
|
|
@@ -539,34 +673,6 @@ class RectGrid(Grid):
|
|
|
539
673
|
return array(xis), array(yis)
|
|
540
674
|
# return arange(self.size)[inds]
|
|
541
675
|
|
|
542
|
-
def extend(self):
|
|
543
|
-
"""
|
|
544
|
-
Return the grid's extension in :obj:`matplotlib.pyplot.imshow` compatible form.
|
|
545
|
-
|
|
546
|
-
Returns
|
|
547
|
-
-------
|
|
548
|
-
:class:`tuple` of :class:`floats<float>`
|
|
549
|
-
(:attr:`x_min`, :attr:`x_max`, :attr:`y_min`, :attr:`y_max`) representing the grid's
|
|
550
|
-
extent.
|
|
551
|
-
|
|
552
|
-
Notes
|
|
553
|
-
-----
|
|
554
|
-
- ``pylab.imhow`` is the same as :obj:`matplotlib.pyplot.imshow`. It's only using a
|
|
555
|
-
different namespace.
|
|
556
|
-
- The return of the method is ment for the ``extent`` parameter of
|
|
557
|
-
:obj:`matplotlib.pyplot.imshow`.
|
|
558
|
-
|
|
559
|
-
Examples
|
|
560
|
-
--------
|
|
561
|
-
>>> from acoular import RectGrid
|
|
562
|
-
>>> grid = RectGrid()
|
|
563
|
-
>>> grid.y_min = -5
|
|
564
|
-
>>> grid.y_max = 5
|
|
565
|
-
>>> grid.extend()
|
|
566
|
-
(-1.0, 1.0, -5.0, 5.0)
|
|
567
|
-
"""
|
|
568
|
-
return (self.x_min, self.x_max, self.y_min, self.y_max)
|
|
569
|
-
|
|
570
676
|
|
|
571
677
|
class RectGrid3D(RectGrid):
|
|
572
678
|
"""
|
|
@@ -575,10 +681,10 @@ class RectGrid3D(RectGrid):
|
|
|
575
681
|
The grid has cubic or nearly cubic cells. It is defined by lower and upper x-, y- and z-limits.
|
|
576
682
|
"""
|
|
577
683
|
|
|
578
|
-
#: The lower z-limit that defines the grid. Default is ``-1``.
|
|
684
|
+
#: The lower z-limit that defines the grid. Default is ``-1.0``.
|
|
579
685
|
z_min = Float(-1.0, desc='minimum z-value')
|
|
580
686
|
|
|
581
|
-
#: The upper z-limit that defines the grid. Default is ``1``.
|
|
687
|
+
#: The upper z-limit that defines the grid. Default is ``1.0``.
|
|
582
688
|
z_max = Float(1.0, desc='maximum z-value')
|
|
583
689
|
|
|
584
690
|
#: Number of grid points along x-axis. (read-only)
|
|
@@ -760,7 +866,7 @@ class RectGrid3D(RectGrid):
|
|
|
760
866
|
return s_[xi1 : xi2 + 1], s_[yi1 : yi2 + 1], s_[zi1 : zi2 + 1]
|
|
761
867
|
|
|
762
868
|
|
|
763
|
-
@deprecated_alias({'from_file': 'file', 'gpos_file': 'pos'})
|
|
869
|
+
@deprecated_alias({'from_file': 'file', 'gpos_file': 'pos'}, removal_version='25.10')
|
|
764
870
|
class ImportGrid(Grid):
|
|
765
871
|
"""
|
|
766
872
|
Load a 3D grid from an XML file.
|
|
@@ -928,7 +1034,7 @@ class ImportGrid(Grid):
|
|
|
928
1034
|
self.subgrids = array(names)
|
|
929
1035
|
|
|
930
1036
|
|
|
931
|
-
@deprecated_alias({'gpos': 'pos', 'numpoints': 'num_points'}, read_only=['gpos'])
|
|
1037
|
+
@deprecated_alias({'gpos': 'pos', 'numpoints': 'num_points'}, read_only=['gpos'], removal_version='25.10')
|
|
932
1038
|
class LineGrid(Grid):
|
|
933
1039
|
"""
|
|
934
1040
|
Define a 3D grid for a line geometry.
|
|
@@ -976,8 +1082,9 @@ class LineGrid(Grid):
|
|
|
976
1082
|
#: are set. (read-only)
|
|
977
1083
|
size = Property(desc='overall number of grid points')
|
|
978
1084
|
|
|
979
|
-
#: A (3, :attr:`size`) array containing the x, y, and z positions
|
|
980
|
-
#:
|
|
1085
|
+
#: A (3, :attr:`size`) array containing the x, y, and z positions of the grid points.
|
|
1086
|
+
#: (read-only)
|
|
1087
|
+
#: All positions' coordinates are in meters by default (see :ref:`notes <units_note_grids>`).
|
|
981
1088
|
pos = Property(desc='x, y, z positions of grid points')
|
|
982
1089
|
|
|
983
1090
|
#: A unique identifier for the grid, based on its properties. (read-only)
|
|
@@ -1008,7 +1115,7 @@ class LineGrid(Grid):
|
|
|
1008
1115
|
return pos.T
|
|
1009
1116
|
|
|
1010
1117
|
|
|
1011
|
-
@deprecated_alias({'gpos': 'pos'}, read_only=True)
|
|
1118
|
+
@deprecated_alias({'gpos': 'pos'}, read_only=True, removal_version='25.10')
|
|
1012
1119
|
class MergeGrid(Grid):
|
|
1013
1120
|
"""
|
|
1014
1121
|
Base class for merging multiple grid geometries.
|
acoular/h5cache.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
"""Implements a cache for HDF5 files used in Acoular."""
|
|
6
|
+
|
|
6
7
|
import gc
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from weakref import WeakValueDictionary
|
|
@@ -92,10 +93,11 @@ class HDF5Cache(HasStrictTraits):
|
|
|
92
93
|
return # cachefile is not created in readonly mode
|
|
93
94
|
|
|
94
95
|
if isinstance(obj.h5f, file_cls):
|
|
95
|
-
|
|
96
|
+
h5filename = Path(obj.h5f.filename).resolve()
|
|
97
|
+
if h5filename == filename:
|
|
96
98
|
self.busy = False
|
|
97
99
|
return
|
|
98
|
-
self._decrease_file_reference_counter(
|
|
100
|
+
self._decrease_file_reference_counter(h5filename)
|
|
99
101
|
|
|
100
102
|
if filename not in self.open_files: # or tables.file._open_files.filenames
|
|
101
103
|
if config.global_caching == 'readonly':
|
acoular/h5files.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
+
"""Implements base classes for handling HDF5 files."""
|
|
6
|
+
|
|
5
7
|
from .configuration import config
|
|
6
8
|
|
|
7
9
|
|
|
@@ -57,6 +59,8 @@ if config.have_tables:
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
class H5FileTables(H5FileBase, tables.File):
|
|
62
|
+
"""Hdf5 File based on PyTables."""
|
|
63
|
+
|
|
60
64
|
def create_extendable_array(self, nodename, shape, precision, group=None):
|
|
61
65
|
if not group:
|
|
62
66
|
group = self.root
|
|
@@ -106,6 +110,8 @@ if config.have_tables:
|
|
|
106
110
|
return result
|
|
107
111
|
|
|
108
112
|
class H5CacheFileTables(H5FileTables, H5CacheFileBase):
|
|
113
|
+
"""Hdf5 Cache File based on PyTables."""
|
|
114
|
+
|
|
109
115
|
compression_filter = tables.Filters(complevel=5, complib='blosc')
|
|
110
116
|
|
|
111
117
|
def is_cached(self, nodename, group=None):
|
|
@@ -124,6 +130,8 @@ if config.have_h5py:
|
|
|
124
130
|
import h5py
|
|
125
131
|
|
|
126
132
|
class H5FileH5py(H5FileBase, h5py.File):
|
|
133
|
+
"""Hdf5 File based on h5py."""
|
|
134
|
+
|
|
127
135
|
def _get_in_file_path(self, nodename, group=None):
|
|
128
136
|
if not group:
|
|
129
137
|
return '/' + nodename
|
|
@@ -182,6 +190,8 @@ if config.have_h5py:
|
|
|
182
190
|
return result
|
|
183
191
|
|
|
184
192
|
class H5CacheFileH5py(H5CacheFileBase, H5FileH5py):
|
|
193
|
+
"""Hdf5 Cache File based on h5py."""
|
|
194
|
+
|
|
185
195
|
compression_filter = 'lzf'
|
|
186
196
|
# compression_filter = 'blosc' # unavailable...
|
|
187
197
|
|
acoular/internal.py
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
+
"""Implements a digest function for caching of traits based on a unique identifier."""
|
|
6
|
+
|
|
5
7
|
from hashlib import md5
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
def digest(obj, name='digest'):
|
|
11
|
+
"""Generate a unique digest for the given object based on its traits."""
|
|
9
12
|
str_ = [str(obj.__class__).encode('UTF-8')]
|
|
10
13
|
for do_ in obj.trait(name).depends_on:
|
|
11
14
|
vobj = obj
|
|
@@ -19,6 +22,7 @@ def digest(obj, name='digest'):
|
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
def ldigest(obj_list):
|
|
25
|
+
"""Generate a unique digest for a list of objects based on their traits."""
|
|
22
26
|
str_ = []
|
|
23
27
|
for i in obj_list:
|
|
24
28
|
str_.append(str(i.digest).encode('UTF-8'))
|
acoular/microphones.py
CHANGED
|
@@ -32,7 +32,9 @@ from .deprecation import deprecated_alias
|
|
|
32
32
|
from .internal import digest
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
@deprecated_alias(
|
|
35
|
+
@deprecated_alias(
|
|
36
|
+
{'mpos_tot': 'pos_total', 'mpos': 'pos', 'from_file': 'file'}, read_only=['mpos'], removal_version='25.10'
|
|
37
|
+
)
|
|
36
38
|
class MicGeom(HasStrictTraits):
|
|
37
39
|
"""
|
|
38
40
|
Provide the geometric arrangement of microphones in an array.
|
|
@@ -47,6 +49,17 @@ class MicGeom(HasStrictTraits):
|
|
|
47
49
|
attribute is updated.
|
|
48
50
|
- Small numerical values in the computed :attr:`center` are set to zero for numerical stability.
|
|
49
51
|
|
|
52
|
+
.. _units_note_microphones:
|
|
53
|
+
|
|
54
|
+
Unit System
|
|
55
|
+
-----------
|
|
56
|
+
The source code is agnostic to the unit of length. The microphone positions' coordinates are
|
|
57
|
+
assumed to be in meters. This is consistent with the standard
|
|
58
|
+
:class:`~acoular.environments.Environment` class which uses the speed of sound at 20°C at sea
|
|
59
|
+
level under standard atmosphere pressure in m/s. If the microphone positions' coordinates are
|
|
60
|
+
provided in a unit other than meter, it is advisable to change the
|
|
61
|
+
:attr:`~acoular.environments.Environment.c` attribute to match the given unit.
|
|
62
|
+
|
|
50
63
|
Examples
|
|
51
64
|
--------
|
|
52
65
|
To set a microphone geomerty for ``n`` programmatically, first a ``(3,n)`` array is needed. In
|
|
@@ -133,11 +146,13 @@ class MicGeom(HasStrictTraits):
|
|
|
133
146
|
|
|
134
147
|
#: Array containing the ``x, y, z`` positions of all microphones, including invalid ones, shape
|
|
135
148
|
#: ``(3,`` :attr:`num_mics` ``)``. This is set automatically when :attr:`file` changes or
|
|
136
|
-
#: explicitly by assigning an array of floats.
|
|
149
|
+
#: explicitly by assigning an array of floats. All coordinates are in meters by default (see
|
|
150
|
+
#: :ref:`notes <units_note_micophones>`).
|
|
137
151
|
pos_total = CArray(dtype=float, shape=(3, None), desc='x, y, z position of all microphones')
|
|
138
152
|
|
|
139
153
|
#: Array containing the ``x, y, z`` positions of valid microphones (i.e., excluding those in
|
|
140
154
|
#: :attr:`invalid_channels`), shape ``(3,`` :attr:`num_mics` ``)``. (read-only)
|
|
155
|
+
#: All coordinates are in meters by default (see :ref:`notes <units_note>`).
|
|
141
156
|
pos = Property(depends_on=['pos_total', 'invalid_channels'], desc='x, y, z position of used microphones')
|
|
142
157
|
|
|
143
158
|
#: List of indices indicating microphones to be excluded from calculations and results.
|
|
@@ -251,6 +266,8 @@ class MicGeom(HasStrictTraits):
|
|
|
251
266
|
index of the microphone.
|
|
252
267
|
- This method only exports the positions of the valid microphones (those not listed in
|
|
253
268
|
:attr:`invalid_channels`).
|
|
269
|
+
- All coordinates (x, y, z) are exported in meters by default (see
|
|
270
|
+
:ref:`notes <units_note_micophones>`).
|
|
254
271
|
"""
|
|
255
272
|
filepath = Path(filename)
|
|
256
273
|
basename = filepath.stem
|
acoular/process.py
CHANGED
|
@@ -10,8 +10,6 @@ General purpose blockwise processing methods independent of the domain (time or
|
|
|
10
10
|
Average
|
|
11
11
|
Cache
|
|
12
12
|
SampleSplitter
|
|
13
|
-
TimeAverage
|
|
14
|
-
TimeCache
|
|
15
13
|
SamplesBuffer
|
|
16
14
|
"""
|
|
17
15
|
|
|
@@ -65,7 +63,9 @@ class LockedGenerator:
|
|
|
65
63
|
return self.it.__next__()
|
|
66
64
|
|
|
67
65
|
|
|
68
|
-
@deprecated_alias(
|
|
66
|
+
@deprecated_alias(
|
|
67
|
+
{'naverage': 'num_per_average', 'numsamples': 'num_samples'}, read_only=['numsamples'], removal_version='25.10'
|
|
68
|
+
)
|
|
69
69
|
class Average(InOut):
|
|
70
70
|
"""
|
|
71
71
|
Calculate the average across consecutive time samples or frequency snapshots.
|
|
@@ -675,48 +675,6 @@ class SampleSplitter(InOut):
|
|
|
675
675
|
raise OSError(msg)
|
|
676
676
|
|
|
677
677
|
|
|
678
|
-
class TimeAverage(Average):
|
|
679
|
-
"""
|
|
680
|
-
Calculate the average of the signal.
|
|
681
|
-
|
|
682
|
-
.. deprecated:: 24.10
|
|
683
|
-
The use of :class:`~acoular.process.TimeAverage` is deprecated
|
|
684
|
-
and will be removed in Acoular version 25.07.
|
|
685
|
-
Please use :class:`~acoular.process.Average` instead for future compatibility.
|
|
686
|
-
|
|
687
|
-
Alias for :class:`~acoular.process.Average`.
|
|
688
|
-
"""
|
|
689
|
-
|
|
690
|
-
def __init__(self, *args, **kwargs):
|
|
691
|
-
super().__init__(*args, **kwargs)
|
|
692
|
-
warn(
|
|
693
|
-
'Using TimeAverage is deprecated and will be removed in Acoular version 25.07. Use Average instead.',
|
|
694
|
-
DeprecationWarning,
|
|
695
|
-
stacklevel=2,
|
|
696
|
-
)
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
class TimeCache(Cache):
|
|
700
|
-
"""
|
|
701
|
-
Cache source signals in cache file.
|
|
702
|
-
|
|
703
|
-
.. deprecated:: 24.10
|
|
704
|
-
The use of :class:`~acoular.process.TimeCache` is deprecated
|
|
705
|
-
and will be removed in Acoular version 25.07.
|
|
706
|
-
Please use :class:`~acoular.process.Cache` instead for future compatibility.
|
|
707
|
-
|
|
708
|
-
Alias for :class:`~acoular.process.Cache`.
|
|
709
|
-
"""
|
|
710
|
-
|
|
711
|
-
def __init__(self, *args, **kwargs):
|
|
712
|
-
super().__init__(*args, **kwargs)
|
|
713
|
-
warn(
|
|
714
|
-
'Using TimeCache is deprecated and will be removed in Acoular version 25.07. Use Cache instead.',
|
|
715
|
-
DeprecationWarning,
|
|
716
|
-
stacklevel=2,
|
|
717
|
-
)
|
|
718
|
-
|
|
719
|
-
|
|
720
678
|
class SamplesBuffer(InOut):
|
|
721
679
|
"""
|
|
722
680
|
Handle buffering of samples from a source.
|
acoular/sdinput.py
CHANGED
|
@@ -21,7 +21,10 @@ if config.have_sounddevice:
|
|
|
21
21
|
import sounddevice as sd
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
@deprecated_alias(
|
|
24
|
+
@deprecated_alias(
|
|
25
|
+
{'numchannels': 'num_channels', 'numsamples': 'num_samples', 'collectsamples': 'collect_samples'},
|
|
26
|
+
removal_version='25.10',
|
|
27
|
+
)
|
|
25
28
|
class SoundDeviceSamplesGenerator(SamplesGenerator):
|
|
26
29
|
"""Controller for sound card hardware using sounddevice library.
|
|
27
30
|
|
|
@@ -87,15 +90,20 @@ class SoundDeviceSamplesGenerator(SamplesGenerator):
|
|
|
87
90
|
self._sample_freq = f
|
|
88
91
|
|
|
89
92
|
def device_properties(self):
|
|
90
|
-
"""
|
|
93
|
+
"""
|
|
94
|
+
Display the properties of the sounddevice input device.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
91
97
|
-------
|
|
92
98
|
Dictionary of device properties according to sounddevice
|
|
93
99
|
"""
|
|
94
100
|
return sd.query_devices(self.device)
|
|
95
101
|
|
|
96
102
|
def result(self, num):
|
|
97
|
-
"""
|
|
98
|
-
|
|
103
|
+
"""
|
|
104
|
+
Python generator that yields the output block-wise.
|
|
105
|
+
|
|
106
|
+
Use at least a block-size of one ring cache block.
|
|
99
107
|
|
|
100
108
|
Parameters
|
|
101
109
|
----------
|
acoular/signals.py
CHANGED
|
@@ -43,7 +43,7 @@ from .deprecation import deprecated_alias
|
|
|
43
43
|
from .internal import digest
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
@deprecated_alias({'numsamples': 'num_samples'})
|
|
46
|
+
@deprecated_alias({'numsamples': 'num_samples'}, removal_version='25.10')
|
|
47
47
|
class SignalGenerator(ABCHasStrictTraits):
|
|
48
48
|
"""
|
|
49
49
|
ABC for a simple one-channel signal generator.
|
|
@@ -556,7 +556,7 @@ class SineGenerator(PeriodicSignalGenerator):
|
|
|
556
556
|
return self.amplitude * sin(2 * pi * self.freq * t + self.phase)
|
|
557
557
|
|
|
558
558
|
|
|
559
|
-
@deprecated_alias({'rms': 'amplitude'})
|
|
559
|
+
@deprecated_alias({'rms': 'amplitude'}, removal_version='25.10')
|
|
560
560
|
class GenericSignalGenerator(SignalGenerator):
|
|
561
561
|
"""
|
|
562
562
|
Generate signals from a :class:`~acoular.base.SamplesGenerator` or derived object.
|