Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/images/anim_fdtd_metadiffuser.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/anim_fdtd_metadiffuser.webm
Binary file not shown.
Binary file added .github/images/anim_fdtd_metadiffuser_dark.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/anim_fdtd_metadiffuser_dark.webm
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/anim_fdtd_metadiffuser_es.webm
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/anim_fdtd_metadiffuser_poster.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
425 changes: 425 additions & 0 deletions .github/images/metadiffuser_geometry.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
425 changes: 425 additions & 0 deletions .github/images/metadiffuser_geometry_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
425 changes: 425 additions & 0 deletions .github/images/metadiffuser_geometry_es.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
425 changes: 425 additions & 0 deletions .github/images/metadiffuser_geometry_es_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
457 changes: 457 additions & 0 deletions .github/images/metadiffuser_polar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
457 changes: 457 additions & 0 deletions .github/images/metadiffuser_polar_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
457 changes: 457 additions & 0 deletions .github/images/metadiffuser_polar_es.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
457 changes: 457 additions & 0 deletions .github/images/metadiffuser_polar_es_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,12 @@ cycle and warn on use; they are removed in 4.0.
| `quadratic_residue_sequence` | `function` | **Quadratic residue sequence s_n (Cox & D'Antonio Eq. 10.2).**<br>• `prime`: odd prime generator N | `quadratic_residue_sequence(7) # [0 1 4 2 2 4 1]`<br><br>• s_n = n² mod N |
| `qrd_well_depths` | `function` | **QRD well depths d_n (Cox & D'Antonio Eq. 10.3).**<br>• `prime`: generator N<br>• `design_frequency` f0 [Hz]<br>• `speed_of_sound` c [m/s] (Default: 343) | `qrd_well_depths(7, 500.0) # d_max 0.196 m`<br><br>• d_n = s_n λ0/(2N) |
| `plot_qrd_geometry` | `function` | **To-scale QRD well profile.**<br>• `depths` d_n [m], `well_width` w [m]<br>• `periods` (Default: 1), `fin_width` [m] (Default: w/12)<br>• `language` | `plot_qrd_geometry(qrd_well_depths(7, 500.0), 0.12, periods=2)`<br><br>• Also `DiffuserPolarResponse.plot_geometry()` |
| `MetadiffuserWell` | `dataclass` | **One slit of a metadiffuser panel (Jiménez et al. Sci. Rep. 2017).**<br>• `slit_height` h [m]<br>• `resonators`: tuple of `HelmholtzResonator`, face to backing<br>• `None` in a well sequence = flat rigid strip (R = 1) | `MetadiffuserWell(14.7e-3, (hr, hr))`<br><br>• lattice a = L/M |
| `metadiffuser_reflection` | `function` | **Per-well reflection spectra R_n(f) of a metadiffuser.**<br>• `frequency` f [Hz], `wells`: `MetadiffuserWell`/`None` sequence<br>• `depth` L, `period` d [m]; `angle` θ [rad] (Default: 0)<br>• `resonator_geometry` `"slit"`/`"square"` (Default: slit)<br>• 2-D visco-thermal TMM per slit | `panel = metadiffuser_reflection(f, wells, depth=0.02, period=0.07)`<br><br>• `MetadiffuserResult` |
| `MetadiffuserResult` | `dataclass` | **Metadiffuser spectra, one reflection row per well.**<br>• `reflection` (N, F), `well_absorption` (N, F)<br>• `absorption`: face average 1 − mean\|R_n\|²<br>• retains `wells`/`depth`/`period` | `panel.plot()`; `panel.plot_geometry()`<br><br>• `.plot()` α per well; `.plot_geometry()` panel section |
| `metadiffuser_polar_response` | `function` | **Far-field polar response of a metadiffuser at one frequency.**<br>• `frequency` f [Hz], `wells`, `depth` L, `period` d [m]<br>• `angles` [°], `source_angle` ψ [°], `periods` (Default: 1)<br>• Fraunhofer of R_n(f), no obliquity factor (Sci. Rep. Eq. (1)) | `pol = metadiffuser_polar_response(2000.0, wells, depth=0.02, period=0.07, periods=6)`<br><br>• `DiffuserPolarResponse` |
| `metadiffuser_diffusion_spectrum` | `function` | **Normalized diffusion spectrum d_n(f) of a metadiffuser.**<br>• `frequencies` [Hz], `wells`, `depth` L, `period` d [m]<br>• normalised against the same-footprint flat panel<br>• ISO 17497-2 directional coefficient per band | `metadiffuser_diffusion_spectrum(f, wells, depth=0.02, period=0.07)`<br><br>• `DiffusionSpectrum` |
| `plot_metadiffuser_panel_geometry` | `function` | **To-scale metadiffuser panel cross-section.**<br>• `wells`, `depth` L, `period` d [m]<br>• numbered slits, resonators shelved into the septum<br>• `language` | `plot_metadiffuser_panel_geometry(wells, depth=0.02, period=0.07)`<br><br>• Also `MetadiffuserResult.plot_geometry()` |
| `predict_diffuser_polar_response` | `function` | **Predicted far-field polar response (Cox & D'Antonio Eq. 5.8).**<br>• `well_width` w [m], `frequency` f [Hz]<br>• `depths` d_n [m] or `reflection` R_n (exactly one)<br>• `angles` [°] (Default: semicircle), `source_angle` ψ [°]<br>• `periods` Np (Default: 1) | `s = predict_diffuser_polar_response(0.10, 2000.0, depths=d, periods=5)`<br><br>• `DiffuserPolarResponse` |
| `predicted_diffusion_spectrum` | `function` | **Predicted diffusion spectrum d(f) of a design.**<br>• `well_width` [m], `frequencies` [Hz]<br>• `depths` d_n [m]<br>• `periods` (Default: 1)<br>• `normalize`: also d_n vs flat reference (Default: True) | `res = predicted_diffusion_spectrum(0.10, f, depths=d, periods=5)`<br><br>• `DiffusionSpectrum` |
| `DiffuserPolarResponse` | `dataclass` | **Predicted diffuser polar response.**<br>• `frequency` [Hz]<br>• `angles` [°], `levels` [dB] (peak at 0)<br>• `coefficient`: d_θ<br>• `.plot()` | `s.coefficient` |
Expand Down
126 changes: 126 additions & 0 deletions docs/surface-scattering.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,124 @@ plt.show()

</details>

### Metadiffusers: deep-subwavelength Schroeder diffusers

A metadiffuser replaces the deep wells of a Schroeder diffuser with thin
slits loaded by Helmholtz resonators (Jiménez, Cox, Romero-García and Groby,
2017). Below their resonance the resonators slow the sound inside each slit,
so a panel a few centimetres thick reaches the reflection phases that a
classical phase grating needs tens of centimetres of depth for, and driving
a slit to critical coupling adds a perfectly absorbing state, the `0` that
ternary sequences require. `metadiffuser_reflection` runs the slit
transfer-matrix chain of the [slow-sound absorber](materials.md) once per
well (two-dimensional resonators, visco-thermal losses and end corrections
included) and returns the per-well complex reflection $R_n(f)$;
`metadiffuser_polar_response` and `metadiffuser_diffusion_spectrum` reduce
that spatial profile through the same Fraunhofer far field and ISO 17497-2
coefficient used for the classical designs above.

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/metadiffuser_geometry_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/metadiffuser_geometry.svg" alt="To-scale cross-section of the published quadratic-residue metadiffuser: a 350 by 20 millimetre panel over a rigid backing with five numbered slits opening at the face, each loaded by two Helmholtz resonators whose necks and cavities shelve sideways into the septum between slits; dimension lines mark the 350 millimetre width, the 70 millimetre pitch, the 14.7 millimetre first slit and the 20 millimetre depth, with the incident sound arriving from above" width="92%"></picture>

The published quadratic-residue design packs the whole diffuser into a
35 cm x 2 cm panel. Its first slit reaches critical coupling (the reflection
zero the ternary `0` state is built from), and at the 2 kHz evaluation
frequency the panel scatters like the 27.4 cm deep QRD it mimics:

```python
import numpy as np
from phonometry import (
HelmholtzResonator,
MetadiffuserWell,
metadiffuser_polar_response,
metadiffuser_reflection,
)

# The published quadratic-residue metadiffuser: five slits with two
# resonators each in a 35 cm x 2 cm panel (7 cm pitch), tuned to mimic a
# QRD designed for 500 Hz whose wells would run up to 27.4 cm deep.
mm = 1e-3
rows = [ # slit h, neck l_n, cavity l_c, neck w_n, cavity w_c [mm]
(14.7, 13.0, 16.4, 6.2, 9.0),
(30.9, 9.1, 4.3, 3.5, 9.0),
(30.9, 9.1, 4.3, 3.5, 9.0),
(15.7, 13.3, 17.0, 6.3, 9.0),
(20.3, 18.0, 20.7, 3.2, 9.0),
]
wells = [
MetadiffuserWell(
h * mm,
2 * (HelmholtzResonator(ln * mm, wn * mm, lc * mm, wc * mm),),
)
for h, ln, lc, wn, wc in rows
]

f = np.arange(1800.0, 2601.0, 5.0)
panel = metadiffuser_reflection(f, wells, depth=0.02, period=0.07)
alpha1 = panel.well_absorption[0]
print(round(float(alpha1.max()), 2), int(f[alpha1.argmax()])) # 0.99 2305

polar = metadiffuser_polar_response(2000.0, wells, depth=0.02,
period=0.07, periods=6)
print(round(polar.coefficient, 2)) # 0.32
```

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/metadiffuser_polar_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/metadiffuser_polar.svg" alt="Semicircular polar plot at 2 kilohertz comparing the far-field response of the 2 centimetre metadiffuser panel, drawn as a solid line, with the 27.4 centimetre deep quadratic residue diffuser it mimics, drawn dashed: the two grating-lobe patterns overlap almost exactly across the whole minus 90 to plus 90 degree arc" width="92%"></picture>

<details>
<summary>Show the code for this figure</summary>

```python
import numpy as np
from phonometry import (
HelmholtzResonator,
MetadiffuserWell,
materials,
metadiffuser_polar_response,
)

mm = 1e-3
rows = [
(14.7, 13.0, 16.4, 6.2, 9.0),
(30.9, 9.1, 4.3, 3.5, 9.0),
(30.9, 9.1, 4.3, 3.5, 9.0),
(15.7, 13.3, 17.0, 6.3, 9.0),
(20.3, 18.0, 20.7, 3.2, 9.0),
]
wells = [
MetadiffuserWell(
h * mm,
2 * (HelmholtzResonator(ln * mm, wn * mm, lc * mm, wc * mm),),
)
for h, ln, lc, wn, wc in rows
]

# The metadiffuser panel and the QRD it was tuned to at 2 kHz, both with
# six repetitions of the period.
meta = metadiffuser_polar_response(2000.0, wells, depth=0.02, period=0.07,
periods=6)
sequence = np.roll(materials.quadratic_residue_sequence(5), -1)
depths = sequence * (343.0 / 500.0) / (2 * 5)
qrd = materials.predict_diffuser_polar_response(
0.07, 2000.0, depths=depths, periods=6, include_obliquity=False,
)

ax = meta.plot(marker="", linewidth=2.2, label="Metadiffuser, panel 2 cm")
qrd.plot(ax=ax, marker="", linewidth=1.6, linestyle="--",
label="QRD, wells up to 27.4 cm")
ax.legend(loc="lower center")
```

</details>

The far-field overlay above is the frequency-domain summary; the FDTD
animation below meshes both panels for real (the metadiffuser at 0.25 mm, slits,
necks and cavities included) and lets the same 2 kHz wavefront hit them: the
27 cm QRD and the 2 cm panel throw out nearly the same scattered fan.

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/anim_fdtd_metadiffuser_dark.gif"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/anim_fdtd_metadiffuser.gif" alt="Animation: a 2 kHz plane wavefront hits a Schroeder diffuser with wells down to 27 centimetres and, beside it, the 2 centimetre metadiffuser whose real slits and resonators are meshed at 0.25 millimetres; the total field and the persistent scattered envelope show both panels spraying nearly identical fans, with the arc diffusion coefficients annotated" width="640" height="360" loading="lazy"></picture>

[Watch the high-resolution video (WebM)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/anim_fdtd_metadiffuser.webm)

## Scattering or diffusion? Two coefficients, two jobs

The two coefficients above are routinely treated as interchangeable, in
Expand Down Expand Up @@ -741,6 +859,14 @@ print(round(s_min, 3), round(s_max, 3)) # 0.078 0.086 (metres)

## References

- Jiménez, N., Cox, T. J., Romero-García, V., & Groby, J.-P. (2017).
Metadiffusers: Deep-subwavelength sound diffusers. *Scientific Reports*,
7, 5389.
[doi:10.1038/s41598-017-05710-5](https://doi.org/10.1038/s41598-017-05710-5).
The metadiffuser model implemented here: slits loaded by Helmholtz
resonators reproduce Schroeder phase profiles and ternary sequences from
panels 1/46 to 1/20 of the design wavelength thick.

- Cox, T. J., & D'Antonio, P. (2017). *Acoustic absorbers and diffusers:
Theory, design and application* (3rd ed.). CRC Press.
ISBN 978-1-4987-4099-9.
Expand Down
3 changes: 3 additions & 0 deletions scripts/api_taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class Section:
"phonometry.materials.slow_sound_absorber",
"phonometry.materials.scattering_diffusion",
"phonometry.materials.diffuser_design",
"phonometry.materials.metadiffuser",
"phonometry.materials.road_absorption",
),
),
Expand Down Expand Up @@ -353,6 +354,8 @@ class Section:
"phonometry.materials.slow_sound_absorber",
"plot_slit_absorber_geometry": "phonometry.materials.slow_sound_absorber",
"plot_qrd_geometry": "phonometry.materials.diffuser_design",
"plot_metadiffuser_panel_geometry": "phonometry.materials.metadiffuser",
"DEFAULT_POLAR_ANGLES": "phonometry.materials.diffuser_design",
"plot_impedance_tube_geometry": "phonometry.materials.impedance_tube",
"plot_transmission_tube_geometry": "phonometry.materials.impedance_tube",
"plot_silencer_geometry": "phonometry.noise_control.silencers",
Expand Down
Loading
Loading