From b26d1fd2b03faf2b52f88d7094d8ac744bb395c8 Mon Sep 17 00:00:00 2001 From: Robin Scheibler Date: Wed, 22 Nov 2023 23:57:11 +0900 Subject: [PATCH] Fixes #191, a bug when setting air abosrption coefficients manually. Improves the doc. --- CHANGELOG.rst | 2 + docs/pyroomacoustics.bss.rst | 2 +- docs/pyroomacoustics.doa.normmusic.rst | 4 +- docs/pyroomacoustics.doa.rst | 1 + pyroomacoustics/room.py | 55 ++++++++++++++++++-- pyroomacoustics/tests/test_air_absorption.py | 37 +++++++++++++ 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 pyroomacoustics/tests/test_air_absorption.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 75cdc20f..a3b08602 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,6 +33,8 @@ Bugfix - Fixes a bug when using randomized image source model with a 2D room (#315) by @hrosseel +- Fixes a bug when setting the air absorption coefficients to custom values (#191), + adds a test, and more details in the doc `0.7.3`_ - 2022-12-05 diff --git a/docs/pyroomacoustics.bss.rst b/docs/pyroomacoustics.bss.rst index 03778cb0..734f0a82 100644 --- a/docs/pyroomacoustics.bss.rst +++ b/docs/pyroomacoustics.bss.rst @@ -20,4 +20,4 @@ Algorithms pyroomacoustics.bss.sparseauxiva pyroomacoustics.bss.common pyroomacoustics.bss.fastmnmf - pytoomacoustics.bss.fastmnmf2 + pyroomacoustics.bss.fastmnmf2 diff --git a/docs/pyroomacoustics.doa.normmusic.rst b/docs/pyroomacoustics.doa.normmusic.rst index d5e6ee40..55e4c3b4 100644 --- a/docs/pyroomacoustics.doa.normmusic.rst +++ b/docs/pyroomacoustics.doa.normmusic.rst @@ -1,5 +1,5 @@ -pyroomacoustics.doa.normmusic module -==================================== +NormMUSIC +========= .. automodule:: pyroomacoustics.doa.normmusic :members: diff --git a/docs/pyroomacoustics.doa.rst b/docs/pyroomacoustics.doa.rst index accce30b..d7db3e66 100644 --- a/docs/pyroomacoustics.doa.rst +++ b/docs/pyroomacoustics.doa.rst @@ -17,6 +17,7 @@ Algorithms pyroomacoustics.doa.cssm pyroomacoustics.doa.frida pyroomacoustics.doa.music + pyroomacoustics.doa.normmusic.rst pyroomacoustics.doa.srp pyroomacoustics.doa.tops pyroomacoustics.doa.waves diff --git a/pyroomacoustics/room.py b/pyroomacoustics/room.py index 95db0cac..a0c9dea4 100644 --- a/pyroomacoustics/room.py +++ b/pyroomacoustics/room.py @@ -482,6 +482,36 @@ - ``floor``/``ceiling`` for the walls int x-y plane with small/large z coordinates, respectively +Air Absorption +-------------- + +The absorption of sound energy by air is frequency dependent. +The absorption is described the frequency dependent coefficient :math:`\\alpha(f)` and the energy decreases with distance as :math:`e^{-\\alpha(f) d}`. +This can be turned simply by providing the keyword argument ``air_absorption=True`` to the room constructor or calling ``set_absorption()`` on an existing room. +The coefficients are also temperature and humidity dependent and the default values are as follows. + +========= ======== ====== ====== ====== ===== ===== ===== ===== ===== +Temp. (C) Hum. (%) 125 Hz 250 Hz 500 Hz 1 kHz 2 kHz 4 kHz 8 kHz +========= ======== ====== ====== ====== ===== ===== ===== ===== ===== +10 30-50 0.1 0.2 0.5 1.1 2.7 9.4 29.0 x1e-3 +10 50-70 0.1 0.2 0.5 0.8 1.8 5.9 21.1 x1e-3 +10 70-90 0.1 0.2 0.5 0.7 1.4 4.4 15.8 x1e-3 +20 30-50 0.1 0.3 0.6 1.0 1.9 5.8 20.3 x1e-3 +20 50-70 0.1 0.3 0.6 1.0 1.7 4.1 13.5 x1e-3 +20 70-90 0.1 0.3 0.6 1.1 1.7 3.5 10.6 x1e-3 +========= ======== ====== ====== ====== ===== ===== ===== ===== ===== + +It is possible to set custom coefficients by providing a lists of coefficients and corresponding frequencies. +If the frequencies are not provided, the default values of 125 Hz to 8 kHz octave bands are assumed. +Note, that the number of octave bands will depend on the sampling frequency used. +For 16 kHz, there will be 7 octave bands. +If less than 7 coefficients are provided, or if the center frequencies do not correspond, a simple interpolation is used to fill the missing values. +Missing values at end of the array are simply replicated from the last value. + +.. code-block:: python + + room.set_air_absorption([0.1, 0.2, 0.4, 1.3, 2.8, 9.4, 23.0]) + Controlling the signal-to-noise ratio ------------------------------------- @@ -1128,14 +1158,29 @@ def unset_ray_tracing(self): self.simulator_state["rt_needed"] = False self._update_room_engine_params() - def set_air_absorption(self, coefficients=None): + def set_air_absorption( + self, coefficients=None, center_freqs=None, interp_kind="linear" + ): """ Activates or deactivates air absorption in the simulation. Parameters ---------- - coefficients: list of float - List of air absorption coefficients, one per octave band + coefficients: list of float, optional + Optional list of air absorption coefficients, one per octave band. + If not provided, values corresponding to the temperature and humidity + of the room are used. + center_freqs: list, optional + The optional list of center frequencies for the octave bands. + If not provided, the values of the default ocatave bands are used. + interp_kind: str + Specifies the kind of interpolation as a string (‘linear’, + ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘previous’, + ‘next’, where ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’ refer to a + spline interpolation of zeroth, first, second or third order; + ‘previous’ and ‘next’ simply return the previous or next value of + the point) or as an integer specifying the order of the spline + interpolator to use. Default is ‘linear’. """ self.simulator_state["air_abs_needed"] = True @@ -1143,7 +1188,9 @@ def set_air_absorption(self, coefficients=None): self.air_absorption = self.octave_bands(**self.physics.get_air_absorption()) else: # ignore temperature and humidity if coefficients are provided - self.air_absorption = self.physics().get_air_absorption() + self.air_absorption = self.octave_bands( + coeffs=coefficients, center_freqs=center_freqs, interp_kind=interp_kind + ) def unset_air_absorption(self): """Deactivates air absorption in the simulation""" diff --git a/pyroomacoustics/tests/test_air_absorption.py b/pyroomacoustics/tests/test_air_absorption.py new file mode 100644 index 00000000..da7ca553 --- /dev/null +++ b/pyroomacoustics/tests/test_air_absorption.py @@ -0,0 +1,37 @@ +import pyroomacoustics as pra +import numpy as np +import pytest + + +@pytest.fixture +def room(): + fs = 16000 + c = pra.constants.get("c") + room_dim = np.array([c, c, 2 * c]) + src = np.ones(3) * 0.5 * c + mic = np.array([0.5, 0.5, 1.5]) * c + mat = pra.Material(energy_absorption="hard_surface") + room = ( + pra.ShoeBox(room_dim, fs, max_order=1, materials=mat) + .add_source(src) + .add_microphone(mic) + ) + return room + + +def test_set_air_absorption_1(room): + air_abs = 0.5 + room.set_air_absorption([air_abs]) + + air_abs_coeffs = room.air_absorption + assert len(air_abs_coeffs) == 7 + assert all([a == air_abs for a in air_abs_coeffs]) + + +def test_set_air_absorption_2(room): + air_abs = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7] + room.set_air_absorption(air_abs) + + air_abs_coeffs = room.air_absorption + assert len(air_abs_coeffs) == 7 + assert all(air_abs == air_abs_coeffs)