Skip to content

Commit

Permalink
Fixes #191 a bug when setting air absorption coefficients manually (#330
Browse files Browse the repository at this point in the history
)

* Fixes #191, a bug when setting air abosrption coefficients manually

* Improves the doc.

* isort
  • Loading branch information
fakufaku authored Nov 24, 2023
1 parent df8af24 commit 52b4eee
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/pyroomacoustics.bss.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ Algorithms
pyroomacoustics.bss.sparseauxiva
pyroomacoustics.bss.common
pyroomacoustics.bss.fastmnmf
pytoomacoustics.bss.fastmnmf2
pyroomacoustics.bss.fastmnmf2
4 changes: 2 additions & 2 deletions docs/pyroomacoustics.doa.normmusic.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pyroomacoustics.doa.normmusic module
====================================
NormMUSIC
=========

.. automodule:: pyroomacoustics.doa.normmusic
:members:
Expand Down
1 change: 1 addition & 0 deletions docs/pyroomacoustics.doa.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 51 additions & 4 deletions pyroomacoustics/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------------------------------
Expand Down Expand Up @@ -1128,22 +1158,39 @@ 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
if coefficients is 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"""
Expand Down
38 changes: 38 additions & 0 deletions pyroomacoustics/tests/test_air_absorption.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import numpy as np
import pytest

import pyroomacoustics as pra


@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)

0 comments on commit 52b4eee

Please sign in to comment.