Directional Sources and Microphones¶
Real-world microphones and sound sources usually exhibit directional responses. That is, the impulse response (or frequency response) depends on the emission or reception angle (for sources and microphones, respectively). A concrete example is the human ear attached to the head. The left ear is typically more sensitive to sounds coming from the left side than from the right.
This sub-module provides an interface to add such directional responses to microphones and sources in the room impulse response simulation.
Warning
The directional responses are currently only supported for the image source method based simulation.
Warning
Directional responses are only supported for 3D rooms.
The directivities are described by an object of a class derived from Directivity
.
Let’s dive right in with an example. Here, we simulate a shoebox room with a cardioid source and a dummy head receiver with two ears (i.e., microphones). This simulates a binaural response.
import pyroomacoustics as pra
room = pra.ShoeBox(
p=[5, 3, 3],
materials=pra.Material(energy_absorption),
fs=16000,
max_order=40,
)
# add a cardioid source
dir = pra.directivities.Cardioid(DirectionVector(azimuth=-65, colatitude=90) , gain=1.0)
room.add_source([3.75, 2.13, 1.41], directivity=dir)
# add a dummy head receiver from the MIT KEMAR database
hrtf = MeasuredDirectivityFile(
path="mit_kemar_normal_pinna.sofa", # SOFA file is in the database
fs=room.fs,
interp_order=12, # interpolation order
interp_n_points=1000, # number of points in the interpolation grid
)
# provide the head rotation
orientation = Rotation3D([90.0, 30.0], "yz", degrees=True)
# choose and interpolate the directivities
dir_left = hrtf.get_mic_directivity("left", orientation=orientation)
dir_right = hrtf.get_mic_directivity("right", orientation=orientation)
# for a head-related transfer function, the microphone should be co-located
mic_pos = [1.05, 1.74, 1.81]
room.add_microphone(mic_pos, directivity=dir)
room.add_microphone(mic_pos, directivity=dir)
Analytic Directional Responses¶
A class of directional responses can be defined analytically. Such respones include in particular the cardioid family of patterns that describes cardioid, super-cardioid, and figure-of-eight microphones, (see cardioid family, under Polar patterns, with cardioid, hypercardioid, cardioid, subcardioid, figure-eight, and omnidirectional). In three dimensions, for an orientation given by unit vector \(\boldsymbol{u}\), a parameter \(p \in [0, 1]\), and a gain \(G\), the response to direction \(\boldsymbol{r}\) (also a unit vector) is given by the following equation.
Note that \(\boldsymbol{d}^\top \boldsymbol{r}\) is the inner product of two unit vectors, that is, the cosine of the angle between them.
Different values of \(p\) correspond to different patterns: 0 for figure-eight, 0.25 for hyper-cardioid, 0.5 for cardioid, 0.75 for sub-cardioid, and 1 for omni.
Specialized objects
Cardioid
,
FigureEight
,
SubCardioid
,
HyperCardioid
,
and Omnidirectional
are provided
for the different patterns.
The class CardioidFamily
can be used to make
a pattern with arbitrary parameter \(p\).
# a cardioid pointing toward the ``z`` direction
from pyroomacoustics.directivities import CardioidFamily
dir = Cardioid([0, 0, 1], gain=1.0)
- class pyroomacoustics.directivities.analytic.Cardioid(orientation, gain=1.0)¶
Bases:
CardioidFamily
Cardioid directivity pattern.
- Parameters:
orientation (DirectionVector) – Indicates direction of the pattern.
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- class pyroomacoustics.directivities.analytic.CardioidFamily(orientation, p, gain=1.0)¶
Bases:
Directivity
Object for directivities coming from the cardioid family. In three dimensions, for an orientation given by unit vector \(\\boldsymbol{u}\), a parameter \(p \in [0, 1]\), and a gain \(G\), the pattern is given by the following equation.
\[f(\boldsymbol{r}\,;\,\boldsymbol{d}, p, G) = G (p + (1 - p) \boldsymbol{d}^\top \boldsymbol{r}),\]Different values of \(p\) correspond to different patterns: 0 for figure-eight, 0.25 for hyper-cardioid, 0.5 for cardioid, 0.75 for sub-cardioid, and 1 for omni.
Note that all the patterns are cylindrically symmetric around the orientation vector.
- Parameters:
orientation (DirectionVector or numpy.ndarray) – Indicates direction of the pattern.
p (float) – Parameter of the cardioid pattern. A value of 0 corresponds to a figure-eight pattern, 0.5 to a cardioid pattern, and 1 to an omni pattern The parameter must be between 0 and 1
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- property directivity_pattern¶
Name of cardioid directivity pattern.
- property filter_len_ir¶
When
is_impulse_response
returnsTrue
, this property returns the lengths of the impulse responses returned. All impulse responses are assumed to have the same length.
- get_azimuth(degrees=True)¶
- get_colatitude(degrees=True)¶
- get_response(azimuth, colatitude=None, magnitude=False, frequency=None, degrees=True)¶
Get response for provided angles.
- Parameters:
azimuth (array_like) – Azimuth
colatitude (array_like, optional) – Colatitude. Default is to be on XY plane.
magnitude (bool, optional) – Whether to return magnitude of response.
frequency (float, optional) – For which frequency to compute the response. Cardioid are frequency-independent so this value has no effect.
degrees (bool, optional) – If
True
,azimuth
andcolatitude
are in degrees. Otherwise, they are in radians.
- Returns:
resp – Response at provided angles.
- Return type:
ndarray
- property is_impulse_response¶
Indicates whether the array contains coefficients for octave bands (returns
False
) or is a full-size impulse response (returnsTrue
).
- plot_response(azimuth, colatitude=None, degrees=True, ax=None, offset=None)¶
Plot directivity response at specified angles.
- Parameters:
azimuth (array_like) – Azimuth values for plotting.
colatitude (array_like, optional) – Colatitude values for plotting. If not provided, 2D plot.
degrees (bool) – Whether provided values are in degrees (True) or radians (False).
ax (axes object)
offset (list) – 3-D coordinates of the point where the response needs to be plotted.
- Returns:
ax
- Return type:
Axes
- set_orientation(orientation)¶
Set orientation of directivity pattern.
- Parameters:
orientation (DirectionVector) – New direction for the directivity pattern.
- class pyroomacoustics.directivities.analytic.FigureEight(orientation, gain=1.0)¶
Bases:
CardioidFamily
Figure-of-eight directivity pattern.
- Parameters:
orientation (DirectionVector) – Indicates direction of the pattern.
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- class pyroomacoustics.directivities.analytic.HyperCardioid(orientation, gain=1.0)¶
Bases:
CardioidFamily
Hyper-cardioid directivity pattern.
- Parameters:
orientation (DirectionVector) – Indicates direction of the pattern.
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- class pyroomacoustics.directivities.analytic.Omnidirectional(gain=1.0)¶
Bases:
CardioidFamily
Hyper-cardioid directivity pattern.
- Parameters:
orientation (DirectionVector) – Indicates direction of the pattern.
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- class pyroomacoustics.directivities.analytic.SubCardioid(orientation, gain=1.0)¶
Bases:
CardioidFamily
Sub-cardioid directivity pattern.
- Parameters:
orientation (DirectionVector) – Indicates direction of the pattern.
gain (float) – The linear gain of the directivity pattern (default is 1.0)
- pyroomacoustics.directivities.analytic.cardioid_energy(p, gain=1.0)¶
This function gives the exact value of the surface integral of the cardioid (family) function on the unit sphere
\[E(p, G) = \iint_{\mathbb{S}^2} G^2 \left( p + (1 - p) \boldsymbol{d}^\top \boldsymbol{r} \right)^2 d\boldsymbol{r} = \frac{4 \pi}{3} G^2 \left( 4 p^2 - 2 p + 1 \right).\]This can be used to normalize the energy sent/received.
- Parameters:
p (float) – The parameter of the cardioid function (between 0 and 1)
gain (float) – The gain of the cardioid function
- pyroomacoustics.directivities.analytic.cardioid_func(x, direction, p, gain=1.0, normalize=True, magnitude=False)¶
One-shot function for computing cardioid response.
- Parameters:
x (array_like, shape (n_dim, ...)) – Cartesian coordinates
direction (array_like, shape (n_dim)) – Direction vector, should be normalized
p (float) – Parameter for the cardioid function (between 0 and 1)
gain (float) – The gain
normalize (bool) – Whether to normalize coordinates and direction vector
magnitude (bool) – Whether to return magnitude, default is False
- Returns:
resp – Response at provided angles for the speficied cardioid function.
- Return type:
ndarray
Measured Directivities¶
Source and microphone directivities can be measured in an anechoic chamber. Such measurements result in a collection of impulse responses or transfer functions each associated with a specific source and receiver (i.e., microphone) location. The SOFA file format has been proposed as a standard for the storage of such measurements.
This sub-module offers a way to read such measurements from (SOFA) files and use the measurement to obtain a more faithful simulation.
The workhorse of this module is the class MeasuredDirectivityFile
which reads the content of a file and standardize the data for futher use.
A single SOFA file can contain multiple measurements (for example corresponding
to different devices). The class provies a method to retrieve measurements
from individual sources and turn them into a py:class:MeasuredDirectivity object
that can be used to create a py:class:pyroomacoustics.MicrophoneArray object
with this directivity.
Such measurements do not provide impulse responses for every possible impinging direction. Instead, during simulation the impulse response closest to the desired direction is used instead. To avoid sharp transitions, the py:class:MeasuredDirectivityFile provides an interpolation method in the spherical harmonics domain. This can be activated by providing an order for the interpolation, e.g, interp_order=12.
Here is an example of loading a head-related transfer function and load the directivities for left and right ears of a dummy head HRTF.
from pyroomacoustics.directivities import MeasuredDirectivityFile, Rotation3D
# the file reader object reads the file and optionally performs interpolation
# if the file contains multiple directivities, they are all read
hrtf = MeasuredDirectivityFile(
path="mit_kemar_normal_pinna.sofa", # SOFA file is in the database
fs=fs,
interp_order=12,
interp_n_points=1000,
)
# orientations can be provided as rotation matrices
orientation = Rotation3D([colatitude_deg, azimuth_deg], "yz", degrees=True)
# we can then choose which directivities we want from the file
dir_left = hrtf.get_mic_directivity("left", orientation=orientation)
dir_right = hrtf.get_mic_directivity("right", orientation=orientation)
- class pyroomacoustics.directivities.measured.MeasuredDirectivity(orientation, grid, impulse_responses, fs)¶
Bases:
Directivity
A class to store directivity patterns obtained by measurements.
- Parameters:
orientation (Rotation3D) – A rotation to apply to the pattern
grid (doa.Grid) – The grid of unit vectors where the measurements were taken
impulse_responses (np.ndarray, (n_grid, n_ir)) – The impulse responses corresponding to the grid points
fs (int) – The sampling frequency of the impulse responses
- property filter_len_ir¶
Length of the impulse response in samples
- get_response(azimuth, colatitude=None, magnitude=False, frequency=None, degrees=True)¶
Get response for provided angles and frequency.
- Parameters:
azimuth (np.ndarray, (n_points,)) – The azimuth of the desired responses
colatitude (np.ndarray, (n_points,)) – The colatitude of the desired responses
magnitude (bool) – Ignored
frequency (np.ndarray, (n_freq,)) – Ignored
degrees (bool) – If
True
, indicates that azimuth and colatitude are provided in degrees
- property is_impulse_response¶
Indicates whether the array contains coefficients for octave bands (returns
False
) or is a full-size impulse response (returnsTrue
).
- plot(freq_bin=0, n_grid=100, ax=None, depth=False, offset=None)¶
Plot the directivity pattern at a given frequency.
- Parameters:
freq_bin (int) – The frequency bin to plot
n_grid (int) – The number of points to use for the interpolation grid
ax (matplotlib.axes.Axes, optional) – The axes to plot on. If not provided, a new figure is created
depth (bool) – If
True
, directive response is both depicted by color and depth of the surface. IfFalse
, then only the color map denotes the intensity. (defaultFalse
)offset (float) – An offset to apply to the directivity pattern
- Returns:
ax – The axes on which the directivity is plotted
- Return type:
matplotlib.axes.Axes
- set_orientation(orientation)¶
Set orientation of directivity pattern.
- Parameters:
orientation (Rotation3D) – New direction for the directivity pattern.
- class pyroomacoustics.directivities.measured.MeasuredDirectivityFile(path, fs=None, interp_order=None, interp_n_points=1000, file_reader_callback=None, mic_labels=None, source_labels=None)¶
Bases:
object
This class reads measured directivities from a SOFA format file. Optionally, it can perform interpolation of the impulse responses onto a finer grid. The interpolation is done in the spherical harmonics domain.
- Parameters:
path ((string)) – Path towards the specific DIRPAT file
fs ((int)) – The desired sampling frequency. If the impulse responses were stored at a different sampling frequency, they are resampled at
fs
.interp_order ((int)) – The order of spherical harmonics to use for interpolation. If
None
interpolation is not used.interp_n_points ((int)) – Number of points for the interpolation grid. The interpolation grid is a Fibonnaci pseudo-uniform sampling of the sphere.
file_reader_callback ((callable)) – A callback function that reads the SOFA file and returns the impulse responses The signature should be the same as the function open_sofa_file
mic_labels ((list of strings)) – List of labels for the microphones. If not provided, the labels are simply the indices of the microphones in the array
source_labels ((list of strings)) – List of labels for the sources. If not provided, the labels are simply the indices of the measurements in the array
- get_mic_directivity(measurement_id, orientation)¶
Get a directivity for a microphone
- Parameters:
measurement_id (int or str) – The id of the microphone
orientation (Rotation3D) – The orientation of the directivity pattern
- get_mic_position(measurement_id)¶
Get the position of source with id measurement_id
- Parameters:
measurement_id (int or str) – The id of the source
- get_source_directivity(measurement_id, orientation)¶
Get a directivity for a source
- Parameters:
measurement_id (int or str) – The id of the source
orientation (Rotation3D) – The orientation of the directivity pattern
- get_source_position(measurement_id)¶
Get the position of source with id measurement_id
- Parameters:
measurement_id (int or str) – The id of the source
Built-in SOFA Files Database¶
Pyroomacoustics contains a small database of SOFA files that have been tested
and can be used for simultions.
The database can be loaded using the function
SOFADatabase
.
# load and display the list of available SOFA files and their content
from pyroomacoustics.datasets import SOFADatabase
db = SOFADatabase()
db.list()
The database contains the following files.
Three files from the DIRPAT database collected by Manuel Brandner, Matthias Frank, and Daniel Rudrich University of Music and Performing Arts, Graz.
AKG_c480_c414_CUBE.sofa
containing the directive responses of a microphone with 4 different patterns.EM32_Directivity.sofa
that contains the directional response of the Eigenmike em32 microphone array.LSPs_HATS_GuitarCabinets_Akustikmessplatz.sofa
that contains 12 source directivities. This file is dynamically downloaded upon its first use.The files are public domain (CC0), but if you use them in your research, please cite the following paper.
M. Brandner, M. Frank, and D. Rudrich, "DirPat—Database and Viewer of 2D/3D Directivity Patterns of Sound Sources and Receivers," in Audio Engineering Society Convention 144, Paper 425, 2018.
Two head-related transfer functions of the MIT KEMAR dummy head with normal and large pinna. The data was collected by Bill Gardner and Keith Martin from MIT and is free to use provided the authors are cited. See the full license for more details.
- class pyroomacoustics.datasets.sofa.SOFADatabase(download=True)
A small database of SOFA files containing source/microphone directional impulse responses
The database object is a dictionary-like object where the keys are the names of the SOFA files and the values are objects with the following attributes:
db = SOFADatabase() # type of device: 'sources' or 'microphones' db["Soundfield_ST450_CUBE"].type # list of the labels of the sources/microphones db["Soundfield_ST450_CUBE"].contains
- Parameters:
download (bool, optional) – If set to True, the SOFA files are downloaded if they are not already present in the default folder
- property db_info_path
The path to the JSON file containing the SOFA files information
- list()
Print a list of the available SOFA files and the labels of the different devices they contain
- property root
The path to the folder containing the SOFA files
- pyroomacoustics.datasets.sofa.get_sofa_db()
A helper function to quickly load the SOFA database
Reading Other or Custom File Types¶
It is possible to read other file types by providing a custom reader function to
MeasuredDirectivityFile
with the
argument file_reader_callback
.
The function should have the same signature as open_sofa_file()
.
SOFA File Readers¶
SOFA is a very flexible file format for storing direction impulse responses. This module provides a function to read SOFA files and extract the impulse responses in a format that can be used for simulation.
- pyroomacoustics.directivities.sofa.open_sofa_file(path, fs=16000)¶
Open a SOFA file and read the impulse responses
- Parameters:
path (str or Path) – Path to the SOFA file
fs (int, optional) – The desired sampling frequency. If the impulse responses were stored at a different sampling frequency, they are resampled at
fs
.
- Returns:
ir (np.ndarray (n_sources, n_mics, taps)) – The impulse responses
fs (int) – The sampling frequency of the impulse responses
source_dir (np.ndarray (3, n_sources)) – The direction of the sources in spherical coordinates
rec_loc (np.ndarray (3, n_mics)) – The location of the receivers in cartesian coordinates
source_labels (List[str]) – If available, a list of human readable labels for the sources is returned. Otherwise,
None
is returnedmic_labels (List[str]) – If available, a list of human readable labels for the microphones is returned. Otherwise,
None
is returned
Direction of the Patterns¶
Using directivities makes sources and microphones having a different response depending on the location of other objects. This means that their orientation in 3D space matters.
Some types of directivities such as CardioidFamily
and derived classes
are defined only by a vector (i.e., direction). The response is then symmetric
around the axis defined by this vector.
However, in general, not all directivities are symmetric in this way.
For the general case, the orientation can be defined by Euler angles.
This is implemented in the class pyroomacoustics.direction.Rotation3D
.
- class pyroomacoustics.directivities.direction.DirectionVector(azimuth, colatitude=None, degrees=True)¶
Bases:
object
Object for representing direction vectors in 3D, parameterized by an azimuth and colatitude angle.
- Parameters:
azimuth (float)
colatitude (float, optional) – Default to PI / 2, only XY plane.
degrees (bool) – Whether provided values are in degrees (True) or radians (False).
- property unit_vector¶
Direction vector in cartesian coordinates.
- class pyroomacoustics.directivities.direction.Rotation3D(angles, rot_order='zyx', degrees=True)¶
Bases:
object
An object representing 3D rotations by their Euler angles.
A rotation in 3D space can be fully described by 3 angles (i.e., the Euler angles). Each rotation is applied around one of the three axes and there are 12 possible ways of pickinig the order or the rotations.
This class can apply full or partial rotations to sets of points.
The angles are provided as an array
angles
. The axes of rotation for the angles are provided inrot_order
as a string of three characters out of["x", "y", "z"]
or a list of three integers out of[0, 1, 2]
. Each axis can be repeated. To obtain full rotations, the same axis should not be used twice in a row.By default, the angles are specified in degrees. This can be changed by setting
degrees=False
. In that case, the angles are assumed to be in radians.- Parameters:
angles (array_like) – An array containing between 0 and 3 angles.
rot_order (str of List[int]) – The order of the rotations. The default is “zyx”. The order indicates around which axis the rotation is performed. For example, “zyx” means that the rotation is first around the z-axis, then the y-axis, and finally the x-axis.
degrees (bool) – Whether the angles are in degrees (True) or radians (False).
- rotate(points)¶
Rotate a set of points.
- Parameters:
points (array_like (3, ...)) – The points to rotate. The first dimension must be 3.
- Returns:
rotated_points – The rotated points.
- Return type:
np.ndarray
- rotate_transpose(points)¶
Transposed rotations of a set of points.
- Parameters:
points (array_like (3, ...)) – The points to rotate. The last dimension must be 3.
- Returns:
rotated_points – The rotated points.
- Return type:
np.ndarray
Creating New Types of Directivities¶
The Directivity class is an abstract class that can be subclassed to create new types of directivities. The class provides a common interface to access the directivity patterns.
The class should implement the following methods:
get_response
to get the response for a given angle and frequencyis_impulse_response
to indicate whether the directivity is an impulse response or just band coefficientsfilter_len_ir
to return the length of the impulse response. This should return 1 if the directivity is not an impulse response.
- class pyroomacoustics.directivities.base.Directivity¶
Bases:
ABC
Abstract class for directivity patterns.
- abstract property filter_len_ir¶
When
is_impulse_response
returnsTrue
, this property returns the lengths of the impulse responses returned. All impulse responses are assumed to have the same length.
- abstractmethod get_response(azimuth, colatitude=None, magnitude=False, frequency=None, degrees=True)¶
Get response for provided angles.
- Parameters:
azimuth (array_like) – Azimuth
colatitude (array_like, optional) – Colatitude in degrees. Default is to be on XY plane.
magnitude (bool, optional) – Whether to return magnitude of response.
frequency (float, optional) – For which frequency to compute the response. If the response is frequency independent, this parameter is ignored.
degrees (bool, optional) – If
True
,azimuth
andcolatitude
are in degrees. Otherwise, they are in radians.
- Returns:
resp – Response at provided angles.
- Return type:
ndarray
- abstract property is_impulse_response¶
Indicates whether the array contains coefficients for octave bands (returns
False
) or is a full-size impulse response (returnsTrue
).
Spherical Interpolation¶
This module provides functions to interpolate impulse responses on a sphere. The interpolation is done in the spherical harmonics domain.
- pyroomacoustics.directivities.interp.spherical_interpolation(grid, impulse_responses, new_grid, spherical_harmonics_order=12, axis=-2, nfft=None)¶
- Parameters:
grid (pyroomacoustics.doa.GridSphere) – The grid of the measurements
impulse_responses (numpy.ndarray, (..., n_measurements, ..., n_samples)) – The impulse responses to interpolate, the last axis is time and one other axis should have dimension matching the length of the grid. By default, it is assumed to be second from the end, but can be specified with the axis argument.
new_grid (pyroomacoustics.doa.GridSphere) – Grid of points at which to interpolate
spherical_harmonics_order (int) – The order of spherical harmonics to use for interpolation
axis (int) – The axis of the grid in the impulse responses array
nfft (int) – The length of the FFT to use for the interpolation (default
n_samples
)
Numerical Spherical Integral¶
Provides a function to numerically integrate a function over the 3D unit-sphere (\(\mathbb{S}^2\)).
- pyroomacoustics.directivities.integration.spherical_integral(func, n_points)¶
Numerically integrate a function over the sphere.
- Parameters:
func (callable) – The function to integrate. It should take an array of shape (3, n_points) and return an array of shape (n_points,)
n_points (int) – The number of points to use for integration
- Returns:
value – The value of the integral
- Return type:
np.ndarray