acoular 24.10__py3-none-any.whl → 25.3__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 +31 -18
- acoular/deprecation.py +85 -0
- acoular/environments.py +481 -229
- acoular/fastFuncs.py +90 -84
- acoular/fbeamform.py +203 -411
- acoular/fprocess.py +233 -123
- acoular/grids.py +793 -424
- acoular/h5cache.py +29 -40
- acoular/h5files.py +2 -6
- acoular/microphones.py +197 -74
- acoular/process.py +660 -149
- acoular/sdinput.py +23 -20
- acoular/signals.py +461 -159
- acoular/sources.py +1311 -489
- acoular/spectra.py +328 -352
- 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 +126 -53
- acoular/version.py +2 -2
- {acoular-24.10.dist-info → acoular-25.3.dist-info}/METADATA +39 -17
- acoular-25.3.dist-info/RECORD +56 -0
- {acoular-24.10.dist-info → acoular-25.3.dist-info}/WHEEL +1 -1
- acoular-24.10.dist-info/RECORD +0 -54
- {acoular-24.10.dist-info → acoular-25.3.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-24.10.dist-info → acoular-25.3.dist-info}/licenses/LICENSE +0 -0
acoular/environments.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# ------------------------------------------------------------------------------
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
|
-
"""
|
|
4
|
+
"""
|
|
5
|
+
Implements acoustic environments with and without flow.
|
|
5
6
|
|
|
6
7
|
.. autosummary::
|
|
7
8
|
:toctree: generated/
|
|
@@ -13,9 +14,15 @@
|
|
|
13
14
|
OpenJet
|
|
14
15
|
RotatingFlow
|
|
15
16
|
SlotJet
|
|
16
|
-
|
|
17
|
+
dist_mat
|
|
18
|
+
cylToCart
|
|
19
|
+
cartToCyl
|
|
20
|
+
spiral_sphere
|
|
17
21
|
"""
|
|
18
22
|
|
|
23
|
+
from abc import abstractmethod
|
|
24
|
+
from warnings import warn
|
|
25
|
+
|
|
19
26
|
import numba as nb
|
|
20
27
|
from numpy import (
|
|
21
28
|
arange,
|
|
@@ -39,7 +46,7 @@ from numpy import (
|
|
|
39
46
|
sign,
|
|
40
47
|
sin,
|
|
41
48
|
sqrt,
|
|
42
|
-
sum,
|
|
49
|
+
sum, # noqa: A004
|
|
43
50
|
vstack,
|
|
44
51
|
zeros_like,
|
|
45
52
|
)
|
|
@@ -47,7 +54,18 @@ from scipy.integrate import ode
|
|
|
47
54
|
from scipy.interpolate import LinearNDInterpolator
|
|
48
55
|
from scipy.linalg import norm
|
|
49
56
|
from scipy.spatial import ConvexHull
|
|
50
|
-
from traits.api import
|
|
57
|
+
from traits.api import (
|
|
58
|
+
ABCHasStrictTraits,
|
|
59
|
+
CArray,
|
|
60
|
+
Dict,
|
|
61
|
+
Float,
|
|
62
|
+
HasStrictTraits,
|
|
63
|
+
Instance,
|
|
64
|
+
Int,
|
|
65
|
+
Property,
|
|
66
|
+
Union,
|
|
67
|
+
cached_property,
|
|
68
|
+
)
|
|
51
69
|
|
|
52
70
|
from .internal import digest
|
|
53
71
|
|
|
@@ -56,18 +74,29 @@ f32ro = nb.types.Array(nb.types.float32, 2, 'C', readonly=True)
|
|
|
56
74
|
|
|
57
75
|
|
|
58
76
|
@nb.njit([(f64ro, f64ro), (f64ro, f32ro), (f32ro, f64ro), (f32ro, f32ro)], cache=True, fastmath=True)
|
|
59
|
-
def dist_mat(gpos, mpos):
|
|
60
|
-
"""
|
|
77
|
+
def dist_mat(gpos, mpos): # pragma: no cover
|
|
78
|
+
"""
|
|
79
|
+
Compute distance matrix. (accelerated with numba).
|
|
80
|
+
|
|
81
|
+
Given an `(3, N)` array of the locations of points in the beamforming map grid in 3D cartesian
|
|
82
|
+
coordinates and `(3, M)` array of the locations of microphones in 3D cartesian coordinates, the
|
|
83
|
+
`(N, M)` matrix of the distances between each microphone and each point in the beamforming map
|
|
84
|
+
grip.
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
gpos : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
89
|
+
The locations of `N` points in the beamforming map grid in 3D cartesian coordinates,
|
|
90
|
+
shape `(3, N)`.
|
|
91
|
+
|
|
92
|
+
mpos : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
93
|
+
The locations of `M` microphones in 3D cartesian coordinates, shape `(3, M)`.
|
|
66
94
|
|
|
67
95
|
Returns
|
|
68
96
|
-------
|
|
69
|
-
|
|
70
|
-
|
|
97
|
+
:class:`numpy.ndarray` of :class:`floats<float>`
|
|
98
|
+
Matrix of the distances between each microphone and each point in the beamforming map grid,
|
|
99
|
+
shape `(N, M)`.
|
|
71
100
|
"""
|
|
72
101
|
_, M = mpos.shape
|
|
73
102
|
_, N = gpos.shape
|
|
@@ -86,24 +115,27 @@ def dist_mat(gpos, mpos):
|
|
|
86
115
|
|
|
87
116
|
|
|
88
117
|
def cartToCyl(x, Q=None): # noqa: N802, N803
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
r"""
|
|
119
|
+
Return cylindrical coordinate representation of an input array in cartesian coordinate.
|
|
120
|
+
|
|
121
|
+
Return the cylindrical coordinate representation of an input position which was before
|
|
122
|
+
transformed into a modified cartesian coordinate, which has flow into positive z direction.
|
|
92
123
|
|
|
93
124
|
Parameters
|
|
94
125
|
----------
|
|
95
|
-
x : float
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
126
|
+
x : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
127
|
+
Cartesian coordinates of `N` points, shape `(3, N)`.
|
|
128
|
+
|
|
129
|
+
Q : :class:`numpy.ndarray` of :class:`floats<float>`, optional
|
|
130
|
+
Orthogonal transformation matrix, shape `(3, 3)`. If provided, the positional vectors are
|
|
131
|
+
transformed via ``new_x = Q * x``, before transforming those modified coordinates into
|
|
132
|
+
cylindrical ones. Default is the identity matrix.
|
|
101
133
|
|
|
102
134
|
Returns
|
|
103
135
|
-------
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
136
|
+
:class:`numpy.ndarray` of :class:`floats<float>`
|
|
137
|
+
Cylindrical representation of given `N` points in cartesian coodrinates as
|
|
138
|
+
an array of shape `(3, N)` with new coordinates :math:`(\phi, r, z)`.
|
|
107
139
|
"""
|
|
108
140
|
Q = identity(3) if Q is None else Q
|
|
109
141
|
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
@@ -112,27 +144,27 @@ def cartToCyl(x, Q=None): # noqa: N802, N803
|
|
|
112
144
|
|
|
113
145
|
|
|
114
146
|
def cylToCart(x, Q=None): # noqa: N802, N803
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
|
|
147
|
+
r"""
|
|
148
|
+
Return cartesian coordinate representation of an input array in cylindrical coordinate.
|
|
149
|
+
|
|
150
|
+
Return the cartesian coordinate representation of a input position which was before transformed
|
|
151
|
+
into a cylindrical coordinate, which has flow into positive z direction.
|
|
118
152
|
|
|
119
153
|
Parameters
|
|
120
154
|
----------
|
|
121
|
-
x : float
|
|
122
|
-
|
|
123
|
-
cartesian coordinates of n points
|
|
124
|
-
|
|
125
|
-
Q : float[3,3]
|
|
126
|
-
Orthogonal transformation matrix. If provided, the pos vectors are
|
|
127
|
-
transformed via posiMod = Q * x, before transforming those modified
|
|
128
|
-
coordinates into cylindrical ones. Default is identity matrix.
|
|
155
|
+
x : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
156
|
+
Cylindrical coordinates of `N` points, shape `(3, N)`.
|
|
129
157
|
|
|
158
|
+
Q : :class:`numpy.ndarray` of :class:`floats<float>`, optional
|
|
159
|
+
Orthogonal transformation matrix, shape `(3, 3)`. If provided, the positional vectors are
|
|
160
|
+
transformed via ``new_x = Q * x`` before transforming those modified coordinates into
|
|
161
|
+
cartesian ones. Default is the identity matrix.
|
|
130
162
|
|
|
131
163
|
Returns
|
|
132
164
|
-------
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
165
|
+
:class:`numpy.ndarray` of :class:`floats<float>`
|
|
166
|
+
Cartesian representation of given `N` points in cylindrical coodrinates as
|
|
167
|
+
an array of shape `(3, N)` with coodinates :math:`(x, y, z)`.
|
|
136
168
|
"""
|
|
137
169
|
Q = identity(3) if Q is None else Q
|
|
138
170
|
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
@@ -140,48 +172,65 @@ def cylToCart(x, Q=None): # noqa: N802, N803
|
|
|
140
172
|
return array([x[1] * sin(x[0]), x[1] * cos(x[0]), x[2]])
|
|
141
173
|
|
|
142
174
|
|
|
143
|
-
class Environment(
|
|
144
|
-
"""
|
|
175
|
+
class Environment(HasStrictTraits):
|
|
176
|
+
"""
|
|
177
|
+
A simple acoustic environment without flow.
|
|
178
|
+
|
|
179
|
+
This class models an acoustic environment where the propagation of sound is considered to occur
|
|
180
|
+
in a homogeneous medium without any flow effects (e.g., wind). It provides functionality for
|
|
181
|
+
computing the travel time or distances between grid point locations and microphone locations.
|
|
145
182
|
|
|
146
|
-
|
|
147
|
-
|
|
183
|
+
Notes
|
|
184
|
+
-----
|
|
185
|
+
- The :func:`dist_mat` function is used internally to compute the pairwise distances
|
|
186
|
+
between grid points and microphone positions efficiently.
|
|
187
|
+
- This class assumes a static, homogeneous environment without accounting
|
|
188
|
+
for factors like temperature gradients, humidity, or atmospheric turbulence.
|
|
148
189
|
"""
|
|
149
190
|
|
|
150
|
-
|
|
151
|
-
digest = Property(
|
|
152
|
-
depends_on=['c'],
|
|
153
|
-
)
|
|
191
|
+
#: A unique identifier based on the environment properties. (read-only)
|
|
192
|
+
digest = Property(depends_on=['c'])
|
|
154
193
|
|
|
155
|
-
#: The speed of sound
|
|
194
|
+
#: The speed of sound in the environment. Default is ``343.0``, which corresponds to the
|
|
195
|
+
#: approximate speed of sound at 20°C in dry air at sea level, if the unit is m/s.
|
|
156
196
|
c = Float(343.0, desc='speed of sound')
|
|
157
197
|
|
|
158
|
-
#: The region of interest (ROI)
|
|
159
|
-
|
|
198
|
+
#: The region of interest (ROI) for calculations. (Not needed for most types of environment.)
|
|
199
|
+
#: Default is :obj:`None`.
|
|
200
|
+
roi = Union(None, CArray)
|
|
160
201
|
|
|
161
202
|
def _get_digest(self):
|
|
162
203
|
return digest(self)
|
|
163
204
|
|
|
164
205
|
def _r(self, gpos, mpos=0.0):
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
206
|
+
# Compute the distance between two sets of points.
|
|
207
|
+
#
|
|
208
|
+
# The distance for each of the `N` points in ``gpos`` in 3-D space to each of the `M` points
|
|
209
|
+
# in ``mpos``.
|
|
210
|
+
#
|
|
211
|
+
# See Also
|
|
212
|
+
# --------
|
|
213
|
+
# :func:`dist_mat`: Compute distance matrix.
|
|
214
|
+
#
|
|
215
|
+
# Parameters
|
|
216
|
+
# ----------
|
|
217
|
+
# gpos : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
218
|
+
# The coordinates of the first set of points. Should be of shape `(N, 3)`,
|
|
219
|
+
# where `N` is the number of points.
|
|
220
|
+
#
|
|
221
|
+
# mpos : :class:`float` or :class:`numpy.ndarray` of :class:`floats<float>`, optional
|
|
222
|
+
# The coordinates of the second set of points. If a scalar is provided,
|
|
223
|
+
# it is treated as the origin ``(0, 0, 0)``. If an array is given,
|
|
224
|
+
# it should have shape `(M, 3)`, where `M` is the number of points.
|
|
225
|
+
#
|
|
226
|
+
# Returns
|
|
227
|
+
# -------
|
|
228
|
+
# rm : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
229
|
+
# The distances between each point in ``gpos`` and ``mpos``.
|
|
230
|
+
# The result is an array of
|
|
231
|
+
#
|
|
232
|
+
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
233
|
+
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
185
234
|
if isscalar(mpos):
|
|
186
235
|
mpos = array((0, 0, 0), dtype=float64)[:, newaxis]
|
|
187
236
|
rm = dist_mat(ascontiguousarray(gpos), ascontiguousarray(mpos))
|
|
@@ -194,21 +243,31 @@ class Environment(HasPrivateTraits):
|
|
|
194
243
|
|
|
195
244
|
|
|
196
245
|
class UniformFlowEnvironment(Environment):
|
|
197
|
-
"""
|
|
246
|
+
"""
|
|
247
|
+
An acoustic environment with uniform flow.
|
|
248
|
+
|
|
249
|
+
This class models an acoustic environment where sound propagates in a medium with uniform flow.
|
|
250
|
+
It extends the :class:`Environment` class to account for the effects of flow on sound
|
|
251
|
+
propagation, such as changes in travel times and distances due to advection by the flow field.
|
|
252
|
+
|
|
253
|
+
The flow is assumed to be uniform and steady, characterized by its Mach number (:attr:`ma`)
|
|
254
|
+
and direction (:attr:`fdv`).
|
|
198
255
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
256
|
+
Notes
|
|
257
|
+
-----
|
|
258
|
+
The effective distance is adjusted by solving a flow-dependent relationship that accounts
|
|
259
|
+
for the cosine of the angle between the flow direction and the propagation path.
|
|
202
260
|
"""
|
|
203
261
|
|
|
204
|
-
#: The Mach number,
|
|
262
|
+
#: The Mach number of the flow, defined as the ratio of the flow velocity to the speed of sound.
|
|
263
|
+
#: Default is ``0.0``, which corresponds to no flow.
|
|
205
264
|
ma = Float(0.0, desc='flow mach number')
|
|
206
265
|
|
|
207
|
-
#:
|
|
208
|
-
#: flow in x-direction.
|
|
266
|
+
#: A unit vector specifying the direction of the flow in 3D Cartesian coordinates.
|
|
267
|
+
#: Default is ``(1.0, 0, 0)``, which corresponds to flow in the x-direction.
|
|
209
268
|
fdv = CArray(dtype=float64, shape=(3,), value=array((1.0, 0, 0)), desc='flow direction')
|
|
210
269
|
|
|
211
|
-
|
|
270
|
+
#: A unique identifier based on the environment properties. (read-only)
|
|
212
271
|
digest = Property(
|
|
213
272
|
depends_on=['c', 'ma', 'fdv'],
|
|
214
273
|
)
|
|
@@ -218,27 +277,30 @@ class UniformFlowEnvironment(Environment):
|
|
|
218
277
|
return digest(self)
|
|
219
278
|
|
|
220
279
|
def _r(self, gpos, mpos=0.0):
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
280
|
+
# Compute the distance between two sets of points.
|
|
281
|
+
#
|
|
282
|
+
# This method calculates the distance between points ``gpos`` and ``mpos`` in a 3-D space,
|
|
283
|
+
# with an additional adjustment based on a mass term and force vector. The result is
|
|
284
|
+
# affected by the angle between the direction of movement and the force vector.
|
|
285
|
+
#
|
|
286
|
+
# Parameters
|
|
287
|
+
# ----------
|
|
288
|
+
# gpos : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
289
|
+
# The 3-D coordinates of the first set of points, shape `(N, 3)`.
|
|
290
|
+
#
|
|
291
|
+
# mpos : :class:`float` or :class:`numpy.ndarray` of :class:`floats<float>`, optional
|
|
292
|
+
# The 3-D coordinates of the second set of points. If a scalar is provided, it is
|
|
293
|
+
# treated as the origin ``(0, 0, 0)``. If an array is given, it should have shape
|
|
294
|
+
# `(M, 3)`, where `M` is the number of points.
|
|
295
|
+
#
|
|
296
|
+
# Returns
|
|
297
|
+
# -------
|
|
298
|
+
# rm : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
299
|
+
# The distances between each point in ``gpos`` and ``mpos``.
|
|
300
|
+
# The result is an array of
|
|
301
|
+
#
|
|
302
|
+
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
303
|
+
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
242
304
|
if isscalar(mpos):
|
|
243
305
|
mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
|
|
244
306
|
fdv = self.fdv / sqrt((self.fdv * self.fdv).sum())
|
|
@@ -252,62 +314,67 @@ class UniformFlowEnvironment(Environment):
|
|
|
252
314
|
return rm
|
|
253
315
|
|
|
254
316
|
|
|
255
|
-
class FlowField(
|
|
317
|
+
class FlowField(ABCHasStrictTraits):
|
|
256
318
|
"""An abstract base class for a spatial flow field."""
|
|
257
319
|
|
|
320
|
+
#: A unique identifier based on the field properties. (read-only)
|
|
258
321
|
digest = Property
|
|
259
322
|
|
|
323
|
+
@abstractmethod
|
|
260
324
|
def _get_digest(self):
|
|
261
|
-
|
|
325
|
+
pass
|
|
262
326
|
|
|
327
|
+
@abstractmethod
|
|
263
328
|
def v(self, xx): # noqa: ARG002
|
|
264
|
-
"""
|
|
265
|
-
|
|
329
|
+
"""
|
|
330
|
+
Provide the flow field as a function of the location.
|
|
266
331
|
|
|
267
332
|
Parameters
|
|
268
333
|
----------
|
|
269
|
-
xx :
|
|
270
|
-
Location in the fluid for which to provide the data.
|
|
271
|
-
|
|
272
|
-
Returns
|
|
273
|
-
-------
|
|
274
|
-
tuple with two elements
|
|
275
|
-
The first element in the tuple is the velocity vector and the
|
|
276
|
-
second is the Jacobian of the velocity vector field, both at the
|
|
277
|
-
given location.
|
|
278
|
-
|
|
334
|
+
xx : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
335
|
+
Location in the fluid for which to provide the data, shape (3,).
|
|
279
336
|
"""
|
|
280
|
-
v = array((0.0, 0.0, 0.0))
|
|
281
|
-
dv = array(((0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0)))
|
|
282
|
-
return -v, -dv
|
|
283
337
|
|
|
284
338
|
|
|
285
339
|
class SlotJet(FlowField):
|
|
286
|
-
"""
|
|
340
|
+
"""
|
|
341
|
+
Analytical approximation of the flow field of a slot jet.
|
|
342
|
+
|
|
343
|
+
This class provides an analytical model of the velocity field for a slot jet,
|
|
344
|
+
based on the description in :cite:`Albertson1950`. It describes the flow field
|
|
345
|
+
originating from a slot nozzle, including the jet core and shear layer, and
|
|
346
|
+
calculates the velocity field and its Jacobian matrix at a given location.
|
|
287
347
|
|
|
288
|
-
|
|
348
|
+
Notes
|
|
349
|
+
-----
|
|
350
|
+
- The slot jet is divided into two regions: the jet core and the shear layer. The model
|
|
351
|
+
distinguishes between these regions based on the non-dimensionalized distance from
|
|
352
|
+
the slot exit plane.
|
|
353
|
+
- The flow field is aligned with the direction of the :attr:`flow` vector,
|
|
354
|
+
while the :attr:`plane` vector helps define the orientation of the slot.
|
|
289
355
|
"""
|
|
290
356
|
|
|
291
|
-
#: Exit velocity at jet origin
|
|
357
|
+
#: Exit velocity at the :attr:`slot jet origin<origin>` (nozzle). Default is ``0.0``.
|
|
292
358
|
v0 = Float(0.0, desc='exit velocity')
|
|
293
359
|
|
|
294
|
-
#:
|
|
295
|
-
#: defaults to the co-ordinate origin.
|
|
360
|
+
#: The location of the slot nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
296
361
|
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
297
362
|
|
|
298
|
-
#: Unit
|
|
363
|
+
#: Unit vector representing the flow direction. Default is ``(1.0, 0.0, 0.0)``.
|
|
299
364
|
flow = CArray(dtype=float64, shape=(3,), value=array((1.0, 0.0, 0.0)), desc='flow direction')
|
|
300
365
|
|
|
301
|
-
#: Unit vector parallel to slot center plane,
|
|
366
|
+
#: Unit vector parallel to the slot center plane, used to define the slot orientation.
|
|
367
|
+
#: Default is ``(0.0, 1.0, 0.0)``.
|
|
302
368
|
plane = CArray(dtype=float64, shape=(3,), value=array((0.0, 1.0, 0.0)), desc='slot center line direction')
|
|
303
369
|
|
|
304
|
-
#: Width of the slot
|
|
370
|
+
#: Width of the slot (slot diameter). Default is ``0.2``.
|
|
305
371
|
B = Float(0.2, desc='nozzle diameter')
|
|
306
372
|
|
|
307
|
-
#:
|
|
373
|
+
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
374
|
+
#: Default is ``5.2``.
|
|
308
375
|
l = Float(5.2, desc='flow establishment length') # noqa: E741
|
|
309
376
|
|
|
310
|
-
|
|
377
|
+
#: A unique identifier based on the field properties. (read-only)
|
|
311
378
|
digest = Property(
|
|
312
379
|
depends_on=['v0', 'origin', 'flow', 'plane', 'B', 'l'],
|
|
313
380
|
)
|
|
@@ -317,32 +384,45 @@ class SlotJet(FlowField):
|
|
|
317
384
|
return digest(self)
|
|
318
385
|
|
|
319
386
|
def v(self, xx):
|
|
320
|
-
"""
|
|
321
|
-
|
|
322
|
-
|
|
387
|
+
"""
|
|
388
|
+
Compute the velocity field and its Jacobian matrix at a given location.
|
|
389
|
+
|
|
390
|
+
This method provides the velocity vector and its Jacobian matrix at the given location
|
|
391
|
+
``xx`` in the fluid. The velocity is computed for the flow component in the direction
|
|
392
|
+
of the slot jet, while the entrainment components are assumed to be zero.
|
|
323
393
|
|
|
324
394
|
Parameters
|
|
325
395
|
----------
|
|
326
|
-
xx :
|
|
327
|
-
|
|
396
|
+
xx : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
397
|
+
The 3D Cartesian coordinates of the location in the fluid where the velocity field
|
|
398
|
+
is to be computed, shape `(3,)`.
|
|
328
399
|
|
|
329
400
|
Returns
|
|
330
401
|
-------
|
|
331
|
-
|
|
332
|
-
The
|
|
333
|
-
|
|
334
|
-
given location
|
|
335
|
-
|
|
402
|
+
velocity_vector : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
403
|
+
The velocity vector at the given location, shape `(3,)`.
|
|
404
|
+
jacobian_matrix : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
405
|
+
The Jacobian matrix of the velocity vector field at the given location, shape `(3,)`.
|
|
406
|
+
|
|
407
|
+
Notes
|
|
408
|
+
-----
|
|
409
|
+
- The velocity field is computed using a local coordinate system aligned with the flow
|
|
410
|
+
direction and the slot orientation.
|
|
411
|
+
- The velocity profile depends on whether the point lies within the jet core region or
|
|
412
|
+
in the shear layer. In the jet core, the velocity is constant, while in the shear layer,
|
|
413
|
+
it decays following a Gaussian distribution.
|
|
414
|
+
- The Jacobian matrix provides the partial derivatives of the velocity vector components
|
|
415
|
+
with respect to the spatial coordinates.
|
|
336
416
|
"""
|
|
337
417
|
# normalize
|
|
338
418
|
flow = self.flow / norm(self.flow)
|
|
339
419
|
plane = self.plane / norm(self.plane)
|
|
340
|
-
# additional axes of global
|
|
420
|
+
# additional axes of global coordinate system
|
|
341
421
|
yy = -cross(flow, plane)
|
|
342
422
|
zz = cross(flow, yy)
|
|
343
423
|
# distance from slot exit plane
|
|
344
424
|
xx1 = xx - self.origin
|
|
345
|
-
# local
|
|
425
|
+
# local coordinate system
|
|
346
426
|
x = dot(flow, xx1)
|
|
347
427
|
y = dot(yy, xx1)
|
|
348
428
|
x1 = 0.5668 / self.l * x # C1 in Albertson1950
|
|
@@ -365,31 +445,50 @@ class SlotJet(FlowField):
|
|
|
365
445
|
|
|
366
446
|
|
|
367
447
|
class OpenJet(FlowField):
|
|
368
|
-
"""
|
|
448
|
+
"""
|
|
449
|
+
Analytical approximation of the flow field of an open jet.
|
|
369
450
|
|
|
370
|
-
|
|
451
|
+
This class provides a simplified analytical model of the velocity field for an open jet, based
|
|
452
|
+
on the description in :cite:`Albertson1950`. It calculates the velocity vector and its
|
|
453
|
+
Jacobian matrix at a given location in the fluid domain, assuming flow in the x-direction only.
|
|
371
454
|
|
|
372
455
|
Notes
|
|
373
456
|
-----
|
|
374
|
-
This is not a fully generic implementation and is limited to flow in the
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
457
|
+
- This is not a fully generic implementation, and is limited to flow in the x-direction only.
|
|
458
|
+
No other directions are possible at the moment and flow components in
|
|
459
|
+
the other direction are zero.
|
|
460
|
+
- The flow field transitions from the jet core to the shear layer, with velocity decay
|
|
461
|
+
modeled using a Gaussian profile in the shear layer.
|
|
462
|
+
|
|
463
|
+
Examples
|
|
464
|
+
--------
|
|
465
|
+
>>> import acoular as ac
|
|
466
|
+
>>> import numpy as np
|
|
467
|
+
>>>
|
|
468
|
+
>>> jet = ac.OpenJet(v0=10.0, D=0.4, l=6.2)
|
|
469
|
+
>>> velocity, jacobian = jet.v(np.array((1.0, 0.1, 0.1)))
|
|
470
|
+
>>> velocity
|
|
471
|
+
array([9.62413564, 0. , 0. ])
|
|
472
|
+
>>> jacobian
|
|
473
|
+
array([[ -1.92660591, -23.25619062, -23.25619062],
|
|
474
|
+
[ 0. , 0. , 0. ],
|
|
475
|
+
[ 0. , 0. , 0. ]])
|
|
378
476
|
"""
|
|
379
477
|
|
|
380
|
-
#: Exit velocity at jet origin
|
|
478
|
+
#: Exit velocity at the jet origin (nozzle). Default is ``0.0``.
|
|
381
479
|
v0 = Float(0.0, desc='exit velocity')
|
|
382
480
|
|
|
383
|
-
#:
|
|
481
|
+
#: The location of the nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
384
482
|
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
|
|
385
483
|
|
|
386
|
-
#: Diameter of the nozzle
|
|
484
|
+
#: Diameter of the nozzle. Default is ``0.2``.
|
|
387
485
|
D = Float(0.2, desc='nozzle diameter')
|
|
388
486
|
|
|
389
|
-
#:
|
|
487
|
+
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
488
|
+
#: Default is ``6.2``. :cite:`Albertson1950`
|
|
390
489
|
l = Float(6.2, desc='flow establishment length') # noqa: E741
|
|
391
490
|
|
|
392
|
-
|
|
491
|
+
#: A unique identifier based on the field properties. (read-only)
|
|
393
492
|
digest = Property(
|
|
394
493
|
depends_on=['v0', 'origin', 'D', 'l'],
|
|
395
494
|
)
|
|
@@ -399,22 +498,36 @@ class OpenJet(FlowField):
|
|
|
399
498
|
return digest(self)
|
|
400
499
|
|
|
401
500
|
def v(self, xx):
|
|
402
|
-
"""
|
|
403
|
-
|
|
404
|
-
|
|
501
|
+
"""
|
|
502
|
+
Compute the velocity field and its Jacobian matrix at a given location.
|
|
503
|
+
|
|
504
|
+
This method calculates the velocity vector and its Jacobian matrix at the
|
|
505
|
+
specified location ``xx`` in the fluid domain. The velocity is modeled only for the
|
|
506
|
+
x-component of the flow, while the y- and z-components are assumed to be zero.
|
|
405
507
|
|
|
406
508
|
Parameters
|
|
407
509
|
----------
|
|
408
|
-
xx :
|
|
409
|
-
|
|
510
|
+
xx : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
511
|
+
The 3D Cartesian coordinates of the location in the fluid where the velocity
|
|
512
|
+
field is to be computed, shape `(3,)`.
|
|
410
513
|
|
|
411
514
|
Returns
|
|
412
515
|
-------
|
|
413
|
-
|
|
414
|
-
The
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
516
|
+
velocity_vector : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
517
|
+
The velocity vector at the specified location ``xx``, shape `(3,)`.
|
|
518
|
+
jacobian_matrix : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
519
|
+
The Jacobian matrix of the velocity vector field at the specified location ``xx``,
|
|
520
|
+
shape `(3, 3)`.
|
|
521
|
+
|
|
522
|
+
Notes
|
|
523
|
+
-----
|
|
524
|
+
- The velocity field is determined based on whether the location is within the jet core
|
|
525
|
+
region or in the shear layer. Within the jet core, the velocity is constant and equal
|
|
526
|
+
to :attr:`v0`. In the shear layer, the velocity decays following a Gaussian distribution.
|
|
527
|
+
- The Jacobian matrix provides the partial derivatives of the velocity components
|
|
528
|
+
with respect to the spatial coordinates.
|
|
529
|
+
- If the radial distance `r` from the jet axis is zero, the derivatives with respect
|
|
530
|
+
to `y` and `z` are set to zero to avoid division by zero.
|
|
418
531
|
"""
|
|
419
532
|
x, y, z = xx - self.origin
|
|
420
533
|
r = sqrt(y * y + z * z)
|
|
@@ -443,71 +556,201 @@ class OpenJet(FlowField):
|
|
|
443
556
|
|
|
444
557
|
|
|
445
558
|
class RotatingFlow(FlowField):
|
|
446
|
-
"""
|
|
559
|
+
"""
|
|
560
|
+
Analytical approximation of a rotating flow field with additional velocity component
|
|
561
|
+
in z-direction.
|
|
562
|
+
|
|
563
|
+
This class provides an analytical model for a fluid flow field with a
|
|
564
|
+
rigid-body-like rotation about the z-axis. The flow combines rotational motion
|
|
565
|
+
in the x-y plane and a constant velocity component in the z-direction.
|
|
447
566
|
|
|
448
|
-
|
|
449
|
-
|
|
567
|
+
Notes
|
|
568
|
+
-----
|
|
569
|
+
- The rotation is assumed to be about the z-axis. The velocity components in the x-y plane are
|
|
570
|
+
determined by the angular velocity :attr:`omega`, while the z-component is constant
|
|
571
|
+
and set by :attr:`v0`.
|
|
572
|
+
- The angular velocity :attr:`omega` is computed as: ``omega = 2 * pi * rps``,
|
|
573
|
+
with the :attr:`rps` given in revolutions per second (i.e. Hz).
|
|
574
|
+
|
|
575
|
+
Examples
|
|
576
|
+
--------
|
|
577
|
+
>>> import acoular as ac
|
|
578
|
+
>>> import numpy as np
|
|
579
|
+
>>>
|
|
580
|
+
>>> flow = RotatingFlow(rps=1, v0=1.0)
|
|
581
|
+
>>> velocity, jacobian = flow.v(array((1.0, 1.0, 0.0)))
|
|
582
|
+
>>> velocity
|
|
583
|
+
array([-6.28318531, 6.28318531, 1. ])
|
|
584
|
+
>>> jacobian
|
|
585
|
+
array([[ 0. , -6.28318531, 0. ],
|
|
586
|
+
[ 6.28318531, 0. , 0. ],
|
|
587
|
+
[ 0. , 0. , 0. ]])
|
|
588
|
+
"""
|
|
450
589
|
|
|
590
|
+
# Revolutions per minute (RPM). Default is ``0.0``.
|
|
591
|
+
# Positive values indicate clockwise rotation of the flow.
|
|
592
|
+
# This is contrary to the usual definition of the direction of rotation.
|
|
593
|
+
# Deprecated! Please use the differently defined :attr:`rps` attribute instead.
|
|
594
|
+
rpm = Property(desc='revolutions per minute of the flow; positive values for clockwise rotation')
|
|
595
|
+
|
|
596
|
+
def _get_rpm(self):
|
|
597
|
+
warn(
|
|
598
|
+
'Deprecated use of "rpm" trait. Please use the "rps" trait instead.',
|
|
599
|
+
DeprecationWarning,
|
|
600
|
+
stacklevel=2,
|
|
601
|
+
)
|
|
602
|
+
return -60 * self.rps
|
|
603
|
+
|
|
604
|
+
def _set_rpm(self, rpm):
|
|
605
|
+
warn(
|
|
606
|
+
'Deprecated use of "rpm" trait. Please use the "rps" trait instead (divide rpm value by -60).',
|
|
607
|
+
DeprecationWarning,
|
|
608
|
+
stacklevel=2,
|
|
609
|
+
)
|
|
610
|
+
self.rps = -rpm / 60
|
|
611
|
+
|
|
612
|
+
#: Rotational speed in revolutions per second. Negative values indicate clockwise
|
|
613
|
+
#: rigid-body-like rotation of the flow. Default is ``0.0``.
|
|
614
|
+
rps = Float(0.0, desc='rotational speed of the flow in Hz')
|
|
615
|
+
|
|
616
|
+
#: Constant flow velocity in the z-direction. Default is ``0.0``.
|
|
451
617
|
v0 = Float(0.0, desc='flow velocity')
|
|
452
618
|
|
|
453
|
-
#:
|
|
454
|
-
|
|
619
|
+
#: The location of the center of rotation.
|
|
620
|
+
#: 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')
|
|
455
622
|
|
|
456
|
-
|
|
623
|
+
#: A unique identifier based on the field properties. (read-only)
|
|
457
624
|
digest = Property(
|
|
458
|
-
depends_on=['v0', 'origin', '
|
|
625
|
+
depends_on=['v0', 'origin', 'rps'],
|
|
459
626
|
)
|
|
460
627
|
|
|
461
|
-
|
|
628
|
+
#: Angular velocity (in radians per second) of the rotation.
|
|
629
|
+
#: This is a derived property based on :attr:`rps`.
|
|
462
630
|
omega = Property(
|
|
463
|
-
depends_on=['
|
|
631
|
+
depends_on=['rps'],
|
|
464
632
|
)
|
|
465
633
|
|
|
466
634
|
@cached_property
|
|
467
635
|
def _get_omega(self):
|
|
468
|
-
return 2 * pi * self.
|
|
636
|
+
return 2 * pi * self.rps
|
|
469
637
|
|
|
470
638
|
@cached_property
|
|
471
639
|
def _get_digest(self):
|
|
472
640
|
return digest(self)
|
|
473
641
|
|
|
474
642
|
def v(self, xx):
|
|
475
|
-
"""
|
|
643
|
+
"""
|
|
644
|
+
Compute the rotating flow field and its Jacobian matrix at a given location.
|
|
645
|
+
|
|
646
|
+
This method calculates the velocity vector and its Jacobian matrix at the specified location
|
|
647
|
+
``xx`` in the fluid domain. The flow field consists of rotational components in the
|
|
648
|
+
x-y plane and a constant velocity component in the z-direction.
|
|
476
649
|
|
|
477
650
|
Parameters
|
|
478
651
|
----------
|
|
479
|
-
xx :
|
|
480
|
-
|
|
652
|
+
xx : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
653
|
+
The 3D Cartesian coordinates of the location in the fluid where the velocity
|
|
654
|
+
field is to be computed, shape `(3,)`.
|
|
481
655
|
|
|
482
656
|
Returns
|
|
483
657
|
-------
|
|
484
|
-
|
|
485
|
-
The
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
658
|
+
velocity_vector : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
659
|
+
The velocity vector at the specified location ``xx``, shape `(3,)`. The components are:
|
|
660
|
+
- U: Velocity in the x-direction (dependent on y-coordinate and :attr:`omega`).
|
|
661
|
+
- V: Velocity in the y-direction (dependent on x-coordinate and :attr:`omega`).
|
|
662
|
+
- W: Constant velocity in the z-direction (set by :attr:`v0`).
|
|
663
|
+
jacobian_matrix : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
664
|
+
The Jacobian matrix of the velocity vector field at the specified location ``xx``.
|
|
665
|
+
The matrix contains partial derivatives of each velocity component with
|
|
666
|
+
respect to the spatial coordinates :math:`(x, y, z)`, shape `(3, 3)`.
|
|
667
|
+
|
|
668
|
+
Notes
|
|
669
|
+
-----
|
|
670
|
+
The Jacobian matrix is constant for this flow field and represents the linear relationship
|
|
671
|
+
between the velocity components and spatial coordinates in the x-y plane.
|
|
489
672
|
"""
|
|
490
673
|
x, y, z = xx - self.origin
|
|
491
674
|
|
|
492
|
-
#
|
|
675
|
+
# angular velocity
|
|
493
676
|
omega = self.omega
|
|
494
677
|
|
|
495
678
|
# velocity vector
|
|
496
|
-
U = omega * y
|
|
497
|
-
V =
|
|
679
|
+
U = omega * -y
|
|
680
|
+
V = omega * x
|
|
498
681
|
W = self.v0
|
|
499
682
|
|
|
500
683
|
# flow field
|
|
501
684
|
v = array((U, V, W))
|
|
502
685
|
# Jacobi matrix
|
|
503
|
-
dv = array(((0,
|
|
686
|
+
dv = array(((0.0, omega, 0.0), (-omega, 0.0, 0.0), (0.0, 0.0, 0.0))).T
|
|
504
687
|
return v, dv
|
|
505
688
|
|
|
506
689
|
|
|
507
690
|
def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
508
|
-
"""
|
|
509
|
-
unit vectors
|
|
510
|
-
|
|
691
|
+
"""
|
|
692
|
+
Generate unit vectors equally distributed over a sphere or a portion of it.
|
|
693
|
+
|
|
694
|
+
Internal helper function for the raycasting that returns an array of unit
|
|
695
|
+
vectors of shape `(N, 3)` giving equally distributed directions on a part
|
|
696
|
+
of sphere given by the center direction ``b`` and the solid angle ``Om``.
|
|
697
|
+
|
|
698
|
+
The function uses spherical coordinates to distribute the points, the converts them to Cartesian
|
|
699
|
+
coordinates. It also applies a transformation to reflect the points about a plane so that the
|
|
700
|
+
direction defined by the vector ``b`` points toward the center of the sphere.
|
|
701
|
+
|
|
702
|
+
Parameters
|
|
703
|
+
----------
|
|
704
|
+
N : :class:`int`
|
|
705
|
+
The number of points to generate on the sphere.
|
|
706
|
+
|
|
707
|
+
Om : :class:`float`, optional
|
|
708
|
+
The solid angle in steradians to cover on the sphere. Default is ``2 * pi``,
|
|
709
|
+
which corresponds to a hemisphere. Smaller values result in covering
|
|
710
|
+
a smaller portion of the hemisphere.
|
|
711
|
+
|
|
712
|
+
b : :class:`numpy.ndarray` of :class:`floats<float>`, optional
|
|
713
|
+
A 3D unit vector specifying the desired center direction of the distribution.
|
|
714
|
+
Points are mirrored such that this vector points toward the center of the sphere.
|
|
715
|
+
Default is ``[0, 0, 1]``, which corresponds to the z-axis.
|
|
716
|
+
|
|
717
|
+
Returns
|
|
718
|
+
-------
|
|
719
|
+
:class:`numpy.ndarray` of :class:`floats<float>`
|
|
720
|
+
An array of unit vectors representing points on the sphere, shape `(3, N)`.
|
|
721
|
+
Each column corresponds to a 3D Cartesian coordinate of a point.
|
|
722
|
+
|
|
723
|
+
Notes
|
|
724
|
+
-----
|
|
725
|
+
- The points are initially distributed using a spiral pattern in spherical coordinates.
|
|
726
|
+
This ensures an approximately equal spacing between points over the specified portion
|
|
727
|
+
of the sphere.
|
|
728
|
+
- If a vector ``b`` is provided, the function mirrors the distribution using a
|
|
729
|
+
Householder reflection so that ``b`` points toward the center.
|
|
730
|
+
- The function avoids generating singularities at the poles by adjusting the spiral
|
|
731
|
+
distribution formula.
|
|
732
|
+
|
|
733
|
+
Examples
|
|
734
|
+
--------
|
|
735
|
+
Generate 100 points over a hemisphere:
|
|
736
|
+
|
|
737
|
+
>>> from acoular.environments import spiral_sphere
|
|
738
|
+
>>> points = spiral_sphere(100)
|
|
739
|
+
>>> points.shape
|
|
740
|
+
(3, 100)
|
|
741
|
+
|
|
742
|
+
Generate 50 points over half a hemisphere with the z-axis as the center direction:
|
|
743
|
+
|
|
744
|
+
>>> import numpy as np
|
|
745
|
+
>>> points = spiral_sphere(50, Om=np.pi, b=array((0, 0, 1)))
|
|
746
|
+
>>> points.shape
|
|
747
|
+
(3, 50)
|
|
748
|
+
|
|
749
|
+
Generate 200 points with a different direction vector:
|
|
750
|
+
|
|
751
|
+
>>> points = spiral_sphere(200, b=array((1, 0, 0)))
|
|
752
|
+
>>> points.shape
|
|
753
|
+
(3, 200)
|
|
511
754
|
"""
|
|
512
755
|
Om = 2 * pi if Om is None else Om
|
|
513
756
|
b = array((0, 0, 1)) if b is None else b
|
|
@@ -533,32 +776,54 @@ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
|
533
776
|
|
|
534
777
|
|
|
535
778
|
class GeneralFlowEnvironment(Environment):
|
|
536
|
-
"""
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
field with non-uniform velocities that
|
|
541
|
-
algorithm for the calculation uses a ray-tracing approach that bases
|
|
542
|
-
rays cast from every microphone position in multiple directions and traced
|
|
543
|
-
|
|
544
|
-
|
|
779
|
+
"""
|
|
780
|
+
An acoustic environment with a generic flow field.
|
|
781
|
+
|
|
782
|
+
This class provides the facilities to calculate the travel time (distances) between grid point
|
|
783
|
+
locations and microphone locations in a generic flow field with non-uniform velocities that
|
|
784
|
+
depend on the location. The algorithm for the calculation uses a ray-tracing approach that bases
|
|
785
|
+
on rays cast from every microphone position in multiple directions and traced backwards in time.
|
|
786
|
+
The result is interpolated within a tetrahedal grid spanned between these rays.
|
|
787
|
+
|
|
788
|
+
See Also
|
|
789
|
+
--------
|
|
790
|
+
:class:`scipy.interpolate.LinearNDInterpolator` :
|
|
791
|
+
Piecewise linear interpolator in N > 1 dimensions.
|
|
792
|
+
|
|
793
|
+
Examples
|
|
794
|
+
--------
|
|
795
|
+
>>> import numpy as np
|
|
796
|
+
>>> import acoular as ac
|
|
797
|
+
>>>
|
|
798
|
+
>>> # Instantiate the flow field
|
|
799
|
+
>>> flow_field = ac.OpenJet(v0=10.0, D=0.4, l=3.121)
|
|
800
|
+
>>>
|
|
801
|
+
>>> # Create an instance of GeneralFlowEnvironment
|
|
802
|
+
>>> environment = ac.GeneralFlowEnvironment(
|
|
803
|
+
... ff=flow_field, # Use the custom flow field
|
|
804
|
+
... N=300, # Number of rays
|
|
805
|
+
... Om=np.pi, # Maximum solid angle
|
|
806
|
+
... )
|
|
545
807
|
"""
|
|
546
808
|
|
|
547
|
-
#: The flow field
|
|
548
|
-
|
|
809
|
+
#: The flow field object describing the velocity field,
|
|
810
|
+
#: which must be an instance of :class:`~acoular.environments.FlowField`.
|
|
811
|
+
ff = Instance(FlowField, desc='flow field')
|
|
549
812
|
|
|
550
|
-
#:
|
|
813
|
+
#: The number of rays used per solid angle :math:`\Omega`. Defaults to ``200``.
|
|
551
814
|
N = Int(200, desc='number of rays per Om')
|
|
552
815
|
|
|
553
|
-
#: The maximum solid angle used in the algorithm
|
|
816
|
+
#: The maximum solid angle (in steradians) used in the ray-tracing algorithm.
|
|
817
|
+
#: Default is :obj:`numpy.pi`.
|
|
554
818
|
Om = Float(pi, desc='maximum solid angle')
|
|
555
819
|
|
|
556
|
-
|
|
820
|
+
#: A unique identifier based on the environment properties. (read-only)
|
|
557
821
|
digest = Property(
|
|
558
822
|
depends_on=['c', 'ff.digest', 'N', 'Om'],
|
|
559
823
|
)
|
|
560
824
|
|
|
561
|
-
|
|
825
|
+
#: A dictionary for storing precomputed interpolators to optimize repeated calculations.
|
|
826
|
+
#: (internal use)
|
|
562
827
|
idict = Dict
|
|
563
828
|
|
|
564
829
|
@cached_property
|
|
@@ -566,28 +831,6 @@ class GeneralFlowEnvironment(Environment):
|
|
|
566
831
|
return digest(self)
|
|
567
832
|
|
|
568
833
|
def _r(self, gpos, mpos=0.0):
|
|
569
|
-
"""Calculates the virtual distances between grid point locations and
|
|
570
|
-
microphone locations or the origin. These virtual distances correspond
|
|
571
|
-
to travel times of the sound along a ray that is traced through the
|
|
572
|
-
medium. Functionality may change in the future.
|
|
573
|
-
|
|
574
|
-
Parameters
|
|
575
|
-
----------
|
|
576
|
-
gpos : array of floats of shape (3, N)
|
|
577
|
-
The locations of points in the beamforming map grid in 3D cartesian
|
|
578
|
-
co-ordinates.
|
|
579
|
-
mpos : array of floats of shape (3, M), optional
|
|
580
|
-
The locations of microphones in 3D cartesian co-ordinates. If not
|
|
581
|
-
given, then only one microphone at the origin (0, 0, 0) is
|
|
582
|
-
considered.
|
|
583
|
-
|
|
584
|
-
Returns
|
|
585
|
-
-------
|
|
586
|
-
array of floats
|
|
587
|
-
The distances in a twodimensional (N, M) array of floats. If M==1,
|
|
588
|
-
then only a one-dimensional array is returned.
|
|
589
|
-
|
|
590
|
-
"""
|
|
591
834
|
c = self.c
|
|
592
835
|
|
|
593
836
|
if isscalar(mpos):
|
|
@@ -612,21 +855,30 @@ class GeneralFlowEnvironment(Environment):
|
|
|
612
855
|
return c * gt # return distance along ray
|
|
613
856
|
|
|
614
857
|
def get_interpolator(self, roi, x0):
|
|
615
|
-
"""
|
|
858
|
+
"""
|
|
859
|
+
Generate an interpolator for ray travel times based on a region of interest.
|
|
860
|
+
|
|
861
|
+
This method computes the ray trajectories starting from a given microphone position (``x0``)
|
|
862
|
+
through a region of interest (``roi``). The rays' paths are integrated numerically using a
|
|
863
|
+
system of differential equations, and the resulting points are used to construct a
|
|
864
|
+
convex hull. A linear interpolator is then created to estimate travel times for arbitrary
|
|
865
|
+
points within the region.
|
|
616
866
|
|
|
617
867
|
Parameters
|
|
618
868
|
----------
|
|
619
|
-
roi :
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
x0 :
|
|
624
|
-
|
|
869
|
+
roi : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
870
|
+
Array representing the region of interest (ROI), where each column corresponds
|
|
871
|
+
to a point in the 3D space :math:`(x, y, z)`, shape `(3, M)`.
|
|
872
|
+
|
|
873
|
+
x0 : :class:`numpy.ndarray` of :class:`floats<float>`
|
|
874
|
+
Array representing the location of the microphone in 3D Cartesian coordinates,
|
|
875
|
+
shape `(3,)`.
|
|
625
876
|
|
|
626
877
|
Returns
|
|
627
878
|
-------
|
|
628
|
-
LinearNDInterpolator object
|
|
629
|
-
|
|
879
|
+
:class:`scipy.interpolate.LinearNDInterpolator` object
|
|
880
|
+
A linear interpolator object for estimating travel times for 3D positions
|
|
881
|
+
within the computed ray trajectories.
|
|
630
882
|
"""
|
|
631
883
|
c = self.c
|
|
632
884
|
|