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/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, desc='sampling frequency')
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, desc='Frequency')
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, desc='Phase')
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 pink white generation.
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, desc='rms amplitude')
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, desc='random seed value')
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
- # internal identifier
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, desc='octave depth')
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, desc='autoregressive coefficients (coefficients of the denominator)')
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, desc='moving-average coefficients (coefficients of the numerator)')
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 sph_harm, spherical_jn, spherical_yn
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.sph_harm` : Computes spherical harmonic values.
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 (``sph_harm``) are computed for each mode ``(l, m)``, where ``l`` is the
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] = sph_harm(m, lidx, azi, ele)
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), desc='name of data file')
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'], desc='basename of data 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, desc='number of input channels')
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, desc='number of samples')
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, desc='the actual time data array')
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(desc='metadata contained in .h5 file')
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, desc='start of valid samples')
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, desc='stop of valid samples')
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, desc='list of invalid channels')
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'], desc='channel mask')
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, desc='total number of input channels')
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, desc='total number of samples per channel')
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 in a left-oriented system. Default is
728
- #: ``(0.0, 0.0, 1.0)``.
729
- loc = Tuple((0.0, 0.0, 1.0), desc='source location')
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, desc='microphone geometry')
739
+ mics = Instance(MicGeom)
736
740
 
737
741
  def _validate_locations(self):
738
- dist = self.env._r(np.array(self.loc).reshape((3, 1)), self.mics.pos)
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, desc='signal start time')
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, desc='sample start time')
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', desc='Behaviour for negative time indices.')
764
+ prepadding = Enum('loop', 'zeros')
761
765
 
762
766
  #: Internal upsampling factor for finer signal resolution. Default is ``16``.
763
- up = Int(16, desc='upsampling factor')
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(np.array(self.loc).reshape((3, 1)), self.mics.pos).reshape(1, -1)
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, desc='Order of spherical harmonic') # noqa: N815
876
+ lOrder = Int(0) # noqa: N815
873
877
 
874
878
  #: Coefficients of the spherical harmonic modes for the given :attr:`lOrder`.
875
- alpha = CArray(desc='coefficients of the (lOrder,) spherical harmonic mode')
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), desc='Spherical Harmonic orientation')
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', desc='Behaviour for negative time indices.')
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(np.array(self.loc).reshape((3, 1)), self.mics.pos)
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, desc='determines if convective amplification is considered')
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, desc='trajectory of the source')
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', desc='Behaviour for negative time indices.')
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
- Mr = (der * loc).sum(0) / c0 # radial Mach number
1143
- eps[:] = (te + rm / c0 - t) / (1 + Mr) # discrepancy in time
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), desc='dipole orientation and distance of the inversely phased monopoles')
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', desc='Behaviour for negative time indices.')
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 = np.array(self.loc, dtype=float).reshape((3, 1))
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)), desc='reference vector')
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), desc='Line orientation ')
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, desc='length of the line source')
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(desc='coefficients of the source strength')
1535
+ source_strength = CArray()
1532
1536
 
1533
1537
  #: Coherence mode for the monopoles (``'coherent'`` or ``'incoherent'``).
1534
- coherence = Enum('coherent', 'incoherent', desc='coherence mode')
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 = np.array(self.loc, dtype=float).reshape((3, 1))
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)), desc='reference vector')
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, desc='type of noise')
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, desc='random seed values')
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, desc='microphone geometry')
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, desc='signal start time')
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, desc='sample start time')
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(desc='channel weights')
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
- (256, 4)
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, desc='Convolution kernel.')
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, desc='signal start time')
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, desc='sample start time')
2274
+ start = Enum(0.0)
2272
2275
 
2273
2276
  #: Behavior for negative time indices. Default is ``None``.
2274
- prepadding = Enum(None, desc='Behavior for negative time indices.')
2277
+ prepadding = Enum(None)
2275
2278
 
2276
2279
  #: Upsampling factor for internal use. Default is ``None``.
2277
- up = Enum(None, desc='upsampling factor')
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', desc='overlap of FFT blocks')
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', desc='precision of the fft')
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
- # Shadow trait, should not be set directly, for internal use.
211
- _ind_low = Int(1, desc='index of lowest frequency line')
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, desc='index of lowest frequency line')
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, desc='index of lowest frequency line')
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, desc='cached flag')
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(desc='overall number of FFT blocks')
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(desc='frequency range')
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(desc='index range')
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'], desc='basename for cache file')
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(desc='cross spectral matrix')
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(desc='eigenvalues of cross spectral matrix')
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(desc='eigenvectors of cross spectral matrix')
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(desc='cross spectral matrix')
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, desc='frequencies included in the cross-spectral matrix')
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, desc='PowerSpectraImport cannot consume time data')
625
+ source = Enum(None)
631
626
 
632
627
  #: Sampling frequency of the signal. Default is ``None``
633
- sample_freq = Enum(None, desc='sampling frequency')
628
+ sample_freq = Enum(None)
634
629
 
635
630
  #: Block size for FFT, non-functional in this class.
636
- block_size = Enum(None, desc='PowerSpectraImport does not operate on blocks of time data')
631
+ block_size = Enum(None)
637
632
 
638
633
  #: Windowing method, non-functional in this class.
639
- window = Enum(None, desc='PowerSpectraImport does not perform windowing')
634
+ window = Enum(None)
640
635
 
641
636
  #: Overlap between blocks, non-functional in this class.
642
- overlap = Enum(None, desc='PowerSpectraImport does not consume time data')
637
+ overlap = Enum(None)
643
638
 
644
639
  #: Caching capability, always disabled.
645
- cached = Enum(False, desc='PowerSpectraImport has no caching capabilities')
640
+ cached = Enum(False)
646
641
 
647
642
  #: Number of FFT blocks, always ``None``.
648
- num_blocks = Enum(None, desc='PowerSpectraImport cannot determine the number of blocks')
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
- # Shadow trait, should not be set directly, for internal use.
654
- _ind_high = Union(None, Int, desc='index of highest frequency line')
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'], desc='basename for cache file')
652
+ basename = Property(depends_on=['digest'])
661
653
 
662
- # Shadow trait for storing the CSM, for internal use only.
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()