acoular 25.4__py3-none-any.whl → 25.10__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 +10 -10
- acoular/base.py +12 -34
- acoular/calib.py +20 -19
- acoular/configuration.py +3 -3
- acoular/demo/__init__.py +6 -1
- acoular/demo/acoular_demo.py +34 -10
- acoular/deprecation.py +10 -1
- acoular/environments.py +107 -117
- acoular/fastFuncs.py +16 -10
- acoular/fbeamform.py +300 -402
- acoular/fprocess.py +7 -33
- acoular/grids.py +228 -134
- acoular/h5cache.py +10 -4
- acoular/h5files.py +106 -9
- acoular/internal.py +4 -0
- acoular/microphones.py +22 -10
- acoular/process.py +7 -53
- acoular/sdinput.py +8 -5
- acoular/signals.py +29 -27
- acoular/sources.py +205 -335
- acoular/spectra.py +33 -43
- acoular/tbeamform.py +220 -199
- acoular/tools/helpers.py +52 -33
- acoular/tools/metrics.py +5 -10
- acoular/tprocess.py +1392 -647
- acoular/traitsviews.py +1 -3
- acoular/trajectory.py +5 -5
- acoular/version.py +4 -3
- {acoular-25.4.dist-info → acoular-25.10.dist-info}/METADATA +8 -4
- acoular-25.10.dist-info/RECORD +56 -0
- acoular-25.4.dist-info/RECORD +0 -56
- {acoular-25.4.dist-info → acoular-25.10.dist-info}/WHEEL +0 -0
- {acoular-25.4.dist-info → acoular-25.10.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.4.dist-info → acoular-25.10.dist-info}/licenses/LICENSE +0 -0
acoular/environments.py
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
"""
|
|
5
5
|
Implements acoustic environments with and without flow.
|
|
6
6
|
|
|
7
|
+
.. inheritance-diagram::
|
|
8
|
+
acoular.environments.Environment
|
|
9
|
+
:include-subclasses:
|
|
10
|
+
:top-classes:
|
|
11
|
+
acoular.environments.Environment
|
|
12
|
+
:parts: 1
|
|
13
|
+
|
|
14
|
+
.. inheritance-diagram::
|
|
15
|
+
acoular.environments.FlowField
|
|
16
|
+
:include-subclasses:
|
|
17
|
+
:top-classes:
|
|
18
|
+
acoular.environments.FlowField
|
|
19
|
+
:parts: 1
|
|
20
|
+
|
|
7
21
|
.. autosummary::
|
|
8
22
|
:toctree: generated/
|
|
9
23
|
|
|
@@ -24,35 +38,10 @@ from abc import abstractmethod
|
|
|
24
38
|
from warnings import warn
|
|
25
39
|
|
|
26
40
|
import numba as nb
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
arccos,
|
|
30
|
-
arctan2,
|
|
31
|
-
array,
|
|
32
|
-
ascontiguousarray,
|
|
33
|
-
cos,
|
|
34
|
-
cross,
|
|
35
|
-
dot,
|
|
36
|
-
empty,
|
|
37
|
-
exp,
|
|
38
|
-
float32,
|
|
39
|
-
float64,
|
|
40
|
-
hstack,
|
|
41
|
-
identity,
|
|
42
|
-
isscalar,
|
|
43
|
-
matmul,
|
|
44
|
-
newaxis,
|
|
45
|
-
pi,
|
|
46
|
-
sign,
|
|
47
|
-
sin,
|
|
48
|
-
sqrt,
|
|
49
|
-
sum, # noqa: A004
|
|
50
|
-
vstack,
|
|
51
|
-
zeros_like,
|
|
52
|
-
)
|
|
41
|
+
import numpy as np
|
|
42
|
+
import scipy.linalg as spla
|
|
53
43
|
from scipy.integrate import ode
|
|
54
44
|
from scipy.interpolate import LinearNDInterpolator
|
|
55
|
-
from scipy.linalg import norm
|
|
56
45
|
from scipy.spatial import ConvexHull
|
|
57
46
|
from traits.api import (
|
|
58
47
|
ABCHasStrictTraits,
|
|
@@ -100,7 +89,7 @@ def dist_mat(gpos, mpos): # pragma: no cover
|
|
|
100
89
|
"""
|
|
101
90
|
_, M = mpos.shape
|
|
102
91
|
_, N = gpos.shape
|
|
103
|
-
rm = empty((N, M), dtype=gpos.dtype)
|
|
92
|
+
rm = np.empty((N, M), dtype=gpos.dtype)
|
|
104
93
|
TWO = rm.dtype.type(2.0) # make sure to have a float32 or float 64 literal
|
|
105
94
|
m0 = mpos[0]
|
|
106
95
|
m1 = mpos[1]
|
|
@@ -110,7 +99,7 @@ def dist_mat(gpos, mpos): # pragma: no cover
|
|
|
110
99
|
g1 = gpos[1, n]
|
|
111
100
|
g2 = gpos[2, n]
|
|
112
101
|
for m in range(M):
|
|
113
|
-
rm[n, m] = sqrt((g0 - m0[m]) ** TWO + (g1 - m1[m]) ** TWO + (g2 - m2[m]) ** TWO)
|
|
102
|
+
rm[n, m] = np.sqrt((g0 - m0[m]) ** TWO + (g1 - m1[m]) ** TWO + (g2 - m2[m]) ** TWO)
|
|
114
103
|
return rm
|
|
115
104
|
|
|
116
105
|
|
|
@@ -137,10 +126,10 @@ def cartToCyl(x, Q=None): # noqa: N802, N803
|
|
|
137
126
|
Cylindrical representation of given `N` points in cartesian coodrinates as
|
|
138
127
|
an array of shape `(3, N)` with new coordinates :math:`(\phi, r, z)`.
|
|
139
128
|
"""
|
|
140
|
-
Q = identity(3) if Q is None else Q
|
|
141
|
-
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
142
|
-
x =
|
|
143
|
-
return array([arctan2(x[1], x[0]), sqrt(x[0] ** 2 + x[1] ** 2), x[2]])
|
|
129
|
+
Q = np.identity(3) if Q is None else Q
|
|
130
|
+
if not (Q == np.identity(3)).all(): # noqa: SIM300
|
|
131
|
+
x = Q @ x # modified position vector
|
|
132
|
+
return np.array([np.arctan2(x[1], x[0]), np.sqrt(x[0] ** 2 + x[1] ** 2), x[2]])
|
|
144
133
|
|
|
145
134
|
|
|
146
135
|
def cylToCart(x, Q=None): # noqa: N802, N803
|
|
@@ -166,10 +155,10 @@ def cylToCart(x, Q=None): # noqa: N802, N803
|
|
|
166
155
|
Cartesian representation of given `N` points in cylindrical coodrinates as
|
|
167
156
|
an array of shape `(3, N)` with coodinates :math:`(x, y, z)`.
|
|
168
157
|
"""
|
|
169
|
-
Q = identity(3) if Q is None else Q
|
|
170
|
-
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
171
|
-
x =
|
|
172
|
-
return array([x[1] * sin(x[0]), x[1] * cos(x[0]), x[2]])
|
|
158
|
+
Q = np.identity(3) if Q is None else Q
|
|
159
|
+
if not (Q == np.identity(3)).all(): # noqa: SIM300
|
|
160
|
+
x = Q @ x # modified position vector
|
|
161
|
+
return np.array([x[1] * np.sin(x[0]), x[1] * np.cos(x[0]), x[2]])
|
|
173
162
|
|
|
174
163
|
|
|
175
164
|
class Environment(HasStrictTraits):
|
|
@@ -231,12 +220,12 @@ class Environment(HasStrictTraits):
|
|
|
231
220
|
#
|
|
232
221
|
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
233
222
|
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
234
|
-
if isscalar(mpos):
|
|
235
|
-
mpos = array((0, 0, 0), dtype=float64)[:, newaxis]
|
|
236
|
-
rm = dist_mat(ascontiguousarray(gpos), ascontiguousarray(mpos))
|
|
237
|
-
# mpos = mpos[:, newaxis, :]
|
|
238
|
-
# rmv = gpos[:, :, newaxis]-mpos
|
|
239
|
-
# rm = sum(rmv*rmv, 0)**0.5
|
|
223
|
+
if np.isscalar(mpos):
|
|
224
|
+
mpos = np.array((0, 0, 0), dtype=np.float64)[:, np.newaxis]
|
|
225
|
+
rm = dist_mat(np.ascontiguousarray(gpos), np.ascontiguousarray(mpos))
|
|
226
|
+
# mpos = mpos[:, np.newaxis, :]
|
|
227
|
+
# rmv = gpos[:, :, np.newaxis]-mpos
|
|
228
|
+
# rm = np.sum(rmv*rmv, 0)**0.5
|
|
240
229
|
if rm.shape[1] == 1:
|
|
241
230
|
rm = rm[:, 0]
|
|
242
231
|
return rm
|
|
@@ -265,7 +254,7 @@ class UniformFlowEnvironment(Environment):
|
|
|
265
254
|
|
|
266
255
|
#: A unit vector specifying the direction of the flow in 3D Cartesian coordinates.
|
|
267
256
|
#: Default is ``(1.0, 0, 0)``, which corresponds to flow in the x-direction.
|
|
268
|
-
fdv = CArray(dtype=float64, shape=(3,), value=array((1.0, 0, 0)), desc='flow direction')
|
|
257
|
+
fdv = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0, 0)), desc='flow direction')
|
|
269
258
|
|
|
270
259
|
#: A unique identifier based on the environment properties. (read-only)
|
|
271
260
|
digest = Property(
|
|
@@ -301,14 +290,14 @@ class UniformFlowEnvironment(Environment):
|
|
|
301
290
|
#
|
|
302
291
|
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
303
292
|
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
304
|
-
if isscalar(mpos):
|
|
305
|
-
mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
|
|
306
|
-
fdv = self.fdv / sqrt((self.fdv * self.fdv).sum())
|
|
307
|
-
mpos = mpos[:, newaxis, :]
|
|
308
|
-
rmv = gpos[:, :, newaxis] - mpos
|
|
309
|
-
rm = sqrt(sum(rmv * rmv, 0))
|
|
310
|
-
macostheta = (self.ma * sum(rmv.reshape((3, -1)) * fdv[:, newaxis], 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
311
|
-
rm *= 1 / (-macostheta + sqrt(macostheta * macostheta - self.ma * self.ma + 1))
|
|
293
|
+
if np.isscalar(mpos):
|
|
294
|
+
mpos = np.array((0, 0, 0), dtype=np.float32)[:, np.newaxis]
|
|
295
|
+
fdv = self.fdv / np.sqrt((self.fdv * self.fdv).sum())
|
|
296
|
+
mpos = mpos[:, np.newaxis, :]
|
|
297
|
+
rmv = gpos[:, :, np.newaxis] - mpos
|
|
298
|
+
rm = np.sqrt(np.sum(rmv * rmv, 0))
|
|
299
|
+
macostheta = (self.ma * np.sum(rmv.reshape((3, -1)) * fdv[:, np.newaxis], 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
300
|
+
rm *= 1 / (-macostheta + np.sqrt(macostheta * macostheta - self.ma * self.ma + 1))
|
|
312
301
|
if rm.shape[1] == 1:
|
|
313
302
|
rm = rm[:, 0]
|
|
314
303
|
return rm
|
|
@@ -358,14 +347,14 @@ class SlotJet(FlowField):
|
|
|
358
347
|
v0 = Float(0.0, desc='exit velocity')
|
|
359
348
|
|
|
360
349
|
#: The location of the slot nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
361
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
350
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
362
351
|
|
|
363
352
|
#: Unit vector representing the flow direction. Default is ``(1.0, 0.0, 0.0)``.
|
|
364
|
-
flow = CArray(dtype=float64, shape=(3,), value=array((1.0, 0.0, 0.0)), desc='flow direction')
|
|
353
|
+
flow = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0.0, 0.0)), desc='flow direction')
|
|
365
354
|
|
|
366
355
|
#: Unit vector parallel to the slot center plane, used to define the slot orientation.
|
|
367
356
|
#: Default is ``(0.0, 1.0, 0.0)``.
|
|
368
|
-
plane = CArray(dtype=float64, shape=(3,), value=array((0.0, 1.0, 0.0)), desc='slot center line direction')
|
|
357
|
+
plane = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 1.0, 0.0)), desc='slot center line direction')
|
|
369
358
|
|
|
370
359
|
#: Width of the slot (slot diameter). Default is ``0.2``.
|
|
371
360
|
B = Float(0.2, desc='nozzle diameter')
|
|
@@ -415,18 +404,18 @@ class SlotJet(FlowField):
|
|
|
415
404
|
with respect to the spatial coordinates.
|
|
416
405
|
"""
|
|
417
406
|
# normalize
|
|
418
|
-
flow = self.flow / norm(self.flow)
|
|
419
|
-
plane = self.plane / norm(self.plane)
|
|
407
|
+
flow = self.flow / spla.norm(self.flow)
|
|
408
|
+
plane = self.plane / spla.norm(self.plane)
|
|
420
409
|
# additional axes of global coordinate system
|
|
421
|
-
yy = -cross(flow, plane)
|
|
422
|
-
zz = cross(flow, yy)
|
|
410
|
+
yy = -np.cross(flow, plane)
|
|
411
|
+
zz = np.cross(flow, yy)
|
|
423
412
|
# distance from slot exit plane
|
|
424
413
|
xx1 = xx - self.origin
|
|
425
414
|
# local coordinate system
|
|
426
|
-
x = dot(flow, xx1)
|
|
427
|
-
y = dot(yy, xx1)
|
|
415
|
+
x = np.dot(flow, xx1)
|
|
416
|
+
y = np.dot(yy, xx1)
|
|
428
417
|
x1 = 0.5668 / self.l * x # C1 in Albertson1950
|
|
429
|
-
h1 = abs(y) + sqrt(pi) * 0.5 * x1 - 0.5 * self.B
|
|
418
|
+
h1 = abs(y) + np.sqrt(np.pi) * 0.5 * x1 - 0.5 * self.B
|
|
430
419
|
if h1 < 0.0:
|
|
431
420
|
# core jet
|
|
432
421
|
Ux = self.v0
|
|
@@ -434,14 +423,14 @@ class SlotJet(FlowField):
|
|
|
434
423
|
Udy = 0
|
|
435
424
|
else:
|
|
436
425
|
# shear layer
|
|
437
|
-
Ux = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
|
|
438
|
-
Udx = (h1 * h1 / (x * x1 * x1) - sqrt(pi) * 0.5 * h1 / (x * x1)) * Ux
|
|
439
|
-
Udy = -sign(y) * h1 * Ux / (x1 * x1)
|
|
426
|
+
Ux = self.v0 * np.exp(-h1 * h1 / (2 * x1 * x1))
|
|
427
|
+
Udx = (h1 * h1 / (x * x1 * x1) - np.sqrt(np.pi) * 0.5 * h1 / (x * x1)) * Ux
|
|
428
|
+
Udy = -np.sign(y) * h1 * Ux / (x1 * x1)
|
|
440
429
|
# Jacobi matrix
|
|
441
|
-
dU = array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
|
|
430
|
+
dU = np.array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
|
|
442
431
|
# rotation matrix
|
|
443
|
-
R = array((flow, yy, zz)).T
|
|
444
|
-
return dot(R, array((Ux, 0, 0))), dot(dot(R, dU), R.T)
|
|
432
|
+
R = np.array((flow, yy, zz)).T
|
|
433
|
+
return np.dot(R, np.array((Ux, 0, 0))), np.dot(np.dot(R, dU), R.T)
|
|
445
434
|
|
|
446
435
|
|
|
447
436
|
class OpenJet(FlowField):
|
|
@@ -479,7 +468,7 @@ class OpenJet(FlowField):
|
|
|
479
468
|
v0 = Float(0.0, desc='exit velocity')
|
|
480
469
|
|
|
481
470
|
#: The location of the nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
482
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
471
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
483
472
|
|
|
484
473
|
#: Diameter of the nozzle. Default is ``0.2``.
|
|
485
474
|
D = Float(0.2, desc='nozzle diameter')
|
|
@@ -530,10 +519,10 @@ class OpenJet(FlowField):
|
|
|
530
519
|
to `y` and `z` are set to zero to avoid division by zero.
|
|
531
520
|
"""
|
|
532
521
|
x, y, z = xx - self.origin
|
|
533
|
-
r = sqrt(y * y + z * z)
|
|
522
|
+
r = np.sqrt(y * y + z * z)
|
|
534
523
|
x1 = 0.5022 / self.l * x # C2 in Albertson1950
|
|
535
524
|
h1 = r + x1 - 0.5 * self.D
|
|
536
|
-
U = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
|
|
525
|
+
U = self.v0 * np.exp(-h1 * h1 / (2 * x1 * x1))
|
|
537
526
|
if h1 < 0.0:
|
|
538
527
|
Udr = 0.0
|
|
539
528
|
U = self.v0
|
|
@@ -549,16 +538,15 @@ class OpenJet(FlowField):
|
|
|
549
538
|
Udx = 0
|
|
550
539
|
|
|
551
540
|
# flow field
|
|
552
|
-
v = array((U, 0.0, 0.0))
|
|
541
|
+
v = np.array((U, 0.0, 0.0))
|
|
553
542
|
# Jacobi matrix
|
|
554
|
-
dv = array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
|
|
543
|
+
dv = np.array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
|
|
555
544
|
return v, dv
|
|
556
545
|
|
|
557
546
|
|
|
558
547
|
class RotatingFlow(FlowField):
|
|
559
548
|
"""
|
|
560
|
-
Analytical approximation of a rotating flow field with
|
|
561
|
-
in z-direction.
|
|
549
|
+
Analytical approximation of a rotating flow field with velocity component in z-direction.
|
|
562
550
|
|
|
563
551
|
This class provides an analytical model for a fluid flow field with a
|
|
564
552
|
rigid-body-like rotation about the z-axis. The flow combines rotational motion
|
|
@@ -569,7 +557,7 @@ class RotatingFlow(FlowField):
|
|
|
569
557
|
- The rotation is assumed to be about the z-axis. The velocity components in the x-y plane are
|
|
570
558
|
determined by the angular velocity :attr:`omega`, while the z-component is constant
|
|
571
559
|
and set by :attr:`v0`.
|
|
572
|
-
- The angular velocity :attr:`omega` is computed as: ``omega = 2 * pi * rps``,
|
|
560
|
+
- The angular velocity :attr:`omega` is computed as: ``omega = 2 * np.pi * rps``,
|
|
573
561
|
with the :attr:`rps` given in revolutions per second (i.e. Hz).
|
|
574
562
|
|
|
575
563
|
Examples
|
|
@@ -578,7 +566,7 @@ class RotatingFlow(FlowField):
|
|
|
578
566
|
>>> import numpy as np
|
|
579
567
|
>>>
|
|
580
568
|
>>> flow = RotatingFlow(rps=1, v0=1.0)
|
|
581
|
-
>>> velocity, jacobian = flow.v(array((1.0, 1.0, 0.0)))
|
|
569
|
+
>>> velocity, jacobian = flow.v(np.array((1.0, 1.0, 0.0)))
|
|
582
570
|
>>> velocity
|
|
583
571
|
array([-6.28318531, 6.28318531, 1. ])
|
|
584
572
|
>>> jacobian
|
|
@@ -595,7 +583,8 @@ class RotatingFlow(FlowField):
|
|
|
595
583
|
|
|
596
584
|
def _get_rpm(self):
|
|
597
585
|
warn(
|
|
598
|
-
'Deprecated use of "rpm" trait
|
|
586
|
+
'Deprecated use of "rpm" trait (will be removed in version 26.01). \
|
|
587
|
+
Please use the "rps" trait instead.',
|
|
599
588
|
DeprecationWarning,
|
|
600
589
|
stacklevel=2,
|
|
601
590
|
)
|
|
@@ -603,7 +592,8 @@ class RotatingFlow(FlowField):
|
|
|
603
592
|
|
|
604
593
|
def _set_rpm(self, rpm):
|
|
605
594
|
warn(
|
|
606
|
-
'Deprecated use of "rpm" trait
|
|
595
|
+
'Deprecated use of "rpm" trait (will be removed in version 26.01). \
|
|
596
|
+
Please use the "rps" trait instead (divide rpm value by -60).',
|
|
607
597
|
DeprecationWarning,
|
|
608
598
|
stacklevel=2,
|
|
609
599
|
)
|
|
@@ -618,7 +608,7 @@ class RotatingFlow(FlowField):
|
|
|
618
608
|
|
|
619
609
|
#: The location of the center of rotation.
|
|
620
610
|
#: Default is ``(0.0, 0.0, 0.0)``.
|
|
621
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of rotation')
|
|
611
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)), desc='center of rotation')
|
|
622
612
|
|
|
623
613
|
#: A unique identifier based on the field properties. (read-only)
|
|
624
614
|
digest = Property(
|
|
@@ -633,7 +623,7 @@ class RotatingFlow(FlowField):
|
|
|
633
623
|
|
|
634
624
|
@cached_property
|
|
635
625
|
def _get_omega(self):
|
|
636
|
-
return 2 * pi * self.rps
|
|
626
|
+
return 2 * np.pi * self.rps
|
|
637
627
|
|
|
638
628
|
@cached_property
|
|
639
629
|
def _get_digest(self):
|
|
@@ -681,13 +671,13 @@ class RotatingFlow(FlowField):
|
|
|
681
671
|
W = self.v0
|
|
682
672
|
|
|
683
673
|
# flow field
|
|
684
|
-
v = array((U, V, W))
|
|
674
|
+
v = np.array((U, V, W))
|
|
685
675
|
# Jacobi matrix
|
|
686
|
-
dv = array(((0.0, omega, 0.0), (-omega, 0.0, 0.0), (0.0, 0.0, 0.0))).T
|
|
676
|
+
dv = np.array(((0.0, omega, 0.0), (-omega, 0.0, 0.0), (0.0, 0.0, 0.0))).T
|
|
687
677
|
return v, dv
|
|
688
678
|
|
|
689
679
|
|
|
690
|
-
def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
680
|
+
def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*np.pi
|
|
691
681
|
"""
|
|
692
682
|
Generate unit vectors equally distributed over a sphere or a portion of it.
|
|
693
683
|
|
|
@@ -705,7 +695,7 @@ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
|
705
695
|
The number of points to generate on the sphere.
|
|
706
696
|
|
|
707
697
|
Om : :class:`float`, optional
|
|
708
|
-
The solid angle in steradians to cover on the sphere. Default is ``2 * pi``,
|
|
698
|
+
The solid angle in steradians to cover on the sphere. Default is ``2 * np.pi``,
|
|
709
699
|
which corresponds to a hemisphere. Smaller values result in covering
|
|
710
700
|
a smaller portion of the hemisphere.
|
|
711
701
|
|
|
@@ -742,37 +732,37 @@ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
|
742
732
|
Generate 50 points over half a hemisphere with the z-axis as the center direction:
|
|
743
733
|
|
|
744
734
|
>>> import numpy as np
|
|
745
|
-
>>> points = spiral_sphere(50, Om=np.pi, b=array((0, 0, 1)))
|
|
735
|
+
>>> points = spiral_sphere(50, Om=np.pi, b=np.array((0, 0, 1)))
|
|
746
736
|
>>> points.shape
|
|
747
737
|
(3, 50)
|
|
748
738
|
|
|
749
739
|
Generate 200 points with a different direction vector:
|
|
750
740
|
|
|
751
|
-
>>> points = spiral_sphere(200, b=array((1, 0, 0)))
|
|
741
|
+
>>> points = spiral_sphere(200, b=np.array((1, 0, 0)))
|
|
752
742
|
>>> points.shape
|
|
753
743
|
(3, 200)
|
|
754
744
|
"""
|
|
755
|
-
Om = 2 * pi if Om is None else Om
|
|
756
|
-
b = array((0, 0, 1)) if b is None else b
|
|
745
|
+
Om = 2 * np.pi if Om is None else Om
|
|
746
|
+
b = np.array((0, 0, 1)) if b is None else b
|
|
757
747
|
# first produce 'equally' distributed directions in spherical coords
|
|
758
|
-
o = 4 * pi / Om
|
|
759
|
-
h = -1 + 2 * arange(N) / (N * o - 1.0)
|
|
760
|
-
theta = arccos(h)
|
|
761
|
-
phi = zeros_like(theta)
|
|
748
|
+
o = 4 * np.pi / Om
|
|
749
|
+
h = -1 + 2 * np.arange(N) / (N * o - 1.0)
|
|
750
|
+
theta = np.arccos(h)
|
|
751
|
+
phi = np.zeros_like(theta)
|
|
762
752
|
for i, hk in enumerate(h[1:]):
|
|
763
|
-
phi[i + 1] = phi[i] + 3.6 / sqrt(N * o * (1 - hk * hk)) % (2 * pi)
|
|
753
|
+
phi[i + 1] = phi[i] + 3.6 / np.sqrt(N * o * (1 - hk * hk)) % (2 * np.pi)
|
|
764
754
|
# translate to cartesian coords
|
|
765
|
-
xyz = vstack((sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)))
|
|
755
|
+
xyz = np.vstack((np.sin(theta) * np.cos(phi), np.sin(theta) * np.sin(phi), np.cos(theta)))
|
|
766
756
|
# mirror everything on a plane so that b points into the center
|
|
767
757
|
a = xyz[:, 0]
|
|
768
|
-
b = b / norm(b)
|
|
769
|
-
ab = (a - b)[:, newaxis]
|
|
770
|
-
if norm(ab) < 1e-10:
|
|
758
|
+
b = b / spla.norm(b)
|
|
759
|
+
ab = (a - b)[:, np.newaxis]
|
|
760
|
+
if spla.norm(ab) < 1e-10:
|
|
771
761
|
return xyz
|
|
772
762
|
# this is the Householder matrix for mirroring
|
|
773
|
-
H = identity(3) - dot(ab, ab.T) / dot(ab.T, a)
|
|
763
|
+
H = np.identity(3) - np.dot(ab, ab.T) / np.dot(ab.T, a)
|
|
774
764
|
# actual mirroring
|
|
775
|
-
return dot(H, xyz)
|
|
765
|
+
return np.dot(H, xyz)
|
|
776
766
|
|
|
777
767
|
|
|
778
768
|
class GeneralFlowEnvironment(Environment):
|
|
@@ -815,7 +805,7 @@ class GeneralFlowEnvironment(Environment):
|
|
|
815
805
|
|
|
816
806
|
#: The maximum solid angle (in steradians) used in the ray-tracing algorithm.
|
|
817
807
|
#: Default is :obj:`numpy.pi`.
|
|
818
|
-
Om = Float(pi, desc='maximum solid angle')
|
|
808
|
+
Om = Float(np.pi, desc='maximum solid angle')
|
|
819
809
|
|
|
820
810
|
#: A unique identifier based on the environment properties. (read-only)
|
|
821
811
|
digest = Property(
|
|
@@ -833,10 +823,10 @@ class GeneralFlowEnvironment(Environment):
|
|
|
833
823
|
def _r(self, gpos, mpos=0.0):
|
|
834
824
|
c = self.c
|
|
835
825
|
|
|
836
|
-
if isscalar(mpos):
|
|
837
|
-
mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
|
|
826
|
+
if np.isscalar(mpos):
|
|
827
|
+
mpos = np.array((0, 0, 0), dtype=np.float32)[:, np.newaxis]
|
|
838
828
|
|
|
839
|
-
gt = empty((gpos.shape[-1], mpos.shape[-1]))
|
|
829
|
+
gt = np.empty((gpos.shape[-1], mpos.shape[-1]))
|
|
840
830
|
for micnum, x0 in enumerate(mpos.T):
|
|
841
831
|
key = x0.tobytes() # make array hashable
|
|
842
832
|
try:
|
|
@@ -887,16 +877,16 @@ class GeneralFlowEnvironment(Environment):
|
|
|
887
877
|
x = y[0:3]
|
|
888
878
|
s = y[3:6]
|
|
889
879
|
vv, dv = v(x)
|
|
890
|
-
sa = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
|
|
891
|
-
x = empty(6)
|
|
880
|
+
sa = np.sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
|
|
881
|
+
x = np.empty(6)
|
|
892
882
|
x[0:3] = c * s / sa - vv # time reversal
|
|
893
|
-
x[3:6] = dot(s, -dv.T) # time reversal
|
|
883
|
+
x[3:6] = np.dot(s, -dv.T) # time reversal
|
|
894
884
|
return x
|
|
895
885
|
|
|
896
886
|
# integration along a single ray
|
|
897
887
|
def fr(x0, n0, rmax, dt, v, xyz, t):
|
|
898
|
-
s0 = n0 / (c + dot(v(x0)[0], n0))
|
|
899
|
-
y0 = hstack((x0, s0))
|
|
888
|
+
s0 = n0 / (c + np.dot(v(x0)[0], n0))
|
|
889
|
+
y0 = np.hstack((x0, s0))
|
|
900
890
|
oo = ode(f1)
|
|
901
891
|
oo.set_f_params(v)
|
|
902
892
|
oo.set_integrator(
|
|
@@ -908,18 +898,18 @@ class GeneralFlowEnvironment(Environment):
|
|
|
908
898
|
while oo.successful():
|
|
909
899
|
xyz.append(oo.y[0:3])
|
|
910
900
|
t.append(oo.t)
|
|
911
|
-
if norm(oo.y[0:3] - x0) > rmax:
|
|
901
|
+
if spla.norm(oo.y[0:3] - x0) > rmax:
|
|
912
902
|
break
|
|
913
903
|
oo.integrate(oo.t + dt)
|
|
914
904
|
|
|
915
905
|
gs2 = roi.shape[-1]
|
|
916
906
|
vv = self.ff.v
|
|
917
|
-
NN = int(sqrt(self.N))
|
|
907
|
+
NN = int(np.sqrt(self.N))
|
|
918
908
|
xe = roi.mean(1) # center of grid
|
|
919
|
-
r = x0[:, newaxis] - roi
|
|
920
|
-
rmax = sqrt((r * r).sum(0).max()) # maximum distance
|
|
909
|
+
r = x0[:, np.newaxis] - roi
|
|
910
|
+
rmax = np.sqrt((r * r).sum(0).max()) # maximum distance
|
|
921
911
|
nv = spiral_sphere(self.N, self.Om, b=xe - x0)
|
|
922
|
-
rstep = rmax / sqrt(self.N)
|
|
912
|
+
rstep = rmax / np.sqrt(self.N)
|
|
923
913
|
rmax += rstep
|
|
924
914
|
tstep = rstep / c
|
|
925
915
|
xyz = []
|
|
@@ -929,13 +919,13 @@ class GeneralFlowEnvironment(Environment):
|
|
|
929
919
|
fr(x0, n0, rmax, tstep, vv, xyz, t)
|
|
930
920
|
if i and i % NN == 0:
|
|
931
921
|
if not lastind:
|
|
932
|
-
dd = ConvexHull(vstack((roi.T, xyz)), incremental=True)
|
|
922
|
+
dd = ConvexHull(np.vstack((roi.T, xyz)), incremental=True)
|
|
933
923
|
else:
|
|
934
924
|
dd.add_points(xyz[lastind:], restart=True)
|
|
935
925
|
lastind = len(xyz)
|
|
936
926
|
# ConvexHull includes grid if no grid points on hull
|
|
937
927
|
if dd.simplices.min() >= gs2:
|
|
938
928
|
break
|
|
939
|
-
xyz = array(xyz)
|
|
940
|
-
t = array(t)
|
|
929
|
+
xyz = np.array(xyz)
|
|
930
|
+
t = np.array(t)
|
|
941
931
|
return LinearNDInterpolator(xyz, t)
|
acoular/fastFuncs.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# ------------------------------------------------------------------------------
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
|
-
"""Contains all
|
|
5
|
-
computational costs. All functionalities are optimized via NUMBA.
|
|
6
|
-
"""
|
|
4
|
+
"""Contains all computationally expensive operations and accelerates them with NUMBA."""
|
|
7
5
|
|
|
8
6
|
import numba as nb
|
|
9
7
|
import numpy as np
|
|
@@ -27,7 +25,8 @@ FAST_OPTION = True # fastmath options
|
|
|
27
25
|
)
|
|
28
26
|
def calcCSM(csm, SpecAllMics):
|
|
29
27
|
"""Adds a given spectrum to the Cross-Spectral-Matrix (CSM).
|
|
30
|
-
|
|
28
|
+
|
|
29
|
+
Here, only the upper triangular matrix of the CSM is calculated. After
|
|
31
30
|
averaging over the various ensembles, the whole CSM is created via complex
|
|
32
31
|
conjugation transposing. This happens outside
|
|
33
32
|
(in :class:`PowerSpectra<acoular.spectra.PowerSpectra>`).
|
|
@@ -56,9 +55,11 @@ def calcCSM(csm, SpecAllMics):
|
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
def beamformerFreq(steerVecType, boolRemovedDiagOfCSM, normFactor, inputTupleSteer, inputTupleCsm):
|
|
59
|
-
r"""
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
r"""
|
|
59
|
+
Conventional beamformer in frequency domain.
|
|
60
|
+
|
|
61
|
+
Use either a predefined steering vector formulation (see Sarradj 2012) or pass your own steering
|
|
62
|
+
vector.
|
|
62
63
|
|
|
63
64
|
Parameters
|
|
64
65
|
----------
|
|
@@ -545,8 +546,11 @@ def _freqBeamformer_EigValProb_SpecificSteerVec_CsmRemovedDiag(
|
|
|
545
546
|
|
|
546
547
|
# %% Point - Spread - Function
|
|
547
548
|
def calcPointSpreadFunction(steerVecType, distGridToArrayCenter, distGridToAllMics, waveNumber, indSource, dtype):
|
|
548
|
-
r"""
|
|
549
|
-
|
|
549
|
+
r"""
|
|
550
|
+
Calculates the Point-Spread-Functions.
|
|
551
|
+
|
|
552
|
+
Use either a predefined steering vector formulation (see :ref:`Sarradj, 2012<Sarradj2012>`) or
|
|
553
|
+
pass it your own steering vector.
|
|
550
554
|
|
|
551
555
|
Parameters
|
|
552
556
|
----------
|
|
@@ -789,7 +793,9 @@ def _psf_Formulation4AkaTrueLocation(
|
|
|
789
793
|
fastmath=FAST_OPTION,
|
|
790
794
|
)
|
|
791
795
|
def damasSolverGaussSeidel(A, dirtyMap, nIterations, relax, damasSolution):
|
|
792
|
-
"""
|
|
796
|
+
"""
|
|
797
|
+
Solves the DAMAS inverse problem via modified gauss seidel.
|
|
798
|
+
|
|
793
799
|
This is the original formulation from :ref:`Brooks and Humphreys, 2006<BrooksHumphreys2006>`.
|
|
794
800
|
|
|
795
801
|
Parameters
|