{content.proof.spectrum.title}
{content.proof.spectrum.note}
diff --git a/site/src/content/docs/aircraft/aircraft-noise.mdx b/site/src/content/docs/aircraft/aircraft-noise.mdx
index e0eb04ed4..c8968b36b 100644
--- a/site/src/content/docs/aircraft/aircraft-noise.mdx
+++ b/site/src/content/docs/aircraft/aircraft-noise.mdx
@@ -72,18 +72,40 @@ pnl = aircraft.perceived_noise_level(spl) # PNdB
## Tone correction
-Spectral irregularities (fan/turbine tones) are penalised by a **tone
-correction** $C$, found with the slope ("encircling") method: slopes are
-smoothed to a background spectrum $\mathrm{SPL}''$, the tone excess
-$F = \mathrm{SPL} - \mathrm{SPL}''$ above 1.5 dB is mapped to a correction
-factor (frequency-split at 500 Hz / 5000 Hz, capped at 6⅔ dB), and the maximum
-over bands is taken. The implementation reproduces the ICAO Doc 9501 ETM Vol. I
-Table 3-7 turbofan example exactly ($C = 2.0\ \text{dB}$ at 2500 Hz).
+A pure tone is judged much noisier than the same energy spread across its
+one-third-octave band, so spectral irregularities (fan and turbine tones) are
+penalised by a **tone correction** $C$. The slope ("encircling") method
+reconstructs what the spectrum would look like *without* the tone by smoothing
+the band-to-band slopes into a background $\mathrm{SPL}''$, so the excess
+$F = \mathrm{SPL} - \mathrm{SPL}''$ is a tone-only quantity. Above 1.5 dB it is
+mapped to a correction factor by the rule of Table A2-2, and the maximum over
+bands is taken:
+
+| Band | $F < 3$ dB | $3 \le F < 20$ dB | $F \ge 20$ dB |
+|---|---|---|---|
+| 50 Hz-400 Hz and 6.3-10 kHz | $F/3 - 0.5$ | $F/6$ | $3\tfrac{1}{3}$ dB |
+| 500 Hz-5 kHz | $2F/3 - 1$ | $F/3$ | $6\tfrac{2}{3}$ dB |
+
+The mid-band branch penalises a tone twice as hard, which is why a 2500 Hz fan
+tone dominates the correction of a turbofan spectrum. The implementation
+reproduces the ICAO Doc 9501 ETM Vol. I Table 3-7 turbofan example exactly
+($C = 2.0\ \text{dB}$ at 2500 Hz).
+
+Two traps come with the method. A rippled but tone-free spectrum can produce a
+correction, which the standard itself allows you to reject after a narrow-band
+re-analysis (§4.3.1 Step 10). And a tone falling between two bands splits its
+excess, so the raw correction comes out too small; the **bandsharing
+adjustment** $\Delta_B$ — the shortfall of $C$ at the $\mathrm{PNLTM}$ record
+against the mean of the records within one second of it — adds it back before
+the 10 dB-down window is located.
```python
from phonometry import aircraft
c = aircraft.tone_correction(spl) # dB; added to PNL to give PNLT
+# start_band=2 (80 Hz) is the aeroplane start of analysis; a helicopter
+# procedure starts at 50 Hz, which is what procedure="helicopter" selects in
+# effective_perceived_noise_level below.
```
## EPNL
@@ -106,9 +128,12 @@ res.plot() # PNL/PNLT time history (needs matplotlib)
```
`effective_perceived_noise_level` returns an `EPNLResult` bundling the per-record
-`pnl`, `tone_correction`, `pnlt`, the peak `pnltm`, the `duration_correction`,
-the `epnl` and the 10 dB-down `band_limits`. The reference-condition
-integrated-method example of ETM Vol. I Table 4-4 is reproduced as
+`pnl`, `tone_correction`, `pnlt`, the peak `pnltm`, the `bandsharing_adjustment`,
+the `duration_correction`, the `epnl` and the 10 dB-down `band_limits`. Its
+`procedure=` argument starts the analysis at 80 Hz for an aeroplane (the
+default) and at 50 Hz for a helicopter. The reference-condition
+integrated-method example of ETM Vol. I Table 4-4 — a different, real
+certification time history — is reproduced as
$\mathrm{EPNL} = 92.6\ \text{EPNdB}$.
@@ -173,7 +198,10 @@ res.report(
```
The example fiche is regenerated with `make reports` and kept rendered in the
-repository; click the preview to open the PDF.
+repository; click the preview to open the PDF. It is rendered from its own,
+quieter synthetic flyover (EPNL 98.3 EPNdB), not from the spectra of the figure
+above: run those through the same call and the fiche reports 114.0 EPNdB and a
+FAIL against the same 101 EPNdB limit, which is the verdict row doing its job.
f_0$ only, and taken as zero at and below the
+resonance. That is a convention: in the band containing $f_0$ the mass-spring
+system amplifies and measured floors fall between about $-5$ dB and $0$ dB
+there, so a design whose $f_0$ lands inside the rated 100-3150 Hz range rates
+optimistically in exactly the band that decides the number. Here $f_0$ is
+52.8 Hz, comfortably below the range, which is why the spectrum below starts
+clean at 100 Hz.
+
```python
import numpy as np
from phonometry import building, materials
diff --git a/site/src/content/docs/buildings/design/index.md b/site/src/content/docs/buildings/design/index.md
index aefd5f502..548c7e62e 100644
--- a/site/src/content/docs/buildings/design/index.md
+++ b/site/src/content/docs/buildings/design/index.md
@@ -1,6 +1,6 @@
---
title: "Insulation design"
-description: "Sound insulation before it is built: the EN 12354 flanking prediction between rooms, the theoretical insulation of a panel from its physical properties, and the two material measurements a floor design consumes (ISO 16251-1 floor coverings, EN 29052-1 dynamic stiffness)."
+description: "Sound insulation before it is built: the EN/ISO 12354 flanking prediction between rooms in its simplified and per-band forms, the theoretical insulation of a panel from its physical properties, the resilient layers a floor or lining design turns on, and the structure-borne sound of building service equipment from the EN 15657 reception plate to the EN 12354-5 receiving-room level."
---
The pages of the [Sound insulation](/phonometry/buildings/insulation/)
@@ -33,14 +33,42 @@ double wall, transmission through slits and apertures, plate radiation
efficiency and point mobilities. It is the physics a catalogue value expresses
in one number.
-Two measurements feed the floor half of any design.
+Two pages here carry the floor half of any design, one measuring and one
+predicting.
[Floor-Covering Impact Improvement (ISO 16251-1)](/phonometry/buildings/design/impact-improvement/)
-gives the weighted improvement $\Delta L_w$ of a soft covering on a small
-heavyweight mock-up, the term EN 12354-2 subtracts from the bare-floor level,
-and
-[Dynamic stiffness of resilient materials (EN 29052-1)](/phonometry/materials/resilient/dynamic-stiffness/)
-gives the stiffness per unit area $s'$ of the resilient layer under a floating
-floor, and with it the resonance frequency the whole improvement hangs on.
+gives the weighted improvement $\Delta L_w$ of a covering that exists, on a
+small heavyweight mock-up, and that is the term EN 12354-2 subtracts from the
+bare-floor level.
+[Predicting Resilient-Layer Performance](/phonometry/buildings/design/resilient-layers/)
+predicts it for a covering that does not yet exist, from the tapping machine's
+own force spectrum, the cut-off frequency of a soft covering, the 30 lg and
+40 lg floating-floor laws and the ISO 12354-1 Annex D rating of a wall lining.
+Both start from the stiffness per unit area $s'$ of the resilient layer,
+measured per EN 29052-1 in
+[Dynamic stiffness of resilient materials](/phonometry/materials/resilient/dynamic-stiffness/)
+over in the materials section, which sets the resonance the whole improvement
+hangs on.
+
+Building service equipment is a chain of its own, and the two pages only read
+correctly in order.
+[Structure-borne sound power of equipment (EN 15657)](/phonometry/buildings/design/structure-borne-power/)
+characterises a pump, fan or cistern by the power it injects into the
+structure, measured on a reception plate of known dissipation and then made
+plate-independent.
+[Installed structure-borne sound (EN 12354-5)](/phonometry/buildings/design/installed-structure-borne/)
+takes that source description, loses part of it to the coupling term the source
+and receiver mobilities set, and carries the rest to a room that may be several
+junctions away.
+
+One bookkeeping note runs through the whole section: the family exists as
+EN 12354:2000 and as ISO 12354:2017, and the two are not interchangeable in
+every clause. The simplified models on
+[Predicting Sound Insulation](/phonometry/buildings/design/insulation-prediction/)
+follow the 2000 text — including the tabulated flanking correction $K$ that the
+2017 impact part replaced with explicit per-path formulae — while
+[Detailed Per-Band Prediction](/phonometry/buildings/design/detailed-prediction/)
+follows the 2017 text. Check which edition your regulation calls up before
+quoting a correction from either.
## Pages in this section
diff --git a/site/src/content/docs/buildings/design/installed-structure-borne.mdx b/site/src/content/docs/buildings/design/installed-structure-borne.mdx
index f4aee414a..eb2158f22 100644
--- a/site/src/content/docs/buildings/design/installed-structure-borne.mdx
+++ b/site/src/content/docs/buildings/design/installed-structure-borne.mdx
@@ -62,11 +62,14 @@ ys = (2e-4 + 1e-4j) * (bands / 250.0) # source mobility
yi = (3e-5 + 1e-5j) * np.ones_like(bands) # receiver mobility
dc = np.array([float(building.coupling_term(a, b)) for a, b in zip(ys, yi)])
-# Two transmission paths: the excited floor and a flanking wall.
+# Two transmission paths: the excited floor and a flanking wall. Dsa is
+# negative and falls with frequency (Annex F.2), and enters with a minus sign.
paths = [
- {"adjustment_term": 6.0, "element_area": 12.0,
+ {"adjustment_term": np.array([-14.0, -17.0, -20.0, -25.0, -30.0, -35.0, -40.0]),
+ "element_area": 12.0,
"flanking_reduction_index": np.linspace(44.0, 62.0, 7)},
- {"adjustment_term": 7.0, "element_area": 9.0,
+ {"adjustment_term": np.array([-16.0, -19.0, -23.0, -28.0, -33.0, -38.0, -43.0]),
+ "element_area": 9.0,
"flanking_reduction_index": np.linspace(46.0, 64.0, 7)},
]
res = building.installed_source_prediction(lws_c, dc, paths, frequencies=bands)
@@ -93,6 +96,16 @@ mobility, Formula 19c) and to $-10\log_{10}(|Y_s|\,\mathrm{Re}\{Z_i\})$ for a **
mobility $Y_k$ inside the modulus (Formula 19e). The **installed** power level is
then (Formula 18b) $L_{Ws,\mathrm{inst}} = L_{Ws,c} - D_C$.
+This is the same $L_{Ws,\mathrm{inst}}$ as the Annex I mobility correction of
+the introduction, reached by a different route: use Formula (18b) when $D_C$ is
+known from the two mobilities, and the direct correction
+$L_{Ws,n} + 10\log_{10}(Y_{\infty,i}/Y_{\infty,\mathrm{rec}})$ when it is not.
+On the Annex I.3 cistern both give 68.2 dB at 63 Hz, from
+$L_{Ws,c} = 84.4$ dB and $D_C = 16.2$ dB. Note which quantity you are handed:
+$L_{Ws,c}$ is the input this page takes, and it is *not* the 68.2 dB the
+[EN 15657 page](/phonometry/buildings/design/structure-borne-power/) prints as
+its installed level — feeding that in subtracts $D_C$ twice.
+
The physics behind $D_C$ is the classical power input of a point-excited
plate: only the real part of the receiver's driving-point mobility absorbs
power, and the mismatch between $Y_s$ and $Y_i$ decides how much of the
@@ -137,20 +150,70 @@ L_{n,s,ij} = L_{Ws,\mathrm{inst},i} - D_{sa,i} - R_{ij,\mathrm{ref}}
- 10\log_{10}\frac{S_i}{S_0} - 10\log_{10}\frac{A_0}{4},
$$
-with $S_0 = A_0 = 10\ \text{m}^2$, and the paths combine energetically (Formula 17):
+with $S_0 = A_0 = 10\ \text{m}^2$, and the paths combine energetically (Formula 17).
+
+### The adjustment term $D_{sa}$
+
+A point force pumps energy into *free* bending waves, while an incident sound
+field drives *forced* waves as well. $D_{sa}$ is the bookkeeping factor that
+lets the airborne flanking index $R_{ij,\mathrm{ref}}$ — an airborne
+quantity — be reused for a structurally excited element: it converts the
+injected structure-borne power into the incident airborne power that would
+leave the element with the same free-vibration energy (Formula 20a). For
+perpendicular force excitation of a homogeneous element that becomes
+Formula (20b),
+
+$$
+D_{sa,i} = 10\log_{10}\frac{2\pi m_i\,2.2\,\tau_i}{\rho_0 c_0 T_{s,i}\sigma_i}\ \text{dB},
+$$
+
+with $R_i = -10\log_{10}\tau_i$, and Annex F.2 gives the working form
+
+$$
+D_{sa,i} = 10\log_{10}\frac{400\,f_{c,i}\,\sigma_i}{m_i\,f^2}\ \text{dB}
+\qquad\text{(Formula F.3)},
+$$
+
+exact above the critical frequency ($\sigma_i \approx 1$) and a good
+approximation over the whole range. Read it: heavier elements and higher
+frequencies make $D_{sa}$ *more negative*, at $-20\log_{10}f$ once $\sigma$
+has saturated.
+
+:::caution
+**$D_{sa}$ is normally negative — pass the tabulated value with its printed
+sign.**
+The standard's own Annex I columns run from about $-14$ dB at 63 Hz to $-45$ dB
+at 2 kHz for ordinary concrete and masonry elements. The term enters
+Formula (18a) with a minus sign, so a negative $D_{sa}$ *raises* the predicted
+level. Earlier revisions of this page passed `"adjustment_term": 5.0` and
+`6.0`; copying that pattern with a real Annex F value in its place would leave
+the prediction roughly 20 to 40 dB low across the spectrum, with no error
+raised.
+:::
+
+Every input of Formula (F.3) is already available:
+[`in_situ_element`](/phonometry/buildings/design/detailed-prediction/) returns
+the in-situ structural reverberation time, the radiation factor and $R$ for the
+element.
```python
import numpy as np
from phonometry import building
+# Formula (F.3) for the 92 kg/m2 wall of the Annex I worked building.
+f = np.array([63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0])
+sigma = np.minimum(1.0, np.sqrt(f / 200.0)) # radiation factor, fc = 200 Hz
+dsa_f3 = 10 * np.log10(400.0 * 200.0 * sigma / (92.0 * f**2))
+print(np.round(dsa_f3, 1)) # [-9.1 -13.6 -18.6 -24.6 -30.6 -36.6] all negative
+
bands = np.array([250.0, 500.0, 1000.0])
res = building.installed_source_prediction(
characteristic_power_level=np.array([80.0, 82.0, 78.0]),
coupling_term=np.array([9.0, 10.0, 11.0]),
paths=[
- {"adjustment_term": 5.0,
+ {"adjustment_term": np.array([-19.0, -25.0, -31.0]),
"flanking_reduction_index": np.array([50.0, 52.0, 55.0]), "element_area": 12.0},
- {"adjustment_term": 6.0,
+ {"adjustment_term": np.array([-22.0, -28.0, -34.0]),
"flanking_reduction_index": np.array([52.0, 54.0, 57.0]), "element_area": 8.0},
],
frequencies=bands,
diff --git a/site/src/content/docs/buildings/design/insulation-prediction.mdx b/site/src/content/docs/buildings/design/insulation-prediction.mdx
index 255c88d34..c9bdbe581 100644
--- a/site/src/content/docs/buildings/design/insulation-prediction.mdx
+++ b/site/src/content/docs/buildings/design/insulation-prediction.mdx
@@ -200,6 +200,23 @@ $L'_{n,w} = L_{n,w,eq} - \Delta L_w + K$, with the bare-floor equivalent level
$L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Annex B), the covering improvement
$\Delta L_w$ (ISO 717-2) and the flanking correction $K$ from Table 1.
+**Check which edition your regulation cites.** The model above is the
+EN 12354-2:2000 one, which condenses all flanking transmission into the single
+tabulated correction $K$ read from the separating and mean flanking masses.
+ISO 12354-2:2017 reorganised the same simplified model into explicit per-path
+formulae — $L_{n,d,w} = L_{n,eq,0,w} - \Delta L_w - \Delta L_{d,w}$ (15) for
+the direct path and, for each flanking path,
+$L_{n,ij,w} = L_{n,eq,0,w} - \Delta L_w + (R_{i,w} - R_{j,w})/2 - \Delta R_{j,w} -
+K_{ij} - 10\log_{10}(S_i/l_0 l_{ij})$ (16) — so **the Table 1 correction is
+not in the current text at all**, even though the underlying physics and the
+accuracy statement are unchanged. The 2017 edition also states a field of
+application the 2000 text left implicit (Clause 4.3.1): the simplified model
+is restricted to 100 Hz–3150 Hz, and for lightweight constructions to the
+measured normalised flanking impact level route $L_{nf,ij}$ of Formula (17).
+The frequency-band route of
+[Detailed Sound Insulation Prediction](/phonometry/buildings/design/detailed-prediction/)
+is anchored on the 2017 editions throughout.
+
```python
from phonometry import building
diff --git a/site/src/content/docs/buildings/design/panel-sound-insulation.mdx b/site/src/content/docs/buildings/design/panel-sound-insulation.mdx
index 717756df2..8484dcaac 100644
--- a/site/src/content/docs/buildings/design/panel-sound-insulation.mdx
+++ b/site/src/content/docs/buildings/design/panel-sound-insulation.mdx
@@ -717,20 +717,47 @@ How much airborne power a vibrating plate actually radiates per unit
mean-square velocity is its **radiation efficiency** $\sigma$, the radiation
factor $\varepsilon$ that
[Sound Power from Surface Vibration](/phonometry/devices/emission/vibration-sound-power/)
-(ISO 7849) otherwise takes as a measured input. Below the critical frequency the
-plate radiates weakly (edge and corner modes); above it $\sigma \to 1$
-(Leppington/Maidanik, Hopkins Eqs 2.227-2.230):
+(ISO 7849) otherwise takes as a measured input. It is defined as the ratio of
+the power the plate actually radiates to the power a rigid piston of the same
+area and the same mean-square velocity would radiate, so $\sigma = 1$ means
+"as efficient as a piston" — and, as the numbers below show, a plate can beat
+that near coincidence.
+
+There are three regimes, not two (Leppington/Maidanik, Hopkins
+Eqs 2.227-2.230). **Well below $f_c$** the bending wavelength is shorter than
+the acoustic one, adjacent half-waves cancel each other's volume flow, and only
+the uncancelled strips at the edges and corners radiate. That is why the
+calculation needs the plate's two dimensions and its edge condition: a clamped
+edge radiates more than a simply supported one, and a plate with baffles
+perpendicular to its edges more than one flush in an infinite baffle — the
+`boundary` and `baffle` arguments select between them. **Around $f_c$** the
+trace wavelength of the bending wave matches the acoustic wavelength, the
+Leppington form $(1 - f_c/f)^{-1/2}$ diverges and is capped by the
+at-coincidence expression; the pane below peaks at $\sigma = 2.6$ in the 2 kHz
+band. **Only far above $f_c$** does $\sigma$ settle towards 1: a third of an
+octave past coincidence this pane is still at 1.74.
$$
-\sigma = \frac{1}{\sqrt{1 - f_c/f}} \quad (f > f_c), \qquad \sigma \to 1 .
+\sigma = \frac{1}{\sqrt{1 - f_c/f}} \quad (f > f_c), \qquad
+\sigma \to 1 \quad (f \gg f_c) .
$$
+Two consequences are worth carrying away. A *small* plate is a relatively
+better radiator than a large one of the same material below $f_c$, because the
+radiating edge strip is a larger fraction of it: the 1.5 × 1.25 m pane below
+gives $\sigma = 0.011$ at 100 Hz, a 0.5 × 0.4 m pane of the same glass 0.034.
+And the coincidence dip in $R$ and the coincidence peak in $\sigma$ are the
+same event seen from the two sides — the same $\sigma$ reappears in the
+transmission factor of the detailed EN 12354 model and as the radiation factor
+ISO 7849 measures.
+
```python
from phonometry import radiation_efficiency, sound_power_from_vibration
# The 6 mm glass pane (1.5 x 1.25 m) of the single-panel example above.
sig = radiation_efficiency(bands, 1.5, 1.25, fc)
-print(sig.radiation_efficiency[bands == 2000].round(2)) # ~2.5 (peak at coincidence)
+print(sig.radiation_efficiency[bands == 2000].round(2))
+# 2.6, the coincidence peak: the plate out-radiates a piston near fc
# Feed the prediction straight into ISO 7849 as the radiation factor:
lw = sound_power_from_vibration(velocity_level=80.0, area=1.875,
diff --git a/site/src/content/docs/buildings/design/resilient-layers.mdx b/site/src/content/docs/buildings/design/resilient-layers.mdx
index cc44327a2..d89c74b69 100644
--- a/site/src/content/docs/buildings/design/resilient-layers.mdx
+++ b/site/src/content/docs/buildings/design/resilient-layers.mdx
@@ -58,9 +58,9 @@ and
Everything downstream depends on the force the standard tapping machine
actually injects, and that force is not a property of the machine alone. Each
hammer is a 0.5 kg mass dropped 40 mm, so it lands at
-$v_0 = \sqrt{2gh} = 0.886\ \text{m/s}$, ten times a second. If the impact were
+$v_\text{h} = \sqrt{2gh} = 0.886\ \text{m/s}$, ten times a second. If the impact were
short compared with the 0.1 s between impacts, the momentum alone would fix
-the force, giving the line spectrum $|F_n| = 2 m v_0 / T_i$ and the band
+the force, giving the line spectrum $|F_n| = 2 m v_\text{h} / T_i$ and the band
mean-square force $F_\text{rms}^2 = 3.9 B$ that ISO 10140 measurements on
concrete are usually reduced with.
@@ -70,10 +70,10 @@ mass-spring-dashpot whose pulse splits into two cases:
- **over-critical**, $K m \ge 4 Z_\text{dp}^2$: a single positive pulse, no
rebound. This is a lightweight walking surface (chipboard, OSB), where the
- spectrum tends to $|F_n|_\text{lower} = m v_0/T_i$;
+ spectrum tends to $|F_n|_\text{lower} = m v_\text{h}/T_i$;
- **under-critical**, $K m < 4 Z_\text{dp}^2$: the hammer rebounds and only the
first positive lobe counts. This is a concrete slab or a screed, where the
- spectrum sits within 1 dB of $|F_n|_\text{upper} = 2 m v_0/T_i$ below 4 kHz
+ spectrum sits within 1 dB of $|F_n|_\text{upper} = 2 m v_\text{h}/T_i$ below 4 kHz
and the short-pulse estimate is adequate.
The two limits are 6 dB apart in mean square, which is the whole reason a
@@ -215,10 +215,20 @@ applies is a question about damping, not about the layer:
| Model | Law | When |
| --- | --- | --- |
-| `"cremer"` | $\Delta L = 40 \log_{10} (f/f_0)$ | Cremer's infinite-plate result; asphalt screeds and dry floating floors, whose internal losses are high enough to behave as infinite plates (ISO 12354-2 Formula C.3) |
+| `"cremer"` | $\Delta L = 40 \log_{10} (f/f_0)$ | Cremer's infinite-plate result; asphalt screeds and dry floating floors, whose internal losses are high enough to behave as infinite plates (ISO 12354-2 Formula C.3). The derivation is reported to hold over $f_0 < f < 4f_0$, so the branch far above resonance is an extrapolation |
| `"en12354"` | $\Delta L = 30 \log_{10} (f/f_0)$ | sand-cement and calcium-sulfate screeds, whose low loss factor makes them finite plates with a reverberant bending field (Formula C.1) |
| `"cremer_hammer"` | $40 \log_{10} (f/f_0) + 10 \log_{10}[1 + (f/f_\text{limit})^2]$ | a lightweight walking surface, where the hammer impedance is no longer negligible; tends to 18 dB per octave |
+All three laws are written for $f > f_0$, and the library clamps them to zero
+at and below the resonance. That clamp is a convention, not a physical result:
+in the band containing $f_0$ the mass-spring system amplifies, and measured
+floors fall between about $-5$ dB and $0$ dB there — the "worse than bare at
+$f_0$" of the introduction, which no model on this page reproduces. As long as
+$f_0$ sits below the rated range the difference is harmless, but a stiff layer
+or a light screed that puts $f_0$ near 100 Hz produces a $\Delta L_w$ that is
+optimistic in precisely the band that decides the rating. Check where $f_0$
+lands before trusting the number.
+
diff --git a/site/src/content/docs/buildings/design/structure-borne-power.mdx b/site/src/content/docs/buildings/design/structure-borne-power.mdx
index b65375ca8..beaa0f07a 100644
--- a/site/src/content/docs/buildings/design/structure-borne-power.mdx
+++ b/site/src/content/docs/buildings/design/structure-borne-power.mdx
@@ -101,9 +101,12 @@ L_{Ws} = 10\log_{10}\!\left(\frac{2\pi f\,\eta\,m\,S}{f_0\,m_0\,S_0}\right)
+ L_v - 60 \;\;[\mathrm{dB\ re\ 1\ pW}],
$$
-with references $f_0 = 1\ \text{Hz}$, $m_0 = 1\ \text{kg}$,
+with references $f_0 = 1\ \text{Hz}$, $m_0 = 1\ \text{kg}$ (printed as 1 kg; the
+quantity it normalises is a mass per unit area, so the reference is
+$1\ \text{kg/m}^2$ — see the [errata registry](/phonometry/reference/errata/)),
$S_0 = 1\ \text{m}^2$; the $-60\ \text{dB}$ term is $10\log_{10}(v_0^2/P_0)$ for
-the EN 15657 velocity reference $v_0 = 10^{-9}\ \text{m/s}$. The plate
+the EN 15657 velocity reference $v_0 = 10^{-9}\ \text{m/s}$ and
+$P_0 = 1\ \text{pW}$. The plate
velocity is the energetic spatial average over the $N$ positions (Formula 12)
and the loss factor comes from the structural reverberation time $T_s$
(Formula 13, identical to the ISO 10848 total loss factor):
@@ -142,12 +145,24 @@ attached. The plate-injected power plus the plate's point mobility (see
[mechanical mobility](/phonometry/vibration/structural/mechanical-mobility/)) yield the
source description for the EN 12354-5 model through the conversion chain below.
+:::caution
+**Two velocity references share the symbol $v_0$.**
+EN 15657 and EN 12354-5 refer velocity levels to $v_0 = 10^{-9}$ m/s (1 nm/s);
+ISO 9611 and ISO/TS 7849 refer them to $5\times10^{-8}$ m/s (50 nm/s). The two
+differ by $20\log_{10}(50) = 33.98$ dB, so a free velocity level taken from an
+ISO 9611 report must be reduced by 34.0 dB before it enters Formula (18) or any
+EN 12354-5 quantity. Section 3 below uses both references, a few lines apart.
+:::
+
## 3. From plate power to source quantities (Formulae 15–19)
The plate-injected $L_{Ws}$ is **not** a source descriptor: the same source
injects a different power into a different receiver. EN 15657 derives the
plate-independent quantities: the **equivalent blocked force level**
-(Formula 15, re $F_0 = 10^{-6}\ \text{N}$) from the low-mobility plate,
+(Formula 15, re $F_0 = 10^{-6}\ \text{N}$, not the 1 N reference of the
+ISO 16283-2
+[impact force exposure level](/phonometry/buildings/insulation/heavy-impact-sources/),
+120 dB away) from the low-mobility plate,
$$
L_{Fb,eq} = L_{Ws,\mathrm{low}} - 10\log_{10}\frac{\mathrm{Re}\{Y_{R,\mathrm{low,eq}}\}}{Y_0},
@@ -180,13 +195,44 @@ lwsn = building.characteristic_reception_plate_power(lfb) # Formula (17)
inst = building.installed_power_from_reception_plate(lwsn, 24.1e-6) # Annex I
print(round(float(lwsn), 1), round(float(inst), 1)) # 61.4 68.2 (Table I.8)
-# Free velocity (Formula 18) + blocked force close the source mobility (19):
+# The same Annex I correction taken to the SOURCE mobility instead gives the
+# plate-independent characteristic power level EN 12354-5 asks for as input:
+lwsc = building.installed_power_from_reception_plate(lwsn, 1.0e-3)
+print(round(float(lwsc), 1)) # 84.4 L_Ws,c
+
+# Free velocity (Formula 18) + blocked force close the source mobility (19).
+# The 1.0e-2 m/(N.s) is EN 15657's minimum specified high-mobility plate
+# mobility, not an arbitrary number.
lvf = building.equivalent_free_velocity_level(70.0, 1.0e-2)
print(float(building.source_mobility_from_levels(lvf, lfb))) # |Y_S,eq| in m/(N·s)
```
+Read the chain in order. The cistern injects 61.7 dB into the measurement
+plate; stripping that plate's mobility leaves an equivalent blocked force, and
+re-expressing the same force on the standard 10 cm concrete plate of
+$Y_{R,\infty,\text{low}} = 5\times10^{-6}\ \text{m/(N·s)}$ gives
+$L_{Wsn} = 61.4$ dB — the number a manufacturer may declare. Referring the same
+force to the actual receiving wall ($Y = 24.1\times10^{-6}$) adds
+$10\log_{10}(24.1/5.0) = 6.8$ dB and gives 68.2 dB. That step is the section's
+whole lesson: a light, high-mobility receiver accepts more power from the same
+source, so a declared $L_{Wsn}$ compares machines and is never the power a
+particular building will see.
+
+:::caution
+**Two quantities come out of the same correction; do not confuse them.**
+With the *receiver* mobility it gives the installed power level
+$L_{Ws,\mathrm{inst}} = 68.2$ dB. With the *source* mobility it gives the
+plate-independent characteristic power level $L_{Ws,c} = 84.4$ dB, and that is
+what [EN 12354-5](/phonometry/buildings/design/installed-structure-borne/) takes
+as its input, from which it subtracts the coupling term $D_C = 16.2$ dB to
+arrive back at the same 68.2 dB. Feed EN 12354-5 the 84.4, never the 68.2:
+carrying 68.2 forward as the characteristic power level subtracts $D_C$ a
+second time and lands 16 dB low, with no error raised.
+:::
+
The direct source-side counterpart is the ISO 9611 free velocity level (re
-$v_0 = 5\times10^{-8}\ \text{m/s}$) measured at the contact points of
+$v_0 = 5\times10^{-8}\ \text{m/s}$, the 50 nm/s reference of the callout above,
+not the 1 nm/s of Formula 14) measured at the contact points of
resiliently mounted
machinery; its equation (9) position average is `mean_free_velocity_level()`.
diff --git a/site/src/content/docs/buildings/insulation/flanking-lab.mdx b/site/src/content/docs/buildings/insulation/flanking-lab.mdx
index 455490fe1..e4ffd9acc 100644
--- a/site/src/content/docs/buildings/insulation/flanking-lab.mdx
+++ b/site/src/content/docs/buildings/insulation/flanking-lab.mdx
@@ -64,8 +64,10 @@ import ThemeImage from '../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../components/ReportPreview.astro';
EN 12354 predicts a building from its junctions, and ISO 10848 is how a
-junction gets its number. Two structurally decoupled elements meet in a
-laboratory junction rig; shakers and tapping machines drive one, and the
+junction gets its number. Two elements rigidly joined along a common edge are
+built into a laboratory rig whose rooms are structurally isolated from each
+other and from the surrounding structure, so the junction under test is the
+only path between them; shakers and tapping machines drive one element, and the
velocity level differences across the junction condense into the
**vibration reduction index** $K_{ij}$, together with the overall flanking
descriptors $D_{n,f}$ (airborne) and $L_{n,f}$ (impact). This guide covers
diff --git a/site/src/content/docs/buildings/insulation/heavy-impact-sources.mdx b/site/src/content/docs/buildings/insulation/heavy-impact-sources.mdx
index 55367331b..f0d59afd1 100644
--- a/site/src/content/docs/buildings/insulation/heavy-impact-sources.mdx
+++ b/site/src/content/docs/buildings/insulation/heavy-impact-sources.mdx
@@ -59,8 +59,9 @@ tapping-machine chain lives in
*Left: the two source specifications are pure spectra of force, not geometry.
-Right: the rating adds the A-weighted band contributions in energy, so the
-63 Hz band decides almost everything.*
+Right: the rating adds the A-weighted band contributions in energy, and the
+A-weighting is 23 dB steeper at 63 Hz than at 500 Hz, so the quietest measured
+band ends up deciding the number.*
## Both sources are specified by the energy of their force pulse
@@ -73,8 +74,12 @@ L_{FE} = 10\log_{10}\!\left[\frac{1}{T_\text{ref}}
\int_{t_1}^{t_2}\frac{F^2(t)}{F_0^2}\,\mathrm{d}t\right]\ \text{dB re 1 N},
$$
-with $F_0 = 1$ N, $T_\text{ref} = 1$ s and $t_2 - t_1$ the duration of the
-impact. Both characteristics require a **single-peak** waveform of
+with $F_0 = 1$ N (ISO 16283-2:2020 Annex A), $T_\text{ref} = 1$ s and
+$t_2 - t_1$ the duration of the impact. Watch the reference: EN 15657 refers
+its blocked-force levels to $F_0 = 10^{-6}$ N, 120 dB away, so a force level
+carried between this page and
+[Structure-borne sound power of equipment](/phonometry/buildings/design/structure-borne-power/)
+without conversion is wrong by exactly that. Both characteristics require a **single-peak** waveform of
$20 \pm 2$ ms (JIS A 1418-2:2019 A.2 b)). The octave-band values are printed
identically in ISO 16283-2:2020 Table A.1, ISO 10140-5:2010 Table F.1 and
JIS A 1418-2:2019 Table A.2 for the ball; the bang machine appears only in
@@ -88,7 +93,8 @@ JIS A 1418-2:2019 Table A.1.
| 250 | 17.0 ± 2.0 | 11.5 ± 2.0 |
| 500 | 12.5 ± 2.0 | 5.5 ± 2.0 |
-The bang machine puts 8 dB more energy into the two lowest octaves and 7 dB
+The bang machine puts 8 to 9 dB more energy into the two lowest octaves (8 dB
+at 31.5 Hz, 9 dB at 63 Hz) and 7 dB
less into the top one, which is why the two sources are not interchangeable and
why a floor can pass one and fail the other.
@@ -232,7 +238,7 @@ Because the A-weighting is 23 dB steeper at 63 Hz than at 500 Hz, a heavy
source's rating is dominated by whichever band survives that slope. For the
Table D.4 spectrum the four A-weighted contributions are 39.1, 48.3, 49.3 and
52.6 dB, so the 500 Hz band carries the most weight even though 63 Hz is the
-loudest band by 10 dB.
+loudest measured band, 9.5 dB above it.
## What this guide covers
diff --git a/site/src/content/docs/buildings/insulation/index.md b/site/src/content/docs/buildings/insulation/index.md
index f0c0acdc8..21eb6c888 100644
--- a/site/src/content/docs/buildings/insulation/index.md
+++ b/site/src/content/docs/buildings/insulation/index.md
@@ -9,8 +9,10 @@ characterised **in the laboratory**, where suppressed flanking isolates its
direct transmission. That laboratory data feeds a **prediction** of how a
whole building will perform, flanking paths included. The finished building is
then **verified in the field**. At every stage the band spectrum is collapsed
-to the **single number** regulations quote, and that collapse is one shared
-engine rather than a step of any single method.
+to the **single number** regulations quote, and for almost everything that
+collapse is one shared reference-curve engine rather than a step of any single
+method. The exception is the heavy-impact rating of ISO 717-2 Annex D, which
+shifts no curve at all: it sums A-weighted band levels in energy.
**Laboratory.**
[Laboratory Insulation Measurement](/phonometry/buildings/insulation/insulation-lab/) covers
@@ -33,6 +35,12 @@ and the two material measurements a floor design consumes.
[Field Insulation Measurement (ISO 16283)](/phonometry/buildings/insulation/insulation-field/)
covers the engineering-grade airborne and impact measurement in the building,
its Clause 14 test report and the ISO 12999-1 uncertainty that qualifies it.
+The same standard specifies two more impact sources, a rubber ball and a bang
+machine, for the slow low-frequency thumps a tapping machine says nothing
+about;
+[Heavy and Soft Impact Sources (ISO 16283-2)](/phonometry/buildings/insulation/heavy-impact-sources/)
+covers their specification, the Fast-weighted standardization of the maximum
+level and the Annex D rating.
When the question does not deserve that effort,
[Sound Insulation Survey Method (ISO 10052)](/phonometry/buildings/insulation/insulation-survey/)
trades accuracy for speed with octave bands and a reverberation index.
diff --git a/site/src/content/docs/buildings/insulation/insulation-field.mdx b/site/src/content/docs/buildings/insulation/insulation-field.mdx
index abf843ff8..34817d51c 100644
--- a/site/src/content/docs/buildings/insulation/insulation-field.mdx
+++ b/site/src/content/docs/buildings/insulation/insulation-field.mdx
@@ -25,11 +25,11 @@ references:
note: "The field airborne method this page implements: the level differences and normalisations."
- type: standard
organization: "International Organization for Standardization"
- year: 2015
+ year: 2020
title: "Acoustics — Field measurement of sound insulation in buildings and of building elements — Part 2: Impact sound insulation"
- designation: "ISO 16283-2:2015"
- url: "https://www.iso.org/standard/59747.html"
- note: "The field impact method: the standardized and normalized impact levels."
+ designation: "ISO 16283-2:2020"
+ url: "https://www.iso.org/standard/74162.html"
+ note: "The field impact method: the standardized and normalized impact levels, the Clause 14 test report and its Annex C results forms. The 2015 first edition is identical for the normalisations used here."
- type: standard
organization: "International Organization for Standardization"
year: 2020
@@ -77,10 +77,16 @@ prediction of in-situ performance in
## How do I compute DnT and R' from a field measurement in Python?
Energy-average the source- and receiving-room levels per one-third-octave band
-and pass them, with the receiving-room reverberation time, to
+across the microphone positions of one loudspeaker position, correct the
+receiving room for background noise, and pass them, with the receiving-room
+reverberation time, to
`building.airborne_insulation(l1, l2, t2, area=S, volume=V)`. The result
carries the raw level difference `d`, the standardized `dnt` and, when `area`
-and `volume` are given, the apparent `r_prime`. Impact measurements go through
+and `volume` are given, the apparent `r_prime`. If a single loudspeaker was
+moved between positions, repeat that for each position and combine the
+*results* with Formula (6), not the levels — see
+[Taking the measurement](#taking-the-measurement-iso-16283-1-clauses-7-and-9).
+Impact measurements go through
`building.impact_insulation(li, t2, volume=V)`, and either spectrum is rated
with `building.weighted_rating` / `weighted_impact_rating`.
@@ -151,12 +157,111 @@ ISO 717-1 reference curve.
| `area` | float, optional | m² | > 0, with `volume` | Partition area $S$ (enables $R'$) |
| `volume` | float, optional | m³ | > 0, with `area` | Receiving-room volume $V$ |
| `t0` | float | s | default `0.5` | Reference reverberation time $T_0$ |
+
`airborne_insulation()` returns an `AirborneInsulationResult` (`d`, `dnt`,
`r_prime` or `None`). The reference-curve engine that turns any of those
spectra into $R_w$, $R'_w$ or $D_{nT,w}$, its spectrum adaptation terms and its
enlarged-range variants are in
[Insulation Ratings (ISO 717)](/phonometry/buildings/insulation/insulation-ratings/).
+## Taking the measurement (ISO 16283-1 Clauses 7 and 9)
+
+The functions consume band levels; the standard says where those levels come
+from, and getting that wrong changes the answer more than any of the
+arithmetic above.
+
+**The source (Clause 7.1, 7.2).** Sound is generated with loudspeakers
+operated simultaneously in at least two positions, or with a single
+loudspeaker moved to at least two positions. Multiple loudspeakers must be of
+the same type, driven at the same level by similar but uncorrelated signals,
+and each must meet the Annex A directivity requirement. The signal is steady
+with a continuous spectrum, and the energy-average source-room level must not
+change by more than 8 dB between adjacent one-third-octave bands, at least
+above 100 Hz — shape the spectrum (a graphic equaliser is usually needed) or
+fall back to serial band-limited measurements. Loudspeakers stand at least
+0.5 m from any boundary, preferably at least 1.0 m from the separating
+partition, measured to the centre of the nearest speaker unit; different
+positions must not lie in planes parallel to a boundary less than 0.7 m apart,
+must be at least 0.7 m apart, and at least two of them at least 1.4 m apart.
+When the floor is the test element and the loudspeaker is in the upper room,
+its base sits at least 1.0 m above the floor.
+
+**The microphones (Clause 7.3).** A minimum of **five** positions per room —
+and, with a single loudspeaker moved between positions, five per room *per
+loudspeaker position*. No two positions may lie in the same plane relative to
+the room boundaries, and the set must not form a regular grid.
+
+### Correcting for background noise (Clause 9.2)
+
+Measure the receiving room again with the source off, at the same positions
+and with the same averaging, and compare band by band with the combined
+signal-plus-background level $L_{sb}$:
+
+- margin $\ge 10$ dB: use $L_{sb}$ unchanged;
+- $6 < \text{margin} < 10$ dB: subtract the background in energy,
+ $L = 10\log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ (Formula 14), with both
+ levels first reduced to one decimal place;
+- margin $\le 6$ dB: apply the fixed 1.3 dB correction, and flag the band in
+ the report as being at the limit of measurement.
+
+```python
+import numpy as np
+
+l2_sb = np.array([44.0, 41.0, 39.5, 38.0]) # receiving room, source on
+l2_bg = np.array([30.0, 33.0, 31.0, 34.0]) # receiving room, source off
+margin = l2_sb - l2_bg # 14.0 8.0 8.5 4.0 dB
+
+formula_14 = 10 * np.log10(10 ** (l2_sb / 10) - 10 ** (l2_bg / 10))
+l2_corr = np.where(margin >= 10.0, l2_sb,
+ np.where(margin > 6.0, formula_14, l2_sb - 1.3))
+print(np.round(l2_corr, 2)) # [44. 40.25 38.84 36.7 ] <- last band flagged
+```
+
+`building.background_correction` exists, but it implements the **ISO 10140-4
+laboratory** rule used on
+[Laboratory Insulation Measurement](/phonometry/buildings/insulation/insulation-lab/),
+whose upper threshold is 15 dB rather than 10 dB. Applied to field data it
+subtracts energy in the 10-15 dB margin band where ISO 16283-1 asks for
+nothing — up to 0.458 dB at a 10 dB margin — and since it acts on the
+receiving room that lands as over-reported insulation, band for band, in $D$.
+Use the three-regime expression above for field levels.
+
+### Averaging over loudspeaker positions (Formula 6)
+
+With **multiple loudspeakers operating simultaneously** (Clause 7.3.3) there
+is one measurement: energy-average the positions in each room, correct for
+background noise, and form $D_{nT}$ or $R'$ once. With a **single loudspeaker
+moved between positions** (Clause 7.3.4) the standard does *not* average the
+levels across loudspeaker positions. It forms the result for each position and
+averages the *results* as transmission factors,
+
+$$
+D_{nT} = -10\log_{10}\left[\frac{1}{m}\sum_{j=1}^{m} 10^{-D_{nT,j}/10}\right],
+$$
+
+which weights the worst position most. The two routes are not the same number:
+
+```python
+import numpy as np
+# `building` is the import of the airborne-insulation block above.
+
+t2 = np.full(16, 0.5)
+l1a, l2a = np.full(16, 80.0), np.full(16, 40.0) # loudspeaker position 1
+l1b, l2b = np.full(16, 83.0), np.full(16, 37.0) # loudspeaker position 2
+
+# Clause 7.3.4: one result per loudspeaker position, combined by Formula (6).
+a = building.airborne_insulation(l1a, l2a, t2, area=10.0, volume=50.0)
+b = building.airborne_insulation(l1b, l2b, t2, area=10.0, volume=50.0)
+dnt = -10 * np.log10(np.mean(10.0 ** (-np.vstack([a.dnt, b.dnt]) / 10.0), axis=0))
+print(round(float(dnt[0]), 1), building.weighted_rating(dnt).rating) # 42.0 42
+
+# Averaging the levels first instead: a different, more flattering number.
+l1m = building.energy_average_level(np.vstack([l1a, l1b]), axis=0)
+l2m = building.energy_average_level(np.vstack([l2a, l2b]), axis=0)
+naive = building.airborne_insulation(l1m, l2m, t2, area=10.0, volume=50.0)
+print(round(float(naive.dnt[0]), 1), building.weighted_rating(naive.dnt).rating) # 43.0 43
+```
+
## Field impact insulation (ISO 16283-2)
Footstep noise is rated the other way round. Instead of how much a floor
@@ -374,7 +479,10 @@ from phonometry import building
# Situation B (same building, different teams) -> the in-situ standard deviation.
print(building.single_number_uncertainty("r_w", "B")) # 0.9 dB (Table 3)
u = building.band_uncertainty("airborne", "B") # per-band u (Table 2)
-print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (the 500 Hz band)
+# Look the band up; never index by position. The impact table has no 500 Hz
+# band at all, so [10] would silently be 630 Hz there.
+i = list(u.frequencies).index(500.0)
+print(len(u.frequencies), u.uncertainties[i]) # 21 1.1 (the 500 Hz band)
u.plot() # the per-band u(f) spectrum of Table 2 (needs matplotlib)
# Report R'w = 52 dB with a two-sided 95 % interval (k = 1.96, Table 8):
@@ -459,7 +567,7 @@ power off the radiating face instead of the receiving-room level, is
**Covered.** ISO 16283-1:2014 (airborne field insulation: the level
difference, standardized $D_{nT}$ and apparent $R'$ of Clause 3.12-3.15 and
-the Clause 7.8 position averaging) and ISO 16283-2:2015 (impact field
+the Clause 7.8 position averaging) and ISO 16283-2:2020 (impact field
insulation, the same normalisations with the sign flip) through
`building.energy_average_level`, `building.airborne_insulation` and
`building.impact_insulation`, each writing the Clause 14 test report with
@@ -471,8 +579,13 @@ single-number ratings quoted here reuse the verified ISO 717-1/ISO 717-2
engines.
**Not covered.** Every field function here takes levels that the caller has
-already corrected for background noise (Clause 9.2 of ISO 16283-1); the
-background-noise measurement and correction itself is not implemented.
+already corrected for background noise (Clause 9.2 of ISO 16283-1). The
+*measurement* of the background level — source off, same positions, same
+averaging — is the operator's job, and nothing here verifies that the 6 dB
+floor was met; the correction itself is three lines of NumPy, written out
+under [Correcting for background noise](#correcting-for-background-noise-clause-92)
+above. (`building.background_correction` is the ISO 10140-4 *laboratory*
+variant and does not match the field thresholds.)
ISO 16283-1/-2's own position and procedure requirements (the minimum number
of source and microphone positions, the low-frequency loudspeaker or
microphone-sweep procedures) are not checked: energy-averaging happens once
diff --git a/site/src/content/docs/buildings/insulation/insulation-intensity.mdx b/site/src/content/docs/buildings/insulation/insulation-intensity.mdx
index d8c448f11..179b3ba0f 100644
--- a/site/src/content/docs/buildings/insulation/insulation-intensity.mdx
+++ b/site/src/content/docs/buildings/insulation/insulation-intensity.mdx
@@ -63,11 +63,20 @@ $$
where the $6$ dB is the diffuse-field offset between the sound pressure level
and the incident intensity level. The same formula gives the apparent index
-$R'_I$ in the field (ISO 15186-2). Because the intensity method slightly
-*underestimates* the power radiated into a real receiving room, a **modified
-index** $R_{I,M} = R_I + K_c$ reproduces the ISO 10140-2 pressure result; the
-adaptation term $K_c$ (Annex B) is $10 \log_{10}(1 + S_{b2}\lambda/8V_2)$ for a
-well-defined room, or the room-independent $10 \log_{10}(1 + 61.4/f)$. For small
+$R'_I$ in the field (ISO 15186-2). The intensity scan measures the transmitted
+power directly. The reverberation-room pressure method does not: it infers the
+power from the receiving-room level and so *underestimates* it, which makes the
+ISO 10140-2 $R$ come out slightly high. The **modified index**
+$R_{I,M} = R_I + K_c$ adds that same bias back to the intensity result, so an
+intensity measurement can be quoted against pressure-method data
+(ISO 15186-1, Clause 3.10 NOTE 1). Report $R_I$ when the aim is the true
+transmitted power; report $R_{I,M}$ when the aim is comparability with an
+ISO 10140-2 result. Earlier revisions of this guide blamed the bias on the
+intensity method itself, which would have called for subtracting $K_c$, not
+adding it. The adaptation term $K_c$ (Annex B) is $10 \log_{10}(1 + S_{b2}\lambda/8V_2)$ for a
+well-defined room, or the room-independent $10 \log_{10}(1 + 61.4/f)$. The
+first form is the Waterhouse boundary-energy term, which makes the second
+readable as that same term evaluated at a fixed $S_{b2}/V_2$. For small
elements the **element normalized level difference** replaces $10\log_{10}(S_m/S)$
with $10\log_{10}(S_m/A_0) + 10\log_{10} N$ ($A_0 = 10\ \text{m}^2$, $N$ element units).
diff --git a/site/src/content/docs/buildings/insulation/insulation-survey.mdx b/site/src/content/docs/buildings/insulation/insulation-survey.mdx
index 90f9832e6..1761f20a6 100644
--- a/site/src/content/docs/buildings/insulation/insulation-survey.mdx
+++ b/site/src/content/docs/buildings/insulation/insulation-survey.mdx
@@ -50,12 +50,39 @@ EN ISO 10052:2004+A1:2010.
The reverberation index is either **measured** (feed the reverberation time to
`reverberation_index(T)`) or, in a control survey, **estimated** from the room
-type and volume with `estimate_reverberation_index(V, room)` (Table 4:
-furnished `"kitchen"` / `"bathroom"` / `"furnished"`, or the unfurnished
-construction classes `"a"`–`"h"` and the mixed `"a+e"`…`"d+h"`). A fourth
+type and volume with `estimate_reverberation_index(V, room)`: furnished
+`"kitchen"` / `"bathroom"` / `"furnished"`, or the unfurnished construction
+classes `"a"`–`"h"` and the mixed `"a+e"`…`"d+h"`. Clause 6.5 splits that in
+two — **Table 3** classifies the room and gives it its letter, **Table 4**
+turns the letter and the volume into the index. A fourth
quantity unique to this method is **service-equipment noise** $L_{XY}$: the
energy average of three A- or C-weighted positions.
+The letters are not arbitrary: Table 3 is a 2 × 2 × 2 grid over the weight of
+the walls and ceiling, the hardness of the floor covering and the weight of
+the floor construction.
+
+| Walls and ceiling | Soft covering, light floor | Soft covering, heavy floor | Hard covering, light floor | Hard covering, heavy floor |
+| :--- | :---: | :---: | :---: | :---: |
+| Light | `a` | `b` | `c` | `d` |
+| Heavy | `e` | `f` | `g` | `h` |
+
+A **light wall** is plasterboard or timber studwork, and a heavy wall carrying
+a plasterboard lining counts as light; a **heavy wall** is unlined masonry or
+block. A **light floor** is planks or boards on timber beams, a **heavy
+floor** a concrete slab. The **covering** is carpet (soft) against tiles or
+timber flooring (hard). Where the room mixes two constructions over roughly
+equal areas, average the two letters — that is what the mixed classes
+`"a+e"`…`"d+h"` are; where one construction clearly dominates by area, use its
+letter alone. Note that the covering and the floor construction are two
+separate axes, so "a hard floor" on its own does not pick a class.
+
+Table 4 comes from a statistical survey of European dwellings built between
+1960 and 1980 (NOTE 1): the standard deviation of the tabulated indices is
+about 1 dB, and the table is valid for $T_0 = 0.5\ \text{s}$ and rooms up to
+150 m³. Changed construction methods or habitation habits can shift it
+systematically, so measure $T$ when the result has to hold up.
+
```python
import numpy as np
from phonometry import building
@@ -69,10 +96,10 @@ print(np.round(res.d_nt, 1)) # [34.5 39.8 45. 50.5 54. ] DnT = D + k
print(res.rating.rating, res.rating.c) # 49 -1 -> DnT,w (C)
print(res.r_prime_rating.rating) # 48 -> R'w
-# No reverberation time measured? Estimate k from Table 4 (heavy walls, hard
-# floor, 35-60 m3 -> class "g").
-k_est = building.estimate_reverberation_index(50.0, "g")
-print(k_est) # [4.5 5. 5.5 5.5 5.5]
+# No reverberation time measured? Classify with Table 3, then read Table 4:
+# heavy masonry walls, concrete slab, tiled floor, 35-60 m3 -> class "h".
+k_est = building.estimate_reverberation_index(50.0, "h")
+print(k_est) # [5. 5.5 6. 5. 5.5]
# Service-equipment noise: energy average of three A-weighted positions.
se = building.survey_service_equipment_level([35.0, 30.0, 32.0], 3.0, volume=50.0)
@@ -118,6 +145,21 @@ plt.show()
+### Background noise: a floor to meet, not a correction to apply
+
+Unlike the engineering methods, the survey method never corrects for
+background noise (Clause 6.2.1). It fixes a signal-to-noise floor instead:
+adjust the source so that the receiving-room level exceeds the background by
+at least 6 dB in every band, checked by switching the source on and off before
+the run. Where the margin still falls below 6 dB, record the uncorrected level
+and state in the report that the level difference is underestimated — or, for
+service equipment, that the level is overestimated — by an unknown amount.
+That is why no correction call appears anywhere on this page:
+`building.background_correction` implements the ISO 10140-4 laboratory rule
+and must not be applied to survey data. Earlier revisions of this guide said
+the opposite, listing the correction as the caller's job; a survey corrected
+that way is non-conforming and over-reports the insulation.
+
### `survey_airborne_insulation()` and friends: parameters
| Parameter | Type | Units | Range / default | Notes |
@@ -128,7 +170,7 @@ plt.show()
| `volume` | float | m³ | > 0 | Receiving-room $V$ (for $D_n$ / $L'_n$ / $R'$ / normalized) |
| `area` | float | m² | > 0 | Common-partition $S$ (airborne $R'$; $V/7.5$ rule applied) |
| `measurements` | array | dB | exactly 3 | Service-equipment positions (`survey_service_equipment_level`) |
-| `room` | str | — | `"kitchen"`/`"bathroom"`/`"furnished"`/`"a"`–`"h"`/`"a+e"`… | `estimate_reverberation_index` room class (Table 4) |
+| `room` | str | — | `"kitchen"`/`"bathroom"`/`"furnished"`/`"a"`–`"h"`/`"a+e"`… | `estimate_reverberation_index` room class (Table 3; the index itself is Table 4) |
`survey_airborne_insulation()` returns a `SurveyAirborneResult` (`d`, `d_nt`,
`d_n`, `r_prime`, `rating`, `r_prime_rating`); `survey_impact_insulation()` a
@@ -235,7 +277,7 @@ plt.show()
**Covered.** The ISO 10052:2021 survey method: the reverberation index
$k = 10\log_{10}(T/T_0)$ measured with `building.reverberation_index` or
-estimated from the Table 4 room classes with
+estimated from the Table 3 room classes with
`building.estimate_reverberation_index`; the survey airborne, impact and
façade quantities ($D_{nT}$, $D_n$, $R'$ with the $V/7.5$ rule, $L'_{nT}$,
$L'_n$, $D_{2m,nT}$) via `building.survey_airborne_insulation`,
@@ -248,8 +290,9 @@ fiches through `.report()`.
**Not covered.** The survey procedure itself (where to hold the meter, the
fixed measurement heights, the tapping-machine placement of the control
method) is not checked: the functions consume band levels wherever they
-came from. Background-noise correction is the caller's job, as in the
-engineering methods. The survey method's accuracy statement relative to
+came from. Nothing verifies that the 6 dB signal-to-background floor of
+Clause 6.2.1 was met, and no correction is applied when it was not — that is
+the method's own rule, not an omission. The survey method's accuracy statement relative to
ISO 16283 is quoted from the standard, not modelled; when the stakes rise,
step up to
[Field Insulation Measurement (ISO 16283)](/phonometry/buildings/insulation/insulation-field/).
diff --git a/site/src/content/docs/buildings/insulation/spanish-building-code.mdx b/site/src/content/docs/buildings/insulation/spanish-building-code.mdx
index 375641528..27fef1134 100644
--- a/site/src/content/docs/buildings/insulation/spanish-building-code.mdx
+++ b/site/src/content/docs/buildings/insulation/spanish-building-code.mdx
@@ -221,6 +221,7 @@ common areas sharing doors with protected rooms, the equivalent sound
absorption area must be at least 0.2 m² per cubic metre of volume.
```python
+import numpy as np
from phonometry import building
facade = building.db_hr_facade_requirement(65.0, "residential", "bedrooms")
@@ -234,10 +235,29 @@ building.db_hr_party_wall_requirement().limit # 40 dBA p
building.db_hr_party_wall_requirement("DnT,A").limit # 50 dBA both together
building.db_hr_reverberation_requirement("classroom").limit # 0.7 s
-check = building.assess_db_hr([(33.0, facade), (51.44, airborne[0])])
+# The between-rooms requirement is stated in DnT,A, so the party-wall R' of the
+# field report cannot be checked against it as it stands. Re-reference it first:
+# a receiving room of V = 50 m3 with T = 0.5 s behind a partition of S = 12 m2
+# has A = 0.16 V / T = 16 m2, and DnT = R' + 10 lg(A/S) + 10 lg(T/T0).
+d_nt = np.asarray(r_prime) + 10 * np.log10(16.0 / 12.0) + 10 * np.log10(0.5 / 0.5)
+building.dnt_a(d_nt).intermediate # 52.7 dBA (R'A was 51.4 dBA)
+
+check = building.assess_db_hr([(33.0, facade), (52.7, airborne[0])])
check.complies # True
```
+The quantity has to match the requirement. DB-HR states the between-rooms limit
+in $D_{nT,A}$, and $R'$ and $D_{nT}$ normalise the same level difference by
+different things — $R' = D + 10\log_{10}(S/A)$ by the partition area and the
+receiving-room absorption, $D_{nT} = D + 10\log_{10}(T/T_0)$ by the
+reverberation time — so an $R'_A$ from a field report has to be converted
+through the room's $T$ and the partition area before it means anything against
+the 50 dBA. Only the *tabiquería* requirement ($R_A \ge 33$ dBA) is stated in
+the $R_A$ family. Earlier revisions of this page checked the party wall's
+$R'_A = 51.4$ dBA straight against the $D_{nT,A}$ requirement: the verdict
+happened to come out the same here, but the comparison was between two
+different quantities and nothing guarantees the agreement in general.
+
`check_db_hr_requirement()` rounds the achieved value the way DB-HR asks before
comparing it (to an integer for the dB quantities, to one decimal for the
reverberation time) and returns the margin; `assess_db_hr()` does the same over
diff --git a/site/src/content/docs/buildings/rooms/enclosed-space-absorption.mdx b/site/src/content/docs/buildings/rooms/enclosed-space-absorption.mdx
index 9ba9d60ca..e850b81fa 100644
--- a/site/src/content/docs/buildings/rooms/enclosed-space-absorption.mdx
+++ b/site/src/content/docs/buildings/rooms/enclosed-space-absorption.mdx
@@ -115,9 +115,14 @@ result = room.enclosed_space_reverberation(
)
print(result.reverberation_time.round(2))
# [2.13 1.03 0.62 0.48 0.43 0.42 0.4 ]
-result.plot() # the figure below: A and T per octave band
+result.plot() # A and T per octave band, for this room alone
```
+The figure below runs that call twice, once with the acoustic tile above and
+once with the ceiling left as bare plaster, so the treatment can be read off as
+a difference. The `[2.13 1.03 …]` printed above is its "acoustic ceiling"
+curve; `result.plot()` draws that curve on its own.
+
@@ -139,6 +144,15 @@ plt.show()
+*The same 60 m³ office with two ceilings. Swapping 20 m² of plaster for
+acoustic tile multiplies the equivalent absorption area by 4 to 5 above
+500 Hz (4.0 m² to 20.2 m² at 1 kHz) and pulls the reverberation time from
+2.4 s to 0.48 s there. The 125 Hz band, where the tile is weakest, improves
+least — 1.9 m² to 4.5 m², and 5.04 s only down to 2.13 s: a 20 mm porous tile
+is a small fraction of a 2.7 m wavelength and absorbs by friction only where
+the particle velocity is high, so low-frequency control needs depth, an air gap
+or a resonant absorber.*
+
The `ReverberationResult` carries the per-band absorption area and reverberation
time, the volume and the object fraction, and its `.plot()` draws the
reverberation-time spectrum. This is the prediction counterpart of the measured
diff --git a/site/src/content/docs/buildings/rooms/open-plan-acoustics.mdx b/site/src/content/docs/buildings/rooms/open-plan-acoustics.mdx
index 067d8efc4..da6611096 100644
--- a/site/src/content/docs/buildings/rooms/open-plan-acoustics.mdx
+++ b/site/src/content/docs/buildings/rooms/open-plan-acoustics.mdx
@@ -24,8 +24,10 @@ import ReportPreview from '../../../../components/ReportPreview.astro';
An open-plan office is not a reverberation problem; it is a privacy
problem, and a room that flatters the closed-room parameters can still fail
-it. ISO 3382-3 therefore characterises the office with four single numbers
-measured along a line of workstations, walking away from a talker. This
+it. ISO 3382-3 therefore characterises the office with four single numbers —
+$r_D$, $D_{2,S}$, $L_{p,A,S,4m}$ and the average background noise
+$L_{p,A,B}$ — measured along a line of workstations, walking away from a
+talker. This
guide covers that measurement chain: the quantities, the to-scale
measurement line and the accredited fiche. The impulse responses and levels
behind it are acquired as in
@@ -40,7 +42,12 @@ the closed-room decay parameters live in
Open-plan acoustics are about **speech privacy**: how fast a talker's speech
fades to unintelligibility as you walk away. Levels and STI are measured
along a line of workstations (at least 4 positions, 6–10 preferred), and
-four single-number quantities summarise the room. The **spatial decay
+four single-number quantities summarise the room: the distraction distance
+$r_D$, the spatial decay rate $D_{2,S}$, the speech level at 4 m
+$L_{p,A,S,4m}$ and the average A-weighted background noise $L_{p,A,B}$
+(Clause 6.4). The privacy distance $r_P$ and the STI at the nearest workstation
+are optional additions; `open_plan_metrics` returns $D_{2,S}$,
+$L_{p,A,S,4m}$, $r_D$ and $r_P$. The **spatial decay
rate** of A-weighted speech is the slope of the level against
$\log_{10}(r/r_0)$, scaled to a per-doubling figure using only the 2–16 m
positions,
@@ -54,7 +61,20 @@ distance** $r_D$ (STI = 0.50) and **privacy distance** $r_P$ (STI = 0.20) come
from a linear regression of STI against distance. Good offices push $r_D$
below ~5 m; poor ones leave speech distracting past 10 m.
-
+$L_{p,A,B}$ is the fourth required quantity and it is not decoration: the
+background noise is measured in octave bands at every position with the same
+$\ge 10$ s integration, A-weighted, and averaged over the line, and that
+average is the masker the per-position STI is computed against. Spatially
+averaging it is what keeps $r_D$ and $r_P$ unambiguous. It is also why
+open-plan design has two levers rather than one — **attenuation** (screens, an
+absorptive ceiling, layout: these raise $D_{2,S}$ and lower $L_{p,A,S,4m}$) and
+**masking** (raising the background so speech loses intelligibility sooner) —
+and why the office is measured furnished, unoccupied and with the services
+running. An office measured with the ventilation or the masking system turned
+down returns a higher STI at every position and pushes both distances outward
+by metres with nothing having changed in the room.
+
+
```python
import numpy as np
@@ -163,12 +183,89 @@ plt.show()
+### From the measured pink noise to $L_{p,A,S,n}$
+
+A loudspeaker is not a talker, so ISO 3382-3 never uses its level directly.
+Clause 6.2 measures the *room* with pink noise and then re-clothes the result
+in the spectrum of a real voice. What is kept from each position is not its
+absolute level but the band-by-band attenuation relative to the source at 1 m
+(Eq. 1-2), so the loudspeaker's output level cancels out and only has to sit
+far enough above the background:
+
+$$
+L_{p,Ls,1m,i} \approx L_{W,Ls,i} - 11\ \text{dB},
+\qquad
+D_{n,i} = L_{p,Ls,1m,i} - L_{p,Ls,n,i} .
+$$
+
+That attenuation is then applied to the normal-effort speech spectrum
+(Eq. 3), A-weighted and summed energetically over the seven octave bands
+(Eq. 4):
+
+$$
+L_{p,S,n,i} = L_{p,S,1m,i} - D_{n,i},
+\qquad
+L_{p,A,S,n} = 10\log_{10}\sum_i 10^{(L_{p,S,n,i} + A_i)/10} .
+$$
+
+Table 1 supplies the omnidirectional normal-effort spectrum and the
+A-weightings:
+
+| Band $i$ | $f$ [Hz] | $L_{p,S,1m,i}$ [dB] | $A_i$ [dB] |
+| ---: | ---: | ---: | ---: |
+| 1 | 125 | 49.9 | −16.1 |
+| 2 | 250 | 54.3 | −8.6 |
+| 3 | 500 | 58.0 | −3.2 |
+| 4 | 1000 | 52.0 | 0.0 |
+| 5 | 2000 | 44.8 | +1.2 |
+| 6 | 4000 | 38.8 | +1.0 |
+| 7 | 8000 | 33.5 | −1.1 |
+
+whose A-weighted total is 57.4 dB — a normal talking voice at 1 m.
+
+**The A-weighted pink-noise reading on the meter is not the input
+`open_plan_metrics` expects.** Feeding it in gives an absolute level that is
+the loudspeaker's, not a talker's, so $L_{p,A,S,4m}$ is wrong outright and
+$D_{2,S}$ is biased by the spectral difference between pink noise and speech.
+Run the four-step chain first:
+
+```python
+import numpy as np
+# `room` is the import of the open_plan_metrics block above.
+
+# ISO 3382-3 Table 1: normal-effort unisex speech at 1 m, omnidirectional,
+# and the A-weighting, octave bands 125 Hz to 8 kHz.
+speech_1m = np.array([49.9, 54.3, 58.0, 52.0, 44.8, 38.8, 33.5])
+a_weight = np.array([-16.1, -8.6, -3.2, 0.0, 1.2, 1.0, -1.1])
+
+# Measured octave-band pink-noise levels, one row per measurement position.
+pink = np.array([
+ [72.0, 71.0, 70.0, 69.0, 67.0, 64.0, 60.0],
+ [67.0, 66.0, 64.5, 63.0, 60.5, 57.0, 52.5],
+ [63.5, 62.0, 60.0, 58.0, 55.0, 51.0, 46.0],
+ [60.0, 58.5, 56.0, 53.5, 50.0, 45.5, 40.0],
+])
+source_1m = np.full(7, 90.0) - 11.0 # Eq. (1): Lp,Ls,1m = Lw,Ls - 11 dB
+
+d_n = source_1m - pink # Eq. (2): attenuation per band
+speech_n = speech_1m - d_n # Eq. (3): re-clothed in speech
+lp_a_s = 10 * np.log10(np.sum(10 ** ((speech_n + a_weight) / 10), axis=1))
+print(np.round(lp_a_s, 1)) # [48. 42.4 37.8 33.8] Eq. (4)
+
+dist = np.array([2.0, 4.0, 8.0, 16.0])
+chain = room.open_plan_metrics(dist, lp_a_s, 0.70 - 0.03 * dist)
+print(round(chain.d2s, 1), round(chain.lp_as_4m, 1)) # 4.7 42.9
+```
+
+The band arithmetic itself — A-weighting and energetic summation — is the
+same as in [Levels](/phonometry/signals/levels/levels/).
+
### `open_plan_metrics()` parameters
| Parameter | Type | Units | Range / default | Notes |
| :--- | :--- | :--- | :--- | :--- |
| `positions_m` | 1D array | m | ≥ 4 positions, all > 0 | Source-to-receiver distances |
-| `spl_a_speech` | 1D array | dB | same length | A-weighted speech level $L_{p,A,S,n}$ per position |
+| `spl_a_speech` | 1D array | dB | same length | A-weighted speech level $L_{p,A,S,n}$ per position, from the Clause 6.2 Eq. (1)-(4) chain — **not** the measured pink-noise dB(A) |
| `sti_values` | 1D array | — | same length | STI per position (full IEC 60268-16 method) |
Returns an `OpenPlanResult` with `d2s`, `lp_as_4m`, `rd` and `rp`; its
@@ -183,8 +280,8 @@ STI can itself be measured with the STIPA tools in the
`OpenPlanResult.report(path)` renders a one-page PDF fiche laid out like an
open-plan-office speech-privacy measurement report: a standard-basis line, an
-optional metadata header block, a compact metrics table of the four
-single-number quantities of Clause 4 ($D_{2,S}$, $L_{p,A,S,4m}$, the
+optional metadata header block, a compact metrics table of the four quantities
+`open_plan_metrics` returns ($D_{2,S}$, $L_{p,A,S,4m}$, the
distraction distance $r_D$ and the privacy distance $r_P$) stacked above the
full-width spatial-decay plot (`.plot()`, the Clause 6.2 regression on the
logarithmic distance axis with the 4 m read-off and the $r_D$ / $r_P$ crossings
@@ -383,6 +480,10 @@ Chapter 17 crowd self-noise model (Eqs. (17.50) to (17.54)) through
`open_plan_metrics` rather than computed inside it: measure it with the
STIPA tools of the
[Speech Transmission Index guide](/phonometry/perception/speech/speech-transmission/).
+The fourth required single number, the average A-weighted background noise
+$L_{p,A,B}$, is likewise not computed here — it is the energetic A-weighted
+average of the per-position octave-band background levels, and it belongs in
+the report alongside the three this page produces.
The standard's measurement procedure itself (loudspeaker directivity, the
unoccupied-versus-furnished conditions, background-noise capture) is not
checked: the function consumes distances, levels and STI values wherever
diff --git a/site/src/content/docs/buildings/rooms/reverberation-prediction.mdx b/site/src/content/docs/buildings/rooms/reverberation-prediction.mdx
index 5a27c422e..509581072 100644
--- a/site/src/content/docs/buildings/rooms/reverberation-prediction.mdx
+++ b/site/src/content/docs/buildings/rooms/reverberation-prediction.mdx
@@ -351,8 +351,28 @@ point, that stays diffuse while it decays. The common breakages:
Scattering objects restore the mixing the models assume: a furnished room
follows the statistical prediction distinctly better than the same room
-bare, beyond what the furniture's own absorption area accounts for. In
-practice, quote a *band* of predictions (Sabine and Eyring, or Fitzroy and
+bare, beyond what the furniture's own absorption area accounts for. The clip
+below is that mechanism with the absorption taken out of it, so only the
+mixing is left: an 800 Hz wavefront enters a 4 m rigid-walled hall filled
+with rigid columns 10 to 17 cm across, a quarter to two fifths of the
+42.9 cm wavelength. Every column diffracts the front and sheds a scattered
+wavelet, the wavelets interfere, and within a few passes the specular front
+has become energy spread over the whole hall with no preferred direction —
+which is the assumption Sabine and Eyring both start from, arriving here as
+a result rather than as a hypothesis. Nothing in the hall absorbs, so what
+you are watching is *only* the redistribution; the decay at the end is the
+energy draining out through the two open ends.
+
+
+
+In practice, quote a *band* of predictions (Sabine and Eyring, or Fitzroy and
Arau-Puchades for axial cases) rather than a single value; where the models
spread, the room is telling you its field is not diffuse.
diff --git a/site/src/content/docs/buildings/rooms/room-image-sources.mdx b/site/src/content/docs/buildings/rooms/room-image-sources.mdx
index dfe4617b1..f11c7cbd3 100644
--- a/site/src/content/docs/buildings/rooms/room-image-sources.mdx
+++ b/site/src/content/docs/buildings/rooms/room-image-sources.mdx
@@ -106,21 +106,23 @@ res = room.image_source_rir(
receiver=(5.2, 3.4, 1.7),
absorption=0.12, # uniform wall absorption (scalar)
fs=48000,
- max_order=12,
+ # Enough order to cover a T30 fit; see "Choosing max_order, duration and
+ # fs" below. The default 20 truncates this room's tail by half.
+ max_order=60,
)
print(res.ir.shape) # (n_samples,) broadband RIR
-print(round(res.direct_time * 1000, 2)) # direct-sound arrival, ms
-print(res.times.size == room.audible_image_count(12) + 1) # images + source
+print(round(res.direct_time * 1000, 2)) # 10.72 direct-sound arrival, ms
+print(res.times.size == room.audible_image_count(60) + 1) # images + source
-res.plot() # the reflectogram of the figure below
+res.plot() # the reflectogram; the figure below draws the same room at order 10
# The synthetic RIR flows straight into the ISO 3382 decay analysis.
params = room.room_parameters(res.ir, res.fs, limits=None)
print(bool(params.t30_valid[0])) # True: the decay window is usable
-# T30 rises toward the Eyring estimate as max_order grows (see below); at a low
-# order the specular tail is truncated, so treat this as an order-limited value.
-print(round(float(params.t30[0]), 2)) # reverberation time, s
+print(round(float(params.t30[0]), 2)) # 1.06 s, specular
+print(round(float(room.eyring_reverberation_time(105.0, [(142.0, 0.12)])), 2))
+# 0.93 s, the diffuse-field Eyring estimate for the same room
```
`image_source_rir` returns an `ImageSourceResult`. Its `ir` is the sampled RIR
@@ -249,6 +251,52 @@ with `.plot()` and a `direct_time` property. `audible_image_count(order)` gives
the shoebox image count and `reflection_density(t, volume)` the density
$4\pi c^3 t^2 / V$.
+### Choosing `max_order`, `duration` and `fs`
+
+`max_order` is not a quality knob, it is a **time horizon**. The image lattice
+is complete only out to a radius of roughly `max_order` × the shortest room
+dimension, so covering $t$ seconds of decay needs
+
+$$
+\text{order} \approx \frac{c\,t}{L_\text{min}} .
+$$
+
+A T30 fit spans 35 dB, about $0.58\,T$ of decay. The 7 × 5 × 3 m room above has
+$L_\text{min} = 3$ m and an Eyring time near 0.93 s, so it needs
+$343 \times 0.54 / 3 \approx 60$. Below that the tail is simply missing, and
+the fitted T30 comes out short:
+
+| `max_order` | audible images | fitted T30 | runtime |
+| ---: | ---: | ---: | ---: |
+| 12 | 2 624 | 0.28 s | < 0.1 s |
+| 20 (default) | 11 520 | 0.43 s | < 0.1 s |
+| 30 | 37 880 | 0.60 s | < 0.1 s |
+| 40 | 88 640 | 0.75 s | 0.1 s |
+| 60 | 295 360 | 1.06 s | 0.2 s |
+
+The Eyring estimate for this room is 0.93 s, so order 12 is 3.3× short and the
+default 20 is 2.1× short. The cost objection does not apply: order 60 is
+295 360 images and runs in a fifth of a second.
+
+**`t30_valid` cannot see a truncated lattice.** It reads the decay range of
+whatever array it is handed, so it returns `True` at every order in the table
+above. The flag catches a noisy or too-short *recording*; it cannot catch a
+model that stopped generating reflections. A `duration` shorter than the decay
+truncates the tail exactly the same way, and silently.
+
+Two more caveats belong to the same section. `fs` quantises every arrival to
+the sample grid, so early-reflection work — arrival times, ITDG, lateral
+fractions — should read the exact `times` / `amplitudes` table rather than
+peak-pick the sampled `ir`. And `absorption` enters as a real,
+angle-independent pressure reflection factor $\sqrt{1-\alpha}$, so grazing
+incidence is treated like normal incidence.
+
+Finally, the honest boundary: if the order needed to cover the reverberation
+time makes the run impractical — a large room with a small $L_\text{min}$, or a
+long tail — the pure image method is being asked to do a job that belongs to a
+hybrid model with a statistical late tail, or to the
+[FDTD solver](/phonometry/simulation/fdtd-simulation/).
+
## 2. Steady-state room field
When a source of constant sound power runs in a room, the level settles to the
@@ -443,6 +491,39 @@ frequency ($T = 0.8$ s) the oblique family has filled in and the modal density
has passed one mode per hertz, which is where the statistical field of §2 takes
over.*
+
+Show the code for this figure
+
+```python
+import matplotlib.pyplot as plt
+import numpy as np
+# `room` is the import of the room_modes block above.
+
+# Long, Architectural Acoustics 2nd ed., Table 8.1.
+modes = room.room_modes((7.0, 5.0, 3.0), max_frequency=200.0,
+ speed_of_sound=344.0, reverberation_time=0.8)
+
+# One line: the mode ladder by family with the modal density below.
+modes.plot()
+plt.show()
+
+# By hand: scatter the eigenfrequencies, one row per family.
+kinds = np.asarray(modes.kinds)
+rows = {"axial": 0, "tangential": 1, "oblique": 2}
+fig, ax = plt.subplots()
+for name, y in rows.items():
+ sel = kinds == name
+ ax.vlines(np.asarray(modes.frequencies)[sel], y, y + 0.8, label=name)
+ax.axvline(modes.schroeder_frequency, ls=":", color="k",
+ label=f"Schroeder {modes.schroeder_frequency:.0f} Hz")
+ax.set_yticks([0.4, 1.4, 2.4], list(rows))
+ax.set_xlabel("Frequency [Hz]")
+ax.legend()
+plt.show()
+```
+
+
+
### `room_modes()` parameters
| Parameter | Type | Units | Range / default | Notes |
diff --git a/site/src/content/docs/devices/broadcast/program-loudness.mdx b/site/src/content/docs/devices/broadcast/program-loudness.mdx
index fc62788ec..435225a94 100644
--- a/site/src/content/docs/devices/broadcast/program-loudness.mdx
+++ b/site/src/content/docs/devices/broadcast/program-loudness.mdx
@@ -91,8 +91,31 @@ t = np.arange(20 * fs) / fs
x = np.zeros((5, t.size)) # L, R, C, Ls, Rs
x[0] = np.sin(2 * np.pi * 997.0 * t) # 0 dB FS on the left channel
print(round(broadcast.integrated_loudness(x, fs), 2)) # -3.01 LKFS
+
+# The same waveform on two channels instead of one (see below):
+mono = np.sin(2 * np.pi * 997.0 * t)
+print(round(broadcast.integrated_loudness(mono, fs), 2)) # -3.01
+print(round(broadcast.integrated_loudness(np.vstack([mono, mono]), fs), 2)) # 0.00
```
+### Channels are summed, not averaged
+
+Formula 2 sums $G_i z_i$ over the channels, so the channel count is part of the
+measurement: the same waveform carried on two channels is exactly
+$10\log_{10} 2 = 3.01$ LU louder than on one. The anchor above shows it — that
+full-scale 997 Hz sine reads −3.01 LKFS on a single channel and 0.00 LKFS as
+dual mono, which is what the last two lines of the snippet above print.
+
+Meter the delivery format, not a stem. A mono podcast delivered as one channel
+is compliant at −23 LUFS as one channel; duplicating it to stereo before
+metering makes it read −20 LUFS and invites a 3 dB correction in the wrong
+direction. The same arithmetic is why the LFE is excluded (Table 3, $G = 0$)
+and why the surround weights are 1.41: the sum is a loudness sum over the
+reproduction layout, so changing the layout changes the number legitimately.
+The `np.vstack` in the snippets below is exactly this — dual mono, the stereo
+delivery of a mono source — and it is why they read 3.01 LU above the
+single-channel value of the same waveform.
+
The biquad coefficients are tabulated at 48 kHz (Tables 1-2) and returned
verbatim at that rate; any other rate re-derives them through the analog
prototype so the response matches the specification (within 0.02 dB at
diff --git a/site/src/content/docs/devices/electroacoustics/loudspeakers.mdx b/site/src/content/docs/devices/electroacoustics/loudspeakers.mdx
index f5a0e4dc2..1db1bb071 100644
--- a/site/src/content/docs/devices/electroacoustics/loudspeakers.mdx
+++ b/site/src/content/docs/devices/electroacoustics/loudspeakers.mdx
@@ -108,17 +108,17 @@ whose first null is at $ka\sin\theta = 3.8317$.
import numpy as np
from phonometry import radiating_piston
-res = radiating_piston(radius=0.1, frequencies=np.geomspace(20, 20000, 200),
+res = radiating_piston(radius=0.075, frequencies=np.geomspace(20, 20000, 200),
angles=np.linspace(0.0, np.pi / 2, 91))
-print(round(res.radiation_mass, 4)) # 8 rho a^3 / 3, kg
+print(round(res.radiation_mass, 4)) # 0.0014 kg = 8 rho a^3 / 3
print(round(float(res.directivity_index[0]), 2)) # 3.01 dB half-space limit
res.plot() # R1 and X1 vs ka
```
-*The `.plot()` of the result is the classic Beranek & Mellow impedance figure
-computed for this piston: below $ka \approx 1$ the load is almost purely
+*The `.plot()` of the 75 mm piston above is the classic Beranek & Mellow
+impedance figure: below $ka \approx 1$ the load is almost purely
mass-like ($X_1$ dominates and $R_1 \propto (ka)^2$, the regime where a
loudspeaker's output is stiffness- and mass-limited), and above it the
resistance settles on $\rho c S$ with interference ripples while the
diff --git a/site/src/content/docs/devices/electroacoustics/microphones.mdx b/site/src/content/docs/devices/electroacoustics/microphones.mdx
index 907bb4670..1a1e9a801 100644
--- a/site/src/content/docs/devices/electroacoustics/microphones.mdx
+++ b/site/src/content/docs/devices/electroacoustics/microphones.mdx
@@ -15,7 +15,7 @@ references:
title: "Sound system equipment – Part 4: Microphones"
designation: "IEC 60268-4:2014"
url: "https://webstore.iec.ch/en/publication/32039"
- note: "The rated microphone characteristics of this guide: the free-field sensitivity and its level re 1 V/Pa (11.1/11.3), the frequency response and effective frequency range (12.1/12.2), the directional pattern and the directivity index through the 11.2.2 a) diffuse-field integral (13.1/13.2), the overload sound pressure level (15.2), the equivalent sound pressure level due to inherent noise (17) and the rated impedances and power supply (9/10). Since revised as IEC 60268-4:2018 (same catalogue page); the 2014 edition is the implemented one."
+ note: "The rated microphone characteristics of this guide: the free-field sensitivity and its level re 1 V/Pa (11.1/11.3), the frequency response and effective frequency range (12.1/12.2), the directional pattern (13.1) and the directivity index (13.2.2) through the 11.2.2 a) diffuse-field integral, the overload sound pressure level (15.2), the equivalent sound pressure level due to inherent noise (17) and the rated impedances and power supply (9/10). Since revised as IEC 60268-4:2018 (same catalogue page); the 2014 edition is the implemented one."
- type: standard
organization: "International Electrotechnical Commission"
year: 1982
@@ -85,7 +85,10 @@ is the omnidirectional capsule, $b = 1/2$ the cardioid with its null at 180°,
and $b = 1$ the figure-of-eight with nulls at ±90°. One number condenses the
pattern: the **directivity index** $D = 20\log_{10}(M_0/M_\mathrm{diff})$ compares the
reference-axis sensitivity with the diffuse-field sensitivity obtained from
-the clause 11.2.2 a) integral over a rotationally symmetric pattern. An
+the clause 11.2.2 a) integral over a rotationally symmetric pattern
+(clause 13.2.2; the index is anchored on two clauses because the
+$M_\mathrm{diff}$ it divides by is the one clause 11.2.2 a) defines, as the
+r.m.s. of the pattern over a rotationally symmetric solid angle). An
omni scores 0 dB, the ideal cardioid and figure-of-eight both
$10\log_{10} 3 = 4.8$ dB: in a diffuse room field, a cardioid picks up three
times less reverberant power than an omni of equal axial sensitivity, which
diff --git a/site/src/content/docs/devices/emission/intensity.mdx b/site/src/content/docs/devices/emission/intensity.mdx
index e0604687d..05926841d 100644
--- a/site/src/content/docs/devices/emission/intensity.mdx
+++ b/site/src/content/docs/devices/emission/intensity.mdx
@@ -86,6 +86,11 @@ plt.show()
+The measurement itself is two synchronous channels: `p1` and `p2` are the
+calibrated pressures of the two capsules in pascals, `p1` the one nearer the
+source, acquired on the same analyser at the same sampling rate with the probe
+axis normal to the measurement surface.
+
```python
import numpy as np
from phonometry import emission
@@ -119,40 +124,40 @@ intensity measurement.*
```python
import matplotlib.pyplot as plt
import numpy as np
+from scipy import signal
from phonometry import emission
-fs = 48000
-rng = np.random.default_rng(0)
-# The two probe-microphone pressures in Pa, p1 closest to the source.
-# In a real measurement these are your two calibrated probe recordings;
-# synthesized here (p2 = p1 delayed one sample) so the guide runs.
-p1 = 0.02 * rng.standard_normal(fs)
-p2 = np.concatenate(([0.0], p1[:-1])) # p2 = p1 delayed one sample
-res = emission.sound_intensity(p1, p2, fs, spacing=0.012, fraction=3,
- limits=[100, 2500])
-
-# res is the IntensityResult computed in the example above.
-# One line — Lp vs LI per band with the pressure-intensity index on a twin axis:
-res.plot()
-plt.show()
-
-# By hand, from the per-band fields the result carries — mirroring what
-# IntensityResult.plot() draws (bar label, merged twin-axis legend, δpI title):
-fig, ax = plt.subplots()
-ax.semilogx(res.frequency, res.pressure_level, "o-", label="Pressure level Lp")
-ax.semilogx(res.frequency, res.intensity_level, "s--", label="Intensity level LI")
-ax.set_xlabel("Frequency [Hz]")
-ax.set_ylabel("Level [dB]")
-twin = ax.twinx()
-twin.bar(res.frequency, res.pressure_intensity_index,
- width=res.frequency * 0.2, color="#2ca02c", alpha=0.25,
- label="δpI = Lp − LI")
-twin.set_ylabel("Pressure-intensity index δpI [dB]")
-# Merge both axes' handles into a single legend, exactly as .plot() does:
-lines, labels = ax.get_legend_handles_labels()
-tlines, tlabels = twin.get_legend_handles_labels()
-ax.legend(lines + tlines, labels + tlabels)
-ax.set_title(f"Lp vs LI (total δpI = {res.total_pressure_intensity_index:.1f} dB)")
+fs, dr, c = 48000, 0.012, 343.0
+n = int(fs * 4.0)
+
+# Broadband noise, band-limited to 80 Hz - 6 kHz and scaled to about 70 dB SPL.
+rng = np.random.default_rng(2026)
+noise = signal.sosfilt(
+ signal.butter(4, [80.0, 6000.0], btype="bandpass", fs=fs, output="sos"),
+ rng.standard_normal(n),
+)
+noise *= 0.063 / np.std(noise)
+spectrum = np.fft.rfft(noise)
+freqs = np.fft.rfftfreq(n, 1 / fs)
+
+# Left: a plane progressive wave. Microphone 2 sees the wave dr/c = 35 us later,
+# applied as a phase shift rather than as a whole number of samples.
+plane = emission.sound_intensity(
+ noise, np.fft.irfft(spectrum * np.exp(-2j * np.pi * freqs * dr / c), n),
+ fs, dr, fraction=3, limits=[100.0, 5000.0],
+)
+
+# Right: a standing wave, two equal counter-propagating waves, with the probe
+# centred at x0 = 0.30 m from the rigid termination.
+k, x0 = 2 * np.pi * freqs / c, 0.30
+def at(pos):
+ return np.fft.irfft(spectrum * 2.0 * np.cos(k * pos), n)
+standing = emission.sound_intensity(at(x0 - dr / 2), at(x0 + dr / 2),
+ fs, dr, fraction=3, limits=[100.0, 5000.0])
+
+fig, (axl, axr) = plt.subplots(1, 2, figsize=(12, 5), sharey=True)
+plane.plot(ax=axl)
+standing.plot(ax=axr)
plt.show()
```
@@ -194,7 +199,7 @@ sample or any whole number of cycles). **$F_1$**, the
temporal variability indicator, is the coefficient of variation of those
samples (equations (A.1)–(A.2)), so it is zero for a perfectly steady field
and grows as the extraneous intensity wanders. Table B.3 asks for action code
-(e) above $F_1 > 0.6$: reduce the variability, measure during quieter periods,
+(e) when $F_1$ exceeds 0.6: reduce the variability, measure during quieter periods,
or lengthen the averaging time at each position. Annex B also has it evaluated
immediately before and after the measurement on any one surface (B.1.4).
@@ -359,8 +364,9 @@ same 3 dB per doubling the previous section arrived at from the physics.
`intensity_class_compliance` compares a measured $\delta_{pI0}$ spectrum
against both
-masks band by band and returns the class the chain actually meets:
-the loosest class every band clears, or `None` when some band clears neither:
+masks band by band and returns an `IntensityInstrumentComplianceResult` holding
+the class the chain actually meets: the loosest class every band clears, or
+`None` when some band clears neither.
```python
from phonometry import metrology
@@ -438,7 +444,7 @@ repository; click the preview to open the PDF.
name="iec61043_intensity_example"
title="IEC 61043 sound intensity instrument class verification example report (PDF)"
description="One-page instrument-class-verification fiche: a metadata header, a per-band table listing the class 1 and class 2 minima, the measured residual index, the margin and the class achieved in each one-third-octave band from 50 Hz to 6.3 kHz, the measured index drawn as a step curve over the two Table 2 masks with the 100 Hz band ringed below the class 1 minimum, the boxed Class 2 - COMPLIES (binding margin +4.20 dB) result, the microphone separation and equivalent phase mismatch, and a FAIL verdict against the required class 1."
- caption="Instrument class verification fiche (IntensityClassResult.report), the achieved class with its binding margin and the measured δpI0 over the Table 2 minima rescaled to the 12 mm spacer."
+ caption="Instrument class verification fiche (IntensityInstrumentComplianceResult.report), the achieved class with its binding margin and the measured δpI0 over the Table 2 minima rescaled to the 12 mm spacer."
/>
### Reading `δpI0` as a phase error
@@ -472,18 +478,23 @@ phase match, and above it for a constant index. The knee sits at 250 Hz for
the three class 1 columns and for the class 2 processor, and at 630 Hz for the
class 2 probe and the class 2 complete instrument, which is also where the
table stops stepping in whole decibels (the instrument goes 14 dB at 315 Hz,
-14,5 dB at 400 Hz, 15 dB at 500 Hz). It is also why a
+14.5 dB at 400 Hz, 15 dB at 500 Hz). It is also why a
tenth of a degree of channel mismatch is a demanding specification, and why a
probe must be verified with the spacer it will actually be used with.
+## Choosing the probe
+
+Two decisions are made before any data is taken: where the measurement surface
+can be placed, and which spacer goes on the probe.
+
### Reactive fields near sources
Close to a source the field turns **reactive**: pressure and particle
velocity drift toward quadrature, so a large pressure carries little net
flow. For a small source the quadrature component grows as $1/(kr)$; at
100 Hz and 0.25 m from the source it is already about twice the active one,
-and $\delta_{pI}$ climbs just as it does in the standing wave of the figure
-above.
+and $\delta_{pI}$ climbs just as it does in the standing wave of the
+two-panel figure at the top of this page.
The same happens between a machine and a hard reflecting surface, and in
reverberant rooms where the diffuse field raises pressure without
transporting energy outward. This is why ISO 9614-1 keeps the measurement
@@ -519,7 +530,7 @@ merged; whichever spacer is fitted, verify $\delta_{pI0}$ with that spacer in
place, since the index belongs to the probe-spacer-analyzer chain, not to
the microphones alone.
-### `sound_intensity()` parameters
+## `sound_intensity()` parameters
| Parameter | Type | Units | Range / default | Notes |
| :--- | :--- | :--- | :--- | :--- |
@@ -565,4 +576,9 @@ does with it is grade it against Table 2.
## See also
+- [Sound Power by Intensity Scanning](/phonometry/devices/emission/sound-power-intensity/) — the ISO 9614-2/-3 routes that consume $\delta_{pI}$, the field indicators and the dynamic capability.
+- [Sound Power](/phonometry/devices/emission/sound-power/) — choosing between the intensity, pressure and reverberation-room routes.
+- [Sound power from surface vibration](/phonometry/devices/emission/vibration-sound-power/) — the ISO/TS 7849-2 radiation factor needs an intensity-measured power.
+- [Calibration](/phonometry/signals/metrology/calibration/) — the absolute scaling of the two channels the estimator assumes.
+- [Theory: signal analysis](/phonometry/reference/theory/signal-analysis/) — the cross-spectral derivation behind $I(f) = -\mathrm{Im}\{G_{12}\}/(2\pi f \rho_0 \Delta r)$.
- API reference: [`emission.intensity`](/phonometry/reference/api/power/intensity/).
diff --git a/site/src/content/docs/devices/emission/sound-power-intensity.mdx b/site/src/content/docs/devices/emission/sound-power-intensity.mdx
index 3463a8f74..f834e8a25 100644
--- a/site/src/content/docs/devices/emission/sound-power-intensity.mdx
+++ b/site/src/content/docs/devices/emission/sound-power-intensity.mdx
@@ -372,8 +372,9 @@ sound-power fiche through `.report()`.
**Not covered.** ISO 9614-1, the discrete fixed-point intensity method, is
not one of the routes here: only its field indicators are reused, and the
-discrete-point power determination itself belongs to the
-[sound intensity guide](/phonometry/devices/emission/intensity/). The probe's
+discrete-point power determination is not implemented at all; the
+[sound intensity guide](/phonometry/devices/emission/intensity/) covers the
+probe and the Annex A field indicators that both parts share. The probe's
finite-difference bias and the pressure-residual intensity index are
measured properties of the instrument, covered in the same guide. Choosing
among the five routes, and the ISO 4871 declaration a result feeds, live in
diff --git a/site/src/content/docs/devices/emission/sound-power-pressure.mdx b/site/src/content/docs/devices/emission/sound-power-pressure.mdx
index 7083aa1a8..892e01962 100644
--- a/site/src/content/docs/devices/emission/sound-power-pressure.mdx
+++ b/site/src/content/docs/devices/emission/sound-power-pressure.mdx
@@ -290,6 +290,25 @@ the measurement radius. The microphone positions are the standardized
unit-vector arrays of Tables D.1 (sphere), E.1 (hemisphere) and E.2 (hemisphere,
broadband).
+**The radius is not free** (clauses 8.1/8.2). It must satisfy $r \ge 2 d_0$ with
+$d_0$ the distance from the acoustic centre to the furthest point of the source
+(in a hemi-anechoic room, $r \ge 2 d_0$ or $r \ge 3 h_0$, whichever is larger,
+$h_0$ being the height of the acoustic centre above the floor), $r \ge \lambda/4$
+at the lowest frequency of interest, and $r \ge 1$ m — 0.5 m only for a small,
+low-noise source over a limited band — with the whole surface inside the region
+qualified per Annex A or B. Worked: a 0.6 × 0.5 × 0.7 m benchtop source has
+$d_0 = \sqrt{0.3^2 + 0.25^2 + 0.7^2} = 0.80$ m, so $r \ge 1.6$ m; at a lowest
+band of 100 Hz, $\lambda/4 = 0.86$ m does not bind and neither does the 1 m
+floor. The `radius=1.0` of the examples below therefore fits only a source under
+about 0.5 m of characteristic dimension.
+
+**The array is not free either.** Positions 1 to 20 are used first, and 21 to 40
+are added only when the difference between the highest and lowest level in any
+band of interest is not less than half the number of positions — a check on data
+the reader already has, `levels.max(0) - levels.min(0) >= 0.5 * levels.shape[0]`.
+If 40 positions still fail it, a localized investigation is required and the
+positions then carry unequal areas, which is what `areas=` is for.
+
```python
import numpy as np
from phonometry import emission
@@ -352,8 +371,14 @@ base = 70.0 + 8.0 * np.exp(-(np.log2(freqs / 1000.0) ** 2) / 2.0)
rng = np.random.default_rng(7)
levels = base[None, :] + rng.normal(0.0, 1.0, (40, freqs.size))
-result = emission.sound_power_anechoic(levels, "hemisphere", radius=1.0, frequencies=freqs)
+# sigma_omc is the operating-and-mounting standard deviation of Clause 10.5;
+# with the EXAMPLE value 2.0 dB and the default coverage factor k = 2 the
+# expanded uncertainty U = k*sqrt(sigma_R0^2 + sigma_omc^2) is the 4.1 dB the
+# fiche below prints. Left at its default of 0 it reports 1.0 dB.
+result = emission.sound_power_anechoic(levels, "hemisphere", radius=1.0,
+ frequencies=freqs, sigma_omc=2.0)
print(round(result.sound_power_level_a, 1)) # 89.3
+print(round(float(result.uncertainty), 1)) # 4.1 dB
result.plot() # LW spectrum, LWA in the title (needs matplotlib)
```
diff --git a/site/src/content/docs/devices/emission/sound-power-reverberation.mdx b/site/src/content/docs/devices/emission/sound-power-reverberation.mdx
index ee0c71c4a..ce315c68c 100644
--- a/site/src/content/docs/devices/emission/sound-power-reverberation.mdx
+++ b/site/src/content/docs/devices/emission/sound-power-reverberation.mdx
@@ -19,6 +19,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
import ReportPreview from '../../../../components/ReportPreview.astro';
A reverberation room turns its main defect as a listening space into a
@@ -66,6 +67,25 @@ terms by a reference sound source of known power $L_W(\text{RSS})$ measured
in the same room, so the room need not be characterised:
$L_W = L_W(\text{RSS}) + (L_p(\text{ST}) - L_p(\text{RSS}) + C_2)$.
+The right-hand panel of the clip below is this method. The same source runs
+in both rooms; in the anechoic room on the left the microphones see only what
+the source sends their way, so the level falls with distance and the free-field
+route has to integrate over a measurement surface, while in the reverberation
+room on the right the reflected energy fills the space and the level stops
+depending on where a microphone is. That is the whole reason Eq. 20 can
+replace a surface integral with a handful of positions and a room constant —
+and the reason the room, not the array, is what has to be qualified. Both
+routes end on the same $L_W$, because sound power is a property of the source
+and not of the room it is measured in.
+
+
+
```python
import numpy as np
from phonometry import emission
diff --git a/site/src/content/docs/devices/emission/sound-power.mdx b/site/src/content/docs/devices/emission/sound-power.mdx
index 4b1cc9585..f0b150daa 100644
--- a/site/src/content/docs/devices/emission/sound-power.mdx
+++ b/site/src/content/docs/devices/emission/sound-power.mdx
@@ -127,7 +127,11 @@ order; the first match names the standard.
calls for precision (grade 1); a first walk-through of a noisy plant
tolerates survey grade (grade 3). Grade 1 exists only in a qualified
laboratory room (ISO 3741, ISO 3745) or via the precision intensity
- methods (ISO 9614-1 at discrete points, ISO 9614-3 by scanning).
+ methods (ISO 9614-1 at discrete points, ISO 9614-3 by scanning), of
+ which phonometry implements the scanning form only: ISO 9614-1's own
+ discrete-point power summation is not provided, though its field
+ indicators are (see
+ [Sound Intensity](/phonometry/devices/emission/intensity/)).
2. **Can the source travel to a laboratory?** ISO 3741 wants the source
small next to the room (volume no more than about 2 % of the room volume)
and its noise steady; ISO 3745 wants it inside a qualified anechoic or
@@ -263,6 +267,9 @@ the diffuse-field method in
[Sound Power in the Reverberation Room](/phonometry/devices/emission/sound-power-reverberation/)
and both scanning methods in
[Sound Power by Intensity Scanning](/phonometry/devices/emission/sound-power-intensity/).
+ISO 9614-1's own discrete-point power summation is not implemented at all;
+only its field indicators are, in
+[Sound Intensity](/phonometry/devices/emission/intensity/).
ISO 4871's batch statistics beyond the single-machine
$K = 1.645\,\sigma_R$ case (Annex A.2.2) are stated, not derived.
diff --git a/site/src/content/docs/devices/emission/vibration-sound-power.mdx b/site/src/content/docs/devices/emission/vibration-sound-power.mdx
index a3565db67..580f4f069 100644
--- a/site/src/content/docs/devices/emission/vibration-sound-power.mdx
+++ b/site/src/content/docs/devices/emission/vibration-sound-power.mdx
@@ -41,11 +41,22 @@ $$
with $Z_c$ the characteristic impedance of air, $\langle v^2 \rangle$ the
mean-square vibratory velocity over the radiating area $S$. Expressed in levels
-(velocity level re $v_0 = 5\times10^{-8}\ \text{m/s}$), the A-weighted sound
-power level is (Formula 12 / 15)
+(velocity level re $v_0 = 5\times10^{-8}\ \text{m/s}$), each part writes that
+relation in its own quantities. **Part 1** is A-weighted throughout: one
+A-weighted surface velocity level $L_{vA}$, the fixed $\varepsilon_A = 1$, and a
+single A-weighted number, the *upper limit* of the airborne sound power level
+(Formula 12)
$$
-L_W = L_v + 10\log_{10}\frac{S}{S_0} + 10\log_{10}\varepsilon
+L_{WA,\max} = L_{vA} + 10\log_{10}\frac{S}{S_0}
+ + 10\log_{10}\frac{Z_{c,n}}{Z_{c,0}}.
+$$
+
+**Part 2** is the band-wise counterpart, with the radiation factor
+$\varepsilon_j$ determined for each band (Formula 15)
+
+$$
+L_{W,j} = L_{v,j} + 10\log_{10}\frac{S}{S_0} + 10\log_{10}\varepsilon_j
+ 10\log_{10}\frac{Z_{c,n}}{Z_{c,0}},
$$
@@ -53,8 +64,11 @@ where $S_0 = 1\ \text{m}^2$, the normalized impedance
$Z_{c,n} = 411\ \text{N·s/m}^3$ and the reference
$Z_{c,0} = 400\ \text{N·s/m}^3$ give the fixed
$10\log_{10}(411/400) = 0.118\ \text{dB}$
-term. This module feeds the structure-borne source and building prediction
-standards (ISO 9611, EN 15657, EN 12354-5).
+term. This guide runs the band-wise form for both parts, so that the Part 1
+upper limit and the Part 2 engineering value can be compared band by band; a
+strict Part 1 survey is the single A-weighted number above, which the result
+object carries as `sound_power_level_a`. This module feeds the structure-borne
+source and building prediction standards (ISO 9611, EN 15657, EN 12354-5).
Before any levels, the radiator itself. The `radiation_efficiency` plate model
that supplies a predicted radiation factor retains its geometry, and
@@ -139,16 +153,24 @@ lv = np.array([82.0, 85.0, 83.0, 79.0]) # mean velocity level per band
# Part 1 upper limit (epsilon = 1):
upper = emission.sound_power_from_vibration(lv, area=1.6, frequencies=bands)
-print(round(upper.total_level, 1)) # e.g. 89.4 dB re 1 pW
+print(round(upper.total_level, 1)) # 90.9 dB re 1 pW, unweighted
+print(round(upper.sound_power_level_a, 1)) # 88.9 dB(A) re 1 pW
# Part 2 engineering value with a measured radiation factor:
eps = np.array([0.45, 0.75, 0.95, 1.00])
eng = emission.sound_power_from_vibration(lv, area=1.6, radiation_factor=eps, frequencies=bands)
print(np.round(eng.sound_power_level, 1)) # per-band L_W
+print(round(eng.sound_power_level_a, 1)) # 88.4 dB(A) re 1 pW
eng.plot() # the LW(f) spectrum, as in the figure above (needs matplotlib)
```
+The two totals are not interchangeable: `total_level` is the unweighted band sum
+$10\lg\sum_j 10^{0.1 L_{W,j}}$, while `sound_power_level_a` is the A-weighted
+total that the fiche boxes and that a noise declaration quotes. They differ by
+the A-weighting of the spectrum — 2.0 dB on this casing, several decibels more
+on a low-frequency-heavy one.
+
## 2. Velocity level, calibration and the radiation factor
The velocity level is $L_v = 20\log_{10}(v/v_0)$ (Formula 3); a sinusoidal
@@ -173,11 +195,21 @@ and the correction `extraneous_velocity_correction` removes extraneous
vibration per Table 2.
Those positions are not free: the standard divides the radiating surface $S$
-into $N$ equal cells and puts one accelerometer at the centre of each. The
-area table gives the initial $N$; a strongly non-uniform vibration field can
-call for more positions or a redistribution.
-
-
+into $N$ equal cells and puts one accelerometer at the centre of each. Table 1
+fixes the initial $N$ from the area alone — **5** positions below 1 m²,
+**10** from 1 m² to 10 m², and $S/S_0$ positions above that ($S_0 = 1$ m²) — so
+the 4 m² surface drawn below takes ten. Increase $N$ when the spread of the
+A-weighted velocity level over the positions, highest minus lowest in decibels,
+exceeds twice the Table 1 count; a strongly non-uniform field can instead be
+handled by redistributing the positions, which makes the partial areas $S_i$
+unequal and so calls for the area-weighted Formula 11 rather than the plain
+energetic mean. The Table 2 correction is a ladder on the same kind of spread:
+with the machine stopped and the surrounding plant running, the mean extraneous
+velocity level must sit at least 3 dB below the machine's, and
+`extraneous_velocity_correction` returns 3 dB at a 3 dB difference, 2 dB at
+4-5 dB, 1 dB at 6-9 dB and 0 dB from 10 dB up.
+
+
## 3. When the radiation-factor assumption breaks
@@ -224,7 +256,11 @@ climate, date), a per-band table (nominal octave/one-third-octave frequency,
the surface vibratory velocity level $L_v$ and the band sound-power level
$L_W$), the sound-power spectrum $L_W(f)$ with a nominal band axis, and a boxed
A-weighted sound power level $L_{WA}$ (dB re 1 pW) with the total $L_W$, the
-radiating area $S$ and the applied method alongside.
+radiating area $S$ and the applied method alongside. Those two come from the
+result's `sound_power_level_a` (the declarable A-weighted total) and
+`total_level` (the unweighted band sum); the table columns come from
+`velocity_level`, `sound_power_level` and, with `verbose=True`,
+`radiation_factor`.
The metadata is supplied through a `ReportMetadata`, whose applicable fields
here are the **machine/source description** (`specimen`), the **test
diff --git a/site/src/content/docs/devices/noise-control/duct-path.mdx b/site/src/content/docs/devices/noise-control/duct-path.mdx
index ca9f5a1e0..5f79dfd94 100644
--- a/site/src/content/docs/devices/noise-control/duct-path.mdx
+++ b/site/src/content/docs/devices/noise-control/duct-path.mdx
@@ -350,10 +350,16 @@ that is what a real sheet uses. When there is none to hand,
`diffuser_sound_power` is Reynolds's estimate as Long Eqs. 13.27 to 13.33:
an overall level
$L_W = 10\log_{10} S_G + 30\log_{10}\xi + 60\log_{10} U_G - 31.3$ from the
-face area, the approach velocity $U_G = Q/S_G$ and the normalised
-pressure-drop coefficient $\xi$, spread over the octaves by the shape
-function $C_D = -11.82 - 0.15 A - 1.13 A^2$ ($-5.82$ for a round device)
-about the peak band $f_P = 48.8\,U_G$.
+face area $S_G$, the approach velocity $U_G = Q/S_G$ and the normalised
+pressure-drop coefficient $\xi = 334.9\,\Delta p/(\rho_0 U_G^2)$ of Eq. 13.28.
+Long writes all four in foot-pound units ($S_G$ in ft², $U_G$ in ft/s,
+$\Delta p$ in inches of water gauge); `diffuser_sound_power` takes and returns
+SI and converts internally, which is why the constants here are quoted on
+Long's units. The spectrum follows as $L_{W,\text{oct}} = L_W + C_D$ with the
+shape function $C_D = -11.82 - 0.15 A - 1.13 A^2$ for a rectangular device
+($-5.82$ for a round one), where $A$ is the distance in octaves from the peak
+band $f_P = 48.8\,U_G$ (Eq. 13.32, $U_G$ in **ft/s**), counted on Long's band
+numbering with band 0 at 32 Hz.
```python
from phonometry import diffuser_sound_power
@@ -367,6 +373,11 @@ print(np.round(diffuser_sound_power(None, (24 * IN) ** 2,
pressure_drop=0.05 * IN_WG).values, 1))
# [ 33.4 32.4 29.1 23.6 15.9 5.9 -6.4 -21. ]
# Long Table 14.9 prints 33/32/29/23/15/4/0/0 for that row.
+
+# The peak band the shape function is counted from, on Long's units:
+face_velocity = 312 * CFM / (24 * IN) ** 2 / 0.3048 # 1.3 ft/s
+print(round(48.8 * face_velocity, 1)) # fP = 63.4 Hz
+print(round(np.log2(48.8 * face_velocity / 32.0))) # band 1: the 63 Hz octave
```
The sixth power of velocity in Eq. 13.27 is the design rule: about 18 dB
@@ -540,17 +551,19 @@ for row in total.table():
print(f"{row['kind']:<12} {row['label'][:26]:<26} "
f"{[round(float(v)) for v in row['values']]}")
-total.report("duct-path.pdf") # needs phonometry[report]
+supply.report("duct-path-supply.pdf") # the fiche previewed below
+total.report("duct-path.pdf") # the combination; needs phonometry[report]
```
-The example fiche, regenerated with `make reports`, is kept rendered in the
-repository. Click the preview to open the PDF:
+The example fiche is the **supply half** of the sheet, regenerated with
+`make reports` and kept rendered in the repository. Click the preview to open
+the PDF:
## 7. What reproduces, and what does not
diff --git a/site/src/content/docs/devices/noise-control/room-to-room.mdx b/site/src/content/docs/devices/noise-control/room-to-room.mdx
index 53c7c7924..db10d3224 100644
--- a/site/src/content/docs/devices/noise-control/room-to-room.mdx
+++ b/site/src/content/docs/devices/noise-control/room-to-room.mdx
@@ -35,6 +35,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
A machine runs in one room, a wall separates that room from an occupied one,
and someone wants to know what the occupant hears. It is a short chain, and
@@ -73,7 +74,9 @@ $$
with $\text{NR} = L_{p1} - L_{p2}$ the noise reduction between the two
reverberant fields, $\text{TL} = 10\log_{10}(1/\tau)$ the transmission loss of the
-partition (the quantity UNE calls the sound reduction index $R$), $S_w$ the
+partition — the quantity ISO 10140-2 measures and ISO 717-1 rates as the sound
+reduction index $R$, so the $R$ and $R_w$ of a laboratory test report drop
+straight into this equation — $S_w$ the
area of the partition and $S_2 \alpha_2$ the equivalent absorption area of
the receiving room.
@@ -371,6 +374,23 @@ and air leaks**. A ceiling void carried over the partition, a service
penetration, a door undercut, or the wall simply not reaching the structural
slab, and the equation's answer becomes an upper bound.
+The clip below draws what the equation leaves out. The chain of section 3
+prices the direct path only, the **Dd** route through the partition; the
+other three pulses leave the source room over the flanking walls, floor or
+ceiling — **Ff** flank to flank, **Fd** flank to partition, **Df** partition
+to flank — and re-radiate on the far side without ever passing through the
+transmission loss the calculation used. Each path shrinks at every element
+and junction it crosses, which is why no single one has to be large for the
+sum of the three to dominate a good partition.
+
+
+
`DesignCriterion.flanking_penalty` is the explicit debit for that, in
decibels off the
predicted noise reduction. It is not a model, it is a place to record the
diff --git a/site/src/content/docs/devices/noise-control/silencers.mdx b/site/src/content/docs/devices/noise-control/silencers.mdx
index 3e725ceea..270f8e384 100644
--- a/site/src/content/docs/devices/noise-control/silencers.mdx
+++ b/site/src/content/docs/devices/noise-control/silencers.mdx
@@ -204,6 +204,22 @@ $f_0 = \tfrac{c}{2\pi}\sqrt{S_n/(l_e V)}$ (Bies Eq. (8.46)) and $f = c/4l_e$
(Eq. (8.44)). An **extended-tube chamber** buries quarter-wave side branches in
an expansion chamber to fill the plain chamber's troughs.
+Both lengths are **effective** lengths, and both functions take them that way
+(`neck_length` and `length` are documented as $l_e$, end corrections included).
+The air in a neck does not stop moving at the mouth: it drags a slug of air
+along on each side, so the mass that resonates against the cavity belongs to a
+tube longer than the one that was drilled. Add about $0.85a$ per flanged end
+and about $0.61a$ per free end, for a neck of radius $a$, at both ends of a
+Helmholtz neck and at the open (duct) end only of a quarter-wave stub. The
+resonator drawn below is the case in point: its neck is 11.3 mm across
+($a = 5.64$ mm) and 20 mm long, so $l_e \approx 20 + 2 \times 4.8 =
+29.6$ mm and the tuning falls from the 122.1 Hz the drilled length returns to
+100.3 Hz — a 22 % error on a notch the figure below shows to be only a few
+hertz wide. The shorter and wider the neck, the larger the correction in
+relative terms, which is exactly the regime a compact resonator lives in, so
+the practical procedure is to compute a nominal length, build it long, and
+trim it against a measurement.
+
```python
import numpy as np
from phonometry import (
@@ -214,12 +230,23 @@ f = np.linspace(20.0, 600.0, 4000)
hr = helmholtz_resonator(f, duct_area=0.01, neck_area=1e-4,
neck_length=0.02, cavity_volume=1e-3)
-print(round(float(hr.resonances[0]), 1)) # tuning frequency, Hz
+print(round(float(hr.resonances[0]), 1)) # 122.1 Hz, for le = 20 mm
hr.plot() # TL spike at the tuning frequency (needs matplotlib)
-qw = quarter_wave_resonator(f, duct_area=0.01, length=1.516, branch_area=2e-3,
- speed_of_sound=343.24)
-print(round(float(qw.resonances[0]), 1)) # 56.6 Hz (Bies Example 8.1)
+qw = quarter_wave_resonator(f, duct_area=0.01, length=0.3, branch_area=2e-3)
+print(round(float(qw.resonances[0]), 1)) # 285.8 Hz = c / 4 le
+
+# Bies Example 8.1, the published anchor: a 1.516 m stub at c = 343.24 m/s.
+print(round(float(quarter_wave_resonator(
+ f, duct_area=0.01, length=1.516, branch_area=2e-3,
+ speed_of_sound=343.24).resonances[0]), 1)) # 56.6 Hz
+
+# The same stub in hot exhaust gas: c(500 degC) = 343*sqrt(773/293) = 557 m/s
+# (see the caution below), which moves the notch by a factor 1.62.
+f_hot = np.linspace(20.0, 900.0, 6000)
+qw_hot = quarter_wave_resonator(f_hot, duct_area=0.01, length=0.3,
+ branch_area=2e-3, speed_of_sound=557.0)
+print(round(float(qw_hot.resonances[0]), 1)) # 464.2 Hz, not 285.8
# An inlet extension of L/4 fills the first expansion-chamber trough.
et = extended_tube_chamber(f, length=0.4, chamber_area=0.04, pipe_area=0.01,
@@ -303,6 +330,24 @@ same duct.
pipe puts the spike at $c/4l_e \approx 285\ \text{Hz}$, and the 20 cm² branch
area only sets how strongly the stub loads the duct.*
+:::caution
+**Tune at the working temperature.**
+Every frequency on this page is a wavelength condition, so all of them scale
+directly with the speed of sound **in the working gas**: $kL = \pi/2$ for the
+chamber, $c/4l_e$ for the stub, and the $c$ in front of the Helmholtz square
+root. For air, $c(T) = 343\sqrt{T/293}$ with $T$ in kelvin, so an exhaust at
+500 °C (773 K) runs at about 557 m/s, a factor 1.62, and the 0.3 m stub cut for
+285.8 Hz on cold-air values sings at 464 Hz once the pipe is hot. Pass the
+working values — `speed_of_sound=` and `density=`, since the density scales
+every characteristic impedance and therefore the insertion loss. The
+`speed_of_sound=557.0` call in the section 1 snippet above is that retune, and
+it prints 464.2 Hz for the same 0.3 m stub.
+
+A mean flow shifts the notch further and lowers its depth, and the temperature
+falls along a real tailpipe, so an exhaust resonator is checked at the hot and
+cold extremes and accepted with margin rather than designed at one value.
+:::
+
Show the code for this figure
@@ -409,12 +454,21 @@ by the airflow resistivity, is the same material theory as
## Cross-check against the FDTD solver
-The four-pole expansion chamber is cross-checked against the independent 2D
-[FDTD wave solver](/phonometry/simulation/fdtd-simulation/): a plane-wave duct that
-widens into a chamber and narrows back transmits far less at the four-pole TL
-peak ($kL = \pi/2$) than at the transparent trough ($kL = \pi$), and the
-measured amplitude ratio reproduces the closed-form peak transmission loss to a
-fraction of a decibel.
+That cross-check is the clip embedded in section 1, and it is worth returning
+to it now with the algebra in hand. The four-pole expansion chamber is checked
+against the independent 2D
+[FDTD wave solver](/phonometry/simulation/fdtd-simulation/), which shares no
+formula and no assumption with the transfer-matrix product beyond the wave
+equation itself: a plane-wave duct that widens into the same 0.30 m, $m = 4$
+chamber and narrows back transmits far less at the four-pole TL peak
+($kL = \pi/2$, here 286 Hz) than at the transparent trough ($kL = \pi$,
+572 Hz). The amplitude ratio measured downstream in the field is the
+transmission loss annotated on the clip, 6.5 dB at 286 Hz and 0.0 dB at
+572 Hz, against the 6.55 dB the closed form gives for $m = 4$. Agreement that
+close rules out an algebra error on either side. The two must eventually part
+company above the duct's first cut-on frequency, where higher-order modes
+propagate: the two-dimensional solver keeps working there and the plane-wave
+algebra does not.
## What this guide covers
diff --git a/site/src/content/docs/environment/assessment/environmental-levels.mdx b/site/src/content/docs/environment/assessment/environmental-levels.mdx
index 56df2ebea..ebd489931 100644
--- a/site/src/content/docs/environment/assessment/environmental-levels.mdx
+++ b/site/src/content/docs/environment/assessment/environmental-levels.mdx
@@ -9,13 +9,19 @@ references:
designation: "ISO 1996-1:2016"
url: "https://www.iso.org/standard/59765.html"
note: "Lden (3.6.4), Ldn (3.6.5) and the composite whole-day rating level of clause 6.5 (Formulae 5-6, Table A.1 adjustments)."
+ - type: standard
+ organization: "International Organization for Standardization"
+ year: 2007
+ title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
+ designation: "ISO 1996-2:2007"
+ note: "Annex C: the critical bandwidth of Table C.1, the audibility of Formula (C.3) and the piecewise adjustment of Formulae (C.4)-(C.6). This is the self-contained engineering method the library implements; the 2009 corrected reprint is identical here."
- type: standard
organization: "International Organization for Standardization"
year: 2017
title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
designation: "ISO 1996-2:2017"
url: "https://www.iso.org/standard/59766.html"
- note: "The Annex C tonal adjustment (with the survey method and the ISO/PAS 20065 mean-audibility mapping), the Clause 10.4 residual-noise correction and the Clause 4 / Annex F measurement uncertainty budget."
+ note: "The Clause 10.4 residual-noise correction, the Clause 4 / Annex F measurement uncertainty budget, the Annex J Table J.1 mean-audibility mapping and the Annex K survey method."
- type: standard
organization: "British Standards Institution"
year: 2003
@@ -130,7 +136,12 @@ into a rating level and reported with its uncertainty. The rating-level *summati
and the time-of-day penalties live in ISO 1996-1 (above); ISO 1996-2 supplies the
tonal adjustment, the residual-noise correction and the uncertainty budget.
-**Tonal adjustment (engineering method, Annex C).** From the energy-summed tone
+**Tonal adjustment (engineering method, ISO 1996-2:2007 Annex C).** The 2017
+edition dropped the self-contained algorithm and refers to ISO/PAS 20065
+instead ([Objective audibility of tones in noise](/phonometry/perception/psychoacoustics/tone-audibility/));
+what it keeps is the Annex J table that converts a *mean* audibility into an
+integer adjustment. The 2007 algorithm is the one implemented here, because it
+runs on a single spectrum. From the energy-summed tone
level $L_{pt}$ and the masking-noise level $L_{pn}$ in the critical band around a
tone, the audibility above the masking threshold is
$\Delta L_{ta} = L_{pt} - L_{pn} + 2 + \log_{10}[1 + (f_c/502)^{2.5}]$ dB (Formula (C.3)),
@@ -193,8 +204,9 @@ environment.expanded_uncertainty(u) # 4.36 dB (k = 2)
**Covered.** ISO 1996-1:2016's $L_{den}$, $L_{dn}$ and composite rating level (clause
6.5, `environment.lden`/`ldn`/`composite_rating_level`); and ISO
-1996-2:2017's tonal adjustment (Annex C), residual-noise correction (Clause
-10.4) and measurement uncertainty budget (Clause 4, Annex F).
+1996-2:2007's Annex C tonal adjustment together with ISO 1996-2:2017's
+residual-noise correction (Clause 10.4), measurement uncertainty budget
+(Clause 4, Annex F), Annex J mean-audibility mapping and Annex K survey method.
**Not covered.** ISO 1996-2 fixes the receiver positions and the façade
corrections that turn a raw measurement into the level this page's
diff --git a/site/src/content/docs/environment/index.md b/site/src/content/docs/environment/index.md
index b0333f384..80fd3e1b1 100644
--- a/site/src/content/docs/environment/index.md
+++ b/site/src/content/docs/environment/index.md
@@ -4,11 +4,16 @@ description: "Sound outdoors and the sources that dominate it: the ISO 9613 prop
---
Environmental noise is a source-path-receiver problem stretched over hundreds
-of metres of open air. This section covers both ends of it. The **outdoor
-sound** pages handle the path and the assessment: ISO 9613 predicts, band by
-band, how much level survives divergence, air absorption, the ground and any
-barrier on the way to a receiver, and NT ACOU 112 quantifies when impulsive
-character makes the received sound more annoying than its LAeq suggests.
+of metres of open air. This section covers all three of them. The **propagation**
+pages handle the path: ISO 9613 predicts, band by band, how much level survives
+divergence, air absorption, the ground and any barrier on the way to a receiver,
+and the wave-acoustic ground and refraction models say when that engineering
+method stops being enough.
+
+The **assessment** pages handle what happens once the sound has arrived: the
+ISO 1996 rating level and the day-evening-night indicators, their Spanish
+application in RD 1367/2007, and the NT ACOU 112 adjustment that quantifies when
+impulsive character makes a received sound more annoying than its LAeq suggests.
The **source** pages handle the other end: what emits, described the way an
environmental model wants it. CNOSSOS-EU gives road traffic and railways a
@@ -17,11 +22,14 @@ by its apparent sound power and its tonal audibility. What unites them is the
pattern: a carefully standardised source descriptor that the path model above
then attenuates.
-This section leans on the core toolkit more than any other: the rating levels
-and Lden that environmental assessment ends in live in
-[Integrated and Statistical Levels](/phonometry/signals/levels/levels/), and the
-atmospheric absorption that every propagation model consumes is shared with
-the room and materials pages. Start with
+This section leans on the core toolkit, but only up to the period level.
+[Integrated and Statistical Levels](/phonometry/signals/levels/levels/) supplies
+the LAeq, percentile and event levels of each reference period; what turns those
+period levels into Lden, Ldn and the rating level, with the tonal adjustment,
+the residual-noise correction and the uncertainty budget on top, is
+[Environmental Levels (ISO 1996-1/-2)](/phonometry/environment/assessment/environmental-levels/),
+in this section. The atmospheric absorption that every propagation model
+consumes is shared with the room and materials pages. Start with
[Outdoor Sound Propagation](/phonometry/environment/propagation/outdoor-propagation/); it
introduces the source-path-receiver bookkeeping the transport pages reuse.
diff --git a/site/src/content/docs/environment/propagation/atmospheric-refraction.mdx b/site/src/content/docs/environment/propagation/atmospheric-refraction.mdx
index 6608f2292..7ad47487b 100644
--- a/site/src/content/docs/environment/propagation/atmospheric-refraction.mdx
+++ b/site/src/content/docs/environment/propagation/atmospheric-refraction.mdx
@@ -233,6 +233,9 @@ cases = [
]
fig, ax = plt.subplots(figsize=(11, 6.2))
with warnings.catch_warnings():
+ # The PorousAbsorberWarning: a 200 kPa.s/m2 ground runs the one-parameter
+ # impedance model below its published fit range, as every outdoor ground
+ # does (see "Choosing the ground impedance" in the ground-effect guide).
warnings.simplefilter("ignore")
for profile, label in cases:
pe = atmospheric_parabolic_equation(400.0, profile, source_height=2.0,
@@ -294,6 +297,9 @@ axes[0].set(ylabel="Height [m]", ylim=(0, 40), title="Sound rays (upward refract
axes[0].legend()
with warnings.catch_warnings():
+ # The PorousAbsorberWarning: a 200 kPa.s/m2 ground runs the one-parameter
+ # impedance model below its published fit range, as every outdoor ground
+ # does (see "Choosing the ground impedance" in the ground-effect guide).
warnings.simplefilter("ignore")
pe = atmospheric_parabolic_equation(400.0, profile, source_height=zs,
flow_resistivity=200e3,
diff --git a/site/src/content/docs/environment/propagation/ground-barriers.mdx b/site/src/content/docs/environment/propagation/ground-barriers.mdx
index f5d5a4325..a4be8cc10 100644
--- a/site/src/content/docs/environment/propagation/ground-barriers.mdx
+++ b/site/src/content/docs/environment/propagation/ground-barriers.mdx
@@ -47,6 +47,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
The [ISO 9613-2 general method](/phonometry/environment/propagation/outdoor-propagation/) folds
the ground and barrier terms into tabulated, energy-based corrections. This page
@@ -166,6 +167,32 @@ the effective flow resistivity $\sigma \to \infty$ tends to that hard ground;
grazing incidence ($h_s, h_r \to 0$) gives $R_p \to -1$; and the ground
effect is reciprocal under an exchange of source and receiver heights.
+### Choosing the ground impedance
+
+Both one-parameter models are being evaluated far **below** their published fit
+range for any outdoor ground, and the `PorousAbsorberWarning` these calls raise
+says so: the range is $0.01 < X < 1$ with $X = \rho_0 f/\sigma$, and the
+grassland above sits at $X = 3.8\times10^{-4}$ at 63 Hz and 0.024 at 4 kHz — the
+asphalt curve of the figure never enters the range at all. Below the range the
+Delany-Bazley regression is an extrapolation whose classic failure is a negative
+real part of the surface impedance; **Miki** is the passivity-constrained refit
+to prefer there (see the fit-range paragraph of
+[Porous absorbers](/phonometry/materials/absorbers/porous-absorbers/)). The
+choice is not cosmetic: on the case above, `model="miki"` moves the excess
+attenuation by up to 3.6 dB (250 Hz band: 0.43 dB with Delany-Bazley,
+−3.18 dB with Miki).
+
+Typical **effective** flow resistivities, the ranges the figure above
+illustrates: fresh snow ≈ 10, forest floor ≈ 50, grassland and pasture
+≈ 150-300, compacted soil and gravel ≈ 1000-3000, asphalt and
+concrete > 20 000 kPa·s/m².
+
+For a real site, fit $\sigma$ to a short-range level-difference measurement
+between two microphone heights over the surface (the template method of
+ANSI/ASA S1.18). The fitted value is an *effective, model-bound* parameter: it
+must be quoted with the impedance model it was fitted with, and it is not the
+EN 29053 airflow resistivity of the same material.
+
## 2. Advanced barrier diffraction
Three levels of screening beyond the ISO 9613-2 $D_z$ term are provided by
@@ -183,6 +210,32 @@ $$
which tends to 5 dB at the shadow boundary $N \to 0$ and approximates Maekawa's
point-source curve within about 1.5 dB.
+The clip below is that formula as a field. It is the
+[2D FDTD solver](/phonometry/simulation/fdtd-simulation/) run twice on one
+12 × 7 m half-space over rigid ground with a thin rigid screen 2.5 m tall,
+once at 100 Hz and once at 500 Hz, each with a barrier-free reference run over
+the same ground so the annotated insertion loss is a true one. The geometry
+fixes the path difference at 1.06 m for the receiver it marks, so the Fresnel
+number is $N = 0.62$ at 100 Hz and $N = 3.1$ at 500 Hz — the same screen, a
+factor of five apart in $N$ purely because $\lambda$ changed — and the field
+shows what that buys: about 8 dB against about 17 dB. Two things are worth
+watching for. The edge of the lit region running down from the top of the
+screen is the shadow boundary, the $N \to 0$ locus where the formula bottoms
+out at 5 dB; and inside the shadow the field is a cylindrical wave centred on
+the top of the screen, which is what "the edge acts as a secondary source"
+looks like. One caveat: the ground in the clip is perfectly rigid, so it shows
+diffraction alone and none of the finite-impedance ground effect of section 1
+— the coherent four-path model below adds that, and its curve swings tens of
+decibels where this one is smooth.
+
+
+
The thin-screen methods share the same three geometric quantities: the two
diffracted segments over the edge and the straight path they replace. Drawn on
the 4 m screen of the snippets, they differ by just 0.15 m.
diff --git a/site/src/content/docs/environment/propagation/outdoor-propagation.mdx b/site/src/content/docs/environment/propagation/outdoor-propagation.mdx
index 4a95ad00a..70501d33e 100644
--- a/site/src/content/docs/environment/propagation/outdoor-propagation.mdx
+++ b/site/src/content/docs/environment/propagation/outdoor-propagation.mdx
@@ -476,6 +476,24 @@ Returns an `OutdoorAttenuation` with `a_div`, `a_atm`, `a_gr`, `a_bar`,
`a_total` and `d_omega`, all one value per band; its `.plot()` draws the
stacked per-band breakdown with the total overlaid (the figure above).
+:::note
+**The method is octave-band only.** ISO 9613-2 is defined for the eight nominal
+octave bands from 63 Hz to 8 kHz, and its Table 3 has no finer resolution, so
+every frequency passed in is mapped to the *nearest nominal octave* for the
+ground term while divergence and atmospheric absorption stay continuous in
+frequency. A one-third-octave call therefore returns a stepped $A_{gr}$, not a
+refined one: over 400 / 500 / 630 / 800 Hz on porous ground at 100 m,
+`a_gr` comes back as 7.65 / 7.65 / 7.65 / 1.76 dB (three bands sharing the
+500 Hz octave, then the 1 kHz octave) while `a_atm` moves smoothly through
+0.216 / 0.280 / 0.348 / 0.419 dB. Run the prediction in octaves and distribute
+afterwards if a finer spectrum is needed, or use the wave-acoustic
+`ground_effect` of
+[Ground effect and barriers](/phonometry/environment/propagation/ground-barriers/)
+when the interference structure inside an octave is the point. Nothing below
+63 Hz or above 8 kHz is covered at all, so a low-frequency assessment falls
+outside this method.
+:::
+
### `Barrier` fields
| Field | Type | Units | Default | Notes |
diff --git a/site/src/content/docs/environment/sources/cnossos-rail-emission.mdx b/site/src/content/docs/environment/sources/cnossos-rail-emission.mdx
index 33d232198..821063bfb 100644
--- a/site/src/content/docs/environment/sources/cnossos-rail-emission.mdx
+++ b/site/src/content/docs/environment/sources/cnossos-rail-emission.mdx
@@ -92,18 +92,25 @@ a real component sits between the two model heights, its energy is distributed
proportionately over them.
For each 1/3-octave band the flow equation turns a single-vehicle sound power
-into a power per metre of line (2.3.2), or, for a stationary vehicle, into the
-idling equivalent over the reference period (2.3.4):
+into a power per metre of line (2.3.2):
$$
L'_{W,\mathrm{eq,line},i}(\psi,\varphi) = L_{W,0,\mathrm{dir},i}(\psi,\varphi)
+ 10\,\log_{10}\!\left(\frac{Q}{1000\,v}\right),
-\qquad
-+\,10\,\log_{10}\!\left(\frac{T_\mathrm{idle}}{T_\mathrm{ref}\,L}\right).
$$
-$Q$ is in vehicles per hour, $v$ in km/h, $L$ the length of the track section in
-metres. Note the unit: the flow term uses km/h, while the roughness conversion
+or, for a stationary vehicle, the same directional power referred to the idling
+time over the reference period (2.3.4):
+
+$$
+L'_{W,\mathrm{eq,line},i}(\psi,\varphi) = L_{W,0,\mathrm{dir},i}(\psi,\varphi)
+ + 10\,\log_{10}\!\left(\frac{T_\mathrm{idle}}{T_\mathrm{ref}\,L}\right).
+$$
+
+The second replaces the first; it does not add to it. $Q$ is in vehicles per
+hour, $v$ in km/h, $L$ the length of the track section in metres, and
+$T_\mathrm{idle}$ and $T_\mathrm{ref}$ share whatever unit of time they are
+given in. Note the unit: the flow term uses km/h, while the roughness conversion
two sections down uses m/s. Both are correct, and mixing them up is the single
most expensive mistake available in this model.
diff --git a/site/src/content/docs/environment/sources/cnossos-road-emission.mdx b/site/src/content/docs/environment/sources/cnossos-road-emission.mdx
index 2cff19d6b..e7c0edd59 100644
--- a/site/src/content/docs/environment/sources/cnossos-road-emission.mdx
+++ b/site/src/content/docs/environment/sources/cnossos-road-emission.mdx
@@ -284,6 +284,7 @@ $dL$ simply carries $L'_{W,\mathrm{eq,line},i} + 10\log_{10}(dL)$, which is
arithmetic and is offered as such.
```python
+import numpy as np
from phonometry import (
PropagationGeometry, RoadTraffic, RoadVehicleCategory,
line_source_segment_power, predicted_receiver_level, road_source_power,
@@ -294,13 +295,38 @@ result = road_source_power([
RoadTraffic(RoadVehicleCategory.HEAVY, 120.0, 80.0),
])
segment = line_source_segment_power(result.total_line_power, 20.0) # a 20 m segment
+
+# One segment, the one directly opposite a receiver 100 m from the road.
levels = predicted_receiver_level(
segment,
PropagationGeometry(100.0, result.source_height, 4.0),
frequencies=result.frequencies,
)
+
+# The road is the energy sum of its segments: 1 km either way, in 20 m steps.
+energy = np.zeros_like(levels)
+for x in np.arange(-990.0, 1000.0, 20.0): # segment centres along the road
+ energy += 10 ** (predicted_receiver_level(
+ segment,
+ PropagationGeometry(float(np.hypot(100.0, x)), result.source_height, 4.0),
+ frequencies=result.frequencies,
+ ) / 10)
+road = 10 * np.log10(energy)
```
+Two rules make a segmentation defensible, and neither is method: 2.5.3 declares
+the split out of scope, so this is engineering practice. Each segment must be
+short enough that the point source at its centre stands for the whole segment —
+ISO 9613-2 allows one equivalent point source only where the propagation
+distance exceeds twice the largest source dimension, so a segment seen from
+100 m may be tens of metres long while one seen from 10 m may not. And the road
+must be modelled far enough in both directions that the tails stop mattering:
+beyond roughly ten times the perpendicular offset, adding segments changes the
+total by less than a tenth of a decibel, which is why 1 km either way is enough
+at 100 m here. The two spectra are read out in dB(A) two paragraphs down:
+**52.9 dB(A)** for the single segment against **64.7 dB(A)** for the road, an
+11.8 dB difference that is entirely the arithmetic above.
+
Note what this is and is not. CNOSSOS-EU has **its own** propagation method in
section 2.5 of Annex II, and it is not ISO 9613-2: the two differ in the ground
model, in the diffraction treatment and in the way favourable and homogeneous
@@ -316,6 +342,13 @@ from phonometry import CNOSSOS_A_WEIGHTING
CNOSSOS_A_WEIGHTING # (-26.2, -16.1, -8.6, -3.2, 0.0, 1.2, 1.0, -1.1)
result.a_weighted_line_power
+
+# The two receiver spectra of the segmentation above, A-weighted:
+weight = np.asarray(CNOSSOS_A_WEIGHTING)
+print(round(float(10 * np.log10(np.sum(10 ** ((levels + weight) / 10)))), 1))
+# 52.9 dB(A) - one 20 m segment, not the road
+print(round(float(10 * np.log10(np.sum(10 ** ((road + weight) / 10)))), 1))
+# 64.7 dB(A) - the same road, summed over 2 km: 11.8 dB more
```
## 7. Substituting a national database
diff --git a/site/src/content/docs/environment/sources/wind-turbine-noise.mdx b/site/src/content/docs/environment/sources/wind-turbine-noise.mdx
index a0db6c9ce..a288874d4 100644
--- a/site/src/content/docs/environment/sources/wind-turbine-noise.mdx
+++ b/site/src/content/docs/environment/sources/wind-turbine-noise.mdx
@@ -22,7 +22,7 @@ references:
title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
designation: "ISO 1996-2:2017"
url: "https://www.iso.org/standard/59766.html"
- note: "The tonal-audibility criterion the IEC method reuses comes from the Annex C of its 2007 edition (the 2017 edition carries the tonal methods in Annexes J and K), and its tonal_adjustment consumes the mean audibility."
+ note: "The tonal-audibility criterion the IEC method reuses comes from the Annex C of its 2007 edition (the 2017 edition carries the tonal methods in Annexes J and K), and its Table J.1 mapping, tonal_adjustment_from_mean_audibility, is the one that consumes the bin-mean audibility."
---
import ThemeImage from '../../../../components/ThemeImage.astro';
@@ -165,8 +165,19 @@ the 9.5.1 energy averaging of $\Delta L_a$ over the spectra of a wind-speed bin
$L_a$ criterion anchor to the highest classified tone line, not the probed
candidate. The audibility formula coincides with ISO 1996-2 Annex C; what is
specific to IEC 61400-11 is the determination of the tone and masking levels
-and the Zwicker critical band from the spectrum. For a rating adjustment
-$K_T$, pass the mean audibility to the ISO 1996-2 `tonal_adjustment`.
+and the Zwicker critical band from the spectrum. IEC 61400-11 stops at
+$\Delta L_a$ and prescribes no adjustment, so which mapping gives the rating
+adjustment $K_t$ depends on the edition the assessment is made under. The
+9.5.1 energy average over the spectra of a wind-speed bin is a *mean*
+audibility, which is the quantity ISO 1996-2:2017 Table J.1 was written for:
+[`tonal_adjustment_from_mean_audibility`](/phonometry/environment/assessment/environmental-levels/),
+integer 0-6 dB (or `coarse=True` for the 0/3/6 ladder of its note). The
+piecewise (C.4)-(C.6) law of `tonal_adjustment` is the 2007 Annex C mapping and
+applies to one spectrum's $\Delta L_{ta}$, and the two differ by 1 to 2 dB on
+the same input: $\Delta L = 5$ dB gives $K_t = 3$ by Table J.1 and 1.0 dB by
+Annex C, $\Delta L = 9$ dB gives 4 dB and 5.0 dB. The notation differs too:
+this page's $\Delta L_a$ is that page's $\Delta L_{ta}$, and the two printings
+carry the criterion with opposite signs.
### Assessment report (`.report()`)
diff --git a/site/src/content/docs/es/aircraft/aircraft-noise.mdx b/site/src/content/docs/es/aircraft/aircraft-noise.mdx
index 56c0f45fb..a2e1bf035 100644
--- a/site/src/content/docs/es/aircraft/aircraft-noise.mdx
+++ b/site/src/content/docs/es/aircraft/aircraft-noise.mdx
@@ -74,19 +74,42 @@ pnl = aircraft.perceived_noise_level(spl) # PNdB
## Corrección tonal
-Las irregularidades espectrales (tonos de ventilador/turbina) se penalizan con
-una **corrección tonal** $C$, hallada con el método de pendientes ("encircling"):
-las pendientes se suavizan a un espectro de fondo $\mathrm{SPL}''$, el exceso
-tonal $F = \mathrm{SPL} - \mathrm{SPL}''$ por encima de 1,5 dB se mapea a un
-factor de corrección (división de frecuencia en 500 Hz / 5000 Hz, con tope de
-6⅔ dB) y se toma el máximo sobre las bandas. La implementación reproduce
-exactamente el ejemplo del turbofán de la Tabla 3-7 del ETM Vol. I
+Un tono puro se juzga mucho más molesto que la misma energía repartida por su
+banda de tercio de octava, así que las irregularidades espectrales (tonos de
+ventilador y de turbina) se penalizan con una **corrección tonal** $C$. El
+método de pendientes ("encircling") reconstruye qué aspecto tendría el espectro
+*sin* el tono suavizando las pendientes de banda a banda hasta un fondo
+$\mathrm{SPL}''$, de modo que el exceso
+$F = \mathrm{SPL} - \mathrm{SPL}''$ es una magnitud que solo contiene el tono.
+Por encima de 1,5 dB se lleva a un factor de corrección con la regla de la
+Tabla A2-2, y se toma el máximo sobre las bandas:
+
+| Banda | $F < 3$ dB | $3 \le F < 20$ dB | $F \ge 20$ dB |
+|---|---|---|---|
+| 50 Hz-400 Hz y 6,3-10 kHz | $F/3 - 0{,}5$ | $F/6$ | $3\tfrac{1}{3}$ dB |
+| 500 Hz-5 kHz | $2F/3 - 1$ | $F/3$ | $6\tfrac{2}{3}$ dB |
+
+La rama de frecuencias medias penaliza un tono el doble de duro, que es la razón
+por la que un tono de ventilador de 2500 Hz domina la corrección de un espectro
+de turbofán. La implementación reproduce exactamente el ejemplo del turbofán de
+la Tabla 3-7 del ETM Vol. I de ICAO Doc 9501
($C = 2{,}0\ \text{dB}$ en 2500 Hz).
+El método trae dos trampas. Un espectro rizado pero sin tonos puede producir una
+corrección, que la propia norma permite rechazar tras un reanálisis en banda
+estrecha (§4.3.1, paso 10). Y un tono que cae entre dos bandas reparte su
+exceso, de modo que la corrección cruda sale demasiado pequeña; el **ajuste por
+reparto de bandas** $\Delta_B$, el defecto de $C$ en el registro de
+$\mathrm{PNLTM}$ frente a la media de los registros que quedan a menos de un
+segundo de él, lo devuelve antes de localizar la ventana de 10 dB por debajo.
+
```python
from phonometry import aircraft
c = aircraft.tone_correction(spl) # dB; se suma al PNL para dar PNLT
+# start_band=2 (80 Hz) es el inicio de análisis para avión; un procedimiento de
+# helicóptero empieza en 50 Hz, que es lo que selecciona procedure="helicopter"
+# en effective_perceived_noise_level más abajo.
```
## EPNL
@@ -109,10 +132,13 @@ res.plot() # historia temporal PNL/PNLT (requiere matplotlib)
```
`effective_perceived_noise_level` devuelve un `EPNLResult` con el `pnl` por
-registro, la `tone_correction`, el `pnlt`, el máximo `pnltm`, la
-`duration_correction`, el `epnl` y los `band_limits` de 10 dB por debajo. El
+registro, la `tone_correction`, el `pnlt`, el máximo `pnltm`, el
+`bandsharing_adjustment`, la `duration_correction`, el `epnl` y los
+`band_limits` de 10 dB por debajo. Su argumento `procedure=` arranca el análisis
+en 80 Hz para un avión (el valor por defecto) y en 50 Hz para un helicóptero. El
ejemplo del método integrado en condiciones de referencia de la Tabla 4-4 del
-ETM Vol. I se reproduce como $\mathrm{EPNL} = 92{,}6\ \text{EPNdB}$.
+ETM Vol. I, que es otra historia temporal de certificación distinta y real, se
+reproduce como $\mathrm{EPNL} = 92{,}6\ \text{EPNdB}$.
Mostrar el código de esta figura
@@ -178,7 +204,11 @@ res.report(
```
La ficha de ejemplo se regenera con `make reports` y se conserva renderizada en
-el repositorio; pulsa la vista previa para abrir el PDF.
+el repositorio; pulsa la vista previa para abrir el PDF. Está renderizada a
+partir de su propio sobrevuelo sintético, más silencioso (EPNL 98,3 EPNdB), y no
+de los espectros de la figura de arriba: si pasas esos por la misma llamada, la
+ficha informa de 114,0 EPNdB y de un NO CUMPLE frente a ese mismo límite de
+101 EPNdB, que es la fila de veredicto haciendo su trabajo.
f_0$ y se toman como cero en la resonancia
+y por debajo de ella. Eso es un convenio: en la banda que contiene $f_0$ el
+sistema masa-muelle amplifica y los suelos medidos caen ahí entre unos $-5$ dB y
+$0$ dB, así que un diseño cuya $f_0$ cae dentro del rango valorado de
+100-3150 Hz se valora de forma optimista justo en la banda que decide el número.
+Aquí $f_0$ vale 52,8 Hz, holgadamente por debajo del rango, y por eso el
+espectro de abajo arranca limpio en 100 Hz.
+
```python
import numpy as np
from phonometry import building, materials
diff --git a/site/src/content/docs/es/buildings/design/index.md b/site/src/content/docs/es/buildings/design/index.md
index 52a23273b..2b8f5ecfc 100644
--- a/site/src/content/docs/es/buildings/design/index.md
+++ b/site/src/content/docs/es/buildings/design/index.md
@@ -1,6 +1,6 @@
---
title: "Diseño del aislamiento"
-description: "El aislamiento acústico antes de construirlo: la predicción de flancos de EN 12354 entre recintos, el aislamiento teórico de un panel a partir de sus propiedades físicas y las dos mediciones de material que consume el diseño de un suelo (revestimientos ISO 16251-1, rigidez dinámica EN 29052-1)."
+description: "El aislamiento acústico antes de construirlo: la predicción de flancos de EN/ISO 12354 entre recintos en sus formas simplificada y por bandas, el aislamiento teórico de un panel a partir de sus propiedades físicas, las capas elásticas de las que depende el diseño de un suelo o de un trasdosado, y el sonido estructural de los equipos de instalaciones desde la placa de recepción de EN 15657 hasta el nivel en el recinto receptor de EN 12354-5."
---
Las páginas de la sección de
@@ -36,16 +36,45 @@ de una doble hoja, la transmisión por rendijas y aberturas, la eficiencia de
radiación de placas y las movilidades puntuales. Es la física que un valor de
catálogo resume en un número.
-Dos mediciones alimentan la mitad de suelos de cualquier diseño.
+Dos páginas de aquí llevan la mitad de suelos de cualquier diseño, una que mide
+y otra que predice.
[Mejora del aislamiento a impacto de suelos (ISO 16251-1)](/phonometry/es/buildings/design/impact-improvement/)
-da la mejora ponderada $\Delta L_w$ de un revestimiento blando sobre una
-maqueta pesada pequeña, el término que EN 12354-2 resta al nivel del forjado
-desnudo, y
-[Rigidez dinámica de materiales resilientes (EN 29052-1)](/phonometry/es/materials/resilient/dynamic-stiffness/)
-da la rigidez por unidad de superficie $s'$ de la capa elástica bajo un suelo
-flotante y, con ella, la frecuencia de resonancia de la que depende toda la
+da la mejora ponderada $\Delta L_w$ de un revestimiento que ya existe, sobre una
+maqueta pesada pequeña, y ese es el término que EN 12354-2 resta al nivel del
+forjado desnudo.
+[Predicción del comportamiento de capas elásticas](/phonometry/es/buildings/design/resilient-layers/)
+la predice para un revestimiento que todavía no existe, a partir del espectro de
+fuerza de la propia máquina de impactos, la frecuencia de corte de un
+revestimiento blando, las leyes de 30 lg y 40 lg del suelo flotante y la
+magnitud global de un trasdosado según el anexo D de ISO 12354-1.
+Ambas parten de la rigidez por unidad de superficie $s'$ de la capa elástica,
+medida según EN 29052-1 en
+[Rigidez dinámica de materiales resilientes](/phonometry/es/materials/resilient/dynamic-stiffness/)
+en la sección de materiales, que fija la resonancia de la que depende toda la
mejora.
+Los equipos de instalaciones del edificio son una cadena aparte, y sus dos
+páginas solo se leen bien en orden.
+[Potencia acústica estructural de equipos (EN 15657)](/phonometry/es/buildings/design/structure-borne-power/)
+caracteriza una bomba, un ventilador o una cisterna por la potencia que inyecta
+en la estructura, medida sobre una placa de recepción de disipación conocida y
+convertida después en independiente de la placa.
+[Sonido estructural instalado (EN 12354-5)](/phonometry/es/buildings/design/installed-structure-borne/)
+toma esa descripción de fuente, pierde parte de ella en el término de
+acoplamiento que fijan las movilidades de fuente y de receptor, y lleva el resto
+a un recinto que puede estar a varias uniones de distancia.
+
+Una nota de contabilidad recorre toda la sección: la familia existe como
+EN 12354:2000 y como ISO 12354:2017, y las dos no son intercambiables en todas
+las cláusulas. Los modelos simplificados de
+[Predicción del aislamiento acústico](/phonometry/es/buildings/design/insulation-prediction/)
+siguen el texto de 2000 — incluida la corrección tabulada por flancos $K$ que la
+parte de impactos de 2017 sustituyó por fórmulas explícitas camino a camino —
+mientras que
+[Predicción detallada por bandas](/phonometry/es/buildings/design/detailed-prediction/)
+sigue el texto de 2017. Comprueba qué edición invoca tu reglamento antes de
+citar una corrección de cualquiera de las dos.
+
## Páginas de esta sección
- [Predicción del aislamiento acústico (EN 12354)](/phonometry/es/buildings/design/insulation-prediction/):
diff --git a/site/src/content/docs/es/buildings/design/installed-structure-borne.mdx b/site/src/content/docs/es/buildings/design/installed-structure-borne.mdx
index 128061a5f..2360d1ab4 100644
--- a/site/src/content/docs/es/buildings/design/installed-structure-borne.mdx
+++ b/site/src/content/docs/es/buildings/design/installed-structure-borne.mdx
@@ -63,11 +63,14 @@ ys = (2e-4 + 1e-4j) * (bands / 250.0) # movilidad de la fuente
yi = (3e-5 + 1e-5j) * np.ones_like(bands) # movilidad del receptor
dc = np.array([float(building.coupling_term(a, b)) for a, b in zip(ys, yi)])
-# Dos vías de transmisión: el forjado excitado y una pared de flanco.
+# Dos vías de transmisión: el forjado excitado y una pared de flanco. Dsa es
+# negativo y cae con la frecuencia (Anexo F.2), y entra con signo menos.
paths = [
- {"adjustment_term": 6.0, "element_area": 12.0,
+ {"adjustment_term": np.array([-14.0, -17.0, -20.0, -25.0, -30.0, -35.0, -40.0]),
+ "element_area": 12.0,
"flanking_reduction_index": np.linspace(44.0, 62.0, 7)},
- {"adjustment_term": 7.0, "element_area": 9.0,
+ {"adjustment_term": np.array([-16.0, -19.0, -23.0, -28.0, -33.0, -38.0, -43.0]),
+ "element_area": 9.0,
"flanking_reduction_index": np.linspace(46.0, 64.0, 7)},
]
res = building.installed_source_prediction(lws_c, dc, paths, frequencies=bands)
@@ -94,6 +97,16 @@ velocidad** (movilidad de fuente baja, Fórmula 19d); un soporte elástico añad
movilidad de transferencia $Y_k$ dentro del módulo (Fórmula 19e). El nivel de
potencia **instalada** es entonces (Fórmula 18b) $L_{Ws,\mathrm{inst}} = L_{Ws,c} - D_C$.
+Este $L_{Ws,\mathrm{inst}}$ es el mismo que el de la corrección por movilidad
+del Anexo I de la introducción, alcanzado por otro camino: usa la Fórmula (18b)
+cuando $D_C$ se conoce a partir de las dos movilidades, y la corrección directa
+$L_{Ws,n} + 10\log_{10}(Y_{\infty,i}/Y_{\infty,\mathrm{rec}})$ cuando no. Sobre
+la cisterna del Anexo I.3 las dos dan 68,2 dB a 63 Hz, a partir de
+$L_{Ws,c} = 84,4$ dB y $D_C = 16,2$ dB. Fíjate en qué magnitud te entregan:
+$L_{Ws,c}$ es la entrada que toma esta página, y *no* es los 68,2 dB que la
+[página de EN 15657](/phonometry/es/buildings/design/structure-borne-power/)
+imprime como su nivel instalado — meter ese valor aquí resta $D_C$ dos veces.
+
La física detrás de $D_C$ es la clásica potencia de entrada de una placa
excitada en un punto: solo la parte real de la movilidad en el punto de
excitación del receptor absorbe potencia, y el desajuste entre $Y_s$ e $Y_i$
@@ -140,20 +153,70 @@ L_{n,s,ij} = L_{Ws,\mathrm{inst},i} - D_{sa,i} - R_{ij,\mathrm{ref}}
- 10\log_{10}\frac{S_i}{S_0} - 10\log_{10}\frac{A_0}{4},
$$
-con $S_0 = A_0 = 10\ \text{m}^2$, y los caminos se combinan energéticamente (Fórmula 17):
+con $S_0 = A_0 = 10\ \text{m}^2$, y los caminos se combinan energéticamente (Fórmula 17).
+
+### El término de ajuste $D_{sa}$
+
+Una fuerza puntual bombea energía a ondas de flexión *libres*, mientras que un
+campo acústico incidente excita además ondas *forzadas*. $D_{sa}$ es el factor
+de contabilidad que permite reutilizar el índice de flancos aéreo
+$R_{ij,\mathrm{ref}}$ — una magnitud aérea — para un elemento excitado
+estructuralmente: convierte la potencia estructural inyectada en la potencia
+aérea incidente que dejaría al elemento con la misma energía de vibración libre
+(Fórmula 20a). Para la excitación por fuerza perpendicular de un elemento
+homogéneo eso se convierte en la Fórmula (20b),
+
+$$
+D_{sa,i} = 10\log_{10}\frac{2\pi m_i\,2.2\,\tau_i}{\rho_0 c_0 T_{s,i}\sigma_i}\ \text{dB},
+$$
+
+con $R_i = -10\log_{10}\tau_i$, y el Anexo F.2 da la forma de trabajo
+
+$$
+D_{sa,i} = 10\log_{10}\frac{400\,f_{c,i}\,\sigma_i}{m_i\,f^2}\ \text{dB}
+\qquad\text{(Fórmula F.3)},
+$$
+
+exacta por encima de la frecuencia crítica ($\sigma_i \approx 1$) y buena
+aproximación en todo el rango. Léela así: los elementos más pesados y las
+frecuencias más altas hacen $D_{sa}$ *más negativo*, a razón de
+$-20\log_{10}f$ una vez que $\sigma$ se ha saturado.
+
+:::caution
+**$D_{sa}$ es normalmente negativo — pasa el valor tabulado con el signo con el
+que está impreso.**
+Las columnas del Anexo I de la propia norma van de unos $-14$ dB a 63 Hz a
+$-45$ dB a 2 kHz para elementos corrientes de hormigón y de fábrica. El término
+entra en la Fórmula (18a) con signo menos, así que un $D_{sa}$ negativo *sube*
+el nivel previsto. Revisiones anteriores de esta página pasaban
+`"adjustment_term": 5.0` y `6.0`; copiar ese patrón poniendo en su lugar un
+valor real del Anexo F dejaría la predicción entre unos 20 y 40 dB por debajo en
+todo el espectro, y sin que se levante ningún error.
+:::
+
+Todas las entradas de la Fórmula (F.3) están ya disponibles:
+[`in_situ_element`](/phonometry/es/buildings/design/detailed-prediction/)
+devuelve el tiempo de reverberación estructural in situ, el factor de radiación
+y la $R$ del elemento.
```python
import numpy as np
from phonometry import building
+# Fórmula (F.3) para la pared de 92 kg/m2 del edificio resuelto del Anexo I.
+f = np.array([63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0])
+sigma = np.minimum(1.0, np.sqrt(f / 200.0)) # factor de radiación, fc = 200 Hz
+dsa_f3 = 10 * np.log10(400.0 * 200.0 * sigma / (92.0 * f**2))
+print(np.round(dsa_f3, 1)) # [-9.1 -13.6 -18.6 -24.6 -30.6 -36.6] todos negativos
+
bands = np.array([250.0, 500.0, 1000.0])
res = building.installed_source_prediction(
characteristic_power_level=np.array([80.0, 82.0, 78.0]),
coupling_term=np.array([9.0, 10.0, 11.0]),
paths=[
- {"adjustment_term": 5.0,
+ {"adjustment_term": np.array([-19.0, -25.0, -31.0]),
"flanking_reduction_index": np.array([50.0, 52.0, 55.0]), "element_area": 12.0},
- {"adjustment_term": 6.0,
+ {"adjustment_term": np.array([-22.0, -28.0, -34.0]),
"flanking_reduction_index": np.array([52.0, 54.0, 57.0]), "element_area": 8.0},
],
frequencies=bands,
diff --git a/site/src/content/docs/es/buildings/design/insulation-prediction.mdx b/site/src/content/docs/es/buildings/design/insulation-prediction.mdx
index 32e4704ae..2a7f66e3e 100644
--- a/site/src/content/docs/es/buildings/design/insulation-prediction.mdx
+++ b/site/src/content/docs/es/buildings/design/insulation-prediction.mdx
@@ -205,6 +205,24 @@ desnudo $L_{n,w,eq} = 164 - 35 \log_{10}(m'/m'_0)$ (Anexo B), la mejora del
revestimiento $\Delta L_w$ (ISO 717-2) y la corrección por flancos $K$ de la
Tabla 1.
+**Comprueba qué edición cita tu reglamento.** El modelo anterior es el de
+EN 12354-2:2000, que condensa toda la transmisión por flancos en la única
+corrección tabulada $K$ que se lee a partir de la masa del elemento separador y
+de la masa media de los flancos. ISO 12354-2:2017 reorganizó ese mismo modelo
+simplificado en fórmulas explícitas camino a camino
+— $L_{n,d,w} = L_{n,eq,0,w} - \Delta L_w - \Delta L_{d,w}$ (15) para el camino
+directo y, para cada camino de flanco,
+$L_{n,ij,w} = L_{n,eq,0,w} - \Delta L_w + (R_{i,w} - R_{j,w})/2 - \Delta R_{j,w} -
+K_{ij} - 10\log_{10}(S_i/l_0 l_{ij})$ (16) —, de modo que **la corrección de
+la Tabla 1 no está en el texto vigente en absoluto**, aunque la física de fondo
+y la declaración de exactitud no hayan cambiado. La edición de 2017 declara
+además un campo de aplicación que el texto de 2000 dejaba implícito
+(apartado 4.3.1): el modelo simplificado se restringe a 100 Hz–3150 Hz y, para
+construcciones ligeras, a la vía del nivel de impactos normalizado por flancos
+medido $L_{nf,ij}$ de la Fórmula (17). La vía por bandas de frecuencia de
+[Predicción detallada por bandas](/phonometry/es/buildings/design/detailed-prediction/)
+está anclada en las ediciones de 2017 de principio a fin.
+
```python
from phonometry import building
diff --git a/site/src/content/docs/es/buildings/design/panel-sound-insulation.mdx b/site/src/content/docs/es/buildings/design/panel-sound-insulation.mdx
index 463f286d8..c7fbfd127 100644
--- a/site/src/content/docs/es/buildings/design/panel-sound-insulation.mdx
+++ b/site/src/content/docs/es/buildings/design/panel-sound-insulation.mdx
@@ -732,20 +732,48 @@ Cuánta potencia aérea radia realmente una placa vibrante por unidad de velocid
cuadrática media es su **eficiencia de radiación** $\sigma$: el factor de
radiación $\varepsilon$ que
[Potencia acústica a partir de la vibración](/phonometry/es/devices/emission/vibration-sound-power/)
-(ISO 7849) toma en otro caso como entrada medida. Por debajo de la frecuencia
-crítica la placa radia poco (modos de borde y de esquina); por encima
-$\sigma \to 1$ (Leppington/Maidanik, Hopkins Ec. 2.227-2.230):
+(ISO 7849) toma en otro caso como entrada medida. Se define como el cociente
+entre la potencia que la placa radia realmente y la que radiaría un pistón
+rígido de la misma superficie y la misma velocidad cuadrática media, de manera
+que $\sigma = 1$ significa «tan eficiente como un pistón» — y, como muestran los
+números de abajo, cerca de la coincidencia una placa puede superarlo.
+
+Hay tres regímenes, no dos (Leppington/Maidanik, Hopkins Ec. 2.227-2.230). **Muy
+por debajo de $f_c$** la longitud de onda de flexión es más corta que la
+acústica, las semiondas contiguas se cancelan mutuamente el caudal volumétrico y
+solo radian las franjas sin cancelar de los bordes y las esquinas. Por eso el
+cálculo necesita las dos dimensiones de la placa y su condición de borde: un
+borde empotrado radia más que uno simplemente apoyado, y una placa con bafles
+perpendiculares a sus bordes más que una enrasada en un bafle infinito — los
+argumentos `boundary` y `baffle` eligen entre ellos. **Alrededor de $f_c$** la
+longitud de onda de traza de la onda de flexión coincide con la acústica, la
+forma de Leppington $(1 - f_c/f)^{-1/2}$ diverge y queda limitada por la
+expresión en coincidencia; el panel de abajo alcanza un máximo de
+$\sigma = 2,6$ en la banda de 2 kHz. **Solo muy por encima de $f_c$** se asienta
+$\sigma$ hacia 1: un tercio de octava pasada la coincidencia este panel sigue en
+1,74.
$$
-\sigma = \frac{1}{\sqrt{1 - f_c/f}} \quad (f > f_c), \qquad \sigma \to 1 .
+\sigma = \frac{1}{\sqrt{1 - f_c/f}} \quad (f > f_c), \qquad
+\sigma \to 1 \quad (f \gg f_c) .
$$
+Merece la pena llevarse dos consecuencias. Una placa *pequeña* es, por debajo de
+$f_c$, mejor radiador relativo que una grande del mismo material, porque la
+franja de borde que radia es una fracción mayor de ella: el panel de
+1,5 × 1,25 m de abajo da $\sigma = 0,011$ a 100 Hz, y un panel de 0,5 × 0,4 m
+del mismo vidrio, 0,034. Y el valle de coincidencia de $R$ y el pico de
+coincidencia de $\sigma$ son el mismo suceso visto por los dos lados — la misma
+$\sigma$ reaparece en el factor de transmisión del modelo detallado de
+EN 12354 y como el factor de radiación que mide ISO 7849.
+
```python
from phonometry import radiation_efficiency, sound_power_from_vibration
# El panel de vidrio de 6 mm (1.5 x 1.25 m) del ejemplo de panel simple anterior.
sig = radiation_efficiency(bands, 1.5, 1.25, fc)
-print(sig.radiation_efficiency[bands == 2000].round(2)) # ~2.5 (pico en coincidencia)
+print(sig.radiation_efficiency[bands == 2000].round(2))
+# 2.6, el pico de coincidencia: la placa radia más que un pistón cerca de fc
# Alimenta la predicción directamente a ISO 7849 como el factor de radiación:
lw = sound_power_from_vibration(velocity_level=80.0, area=1.875,
@@ -903,6 +931,14 @@ real proviene de resonancias de los tramos de panel entre nervios, que ninguna
de las dos vías predice. Solo la greca sinusoidal tiene aquí rigideces
equivalentes; la chapa trapezoidal necesita las suyas, de la bibliografía que
cita Vigran.
+El modelo de llaves está en la misma situación por su lado de salida: las
+entradas son datos impresos, pero no hay tabulado ningún índice de reducción
+acústica publicado de un muro de fábrica con cámara puenteado, así que la
+penalización por bandas que causan las llaves no tiene oráculo numérico y solo
+está anclado el desplazamiento de la resonancia (Hopkins Fig. 4.35, de 26 Hz a
+50 Hz). El factor de pérdidas por acoplamiento no se introduce aquí en un
+análisis estadístico de energía completo; combinarlo con el camino aéreo
+exigiría toda la cadena sala-placa-cámara-placa-sala.
## Véase también
diff --git a/site/src/content/docs/es/buildings/design/resilient-layers.mdx b/site/src/content/docs/es/buildings/design/resilient-layers.mdx
index 158243d94..2a5982979 100644
--- a/site/src/content/docs/es/buildings/design/resilient-layers.mdx
+++ b/site/src/content/docs/es/buildings/design/resilient-layers.mdx
@@ -58,9 +58,9 @@ y en
Todo lo que sigue depende de la fuerza que la máquina de impactos normalizada
inyecta realmente, y esa fuerza no es una propiedad solo de la máquina. Cada
martillo es una masa de 0,5 kg que cae desde 40 mm, de modo que llega a
-$v_0 = \sqrt{2gh} = 0{,}886\ \text{m/s}$, diez veces por segundo. Si el impacto
+$v_\text{h} = \sqrt{2gh} = 0{,}886\ \text{m/s}$, diez veces por segundo. Si el impacto
fuese corto frente a los 0,1 s entre golpes, la cantidad de movimiento fijaría
-por sí sola la fuerza y daría el espectro de líneas $|F_n| = 2 m v_0 / T_i$ y
+por sí sola la fuerza y daría el espectro de líneas $|F_n| = 2 m v_\text{h} / T_i$ y
la fuerza cuadrática media por banda $F_\text{rms}^2 = 3{,}9 B$ con la que se
reducen habitualmente las medidas ISO 10140 sobre hormigón.
@@ -70,11 +70,11 @@ un sistema masa-resorte-amortiguador cuyo impulso se divide en dos casos:
- **sobrecrítico**, $K m \ge 4 Z_\text{dp}^2$: un único impulso positivo, sin
rebote. Es el caso de una superficie de paso ligera (tablero de partículas,
- OSB), donde el espectro tiende a $|F_n|_\text{lower} = m v_0/T_i$;
+ OSB), donde el espectro tiende a $|F_n|_\text{lower} = m v_\text{h}/T_i$;
- **subcrítico**, $K m < 4 Z_\text{dp}^2$: el martillo rebota y solo cuenta el
primer lóbulo positivo. Es el caso de una losa de hormigón o una solera,
donde el espectro queda a menos de 1 dB de
- $|F_n|_\text{upper} = 2 m v_0/T_i$ por debajo de 4 kHz y la estimación de
+ $|F_n|_\text{upper} = 2 m v_\text{h}/T_i$ por debajo de 4 kHz y la estimación de
impulso corto es suficiente.
Los dos límites distan 6 dB en valor cuadrático medio, que es justo la razón
@@ -221,11 +221,21 @@ se aplica es una pregunta sobre el amortiguamiento, no sobre la capa:
| Modelo | Ley | Cuándo |
| --- | --- | --- |
-| `"cremer"` | $\Delta L = 40 \log_{10} (f/f_0)$ | resultado de placa infinita de Cremer; soleras de asfalto y suelos flotantes secos, cuyas pérdidas internas bastan para comportarse como placas infinitas (fórmula C.3 de ISO 12354-2) |
+| `"cremer"` | $\Delta L = 40 \log_{10} (f/f_0)$ | resultado de placa infinita de Cremer; soleras de asfalto y suelos flotantes secos, cuyas pérdidas internas bastan para comportarse como placas infinitas (fórmula C.3 de ISO 12354-2). La deducción se declara válida en $f_0 < f < 4f_0$, así que la rama muy por encima de la resonancia es una extrapolación |
| `"en12354"` | $\Delta L = 30 \log_{10} (f/f_0)$ | soleras de mortero de cemento y de sulfato de calcio, cuyo bajo factor de pérdidas las convierte en placas finitas con campo reverberante de flexión (fórmula C.1) |
| `"cremer_hammer"` | $40 \log_{10} (f/f_0) + 10 \log_{10}[1 + (f/f_\text{limit})^2]$ | superficie de paso ligera, donde la impedancia del martillo ya no es despreciable; tiende a 18 dB por octava |
-
+Las tres leyes están escritas para $f > f_0$, y la biblioteca las recorta a cero
+en la resonancia y por debajo de ella. Ese recorte es un convenio, no un
+resultado físico: en la banda que contiene $f_0$ el sistema masa-resorte
+amplifica, y los suelos medidos caen ahí entre unos $-5$ dB y $0$ dB — el
+*peor que la desnuda en $f_0$* de la introducción, que ningún modelo de esta
+página reproduce. Mientras $f_0$ quede por debajo del rango valorado la
+diferencia es inocua, pero una capa rígida o una solera ligera que sitúe $f_0$
+cerca de 100 Hz produce un $\Delta L_w$ optimista justo en la banda que decide
+la valoración. Comprueba dónde cae $f_0$ antes de fiarte del número.
+
+
Ver el código de esta figura
@@ -342,7 +352,7 @@ from phonometry import (
)
# Placa de yeso de 9,5 mm laminada con 32 mm de EPS (s' = 65 MN/m3), adherida
-# con pelladas a una pared de bloque de hormigón celular de 51 kg/m2.
+# con pelladas a una pared de bloque de hormigón celular de 100 mm y 51 kg/m2.
f0 = lining_resonance_frequency(51.0, 6.3, dynamic_stiffness=65e6)
round(f0) # 542 Hz: justo en medio
round(weighted_lining_improvement(f0, 45.0)) # -9 dB, empeora las cosas
diff --git a/site/src/content/docs/es/buildings/design/structure-borne-power.mdx b/site/src/content/docs/es/buildings/design/structure-borne-power.mdx
index ceba1e971..44172a5af 100644
--- a/site/src/content/docs/es/buildings/design/structure-borne-power.mdx
+++ b/site/src/content/docs/es/buildings/design/structure-borne-power.mdx
@@ -103,9 +103,13 @@ L_{Ws} = 10\log_{10}\!\left(\frac{2\pi f\,\eta\,m\,S}{f_0\,m_0\,S_0}\right)
+ L_v - 60 \;\;[\mathrm{dB\ re\ 1\ pW}],
$$
-con las referencias $f_0 = 1\ \text{Hz}$, $m_0 = 1\ \text{kg}$,
+con las referencias $f_0 = 1\ \text{Hz}$, $m_0 = 1\ \text{kg}$ (impresa como
+1 kg; la magnitud que normaliza es una masa por unidad de superficie, así que la
+referencia es $1\ \text{kg/m}^2$ — véase el
+[registro de erratas](/phonometry/es/reference/errata/)),
$S_0 = 1\ \text{m}^2$; el término $-60\ \text{dB}$ es $10\log_{10}(v_0^2/P_0)$ para
-la velocidad de referencia de EN 15657 $v_0 = 10^{-9}\ \text{m/s}$. La
+la velocidad de referencia de EN 15657 $v_0 = 10^{-9}\ \text{m/s}$ y
+$P_0 = 1\ \text{pW}$. La
velocidad de la placa es la media energética espacial sobre las $N$ posiciones
(Fórmula 12) y el factor de pérdida procede del tiempo de reverberación
estructural $T_s$ (Fórmula 13, idéntica al factor de pérdida total de
@@ -147,12 +151,26 @@ inyectada en la placa junto con su movilidad puntual (véase la
la descripción de la fuente para el modelo de EN 12354-5 a través de la cadena
de conversión siguiente.
+:::caution
+**Dos velocidades de referencia comparten el símbolo $v_0$.**
+EN 15657 y EN 12354-5 refieren los niveles de velocidad a
+$v_0 = 10^{-9}$ m/s (1 nm/s); ISO 9611 e ISO/TS 7849 los refieren a
+$5\times10^{-8}$ m/s (50 nm/s). Las dos se diferencian en
+$20\log_{10}(50) = 33,98$ dB, así que un nivel de velocidad libre tomado de un
+informe ISO 9611 hay que reducirlo en 34,0 dB antes de que entre en la
+Fórmula (18) o en cualquier magnitud de EN 12354-5. El apartado 3 de abajo usa
+las dos referencias con pocas líneas de diferencia.
+:::
+
## 3. De la potencia de placa a las magnitudes de fuente (Fórmulas 15–19)
La $L_{Ws}$ inyectada en la placa **no** es un descriptor de la fuente: la misma
fuente inyecta una potencia distinta en un receptor distinto. La EN 15657
deriva las magnitudes independientes de la placa: el **nivel de fuerza
-bloqueada equivalente** (Fórmula 15, re $F_0 = 10^{-6}\ \text{N}$) desde la
+bloqueada equivalente** (Fórmula 15, re $F_0 = 10^{-6}\ \text{N}$, no la
+referencia de 1 N del
+[nivel de exposición a la fuerza de impacto](/phonometry/es/buildings/insulation/heavy-impact-sources/)
+de ISO 16283-2, a 120 dB de distancia) desde la
placa de baja movilidad,
$$
@@ -186,13 +204,45 @@ lwsn = building.characteristic_reception_plate_power(lfb) # Fórmula (17
inst = building.installed_power_from_reception_plate(lwsn, 24.1e-6) # Anexo I
print(round(float(lwsn), 1), round(float(inst), 1)) # 61.4 68.2 (Tabla I.8)
-# La velocidad libre (Fórmula 18) y la fuerza bloqueada cierran la movilidad (19):
+# La misma corrección del Anexo I llevada a la movilidad de la FUENTE da en
+# cambio el nivel de potencia característico independiente de la placa que
+# EN 12354-5 pide como entrada:
+lwsc = building.installed_power_from_reception_plate(lwsn, 1.0e-3)
+print(round(float(lwsc), 1)) # 84.4 L_Ws,c
+
+# La velocidad libre (Fórmula 18) y la fuerza bloqueada cierran la movilidad (19).
+# El valor 1.0e-2 m/(N.s) es la movilidad mínima especificada por EN 15657 para
+# la placa de alta movilidad, no un número arbitrario.
lvf = building.equivalent_free_velocity_level(70.0, 1.0e-2)
print(float(building.source_mobility_from_levels(lvf, lfb))) # |Y_S,eq| en m/(N·s)
```
+Lee la cadena en orden. La cisterna inyecta 61,7 dB en la placa de medida;
+quitar la movilidad de esa placa deja una fuerza bloqueada equivalente, y
+volver a expresar esa misma fuerza sobre la placa normalizada de hormigón de
+10 cm, de $Y_{R,\infty,\text{baja}} = 5\times10^{-6}\ \text{m/(N·s)}$, da
+$L_{Wsn} = 61,4$ dB, el número que un fabricante puede declarar. Referir esa
+misma fuerza a la pared receptora real ($Y = 24,1\times10^{-6}$) suma
+$10\log_{10}(24,1/5,0) = 6,8$ dB y da 68,2 dB. Ese paso es toda la lección del
+apartado: un receptor ligero y de movilidad alta acepta más potencia de la misma
+fuente, así que un $L_{Wsn}$ declarado compara máquinas y nunca es la potencia
+que verá un edificio concreto.
+
+:::caution
+**De la misma corrección salen dos magnitudes; no las confundas.**
+Con la movilidad del *receptor* da el nivel de potencia instalada
+$L_{Ws,\mathrm{inst}} = 68,2$ dB. Con la movilidad de la *fuente* da el nivel de
+potencia característico independiente de la placa $L_{Ws,c} = 84,4$ dB, y eso es
+lo que [EN 12354-5](/phonometry/es/buildings/design/installed-structure-borne/)
+toma como entrada, del que resta el término de acoplamiento $D_C = 16,2$ dB para
+volver a los mismos 68,2 dB. Alimenta EN 12354-5 con los 84,4, nunca con los
+68,2: arrastrar 68,2 como nivel de potencia característico resta $D_C$ una
+segunda vez y cae 16 dB por debajo, sin que se levante ningún error.
+:::
+
El homólogo directo del lado de la fuente es el nivel de velocidad libre de
-ISO 9611 (re $v_0 = 5\times10^{-8}\ \text{m/s}$) medido en los puntos de
+ISO 9611 (re $v_0 = 5\times10^{-8}\ \text{m/s}$, la referencia de 50 nm/s del
+aviso de arriba, no la de 1 nm/s de la Fórmula 14) medido en los puntos de
contacto de maquinaria
montada elásticamente; su media por posiciones de la ecuación (9) es
`mean_free_velocity_level()`.
@@ -222,7 +272,7 @@ sobre el total $L_{Ws}$ (una emisión de potencia es una magnitud donde menos es
mejor, así que la fuente cumple en el límite o por debajo). `verbose=True` añade
la columna del factor de pérdidas de la placa $\eta$ a la tabla.
`language="es"` genera la ficha en español con comas decimales. La franja de
-base recuerda que el nivel inyectado en la placa debe convertirse a las
+base enuncia la Fórmula 14 y recuerda que el nivel inyectado en la placa debe convertirse a las
magnitudes de fuente independientes de la placa (Fórmulas 15/17) antes de
alimentar la EN 12354-5.
diff --git a/site/src/content/docs/es/buildings/insulation/flanking-lab.mdx b/site/src/content/docs/es/buildings/insulation/flanking-lab.mdx
index 5a8f38dde..a14bd0e90 100644
--- a/site/src/content/docs/es/buildings/insulation/flanking-lab.mdx
+++ b/site/src/content/docs/es/buildings/insulation/flanking-lab.mdx
@@ -64,9 +64,11 @@ import ThemeImage from '../../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../../components/ReportPreview.astro';
EN 12354 predice un edificio a partir de sus uniones, e ISO 10848 es la vía
-por la que una unión consigue su número. Dos elementos estructuralmente
-desacoplados se encuentran en un banco de uniones de laboratorio;
-excitadores y máquinas de impactos accionan uno de ellos, y las diferencias
+por la que una unión consigue su número. Dos elementos unidos rígidamente a lo
+largo de un borde común se montan en un banco de laboratorio cuyos recintos
+están aislados estructuralmente entre sí y de la estructura circundante, de modo
+que la unión ensayada es el único camino entre ellos; excitadores y máquinas de
+impactos accionan uno de los elementos, y las diferencias
de nivel de velocidad a través de la unión se condensan en el **índice de
reducción de vibraciones** $K_{ij}$, junto con los descriptores globales de
flanco $D_{n,f}$ (aéreo) y $L_{n,f}$ (impacto). Esta guía cubre esa cadena
diff --git a/site/src/content/docs/es/buildings/insulation/heavy-impact-sources.mdx b/site/src/content/docs/es/buildings/insulation/heavy-impact-sources.mdx
index 9e766d3f3..0b75cca5c 100644
--- a/site/src/content/docs/es/buildings/insulation/heavy-impact-sources.mdx
+++ b/site/src/content/docs/es/buildings/insulation/heavy-impact-sources.mdx
@@ -62,7 +62,8 @@ y [Medición del aislamiento en laboratorio](/phonometry/es/buildings/insulation
*Izquierda: las dos especificaciones son espectros puros de fuerza, no de
geometría. Derecha: la valoración suma en energía las contribuciones
-ponderadas A, de modo que la banda de 63 Hz decide casi todo.*
+ponderadas A, y la ponderación A cae 23 dB más a 63 Hz que a 500 Hz, así que
+acaba decidiendo el número la banda medida más silenciosa.*
## Ambas fuentes se especifican por la energía de su impulso de fuerza
@@ -75,7 +76,12 @@ L_{FE} = 10\log_{10}\!\left[\frac{1}{T_\text{ref}}
\int_{t_1}^{t_2}\frac{F^2(t)}{F_0^2}\,\mathrm{d}t\right]\ \text{dB re 1 N},
$$
-con $F_0 = 1$ N, $T_\text{ref} = 1$ s y $t_2 - t_1$ la duración del impacto.
+con $F_0 = 1$ N (ISO 16283-2:2020 Anexo A), $T_\text{ref} = 1$ s y
+$t_2 - t_1$ la duración del impacto. Ojo con la referencia: la EN 15657 refiere
+sus niveles de fuerza bloqueada a $F_0 = 10^{-6}$ N, 120 dB más abajo, así que
+un nivel de fuerza que pase entre esta página y
+[Potencia acústica estructural de equipos](/phonometry/es/buildings/design/structure-borne-power/)
+sin convertir está equivocado exactamente en eso.
Ambas características exigen una forma de onda de **pico único** de
$20 \pm 2$ ms (JIS A 1418-2:2019 A.2 b)). Los valores por bandas de octava se
imprimen de forma idéntica en la Tabla A.1 de ISO 16283-2:2020, la Tabla F.1 de
@@ -90,8 +96,8 @@ de neumático solo aparece en la Tabla A.1 de JIS A 1418-2:2019.
| 250 | 17,0 ± 2,0 | 11,5 ± 2,0 |
| 500 | 12,5 ± 2,0 | 5,5 ± 2,0 |
-La máquina de neumático inyecta 8 dB más de energía en las dos octavas más
-bajas y 7 dB menos en la más alta, y por eso las dos fuentes no son
+La máquina de neumático inyecta de 8 a 9 dB más de energía en las dos octavas
+más bajas (8 dB a 31,5 Hz, 9 dB a 63 Hz) y 7 dB menos en la más alta, y por eso las dos fuentes no son
intercambiables y un forjado puede cumplir con una y fallar con la otra.
```python
@@ -239,7 +245,8 @@ Como la ponderación A es 23 dB más pronunciada a 63 Hz que a 500 Hz, la
valoración de una fuente pesada la domina la banda que sobreviva a esa
pendiente. Para el espectro de la Tabla D.4 las cuatro contribuciones
ponderadas A son 39,1; 48,3; 49,3 y 52,6 dB, así que la banda de 500 Hz es la
-que más pesa aunque la de 63 Hz sea la más alta por 10 dB.
+que más pesa aunque la de 63 Hz sea la banda medida más alta, 9,5 dB por
+encima de ella.
## Qué cubre esta guía
diff --git a/site/src/content/docs/es/buildings/insulation/index.md b/site/src/content/docs/es/buildings/insulation/index.md
index fd3556025..1696c29f1 100644
--- a/site/src/content/docs/es/buildings/insulation/index.md
+++ b/site/src/content/docs/es/buildings/insulation/index.md
@@ -10,8 +10,10 @@ suprimidos aíslan su transmisión directa. Esos datos de laboratorio alimentan
una **predicción** de cómo se comportará el edificio completo, caminos de
flancos incluidos. El edificio terminado se **verifica en campo**. En cada
etapa el espectro por bandas se reduce al **número único** que citan las
-regulaciones, y esa reducción es un motor compartido y no un paso propio de
-ningún método.
+regulaciones, y en casi todos los casos esa reducción es un único motor de
+curva de referencia compartido y no un paso propio de ningún método. La
+excepción es la valoración de impactos pesados del anexo D de ISO 717-2, que no
+desplaza curva alguna: suma en energía niveles de banda ponderados A.
**Laboratorio.**
[Medición del aislamiento en laboratorio](/phonometry/es/buildings/insulation/insulation-lab/)
@@ -35,6 +37,12 @@ las dos mediciones de material que consume el diseño de un suelo.
[Medición del aislamiento en campo (ISO 16283)](/phonometry/es/buildings/insulation/insulation-field/)
cubre la medición aérea y de impacto con método de ingeniería en el edificio,
su informe del apartado 14 y la incertidumbre de ISO 12999-1 que lo cualifica.
+La misma norma especifica dos fuentes de impacto más, una pelota de caucho y
+una máquina de neumático, para los golpes lentos de baja frecuencia sobre los
+que una máquina de impactos no dice nada;
+[Fuentes de impacto pesadas y blandas (ISO 16283-2)](/phonometry/es/buildings/insulation/heavy-impact-sources/)
+cubre su especificación, la estandarización del nivel máximo con ponderación
+Fast y la valoración del anexo D.
Cuando la pregunta no merece ese esfuerzo,
[Método de control del aislamiento (ISO 10052)](/phonometry/es/buildings/insulation/insulation-survey/)
cambia exactitud por rapidez con bandas de octava y un índice de reverberación.
diff --git a/site/src/content/docs/es/buildings/insulation/insulation-field.mdx b/site/src/content/docs/es/buildings/insulation/insulation-field.mdx
index ee27b6af8..a258de105 100644
--- a/site/src/content/docs/es/buildings/insulation/insulation-field.mdx
+++ b/site/src/content/docs/es/buildings/insulation/insulation-field.mdx
@@ -25,11 +25,11 @@ references:
note: "El método aéreo de campo que implementa esta página: las diferencias de nivel y normalizaciones."
- type: standard
organization: "International Organization for Standardization"
- year: 2015
+ year: 2020
title: "Acoustics — Field measurement of sound insulation in buildings and of building elements — Part 2: Impact sound insulation"
- designation: "ISO 16283-2:2015"
- url: "https://www.iso.org/standard/59747.html"
- note: "El método de impactos de campo: los niveles de impactos estandarizado y normalizado."
+ designation: "ISO 16283-2:2020"
+ url: "https://www.iso.org/standard/74162.html"
+ note: "El método de impactos de campo: los niveles de impactos estandarizado y normalizado, el informe de ensayo del apartado 14 y los formularios de resultados de su Anexo C. La primera edición de 2015 es idéntica en las normalizaciones que se usan aquí."
- type: standard
organization: "International Organization for Standardization"
year: 2020
@@ -77,10 +77,16 @@ y la predicción del comportamiento in situ en
## ¿Cómo calculo DnT y R' a partir de una medición en campo con Python?
Promedia en energía los niveles de los recintos emisor y receptor por banda de
-tercio de octava y pásalos, junto con el tiempo de reverberación del recinto
+tercio de octava sobre las posiciones de micrófono de una misma posición de
+altavoz, corrige el recinto receptor por ruido de fondo y pásalos, junto con el
+tiempo de reverberación del recinto
receptor, a `building.airborne_insulation(l1, l2, t2, area=S, volume=V)`. El
resultado lleva la diferencia de niveles bruta `d`, la estandarizada `dnt` y,
-cuando se dan `area` y `volume`, la aparente `r_prime`. Las mediciones de
+cuando se dan `area` y `volume`, la aparente `r_prime`. Si se ha movido un único
+altavoz entre posiciones, repite eso para cada posición y combina los
+*resultados* con la Fórmula (6), no los niveles; véase
+[La medición](#la-medicion-iso-16283-1).
+Las mediciones de
impactos pasan por `building.impact_insulation(li, t2, volume=V)`, y cualquiera
de los dos espectros se valora con `building.weighted_rating` /
`weighted_impact_rating`.
@@ -152,12 +158,118 @@ función a `weighted_rating`, de modo que cada banda quede alineada índice a
| `area` | float, opcional | m² | > 0, con `volume` | Superficie del cerramiento $S$ (habilita $R'$) |
| `volume` | float, opcional | m³ | > 0, con `area` | Volumen del recinto receptor $V$ |
| `t0` | float | s | por defecto `0.5` | Tiempo de reverberación de referencia $T_0$ |
+
`airborne_insulation()` devuelve un `AirborneInsulationResult` (`d`, `dnt`,
`r_prime` o `None`). El motor de curva de referencia que convierte cualquiera
de esos espectros en $R_w$, $R'_w$ o $D_{nT,w}$, sus términos de adaptación
espectral y sus variantes de rango ampliado están en
[Índices globales de aislamiento (ISO 717)](/phonometry/es/buildings/insulation/insulation-ratings/).
+
+
+## La medición (apartados 7 y 9 de ISO 16283-1)
+
+Las funciones consumen niveles por banda; la norma dice de dónde salen esos
+niveles, y equivocarse ahí cambia el resultado más que cualquiera de las
+operaciones anteriores.
+
+**La fuente (apartados 7.1 y 7.2).** El sonido se genera con altavoces
+funcionando simultáneamente en dos posiciones como mínimo, o con un único
+altavoz desplazado a dos posiciones como mínimo. Si son varios altavoces han de
+ser del mismo tipo, excitados al mismo nivel con señales similares pero no
+correlacionadas, y cada uno debe cumplir el requisito de directividad del
+Anexo A. La señal es estacionaria y de espectro continuo, y el nivel promediado
+en energía del recinto emisor no debe variar más de 8 dB entre bandas de tercio
+de octava contiguas, al menos por encima de 100 Hz — conforma el espectro
+(normalmente hace falta un ecualizador gráfico) o recurre a mediciones
+sucesivas en banda limitada. Los altavoces se sitúan a 0,5 m como mínimo de
+cualquier paramento, preferiblemente a 1,0 m como mínimo del elemento
+separador, medido hasta el centro del altavoz más próximo; posiciones distintas
+no deben quedar en planos paralelos a un paramento separados menos de 0,7 m,
+deben distar entre sí 0,7 m como mínimo y al menos dos de ellas 1,4 m como
+mínimo. Cuando el elemento de ensayo es el forjado y el altavoz está en el
+recinto superior, su base queda a 1,0 m como mínimo sobre el suelo.
+
+**Los micrófonos (apartado 7.3).** Un mínimo de **cinco** posiciones por
+recinto — y, con un único altavoz desplazado entre posiciones, cinco por
+recinto *y por posición de altavoz*. No puede haber dos posiciones en el mismo
+plano respecto a los paramentos del recinto, y el conjunto no debe formar una
+retícula regular.
+
+
+
+### Corrección por ruido de fondo (apartado 9.2)
+
+Mide otra vez el recinto receptor con la fuente apagada, en las mismas
+posiciones y con el mismo promediado, y compara banda a banda con el nivel
+combinado de señal más fondo $L_{sb}$:
+
+- margen $\ge 10$ dB: usa $L_{sb}$ sin tocarlo;
+- $6 < \text{margen} < 10$ dB: resta el fondo en energía,
+ $L = 10\log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ (Fórmula 14), con los dos
+ niveles reducidos antes a un decimal;
+- margen $\le 6$ dB: aplica la corrección fija de 1,3 dB y señala la banda en
+ el informe como que está en el límite de la medición.
+
+```python
+import numpy as np
+
+l2_sb = np.array([44.0, 41.0, 39.5, 38.0]) # recinto receptor, fuente encendida
+l2_bg = np.array([30.0, 33.0, 31.0, 34.0]) # recinto receptor, fuente apagada
+margin = l2_sb - l2_bg # 14.0 8.0 8.5 4.0 dB
+
+formula_14 = 10 * np.log10(10 ** (l2_sb / 10) - 10 ** (l2_bg / 10))
+l2_corr = np.where(margin >= 10.0, l2_sb,
+ np.where(margin > 6.0, formula_14, l2_sb - 1.3))
+print(np.round(l2_corr, 2)) # [44. 40.25 38.84 36.7 ] <- última banda señalada
+```
+
+`building.background_correction` existe, pero implementa la regla de
+**laboratorio de ISO 10140-4** que se usa en
+[Medición del aislamiento en laboratorio](/phonometry/es/buildings/insulation/insulation-lab/),
+cuyo umbral superior es de 15 dB y no de 10 dB. Aplicada a datos de campo resta
+energía en la franja de margen de 10-15 dB en la que ISO 16283-1 no pide nada
+— hasta 0,458 dB con un margen de 10 dB — y, como actúa sobre el recinto
+receptor, eso acaba siendo aislamiento declarado de más, banda a banda, en $D$.
+Para niveles de campo usa la expresión de tres regímenes de arriba.
+
+### Promediado sobre posiciones de altavoz (Fórmula 6)
+
+Con **varios altavoces funcionando simultáneamente** (apartado 7.3.3) hay una
+sola medición: promedia en energía las posiciones de cada recinto, corrige por
+ruido de fondo y forma $D_{nT}$ o $R'$ una sola vez. Con un **único altavoz
+desplazado entre posiciones** (apartado 7.3.4) la norma *no* promedia los
+niveles entre posiciones de altavoz. Forma el resultado para cada posición y
+promedia los *resultados* como factores de transmisión,
+
+$$
+D_{nT} = -10\log_{10}\left[\frac{1}{m}\sum_{j=1}^{m} 10^{-D_{nT,j}/10}\right],
+$$
+
+que es lo que da más peso a la peor posición. Las dos vías no dan el mismo
+número:
+
+```python
+import numpy as np
+# `building` es el import del bloque de aislamiento a ruido aéreo de arriba.
+
+t2 = np.full(16, 0.5)
+l1a, l2a = np.full(16, 80.0), np.full(16, 40.0) # posición de altavoz 1
+l1b, l2b = np.full(16, 83.0), np.full(16, 37.0) # posición de altavoz 2
+
+# Apartado 7.3.4: un resultado por posición de altavoz, combinados con la Fórmula (6).
+a = building.airborne_insulation(l1a, l2a, t2, area=10.0, volume=50.0)
+b = building.airborne_insulation(l1b, l2b, t2, area=10.0, volume=50.0)
+dnt = -10 * np.log10(np.mean(10.0 ** (-np.vstack([a.dnt, b.dnt]) / 10.0), axis=0))
+print(round(float(dnt[0]), 1), building.weighted_rating(dnt).rating) # 42.0 42
+
+# Promediar antes los niveles: otro número, más halagüeño.
+l1m = building.energy_average_level(np.vstack([l1a, l1b]), axis=0)
+l2m = building.energy_average_level(np.vstack([l2a, l2b]), axis=0)
+naive = building.airborne_insulation(l1m, l2m, t2, area=10.0, volume=50.0)
+print(round(float(naive.dnt[0]), 1), building.weighted_rating(naive.dnt).rating) # 43.0 43
+```
+
## Aislamiento a ruido de impactos en campo (ISO 16283-2)
El ruido de pisadas se califica al revés. En lugar de cuánto *bloquea* un
@@ -383,7 +495,10 @@ from phonometry import building
# Situación B (mismo edificio, equipos distintos) -> la desviación típica in situ.
print(building.single_number_uncertainty("r_w", "B")) # 0.9 dB (Tabla 3)
u = building.band_uncertainty("airborne", "B") # u por banda (Tabla 2)
-print(len(u.frequencies), u.uncertainties[10]) # 21 1.1 (la banda de 500 Hz)
+# Busca la banda; nunca indexes por posición. La tabla de impactos no tiene
+# banda de 500 Hz siquiera, así que ahí [10] sería 630 Hz sin avisar.
+i = list(u.frequencies).index(500.0)
+print(len(u.frequencies), u.uncertainties[i]) # 21 1.1 (la banda de 500 Hz)
u.plot() # el espectro por banda u(f) de la Tabla 2 (requiere matplotlib)
# Informa R'w = 52 dB con un intervalo bilateral al 95 % (k = 1.96, Tabla 8):
@@ -470,7 +585,7 @@ receptor, es
**Cubierto.** La ISO 16283-1:2014 (aislamiento a ruido aéreo de campo: la diferencia
de niveles, la $D_{nT}$ estandarizada y el $R'$ aparente de los apartados 3.12
-a 3.15 y el promediado de posiciones del apartado 7.8) y la ISO 16283-2:2015
+a 3.15 y el promediado de posiciones del apartado 7.8) y la ISO 16283-2:2020
(aislamiento a ruido de impactos de campo, las mismas normalizaciones con el
signo invertido) mediante `building.energy_average_level`,
`building.airborne_insulation` y `building.impact_insulation`, cada una con su
@@ -483,8 +598,13 @@ globales citados aquí reutilizan los motores verificados de
ISO 717-1/ISO 717-2.
**No cubierto.** Todas las funciones de campo de aquí toman niveles que el
-usuario ya ha corregido por ruido de fondo (apartado 9.2 de la ISO 16283-1);
-la medición y corrección del ruido de fondo en sí no está implementada. Los
+usuario ya ha corregido por ruido de fondo (apartado 9.2 de la ISO 16283-1). La
+*medición* del nivel de fondo — fuente apagada, mismas posiciones, mismo
+promediado — es cosa del operador, y aquí nada verifica que se haya cumplido el
+suelo de 6 dB; la corrección en sí son tres líneas de NumPy, escritas en
+[Corrección por ruido de fondo](#correccion-por-ruido-de-fondo)
+más arriba. (`building.background_correction` es la variante de *laboratorio*
+de ISO 10140-4 y no coincide con los umbrales de campo.) Los
propios requisitos de posición y procedimiento de la ISO 16283-1/-2 (el número
mínimo de posiciones de fuente y micrófono, los procedimientos de baja
frecuencia con altavoz móvil o barrido de micrófono) no se comprueban: el
diff --git a/site/src/content/docs/es/buildings/insulation/insulation-intensity.mdx b/site/src/content/docs/es/buildings/insulation/insulation-intensity.mdx
index 9f14299b2..206c69698 100644
--- a/site/src/content/docs/es/buildings/insulation/insulation-intensity.mdx
+++ b/site/src/content/docs/es/buildings/insulation/insulation-intensity.mdx
@@ -65,12 +65,22 @@ $$
donde los $6$ dB son el desfase de campo difuso entre el nivel de presión acústica
y el nivel de intensidad incidente. La misma fórmula da el índice aparente
-$R'_I$ en campo (ISO 15186-2). Como el método por intensidad *subestima*
-ligeramente la potencia radiada a un recinto receptor real, un **índice
-modificado** $R_{I,M} = R_I + K_c$ reproduce el resultado por presión de la
-ISO 10140-2; el término de adaptación $K_c$ (Anexo B) es
+$R'_I$ en campo (ISO 15186-2). El barrido de intensidad mide directamente la
+potencia transmitida. El método por presión en cámara reverberante no: infiere
+la potencia a partir del nivel del recinto receptor y por eso la *subestima*,
+lo que hace que el $R$ de ISO 10140-2 salga ligeramente alto. El **índice
+modificado** $R_{I,M} = R_I + K_c$ vuelve a añadir ese mismo sesgo al resultado
+por intensidad, de modo que una medición por intensidad pueda contrastarse con
+datos del método por presión (ISO 15186-1, cláusula 3.10 NOTA 1). Informa
+$R_I$ cuando lo que se busca es la potencia transmitida real; informa
+$R_{I,M}$ cuando lo que se busca es la comparabilidad con un resultado de
+ISO 10140-2. Revisiones anteriores de esta guía achacaban el sesgo al propio
+método por intensidad, lo que habría exigido restar $K_c$ en lugar de sumarlo.
+El término de adaptación $K_c$ (Anexo B) es
$10 \log_{10}(1 + S_{b2}\lambda/8V_2)$ para una sala bien definida, o el
-independiente de la sala $10 \log_{10}(1 + 61{,}4/f)$. Para elementos pequeños, la
+independiente de la sala $10 \log_{10}(1 + 61{,}4/f)$. La primera forma es el
+término de energía de contorno de Waterhouse, lo que deja leer la segunda como
+ese mismo término evaluado a un $S_{b2}/V_2$ fijo. Para elementos pequeños, la
**diferencia de niveles normalizada por elemento** sustituye $10\log_{10}(S_m/S)$ por
$10\log_{10}(S_m/A_0) + 10\log_{10} N$ ($A_0 = 10\ \text{m}^2$, $N$ unidades de elemento).
diff --git a/site/src/content/docs/es/buildings/insulation/insulation-survey.mdx b/site/src/content/docs/es/buildings/insulation/insulation-survey.mdx
index b2faf3d2f..120bee696 100644
--- a/site/src/content/docs/es/buildings/insulation/insulation-survey.mdx
+++ b/site/src/content/docs/es/buildings/insulation/insulation-survey.mdx
@@ -35,7 +35,7 @@ los motores de número único tras los índices del método de control en
## Bandas de octava y el índice de reverberación
-Los métodos de ingeniería anteriores compran precisión con esfuerzo:
+Los [métodos de ingeniería](/phonometry/es/buildings/insulation/insulation-field/) compran precisión con esfuerzo:
micrófonos barridos, tiempos de reverberación por banda, corrección de ruido de
fondo cuidadosa. Para una comprobación rápida en una vivienda, ISO 10052 define
un **método de control (survey)**: bandas de octava, un sonómetro de mano y una
@@ -52,13 +52,42 @@ reverberación son idénticas en la armonizada EN ISO 10052:2004+A1:2010.
El índice de reverberación se **mide** (pasa el tiempo de reverberación a
`reverberation_index(T)`) o, en un control, se **estima** a partir del tipo de
-sala y el volumen con `estimate_reverberation_index(V, room)` (Tabla 4:
-amueblada `"kitchen"` / `"bathroom"` / `"furnished"`, o las clases de
-construcción sin amueblar `"a"`–`"h"` y las mixtas `"a+e"`…`"d+h"`). Una cuarta
+sala y el volumen con `estimate_reverberation_index(V, room)`: amueblada
+`"kitchen"` / `"bathroom"` / `"furnished"`, o las clases de construcción sin
+amueblar `"a"`–`"h"` y las mixtas `"a+e"`…`"d+h"`. La cláusula 6.5 separa eso
+en dos: la **Tabla 3** clasifica el recinto y le asigna su letra, y la
+**Tabla 4** convierte la letra y el volumen en el índice. Una cuarta
magnitud propia de este método es el **ruido de equipos de servicio**
$L_{XY}$: la
media energética de tres posiciones ponderadas A o C.
+Las letras no son arbitrarias: la Tabla 3 es una malla de 2 × 2 × 2 sobre el
+peso de las paredes y el techo, la dureza del revestimiento del suelo y el
+peso de la construcción del forjado.
+
+| Paredes y techo | Revestimiento blando, forjado ligero | Revestimiento blando, forjado pesado | Revestimiento duro, forjado ligero | Revestimiento duro, forjado pesado |
+| :--- | :---: | :---: | :---: | :---: |
+| Ligeras | `a` | `b` | `c` | `d` |
+| Pesadas | `e` | `f` | `g` | `h` |
+
+Una **pared ligera** es placa de yeso o entramado de madera, y una pared
+pesada con trasdosado de placa de yeso cuenta como ligera; una **pared
+pesada** es fábrica o bloque sin trasdosar. Un **forjado ligero** es
+entablado o tablero sobre viguetas de madera, y un **forjado pesado** una
+losa de hormigón. El **revestimiento** es moqueta (blando) frente a baldosa o
+tarima (duro). Cuando el recinto mezcla dos construcciones sobre áreas
+aproximadamente iguales, promedia las dos letras: eso son las clases mixtas
+`"a+e"`…`"d+h"`; cuando una construcción domina claramente en área, usa su
+letra sola. Fíjate en que el revestimiento y la construcción del forjado son
+dos ejes distintos, así que «suelo duro» por sí solo no elige una clase.
+
+La Tabla 4 procede de un estudio estadístico de viviendas europeas
+construidas entre 1960 y 1980 (NOTA 1): la desviación típica de los índices
+tabulados ronda 1 dB, y la tabla vale para $T_0 = 0{,}5\ \text{s}$ y recintos
+de hasta 150 m³. Un cambio en los métodos constructivos o en los hábitos de
+habitación puede desplazarla sistemáticamente, así que mide $T$ cuando el
+resultado tenga que sostenerse.
+
```python
import numpy as np
from phonometry import building
@@ -72,10 +101,10 @@ print(np.round(res.d_nt, 1)) # [34.5 39.8 45. 50.5 54. ] DnT = D + k
print(res.rating.rating, res.rating.c) # 49 -1 -> DnT,w (C)
print(res.r_prime_rating.rating) # 48 -> R'w
-# ¿Sin T medido? Estima k con la Tabla 4 (paredes pesadas, suelo duro,
-# 35-60 m³ -> clase "g").
-k_est = building.estimate_reverberation_index(50.0, "g")
-print(k_est) # [4.5 5. 5.5 5.5 5.5]
+# ¿Sin T medido? Clasifica con la Tabla 3 y luego lee la Tabla 4: paredes
+# pesadas de fábrica, losa de hormigón, suelo de baldosa, 35-60 m³ -> clase "h".
+k_est = building.estimate_reverberation_index(50.0, "h")
+print(k_est) # [5. 5.5 6. 5. 5.5]
# Ruido de equipos de servicio: media energética de tres posiciones (dB(A)).
se = building.survey_service_equipment_level([35.0, 30.0, 32.0], 3.0, volume=50.0)
@@ -121,6 +150,22 @@ plt.show()
+### Ruido de fondo: un umbral que cumplir, no una corrección que aplicar
+
+A diferencia de los métodos de ingeniería, el método de control nunca corrige
+por ruido de fondo (cláusula 6.2.1). Fija en su lugar un umbral de relación
+señal/ruido: ajusta la fuente para que el nivel en el recinto receptor supere
+al fondo en al menos 6 dB en todas las bandas, comprobado encendiendo y
+apagando la fuente antes de la tanda. Donde el margen siga por debajo de
+6 dB, registra el nivel sin corregir y haz constar en el informe que la
+diferencia de niveles queda infravalorada (o, para equipos de servicio, que el
+nivel queda sobrevalorado) en una cantidad desconocida. Por eso no aparece
+ninguna llamada de corrección en toda esta página:
+`building.background_correction` implementa la regla de laboratorio de
+ISO 10140-4 y no debe aplicarse a datos de control. Revisiones anteriores de
+esta guía decían lo contrario, y presentaban la corrección como tarea de quien
+llama; un control corregido así no es conforme y sobrestima el aislamiento.
+
### Parámetros de `survey_airborne_insulation()` y afines
| Parámetro | Tipo | Unidades | Rango / def. | Notas |
@@ -131,7 +176,7 @@ plt.show()
| `volume` | float | m³ | > 0 | Volumen receptor $V$ (para $D_n$ / $L'_n$ / $R'$ / normalizadas) |
| `area` | float | m² | > 0 | Área de partición común $S$ (aéreo $R'$; regla $V/7{,}5$) |
| `measurements` | array | dB | exactamente 3 | Posiciones de equipo de servicio (`survey_service_equipment_level`) |
-| `room` | str | — | `"kitchen"`/`"bathroom"`/`"furnished"`/`"a"`–`"h"`/`"a+e"`… | Clase de sala para `estimate_reverberation_index` (Tabla 4) |
+| `room` | str | — | `"kitchen"`/`"bathroom"`/`"furnished"`/`"a"`–`"h"`/`"a+e"`… | Clase de sala para `estimate_reverberation_index` (Tabla 3; el índice en sí es la Tabla 4) |
`survey_airborne_insulation()` devuelve un `SurveyAirborneResult` (`d`, `d_nt`,
`d_n`, `r_prime`, `rating`, `r_prime_rating`); `survey_impact_insulation()` un
@@ -243,7 +288,7 @@ plt.show()
**Cubierto.** El método de control de ISO 10052:2021: el índice de
reverberación $k = 10\log_{10}(T/T_0)$ medido con
`building.reverberation_index` o estimado desde las clases de recinto de la
-Tabla 4 con `building.estimate_reverberation_index`; las magnitudes de
+Tabla 3 con `building.estimate_reverberation_index`; las magnitudes de
control aéreas, de impacto y de fachada ($D_{nT}$, $D_n$, $R'$ con la regla
$V/7,5$, $L'_{nT}$, $L'_n$, $D_{2m,nT}$) mediante
`building.survey_airborne_insulation`, `building.survey_impact_insulation`
@@ -256,8 +301,10 @@ sobre espectros de 5 octavas o 16 tercios; y las fichas del método con
**No cubierto.** El propio procedimiento de control (dónde sostener el
sonómetro, las alturas de medición fijas, la colocación de la máquina de
impactos del método) no se comprueba: las funciones consumen niveles por
-banda vengan de donde vengan. La corrección de ruido de fondo es tarea de
-quien llama, como en los métodos de ingeniería. La declaración de exactitud
+banda vengan de donde vengan. Nada verifica que se cumpliese el umbral de
+6 dB de señal a fondo de la cláusula 6.2.1, y no se aplica corrección alguna
+cuando no se cumplió: esa es la regla del propio método, no una omisión. La
+declaración de exactitud
del método frente a ISO 16283 se cita de la norma, no se modela; cuando
sube lo que hay en juego, pasa a
[Medición del aislamiento en campo (ISO 16283)](/phonometry/es/buildings/insulation/insulation-field/).
diff --git a/site/src/content/docs/es/buildings/insulation/spanish-building-code.mdx b/site/src/content/docs/es/buildings/insulation/spanish-building-code.mdx
index 351d7a42c..5dde34cbe 100644
--- a/site/src/content/docs/es/buildings/insulation/spanish-building-code.mdx
+++ b/site/src/content/docs/es/buildings/insulation/spanish-building-code.mdx
@@ -231,6 +231,7 @@ protegidos, el área de absorción acústica equivalente debe ser al menos
0,2 m² por cada metro cúbico de volumen.
```python
+import numpy as np
from phonometry import building
facade = building.db_hr_facade_requirement(65.0, "residential", "bedrooms")
@@ -244,10 +245,31 @@ building.db_hr_party_wall_requirement().limit # 40 dBA p
building.db_hr_party_wall_requirement("DnT,A").limit # 50 dBA las dos juntas
building.db_hr_reverberation_requirement("classroom").limit # 0,7 s
-check = building.assess_db_hr([(33.0, facade), (51.44, airborne[0])])
+# La exigencia entre recintos está declarada en DnT,A, así que el R' de la
+# medianería del informe de campo no se puede contrastar con ella tal cual. Hay
+# que rereferenciarlo antes: un recinto receptor de V = 50 m3 con T = 0,5 s
+# detrás de una partición de S = 12 m2 tiene A = 0,16 V / T = 16 m2, y
+# DnT = R' + 10 lg(A/S) + 10 lg(T/T0).
+d_nt = np.asarray(r_prime) + 10 * np.log10(16.0 / 12.0) + 10 * np.log10(0.5 / 0.5)
+building.dnt_a(d_nt).intermediate # 52,7 dBA (el R'A era 51,4 dBA)
+
+check = building.assess_db_hr([(33.0, facade), (52.7, airborne[0])])
check.complies # True
```
+La magnitud tiene que coincidir con la exigencia. El DB HR declara el límite
+entre recintos en $D_{nT,A}$, y $R'$ y $D_{nT}$ normalizan la misma diferencia
+de niveles por cosas distintas — $R' = D + 10\log_{10}(S/A)$ por el área de la
+partición y la absorción del recinto receptor, $D_{nT} = D + 10\log_{10}(T/T_0)$
+por el tiempo de reverberación —, así que un $R'_A$ de un informe de campo hay
+que convertirlo a través de la $T$ del recinto y del área de la partición antes
+de que signifique algo frente a los 50 dBA. Solo la exigencia de la
+*tabiquería* ($R_A \ge 33$ dBA) está declarada en la familia de $R_A$.
+Revisiones anteriores de esta página contrastaban el $R'_A = 51,4$ dBA de la
+medianería directamente con la exigencia en $D_{nT,A}$: aquí el veredicto salía
+igual por casualidad, pero la comparación era entre dos magnitudes distintas y
+nada garantiza esa coincidencia en general.
+
`check_db_hr_requirement()` redondea el valor alcanzado como pide el DB HR
antes de compararlo (a entero en las magnitudes en dB, a un decimal en el
tiempo de reverberación) y devuelve el margen; `assess_db_hr()` hace lo mismo
diff --git a/site/src/content/docs/es/buildings/rooms/enclosed-space-absorption.mdx b/site/src/content/docs/es/buildings/rooms/enclosed-space-absorption.mdx
index 461e65678..8e447a5eb 100644
--- a/site/src/content/docs/es/buildings/rooms/enclosed-space-absorption.mdx
+++ b/site/src/content/docs/es/buildings/rooms/enclosed-space-absorption.mdx
@@ -115,9 +115,14 @@ result = room.enclosed_space_reverberation(
)
print(result.reverberation_time.round(2))
# [2.13 1.03 0.62 0.48 0.43 0.42 0.4 ]
-result.plot() # la figura de abajo: A y T por banda de octava
+result.plot() # A y T por banda de octava, solo para esta sala
```
+La figura de abajo ejecuta esa llamada dos veces, una con la placa acústica de
+arriba y otra dejando el techo como yeso desnudo, para que el tratamiento se
+lea como una diferencia. El `[2.13 1.03 …]` impreso arriba es su curva de
+«techo acústico»; `result.plot()` dibuja esa curva sola.
+
@@ -139,6 +144,16 @@ plt.show()
+*La misma oficina de 60 m³ con dos techos. Cambiar 20 m² de yeso por placa
+acústica multiplica el área de absorción equivalente por 4 o 5 por encima de
+500 Hz (de 4,0 m² a 20,2 m² a 1 kHz) y baja el tiempo de reverberación ahí de
+2,4 s a 0,48 s. La banda de 125 Hz, donde la placa es más floja, es la que
+menos mejora: de 1,9 m² a 4,5 m², y de 5,04 s solo hasta 2,13 s. Una placa
+porosa de 20 mm es una fracción pequeña de una longitud de onda de 2,7 m y
+absorbe por fricción solo donde la velocidad de partícula es alta, así que el
+control a baja frecuencia necesita espesor, una cámara de aire o un absorbente
+resonante.*
+
El `ReverberationResult` lleva el área de absorción y el tiempo de reverberación
por banda, el volumen y la fracción de objetos, y su `.plot()` dibuja el espectro
del tiempo de reverberación. Es la contraparte de predicción del tiempo de
diff --git a/site/src/content/docs/es/buildings/rooms/open-plan-acoustics.mdx b/site/src/content/docs/es/buildings/rooms/open-plan-acoustics.mdx
index 0ff3cbda8..50e07883c 100644
--- a/site/src/content/docs/es/buildings/rooms/open-plan-acoustics.mdx
+++ b/site/src/content/docs/es/buildings/rooms/open-plan-acoustics.mdx
@@ -25,7 +25,8 @@ import ReportPreview from '../../../../../components/ReportPreview.astro';
Una oficina diáfana no es un problema de reverberación; es un problema de
privacidad, y una sala que luce bien en los parámetros de sala cerrada puede
suspenderlo igualmente. ISO 3382-3 caracteriza por ello la oficina con
-cuatro números únicos medidos a lo largo de una línea de puestos de trabajo,
+cuatro números únicos — $r_D$, $D_{2,S}$, $L_{p,A,S,4m}$ y el ruido de fondo
+medio $L_{p,A,B}$ — medidos a lo largo de una línea de puestos de trabajo,
alejándose de un hablante. Esta guía cubre esa cadena de medición: las
magnitudes, la línea de medición a escala y la ficha acreditada. Las
respuestas al impulso y los niveles que la sustentan se adquieren como en
@@ -41,7 +42,12 @@ La acústica de oficinas diáfanas trata de la **privacidad del habla**: con
qué rapidez el habla de un hablante se desvanece hasta la ininteligibilidad a
medida que uno se aleja. Los niveles y el STI se miden a lo largo de una fila
de puestos de trabajo (al menos 4 posiciones, preferiblemente 6–10), y cuatro
-magnitudes de un solo número resumen la sala. La **tasa de decaimiento
+magnitudes de un solo número resumen la sala: la distancia de distracción
+$r_D$, la tasa de decaimiento espacial $D_{2,S}$, el nivel de habla a 4 m
+$L_{p,A,S,4m}$ y el ruido de fondo medio ponderado A $L_{p,A,B}$
+(apartado 6.4). La distancia de privacidad $r_P$ y el STI en el puesto más
+cercano son añadidos opcionales; `open_plan_metrics` devuelve $D_{2,S}$,
+$L_{p,A,S,4m}$, $r_D$ y $r_P$. La **tasa de decaimiento
espacial** del habla ponderada A es la pendiente del nivel frente a
$\log_{10}(r/r_0)$, escalada a una cifra por duplicación usando solo las posiciones
de 2–16 m,
@@ -56,7 +62,21 @@ distracción** $r_D$ (STI = 0,50) y la **distancia de privacidad** $r_P$
Las buenas oficinas empujan $r_D$ por debajo de ~5 m; las malas dejan el habla
molesta más allá de 10 m.
-
+$L_{p,A,B}$ es la cuarta magnitud exigida y no es un adorno: el ruido de fondo
+se mide en bandas de octava en todas las posiciones con la misma integración de
+$\ge 10$ s, se pondera A y se promedia sobre la línea, y esa media es el
+enmascarador frente al que se calcula el STI de cada posición. Promediarlo
+espacialmente es lo que deja $r_D$ y $r_P$ sin ambigüedad. Es también la razón
+de que el diseño de una oficina diáfana tenga dos palancas y no una
+— **atenuación** (mamparas, techo absorbente, distribución: suben $D_{2,S}$ y
+bajan $L_{p,A,S,4m}$) y **enmascaramiento** (subir el fondo para que el habla
+pierda antes la inteligibilidad) — y de que la oficina se mida amueblada,
+desocupada y con las instalaciones en marcha. Una oficina medida con la
+ventilación o el sistema de enmascaramiento bajados devuelve un STI mayor en
+todas las posiciones y desplaza las dos distancias metros hacia fuera sin que
+nada haya cambiado en la sala.
+
+
```python
import numpy as np
@@ -166,12 +186,89 @@ plt.show()
+### Del ruido rosa medido a $L_{p,A,S,n}$
+
+Un altavoz no es un hablante, así que ISO 3382-3 no usa nunca su nivel
+directamente. El apartado 6.2 mide la *sala* con ruido rosa y después vuelve a
+vestir el resultado con el espectro de una voz real. De cada posición no se
+guarda su nivel absoluto, sino la atenuación banda a banda respecto a la fuente
+a 1 m (Ec. 1-2), de modo que el nivel de salida del altavoz se cancela y solo
+tiene que quedar lo bastante por encima del fondo:
+
+$$
+L_{p,Ls,1m,i} \approx L_{W,Ls,i} - 11\ \text{dB},
+\qquad
+D_{n,i} = L_{p,Ls,1m,i} - L_{p,Ls,n,i} .
+$$
+
+Esa atenuación se aplica después al espectro de habla de esfuerzo normal
+(Ec. 3), se pondera A y se suma en energía sobre las siete bandas de octava
+(Ec. 4):
+
+$$
+L_{p,S,n,i} = L_{p,S,1m,i} - D_{n,i},
+\qquad
+L_{p,A,S,n} = 10\log_{10}\sum_i 10^{(L_{p,S,n,i} + A_i)/10} .
+$$
+
+La Tabla 1 aporta el espectro omnidireccional de esfuerzo normal y las
+ponderaciones A:
+
+| Banda $i$ | $f$ [Hz] | $L_{p,S,1m,i}$ [dB] | $A_i$ [dB] |
+| ---: | ---: | ---: | ---: |
+| 1 | 125 | 49,9 | −16,1 |
+| 2 | 250 | 54,3 | −8,6 |
+| 3 | 500 | 58,0 | −3,2 |
+| 4 | 1000 | 52,0 | 0,0 |
+| 5 | 2000 | 44,8 | +1,2 |
+| 6 | 4000 | 38,8 | +1,0 |
+| 7 | 8000 | 33,5 | −1,1 |
+
+cuyo total ponderado A es 57,4 dB: una voz que habla con normalidad a 1 m.
+
+**La lectura ponderada A del ruido rosa en el sonómetro no es la entrada que
+espera `open_plan_metrics`.** Meterla da un nivel absoluto que es el del
+altavoz, no el de un hablante, así que $L_{p,A,S,4m}$ sale directamente mal y
+$D_{2,S}$ queda sesgada por la diferencia espectral entre el ruido rosa y el
+habla. Ejecuta antes la cadena de cuatro pasos:
+
+```python
+import numpy as np
+# `room` es el import del bloque de open_plan_metrics de arriba.
+
+# Tabla 1 de ISO 3382-3: habla unisex de esfuerzo normal a 1 m, omnidireccional,
+# y la ponderación A, bandas de octava de 125 Hz a 8 kHz.
+speech_1m = np.array([49.9, 54.3, 58.0, 52.0, 44.8, 38.8, 33.5])
+a_weight = np.array([-16.1, -8.6, -3.2, 0.0, 1.2, 1.0, -1.1])
+
+# Niveles de ruido rosa medidos por banda de octava, una fila por posición de medición.
+pink = np.array([
+ [72.0, 71.0, 70.0, 69.0, 67.0, 64.0, 60.0],
+ [67.0, 66.0, 64.5, 63.0, 60.5, 57.0, 52.5],
+ [63.5, 62.0, 60.0, 58.0, 55.0, 51.0, 46.0],
+ [60.0, 58.5, 56.0, 53.5, 50.0, 45.5, 40.0],
+])
+source_1m = np.full(7, 90.0) - 11.0 # Ec. (1): Lp,Ls,1m = Lw,Ls - 11 dB
+
+d_n = source_1m - pink # Ec. (2): atenuación por banda
+speech_n = speech_1m - d_n # Ec. (3): revestida de habla
+lp_a_s = 10 * np.log10(np.sum(10 ** ((speech_n + a_weight) / 10), axis=1))
+print(np.round(lp_a_s, 1)) # [48. 42.4 37.8 33.8] Ec. (4)
+
+dist = np.array([2.0, 4.0, 8.0, 16.0])
+chain = room.open_plan_metrics(dist, lp_a_s, 0.70 - 0.03 * dist)
+print(round(chain.d2s, 1), round(chain.lp_as_4m, 1)) # 4.7 42.9
+```
+
+La aritmética de bandas en sí — ponderación A y suma en energía — es la misma
+que en [Niveles](/phonometry/es/signals/levels/levels/).
+
### Parámetros de `open_plan_metrics()`
| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
| `positions_m` | array 1D | m | ≥ 4 posiciones, todas > 0 | Distancias fuente-receptor |
-| `spl_a_speech` | array 1D | dB | misma longitud | Nivel de habla ponderado A $L_{p,A,S,n}$ por posición |
+| `spl_a_speech` | array 1D | dB | misma longitud | Nivel de habla ponderado A $L_{p,A,S,n}$ por posición, procedente de la cadena de las Ec. (1)-(4) del apartado 6.2 — **no** los dB(A) de ruido rosa medidos |
| `sti_values` | array 1D | — | misma longitud | STI por posición (método completo de IEC 60268-16) |
Devuelve un `OpenPlanResult` con `d2s`, `lp_as_4m`, `rd` y `rp`; su
@@ -187,7 +284,7 @@ posición puede medirse a su vez con las herramientas STIPA de la
`OpenPlanResult.report(path)` renderiza una ficha PDF de una página con el
formato de un informe de medición de privacidad acústica en oficinas diáfanas:
la línea de norma base, un bloque de cabecera de metadatos opcional, una tabla
-compacta de las cuatro magnitudes de número único del apartado 4 ($D_{2,S}$,
+compacta de las cuatro magnitudes que devuelve `open_plan_metrics` ($D_{2,S}$,
$L_{p,A,S,4m}$, la distancia de distracción $r_D$ y la distancia de privacidad
$r_P$) apilada sobre la gráfica de decaimiento espacial a todo el ancho del
resultado (`.plot()`, la regresión del apartado 6.2 en el eje logarítmico de
@@ -393,6 +490,10 @@ los ocupantes del capítulo 17 de *Architectural Acoustics* 2.ª ed. de Long
de `open_plan_metrics` en lugar de calcularse dentro de la función: mídela
con las herramientas STIPA de la
[guía del Índice de transmisión del habla](/phonometry/es/perception/speech/speech-transmission/).
+La cuarta magnitud de número único exigida, el ruido de fondo medio ponderado A
+$L_{p,A,B}$, tampoco se calcula aquí: es la media energética ponderada A de los
+niveles de fondo por banda de octava de cada posición, y le corresponde ir en el
+informe junto a las tres que sí produce esta página.
El propio procedimiento de medición de la norma (la directividad del
altavoz, las condiciones amueblada frente a desocupada, la captura del
ruido de fondo) no se comprueba: la función consume distancias, niveles y
diff --git a/site/src/content/docs/es/buildings/rooms/reverberation-prediction.mdx b/site/src/content/docs/es/buildings/rooms/reverberation-prediction.mdx
index d108caf38..deb27dd67 100644
--- a/site/src/content/docs/es/buildings/rooms/reverberation-prediction.mdx
+++ b/site/src/content/docs/es/buildings/rooms/reverberation-prediction.mdx
@@ -363,7 +363,28 @@ habituales:
Los objetos difusores restauran la mezcla que los modelos suponen: una sala
amueblada sigue la predicción estadística claramente mejor que la misma
sala vacía, más allá de lo que explica el área de absorción propia del
-mobiliario. En la práctica, indica una *banda* de predicciones (Sabine y
+mobiliario. El clip de abajo es ese mecanismo con la absorción quitada de
+en medio, de modo que solo queda la mezcla: un frente de onda de 800 Hz entra
+en una sala rígida de 4 m llena de columnas rígidas de 10 a 17 cm de anchura,
+de un cuarto a dos quintos de la longitud de onda de 42,9 cm. Cada columna
+difracta el frente y suelta una onda dispersada, las ondas dispersadas
+interfieren y en unos pocos pasos el frente especular se ha convertido en
+energía repartida por toda la sala sin dirección preferente, que es la
+hipótesis de la que parten tanto Sabine como Eyring y que aquí aparece como
+resultado en lugar de como hipótesis. Nada absorbe dentro de la sala, así que
+lo que se ve es *solo* la redistribución; el decaimiento del final es la
+energía escapándose por los dos extremos abiertos.
+
+
+
+En la práctica, indica una *banda* de predicciones (Sabine y
Eyring, o Fitzroy y Arau-Puchades en los casos axiales) en lugar de un
único valor; donde los modelos se separan, la sala está diciendo que su
campo no es difuso.
diff --git a/site/src/content/docs/es/buildings/rooms/room-image-sources.mdx b/site/src/content/docs/es/buildings/rooms/room-image-sources.mdx
index c4ac4248d..b5e30dd41 100644
--- a/site/src/content/docs/es/buildings/rooms/room-image-sources.mdx
+++ b/site/src/content/docs/es/buildings/rooms/room-image-sources.mdx
@@ -108,21 +108,24 @@ res = room.image_source_rir(
receiver=(5.2, 3.4, 1.7),
absorption=0.12, # absorción de pared uniforme (escalar)
fs=48000,
- max_order=12,
+ # Orden suficiente para cubrir un ajuste de T30; véase «Elegir max_order,
+ # duration y fs» más abajo. El 20 por defecto trunca a la mitad la cola de
+ # esta sala.
+ max_order=60,
)
print(res.ir.shape) # (n_muestras,) RIR de banda ancha
-print(round(res.direct_time * 1000, 2)) # llegada del sonido directo, ms
-print(res.times.size == room.audible_image_count(12) + 1) # imágenes + fuente
+print(round(res.direct_time * 1000, 2)) # 10.72 llegada del sonido directo, ms
+print(res.times.size == room.audible_image_count(60) + 1) # imágenes + fuente
-res.plot() # el reflectograma de la figura de abajo
+res.plot() # el reflectograma; la figura de abajo dibuja la misma sala a orden 10
# La RIR sintética entra directa en el análisis de decaimiento de ISO 3382.
params = room.room_parameters(res.ir, res.fs, limits=None)
print(bool(params.t30_valid[0])) # True: la ventana de decaimiento es usable
-# T30 crece hacia la estimación de Eyring al aumentar max_order (ver abajo); a
-# orden bajo la cola especular se trunca, trátalo como un valor limitado por orden.
-print(round(float(params.t30[0]), 2)) # tiempo de reverberación, s
+print(round(float(params.t30[0]), 2)) # 1.06 s, especular
+print(round(float(room.eyring_reverberation_time(105.0, [(142.0, 0.12)])), 2))
+# 0.93 s, la estimación difusa de Eyring para la misma sala
```
`image_source_rir` devuelve un `ImageSourceResult`. Su `ir` es la RIR muestreada
@@ -253,6 +256,56 @@ reflexiones `times`/`distances`/`orders`/`amplitudes`/`image_positions`) con
recuento de imágenes de la caja de zapatos y `reflection_density(t, volume)` la
densidad $4\pi c^3 t^2 / V$.
+### Elegir `max_order`, `duration` y `fs`
+
+`max_order` no es un mando de calidad, es un **horizonte temporal**. La retícula
+de imágenes solo está completa hasta un radio de aproximadamente `max_order` ×
+la dimensión más corta de la sala, así que cubrir $t$ segundos de decaimiento
+exige
+
+$$
+\text{orden} \approx \frac{c\,t}{L_\text{min}} .
+$$
+
+Un ajuste de T30 abarca 35 dB, unos $0{,}58\,T$ de decaimiento. La sala de
+7 × 5 × 3 m de arriba tiene $L_\text{min} = 3$ m y un tiempo de Eyring cercano a
+0,93 s, así que necesita $343 \times 0{,}54 / 3 \approx 60$. Por debajo de eso
+la cola sencillamente falta, y la T30 ajustada sale corta:
+
+| `max_order` | imágenes audibles | T30 ajustada | tiempo de ejecución |
+| ---: | ---: | ---: | ---: |
+| 12 | 2 624 | 0,28 s | < 0,1 s |
+| 20 (por defecto) | 11 520 | 0,43 s | < 0,1 s |
+| 30 | 37 880 | 0,60 s | < 0,1 s |
+| 40 | 88 640 | 0,75 s | 0,1 s |
+| 60 | 295 360 | 1,06 s | 0,2 s |
+
+La estimación de Eyring para esta sala es de 0,93 s, así que el orden 12 se
+queda corto por un factor de 3,3 y el 20 por defecto, por un factor de 2,1. La
+objeción del coste no vale: el orden 60 son 295 360 imágenes y se resuelve en
+dos décimas de segundo.
+
+**`t30_valid` no ve una retícula truncada.** Lee el rango de decaimiento del
+array que le entreguen, así que devuelve `True` en todos los órdenes de la tabla
+anterior. La bandera detecta una *grabación* ruidosa o demasiado corta; no puede
+detectar un modelo que dejó de generar reflexiones. Una `duration` más corta que
+el decaimiento trunca la cola exactamente igual, y en silencio.
+
+Otras dos advertencias pertenecen a este mismo apartado. `fs` cuantiza todas las
+llegadas a la retícula de muestreo, así que el trabajo con reflexiones tempranas
+— tiempos de llegada, ITDG, fracciones laterales — debe leer la tabla exacta
+`times` / `amplitudes` en lugar de buscar picos en la `ir` muestreada. Y
+`absorption` entra como un factor de reflexión de presión real e independiente
+del ángulo $\sqrt{1-\alpha}$, de modo que la incidencia rasante se trata igual
+que la normal.
+
+Y por último, la frontera honesta: si el orden que hace falta para cubrir el
+tiempo de reverberación vuelve impracticable la ejecución — una sala grande con
+un $L_\text{min}$ pequeño, o una cola larga — al método de imágenes puro se le
+está pidiendo un trabajo que corresponde a un modelo híbrido con cola tardía
+estadística, o al
+[solver FDTD](/phonometry/es/simulation/fdtd-simulation/).
+
## 2. Campo estacionario de sala
Cuando una fuente de potencia acústica constante funciona en una sala, el nivel se
@@ -448,6 +501,39 @@ hacia la frecuencia de Schroeder de 175 Hz ($T = 0{,}8$ s) la familia oblicua ya
ha rellenado el espectro y la densidad modal ha superado un modo por hercio, que
es donde toma el relevo el campo estadístico del apartado 2.*
+
+Mostrar el código de esta figura
+
+```python
+import matplotlib.pyplot as plt
+import numpy as np
+# `room` es el import del bloque de room_modes de arriba.
+
+# Long, Architectural Acoustics 2.ª ed., tabla 8.1.
+modes = room.room_modes((7.0, 5.0, 3.0), max_frequency=200.0,
+ speed_of_sound=344.0, reverberation_time=0.8)
+
+# En una línea: la escalera de modos por familia con la densidad modal debajo.
+modes.plot(language="es")
+plt.show()
+
+# A mano: dispersión de las frecuencias propias, una fila por familia.
+kinds = np.asarray(modes.kinds)
+rows = {"axial": 0, "tangential": 1, "oblique": 2}
+fig, ax = plt.subplots()
+for name, y in rows.items():
+ sel = kinds == name
+ ax.vlines(np.asarray(modes.frequencies)[sel], y, y + 0.8, label=name)
+ax.axvline(modes.schroeder_frequency, ls=":", color="k",
+ label=f"Schroeder {modes.schroeder_frequency:.0f} Hz")
+ax.set_yticks([0.4, 1.4, 2.4], list(rows))
+ax.set_xlabel("Frecuencia [Hz]")
+ax.legend()
+plt.show()
+```
+
+
+
### Parámetros de `room_modes()`
| Parámetro | Tipo | Unidades | Rango / defecto | Notas |
diff --git a/site/src/content/docs/es/devices/broadcast/program-loudness.mdx b/site/src/content/docs/es/devices/broadcast/program-loudness.mdx
index 158dc986c..2f2841fec 100644
--- a/site/src/content/docs/es/devices/broadcast/program-loudness.mdx
+++ b/site/src/content/docs/es/devices/broadcast/program-loudness.mdx
@@ -93,8 +93,33 @@ t = np.arange(20 * fs) / fs
x = np.zeros((5, t.size)) # L, R, C, Ls, Rs
x[0] = np.sin(2 * np.pi * 997.0 * t) # 0 dB FS en el canal izquierdo
print(round(broadcast.integrated_loudness(x, fs), 2)) # -3.01 LKFS
+
+# La misma forma de onda en dos canales en vez de en uno (ver más abajo):
+mono = np.sin(2 * np.pi * 997.0 * t)
+print(round(broadcast.integrated_loudness(mono, fs), 2)) # -3.01
+print(round(broadcast.integrated_loudness(np.vstack([mono, mono]), fs), 2)) # 0.00
```
+### Los canales se suman, no se promedian
+
+La Fórmula 2 suma $G_i z_i$ sobre los canales, así que el número de canales
+forma parte de la medida: la misma forma de onda llevada en dos canales es
+exactamente $10\log_{10} 2 = 3,01$ LU más sonora que en uno. El anclaje de
+arriba lo enseña — ese seno de 997 Hz a plena escala marca −3,01 LKFS en un
+solo canal y 0,00 LKFS como mono dual, que es lo que imprimen las dos últimas
+líneas del fragmento anterior.
+
+Se mide el formato de entrega, no un stem. Un pódcast mono entregado como un
+canal cumple a −23 LUFS siendo un canal; duplicarlo a estéreo antes de medir
+hace que marque −20 LUFS e invita a una corrección de 3 dB en el sentido
+equivocado. La misma aritmética explica por qué se excluye el LFE (Tabla 3,
+$G = 0$) y por qué las ponderaciones de los envolventes son 1,41: la suma es
+una suma de sonoridad sobre la disposición de reproducción, de modo que
+cambiar la disposición cambia el número legítimamente. El `np.vstack` de los
+fragmentos siguientes es exactamente esto — mono dual, la entrega estéreo de
+una fuente mono — y es la razón de que marquen 3,01 LU por encima del valor
+de un solo canal de la misma forma de onda.
+
Los coeficientes de los biquads están tabulados a 48 kHz (Tablas 1-2) y a
esa frecuencia se devuelven literalmente; cualquier otra frecuencia los
rederiva a través del prototipo analógico para que la respuesta coincida con
diff --git a/site/src/content/docs/es/devices/electroacoustics/loudspeakers.mdx b/site/src/content/docs/es/devices/electroacoustics/loudspeakers.mdx
index 165b123a3..8844155ef 100644
--- a/site/src/content/docs/es/devices/electroacoustics/loudspeakers.mdx
+++ b/site/src/content/docs/es/devices/electroacoustics/loudspeakers.mdx
@@ -113,17 +113,17 @@ está en $ka\sin\theta = 3{,}8317$.
import numpy as np
from phonometry import radiating_piston
-res = radiating_piston(radius=0.1, frequencies=np.geomspace(20, 20000, 200),
+res = radiating_piston(radius=0.075, frequencies=np.geomspace(20, 20000, 200),
angles=np.linspace(0.0, np.pi / 2, 91))
-print(round(res.radiation_mass, 4)) # 8 rho a^3 / 3, kg
+print(round(res.radiation_mass, 4)) # 0.0014 kg = 8 rho a^3 / 3
print(round(float(res.directivity_index[0]), 2)) # 3.01 dB, límite de semiespacio
res.plot() # R1 y X1 vs ka
```
-*El `.plot()` del resultado es la figura clásica de impedancia de Beranek y
-Mellow calculada para este pistón: por debajo de $ka \approx 1$ la carga es
+*El `.plot()` del pistón de 75 mm de arriba es la figura clásica de impedancia
+de Beranek y Mellow: por debajo de $ka \approx 1$ la carga es
casi puramente de tipo masa ($X_1$ domina y $R_1 \propto (ka)^2$, el régimen
en el que la salida de un altavoz está limitada por rigidez y masa), y por
encima la resistencia se asienta en $\rho c S$ con rizados de interferencia
diff --git a/site/src/content/docs/es/devices/electroacoustics/microphones.mdx b/site/src/content/docs/es/devices/electroacoustics/microphones.mdx
index 22af7c6d5..3fe33b0c3 100644
--- a/site/src/content/docs/es/devices/electroacoustics/microphones.mdx
+++ b/site/src/content/docs/es/devices/electroacoustics/microphones.mdx
@@ -15,7 +15,7 @@ references:
title: "Sound system equipment – Part 4: Microphones"
designation: "IEC 60268-4:2014"
url: "https://webstore.iec.ch/en/publication/32039"
- note: "Las características nominales de micrófono de esta guía: la sensibilidad de campo libre y su nivel re 1 V/Pa (11.1/11.3), la respuesta en frecuencia y el rango de frecuencias efectivo (12.1/12.2), el patrón direccional y el índice de directividad mediante la integral de campo difuso de 11.2.2 a) (13.1/13.2), el nivel de presión acústica de sobrecarga (15.2), el nivel de presión acústica equivalente debido al ruido propio (17) y las impedancias nominales y la alimentación (9/10). Revisada después como IEC 60268-4:2018 (misma página de catálogo); la edición implementada es la de 2014."
+ note: "Las características nominales de micrófono de esta guía: la sensibilidad de campo libre y su nivel re 1 V/Pa (11.1/11.3), la respuesta en frecuencia y el rango de frecuencias efectivo (12.1/12.2), el patrón direccional (13.1) y el índice de directividad (13.2.2) mediante la integral de campo difuso de 11.2.2 a), el nivel de presión acústica de sobrecarga (15.2), el nivel de presión acústica equivalente debido al ruido propio (17) y las impedancias nominales y la alimentación (9/10). Revisada después como IEC 60268-4:2018 (misma página de catálogo); la edición implementada es la de 2014."
- type: standard
organization: "International Electrotechnical Commission"
year: 1982
@@ -90,7 +90,10 @@ figura en ocho con nulos a ±90°. Un número condensa el patrón: el **índice
de directividad** $D = 20\log_{10}(M_0/M_\mathrm{diff})$ compara la sensibilidad
en el eje de referencia con la sensibilidad de campo difuso obtenida de la
integral de la cláusula 11.2.2 a) sobre un patrón con simetría de
-revolución. Un omni puntúa 0 dB; el cardioide ideal y la figura en ocho,
+revolución (cláusula 13.2.2; el índice se ancla en dos cláusulas porque el
+$M_\mathrm{diff}$ por el que divide es el que define la cláusula 11.2.2 a),
+como el valor eficaz del patrón sobre un ángulo sólido con simetría de
+revolución). Un omni puntúa 0 dB; el cardioide ideal y la figura en ocho,
ambos $10\log_{10} 3 = 4{,}8$ dB: en un campo difuso de sala, un cardioide
capta tres veces menos potencia reverberante que un omni de igual
sensibilidad axial, que es exactamente la relación que quiere un cálculo de
diff --git a/site/src/content/docs/es/devices/emission/intensity.mdx b/site/src/content/docs/es/devices/emission/intensity.mdx
index 58d6ba4c4..83e04e58a 100644
--- a/site/src/content/docs/es/devices/emission/intensity.mdx
+++ b/site/src/content/docs/es/devices/emission/intensity.mdx
@@ -89,6 +89,11 @@ plt.show()
+La medición en sí son dos canales síncronos: `p1` y `p2` son las presiones
+calibradas de las dos cápsulas en pascales, `p1` la más cercana a la fuente,
+adquiridas en el mismo analizador a la misma frecuencia de muestreo y con el
+eje de la sonda normal a la superficie de medida.
+
```python
import numpy as np
from phonometry import emission
@@ -123,40 +128,40 @@ medición de intensidad.*
```python
import matplotlib.pyplot as plt
import numpy as np
+from scipy import signal
from phonometry import emission
-fs = 48000
-rng = np.random.default_rng(0)
-# Las presiones de los dos micrófonos de la sonda en Pa, p1 el más cercano a la fuente.
-# En una medición real son tus dos grabaciones de sonda calibradas;
-# sintetizadas aquí (p2 = p1 retardada una muestra) para que la guía funcione.
-p1 = 0.02 * rng.standard_normal(fs)
-p2 = np.concatenate(([0.0], p1[:-1])) # p2 = p1 retardada una muestra
-res = emission.sound_intensity(p1, p2, fs, spacing=0.012, fraction=3,
- limits=[100, 2500])
-
-# res es el IntensityResult calculado en el ejemplo anterior.
-# En una línea — Lp frente a LI por banda, con el índice presión-intensidad en un eje gemelo:
-res.plot(language="es")
-plt.show()
-
-# A mano, con los campos por banda que lleva el resultado — reproduciendo lo que
-# dibuja IntensityResult.plot() (etiqueta de barra, leyenda combinada de ambos ejes, título δpI):
-fig, ax = plt.subplots()
-ax.semilogx(res.frequency, res.pressure_level, "o-", label="Nivel de presión Lp")
-ax.semilogx(res.frequency, res.intensity_level, "s--", label="Nivel de intensidad LI")
-ax.set_xlabel("Frecuencia [Hz]")
-ax.set_ylabel("Nivel [dB]")
-twin = ax.twinx()
-twin.bar(res.frequency, res.pressure_intensity_index,
- width=res.frequency * 0.2, color="#2ca02c", alpha=0.25,
- label="δpI = Lp − LI")
-twin.set_ylabel("Índice presión-intensidad δpI [dB]")
-# Combina los manejadores de ambos ejes en una sola leyenda, igual que .plot():
-lines, labels = ax.get_legend_handles_labels()
-tlines, tlabels = twin.get_legend_handles_labels()
-ax.legend(lines + tlines, labels + tlabels)
-ax.set_title(f"Lp frente a LI (δpI total = {res.total_pressure_intensity_index:.1f} dB)")
+fs, dr, c = 48000, 0.012, 343.0
+n = int(fs * 4.0)
+
+# Ruido de banda ancha, limitado a 80 Hz - 6 kHz y escalado a unos 70 dB SPL.
+rng = np.random.default_rng(2026)
+noise = signal.sosfilt(
+ signal.butter(4, [80.0, 6000.0], btype="bandpass", fs=fs, output="sos"),
+ rng.standard_normal(n),
+)
+noise *= 0.063 / np.std(noise)
+spectrum = np.fft.rfft(noise)
+freqs = np.fft.rfftfreq(n, 1 / fs)
+
+# Izquierda: una onda plana progresiva. El micrófono 2 ve la onda dr/c = 35 us
+# más tarde, aplicado como desfase y no como un número entero de muestras.
+plane = emission.sound_intensity(
+ noise, np.fft.irfft(spectrum * np.exp(-2j * np.pi * freqs * dr / c), n),
+ fs, dr, fraction=3, limits=[100.0, 5000.0],
+)
+
+# Derecha: una onda estacionaria, dos ondas iguales contrapropagantes, con la
+# sonda centrada en x0 = 0,30 m de la terminación rígida.
+k, x0 = 2 * np.pi * freqs / c, 0.30
+def at(pos):
+ return np.fft.irfft(spectrum * 2.0 * np.cos(k * pos), n)
+standing = emission.sound_intensity(at(x0 - dr / 2), at(x0 + dr / 2),
+ fs, dr, fraction=3, limits=[100.0, 5000.0])
+
+fig, (axl, axr) = plt.subplots(1, 2, figsize=(12, 5), sharey=True)
+plane.plot(ax=axl, language="es")
+standing.plot(ax=axr, language="es")
plt.show()
```
@@ -200,8 +205,8 @@ periódicas, de 8 s a 12 s por muestra o cualquier número entero de ciclos).
**$F_1$**, el indicador de variabilidad temporal, es el coeficiente de
variación de esas muestras (ecuaciones (A.1)-(A.2)), de modo que vale cero
para un campo perfectamente estacionario y crece a medida que la intensidad
-parásita fluctúa. La tabla B.3 exige el código de acción (e) por encima de
-$F_1 > 0{,}6$: reducir la variabilidad, medir en periodos más tranquilos o
+parásita fluctúa. La tabla B.3 exige el código de acción (e) cuando
+$F_1$ supera 0,6: reducir la variabilidad, medir en periodos más tranquilos o
alargar el tiempo de promediación en cada posición. El Anexo B además lo
evalúa inmediatamente antes y después de la medida en cualquiera de las
superficies (B.1.4).
@@ -372,9 +377,9 @@ que llegaba el apartado anterior a partir de la física.
`intensity_class_compliance` compara un espectro de $\delta_{pI0}$ medido con
ambas
-máscaras banda a banda y devuelve la clase que la cadena cumple realmente: la
-clase más laxa que superan todas las bandas, o `None` cuando alguna banda no
-supera ninguna de las dos:
+máscaras banda a banda y devuelve un `IntensityInstrumentComplianceResult` que
+lleva la clase que la cadena cumple realmente: la clase más laxa que superan
+todas las bandas, o `None` cuando alguna banda no supera ninguna de las dos.
```python
from phonometry import metrology
@@ -455,7 +460,7 @@ el repositorio; haz clic en la vista previa para abrir el PDF.
name="iec61043_intensity_example"
title="Informe de ejemplo de verificación de clase de instrumento de intensidad IEC 61043 (PDF)"
description="Ficha de verificación de clase de instrumento de una página: una cabecera de metadatos, una tabla por bandas con los mínimos de clase 1 y clase 2, el índice residual medido, el margen y la clase alcanzada en cada banda de tercio de octava de 50 Hz a 6,3 kHz, el índice medido trazado como curva escalonada sobre las dos máscaras de la Tabla 2 con la banda de 100 Hz marcada por debajo del mínimo de clase 1, el resultado encuadrado Class 2 - COMPLIES (binding margin +4.20 dB), la separación entre micrófonos y el desfase equivalente, y un veredicto FAIL frente a la clase 1 exigida."
- caption="Ficha de verificación de clase de instrumento (IntensityClassResult.report), la clase alcanzada con su margen vinculante y el δpI0 medido sobre los mínimos de la Tabla 2 reescalados al separador de 12 mm."
+ caption="Ficha de verificación de clase de instrumento (IntensityInstrumentComplianceResult.report), la clase alcanzada con su margen vinculante y el δpI0 medido sobre los mínimos de la Tabla 2 reescalados al separador de 12 mm."
/>
### Leer `δpI0` como un error de fase
@@ -494,6 +499,11 @@ También por eso una décima de grado de desfase entre canales es
una especificación exigente, y por eso una sonda debe verificarse con el
separador con el que realmente se va a usar.
+## Elegir la sonda
+
+Antes de tomar ningún dato hay dos decisiones: dónde se puede colocar la
+superficie de medida y qué separador se monta en la sonda.
+
### Campos reactivos cerca de la fuente
Cerca de una fuente el campo se vuelve **reactivo**: la presión y la
@@ -501,7 +511,7 @@ velocidad de partícula tienden a la cuadratura, así que una presión grande
transporta poco flujo neto. Para una fuente pequeña la componente en
cuadratura crece como $1/(kr)$; a 100 Hz y 0,25 m de la fuente ya es
aproximadamente el doble de la activa, y $\delta_{pI}$ sube igual que en la onda
-estacionaria de la figura anterior. Lo mismo ocurre entre una máquina y una
+estacionaria de la figura de dos paneles del principio de esta página. Lo mismo ocurre entre una máquina y una
superficie reflectante rígida, y en cámaras reverberantes donde el campo difuso
eleva la presión sin transportar energía hacia fuera. Por eso ISO 9614-1
mantiene la superficie de medida a más de 0,5 m de la fuente en promedio, y
@@ -539,7 +549,7 @@ separador
instalado, porque el índice pertenece a la cadena
sonda-separador-analizador, no a los micrófonos por sí solos.
-### Parámetros de `sound_intensity()`
+## Parámetros de `sound_intensity()`
| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
@@ -590,4 +600,9 @@ phonometry hace con él es clasificarlo frente a la tabla 2.
## Véase también
+- [Potencia acústica por barrido de intensidad](/phonometry/es/devices/emission/sound-power-intensity/) — las rutas de ISO 9614-2/-3 que consumen $\delta_{pI}$, los indicadores de campo y la capacidad dinámica.
+- [Potencia acústica](/phonometry/es/devices/emission/sound-power/) — la elección entre las rutas de intensidad, de presión y de cámara reverberante.
+- [Potencia acústica desde la vibración superficial](/phonometry/es/devices/emission/vibration-sound-power/) — el factor de radiación de ISO/TS 7849-2 necesita una potencia medida por intensidad.
+- [Calibración](/phonometry/es/signals/metrology/calibration/) — el escalado absoluto de los dos canales que el estimador da por supuesto.
+- [Teoría: análisis de señal](/phonometry/es/reference/theory/signal-analysis/) — la derivación por espectro cruzado que hay detrás de $I(f) = -\mathrm{Im}\{G_{12}\}/(2\pi f \rho_0 \Delta r)$.
- Referencia de la API: [`emission.intensity`](/phonometry/es/reference/api/power/intensity/).
diff --git a/site/src/content/docs/es/devices/emission/sound-power-intensity.mdx b/site/src/content/docs/es/devices/emission/sound-power-intensity.mdx
index 134ee7804..548c02f46 100644
--- a/site/src/content/docs/es/devices/emission/sound-power-intensity.mdx
+++ b/site/src/content/docs/es/devices/emission/sound-power-intensity.mdx
@@ -315,7 +315,7 @@ El resultado de barrido por intensidad (`SoundPowerIntensityResult`,
ISO 9614-2) escribe mediante su propio `.report()` una ficha PDF de una
página con el formato de una hoja de ensayo de potencia acústica,
compartiendo el diseño y el contenedor `ReportMetadata` de la
-[ficha de los métodos de presión](/phonometry/es/devices/emission/sound-power-pressure/#informe-de-medicion).
+[ficha de los métodos de presión](/phonometry/es/devices/emission/sound-power-pressure/#3-el-informe-de-medición-report).
La línea de base normativa nombra la ISO 9614-2:1996 y el grado de
medición, la tabla por bandas lista el nivel de potencia acústica de banda
$L_W$ derivado de la intensidad, y el recuadro del $L_{WA}$ recoge el $L_W$
@@ -385,8 +385,9 @@ estilo acreditado mediante `.report()`.
**No cubierto.** ISO 9614-1, el método de intensidad de puntos fijos
discretos, no es una de las vías de aquí: solo se reutilizan sus
indicadores de campo, y la determinación de potencia por puntos discretos
-en sí pertenece a la
-[guía de intensidad acústica](/phonometry/es/devices/emission/intensity/). El sesgo
+no está implementada en absoluto; la
+[guía de intensidad acústica](/phonometry/es/devices/emission/intensity/) cubre la
+sonda y los indicadores de campo del Anexo A que ambas partes comparten. El sesgo
por diferencias finitas de la sonda y el índice de intensidad residual de
presión son propiedades medidas del instrumento, cubiertas en la misma
guía. La elección entre las cinco vías, y la declaración ISO 4871 que un
diff --git a/site/src/content/docs/es/devices/emission/sound-power-pressure.mdx b/site/src/content/docs/es/devices/emission/sound-power-pressure.mdx
index a624314fa..fc33ce33f 100644
--- a/site/src/content/docs/es/devices/emission/sound-power-pressure.mdx
+++ b/site/src/content/docs/es/devices/emission/sound-power-pressure.mdx
@@ -298,6 +298,27 @@ absorción del aire sobre el radio de medición. Las posiciones de micrófono so
conjuntos normalizados de vectores unitarios de las Tablas D.1 (esfera), E.1
(semiesfera) y E.2 (semiesfera, banda ancha).
+**El radio no es libre** (cláusulas 8.1/8.2). Debe cumplir $r \ge 2 d_0$, con
+$d_0$ la distancia del centro acústico al punto más alejado de la fuente (en
+cámara semianecoica, $r \ge 2 d_0$ o $r \ge 3 h_0$, el que sea mayor, siendo
+$h_0$ la altura del centro acústico sobre el suelo), $r \ge \lambda/4$ a la
+frecuencia más baja de interés y $r \ge 1$ m — 0,5 m solo para una fuente
+pequeña y poco ruidosa en una banda limitada — con toda la superficie dentro
+de la región cualificada según el Anexo A o el B. Con números: una fuente de
+sobremesa de 0,6 × 0,5 × 0,7 m tiene
+$d_0 = \sqrt{0{,}3^2 + 0{,}25^2 + 0{,}7^2} = 0{,}80$ m, así que $r \ge 1{,}6$ m;
+con una banda más baja de 100 Hz, $\lambda/4 = 0{,}86$ m no manda, y el suelo
+de 1 m tampoco. El `radius=1.0` de los ejemplos de abajo solo vale, por tanto,
+para una fuente de menos de unos 0,5 m de dimensión característica.
+
+**El conjunto de posiciones tampoco lo es.** Primero se usan las posiciones 1
+a 20, y las 21 a 40 se añaden solo cuando la diferencia entre el nivel más
+alto y el más bajo en alguna banda de interés no es menor que la mitad del
+número de posiciones — una comprobación sobre datos que el lector ya tiene,
+`levels.max(0) - levels.min(0) >= 0.5 * levels.shape[0]`. Si con 40 posiciones
+sigue sin cumplirse, hace falta una investigación localizada y las posiciones
+pasan entonces a tener áreas desiguales, que es para lo que está `areas=`.
+
```python
import numpy as np
from phonometry import emission
@@ -359,8 +380,15 @@ base = 70.0 + 8.0 * np.exp(-(np.log2(freqs / 1000.0) ** 2) / 2.0)
rng = np.random.default_rng(7)
levels = base[None, :] + rng.normal(0.0, 1.0, (40, freqs.size))
-result = emission.sound_power_anechoic(levels, "hemisphere", radius=1.0, frequencies=freqs)
+# sigma_omc es la desviación típica de funcionamiento y montaje de la
+# Cláusula 10.5; con el valor de EJEMPLO 2.0 dB y el factor de cobertura por
+# defecto k = 2, la incertidumbre expandida U = k*sqrt(sigma_R0^2 + sigma_omc^2)
+# son los 4.1 dB que imprime la ficha de abajo. Con su valor por defecto 0
+# informa 1.0 dB.
+result = emission.sound_power_anechoic(levels, "hemisphere", radius=1.0,
+ frequencies=freqs, sigma_omc=2.0)
print(round(result.sound_power_level_a, 1)) # 89.3
+print(round(float(result.uncertainty), 1)) # 4.1 dB
result.plot() # espectro LW, LWA en el título (requiere matplotlib)
```
diff --git a/site/src/content/docs/es/devices/emission/sound-power-reverberation.mdx b/site/src/content/docs/es/devices/emission/sound-power-reverberation.mdx
index fe36c1986..ea637f4a7 100644
--- a/site/src/content/docs/es/devices/emission/sound-power-reverberation.mdx
+++ b/site/src/content/docs/es/devices/emission/sound-power-reverberation.mdx
@@ -19,6 +19,7 @@ references:
---
import ThemeImage from '../../../../../components/ThemeImage.astro';
+import Video from '../../../../../components/Video.astro';
import ReportPreview from '../../../../../components/ReportPreview.astro';
Una cámara reverberante convierte su principal defecto como espacio de escucha
@@ -67,6 +68,26 @@ por una fuente sonora de referencia de potencia conocida $L_W(\text{RSS})$
medida en la misma cámara, de modo que la cámara no necesita caracterizarse:
$L_W = L_W(\text{RSS}) + (L_p(\text{ST}) - L_p(\text{RSS}) + C_2)$.
+El panel derecho del clip de abajo es este método. La misma fuente suena en
+las dos salas; en la cámara anecoica de la izquierda los micrófonos solo ven
+lo que la fuente les envía, así que el nivel cae con la distancia y la vía de
+campo libre tiene que integrar sobre una superficie de medida, mientras que
+en la cámara reverberante de la derecha la energía reflejada llena el espacio
+y el nivel deja de depender de dónde esté un micrófono. Esa es toda la razón
+de que la Ec. 20 pueda sustituir una integral de superficie por un puñado de
+posiciones y una constante de sala — y la razón de que lo que hay que
+cualificar sea la cámara, no el conjunto de micrófonos. Las dos vías acaban
+en el mismo $L_W$, porque la potencia acústica es una propiedad de la fuente
+y no de la sala en la que se mide.
+
+
+
```python
import numpy as np
from phonometry import emission
@@ -191,7 +212,7 @@ El resultado en cámara reverberante (`ReverberationSoundPowerResult`, ISO 3741)
escribe mediante su propio `.report()` una ficha PDF de una página con el
formato de una hoja de ensayo de potencia acústica, compartiendo el diseño y
el contenedor `ReportMetadata` de la
-[ficha de los métodos de presión](/phonometry/es/devices/emission/sound-power-pressure/#informe-de-medicion).
+[ficha de los métodos de presión](/phonometry/es/devices/emission/sound-power-pressure/#3-el-informe-de-medición-report).
La línea
de base normativa nombra la ISO 3741:2010 y el grado de precisión (grado 1) e
indica qué método se empleó, el método directo usando el área de absorción
diff --git a/site/src/content/docs/es/devices/emission/sound-power.mdx b/site/src/content/docs/es/devices/emission/sound-power.mdx
index aa91b8590..fe1fd1d1b 100644
--- a/site/src/content/docs/es/devices/emission/sound-power.mdx
+++ b/site/src/content/docs/es/devices/emission/sound-power.mdx
@@ -129,7 +129,11 @@ primera coincidencia nombra la norma.
(grado 1); un primer reconocimiento de una nave ruidosa tolera el grado de
inspección (grado 3). El grado 1 solo existe en una sala de laboratorio
cualificada (ISO 3741, ISO 3745) o mediante los métodos de intensidad de
- precisión (ISO 9614-1 en puntos discretos, ISO 9614-3 por barrido).
+ precisión (ISO 9614-1 en puntos discretos, ISO 9614-3 por barrido), de los
+ cuales phonometry implementa solo la forma de barrido: la suma de potencia
+ por puntos discretos de la propia ISO 9614-1 no se ofrece, aunque sí sus
+ indicadores de campo (ver
+ [Intensidad acústica](/phonometry/es/devices/emission/intensity/)).
2. **¿Puede la fuente viajar al laboratorio?** ISO 3741 quiere la fuente
pequeña frente a la cámara (volumen no mayor de aproximadamente el 2 % del
volumen de la cámara) y su ruido estacionario; ISO 3745 la quiere dentro de
@@ -270,6 +274,9 @@ el método de campo difuso en
[Potencia acústica en cámara reverberante](/phonometry/es/devices/emission/sound-power-reverberation/)
y los dos métodos de barrido en
[Potencia acústica por barrido de intensidad](/phonometry/es/devices/emission/sound-power-intensity/).
+La suma de potencia por puntos discretos de la propia ISO 9614-1 no está
+implementada en absoluto; solo lo están sus indicadores de campo, en
+[Intensidad acústica](/phonometry/es/devices/emission/intensity/).
La estadística de lote de ISO 4871 más allá del caso de máquina única
$K = 1{,}645\,\sigma_R$ (Anexo A.2.2) se enuncia, no se deriva.
diff --git a/site/src/content/docs/es/devices/emission/vibration-sound-power.mdx b/site/src/content/docs/es/devices/emission/vibration-sound-power.mdx
index 507e1c9b2..464465b68 100644
--- a/site/src/content/docs/es/devices/emission/vibration-sound-power.mdx
+++ b/site/src/content/docs/es/devices/emission/vibration-sound-power.mdx
@@ -42,12 +42,22 @@ $$
con $Z_c$ la impedancia característica del aire y $\langle v^2 \rangle$ la
velocidad vibratoria cuadrática media sobre el área radiante $S$. Expresada en
-niveles (nivel de velocidad re $v_0 = 5\times10^{-8}\ \text{m/s}$), el nivel de
-potencia acústica con ponderación A es
-(Fórmula 12 / 15)
+niveles (nivel de velocidad re $v_0 = 5\times10^{-8}\ \text{m/s}$), cada parte
+escribe esa relación con sus propias magnitudes. La **Parte 1** va ponderada
+en A de principio a fin: un solo nivel de velocidad superficial ponderado A
+$L_{vA}$, el valor fijo $\varepsilon_A = 1$ y un único número ponderado A, el
+*límite superior* del nivel de potencia acústica aérea (Fórmula 12)
$$
-L_W = L_v + 10\log_{10}\frac{S}{S_0} + 10\log_{10}\varepsilon
+L_{WA,\max} = L_{vA} + 10\log_{10}\frac{S}{S_0}
+ + 10\log_{10}\frac{Z_{c,n}}{Z_{c,0}}.
+$$
+
+La **Parte 2** es la contrapartida por bandas, con el factor de radiación
+$\varepsilon_j$ determinado en cada banda (Fórmula 15)
+
+$$
+L_{W,j} = L_{v,j} + 10\log_{10}\frac{S}{S_0} + 10\log_{10}\varepsilon_j
+ 10\log_{10}\frac{Z_{c,n}}{Z_{c,0}},
$$
@@ -55,8 +65,12 @@ donde $S_0 = 1\ \text{m}^2$, la impedancia normalizada
$Z_{c,n} = 411\ \text{N·s/m}^3$ y la de referencia
$Z_{c,0} = 400\ \text{N·s/m}^3$ dan el término fijo
$10\log_{10}(411/400) = 0{,}118\ \text{dB}$.
-Este módulo alimenta las normas de fuente estructural y de predicción
-en edificación (ISO 9611, EN 15657, EN 12354-5).
+Esta guía ejecuta la forma por bandas para las dos partes, de modo que el
+límite superior de la Parte 1 y el valor de ingeniería de la Parte 2 puedan
+compararse banda a banda; un ensayo estricto de Parte 1 es el número único
+ponderado A de arriba, que el objeto resultado lleva como
+`sound_power_level_a`. Este módulo alimenta las normas de fuente estructural
+y de predicción en edificación (ISO 9611, EN 15657, EN 12354-5).
Antes que los niveles, el propio radiador. El modelo de placa de
`radiation_efficiency` que aporta un factor de radiación predicho retiene su
@@ -142,16 +156,24 @@ lv = np.array([82.0, 85.0, 83.0, 79.0]) # nivel de velocidad por banda
# Límite superior de la Parte 1 (epsilon = 1):
upper = emission.sound_power_from_vibration(lv, area=1.6, frequencies=bands)
-print(round(upper.total_level, 1)) # p. ej. 89.4 dB re 1 pW
+print(round(upper.total_level, 1)) # 90.9 dB re 1 pW, sin ponderar
+print(round(upper.sound_power_level_a, 1)) # 88.9 dB(A) re 1 pW
# Valor de ingeniería de la Parte 2 con un factor de radiación medido:
eps = np.array([0.45, 0.75, 0.95, 1.00])
eng = emission.sound_power_from_vibration(lv, area=1.6, radiation_factor=eps, frequencies=bands)
print(np.round(eng.sound_power_level, 1)) # L_W por banda
+print(round(eng.sound_power_level_a, 1)) # 88.4 dB(A) re 1 pW
eng.plot() # el espectro LW(f), como en la figura de arriba (requiere matplotlib)
```
+Los dos totales no son intercambiables: `total_level` es la suma en bandas sin
+ponderar $10\lg\sum_j 10^{0{,}1 L_{W,j}}$, mientras que `sound_power_level_a` es
+el total ponderado A que la ficha recuadra y que cita una declaración de ruido.
+Se diferencian en la ponderación A del espectro — 2,0 dB en esta carcasa,
+varios decibelios más en una con mucho peso en baja frecuencia.
+
## 2. Nivel de velocidad, calibración y factor de radiación
El nivel de velocidad es $L_v = 20\log_{10}(v/v_0)$ (Fórmula 3); una aceleración de
@@ -178,10 +200,22 @@ vibración extraña según la Tabla 2.
Esas posiciones no son libres: la norma divide la superficie radiante $S$ en
$N$ celdas iguales y coloca un acelerómetro en el centro de cada una. La
-tabla por área da el $N$ inicial; un campo de vibración muy poco uniforme
-puede exigir más posiciones o redistribuirlas.
-
-
+Tabla 1 fija el $N$ inicial solo a partir del área — **5** posiciones por
+debajo de 1 m², **10** de 1 m² a 10 m², y $S/S_0$ posiciones por encima
+($S_0 = 1$ m²) —, así que la superficie de 4 m² dibujada abajo lleva diez.
+Hay que aumentar $N$ cuando la dispersión del nivel de velocidad ponderado A
+entre las posiciones, el más alto menos el más bajo en decibelios, supera el
+doble del número de la Tabla 1; un campo muy poco uniforme puede tratarse en
+cambio redistribuyendo las posiciones, lo que hace desiguales las áreas
+parciales $S_i$ y obliga entonces a la Fórmula 11 ponderada por área en vez de
+a la media energética simple. La corrección de la Tabla 2 es una escalera
+sobre esa misma clase de dispersión: con la máquina parada y la instalación
+circundante en marcha, el nivel medio de velocidad extraña debe quedar al
+menos 3 dB por debajo del de la máquina, y `extraneous_velocity_correction`
+devuelve 3 dB con 3 dB de diferencia, 2 dB con 4-5 dB, 1 dB con 6-9 dB y 0 dB
+a partir de 10 dB.
+
+
## 3. Cuándo se rompe la hipótesis del factor de radiación
@@ -231,7 +265,10 @@ nivel de velocidad vibratoria superficial $L_v$ y el nivel de potencia acústica
de banda $L_W$), el espectro de potencia acústica $L_W(f)$ con eje de banda
nominal, y un nivel de potencia acústica ponderado A $L_{WA}$ (dB re 1 pW)
recuadrado con el total $L_W$, el área radiante $S$ y el método aplicado al
-lado.
+lado. Esos dos salen del `sound_power_level_a` del resultado (el total
+ponderado A declarable) y de su `total_level` (la suma en bandas sin
+ponderar); las columnas de la tabla salen de `velocity_level`,
+`sound_power_level` y, con `verbose=True`, `radiation_factor`.
Los metadatos se aportan mediante un `ReportMetadata`, cuyos campos aplicables
aquí son la **descripción de la máquina/fuente** (`specimen`), el **entorno de
diff --git a/site/src/content/docs/es/devices/noise-control/duct-path.mdx b/site/src/content/docs/es/devices/noise-control/duct-path.mdx
index 4b54f09f9..a07b5829a 100644
--- a/site/src/content/docs/es/devices/noise-control/duct-path.mdx
+++ b/site/src/content/docs/es/devices/noise-control/duct-path.mdx
@@ -362,11 +362,18 @@ Standard 70, que es lo que usa una hoja real. Cuando no se dispone de ellos,
`diffuser_sound_power` es la estimación de Reynolds tal como la dan las
Ecs. 13.27 a 13.33 de Long: un nivel global
$L_W = 10\log_{10} S_G + 30\log_{10}\xi + 60\log_{10} U_G - 31{,}3$ a partir
-del área de la cara, la velocidad de aproximación $U_G = Q/S_G$ y el
-coeficiente normalizado de pérdida de carga $\xi$, repartido por octavas
-mediante la función de forma $C_D = -11{,}82 - 0{,}15 A - 1{,}13 A^2$
-($-5{,}82$ si el equipo es circular) en torno a la banda de pico
-$f_P = 48{,}8\,U_G$.
+del área de la cara $S_G$, la velocidad de aproximación $U_G = Q/S_G$ y el
+coeficiente normalizado de pérdida de carga
+$\xi = 334{,}9\,\Delta p/(\rho_0 U_G^2)$ de la Ec. 13.28. Long escribe las
+cuatro en unidades anglosajonas ($S_G$ en ft², $U_G$ en ft/s, $\Delta p$ en
+pulgadas de columna de agua); `diffuser_sound_power` acepta y devuelve SI y
+convierte internamente, que es la razón de que aquí las constantes se citen
+sobre las unidades de Long. El espectro sale como
+$L_{W,\text{oct}} = L_W + C_D$ con la función de forma
+$C_D = -11{,}82 - 0{,}15 A - 1{,}13 A^2$ para un equipo rectangular
+($-5{,}82$ si es circular), donde $A$ es la distancia en octavas a la banda
+de pico $f_P = 48{,}8\,U_G$ (Ec. 13.32, $U_G$ en **ft/s**), contada sobre la
+numeración de bandas de Long con la banda 0 en 32 Hz.
```python
from phonometry import diffuser_sound_power
@@ -380,6 +387,11 @@ print(np.round(diffuser_sound_power(None, (24 * IN) ** 2,
pressure_drop=0.05 * IN_WG).values, 1))
# [ 33.4 32.4 29.1 23.6 15.9 5.9 -6.4 -21. ]
# La Tabla 14.9 de Long imprime 33/32/29/23/15/4/0/0 en esa fila.
+
+# La banda de pico desde la que se cuenta la función de forma, en unidades de Long:
+face_velocity = 312 * CFM / (24 * IN) ** 2 / 0.3048 # 1.3 ft/s
+print(round(48.8 * face_velocity, 1)) # fP = 63.4 Hz
+print(round(np.log2(48.8 * face_velocity / 32.0))) # banda 1: la octava de 63 Hz
```
La sexta potencia de la velocidad en la Ec. 13.27 es la regla de diseño:
@@ -560,17 +572,19 @@ for fila in total.table():
print(f"{fila['kind']:<12} {fila['label'][:26]:<26} "
f"{[round(float(v)) for v in fila['values']]}")
-total.report("ruido-conductos.pdf", language="es") # necesita phonometry[report]
+impulsion.report("ruido-conductos-impulsion.pdf", language="es") # la ficha de abajo
+total.report("ruido-conductos.pdf", language="es") # la combinación; necesita phonometry[report]
```
-La ficha de ejemplo, regenerada con `make reports`, se mantiene renderizada en
-el repositorio. Pulse la vista previa para abrir el PDF:
+La ficha de ejemplo es la **mitad de impulsión** de la hoja, regenerada con
+`make reports` y mantenida renderizada en el repositorio. Pulse la vista
+previa para abrir el PDF:
## 7. Qué se reproduce y qué no
diff --git a/site/src/content/docs/es/devices/noise-control/room-to-room.mdx b/site/src/content/docs/es/devices/noise-control/room-to-room.mdx
index ecf11ce9e..6ecc1023e 100644
--- a/site/src/content/docs/es/devices/noise-control/room-to-room.mdx
+++ b/site/src/content/docs/es/devices/noise-control/room-to-room.mdx
@@ -35,6 +35,7 @@ references:
---
import ThemeImage from '../../../../../components/ThemeImage.astro';
+import Video from '../../../../../components/Video.astro';
Una máquina funciona en un recinto, un muro separa ese recinto de otro
ocupado, y alguien quiere saber qué oye el ocupante. Es una cadena corta, y
@@ -75,7 +76,9 @@ $$
con $\text{NR} = L_{p1} - L_{p2}$ la reducción de ruido entre los dos campos
reverberantes, $\text{TL} = 10\log_{10}(1/\tau)$ la pérdida por transmisión de la
-partición (la magnitud que UNE llama índice de reducción acústica $R$), $S_w$
+partición — la magnitud que mide ISO 10140-2 y que ISO 717-1 valora como
+índice de reducción acústica $R$, de modo que el $R$ y el $R_w$ de un informe
+de ensayo de laboratorio entran directamente en esta ecuación —, $S_w$
el área de la partición y $S_2 \alpha_2$ el área de absorción sonora
equivalente del recinto receptor.
@@ -379,6 +382,24 @@ la partición, un paso de instalaciones, el hueco bajo una puerta, o
simplemente el muro que no llega al forjado, y la respuesta de la ecuación
pasa a ser una cota superior.
+El clip de abajo dibuja lo que la ecuación deja fuera. La cadena del
+apartado 3 tarifa solo el camino directo, la vía **Dd** a través de la
+partición; los otros tres pulsos salen del recinto emisor por los muros,
+el suelo o el techo de flanco — **Ff** de flanco a flanco, **Fd** de flanco a
+partición, **Df** de partición a flanco — y vuelven a radiar al otro lado sin
+haber pasado nunca por la pérdida por transmisión que usó el cálculo. Cada
+camino mengua en cada elemento y en cada unión que atraviesa, y por eso
+ninguno tiene que ser grande por sí solo para que la suma de los tres domine
+sobre una buena partición.
+
+
+
`DesignCriterion.flanking_penalty` es el cargo explícito por eso, en
decibelios restados a la
reducción de ruido predicha. No es un modelo, es un sitio donde registrar la
diff --git a/site/src/content/docs/es/devices/noise-control/silencers.mdx b/site/src/content/docs/es/devices/noise-control/silencers.mdx
index 9865e244b..987d9d96c 100644
--- a/site/src/content/docs/es/devices/noise-control/silencers.mdx
+++ b/site/src/content/docs/es/devices/noise-control/silencers.mdx
@@ -209,6 +209,24 @@ pérdida de transmisión: $f_0 = \tfrac{c}{2\pi}\sqrt{S_n/(l_e V)}$ (Bies Ec. (8
y $f = c/4l_e$ (Ec. (8.44)). Una **cámara de tubo extendido** aloja ramas de
cuarto de onda dentro de una cámara de expansión para rellenar sus caídas.
+Las dos longitudes son longitudes **efectivas**, y las dos funciones las
+toman así (`neck_length` y `length` están documentadas como $l_e$, con las
+correcciones de extremo incluidas). El aire del cuello no deja de moverse en
+la boca: arrastra consigo un tapón de aire a cada lado, así que la masa que
+resuena contra la cavidad pertenece a un tubo más largo que el que se
+taladró. Hay que añadir unos $0{,}85a$ por extremo embridado y unos $0{,}61a$
+por extremo libre, para un cuello de radio $a$, en los dos extremos de un
+cuello de Helmholtz y solo en el extremo abierto (el del conducto) de un tubo
+de cuarto de onda. El resonador dibujado abajo es el caso de manual: su
+cuello mide 11,3 mm de diámetro ($a = 5{,}64$ mm) y 20 mm de largo, así que
+$l_e \approx 20 + 2 \times 4{,}8 = 29{,}6$ mm y la sintonía baja de los
+122,1 Hz que devuelve la longitud taladrada a 100,3 Hz — un error del 22 % en
+una muesca que la figura de abajo enseña que solo tiene unos pocos hercios de
+ancho. Cuanto más corto y más ancho el cuello, mayor es la corrección en
+términos relativos, que es justo el régimen en el que vive un resonador
+compacto, así que el procedimiento práctico es calcular una longitud nominal,
+construirlo largo y recortarlo contra una medición.
+
```python
import numpy as np
from phonometry import (
@@ -219,12 +237,23 @@ f = np.linspace(20.0, 600.0, 4000)
hr = helmholtz_resonator(f, duct_area=0.01, neck_area=1e-4,
neck_length=0.02, cavity_volume=1e-3)
-print(round(float(hr.resonances[0]), 1)) # frecuencia de sintonía, Hz
+print(round(float(hr.resonances[0]), 1)) # 122.1 Hz, para le = 20 mm
hr.plot() # pico de TL en la frecuencia de sintonía (necesita matplotlib)
-qw = quarter_wave_resonator(f, duct_area=0.01, length=1.516, branch_area=2e-3,
- speed_of_sound=343.24)
-print(round(float(qw.resonances[0]), 1)) # 56.6 Hz (Bies Ejemplo 8.1)
+qw = quarter_wave_resonator(f, duct_area=0.01, length=0.3, branch_area=2e-3)
+print(round(float(qw.resonances[0]), 1)) # 285.8 Hz = c / 4 le
+
+# Ejemplo 8.1 de Bies, el anclaje publicado: un tubo de 1.516 m con c = 343.24 m/s.
+print(round(float(quarter_wave_resonator(
+ f, duct_area=0.01, length=1.516, branch_area=2e-3,
+ speed_of_sound=343.24).resonances[0]), 1)) # 56.6 Hz
+
+# El mismo tubo en gases de escape calientes: c(500 degC) = 343*sqrt(773/293) = 557 m/s
+# (ver la advertencia de abajo), que desplaza la muesca en un factor 1.62.
+f_hot = np.linspace(20.0, 900.0, 6000)
+qw_hot = quarter_wave_resonator(f_hot, duct_area=0.01, length=0.3,
+ branch_area=2e-3, speed_of_sound=557.0)
+print(round(float(qw_hot.resonances[0]), 1)) # 464.2 Hz, no 285.8
# Una extensión de entrada de L/4 rellena la primera caída de la cámara.
et = extended_tube_chamber(f, length=0.4, chamber_area=0.04, pipe_area=0.01,
@@ -309,6 +338,27 @@ plantado sobre el mismo conducto.
0,3 m de tubo colocan el pico en $c/4l_e \approx 285\ \text{Hz}$, y el área de
rama de 20 cm² solo fija con cuánta fuerza carga el conducto.*
+:::caution
+**Sintonizar a la temperatura de trabajo.**
+Todas las frecuencias de esta página son condiciones de longitud de onda, así
+que todas escalan directamente con la velocidad del sonido **en el gas de
+trabajo**: $kL = \pi/2$ para la cámara, $c/4l_e$ para el tubo y la $c$ que va
+delante de la raíz cuadrada de Helmholtz. Para el aire,
+$c(T) = 343\sqrt{T/293}$ con $T$ en kelvin, así que un escape a 500 °C
+(773 K) funciona a unos 557 m/s, un factor 1,62, y el tubo de 0,3 m cortado
+para 285,8 Hz con valores de aire frío canta a 464 Hz en cuanto el tubo se
+calienta. Hay que pasar los valores de trabajo — `speed_of_sound=` y
+`density=`, porque la densidad escala toda impedancia característica y por
+tanto la pérdida de inserción. La llamada con `speed_of_sound=557.0` del
+fragmento del apartado 1 es ese reajuste, y devuelve 464,2 Hz para el mismo
+tubo de 0,3 m.
+
+Un flujo medio desplaza aún más la muesca y rebaja su profundidad, y la
+temperatura cae a lo largo de un escape real, así que un resonador de escape
+se comprueba en los extremos caliente y frío y se acepta con margen en vez de
+diseñarse a un solo valor.
+:::
+
Mostrar el código de esta figura
@@ -423,13 +473,23 @@ la resistividad al flujo de aire, es la misma teoría de materiales que
## Contraste con el solucionador FDTD
-La cámara de expansión de cuatro polos se contrasta con el
+Ese contraste es el clip incrustado en el apartado 1, y vale la pena volver a
+él ahora con el álgebra en la mano. La cámara de expansión de cuatro polos se
+contrasta con el
[solucionador de ondas FDTD 2D](/phonometry/es/simulation/fdtd-simulation/)
-independiente: un conducto de onda plana que se ensancha en una cámara y vuelve a
-estrecharse transmite mucho menos en el máximo de TL de cuatro polos ($kL = \pi/2$)
-que en la caída transparente ($kL = \pi$), y la razón de amplitudes medida
-reproduce la pérdida de transmisión máxima en forma cerrada con una fracción de
-decibelio.
+independiente, que no comparte con el producto de matrices de transferencia
+ninguna fórmula ni ninguna hipótesis más allá de la propia ecuación de ondas:
+un conducto de onda plana que se ensancha en la misma cámara de 0,30 m y
+$m = 4$ y vuelve a estrecharse transmite mucho menos en el máximo de TL de
+cuatro polos ($kL = \pi/2$, aquí 286 Hz) que en la caída transparente
+($kL = \pi$, 572 Hz). La razón de amplitudes medida aguas abajo en el campo es
+la pérdida de transmisión anotada en el clip, 6,5 dB a 286 Hz y 0,0 dB a
+572 Hz, frente a los 6,55 dB que da la forma cerrada para $m = 4$. Un acuerdo
+tan estrecho descarta un error de álgebra en cualquiera de los dos lados. Los
+dos tienen que separarse tarde o temprano por encima de la primera frecuencia
+de corte del conducto, donde se propagan modos de orden superior: el
+solucionador bidimensional sigue funcionando ahí y el álgebra de onda plana
+no.
## Qué cubre esta guía
diff --git a/site/src/content/docs/es/environment/assessment/environmental-levels.mdx b/site/src/content/docs/es/environment/assessment/environmental-levels.mdx
index a7a39ffe8..d6009e2f4 100644
--- a/site/src/content/docs/es/environment/assessment/environmental-levels.mdx
+++ b/site/src/content/docs/es/environment/assessment/environmental-levels.mdx
@@ -9,13 +9,19 @@ references:
designation: "ISO 1996-1:2016"
url: "https://www.iso.org/standard/59765.html"
note: "Lden (3.6.4), Ldn (3.6.5) y el nivel de evaluación compuesto de jornada completa del apartado 6.5 (Fórmulas 5-6, ajustes de la Tabla A.1)."
+ - type: standard
+ organization: "International Organization for Standardization"
+ year: 2007
+ title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
+ designation: "ISO 1996-2:2007"
+ note: "Anexo C: el ancho de banda crítico de la Tabla C.1, la audibilidad de la Fórmula (C.3) y el ajuste a tramos de las Fórmulas (C.4)-(C.6). Es el método de ingeniería autocontenido que implementa la biblioteca; la reimpresión corregida de 2009 es idéntica en esta parte."
- type: standard
organization: "International Organization for Standardization"
year: 2017
title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
designation: "ISO 1996-2:2017"
url: "https://www.iso.org/standard/59766.html"
- note: "El ajuste tonal del Anexo C (con el método de cribado y el mapeo de audibilidad media de ISO/PAS 20065), la corrección de ruido residual del apartado 10.4 y el balance de incertidumbre de medida del apartado 4 / Anexo F."
+ note: "La corrección de ruido residual del apartado 10.4, el balance de incertidumbre de medida del apartado 4 / Anexo F, el mapeo de audibilidad media de la Tabla J.1 del Anexo J y el método de cribado del Anexo K."
- type: standard
organization: "British Standards Institution"
year: 2003
@@ -109,7 +115,7 @@ plt.show()
| :--- | :--- | :--- |
| `lden(lday, levening, lnight, hours=(12, 4, 8))` | $L_{Aeq}$ por periodo [dB]; `hours` debe sumar 24 | +5 dB tarde, +10 dB noche (3.6.4) |
| `ldn(lday, lnight, hours=(15, 9))` | | +10 dB noche (3.6.5) |
-| `composite_rating_level(periods)` | iterable de `(level_db, hours, adjustment_db)` | Fórmulas generales (5)-(6); ajustes según la Tabla A.1 |
+| `composite_rating_level(periods)` | iterable de `(level_db, hours, adjustment_db)`; horas positivas, finitas y sumando 24 | Fórmulas generales (5)-(6); ajustes según la Tabla A.1 |
Dónde pones el micrófono cambia el número: ISO 1996-2 fija las posiciones del receptor y sus correcciones de fachada. El diagrama es contexto de medida; aplica las correcciones a tus niveles antes del análisis:
@@ -131,7 +137,12 @@ nivel de valoración y las penalizaciones por periodo están en ISO 1996-1 (arri
ISO 1996-2 aporta el ajuste tonal, la corrección de ruido residual y el
presupuesto de incertidumbre.
-**Ajuste tonal (método de ingeniería, Anexo C).** A partir del nivel tonal
+**Ajuste tonal (método de ingeniería, Anexo C de ISO 1996-2:2007).** La edición
+de 2017 abandonó el algoritmo autocontenido y remite en su lugar a ISO/PAS 20065
+([Audibilidad objetiva de tonos en ruido](/phonometry/es/perception/psychoacoustics/tone-audibility/));
+lo que conserva es la tabla del Anexo J que convierte una audibilidad *media* en
+un ajuste entero. El algoritmo de 2007 es el implementado aquí, porque funciona
+sobre un único espectro. A partir del nivel tonal
sumado en energía $L_{pt}$ y el nivel de ruido enmascarante $L_{pn}$ en la banda
crítica alrededor de un tono, la audibilidad sobre el umbral de enmascaramiento es
$\Delta L_{ta} = L_{pt} - L_{pn} + 2 + \log_{10}[1 + (f_c/502)^{2{,}5}]$ dB (Fórmula (C.3)),
@@ -196,9 +207,11 @@ environment.expanded_uncertainty(u) # 4,36 dB (k = 2)
**Cubierto.** El $L_{den}$, el $L_{dn}$ y el nivel de valoración compuesto de la ISO
1996-1:2016 (apartado 6.5,
-`environment.lden`/`ldn`/`composite_rating_level`); y el ajuste tonal
-(anexo C), la corrección de ruido residual (apartado 10.4) y el balance de
-incertidumbre de medida (apartado 4, anexo F) de la ISO 1996-2:2017.
+`environment.lden`/`ldn`/`composite_rating_level`); y el ajuste tonal del
+anexo C de la ISO 1996-2:2007 junto con la corrección de ruido residual
+(apartado 10.4), el balance de incertidumbre de medida (apartado 4, anexo F),
+el mapeo de audibilidad media del anexo J y el método de cribado del anexo K
+de la ISO 1996-2:2017.
**No cubierto.** La ISO 1996-2 fija las posiciones del receptor y las
correcciones de fachada que convierten una medida en bruto en el nivel que
diff --git a/site/src/content/docs/es/environment/index.md b/site/src/content/docs/es/environment/index.md
index 9ebdfcb6d..c50fd400c 100644
--- a/site/src/content/docs/es/environment/index.md
+++ b/site/src/content/docs/es/environment/index.md
@@ -4,12 +4,17 @@ description: "El sonido en exteriores y las fuentes que lo dominan: el modelo de
---
El ruido ambiental es un problema fuente-camino-receptor estirado a lo largo
-de cientos de metros de aire libre. Esta sección cubre sus dos extremos. Las
-páginas de **sonido en exteriores** se ocupan del camino y de la evaluación:
-ISO 9613 predice, banda a banda, cuánto nivel sobrevive a la divergencia, la
-absorción del aire, el suelo y cualquier barrera de camino al receptor, y
-NT ACOU 112 cuantifica cuándo el carácter impulsivo hace el sonido recibido
-más molesto de lo que sugiere su LAeq.
+de cientos de metros de aire libre. Esta sección cubre los tres. Las páginas
+de **propagación** se ocupan del camino: ISO 9613 predice, banda a banda,
+cuánto nivel sobrevive a la divergencia, la absorción del aire, el suelo y
+cualquier barrera de camino al receptor, y los modelos ondulatorios de suelo y
+de refracción dicen cuándo ese método de ingeniería deja de bastar.
+
+Las páginas de **evaluación** se ocupan de lo que pasa una vez ha llegado el
+sonido: el nivel de evaluación de ISO 1996 y los indicadores día-tarde-noche,
+su aplicación española en el RD 1367/2007, y el ajuste de NT ACOU 112 que
+cuantifica cuándo el carácter impulsivo hace un sonido recibido más molesto de
+lo que sugiere su LAeq.
Las páginas de **fuentes** se ocupan del otro extremo: lo que emite, descrito
como lo quiere un modelo ambiental. CNOSSOS-EU da al tráfico viario y al
@@ -18,9 +23,15 @@ valora un aerogenerador por su potencia acústica aparente y su audibilidad
tonal. Lo que los une es el patrón: un descriptor de fuente cuidadosamente
normalizado que el modelo de camino de arriba atenúa después.
-Esta sección se apoya en el núcleo de la biblioteca más que ninguna otra: los
-niveles de valoración y el Lden en que termina la evaluación ambiental viven
-en [Niveles integrados y estadísticos](/phonometry/es/signals/levels/levels/), y la
+Esta sección se apoya en el núcleo de la biblioteca, pero solo hasta el nivel
+de periodo.
+[Niveles integrados y estadísticos](/phonometry/es/signals/levels/levels/)
+aporta el LAeq, los percentiles y los niveles de suceso de cada periodo de
+referencia; lo que convierte esos niveles de periodo en Lden, Ldn y el nivel de
+evaluación, con la corrección por tonalidad, la corrección por ruido residual y
+el presupuesto de incertidumbre encima, es
+[Niveles ambientales (ISO 1996-1/-2)](/phonometry/es/environment/assessment/environmental-levels/),
+en esta misma sección. La
absorción atmosférica que consume todo modelo de propagación se comparte con
las páginas de salas y materiales. Empieza por
[Propagación del sonido en exteriores](/phonometry/es/environment/propagation/outdoor-propagation/):
diff --git a/site/src/content/docs/es/environment/propagation/atmospheric-refraction.mdx b/site/src/content/docs/es/environment/propagation/atmospheric-refraction.mdx
index 1cb7410e3..8136eeecf 100644
--- a/site/src/content/docs/es/environment/propagation/atmospheric-refraction.mdx
+++ b/site/src/content/docs/es/environment/propagation/atmospheric-refraction.mdx
@@ -242,6 +242,10 @@ casos = [
]
fig, ax = plt.subplots(figsize=(11, 6.2))
with warnings.catch_warnings():
+ # El PorousAbsorberWarning: un suelo de 200 kPa.s/m2 hace trabajar al
+ # modelo de impedancia de un parámetro por debajo de su rango de ajuste
+ # publicado, como todo suelo exterior (ver «Elección de la impedancia del
+ # suelo» en la guía de efecto suelo).
warnings.simplefilter("ignore")
for perfil, etiqueta in casos:
pe = atmospheric_parabolic_equation(400.0, perfil, source_height=2.0,
@@ -305,6 +309,10 @@ axes[0].set(ylabel="Altura [m]", ylim=(0, 40), title="Rayos sonoros (refracción
axes[0].legend()
with warnings.catch_warnings():
+ # El PorousAbsorberWarning: un suelo de 200 kPa.s/m2 hace trabajar al
+ # modelo de impedancia de un parámetro por debajo de su rango de ajuste
+ # publicado, como todo suelo exterior (ver «Elección de la impedancia del
+ # suelo» en la guía de efecto suelo).
warnings.simplefilter("ignore")
pe = atmospheric_parabolic_equation(400.0, perfil, source_height=zs,
flow_resistivity=200e3,
diff --git a/site/src/content/docs/es/environment/propagation/ground-barriers.mdx b/site/src/content/docs/es/environment/propagation/ground-barriers.mdx
index 7ac3acfa0..5a50ffebd 100644
--- a/site/src/content/docs/es/environment/propagation/ground-barriers.mdx
+++ b/site/src/content/docs/es/environment/propagation/ground-barriers.mdx
@@ -47,6 +47,7 @@ references:
---
import ThemeImage from '../../../../../components/ThemeImage.astro';
+import Video from '../../../../../components/Video.astro';
El [método general ISO 9613-2](/phonometry/es/environment/propagation/outdoor-propagation/)
pliega los términos de suelo y barrera en correcciones tabuladas basadas en
@@ -167,6 +168,34 @@ tiende a ese suelo rígido; la incidencia rasante ($h_s, h_r \to 0$) da
$R_p \to -1$; y el efecto suelo es recíproco al intercambiar las alturas de
fuente y receptor.
+### Elección de la impedancia del suelo
+
+Ambos modelos de un parámetro se están evaluando muy **por debajo** de su
+rango de ajuste publicado para cualquier suelo exterior, y el
+`PorousAbsorberWarning` que emiten estas llamadas lo dice: el rango es
+$0{,}01 < X < 1$ con $X = \rho_0 f/\sigma$, y la pradera de arriba se sitúa en
+$X = 3{,}8\times10^{-4}$ a 63 Hz y 0,024 a 4 kHz; la curva del asfalto de la
+figura no llega a entrar en el rango en ningún punto. Por debajo del rango, la
+regresión de Delany-Bazley es una extrapolación cuyo fallo clásico es una parte
+real negativa de la impedancia de superficie; **Miki** es el reajuste con
+restricción de pasividad que conviene preferir ahí (ver el párrafo del rango de
+ajuste en [Absorbentes porosos](/phonometry/es/materials/absorbers/porous-absorbers/)).
+La elección no es cosmética: en el caso de arriba, `model="miki"` mueve la
+atenuación en exceso hasta 3,6 dB (banda de 250 Hz: 0,43 dB con Delany-Bazley,
+−3,18 dB con Miki).
+
+Resistividades al flujo **efectivas** típicas, los rangos que ilustra la figura
+de arriba: nieve reciente ≈ 10, suelo forestal ≈ 50, pradera y pasto
+≈ 150-300, tierra compactada y grava ≈ 1000-3000, asfalto y
+hormigón > 20 000 kPa·s/m².
+
+Para un emplazamiento real, $\sigma$ se ajusta a una medida de diferencia de
+niveles a corta distancia entre dos alturas de micrófono sobre la superficie
+(el método de plantillas de ANSI/ASA S1.18). El valor ajustado es un parámetro
+*efectivo y ligado al modelo*: hay que citarlo junto con el modelo de
+impedancia con el que se ajustó, y no es la resistividad al flujo de aire de
+EN 29053 del mismo material.
+
## 2. Difracción de barreras avanzada
`barrier_insertion_loss` y sus piezas dan tres niveles de apantallamiento más
@@ -185,6 +214,34 @@ $$
que tiende a 5 dB en el límite de sombra $N \to 0$ y aproxima la curva de
fuente puntual de Maekawa dentro de unos 1,5 dB.
+El clip de abajo es esa fórmula convertida en campo. Es el
+[solver FDTD 2D](/phonometry/es/simulation/fdtd-simulation/) ejecutado dos veces
+sobre un mismo semiespacio de 12 × 7 m sobre suelo rígido con una pantalla
+rígida delgada de 2,5 m de alto, una vez a 100 Hz y otra a 500 Hz, cada una con
+una simulación de referencia sin barrera sobre el mismo suelo para que la
+pérdida por inserción anotada sea una pérdida real. La geometría fija la
+diferencia de caminos en 1,06 m para el receptor que marca, así que el número
+de Fresnel es $N = 0{,}62$ a 100 Hz y $N = 3{,}1$ a 500 Hz (la misma pantalla,
+un factor cinco de diferencia en $N$ solo porque ha cambiado $\lambda$), y el
+campo enseña lo que eso compra: unos 8 dB frente a unos 17 dB. Hay dos cosas
+que merece la pena mirar. El borde de la región iluminada que baja desde lo
+alto de la pantalla es la frontera de sombra, el lugar geométrico $N \to 0$
+donde la fórmula toca fondo en 5 dB; y dentro de la sombra el campo es una onda
+cilíndrica centrada en lo alto de la pantalla, que es el aspecto que tiene «el
+borde actúa como fuente secundaria». Una advertencia: el suelo del clip es
+perfectamente rígido, así que muestra difracción sola y nada del efecto suelo
+de impedancia finita de la sección 1; el modelo coherente de cuatro caminos de
+más abajo sí lo añade, y su curva oscila decenas de decibelios donde esta es
+suave.
+
+
+
Los métodos de pantalla delgada comparten las mismas tres magnitudes
geométricas: los dos segmentos difractados sobre el borde y el camino recto
al que sustituyen. Dibujados sobre la pantalla de 4 m de los ejemplos,
diff --git a/site/src/content/docs/es/environment/propagation/outdoor-propagation.mdx b/site/src/content/docs/es/environment/propagation/outdoor-propagation.mdx
index 9e7af5e7e..1bcf01f0c 100644
--- a/site/src/content/docs/es/environment/propagation/outdoor-propagation.mdx
+++ b/site/src/content/docs/es/environment/propagation/outdoor-propagation.mdx
@@ -495,6 +495,25 @@ Devuelve un `OutdoorAttenuation` con `a_div`, `a_atm`, `a_gr`, `a_bar`,
`a_total` y `d_omega`, todos un valor por banda; su `.plot()` dibuja el
desglose apilado por bandas con el total superpuesto (la figura anterior).
+:::note
+**El método es solo de bandas de octava.** La ISO 9613-2 está definida para las
+ocho bandas de octava nominales de 63 Hz a 8 kHz, y su Tabla 3 no tiene más
+resolución, así que toda frecuencia que se pase se lleva a la *octava nominal
+más próxima* para el término de suelo, mientras que la divergencia y la
+absorción atmosférica siguen siendo continuas en frecuencia. Una llamada en
+tercios de octava devuelve por tanto un $A_{gr}$ escalonado, no uno más fino:
+en 400 / 500 / 630 / 800 Hz sobre suelo poroso a 100 m, `a_gr` sale como
+7,65 / 7,65 / 7,65 / 1,76 dB (tres bandas que comparten la octava de 500 Hz y
+luego la de 1 kHz), mientras que `a_atm` avanza suavemente por
+0,216 / 0,280 / 0,348 / 0,419 dB. Si hace falta un espectro más fino, conviene
+ejecutar la predicción en octavas y repartir después, o usar el `ground_effect`
+de acústica ondulatoria de
+[Efecto suelo y barreras](/phonometry/es/environment/propagation/ground-barriers/)
+cuando lo que importa es la estructura de interferencia dentro de una octava.
+Por debajo de 63 Hz o por encima de 8 kHz no hay cobertura alguna, de modo que
+una evaluación en baja frecuencia queda fuera de este método.
+:::
+
### Campos de `Barrier`
| Campo | Tipo | Unidades | Def. | Notas |
diff --git a/site/src/content/docs/es/environment/sources/cnossos-rail-emission.mdx b/site/src/content/docs/es/environment/sources/cnossos-rail-emission.mdx
index b5817c8c4..3680cc627 100644
--- a/site/src/content/docs/es/environment/sources/cnossos-rail-emission.mdx
+++ b/site/src/content/docs/es/environment/sources/cnossos-rail-emission.mdx
@@ -93,19 +93,25 @@ Directiva solo añade que, cuando una componente real queda entre las dos altura
del modelo, su energía se distribuye proporcionalmente entre ambas.
Para cada banda de tercio de octava, la ecuación de flujo convierte la potencia
-acústica de un vehículo en potencia por metro de línea (2.3.2) o, para un
-vehículo parado, en el equivalente al ralentí sobre el periodo de referencia
-(2.3.4):
+acústica de un vehículo en potencia por metro de línea (2.3.2):
$$
L'_{W,\mathrm{eq,line},i}(\psi,\varphi) = L_{W,0,\mathrm{dir},i}(\psi,\varphi)
+ 10\,\log_{10}\!\left(\frac{Q}{1000\,v}\right),
-\qquad
-+\,10\,\log_{10}\!\left(\frac{T_\mathrm{idle}}{T_\mathrm{ref}\,L}\right).
$$
-$Q$ va en vehículos por hora, $v$ en km/h y $L$ es la longitud del tramo de vía
-en metros. Atención a la unidad: el término de flujo usa km/h, mientras que la
+o, para un vehículo parado, la misma potencia direccional referida al tiempo al
+ralentí sobre el periodo de referencia (2.3.4):
+
+$$
+L'_{W,\mathrm{eq,line},i}(\psi,\varphi) = L_{W,0,\mathrm{dir},i}(\psi,\varphi)
+ + 10\,\log_{10}\!\left(\frac{T_\mathrm{idle}}{T_\mathrm{ref}\,L}\right).
+$$
+
+La segunda sustituye a la primera; no se suma a ella. $Q$ va en vehículos por
+hora, $v$ en km/h, $L$ es la longitud del tramo de vía en metros, y
+$T_\mathrm{idle}$ y $T_\mathrm{ref}$ comparten la unidad de tiempo en que se
+den. Atención a la unidad: el término de flujo usa km/h, mientras que la
conversión de rugosidad dos apartados más abajo usa m/s. Las dos son correctas,
y confundirlas es el error más caro disponible en este modelo.
diff --git a/site/src/content/docs/es/environment/sources/cnossos-road-emission.mdx b/site/src/content/docs/es/environment/sources/cnossos-road-emission.mdx
index b2e6b46be..662dff004 100644
--- a/site/src/content/docs/es/environment/sources/cnossos-road-emission.mdx
+++ b/site/src/content/docs/es/environment/sources/cnossos-road-emission.mdx
@@ -292,6 +292,7 @@ longitud $dL$ lleva simplemente $L'_{W,\mathrm{eq,line},i} + 10\log_{10}(dL)$, q
es aritmética y se ofrece como tal.
```python
+import numpy as np
from phonometry import (
PropagationGeometry, RoadTraffic, RoadVehicleCategory,
line_source_segment_power, predicted_receiver_level, road_source_power,
@@ -302,13 +303,40 @@ result = road_source_power([
RoadTraffic(RoadVehicleCategory.HEAVY, 120.0, 80.0),
])
segment = line_source_segment_power(result.total_line_power, 20.0) # tramo de 20 m
+
+# Un tramo, el que queda justo enfrente de un receptor a 100 m de la carretera.
levels = predicted_receiver_level(
segment,
PropagationGeometry(100.0, result.source_height, 4.0),
frequencies=result.frequencies,
)
+
+# La carretera es la suma energética de sus tramos: 1 km a cada lado, en pasos de 20 m.
+energy = np.zeros_like(levels)
+for x in np.arange(-990.0, 1000.0, 20.0): # centros de tramo a lo largo de la vía
+ energy += 10 ** (predicted_receiver_level(
+ segment,
+ PropagationGeometry(float(np.hypot(100.0, x)), result.source_height, 4.0),
+ frequencies=result.frequencies,
+ ) / 10)
+road = 10 * np.log10(energy)
```
+Dos reglas hacen defendible un troceado, y ninguna de las dos es método: el
+2.5.3 declara el reparto fuera de alcance, así que esto es práctica de
+ingeniería. Cada tramo tiene que ser bastante corto como para que la fuente
+puntual de su centro represente al tramo entero: la ISO 9613-2 solo admite una
+fuente puntual equivalente cuando la distancia de propagación supera el doble
+de la mayor dimensión de la fuente, de modo que un tramo visto desde 100 m
+puede medir decenas de metros y uno visto desde 10 m no. Y la carretera tiene
+que modelarse lo bastante lejos en ambos sentidos como para que las colas dejen
+de importar: más allá de unas diez veces la distancia perpendicular, añadir
+tramos cambia el total en menos de una décima de decibelio, y por eso 1 km a
+cada lado basta a 100 m aquí. Los dos espectros se leen en dB(A) dos párrafos
+más abajo: **52,9 dB(A)** para el tramo aislado frente a **64,7 dB(A)** para la
+carretera, una diferencia de 11,8 dB que es enteramente la aritmética de
+arriba.
+
Conviene ver qué es esto y qué no. CNOSSOS-EU tiene **su propio** método de
propagación en el apartado 2.5 del Anexo II, y no es la ISO 9613-2: difieren en
el modelo de suelo, en el tratamiento de la difracción y en la forma de combinar
@@ -324,6 +352,13 @@ from phonometry import CNOSSOS_A_WEIGHTING
CNOSSOS_A_WEIGHTING # (-26.2, -16.1, -8.6, -3.2, 0.0, 1.2, 1.0, -1.1)
result.a_weighted_line_power
+
+# Los dos espectros en el receptor del troceado de arriba, ponderados A:
+weight = np.asarray(CNOSSOS_A_WEIGHTING)
+print(round(float(10 * np.log10(np.sum(10 ** ((levels + weight) / 10)))), 1))
+# 52.9 dB(A) - un tramo de 20 m, no la carretera
+print(round(float(10 * np.log10(np.sum(10 ** ((road + weight) / 10)))), 1))
+# 64.7 dB(A) - la misma carretera, sumada sobre 2 km: 11.8 dB más
```
## 7. Sustituir por una base de datos nacional
diff --git a/site/src/content/docs/es/environment/sources/wind-turbine-noise.mdx b/site/src/content/docs/es/environment/sources/wind-turbine-noise.mdx
index c6f20cb99..1405a9ed6 100644
--- a/site/src/content/docs/es/environment/sources/wind-turbine-noise.mdx
+++ b/site/src/content/docs/es/environment/sources/wind-turbine-noise.mdx
@@ -22,7 +22,7 @@ references:
title: "Acoustics — Description, measurement and assessment of environmental noise — Part 2: Determination of sound pressure levels"
designation: "ISO 1996-2:2017"
url: "https://www.iso.org/standard/59766.html"
- note: "El criterio de audibilidad tonal que reutiliza el método IEC procede del anexo C de su edición de 2007 (la edición de 2017 lleva los métodos tonales en los anexos J y K), y su tonal_adjustment consume la audibilidad media."
+ note: "El criterio de audibilidad tonal que reutiliza el método IEC procede del anexo C de su edición de 2007 (la edición de 2017 lleva los métodos tonales en los anexos J y K), y su mapeo de la Tabla J.1, tonal_adjustment_from_mean_audibility, es el que consume la audibilidad media del intervalo."
---
import ThemeImage from '../../../../../components/ThemeImage.astro';
@@ -173,8 +173,20 @@ anclan a la
línea de tono clasificada más alta, no al candidato sondeado. La fórmula de
audibilidad coincide con la del Anexo C de la ISO 1996-2; lo específico de la
IEC 61400-11 es la determinación de los niveles de tono y enmascaramiento y la
-banda crítica de Zwicker a partir del espectro. Para un ajuste de valoración
-$K_T$, pasa la audibilidad media al `tonal_adjustment` de la ISO 1996-2.
+banda crítica de Zwicker a partir del espectro. La IEC 61400-11 se detiene en
+$\Delta L_a$ y no prescribe ningún ajuste, así que qué mapeo da el ajuste de
+valoración $K_t$ depende de la edición bajo la que se haga la evaluación. El
+promedio energético de 9.5.1 sobre los espectros de un intervalo de velocidad
+de viento es una audibilidad *media*, que es la magnitud para la que se
+escribió la Tabla J.1 de la ISO 1996-2:2017:
+[`tonal_adjustment_from_mean_audibility`](/phonometry/es/environment/assessment/environmental-levels/),
+entero de 0 a 6 dB (o `coarse=True` para la escala 0/3/6 de su nota). La ley a
+tramos (C.4)-(C.6) de `tonal_adjustment` es el mapeo del Anexo C de 2007 y se
+aplica al $\Delta L_{ta}$ de un único espectro, y las dos difieren entre 1 y
+2 dB con la misma entrada: $\Delta L = 5$ dB da $K_t = 3$ por la Tabla J.1 y
+1,0 dB por el Anexo C, y $\Delta L = 9$ dB da 4 dB y 5,0 dB. También difiere la
+notación: el $\Delta L_a$ de esta página es el $\Delta L_{ta}$ de aquella, y
+las dos impresiones llevan el criterio con signos opuestos.
### Informe de evaluación (`.report()`)
diff --git a/site/src/content/docs/es/materials/absorbers/absorption-measurement.mdx b/site/src/content/docs/es/materials/absorbers/absorption-measurement.mdx
index 7ec74973b..fc22f27ee 100644
--- a/site/src/content/docs/es/materials/absorbers/absorption-measurement.mdx
+++ b/site/src/content/docs/es/materials/absorbers/absorption-measurement.mdx
@@ -35,6 +35,7 @@ references:
import ThemeImage from '../../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../../components/ReportPreview.astro';
+import Video from '../../../../../components/Video.astro';
De todos los números que produce un laboratorio de materiales, el coeficiente
de absorción acústica es el que más lejos viaja: sale de la cámara
@@ -229,7 +230,28 @@ print(np.round(alpha, 3)) # [0.398 0.448 0.498]
$T_1$ y $T_2$ son exactamente los tiempos de reverberación que devuelve
[`room_parameters`](/phonometry/es/buildings/rooms/room-acoustics/), así que una medición de decaimiento ISO 3382-2 de la sala
-vacía y tratada fluye directamente a `absorption_coefficient`. Un volumen de
+vacía y tratada fluye directamente a `absorption_coefficient`.
+
+Cada uno de esos dos números se lee de un decaimiento, y el clip de abajo
+enseña cómo se lee uno: la respuesta al impulso al cuadrado se integra hacia
+atrás desde la cola, emerge la curva de Schroeder y las regresiones T20 y T30
+se ajustan a un tramo recto de ella. Esa es la operación que hay detrás de
+$T_1$, y otra vez detrás de $T_2$: el clip enseña una *única* sala, no el par,
+así que responde a «de dónde sale una $T$» y no a «qué cuesta restar dos de
+ellas». La segunda pregunta es la que gobierna esta medición, y la sección 4 le
+pone número: como $\alpha_s$ es una diferencia de dos inversos de tiempos de
+decaimiento, su incertidumbre es peor justo donde los dos decaimientos más se
+parecen, en el extremo de baja frecuencia.
+
+
+
+Un volumen de
sala por debajo del mínimo de 150 m³ o un área de muestra fuera de 10–12 m²
genera un `AbsorptionWarning` de aviso; el resultado se devuelve igualmente.
@@ -432,9 +454,18 @@ $$
\alpha_{st} = \int_0^{\pi/2} \alpha(\theta)\,\sin 2\theta\,\mathrm{d}\theta,
$$
-una integral que pondera sobre todo los ángulos oblicuos; evaluarla exige el
-$\alpha(\theta)$ dependiente del ángulo a partir de la impedancia superficial
-medida, no solo el propio coeficiente a incidencia normal.
+una integral que pondera sobre todo los ángulos oblicuos. Necesita el
+$\alpha(\theta)$ dependiente del ángulo, no el propio coeficiente a incidencia
+normal; pero para una superficie de **reacción local** el $\alpha(\theta)$ se
+deduce solo de la impedancia superficial normalizada, así que la integral tiene
+forma cerrada y un resultado de tubo se convierte en una línea:
+`materials.statistical_absorption(result.normalized_impedance)`, documentada
+con los
+[modelos multicapa](/phonometry/es/materials/absorbers/porous-absorbers/#4-incidencia-oblicua-y-aleatoria).
+Lo que eso no puede hacer es cubrir una capa de **reacción volumétrica**, donde
+el comportamiento oblicuo depende de la refracción dentro del material y la
+integral hay que evaluarla ángulo a ángulo a partir de un modelo:
+`diffuse_field_absorption`, en la misma página.
**Por qué los valores de ISO 354 superan 1.** Un cociente de energía absorbida
sobre incidente no puede superar la unidad y, sin embargo, los informes de
@@ -560,12 +591,13 @@ de octava y prácticos y para las valoraciones de número único, en
`sound_absorption_coefficient_uncertainty`,
`weighted_coefficient_uncertainty` y `single_number_rating_uncertainty`.
-**No cubierto.** El coeficiente de absorción estadístico (a incidencia
-aleatoria) $\alpha_{st}$ del promedio angular de Paris se describe pero no se
-calcula: necesita el $\alpha(\theta)$ dependiente del ángulo a partir de la
-impedancia superficial, que el
-[tubo de impedancia](/phonometry/es/materials/absorbers/impedance-tube/) recupera y nada
-aquí consume. Los requisitos de cualificación de la sala de ISO 354 (Anexo A:
+**No cubierto.** Nada de *esta* página consume una impedancia superficial
+medida: la conversión de un resultado de tubo al coeficiente estadístico
+$\alpha_{st}$ vive con los modelos de predicción (`statistical_absorption` para
+una superficie de reacción local, `diffuse_field_absorption` para una de
+reacción volumétrica), y ninguno de los dos sustituye a una medición según
+ISO 354, porque ninguno reproduce el efecto de borde. Los requisitos de
+cualificación de la sala de ISO 354 (Anexo A:
número de posiciones de altavoz y micrófono, elementos difusores) no se
comprueban; `absorption_area`/`absorption_coefficient` solo convierten una
pareja $T_1$/$T_2$ ya medida y emiten un aviso cuando el volumen de la sala o
@@ -593,6 +625,6 @@ lo está.
$\alpha_s$.
- [Área de absorción equivalente de recintos amueblados](/phonometry/es/buildings/rooms/enclosed-space-absorption/):
el presupuesto de absorción EN 12354-6 que alimentan estos coeficientes.
-- [Medición y valoración del aislamiento in situ](/phonometry/es/buildings/insulation/insulation-field/):
+- [Medición del aislamiento en campo (ISO 16283)](/phonometry/es/buildings/insulation/insulation-field/):
la norma de incertidumbre hermana del aislamiento acústico, ISO 12999-1.
- Referencia de la API: [`materials.absorbers.sound_absorption`](/phonometry/es/reference/api/materials/sound-absorption/), [`materials.absorbers.rating`](/phonometry/es/reference/api/materials/rating/) y [`materials.absorbers.uncertainty`](/phonometry/es/reference/api/materials/uncertainty/).
diff --git a/site/src/content/docs/es/materials/absorbers/impedance-tube.mdx b/site/src/content/docs/es/materials/absorbers/impedance-tube.mdx
index 3bd446767..7fb8d52a8 100644
--- a/site/src/content/docs/es/materials/absorbers/impedance-tube.mdx
+++ b/site/src/content/docs/es/materials/absorbers/impedance-tube.mdx
@@ -386,19 +386,46 @@ figura que incrusta la ficha, matplotlib (`pip install
genera en inglés por defecto; pasa `language="es"` para una ficha en español
(cadenas fijas traducidas y coma decimal).
+El bloque de abajo es la probeta de la ficha que va debajo: una capa resistiva
+de resistencia al flujo normalizada $\theta = 1$ sobre una cavidad de aire de
+86 mm con respaldo rígido, cuya impedancia superficial
+$z = \theta - \mathrm{j}\cot(k_0 L)$ se conoce en forma cerrada, así que el
+$\alpha$ impreso se puede comprobar a mano: 1,00 en la resonancia de cuarto de
+onda de 1 kHz, donde la lámina adaptada da $z = 1$ y $r = 0$; 0,80 a 500 Hz,
+donde $k_0 L = \pi/4$ y $z = 1 - \mathrm{j}$.
+
```python
+import numpy as np
from phonometry import materials, ReportMetadata
-result = materials.two_microphone_impedance(
- h12, frequency=freqs, spacing=0.05, x1=0.10,
- speed_of_sound=c0, characteristic_impedance=rho_c, diameter=0.10,
+# Tubo de 100 mm, s = 50 mm, micrófono lejano en x1 = 100 mm, 20 degC / 101 kPa.
+c0 = float(materials.speed_of_sound_iso(293.15)) # 343.29 m/s
+rho_c = materials.characteristic_impedance(
+ float(materials.air_density_iso(293.15, 101.0)), c0) # 405.6 Pa.s/m
+diameter, spacing, x1 = 0.100, 0.050, 0.100
+theta, cavity = 1.0, c0 / (4.0 * 1000.0) # cuarto de onda a 1 kHz: 86 mm
+freqs = np.array([400, 500, 630, 800, 1000, 1250, 1600], dtype=float)
+
+# La función de transferencia que mediría el tubo, sintetizada desde la r conocida.
+k0 = materials.tube_wavenumber(freqs, c0)
+z = theta - 1j / np.tan(2 * np.pi * freqs / c0 * cavity)
+r_known = (z - 1.0) / (z + 1.0)
+x2 = x1 - spacing
+h12_fiche = (np.exp(1j*k0*x2) + r_known*np.exp(-1j*k0*x2)) / \
+ (np.exp(1j*k0*x1) + r_known*np.exp(-1j*k0*x1))
+
+fiche = materials.two_microphone_impedance(
+ h12_fiche, frequency=freqs, spacing=spacing, x1=x1,
+ speed_of_sound=c0, characteristic_impedance=rho_c, diameter=diameter,
)
-result.report(
+print(np.round(fiche.absorption, 2)) # [0.68 0.8 0.9 0.97 1. 0.96 0.68]
+
+fiche.report(
"alpha_fiche.pdf",
metadata=ReportMetadata(
specimen="Capa resistiva sobre cavidad de aire de 86 mm con respaldo rígido",
- tube_diameter=0.10, # m (se imprime como 100 mm)
- mic_spacing=0.05, # m (se imprime como 50 mm)
+ tube_diameter=diameter, # m (se imprime como 100 mm)
+ mic_spacing=spacing, # m (se imprime como 50 mm)
measurement_standard="ISO 10534-2",
laboratory="Phonometry Reference Laboratory",
),
diff --git a/site/src/content/docs/es/materials/absorbers/metamaterial-absorbers.mdx b/site/src/content/docs/es/materials/absorbers/metamaterial-absorbers.mdx
index 83f62310c..1cb3c3bed 100644
--- a/site/src/content/docs/es/materials/absorbers/metamaterial-absorbers.mdx
+++ b/site/src/content/docs/es/materials/absorbers/metamaterial-absorbers.mdx
@@ -70,9 +70,11 @@ absorción útil donde la capa es una fracción apreciable de la longitud de
onda, lo que a 300 Hz significa decenas de centímetros. Los absorbentes de
metamaterial acústico rompen esa regla con resonancia en lugar de volumen. Un
panel rígido de ranuras finas cerradas, cada una cargada con resonadores de
-Helmholtz, ralentiza el sonido dentro de la ranura hasta que un panel de 3 cm
-resuena donde una cavidad simple de la misma profundidad tendría que ser diez
-veces más honda, y sintonizar las pérdidas internas del panel contra su fuga
+Helmholtz, ralentiza el sonido dentro de la ranura de forma tan drástica que un
+panel de 3 cm resuena en torno a 300 Hz, donde una cavidad vacía de cuarto de
+onda tendría que ser diez veces más honda, ya que 3 cm de aire simple resuenan
+a 2,9 kHz (sección 3). Sintonizar entonces las pérdidas internas del panel
+contra su fuga
produce **absorción perfecta**, $\alpha = 1$, a una frecuencia de diseño en la
que el panel solo tiene $\lambda/38$ de profundidad; diseños publicados de la
misma familia llegan a $\lambda/88$ (Jiménez et al. 2016). Esta guía cubre la
diff --git a/site/src/content/docs/es/materials/absorbers/porous-absorbers.mdx b/site/src/content/docs/es/materials/absorbers/porous-absorbers.mdx
index fc7256cf9..83236f85e 100644
--- a/site/src/content/docs/es/materials/absorbers/porous-absorbers.mdx
+++ b/site/src/content/docs/es/materials/absorbers/porous-absorbers.mdx
@@ -688,7 +688,31 @@ interacción de la función de Fok
$\delta = 0{,}85\,(1 - 1{,}47\sqrt{\varepsilon} + 0{,}47\varepsilon^{3/2})$
(tabla 7.1), válido para cualquier área abierta. Para una cámara poco
profunda la resonancia es
-$f_0 = (c_0/2\pi)\sqrt{\varepsilon/(t'\,d)}$ (ec. 7.4).
+$f_0 = (c_0/2\pi)\sqrt{\varepsilon/(t'\,d)}$ (ec. 7.4). En esas dos
+expresiones, $t$ es el espesor de la placa, $a$ el **radio** del orificio,
+$\varepsilon$ el área abierta (área de orificios sobre área de panel), $\nu$ la
+viscosidad cinemática del aire, $t' = t + 2\delta a$ el espesor de placa con
+corrección de extremo y $d$ la profundidad de la cámara tras el panel.
+
+### Las clases de lámina: parámetros
+
+Las tres láminas toman argumentos posicionales, y la dimensión del orificio es
+un **radio**, no un diámetro: la mitad del orificio taladrado. Equivocarse ahí
+calcula la resonancia y la absorción de pico de un orificio del doble del
+tamaño real.
+
+| Clase | Parámetro | Unidades | Notas |
+| :--- | :--- | :--- | :--- |
+| `PerforatedPlateLayer` | `thickness` | m | Espesor de la placa $t$ |
+| | `hole_radius` | m | **Radio** del orificio $a$, la mitad del diámetro taladrado |
+| | `open_area` | — | Razón de perforación $\varepsilon$ = área de orificios / área de panel |
+| | `end_correction` | — | $\delta$ por extremo de orificio; `None` usa el ajuste de interacción de Fok |
+| `MicroperforatedPlateLayer` | `thickness` | m | Espesor de la placa $t$ |
+| | `hole_radius` | m | **Radio** del orificio $a$ |
+| | `open_area` | — | Razón de perforación $\varepsilon$ |
+| | `end_correction` | — | Por defecto `0.85`, la reactancia de pistón de Maa |
+| `MembraneLayer` | `surface_density` | kg/m² | Masa por unidad de superficie $m$ |
+| | `resistance` | Pa·s/m | Resistencia al flujo añadida; por defecto `0.0` |
**Panel microperforado (MPP).** Con orificios submilimétricos la capa
límite viscosa llena el orificio y el panel absorbe *sin ningún material
@@ -713,7 +737,8 @@ $f_2/f_1 = \pi/\mathrm{arccot}(1+r) - 1$ (Maa, ecs. 9–21, tabla I).
import numpy as np
from phonometry import materials
-# Maa (1998), fig. 5: d = t = 0,2 mm, orificios cada 2,5 mm, cámara de 6 cm.
+# Maa (1998), fig. 5: diámetro de orificio 0,2 mm (o sea hole_radius = 0,1 mm),
+# placa de 0,2 mm de espesor, orificios cada 2,5 mm, cámara de 6 cm.
eps = (np.pi / 4.0) * (0.2 / 2.5) ** 2
f = np.linspace(100.0, 4000.0, 2000)
res = materials.layered_absorber(
@@ -743,7 +768,8 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import materials
-# Maa (1998), fig. 5: d = t = 0,2 mm, orificios cada 2,5 mm, cámara de 6 cm.
+# Maa (1998), fig. 5: diámetro de orificio 0,2 mm (o sea hole_radius = 0,1 mm),
+# placa de 0,2 mm de espesor, orificios cada 2,5 mm, cámara de 6 cm.
eps = (np.pi / 4.0) * (0.2 / 2.5) ** 2
f = np.linspace(100.0, 4000.0, 1200)
res = materials.layered_absorber(
diff --git a/site/src/content/docs/es/materials/diffusers/diffusers.mdx b/site/src/content/docs/es/materials/diffusers/diffusers.mdx
index b9cdc785c..2f538c940 100644
--- a/site/src/content/docs/es/materials/diffusers/diffusers.mdx
+++ b/site/src/content/docs/es/materials/diffusers/diffusers.mdx
@@ -81,14 +81,32 @@ dispersan como pozos de decenas de centímetros, tienen su propia guía:
## 1. Coeficiente de dispersión de incidencia aleatoria (ISO 17497-1)
El coeficiente de dispersión $s$ es la fracción de energía reflejada que **no**
-abandona la superficie en la dirección especular. ISO 17497-1 lo mide en una cámara
-reverberante a partir de cuatro situaciones de tiempo de reverberación: con la
-muestra de ensayo montada sobre una plataforma giratoria y mantenida
-**inmóvil**, y con la plataforma **en rotación** (que promedia y elimina la
-reflexión especular coherente en fase), cada una con y sin una placa base
-reflectante.
-
-
+abandona la superficie en la dirección especular. ISO 17497-1 lo mide en una
+cámara reverberante a partir de cuatro tiempos de reverberación. La plataforma
+giratoria y su placa base circular rígida permanecen en la sala en los cuatro
+casos, simétricas respecto al eje de rotación y dimensionadas a la muestra; lo
+que cambia es si la **muestra de ensayo** está sobre la placa y si la placa
+**gira** (Tabla 2):
+
+| | Muestra de ensayo | Plataforma giratoria |
+| :--- | :--- | :--- |
+| $T_1$ | ausente | sin girar |
+| $T_2$ | presente | sin girar |
+| $T_3$ | ausente | girando |
+| $T_4$ | presente | girando |
+
+$(T_1, T_2)$ es una medición de absorción ISO 354 corriente de la probeta y da
+el $\alpha_s$ de incidencia aleatoria; $(T_3, T_4)$ la repite bajo rotación y
+da el $\alpha_{spec}$ especular. El área $S$ de ambas fórmulas es el área de la
+**probeta**, no la de la placa base. La pareja $(T_1, T_3)$ tampoco se
+desperdicia: es la comprobación de calidad de la placa base de la ec. (6), más
+abajo.
+
+Comprobación de coherencia antes de calcular nada: añadir la muestra siempre
+acorta el decaimiento, así que $T_2 < T_1$ y $T_4 < T_3$. Un coeficiente de
+absorción negativo significa que los miembros de una pareja entraron al revés.
+
+
**Absorción a partir del tiempo de reverberación (cláusula 6).** Cada situación se
convierte en un coeficiente de absorción de Sabine con el propio término de
@@ -101,9 +119,10 @@ $$
donde $V$ es el volumen de la sala, $S$ el área de la muestra, $T$ el tiempo de
reverberación, $c$ la velocidad del sonido (ec. (2): $c = 343{,}2\sqrt{(273{,}15+t)/293{,}15}$)
-y $m$ el coeficiente de atenuación en potencia del aire. El par **inmóvil** da la
-absorción de incidencia aleatoria $\alpha_s$ (ec. (1)); el par **en rotación** da
-la absorción especular $\alpha_{spec}$ (ec. (4)).
+y $m$ el coeficiente de atenuación en potencia del aire. El par **inmóvil**
+$(T_1, T_2)$ da la absorción de incidencia aleatoria $\alpha_s$ (ec. (1)); el
+par **en rotación** $(T_3, T_4)$ da la absorción especular $\alpha_{spec}$
+(ec. (4)).
**Coeficiente de dispersión (ec. (5)).** Ambos se combinan en
@@ -121,11 +140,13 @@ from phonometry import materials
# Cuatro situaciones de tiempo de reverberación reducidas a dos coeficientes de absorción.
# alpha_s del par inmóvil (ec. 1); alpha_spec del par en rotación (ec. 4).
-# V = 200 m^3, S = 10 m^2, c = 343.2 m/s en todo momento.
-alpha_s = materials.random_incidence_absorption(200.0, 10.0, c1=343.2, t1=8.0,
- c2=343.2, t2=6.0)
-alpha_spec = materials.specular_absorption_coefficient(200.0, 10.0, c3=343.2, t3=7.5,
- c4=343.2, t4=5.0)
+# V = 200 m^3, S = 10 m^2 (el área de la MUESTRA), c = 343.2 m/s en todo momento.
+alpha_s = materials.random_incidence_absorption(200.0, 10.0,
+ c1=343.2, t1=8.0, # T1 placa base, inmóvil
+ c2=343.2, t2=6.0) # T2 muestra, inmóvil
+alpha_spec = materials.specular_absorption_coefficient(200.0, 10.0,
+ c3=343.2, t3=7.5, # T3 placa base, en rotación
+ c4=343.2, t4=5.0) # T4 muestra, en rotación
s = materials.scattering_coefficient(alpha_spec, alpha_s) # ec. (5)
print(round(float(alpha_s), 4)) # 0.1343
print(round(float(alpha_spec), 4)) # 0.2148
@@ -141,8 +162,8 @@ import numpy as np
from phonometry import materials
# Una medición de 13 bandas (250-4000 Hz): la absorción de incidencia aleatoria
-# alpha_s (muestra inmóvil) y la absorción especular alpha_spec (plataforma en
-# rotación). Un difusor dispersa más con la frecuencia, así que s(f) crece.
+# alpha_s (muestra sobre la plataforma inmóvil) y la absorción especular alpha_spec
+# (plataforma en rotación). Un difusor dispersa más con la frecuencia, así que s(f) crece.
freqs = np.array([250, 315, 400, 500, 630, 800, 1000,
1250, 1600, 2000, 2500, 3150, 4000], float)
alpha_s = np.full_like(freqs, 0.10)
@@ -169,8 +190,8 @@ import numpy as np
from phonometry import materials
# Una medición de 13 bandas (250-4000 Hz): la absorción de incidencia aleatoria
-# alpha_s (muestra inmóvil) y la absorción especular alpha_spec (plataforma en
-# rotación). Un difusor dispersa más con la frecuencia, así que s(f) crece.
+# alpha_s (muestra sobre la plataforma inmóvil) y la absorción especular alpha_spec
+# (plataforma en rotación). Un difusor dispersa más con la frecuencia, así que s(f) crece.
freqs = np.array([250, 315, 400, 500, 630, 800, 1000,
1250, 1600, 2000, 2500, 3150, 4000], float)
alpha_s = np.full_like(freqs, 0.10)
@@ -248,9 +269,25 @@ $$
Una respuesta polar perfectamente uniforme ($L_i$ todos iguales) da $d = 1$; un
único lóbulo especular agudo da $d = 0$. Cuando los receptores subtienden ángulos
-sólidos desiguales, la fórmula (6) pondera por área cada energía con $N_i$ de la
-fórmula (8), y esos factores de área se evalúan en **radianes**, razón por la que
-un espaciado de 5° en el cenit produce un peso cercano a 1,57, no a 51,9.
+sólidos desiguales, la fórmula (6) pondera por área cada energía con
+$N_i = A_i / A_\text{min}$ de la fórmula (8), con
+
+$$
+A_i = \frac{4\pi}{\Delta\phi}\sin^2\frac{\Delta\theta}{4}\ (\theta = 0),
+\qquad
+A_i = 2\sin\theta\,\sin\frac{\Delta\theta}{2}\ (0 < \theta < 90°),
+\qquad
+A_i = \sin\frac{\Delta\theta}{2}\ (\theta = 90°).
+$$
+
+Todos los ángulos de esas tres formas se manejan en **radianes**, incluido el
+$\Delta\phi$ bajo el $4\pi$ del término del cenit: eso es lo que mantiene el
+cenit dimensionalmente coherente con los otros dos. En el hemisferio estándar
+de 5° × 5° las áreas salen 0,0685 en el cenit, 0,0076 en $\theta = 5°$ (la
+menor, así que $A_\text{min}$) y 0,0436 en el polo, de modo que los pesos van
+9,01 en el cenit, 1 en el primer anillo contiguo y 5,74 en el polo. Conviene
+comprobar los propios con `materials.area_factors(elevations, delta_theta=5.0)`
+antes de meter un vector de pesos construido a mano en la fórmula (6).
El montaje que asumen esas fórmulas merece dibujarse a escala.
`plot_goniometer_geometry` traza la disposición estándar en planta: el
@@ -284,6 +321,14 @@ difusor de Schroeder (un perfil de residuos cuadráticos con $N = 7$), y la
energía dispersada sobre el arco de receptores convierte un haz especular
colimado ($d = 0{,}32$) en un abanico ancho ($d = 0{,}63$).
+Esos dos números no son comparables con los coeficientes que se calculan más
+abajo. Los paneles simulados son un único periodo corto leído en el campo
+próximo de una malla 2D; la predicción que sigue es un array de seis periodos y
+3,6 m leído en campo lejano, donde la periodicidad encauza la energía hacia unos
+pocos lóbulos de red y hunde todos los coeficientes. Los coeficientes de
+difusión solo se comparan dentro de una misma geometría, un mismo arco y una
+misma distancia, que es justo lo que fija la ISO 17497-2 con los tres.
+
diff --git a/site/src/content/docs/es/materials/resilient/dynamic-stiffness.mdx b/site/src/content/docs/es/materials/resilient/dynamic-stiffness.mdx
index 7136e33a8..b13ead6e1 100644
--- a/site/src/content/docs/es/materials/resilient/dynamic-stiffness.mdx
+++ b/site/src/content/docs/es/materials/resilient/dynamic-stiffness.mdx
@@ -47,7 +47,8 @@ from phonometry import materials
res = materials.floating_floor_resonance(
resonant_frequency=25.0, total_mass_per_area=200.0,
floor_mass_per_area=120.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 de la ISO 9053)
+ thickness=0.020, porosity=0.9,
)
res.plot(language="es")
plt.show()
@@ -150,6 +151,19 @@ $r \ge 100\ \text{kPa}\cdot\text{s/m}^2$, $s' = s'_t + s'_a$ para
$10 \le r < 100\ \text{kPa}\cdot\text{s/m}^2$, y para
$r < 10\ \text{kPa}\cdot\text{s/m}^2$ el método solo resuelve $s' = s'_t$
cuando el término del gas es despreciable.
+
+**Ojo al prefijo.** $r$ es la magnitud que la ISO 9053 llama $\sigma$ y reporta
+en Pa·s/m², mientras que la EN 29052-1 la escribe $r$ y pone sus umbrales en
+**kPa·s/m²**. La biblioteca sigue a la norma, así que `airflow_resistivity` va
+en kPa·s/m²: el único argumento de esta página que no está en SI puro. Una lana
+mineral medida en 50 000 Pa·s/m² entra como `50.0`, no como `50000.0`; un
+[resultado de ISO 9053](/phonometry/es/materials/absorbers/airflow-resistance/)
+se convierte con `sigma / 1000`. Pasar el número en Pa·s/m² cae en silencio en
+la rama $r \ge 100$, que descarta el término del gas encerrado: para la
+determinación de abajo eso convierte $s' = 10{,}49$ MN/m³ en 4,93 MN/m³ y la
+frecuencia natural de diseño de 47,1 Hz en 32,3 Hz, sin ningún aviso, porque la
+rama equivocada es una rama válida.
+
`floating_floor_resonance` encadena toda la determinación:
```python
@@ -158,7 +172,8 @@ from phonometry import materials
res = materials.floating_floor_resonance(
resonant_frequency=25.0, total_mass_per_area=200.0,
floor_mass_per_area=120.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 de la ISO 9053)
+ thickness=0.020, porosity=0.9,
)
print(round(res.dynamic_stiffness / 1e6, 2), round(res.natural_frequency, 1))
# 10.49 47.1
@@ -193,7 +208,8 @@ from phonometry import ReportMetadata, materials
res = materials.floating_floor_resonance(
resonant_frequency=45.0, total_mass_per_area=200.0,
floor_mass_per_area=110.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 de la ISO 9053)
+ thickness=0.020, porosity=0.9,
)
res.report(
"dynamic_stiffness.pdf",
@@ -260,7 +276,9 @@ por métodos sinusoidal, de ruido blanco o de impulso y la extrapola a
amplitud de fuerza nula, no está implementado: pasa una $f_r$ ya extrapolada.
La resistividad al flujo lateral $r$ de la cláusula 8.2 también se toma como
entrada en lugar de medirse; los métodos estático y alterno de la ISO 9053
-están implementados aparte, en `materials.absorbers.airflow_resistance`. El requisito
+están implementados aparte, en `materials.absorbers.airflow_resistance`, y
+reportan $\sigma$ en Pa·s/m² mientras que el argumento `airflow_resistivity` de
+esta página va en kPa·s/m². El requisito
de selección de probetas de la cláusula 6 (al menos tres probetas de
200 mm × 200 mm) no se aplica.
diff --git a/site/src/content/docs/es/materials/surfaces/road-absorption.mdx b/site/src/content/docs/es/materials/surfaces/road-absorption.mdx
index 45d55d467..e59a3db44 100644
--- a/site/src/content/docs/es/materials/surfaces/road-absorption.mdx
+++ b/site/src/content/docs/es/materials/surfaces/road-absorption.mdx
@@ -266,21 +266,35 @@ $$
con $d$ el diámetro del tubo, y el espaciado de micrófonos $s$ debe situarse entre
$0{,}05\,c_0/f_{min}$ y $0{,}45\,c_0/f_{max}$. El rango informado son las bandas de
-tercio de octava de 250 a 1600 Hz.
+tercio de octava de 250 a 1600 Hz y, como la propia norma define un rango de
+frecuencia por los *bordes* de banda, esas frecuencias centrales significan de
+220 Hz a 1800 Hz en banda estrecha, que es de donde salen los dos argumentos de
+abajo.
```python
from phonometry import materials
# Frecuencia superior utilizable de un tubo de 100 mm y la ventana de espaciado válida.
print(round(materials.spot_tube_upper_frequency(0.100, 343.0), 1)) # 1989.4 Hz
+# 220 Hz y 1800 Hz son los bordes exteriores de las bandas de 250 Hz y 1600 Hz.
s_min, s_max = materials.spot_microphone_spacing_bounds(
343.0, f_min=220.0, f_max=1800.0)
print(round(s_min, 3), round(s_max, 3)) # 0.078 0.086 (metros)
```
-La ventana de frecuencia es el precio de la portabilidad: el diámetro de tubo
-que mantiene la boca sellable sobre pavimento real limita las bandas altas a
-1600 Hz, y la longitud del tubo limita las bajas a 250 Hz, una ventana más
+Tres números, tres límites distintos, y sí se reconcilian. Los 1989 Hz son el
+techo de onda plana del calibre de 100 mm; el rango informado se detiene una
+banda por debajo porque una banda solo es utilizable cuando *toda* su anchura
+cae dentro del rango válido, y la banda de 1600 Hz llega hasta 1800 Hz. El
+suelo de 250 Hz es un límite de **espaciado**, no de longitud: por debajo de
+$f_{min}$ los dos micrófonos están a menos del 5 % de una longitud de onda uno
+de otro y no queda diferencia de fase que resolver. La longitud del tubo
+responde a otra pregunta: tiene que ser suficiente para que se forme una onda
+plana, lo que la cláusula 5.4.2 consigue poniendo los micrófonos al menos a
+$3d$ de la fuente (una longitud mínima de 480 mm para el tubo de 100 mm). La
+ventana de espaciado resultante, de 78 mm a 86 mm aquí, es la razón de que la
+norma especifique $(81 \pm 4)$ mm para una única pareja de micrófonos. Es una
+ventana más
estrecha que los 250–4000 Hz de la técnica de sustracción. Dentro de ella, la
reducción es la cadena de ISO 10534-2 sin cambios: la función de
transferencia entre los dos micrófonos separa las ondas incidente y
diff --git a/site/src/content/docs/es/perception/hearing/occupational-exposure.mdx b/site/src/content/docs/es/perception/hearing/occupational-exposure.mdx
index 308093c84..439783aab 100644
--- a/site/src/content/docs/es/perception/hearing/occupational-exposure.mdx
+++ b/site/src/content/docs/es/perception/hearing/occupational-exposure.mdx
@@ -54,8 +54,13 @@ en energía.
Describe cada actividad como una `hearing.Task` con sus muestras y su duración
y llama a `hearing.task_based_exposure(tasks)`. Para la jornada del soldador
-del anexo D que se usa abajo devuelve `lex_8h` = 84,3 dB con una incertidumbre
-expandida $U = 2{,}7$ dB, así que el `upper_limit` unilateral al 95 % es 87,0 dB.
+del anexo D que se usa abajo devuelve `lex_8h` = 84,3 dB con una
+`expanded_uncertainty` $U = 3{,}2$ dB, así que el `upper_limit` unilateral al
+95 % es 87,5 dB, porque por defecto se incluye el término de duración $u_{1b}$
+del anexo C construido a partir del `duration_range` de cada tarea. El
+fragmento del apartado 1 pasa `include_duration_uncertainty=False` para
+reproducir el caso a del anexo D, donde las duraciones se tratan como exactas,
+y eso es lo que baja $U$ a 2,7 dB y el límite superior a 87,0 dB.
Las jornadas sin estructura usan `job_based_exposure()` o `full_day_exposure()`
sobre muestras aleatorias.
@@ -71,8 +76,11 @@ $$
de modo que una tarea ruidosa pero corta contribuye poco. Las estrategias
*basadas en la función* (apartado 10) y *de jornada completa* (apartado 11) toman
-en cambio $N \ge 5$ (o tres jornadas completas) muestras aleatorias sobre un grupo
-de exposición homogéneo y normalizan la duración efectiva de la jornada. El nivel
+en cambio muestras aleatorias sobre un grupo de exposición homogéneo — $N \ge 5$
+muestras para la estrategia basada en la función, al menos tres turnos completos
+para la de jornada completa —, las promedian en energía y normalizan ese promedio
+a la jornada nominal de ocho horas con la duración efectiva de la jornada $T_e$
+en el mismo término $10\log_{10}(T_e/T_0)$. El nivel
diario es el mismo en ambos casos; las estrategias difieren en cómo se construye
la **incertidumbre**.
diff --git a/site/src/content/docs/es/perception/psychoacoustics/advanced-loudness.mdx b/site/src/content/docs/es/perception/psychoacoustics/advanced-loudness.mdx
index e7a4a2c54..9241f6251 100644
--- a/site/src/content/docs/es/perception/psychoacoustics/advanced-loudness.mdx
+++ b/site/src/content/docs/es/perception/psychoacoustics/advanced-loudness.mdx
@@ -304,7 +304,25 @@ print(f"sonoridad de largo plazo superada el 5% del tiempo: {res.percentiles[5.0
res.plot() # sonoridad de corto plazo S'(t) y de largo plazo S''(t) frente al tiempo
```
-
+La sonoridad de corto plazo sube en unas pocas decenas de milisegundos y cae
+despacio, imitando la sensibilidad rápida del oído al ataque y su recuperación
+más lenta; la de largo plazo vuelve a integrar esa traza con una constante de
+tiempo mucho mayor, así que apenas reacciona a una sílaba suelta y sigue en
+cambio el nivel global de un suceso. El máximo de esa traza lenta,
+$N_\text{max}$, es el predictor que la norma da para la sonoridad de un
+sonido breve, y su validez se acaba hacia los 5 s porque más allá el oyente
+deja de juzgar el sonido como un único suceso. Por eso mismo los percentiles
+van a su lado: para un sonido que fluctúa sin una estructura clara de sucesos,
+un percentil de la sonoridad de largo plazo (típicamente el valor al 5 %) es el
+estadístico estable, donde $N_\text{max}$ lo fijaría el único peor instante.
+
+
+
+*Un pulso de 200 ms a 1 kHz y 60 dB SPL: la sonoridad de corto plazo alcanza
+4,8 sone en unas pocas decenas de milisegundos y se relaja deprisa, mientras la
+de largo plazo integra hasta 3,6 sone y decae lentamente tras el final del
+pulso; el par de constantes de tiempo que definen las cláusulas 7.8/7.9 de
+ISO 532-3.*
Mostrar el código de esta figura
@@ -314,22 +332,19 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
-fs = 32000
-t = np.arange(int(1.3 * fs)) / fs
-x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)
-res = psychoacoustics.loudness_moore_glasberg_time(x, fs, field="free")
+# La figura es un pulso, no un tono estacionario: 1 kHz a 60 dB SPL, abierto
+# entre los 200 y los 400 ms de un registro de 0,8 s.
+fs = 48000
+t = np.arange(int(0.8 * fs)) / fs
+sig = np.zeros_like(t)
+on = (t >= 0.2) & (t < 0.4)
+sig[on] = np.sqrt(2) * 2e-5 * 10 ** (60 / 20) * np.sin(2 * np.pi * 1000 * t[on])
+burst = psychoacoustics.loudness_moore_glasberg_time(sig, fs)
+print(round(float(burst.short_term_loudness.max()), 1),
+ round(float(burst.long_term_loudness.max()), 1)) # 4.8 3.6
# El resultado lleva ambas trazas sobre un eje temporal de 1 ms:
-res.plot(language="es")
-plt.show()
-
-# O dibújalas directamente para ver la STL rápida frente a la LTL lenta:
-fig, ax = plt.subplots()
-ax.plot(res.time, res.short_term_loudness, label="Corto plazo S'(t)")
-ax.plot(res.time, res.long_term_loudness, label="Largo plazo S''(t)")
-ax.set_xlabel("Tiempo [s]")
-ax.set_ylabel("Sonoridad [sone]")
-ax.legend()
+burst.plot(language="es")
plt.show()
```
@@ -375,7 +390,12 @@ print(res.specific_loudness.shape) # (53,) sonoridad específica media
res.plot() # sonoridad específica media N'(z) + N(l) dependiente del tiempo a 187.5 Hz
```
-
+
+
+*El tono de 1 kHz a 60 dB SPL, N = 2,8 sone_HMS: un tono más sonoro que el
+ancla de 40 dB del fragmento de arriba, que da 0,98 sone_HMS. La sonoridad es
+el área bajo $N'(z)$, así que un sonido de banda ancha que reparta un patrón
+bajo sobre muchas bandas puede pesar más que este pico único.*
Mostrar el código de esta figura
@@ -385,10 +405,12 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
+# La figura es el tono de 60 dB, no el ancla de 40 dB del fragmento de arriba.
fs = 48000
t = np.arange(int(1.2 * fs)) / fs
-x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)
+x = np.sqrt(2) * 2e-5 * 10 ** (60 / 20) * np.sin(2 * np.pi * 1000 * t)
res = psychoacoustics.loudness_ecma(x, fs, field="free")
+print(f"N = {res.loudness:.1f} sone_HMS") # 2.8 sone_HMS
# El resultado lleva la sonoridad específica media sobre las 53 bandas Bark_HMS:
res.plot(language="es")
diff --git a/site/src/content/docs/es/perception/psychoacoustics/index.md b/site/src/content/docs/es/perception/psychoacoustics/index.md
index d1e0e1eff..debfaf304 100644
--- a/site/src/content/docs/es/perception/psychoacoustics/index.md
+++ b/site/src/content/docs/es/perception/psychoacoustics/index.md
@@ -37,8 +37,12 @@ ISO 1996-2.
[Molestia psicoacústica e intensidad de fluctuación](/phonometry/es/perception/psychoacoustics/psychoacoustic-annoyance/)
cierra la cadena con el modelo de Fastl y Zwicker, que combina sonoridad,
agudeza, aspereza y la sensación de modulación lenta de la intensidad de
-fluctuación en un único valor de molestia. Léela en último lugar: sus cuatro
-entradas salen de las páginas anteriores.
+fluctuación en un único valor de molestia. Léela en último lugar: tres de sus
+cuatro entradas salen de las páginas anteriores, y la cuarta, la intensidad de
+fluctuación, la aporta ella misma, tanto en la forma cerrada de Fastl y Zwicker
+como en el modelo de señal de Osses 2016. La intensidad de fluctuación de
+ECMA-418-2 de la página de calidad sonora es un modelo normativo más de esa
+misma sensación, bajo otro nombre de unidad.
## Páginas de esta sección
diff --git a/site/src/content/docs/es/perception/psychoacoustics/loudness.mdx b/site/src/content/docs/es/perception/psychoacoustics/loudness.mdx
index 4616d41d2..fa4293fdb 100644
--- a/site/src/content/docs/es/perception/psychoacoustics/loudness.mdx
+++ b/site/src/content/docs/es/perception/psychoacoustics/loudness.mdx
@@ -144,8 +144,8 @@ broad = psychoacoustics.loudness_zwicker_from_spectrum(np.full(28, 60.0))
z = np.arange(1, narrow.specific.size + 1) * 0.1 # eje Bark
fig, ax = plt.subplots()
for r, color, label in [
- (broad, "#ff7f0e", f"Banda ancha N = {broad.loudness:.1f} sone"),
- (narrow, "#1f77b4", f"Banda estrecha 1 kHz N = {narrow.loudness:.1f} sone"),
+ (broad, "#d62728", f"Banda ancha plana 60 dB - N = {broad.loudness:.1f} sone"),
+ (narrow, "#1f77b4", f"Banda estrecha 1 kHz - N = {narrow.loudness:.1f} sone"),
]:
ax.fill_between(z, r.specific, color=color, alpha=0.3)
ax.plot(z, r.specific, color=color, label=label)
diff --git a/site/src/content/docs/es/perception/psychoacoustics/sound-quality.mdx b/site/src/content/docs/es/perception/psychoacoustics/sound-quality.mdx
index bf13054e8..1deab4288 100644
--- a/site/src/content/docs/es/perception/psychoacoustics/sound-quality.mdx
+++ b/site/src/content/docs/es/perception/psychoacoustics/sound-quality.mdx
@@ -229,10 +229,15 @@ res.plot() # aspereza R(l50) dependiente del tiempo + mapa de calor de asperez
+*Las dos sensaciones, cada una leída como la define su cláusula: la tonalidad
+como traza temporal, que separa un tono en ruido del ruido solo, y la aspereza
+en función de la tasa de modulación, cuyo máximo a 70 Hz sobre una portadora de
+1 kHz totalmente modulada a 60 dB es el punto de calibración del asper.*
+
Mostrar el código de esta figura
@@ -241,30 +246,38 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
-fs = 48000
+fs, p0 = 48000, 2e-5
+
+# Panel superior: la tonalidad T(t) de un tono de 1 kHz en ruido frente al
+# ruido solo, cada componente a 50 dB SPL durante 2 s.
t = np.arange(int(2.0 * fs)) / fs
-amp = np.sqrt(2) * 2e-5 * 10 ** (60 / 20)
-
-# Un tono puro (tonal, suave) frente a un tono modulado en amplitud a 70 Hz
-# (áspero), ambos normalizados a un nivel global de 60 dB SPL:
-tone = amp * np.sin(2 * np.pi * 1000 * t)
-rough = (1.0 + np.cos(2 * np.pi * 70 * t)) * np.sin(2 * np.pi * 1000 * t)
-rough *= 2e-5 * 10 ** (60 / 20) / np.sqrt(np.mean(rough**2))
-
-scores = {
- "Tono puro": (psychoacoustics.tonality_ecma(tone, fs).tonality, psychoacoustics.roughness_ecma(tone, fs).roughness),
- "Tono AM 70 Hz": (psychoacoustics.tonality_ecma(rough, fs).tonality, psychoacoustics.roughness_ecma(rough, fs).roughness),
-}
-labels = list(scores)
-tonal = [scores[k][0] for k in labels]
-rough_v = [scores[k][1] for k in labels]
-xpos = np.arange(len(labels))
-fig, ax = plt.subplots()
-ax.bar(xpos - 0.2, tonal, 0.4, label="Tonalidad [tu_HMS]")
-ax.bar(xpos + 0.2, rough_v, 0.4, label="Aspereza [asper]")
-ax.set_xticks(xpos)
-ax.set_xticklabels(labels)
-ax.legend()
+rng = np.random.default_rng(2026)
+noise = rng.standard_normal(t.size)
+noise *= p0 * 10 ** (50 / 20) / np.sqrt(np.mean(noise**2))
+tone = p0 * 10 ** (50 / 20) * np.sqrt(2) * np.sin(2 * np.pi * 1000 * t)
+tin = psychoacoustics.tonality_ecma(tone + noise, fs)
+pn = psychoacoustics.tonality_ecma(noise, fs)
+
+# Panel inferior: la aspereza de una portadora de 1 kHz con AM del 100 %,
+# barriendo la frecuencia de modulación (1 s por punto a 60 dB SPL).
+tm = np.arange(fs) / fs
+fmods = np.array([20.0, 30, 40, 50, 60, 70, 80, 100, 120, 150, 180, 200])
+r = []
+for fm in fmods:
+ am = (1 + np.sin(2 * np.pi * fm * tm)) * np.sin(2 * np.pi * 1000 * tm)
+ am *= p0 * 10 ** (60 / 20) / np.sqrt(np.mean(am**2))
+ r.append(psychoacoustics.roughness_ecma(am, fs).roughness)
+
+fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(10, 8.5))
+ax0.plot(tin.time, tin.tonality_vs_time,
+ label=f"Tono en ruido (T = {tin.tonality:.2f} tu_HMS)") # 1,19
+ax0.plot(pn.time, pn.tonality_vs_time,
+ label=f"Ruido puro (T = {pn.tonality:.2f} tu_HMS)") # 0,02
+ax0.set(xlabel="Tiempo [s]", ylabel="Tonalidad T [tu_HMS]")
+ax0.legend()
+ax1.plot(fmods, r, "o-", label="Portadora de 1 kHz, AM del 100 %") # máximo 1,0 asper
+ax1.set(xlabel="Frecuencia de modulación f_mod [Hz]", ylabel="Aspereza R [asper]")
+ax1.legend()
plt.show()
```
diff --git a/site/src/content/docs/es/perception/psychoacoustics/tone-audibility.mdx b/site/src/content/docs/es/perception/psychoacoustics/tone-audibility.mdx
index 60bcf1b99..a12f2aaa4 100644
--- a/site/src/content/docs/es/perception/psychoacoustics/tone-audibility.mdx
+++ b/site/src/content/docs/es/perception/psychoacoustics/tone-audibility.mdx
@@ -136,8 +136,10 @@ La audibilidad **decisiva** de un espectro de banda estrecha es la mayor
audibilidad de tono en él (apartado 5.3.8). Sobre $J$ espectros escalonados en
el tiempo, la **audibilidad media** es su media energética (Fórmula 20); un
espectro en el que no se encuentra ningún tono aporta
-$\Delta L_j = -10\ \text{dB}$ (Fórmula 21). `assess_tones` aplica toda la
-cadena a los tonos de un espectro e informa del tono decisivo.
+$\Delta L_j = -10\ \text{dB}$ (Fórmula 21). `assess_tones` es el punto de
+entrada *por tono*: aplica las Fórmulas (2)-(5) y (12)-(14) a cada tono que se
+le pasa e informa del mayor, que es la audibilidad decisiva solo cuando no hay
+dos tonos audibles que compartan banda crítica.
**Cómo se selecciona la banda decisiva.** El método no barre un conjunto fijo
de bandas: cada *tono* detectado define su propia banda crítica (§1), la
@@ -161,12 +163,28 @@ LS = [48.91, 49.22, 50.50, 52.85, 58.29, 59.53, 59.71, 61.98, 54.16]
res = psychoacoustics.assess_tones(fT, LT, LS, 2.7)
print(round(res.decisive_audibility, 2), res.decisive_frequency) # 5.01 137.3
-# Audibilidad media de los cinco espectros medidos (valores decisivos, Tabla E.3):
+# Los cinco espectros de la campaña del Anexo E, calificados con el Paso 3
+# aplicado (valores decisivos de la Tabla E.3), promediados en energía por la
+# Fórmula 20:
print(round(psychoacoustics.mean_audibility([9.18, 6.04, 7.46, 2.67, 7.17]), 2)) # 6.98 dB
res.plot(view="levels") # niveles de tono sobre el ruido enmascarante de su banda crítica
```
+Los dos números de ese bloque no son el mismo espectro calificado dos veces con
+la misma regla. Los tonos a 118,4, 137,3 y 158,8 Hz caen todos en una misma
+banda crítica, así que el Paso 3 del apartado 5.3.8 los fusiona en un grupo
+`FG` a su nivel combinado $L_T = 72{,}15$ dB, y el valor decisivo de la norma
+para el espectro 1 son los 9,18 dB que abren la lista de `mean_audibility`, no
+los 5,01 dB que imprime la llamada por tono, que es la mayor de las nueve
+audibilidades individuales
+`[0.75, 0.89, 1.02, 1.79, 1.93, 3.47, 4.39, 4.57, 5.01]`. Esos 4,2 dB
+sobreviven al promediado: el valor por tono en lugar de 9,18 baja la media de
+la campaña de 6,98 dB a 5,98 dB, que es $K_t = 3$ dB en vez de 4 dB en la
+Tabla J.1 de ISO 1996-2. Así que usa `analyze_spectrum` (§5), que ejecuta el
+agrupamiento, siempre que se vaya a declarar una audibilidad decisiva, y
+`assess_tones` solo cuando el agrupamiento ya está resuelto.
+
La misma evaluación se lee de dos maneras. Las barras de audibilidad del
principio de esta página responden a «cuánto supera cada tono el umbral de
enmascaramiento»; la vista de niveles responde a «qué vio el analizador», que
diff --git a/site/src/content/docs/es/perception/speech/speech-intelligibility.mdx b/site/src/content/docs/es/perception/speech/speech-intelligibility.mdx
index d9f369cb5..a2146a725 100644
--- a/site/src/content/docs/es/perception/speech/speech-intelligibility.mdx
+++ b/site/src/content/docs/es/perception/speech/speech-intelligibility.mdx
@@ -362,12 +362,16 @@ y en cómo se expresa la propagación ascendente del enmascaramiento, y `method=
elige uno. El valor por omisión es el procedimiento por tercios de octava usado
arriba.
-| `method=` | Bandas | Intervalo | Constantes | Propagación de la máscara |
-| :--- | ---: | :--- | :--- | :--- |
-| `"critical-band"` | 21 | 100 Hz a 9500 Hz | Tabla 1 | entre los límites de banda tabulados |
-| `"equally-contributing"` | 17 | 300 Hz a 6400 Hz | Tabla 2 | entre los límites de banda tabulados |
-| `"one-third-octave"` | 18 | 160 Hz a 8000 Hz | Tabla 3 | entre las frecuencias centrales de banda |
-| `"octave"` | 6 | 177 Hz a 11314 Hz | Tabla 4 | ninguna |
+| `method=` | Bandas | Centros de banda | Límites de banda | Constantes | Propagación de la máscara |
+| :--- | ---: | :--- | :--- | :--- | :--- |
+| `"critical-band"` | 21 | 150 Hz a 8500 Hz | 100 Hz a 9500 Hz | Tabla 1 | entre los límites de banda tabulados |
+| `"equally-contributing"` | 17 | 350 Hz a 5800 Hz | 300 Hz a 6400 Hz | Tabla 2 | entre los límites de banda tabulados |
+| `"one-third-octave"` | 18 | 160 Hz a 8000 Hz | 143 Hz a 8980 Hz (calculados) | Tabla 3 | entre las frecuencias centrales de banda |
+| `"octave"` | 6 | 250 Hz a 8000 Hz | 177 Hz a 11314 Hz | Tabla 4 | ninguna |
+
+Las dos columnas son `sii_procedure(method).frequencies` y `.band_edges`; solo
+los límites de tercio de octava se calculan a partir de los centros en vez de
+estar tabulados.
Todos los procedimientos recorren la misma cadena del apartado 2: la automáscara
del habla, la propagación ascendente del enmascaramiento, el ruido interno
@@ -639,10 +643,11 @@ propagación ascendente del enmascaramiento y el ruido interno equivalente. El
### ¿Cuál de los cuatro procedimientos por bandas de ANSI S3.5 debo usar?
-ANSI S3.5-1997 define cuatro: bandas críticas (21 bandas, 100 Hz a 9500 Hz),
-bandas críticas de contribución equitativa (17 bandas, 300 Hz a 6400 Hz), tercio
-de octava (18 bandas, 160 Hz a 8000 Hz) y octava (6 bandas, 250 Hz a 8000 Hz
-nominales). Usa `method="one-third-octave"` por omisión: es la resolución más
+ANSI S3.5-1997 define cuatro, citados aquí por el centro de banda: bandas
+críticas (21 bandas, centros de 150 Hz a 8500 Hz), bandas críticas de
+contribución equitativa (17 bandas, centros de 350 Hz a 5800 Hz), tercio de
+octava (18 bandas, centros de 160 Hz a 8000 Hz) y octava (6 bandas, centros de
+250 Hz a 8000 Hz). Usa `method="one-third-octave"` por omisión: es la resolución más
fina y el único procedimiento cuya tabla trae los espectros de voz elevado, alto
y de grito. Usa `method="critical-band"` para alinear el índice con un modelo de
enmascaramiento o sonoridad por bandas críticas (Bark),
diff --git a/site/src/content/docs/es/reference/bibliography.md b/site/src/content/docs/es/reference/bibliography.md
index 3532637e4..ff3e93844 100644
--- a/site/src/content/docs/es/reference/bibliography.md
+++ b/site/src/content/docs/es/reference/bibliography.md
@@ -1,6 +1,6 @@
---
title: "Bibliografía"
-description: "Los libros y artículos que sustentan las guías, agrupados por dominio: cada entrada con un DOI verificado o un enlace oficial del editor y una nota sobre qué sustenta."
+description: "Una selección curada de los libros y artículos que sustentan las guías, agrupados por dominio: cada entrada con un DOI verificado o un enlace oficial del editor y una nota sobre qué sustenta."
---
Cada guía de este sitio se cierra con dos secciones de citas: una sección
@@ -8,11 +8,14 @@ Cada guía de este sitio se cierra con dos secciones de citas: una sección
página (estilo APA, un punto por fuente, cada uno con un DOI o un enlace
oficial del editor, y media frase sobre qué sustenta la entrada), seguida de
una sección **Normas** que nombra los documentos normativos que la página
-implementa, apartado por apartado. Esta página reúne las entradas de
-Referencias de todas las guías en un solo lugar, agrupadas por dominio: una
-lista de lectura curada y la fuente única de verdad para la comprobación de
-enlaces. Cada entrada lista las guías que la citan; la lista crece a medida
-que las guías incorporan sus secciones de Referencias.
+implementa, apartado por apartado. Esta página reúne las obras en las que más
+se apoyan las guías, agrupadas por dominio, y cada entrada lista las páginas de
+guía que la citan. Es una **selección curada, no la lista completa de citas**:
+en el momento de escribir esto, dos docenas de obras con DOI citadas en el
+frontmatter de las propias guías no aparecen aquí, entre ellas Welch (1967),
+Harris (1978), Knapp y Carter (1976), Allen y Berkley (1979) y Maa (1998). La
+sección de Referencias de cada guía, generada a partir de su frontmatter, es la
+autoridad para esa página.
## Acústica general
diff --git a/site/src/content/docs/es/reference/conformance.md b/site/src/content/docs/es/reference/conformance.md
index bf76e90d9..97360c0de 100644
--- a/site/src/content/docs/es/reference/conformance.md
+++ b/site/src/content/docs/es/reference/conformance.md
@@ -130,7 +130,7 @@ Only **Butterworth** (the library default) and **Chebyshev-II** are class-compli
| Standard | Quantity | Expected (norm) | Computed | Δ | Status |
|:---|:---|:---|:---|:---|:---:|
| IEC 61672-1:2013 (Leq) | Leq of a 1 Pa 1 kHz sine | 90.97 dB (+/-0.05 dB) | 90.969 dB | -0.001 dB | ✅ |
-| IEC 61252:1995 (LEX,8h) | 8 h exposure to 90 dB(A) noise | 90 dB (+/-0.05 dB) | 90.008 dB | 0.008 dB | ✅ |
+| IEC 61252:1993 (LEX,8h) | 8 h exposure to 90 dB(A) noise | 90 dB (+/-0.05 dB) | 90.008 dB | 0.008 dB | ✅ |
| ISO 1996-1:2016 3.6.4 | Lden, constant 60 dB in day/evening/night | 66.3952 dB (+/-0 dB) | 66.3952 dB | 0 dB | ✅ |
| ISO 1996-2:2007 Annex C.5 Example 1 | Tonal audibility ΔLta (Formula C.3), 4 kHz tone | 13.7 dB (+/-0.05 dB) | 13.66 dB | -0.044 dB | ✅ |
| ISO 1996-2:2007 Annex C.5 Example 1 | Tonal adjustment Kt (Formulae C.4-C.6) | 6 dB (+/-0 dB) | 6 dB | 0 dB | ✅ |
diff --git a/site/src/content/docs/es/reference/errata.md b/site/src/content/docs/es/reference/errata.md
index 9c0a7d496..7d18f1544 100644
--- a/site/src/content/docs/es/reference/errata.md
+++ b/site/src/content/docs/es/reference/errata.md
@@ -663,6 +663,38 @@ which is the check that enforces the rule; see
retained because the library cites the 2006 edition, whose print carries the
defect; the 2017 edition stands as the confirmation.
+## UNE-EN 15657:2018, Clause 7.1, Formula (14) (reference mass dimensionally inconsistent with the quantity it normalises)
+
+- **Location:** Clause 7.1, the sentence introducing Formula (14) (printed
+ p. 14) and Formula (14) itself (printed p. 15), the structural power level
+ injected into the reception plate.
+- **The print:** the sentence reads "a partir del nivel de velocidad promediado
+ espacialmente de la placa $L_v$, de la **masa por unidad de superficie** $m$,
+ del área de la placa $S$ y del factor de pérdida $\eta$, utilizando
+ $f_0 = 1$ Hz, $m_0 = 1$ kg y $S_0 = 1$ m² como referencias", above
+ $L_{Ws} = \left(10\lg\left(\dfrac{2\pi f m \eta S}{f_0 \cdot m_0 \cdot S_0}\right)\right)\text{dB} + L_v - 60\ \text{dB}$.
+- **The problem:** the same sentence defines $m$ as a mass per unit area, in
+ kg/m², and its reference $m_0$ as 1 kg. With $m$ in kg/m² and $S$ in m², the
+ group $2\pi f\,\eta\,m\,S / (f_0 m_0 S_0)$ is dimensionless only if $m_0$ is
+ 1 kg/m²; as printed it carries a leftover m⁻². The closing constant confirms
+ the intended reading: $10\lg(f_0 m_0 S_0 v_0^2 / P_0) = -60$ dB with
+ $v_0 = 10^{-9}$ m/s and $P_0 = 1$ pW closes in watts only when $f_0 m_0 S_0$
+ has the units of an area density times an area times a frequency. The numeric
+ result is unaffected, because $10\lg(1) = 0$ whichever unit is attached, which
+ is why the slip survives a worked example.
+- **Evidence:** dimensional analysis of Formula (14) against the definition of
+ $m$ in the sentence above it, and against the $-60$ dB constant it closes on;
+ the sentence and the formula were read as images, not from extracted text.
+ Verified on PDF page 14 (printed p. 14) and PDF page 15 (printed p. 15) of
+ UNE-EN 15657:2018. Only the Spanish-language adoption was read, so this entry
+ does not establish whether the English EN 15657:2018 print carries the same
+ reference.
+- **Library behaviour:** no change required. `characteristic_reception_plate_power`
+ takes `mass_per_area` in kg/m² and reproduces the standard's own worked values,
+ so the intended reading is the implemented one; the guide and the docstring
+ keep the printed reference and name this entry beside it.
+- **Status:** unreported.
+
## ISO 12999-1:2020, Table 4 (missing 500 Hz row)
- **Location:** Table 4 (in-situ uncertainties per band).
diff --git a/site/src/content/docs/es/reference/index.md b/site/src/content/docs/es/reference/index.md
index 5c3db205a..d45ac25dc 100644
--- a/site/src/content/docs/es/reference/index.md
+++ b/site/src/content/docs/es/reference/index.md
@@ -63,8 +63,9 @@ nombre necesite la cláusula de la que viene.
## [Bibliografía](/phonometry/es/reference/bibliography/)
-Todos los libros y artículos que citan las guías, en una sola lista agrupada
-por dominio, cada entrada con un DOI verificado o un enlace oficial del
-editor, media frase sobre qué sustenta y las páginas de guía que la citan.
-Sirve a la vez como lista de lectura del campo y como fuente única de verdad
-para la comprobación de enlaces.
+Una selección curada de los libros y artículos en los que se apoyan las guías,
+en una sola lista agrupada por dominio, cada entrada con un DOI verificado o un
+enlace oficial del editor, media frase sobre qué sustenta y las páginas de guía
+que la citan. Es una lista de lectura del campo más que el índice completo de
+citas: la lista con autoridad para una página concreta es la sección de
+Referencias de esa misma página, generada a partir de su frontmatter.
diff --git a/site/src/content/docs/es/reference/theory/environment-transport.mdx b/site/src/content/docs/es/reference/theory/environment-transport.mdx
index 83fd03133..de3d48a2d 100644
--- a/site/src/content/docs/es/reference/theory/environment-transport.mdx
+++ b/site/src/content/docs/es/reference/theory/environment-transport.mdx
@@ -147,6 +147,15 @@ $$
P = 3 \log_{10}(\text{tasa de crecimiento}) + 2 \log_{10}(\text{diferencia de nivel}),
$$
+
+
+*Las dos entradas de $P$ son geometría sobre esta traza, y por eso el método
+necesita un historial de nivel y no un nivel. La tasa de crecimiento es la
+pendiente de la recta ajustada al arranque, en dB/s, y el umbral de
+cualificación de 10 dB/s es una inclinación sobre este eje; la diferencia de
+nivel es la altura de ese mismo arranque. Aquí se detectan tres golpes y solo
+el más empinado y alto determina el ajuste.*
+
diseñada para alcanzar en torno a 15 en impulsos muy súbitos e intensos. El ajuste al nivel del periodo de medición toma el impulso determinante (el de mayor $P$) (cláusula 8, Fórmula 2):
$$
@@ -211,6 +220,20 @@ $$
A = A_{div} + A_{atm} + A_{gr} + A_{bar} + A_{misc}.
$$
+
+
+*Los cuatro términos a su tamaño relativo real, banda a banda, para un recorrido
+de 200 m sobre suelo poroso con una barrera de 4 m. $A_{div}$ vale 57 dB en
+todas las bandas porque es geometría pura. $A_{atm}$ es nulo a 63 Hz y vale
+18,7 dB a 8 kHz, así que es el término que decide hasta dónde llegan las
+frecuencias altas y ningún otro. $A_{gr}$ es donde viven las bandas bajas y es
+**negativo** a 63 Hz (−4,6 dB: la reflexión en el suelo añade energía en vez de
+quitarla). $A_{bar}$ está en su tope de 20 dB de 2 kHz hacia arriba, pero cae a
+cero a 250 Hz, porque la forma de borde superior resta el efecto del suelo al
+que renuncia el recorrido apantallado, $A_{bar} = D_z - A_{gr} \geq 0$, y
+250 Hz es justo donde $A_{gr}$ alcanza su máximo. Qué término merece la pena
+afinar depende por completo de la banda y de la geometría.*
+
La biblioteca implementa los cuatro términos generales de la cláusula 7; el
$A_{misc}$ informativo (vegetación, zonas industriales, edificación) y las
reflexiones se dejan a criterio del usuario. La **divergencia geométrica** es la
@@ -244,6 +267,8 @@ nivel medio a largo plazo resta la corrección meteorológica $C_{met}$ (Ec. (6)
(21)/(22)). La exactitud declarada del método es de $\pm 1$ a $\pm 3$ dB para
ruido de banda ancha hasta 1000 m (Tabla 5).
+
+
### Exposición al ruido en el trabajo e incertidumbre (ISO 9612)
La ISO 9612:2009 es el método de ingeniería (clase de exactitud 2) para el nivel
diff --git a/site/src/content/docs/es/reference/theory/materials-surfaces.mdx b/site/src/content/docs/es/reference/theory/materials-surfaces.mdx
index de5975ef3..7776ebd3a 100644
--- a/site/src/content/docs/es/reference/theory/materials-surfaces.mdx
+++ b/site/src/content/docs/es/reference/theory/materials-surfaces.mdx
@@ -257,6 +257,16 @@ r = \frac{H_{12} - H_I}{H_R - H_{12}}\ e^{2 j k_0 x_1}, \qquad
\alpha = 1 - |r|^2, \qquad \frac{Z}{\rho c_0} = \frac{1 + r}{1 - r},
$$
+
+
+
+
+*Lo que devuelve la fórmula: $\alpha$ y $|r|$ de un absorbente poroso de 50 mm
+en la banda útil de un tubo de 100 mm. Las dos curvas son la misma información,
+$\alpha = 1 - |r|^2$, así que la figura es en realidad una sola medida dibujada
+dos veces, y el ascenso con la frecuencia es el espesor de la capa creciendo
+frente a la longitud de onda.*
+
con la cota inferior de atenuación del número de onda complejo
$k_0'' = 1{,}94 \times 10^{-2} \sqrt{f}/(c_0 d)$ (Ec. A.18). ISO 10534-1
(método de la razón de onda estacionaria) es el clásico en forma cerrada:
@@ -287,4 +297,14 @@ rígido),
recorridos de ida y vuelta sintéticos que recuperan una $r$ conocida y la
recuperación con dos cargas de una muestra recíproca asimétrica.
+
+
+
+
+*Los mismos términos del cuadripolo respondiendo a dos preguntas distintas:
+cuánto sonido deja pasar la capa exenta (la pérdida por transmisión de arriba) y
+cuánto absorbe esa misma capa una vez colocada contra un fondo rígido. Un
+material puede ser un buen absorbente y una mala barrera a la vez, y esta pareja
+lo deja claro.*
+
Consulta la [guía del tubo de impedancia](/phonometry/es/materials/absorbers/impedance-tube/) para su uso.
diff --git a/site/src/content/docs/es/reference/theory/perception.mdx b/site/src/content/docs/es/reference/theory/perception.mdx
index 9874d97bd..0eead54d1 100644
--- a/site/src/content/docs/es/reference/theory/perception.mdx
+++ b/site/src/content/docs/es/reference/theory/perception.mdx
@@ -137,6 +137,16 @@ $$
**PR** (cláusula 12) compara el nivel de la banda crítica centrada en el tono, $L_M$, con la potencia media de las dos bandas críticas **contiguas** $L_L$, $L_U$ (bordes según las Fórmulas ajustadas 21–22 con las Tablas 2–3): $\mathrm{PR} = 10\log_{10} P_M - 10\log_{10}\left[(P_L + P_U)/2\right]$ (Fórmula 23). Para $f_t \le 171{,}4$ Hz la banda inferior se trunca en 20 Hz y su potencia se reescala a un **ancho de banda de 100 Hz** (Fórmula 24). El criterio (Fórmulas 25–26) es 9,0 dB para $f_t \ge 1$ kHz, y crece como $9{,}0 + 10{,}0\log_{10}(1000/f_t)$ por debajo. Los tonos se evalúan dentro del rango de interés de 89,1 Hz – 11,2 kHz (cláusulas 11.5 / 12.6).
+
+
+*El criterio de TNR dibujado en lugar de evaluado, sobre el rango de interés de
+89,1 Hz – 11,2 kHz, con un tono evaluado encima. Como el criterio vale
+$8{,}0 + 8{,}33\log_{10}(1000/f_t)$ por debajo de 1 kHz y es constante por
+encima, una misma relación tono-ruido se juzga contra un umbral distinto en
+cada frecuencia: el tono del ejemplo supera en 2,1 dB su umbral de 13,0 dB a
+250 Hz, mientras que un tono de 10 dB sería prominente en cualquier punto por
+encima de 1 kHz y no lo sería aquí.*
+
Consulta la [guía de tonos discretos prominentes](/phonometry/es/perception/psychoacoustics/tone-prominence/) para su uso.
## Sonoridad de Zwicker (ISO 532-1)
@@ -240,6 +250,15 @@ $$
(Fórmulas 65–111). El valor único $R$ es el percentil 90 de $R(l_{50})$ en el tiempo (Cláusula 7.1.10); la constante $c_R$ (Fórmula 104) calibra el sonido de referencia (un portador de 1 kHz modulado en amplitud al 100 % a 70 Hz y 60 dB SPL) a 1 asper.
+
+
+*La ponderación por tasa de modulación que aplican las fórmulas anteriores, y
+la razón por la que el rango «aproximadamente 20–300 Hz, máxima cerca de
+70 Hz» es un paso banda y no un umbral: el mismo portador de 1 kHz modulado
+despacio se oye como intensidad de fluctuación, con máximo cerca de 4–6 Hz, y
+modulado deprisa se oye como aspereza, con máximo cerca de 70 Hz. Entre los dos
+máximos la sensación cambia de nombre, no de grado.*
+
### Agudeza (DIN 45692)
La agudeza (*sharpness*) condensa en un solo número el énfasis en alta frecuencia de un sonido: el primer momento ponderado por $g(z)$ del patrón de sonoridad específica estacionaria de ISO 532-1 (DIN 45692:2009, Ecuación 1):
@@ -251,6 +270,15 @@ $$
evaluado sobre la misma malla de 240 puntos a 0,1 Bark. La constante $k$ no está codificada a mano, sino que se deriva del requisito de calibración (cláusula 6): un ruido de banda estrecha de una banda crítica de ancho, 920–1080 Hz a 60 dB SPL, puntúa exactamente 1 acum, y la $k = 0{,}108$ derivada cae dentro de la ventana normativa $0{,}105 \le k < 0{,}115$ (cláusula 5.2). Las ponderaciones informativas del Anexo B se ofrecen bajo el mismo anclaje de 1 acum: von Bismarck (codo en 15 Bark, $0{,}2\ e^{0{,}308(z-15)} + 0{,}8$) y Aures (dependiente de la sonoridad, $g(z) = 0{,}078\ (e^{0{,}171 z}/z)\ N/\ln(0{,}05 N + 1)$). Los objetivos de banda estrecha de la Tabla A.2 se reproducen dentro de la tolerancia de la cláusula 6 (5 % o 0,05 acum): 0,38 acum a 250 Hz, 1,00 a 1 kHz, 1,78 a 2,5 kHz, 2,82 a 4 kHz.
+
+
+*Las tres ponderaciones $g(z)$ de la fórmula anterior en un mismo eje: la DIN
+con su codo en 15,8 Bark, la de von Bismarck con su codo en 15 Bark y la curva
+de Aures, dependiente de la sonoridad. Por eso la elección de ponderación
+cambia un valor de agudeza solo para sonidos con energía por encima del codo
+(de 15 a 15,8 Bark, unos 2,5 a 3 kHz) y deja intacto todo lo que queda por
+debajo.*
+
Consulta la [guía de métricas de calidad sonora](/phonometry/es/perception/psychoacoustics/sound-quality/) para su uso.
## Transferencia de modulación y STI (IEC 60268-16)
@@ -279,7 +307,28 @@ $$
\mathrm{STI} = \sum_{k=1}^{7} \alpha_k\ \mathrm{MTI}_k - \sum_{k=1}^{6} \beta_k \sqrt{\mathrm{MTI}_k\ \mathrm{MTI}_{k+1}}
$$
-truncado a 1,0. STIPA (Anexo B) muestrea la misma física con solo dos frecuencias de modulación por banda (Tabla B.1) sobre una señal de prueba con índice de modulación de fuente 0,55; las profundidades recibidas se miden por correlación seno/coseno de las envolventes de intensidad $I_k(t)$ filtradas paso-bajo a ~100 Hz sobre un número entero de periodos de modulación:
+truncado a 1,0.
+
+
+
+*Los siete $\mathrm{MTI}_k$ que consume la suma ponderada anterior, para una
+sala con $T = 0{,}9$ s y una relación habla-ruido de 15 dB. Cada barra es ya la
+media de 14 índices de transmisión, así que esto queda dos etapas de promediado
+por debajo del $m(F)$ crudo; las barras caen dentro de 0,06 unas de otras, que
+es el caso en el que los términos de redundancia $\beta_k$ apenas restan nada y
+el STI se acerca a la media simple ponderada por $\alpha$.*
+
+
+
+*El final de la cadena en lugar de su parte central: lo que la forma cerrada de
+Schroeder le hace al STI a medida que crece la reverberación, frente a las
+bandas de calificación del Anexo F. La curva cae abruptamente en el rango en el
+que una sala todavía es utilizable y se aplana una vez que la modulación ya
+está destruida, que es la razón por la que reducir a la mitad un tiempo de
+reverberación largo compra menos inteligibilidad que reducir a la mitad uno
+corto.*
+
+STIPA (Anexo B) muestrea la misma física con solo dos frecuencias de modulación por banda (Tabla B.1) sobre una señal de prueba con índice de modulación de fuente 0,55; las profundidades recibidas se miden por correlación seno/coseno de las envolventes de intensidad $I_k(t)$ filtradas paso-bajo a ~100 Hz sobre un número entero de periodos de modulación:
$$
m_{dr} = \frac{2 \sqrt{\left( \sum_t I_k(t) \sin 2 \pi f_m t \right)^2 + \left( \sum_t I_k(t) \cos 2 \pi f_m t \right)^2}}{\sum_t I_k(t)}, \qquad m = \frac{m_{dr}}{0{,}55}
@@ -325,7 +374,7 @@ $$
N_{50} = \big[ u + v \log_{10}(t/t_0) \big]\ (L_{EX,8h} - L_0)^2, \qquad t_0 = 1\ \text{año},
$$
-cuadrático en el exceso sobre el nivel de inicio dependiente de la frecuencia $L_0$ (75 dB a 4 kHz, la banda más sensible, hasta 93 dB a 500 Hz) y cero por debajo; para menos de 10 años escala como $\log_{10}(t+1)/\log_{10} 11$ (Fórmula 3). Los fractiles añaden la dispersión, $N_Q = N_{50} + z\ d_{u,l}$ con $d = (X + Y \log_{10} t)(L_{EX,8h} - L_0)^2$ (cláusula 6.3.2, Fórmulas 4–7, Tablas 2/3), acotada en cero; la convención cuenta la fracción de la población con el desplazamiento *menor*, así que $Q = 0{,}9$ es el decil más susceptible (rango fiable 0,05–0,95). El nivel de umbral de audición asociado a edad y ruido (HTLAN) combina el NIPTS con la componente de edad de ISO 7029 al mismo fractil mediante la suma comprimida (cláusula 6.1, Fórmula 1):
+cuadrático en el exceso sobre el nivel de inicio dependiente de la frecuencia $L_0$ (75 dB a 4 kHz, la banda más sensible, hasta 93 dB a 500 Hz) y cero por debajo; para menos de 10 años escala como $\log_{10}(t+1)/\log_{10} 11$ (Fórmula 3). Los fractiles añaden la dispersión, $N_Q = N_{50} + z\ d_{u,l}$ con $d = (X + Y \log_{10} t)(L_{EX,8h} - L_0)^2$ (cláusula 6.3.2, Fórmulas 4–7, Tablas 2/3), acotada en cero. El `fractile` de la librería cuenta la fracción de la población con el desplazamiento *menor*, así que `fractile=0.9` es el decil más susceptible (rango fiable 0,05–0,95); la $Q$ de la propia ISO 1999 corre al revés, contando el porcentaje con peor audición, así que ese mismo decil es allí $Q = 10\ \%$, igual que en los encabezados de columna del Anexo D. El nivel de umbral de audición asociado a edad y ruido (HTLAN) combina el NIPTS con la componente de edad de ISO 7029 al mismo fractil mediante la suma comprimida (cláusula 6.1, Fórmula 1):
$$
H' = H + N - \frac{H\ N}{120}.
@@ -333,4 +382,15 @@ $$
Los ejemplos resueltos del Anexo D (Tablas D.1–D.4; p. ej. 100 dB / 40 años a 3 kHz: 29/38/60 dB en los fractiles 0,10/0,50/0,90) se reproducen exactamente con el redondeo a enteros de la norma, y el valor a mano de la Fórmula 2 a 4 kHz / 20 años / 90 dB es $N_{50} = 12{,}94$ dB.
+
+
+*El modelo como audiograma: 40 años a 95 dB(A) normalizados a 8 h. La muesca a
+4 kHz es lo que hace reconocible en consulta la pérdida inducida por ruido, y
+está ahí solo porque $L_0$ es mínimo (75 dB) en esa banda. Atención a la
+dirección del fractil que enuncia el párrafo anterior: el borde de la banda
+sombreada que muestra el desplazamiento **mayor** es el `fractile=0.90` de la
+librería, el décimo más susceptible, al que ISO 1999 y los encabezados de
+columna de su Anexo D llaman $Q = 10\ \%$. A 4 kHz este caso da 19,5 / 26,0 /
+36,0 dB para `fractile` 0,10 / 0,50 / 0,90.*
+
Consulta la [guía de pérdida auditiva inducida por ruido](/phonometry/es/perception/hearing/noise-induced-hearing-loss/) para su uso.
diff --git a/site/src/content/docs/es/reference/theory/rooms-buildings.mdx b/site/src/content/docs/es/reference/theory/rooms-buildings.mdx
index fc7301f74..eb56f08b1 100644
--- a/site/src/content/docs/es/reference/theory/rooms-buildings.mdx
+++ b/site/src/content/docs/es/reference/theory/rooms-buildings.mdx
@@ -190,6 +190,16 @@ $$
con $t_e = 50$ ms (C50, habla) o 80 ms (C80, música), y el **tiempo central** $T_s = \int_0^{\infty} t\ p^2\ dt / \int_0^{\infty} p^2\ dt$. Para un decaimiento puramente exponencial tienen formas cerradas $C_{te} = 10 \log_{10}(e^{a t_e} - 1)$ y $T_s = 1/a$; a $T = 1$ s ($a = 13{,}8155$) evalúan a C80 = 3,05 dB, C50 = −0,02 dB, D50 = 0,499 y Ts = 72,4 ms, los valores que reproduce la implementación. Las JND de la Tabla A.1 (EDT 5 %, C80 1 dB, D50 0,05, Ts 10 ms) acotan con qué finura merece la pena informar cada una.
+
+
+*Las formas cerradas anteriores valen para un único decaimiento exponencial;
+una sala real da un juego de valores por banda. El panel superior es el
+decaimiento en sí (EDT, T20 y T30 cayendo con la frecuencia a medida que el
+aire y las superficies absorben más), el inferior es el reparto
+temprano/tardío de esa misma respuesta al impulso, y C50 y C80 crecen con la
+frecuencia por la misma razón por la que cae el tiempo de reverberación: cuanto
+más tardía es la energía, mayor parte de ella ha eliminado ya la sala.*
+
### Decaimiento espacial en oficinas diáfanas (ISO 3382-3, Cláusula 6)
La tasa de decaimiento espacial del habla ponderada A es la pendiente por mínimos cuadrados ordinarios de $L_{p,A,S}$ frente a $\log_{10}(r/r_0)$ ($r_0 = 1$ m) sobre las posiciones de 2–16 m, reescalada a una cifra por duplicación, y el nivel nominal se lee en la misma recta a 4 m:
@@ -200,6 +210,16 @@ $$
La distancia de distracción rD y la distancia de privacidad rP son las distancias donde una regresión **lineal** (no logarítmica) del STI frente a la distancia cruza 0,50 y 0,20; una pendiente ajustada no negativa (el STI no decrece con la distancia) las deja indefinidas, materializando la nota de la norma de que "puede resultar imposible de determinar".
+
+
+*Dos regresiones sobre dos ejes distintos, que es lo que hace difícil de
+retener esta cláusula. La recta de nivel se ajusta frente a
+$\log_{10}(r/r_0)$ y se lee dos veces: como la pendiente $D_{2,S}$ por
+duplicación y en $r = 4$ m para $L_{p,A,S,4\text{m}}$. La recta del STI se
+ajusta frente a $r$ mismo, de forma **lineal**, y se lee donde cruza 0,50 y
+0,20 para las distancias de distracción y de privacidad. Si ese segundo ajuste
+sale plano o creciente, las dos distancias no existen, no es que sean grandes.*
+
### Aislamiento en campo e índice ponderado (ISO 16283-1, ISO 717-1)
Por banda de tercio de octava, la diferencia de niveles $D = L_1 - L_2$ (promediada en energía sobre las posiciones de micrófono, $L = 10 \log_{10}[(1/n) \sum_i 10^{L_i/10}]$) se normaliza de dos formas: la diferencia de niveles estandarizada $D_{nT} = D + 10 \log_{10}(T/T_0)$ con $T_0 = 0{,}5$ s (de modo que $D_{nT} = D$ cuando $T = T_0$), y el índice de reducción acústica aparente $R' = D + 10 \log_{10}(S/A)$ con el área de absorción de Sabine $A = 0{,}16\ V / T$, por tanto $R' = D + 10 \log_{10}[S T / (0{,}16\ V)]$.
@@ -229,6 +249,17 @@ ISO 717-2 se reproducen exactamente (tercios $L_{n,w} = 79$, $C_I = -11$;
octavas $54$, $0$), mediante la misma búsqueda de desplazamiento monótono que
ISO 717-1 ejecutada sobre las curvas negadas.
+
+
+*La imagen especular de la figura de ruido aéreo anterior, dibujada para que la
+inversión se vea en vez de enunciarse. Allí las desviaciones desfavorables se
+contaban donde la medición quedaba **por debajo** de la referencia; aquí se
+cuentan donde la supera **por arriba**, porque un recinto receptor más ruidoso
+es un forjado peor. Todo lo demás es el mismo procedimiento: la curva de
+referencia desplazada en pasos de 1 dB hasta que la suma desfavorable es lo
+mayor posible sin pasar de 32,0 dB, y el índice leído en la referencia
+desplazada a 500 Hz.*
+
La absorción acústica (ISO 354) mide el área de absorción equivalente a partir de
la relación de Sabine aplicada a una cámara reverberante vacía y con la muestra:
$A = 55{,}3\ V/(c\ T) - 4 V m$ (el término $4 V m$ es la absorción del aire, $m$ el
@@ -242,14 +273,19 @@ NOTA 2).
### Normalización en laboratorio frente a campo (ISO 10140, ISO 16283)
-Los índices de campo llevan una prima porque incluyen la transmisión por flancos
-alrededor del cerramiento; los índices de laboratorio no, porque una instalación
-cualificada la suprime. El álgebra es por lo demás idéntica, y difiere solo en
-qué magnitud se normaliza. El par a ruido aéreo es el índice de reducción acústica
-directo de laboratorio $R = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 10140-2) frente
-al índice aparente de campo $R' = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 16283-1),
-la misma forma cerrada evaluada con el $A$ conocido de la instalación o el
-$A = 0{,}16\ V/T$ medido de la sala. El par a impactos es el nivel normalizado de
+Los índices de campo llevan una prima porque el nivel del recinto receptor del
+que parten incluye la transmisión por flancos alrededor del cerramiento; los
+índices de laboratorio no, porque una instalación cualificada la suprime. Las
+fórmulas son, por tanto, las *mismas*, y la prima es una afirmación sobre la
+probeta y no sobre la aritmética: el índice de reducción acústica directo de
+laboratorio $R = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 10140-2) y el índice
+aparente de campo $R' = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 16283-1) son una
+única forma cerrada, evaluada con el $A$ conocido de la instalación en el
+laboratorio y con el $A = 0{,}16\ V/T$ medido del recinto receptor en campo. Lo
+que difiere en *qué se normaliza* no es laboratorio frente a campo, sino ruido
+aéreo frente a impactos: los índices a ruido aéreo escalan por la razón
+superficie-absorción $S/A$, y los niveles de impactos por $A/A_0$. El par a
+impactos es el nivel normalizado de
laboratorio $L_n = L_i + 10 \log_{10}(A/A_0)$ (ISO 10140-3) frente al $L'_n$ de
campo (ISO 16283-2), ambos referidos a $A_0 = 10$ m². Antes de formar cualquiera
de ellos, el nivel del recinto receptor se corrige por ruido de fondo mediante la
@@ -335,6 +371,15 @@ reproducen: la sala desnuda de 29,75 m³ da $A = 2{,}26$ m² y $T = 2{,}1$ s a
baja $T$ a 0,9 s. El método informativo del Anexo D para espacios irregulares
y absorción distribuida de forma no uniforme queda fuera de alcance.
+
+
+*Lo que hace la Fórmula 1 banda a banda: el área de absorción equivalente a la
+izquierda y el tiempo de reverberación que implica por la Fórmula 5 a la
+derecha, para la misma sala desnuda y tratada. El caso del Anexo E citado más
+arriba es esta misma aritmética sobre una sala más pequeña ($A$ de 2,26 a
+5,03 m² y $T$ de 2,1 a 0,9 s a 1 kHz), y la figura muestra por qué las dos se
+mueven en sentidos opuestos y no de forma proporcional.*
+
Consulta la [guía de absorción acústica en recintos](/phonometry/es/buildings/rooms/enclosed-space-absorption/) para su uso.
### Incertidumbre de medición (ISO 12999-1)
@@ -362,7 +407,7 @@ correlacionada es la suma en cuadratura ponderada en energía de las
incertidumbres por banda (Fórmula B.2).
Consulta las guías de [acústica de salas](/phonometry/es/buildings/rooms/room-acoustics/) y de
-[medición del aislamiento en campo](/phonometry/es/buildings/insulation/insulation-field/) para su uso.
+[medición del aislamiento en campo (ISO 16283)](/phonometry/es/buildings/insulation/insulation-field/) para su uso.
### Predicción del aislamiento de paneles (Bies 7.2, Hopkins 2.9/4.3.10, Cremer 5)
@@ -392,5 +437,19 @@ $10\log_{10}(S/S_a)$. El camino de transmisión resonante y la radiación de la
doble se apoyan en la eficiencia de radiación de placa y las movilidades
puntuales de la [teoría de vibración](/phonometry/es/reference/theory/vibration/).
+
+
+*Los cuatro comportamientos del párrafo anterior, uno por panel. Arriba a la
+izquierda, la ley de masas subiendo 6 dB por octava con el valle de coincidencia
+de Sharp recortado en $f_c$. Arriba a la derecha, la pared doble: no mejor que
+la masa combinada por debajo de $f_0$, y luego el término de cámara subiendo
+hasta saturar. Abajo a la izquierda, la eficiencia de radiación que decide
+cuánta de la vibración de la placa se convierte en sonido. Abajo a la derecha,
+el techo que impone una fuga: un área abierta del 1 % deja la composición en
+$10\log_{10}(S/S_a) = 20$ dB por buena que sea la pared, que es el panel que
+merece la pena enseñar a un cliente.*
+
+
+
Consulta la guía [Predicción del aislamiento de paneles](/phonometry/es/buildings/design/panel-sound-insulation/)
para su uso.
diff --git a/site/src/content/docs/es/reference/theory/signal-analysis.mdx b/site/src/content/docs/es/reference/theory/signal-analysis.mdx
index 4bf8cb9a7..40c13cd53 100644
--- a/site/src/content/docs/es/reference/theory/signal-analysis.mdx
+++ b/site/src/content/docs/es/reference/theory/signal-analysis.mdx
@@ -173,6 +173,19 @@ for f, pxx in zip(freq_bins[in_band], psd[in_band]):
print(f, pxx)
```
+
+
+*Los dos objetos sobre un mismo eje, para una señal de seis tonos a 20, 100,
+500, 2000, 4000 y 15 000 Hz. La traza gris es una PSD de Welch ($f_s$ = 48 kHz,
+`nperseg = 8192`, es decir, un bin fijo de 5,86 Hz en todas partes); los
+marcadores son los niveles normalizados en tercios de octava de esa misma
+señal. El ancho de bin nunca cambia y el ancho de banda sí: 4,60 Hz en la banda
+de 20 Hz, más estrecho que un bin, frente a 230,77 Hz a 1 kHz y 3657 Hz a
+16 kHz. Por eso las bandas altas se tragan cientos de bins cada una mientras
+que las bajas caben dentro de uno solo, y por eso las dos respuestas no se
+pueden convertir la una en la otra. (La traza de PSD lleva un desplazamiento
+vertical por legibilidad, así que hay que leer su forma y no su nivel.)*
+
Esto mantiene separados los dos conceptos: phonometry da niveles de octava
fraccional normalizados, mientras Welch da bins FFT de banda estrecha. Con
`fs=100000` y `nperseg=2**15`, la separación de bins Welch es de unos 3,05 Hz.
@@ -241,7 +254,7 @@ casos requieren tratamiento especial:
## Diseño del banco y estabilidad numérica
-Para garantizar **estabilidad total** en todo el espectro audible (incluso a
+Para garantizar una **estabilidad del 100 %** en todo el espectro audible (incluso a
frecuencias bajas como 16 Hz con frecuencias de muestreo altas), phonometry
emplea dos estrategias fundamentales:
@@ -297,7 +310,27 @@ $$
\alpha = 1 - e^{-1 / (f_s \cdot \tau)}
$$
-donde $\tau$ es la constante de tiempo (p. ej. 125 ms para Fast).
+Esta es la imagen digital del detector RC analógico del sonómetro clásico: la
+presión al cuadrado carga un condensador a través de una resistencia, así que el
+valor cuadrático medio que se muestra es un paso bajo de un polo sobre $p^2$ con
+constante de tiempo $\tau$, y $\alpha = 1 - e^{-1/(f_s \tau)}$ es su
+discretización invariante al impulso, exacta a cualquier $f_s$, al contrario que
+la aproximación $1/(f_s \tau)$ que suele verse. Las dos constantes normalizadas
+son $\tau = 125$ ms (**Fast**) y $\tau = 1$ s (**Slow**). Una entrada en escalón
+llega a menos de 1 dB de su valor final tras unas $1{,}6\tau$ y le faltan
+0,03 dB a $5\tau$, que es la razón por la que los niveles leídos en las primeras
+constantes de tiempo de un registro salen sesgados a la baja.
+
+**Impulse no es este filtro.** No puede serlo: un único $\alpha$ no puede
+retener un pico, y la figura de más abajo muestra a Impulse reteniendo uno. La
+IEC 61672-1 define la ponderación I como un detector rápido de 35 ms seguido de
+una caída de 1,5 s, implementada aquí como un detector *asimétrico*: carga con
+$\tau = 35$ ms siempre que la entrada supera el estado actual y descarga con
+$\tau = 1{,}5$ s en caso contrario, de modo que un transitorio se captura deprisa
+y luego se retiene durante más de un segundo. Eso hace que I no sea ni un valor
+eficaz ni un promedio energético, que es la razón por la que se reserva para las
+reglamentaciones concretas que la nombran y por la que nunca debe sumarse en
+energía entre intervalos.
La condición inicial por defecto es $y[-1] = 0$. Usa `initial_state='first'`
para partir de la energía de la primera muestra, o pasa un escalar/array con el
@@ -324,7 +357,17 @@ $$
k = \left| \frac{\prod_i (j\omega_{10} - p_i)}{\prod_i (j\omega_{10} - z_i)} \right|, \qquad \omega_{10} = 2\pi \cdot 10 \ \text{rad/s}
$$
-Los cuatro ceros frente a ocho polos dan forma a la respuesta característica: una subida de aproximadamente **+12 dB/octava entre 1 Hz y 20 Hz**, con caídas de aproximadamente **24 dB/octava** por debajo de 1 Hz y por encima de 20 Hz. Los infrasonidos necesitan su propia curva porque, cerca del umbral de audición, la sonoridad percibida de los tonos de muy baja frecuencia crece con el nivel de presión acústica mucho más abruptamente que a frecuencias medias (un pequeño incremento en dB sobre el umbral produce un gran salto de sonoridad), de modo que la curva A (anclada en 1 kHz) distorsiona por completo la molestia infrasónica.
+Los cuatro ceros frente a ocho polos dan forma a la respuesta característica: una subida de aproximadamente **+12 dB/octava entre 1 Hz y 20 Hz**, con caídas de aproximadamente **24 dB/octava** por debajo de 1 Hz y por encima de 20 Hz.
+
+
+
+*La forma que dibujan esos cuatro ceros y cuatro pares de polos, frente a los
+valores nominales de la Tabla 2 de ISO 7196: 0 dB en el anclaje de 10 Hz, la
+subida de +12 dB/octava a lo largo de la década infrasónica que queda por debajo
+y las dos caídas de 24 dB/octava que acotan la curva por debajo de 1 Hz y por
+encima de 20 Hz.*
+
+Los infrasonidos necesitan su propia curva porque, cerca del umbral de audición, la sonoridad percibida de los tonos de muy baja frecuencia crece con el nivel de presión acústica mucho más abruptamente que a frecuencias medias (un pequeño incremento en dB sobre el umbral produce un gran salto de sonoridad), de modo que la curva A (anclada en 1 kHz) distorsiona por completo la molestia infrasónica.
Como G actúa sobre 0,25 Hz – 315 Hz, muy por debajo de la frecuencia de Nyquist a tasas de audio, la deformación en frecuencia de la transformación bilineal simple (aplicada sin precompensación) es despreciable en ese rango: en torno al 0,014 % a 315 Hz con $f_s = 48$ kHz, menos de 0,01 dB en la respuesta. Por eso no se aplica el sobremuestreo interno usado en los diseños A/C (cuya acción se extiende hasta 16 kHz).
@@ -338,6 +381,14 @@ $$
\mathrm{SEL} = L_{eq,T} + 10 \log_{10}\left(\frac{T}{T_0}\right), \qquad T_0 = 1\ \text{s}
$$
+
+
+*Lo que la fórmula le hace a un evento: el paso se sustituye por un bloque de un
+segundo con la misma energía total, que es la razón por la que el SEL supera al
+$L_{eq}$ del evento siempre que este dura más de un segundo, y por la que dos
+eventos con el mismo SEL son intercambiables en una dosis aunque uno sea fuerte
+y corto y el otro flojo y largo.*
+
La **exposición sonora** $E$ (IEC 61252, 3.1) es la integral temporal del cuadrado de la presión acústica ponderada A, expresada en pascales al cuadrado por hora:
$$
@@ -364,7 +415,7 @@ $$
\rho_0 \frac{\partial u}{\partial t} = -\frac{\partial p}{\partial r}
$$
-Una sonda p-p aproxima el gradiente de presión por la **diferencia finita** de dos micrófonos separados una distancia de separador $\Delta r$ (IEC 61043:1994, definición 3.2):
+Una sonda p-p aproxima el gradiente de presión por la **diferencia finita** de dos micrófonos separados una distancia de separador $\Delta r$ (IEC 61043:1993, definición 3.2):
$$
p = \frac{p_1 + p_2}{2}, \qquad u = -\frac{1}{\rho_0 \Delta r} \int (p_2 - p_1)\ dt, \qquad I = \overline{p\ u}
@@ -430,4 +481,16 @@ no gaussiana, así que el intervalo es más estrecho que $\pm 1{,}96\,u$), y el
ejemplo del bloque patrón del Anexo H.1 de la GUM da
$k = t_{0{,}99}(\nu_{\mathrm{eff}} = 16) = 2{,}92$ y $U_{99} = 93$ nm.
+
+
+*Las dos vías sobre un mismo problema, un nivel ponderado A y no el ejemplo de
+cuatro términos del Suplemento 1 citado más arriba. A la izquierda, la ley de
+propagación como presupuesto: una barra por entrada, de modo que se ve cuál es
+el término que merece la pena reducir. A la derecha, la vía del Suplemento 1: la
+distribución de salida de Monte Carlo con la gaussiana GUM dibujada encima y el
+intervalo de cobertura del 95 % sombreado. Aquí las dos coinciden, que es lo que
+la cláusula 8 llama validación; cuando el modelo es no lineal o la salida
+visiblemente no gaussiana, el histograma se separa de la curva y el intervalo se
+lee de los fractiles en su lugar.*
+
Consulta la [guía de incertidumbre de medida](/phonometry/es/signals/metrology/gum-uncertainty/) para su uso.
diff --git a/site/src/content/docs/es/reference/theory/vibration.mdx b/site/src/content/docs/es/reference/theory/vibration.mdx
index 096ee098d..924d1717a 100644
--- a/site/src/content/docs/es/reference/theory/vibration.mdx
+++ b/site/src/content/docs/es/reference/theory/vibration.mdx
@@ -126,6 +126,16 @@ al día durante 20 años) se reproduce: $D_{zd} = 55{,}97$ m/s², $R = 1{,}22$,
$\Pi = 0{,}37$. El modelo espinal de elementos finitos del Anexo A
(distribuido por ISO como software aparte) queda fuera de alcance.
+
+
+*Los dos objetos del modelo. A la izquierda, la transmisibilidad
+asiento-columna de la cláusula 5.2: unidad en continua, máximo en
+$|H| \approx 1{,}54$ cerca de 5 Hz y caída por encima, que es la razón por la
+que hubo que sustituir $W_k$ para los choques. A la derecha, la ley de Weibull
+$\Pi(R)$ de la Tabla C.1 con el ejemplo resuelto del Anexo C marcado en
+$R = 1{,}22$, $\Pi = 0{,}37$: el riesgo sube abruptamente en una banda estrecha
+de $R$, así que una dosis que se duplica no duplica la probabilidad.*
+
Consulta la [guía de vibración en humanos](/phonometry/es/vibration/human/human-vibration/) y la
[guía de vibración con choques múltiples](/phonometry/es/vibration/human/multiple-shock-vibration/) para su uso.
@@ -157,4 +167,21 @@ para su uso.
-*Receptancia, movilidad y acelerancia de un resonador de un grado de libertad: la misma resonancia vista a través de las tres magnitudes cinemáticas.*
+*No es ninguna de las formas cerradas anteriores: este es un resonador
+**finito** de un grado de libertad, y la receptancia, la movilidad y la
+acelerancia son la misma resonancia vista a través de las tres magnitudes
+cinemáticas. Está aquí como contraste: los resultados de estructura infinita
+son independientes de la frecuencia o caen suavemente, mientras que todo lo
+finito resuena.*
+
+
+
+*El mismo punto leído como diagnóstico: por debajo de la resonancia el módulo
+sube por la **recta de rigidez** $\omega/k$, por encima cae por la **recta de
+masa** $1/(\omega m)$, y la altura del máximo la fija solo el amortiguamiento.
+Una estructura real tiene muchas resonancias de estas, y las formas cerradas de
+estructura infinita anteriores son la media en torno a la cual oscila la
+movilidad medida, no el valor que toma a una frecuencia dada, que es la razón
+por la que se usan con entradas de octava o tercio de octava y por la que son
+menos fiables en las bandas más bajas de un elemento pequeño o poco
+amortiguado.*
diff --git a/site/src/content/docs/es/signals/filters/filter-banks.mdx b/site/src/content/docs/es/signals/filters/filter-banks.mdx
index 0e43ca7df..45957df1d 100644
--- a/site/src/content/docs/es/signals/filters/filter-banks.mdx
+++ b/site/src/content/docs/es/signals/filters/filter-banks.mdx
@@ -51,9 +51,13 @@ import ThemeImage from '../../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../../components/ReportPreview.astro';
phonometry soporta varios tipos de filtro, cada uno con su propia función de
-transferencia característica. Todos los bancos sitúan sus **puntos de −3 dB en
-los bordes de banda de ANSI S1.11**, de modo que los niveles por banda son
-comparables entre arquitecturas.
+transferencia característica. Butterworth, Chebyshev II y Bessel sitúan sus
+**puntos de −3 dB en los bordes de banda de ANSI S1.11**, de modo que sus
+niveles por banda son directamente comparables. Los dos diseños de rizado
+constante (Chebyshev I, Elíptico) no: toman esos bordes como borde de *rizado*,
+lo que ensancha la banda y sesga todos los niveles por banda en unas décimas de
+decibelio fijas — ver el apartado 1, porque el sesgo es sistemático y no se
+promedia a cero.
## 1. Bandas de octava fraccionaria: las matemáticas
@@ -70,10 +74,46 @@ $$
de modo que cada banda de tercio de octava abarca
$G^{1/3} \approx 1{,}2589 \approx 10^{1/10}$: diez bandas por década, y por eso
las frecuencias nominales (25, 31,5, 40 …) se repiten escaladas por 10.
-phonometry diseña cada banda como una cascada SOS cuyos puntos de −3 dB caen
-exactamente en $f_1$ y $f_2$ en todas las arquitecturas; para Chebyshev II,
-Elíptico y Bessel eso exige pre-deformar (pre-warping) el mapeo analítico de los
-bordes de banda en lugar de confiar en la parametrización por defecto de SciPy.
+phonometry diseña cada banda como una cascada SOS sobre esos bordes, pero dónde
+acaba cayendo el punto de −3 dB depende de qué entiende cada arquitectura por su
+frecuencia de diseño, y solo tres de las cinco lo ponen en $f_1$ y $f_2$.
+
+### Dónde cae de verdad el punto de −3 dB de cada arquitectura
+
+La frecuencia de diseño de SciPy para Butterworth *es* su punto de −3 dB, así
+que no necesita corrección. Chebyshev II se diseña por sus bordes de banda
+eliminada, obtenidos analíticamente desde los bordes de banda, y Bessel se
+normaliza con `norm="mag"` en lugar de con la normalización de fase por defecto
+de SciPy: las dos correcciones existen para que sus puntos de −3 dB caigan
+también en los bordes. A Chebyshev I y al Elíptico se les entregan los bordes de
+banda directamente, y para esas dos familias SciPy los lee como borde de la
+*banda de paso de rizado constante*: la respuesta ahí es la profundidad del
+rizado, no −3 dB. Medido sobre la banda de octava de 1 kHz a 48 kHz con orden 6
+y el `ripple=0.1` por defecto:
+
+| Arquitectura | Respuesta en $f_1$ y $f_2$ | Ancho de banda de ruido / $(f_2 - f_1)$ | Desviación del nivel de banda |
+| :--- | :---: | :---: | :---: |
+| `butter` | −3,01 dB | 1,003 | referencia |
+| `cheby2` | −3,01 dB | 1,003 | −0,02 dB |
+| `bessel` | −3,01 dB | 0,971 | +0,05 dB |
+| `cheby1` | **−0,10 dB** | 1,066 | **+0,33 dB** |
+| `ellip` | **−0,10 dB** | 1,052 | **+0,25 dB** |
+
+Las tres primeras columnas son la banda de octava de 1 kHz; la última es la
+diferencia mediana de nivel de banda respecto a Butterworth sobre un banco
+entero de tercios de octava analizando 20 s de ruido blanco. Esa última columna
+importa porque es un *sesgo*, no dispersión: no se reduce con el tiempo de
+promediación, es mayor que todo el corredor de banda de paso de clase 1
+(±0,4 dB) y mueve todas las bandas a la vez, así que un espectro medido con
+`cheby1` queda en bloque por encima de uno medido con `butter`. Conviene elegir
+una arquitectura por campaña y no mezclar nunca arquitecturas dentro de un mismo
+espectro. Subir el `order` reduce la desviación, porque una banda de transición
+más estrecha devuelve el punto de −3 dB hacia el borde de rizado: para `cheby1`
+la mediana pasa de +0,76 dB con orden 4 a +0,33 dB con orden 6, +0,16 dB con
+orden 8 y +0,04 dB con orden 12. Bajar `design.ripple` hace lo contrario de lo
+que sugiere la intuición y hace la desviación *mayor* (+0,62 dB con
+`ripple=0.02`), porque a orden fijo una banda de paso más plana se paga con una
+caída más lenta.
### Polos, ceros y estabilidad
@@ -150,26 +190,51 @@ argumentos de cada día siguen primero: `FilterDesign` (`design`),
`LevelCalibration` (`calibration`), `BlockProcessing` (`block_processing`) y
`ResponsePlot` (`response_plot`). La tabla nombra cada opción por su grupo.
-| Parámetro | Tipo | Unidades | Rango / por defecto | Notas |
-| :--- | :--- | :--- | :--- | :--- |
-| `x` | array 1D o 2D | unidades digitales | no vacío | 2D es `[channels, samples]` |
-| `fs` | int | Hz | > 0 | |
-| `fraction` | int | — | por defecto `1`; habitual `3`; cualquier $b \ge 1$ | Bandas por octava = $b$ |
-| `order` | int | — | por defecto `6` | Orden SOS por banda |
-| `limits` | lista `[lo, hi]` | Hz | por defecto `[12, 20000]` | Rango de análisis |
-| `design.filter_type` | str | — | `'butter'` (por defecto), `'cheby1'`, `'cheby2'`, `'ellip'`, `'bessel'` | Consulta la [Galería de arquitecturas de filtro](/phonometry/es/signals/filters/filter-gallery/) |
-| `design.ripple` / `design.attenuation` | float | dB | `ripple` defecto `0.1`; `attenuation` defecto `72.0` | Rizado de banda de paso / atenuación en banda atenuada (cheby/ellip); `cheby2` necesita `attenuation` $\ge 70$ para clase 1, ya que scipy fija su suelo equirizado en exactamente este valor |
-| `design.resample` | bool | — | por defecto `True` | Filtra cada banda a una frecuencia diezmada (multitasa) |
-| `response_plot.show` | bool | — | por defecto `False` | Dibuja la respuesta del banco (requiere matplotlib) |
-| `sigbands` | bool | — | por defecto `False` | Devuelve también las señales temporales por banda |
-| `mode` | str | — | `'rms'` (por defecto), `'peak'`, `'sum'` | Estadístico por banda devuelto |
-| `nominal` | bool | — | por defecto `False` | Devuelve etiquetas nominales (p. ej. `1000`) en vez de las frecuencias centrales exactas |
-| `detrend` | bool | — | por defecto `True` | Elimina el offset DC de cada banda antes del nivel (mejora la precisión en graves) |
-| `calibration.factor` | float | — | por defecto `1.0` | Escala la entrada a pascales (consulta la guía de Calibración) |
-| `calibration.dbfs` | bool | — | por defecto `False` | Referencia los niveles a fondo de escala digital en vez de 20 µPa |
-| `response_plot.file` | str o `None` | — | por defecto `None` | Guarda la gráfica de respuesta del banco en esta ruta |
-| `zero_phase` | bool | — | por defecto `False` | Filtrado adelante-atrás (offline) |
-| `block_processing.stateful` / `.steady_ic` (clase) | bool | — | por defecto `False` | Estado en streaming; consulta [Procesado por bloques](/phonometry/es/signals/filters/block-processing/) |
+Tres puntos de llamada comparten esta tabla, y no aceptan las mismas opciones,
+así que la columna **Dónde** nombra aquel al que pertenece cada una:
+`octave_filter()` es la función de un solo uso, `OctaveFilterBank(...)` es el
+constructor y `bank.filter()` es el método por llamada.
+
+| Parámetro | Dónde | Tipo | Unidades | Rango / por defecto | Notas |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| `x` | función, `.filter()` | array 1D o 2D | unidades digitales | no vacío | 2D es `[channels, samples]` |
+| `fs` | función, constructor | int | Hz | > 0 | |
+| `fraction` | función, constructor | int | — | por defecto `1`; habitual `3`; cualquier $b \ge 1$ | Bandas por octava = $b$ |
+| `order` | función, constructor | int | — | por defecto `6` | Orden SOS por banda |
+| `limits` | función, constructor | lista `[lo, hi]` | Hz | por defecto `[12, 20000]` | Rango de análisis |
+| `design.filter_type` | función, constructor | str | — | `'butter'` (por defecto), `'cheby1'`, `'cheby2'`, `'ellip'`, `'bessel'` | Consulta la [Galería de arquitecturas de filtro](/phonometry/es/signals/filters/filter-gallery/) |
+| `design.ripple` / `design.attenuation` | función, constructor | float | dB | `ripple` defecto `0.1`; `attenuation` defecto `72.0` | Rizado de banda de paso / atenuación en banda atenuada (cheby/ellip); `cheby2` necesita `attenuation` $\ge 70$ para clase 1, ya que scipy fija su suelo equirizado en exactamente este valor |
+| `design.resample` | función, constructor | bool | — | por defecto `True` | Filtra cada banda a una frecuencia diezmada (multitasa) |
+| `response_plot.show` | función, constructor | bool | — | por defecto `False` | Dibuja la respuesta del banco (requiere matplotlib) |
+| `response_plot.file` | función, constructor | str o `None` | — | por defecto `None` | Guarda la gráfica de respuesta del banco en esta ruta |
+| `calibration.factor` | función, constructor | float | — | por defecto `1.0` | Escala la entrada a pascales (consulta la guía de Calibración) |
+| `calibration.dbfs` | función, constructor | bool | — | por defecto `False` | Referencia los niveles a fondo de escala digital en vez de 20 µPa |
+| `block_processing.stateful` / `.steady_ic` | solo constructor | bool | — | por defecto `False` | Estado en streaming; consulta [Procesado por bloques](/phonometry/es/signals/filters/block-processing/) |
+| `sigbands` | función, `.filter()` | bool | — | por defecto `False` | Devuelve también las señales temporales por banda |
+| `mode` | función, `.filter()` | str | — | `'rms'` (por defecto) o `'peak'` | Estadístico por banda devuelto |
+| `nominal` | función, `.filter()` | bool | — | por defecto `False` | Devuelve etiquetas nominales (p. ej. `1000`) en vez de las frecuencias centrales exactas |
+| `detrend` | función, `.filter()` | bool | — | por defecto `True` | Elimina el offset DC de cada banda antes del nivel (mejora la precisión en graves) |
+| `zero_phase` | solo `.filter()` | bool | — | por defecto `False` | Filtrado adelante-atrás (offline); ver el apartado 5 |
+| `calculate_level` | solo `.filter()` | bool | — | por defecto `True` | Con `False` devuelve las señales de banda sin calcular niveles (usar con `sigbands=True`) |
+
+El reparto no es arbitrario: la `octave_filter()` de un solo uso diseña un banco
+y lo usa una vez, así que solo lleva las opciones de tiempo de diseño.
+`zero_phase` y `calculate_level` se deciden en cada llamada y por eso viven en
+`OctaveFilterBank.filter()` — `octave_filter(x, fs, zero_phase=True)` lanza
+`TypeError` —, mientras que el estado de streaming queda fijado al construir el
+banco.
+
+`mode` tiene exactamente dos valores. `'rms'` da el nivel medio energético de la
+banda sobre todo el registro, que es lo que toda norma entiende por "nivel de
+banda". `'peak'` da $20\log_{10}$ de la mayor muestra en valor absoluto dentro
+de la banda, contra la misma referencia de 20 µPa; es un pico instantáneo de
+banda, no una lectura de retención de pico, está limitado en banda y sin
+ponderar, así que *no* es el pico ponderado C $L_{C\text{peak}}$ de la guía de
+[Niveles](/phonometry/es/signals/levels/levels/), y en señales impulsivas lo
+domina el propio timbrado del filtro: pertenece al diagnóstico de transitorios,
+no a la comunicación de niveles. No hay modo `'sum'`: un total entre bandas es
+una suma energética que hace quien llama,
+`10*np.log10(np.sum(10**(spl/10)))`, nunca una media aritmética de decibelios.
`verify_filter_class(bank)` comprueba el banco diseñado contra los límites de
aceptación de la Tabla 1 de IEC 61260-1 e informa de la clase (`1`, `2` o `None` si queda fuera de ambas) con los
@@ -367,9 +432,10 @@ plt.show()
## 5. Filtrado de fase cero
Para análisis offline puedes eliminar por completo el retardo de grupo:
-`zero_phase=True` filtra cada banda hacia delante y hacia atrás
-(`scipy.signal.sosfiltfilt`), manteniendo las señales por banda alineadas con la
-entrada. La atenuación efectiva se duplica y la banda de paso efectiva se
+`OctaveFilterBank.filter(…, zero_phase=True)` filtra cada banda hacia delante y
+hacia atrás (`scipy.signal.sosfiltfilt`), manteniendo las señales por banda
+alineadas con la entrada. Es una opción por llamada del banco, no un argumento
+de la `octave_filter()` de un solo uso. La atenuación efectiva se duplica y la banda de paso efectiva se
estrecha, reduciendo el nivel de banda ancha medido en ~0,2 a 0,3 dB por banda
(un tono puro dentro de banda no se ve afectado); prefiere el filtrado hacia
delante cuando el SPL absoluto de banda debe coincidir con el convenio de un
diff --git a/site/src/content/docs/es/signals/filters/filter-compliance.mdx b/site/src/content/docs/es/signals/filters/filter-compliance.mdx
index cb66736f6..4dc4e4fbd 100644
--- a/site/src/content/docs/es/signals/filters/filter-compliance.mdx
+++ b/site/src/content/docs/es/signals/filters/filter-compliance.mdx
@@ -68,6 +68,25 @@ print(result["bands"][0])
# {'freq': 12.589254117941678, 'class': 1, 'checked_to_omega': 3.8127755266765493, 'margin_class1_db': 0.3999999999999595, 'margin_class2_db': 0.5999999999999595}
```
+**Qué mide el margen.** Es el mínimo, sobre todas las frecuencias normalizadas
+en las que se evaluó la banda, de la distancia al límite más próximo de esa
+clase: positivo cuando la respuesta se queda dentro del corredor en todas
+partes, y negativo por exactamente la peor violación cuando no. La `class` que
+se informa es la clase más estricta cuyo margen no es negativo.
+
+Conviene saber qué restricción manda antes de intentar mejorar el número. Un
+Butterworth de planitud máxima es plano en el centro de banda, donde el corredor
+de clase 1 es de ±0,4 dB, así que su margen *satura en +0,400 dB* en cuanto la
+banda atenuada deja de ser el factor limitante: medido sobre un banco de tercios
+de octava a 48 kHz, el orden 2 falla de plano (clase `None`, peor margen de
+clase 1 de −27,03 dB) y los órdenes 4, 6, 8 y 10 informan todos clase 1 con
+exactamente +0,400 dB. Subir el orden ayuda, por tanto, solo mientras el margen
+es negativo por un motivo de banda atenuada; una vez que un diseño cumple, el
+margen queda acotado por la semianchura del corredor de banda de paso y ningún
+orden lo moverá. Un margen de +0,400 dB no es un resultado mediocre que haya que
+mejorar: es lo mejor que puede informar un diseño conforme frente a esta
+máscara.
+
La propia máscara de aceptación de la Tabla 1 también es pública:
`class_limits(fraction, filter_class, omega)` devuelve los límites
mínimo/máximo de atenuación relativa en frecuencias normalizadas
@@ -124,7 +143,10 @@ $\ge 70\ \text{dB}$ cumple; el valor por defecto de 72 dB mantiene el mismo
margen de banda de paso de +0,400 dB que Butterworth). Chebyshev I, elíptico y
Bessel no cumplen
los límites de clase con orden 6: el rizado de banda de paso (cheby1/ellip) y la
-caída lenta (bessel) violan la máscara.
+caída lenta (bessel) violan la máscara. La clase 1 es el veredicto más estricto
+que puede devolver esta edición; la clase 0, más estricta todavía, que el banco
+por defecto también supera, pertenece a la máscara retirada de 1995 y es el
+apartado 2.
## 2. Clase 0 (IEC 61260:1995 / ANSI S1.11-2004)
@@ -217,16 +239,24 @@ calificaciones abstractas:
un sonómetro de clase 1, y por eso las cadenas con calidad de instrumento
especifican la clase de cada etapa en lugar de una única cifra global.
-**¿Qué arquitectura alcanza qué clase?** El **valor por defecto de la biblioteca,
-Butterworth de orden 6, cumple clase 0** en las configuraciones que verifica
-el conjunto de conformidad (bancos de octava y tercio de octava a 48 kHz), así
-que no hace falta ninguna configuración especial para bancos de laboratorio en
-ese rango. La tabla siguiente indica la mejor clase que alcanza cada arquitectura
-con esa misma configuración de orden 6 / 48 kHz; las demás arquitecturas se
-quedan por debajo de clase 0 porque cambian la máscara IEC por otra propiedad
+**¿Qué arquitectura alcanza qué clase?** Bajo la edición de 2014, cuyas únicas
+clases son la 1 y la 2, el banco Butterworth de orden 6 por defecto de la
+biblioteca **cumple la clase 1** con un margen vinculante de +0,400 dB: ese es
+el techo, y el apartado 1 explica por qué. Frente a la máscara más estricta de
+1995 / ANSI S1.11-2004 (`edition="1995"`) ese mismo valor por defecto alcanza la
+**clase 0**; la configuración que verifica el conjunto de conformidad a esa
+clase es el banco de *bandas de octava* a 48 kHz, así que vuelve a ejecutar
+`verify_filter_class(bank, edition="1995")` por tu cuenta antes de escribir
+clase 0 en un documento para cualquier otra fracción o frecuencia de muestreo.
+Escribir "clase 0 según IEC 61260-1:2014" es una afirmación contra una clase que
+esa edición no define.
+
+La tabla indica la mejor clase que alcanza cada arquitectura con orden 6 y
+fs 48 kHz bajo la máscara de 1995; las arquitecturas distintas de Butterworth se
+quedan por debajo porque cambian la máscara IEC por otra propiedad
*por construcción*:
-| Arquitectura | Mejor clase (orden 6, fs 48 kHz) | Por qué |
+| Arquitectura | Mejor clase (orden 6, fs 48 kHz, `edition="1995"`) | Por qué |
| :--- | :---: | :--- |
| `butter` (por defecto) | **0** | Banda de paso máximamente plana, caída monótona; encaja en la máscara |
| `cheby2` | 1 | Banda de paso plana pero la relación de la máscara limita en clase 1 |
@@ -234,13 +264,15 @@ quedan por debajo de clase 0 porque cambian la máscara IEC por otra propiedad
| `ellip` | — | Rizado en banda de paso y atenuada |
| `bessel` | — | Retardo de grupo plano a costa de una caída lenta |
-Así que el valor por defecto sensato es el habitual (Butterworth de orden 6):
-supera la clase 0 en las configuraciones verificadas, mientras que las
-arquitecturas alternativas son opciones deliberadas cuyo propósito (caída más
-abrupta, fase lineal) va en contra de la máscara de clase. Fuera de estos
-ajustes (`fraction` muy alto o bandas cercanas a Nyquist), vuelve a ejecutar
-`verify_filter_class` para confirmar la clase que necesitas, y sube el orden si
-una banda necesita más margen.
+Bajo la edición de 2014 esa misma ordenación se lee 1 / 1 / — / — / —:
+`cheby2` se junta con Butterworth en lo más alto porque ya no existe la clase 0
+para separarlos.
+
+Así que el valor por defecto sensato es el habitual (Butterworth de orden 6),
+mientras que las arquitecturas alternativas son opciones deliberadas cuyo
+propósito (caída más abrupta, fase lineal) va en contra de la máscara de clase.
+Fuera de estos ajustes (`fraction` muy alto o bandas cercanas a Nyquist), vuelve
+a ejecutar `verify_filter_class` para confirmar la clase que necesitas.
## 4. La ficha de conformidad (`.report()`)
@@ -363,4 +395,8 @@ La clase 0 es la clase de prestaciones más estricta, definida por IEC
61260-1:2014. Su corredor de banda de paso admite solo ±0,15 dB en el
centro de banda, frente a ±0,3 dB para la clase 1 en las máscaras de 1995.
Sigue accesible con `edition="1995"`, y el banco Butterworth de orden 6 por
-defecto cumple la clase 0 en las configuraciones verificadas a 48 kHz.
+defecto cumple la clase 0 en la configuración que verifica el informe de
+conformidad, el banco de bandas de octava a 48 kHz. Bajo IEC 61260-1:2014 ese
+mismo banco es clase 1: la edición de 2014 no define ninguna clase 0, así que
+una afirmación de clase 0 tiene que citar la máscara de 1995 / ANSI S1.11-2004
+frente a la que se midió.
diff --git a/site/src/content/docs/es/signals/filters/filter-gallery.mdx b/site/src/content/docs/es/signals/filters/filter-gallery.mdx
index 60f58a578..14e8a9828 100644
--- a/site/src/content/docs/es/signals/filters/filter-gallery.mdx
+++ b/site/src/content/docs/es/signals/filters/filter-gallery.mdx
@@ -30,10 +30,14 @@ import ThemeImage from '../../../../../components/ThemeImage.astro';
Elegir una arquitectura de filtro es un compromiso: la selectividad, el
rizado de banda de paso y el comportamiento de fase no pueden ser óptimos a
la vez, y cada una de las cinco arquitecturas que ofrece phonometry
-resuelve el compromiso de forma distinta. Como todas sitúan sus **puntos de
-−3 dB en los bordes de banda de ANSI S1.11**, la elección cambia cómo
-rechaza una banda a sus vecinas y cómo trata los transitorios, no dónde se
-sitúa la banda. Esta página pone las arquitecturas frente a frente: la
+resuelve el compromiso de forma distinta. Tres de ellas — Butterworth,
+Chebyshev II y Bessel — sitúan sus **puntos de −3 dB en los bordes de banda de
+ANSI S1.11**, así que para esas tres la elección cambia cómo rechaza una banda a
+sus vecinas y cómo trata los transitorios, no dónde se sitúa la banda. Los dos
+diseños de rizado constante son la excepción, y el apartado 3 da su tamaño:
+`cheby1` y `ellip` toman los bordes de banda como su borde de rizado, así que
+sus bandas son efectivamente más anchas y todos sus niveles por banda salen unas
+décimas de decibelio altos. Esta página pone las arquitecturas frente a frente: la
comparación en el cruce a −3 dB, la galería completa de respuestas en
octava y tercio de octava, ejemplos de uso por arquitectura y el crossover
Linkwitz-Riley para cuando el objetivo es dividir una señal en lugar de
@@ -94,7 +98,7 @@ plt.show()
Vista espectral completa de los bancos para octava (1/1) y tercio de octava (1/3).
-| Arquitectura | Octava 1/1 (fraction=1) | Octava 1/3 (fraction=3) |
+| Arquitectura | Octava (`fraction=1`) | Tercio de octava (`fraction=3`) |
| :--- | :--- | :--- |
| **Butterworth** | | |
| **Chebyshev I** | | |
@@ -302,12 +306,32 @@ filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
-### 6. Linkwitz-Riley (`linkwitz_riley`)
-
-Diseñado específicamente para **crossovers de audio**. Los filtros Linkwitz-Riley
-(típicamente de 4.º orden, aunque se admite cualquier orden par) permiten dividir
-una señal en bandas que, al sumarse, producen una respuesta en magnitud
-perfectamente plana y sin diferencia de fase entre bandas en el cruce.
+## 4. Crossover Linkwitz-Riley (`linkwitz_riley`)
+
+Linkwitz-Riley no es una sexta arquitectura: no construye una banda IEC ni es un
+valor de `FilterDesign(filter_type=…)`. Se llama directamente, y hace el trabajo
+contrario: divide una señal en dos ramas que se recombinan en una respuesta
+plana en magnitud, que es lo que necesita un **crossover** de altavoz y lo que
+una banda de medida no debe hacer jamás. Cada rama es un Butterworth de orden
+`order/2` aplicado dos veces, así que cada una queda exactamente a **−6 dB en la
+frecuencia de cruce** (no a −3 dB como las bandas de arriba): las ramas suman a
+la unidad en *amplitud*, no en potencia.
+
+Qué recombinación es plana depende de la paridad de `order/2`, y la suma ingenua
+es incorrecta para la mitad de los órdenes pares:
+
+| `order` | `order/2` | Diferencia de fase entre ramas en $f_c$ | Recombinación plana |
+| :---: | :---: | :---: | :--- |
+| 2 | 1 (impar) | 180° | `low - high` |
+| 4 | 2 (par) | 0° | `low + high` |
+| 6 | 3 (impar) | 180° | `low - high` |
+| 8 | 4 (par) | 0° | `low + high` |
+
+Con los órdenes 2 y 6 las ramas quedan en antifase en $f_c$ y `low + high` se
+hunde ahí en una muesca profunda en vez de sumar plano. Incluso en los casos
+planos la suma es **paso todo**, no libre de fase: su magnitud es plana con
+mejor de 0,001 dB de 20 Hz a 20 kHz mientras su fase gira 360° completos a
+través del cruce.
```python
import numpy as np
@@ -318,8 +342,10 @@ fs = 48000
recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Dividir la grabación en bandas grave y aguda a 1000 Hz
-low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=4)
-# Recombinada, low + high tiene una respuesta plana en magnitud (suma paso todo)
+order = 4
+low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=order)
+# Recombinación plana: suma si order/2 es par, diferencia si order/2 es impar
+recombined = low + high if (order // 2) % 2 == 0 else low - high
```
@@ -356,15 +382,25 @@ plt.show()
+**En un crossover real** las dos ramas suman acústicamente, no eléctricamente, y
+la planitud de arriba solo sobrevive si los dos caminos acústicos están
+alineados en el tiempo. Un desfase de unos pocos centímetros entre los centros
+acústicos del woofer y el tweeter basta como rotación de fase a 1 kHz para
+hundir la suma en una muesca, y el remedio es un retardo en el altavoz
+adelantado, no otro orden de filtro. Se comprueba midiendo la respuesta sumada
+en eje con el método de barrido senoidal de
+[Medición de sistemas](/phonometry/es/signals/spectra/system-measurement/).
+
## Qué cubre esta guía
**Cubierto.** Las cinco arquitecturas sobre las que puede construirse
cualquier banco de bandas IEC (Butterworth, Chebyshev I/II, elíptico,
Bessel): sus respuestas en magnitud comparadas en el cruce a −3 dB y en la
-galería completa de octava y tercio de octava, el convenio de bordes de
-banda a −3 dB de ANSI S1.11 que todas comparten, y un ejemplo de uso por
-arquitectura, más el crossover Linkwitz-Riley cuyas bandas grave y aguda
-suman una respuesta plana.
+galería completa de octava y tercio de octava, el convenio de bordes de banda
+(exacto para Butterworth, Chebyshev II y Bessel; el borde de rizado para las dos
+familias de rizado constante), y un ejemplo de uso por arquitectura, más el
+crossover Linkwitz-Riley, cuyas dos ramas se recombinan planas por suma o por
+diferencia según la paridad de `order/2`.
**No cubierto.** Las matemáticas de banda, el diseño de polos y ceros,
estabilidad y multitasa y la referencia de parámetros de `octave_filter()`
@@ -394,5 +430,10 @@ abrupta a costa de rizado en la banda de paso; Chebyshev II mantiene la
banda de paso plana y traslada el rizado a la banda atenuada; el elíptico
ofrece la máxima selectividad, con rizado en ambas bandas; y Bessel
preserva la forma de los transitorios gracias a su respuesta de fase
-lineal, pero tiene la caída más lenta. Linkwitz-Riley es para crossovers de
-audio: sus bandas suman una respuesta perfectamente plana.
+lineal, pero tiene la caída más lenta. Conviene tener presente que Chebyshev I y
+el elíptico toman los bordes de banda como su borde de *rizado* y no como su
+punto de −3 dB, así que sus niveles por banda quedan unas décimas de decibelio
+por encima de los de las otras tres y no deben mezclarse con ellos en un mismo
+espectro. Linkwitz-Riley no es una de las cinco: es un crossover, y sus dos
+ramas se recombinan planas con `low + high` cuando `order/2` es par y con
+`low - high` cuando es impar.
diff --git a/site/src/content/docs/es/signals/levels/index.md b/site/src/content/docs/es/signals/levels/index.md
index 23d705352..6706327d3 100644
--- a/site/src/content/docs/es/signals/levels/index.md
+++ b/site/src/content/docs/es/signals/levels/index.md
@@ -7,9 +7,12 @@ Un sonómetro hace tres cosas a una señal calibrada, en orden: la **pondera en
frecuencia** para imitar la sensibilidad del oído, la **suaviza en el tiempo**
con una balística normalizada y la **integra en un nivel**. Las páginas
de esta sección implementan esa cadena etapa a etapa para el nivel
-mostrado: las curvas A/C/Z y las balísticas Fast/Slow/Impulse siguen
-**IEC 61672-1:2013** tan de cerca que las ponderaciones se verifican en CI
-contra las propias tablas de tolerancia de la norma.
+mostrado: las curvas A/C/Z y las balísticas Fast y Slow de
+**IEC 61672-1:2013**, verificadas en CI contra las propias tablas de tolerancia
+de la norma (la Tabla 3 para las ponderaciones, la Tabla 4 para las respuestas
+a ráfaga de tono), más la balística Impulse heredada que la IEC 61672-1 recibió
+de la IEC 60651 y después retiró de sus requisitos, conservada aquí para
+procedimientos nacionales antiguos.
[Ponderación frecuencial (A, C, Z)](/phonometry/es/signals/levels/weighting/)
cubre la primera etapa. La curva A sigue la sensibilidad del oído a niveles
@@ -23,10 +26,12 @@ los datos antiguos, y la AU rechaza el ultrasonido de una lectura de sonido
audible según IEC 61012.
[Ponderación temporal](/phonometry/es/signals/levels/time-weighting/) cubre la
-segunda etapa: las balísticas exponenciales Fast (125 ms), Slow (1 s) e
-Impulse que deciden con qué rapidez el nivel mostrado sigue al sonido.
-phonometry implementa las constantes de tiempo exactas, verificadas contra
-las respuestas a ráfagas de tono de la norma.
+segunda etapa: las balísticas exponenciales Fast (125 ms) y Slow (1 s) que
+deciden con qué rapidez el nivel mostrado sigue al sonido, y la balística
+Impulse asimétrica heredada (35 ms de subida, 1,5 s de caída) que vino de la
+IEC 60651 y que la IEC 61672-1 ya no exige. phonometry implementa las
+constantes de tiempo exactas, verificadas contra las respuestas a ráfagas de
+tono de la norma.
[Niveles integrados y estadísticos](/phonometry/es/signals/levels/levels/) es la
recompensa: el nivel continuo equivalente Leq y su versión ponderada A LAeq,
@@ -59,7 +64,8 @@ las que se juzga una actividad.
la ponderación G para infrasonido de ISO 7196, las curvas históricas B y D
y la AU según IEC 61012.
- [Ponderación temporal](/phonometry/es/signals/levels/time-weighting/): las
- balísticas exponenciales Fast, Slow e Impulse.
+ balísticas exponenciales Fast y Slow de IEC 61672-1, y la balística Impulse
+ heredada que retiró.
- [Niveles integrados y estadísticos](/phonometry/es/signals/levels/levels/): Leq y
LAeq, niveles percentiles, LCpeak/SEL, dosis de ruido y espectrogramas de
octava.
diff --git a/site/src/content/docs/es/signals/levels/levels.mdx b/site/src/content/docs/es/signals/levels/levels.mdx
index 85b4a0516..ae7e3685d 100644
--- a/site/src/content/docs/es/signals/levels/levels.mdx
+++ b/site/src/content/docs/es/signals/levels/levels.mdx
@@ -357,13 +357,22 @@ integral temporal de la presión ponderada A al cuadrado) y el **nivel
normalizado a 8 h** equivalente:
$$
-E = \int_0^T p_A^2(t)\ dt \quad [\text{Pa}^2\text{h}], \qquad
-L_{EX,8h} = 10\log_{10}\frac{E}{8\ \text{h} \cdot p_0^2}
+E = \int_0^T p_A^2(t)\ dt \quad [\text{Pa}^2\text{h}],\ t\ \text{en horas}
+\qquad
+L_{EX,8h} = 10\log_{10}\frac{E}{T_0\,p_0^2}, \quad T_0 = 8\ \text{h}
$$
+La anotación de unidades solo se sostiene si $t$ está en horas: integrando en
+segundos salen Pa²s, que es la misma exposición expresada 3600 veces mayor, y
+35,6 dB de error si luego se mete en la fórmula de $L_{EX,8h}$. En la práctica
+se integra en segundos y se divide entre 3600, que es lo que hace
+`sound_exposure` internamente (media cuadrática × duración en horas).
+
El ancla que conviene memorizar: **3,2 Pa²h ⇔ exactamente 90 dB durante 8 h**
-(la suite de CI lo verifica). La mitad de dosis son −3 dB; el doble de
-duración al mismo nivel son +3 dB.
+(la suite de CI lo verifica). Sale directamente de la fórmula: 90 dB son
+$p_{A,\mathrm{rms}} = 20\,\mu\mathrm{Pa} \times 10^{4{,}5} = 0{,}6325$ Pa, y
+$8\ \text{h} \times (0{,}6325\ \text{Pa})^2 = 3{,}2\ \text{Pa}^2\text{h}$. La
+mitad de dosis son −3 dB; el doble de duración al mismo nivel son +3 dB.
### Parámetros de pico / evento / dosis
diff --git a/site/src/content/docs/es/signals/levels/time-weighting.mdx b/site/src/content/docs/es/signals/levels/time-weighting.mdx
index bdf6c3cb0..6ccbe717a 100644
--- a/site/src/content/docs/es/signals/levels/time-weighting.mdx
+++ b/site/src/content/docs/es/signals/levels/time-weighting.mdx
@@ -1,6 +1,6 @@
---
title: "Ponderación temporal"
-description: "Ponderación temporal Fast, Slow e Impulse según IEC 61672-1."
+description: "El detector exponencial de IEC 61672-1:2013: las constantes de tiempo Fast y Slow, la balística Impulse heredada que esa norma retiró, la verificación con ráfaga de tono frente a la Tabla 4, las opciones de estado inicial y el streaming entre bloques."
references:
- type: standard
organization: "International Electrotechnical Commission"
@@ -184,7 +184,9 @@ $$
| `x` | array 1D o 2D | presión (cualquier escala) | no vacío | Se eleva al cuadrado internamente; la salida es una envolvente cuadrática media |
| `fs` | int | Hz | > 0 | |
| `mode` | str | — | `'fast'` (por defecto), `'slow'`, `'impulse'` | $\tau$ = 125 ms / 1 s / ataque de 35 ms + caída de 1,5 s |
+| `initial_state` | `None` / `'zero'` / `'first'` / float / array | cuadrado medio de $x$ | por defecto `None` (= `'zero'`) | Estado del integrador $y[-1]$; ver los apartados 5 y 6 |
| `TimeWeighting(fs, mode)` (clase) | — | — | — | Variante con estado para streaming: `process(x)` conserva el estado del integrador entre bloques |
+| `TimeWeighting.reset()` | — | — | — | Descarta el estado arrastrado para que el siguiente `process()` arranque del reposo |
La salida tiene las unidades de $x^2$: toma `10*log10(y / p0**2)` para SPL o
usa las funciones de nivel, que lo hacen por ti.
@@ -232,11 +234,30 @@ plt.show()
## 5. Estado inicial
-Por defecto, el integrador exponencial parte del reposo (`y[-1] = 0`). Pasar
-`initial_state=None` deja ese comportamiento por defecto, mientras que
-`initial_state='zero'` lo solicita explícitamente. Si el segmento grabado
-comienza con una señal estacionaria ya presente, puedes partir de la energía de
-la primera muestra:
+El integrador necesita un valor de partida para $y[-1]$, y hay cuatro maneras
+de dárselo.
+
+- **`None` (el valor por defecto) y `'zero'` son lo mismo**, un arranque desde
+ el reposo, así que el nivel sube por la rampa de establecimiento del
+ apartado 1.
+- **`'first'` lo siembra con el cuadrado de la primerísima muestra**, $x[0]^2$.
+ Es una estimación insesgada pero extremadamente ruidosa del cuadrado medio
+ (un grado de libertad) y, para un tono, depende por completo de la fase en el
+ corte. En el fragmento de abajo vale *exactamente cero*, porque un seno que
+ empieza en $t = 0$ empieza en un paso por cero, así que ahí `'first'` es
+ idéntico bit a bit a `'zero'`.
+- **Un float** reanuda un estado que hayas guardado tú, que es lo que hace el
+ procesado por bloques del apartado 6.
+- **Un array** difundible a la forma de la entrada sin el eje temporal hace lo
+ mismo por canal.
+
+Si el registro es la continuación de una señal que ya venía sonando, siembra el
+integrador con algo robusto: el cuadrado medio del primer medio segundo,
+`initial_state=float(np.mean(recording[:fs // 2] ** 2))`, es una estimación
+mucho mejor que una muestra suelta. Si el registro es el *comienzo* del suceso,
+no siembres nada: deja que arranque del reposo y descarta los primeros $5\tau$
+(0,6 s en Fast, 5 s en Slow), que es exactamente lo que `ln_levels` hace por
+dentro antes de calcular percentiles.
```python
import numpy as np
@@ -246,7 +267,10 @@ from phonometry import filters
fs = 48000
recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
-energy_envelope = filters.time_weighting(recording, fs, mode='fast', initial_state='first')
+# Semilla robusta: el cuadrado medio del primer medio segundo, no una muestra.
+energy_envelope = filters.time_weighting(
+ recording, fs, mode='fast',
+ initial_state=float(np.mean(recording[:fs // 2] ** 2)))
```
## 6. Procesado por bloques
diff --git a/site/src/content/docs/es/signals/metrology/calibration.mdx b/site/src/content/docs/es/signals/metrology/calibration.mdx
index ba5ae1802..f6c31e35d 100644
--- a/site/src/content/docs/es/signals/metrology/calibration.mdx
+++ b/site/src/content/docs/es/signals/metrology/calibration.mdx
@@ -50,7 +50,7 @@ y vuelve a comprobarlo después de cada sesión, verifica sonómetro y
calibrador periódicamente en laboratorio (IEC 61672-3 e IEC 60942; Bies,
Hansen y Howard 2017, §3.4) y trata la diferencia pre/post como tu cota de
deriva. La sección de
-[campo, laboratorio y deriva](#comprobaciones-de-campo-verificación-de-laboratorio-y-deriva)
+[campo, laboratorio y deriva](#comprobaciones-verificacion-y-deriva)
de más abajo convierte eso en reglas concretas, y el recorrido
[Construye un sonómetro](/phonometry/es/signals/sound-level-meter/) empieza
exactamente en este paso antes de calcular ningún nivel.
@@ -75,11 +75,14 @@ nada cambie en la cadena: si tocas la ganancia, recalibra.
-## Calibración física (sonómetro)
+## Calibrar una grabación de principio a fin
-Para obtener mediciones SPL precisas a partir de una grabación digital, primero
-debes calcular la sensibilidad de tu cadena de medición usando un tono de
-referencia (p. ej. 94 dB @ 1 kHz).
+Los tres pasos de abajo son todo el flujo de trabajo de SPL físico: una toma del
+calibrador, una llamada a `sensitivity()` y el factor entregado a una función de
+nivel. Las dos grabaciones tienen que venir de la misma cadena sin tocar nada
+entre medias. El mismo factor funciona en toda la librería: `octave_filter` y
+`OctaveFilterBank` lo reciben dentro de `LevelCalibration(factor=...)`, y `leq`,
+`laeq` y `ln_levels` como `calibration_factor=`.
@@ -103,13 +106,9 @@ calibration_factor = metrology.sensitivity(calibrator_recording, target_spl=94.0
spl, freq = filters.octave_filter(
recording, fs,
calibration=filters.LevelCalibration(factor=calibration_factor))
-# ¡Ahora los valores de 'spl' son dB SPL reales!
+# spl está ahora en dB SPL re 20 µPa
```
-El mismo factor funciona en toda la librería: `octave_filter` y
-`OctaveFilterBank` lo reciben dentro de `LevelCalibration(factor=...)`, y `leq`,
-`laeq` y `ln_levels` como `calibration_factor=`.
-
## Supuestos del calibrador (IEC 60942)
`sensitivity` asume que la grabación de referencia procede de un
@@ -132,11 +131,20 @@ Si pasas la frecuencia de muestreo (y `validate=True`, el valor por defecto),
IEC 60942:2017 comprueba el calibrador (5.3.3): la *fluctuación de nivel a
corto plazo*, el valor absoluto de la diferencia entre cada uno de los niveles
máximo y mínimo con ponderación temporal F y el nivel medio, no debe superar
-el límite de clase 1 de la Tabla 2 para la frecuencia nominal del calibrador
-(0,07 dB desde 160 Hz, relajado a 0,10 dB por debajo de 160 Hz y a 0,20 dB por
-debajo de 63 Hz, donde la propia ponderación F ondula). Pasa `frequency=` para
-seleccionar la fila correcta en calibradores que no sean de 1 kHz. Un
-`CalibrationWarning` delata micrófonos mal acoplados o ruido de manipulación
+el límite de clase 1 de la Tabla 2 para la frecuencia nominal del calibrador.
+La Tabla 2 da tres filas disjuntas, y no deben leerse como rangos solapados:
+
+| Frecuencia nominal | Límite de clase 1 | |
+| :--- | :---: | :--- |
+| 160 Hz a 16 kHz | 0,07 dB | la fila estricta, y con la que se juzga un calibrador de 1 kHz |
+| por encima de 63 Hz y por debajo de 160 Hz | 0,10 dB | |
+| 31,5 Hz a 63 Hz | 0,20 dB | donde la propia ponderación temporal F ondula sobre el tono |
+
+La Tabla 2 abarca de 31,5 Hz a 16 kHz y no especifica nada fuera de ese rango,
+así que una `frequency` por debajo de 31,5 Hz o por encima de 16 kHz recae en
+los 0,07 dB estrictos y no en las filas relajadas de baja frecuencia. Pasa
+`frequency=` para seleccionar la fila correcta en calibradores que no sean de
+1 kHz. Un `CalibrationWarning` delata micrófonos mal acoplados o ruido de manipulación
antes de que corrompan silenciosamente todos los niveles calibrados. La
grabación debe durar al menos 2 s (1 s para que el integrador F se asiente más
1 s de envolvente estable); con grabaciones más cortas se avisa en lugar de dar
@@ -197,6 +205,8 @@ Devuelve el factor de sensibilidad (float) para pasarlo como
funciones de dosis, y como `calibration=LevelCalibration(factor=...)` a
`octave_filter`.
+
+
## Comprobaciones de campo, verificación de laboratorio y deriva
La calibración vive en tres escalas de tiempo:
@@ -257,13 +267,17 @@ spl_dbfs, freq = filters.octave_filter(
# Los resultados serán negativos (p. ej. -20 dBFS)
```
-## RMS vs niveles de pico
+## RMS frente a niveles de pico
-phonometry admite dos modos de medición, alineados con software profesional
-como BK:
+Los niveles se pueden leer de dos maneras, y las dos se usan en los analizadores
+comerciales:
-- **RMS (`mode='rms'`)**: nivel energético (estándar).
-- **Pico (`mode='peak'`)**: máximo absoluto alcanzado en el frame (peak-holding).
+- **RMS (`mode='rms'`)** integra energía sobre el frame, que es sobre lo que
+ está definido todo nivel normalizado ($L_{eq}$, $L_{Aeq}$, $L_N$).
+- **Pico (`mode='peak'`)** retiene el mayor valor instantáneo del frame, que es
+ contra lo que se comprueban los criterios de impacto y de límite de pico como
+ $L_{Cpeak}$. Ojo: el pico de banda que se devuelve aquí está limitado en banda
+ y sin ponderar, así que no es en sí mismo $L_{Cpeak}$.
```python
import numpy as np
@@ -289,9 +303,19 @@ del procesado.
## Entrada de audio entero
Las señales enteras (p. ej. int16 de `scipy.io.wavfile.read`) se convierten
-internamente a float64 antes de cualquier elevación al cuadrado, así que la
-calibración y los niveles son idénticos tanto si pasas el array entero crudo
-como una conversión a float.
+internamente a float64 antes de cualquier elevación al cuadrado. La conversión
+es un cambio de dtype, no un reescalado: una muestra int16 de +32767 entra como
+32767.0, no como 1.0. Eso es inofensivo *mientras la grabación del calibrador y
+la medición estén en el mismo formato*, porque entonces `sensitivity` devuelve
+un factor 32768 veces menor y los dos se cancelan exactamente: un tono que marca
+87,958 dB desde arrays float marca 87,958 dB desde los arrays int16 de las
+mismas grabaciones. No es inofensivo en el caso contrario: el mismo tono leído
+sin calibrar da 87,94 dB como float y 172,14 dB como int16, una desviación de
+$20\log_{10}(32768) = 90{,}3$ dB, y aplicar una sensibilidad derivada de float a
+una medición leída como entero (o al revés) arrastra esa desviación al resultado
+sin ningún síntoma. O se mantienen las dos grabaciones en un solo formato, o se
+dividen las dos por el valor de fondo de escala (`x / 32768.0` para int16) antes
+de nada.
## Qué cubre esta guía
diff --git a/site/src/content/docs/es/signals/sound-level-meter.mdx b/site/src/content/docs/es/signals/sound-level-meter.mdx
index 6bb3223e9..c5339e15a 100644
--- a/site/src/content/docs/es/signals/sound-level-meter.mdx
+++ b/site/src/content/docs/es/signals/sound-level-meter.mdx
@@ -26,6 +26,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
Un sonómetro no es un algoritmo, sino una breve cadena de ellos, e
IEC 61672-1 especifica cada etapa. phonometry implementa cada etapa como una
@@ -86,8 +87,15 @@ cal = metrology.sensitivity(calibrator, target_spl=94.0, fs=fs)
```
Guía de fondo: [Calibración y dBFS](/phonometry/es/signals/metrology/calibration/), que
-cubre también la calibración desde una sensibilidad de micrófono conocida y
-el modo digital dBFS que se usa cuando no existe referencia física.
+cubre la comprobación de estabilidad que esta llamada ejecuta sobre la grabación
+del calibrador, la regla del formato entero y el modo digital dBFS que se usa
+cuando no existe referencia física. Sin ningún calibrador, el factor puede
+calcularse a partir de la sensibilidad nominal de la cadena en vez de medirse
+— un micrófono de sensibilidad nominal $M$ mV/Pa a través de un preamplificador
+de ganancia lineal $G$ hacia un convertidor cuyo fondo de escala es $V_{FS}$
+voltios da $S = V_{FS} / (M G / 1000)$ pascales por unidad digital —, pero un
+factor nominal arrastra la tolerancia de la hoja de datos y no los ±0,4 dB de un
+calibrador de clase 1, así que no puede informarse como una medición calibrada.
## 3. Pondera: frecuencia y tiempo (IEC 61672-1)
@@ -105,16 +113,30 @@ laf_t = 10 * np.log10(np.maximum(envelope, 1e-12) / (2e-5) ** 2)
# laf_t alcanza unos 80 dB durante el evento y se asienta cerca de 55 dB entre medias.
```
-Rara vez escribirás esta cadena a mano: todas las funciones de nivel del paso
-siguiente aplican la ponderación frecuencial internamente, y los niveles
-percentiles reconstruyen por ti esta envolvente Fast. Las métricas de energía
-($L_{eq}$, SEL) integran directamente la señal ponderada al cuadrado, sin
-balística, exactamente como hace un sonómetro. La cadena se muestra aquí
-porque *es* la pantalla del sonómetro.
+
+
+La aguja del clip es esa llamada a `time_weighting`: un paso bajo de primer
+orden que se carga y se descarga sobre la señal al cuadrado. Las tres agujas se
+diferencian en un solo número, la constante de tiempo, y por eso Fast atrapa un
+evento que Slow suaviza hasta borrarlo. Rara vez escribirás esta cadena a mano:
+todas las funciones de nivel del paso siguiente aplican la ponderación
+frecuencial internamente, y los niveles percentiles reconstruyen por ti esta
+envolvente Fast. Las métricas de energía ($L_{eq}$, SEL) integran directamente
+la señal ponderada al cuadrado, sin balística ninguna — y por eso no muestran
+ningún movimiento de aguja al que seguir. La cadena se muestra aquí porque *es*
+la pantalla del sonómetro.
Guías de fondo:
[Ponderación frecuencial (A, C, Z)](/phonometry/es/signals/levels/weighting/) y
-[Ponderación temporal](/phonometry/es/signals/levels/time-weighting/).
+[Ponderación temporal](/phonometry/es/signals/levels/time-weighting/), que
+desmonta este mismo clip frente a la tabla de ráfagas de tono de
+IEC 61672-1.
## 4. Integra: los números que reporta un sonómetro
@@ -137,11 +159,18 @@ print(f"LAeq {la_eq:.1f} dB | L10 {ln[10]:.1f} | L90 {ln[90]:.1f} "
f"| LAE {lae:.1f} | LCpeak {lc_pk:.1f}")
```
-Fíjate en la aritmética que codifican los números: el evento de 1 s domina
-el $L_{Aeq}$ (está 25 dB por encima del fondo, mucho más de los 10 dB que el
-fondo, nueve veces más largo, recupera por duración), el $L_{AE}$ es el
-$L_{Aeq}$ más $10\log_{10}$ de los 10 s de duración, y el $L_{90}$ apenas nota el
-evento.
+Fíjate en la aritmética que codifican los números. El segundo del evento mide
+80,0 dB por sí solo y los nueve segundos de fondo 55,0 dB, así que en energía el
+evento aporta $1 \times 10^{8{,}00}$ y el fondo
+$9 \times 10^{5{,}50} = 2{,}9 \times 10^{6}$: una razón de unos 35:1, o 15,5 dB.
+La ventaja de 25 dB del evento gana a los 9,5 dB ($10\log_{10}9$) que el fondo
+recupera por duración, y por eso el $L_{Aeq}$ de 10 s de 70,2 dB queda solo
+0,1 dB por encima de los 70,0 dB que daría el evento solo repartido sobre esos
+mismos 10 s: el fondo es casi invisible en el promedio energético. El $L_{AE}$
+es ese $L_{Aeq}$ más $10\log_{10}(10\ \mathrm{s}/1\ \mathrm{s}) = 10$ dB, toda
+la energía comprimida en un segundo. Los percentiles se leen al revés: el evento
+ocupa exactamente el 10 % del registro, así que sube el $L_{10}$ a 78,0 dB y
+deja el $L_{90}$ en 54,9 dB, el nivel de fondo.
Guía de fondo:
[Niveles integrados y estadísticos](/phonometry/es/signals/levels/levels/), que añade
diff --git a/site/src/content/docs/es/signals/spectra/time-frequency.mdx b/site/src/content/docs/es/signals/spectra/time-frequency.mdx
index 69eff8036..89c00c879 100644
--- a/site/src/content/docs/es/signals/spectra/time-frequency.mdx
+++ b/site/src/content/docs/es/signals/spectra/time-frequency.mdx
@@ -77,8 +77,16 @@ res.plot(language="es") # imagen en dB en el plano tiempo-frecuencia
La longitud del segmento es toda la decisión de diseño:
$T_B = \text{nperseg}/f_s$ de resolución temporal contra
-$B_e \approx 1/T_B$ de resolución frecuencial, un
-producto igual a uno (sección 12.6.4.2). Los segmentos largos fijan las
+$B_e = \mathrm{ENBW}/T_B$ de resolución frecuencial, así que su producto
+$T_B B_e$ lo fija solo la ventana: 1 para una ventana rectangular y **1,5 para
+la Hann por defecto que se usa aquí** (sección 12.6.4.2, y las figuras de
+mérito de ventana de la
+[página de análisis espectral](/phonometry/es/signals/spectra/spectral-analysis/#6-elegir-la-ventana)).
+El diagrama de teselado de arriba dibuja el caso sin ventana, donde ese
+producto vale exactamente uno. Partir por la mitad la longitud del segmento
+compra el doble de resolución temporal y cuesta exactamente la mitad de
+resolución frecuencial; nada compra las dos.
+Los segmentos largos fijan las
frecuencias y emborronan los transitorios; los cortos, lo contrario. Y como
cada celda es una única estimación *sin promediar*, los datos aleatorios
llevan un error aleatorio normalizado de 1 por celda (ec. 8.158 con
@@ -173,8 +181,10 @@ Una distinción importa y el resultado la declara: la **malla** puede
hacerse arbitrariamente fina (`n_points`), pero la **resolución** - la
capacidad de separar dos tonos - la fijan la longitud del registro y la
ventana, informada como `resolution_bandwidth`
-($B_e = f_s \sum w^2/(\sum w)^2$, es decir, $1/T$ sin ventana, $1{,}5/T$
-con Hann). El
+($B_e = f_s \sum w^2/(\sum w)^2$, es decir, $1/T_r$ sin ventana y $1{,}5/T_r$
+con Hann; el mismo factor de ventana del apartado 1, aplicado aquí a la
+duración del registro $T_r$ en lugar de a un segmento, porque la FFT con zoom
+transforma el registro entero). El
zoom refina el muestreo del mismo espectro subyacente; solo un registro
más largo separa tonos más próximos.
diff --git a/site/src/content/docs/es/simulation/elastic-waves.mdx b/site/src/content/docs/es/simulation/elastic-waves.mdx
index 31b5e3cca..7639cfcaf 100644
--- a/site/src/content/docs/es/simulation/elastic-waves.mdx
+++ b/site/src/content/docs/es/simulation/elastic-waves.mdx
@@ -49,6 +49,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
Un fluido transporta una onda; un sólido, una familia de ellas. Esta guía
cubre el compañero elástico de la
@@ -208,13 +209,27 @@ plt.show()
-Esa onda de flexión merece verse en movimiento: la
+Esa onda de flexión merece verse en movimiento. El clip de abajo es este mismo
+solucionador lanzando un paquete de flexión de 4 kHz por una placa de acero de
+10 mm: en el panel de control la placa sigue recta y el paquete simplemente se
+marcha, y en el panel de la unión una placa perpendicular del mismo espesor
+convierte la esquina en un dispersor. Allí el paquete se parte en las ondas de
+flexión reflejada y transmitida que la forma cerrada tasa en
+$\tau_{12}(0°) = 0{,}5$, más el rápido precursor de onda en el plano que corre
+por delante por la placa receptora: la conversión de modo que el modelo de unión
+articulada deja fuera a propósito, y la razón por la que esta página necesita un
+solucionador elástico y no uno de flexión. La
[guía de transmisión de onda de flexión](/phonometry/es/vibration/structural/junction-transmission/)
-incrusta una animación de este solucionador lanzando un paquete de flexión
-de 4 kHz por una placa de acero de 10 mm hasta una unión en L, donde la
-esquina lo divide en las ondas reflejada y transmitida que la forma cerrada
-tasa en $\tau_{12}(0°) = 0{,}5$, más el rápido precursor de onda en el plano que
-el modelo de unión articulada deja fuera a propósito.
+desmonta esa misma ejecución frente al índice de reducción vibracional de
+EN 12354.
+
+
## 4. Acoplamiento fluido-sólido a incidencia normal
@@ -366,13 +381,33 @@ somete a esfuerzo el contraste extremo de un contacto aire-acero (razón de
impedancias ~$10^5$:1): estable durante 10 000 pasos con la amplitud
reflejada conservada al 0,5 %.
-A incidencia oblicua la física de la placa se enriquece, y la
+A incidencia oblicua la física de la placa se enriquece, y el clip de abajo es
+este solucionador excitando la misma placa de acero de 10 mm, ahora tendida en
+aire, con una onda plana sostenida que llega a 45°. Los dos paneles se
+diferencian en **un solo número**: la frecuencia de excitación, $f_c/2 = 603$ Hz
+a la izquierda y $2 f_c = 2413$ Hz a la derecha, a un lado y otro de la
+frecuencia de coincidencia de 1206 Hz que la librería calcula con los mismos
+$m''$ y $B'$ usados más arriba. Todo lo demás (la placa, el ángulo, la malla y
+la escala de color) se mantiene fijo. Por debajo de $f_c$ la placa refleja casi
+todo y el nivel transmitido cae sobre la ley de masas oblicua; por encima, la
+longitud de onda de traza acústica coincide con la longitud de onda de flexión
+libre, la placa re-radia un haz a 45° que crece a lo largo del tramo iluminado y
+el nivel transmitido se mantiene en la cifra de baja frecuencia, justo donde la
+ley de masas exigía 12 dB más de bloqueo. El aire bajo la placa se dibuja en los
+dos paneles con la ganancia de visualización que `_weak_field_gain` mide sobre
+el campo asentado de las dos ejecuciones juntas (×150, es decir, +44 dB) y que
+se imprime en el lienzo: lee las *anotaciones* para los niveles, no el brillo.
+La
[guía de predicción del aislamiento de paneles](/phonometry/es/buildings/design/panel-sound-insulation/)
-incrusta la animación: este solucionador excitando la misma placa de acero
-de 10 mm, tendida en aire, con una onda plana sostenida a 45° por debajo y
-por encima de su frecuencia de coincidencia, donde la onda de flexión con
-la traza adaptada re-radia un haz creciente y mantiene el nivel transmitido
-en el punto donde la ley de masas exige 12 dB más de bloqueo.
+desmonta esa misma ejecución frente al método de la meseta y a la ley de masas.
+
+
## Qué cubre esta guía
diff --git a/site/src/content/docs/es/simulation/fdtd-simulation.mdx b/site/src/content/docs/es/simulation/fdtd-simulation.mdx
index 6914c5940..bccb3fb05 100644
--- a/site/src/content/docs/es/simulation/fdtd-simulation.mdx
+++ b/site/src/content/docs/es/simulation/fdtd-simulation.mdx
@@ -37,6 +37,7 @@ references:
---
import ThemeImage from '../../../../components/ThemeImage.astro';
+import Video from '../../../../components/Video.astro';
La mayor parte de phonometry predice un **número**: un nivel, un tiempo de
reverberación, una pérdida por transmisión. El dominio `simulation` calcula el
@@ -60,6 +61,33 @@ las animaciones FDTD de esta documentación, promocionado a API pública con
fuentes, sondas de presión, obstáculos rasterizados, condiciones de contorno
por lado y un objeto de resultado congelado.
+Aquí tienes una de esas animaciones, y es un anuncio honesto de lo que
+construye el resto de la página. En ella no hay nada dibujado: la columnata es
+una `obstacle_mask` booleana de círculos rasterizados y el frente de onda es un
+único paquete de onda plana unidireccional con una envolvente gaussiana de una
+longitud de onda de ancho, lanzado en $x = 0{,}30$ m dentro de una sala de
+4 m × 1 m de paredes rígidas cuyos dos extremos absorben mediante esponjas
+ocultas fuera del encuadre. La portadora es de 800 Hz, así que la longitud de
+onda es de 42,9 cm y las columnas de 10 a 17 cm son aproximadamente de un cuarto
+a dos quintos de ella: el régimen en el que un cilindro rígido a la vez proyecta
+una sombra legible y rerradia con fuerza, que es la razón por la que la cola que
+llena la sala está estructurada y no es ruido. Esa cola es dispersión múltiple
+determinista: es el aspecto que tiene un campo difuso *antes* de hacer ninguna
+hipótesis estadística sobre él. La malla es el ejemplo resuelto de la regla que
+deduce la [sección 4](#dispersion-numerica-y-precision): el hueco más
+estrecho de esta disposición es de 6,6 cm entre una columna y una pared, así que
+$\Delta x = \min(\text{apertura más pequeña}/4,\ \lambda/8)$ permite hasta
+1,6 cm, y el clip corre a 2,5 mm porque un banner necesita la definición.
+
+
+
## 1. El esquema: una ecuación de onda sobre una malla
@@ -94,10 +122,13 @@ $$
= \frac{c\,\Delta t\,\sqrt{2}}{\Delta x} \le 1,
$$
-y `fdtd_simulation` deriva el paso temporal del parámetro `cfl` (el número de
-Courant, por defecto 0,6) y de la mayor velocidad del sonido del mapa; los
+y `fdtd_simulation` deriva el paso temporal del parámetro `cfl` (este
+$\mathrm{CN}$, por defecto 0,6) y de la mayor velocidad del sonido del mapa; los
valores fuera de $(0, 1)$ se rechazan porque el esquema carece de sentido
-más allá del límite (Ec. 4.14).
+más allá del límite (Ec. 4.14). La sección 4 usa además un número de Courant
+*por eje*, $S = c\,\Delta t/\Delta x = \mathrm{CN}/\sqrt{2}$, en la relación de
+dispersión; los dos no son el mismo número, y el `cfl = 0.6` por defecto
+significa $S = 0{,}424$.
```python
from phonometry import simulation
@@ -525,6 +556,8 @@ de una sala 3D. Trate las ejecuciones 2D como secciones y demostraciones, y
valide cualquier afirmación cuantitativa 3D contra una forma cerrada o un
solucionador 3D.
+
+
## 4. Dispersión numérica y precisión
La malla discreta propaga cada frecuencia a una velocidad ligeramente
@@ -542,7 +575,10 @@ $$
con un error relativo de frecuencia a primer orden de magnitud
$(1 - S^2)\,(k\,\Delta x)^2 / 24$ sobre los ejes de la malla (la frecuencia
modelada queda por debajo de la real, así que el error con signo es
-negativo), con $S = c\,\Delta t / \Delta x$; el error es máximo exactamente sobre un
+negativo), donde $S = c\,\Delta t / \Delta x$ es el número de Courant **por
+eje**, que con celdas cuadradas es el valor de `cfl` dividido por $\sqrt{2}$:
+el `cfl = 0.6` por defecto da $S = 0{,}424$ y $1 - S^2 = 0{,}82$; el error es
+máximo exactamente sobre un
eje y se anula a lo largo de la diagonal de las celdas en el límite de
Courant $\mathrm{CN} = 1$. La regla práctica es resolver **al menos 10 celdas por
longitud de onda más corta**, $\Delta x \le c_\text{min} / (10 f_\text{max})$ con la velocidad
@@ -632,7 +668,9 @@ $\Delta x \le c_\text{min} / (10 f_\text{max})$, con la velocidad de sonido
más baja del
dominio. Con exactamente 10 celdas la cota del error de dispersión sobre el
eje es alrededor del 1,6 %, reducida a en torno al 1,4 % con el
-``cfl = 0.6`` por defecto, y reducir $\Delta x$ a la mitad divide el error entre
+``cfl = 0.6`` por defecto (el número de Courant por eje es entonces
+$S = \mathrm{cfl}/\sqrt{2} = 0{,}424$, así que el factor $1 - S^2$ vale 0,82), y
+reducir $\Delta x$ a la mitad divide el error entre
cuatro (el esquema es de segundo orden). Con $\Delta x = 1$ cm el punto de 10
celdas en aire queda hacia los 3,4 kHz.
@@ -642,8 +680,11 @@ El esquema explícito solo es estable mientras un frente de onda cruce como
mucho una celda por paso temporal. Con celdas cuadradas el número de Courant
es $\mathrm{CN} = c\,\Delta t\,\sqrt{2}/\Delta x \le 1$ (Attenborough y Van
Renterghem, Ec. 4.13). `fdtd_simulation` deriva el paso temporal del
-parámetro `cfl` (el número de Courant, por defecto 0,6) y de la mayor
-velocidad del sonido del mapa, y rechaza los valores fuera de $(0, 1)$.
+parámetro `cfl` (ese mismo $\mathrm{CN}$, por defecto 0,6) y de la mayor
+velocidad del sonido del mapa, y rechaza los valores fuera de $(0, 1)$. El
+número de Courant *por eje* de la relación de dispersión de más arriba es un
+número distinto, $S = c\,\Delta t/\Delta x = \mathrm{CN}/\sqrt{2}$, que vale
+0,424 con el valor por defecto.
### ¿Puedo fiarme de los niveles absolutos de una ejecución FDTD 2D?
diff --git a/site/src/content/docs/es/simulation/index.md b/site/src/content/docs/es/simulation/index.md
index 4e649eff2..67a4908ff 100644
--- a/site/src/content/docs/es/simulation/index.md
+++ b/site/src/content/docs/es/simulation/index.md
@@ -41,6 +41,38 @@ recurso que aún da una respuesta cuantitativa; cuando existe una forma
cerrada, prefiérela, y usa el solucionador para verificar las hipótesis en
las que se apoya.
+Esos contrastes no son solo argumentos: quince de las animaciones de esta
+documentación son salida de estos dos solucionadores, y están archivadas en las
+guías cuya física zanjan y no aquí. Los modos de sala creciendo en resonancia y
+fuera de ella aparecen en
+[acústica de salas](/phonometry/es/buildings/rooms/room-acoustics/) y en
+[predicción de la reverberación](/phonometry/es/buildings/rooms/reverberation-prediction/),
+que además lleva la sala de columnas que convierte un solo frente de onda en un
+campo mezclado; la difracción por barrera a dos longitudes de onda, en
+[propagación en exteriores](/phonometry/es/environment/propagation/outdoor-propagation/)
+y en [efecto del suelo y barreras](/phonometry/es/environment/propagation/ground-barriers/);
+la refracción a favor y en contra del viento, en
+[refracción atmosférica](/phonometry/es/environment/propagation/atmospheric-refraction/);
+el patrón de lóbulos del efecto del suelo, en propagación en exteriores y en
+[ruido de aeropuerto](/phonometry/es/aircraft/airport-noise/); los tubos de onda
+estacionaria y de transmisión, en
+[el tubo de impedancia](/phonometry/es/materials/absorbers/impedance-tube/); los
+paneles QRD y de metadifusor, en
+[difusores](/phonometry/es/materials/diffusers/diffusers/) y
+[metadifusores](/phonometry/es/materials/diffusers/metadiffusers/); el absorbente
+de rendija, en [absorbentes metamateriales](/phonometry/es/materials/absorbers/metamaterial-absorbers/);
+la cámara de expansión, en [silenciadores](/phonometry/es/devices/noise-control/silencers/);
+la abertura en la pared, en
+[aislamiento acústico de paneles](/phonometry/es/buildings/design/panel-sound-insulation/);
+y el canal SOFAR, en
+[propagación submarina](/phonometry/es/underwater/underwater-propagation/). El
+solucionador elástico aporta dos más: el paquete de flexión que entra en una
+unión en L, en
+[transmisión en uniones](/phonometry/es/vibration/structural/junction-transmission/),
+y la placa en coincidencia, en aislamiento acústico de paneles. Las dos aparecen
+también en la página elástica de más abajo, donde se explica el solucionador que
+las produjo.
+
## Páginas de esta sección
- [Simulación de ondas FDTD 2D](/phonometry/es/simulation/fdtd-simulation/): el
diff --git a/site/src/content/docs/es/start/getting-started.mdx b/site/src/content/docs/es/start/getting-started.mdx
index 5978ed064..34d0c1011 100644
--- a/site/src/content/docs/es/start/getting-started.mdx
+++ b/site/src/content/docs/es/start/getting-started.mdx
@@ -74,9 +74,9 @@ las guías las recorren de izquierda a derecha ([Calibración](/phonometry/es/si
[Ponderación frecuencial](/phonometry/es/signals/levels/weighting/) → [Bancos de filtros](/phonometry/es/signals/filters/filter-banks/) →
[Ponderación temporal](/phonometry/es/signals/levels/time-weighting/) → [Niveles](/phonometry/es/signals/levels/levels/)).
-## Uso básico: análisis en tercios de octava
+## Un primer análisis: bandas de tercio de octava (sin calibrar)
-Analiza una señal y obtén el nivel de presión acústica (SPL) por banda de frecuencia.
+Divide una señal en bandas de tercio de octava y lee el nivel de cada una.
```python
import numpy as np
@@ -93,12 +93,30 @@ spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
print(f"Bandas: {freq}")
# Bandas: [12.589254117941678, 15.848931924611138, ..., 19952.623149688785] (33 bandas)
print(f"SPL [dB]: {spl}")
-# SPL [dB]: [46.88395351 47.96774897 49.04991279 ...] — ~90.7 dB en 100 Hz y ~90.9 dB en 1 kHz
+# SPL [dB]: [46.88395351 47.96774897 49.04991279 ...] — 90,71 dB en 100 Hz y 90,95 dB en 1 kHz
```
-
-
-*Ejemplo de análisis espectral en tercios de octava de una señal compleja.*
+**Todavía no son niveles físicos.** `octave_filter` devuelve siempre
+$20\log_{10}(p_\mathrm{rms} / 20\,\mu\mathrm{Pa})$ y, con la calibración por
+defecto, toma el valor numérico de cada muestra *como si fuera* la presión en
+pascales. Una senoide de amplitud unidad se lee, por tanto, como 0,7071 Pa
+eficaces, es decir 90,97 dB: exactamente correcto para una señal sintética
+definida en pascales, y exactamente incorrecto para una grabación, cuyas
+muestras valen lo que hayan dado el convertidor y la cadena de ganancia. Hay dos
+formas honestas de obtener un nivel defendible. Pasa el factor de pascales por
+unidad digital obtenido con un tono de calibrador,
+`calibration=filters.LevelCalibration(factor=S)` (consulta
+[Calibración y dBFS](/phonometry/es/signals/metrology/calibration/)), o, cuando
+la señal nunca tuvo escala física, pide `LevelCalibration(dbfs=True)` y lee
+niveles referidos a fondo de escala digital, que salen negativos y no se pueden
+confundir con un SPL.
+
+
+
+*Un ejemplo más rico que el fragmento de arriba: seis tonos (20, 100, 500, 2000,
+4000 y 15000 Hz) de amplitud 100, así que los niveles de banda llegan a unos
+131 dB. La curva gris es la PSD de la señal cruda, desplazada hacia abajo para
+compartir el eje.*
Mostrar el código de esta figura
@@ -110,15 +128,16 @@ import numpy as np
from phonometry import filters
fs = 48000
-t = np.linspace(0, 1, fs, endpoint=False)
-# Señal compuesta: 100 Hz + 1000 Hz
-signal = np.sin(2 * np.pi * 100 * t) + np.sin(2 * np.pi * 1000 * t)
+t = np.linspace(0, 5, 5 * fs, endpoint=False)
+# Seis tonos de amplitud 100, así que las bandas quedan en torno a 130 dB
+tones = [20, 100, 500, 2000, 4000, 15000]
+y = 100 * np.sum([np.sin(2 * np.pi * f * t) for f in tones], axis=0)
# Aplicar el banco de filtros de 1/3 de octava
-spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
+spl, freq = filters.octave_filter(y, fs=fs, fraction=3, limits=[12.0, 20000.0])
# Fondo gris: la PSD de la señal cruda (Welch), desplazada justo por debajo
# de los SPL de banda para comparar ambas formas espectrales en un mismo eje.
-f_psd, psd = scipy.signal.welch(signal, fs, nperseg=8192)
+f_psd, psd = scipy.signal.welch(y, fs, nperseg=8192)
psd_db = 10 * np.log10(psd + 1e-12)
psd_db += np.max(spl) - np.max(psd_db) - 5
@@ -128,7 +147,8 @@ ax.semilogx(freq, spl, marker="o", markerfacecolor="white",
label="Bandas de 1/3 de octava")
ax.set_xlabel("Frecuencia [Hz]")
ax.set_ylabel("SPL [dB]")
-ax.legend()
+ax.set_xlim(11, 25000)
+ax.legend(loc="lower right")
plt.show()
```
@@ -143,25 +163,56 @@ from phonometry import filters
# Cargar un archivo WAV estándar
fs, signal = wavfile.read("measurement.wav")
+# wavfile.read devuelve (muestras, canales); el banco espera (canales, muestras)
+if signal.ndim > 1:
+ signal = signal[:, 0] # micrófono de medida en el canal 1
+
# Analizar
# Nota: para obtener valores SPL reales debes calibrar la entrada.
# Consulta la guía de calibración.
spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
```
-El audio entero (por ejemplo, datos int16 de un WAV) se convierte internamente a
-float64, así que es seguro pasar directamente la salida de `wavfile.read`.
+**Reduce un archivo multicanal al canal con el que mediste, o traspónlo.** La
+guarda de arriba no es adorno: `wavfile.read` devuelve un array
+`(muestras, canales)` y el banco lee un array 2D como `(canales, muestras)`.
+Pasa un archivo estéreo tal cual y no salta nada: un array estéreo de 2400
+muestras devuelve un `spl` de forma `(2400, 33)`, un espectro por cada *par de
+muestras*, y un archivo de un segundo tarda minutos en producir números sin
+sentido. Consulta
+[Multicanal y rendimiento](/phonometry/es/signals/filters/multichannel/) para el
+convenio, y para el caso en que se analizan varios canales calibrados a la vez,
+cada uno con su propia sensibilidad.
+
+**El audio entero se convierte de tipo, no se reescala.** La salida de
+`wavfile.read` se ejecuta sin error porque los enteros se convierten
+internamente a float64, pero una muestra int16 de +32767 entra en el banco como
+32767.0 y no como 1.0. Todos los niveles salen, por tanto,
+$20\log_{10}(32768) = 90{,}3$ dB por encima de los de la misma señal leída como
+float: medido, una senoide de 1 kHz de amplitud unidad tiene su máximo en
+90,95 dB y esa misma senoide escrita en int16 lo tiene en 181,26 dB. Divide por
+el valor de fondo de escala (`signal / 32768.0` para int16) antes de analizar, o
+deja que lo absorba el paso de calibración: una sensibilidad determinada a
+partir de una grabación de calibrador *en el mismo formato entero* ya lleva el
+factor incorporado. Mezclar los dos, un calibrador leído como float con una
+medida leída como entero, o al revés, se equivoca en 90 dB sin ningún síntoma.
+Las reglas están en
+[Calibración y dBFS](/phonometry/es/signals/metrology/calibration/).
## Siguientes pasos
-El análisis en octavas de arriba usa el núcleo `filters`, uno de los dieciocho
-espacios de nombres de dominio; las secciones de la barra lateral recorren el
-resto, desde la psicoacústica y la acústica de salas, edificación y vibraciones
-hasta el ruido ambiental, aeronáutico y submarino, la electroacústica y la
-simulación de ondas FDTD. Cada objeto de resultado expone una figura
-`.plot(language="en"|"es")` de una línea y, cuando una norma define un formato
-de informe, un método `.report()` que genera la ficha PDF normativa.
-
+El análisis en octavas de arriba usa `phonometry.filters`, uno de los dieciocho
+espacios de nombres de importación. La documentación los agrupa en **diez
+áreas**, una por tema de la barra lateral, desde la psicoacústica y la acústica
+de salas, edificación y vibraciones hasta el ruido ambiental, aeronáutico y
+submarino, la electroacústica y la simulación de ondas FDTD. Cada objeto de
+resultado expone una figura `.plot(language="en"|"es")` de una línea y, cuando
+una norma define un formato de informe, un método `.report()` que genera la
+ficha PDF normativa.
+
+- [Construir un sonómetro](/phonometry/es/signals/sound-level-meter/): la misma cadena de principio a fin, del tono de calibrador a $L_{AF}(t)$, $L_{Aeq}$, $L_{AE}$, $L_{Cpeak}$, los niveles percentiles y la comprobación de clase de cada etapa
+- [Todas las guías](/phonometry/es/start/guides/): el mapa, todas las guías agrupadas por tema con una línea sobre cada una
+- [Glosario](/phonometry/es/reference/glossary/): un símbolo, su unidad, la cláusula que lo define y la guía que lo calcula
- [Galería de arquitecturas de filtro](/phonometry/es/signals/filters/filter-gallery/): elige una arquitectura e inspecciona sus respuestas
- [Calibración y dBFS](/phonometry/es/signals/metrology/calibration/): obtén valores SPL reales
- [Por qué phonometry](/phonometry/es/start/why-phonometry/): la filosofía de diseño basada en conformidad
diff --git a/site/src/content/docs/es/start/guides.md b/site/src/content/docs/es/start/guides.md
index c6d189722..b73207b0d 100644
--- a/site/src/content/docs/es/start/guides.md
+++ b/site/src/content/docs/es/start/guides.md
@@ -55,7 +55,7 @@ head:
"@type": "ListItem",
"position": 6,
"name": "Medio ambiente y transporte",
- "description": "Propagación en exteriores, barreras, refracción, aeronaves, helicópteros y aerogeneradores.",
+ "description": "Propagación en exteriores, barreras, refracción, fuentes viarias, ferroviarias y de aerogenerador, y la valoración construida sobre ellas.",
"url": "https://jmrplens.github.io/phonometry/es/environment/"
},
{
@@ -371,6 +371,8 @@ sonido que le llega, medido en laboratorio o predicho a partir de los
parámetros del material. Implementa ISO 354, ISO 11654, ISO 10534-1/-2,
ISO 9053-1/-2, ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 e ISO 12999-2.
+**[Absorbentes](/phonometry/es/materials/absorbers/)**
+
- [Medida y clasificación de la absorción sonora](/phonometry/es/materials/absorbers/absorption-measurement/):
la medición en cámara reverberante ISO 354, la valoración ponderada con su
clase y la incertidumbre de medida de ambas.
@@ -388,6 +390,8 @@ ISO 9053-1/-2, ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 e ISO 12999-2.
condición de acoplamiento crítico para la absorción perfecta y el panel
ranurado de sonido lento cargado con resonadores de Helmholtz, con su
solucionador de diseño.
+**[Difusores y superficies](/phonometry/es/materials/diffusers/)**
+
- [Difusores y sus coeficientes](/phonometry/es/materials/diffusers/diffusers/): el
coeficiente de dispersión de incidencia aleatoria, el coeficiente de
difusión por autocorrelación y el diseño de Schroeder con su predicción en
@@ -399,6 +403,11 @@ ISO 9053-1/-2, ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 e ISO 12999-2.
la absorción in situ de pavimentos por la técnica de sustracción y el
método puntual.
+El tercer grupo de esta área, Capas elásticas, tiene una sola guía,
+[Rigidez dinámica de materiales resilientes](/phonometry/es/materials/resilient/dynamic-stiffness/),
+listada más arriba dentro de Diseño del aislamiento, junto a la predicción de
+suelo flotante que la consume.
+
## [Vibración y ruido estructural](/phonometry/es/vibration/)
Movilidad y funciones de respuesta en frecuencia, aisladores, potencia radiada,
@@ -457,6 +466,15 @@ IEC 61400-11.
- [Propagación del sonido en exteriores](/phonometry/es/environment/propagation/outdoor-propagation/):
la absorción atmosférica y el método general de ISO 9613-2, con el desglose de
la atenuación por bandas de octava y por términos.
+- [Efecto suelo esférico y barreras avanzadas](/phonometry/es/environment/propagation/ground-barriers/):
+ el coeficiente de reflexión de Weyl-Van der Pol sobre suelo de impedancia
+ finita y la difracción en barreras desde la teoría ondulatoria.
+- [Refracción atmosférica: rayos y GFPE](/phonometry/es/environment/propagation/atmospheric-refraction/):
+ los perfiles de velocidad efectiva del sonido, los rayos curvos con distancia
+ de zona de sombra en forma cerrada y el campo de nivel relativo por GFPE.
+
+**[Fuentes](/phonometry/es/environment/sources/)**
+
- [Emisión de la fuente de tráfico viario CNOSSOS-EU](/phonometry/es/environment/sources/cnossos-road-emission/):
la fuente viaria común europea del Anexo II 2.2: potencia acústica de rodadura
y propulsión por categoría de vehículo y potencia direccional por metro de
@@ -468,16 +486,18 @@ IEC 61400-11.
- [Ruido de aerogeneradores: potencia y audibilidad tonal](/phonometry/es/environment/sources/wind-turbine-noise/):
el nivel de potencia acústica aparente referido al centro del rotor y la cadena
de audibilidad tonal que decide si un tono se oye.
-- [Efecto suelo esférico y barreras avanzadas](/phonometry/es/environment/propagation/ground-barriers/):
- el coeficiente de reflexión de Weyl-Van der Pol sobre suelo de impedancia
- finita y la difracción en barreras desde la teoría ondulatoria.
-- [Refracción atmosférica: rayos y GFPE](/phonometry/es/environment/propagation/atmospheric-refraction/):
- los perfiles de velocidad efectiva del sonido, los rayos curvos con distancia
- de zona de sombra en forma cerrada y el campo de nivel relativo por GFPE.
+
+**[Evaluación y normativa](/phonometry/es/environment/assessment/)**
+
- [Prominencia de sonidos impulsivos (NT ACOU 112)](/phonometry/es/environment/assessment/impulsive-sound/):
la prominencia prevista de cada impulso a partir de su tasa de ataque y su
diferencia de nivel, y el ajuste que se suma al $L_{Aeq}$.
+Las otras dos guías de este grupo, [Niveles ambientales](/phonometry/es/environment/assessment/environmental-levels/)
+y [Normativa española de ruido](/phonometry/es/environment/assessment/spanish-noise-regulation/),
+están listadas más arriba dentro de Análisis de señal, junto a las definiciones
+de nivel sobre las que se construyen.
+
## [Ruido de aeronaves](/phonometry/es/aircraft/)
Niveles de certificación, contornos de aeropuerto y el método del
diff --git a/site/src/content/docs/es/start/index.md b/site/src/content/docs/es/start/index.md
index 2509c307d..b3104cbae 100644
--- a/site/src/content/docs/es/start/index.md
+++ b/site/src/content/docs/es/start/index.md
@@ -1,18 +1,39 @@
---
title: "Inicio"
-description: "Por dónde empezar con phonometry: la visita de diez minutos, por qué existe la biblioteca y qué es."
+description: "Por dónde empezar con phonometry: el primer análisis de principio a fin, el mapa de todas las guías, por qué existe la biblioteca y quién la mantiene."
---
-Las tres páginas que abren la documentación, antes de las guías.
+Cuatro páginas breves, pensadas para leerse una vez antes que nada. Cada una
+responde a una pregunta, y están en el orden en que llegan las preguntas.
+**¿Puedo instalarla y sacar un número?**
[Primeros pasos](/phonometry/es/start/getting-started/) instala la biblioteca y
-recorre una primera medición de principio a fin, desde un archivo WAV hasta un
-espectro calibrado en tercios de octava. [Por qué
-phonometry](/phonometry/es/start/why-phonometry/) explica para qué sirve la
-biblioteca y cómo se valida contra las normas que implementa.
-[Acerca de](/phonometry/es/start/about/) dice quién la mantiene, cómo citarla y
-bajo qué licencia.
+ejecuta un primer análisis en tercios de octava, sobre una señal sintética y
+después sobre un archivo WAV, y dice qué tiene que cumplir una grabación para
+que esos números signifiquen algo físico. Se queda a propósito antes de una
+medición calibrada:
+[Calibración y dBFS](/phonometry/es/signals/metrology/calibration/) es el paso
+siguiente, el que convierte los niveles de banda en pascales, y
+[Construir un sonómetro](/phonometry/es/signals/sound-level-meter/) recorre la
+cadena entera de principio a fin.
+**¿Dónde está lo que vine a buscar?**
[Todas las guías](/phonometry/es/start/guides/) es el mapa: todas las guías de
la biblioteca, agrupadas por el tema al que pertenecen, con una línea sobre
cada una.
+
+**¿Me puedo fiar del número?**
+[Por qué phonometry](/phonometry/es/start/why-phonometry/) explica para qué
+sirve la biblioteca y cómo se valida contra las normas que implementa, con la
+comprobación de ráfagas de tono desarrollada frente a los límites de
+aceptación.
+
+**¿Quién responde de ella y cómo la cito?**
+[Acerca de](/phonometry/es/start/about/) dice quién la mantiene, cómo citarla y
+bajo qué licencia.
+
+El punto de partida que se supone es Python 3.13 o posterior con NumPy y SciPy
+funcionando, y la acústica suficiente para saber qué son una banda de tercio de
+octava y un nivel de presión acústica. Cualquier símbolo que las guías usen sin
+presentarlo está en el [glosario](/phonometry/es/reference/glossary/), con su
+unidad, la cláusula que lo define y la guía que lo calcula.
diff --git a/site/src/content/docs/es/start/why-phonometry.mdx b/site/src/content/docs/es/start/why-phonometry.mdx
index 8b4911e8d..23cb6ac6c 100644
--- a/site/src/content/docs/es/start/why-phonometry.mdx
+++ b/site/src/content/docs/es/start/why-phonometry.mdx
@@ -47,36 +47,66 @@ La prueba rigurosa para la ponderación temporal es la **respuesta a ráfaga de
tono** (IEC 61672-1, Tabla 4), usando una ráfaga senoidal de 4 kHz referida al
nivel de régimen estacionario.
+### Cómo se ejecuta la comprobación
+
+La Tabla 4 fija la excitación pero no el montaje, así que aquí va el montaje. Se
+genera una senoide de 4 kHz a 48 kHz durante 3 s. La **referencia** es el nivel
+Fast estacionario de esa senoide continua, promediado sobre su último medio
+segundo: una vez asentado el integrador, este es el $L_A$ en la notación de la
+norma. La ráfaga de la duración indicada se recorta después de *esa misma*
+senoide, de modo que su fase y su amplitud son idénticas a las del tono de
+referencia, y se rodea de ceros. La **respuesta** es el máximo de la envolvente
+Fast de esa ráfaga, expresado respecto de la referencia:
+$10\log_{10}(\max \text{env} / \text{ref})$, que es el $L_{AFmax} - L_A$ de la
+norma. Fíjate en qué verifica y qué no: la IEC 61672-1 enuncia estos límites
+para el dispositivo de entrada eléctrica sobre un rango definido de niveles
+estacionarios y sin indicación de sobrecarga (cláusulas 5.9.5-5.9.6), así que
+los números de abajo verifican la *balística*, no un instrumento completo. Los
+mismos valores de referencia están transcritos en
+`tests/filters/test_iec_compliance.py` para F y S y para la columna $L_{AE}$.
+
**Resultados de phonometry (FAST):**
-| Duración de la ráfaga | Objetivo IEC (dB) | phonometry (dB) | Error (dB) | Estado |
-| :--- | :--- | :--- | :--- | :--- |
-| 200 ms | −1,0 | −0,98 | +0,02 | ✅ PASA |
-| 50 ms | −4,8 | −4,82 | −0,02 | ✅ PASA |
-| 10 ms | −11,1 | −11,14 | −0,04 | ✅ PASA |
-| 1 ms | −21,0 | −20,99 | +0,01 | ✅ PASA |
+| Duración de la ráfaga | Objetivo IEC (dB) | Límite clase 1 (dB) | phonometry (dB) | Error (dB) | Estado |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| 200 ms | −1,0 | ±0,5 | −0,98 | +0,02 | ✅ PASA |
+| 50 ms | −4,8 | ±1,0 | −4,82 | −0,02 | ✅ PASA |
+| 10 ms | −11,1 | ±1,0 | −11,14 | −0,04 | ✅ PASA |
+| 1 ms | −21,0 | +1,0 / −2,0 | −20,99 | +0,01 | ✅ PASA |
**Resultados de python-acoustics (FAST, pasando la señal al cuadrado como
requiere esa librería):**
-| Duración de la ráfaga | Objetivo IEC (dB) | python-acoustics (dB) | Error (dB) | Estado |
-| :--- | :--- | :--- | :--- | :--- |
-| 200 ms | −1,0 | −0,97 | +0,03 | ✅ PASA |
-| 50 ms | −4,8 | −3,93 | **+0,87** | ⚠️ FALLA |
-| 10 ms | −11,1 | −10,90 | +0,20 | ✅ PASA |
-| 1 ms | −21,0 | −20,90 | +0,10 | ✅ PASA |
-
-phonometry mantiene alta precisión en todos los casos. El enfoque por bloques
-se desvía significativamente (más de 0,8 dB) en la ráfaga de 50 ms porque los
-bloques de 125 ms no pueden resolver con precisión eventos transitorios cortos;
-el resultado depende de cómo se alinee la ráfaga con los límites de los
-bloques.
+| Duración de la ráfaga | Objetivo IEC (dB) | Límite clase 1 (dB) | python-acoustics (dB) | Error (dB) | Estado |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| 200 ms | −1,0 | ±0,5 | −0,97 | +0,03 | ✅ PASA |
+| 50 ms | −4,8 | ±1,0 | −3,93 | **+0,87** | ✅ PASA |
+| 10 ms | −11,1 | ±1,0 | −10,90 | +0,20 | ✅ PASA |
+| 1 ms | −21,0 | +1,0 / −2,0 | −20,90 | +0,10 | ✅ PASA |
+
+**Las dos librerías pasan todas las filas mostradas**, y decir lo contrario
+sería exagerar el caso: lo que importa aquí es la *forma* del error, no un
+incumplimiento. phonometry se queda dentro de 0,05 dB de la referencia de la
+Tabla 4 en todas las duraciones, menos del 5 % del margen de clase 1, porque a
+un detector exponencial continuo no le queda ningún parámetro libre que
+equivocar. El integrador por bloques también se queda dentro de clase 1, pero
+gasta 0,87 de los 1,0 dB disponibles a 50 ms, y los gasta por un motivo que es
+suerte y no diseño: cómo se reparte la ráfaga a caballo de un bloque de 125 ms.
+Lee las dos tablas junto a la primera columna de la Tabla 4, que se estrecha a
+±0,5 dB para ráfagas de 200 ms y más largas: en ese extremo a un integrador por
+bloques no le queda margen que perder.
*Envolventes Fast medidas (azul) coincidiendo con los valores de referencia
de la Tabla 4 (discontinua) dentro de 0,1 dB para ráfagas de 200/50/10 ms.*
+El generador que hay detrás de esta figura es
+`scripts/figures/signals.py::generate_tone_burst_iec`, y es el procedimiento
+descrito arriba con tres de las filas de la Tabla 4: imprime
+`env_db.max() - target`, que es la columna Error de la primera tabla, de modo
+que las filas de phonometry se pueden reproducir directamente.
+
## Qué significa esto en la práctica
- Si necesitas **envolventes Fast/Slow/Impulse conformes con la norma**
diff --git a/site/src/content/docs/es/underwater/marine-mammal-exposure.mdx b/site/src/content/docs/es/underwater/marine-mammal-exposure.mdx
index af7e9f5e7..5780841be 100644
--- a/site/src/content/docs/es/underwater/marine-mammal-exposure.mdx
+++ b/site/src/content/docs/es/underwater/marine-mammal-exposure.mdx
@@ -77,15 +77,24 @@ Todos los conjuntos de criterios vigentes clasifican a los mamíferos marinos en
grupos auditivos y asignan un filtro a cada uno. Los **códigos de grupo no son
portables entre versiones de guía**, y la colisión es una trampa real:
-| Southall et al. (2019) / NMFS 2024 | NMFS 2018 | Géneros típicos |
-|---|---|---|
-| Cetáceos LF | LF | ballenas barbadas |
-| Cetáceos HF | **MF** | cachalote, zifios y la mayoría de delfínidos |
-| Cetáceos VHF | **HF** | marsopas, *Cephalorhynchus*, *Kogia* |
-| PCW / PW | PW | focas fócidas en agua |
-| OCW / OW | OW | otáridos, en agua |
-| SI, PCA, OCA | — | sirenios y carnívoros en aire |
-
+| Grupo animal | Southall 2019 | NMFS 2024 | NMFS 2018 | Audiograma |
+|---|---|---|---|---|
+| Ballenas barbadas | LF | LF | LF | no ($F_1$ sin publicar) |
+| Cachalote, zifios y la mayoría de delfínidos | HF | HF | **MF** | sí (`"HF"`) |
+| Marsopas, *Cephalorhynchus*, *Kogia* | VHF | VHF | **HF** | sí (`"VHF"`) |
+| Focas fócidas en agua | PCW | PW | PW | sí (`"PCW"`) |
+| Otáridos en agua | OCW | OW | OW | sí (`"OCW"`) |
+| Sirenios | SI | — | — | sí (`"SI"`) |
+| Focas fócidas en aire | PCA | PA | — | sí (`"PCA"`) |
+| Otáridos en aire | OCA | OA | — | sí (`"OCA"`) |
+
+Lee la columna en la que estás trabajando. `auditory_weighting` y
+`exposure_criteria` toman el código de la `guidance` que selecciones;
+`group_audiogram` toma siempre el código **Southall**, porque los audiogramas
+son los de Southall. Así que `group_audiogram(f, "PW")` lanza un error aunque
+`"PW"` sea un grupo de ponderación válido de NMFS 2024 (hay que pedir `"PCW"`),
+y `auditory_weighting(f, "PCW")` lanza un error con la guía por defecto por la
+razón simétrica.
`hearing_groups(guidance)` lista los códigos que define cada versión, y pasar un
código de la versión equivocada lanza un error en vez de devolver en silencio el
filtro incorrecto.
@@ -257,11 +266,32 @@ golpe registrado al veredicto:
la acumula sobre el número de golpes (el $+10\log_{10} N$ de la ISO 18406) y
compara el resultado con los criterios, nivel de pico sin ponderar incluido.
+### Qué tiene que cubrir el registro
+
+La suma ponderada recorre las bandas que se le entregan, así que **el registro
+tiene que abarcar la banda de paso del grupo auditivo**. Las frecuencias de
+transición superiores $f_2$ de NMFS 2024 son 26,6 kHz (LF), 129 kHz (HF),
+186 kHz (VHF), 68,3 kHz (PW) y 43,8 kHz (OW), y los rangos auditivos
+generalizados llegan aún más lejos (LF hasta 36 kHz, VHF hasta 165 kHz). Como
+regla, la frecuencia de muestreo tiene que ser unas 2,5 veces el borde de banda
+más alto que importe, así que el registro de 48 kHz de abajo (con bandas
+resueltas hasta unos 20 kHz) sirve para LF, va justo para OW y trunca gravemente
+HF, VHF y PW. Una evaluación de marsopa necesita unos cuantos cientos de
+kilohercios.
+
+`weighted_exposure` no puede detectar un espectro truncado: pondera lo que se le
+da, así que un registro corto simplemente informa de un SEL acumulado menor y de
+ningún aviso. La mitad de pico sin ponderar de la métrica dual tiene que salir
+de ese mismo registro sin recorte y con margen de sobra, que es la razón por la
+que la ISO 18406 hace del margen dinámico un requisito de campaña: una captura
+saturada se lee como un pico conforme.
+
```python
import numpy as np
from phonometry import underwater
-# Un golpe registrado (aquí una ráfaga sintética de 200 Hz con caída).
+# Un golpe registrado (aquí una ráfaga sintética de 200 Hz con caída). 48 kHz
+# basta para el grupo LF usado abajo y para nada por encima de él.
fs = 48_000
t = np.arange(int(0.2 * fs)) / fs
strike = 50.0 * np.exp(-t / 0.06) * np.sin(2 * np.pi * 200.0 * t)
@@ -309,7 +339,9 @@ hostigamiento) quedan fuera de alcance: solo se implementan los criterios de
efecto auditivo. La biblioteca no elige por el usuario ni el grupo auditivo ni
el periodo de acumulación, y no modela el movimiento del animal respecto a la
fuente, de modo que el SEL acumulado que informa es el caso peor de receptor
-estático. La propagación de la fuente al receptor pertenece a
+estático. Tampoco comprueba que el espectro aportado abarque la banda de paso
+del grupo: un registro que se queda corto respecto de $f_2$ se pondera tal cual
+y subestima la exposición. La propagación de la fuente al receptor pertenece a
[Propagación del sonido submarino](/phonometry/es/underwater/underwater-propagation/).
## Véase también
diff --git a/site/src/content/docs/es/underwater/underwater-acoustics.mdx b/site/src/content/docs/es/underwater/underwater-acoustics.mdx
index 14f8817e3..b9d1d674b 100644
--- a/site/src/content/docs/es/underwater/underwater-acoustics.mdx
+++ b/site/src/content/docs/es/underwater/underwater-acoustics.mdx
@@ -59,7 +59,9 @@ exacta, verificada analíticamente.
## 1. Niveles de referencia (ISO 18405)
Tres primitivos, referidos a 1 µPa, se calculan desde una señal de presión
-capturada (en Pa):
+capturada. **Todo argumento de presión de esta página está en pascales** (salida
+de hidrófono calibrada, sin ponderación aplicada) y todo nivel sale re 1 µPa (o
+re 1 µPa²·s):
$$
\mathrm{SPL} = 10\log_{10}\frac{\langle p^2\rangle}{p_0^2}, \qquad
@@ -131,18 +133,36 @@ res.plot(language="es")
```python
+import numpy as np
from phonometry import underwater
-lrn = underwater.radiated_noise_level(2e-6, 100.0) # p_rms = 2 µPa, r = 100 m
-res = underwater.monopole_source_level(lrn, 200.0, draught=6.0)
-print(res.source_level, res.surface_correction, res.source_depth)
+# Presiones eficaces por banda medidas a 100 m de un buque mercante, en pascales.
+freqs = np.array([31.5, 63.0, 125.0, 250.0, 500.0, 1000.0])
+p_rms = np.array([4.3, 2.8, 1.9, 1.2, 0.8, 0.54])
+rnl = np.array([underwater.radiated_noise_level(float(x), 100.0) for x in p_rms])
+print(np.round(rnl, 1)) # [172.7 168.9 165.6 161.6 158.1 154.6] dB re 1 uPa.m
+
+# La corrección de superficie depende de la frecuencia, así que la conversión
+# se suele ejecutar sobre todo el vector de bandas a la vez.
+res = underwater.monopole_source_level(rnl, freqs, draught=6.0)
+print(np.round(res.source_level, 1)) # [177.8 168.4 161.7 157.8 154.8 151.6]
+print(np.round(res.surface_correction, 2)) # [ 5.15 -0.51 -3.86 -3.78 -3.27 -3.08]
+print(round(res.source_depth, 2)) # 4.2 m = 0,7 x calado
res.plot() # RNL, Ls y ΔL en función de la frecuencia (necesita matplotlib)
```
+Lee los órdenes de magnitud antes de seguir. Un buque mercante vive en un nivel
+de ruido radiado de aproximadamente 160-180 dB re 1 µPa·m, frente a niveles
+espectrales de ruido ambiente oceánico de 60-100 dB, así que un resultado muy
+fuera de ese rango es un error de unidades y no un buque silencioso. Por encima
+del primer cero del Lloyd's mirror la corrección se asienta hacia $-3$ dB y el
+nivel monopolar equivalente queda justo *por debajo* del nivel de ruido radiado;
+solo en las bandas más bajas, donde $u$ es pequeño, va al revés.
+
`hydrophone_depths` da las tres profundidades de medida de la ISO 17208-1 a
partir de los ángulos de depresión 15°/30°/45°, y `source_level_uncertainty` la
-incertidumbre expandida tabulada (5 dB ≤100 Hz, 3 dB 125 Hz–16 kHz, 4 dB
->16 kHz).
+incertidumbre expandida tabulada (5 dB ≤100 Hz, 3 dB 125 Hz–16 kHz,
+4 dB >16 kHz).
Lo que convierte estas formas cerradas en un número *comparable* es la
disciplina de medida con que la ISO 17208-1 las envuelve. El buque recorre un
diff --git a/site/src/content/docs/es/underwater/underwater-propagation.mdx b/site/src/content/docs/es/underwater/underwater-propagation.mdx
index 9dab07cf6..a54a6466b 100644
--- a/site/src/content/docs/es/underwater/underwater-propagation.mdx
+++ b/site/src/content/docs/es/underwater/underwater-propagation.mdx
@@ -71,7 +71,7 @@ references:
issue: 4
pages: "1084-1091"
doi: "10.1121/1.1903388"
- note: "La ecuación alternativa de velocidad del sonido basada en presión (\"del-grosso\")."
+ note: "La ecuación alternativa de velocidad del sonido basada en presión (\"del_grosso\")."
- type: article
authors: ["Mackenzie, K. V."]
year: 1981
@@ -179,9 +179,10 @@ $$
El ensanchamiento geométrico es $20 \log_{10} R$ (esférico), $10 \log_{10} R$ (cilíndrico)
o esférico hasta una distancia de transición $R_0$ y cilíndrico más allá
de esta (`"practical"`). El coeficiente de absorción de volumen $\alpha$ (dB/km)
-procede de **Francois–Garrison** (1982, por
-defecto y de referencia), **Ainslie–McColm** (1998) o **Thorp** (1967, solo
-frecuencia); los dos primeros coinciden en ~10 % entre 100 Hz y 1 MHz.
+procede de **Francois-Garrison** (`model="francois-garrison"`, 1982, el valor
+por defecto y la referencia), **Ainslie-McColm** (`"ainslie-mccolm"`, 1998) o
+**Thorp** (`"thorp"`, 1967, solo frecuencia); los dos primeros coinciden en
+~10 % entre 100 Hz y 1 MHz.
@@ -212,7 +213,17 @@ from phonometry import underwater
ranges = np.linspace(10.0, 20_000.0, 400)
tl = underwater.transmission_loss(ranges, 10e3, law="practical", transition_range=1000.0,
temperature=10.0, salinity=35.0, depth=100.0)
-print(tl.absorption_coefficient, tl.tl[-1])
+print(round(tl.absorption_coefficient, 3), round(float(tl.tl[-1]), 1))
+# 0.95 dB/km, 92.0 dB a 20 km
+
+# El mismo caso con los otros dos modelos de absorción, para que la
+# afirmación de concordancia de arriba sea comprobable y no un enunciado:
+for model in ("ainslie-mccolm", "thorp"):
+ other = underwater.transmission_loss(ranges, 10e3, law="practical",
+ transition_range=1000.0, temperature=10.0,
+ salinity=35.0, depth=100.0, model=model)
+ print(model, round(other.absorption_coefficient, 3)) # 0.973 / 1.15
+
tl.plot() # TL frente a distancia con la separación ensanchamiento/absorción
```
@@ -291,8 +302,11 @@ implementa la forma coherente con la derivación; véase
## Velocidad del sonido en agua de mar
`sea_water_sound_speed(T, S, depth, model=…)` usa la ecuación **UNESCO /
-Chen–Millero** (por defecto, en la forma Wong & Zhu 1995 ITS-90), **Del Grosso**
-(1974), **Mackenzie** (1981) o **Medwin** (1975). La profundidad se convierte a
+Chen-Millero** (`model="unesco"`, el valor por defecto, en la forma Wong & Zhu
+1995 ITS-90), **Del Grosso** (`"del_grosso"`, fíjate en el guion bajo, al
+contrario que en los modelos de absorción de arriba, con guion), **Mackenzie**
+(`"mackenzie"`) o **Medwin** (`"medwin"`), todas de 1974-1981. La profundidad se
+convierte a
presión con Leroy & Parthiot (1998). Las cuatro coinciden en ~2,5 m/s; el valor de
verificación canónico de Mackenzie es 1550,744 m/s a 25 °C, 35 ‰, 1000 m. La
forma de seis términos de Medwin es la más basta de la familia y la que está
@@ -399,9 +413,36 @@ print(se.figure_of_merit)
se.plot() # exceso de señal frente a pérdida por transmisión
```
-Los niveles de sonar, propagación y ambiental están en dB re una onda plana de
-1 µPa rms (niveles espectrales). Los niveles de fuente (más abajo) usan la
-convención de fuente, dB re 1 µPa²/Hz **a 1 m**.
+Los términos, una vez: $SL$ el nivel de fuente del blanco, $TL$ la pérdida por
+transmisión de ida, $NL$ el nivel de ruido en el receptor, $DI$ el índice de
+directividad (ganancia de array), $DT$ el umbral de detección y, para la forma
+activa, $TS$ la fuerza del blanco.
+
+**Hay dos referencias en juego, y la ISO 18405 las mantiene separadas.** Los
+niveles de banda y de banda ancha (el nivel ambiental en una banda, $NL$, y $SL$
+tal como se usa en la ecuación del sonar) son re 1 µPa. Las *densidades
+espectrales*, que es lo que devuelven `ocean_ambient_noise` y
+`ship_source_spectrum`, son re 1 µPa²/Hz. Un nivel de fuente lleva además un
+metro cuadrado que viene de su distancia de referencia, lo que la ISO 18405
+escribe re 1 µPa²m² (equivalentemente, «dB re 1 µPa a 1 m»).
+
+**Todos los términos tienen que referirse al mismo ancho de banda.** La ecuación
+del sonar es un balance de niveles, así que mezclar un nivel de fuente de banda
+ancha con un nivel *espectral* de ruido ambiental se equivoca en
+$10\log_{10} B$, decenas de decibelios con cualquier ancho de banda útil, y la
+función no puede detectarlo porque recibe decibelios pelados. Como los modelos
+de ambiental y de tráfico marítimo de aquí son por hercio, la disciplina más
+simple es trabajar por hercio en todo y dejar que el ancho de banda de proceso
+entre por $DT$; la alternativa suma $10\log_{10} B$ a una señal de banda ancha
+*y* al ruido (para un tono, solo al ruido, que es toda la ganancia de proceso).
+El resultado del buque lleva los niveles de banda de decidécada junto a su
+densidad justo para esta conversión.
+
+La cifra de mérito se expresa más abajo como «dB re m²»: Ainslie la escribe como
+un *factor de propagación* máximo y no como una pérdida, y el factor de
+propagación tiene unidades de m², así que el mismo número que se lee como
+pérdida por transmisión máxima admisible en decibelios se lee como cifra de
+mérito re 1 m².
### Alcance de detección
@@ -578,17 +619,37 @@ plt.show()
```python
+import numpy as np
from phonometry import underwater
ship = underwater.ship_source_spectrum(18.0, 300.0, vessel_class="containership")
ship.plot() # densidad espectral de fuente frente a frecuencia
print(underwater.VESSEL_CLASSES) # las 13 clases de buque de JOMOPANS-ECHO
-# Alimenta la predicción al ruido ambiental como término de tráfico:
+# `source_psd` es un nivel de FUENTE a 1 m; el término `shipping` de la suma
+# ambiental es un nivel espectral RECIBIDO en la posición de escucha. La
+# propagación es el paso entre ambos: aquí, ese buque a 2 km.
+tl = np.array([float(underwater.transmission_loss(
+ 2000.0, float(f), law="practical", transition_range=1000.0).tl[0])
+ for f in ship.frequency])
+received = ship.source_psd - tl
noise = underwater.ocean_ambient_noise(ship.frequency, wind_speed_knots=10.0,
- shipping=ship.source_psd)
+ shipping=received)
+print(round(float(np.interp(100.0, ship.frequency, noise.spectrum_level)), 1))
+# 97.6 dB re 1 uPa^2/Hz a 100 Hz, frente a 72.7 solo con el viento. Pasar
+# ship.source_psd directamente imprimiría 160.6: un nivel de fuente no es uno
+# recibido, y el error es la pérdida por transmisión entera.
```
+Ni siquiera eso es más que una estimación de un solo buque. El ruido de tráfico
+marítimo medido en un emplazamiento es la suma sobre todo el campo de tráfico,
+así que un término realista integra muchos buques sobre sus distancias y clases,
+que es la razón por la que `ocean_ambient_noise` deja el espectro de tráfico a
+quien llama en vez de construir uno por dentro. Una sola comprobación de
+sensatez se lleva casi todo el valor: un espectro ambiental compuesto por encima
+de unos 120 dB re 1 µPa²/Hz es un error de unidades o de geometría, no un mar
+ruidoso.
+
Todas las formas cerradas anteriores dejan de bastar cuando la refracción y
los contornos deciden la respuesta: un mínimo de velocidad del sonido que
atrapa energía, reflexiones en la superficie y el fondo en aguas someras, o
diff --git a/site/src/content/docs/es/underwater/underwater-solvers.mdx b/site/src/content/docs/es/underwater/underwater-solvers.mdx
index 247ccf4cb..bc9045016 100644
--- a/site/src/content/docs/es/underwater/underwater-solvers.mdx
+++ b/site/src/content/docs/es/underwater/underwater-solvers.mdx
@@ -171,6 +171,21 @@ print(round(float(modes.wavenumbers[0]), 5)) # 0.20885 kr1 calculado
print(round(np.sqrt(k**2 - (np.pi / 200.0) ** 2), 5)) # 0.20885 exacto
```
+Esa guía de ondas ideal cumple dos papeles, y no conviene confundirlos. Es el
+oráculo exacto contra el que se comprueba el solucionador, que es para lo que se
+usa aquí, y es además un fondo físicamente *extremo*: un lecho de presión nula
+refleja con módulo unidad e inversión de fase, así que no transmite nada al
+sedimento y no absorbe nada. Una pérdida por transmisión modal o PE calculada
+sobre él subestima, por tanto, la pérdida de cualquier fondo marino real, y la
+diferencia se ensancha con el alcance porque se acumula rebote a rebote. La
+opción rígida es el extremo contrario, ofrecida por la misma razón de validación
+y no como modelo de sedimento. Para un fondo real en aguas someras, tasa el
+lecho con los regímenes de Weston de
+[propagación submarina del sonido](/phonometry/es/underwater/underwater-propagation/),
+cuyo ángulo crítico y gradiente de pérdida por reflexión codifican exactamente
+lo que estas condiciones de contorno omiten, y lee la respuesta modal como una
+cota superior del nivel recibido.
+
## 3. Trazado de rayos: tiempos de propagación y zonas de convergencia
En el límite de alta frecuencia la ecuación de Helmholtz colapsa en la
@@ -279,7 +294,7 @@ velocidad del sonido y de absorción nombrados abajo están implementados y
referenciados en la
[propagación submarina del sonido](/phonometry/es/underwater/underwater-propagation/).
-**Velocidad del sonido.** Las tres ecuaciones coinciden a menos de 1 m/s
+**Velocidad del sonido.** Las cuatro ecuaciones coinciden a menos de 2,5 m/s
dentro de su dominio común, así que la elección va de *rango de validez*, no
de exactitud. La forma **UNESCO / Chen-Millero** por defecto (en la
reformulación de Wong y Zhu de 1995) cubre de 0 a 40 °C, de 0 a 40 ppt y de 0
@@ -290,7 +305,12 @@ autores la prefieren para trabajo de océano profundo dentro de ese dominio
cambia presión por profundidad directamente (2-30 °C, 25-40 ppt, 0-8000 m),
lo que la convierte en la opción cómoda cuando se dispone de una profundidad
de ecosonda y no de una presión de CTD; las otras dos convierten profundidad a
-presión internamente mediante Leroy y Parthiot (1998).
+presión internamente mediante Leroy y Parthiot (1998). **Medwin** (1975) es una
+simplificación de seis términos válida hasta unos 1000 m en aguas someras y
+cálidas; es la más basta de las cuatro y la que hay detrás de las reglas
+prácticas $\partial c/\partial T \approx 4{,}6 - 0{,}110\,T$ m/s por °C y
+$\partial c/\partial z \approx 0{,}016$ m/s por metro, así que resérvala para el
+cálculo mental y las comprobaciones a mano, no para un presupuesto.
**Absorción.** **Francois-Garrison** (1982) es la referencia y el valor por
defecto: incorpora las relajaciones del ácido bórico, el sulfato de magnesio y
diff --git a/site/src/content/docs/es/vibration/human/human-vibration.mdx b/site/src/content/docs/es/vibration/human/human-vibration.mdx
index b64cc0493..38c745ee4 100644
--- a/site/src/content/docs/es/vibration/human/human-vibration.mdx
+++ b/site/src/content/docs/es/vibration/human/human-vibration.mdx
@@ -112,11 +112,11 @@ mano-brazo.
from phonometry import vibration
# La respuesta de ponderación global a cualquier frecuencia (ISO 8041-1, fórmula (5)).
+# 6,3096 Hz es el centro *verdadero* de la banda nominal de 6,3 Hz, que es donde
+# las tablas del Anexo B imprimen sus factores.
resp = vibration.frequency_weighting("Wk", [1.0, 6.3096, 20.0])
print(resp.magnitude.round(3)) # [0.482 1.054 0.636] (factores)
print(resp.magnitude_db.round(2)) # [-6.33 0.46 -3.93] (dB)
-
-resp.plot() # la respuesta de la ponderación en dB, como en la figura de abajo (requiere matplotlib)
```
Los factores reproducen las tablas de objetivo de diseño del Anexo B de
@@ -206,17 +206,26 @@ verdaderos al comparar con los factores tabulados.
import numpy as np
from phonometry import vibration
-# Un espectro vertical de asiento medido (eficaz por tercio de octava, m/s^2).
-freqs = np.array([1.0, 2.0, 4.0, 8.0, 16.0, 31.5, 63.0])
-accel = np.array([0.20, 0.45, 0.42, 0.25, 0.12, 0.05, 0.02])
+# Un espectro vertical de asiento medido (eficaz por tercio de octava, m/s^2),
+# las mismas 19 bandas con las que está dibujada la figura de abajo.
+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,
+ 12.5, 16.0, 20.0, 25.0, 31.5, 40.0, 63.0, 80.0])
+accel = np.array([0.18, 0.24, 0.33, 0.46, 0.52, 0.55, 0.48, 0.39, 0.31, 0.26,
+ 0.21, 0.17, 0.13, 0.10, 0.078, 0.060, 0.045, 0.028, 0.020])
result = vibration.weighted_acceleration(accel, freqs, "Wk")
-print(round(result.overall, 3)) # 0.555 m/s^2 (a_w)
+print(round(result.overall, 3)) # 1.026 m/s^2 (a_w)
print(result.weighted.round(3)) # W_i * a_i por banda
result.plot() # bandas sin ponderar frente a ponderadas, como en la figura de abajo (requiere matplotlib)
```
+Esas etiquetas de banda son las nominales, por legibilidad. Pasar en su lugar
+los centros verdaderos $10^{n/10}$ Hz (1; 1,259; 1,585; ...; 79,433) mueve
+$a_w$ de 1,0260 a 1,0267 m/s², así que la advertencia anterior va de comparar
+un $W_i$ *aislado* con una tabla impresa, no de un valor eficaz de banda ancha,
+donde ambos coinciden en tres cifras.
+
diff --git a/site/src/content/docs/es/vibration/human/multiple-shock-vibration.mdx b/site/src/content/docs/es/vibration/human/multiple-shock-vibration.mdx
index 60610f05b..6645a5076 100644
--- a/site/src/content/docs/es/vibration/human/multiple-shock-vibration.mdx
+++ b/site/src/content/docs/es/vibration/human/multiple-shock-vibration.mdx
@@ -46,7 +46,7 @@ En caso de duda, la delimitación es cuantitativa: cuando la aceleración de
pico vertical limitada en banda supera 9,81 m/s² (1 g, el umbral de caída
libre), se aplican la cláusula 5 y el Anexo C.
-
+
## 1. Respuesta espinal (cláusula 5.2)
@@ -102,14 +102,28 @@ $S_d = m_z\,D_{zd}$ (Fórmula C.1), donde $m_z$ (0,029 MPa por m/s² para un
hombre de 82 kg, 0,025 para una mujer de 64 kg) convierte la aceleración en
tensión vertebral. La tensión se acumula sobre los años de exposición frente a
la resistencia última decreciente de la columna que envejece
-$S_u = 6{,}75 - S_{\mathrm{age}}\,(b+i)$ (Fórmulas C.3/C.4):
+$S_u = 6{,}75\ \mathrm{MPa} - S_{\mathrm{age}}\,(b+i)$ (Fórmulas C.3/C.4):
$$
R = \left[\sum_{i=0}^{n-1}
\left(\frac{S_d\,N^{1/6}}{S_{u,i} - S_{\mathrm{stat}}}\right)^{6}\right]^{1/6},
$$
-y un modelo de Weibull da la probabilidad de lesión lumbar (Fórmula C.5):
+donde $b$ es la edad a la que empezó la exposición, $n$ el número de años de
+exposición, $i$ el contador de años $0 \le i \le n-1$ (de modo que $S_{u,i}$ es
+la resistencia última a la edad $b+i$) y $N$ el número de días de exposición al
+año. $S_{\mathrm{stat}} = m_z \times 9{,}81\ \mathrm{m/s^2}$ es la tensión
+compresiva estática que la columna ya soporta bajo la gravedad — 0,284 MPa con
+el $m_z$ masculino, 0,245 MPa con el femenino (`vibration.static_stress`) — y
+$S_{\mathrm{age}}$ es la pérdida anual de resistencia última, 0,052 MPa/año en
+hombres y 0,039 MPa/año en mujeres (`vibration.ultimate_strength`, que devuelve
+5,71 MPa a los 20 años y 4,67 MPa a los 40 en un hombre). El denominador es,
+por tanto, un *margen*: $R$ crece tanto porque la dosis se acumula día tras día
+como porque ese margen se estrecha en $S_{\mathrm{age}}$ cada año, así que la
+misma dosis diaria daña más a una columna más envejecida.
+
+Un modelo de Weibull convierte $R$ en la probabilidad de lesión lumbar
+(Fórmula C.5):
$$
\Pi(R) = 1 - \exp\!\left[-\left(\frac{R}{\alpha}\right)^{\beta}\right].
@@ -140,14 +154,24 @@ az = np.zeros(2560)
az[256::512] = 60.0
result = vibration.multiple_shock_assessment(
az, fs, start_age=20, years=20, days_per_year=120, sex="male",
+ measurement_time=10.0, # t_m: el registro dura 10 s
+ exposure_time=4 * 3600.0, # t_d: 4 h al día en este vehículo
)
-print(round(result.acceleration_dose, 2)) # 20.94 m/s2
-print(round(result.risk, 2)) # 0.46
-print(round(result.probability, 2)) # 0.03
+print(round(result.acceleration_dose, 2)) # 20.94 m/s2, sobre el registro de 10 s
+print(round(result.daily_dose, 2)) # 70.35 m/s2, Fórmula 4 escalada a td
+print(round(result.risk, 2)) # 1.53
+print(round(result.probability, 2)) # 0.58
result.plot() # la curva de probabilidad de lesión con la R de esta evaluación marcada (requiere matplotlib)
```
+`exposure_time` y `measurement_time` son los que implementan aquí la Fórmula 4.
+Si se omiten, la dosis medida se toma sin cambios como dosis diaria, lo cual
+solo es correcto cuando el registro ya cubre toda la exposición diaria: para
+este registro de 10 s y una jornada de 4 h ese atajo divide la dosis entre
+$(t_d/t_m)^{1/6} = 3{,}36$ y declara $R = 0{,}46$ en lugar de $1{,}53$ — un 3 %
+de probabilidad de lesión donde la exposición da un 58 %.
+
@@ -158,19 +182,33 @@ import numpy as np
import matplotlib.pyplot as plt
from phonometry import vibration
-# Izquierda: la magnitud de la función de transferencia asiento-columna.
-f = np.logspace(np.log10(0.5), np.log10(80.0), 400)
-plt.plot(f, np.abs(vibration.seat_to_spine_transfer(f)))
-plt.xscale("log"); plt.show()
+fig, (ax_h, ax_r) = plt.subplots(1, 2, figsize=(12.5, 5.4))
-# Derecha: la curva de probabilidad de lesión con la R de esta evaluación
-# (az/fs como en el snippet anterior).
-fs = 256.0
-az = np.zeros(2560)
-az[256::512] = 60.0
-vibration.multiple_shock_assessment(
- az, fs, start_age=20, years=20, days_per_year=120,
-).plot(language="es")
+# Izquierda: la magnitud de la función de transferencia asiento-columna (Fórmula 1).
+f = np.logspace(np.log10(0.5), np.log10(80.0), 400)
+ax_h.plot(f, np.abs(vibration.seat_to_spine_transfer(f)), label="|H(f)|")
+ax_h.set_xscale("log")
+ax_h.set_xlabel("Frecuencia [Hz]")
+ax_h.set_ylabel("Transmisibilidad asiento -> columna")
+ax_h.legend()
+
+# Derecha: la probabilidad de lesión de Weibull para ambos sexos, con el
+# ejemplo masculino del Anexo C (cinco picos de respuesta de 40 m/s2 al día)
+# marcado, que es la R que imprime la figura, no la R del registro sintético
+# de 10 s de arriba.
+grid = np.linspace(0.0, 3.0, 300)
+for sex, etiqueta in (("male", "hombre"), ("female", "mujer")):
+ ax_r.plot(grid, 100.0 * vibration.injury_probability(grid, sex=sex), label=etiqueta)
+sd = vibration.compression_dose(vibration.dose_from_peaks([40.0] * 5))
+r = vibration.injury_risk(sd, start_age=20, years=20, days_per_year=120)
+for level, r_level in zip((10, 50, 90), (0.72, 1.42, 2.17)): # Tabla C.2, hombre
+ ax_r.axhline(level, color="#7f7f7f", linestyle=":", lw=0.8)
+ ax_r.plot([r_level, r_level], [0.0, level], color="#7f7f7f", linestyle=":", lw=0.8)
+ax_r.scatter([r], [100.0 * vibration.injury_probability(r)], marker="*", s=160,
+ label=f"Ejemplo R = {r:.2f}")
+ax_r.set_xlabel("Variable de tensión R")
+ax_r.set_ylabel("Probabilidad de lesión lumbar [%]")
+ax_r.legend()
plt.show()
```
@@ -224,7 +262,8 @@ from phonometry import vibration, ReportMetadata
# 40 m/s2 al día, hombre de 82 kg, expuesto desde los 20 años durante 20 años a
# 120 días/año. El registro se reconstruye a partir de esos picos de respuesta
# (la norma plantea el ejemplo en términos de los picos), de modo que la ficha
-# imprime los valores publicados del anexo C.
+# imprime los valores publicados del anexo C. Los cinco picos son toda la
+# jornada, así que td = tm y daily_dose es dz sin escalar.
peaks = np.array([40.0] * 5)
dz = vibration.dose_from_peaks(peaks)
sd = vibration.compression_dose(dz)
@@ -240,7 +279,7 @@ result = vibration.MultipleShockResult(
years=20,
days_per_year=120.0,
peaks=peaks,
- risk_thresholds=vibration.RISK_THRESHOLDS_MALE,
+ risk_thresholds=(0.72, 1.42, 2.17), # Tabla C.2, hombre: riesgo del 10 / 50 / 90 %
)
result.report(
diff --git a/site/src/content/docs/es/vibration/machinery/machine-diagnostics.mdx b/site/src/content/docs/es/vibration/machinery/machine-diagnostics.mdx
index b44029f7d..6aa6e080b 100644
--- a/site/src/content/docs/es/vibration/machinery/machine-diagnostics.mdx
+++ b/site/src/content/docs/es/vibration/machinery/machine-diagnostics.mdx
@@ -30,11 +30,12 @@ La vista de trabajo es la unión de ambas cosas: el espectro de envolvente de un
registro de vibración filtrado en banda con las líneas previstas dibujadas
encima y con su nombre.
-
+
*Las cuatro líneas altas caen sobre la BPFO y sus armónicos; no aparece nada en
-la BPFI ni en la BSF. Ese es el diagnóstico: un descascarillado en la pista
-exterior.*
+la BPFI, ni en la BSF, la frecuencia de rotación del elemento rodante, ni en la
+BDF de 183 Hz, donde golpearía un elemento rodante dañado. Ese es el
+diagnóstico: un descascarillado en la pista exterior.*
Ver el código de esta figura
@@ -94,7 +95,15 @@ $f_s = N/60$:
Tres de ellas llevan el diagnóstico: `BPFO` para un defecto en la pista
exterior, `BPFI` para un defecto en la pista interior y `BDF` para un elemento
-rodante o una jaula dañados. Dos identidades conviene recordarlas porque son
+rodante o una jaula dañados. Las dos filas del elemento rodante se diferencian
+en un factor dos porque responden a preguntas distintas: `BSF` es a qué
+velocidad gira un elemento rodante, y `BDF` con qué frecuencia un defecto suyo
+golpea una pista — dos veces por vuelta del elemento, una contra cada pista. La
+evidencia de un elemento rodante dañado se espera, por tanto, en la `BDF`
+(183,3 Hz para el rodamiento de arriba), normalmente modulada a la frecuencia
+de la jaula `FTF`, mientras que la línea que la figura dibuja en 91,7 Hz es la
+frecuencia de rotación del elemento rodante, la `BSF`. Dos identidades
+conviene recordarlas porque son
exactas y detectan al instante los errores de introducción de datos:
$\text{BPFO} + \text{BPFI} = Z f_s$ siempre, y
$\text{BPFO} = Z \times \text{FTF}$ siempre que la pista exterior esté
@@ -187,8 +196,24 @@ una barra de rotor rota coloca alrededor de `1x`.
La frecuencia de paso de pala de un rodete de $N$ palas es $f_b = n N f_s$
(Ec. 8.15); las pulsaciones hidráulicas de una bomba siguen la misma forma
con $N$ eventos de bombeo por vuelta (Ec. 8.18), y una soplante
-volumétrica rotativa repite cuatro veces por vuelta, así que se trata
-pasando $4 \times \text{r/min}$.
+volumétrica rotativa repite cuatro veces por vuelta, lo que se trata
+pasando $4 \times \text{r/min}$ con una sola «pala»:
+
+```python
+from phonometry import blade_pass_frequencies
+
+# Una soplante volumétrica rotativa a 1200 r/min: cuatro pulsaciones por
+# vuelta, así que la frecuencia de pulsación se pide como 4 x r/min con N = 1.
+res = blade_pass_frequencies(4 * 1200.0, 1, harmonics=3)
+print(round(res["BPF"], 1)) # 80.0 Hz, la frecuencia de pulsación
+print(round(res.shaft_rate, 1)) # 80.0 Hz - NO la del eje, que es 20
+```
+
+El truco cuesta la línea del eje: `shaft_rate` vuelve valiendo $4 f_s$, así que
+lee la frecuencia del eje de una llamada aparte a la velocidad verdadera (o de
+`bearing_fault_frequencies`) antes de combinar familias con
+`combine_fault_lines`, o se dibujará un cuarto armónico del eje como si fuera
+evidencia de rodamiento.
En un **ventilador axial entubado** las palas interaccionan además con los
álabes del estátor y establecen patrones de presión rotativos con
@@ -201,9 +226,7 @@ porque la Ec. (8.17) lleva $n$, de modo que el mismo número de lóbulos
alcanzado desde otro armónico es otro patrón, que gira a otra velocidad.
```python
-from phonometry import blade_pass_frequencies
-
-# Seis palas, cuatro álabes, 3500 r/min.
+# Seis palas, cuatro álabes, 3500 r/min (blade_pass_frequencies importado arriba).
res = blade_pass_frequencies(3500.0, 6, harmonics=1, n_vanes=4)
print(round(res["BPF"])) # 350
print(round(res["lobe n=1 m=2"]), round(res["lobe n=1 m=10"])) # 175 35
diff --git a/site/src/content/docs/es/vibration/structural/junction-transmission.mdx b/site/src/content/docs/es/vibration/structural/junction-transmission.mdx
index 86dd618ce..fd3198588 100644
--- a/site/src/content/docs/es/vibration/structural/junction-transmission.mdx
+++ b/site/src/content/docs/es/vibration/structural/junction-transmission.mdx
@@ -256,14 +256,28 @@ from phonometry import junction_transmission, wave_vibration_reduction_index
# 100 mm, placa 2 en barrido de 50 mm a 400 mm.
h1, cl, rho = 0.1, 3200.0, 2400.0
ratios = np.linspace(0.5, 4.0, 36)
-kij_corner = []
+curves = {"X esquina": [], "X recta": [], "unión en T (1) esquina": [],
+ "L esquina": []}
for ratio in ratios:
h2 = h1 * float(ratio)
- res = junction_transmission("X", h1, cl, rho * h1, h2, cl, rho * h2)
- kij_corner.append(res.corner_reduction_index)
+ res_x = junction_transmission("X", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["X esquina"].append(res_x.corner_reduction_index)
+ # En el resultado solo viene precalculado el índice de esquina; el camino
+ # recto es la media angular tau13 convertida de la misma forma.
+ curves["X recta"].append(float(wave_vibration_reduction_index(
+ res_x.straight_average, res_x.critical_frequency2)))
+ res_t = junction_transmission("T1", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["unión en T (1) esquina"].append(res_t.corner_reduction_index)
+ res_l = junction_transmission("L", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["L esquina"].append(res_l.corner_reduction_index)
fig, ax = plt.subplots()
-ax.plot(ratios, kij_corner, label="X esquina")
+for label, values in curves.items():
+ ax.plot(ratios, values, "--" if label == "X recta" else "-", label=label)
+# La unión en X de placas idénticas: Kij = 10 lg 12 + 5 lg(fc2/1000).
+res_eq = junction_transmission("X", h1, cl, rho * h1, h1, cl, rho * h1)
+ax.scatter([1.0], [res_eq.corner_reduction_index], zorder=6,
+ label="placas idénticas (tau = 1/12)")
ax.set_xlabel("Relación de espesores h2/h1")
ax.set_ylabel("Índice de reducción de vibraciones Kij [dB]")
ax.set_title("Kij de unión por el enfoque ondulatorio (Hopkins Ec. 5.116)")
@@ -276,8 +290,9 @@ plt.show()
## 5. Ejemplo resuelto: llevar Kij a la EN 12354
El número que predice esta página es exactamente el que consume el modelo de
-flancos de EN 12354-1. Toma la unión en X de hormigón de 100 mm / 200 mm de
-la figura inicial: su camino de esquina da $K_{12} = 9{,}8\ \text{dB}$.
+flancos de EN 12354-1. Toma la unión en X de hormigón de 100 mm / 200 mm de la
+figura de $\tau(\theta)$ del apartado 2: su camino de esquina da
+$K_{12} = 9{,}8\ \text{dB}$.
Entregarlo a
`flanking_element` en lugar de un valor tabulado del Anexo E valora los tres
caminos de flancos de la unión y su efecto sobre el índice aparente:
@@ -285,7 +300,7 @@ caminos de flancos de la unión y su efecto sobre el índice aparente:
```python
from phonometry import building, junction_transmission
-# La unión en X de hormigón de 100 mm / 200 mm de la figura inicial:
+# La unión en X de hormigón de 100 mm / 200 mm de la figura de tau(theta):
res = junction_transmission("X", 0.1, 3200.0, 240.0, 0.2, 3200.0, 480.0)
k12 = res.corner_reduction_index # 9.8 dB (camino de esquina)
@@ -468,9 +483,15 @@ midiendo ambas energías en cada caso. Eso da cuatro ecuaciones para $\eta_1$,
$\eta_2$, $\eta_{12}$ y $\eta_{21}$ sin ninguna hipótesis previa, que
`power_injection_matrix` resuelve banda a banda. La reciprocidad pasa entonces a
ser una *comprobación* de la medida en lugar de un dato de entrada:
-`modal_density_ratio` compara el $\eta_{21}/\eta_{12}$ medido con el $n_1/n_2$
-calculado a partir de la geometría, y una discrepancia grande significa que las
-fronteras de los subsistemas se trazaron en el sitio equivocado.
+`PowerInjectionResult.modal_density_ratio` es una propiedad, no una función, y
+devuelve únicamente el $n_1/n_2$ que *implican* los factores de pérdidas por
+acoplamiento medidos, $\eta_{21}/\eta_{12}$. Convertirlo en comprobación es
+tarea del lector: compáralo con la relación construida a partir de la geometría
+con `flat_plate_modal_density` y sus hermanas, y una discrepancia grande
+significa que las fronteras de los subsistemas se trazaron en el sitio
+equivocado. `coupling_strength` es el otro diagnóstico del mismo resultado, y
+dice si la hipótesis de acoplamiento débil sobre la que se apoya la inversión
+se sostiene siquiera.
## Véase también
diff --git a/site/src/content/docs/es/vibration/structural/transfer-stiffness.mdx b/site/src/content/docs/es/vibration/structural/transfer-stiffness.mdx
index 234828f21..d7d8b0e60 100644
--- a/site/src/content/docs/es/vibration/structural/transfer-stiffness.mdx
+++ b/site/src/content/docs/es/vibration/structural/transfer-stiffness.mdx
@@ -82,7 +82,7 @@ fig, ax = plt.subplots()
ax.semilogx(f, vibration.transfer_stiffness_level(k_true),
label="$L_k$ real de $k+j\\omega c$")
ax.semilogx(f, vibration.transfer_stiffness_level(k_indirect), "--",
- label="método indirecto $-(2\\pi f)^2 m_2 T$")
+ label="método indirecto $-(2\\pi f)^2 m_2 T$") # aquí no hay brida
ax.axvline(f0, color="0.6", linestyle=":", label="resonancia $f_0$")
ax.set(xlabel="Frecuencia [Hz]", ylabel="Nivel de rigidez de transferencia $L_k$ [dB re 1 N/m]")
ax.grid(True, which="both", alpha=0.3)
@@ -138,16 +138,25 @@ $$
k_{2,1} = -(2\pi f)^2\,(m_2 + m_f)\,T \qquad (T \ll 1),
$$
-con $m_f$ la masa de la brida de salida. La aproximación es válida bastante por
+con $m_f$ la masa de la brida de salida, que transporta la palabra clave
+`flange_mass=` (vale cero por defecto). No es un refinamiento: la ISO 10846-3
+mide la vibración del centro de masas del *cuerpo compacto* que forman la masa
+de bloqueo junto con la brida de salida del elemento de ensayo, así que $m_f$
+es todo lo que se pese con ella — la brida y cualquier utillaje auxiliar que se
+mueva como parte del elemento de ensayo. Dejada en cero, declara una rigidez
+baja en un factor $m_2/(m_2 + m_f)$. La aproximación es válida bastante por
encima de la resonancia masa/resorte, donde $T$ es pequeña.
```python
import numpy as np
from phonometry import vibration
-# Método indirecto: masa de bloqueo de 10 kg, transmisibilidad 0,01 a 500 Hz.
-k = vibration.transfer_stiffness_indirect(500.0, 0.01, blocking_mass=10.0)
-print(f"{abs(complex(k)):.3e}") # 9.870e+05 N/m
+# Método indirecto: masa de bloqueo de 10 kg, transmisibilidad 0,01 a 500 Hz,
+# y la brida de salida de 1,2 kg del elemento de ensayo atornillada encima.
+k = vibration.transfer_stiffness_indirect(500.0, 0.01, blocking_mass=10.0,
+ flange_mass=1.2)
+print(f"{abs(complex(k)):.3e}") # 1.105e+06 N/m
+# flange_mass vale 0 por defecto, lo que declara 9.870e+05 N/m: aquí un 12 % baja.
# Agrupa una medición en barrido en un resultado con su nivel y factor de pérdidas:
f = np.logspace(1.5, 3.3, 200)
@@ -279,7 +288,8 @@ res.report(
(ISO 10846-2 y -3, 3.17) y el factor de pérdidas (ISO 10846-1, 3.8)
(`transfer_stiffness_level`, `loss_factor`), el método directo de la
ISO 10846-2:2008 (`transfer_stiffness_direct`) y el método indirecto de la
-ISO 10846-3:2002 de la Fórmula 1 (`transfer_stiffness_indirect`). También
+ISO 10846-3:2002 de la Fórmula 1 (`transfer_stiffness_indirect`, incluido su
+término `flange_mass=`). También
están implementadas la aproximación de la fuerza de bloqueo de las
Ecuaciones 6-7 (`blocking_force_ratio`) y las relaciones FRF del Anexo A /
Tabla A.2 (`convert_frf`). `TransferStiffnessResult` agrupa una
diff --git a/site/src/content/docs/materials/absorbers/absorption-measurement.mdx b/site/src/content/docs/materials/absorbers/absorption-measurement.mdx
index db74830ad..eb845d66c 100644
--- a/site/src/content/docs/materials/absorbers/absorption-measurement.mdx
+++ b/site/src/content/docs/materials/absorbers/absorption-measurement.mdx
@@ -35,6 +35,7 @@ references:
import ThemeImage from '../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../components/ReportPreview.astro';
+import Video from '../../../../components/Video.astro';
Of all the numbers a materials laboratory produces, the sound-absorption
coefficient is the one that travels furthest: it leaves the reverberation room
@@ -224,7 +225,28 @@ print(np.round(alpha, 3)) # [0.398 0.448 0.498]
$T_1$ and $T_2$ are exactly the reverberation times [`room_parameters`](/phonometry/buildings/rooms/room-acoustics/) returns, so
an ISO 3382-2 decay measurement of the empty and treated room flows straight
-into `absorption_coefficient`. A room volume below the 150 m³ minimum or a
+into `absorption_coefficient`.
+
+Each of those two numbers is read off a decay, and the clip below shows how
+one is read: the squared impulse response is integrated backwards from the
+tail, the Schroeder curve emerges, and the T20 and T30 regressions are fitted
+to a straight portion of it. That is the operation behind $T_1$, and again
+behind $T_2$ — the clip shows a *single* room, not the pair, so it answers
+"where does one $T$ come from" and not "what does subtracting two of them
+cost". The second question is the one that governs this measurement, and
+section 4 puts a number on it: because $\alpha_s$ is a difference of two
+reciprocal decay times, its uncertainty is worst exactly where the two decays
+are most alike, at the low-frequency end.
+
+
+
+A room volume below the 150 m³ minimum or a
sample area outside 10–12 m² raises an advisory `AbsorptionWarning`; the result
still returns.
@@ -422,10 +444,18 @@ $$
\alpha_{st} = \int_0^{\pi/2} \alpha(\theta)\,\sin 2\theta\,\mathrm{d}\theta,
$$
-an integral that weights the oblique angles most heavily; evaluating it
-needs the
-angle-dependent $\alpha(\theta)$ from the measured surface impedance, not just
-the normal-incidence coefficient itself.
+an integral that weights the oblique angles most heavily. It needs the
+angle-dependent $\alpha(\theta)$, not the normal-incidence coefficient itself
+— but for a **locally reacting** surface $\alpha(\theta)$ follows from the
+normalised surface impedance alone, so the integral has a closed form and a
+tube result converts in one line:
+`materials.statistical_absorption(result.normalized_impedance)`, documented
+with the
+[multilayer models](/phonometry/materials/absorbers/porous-absorbers/#4-oblique-and-random-incidence).
+What that cannot do is cover a **bulk-reacting** layer, where the oblique
+behaviour depends on refraction inside the material and the integral has to be
+evaluated angle by angle from a model — `diffuse_field_absorption`, on the same
+page.
**Why ISO 354 values exceed 1.** A ratio of absorbed to incident energy cannot
exceed one, yet reverberation-room reports of $\alpha_s = 1.05$ to $1.20$ for
@@ -545,11 +575,13 @@ one-third-octave and practical coefficients and for the single-number
ratings, in `sound_absorption_coefficient_uncertainty`,
`weighted_coefficient_uncertainty` and `single_number_rating_uncertainty`.
-**Not covered.** The statistical (random-incidence) absorption coefficient
-$\alpha_{st}$ of Paris' angular average is described but not computed: it
-needs the angle-dependent $\alpha(\theta)$ from the surface impedance, which
-the [impedance tube](/phonometry/materials/absorbers/impedance-tube/) recovers and nothing
-here consumes. ISO 354's room-qualification requirements (Annex A: the number
+**Not covered.** Nothing on *this* page consumes a measured surface impedance:
+the conversion from a tube result to the statistical coefficient
+$\alpha_{st}$ lives with the prediction models
+(`statistical_absorption` for a locally reacting surface,
+`diffuse_field_absorption` for a bulk-reacting one), and neither is a
+substitute for an ISO 354 measurement, because neither reproduces the edge
+effect. ISO 354's room-qualification requirements (Annex A: the number
of loudspeaker and microphone positions, the diffusing elements) are not
checked; `absorption_area`/`absorption_coefficient` only convert an
already-measured $T_1$/$T_2$ pair and raise an advisory warning when the room
diff --git a/site/src/content/docs/materials/absorbers/impedance-tube.mdx b/site/src/content/docs/materials/absorbers/impedance-tube.mdx
index e92abaef1..1811a6d4b 100644
--- a/site/src/content/docs/materials/absorbers/impedance-tube.mdx
+++ b/site/src/content/docs/materials/absorbers/impedance-tube.mdx
@@ -373,19 +373,45 @@ fiche embeds, matplotlib (`pip install "phonometry[report,plot]"`); only
`language="es"` for a Spanish fiche (translated fixed strings and a comma
decimal separator).
+The block below is the specimen of the fiche underneath it: a resistive facing
+of normalised flow resistance $\theta = 1$ over an 86 mm rigidly-backed air
+cavity, whose surface impedance $z = \theta - \mathrm{j}\cot(k_0 L)$ is known
+in closed form, so the printed $\alpha$ can be checked by hand: 1.00 at the
+1 kHz quarter-wave resonance, where the matched screen gives $z = 1$ and
+$r = 0$; 0.80 at 500 Hz, where $k_0 L = \pi/4$ and $z = 1 - \mathrm{j}$.
+
```python
+import numpy as np
from phonometry import materials, ReportMetadata
-result = materials.two_microphone_impedance(
- h12, frequency=freqs, spacing=0.05, x1=0.10,
- speed_of_sound=c0, characteristic_impedance=rho_c, diameter=0.10,
+# 100 mm tube, s = 50 mm, far microphone at x1 = 100 mm, 20 degC / 101 kPa.
+c0 = float(materials.speed_of_sound_iso(293.15)) # 343.29 m/s
+rho_c = materials.characteristic_impedance(
+ float(materials.air_density_iso(293.15, 101.0)), c0) # 405.6 Pa.s/m
+diameter, spacing, x1 = 0.100, 0.050, 0.100
+theta, cavity = 1.0, c0 / (4.0 * 1000.0) # quarter-wave at 1 kHz: 86 mm
+freqs = np.array([400, 500, 630, 800, 1000, 1250, 1600], dtype=float)
+
+# The transfer function the tube would measure, synthesised from the known r.
+k0 = materials.tube_wavenumber(freqs, c0)
+z = theta - 1j / np.tan(2 * np.pi * freqs / c0 * cavity)
+r_known = (z - 1.0) / (z + 1.0)
+x2 = x1 - spacing
+h12_fiche = (np.exp(1j*k0*x2) + r_known*np.exp(-1j*k0*x2)) / \
+ (np.exp(1j*k0*x1) + r_known*np.exp(-1j*k0*x1))
+
+fiche = materials.two_microphone_impedance(
+ h12_fiche, frequency=freqs, spacing=spacing, x1=x1,
+ speed_of_sound=c0, characteristic_impedance=rho_c, diameter=diameter,
)
-result.report(
+print(np.round(fiche.absorption, 2)) # [0.68 0.8 0.9 0.97 1. 0.96 0.68]
+
+fiche.report(
"alpha_fiche.pdf",
metadata=ReportMetadata(
specimen="Resistive facing over an 86 mm rigidly-backed air cavity",
- tube_diameter=0.10, # m (printed as 100 mm)
- mic_spacing=0.05, # m (printed as 50 mm)
+ tube_diameter=diameter, # m (printed as 100 mm)
+ mic_spacing=spacing, # m (printed as 50 mm)
measurement_standard="ISO 10534-2",
laboratory="Phonometry Reference Laboratory",
),
diff --git a/site/src/content/docs/materials/absorbers/metamaterial-absorbers.mdx b/site/src/content/docs/materials/absorbers/metamaterial-absorbers.mdx
index 434e22615..3ec816db5 100644
--- a/site/src/content/docs/materials/absorbers/metamaterial-absorbers.mdx
+++ b/site/src/content/docs/materials/absorbers/metamaterial-absorbers.mdx
@@ -69,9 +69,10 @@ A porous blanket absorbs low frequencies only by growing thick: the
absorption where the layer is a fair fraction of the wavelength, which at
300 Hz means tens of centimetres. Acoustic metamaterial absorbers break that
rule with resonance instead of bulk. A rigid panel of thin closed slits, each
-loaded by Helmholtz resonators, slows the sound inside the slit until a 3 cm
-panel resonates where a plain cavity of the same depth would need to be ten
-times deeper, and tuning the panel's internal losses against its leakage
+loaded by Helmholtz resonators, slows the sound inside the slit so drastically
+that a 3 cm panel resonates at about 300 Hz — where an empty quarter-wave
+cavity would have to be ten times deeper, since 3 cm of plain air resonates at
+2.9 kHz (section 3). Tuning the panel's internal losses against its leakage then
produces **perfect absorption**, $\alpha = 1$, at a design frequency where the
panel is only $\lambda/38$ deep; published designs of the same family reach
$\lambda/88$ (Jiménez et al. 2016). This guide covers the critical-coupling
diff --git a/site/src/content/docs/materials/absorbers/porous-absorbers.mdx b/site/src/content/docs/materials/absorbers/porous-absorbers.mdx
index abdb2bfca..dae6a3e01 100644
--- a/site/src/content/docs/materials/absorbers/porous-absorbers.mdx
+++ b/site/src/content/docs/materials/absorbers/porous-absorbers.mdx
@@ -661,7 +661,30 @@ Fok-function interaction fit
$\delta = 0.85\,(1 - 1.47\sqrt{\varepsilon} + 0.47\varepsilon^{3/2})$
(Table 7.1), valid for any open area. For a
shallow cavity the resonance is
-$f_0 = (c_0/2\pi)\sqrt{\varepsilon/(t'\,d)}$ (Eq. 7.4).
+$f_0 = (c_0/2\pi)\sqrt{\varepsilon/(t'\,d)}$ (Eq. 7.4). In those two
+expressions $t$ is the plate thickness, $a$ the hole **radius**, $\varepsilon$
+the open area (hole area over panel area), $\nu$ the kinematic viscosity of
+air, $t' = t + 2\delta a$ the end-corrected plate thickness and $d$ the cavity
+depth behind the panel.
+
+### The sheet layer classes: parameters
+
+The three sheet layers take positional arguments, and the hole dimension is a
+**radius**, not a diameter — half the drilled hole. Getting that wrong
+computes the resonance and the peak absorption for a hole twice the real size.
+
+| Class | Parameter | Units | Notes |
+| :--- | :--- | :--- | :--- |
+| `PerforatedPlateLayer` | `thickness` | m | Plate thickness $t$ |
+| | `hole_radius` | m | Hole **radius** $a$, half the drilled diameter |
+| | `open_area` | — | Perforation ratio $\varepsilon$ = hole area / panel area |
+| | `end_correction` | — | $\delta$ per orifice end; `None` uses the Fok interaction fit |
+| `MicroperforatedPlateLayer` | `thickness` | m | Plate thickness $t$ |
+| | `hole_radius` | m | Hole **radius** $a$ |
+| | `open_area` | — | Perforation ratio $\varepsilon$ |
+| | `end_correction` | — | Default `0.85`, Maa's piston reactance |
+| `MembraneLayer` | `surface_density` | kg/m² | Mass per unit area $m$ |
+| | `resistance` | Pa·s/m | Added flow resistance; default `0.0` |
**Microperforated panel (MPP).** With submillimetre holes the viscous
boundary layer fills the orifice and the panel absorbs *without any porous
@@ -686,7 +709,8 @@ $f_2/f_1 = \pi/\mathrm{arccot}(1+r) - 1$ (Maa Eqs. 9–21, Table I).
import numpy as np
from phonometry import materials
-# Maa (1998) Fig. 5: d = t = 0.2 mm, holes every 2.5 mm, cavity 6 cm.
+# Maa (1998) Fig. 5: hole diameter 0.2 mm (so hole_radius = 0.1 mm),
+# plate 0.2 mm thick, holes every 2.5 mm, cavity 6 cm.
eps = (np.pi / 4.0) * (0.2 / 2.5) ** 2
f = np.linspace(100.0, 4000.0, 2000)
res = materials.layered_absorber(
@@ -715,7 +739,8 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import materials
-# Maa (1998) Fig. 5: d = t = 0.2 mm, holes every 2.5 mm, cavity 6 cm.
+# Maa (1998) Fig. 5: hole diameter 0.2 mm (so hole_radius = 0.1 mm),
+# plate 0.2 mm thick, holes every 2.5 mm, cavity 6 cm.
eps = (np.pi / 4.0) * (0.2 / 2.5) ** 2
f = np.linspace(100.0, 4000.0, 1200)
res = materials.layered_absorber(
diff --git a/site/src/content/docs/materials/diffusers/diffusers.mdx b/site/src/content/docs/materials/diffusers/diffusers.mdx
index 375a04617..49e498306 100644
--- a/site/src/content/docs/materials/diffusers/diffusers.mdx
+++ b/site/src/content/docs/materials/diffusers/diffusers.mdx
@@ -80,13 +80,30 @@ tens of centimetres deep, have their own guide:
## 1. Random-incidence scattering coefficient (ISO 17497-1)
The scattering coefficient $s$ is the fraction of reflected energy that does
-**not** leave the surface in the specular direction. ISO 17497-1 measures it in a
-reverberation room from four reverberation-time situations: with the test sample
-mounted on a turntable and held **stationary**, and with the turntable
-**rotating** (which averages the phase-coherent specular reflection away), each
-with and without a reflecting base plate.
-
-
+**not** leave the surface in the specular direction. ISO 17497-1 measures it in
+a reverberation room from four reverberation times. The turntable and its rigid
+circular base plate stay in the room for all four, symmetrical about the axis
+of rotation and sized to the sample; what changes is whether the **test sample**
+is on the plate and whether the plate **turns** (Table 2):
+
+| | Test sample | Turntable |
+| :--- | :--- | :--- |
+| $T_1$ | not present | not rotating |
+| $T_2$ | present | not rotating |
+| $T_3$ | not present | rotating |
+| $T_4$ | present | rotating |
+
+$(T_1, T_2)$ is an ordinary ISO 354 absorption measurement of the specimen and
+yields the random-incidence $\alpha_s$; $(T_3, T_4)$ repeats it under rotation
+and yields the specular $\alpha_{spec}$. The area $S$ in both formulas is the
+**specimen** area, not the base-plate area. The pair $(T_1, T_3)$ is not waste
+either: it is the base-plate quality check of Eq. (6), below.
+
+Sanity check before you compute anything: adding the sample always shortens the
+decay, so $T_2 < T_1$ and $T_4 < T_3$. A negative absorption coefficient means
+the members of a pair went in the wrong way round.
+
+
**Absorption from reverberation time (Clause 6).** Each situation converts to a
Sabine absorption coefficient with the standard's own air-attenuation term:
@@ -98,9 +115,9 @@ $$
where $V$ is the room volume, $S$ the sample area, $T$ the reverberation time,
$c$ the speed of sound (Eq. (2): $c = 343.2\sqrt{(273.15+t)/293.15}$) and $m$ the
-power attenuation coefficient of air. The **stationary** pair gives the
-random-incidence absorption $\alpha_s$ (Eq. (1)); the **rotating** pair gives the
-specular absorption $\alpha_{spec}$ (Eq. (4)).
+power attenuation coefficient of air. The **static** pair $(T_1, T_2)$ gives the
+random-incidence absorption $\alpha_s$ (Eq. (1)); the **rotating** pair
+$(T_3, T_4)$ gives the specular absorption $\alpha_{spec}$ (Eq. (4)).
**Scattering coefficient (Eq. (5)).** The two combine into
@@ -116,12 +133,14 @@ energy everywhere, raising $\alpha_{spec}$ towards 1 and $s$ towards 1.
from phonometry import materials
# Four reverberation-time situations reduced to two absorption coefficients.
-# alpha_s from the stationary pair (Eq. 1); alpha_spec from the rotating pair
-# (Eq. 4). V = 200 m^3, S = 10 m^2, c = 343.2 m/s throughout.
-alpha_s = materials.random_incidence_absorption(200.0, 10.0, c1=343.2, t1=8.0,
- c2=343.2, t2=6.0)
-alpha_spec = materials.specular_absorption_coefficient(200.0, 10.0, c3=343.2, t3=7.5,
- c4=343.2, t4=5.0)
+# alpha_s from the static pair (Eq. 1); alpha_spec from the rotating pair
+# (Eq. 4). V = 200 m^3, S = 10 m^2 (the SAMPLE area), c = 343.2 m/s throughout.
+alpha_s = materials.random_incidence_absorption(200.0, 10.0,
+ c1=343.2, t1=8.0, # T1 base plate, static
+ c2=343.2, t2=6.0) # T2 sample, static
+alpha_spec = materials.specular_absorption_coefficient(200.0, 10.0,
+ c3=343.2, t3=7.5, # T3 base plate, rotating
+ c4=343.2, t4=5.0) # T4 sample, rotating
s = materials.scattering_coefficient(alpha_spec, alpha_s) # Eq. (5)
print(round(float(alpha_s), 4)) # 0.1343
print(round(float(alpha_spec), 4)) # 0.2148
@@ -137,7 +156,7 @@ import numpy as np
from phonometry import materials
# A 13-band measurement (250-4000 Hz): the random-incidence absorption alpha_s
-# (stationary sample) and the specular absorption alpha_spec (rotating
+# (sample on the static turntable) and the specular absorption alpha_spec (rotating
# turntable). A diffuser scatters more with frequency, so s(f) rises.
freqs = np.array([250, 315, 400, 500, 630, 800, 1000,
1250, 1600, 2000, 2500, 3150, 4000], float)
@@ -165,7 +184,7 @@ import numpy as np
from phonometry import materials
# A 13-band measurement (250-4000 Hz): the random-incidence absorption alpha_s
-# (stationary sample) and the specular absorption alpha_spec (rotating
+# (sample on the static turntable) and the specular absorption alpha_spec (rotating
# turntable). A diffuser scatters more with frequency, so s(f) rises.
freqs = np.array([250, 315, 400, 500, 630, 800, 1000,
1250, 1600, 2000, 2500, 3150, 4000], float)
@@ -243,9 +262,25 @@ $$
A perfectly uniform polar response ($L_i$ all equal) gives $d = 1$; a single
sharp specular lobe gives $d = 0$. When receivers subtend unequal solid angles,
-Formula (6) area-weights each energy by $N_i$ from Formula (8), and those area
-factors are evaluated in **radians**, which is why a 5° spacing at the zenith
-produces a weight near 1.57, not 51.9.
+Formula (6) area-weights each energy by $N_i = A_i / A_\text{min}$ from
+Formula (8), with
+
+$$
+A_i = \frac{4\pi}{\Delta\phi}\sin^2\frac{\Delta\theta}{4}\ (\theta = 0),
+\qquad
+A_i = 2\sin\theta\,\sin\frac{\Delta\theta}{2}\ (0 < \theta < 90°),
+\qquad
+A_i = \sin\frac{\Delta\theta}{2}\ (\theta = 90°).
+$$
+
+Every angle in those three forms is handled in **radians**, including the
+$\Delta\phi$ under the $4\pi$ of the zenith term — that is what keeps the
+zenith dimensionally consistent with the other two. On the standard
+5° × 5° hemisphere the areas come out 0.0685 at the zenith, 0.0076 at
+$\theta = 5°$ (the smallest, so $A_\text{min}$) and 0.0436 at the pole, so the
+weights run 9.01 at the zenith, 1 on the first ring off it and 5.74 at the
+pole. Check yours with `materials.area_factors(elevations, delta_theta=5.0)`
+before feeding a hand-built weight vector into Formula (6).
The rig those formulas assume is worth drawing to scale.
`plot_goniometer_geometry` lays out the standard arrangement in plan: the
@@ -278,6 +313,13 @@ plane wavefront hits a flat rigid panel and a Schroeder diffuser (an $N = 7$
quadratic-residue profile), and the scattered energy on the receiver arc turns
a collimated specular beam ($d = 0.32$) into a wide fan ($d = 0.63$).
+Those two numbers are not comparable with the coefficients computed below. The
+simulated panels are a single short period read in the near field of a 2-D
+grid; the prediction that follows is a six-period 3.6 m array read in the far
+field, where the periodicity funnels the energy into a few grating lobes and
+drives every coefficient down. Diffusion coefficients only compare within one
+geometry, one arc and one distance — which is why ISO 17497-2 fixes all three.
+
diff --git a/site/src/content/docs/materials/resilient/dynamic-stiffness.mdx b/site/src/content/docs/materials/resilient/dynamic-stiffness.mdx
index f82c5ea0e..d29619e0b 100644
--- a/site/src/content/docs/materials/resilient/dynamic-stiffness.mdx
+++ b/site/src/content/docs/materials/resilient/dynamic-stiffness.mdx
@@ -47,7 +47,8 @@ from phonometry import materials
res = materials.floating_floor_resonance(
resonant_frequency=25.0, total_mass_per_area=200.0,
floor_mass_per_area=120.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 from ISO 9053)
+ thickness=0.020, porosity=0.9,
)
res.plot()
plt.show()
@@ -148,6 +149,19 @@ $r \ge 100\ \text{kPa}\cdot\text{s/m}^2$, $s' = s'_t + s'_a$ for
$10 \le r < 100\ \text{kPa}\cdot\text{s/m}^2$, and for
$r < 10\ \text{kPa}\cdot\text{s/m}^2$ the method only resolves $s' = s'_t$
when the gas term is negligible.
+
+**Mind the prefix.** $r$ is the quantity ISO 9053 calls $\sigma$ and reports in
+Pa·s/m², while EN 29052-1 writes it $r$ and thresholds it in **kPa·s/m²**. The
+library follows the standard, so `airflow_resistivity` is in kPa·s/m² — the one
+argument on this page that is not plain SI. A mineral wool measured at
+50 000 Pa·s/m² goes in as `50.0`, not `50000.0`; convert an
+[ISO 9053 result](/phonometry/materials/absorbers/airflow-resistance/) with
+`sigma / 1000`. Passing the Pa·s/m² number lands silently in the
+$r \ge 100$ branch, which drops the enclosed-gas term: for the determination
+below that turns $s' = 10.49$ MN/m³ into 4.93 MN/m³ and the design natural
+frequency from 47.1 Hz to 32.3 Hz, with no warning, because the wrong branch is
+a valid branch.
+
`floating_floor_resonance` chains the whole determination:
```python
@@ -156,7 +170,8 @@ from phonometry import materials
res = materials.floating_floor_resonance(
resonant_frequency=25.0, total_mass_per_area=200.0,
floor_mass_per_area=120.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 from ISO 9053)
+ thickness=0.020, porosity=0.9,
)
print(round(res.dynamic_stiffness / 1e6, 2), round(res.natural_frequency, 1))
# 10.49 47.1
@@ -190,7 +205,8 @@ from phonometry import ReportMetadata, materials
res = materials.floating_floor_resonance(
resonant_frequency=45.0, total_mass_per_area=200.0,
floor_mass_per_area=110.0,
- airflow_resistivity=50.0, thickness=0.020, porosity=0.9,
+ airflow_resistivity=50.0, # kPa.s/m2 (= 50000 Pa.s/m2 from ISO 9053)
+ thickness=0.020, porosity=0.9,
)
res.report(
"dynamic_stiffness.pdf",
@@ -255,7 +271,9 @@ white-noise or pulse methods and extrapolating to zero force amplitude, is
not implemented: pass an already-extrapolated $f_r$. The lateral airflow
resistivity $r$ of clause 8.2 is likewise taken as an input rather than
measured; ISO 9053's static and alternating methods are implemented
-separately, in `materials.absorbers.airflow_resistance`. Clause 6's specimen-selection
+separately, in `materials.absorbers.airflow_resistance`, and they report
+$\sigma$ in Pa·s/m² while this page's `airflow_resistivity` argument is in
+kPa·s/m². Clause 6's specimen-selection
requirement (at least three 200 mm × 200 mm specimens) is not enforced.
## See also
diff --git a/site/src/content/docs/materials/surfaces/road-absorption.mdx b/site/src/content/docs/materials/surfaces/road-absorption.mdx
index 0a57e3a9d..d1584abb0 100644
--- a/site/src/content/docs/materials/surfaces/road-absorption.mdx
+++ b/site/src/content/docs/materials/surfaces/road-absorption.mdx
@@ -260,21 +260,33 @@ $$
with $d$ the tube diameter, and the microphone spacing $s$ must sit between
$0.05\,c_0/f_{min}$ and $0.45\,c_0/f_{max}$. The reported range is the
-one-third-octave bands 250–1600 Hz.
+one-third-octave bands 250–1600 Hz, and the standard's own definition of a
+frequency range is by band *edges*: those centre frequencies mean 220 Hz to
+1800 Hz in narrow bands, which is where the two arguments below come from.
```python
from phonometry import materials
# Upper usable frequency of a 100 mm tube and the valid spacing window.
print(round(materials.spot_tube_upper_frequency(0.100, 343.0), 1)) # 1989.4 Hz
+# 220 Hz and 1800 Hz are the outer edges of the 250 Hz and 1600 Hz bands.
s_min, s_max = materials.spot_microphone_spacing_bounds(
343.0, f_min=220.0, f_max=1800.0)
print(round(s_min, 3), round(s_max, 3)) # 0.078 0.086 (metres)
```
-The frequency window is the price of portability: the tube diameter that
-keeps the mouth sealable on real pavement caps the upper bands at 1600 Hz,
-and the tube length caps the lower ones at 250 Hz, a narrower window than the
+Three numbers, three different limits, and they do reconcile. The 1989 Hz is
+the plane-wave ceiling of the 100 mm bore; the reported range stops one band
+below it because a band is only usable when its *whole* width is inside the
+valid range, and the 1600 Hz band reaches 1800 Hz. The 250 Hz floor is a
+**spacing** limit, not a length limit: below $f_{min}$ the two microphones are
+closer than 5 % of a wavelength apart and there is no phase difference left to
+resolve. Tube length answers a different question — it must be long enough for
+a plane wave to form, which Clause 5.4.2 meets by putting the microphones at
+least $3d$ from the source (a minimum length of 480 mm for the 100 mm tube).
+The resulting spacing window, 78 mm to 86 mm here, is why the standard
+specifies $(81 \pm 4)$ mm for a single microphone pair. It is a narrower
+window than the
250–4000 Hz of the subtraction technique. Within it, the reduction is the
ISO 10534-2 chain unchanged: the transfer function between the two
microphones separates incident and reflected waves, and the standard's
diff --git a/site/src/content/docs/perception/hearing/occupational-exposure.mdx b/site/src/content/docs/perception/hearing/occupational-exposure.mdx
index b0f78a169..bde777da0 100644
--- a/site/src/content/docs/perception/hearing/occupational-exposure.mdx
+++ b/site/src/content/docs/perception/hearing/occupational-exposure.mdx
@@ -51,8 +51,12 @@ to attach the normative uncertainty every occupational-hygiene report needs. The
Describe each activity as a `hearing.Task` with its samples and duration, then
call `hearing.task_based_exposure(tasks)`. For the Annex D welder's day below
-it returns `lex_8h` = 84.3 dB with an expanded uncertainty $U = 2.7$ dB, so the
-one-sided 95 % `upper_limit` is 87.0 dB. Unstructured days use
+it returns `lex_8h` = 84.3 dB with an `expanded_uncertainty` $U = 3.2$ dB, so
+the one-sided 95 % `upper_limit` is 87.5 dB, because the default includes the
+Annex C duration term $u_{1b}$ built from each task's `duration_range`. The §1
+snippet passes `include_duration_uncertainty=False` to reproduce Annex D case a,
+where the durations are treated as exact, and that is what drops $U$ to 2.7 dB
+and the upper limit to 87.0 dB. Unstructured days use
`job_based_exposure()` or `full_day_exposure()` on random samples instead.
## 1. The three measurement strategies (Clauses 9-11)
@@ -65,10 +69,12 @@ L_{EX,8h,m} = L_{p,A,eqT,m} + 10 \log_{10}(T_m/T_0), \qquad T_0 = 8\ \text{h},
$$
so a loud but short task contributes little. The *job-based* (Clause 10) and
-*full-day* (Clause 11) strategies instead take $N \ge 5$ (or three whole-day)
-random samples over a homogeneous exposure group and normalise the effective-day
-duration. The daily level is the same either way; the strategies differ in how
-the **uncertainty** is built.
+*full-day* (Clause 11) strategies instead take random samples over a homogeneous
+exposure group — $N \ge 5$ samples for the job-based strategy, at least three
+whole shifts for the full-day one — energy-average them, and normalise that
+average to the nominal eight-hour day with the effective working-day duration
+$T_e$ in the same $10\log_{10}(T_e/T_0)$ term. The daily level is the same
+either way; the strategies differ in how the **uncertainty** is built.
**Choosing a strategy.** ISO 9612 Table B.1 picks the strategy from the *work
pattern*, not from convenience, and the trade-off is coverage against effort.
diff --git a/site/src/content/docs/perception/psychoacoustics/advanced-loudness.mdx b/site/src/content/docs/perception/psychoacoustics/advanced-loudness.mdx
index 7c32d5fb9..52a219082 100644
--- a/site/src/content/docs/perception/psychoacoustics/advanced-loudness.mdx
+++ b/site/src/content/docs/perception/psychoacoustics/advanced-loudness.mdx
@@ -299,7 +299,24 @@ print(f"long-term loudness exceeded 5% of the time: {res.percentiles[5.0]:.3f} s
res.plot() # short-term S'(t) and long-term S''(t) loudness vs time
```
-
+The short-term loudness rises within a few tens of milliseconds and falls back
+slowly, mimicking the ear's fast onset sensitivity and its slower recovery; the
+long-term loudness integrates that trace again with a much longer time
+constant, so it barely reacts to a single syllable and instead tracks the
+overall level of an event. The peak of that slow trace, $N_\text{max}$, is the
+standard's predictor of the loudness of a short sound, and its validity stops
+at roughly 5 s because beyond that a listener stops judging the sound as one
+event. That is also why the percentiles sit beside it: for a sound that
+fluctuates without a clear event structure, a percentile of the long-term
+loudness (typically the 5 % value) is the stable statistic, where
+$N_\text{max}$ would be set by the single worst moment.
+
+
+
+*A 200 ms 1 kHz burst at 60 dB SPL: the short-term loudness reaches 4.8 sone
+within a few tens of milliseconds and releases quickly, while the long-term
+loudness integrates to 3.6 sone and decays slowly after the burst ends — the
+pair of time constants ISO 532-3 clauses 7.8/7.9 define.*
Show the code for this figure
@@ -309,22 +326,19 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
-fs = 32000
-t = np.arange(int(1.3 * fs)) / fs
-x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)
-res = psychoacoustics.loudness_moore_glasberg_time(x, fs, field="free")
+# The figure is a burst, not a steady tone: 1 kHz at 60 dB SPL, gated on
+# between 200 and 400 ms of an 0.8 s record.
+fs = 48000
+t = np.arange(int(0.8 * fs)) / fs
+sig = np.zeros_like(t)
+on = (t >= 0.2) & (t < 0.4)
+sig[on] = np.sqrt(2) * 2e-5 * 10 ** (60 / 20) * np.sin(2 * np.pi * 1000 * t[on])
+burst = psychoacoustics.loudness_moore_glasberg_time(sig, fs)
+print(round(float(burst.short_term_loudness.max()), 1),
+ round(float(burst.long_term_loudness.max()), 1)) # 4.8 3.6
# The result carries both traces on a 1 ms time axis:
-res.plot()
-plt.show()
-
-# Or plot them directly to see the fast STL vs the slow LTL:
-fig, ax = plt.subplots()
-ax.plot(res.time, res.short_term_loudness, label="Short-term S'(t)")
-ax.plot(res.time, res.long_term_loudness, label="Long-term S''(t)")
-ax.set_xlabel("Time [s]")
-ax.set_ylabel("Loudness [sone]")
-ax.legend()
+burst.plot()
plt.show()
```
@@ -370,7 +384,12 @@ print(res.specific_loudness.shape) # (53,) average specific loudness N'
res.plot() # average specific loudness N'(z) + time-dependent N(l) at 187.5 Hz
```
-
+
+
+*The 1 kHz tone at 60 dB SPL, N = 2.8 sone_HMS — a louder tone than the 40 dB
+anchor of the snippet above, which gives 0.98 sone_HMS. The loudness is the
+area under $N'(z)$, so a broadband sound spreading a low pattern over many
+bands can outweigh this single peak.*
Show the code for this figure
@@ -380,10 +399,12 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
+# The figure is the 60 dB tone, not the 40 dB anchor of the snippet above.
fs = 48000
t = np.arange(int(1.2 * fs)) / fs
-x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)
+x = np.sqrt(2) * 2e-5 * 10 ** (60 / 20) * np.sin(2 * np.pi * 1000 * t)
res = psychoacoustics.loudness_ecma(x, fs, field="free")
+print(f"N = {res.loudness:.1f} sone_HMS") # 2.8 sone_HMS
# The result carries the average specific loudness over the 53 Bark_HMS bands:
res.plot()
diff --git a/site/src/content/docs/perception/psychoacoustics/index.md b/site/src/content/docs/perception/psychoacoustics/index.md
index 3e10f8569..1a4b93932 100644
--- a/site/src/content/docs/perception/psychoacoustics/index.md
+++ b/site/src/content/docs/perception/psychoacoustics/index.md
@@ -37,8 +37,11 @@ ISO 1996-2.
[Psychoacoustic annoyance and fluctuation strength](/phonometry/perception/psychoacoustics/psychoacoustic-annoyance/)
closes the chain with the Fastl & Zwicker model, which combines loudness,
sharpness, roughness and the slow-modulation sensation of fluctuation strength
-into a single annoyance value. Read it last: its four inputs all come from
-the earlier pages.
+into a single annoyance value. Read it last: three of its four inputs come from
+the earlier pages, and it supplies the fourth, fluctuation strength, itself, in
+both the Fastl & Zwicker closed form and the Osses 2016 signal model. The
+ECMA-418-2 fluctuation strength on the Sound Quality page is a further,
+normative model of the same sensation, under a different unit name.
## Pages in this section
diff --git a/site/src/content/docs/perception/psychoacoustics/loudness.mdx b/site/src/content/docs/perception/psychoacoustics/loudness.mdx
index b3af69fca..497c1f359 100644
--- a/site/src/content/docs/perception/psychoacoustics/loudness.mdx
+++ b/site/src/content/docs/perception/psychoacoustics/loudness.mdx
@@ -138,8 +138,8 @@ broad = psychoacoustics.loudness_zwicker_from_spectrum(np.full(28, 60.0))
z = np.arange(1, narrow.specific.size + 1) * 0.1 # Bark axis
fig, ax = plt.subplots()
for r, color, label in [
- (broad, "#ff7f0e", f"Broadband N = {broad.loudness:.1f} sone"),
- (narrow, "#1f77b4", f"1 kHz narrowband N = {narrow.loudness:.1f} sone"),
+ (broad, "#d62728", f"Flat broadband 60 dB - N = {broad.loudness:.1f} sone"),
+ (narrow, "#1f77b4", f"1 kHz narrowband - N = {narrow.loudness:.1f} sone"),
]:
ax.fill_between(z, r.specific, color=color, alpha=0.3)
ax.plot(z, r.specific, color=color, label=label)
diff --git a/site/src/content/docs/perception/psychoacoustics/sound-quality.mdx b/site/src/content/docs/perception/psychoacoustics/sound-quality.mdx
index f3b551c0f..c15478ee0 100644
--- a/site/src/content/docs/perception/psychoacoustics/sound-quality.mdx
+++ b/site/src/content/docs/perception/psychoacoustics/sound-quality.mdx
@@ -223,10 +223,15 @@ res.plot() # time-dependent roughness R(l50) + specific-roughness heatmap
+*The two sensations, each read the way its clause defines it: tonality as a
+time trace, which separates a tone in noise from the noise alone, and roughness
+as a function of modulation rate, whose 70 Hz peak on a fully modulated 1 kHz
+carrier at 60 dB is the calibration point of the asper.*
+
Show the code for this figure
@@ -235,30 +240,38 @@ import matplotlib.pyplot as plt
import numpy as np
from phonometry import psychoacoustics
-fs = 48000
+fs, p0 = 48000, 2e-5
+
+# Top panel: tonality T(t) of a 1 kHz tone in noise against the noise alone,
+# each component at 50 dB SPL over 2 s.
t = np.arange(int(2.0 * fs)) / fs
-amp = np.sqrt(2) * 2e-5 * 10 ** (60 / 20)
-
-# A pure tone (tonal, smooth) vs a 70 Hz amplitude-modulated tone (rough),
-# both normalized to an overall level of 60 dB SPL:
-tone = amp * np.sin(2 * np.pi * 1000 * t)
-rough = (1.0 + np.cos(2 * np.pi * 70 * t)) * np.sin(2 * np.pi * 1000 * t)
-rough *= 2e-5 * 10 ** (60 / 20) / np.sqrt(np.mean(rough**2))
-
-scores = {
- "Pure tone": (psychoacoustics.tonality_ecma(tone, fs).tonality, psychoacoustics.roughness_ecma(tone, fs).roughness),
- "70 Hz AM tone": (psychoacoustics.tonality_ecma(rough, fs).tonality, psychoacoustics.roughness_ecma(rough, fs).roughness),
-}
-labels = list(scores)
-tonal = [scores[k][0] for k in labels]
-rough_v = [scores[k][1] for k in labels]
-xpos = np.arange(len(labels))
-fig, ax = plt.subplots()
-ax.bar(xpos - 0.2, tonal, 0.4, label="Tonality [tu_HMS]")
-ax.bar(xpos + 0.2, rough_v, 0.4, label="Roughness [asper]")
-ax.set_xticks(xpos)
-ax.set_xticklabels(labels)
-ax.legend()
+rng = np.random.default_rng(2026)
+noise = rng.standard_normal(t.size)
+noise *= p0 * 10 ** (50 / 20) / np.sqrt(np.mean(noise**2))
+tone = p0 * 10 ** (50 / 20) * np.sqrt(2) * np.sin(2 * np.pi * 1000 * t)
+tin = psychoacoustics.tonality_ecma(tone + noise, fs)
+pn = psychoacoustics.tonality_ecma(noise, fs)
+
+# Bottom panel: roughness of a 1 kHz carrier at 100 % AM, swept over the
+# modulation frequency (1 s per point at 60 dB SPL).
+tm = np.arange(fs) / fs
+fmods = np.array([20.0, 30, 40, 50, 60, 70, 80, 100, 120, 150, 180, 200])
+r = []
+for fm in fmods:
+ am = (1 + np.sin(2 * np.pi * fm * tm)) * np.sin(2 * np.pi * 1000 * tm)
+ am *= p0 * 10 ** (60 / 20) / np.sqrt(np.mean(am**2))
+ r.append(psychoacoustics.roughness_ecma(am, fs).roughness)
+
+fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(10, 8.5))
+ax0.plot(tin.time, tin.tonality_vs_time,
+ label=f"Tone in noise (T = {tin.tonality:.2f} tu_HMS)") # 1.19
+ax0.plot(pn.time, pn.tonality_vs_time,
+ label=f"Pure noise (T = {pn.tonality:.2f} tu_HMS)") # 0.02
+ax0.set(xlabel="Time [s]", ylabel="Tonality T [tu_HMS]")
+ax0.legend()
+ax1.plot(fmods, r, "o-", label="1 kHz carrier, 100 % AM") # peak 1.0 asper
+ax1.set(xlabel="Modulation frequency f_mod [Hz]", ylabel="Roughness R [asper]")
+ax1.legend()
plt.show()
```
diff --git a/site/src/content/docs/perception/psychoacoustics/tone-audibility.mdx b/site/src/content/docs/perception/psychoacoustics/tone-audibility.mdx
index 2e96bb5a8..9e37ac289 100644
--- a/site/src/content/docs/perception/psychoacoustics/tone-audibility.mdx
+++ b/site/src/content/docs/perception/psychoacoustics/tone-audibility.mdx
@@ -133,8 +133,10 @@ tone through that chain, down to the $K_t$ the mean audibility earns.
The **decisive** audibility of one narrow-band spectrum is the largest tone
audibility in it (clause 5.3.8). Over $J$ staggered spectra the **mean
audibility** is their energy mean (Formula 20); a spectrum in which no tone is
-found contributes $\Delta L_j = -10\ \text{dB}$ (Formula 21). `assess_tones` applies the whole
-chain to a spectrum's tones and reports the decisive tone.
+found contributes $\Delta L_j = -10\ \text{dB}$ (Formula 21). `assess_tones` is
+the *per-tone* entry point: it applies Formulae (2)-(5) and (12)-(14) to each
+tone it is given and reports the largest, which is the decisive audibility only
+when no two audible tones share a critical band.
**How the decisive band is selected.** The method does not scan a fixed set of
bands: each detected *tone* defines its own critical band (§1), the audibility
@@ -158,12 +160,26 @@ LS = [48.91, 49.22, 50.50, 52.85, 58.29, 59.53, 59.71, 61.98, 54.16]
res = psychoacoustics.assess_tones(fT, LT, LS, 2.7)
print(round(res.decisive_audibility, 2), res.decisive_frequency) # 5.01 137.3
-# Mean audibility of the five measured spectra (Table E.3 decisive values):
+# The five spectra of the Annex E campaign, rated with Step 3 applied
+# (Table E.3 decisive values), energy-averaged by Formula 20:
print(round(psychoacoustics.mean_audibility([9.18, 6.04, 7.46, 2.67, 7.17]), 2)) # 6.98 dB
res.plot(view="levels") # tone levels above their critical-band masking noise
```
+The two numbers in that block are not the same spectrum rated twice by the same
+rule. The tones at 118.4, 137.3 and 158.8 Hz all fall in one critical band, so
+clause 5.3.8 Step 3 merges them into an `FG` group at their combined level
+$L_T = 72.15$ dB, and the standard's decisive value for spectrum 1 is the
+9.18 dB that opens the `mean_audibility` list — not the 5.01 dB the per-tone
+call prints, which is the largest of the nine individual audibilities
+`[0.75, 0.89, 1.02, 1.79, 1.93, 3.47, 4.39, 4.57, 5.01]`. Those 4.2 dB survive
+the averaging: the per-tone value in place of 9.18 pulls the campaign mean from
+6.98 dB to 5.98 dB, which is $K_t = 3$ dB instead of 4 dB in ISO 1996-2
+Table J.1. So use `analyze_spectrum` (§5), which runs the grouping,
+whenever a decisive audibility is going to be reported, and `assess_tones` only
+when the grouping has already been resolved.
+
The same assessment reads two ways. The audibility bars at the top of this
page answer "how far above the masking threshold is each tone"; the levels
view answers "what did the analyser see", which is the view an assessment
diff --git a/site/src/content/docs/perception/speech/speech-intelligibility.mdx b/site/src/content/docs/perception/speech/speech-intelligibility.mdx
index 11f5bc4ed..689b6239c 100644
--- a/site/src/content/docs/perception/speech/speech-intelligibility.mdx
+++ b/site/src/content/docs/perception/speech/speech-intelligibility.mdx
@@ -351,12 +351,15 @@ defines **four** band procedures. They differ only in the band table and in how
the upward spread of masking is expressed, and `method=` selects one. The
default is the one-third-octave procedure used above.
-| `method=` | Bands | Range | Constants | Spread of masking |
-| :--- | ---: | :--- | :--- | :--- |
-| `"critical-band"` | 21 | 100 Hz to 9500 Hz | Table 1 | between tabulated band limits |
-| `"equally-contributing"` | 17 | 300 Hz to 6400 Hz | Table 2 | between tabulated band limits |
-| `"one-third-octave"` | 18 | 160 Hz to 8000 Hz | Table 3 | between band centre frequencies |
-| `"octave"` | 6 | 177 Hz to 11314 Hz | Table 4 | none |
+| `method=` | Bands | Band centres | Band limits | Constants | Spread of masking |
+| :--- | ---: | :--- | :--- | :--- | :--- |
+| `"critical-band"` | 21 | 150 Hz to 8500 Hz | 100 Hz to 9500 Hz | Table 1 | between tabulated band limits |
+| `"equally-contributing"` | 17 | 350 Hz to 5800 Hz | 300 Hz to 6400 Hz | Table 2 | between tabulated band limits |
+| `"one-third-octave"` | 18 | 160 Hz to 8000 Hz | 143 Hz to 8980 Hz (computed) | Table 3 | between band centre frequencies |
+| `"octave"` | 6 | 250 Hz to 8000 Hz | 177 Hz to 11314 Hz | Table 4 | none |
+
+The two columns are `sii_procedure(method).frequencies` and `.band_edges`; only
+the one-third-octave limits are computed from the centres rather than tabulated.
Every procedure runs the same chain as section 2: self-speech masking, the
upward spread of masking, the equivalent internal noise and disturbance, the
@@ -617,10 +620,10 @@ and the equivalent internal noise. The index lies in $[0, 1]$.
### Which of the four ANSI S3.5 band procedures should I use?
-ANSI S3.5-1997 defines four: critical band (21 bands, 100 Hz to 9500 Hz),
-equally-contributing critical band (17 bands, 300 Hz to 6400 Hz), one-third
-octave (18 bands, 160 Hz to 8000 Hz) and octave (6 bands, 250 Hz to 8000 Hz
-nominal). Use `method="one-third-octave"` by default: it is the finest
+ANSI S3.5-1997 defines four, quoted here by band centre: critical band
+(21 bands, centres 150 Hz to 8500 Hz), equally-contributing critical band
+(17 bands, centres 350 Hz to 5800 Hz), one-third octave (18 bands, centres
+160 Hz to 8000 Hz) and octave (6 bands, centres 250 Hz to 8000 Hz). Use `method="one-third-octave"` by default: it is the finest
resolution and the only procedure whose table carries the raised, loud and
shout speech spectra. Use `method="critical-band"` to align the index with a
critical-band (Bark) masking or loudness model, `method="equally-contributing"`
diff --git a/site/src/content/docs/reference/api/building/structure-borne-power.md b/site/src/content/docs/reference/api/building/structure-borne-power.md
index 60f756cee..3745e1124 100644
--- a/site/src/content/docs/reference/api/building/structure-borne-power.md
+++ b/site/src/content/docs/reference/api/building/structure-borne-power.md
@@ -23,8 +23,10 @@ $$
L_{Ws} = 10 \log_{10}\frac{2 \pi f \eta\, m S}{f_0 m_0 S_0} + L_v - 60 \qquad \text{dB re 1 pW}
$$
-with the references $f_0 = 1$ Hz, $m_0 = 1$ kg,
-$S_0 = 1$ m²; the fixed `-60 dB` term is
+with the references $f_0 = 1$ Hz, $m_0 = 1$ kg (printed as 1 kg;
+the quantity it normalises is a mass per unit area, so the reference is
+1 kg/m² -- see `docs/ERRATA.md`), $S_0 = 1$ m²;
+the fixed `-60 dB` term is
$10 \log_{10}(v_0^2 / P_0)$ for the EN 15657 velocity reference
$v_0 = 10^{-9}$ m/s and $P_0 = 1$ pW. The spatial mean velocity
level is the energetic average over the `N` plate positions (Formula 12):
diff --git a/site/src/content/docs/reference/bibliography.md b/site/src/content/docs/reference/bibliography.md
index 702e0e429..a96c927f9 100644
--- a/site/src/content/docs/reference/bibliography.md
+++ b/site/src/content/docs/reference/bibliography.md
@@ -1,6 +1,6 @@
---
title: "Bibliography"
-description: "The books and papers behind the guides, grouped by domain: every entry with a verified DOI or official publisher link and a note on what it supports."
+description: "A curated selection of the books and papers behind the guides, grouped by domain: every entry with a verified DOI or official publisher link and a note on what it supports."
---
Every guide on this site closes with two citation sections: a **References**
@@ -8,10 +8,13 @@ section listing the books and papers that support the physics on the page
(APA style, one bullet per source, each with a DOI or an official publisher
link, and half a sentence on what the entry supports), followed by a
**Standards** section naming the normative documents the page implements,
-clause by clause. This page collects the References entries of all guides in
-one place, grouped by domain: a curated reading list, and the single source of
-truth for link checking. Each entry lists the guide pages that cite it; the
-list grows as guides gain their References sections.
+clause by clause. This page collects the works the guides lean on most, grouped
+by domain, and each entry lists the guide pages that cite it. It is a **curated
+selection, not the complete citation list**: at the time of writing, two dozen
+DOI-bearing works cited in the guides' own frontmatter do not appear here, among
+them Welch (1967), Harris (1978), Knapp & Carter (1976), Allen & Berkley (1979)
+and Maa (1998). Each guide's own References section, generated from its
+frontmatter, is authoritative for that page.
## General acoustics
diff --git a/site/src/content/docs/reference/conformance.md b/site/src/content/docs/reference/conformance.md
index ddd11e91b..f19fc09c8 100644
--- a/site/src/content/docs/reference/conformance.md
+++ b/site/src/content/docs/reference/conformance.md
@@ -121,7 +121,7 @@ Only **Butterworth** (the library default) and **Chebyshev-II** are class-compli
| Standard | Quantity | Expected (norm) | Computed | Δ | Status |
|:---|:---|:---|:---|:---|:---:|
| IEC 61672-1:2013 (Leq) | Leq of a 1 Pa 1 kHz sine | 90.97 dB (+/-0.05 dB) | 90.969 dB | -0.001 dB | ✅ |
-| IEC 61252:1995 (LEX,8h) | 8 h exposure to 90 dB(A) noise | 90 dB (+/-0.05 dB) | 90.008 dB | 0.008 dB | ✅ |
+| IEC 61252:1993 (LEX,8h) | 8 h exposure to 90 dB(A) noise | 90 dB (+/-0.05 dB) | 90.008 dB | 0.008 dB | ✅ |
| ISO 1996-1:2016 3.6.4 | Lden, constant 60 dB in day/evening/night | 66.3952 dB (+/-0 dB) | 66.3952 dB | 0 dB | ✅ |
| ISO 1996-2:2007 Annex C.5 Example 1 | Tonal audibility ΔLta (Formula C.3), 4 kHz tone | 13.7 dB (+/-0.05 dB) | 13.66 dB | -0.044 dB | ✅ |
| ISO 1996-2:2007 Annex C.5 Example 1 | Tonal adjustment Kt (Formulae C.4-C.6) | 6 dB (+/-0 dB) | 6 dB | 0 dB | ✅ |
diff --git a/site/src/content/docs/reference/errata.md b/site/src/content/docs/reference/errata.md
index 0d9936d1f..e49e5e883 100644
--- a/site/src/content/docs/reference/errata.md
+++ b/site/src/content/docs/reference/errata.md
@@ -654,6 +654,38 @@ which is the check that enforces the rule; see
retained because the library cites the 2006 edition, whose print carries the
defect; the 2017 edition stands as the confirmation.
+## UNE-EN 15657:2018, Clause 7.1, Formula (14) (reference mass dimensionally inconsistent with the quantity it normalises)
+
+- **Location:** Clause 7.1, the sentence introducing Formula (14) (printed
+ p. 14) and Formula (14) itself (printed p. 15), the structural power level
+ injected into the reception plate.
+- **The print:** the sentence reads "a partir del nivel de velocidad promediado
+ espacialmente de la placa $L_v$, de la **masa por unidad de superficie** $m$,
+ del área de la placa $S$ y del factor de pérdida $\eta$, utilizando
+ $f_0 = 1$ Hz, $m_0 = 1$ kg y $S_0 = 1$ m² como referencias", above
+ $L_{Ws} = \left(10\lg\left(\dfrac{2\pi f m \eta S}{f_0 \cdot m_0 \cdot S_0}\right)\right)\text{dB} + L_v - 60\ \text{dB}$.
+- **The problem:** the same sentence defines $m$ as a mass per unit area, in
+ kg/m², and its reference $m_0$ as 1 kg. With $m$ in kg/m² and $S$ in m², the
+ group $2\pi f\,\eta\,m\,S / (f_0 m_0 S_0)$ is dimensionless only if $m_0$ is
+ 1 kg/m²; as printed it carries a leftover m⁻². The closing constant confirms
+ the intended reading: $10\lg(f_0 m_0 S_0 v_0^2 / P_0) = -60$ dB with
+ $v_0 = 10^{-9}$ m/s and $P_0 = 1$ pW closes in watts only when $f_0 m_0 S_0$
+ has the units of an area density times an area times a frequency. The numeric
+ result is unaffected, because $10\lg(1) = 0$ whichever unit is attached, which
+ is why the slip survives a worked example.
+- **Evidence:** dimensional analysis of Formula (14) against the definition of
+ $m$ in the sentence above it, and against the $-60$ dB constant it closes on;
+ the sentence and the formula were read as images, not from extracted text.
+ Verified on PDF page 14 (printed p. 14) and PDF page 15 (printed p. 15) of
+ UNE-EN 15657:2018. Only the Spanish-language adoption was read, so this entry
+ does not establish whether the English EN 15657:2018 print carries the same
+ reference.
+- **Library behaviour:** no change required. `characteristic_reception_plate_power`
+ takes `mass_per_area` in kg/m² and reproduces the standard's own worked values,
+ so the intended reading is the implemented one; the guide and the docstring
+ keep the printed reference and name this entry beside it.
+- **Status:** unreported.
+
## ISO 12999-1:2020, Table 4 (missing 500 Hz row)
- **Location:** Table 4 (in-situ uncertainties per band).
diff --git a/site/src/content/docs/reference/index.md b/site/src/content/docs/reference/index.md
index 538db44c4..a71046f42 100644
--- a/site/src/content/docs/reference/index.md
+++ b/site/src/content/docs/reference/index.md
@@ -59,7 +59,9 @@ needs the clause it came from.
## [Bibliography](/phonometry/reference/bibliography/)
-Every book and paper cited by the guides, in one list grouped by domain, each
-entry with a verified DOI or official publisher link, half a sentence on what
-it supports, and the guide pages that cite it. It doubles as a reading list
-for the field and as the single source of truth for link checking.
+A curated selection of the books and papers the guides lean on, in one list
+grouped by domain, each entry with a verified DOI or official publisher link,
+half a sentence on what it supports, and the guide pages that cite it. It is a
+reading list for the field rather than the complete citation index: the
+authoritative list for any one page is that page's own References section,
+generated from its frontmatter.
diff --git a/site/src/content/docs/reference/theory/environment-transport.mdx b/site/src/content/docs/reference/theory/environment-transport.mdx
index f4ea565e9..3493b4842 100644
--- a/site/src/content/docs/reference/theory/environment-transport.mdx
+++ b/site/src/content/docs/reference/theory/environment-transport.mdx
@@ -147,6 +147,15 @@ $$
P = 3 \log_{10}(\text{onset rate}) + 2 \log_{10}(\text{level difference}),
$$
+
+
+*Both inputs of $P$ are geometry on this trace, which is why the method needs a
+level history and not a level. The onset rate is the slope of the fitted line
+through the rise, in dB/s, and the qualifying threshold of 10 dB/s is a
+steepness on this axis; the level difference is the height of the same rise.
+Three strikes are detected here and only the steepest-and-tallest one governs
+the adjustment.*
+
designed to peak around 15 for very sudden, loud impulses. The adjustment to the measurement-period level takes the governing (highest-$P$) impulse (clause 8, Formula 2):
$$
@@ -209,6 +218,19 @@ $$
A = A_{div} + A_{atm} + A_{gr} + A_{bar} + A_{misc}.
$$
+
+
+*The four terms at their true relative sizes, band by band, for a 200 m path
+over porous ground with a 4 m barrier. $A_{div}$ is 57 dB in every band because
+it is pure geometry. $A_{atm}$ is nothing at 63 Hz and 18.7 dB at 8 kHz, so it
+is the term that decides how far high frequencies travel and no other. $A_{gr}$
+is where the low bands live and is **negative** at 63 Hz (−4.6 dB: the ground
+reflection adds energy rather than removing it). $A_{bar}$ is at its 20 dB cap
+from 2 kHz up but falls to zero at 250 Hz, because the top-edge form subtracts
+the ground effect the screened path gives away, $A_{bar} = D_z - A_{gr} \geq 0$,
+and 250 Hz is exactly where $A_{gr}$ peaks. Which term is worth refining
+depends entirely on the band and the geometry.*
+
The library implements the four general terms of Clause 7; the informative
$A_{misc}$ (foliage, industrial sites, housing) and reflections are left to the
caller. **Geometrical divergence** is spherical spreading from a point source,
@@ -240,6 +262,8 @@ average level subtracts the meteorological correction $C_{met}$ (Eq. (6),
(21)/(22)). The method's stated accuracy is $\pm 1$ to $\pm 3$ dB for broadband
noise up to 1000 m (Table 5).
+
+
### Occupational noise exposure and uncertainty (ISO 9612)
ISO 9612:2009 is the engineering method (accuracy grade 2) for a worker's daily
diff --git a/site/src/content/docs/reference/theory/materials-surfaces.mdx b/site/src/content/docs/reference/theory/materials-surfaces.mdx
index 37d9572a5..bb4f07180 100644
--- a/site/src/content/docs/reference/theory/materials-surfaces.mdx
+++ b/site/src/content/docs/reference/theory/materials-surfaces.mdx
@@ -250,6 +250,15 @@ r = \frac{H_{12} - H_I}{H_R - H_{12}}\ e^{2 j k_0 x_1}, \qquad
\alpha = 1 - |r|^2, \qquad \frac{Z}{\rho c_0} = \frac{1 + r}{1 - r},
$$
+
+
+
+
+*What the formula returns: $\alpha$ and $|r|$ for a 50 mm porous absorber over
+the working band of a 100 mm tube. The two curves are the same information —
+$\alpha = 1 - |r|^2$ — so the figure is really one measurement drawn twice, and
+the rise with frequency is the layer thickness growing against the wavelength.*
+
with the complex wavenumber's attenuation lower bound
$k_0'' = 1.94 \times 10^{-2} \sqrt{f}/(c_0 d)$ (Eq. A.18). ISO 10534-1
(standing-wave-ratio method) is the closed-form classic:
@@ -278,4 +287,13 @@ $TL = 0\ \text{dB}$, hard-backed $|R| = 1$), synthetic round-trips that
recover a known $r$, and
two-load recovery of an asymmetric reciprocal specimen.
+
+
+
+
+*The same four-pole entries answering two different questions: how much sound
+the free-standing layer lets through (the transmission loss above) and how much
+the same layer absorbs once it is backed rigidly. A material can be a good
+absorber and a poor barrier at once, which this pair makes plain.*
+
See the [Impedance Tube guide](/phonometry/materials/absorbers/impedance-tube/) for usage.
diff --git a/site/src/content/docs/reference/theory/perception.mdx b/site/src/content/docs/reference/theory/perception.mdx
index fef4ebea6..a0365aace 100644
--- a/site/src/content/docs/reference/theory/perception.mdx
+++ b/site/src/content/docs/reference/theory/perception.mdx
@@ -137,6 +137,15 @@ $$
**PR** (clause 12) compares the level of the critical band centred on the tone, $L_M$, with the mean power of the two **contiguous** critical bands $L_L$, $L_U$ (edges from the fitted Formulae 21–22 with Tables 2–3): $\mathrm{PR} = 10\log_{10} P_M - 10\log_{10}\left[(P_L + P_U)/2\right]$ (Formula 23). For $f_t \le 171.4$ Hz the lower band is truncated at 20 Hz and its power rescaled to a **100 Hz bandwidth** (Formula 24). The criterion (Formulae 25–26) is 9.0 dB at $f_t \ge 1$ kHz, rising as $9.0 + 10.0\log_{10}(1000/f_t)$ below. Tones are assessed within the 89.1 Hz – 11.2 kHz range of interest (clauses 11.5 / 12.6).
+
+
+*The TNR criterion drawn rather than evaluated, over the 89.1 Hz – 11.2 kHz
+range of interest, with one assessed tone on it. Because the criterion is
+$8.0 + 8.33\log_{10}(1000/f_t)$ below 1 kHz and flat above, the same
+tone-to-noise ratio is judged against a different threshold at every frequency:
+the example tone clears its 13.0 dB threshold at 250 Hz by 2.1 dB, while a
+10 dB tone would be prominent anywhere above 1 kHz and not prominent here.*
+
See the [Prominent Discrete Tones guide](/phonometry/perception/psychoacoustics/tone-prominence/) for usage.
## Zwicker loudness (ISO 532-1)
@@ -240,6 +249,15 @@ $$
(Formulae 65–111). The single value $R$ is the 90th percentile of $R(l_{50})$ over time (Clause 7.1.10); the constant $c_R$ (Formula 104) calibrates the reference sound (a 1 kHz carrier 100 % amplitude-modulated at 70 Hz at 60 dB SPL) to 1 asper.
+
+
+*The modulation-rate weighting the formulae above apply, and the reason the
+range "roughly 20–300 Hz, strongest near 70 Hz" is a band-pass and not a
+threshold: the same 1 kHz carrier modulated slowly is heard as fluctuation
+strength, peaking near 4–6 Hz, and modulated fast is heard as roughness,
+peaking near 70 Hz. Between the two peaks the sensation changes name, not
+degree.*
+
### Sharpness (DIN 45692)
Sharpness condenses the high-frequency emphasis of a sound into one number: the $g(z)$-weighted first moment of the ISO 532-1 stationary specific-loudness pattern (DIN 45692:2009, Equation 1):
@@ -251,6 +269,14 @@ $$
evaluated on the same 240-bin, 0.1-Bark grid. The constant $k$ is not hard-coded but derived from the calibration requirement (clause 6): a critical-band-wide narrowband noise 920–1080 Hz at 60 dB SPL scores exactly 1 acum, and the derived $k = 0.108$ lands inside the normative window $0.105 \le k < 0.115$ (clause 5.2). The informative Annex B weightings are provided under the same 1-acum anchor: von Bismarck (knee at 15 Bark, $0.2\ e^{0.308(z-15)} + 0.8$) and Aures (loudness-dependent, $g(z) = 0.078\ (e^{0.171 z}/z)\ N/\ln(0.05 N + 1)$). The Table A.2 narrow-band targets are reproduced within the clause 6 tolerance (5 % or 0.05 acum): 0.38 acum at 250 Hz, 1.00 at 1 kHz, 1.78 at 2.5 kHz, 2.82 at 4 kHz.
+
+
+*The three $g(z)$ weightings of the formula above on one axis: DIN with its
+15.8 Bark knee, von Bismarck with its 15 Bark knee, and the loudness-dependent
+Aures curve, which is why the choice of weighting changes a sharpness value
+only for sounds with energy above the knee (15 to 15.8 Bark, about 2.5 to
+3 kHz) and leaves everything below it untouched.*
+
See the [Sound Quality Metrics guide](/phonometry/perception/psychoacoustics/sound-quality/) for usage.
## Modulation transfer and STI (IEC 60268-16)
@@ -279,7 +305,26 @@ $$
\mathrm{STI} = \sum_{k=1}^{7} \alpha_k\ \mathrm{MTI}_k - \sum_{k=1}^{6} \beta_k \sqrt{\mathrm{MTI}_k\ \mathrm{MTI}_{k+1}}
$$
-truncated to 1.0. STIPA (Annex B) samples the same physics with just two modulation frequencies per band (Table B.1) on a test signal with source modulation index 0.55; the received depths are measured by sine/cosine correlation of the ~100 Hz low-passed intensity envelopes $I_k(t)$ over an integer number of modulation periods:
+truncated to 1.0.
+
+
+
+*The seven $\mathrm{MTI}_k$ the weighted sum above consumes, for a hall with
+$T = 0.9$ s and a 15 dB speech-to-noise ratio. Each bar is already the mean of
+14 transmission indices, so this is two stages of averaging below the raw
+$m(F)$; the bars sit within 0.06 of one another, which is the case in which
+the $\beta_k$ redundancy terms subtract almost nothing and the STI is close to
+the plain $\alpha$-weighted mean.*
+
+
+
+*The end of the chain rather than its middle: what the Schroeder closed form
+does to the STI as reverberation grows, against the Annex F rating bands. The
+curve falls steeply through the range where a room is still usable and
+flattens once the modulation has already been destroyed, which is why halving
+a long reverberation time buys less intelligibility than halving a short one.*
+
+STIPA (Annex B) samples the same physics with just two modulation frequencies per band (Table B.1) on a test signal with source modulation index 0.55; the received depths are measured by sine/cosine correlation of the ~100 Hz low-passed intensity envelopes $I_k(t)$ over an integer number of modulation periods:
$$
m_{dr} = \frac{2 \sqrt{\left( \sum_t I_k(t) \sin 2 \pi f_m t \right)^2 + \left( \sum_t I_k(t) \cos 2 \pi f_m t \right)^2}}{\sum_t I_k(t)}, \qquad m = \frac{m_{dr}}{0.55}
@@ -333,4 +378,14 @@ $$
The Annex D worked examples (Tables D.1–D.4; e.g. 100 dB / 40 yr at 3 kHz: 29/38/60 dB at the 0.10/0.50/0.90 fractiles) are reproduced exactly at the standard's integer rounding, and the Formula 2 hand value at 4 kHz / 20 yr / 90 dB is $N_{50} = 12.94$ dB.
+
+
+*The model as an audiogram: 40 years at an 8 h-normalised 95 dB(A). The notch
+at 4 kHz is what makes noise-induced loss recognisable in a clinic, and it is
+here only because $L_0$ is lowest (75 dB) in that band. Mind the fractile
+direction the paragraph above states: the edge of the shaded band showing the
+**deeper** shift is the library's `fractile=0.90`, the most susceptible tenth
+— which ISO 1999 and its Annex D column headings label $Q = 10\ \%$. At 4 kHz
+this case runs 19.5 / 26.0 / 36.0 dB at `fractile` 0.10 / 0.50 / 0.90.*
+
See the [Noise-Induced Hearing Loss guide](/phonometry/perception/hearing/noise-induced-hearing-loss/) for usage.
diff --git a/site/src/content/docs/reference/theory/rooms-buildings.mdx b/site/src/content/docs/reference/theory/rooms-buildings.mdx
index 478f0f9fe..beddce633 100644
--- a/site/src/content/docs/reference/theory/rooms-buildings.mdx
+++ b/site/src/content/docs/reference/theory/rooms-buildings.mdx
@@ -190,6 +190,15 @@ $$
with $t_e = 50$ ms (C50, speech) or 80 ms (C80, music), and the **centre time** $T_s = \int_0^{\infty} t\ p^2\ dt / \int_0^{\infty} p^2\ dt$. For a pure exponential decay these have closed forms $C_{te} = 10 \log_{10}(e^{a t_e} - 1)$ and $T_s = 1/a$; at $T = 1$ s ($a = 13.8155$) they evaluate to C80 = 3.05 dB, C50 = −0.02 dB, D50 = 0.499 and Ts = 72.4 ms, the values the implementation reproduces. Table A.1 JNDs (EDT 5 %, C80 1 dB, D50 0.05, Ts 10 ms) bound how finely each is worth reporting.
+
+
+*The closed forms above hold for a single exponential decay; a real room gives
+one set of values per band. The upper panel is the decay itself (EDT, T20 and
+T30 falling with frequency as air and surfaces absorb more), the lower panel
+the early/late split of the same impulse response, and C50 and C80 rise with
+frequency for the same reason the decay time falls — the later the energy, the
+more of it the room has already removed.*
+
### Open-plan spatial decay (ISO 3382-3, Clause 6)
The spatial decay rate of A-weighted speech is the ordinary least-squares slope of $L_{p,A,S}$ against $\log_{10}(r/r_0)$ ($r_0 = 1$ m) over the 2–16 m positions, rescaled to a per-doubling figure, and the nominal level is read off the same line at 4 m:
@@ -200,6 +209,16 @@ $$
The distraction distance rD and privacy distance rP are the distances where a **linear** (not logarithmic) regression of STI against distance crosses 0.50 and 0.20; a non-negative fitted slope (STI not falling with distance) makes them undefined, realising the standard's "can prove impossible to determine" note.
+
+
+*Two regressions on two different axes, which is what makes this clause hard to
+hold in the head. The level line is fitted against $\log_{10}(r/r_0)$ and read
+twice — as the slope $D_{2,S}$ per doubling, and at $r = 4$ m for
+$L_{p,A,S,4\text{m}}$. The STI line is fitted against $r$ itself, **linearly**,
+and read where it crosses 0.50 and 0.20 for the distraction and privacy
+distances. If that second fit comes out flat or rising, the two distances do
+not exist rather than being large.*
+
### Field insulation and weighted rating (ISO 16283-1, ISO 717-1)
Per one-third-octave band the level difference $D = L_1 - L_2$ (energy-averaged over microphone positions, $L = 10 \log_{10}[(1/n) \sum_i 10^{L_i/10}]$) is normalised two ways: the standardized level difference $D_{nT} = D + 10 \log_{10}(T/T_0)$ with $T_0 = 0.5$ s (so $D_{nT} = D$ when $T = T_0$), and the apparent sound reduction index $R' = D + 10 \log_{10}(S/A)$ with the Sabine absorption area $A = 0.16\ V / T$, hence $R' = D + 10 \log_{10}[S T / (0.16\ V)]$.
@@ -228,6 +247,16 @@ with the energetic sum $L_{n,\text{sum}} = 10 \log_{10} \sum_i 10^{L_i/10}$ over
are reproduced exactly (thirds $L_{n,w} = 79$, $C_I = -11$; octaves $54$, $0$),
via the same monotone shift search as ISO 717-1 run on the negated curves.
+
+
+*The mirror image of the airborne figure above, drawn so the flip is visible
+rather than asserted. There the unfavourable deviations were counted where the
+measurement fell **below** the reference; here they are counted where it rises
+**above** it, because a louder receiving room is a worse floor. Everything else
+is the same procedure: the reference curve shifted in 1 dB steps until the
+unfavourable sum is as large as it can be without passing 32.0 dB, and the
+rating read off the shifted reference at 500 Hz.*
+
Sound absorption (ISO 354) measures the equivalent absorption area from
Sabine's relation applied to a reverberation room empty and with the specimen:
$A = 55.3\ V/(c\ T) - 4 V m$ (the $4 V m$ term is the air absorption, $m$ the
@@ -240,14 +269,18 @@ $\alpha_s$ is left unclamped and may exceed 1.0 (Clause 3.7 NOTE 2).
### Laboratory vs field normalization (ISO 10140, ISO 16283)
-The field indices carry a prime because they include flanking transmission
-around the partition; the laboratory indices do not, because a qualified
-facility suppresses it. The algebra is otherwise identical, differing only in
-which quantity is normalised. The airborne pair is the direct laboratory sound
-reduction index $R = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 10140-2) versus the
-apparent field index $R' = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 16283-1), the
-same closed form evaluated with the facility's known $A$ or the room's measured
-$A = 0.16\ V/T$. The impact pair is the normalized laboratory level
+The field indices carry a prime because the receiving-room level they start from
+includes flanking transmission around the partition; the laboratory indices do
+not, because a qualified facility suppresses it. The formulas are therefore the
+*same*, and the prime is a statement about the specimen rather than about the
+arithmetic: the direct laboratory sound reduction index
+$R = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 10140-2) and the apparent field index
+$R' = L_1 - L_2 + 10 \log_{10}(S/A)$ (ISO 16283-1) are one closed form,
+evaluated with the facility's known $A$ in the laboratory and with the receiving
+room's measured $A = 0.16\ V/T$ in the field. What differs in *what is
+normalised* is not laboratory against field but airborne against impact: the
+airborne indices scale by the area-to-absorption ratio $S/A$, the impact levels
+by $A/A_0$. The impact pair is the normalized laboratory level
$L_n = L_i + 10 \log_{10}(A/A_0)$ (ISO 10140-3) versus the field $L'_n$
(ISO 16283-2), both referenced to $A_0 = 10$ m². Before either is formed the
receiving-room level is corrected for background noise by the energy
@@ -330,6 +363,15 @@ hard objects ($\psi \approx 0.072$) raises $A$ to 5.03 m² and drops $T$ to
0.9 s. The informative Annex D method for irregular spaces and unevenly
distributed absorption is out of scope.
+
+
+*What Formula 1 does band by band: the equivalent absorption area on the left
+and the reverberation time it implies through Formula 5 on the right, for the
+same room bare and treated. The Annex E case quoted above is the same
+arithmetic on a smaller room — $A$ from 2.26 to 5.03 m² and $T$ from 2.1 to
+0.9 s at 1 kHz — and the figure shows why the two move in opposite directions
+and not proportionally.*
+
See the [Enclosed-Space Absorption guide](/phonometry/buildings/rooms/enclosed-space-absorption/) for usage.
### Measurement uncertainty (ISO 12999-1)
@@ -383,5 +425,18 @@ transmission path and the double-wall radiation draw on the plate radiation
efficiency and point mobilities of the
[vibration theory](/phonometry/reference/theory/vibration/).
+
+
+*The four behaviours of the paragraph above, one per panel. Top left, the mass
+law rising 6 dB per octave with Sharp's coincidence dip cut into it at $f_c$.
+Top right, the double wall: no better than the combined mass below $f_0$, then
+the cavity term climbing until it saturates. Bottom left, the radiation
+efficiency that decides how much of the plate's vibration becomes sound. Bottom
+right, the ceiling a leak imposes: a 1 % open area holds the composite at
+$10\log_{10}(S/S_a) = 20$ dB however good the wall is, which is the panel worth
+showing a client.*
+
+
+
See the [Predicting Panel Sound Insulation](/phonometry/buildings/design/panel-sound-insulation/)
guide for usage.
diff --git a/site/src/content/docs/reference/theory/signal-analysis.mdx b/site/src/content/docs/reference/theory/signal-analysis.mdx
index ead2c6920..a67f62a93 100644
--- a/site/src/content/docs/reference/theory/signal-analysis.mdx
+++ b/site/src/content/docs/reference/theory/signal-analysis.mdx
@@ -104,13 +104,13 @@ $$
Welch spectrum estimator. Therefore, its result does not have a frequency
resolution in the `fs / nfft` sense.
-For `fraction=3`, the output contains one scalar level per third-octave band.
+For `fraction=3`, the output contains one scalar level per one-third-octave band.
The relevant frequency granularity is the standardized band definition: center
frequency, lower edge, and upper edge. Because fractional-octave bands are
logarithmically spaced, their absolute bandwidth in Hz grows with frequency
while their relative bandwidth remains approximately constant.
-For example, with `fraction=3` and `limits=[12, 20000]`, the exact third-octave
+For example, with `fraction=3` and `limits=[12, 20000]`, the exact one-third-octave
band around 1 kHz is approximately:
| Nominal band | Lower edge | Center | Upper edge | Bandwidth |
@@ -140,7 +140,7 @@ fs = 100_000
pressure_signal_pa = 0.02 * np.random.default_rng(0).standard_normal(fs)
x = pressure_signal_pa
-# Standardized third-octave levels from phonometry.
+# Standardized one-third-octave levels from phonometry.
levels, centers = filters.octave_filter(
x,
fs=fs,
@@ -162,16 +162,28 @@ freq_bins, psd = signal.welch(
scaling="density",
)
-# Example: list the Welch bins inside the third-octave band closest to 1 kHz.
+# Example: list the Welch bins inside the one-third-octave band closest to 1 kHz.
band_index = int(np.argmin(np.abs(np.asarray(fc) - 1000.0)))
in_band = (freq_bins >= fl[band_index]) & (freq_bins <= fu[band_index])
-print("Selected third-octave band:", labels[band_index])
+print("Selected one-third-octave band:", labels[band_index])
print("Welch bin spacing:", freq_bins[1] - freq_bins[0], "Hz")
for f, pxx in zip(freq_bins[in_band], psd[in_band]):
print(f, pxx)
```
+
+
+*The two objects on one axis, for a six-tone signal at 20, 100, 500, 2000,
+4000 and 15 000 Hz. The grey trace is a Welch PSD ($f_s$ = 48 kHz,
+`nperseg = 8192`, so a fixed 5.86 Hz bin everywhere); the markers are the
+standardized one-third-octave levels of the same signal. The bin width never
+changes and the band width does: 4.60 Hz at the 20 Hz band, narrower than one
+bin, against 230.77 Hz at 1 kHz and 3657 Hz at 16 kHz. That is why the top
+bands each swallow hundreds of bins while the bottom ones sit inside a single
+one, and why the two answers cannot be converted into each other. (The PSD
+trace is offset vertically for legibility, so read its shape, not its level.)*
+
This keeps the two concepts separate: phonometry gives standardized
fractional-octave levels, while Welch gives narrowband FFT bins. With
`fs=100000` and `nperseg=2**15`, the Welch bin spacing is about 3.05 Hz.
@@ -290,7 +302,25 @@ $$
\alpha = 1 - e^{-1 / (f_s \cdot \tau)}
$$
-Where $\tau$ is the time constant (e.g., 125 ms for Fast).
+This is the digital image of the analogue RC detector of the classical sound
+level meter: the squared pressure charges a capacitor through a resistor, so the
+displayed mean square is a one-pole low pass on $p^2$ with time constant $\tau$,
+and $\alpha = 1 - e^{-1/(f_s \tau)}$ is its impulse-invariant discretisation —
+exact at any $f_s$, unlike the $1/(f_s \tau)$ approximation often seen. The two
+standard constants are $\tau = 125$ ms (**Fast**) and $\tau = 1$ s (**Slow**).
+A step input reaches within 1 dB of its final value after about $1.6\tau$ and is
+0.03 dB short at $5\tau$, which is why levels read from the first few time
+constants of a record are biased low.
+
+**Impulse is not this filter.** It cannot be: a single $\alpha$ cannot hold a
+peak, and the figure below shows Impulse holding one. IEC 61672-1 defines the I
+weighting as a fast 35 ms detector followed by a 1.5 s decay, implemented here as
+an *asymmetric* detector — it charges with $\tau = 35$ ms whenever the input
+exceeds the current state and discharges with $\tau = 1.5$ s otherwise — so a
+transient is captured quickly and then held for over a second. That makes I
+neither an r.m.s. nor an energy average, which is why it is reserved for the
+specific regulations that name it and must never be energy-summed across
+intervals.
The default initial condition is $y[-1] = 0$. Use `initial_state='first'` to
start from the first input energy, or pass a scalar/array with the previous
@@ -316,7 +346,16 @@ $$
k = \left| \frac{\prod_i (j\omega_{10} - p_i)}{\prod_i (j\omega_{10} - z_i)} \right|, \qquad \omega_{10} = 2\pi \cdot 10 \ \text{rad/s}
$$
-The four zeros against eight poles shape the characteristic response: a rise of approximately **+12 dB/octave between 1 Hz and 20 Hz**, with roll-offs of approximately **24 dB/octave** below 1 Hz and above 20 Hz. Infrasound needs its own curve because near the hearing threshold the perceived loudness of very-low-frequency tones grows much more steeply with sound pressure level than at mid frequencies (a small dB increase above threshold produces a large loudness jump), so the A curve (anchored at 1 kHz) grossly misrepresents infrasonic annoyance.
+The four zeros against eight poles shape the characteristic response: a rise of approximately **+12 dB/octave between 1 Hz and 20 Hz**, with roll-offs of approximately **24 dB/octave** below 1 Hz and above 20 Hz.
+
+
+
+*The shape those four zeros and four pole pairs make, against the ISO 7196
+Table 2 nominal values: 0 dB at the 10 Hz anchor, the +12 dB/octave climb
+through the infrasound decade below it, and the two 24 dB/octave roll-offs
+that fence the curve off below 1 Hz and above 20 Hz.*
+
+Infrasound needs its own curve because near the hearing threshold the perceived loudness of very-low-frequency tones grows much more steeply with sound pressure level than at mid frequencies (a small dB increase above threshold produces a large loudness jump), so the A curve (anchored at 1 kHz) grossly misrepresents infrasonic annoyance.
Since G acts on 0.25 Hz – 315 Hz, far below the Nyquist frequency at audio rates, the frequency warping of the plain bilinear transform (applied without prewarping) is negligible there: about 0.014 % at 315 Hz for $f_s = 48$ kHz, under 0.01 dB on the response. The internal oversampling used for the A/C designs (whose action extends to 16 kHz) is therefore not applied.
@@ -330,6 +369,14 @@ $$
\mathrm{SEL} = L_{eq,T} + 10 \log_{10}\left(\frac{T}{T_0}\right), \qquad T_0 = 1\ \text{s}
$$
+
+
+*What the formula does to an event: the pass-by is replaced by a one-second
+block of the same total energy, which is why SEL exceeds the event's $L_{eq}$
+whenever the event lasts longer than a second, and why two events of the same
+SEL are interchangeable in a dose even when one is loud and short and the
+other quiet and long.*
+
**Sound exposure** $E$ (IEC 61252, 3.1) is the time integral of the squared A-weighted sound pressure, expressed in pascal-squared hours:
$$
@@ -356,7 +403,7 @@ $$
\rho_0 \frac{\partial u}{\partial t} = -\frac{\partial p}{\partial r}
$$
-A p-p probe approximates the pressure gradient by the **finite difference** of two microphones a spacer distance $\Delta r$ apart (IEC 61043:1994, definition 3.2):
+A p-p probe approximates the pressure gradient by the **finite difference** of two microphones a spacer distance $\Delta r$ apart (IEC 61043:1993, definition 3.2):
$$
p = \frac{p_1 + p_2}{2}, \qquad u = -\frac{1}{\rho_0 \Delta r} \int (p_2 - p_1)\ dt, \qquad I = \overline{p\ u}
@@ -380,7 +427,7 @@ The **pressure-intensity index** $\delta_{pI} = L_p - L_I$ measures how reactive
See the [Sound Intensity guide](/phonometry/devices/emission/intensity/) for usage.
-
+
*The p-p estimator in the two limiting fields: the gap between $L_p$ and $L_I$ is the pressure-intensity index that flags reactive fields.*
@@ -420,4 +467,15 @@ inputs; the output is nearly trapezoidal, not Gaussian, so the interval is
narrower than $\pm 1.96\,u$), and the GUM Annex H.1 end-gauge example gives
$k = t_{0.99}(\nu_{\mathrm{eff}} = 16) = 2.92$ and $U_{99} = 93$ nm.
+
+
+*The two routes on one problem — an A-weighted level, not the Supplement 1
+four-term example quoted above. Left is the law of propagation as a budget:
+one bar per input, so the term worth reducing is visible. Right is the
+Supplement 1 route: the Monte Carlo output distribution with the GUM Gaussian
+drawn over it and the 95 % coverage interval shaded. Here the two agree, which
+is what clause 8 calls validation; where the model is non-linear or the output
+visibly non-Gaussian the histogram departs from the curve and the interval is
+read off the fractiles instead.*
+
See the [GUM Uncertainty guide](/phonometry/signals/metrology/gum-uncertainty/) for usage.
diff --git a/site/src/content/docs/reference/theory/vibration.mdx b/site/src/content/docs/reference/theory/vibration.mdx
index 9bf6d7932..71b4f95f1 100644
--- a/site/src/content/docs/reference/theory/vibration.mdx
+++ b/site/src/content/docs/reference/theory/vibration.mdx
@@ -122,6 +122,15 @@ over 20 years) is reproduced: $D_{zd} = 55.97$ m/s², $R = 1.22$,
$\Pi = 0.37$. The Annex A finite-element spinal model (distributed by ISO as
separate software) is out of scope.
+
+
+*The two objects of the model. Left, the clause 5.2 seat-to-spine
+transmissibility: unity at DC, peaking at $|H| \approx 1.54$ near 5 Hz and
+rolling off above it, which is why $W_k$ had to be replaced for shocks. Right,
+the Table C.1 Weibull law $\Pi(R)$ with the Annex C worked example marked at
+$R = 1.22$, $\Pi = 0.37$ — the risk rises steeply over a narrow band of $R$, so
+a dose that doubles does not double the probability.*
+
See the [Human Vibration guide](/phonometry/vibration/human/human-vibration/) and the
[Multiple-Shock Vibration guide](/phonometry/vibration/human/multiple-shock-vibration/) for usage.
@@ -152,4 +161,19 @@ for usage.
-*Receptance, mobility and accelerance of a one-degree-of-freedom resonator: the same resonance seen through the three kinematic quantities.*
+*Not one of the closed forms above: this is a **finite** one-degree-of-freedom
+resonator, receptance, mobility and accelerance being the same resonance seen
+through the three kinematic quantities. It is here as the contrast — the
+infinite-structure results are frequency-independent or smoothly falling,
+while anything finite resonates.*
+
+
+
+*The same point read as a diagnosis: below resonance the magnitude climbs the
+**stiffness line** $\omega/k$, above it it falls along the **mass line**
+$1/(\omega m)$, and the peak height is set by the damping alone. A real
+structure has many such resonances, and the infinite-structure closed forms
+above are the average the measured mobility oscillates about, not the value it
+takes at a given frequency — which is why they are used with octave or
+third-octave inputs and are least trustworthy in the lowest bands of a small
+or lightly damped element.*
diff --git a/site/src/content/docs/signals/filters/filter-banks.mdx b/site/src/content/docs/signals/filters/filter-banks.mdx
index 785f4ad4c..d34fb1445 100644
--- a/site/src/content/docs/signals/filters/filter-banks.mdx
+++ b/site/src/content/docs/signals/filters/filter-banks.mdx
@@ -51,8 +51,12 @@ import ThemeImage from '../../../../components/ThemeImage.astro';
import ReportPreview from '../../../../components/ReportPreview.astro';
phonometry supports several filter types, each with its own transfer function
-characteristic. All banks place their **−3 dB points on the ANSI S1.11 band
-edges**, so band levels are comparable across architectures.
+characteristic. Butterworth, Chebyshev II and Bessel place their **−3 dB points
+on the ANSI S1.11 band edges**, so their band levels are directly comparable.
+The two equiripple designs (Chebyshev I, Elliptic) do not: they take those edges
+as the *ripple* edge instead, which widens the band and biases every band level
+by a fixed few tenths of a decibel — see section 1, because the bias is
+systematic and does not average out.
## 1. Fractional octave bands: the math
@@ -67,10 +71,43 @@ $$
so every 1/3-octave band spans $G^{1/3} \approx 1.2589 \approx 10^{1/10}$:
ten bands per decade, which is why the nominal frequencies (25, 31.5, 40 …)
-repeat scaled by 10. phonometry designs each band as an SOS cascade whose
-−3 dB points land exactly on $f_1$ and $f_2$ for every architecture; for
-Chebyshev II, Elliptic and Bessel that requires pre-warping the analytic
-band-edge mapping rather than trusting SciPy's default parametrization.
+repeat scaled by 10. phonometry designs each band as an SOS cascade on those
+edges, but where the −3 dB point ends up depends on what the architecture means
+by its design frequency, and only three of the five put it on $f_1$ and $f_2$.
+
+### Where each architecture's −3 dB point actually lands
+
+Butterworth's SciPy design frequency *is* its −3 dB point, so it needs no
+correction. Chebyshev II is designed through its stopband edges, mapped back
+from the band edges analytically, and Bessel is normalized with `norm="mag"`
+rather than SciPy's default phase normalization — both corrections exist so that
+their −3 dB points land on the edges too. Chebyshev I and Elliptic are handed
+the band edges directly, and for those two families SciPy reads them as the
+*equiripple passband* edge: the response there is the ripple depth, not −3 dB.
+Measured on the 1 kHz octave band at 48 kHz with order 6 and the default
+`ripple=0.1`:
+
+| Architecture | Response at $f_1$ and $f_2$ | Noise bandwidth / $(f_2 - f_1)$ | Band-level offset |
+| :--- | :---: | :---: | :---: |
+| `butter` | −3.01 dB | 1.003 | reference |
+| `cheby2` | −3.01 dB | 1.003 | −0.02 dB |
+| `bessel` | −3.01 dB | 0.971 | +0.05 dB |
+| `cheby1` | **−0.10 dB** | 1.066 | **+0.33 dB** |
+| `ellip` | **−0.10 dB** | 1.052 | **+0.25 dB** |
+
+The first three columns are the 1 kHz octave band; the last is the median
+band-level difference from Butterworth over a whole 1/3-octave bank analysing
+20 s of white noise. That last column matters because it is a *bias*, not
+scatter: it does not shrink with averaging time, it is larger than the whole
+class 1 passband corridor (±0.4 dB), and it moves every band at once, so a
+spectrum measured with `cheby1` sits bodily above one measured with `butter`.
+Choose one architecture per campaign, and never mix architectures inside one
+spectrum. Raising `order` shrinks the offset, because a narrower transition band
+pulls the −3 dB point back toward the ripple edge — for `cheby1` the median goes
++0.76 dB at order 4, +0.33 dB at order 6, +0.16 dB at order 8 and +0.04 dB at
+order 12. Lowering `design.ripple` does the opposite of what intuition suggests
+and makes the offset *larger* (+0.62 dB at `ripple=0.02`), because at fixed
+order a flatter passband buys a slower roll-off.
### Poles, zeros and stability
@@ -140,26 +177,50 @@ everyday arguments stay first: `FilterDesign` (`design`), `LevelCalibration`
(`calibration`), `BlockProcessing` (`block_processing`) and `ResponsePlot`
(`response_plot`). The table names each option by its bundle.
-| Parameter | Type | Units | Range / default | Notes |
-| :--- | :--- | :--- | :--- | :--- |
-| `x` | 1D or 2D array | digital units | non-empty | 2D is `[channels, samples]` |
-| `fs` | int | Hz | > 0 | |
-| `fraction` | int | — | default `1`; common `3`; any $b \ge 1$ | Bands per octave = $b$ |
-| `order` | int | — | default `6` | SOS order per band |
-| `limits` | list `[lo, hi]` | Hz | default `[12, 20000]` | Analysis range |
-| `design.filter_type` | str | — | `'butter'` (default), `'cheby1'`, `'cheby2'`, `'ellip'`, `'bessel'` | See the [Filter Architecture Gallery](/phonometry/signals/filters/filter-gallery/) |
-| `design.ripple` / `design.attenuation` | float | dB | `ripple` default `0.1`; `attenuation` default `72.0` | Passband ripple / stopband attenuation (cheby/ellip); `cheby2` needs `attenuation` $\ge 70$ for class 1, since scipy pins its equiripple floor at exactly this value |
-| `design.resample` | bool | — | default `True` | Filter each band on a decimated rate (multirate) |
-| `response_plot.show` | bool | — | default `False` | Plot the bank response (needs matplotlib) |
-| `sigbands` | bool | — | default `False` | Also return the per-band time signals |
-| `mode` | str | — | `'rms'` (default), `'peak'`, `'sum'` | Per-band statistic returned |
-| `nominal` | bool | — | default `False` | Return nominal band labels (e.g. `1000`) instead of exact centre frequencies |
-| `detrend` | bool | — | default `True` | Remove each band's DC offset before the level (improves low-frequency accuracy) |
-| `calibration.factor` | float | — | default `1.0` | Scales the input to pascals (see the Calibration guide) |
-| `calibration.dbfs` | bool | — | default `False` | Reference levels to digital full scale instead of 20 µPa |
-| `response_plot.file` | str or `None` | — | default `None` | Save the bank-response plot to this path |
-| `zero_phase` | bool | — | default `False` | Forward-backward filtering (offline) |
-| `block_processing.stateful` / `.steady_ic` (class) | bool | — | default `False` | Streaming state; see [Block Processing](/phonometry/signals/filters/block-processing/) |
+Three call sites share this table, and they do not accept the same options, so
+the **Where** column names the one each option belongs to: `octave_filter()` is
+the one-shot function, `OctaveFilterBank(...)` is the constructor, and
+`bank.filter()` is the per-call method.
+
+| Parameter | Where | Type | Units | Range / default | Notes |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| `x` | function, `.filter()` | 1D or 2D array | digital units | non-empty | 2D is `[channels, samples]` |
+| `fs` | function, constructor | int | Hz | > 0 | |
+| `fraction` | function, constructor | int | — | default `1`; common `3`; any $b \ge 1$ | Bands per octave = $b$ |
+| `order` | function, constructor | int | — | default `6` | SOS order per band |
+| `limits` | function, constructor | list `[lo, hi]` | Hz | default `[12, 20000]` | Analysis range |
+| `design.filter_type` | function, constructor | str | — | `'butter'` (default), `'cheby1'`, `'cheby2'`, `'ellip'`, `'bessel'` | See the [Filter Architecture Gallery](/phonometry/signals/filters/filter-gallery/) |
+| `design.ripple` / `design.attenuation` | function, constructor | float | dB | `ripple` default `0.1`; `attenuation` default `72.0` | Passband ripple / stopband attenuation (cheby/ellip); `cheby2` needs `attenuation` $\ge 70$ for class 1, since scipy pins its equiripple floor at exactly this value |
+| `design.resample` | function, constructor | bool | — | default `True` | Filter each band on a decimated rate (multirate) |
+| `response_plot.show` | function, constructor | bool | — | default `False` | Plot the bank response (needs matplotlib) |
+| `response_plot.file` | function, constructor | str or `None` | — | default `None` | Save the bank-response plot to this path |
+| `calibration.factor` | function, constructor | float | — | default `1.0` | Scales the input to pascals (see the Calibration guide) |
+| `calibration.dbfs` | function, constructor | bool | — | default `False` | Reference levels to digital full scale instead of 20 µPa |
+| `block_processing.stateful` / `.steady_ic` | constructor only | bool | — | default `False` | Streaming state; see [Block Processing](/phonometry/signals/filters/block-processing/) |
+| `sigbands` | function, `.filter()` | bool | — | default `False` | Also return the per-band time signals |
+| `mode` | function, `.filter()` | str | — | `'rms'` (default) or `'peak'` | Per-band statistic returned |
+| `nominal` | function, `.filter()` | bool | — | default `False` | Return nominal band labels (e.g. `1000`) instead of exact centre frequencies |
+| `detrend` | function, `.filter()` | bool | — | default `True` | Remove each band's DC offset before the level (improves low-frequency accuracy) |
+| `zero_phase` | `.filter()` only | bool | — | default `False` | Forward-backward filtering (offline); see section 5 |
+| `calculate_level` | `.filter()` only | bool | — | default `True` | `False` returns the band signals without computing levels (use with `sigbands=True`) |
+
+The split is not arbitrary: the one-shot `octave_filter()` designs a bank and
+uses it once, so it carries the design-time options only. `zero_phase` and
+`calculate_level` are decided per call and therefore live on
+`OctaveFilterBank.filter()` — `octave_filter(x, fs, zero_phase=True)` raises
+`TypeError` — while streaming state is fixed when the bank is built.
+
+`mode` has exactly two values. `'rms'` reports the energy-mean level of the band
+over the whole record, which is what every standard means by "band level".
+`'peak'` reports $20\log_{10}$ of the largest absolute sample inside the band,
+against the same 20 µPa reference; it is an instantaneous band peak, not a
+peak-hold reading, it is band-limited and unweighted so it is *not* the
+C-weighted peak $L_{C\text{peak}}$ of the
+[Levels](/phonometry/signals/levels/levels/) guide, and on impulsive signals it
+is dominated by the filter's own ringing — it belongs to transient diagnostics,
+not to level reporting. There is no `'sum'` mode: a total across bands is an
+energy sum the caller performs, `10*np.log10(np.sum(10**(spl/10)))`, never an
+arithmetic mean of decibels.
`verify_filter_class(bank)` checks the designed bank against the IEC 61260-1
Table 1 acceptance limits and reports the class (`1`, `2` or `None` if outside both) with per-band
@@ -352,9 +413,11 @@ plt.show()
## 5. Zero-phase filtering
-For offline analysis you can eliminate group delay entirely: `zero_phase=True`
-filters each band forward-backward (`scipy.signal.sosfiltfilt`), keeping band
-signals time-aligned with the input. The effective attenuation doubles and the
+For offline analysis you can eliminate group delay entirely:
+`OctaveFilterBank.filter(…, zero_phase=True)` filters each band
+forward-backward (`scipy.signal.sosfiltfilt`), keeping band signals
+time-aligned with the input. It is a per-call option on the bank, not an
+argument of the one-shot `octave_filter()`. The effective attenuation doubles and the
effective passband narrows, lowering the measured broadband band level by
~0.2 to 0.3 dB per band (a pure in-band tone is unaffected); prefer forward
filtering when the absolute band SPL must match single-pass conventions, and
diff --git a/site/src/content/docs/signals/filters/filter-compliance.mdx b/site/src/content/docs/signals/filters/filter-compliance.mdx
index 70607c23d..a736e1237 100644
--- a/site/src/content/docs/signals/filters/filter-compliance.mdx
+++ b/site/src/content/docs/signals/filters/filter-compliance.mdx
@@ -66,6 +66,23 @@ print(result["bands"][0])
# {'freq': 12.589254117941678, 'class': 1, 'checked_to_omega': 3.8127755266765493, 'margin_class1_db': 0.3999999999999595, 'margin_class2_db': 0.5999999999999595}
```
+**What the margin measures.** It is the minimum, over every normalized frequency
+the band was evaluated at, of the distance to the nearest limit of that class:
+positive when the response stays inside the corridor everywhere, and negative by
+exactly the worst violation when it does not. The reported `class` is the
+strictest class whose margin is non-negative.
+
+Which constraint binds is worth knowing before you try to improve the number. A
+maximally-flat Butterworth is flat at mid-band, where the class 1 corridor is
+±0.4 dB, so its margin *saturates at +0.400 dB* the moment the stopband stops
+being the limiting factor: measured on a 48 kHz one-third-octave bank, order 2
+fails outright (class `None`, worst class 1 margin −27.03 dB) and orders 4, 6, 8
+and 10 all report class 1 with exactly +0.400 dB. Raising the order therefore
+helps only while the margin is negative for a stopband reason; once a design
+passes, the margin is capped by the passband half-corridor and no order will
+move it. A margin of +0.400 dB is not a mediocre result to be improved — it is
+the best a compliant design can report against this mask.
+
The Table 1 acceptance mask itself is public too: `class_limits(fraction,
filter_class, omega)` returns the minimum/maximum relative-attenuation
limits at normalized frequencies $\Omega = f/f_m$, the same limits the
@@ -120,7 +137,9 @@ far-stopband class 1 limit (scipy pins the cheby2 equiripple floor at exactly
keeps the same +0.400 dB passband margin as Butterworth). Chebyshev I,
Elliptic and Bessel do
not meet class limits at order 6: passband ripple (cheby1/ellip) and slow
-roll-off (bessel) violate the mask.
+roll-off (bessel) violate the mask. Class 1 is the strictest verdict this
+edition can return; the stricter class 0 the default bank also clears belongs to
+the withdrawn 1995 mask and is section 2.
## 2. Class 0 (IEC 61260:1995 / ANSI S1.11-2004)
@@ -210,15 +229,21 @@ grades:
terms, which is why instrument-grade chains specify the class of every
stage rather than a single overall figure.
-**Which architecture reaches which class?** The library's **default, Butterworth
-order 6, meets class 0** in the configurations the conformance suite verifies
-(octave and third-octave banks at 48 kHz), so no special setup is needed for
-laboratory-grade banks in that range. The table below reports the best class
-each architecture reaches under that same order-6 / 48 kHz setup; the other
-architectures fall short of class 0 because they trade the IEC mask for a
-different property *by construction*:
-
-| Architecture | Best class (order 6, fs 48 kHz) | Why |
+**Which architecture reaches which class?** Under the 2014 edition, whose only
+classes are 1 and 2, the library's default Butterworth order-6 bank **meets
+class 1** with a +0.400 dB binding margin — that is the ceiling, and section 1
+explains why. Against the stricter 1995 / ANSI S1.11-2004 mask
+(`edition="1995"`) the same default reaches **class 0**; the configuration the
+conformance suite verifies at that class is the *octave-band* bank at 48 kHz,
+so re-run `verify_filter_class(bank, edition="1995")` yourself before writing
+class 0 into a document for any other fraction or sample rate. Writing "class 0
+per IEC 61260-1:2014" is a claim against a class that edition does not define.
+
+The table reports the best class each architecture reaches at order 6, fs
+48 kHz, under the 1995 mask; the architectures other than Butterworth fall short
+because they trade the IEC mask for a different property *by construction*:
+
+| Architecture | Best class (order 6, fs 48 kHz, `edition="1995"`) | Why |
| :--- | :---: | :--- |
| `butter` (default) | **0** | Maximally-flat pass-band, monotone roll-off; fits the mask |
| `cheby2` | 1 | Flat pass-band but the mask relationship binds at class 1 |
@@ -226,12 +251,14 @@ different property *by construction*:
| `ellip` | — | Pass- and stop-band ripple |
| `bessel` | — | Flat group delay bought with a slow roll-off |
-So the sensible default is the common one (Butterworth order 6): it clears
-class 0 in the verified configurations, while the alternative architectures are
-deliberate opt-ins whose purpose (steeper roll-off, linear phase) works against
-the class mask. Away from these settings (very high `fraction` or near-Nyquist
-bands), always re-run `verify_filter_class` to confirm the class you need, and
-raise the order if a band needs more margin.
+Under the 2014 edition the same ranking reads 1 / 1 / — / — / —: `cheby2` joins
+Butterworth at the top because class 0 no longer exists to separate them.
+
+So the sensible default is the common one (Butterworth order 6), while the
+alternative architectures are deliberate opt-ins whose purpose (steeper
+roll-off, linear phase) works against the class mask. Away from these settings
+(very high `fraction` or near-Nyquist bands), always re-run
+`verify_filter_class` to confirm the class you need.
## 4. The compliance fiche (`.report()`)
@@ -349,6 +376,9 @@ the achieved class per band.
Class 0 is the tightest filter performance class, defined by IEC 61260:1995
and its US twin ANSI S1.11-2004 and dropped by IEC 61260-1:2014. Its
passband corridor allows only ±0.15 dB at mid-band, against ±0.3 dB for
-class 1 in the 1995 masks. It stays available through `edition="1995"`, and
-the default order-6 Butterworth bank meets class 0 in the verified 48 kHz
-configurations.
+class 1 in the 1995 masks. It stays available through `edition="1995"`, and the
+default order-6 Butterworth bank meets class 0 in the configuration the
+conformance report verifies, the octave-band bank at 48 kHz. Under
+IEC 61260-1:2014 that same bank is class 1: the 2014 edition defines no class 0,
+so a class 0 claim must cite the 1995 / ANSI S1.11-2004 mask it was measured
+against.
diff --git a/site/src/content/docs/signals/filters/filter-gallery.mdx b/site/src/content/docs/signals/filters/filter-gallery.mdx
index 48b381e78..46b71670a 100644
--- a/site/src/content/docs/signals/filters/filter-gallery.mdx
+++ b/site/src/content/docs/signals/filters/filter-gallery.mdx
@@ -29,10 +29,14 @@ import ThemeImage from '../../../../components/ThemeImage.astro';
Choosing a filter architecture is a trade-off: selectivity, passband ripple
and phase behaviour cannot all be optimal at once, and each of the five
-architectures phonometry offers resolves the trade-off differently. Because
-every one of them places its **−3 dB points on the ANSI S1.11 band edges**,
-the choice changes how a band rejects its neighbours and how it treats
-transients, not where the band sits. This page puts the architectures side
+architectures phonometry offers resolves the trade-off differently. Three of
+them — Butterworth, Chebyshev II and Bessel — place their **−3 dB points on the
+ANSI S1.11 band edges**, so for those three the choice changes how a band
+rejects its neighbours and how it treats transients, not where the band sits.
+The two equiripple designs are the exception, and section 3 gives the size of
+it: `cheby1` and `ellip` treat the band edges as their ripple edge, so their
+bands are effectively wider and every band level reads a few tenths of a decibel
+high. This page puts the architectures side
by side: the comparison at the −3 dB crossover, the full 1/1 and 1/3 octave
response gallery, usage examples per architecture, and the Linkwitz-Riley
crossover for when the goal is splitting a signal rather than measuring
@@ -92,7 +96,7 @@ plt.show()
Full spectral view of the filter banks for Octave (1/1) and 1/3-Octave fractions.
-| Architecture | 1/1 Octave (Fraction=1) | 1/3 Octave (Fraction=3) |
+| Architecture | Octave (`fraction=1`) | One-third octave (`fraction=3`) |
| :--- | :--- | :--- |
| **Butterworth** | | |
| **Chebyshev I** | | |
@@ -299,12 +303,32 @@ filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
-### 6. Linkwitz-Riley (`linkwitz_riley`)
-
-Specifically designed for **audio crossovers**. Linkwitz-Riley filters (typically
-4th order, but any even order is supported) allow splitting a signal into bands
-that, when summed, result in a perfectly flat magnitude response and zero phase
-difference between bands at the crossover.
+## 4. Linkwitz-Riley crossover (`linkwitz_riley`)
+
+Linkwitz-Riley is not a sixth architecture: it does not build an IEC band, and
+it is not a `FilterDesign(filter_type=…)` value. It is called directly, and it
+does the opposite job — it splits one signal into two branches that recombine
+into a flat magnitude response, which is what a loudspeaker **crossover** needs
+and what a measurement band must never do. Each branch is a Butterworth of order
+`order/2` applied twice, so each is exactly **−6 dB at the crossover frequency**
+(not −3 dB as in the bands above): the branches add to unity in *amplitude*,
+not in power.
+
+Which recombination is flat depends on the parity of `order/2`, and the naive
+sum is wrong for half the even orders:
+
+| `order` | `order/2` | Branch phase difference at $f_c$ | Flat recombination |
+| :---: | :---: | :---: | :--- |
+| 2 | 1 (odd) | 180° | `low - high` |
+| 4 | 2 (even) | 0° | `low + high` |
+| 6 | 3 (odd) | 180° | `low - high` |
+| 8 | 4 (even) | 0° | `low + high` |
+
+At orders 2 and 6 the branches are in antiphase at $f_c$ and `low + high`
+collapses into a deep notch there instead of summing flat. Even in the flat
+cases the sum is **all-pass**, not phase-free: its magnitude is flat to better
+than 0.001 dB from 20 Hz to 20 kHz while its phase turns a full 360° through the
+crossover.
```python
import numpy as np
@@ -315,8 +339,10 @@ fs = 48000
recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Split the recording into Low and High bands at 1000 Hz
-low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=4)
-# Recombined, low + high has a flat magnitude response (allpass sum)
+order = 4
+low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=order)
+# Flat recombination: sum for order/2 even, difference for order/2 odd
+recombined = low + high if (order // 2) % 2 == 0 else low - high
```
@@ -353,14 +379,23 @@ plt.show()
+**In a real crossover** the two branches sum acoustically, not electrically, and
+the flatness above only survives if the two acoustic paths are time-aligned. A
+woofer/tweeter acoustic-centre offset of a few centimetres is enough phase
+rotation at 1 kHz to notch the summation, and the remedy is a delay on the
+forward driver, not a different filter order. Verify by measuring the summed
+on-axis response with the swept-sine method of
+[System measurement](/phonometry/signals/spectra/system-measurement/).
+
## What this guide covers
**Covered.** The five architectures every IEC-band bank can be built on
(Butterworth, Chebyshev I/II, Elliptic, Bessel): their magnitude responses
compared at the −3 dB crossover and in the full 1/1 and 1/3 octave gallery,
-the ANSI S1.11 −3 dB band-edge convention they all share, and a usage
-example per architecture, plus the Linkwitz-Riley crossover whose low and
-high bands sum to a flat response.
+the band-edge convention (exact for Butterworth, Chebyshev II and Bessel; the
+ripple edge for the two equiripple families), and a usage example per
+architecture, plus the Linkwitz-Riley crossover, whose two branches recombine
+flat — by sum or by difference, depending on the parity of `order/2`.
**Not covered.** The band mathematics, the pole-zero, stability and
multirate design and the `octave_filter()` / `OctaveFilterBank` parameter
@@ -389,5 +424,9 @@ roll-off at the cost of passband ripple; Chebyshev II keeps the passband
flat and puts the ripple in the stopband instead; Elliptic offers maximum
selectivity, with ripple in both bands; and Bessel preserves transient
waveform shapes thanks to its linear phase response, but has the slowest
-roll-off. Linkwitz-Riley is for audio crossovers: its bands sum to a
-perfectly flat response.
+roll-off. Note that Chebyshev I and Elliptic take the band edges as their
+*ripple* edge rather than their −3 dB point, so their band levels sit a few
+tenths of a decibel above the other three and must not be mixed with them in one
+spectrum. Linkwitz-Riley is not one of the five: it is a crossover, and its two
+branches recombine flat by `low + high` when `order/2` is even and by
+`low - high` when it is odd.
diff --git a/site/src/content/docs/signals/filters/index.md b/site/src/content/docs/signals/filters/index.md
index 6c877af51..1653a9248 100644
--- a/site/src/content/docs/signals/filters/index.md
+++ b/site/src/content/docs/signals/filters/index.md
@@ -6,10 +6,13 @@ description: "Fractional octave band analysis in phonometry: the ANSI S1.11 / IE
Acoustic analysis rarely wants a raw FFT: standards, ratings and human hearing
all work in **fractional octave bands**, frequency intervals whose width grows
proportionally with frequency. phonometry implements them as banks of
-recursive filters whose **-3 dB points sit exactly on the ANSI S1.11 band
-edges**, so band levels are comparable whichever filter architecture computes
-them, and whose designs are verified against the class tolerances of
-**IEC 61260-1:2014**.
+recursive filters whose designs are verified against the class tolerances of
+**IEC 61260-1:2014**. The default Butterworth bank, and the Chebyshev II and
+Bessel alternatives, put their **-3 dB points exactly on the ANSI S1.11 band
+edges**, so their band levels are directly comparable; the two equiripple
+architectures (Chebyshev I, Elliptic) place their ripple edge there instead and
+consequently read a few tenths of a decibel high in every band, which is why a
+campaign should fix one architecture and keep it.
The foundation page is [Filter Banks](/phonometry/signals/filters/filter-banks/). It
covers the band mathematics, how a signal is decomposed into 1/1, 1/3 or
diff --git a/site/src/content/docs/signals/index.md b/site/src/content/docs/signals/index.md
index 0b15be3cf..1bef47d17 100644
--- a/site/src/content/docs/signals/index.md
+++ b/site/src/content/docs/signals/index.md
@@ -22,8 +22,7 @@ confidence intervals), **correlation and time-delay estimation** and the
**Hilbert envelope**, all stated with the Bendat & Piersol error analysis.
And two transversal concerns complete the core. **Calibration** decides what
the digital samples mean physically: results can be referenced to a measured
-calibrator tone or a known sensitivity (dB SPL), or stay in digital full
-scale (dBFS). **Measurement uncertainty** (the GUM and its Monte Carlo
+calibrator tone (dB SPL), or stay in digital full scale (dBFS). **Measurement uncertainty** (the GUM and its Monte Carlo
supplement) qualifies any result computed from uncertain inputs, which is
what makes a number defensible in a report.
@@ -129,8 +128,8 @@ and carrying its statistical quality.
What the numbers mean and how much to trust them.
- [Calibration and dBFS](/phonometry/signals/metrology/calibration/): physical SPL
- calibration from a calibrator tone (IEC 60942) or a known sensitivity, and
- the digital dBFS mode.
+ calibration from a calibrator tone (IEC 60942), the stability check it applies
+ to that recording, and the digital dBFS mode.
- [Measurement uncertainty (GUM and Monte Carlo)](/phonometry/signals/metrology/gum-uncertainty/):
the law of propagation of uncertainty and the Monte Carlo method of
ISO/IEC Guide 98-3, with expanded uncertainty and coverage intervals.
diff --git a/site/src/content/docs/signals/levels/index.md b/site/src/content/docs/signals/levels/index.md
index 7dfe4c5fe..09ab7d2f9 100644
--- a/site/src/content/docs/signals/levels/index.md
+++ b/site/src/content/docs/signals/levels/index.md
@@ -7,9 +7,11 @@ A sound level meter does three things to a calibrated signal, in order: it
**weights it in frequency** to mimic the ear's sensitivity, it **smooths it in
time** with a standardised ballistic, and it **integrates it into a level**.
The pages of this section implement that chain stage by stage for the
-displayed level: the A/C/Z curves and the Fast/Slow/Impulse ballistics
-follow **IEC 61672-1:2013** closely enough that the weightings are
-verified against the standard's own tolerance tables in CI.
+displayed level: the A/C/Z curves and the Fast and Slow ballistics of
+**IEC 61672-1:2013**, verified in CI against the standard's own tolerance
+tables (Table 3 for the weightings, Table 4 for the tone-burst responses), plus
+the legacy Impulse ballistics that IEC 61672-1 inherited from IEC 60651 and then
+dropped from its requirements, kept here for older national procedures.
[Frequency Weighting (A, C, Z)](/phonometry/signals/levels/weighting/) covers the
first stage. The A-curve tracks hearing sensitivity at moderate levels and
@@ -21,10 +23,11 @@ conventional weightings are blind, the historical B and D curves serve legacy
data, and AU rejects ultrasound from an audible-sound reading per IEC 61012.
[Time Weighting](/phonometry/signals/levels/time-weighting/) covers the second stage:
-the exponential Fast (125 ms), Slow (1 s) and Impulse ballistics that decide
-how quickly a displayed level follows the sound. phonometry implements the
-exact time constants, verified against the toneburst responses of the
-standard.
+the exponential Fast (125 ms) and Slow (1 s) ballistics that decide how quickly
+a displayed level follows the sound, and the legacy asymmetric Impulse
+ballistics (35 ms rise, 1.5 s decay) that came from IEC 60651 and is no longer
+required by IEC 61672-1. phonometry implements the exact time constants,
+verified against the tone-burst responses of the standard.
[Integrated and Statistical Levels](/phonometry/signals/levels/levels/) is the payoff:
the equivalent continuous level Leq and its A-weighted LAeq, the percentile
@@ -53,8 +56,9 @@ noise phases, and the limit tables an activity is judged against.
- [Special Weightings (G, B, D, AU)](/phonometry/signals/levels/special-weightings/):
the ISO 7196 infrasound G-weighting, the historical B and D curves and AU
per IEC 61012.
-- [Time Weighting](/phonometry/signals/levels/time-weighting/): Fast, Slow and
- Impulse exponential ballistics.
+- [Time Weighting](/phonometry/signals/levels/time-weighting/): the Fast and Slow
+ exponential ballistics of IEC 61672-1, and the legacy Impulse ballistics it
+ dropped.
- [Integrated and Statistical Levels](/phonometry/signals/levels/levels/): Leq and
LAeq, percentile levels, LCpeak/SEL, noise dose and octave spectrograms.
diff --git a/site/src/content/docs/signals/levels/levels.mdx b/site/src/content/docs/signals/levels/levels.mdx
index b45b42763..462f3d2cf 100644
--- a/site/src/content/docs/signals/levels/levels.mdx
+++ b/site/src/content/docs/signals/levels/levels.mdx
@@ -353,13 +353,22 @@ integral of the squared A-weighted pressure) and the equivalent
**normalized 8 h level**:
$$
-E = \int_0^T p_A^2(t)\ dt \quad [\text{Pa}^2\text{h}], \qquad
-L_{EX,8h} = 10\log_{10}\frac{E}{8\ \text{h} \cdot p_0^2}
+E = \int_0^T p_A^2(t)\ dt \quad [\text{Pa}^2\text{h}],\ t\ \text{in hours}
+\qquad
+L_{EX,8h} = 10\log_{10}\frac{E}{T_0\,p_0^2}, \quad T_0 = 8\ \text{h}
$$
+The unit annotation only holds if $t$ is in hours: integrate in seconds and you
+get Pa²s, which is the same exposure expressed 3600 times larger — 35.6 dB out
+if you then feed it to the $L_{EX,8h}$ formula. In practice you integrate in
+seconds and divide by 3600, which is what `sound_exposure` does internally
+(mean square × duration in hours).
+
The anchor worth memorizing: **3.2 Pa²h ⇔ exactly 90 dB over 8 h** (the CI
-suite enforces it). Half the dose is −3 dB; double duration at the same level
-is +3 dB.
+suite enforces it). It falls straight out of the formula: 90 dB is
+$p_{A,\mathrm{rms}} = 20\,\mu\mathrm{Pa} \times 10^{4.5} = 0.6325$ Pa, and
+$8\ \text{h} \times (0.6325\ \text{Pa})^2 = 3.2\ \text{Pa}^2\text{h}$. Half the
+dose is −3 dB; double duration at the same level is +3 dB.
### Peak / event / dose parameters
diff --git a/site/src/content/docs/signals/levels/time-weighting.mdx b/site/src/content/docs/signals/levels/time-weighting.mdx
index b0730ce79..5d7e81589 100644
--- a/site/src/content/docs/signals/levels/time-weighting.mdx
+++ b/site/src/content/docs/signals/levels/time-weighting.mdx
@@ -1,6 +1,6 @@
---
title: "Time Weighting"
-description: "Fast, Slow and Impulse ballistics per IEC 61672-1."
+description: "The exponential detector of IEC 61672-1:2013: the Fast and Slow time constants, the legacy Impulse ballistics that standard dropped, the tone-burst verification against Table 4, the initial-state options and streaming across blocks."
references:
- type: standard
organization: "International Electrotechnical Commission"
@@ -175,7 +175,9 @@ $$
| `x` | 1D or 2D array | pressure (any scale) | non-empty | Squared internally; output is a mean-square envelope |
| `fs` | int | Hz | > 0 | |
| `mode` | str | — | `'fast'` (default), `'slow'`, `'impulse'` | $\tau$ = 125 ms / 1 s / 35 ms attack + 1.5 s decay |
+| `initial_state` | `None` / `'zero'` / `'first'` / float / array | mean square of $x$ | default `None` (= `'zero'`) | Integrator state $y[-1]$; see sections 5 and 6 |
| `TimeWeighting(fs, mode)` (class) | — | — | — | Stateful variant for streaming: `process(x)` carries the integrator state between blocks |
+| `TimeWeighting.reset()` | — | — | — | Drops the carried state so the next `process()` starts from rest |
The output has the units of $x^2$: take `10*log10(y / p0**2)` for SPL or use
the level functions, which do it for you.
@@ -223,10 +225,28 @@ plt.show()
## 5. Initial state
-By default, the exponential integrator starts from rest (`y[-1] = 0`). Passing
-`initial_state=None` leaves this default unspecified, while `initial_state='zero'`
-requests the same zero state explicitly. If the recorded segment begins after a
-steady signal is already present, you can start from the first sample energy instead:
+The integrator needs a starting value for $y[-1]$, and there are four ways to
+give it.
+
+- **`None` (the default) and `'zero'` are the same thing**, a start from rest, so
+ the level climbs through the settling ramp of section 1.
+- **`'first'` seeds it with the square of the very first sample**, $x[0]^2$. That
+ is an unbiased but extremely noisy estimate of the mean square — one degree of
+ freedom — and for a tone it depends entirely on the phase at the cut. In the
+ snippet below it is *exactly zero*, because a sine starting at $t = 0$ starts
+ at a zero crossing, so `'first'` there is bit-identical to `'zero'`.
+- **A float** resumes a state you saved yourself, which is what block processing
+ does in section 6.
+- **An array** broadcastable to the input shape without the time axis does the
+ same per channel.
+
+If the record is a continuation of a signal already running, seed the integrator
+with something robust — the mean square of the first half second,
+`initial_state=float(np.mean(recording[:fs // 2] ** 2))`, is a far better
+estimate than a single sample. If the record is the *start* of the event, do not
+seed at all: let it start from rest and discard the first $5\tau$ (0.6 s Fast,
+5 s Slow), which is exactly what `ln_levels` does internally before computing
+percentiles.
```python
import numpy as np
@@ -236,7 +256,10 @@ from phonometry import filters
fs = 48000
recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
-energy_envelope = filters.time_weighting(recording, fs, mode='fast', initial_state='first')
+# Robust seed: the mean square of the first half second, not one sample.
+energy_envelope = filters.time_weighting(
+ recording, fs, mode='fast',
+ initial_state=float(np.mean(recording[:fs // 2] ** 2)))
```
## 6. Block processing
diff --git a/site/src/content/docs/signals/metrology/calibration.mdx b/site/src/content/docs/signals/metrology/calibration.mdx
index ac746f6cb..f18c7ace9 100644
--- a/site/src/content/docs/signals/metrology/calibration.mdx
+++ b/site/src/content/docs/signals/metrology/calibration.mdx
@@ -73,11 +73,14 @@ changes: touch the gain knob and you must recalibrate.
-## Physical Calibration (Sound Level Meter)
+## Calibrating a recording, end to end
-To get accurate SPL measurements from a digital recording, you must first
-calculate the sensitivity of your measurement chain using a reference tone
-(e.g., 94 dB @ 1 kHz).
+The three steps below are the whole physical-SPL workflow: a calibrator take,
+one call to `sensitivity()`, and the factor handed to a level function. Both
+recordings must come from the same chain with nothing touched in between. The
+same factor works across the whole library: `octave_filter` and
+`OctaveFilterBank` take it inside `LevelCalibration(factor=...)`, and `leq`,
+`laeq` and `ln_levels` as `calibration_factor=`.
@@ -101,13 +104,9 @@ calibration_factor = metrology.sensitivity(calibrator_recording, target_spl=94.0
spl, freq = filters.octave_filter(
recording, fs,
calibration=filters.LevelCalibration(factor=calibration_factor))
-# Now 'spl' values are in real-world dB SPL!
+# spl is now in dB SPL re 20 µPa
```
-The same factor works across the whole library: `octave_filter` and
-`OctaveFilterBank` take it inside `LevelCalibration(factor=...)`, and `leq`,
-`laeq` and `ln_levels` as `calibration_factor=`.
-
## Calibrator assumptions (IEC 60942)
`sensitivity` assumes the reference recording comes from an acoustic
@@ -130,10 +129,19 @@ When you pass the sample rate (and `validate=True`, the default),
IEC 60942:2017 checks the calibrator itself (5.3.3): the *short-term level
fluctuation*, the absolute difference between each of the maximum and minimum
F-time-weighted levels and the mean level, must not exceed the Table 2 class 1
-limit for the calibrator's nominal frequency (0.07 dB at and above 160 Hz, relaxed
-to 0.10 dB below 160 Hz and 0.20 dB at or below 63 Hz, where the F
-time-weighting itself ripples). Pass `frequency=` to select the right row for non-1 kHz
-calibrators. A `CalibrationWarning` flags badly coupled microphones or handling
+limit for the calibrator's nominal frequency. Table 2 gives three disjoint rows,
+and they must not be read as overlapping ranges:
+
+| Nominal frequency | Class 1 limit | |
+| :--- | :---: | :--- |
+| 160 Hz to 16 kHz | 0.07 dB | the strict row, and the one a 1 kHz calibrator is judged on |
+| above 63 Hz to below 160 Hz | 0.10 dB | |
+| 31.5 Hz to 63 Hz | 0.20 dB | where the F time weighting itself ripples on the tone |
+
+Table 2 spans 31.5 Hz to 16 kHz and specifies nothing outside it, so a
+`frequency` below 31.5 Hz or above 16 kHz falls back to the strict 0.07 dB
+rather than to the relaxed low-frequency rows. Pass `frequency=` to select the
+right row for non-1 kHz calibrators. A `CalibrationWarning` flags badly coupled microphones or handling
noise before they silently corrupt every calibrated level. The recording must
be at least 2 s long (1 s for the F-integrator to settle plus 1 s of settled
envelope); shorter recordings get a warning instead of an unreliable verdict.
@@ -224,7 +232,7 @@ chain with a class 2 calibrator silently downgrades every derived level to
class 2 accuracy, because the calibrator's wider level tolerance enters
$S$ directly.
-## Digital Analysis (dBFS)
+## Digital analysis (dBFS)
If you are working with digital audio files (e.g., WAV, FLAC) and want to
analyze levels relative to Full Scale rather than physical pressure, you can use
@@ -251,14 +259,16 @@ spl_dbfs, freq = filters.octave_filter(
# Results will be negative (e.g., -20 dBFS)
```
-## RMS vs Peak Levels
+## RMS versus peak levels
-phonometry supports two measurement modes to align with professional software
-like BK:
+Levels can be read two ways, and both are in use in commercial analysers:
-- **RMS (`mode='rms'`)**: Energy-based level (standard).
-- **Peak (`mode='peak'`)**: Absolute maximum value reached in the frame
- (Peak-holding).
+- **RMS (`mode='rms'`)** integrates energy over the frame, which is what every
+ standardized level ($L_{eq}$, $L_{Aeq}$, $L_N$) is defined on.
+- **Peak (`mode='peak'`)** holds the largest instantaneous value in the frame,
+ which is what impact and peak-limit criteria such as $L_{Cpeak}$ are checked
+ against. Note that the band peak returned here is band-limited and
+ unweighted, so it is not itself $L_{Cpeak}$.
```python
import numpy as np
@@ -283,8 +293,18 @@ abruptly may read up to ~1 dB high. This is inherent to IIR band filters
## Integer audio input
Integer signals (e.g. int16 from `scipy.io.wavfile.read`) are converted to
-float64 internally before any squaring, so calibration and level results are
-identical whether you pass the raw integer array or a float conversion.
+float64 internally before any squaring. The conversion is a dtype cast, not a
+rescaling: an int16 sample of +32767 enters as 32767.0, not as 1.0. That is
+harmless *as long as the calibrator recording and the measurement are in the
+same format*, because `sensitivity` then returns a factor 32768 times smaller
+and the two cancel exactly — a tone that reads 87.958 dB from float arrays reads
+87.958 dB from the int16 arrays of the same recordings. It is not harmless
+otherwise: the same tone read uncalibrated is 87.94 dB as float and 172.14 dB as
+int16, a $20\log_{10}(32768) = 90.3$ dB offset, and applying a float-derived
+sensitivity to an integer-read measurement (or the reverse) carries that offset
+straight into the result with no symptom. Either keep both recordings in one
+format, or divide both by the full-scale value (`x / 32768.0` for int16) before
+anything else.
## What this guide covers
diff --git a/site/src/content/docs/signals/sound-level-meter.mdx b/site/src/content/docs/signals/sound-level-meter.mdx
index c8cb59c70..80ea4a492 100644
--- a/site/src/content/docs/signals/sound-level-meter.mdx
+++ b/site/src/content/docs/signals/sound-level-meter.mdx
@@ -26,6 +26,7 @@ references:
---
import ThemeImage from '../../../components/ThemeImage.astro';
+import Video from '../../../components/Video.astro';
A sound level meter is not one algorithm but a short pipeline of them, and
IEC 61672-1 specifies every stage. phonometry implements each stage as an
@@ -85,8 +86,14 @@ cal = metrology.sensitivity(calibrator, target_spl=94.0, fs=fs)
```
Deep guide: [Calibration and dBFS](/phonometry/signals/metrology/calibration/), which
-also covers calibrating from a known microphone sensitivity and the digital
-dBFS mode used when no physical reference exists.
+covers the stability check this call runs on the calibrator recording, the
+integer-format rule, and the digital dBFS mode used when no physical reference
+exists. With no calibrator at all the factor can be computed from the chain's
+rated sensitivity rather than measured — a microphone rated $M$ mV/Pa through a
+preamplifier of linear gain $G$ into a converter whose full scale is $V_{FS}$
+volts gives $S = V_{FS} / (M G / 1000)$ pascals per digital unit — but a rated
+factor carries the datasheet's tolerance rather than the ±0.4 dB of a class 1
+calibrator, so it cannot be reported as a calibrated measurement.
## 3. Weight: frequency and time (IEC 61672-1)
@@ -104,14 +111,27 @@ laf_t = 10 * np.log10(np.maximum(envelope, 1e-12) / (2e-5) ** 2)
# laf_t peaks near 80 dB during the event and settles near 55 dB between.
```
-You rarely write this chain yourself: every level function of the next step
-applies the frequency weighting internally, and the percentile levels rebuild
-this Fast envelope for you. The energy metrics ($L_{eq}$, SEL) integrate the
-squared weighted signal directly, with no ballistics, exactly as a meter
-does. The chain is shown here because it *is* the meter's display.
+
+
+The needle in the clip is that `time_weighting` call: a first-order low-pass
+charging and draining on the squared signal. The three needles differ in one
+number, the time constant, which is why Fast catches an event that Slow
+smooths away. You rarely write this chain yourself: every level function of
+the next step applies the frequency weighting internally, and the percentile
+levels rebuild this Fast envelope for you. The energy metrics ($L_{eq}$, SEL)
+integrate the squared weighted signal directly, with no ballistics at all —
+which is why they show no needle movement to follow. The chain is shown here
+because it *is* the meter's display.
Deep guides: [Frequency Weighting (A, C, Z)](/phonometry/signals/levels/weighting/)
-and [Time Weighting](/phonometry/signals/levels/time-weighting/).
+and [Time Weighting](/phonometry/signals/levels/time-weighting/), which takes
+this same clip apart against the IEC 61672-1 tone-burst table.
## 4. Integrate: the numbers a meter reports
@@ -133,11 +153,18 @@ print(f"LAeq {la_eq:.1f} dB | L10 {ln[10]:.1f} | L90 {ln[90]:.1f} "
f"| LAE {lae:.1f} | LCpeak {lc_pk:.1f}")
```
-Note the arithmetic the numbers encode: the 1 s event dominates $L_{Aeq}$ (it
-sits 25 dB above the background, far more than the 10 dB the
-nine-times-longer background gets back in duration), $L_{AE}$ is $L_{Aeq}$
-plus $10\log_{10}$ of the 10 s duration, and $L_{90}$ barely notices the event at
-all.
+Note the arithmetic the numbers encode. The event second measures 80.0 dB on its
+own and the nine background seconds 55.0 dB, so in energy the event contributes
+$1 \times 10^{8.00}$ and the background $9 \times 10^{5.50} = 2.9 \times 10^{6}$
+— a ratio of about 35:1, or 15.5 dB. The event's 25 dB head start beats the
+9.5 dB ($10\log_{10}9$) the background wins back on duration, which is why the
+10 s $L_{Aeq}$ of 70.2 dB sits only 0.1 dB above the 70.0 dB the event alone
+would give spread over the same 10 s: the background is almost invisible in the
+energy average. $L_{AE}$ is that $L_{Aeq}$ plus $10\log_{10}(10\ \mathrm{s}/1\
+\mathrm{s}) = 10$ dB, the whole energy compressed into one second. The
+percentiles read the other way round: the event fills exactly 10 % of the
+record, so it lifts $L_{10}$ to 78.0 dB and leaves $L_{90}$ at 54.9 dB, the
+background level.
Deep guide: [Integrated and Statistical Levels](/phonometry/signals/levels/levels/),
which adds noise dose and octave spectrograms; the $L_{den}$ and rating levels
diff --git a/site/src/content/docs/signals/spectra/time-frequency.mdx b/site/src/content/docs/signals/spectra/time-frequency.mdx
index b0ae078a5..8780a0121 100644
--- a/site/src/content/docs/signals/spectra/time-frequency.mdx
+++ b/site/src/content/docs/signals/spectra/time-frequency.mdx
@@ -73,9 +73,15 @@ res.plot() # dB image over the time-frequency plane
```
The segment length is the whole design decision: $T_B = \text{nperseg}/f_s$
-of time resolution against $B_e \approx 1/T_B$ of frequency resolution, a
-product of one
-(Section 12.6.4.2). Long segments pin frequencies and smear transients;
+of time resolution against $B_e = \mathrm{ENBW}/T_B$ of frequency resolution,
+so their product $T_B B_e$ is fixed by the taper alone — 1 for a rectangular
+window, **1.5 for the Hann default used here** (Section 12.6.4.2, and the
+window figures of merit on the
+[spectral-analysis page](/phonometry/signals/spectra/spectral-analysis/#6-choosing-the-window)).
+The tiling diagram above draws the untapered case, where that product is exactly
+one. Halving the segment length buys twice the time resolution and costs exactly
+half the frequency resolution; nothing buys both.
+Long segments pin frequencies and smear transients;
short segments do the opposite. And because each cell is a single
*unaveraged* estimate, random data carries a per-cell normalized random
error of 1 (Eq. 8.158 with $n_d = 1$; Bendat & Piersol quote
@@ -163,8 +169,10 @@ res.plot() # power spectrum in dB over the band
One distinction matters and the result states it: the **grid** can be made
arbitrarily fine (`n_points`), but the **resolution** - the ability to
separate two tones - is set by the record length and taper, reported as
-`resolution_bandwidth` ($B_e = f_s \sum w^2/(\sum w)^2$, i.e. $1/T$
-untapered, $1.5/T$ for Hann). Zooming refines the sampling of the same underlying spectrum;
+`resolution_bandwidth` ($B_e = f_s \sum w^2/(\sum w)^2$, i.e. $1/T_r$
+untapered and $1.5/T_r$ for Hann — the same taper factor as section 1, applied
+here to the record duration $T_r$ rather than to a segment, because the zoom FFT
+transforms the whole record). Zooming refines the sampling of the same underlying spectrum;
only a longer record separates closer tones.
diff --git a/site/src/content/docs/simulation/elastic-waves.mdx b/site/src/content/docs/simulation/elastic-waves.mdx
index 627b063b5..46434750e 100644
--- a/site/src/content/docs/simulation/elastic-waves.mdx
+++ b/site/src/content/docs/simulation/elastic-waves.mdx
@@ -49,6 +49,7 @@ references:
---
import ThemeImage from '../../../components/ThemeImage.astro';
+import Video from '../../../components/Video.astro';
A fluid carries one wave; a solid carries a family of them. This guide
covers the elastic companion of the
@@ -199,13 +200,25 @@ plt.show()
-That flexural wave is worth watching in motion: the
+That flexural wave is worth watching in motion. The clip below is this same
+solver launching a 4 kHz bending packet along a 10 mm steel plate: on the
+control panel the plate runs straight and the packet simply leaves, and on the
+junction panel a perpendicular plate of the same thickness turns the corner
+into a scatterer. The packet splits there into the reflected and transmitted
+bending waves the closed form prices at $\tau_{12}(0°) = 0.5$, plus the fast
+in-plane precursor that races ahead down the receiving plate — the mode
+conversion the pinned-junction model deliberately leaves out, and the reason
+this page needs an elastic solver rather than a flexural one. The
[bending-wave transmission guide](/phonometry/vibration/structural/junction-transmission/)
-embeds an animation of this solver launching a 4 kHz bending packet along a
-10 mm steel plate into an L-junction, where the corner splits it into the
-reflected and transmitted waves the closed form prices at
-$\tau_{12}(0°) = 0.5$, plus the fast in-plane precursor the pinned-junction
-model deliberately leaves out.
+takes the same run apart against the EN 12354 vibration reduction index.
+
+
## 4. Fluid-solid coupling at normal incidence
@@ -353,13 +366,32 @@ dip within 0.1 % of the 295 kHz resonance. The same suite stress-tests the
extreme contrast of an air-steel contact (impedance ratio ~$10^5$:1): stable
over 10 000 steps with the reflected amplitude conserved to 0.5 %.
-At oblique incidence the plate physics gets richer, and the
+At oblique incidence the plate physics gets richer, and the clip below is
+this solver driving the same 10 mm steel plate, now lying in air, with a
+sustained 45° plane wave arriving on it. The two panels differ in **one
+number only** — the drive frequency, $f_c/2 = 603$ Hz on the left and
+$2 f_c = 2413$ Hz on the right, either side of the 1206 Hz coincidence
+frequency the library computes from the same $m''$ and $B'$ used above.
+Everything else, the plate, the angle, the mesh and the colour scale, is
+held fixed. Below $f_c$ the plate reflects almost everything and the
+transmitted level lands on the oblique mass law; above it the acoustic
+trace wavelength matches the free bending wavelength, the plate re-radiates
+a 45° beam that grows along the lit span, and the transmitted level holds at
+the low-frequency figure where the mass law demanded 12 dB more blocking.
+The air below the plate is drawn on both panels with the display gain
+`_weak_field_gain` measures off the settled field of the two runs together
+(×150, that is +44 dB) and prints on the canvas: read the *annotations* for
+levels, not the brightness. The
[panel sound insulation guide](/phonometry/buildings/design/panel-sound-insulation/)
-embeds the animation: this solver driving the same 10 mm steel plate, lying
-in air, with a sustained 45° plane wave below and above its coincidence
-frequency, where the trace-matched bending wave re-radiates a growing beam
-and holds the transmitted level at the point where the mass law demands
-12 dB more blocking.
+takes the same run apart against the plateau method and the mass law.
+
+
## What this guide covers
diff --git a/site/src/content/docs/simulation/fdtd-simulation.mdx b/site/src/content/docs/simulation/fdtd-simulation.mdx
index 8f71d53e5..bdfe20746 100644
--- a/site/src/content/docs/simulation/fdtd-simulation.mdx
+++ b/site/src/content/docs/simulation/fdtd-simulation.mdx
@@ -37,6 +37,7 @@ references:
---
import ThemeImage from '../../../components/ThemeImage.astro';
+import Video from '../../../components/Video.astro';
Most of phonometry predicts a **number**: a level, a reverberation time, a
transmission loss. The `simulation` domain computes the **wave field
@@ -58,6 +59,32 @@ animations of this documentation, promoted to a public API with sources,
pressure probes, rasterised obstacles, per-side boundary conditions and a
frozen result object.
+Here is one of those animations, and it is a fair advertisement for what the
+rest of this page builds. Nothing in it is drawn: the colonnade is a boolean
+`obstacle_mask` of rasterised circles and the wavefront is a single one-way
+plane-wave packet with a Gaussian envelope one wavelength wide, launched at
+$x = 0.30$ m into a 4 m × 1 m rigid-walled hall whose two ends absorb through
+sponges hidden outside the frame. The carrier is 800 Hz, so the wavelength is
+42.9 cm and the 10 to 17 cm columns are roughly a quarter to two fifths of it
+— the regime in which a rigid cylinder both casts a readable shadow and
+re-radiates strongly, which is why the coda that fills the hall is structured
+rather than noise. That coda is deterministic multiple scattering: it is what
+a diffuse field looks like *before* any statistical assumption is made about
+it. The mesh is the worked example of the rule
+[section 4](#4-numerical-dispersion-and-accuracy) derives: the tightest gap
+in this layout is 6.6 cm between a column and a wall, so
+$\Delta x = \min(\text{smallest aperture}/4,\ \lambda/8)$ allows up to 1.6 cm,
+and the clip runs at 2.5 mm because a banner needs the definition.
+
+
+
## 1. The scheme: a wave equation on a grid
@@ -89,10 +116,13 @@ $$
= \frac{c\,\Delta t\,\sqrt{2}}{\Delta x} \le 1,
$$
-and `fdtd_simulation` derives the time step from the `cfl` parameter (the
-Courant number, default 0.6) and the largest sound speed in the map; values
+and `fdtd_simulation` derives the time step from the `cfl` parameter (this
+$\mathrm{CN}$, default 0.6) and the largest sound speed in the map; values
outside $(0, 1)$ are rejected because the scheme is unconditionally
-meaningless beyond the bound (Eq. 4.14).
+meaningless beyond the bound (Eq. 4.14). Section 4 also uses a *per-axis*
+Courant number $S = c\,\Delta t/\Delta x = \mathrm{CN}/\sqrt{2}$ in the
+dispersion relation; the two are not the same number, and the default
+`cfl = 0.6` means $S = 0.424$.
```python
from phonometry import simulation
@@ -521,7 +551,10 @@ $$
with a leading-order relative frequency error of magnitude
$(1 - S^2)\,(k\,\Delta x)^2 / 24$ along the grid axes (the modelled frequency
-under-reads, so the signed error is negative), where $S = c\,\Delta t / \Delta x$;
+under-reads, so the signed error is negative), where
+$S = c\,\Delta t / \Delta x$ is the **per-axis** Courant number, which for
+square cells is the `cfl` value divided by $\sqrt{2}$ — the default
+`cfl = 0.6` gives $S = 0.424$ and $1 - S^2 = 0.82$;
the error is largest exactly on-axis and vanishes along the cell diagonal
at the Courant limit $\mathrm{CN} = 1$. The practical rule is to resolve **at
least 10 cells per shortest wavelength**, $\Delta x \le c_\text{min} / (10 f_\text{max})$
@@ -603,7 +636,9 @@ Resolve at least 10 cells per shortest wavelength,
$\Delta x \le c_\text{min} / (10 f_\text{max})$, using the smallest sound
speed in the domain.
At exactly 10 cells the on-axis dispersion error bound is about 1.6 %,
-reduced to about 1.4 % at the default ``cfl = 0.6``, and halving $\Delta x$
+reduced to about 1.4 % at the default ``cfl = 0.6`` (the per-axis Courant
+number is then $S = \mathrm{cfl}/\sqrt{2} = 0.424$, so the $1 - S^2$ factor is
+0.82), and halving $\Delta x$
quarters the error (the scheme is second order). With $\Delta x = 1$ cm the
10-cell point in air sits at roughly 3.4 kHz.
@@ -613,8 +648,11 @@ The explicit scheme is stable only while a wavefront crosses at most one
cell per time step. With square cells the Courant number is
$\mathrm{CN} = c\,\Delta t\,\sqrt{2}/\Delta x \le 1$ (Attenborough & Van
Renterghem Eq. 4.13). `fdtd_simulation` derives the time step from the
-`cfl` parameter (the Courant number, default 0.6) and the largest sound
-speed in the map, rejecting values outside $(0, 1)$.
+`cfl` parameter (that same $\mathrm{CN}$, default 0.6) and the largest sound
+speed in the map, rejecting values outside $(0, 1)$. The *per-axis* Courant
+number of the dispersion relation above is a different number,
+$S = c\,\Delta t/\Delta x = \mathrm{CN}/\sqrt{2}$, which is 0.424 at the
+default.
### Can I trust the absolute levels from a 2D FDTD run?
diff --git a/site/src/content/docs/simulation/index.md b/site/src/content/docs/simulation/index.md
index 04894d0ff..d9f7fdb90 100644
--- a/site/src/content/docs/simulation/index.md
+++ b/site/src/content/docs/simulation/index.md
@@ -36,6 +36,32 @@ ground), the simulation is the fallback that still gives a quantitative
answer; when a closed form exists, prefer it, and use the solver to verify
the assumptions it rests on.
+Those cross-checks are not only arguments: fifteen of the animations in this
+documentation are output from these two solvers, and they are filed on the
+guides whose physics they settle rather than here. Room modes growing on and
+off resonance appear in [room acoustics](/phonometry/buildings/rooms/room-acoustics/)
+and [reverberation prediction](/phonometry/buildings/rooms/reverberation-prediction/),
+which also carries the hall of columns that turns one wavefront into a mixed
+field; barrier diffraction at two wavelengths in
+[outdoor propagation](/phonometry/environment/propagation/outdoor-propagation/)
+and [ground effect and barriers](/phonometry/environment/propagation/ground-barriers/);
+downwind and upwind refraction in
+[atmospheric refraction](/phonometry/environment/propagation/atmospheric-refraction/);
+the ground-effect lobe pattern in outdoor propagation and in
+[airport noise](/phonometry/aircraft/airport-noise/); the standing-wave and
+transmission tubes in [the impedance tube](/phonometry/materials/absorbers/impedance-tube/);
+the QRD and metadiffuser panels in
+[diffusers](/phonometry/materials/diffusers/diffusers/) and
+[metadiffusers](/phonometry/materials/diffusers/metadiffusers/); the slit
+absorber in [metamaterial absorbers](/phonometry/materials/absorbers/metamaterial-absorbers/);
+the expansion chamber in [silencers](/phonometry/devices/noise-control/silencers/);
+the wall aperture in [panel sound insulation](/phonometry/buildings/design/panel-sound-insulation/);
+and the SOFAR duct in [underwater propagation](/phonometry/underwater/underwater-propagation/).
+The elastic solver adds two: the bending packet entering an L-junction, on
+[junction transmission](/phonometry/vibration/structural/junction-transmission/),
+and the coincidence plate, on panel sound insulation. Both also appear on the
+elastic page below, where the solver that produced them is explained.
+
## Pages in this section
- [2D FDTD wave simulation](/phonometry/simulation/fdtd-simulation/): the
diff --git a/site/src/content/docs/start/getting-started.mdx b/site/src/content/docs/start/getting-started.mdx
index 7b4faf446..87a9065b6 100644
--- a/site/src/content/docs/start/getting-started.mdx
+++ b/site/src/content/docs/start/getting-started.mdx
@@ -72,9 +72,9 @@ guides cover them left to right ([Calibration](/phonometry/signals/metrology/cal
[Frequency Weighting](/phonometry/signals/levels/weighting/) → [Filter Banks](/phonometry/signals/filters/filter-banks/) →
[Time Weighting](/phonometry/signals/levels/time-weighting/) → [Levels](/phonometry/signals/levels/levels/)).
-## Basic Usage: 1/3 Octave Analysis
+## A first analysis: one-third-octave bands (uncalibrated)
-Analyze a signal and get the Sound Pressure Level (SPL) per frequency band.
+Split a signal into one-third-octave bands and read the level of each one.
```python
import numpy as np
@@ -91,12 +91,28 @@ spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
print(f"Bands: {freq}")
# Bands: [12.589254117941678, 15.848931924611138, ..., 19952.623149688785] (33 bands)
print(f"SPL [dB]: {spl}")
-# SPL [dB]: [46.88395351 47.96774897 49.04991279 ...] — ~90.7 dB at 100 Hz and ~90.9 dB at 1 kHz
+# SPL [dB]: [46.88395351 47.96774897 49.04991279 ...] — 90.71 dB at 100 Hz and 90.95 dB at 1 kHz
```
-
-
-*Example of a 1/3 Octave Band spectrum analysis of a complex signal.*
+**These are not yet physical levels.** `octave_filter` always returns
+$20\log_{10}(p_\mathrm{rms} / 20\,\mu\mathrm{Pa})$, and with the default
+calibration it takes the numeric value of each sample *to be* the pressure in
+pascals. A unit-amplitude sine is therefore read as 0.7071 Pa rms, which is
+90.97 dB — exactly right for a synthetic signal defined in pascals, and exactly
+wrong for a recording, whose sample values are whatever the converter and the
+gain staging happened to produce. There are two honest ways to get a level you
+can defend. Pass the pascals-per-digital-unit factor obtained from a calibrator
+tone, `calibration=filters.LevelCalibration(factor=S)` — see
+[Calibration and dBFS](/phonometry/signals/metrology/calibration/) — or, when
+the signal never had a physical scale, ask for `LevelCalibration(dbfs=True)` and
+read levels relative to digital full scale, which come out negative and cannot
+be mistaken for an SPL.
+
+
+
+*A richer example than the snippet above: six tones (20, 100, 500, 2000, 4000
+and 15000 Hz) at amplitude 100, so the band levels run to about 131 dB. The
+grey curve is the raw-signal PSD, shifted down to share the axis.*
Show the code for this figure
@@ -108,15 +124,16 @@ import numpy as np
from phonometry import filters
fs = 48000
-t = np.linspace(0, 1, fs, endpoint=False)
-# Composite signal: 100Hz + 1000Hz
-signal = np.sin(2 * np.pi * 100 * t) + np.sin(2 * np.pi * 1000 * t)
+t = np.linspace(0, 5, 5 * fs, endpoint=False)
+# Six tones at amplitude 100, so the bands land around 130 dB
+tones = [20, 100, 500, 2000, 4000, 15000]
+y = 100 * np.sum([np.sin(2 * np.pi * f * t) for f in tones], axis=0)
# Apply 1/3 octave filter bank
-spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
+spl, freq = filters.octave_filter(y, fs=fs, fraction=3, limits=[12.0, 20000.0])
# Gray background: the raw-signal PSD (Welch), shifted to sit just below the
# band SPLs so both spectral shapes share one axis.
-f_psd, psd = scipy.signal.welch(signal, fs, nperseg=8192)
+f_psd, psd = scipy.signal.welch(y, fs, nperseg=8192)
psd_db = 10 * np.log10(psd + 1e-12)
psd_db += np.max(spl) - np.max(psd_db) - 5
@@ -126,7 +143,8 @@ ax.semilogx(freq, spl, marker="o", markerfacecolor="white",
label="1/3 octave bands")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("SPL [dB]")
-ax.legend()
+ax.set_xlim(11, 25000)
+ax.legend(loc="lower right")
plt.show()
```
@@ -141,25 +159,52 @@ from phonometry import filters
# Load standard WAV file
fs, signal = wavfile.read("measurement.wav")
+# wavfile.read returns (samples, channels); the bank expects (channels, samples)
+if signal.ndim > 1:
+ signal = signal[:, 0] # measurement microphone on channel 1
+
# Analyze
# Note: To obtain real-world SPL values, you must calibrate the input.
# See the Calibration guide.
spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
```
-Integer audio (e.g. int16 WAV data) is converted to float64 internally, so it is
-safe to pass `wavfile.read` output directly.
+**Reduce a multichannel file to the channel you measured with, or transpose it.**
+The guard above is not decoration: `wavfile.read` returns a `(samples,
+channels)` array, and the bank reads a 2D array as `(channels, samples)`. Pass a
+stereo file as it comes and nothing raises — a 2400-sample stereo array returns
+an `spl` of shape `(2400, 33)`, one spectrum per *pair of samples*, and a
+one-second file takes minutes to produce meaningless numbers. See
+[Multichannel and Performance](/phonometry/signals/filters/multichannel/) for
+the convention, and for the case where several calibrated channels are analysed
+at once, each with its own sensitivity.
+
+**Integer audio is cast, not rescaled.** `wavfile.read` output runs without an
+error because integers are converted to float64 internally, but an int16 sample
+of +32767 enters the bank as 32767.0 rather than 1.0. Every level therefore
+comes out $20\log_{10}(32768) = 90.3$ dB above the same signal read as float —
+measured, a unit-amplitude 1 kHz sine peaks at 90.95 dB and the same sine
+written to int16 peaks at 181.26 dB. Divide by the full-scale value
+(`signal / 32768.0` for int16) before analysing, or let the calibration step
+absorb it: a sensitivity determined from a calibrator recording *in the same
+integer format* already carries the factor. Mixing the two — a float-read
+calibrator and an integer-read measurement, or the reverse — is wrong by 90 dB
+with no symptom. The rules are in
+[Calibration and dBFS](/phonometry/signals/metrology/calibration/).
## Where to go next
-The octave analysis above uses the `filters` core, one of eighteen domain
-namespaces; the sidebar sections walk through the rest, from psychoacoustics
-and room, building and vibration acoustics to environmental, aircraft and
-underwater noise, electroacoustics and FDTD wave simulation. Every result
-object exposes a one-line `.plot(language="en"|"es")` figure and, where a
-standard defines a reporting format, a `.report()` method that renders the
-normative PDF fiche.
-
+The octave analysis above uses `phonometry.filters`, one of eighteen import
+namespaces. The documentation groups them into **ten areas**, one per sidebar
+topic, from psychoacoustics and room, building and vibration acoustics to
+environmental, aircraft and underwater noise, electroacoustics and FDTD wave
+simulation. Every result object exposes a one-line
+`.plot(language="en"|"es")` figure and, where a standard defines a reporting
+format, a `.report()` method that renders the normative PDF fiche.
+
+- [Build a sound level meter](/phonometry/signals/sound-level-meter/): the same chain run end to end, from the calibrator tone to $L_{AF}(t)$, $L_{Aeq}$, $L_{AE}$, $L_{Cpeak}$, the percentile levels and the class check of every stage
+- [All guides](/phonometry/start/guides/): the map, every guide grouped by topic with a line on each
+- [Glossary](/phonometry/reference/glossary/): a symbol, its unit, its defining clause and the guide that computes it
- [Filter Architecture Gallery](/phonometry/signals/filters/filter-gallery/): choose an architecture and inspect responses
- [Calibration and dBFS](/phonometry/signals/metrology/calibration/): get real-world SPL values
- [Why phonometry](/phonometry/start/why-phonometry/): the conformance-first design philosophy
diff --git a/site/src/content/docs/start/guides.md b/site/src/content/docs/start/guides.md
index df02058cb..77cb7d0de 100644
--- a/site/src/content/docs/start/guides.md
+++ b/site/src/content/docs/start/guides.md
@@ -55,7 +55,7 @@ head:
"@type": "ListItem",
"position": 6,
"name": "Environment and transport",
- "description": "Outdoor propagation, barriers, refraction, aircraft, rotorcraft and wind turbines.",
+ "description": "Outdoor propagation, barriers, refraction, road, rail and wind-turbine sources, and the assessment built on them.",
"url": "https://jmrplens.github.io/phonometry/environment/"
},
{
@@ -356,6 +356,8 @@ reaches it, measured in a laboratory or predicted from the material
parameters. Implements ISO 354, ISO 11654, ISO 10534-1/-2, ISO 9053-1/-2,
ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 and ISO 12999-2.
+**[Absorbers](/phonometry/materials/absorbers/)**
+
- [Sound Absorption Measurement and Rating](/phonometry/materials/absorbers/absorption-measurement/):
the ISO 354 reverberation-room measurement, the weighted rating and its
class, and the measurement uncertainty of both.
@@ -371,6 +373,8 @@ ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 and ISO 12999-2.
- [Metamaterial Absorbers](/phonometry/materials/absorbers/metamaterial-absorbers/): the
critical-coupling condition for perfect absorption and the slow-sound slit
panel loaded by Helmholtz resonators, with its design solver.
+**[Diffusers and surfaces](/phonometry/materials/diffusers/)**
+
- [Diffusers and Their Coefficients](/phonometry/materials/diffusers/diffusers/): the
random-incidence scattering coefficient, the autocorrelation diffusion
coefficient, and Schroeder design with its far-field prediction.
@@ -381,6 +385,11 @@ ISO 17497-1/-2, ISO 13472-1/-2, EN 29052-1 and ISO 12999-2.
in-situ road-surface absorption by the subtraction technique and the spot
method.
+The third group of this area, Resilient layers, has one guide,
+[Dynamic stiffness of resilient materials](/phonometry/materials/resilient/dynamic-stiffness/),
+listed above under Insulation design beside the floating-floor prediction that
+consumes it.
+
## [Vibration and structure-borne sound](/phonometry/vibration/)
Mobility and frequency-response functions, isolators, radiated power,
@@ -435,6 +444,15 @@ and IEC 61400-11.
- [Outdoor Sound Propagation](/phonometry/environment/propagation/outdoor-propagation/):
atmospheric absorption and the ISO 9613-2 general method, with a per-term
octave-band attenuation breakdown.
+- [Spherical ground effect and advanced barriers](/phonometry/environment/propagation/ground-barriers/):
+ the Weyl-Van der Pol reflection coefficient over finite-impedance ground, and
+ wave-theoretic barrier diffraction.
+- [Atmospheric refraction: rays and the GFPE](/phonometry/environment/propagation/atmospheric-refraction/):
+ effective sound-speed profiles, curved rays with a closed-form shadow-zone
+ distance, and the GFPE relative-level field.
+
+**[Sources](/phonometry/environment/sources/)**
+
- [CNOSSOS-EU road traffic source emission](/phonometry/environment/sources/cnossos-road-emission/):
the common EU road source of Annex II 2.2: rolling and propulsion sound power
per vehicle category and the directional power per metre of source line.
@@ -445,16 +463,17 @@ and IEC 61400-11.
- [Wind-turbine noise: sound power and tonal audibility](/phonometry/environment/sources/wind-turbine-noise/):
the apparent sound power level referred to the rotor centre, and the tonal
audibility chain that decides whether a tone is audible.
-- [Spherical ground effect and advanced barriers](/phonometry/environment/propagation/ground-barriers/):
- the Weyl-Van der Pol reflection coefficient over finite-impedance ground, and
- wave-theoretic barrier diffraction.
-- [Atmospheric refraction: rays and the GFPE](/phonometry/environment/propagation/atmospheric-refraction/):
- effective sound-speed profiles, curved rays with a closed-form shadow-zone
- distance, and the GFPE relative-level field.
+
+**[Assessment and regulation](/phonometry/environment/assessment/)**
+
- [Impulsive-sound prominence (NT ACOU 112)](/phonometry/environment/assessment/impulsive-sound/):
the predicted prominence of each impulse from its onset rate and level
difference, and the adjustment added to $L_{Aeq}$.
+The two remaining guides of this group, [Environmental Levels](/phonometry/environment/assessment/environmental-levels/)
+and [Spanish Noise Regulation](/phonometry/environment/assessment/spanish-noise-regulation/),
+are listed above under Signal analysis, beside the level definitions they build on.
+
## [Aircraft noise](/phonometry/aircraft/)
Certification levels, airport contours and the rotorcraft hemisphere
diff --git a/site/src/content/docs/start/index.md b/site/src/content/docs/start/index.md
index 32c384a43..389be9fdf 100644
--- a/site/src/content/docs/start/index.md
+++ b/site/src/content/docs/start/index.md
@@ -1,16 +1,36 @@
---
title: "Start"
-description: "Where to begin with phonometry: the ten-minute tour, why the library exists, and what it is."
+description: "Where to begin with phonometry: the first analysis end to end, the map of all the guides, why the library exists and who maintains it."
---
-The three pages that open the documentation, before the guides themselves.
+Four short pages, meant to be read once before anything else. Each answers one
+question, and they are in the order the questions arrive.
+**Can I install it and get a number out?**
[Getting Started](/phonometry/start/getting-started/) installs the library and
-walks a first measurement end to end, from a WAV file to a calibrated
-one-third-octave spectrum. [Why phonometry](/phonometry/start/why-phonometry/)
-sets out what the library is for and how it is validated against the standards
-it implements. [About](/phonometry/start/about/) states who maintains it, how
-to cite it and under what licence.
+runs a first one-third-octave analysis, on a synthetic signal and then on a WAV
+file, and states what a recording must satisfy before those numbers mean
+anything physical. It stops short of a calibrated measurement on purpose:
+[Calibration and dBFS](/phonometry/signals/metrology/calibration/) is the next
+step, the one that turns band levels into pascals, and
+[Build a sound level meter](/phonometry/signals/sound-level-meter/) runs the
+whole chain end to end.
+**Where is the thing I came for?**
[All guides](/phonometry/start/guides/) is the map: every guide in the library,
grouped by the topic it belongs to, with a line on each.
+
+**Should I trust the number?**
+[Why phonometry](/phonometry/start/why-phonometry/) sets out what the library
+is for and how it is validated against the standards it implements, with the
+tone-burst check worked through against the acceptance limits.
+
+**Who is answerable for it, and how do I cite it?**
+[About](/phonometry/start/about/) states who maintains it, how to cite it and
+under what licence.
+
+The assumed starting point is Python 3.13 or newer with working NumPy and
+SciPy, and enough acoustics to know what a one-third-octave band and a sound
+pressure level are. Any symbol the guides use without introducing is in the
+[glossary](/phonometry/reference/glossary/), with its unit, its defining clause
+and the guide that computes it.
diff --git a/site/src/content/docs/start/why-phonometry.mdx b/site/src/content/docs/start/why-phonometry.mdx
index 84b4569b5..6ea592f19 100644
--- a/site/src/content/docs/start/why-phonometry.mdx
+++ b/site/src/content/docs/start/why-phonometry.mdx
@@ -46,35 +46,64 @@ The rigorous test for time weighting is the **Tone Burst Response**
(IEC 61672-1, Table 4), using a 4 kHz sine burst referenced to the steady-state
level.
+### How the check is run
+
+Table 4 fixes the excitation but not the plumbing, so here is the plumbing. A
+4 kHz sine is generated at 48 kHz for 3 s. The **reference** is the steady Fast
+level of that continuous sine, averaged over its last half second — once the
+integrator has settled, this is $L_A$ in the standard's notation. The burst of
+the stated duration is then cut out of *the same* sine, so its phase and
+amplitude are identical to the reference tone's, and zeros surround it. The
+**response** is the maximum of the Fast envelope of that burst, expressed
+relative to the reference: $10\log_{10}(\max \text{env} / \text{ref})$, which is
+the standard's $L_{AFmax} - L_A$. Note what this does and does not verify:
+IEC 61672-1 states these limits for the electrical input facility over a defined
+range of steady levels with no overload indicated (clauses 5.9.5-5.9.6), so the
+numbers below verify the *ballistics*, not a complete instrument. The same
+reference values are transcribed in `tests/filters/test_iec_compliance.py` for F
+and S and for the $L_{AE}$ column.
+
**phonometry results (FAST):**
-| Burst duration | IEC target (dB) | phonometry (dB) | Error (dB) | Status |
-| :--- | :--- | :--- | :--- | :--- |
-| 200 ms | −1.0 | −0.98 | +0.02 | ✅ PASS |
-| 50 ms | −4.8 | −4.82 | −0.02 | ✅ PASS |
-| 10 ms | −11.1 | −11.14 | −0.04 | ✅ PASS |
-| 1 ms | −21.0 | −20.99 | +0.01 | ✅ PASS |
+| Burst duration | IEC target (dB) | Class 1 limit (dB) | phonometry (dB) | Error (dB) | Status |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| 200 ms | −1.0 | ±0.5 | −0.98 | +0.02 | ✅ PASS |
+| 50 ms | −4.8 | ±1.0 | −4.82 | −0.02 | ✅ PASS |
+| 10 ms | −11.1 | ±1.0 | −11.14 | −0.04 | ✅ PASS |
+| 1 ms | −21.0 | +1.0 / −2.0 | −20.99 | +0.01 | ✅ PASS |
**python-acoustics results (FAST, squared signal passed as required by that
library):**
-| Burst duration | IEC target (dB) | python-acoustics (dB) | Error (dB) | Status |
-| :--- | :--- | :--- | :--- | :--- |
-| 200 ms | −1.0 | −0.97 | +0.03 | ✅ PASS |
-| 50 ms | −4.8 | −3.93 | **+0.87** | ⚠️ FAIL |
-| 10 ms | −11.1 | −10.90 | +0.20 | ✅ PASS |
-| 1 ms | −21.0 | −20.90 | +0.10 | ✅ PASS |
-
-phonometry maintains high precision across all test cases. The block-based
-approach deviates significantly (> 0.8 dB) for the 50 ms burst because 125 ms
-blocks cannot resolve short transient events accurately; the result depends on
-how the burst aligns with the block boundaries.
+| Burst duration | IEC target (dB) | Class 1 limit (dB) | python-acoustics (dB) | Error (dB) | Status |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| 200 ms | −1.0 | ±0.5 | −0.97 | +0.03 | ✅ PASS |
+| 50 ms | −4.8 | ±1.0 | −3.93 | **+0.87** | ✅ PASS |
+| 10 ms | −11.1 | ±1.0 | −10.90 | +0.20 | ✅ PASS |
+| 1 ms | −21.0 | +1.0 / −2.0 | −20.90 | +0.10 | ✅ PASS |
+
+**Both libraries pass every row shown**, and saying otherwise would be
+overstating the case — the point here is the *shape* of the error, not a
+compliance failure. phonometry stays within 0.05 dB of the Table 4 reference at
+every duration, under 5 % of the class 1 budget, because a continuous
+exponential detector has no free parameter left to get wrong. The block
+integrator stays inside class 1 too, but it spends 0.87 of the 1.0 dB available
+at 50 ms, and it spends it for a reason that is luck rather than design: how the
+burst happens to straddle a 125 ms block. Read the two tables together with the
+first column of Table 4, which tightens to ±0.5 dB for bursts of 200 ms and
+longer — at that end a block integrator has no margin left to lose.
*Measured Fast envelopes (blue) matching the Table 4 reference values
(dashed) within 0.1 dB for 200/50/10 ms bursts.*
+The generator behind this figure is
+`scripts/figures/signals.py::generate_tone_burst_iec`, and it is the procedure
+described above with three of the Table 4 rows: it prints
+`env_db.max() - target`, which is the Error column of the first table, so the
+phonometry rows can be reproduced directly.
+
## What this means in practice
- If you need **standard-compliant Fast/Slow/Impulse envelopes** (sound level
diff --git a/site/src/content/docs/underwater/marine-mammal-exposure.mdx b/site/src/content/docs/underwater/marine-mammal-exposure.mdx
index d233581e0..8339f9941 100644
--- a/site/src/content/docs/underwater/marine-mammal-exposure.mdx
+++ b/site/src/content/docs/underwater/marine-mammal-exposure.mdx
@@ -76,15 +76,23 @@ Every current criteria set sorts marine mammals into hearing groups and gives
each one a filter. The **group codes are not portable between guidance
versions**, and the collision is a real trap:
-| Southall et al. (2019) / NMFS 2024 | NMFS 2018 | Typical genera |
-|---|---|---|
-| LF cetaceans | LF | baleen whales |
-| HF cetaceans | **MF** | sperm, beaked and most delphinid whales |
-| VHF cetaceans | **HF** | porpoises, *Cephalorhynchus*, *Kogia* |
-| PCW / PW | PW | phocid seals in water |
-| OCW / OW | OW | otariids, in water |
-| SI, PCA, OCA | — | sirenians and carnivores in air |
-
+| Animal group | Southall 2019 | NMFS 2024 | NMFS 2018 | Audiogram |
+|---|---|---|---|---|
+| Baleen whales | LF | LF | LF | no ($F_1$ unpublished) |
+| Sperm, beaked and most delphinid whales | HF | HF | **MF** | yes (`"HF"`) |
+| Porpoises, *Cephalorhynchus*, *Kogia* | VHF | VHF | **HF** | yes (`"VHF"`) |
+| Phocid seals in water | PCW | PW | PW | yes (`"PCW"`) |
+| Otariids in water | OCW | OW | OW | yes (`"OCW"`) |
+| Sirenians | SI | — | — | yes (`"SI"`) |
+| Phocid seals in air | PCA | PA | — | yes (`"PCA"`) |
+| Otariids in air | OCA | OA | — | yes (`"OCA"`) |
+
+Read the column you are working in. `auditory_weighting` and
+`exposure_criteria` take the code of the `guidance` you select;
+`group_audiogram` always takes the **Southall** code, because the audiograms are
+Southall's. So `group_audiogram(f, "PW")` raises even though `"PW"` is a valid
+NMFS 2024 weighting group — ask for `"PCW"` — and `auditory_weighting(f, "PCW")`
+raises under the default guidance for the mirror-image reason.
`hearing_groups(guidance)` lists the codes a version defines, and passing a
code from the wrong version raises rather than silently returning the wrong
filter.
@@ -256,11 +264,29 @@ the recorded strike to the verdict:
accumulates it over the number of strikes (the ISO 18406 $+10\log_{10} N$) and
compares the result with the criteria, unweighted peak SPL included.
+### What the recording has to cover
+
+The weighted sum runs over the bands it is handed, so **the record must span the
+hearing group's passband**. The NMFS 2024 upper transition frequencies $f_2$ are
+26.6 kHz (LF), 129 kHz (HF), 186 kHz (VHF), 68.3 kHz (PW) and 43.8 kHz (OW), and
+the generalised hearing ranges reach further still (LF to 36 kHz, VHF to
+165 kHz). As a rule the sample rate has to be about 2.5 times the highest band
+edge that matters, so the 48 kHz record below — bands resolved to roughly 20 kHz
+— supports LF, is marginal for OW, and truncates HF, VHF and PW badly. A
+porpoise assessment needs a few hundred kilohertz.
+
+`weighted_exposure` cannot detect a truncated spectrum: it weights what it is
+given, so a short record simply reports a lower cumulative SEL and no warning.
+The unweighted peak half of the dual metric has to come from the same record
+with no clipping and headroom to spare, which is why ISO 18406 makes dynamic
+range a survey requirement: a saturated capture reads as a compliant peak.
+
```python
import numpy as np
from phonometry import underwater
-# One recorded strike (here a synthetic 200 Hz decaying burst).
+# One recorded strike (here a synthetic 200 Hz decaying burst). 48 kHz is
+# enough for the LF group used below and for nothing above it.
fs = 48_000
t = np.arange(int(0.2 * fs)) / fs
strike = 50.0 * np.exp(-t / 0.06) * np.sin(2 * np.pi * 200.0 * t)
@@ -306,8 +332,10 @@ step-function and dose-response thresholds used for harassment take estimates)
are out of scope: only the auditory-effect criteria are implemented. The
library does not choose a hearing group or an accumulation period for you, and
it does not model the animal's movement relative to the source, so the
-cumulative SEL it reports is the stationary-receiver worst case. Propagation
-from source to receiver belongs to
+cumulative SEL it reports is the stationary-receiver worst case. It also does
+not check that the supplied spectrum spans the group's passband: a record that
+stops short of $f_2$ is weighted as given and under-reports the exposure.
+Propagation from source to receiver belongs to
[Underwater sound propagation](/phonometry/underwater/underwater-propagation/).
## See also
diff --git a/site/src/content/docs/underwater/underwater-acoustics.mdx b/site/src/content/docs/underwater/underwater-acoustics.mdx
index ca38f8590..9ac72e055 100644
--- a/site/src/content/docs/underwater/underwater-acoustics.mdx
+++ b/site/src/content/docs/underwater/underwater-acoustics.mdx
@@ -58,7 +58,9 @@ exposure. Every quantity is an exact closed form, verified analytically.
## 1. Reference levels (ISO 18405)
Three primitives, referred to 1 µPa, are computed from a captured pressure
-signal (in Pa):
+signal. **Every pressure argument on this page is in pascals** — calibrated
+hydrophone output with no weighting applied — and every level comes out
+re 1 µPa (or re 1 µPa²·s):
$$
\mathrm{SPL} = 10\log_{10}\frac{\langle p^2\rangle}{p_0^2}, \qquad
@@ -128,14 +130,31 @@ res.plot()
```python
+import numpy as np
from phonometry import underwater
-lrn = underwater.radiated_noise_level(2e-6, 100.0) # p_rms = 2 µPa, r = 100 m
-res = underwater.monopole_source_level(lrn, 200.0, draught=6.0)
-print(res.source_level, res.surface_correction, res.source_depth)
+# Band r.m.s. pressures measured at 100 m from a merchant ship, in pascals.
+freqs = np.array([31.5, 63.0, 125.0, 250.0, 500.0, 1000.0])
+p_rms = np.array([4.3, 2.8, 1.9, 1.2, 0.8, 0.54])
+rnl = np.array([underwater.radiated_noise_level(float(x), 100.0) for x in p_rms])
+print(np.round(rnl, 1)) # [172.7 168.9 165.6 161.6 158.1 154.6] dB re 1 uPa.m
+
+# The surface correction is frequency-dependent, so the conversion is normally
+# run on the whole band vector at once.
+res = underwater.monopole_source_level(rnl, freqs, draught=6.0)
+print(np.round(res.source_level, 1)) # [177.8 168.4 161.7 157.8 154.8 151.6]
+print(np.round(res.surface_correction, 2)) # [ 5.15 -0.51 -3.86 -3.78 -3.27 -3.08]
+print(round(res.source_depth, 2)) # 4.2 m = 0.7 x draught
res.plot() # RNL, Ls and ΔL vs frequency (needs matplotlib)
```
+Read the magnitudes before going on. A merchant ship lives at a radiated noise
+level of roughly 160-180 dB re 1 µPa·m, against ocean ambient spectrum levels of
+60-100 dB, so a result far outside that range is a units error rather than a
+quiet ship. Above the first Lloyd's-mirror null the correction settles towards
+$-3$ dB and the equivalent monopole level sits just *below* the radiated noise
+level; only at the lowest bands, where $u$ is small, does it go the other way.
+
`hydrophone_depths` gives the three ISO 17208-1 measurement depths from the
15°/30°/45° depression angles, and `source_level_uncertainty` the tabulated
expanded uncertainty (5 dB ≤100 Hz, 3 dB 125 Hz–16 kHz, 4 dB >16 kHz).
diff --git a/site/src/content/docs/underwater/underwater-propagation.mdx b/site/src/content/docs/underwater/underwater-propagation.mdx
index 7f0acc0ee..ed1fd75a1 100644
--- a/site/src/content/docs/underwater/underwater-propagation.mdx
+++ b/site/src/content/docs/underwater/underwater-propagation.mdx
@@ -71,7 +71,7 @@ references:
issue: 4
pages: "1084-1091"
doi: "10.1121/1.1903388"
- note: "The alternative pressure-based sound-speed equation (\"del-grosso\")."
+ note: "The alternative pressure-based sound-speed equation (\"del_grosso\")."
- type: article
authors: ["Mackenzie, K. V."]
year: 1981
@@ -178,9 +178,10 @@ $$
Geometrical spreading is $20 \log_{10} R$ (spherical), $10 \log_{10} R$ (cylindrical) or
spherical up to a transition range $R_0$ and cylindrical beyond it (`"practical"`). The
volume absorption $\alpha$ (dB/km) comes
-from **Francois–Garrison** (1982, default and reference), **Ainslie–McColm**
-(1998) or **Thorp** (1967, frequency-only); the first two agree to within ~10 %
-across 100 Hz–1 MHz.
+from **Francois-Garrison** (`model="francois-garrison"`, 1982, the default and
+the reference), **Ainslie-McColm** (`"ainslie-mccolm"`, 1998) or **Thorp**
+(`"thorp"`, 1967, frequency-only); the first two agree to within ~10 % across
+100 Hz-1 MHz.
@@ -211,7 +212,17 @@ from phonometry import underwater
ranges = np.linspace(10.0, 20_000.0, 400)
tl = underwater.transmission_loss(ranges, 10e3, law="practical", transition_range=1000.0,
temperature=10.0, salinity=35.0, depth=100.0)
-print(tl.absorption_coefficient, tl.tl[-1])
+print(round(tl.absorption_coefficient, 3), round(float(tl.tl[-1]), 1))
+# 0.95 dB/km, 92.0 dB at 20 km
+
+# The same case on the other two absorption models, so the agreement claim
+# above is checkable rather than asserted:
+for model in ("ainslie-mccolm", "thorp"):
+ other = underwater.transmission_loss(ranges, 10e3, law="practical",
+ transition_range=1000.0, temperature=10.0,
+ salinity=35.0, depth=100.0, model=model)
+ print(model, round(other.absorption_coefficient, 3)) # 0.973 / 1.15
+
tl.plot() # TL vs range with the spreading/absorption split (needs matplotlib)
```
@@ -287,9 +298,11 @@ the derivation-consistent form; see
## Speed of sound in sea water
-`sea_water_sound_speed(T, S, depth, model=…)` uses the **UNESCO / Chen–Millero**
-equation (default, in the Wong & Zhu 1995 ITS-90 form), **Del Grosso** (1974),
-**Mackenzie** (1981) or **Medwin** (1975). Depth is converted to pressure with
+`sea_water_sound_speed(T, S, depth, model=…)` uses the **UNESCO / Chen-Millero**
+equation (`model="unesco"`, the default, in the Wong & Zhu 1995 ITS-90 form),
+**Del Grosso** (`"del_grosso"`, note the underscore, unlike the hyphenated
+absorption models above), **Mackenzie** (`"mackenzie"`) or **Medwin**
+(`"medwin"`), all 1974-1981. Depth is converted to pressure with
Leroy & Parthiot (1998). The four agree to within ~2.5 m/s; Mackenzie's canonical
check value is 1550.744 m/s at 25 °C, 35 ppt, 1000 m. Medwin's six-term form is
the coarsest of the family and the one behind the classic rules of thumb
@@ -396,9 +409,33 @@ print(se.figure_of_merit)
se.plot() # signal excess vs transmission loss (needs matplotlib)
```
-Sonar, propagation and ambient levels are in dB re a plane wave of 1 µPa rms
-(spectrum levels). Source levels (below) use the source convention, dB re
-1 µPa²/Hz **at 1 m**.
+The terms, once: $SL$ the source level of the target, $TL$ the one-way
+transmission loss, $NL$ the noise level at the receiver, $DI$ the directivity
+index (array gain), $DT$ the detection threshold and, for the active form, $TS$
+the target strength.
+
+**Two references are in play, and ISO 18405 keeps them apart.** Band and
+broadband levels — the ambient level in a band, $NL$, and $SL$ as used in the
+sonar equation — are re 1 µPa. *Spectral densities*, which is what
+`ocean_ambient_noise` and `ship_source_spectrum` return, are re 1 µPa²/Hz. A
+source level carries an extra squared metre from its reference range, which
+ISO 18405 writes re 1 µPa²m² (equivalently "dB re 1 µPa at 1 m").
+
+**Every term must refer to the same bandwidth.** The sonar equation is a level
+balance, so mixing a broadband source level with an ambient *spectrum* level is
+wrong by $10\log_{10} B$ — tens of decibels at any useful bandwidth, and the
+function cannot catch it because it takes bare decibels. Since the ambient and
+ship-traffic models here are per hertz, the simplest discipline is to work per
+hertz throughout and let the processing bandwidth enter through $DT$; the
+alternative adds $10\log_{10} B$ to a broadband signal *and* to the noise (for
+a tone, to the noise alone, which is the whole of processing gain). The ship
+result carries the decidecade band levels beside its density for exactly this
+conversion.
+
+The figure of merit is quoted below as "dB re m²": Ainslie writes it as a
+maximum *propagation factor* rather than as a loss, and the propagation factor
+has units of m², so the same number that reads as a maximum allowable
+transmission loss in decibels reads as a figure of merit re 1 m².
### Detection range
@@ -575,17 +612,35 @@ plt.show()
```python
+import numpy as np
from phonometry import underwater
ship = underwater.ship_source_spectrum(18.0, 300.0, vessel_class="containership")
ship.plot() # source spectral density vs frequency
print(underwater.VESSEL_CLASSES) # the 13 JOMOPANS-ECHO vessel classes
-# Feed the prediction into the ambient noise as the shipping term:
+# `source_psd` is a SOURCE level at 1 m; the `shipping` term of the ambient sum
+# is a RECEIVED spectrum level at the listening position. Propagation is the
+# step between them - here that one ship, 2 km away.
+tl = np.array([float(underwater.transmission_loss(
+ 2000.0, float(f), law="practical", transition_range=1000.0).tl[0])
+ for f in ship.frequency])
+received = ship.source_psd - tl
noise = underwater.ocean_ambient_noise(ship.frequency, wind_speed_knots=10.0,
- shipping=ship.source_psd)
+ shipping=received)
+print(round(float(np.interp(100.0, ship.frequency, noise.spectrum_level)), 1))
+# 97.6 dB re 1 uPa^2/Hz at 100 Hz, against 72.7 for the wind alone. Passing
+# ship.source_psd straight in would print 160.6: a source level is not a
+# received one, and the error is the whole transmission loss.
```
+Even that is a single-ship estimate. Measured shipping noise at a site is the
+sum over the whole traffic field, so a realistic term integrates many vessels
+over their ranges and classes, which is why `ocean_ambient_noise` leaves the
+shipping spectrum to the caller instead of building one in. One sanity check
+carries most of the value: a composite ambient spectrum above roughly
+120 dB re 1 µPa²/Hz is a units or geometry error, not a noisy sea.
+
Every closed form above stops being enough when refraction and boundaries
decide the answer: a sound-speed minimum that traps energy, surface and
bottom reflections in shallow water, or a detection range that swings with
diff --git a/site/src/content/docs/underwater/underwater-solvers.mdx b/site/src/content/docs/underwater/underwater-solvers.mdx
index a5b39769f..603a9a5fa 100644
--- a/site/src/content/docs/underwater/underwater-solvers.mdx
+++ b/site/src/content/docs/underwater/underwater-solvers.mdx
@@ -166,6 +166,20 @@ print(round(float(modes.wavenumbers[0]), 5)) # 0.20885 computed kr1
print(round(np.sqrt(k**2 - (np.pi / 200.0) ** 2), 5)) # 0.20885 exact
```
+That ideal waveguide plays two roles, and they should not be confused. It is the
+exact oracle the solver is checked against — which is why it is used here — and
+it is also a physically *extreme* bottom: a pressure-release bed reflects with
+unit magnitude and a phase inversion, so it transmits nothing into the sediment
+and absorbs nothing. A modal or PE transmission loss computed over it therefore
+understates the loss of any real seabed, and the gap widens with range because
+it accumulates over bounces. The rigid option is the opposite extreme, offered
+for the same validation reason and not as a sediment model. For a real bottom in
+shallow water, price the seabed with the Weston regimes of
+[Underwater sound propagation](/phonometry/underwater/underwater-propagation/),
+whose critical angle and reflection-loss gradient encode exactly what these
+boundary conditions omit, and read the modal answer as an upper bound on the
+received level.
+
## 3. Ray tracing: travel times and convergence zones
In the high-frequency limit the Helmholtz equation collapses to the eikonal
@@ -268,7 +282,7 @@ source level, levels re 1 µPa). The sound-speed and absorption models named
below are implemented and referenced in
[Underwater sound propagation](/phonometry/underwater/underwater-propagation/).
-**Sound speed.** The three equations agree to within about 1 m/s inside their
+**Sound speed.** The four equations agree to within about 2.5 m/s inside their
common domain, so the choice is about *validity range*, not accuracy. The
default **UNESCO / Chen-Millero** form (as recast by Wong & Zhu 1995) covers
0–40 °C, 0–40 ppt and 0–1000 bar, the widest envelope, and is the
@@ -278,7 +292,11 @@ domain (much of the SOFAR-channel literature uses it). **Mackenzie** (1981)
trades pressure for depth directly (2–30 °C, 25–40 ppt, 0–8000 m), which makes
it the convenient choice when you have an echo-sounder depth rather than a CTD
pressure; the other two convert depth to pressure through Leroy & Parthiot
-(1998) internally.
+(1998) internally. **Medwin** (1975) is a six-term simplification valid to about
+1000 m in shallow, warm water; it is the coarsest of the four and the one behind
+the rules of thumb $\partial c/\partial T \approx 4.6 - 0.110\,T$ m/s per °C and
+$\partial c/\partial z \approx 0.016$ m/s per metre, so keep it for mental
+arithmetic and hand checks, not for a budget.
**Absorption.** **Francois–Garrison** (1982) is the reference and the default:
it carries the boric-acid, magnesium-sulfate and pure-water relaxations with
diff --git a/site/src/content/docs/vibration/human/human-vibration.mdx b/site/src/content/docs/vibration/human/human-vibration.mdx
index e4d31c687..2557c531f 100644
--- a/site/src/content/docs/vibration/human/human-vibration.mdx
+++ b/site/src/content/docs/vibration/human/human-vibration.mdx
@@ -109,11 +109,11 @@ weighting, and `Wh` the hand-arm weighting.
from phonometry import vibration
# The overall weighting response at any frequencies (ISO 8041-1 Formula (5)).
+# 6.3096 Hz is the *true* centre of the nominal 6.3 Hz band, which is where
+# the Annex B tables print their factors.
resp = vibration.frequency_weighting("Wk", [1.0, 6.3096, 20.0])
print(resp.magnitude.round(3)) # [0.482 1.054 0.636] (factors)
print(resp.magnitude_db.round(2)) # [-6.33 0.46 -3.93] (dB)
-
-resp.plot() # the weighting response in dB, as in the figure below (needs matplotlib)
```
The factors reproduce the ISO 8041-1 Annex B design-goal tables to their four
@@ -202,17 +202,26 @@ factors.
import numpy as np
from phonometry import vibration
-# A measured vertical seat spectrum (r.m.s. per one-third octave, m/s^2).
-freqs = np.array([1.0, 2.0, 4.0, 8.0, 16.0, 31.5, 63.0])
-accel = np.array([0.20, 0.45, 0.42, 0.25, 0.12, 0.05, 0.02])
+# A measured vertical seat spectrum (r.m.s. per one-third octave, m/s^2),
+# the same 19 bands the figure below is drawn from.
+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,
+ 12.5, 16.0, 20.0, 25.0, 31.5, 40.0, 63.0, 80.0])
+accel = np.array([0.18, 0.24, 0.33, 0.46, 0.52, 0.55, 0.48, 0.39, 0.31, 0.26,
+ 0.21, 0.17, 0.13, 0.10, 0.078, 0.060, 0.045, 0.028, 0.020])
result = vibration.weighted_acceleration(accel, freqs, "Wk")
-print(round(result.overall, 3)) # 0.555 m/s^2 (a_w)
+print(round(result.overall, 3)) # 1.026 m/s^2 (a_w)
print(result.weighted.round(3)) # W_i * a_i per band
result.plot() # unweighted vs weighted bands, as in the figure below (needs matplotlib)
```
+Those band labels are the nominal ones, for legibility. Passing the true centres
+$10^{n/10}$ Hz (1, 1.259, 1.585, ... 79.433) instead moves $a_w$ from 1.0260 to
+1.0267 m/s², so the caution above is about comparing a *single* $W_i$ against a
+printed table, not about a broadband r.m.s., where the two agree to three
+figures.
+
diff --git a/site/src/content/docs/vibration/human/multiple-shock-vibration.mdx b/site/src/content/docs/vibration/human/multiple-shock-vibration.mdx
index 3b3f8a4cb..7d1454254 100644
--- a/site/src/content/docs/vibration/human/multiple-shock-vibration.mdx
+++ b/site/src/content/docs/vibration/human/multiple-shock-vibration.mdx
@@ -43,7 +43,7 @@ belong to the Annex A finite-element model. In case of doubt the delineation
is quantitative: when the band-limited vertical peak acceleration exceeds
9.81 m/s² (1 g, the free-fall threshold), clause 5 and Annex C apply.
-
+
## 1. Spinal response (clause 5.2)
@@ -95,14 +95,27 @@ The daily dose becomes a daily **compressive stress** $S_d = m_z\,D_{zd}$
(Formula C.1), where $m_z$ (0.029 MPa per m/s² for an 82 kg male, 0.025 for a
64 kg female) converts acceleration to vertebral stress. The stress accumulates
over the exposure years against the ageing spine's reducing ultimate strength
-$S_u = 6.75 - S_{\mathrm{age}}\,(b+i)$ (Formulae C.3/C.4):
+$S_u = 6.75\ \mathrm{MPa} - S_{\mathrm{age}}\,(b+i)$ (Formulae C.3/C.4):
$$
R = \left[\sum_{i=0}^{n-1}
\left(\frac{S_d\,N^{1/6}}{S_{u,i} - S_{\mathrm{stat}}}\right)^{6}\right]^{1/6},
$$
-and a Weibull model gives the probability of lumbar injury (Formula C.5):
+where $b$ is the age at which the exposure started, $n$ the number of exposure
+years, $i$ the year counter $0 \le i \le n-1$ (so $S_{u,i}$ is the ultimate
+strength at age $b+i$), and $N$ the number of exposure days per year.
+$S_{\mathrm{stat}} = m_z \times 9.81\ \mathrm{m/s^2}$ is the static compressive
+stress the spine already carries under gravity — 0.284 MPa for the male $m_z$,
+0.245 MPa for the female one (`vibration.static_stress`) — and
+$S_{\mathrm{age}}$ is the annual loss of ultimate strength, 0.052 MPa/year for
+males and 0.039 MPa/year for females (`vibration.ultimate_strength`, which
+returns 5.71 MPa at age 20 and 4.67 MPa at age 40 for a male). The denominator
+is therefore a *margin*: $R$ grows both because the dose accumulates day after
+day and because that margin shrinks by $S_{\mathrm{age}}$ every year, so the
+same daily dose is more damaging to an older spine.
+
+A Weibull model turns $R$ into the probability of lumbar injury (Formula C.5):
$$
\Pi(R) = 1 - \exp\!\left[-\left(\frac{R}{\alpha}\right)^{\beta}\right].
@@ -133,14 +146,24 @@ az = np.zeros(2560)
az[256::512] = 60.0
result = vibration.multiple_shock_assessment(
az, fs, start_age=20, years=20, days_per_year=120, sex="male",
+ measurement_time=10.0, # t_m: the record is 10 s long
+ exposure_time=4 * 3600.0, # t_d: 4 h a day in this vehicle
)
-print(round(result.acceleration_dose, 2)) # 20.94 m/s2
-print(round(result.risk, 2)) # 0.46
-print(round(result.probability, 2)) # 0.03
+print(round(result.acceleration_dose, 2)) # 20.94 m/s2, over the 10 s record
+print(round(result.daily_dose, 2)) # 70.35 m/s2, Formula 4 scaled to td
+print(round(result.risk, 2)) # 1.53
+print(round(result.probability, 2)) # 0.58
result.plot() # the injury-probability curve with this assessment's R marked (needs matplotlib)
```
+`exposure_time` and `measurement_time` are what implement Formula 4 here.
+Omitted, the measured dose is taken unchanged as the daily dose, which is only
+correct when the record already covers the whole daily exposure: for this 10 s
+record and a 4 h day that shortcut divides the dose by
+$(t_d/t_m)^{1/6} = 3.36$ and reports $R = 0.46$ instead of $1.53$ — a 3 %
+probability of injury where the exposure gives 58 %.
+
@@ -151,19 +174,32 @@ import numpy as np
import matplotlib.pyplot as plt
from phonometry import vibration
-# Left: the seat-to-spine transfer function magnitude.
-f = np.logspace(np.log10(0.5), np.log10(80.0), 400)
-plt.plot(f, np.abs(vibration.seat_to_spine_transfer(f)))
-plt.xscale("log"); plt.show()
+fig, (ax_h, ax_r) = plt.subplots(1, 2, figsize=(12.5, 5.4))
-# Right: the injury-probability curve with this assessment's R marked
-# (az/fs as in the snippet above).
-fs = 256.0
-az = np.zeros(2560)
-az[256::512] = 60.0
-vibration.multiple_shock_assessment(
- az, fs, start_age=20, years=20, days_per_year=120,
-).plot()
+# Left: the seat-to-spine transfer function magnitude (Formula 1).
+f = np.logspace(np.log10(0.5), np.log10(80.0), 400)
+ax_h.plot(f, np.abs(vibration.seat_to_spine_transfer(f)), label="|H(f)|")
+ax_h.set_xscale("log")
+ax_h.set_xlabel("Frequency [Hz]")
+ax_h.set_ylabel("Transmissibility seat -> spine")
+ax_h.legend()
+
+# Right: the Weibull injury probability for both sexes, with the Annex C
+# male example (five 40 m/s2 response peaks a day) marked, which is the R
+# the figure prints - not the R of the 10 s synthetic record above.
+grid = np.linspace(0.0, 3.0, 300)
+for sex in ("male", "female"):
+ ax_r.plot(grid, 100.0 * vibration.injury_probability(grid, sex=sex), label=sex)
+sd = vibration.compression_dose(vibration.dose_from_peaks([40.0] * 5))
+r = vibration.injury_risk(sd, start_age=20, years=20, days_per_year=120)
+for level, r_level in zip((10, 50, 90), (0.72, 1.42, 2.17)): # Table C.2, male
+ ax_r.axhline(level, color="#7f7f7f", linestyle=":", lw=0.8)
+ ax_r.plot([r_level, r_level], [0.0, level], color="#7f7f7f", linestyle=":", lw=0.8)
+ax_r.scatter([r], [100.0 * vibration.injury_probability(r)], marker="*", s=160,
+ label=f"Example R = {r:.2f}")
+ax_r.set_xlabel("Stress variable R")
+ax_r.set_ylabel("Probability of lumbar injury [%]")
+ax_r.legend()
plt.show()
```
@@ -213,7 +249,8 @@ from phonometry import vibration, ReportMetadata
# The Annex C worked example: five 40 m/s2 spinal-response shocks per day,
# 82 kg male, exposed from age 20 for 20 years at 120 days/year. The record is
# rebuilt from those response peaks (the standard states the example in terms
-# of the peaks), so the fiche prints the published Annex C values.
+# of the peaks), so the fiche prints the published Annex C values. The five
+# peaks are the whole day, so td = tm and daily_dose is dz unscaled.
peaks = np.array([40.0] * 5)
dz = vibration.dose_from_peaks(peaks)
sd = vibration.compression_dose(dz)
@@ -229,7 +266,7 @@ result = vibration.MultipleShockResult(
years=20,
days_per_year=120.0,
peaks=peaks,
- risk_thresholds=vibration.RISK_THRESHOLDS_MALE,
+ risk_thresholds=(0.72, 1.42, 2.17), # Table C.2, male: 10 / 50 / 90 % risk
)
result.report(
diff --git a/site/src/content/docs/vibration/machinery/machine-diagnostics.mdx b/site/src/content/docs/vibration/machinery/machine-diagnostics.mdx
index 208b7423c..199087a78 100644
--- a/site/src/content/docs/vibration/machinery/machine-diagnostics.mdx
+++ b/site/src/content/docs/vibration/machinery/machine-diagnostics.mdx
@@ -28,10 +28,11 @@ already provides - the [envelope spectrum and cepstrum](/phonometry/signals/spec
The working view is the two put together: the envelope spectrum of a
band-passed vibration record with the predicted lines drawn on top and named.
-
+
-*The four tall lines land on BPFO and its harmonics; nothing appears on BPFI or
-BSF. That is the diagnosis: a spall on the outer race.*
+*The four tall lines land on BPFO and its harmonics; nothing appears on BPFI,
+on the roller rate BSF or on the 183 Hz BDF where a damaged roller would strike.
+That is the diagnosis: a spall on the outer race.*
Show the code for this figure
@@ -88,7 +89,13 @@ and writing $g = (d/D)\cos\phi$ and $f_s = N/60$:
| `BPFI` | element pass frequency, inner race | $Z(f_s/2)(1 + g)$ | (8.9) |
Three of them carry the diagnosis: `BPFO` for an outer-race defect, `BPFI` for
-an inner-race defect, and `BDF` for a damaged rolling element or cage. Two
+an inner-race defect, and `BDF` for a damaged rolling element or cage. The two
+rolling-element rows are one factor of two apart because they answer different
+questions: `BSF` is how fast a roller turns, `BDF` how often a defect on it
+strikes a race — twice per roller revolution, once against each. Evidence of a
+damaged roller is therefore expected at `BDF` (183.3 Hz for the bearing above),
+usually modulated at the cage rate `FTF`, while the line the figure draws at
+91.7 Hz is the roller's rotational rate `BSF`. Two
identities are worth remembering because they are exact and catch data-entry
errors instantly: $\text{BPFO} + \text{BPFI} = Z f_s$ always, and
$\text{BPFO} = Z \times \text{FTF}$ whenever the outer race is stationary.
@@ -173,8 +180,24 @@ sideband spacing that a broken rotor bar puts around `1x`.
The blade-passing frequency of an impeller with $N$ blades is $f_b = n N f_s$
(Eq. 8.15); a pump's hydraulic pulsations follow the same form with $N$
pumping events per revolution (Eq. 8.18), and a rotary
-positive-displacement blower repeats four times per revolution, so it is
-handled by passing $4 \times \text{r/min}$.
+positive-displacement blower repeats four times per revolution, which is
+handled by passing $4 \times \text{r/min}$ with a single "blade":
+
+```python
+from phonometry import blade_pass_frequencies
+
+# A rotary positive-displacement blower at 1200 r/min: four pulsations per
+# revolution, so the pulsation rate is asked for as 4 x r/min with N = 1.
+res = blade_pass_frequencies(4 * 1200.0, 1, harmonics=3)
+print(round(res["BPF"], 1)) # 80.0 Hz, the pulsation rate
+print(round(res.shaft_rate, 1)) # 80.0 Hz - NOT the shaft rate, which is 20
+```
+
+The trick costs the shaft line: `shaft_rate` comes back at $4 f_s$, so read the
+shaft rate from a separate call at the true speed (or from
+`bearing_fault_frequencies`) before combining families with
+`combine_fault_lines`, or a 4th shaft harmonic will be plotted as if it were
+bearing evidence.
In a **ducted axial fan** the blades also interact with the stator vanes and set
up rotating pressure patterns with $m_L = nN \pm kV$ lobes for $V$ vanes
@@ -187,9 +210,7 @@ count reached from a different harmonic is a different pattern turning at a
different speed.
```python
-from phonometry import blade_pass_frequencies
-
-# Six blades, four vanes, 3500 r/min.
+# Six blades, four vanes, 3500 r/min (blade_pass_frequencies imported above).
res = blade_pass_frequencies(3500.0, 6, harmonics=1, n_vanes=4)
print(round(res["BPF"])) # 350
print(round(res["lobe n=1 m=2"]), round(res["lobe n=1 m=10"])) # 175 35
diff --git a/site/src/content/docs/vibration/structural/junction-transmission.mdx b/site/src/content/docs/vibration/structural/junction-transmission.mdx
index 429228ee5..8fa002150 100644
--- a/site/src/content/docs/vibration/structural/junction-transmission.mdx
+++ b/site/src/content/docs/vibration/structural/junction-transmission.mdx
@@ -250,14 +250,28 @@ from phonometry import junction_transmission, wave_vibration_reduction_index
# 100 mm, plate 2 swept from 50 mm to 400 mm.
h1, cl, rho = 0.1, 3200.0, 2400.0
ratios = np.linspace(0.5, 4.0, 36)
-kij_corner = []
+curves = {"X corner": [], "X straight": [], "T-junction (1) corner": [],
+ "L corner": []}
for ratio in ratios:
h2 = h1 * float(ratio)
- res = junction_transmission("X", h1, cl, rho * h1, h2, cl, rho * h2)
- kij_corner.append(res.corner_reduction_index)
+ res_x = junction_transmission("X", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["X corner"].append(res_x.corner_reduction_index)
+ # Only the corner index is precomputed on the result; the straight path
+ # is the angular average tau13 converted the same way.
+ curves["X straight"].append(float(wave_vibration_reduction_index(
+ res_x.straight_average, res_x.critical_frequency2)))
+ res_t = junction_transmission("T1", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["T-junction (1) corner"].append(res_t.corner_reduction_index)
+ res_l = junction_transmission("L", h1, cl, rho * h1, h2, cl, rho * h2)
+ curves["L corner"].append(res_l.corner_reduction_index)
fig, ax = plt.subplots()
-ax.plot(ratios, kij_corner, label="X corner")
+for label, values in curves.items():
+ ax.plot(ratios, values, "--" if label == "X straight" else "-", label=label)
+# The identical-plate X-junction: Kij = 10 lg 12 + 5 lg(fc2/1000).
+res_eq = junction_transmission("X", h1, cl, rho * h1, h1, cl, rho * h1)
+ax.scatter([1.0], [res_eq.corner_reduction_index], zorder=6,
+ label="identical plates (tau = 1/12)")
ax.set_xlabel("Thickness ratio h2/h1")
ax.set_ylabel("Vibration reduction index Kij [dB]")
ax.set_title("Wave-approach junction Kij (Hopkins Eq. 5.116)")
@@ -270,15 +284,15 @@ plt.show()
## 5. Worked example: feeding Kij into EN 12354
The number this page predicts is exactly what the EN 12354-1 flanking model
-consumes. Take the 100 mm / 200 mm concrete X-junction from the figure at
-the top: its corner path gives $K_{12} = 9.8\ \text{dB}$. Handing that to
+consumes. Take the 100 mm / 200 mm concrete X-junction of section 2's
+$\tau(\theta)$ figure: its corner path gives $K_{12} = 9.8\ \text{dB}$. Handing it to
`flanking_element` in place of a tabulated Annex E value prices the
junction's three flanking paths and their effect on the apparent rating:
```python
from phonometry import building, junction_transmission
-# The 100 mm / 200 mm concrete X-junction of the opening figure:
+# The 100 mm / 200 mm concrete X-junction of the tau(theta) figure:
res = junction_transmission("X", 0.1, 3200.0, 240.0, 0.2, 3200.0, 480.0)
k12 = res.corner_reduction_index # 9.8 dB (corner path)
@@ -451,10 +465,14 @@ method** drives each subsystem in turn while measuring both energies each time.
That gives four equations for $\eta_1$, $\eta_2$, $\eta_{12}$ and $\eta_{21}$
with no prior assumption at all, which `power_injection_matrix` solves band by
band. Reciprocity then becomes a *check* on the measurement rather than an
-input: `modal_density_ratio` compares the measured $\eta_{21}/\eta_{12}$
-against the $n_1/n_2$ computed from the geometry, and a large disagreement
-means the
-subsystem boundaries were drawn in the wrong place.
+input: `PowerInjectionResult.modal_density_ratio` is a property, not a
+function, and it returns only the $n_1/n_2$ *implied* by the measured coupling
+loss factors, $\eta_{21}/\eta_{12}$. Making it a check is the reader's step:
+compare it against the ratio built from the geometry with
+`flat_plate_modal_density` and its siblings, and a large disagreement means the
+subsystem boundaries were drawn in the wrong place. `coupling_strength` is the
+other diagnostic on the same result, and says whether the weak-coupling
+assumption the inversion rests on holds at all.
## See also
diff --git a/site/src/content/docs/vibration/structural/transfer-stiffness.mdx b/site/src/content/docs/vibration/structural/transfer-stiffness.mdx
index 03aeb49b9..c0280af44 100644
--- a/site/src/content/docs/vibration/structural/transfer-stiffness.mdx
+++ b/site/src/content/docs/vibration/structural/transfer-stiffness.mdx
@@ -82,7 +82,7 @@ fig, ax = plt.subplots()
ax.semilogx(f, vibration.transfer_stiffness_level(k_true),
label="true $L_k$ of $k+j\\omega c$")
ax.semilogx(f, vibration.transfer_stiffness_level(k_indirect), "--",
- label="indirect method $-(2\\pi f)^2 m_2 T$")
+ label="indirect method $-(2\\pi f)^2 m_2 T$") # no flange here
ax.axvline(f0, color="0.6", linestyle=":", label="resonance $f_0$")
ax.set(xlabel="Frequency [Hz]", ylabel="Transfer stiffness level $L_k$ [dB re 1 N/m]")
ax.grid(True, which="both", alpha=0.3)
@@ -138,16 +138,25 @@ $$
k_{2,1} = -(2\pi f)^2\,(m_2 + m_f)\,T \qquad (T \ll 1),
$$
-with $m_f$ the mass of the output flange. The approximation is valid well above
-the mass/spring resonance, where $T$ is small.
+with $m_f$ the mass of the output flange, which the `flange_mass=` keyword
+carries (it defaults to zero). It is not a refinement: ISO 10846-3 measures the
+vibration of the mass centre of the *compact body* formed by the blocking mass
+together with the output flange of the test element, so $m_f$ is whatever is
+weighed with it — the flange and any auxiliary fixture that moves as part of the
+test element. Left at zero it reports a stiffness low by $m_2/(m_2 + m_f)$. The
+approximation is valid well above the mass/spring resonance, where $T$ is
+small.
```python
import numpy as np
from phonometry import vibration
-# Indirect method: a 10 kg blocking mass, transmissibility 0.01 at 500 Hz.
-k = vibration.transfer_stiffness_indirect(500.0, 0.01, blocking_mass=10.0)
-print(f"{abs(complex(k)):.3e}") # 9.870e+05 N/m
+# Indirect method: a 10 kg blocking mass, transmissibility 0.01 at 500 Hz,
+# and the 1.2 kg output flange of the test element bolted on top of it.
+k = vibration.transfer_stiffness_indirect(500.0, 0.01, blocking_mass=10.0,
+ flange_mass=1.2)
+print(f"{abs(complex(k)):.3e}") # 1.105e+06 N/m
+# flange_mass defaults to 0, which reports 9.870e+05 N/m: 12 % low here.
# Bundle a swept measurement into a result carrying its level and loss factor:
f = np.logspace(1.5, 3.3, 200)
@@ -273,7 +282,8 @@ res.report(
10846-2 and -3, 3.17) and loss factor (ISO 10846-1, 3.8)
(`transfer_stiffness_level`, `loss_factor`), the ISO 10846-2:2008 direct
method (`transfer_stiffness_direct`), and the ISO 10846-3:2002 indirect
-method of Formula 1 (`transfer_stiffness_indirect`). The blocking-force
+method of Formula 1 (`transfer_stiffness_indirect`, including its
+`flange_mass=` term). The blocking-force
approximation of Equations 6-7 (`blocking_force_ratio`) and the Annex A /
Table A.2 FRF relations (`convert_frf`) are implemented too.
`TransferStiffnessResult` bundles a swept determination, and `.report()`
diff --git a/site/src/data/glossary.mjs b/site/src/data/glossary.mjs
index afdfb190e..9c2ebb350 100644
--- a/site/src/data/glossary.mjs
+++ b/site/src/data/glossary.mjs
@@ -585,6 +585,10 @@ export const glossary = [
{
id: "nr",
symbol: "NR",
+ qualifier: {
+ en: "curve family",
+ es: "familia de curvas",
+ },
unit: {
en: "dB (index)",
es: "dB (índice)",
@@ -595,8 +599,8 @@ export const glossary = [
},
guide: "buildings/rooms/room-noise",
definition: {
- en: "Noise rating, the European counterpart curve family of NC. Discussed for comparison and deliberately not implemented.",
- es: "Noise Rating, la familia de curvas europea equivalente a NC. Se comenta a efectos de comparación y no se implementa deliberadamente.",
+ en: "Noise rating, the European counterpart curve family of NC. Discussed for comparison and deliberately not implemented. Not the NR of the noise-control guides, which is a level drop.",
+ es: "Noise Rating, la familia de curvas europea equivalente a NC. Se comenta a efectos de comparación y no se implementa deliberadamente. No es el NR de las guías de control de ruido, que es una caída de nivel.",
},
},
],
@@ -723,6 +727,24 @@ export const glossary = [
es: "Aislamiento acústico",
},
terms: [
+ {
+ id: "nr-2",
+ symbol: "NR",
+ qualifier: {
+ en: "level drop",
+ es: "caída de nivel",
+ },
+ unit: "dB",
+ standard: {
+ en: "Norton and Karczub (2003), Equation (4.101)",
+ es: "Norton y Karczub (2003), ecuación (4.101)",
+ },
+ guide: "devices/noise-control/room-to-room",
+ definition: {
+ en: "Noise reduction: the sound pressure level in the source room minus the level in the receiving room, $L_{p1} - L_{p2}$. It is not the transmission loss of the partition: the two differ by a term set by the partition area against the receiving room's absorption, so a small partition into a well-absorbing room delivers more noise reduction than its transmission loss, and a large one into a hard room delivers less.",
+ es: "Reducción de ruido: el nivel de presión acústica del recinto emisor menos el del receptor, $L_{p1} - L_{p2}$. No es la pérdida por transmisión del elemento separador: ambas difieren en un término fijado por la superficie del separador frente a la absorción del recinto receptor, de modo que un separador pequeño hacia un recinto muy absorbente ofrece más reducción de ruido que su pérdida por transmisión, y uno grande hacia un recinto reverberante ofrece menos.",
+ },
+ },
{
id: "d-2",
symbol: "$D$",
diff --git a/site/src/data/home.ts b/site/src/data/home.ts
index d1255d095..320d265ee 100644
--- a/site/src/data/home.ts
+++ b/site/src/data/home.ts
@@ -51,6 +51,12 @@ export interface HomeContent {
proof: {
title: string;
lead: string;
+ /**
+ * The banner clip that opens the block. Optional while the Spanish
+ * strings are still to be written: a locale without it simply renders
+ * the block without the clip.
+ */
+ banner?: { title: string; description: string; caption: string };
spectrum: { title: string; note: string; code: string; alt: string; caption: string };
fiche: { title: string; note: string; code: string; caption: string; description: string; linkTitle: string };
};
@@ -65,14 +71,20 @@ export interface HomeContent {
*/
const DOI = '10.5281/zenodo.21215280';
+// `octave_filter` is the one-shot function and returns a pair of arrays, so the
+// "draws itself" claim has to be carried by a result object: the PSD estimate
+// returns a SpectralDensityResult and `.plot()` on it is the whole figure call.
const SPECTRUM_CODE = `import numpy as np
-from phonometry import filters
+from phonometry import filters, signals
fs = 48_000
t = np.linspace(0, 1, fs, endpoint=False)
signal = np.sin(2 * np.pi * 100 * t) + np.sin(2 * np.pi * 1000 * t)
-spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)`;
+spl, freq = filters.octave_filter(signal, fs=fs, fraction=3)
+
+psd = signals.power_spectral_density(signal, fs=fs)
+ax = psd.plot() # the result draws itself`;
// The call that renders the committed fiche shown beside it
// (scripts/generate_reports.py), with the metadata block cut to the four
@@ -134,13 +146,20 @@ export const en: HomeContent = {
},
proof: {
title: 'What it looks like in use',
- lead: 'Two things the library does that are hard to claim and easy to show: the result of an analysis draws itself, and where a standard prescribes a reporting layout, the same result renders that layout as a PDF.',
+ lead: 'Three things the library does that are hard to claim and easy to show: it computes wave fields and renders them, the result of an analysis draws itself, and where a standard prescribes a reporting layout, the same result renders that layout as a PDF.',
+ banner: {
+ title: 'A wavefront through a hall of columns (2D FDTD)',
+ description:
+ 'An 800 Hz plane wavefront sweeps a 4 m rigid-walled hall filled with a staggered colonnade of rigid columns 10 to 17 cm across, simulated at 2.5 mm; every column diffracts the front and sheds a scattered wavelet, and the wavelets interfere until the whole hall is filled with structured energy that then drains through the absorbing ends.',
+ caption:
+ 'An 800 Hz front through a hall of rigid columns, 2D FDTD at 2.5 mm: every column diffracts the front until the scattered wavelets fill the hall.',
+ },
spectrum: {
title: 'An analysis, and the figure it draws',
- note: 'One-third-octave band levels of a two-tone signal, per IEC 61260-1 band edges, with the raw power spectral density behind them. The figure below is the one committed to the documentation, not a mock-up.',
+ note: 'One-third-octave band levels per the IEC 61260-1 band edges, and the power spectral density of the same record — which is a result object, so one call draws it. The figure below is committed to the documentation, not a mock-up; it is drawn from a six-tone signal rather than the two-tone one in the snippet, so that the band structure is worth looking at.',
code: SPECTRUM_CODE,
- alt: 'One-third-octave spectrum of a two-tone signal, with the raw power spectral density in the background',
- caption: 'From the Getting Started guide: 33 bands from 12.6 Hz to 20 kHz, peaking at 100 Hz and 1 kHz.',
+ alt: 'One-third-octave spectrum of a six-tone signal, with the raw power spectral density in the background',
+ caption: 'From the Getting Started guide: 33 bands from 12.6 Hz to 20 kHz, with tones at 20, 100, 500, 2000, 4000 and 15 000 Hz standing out of the spectrum behind them.',
},
fiche: {
title: 'A rating, and the fiche it renders',
diff --git a/src/phonometry/building/measurement/structure_borne_power.py b/src/phonometry/building/measurement/structure_borne_power.py
index c931410e0..29bc9342e 100644
--- a/src/phonometry/building/measurement/structure_borne_power.py
+++ b/src/phonometry/building/measurement/structure_borne_power.py
@@ -19,8 +19,10 @@
L_{Ws} = 10 \log_{10}\frac{2 \pi f \eta\, m S}{f_0 m_0 S_0} + L_v - 60
\qquad \text{dB re 1 pW}
-with the references :math:`f_0 = 1` Hz, :math:`m_0 = 1` kg,
-:math:`S_0 = 1` m²; the fixed ``-60 dB`` term is
+with the references :math:`f_0 = 1` Hz, :math:`m_0 = 1` kg (printed as 1 kg;
+the quantity it normalises is a mass per unit area, so the reference is
+1 kg/m² -- see ``docs/ERRATA.md``), :math:`S_0 = 1` m²;
+the fixed ``-60 dB`` term is
:math:`10 \log_{10}(v_0^2 / P_0)` for the EN 15657 velocity reference
:math:`v_0 = 10^{-9}` m/s and :math:`P_0 = 1` pW. The spatial mean velocity
level is the energetic average over the ``N`` plate positions (Formula 12):