← [Documentation index](README.md)

# Laboratory Insulation Measurement

To rate a building element on its own (a wall type, a floating floor, a
window) you take it to a qualified laboratory, where suppressed flanking makes
the direct transmission the whole story. This page covers the laboratory
chain: the ISO 10140 sound reduction index and normalized impact level, the
sound-intensity alternative of ISO 15186, the small-mock-up floor-covering
improvement of ISO 16251-1 and the flanking-transmission measurement of
ISO 10848. Field measurement and ratings live in
[Field Insulation Measurement and Ratings](insulation-field.md), and the
prediction that consumes these laboratory ratings in
[Predicting Sound Insulation (EN 12354)](insulation-prediction.md).

## Laboratory measurement (ISO 10140)

An [ISO 16283 field measurement](insulation-field.md) yields the primed
quantities ($R'$, $L'_n$): the number a real building achieves, flanking
transmission and all. To rate an
element on its own (a wall type, a floating floor, a window), you take it to a
qualified **laboratory** (ISO 10140), where suppressed flanking makes the
*direct* transmission the whole story. The formulas lose their primes: the
**sound reduction index** $R$ (not $R'$) and the **normalized impact level**
$L_n$ (not $L'_n$), with the receiving room's absorption area $A = 0.16\ V/T$
now a known property of the facility:

$$
R = L_1 - L_2 + 10 \log_{10}\frac{S}{A}, \qquad
L_n = L_i + 10 \log_{10}\frac{A}{A_0}, \quad A_0 = 10\ \text{m}^2.
$$

| | Field (ISO 16283) | Laboratory (ISO 10140) |
| :--- | :--- | :--- |
| Airborne element index | $R'$ apparent (with flanking) | $R$ direct (flanking suppressed) |
| Airborne room pair | $D_{nT}$, $D_n$ (no prime: room quantities) | — |
| Impact | $L'_n$, $L'_{nT}$ apparent | $L_n$ direct |
| Single number | $R'_w$, $D_{nT,w}$, $L'_{n,w}$, $L'_{nT,w}$ | $R_w$, $L_{n,w}$ |
| Absorption area | measured in the room | property of the facility |

The apostrophe is the flanking marker of building acoustics, and it travels
with the quantity into its single number: $R_w$ rates a laboratory spectrum,
$R'_w$ a field one. The standardized and normalized level differences
$D_{nT}$ and $D_n$ carry no prime because they describe the room pair rather
than an element, so there is no flanking-free counterpart to mark. In a
well-built construction $R'_w$ lands a few dB below the laboratory $R_w$ of
the same partition; a much larger gap says flanking dominates, and the
[EN 12354 model](insulation-prediction.md) tells you which path carries it.

The single-number ratings reuse the very same ISO 717-1/2 engines
(`weighted_rating`, `weighted_impact_rating`): an $R$ spectrum rates to $R_w$
exactly as an $R'$ spectrum rated to $R'_w$. Before forming the index the
receiving-room levels must be **corrected for background noise** (Clause 4.3):
the energy subtraction $10 \log_{10}(10^{L_{sb}/10} - 10^{L_b/10})$ applies for a
6–15 dB signal-to-background margin, a fixed 1.3 dB correction (the *limit of
measurement*) at or below 6 dB, and no correction at or above 15 dB.

```python
import numpy as np
from phonometry import building

# Source/receiving levels and receiving-room T over the 16 one-third-octave
# bands; S is the free test-opening area, V the receiving-room volume.
l1 = np.full(16, 80.0)
l2 = np.full(16, 40.0)
t2 = np.full(16, 0.5)
lab = building.lab_airborne_insulation(l1, l2, t2, area=10.0, volume=50.0)
print(round(float(lab.r[0]), 1))              # 38.0  R = L1 - L2 + 10 lg(S/A)
print(round(float(lab.absorption[0]), 1))     # 16.0  A = 0.16 V / T (m^2)
print(lab.rating.rating, lab.rating.c, lab.rating.ctr)   # 38 0 0  ->  Rw(C;Ctr)

# Impact: the tapping-machine level Li normalized to A0 = 10 m^2 gives Ln
li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1,
               73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2])
imp = building.lab_impact_insulation(li, t2, volume=50.0)
print(round(float(imp.l_n[0]), 1))            # 64.1  Ln = Li + 10 lg(A/A0)
print(imp.rating.rating, imp.rating.ci)       # 81 -11  ->  Ln,w(CI)

# Background correction: margins 6 / 1 / 20 dB -> capped / capped / unchanged
corrected = building.background_correction([30.0, 33.0, 50.0], [24.0, 32.0, 30.0])
print(np.round(corrected, 1))                 # [28.7 31.7 50.0]  (1.3 dB cap twice)

lab.rating.plot()   # measured R vs shifted ISO 717-1 reference (needs matplotlib)
```

A margin at or below 6 dB emits a `LabInsulationWarning` and flags the band as
the limit of measurement; catch it with `warnings.simplefilter("error",
LabInsulationWarning)`. The automatic rating is formed only when exactly 16
one-third-octave or 5 octave values are supplied (`rating` is `None` otherwise).

### `lab_airborne_insulation()` / `lab_impact_insulation()` parameters

| Parameter | Type | Units | Range / default | Notes |
| :--- | :--- | :--- | :--- | :--- |
| `l1` / `l2` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source / receiving levels (airborne) |
| `li` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Impact SPL from the tapping machine (impact) |
| `t2` | 1D array | s | > 0, one per band | Receiving-room reverberation time |
| `area` | float | m² | > 0 | Free test-opening area `S` (airborne only) |
| `volume` | float | m³ | > 0 | Receiving-room volume `V` |

`lab_airborne_insulation()` returns a `LabAirborneInsulationResult` (`r`,
`absorption`, `rating`); `lab_impact_insulation()` a
`LabImpactInsulationResult` (`l_n`, `absorption`, `rating`);
`background_correction(signal_and_background, background)` returns the corrected
levels directly.

### ISO 10140 laboratory test report (`.report()`)

Both laboratory results write the one-page ISO 10140 test report directly, laid
out like the accredited laboratory reports rated per ISO 717.
`LabAirborneInsulationResult.report()` renders the sound reduction index *R*
fiche (ISO 10140-2:2010) and `LabImpactInsulationResult.report()` the
normalized impact sound pressure level *Ln* fiche (ISO 10140-3:2010). Each
fiche names the laboratory standard in its basis line, evaluates the
ISO 717-1 / ISO 717-2 single-number rating (16 one-third-octave bands from
100 Hz to 3150 Hz, or the 5 octave bands), states the quantity to one decimal
place both in tabular form and as a curve against the shifted reference curve,
boxes the laboratory rating (`Rw (C; Ctr)` or `Ln,w (CI)`) and prints the
statement that the evaluation is based on laboratory measurement results
obtained by a precision method. Because a qualified suite suppresses flanking
transmission, the reported quantity is the *direct* *R* / *Ln*, not the field
*R'* / *L'n*.

`verbose=True` annexes the per-band equivalent sound absorption area
*A* = 0,16 *V* / *T* (ISO 10140-4:2010) beside the reported quantity, the
normalization datum the laboratory report carries. Metadata (client, specimen,
mounting, room volumes, climatic conditions), the requirement verdict (airborne
passes at or above it, impact at or below it), `language="es"` and the
`phonometry[report]` extra behave exactly as in the ISO 717 and ISO 16283
fiches.

```python
import numpy as np
from phonometry import building, ReportMetadata

# Laboratory airborne: source/receiving levels and T per one-third-octave band
l1 = np.full(16, 90.0)
r = np.array([20.4, 16.3, 17.7, 22.6, 22.4, 22.7, 24.8, 26.6,
              28.0, 30.5, 31.8, 32.5, 33.4, 33.0, 31.0, 25.5])
lab = building.lab_airborne_insulation(
    l1, l1 - r, np.full(16, 0.8), area=10.0, volume=50.0
)
metadata = ReportMetadata(
    specimen="100 mm autoclaved aerated concrete block wall",
    client="Example client",
    area=10.0, mass_per_area=75.0,
    source_volume=53.0, receiving_volume=50.0,
    test_room="Transmission suite (example)",
    mounting="Type A mounting, mortar-bedded perimeter (ISO 10140-1)",
    measurement_standard="ISO 10140-2",
    laboratory="Phonometry Reference Laboratory",
    report_id="PHN-2026-0143",
    requirement=30.0,               # Rw >= 30 dB -> PASS/FAIL row
)
lab.report("Rw_lab.pdf", metadata=metadata)            # Rw (C; Ctr)
lab.report("Rw_lab_chain.pdf", metadata=metadata,
           verbose=True)                               # f | A | R

# Laboratory impact: tapping-machine levels in the receiving room
li = np.array([62.1, 63.2, 63.5, 66.2, 68.5, 70.0, 71.7, 73.1,
               73.8, 73.5, 73.8, 73.3, 73.1, 73.0, 72.4, 71.2])
imp = building.lab_impact_insulation(li, np.full(16, 0.8), volume=50.0)
imp.report("Lnw_lab.pdf",
           metadata=ReportMetadata(requirement=80.0))  # Ln,w (CI)
```

Rendered examples of both laboratory fiches, regenerated with `make reports`,
are kept in the repository. Click either preview to open the PDF:

[![Laboratory airborne ISO 10140-2 example report: metadata header, one-third-octave R table beside the measured-versus-shifted-reference curve, boxed Rw (C; Ctr), the precision-method statement and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10140_airborne_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10140_airborne_example.pdf)

*Laboratory airborne fiche (`LabAirborneInsulationResult.report`), Rw (C; Ctr).*

[![Laboratory impact ISO 10140-3 example report: the same laboratory layout for the normalized impact level Ln with the 500 Hz read-off, boxed Ln,w (CI), the precision-method statement and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10140_impact_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10140_impact_example.pdf)

*Laboratory impact fiche (`LabImpactInsulationResult.report`), Ln,w (CI).*

## Sound insulation by intensity (ISO 15186)

The ISO 10140 laboratory method above reads the transmitted power *indirectly*, from the
receiving-room level and its absorption area; this breaks down when flanking
paths leak power the room integrates in anyway. The **sound-intensity** method
(ISO 15186) sidesteps that: an intensity probe scans a measurement surface that
encloses the specimen and measures the radiated power *directly*, so only the
element under test contributes. It is the tool of choice when flanking is high
(ISO 15186-1:2000, Clause 1). From the source-room level $L_{p1}$ and the
average normal intensity level $L_{In}$ over the surface (area $S_m$), for a
specimen of area $S$,

$$
R_I = L_{p1} - 6 - \left[ L_{In} + 10 \log_{10}\frac{S_m}{S} \right],
$$

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
elements the **element normalized level difference** replaces $10\lg(S_m/S)$
with $10\lg(S_m/A_0) + 10\lg N$ ($A_0 = 10\ \text{m}^2$, $N$ element units).

```python
import numpy as np
from phonometry import building

# Source-room level Lp1 and the average normal intensity level LIn over the
# measurement surface (Sm), for a specimen of area S; 16 one-third-octave bands.
lp1 = np.full(16, 85.0)
l_in = np.full(16, 40.0)
freqs = [100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
         1000, 1250, 1600, 2000, 2500, 3150]   # nominal 1/3-octave centres
kc = building.adaptation_term_kc(freqs)                  # Annex B (B.2)
res = building.intensity_sound_reduction(lp1, l_in, measurement_area=12.0, area=10.0, kc=kc)
print(round(float(res.r_i[0]), 2))          # 38.21  RI = Lp1 - 6 - [LIn + 10 lg(Sm/S)]
print(round(float(res.r_i_modified[0]), 2)) # 40.29  RI,M = RI + Kc
print(res.rating.rating)                     # 38  ->  RI,w (ISO 717-1 engine)

# Qualify the measurement surface: FpI = Lp - LIn must stay < 10 dB (< 6 dB when
# the receiving side is absorbing); the probe's residual index must exceed FpI+10.
fpi = building.surface_pressure_intensity_indicator(np.full(16, 46.0), l_in)
print(round(float(fpi[0]), 1))               # 6.0

res.plot()   # measured RI vs shifted ISO 717-1 reference (needs matplotlib)
```

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_insulation_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/intensity_insulation.svg" alt="Intensity sound reduction index RI and the Kc-modified index RI,M across the one-third-octave bands, with the Annex B adaptation lift shaded between the two curves" width="80%"></picture>

*The modified index $R_{I,M} = R_I + K_c$ lifts $R_I$ (most at the low bands,
where $K_c$ is largest), so an intensity measurement reproduces the ISO 10140-2
pressure result. The automatic rating is formed only for exactly 16
one-third-octave or 5 octave values (`rating`/`rating_modified` are `None`
otherwise). Subareas scanned separately are combined first with
`combine_subareas` (Formulas (11)-(12)); a subarea whose net energy flows back
towards the specimen enters with a negative area, applying the minus-sign rule
of Clause 6.4.6 while $S_m$ keeps the unsigned area sum.*

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

```python
import matplotlib.pyplot as plt
import numpy as np
from phonometry import building

# A light wall: source-room SPL Lp1 = 85 dB and the measured normal intensity
# level LIn over the Sm = 12 m2 surface, 16 one-third-octave bands.
freqs = [100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
         1000, 1250, 1600, 2000, 2500, 3150]
l_in = np.array([57.8, 61.9, 60.5, 55.6, 55.8, 55.5, 53.4, 51.6,
                 50.2, 47.7, 46.4, 45.7, 44.8, 45.2, 47.2, 52.7])
kc = building.adaptation_term_kc(freqs)           # Annex B adaptation term
res = building.intensity_sound_reduction(np.full(16, 85.0), l_in,
                                         measurement_area=12.0, area=10.0,
                                         kc=kc)

x = np.arange(len(freqs))
fig, ax = plt.subplots()
ax.fill_between(x, res.r_i, res.r_i_modified, alpha=0.2, label="Kc adaptation")
ax.plot(x, res.r_i, "-o", label="RI (intensity)")
ax.plot(x, res.r_i_modified, "--s", label="RI,M = RI + Kc")
ax.set_xticks(x, [str(f) for f in freqs], rotation=45)
ax.set(xlabel="Frequency [Hz]", ylabel="Sound reduction index [dB]",
       title=f"RI,w = {res.rating.rating} dB, RI,M,w = {res.rating_modified.rating} dB")
ax.legend()
plt.show()
```

</details>

### `intensity_sound_reduction()` / `adaptation_term_kc()` parameters

| Parameter | Type | Units | Range / default | Notes |
| :--- | :--- | :--- | :--- | :--- |
| `lp1` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Source-room sound pressure level |
| `l_in` | 1D or 2D array | dB | one/band, or `(positions, bands)` | Normal intensity level over the surface |
| `measurement_area` | float | m² | > 0 | Measurement-surface area `Sm` |
| `area` | float | m² | > 0 | Specimen area `S` |
| `kc` | 1D array | dB | one per band / `None` | Adaptation term for the modified index |
| `freq` | 1D array | Hz | > 0 | Midband frequencies (`adaptation_term_kc`) |
| `boundary_area` / `volume` | float | m² / m³ | > 0, both or neither | Room `Sb2` / `V2` for Formula (B.1) |

`intensity_sound_reduction()` returns an `IntensityReductionResult` (`r_i`,
`r_i_modified`, `rating`, `rating_modified`);
`intensity_element_normalized_difference()` an
`IntensityElementNormalizedResult` (`d_i_n_e`, `rating`);
`surface_pressure_intensity_indicator()` and `combine_subareas()` return arrays.

### ISO 15186-1 intensity test report (`.report()`)

`IntensityReductionResult.report()` writes the one-page ISO 15186-1:2000 test
report of the intensity sound reduction index *R*<sub>I</sub>, reusing the same
accredited two-panel layout as the ISO 10140 and ISO 16283 fiches. Because
*R*<sub>I</sub> is an ordinary sound reduction index, its single-number rating
*R*<sub>I,w</sub> is the ISO 717-1 airborne rating evaluated on the intensity
spectrum: the fiche names ISO 15186-1 in its basis line, tabulates
*R*<sub>I</sub> to one decimal place beside the measured-versus-shifted-reference
curve, boxes `RI,w (C; Ctr)` and prints the statement that the transmitted
sound power was measured directly over the measurement surface. `verbose=True`
annexes the *K*<sub>c</sub>-modified index *R*<sub>I,M</sub> (Formula (9))
beside *R*<sub>I</sub> when an adaptation term was supplied.

The applicable `ReportMetadata` fields describe the intensity measurement:
`specimen` (the tested element), `area` (specimen area *S*), `client`,
`manufacturer`, `test_room`, `laboratory`, `operator`, `report_id` and
`test_date`, plus the room/climate fields shared with the other insulation
fiches. There is no dedicated field for the measurement-surface geometry or the
scanning-versus-discrete-point acquisition method; record those in `notes` and
name the standard in `measurement_standard` (`"ISO 15186-1"`). The requirement
verdict, `language="es"` and the `phonometry[report]` extra behave exactly as
in the sibling fiches.

```python
import numpy as np
from phonometry import building, ReportMetadata

freqs = np.array([100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
                  1000, 1250, 1600, 2000, 2500, 3150], dtype=float)
lp1, sm, s = 85.0, 12.0, 10.0
l_in = np.array([57.8, 61.9, 60.5, 55.6, 55.8, 55.5, 53.4, 51.6,
                 50.2, 47.7, 46.4, 45.7, 44.8, 45.2, 47.2, 52.7])
kc = building.adaptation_term_kc(freqs)                 # Annex B, Formula (B.2)
res = building.intensity_sound_reduction(
    np.full(16, lp1), l_in, measurement_area=sm, area=s, kc=kc
)
metadata = ReportMetadata(
    specimen="100 mm autoclaved aerated concrete block wall",
    area=10.0, measurement_standard="ISO 15186-1",
    test_room="Transmission suite (example)",
    laboratory="Phonometry Reference Laboratory",
    report_id="PHN-2026-0150",
    requirement=30.0,                                   # RI,w >= 30 dB -> PASS
)
res.report("RIw.pdf", metadata=metadata)                # RI,w (C; Ctr)
res.report("RIw_kc.pdf", metadata=metadata, verbose=True)  # f | RI | RI,M
```

The example fiche is regenerated with `make reports` and kept in the
repository. Click the preview to open the PDF:

[![Intensity ISO 15186-1 example report: metadata header, one-third-octave RI table beside the measured-versus-shifted-reference curve, boxed RI,w (C; Ctr), the intensity-method statement and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso15186_intensity_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso15186_intensity_example.pdf)

*Intensity fiche (`IntensityReductionResult.report`), RI,w (C; Ctr).*

For a **small building element** (a ventilator, a socket, a small window) the
intensity method reports the element-normalized level difference
*D*<sub>I,n,e</sub> (Formula (8)) instead, normalized to the reference
absorption area *A*<sub>0</sub> = 10 m<sup>2</sup>.
`IntensityElementNormalizedResult.report()` writes the same one-page fiche
through the shared renderer, boxing `DI,n,e,w (C; Ctr)` rated per ISO 717-1;
`verbose=True` shows the ISO 717 evaluation per band and a `requirement` adds a
PASS/FAIL verdict (the element insulation passes at or above the target).

```python
import numpy as np
from phonometry import building, ReportMetadata

lp1, sm, n = 85.0, 12.0, 1                              # source SPL, surface, units
l_in = np.array([57.9, 62.0, 60.6, 55.7, 55.9, 55.6, 53.5, 51.7,
                 50.3, 47.8, 46.5, 45.8, 44.9, 45.3, 47.3, 52.8])
res = building.intensity_element_normalized_difference(
    np.full(16, lp1), l_in, measurement_area=sm, n=n
)
metadata = ReportMetadata(
    specimen="Trickle ventilator in a 100 mm masonry wall",
    measurement_standard="ISO 15186-1",
    laboratory="Phonometry Reference Laboratory",
    report_id="PHN-2026-0151",
    requirement=30.0,                                   # DI,n,e,w >= 30 dB -> PASS
)
res.report("DIne.pdf", metadata=metadata)               # DI,n,e,w (C; Ctr)
```

[![Intensity ISO 15186-1 element example report: metadata header, one-third-octave DI,n,e table beside the measured-versus-shifted-reference curve, boxed DI,n,e,w (C; Ctr), the intensity-method statement and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso15186_element_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso15186_element_example.pdf)

*Element intensity fiche (`IntensityElementNormalizedResult.report`), DI,n,e,w (C; Ctr).*

## Floor-covering impact improvement (ISO 16251-1)

ISO 16251-1:2014 is a laboratory method for the **improvement of impact sound
insulation** $\Delta L$ of a soft, locally-reacting floor covering (carpet, PVC,
linoleum). The two ISO 10140 rooms are replaced by a small softly-supported
concrete plate; a standard tapping machine excites it and the structure-borne
**acceleration level** on the underside is measured with and without the
covering. For locally-reacting coverings that acceleration-level difference
equals the ISO 10140 impact sound reduction.

**Acceleration level (Formula (1)).** $L_a = 10\lg(\langle a^2\rangle / a_0^2)$ dB,
reference $a_0 = 10^{-6}\ \text{m/s}^2$. **Background correction (Formula (2))**
follows the ISO 10140 three-branch rule (unchanged ≥ 15 dB; energy subtraction
for 6 ≤ margin < 15 dB; the 1.3 dB limit below 6 dB, flagged as $> \Delta L$).
The improvement is the position-averaged difference
$\Delta L = L_0 - L_1$ (Formulae (3)/(4)); octaves follow
$\Delta L_\text{oct} = -10\lg[\tfrac{1}{3}\sum 10^{-\Delta L_n/10}]$ (Formula (5)).

**Weighted improvement.** $\Delta L_w$ is the ISO 717-2 weighted reduction: the
improvement is applied to the heavyweight **reference floor** $L_{n,r,0}$
(ISO 717-2 Table 4), $L_{n,r} = L_{n,r,0} - \Delta L$, and
$\Delta L_w = 78 - L_{n,r,w}$, computed by `weighted_impact_improvement()`, which
reuses the verified ISO 717-2 rating engine. A clause 6.3 measurement spans 18
bands (100–5000 Hz, optionally extended to 50 Hz); the rating is formed on the
100–3150 Hz sub-range of whatever spectrum contains it. The statement of
results (clause 8 e)) also carries the spectrum adaptation term
$C_{I,\Delta} = C_{I,r,0} - C_{I,r}$ (ISO 717-2:2020 Formula (A.4)), exposed as
`ci_delta` on the result and standalone as
`impact_improvement_adaptation_term()`.

The worked example below is a real measurement: the improvement of a textile
carpet on the CSTB heavyweight mock-up, digitized from Figure 4 of Foret,
Chéné and Guigou-Carter, "A comparison of the reduction of transmitted impact
noise by floor coverings measured using ISO 140-8 and ISO/CD 16251-1" (Forum
Acusticum 2011, Aalborg). Its published ISO 16251-1 weighted improvement is
$\Delta L_w = 29$ dB, reproduced exactly by the rating engine.

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/floor_covering_improvement_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/floor_covering_improvement.svg" alt="ISO 16251-1 floor-covering impact sound improvement: the improvement delta-L of a real textile carpet rising with frequency across one-third-octave bands from 100 Hz to 3150 Hz, with the shaded improvement area and the weighted single-number delta-Lw annotated" width="80%"></picture>

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

```python
import matplotlib.pyplot as plt
import numpy as np
from phonometry import building

freqs = [100, 125, 160, 200, 250, 315, 400, 500,
         630, 800, 1000, 1250, 1600, 2000, 2500, 3150]
bare = np.full(16, 78.0)                       # bare-plate acceleration level
# A real textile carpet measured on the CSTB mock-up (Foret et al. 2011, Fig. 4).
covering = bare - np.array([5, 8, 10, 14, 18, 23, 30, 31,
                            39, 49, 53, 57, 60, 67, 68, 71])
res = building.impact_improvement(bare, covering, freqs)
print(res.delta_lw)   # weighted improvement delta-Lw = 29 dB (ISO 717-2)
res.plot()
plt.show()
```

</details>

```python
from phonometry import building

# delta-Lw straight from an improvement spectrum (16 one-third-octave bands):
delta_l = [5, 8, 10, 14, 18, 23, 30, 31, 39, 49, 53, 57, 60, 67, 68, 71]
print(building.weighted_impact_improvement(delta_l))    # 29 dB (carpet)

# From the measured bare/covered acceleration levels, with a background trace:
freqs = [100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
         1000, 1250, 1600, 2000, 2500, 3150]
bare_levels = [72, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80]
covered_levels = [b - d for b, d in zip(bare_levels, delta_l)]
bg = [40.0] * 16
res = building.impact_improvement(bare_levels, covered_levels, freqs, background=bg)
res.improvement       # delta-L per band
res.delta_lw          # weighted single number (rated on the 100-3150 Hz sub-range)
res.ci_delta          # spectrum adaptation term CI,delta (Formula (A.4))
res.limited           # bands at the 1.3 dB limit of measurement (> delta-L)
res.octave_bands()    # (octave freqs, delta-L_oct) via Formula (5)
```

### ISO 16251-1 impact-improvement report (`.report()`)

`FloorCoveringImprovementResult.report()` writes a one-page accredited
impact-improvement fiche: the ISO 16251-1 basis line, a metadata header, the
per-band table (frequency and *delta-L*, bands at the 1.3 dB limit prefixed
`>`) beside the *delta-L(f)* improvement curve, the boxed single-number
*delta-Lw (CI,delta)* (the ISO 16251-1 Clause 8 e) statement of results, rated
per ISO 717-2) and a footer. The applicable `ReportMetadata` fields are
`specimen` (the floor covering under test), `client`, `manufacturer`,
`mounting`, `mass_per_area`, `test_room`, `test_date`, `temperature`,
`pressure`, `measurement_standard`, `laboratory`, `operator`, `report_id`,
`notes` and `requirement` (a higher weighted improvement is better, so the
verdict passes at or above it). The bare reference floor is the standardised
heavyweight floor of ISO 717-2:2020 Table 4, fixed by the standard.
`verbose=True` adds the reference-floor-with-covering column
*Ln,r = Ln,r,0 - delta-L*, the derivation basis of *delta-Lw*.

```python
from phonometry import building, ReportMetadata

freqs = [100, 125, 160, 200, 250, 315, 400, 500,
         630, 800, 1000, 1250, 1600, 2000, 2500, 3150]
delta_l = [5, 8, 10, 14, 18, 23, 30, 31, 39, 49, 53, 57, 60, 67, 68, 71]
bare = [78.0] * 16
res = building.impact_improvement(bare, [b - d for b, d in zip(bare, delta_l)], freqs)
res.report("dLw.pdf",
           metadata=ReportMetadata(
               specimen="Textile floor covering (carpet), laid loose",
               measurement_standard="ISO 16251-1",
               requirement=20.0))  # delta-Lw (CI,delta) = 29 (-13) dB
```

A rendered example fiche, regenerated with `make reports`, is kept in the
repository. Click the preview to open the PDF:

[![Floor-covering impact improvement ISO 16251-1 example report: metadata header, one-third-octave delta-L table beside the delta-L(f) improvement curve, boxed delta-Lw (CI,delta) = 29 (-13) dB weighted improvement (ISO 717-2) and a PASS verdict against the 20 dB requirement](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso16251_floor_covering_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso16251_floor_covering_example.pdf)

## Laboratory flanking transmission (ISO 10848)

ISO 10848:2006/2010 is the laboratory method that **measures** the junction
**vibration reduction index** $K_{ij}$ that the [EN 12354 prediction](insulation-prediction.md) takes
as an input, together with the overall flanking descriptors $D_{n,f}$
(airborne) and $L_{n,f}$ (impact). It is the measurement counterpart of the
empirical `junction_vibration_reduction()` of that prediction.

**Vibration reduction index (Formula (13)).**
$K_{ij} = \overline{D}_{v,ij} + 10\lg\!\big(l_{ij} / \sqrt{a_i a_j}\big)$ dB, from
the direction-averaged velocity level difference
$\overline{D}_{v,ij} = \tfrac{1}{2}(D_{v,ij} + D_{v,ji})$ (Formula (11), which
makes $K_{ij}$ symmetric), the common-edge junction length $l_{ij}$ and the
**equivalent absorption lengths** $a_j = 2.2\pi^2 S_j /(T_{s,j} c_0)\sqrt{f_\text{ref}/f}$
(Formula (12), $f_\text{ref} = 1000$ Hz). For lightweight well-damped elements
$a_j = S_j / l_0$ ($l_0 = 1$ m) and Formula (13) reduces to the simplified
Formula (14). The related **total loss factor** is $\eta = 2.2/(f T_s)$.

**Overall descriptors.** $D_{n,f} = L_1 - L_2 - 10\lg(A/A_0)$ (Formula (4),
airborne) and $L_{n,f} = L_2 + 10\lg(A/A_0)$ (Formula (5), tapping machine),
$A_0 = 10\ \text{m}^2$; their $D_{n,f,w}$ / $L_{n,f,w}$ single numbers reuse the
ISO 717 rating engines. The single-number $\overline{K}_{ij}$ is the arithmetic
mean over 200–1250 Hz for one-third-octave bands, or over 125–1000 Hz for
octave bands (Annex A).

<picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/flanking_transmission_dark.svg"><img src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/flanking_transmission.svg" alt="ISO 10848 junction vibration reduction index Kij rising across one-third-octave bands from 100 Hz to 5000 Hz for a rigid T-junction of two heavy walls, with the single-number mean Kij over 200-1250 Hz drawn as a dashed line" width="80%"></picture>

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

```python
import matplotlib.pyplot as plt
import numpy as np
from phonometry import building

freqs = [100, 125, 160, 200, 250, 315, 400, 500, 630,
         800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000]
# Direction-averaged velocity level difference of a rigid T-junction (dB):
dv = np.array([4.5, 4.8, 5.2, 5.6, 6.0, 6.5, 7.0, 7.6, 8.1, 8.7,
               9.2, 9.8, 10.3, 10.9, 11.4, 11.9, 12.3, 12.7])
res = building.vibration_reduction_index(
    dv, junction_length=4.0, area_i=12.0, area_j=10.0, frequency=freqs,
    structural_reverberation_time_i=0.35, structural_reverberation_time_j=0.40,
)
print(res.single_number)   # mean Kij over 200-1250 Hz (Annex A)
res.plot()
plt.show()
```

</details>

**Validity.** $K_{ij}$ rests on a statistical-energy-analysis simplification:
`strong_coupling_satisfied()` checks the Formula (15) inequality and, for the
heavy junctions of Part 4, `modal_density()`, `band_mode_count()` and
`modal_overlap_factor()` (Formulae (5)/(4)/(6)) quantify where the mode count
is too low for $K_{ij}$ to be reliable. Pass the per-band modal overlap factor
to `vibration_reduction_index(..., modal_overlap=M)`: bands with $M < 0.25$
are flagged in `result.bracketed` and excluded from the single-number
$\overline{K}_{ij}$, as Part 4 Clause 9 requires. Because ISO 10848 contains no
worked numeric example, conformance is anchored on closed-form identities
(simplified $K_{ij}$, $a_j$ at $f_\text{ref}$, $\eta$).

```python
import numpy as np
from phonometry import building

freqs = [200, 250, 315, 400, 500, 630, 800, 1000, 1250]
lij, s_i, s_j = 4.0, 12.0, 10.0     # junction length (m), element areas (m^2)
ts = np.linspace(0.30, 0.10, 9)     # structural reverberation time Ts (s)
dv_ij = [5.6, 6.0, 6.5, 7.0, 7.6, 8.1, 8.7, 9.2, 9.8]    # element i excited (dB)
dv_ji = [6.4, 6.8, 7.3, 7.8, 8.4, 8.9, 9.5, 10.0, 10.6]  # element j excited (dB)

# Kij from both excitation directions (symmetric via the direction average):
dbar = building.direction_averaged_level_difference(dv_ij, dv_ji)
res = building.vibration_reduction_index(dbar, lij, s_i, s_j, frequency=freqs,
                                structural_reverberation_time_i=ts,
                                structural_reverberation_time_j=ts)
res.k_ij           # Kij per band (Formula (13))
res.single_number  # mean Kij over 200-1250 Hz, or None without the band set
res.octave_bands() # Kij in octave bands (its single number averages 125-1000 Hz)

# Overall airborne flanking descriptor and a Part-4 modal-overlap validity check:
dnf = building.normalized_flanking_level_difference(np.full(9, 75.0), np.full(9, 42.0),
                                           absorption_area=np.full(9, 12.0))
m = building.modal_overlap_factor(s_i, critical_frequency=85.0,
                         structural_reverberation_time=ts)
res_m = building.vibration_reduction_index(dbar, lij, s_i, s_j, frequency=freqs,
                                  modal_overlap=m)   # M < 0.25 bands bracketed
res_m.bracketed    # per-band flags; bracketed bands leave the single number
```

### ISO 10848 flanking-transmission reports (`.report()`)

Each of the three results renders a one-page PDF fiche. `VibrationReductionResult.report()`
writes a **junction characterization** report of *K*<sub>ij</sub>
(ISO 10848-1:2006): the standard-basis line, an optional metadata header, the
per-band *K*<sub>ij</sub> table beside the *K*<sub>ij</sub>(*f*) curve and a
boxed single-number mean *K*<sub>ij</sub> over the Annex A band range, with the
count of averaged and bracketed bands. Bands bracketed for poor modal overlap
(*M* < 0.25, ISO 10848-4:2010 Clause 9) print their value in brackets and are
excluded from the mean; `verbose=True` adds a column stating whether each band
enters the mean.

`FlankingLevelDifferenceResult.report()` and `FlankingImpactLevelResult.report()`
write **measurement** reports of the overall descriptors *D*<sub>n,f</sub>
(airborne) and *L*<sub>n,f</sub> (impact, tapping machine), reusing the same
two-panel insulation layout: the per-band quantity beside the
measured-versus-shifted-ISO 717-reference curve and the boxed single number
`Dn,f,w (C; Ctr)` (ISO 717-1) or `Ln,f,w (CI)` (ISO 717-2). `verbose=True`
annexes the ISO 717 evaluation per band (the value, the shifted reference and
the unfavourable deviation). A `requirement` supplied on the `ReportMetadata`
adds a verdict (`Dn,f,w` passes at or above it, `Ln,f,w` at or below it), and
`language="es"` renders every fiche in Spanish. reportlab is required
(`pip install phonometry[report]`).

```python
import numpy as np
from phonometry import building, ReportMetadata

freqs = [100, 125, 160, 200, 250, 315, 400, 500, 630,
         800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000]
dv = np.array([4.5, 4.8, 5.2, 5.6, 6.0, 6.5, 7.0, 7.6, 8.1, 8.7,
               9.2, 9.8, 10.3, 10.9, 11.4, 11.9, 12.3, 12.7])
m = np.full(18, 1.0); m[:3] = 0.1                        # bracket the low bands
kij = building.vibration_reduction_index(
    dv, junction_length=4.0, area_i=12.0, area_j=10.0, frequency=freqs,
    structural_reverberation_time_i=0.35, structural_reverberation_time_j=0.40,
    modal_overlap=m,
)
kij.report("Kij.pdf", metadata=ReportMetadata(specimen="Rigid T-junction"))

l1 = np.full(16, 80.0)
dnf = np.array([48, 49, 50, 51, 52, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 65],
               dtype=float)
dres = building.normalized_flanking_level_difference(
    l1, l1 - dnf, absorption_area=np.full(16, 10.0)
)
dres.report("Dnf.pdf", metadata=ReportMetadata(requirement=55.0))   # Dn,f,w (C; Ctr)

recv = np.array([58, 57, 56, 55, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32],
                dtype=float)
lres = building.normalized_flanking_impact_level(recv, absorption_area=np.full(16, 10.0))
lres.report("Lnf.pdf", metadata=ReportMetadata(requirement=55.0))   # Ln,f,w (CI)
```

The example fiches are regenerated with `make reports` and kept in the
repository. Click a preview to open the PDF:

[![ISO 10848-1 junction report: metadata header, per-band Kij table beside the Kij curve, boxed single-number mean Kij with the count of averaged and bracketed bands](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_kij_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_kij_example.pdf)

*Vibration reduction index fiche (`VibrationReductionResult.report`), mean Kij.*

[![ISO 10848-2 airborne flanking report: per-band Dn,f table beside the measured-versus-shifted-reference curve, boxed Dn,f,w (C; Ctr) and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_dnf_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_dnf_example.pdf)

*Flanking level difference fiche (`FlankingLevelDifferenceResult.report`), Dn,f,w (C; Ctr).*

[![ISO 10848-2 impact flanking report: per-band Ln,f table beside the measured-versus-shifted-reference curve, boxed Ln,f,w (CI) and a PASS verdict](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_lnf_example.webp)](https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/reports/iso10848_lnf_example.pdf)

*Flanking impact level fiche (`FlankingImpactLevelResult.report`), Ln,f,w (CI).*

## References

- Hopkins, C. (2007). *Sound insulation*. Butterworth-Heinemann.
  ISBN 978-0-7506-6526-1.
  [doi:10.4324/9780080550473](https://doi.org/10.4324/9780080550473).
  The reference monograph for laboratory sound-insulation measurement,
  flanking transmission and the vibration reduction index.
- Vigran, T. E. (2008). *Building acoustics*. CRC Press.
  ISBN 978-0-415-42853-8.
  [doi:10.1201/9781482266016](https://doi.org/10.1201/9781482266016).
  The transmission theory of single and double constructions that laboratory
  indices quantify.

## Standards

ISO 10140-2:2010, ISO 10140-3:2010 and ISO 10140-4:2010, which provide the
laboratory R and Ln with the background-noise correction; ISO 15186-1:2000 and
ISO 15186-2:2003, which define the sound-intensity sound reduction index $R_I$, its
$K_c$-modified form and the element normalized level difference (laboratory
and field); ISO 16251-1:2014, which specifies the small-mock-up laboratory method for the
impact-sound improvement $\Delta L$ of floor coverings, with $\Delta L_w$ via
the ISO 717-2 reference floor; ISO 10848-1:2006, ISO 10848-2:2006,
ISO 10848-3:2006 and ISO 10848-4:2010, which cover the laboratory measurement of flanking
transmission: the vibration reduction index $K_{ij}$, the equivalent
absorption length, the normalized flanking descriptors $D_{n,f}$ / $L_{n,f}$
and the modal-overlap validity checks that feed the EN 12354 prediction.

## See also

- [Field Insulation Measurement and Ratings](insulation-field.md):
  the in-building airborne, impact and façade measurements, their single-number
  ratings and their uncertainty.
- [Predicting Sound Insulation (EN 12354)](insulation-prediction.md):
  the flanking model that consumes the laboratory $R$, $L_n$ and $K_{ij}$.
- [Sound Power](sound-power.md): the `LW` methods that share the
  absorption-area machinery of the receiving room.
- API reference: [`building.lab_insulation`](https://jmrplens.github.io/phonometry/reference/api/building/lab-insulation/), [`building.intensity_insulation`](https://jmrplens.github.io/phonometry/reference/api/building/intensity-insulation/) and [`building.flanking_transmission`](https://jmrplens.github.io/phonometry/reference/api/building/flanking-transmission/).
