acoular 25.7__py3-none-any.whl → 26.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acoular/aiaa/aiaa.py +8 -10
- acoular/base.py +13 -16
- acoular/calib.py +25 -24
- acoular/configuration.py +2 -2
- acoular/demo/__init__.py +97 -9
- acoular/demo/__main__.py +37 -0
- acoular/environments.py +119 -130
- acoular/fbeamform.py +438 -440
- acoular/fprocess.py +18 -13
- acoular/grids.py +122 -301
- acoular/h5cache.py +5 -1
- acoular/h5files.py +96 -9
- acoular/microphones.py +30 -35
- acoular/process.py +14 -25
- acoular/sdinput.py +9 -14
- acoular/signals.py +36 -34
- acoular/sources.py +263 -380
- acoular/spectra.py +60 -80
- acoular/tbeamform.py +242 -224
- acoular/tools/helpers.py +25 -33
- acoular/tools/metrics.py +5 -10
- acoular/tools/utils.py +168 -0
- acoular/tprocess.py +248 -271
- acoular/trajectory.py +5 -6
- acoular/version.py +2 -2
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/METADATA +54 -105
- acoular-26.1.dist-info/RECORD +56 -0
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/WHEEL +1 -1
- acoular/demo/acoular_demo.py +0 -135
- acoular-25.7.dist-info/RECORD +0 -56
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/licenses/LICENSE +0 -0
acoular/tbeamform.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# ------------------------------------------------------------------------------
|
|
2
2
|
# Copyright (c) Acoular Development Team.
|
|
3
3
|
# ------------------------------------------------------------------------------
|
|
4
|
-
"""
|
|
4
|
+
"""
|
|
5
|
+
Implements beamformers in the time domain.
|
|
6
|
+
|
|
7
|
+
.. inheritance-diagram::
|
|
8
|
+
acoular.tbeamform
|
|
9
|
+
:top-classes:
|
|
10
|
+
acoular.base.TimeOut
|
|
11
|
+
:parts: 1
|
|
5
12
|
|
|
6
13
|
.. autosummary::
|
|
7
14
|
:toctree: generated/
|
|
@@ -17,32 +24,8 @@
|
|
|
17
24
|
IntegratorSectorTime
|
|
18
25
|
"""
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
from numpy import (
|
|
23
|
-
arange,
|
|
24
|
-
argmax,
|
|
25
|
-
array,
|
|
26
|
-
ceil,
|
|
27
|
-
dot,
|
|
28
|
-
empty,
|
|
29
|
-
float32,
|
|
30
|
-
float64,
|
|
31
|
-
histogram,
|
|
32
|
-
int32,
|
|
33
|
-
int64,
|
|
34
|
-
interp,
|
|
35
|
-
isscalar,
|
|
36
|
-
newaxis,
|
|
37
|
-
r_,
|
|
38
|
-
s_,
|
|
39
|
-
sqrt,
|
|
40
|
-
sum, # noqa: A004
|
|
41
|
-
unique,
|
|
42
|
-
where,
|
|
43
|
-
zeros,
|
|
44
|
-
)
|
|
45
|
-
from scipy.linalg import norm
|
|
27
|
+
import numpy as np
|
|
28
|
+
import scipy.linalg as spla
|
|
46
29
|
from traits.api import Bool, CArray, Enum, Float, Instance, Int, List, Map, Property, Range, cached_property
|
|
47
30
|
|
|
48
31
|
from .base import SamplesGenerator, TimeOut
|
|
@@ -57,7 +40,8 @@ from .trajectory import Trajectory
|
|
|
57
40
|
|
|
58
41
|
|
|
59
42
|
def const_power_weight(bf):
|
|
60
|
-
"""
|
|
43
|
+
"""
|
|
44
|
+
Internal helper function for :class:`BeamformerTime`.
|
|
61
45
|
|
|
62
46
|
Provides microphone weighting
|
|
63
47
|
to make the power per unit area of the
|
|
@@ -73,14 +57,14 @@ def const_power_weight(bf):
|
|
|
73
57
|
array of floats
|
|
74
58
|
The weight factors.
|
|
75
59
|
"""
|
|
76
|
-
r = bf.steer.env._r(zeros((3, 1)), bf.steer.mics.pos) # distances to center
|
|
60
|
+
r = bf.steer.env._r(np.zeros((3, 1)), bf.steer.mics.pos) # distances to center
|
|
77
61
|
# round the relative distances to one decimal place
|
|
78
62
|
r = (r / r.max()).round(decimals=1)
|
|
79
|
-
ru, ind = unique(r, return_inverse=True)
|
|
63
|
+
ru, ind = np.unique(r, return_inverse=True)
|
|
80
64
|
ru = (ru[1:] + ru[:-1]) / 2
|
|
81
|
-
count, bins = histogram(r, r_[0, ru, 1.5 * r.max() - 0.5 * ru[-1]])
|
|
65
|
+
count, bins = np.histogram(r, np.r_[0, ru, 1.5 * r.max() - 0.5 * ru[-1]])
|
|
82
66
|
bins *= bins
|
|
83
|
-
weights = sqrt((bins[1:] - bins[:-1]) / count)
|
|
67
|
+
weights = np.sqrt((bins[1:] - bins[:-1]) / count)
|
|
84
68
|
weights /= weights.mean()
|
|
85
69
|
return weights[ind]
|
|
86
70
|
|
|
@@ -90,26 +74,28 @@ possible_weights = {'none': None, 'power': const_power_weight}
|
|
|
90
74
|
|
|
91
75
|
|
|
92
76
|
class BeamformerTime(TimeOut):
|
|
93
|
-
"""
|
|
77
|
+
"""
|
|
78
|
+
Provides a basic time domain beamformer with time signal output.
|
|
79
|
+
|
|
94
80
|
for a spatially fixed grid.
|
|
95
81
|
"""
|
|
96
82
|
|
|
97
83
|
#: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
|
|
98
84
|
source = Instance(SamplesGenerator)
|
|
99
85
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
#: Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
|
|
87
|
+
#: that contains information about the steering vector. This is a private trait.
|
|
88
|
+
#: Do not set this directly, use :attr:`steer` trait instead.
|
|
103
89
|
steer = Instance(SteeringVector, args=())
|
|
104
90
|
|
|
105
91
|
#: Number of channels in output (=number of grid points).
|
|
106
92
|
num_channels = Property()
|
|
107
93
|
|
|
108
94
|
#: Spatial weighting function.
|
|
109
|
-
weights = Map(possible_weights, default_value='none'
|
|
95
|
+
weights = Map(possible_weights, default_value='none')
|
|
110
96
|
# (from timedomain.possible_weights)
|
|
111
97
|
|
|
112
|
-
|
|
98
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
113
99
|
digest = Property(
|
|
114
100
|
depends_on=['steer.digest', 'source.digest', 'weights'],
|
|
115
101
|
)
|
|
@@ -121,41 +107,42 @@ class BeamformerTime(TimeOut):
|
|
|
121
107
|
return digest(self)
|
|
122
108
|
|
|
123
109
|
def _get_weights(self):
|
|
124
|
-
return self.weights_(self)[newaxis] if self.weights_ else 1.0
|
|
110
|
+
return self.weights_(self)[np.newaxis] if self.weights_ else 1.0
|
|
125
111
|
|
|
126
112
|
def result(self, num=2048):
|
|
127
|
-
"""
|
|
113
|
+
"""
|
|
114
|
+
Python generator that yields the time-domain beamformer output.
|
|
128
115
|
|
|
129
116
|
The output time signal starts for source signals that were emitted from
|
|
130
117
|
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
131
118
|
|
|
132
119
|
Parameters
|
|
133
120
|
----------
|
|
134
|
-
num : int
|
|
121
|
+
num : :class:`int`
|
|
135
122
|
This parameter defines the size of the blocks to be yielded
|
|
136
123
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
137
124
|
|
|
138
125
|
Yields
|
|
139
126
|
------
|
|
140
|
-
numpy.ndarray
|
|
141
|
-
Samples in blocks of shape (num
|
|
127
|
+
:class:`numpy.ndarray`
|
|
128
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
142
129
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
143
130
|
large (number of grid points).
|
|
144
|
-
The last block returned by the generator may be shorter than num
|
|
131
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
145
132
|
"""
|
|
146
133
|
# initialize values
|
|
147
134
|
steer_func = self.steer._steer_funcs_time[self.steer.steer_type]
|
|
148
|
-
fdtype = float64
|
|
149
|
-
idtype = int64
|
|
135
|
+
fdtype = np.float64
|
|
136
|
+
idtype = np.int64
|
|
150
137
|
num_mics = self.steer.mics.num_mics
|
|
151
|
-
n_index = arange(0, num + 1)[:, newaxis]
|
|
138
|
+
n_index = np.arange(0, num + 1)[:, np.newaxis]
|
|
152
139
|
c = self.steer.env.c / self.source.sample_freq
|
|
153
|
-
amp = empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
154
|
-
# delays = empty((1,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
155
|
-
d_index = empty((1, self.steer.grid.size, num_mics), dtype=idtype)
|
|
156
|
-
d_interp2 = empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
157
|
-
steer_func(self.steer.rm[newaxis, :, :], self.steer.r0[newaxis, :], amp)
|
|
158
|
-
_delays(self.steer.rm[newaxis, :, :], c, d_interp2, d_index)
|
|
140
|
+
amp = np.empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
141
|
+
# delays = np.empty((1,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
142
|
+
d_index = np.empty((1, self.steer.grid.size, num_mics), dtype=idtype)
|
|
143
|
+
d_interp2 = np.empty((1, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
144
|
+
steer_func(self.steer.rm[np.newaxis, :, :], self.steer.r0[np.newaxis, :], amp)
|
|
145
|
+
_delays(self.steer.rm[np.newaxis, :, :], c, d_interp2, d_index)
|
|
159
146
|
amp.shape = amp.shape[1:]
|
|
160
147
|
# delays.shape = delays.shape[1:]
|
|
161
148
|
d_index.shape = d_index.shape[1:]
|
|
@@ -165,7 +152,7 @@ class BeamformerTime(TimeOut):
|
|
|
165
152
|
|
|
166
153
|
buffer = SamplesBuffer(
|
|
167
154
|
source=self.source,
|
|
168
|
-
length=int(ceil((num + max_sample_delay) / num)) * num,
|
|
155
|
+
length=int(np.ceil((num + max_sample_delay) / num)) * num,
|
|
169
156
|
result_num=num + max_sample_delay,
|
|
170
157
|
shift_index_by='num',
|
|
171
158
|
dtype=fdtype,
|
|
@@ -177,74 +164,76 @@ class BeamformerTime(TimeOut):
|
|
|
177
164
|
# exit loop if there is not enough data left to be processed
|
|
178
165
|
if num <= 0:
|
|
179
166
|
break
|
|
180
|
-
n_index = arange(0, num + 1)[:, newaxis]
|
|
167
|
+
n_index = np.arange(0, num + 1)[:, np.newaxis]
|
|
181
168
|
# init step
|
|
182
|
-
|
|
169
|
+
phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
183
170
|
if 'Cleant' not in self.__class__.__name__:
|
|
184
171
|
if 'Sq' not in self.__class__.__name__:
|
|
185
|
-
yield
|
|
172
|
+
yield phi[:num]
|
|
186
173
|
elif self.r_diag:
|
|
187
|
-
yield (
|
|
174
|
+
yield (phi[:num] ** 2 - autopow[:num]).clip(min=0)
|
|
188
175
|
else:
|
|
189
|
-
yield
|
|
176
|
+
yield phi[:num] ** 2
|
|
190
177
|
else:
|
|
191
178
|
p_res_copy = p_res.copy()
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
179
|
+
gamma = np.zeros(phi.shape)
|
|
180
|
+
gamma_autopow = np.zeros(phi.shape)
|
|
181
|
+
j = 0
|
|
195
182
|
# deconvolution
|
|
196
|
-
while self.n_iter >
|
|
197
|
-
# print(f"start clean iteration {
|
|
198
|
-
|
|
199
|
-
imax = argmax(
|
|
183
|
+
while self.n_iter > j:
|
|
184
|
+
# print(f"start clean iteration {j+1} of max {self.n_iter}")
|
|
185
|
+
pow_phi = (phi[:num] ** 2 - autopow).sum(0).clip(min=0) if self.r_diag else (phi[:num] ** 2).sum(0)
|
|
186
|
+
imax = np.argmax(pow_phi)
|
|
200
187
|
t_float = d_interp2[imax] + d_index[imax] + n_index
|
|
201
|
-
t_ind = t_float.astype(int64)
|
|
188
|
+
t_ind = t_float.astype(np.int64)
|
|
202
189
|
for m in range(num_mics):
|
|
203
|
-
p_res_copy[t_ind[: num + 1, m], m] -= self.damp * interp(
|
|
190
|
+
p_res_copy[t_ind[: num + 1, m], m] -= self.damp * np.interp(
|
|
204
191
|
t_ind[: num + 1, m],
|
|
205
192
|
t_float[:num, m],
|
|
206
|
-
|
|
193
|
+
phi[:num, imax] * self.steer.r0[imax] / self.steer.rm[imax, m],
|
|
207
194
|
)
|
|
208
|
-
|
|
195
|
+
next_phi, next_autopow = self._delay_and_sum(num, p_res_copy, d_interp2, d_index, amp)
|
|
209
196
|
if self.r_diag:
|
|
210
|
-
|
|
197
|
+
pow_next_phi = (next_phi[:num] ** 2 - next_autopow).sum(0).clip(min=0)
|
|
211
198
|
else:
|
|
212
|
-
|
|
213
|
-
# print(f"total signal power: {
|
|
214
|
-
if
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
autopow =
|
|
219
|
-
# print(f"clean max: {L_p((
|
|
220
|
-
|
|
199
|
+
pow_next_phi = (next_phi[:num] ** 2).sum(0)
|
|
200
|
+
# print(f"total signal power: {pow_phi.sum()}")
|
|
201
|
+
if pow_next_phi.sum() < pow_phi.sum(): # stopping criterion
|
|
202
|
+
gamma[:num, imax] += self.damp * phi[:num, imax]
|
|
203
|
+
gamma_autopow[:num, imax] = autopow[:num, imax].copy()
|
|
204
|
+
phi = next_phi
|
|
205
|
+
autopow = next_autopow
|
|
206
|
+
# print(f"clean max: {L_p((gamma**2).sum(0)/num).max()} dB")
|
|
207
|
+
j += 1
|
|
221
208
|
else:
|
|
222
209
|
break
|
|
223
210
|
if 'Sq' not in self.__class__.__name__:
|
|
224
|
-
yield
|
|
211
|
+
yield gamma[:num]
|
|
225
212
|
elif self.r_diag:
|
|
226
|
-
yield
|
|
213
|
+
yield gamma[:num] ** 2 - (self.damp**2) * gamma_autopow[:num]
|
|
227
214
|
else:
|
|
228
|
-
yield
|
|
215
|
+
yield gamma[:num] ** 2
|
|
229
216
|
|
|
230
217
|
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
231
218
|
"""Standard delay-and-sum method."""
|
|
232
|
-
result = empty((num, self.steer.grid.size), dtype=float) # output array
|
|
233
|
-
autopow = empty((num, self.steer.grid.size), dtype=float) # output array
|
|
219
|
+
result = np.empty((num, self.steer.grid.size), dtype=float) # output array
|
|
220
|
+
autopow = np.empty((num, self.steer.grid.size), dtype=float) # output array
|
|
234
221
|
_delayandsum4(p_res, d_index, d_interp2, amp, result, autopow)
|
|
235
222
|
return result, autopow
|
|
236
223
|
|
|
237
224
|
|
|
238
225
|
class BeamformerTimeSq(BeamformerTime):
|
|
239
|
-
"""
|
|
240
|
-
|
|
241
|
-
|
|
226
|
+
"""
|
|
227
|
+
Time domain beamformer with squared output and optional autopower removal.
|
|
228
|
+
|
|
229
|
+
Provides a time domain beamformer with time-dependend power signal output and possible autopower
|
|
230
|
+
removal for a spatially fixed grid.
|
|
242
231
|
"""
|
|
243
232
|
|
|
244
233
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
245
|
-
r_diag = Bool(True
|
|
234
|
+
r_diag = Bool(True)
|
|
246
235
|
|
|
247
|
-
|
|
236
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
248
237
|
digest = Property(
|
|
249
238
|
depends_on=['steer.digest', 'source.digest', 'r_diag', 'weights'],
|
|
250
239
|
)
|
|
@@ -254,47 +243,50 @@ class BeamformerTimeSq(BeamformerTime):
|
|
|
254
243
|
return digest(self)
|
|
255
244
|
|
|
256
245
|
def result(self, num=2048):
|
|
257
|
-
"""
|
|
246
|
+
"""
|
|
247
|
+
Python generator that yields the **squared** time-domain beamformer output.
|
|
258
248
|
|
|
259
249
|
The squared output time signal starts for source signals that were emitted from
|
|
260
250
|
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
261
251
|
|
|
262
252
|
Parameters
|
|
263
253
|
----------
|
|
264
|
-
num : int
|
|
254
|
+
num : :class:`int`
|
|
265
255
|
This parameter defines the size of the blocks to be yielded
|
|
266
256
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
267
257
|
|
|
268
258
|
Yields
|
|
269
259
|
------
|
|
270
|
-
numpy.ndarray
|
|
271
|
-
Samples in blocks of shape (num
|
|
260
|
+
:class:`numpy.ndarray`
|
|
261
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
272
262
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
273
263
|
large (number of grid points).
|
|
274
|
-
The last block returned by the generator may be shorter than num
|
|
264
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
275
265
|
"""
|
|
276
266
|
return super().result(num)
|
|
277
267
|
|
|
278
268
|
|
|
279
269
|
class BeamformerTimeTraj(BeamformerTime):
|
|
280
|
-
"""
|
|
270
|
+
"""
|
|
271
|
+
Provides a basic time domain beamformer with time signal output.
|
|
272
|
+
|
|
281
273
|
for a grid moving along a trajectory.
|
|
282
274
|
"""
|
|
283
275
|
|
|
284
276
|
#: :class:`~acoular.trajectory.Trajectory` or derived object.
|
|
285
277
|
#: Start time is assumed to be the same as for the samples.
|
|
286
|
-
trajectory = Instance(Trajectory
|
|
278
|
+
trajectory = Instance(Trajectory)
|
|
287
279
|
|
|
288
280
|
#: Reference vector, perpendicular to the y-axis of moving grid.
|
|
289
|
-
rvec = CArray(dtype=float, shape=(3,), value=array((0, 0, 0))
|
|
281
|
+
rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0)))
|
|
290
282
|
|
|
291
283
|
#: Considering of convective amplification in beamforming formula.
|
|
292
|
-
conv_amp = Bool(False
|
|
284
|
+
conv_amp = Bool(False)
|
|
293
285
|
|
|
294
286
|
#: Floating point and integer precision
|
|
295
|
-
precision = Enum(64, 32
|
|
287
|
+
precision = Enum(64, 32)
|
|
296
288
|
|
|
297
|
-
|
|
289
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
298
290
|
digest = Property(
|
|
299
291
|
depends_on=[
|
|
300
292
|
'steer.digest',
|
|
@@ -315,10 +307,12 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
315
307
|
"""Python generator that yields the moving grid coordinates samplewise."""
|
|
316
308
|
|
|
317
309
|
def cross(a, b):
|
|
318
|
-
"""
|
|
310
|
+
"""
|
|
311
|
+
Cross product for fast computation.
|
|
312
|
+
|
|
319
313
|
because numpy.cross is ultra slow in this case.
|
|
320
314
|
"""
|
|
321
|
-
return array([a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]])
|
|
315
|
+
return np.array([a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]])
|
|
322
316
|
|
|
323
317
|
start_t = 0.0
|
|
324
318
|
gpos = self.steer.grid.pos
|
|
@@ -328,74 +322,87 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
328
322
|
if rflag:
|
|
329
323
|
for g in trajg:
|
|
330
324
|
# grid is only translated, not rotated
|
|
331
|
-
tpos = gpos + array(g)[:, newaxis]
|
|
325
|
+
tpos = gpos + np.array(g)[:, np.newaxis]
|
|
332
326
|
yield tpos
|
|
333
327
|
else:
|
|
334
|
-
for g, g1 in zip(trajg, trajg1):
|
|
328
|
+
for g, g1 in zip(trajg, trajg1, strict=True):
|
|
335
329
|
# grid is both translated and rotated
|
|
336
|
-
loc = array(g) # translation array([0., 0.4, 1.])
|
|
337
|
-
dx = array(g1) # direction vector (new x-axis)
|
|
330
|
+
loc = np.array(g) # translation array([0., 0.4, 1.])
|
|
331
|
+
dx = np.array(g1) # direction vector (new x-axis)
|
|
338
332
|
dy = cross(self.rvec, dx) # new y-axis
|
|
339
333
|
dz = cross(dx, dy) # new z-axis
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
tpos = dot(
|
|
334
|
+
rm = np.array((dx, dy, dz)).T # rotation matrix
|
|
335
|
+
rm /= np.sqrt((rm * rm).sum(0)) # column normalized
|
|
336
|
+
tpos = np.dot(rm, gpos) + loc[:, np.newaxis] # rotation+translation
|
|
343
337
|
# print(loc[:])
|
|
344
338
|
yield tpos
|
|
345
339
|
|
|
346
340
|
def _get_macostheta(self, g1, tpos, rm):
|
|
347
|
-
vvec = array(g1) # velocity vector
|
|
348
|
-
ma = norm(vvec) / self.steer.env.c # machnumber
|
|
349
|
-
fdv = (vvec / sqrt((vvec * vvec).sum()))[:, newaxis] # unit vecor velocity
|
|
350
|
-
mpos = self.steer.mics.pos[:, newaxis, :]
|
|
351
|
-
rmv = tpos[:, :, newaxis] - mpos
|
|
352
|
-
return (ma * sum(rmv.reshape((3, -1)) * fdv, 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
341
|
+
vvec = np.array(g1) # velocity vector
|
|
342
|
+
ma = spla.norm(vvec) / self.steer.env.c # machnumber
|
|
343
|
+
fdv = (vvec / np.sqrt((vvec * vvec).sum()))[:, np.newaxis] # unit vecor velocity
|
|
344
|
+
mpos = self.steer.mics.pos[:, np.newaxis, :]
|
|
345
|
+
rmv = tpos[:, :, np.newaxis] - mpos
|
|
346
|
+
return (ma * np.sum(rmv.reshape((3, -1)) * fdv, 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
353
347
|
|
|
354
348
|
def get_r0(self, tpos):
|
|
355
|
-
|
|
349
|
+
"""
|
|
350
|
+
Get reference distance for grid positions.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
tpos : :class:`numpy.ndarray`
|
|
355
|
+
Grid positions.
|
|
356
|
+
|
|
357
|
+
Returns
|
|
358
|
+
-------
|
|
359
|
+
:class:`float` or :class:`numpy.ndarray`
|
|
360
|
+
Reference distance(s).
|
|
361
|
+
"""
|
|
362
|
+
if np.isscalar(self.steer.ref) and self.steer.ref > 0:
|
|
356
363
|
return self.steer.ref # full((self.steer.grid.size,), self.steer.ref)
|
|
357
364
|
return self.steer.env._r(tpos)
|
|
358
365
|
|
|
359
366
|
def result(self, num=2048):
|
|
360
|
-
"""
|
|
367
|
+
"""
|
|
368
|
+
Python generator that yields the time-domain beamformer output.
|
|
361
369
|
|
|
362
370
|
The output time signal starts for source signals that were emitted from
|
|
363
371
|
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
364
372
|
|
|
365
373
|
Parameters
|
|
366
374
|
----------
|
|
367
|
-
num : int
|
|
375
|
+
num : :class:`int`
|
|
368
376
|
This parameter defines the size of the blocks to be yielded
|
|
369
377
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
370
378
|
|
|
371
379
|
Yields
|
|
372
380
|
------
|
|
373
|
-
numpy.ndarray
|
|
374
|
-
Samples in blocks of shape (num
|
|
381
|
+
:class:`numpy.ndarray`
|
|
382
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
375
383
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
376
384
|
large (number of grid points).
|
|
377
|
-
The last block returned by the generator may be shorter than num
|
|
385
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
378
386
|
"""
|
|
379
387
|
# initialize values
|
|
380
388
|
if self.precision == 64:
|
|
381
|
-
fdtype = float64
|
|
382
|
-
idtype = int64
|
|
389
|
+
fdtype = np.float64
|
|
390
|
+
idtype = np.int64
|
|
383
391
|
else:
|
|
384
|
-
fdtype = float32
|
|
385
|
-
idtype = int32
|
|
386
|
-
w = self._get_weights()
|
|
392
|
+
fdtype = np.float32
|
|
393
|
+
idtype = np.int32
|
|
387
394
|
c = self.steer.env.c / self.source.sample_freq
|
|
388
395
|
num_mics = self.steer.mics.num_mics
|
|
389
396
|
mpos = self.steer.mics.pos.astype(fdtype)
|
|
390
|
-
m_index = arange(num_mics, dtype=idtype)
|
|
391
|
-
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
392
|
-
blockrm = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
393
|
-
blockrmconv = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
394
|
-
amp = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
395
|
-
# delays = empty((num,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
396
|
-
d_index = empty((num, self.steer.grid.size, num_mics), dtype=idtype)
|
|
397
|
-
d_interp2 = empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
398
|
-
blockr0 = empty((num, self.steer.grid.size), dtype=fdtype)
|
|
397
|
+
m_index = np.arange(num_mics, dtype=idtype)
|
|
398
|
+
n_index = np.arange(num, dtype=idtype)[:, np.newaxis]
|
|
399
|
+
blockrm = np.empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
400
|
+
blockrmconv = np.empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
401
|
+
amp = np.empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
402
|
+
# delays = np.empty((num,self.steer.grid.size,num_mics),dtype=fdtype)
|
|
403
|
+
d_index = np.empty((num, self.steer.grid.size, num_mics), dtype=idtype)
|
|
404
|
+
d_interp2 = np.empty((num, self.steer.grid.size, num_mics), dtype=fdtype)
|
|
405
|
+
blockr0 = np.empty((num, self.steer.grid.size), dtype=fdtype)
|
|
399
406
|
movgpos = self._get_moving_gpos() # create moving grid pos generator
|
|
400
407
|
movgspeed = self.trajectory.traj(0.0, delta_t=1 / self.source.sample_freq, der=1)
|
|
401
408
|
weights = self._get_weights()
|
|
@@ -430,35 +437,35 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
430
437
|
except StopIteration:
|
|
431
438
|
break
|
|
432
439
|
if time_block.shape[0] < buffer.result_num: # last block shorter
|
|
433
|
-
num = sum((d_index.max((1, 2)) + 1 + arange(0, num)) < time_block.shape[0])
|
|
434
|
-
n_index = arange(num, dtype=idtype)[:, newaxis]
|
|
440
|
+
num = np.sum((d_index.max((1, 2)) + 1 + np.arange(0, num)) < time_block.shape[0])
|
|
441
|
+
n_index = np.arange(num, dtype=idtype)[:, np.newaxis]
|
|
435
442
|
flag = False
|
|
436
443
|
# init step
|
|
437
444
|
p_res = time_block.copy()
|
|
438
|
-
|
|
445
|
+
phi, autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
439
446
|
if 'Cleant' not in self.__class__.__name__:
|
|
440
447
|
if 'Sq' not in self.__class__.__name__:
|
|
441
|
-
yield
|
|
448
|
+
yield phi[:num]
|
|
442
449
|
elif self.r_diag:
|
|
443
|
-
yield (
|
|
450
|
+
yield (phi[:num] ** 2 - autopow[:num]).clip(min=0)
|
|
444
451
|
else:
|
|
445
|
-
yield
|
|
452
|
+
yield phi[:num] ** 2
|
|
446
453
|
else:
|
|
447
454
|
# choose correct distance
|
|
448
455
|
blockrm1 = blockrmconv if self.conv_amp else blockrm
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
t_ind = arange(p_res.shape[0], dtype=idtype)
|
|
456
|
+
gamma = np.zeros(phi.shape, dtype=fdtype)
|
|
457
|
+
gamma_autopow = np.zeros(phi.shape, dtype=fdtype)
|
|
458
|
+
j = 0
|
|
459
|
+
t_ind = np.arange(p_res.shape[0], dtype=idtype)
|
|
453
460
|
# deconvolution
|
|
454
|
-
while self.n_iter >
|
|
455
|
-
# print(f"start clean iteration {
|
|
461
|
+
while self.n_iter > j:
|
|
462
|
+
# print(f"start clean iteration {j+1} of max {self.n_iter}")
|
|
456
463
|
if self.r_diag:
|
|
457
|
-
|
|
464
|
+
pow_phi = (phi[:num] * phi[:num] - autopow).sum(0).clip(min=0)
|
|
458
465
|
else:
|
|
459
|
-
|
|
466
|
+
pow_phi = (phi[:num] * phi[:num]).sum(0)
|
|
460
467
|
# find index of max power focus point
|
|
461
|
-
imax = argmax(
|
|
468
|
+
imax = np.argmax(pow_phi)
|
|
462
469
|
# find backward delays
|
|
463
470
|
t_float = (d_interp2[:num, imax, m_index] + d_index[:num, imax, m_index] + n_index).astype(fdtype)
|
|
464
471
|
# determine max/min delays in sample units
|
|
@@ -466,52 +473,54 @@ class BeamformerTimeTraj(BeamformerTime):
|
|
|
466
473
|
ind_max = t_float.max(0).astype(idtype) + 2
|
|
467
474
|
ind_min = t_float.min(0).astype(idtype)
|
|
468
475
|
# store time history at max power focus point
|
|
469
|
-
h =
|
|
476
|
+
h = phi[:num, imax] * blockr0[:num, imax]
|
|
470
477
|
for m in range(num_mics):
|
|
471
478
|
# subtract interpolated time history from microphone signals
|
|
472
|
-
p_res[ind_min[m] : ind_max[m], m] -= self.damp * interp(
|
|
479
|
+
p_res[ind_min[m] : ind_max[m], m] -= self.damp * np.interp(
|
|
473
480
|
t_ind[ind_min[m] : ind_max[m]],
|
|
474
481
|
t_float[:num, m],
|
|
475
482
|
h / blockrm1[:num, imax, m],
|
|
476
483
|
)
|
|
477
|
-
|
|
484
|
+
next_phi, next_autopow = self._delay_and_sum(num, p_res, d_interp2, d_index, amp)
|
|
478
485
|
if self.r_diag:
|
|
479
|
-
|
|
486
|
+
pow_next_phi = (next_phi[:num] * next_phi[:num] - next_autopow).sum(0).clip(min=0)
|
|
480
487
|
else:
|
|
481
|
-
|
|
482
|
-
# print(f"total signal power: {
|
|
483
|
-
if
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
autopow =
|
|
488
|
-
# print(f"clean max: {L_p((
|
|
489
|
-
|
|
488
|
+
pow_next_phi = (next_phi[:num] * next_phi[:num]).sum(0)
|
|
489
|
+
# print(f"total signal power: {pow_phi.sum()}")
|
|
490
|
+
if pow_next_phi.sum() < pow_phi.sum(): # stopping criterion
|
|
491
|
+
gamma[:num, imax] += self.damp * phi[:num, imax]
|
|
492
|
+
gamma_autopow[:num, imax] = autopow[:num, imax].copy()
|
|
493
|
+
phi = next_phi
|
|
494
|
+
autopow = next_autopow
|
|
495
|
+
# print(f"clean max: {L_p((gamma**2).sum(0)/num).max()} dB")
|
|
496
|
+
j += 1
|
|
490
497
|
else:
|
|
491
498
|
break
|
|
492
499
|
if 'Sq' not in self.__class__.__name__:
|
|
493
|
-
yield
|
|
500
|
+
yield gamma[:num]
|
|
494
501
|
elif self.r_diag:
|
|
495
|
-
yield
|
|
502
|
+
yield gamma[:num] ** 2 - (self.damp**2) * gamma_autopow[:num]
|
|
496
503
|
else:
|
|
497
|
-
yield
|
|
504
|
+
yield gamma[:num] ** 2
|
|
498
505
|
|
|
499
506
|
def _delay_and_sum(self, num, p_res, d_interp2, d_index, amp):
|
|
500
507
|
"""Standard delay-and-sum method."""
|
|
501
|
-
fdtype = float64 if self.precision == 64 else float32
|
|
502
|
-
result = empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
503
|
-
autopow = empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
508
|
+
fdtype = np.float64 if self.precision == 64 else np.float32
|
|
509
|
+
result = np.empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
510
|
+
autopow = np.empty((num, self.steer.grid.size), dtype=fdtype) # output array
|
|
504
511
|
_delayandsum5(p_res, d_index, d_interp2, amp, result, autopow)
|
|
505
512
|
return result, autopow
|
|
506
513
|
|
|
507
514
|
|
|
508
515
|
class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
509
|
-
"""Provides a time domain beamformer with time-dependent
|
|
510
|
-
power signal output and possible autopower removal
|
|
511
|
-
for a grid moving along a trajectory.
|
|
512
516
|
"""
|
|
517
|
+
Time domain beamformer with squared output for a grid moving along a trajectory.
|
|
513
518
|
|
|
514
|
-
|
|
519
|
+
Provides a time domain beamformer with time-dependent power signal output and possible autopower
|
|
520
|
+
removal for a grid moving along a trajectory.
|
|
521
|
+
"""
|
|
522
|
+
|
|
523
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
515
524
|
digest = Property(
|
|
516
525
|
depends_on=[
|
|
517
526
|
'steer.digest',
|
|
@@ -530,46 +539,48 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
|
|
|
530
539
|
return digest(self)
|
|
531
540
|
|
|
532
541
|
def result(self, num=2048):
|
|
533
|
-
"""
|
|
542
|
+
"""
|
|
543
|
+
Python generator that yields the **squared** time-domain beamformer output.
|
|
534
544
|
|
|
535
545
|
The squared output time signal starts for source signals that were emitted from
|
|
536
546
|
the :class:`~acoular.grids.Grid` at `t=0`.
|
|
537
547
|
|
|
538
548
|
Parameters
|
|
539
549
|
----------
|
|
540
|
-
num : int
|
|
550
|
+
num : :class:`int`
|
|
541
551
|
This parameter defines the size of the blocks to be yielded
|
|
542
552
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
543
553
|
|
|
544
554
|
Yields
|
|
545
555
|
------
|
|
546
|
-
numpy.ndarray
|
|
547
|
-
Samples in blocks of shape (num
|
|
556
|
+
:class:`numpy.ndarray`
|
|
557
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
548
558
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
549
559
|
large (number of grid points).
|
|
550
|
-
The last block returned by the generator may be shorter than num
|
|
560
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
551
561
|
"""
|
|
552
562
|
return super().result(num)
|
|
553
563
|
|
|
554
564
|
|
|
555
565
|
class BeamformerCleant(BeamformerTime):
|
|
556
|
-
"""
|
|
566
|
+
"""
|
|
567
|
+
CLEANT deconvolution method.
|
|
557
568
|
|
|
558
569
|
An implementation of the CLEAN method in time domain. This class can only
|
|
559
570
|
be used for static sources. See :cite:`Cousson2019` for details.
|
|
560
571
|
"""
|
|
561
572
|
|
|
562
573
|
#: Boolean flag, always False
|
|
563
|
-
r_diag = Enum(False
|
|
574
|
+
r_diag = Enum(False)
|
|
564
575
|
|
|
565
576
|
#: iteration damping factor also referred as loop gain in Cousson et al.
|
|
566
577
|
#: defaults to 0.6
|
|
567
|
-
damp = Range(0.01, 1.0, 0.6
|
|
578
|
+
damp = Range(0.01, 1.0, 0.6)
|
|
568
579
|
|
|
569
580
|
#: max number of iterations
|
|
570
|
-
n_iter = Int(100
|
|
581
|
+
n_iter = Int(100)
|
|
571
582
|
|
|
572
|
-
|
|
583
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
573
584
|
digest = Property(
|
|
574
585
|
depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter'],
|
|
575
586
|
)
|
|
@@ -579,30 +590,32 @@ class BeamformerCleant(BeamformerTime):
|
|
|
579
590
|
return digest(self)
|
|
580
591
|
|
|
581
592
|
def result(self, num=2048):
|
|
582
|
-
"""
|
|
593
|
+
"""
|
|
594
|
+
Python generator that yields the deconvolved time-domain beamformer output.
|
|
583
595
|
|
|
584
596
|
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
585
597
|
`t=0`.
|
|
586
598
|
|
|
587
599
|
Parameters
|
|
588
600
|
----------
|
|
589
|
-
num : int
|
|
601
|
+
num : :class:`int`
|
|
590
602
|
This parameter defines the size of the blocks to be yielded
|
|
591
603
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
592
604
|
|
|
593
605
|
Yields
|
|
594
606
|
------
|
|
595
|
-
numpy.ndarray
|
|
596
|
-
Samples in blocks of shape (num
|
|
607
|
+
:class:`numpy.ndarray`
|
|
608
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
597
609
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
598
610
|
large (number of grid points).
|
|
599
|
-
The last block returned by the generator may be shorter than num
|
|
611
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
600
612
|
"""
|
|
601
613
|
return super().result(num)
|
|
602
614
|
|
|
603
615
|
|
|
604
616
|
class BeamformerCleantSq(BeamformerCleant):
|
|
605
|
-
"""
|
|
617
|
+
"""
|
|
618
|
+
CLEANT deconvolution method with optional removal of autocorrelation.
|
|
606
619
|
|
|
607
620
|
An implementation of the CLEAN method in time domain. This class can only
|
|
608
621
|
be used for static sources. See :cite:`Cousson2019` for details on the method
|
|
@@ -610,9 +623,9 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
610
623
|
"""
|
|
611
624
|
|
|
612
625
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
613
|
-
r_diag = Bool(True
|
|
626
|
+
r_diag = Bool(True)
|
|
614
627
|
|
|
615
|
-
|
|
628
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
616
629
|
digest = Property(
|
|
617
630
|
depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter', 'r_diag'],
|
|
618
631
|
)
|
|
@@ -622,7 +635,8 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
622
635
|
return digest(self)
|
|
623
636
|
|
|
624
637
|
def result(self, num=2048):
|
|
625
|
-
"""
|
|
638
|
+
"""
|
|
639
|
+
Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
626
640
|
|
|
627
641
|
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
628
642
|
`t=0`. Per default, block-wise removal of autocorrelation is performed, which can be turned
|
|
@@ -630,32 +644,33 @@ class BeamformerCleantSq(BeamformerCleant):
|
|
|
630
644
|
|
|
631
645
|
Parameters
|
|
632
646
|
----------
|
|
633
|
-
num : int
|
|
647
|
+
num : :class:`int`
|
|
634
648
|
This parameter defines the size of the blocks to be yielded
|
|
635
649
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
636
650
|
|
|
637
651
|
Yields
|
|
638
652
|
------
|
|
639
|
-
numpy.ndarray
|
|
640
|
-
Samples in blocks of shape (num
|
|
653
|
+
:class:`numpy.ndarray`
|
|
654
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
641
655
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
642
656
|
large (number of grid points).
|
|
643
|
-
The last block returned by the generator may be shorter than num
|
|
657
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
644
658
|
"""
|
|
645
659
|
return super().result(num)
|
|
646
660
|
|
|
647
661
|
|
|
648
662
|
class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
649
|
-
"""
|
|
663
|
+
"""
|
|
664
|
+
CLEANT deconvolution method.
|
|
650
665
|
|
|
651
666
|
An implementation of the CLEAN method in time domain for moving sources
|
|
652
667
|
with known trajectory. See :cite:`Cousson2019` for details.
|
|
653
668
|
"""
|
|
654
669
|
|
|
655
670
|
#: Floating point and integer precision
|
|
656
|
-
precision = Enum(32, 64
|
|
671
|
+
precision = Enum(32, 64)
|
|
657
672
|
|
|
658
|
-
|
|
673
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
659
674
|
digest = Property(
|
|
660
675
|
depends_on=[
|
|
661
676
|
'steer.digest',
|
|
@@ -675,30 +690,32 @@ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
|
|
|
675
690
|
return digest(self)
|
|
676
691
|
|
|
677
692
|
def result(self, num=2048):
|
|
678
|
-
"""
|
|
693
|
+
"""
|
|
694
|
+
Python generator that yields the deconvolved time-domain beamformer output.
|
|
679
695
|
|
|
680
696
|
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
681
697
|
`t=0`.
|
|
682
698
|
|
|
683
699
|
Parameters
|
|
684
700
|
----------
|
|
685
|
-
num : int
|
|
701
|
+
num : :class:`int`
|
|
686
702
|
This parameter defines the size of the blocks to be yielded
|
|
687
703
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
688
704
|
|
|
689
705
|
Yields
|
|
690
706
|
------
|
|
691
|
-
numpy.ndarray
|
|
692
|
-
Samples in blocks of shape (num
|
|
707
|
+
:class:`numpy.ndarray`
|
|
708
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
693
709
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
694
710
|
large (number of grid points).
|
|
695
|
-
The last block returned by the generator may be shorter than num
|
|
711
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
696
712
|
"""
|
|
697
713
|
return super().result(num)
|
|
698
714
|
|
|
699
715
|
|
|
700
716
|
class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
701
|
-
"""
|
|
717
|
+
"""
|
|
718
|
+
CLEANT deconvolution method with optional removal of autocorrelation.
|
|
702
719
|
|
|
703
720
|
An implementation of the CLEAN method in time domain for moving sources
|
|
704
721
|
with known trajectory. See :cite:`Cousson2019` for details on the method and
|
|
@@ -706,9 +723,9 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
706
723
|
"""
|
|
707
724
|
|
|
708
725
|
#: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
|
|
709
|
-
r_diag = Bool(True
|
|
726
|
+
r_diag = Bool(True)
|
|
710
727
|
|
|
711
|
-
|
|
728
|
+
#: A unique identifier for the beamformer, based on its properties. (read-only)
|
|
712
729
|
digest = Property(
|
|
713
730
|
depends_on=[
|
|
714
731
|
'steer.digest',
|
|
@@ -729,7 +746,8 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
729
746
|
return digest(self)
|
|
730
747
|
|
|
731
748
|
def result(self, num=2048):
|
|
732
|
-
"""
|
|
749
|
+
"""
|
|
750
|
+
Python generator that yields the *squared* deconvolved time-domain beamformer output.
|
|
733
751
|
|
|
734
752
|
The output starts for signals that were emitted from the :class:`~acoular.grids.Grid` at
|
|
735
753
|
`t=0`. Per default, block-wise removal of autocorrelation is performed, which can be turned
|
|
@@ -737,17 +755,17 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
|
|
|
737
755
|
|
|
738
756
|
Parameters
|
|
739
757
|
----------
|
|
740
|
-
num : int
|
|
758
|
+
num : :class:`int`
|
|
741
759
|
This parameter defines the size of the blocks to be yielded
|
|
742
760
|
(i.e. the number of samples per block). Defaults to 2048.
|
|
743
761
|
|
|
744
762
|
Yields
|
|
745
763
|
------
|
|
746
|
-
numpy.ndarray
|
|
747
|
-
Samples in blocks of shape (num
|
|
764
|
+
:class:`numpy.ndarray`
|
|
765
|
+
Samples in blocks of shape (``num``, :attr:`~BeamformerTime.num_channels`).
|
|
748
766
|
:attr:`~BeamformerTime.num_channels` is usually very \
|
|
749
767
|
large (number of grid points).
|
|
750
|
-
The last block returned by the generator may be shorter than num
|
|
768
|
+
The last block returned by the generator may be shorter than ``num``.
|
|
751
769
|
"""
|
|
752
770
|
return super().result(num)
|
|
753
771
|
|
|
@@ -759,7 +777,7 @@ class IntegratorSectorTime(TimeOut):
|
|
|
759
777
|
source = Instance(SamplesGenerator)
|
|
760
778
|
|
|
761
779
|
#: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
|
|
762
|
-
grid = Instance(RectGrid
|
|
780
|
+
grid = Instance(RectGrid)
|
|
763
781
|
|
|
764
782
|
#: List of sectors in grid
|
|
765
783
|
sectors = List()
|
|
@@ -770,7 +788,7 @@ class IntegratorSectorTime(TimeOut):
|
|
|
770
788
|
#: Number of channels in output (= number of sectors).
|
|
771
789
|
num_channels = Property(depends_on=['sectors'])
|
|
772
790
|
|
|
773
|
-
|
|
791
|
+
#: A unique identifier for the integrator, based on its properties. (read-only)
|
|
774
792
|
digest = Property(
|
|
775
793
|
depends_on=['sectors', 'clip', 'grid.digest', 'source.digest'],
|
|
776
794
|
)
|
|
@@ -784,32 +802,32 @@ class IntegratorSectorTime(TimeOut):
|
|
|
784
802
|
return len(self.sectors)
|
|
785
803
|
|
|
786
804
|
def result(self, num=1):
|
|
787
|
-
"""
|
|
788
|
-
sectors
|
|
805
|
+
"""
|
|
806
|
+
Python generator that yields the source output integrated over specified grid sectors.
|
|
789
807
|
|
|
790
808
|
Parameters
|
|
791
809
|
----------
|
|
792
|
-
num :
|
|
793
|
-
|
|
794
|
-
(i.e. the number of samples per block).
|
|
810
|
+
num : :class:`int`
|
|
811
|
+
Size of the blocks to be yielded (number of samples per block). Default is ``1``.
|
|
795
812
|
|
|
796
813
|
Returns
|
|
797
814
|
-------
|
|
798
|
-
|
|
815
|
+
:class:`numpy.ndarray`
|
|
816
|
+
Samples in blocks of shape (``num``, :attr:`num_channels`).
|
|
799
817
|
:attr:`num_channels` is the number of sectors.
|
|
800
818
|
The last block may be shorter than num.
|
|
801
819
|
"""
|
|
802
820
|
inds = [self.grid.indices(*sector) for sector in self.sectors]
|
|
803
821
|
gshape = self.grid.shape
|
|
804
|
-
o = empty((num, self.num_channels), dtype=float) # output array
|
|
822
|
+
o = np.empty((num, self.num_channels), dtype=float) # output array
|
|
805
823
|
for r in self.source.result(num):
|
|
806
824
|
ns = r.shape[0]
|
|
807
825
|
mapshape = (ns,) + gshape
|
|
808
826
|
rmax = r.max()
|
|
809
827
|
rmin = rmax * 10 ** (self.clip / 10.0)
|
|
810
|
-
r = where(r > rmin, r, 0.0)
|
|
828
|
+
r = np.where(r > rmin, r, 0.0)
|
|
811
829
|
for i, ind in enumerate(inds):
|
|
812
|
-
h = r[:].reshape(mapshape)[(s_[:],) + ind]
|
|
830
|
+
h = r[:].reshape(mapshape)[(np.s_[:],) + ind]
|
|
813
831
|
o[:ns, i] = h.reshape(h.shape[0], -1).sum(axis=1)
|
|
814
832
|
i += 1
|
|
815
833
|
yield o[:ns]
|