Skip to content

Commit

Permalink
Fixes from_corner/extrude for mixed single/multi-band materials (#388)
Browse files Browse the repository at this point in the history
Fixes a bug where the single/multi-band materials is not properly handled when using from_corners together with extrude. (issue #381)
  • Loading branch information
fakufaku authored Dec 8, 2024
1 parent d8d5e84 commit 033126f
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 14 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ Bugfix
directivity to ``Room.add_microphone_array``, the directivity was dropped
from the object.

- Fixes issues #381: When creating a room with from_corners with multi-band
material, and then making it 3D with ``extrude`` with a single band material
for the floor and ceiling, an error would occur.
After the fix, the materials for floor and ceiling are automatically extended
to multi-band, as expected.

- Fixes issue #380: Caused by the attribute ``cartesian`` of ``GridSphere`` not
being set properly when the grid is only initialized with a number of points.

Expand All @@ -30,7 +36,7 @@ Bugfix
Changed
~~~~~~~

- Makes the ``pyroomacoustics.utilities.resample`` backend is made configurable
- Makes the ``pyroomacoustics.utilities.resample`` backend configurable
to avoid ``soxr`` dependency. The resample backend is configurable to
``soxr``, ``samplerate``, if these packages are available, and otherwise
falls back to ``scipy.signal.resample_poly``.
Expand Down
58 changes: 45 additions & 13 deletions pyroomacoustics/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -1395,24 +1395,45 @@ def extrude(self, height, v_vec=None, absorption=None, materials=None):
if libroom.area_2d_polygon(floor_corners) <= 0:
floor_corners = np.fliplr(floor_corners)

walls = []
wall_corners = {}
wall_materials = {}
for i in range(nw):
corners = np.array(
name = str(i)
wall_corners[name] = np.array(
[
np.r_[floor_corners[:, i], 0],
np.r_[floor_corners[:, (i + 1) % nw], 0],
np.r_[floor_corners[:, (i + 1) % nw], 0] + height * v_vec,
np.r_[floor_corners[:, i], 0] + height * v_vec,
]
).T
walls.append(
wall_factory(
corners,
self.walls[i].absorption,
self.walls[i].scatter,
name=str(i),

if len(self.walls[i].absorption) == 1:
# Single band
wall_materials[name] = Material(
energy_absorption=float(self.walls[i].absorption),
scattering=float(self.walls[i].scatter),
)
elif len(self.walls[i].absorption) == self.octave_bands.n_bands:
# Multi-band
abs_dict = {
"coeffs": self.walls[i].absorption,
"center_freqs": self.octave_bands.centers,
"description": "",
}
sca_dict = {
"coeffs": self.walls[i].scatter,
"center_freqs": self.octave_bands.centers,
"description": "",
}
wall_materials[name] = Material(
energy_absorption=abs_dict,
scattering=sca_dict,
)
else:
raise ValueError(
"Encountered a material with inconsistent number of bands."
)
)

############################
# BEGIN COMPATIBILITY CODE #
Expand Down Expand Up @@ -1477,12 +1498,23 @@ def extrude(self, height, v_vec=None, absorption=None, materials=None):
# we need the floor corners to ordered clockwise (for the normal to point outward)
new_corners["floor"] = np.fliplr(new_corners["floor"])

for key in ["floor", "ceiling"]:
# Concatenate new walls param with old ones.
wall_corners.update(new_corners)
wall_materials.update(materials)

# If some of the materials used are multi-band, we need to resample
# all of them to have the same number of values
if not Material.all_flat(wall_materials):
for name, mat in wall_materials.items():
mat.resample(self.octave_bands)

walls = []
for key, corners in wall_corners.items():
walls.append(
wall_factory(
new_corners[key],
materials[key].absorption_coeffs,
materials[key].scattering_coeffs,
corners,
wall_materials[key].absorption_coeffs,
wall_materials[key].scattering_coeffs,
name=key,
)
)
Expand Down
68 changes: 68 additions & 0 deletions pyroomacoustics/tests/test_from_corners_extrude.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import numpy as np
import pytest

import pyroomacoustics as pra

_FS = 16000
_MAX_ORDER = 3


def test_from_corner_extrude():

room_dim = [3, 4, 5]
# This test is sensitive to the selection of this value.
# If some symmetries are present, for some reasons differences between
# the two simulated methods happen.
src_loc = [1.001, 0.999, 1.002]
mic_loc = [2, 3, 4]
mat = pra.Material(energy_absorption=0.1)

room_ref = pra.ShoeBox(room_dim, fs=_FS, max_order=_MAX_ORDER, materials=mat)
room_ref.add_source(src_loc).add_microphone(mic_loc)
room_ref.compute_rir()

# Now construct the same room with the other set of primitives.
corners = np.array(
[[0, 0], [room_dim[0], 0], [room_dim[0], room_dim[1]], [0, room_dim[1]]]
).T
room = pra.Room.from_corners(corners, fs=_FS, max_order=_MAX_ORDER, materials=mat)
room.extrude(height=room_dim[2], materials=mat)
room.add_source(src_loc).add_microphone(mic_loc)
room.compute_rir()

assert np.allclose(room_ref.rir[0][0], room.rir[0][0], rtol=1e-4, atol=1e-4)


def test_from_corner_extrude_different_materials():

room_dim = [3, 4, 5]
# This test is sensitive to the selection of this value.
# If some symmetries are present, for some reasons differences between
# the two simulated methods happen.
src_loc = [1.001, 0.999, 1.002]
mic_loc = [2, 3, 4]
mat1 = "hard_surface"
mat2 = 0.1

materials = pra.make_materials(
east=mat1, west=mat1, south=mat1, north=mat1, floor=mat2, ceiling=mat2
)
room_ref = pra.ShoeBox(room_dim, fs=_FS, max_order=_MAX_ORDER, materials=materials)
room_ref.add_source(src_loc).add_microphone(mic_loc)
room_ref.compute_rir()

# Now construct the same room with the other set of primitives.
corners = np.array(
[[0, 0], [room_dim[0], 0], [room_dim[0], room_dim[1]], [0, room_dim[1]]]
).T
room = pra.Room.from_corners(
corners,
fs=_FS,
max_order=_MAX_ORDER,
materials=pra.Material(energy_absorption=mat1),
)
room.extrude(height=room_dim[2], materials=pra.Material(energy_absorption=mat2))
room.add_source(src_loc).add_microphone(mic_loc)
room.compute_rir()

assert np.allclose(room_ref.rir[0][0], room.rir[0][0], rtol=1e-4, atol=1e-4)

0 comments on commit 033126f

Please sign in to comment.