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/signals.py
CHANGED
|
@@ -67,7 +67,7 @@ class SignalGenerator(ABCHasStrictTraits):
|
|
|
67
67
|
"""
|
|
68
68
|
|
|
69
69
|
#: Sampling frequency of the signal in Hz. Default is ``1.0``.
|
|
70
|
-
sample_freq = Float(1.0
|
|
70
|
+
sample_freq = Float(1.0)
|
|
71
71
|
|
|
72
72
|
#: The number of samples to generate for the signal.
|
|
73
73
|
num_samples = CInt
|
|
@@ -141,10 +141,10 @@ class PeriodicSignalGenerator(SignalGenerator):
|
|
|
141
141
|
"""
|
|
142
142
|
|
|
143
143
|
#: The frequency of the signal. Default is ``1000.0``.
|
|
144
|
-
freq = Float(1000.0
|
|
144
|
+
freq = Float(1000.0)
|
|
145
145
|
|
|
146
146
|
#: The phase of the signal (in radians). Default is ``0.0``.
|
|
147
|
-
phase = Float(0.0
|
|
147
|
+
phase = Float(0.0)
|
|
148
148
|
|
|
149
149
|
#: The amplitude of the signal. Default is ``1.0``.
|
|
150
150
|
amplitude = Float(1.0)
|
|
@@ -174,18 +174,18 @@ class NoiseGenerator(SignalGenerator):
|
|
|
174
174
|
See Also
|
|
175
175
|
--------
|
|
176
176
|
:class:`~acoular.signals.PNoiseGenerator` : For pink noise generation.
|
|
177
|
-
:class:`~acoular.signals.WNoiseGenerator` : For
|
|
177
|
+
:class:`~acoular.signals.WNoiseGenerator` : For white noise generation.
|
|
178
178
|
:class:`~acoular.sources.UncorrelatedNoiseSource` : For per-channel noise generation.
|
|
179
179
|
"""
|
|
180
180
|
|
|
181
181
|
#: Root mean square (RMS) amplitude of the signal. For a point source,
|
|
182
182
|
#: this corresponds to the RMS amplitude at a distance of 1 meter. Default is ``1.0``.
|
|
183
|
-
rms = Float(1.0
|
|
183
|
+
rms = Float(1.0)
|
|
184
184
|
|
|
185
185
|
#: Seed for random number generator. Default is ``0``.
|
|
186
186
|
#: This parameter should be set differently for different instances
|
|
187
187
|
#: to guarantee statistically independent (non-correlated) outputs.
|
|
188
|
-
seed = Int(0
|
|
188
|
+
seed = Int(0)
|
|
189
189
|
|
|
190
190
|
#: Internal identifier based on generator properties. (read-only)
|
|
191
191
|
digest = Property(depends_on=['rms', 'seed', 'sample_freq', 'num_samples'])
|
|
@@ -243,7 +243,7 @@ class WNoiseGenerator(NoiseGenerator):
|
|
|
243
243
|
array([False, False, False])
|
|
244
244
|
"""
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
#: A unique identifier for the generator, based on its properties. (read-only)
|
|
247
247
|
digest = Property(depends_on=['rms', 'seed', 'sample_freq', 'num_samples'])
|
|
248
248
|
|
|
249
249
|
@cached_property
|
|
@@ -294,7 +294,7 @@ class PNoiseGenerator(NoiseGenerator):
|
|
|
294
294
|
#: of the :math:`1/f` spectrum at low frequencies but increase computation time. The maximum
|
|
295
295
|
#: allowable value depends on the :attr:`number of samples<SignalGenerator.num_samples>`.
|
|
296
296
|
#: Default is ``16``.
|
|
297
|
-
depth = Int(16
|
|
297
|
+
depth = Int(16)
|
|
298
298
|
|
|
299
299
|
#: A unique checksum identifier based on the object properties. (read-only)
|
|
300
300
|
digest = Property(depends_on=['rms', 'seed', 'sample_freq', 'num_samples', 'depth'])
|
|
@@ -402,11 +402,11 @@ class FiltWNoiseGenerator(WNoiseGenerator):
|
|
|
402
402
|
|
|
403
403
|
#: A :class:`numpy.ndarray` of autoregressive coefficients (denominator). Default is ``[]``,
|
|
404
404
|
#: which results in no AR filtering (i.e., all-pole filter is ``[1.0]``).
|
|
405
|
-
ar = CArray(value=np.array([]), dtype=float
|
|
405
|
+
ar = CArray(value=np.array([]), dtype=float)
|
|
406
406
|
|
|
407
407
|
#: A :class:`numpy.ndarray` of moving-average coefficients (numerator). Default is ``[]``,
|
|
408
408
|
#: which results in no MA filtering (i.e., all-zero filter is ``[1.0]``).
|
|
409
|
-
ma = CArray(value=np.array([]), dtype=float
|
|
409
|
+
ma = CArray(value=np.array([]), dtype=float)
|
|
410
410
|
|
|
411
411
|
#: A unique checksum identifier based on the object properties. (read-only)
|
|
412
412
|
digest = Property(depends_on=['rms', 'seed', 'sample_freq', 'num_samples', 'ar', 'ma'])
|
acoular/sources.py
CHANGED
|
@@ -40,7 +40,7 @@ import numba as nb
|
|
|
40
40
|
import numpy as np
|
|
41
41
|
import scipy.linalg as spla
|
|
42
42
|
from numpy.fft import fft, ifft
|
|
43
|
-
from scipy.special import
|
|
43
|
+
from scipy.special import sph_harm_y, spherical_jn, spherical_yn
|
|
44
44
|
from traits.api import (
|
|
45
45
|
Any,
|
|
46
46
|
Bool,
|
|
@@ -258,13 +258,13 @@ def get_modes(lOrder, direction, mpos, sourceposition=None): # noqa: N803
|
|
|
258
258
|
--------
|
|
259
259
|
:func:`get_radiation_angles` :
|
|
260
260
|
Computes azimuth and elevation angles between microphones and the source.
|
|
261
|
-
:obj:`scipy.special.
|
|
261
|
+
:obj:`scipy.special.sph_harm_y` : Computes spherical harmonic values.
|
|
262
262
|
|
|
263
263
|
Notes
|
|
264
264
|
-----
|
|
265
265
|
- The azimuth (``azi``) and elevation (``ele``) angles between the microphones and the source
|
|
266
266
|
are calculated using the :func:`get_radiation_angles` function.
|
|
267
|
-
- Spherical harmonics (``
|
|
267
|
+
- Spherical harmonics (``sph_harm_y``) are computed for each mode ``(l, m)``, where ``l`` is the
|
|
268
268
|
degree (ranging from ``0`` to ``lOrder``) and ``m`` is the order
|
|
269
269
|
(ranging from ``-l`` to ``+l``).
|
|
270
270
|
- For negative orders (`m < 0`), the conjugate of the spherical harmonic is computed and scaled
|
|
@@ -290,7 +290,7 @@ def get_modes(lOrder, direction, mpos, sourceposition=None): # noqa: N803
|
|
|
290
290
|
i = 0
|
|
291
291
|
for lidx in range(lOrder + 1):
|
|
292
292
|
for m in range(-lidx, lidx + 1):
|
|
293
|
-
modes[:, i] =
|
|
293
|
+
modes[:, i] = sph_harm_y(m, lidx, ele, azi)
|
|
294
294
|
if m < 0:
|
|
295
295
|
modes[:, i] = modes[:, i].conj() * 1j
|
|
296
296
|
i += 1
|
|
@@ -347,28 +347,28 @@ class TimeSamples(SamplesGenerator):
|
|
|
347
347
|
"""
|
|
348
348
|
|
|
349
349
|
#: Full path to the ``.h5`` file containing time-domain data.
|
|
350
|
-
file = Union(None, File(filter=['*.h5'], exists=True)
|
|
350
|
+
file = Union(None, File(filter=['*.h5'], exists=True))
|
|
351
351
|
|
|
352
352
|
#: Basename of the ``.h5`` file, set automatically from the :attr:`file` attribute.
|
|
353
|
-
basename = Property(depends_on=['file']
|
|
353
|
+
basename = Property(depends_on=['file'])
|
|
354
354
|
|
|
355
355
|
#: Number of input channels in the time data, set automatically based on the
|
|
356
356
|
#: :attr:`loaded data<file>` or :attr:`specified array<data>`.
|
|
357
|
-
num_channels = CInt(0
|
|
357
|
+
num_channels = CInt(0)
|
|
358
358
|
|
|
359
359
|
#: Total number of time-domain samples, set automatically based on the :attr:`loaded data<file>`
|
|
360
360
|
#: or :attr:`specified array<data>`.
|
|
361
|
-
num_samples = CInt(0
|
|
361
|
+
num_samples = CInt(0)
|
|
362
362
|
|
|
363
363
|
#: A 2D NumPy array containing the time-domain data, shape (:attr:`num_samples`,
|
|
364
364
|
#: :attr:`num_channels`).
|
|
365
|
-
data = Any(transient=True
|
|
365
|
+
data = Any(transient=True)
|
|
366
366
|
|
|
367
367
|
#: HDF5 file object.
|
|
368
368
|
h5f = Instance(H5FileBase, transient=True)
|
|
369
369
|
|
|
370
370
|
#: Metadata loaded from the HDF5 file, if available.
|
|
371
|
-
metadata = Dict(
|
|
371
|
+
metadata = Dict()
|
|
372
372
|
|
|
373
373
|
# Checksum over first data entries of all channels
|
|
374
374
|
_datachecksum = Property(depends_on=['data'])
|
|
@@ -516,35 +516,31 @@ class MaskedTimeSamples(TimeSamples):
|
|
|
516
516
|
"""
|
|
517
517
|
|
|
518
518
|
#: Index of the first sample to be considered valid. Default is ``0``.
|
|
519
|
-
start = CInt(0
|
|
519
|
+
start = CInt(0)
|
|
520
520
|
|
|
521
521
|
#: Index of the last sample to be considered valid. If ``None``, all remaining samples from the
|
|
522
522
|
#: :attr:`start` index onward are considered valid. Default is ``None``.
|
|
523
|
-
stop = Union(None, CInt
|
|
523
|
+
stop = Union(None, CInt)
|
|
524
524
|
|
|
525
525
|
#: List of channel indices to be excluded from processing. Default is ``[]``.
|
|
526
|
-
invalid_channels = List(int
|
|
526
|
+
invalid_channels = List(int)
|
|
527
527
|
|
|
528
528
|
#: A mask or index array representing valid channels. Automatically updated based on the
|
|
529
529
|
#: :attr:`invalid_channels` and :attr:`num_channels_total` attributes.
|
|
530
|
-
channels = Property(depends_on=['invalid_channels', 'num_channels_total']
|
|
530
|
+
channels = Property(depends_on=['invalid_channels', 'num_channels_total'])
|
|
531
531
|
|
|
532
532
|
#: Total number of input channels, including invalid channels. (read-only).
|
|
533
|
-
num_channels_total = CInt(0
|
|
533
|
+
num_channels_total = CInt(0)
|
|
534
534
|
|
|
535
535
|
#: Total number of samples, including invalid samples. (read-only).
|
|
536
|
-
num_samples_total = CInt(0
|
|
536
|
+
num_samples_total = CInt(0)
|
|
537
537
|
|
|
538
538
|
#: Number of valid input channels after excluding :attr:`invalid_channels`. (read-only)
|
|
539
|
-
num_channels = Property(
|
|
540
|
-
depends_on=['invalid_channels', 'num_channels_total'], desc='number of valid input channels'
|
|
541
|
-
)
|
|
539
|
+
num_channels = Property(depends_on=['invalid_channels', 'num_channels_total'])
|
|
542
540
|
|
|
543
541
|
#: Number of valid time-domain samples, based on :attr:`start` and :attr:`stop` indices.
|
|
544
542
|
#: (read-only)
|
|
545
|
-
num_samples = Property(
|
|
546
|
-
depends_on=['start', 'stop', 'num_samples_total'], desc='number of valid samples per channel'
|
|
547
|
-
)
|
|
543
|
+
num_samples = Property(depends_on=['start', 'stop', 'num_samples_total'])
|
|
548
544
|
|
|
549
545
|
#: A unique identifier for the samples, based on its properties. (read-only)
|
|
550
546
|
digest = Property(depends_on=['basename', 'start', 'stop', 'invalid_channels', '_datachecksum'])
|
|
@@ -724,18 +720,26 @@ class PointSource(SamplesGenerator):
|
|
|
724
720
|
#: Instance of the :class:`~acoular.signals.SignalGenerator` class defining the emitted signal.
|
|
725
721
|
signal = Instance(SignalGenerator)
|
|
726
722
|
|
|
727
|
-
#: Coordinates ``(x, y, z)`` of the source
|
|
728
|
-
|
|
729
|
-
|
|
723
|
+
#: Coordinates ``(x, y, z)`` of the source. Default is ``np.array([[0.0], [0.0], [1.0]])``.
|
|
724
|
+
loc = Property(CArray, desc='source location')
|
|
725
|
+
|
|
726
|
+
_loc = CArray(shape=(3, 1), value=np.array([[0.0], [0.0], [1.0]]), dtype=float)
|
|
727
|
+
|
|
728
|
+
def _get_loc(self):
|
|
729
|
+
return self._loc
|
|
730
|
+
|
|
731
|
+
def _set_loc(self, value):
|
|
732
|
+
value = np.asarray(value, dtype=float).reshape((3, 1))
|
|
733
|
+
self._loc = value
|
|
730
734
|
|
|
731
735
|
#: Number of output channels, automatically set based on the :attr:`microphone geometry<mics>`.
|
|
732
736
|
num_channels = Delegate('mics', 'num_mics')
|
|
733
737
|
|
|
734
738
|
#: :class:`~acoular.microphones.MicGeom` object defining the positions of the microphones.
|
|
735
|
-
mics = Instance(MicGeom
|
|
739
|
+
mics = Instance(MicGeom)
|
|
736
740
|
|
|
737
741
|
def _validate_locations(self):
|
|
738
|
-
dist = self.env._r(
|
|
742
|
+
dist = self.env._r(self.loc, self.mics.pos)
|
|
739
743
|
if np.any(dist < 1e-7):
|
|
740
744
|
warn('Source and microphone locations are identical.', Warning, stacklevel=2)
|
|
741
745
|
|
|
@@ -745,10 +749,10 @@ class PointSource(SamplesGenerator):
|
|
|
745
749
|
env = Instance(Environment, args=())
|
|
746
750
|
|
|
747
751
|
#: Start time of the signal in seconds. Default is ``0.0``.
|
|
748
|
-
start_t = Float(0.0
|
|
752
|
+
start_t = Float(0.0)
|
|
749
753
|
|
|
750
754
|
#: Start time of data acquisition at the microphones in seconds. Default is ``0.0``.
|
|
751
|
-
start = Float(0.0
|
|
755
|
+
start = Float(0.0)
|
|
752
756
|
|
|
753
757
|
#: Behavior of the signal for negative time indices,
|
|
754
758
|
#: i.e. if (:attr:`start` ``<`` :attr:`start_t`):
|
|
@@ -757,10 +761,10 @@ class PointSource(SamplesGenerator):
|
|
|
757
761
|
#: - ``'zeros'``: Use zeros, recommended for deterministic signals.
|
|
758
762
|
#:
|
|
759
763
|
#: Default is ``'loop'``.
|
|
760
|
-
prepadding = Enum('loop', 'zeros'
|
|
764
|
+
prepadding = Enum('loop', 'zeros')
|
|
761
765
|
|
|
762
766
|
#: Internal upsampling factor for finer signal resolution. Default is ``16``.
|
|
763
|
-
up = Int(16
|
|
767
|
+
up = Int(16)
|
|
764
768
|
|
|
765
769
|
#: Total number of samples in the emitted signal, derived from the :attr:`signal` generator.
|
|
766
770
|
num_samples = Delegate('signal')
|
|
@@ -819,7 +823,7 @@ class PointSource(SamplesGenerator):
|
|
|
819
823
|
signal = self.signal.usignal(self.up)
|
|
820
824
|
out = np.empty((num, self.num_channels))
|
|
821
825
|
# distances
|
|
822
|
-
rm = self.env._r(
|
|
826
|
+
rm = self.env._r(self.loc, self.mics.pos).reshape(1, -1)
|
|
823
827
|
# emission time relative to start_t (in samples) for first sample
|
|
824
828
|
ind = (-rm / self.env.c - self.start_t + self.start) * self.sample_freq * self.up
|
|
825
829
|
|
|
@@ -869,18 +873,18 @@ class SphericalHarmonicSource(PointSource):
|
|
|
869
873
|
"""
|
|
870
874
|
|
|
871
875
|
#: Order of the spherical harmonic representation. Default is ``0``.
|
|
872
|
-
lOrder = Int(0
|
|
876
|
+
lOrder = Int(0) # noqa: N815
|
|
873
877
|
|
|
874
878
|
#: Coefficients of the spherical harmonic modes for the given :attr:`lOrder`.
|
|
875
|
-
alpha = CArray(
|
|
879
|
+
alpha = CArray()
|
|
876
880
|
|
|
877
881
|
#: Vector defining the orientation of the spherical harmonic source. Default is
|
|
878
882
|
#: ``(1.0, 0.0, 0.0)``.
|
|
879
|
-
direction = Tuple((1.0, 0.0, 0.0)
|
|
883
|
+
direction = Tuple((1.0, 0.0, 0.0))
|
|
880
884
|
|
|
881
885
|
#: Behavior of the signal for negative time indices. Currently only supports `loop`. Default is
|
|
882
886
|
#: ``'loop'``.
|
|
883
|
-
prepadding = Enum('loop'
|
|
887
|
+
prepadding = Enum('loop')
|
|
884
888
|
|
|
885
889
|
# Unique identifier for the current state of the source, based on its properties. (read-only)
|
|
886
890
|
digest = Property(
|
|
@@ -970,7 +974,7 @@ class SphericalHarmonicSource(PointSource):
|
|
|
970
974
|
|
|
971
975
|
signal = self.signal.usignal(self.up)
|
|
972
976
|
# emission time relative to start_t (in samples) for first sample
|
|
973
|
-
rm = self.env._r(
|
|
977
|
+
rm = self.env._r(self.loc, self.mics.pos)
|
|
974
978
|
ind = (-rm / self.env.c - self.start_t + self.start) * self.sample_freq + np.pi / 30
|
|
975
979
|
i = 0
|
|
976
980
|
n = self.num_samples
|
|
@@ -1008,15 +1012,15 @@ class MovingPointSource(PointSource):
|
|
|
1008
1012
|
#: Determines whether convective amplification is considered. When ``True``, the amplitude of
|
|
1009
1013
|
#: the signal is adjusted based on the relative motion between the source and microphones.
|
|
1010
1014
|
#: Default is ``False``.
|
|
1011
|
-
conv_amp = Bool(False
|
|
1015
|
+
conv_amp = Bool(False)
|
|
1012
1016
|
|
|
1013
1017
|
#: Instance of the :class:`~acoular.trajectory.Trajectory` class specifying the source's motion.
|
|
1014
1018
|
#: The trajectory defines the source's position and velocity at any given time.
|
|
1015
|
-
trajectory = Instance(Trajectory
|
|
1019
|
+
trajectory = Instance(Trajectory)
|
|
1016
1020
|
|
|
1017
1021
|
#: Behavior of the signal for negative time indices. Currently only supports ``'loop'``.
|
|
1018
1022
|
#: Default is ``'loop'``.
|
|
1019
|
-
prepadding = Enum('loop'
|
|
1023
|
+
prepadding = Enum('loop')
|
|
1020
1024
|
|
|
1021
1025
|
#: A unique identifier for the current state of the source, based on its properties. (read-only)
|
|
1022
1026
|
digest = Property(
|
|
@@ -1135,12 +1139,12 @@ class MovingPointSource(PointSource):
|
|
|
1135
1139
|
# Newton-Rhapson iteration
|
|
1136
1140
|
while abs(eps).max() > epslim and j < 100:
|
|
1137
1141
|
loc = np.array(tr.location(te.flatten())).reshape((3, num_mics, -1))
|
|
1138
|
-
rm = loc - mpos # distance vectors to microphones
|
|
1139
|
-
rm = np.sqrt((rm * rm).sum(0)) # absolute distance
|
|
1140
|
-
loc /= np.sqrt((loc * loc).sum(0)) # distance unit vector
|
|
1141
1142
|
der = np.array(tr.location(te.flatten(), der=1)).reshape((3, num_mics, -1))
|
|
1142
|
-
|
|
1143
|
-
|
|
1143
|
+
dv = mpos - loc # distance vectors from source to microphones
|
|
1144
|
+
rm = np.sqrt((dv * dv).sum(0)) # absolute distance
|
|
1145
|
+
dv /= rm # just directions from source to microphones
|
|
1146
|
+
Mr = (der * dv).sum(0) / c0 # radial Mach number
|
|
1147
|
+
eps[:] = (te + rm / c0 - t) / (1 - Mr) # discrepancy in time
|
|
1144
1148
|
te -= eps
|
|
1145
1149
|
j += 1 # iteration count
|
|
1146
1150
|
t += num / self.sample_freq
|
|
@@ -1194,11 +1198,11 @@ class PointSourceDipole(PointSource):
|
|
|
1194
1198
|
#: Default is ``(0.0, 0.0, 1.0)`` (z-axis orientation).
|
|
1195
1199
|
#:
|
|
1196
1200
|
#: **Note:** Use vectors with order of magnitude around ``1.0`` or less for good results.
|
|
1197
|
-
direction = Tuple((0.0, 0.0, 1.0)
|
|
1201
|
+
direction = Tuple((0.0, 0.0, 1.0))
|
|
1198
1202
|
|
|
1199
1203
|
#: Behavior of the signal for negative time indices. Currently only supports ``'loop'``.
|
|
1200
1204
|
#: Default is ``'loop'``.
|
|
1201
|
-
prepadding = Enum('loop'
|
|
1205
|
+
prepadding = Enum('loop')
|
|
1202
1206
|
|
|
1203
1207
|
#: A unique identifier for the current state of the source, based on its properties. (read-only)
|
|
1204
1208
|
digest = Property(
|
|
@@ -1251,7 +1255,7 @@ class PointSourceDipole(PointSource):
|
|
|
1251
1255
|
|
|
1252
1256
|
mpos = self.mics.pos
|
|
1253
1257
|
# position of the dipole as (3,1) vector
|
|
1254
|
-
loc =
|
|
1258
|
+
loc = self.loc
|
|
1255
1259
|
# direction vector from tuple
|
|
1256
1260
|
direc = np.array(self.direction, dtype=float) * 1e-5
|
|
1257
1261
|
direc_mag = np.sqrt(np.dot(direc, direc))
|
|
@@ -1348,7 +1352,7 @@ class MovingPointSourceDipole(PointSourceDipole, MovingPointSource):
|
|
|
1348
1352
|
#: A reference vector, perpendicular to the x and y-axis of moving source, defining the axis of
|
|
1349
1353
|
#: rotation for the dipole directivity. If set to ``(0, 0, 0)``, the dipole is only translated
|
|
1350
1354
|
#: along the :attr:`~MovingPointSource.trajectory` without rotation. Default is ``(0, 0, 0)``.
|
|
1351
|
-
rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0))
|
|
1355
|
+
rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0)))
|
|
1352
1356
|
|
|
1353
1357
|
@cached_property
|
|
1354
1358
|
def _get_digest(self):
|
|
@@ -1519,19 +1523,19 @@ class LineSource(PointSource):
|
|
|
1519
1523
|
"""
|
|
1520
1524
|
|
|
1521
1525
|
#: Vector to define the orientation of the line source. Default is ``(0.0, 0.0, 1.0)``.
|
|
1522
|
-
direction = Tuple((0.0, 0.0, 1.0)
|
|
1526
|
+
direction = Tuple((0.0, 0.0, 1.0))
|
|
1523
1527
|
|
|
1524
1528
|
#: Vector to define the length of the line source in meters. Default is ``1.0``.
|
|
1525
|
-
length = Float(1
|
|
1529
|
+
length = Float(1)
|
|
1526
1530
|
|
|
1527
1531
|
#: Number of monopole sources in the line source. Default is ``1``.
|
|
1528
1532
|
num_sources = Int(1)
|
|
1529
1533
|
|
|
1530
1534
|
#: Strength coefficients for each monopole source.
|
|
1531
|
-
source_strength = CArray(
|
|
1535
|
+
source_strength = CArray()
|
|
1532
1536
|
|
|
1533
1537
|
#: Coherence mode for the monopoles (``'coherent'`` or ``'incoherent'``).
|
|
1534
|
-
coherence = Enum('coherent', 'incoherent'
|
|
1538
|
+
coherence = Enum('coherent', 'incoherent')
|
|
1535
1539
|
|
|
1536
1540
|
#: A unique identifier for the current state of the source, based on its properties. (read-only)
|
|
1537
1541
|
digest = Property(
|
|
@@ -1587,7 +1591,7 @@ class LineSource(PointSource):
|
|
|
1587
1591
|
out = np.zeros((num, self.num_channels))
|
|
1588
1592
|
|
|
1589
1593
|
# distance from line start position to microphones
|
|
1590
|
-
loc =
|
|
1594
|
+
loc = self.loc
|
|
1591
1595
|
|
|
1592
1596
|
# distances from monopoles in the line to microphones
|
|
1593
1597
|
rms = np.empty((self.num_channels, self.num_sources))
|
|
@@ -1666,7 +1670,7 @@ class MovingLineSource(LineSource, MovingPointSource):
|
|
|
1666
1670
|
#: rotation for the line source directivity. If set to ``(0, 0, 0)``, the line source is only
|
|
1667
1671
|
#: translated along the :attr:`~MovingPointSource.trajectory` without rotation. Default is
|
|
1668
1672
|
#: ``(0, 0, 0)``.
|
|
1669
|
-
rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0))
|
|
1673
|
+
rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0)))
|
|
1670
1674
|
|
|
1671
1675
|
@cached_property
|
|
1672
1676
|
def _get_digest(self):
|
|
@@ -1874,12 +1878,12 @@ class UncorrelatedNoiseSource(SamplesGenerator):
|
|
|
1874
1878
|
#: Instance of a :class:`~acoular.signals.NoiseGenerator`-derived class. For example:
|
|
1875
1879
|
#: - :class:`~acoular.signals.WNoiseGenerator` for white noise.
|
|
1876
1880
|
#: - :class:`~acoular.signals.PNoiseGenerator` for pink noise.
|
|
1877
|
-
signal = Instance(NoiseGenerator
|
|
1881
|
+
signal = Instance(NoiseGenerator)
|
|
1878
1882
|
|
|
1879
1883
|
#: Array of random seed values for generating uncorrelated noise at each channel. If left empty,
|
|
1880
1884
|
#: seeds will be automatically generated as ``np.arange(self.num_channels) + signal.seed``. The
|
|
1881
1885
|
#: size of the array must match the :attr:`number of output channels<num_channels>`.
|
|
1882
|
-
seed = CArray(dtype=np.uint32
|
|
1886
|
+
seed = CArray(dtype=np.uint32)
|
|
1883
1887
|
|
|
1884
1888
|
#: Number of output channels, automatically determined by the number of microphones
|
|
1885
1889
|
#: defined in the :attr:`mics` attribute. Corresponds to the number of uncorrelated noise
|
|
@@ -1889,15 +1893,15 @@ class UncorrelatedNoiseSource(SamplesGenerator):
|
|
|
1889
1893
|
#: :class:`~acoular.microphones.MicGeom` object specifying the positions of microphones.
|
|
1890
1894
|
#: This attribute is used to define the microphone geometry and the
|
|
1891
1895
|
#: :attr:`number of channels<num_channels>`.
|
|
1892
|
-
mics = Instance(MicGeom
|
|
1896
|
+
mics = Instance(MicGeom)
|
|
1893
1897
|
|
|
1894
1898
|
#: Start time of the generated noise signal in seconds. Determines the time offset for the noise
|
|
1895
1899
|
#: output relative to the start of data acquisition. Default is ``0.0``.
|
|
1896
|
-
start_t = Float(0.0
|
|
1900
|
+
start_t = Float(0.0)
|
|
1897
1901
|
|
|
1898
1902
|
#: Start time of data acquisition at the microphones in seconds. This value determines when the
|
|
1899
1903
|
#: generated noise begins relative to the acquisition process. Default is ``0.0``.
|
|
1900
|
-
start = Float(0.0
|
|
1904
|
+
start = Float(0.0)
|
|
1901
1905
|
|
|
1902
1906
|
#: Total number of samples in the noise signal, derived from the :attr:`signal` generator.
|
|
1903
1907
|
#: This value determines the length of the output signal for all channels.
|
|
@@ -2095,7 +2099,7 @@ class SourceMixer(SamplesGenerator):
|
|
|
2095
2099
|
#: The size of the weights array must match the number of sources in :attr:`sources`.
|
|
2096
2100
|
#: For example, with two sources, ``weights = [1.0, 0.5]`` would mix the first source at
|
|
2097
2101
|
#: full amplitude and the second source at half amplitude.
|
|
2098
|
-
weights = CArray(
|
|
2102
|
+
weights = CArray()
|
|
2099
2103
|
|
|
2100
2104
|
#: Internal identifier for the combined state of all sources, used to track
|
|
2101
2105
|
#: changes in the sources for reproducibility and caching.
|
|
@@ -2253,8 +2257,7 @@ class PointSourceConvolve(PointSource):
|
|
|
2253
2257
|
(256, 4)
|
|
2254
2258
|
(256, 4)
|
|
2255
2259
|
(256, 4)
|
|
2256
|
-
(
|
|
2257
|
-
(75, 4)
|
|
2260
|
+
(232, 4)
|
|
2258
2261
|
|
|
2259
2262
|
The last block has fewer samples.
|
|
2260
2263
|
"""
|
|
@@ -2262,24 +2265,36 @@ class PointSourceConvolve(PointSource):
|
|
|
2262
2265
|
#: Convolution kernel in the time domain.
|
|
2263
2266
|
#: The array must either have one column (a single kernel applied to all channels)
|
|
2264
2267
|
#: or match the number of output channels in its second dimension.
|
|
2265
|
-
kernel = CArray(dtype=float
|
|
2268
|
+
kernel = CArray(dtype=float)
|
|
2266
2269
|
|
|
2267
2270
|
#: Start time of the signal in seconds. Default is ``0.0``.
|
|
2268
|
-
start_t = Enum(0.0
|
|
2271
|
+
start_t = Enum(0.0)
|
|
2269
2272
|
|
|
2270
2273
|
#: Start time of the data acquisition the the microphones in seconds. Default is ``0.0``.
|
|
2271
|
-
start = Enum(0.0
|
|
2274
|
+
start = Enum(0.0)
|
|
2272
2275
|
|
|
2273
2276
|
#: Behavior for negative time indices. Default is ``None``.
|
|
2274
|
-
prepadding = Enum(None
|
|
2277
|
+
prepadding = Enum(None)
|
|
2275
2278
|
|
|
2276
2279
|
#: Upsampling factor for internal use. Default is ``None``.
|
|
2277
|
-
up = Enum(None
|
|
2280
|
+
up = Enum(None)
|
|
2278
2281
|
|
|
2279
2282
|
#: Unique identifier for the current state of the source,
|
|
2280
2283
|
#: based on microphone geometry, input signal, source location, and kernel. (read-only)
|
|
2281
2284
|
digest = Property(depends_on=['mics.digest', 'signal.digest', 'loc', 'kernel'])
|
|
2282
2285
|
|
|
2286
|
+
#: Controls whether to extend the output to include the full convolution result.
|
|
2287
|
+
#:
|
|
2288
|
+
#: - If ``False`` (default): Output length is :math:`\\max(L, M)`, where :math:`L` is the
|
|
2289
|
+
#: kernel length and :math:`M` is the signal length. This mode keeps the output length
|
|
2290
|
+
#: equal to the longest input (different from NumPy's ``mode='same'``, since it does not
|
|
2291
|
+
#: pad the output).
|
|
2292
|
+
#: - If ``True``: Output length is :math:`L + M - 1`, returning the full convolution at
|
|
2293
|
+
#: each overlap point (similar to NumPy's ``mode='full'``).
|
|
2294
|
+
#:
|
|
2295
|
+
#: Default is ``False``.
|
|
2296
|
+
extend_signal = Bool(False)
|
|
2297
|
+
|
|
2283
2298
|
@cached_property
|
|
2284
2299
|
def _get_digest(self):
|
|
2285
2300
|
return digest(self)
|
|
@@ -2321,5 +2336,6 @@ class PointSourceConvolve(PointSource):
|
|
|
2321
2336
|
time_convolve = TimeConvolve(
|
|
2322
2337
|
source=source,
|
|
2323
2338
|
kernel=self.kernel,
|
|
2339
|
+
extend_signal=self.extend_signal,
|
|
2324
2340
|
)
|
|
2325
2341
|
yield from time_convolve.result(num)
|
acoular/spectra.py
CHANGED
|
@@ -85,7 +85,6 @@ class BaseSpectra(ABCHasStrictTraits):
|
|
|
85
85
|
'Blackman': np.blackman,
|
|
86
86
|
},
|
|
87
87
|
default_value='Rectangular',
|
|
88
|
-
desc='type of window for FFT',
|
|
89
88
|
)
|
|
90
89
|
|
|
91
90
|
#: Overlap factor for FFT block averaging. One of:
|
|
@@ -97,7 +96,7 @@ class BaseSpectra(ABCHasStrictTraits):
|
|
|
97
96
|
#: - ``'75%'``
|
|
98
97
|
#:
|
|
99
98
|
#: - ``'87.5%'``
|
|
100
|
-
overlap = Map({'None': 1, '50%': 2, '75%': 4, '87.5%': 8}, default_value='None'
|
|
99
|
+
overlap = Map({'None': 1, '50%': 2, '75%': 4, '87.5%': 8}, default_value='None')
|
|
101
100
|
|
|
102
101
|
#: FFT block size. Must be one of: ``128``, ``256``, ``512``, ``1024``, ... ``65536``.
|
|
103
102
|
#: Default is ``1024``.
|
|
@@ -112,11 +111,10 @@ class BaseSpectra(ABCHasStrictTraits):
|
|
|
112
111
|
16384,
|
|
113
112
|
32768,
|
|
114
113
|
65536,
|
|
115
|
-
desc='number of samples per FFT block',
|
|
116
114
|
)
|
|
117
115
|
|
|
118
116
|
#: Precision of the FFT, corresponding to NumPy dtypes. Default is ``'complex128'``.
|
|
119
|
-
precision = Enum('complex128', 'complex64'
|
|
117
|
+
precision = Enum('complex128', 'complex64')
|
|
120
118
|
|
|
121
119
|
#: A unique identifier for the spectra, based on its properties. (read-only)
|
|
122
120
|
digest = Property(depends_on=['precision', 'block_size', 'window', 'overlap'])
|
|
@@ -207,19 +205,16 @@ class PowerSpectra(BaseSpectra):
|
|
|
207
205
|
#: :class:`SamplesGenerator<acoular.base.SamplesGenerator>` or a derived class.
|
|
208
206
|
source = Instance(SamplesGenerator)
|
|
209
207
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# Shadow trait, should not be set directly, for internal use.
|
|
214
|
-
_ind_high = Union(Int(-1), None, desc='index of highest frequency line')
|
|
208
|
+
_ind_low = Int(1)
|
|
209
|
+
_ind_high = Union(Int(-1), None)
|
|
215
210
|
|
|
216
211
|
#: Index of lowest frequency line to compute. Default is ``1``. Only used by objects that fetch
|
|
217
212
|
#: the CSM. PowerSpectra computes every frequency line.
|
|
218
|
-
ind_low = Property(_ind_low
|
|
213
|
+
ind_low = Property(_ind_low)
|
|
219
214
|
|
|
220
215
|
#: Index of highest frequency line to compute. Default is ``-1``
|
|
221
216
|
#: (last possible line for default :attr:`~BaseSpectra.block_size`).
|
|
222
|
-
ind_high = Property(_ind_high
|
|
217
|
+
ind_high = Property(_ind_high)
|
|
223
218
|
|
|
224
219
|
# Stores the set lower frequency, for internal use, should not be set directly.
|
|
225
220
|
_freqlc = Float(0)
|
|
@@ -233,37 +228,37 @@ class PowerSpectra(BaseSpectra):
|
|
|
233
228
|
_index_set_last = Bool(True)
|
|
234
229
|
|
|
235
230
|
#: A flag indicating whether the result should be cached in HDF5 files. Default is ``True``.
|
|
236
|
-
cached = Bool(True
|
|
231
|
+
cached = Bool(True)
|
|
237
232
|
|
|
238
233
|
#: The number of FFT blocks used for averaging. This is derived from the
|
|
239
234
|
#: :attr:`~BaseSpectra.block_size` and :attr:`~BaseSpectra.overlap` parameters. (read-only)
|
|
240
|
-
num_blocks = Property(
|
|
235
|
+
num_blocks = Property()
|
|
241
236
|
|
|
242
237
|
#: 2-element array with the lowest and highest frequency. If the higher frequency is larger than
|
|
243
238
|
#: the max frequency, the max frequency will be the upper bound.
|
|
244
|
-
freq_range = Property(
|
|
239
|
+
freq_range = Property()
|
|
245
240
|
# If set, will overwrite :attr:`_freqlc` and :attr:`_freqhc` according to the range. The
|
|
246
241
|
# freq_range interval will be the smallest discrete frequency inside the half-open interval
|
|
247
242
|
# [_freqlc, _freqhc[ and the smallest upper frequency outside of the interval.
|
|
248
243
|
|
|
249
244
|
#: The sequence of frequency indices between :attr:`ind_low` and :attr:`ind_high`. (read-only)
|
|
250
|
-
indices = Property(
|
|
245
|
+
indices = Property()
|
|
251
246
|
|
|
252
247
|
#: The name of the cache file (without the file extension) used for storing results. (read-only)
|
|
253
|
-
basename = Property(depends_on=['source.digest']
|
|
248
|
+
basename = Property(depends_on=['source.digest'])
|
|
254
249
|
|
|
255
250
|
#: The cross-spectral matrix, represented as an array of shape ``(n, m, m)`` of complex values
|
|
256
251
|
#: for ``n`` frequencies and ``m`` channels as in :attr:`~BaseSpectra.num_channels`. (read-only)
|
|
257
|
-
csm = Property(
|
|
252
|
+
csm = Property()
|
|
258
253
|
|
|
259
254
|
#: The eigenvalues of the CSM, stored as an array of shape ``(n,)`` of floats for ``n``
|
|
260
255
|
#: frequencies. (read-only)
|
|
261
|
-
eva = Property(
|
|
256
|
+
eva = Property()
|
|
262
257
|
|
|
263
258
|
#: The eigenvectors of the cross spectral matrix, stored as an array of shape ``(n, m, m)`` of
|
|
264
259
|
#: floats for ``n`` frequencies and ``m`` channels as in :attr:`~BaseSpectra.num_channels`.
|
|
265
260
|
#: (read-only)
|
|
266
|
-
eve = Property(
|
|
261
|
+
eve = Property()
|
|
267
262
|
|
|
268
263
|
#: A unique identifier for the spectra, based on its properties. (read-only)
|
|
269
264
|
digest = Property(
|
|
@@ -617,50 +612,46 @@ class PowerSpectraImport(PowerSpectra):
|
|
|
617
612
|
|
|
618
613
|
#: The cross-spectral matrix stored in an array of shape ``(n, m, m)`` of complex for ``n``
|
|
619
614
|
#: frequencies and ``m`` channels.
|
|
620
|
-
csm = Property(
|
|
615
|
+
csm = Property()
|
|
621
616
|
|
|
622
617
|
#: The frequencies included in the CSM in ascending order. Accepts list, array, or a single
|
|
623
618
|
#: float value.
|
|
624
|
-
frequencies = Union(None, CArray, Float
|
|
619
|
+
frequencies = Union(None, CArray, Float)
|
|
625
620
|
|
|
626
621
|
#: Number of time data channels, inferred from the shape of the CSM.
|
|
627
622
|
num_channels = Property(depends_on=['digest'])
|
|
628
623
|
|
|
629
624
|
#: :class:`PowerSpectraImport` does not consume time data; source is always ``None``.
|
|
630
|
-
source = Enum(None
|
|
625
|
+
source = Enum(None)
|
|
631
626
|
|
|
632
627
|
#: Sampling frequency of the signal. Default is ``None``
|
|
633
|
-
sample_freq = Enum(None
|
|
628
|
+
sample_freq = Enum(None)
|
|
634
629
|
|
|
635
630
|
#: Block size for FFT, non-functional in this class.
|
|
636
|
-
block_size = Enum(None
|
|
631
|
+
block_size = Enum(None)
|
|
637
632
|
|
|
638
633
|
#: Windowing method, non-functional in this class.
|
|
639
|
-
window = Enum(None
|
|
634
|
+
window = Enum(None)
|
|
640
635
|
|
|
641
636
|
#: Overlap between blocks, non-functional in this class.
|
|
642
|
-
overlap = Enum(None
|
|
637
|
+
overlap = Enum(None)
|
|
643
638
|
|
|
644
639
|
#: Caching capability, always disabled.
|
|
645
|
-
cached = Enum(False
|
|
640
|
+
cached = Enum(False)
|
|
646
641
|
|
|
647
642
|
#: Number of FFT blocks, always ``None``.
|
|
648
|
-
num_blocks = Enum(None
|
|
649
|
-
|
|
650
|
-
# Shadow trait, should not be set directly, for internal use.
|
|
651
|
-
_ind_low = Int(0, desc='index of lowest frequency line')
|
|
643
|
+
num_blocks = Enum(None)
|
|
652
644
|
|
|
653
|
-
|
|
654
|
-
_ind_high = Union(None, Int
|
|
645
|
+
_ind_low = Int(0)
|
|
646
|
+
_ind_high = Union(None, Int)
|
|
655
647
|
|
|
656
648
|
#: A unique identifier for the spectra, based on its properties. (read-only)
|
|
657
649
|
digest = Property(depends_on=['_csmsum'])
|
|
658
650
|
|
|
659
651
|
#: Name of the cache file without extension. (read-only)
|
|
660
|
-
basename = Property(depends_on=['digest']
|
|
652
|
+
basename = Property(depends_on=['digest'])
|
|
661
653
|
|
|
662
|
-
|
|
663
|
-
_csm = Union(None, CArray(shape=(None, None, None)), desc='cross spectral matrix')
|
|
654
|
+
_csm = Union(None, CArray(shape=(None, None, None)))
|
|
664
655
|
|
|
665
656
|
# Checksum for the CSM to trigger digest calculation, for internal use only.
|
|
666
657
|
_csmsum = Float()
|