[READ-ONLY] Mirror of https://github.com/jmrplens/PyOctaveBand. [Python3] Octave-Band and Fractional Octave-Band filter. For signal in time domain. jmrplens.github.io/PyOctaveBand/
acoustics audio filter frequency frequency-analysis frequency-domain octave python3 signal time-domain
0

Configure Feed

Select the types of activity you want to include in your feed.

docs(site): full functionality coverage + thematic sidebar reorganization (#95)

Bring the Astro/Starlight docs site to parity with the library's implemented
functionality and reorganize the sidebar into thematic groups (docs-only).

- New bilingual guides (EN + ES): Human Vibration (ISO 8041-1 / 2631 / 5349 /
Directive 2002/44/EC), Acoustic Materials (ISO 11654 / 9053 / 10534 /
ASTM E2611), Surface Scattering (ISO 17497 / 13472).
- Split Room & Building Acoustics into 'Room Acoustics' (ISO 18233 / 3382 / 354)
and a new 'Building Acoustics & Sound Insulation' guide (ISO 16283 / 717 /
10140, EN 12354, ISO 12999-1).
- Sound Power extended to five methods (added ISO 3745 anechoic and ISO 9614-3
precision-intensity-scanning sections).
- Sidebar reorganized from a flat 12-item list into eight thematic groups,
translated in Spanish.

Site build, internal-link validation and html-validate all pass.

authored by

José M. Requena Plens and committed by
GitHub
(Jul 9, 2026, 7:02 AM +0200) f41dedb0 603fc8d4

+3791 -1313
+47 -9
site/astro.config.mjs
··· 270 270 items: ['getting-started'], 271 271 }, 272 272 { 273 - label: 'Guides', 274 - translations: { es: 'Guías' }, 273 + label: 'Signal processing & instrumentation', 274 + translations: { es: 'Procesado e instrumentación' }, 275 275 items: [ 276 276 'guides/filter-banks', 277 + 'guides/block-processing', 278 + 'guides/multichannel', 279 + 'guides/calibration', 280 + ], 281 + }, 282 + { 283 + label: 'Levels & weighting', 284 + translations: { es: 'Niveles y ponderación' }, 285 + items: [ 286 + 'guides/levels', 277 287 'guides/weighting', 278 288 'guides/time-weighting', 279 - 'guides/levels', 280 - 'guides/psychoacoustics', 289 + ], 290 + }, 291 + { 292 + label: 'Perception & speech', 293 + translations: { es: 'Percepción e inteligibilidad' }, 294 + items: ['guides/psychoacoustics'], 295 + }, 296 + { 297 + label: 'Sound power & intensity', 298 + translations: { es: 'Potencia e intensidad' }, 299 + items: [ 281 300 'guides/intensity', 282 - 'guides/room-acoustics', 283 - 'guides/outdoor-propagation', 284 301 'guides/sound-power', 285 - 'guides/calibration', 286 - 'guides/block-processing', 287 - 'guides/multichannel', 288 302 ], 303 + }, 304 + { 305 + label: 'Room acoustics', 306 + translations: { es: 'Acústica de salas' }, 307 + items: [ 308 + 'guides/room-acoustics', 309 + 'guides/materials', 310 + 'guides/surface-scattering', 311 + ], 312 + }, 313 + { 314 + label: 'Building acoustics & insulation', 315 + translations: { es: 'Acústica de la edificación y aislamiento' }, 316 + items: ['guides/building-acoustics'], 317 + }, 318 + { 319 + label: 'Environmental acoustics', 320 + translations: { es: 'Acústica ambiental' }, 321 + items: ['guides/outdoor-propagation'], 322 + }, 323 + { 324 + label: 'Human vibration', 325 + translations: { es: 'Vibración en humanos' }, 326 + items: ['guides/human-vibration'], 289 327 }, 290 328 { 291 329 label: 'Reference',
+660
site/src/content/docs/es/guides/building-acoustics.md
··· 1 + --- 2 + title: "Acústica de la edificación y aislamiento" 3 + description: "Aislamiento en campo a ruido aéreo, a impactos y de fachadas (ISO 16283-1/2/3) con índices ponderados de un solo número (ISO 717-1/2), caracterización en laboratorio de elementos constructivos (ISO 10140), predicción de la transmisión por flancos (EN 12354-1/2) e incertidumbre de medición (ISO 12999-1)." 4 + --- 5 + 6 + Esta guía continúa desde la [guía de Acústica de salas](/phonometry/es/guides/room-acoustics/): 7 + la misma respuesta al impulso, medida a ambos lados de un cerramiento, da su 8 + aislamiento acústico. Donde la acústica de salas describe el campo sonoro dentro 9 + de un único recinto, la acústica de la edificación describe cuánto de ese campo 10 + pasa *entre* recintos. Esta página sigue la cadena del aislamiento: aislamiento 11 + en campo a ruido aéreo, a impactos y de fachadas con índices de un solo número 12 + (ISO 16283-1/2/3, ISO 717-1/2), la caracterización en laboratorio de un elemento 13 + constructivo (ISO 10140), la predicción del comportamiento in situ a partir de la 14 + transmisión por flancos (EN 12354-1/2) y la incertidumbre de medición que 15 + cualifica cada índice (ISO 12999-1). 16 + 17 + ## 1. Aislamiento en campo e índices de un solo número (ISO 16283-1, ISO 717-1) 18 + 19 + Para calificar una pared o un forjado, mide el nivel promediado en energía en 20 + la sala **emisora** ($L_1$) y en la sala **receptora** ($L_2$) por banda de 21 + tercio de octava y forma la diferencia de niveles $D = L_1 - L_2$. Dos 22 + normalizaciones la hacen comparable entre salas. La **diferencia de niveles 23 + estandarizada** refiere el tiempo de reverberación de la sala receptora $T$ a 24 + $T_0 = 0.5$ s (de modo que con $T = 0.5$ s, $D_{nT} = D$ exactamente), y el 25 + **índice de reducción sonora aparente** normaliza por la superficie del 26 + cerramiento $S$ y el área de absorción de Sabine $A$: 27 + 28 + $$ 29 + D_{nT} = D + 10 \log_{10} \frac{T}{T_0}, \qquad 30 + R' = D + 10 \log_{10} \frac{S}{A}, \qquad A = \frac{0.16\ V}{T}. 31 + $$ 32 + 33 + Las posiciones se promedian en energía con 34 + $L = 10 \log_{10}\left( \frac{1}{n} \sum_i 10^{L_i/10} \right)$. 35 + 36 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_es.svg" alt="Montaje de aislamiento a ruido aéreo en campo: un altavoz en la sala emisora, micrófonos promediados en energía en las salas emisora y receptora a través del cerramiento común" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_es_dark.svg" alt="Montaje de aislamiento a ruido aéreo en campo: un altavoz en la sala emisora, micrófonos promediados en energía en las salas emisora y receptora a través del cerramiento común" style="width:92%"> 37 + 38 + El espectro por bandas se reduce a un número mediante el **método de la curva 39 + de referencia** de ISO 717-1: una curva de referencia fija se desplaza en 40 + pasos de 1 dB hacia la curva medida hasta que la suma de desviaciones 41 + *desfavorables* (donde la medición cae por debajo de la referencia) es lo más 42 + grande posible pero no mayor que 32,0 dB (16 bandas de tercio de octava) o 43 + 10,0 dB (5 bandas de octava). El índice (`Rw`, `R'w`, `DnT,w` …) es la 44 + referencia desplazada leída a 500 Hz. Los **términos de adaptación 45 + espectral** $C$ (ruido rosa) y $C_{tr}$ (tráfico urbano) añaden la 46 + penalización en baja frecuencia de una fuente real. 47 + 48 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_es.png" alt="Índice de reducción sonora medido en tercios de octava con la curva de referencia de ISO 717-1 desplazada y el índice ponderado resultante a 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_es_dark.png" alt="Índice de reducción sonora medido en tercios de octava con la curva de referencia de ISO 717-1 desplazada y el índice ponderado resultante a 500 Hz" style="width:80%"> 49 + 50 + ```python 51 + import numpy as np 52 + from phonometry import airborne_insulation, weighted_rating, energy_average_level 53 + 54 + # Promedia en energía varias posiciones de micrófono en una sala (dB) 55 + print(round(float(energy_average_level([60.0, 66.0])), 1)) # 64.0 56 + 57 + # Aislamiento en campo por banda; la superficie S y el volumen V añaden R' 58 + l1 = np.full(16, 80.0) # niveles de la sala emisora 59 + l2 = np.full(16, 40.0) # niveles de la sala receptora 60 + t2 = np.full(16, 0.5) # T de la sala receptora (s) 61 + ins = airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 62 + print(round(float(ins.dnt[0]), 1)) # 40.0 (= D ya que T = T0) 63 + print(round(float(ins.r_prime[0]), 1)) # 38.0 64 + 65 + # Índice de un solo número desde un espectro R medido de 16 bandas (ISO 717-1 Anexo C) 66 + R = [20.4, 16.3, 17.7, 22.6, 22.4, 22.7, 24.8, 26.6, 67 + 28.0, 30.5, 31.8, 32.5, 33.4, 33.0, 31.0, 25.5] 68 + w = weighted_rating(R) 69 + print(w.rating, w.c, w.ctr) # 30 -2 -3 -> Rw(C;Ctr) = 30(-2;-3) 70 + 71 + w.plot() # R' medido frente a la referencia ISO 717-1 desplazada, desviaciones sombreadas (requiere matplotlib) 72 + ``` 73 + 74 + <details> 75 + <summary>Ver el código de esta figura</summary> 76 + 77 + ```python 78 + import matplotlib.pyplot as plt 79 + 80 + # En una línea — la curva medida frente a la referencia ISO 717-1 desplazada: 81 + w.plot() 82 + plt.show() 83 + 84 + # A mano, con los campos de la curva por banda que ahora lleva el resultado: 85 + fig, ax = plt.subplots() 86 + ax.semilogx(w.band_centers, w.measured, "o-", label="R' medido") 87 + ax.semilogx(w.band_centers, w.shifted_reference, "s--", label="Referencia desplazada") 88 + ax.fill_between(w.band_centers, w.measured, w.shifted_reference, 89 + where=w.measured < w.shifted_reference, interpolate=True, 90 + alpha=0.3, label="Desviaciones desfavorables") 91 + ax.set_xlabel("Frecuencia [Hz]") 92 + ax.set_ylabel("Índice de reducción sonora [dB]") 93 + ax.set_title(f"Rw = {w.rating} dB (C={w.c:+d}; Ctr={w.ctr:+d})") 94 + ax.legend() 95 + plt.show() 96 + ``` 97 + 98 + </details> 99 + 100 + Calcula `l1`, `l2` y `t2` en las mismas 16 bandas de tercio de octava de 101 + 100 Hz a 3150 Hz — obtén `t2` de 102 + `room_parameters(ir, fs, limits=(100, 3150), fraction=3).t30`, por ejemplo — y 103 + pásalos a `airborne_insulation`. Alimenta el espectro `dnt` (o `r_prime`) de esa 104 + función a `weighted_rating`, de modo que cada banda quede alineada índice a 105 + índice con la curva de referencia ISO 717-1. 106 + 107 + ### Parámetros de `airborne_insulation()` 108 + 109 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 110 + | :--- | :--- | :--- | :--- | :--- | 111 + | `l1` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Niveles de la sala emisora (2D se promedia en energía) | 112 + | `l2` | array 1D o 2D | dB | mismo número de bandas | Niveles de la sala receptora | 113 + | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 114 + | `area` | float, opcional | m² | > 0, con `volume` | Superficie del cerramiento `S` (habilita `R'`) | 115 + | `volume` | float, opcional | m³ | > 0, con `area` | Volumen de la sala receptora `V` | 116 + | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 117 + 118 + ### Parámetros de `weighted_rating()` 119 + 120 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 121 + | :--- | :--- | :--- | :--- | :--- | 122 + | `values_by_band` | array 1D | dB | 16 (tercios) o 5 (octavas) | `R`, `R'`, `DnT` … medidos por banda | 123 + | `bands` | str o `None` | — | `'third-octave'` / `'octave'` / `None` | `None` lo infiere del número de bandas | 124 + 125 + `airborne_insulation()` devuelve un `AirborneInsulationResult` (`d`, `dnt`, 126 + `r_prime` o `None`); `weighted_rating()` devuelve un `WeightedRatingResult` 127 + (`rating`, `c`, `ctr`, `unfavourable_sum`, todos enteros salvo la suma). 128 + 129 + ### Ruido de impactos (ISO 16283-2, ISO 717-2) 130 + 131 + El ruido de pisadas se califica al revés. En lugar de cuánto *bloquea* un 132 + forjado, el aislamiento a impactos mide cuánto introduce en la sala inferior 133 + una **máquina de impactos normalizada** situada en el forjado superior —así que 134 + un número *mayor* es *peor*. El nivel de presión de ruido de impactos $L_i$ 135 + promediado en energía en la sala receptora se normaliza igual que el caso 136 + aéreo, pero con un cambio de signo en el término de reverberación: 137 + 138 + $$ 139 + L'_{nT} = L_i - 10 \log_{10} \frac{T}{T_0}, \qquad 140 + L'_n = L_i + 10 \log_{10} \frac{A}{A_0}, \quad 141 + A_0 = 10\ \text{m}^2,\ A = \frac{0.16\ V}{T}. 142 + $$ 143 + 144 + El nivel de impactos **estandarizado** $L'_{nT}$ ($T_0 = 0.5$ s para viviendas) 145 + solo necesita el $T$ de la sala receptora, así que con $T = 0.5$ s es igual a 146 + $L_i$; el nivel **normalizado** $L'_n$ (referido a un área de absorción de 147 + 10 m²) necesita además el volumen de la sala receptora. Fíjate en el signo 148 + **menos** —más reverberación *reduce* $L'_{nT}$, al contrario que el $D_{nT}$ 149 + aéreo. 150 + 151 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_es.svg" alt="Montaje de aislamiento a impactos en campo: una máquina de impactos normalizada sobre el suelo de la sala emisora superior, micrófonos promediados en energía en la sala receptora inferior, y el tiempo de reverberación de la sala receptora" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_es_dark.svg" alt="Montaje de aislamiento a impactos en campo: una máquina de impactos normalizada sobre el suelo de la sala emisora superior, micrófonos promediados en energía en la sala receptora inferior, y el tiempo de reverberación de la sala receptora" style="width:92%"> 152 + 153 + El índice de un solo número (ISO 717-2) desplaza el mismo estilo de curva de 154 + referencia, pero una **desviación desfavorable se produce ahora donde la 155 + medición *supera* la referencia** (el ruido de impactos es peor cuanto más 156 + alto) —el signo opuesto a ISO 717-1. El índice (`Ln,w`, `L'n,w`, `L'nT,w`) es 157 + la referencia desplazada leída a 500 Hz; para bandas de octava se reduce además 158 + en 5 dB. El término de adaptación espectral $C_I = L_{n,\text{sum}} - 15 - L_{n,w}$ 159 + usa la suma energética sobre 100–2500 Hz (16 tercios excluyendo 3150 Hz) o 160 + 125–2000 Hz (octavas). 161 + 162 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_es.png" alt="Nivel de presión de ruido de impactos normalizado medido en tercios de octava con la curva de referencia de ISO 717-2 desplazada y el índice ponderado resultante leído a 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_es_dark.png" alt="Nivel de presión de ruido de impactos normalizado medido en tercios de octava con la curva de referencia de ISO 717-2 desplazada y el índice ponderado resultante leído a 500 Hz" style="width:80%"> 163 + 164 + ```python 165 + import numpy as np 166 + from phonometry import impact_insulation, weighted_impact_rating 167 + 168 + # 16 niveles de impactos Li en tercios de octava (100 Hz - 3150 Hz), dB, del 169 + # ejemplo resuelto del Anexo C de ISO 717-2, y el T de la sala receptora por banda. 170 + li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 171 + 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 172 + t2 = np.full(16, 0.5) 173 + 174 + imp = impact_insulation(li, t2, volume=50.0) 175 + print(round(float(imp.l_n_t[0]), 1)) # 62.1 (= Li ya que T = T0) 176 + print(round(float(imp.l_n[0]), 1)) # 64.1 normalizado a A0 = 10 m^2 177 + 178 + # Índice de impactos ponderado + término de adaptación espectral CI (ISO 717-2) 179 + res_imp = weighted_impact_rating(imp.l_n_t) 180 + print(res_imp.rating, res_imp.ci, res_imp.unfavourable_sum) # 79 -11 28.0 -> L'nT,w(CI)=79(-11) 181 + 182 + # Los datos en banda de octava llevan la reducción extra de -5 dB (Cláusula 4.3.2) 183 + octave = np.array([65.3, 64.5, 58.0, 55.8, 43.0]) 184 + print(weighted_impact_rating(octave).rating) # 54 185 + 186 + res_imp.plot() # L'nT medido frente a la referencia ISO 717-2 desplazada, exceso sombreado (requiere matplotlib) 187 + ``` 188 + 189 + <details> 190 + <summary>Ver el código de esta figura</summary> 191 + 192 + ```python 193 + import matplotlib.pyplot as plt 194 + 195 + # En una línea — L'nT medido frente a la referencia ISO 717-2 desplazada (exceso sombreado): 196 + res_imp.plot() 197 + plt.show() 198 + 199 + # A mano, con la curva por banda que ahora lleva el resultado (signo opuesto: la 200 + # desviación desfavorable está donde el nivel MEDIDO supera la referencia). 201 + # Aquí la entrada fue l_n_t, así que la magnitud valorada es el nivel de campo L'nT,w: 202 + fig, ax = plt.subplots() 203 + ax.semilogx(res_imp.band_centers, res_imp.measured, "o-", label="L'nT medido") 204 + ax.semilogx(res_imp.band_centers, res_imp.shifted_reference, "s--", label="Referencia desplazada") 205 + ax.fill_between(res_imp.band_centers, res_imp.shifted_reference, res_imp.measured, 206 + where=res_imp.measured > res_imp.shifted_reference, interpolate=True, 207 + alpha=0.3, label="Desviaciones desfavorables") 208 + ax.set_xlabel("Frecuencia [Hz]") 209 + ax.set_ylabel("Nivel de presión sonora de impacto [dB]") 210 + ax.set_title(f"L'nT,w = {res_imp.rating} dB (CI={res_imp.ci:+d})") 211 + ax.legend() 212 + plt.show() 213 + ``` 214 + 215 + </details> 216 + 217 + Pasa el `l_n_t` (o `l_n`) de `impact_insulation` directamente a 218 + `weighted_impact_rating`; el índice y `CI` reproducen los valores del Anexo C de 219 + ISO 717-2 (tercios `L'nT,w = 79`, `CI = −11`; octava `54`, `CI = 0`). 220 + 221 + #### Parámetros de `impact_insulation()` 222 + 223 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 224 + | :--- | :--- | :--- | :--- | :--- | 225 + | `li` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | SPL de impactos promediado en energía (2D se promedia sobre las posiciones) | 226 + | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 227 + | `volume` | float, opcional | m³ | > 0 | `V` de la sala receptora (habilita `L'n`) | 228 + | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 229 + 230 + #### Parámetros de `weighted_impact_rating()` 231 + 232 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 233 + | :--- | :--- | :--- | :--- | :--- | 234 + | `values_by_band` | array 1D | dB | 16 (tercios) o 5 (octavas) | `Ln`, `L'n` o `L'nT` medidos por banda | 235 + | `bands` | str o `None` | — | `'third-octave'` / `'octave'` / `None` | `None` lo infiere del número de bandas | 236 + 237 + `impact_insulation()` devuelve un `ImpactInsulationResult` (`l_n_t`, `l_n` o 238 + `None`); `weighted_impact_rating()` devuelve un `ImpactRatingResult` (`rating`, 239 + `ci` enteros, `unfavourable_sum` en dB). 240 + 241 + ### Aislamiento a ruido aéreo de fachadas en campo (ISO 16283-3) 242 + 243 + La misma lógica fuente/receptor alcanza la **fachada** del edificio, pero ahora 244 + la fuente está *en el exterior*: un altavoz a 45° o el propio tráfico rodado. En 245 + lugar de una diferencia de niveles a través de un cerramiento interior, 246 + ISO 16283-3 referencia el nivel de la sala receptora $L_2$ al nivel **2 m frente 247 + a la fachada** $L_{1,2m}$, dando la diferencia de niveles $D_{2m}$ y, exactamente 248 + como en el caso a ruido aéreo, sus formas estandarizada y normalizada: 249 + 250 + $$ 251 + D_{2m} = L_{1,2m} - L_2, \quad 252 + D_{2m,nT} = D_{2m} + 10 \log_{10}\frac{T}{T_0}, \quad 253 + D_{2m,n} = D_{2m} - 10 \log_{10}\frac{A}{A_0}, 254 + $$ 255 + 256 + con $T_0 = 0.5$ s, $A_0 = 10$ m² y $A = 0.16\ V/T$ (viviendas). Cuando el 257 + micrófono se sitúa **sobre el elemento de ensayo** (nivel superficial $L_{1,s}$), 258 + el método del *elemento* también da un índice de reducción sonora aparente, que 259 + lleva una corrección fija por ángulo de incidencia: $-1.5$ dB para el método del 260 + altavoz a 45° y $-3$ dB para el método de tráfico rodado con todos los ángulos: 261 + 262 + $$ 263 + R'_{45°} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 1.5, \qquad 264 + R'_{tr,s} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 3. 265 + $$ 266 + 267 + La magnitud de fachada es a ruido aéreo, así que su índice de un solo número usa 268 + la curva de referencia de **ISO 717-1** a través de `weighted_rating` sin cambios 269 + (Anexo F). 270 + 271 + ```python 272 + import numpy as np 273 + from phonometry import facade_insulation, weighted_rating 274 + 275 + # Nivel exterior 2 m frente a la fachada, nivel de la sala receptora y T por 276 + # banda de tercio de octava; surface_level es el micrófono sobre el elemento de ensayo. 277 + l1_2m = np.full(16, 75.0) # L1,2m en el exterior 278 + l2 = np.full(16, 33.0) # L2 de la sala receptora 279 + t2 = np.full(16, 0.5) # T de la sala receptora (s) 280 + 281 + fac = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 282 + surface_level=np.full(16, 78.0), method="loudspeaker") 283 + print(round(float(fac.d_2m[0]), 1)) # 42.0 D2m = L1,2m - L2 284 + print(round(float(fac.d_2m_nt[0]), 1)) # 42.0 (= D2m ya que T = T0) 285 + print(round(float(fac.d_2m_n[0]), 1)) # 40.0 normalizado a A0 = 10 m^2 286 + print(round(float(fac.r_prime[0]), 1)) # 42.1 R'45deg (altavoz, -1.5 dB) 287 + 288 + # El método del elemento por tráfico rodado lleva en su lugar la corrección de -3 dB para todos los ángulos 289 + tr = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 290 + surface_level=np.full(16, 78.0), method="road_traffic") 291 + print(round(float(tr.r_prime[0]), 1)) # 40.6 R'tr,s (tráfico, -3 dB) 292 + 293 + # La magnitud de fachada es a ruido aéreo: valora D2m,nT con el motor de ISO 717-1 294 + print(weighted_rating(fac.d_2m_nt).rating) # 42 Dls,2m,nT,w 295 + 296 + fac.plot() # D2m,nT por banda con D2m, D2m,n y R' superpuestos (requiere matplotlib) 297 + ``` 298 + 299 + `surface_level`, `area` y `volume` son todos opcionales: solo con `l1_2m`, `l2` 300 + y `t2` la función devuelve `d_2m` y `d_2m_nt`; añade `volume` para `d_2m_n`; 301 + añade `surface_level` **y** `area` **y** `volume` para `r_prime`. Las posiciones 302 + se promedian en energía con la fórmula del nivel superficial (Cláusula 9.5.1); 303 + se asume que los niveles por banda ya están corregidos por ruido de fondo. 304 + 305 + #### Parámetros de `facade_insulation()` 306 + 307 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 308 + | :--- | :--- | :--- | :--- | :--- | 309 + | `l1_2m` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Nivel 2 m frente a la fachada `L1,2m` | 310 + | `l2` | array 1D o 2D | dB | mismo número de bandas | Niveles de la sala receptora | 311 + | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 312 + | `area` | float, opcional | m² | > 0, con `surface_level`, `volume` | Superficie del elemento de ensayo `S` (habilita `R'`) | 313 + | `volume` | float, opcional | m³ | > 0 | Sala receptora `V` (habilita `D2m,n`; requerido para `R'`) | 314 + | `surface_level` | array 1D/2D, opcional | dB | mismo número de bandas | Nivel superficial `L1,s` sobre el elemento (habilita `R'`) | 315 + | `method` | str | — | `'loudspeaker'` (−1,5 dB) / `'road_traffic'` (−3 dB) | Corrección por ángulo de incidencia de `R'` | 316 + | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 317 + | `frequencies` | array 1D, opcional | Hz | — | Centros de banda que lleva el resultado para representar | 318 + 319 + `facade_insulation()` devuelve un `FacadeInsulationResult` (`d_2m`, `d_2m_nt`, 320 + `d_2m_n` o `None`, `r_prime` o `None`, `frequencies`); pasa cualquier magnitud de 321 + fachada de 16 bandas a `weighted_rating` para su número único de ISO 717-1. 322 + 323 + ## 2. Medición en laboratorio (ISO 10140) 324 + 325 + Todo lo anterior es una medición **en campo** (las magnitudes con prima $R'$, 326 + $L'_n$): el número que un edificio real alcanza, con transmisión por flancos 327 + incluida. Para valorar un elemento por sí solo —un tipo de pared, un suelo 328 + flotante, una ventana— se lleva a un **laboratorio** cualificado (ISO 10140), 329 + donde la transmisión por flancos suprimida hace que la transmisión *directa* sea 330 + toda la historia. Las fórmulas pierden sus primas: el **índice de reducción 331 + sonora** $R$ (no $R'$) y el **nivel de impactos normalizado** $L_n$ (no $L'_n$), 332 + con el área de absorción de la sala receptora $A = 0.16\ V/T$ ahora una propiedad 333 + conocida de la instalación: 334 + 335 + $$ 336 + R = L_1 - L_2 + 10 \log_{10}\frac{S}{A}, \qquad 337 + L_n = L_i + 10 \log_{10}\frac{A}{A_0}, \quad A_0 = 10\ \text{m}^2. 338 + $$ 339 + 340 + | | Campo (ISO 16283) | Laboratorio (ISO 10140) | 341 + | :--- | :--- | :--- | 342 + | Ruido aéreo | $R'$ aparente (con flancos) | $R$ directo (flancos suprimidos) | 343 + | Impactos | $L'_n$ aparente | $L_n$ directo | 344 + | Área de absorción | medida en la sala | propiedad de la instalación | 345 + 346 + Los índices de un solo número reutilizan los mismísimos motores de ISO 717-1/2 347 + (`weighted_rating`, `weighted_impact_rating`): un espectro $R$ se valora a $R_w$ 348 + exactamente igual que un espectro $R'$ se valoraba a $R'_w$. Antes de formar el 349 + índice, los niveles de la sala receptora deben **corregirse por ruido de fondo** 350 + (Cláusula 4.3): la resta energética $10 \log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ 351 + se aplica para un margen señal-fondo de 6–15 dB, una corrección fija de 1,3 dB 352 + (el *límite de medición*) en 6 dB o por debajo, y ninguna corrección en 15 dB o 353 + por encima. 354 + 355 + ```python 356 + import numpy as np 357 + from phonometry import (lab_airborne_insulation, lab_impact_insulation, 358 + background_correction) 359 + 360 + # Niveles emisor/receptor y T de la sala receptora en las 16 bandas de tercio 361 + # de octava; S es el área libre de la abertura de ensayo, V el volumen de la sala receptora. 362 + l1 = np.full(16, 80.0) 363 + l2 = np.full(16, 40.0) 364 + t2 = np.full(16, 0.5) 365 + lab = lab_airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 366 + print(round(float(lab.r[0]), 1)) # 38.0 R = L1 - L2 + 10 lg(S/A) 367 + print(round(float(lab.absorption[0]), 1)) # 16.0 A = 0.16 V / T (m^2) 368 + print(lab.rating.rating, lab.rating.c, lab.rating.ctr) # 38 0 0 -> Rw(C;Ctr) 369 + 370 + # Impactos: el nivel de la máquina de impactos Li normalizado a A0 = 10 m^2 da Ln 371 + li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 372 + 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 373 + imp = lab_impact_insulation(li, t2, volume=50.0) 374 + print(round(float(imp.l_n[0]), 1)) # 64.1 Ln = Li + 10 lg(A/A0) 375 + print(imp.rating.rating, imp.rating.ci) # 81 -11 -> Ln,w(CI) 376 + 377 + # Corrección por ruido de fondo: márgenes 6 / 1 / 20 dB -> saturado / saturado / sin cambio 378 + corrected = background_correction([30.0, 33.0, 50.0], [24.0, 32.0, 30.0]) 379 + print(np.round(corrected, 1)) # [28.7 31.7 50.0] (saturación de 1.3 dB dos veces) 380 + 381 + lab.rating.plot() # R medido frente a la referencia ISO 717-1 desplazada (requiere matplotlib) 382 + ``` 383 + 384 + Un margen en 6 dB o por debajo emite un `LabInsulationWarning` y marca la banda 385 + como el límite de medición; captúralo con `warnings.simplefilter("error", 386 + LabInsulationWarning)`. El índice automático se forma solo cuando se suministran 387 + exactamente 16 valores en tercio de octava o 5 en octava (`rating` es `None` en 388 + caso contrario). 389 + 390 + ### Parámetros de `lab_airborne_insulation()` / `lab_impact_insulation()` 391 + 392 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 393 + | :--- | :--- | :--- | :--- | :--- | 394 + | `l1` / `l2` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Niveles emisor / receptor (ruido aéreo) | 395 + | `li` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | SPL de impactos de la máquina de impactos (impactos) | 396 + | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 397 + | `area` | float | m² | > 0 | Área libre de la abertura de ensayo `S` (solo ruido aéreo) | 398 + | `volume` | float | m³ | > 0 | Volumen de la sala receptora `V` | 399 + 400 + `lab_airborne_insulation()` devuelve un `LabAirborneInsulationResult` (`r`, 401 + `absorption`, `rating`); `lab_impact_insulation()` un 402 + `LabImpactInsulationResult` (`l_n`, `absorption`, `rating`); 403 + `background_correction(signal_and_background, background)` devuelve los niveles 404 + corregidos directamente. 405 + 406 + ## 3. Predicción del comportamiento (EN 12354) 407 + 408 + Un índice de laboratorio describe un elemento de forma aislada, pero el sonido 409 + que un edificio transmite realmente también viaja *alrededor* del cerramiento 410 + —por el suelo, por la fachada, a través de las paredes de flanco— y se vuelve a 411 + radiar en la sala receptora. Esta **transmisión por flancos** es toda la 412 + diferencia entre el $R$ de laboratorio y el $R'$ de campo. EN 12354 predice el 413 + índice aparente in situ a partir de los índices de laboratorio de los elementos 414 + más la transmisión vibratoria de sus uniones. 415 + 416 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_es.svg" alt="El camino directo Dd a través del elemento separador y los tres caminos de flanco Ff, Df y Fd en cada unión entre un elemento de flanco y el elemento separador" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_es_dark.svg" alt="El camino directo Dd a través del elemento separador y los tres caminos de flanco Ff, Df y Fd en cada unión entre un elemento de flanco y el elemento separador" style="width:92%"> 417 + 418 + Cada unión entre un elemento de flanco y el elemento separador lleva tres 419 + caminos —$Ff$ (flanco→flanco), $Df$ (directo→flanco) y $Fd$ (flanco→directo)— 420 + junto al único camino directo $Dd$. El **modelo simplificado de un solo número** 421 + los combina energéticamente (Fórmula 26): 422 + 423 + $$ 424 + R'_w = -10 \log_{10}\Big[ 10^{-R_{Dd,w}/10} 425 + + \sum 10^{-R_{Ff,w}/10} + \sum 10^{-R_{Df,w}/10} 426 + + \sum 10^{-R_{Fd,w}/10} \Big], 427 + $$ 428 + 429 + con el camino directo $R_{Dd,w} = R_{s,w} + \Delta R_{Dd,w}$ (Fórmula 27) y cada 430 + camino de flanco (Fórmula 28a) 431 + 432 + $$ 433 + R_{ij,w} = \tfrac{R_{i,w} + R_{j,w}}{2} + \Delta R_{ij,w} + K_{ij} 434 + + 10 \log_{10}\frac{S_s}{l_0\ l_f}, 435 + $$ 436 + 437 + donde $l_0 = 1$ m es la longitud de acoplamiento de referencia, $l_f$ la longitud 438 + de acoplamiento de la unión y $K_{ij}$ el **índice de reducción vibracional** de 439 + la unión (Anexo E, empírico en la relación de masas 440 + $M = \log_{10}(m'_{\perp,i}/m'_i)$). 441 + 442 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_es.png" alt="Índices de reducción sonora por camino para el ejemplo del Anexo H.3 de EN 12354-1 y la fracción de energía transmitida de cada camino, mostrando el camino directo dominando en R'w = 52 dB" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_es_dark.png" alt="Índices de reducción sonora por camino para el ejemplo del Anexo H.3 de EN 12354-1 y la fracción de energía transmitida de cada camino, mostrando el camino directo dominando en R'w = 52 dB" style="width:80%"> 443 + 444 + ```python 445 + import numpy as np 446 + from phonometry import (junction_vibration_reduction, flanking_element, 447 + predicted_airborne_insulation) 448 + 449 + # EN 12354-1 Anexo H.3: una pared separadora Rs,w = 57 dB, área Ss = 11.5 m², con 450 + # cuatro elementos de flanco. El modelo simplificado lee el Kij de cada unión a 451 + # 500 Hz a partir de la relación de masas m'perp / m' (Anexo E); aquí la unión 452 + # rígida en cruz del suelo (la relación de masas está redondeada, de ahí 12.5 vs Anexo 12.4): 453 + print(round(junction_vibration_reduction("rigid_cross", "through", 1.61), 1)) # 12.5 KFf 454 + print(round(junction_vibration_reduction("rigid_cross", "corner", 1.61), 1)) # 8.9 KFd = KDf 455 + 456 + # Construye los tres caminos de flanco (Ff, Df, Fd) de cada elemento a partir del 457 + # Kij tabulado del Anexo H, luego combina el camino directo Dd energéticamente (Fórmula 26). 458 + elements = [ # (nombre, Rw, KFf, KFd = KDf, longitud de acoplamiento lf) 459 + ("floor", 49, 12.4, 8.9, 4.50), 460 + ("ceiling", 46, 14.4, 9.2, 4.50), 461 + ("facade", 42, 12.6, 6.7, 2.55), 462 + ("int-wall", 33, 33.5, 15.7, 2.55), 463 + ] 464 + paths = [] 465 + for name, rw, k_ff, k_fd, lf in elements: 466 + paths += flanking_element(label=name, r_flanking=rw, r_separating=57, 467 + k_ff=k_ff, k_fd=k_fd, k_df=k_fd, 468 + separating_area=11.5, coupling_length=lf) 469 + 470 + res = predicted_airborne_insulation(r_direct=57.0, flanking_paths=paths) 471 + print(round(res.r_prime_w, 1)) # 52.2 -> R'w = 52 dB 472 + print(res.dominant.label, round(res.dominant.fraction, 2)) # Dd 0.33 (domina el directo) 473 + ``` 474 + 475 + Cada camino de flanco añadido rebaja estrictamente $R'_w$ por debajo del directo 476 + $R_{Dd,w} = 57$; `res.paths` expone la fracción de energía transmitida de cada 477 + camino, de modo que el camino dominante queda visible. La Cláusula 4.4.2 también 478 + impone un límite inferior $K_{ij} \ge K_{ij,\min}$ a partir de la geometría de la 479 + unión: calcúlalo con `junction_min_vibration_reduction` y pásalo a 480 + `flanking_path(..., kij_min=...)`, que eleva un $K_{ij}$ por debajo del límite 481 + hasta el mínimo: 482 + 483 + ```python 484 + from phonometry import junction_min_vibration_reduction 485 + # Kij,min = 10 lg[lf·l0·(1/Si + 1/Sj)]; los elementos grandes dan un límite bajo 486 + # (aquí negativo), así que un Kij tabulado realista rara vez se satura. 487 + print(round(junction_min_vibration_reduction(coupling_length=4.5, 488 + s_i=11.5, s_j=11.5), 1)) # -1.1 489 + ``` 490 + 491 + La contrapartida a impactos (EN 12354-2, Fórmula 21) es una resta directa: 492 + $L'_{n,w} = L_{n,w,eq} - \Delta L_w + K$, con el nivel equivalente del suelo 493 + desnudo $L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Anexo B), la mejora del 494 + revestimiento $\Delta L_w$ (ISO 717-2) y la corrección por flancos $K$ de la 495 + Tabla 1. 496 + 497 + ```python 498 + from phonometry import (equivalent_impact_level, impact_flanking_correction, 499 + predicted_impact_insulation, standardized_impact_level) 500 + 501 + # EN 12354-2 Anexo E.3: un forjado de hormigón de 0.14 m (m' = 322 kg/m²) con un 502 + # suelo flotante (ΔLw = 33 dB), salas una sobre otra, masa media de flanco 145 kg/m². 503 + ln_eq = equivalent_impact_level(322.0) # 164 - 35 lg(m') 504 + k = impact_flanking_correction(322.0, 145.0) # Tabla 1 (sep 322, flk 145) 505 + imp = predicted_impact_insulation(ln_w_eq=ln_eq, delta_l_w=33.0, k_correction=k) 506 + print(round(ln_eq, 1), k, round(imp.l_prime_n_w, 1)) # 76.2 2 45.2 -> L'n,w = 45 dB 507 + print(round(standardized_impact_level(imp.l_prime_n_w, 50.0), 1)) # 43.0 L'nT,w 508 + ``` 509 + 510 + <details> 511 + <summary>Ver el código de esta figura</summary> 512 + 513 + ```python 514 + import matplotlib.pyplot as plt 515 + 516 + # Índice de reducción sonora por camino y fracción de energía transmitida de cada 517 + # camino para el resultado del Anexo H.3 calculado arriba. 518 + labels = [p.label for p in res.paths] 519 + r_w = [p.r_w for p in res.paths] 520 + frac = [100.0 * p.fraction for p in res.paths] 521 + 522 + fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True) 523 + ax1.bar(labels, r_w, color="tab:blue") 524 + ax1.axhline(res.r_prime_w, ls="--", color="k", label=f"R'w = {res.r_prime_w:.1f} dB") 525 + ax1.set_ylabel("Rij,w del camino [dB]"); ax1.legend() 526 + ax2.bar(labels, frac, color="tab:orange") 527 + ax2.set_ylabel("Fracción de energía [%]"); ax2.set_xlabel("Camino de transmisión") 528 + for ax in (ax1, ax2): 529 + ax.tick_params(axis="x", rotation=45) 530 + fig.suptitle("EN 12354-1 Anexo H.3 — transmisión por flancos") 531 + fig.tight_layout() 532 + plt.show() 533 + ``` 534 + 535 + </details> 536 + 537 + ### Parámetros de `junction_vibration_reduction()` / `flanking_element()` 538 + 539 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 540 + | :--- | :--- | :--- | :--- | :--- | 541 + | `junction_type` | str | — | `'rigid_cross'` / `'rigid_t'` / `'flexible_t'` / `'lightweight_facade'` | Geometría de la unión (Anexo E) | 542 + | `path` | str | — | `'through'` (K13) / `'corner'` (K12 = K23) | Rama del camino | 543 + | `mass_ratio` | float | — | > 0 | `m'⊥,i / m'i` (Fórmula E.2) | 544 + | `frequency` | float | Hz | por defecto `500` | Solo `flexible_t` depende de la frecuencia | 545 + | `r_flanking` / `r_separating` | float | dB | — | Índices ponderados del elemento de flanco / separador | 546 + | `k_ff` / `k_fd` / `k_df` | float | dB | — | `Kij` de la unión para los tres caminos | 547 + | `separating_area` | float | m² | > 0 | Superficie del elemento separador `Ss` | 548 + | `coupling_length` | float | m | > 0 | Longitud de acoplamiento de la unión `lf` | 549 + | `delta_r_ff` / `delta_r_fd` / `delta_r_df` | float | dB | por defecto `0` | Mejoras del trasdosado por camino | 550 + 551 + `predicted_airborne_insulation()` devuelve un `AirbornePredictionResult` 552 + (`r_prime_w`, `r_direct_w`, `paths` de `PathContribution`, `dominant`); 553 + `predicted_impact_insulation()` un `ImpactPredictionResult` (`l_prime_n_w`, 554 + `ln_w_eq`, `delta_l_w`, `k_correction`). El modelo simplificado lleva una 555 + desviación típica declarada de unos 2 dB (Cláusula 5). 556 + 557 + ## 4. Incertidumbre de medición (ISO 12999-1) 558 + 559 + Un índice sin incertidumbre es solo medio resultado. ISO 12999-1 no vuelve a 560 + medir nada; tabula la **incertidumbre típica** $u$ de cada magnitud de 561 + aislamiento acústico —derivada de ensayos interlaboratorio— y prescribe cómo 562 + expandirla y combinarla. Qué desviación típica es $u$ depende de la **situación 563 + de medición** (Cláusula 5.2): 564 + 565 + | Situación | Significado | Incertidumbre típica $u$ | 566 + | :--- | :--- | :--- | 567 + | **A** | caracterización en laboratorio (ISO 10140) | reproducibilidad $\sigma_R$ | 568 + | **B** | misma ubicación, equipos distintos | in situ $\sigma_{situ}$ | 569 + | **C** | misma ubicación, mismo operador repetido | repetibilidad $\sigma_r$ | 570 + 571 + La incertidumbre expandida es $U = k\ u$ (Fórmula 2) con el factor de cobertura 572 + $k$ de la Tabla 8. Un intervalo bilateral $Y = y \pm U$ (Fórmula 3, $k = 1.96$ al 573 + 95 %) *informa* un valor; el factor **unilateral** ($k = 1.65$ al 95 %) *declara 574 + conformidad* con un requisito (Fórmulas 4/5). 575 + 576 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_es.png" alt="Un índice ponderado informado con su incertidumbre expandida bilateral al 95 % en las situaciones A, B y C, con la incertidumbre de reproducibilidad más ancha y la de repetibilidad más estrecha" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_es_dark.png" alt="Un índice ponderado informado con su incertidumbre expandida bilateral al 95 % en las situaciones A, B y C, con la incertidumbre de reproducibilidad más ancha y la de repetibilidad más estrecha" style="width:80%"> 577 + 578 + ```python 579 + from phonometry import (band_uncertainty, single_number_uncertainty, 580 + uncertain_value, satisfies_lower_requirement) 581 + 582 + # Situación B (mismo edificio, equipos distintos) -> la desviación típica in situ. 583 + print(single_number_uncertainty("r_w", "B")) # 0.9 dB (Tabla 3) 584 + u = band_uncertainty("airborne", "B") # u por banda (Tabla 2) 585 + print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (la banda de 500 Hz) 586 + 587 + # Informa R'w = 52 dB con un intervalo bilateral al 95 % (k = 1.96, Tabla 8): 588 + uv = uncertain_value(52.0, "rprime_w", "B") # los alias resuelven a r_w 589 + print(uv.coverage_factor, round(uv.expanded_uncertainty, 1)) # 1.96 1.8 590 + print(round(uv.lower, 1), round(uv.upper, 1)) # 50.2 53.8 -> 52 ± 1.8 dB 591 + 592 + # Declarar conformidad usa el factor UNILATERAL (k = 1.65): ¿supera R'w de forma 593 + # demostrable un requisito de 50 dB? 594 + uc = uncertain_value(52.0, "rprime_w", "B", one_sided=True) 595 + print(satisfies_lower_requirement(52.0, uc.expanded_uncertainty, 50.0)) # True 596 + ``` 597 + 598 + Las magnitudes a impactos ofrecen solo las situaciones B/C (Tabla 4, sin banda de 599 + 500 Hz en la edición de 2020), y $\Delta L$ solo la situación A. Los descriptores 600 + son insensibles a mayúsculas y con alias (`rprime_w`/`dnt_w`→`r_w`, 601 + `lprime_n_w`→`ln_w`); combina componentes independientes en cuadratura con 602 + `combine_uncertainties`, y redúcelas por $m$ mediciones independientes con 603 + `reduce_by_independent_measurements` ($u/\sqrt{m}$). 604 + 605 + <details> 606 + <summary>Ver el código de esta figura</summary> 607 + 608 + ```python 609 + import matplotlib.pyplot as plt 610 + from phonometry import uncertain_value 611 + 612 + # El mismo R'w = 52 dB informado en cada situación con su U bilateral al 95 %. 613 + situations = ["A", "B", "C"] 614 + vals = [uncertain_value(52.0, "r_w", s) for s in situations] 615 + 616 + fig, ax = plt.subplots(figsize=(7, 4)) 617 + ax.errorbar(situations, [v.value for v in vals], 618 + yerr=[v.expanded_uncertainty for v in vals], 619 + fmt="o", capsize=8, color="tab:blue") 620 + for s, v in zip(situations, vals): 621 + ax.annotate(f"±{v.expanded_uncertainty:.1f}", (s, v.upper), 622 + textcoords="offset points", xytext=(8, 4)) 623 + ax.set_ylabel("R'w [dB]"); ax.set_xlabel("Situación de medición") 624 + ax.set_title("R'w = 52 dB con incertidumbre expandida al 95 % (ISO 12999-1)") 625 + fig.tight_layout() 626 + plt.show() 627 + ``` 628 + 629 + </details> 630 + 631 + ### Parámetros de `band_uncertainty()` / `single_number_uncertainty()` / `uncertain_value()` 632 + 633 + | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 634 + | :--- | :--- | :--- | :--- | :--- | 635 + | `measurand` | str | — | `'airborne'` / `'impact'` / `'impact_reduction'` | Selecciona la Tabla 2 / 4 / 6 | 636 + | `quantity` | str | — | `'r_w'`, `'ln_w'`, `'delta_lw'` (+ alias, variantes `+c`/`+ctr`) | Descriptor de un solo número | 637 + | `situation` | str | — | `'A'` / `'B'` / `'C'` | Situación de medición (Cláusula 5.2) | 638 + | `value` | float | dB | — | Mejor estimación `y` a la que adjuntar `U` | 639 + | `coverage` | float | — | por defecto `0.95` | Nivel de confianza (Tabla 8) | 640 + | `one_sided` | bool | — | por defecto `False` | Factor unilateral para verificaciones de conformidad | 641 + | `upper_limit` | bool | — | por defecto `False` | Selecciona el límite superior σR95 (ruido aéreo, situación A) | 642 + 643 + `band_uncertainty()` devuelve una `BandUncertainty` (`frequencies`, 644 + `uncertainties`, `.to_arrays()`); `single_number_uncertainty()` un float; 645 + `uncertain_value()` un `UncertainValue` (`value`, `standard_uncertainty`, 646 + `coverage_factor`, `expanded_uncertainty`, `.lower`, `.upper`). El mapa de solo 647 + lectura `COVERAGE_FACTORS` expone la Tabla 8 indexada por `(confidence, one_sided)`. 648 + 649 + ## Véase también 650 + 651 + - [Acústica de salas](/phonometry/es/guides/room-acoustics/) — la respuesta al impulso, 652 + los parámetros de sala y la absorción sonora sobre los que se apoya la cadena de aislamiento de esta guía. 653 + - [Niveles](/phonometry/es/guides/levels/) — el promediado en energía y las métricas de 654 + nivel tras los niveles de las salas emisora/receptora. 655 + - [Bancos de filtros](/phonometry/es/guides/filter-banks/) — los filtros de octava 656 + fraccionaria IEC 61260 usados para los espectros de aislamiento. 657 + - [Potencia sonora](/phonometry/es/guides/sound-power/) — los métodos de `LW` que comparten 658 + la maquinaria del área de absorción de la sala receptora. 659 + - [Teoría](/phonometry/es/reference/theory/) — la derivación de la curva de referencia tras 660 + los índices ponderados de un solo número.
+277
site/src/content/docs/es/guides/human-vibration.md
··· 1 + --- 2 + title: "Vibración en humanos" 3 + description: "Exposición a vibración de cuerpo completo y mano-brazo: las ponderaciones frecuenciales de ISO 8041-1, el valor eficaz ponderado y las medidas de dosis de ISO 2631-1 (VDV, MTVV, MSDV, factor de cresta), el valor total de vibración y la exposición diaria de 8 horas A(8), con la orientación de exposición de ISO 5349 y los valores de acción y límite de la Directiva 2002/44/CE." 4 + --- 5 + 6 + La vibración transmitida a una persona se evalúa con la misma cadena de medida 7 + sea cual sea su origen: la aceleración se **pondera en frecuencia** para reflejar 8 + cómo responde el cuerpo a cada frecuencia, se reduce a una aceleración **eficaz 9 + ponderada** (con medidas de dosis para choques y registros largos), se combina 10 + entre ejes en un **valor total de vibración** y, por último, se normaliza a una 11 + **exposición diaria de 8 horas** `A(8)` que se compara con los valores de acción 12 + y límite de la directiva europea. 13 + 14 + Las ponderaciones se definen una sola vez, en **ISO 8041-1:2017**, como una 15 + cascada de filtros analógicos; **ISO 2631-1** las aplica a la vibración de cuerpo 16 + completo, **ISO 2631-2** a la vibración en edificios, **ISO 2631-4** al confort 17 + de marcha ferroviaria e **ISO 5349-1/-2** a la vibración transmitida a la mano. 18 + Esta página recorre toda la cadena. 19 + 20 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_human_vibration_es.svg" alt="Cadena de medida de vibración de cuerpo completo: un acelerómetro triaxial en la interfaz asiento/cuerpo de una persona sentada mide la aceleración x, y y z; cada eje se limita en banda y se pondera en frecuencia (Wk vertical, Wd horizontal) según ISO 8041-1, se reduce a un valor eficaz ponderado a_w y VDV según ISO 2631-1, se combina en el valor total de vibración a_v, se normaliza a la exposición diaria A(8) y se evalúa frente al VAE y el VLE de la Directiva 2002/44/CE" style="width:94%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_human_vibration_es_dark.svg" alt="Cadena de medida de vibración de cuerpo completo: un acelerómetro triaxial en la interfaz asiento/cuerpo de una persona sentada mide la aceleración x, y y z; cada eje se limita en banda y se pondera en frecuencia (Wk vertical, Wd horizontal) según ISO 8041-1, se reduce a un valor eficaz ponderado a_w y VDV según ISO 2631-1, se combina en el valor total de vibración a_v, se normaliza a la exposición diaria A(8) y se evalúa frente al VAE y el VLE de la Directiva 2002/44/CE" style="width:94%"> 21 + 22 + ## 1. Ponderaciones frecuenciales (ISO 8041-1) 23 + 24 + Toda ponderación de vibración humana es el producto de cuatro etapas analógicas 25 + evaluadas en $s = j\,2\pi f$ (ISO 8041-1, fórmulas (1)–(5)): un **paso-alto** y un 26 + **paso-bajo** Butterworth de segundo orden que limitan la banda, una **transición 27 + aceleración–velocidad** que porta la ganancia global $K$ y un **escalón 28 + ascendente**: 29 + 30 + $$ 31 + H(s) = H_h(s)\,H_l(s)\,H_t(s)\,H_s(s). 32 + $$ 33 + 34 + Un único conjunto de parámetros de la Tabla 3 $(f_1, Q_1, f_2, Q_2, f_3, f_4, 35 + Q_4, f_5, Q_5, f_6, Q_6, K)$ realiza las nueve ponderaciones — `Wb, Wc, Wd, We, 36 + Wf, Wh, Wj, Wk, Wm` — colapsando su etapa a la unidad cuando un corte se fija en 37 + infinito. La ponderación principal de cuerpo completo es `Wk` (vertical, 38 + superficie del asiento); `Wd` es la ponderación horizontal y `Wh` la de 39 + mano-brazo. 40 + 41 + ```python 42 + import phonometry as ph 43 + 44 + # La respuesta de ponderación global a cualquier frecuencia (ISO 8041-1, fórmula (5)). 45 + resp = ph.frequency_weighting("Wk", [1.0, 6.3096, 20.0]) 46 + print(resp.magnitude.round(3)) # [0.482 1.054 0.636] (factores) 47 + print(resp.magnitude_db.round(2)) # [-6.33 0.46 -3.93] (dB) 48 + ``` 49 + 50 + Los factores reproducen las tablas de objetivo de diseño del Anexo B de 51 + ISO 8041-1 con sus cuatro cifras significativas: `Wk` presenta una meseta cerca 52 + de −6 dB por debajo de 2 Hz, alcanza +0,46 dB cerca de 6,3 Hz y decae por encima. 53 + 54 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/vibration_weighting_es.png" alt="La ponderación vertical de cuerpo completo Wk en decibelios de 0,4 a 100 Hz: una meseta cerca de -6 dB por debajo de 2 Hz, un pequeño pico de +0,5 dB cerca de 6 Hz y una caída hasta cerca de -21 dB a 100 Hz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/vibration_weighting_es_dark.png" alt="La ponderación vertical de cuerpo completo Wk en decibelios de 0,4 a 100 Hz: una meseta cerca de -6 dB por debajo de 2 Hz, un pequeño pico de +0,5 dB cerca de 6 Hz y una caída hasta cerca de -21 dB a 100 Hz" style="width:88%"> 55 + 56 + <details> 57 + <summary>Ver el código de esta figura</summary> 58 + 59 + ```python 60 + import numpy as np 61 + import matplotlib.pyplot as plt 62 + import phonometry as ph 63 + 64 + result = ph.frequency_weighting("Wk", np.geomspace(0.4, 100.0, 240)) 65 + 66 + # En una línea: 67 + result.plot() 68 + plt.show() 69 + 70 + # A mano, a partir de los campos del resultado, replicando lo que dibuja WeightingResponse.plot(): 71 + fig, ax = plt.subplots() 72 + ax.semilogx(result.frequencies, result.magnitude_db, color="#1f77b4") 73 + ax.set_xlabel("Frecuencia [Hz]") 74 + ax.set_ylabel("Factor de ponderación [dB]") 75 + ax.set_title("Ponderación vertical de cuerpo completo Wk (ISO 8041-1)") 76 + plt.show() 77 + ``` 78 + 79 + </details> 80 + 81 + Para ponderar una señal temporal, `apply_weighting` aplica la respuesta compleja 82 + exacta en el dominio de la frecuencia (de modo que coinciden magnitud *y* fase 83 + con la norma), que luego consumen las métricas de dosis en el tiempo siguientes. 84 + 85 + ## 2. Aceleración ponderada y medidas de dosis (ISO 2631-1) 86 + 87 + La evaluación básica es la **aceleración eficaz ponderada**. A partir de un 88 + espectro de tercios de octava es (ISO 2631-1, ec. (9); la construcción idéntica 89 + da la $a_{hw}$ de mano-brazo de ISO 5349-1, ec. (A.1)): 90 + 91 + $$ 92 + a_w = \sqrt{\sum_i \left(W_i\,a_i\right)^2}, 93 + $$ 94 + 95 + con $W_i$ el factor de ponderación en el centro de banda $i$ y $a_i$ la 96 + aceleración de banda medida. 97 + 98 + ```python 99 + import numpy as np 100 + import phonometry as ph 101 + 102 + # Un espectro vertical de asiento medido (eficaz por tercio de octava, m/s^2). 103 + freqs = np.array([1.0, 2.0, 4.0, 8.0, 16.0, 31.5, 63.0]) 104 + accel = np.array([0.20, 0.45, 0.42, 0.25, 0.12, 0.05, 0.02]) 105 + 106 + result = ph.weighted_acceleration(accel, freqs, "Wk") 107 + print(round(result.overall, 3)) # 0.555 m/s^2 (a_w) 108 + print(result.weighted.round(3)) # W_i * a_i por banda 109 + ``` 110 + 111 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/weighted_acceleration_es.png" alt="Un espectro de aceleración de asiento de vehículo medido (gris) y su contribución ponderada por Wk (azul) sobre los tercios de octava de 1 a 80 Hz: la ponderación atenúa las bandas bajas y altas pero deja el rango de 4 a 8 Hz casi inalterado, dando un valor eficaz ponderado a_w de aproximadamente 1,03 m/s^2" style="width:90%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/weighted_acceleration_es_dark.png" alt="Un espectro de aceleración de asiento de vehículo medido (gris) y su contribución ponderada por Wk (azul) sobre los tercios de octava de 1 a 80 Hz: la ponderación atenúa las bandas bajas y altas pero deja el rango de 4 a 8 Hz casi inalterado, dando un valor eficaz ponderado a_w de aproximadamente 1,03 m/s^2" style="width:90%"> 112 + 113 + <details> 114 + <summary>Ver el código de esta figura</summary> 115 + 116 + ```python 117 + import numpy as np 118 + import matplotlib.pyplot as plt 119 + import phonometry as ph 120 + 121 + freqs = np.array([1.0, 1.25, 1.6, 2.0, 2.5, 3.15, 4.0, 5.0, 6.3, 8.0, 10.0, 122 + 12.5, 16.0, 20.0, 25.0, 31.5, 40.0, 63.0, 80.0]) 123 + accel = np.array([0.18, 0.24, 0.33, 0.46, 0.52, 0.55, 0.48, 0.39, 0.31, 0.26, 124 + 0.21, 0.17, 0.13, 0.10, 0.078, 0.060, 0.045, 0.028, 0.020]) 125 + result = ph.weighted_acceleration(accel, freqs, "Wk") 126 + 127 + # En una línea: 128 + result.plot() 129 + plt.show() 130 + 131 + # A mano, replicando lo que dibuja WeightedSpectrum.plot(): 132 + pos = np.arange(freqs.size) 133 + fig, ax = plt.subplots() 134 + ax.bar(pos - 0.2, result.band_accelerations, 0.4, color="#bbbbbb", 135 + label="Sin ponderar $a_i$") 136 + ax.bar(pos + 0.2, result.weighted, 0.4, color="#1f77b4", 137 + label="Ponderada $W_i a_i$ (Wk)") 138 + ax.set_xticks(pos) 139 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 140 + ax.set_xlabel("Frecuencia [Hz]") 141 + ax.set_ylabel(r"Aceleración eficaz [m/s$^2$]") 142 + ax.set_title(f"Aceleración ponderada ($a_w$ = {result.overall:.3f} m/s²)") 143 + ax.legend() 144 + plt.show() 145 + ``` 146 + 147 + </details> 148 + 149 + Cuando el valor eficaz subestima una exposición intermitente o cargada de 150 + choques, ISO 2631-1 añade medidas de dosis calculadas sobre la señal temporal 151 + ponderada: el **valor eficaz móvil** y su máximo, el **valor máximo de vibración 152 + transitoria** `MTVV` (ec. (4), un eficaz móvil de 1 s); el **valor de dosis de 153 + vibración** de cuarta potencia $\text{VDV} = \left(\int a_w^4\,dt\right)^{1/4}$ 154 + (ec. (5)); el **valor de dosis de mareo** $\text{MSDV} = \left(\int a_w^2\,dt 155 + \right)^{1/2}$; y el **factor de cresta** (pico / eficaz), cuyo valor por encima 156 + de 9 indica que el método básico es inadecuado. 157 + 158 + ```python 159 + import numpy as np 160 + import phonometry as ph 161 + 162 + fs = 1000.0 163 + raw = np.random.default_rng(0).standard_normal(int(60 * fs)) # registro de 60 s 164 + a_w = ph.apply_weighting(raw, fs, "Wk") # señal ponderada 165 + 166 + print(round(ph.vibration_dose_value(a_w, fs), 3)) # VDV [m/s^1.75] 167 + print(round(ph.mtvv(a_w, fs), 3)) # MTVV [m/s^2] 168 + print(round(ph.crest_factor(a_w), 2)) # factor de cresta 169 + ``` 170 + 171 + ## 3. Valor total de vibración y exposición diaria `A(8)` 172 + 173 + Entre los tres ejes, el **valor total de vibración** combina las aceleraciones 174 + eficaces ponderadas por eje con los factores multiplicadores de postura $k_j$ 175 + (ISO 2631-1, ec. (10); para mano-brazo, ISO 5349-1, ec. (1), con todo $k = 1$): 176 + 177 + $$ 178 + a_v = \sqrt{\sum_j k_j^2\,a_{wj}^2}. 179 + $$ 180 + 181 + ```python 182 + import phonometry as ph 183 + 184 + # Salud, sentado: k = 1.4 / 1.4 / 1.0 (ISO 2631-1, 7.2.3). 185 + a_v = ph.vibration_total_value([0.35, 0.28, 0.62], k=[1.4, 1.4, 1.0]) 186 + print(round(a_v, 3)) # 0.882 m/s^2 187 + ``` 188 + 189 + La **exposición diaria** normaliza el valor total a una jornada de referencia de 190 + 8 horas ($T_0 = 28\,800$ s). Para una sola operación $A(8) = a_v\,\sqrt{T/T_0}$; 191 + varias operaciones se combinan mediante sus exposiciones parciales 192 + $A_i(8) = a_{vi}\,\sqrt{T_i/T_0}$ como $A(8) = \sqrt{\sum_i A_i(8)^2}$ (ISO 5349-1, 193 + ecs. (2)/(3); ISO 5349-2, ecs. (1)–(3)). 194 + 195 + `daily_vibration_exposure` construye las exposiciones parciales, las combina y 196 + evalúa el resultado frente a la **Directiva 2002/44/CE** — valor de acción de 197 + mano-brazo `A(8) = 2.5` y valor límite `5` m/s²; acción de cuerpo completo `0.5` 198 + y límite `1.15` m/s² (o un VDV de `9.1` / `21` m/s¹·⁷⁵): 199 + 200 + ```python 201 + import phonometry as ph 202 + 203 + # ISO 5349-2 Anexo E.3: las tres tareas con motosierra de un trabajador forestal. 204 + result = ph.daily_vibration_exposure( 205 + total_values=[4.6, 6.0, 3.6], # a_hv por tarea, m/s^2 206 + durations_s=[2 * 3600, 1 * 3600, 2 * 3600], # tiempo de exposición por tarea 207 + kind="hav", 208 + labels=["desbrozadora", "tala", "descortezado"], 209 + ) 210 + print(result.partials.round(2)) # [2.3 2.12 1.8 ] A_i(8) 211 + print(round(result.a8, 2)) # 3.61 m/s^2 212 + print(result.assessment.zone) # 'action' (2.5 <= A(8) < 5.0) 213 + ``` 214 + 215 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/daily_vibration_exposure_es.png" alt="Un diagrama de barras de las tres exposiciones parciales de mano-brazo (cerca de 2,3, 2,1 y 1,8 m/s^2) y la A(8) combinada de 3,61 m/s^2, con el valor de acción de exposición de la Directiva 2002/44/CE en 2,5 y el valor límite de exposición en 5,0 m/s^2 marcados como líneas horizontales; la exposición diaria se sitúa en la zona de acción entre ambos" style="width:82%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/daily_vibration_exposure_es_dark.png" alt="Un diagrama de barras de las tres exposiciones parciales de mano-brazo (cerca de 2,3, 2,1 y 1,8 m/s^2) y la A(8) combinada de 3,61 m/s^2, con el valor de acción de exposición de la Directiva 2002/44/CE en 2,5 y el valor límite de exposición en 5,0 m/s^2 marcados como líneas horizontales; la exposición diaria se sitúa en la zona de acción entre ambos" style="width:82%"> 216 + 217 + <details> 218 + <summary>Ver el código de esta figura</summary> 219 + 220 + ```python 221 + import numpy as np 222 + import matplotlib.pyplot as plt 223 + import phonometry as ph 224 + 225 + result = ph.daily_vibration_exposure( 226 + [4.6, 6.0, 3.6], [2 * 3600, 1 * 3600, 2 * 3600], kind="hav", 227 + labels=["desbrozadora", "tala", "descortezado"], 228 + ) 229 + 230 + # En una línea: 231 + result.plot() 232 + plt.show() 233 + 234 + # A mano, replicando lo que dibuja DailyVibrationExposure.plot(): 235 + labels = [*result.labels, "A(8)"] 236 + values = [*result.partials.tolist(), result.a8] 237 + a = result.assessment 238 + fig, ax = plt.subplots() 239 + ax.bar(range(len(values)), values, 240 + color=["#bbbbbb"] * result.partials.size + ["#1f77b4"]) 241 + ax.axhline(a.action_value, color="#2ca02c", ls="--", label=f"VAE = {a.action_value:g}") 242 + ax.axhline(a.limit_value, color="#d62728", ls="--", label=f"VLE = {a.limit_value:g}") 243 + ax.set_xticks(range(len(values))) 244 + ax.set_xticklabels(labels, rotation=30, ha="right") 245 + ax.set_ylabel(r"Exposición diaria A(8) [m/s$^2$]") 246 + ax.legend() 247 + plt.show() 248 + ``` 249 + 250 + </details> 251 + 252 + ## 4. Orientación exposición–respuesta 253 + 254 + Para la vibración transmitida a la mano, el Anexo C de ISO 5349-1 relaciona la 255 + exposición diaria con la vida media de grupo $D_y$ (en años) que produce el dedo 256 + blanco por vibración en el 10 % de un grupo expuesto, $D_y = 31.8\,A(8)^{-1.06}$ 257 + (ec. (C.1)): 258 + 259 + ```python 260 + import phonometry as ph 261 + 262 + print(round(ph.hav_vwf_lifetime_years(7.0), 1)) # 4.0 años (Tabla C.1) 263 + ``` 264 + 265 + Las normas no definen deliberadamente ningún límite seguro — `A(8)` y los valores 266 + de acción y límite de la directiva son la base de cualquier criterio de 267 + exposición. Para la exposición de cuerpo completo, `energy_equivalent_acceleration` 268 + da la magnitud energético-equivalente de ISO 2631-1 ec. (B.3) entre periodos de 269 + distinta magnitud y duración. 270 + 271 + --- 272 + 273 + **Normas.** ISO 8041-1:2017 (definiciones de ponderación y tolerancias); 274 + ISO 2631-1:1997 (evaluación de cuerpo completo); ISO 2631-2:2003 (edificios, 275 + `Wm`); ISO 2631-4:2001 (confort de marcha ferroviaria, `Wb`); ISO 5349-1:2001 e 276 + ISO 5349-2:2001 (vibración transmitida a la mano); Directiva 2002/44/CE (valores 277 + de acción y límite de exposición).
+290
site/src/content/docs/es/guides/materials.md
··· 1 + --- 2 + title: "Materiales acústicos" 3 + description: "Caracterización de absorbentes y particiones en laboratorio: la valoración ponderada de absorción sonora alpha_w de ISO 11654 y su clase, la resistencia y resistividad al flujo de aire de ISO 9053-1/-2, y la impedancia superficial, la absorción y la pérdida por transmisión en tubo de impedancia de ISO 10534-1/-2 y ASTM E2611." 4 + --- 5 + 6 + Caracterizar un absorbente o una partición es un ejercicio de laboratorio con 7 + tres instrumentos distintos detrás. La **sala reverberante** entrega un espectro 8 + de coeficientes de absorción sonora que ISO 11654 condensa en un único número 9 + valorado $\alpha_w$ con una clase por letra. El **banco de flujo** —estacionario 10 + u oscilante— mide cuánto cuesta empujar aire a través de una muestra porosa, la 11 + resistencia al flujo de aire que gobierna su comportamiento a baja frecuencia 12 + (ISO 9053-1/-2). Y el **tubo de impedancia** recupera, a incidencia normal, la 13 + impedancia superficial compleja completa, el factor de reflexión y la absorción 14 + de una muestra pequeña, y —con cuatro micrófonos— su pérdida por transmisión 15 + (ISO 10534-1/-2, ASTM E2611). Esta página cubre las tres. 16 + 17 + ## 1. Valoración de la absorción sonora (ISO 11654) 18 + 19 + ISO 354 mide el coeficiente de absorción sonora $\alpha_s$ de un material en 20 + bandas de tercio de octava en una sala reverberante. ISO 11654:1997 convierte 21 + ese espectro en una valoración de número único comparable entre productos. 22 + 23 + **Coeficiente de absorción práctico (cláusula 4.1).** Los datos de tercio de 24 + octava se agrupan primero en bandas de octava, cada una la media aritmética de 25 + sus tres tercios: 26 + 27 + $$ 28 + \alpha_{p,i} = \tfrac{1}{3}\big(\alpha_{i1} + \alpha_{i2} + \alpha_{i3}\big), 29 + $$ 30 + 31 + evaluado al segundo decimal y luego redondeado en pasos de $0.05$ (la NOTA de la 32 + cláusula 4.1 fija el redondeo, p. ej. $0.92 \to 0.90$); las medias redondeadas 33 + por encima de $1.00$ se fijan en $1.00$. Las cinco bandas de valoración son 250, 34 + 500, 1000, 2000 y 4000 Hz. 35 + 36 + **Absorción ponderada (cláusula 4.2).** Una curva de referencia fija 37 + $\{250{:}\,0.80,\ 500{:}\,1.00,\ 1000{:}\,1.00,\ 2000{:}\,1.00,\ 4000{:}\,0.90\}$ 38 + se desplaza hacia abajo, hacia el $\alpha_p$ medido, en pasos de $0.05$ hasta que 39 + la suma de las desviaciones **desfavorables** —tomadas solo donde la medida 40 + queda por debajo de la curva desplazada, con magnitud 41 + $(\text{curva} - \text{medida})$— no supera $0.10$. El coeficiente ponderado 42 + $\alpha_w$ es el valor de la curva desplazada leído a 500 Hz. 43 + 44 + **Indicadores de forma (cláusula 4.3).** Cuando un coeficiente práctico supera la 45 + curva desplazada en $0.25$ o más, se añade un indicador de forma: `L` a 250 Hz, 46 + `M` a 500 o 1000 Hz, `H` a 2000 o 4000 Hz (p. ej. `0.60(M)`). 47 + 48 + **Clase de absorción (Tabla B.1).** Por último, $\alpha_w$ se asigna a una clase: 49 + A (0,90–1,00), B (0,80–0,85), C (0,60–0,75), D (0,30–0,55), E (0,15–0,25) o "no 50 + clasificado" (0,00–0,10). Como $\alpha_w$ es siempre un múltiplo de $0.05$, estos 51 + rangos particionan la rejilla de forma exacta. 52 + 53 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/absorption_rating_es.png" alt="Valoración ponderada de absorción sonora de ISO 11654: el espectro de absorción práctica trazado frente a la curva de referencia desplazada de 250 Hz a 4000 Hz, con la desviación desfavorable a 250 Hz sombreada y el coeficiente ponderado alpha_w leído a 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/absorption_rating_es_dark.png" alt="Valoración ponderada de absorción sonora de ISO 11654: el espectro de absorción práctica trazado frente a la curva de referencia desplazada de 250 Hz a 4000 Hz, con la desviación desfavorable a 250 Hz sombreada y el coeficiente ponderado alpha_w leído a 500 Hz" style="width:80%"> 54 + 55 + *El ejemplo resuelto del Anexo A.2: la curva de referencia se desplaza hacia 56 + abajo 0,40 hasta que las desviaciones desfavorables suman 0,05 (≤ 0,10), dando 57 + $\alpha_w = 0.60$; el pico de 500 Hz sobrepasa la curva desplazada en ≥ 0,25, 58 + añadiendo el indicador `M`, de modo que la valoración es $0.60(\text{M})$, clase 59 + C.* 60 + 61 + ```python 62 + from phonometry import weighted_absorption, absorption_class 63 + 64 + # Coeficientes prácticos del Anexo A.2 de ISO 11654 a 250/500/1000/2000/4000 Hz 65 + alpha_p = [0.35, 1.00, 0.65, 0.60, 0.55] 66 + 67 + result = weighted_absorption(alpha_p) 68 + print(result.rating_label) # 0.60(M) 69 + print(result.alpha_w) # 0.6 70 + print(result.absorption_class) # C 71 + print(round(result.unfavourable_sum, 2)) # 0.05 72 + 73 + # Un alpha_w a secas también se asigna directamente a su clase (Tabla B.1) 74 + print(absorption_class(0.85)) # B 75 + ``` 76 + 77 + `weighted_absorption` acepta los cinco valores de $\alpha_p$ por banda de octava 78 + (como una secuencia o un mapeo `{frecuencia: valor}`); pasa antes los quince 79 + valores de $\alpha_s$ de tercio de octava a `practical_absorption_coefficient` 80 + si partes de datos brutos de ISO 354. El resultado lleva la curva de referencia 81 + desplazada y las desviaciones por banda, y su `.plot()` genera la figura de 82 + arriba. 83 + 84 + ## 2. Resistencia al flujo de aire (ISO 9053-1/-2) 85 + 86 + La resistencia al flujo de aire cuantifica con qué fuerza un material poroso se 87 + opone a un flujo estacionario o lentamente oscilante. Ambas partes comparten las 88 + mismas tres magnitudes y unidades (ISO 9053-1:2018, cláusula 3): 89 + 90 + $$ 91 + R = \frac{\Delta p}{q_v}\ \left[\text{Pa·s/m}^3\right], \qquad 92 + R_s = R\,A\ \left[\text{Pa·s/m}\right], \qquad 93 + \sigma = \frac{R_s}{d}\ \left[\text{Pa·s/m}^2\right], 94 + $$ 95 + 96 + con $\Delta p$ la diferencia de presión a través de la probeta, $q_v$ el flujo 97 + volumétrico, $A$ la sección transversal y $d$ el espesor. Nótese que la 98 + resistencia específica al flujo de aire $R_s$ está en **Pa·s/m** (no Pa·s/m²); la 99 + resistividad al flujo de aire $\sigma$ es $R_s$ por metro de espesor. 100 + 101 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_airflow_resistance_es.svg" alt="Bancos de medición de la resistencia al flujo de aire: el método estático de ISO 9053-1 con una probeta en un portamuestras, un flujo laminar estacionario q_v y un manómetro diferencial que lee la caída de presión; y el método alterno de ISO 9053-2 con un pistón oscilante que acciona una cavidad terminada por la probeta o por un tapón hermético, y un micrófono que lee el nivel de la cavidad" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_airflow_resistance_es_dark.svg" alt="Bancos de medición de la resistencia al flujo de aire: el método estático de ISO 9053-1 con una probeta en un portamuestras, un flujo laminar estacionario q_v y un manómetro diferencial que lee la caída de presión; y el método alterno de ISO 9053-2 con un pistón oscilante que acciona una cavidad terminada por la probeta o por un tapón hermético, y un micrófono que lee el nivel de la cavidad" style="width:92%"> 102 + 103 + **Método estático (ISO 9053-1:2018).** Un flujo laminar estacionario se aumenta 104 + por escalones y la diferencia de presión se traza frente a la velocidad lineal 105 + $u = q_v/A$. Se ajusta una regresión de al menos segundo orden **forzada a pasar 106 + por el origen**, $\Delta p = a\,u + b\,u^2$, y $\Delta p$ y $R_s$ se leen a la 107 + velocidad de referencia $u = 0.5\ \text{mm/s}$ (cláusula 7.5); la velocidad más 108 + alta no debe superar los 15 mm/s. Como $R_s = \Delta p/u = a + b\,u$, el término 109 + lineal $a$ es la resistencia específica al flujo de aire a velocidad nula. 110 + 111 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/airflow_resistance_es.png" alt="Resistencia al flujo de aire por el método estático de ISO 9053-1: la caída de presión medida frente a la velocidad lineal del flujo, ajustada con una cuadrática que pasa por el origen, con la resistencia específica al flujo de aire evaluada a la velocidad de referencia de 0,5 mm/s" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/airflow_resistance_es_dark.png" alt="Resistencia al flujo de aire por el método estático de ISO 9053-1: la caída de presión medida frente a la velocidad lineal del flujo, ajustada con una cuadrática que pasa por el origen, con la resistencia específica al flujo de aire evaluada a la velocidad de referencia de 0,5 mm/s" style="width:80%"> 112 + 113 + *La caída de presión, ligeramente superlineal, se ajusta pasando por el origen; 114 + la resistencia específica al flujo de aire es el ajuste leído a 0,5 mm/s.* 115 + 116 + ```python 117 + import numpy as np 118 + from phonometry import static_airflow_resistance 119 + 120 + area = np.pi * 0.05**2 # celda de 100 mm de diámetro [m^2] 121 + u = np.array([0.5, 1, 2, 4, 8, 12]) * 1e-3 # velocidad lineal [m/s] 122 + dp = 1.6e4 * u + 4.0e5 * u**2 # caída de presión medida [Pa] 123 + 124 + r = static_airflow_resistance(u, dp, area=area, thickness=0.05) 125 + print(round(r.specific_resistance)) # 16200 R_s [Pa*s/m] 126 + print(round(r.resistivity)) # 324000 sigma [Pa*s/m^2] 127 + print(round(r.linear_coefficient)) # 16000 a = R_s cuando u -> 0 128 + ``` 129 + 130 + **Método alterno (ISO 9053-2:2020).** Un pistón que oscila a 1–4 Hz acciona un 131 + flujo alterno hacia una cavidad terminada por la probeta o por un tapón 132 + hermético; la resistencia se obtiene de la diferencia de nivel de presión sonora 133 + entre las dos terminaciones (Fórmula (2)): 134 + 135 + $$ 136 + R = \frac{\kappa'\,P_S}{2\pi f\,V}\cdot\frac{h_t}{h_s}\cdot 137 + 10^{(L_{p,s} - L_{p,t})/20}, 138 + $$ 139 + 140 + donde $\kappa'$ es la razón **efectiva** de calores específicos. La conducción de 141 + calor entre el aire oscilante y las paredes de la cavidad hace que la compresión 142 + no sea plenamente adiabática; el Anexo A normativo corrige $\kappa$ a la baja 143 + hasta 144 + 145 + $$ 146 + \kappa' = \frac{\kappa}{\sqrt{1 + (\kappa-1)\tfrac{S}{V}b 147 + + \tfrac{1}{2}\big((\kappa-1)\tfrac{S}{V}b\big)^2}}, 148 + \qquad b = \sqrt{\frac{2 c_0 l_h}{\omega}},\quad 149 + l_h = \frac{k_a}{\rho_0 c_0 C_P}, 150 + $$ 151 + 152 + con $S$ y $V$ la superficie y el volumen de la cavidad y $b$ el espesor de la 153 + capa límite térmica. Para la cavidad de ejemplo del Anexo A.3 esto da 154 + $\kappa' = 1.370$, cerca de un 2 % por debajo del adiabático 1,4008. 155 + 156 + ```python 157 + from phonometry import effective_kappa, alternating_airflow_resistance 158 + 159 + # Cavidad del Anexo A.3: cilindro cerrado de 100 mm x 100 mm, pistón a 2 Hz 160 + kp = effective_kappa(cavity_surface=0.0471, cavity_volume=7.854e-4, frequency=2.0) 161 + print(round(kp, 3)) # 1.37 razón efectiva de calores específicos 162 + 163 + R = alternating_airflow_resistance( 164 + level_specimen=74.0, level_termination=90.0, 165 + piston_stroke_specimen=14e-3, piston_stroke_termination=1.4e-3, 166 + frequency=2.0, cavity_volume=7.854e-4, kappa_prime=kp, 167 + ) 168 + print(round(R)) # resistencia al flujo de aire R [Pa*s/m^3] 169 + ``` 170 + 171 + Pasa el resultado de `effective_kappa` a `alternating_airflow_resistance` para 172 + una cifra conforme al Anexo A; en caso contrario, su argumento `kappa_prime` 173 + adopta por defecto el adiabático sin corregir 1.4. La llamada avisa (mediante 174 + `AirflowResistanceWarning`) cuando la frecuencia del pistón sale de 1–4 Hz o 175 + fallan los criterios de validez de las Fórmulas (3)/(4). 176 + 177 + ## 3. Tubo de impedancia (ISO 10534-1/-2, ASTM E2611) 178 + 179 + El tubo de impedancia mide una muestra pequeña a **incidencia normal**. Dos 180 + normas comparten la geometría pero difieren en método y convención de signo, así 181 + que la biblioteca mantiene sus ayudantes separados y nunca los mezcla. 182 + 183 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impedance_tube_es.svg" alt="Tubo de impedancia de dos micrófonos de ISO 10534-2: un altavoz radiando una onda plana por el tubo, dos micrófonos enrasados en la pared a la separación s y a la distancia x1 de la cara de la probeta, la probeta de ensayo contra un respaldo rígido, y las ondas incidente y reflejada" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impedance_tube_es_dark.svg" alt="Tubo de impedancia de dos micrófonos de ISO 10534-2: un altavoz radiando una onda plana por el tubo, dos micrófonos enrasados en la pared a la separación s y a la distancia x1 de la cara de la probeta, la probeta de ensayo contra un respaldo rígido, y las ondas incidente y reflejada" style="width:92%"> 184 + 185 + **Método de la razón de onda estacionaria (ISO 10534-1).** Una sonda recorre la 186 + onda estacionaria y lee la diferencia de nivel $\Delta L = L_\text{max} - 187 + L_\text{min}$ entre un máximo de presión y el mínimo adyacente. La razón de onda 188 + estacionaria, la magnitud de reflexión y la absorción se obtienen en forma 189 + cerrada: 190 + 191 + $$ 192 + s = 10^{\Delta L/20}, \qquad |r| = \frac{s-1}{s+1}, \qquad 193 + \alpha = 1 - |r|^2. 194 + $$ 195 + 196 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impedance_tube_es.png" alt="Método de la razón de onda estacionaria de ISO 10534-1: el coeficiente de absorción y la magnitud del factor de reflexión en función de la diferencia de nivel de la onda estacionaria, mostrando que una diferencia de 9,54 dB corresponde a una razón de onda estacionaria de 3, una magnitud de reflexión de 0,5 y una absorción de 0,75" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impedance_tube_es_dark.png" alt="Método de la razón de onda estacionaria de ISO 10534-1: el coeficiente de absorción y la magnitud del factor de reflexión en función de la diferencia de nivel de la onda estacionaria, mostrando que una diferencia de 9,54 dB corresponde a una razón de onda estacionaria de 3, una magnitud de reflexión de 0,5 y una absorción de 0,75" style="width:80%"> 197 + 198 + *Una diferencia de nivel pequeña significa un absorbente casi perfecto; una 199 + diferencia de nivel de 9,54 dB da $s = 3$, $|r| = 0.5$ y $\alpha = 0.75$.* 200 + 201 + ```python 202 + from phonometry import standing_wave_absorption, standing_wave_ratio_from_level 203 + 204 + s = float(standing_wave_ratio_from_level(9.542)) # diferencia de nivel [dB] -> SWR 205 + print(round(s, 2)) # 3.0 206 + print(round(float(standing_wave_absorption(s)), 2)) # 0.75 207 + ``` 208 + 209 + **Método de la función de transferencia (ISO 10534-2).** Dos micrófonos fijos 210 + miden la función de transferencia compleja $H_{12}$; de ella se obtienen el 211 + factor de reflexión en la cara de la muestra, la absorción y la impedancia 212 + superficial normalizada (ecs. (17)–(19)): 213 + 214 + $$ 215 + r = \frac{H_{12} - H_I}{H_R - H_{12}}\,e^{\,2 j k_0 x_1}, \qquad 216 + \alpha = 1 - |r|^2, \qquad \frac{Z}{\rho c_0} = \frac{1+r}{1-r}, 217 + $$ 218 + 219 + con $H_I = e^{-j k_0 s}$, $H_R = e^{+j k_0 s}$, la separación de micrófonos $s$ y 220 + $x_1$ la distancia de la muestra al micrófono más lejano. 221 + 222 + ```python 223 + import numpy as np 224 + from phonometry import ( 225 + tube_wavenumber, reflection_factor, 226 + absorption_from_reflection, normalized_surface_impedance, 227 + ) 228 + 229 + f = np.array([500.0, 1000.0, 1800.0]) 230 + x1, spacing, c0 = 0.12, 0.03, 343.2 231 + k0 = tube_wavenumber(f, c0) 232 + 233 + # Una función de transferencia H12 medida (aquí sintetizada a partir de r = 0.3 - 0.4j) 234 + target = 0.3 - 0.4j 235 + x2 = x1 - spacing 236 + h12 = (np.exp(1j*k0*x2) + target*np.exp(-1j*k0*x2)) / \ 237 + (np.exp(1j*k0*x1) + target*np.exp(-1j*k0*x1)) 238 + 239 + r = reflection_factor(h12, spacing=spacing, x1=x1, wavenumber=k0) 240 + print(np.round(absorption_from_reflection(r), 3)) # [0.75 0.75 0.75] 241 + print(np.round(normalized_surface_impedance(r), 2)) # Z / rho c0 242 + ``` 243 + 244 + El `two_microphone_impedance` de alto nivel envuelve esta cadena y devuelve un 245 + `ImpedanceTubeResult` con la absorción, el factor de reflexión, la impedancia 246 + superficial y la impedancia normalizada, aplicando la comprobación del rango de 247 + frecuencias de onda plana y la atenuación opcional del tubo; corrige antes 248 + cualquier desajuste de micrófonos con `apply_mic_calibration`. 249 + 250 + **Pérdida por transmisión (ASTM E2611).** Con cuatro micrófonos —dos aguas 251 + arriba, dos aguas abajo de la muestra— una medición de dos cargas (o de una 252 + carga) recupera la matriz de transferencia de la muestra, cuyos elementos dan la 253 + pérdida por transmisión a incidencia normal, la reflexión y el número de onda: 254 + 255 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_astm_tube_es.svg" alt="Tubo de pérdida por transmisión de cuatro micrófonos de ASTM E2611: una fuente sonora, dos micrófonos aguas arriba y dos aguas abajo de la probeta de ensayo a las separaciones s1 y s2 y los desplazamientos l1 y l2, una terminación ajustable para el método de dos cargas, las ondas viajeras A y B aguas arriba y C y D aguas abajo, y las relaciones de matriz de transferencia y pérdida por transmisión" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_astm_tube_es_dark.svg" alt="Tubo de pérdida por transmisión de cuatro micrófonos de ASTM E2611: una fuente sonora, dos micrófonos aguas arriba y dos aguas abajo de la probeta de ensayo a las separaciones s1 y s2 y los desplazamientos l1 y l2, una terminación ajustable para el método de dos cargas, las ondas viajeras A y B aguas arriba y C y D aguas abajo, y las relaciones de matriz de transferencia y pérdida por transmisión" style="width:92%"> 256 + 257 + $$ 258 + \mathrm{TL} = 20\log_{10}\left|\frac{T_{11} + T_{12}/\rho c 259 + + \rho c\,T_{21} + T_{22}}{2}\right|. 260 + $$ 261 + 262 + ```python 263 + import numpy as np 264 + from phonometry import air_layer_transfer_matrix 265 + 266 + # Una capa de aire es una matriz de transferencia conocida; TL = 0 dB (no se pierde nada) 267 + f = np.array([500.0, 1000.0, 2000.0]) 268 + k0 = 2*np.pi*f / 343.2 269 + rho_c = 1.186 * 343.2 270 + tm = air_layer_transfer_matrix(thickness=0.05, wavenumber=k0, 271 + characteristic_impedance=rho_c) 272 + print(np.round(tm.transmission_loss(rho_c), 6)) # [0. 0. 0.] 273 + ``` 274 + 275 + `transfer_matrix_two_load` / `transfer_matrix_one_load` construyen la 276 + `TransferMatrix` a partir de las funciones de transferencia de los cuatro 277 + micrófonos `(H1, H2, H3, H4)` medidas en cada carga; sus métodos 278 + (`transmission_loss`, `reflection_hard_backed`, 279 + `absorption_hard_backed`, `characteristic_impedance_material`, 280 + `material_wavenumber`) leen entonces las magnitudes de ASTM E2611. 281 + 282 + --- 283 + 284 + **Normas.** ISO 11654:1997 (valoración ponderada de absorción sonora); 285 + ISO 9053-1:2018 (resistencia estática al flujo de aire); ISO 9053-2:2020 286 + (resistencia alterna al flujo de aire); ISO 10534-1:1996 e ISO 10534-2:1998 287 + (tubo de impedancia); ASTM E2611-19 (pérdida por transmisión de cuatro 288 + micrófonos). Toda ecuación se deriva del texto de la norma y se valida frente a 289 + los ejemplos resueltos de las propias normas (ISO 11654 Anexo A, ISO 9053-2 290 + Anexo A.3) e identidades en forma cerrada.
+1 -1
site/src/content/docs/es/guides/outdoor-propagation.md
··· 259 259 260 260 La exactitud declarada del método es de $\pm 1$ a $\pm 3$ dB para ruido de banda 261 261 ancha hasta 1000 m (Tabla 5). Consulta la página de [Teoría](/phonometry/es/reference/theory/) 262 - para la derivación completa, la [guía de Acústica de salas y edificación](/phonometry/es/guides/room-acoustics/) 262 + para la derivación completa, la [guía de Acústica de salas](/phonometry/es/guides/room-acoustics/) 263 263 para cómo $\alpha$ alimenta la ISO 354, y la [guía de Niveles](/phonometry/es/guides/levels/) 264 264 para la exposición al ruido en el trabajo (ISO 9612) que consume niveles 265 265 ponderados A.
+15 -648
site/src/content/docs/es/guides/room-acoustics.md
··· 1 1 --- 2 - title: "Acústica de salas y edificación" 3 - description: "Adquisición de la respuesta al impulso (ISO 18233), parámetros de sala EDT/T20/T30/C50/C80/Ts (ISO 3382-1/2), métricas de habla en oficinas diáfanas (ISO 3382-3), aislamiento acústico en laboratorio (ISO 10140) y en campo (ISO 16283-1/2/3) a ruido aéreo y a impactos con índices ponderados (ISO 717-1/2), predicción de la transmisión (EN 12354) e incertidumbre de medición (ISO 12999-1), y absorción sonora en sala reverberante (ISO 354)." 2 + title: "Acústica de salas" 3 + description: "Adquisición de la respuesta al impulso (ISO 18233), parámetros de sala EDT/T20/T30/C50/C80/Ts (ISO 3382-1/2), métricas de habla en oficinas diáfanas (ISO 3382-3) y absorción sonora en sala reverberante (ISO 354)." 4 4 --- 5 5 6 - La acústica de salas y de la edificación parte de una única medición: la 7 - **respuesta al impulso** (RI) entre una fuente y un receptor. Fíltrala en 8 - bandas e intégrala, y da el tiempo de reverberación, la claridad y la 9 - inteligibilidad del habla; mídela a ambos lados de una pared, y da el 10 - aislamiento acústico del cerramiento. Esta página sigue esa cadena en orden 11 - de medición: adquirir la RI (ISO 18233), convertirla en parámetros de sala 12 - (ISO 3382-1/2), métricas espaciales del habla para oficinas diáfanas 13 - (ISO 3382-3), aislamiento en campo a ruido aéreo, a impactos y de fachadas con 14 - índices de un solo número (ISO 16283-1/2/3, ISO 717-1/2), la caracterización en 15 - laboratorio de un elemento constructivo (ISO 10140), la predicción del 16 - comportamiento in situ a partir de la transmisión por flancos (EN 12354-1/2), la 17 - incertidumbre de medición que cualifica cada índice (ISO 12999-1) y, cerrando el 18 - ciclo, la absorción sonora de un material en una sala reverberante (ISO 354). 6 + La acústica de salas parte de una única medición: la **respuesta al impulso** 7 + (RI) entre una fuente y un receptor. Fíltrala en bandas e intégrala, y da el 8 + tiempo de reverberación, la claridad y la inteligibilidad del habla —todo 9 + sobre el campo sonoro dentro de un único recinto. Esta página sigue esa cadena 10 + en orden de medición: adquirir la RI (ISO 18233), convertirla en parámetros de 11 + sala (ISO 3382-1/2), métricas espaciales del habla para oficinas diáfanas 12 + (ISO 3382-3) y, cerrando el ciclo, la absorción sonora de un material en una 13 + sala reverberante (ISO 354). Para el aislamiento acústico *entre* recintos —la 14 + misma RI medida a ambos lados de un cerramiento— consulta la guía complementaria 15 + [Acústica de la edificación y aislamiento](/phonometry/es/guides/building-acoustics/). 19 16 20 17 ## 1. Adquisición de la respuesta al impulso (ISO 18233) 21 18 ··· 325 322 posición puede medirse a su vez con las herramientas STIPA de la 326 323 [guía de Psicoacústica](/phonometry/es/guides/psychoacoustics/). 327 324 328 - ## 4. Aislamiento en campo e índices de un solo número (ISO 16283-1, ISO 717-1) 329 - 330 - Para calificar una pared o un forjado, mide el nivel promediado en energía en 331 - la sala **emisora** ($L_1$) y en la sala **receptora** ($L_2$) por banda de 332 - tercio de octava y forma la diferencia de niveles $D = L_1 - L_2$. Dos 333 - normalizaciones la hacen comparable entre salas. La **diferencia de niveles 334 - estandarizada** refiere el tiempo de reverberación de la sala receptora $T$ a 335 - $T_0 = 0.5$ s (de modo que con $T = 0.5$ s, $D_{nT} = D$ exactamente), y el 336 - **índice de reducción sonora aparente** normaliza por la superficie del 337 - cerramiento $S$ y el área de absorción de Sabine $A$: 338 - 339 - $$ 340 - D_{nT} = D + 10 \log_{10} \frac{T}{T_0}, \qquad 341 - R' = D + 10 \log_{10} \frac{S}{A}, \qquad A = \frac{0.16\ V}{T}. 342 - $$ 343 - 344 - Las posiciones se promedian en energía con 345 - $L = 10 \log_{10}\left( \frac{1}{n} \sum_i 10^{L_i/10} \right)$. 346 - 347 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_es.svg" alt="Montaje de aislamiento a ruido aéreo en campo: un altavoz en la sala emisora, micrófonos promediados en energía en las salas emisora y receptora a través del cerramiento común" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_es_dark.svg" alt="Montaje de aislamiento a ruido aéreo en campo: un altavoz en la sala emisora, micrófonos promediados en energía en las salas emisora y receptora a través del cerramiento común" style="width:92%"> 348 - 349 - El espectro por bandas se reduce a un número mediante el **método de la curva 350 - de referencia** de ISO 717-1: una curva de referencia fija se desplaza en 351 - pasos de 1 dB hacia la curva medida hasta que la suma de desviaciones 352 - *desfavorables* (donde la medición cae por debajo de la referencia) es lo más 353 - grande posible pero no mayor que 32,0 dB (16 bandas de tercio de octava) o 354 - 10,0 dB (5 bandas de octava). El índice (`Rw`, `R'w`, `DnT,w` …) es la 355 - referencia desplazada leída a 500 Hz. Los **términos de adaptación 356 - espectral** $C$ (ruido rosa) y $C_{tr}$ (tráfico urbano) añaden la 357 - penalización en baja frecuencia de una fuente real. 358 - 359 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_es.png" alt="Índice de reducción sonora medido en tercios de octava con la curva de referencia de ISO 717-1 desplazada y el índice ponderado resultante a 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_es_dark.png" alt="Índice de reducción sonora medido en tercios de octava con la curva de referencia de ISO 717-1 desplazada y el índice ponderado resultante a 500 Hz" style="width:80%"> 360 - 361 - ```python 362 - import numpy as np 363 - from phonometry import airborne_insulation, weighted_rating, energy_average_level 364 - 365 - # Promedia en energía varias posiciones de micrófono en una sala (dB) 366 - print(round(float(energy_average_level([60.0, 66.0])), 1)) # 64.0 367 - 368 - # Aislamiento en campo por banda; la superficie S y el volumen V añaden R' 369 - l1 = np.full(16, 80.0) # niveles de la sala emisora 370 - l2 = np.full(16, 40.0) # niveles de la sala receptora 371 - t2 = np.full(16, 0.5) # T de la sala receptora (s) 372 - ins = airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 373 - print(round(float(ins.dnt[0]), 1)) # 40.0 (= D ya que T = T0) 374 - print(round(float(ins.r_prime[0]), 1)) # 38.0 375 - 376 - # Índice de un solo número desde un espectro R medido de 16 bandas (ISO 717-1 Anexo C) 377 - R = [20.4, 16.3, 17.7, 22.6, 22.4, 22.7, 24.8, 26.6, 378 - 28.0, 30.5, 31.8, 32.5, 33.4, 33.0, 31.0, 25.5] 379 - w = weighted_rating(R) 380 - print(w.rating, w.c, w.ctr) # 30 -2 -3 -> Rw(C;Ctr) = 30(-2;-3) 381 - 382 - w.plot() # R' medido frente a la referencia ISO 717-1 desplazada, desviaciones sombreadas (requiere matplotlib) 383 - ``` 384 - 385 - <details> 386 - <summary>Ver el código de esta figura</summary> 387 - 388 - ```python 389 - import matplotlib.pyplot as plt 390 - 391 - # En una línea — la curva medida frente a la referencia ISO 717-1 desplazada: 392 - w.plot() 393 - plt.show() 394 - 395 - # A mano, con los campos de la curva por banda que ahora lleva el resultado: 396 - fig, ax = plt.subplots() 397 - ax.semilogx(w.band_centers, w.measured, "o-", label="R' medido") 398 - ax.semilogx(w.band_centers, w.shifted_reference, "s--", label="Referencia desplazada") 399 - ax.fill_between(w.band_centers, w.measured, w.shifted_reference, 400 - where=w.measured < w.shifted_reference, interpolate=True, 401 - alpha=0.3, label="Desviaciones desfavorables") 402 - ax.set_xlabel("Frecuencia [Hz]") 403 - ax.set_ylabel("Índice de reducción sonora [dB]") 404 - ax.set_title(f"Rw = {w.rating} dB (C={w.c:+d}; Ctr={w.ctr:+d})") 405 - ax.legend() 406 - plt.show() 407 - ``` 408 - 409 - </details> 410 - 411 - Calcula `l1`, `l2` y `t2` en las mismas 16 bandas de tercio de octava de 412 - 100 Hz a 3150 Hz — obtén `t2` de 413 - `room_parameters(ir, fs, limits=(100, 3150), fraction=3).t30`, por ejemplo — y 414 - pásalos a `airborne_insulation`. Alimenta el espectro `dnt` (o `r_prime`) de esa 415 - función a `weighted_rating`, de modo que cada banda quede alineada índice a 416 - índice con la curva de referencia ISO 717-1. 417 - 418 - ### Parámetros de `airborne_insulation()` 419 - 420 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 421 - | :--- | :--- | :--- | :--- | :--- | 422 - | `l1` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Niveles de la sala emisora (2D se promedia en energía) | 423 - | `l2` | array 1D o 2D | dB | mismo número de bandas | Niveles de la sala receptora | 424 - | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 425 - | `area` | float, opcional | m² | > 0, con `volume` | Superficie del cerramiento `S` (habilita `R'`) | 426 - | `volume` | float, opcional | m³ | > 0, con `area` | Volumen de la sala receptora `V` | 427 - | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 428 - 429 - ### Parámetros de `weighted_rating()` 430 - 431 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 432 - | :--- | :--- | :--- | :--- | :--- | 433 - | `values_by_band` | array 1D | dB | 16 (tercios) o 5 (octavas) | `R`, `R'`, `DnT` … medidos por banda | 434 - | `bands` | str o `None` | — | `'third-octave'` / `'octave'` / `None` | `None` lo infiere del número de bandas | 435 - 436 - `airborne_insulation()` devuelve un `AirborneInsulationResult` (`d`, `dnt`, 437 - `r_prime` o `None`); `weighted_rating()` devuelve un `WeightedRatingResult` 438 - (`rating`, `c`, `ctr`, `unfavourable_sum`, todos enteros salvo la suma). 439 - 440 - ### Ruido de impactos (ISO 16283-2, ISO 717-2) 441 - 442 - El ruido de pisadas se califica al revés. En lugar de cuánto *bloquea* un 443 - forjado, el aislamiento a impactos mide cuánto introduce en la sala inferior 444 - una **máquina de impactos normalizada** situada en el forjado superior —así que 445 - un número *mayor* es *peor*. El nivel de presión de ruido de impactos $L_i$ 446 - promediado en energía en la sala receptora se normaliza igual que el caso 447 - aéreo, pero con un cambio de signo en el término de reverberación: 448 - 449 - $$ 450 - L'_{nT} = L_i - 10 \log_{10} \frac{T}{T_0}, \qquad 451 - L'_n = L_i + 10 \log_{10} \frac{A}{A_0}, \quad 452 - A_0 = 10\ \text{m}^2,\ A = \frac{0.16\ V}{T}. 453 - $$ 454 - 455 - El nivel de impactos **estandarizado** $L'_{nT}$ ($T_0 = 0.5$ s para viviendas) 456 - solo necesita el $T$ de la sala receptora, así que con $T = 0.5$ s es igual a 457 - $L_i$; el nivel **normalizado** $L'_n$ (referido a un área de absorción de 458 - 10 m²) necesita además el volumen de la sala receptora. Fíjate en el signo 459 - **menos** —más reverberación *reduce* $L'_{nT}$, al contrario que el $D_{nT}$ 460 - aéreo. 461 - 462 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_es.svg" alt="Montaje de aislamiento a impactos en campo: una máquina de impactos normalizada sobre el suelo de la sala emisora superior, micrófonos promediados en energía en la sala receptora inferior, y el tiempo de reverberación de la sala receptora" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_es_dark.svg" alt="Montaje de aislamiento a impactos en campo: una máquina de impactos normalizada sobre el suelo de la sala emisora superior, micrófonos promediados en energía en la sala receptora inferior, y el tiempo de reverberación de la sala receptora" style="width:92%"> 463 - 464 - El índice de un solo número (ISO 717-2) desplaza el mismo estilo de curva de 465 - referencia, pero una **desviación desfavorable se produce ahora donde la 466 - medición *supera* la referencia** (el ruido de impactos es peor cuanto más 467 - alto) —el signo opuesto a ISO 717-1. El índice (`Ln,w`, `L'n,w`, `L'nT,w`) es 468 - la referencia desplazada leída a 500 Hz; para bandas de octava se reduce además 469 - en 5 dB. El término de adaptación espectral $C_I = L_{n,\text{sum}} - 15 - L_{n,w}$ 470 - usa la suma energética sobre 100–2500 Hz (16 tercios excluyendo 3150 Hz) o 471 - 125–2000 Hz (octavas). 472 - 473 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_es.png" alt="Nivel de presión de ruido de impactos normalizado medido en tercios de octava con la curva de referencia de ISO 717-2 desplazada y el índice ponderado resultante leído a 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_es_dark.png" alt="Nivel de presión de ruido de impactos normalizado medido en tercios de octava con la curva de referencia de ISO 717-2 desplazada y el índice ponderado resultante leído a 500 Hz" style="width:80%"> 474 - 475 - ```python 476 - import numpy as np 477 - from phonometry import impact_insulation, weighted_impact_rating 478 - 479 - # 16 niveles de impactos Li en tercios de octava (100 Hz - 3150 Hz), dB, del 480 - # ejemplo resuelto del Anexo C de ISO 717-2, y el T de la sala receptora por banda. 481 - li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 482 - 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 483 - t2 = np.full(16, 0.5) 484 - 485 - imp = impact_insulation(li, t2, volume=50.0) 486 - print(round(float(imp.l_n_t[0]), 1)) # 62.1 (= Li ya que T = T0) 487 - print(round(float(imp.l_n[0]), 1)) # 64.1 normalizado a A0 = 10 m^2 488 - 489 - # Índice de impactos ponderado + término de adaptación espectral CI (ISO 717-2) 490 - res_imp = weighted_impact_rating(imp.l_n_t) 491 - print(res_imp.rating, res_imp.ci, res_imp.unfavourable_sum) # 79 -11 28.0 -> L'nT,w(CI)=79(-11) 492 - 493 - # Los datos en banda de octava llevan la reducción extra de -5 dB (Cláusula 4.3.2) 494 - octave = np.array([65.3, 64.5, 58.0, 55.8, 43.0]) 495 - print(weighted_impact_rating(octave).rating) # 54 496 - 497 - res_imp.plot() # L'nT medido frente a la referencia ISO 717-2 desplazada, exceso sombreado (requiere matplotlib) 498 - ``` 499 - 500 - <details> 501 - <summary>Ver el código de esta figura</summary> 502 - 503 - ```python 504 - import matplotlib.pyplot as plt 505 - 506 - # En una línea — L'nT medido frente a la referencia ISO 717-2 desplazada (exceso sombreado): 507 - res_imp.plot() 508 - plt.show() 509 - 510 - # A mano, con la curva por banda que ahora lleva el resultado (signo opuesto: la 511 - # desviación desfavorable está donde el nivel MEDIDO supera la referencia). 512 - # Aquí la entrada fue l_n_t, así que la magnitud valorada es el nivel de campo L'nT,w: 513 - fig, ax = plt.subplots() 514 - ax.semilogx(res_imp.band_centers, res_imp.measured, "o-", label="L'nT medido") 515 - ax.semilogx(res_imp.band_centers, res_imp.shifted_reference, "s--", label="Referencia desplazada") 516 - ax.fill_between(res_imp.band_centers, res_imp.shifted_reference, res_imp.measured, 517 - where=res_imp.measured > res_imp.shifted_reference, interpolate=True, 518 - alpha=0.3, label="Desviaciones desfavorables") 519 - ax.set_xlabel("Frecuencia [Hz]") 520 - ax.set_ylabel("Nivel de presión sonora de impacto [dB]") 521 - ax.set_title(f"L'nT,w = {res_imp.rating} dB (CI={res_imp.ci:+d})") 522 - ax.legend() 523 - plt.show() 524 - ``` 525 - 526 - </details> 527 - 528 - Pasa el `l_n_t` (o `l_n`) de `impact_insulation` directamente a 529 - `weighted_impact_rating`; el índice y `CI` reproducen los valores del Anexo C de 530 - ISO 717-2 (tercios `L'nT,w = 79`, `CI = −11`; octava `54`, `CI = 0`). 531 - 532 - #### Parámetros de `impact_insulation()` 533 - 534 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 535 - | :--- | :--- | :--- | :--- | :--- | 536 - | `li` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | SPL de impactos promediado en energía (2D se promedia sobre las posiciones) | 537 - | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 538 - | `volume` | float, opcional | m³ | > 0 | `V` de la sala receptora (habilita `L'n`) | 539 - | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 540 - 541 - #### Parámetros de `weighted_impact_rating()` 542 - 543 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 544 - | :--- | :--- | :--- | :--- | :--- | 545 - | `values_by_band` | array 1D | dB | 16 (tercios) o 5 (octavas) | `Ln`, `L'n` o `L'nT` medidos por banda | 546 - | `bands` | str o `None` | — | `'third-octave'` / `'octave'` / `None` | `None` lo infiere del número de bandas | 547 - 548 - `impact_insulation()` devuelve un `ImpactInsulationResult` (`l_n_t`, `l_n` o 549 - `None`); `weighted_impact_rating()` devuelve un `ImpactRatingResult` (`rating`, 550 - `ci` enteros, `unfavourable_sum` en dB). 551 - 552 - ### Aislamiento a ruido aéreo de fachadas en campo (ISO 16283-3) 553 - 554 - La misma lógica fuente/receptor alcanza la **fachada** del edificio, pero ahora 555 - la fuente está *en el exterior*: un altavoz a 45° o el propio tráfico rodado. En 556 - lugar de una diferencia de niveles a través de un cerramiento interior, 557 - ISO 16283-3 referencia el nivel de la sala receptora $L_2$ al nivel **2 m frente 558 - a la fachada** $L_{1,2m}$, dando la diferencia de niveles $D_{2m}$ y, exactamente 559 - como en el caso a ruido aéreo, sus formas estandarizada y normalizada: 560 - 561 - $$ 562 - D_{2m} = L_{1,2m} - L_2, \quad 563 - D_{2m,nT} = D_{2m} + 10 \log_{10}\frac{T}{T_0}, \quad 564 - D_{2m,n} = D_{2m} - 10 \log_{10}\frac{A}{A_0}, 565 - $$ 566 - 567 - con $T_0 = 0.5$ s, $A_0 = 10$ m² y $A = 0.16\ V/T$ (viviendas). Cuando el 568 - micrófono se sitúa **sobre el elemento de ensayo** (nivel superficial $L_{1,s}$), 569 - el método del *elemento* también da un índice de reducción sonora aparente, que 570 - lleva una corrección fija por ángulo de incidencia: $-1.5$ dB para el método del 571 - altavoz a 45° y $-3$ dB para el método de tráfico rodado con todos los ángulos: 572 - 573 - $$ 574 - R'_{45°} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 1.5, \qquad 575 - R'_{tr,s} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 3. 576 - $$ 577 - 578 - La magnitud de fachada es a ruido aéreo, así que su índice de un solo número usa 579 - la curva de referencia de **ISO 717-1** a través de `weighted_rating` sin cambios 580 - (Anexo F). 581 - 582 - ```python 583 - import numpy as np 584 - from phonometry import facade_insulation, weighted_rating 585 - 586 - # Nivel exterior 2 m frente a la fachada, nivel de la sala receptora y T por 587 - # banda de tercio de octava; surface_level es el micrófono sobre el elemento de ensayo. 588 - l1_2m = np.full(16, 75.0) # L1,2m en el exterior 589 - l2 = np.full(16, 33.0) # L2 de la sala receptora 590 - t2 = np.full(16, 0.5) # T de la sala receptora (s) 591 - 592 - fac = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 593 - surface_level=np.full(16, 78.0), method="loudspeaker") 594 - print(round(float(fac.d_2m[0]), 1)) # 42.0 D2m = L1,2m - L2 595 - print(round(float(fac.d_2m_nt[0]), 1)) # 42.0 (= D2m ya que T = T0) 596 - print(round(float(fac.d_2m_n[0]), 1)) # 40.0 normalizado a A0 = 10 m^2 597 - print(round(float(fac.r_prime[0]), 1)) # 42.1 R'45deg (altavoz, -1.5 dB) 598 - 599 - # El método del elemento por tráfico rodado lleva en su lugar la corrección de -3 dB para todos los ángulos 600 - tr = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 601 - surface_level=np.full(16, 78.0), method="road_traffic") 602 - print(round(float(tr.r_prime[0]), 1)) # 40.6 R'tr,s (tráfico, -3 dB) 603 - 604 - # La magnitud de fachada es a ruido aéreo: valora D2m,nT con el motor de ISO 717-1 605 - print(weighted_rating(fac.d_2m_nt).rating) # 42 Dls,2m,nT,w 606 - 607 - fac.plot() # D2m,nT por banda con D2m, D2m,n y R' superpuestos (requiere matplotlib) 608 - ``` 609 - 610 - `surface_level`, `area` y `volume` son todos opcionales: solo con `l1_2m`, `l2` 611 - y `t2` la función devuelve `d_2m` y `d_2m_nt`; añade `volume` para `d_2m_n`; 612 - añade `surface_level` **y** `area` **y** `volume` para `r_prime`. Las posiciones 613 - se promedian en energía con la fórmula del nivel superficial (Cláusula 9.5.1); 614 - se asume que los niveles por banda ya están corregidos por ruido de fondo. 615 - 616 - #### Parámetros de `facade_insulation()` 617 - 618 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 619 - | :--- | :--- | :--- | :--- | :--- | 620 - | `l1_2m` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Nivel 2 m frente a la fachada `L1,2m` | 621 - | `l2` | array 1D o 2D | dB | mismo número de bandas | Niveles de la sala receptora | 622 - | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 623 - | `area` | float, opcional | m² | > 0, con `surface_level`, `volume` | Superficie del elemento de ensayo `S` (habilita `R'`) | 624 - | `volume` | float, opcional | m³ | > 0 | Sala receptora `V` (habilita `D2m,n`; requerido para `R'`) | 625 - | `surface_level` | array 1D/2D, opcional | dB | mismo número de bandas | Nivel superficial `L1,s` sobre el elemento (habilita `R'`) | 626 - | `method` | str | — | `'loudspeaker'` (−1,5 dB) / `'road_traffic'` (−3 dB) | Corrección por ángulo de incidencia de `R'` | 627 - | `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia `T0` | 628 - | `frequencies` | array 1D, opcional | Hz | — | Centros de banda que lleva el resultado para representar | 629 - 630 - `facade_insulation()` devuelve un `FacadeInsulationResult` (`d_2m`, `d_2m_nt`, 631 - `d_2m_n` o `None`, `r_prime` o `None`, `frequencies`); pasa cualquier magnitud de 632 - fachada de 16 bandas a `weighted_rating` para su número único de ISO 717-1. 633 - 634 - ## 5. Medición en laboratorio (ISO 10140) 635 - 636 - Todo lo anterior es una medición **en campo** (las magnitudes con prima $R'$, 637 - $L'_n$): el número que un edificio real alcanza, con transmisión por flancos 638 - incluida. Para valorar un elemento por sí solo —un tipo de pared, un suelo 639 - flotante, una ventana— se lleva a un **laboratorio** cualificado (ISO 10140), 640 - donde la transmisión por flancos suprimida hace que la transmisión *directa* sea 641 - toda la historia. Las fórmulas pierden sus primas: el **índice de reducción 642 - sonora** $R$ (no $R'$) y el **nivel de impactos normalizado** $L_n$ (no $L'_n$), 643 - con el área de absorción de la sala receptora $A = 0.16\ V/T$ ahora una propiedad 644 - conocida de la instalación: 645 - 646 - $$ 647 - R = L_1 - L_2 + 10 \log_{10}\frac{S}{A}, \qquad 648 - L_n = L_i + 10 \log_{10}\frac{A}{A_0}, \quad A_0 = 10\ \text{m}^2. 649 - $$ 650 - 651 - | | Campo (ISO 16283) | Laboratorio (ISO 10140) | 652 - | :--- | :--- | :--- | 653 - | Ruido aéreo | $R'$ aparente (con flancos) | $R$ directo (flancos suprimidos) | 654 - | Impactos | $L'_n$ aparente | $L_n$ directo | 655 - | Área de absorción | medida en la sala | propiedad de la instalación | 656 - 657 - Los índices de un solo número reutilizan los mismísimos motores de ISO 717-1/2 658 - (`weighted_rating`, `weighted_impact_rating`): un espectro $R$ se valora a $R_w$ 659 - exactamente igual que un espectro $R'$ se valoraba a $R'_w$. Antes de formar el 660 - índice, los niveles de la sala receptora deben **corregirse por ruido de fondo** 661 - (Cláusula 4.3): la resta energética $10 \log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ 662 - se aplica para un margen señal-fondo de 6–15 dB, una corrección fija de 1,3 dB 663 - (el *límite de medición*) en 6 dB o por debajo, y ninguna corrección en 15 dB o 664 - por encima. 665 - 666 - ```python 667 - import numpy as np 668 - from phonometry import (lab_airborne_insulation, lab_impact_insulation, 669 - background_correction) 670 - 671 - # Niveles emisor/receptor y T de la sala receptora en las 16 bandas de tercio 672 - # de octava; S es el área libre de la abertura de ensayo, V el volumen de la sala receptora. 673 - l1 = np.full(16, 80.0) 674 - l2 = np.full(16, 40.0) 675 - t2 = np.full(16, 0.5) 676 - lab = lab_airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 677 - print(round(float(lab.r[0]), 1)) # 38.0 R = L1 - L2 + 10 lg(S/A) 678 - print(round(float(lab.absorption[0]), 1)) # 16.0 A = 0.16 V / T (m^2) 679 - print(lab.rating.rating, lab.rating.c, lab.rating.ctr) # 38 0 0 -> Rw(C;Ctr) 680 - 681 - # Impactos: el nivel de la máquina de impactos Li normalizado a A0 = 10 m^2 da Ln 682 - li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 683 - 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 684 - imp = lab_impact_insulation(li, t2, volume=50.0) 685 - print(round(float(imp.l_n[0]), 1)) # 64.1 Ln = Li + 10 lg(A/A0) 686 - print(imp.rating.rating, imp.rating.ci) # 81 -11 -> Ln,w(CI) 687 - 688 - # Corrección por ruido de fondo: márgenes 6 / 1 / 20 dB -> saturado / saturado / sin cambio 689 - corrected = background_correction([30.0, 33.0, 50.0], [24.0, 32.0, 30.0]) 690 - print(np.round(corrected, 1)) # [28.7 31.7 50.0] (saturación de 1.3 dB dos veces) 691 - 692 - lab.rating.plot() # R medido frente a la referencia ISO 717-1 desplazada (requiere matplotlib) 693 - ``` 694 - 695 - Un margen en 6 dB o por debajo emite un `LabInsulationWarning` y marca la banda 696 - como el límite de medición; captúralo con `warnings.simplefilter("error", 697 - LabInsulationWarning)`. El índice automático se forma solo cuando se suministran 698 - exactamente 16 valores en tercio de octava o 5 en octava (`rating` es `None` en 699 - caso contrario). 700 - 701 - ### Parámetros de `lab_airborne_insulation()` / `lab_impact_insulation()` 702 - 703 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 704 - | :--- | :--- | :--- | :--- | :--- | 705 - | `l1` / `l2` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | Niveles emisor / receptor (ruido aéreo) | 706 - | `li` | array 1D o 2D | dB | uno/banda, o `(posiciones, bandas)` | SPL de impactos de la máquina de impactos (impactos) | 707 - | `t2` | array 1D | s | > 0, uno por banda | Tiempo de reverberación de la sala receptora | 708 - | `area` | float | m² | > 0 | Área libre de la abertura de ensayo `S` (solo ruido aéreo) | 709 - | `volume` | float | m³ | > 0 | Volumen de la sala receptora `V` | 710 - 711 - `lab_airborne_insulation()` devuelve un `LabAirborneInsulationResult` (`r`, 712 - `absorption`, `rating`); `lab_impact_insulation()` un 713 - `LabImpactInsulationResult` (`l_n`, `absorption`, `rating`); 714 - `background_correction(signal_and_background, background)` devuelve los niveles 715 - corregidos directamente. 716 - 717 - ## 6. Predicción del comportamiento (EN 12354) 718 - 719 - Un índice de laboratorio describe un elemento de forma aislada, pero el sonido 720 - que un edificio transmite realmente también viaja *alrededor* del cerramiento 721 - —por el suelo, por la fachada, a través de las paredes de flanco— y se vuelve a 722 - radiar en la sala receptora. Esta **transmisión por flancos** es toda la 723 - diferencia entre el $R$ de laboratorio y el $R'$ de campo. EN 12354 predice el 724 - índice aparente in situ a partir de los índices de laboratorio de los elementos 725 - más la transmisión vibratoria de sus uniones. 726 - 727 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_es.svg" alt="El camino directo Dd a través del elemento separador y los tres caminos de flanco Ff, Df y Fd en cada unión entre un elemento de flanco y el elemento separador" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_es_dark.svg" alt="El camino directo Dd a través del elemento separador y los tres caminos de flanco Ff, Df y Fd en cada unión entre un elemento de flanco y el elemento separador" style="width:92%"> 728 - 729 - Cada unión entre un elemento de flanco y el elemento separador lleva tres 730 - caminos —$Ff$ (flanco→flanco), $Df$ (directo→flanco) y $Fd$ (flanco→directo)— 731 - junto al único camino directo $Dd$. El **modelo simplificado de un solo número** 732 - los combina energéticamente (Fórmula 26): 733 - 734 - $$ 735 - R'_w = -10 \log_{10}\Big[ 10^{-R_{Dd,w}/10} 736 - + \sum 10^{-R_{Ff,w}/10} + \sum 10^{-R_{Df,w}/10} 737 - + \sum 10^{-R_{Fd,w}/10} \Big], 738 - $$ 739 - 740 - con el camino directo $R_{Dd,w} = R_{s,w} + \Delta R_{Dd,w}$ (Fórmula 27) y cada 741 - camino de flanco (Fórmula 28a) 742 - 743 - $$ 744 - R_{ij,w} = \tfrac{R_{i,w} + R_{j,w}}{2} + \Delta R_{ij,w} + K_{ij} 745 - + 10 \log_{10}\frac{S_s}{l_0\ l_f}, 746 - $$ 747 - 748 - donde $l_0 = 1$ m es la longitud de acoplamiento de referencia, $l_f$ la longitud 749 - de acoplamiento de la unión y $K_{ij}$ el **índice de reducción vibracional** de 750 - la unión (Anexo E, empírico en la relación de masas 751 - $M = \log_{10}(m'_{\perp,i}/m'_i)$). 752 - 753 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_es.png" alt="Índices de reducción sonora por camino para el ejemplo del Anexo H.3 de EN 12354-1 y la fracción de energía transmitida de cada camino, mostrando el camino directo dominando en R'w = 52 dB" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_es_dark.png" alt="Índices de reducción sonora por camino para el ejemplo del Anexo H.3 de EN 12354-1 y la fracción de energía transmitida de cada camino, mostrando el camino directo dominando en R'w = 52 dB" style="width:80%"> 754 - 755 - ```python 756 - import numpy as np 757 - from phonometry import (junction_vibration_reduction, flanking_element, 758 - predicted_airborne_insulation) 759 - 760 - # EN 12354-1 Anexo H.3: una pared separadora Rs,w = 57 dB, área Ss = 11.5 m², con 761 - # cuatro elementos de flanco. El modelo simplificado lee el Kij de cada unión a 762 - # 500 Hz a partir de la relación de masas m'perp / m' (Anexo E); aquí la unión 763 - # rígida en cruz del suelo (la relación de masas está redondeada, de ahí 12.5 vs Anexo 12.4): 764 - print(round(junction_vibration_reduction("rigid_cross", "through", 1.61), 1)) # 12.5 KFf 765 - print(round(junction_vibration_reduction("rigid_cross", "corner", 1.61), 1)) # 8.9 KFd = KDf 766 - 767 - # Construye los tres caminos de flanco (Ff, Df, Fd) de cada elemento a partir del 768 - # Kij tabulado del Anexo H, luego combina el camino directo Dd energéticamente (Fórmula 26). 769 - elements = [ # (nombre, Rw, KFf, KFd = KDf, longitud de acoplamiento lf) 770 - ("floor", 49, 12.4, 8.9, 4.50), 771 - ("ceiling", 46, 14.4, 9.2, 4.50), 772 - ("facade", 42, 12.6, 6.7, 2.55), 773 - ("int-wall", 33, 33.5, 15.7, 2.55), 774 - ] 775 - paths = [] 776 - for name, rw, k_ff, k_fd, lf in elements: 777 - paths += flanking_element(label=name, r_flanking=rw, r_separating=57, 778 - k_ff=k_ff, k_fd=k_fd, k_df=k_fd, 779 - separating_area=11.5, coupling_length=lf) 780 - 781 - res = predicted_airborne_insulation(r_direct=57.0, flanking_paths=paths) 782 - print(round(res.r_prime_w, 1)) # 52.2 -> R'w = 52 dB 783 - print(res.dominant.label, round(res.dominant.fraction, 2)) # Dd 0.33 (domina el directo) 784 - ``` 785 - 786 - Cada camino de flanco añadido rebaja estrictamente $R'_w$ por debajo del directo 787 - $R_{Dd,w} = 57$; `res.paths` expone la fracción de energía transmitida de cada 788 - camino, de modo que el camino dominante queda visible. La Cláusula 4.4.2 también 789 - impone un límite inferior $K_{ij} \ge K_{ij,\min}$ a partir de la geometría de la 790 - unión: calcúlalo con `junction_min_vibration_reduction` y pásalo a 791 - `flanking_path(..., kij_min=...)`, que eleva un $K_{ij}$ por debajo del límite 792 - hasta el mínimo: 793 - 794 - ```python 795 - from phonometry import junction_min_vibration_reduction 796 - # Kij,min = 10 lg[lf·l0·(1/Si + 1/Sj)]; los elementos grandes dan un límite bajo 797 - # (aquí negativo), así que un Kij tabulado realista rara vez se satura. 798 - print(round(junction_min_vibration_reduction(coupling_length=4.5, 799 - s_i=11.5, s_j=11.5), 1)) # -1.1 800 - ``` 801 - 802 - La contrapartida a impactos (EN 12354-2, Fórmula 21) es una resta directa: 803 - $L'_{n,w} = L_{n,w,eq} - \Delta L_w + K$, con el nivel equivalente del suelo 804 - desnudo $L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Anexo B), la mejora del 805 - revestimiento $\Delta L_w$ (ISO 717-2) y la corrección por flancos $K$ de la 806 - Tabla 1. 807 - 808 - ```python 809 - from phonometry import (equivalent_impact_level, impact_flanking_correction, 810 - predicted_impact_insulation, standardized_impact_level) 811 - 812 - # EN 12354-2 Anexo E.3: un forjado de hormigón de 0.14 m (m' = 322 kg/m²) con un 813 - # suelo flotante (ΔLw = 33 dB), salas una sobre otra, masa media de flanco 145 kg/m². 814 - ln_eq = equivalent_impact_level(322.0) # 164 - 35 lg(m') 815 - k = impact_flanking_correction(322.0, 145.0) # Tabla 1 (sep 322, flk 145) 816 - imp = predicted_impact_insulation(ln_w_eq=ln_eq, delta_l_w=33.0, k_correction=k) 817 - print(round(ln_eq, 1), k, round(imp.l_prime_n_w, 1)) # 76.2 2 45.2 -> L'n,w = 45 dB 818 - print(round(standardized_impact_level(imp.l_prime_n_w, 50.0), 1)) # 43.0 L'nT,w 819 - ``` 820 - 821 - <details> 822 - <summary>Ver el código de esta figura</summary> 823 - 824 - ```python 825 - import matplotlib.pyplot as plt 826 - 827 - # Índice de reducción sonora por camino y fracción de energía transmitida de cada 828 - # camino para el resultado del Anexo H.3 calculado arriba. 829 - labels = [p.label for p in res.paths] 830 - r_w = [p.r_w for p in res.paths] 831 - frac = [100.0 * p.fraction for p in res.paths] 832 - 833 - fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True) 834 - ax1.bar(labels, r_w, color="tab:blue") 835 - ax1.axhline(res.r_prime_w, ls="--", color="k", label=f"R'w = {res.r_prime_w:.1f} dB") 836 - ax1.set_ylabel("Rij,w del camino [dB]"); ax1.legend() 837 - ax2.bar(labels, frac, color="tab:orange") 838 - ax2.set_ylabel("Fracción de energía [%]"); ax2.set_xlabel("Camino de transmisión") 839 - for ax in (ax1, ax2): 840 - ax.tick_params(axis="x", rotation=45) 841 - fig.suptitle("EN 12354-1 Anexo H.3 — transmisión por flancos") 842 - fig.tight_layout() 843 - plt.show() 844 - ``` 845 - 846 - </details> 847 - 848 - ### Parámetros de `junction_vibration_reduction()` / `flanking_element()` 849 - 850 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 851 - | :--- | :--- | :--- | :--- | :--- | 852 - | `junction_type` | str | — | `'rigid_cross'` / `'rigid_t'` / `'flexible_t'` / `'lightweight_facade'` | Geometría de la unión (Anexo E) | 853 - | `path` | str | — | `'through'` (K13) / `'corner'` (K12 = K23) | Rama del camino | 854 - | `mass_ratio` | float | — | > 0 | `m'⊥,i / m'i` (Fórmula E.2) | 855 - | `frequency` | float | Hz | por defecto `500` | Solo `flexible_t` depende de la frecuencia | 856 - | `r_flanking` / `r_separating` | float | dB | — | Índices ponderados del elemento de flanco / separador | 857 - | `k_ff` / `k_fd` / `k_df` | float | dB | — | `Kij` de la unión para los tres caminos | 858 - | `separating_area` | float | m² | > 0 | Superficie del elemento separador `Ss` | 859 - | `coupling_length` | float | m | > 0 | Longitud de acoplamiento de la unión `lf` | 860 - | `delta_r_ff` / `delta_r_fd` / `delta_r_df` | float | dB | por defecto `0` | Mejoras del trasdosado por camino | 861 - 862 - `predicted_airborne_insulation()` devuelve un `AirbornePredictionResult` 863 - (`r_prime_w`, `r_direct_w`, `paths` de `PathContribution`, `dominant`); 864 - `predicted_impact_insulation()` un `ImpactPredictionResult` (`l_prime_n_w`, 865 - `ln_w_eq`, `delta_l_w`, `k_correction`). El modelo simplificado lleva una 866 - desviación típica declarada de unos 2 dB (Cláusula 5). 867 - 868 - ## 7. Incertidumbre de medición (ISO 12999-1) 869 - 870 - Un índice sin incertidumbre es solo medio resultado. ISO 12999-1 no vuelve a 871 - medir nada; tabula la **incertidumbre típica** $u$ de cada magnitud de 872 - aislamiento acústico —derivada de ensayos interlaboratorio— y prescribe cómo 873 - expandirla y combinarla. Qué desviación típica es $u$ depende de la **situación 874 - de medición** (Cláusula 5.2): 875 - 876 - | Situación | Significado | Incertidumbre típica $u$ | 877 - | :--- | :--- | :--- | 878 - | **A** | caracterización en laboratorio (ISO 10140) | reproducibilidad $\sigma_R$ | 879 - | **B** | misma ubicación, equipos distintos | in situ $\sigma_{situ}$ | 880 - | **C** | misma ubicación, mismo operador repetido | repetibilidad $\sigma_r$ | 881 - 882 - La incertidumbre expandida es $U = k\ u$ (Fórmula 2) con el factor de cobertura 883 - $k$ de la Tabla 8. Un intervalo bilateral $Y = y \pm U$ (Fórmula 3, $k = 1.96$ al 884 - 95 %) *informa* un valor; el factor **unilateral** ($k = 1.65$ al 95 %) *declara 885 - conformidad* con un requisito (Fórmulas 4/5). 886 - 887 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_es.png" alt="Un índice ponderado informado con su incertidumbre expandida bilateral al 95 % en las situaciones A, B y C, con la incertidumbre de reproducibilidad más ancha y la de repetibilidad más estrecha" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_es_dark.png" alt="Un índice ponderado informado con su incertidumbre expandida bilateral al 95 % en las situaciones A, B y C, con la incertidumbre de reproducibilidad más ancha y la de repetibilidad más estrecha" style="width:80%"> 888 - 889 - ```python 890 - from phonometry import (band_uncertainty, single_number_uncertainty, 891 - uncertain_value, satisfies_lower_requirement) 892 - 893 - # Situación B (mismo edificio, equipos distintos) -> la desviación típica in situ. 894 - print(single_number_uncertainty("r_w", "B")) # 0.9 dB (Tabla 3) 895 - u = band_uncertainty("airborne", "B") # u por banda (Tabla 2) 896 - print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (la banda de 500 Hz) 897 - 898 - # Informa R'w = 52 dB con un intervalo bilateral al 95 % (k = 1.96, Tabla 8): 899 - uv = uncertain_value(52.0, "rprime_w", "B") # los alias resuelven a r_w 900 - print(uv.coverage_factor, round(uv.expanded_uncertainty, 1)) # 1.96 1.8 901 - print(round(uv.lower, 1), round(uv.upper, 1)) # 50.2 53.8 -> 52 ± 1.8 dB 902 - 903 - # Declarar conformidad usa el factor UNILATERAL (k = 1.65): ¿supera R'w de forma 904 - # demostrable un requisito de 50 dB? 905 - uc = uncertain_value(52.0, "rprime_w", "B", one_sided=True) 906 - print(satisfies_lower_requirement(52.0, uc.expanded_uncertainty, 50.0)) # True 907 - ``` 908 - 909 - Las magnitudes a impactos ofrecen solo las situaciones B/C (Tabla 4, sin banda de 910 - 500 Hz en la edición de 2020), y $\Delta L$ solo la situación A. Los descriptores 911 - son insensibles a mayúsculas y con alias (`rprime_w`/`dnt_w`→`r_w`, 912 - `lprime_n_w`→`ln_w`); combina componentes independientes en cuadratura con 913 - `combine_uncertainties`, y redúcelas por $m$ mediciones independientes con 914 - `reduce_by_independent_measurements` ($u/\sqrt{m}$). 915 - 916 - <details> 917 - <summary>Ver el código de esta figura</summary> 918 - 919 - ```python 920 - import matplotlib.pyplot as plt 921 - from phonometry import uncertain_value 922 - 923 - # El mismo R'w = 52 dB informado en cada situación con su U bilateral al 95 %. 924 - situations = ["A", "B", "C"] 925 - vals = [uncertain_value(52.0, "r_w", s) for s in situations] 926 - 927 - fig, ax = plt.subplots(figsize=(7, 4)) 928 - ax.errorbar(situations, [v.value for v in vals], 929 - yerr=[v.expanded_uncertainty for v in vals], 930 - fmt="o", capsize=8, color="tab:blue") 931 - for s, v in zip(situations, vals): 932 - ax.annotate(f"±{v.expanded_uncertainty:.1f}", (s, v.upper), 933 - textcoords="offset points", xytext=(8, 4)) 934 - ax.set_ylabel("R'w [dB]"); ax.set_xlabel("Situación de medición") 935 - ax.set_title("R'w = 52 dB con incertidumbre expandida al 95 % (ISO 12999-1)") 936 - fig.tight_layout() 937 - plt.show() 938 - ``` 939 - 940 - </details> 941 - 942 - ### Parámetros de `band_uncertainty()` / `single_number_uncertainty()` / `uncertain_value()` 943 - 944 - | Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas | 945 - | :--- | :--- | :--- | :--- | :--- | 946 - | `measurand` | str | — | `'airborne'` / `'impact'` / `'impact_reduction'` | Selecciona la Tabla 2 / 4 / 6 | 947 - | `quantity` | str | — | `'r_w'`, `'ln_w'`, `'delta_lw'` (+ alias, variantes `+c`/`+ctr`) | Descriptor de un solo número | 948 - | `situation` | str | — | `'A'` / `'B'` / `'C'` | Situación de medición (Cláusula 5.2) | 949 - | `value` | float | dB | — | Mejor estimación `y` a la que adjuntar `U` | 950 - | `coverage` | float | — | por defecto `0.95` | Nivel de confianza (Tabla 8) | 951 - | `one_sided` | bool | — | por defecto `False` | Factor unilateral para verificaciones de conformidad | 952 - | `upper_limit` | bool | — | por defecto `False` | Selecciona el límite superior σR95 (ruido aéreo, situación A) | 953 - 954 - `band_uncertainty()` devuelve una `BandUncertainty` (`frequencies`, 955 - `uncertainties`, `.to_arrays()`); `single_number_uncertainty()` un float; 956 - `uncertain_value()` un `UncertainValue` (`value`, `standard_uncertainty`, 957 - `coverage_factor`, `expanded_uncertainty`, `.lower`, `.upper`). El mapa de solo 958 - lectura `COVERAGE_FACTORS` expone la Tabla 8 indexada por `(confidence, one_sided)`. 959 - 960 - ## 8. Absorción sonora (ISO 354) 325 + ## 4. Absorción sonora (ISO 354) 961 326 962 327 El área de absorción sonora equivalente `A` que gobierna `R'`, `L'n`, la 963 328 corrección ambiental `K2` de ISO 3744 y el término de absorción de ISO 3741 se ··· 1019 384 1020 385 ## Véase también 1021 386 387 + - [Acústica de la edificación y aislamiento](/phonometry/es/guides/building-acoustics/) — 388 + el aislamiento acústico entre recintos en campo, laboratorio y predicción, y su incertidumbre de medición. 1022 389 - [Potencia sonora](/phonometry/es/guides/sound-power/) — los métodos de `LW` que 1023 390 consumen el área de absorción de ISO 354 (el `K2` de ISO 3744 y el término de 1024 391 absorción de ISO 3741).
+227 -8
site/src/content/docs/es/guides/sound-power.md
··· 1 1 --- 2 2 title: "Potencia sonora" 3 - description: "Nivel de potencia sonora LW por tres vías: presión sonora sobre superficie envolvente (ISO 3744/3746), el método de precisión en sala reverberante con las correcciones de Waterhouse y C1/C2 (ISO 3741) y el barrido de intensidad con indicadores de campo y grado alcanzado (ISO 9614-2)." 3 + description: "Nivel de potencia sonora LW por cinco vías: presión sonora sobre superficie envolvente (ISO 3744/3746), el método de precisión en sala reverberante con las correcciones de Waterhouse y C1/C2 (ISO 3741), el barrido de intensidad con indicadores de campo y grado alcanzado (ISO 9614-2), el método de precisión en sala anecoica (ISO 3745) y el barrido de intensidad de precisión (ISO 9614-3)." 4 4 --- 5 5 6 6 La presión *sonora* depende de dónde te sitúes y de la sala en la que estés; ··· 8 8 acústica total por segundo que radia una fuente, referida a `P0 = 1 pW`, y es 9 9 el descriptor de **emisión** independiente del dispositivo que figura en una 10 10 ficha técnica, alimenta una predicción de sala (ISO 12354) o se contrasta con 11 - un límite de emisión de ruido. Esta página cubre las tres vías que phonometry 11 + un límite de emisión de ruido. Esta página cubre las vías que phonometry 12 12 implementa para obtenerlo y cuándo recurrir a cada una: una superficie 13 13 envolvente de *presión* en campo (ISO 3744/3746), el campo difuso de una 14 - *sala reverberante* (ISO 3741) y el *barrido* de intensidad sobre una 15 - superficie (ISO 9614-2). 14 + *sala reverberante* (ISO 3741), el *barrido* de intensidad sobre una 15 + superficie (ISO 9614-2) y —para la máxima exactitud— los grados de precisión 16 + en una *sala anecoica* (ISO 3745) y mediante el *barrido* de intensidad de 17 + precisión (ISO 9614-3). 16 18 17 19 ## Elegir un método 18 20 19 - Las tres proporcionan la misma magnitud —un `LW` por banda y un total 21 + Todas proporcionan la misma magnitud —un `LW` por banda y un total 20 22 ponderado A `LWA`— pero bajo entornos, grados de precisión y restricciones 21 23 prácticas distintos. 22 24 ··· 25 27 | Superficie envolvente | **ISO 3744** (ingeniería) / **ISO 3746** (control) | Presión sonora sobre una semiesfera o caja | Campo esencialmente libre sobre uno o varios planos reflectantes | Grado 2 (`σR0 ≈ 1.5 dB`) / grado 3 (`≈ 3.0 dB`) | In situ o en una sala grande; sin instalación de ensayo especial disponible | 26 28 | Sala reverberante | **ISO 3741** | Presión sonora en el campo difuso | Sala reverberante cualificada de paredes rígidas | Grado 1 (precisión) | Máxima precisión para fuentes estacionarias de banda ancha en laboratorio | 27 29 | Barrido de intensidad | **ISO 9614-2** | Intensidad sonora normal barrida sobre una superficie | Casi cualquiera, tolerante al ruido extraño estacionario | Grado 2 / 3 (a partir de los indicadores de campo por banda) | In situ con ruido de fondo, o una máquina entre muchas | 30 + | Sala anecoica | **ISO 3745** | Presión sonora sobre un conjunto fijo de micrófonos | Sala anecoica o semianecoica cualificada | Grado 1 (precisión) | Emisión de grado de referencia en un laboratorio de campo libre | 31 + | Barrido de intensidad de precisión | **ISO 9614-3** | Intensidad normal barrida, con criterios más estrictos | Casi cualquiera, tolerante al ruido extraño estacionario | Grado 1 (precisión) | Precisión in situ, con las comprobaciones de indicadores de campo de ISO 9614-3 | 28 32 29 33 Los métodos de presión corrigen el nivel superficial por la sala (`K2`) y por 30 34 el ruido de fondo (`K1`); el método en sala reverberante necesita una sala ··· 337 341 `dynamic_capability_index` (`Ld`), `achieved_grade`, `surface_area`, 338 342 `sound_power_level_a` y `grade`. 339 343 344 + ## 4. Grado de precisión, sala anecoica (ISO 3745) 345 + 346 + Cuando se requiere la máxima exactitud, ISO 3745 mide la potencia sonora en una 347 + **sala anecoica** o **semianecoica** cualificada, donde el campo libre permite que 348 + un conjunto fijo de micrófonos muestree directamente la presión sonora radiada. Es 349 + la contraparte de grado 1 del método de superficie envolvente de la Sección 1, con 350 + coordenadas de micrófono normalizadas, una corrección por ruido de fondo por 351 + posición y una corrección meteorológica explícita. 352 + 353 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_precision_anechoic_es.svg" alt="Potencia sonora de precisión de ISO 3745 en una sala anecoica: paredes revestidas de cuñas, el dispositivo bajo ensayo en el centro y un conjunto hemisférico de micrófonos a un radio fijo, con el nivel de potencia sonora formado a partir de la presión promediada en la superficie más las correcciones de área, ruido de fondo y meteorológica" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_precision_anechoic_es_dark.svg" alt="Potencia sonora de precisión de ISO 3745 en una sala anecoica: paredes revestidas de cuñas, el dispositivo bajo ensayo en el centro y un conjunto hemisférico de micrófonos a un radio fijo, con el nivel de potencia sonora formado a partir de la presión promediada en la superficie más las correcciones de área, ruido de fondo y meteorológica" style="width:92%"> 354 + 355 + **Nivel de potencia sonora (Cláusula 8).** El nivel de potencia sonora por banda es 356 + el nivel de presión promediado en la superficie más el término de superficie y las 357 + correcciones: 358 + 359 + $$ 360 + L_W = \overline{L_p} + 10\lg\frac{S}{S_0} + C_1 + C_2 + C_3, 361 + $$ 362 + 363 + con $S = 4\pi r^2$ sobre la esfera o $S = 2\pi r^2$ sobre la semiesfera, 364 + $S_0 = 1\ \text{m}^2$. $C_1$ y $C_2$ son las correcciones meteorológicas 365 + (términos de referencia e impedancia de radiación); $C_3$ tiene en cuenta la 366 + absorción del aire sobre el radio de medición. Las posiciones de micrófono son los 367 + conjuntos normalizados de vectores unitarios de las Tablas D.1 (esfera), E.1 368 + (semiesfera) y E.2 (semiesfera, banda ancha). 369 + 370 + ```python 371 + import numpy as np 372 + import phonometry as ph 373 + 374 + # Las 40 posiciones normalizadas de la semiesfera (vectores unitarios escalados por el radio). 375 + pos = ph.precision_positions("hemisphere", radius=1.0, count=40) 376 + print(pos.shape) # (40, 3) 377 + 378 + # SPL en banda de octava/tercio (dB) en cada una de las 40 posiciones; aquí un 379 + # valor uniforme de 74 dB en una banda. El resultado lleva S = 2*pi*r^2 y LW con C1+C2+C3. 380 + levels = np.full((40, 1), 74.0) 381 + res = ph.sound_power_anechoic(levels, "hemisphere", radius=1.0) 382 + print(round(res.surface_area, 3)) # 6.283 (2*pi*1^2) 383 + print(np.round(res.sound_power_level, 2)) # [81.85] 384 + ``` 385 + 386 + **Correcciones por ruido de fondo y meteorológica.** La corrección por ruido de 387 + fondo $K_1$ se aplica **por posición** y se acota donde la diferencia 388 + señal-fondo es pequeña (Ec. 11); la corrección meteorológica se evalúa a partir de 389 + la temperatura y la presión estática medidas. 390 + 391 + ```python 392 + import numpy as np 393 + import phonometry as ph 394 + 395 + # K1 para una diferencia señal-fondo de 6 dB en una banda de borde <=200 Hz: el 396 + # límite es 1.26 dB (Ec. 11). Los niveles de fuente y fondo son [posiciones, bandas]. 397 + k1 = ph.precision_background_correction( 398 + np.array([[56.0]]), np.array([[50.0]]), np.array([200.0])) 399 + print(round(float(k1[0, 0]), 4)) # 1.2563 400 + 401 + # Correcciones meteorológicas en la referencia de 23 C, 101.325 kPa (Ec. 16): 402 + mc = ph.meteorological_corrections(23.0, 101.325) 403 + print(round(mc.c1, 4), round(mc.c2, 4)) # -0.1282 0.0 404 + 405 + # Incertidumbre expandida (EJEMPLO de la Cláusula 10.5): sigma_R0 = 0.5, sigma_omc = 2.0, 406 + # k = 2 -> U = 4.1 dB. 407 + print(round(ph.precision_uncertainty(0.5, 2.0, 2.0), 3)) # 4.123 408 + ``` 409 + 410 + Sobre varias bandas `sound_power_anechoic` devuelve un `PrecisionSoundPowerResult` 411 + representable que lleva el `LW` por banda y el total ponderado A: 412 + 413 + ```python 414 + import numpy as np 415 + import phonometry as ph 416 + 417 + # Una máquina con pico en frecuencias medias medida sobre el conjunto hemisférico de 418 + # 40 posiciones (Anexo E). levels_positions es el espectro de presión superficial 419 + # (40, NB): un espectro base con pico cerca de 1 kHz más una pequeña dispersión espacial por posición. 420 + freqs = np.array([125, 250, 500, 1000, 2000, 4000, 8000], float) 421 + base = 70.0 + 8.0 * np.exp(-(np.log2(freqs / 1000.0) ** 2) / 2.0) 422 + rng = np.random.default_rng(7) 423 + levels = base[None, :] + rng.normal(0.0, 1.0, (40, freqs.size)) 424 + 425 + result = ph.sound_power_anechoic(levels, "hemisphere", radius=1.0, frequencies=freqs) 426 + print(round(result.sound_power_level_a, 1)) # 89.3 427 + result.plot() # espectro LW, LWA en el título (requiere matplotlib) 428 + ``` 429 + 430 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/precision_anechoic_power_es.png" alt="El espectro de nivel de potencia sonora de precisión de una máquina con pico en frecuencias medias medida sobre el conjunto hemisférico de ISO 3745, una barra por banda con pico cerca de 1 kHz, con el total ponderado A de 89,3 dB(A) en el título" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/precision_anechoic_power_es_dark.png" alt="El espectro de nivel de potencia sonora de precisión de una máquina con pico en frecuencias medias medida sobre el conjunto hemisférico de ISO 3745, una barra por banda con pico cerca de 1 kHz, con el total ponderado A de 89,3 dB(A) en el título" style="width:88%"> 431 + 432 + *Una barra por banda: la presión promediada en la superficie más las correcciones 433 + de área, ruido de fondo y meteorológica dan `LW(f)`, y la suma energética ponderada 434 + A entre bandas da el número único `LWA` del título.* 435 + 436 + <details> 437 + <summary>Ver el código de esta figura</summary> 438 + 439 + ```python 440 + import matplotlib.pyplot as plt 441 + import numpy as np 442 + 443 + # result es el PrecisionSoundPowerResult calculado arriba. Una línea: 444 + result.plot() 445 + plt.show() 446 + 447 + # A mano: un espectro de barras de LW con el total ponderado A en el título. 448 + freqs = result.frequencies 449 + positions = np.arange(freqs.size) 450 + fig, ax = plt.subplots() 451 + ax.bar(positions, result.sound_power_level, width=0.7, color="#1f77b4") 452 + ax.set_xticks(positions) 453 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 454 + ax.set_xlabel("Frecuencia [Hz]") 455 + ax.set_ylabel("Nivel de potencia sonora LW [dB]") 456 + ax.set_title( 457 + f"Potencia sonora de precisión (ISO 3745) LWA = {result.sound_power_level_a:.1f} dB(A)") 458 + plt.show() 459 + ``` 460 + 461 + </details> 462 + 463 + ## 5. Barrido de intensidad de precisión (ISO 9614-3) 464 + 465 + ISO 9614-3 es el método de barrido de grado 1: como ISO 9614-2, integra la 466 + intensidad normal sobre una superficie que encierra la fuente, pero con un barrido 467 + continuo, criterios de indicadores de campo más estrictos y un presupuesto de 468 + incertidumbre explícito. 469 + 470 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_intensity_scan_es.svg" alt="Barrido de intensidad sonora de precisión de ISO 9614-3: una fuente encerrada por una superficie de medición dividida en segmentos, una sonda de intensidad de dos micrófonos barrida a lo largo de un recorrido en serpentina sobre cada segmento, y la potencia sonora formada sumando la intensidad normal por el área del segmento, sujeta a los criterios de aceptación de los indicadores de campo" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_intensity_scan_es_dark.svg" alt="Barrido de intensidad sonora de precisión de ISO 9614-3: una fuente encerrada por una superficie de medición dividida en segmentos, una sonda de intensidad de dos micrófonos barrida a lo largo de un recorrido en serpentina sobre cada segmento, y la potencia sonora formada sumando la intensidad normal por el área del segmento, sujeta a los criterios de aceptación de los indicadores de campo" style="width:92%"> 471 + 472 + **Potencia y nivel (Cláusula 7).** La potencia parcial de cada segmento es 473 + $P_i = I_{n,i}\,S_i$; el total $P = \sum_i P_i$ da 474 + $L_W = 10\lg(P/P_0)$, $P_0 = 1\ \text{pW}$. Una banda cuya intensidad neta es 475 + negativa (más potencia entrando que saliendo) se marca no aplicable en lugar de 476 + registrarse. Los indicadores de campo (variabilidad temporal $F_T$, los 477 + indicadores presión-intensidad con y sin signo, y la no uniformidad $F_S$) 478 + gobiernan los cinco criterios de aceptación. 479 + 480 + ```python 481 + import numpy as np 482 + import phonometry as ph 483 + 484 + # Una superficie totalmente envolvente con una intensidad normal uniforme In = W/S 485 + # recupera exactamente la potencia de la fuente: LW = 10*lg(W/P0). Aquí W = 100 uW -> 80 dB. 486 + areas = np.array([0.5, 1.0, 0.25, 2.0]) 487 + w = 1.0e-4 488 + i_n = np.full(areas.shape, w / float(areas.sum())) 489 + res = ph.sound_power_intensity_precision(i_n, areas) 490 + print(round(float(res.sound_power[0]), 6)) # 0.0001 491 + print(round(float(res.sound_power_level[0]), 2)) # 80.0 492 + ``` 493 + 494 + A lo largo de varias bandas el resultado lleva el `LW` por banda (`NaN` donde la 495 + potencia neta es no positiva) y marca esas bandas como `not_applicable`: 496 + 497 + ```python 498 + import numpy as np 499 + import phonometry as ph 500 + 501 + # Cuatro superficies parciales barridas sobre cinco bandas de tercio de octava. Cada 502 + # celda de partial_intensity es la intensidad normal con signo In_i (W/m^2); areas son 503 + # las áreas de las superficies parciales Si. La banda de 250 Hz tiene potencia neta 504 + # negativa (un campo localmente reactivo), así que ISO 9614-3 la marca no aplicable (cláusula 9.2) -> NaN. 505 + freqs = np.array([250, 500, 1000, 2000, 4000], float) 506 + areas = np.array([0.5, 1.0, 0.75, 0.5]) 507 + base_intensity = np.array([2.0e-6, 8.0e-6, 2.0e-5, 1.0e-5, 3.0e-6]) 508 + partial_intensity = base_intensity[None, :] * np.array([1.0, 1.1, 0.9, 1.05])[:, None] 509 + partial_intensity[:, 0] = [2.0e-6, -3.0e-6, -4.0e-6, -1.0e-6] # banda de potencia neta negativa 510 + 511 + result = ph.sound_power_intensity_precision(partial_intensity, areas, frequencies=freqs) 512 + print(result.not_applicable_band.tolist()) # [True, False, False, False, False] 513 + print(round(result.sound_power_level_a, 1)) # 80.6 514 + result.plot() # espectro LW; la banda no aplicable con trama (requiere matplotlib) 515 + ``` 516 + 517 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_scan_power_es.png" alt="El espectro de nivel de potencia sonora del barrido de intensidad de precisión sobre cinco bandas de tercio de octava, cuatro barras determinadas y una banda de 250 Hz con trama y en gris marcada como no aplicable porque su intensidad neta es negativa, con el total ponderado A de 80,6 dB(A) en el título" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_scan_power_es_dark.png" alt="El espectro de nivel de potencia sonora del barrido de intensidad de precisión sobre cinco bandas de tercio de octava, cuatro barras determinadas y una banda de 250 Hz con trama y en gris marcada como no aplicable porque su intensidad neta es negativa, con el total ponderado A de 80,6 dB(A) en el título" style="width:88%"> 518 + 519 + *La banda de 250 Hz da un neto negativo (más energía entrando que saliendo), así que 520 + ISO 9614-3 la declara no aplicable —la figura la trama y la agrisa mientras las 521 + cuatro bandas determinadas y el total ponderado A se mantienen.* 522 + 523 + <details> 524 + <summary>Ver el código de esta figura</summary> 525 + 526 + ```python 527 + import matplotlib.pyplot as plt 528 + import numpy as np 529 + 530 + # result es el PrecisionIntensityResult calculado arriba. Una línea: 531 + result.plot() 532 + plt.show() 533 + 534 + # A mano: bandas determinadas como barras de LW; una banda no aplicable (su LW es NaN) 535 + # se señala con una franja gris y con trama a plena altura en lugar de una barra de altura cero. 536 + freqs = result.frequencies 537 + positions = np.arange(freqs.size) 538 + neg = result.not_applicable_band 539 + lw = np.nan_to_num(result.sound_power_level) 540 + fig, ax = plt.subplots() 541 + ax.bar(positions[~neg], lw[~neg], width=0.7, color="#1f77b4") 542 + for pos in positions[neg]: 543 + ax.axvspan(pos - 0.35, pos + 0.35, facecolor="#888888", alpha=0.28, 544 + hatch="//", edgecolor="#888888") 545 + ax.set_xticks(positions) 546 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 547 + ax.set_xlabel("Frecuencia [Hz]") 548 + ax.set_ylabel("Nivel de potencia sonora LW [dB]") 549 + ax.set_title( 550 + f"Barrido de intensidad de precisión (ISO 9614-3) " 551 + f"LWA = {result.sound_power_level_a:.1f} dB(A)") 552 + plt.show() 553 + ``` 554 + 555 + </details> 556 + 340 557 ## Véase también 341 558 342 559 - [Intensidad sonora (p-p)](/phonometry/es/guides/intensity/) — la sonda de dos 343 560 micrófonos, su sesgo por diferencias finitas y los indicadores de campo de 344 561 ISO 9614-1 que sustentan el método de barrido. 345 - - [Acústica de salas y edificación](/phonometry/es/guides/room-acoustics/) — el tiempo 562 + - [Acústica de salas](/phonometry/es/guides/room-acoustics/) — el tiempo 346 563 de reverberación y el área de absorción sonora equivalente (ISO 354) que 347 - alimentan `K2` y el área de absorción de ISO 3741; aislamiento a impactos y a 348 - ruido aéreo. 564 + alimentan `K2` y el área de absorción de ISO 3741. 565 + - [Acústica de la edificación y aislamiento](/phonometry/es/guides/building-acoustics/) — los 566 + índices de aislamiento a ruido aéreo y a impactos y las predicciones de emisión 567 + de EN 12354 que consumen una `LW` de fuente. 349 568 - [Niveles](/phonometry/es/guides/levels/) — el promediado en energía y la ponderación A 350 569 tras `LWA`. 351 570 - [Teoría](/phonometry/es/reference/theory/) — las derivaciones de Waterhouse, K1/K2 y
+420
site/src/content/docs/es/guides/surface-scattering.md
··· 1 + --- 2 + title: "Dispersión superficial, difusión y absorción in situ" 3 + description: "Cómo devuelve una superficie el sonido incidente: el coeficiente de dispersión (scattering) de incidencia aleatoria en sala reverberante (ISO 17497-1), el coeficiente de difusión por autocorrelación de un goniómetro en campo libre (ISO 17497-2) y la absorción in situ de pavimentos por la técnica de sustracción (ISO 13472-1) y el método de tubo puntual (ISO 13472-2)." 4 + --- 5 + 6 + Cómo devuelve una superficie el sonido incidente —cuánto dispersa fuera de la 7 + dirección especular, con qué uniformidad reparte lo que dispersa y cuánto 8 + absorbe— se mide con una familia de métodos dedicados. La **sala reverberante** 9 + proporciona el *coeficiente de dispersión* de incidencia aleatoria de una 10 + superficie comparando las caídas con la muestra inmóvil y en rotación 11 + (ISO 17497-1). Un **goniómetro en campo libre** mide la respuesta polar del 12 + sonido reflejado y la condensa en un *coeficiente de difusión* (ISO 17497-2). Y 13 + sobre un pavimento, un altavoz y un solo micrófono recuperan la *absorción in 14 + situ* del firme, ya sea sobre una superficie extensa restando la onda incidente 15 + (ISO 13472-1) o a través de un pequeño tubo apoyado sobre la superficie 16 + (ISO 13472-2). Esta página cubre los cuatro. 17 + 18 + Los coeficientes de dispersión y de difusión responden a preguntas distintas y no 19 + son intercambiables: la dispersión es *cuánta* energía abandona la dirección 20 + especular; la difusión es *cuán uniformemente* se reparte en ángulo la energía 21 + reflejada. 22 + 23 + ## 1. Coeficiente de dispersión de incidencia aleatoria (ISO 17497-1) 24 + 25 + El coeficiente de dispersión $s$ es la fracción de energía reflejada que **no** 26 + abandona la superficie en la dirección especular. ISO 17497-1 lo mide en una sala 27 + reverberante a partir de cuatro situaciones de tiempo de reverberación: con la 28 + muestra de ensayo montada sobre una plataforma giratoria y mantenida 29 + **inmóvil**, y con la plataforma **en rotación** (que promedia y elimina la 30 + reflexión especular coherente en fase), cada una con y sin una placa base 31 + reflectante. 32 + 33 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_scattering_reverb_es.svg" alt="Montaje de dispersión de incidencia aleatoria de ISO 17497-1: una sala reverberante con la muestra de ensayo sobre una plataforma giratoria, un brazo de altavoz giratorio y un micrófono, midiendo el tiempo de reverberación con la muestra inmóvil (que da la absorción de incidencia aleatoria) y en rotación (que da la absorción especular), a partir de los cuales se deriva el coeficiente de dispersión" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_scattering_reverb_es_dark.svg" alt="Montaje de dispersión de incidencia aleatoria de ISO 17497-1: una sala reverberante con la muestra de ensayo sobre una plataforma giratoria, un brazo de altavoz giratorio y un micrófono, midiendo el tiempo de reverberación con la muestra inmóvil (que da la absorción de incidencia aleatoria) y en rotación (que da la absorción especular), a partir de los cuales se deriva el coeficiente de dispersión" style="width:92%"> 34 + 35 + **Absorción a partir del tiempo de reverberación (cláusula 6).** Cada situación se 36 + convierte en un coeficiente de absorción de Sabine con el propio término de 37 + atenuación del aire de la norma: 38 + 39 + $$ 40 + \alpha = 55.3\,\frac{V}{S}\left(\frac{1}{c_2 T_2} - \frac{1}{c_1 T_1}\right) 41 + - 4\,\frac{V}{S}\,(m_2 - m_1), 42 + $$ 43 + 44 + donde $V$ es el volumen de la sala, $S$ el área de la muestra, $T$ el tiempo de 45 + reverberación, $c$ la velocidad del sonido (ec. (2): $c = 343.2\sqrt{(273.15+t)/293.15}$) 46 + y $m$ el coeficiente de atenuación en potencia del aire. El par **inmóvil** da la 47 + absorción de incidencia aleatoria $\alpha_s$ (ec. (1)); el par **en rotación** da 48 + la absorción especular $\alpha_{spec}$ (ec. (4)). 49 + 50 + **Coeficiente de dispersión (ec. (5)).** Ambos se combinan en 51 + 52 + $$ 53 + s = \frac{\alpha_{spec} - \alpha_s}{1 - \alpha_s}. 54 + $$ 55 + 56 + Una superficie totalmente especular refleja toda su energía no absorbida en la 57 + dirección especular, de modo que $\alpha_{spec} = \alpha_s$ y $s = 0$; un difusor 58 + fuerte envía energía en todas direcciones, elevando $\alpha_{spec}$ hacia 1 y $s$ 59 + hacia 1. 60 + 61 + ```python 62 + import phonometry as ph 63 + 64 + # Cuatro situaciones de tiempo de reverberación reducidas a dos coeficientes de absorción. 65 + # alpha_s del par inmóvil (ec. 1); alpha_spec del par en rotación (ec. 4). 66 + # V = 200 m^3, S = 10 m^2, c = 343.2 m/s en todo momento. 67 + alpha_s = ph.random_incidence_absorption(200.0, 10.0, c1=343.2, T1=8.0, 68 + c2=343.2, T2=6.0) 69 + alpha_spec = ph.specular_absorption_coefficient(200.0, 10.0, c3=343.2, T3=7.5, 70 + c4=343.2, T4=5.0) 71 + s = ph.scattering_coefficient(alpha_spec, alpha_s) # ec. (5) 72 + print(round(float(alpha_s), 4)) # 0.1343 73 + print(round(float(alpha_spec), 4)) # 0.2148 74 + print(round(float(s), 4)) # 0.0931 75 + ``` 76 + 77 + Sobre una medición completa en tercios de octava, `scattering_coefficient_spectrum` 78 + empareja los $\alpha_{spec}$ y $\alpha_s$ por banda con sus centros de banda y 79 + devuelve un `ScatteringResult` representable: 80 + 81 + ```python 82 + import numpy as np 83 + import phonometry as ph 84 + 85 + # Una medición de 13 bandas (250-4000 Hz): la absorción de incidencia aleatoria 86 + # alpha_s (muestra inmóvil) y la absorción especular alpha_spec (plataforma en 87 + # rotación). Un difusor dispersa más con la frecuencia, así que s(f) crece. 88 + freqs = np.array([250, 315, 400, 500, 630, 800, 1000, 89 + 1250, 1600, 2000, 2500, 3150, 4000], float) 90 + alpha_s = np.full_like(freqs, 0.10) 91 + alpha_spec = 0.11 + 0.75 * (np.log10(freqs / 250) / np.log10(4000 / 250)) 92 + 93 + result = ph.scattering_coefficient_spectrum(freqs, alpha_spec, alpha_s) 94 + print(np.round(result.scattering[[0, 6, 12]], 3)) # [0.011 0.428 0.844] 95 + result.plot() # s(f) en eje de frecuencia logarítmico, de 0 a 1 (requiere matplotlib) 96 + ``` 97 + 98 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/scattering_coefficient_es.png" alt="El coeficiente de dispersión de incidencia aleatoria s de una superficie difusora sobre las 13 bandas de tercio de octava de 250 a 4000 Hz, creciendo suavemente desde casi cero a baja frecuencia hasta 0,84 a 4 kHz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/scattering_coefficient_es_dark.png" alt="El coeficiente de dispersión de incidencia aleatoria s de una superficie difusora sobre las 13 bandas de tercio de octava de 250 a 4000 Hz, creciendo suavemente desde casi cero a baja frecuencia hasta 0,84 a 4 kHz" style="width:88%"> 99 + 100 + *El coeficiente de dispersión asciende con la frecuencia: a baja frecuencia el 101 + relieve de la superficie es pequeño frente a la longitud de onda y la reflexión 102 + permanece especular ($s \to 0$); al acortarse la longitud de onda el relieve 103 + dispersa más energía fuera de la dirección especular ($s \to 1$).* 104 + 105 + <details> 106 + <summary>Ver el código de esta figura</summary> 107 + 108 + ```python 109 + import matplotlib.pyplot as plt 110 + 111 + # result es el ScatteringResult calculado arriba. En una línea: 112 + result.plot() 113 + plt.show() 114 + 115 + # A mano, a partir de los campos del resultado, replicando lo que dibuja ScatteringResult.plot(): 116 + fig, ax = plt.subplots() 117 + ax.semilogx(result.frequencies, result.scattering, "o-", color="#1f77b4") 118 + ax.set_xlabel("Frecuencia [Hz]") 119 + ax.set_ylabel("Coeficiente de dispersión s") 120 + ax.set_ylim(0.0, 1.0) 121 + ax.set_title("Coeficiente de dispersión de incidencia aleatoria (ISO 17497-1)") 122 + plt.show() 123 + ``` 124 + 125 + </details> 126 + 127 + **Comprobación de la placa base (cláusula 6.4, Tabla 1).** La placa base vacía 128 + debe dispersar por sí sola de forma despreciable, o sesgaría el resultado. 129 + ISO 17497-1 limita el coeficiente de dispersión de la placa base por banda de 130 + tercio de octava; la librería expone esos límites y un comprobador. 131 + 132 + ```python 133 + from phonometry import ( 134 + BASE_PLATE_BANDS_HZ, BASE_PLATE_MAX_SCATTERING, check_base_plate_scattering, 135 + ) 136 + 137 + # Los techos normativos por banda (Tabla 1): 0.05 hasta 500 Hz, ascendiendo a 0.25. 138 + # BASE_PLATE_BANDS_HZ es la tupla de bandas; BASE_PLATE_MAX_SCATTERING asigna banda -> techo. 139 + print(BASE_PLATE_BANDS_HZ[0], BASE_PLATE_MAX_SCATTERING[100]) # 100 0.05 140 + 141 + # Una placa base cuya dispersión medida se mantiene bajo el techo pasa en silencio; 142 + # una banda que lo supera lanza un ScatteringDiffusionWarning que lista las infractoras. 143 + check_base_plate_scattering([0.02] * len(BASE_PLATE_BANDS_HZ)) 144 + ``` 145 + 146 + ## 2. Coeficiente de difusión (ISO 17497-2) 147 + 148 + El coeficiente de difusión $d$ mide la **uniformidad espacial** del sonido 149 + reflejado, no cuánto se dispersa. Un goniómetro barre un receptor sobre un arco 150 + polar y registra el nivel reflejado $L_i$ en cada ángulo; el coeficiente es la 151 + autocorrelación normalizada de la distribución de energía polar. 152 + 153 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_diffusion_goniometer_es.svg" alt="Goniómetro de difusión en campo libre de ISO 17497-2: una muestra de ensayo sobre una plataforma giratoria, una fuente de altavoz fija y un arco semicircular de micrófonos receptores muestreando la respuesta polar reflejada, a partir de la cual se calcula el coeficiente de difusión por autocorrelación" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_diffusion_goniometer_es_dark.svg" alt="Goniómetro de difusión en campo libre de ISO 17497-2: una muestra de ensayo sobre una plataforma giratoria, una fuente de altavoz fija y un arco semicircular de micrófonos receptores muestreando la respuesta polar reflejada, a partir de la cual se calcula el coeficiente de difusión por autocorrelación" style="width:92%"> 154 + 155 + **Autocorrelación (fórmula (5)).** Para $n$ receptores con espaciado angular 156 + igual, con $p_i = 10^{L_i/10}$ la energía de banda en el receptor $i$, 157 + 158 + $$ 159 + d = \frac{\left(\sum_i p_i\right)^2 - \sum_i p_i^2} 160 + {(n-1)\,\sum_i p_i^2}. 161 + $$ 162 + 163 + Una respuesta polar perfectamente uniforme ($L_i$ todos iguales) da $d = 1$; un 164 + único lóbulo especular agudo da $d = 0$. Cuando los receptores subtienden ángulos 165 + sólidos desiguales, la fórmula (6) pondera por área cada energía con $N_i$ de la 166 + fórmula (8) —y esos factores de área se evalúan en **radianes**, razón por la que 167 + un espaciado de 5° en el cenit produce un peso cercano a 1,57, no a 51,9. 168 + 169 + ```python 170 + import phonometry as ph 171 + 172 + # Respuesta polar de un difusor (niveles en dB en receptores equiespaciados). 173 + levels = [70.0, 74.0, 68.0, 72.0] 174 + d = ph.directional_diffusion_coefficient(levels) # fórmula (5) 175 + print(round(float(d), 4)) # 0.7367 176 + 177 + # Normaliza frente a una superficie de referencia plana para aislar el efecto del 178 + # difusor (fórmula (7)): d_n = (d - d_ref) / (1 - d_ref). 179 + d_n = ph.normalized_diffusion_coefficient(d, 0.10) 180 + print(round(float(d_n), 4)) # 0.7075 181 + 182 + # Valor de incidencia aleatoria: promedia los coeficientes de banda sobre las 183 + # posiciones de fuente, con la ponderación 2-D de la norma (0 grados -> 1, 184 + # +/-30/+/-60 grados -> 3). 185 + from phonometry import TWO_DIMENSIONAL_SOURCE_WEIGHTS 186 + d_random = ph.random_incidence_diffusion( 187 + [0.5, 0.2, 0.2, 0.2, 0.2], weights=TWO_DIMENSIONAL_SOURCE_WEIGHTS) 188 + print(round(float(d_random), 4)) # 0.2231 189 + ``` 190 + 191 + `directional_diffusion` mantiene los ángulos de los receptores junto a los 192 + niveles de un barrido completo de goniómetro y devuelve un `DiffusionResult` 193 + representable: 194 + 195 + ```python 196 + import numpy as np 197 + import phonometry as ph 198 + 199 + # Un barrido de goniómetro de una superficie difusora: niveles reflejados L_i en 200 + # 37 receptores de -90 a 90 grados (espaciado de 5 grados). La energía se reparte 201 + # casi uniformemente en ángulo, así que el coeficiente d de la fórmula (5) es alto. 202 + angles = np.arange(-90.0, 90.5, 5.0) 203 + rng = np.random.default_rng(3) 204 + levels = 70.0 + 2.0 * np.sin(np.radians(angles) * 3.0) + rng.normal(0.0, 1.0, angles.size) 205 + 206 + result = ph.directional_diffusion(angles, levels) 207 + print(round(result.coefficient, 2)) # 0.82 208 + result.plot() # respuesta polar reflejada, d en el título (requiere matplotlib) 209 + ``` 210 + 211 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diffusion_polar_es.png" alt="Un diagrama polar del nivel de presión sonora reflejado de una superficie difusora sobre 37 receptores de -90 a 90 grados, con la respuesta repartida casi uniformemente en ángulo, dando un coeficiente de difusión por autocorrelación d de aproximadamente 0,82" style="width:72%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diffusion_polar_es_dark.png" alt="Un diagrama polar del nivel de presión sonora reflejado de una superficie difusora sobre 37 receptores de -90 a 90 grados, con la respuesta repartida casi uniformemente en ángulo, dando un coeficiente de difusión por autocorrelación d de aproximadamente 0,82" style="width:72%"> 212 + 213 + *La energía reflejada llena todo el semicírculo en lugar de concentrarse en un 214 + lóbulo especular, de modo que el coeficiente de difusión por autocorrelación es 215 + alto ($d \approx 0.82$). Una superficie plana colapsaría la respuesta en un pico 216 + estrecho y llevaría $d$ hacia cero.* 217 + 218 + <details> 219 + <summary>Ver el código de esta figura</summary> 220 + 221 + ```python 222 + import matplotlib.pyplot as plt 223 + import numpy as np 224 + 225 + # result es el DiffusionResult calculado arriba. En una línea: 226 + result.plot() 227 + plt.show() 228 + 229 + # A mano: un diagrama polar de los niveles, con d anotado en el título. 230 + fig, ax = plt.subplots(subplot_kw={"projection": "polar"}) 231 + theta = np.radians(result.angles) 232 + ax.plot(theta, result.levels, "o-", color="#1f77b4") 233 + ax.fill(theta, result.levels, color="#1f77b4", alpha=0.15) 234 + ax.set_theta_zero_location("N") 235 + ax.set_theta_direction(-1) 236 + ax.set_thetamin(-90) 237 + ax.set_thetamax(90) 238 + ax.set_title(f"Difusión direccional d = {result.coefficient:.2f} (ISO 17497-2)") 239 + plt.show() 240 + ``` 241 + 242 + </details> 243 + 244 + ## 3. Absorción in situ de pavimentos — técnica de sustracción (ISO 13472-1) 245 + 246 + En campo no hay sala reverberante. ISO 13472-1 mide la absorción sonora de un 247 + pavimento (o de cualquier superficie plana extensa) *in situ* disparando un 248 + impulso desde un altavoz a la altura $d_s$ hacia la superficie y registrando la 249 + respuesta al impulso en un micrófono a la altura $d_m$. Las componentes 250 + **incidente** y **reflejada** se separan en el tiempo con una ventana de 251 + Adrienne; su función de transferencia da el factor de reflexión y de ahí la 252 + absorción. 253 + 254 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insitu_subtraction_es.svg" alt="Absorción in situ de pavimentos por la técnica de sustracción de ISO 13472-1: un altavoz a 1,25 m y un micrófono a 0,25 m sobre la superficie del pavimento, con los trayectos de rayo directo y reflejado por el pavimento y una medición de referencia en campo libre, con la componente reflejada aislada por una ventana temporal de Adrienne" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insitu_subtraction_es_dark.svg" alt="Absorción in situ de pavimentos por la técnica de sustracción de ISO 13472-1: un altavoz a 1,25 m y un micrófono a 0,25 m sobre la superficie del pavimento, con los trayectos de rayo directo y reflejado por el pavimento y una medición de referencia en campo libre, con la componente reflejada aislada por una ventana temporal de Adrienne" style="width:92%"> 255 + 256 + **Divergencia geométrica (cláusula 4.1).** La onda reflejada recorre más camino 257 + que la directa, así que se atenúa por el factor de divergencia geométrica 258 + 259 + $$ 260 + K_r = \frac{d_s - d_m}{d_s + d_m}, 261 + $$ 262 + 263 + que vale $2/3$ para la geometría obligatoria $d_s = 1.25$ m, $d_m = 0.25$ m. La 264 + absorción se obtiene de los espectros incidente y reflejado enventanados $H_i$, 265 + $H_r$: 266 + 267 + $$ 268 + \alpha(f) = 1 - \frac{1}{K_r^2}\left|\frac{H_r(f)}{H_i(f)}\right|^2. 269 + $$ 270 + 271 + ```python 272 + import numpy as np 273 + import phonometry as ph 274 + 275 + # Una respuesta al impulso incidente limitada en banda y una reflexión de 276 + # pavimento sintética hr = Kr * r0 * delayed(hi): una reflexión de magnitud 277 + # r0 = 0.4, retardada por el camino adicional y escalada por el factor de 278 + # divergencia geométrica Kr. 279 + fs, n = 48000.0, 4096 280 + t = np.arange(n) / fs 281 + hi = np.zeros(n) 282 + hi[:64] = np.hanning(64) * np.cos(2.0 * np.pi * 1500.0 * t[:64]) 283 + 284 + kr = ph.geometric_spreading_factor() # (ds - dm)/(ds + dm) = 2/3 285 + hr = kr * 0.4 * np.roll(hi, 96) 286 + 287 + # Absorción de banda estrecha, luego reducida a tercios de octava en 250-4000 Hz. 288 + alpha = ph.insitu_absorption_coefficient(hi, hr) # 1 - (1/Kr^2)|Hr/Hi|^2 289 + freq = np.fft.rfftfreq(n, 1.0 / fs) 290 + centres, band = ph.one_third_octave_absorption(freq, alpha) 291 + print(round(kr, 4)) # 0.6667 292 + print(round(float(band[2]), 3)) # 0.84 (alpha = 1 - 0.4^2 = 0.84) 293 + ``` 294 + 295 + **Ventana de Adrienne (cláusula 6.4).** La ventana temporal que aísla la 296 + reflexión solo exige un flanco de subida abrupto, una porción plana de 5 ms y un 297 + flanco de bajada de coseno cuadrado o Blackman-Harris —las duraciones exactas se 298 + informan en cada medición, no son fijas, así que aquí son configurables. 299 + 300 + ```python 301 + from phonometry import adrienne_window 302 + 303 + # Por defecto: flanco de subida de 0.5 ms, meseta de 5 ms, bajada Blackman-Harris de 5 ms. 304 + w = adrienne_window(48000.0) 305 + print(w.shape[0]) # 504 muestras a 48 kHz 306 + print(round(float(w.max()), 3)) # 1.0 (la meseta y los flancos se encuentran en la unidad) 307 + ``` 308 + 309 + **Espectro de principio a fin.** `insitu_absorption_spectrum` ejecuta toda la 310 + cadena —de las respuestas al impulso incidente y reflejada enventanadas a la 311 + absorción de banda estrecha y de ahí a las bandas de tercio de octava— y devuelve 312 + un `InsituAbsorptionResult` representable: 313 + 314 + ```python 315 + import numpy as np 316 + import phonometry as ph 317 + from scipy.signal import firwin, lfilter 318 + 319 + # Una medición sintética pero realista. hi es un impulso incidente unitario; la 320 + # reflexión del pavimento hr = Kr * r0 * roll(hi, shift) usa el factor de 321 + # divergencia geométrica Kr, un r0 levemente dependiente de la frecuencia (un 322 + # suave paso-bajo, de modo que una superficie porosa refleja menos al subir la 323 + # frecuencia) y el retardo del camino reflejado shift = round(2 dm / c * fs). 324 + fs, n = 48000.0, 8192 325 + kr = ph.geometric_spreading_factor() # (ds - dm)/(ds + dm) = 2/3 326 + hi = np.zeros(n) 327 + hi[0] = 1.0 328 + taps = firwin(41, 1200.0, fs=fs) 329 + taps = taps / taps.sum() 330 + shift = int(round(2.0 * 0.25 / 340.0 * fs)) # retardo del camino reflejado 2 dm / c 331 + hr = kr * 0.85 * np.roll(lfilter(taps, 1.0, hi), shift) 332 + 333 + result = ph.insitu_absorption_spectrum(hi, hr, fs) 334 + print(result.frequencies[[0, -1]].astype(int)) # [ 250 4000] 335 + print(np.round(result.absorption[[0, 6, 12]], 2)) # [0.31 0.65 1. ] 336 + result.plot() # diagrama de barras alpha(f) en 250-4000 Hz (requiere matplotlib) 337 + ``` 338 + 339 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insitu_absorption_es.png" alt="Un espectro de absorción de pavimento in situ en tercios de octava calculado por la vía del factor de reflexión a partir de una reflexión de pavimento sintética, creciendo desde cerca de 0,3 a 250 Hz hasta casi 1,0 por encima de 2 kHz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insitu_absorption_es_dark.png" alt="Un espectro de absorción de pavimento in situ en tercios de octava calculado por la vía del factor de reflexión a partir de una reflexión de pavimento sintética, creciendo desde cerca de 0,3 a 250 Hz hasta casi 1,0 por encima de 2 kHz" style="width:88%"> 340 + 341 + *La absorción crece con la frecuencia porque la superficie refleja menos energía 342 + de alta frecuencia, exactamente como dicta el factor de reflexión paso-bajo 343 + $r_0(f)$ a través de $\alpha = 1 - (1/K_r^2)\,|H_r/H_i|^2$.* 344 + 345 + <details> 346 + <summary>Ver el código de esta figura</summary> 347 + 348 + ```python 349 + import matplotlib.pyplot as plt 350 + import numpy as np 351 + 352 + # result es el InsituAbsorptionResult calculado arriba. En una línea: 353 + result.plot() 354 + plt.show() 355 + 356 + # A mano: un diagrama de barras de alpha sobre las bandas de tercio de octava. 357 + freqs = result.frequencies 358 + positions = np.arange(freqs.size) 359 + fig, ax = plt.subplots() 360 + ax.bar(positions, np.nan_to_num(result.absorption), width=0.7, color="#1f77b4") 361 + ax.set_xticks(positions) 362 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 363 + ax.set_xlabel("Frecuencia [Hz]") 364 + ax.set_ylabel("Coeficiente de absorción alpha") 365 + ax.set_ylim(0.0, 1.0) 366 + ax.set_title("Absorción in situ de pavimentos (ISO 13472-1)") 367 + plt.show() 368 + ``` 369 + 370 + </details> 371 + 372 + **Área máxima muestreada (Anexo A).** La ventana temporal finita limita cuánta 373 + superficie contribuye a la reflexión. El área máxima muestreada es un círculo 374 + cuyo radio la librería calcula a partir de la geometría y la anchura de la 375 + ventana; el ejemplo trabajado del Anexo A ($d_s = 1.25$ m, $d_m = 0.25$ m, 376 + $c = 340$ m/s, ventana plana de 5 ms) da unos 1,34 m. 377 + 378 + ```python 379 + import phonometry as ph 380 + print(round(ph.max_sampled_area_radius(5.0e-3), 3)) # 1.343 (metros) 381 + ``` 382 + 383 + ## 4. Absorción in situ de pavimentos — método puntual (ISO 13472-2) 384 + 385 + Para parches más pequeños, ISO 13472-2 sella un tubo circular corto sobre la 386 + superficie y mide la absorción con el método de la función de transferencia de 387 + dos micrófonos de ISO 10534-2. La librería aporta la geometría del método puntual 388 + y los ayudantes de validez; el propio DSP de la función de transferencia es la 389 + rutina de tubo de impedancia `two_microphone_impedance` (véase la 390 + [guía de Materiales acústicos](/phonometry/es/guides/materials/)). 391 + 392 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_spot_tube_es.svg" alt="Método puntual de ISO 13472-2: un tubo circular corto sellado sobre la superficie del pavimento con un altavoz en la parte superior y dos micrófonos enrasados en la pared del tubo con espaciado s, midiendo la absorción de 250 a 1600 Hz mediante el método de la función de transferencia de dos micrófonos de ISO 10534-2" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_spot_tube_es_dark.svg" alt="Método puntual de ISO 13472-2: un tubo circular corto sellado sobre la superficie del pavimento con un altavoz en la parte superior y dos micrófonos enrasados en la pared del tubo con espaciado s, midiendo la absorción de 250 a 1600 Hz mediante el método de la función de transferencia de dos micrófonos de ISO 10534-2" style="width:92%"> 393 + 394 + **Límites de onda plana (cláusula 5.4).** El tubo solo soporta ondas planas por 395 + debajo de 396 + 397 + $$ 398 + f_u = 0.58\,\frac{c_0}{d}, 399 + $$ 400 + 401 + con $d$ el diámetro del tubo, y el espaciado de micrófonos $s$ debe situarse entre 402 + $0.05\,c_0/f_{min}$ y $0.45\,c_0/f_{max}$. El rango informado son las bandas de 403 + tercio de octava de 250 a 1600 Hz. 404 + 405 + ```python 406 + import phonometry as ph 407 + 408 + # Frecuencia superior utilizable de un tubo de 100 mm y la ventana de espaciado válida. 409 + print(round(ph.spot_tube_upper_frequency(0.100, 343.0), 1)) # 1989.4 Hz 410 + s_min, s_max = ph.spot_microphone_spacing_bounds( 411 + 343.0, f_min=220.0, f_max=1800.0) 412 + print(round(s_min, 3), round(s_max, 3)) # 0.078 0.086 (metros) 413 + ``` 414 + 415 + --- 416 + 417 + **Normas implementadas en esta página:** ISO 17497-1:2004 (coeficiente de 418 + dispersión), ISO 17497-2:2012 (coeficiente de difusión), ISO 13472-1:2002 419 + (absorción in situ, superficie extensa), ISO 13472-2:2010 (absorción in situ, 420 + método puntual).
+648
site/src/content/docs/guides/building-acoustics.md
··· 1 + --- 2 + title: "Building Acoustics & Sound Insulation" 3 + description: "Field airborne, impact and façade insulation (ISO 16283-1/2/3) with weighted single-number ratings (ISO 717-1/2), laboratory element characterisation (ISO 10140), flanking-transmission prediction (EN 12354-1/2) and measurement uncertainty (ISO 12999-1)." 4 + --- 5 + 6 + This guide continues from the [Room Acoustics guide](/phonometry/guides/room-acoustics/): 7 + the same impulse response, measured either side of a partition, yields its sound 8 + insulation. Where room acoustics describes the sound field inside a single space, 9 + building acoustics describes how much of that field passes *between* spaces. This 10 + page follows the insulation chain — field airborne, impact and façade insulation 11 + with single-number ratings (ISO 16283-1/2/3, ISO 717-1/2), the laboratory 12 + characterisation of a building element (ISO 10140), the prediction of in-situ 13 + performance from flanking transmission (EN 12354-1/2), and the measurement 14 + uncertainty that qualifies every rating (ISO 12999-1). 15 + 16 + ## 1. Field insulation and single-number ratings (ISO 16283-1, ISO 717-1) 17 + 18 + To rate a wall or floor, measure the energy-average level in the **source** 19 + room ($L_1$) and the **receiving** room ($L_2$) per one-third-octave band 20 + and form the level difference $D = L_1 - L_2$. Two normalisations make it 21 + comparable between rooms. The **standardized level difference** references 22 + the receiving-room reverberation time $T$ to $T_0 = 0.5$ s (so with 23 + $T = 0.5$ s, $D_{nT} = D$ exactly), and the **apparent sound reduction 24 + index** normalises by the partition area $S$ and the Sabine absorption area 25 + $A$: 26 + 27 + $$ 28 + D_{nT} = D + 10 \log_{10} \frac{T}{T_0}, \qquad 29 + R' = D + 10 \log_{10} \frac{S}{A}, \qquad A = \frac{0.16\ V}{T}. 30 + $$ 31 + 32 + Positions are energy-averaged with 33 + $L = 10 \log_{10}\left( \frac{1}{n} \sum_i 10^{L_i/10} \right)$. 34 + 35 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup.svg" alt="Field airborne insulation setup: a loudspeaker in the source room, microphones energy-averaged in source and receiving rooms across the common partition" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_dark.svg" alt="Field airborne insulation setup: a loudspeaker in the source room, microphones energy-averaged in source and receiving rooms across the common partition" style="width:92%"> 36 + 37 + The band spectrum is collapsed to one number by the **reference-curve 38 + method** of ISO 717-1: a fixed reference curve is shifted in 1 dB steps 39 + toward the measured curve until the sum of *unfavourable* deviations 40 + (where the measurement falls below the reference) is as large as possible 41 + but not more than 32.0 dB (16 one-third-octave bands) or 10.0 dB (5 octave 42 + bands). The rating (`Rw`, `R'w`, `DnT,w` …) is the shifted reference read at 43 + 500 Hz. The **spectrum adaptation terms** $C$ (pink noise) and $C_{tr}$ 44 + (urban traffic) add the low-frequency penalty of a real source. 45 + 46 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating.png" alt="Measured one-third-octave sound reduction index with the shifted ISO 717-1 reference curve and the resulting weighted rating at 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_dark.png" alt="Measured one-third-octave sound reduction index with the shifted ISO 717-1 reference curve and the resulting weighted rating at 500 Hz" style="width:80%"> 47 + 48 + ```python 49 + import numpy as np 50 + from phonometry import airborne_insulation, weighted_rating, energy_average_level 51 + 52 + # Energy-average several microphone positions in one room (dB) 53 + print(round(float(energy_average_level([60.0, 66.0])), 1)) # 64.0 54 + 55 + # Field insulation per band; area S and volume V add R' 56 + l1 = np.full(16, 80.0) # source-room levels 57 + l2 = np.full(16, 40.0) # receiving-room levels 58 + t2 = np.full(16, 0.5) # receiving-room T (s) 59 + ins = airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 60 + print(round(float(ins.dnt[0]), 1)) # 40.0 (= D since T = T0) 61 + print(round(float(ins.r_prime[0]), 1)) # 38.0 62 + 63 + # Single-number rating from a measured 16-band R spectrum (ISO 717-1 Annex C) 64 + R = [20.4, 16.3, 17.7, 22.6, 22.4, 22.7, 24.8, 26.6, 65 + 28.0, 30.5, 31.8, 32.5, 33.4, 33.0, 31.0, 25.5] 66 + w = weighted_rating(R) 67 + print(w.rating, w.c, w.ctr) # 30 -2 -3 -> Rw(C;Ctr) = 30(-2;-3) 68 + 69 + w.plot() # measured R' vs shifted ISO 717-1 reference, deviations shaded (needs matplotlib) 70 + ``` 71 + 72 + <details> 73 + <summary>Show the code for this figure</summary> 74 + 75 + ```python 76 + import matplotlib.pyplot as plt 77 + 78 + # One line — measured curve vs the shifted ISO 717-1 reference, deviations shaded: 79 + w.plot() 80 + plt.show() 81 + 82 + # By hand, from the band curve the result now carries: 83 + fig, ax = plt.subplots() 84 + ax.semilogx(w.band_centers, w.measured, "o-", label="Measured R'") 85 + ax.semilogx(w.band_centers, w.shifted_reference, "s--", label="Shifted reference") 86 + ax.fill_between(w.band_centers, w.measured, w.shifted_reference, 87 + where=w.measured < w.shifted_reference, interpolate=True, 88 + alpha=0.3, label="Unfavourable deviations") 89 + ax.set_xlabel("Frequency [Hz]") 90 + ax.set_ylabel("Sound reduction index [dB]") 91 + ax.set_title(f"Rw = {w.rating} dB (C={w.c:+d}; Ctr={w.ctr:+d})") 92 + ax.legend() 93 + plt.show() 94 + ``` 95 + 96 + </details> 97 + 98 + Compute `l1`, `l2` and `t2` on the same 16 one-third-octave bands from 99 + 100 Hz to 3150 Hz — obtain `t2` from 100 + `room_parameters(ir, fs, limits=(100, 3150), fraction=3).t30`, for example — and 101 + pass them to `airborne_insulation`. Feed that function's `dnt` (or `r_prime`) 102 + spectrum to `weighted_rating`, so every band aligns index-by-index with the 103 + ISO 717-1 reference curve. 104 + 105 + ### `airborne_insulation()` parameters 106 + 107 + | Parameter | Type | Units | Range / default | Notes | 108 + | :--- | :--- | :--- | :--- | :--- | 109 + | `l1` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source-room levels (2D is energy-averaged) | 110 + | `l2` | 1D or 2D array | dB | same band count | Receiving-room levels | 111 + | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 112 + | `area` | float, optional | m² | > 0, with `volume` | Partition area `S` (enables `R'`) | 113 + | `volume` | float, optional | m³ | > 0, with `area` | Receiving-room volume `V` | 114 + | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 115 + 116 + ### `weighted_rating()` parameters 117 + 118 + | Parameter | Type | Units | Range / default | Notes | 119 + | :--- | :--- | :--- | :--- | :--- | 120 + | `values_by_band` | 1D array | dB | 16 (thirds) or 5 (octaves) | Measured `R`, `R'`, `DnT` … per band | 121 + | `bands` | str or `None` | — | `'third-octave'` / `'octave'` / `None` | `None` infers from the count | 122 + 123 + `airborne_insulation()` returns an `AirborneInsulationResult` (`d`, `dnt`, 124 + `r_prime` or `None`); `weighted_rating()` returns a `WeightedRatingResult` 125 + (`rating`, `c`, `ctr`, `unfavourable_sum`, all integers except the sum). 126 + 127 + ### Impact sound (ISO 16283-2, ISO 717-2) 128 + 129 + Footstep noise is rated the other way round. Instead of how much a floor 130 + *blocks*, impact insulation measures how much a standardized **tapping 131 + machine** on the floor above puts into the room below — so a *higher* number 132 + is *worse*. The energy-average impact sound pressure level $L_i$ in the 133 + receiving room is normalised like the airborne case, but with a sign flip on 134 + the reverberation term: 135 + 136 + $$ 137 + L'_{nT} = L_i - 10 \log_{10} \frac{T}{T_0}, \qquad 138 + L'_n = L_i + 10 \log_{10} \frac{A}{A_0}, \quad 139 + A_0 = 10\ \text{m}^2,\ A = \frac{0.16\ V}{T}. 140 + $$ 141 + 142 + The **standardized** impact level $L'_{nT}$ ($T_0 = 0.5$ s for dwellings) 143 + needs only the receiving-room $T$, so with $T = 0.5$ s it equals $L_i$; the 144 + **normalized** level $L'_n$ (referenced to a 10 m² absorption area) also needs 145 + the receiving-room volume. Note the **minus** sign — more reverberation 146 + *lowers* $L'_{nT}$, opposite to the airborne $D_{nT}$. 147 + 148 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup.svg" alt="Field impact insulation setup: a standardized tapping machine on the floor of the source room above, microphones energy-averaged in the receiving room below, and the receiving-room reverberation time" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_dark.svg" alt="Field impact insulation setup: a standardized tapping machine on the floor of the source room above, microphones energy-averaged in the receiving room below, and the receiving-room reverberation time" style="width:92%"> 149 + 150 + The single-number rating (ISO 717-2) shifts the same style of reference curve, 151 + but an **unfavourable deviation now occurs where the measurement *exceeds* the 152 + reference** (impact noise is worse when higher) — the sign opposite to 153 + ISO 717-1. The rating (`Ln,w`, `L'n,w`, `L'nT,w`) is the shifted reference read 154 + at 500 Hz; for octave bands it is then reduced by 5 dB. The spectrum 155 + adaptation term $C_I = L_{n,\text{sum}} - 15 - L_{n,w}$ uses the energetic sum 156 + over 100–2500 Hz (16-band thirds excluding 3150 Hz) or 125–2000 Hz (octaves). 157 + 158 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating.png" alt="Measured one-third-octave normalized impact sound pressure level with the shifted ISO 717-2 reference curve and the resulting weighted rating read at 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_dark.png" alt="Measured one-third-octave normalized impact sound pressure level with the shifted ISO 717-2 reference curve and the resulting weighted rating read at 500 Hz" style="width:80%"> 159 + 160 + ```python 161 + import numpy as np 162 + from phonometry import impact_insulation, weighted_impact_rating 163 + 164 + # 16 one-third-octave impact levels Li (100 Hz - 3150 Hz), dB, from the 165 + # ISO 717-2 Annex C worked example, and the receiving-room T per band. 166 + li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 167 + 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 168 + t2 = np.full(16, 0.5) 169 + 170 + imp = impact_insulation(li, t2, volume=50.0) 171 + print(round(float(imp.l_n_t[0]), 1)) # 62.1 (= Li since T = T0) 172 + print(round(float(imp.l_n[0]), 1)) # 64.1 normalized to A0 = 10 m^2 173 + 174 + # Weighted impact rating + spectrum adaptation term CI (ISO 717-2) 175 + res_imp = weighted_impact_rating(imp.l_n_t) 176 + print(res_imp.rating, res_imp.ci, res_imp.unfavourable_sum) # 79 -11 28.0 -> L'nT,w(CI)=79(-11) 177 + 178 + # Octave-band data carry the extra -5 dB reduction (Clause 4.3.2) 179 + octave = np.array([65.3, 64.5, 58.0, 55.8, 43.0]) 180 + print(weighted_impact_rating(octave).rating) # 54 181 + 182 + res_imp.plot() # measured L'nT vs shifted ISO 717-2 reference, measured-above shaded (needs matplotlib) 183 + ``` 184 + 185 + <details> 186 + <summary>Show the code for this figure</summary> 187 + 188 + ```python 189 + import matplotlib.pyplot as plt 190 + 191 + # One line — measured L'nT vs the shifted ISO 717-2 reference (measured-above shaded): 192 + res_imp.plot() 193 + plt.show() 194 + 195 + # By hand, from the band curve the result now carries (note the opposite sign: 196 + # an unfavourable deviation is where the MEASURED level exceeds the reference). 197 + # Here the input was l_n_t, so the rated quantity is the field level L'nT,w: 198 + fig, ax = plt.subplots() 199 + ax.semilogx(res_imp.band_centers, res_imp.measured, "o-", label="Measured L'nT") 200 + ax.semilogx(res_imp.band_centers, res_imp.shifted_reference, "s--", label="Shifted reference") 201 + ax.fill_between(res_imp.band_centers, res_imp.shifted_reference, res_imp.measured, 202 + where=res_imp.measured > res_imp.shifted_reference, interpolate=True, 203 + alpha=0.3, label="Unfavourable deviations") 204 + ax.set_xlabel("Frequency [Hz]") 205 + ax.set_ylabel("Impact sound pressure level [dB]") 206 + ax.set_title(f"L'nT,w = {res_imp.rating} dB (CI={res_imp.ci:+d})") 207 + ax.legend() 208 + plt.show() 209 + ``` 210 + 211 + </details> 212 + 213 + Feed `impact_insulation`'s `l_n_t` (or `l_n`) straight into 214 + `weighted_impact_rating`; the rating and `CI` reproduce the ISO 717-2 Annex C 215 + values (thirds `L'nT,w = 79`, `CI = −11`; octave `54`, `CI = 0`). 216 + 217 + #### `impact_insulation()` parameters 218 + 219 + | Parameter | Type | Units | Range / default | Notes | 220 + | :--- | :--- | :--- | :--- | :--- | 221 + | `li` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Energy-average impact SPL (2D is averaged over positions) | 222 + | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 223 + | `volume` | float, optional | m³ | > 0 | Receiving-room `V` (enables `L'n`) | 224 + | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 225 + 226 + #### `weighted_impact_rating()` parameters 227 + 228 + | Parameter | Type | Units | Range / default | Notes | 229 + | :--- | :--- | :--- | :--- | :--- | 230 + | `values_by_band` | 1D array | dB | 16 (thirds) or 5 (octaves) | Measured `Ln`, `L'n` or `L'nT` per band | 231 + | `bands` | str or `None` | — | `'third-octave'` / `'octave'` / `None` | `None` infers from the count | 232 + 233 + `impact_insulation()` returns an `ImpactInsulationResult` (`l_n_t`, `l_n` or 234 + `None`); `weighted_impact_rating()` returns an `ImpactRatingResult` (`rating`, 235 + `ci` integers, `unfavourable_sum` in dB). 236 + 237 + ### Field façade insulation (ISO 16283-3) 238 + 239 + The same source/receiver logic reaches the building **façade**, but now the 240 + source is *outdoors* — a loudspeaker at 45° or the road traffic itself. Rather 241 + than a level difference across an internal partition, ISO 16283-3 references the 242 + receiving-room level $L_2$ to the level **2 m in front of the façade** 243 + $L_{1,2m}$, giving the level difference $D_{2m}$ and, exactly as in the airborne 244 + case, its standardized and normalized forms: 245 + 246 + $$ 247 + D_{2m} = L_{1,2m} - L_2, \quad 248 + D_{2m,nT} = D_{2m} + 10 \log_{10}\frac{T}{T_0}, \quad 249 + D_{2m,n} = D_{2m} - 10 \log_{10}\frac{A}{A_0}, 250 + $$ 251 + 252 + with $T_0 = 0.5$ s, $A_0 = 10$ m² and $A = 0.16\ V/T$ (dwellings). When the 253 + microphone sits **on the test element** (surface level $L_{1,s}$) the *element* 254 + method also yields an apparent sound reduction index, carrying a fixed 255 + angle-of-incidence correction — $-1.5$ dB for the 45° loudspeaker method, 256 + $-3$ dB for the all-angle road-traffic method: 257 + 258 + $$ 259 + R'_{45°} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 1.5, \qquad 260 + R'_{tr,s} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 3. 261 + $$ 262 + 263 + The façade quantity is airborne, so its single-number rating uses the 264 + **ISO 717-1** reference curve through `weighted_rating` unchanged (Annex F). 265 + 266 + ```python 267 + import numpy as np 268 + from phonometry import facade_insulation, weighted_rating 269 + 270 + # Outdoor level 2 m in front of the façade, receiving-room level and T per 271 + # one-third-octave band; surface_level is the microphone on the test element. 272 + l1_2m = np.full(16, 75.0) # L1,2m outdoors 273 + l2 = np.full(16, 33.0) # receiving-room L2 274 + t2 = np.full(16, 0.5) # receiving-room T (s) 275 + 276 + fac = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 277 + surface_level=np.full(16, 78.0), method="loudspeaker") 278 + print(round(float(fac.d_2m[0]), 1)) # 42.0 D2m = L1,2m - L2 279 + print(round(float(fac.d_2m_nt[0]), 1)) # 42.0 (= D2m since T = T0) 280 + print(round(float(fac.d_2m_n[0]), 1)) # 40.0 normalized to A0 = 10 m^2 281 + print(round(float(fac.r_prime[0]), 1)) # 42.1 R'45deg (loudspeaker, -1.5 dB) 282 + 283 + # The road-traffic element method carries the -3 dB all-angle correction instead 284 + tr = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 285 + surface_level=np.full(16, 78.0), method="road_traffic") 286 + print(round(float(tr.r_prime[0]), 1)) # 40.6 R'tr,s (traffic, -3 dB) 287 + 288 + # The façade quantity is airborne: rate D2m,nT with the ISO 717-1 engine 289 + print(weighted_rating(fac.d_2m_nt).rating) # 42 Dls,2m,nT,w 290 + 291 + fac.plot() # per-band D2m,nT with D2m, D2m,n and R' overlaid (needs matplotlib) 292 + ``` 293 + 294 + `surface_level`, `area` and `volume` are all optional: with only `l1_2m`, `l2` 295 + and `t2` the function returns `d_2m` and `d_2m_nt`; add `volume` for `d_2m_n`; 296 + add `surface_level` **and** `area` **and** `volume` for `r_prime`. Positions are 297 + energy-averaged with the surface-level formula (Clause 9.5.1); band levels are 298 + assumed already corrected for background noise. 299 + 300 + #### `facade_insulation()` parameters 301 + 302 + | Parameter | Type | Units | Range / default | Notes | 303 + | :--- | :--- | :--- | :--- | :--- | 304 + | `l1_2m` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Level 2 m in front of the façade `L1,2m` | 305 + | `l2` | 1D or 2D array | dB | same band count | Receiving-room levels | 306 + | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 307 + | `area` | float, optional | m² | > 0, with `surface_level`, `volume` | Test-element area `S` (enables `R'`) | 308 + | `volume` | float, optional | m³ | > 0 | Receiving-room `V` (enables `D2m,n`; required for `R'`) | 309 + | `surface_level` | 1D/2D array, optional | dB | same band count | Surface level `L1,s` on the element (enables `R'`) | 310 + | `method` | str | — | `'loudspeaker'` (−1.5 dB) / `'road_traffic'` (−3 dB) | Angle-of-incidence correction of `R'` | 311 + | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 312 + | `frequencies` | 1D array, optional | Hz | — | Band centres carried on the result for plotting | 313 + 314 + `facade_insulation()` returns a `FacadeInsulationResult` (`d_2m`, `d_2m_nt`, 315 + `d_2m_n` or `None`, `r_prime` or `None`, `frequencies`); feed any 16-band façade 316 + quantity to `weighted_rating` for its ISO 717-1 single number. 317 + 318 + ## 2. Laboratory measurement (ISO 10140) 319 + 320 + Everything above is a **field** measurement (the primed quantities $R'$, $L'_n$): 321 + the number a real building achieves, flanking transmission and all. To rate an 322 + element on its own — a wall type, a floating floor, a window — you take it to a 323 + qualified **laboratory** (ISO 10140), where suppressed flanking makes the 324 + *direct* transmission the whole story. The formulas lose their primes: the 325 + **sound reduction index** $R$ (not $R'$) and the **normalized impact level** 326 + $L_n$ (not $L'_n$), with the receiving room's absorption area $A = 0.16\ V/T$ 327 + now a known property of the facility: 328 + 329 + $$ 330 + R = L_1 - L_2 + 10 \log_{10}\frac{S}{A}, \qquad 331 + L_n = L_i + 10 \log_{10}\frac{A}{A_0}, \quad A_0 = 10\ \text{m}^2. 332 + $$ 333 + 334 + | | Field (ISO 16283) | Laboratory (ISO 10140) | 335 + | :--- | :--- | :--- | 336 + | Airborne | $R'$ apparent (with flanking) | $R$ direct (flanking suppressed) | 337 + | Impact | $L'_n$ apparent | $L_n$ direct | 338 + | Absorption area | measured in the room | property of the facility | 339 + 340 + The single-number ratings reuse the very same ISO 717-1/2 engines 341 + (`weighted_rating`, `weighted_impact_rating`) — an $R$ spectrum rates to $R_w$ 342 + exactly as an $R'$ spectrum rated to $R'_w$. Before forming the index the 343 + receiving-room levels must be **corrected for background noise** (Clause 4.3): 344 + the energy subtraction $10 \log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ applies for a 345 + 6–15 dB signal-to-background margin, a fixed 1.3 dB correction (the *limit of 346 + measurement*) at or below 6 dB, and no correction at or above 15 dB. 347 + 348 + ```python 349 + import numpy as np 350 + from phonometry import (lab_airborne_insulation, lab_impact_insulation, 351 + background_correction) 352 + 353 + # Source/receiving levels and receiving-room T over the 16 one-third-octave 354 + # bands; S is the free test-opening area, V the receiving-room volume. 355 + l1 = np.full(16, 80.0) 356 + l2 = np.full(16, 40.0) 357 + t2 = np.full(16, 0.5) 358 + lab = lab_airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 359 + print(round(float(lab.r[0]), 1)) # 38.0 R = L1 - L2 + 10 lg(S/A) 360 + print(round(float(lab.absorption[0]), 1)) # 16.0 A = 0.16 V / T (m^2) 361 + print(lab.rating.rating, lab.rating.c, lab.rating.ctr) # 38 0 0 -> Rw(C;Ctr) 362 + 363 + # Impact: the tapping-machine level Li normalized to A0 = 10 m^2 gives Ln 364 + li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 365 + 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 366 + imp = lab_impact_insulation(li, t2, volume=50.0) 367 + print(round(float(imp.l_n[0]), 1)) # 64.1 Ln = Li + 10 lg(A/A0) 368 + print(imp.rating.rating, imp.rating.ci) # 81 -11 -> Ln,w(CI) 369 + 370 + # Background correction: margins 6 / 1 / 20 dB -> capped / capped / unchanged 371 + corrected = background_correction([30.0, 33.0, 50.0], [24.0, 32.0, 30.0]) 372 + print(np.round(corrected, 1)) # [28.7 31.7 50.0] (1.3 dB cap twice) 373 + 374 + lab.rating.plot() # measured R vs shifted ISO 717-1 reference (needs matplotlib) 375 + ``` 376 + 377 + A margin at or below 6 dB emits a `LabInsulationWarning` and flags the band as 378 + the limit of measurement; catch it with `warnings.simplefilter("error", 379 + LabInsulationWarning)`. The automatic rating is formed only when exactly 16 380 + one-third-octave or 5 octave values are supplied (`rating` is `None` otherwise). 381 + 382 + ### `lab_airborne_insulation()` / `lab_impact_insulation()` parameters 383 + 384 + | Parameter | Type | Units | Range / default | Notes | 385 + | :--- | :--- | :--- | :--- | :--- | 386 + | `l1` / `l2` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source / receiving levels (airborne) | 387 + | `li` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Impact SPL from the tapping machine (impact) | 388 + | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 389 + | `area` | float | m² | > 0 | Free test-opening area `S` (airborne only) | 390 + | `volume` | float | m³ | > 0 | Receiving-room volume `V` | 391 + 392 + `lab_airborne_insulation()` returns a `LabAirborneInsulationResult` (`r`, 393 + `absorption`, `rating`); `lab_impact_insulation()` a 394 + `LabImpactInsulationResult` (`l_n`, `absorption`, `rating`); 395 + `background_correction(signal_and_background, background)` returns the corrected 396 + levels directly. 397 + 398 + ## 3. Predicting performance (EN 12354) 399 + 400 + A laboratory rating describes an element in isolation, yet the sound a building 401 + actually transmits also travels *around* the partition — along the floor, up the 402 + façade, through the flanking walls — re-radiating into the receiving room. This 403 + **flanking transmission** is the whole difference between the laboratory $R$ and 404 + the field $R'$. EN 12354 predicts the in-situ apparent rating from the 405 + laboratory ratings of the elements plus the vibration transmission of their 406 + junctions. 407 + 408 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths.svg" alt="The direct path Dd through the separating element and the three flanking paths Ff, Df and Fd across each junction between a flanking element and the separating element" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_dark.svg" alt="The direct path Dd through the separating element and the three flanking paths Ff, Df and Fd across each junction between a flanking element and the separating element" style="width:92%"> 409 + 410 + Each junction between a flanking element and the separating element carries 411 + three paths — $Ff$ (flanking→flanking), $Df$ (direct→flanking) and $Fd$ 412 + (flanking→direct) — alongside the single direct path $Dd$. The **simplified 413 + single-number model** combines them energetically (Formula 26): 414 + 415 + $$ 416 + R'_w = -10 \log_{10}\Big[ 10^{-R_{Dd,w}/10} 417 + + \sum 10^{-R_{Ff,w}/10} + \sum 10^{-R_{Df,w}/10} 418 + + \sum 10^{-R_{Fd,w}/10} \Big], 419 + $$ 420 + 421 + with the direct path $R_{Dd,w} = R_{s,w} + \Delta R_{Dd,w}$ (Formula 27) and each 422 + flanking path (Formula 28a) 423 + 424 + $$ 425 + R_{ij,w} = \tfrac{R_{i,w} + R_{j,w}}{2} + \Delta R_{ij,w} + K_{ij} 426 + + 10 \log_{10}\frac{S_s}{l_0\ l_f}, 427 + $$ 428 + 429 + where $l_0 = 1$ m is the reference coupling length, $l_f$ the junction coupling 430 + length and $K_{ij}$ the junction's **vibration reduction index** (Annex E, 431 + empirical in the mass ratio $M = \log_{10}(m'_{\perp,i}/m'_i)$). 432 + 433 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo.png" alt="Per-path sound reduction indices for the EN 12354-1 Annex H.3 example and each path's share of the transmitted energy, showing the direct path dominating at R'w = 52 dB" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_dark.png" alt="Per-path sound reduction indices for the EN 12354-1 Annex H.3 example and each path's share of the transmitted energy, showing the direct path dominating at R'w = 52 dB" style="width:80%"> 434 + 435 + ```python 436 + import numpy as np 437 + from phonometry import (junction_vibration_reduction, flanking_element, 438 + predicted_airborne_insulation) 439 + 440 + # EN 12354-1 Annex H.3: a separating wall Rs,w = 57 dB, area Ss = 11.5 m², with 441 + # four flanking elements. The simplified model reads each junction's Kij at 442 + # 500 Hz from the mass ratio m'perp / m' (Annex E) — here the floor's rigid 443 + # cross-junction (the mass ratio is itself rounded, hence 12.5 vs Annex 12.4): 444 + print(round(junction_vibration_reduction("rigid_cross", "through", 1.61), 1)) # 12.5 KFf 445 + print(round(junction_vibration_reduction("rigid_cross", "corner", 1.61), 1)) # 8.9 KFd = KDf 446 + 447 + # Build each element's three flanking paths (Ff, Df, Fd) from the Annex H 448 + # tabulated Kij, then combine the direct path Dd energetically (Formula 26). 449 + elements = [ # (name, Rw, KFf, KFd = KDf, coupling length lf) 450 + ("floor", 49, 12.4, 8.9, 4.50), 451 + ("ceiling", 46, 14.4, 9.2, 4.50), 452 + ("facade", 42, 12.6, 6.7, 2.55), 453 + ("int-wall", 33, 33.5, 15.7, 2.55), 454 + ] 455 + paths = [] 456 + for name, rw, k_ff, k_fd, lf in elements: 457 + paths += flanking_element(label=name, r_flanking=rw, r_separating=57, 458 + k_ff=k_ff, k_fd=k_fd, k_df=k_fd, 459 + separating_area=11.5, coupling_length=lf) 460 + 461 + res = predicted_airborne_insulation(r_direct=57.0, flanking_paths=paths) 462 + print(round(res.r_prime_w, 1)) # 52.2 -> R'w = 52 dB 463 + print(res.dominant.label, round(res.dominant.fraction, 2)) # Dd 0.33 (direct dominates) 464 + ``` 465 + 466 + Every added flanking path strictly lowers $R'_w$ below the direct $R_{Dd,w} = 57$; 467 + `res.paths` exposes each path's share of the transmitted energy so the dominant 468 + path is visible. Clause 4.4.2 also enforces a floor $K_{ij} \ge K_{ij,\min}$ from 469 + the junction geometry — compute it with `junction_min_vibration_reduction` and 470 + pass it to `flanking_path(..., kij_min=...)`, which raises a below-floor $K_{ij}$ 471 + to the minimum: 472 + 473 + ```python 474 + from phonometry import junction_min_vibration_reduction 475 + # Kij,min = 10 lg[lf·l0·(1/Si + 1/Sj)]; large elements give a low (here negative) 476 + # floor, so a realistic tabulated Kij is rarely clamped. 477 + print(round(junction_min_vibration_reduction(coupling_length=4.5, 478 + s_i=11.5, s_j=11.5), 1)) # -1.1 479 + ``` 480 + 481 + The impact counterpart (EN 12354-2, Formula 21) is a direct subtraction: 482 + $L'_{n,w} = L_{n,w,eq} - \Delta L_w + K$, with the bare-floor equivalent level 483 + $L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Annex B), the covering improvement 484 + $\Delta L_w$ (ISO 717-2) and the flanking correction $K$ from Table 1. 485 + 486 + ```python 487 + from phonometry import (equivalent_impact_level, impact_flanking_correction, 488 + predicted_impact_insulation, standardized_impact_level) 489 + 490 + # EN 12354-2 Annex E.3: a 0.14 m concrete floor (m' = 322 kg/m²) with a floating 491 + # floor (ΔLw = 33 dB), rooms one above the other, mean flanking mass 145 kg/m². 492 + ln_eq = equivalent_impact_level(322.0) # 164 - 35 lg(m') 493 + k = impact_flanking_correction(322.0, 145.0) # Table 1 (sep 322, flk 145) 494 + imp = predicted_impact_insulation(ln_w_eq=ln_eq, delta_l_w=33.0, k_correction=k) 495 + print(round(ln_eq, 1), k, round(imp.l_prime_n_w, 1)) # 76.2 2 45.2 -> L'n,w = 45 dB 496 + print(round(standardized_impact_level(imp.l_prime_n_w, 50.0), 1)) # 43.0 L'nT,w 497 + ``` 498 + 499 + <details> 500 + <summary>Show the code for this figure</summary> 501 + 502 + ```python 503 + import matplotlib.pyplot as plt 504 + 505 + # Per-path sound reduction index and each path's share of the transmitted 506 + # energy for the Annex H.3 result computed above. 507 + labels = [p.label for p in res.paths] 508 + r_w = [p.r_w for p in res.paths] 509 + frac = [100.0 * p.fraction for p in res.paths] 510 + 511 + fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True) 512 + ax1.bar(labels, r_w, color="tab:blue") 513 + ax1.axhline(res.r_prime_w, ls="--", color="k", label=f"R'w = {res.r_prime_w:.1f} dB") 514 + ax1.set_ylabel("Path Rij,w [dB]"); ax1.legend() 515 + ax2.bar(labels, frac, color="tab:orange") 516 + ax2.set_ylabel("Energy share [%]"); ax2.set_xlabel("Transmission path") 517 + for ax in (ax1, ax2): 518 + ax.tick_params(axis="x", rotation=45) 519 + fig.suptitle("EN 12354-1 Annex H.3 — flanking transmission") 520 + fig.tight_layout() 521 + plt.show() 522 + ``` 523 + 524 + </details> 525 + 526 + ### `junction_vibration_reduction()` / `flanking_element()` parameters 527 + 528 + | Parameter | Type | Units | Range / default | Notes | 529 + | :--- | :--- | :--- | :--- | :--- | 530 + | `junction_type` | str | — | `'rigid_cross'` / `'rigid_t'` / `'flexible_t'` / `'lightweight_facade'` | Junction geometry (Annex E) | 531 + | `path` | str | — | `'through'` (K13) / `'corner'` (K12 = K23) | Path branch | 532 + | `mass_ratio` | float | — | > 0 | `m'⊥,i / m'i` (Formula E.2) | 533 + | `frequency` | float | Hz | default `500` | Only `flexible_t` is frequency-dependent | 534 + | `r_flanking` / `r_separating` | float | dB | — | Weighted indices of the flanking / separating element | 535 + | `k_ff` / `k_fd` / `k_df` | float | dB | — | Junction `Kij` for the three paths | 536 + | `separating_area` | float | m² | > 0 | Separating-element area `Ss` | 537 + | `coupling_length` | float | m | > 0 | Junction coupling length `lf` | 538 + | `delta_r_ff` / `delta_r_fd` / `delta_r_df` | float | dB | default `0` | Lining improvements per path | 539 + 540 + `predicted_airborne_insulation()` returns an `AirbornePredictionResult` 541 + (`r_prime_w`, `r_direct_w`, `paths` of `PathContribution`, `dominant`); 542 + `predicted_impact_insulation()` an `ImpactPredictionResult` (`l_prime_n_w`, 543 + `ln_w_eq`, `delta_l_w`, `k_correction`). The simplified model carries a reported 544 + standard deviation of about 2 dB (Clause 5). 545 + 546 + ## 4. Measurement uncertainty (ISO 12999-1) 547 + 548 + A rating without an uncertainty is only half a result. ISO 12999-1 does not 549 + re-measure anything; it tabulates the **standard uncertainty** $u$ of every 550 + sound-insulation quantity — derived from inter-laboratory tests — and prescribes 551 + how to expand and combine it. Which standard deviation is $u$ depends on the 552 + **measurement situation** (Clause 5.2): 553 + 554 + | Situation | Meaning | Standard uncertainty $u$ | 555 + | :--- | :--- | :--- | 556 + | **A** | laboratory characterisation (ISO 10140) | reproducibility $\sigma_R$ | 557 + | **B** | same location, different teams | in-situ $\sigma_{situ}$ | 558 + | **C** | same location, same operator repeated | repeatability $\sigma_r$ | 559 + 560 + The expanded uncertainty is $U = k\ u$ (Formula 2) with the coverage factor $k$ 561 + of Table 8. A two-sided interval $Y = y \pm U$ (Formula 3, $k = 1.96$ at 95 %) 562 + *reports* a value; the **one-sided** factor ($k = 1.65$ at 95 %) *declares 563 + conformity* with a requirement (Formulae 4/5). 564 + 565 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo.png" alt="A weighted rating reported with its two-sided 95 % expanded uncertainty in situations A, B and C, the reproducibility uncertainty widest and the repeatability uncertainty narrowest" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_dark.png" alt="A weighted rating reported with its two-sided 95 % expanded uncertainty in situations A, B and C, the reproducibility uncertainty widest and the repeatability uncertainty narrowest" style="width:80%"> 566 + 567 + ```python 568 + from phonometry import (band_uncertainty, single_number_uncertainty, 569 + uncertain_value, satisfies_lower_requirement) 570 + 571 + # Situation B (same building, different teams) -> the in-situ standard deviation. 572 + print(single_number_uncertainty("r_w", "B")) # 0.9 dB (Table 3) 573 + u = band_uncertainty("airborne", "B") # per-band u (Table 2) 574 + print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (the 500 Hz band) 575 + 576 + # Report R'w = 52 dB with a two-sided 95 % interval (k = 1.96, Table 8): 577 + uv = uncertain_value(52.0, "rprime_w", "B") # aliases resolve to r_w 578 + print(uv.coverage_factor, round(uv.expanded_uncertainty, 1)) # 1.96 1.8 579 + print(round(uv.lower, 1), round(uv.upper, 1)) # 50.2 53.8 -> 52 ± 1.8 dB 580 + 581 + # Declaring conformity uses the ONE-sided factor (k = 1.65): does R'w provably 582 + # clear a 50 dB requirement? 583 + uc = uncertain_value(52.0, "rprime_w", "B", one_sided=True) 584 + print(satisfies_lower_requirement(52.0, uc.expanded_uncertainty, 50.0)) # True 585 + ``` 586 + 587 + Impact quantities offer situations B/C only (Table 4, no 500 Hz band in the 2020 588 + edition), and $\Delta L$ only situation A. Descriptors are case-insensitive with 589 + aliases (`rprime_w`/`dnt_w`→`r_w`, `lprime_n_w`→`ln_w`); combine independent 590 + components in quadrature with `combine_uncertainties`, and reduce by $m$ 591 + independent measurements with `reduce_by_independent_measurements` ($u/\sqrt{m}$). 592 + 593 + <details> 594 + <summary>Show the code for this figure</summary> 595 + 596 + ```python 597 + import matplotlib.pyplot as plt 598 + from phonometry import uncertain_value 599 + 600 + # The same R'w = 52 dB reported in each situation with its two-sided 95 % U. 601 + situations = ["A", "B", "C"] 602 + vals = [uncertain_value(52.0, "r_w", s) for s in situations] 603 + 604 + fig, ax = plt.subplots(figsize=(7, 4)) 605 + ax.errorbar(situations, [v.value for v in vals], 606 + yerr=[v.expanded_uncertainty for v in vals], 607 + fmt="o", capsize=8, color="tab:blue") 608 + for s, v in zip(situations, vals): 609 + ax.annotate(f"±{v.expanded_uncertainty:.1f}", (s, v.upper), 610 + textcoords="offset points", xytext=(8, 4)) 611 + ax.set_ylabel("R'w [dB]"); ax.set_xlabel("Measurement situation") 612 + ax.set_title("R'w = 52 dB with 95 % expanded uncertainty (ISO 12999-1)") 613 + fig.tight_layout() 614 + plt.show() 615 + ``` 616 + 617 + </details> 618 + 619 + ### `band_uncertainty()` / `single_number_uncertainty()` / `uncertain_value()` parameters 620 + 621 + | Parameter | Type | Units | Range / default | Notes | 622 + | :--- | :--- | :--- | :--- | :--- | 623 + | `measurand` | str | — | `'airborne'` / `'impact'` / `'impact_reduction'` | Selects Table 2 / 4 / 6 | 624 + | `quantity` | str | — | `'r_w'`, `'ln_w'`, `'delta_lw'` (+ aliases, `+c`/`+ctr` variants) | Single-number descriptor | 625 + | `situation` | str | — | `'A'` / `'B'` / `'C'` | Measurement situation (Clause 5.2) | 626 + | `value` | float | dB | — | Best estimate `y` to attach `U` to | 627 + | `coverage` | float | — | default `0.95` | Confidence level (Table 8) | 628 + | `one_sided` | bool | — | default `False` | One-sided factor for conformity checks | 629 + | `upper_limit` | bool | — | default `False` | Select the σR95 upper limit (airborne, situation A) | 630 + 631 + `band_uncertainty()` returns a `BandUncertainty` (`frequencies`, 632 + `uncertainties`, `.to_arrays()`); `single_number_uncertainty()` a float; 633 + `uncertain_value()` an `UncertainValue` (`value`, `standard_uncertainty`, 634 + `coverage_factor`, `expanded_uncertainty`, `.lower`, `.upper`). The read-only 635 + `COVERAGE_FACTORS` mapping exposes Table 8 keyed by `(confidence, one_sided)`. 636 + 637 + ## See also 638 + 639 + - [Room Acoustics](/phonometry/guides/room-acoustics/) — the impulse response, 640 + room parameters and sound absorption that this guide's insulation chain builds on. 641 + - [Levels](/phonometry/guides/levels/) — energy averaging and the level metrics behind 642 + source/receiving-room levels. 643 + - [Filter Banks](/phonometry/guides/filter-banks/) — the IEC 61260 fractional-octave filters 644 + used for the insulation spectra. 645 + - [Sound Power](/phonometry/guides/sound-power/) — the `LW` methods that share the 646 + absorption-area machinery of the receiving room. 647 + - [Theory](/phonometry/reference/theory/) — the reference-curve derivation behind the 648 + weighted single-number ratings.
+273
site/src/content/docs/guides/human-vibration.md
··· 1 + --- 2 + title: "Human Vibration" 3 + description: "Whole-body and hand-arm vibration exposure: the ISO 8041-1 frequency weightings, the ISO 2631-1 weighted r.m.s. and dose measures (VDV, MTVV, MSDV, crest factor), the vibration total value and the 8-hour daily exposure A(8), with the ISO 5349 exposure guidance and the action and limit values of Directive 2002/44/EC." 4 + --- 5 + 6 + Vibration transmitted to a person is evaluated with the same measurement chain 7 + whatever its origin: the acceleration is **frequency-weighted** to reflect how 8 + the body responds at each frequency, reduced to a **weighted r.m.s.** 9 + acceleration (with dose measures for shocks and long records), combined across 10 + axes into a **vibration total value**, and finally normalised to an **8-hour 11 + daily exposure** `A(8)` that is compared against the action and limit values of 12 + the European directive. 13 + 14 + The weightings themselves are defined once, in **ISO 8041-1:2017**, as a cascade 15 + of analog filters; **ISO 2631-1** applies them to whole-body vibration, 16 + **ISO 2631-2** to vibration in buildings, **ISO 2631-4** to rail ride comfort, 17 + and **ISO 5349-1/-2** to hand-transmitted vibration. This page covers the whole 18 + chain. 19 + 20 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_human_vibration.svg" alt="Whole-body vibration measurement chain: a triaxial accelerometer at the seat/body interface of a seated person measures the x, y and z acceleration; each axis is band-limited and frequency-weighted (Wk vertical, Wd horizontal) per ISO 8041-1, reduced to a weighted r.m.s. a_w and VDV per ISO 2631-1, combined into the vibration total value a_v, normalised to the daily exposure A(8) and assessed against the EAV and ELV of Directive 2002/44/EC" style="width:94%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_human_vibration_dark.svg" alt="Whole-body vibration measurement chain: a triaxial accelerometer at the seat/body interface of a seated person measures the x, y and z acceleration; each axis is band-limited and frequency-weighted (Wk vertical, Wd horizontal) per ISO 8041-1, reduced to a weighted r.m.s. a_w and VDV per ISO 2631-1, combined into the vibration total value a_v, normalised to the daily exposure A(8) and assessed against the EAV and ELV of Directive 2002/44/EC" style="width:94%"> 21 + 22 + ## 1. Frequency weightings (ISO 8041-1) 23 + 24 + Every human-vibration weighting is the product of four analog stages evaluated 25 + at $s = j\,2\pi f$ (ISO 8041-1 Formulae (1)–(5)): a second-order Butterworth 26 + **high-pass** and **low-pass** band limiting, an **acceleration–velocity 27 + transition** carrying the overall gain $K$, and an **upward step**: 28 + 29 + $$ 30 + H(s) = H_h(s)\,H_l(s)\,H_t(s)\,H_s(s). 31 + $$ 32 + 33 + A single Table 3 parameter set $(f_1, Q_1, f_2, Q_2, f_3, f_4, Q_4, f_5, Q_5, 34 + f_6, Q_6, K)$ realises all nine weightings — `Wb, Wc, Wd, We, Wf, Wh, Wj, Wk, 35 + Wm` — a corner set to infinity collapsing its stage to unity. The principal 36 + whole-body weighting is `Wk` (vertical, seat surface); `Wd` is the horizontal 37 + weighting, and `Wh` the hand-arm weighting. 38 + 39 + ```python 40 + import phonometry as ph 41 + 42 + # The overall weighting response at any frequencies (ISO 8041-1 Formula (5)). 43 + resp = ph.frequency_weighting("Wk", [1.0, 6.3096, 20.0]) 44 + print(resp.magnitude.round(3)) # [0.482 1.054 0.636] (factors) 45 + print(resp.magnitude_db.round(2)) # [-6.33 0.46 -3.93] (dB) 46 + ``` 47 + 48 + The factors reproduce the ISO 8041-1 Annex B design-goal tables to their four 49 + significant figures: `Wk` plateaus near −6 dB below 2 Hz, peaks at +0.46 dB near 50 + 6.3 Hz and rolls off above. 51 + 52 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/vibration_weighting.png" alt="The whole-body vertical weighting Wk in decibels over 0.4 to 100 Hz: a plateau near -6 dB below 2 Hz, a small +0.5 dB peak near 6 Hz and a roll-off to about -21 dB at 100 Hz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/vibration_weighting_dark.png" alt="The whole-body vertical weighting Wk in decibels over 0.4 to 100 Hz: a plateau near -6 dB below 2 Hz, a small +0.5 dB peak near 6 Hz and a roll-off to about -21 dB at 100 Hz" style="width:88%"> 53 + 54 + <details> 55 + <summary>Show the code for this figure</summary> 56 + 57 + ```python 58 + import numpy as np 59 + import matplotlib.pyplot as plt 60 + import phonometry as ph 61 + 62 + result = ph.frequency_weighting("Wk", np.geomspace(0.4, 100.0, 240)) 63 + 64 + # One line: 65 + result.plot() 66 + plt.show() 67 + 68 + # By hand, from the result's fields, mirroring what WeightingResponse.plot() draws: 69 + fig, ax = plt.subplots() 70 + ax.semilogx(result.frequencies, result.magnitude_db, color="#1f77b4") 71 + ax.set_xlabel("Frequency [Hz]") 72 + ax.set_ylabel("Weighting factor [dB]") 73 + ax.set_title("Whole-body vertical weighting Wk (ISO 8041-1)") 74 + plt.show() 75 + ``` 76 + 77 + </details> 78 + 79 + To weight a time signal, `apply_weighting` applies the exact complex response in 80 + the frequency domain (so magnitude *and* phase match the standard), which the 81 + time-domain dose metrics below then consume. 82 + 83 + ## 2. Weighted acceleration and dose measures (ISO 2631-1) 84 + 85 + The basic evaluation is the **weighted r.m.s. acceleration**. From a 86 + one-third-octave spectrum it is (ISO 2631-1 Eq. (9); the identical construction 87 + gives the hand-arm $a_{hw}$ of ISO 5349-1 Eq. (A.1)): 88 + 89 + $$ 90 + a_w = \sqrt{\sum_i \left(W_i\,a_i\right)^2}, 91 + $$ 92 + 93 + with $W_i$ the weighting factor at band centre $i$ and $a_i$ the measured band 94 + acceleration. 95 + 96 + ```python 97 + import numpy as np 98 + import phonometry as ph 99 + 100 + # A measured vertical seat spectrum (r.m.s. per one-third octave, m/s^2). 101 + freqs = np.array([1.0, 2.0, 4.0, 8.0, 16.0, 31.5, 63.0]) 102 + accel = np.array([0.20, 0.45, 0.42, 0.25, 0.12, 0.05, 0.02]) 103 + 104 + result = ph.weighted_acceleration(accel, freqs, "Wk") 105 + print(round(result.overall, 3)) # 0.555 m/s^2 (a_w) 106 + print(result.weighted.round(3)) # W_i * a_i per band 107 + ``` 108 + 109 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/weighted_acceleration.png" alt="A measured vehicle-seat acceleration spectrum (grey) and its Wk-weighted contribution (blue) over the one-third octaves from 1 to 80 Hz: the weighting attenuates the low and high bands but leaves the 4 to 8 Hz range nearly unchanged, giving a weighted r.m.s. a_w of about 1.03 m/s^2" style="width:90%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/weighted_acceleration_dark.png" alt="A measured vehicle-seat acceleration spectrum (grey) and its Wk-weighted contribution (blue) over the one-third octaves from 1 to 80 Hz: the weighting attenuates the low and high bands but leaves the 4 to 8 Hz range nearly unchanged, giving a weighted r.m.s. a_w of about 1.03 m/s^2" style="width:90%"> 110 + 111 + <details> 112 + <summary>Show the code for this figure</summary> 113 + 114 + ```python 115 + import numpy as np 116 + import matplotlib.pyplot as plt 117 + import phonometry as ph 118 + 119 + freqs = np.array([1.0, 1.25, 1.6, 2.0, 2.5, 3.15, 4.0, 5.0, 6.3, 8.0, 10.0, 120 + 12.5, 16.0, 20.0, 25.0, 31.5, 40.0, 63.0, 80.0]) 121 + accel = np.array([0.18, 0.24, 0.33, 0.46, 0.52, 0.55, 0.48, 0.39, 0.31, 0.26, 122 + 0.21, 0.17, 0.13, 0.10, 0.078, 0.060, 0.045, 0.028, 0.020]) 123 + result = ph.weighted_acceleration(accel, freqs, "Wk") 124 + 125 + # One line: 126 + result.plot() 127 + plt.show() 128 + 129 + # By hand, mirroring what WeightedSpectrum.plot() draws: 130 + pos = np.arange(freqs.size) 131 + fig, ax = plt.subplots() 132 + ax.bar(pos - 0.2, result.band_accelerations, 0.4, color="#bbbbbb", 133 + label="Unweighted $a_i$") 134 + ax.bar(pos + 0.2, result.weighted, 0.4, color="#1f77b4", 135 + label="Weighted $W_i a_i$ (Wk)") 136 + ax.set_xticks(pos) 137 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 138 + ax.set_xlabel("Frequency [Hz]") 139 + ax.set_ylabel(r"r.m.s. acceleration [m/s$^2$]") 140 + ax.set_title(f"Weighted acceleration ($a_w$ = {result.overall:.3f} m/s²)") 141 + ax.legend() 142 + plt.show() 143 + ``` 144 + 145 + </details> 146 + 147 + When the r.m.s. value understates an intermittent or shock-laden exposure, 148 + ISO 2631-1 adds dose measures computed on the weighted time signal: the 149 + **running r.m.s.** and its maximum, the **maximum transient vibration value** 150 + `MTVV` (Eq. (4), a 1 s running r.m.s.); the fourth-power **vibration dose 151 + value** $\text{VDV} = \left(\int a_w^4\,dt\right)^{1/4}$ (Eq. (5)); the **motion 152 + sickness dose value** $\text{MSDV} = \left(\int a_w^2\,dt\right)^{1/2}$; and the 153 + **crest factor** (peak / r.m.s.), whose value above 9 signals that the basic 154 + method is inadequate. 155 + 156 + ```python 157 + import numpy as np 158 + import phonometry as ph 159 + 160 + fs = 1000.0 161 + raw = np.random.default_rng(0).standard_normal(int(60 * fs)) # 60 s record 162 + a_w = ph.apply_weighting(raw, fs, "Wk") # weighted signal 163 + 164 + print(round(ph.vibration_dose_value(a_w, fs), 3)) # VDV [m/s^1.75] 165 + print(round(ph.mtvv(a_w, fs), 3)) # MTVV [m/s^2] 166 + print(round(ph.crest_factor(a_w), 2)) # crest factor 167 + ``` 168 + 169 + ## 3. Vibration total value and daily exposure `A(8)` 170 + 171 + Across the three axes the **vibration total value** combines the axis-weighted 172 + r.m.s. accelerations with the posture multiplying factors $k_j$ (ISO 2631-1 173 + Eq. (10); for hand-arm, ISO 5349-1 Eq. (1) with every $k = 1$): 174 + 175 + $$ 176 + a_v = \sqrt{\sum_j k_j^2\,a_{wj}^2}. 177 + $$ 178 + 179 + ```python 180 + import phonometry as ph 181 + 182 + # Health, seated: k = 1.4 / 1.4 / 1.0 (ISO 2631-1, 7.2.3). 183 + a_v = ph.vibration_total_value([0.35, 0.28, 0.62], k=[1.4, 1.4, 1.0]) 184 + print(round(a_v, 3)) # 0.882 m/s^2 185 + ``` 186 + 187 + The **daily exposure** normalises the total value to a reference 8-hour day 188 + ($T_0 = 28\,800$ s). For a single operation $A(8) = a_v\,\sqrt{T/T_0}$; several 189 + operations combine through their partial exposures $A_i(8) = a_{vi}\,\sqrt{T_i/T_0}$ 190 + as $A(8) = \sqrt{\sum_i A_i(8)^2}$ (ISO 5349-1 Eqs. (2)/(3); ISO 5349-2 191 + Eqs. (1)–(3)). 192 + 193 + `daily_vibration_exposure` builds the partial exposures, combines them and 194 + assesses the result against **Directive 2002/44/EC** — hand-arm action value 195 + `A(8) = 2.5` and limit value `5` m/s²; whole-body action `0.5` and limit `1.15` 196 + m/s² (or a VDV of `9.1` / `21` m/s¹·⁷⁵): 197 + 198 + ```python 199 + import phonometry as ph 200 + 201 + # ISO 5349-2 Annex E.3: a forestry worker's three chain-saw tasks. 202 + result = ph.daily_vibration_exposure( 203 + total_values=[4.6, 6.0, 3.6], # a_hv per task, m/s^2 204 + durations_s=[2 * 3600, 1 * 3600, 2 * 3600], # exposure time per task 205 + kind="hav", 206 + labels=["brush-saw", "felling", "stripping"], 207 + ) 208 + print(result.partials.round(2)) # [2.3 2.12 1.8 ] A_i(8) 209 + print(round(result.a8, 2)) # 3.61 m/s^2 210 + print(result.assessment.zone) # 'action' (2.5 <= A(8) < 5.0) 211 + ``` 212 + 213 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/daily_vibration_exposure.png" alt="A bar chart of the three partial hand-arm exposures (about 2.3, 2.1 and 1.8 m/s^2) and the combined A(8) of 3.61 m/s^2, with the Directive 2002/44/EC exposure action value at 2.5 and exposure limit value at 5.0 m/s^2 marked as horizontal lines; the daily exposure sits in the action zone between them" style="width:82%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/daily_vibration_exposure_dark.png" alt="A bar chart of the three partial hand-arm exposures (about 2.3, 2.1 and 1.8 m/s^2) and the combined A(8) of 3.61 m/s^2, with the Directive 2002/44/EC exposure action value at 2.5 and exposure limit value at 5.0 m/s^2 marked as horizontal lines; the daily exposure sits in the action zone between them" style="width:82%"> 214 + 215 + <details> 216 + <summary>Show the code for this figure</summary> 217 + 218 + ```python 219 + import numpy as np 220 + import matplotlib.pyplot as plt 221 + import phonometry as ph 222 + 223 + result = ph.daily_vibration_exposure( 224 + [4.6, 6.0, 3.6], [2 * 3600, 1 * 3600, 2 * 3600], kind="hav", 225 + labels=["brush-saw", "felling", "stripping"], 226 + ) 227 + 228 + # One line: 229 + result.plot() 230 + plt.show() 231 + 232 + # By hand, mirroring what DailyVibrationExposure.plot() draws: 233 + labels = [*result.labels, "A(8)"] 234 + values = [*result.partials.tolist(), result.a8] 235 + a = result.assessment 236 + fig, ax = plt.subplots() 237 + ax.bar(range(len(values)), values, 238 + color=["#bbbbbb"] * result.partials.size + ["#1f77b4"]) 239 + ax.axhline(a.action_value, color="#2ca02c", ls="--", label=f"EAV = {a.action_value:g}") 240 + ax.axhline(a.limit_value, color="#d62728", ls="--", label=f"ELV = {a.limit_value:g}") 241 + ax.set_xticks(range(len(values))) 242 + ax.set_xticklabels(labels, rotation=30, ha="right") 243 + ax.set_ylabel(r"Daily exposure A(8) [m/s$^2$]") 244 + ax.legend() 245 + plt.show() 246 + ``` 247 + 248 + </details> 249 + 250 + ## 4. Exposure–response guidance 251 + 252 + For hand-transmitted vibration, ISO 5349-1 Annex C relates the daily exposure to 253 + the group-mean lifetime $D_y$ (in years) that produces vibration-white-finger in 254 + 10 % of an exposed group, $D_y = 31.8\,A(8)^{-1.06}$ (Eq. (C.1)): 255 + 256 + ```python 257 + import phonometry as ph 258 + 259 + print(round(ph.hav_vwf_lifetime_years(7.0), 1)) # 4.0 years (Table C.1) 260 + ``` 261 + 262 + The standards deliberately define no safe limit — `A(8)` and the directive's 263 + action and limit values are the basis for any exposure criterion. For whole-body 264 + exposure, `energy_equivalent_acceleration` gives the ISO 2631-1 Eq. (B.3) 265 + energy-equivalent magnitude across periods of different magnitude and duration. 266 + 267 + --- 268 + 269 + **Standards.** ISO 8041-1:2017 (weighting definitions and tolerances); 270 + ISO 2631-1:1997 (whole-body evaluation); ISO 2631-2:2003 (buildings, `Wm`); 271 + ISO 2631-4:2001 (rail ride comfort, `Wb`); ISO 5349-1:2001 and ISO 5349-2:2001 272 + (hand-transmitted vibration); Directive 2002/44/EC (exposure action and limit 273 + values).
+281
site/src/content/docs/guides/materials.md
··· 1 + --- 2 + title: "Acoustic Materials" 3 + description: "Characterising absorbers and partitions in the lab: the ISO 11654 weighted sound-absorption rating alpha_w and its class, the ISO 9053-1/-2 airflow resistance and resistivity, and the impedance-tube surface impedance, absorption and transmission loss of ISO 10534-1/-2 and ASTM E2611." 4 + --- 5 + 6 + Characterising an absorber or a partition is a laboratory exercise with three 7 + distinct instruments behind it. The **reverberation room** delivers a spectrum of 8 + sound-absorption coefficients that ISO 11654 collapses into a single rated number 9 + $\alpha_w$ with a letter class. The **flow rig** — steady or oscillating — 10 + measures how hard air is to push through a porous sample, the airflow resistance 11 + that governs its low-frequency behaviour (ISO 9053-1/-2). And the **impedance 12 + tube** recovers, at normal incidence, the full complex surface impedance, 13 + reflection factor and absorption of a small sample, and — with four microphones — 14 + its transmission loss (ISO 10534-1/-2, ASTM E2611). This page covers all three. 15 + 16 + ## 1. Sound-absorption rating (ISO 11654) 17 + 18 + ISO 354 measures the sound-absorption coefficient $\alpha_s$ of a material in 19 + one-third-octave bands in a reverberation room. ISO 11654:1997 turns that 20 + spectrum into a single-number rating comparable across products. 21 + 22 + **Practical absorption coefficient (Clause 4.1).** The one-third-octave data are 23 + first grouped into octave bands, each the arithmetic mean of its three thirds: 24 + 25 + $$ 26 + \alpha_{p,i} = \tfrac{1}{3}\big(\alpha_{i1} + \alpha_{i2} + \alpha_{i3}\big), 27 + $$ 28 + 29 + evaluated to the second decimal and then rounded in steps of $0.05$ (the 30 + Clause 4.1 NOTE fixes the rounding, e.g. $0.92 \to 0.90$); rounded means above 31 + $1.00$ are set to $1.00$. The five rating bands are 250, 500, 1000, 2000 and 32 + 4000 Hz. 33 + 34 + **Weighted absorption (Clause 4.2).** A fixed reference curve 35 + $\{250{:}\,0.80,\ 500{:}\,1.00,\ 1000{:}\,1.00,\ 2000{:}\,1.00,\ 4000{:}\,0.90\}$ 36 + is shifted downwards, towards the measured $\alpha_p$, in steps of $0.05$ until 37 + the sum of the **unfavourable** deviations — taken only where the measurement 38 + lies below the shifted curve, with magnitude $(\text{curve} - \text{measured})$ — 39 + is no more than $0.10$. The weighted coefficient $\alpha_w$ is the shifted-curve 40 + value read at 500 Hz. 41 + 42 + **Shape indicators (Clause 4.3).** When a practical coefficient exceeds the 43 + shifted curve by $0.25$ or more, a shape indicator is appended: `L` at 250 Hz, 44 + `M` at 500 or 1000 Hz, `H` at 2000 or 4000 Hz (e.g. `0.60(M)`). 45 + 46 + **Absorption class (Table B.1).** Finally $\alpha_w$ maps to a class: A 47 + (0.90–1.00), B (0.80–0.85), C (0.60–0.75), D (0.30–0.55), E (0.15–0.25), or "not 48 + classified" (0.00–0.10). Because $\alpha_w$ is always a multiple of $0.05$ these 49 + ranges partition the grid exactly. 50 + 51 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/absorption_rating.png" alt="ISO 11654 weighted sound absorption rating: the practical absorption spectrum plotted against the shifted reference curve over 250 Hz to 4000 Hz, with the unfavourable deviation at 250 Hz shaded and the weighted coefficient alpha_w read at 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/absorption_rating_dark.png" alt="ISO 11654 weighted sound absorption rating: the practical absorption spectrum plotted against the shifted reference curve over 250 Hz to 4000 Hz, with the unfavourable deviation at 250 Hz shaded and the weighted coefficient alpha_w read at 500 Hz" style="width:80%"> 52 + 53 + *The Annex A.2 worked example: the reference curve is shifted down by 0.40 until 54 + the unfavourable deviations sum to 0.05 (≤ 0.10), giving $\alpha_w = 0.60$; the 55 + 500 Hz peak overshoots the shifted curve by ≥ 0.25, adding the `M` indicator, so 56 + the rating is $0.60(\text{M})$, class C.* 57 + 58 + ```python 59 + from phonometry import weighted_absorption, absorption_class 60 + 61 + # ISO 11654 Annex A.2 practical coefficients at 250/500/1000/2000/4000 Hz 62 + alpha_p = [0.35, 1.00, 0.65, 0.60, 0.55] 63 + 64 + result = weighted_absorption(alpha_p) 65 + print(result.rating_label) # 0.60(M) 66 + print(result.alpha_w) # 0.6 67 + print(result.absorption_class) # C 68 + print(round(result.unfavourable_sum, 2)) # 0.05 69 + 70 + # A bare alpha_w also maps straight to its class (Table B.1) 71 + print(absorption_class(0.85)) # B 72 + ``` 73 + 74 + `weighted_absorption` accepts the five octave-band $\alpha_p$ values (as a 75 + sequence or a `{frequency: value}` mapping); pass the fifteen one-third-octave 76 + $\alpha_s$ values to `practical_absorption_coefficient` first if you are starting 77 + from raw ISO 354 data. The result carries the shifted reference curve and the 78 + per-band deviations, and its `.plot()` renders the figure above. 79 + 80 + ## 2. Airflow resistance (ISO 9053-1/-2) 81 + 82 + The airflow resistance quantifies how strongly a porous material opposes a steady 83 + or slowly-oscillating flow. Both parts share the same three quantities and units 84 + (ISO 9053-1:2018, Clause 3): 85 + 86 + $$ 87 + R = \frac{\Delta p}{q_v}\ \left[\text{Pa·s/m}^3\right], \qquad 88 + R_s = R\,A\ \left[\text{Pa·s/m}\right], \qquad 89 + \sigma = \frac{R_s}{d}\ \left[\text{Pa·s/m}^2\right], 90 + $$ 91 + 92 + with $\Delta p$ the pressure difference across the specimen, $q_v$ the volumetric 93 + flow, $A$ the cross-section and $d$ the thickness. Note the specific airflow 94 + resistance $R_s$ is in **Pa·s/m** (not Pa·s/m²); the airflow resistivity $\sigma$ 95 + is $R_s$ per metre of thickness. 96 + 97 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_airflow_resistance.svg" alt="Airflow resistance measurement rigs: the ISO 9053-1 static method with a specimen in a holder, a steady laminar flow q_v and a differential manometer reading the pressure drop; and the ISO 9053-2 alternating method with an oscillating piston driving a cavity terminated by the specimen or an airtight plug, and a microphone reading the cavity level" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_airflow_resistance_dark.svg" alt="Airflow resistance measurement rigs: the ISO 9053-1 static method with a specimen in a holder, a steady laminar flow q_v and a differential manometer reading the pressure drop; and the ISO 9053-2 alternating method with an oscillating piston driving a cavity terminated by the specimen or an airtight plug, and a microphone reading the cavity level" style="width:92%"> 98 + 99 + **Static method (ISO 9053-1:2018).** A steady laminar flow is stepped up and the 100 + pressure difference plotted against the linear velocity $u = q_v/A$. A regression 101 + of at least second order **constrained through the origin**, $\Delta p = a\,u + 102 + b\,u^2$, is fitted, and $\Delta p$ and $R_s$ are read at the reference velocity 103 + $u = 0.5\ \text{mm/s}$ (Clause 7.5); the highest velocity must not exceed 104 + 15 mm/s. Because $R_s = \Delta p/u = a + b\,u$, the linear term $a$ is the 105 + zero-velocity specific airflow resistance. 106 + 107 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/airflow_resistance.png" alt="ISO 9053-1 static-method airflow resistance: the measured pressure drop against linear airflow velocity, fitted with a through-origin quadratic, with the specific airflow resistance evaluated at the 0.5 mm/s reference velocity" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/airflow_resistance_dark.png" alt="ISO 9053-1 static-method airflow resistance: the measured pressure drop against linear airflow velocity, fitted with a through-origin quadratic, with the specific airflow resistance evaluated at the 0.5 mm/s reference velocity" style="width:80%"> 108 + 109 + *The slightly super-linear pressure drop is fitted through the origin; the 110 + specific airflow resistance is the fit read at 0.5 mm/s.* 111 + 112 + ```python 113 + import numpy as np 114 + from phonometry import static_airflow_resistance 115 + 116 + area = np.pi * 0.05**2 # 100 mm diameter cell [m^2] 117 + u = np.array([0.5, 1, 2, 4, 8, 12]) * 1e-3 # linear velocity [m/s] 118 + dp = 1.6e4 * u + 4.0e5 * u**2 # measured pressure drop [Pa] 119 + 120 + r = static_airflow_resistance(u, dp, area=area, thickness=0.05) 121 + print(round(r.specific_resistance)) # 16200 R_s [Pa*s/m] 122 + print(round(r.resistivity)) # 324000 sigma [Pa*s/m^2] 123 + print(round(r.linear_coefficient)) # 16000 a = R_s at u -> 0 124 + ``` 125 + 126 + **Alternating method (ISO 9053-2:2020).** A piston oscillating at 1–4 Hz drives 127 + an alternating flow into a cavity terminated either by the specimen or by an 128 + airtight plug; the resistance follows from the sound-pressure-level difference 129 + between the two terminations (Formula (2)): 130 + 131 + $$ 132 + R = \frac{\kappa'\,P_S}{2\pi f\,V}\cdot\frac{h_t}{h_s}\cdot 133 + 10^{(L_{p,s} - L_{p,t})/20}, 134 + $$ 135 + 136 + where $\kappa'$ is the **effective** ratio of specific heats. Heat conduction 137 + between the oscillating air and the cavity walls makes the compression not fully 138 + adiabatic; the normative Annex A corrects $\kappa$ down to 139 + 140 + $$ 141 + \kappa' = \frac{\kappa}{\sqrt{1 + (\kappa-1)\tfrac{S}{V}b 142 + + \tfrac{1}{2}\big((\kappa-1)\tfrac{S}{V}b\big)^2}}, 143 + \qquad b = \sqrt{\frac{2 c_0 l_h}{\omega}},\quad 144 + l_h = \frac{k_a}{\rho_0 c_0 C_P}, 145 + $$ 146 + 147 + with $S$ and $V$ the cavity surface and volume and $b$ the thermal 148 + boundary-layer thickness. For the Annex A.3 example cavity this gives 149 + $\kappa' = 1.370$, about 2 % below the adiabatic 1.4008. 150 + 151 + ```python 152 + from phonometry import effective_kappa, alternating_airflow_resistance 153 + 154 + # Annex A.3 cavity: closed cylinder 100 mm x 100 mm, piston at 2 Hz 155 + kp = effective_kappa(cavity_surface=0.0471, cavity_volume=7.854e-4, frequency=2.0) 156 + print(round(kp, 3)) # 1.37 effective ratio of specific heats 157 + 158 + R = alternating_airflow_resistance( 159 + level_specimen=74.0, level_termination=90.0, 160 + piston_stroke_specimen=14e-3, piston_stroke_termination=1.4e-3, 161 + frequency=2.0, cavity_volume=7.854e-4, kappa_prime=kp, 162 + ) 163 + print(round(R)) # airflow resistance R [Pa*s/m^3] 164 + ``` 165 + 166 + Pass the `effective_kappa` result to `alternating_airflow_resistance` for an 167 + Annex-A-conforming figure; its `kappa_prime` argument otherwise defaults to the 168 + uncorrected adiabatic 1.4. The call warns (via `AirflowResistanceWarning`) when 169 + the piston frequency leaves 1–4 Hz or the Formula (3)/(4) validity criteria fail. 170 + 171 + ## 3. Impedance tube (ISO 10534-1/-2, ASTM E2611) 172 + 173 + The impedance tube measures a small sample at **normal incidence**. Two standards 174 + share the geometry but differ in method and sign convention, so the library keeps 175 + their helpers separate and never mixes them. 176 + 177 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impedance_tube.svg" alt="ISO 10534-2 two-microphone impedance tube: a loudspeaker radiating a plane wave down the tube, two microphones flush in the wall at spacing s and distance x1 from the specimen face, the test specimen against a rigid backing, and the incident and reflected waves" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impedance_tube_dark.svg" alt="ISO 10534-2 two-microphone impedance tube: a loudspeaker radiating a plane wave down the tube, two microphones flush in the wall at spacing s and distance x1 from the specimen face, the test specimen against a rigid backing, and the incident and reflected waves" style="width:92%"> 178 + 179 + **Standing-wave-ratio method (ISO 10534-1).** A probe traverses the standing wave 180 + and reads the level difference $\Delta L = L_\text{max} - L_\text{min}$ between a 181 + pressure maximum and the adjacent minimum. The standing-wave ratio, reflection 182 + magnitude and absorption follow in closed form: 183 + 184 + $$ 185 + s = 10^{\Delta L/20}, \qquad |r| = \frac{s-1}{s+1}, \qquad 186 + \alpha = 1 - |r|^2. 187 + $$ 188 + 189 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impedance_tube.png" alt="ISO 10534-1 standing-wave-ratio method: the absorption coefficient and the reflection factor magnitude as functions of the standing-wave level difference, showing that a 9.54 dB difference corresponds to a standing-wave ratio of 3, a reflection magnitude of 0.5 and an absorption of 0.75" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impedance_tube_dark.png" alt="ISO 10534-1 standing-wave-ratio method: the absorption coefficient and the reflection factor magnitude as functions of the standing-wave level difference, showing that a 9.54 dB difference corresponds to a standing-wave ratio of 3, a reflection magnitude of 0.5 and an absorption of 0.75" style="width:80%"> 190 + 191 + *A small level difference means a near-perfect absorber; a level difference of 192 + 9.54 dB gives $s = 3$, $|r| = 0.5$ and $\alpha = 0.75$.* 193 + 194 + ```python 195 + from phonometry import standing_wave_absorption, standing_wave_ratio_from_level 196 + 197 + s = float(standing_wave_ratio_from_level(9.542)) # level difference [dB] -> SWR 198 + print(round(s, 2)) # 3.0 199 + print(round(float(standing_wave_absorption(s)), 2)) # 0.75 200 + ``` 201 + 202 + **Transfer-function method (ISO 10534-2).** Two fixed microphones measure the 203 + complex transfer function $H_{12}$; from it the reflection factor at the sample 204 + face, the absorption and the normalised surface impedance follow (Eqs. (17)–(19)): 205 + 206 + $$ 207 + r = \frac{H_{12} - H_I}{H_R - H_{12}}\,e^{\,2 j k_0 x_1}, \qquad 208 + \alpha = 1 - |r|^2, \qquad \frac{Z}{\rho c_0} = \frac{1+r}{1-r}, 209 + $$ 210 + 211 + with $H_I = e^{-j k_0 s}$, $H_R = e^{+j k_0 s}$, microphone spacing $s$ and $x_1$ 212 + the distance from the sample to the farther microphone. 213 + 214 + ```python 215 + import numpy as np 216 + from phonometry import ( 217 + tube_wavenumber, reflection_factor, 218 + absorption_from_reflection, normalized_surface_impedance, 219 + ) 220 + 221 + f = np.array([500.0, 1000.0, 1800.0]) 222 + x1, spacing, c0 = 0.12, 0.03, 343.2 223 + k0 = tube_wavenumber(f, c0) 224 + 225 + # A measured transfer function H12 (here synthesised from r = 0.3 - 0.4j) 226 + target = 0.3 - 0.4j 227 + x2 = x1 - spacing 228 + h12 = (np.exp(1j*k0*x2) + target*np.exp(-1j*k0*x2)) / \ 229 + (np.exp(1j*k0*x1) + target*np.exp(-1j*k0*x1)) 230 + 231 + r = reflection_factor(h12, spacing=spacing, x1=x1, wavenumber=k0) 232 + print(np.round(absorption_from_reflection(r), 3)) # [0.75 0.75 0.75] 233 + print(np.round(normalized_surface_impedance(r), 2)) # Z / rho c0 234 + ``` 235 + 236 + The high-level `two_microphone_impedance` wraps this chain and returns an 237 + `ImpedanceTubeResult` with absorption, reflection factor, surface impedance and 238 + normalised impedance, applying the plane-wave frequency-range check and optional 239 + tube attenuation; correct any microphone mismatch beforehand with 240 + `apply_mic_calibration`. 241 + 242 + **Transmission loss (ASTM E2611).** With four microphones — two upstream, two 243 + downstream of the sample — a two-load (or one-load) measurement recovers the 244 + sample's transfer matrix, whose entries give the normal-incidence transmission 245 + loss, reflection and wavenumber: 246 + 247 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_astm_tube.svg" alt="ASTM E2611 four-microphone transmission-loss tube: a sound source, two microphones upstream and two downstream of the test specimen at spacings s1 and s2 and offsets l1 and l2, an adjustable termination for the two-load method, the upstream A and B and downstream C and D travelling waves, and the transfer matrix and transmission-loss relations" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_astm_tube_dark.svg" alt="ASTM E2611 four-microphone transmission-loss tube: a sound source, two microphones upstream and two downstream of the test specimen at spacings s1 and s2 and offsets l1 and l2, an adjustable termination for the two-load method, the upstream A and B and downstream C and D travelling waves, and the transfer matrix and transmission-loss relations" style="width:92%"> 248 + 249 + $$ 250 + \mathrm{TL} = 20\log_{10}\left|\frac{T_{11} + T_{12}/\rho c 251 + + \rho c\,T_{21} + T_{22}}{2}\right|. 252 + $$ 253 + 254 + ```python 255 + import numpy as np 256 + from phonometry import air_layer_transfer_matrix 257 + 258 + # An air layer is a known transfer matrix; TL = 0 dB (nothing is lost) 259 + f = np.array([500.0, 1000.0, 2000.0]) 260 + k0 = 2*np.pi*f / 343.2 261 + rho_c = 1.186 * 343.2 262 + tm = air_layer_transfer_matrix(thickness=0.05, wavenumber=k0, 263 + characteristic_impedance=rho_c) 264 + print(np.round(tm.transmission_loss(rho_c), 6)) # [0. 0. 0.] 265 + ``` 266 + 267 + `transfer_matrix_two_load` / `transfer_matrix_one_load` build the 268 + `TransferMatrix` from the four measured microphone transfer functions 269 + `(H1, H2, H3, H4)` of each load; its methods 270 + (`transmission_loss`, `reflection_hard_backed`, `absorption_hard_backed`, 271 + `characteristic_impedance_material`, `material_wavenumber`) then read off the 272 + ASTM E2611 quantities. 273 + 274 + --- 275 + 276 + **Standards.** ISO 11654:1997 (weighted sound-absorption rating); ISO 9053-1:2018 277 + (static airflow resistance); ISO 9053-2:2020 (alternating airflow resistance); 278 + ISO 10534-1:1996 and ISO 10534-2:1998 (impedance tube); ASTM E2611-19 279 + (four-microphone transmission loss). Every equation is derived from the standard 280 + text and validated against the standards' own worked examples (ISO 11654 Annex A, 281 + ISO 9053-2 Annex A.3) and closed-form identities.
+1 -1
site/src/content/docs/guides/outdoor-propagation.md
··· 248 248 249 249 The method's stated accuracy is $\pm 1$ to $\pm 3$ dB for broadband noise up to 250 250 1000 m (Table 5). See the [Theory](/phonometry/reference/theory/) page for the full derivation, the 251 - [Room and Building Acoustics guide](/phonometry/guides/room-acoustics/) for how $\alpha$ feeds 251 + [Room Acoustics guide](/phonometry/guides/room-acoustics/) for how $\alpha$ feeds 252 252 ISO 354, and the [Levels guide](/phonometry/guides/levels/) for the ISO 9612 occupational 253 253 exposure that consumes A-weighted levels.
+15 -638
site/src/content/docs/guides/room-acoustics.md
··· 1 1 --- 2 - title: "Room & Building Acoustics" 3 - description: "Impulse-response acquisition (ISO 18233), room parameters EDT/T20/T30/C50/C80/Ts (ISO 3382-1/2), open-plan speech metrics (ISO 3382-3), laboratory (ISO 10140) and field (ISO 16283-1/2/3) airborne and impact sound insulation with weighted ratings (ISO 717-1/2), transmission prediction (EN 12354) and measurement uncertainty (ISO 12999-1), and sound absorption in a reverberation room (ISO 354)." 2 + title: "Room Acoustics" 3 + description: "Impulse-response acquisition (ISO 18233), room parameters EDT/T20/T30/C50/C80/Ts (ISO 3382-1/2), open-plan speech metrics (ISO 3382-3) and sound absorption in a reverberation room (ISO 354)." 4 4 --- 5 5 6 - Room and building acoustics start from one measurement: the **impulse 7 - response** (IR) between a source and a receiver. Filter it into bands and 8 - integrate it, and it yields reverberation time, clarity and speech 9 - intelligibility; measure it either side of a wall and it yields the sound 10 - insulation of the partition. This page follows that chain in measurement 11 - order — acquiring the IR (ISO 18233), turning it into room parameters 12 - (ISO 3382-1/2), spatial speech metrics for open-plan offices 13 - (ISO 3382-3), field airborne, impact and façade insulation with 14 - single-number ratings (ISO 16283-1/2/3, ISO 717-1/2), the laboratory 15 - characterisation of a building element (ISO 10140), the prediction of 16 - in-situ performance from flanking transmission (EN 12354-1/2), the 17 - measurement uncertainty that qualifies every rating (ISO 12999-1) and, 18 - closing the loop, the sound absorption of a material in a reverberation 19 - room (ISO 354). 6 + Room acoustics starts from one measurement: the **impulse response** (IR) 7 + between a source and a receiver. Filter it into bands and integrate it, and 8 + it yields reverberation time, clarity and speech intelligibility — everything 9 + about the sound field inside a single room. This page follows that chain in 10 + measurement order — acquiring the IR (ISO 18233), turning it into room 11 + parameters (ISO 3382-1/2), spatial speech metrics for open-plan offices 12 + (ISO 3382-3) and, closing the loop, the sound absorption of a material in a 13 + reverberation room (ISO 354). For sound insulation *between* spaces — the same 14 + IR measured either side of a partition — see the companion 15 + [Building Acoustics & Sound Insulation guide](/phonometry/guides/building-acoustics/). 20 16 21 17 ## 1. Impulse-response acquisition (ISO 18233) 22 18 ··· 317 313 STI can itself be measured with the STIPA tools in the 318 314 [Psychoacoustics guide](/phonometry/guides/psychoacoustics/). 319 315 320 - ## 4. Field insulation and single-number ratings (ISO 16283-1, ISO 717-1) 321 - 322 - To rate a wall or floor, measure the energy-average level in the **source** 323 - room ($L_1$) and the **receiving** room ($L_2$) per one-third-octave band 324 - and form the level difference $D = L_1 - L_2$. Two normalisations make it 325 - comparable between rooms. The **standardized level difference** references 326 - the receiving-room reverberation time $T$ to $T_0 = 0.5$ s (so with 327 - $T = 0.5$ s, $D_{nT} = D$ exactly), and the **apparent sound reduction 328 - index** normalises by the partition area $S$ and the Sabine absorption area 329 - $A$: 330 - 331 - $$ 332 - D_{nT} = D + 10 \log_{10} \frac{T}{T_0}, \qquad 333 - R' = D + 10 \log_{10} \frac{S}{A}, \qquad A = \frac{0.16\ V}{T}. 334 - $$ 335 - 336 - Positions are energy-averaged with 337 - $L = 10 \log_{10}\left( \frac{1}{n} \sum_i 10^{L_i/10} \right)$. 338 - 339 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup.svg" alt="Field airborne insulation setup: a loudspeaker in the source room, microphones energy-averaged in source and receiving rooms across the common partition" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insulation_setup_dark.svg" alt="Field airborne insulation setup: a loudspeaker in the source room, microphones energy-averaged in source and receiving rooms across the common partition" style="width:92%"> 340 - 341 - The band spectrum is collapsed to one number by the **reference-curve 342 - method** of ISO 717-1: a fixed reference curve is shifted in 1 dB steps 343 - toward the measured curve until the sum of *unfavourable* deviations 344 - (where the measurement falls below the reference) is as large as possible 345 - but not more than 32.0 dB (16 one-third-octave bands) or 10.0 dB (5 octave 346 - bands). The rating (`Rw`, `R'w`, `DnT,w` …) is the shifted reference read at 347 - 500 Hz. The **spectrum adaptation terms** $C$ (pink noise) and $C_{tr}$ 348 - (urban traffic) add the low-frequency penalty of a real source. 349 - 350 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating.png" alt="Measured one-third-octave sound reduction index with the shifted ISO 717-1 reference curve and the resulting weighted rating at 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_rating_dark.png" alt="Measured one-third-octave sound reduction index with the shifted ISO 717-1 reference curve and the resulting weighted rating at 500 Hz" style="width:80%"> 351 - 352 - ```python 353 - import numpy as np 354 - from phonometry import airborne_insulation, weighted_rating, energy_average_level 355 - 356 - # Energy-average several microphone positions in one room (dB) 357 - print(round(float(energy_average_level([60.0, 66.0])), 1)) # 64.0 358 - 359 - # Field insulation per band; area S and volume V add R' 360 - l1 = np.full(16, 80.0) # source-room levels 361 - l2 = np.full(16, 40.0) # receiving-room levels 362 - t2 = np.full(16, 0.5) # receiving-room T (s) 363 - ins = airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 364 - print(round(float(ins.dnt[0]), 1)) # 40.0 (= D since T = T0) 365 - print(round(float(ins.r_prime[0]), 1)) # 38.0 366 - 367 - # Single-number rating from a measured 16-band R spectrum (ISO 717-1 Annex C) 368 - R = [20.4, 16.3, 17.7, 22.6, 22.4, 22.7, 24.8, 26.6, 369 - 28.0, 30.5, 31.8, 32.5, 33.4, 33.0, 31.0, 25.5] 370 - w = weighted_rating(R) 371 - print(w.rating, w.c, w.ctr) # 30 -2 -3 -> Rw(C;Ctr) = 30(-2;-3) 372 - 373 - w.plot() # measured R' vs shifted ISO 717-1 reference, deviations shaded (needs matplotlib) 374 - ``` 375 - 376 - <details> 377 - <summary>Show the code for this figure</summary> 378 - 379 - ```python 380 - import matplotlib.pyplot as plt 381 - 382 - # One line — measured curve vs the shifted ISO 717-1 reference, deviations shaded: 383 - w.plot() 384 - plt.show() 385 - 386 - # By hand, from the band curve the result now carries: 387 - fig, ax = plt.subplots() 388 - ax.semilogx(w.band_centers, w.measured, "o-", label="Measured R'") 389 - ax.semilogx(w.band_centers, w.shifted_reference, "s--", label="Shifted reference") 390 - ax.fill_between(w.band_centers, w.measured, w.shifted_reference, 391 - where=w.measured < w.shifted_reference, interpolate=True, 392 - alpha=0.3, label="Unfavourable deviations") 393 - ax.set_xlabel("Frequency [Hz]") 394 - ax.set_ylabel("Sound reduction index [dB]") 395 - ax.set_title(f"Rw = {w.rating} dB (C={w.c:+d}; Ctr={w.ctr:+d})") 396 - ax.legend() 397 - plt.show() 398 - ``` 399 - 400 - </details> 401 - 402 - Compute `l1`, `l2` and `t2` on the same 16 one-third-octave bands from 403 - 100 Hz to 3150 Hz — obtain `t2` from 404 - `room_parameters(ir, fs, limits=(100, 3150), fraction=3).t30`, for example — and 405 - pass them to `airborne_insulation`. Feed that function's `dnt` (or `r_prime`) 406 - spectrum to `weighted_rating`, so every band aligns index-by-index with the 407 - ISO 717-1 reference curve. 408 - 409 - ### `airborne_insulation()` parameters 410 - 411 - | Parameter | Type | Units | Range / default | Notes | 412 - | :--- | :--- | :--- | :--- | :--- | 413 - | `l1` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source-room levels (2D is energy-averaged) | 414 - | `l2` | 1D or 2D array | dB | same band count | Receiving-room levels | 415 - | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 416 - | `area` | float, optional | m² | > 0, with `volume` | Partition area `S` (enables `R'`) | 417 - | `volume` | float, optional | m³ | > 0, with `area` | Receiving-room volume `V` | 418 - | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 419 - 420 - ### `weighted_rating()` parameters 421 - 422 - | Parameter | Type | Units | Range / default | Notes | 423 - | :--- | :--- | :--- | :--- | :--- | 424 - | `values_by_band` | 1D array | dB | 16 (thirds) or 5 (octaves) | Measured `R`, `R'`, `DnT` … per band | 425 - | `bands` | str or `None` | — | `'third-octave'` / `'octave'` / `None` | `None` infers from the count | 426 - 427 - `airborne_insulation()` returns an `AirborneInsulationResult` (`d`, `dnt`, 428 - `r_prime` or `None`); `weighted_rating()` returns a `WeightedRatingResult` 429 - (`rating`, `c`, `ctr`, `unfavourable_sum`, all integers except the sum). 430 - 431 - ### Impact sound (ISO 16283-2, ISO 717-2) 432 - 433 - Footstep noise is rated the other way round. Instead of how much a floor 434 - *blocks*, impact insulation measures how much a standardized **tapping 435 - machine** on the floor above puts into the room below — so a *higher* number 436 - is *worse*. The energy-average impact sound pressure level $L_i$ in the 437 - receiving room is normalised like the airborne case, but with a sign flip on 438 - the reverberation term: 439 - 440 - $$ 441 - L'_{nT} = L_i - 10 \log_{10} \frac{T}{T_0}, \qquad 442 - L'_n = L_i + 10 \log_{10} \frac{A}{A_0}, \quad 443 - A_0 = 10\ \text{m}^2,\ A = \frac{0.16\ V}{T}. 444 - $$ 445 - 446 - The **standardized** impact level $L'_{nT}$ ($T_0 = 0.5$ s for dwellings) 447 - needs only the receiving-room $T$, so with $T = 0.5$ s it equals $L_i$; the 448 - **normalized** level $L'_n$ (referenced to a 10 m² absorption area) also needs 449 - the receiving-room volume. Note the **minus** sign — more reverberation 450 - *lowers* $L'_{nT}$, opposite to the airborne $D_{nT}$. 451 - 452 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup.svg" alt="Field impact insulation setup: a standardized tapping machine on the floor of the source room above, microphones energy-averaged in the receiving room below, and the receiving-room reverberation time" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_impact_setup_dark.svg" alt="Field impact insulation setup: a standardized tapping machine on the floor of the source room above, microphones energy-averaged in the receiving room below, and the receiving-room reverberation time" style="width:92%"> 453 - 454 - The single-number rating (ISO 717-2) shifts the same style of reference curve, 455 - but an **unfavourable deviation now occurs where the measurement *exceeds* the 456 - reference** (impact noise is worse when higher) — the sign opposite to 457 - ISO 717-1. The rating (`Ln,w`, `L'n,w`, `L'nT,w`) is the shifted reference read 458 - at 500 Hz; for octave bands it is then reduced by 5 dB. The spectrum 459 - adaptation term $C_I = L_{n,\text{sum}} - 15 - L_{n,w}$ uses the energetic sum 460 - over 100–2500 Hz (16-band thirds excluding 3150 Hz) or 125–2000 Hz (octaves). 461 - 462 - <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating.png" alt="Measured one-third-octave normalized impact sound pressure level with the shifted ISO 717-2 reference curve and the resulting weighted rating read at 500 Hz" style="width:80%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/impact_rating_dark.png" alt="Measured one-third-octave normalized impact sound pressure level with the shifted ISO 717-2 reference curve and the resulting weighted rating read at 500 Hz" style="width:80%"> 463 - 464 - ```python 465 - import numpy as np 466 - from phonometry import impact_insulation, weighted_impact_rating 467 - 468 - # 16 one-third-octave impact levels Li (100 Hz - 3150 Hz), dB, from the 469 - # ISO 717-2 Annex C worked example, and the receiving-room T per band. 470 - li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 471 - 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 472 - t2 = np.full(16, 0.5) 473 - 474 - imp = impact_insulation(li, t2, volume=50.0) 475 - print(round(float(imp.l_n_t[0]), 1)) # 62.1 (= Li since T = T0) 476 - print(round(float(imp.l_n[0]), 1)) # 64.1 normalized to A0 = 10 m^2 477 - 478 - # Weighted impact rating + spectrum adaptation term CI (ISO 717-2) 479 - res_imp = weighted_impact_rating(imp.l_n_t) 480 - print(res_imp.rating, res_imp.ci, res_imp.unfavourable_sum) # 79 -11 28.0 -> L'nT,w(CI)=79(-11) 481 - 482 - # Octave-band data carry the extra -5 dB reduction (Clause 4.3.2) 483 - octave = np.array([65.3, 64.5, 58.0, 55.8, 43.0]) 484 - print(weighted_impact_rating(octave).rating) # 54 485 - 486 - res_imp.plot() # measured L'nT vs shifted ISO 717-2 reference, measured-above shaded (needs matplotlib) 487 - ``` 488 - 489 - <details> 490 - <summary>Show the code for this figure</summary> 491 - 492 - ```python 493 - import matplotlib.pyplot as plt 494 - 495 - # One line — measured L'nT vs the shifted ISO 717-2 reference (measured-above shaded): 496 - res_imp.plot() 497 - plt.show() 498 - 499 - # By hand, from the band curve the result now carries (note the opposite sign: 500 - # an unfavourable deviation is where the MEASURED level exceeds the reference). 501 - # Here the input was l_n_t, so the rated quantity is the field level L'nT,w: 502 - fig, ax = plt.subplots() 503 - ax.semilogx(res_imp.band_centers, res_imp.measured, "o-", label="Measured L'nT") 504 - ax.semilogx(res_imp.band_centers, res_imp.shifted_reference, "s--", label="Shifted reference") 505 - ax.fill_between(res_imp.band_centers, res_imp.shifted_reference, res_imp.measured, 506 - where=res_imp.measured > res_imp.shifted_reference, interpolate=True, 507 - alpha=0.3, label="Unfavourable deviations") 508 - ax.set_xlabel("Frequency [Hz]") 509 - ax.set_ylabel("Impact sound pressure level [dB]") 510 - ax.set_title(f"L'nT,w = {res_imp.rating} dB (CI={res_imp.ci:+d})") 511 - ax.legend() 512 - plt.show() 513 - ``` 514 - 515 - </details> 516 - 517 - Feed `impact_insulation`'s `l_n_t` (or `l_n`) straight into 518 - `weighted_impact_rating`; the rating and `CI` reproduce the ISO 717-2 Annex C 519 - values (thirds `L'nT,w = 79`, `CI = −11`; octave `54`, `CI = 0`). 520 - 521 - #### `impact_insulation()` parameters 522 - 523 - | Parameter | Type | Units | Range / default | Notes | 524 - | :--- | :--- | :--- | :--- | :--- | 525 - | `li` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Energy-average impact SPL (2D is averaged over positions) | 526 - | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 527 - | `volume` | float, optional | m³ | > 0 | Receiving-room `V` (enables `L'n`) | 528 - | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 529 - 530 - #### `weighted_impact_rating()` parameters 531 - 532 - | Parameter | Type | Units | Range / default | Notes | 533 - | :--- | :--- | :--- | :--- | :--- | 534 - | `values_by_band` | 1D array | dB | 16 (thirds) or 5 (octaves) | Measured `Ln`, `L'n` or `L'nT` per band | 535 - | `bands` | str or `None` | — | `'third-octave'` / `'octave'` / `None` | `None` infers from the count | 536 - 537 - `impact_insulation()` returns an `ImpactInsulationResult` (`l_n_t`, `l_n` or 538 - `None`); `weighted_impact_rating()` returns an `ImpactRatingResult` (`rating`, 539 - `ci` integers, `unfavourable_sum` in dB). 540 - 541 - ### Field façade insulation (ISO 16283-3) 542 - 543 - The same source/receiver logic reaches the building **façade**, but now the 544 - source is *outdoors* — a loudspeaker at 45° or the road traffic itself. Rather 545 - than a level difference across an internal partition, ISO 16283-3 references the 546 - receiving-room level $L_2$ to the level **2 m in front of the façade** 547 - $L_{1,2m}$, giving the level difference $D_{2m}$ and, exactly as in the airborne 548 - case, its standardized and normalized forms: 549 - 550 - $$ 551 - D_{2m} = L_{1,2m} - L_2, \quad 552 - D_{2m,nT} = D_{2m} + 10 \log_{10}\frac{T}{T_0}, \quad 553 - D_{2m,n} = D_{2m} - 10 \log_{10}\frac{A}{A_0}, 554 - $$ 555 - 556 - with $T_0 = 0.5$ s, $A_0 = 10$ m² and $A = 0.16\ V/T$ (dwellings). When the 557 - microphone sits **on the test element** (surface level $L_{1,s}$) the *element* 558 - method also yields an apparent sound reduction index, carrying a fixed 559 - angle-of-incidence correction — $-1.5$ dB for the 45° loudspeaker method, 560 - $-3$ dB for the all-angle road-traffic method: 561 - 562 - $$ 563 - R'_{45°} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 1.5, \qquad 564 - R'_{tr,s} = L_{1,s} - L_2 + 10 \log_{10}\frac{S}{A} - 3. 565 - $$ 566 - 567 - The façade quantity is airborne, so its single-number rating uses the 568 - **ISO 717-1** reference curve through `weighted_rating` unchanged (Annex F). 569 - 570 - ```python 571 - import numpy as np 572 - from phonometry import facade_insulation, weighted_rating 573 - 574 - # Outdoor level 2 m in front of the façade, receiving-room level and T per 575 - # one-third-octave band; surface_level is the microphone on the test element. 576 - l1_2m = np.full(16, 75.0) # L1,2m outdoors 577 - l2 = np.full(16, 33.0) # receiving-room L2 578 - t2 = np.full(16, 0.5) # receiving-room T (s) 579 - 580 - fac = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 581 - surface_level=np.full(16, 78.0), method="loudspeaker") 582 - print(round(float(fac.d_2m[0]), 1)) # 42.0 D2m = L1,2m - L2 583 - print(round(float(fac.d_2m_nt[0]), 1)) # 42.0 (= D2m since T = T0) 584 - print(round(float(fac.d_2m_n[0]), 1)) # 40.0 normalized to A0 = 10 m^2 585 - print(round(float(fac.r_prime[0]), 1)) # 42.1 R'45deg (loudspeaker, -1.5 dB) 586 - 587 - # The road-traffic element method carries the -3 dB all-angle correction instead 588 - tr = facade_insulation(l1_2m, l2, t2, volume=50.0, area=11.5, 589 - surface_level=np.full(16, 78.0), method="road_traffic") 590 - print(round(float(tr.r_prime[0]), 1)) # 40.6 R'tr,s (traffic, -3 dB) 591 - 592 - # The façade quantity is airborne: rate D2m,nT with the ISO 717-1 engine 593 - print(weighted_rating(fac.d_2m_nt).rating) # 42 Dls,2m,nT,w 594 - 595 - fac.plot() # per-band D2m,nT with D2m, D2m,n and R' overlaid (needs matplotlib) 596 - ``` 597 - 598 - `surface_level`, `area` and `volume` are all optional: with only `l1_2m`, `l2` 599 - and `t2` the function returns `d_2m` and `d_2m_nt`; add `volume` for `d_2m_n`; 600 - add `surface_level` **and** `area` **and** `volume` for `r_prime`. Positions are 601 - energy-averaged with the surface-level formula (Clause 9.5.1); band levels are 602 - assumed already corrected for background noise. 603 - 604 - #### `facade_insulation()` parameters 605 - 606 - | Parameter | Type | Units | Range / default | Notes | 607 - | :--- | :--- | :--- | :--- | :--- | 608 - | `l1_2m` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Level 2 m in front of the façade `L1,2m` | 609 - | `l2` | 1D or 2D array | dB | same band count | Receiving-room levels | 610 - | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 611 - | `area` | float, optional | m² | > 0, with `surface_level`, `volume` | Test-element area `S` (enables `R'`) | 612 - | `volume` | float, optional | m³ | > 0 | Receiving-room `V` (enables `D2m,n`; required for `R'`) | 613 - | `surface_level` | 1D/2D array, optional | dB | same band count | Surface level `L1,s` on the element (enables `R'`) | 614 - | `method` | str | — | `'loudspeaker'` (−1.5 dB) / `'road_traffic'` (−3 dB) | Angle-of-incidence correction of `R'` | 615 - | `t0` | float | s | default `0.5` | Reference reverberation time `T0` | 616 - | `frequencies` | 1D array, optional | Hz | — | Band centres carried on the result for plotting | 617 - 618 - `facade_insulation()` returns a `FacadeInsulationResult` (`d_2m`, `d_2m_nt`, 619 - `d_2m_n` or `None`, `r_prime` or `None`, `frequencies`); feed any 16-band façade 620 - quantity to `weighted_rating` for its ISO 717-1 single number. 621 - 622 - ## 5. Laboratory measurement (ISO 10140) 623 - 624 - Everything above is a **field** measurement (the primed quantities $R'$, $L'_n$): 625 - the number a real building achieves, flanking transmission and all. To rate an 626 - element on its own — a wall type, a floating floor, a window — you take it to a 627 - qualified **laboratory** (ISO 10140), where suppressed flanking makes the 628 - *direct* transmission the whole story. The formulas lose their primes: the 629 - **sound reduction index** $R$ (not $R'$) and the **normalized impact level** 630 - $L_n$ (not $L'_n$), with the receiving room's absorption area $A = 0.16\ V/T$ 631 - now a known property of the facility: 632 - 633 - $$ 634 - R = L_1 - L_2 + 10 \log_{10}\frac{S}{A}, \qquad 635 - L_n = L_i + 10 \log_{10}\frac{A}{A_0}, \quad A_0 = 10\ \text{m}^2. 636 - $$ 637 - 638 - | | Field (ISO 16283) | Laboratory (ISO 10140) | 639 - | :--- | :--- | :--- | 640 - | Airborne | $R'$ apparent (with flanking) | $R$ direct (flanking suppressed) | 641 - | Impact | $L'_n$ apparent | $L_n$ direct | 642 - | Absorption area | measured in the room | property of the facility | 643 - 644 - The single-number ratings reuse the very same ISO 717-1/2 engines 645 - (`weighted_rating`, `weighted_impact_rating`) — an $R$ spectrum rates to $R_w$ 646 - exactly as an $R'$ spectrum rated to $R'_w$. Before forming the index the 647 - receiving-room levels must be **corrected for background noise** (Clause 4.3): 648 - the energy subtraction $10 \log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ applies for a 649 - 6–15 dB signal-to-background margin, a fixed 1.3 dB correction (the *limit of 650 - measurement*) at or below 6 dB, and no correction at or above 15 dB. 651 - 652 - ```python 653 - import numpy as np 654 - from phonometry import (lab_airborne_insulation, lab_impact_insulation, 655 - background_correction) 656 - 657 - # Source/receiving levels and receiving-room T over the 16 one-third-octave 658 - # bands; S is the free test-opening area, V the receiving-room volume. 659 - l1 = np.full(16, 80.0) 660 - l2 = np.full(16, 40.0) 661 - t2 = np.full(16, 0.5) 662 - lab = lab_airborne_insulation(l1, l2, t2, area=10.0, volume=50.0) 663 - print(round(float(lab.r[0]), 1)) # 38.0 R = L1 - L2 + 10 lg(S/A) 664 - print(round(float(lab.absorption[0]), 1)) # 16.0 A = 0.16 V / T (m^2) 665 - print(lab.rating.rating, lab.rating.c, lab.rating.ctr) # 38 0 0 -> Rw(C;Ctr) 666 - 667 - # Impact: the tapping-machine level Li normalized to A0 = 10 m^2 gives Ln 668 - li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1, 669 - 73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2]) 670 - imp = lab_impact_insulation(li, t2, volume=50.0) 671 - print(round(float(imp.l_n[0]), 1)) # 64.1 Ln = Li + 10 lg(A/A0) 672 - print(imp.rating.rating, imp.rating.ci) # 81 -11 -> Ln,w(CI) 673 - 674 - # Background correction: margins 6 / 1 / 20 dB -> capped / capped / unchanged 675 - corrected = background_correction([30.0, 33.0, 50.0], [24.0, 32.0, 30.0]) 676 - print(np.round(corrected, 1)) # [28.7 31.7 50.0] (1.3 dB cap twice) 677 - 678 - lab.rating.plot() # measured R vs shifted ISO 717-1 reference (needs matplotlib) 679 - ``` 680 - 681 - A margin at or below 6 dB emits a `LabInsulationWarning` and flags the band as 682 - the limit of measurement; catch it with `warnings.simplefilter("error", 683 - LabInsulationWarning)`. The automatic rating is formed only when exactly 16 684 - one-third-octave or 5 octave values are supplied (`rating` is `None` otherwise). 685 - 686 - ### `lab_airborne_insulation()` / `lab_impact_insulation()` parameters 687 - 688 - | Parameter | Type | Units | Range / default | Notes | 689 - | :--- | :--- | :--- | :--- | :--- | 690 - | `l1` / `l2` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source / receiving levels (airborne) | 691 - | `li` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Impact SPL from the tapping machine (impact) | 692 - | `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time | 693 - | `area` | float | m² | > 0 | Free test-opening area `S` (airborne only) | 694 - | `volume` | float | m³ | > 0 | Receiving-room volume `V` | 695 - 696 - `lab_airborne_insulation()` returns a `LabAirborneInsulationResult` (`r`, 697 - `absorption`, `rating`); `lab_impact_insulation()` a 698 - `LabImpactInsulationResult` (`l_n`, `absorption`, `rating`); 699 - `background_correction(signal_and_background, background)` returns the corrected 700 - levels directly. 701 - 702 - ## 6. Predicting performance (EN 12354) 703 - 704 - A laboratory rating describes an element in isolation, yet the sound a building 705 - actually transmits also travels *around* the partition — along the floor, up the 706 - façade, through the flanking walls — re-radiating into the receiving room. This 707 - **flanking transmission** is the whole difference between the laboratory $R$ and 708 - the field $R'$. EN 12354 predicts the in-situ apparent rating from the 709 - laboratory ratings of the elements plus the vibration transmission of their 710 - junctions. 711 - 712 - <picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_flanking_paths.svg" alt="The direct path Dd through the separating element and the three flanking paths Ff, Df and Fd across each junction between a flanking element and the separating element" style="width:92%"></picture> 713 - 714 - Each junction between a flanking element and the separating element carries 715 - three paths — $Ff$ (flanking→flanking), $Df$ (direct→flanking) and $Fd$ 716 - (flanking→direct) — alongside the single direct path $Dd$. The **simplified 717 - single-number model** combines them energetically (Formula 26): 718 - 719 - $$ 720 - R'_w = -10 \log_{10}\Big[ 10^{-R_{Dd,w}/10} 721 - + \sum 10^{-R_{Ff,w}/10} + \sum 10^{-R_{Df,w}/10} 722 - + \sum 10^{-R_{Fd,w}/10} \Big], 723 - $$ 724 - 725 - with the direct path $R_{Dd,w} = R_{s,w} + \Delta R_{Dd,w}$ (Formula 27) and each 726 - flanking path (Formula 28a) 727 - 728 - $$ 729 - R_{ij,w} = \tfrac{R_{i,w} + R_{j,w}}{2} + \Delta R_{ij,w} + K_{ij} 730 - + 10 \log_{10}\frac{S_s}{l_0\ l_f}, 731 - $$ 732 - 733 - where $l_0 = 1$ m is the reference coupling length, $l_f$ the junction coupling 734 - length and $K_{ij}$ the junction's **vibration reduction index** (Annex E, 735 - empirical in the mass ratio $M = \log_{10}(m'_{\perp,i}/m'_i)$). 736 - 737 - <picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo_dark.png"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/prediction_flanking_demo.png" alt="Per-path sound reduction indices for the EN 12354-1 Annex H.3 example and each path's share of the transmitted energy, showing the direct path dominating at R'w = 52 dB" style="width:80%"></picture> 738 - 739 - ```python 740 - import numpy as np 741 - from phonometry import (junction_vibration_reduction, flanking_element, 742 - predicted_airborne_insulation) 743 - 744 - # EN 12354-1 Annex H.3: a separating wall Rs,w = 57 dB, area Ss = 11.5 m², with 745 - # four flanking elements. The simplified model reads each junction's Kij at 746 - # 500 Hz from the mass ratio m'perp / m' (Annex E) — here the floor's rigid 747 - # cross-junction (the mass ratio is itself rounded, hence 12.5 vs Annex 12.4): 748 - print(round(junction_vibration_reduction("rigid_cross", "through", 1.61), 1)) # 12.5 KFf 749 - print(round(junction_vibration_reduction("rigid_cross", "corner", 1.61), 1)) # 8.9 KFd = KDf 750 - 751 - # Build each element's three flanking paths (Ff, Df, Fd) from the Annex H 752 - # tabulated Kij, then combine the direct path Dd energetically (Formula 26). 753 - elements = [ # (name, Rw, KFf, KFd = KDf, coupling length lf) 754 - ("floor", 49, 12.4, 8.9, 4.50), 755 - ("ceiling", 46, 14.4, 9.2, 4.50), 756 - ("facade", 42, 12.6, 6.7, 2.55), 757 - ("int-wall", 33, 33.5, 15.7, 2.55), 758 - ] 759 - paths = [] 760 - for name, rw, k_ff, k_fd, lf in elements: 761 - paths += flanking_element(label=name, r_flanking=rw, r_separating=57, 762 - k_ff=k_ff, k_fd=k_fd, k_df=k_fd, 763 - separating_area=11.5, coupling_length=lf) 764 - 765 - res = predicted_airborne_insulation(r_direct=57.0, flanking_paths=paths) 766 - print(round(res.r_prime_w, 1)) # 52.2 -> R'w = 52 dB 767 - print(res.dominant.label, round(res.dominant.fraction, 2)) # Dd 0.33 (direct dominates) 768 - ``` 769 - 770 - Every added flanking path strictly lowers $R'_w$ below the direct $R_{Dd,w} = 57$; 771 - `res.paths` exposes each path's share of the transmitted energy so the dominant 772 - path is visible. Clause 4.4.2 also enforces a floor $K_{ij} \ge K_{ij,\min}$ from 773 - the junction geometry — compute it with `junction_min_vibration_reduction` and 774 - pass it to `flanking_path(..., kij_min=...)`, which raises a below-floor $K_{ij}$ 775 - to the minimum: 776 - 777 - ```python 778 - from phonometry import junction_min_vibration_reduction 779 - # Kij,min = 10 lg[lf·l0·(1/Si + 1/Sj)]; large elements give a low (here negative) 780 - # floor, so a realistic tabulated Kij is rarely clamped. 781 - print(round(junction_min_vibration_reduction(coupling_length=4.5, 782 - s_i=11.5, s_j=11.5), 1)) # -1.1 783 - ``` 784 - 785 - The impact counterpart (EN 12354-2, Formula 21) is a direct subtraction: 786 - $L'_{n,w} = L_{n,w,eq} - \Delta L_w + K$, with the bare-floor equivalent level 787 - $L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Annex B), the covering improvement 788 - $\Delta L_w$ (ISO 717-2) and the flanking correction $K$ from Table 1. 789 - 790 - ```python 791 - from phonometry import (equivalent_impact_level, impact_flanking_correction, 792 - predicted_impact_insulation, standardized_impact_level) 793 - 794 - # EN 12354-2 Annex E.3: a 0.14 m concrete floor (m' = 322 kg/m²) with a floating 795 - # floor (ΔLw = 33 dB), rooms one above the other, mean flanking mass 145 kg/m². 796 - ln_eq = equivalent_impact_level(322.0) # 164 - 35 lg(m') 797 - k = impact_flanking_correction(322.0, 145.0) # Table 1 (sep 322, flk 145) 798 - imp = predicted_impact_insulation(ln_w_eq=ln_eq, delta_l_w=33.0, k_correction=k) 799 - print(round(ln_eq, 1), k, round(imp.l_prime_n_w, 1)) # 76.2 2 45.2 -> L'n,w = 45 dB 800 - print(round(standardized_impact_level(imp.l_prime_n_w, 50.0), 1)) # 43.0 L'nT,w 801 - ``` 802 - 803 - <details> 804 - <summary>Show the code for this figure</summary> 805 - 806 - ```python 807 - import matplotlib.pyplot as plt 808 - 809 - # Per-path sound reduction index and each path's share of the transmitted 810 - # energy for the Annex H.3 result computed above. 811 - labels = [p.label for p in res.paths] 812 - r_w = [p.r_w for p in res.paths] 813 - frac = [100.0 * p.fraction for p in res.paths] 814 - 815 - fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True) 816 - ax1.bar(labels, r_w, color="tab:blue") 817 - ax1.axhline(res.r_prime_w, ls="--", color="k", label=f"R'w = {res.r_prime_w:.1f} dB") 818 - ax1.set_ylabel("Path Rij,w [dB]"); ax1.legend() 819 - ax2.bar(labels, frac, color="tab:orange") 820 - ax2.set_ylabel("Energy share [%]"); ax2.set_xlabel("Transmission path") 821 - for ax in (ax1, ax2): 822 - ax.tick_params(axis="x", rotation=45) 823 - fig.suptitle("EN 12354-1 Annex H.3 — flanking transmission") 824 - fig.tight_layout() 825 - plt.show() 826 - ``` 827 - 828 - </details> 829 - 830 - ### `junction_vibration_reduction()` / `flanking_element()` parameters 831 - 832 - | Parameter | Type | Units | Range / default | Notes | 833 - | :--- | :--- | :--- | :--- | :--- | 834 - | `junction_type` | str | — | `'rigid_cross'` / `'rigid_t'` / `'flexible_t'` / `'lightweight_facade'` | Junction geometry (Annex E) | 835 - | `path` | str | — | `'through'` (K13) / `'corner'` (K12 = K23) | Path branch | 836 - | `mass_ratio` | float | — | > 0 | `m'⊥,i / m'i` (Formula E.2) | 837 - | `frequency` | float | Hz | default `500` | Only `flexible_t` is frequency-dependent | 838 - | `r_flanking` / `r_separating` | float | dB | — | Weighted indices of the flanking / separating element | 839 - | `k_ff` / `k_fd` / `k_df` | float | dB | — | Junction `Kij` for the three paths | 840 - | `separating_area` | float | m² | > 0 | Separating-element area `Ss` | 841 - | `coupling_length` | float | m | > 0 | Junction coupling length `lf` | 842 - | `delta_r_ff` / `delta_r_fd` / `delta_r_df` | float | dB | default `0` | Lining improvements per path | 843 - 844 - `predicted_airborne_insulation()` returns an `AirbornePredictionResult` 845 - (`r_prime_w`, `r_direct_w`, `paths` of `PathContribution`, `dominant`); 846 - `predicted_impact_insulation()` an `ImpactPredictionResult` (`l_prime_n_w`, 847 - `ln_w_eq`, `delta_l_w`, `k_correction`). The simplified model carries a reported 848 - standard deviation of about 2 dB (Clause 5). 849 - 850 - ## 7. Measurement uncertainty (ISO 12999-1) 851 - 852 - A rating without an uncertainty is only half a result. ISO 12999-1 does not 853 - re-measure anything; it tabulates the **standard uncertainty** $u$ of every 854 - sound-insulation quantity — derived from inter-laboratory tests — and prescribes 855 - how to expand and combine it. Which standard deviation is $u$ depends on the 856 - **measurement situation** (Clause 5.2): 857 - 858 - | Situation | Meaning | Standard uncertainty $u$ | 859 - | :--- | :--- | :--- | 860 - | **A** | laboratory characterisation (ISO 10140) | reproducibility $\sigma_R$ | 861 - | **B** | same location, different teams | in-situ $\sigma_{situ}$ | 862 - | **C** | same location, same operator repeated | repeatability $\sigma_r$ | 863 - 864 - The expanded uncertainty is $U = k\ u$ (Formula 2) with the coverage factor $k$ 865 - of Table 8. A two-sided interval $Y = y \pm U$ (Formula 3, $k = 1.96$ at 95 %) 866 - *reports* a value; the **one-sided** factor ($k = 1.65$ at 95 %) *declares 867 - conformity* with a requirement (Formulae 4/5). 868 - 869 - <picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo_dark.png"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insulation_uncertainty_demo.png" alt="A weighted rating reported with its two-sided 95 % expanded uncertainty in situations A, B and C, the reproducibility uncertainty widest and the repeatability uncertainty narrowest" style="width:80%"></picture> 870 - 871 - ```python 872 - from phonometry import (band_uncertainty, single_number_uncertainty, 873 - uncertain_value, satisfies_lower_requirement) 874 - 875 - # Situation B (same building, different teams) -> the in-situ standard deviation. 876 - print(single_number_uncertainty("r_w", "B")) # 0.9 dB (Table 3) 877 - u = band_uncertainty("airborne", "B") # per-band u (Table 2) 878 - print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (the 500 Hz band) 879 - 880 - # Report R'w = 52 dB with a two-sided 95 % interval (k = 1.96, Table 8): 881 - uv = uncertain_value(52.0, "rprime_w", "B") # aliases resolve to r_w 882 - print(uv.coverage_factor, round(uv.expanded_uncertainty, 1)) # 1.96 1.8 883 - print(round(uv.lower, 1), round(uv.upper, 1)) # 50.2 53.8 -> 52 ± 1.8 dB 884 - 885 - # Declaring conformity uses the ONE-sided factor (k = 1.65): does R'w provably 886 - # clear a 50 dB requirement? 887 - uc = uncertain_value(52.0, "rprime_w", "B", one_sided=True) 888 - print(satisfies_lower_requirement(52.0, uc.expanded_uncertainty, 50.0)) # True 889 - ``` 890 - 891 - Impact quantities offer situations B/C only (Table 4, no 500 Hz band in the 2020 892 - edition), and $\Delta L$ only situation A. Descriptors are case-insensitive with 893 - aliases (`rprime_w`/`dnt_w`→`r_w`, `lprime_n_w`→`ln_w`); combine independent 894 - components in quadrature with `combine_uncertainties`, and reduce by $m$ 895 - independent measurements with `reduce_by_independent_measurements` ($u/\sqrt{m}$). 896 - 897 - <details> 898 - <summary>Show the code for this figure</summary> 899 - 900 - ```python 901 - import matplotlib.pyplot as plt 902 - from phonometry import uncertain_value 903 - 904 - # The same R'w = 52 dB reported in each situation with its two-sided 95 % U. 905 - situations = ["A", "B", "C"] 906 - vals = [uncertain_value(52.0, "r_w", s) for s in situations] 907 - 908 - fig, ax = plt.subplots(figsize=(7, 4)) 909 - ax.errorbar(situations, [v.value for v in vals], 910 - yerr=[v.expanded_uncertainty for v in vals], 911 - fmt="o", capsize=8, color="tab:blue") 912 - for s, v in zip(situations, vals): 913 - ax.annotate(f"±{v.expanded_uncertainty:.1f}", (s, v.upper), 914 - textcoords="offset points", xytext=(8, 4)) 915 - ax.set_ylabel("R'w [dB]"); ax.set_xlabel("Measurement situation") 916 - ax.set_title("R'w = 52 dB with 95 % expanded uncertainty (ISO 12999-1)") 917 - fig.tight_layout() 918 - plt.show() 919 - ``` 920 - 921 - </details> 922 - 923 - ### `band_uncertainty()` / `single_number_uncertainty()` / `uncertain_value()` parameters 924 - 925 - | Parameter | Type | Units | Range / default | Notes | 926 - | :--- | :--- | :--- | :--- | :--- | 927 - | `measurand` | str | — | `'airborne'` / `'impact'` / `'impact_reduction'` | Selects Table 2 / 4 / 6 | 928 - | `quantity` | str | — | `'r_w'`, `'ln_w'`, `'delta_lw'` (+ aliases, `+c`/`+ctr` variants) | Single-number descriptor | 929 - | `situation` | str | — | `'A'` / `'B'` / `'C'` | Measurement situation (Clause 5.2) | 930 - | `value` | float | dB | — | Best estimate `y` to attach `U` to | 931 - | `coverage` | float | — | default `0.95` | Confidence level (Table 8) | 932 - | `one_sided` | bool | — | default `False` | One-sided factor for conformity checks | 933 - | `upper_limit` | bool | — | default `False` | Select the σR95 upper limit (airborne, situation A) | 934 - 935 - `band_uncertainty()` returns a `BandUncertainty` (`frequencies`, 936 - `uncertainties`, `.to_arrays()`); `single_number_uncertainty()` a float; 937 - `uncertain_value()` an `UncertainValue` (`value`, `standard_uncertainty`, 938 - `coverage_factor`, `expanded_uncertainty`, `.lower`, `.upper`). The read-only 939 - `COVERAGE_FACTORS` mapping exposes Table 8 keyed by `(confidence, one_sided)`. 940 - 941 - ## 8. Sound absorption (ISO 354) 316 + ## 4. Sound absorption (ISO 354) 942 317 943 318 The equivalent absorption area `A` that drives `R'`, `L'n`, the ISO 3744 `K2` 944 319 environmental correction and the ISO 3741 absorption term is itself measured in ··· 999 374 1000 375 ## See also 1001 376 377 + - [Building Acoustics & Sound Insulation](/phonometry/guides/building-acoustics/) — field, 378 + laboratory and predicted sound insulation between spaces, and its measurement uncertainty. 1002 379 - [Sound Power](/phonometry/guides/sound-power/) — the `LW` methods that consume the 1003 380 ISO 354 absorption area (the ISO 3744 `K2` and the ISO 3741 absorption term). 1004 381 - [Psychoacoustics and Speech Intelligibility](/phonometry/guides/psychoacoustics/) — STI/STIPA
+226 -8
site/src/content/docs/guides/sound-power.md
··· 1 1 --- 2 2 title: "Sound Power" 3 - description: "Sound power level LW by three routes: enveloping-surface sound pressure (ISO 3744/3746), the reverberation-room precision method with Waterhouse and C1/C2 corrections (ISO 3741), and intensity scanning with field indicators and achieved grade (ISO 9614-2)." 3 + description: "Sound power level LW by five routes: enveloping-surface sound pressure (ISO 3744/3746), the reverberation-room precision method with Waterhouse and C1/C2 corrections (ISO 3741), intensity scanning with field indicators and achieved grade (ISO 9614-2), the precision anechoic-room method (ISO 3745) and precision intensity scanning (ISO 9614-3)." 4 4 --- 5 5 6 6 Sound *pressure* depends on where you stand and on the room you stand in; ··· 8 8 energy per second a source radiates, referenced to `P0 = 1 pW`, and it is 9 9 the device-independent **emission** descriptor that goes on a datasheet, 10 10 feeds a room prediction (ISO 12354) or is checked against a noise-emission 11 - limit. This page covers the three routes phonometry implements to obtain it 11 + limit. This page covers the routes phonometry implements to obtain it 12 12 and when to reach for each: an enveloping *pressure* surface in the field 13 13 (ISO 3744/3746), the diffuse field of a *reverberation room* (ISO 3741), 14 - and *intensity* scanning over a surface (ISO 9614-2). 14 + *intensity* scanning over a surface (ISO 9614-2), and — for the highest 15 + accuracy — the precision grades in an *anechoic room* (ISO 3745) and by 16 + precision *intensity* scanning (ISO 9614-3). 15 17 16 18 ## Choosing a method 17 19 18 - All three deliver the same quantity — a per-band `LW` and an A-weighted 19 - total `LWA` — but under different environments, accuracy grades and 20 - practical constraints. 20 + All deliver the same quantity — a per-band `LW` and an A-weighted total 21 + `LWA` — but under different environments, accuracy grades and practical 22 + constraints. 21 23 22 24 | Method | Standard | Measured quantity | Environment | Accuracy grade | Use when | 23 25 | :--- | :--- | :--- | :--- | :--- | :--- | 24 26 | Enveloping surface | **ISO 3744** (engineering) / **ISO 3746** (survey) | Sound pressure on a hemisphere or box | Essentially free field over one or more reflecting planes | Grade 2 (`σR0 ≈ 1.5 dB`) / grade 3 (`≈ 3.0 dB`) | In situ or a large room; no special test facility available | 25 27 | Reverberation room | **ISO 3741** | Sound pressure in the diffuse field | Qualified hard-walled reverberation room | Grade 1 (precision) | Highest accuracy for steady, broadband sources in a lab | 26 28 | Intensity scanning | **ISO 9614-2** | Normal sound intensity scanned over a surface | Almost any, tolerant of steady extraneous noise | Grade 2 / 3 (from per-band field indicators) | On-site with background noise, or one machine among many | 29 + | Anechoic room | **ISO 3745** | Sound pressure on a fixed microphone array | Qualified anechoic or hemi-anechoic room | Grade 1 (precision) | Reference-grade emission in a free-field laboratory | 30 + | Precision intensity scanning | **ISO 9614-3** | Scanned normal intensity, tighter criteria | Almost any, tolerant of steady extraneous noise | Grade 1 (precision) | Precision on-site, with the ISO 9614-3 field-indicator checks | 27 31 28 32 The pressure methods correct the surface level for the room (`K2`) and for 29 33 background noise (`K1`); the reverberation method needs a *qualified* room ··· 328 332 `dynamic_capability_index` (`Ld`), `achieved_grade`, `surface_area`, 329 333 `sound_power_level_a` and `grade`. 330 334 335 + ## 4. Precision grade, anechoic room (ISO 3745) 336 + 337 + When the highest accuracy is required, ISO 3745 measures sound power in a 338 + qualified **anechoic** or **hemi-anechoic** room, where the free field lets a 339 + fixed array of microphones sample the radiated sound pressure directly. It is the 340 + grade-1 counterpart to the enveloping-surface method of Section 1, with 341 + standardized microphone coordinates, a per-position background correction and an 342 + explicit meteorological correction. 343 + 344 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_precision_anechoic.svg" alt="ISO 3745 precision sound power in an anechoic room: wedge-lined walls, the device under test at the centre and a hemispherical array of microphones at a fixed radius, with the sound power level formed from the surface-averaged pressure plus the area, background and meteorological corrections" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_precision_anechoic_dark.svg" alt="ISO 3745 precision sound power in an anechoic room: wedge-lined walls, the device under test at the centre and a hemispherical array of microphones at a fixed radius, with the sound power level formed from the surface-averaged pressure plus the area, background and meteorological corrections" style="width:92%"> 345 + 346 + **Sound power level (Clause 8).** The band sound power level is the 347 + surface-averaged pressure level plus the surface term and the corrections: 348 + 349 + $$ 350 + L_W = \overline{L_p} + 10\lg\frac{S}{S_0} + C_1 + C_2 + C_3, 351 + $$ 352 + 353 + with $S = 4\pi r^2$ over the sphere or $S = 2\pi r^2$ over the hemisphere, 354 + $S_0 = 1\ \text{m}^2$. $C_1$ and $C_2$ are the meteorological corrections 355 + (reference and radiation-impedance terms); $C_3$ accounts for air absorption over 356 + the measurement radius. The microphone positions are the standardized 357 + unit-vector arrays of Tables D.1 (sphere), E.1 (hemisphere) and E.2 (hemisphere, 358 + broadband). 359 + 360 + ```python 361 + import numpy as np 362 + import phonometry as ph 363 + 364 + # The 40 standardized hemisphere positions (unit vectors scaled by the radius). 365 + pos = ph.precision_positions("hemisphere", radius=1.0, count=40) 366 + print(pos.shape) # (40, 3) 367 + 368 + # Octave/third-octave band SPL (dB) at each of the 40 positions; here a uniform 369 + # 74 dB in one band. The result carries S = 2*pi*r^2 and LW with C1+C2+C3. 370 + levels = np.full((40, 1), 74.0) 371 + res = ph.sound_power_anechoic(levels, "hemisphere", radius=1.0) 372 + print(round(res.surface_area, 3)) # 6.283 (2*pi*1^2) 373 + print(np.round(res.sound_power_level, 2)) # [81.85] 374 + ``` 375 + 376 + **Background and meteorological corrections.** The $K_1$ background correction is 377 + applied **per position** and floored where the signal-to-background difference is 378 + small (Eq. 11); the meteorological correction is evaluated from the measured 379 + temperature and static pressure. 380 + 381 + ```python 382 + import numpy as np 383 + import phonometry as ph 384 + 385 + # K1 for a 6 dB signal-to-background difference in a <=200 Hz edge band: the 386 + # floor is 1.26 dB (Eq. 11). Source and background levels are [positions, bands]. 387 + k1 = ph.precision_background_correction( 388 + np.array([[56.0]]), np.array([[50.0]]), np.array([200.0])) 389 + print(round(float(k1[0, 0]), 4)) # 1.2563 390 + 391 + # Meteorological corrections at the 23 C, 101.325 kPa reference (Eq. 16): 392 + mc = ph.meteorological_corrections(23.0, 101.325) 393 + print(round(mc.c1, 4), round(mc.c2, 4)) # -0.1282 0.0 394 + 395 + # Expanded uncertainty (Clause 10.5 EXAMPLE): sigma_R0 = 0.5, sigma_omc = 2.0, 396 + # k = 2 -> U = 4.1 dB. 397 + print(round(ph.precision_uncertainty(0.5, 2.0, 2.0), 3)) # 4.123 398 + ``` 399 + 400 + Over several bands `sound_power_anechoic` returns a plottable 401 + `PrecisionSoundPowerResult` carrying the per-band `LW` and the A-weighted total: 402 + 403 + ```python 404 + import numpy as np 405 + import phonometry as ph 406 + 407 + # A mid-frequency-peaked machine measured over the 40-position hemisphere array 408 + # (Annex E). levels_positions is the (40, NB) surface pressure spectrum: a base 409 + # spectrum peaked near 1 kHz plus a small per-position spatial spread. 410 + freqs = np.array([125, 250, 500, 1000, 2000, 4000, 8000], float) 411 + base = 70.0 + 8.0 * np.exp(-(np.log2(freqs / 1000.0) ** 2) / 2.0) 412 + rng = np.random.default_rng(7) 413 + levels = base[None, :] + rng.normal(0.0, 1.0, (40, freqs.size)) 414 + 415 + result = ph.sound_power_anechoic(levels, "hemisphere", radius=1.0, frequencies=freqs) 416 + print(round(result.sound_power_level_a, 1)) # 89.3 417 + result.plot() # LW spectrum, LWA in the title (needs matplotlib) 418 + ``` 419 + 420 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/precision_anechoic_power.png" alt="The precision sound power level spectrum of a mid-frequency-peaked machine measured over the ISO 3745 hemisphere array, one bar per band peaking near 1 kHz, with the A-weighted total of 89.3 dB(A) in the title" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/precision_anechoic_power_dark.png" alt="The precision sound power level spectrum of a mid-frequency-peaked machine measured over the ISO 3745 hemisphere array, one bar per band peaking near 1 kHz, with the A-weighted total of 89.3 dB(A) in the title" style="width:88%"> 421 + 422 + *One bar per band: the surface-averaged pressure plus the area, background and 423 + meteorological corrections give `LW(f)`, and the A-weighted energy sum across 424 + bands gives the single-number `LWA` in the title.* 425 + 426 + <details> 427 + <summary>Show the code for this figure</summary> 428 + 429 + ```python 430 + import matplotlib.pyplot as plt 431 + import numpy as np 432 + 433 + # result is the PrecisionSoundPowerResult computed above. One line: 434 + result.plot() 435 + plt.show() 436 + 437 + # By hand: a bar spectrum of LW with the A-weighted total in the title. 438 + freqs = result.frequencies 439 + positions = np.arange(freqs.size) 440 + fig, ax = plt.subplots() 441 + ax.bar(positions, result.sound_power_level, width=0.7, color="#1f77b4") 442 + ax.set_xticks(positions) 443 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 444 + ax.set_xlabel("Frequency [Hz]") 445 + ax.set_ylabel("Sound power level LW [dB]") 446 + ax.set_title( 447 + f"Precision sound power (ISO 3745) LWA = {result.sound_power_level_a:.1f} dB(A)") 448 + plt.show() 449 + ``` 450 + 451 + </details> 452 + 453 + ## 5. Precision intensity scanning (ISO 9614-3) 454 + 455 + ISO 9614-3 is the grade-1 scanning method: like ISO 9614-2 it integrates the 456 + normal intensity over a surface enclosing the source, but with a continuous 457 + scan, tighter field-indicator criteria and an explicit uncertainty budget. 458 + 459 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_intensity_scan.svg" alt="ISO 9614-3 precision sound intensity scanning: a source enclosed by a measurement surface divided into segments, a two-microphone intensity probe scanned along a serpentine path over each segment, and the sound power formed by summing the normal intensity times segment area, subject to the field-indicator acceptance criteria" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_intensity_scan_dark.svg" alt="ISO 9614-3 precision sound intensity scanning: a source enclosed by a measurement surface divided into segments, a two-microphone intensity probe scanned along a serpentine path over each segment, and the sound power formed by summing the normal intensity times segment area, subject to the field-indicator acceptance criteria" style="width:92%"> 460 + 461 + **Power and level (Clause 7).** The partial power of each segment is 462 + $P_i = I_{n,i}\,S_i$; the total $P = \sum_i P_i$ gives 463 + $L_W = 10\lg(P/P_0)$, $P_0 = 1\ \text{pW}$. A band whose net intensity is 464 + negative (more power flowing in than out) is flagged not-applicable rather than 465 + logged. The field indicators (temporal variability $F_T$, the signed and 466 + unsigned pressure–intensity indicators, and the non-uniformity $F_S$) drive the 467 + five acceptance criteria. 468 + 469 + ```python 470 + import numpy as np 471 + import phonometry as ph 472 + 473 + # A fully enclosing surface with a uniform normal intensity In = W/S recovers 474 + # the source power exactly: LW = 10*lg(W/P0). Here W = 100 uW -> 80 dB. 475 + areas = np.array([0.5, 1.0, 0.25, 2.0]) 476 + w = 1.0e-4 477 + i_n = np.full(areas.shape, w / float(areas.sum())) 478 + res = ph.sound_power_intensity_precision(i_n, areas) 479 + print(round(float(res.sound_power[0]), 6)) # 0.0001 480 + print(round(float(res.sound_power_level[0]), 2)) # 80.0 481 + ``` 482 + 483 + Across several bands the result carries the per-band `LW` (`NaN` where the net 484 + power is non-positive) and flags those bands `not_applicable`: 485 + 486 + ```python 487 + import numpy as np 488 + import phonometry as ph 489 + 490 + # Four partial surfaces scanned over five one-third-octave bands. Each cell of 491 + # partial_intensity is the signed normal intensity In_i (W/m^2); areas are the 492 + # partial-surface areas Si. The 250 Hz band has net-negative power (a locally 493 + # reactive field), so ISO 9614-3 flags it not-applicable (clause 9.2) -> NaN. 494 + freqs = np.array([250, 500, 1000, 2000, 4000], float) 495 + areas = np.array([0.5, 1.0, 0.75, 0.5]) 496 + base_intensity = np.array([2.0e-6, 8.0e-6, 2.0e-5, 1.0e-5, 3.0e-6]) 497 + partial_intensity = base_intensity[None, :] * np.array([1.0, 1.1, 0.9, 1.05])[:, None] 498 + partial_intensity[:, 0] = [2.0e-6, -3.0e-6, -4.0e-6, -1.0e-6] # net-negative band 499 + 500 + result = ph.sound_power_intensity_precision(partial_intensity, areas, frequencies=freqs) 501 + print(result.not_applicable_band.tolist()) # [True, False, False, False, False] 502 + print(round(result.sound_power_level_a, 1)) # 80.6 503 + result.plot() # LW spectrum; the not-applicable band is hatched (needs matplotlib) 504 + ``` 505 + 506 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_scan_power.png" alt="The precision intensity-scanning sound power level spectrum over five one-third-octave bands, four determinate bars and a hatched, greyed 250 Hz band flagged not-applicable because its net intensity is negative, with the A-weighted total of 80.6 dB(A) in the title" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_scan_power_dark.png" alt="The precision intensity-scanning sound power level spectrum over five one-third-octave bands, four determinate bars and a hatched, greyed 250 Hz band flagged not-applicable because its net intensity is negative, with the A-weighted total of 80.6 dB(A) in the title" style="width:88%"> 507 + 508 + *The 250 Hz band nets negative (more energy flowing in than out), so ISO 9614-3 509 + declares it not-applicable — the figure hatches and greys it while the four 510 + determinate bands and the A-weighted total stand.* 511 + 512 + <details> 513 + <summary>Show the code for this figure</summary> 514 + 515 + ```python 516 + import matplotlib.pyplot as plt 517 + import numpy as np 518 + 519 + # result is the PrecisionIntensityResult computed above. One line: 520 + result.plot() 521 + plt.show() 522 + 523 + # By hand: determinate bands as LW bars; a not-applicable band (its LW is NaN) 524 + # is flagged by a full-height greyed, hatched span rather than a zero-height bar. 525 + freqs = result.frequencies 526 + positions = np.arange(freqs.size) 527 + neg = result.not_applicable_band 528 + lw = np.nan_to_num(result.sound_power_level) 529 + fig, ax = plt.subplots() 530 + ax.bar(positions[~neg], lw[~neg], width=0.7, color="#1f77b4") 531 + for pos in positions[neg]: 532 + ax.axvspan(pos - 0.35, pos + 0.35, facecolor="#888888", alpha=0.28, 533 + hatch="//", edgecolor="#888888") 534 + ax.set_xticks(positions) 535 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 536 + ax.set_xlabel("Frequency [Hz]") 537 + ax.set_ylabel("Sound power level LW [dB]") 538 + ax.set_title( 539 + f"Precision intensity scanning (ISO 9614-3) " 540 + f"LWA = {result.sound_power_level_a:.1f} dB(A)") 541 + plt.show() 542 + ``` 543 + 544 + </details> 545 + 331 546 ## See also 332 547 333 548 - [Sound Intensity (p-p)](/phonometry/guides/intensity/) — the two-microphone probe, its 334 549 finite-difference bias and the ISO 9614-1 field indicators behind the 335 550 scanning method. 336 - - [Room and Building Acoustics](/phonometry/guides/room-acoustics/) — the reverberation time 551 + - [Room Acoustics](/phonometry/guides/room-acoustics/) — the reverberation time 337 552 and equivalent absorption area (ISO 354) that feed `K2` and the ISO 3741 338 - absorption area; impact and airborne insulation. 553 + absorption area. 554 + - [Building Acoustics & Sound Insulation](/phonometry/guides/building-acoustics/) — the 555 + airborne and impact insulation ratings and the EN 12354 emission predictions 556 + that consume a source `LW`. 339 557 - [Levels](/phonometry/guides/levels/) — energy averaging and the A-weighting behind `LWA`. 340 558 - [Theory](/phonometry/reference/theory/) — the Waterhouse, K1/K2 and C1/C2 derivations.
+410
site/src/content/docs/guides/surface-scattering.md
··· 1 + --- 2 + title: "Surface Scattering, Diffusion and In-situ Absorption" 3 + description: "How a surface returns incident sound: the random-incidence scattering coefficient in a reverberation room (ISO 17497-1), the autocorrelation diffusion coefficient from a free-field goniometer (ISO 17497-2), and in-situ road-surface absorption by the subtraction technique (ISO 13472-1) and the spot-tube method (ISO 13472-2)." 4 + --- 5 + 6 + How a surface returns incident sound — how much it scatters away from the 7 + specular direction, how uniformly it spreads what it scatters, and how much it 8 + absorbs — is measured by a family of dedicated methods. The **reverberation 9 + room** gives the random-incidence *scattering coefficient* of a surface by 10 + comparing decays with the sample held still and rotating (ISO 17497-1). A 11 + **free-field goniometer** measures the polar response of the reflected sound and 12 + condenses it into a *diffusion coefficient* (ISO 17497-2). And out on a road, a 13 + loudspeaker and a single microphone recover the *in-situ absorption* of the 14 + pavement, either over an extended surface by subtracting the incident wave 15 + (ISO 13472-1) or through a small tube pressed onto the surface (ISO 13472-2). 16 + This page covers all four. 17 + 18 + The scattering and diffusion coefficients answer different questions and are not 19 + interchangeable: scattering is *how much* energy leaves the specular direction; 20 + diffusion is *how evenly* the reflected energy is spread over angle. 21 + 22 + ## 1. Random-incidence scattering coefficient (ISO 17497-1) 23 + 24 + The scattering coefficient $s$ is the fraction of reflected energy that does 25 + **not** leave the surface in the specular direction. ISO 17497-1 measures it in a 26 + reverberation room from four reverberation-time situations: with the test sample 27 + mounted on a turntable and held **stationary**, and with the turntable 28 + **rotating** (which averages the phase-coherent specular reflection away), each 29 + with and without a reflecting base plate. 30 + 31 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_scattering_reverb.svg" alt="ISO 17497-1 random-incidence scattering setup: a reverberation room with the test sample on a turntable, a rotating loudspeaker boom and a microphone, measuring reverberation time with the sample stationary (giving the random-incidence absorption) and rotating (giving the specular absorption), from which the scattering coefficient is derived" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_scattering_reverb_dark.svg" alt="ISO 17497-1 random-incidence scattering setup: a reverberation room with the test sample on a turntable, a rotating loudspeaker boom and a microphone, measuring reverberation time with the sample stationary (giving the random-incidence absorption) and rotating (giving the specular absorption), from which the scattering coefficient is derived" style="width:92%"> 32 + 33 + **Absorption from reverberation time (Clause 6).** Each situation converts to a 34 + Sabine absorption coefficient with the standard's own air-attenuation term: 35 + 36 + $$ 37 + \alpha = 55.3\,\frac{V}{S}\left(\frac{1}{c_2 T_2} - \frac{1}{c_1 T_1}\right) 38 + - 4\,\frac{V}{S}\,(m_2 - m_1), 39 + $$ 40 + 41 + where $V$ is the room volume, $S$ the sample area, $T$ the reverberation time, 42 + $c$ the speed of sound (Eq. (2): $c = 343.2\sqrt{(273.15+t)/293.15}$) and $m$ the 43 + power attenuation coefficient of air. The **stationary** pair gives the 44 + random-incidence absorption $\alpha_s$ (Eq. (1)); the **rotating** pair gives the 45 + specular absorption $\alpha_{spec}$ (Eq. (4)). 46 + 47 + **Scattering coefficient (Eq. (5)).** The two combine into 48 + 49 + $$ 50 + s = \frac{\alpha_{spec} - \alpha_s}{1 - \alpha_s}. 51 + $$ 52 + 53 + A fully specular surface reflects all its non-absorbed energy in the specular 54 + direction, so $\alpha_{spec} = \alpha_s$ and $s = 0$; a strong diffuser sends 55 + energy everywhere, raising $\alpha_{spec}$ towards 1 and $s$ towards 1. 56 + 57 + ```python 58 + import phonometry as ph 59 + 60 + # Four reverberation-time situations reduced to two absorption coefficients. 61 + # alpha_s from the stationary pair (Eq. 1); alpha_spec from the rotating pair 62 + # (Eq. 4). V = 200 m^3, S = 10 m^2, c = 343.2 m/s throughout. 63 + alpha_s = ph.random_incidence_absorption(200.0, 10.0, c1=343.2, T1=8.0, 64 + c2=343.2, T2=6.0) 65 + alpha_spec = ph.specular_absorption_coefficient(200.0, 10.0, c3=343.2, T3=7.5, 66 + c4=343.2, T4=5.0) 67 + s = ph.scattering_coefficient(alpha_spec, alpha_s) # Eq. (5) 68 + print(round(float(alpha_s), 4)) # 0.1343 69 + print(round(float(alpha_spec), 4)) # 0.2148 70 + print(round(float(s), 4)) # 0.0931 71 + ``` 72 + 73 + Over a full one-third-octave measurement, `scattering_coefficient_spectrum` 74 + pairs the per-band $\alpha_{spec}$ and $\alpha_s$ with their band centres and 75 + returns a plottable `ScatteringResult`: 76 + 77 + ```python 78 + import numpy as np 79 + import phonometry as ph 80 + 81 + # A 13-band measurement (250-4000 Hz): the random-incidence absorption alpha_s 82 + # (stationary sample) and the specular absorption alpha_spec (rotating 83 + # turntable). A diffuser scatters more with frequency, so s(f) rises. 84 + freqs = np.array([250, 315, 400, 500, 630, 800, 1000, 85 + 1250, 1600, 2000, 2500, 3150, 4000], float) 86 + alpha_s = np.full_like(freqs, 0.10) 87 + alpha_spec = 0.11 + 0.75 * (np.log10(freqs / 250) / np.log10(4000 / 250)) 88 + 89 + result = ph.scattering_coefficient_spectrum(freqs, alpha_spec, alpha_s) 90 + print(np.round(result.scattering[[0, 6, 12]], 3)) # [0.011 0.428 0.844] 91 + result.plot() # s(f) on a log-frequency axis, 0 to 1 (needs matplotlib) 92 + ``` 93 + 94 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/scattering_coefficient.png" alt="The random-incidence scattering coefficient s of a diffusing surface over the 13 one-third-octave bands from 250 to 4000 Hz, rising smoothly from near zero at low frequency towards 0.84 at 4 kHz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/scattering_coefficient_dark.png" alt="The random-incidence scattering coefficient s of a diffusing surface over the 13 one-third-octave bands from 250 to 4000 Hz, rising smoothly from near zero at low frequency towards 0.84 at 4 kHz" style="width:88%"> 95 + 96 + *The scattering coefficient climbs with frequency: at low frequency the surface 97 + relief is small compared with the wavelength and the reflection stays specular 98 + ($s \to 0$); as the wavelength shrinks the relief scatters more energy out of 99 + the specular direction ($s \to 1$).* 100 + 101 + <details> 102 + <summary>Show the code for this figure</summary> 103 + 104 + ```python 105 + import matplotlib.pyplot as plt 106 + 107 + # result is the ScatteringResult computed above. One line: 108 + result.plot() 109 + plt.show() 110 + 111 + # By hand, from the result's fields, mirroring what ScatteringResult.plot() draws: 112 + fig, ax = plt.subplots() 113 + ax.semilogx(result.frequencies, result.scattering, "o-", color="#1f77b4") 114 + ax.set_xlabel("Frequency [Hz]") 115 + ax.set_ylabel("Scattering coefficient s") 116 + ax.set_ylim(0.0, 1.0) 117 + ax.set_title("Random-incidence scattering coefficient (ISO 17497-1)") 118 + plt.show() 119 + ``` 120 + 121 + </details> 122 + 123 + **Base-plate check (Clause 6.4, Table 1).** The empty base plate must itself 124 + scatter only negligibly, or it would bias the result. ISO 17497-1 caps the 125 + base-plate scattering coefficient per one-third-octave band; the library exposes 126 + those limits and a checker. 127 + 128 + ```python 129 + from phonometry import ( 130 + BASE_PLATE_BANDS_HZ, BASE_PLATE_MAX_SCATTERING, check_base_plate_scattering, 131 + ) 132 + 133 + # The normative per-band ceilings (Table 1): 0.05 up to 500 Hz, rising to 0.25. 134 + # BASE_PLATE_BANDS_HZ is the band tuple; BASE_PLATE_MAX_SCATTERING maps band -> ceiling. 135 + print(BASE_PLATE_BANDS_HZ[0], BASE_PLATE_MAX_SCATTERING[100]) # 100 0.05 136 + 137 + # A base plate whose measured scattering stays under the ceiling passes silently; 138 + # an over-limit band raises a ScatteringDiffusionWarning listing the offenders. 139 + check_base_plate_scattering([0.02] * len(BASE_PLATE_BANDS_HZ)) 140 + ``` 141 + 142 + ## 2. Diffusion coefficient (ISO 17497-2) 143 + 144 + The diffusion coefficient $d$ measures the **spatial uniformity** of the 145 + reflected sound, not how much is scattered. A goniometer sweeps a receiver over a 146 + polar arc and records the reflected level $L_i$ at each angle; the coefficient is 147 + the normalised autocorrelation of the polar energy distribution. 148 + 149 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_diffusion_goniometer.svg" alt="ISO 17497-2 free-field diffusion goniometer: a test sample on a turntable, a fixed loudspeaker source, and a semicircular arc of receiver microphones sampling the reflected polar response, from which the autocorrelation diffusion coefficient is computed" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_diffusion_goniometer_dark.svg" alt="ISO 17497-2 free-field diffusion goniometer: a test sample on a turntable, a fixed loudspeaker source, and a semicircular arc of receiver microphones sampling the reflected polar response, from which the autocorrelation diffusion coefficient is computed" style="width:92%"> 150 + 151 + **Autocorrelation (Formula (5)).** For $n$ receivers at equal angular spacing, 152 + with $p_i = 10^{L_i/10}$ the band energy at receiver $i$, 153 + 154 + $$ 155 + d = \frac{\left(\sum_i p_i\right)^2 - \sum_i p_i^2} 156 + {(n-1)\,\sum_i p_i^2}. 157 + $$ 158 + 159 + A perfectly uniform polar response ($L_i$ all equal) gives $d = 1$; a single 160 + sharp specular lobe gives $d = 0$. When receivers subtend unequal solid angles, 161 + Formula (6) area-weights each energy by $N_i$ from Formula (8) — and those area 162 + factors are evaluated in **radians**, which is why a 5° spacing at the zenith 163 + produces a weight near 1.57, not 51.9. 164 + 165 + ```python 166 + import phonometry as ph 167 + 168 + # Polar response of a diffuser (levels in dB at equally spaced receivers). 169 + levels = [70.0, 74.0, 68.0, 72.0] 170 + d = ph.directional_diffusion_coefficient(levels) # Formula (5) 171 + print(round(float(d), 4)) # 0.7367 172 + 173 + # Normalise against a flat reference surface to isolate the diffuser's effect 174 + # (Formula (7)): d_n = (d - d_ref) / (1 - d_ref). 175 + d_n = ph.normalized_diffusion_coefficient(d, 0.10) 176 + print(round(float(d_n), 4)) # 0.7075 177 + 178 + # Random-incidence value: average the band coefficients over source positions, 179 + # with the standard's 2-D weighting (0 deg -> 1, +/-30/+/-60 deg -> 3). 180 + from phonometry import TWO_DIMENSIONAL_SOURCE_WEIGHTS 181 + d_random = ph.random_incidence_diffusion( 182 + [0.5, 0.2, 0.2, 0.2, 0.2], weights=TWO_DIMENSIONAL_SOURCE_WEIGHTS) 183 + print(round(float(d_random), 4)) # 0.2231 184 + ``` 185 + 186 + `directional_diffusion` keeps the receiver angles beside the levels of a full 187 + goniometer sweep and returns a plottable `DiffusionResult`: 188 + 189 + ```python 190 + import numpy as np 191 + import phonometry as ph 192 + 193 + # A goniometer sweep of a diffusing surface: reflected levels L_i at 37 194 + # receivers from -90 to 90 deg (5 deg spacing). The energy is spread almost 195 + # uniformly over angle, so the Formula (5) coefficient d is high. 196 + angles = np.arange(-90.0, 90.5, 5.0) 197 + rng = np.random.default_rng(3) 198 + levels = 70.0 + 2.0 * np.sin(np.radians(angles) * 3.0) + rng.normal(0.0, 1.0, angles.size) 199 + 200 + result = ph.directional_diffusion(angles, levels) 201 + print(round(result.coefficient, 2)) # 0.82 202 + result.plot() # polar reflected response, d in the title (needs matplotlib) 203 + ``` 204 + 205 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diffusion_polar.png" alt="A polar plot of the reflected sound-pressure level of a diffusing surface over 37 receivers from -90 to 90 degrees, the response spread almost uniformly over angle, giving an autocorrelation diffusion coefficient d of about 0.82" style="width:72%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diffusion_polar_dark.png" alt="A polar plot of the reflected sound-pressure level of a diffusing surface over 37 receivers from -90 to 90 degrees, the response spread almost uniformly over angle, giving an autocorrelation diffusion coefficient d of about 0.82" style="width:72%"> 206 + 207 + *The reflected energy fills the whole semicircle rather than concentrating in a 208 + specular lobe, so the autocorrelation diffusion coefficient is high 209 + ($d \approx 0.82$). A flat surface would collapse the response into a narrow 210 + spike and drive $d$ towards zero.* 211 + 212 + <details> 213 + <summary>Show the code for this figure</summary> 214 + 215 + ```python 216 + import matplotlib.pyplot as plt 217 + import numpy as np 218 + 219 + # result is the DiffusionResult computed above. One line: 220 + result.plot() 221 + plt.show() 222 + 223 + # By hand: a polar plot of the levels, with d annotated in the title. 224 + fig, ax = plt.subplots(subplot_kw={"projection": "polar"}) 225 + theta = np.radians(result.angles) 226 + ax.plot(theta, result.levels, "o-", color="#1f77b4") 227 + ax.fill(theta, result.levels, color="#1f77b4", alpha=0.15) 228 + ax.set_theta_zero_location("N") 229 + ax.set_theta_direction(-1) 230 + ax.set_thetamin(-90) 231 + ax.set_thetamax(90) 232 + ax.set_title(f"Directional diffusion d = {result.coefficient:.2f} (ISO 17497-2)") 233 + plt.show() 234 + ``` 235 + 236 + </details> 237 + 238 + ## 3. In-situ road absorption — subtraction technique (ISO 13472-1) 239 + 240 + Out in the field there is no reverberation room. ISO 13472-1 measures the sound 241 + absorption of a road surface (or any extended flat surface) *in situ* by firing 242 + an impulse from a loudspeaker at height $d_s$ down onto the surface and recording 243 + the impulse response at a microphone at height $d_m$. The **incident** and 244 + **reflected** components are separated in time with an Adrienne window; their 245 + transfer function gives the reflection factor and hence the absorption. 246 + 247 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insitu_subtraction.svg" alt="ISO 13472-1 in-situ road absorption by the subtraction technique: a loudspeaker at 1.25 m and a microphone at 0.25 m above the road surface, with the direct and road-reflected ray paths and a free-field reference measurement, the reflected component isolated by an Adrienne time window" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_insitu_subtraction_dark.svg" alt="ISO 13472-1 in-situ road absorption by the subtraction technique: a loudspeaker at 1.25 m and a microphone at 0.25 m above the road surface, with the direct and road-reflected ray paths and a free-field reference measurement, the reflected component isolated by an Adrienne time window" style="width:92%"> 248 + 249 + **Geometrical spreading (Clause 4.1).** The reflected wave travels farther than 250 + the direct wave, so it is attenuated by the geometrical-spreading factor 251 + 252 + $$ 253 + K_r = \frac{d_s - d_m}{d_s + d_m}, 254 + $$ 255 + 256 + which equals $2/3$ for the mandatory geometry $d_s = 1.25$ m, $d_m = 0.25$ m. 257 + The absorption follows from the windowed incident and reflected spectra 258 + $H_i$, $H_r$: 259 + 260 + $$ 261 + \alpha(f) = 1 - \frac{1}{K_r^2}\left|\frac{H_r(f)}{H_i(f)}\right|^2. 262 + $$ 263 + 264 + ```python 265 + import numpy as np 266 + import phonometry as ph 267 + 268 + # A band-limited incident impulse response and a synthetic road reflection 269 + # hr = Kr * r0 * delayed(hi): a reflection of magnitude r0 = 0.4, delayed by the 270 + # extra path, and scaled by the geometrical-spreading factor Kr. 271 + fs, n = 48000.0, 4096 272 + t = np.arange(n) / fs 273 + hi = np.zeros(n) 274 + hi[:64] = np.hanning(64) * np.cos(2.0 * np.pi * 1500.0 * t[:64]) 275 + 276 + kr = ph.geometric_spreading_factor() # (ds - dm)/(ds + dm) = 2/3 277 + hr = kr * 0.4 * np.roll(hi, 96) 278 + 279 + # Narrow-band absorption, then reduced to one-third octaves over 250-4000 Hz. 280 + alpha = ph.insitu_absorption_coefficient(hi, hr) # 1 - (1/Kr^2)|Hr/Hi|^2 281 + freq = np.fft.rfftfreq(n, 1.0 / fs) 282 + centres, band = ph.one_third_octave_absorption(freq, alpha) 283 + print(round(kr, 4)) # 0.6667 284 + print(round(float(band[2]), 3)) # 0.84 (alpha = 1 - 0.4^2 = 0.84) 285 + ``` 286 + 287 + **Adrienne window (Clause 6.4).** The time window that isolates the reflection 288 + mandates only a sharp leading edge, a 5 ms flat portion and a cosine-squared or 289 + Blackman-Harris trailing edge — the exact durations are reported per measurement, 290 + not fixed, so they are configurable here. 291 + 292 + ```python 293 + from phonometry import adrienne_window 294 + 295 + # Default: 0.5 ms leading edge, 5 ms flat top, 5 ms Blackman-Harris trailing. 296 + w = adrienne_window(48000.0) 297 + print(w.shape[0]) # 504 samples at 48 kHz 298 + print(round(float(w.max()), 3)) # 1.0 (flat top and edges meet at unity) 299 + ``` 300 + 301 + **End-to-end spectrum.** `insitu_absorption_spectrum` runs the whole chain — the 302 + windowed incident and reflected impulse responses to the narrow-band absorption 303 + and on to one-third-octave bands — and returns a plottable 304 + `InsituAbsorptionResult`: 305 + 306 + ```python 307 + import numpy as np 308 + import phonometry as ph 309 + from scipy.signal import firwin, lfilter 310 + 311 + # A synthetic-but-realistic measurement. hi is a unit incident impulse; the road 312 + # reflection hr = Kr * r0 * roll(hi, shift) uses the geometrical-spreading 313 + # factor Kr, a mildly frequency-dependent r0 (a gentle low-pass, so a porous 314 + # surface reflects less as frequency rises) and the reflected-path delay 315 + # shift = round(2 dm / c * fs). 316 + fs, n = 48000.0, 8192 317 + kr = ph.geometric_spreading_factor() # (ds - dm)/(ds + dm) = 2/3 318 + hi = np.zeros(n) 319 + hi[0] = 1.0 320 + taps = firwin(41, 1200.0, fs=fs) 321 + taps = taps / taps.sum() 322 + shift = int(round(2.0 * 0.25 / 340.0 * fs)) # reflected-path delay 2 dm / c 323 + hr = kr * 0.85 * np.roll(lfilter(taps, 1.0, hi), shift) 324 + 325 + result = ph.insitu_absorption_spectrum(hi, hr, fs) 326 + print(result.frequencies[[0, -1]].astype(int)) # [ 250 4000] 327 + print(np.round(result.absorption[[0, 6, 12]], 2)) # [0.31 0.65 1. ] 328 + result.plot() # alpha(f) bar chart over 250-4000 Hz (needs matplotlib) 329 + ``` 330 + 331 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insitu_absorption.png" alt="An in-situ one-third-octave road-surface absorption spectrum computed by the reflection-factor route from a synthetic road reflection, rising from about 0.3 at 250 Hz to near 1.0 above 2 kHz" style="width:88%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/insitu_absorption_dark.png" alt="An in-situ one-third-octave road-surface absorption spectrum computed by the reflection-factor route from a synthetic road reflection, rising from about 0.3 at 250 Hz to near 1.0 above 2 kHz" style="width:88%"> 332 + 333 + *The absorption rises with frequency because the surface reflects less of the 334 + high-frequency energy, exactly as the low-pass reflection factor $r_0(f)$ 335 + dictates through $\alpha = 1 - (1/K_r^2)\,|H_r/H_i|^2$.* 336 + 337 + <details> 338 + <summary>Show the code for this figure</summary> 339 + 340 + ```python 341 + import matplotlib.pyplot as plt 342 + import numpy as np 343 + 344 + # result is the InsituAbsorptionResult computed above. One line: 345 + result.plot() 346 + plt.show() 347 + 348 + # By hand: a bar chart of alpha over the one-third-octave bands. 349 + freqs = result.frequencies 350 + positions = np.arange(freqs.size) 351 + fig, ax = plt.subplots() 352 + ax.bar(positions, np.nan_to_num(result.absorption), width=0.7, color="#1f77b4") 353 + ax.set_xticks(positions) 354 + ax.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right") 355 + ax.set_xlabel("Frequency [Hz]") 356 + ax.set_ylabel("Absorption coefficient alpha") 357 + ax.set_ylim(0.0, 1.0) 358 + ax.set_title("In-situ road-surface absorption (ISO 13472-1)") 359 + plt.show() 360 + ``` 361 + 362 + </details> 363 + 364 + **Maximum sampled area (Annex A).** The finite time window limits how much of the 365 + surface contributes to the reflection. The maximum sampled area is a circle whose 366 + radius the library computes from the geometry and window width; the Annex A worked 367 + example ($d_s = 1.25$ m, $d_m = 0.25$ m, $c = 340$ m/s, 5 ms flat window) gives 368 + about 1.34 m. 369 + 370 + ```python 371 + import phonometry as ph 372 + print(round(ph.max_sampled_area_radius(5.0e-3), 3)) # 1.343 (metres) 373 + ``` 374 + 375 + ## 4. In-situ road absorption — spot method (ISO 13472-2) 376 + 377 + For smaller patches, ISO 13472-2 seals a short circular tube onto the surface and 378 + measures the absorption with the two-microphone transfer-function method of 379 + ISO 10534-2. The library provides the spot-method geometry and validity helpers; 380 + the transfer-function DSP itself is the impedance-tube routine 381 + `two_microphone_impedance` (see the [Acoustic Materials guide](/phonometry/guides/materials/)). 382 + 383 + <img class="light-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_spot_tube.svg" alt="ISO 13472-2 spot method: a short circular tube sealed onto the road surface with a loudspeaker at the top and two microphones flush in the tube wall at spacing s, measuring absorption over 250 to 1600 Hz via the ISO 10534-2 two-microphone transfer-function method" style="width:92%"><img class="dark-only" src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/diagram_spot_tube_dark.svg" alt="ISO 13472-2 spot method: a short circular tube sealed onto the road surface with a loudspeaker at the top and two microphones flush in the tube wall at spacing s, measuring absorption over 250 to 1600 Hz via the ISO 10534-2 two-microphone transfer-function method" style="width:92%"> 384 + 385 + **Plane-wave limits (Clause 5.4).** The tube supports only plane waves below 386 + 387 + $$ 388 + f_u = 0.58\,\frac{c_0}{d}, 389 + $$ 390 + 391 + with $d$ the tube diameter, and the microphone spacing $s$ must sit between 392 + $0.05\,c_0/f_{min}$ and $0.45\,c_0/f_{max}$. The reported range is the 393 + one-third-octave bands 250–1600 Hz. 394 + 395 + ```python 396 + import phonometry as ph 397 + 398 + # Upper usable frequency of a 100 mm tube and the valid spacing window. 399 + print(round(ph.spot_tube_upper_frequency(0.100, 343.0), 1)) # 1989.4 Hz 400 + s_min, s_max = ph.spot_microphone_spacing_bounds( 401 + 343.0, f_min=220.0, f_max=1800.0) 402 + print(round(s_min, 3), round(s_max, 3)) # 0.078 0.086 (metres) 403 + ``` 404 + 405 + --- 406 + 407 + **Standards implemented on this page:** ISO 17497-1:2004 (scattering 408 + coefficient), ISO 17497-2:2012 (diffusion coefficient), ISO 13472-1:2002 (in-situ 409 + absorption, extended surface), ISO 13472-2:2010 (in-situ absorption, spot 410 + method).