Source code for pyfasst.spatial.steering_vectors
"""
================
STEERING VECTORS
================
generating steering vectors for arrays of sensors
Content
=======
"""
[docs]def gen_steer_vec_acous(freqs,
dist_src_mic):
"""generates a steering vector for the given frequencies and given
distances between the microphones and the source.
To the difference with
:py:func:`gen_steer_vec_far_src_uniform_linear_array`, this function
also includes gains depending on the distance between the source and
the mics.
"""
gains = 1 / (np.sqrt(4. * np.pi) * dist_src_mic)
a = (np.vstack(gains) *
np.exp(- 1j * 2. * np.pi *
np.outer(dist_src_mic,
freqs) /
soundCelerity
)
)
return a
[docs]def dir_diag_stereo(Cx,
nft=2048,
ntheta=512,
samplerate=44100,#Hz
distanceInterMic=0.3,#m
):
"""Compute the diagram of directivity for the input
short time Fourier transform second order statistics in Cx
(this Cx is compatible with the attribute from an instantiation
of :py:class:`pyfasst.audioModel.FASST`)
.. math::
C_x[0] = E[|x_0|^2]
C_x[2] = E[|x_1|^2]
C_x[1] = E[x_0 x_1^H]
**Method**:
We use the Capon method, on each of the Fourier channel :math:`k`:
.. math::
\phi_k(\\theta) = a_k(\\theta)^H R_{xx}^{-1} a_k(\\theta)
The algorithm therefore returns one directivity graph for each
frequency band.
**Remarks**:
One can compute a summary directivity by adding the directivity functions
across all the frequency channels. The invert of the resulting array may
also be of interest (looking at peaks and not valleys to find directions)::
>>> directivity_diag = dir_diag_stereo(Cx)
>>> summary_dir_diag = 1./directivity_diag.sum(axis=1)
Some tests show that it is very important that the distance between the
microphone is known. Otherwise, little can be infered from the resulting
directivity measure...
"""
nchannels = 2 # this function only works for stereo audio
# for capon, we need the average of Cx:
meanCx_diag = np.array([Cx[0].mean(axis=1),
Cx[2].mean(axis=1)],
dtype=np.float64)
meanCx_off = Cx[1].mean(axis=1)
# ... and its inverse:
inv_mat_diag, inv_mat_off, det_mat = (
inv_mat(meanCx_diag, meanCx_off)
)
if not np.all(det_mat):
raise ValueError(
"Not possible to compute directivity, singular covariance. "+
"\nThe channels are probably either identical or colinear.")
nfreqs = nft / 2 + 1
freqs = np.arange(nfreqs) * 1. / nft * samplerate
# now computing the directivity diagram, angle after angle
directivity_diagram = np.zeros([ntheta, nfreqs], dtype=np.float64)
# theta from -pi/2 to +pi/2
theta = np.arange(1, ntheta+1) * np.pi / (ntheta + 1.) - np.pi / 2.
for nth in range(ntheta):
# Compute steering vectors for each frequency
filt = gen_steer_vec_far_src_uniform_linear_array(freqs,
nchannels,
theta[nth],
distanceInterMic)
directivity_diagram[nth] = (
(np.abs(filt[0]**2)) * inv_mat_diag[0] +
(np.abs(filt[1]**2)) * inv_mat_diag[1] +
2. * np.real((np.conjugate(filt[0]) * filt[1]) *
inv_mat_off)
#filt[0] * np.conjugate(filt[1]) * np.conjugate(inv_mat_off) +
#np.conjugate(filt[0]) * filt[1] * inv_mat_off
)
return directivity_diagram, theta