Source code for mesh2scattering.process.coefficients
"""Coefficient calculation functions for the scattering analysis."""
import numpy as np
import pyfar as pf
[docs]
def scattering_freefield(
sample_pressure, reference_pressure, microphone_weights):
r"""
Calculate the direction dependent free-field scattering coefficient.
Uses the Mommertz correlation method [#]_ to calculate the scattering
coefficient of the input data:
.. math::
s = 1 -
\frac{|\sum_w \underline{p}_{\text{sample}}(\vartheta,\varphi)
\cdot \underline{p}_{\text{reference}}^*(\vartheta,\varphi)
\cdot w(\vartheta,\varphi)|^2}
{\sum_w |\underline{p}_{\text{sample}}(\vartheta,\varphi)|^2
\cdot w(\vartheta,\varphi) \cdot \sum_w
|\underline{p}_{\text{reference}}(\vartheta,\varphi)|^2
\cdot w(\vartheta,\varphi) }
with the reflected sound pressure of the the sample under investigation
:math:`\underline{p}_{\text{sample}}`, the reflected sound pressure from
the reference sample (same dimension as the sample under investigation,
but with flat surface) :math:`\underline{p}_{\text{reference}}`, the
area weights of the sampling :math:`w`, and :math:`\vartheta` and
:math:`\varphi` are the ``colatitude``
angle and ``azimuth`` angles from the
:py:class:`~pyfar.classes.coordinates.Coordinates` object.
In other words, the test sample lies in the x-y-plane.
Parameters
----------
sample_pressure : :py:class:`~pyfar.classes.audio.FrequencyData`
Reflected sound pressure or directivity of the test sample. Its cshape
needs to be (..., microphone_weights.size).
reference_pressure : :py:class:`~pyfar.classes.audio.FrequencyData`
Reflected sound pressure or directivity of the
reference sample. Needs to have the same cshape and frequencies as
`sample_pressure`.
microphone_weights : numpy.ndarray
Array containing the area weights for the microphone positions,
no normalization required.
Its shape needs to match the last dimension in the cshape of
`sample_pressure` and `reference_pressure`.
Returns
-------
scattering_coefficients : :py:class:`~pyfar.classes.audio.FrequencyData`
The scattering coefficient for each incident direction depending on
frequency.
References
----------
.. [#] E. Mommertz, „Determination of scattering coefficients from the
reflection directivity of architectural surfaces“, Applied
Acoustics, Bd. 60, Nr. 2, S. 201-203, June 2000,
doi: 10.1016/S0003-682X(99)00057-2.
"""
# check inputs
if not isinstance(sample_pressure, pf.FrequencyData):
raise ValueError(
'sample_pressure has to be a pyfar.FrequencyData object')
if not isinstance(reference_pressure, pf.FrequencyData):
raise ValueError(
'reference_pressure has to be a pyfar.FrequencyData object')
microphone_weights = np.atleast_1d(
np.asarray(microphone_weights, dtype=float))
# if sample_pressure.cshape != reference_pressure.cshape:
# raise ValueError(
# 'sample_pressure and reference_pressure have to have the '
# 'same cshape.')
if microphone_weights.shape[0] != sample_pressure.cshape[-1]:
raise ValueError(
'the last dimension of sample_pressure needs be same as the '
'microphone_weights.shape.')
if not np.allclose(
sample_pressure.frequencies, reference_pressure.frequencies):
raise ValueError(
'sample_pressure and reference_pressure have to have the '
'same frequencies.')
# calculate according to mommertz correlation method Equation (5)
p_sample = np.moveaxis(sample_pressure.freq, -1, 0)
p_reference = np.moveaxis(reference_pressure.freq, -1, 0)
p_sample_sum = np.sum(microphone_weights * np.abs(p_sample)**2, axis=-1)
p_ref_sum = np.sum(microphone_weights * np.abs(p_reference)**2, axis=-1)
final_shape = np.broadcast_shapes(p_sample.shape, p_reference.shape)
result = 1
for x in final_shape:
result = result * x
if result < 1e9:
p_cross_sum = np.sum(
p_sample * np.conj(p_reference) * microphone_weights, axis=-1)
else:
p_cross_sum = np.empty(final_shape[:-1], dtype=complex)
for i in range(final_shape[0]):
p_cross_sum[i] = np.sum(
p_sample[i] * np.conj(p_reference[i]) * microphone_weights,
axis=-1)
del p_sample, p_reference
data_scattering_coefficient \
= 1 - ((np.abs(p_cross_sum)**2)/(p_sample_sum*p_ref_sum))
del p_cross_sum, p_sample_sum, p_ref_sum
scattering_coefficients = pf.FrequencyData(
np.moveaxis(data_scattering_coefficient, 0, -1),
sample_pressure.frequencies)
return scattering_coefficients