acoular 24.10__py3-none-any.whl → 25.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/__init__.py +5 -2
- acoular/aiaa/__init__.py +12 -0
- acoular/{tools → aiaa}/aiaa.py +23 -28
- acoular/base.py +75 -55
- acoular/calib.py +129 -34
- acoular/configuration.py +11 -9
- acoular/demo/__init__.py +1 -0
- acoular/demo/acoular_demo.py +29 -16
- acoular/deprecation.py +85 -0
- acoular/environments.py +31 -19
- acoular/fastFuncs.py +90 -84
- acoular/fbeamform.py +203 -411
- acoular/fprocess.py +49 -41
- acoular/grids.py +101 -143
- acoular/h5cache.py +29 -40
- acoular/h5files.py +2 -6
- acoular/microphones.py +50 -59
- acoular/process.py +366 -59
- acoular/sdinput.py +23 -20
- acoular/signals.py +116 -109
- acoular/sources.py +201 -240
- acoular/spectra.py +53 -229
- acoular/tbeamform.py +79 -202
- acoular/tfastfuncs.py +21 -21
- acoular/tools/__init__.py +2 -8
- acoular/tools/helpers.py +216 -2
- acoular/tools/metrics.py +4 -4
- acoular/tools/utils.py +106 -200
- acoular/tprocess.py +348 -309
- acoular/traitsviews.py +10 -10
- acoular/trajectory.py +7 -10
- acoular/version.py +2 -2
- {acoular-24.10.dist-info → acoular-25.1.dist-info}/METADATA +38 -17
- acoular-25.1.dist-info/RECORD +56 -0
- {acoular-24.10.dist-info → acoular-25.1.dist-info}/WHEEL +1 -1
- acoular-24.10.dist-info/RECORD +0 -54
- {acoular-24.10.dist-info → acoular-25.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.10.dist-info → acoular-25.1.dist-info}/licenses/LICENSE +0 -0
acoular/fprocess.py
CHANGED
|
@@ -17,15 +17,18 @@ from warnings import warn
|
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
19
|
from scipy import fft
|
|
20
|
-
from traits.api import Bool, CArray, Enum, Instance, Int, Property,
|
|
20
|
+
from traits.api import Bool, CArray, Enum, Instance, Int, Property, Union, cached_property
|
|
21
21
|
|
|
22
|
+
# acoular imports
|
|
22
23
|
from .base import SamplesGenerator, SpectraGenerator, SpectraOut, TimeOut
|
|
24
|
+
from .deprecation import deprecated_alias
|
|
23
25
|
from .fastFuncs import calcCSM
|
|
24
26
|
from .internal import digest
|
|
27
|
+
from .process import SamplesBuffer
|
|
25
28
|
from .spectra import BaseSpectra
|
|
26
|
-
from .tools.utils import SamplesBuffer
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
@deprecated_alias({'numfreqs': 'num_freqs', 'numsamples': 'num_samples'}, read_only=True)
|
|
29
32
|
class RFFT(BaseSpectra, SpectraOut):
|
|
30
33
|
"""Provides the one-sided Fast Fourier Transform (FFT) for real-valued multichannel time data.
|
|
31
34
|
|
|
@@ -38,7 +41,8 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
38
41
|
source = Instance(SamplesGenerator)
|
|
39
42
|
|
|
40
43
|
#: Number of workers to use for the FFT calculation. If negative values are used,
|
|
41
|
-
#: all available logical CPUs will be considered (``scipy.fft.rfft`` implementation wraps around
|
|
44
|
+
#: all available logical CPUs will be considered (``scipy.fft.rfft`` implementation wraps around
|
|
45
|
+
#: from ``os.cpu_count()``).
|
|
42
46
|
#: Default is `None` (handled by scipy)
|
|
43
47
|
workers = Union(Int(), None, default_value=None, desc='number of workers to use')
|
|
44
48
|
|
|
@@ -46,18 +50,18 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
46
50
|
#: Default is :code:`none`.
|
|
47
51
|
#: 'energy': compensates for the energy loss due to truncation of the FFT result. The resulting
|
|
48
52
|
#: one-sided spectrum is multiplied by 2.0, except for the DC and Nyquist frequency.
|
|
49
|
-
#: 'amplitude': scales the one-sided spectrum so that the amplitude of discrete tones does not
|
|
50
|
-
#: on the block size.
|
|
53
|
+
#: 'amplitude': scales the one-sided spectrum so that the amplitude of discrete tones does not
|
|
54
|
+
#: depend on the block size.
|
|
51
55
|
scaling = Enum('none', 'energy', 'amplitude')
|
|
52
56
|
|
|
53
57
|
#: block size of the FFT. Default is 1024.
|
|
54
58
|
block_size = Property()
|
|
55
59
|
|
|
56
60
|
#: Number of frequencies in the output.
|
|
57
|
-
|
|
61
|
+
num_freqs = Property(depends_on=['_block_size'])
|
|
58
62
|
|
|
59
63
|
#: Number of snapshots in the output.
|
|
60
|
-
|
|
64
|
+
num_samples = Property(depends_on=['source.num_samples', '_block_size'])
|
|
61
65
|
|
|
62
66
|
#: 1-D array of FFT sample frequencies.
|
|
63
67
|
freqs = Property()
|
|
@@ -73,13 +77,13 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
73
77
|
return digest(self)
|
|
74
78
|
|
|
75
79
|
@cached_property
|
|
76
|
-
def
|
|
80
|
+
def _get_num_freqs(self):
|
|
77
81
|
return int(self.block_size / 2 + 1)
|
|
78
82
|
|
|
79
83
|
@cached_property
|
|
80
|
-
def
|
|
81
|
-
if self.source.
|
|
82
|
-
return int(np.floor(self.source.
|
|
84
|
+
def _get_num_samples(self):
|
|
85
|
+
if self.source.num_samples >= 0:
|
|
86
|
+
return int(np.floor(self.source.num_samples / self.block_size))
|
|
83
87
|
return -1
|
|
84
88
|
|
|
85
89
|
def _get_block_size(self):
|
|
@@ -122,7 +126,7 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
122
126
|
|
|
123
127
|
Returns
|
|
124
128
|
-------
|
|
125
|
-
Spectra block of shape (num, :attr:`
|
|
129
|
+
Spectra block of shape (num, :attr:`num_channels` * :attr:`num_freqs`).
|
|
126
130
|
The last block may be shorter than num.
|
|
127
131
|
|
|
128
132
|
"""
|
|
@@ -132,7 +136,7 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
132
136
|
elif self.scaling == 'amplitude': # compensates for the window and the energy loss
|
|
133
137
|
svalue = 1 / wind.sum()
|
|
134
138
|
wind = wind[:, np.newaxis]
|
|
135
|
-
fftdata = np.zeros((num, self.
|
|
139
|
+
fftdata = np.zeros((num, self.num_channels * self.num_freqs), dtype=self.precision)
|
|
136
140
|
j = 0
|
|
137
141
|
for i, data in enumerate(self._get_source_data()): # yields one block of time data
|
|
138
142
|
j = i % num
|
|
@@ -146,6 +150,7 @@ class RFFT(BaseSpectra, SpectraOut):
|
|
|
146
150
|
yield fftdata[: j + 1]
|
|
147
151
|
|
|
148
152
|
|
|
153
|
+
@deprecated_alias({'numsamples': 'num_samples'}, read_only=True)
|
|
149
154
|
class IRFFT(TimeOut):
|
|
150
155
|
"""Calculates the inverse Fast Fourier Transform (IFFT) for one-sided multi-channel spectra."""
|
|
151
156
|
|
|
@@ -153,16 +158,17 @@ class IRFFT(TimeOut):
|
|
|
153
158
|
source = Instance(SpectraGenerator)
|
|
154
159
|
|
|
155
160
|
#: Number of workers to use for the FFT calculation. If negative values are used,
|
|
156
|
-
#: all available logical CPUs will be considered (``scipy.fft.rfft`` implementation wraps around
|
|
161
|
+
#: all available logical CPUs will be considered (``scipy.fft.rfft`` implementation wraps around
|
|
162
|
+
#: from ``os.cpu_count()``).
|
|
157
163
|
#: Default is `None` (handled by scipy)
|
|
158
164
|
workers = Union(Int(), None, default_value=None, desc='number of workers to use')
|
|
159
165
|
|
|
160
166
|
#: The floating-number-precision of the resulting time signals, corresponding to numpy dtypes.
|
|
161
167
|
#: Default is 64 bit.
|
|
162
|
-
precision =
|
|
168
|
+
precision = Enum('float64', 'float32', desc='precision of the time signal after the ifft')
|
|
163
169
|
|
|
164
170
|
#: Number of time samples in the output.
|
|
165
|
-
|
|
171
|
+
num_samples = Property(depends_on=['source.num_samples', 'source._block_size'])
|
|
166
172
|
|
|
167
173
|
# internal time signal buffer to handle arbitrary output block sizes
|
|
168
174
|
_buffer = CArray(desc='signal buffer')
|
|
@@ -170,9 +176,9 @@ class IRFFT(TimeOut):
|
|
|
170
176
|
# internal identifier
|
|
171
177
|
digest = Property(depends_on=['source.digest', 'scaling', 'precision', '_block_size', 'window', 'overlap'])
|
|
172
178
|
|
|
173
|
-
def
|
|
174
|
-
if self.source.
|
|
175
|
-
return int(self.source.
|
|
179
|
+
def _get_num_samples(self):
|
|
180
|
+
if self.source.num_samples >= 0:
|
|
181
|
+
return int(self.source.num_samples * self.source.block_size)
|
|
176
182
|
return -1
|
|
177
183
|
|
|
178
184
|
@cached_property
|
|
@@ -186,9 +192,9 @@ class IRFFT(TimeOut):
|
|
|
186
192
|
'This is likely due to incomplete spectral data from which the inverse FFT cannot be calculated.'
|
|
187
193
|
)
|
|
188
194
|
raise ValueError(msg)
|
|
189
|
-
if (self.source.
|
|
195
|
+
if (self.source.num_freqs - 1) * 2 != self.source.block_size:
|
|
190
196
|
msg = (
|
|
191
|
-
f'Block size must be 2*(
|
|
197
|
+
f'Block size must be 2*(num_freqs-1) but is {self.source.block_size}.'
|
|
192
198
|
'This is likely due to incomplete spectral data from which the inverse FFT cannot be calculated.'
|
|
193
199
|
)
|
|
194
200
|
raise ValueError(msg)
|
|
@@ -208,7 +214,7 @@ class IRFFT(TimeOut):
|
|
|
208
214
|
Yields
|
|
209
215
|
------
|
|
210
216
|
numpy.ndarray
|
|
211
|
-
Yields blocks of shape (num,
|
|
217
|
+
Yields blocks of shape (num, num_channels).
|
|
212
218
|
"""
|
|
213
219
|
self._validate()
|
|
214
220
|
bs = self.source.block_size
|
|
@@ -219,7 +225,7 @@ class IRFFT(TimeOut):
|
|
|
219
225
|
else:
|
|
220
226
|
for spectra in self.source.result(1):
|
|
221
227
|
yield fft.irfft(
|
|
222
|
-
spectra.reshape(self.source.
|
|
228
|
+
spectra.reshape(self.source.num_freqs, self.num_channels), n=num, axis=0, workers=self.workers
|
|
223
229
|
)
|
|
224
230
|
|
|
225
231
|
|
|
@@ -237,7 +243,7 @@ class AutoPowerSpectra(SpectraOut):
|
|
|
237
243
|
single_sided = Bool(True, desc='single sided spectrum')
|
|
238
244
|
|
|
239
245
|
#: The floating-number-precision of entries, corresponding to numpy dtypes. Default is 64 bit.
|
|
240
|
-
precision =
|
|
246
|
+
precision = Enum('float64', 'float32', desc='floating-number-precision')
|
|
241
247
|
|
|
242
248
|
# internal identifier
|
|
243
249
|
digest = Property(depends_on=['source.digest', 'precision', 'scaling', 'single_sided'])
|
|
@@ -265,7 +271,7 @@ class AutoPowerSpectra(SpectraOut):
|
|
|
265
271
|
Yields
|
|
266
272
|
------
|
|
267
273
|
numpy.ndarray
|
|
268
|
-
Yields blocks of shape (num,
|
|
274
|
+
Yields blocks of shape (num, num_channels * num_freqs).
|
|
269
275
|
The last block may be shorter than num.
|
|
270
276
|
|
|
271
277
|
"""
|
|
@@ -274,38 +280,40 @@ class AutoPowerSpectra(SpectraOut):
|
|
|
274
280
|
yield ((temp * temp.conjugate()).real * scale).astype(self.precision)
|
|
275
281
|
|
|
276
282
|
|
|
283
|
+
@deprecated_alias({'numchannels': 'num_channels'}, read_only=True)
|
|
277
284
|
class CrossPowerSpectra(AutoPowerSpectra):
|
|
278
285
|
"""Calculates the complex-valued auto- and cross-power spectra.
|
|
279
286
|
|
|
280
|
-
Receives the complex-valued spectra from the source and returns the cross-spectral matrix (CSM)
|
|
281
|
-
representation (i.e. the auto- and cross-power spectra are concatenated along the
|
|
282
|
-
If :attr:`calc_mode` is 'full', the full CSM is calculated, if 'upper', only the
|
|
287
|
+
Receives the complex-valued spectra from the source and returns the cross-spectral matrix (CSM)
|
|
288
|
+
in a flattened representation (i.e. the auto- and cross-power spectra are concatenated along the
|
|
289
|
+
last axis). If :attr:`calc_mode` is 'full', the full CSM is calculated, if 'upper', only the
|
|
290
|
+
upper triangle is calculated.
|
|
283
291
|
"""
|
|
284
292
|
|
|
285
293
|
#: Data source; :class:`~acoular.base.SpectraGenerator` or derived object.
|
|
286
|
-
source =
|
|
294
|
+
source = Instance(SpectraGenerator)
|
|
287
295
|
|
|
288
296
|
#: The floating-number-precision of entries of csm, eigenvalues and
|
|
289
297
|
#: eigenvectors, corresponding to numpy dtypes. Default is 64 bit.
|
|
290
|
-
precision =
|
|
298
|
+
precision = Enum('complex128', 'complex64', desc='precision of the fft')
|
|
291
299
|
|
|
292
300
|
#: Calculation mode, either 'full' or 'upper'.
|
|
293
301
|
#: 'full' calculates the full cross-spectral matrix, 'upper' calculates
|
|
294
302
|
# only the upper triangle. Default is 'full'.
|
|
295
|
-
calc_mode =
|
|
303
|
+
calc_mode = Enum('full', 'upper', 'lower', desc='calculation mode')
|
|
296
304
|
|
|
297
305
|
#: Number of channels in output. If :attr:`calc_mode` is 'full', then
|
|
298
|
-
#: :attr:`
|
|
306
|
+
#: :attr:`num_channels` is :math:`n^2`, where :math:`n` is the number of
|
|
299
307
|
#: channels in the input. If :attr:`calc_mode` is 'upper', then
|
|
300
|
-
#: :attr:`
|
|
301
|
-
|
|
308
|
+
#: :attr:`num_channels` is :math:`n + n(n-1)/2`.
|
|
309
|
+
num_channels = Property(depends_on=['source.num_channels'])
|
|
302
310
|
|
|
303
311
|
# internal identifier
|
|
304
312
|
digest = Property(depends_on=['source.digest', 'precision', 'scaling', 'single_sided', 'calc_mode'])
|
|
305
313
|
|
|
306
314
|
@cached_property
|
|
307
|
-
def
|
|
308
|
-
n = self.source.
|
|
315
|
+
def _get_num_channels(self):
|
|
316
|
+
n = self.source.num_channels
|
|
309
317
|
return n**2 if self.calc_mode == 'full' else int(n + n * (n - 1) / 2)
|
|
310
318
|
|
|
311
319
|
@cached_property
|
|
@@ -324,11 +332,11 @@ class CrossPowerSpectra(AutoPowerSpectra):
|
|
|
324
332
|
Yields
|
|
325
333
|
------
|
|
326
334
|
numpy.ndarray
|
|
327
|
-
Yields blocks of shape (num,
|
|
335
|
+
Yields blocks of shape (num, num_channels * num_freqs).
|
|
328
336
|
"""
|
|
329
|
-
nc_src = self.source.
|
|
330
|
-
nc = self.
|
|
331
|
-
nf = self.
|
|
337
|
+
nc_src = self.source.num_channels
|
|
338
|
+
nc = self.num_channels
|
|
339
|
+
nf = self.num_freqs
|
|
332
340
|
scale = self._get_scaling_value()
|
|
333
341
|
|
|
334
342
|
csm_flat = np.zeros((num, nc * nf), dtype=self.precision)
|
|
@@ -345,7 +353,7 @@ class CrossPowerSpectra(AutoPowerSpectra):
|
|
|
345
353
|
else: # lower
|
|
346
354
|
csm_lower = csm_upper.conj().transpose(0, 2, 1)
|
|
347
355
|
csm_flat[i] = csm_lower[:, :nc].reshape(-1)
|
|
348
|
-
csm_upper[...] = 0 # calcCSM adds
|
|
356
|
+
csm_upper[...] = 0 # calcCSM adds cumulative
|
|
349
357
|
yield csm_flat[: i + 1] * scale
|
|
350
358
|
|
|
351
359
|
|