<!-- canonical: https://docs.jmrp.io/phonometry/reference/api/ -->
Source: https://docs.jmrp.io/phonometry/reference/api/

# API Reference

All core functionality lives in twenty-one subpackages, and every public name is
reached through the one that owns it. The top-level `phonometry` package
publishes those twenty-one and four names that belong to none of them:
`Signal`, `ReportMetadata`, `PhonometryWarning` and `__version__`.

> **Note.** This page is the curated quick table for the GitHub/PyPI audience:
> one row per public name, kept complete by a CI gate
> (`scripts/check_api_reference.py`). The full generated reference, with every
> signature, parameter table and cross-link, lives on the site:
> [phonometry API reference](https://docs.jmrp.io/phonometry/reference/api/).

## Namespaces

The library is organized into twenty-one subpackages, and importing the
namespace is the primary form used throughout the documentation:

```python
from phonometry import aircraft

contour = aircraft.noise_contour(..., x=..., y=...)   # the shape of every call
```

| Subpackage | Scope |
| :--- | :--- |
| `phonometry.filters` | Octave and fractional-octave filter banks, frequency weightings and time weighting, parametric EQ, IEC 61260-1 and IEC 61672-1 class verification |
| `phonometry.signals` | Levels (Leq, LAeq, percentiles), Welch and multitaper spectra, coherence, time-frequency, correlation, envelope, cepstrum, phase, synchronous averaging, test signals |
| `phonometry.metrology` | Calibration, GUM uncertainty and Monte Carlo, data qualification (stationarity, trends, peak statistics), the ISO 1683 reference values |
| `phonometry.fluids` | The state of the propagating medium: humid air from IEC 61094-2:2009 Annex F (CIPM-2007), with the conditions it was computed for and the domain its model states for itself |
| `phonometry.solids` | The elastic constants of a solid and the three longitudinal wave speeds that follow from them, named apart by the shape the wave travels in (beam, plate, unbounded), with the inverse of each and the `h f_c` a materials table prints |
| `phonometry.io` | Files. Measurement audio: WAV/BWF/RF64 read and write with `bext` provenance (EBU Tech 3285), headers-only `info`, block streaming, lossless conversion, calibration sidecar; FLAC, AIFF, Ogg/Opus and MP3 via the `[audio]` extra. Catalogues of materials of your own read from and written to JSON, with their provenance, into the published row classes |
| `phonometry.psychoacoustics` | Two families: `loudness` (ISO 532-1 Zwicker, ISO 532-2 and ISO 532-3 Moore-Glasberg, ECMA-418-2, ISO 226 equal-loudness contours) and `quality` (sharpness, roughness, fluctuation strength, tonality, tone audibility, annoyance), plus the ERB scale both measure on |
| `phonometry.speech` | Speech Transmission Index (IEC 60268-16), Speech Intelligibility Index (ANSI S3.5), STOI and ESTOI |
| `phonometry.hearing` | Audiometric thresholds (ISO 7029/389-7), audiometric test methods and rooms (ISO 8253-1/-2), noise-induced hearing loss (ISO 1999), occupational exposure (ISO 9612), hearing protectors (ISO 4869-1/-2/-3/-6) |
| `phonometry.emission` | Sound power (ISO 3740 family), sound intensity and the IEC 61043 instrument class it is measured with, vibration-based power |
| `phonometry.room` | Room acoustics (ISO 3382), impulse responses, open-plan, room-noise criteria, reverberation prediction, EN 12354-6 |
| `phonometry.building` | Three subgroups: `measurement` (field, laboratory, survey and intensity methods with their ISO 717 ratings and ISO 12999 uncertainty), `prediction` (EN 12354 global and detailed models, facades, panels, apertures, plenums and resilient layers) and `regulation` (national codes) |
| `phonometry.materials` | Four families by what the material does: `absorbers` (ISO 354, ISO 11654, ISO 12999-2, impedance tube ISO 10534-2, airflow resistance ISO 9053, porous and multilayer models, Biot, slow-sound metamaterials), `diffusers` (Schroeder design, metadiffusers, scattering and diffusion ISO 17497), `surfaces` (in-situ road absorption ISO 13472) and `resilient` (dynamic stiffness EN 29052-1) |
| `phonometry.vibration` | Three families: `structural` (mobility ISO 7626, plate junctions, radiation, experimental SEA, transfer stiffness ISO 10846), `human` (ISO 2631/5349/8041 exposure and multiple shocks) and `machinery` (fault frequencies and condition monitoring) |
| `phonometry.environment` | Three subgroups: `sources` (CNOSSOS road and rail emission, wind-turbine apparent sound power), `propagation` (ISO 9613-1/-2, ground effect and barriers, refraction by ray tracing and the parabolic equation) and `assessment` (ISO 1996-1/-2 rating and measurement, impulsive prominence, RD 1367/2007) |
| `phonometry.aircraft` | EPNL (ICAO Annex 16), SAE ARP 5534 and 866A absorption, airport contours (ECAC Doc 29) with NPD data for a non-reference atmosphere, rotorcraft (ECAC Doc 32) |
| `phonometry.underwater` | Three families: `sources` (ISO 17208 ship radiated noise, traffic, pile driving, wind and thermal ambient noise), `propagation` (closed-form and Weston propagation loss, normal modes, rays, Gaussian beams and the parabolic equation, seabed reflection, sound speed) and `bioacoustics` (marine-mammal audiograms and regulatory auditory weighting), over the ISO 18405 quantities and the sonar equation at the root |
| `phonometry.electroacoustics` | Distortion (IEC 60268-3 / AES17), transfer function and coherence, radiating piston |
| `phonometry.noise_control` | Reactive silencers (four-pole method), HVAC duct attenuation, machine-enclosure insertion loss |
| `phonometry.broadcast` | Programme loudness and true peak (ITU-R BS.1770-5, EBU R 128 with Tech 3341/3342) |
| `phonometry.simulation` | 2D acoustic FDTD wave simulation (staggered grid, sources, probes, impedance boundaries, obstacles) |

The table below lists each name unqualified, the way its own page titles it;
the usage snippet shows the namespace to import and call it through. The
module paths of
every earlier layout were removed in 4.0 along with the shims that served
them, so `phonometry.metrology.levels`, `phonometry.environmental` and the
rest of the pre-4.0 spellings raise `ModuleNotFoundError`. The paths in force
are the ones the
[generated reference](https://docs.jmrp.io/phonometry/reference/api/)
documents, one page per module.

> **Reading the input column.** Every function that consumes a recording
> accepts a `phonometry.io.Signal` wherever the table writes a signal
> argument, and then `fs` is optional: the object carries it, and an
> explicit value that disagrees with it raises rather than overriding it. A
> bare array still requires `fs` by name. A calibrated `Signal` is analysed
> in pascals, with four documented exemptions (the EBU R 128 family, the
> `dbfs=True` paths, quantities that are not pressures, and
> `metrology.sensitivity`, which is what produces a calibration factor).
> Each function's own page states which of these applies to it.

| Name | Type | Description (Inputs) | Usage Snippet (Outputs) |
| :--- | :--- | :--- | :--- |
| `octave_filter` | `function` | **High-level analysis.**<br>• `x`: Signal array<br>• `fs`: Sample rate [Hz]<br>• `fraction`: 1, 3, etc. (Default: 1)<br>• `order`: Filter order (Default: 6)<br>• `limits`: [f_min, f_max] (Default: [12, 20000])<br>• `sigbands`: Return time signals (Default: False)<br>• `detrend`: Remove DC offset (Default: True)<br>• `mode`: 'rms' or 'peak' (Default: 'rms')<br>• `nominal`: IEC 61260-1 nominal labels (Default: False)<br>• `design`: `FilterDesign` (family, ripple, attenuation, decimation)<br>• `calibration`: `LevelCalibration` (factor, dBFS)<br>• `response_plot`: `ResponsePlot` (show, file) | `r = filters.octave_filter(x, fs, ...)`<br>• `r.levels`: band levels [dB]<br>• `r.frequencies`: band centres [Hz]<br>• `r.bands`: one waveform per band, or `None`<br><br>**With `sigbands=True`:**<br>`bands = filters.octave_filter(x, fs, sigbands=True).require_bands()`<br><br>**Calibrated usage:**<br>`filters.octave_filter(x, fs, calibration=filters.LevelCalibration(factor=0.05)).levels` |
| `OctaveFilterResult` | `dataclass` | **What a filter bank gives back for one signal.**<br>• `levels`: band levels [dB], `(bands,)` or `(channels, bands)`, `None` when the call asked for no level<br>• `frequencies`: one band centre per level, exact or IEC 61260-1 nominal labels<br>• `bands`: one waveform per band, `None` unless `sigbands=True`<br>• `.require_levels()` / `.require_bands()`: the value, or a `ValueError` naming the argument that was missing<br>• `.plot()`: the band spectrum on a log frequency axis | `r = filters.octave_filter(x, fs, fraction=3)`<br>`r.levels[r.frequencies.index(1000.0)]`<br><br>• `ax = r.plot()` |
| `OctaveFilterBank` | `class` | **Efficient bank implementation.**<br>• `fs`: Sample rate [Hz]<br>• `fraction`: 1, 3, etc.<br>• `order`: Filter order<br>• `limits`: [f_min, f_max] (Default: [12, 20000])<br>• `design`: `FilterDesign` (family, ripple, attenuation, decimation)<br>• `calibration`: `LevelCalibration` (factor, dBFS)<br>• `block_processing`: `BlockProcessing` (stateful, steady_ic)<br>• `response_plot`: `ResponsePlot` (show, file) | `bank = filters.OctaveFilterBank(fs=48000, fraction=3, order=6, design=filters.FilterDesign(filter_type='butter'))`<br>`r = bank.filter(x, sigbands=False, mode='rms', detrend=True, zero_phase=False)`<br>• `r.levels`, `r.frequencies`, `r.bands` (an `OctaveFilterResult`)<br><br>• `bank`: Instance of the filter bank<br>• `bank.freq` / `bank.freq_d` / `bank.freq_u` / `bank.sos`: computed properties |
| `FilterDesign` | `dataclass` | **How the band filters are designed.**<br>• `filter_type`: 'butter', 'cheby1', 'cheby2', 'ellip', 'bessel' (Default: 'butter')<br>• `ripple`: Passband ripple [dB] (for cheby1/ellip; Default: 0.1)<br>• `attenuation`: Stopband attenuation [dB] (Default: 72; cheby2 needs >= 70 dB for class 1)<br>• `resample`: Multirate decimation (Default: True) | `OctaveFilterBank(48000, 3, design=filters.FilterDesign(filter_type='cheby2'))` |
| `LevelCalibration` | `dataclass` | **How band energy becomes a level.**<br>• `factor`: Sensitivity multiplier, Pa per digital unit (Default: 1.0)<br>• `dbfs`: Output in dBFS instead of dB SPL (Default: False) | `octave_filter(x, fs, calibration=filters.LevelCalibration(factor=0.05))` |
| `BlockProcessing` | `dataclass` | **Filter state carried between calls.**<br>• `stateful`: Carry filter state between calls (Default: False)<br>• `steady_ic`: Steady-state initial conditions (Default: False) | `OctaveFilterBank(48000, 1, design=filters.FilterDesign(resample=False), block_processing=filters.BlockProcessing(stateful=True))` |
| `ResponsePlot` | `dataclass` | **Response plot drawn while designing.**<br>• `show`: Show the plot (Default: False)<br>• `file`: Path to save the plot (Default: None) | `OctaveFilterBank(48000, 3, response_plot=filters.ResponsePlot(show=True))` |
| `OctaveFilterBank.spectrogram` | `method` | **Band levels over time.**<br>• `x`: Signal array (1D or 2D)<br>• `window_time`: Window length [s] (Default: 0.125)<br>• `overlap`: Fraction in [0, 1) (Default: 0.5)<br>• `mode`: 'rms' or 'peak'<br>• `zero_phase`: Group-delay-free frames (Default: False) | `levels, freq, times = bank.spectrogram(x)`<br><br>• `levels`: (bands, frames) or (channels, bands, frames)<br>• `times`: window centers [s] |
| `weighting_filter` | `function` | **Acoustic weighting.**<br>• `x`: Signal array<br>• `fs`: Sample rate [Hz]<br>• `curve`: 'A', 'C' (IEC 61672-1), 'B' (ANSI S1.4-1983, historical), 'D' (withdrawn IEC 537, aircraft), 'G' (ISO 7196 infrasound), 'AU' (IEC 61012), '468' (ITU-R BS.468-4 psophometric) or 'Z' (Default: 'A')<br>• `high_accuracy`: fit the analog prototype at `fs` instead of transforming it blind, for IEC class 1 accuracy at every rate (Default: True; '468' requires it) | `y = filters.weighting_filter(x, fs, curve='A')`<br><br>• `y`: weighted signal |
| `WeightingFilter` | `class` | **Reusable weighting filter.**<br>• `fs`: Sample rate [Hz]<br>• `curve`: 'A', 'B', 'C', 'D', 'G', 'AU', '468' or 'Z'<br>• `stateful`: Block processing (Default: False)<br>• `steady_ic`: Steady-state initial conditions (Default: False)<br>• `high_accuracy`: Fitted design, independent of `stateful` (Default: True; '468' refuses False) | `wf = filters.WeightingFilter(fs, 'A')`<br>`y = wf.filter(x)` |
| `time_weighting` | `function` | **Energy capture.**<br>• `x`: Raw signal array (squared internally; time is the last axis)<br>• `fs`: Sample rate [Hz]<br>• `mode`: 'fast', 'slow', or 'impulse'<br>• `initial_state`: None, 'zero', 'first', scalar, or array (Default: None) | `env = filters.time_weighting(x, fs, mode='fast')`<br><br>• `env`: energy envelope (Mean Square), same shape as `x` |
| `TimeWeightedEnvelope` | `dataclass` | **Exponentially averaged mean square of a record, with its rate.**<br>• `mean_square` [Pa² when calibrated], `fs` [Hz], `mode`, `calibrated`<br>• stands in for the bare array it replaced (`np.asarray`, indexing, `shape`)<br>• returned by `time_weighting`/`TimeWeighting.process` for a `Signal` input; a mean square is not a pressure record, so it is not a `Signal` | `env = filters.time_weighting(filters.weighting_filter(sig, curve='A'), mode='fast')`<br>`env.plot()`  # the L_pAF trace in dB |
| `TimeWeighting` | `class` | **Stateful time weighting.**<br>• `fs`: Sample rate [Hz]<br>• `mode`: 'fast', 'slow', 'impulse' (Default: 'fast') | `tw = filters.TimeWeighting(fs, mode='fast')`<br>`env = tw.process(block)` per block<br>`tw.reset()` to start over |
| `leq` | `function` | **Equivalent level (Leq).**<br>• `x`: Signal array (1D or 2D) or a `phonometry.io.Signal`<br>• `calibration_factor`: Sensitivity multiplier (Default: None: a calibrated `Signal`'s factor, else 1.0; explicit wins)<br>• `dbfs`: Output in dBFS (Default: False) | `level = signals.leq(x, calibration_factor=s)`<br><br>• `level`: Scalar (1D) or per-channel array (2D) |
| `laeq` | `function` | **A-weighted Leq (LAeq).**<br>• `x`: Signal array (1D or 2D) or a `phonometry.io.Signal`<br>• `fs`: Sample rate [Hz] (taken from `x` when `x` is a `Signal`)<br>• `calibration_factor` / `dbfs`: as `leq` | `level = signals.laeq(x, fs, calibration_factor=s)`<br><br>• `level`: Scalar (1D) or per-channel array (2D) |
| `ln_levels` | `function` | **Statistical levels (LN).**<br>• `x`: Signal array (1D or 2D) or a `phonometry.io.Signal`<br>• `fs`: Sample rate [Hz] (taken from `x` when `x` is a `Signal`)<br>• `n`: Exceedance percentiles (Default: (10, 50, 90))<br>• `mode`: 'fast', 'slow', 'impulse' (Default: 'fast')<br>• `weighting`: any `weighting_filter` curve, 'A', 'B', 'C', 'D', 'G', 'AU', '468' or 'Z', or None (Default: None)<br>• `calibration_factor` / `dbfs`: as `leq` | `stats = signals.ln_levels(x, fs, n=(10, 50, 90), weighting='A')`<br><br>• `stats`: Dict `{10: L10, 50: L50, 90: L90}` |
| `lc_peak` | `function` | **C-weighted peak (LCpeak).**<br>• `x`: Signal array (1D or 2D) or a `phonometry.io.Signal`<br>• `fs`: Sample rate [Hz] (taken from `x` when `x` is a `Signal`)<br>• `calibration_factor`: as `leq`<br>• `dbfs`: 0 dBFS = full-scale *peak* (amplitude 1.0), unlike the RMS reference of `leq`<br>• `oversample`: HF inter-sample peak recovery (Default: 8; 1 = on-grid, under-reads up to ~1.15 dB at 48 kHz) | `peak = signals.lc_peak(x, fs)`<br><br>• IEC 61672-1 §5.13; verified against Table 5 |
| `sel` | `function` | **Sound exposure level (SEL/LAE).**<br>• `x`: Whole-event signal (1D or 2D) or a `phonometry.io.Signal`<br>• `fs`: Sample rate [Hz] (taken from `x` when `x` is a `Signal`)<br>• `weighting`: any `weighting_filter` curve, 'A', 'B', 'C', 'D', 'G', 'AU', '468' or 'Z', or None (Default: None)<br>• `calibration_factor` / `dbfs`: as `leq` | `lae = signals.sel(x, fs, weighting='A')`<br><br>• Event level normalized to 1 s |
| `sound_exposure` | `function` | **A-weighted exposure E (IEC 61252).**<br>• `x`: Signal (1D or 2D) or a `phonometry.io.Signal`<br>• `fs`: Sample rate [Hz] (taken from `x` when `x` is a `Signal`)<br>• `duration_hours`: exposure period represented (Default: recording length)<br>• `calibration_factor` | `E = signals.sound_exposure(x, fs, duration_hours=8)`<br><br>• `E`: Pa²·h |
| `lex_8h` | `function` | **Daily exposure LEX,8h / LEP,d.**<br>• Same params as `sound_exposure` | `lex = signals.lex_8h(x, fs, duration_hours=4)`<br><br>• Normalized 8 h level [dB] |
| `loudness_zwicker` | `function` | **Zwicker loudness (ISO 532-1:2017).**<br>• `x`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz]<br>• `field`: 'free' or 'diffuse' (Default: 'free')<br>• `stationary`: Clause 5 stationary method (Default: False)<br>• `time_skip`: seconds excluded from the stationary mean square (Annex B.1 uses 0.2 s; Default: 0.0)<br>• `calibration_factor`: Digital units to Pa (Default: 1.0) | `res = psychoacoustics.loudness_zwicker(x, fs)`<br><br>• `ZwickerLoudness`; time-varying runs add N5/N10 and the 500 Hz N(t) trace |
| `loudness_zwicker_from_spectrum` | `function` | **Stationary loudness from band levels.**<br>• `levels`: 28 one-third-octave levels, 25 Hz-12.5 kHz [dB SPL]<br>• `field`: 'free' or 'diffuse' (Default: 'free') | `res = psychoacoustics.loudness_zwicker_from_spectrum(levels)`<br><br>• `res.loudness` [sone], `res.loudness_level` [phon] |
| `ZwickerLoudness` | `dataclass` | **Loudness result.**<br>• `loudness`: N [sone]<br>• `loudness_level`: LN [phon]<br>• `specific`: N′(z), 240 bins of 0.1 Bark<br>• `n5` / `n10`: percentile loudness (time-varying only)<br>• `times` / `loudness_vs_time`: 500 Hz trace<br>• `field`: sound field assumed ('free'/'diffuse') | `res.loudness, res.n5`<br><br>• Time-varying fields are `None` for stationary results |
| `sharpness_din` | `function` | **Sharpness in acum (DIN 45692).**<br>• `x`: Signal (1D)<br>• `fs`: Sample rate [Hz]<br>• `field`: 'free' or 'diffuse' (Default: 'free')<br>• `method`: 'din', 'aures' or 'bismarck' (Default: 'din')<br>• `calibration_factor`: Digital units to Pa (Default: 1.0) | `s = psychoacoustics.sharpness_din(x, fs)`<br><br>• `s`: sharpness [acum] |
| `sharpness_din_from_specific` | `function` | **Sharpness from a specific-loudness pattern.**<br>• `specific`: N′(z), 240 values at 0.1 Bark (e.g. `ZwickerLoudness.specific`)<br>• `method`: 'din', 'aures' or 'bismarck' (Default: 'din') | `s = psychoacoustics.sharpness_din_from_specific(res.specific)`<br><br>• `s`: sharpness [acum] |
| `erb_bandwidth` | `function` | **Auditory-filter equivalent rectangular bandwidth ERB_N (Glasberg & Moore 1990; Moore 6e p. 76).**<br>• `frequency` [Hz] (scalar or array, ≥ 0)<br>• `ERB_N = 24.673(0.004368 f + 1)` [Hz] | `erb_bandwidth(1000.0)  # 132.4` |
| `cam_from_frequency` / `frequency_from_cam` | `function` | **The Cam (ERB_N-number) frequency scale, one unit per auditory-filter width.**<br>• `cam_from_frequency(f)` = `21.366 log10(0.004368 f + 1)` [Cam]<br>• `frequency_from_cam(i)`: the exact inverse [Hz] | `cam_from_frequency(1000.0)  # 15.59`<br>`frequency_from_cam(15.59)` |
| `ERB_C1` / `ERB_C2` / `CAM_C` | `constant` | **Constants of the ERB_N fit shared with the ISO 532-2 loudness model.**<br>• `ERB_C1` = 24.673 [Hz], `ERB_C2` = 0.004368 [1/Hz], `CAM_C` = 21.366 [Cam] | `ERB_C1 * (ERB_C2 * f + 1)` |
| `loudness_moore_glasberg` | `function` | **Moore-Glasberg loudness (ISO 532-2:2017).**<br>• `x`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz]<br>• `field`: 'free', 'diffuse' or 'eardrum' (Default: 'free')<br>• `presentation`: 'binaural'/'diotic' or 'monaural' (Default: 'binaural') | `res = psychoacoustics.loudness_moore_glasberg(x, fs)`<br><br>• `MooreGlasbergLoudness` (roex excitation pattern) |
| `loudness_moore_glasberg_from_spectrum` | `function` | **Exact loudness from sinusoidal components (ISO 532-2 §5.2/5.4).**<br>• `components`: sequence of (frequency [Hz], level [dB SPL]) pairs<br>• `field`: 'free'/'diffuse'/'eardrum' (Default: 'free')<br>• `presentation`: (Default: 'binaural') | `res = psychoacoustics.loudness_moore_glasberg_from_spectrum([(1000.0, 40.0)])`<br><br>• 1 kHz/40 dB → 1.000 sone |
| `loudness_moore_glasberg_from_third_octave` | `function` | **Loudness from 29 one-third-octave band levels (ISO 532-2 §5.5).**<br>• `band_levels`: 29 levels, 25 Hz–16 kHz [dB SPL]<br>• `field` / `presentation`: as above | `res = psychoacoustics.loudness_moore_glasberg_from_third_octave(levels)`<br><br>• `MooreGlasbergLoudness` |
| `MooreGlasbergLoudness` | `dataclass` | **Moore-Glasberg loudness result.**<br>• `loudness`: N [sone]<br>• `loudness_level`: LN [phon]<br>• `specific`: N′(i), 372 bins of 0.1 Cam<br>• `erb_number` / `centre_frequencies`: Cam / Hz axes<br>• `field` / `presentation`<br>• `.plot()`: specific loudness N′(i) over Cam | `res.loudness, res.loudness_level` |
| `loudness_moore_glasberg_time` | `function` | **Time-varying loudness (ISO 532-3:2023).**<br>• `signal`: Calibrated Pa; 1D (diotic) or (n, 2) ears<br>• `fs`: Sample rate [Hz]<br>• `field`: 'free'/'diffuse'/'eardrum' (Default: 'free')<br>• `presentation`: (Default: 'binaural')<br>• `percentiles`: exceedance % (Default: (1,5,10,50,90,95)) | `res = psychoacoustics.loudness_moore_glasberg_time(x, fs)`<br><br>• `MooreGlasbergTimeVaryingLoudness` |
| `MooreGlasbergTimeVaryingLoudness` | `dataclass` | **Time-varying loudness result.**<br>• `times`: 1 ms grid [s]<br>• `short_term_loudness` / `long_term_loudness`: S′(t)/S″(t) [sone]<br>• `short_term_loudness_level` / `long_term_loudness_level` [phon]<br>• `n_max` / `loudness_level_max`: peak long-term loudness<br>• `percentiles`: dict {percent: sone}<br>• `.plot()`: STL and LTL vs time | `res.n_max, res.percentiles[5.0]` |
| `loudness_ecma` | `function` | **Sottek Hearing Model loudness (ECMA-418-2:2025).**<br>• `signal_in`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz] (resampled to 48 kHz)<br>• `field`: 'free' or 'diffuse' (Default: 'free') | `res = psychoacoustics.loudness_ecma(x, fs)`<br><br>• `EcmaLoudness`; 1 kHz/40 dB ≈ 1 sone_HMS |
| `EcmaLoudness` | `dataclass` | **Sottek loudness result.**<br>• `loudness`: N [sone_HMS]<br>• `specific_loudness`: N′(z), 53 Bark_HMS bands<br>• `bark` / `centre_frequencies`: z / Hz axes<br>• `times` / `loudness_vs_time`: N(l) at 187.5 Hz<br>• `field`<br>• `.plot()`: N′(z) + N(l) | `res.loudness, res.specific_loudness` |
| `tonality_ecma` | `function` | **Sottek tonality (ECMA-418-2:2025).**<br>• `signal_in`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz] (resampled to 48 kHz)<br>• `field`: 'free' or 'diffuse' (Default: 'free')<br>• `f_low` / `f_high`: optional user band [Hz] (Default: None) | `res = psychoacoustics.tonality_ecma(x, fs)`<br><br>• `EcmaTonality`; 1 kHz/40 dB ≈ 1 tu_HMS |
| `EcmaTonality` | `dataclass` | **Sottek tonality result.**<br>• `tonality`: T [tu_HMS]<br>• `specific_tonality`: T′(z), 53 bands<br>• `tonal_frequencies`: f_ton,z per band [Hz]<br>• `bark` / `centre_frequencies`<br>• `times` / `tonality_vs_time` / `tonal_frequency_vs_time`: T(l), f_ton(l)<br>• `field`<br>• `.plot()`: T′(z) + T(l) | `res.tonality, res.tonal_frequencies` |
| `roughness_ecma` | `function` | **Sottek roughness (ECMA-418-2:2025), new capability.**<br>• `signal_in`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz] (resampled to 48 kHz)<br>• `field`: 'free' or 'diffuse' (Default: 'free') | `res = psychoacoustics.roughness_ecma(x, fs)`<br><br>• `EcmaRoughness`; 1 kHz/70 Hz/100 %-AM/60 dB ≈ 1 asper |
| `EcmaRoughness` | `dataclass` | **Sottek roughness result.**<br>• `roughness`: R [asper] (90th percentile of R(l50))<br>• `specific_roughness`: R′(z), 53 bands<br>• `bark` / `centre_frequencies`<br>• `times` / `roughness_vs_time`: R(l50) at 50 Hz<br>• `specific_roughness_vs_time`: (n_times, 53)<br>• `field`<br>• `.plot()`: R(l50) + specific-roughness heatmap | `res.roughness, res.specific_roughness` |
| `fluctuation_strength_ecma` | `function` | **Sottek fluctuation strength (ECMA-418-2:2025 Clause 9), new capability.**<br>• `signal_in`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz] (resampled to 48 kHz)<br>• `field`: 'free' or 'diffuse' (Default: 'free') | `res = psychoacoustics.fluctuation_strength_ecma(x, fs)`<br><br>• `EcmaFluctuationStrength`; 1 kHz/4 Hz/100 %-AM/60 dB ≈ 1 vacil_HMS |
| `EcmaFluctuationStrength` | `dataclass` | **Sottek fluctuation-strength result.**<br>• `fluctuation_strength`: F [vacil_HMS] (90th percentile of F(l50))<br>• `specific_fluctuation_strength`: F′(z), 53 bands<br>• `bark` / `centre_frequencies`<br>• `times` / `fluctuation_strength_vs_time`: F(l50) at 50 Hz<br>• `specific_fluctuation_strength_vs_time`: (n_times, 53)<br>• `field`<br>• `.plot()`: F(l50) + specific-fluctuation-strength heatmap | `res.fluctuation_strength, res.specific_fluctuation_strength` |
| `psychoacoustic_annoyance` | `function` | **Psychoacoustic annoyance PA (Fastl & Zwicker Eqs 16.2–16.4), exact model.**<br>• `n5`: percentile loudness N5 [sone]<br>• `sharpness` S [acum]<br>• `fluctuation_strength` F [vacil]<br>• `roughness` R [asper] | `res = psychoacoustics.psychoacoustic_annoyance(30, 2.0, 0.5, 0.3)`<br><br>• `PsychoacousticAnnoyanceResult`; `res.annoyance == 37.0478` |
| `psychoacoustic_annoyance_from_signal` | `function` | **PA from a calibrated signal (convenience, engineering estimate).**<br>• `x`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz]<br>• `field`: 'free' or 'diffuse' (Default: 'free')<br>• `calibration_factor` (Default: 1.0)<br>Mixes Zwicker N5/S + Sottek R + Osses F. | `res = psychoacoustics.psychoacoustic_annoyance_from_signal(x, fs)`<br><br>• `PsychoacousticAnnoyanceResult` |
| `PsychoacousticAnnoyanceResult` | `dataclass` | **Psychoacoustic annoyance result.**<br>• `annoyance`: PA<br>• `n5` [sone] / `sharpness` [acum] / `fluctuation_strength` [vacil] / `roughness` [asper]: the four inputs<br>• `w_s`: sharpness weighting wS<br>• `w_fr`: roughness/fluctuation weighting wFR<br>• `.plot()`: term-contribution bar | `res.annoyance, res.w_s, res.w_fr` |
| `fluctuation_strength_am_noise` | `function` | **Fluctuation strength of AM broadband noise (Fastl & Zwicker Eq. 10.2), exact closed form.**<br>• `level_db` L [dB]<br>• `modulation_factor` m (0–1)<br>• `mod_frequency` fmod [Hz] | `fluctuation_strength_am_noise(60, 1.0, 4.0)  # 3.6943 vacil` |
| `fluctuation_strength` | `function` | **Fluctuation strength F (Osses 2016 signal model), no numeric standard, free-field.**<br>• `signal_in`: Calibrated signal in Pa (1D)<br>• `fs`: Sample rate [Hz] | `res = psychoacoustics.fluctuation_strength(x, fs)`<br><br>• `FluctuationStrengthResult`; 1 kHz/60 dB/m=1/4 Hz AM ≈ 1 vacil |
| `FluctuationStrengthResult` | `dataclass` | **Fluctuation strength result.**<br>• `fluctuation_strength`: F [vacil]<br>• `specific`: F′(z), 47 values<br>• `bark_axis`: z [Bark], 47 values<br>• `time_dependent`: F(t) per frame<br>• `.plot()`: specific F′(z) over the Bark axis | `res.fluctuation_strength, res.specific` |
| `equal_loudness_contour` | `function` | **ISO 226:2023 equal-loudness contour.**<br>• `phon`: Loudness level, 20-90 phon | `freqs, spl = psychoacoustics.equal_loudness_contour(40.0)`<br><br>• SPL at the 29 preferred frequencies |
| `equal_loudness_contours` | `function` | **ISO 226:2023 equal-loudness contour family (plottable).**<br>• `phons`: Loudness levels [phon] (Default: 20-90 in 10-phon steps)<br>• `frequencies`: Grid [Hz] (Default: the 29 preferred) | `res = psychoacoustics.equal_loudness_contours()`<br><br>• `EqualLoudnessContours`; `res.plot()` |
| `EqualLoudnessContours` | `dataclass` | **Equal-loudness contour family result.**<br>• `frequencies`: grid [Hz]<br>• `phons`: contour levels [phon]<br>• `contours`: SPL, `(len(phons), len(frequencies))` [dB] (`nan` where undefined)<br>• `threshold`: hearing threshold $T_f$ [dB]<br>• `.plot()`: the iconic ISO 226 chart | `res.contours, res.threshold` |
| `loudness_level` | `function` | **Loudness level of a pure tone (phon).**<br>• `spl`: Tone SPL [dB]<br>• `frequency`: One of the 29 Table 1 frequencies [Hz] | `phon = psychoacoustics.loudness_level(73.0, 63.0)` |
| `hearing_threshold` | `function` | **Threshold of hearing (ISO 226 Table 1).**<br>• (no parameters) | `freqs, tf = psychoacoustics.hearing_threshold()` |
| `tone_to_noise_ratio` | `function` | **Tone-to-noise ratio (ECMA-418-1 §11).**<br>• `x`: Signal (1D)<br>• `fs`: Sample rate [Hz]<br>• `tone_freq`: Tone to assess [Hz] (Default: highest peak)<br>• `resolution_hz`: FFT bin spacing (Default: 1.0) | `r = psychoacoustics.tone_to_noise_ratio(x, fs)`<br><br>• `ToneAssessment(frequency, ratio_db, method)` |
| `prominence_ratio` | `function` | **Prominence ratio (ECMA-418-1 §12).**<br>• Same params as `tone_to_noise_ratio` | `r = psychoacoustics.prominence_ratio(x, fs, tone_freq=1000)`<br><br>• `ToneAssessment(...)` |
| `ToneAssessment` | `dataclass` | **Tone prominence verdict.**<br>• `frequency`: Assessed tone [Hz]<br>• `ratio_db`: TNR or PR [dB]<br>• `method`: 'tone_to_noise_ratio' or 'prominence_ratio', which selects the criterion<br>• read-only: `criterion_db`, the ECMA-418-1 prominence limit at that frequency [dB], and `prominent`: bool | `r = psychoacoustics.tone_to_noise_ratio(x, fs)`<br>`if r.prominent: ...` |
| `tone_audibility` | `function` | **Tone audibility ΔL = LT−LG−av (ISO/PAS 20065 Formulae 12–14).**<br>• `tone_level` LT, `mean_narrowband_level` LS [dB]<br>• `tone_frequency` fT [Hz], `line_spacing` Δf [Hz] | `tone_audibility(67.96, 49.22, 137.3, 2.7)  # 5.01 dB` |
| `assess_tones` | `function` | **Audibility of a spectrum's tones (ISO/PAS 20065).**<br>• `tone_frequencies` [Hz], `tone_levels` LT, `mean_narrowband_levels` LS [dB]<br>• `line_spacing` Δf [Hz]<br>• `extended_uncertainties`: attach the Clause 5.4 U per tone (Default: True) | `res = psychoacoustics.assess_tones(fT, LT, LS, 2.7)`<br><br>• `ToneAudibilityResult` |
| `critical_bandwidth_engineering` | `function` | **Critical bandwidth Δfc about a tone (Formula 2).**<br>• `tone_frequency` fT [Hz] | `critical_bandwidth_engineering(137.3)  # 101.36 Hz` |
| `critical_band_corners` | `function` | **Corner frequencies (f₁, f₂) of the critical band (Formulae 3–5).**<br>• `tone_frequency` fT [Hz] | `f1, f2 = psychoacoustics.critical_band_corners(137.3)` |
| `critical_band_level` | `function` | **Masking-noise level LG = LS+10lg(Δfc/Δf) (Formula 12).**<br>• `mean_narrowband_level` LS [dB], `tone_frequency` fT, `line_spacing` Δf [Hz] | `critical_band_level(49.22, 137.3, 2.7)  # 64.97 dB` |
| `masking_index` | `function` | **Masking index av = −2−lg[1+(f/502)²·⁵] (Formula 13).**<br>• `frequency` f [Hz] | `masking_index(137.3)  # -2.02 dB` |
| `audibility_from_levels` | `function` | **ΔL = LT − LG − av (Formula 14).**<br>• `tone_level` LT, `critical_band_level` LG, `masking_index` av [dB] | `audibility_from_levels(67.96, 64.98, -2.02)  # 5.0 dB` |
| `energy_sum_level` | `function` | **Energy sum of lines with window correction (Formulae 7/8).**<br>• `line_levels` Li [dB]; a single line (K = 1) takes its level unchanged (Formula 7, no correction)<br>• `effective_bandwidth_factor` Δfe/Δf (Default: 1.5, Hanning; K > 1 only) | `energy_sum_level([80, 80])  # 81.25 dB` |
| `mean_narrowband_level` | `function` | **Masking-noise level LS from a critical-band spectrum (Formula 6, iterative Annex D).**<br>• `levels` Li [dB], `frequencies` [Hz]<br>• `tone_frequency` fT [Hz]<br>• `effective_bandwidth_factor` (Default: 1.5) | `mean_narrowband_level(levels, freqs, 137.3)  # 49.22 dB` |
| `tone_level` | `function` | **Tone level LT from the tonal lines about a peak (Formulae (7)/(8): single lines take (7), without the Hanning bandwidth correction).**<br>• `levels` Li [dB], `frequencies` [Hz]<br>• `tone_frequency` fT [Hz], `mean_narrowband_level` LS [dB]<br>• `effective_bandwidth_factor` (Default: 1.5) | `tone_level(levels, freqs, 137.3, ls)  # 67.96 dB` |
| `audibility_uncertainty` / `mean_audibility_uncertainty` | `function` | **Extended uncertainty U of the audibility (ISO/PAS 20065 Clause 5.4/6, 90 % bilateral).**<br>• per tone: `audibility_uncertainty(tone_line_levels, noise_line_levels, tone_frequency, line_spacing)`<br>• mean: U of the energy-averaged audibility over the per-spectrum (ΔL, U) pairs<br>Mandatory when fewer than 12 spectra are averaged (Clause 6) | `u = psychoacoustics.audibility_uncertainty(lt_lines, ls_lines, 137.3, 2.7)`<br><br>• U [dB] |
| `analyze_spectrum` | `function` | **Detect & rate the audible tones of a spectrum (Clause 5.3.8 + distinctness 5.3.4), incl. Step 3 same-band FG combination (Formula 17).**<br>• `levels` Li [dB], `frequencies` [Hz]<br>• `line_spacing` Δf [Hz]<br>• `effective_bandwidth_factor` (Default: 1.5) | `res = psychoacoustics.analyze_spectrum(levels, freqs, 2.7)`<br><br>• `ToneAudibilityResult` of detected tones + FG entries (`group_sizes`) |
| `combined_tone_level` | `function` | **Multi-tone FG combined level (Formula 17).**<br>• `levels` Li [dB], `frequencies` [Hz]<br>• `tone_frequencies` [Hz], `mean_narrowband_levels` LS [dB]<br>• `effective_bandwidth_factor` (Default: 1.5) | `combined_tone_level(lv, f, [118.4,137.3,158.8], ls)  # 72.15 dB` |
| `two_tone_separation_frequency` | `function` | **Two-tone separation threshold fD = 21·10^(1.2·\|lg(fT/212)\|^1.8) Hz (Formula 19).**<br>• `tone_frequency` fT [Hz] (more prominent tone) | `two_tone_separation_frequency(212.0)  # 21.0 Hz` |
| `resolve_tones_separately` | `function` | **Rate two tones <1000 Hz separately vs combined (Formulae 18/19).**<br>• `tone1_frequency`, `tone2_frequency` [Hz]<br>• `audibility1`, `audibility2` ΔL [dB] | `resolve_tones_separately(200., 260., 3., 2.)  # True` |
| `mean_audibility` | `function` | **Energy-mean mean audibility over spectra (Formula 20).**<br>• `decisive_audibilities` ΔLj [dB]; no-tone spectra use −10 dB | `mean_audibility([9.18, 6.04, 7.46])  # dB` |
| `ToneAudibilityResult` | `dataclass` | **Tonal audibility of a spectrum's tones (ISO/PAS 20065).**<br>• `audibilities` ΔL, `critical_band_levels` LG, `masking_indices` av [dB]<br>• `critical_bandwidths` Δfc, `lower_corners`/`upper_corners` [Hz]<br>• `audible`: ΔL > 0 mask<br>• `extended_uncertainties`: Clause 5.4 U per tone [dB]<br>• `group_sizes`: 1 = single tone, N ≥ 2 = Step 3 FG entry (None from `assess_tones`)<br>• `decisive_audibility` / `decisive_frequency`<br>• `.plot()`: per-tone ΔL vs frequency | `res.decisive_audibility, res.audible` |
| `HANNING_BANDWIDTH_FACTOR` | `float` | **Hanning effective-bandwidth factor Δfe/Δf (ISO/PAS 20065 Annex A).**<br>1.5 | `HANNING_BANDWIDTH_FACTOR  # 1.5` |
| `NO_TONE_AUDIBILITY` | `float` | **Audibility reported when no tone is found [dB] (ISO/PAS 20065 Formula 21).**<br>-10.0 | `NO_TONE_AUDIBILITY  # -10.0` |
| `sti_from_impulse_response` | `function` | **Full STI, indirect method (IEC 60268-16 Ed. 5).**<br>• `ir`: Impulse response (1D)<br>• `fs`: Sample rate [Hz] (>= 22500)<br>• `snr`: SNR [dB], scalar or 7 bands (Default: None)<br>• `levels`: 7 speech band levels [dB SPL]; enables masking + reception threshold (Default: None)<br>• `ambient`: 7 noise band levels [dB SPL]; requires `levels` | `res = speech.sti_from_impulse_response(ir, fs, snr=25.0)`<br><br>• `STIResult` with `mtf` (7×14) |
| `stipa` | `function` | **STIPA direct method (Annex B).**<br>• `x`: Recorded STIPA signal (1D), 15-25 s<br>• `fs`: Sample rate [Hz] (>= 22500)<br>• `reference`: Measured source signal instead of the nominal m = 0.55 (Default: None)<br>• `levels` / `ambient`: as `sti_from_impulse_response`<br>• warns (`UserWarning`) if the recording is < 15 s (STI biased low) | `res = speech.stipa(recording, fs)`<br><br>• `STIResult` with `mtf` (7×2) |
| `stipa_signal` | `function` | **STIPA test-signal generator (A.4/A.6.1).**<br>• `fs`: Sample rate [Hz] (>= 22500)<br>• `seconds`: Duration [s] (Default: 18.0)<br>• `level_db`: RMS level [dB SPL] (Default: None → RMS 0.1)<br>• `seed`: Pink-noise seed (Default: None) | `sig = speech.stipa_signal(48000, seconds=18.0)`<br><br>• 1D test signal, Ed. 5 male spectrum |
| `sti_adjusted_for_levels` | `function` | **Occupancy-noise and speech-level adjustment (Ed. 4 Annex M).**<br>• `mtf`: measured m matrix (7×n), noise and masking included<br>• `measured_levels`: 7 band levels [dB SPL] during the measurement<br>• `measured_ambient`: same, background noise (Default: None)<br>• `operational_levels`: 7 band levels [dB SPL] of the condition simulated<br>• `operational_ambient`: same, occupancy noise (Default: None) | `res = speech.sti_adjusted_for_levels(mtf, measured_levels=lm, measured_ambient=nm, operational_levels=lo, operational_ambient=no)`<br><br>• `STIResult` at the operational levels |
| `STIResult` | `dataclass` | **STI result.**<br>• `sti`: 0 to 1<br>• `mti`: band indices (7,)<br>• `mtf`: corrected m values (7×14 or 7×2)<br>• `band_levels` / `ambient_levels`: levels used or None<br>• `rating`: Annex F letter 'A+'…'U'<br>• `.adjusted_for_levels(operational_levels=…, operational_ambient=…)`: the same result at another condition (Annex M) | `res = speech.stipa(x, fs)`<br>`print(res.sti, res.rating)` |
| `sound_intensity` | `function` | **p-p sound intensity (IEC 61043).**<br>• `p1`, `p2`: Microphone signals [Pa], equal length<br>• `fs`: Sample rate [Hz]<br>• `spacing`: Microphone separation Δr [m]<br>• `density`: Air density (Default: 1.204)<br>• `speed_of_sound`: Speed of sound (Default: 343.0)<br>• `fraction`: None, 1 or 3 (Default: None)<br>• `limits`: [f_min, f_max] (Default: [12, 20000])<br>• `bias_correct`: undo finite-difference under-read of band/broadband totals near `max_valid_frequency` (Default: False) | `res = emission.sound_intensity(p1, p2, fs, spacing=0.012, fraction=3)`<br><br>• `IntensityResult` |
| `plot_pp_probe_geometry` | `function` | **Face-to-face p-p probe to scale.**<br>• `spacing` dr [m] (Default: 12 mm)<br>• `language` | `plot_pp_probe_geometry()`<br><br>• Also `IntensityResult.plot_geometry()` |
| `IntensityResult` | `dataclass` | **Intensity result.**<br>• Per band (with `fraction`): `frequencies`, `intensity` [W/m²], `intensity_level`, `pressure_level`, `pressure_intensity_index`, `direction` (±1), `bias_correction`<br>• Broadband: `total_*` counterparts<br>• `max_valid_frequency`: 0.1·c/Δr | `res.total_intensity_level`<br>`res.total_direction` |
| `field_indicators` | `function` | **ISO 9614-1 Annex A field indicators.**<br>• `pressure_levels`: Lpi per position [dB]<br>• `normal_intensity`: Signed Ini per position [W/m²]<br>• `temporal_intensity`: optional M short-time Ink samples at one fixed position, filling `f1` | `fi = emission.field_indicators(lp, i_n)`<br><br>• `FieldIndicators(f2, f3, f4, f1)` |
| `FieldIndicators` | `dataclass` | **ISO 9614-1 Annex A indicators.**<br>• `f1`: temporal variability indicator (Eq. A.1), or `None` when no `temporal_intensity` was given<br>• `f2`: surface pressure-intensity indicator (Eq. A.3)<br>• `f3`: negative partial power indicator (Eq. A.6)<br>• `f4`: field non-uniformity indicator (Eq. A.8)<br>• f3 − f2 > 0 reveals negative partial power<br>• `.field_is_stationary(limit=0.6)`: Table B.3 check on F1 | `fi.f2, fi.f3, fi.f4`<br><br>• Criteria: Ld > F2, N > C·F4² |
| `dynamic_capability_index` | `function` | **Dynamic capability Ld (ISO 9614-1 §3.12).**<br>• `pressure_residual_intensity_index`: δpI0 [dB]<br>• `bias_error_factor`: K [dB] (Default: 10.0) | `ld = emission.dynamic_capability_index(18.0)`<br><br>• Adequate when `Ld > F2` (criterion 1) |
| `temporal_variability_indicator` | `function` | **ISO 9614-1 temporal variability F1 (Eq. A.1).**<br>• `short_time_intensity`: M short-time-averaged signed In samples at one fixed position [W/m²], 1D `(samples,)` or 2D `(samples, bands)` | `f1 = emission.temporal_variability_indicator(samples)`<br><br>• Coefficient of variation of the M samples; Table B.3 acts above 0.6 |
| `TEMPORAL_VARIABILITY_LIMIT` | `constant` | **ISO 9614-1 Table B.3 limit on F1** (0.6): above it the field is too variable and action code (e) applies | `fi.field_is_stationary(TEMPORAL_VARIABILITY_LIMIT)` |
| `residual_index_limits` | `function` | **IEC 61043 Table 2 minimum δpI0.**<br>• `device`: `'probe'`, `'processor'` or `'instrument'` (Default: `'instrument'`)<br>• `spacing`: microphone separation [m] (Default: 0.025; Note 1 adds 10 lg(x/25))<br>• `frequencies`: bands to report (Default: all 22, 50 Hz to 6.3 kHz) | `f, c1, c2 = emission.residual_index_limits("probe", spacing=0.012)`<br><br>• `(frequencies, class1, class2)` minima [dB] |
| `verify_intensity_class` | `function` | **IEC 61043 Table 2 class check.**<br>• `residual_index`: measured δpI0 per band [dB]<br>• `frequencies`: band centres [Hz]<br>• keyword-only: `device`, `spacing`, as above | `res = emission.verify_intensity_class(d, f, spacing=0.012)`<br>`res.report("iec61043.pdf")`<br><br>• `IntensityInstrumentComplianceResult` |
| `IntensityInstrumentComplianceResult` | `dataclass` | **IEC 61043 instrument class verdict.**<br>• `overall_class`: loosest class every band meets (1/2), or `None`<br>• `bands`, `frequencies`, `residual_index`, `spacing`, `device`, `range_limited`<br>• read-only from the device and the separation: `limit_class1`, `limit_class2`, `spacing_offset_db`; the band rows and the class are read from them and the measured index<br>• `.binding_margin()` / `.failing_bands()` / `.reference_class()`<br>• `.phase_mismatch(speed_of_sound=343.0)`: equivalent channel phase error per band [deg]<br>• `.plot()`: measured δpI0 over the two Table 2 masks<br>• `.report(path, *, metadata=None)`: one-page PDF fiche<br>• takes `frequencies`, `residual_index`, `device`, `spacing`; `bands`, `overall_class`, `range_limited` are read-only, read from them | `res.overall_class, res.binding_margin()` |
| `instrument_class_from_components` | `function` | **IEC 61043 clause 8 combination rule.**<br>• `probe_class`, `processor_class`: 1 or 2 | `instrument_class_from_components(1, 2)`<br><br>• 1 only when both are class 1, else 2 |
| `phase_mismatch_from_residual_index` | `function` | **δpI0 → channel phase mismatch.**<br>• `residual_index`: δpI0 [dB]<br>• `frequency` [Hz], `spacing` [m], `speed_of_sound` (Default: 343.0)<br>• φs = kd·10^(−δpI0/10) | `phase_mismatch_from_residual_index(20.0, 1000.0, 0.025)`<br><br>• 0.26 degrees |
| `residual_index_from_phase_mismatch` | `function` | **Channel phase mismatch → δpI0.**<br>• `phase_mismatch`: φs [deg], > 0<br>• `frequency` [Hz], `spacing` [m], `speed_of_sound` (Default: 343.0)<br>• δpI0 = 10 lg(kd/φs) | `residual_index_from_phase_mismatch(0.05, 1000.0, 0.012)`<br><br>• 24.0 dB |
| `CalibrationWarning` | `warning class` | **Unreliable calibration recording.**<br>Emitted by `sensitivity` (with `fs` given and `validate=True`) when the tone is unstable (IEC 60942 limit) or too short | `warnings.simplefilter("error", CalibrationWarning)` |
| `lden` | `function` | **Day-evening-night level (ISO 1996-1 §3.6.4).**<br>• `lday`/`levening`/`lnight`: LAeq per period [dB]<br>• `hours`: Period durations (Default: (12, 4, 8)) | `l = environment.lden(63.2, 58.1, 51.4)` |
| `ldn` | `function` | **Day-night level (ISO 1996-1 §3.6.5).**<br>• `lday`/`lnight`: LAeq per period [dB]<br>• `hours`: Default (15, 9) | `l = environment.ldn(63.2, 51.4)` |
| `composite_rating_level` | `function` | **Whole-day composite rating (ISO 1996-1 §6.5).**<br>• `periods`: list of (level_db, hours, adjustment_db) summing 24 h | `r = environment.composite_rating_level([(63, 12, 0), (58, 4, 5), (51, 8, 10)])` |
| `assess_tonal_audibility` | `function` | **Tonal audibility & adjustment (ISO 1996-2 Annex C).**<br>• `tone_level` Lpt, `masking_noise_level` Lpn [dB]<br>• `centre_frequency` fc [Hz] | `res = environment.assess_tonal_audibility(54.1, 45.2, 430.0)`<br><br>• `TonalAssessmentResult` (`.audibility`, `.adjustment`, `.plot()`) |
| `tonal_audibility` | `function` | **ΔLta = Lpt−Lpn+2+lg[1+(fc/502)²·⁵] (Formula C.3).**<br>• `tone_level`, `masking_noise_level` [dB], `centre_frequency` [Hz] | `d = environment.tonal_audibility(54.1, 45.2, 430.0)  # 11.1 dB` |
| `tonal_adjustment` | `function` | **Kt(ΔLta) piecewise (Formulae C.4-C.6).**<br>• `audibility` ΔLta [dB] | `tonal_adjustment(7.0)  # 3.0 dB` |
| `tonal_adjustment_from_mean_audibility` | `function` | **Kt from mean audibility ΔL (ISO 1996-2 Table J.1).**<br>• `mean_audibility` [dB], `coarse` (Default: False) | `tonal_adjustment_from_mean_audibility(5.0)  # 3` |
| `critical_bandwidth` | `function` | **Critical bandwidth (ISO 1996-2 Table C.1).**<br>• `centre_frequency` [Hz] (100 Hz ≤ 500 Hz, else 20 %·fc) | `critical_bandwidth(4000.0)  # 800 Hz` |
| `tonal_seeking_survey` | `function` | **One-third-octave tonal screen (ISO 1996-2 Annex K).**<br>• `levels` [dB], `frequencies` [Hz] (15/8/5 dB neighbour rule) | `flags = environment.tonal_seeking_survey(levels, freqs)` |
| `NoisePhase` | `dataclass` | **Noise phase Ti of steady emission (RD 1367/2007 Annex IV A.3.4.2 b).**<br>• `hours` Ti [h], `laeq` background-corrected LAeq,Ti [dB]<br>• `kt`, `kf`, `ki` corrections [dB]; `label`<br>• `.correction` (capped at 9 dB), `.lkeq` | `NoisePhase(6, 50.0, kt=6, kf=3)  # LKeq,Ti = 59 dB` |
| `tonal_correction` | `function` | **Kt from an unweighted 1/3-octave spectrum (Annex IV A.3.3).**<br>• `levels` [dB], `frequencies` [Hz]<br>• Lt = Lf − Ls against the arithmetic mean of the two neighbours; 8/12, 5/8 and 3/5 dB thresholds by band range | `res = environment.tonal_correction(levels, freqs)`<br><br>• `TonalCorrectionResult` (`.correction`, `.plot()`) |
| `TonalCorrectionResult` | `dataclass` | **RD 1367/2007 tonal correction.**<br>• `correction` Kt [dB] (0/3/6), `governing_frequency`<br>• `differences` Lt and `band_corrections` per band (NaN where not evaluable)<br>• `frequencies`, `levels` | `res.correction, res.governing_frequency` |
| `low_frequency_correction` | `function` | **Kf from Lf = LCeq,Ti − LAeq,Ti (Annex IV A.3.3).**<br>• `lceq`, `laeq` [dB], background-corrected | `low_frequency_correction(63.0, 50.0)  # 3.0 dB` |
| `impulsive_correction` | `function` | **Ki from Li = LAIeq,Ti − LAeq,Ti (Annex IV A.3.3).**<br>• `laieq`, `laeq` [dB], background-corrected | `impulsive_correction(67.0, 50.0)  # 6.0 dB` |
| `total_correction` | `function` | **K = Kt + Kf + Ki, capped at 9 dB (Annex IV A.3.3).**<br>• `kt`, `kf`, `ki` [dB] | `total_correction(6, 3, 0)  # 9.0` |
| `corrected_level` | `function` | **LKeq,T = LAeq,T + Kt + Kf + Ki (Annex I A.2 c).**<br>• `laeq` [dB]; `kt`, `kf`, `ki` [dB] | `corrected_level(50.0, kt=6, kf=3)  # 59.0 dB` |
| `evaluation_period_level` | `function` | **LKeq,T from its noise phases (Annex IV A.3.4.2 b).**<br>• `phases`: `NoisePhase` list<br>• `hours` T [h] (None = sum of Ti) | `evaluation_period_level(phases, hours=12)` |
| `long_term_corrected_level` | `function` | **Annual LK,x, energy mean of the daily levels (Annex I A.2 d).**<br>• `daily_levels` [dB]; `weights`: days each level represents | `long_term_corrected_level([57, 0], weights=[303, 62])  # 56.2` |
| `round_reported_level` | `function` | **Rounding of Annex IV A.3.4.2: add 0,5 dB, take the integer part.**<br>• `value` [dB] | `round_reported_level(56.82)  # 57` |
| `outdoor_quality_objectives` | `function` | **Outdoor quality objectives Ld/Le/Ln (Annex II Table A).**<br>• `area_type`: 'e','a','d','c','b' or an alias<br>• `urbanisation`: 'existing' or 'new' (−5 dB, Article 14.2) | `outdoor_quality_objectives("a")  # 65/65/55 dB` |
| `indoor_quality_objectives` | `function` | **Indoor quality objectives (Annex II Table B).**<br>• `building_use`: 'residential','sanitary','educational'<br>• `room_type`: 'living','bedrooms','classrooms','reading_rooms' | `indoor_quality_objectives("residential", "bedrooms")` |
| `vibration_quality_objective` | `function` | **Indoor vibration objective Law [dB] (Annex II Table C).**<br>• `building_use` | `vibration_quality_objective("residential")  # 75.0` |
| `infrastructure_limits` | `function` | **Immission limits for new transport infrastructure (Annex III Table A1).**<br>• `area_type` | `infrastructure_limits("a")  # 60/60/50 dB` |
| `max_infrastructure_limit` | `function` | **LAmax limit for rail and airport infrastructure (Annex III Table A2).**<br>• `area_type` | `max_infrastructure_limit("a")  # 85.0 dB` |
| `activity_limits` | `function` | **Outdoor limits for activities and ports (Annex III Table B1).**<br>• `area_type` | `activity_limits("a")  # LK,d/e/n = 55/55/45 dB` |
| `adjacent_premises_limits` | `function` | **Noise transmitted to acoustically adjacent premises (Annex III Table B2).**<br>• `building_use`, `room_type` | `adjacent_premises_limits("residential", "bedrooms")` |
| `RegulationLimits` | `dataclass` | **A day/evening/night limit triple of RD 1367/2007.**<br>• `day`, `evening`, `night` [dB]; `index`, `reference`, `description`<br>• Indexable by period; `.as_dict()` | `lim["night"]` |
| `assess_activity` | `function` | **Article 25 compliance of an activity or port.**<br>• `measurements`: phases keyed by period<br>• `limits`: a `RegulationLimits` row<br>• `long_term_levels` or `operating_days` / `year_days` / `closed_level`<br>• `new_activity` (Default: True; False = Article 25.2)<br>• `period_hours` | `v = environment.assess_activity({"day": day}, environment.activity_limits("a"), operating_days=303)`<br><br>• `ActivityAssessment` |
| `ActivityAssessment` | `dataclass` | **RD 1367/2007 activity verdict.**<br>• `periods`: `PeriodAssessment` tuple; `limits`; `new_activity`<br>• `.complies`<br>• `.plot()`; `.report(path, language='es')`: one-page inspection fiche → PDF | `v.complies`<br>`v.report("acta.pdf")` |
| `PeriodAssessment` | `dataclass` | **One evaluation period against its limit.**<br>• `evaluation_period_level`, `reported_level` (rounded)<br>• `long_term_corrected_level`, `reported_long_term`<br>• `limit`, `daily_limit` (+3), `phase_limit` (+5), `max_phase_level`<br>• `phase_pass`, `daily_pass`, `long_term_pass`, `.complies`<br>• takes `period`, `phases`, `duration_hours`, `evaluation_period_level`, `long_term_corrected_level`, `limit`, `new_activity`; `reported_level`, `reported_long_term`, `max_phase_level`, `phase_pass`, `daily_pass`, `long_term_pass` are read-only, read from them | `p.reported_level, p.long_term_pass` |
| `ACOUSTIC_AREA_TYPES` | `constant` | **Acoustic area types of Article 7 of Ley 37/2003, keyed by letter.**<br>e sanitary/educational/cultural, a residential, d tertiary, c recreational, b industrial, f transport systems | `ACOUSTIC_AREA_TYPES["a"]` |
| `RD1367_EVALUATION_PERIODS` | `constant` | **The three daily evaluation periods (Annex I A.1).** | `("day", "evening", "night")` |
| `RD1367_PERIOD_HOURS` | `constant` | **Default period durations [h] (Annex I A.1 a).** | `{"day": 12, "evening": 4, "night": 8}` |
| `RD1367_PERIOD_CLOCK_LIMITS` | `constant` | **Local-time start/end hour of each period (Annex I A.1 b).** | `{"day": (7, 19), ...}` |
| `RD1367_CORRECTION_VALUES` | `constant` | **The only values a single correction takes (Annex IV A.3.3).**<br>Each table grades its parameter 0, 3 or 6 dB | `RD1367_CORRECTION_VALUES  # (0.0, 3.0, 6.0)` |
| `RD1367_MAX_CORRECTION` | `constant` | **Cap on Kt + Kf + Ki [dB] (Annex IV A.3.3).** | `9.0` |
| `residual_sound_correction` | `function` | **Residual-noise correction L = 10 lg(10^(L'/10)−10^(Lres/10)) (Formula 16).**<br>• `measured_level` L', `residual_level` Lres [dB] | `res = environment.residual_sound_correction(58.0, 50.0)`<br><br>• `ResidualCorrectionResult` (`.corrected_level`, `.reportable_upper_bound`, `.reliable`) |
| `gaussian_residual_level` | `function` | **Residual Leq from percentiles (ISO 1996-2 Annex I).**<br>• `l50` [dB]; exactly one of `l90` / `l95` (must not exceed `l50`) | `gaussian_residual_level(50.0, l90=40.0)` |
| `combined_standard_uncertainty` | `function` | **u = √(Σ(cj·uj)²) (ISO 1996-2 Formula 2).**<br>• `contributions`: cj·uj products or (uj, cj) pairs | `u = environment.combined_standard_uncertainty([0.59, 0.3, 2.0, 0.40, 0.38])  # 2.18` |
| `environmental_expanded_uncertainty` | `function` | **U = k·u (ISO 1996-2 §4).**<br>• `standard_uncertainty` [dB], `confidence` 0.95 (k=2) / 0.80 (k=1.3) | `environment.environmental_expanded_uncertainty(2.18)  # 4.36` |
| `residual_correction_uncertainty` | `function` | **Uncertainty of the residual-corrected level (Formulae F.7-F.9).**<br>• `measured_level`, `residual_level`, `measured_uncertainty`, `residual_uncertainty` [dB] | `residual_correction_uncertainty(58, 50, 0.5, 2.0)` |
| `uncertainty_from_repeated_measurements` | `function` | **Energy mean & uncertainty from repeats: primary Formulae (17)+(19) route, Formula (20) approximation alongside.**<br>• `levels` [dB] (≥ 2); warns when they spread > 3 dB | `res = environment.uncertainty_from_repeated_measurements(levels)`<br><br>• `RepeatedMeasurementResult` |
| `TonalAssessmentResult` | `dataclass` | **Tonal assessment (ISO 1996-2).**<br>• `audibility` ΔLta, `adjustment` Kt [dB]<br>• `centre_frequency`, `critical_bandwidth`; `.plot()` | `res.audibility, res.adjustment` |
| `ResidualCorrectionResult` | `dataclass` | **Residual-corrected level (ISO 1996-2).**<br>• `corrected_level` [dB], `reportable_upper_bound` = measured L' [dB], `margin` [dB], `reliable` (> 3 dB; when False report the upper bound, not the correction)<br>• takes `corrected_level`, `reportable_upper_bound`, `margin`; `reliable` is read-only, read from them | `res.corrected_level, res.reliable` |
| `EnvironmentalMeasurementWarning` | `warning class` | **Unreliable environmental-noise determination (ISO 1996-2:2017).**<br>• Residual within 3 dB of the measured level: no correction is allowed and only `reportable_upper_bound` may be reported (10.4)<br>• Repeated levels spreading more than 3 dB: `approximate_uncertainty` (Formula (20)) is unreliable there (10.5 Note 2)<br>• Subclass of `PhonometryWarning` | `warnings.simplefilter('error', EnvironmentalMeasurementWarning)`<br>Emitted by `environment.assessment.measurement` |
| `RepeatedMeasurementResult` | `dataclass` | **Repeat-measurement mean & uncertainty (ISO 1996-2).**<br>• `mean_level`, `standard_uncertainty` (Formulae (17)+(19)), `approximate_uncertainty` (Formula (20)) [dB], `n` | `res.mean_level, res.standard_uncertainty` |
| `linkwitz_riley` | `function` | **Audio crossover.**<br>• `x`: Signal array<br>• `fs`: Sample rate [Hz]<br>• `frequency`: Crossover frequency [Hz]<br>• `order`: Any even number (Default: 4) | `lo, hi = filters.linkwitz_riley(x, fs, frequency=1000, order=4)`<br><br>• `lo`: Low-pass filtered signal<br>• `hi`: High-pass filtered signal |
| `parametric_eq` | `function` | **Parametric EQ, one shot (RBJ Audio EQ Cookbook).**<br>• `x`: Signal array (1D or 2D `[channels, samples]`)<br>• `fs`: Sample rate [Hz]<br>• `sections`: an `EQSection` or a sequence of them | `y = filters.parametric_eq(x, fs, sections=filters.EQSection("peaking", 1000, gain_db=6.0))` |
| `ParametricEQ` | `class` | **Reusable parametric-EQ cascade (RBJ Audio EQ Cookbook).**<br>• `fs`: Sample rate [Hz]<br>• `sections`: `EQSection` or sequence of them (cascade order)<br>• `stateful`: Block processing (Default: False)<br>• `steady_ic`: Steady-state initial conditions (Default: False)<br>• `.sos`: the designed cascade, `.filter(x)`, `.response()` | `eq = filters.ParametricEQ(fs, sections)`<br>`y = eq.filter(x)`<br>`res = eq.response()` |
| `EQSection` | `dataclass` | **One cookbook biquad specification.**<br>• `filter_type`: 'peaking', 'lowshelf', 'highshelf', 'lowpass', 'highpass', 'bandpass', 'bandpass_skirt', 'notch', 'allpass'<br>• `f0`: Centre/corner frequency [Hz]<br>• `gain_db`: Gain (peaking/shelves) [dB]<br>• One of `q` (Default: 1/√2), `bw` [octaves] or `slope` (shelves) | `EQSection("peaking", 1000.0, gain_db=-6.0, bw=1.0)` |
| `EQResponseResult` | `dataclass` | **Parametric-EQ cascade response.**<br>• `frequencies` [Hz], `magnitude_db` [dB], `phase_rad` [rad]<br>• `section_magnitude_db`: per-section magnitudes [dB]<br>• `sos`: the cascade, `fs`, `sections`; `.plot()` magnitude + phase | `res = eq.response()`<br>`res.plot()` |
| `sensitivity` | `function`| **SPL Calibration.**<br>• `ref_signal`: Calibration signal<br>• `target_spl`: Level of calibrator (Default: 94.0)<br>• `reference_pressure_pa`: Reference pressure (Default: 20e-6)<br>• `frequency`, `calibrator_class`: select the IEC 60942 Table 2 fluctuation limit the take is screened with (Default: 1000.0, `'1'`)<br>• `narrowband`: coherent Goertzel tone estimate that rejects broadband hum/noise (needs `fs`; Default: False) | `s = sensitivity(ref_signal, target_spl=94.0)`<br><br>• `s`: Float (multiplier for pressure) |
| `read` | `function` | **Read a measurement audio file into a `Signal`.**<br>• `path`: WAV/BWF/RF64 in the base install; FLAC, AIFF, Ogg/Opus, MP3 with `[audio]`<br>• `calibration_factor`: digital units → Pa (Default: None; an existing sidecar is applied automatically, an explicit value wins)<br>Native fs kept, no downmix, no normalization; int PCM scaled by 2^(bits−1); lossy sources raise `LossyCompressionWarning` | `sig = io.read("night.wav")`<br><br>• `sig`: `Signal` (float64, (channels, samples), with fs, calibration, `bext`, labels) |
| `info` | `function` | **Describe a file from its headers alone.**<br>• `path`: any supported container<br>No sample is decoded, so a 12-hour RF64 answers instantly; compressed WAV that `read` refuses still describes itself | `meta = io.info("night.wav")`<br><br>• `meta`: `AudioFileInfo` |
| `read_blocks` | `function` | **Stream a file block by block.**<br>• `path`, `block_size` [samples]<br>• `overlap`: samples shared between consecutive blocks (Default: 0)<br>• `calibration_factor`: as in `read`; `None` takes the sidecar's (Default: `None`)<br>Yields exactly what `read` returns, in slices: feeds `BlockProcessing(stateful=True)` unchanged | `for block in io.read_blocks(p, 65536): ...`<br><br>• each `block`: a `Signal` with the rate, calibration, labels and provenance `read` gives |
| `write` | `function` | **Write WAV/BWF (FLAC with `[audio]`) without touching the level.**<br>• `path`, `x` (array or `Signal`), `fs` (taken from `x` when `x` is a `Signal`)<br>• `subtype`: 'PCM_16'/'PCM_24'/'PCM_32'/'FLOAT'/'DOUBLE' (Default: FLOAT for float data, the matching depth for integer pass-through; FLAC: PCM up to 24)<br>• `bext`: None (Default) carries a `Signal`'s own provenance; `"loudness"` also measures the five EBU R 128 fields in-house; a `BroadcastMetadata` is written as given<br>• `dither`: 'tpdf' at PCM_16 only (Default: None)<br>• `rng`: `numpy.random.Generator` or int seed for the dither noise, for byte-reproducible writes (Default: None = fresh entropy)<br>• `sidecar`: write the calibration sidecar too (Default: False)<br>Never normalizes; clipping saturates, is counted and warns (`ClippingWarning`); RF64 automatic past 4 GiB | `io.write("out.wav", sig, subtype="PCM_24")` |
| `convert` | `function` | **Convert between lossless containers with the measurement intact.**<br>• `src`, `dst`: WAV/BWF/RF64 ↔ FLAC (lossy targets refused)<br>Samples bit-exact at full precision, `bext` carried (into FLAC via the `riff` APPLICATION block), sidecar copied byte for byte, CodingHistory extended one line; streams, so an hour of RF64 converts flat | `io.convert("night.wav", "night.flac")` |
| `Signal` | `dataclass` | **Samples plus the metadata they need.**<br>• `data`: (channels, samples) float64<br>• `fs` [Hz]<br>• `calibration_factor`: Pa per digital unit, or None until known<br>• `channel_labels`, `provenance` (`bext`), `source` (`SignalOrigin`)<br>`np.asarray(sig)` yields the bare array (1D mono), so every `(x, fs, ...)` function accepts it; `leq`/`laeq`/`ln_levels`/`sel`/`lc_peak`/`sound_exposure`/`lex_8h` read fs and calibration from it directly | `sig.duration`, `sig.n_channels`<br>`sig.plot()` draws the calibrated waveform |
| `SignalOrigin` | `dataclass` | **Where a `Signal` came from.**<br>• `path`, `container`, `format_name`<br>• `bit_depth`: valid bits, None for lossy codecs<br>• `lossy`: the read-time warning, kept attached to the data | `sig.source.lossy` |
| `AudioFileInfo` | `dataclass` | **Everything `info()` reads from the headers.**<br>• `container`, `format_name`, `fs`, `channels`, `frames`, `duration`, `bit_depth`, `lossy`<br>• `channel_mask` / `channel_labels` (EXTENSIBLE speaker positions)<br>• `bext`, `has_ixml`, `cue_points` | `io.info(p).duration` |
| `BroadcastMetadata` | `dataclass` | **The `bext` chunk of EBU Tech 3285 v2, field by field.**<br>• `description`, `originator`, `originator_reference`, `origination_date`/`_time`<br>• `time_reference`: 64-bit samples since midnight<br>• `version`, `umid`<br>• v2 loudness: `loudness_value`, `loudness_range`, `max_true_peak_level`, `max_momentary_loudness`, `max_short_term_loudness` (0x7FFF sentinel → None)<br>• `coding_history` (EBU R98) | `io.info(p).bext.time_reference` |
| `CuePoint` | `dataclass` | **One marker of a WAV `cue ` chunk.**<br>• `cue_id`, `position` [samples], plus the raw `chunk_id`/`chunk_start`/`block_start`/`sample_offset` fields of the spec | `io.info(p).cue_points` |
| `CalibrationSidecar` | `dataclass` | **The versioned JSON sidecar that carries the calibration.**<br>• `calibration_factor`, `reference_spl`, `calibrator_frequency`, `calibrator_model`, `channel_labels`, `phonometry_version`<br>Lives at `<audio>.phonometry.json`; applied automatically by `read` | `io.read("m.wav").calibration_factor` |
| `read_sidecar` / `write_sidecar` / `sidecar_path` | `function` | **Sidecar round-trip.**<br>• `read_sidecar(path)`: the sidecar next to an audio file, or None (foreign or newer schema refused loudly)<br>• `write_sidecar(path, calibration_factor, ...)`: write one, with the optional calibrator tone metadata<br>• `sidecar_path(path)`: where it lives | `io.write_sidecar("m.wav", cal, reference_spl=94.0)` |
| `LossyCompressionWarning` | `warning class` | **A lossy decoder produced these samples** (MP3/Ogg/Opus/ADPCM): levels are not metrologically defensible. Subclass of `PhonometryWarning`<br>Emitted by `io.read` / `io.read_blocks` / `io.convert` | `warnings.simplefilter('error', io.LossyCompressionWarning)` |
| `ClippingWarning` | `warning class` | **Samples clipped while quantizing on write:** count and peak overshoot in dBFS; the file is written with saturated codes rather than wrapped ones. Subclass of `PhonometryWarning`<br>Emitted by `io.write` | `warnings.simplefilter('error', io.ClippingWarning)` |
| `CatalogueRow` | `dataclass` | **The row every published catalogue hands out, with what each cell said.**<br>• `name`, `source` (document, table, PDF page and printed folio), `table`, `variant`, `group`, `note`<br>• A quantity is `None` when the page had something other than a number there, and `ranges`, `bounded_above` / `bounded_below`, `reported`, `unquantified`, `uncertainty`, `not_derivable` and `misprinted` say what<br>• `basis`: field or `'row'` → what the source claims the value is, one of `CATALOGUE_BASES`; `.basis_of(field)` reads it, and `''` means the source does not say<br>• `derived`: field → how this library computed it, written by `.from_printed` on every row the library builds (one passed to `Cls(...)` is the caller's, and `.printed_fields()` leaves it out with its value); `converted`: field → the page's figure and its unit, `(figure, unit)`, for a value held in a unit the page does not use; `carried`: field → the row the page gives it on, for a value it gives by reference to another row<br>• `.from_printed(**cells)` builds a row and fills what follows from its cells, `.printed_fields()` gives the cells back; `.printed(field)` narrows or refuses, `.why_missing(field)` says what the page had, `.is_derived(field)`, `.is_approximate(field)`<br>• Checks itself when built, whoever builds it, and raises `CatalogueError` for a cell nothing downstream can read: a number that is `NaN`, a `bool` or a text, a hedge on a field the class does not have, a bound with no range, a value beside `misprinted`, a density or a length below zero, a porosity above 1; sets and mappings frozen all the way down<br>• `provenance`: the `Provenance` of a row read from a catalogue file of yours, `None` on every packaged row; `.why_missing` names the document by its kind ('the datasheet prints ...', 'the page' without one) and quotes a converted figure before the value the row holds<br>Frozen and keyword-only; a subclass leaves out `slots=True` and annotates its fields `float \| None`, `int \| None`, `bool`, `str`, `frozenset[str]` or `Mapping[str, ...]`, anything else (a bare `float` or `int` too) a `TypeError` | `row = solids.PUBLISHED_SOLIDS['hopkins-2007-table-a2/aircrete']`<br>`row.basis_of('poisson_ratio')  # 'estimated'` |
| `BandedRow` | `dataclass` | **A catalogue row that prints one value per frequency band.**<br>• One field per band, so every hedge of `CatalogueRow` applies to a band as to any other cell<br>• `.bands()`: the bands the row prints; `.spectrum()`: `{band_hz: value}` over them, a band the page left empty left out rather than read as zero; `.values_at(frequencies_hz)`: the row at an array of frequencies | `materials.PUBLISHED_ABSORPTION['bies-2017-table-6-2/unoccupied_heavily_upholstered_seats'].spectrum()[500]  # 0.81` |
| `CatalogueRow.from_printed` | `classmethod` | **A row built from the cells its page prints, completed and marked.**<br>• `**cells`: the printed cells under the class's field names, with their hedges, as a data file writes them<br>• Checks every cell as the constructor does, then fills what follows from them (a modulus from a plate speed, a density and a Poisson ratio) and names each filled value in `derived`, never over a printed value or a hedged cell; when the printed cells a value rests on do not share one `basis`, the text names the basis of each<br>• Cells the arithmetic refuses (a modulus and a shear modulus no isotropic solid has together) raise `CatalogueError` naming them, unless `not_derivable` says the value does not follow<br>• A figure in another unit of the same kind as its field (`thickness_m` for `thickness_mm`, `flow_resistivity_kpa_s_m2`, `temperature_k`), or under a unit the class takes as an alias of its own (`absorption_area_125_ft2` on `AbsorptionAreaSpectrum`), as a value or as the key of a hedge, is converted on its digits with an exact factor, rounded once, and recorded in `converted`; every number of one cell in one unit<br>• The one path that works anything out, and every packaged catalogue is built through it; `Cls(...)` stays literal. A `derived` among the cells raises `CatalogueError` | `row = solids.SolidMaterial.from_printed(name='Board', source='...', density_kg_m3=860.0, plate_longitudinal_speed_m_s=1490.0, poisson_ratio=0.3)`<br>`row.is_derived('youngs_modulus_pa')  # True` |
| `CatalogueRow.printed_fields` | `method` | **The cells the page prints, as `from_printed` takes them.**<br>• Every field, hedges, `converted` and `carried` included, without the derived values, without `derived`, and without a field left at a default that holds nothing; an empty `per` stays, since its default is a person<br>• `type(row).from_printed(**row.printed_fields())` is the row again for every row `.from_printed` builds. Change a cell here and build again to edit a row: `dataclasses.replace` keeps derived values that no longer follow from the cell that changed | `cells = row.printed_fields()`<br>`cells['density_kg_m3'] = 2400.0`<br>`row = type(row).from_printed(**cells)` |
| `BandedRow.values_at` | `method` | **The row at an array of frequencies, one band per frequency.**<br>• `frequencies_hz`: band centres [Hz], any shape; each matches the band whose centre is nearest on a logarithmic scale, within a sixth of the band spacing, so a nominal, an exact base-ten and an exact base-two centre read the same band<br>• A band the row does not print raises `ValueError` with what the page had there, never a zero; a frequency between bands raises naming the nearest<br>• For a function that takes one value per band by position: the surfaces of `room.sabine_reverberation_time`, or `noise_control.enclosure_insertion_loss` given `row.values_at` as its transmission loss | `seats.values_at([125.0, 250.0, 500.0])`<br><br>• a new float64 array of the frequencies' shape |
| `CatalogueError` | `exception` | **A catalogue that does not say what a reader needs to trust it.**<br>A table without its citation or its rows, two rows under one key, a `NaN` or a name written twice in its JSON, a `/` in a row key; a row that breaks the contract it is checked against when built, from a file or by hand; the problems of a catalogue file, raised together<br>• `.issues`: each problem, a `CatalogueIssue` with its place (every problem of form in a file, and the first rule of the row contract each row breaks); a row built in Python raises one at `'<Python>'`<br>Subclass of `ValueError` | `except io.CatalogueError as error: error.issues` |
| `CATALOGUE_BASES` | `constant` | **What a source can claim a value is.**<br>`'measured'`, `'declared'`, `'calculated'`, `'estimated'` and `'extended'`; no entry means the source does not say | `'estimated' in io.CATALOGUE_BASES  # True` |
| `Provenance` | `dataclass` | **Which document a catalogue's cells were read from.**<br>• `kind`: one of `PROVENANCE_KINDS`; `document`; `version` (`None` when the document prints none); `consulted`: the day it was read, `YYYY-MM-DD`<br>• `publisher`, `issued` (`YYYY`, `YYYY-MM` or `YYYY-MM-DD`), `url` and `sha256` (never opened or checked), `page`, `printed_table`, `laboratory`, `accreditation`, `report`, `test_date`, `test_standard`<br>• `field_test_standards`: field → the standard cited for that property alone, over `test_standard`; `.test_standard_of(field)` reads it<br>• `.noun`: the document as a refusal names it; `.cited()`: the `source` of every row read with it (a publication as its document is cited; any other kind with its publisher, version, page, table, report, laboratory and the day consulted)<br>Frozen and keyword-only, not hashable | `p = io.Provenance(kind='datasheet', document='Panel 40 technical data sheet', version='Rev. 4', consulted='2026-09-23')`<br>`p.noun  # 'the datasheet'` |
| `PROVENANCE_KINDS` | `constant` | **What kind of document a catalogue is read from.**<br>`'datasheet'`, `'declaration_of_performance'`, `'test_report'`, `'measurement'`, `'calculation'`, `'publication'` and `'other'` | `'test_report' in io.PROVENANCE_KINDS  # True` |
| `read_catalogue` | `function` | **Read a catalogue of your own from a JSON file, or from a CSV file with its JSON header.**<br>• `path`: a name ending in `.json` or `.csv`, any case<br>• `row_type`: the row class, a `CatalogueRow` subclass such as `materials.PorousMaterial`; the class the file names is only compared with it, never imported<br>• `header_path`: the JSON header of a CSV file, where it is not the one beside it, named as the file with `.phonometry.json` after it (Default: None)<br>A CSV file holds the rows, each starting on a line of its own, under a first line naming the columns (`key`, the fields, `basis`, `attributed_to.row` for the credit of the row, `provenance.page` and the other six `provenance.*`, `x-...`), and the credit of the whole table in the header's `attributed_to`; each cell holds one value, bound, range or word (`0,85`, `~0,85`, `<=30`, `>=5`, `0,30..0,50`, `0,85±0,05`, `[AFr5]`, `true`) in the delimiter and decimal mark the header declares, never guessed; UTF-8 with or without a byte order mark. Every row is built through `.from_printed` and carries the document's `Provenance`; a cell may be written in another unit of the same kind (`thickness_m`, `flow_resistivity_kpa_s_m2`, as a value or as the key of a hedge), converted on its digits and recorded in `converted`. The problems in the file raise together, in one `CatalogueError` whose issues carry a JSON pointer, or a line and a column of the CSV file: every problem of form, and the first rule of the row contract each row breaks; notes ride on the result with one `CatalogueWarning`. A regular file of 16 MiB, 50 000 rows and six levels of nesting at most, and a CSV file's header a regular file of 64 KiB; a pipe, a device or a directory at the name of either is refused before it is opened | `mine = io.read_catalogue('panel-40.json', row_type=materials.PorousMaterial)`<br><br>• `mine`: `Catalogue` |
| `parse_catalogue` | `function` | **The same, from JSON text or a mapping in memory.**<br>• `document`: text, or a mapping of the same shape<br>• `row_type`; `label`: what names the document in every issue (Default: `'<document>'`)<br>A mapping has no printed digits, so a figure in another unit converts from the `repr` of its float | `mine = io.parse_catalogue(text, row_type=materials.PorousMaterial)` |
| `write_catalogue` | `function` | **Write rows as a catalogue file that reads back into the same rows.**<br>• `rows`: a `Catalogue`, or a mapping of rows of one class, a published table among them<br>• `path`: a name ending in `.json` or `.csv`; a CSV file is written with its JSON header beside it<br>• `catalogue`, `about`, `provenance`: what the rows do not bring (a published table needs a `catalogue` name of your own, and takes the table's `about` and legends and a publication consulted on the day of the export)<br>• `delimiter`, `decimal`: the dialect of a CSV file, `','`, `';'` or a tab and `'.'` or `','` (Default: `','` and `'.'`); a decimal comma never between commas<br>• `overwrite`: replace a file already there, and its header (Default: False)<br>A CSV file is UTF-8 with a byte order mark, and a text a spreadsheet would run as a formula is written after an apostrophe the reader takes off; a row's credit is written in its `attributed_to.row` column and the credit every row gives the table in the header; what one cell cannot hold (several readings, a misprint, a carried cell, a credit, a basis or a standard for one cell, a table the rows credit apart) is refused at its JSON pointer and nothing is written. The cells each page prints, never a derived value; a converted value in the unit it was read in when that reads back to the same float. Each file written beside its name and renamed into place (a CSV file and its header are two files, not written as one); a symbolic link is never followed | `io.write_catalogue(a2, 'template.json', catalogue='template-a2')`<br><br>• returns the paths written |
| `catalogue_schema` | `function` | **The JSON Schema of a catalogue document, for an editor to complete a file as it is typed.**<br>• `*row_types`: one or more row classes, a `CatalogueRow` subclass of your own among them<br>Dialect 2020-12, `$id` `urn:phonometry:schema:catalogue:1`: the top-level keys, the provenance and its kinds, every field of each class under its own name and every other unit the reader converts (`thickness_m` beside `thickness_mm`), the fields each hedge may name, the words of `basis`, the limits a field's unit sets (a density never negative, a porosity from 0 to 1), and a CSV file's header with its dialect. It holds a file to its form; what depends on two cells at once is the reader's to refuse, so a document the reader reads is never refused by it. A document may point at it with a top-level `$schema`, which the reader never reads. The documentation site publishes the schema of every published row class as `schemas/phonometry-catalogue-1.json`<br>`TypeError` for no class, a class that is not a row class (a `Fluid` among them) or two classes sharing a name | `json.dumps(io.catalogue_schema(materials.PorousMaterial))`<br><br>• a new `dict`, ready for `json.dump` |
| `Catalogue` | `dataclass` | **A catalogue of your own: rows of one class, keyed `'<name>/<key>'`.**<br>• A read-only mapping, so it goes wherever a `PUBLISHED_*` catalogue goes; `PUBLISHED_POROUS \| mine` joins the two and refuses a key both hold, at every join<br>• `name`, `row_type`, `about`, `provenance` (the document's), `rows`, `extras` (your `x-...` columns, as text), `conventions`, `notes`, `schema_version`, `file_sha256` (of the bytes read: the JSON document, or the CSV file), `header_sha256` (of a CSV file's header; empty otherwise)<br>Equal to any mapping of the same rows under the same keys | `mine['panel-40/core-lab'].basis_of('flow_resistivity_pa_s_m2')  # 'measured'` |
| `CatalogueIssue` | `dataclass` | **One problem in a catalogue, or one note, and where.**<br>• `file`, `location` (a JSON pointer; a line and a column of a CSV file, `'line 3, column E (porosity)'`; or `'<Python>'` for a row built in Python), `row_key`, `field`, `message`<br>• `severity`: `'error'` or `'note'`<br>`str()` is one line: file, place, row and message | `error.issues[0].location  # '/rows/1/porosity'` |
| `CatalogueWarning` | `warning class` | **A catalogue was read with notes on it:** a measured value with no report or laboratory named, a word in place of a number long enough to be a sentence, or what the row's own class notes. Nothing is changed; the notes are in `Catalogue.notes`. Subclass of `PhonometryWarning`<br>Emitted once per document by `io.read_catalogue` and `io.parse_catalogue` | `warnings.simplefilter('error', io.CatalogueWarning)` |
| `verify_filter_class` | `function` | **IEC 61260 class check of a bank design.** Each band is read at the bank's input rate up to half of it, the alias images of a decimated band included. For `'2014'` it grades Table 1 (5.10), the effective bandwidth deviation (5.12) and the summation of output signals (5.16), the last two as IEC 61260-2:2016 tests them (Formulas (1) to (3)); for `'1995'` Table 1, the filter integrated response (4.5.3) and the summation of output signals (4.9), as its clause 5 tests them.<br>• `bank`: an `OctaveFilterBank`<br>• keyword-only: `num_points`, frequency grid points per band on its decimated half-band, the images read at the same spacing (Default: 32768)<br>• keyword-only: `edition`, `'2014'` (classes 1/2, default) or `'1995'` (IEC 61260:1995 / ANSI S1.11-2004, adds class 0)<br>• keyword-only: `points_per_bandwidth`, S of IEC 61260-2 Formula (1), at least 24; for `'1995'` where S starts, raised in steps of 12 as its 5.3.3 asks (Default: 24) | `result = filters.verify_filter_class(bank)`<br>`result.requirement_class("summation")`<br><br>• `FilterComplianceResult` |
| `FilterComplianceResult` | `dataclass` | **IEC 61260 filter class-compliance result.**<br>• `overall_class`: strictest class every band meets on every requirement graded: 1/2 (`'2014'`), 0/1/2 (`'1995'`), or `None`<br>• `bands`: per-band verdict dictionaries, with `bandwidth_deviation_db` and `summation_min_db` / `summation_max_db`<br>• `requirements`, `.requirement_class(name)`, `.binding_margin_db(name, cls)`: each requirement on its own<br>• `range_limited`: stop-band mask beyond half the input sampling rate not exercised<br>• `.available_classes()` / `.reference_class()`: the edition's classes and the fiche's reference class<br>• `.plot(requirement=...)`: the relative attenuation over its corridor (default), `'effective_bandwidth'` or `'summation'`<br>• `.report(path, *, metadata=None, required_class via metadata)`: one-page PDF fiche<br>• takes `band_margins` (held as read-only copies), `fraction`, `edition`, `sos`, `band_frequencies`, `factors`, `fs`, `num_points`, `points_per_bandwidth`; `bands`, `overall_class`, `range_limited` are read-only, read from them | `verify_filter_class(bank).report("iec61260.pdf")` |
| `verify_time_invariance` | `function` | **Time-invariant operation of a bank, IEC 61260-1:2014 5.14 (IEC 61260-2:2016 7.4).** An exponential sweep through the bank itself, decimation included, against Formula (17), ±0.4 dB (class 1) or ±0.6 dB (class 2).<br>• `bank`: an `OctaveFilterBank`<br>• keyword-only: `seconds_per_decade`, the sweep rates, each 2 s to 5 s (Default: `(2.0, 5.0)`) | `res = filters.verify_time_invariance(bank)`<br><br>• `TimeInvarianceResult` |
| `TimeInvarianceResult` | `dataclass` | **The swept verdict of a bank.**<br>• `output_levels_db` / `expected_levels_db`: (rates, bands), re the sweep level; `deviations_db`<br>• `band_classes`, `overall_class`, `worst_deviation_db`<br>• `seconds_per_decade`, `start_frequency_hz`, `end_frequency_hz`, `sweep_durations_s`, `averaging_times_s`<br>• no truth value; `.plot()` draws each band's deviation per rate | `res.overall_class` |
| `swept_band_level` | `function` | **IEC 61260-1:2014 Formula (17): the time-averaged output of an exponential sweep.**<br>• `input_level_db`<br>• keyword-only: `fraction`, `sweep_duration_s`, `averaging_time_s`, `start_frequency_hz`, `end_frequency_hz`, `reference_attenuation_db` (Default: 0) | `filters.swept_band_level(127.0, fraction=3, sweep_duration_s=30, averaging_time_s=30, start_frequency_hz=0.01, end_frequency_hz=1e6)`<br><br>• `107.969...` (IEC 61260-2 and -3 Annex B, 107,97 dB) |
| `swept_level_uncertainty` | `function` | **The standard uncertainty of Formula (17) from the sweep, Annex A of IEC 61260-2 and -3.** Formula (A.2) with the square its printed form drops (see the errata registry)<br>• keyword-only: `input_level_uncertainty_db`, `sweep_duration_s`, `sweep_duration_uncertainty_s`, `averaging_time_s`, `averaging_time_uncertainty_s`, `start_frequency_hz`, `start_frequency_uncertainty_hz`, `end_frequency_hz`, `end_frequency_uncertainty_hz`, `display_resolution_db` (Default: 0) | `u = filters.swept_level_uncertainty(...)`<br><br>• `u` [dB], standard; `2 * u` the expanded (0.115 dB in A.3.5) |
| `periodic_test_frequencies` | `function` | **The 15 test frequencies of IEC 61260-3:2016 Clause 13**, Formulas (1) and (2), k = -7 .. 7, any bandwidth designator<br>• `fraction`: b (1, 3, ...) | `omega = filters.periodic_test_frequencies(3)`<br><br>• read-only array of Ω_k; `omega[8]  # 1.02667` (Table C.1) |
| `PERIODIC_TEST_ATTENUATION_LIMITS_DB` | `mapping` | **IEC 61260-3:2016 Table 1**: class → the minimum and maximum relative attenuation [dB] for \|k\| = 0 .. 7, the stop-band maximum `inf` | `filters.PERIODIC_TEST_ATTENUATION_LIMITS_DB[1][7]  # (70.0, inf)` |
| `verify_filter_periodic` | `function` | **The periodic tests of IEC 61260-3:2016 on a laboratory's results.** Each clause (10.2 or 10.3, 11.7, 11.9, 13) judged by `metrology.verify_conformance` with the maxima of IEC 61260-1:2014 Annex B; results 5.3 makes unusable are named<br>• `filter_class`: 1 or 2<br>• `measurements`: a `FilterPeriodicMeasurements`<br>• keyword-only: `fraction`, b of the filters of Clause 13<br>• keyword-only: `pattern_approval_public`, whether the model's IEC 61260-2 approval is public (Default: False) | `res = filters.verify_filter_periodic(1, record, fraction=3)`<br><br>• `FilterPeriodicVerification` |
| `FilterPeriodicMeasurements` | `dataclass` | **What a laboratory measured in the periodic tests**, each result with its expanded uncertainty: `midband_attenuations_db` (10.2), `bandwidth_deviations_db` (10.3), `linearity_deviations_db` with `linearity_levels_below_upper_db` (11.7), `range_linearity_deviations_db` (11.9), `relative_attenuations_db` rows of 15 with NaN where 13.4 drops a frequency (13), and optional `set_midband_frequencies_hz` / `tested_midband_frequencies_hz` / `linearity_midband_frequencies_hz` labels, which let the verdict check the three filters of 11.3 and the frequencies of 13.4 | `filters.FilterPeriodicMeasurements(midband_attenuations_db=[0.1], midband_uncertainties_db=[0.15])` |
| `PeriodicTestClause` | `dataclass` | **The verdict on one clause of IEC 61260-3.**<br>• `clause`, `title`, `labels`, `verifications` (one `ConformanceVerification` per result)<br>• `passes`, `failed`, `unusable` (5.3)<br>• no truth value; `.plot()` as Figure C.1, clause 13 as margins against Ω_k | `res.clause("13").failed` |
| `FilterPeriodicVerification` | `dataclass` | **The IEC 61260-3:2016 verdict.**<br>• `filter_class`, `fraction`, `pattern_approval_public`, `measurements`, `clauses`; `clause(id)`<br>• `passes`: every clause a complete test grades was measured on the filters and frequencies it requires and every result conforms<br>• `missing`, `incomplete` (11.3, 13.1, 13.4), `coverage_checked`, `failed`, `unusable`<br>• `statement`: the text of Clause 14 k), l) or m), with the caveat of 1.5 when the pattern approval is not public<br>• no truth value; `.plot()` draws every result's margin, clause by clause | `res.passes, res.statement` |
| `class_limits` | `function` | **IEC 61260 Table 1 acceptance limits.**<br>• `fraction`: bandwidth designator denominator b (1, 3, ...)<br>• `filter_class`: 1 or 2 (`'2014'`); 0, 1 or 2 (`'1995'`)<br>• `omega`: normalized frequencies f/fm<br>• `edition`: `'2014'` (default) or `'1995'` | `lo, hi = filters.class_limits(3, 0, omega, edition="1995")`<br><br>• `lo` / `hi`: min/max relative attenuation [dB] (`hi` is `inf` outside the pass-band) |
| `verify_weighting_class` | `function` | **Weighting tolerance check** against IEC 61672-1:2013 Table 3 (A/C/Z), ANSI S1.4-1983 Tables IV/V (B, Types as classes) or IEC 61012:1990 Table 1 (AU), at the exact base-10 frequencies, plus the 5.5.7 between-nominals sweep. `edition="1979"` grades against IEC 651:1979 Table V instead, which publishes the laboratory-grade Type 0 (A, B and C).<br>• `wf`: a `WeightingFilter` (A, B, C, AU or Z)<br>• keyword-only: `sweep_points` (Default: 4096)<br>• keyword-only: `edition` (Default: `"2013"`; `"1979"` for Types 0-3) | `result = filters.verify_weighting_class(wf)`<br><br>• `WeightingComplianceResult` |
| `WeightingComplianceResult` | `dataclass` | **Weighting class verdict of a `WeightingFilter`.**<br>• `overall_class`: 1, 2 or `None` (0-3 or `None` for `'1979'`)<br>• `bands`: per-frequency class, deviation and `margin_class<c>_db` [dB]<br>• `between_nominals`: the 5.5.7 sweep, or `None` when no row was in range<br>• `curve`, `edition`, `fs` [Hz], `sweep_points`<br>• `range_limited`: finite-lower-limit rows beyond Nyquist<br>• takes `band_margins`, `between_nominals` (both held as read-only copies), `curve`, `edition`, `fs`, `sweep_points`; `bands`, `overall_class`, `range_limited` are read-only, read from them | `result.overall_class, result.range_limited` |
| `weighting_class_limits` | `function` | **IEC 61672-1:2013 Table 3 acceptance limits**, or the IEC 651:1979 Table V ones with `edition="1979"`.<br>• `weighting_class`: 1 or 2 (0-3 for `"1979"`, where class N is instrument Type N)<br>• `edition` (Default: `"2013"`) | `f, lo, hi = filters.weighting_class_limits(1)`<br><br>• `f`: 34 nominal frequencies [Hz]<br>• `lo` / `hi`: lower/upper deviation limits [dB] (`lo` is `-inf` where one-sided) |
| `nominal_frequencies` | `function` | **ANSI Frequency generator.**<br>• `fraction`: 1, 3, etc. (Required)<br>• `limits`: [f_min, f_max] (Default: [12, 20000]) | `f_cen, f_low, f_high, labels = filters.nominal_frequencies(fraction=3)`<br><br>• `f_cen`: List of center frequencies [Hz]<br>• `f_low`: List of lower edges [Hz]<br>• `f_high`: List of upper edges [Hz]<br>• `labels`: IEC nominal frequency labels |
| `normalized_frequencies` | `function` | **Standard IEC Frequencies.**<br>• `fraction`: 1 or 3 | `freqs = filters.normalized_frequencies(fraction=3)`<br><br>• `freqs`: List of standard center frequencies [Hz] |
| `sweep_signal` | `function` | **ESS excitation (ISO 18233 Annex B).**<br>• `fs`: Sample rate [Hz]<br>• `f1`: Start frequency [Hz]<br>• `f2`: Stop frequency [Hz] (≤ fs/2)<br>• `seconds`: Duration [s]<br>• `amplitude`: Peak (Default: 1.0)<br>• `fade`: Half-Hann fraction (Default: 0.01) | `s = room.sweep_signal(48000, 20, 20000, 3.0)`<br><br>• 1D exponential sine sweep |
| `inverse_filter` | `function` | **Farina inverse filter for an ESS.**<br>• Same parameters as `sweep_signal` | `inv = room.inverse_filter(48000, 20, 20000, 3.0)`<br><br>• Time-reversed, +6 dB/oct compensated sweep |
| `impulse_response` | `function` | **Sweep deconvolution (ISO 18233 B.5).**<br>• `recorded`: Recorded response (1D)<br>• `reference`: Emitted sweep (1D)<br>• `fs`: Sample rate [Hz]<br>• `method`: 'spectral' (Default) or 'farina'<br>• `f_range`: (f1, f2) for 'farina'<br>• `regularization`: Tikhonov term (Default: 1e-6)<br>• `length`: causal samples (Default: len(recorded))<br>• `return_full`: keep distortion tail (Default: False) | `ir = room.impulse_response(rec, sweep, fs)`<br><br>• `ImpulseResponseResult` (array-like; `.plot()`) |
| `mls_signal` | `function` | **Maximum-length sequence (ISO 18233 Annex A).**<br>• `order`: Register length N, 2-20 | `mls = room.mls_signal(16)`<br><br>• Bipolar sequence, length 2**N − 1 |
| `mls_impulse_response` | `function` | **IR from a periodic MLS.**<br>• `recorded`: Response spanning whole MLS periods (1D)<br>• `mls`: Excitation sequence<br>• `length`: IR samples (Default: 2**N − 1)<br>• `fs`: optional sample rate for the plot time axis | `ir = room.mls_impulse_response(rec, mls)`<br><br>• `ImpulseResponseResult` (array-like; `.plot()`) |
| `ImpulseResponseResult` | `dataclass` | **Recovered impulse response with metadata.**<br>• `ir`: IR samples<br>• `fs` [Hz] or None (e.g. an MLS recovery without one)<br>• `method`: 'spectral'/'farina'/'mls'/'golay'<br>• array-like: `np.asarray(res)`, indexing, `len()` and `shape`/`dtype` forward to `ir`<br>• `.plot()` | `ir = room.impulse_response(rec, sweep, fs)`<br>`room_parameters(ir, fs)  # drop-in array` |
| `golay_pair` | `function` | **Complementary Golay pair (Havelock Pt. I Ch. 6).**<br>• `order`: recursion steps n, 1-22; each code has 2**n samples<br>Periodic autocorrelations sum to an exact 2L·delta | `a, b = room.golay_pair(14)`<br><br>• Two bipolar codes, length 2**n |
| `golay_impulse_response` | `function` | **IR from a periodic Golay-pair excitation.**<br>• `recorded_a` / `recorded_b`: steady-state responses to each code (whole periods)<br>• `pair`: the `(a, b)` codes<br>• `length`: IR samples (Default: 2**n)<br>• `fs`: optional sample rate for the plot time axis<br>Noiseless LTI recovery is exact (machine precision) | `ir = room.golay_impulse_response(rec_a, rec_b, pair)`<br><br>• `ImpulseResponseResult` (array-like; `.plot()`) |
| `shaped_sweep_signal` | `function` | **Sweep with an arbitrary target spectrum (Mueller & Massarani Secs. 4.2-4.3).**<br>• `fs`, `f1`, `f2`, `seconds`<br>• `target`: 'pink' (Default), 'white' or `(frequencies_hz, magnitude_db)`<br>• `amplitude` (Default: 1.0), `start_delay` (Default: 0.05·seconds), `fade` (Default: 0.01)<br>Group delay grows with the target power: near-constant envelope | `sweep = room.shaped_sweep_signal(fs, 50, 5000, 2, target="pink")`<br><br>• `ShapedSweepResult` (array-like; `.plot()`) |
| `ShapedSweepResult` | `dataclass` | **Synthesized shaped sweep.**<br>• `signal`, `fs`, `frequencies`, `magnitude` (imposed, peak 1), `group_delay` [s], `f_range`, `crest_factor_db`<br>• array-like: usable directly as the deconvolution reference<br>• `.plot()`: waveform + Welch spectrum vs target | `ir = room.impulse_response(rec, np.asarray(sweep), fs)` |
| `ImpulseResponseWarning` | `warning class` | **Suspect recovered impulse response.**<br>Emitted e.g. for MLS aliasing in the recovery | `warnings.simplefilter('error', ImpulseResponseWarning)` |
| `plot_excitation` | `function` | **Plot an excitation signal.**<br>• `signal`: sweep or MLS samples (1D)<br>• `fs`: Sample rate [Hz]<br>• `kind`: `'sweep'` (default) or `'mls'` | `plot_excitation(sweep, fs, kind="sweep")`<br><br>• waveform + spectrogram / spectrum axes |
| `decay_curve` | `function` | **Schroeder decay curve (ISO 3382-1 5.3.3).**<br>• `ir`: Impulse response (1D)<br>• `fs`: Sample rate [Hz]<br>• `band`: Band centre [Hz] (Default: None → broadband)<br>• `fraction`: 1 or 3 (Default: 1)<br>• `zero_phase`: forward-backward band filtering, halves the 125 Hz short-T bias (Default: False) | `dc = room.decay_curve(ir, fs)` → `DecayCurve`<br>`times, levels = dc` still unpacks (`times` [s], `levels` [dB], 0 dB at t=0)<br>`dc.plot()` draws the decay + EDT/T20/T30 fits |
| `DecayCurve` | `dataclass` | **Schroeder decay curve (ISO 3382-1 5.3.3).**<br>• `times`: from the direct sound [s]<br>• `levels`: decay [dB], 0 dB at t = 0, up to the noise truncation point<br>• `band`: centre [Hz] or None (broadband)<br>• iterable: unpacks as `times, levels`<br>• `.plot()`: decay + EDT/T20/T30 fits | `dc = room.decay_curve(ir, fs)`<br>`dc.times, dc.levels, dc.band` |
| `room_parameters` | `function` | **Room acoustics (ISO 3382-1/2).**<br>• `ir`: Impulse response (1D)<br>• `fs`: Sample rate [Hz]<br>• `limits`: (f_min, f_max) or None (Default: (125, 4000))<br>• `fraction`: 1 or 3 (Default: 1)<br>• `zero_phase`: forward-backward octave filtering, halves the 125 Hz short-T T30 bias (Default: False) | `res = room.room_parameters(ir, fs)`<br><br>• `RoomAcousticsResult` per band |
| `RoomAcousticsResult` | `dataclass` | **Per-band room parameters.**<br>• `frequencies` [Hz]<br>• `edt`, `t20`, `t30` [s]<br>• `c50`, `c80` [dB], `d50`, `ts` [s]<br>• `dynamic_range` [dB]<br>• `edt_valid`/`t20_valid`/`t30_valid`<br>• `curvature` [%]<br>• takes `frequencies`, `edt`, `t20`, `t30`, `c50`, `c80`, `d50`, `ts`, `dynamic_range`, `curvature`; `edt_valid`, `t20_valid`, `t30_valid` are read-only, read from them | `res.t30, res.c80, res.t30_valid`<br><br>• Arrays with one entry per band |
| `sound_strength` | `function` | **Sound strength G (ISO 3382-1 A.2.1, Eq. (A.1)).**<br>• `ir`: hall impulse response (1D)<br>• `reference_ir`: same source at 10 m in a free field (1D)<br>• `fs`: Sample rate [Hz]<br>• `reference_level`: L_pE,10 [dB] instead of `reference_ir` (exactly one of the two)<br>• `limits`: (f_min, f_max) or None (Default: (125, 4000))<br>• `fraction`: 1 or 3 (Default: 1) | `res = room.sound_strength(ir, ref, fs)`<br><br>• `SoundStrengthResult` per band |
| `SoundStrengthResult` | `dataclass` | **Per-band sound strength.**<br>• `frequencies` [Hz] or None<br>• `strength`: G [dB]<br>• `exposure_level`: L_pE [dB]<br>• `reference_level`: L_pE,10 [dB]<br>• `.plot()`: G against the Table A.1 typical range | `res.strength, res.exposure_level`<br><br>• `strength == exposure_level - reference_level` |
| `sound_pressure_exposure_level` | `function` | **L_pE of an impulse response (ISO 3382-1 Eq. (A.2)).**<br>• `ir`: Impulse response (1D)<br>• `fs`: Sample rate [Hz]<br>• `limits`: (f_min, f_max) or None (Default: (125, 4000))<br>• `fraction`: 1 or 3 (Default: 1) | `lpe = room.sound_pressure_exposure_level(ir, fs)`<br><br>• [dB] re 20 uPa, one per band |
| `free_field_reference_level` | `function` | **Refer a free-field level to 10 m (ISO 3382-1 Eqs. (A.4)/(A.8)).**<br>• `level`: measured level [dB]<br>• `distance`: of that measurement [m], printed for >= 3 m | `room.free_field_reference_level(75.03, 5.0)`<br><br>• `69.0094` dB |
| `reverberation_room_reference_level` | `function` | **Free-field reference from a diffuse-field reading (ISO 3382-1 Eq. (A.5)).**<br>• `reverberation_room_level`: spatial-average L_pE in that room [dB]<br>• `absorption_area`: A [m2] | `room.reverberation_room_reference_level(80.0, 10.0)`<br><br>• `53.0` dB |
| `sound_strength_from_power` | `function` | **G from the source's power level (ISO 3382-1 Eq. (A.9)).**<br>• `pressure_level`: L_p in the room [dB]<br>• `power_level`: L_W of the source [dB] | `room.sound_strength_from_power(80.0, 100.0)`<br><br>• `11.0` dB |
| `directivity_energy_average` | `function` | **Energy mean over bearings round the source (ISO 3382-1, note to Eq. (A.4)).**<br>• `levels`: one per bearing [dB], evenly spaced over a full turn, at least 29 | `room.directivity_energy_average(levels)`<br><br>• [dB]; raises below 29 bearings |
| `early_lateral_energy_fraction` | `function` | **Early lateral energy fraction (ISO 3382-1 Eqs. (A.14)/(A.15)).**<br>• `ir`: omnidirectional response at the point (1D), which also sets t = 0<br>• `lateral_ir`: figure-of-eight response at the same point (1D)<br>• `fs`: Sample rate [Hz]<br>• `weighting`: 'squared' (J_LF) or 'cosine' (J_LFC)<br>• `limits`: (f_min, f_max) or None (Default: (125, 4000))<br>• `fraction`: 1 or 3 (Default: 1) | `res = room.early_lateral_energy_fraction(omni, fig8, fs)`<br><br>• `LateralEnergyResult` per band |
| `LateralEnergyResult` | `dataclass` | **Per-band lateral energy fraction.**<br>• `frequencies` [Hz] or None<br>• `energy_fraction`: J_LF or J_LFC, dimensionless<br>• `weighting`: which of the two was computed<br>• `.plot()`: against the Table A.1 range | `res.energy_fraction, res.weighting` |
| `LATERAL_WEIGHTINGS` | `constant` | **('squared', 'cosine')**, the two angular weightings Eqs. (A.14) and (A.15) print. | `room.LATERAL_WEIGHTINGS` |
| `EARLY_LATERAL_WINDOW_S` | `constant` | **(0.005, 0.080) s**, the numerator window of Eqs. (A.14)/(A.15) from the direct sound. | `room.EARLY_LATERAL_WINDOW_S` |
| `EARLY_ENERGY_LIMIT_S` | `constant` | **0.080 s**, the upper limit of their denominator. | `room.EARLY_ENERGY_LIMIT_S` |
| `late_lateral_sound_level` | `function` | **Late lateral sound level (ISO 3382-1 Eq. (A.16)).**<br>• `ir`: omnidirectional response at the point (1D), for t = 0<br>• `lateral_ir`: figure-of-eight response at the same point (1D)<br>• `reference_ir`: same source at 10 m in a free field (1D)<br>• `fs`: Sample rate [Hz]<br>• `reference_level`: L_pE,10 [dB] instead of `reference_ir`<br>• `limits`, `fraction`: as above | `res = room.late_lateral_sound_level(omni, fig8, ref, fs)`<br><br>• `LateLateralResult` per band |
| `LateLateralResult` | `dataclass` | **Per-band late lateral level.**<br>• `frequencies` [Hz] or None<br>• `levels`: L_J [dB]<br>• `reference_level`: L_pE,10 [dB]<br>• `.plot()`: against the Table A.1 range, with the Eq. (A.17) average | `res.levels, res.reference_level` |
| `late_lateral_average` | `function` | **Energy average of L_J over four octave bands (ISO 3382-1 Eq. (A.17)).**<br>• `levels`: the 125 Hz, 250 Hz, 500 Hz and 1 kHz values [dB], exactly four | `room.late_lateral_average([-8.0] * 4)`<br><br>• `-8.0` dB; four equal values are unchanged |
| `LATE_LATERAL_START_S` | `constant` | **0.080 s**, where the numerator of Eq. (A.16) starts. | `room.LATE_LATERAL_START_S` |
| `LATE_LATERAL_AVERAGE_BANDS_HZ` | `constant` | **(125, 250, 500, 1000) Hz**, the four bands Eq. (A.17) averages. | `room.LATE_LATERAL_AVERAGE_BANDS_HZ` |
| `interaural_cross_correlation` | `function` | **Interaural cross correlation (ISO 3382-1 Eqs. (B.1)/(B.2)).**<br>• `left`, `right`: ear-canal responses (1D, same length)<br>• `fs`: Sample rate [Hz]<br>• `window`: (t1, t2) [s] from the direct sound, t2 None for the end (Default: (0.0, None))<br>• `limits`, `fraction`: as above | `res = room.interaural_cross_correlation(left, right, fs)`<br><br>• `InterauralCorrelationResult` per band |
| `InterauralCorrelationResult` | `dataclass` | **Per-band interaural correlation.**<br>• `frequencies` [Hz] or None<br>• `coefficient`: IACC<br>• `delay`: lag of the maximum [s], positive when the right ear lags<br>• `lag` [s] and `correlation`: the function itself, one row per band<br>• `.plot()`: the function over the search window | `res.coefficient, res.delay` |
| `IACC_SEARCH_S` | `constant` | **0.001 s**, the half-width of the Eq. (B.2) search window. | `room.IACC_SEARCH_S` |
| `IACC_EARLY_WINDOW_S` | `constant` | **(0.0, 0.080) s**, the early window of B.4. | `room.IACC_EARLY_WINDOW_S` |
| `IACC_LATE_START_S` | `constant` | **0.080 s**, where B.4's reverberant window starts. | `room.IACC_LATE_START_S` |
| `IACC_JND` | `constant` | **0.075**, the just-noticeable difference B.4 assumes for IACC. | `room.IACC_JND` |
| `stage_support` | `function` | **Early and late stage support (ISO 3382-1 Eqs. (C.1)/(C.2)).**<br>• `ir`: platform response 1,0 m from the source (1D)<br>• `fs`: Sample rate [Hz]<br>• `limits`: (f_min, f_max) or None (Default: (250, 2000), the bands C.2.4 averages)<br>• `fraction`: 1 or 3 (Default: 1) | `res = room.stage_support(ir, fs)`<br><br>• `StageSupportResult` per band |
| `StageSupportResult` | `dataclass` | **Per-band stage support.**<br>• `frequencies` [Hz] or None<br>• `early`: ST_Early [dB]<br>• `late`: ST_Late [dB]<br>• `.plot()`: both against the Table C.1 ranges | `res.early, res.late` |
| `STAGE_DIRECT_WINDOW_S` | `constant` | **(0.0, 0.010) s**, the direct-sound window both equations divide by. | `room.STAGE_DIRECT_WINDOW_S` |
| `EARLY_SUPPORT_WINDOW_S` | `constant` | **(0.020, 0.100) s**, the numerator of Eq. (C.1); it starts at 20 ms, not at 10 ms. | `room.EARLY_SUPPORT_WINDOW_S` |
| `LATE_SUPPORT_WINDOW_S` | `constant` | **(0.100, 1.000) s**, the numerator of Eq. (C.2); it stops at one second. | `room.LATE_SUPPORT_WINDOW_S` |
| `STAGE_SUPPORT_DISTANCE_M` | `constant` | **1.0 m** between source and microphone (C.2.1). | `room.STAGE_SUPPORT_DISTANCE_M` |
| `STAGE_SUPPORT_HEIGHTS_M` | `constant` | **(1.0, 1.5) m**, the two heights C.2.3 permits for both. | `room.STAGE_SUPPORT_HEIGHTS_M` |
| `STAGE_SUPPORT_BANDS_HZ` | `constant` | **(250, 500, 1000, 2000) Hz**, the bands C.2.4 averages. | `room.STAGE_SUPPORT_BANDS_HZ` |
| `STAGE_SUPPORT_POSITIONS` | `constant` | **3** positions C.2.3 asks for and C.2.4 averages over. | `room.STAGE_SUPPORT_POSITIONS` |
| `STAGE_SUPPORT_STANDARD_DEVIATION_DB` | `constant` | **1.0 dB** for one band in one position (C.2.4). | `room.STAGE_SUPPORT_STANDARD_DEVIATION_DB` |
| `STAGE_SUPPORT_SINGLE_NUMBER_STANDARD_DEVIATION_DB` | `constant` | **0.3 dB** for the single number (C.2.4); it is 1 dB over the root of the twelve readings. | `room.STAGE_SUPPORT_SINGLE_NUMBER_STANDARD_DEVIATION_DB` |
| `reverberation_time_standard_deviation` | `function` | **Standard deviation of a measured T (ISO 3382-1 Eqs. (4)/(5)).**<br>• `reverberation_time` [s]<br>• `bandwidth` [Hz], from `filter_bandwidth`<br>• `evaluation_range`: 20 or 30 [dB] (Default: 30)<br>• `decays`: n per position (Default: 10, what 7.2 values an integrated response at)<br>• `positions`: N source-receiver combinations (Default: 1) | `room.reverberation_time_standard_deviation(2.0, 710.0, positions=12)`<br><br>• `0.009044` s |
| `filter_bandwidth` | `function` | **Bandwidth of a fractional-octave filter (ISO 3382-1 7.1).**<br>• `centre`: mid-band frequency [Hz]<br>• `fraction`: 1 or 3 (Default: 1) | `room.filter_bandwidth(1000.0)` → `710.0` Hz |
| `minimum_reliable_reverberation_time` | `function` | **Shortest decay a forward analysis can resolve (ISO 3382-1 Eqs. (6)/(7)).**<br>• `bandwidth` [Hz]<br>• `detector_time`: T of the averaging detector [s] (Default: 0.0, no detector) | `room.minimum_reliable_reverberation_time(88.75)`<br><br>• `0.1803` s |
| `FILTER_BANDWIDTH_FRACTION` | `constant` | **{1: 0.71, 3: 0.23}**, the two bandwidths 7.1 prints as a fraction of the centre. | `room.FILTER_BANDWIDTH_FRACTION[1]` → `0.71` |
| `DECAY_UNCERTAINTY_COEFFICIENTS` | `constant` | **{20.0: (0.88, 1.90), 30.0: (0.55, 1.52)}**, the printed pairs of Eqs. (4) and (5). | `room.DECAY_UNCERTAINTY_COEFFICIENTS[30.0]` |
| `INTEGRATED_RESPONSE_DECAYS` | `constant` | **10**, the decays per position 7.2 values an integrated impulse response at. | `room.INTEGRATED_RESPONSE_DECAYS` |
| `MINIMUM_BANDWIDTH_TIME_PRODUCT` | `constant` | **16.0**, the B·T of Eq. (6). | `room.MINIMUM_BANDWIDTH_TIME_PRODUCT` |
| `MINIMUM_DETECTOR_MULTIPLE` | `constant` | **2.0**, the multiple of the detector's own T in Eq. (7). | `room.MINIMUM_DETECTOR_MULTIPLE` |
| `TABLE_A1` | `constant` | **ISO 3382-1 Table A.1**, keyed by the symbol the standard prints: `G`, `EDT`, `C80`, `D50`, `Ts`, `J_LF`, `L_J`.<br>• each value is an `AuditoriumQuantity` | `room.TABLE_A1['G'].averaging_bands_hz` → `(500.0, 1000.0)` |
| `AuditoriumQuantity` | `dataclass` | **One row of Table A.1.**<br>• `symbol`, `aspect`, `unit`<br>• `averaging_bands_hz`: the bands its single number averages, two or four<br>• `just_noticeable_difference`: None for `L_J`, whose JND the table prints as 'Not known'<br>• `relative_jnd`: True only for EDT's 'Rel. 5 %'<br>• `typical_range`, `energy_averaged` | `room.TABLE_A1['L_J'].energy_averaged` → `True` |
| `single_number_average` | `function` | **The Table A.1 single number of one quantity (A.5).**<br>• `symbol`: as `TABLE_A1` keys it<br>• `values`: per-band values<br>• `frequency`: the band centres [Hz] | `room.single_number_average('G', g, freqs)`<br><br>• arithmetic, except `L_J`, which goes through Eq. (A.17) |
| `octave_pair_averages` | `function` | **The low, mid and high pair averages of A.5.**<br>• `values`: per-band values<br>• `frequency`: the band centres [Hz], all six octaves | `room.octave_pair_averages(v, freqs)`<br><br>• `{'low': ..., 'mid': ..., 'high': ...}` |
| `perceptibly_different` | `function` | **Whether two values differ by the Table A.1 JND.**<br>• `symbol`, `first`, `second`<br>• relative for EDT, absolute otherwise; raises for `L_J` | `room.perceptibly_different('EDT', 0.5, 0.56)` → `True` |
| `minimum_receiver_positions` | `function` | **Fewest microphone positions a hall wants (Table A.2).**<br>• `seats`: the number of seats | `room.minimum_receiver_positions(1000)` → `8.0`<br><br>• clamped to the 6 to 10 A.4 authorises |
| `gliding_directivity_deviation` | `function` | **Deviation of each gliding 30 degree arc from the whole turn (4.2.1).**<br>• `levels`: one per bearing [dB], evenly spaced over a full turn | `room.gliding_directivity_deviation(levels)`<br><br>• one deviation per bearing [dB] |
| `source_directivity_limit` | `function` | **The Table 1 limit for one octave band.**<br>• `centre`: nominal band centre [Hz], one of the six the table prints | `room.source_directivity_limit(4000.0)` → `6.0` dB |
| `MAX_SOURCE_DIRECTIVITY_DEVIATION_DB` | `constant` | **Table 1**, six octave bands to their maximum deviation in dB: 1, 1, 1, 3, 5, 6. | `room.MAX_SOURCE_DIRECTIVITY_DEVIATION_DB[1000.0]` → `3.0` |
| `DIRECTIVITY_ARC_DEG` | `constant` | **30.0 degrees**, the arc each gliding average of 4.2.1 covers. | `room.DIRECTIVITY_ARC_DEG` |
| `DIRECTIVITY_STEP_DEG` | `constant` | **5.0 degrees**, the step 4.2.1 asks for without a turntable; it divides a turn into 72. | `room.DIRECTIVITY_STEP_DEG` |
| `DIRECTIVITY_SURVEY_DISTANCE_M` | `constant` | **1.5 m**, the shortest source-to-microphone distance 4.2.1 allows in a survey. | `room.DIRECTIVITY_SURVEY_DISTANCE_M` |
| `OCTAVE_PAIRS_HZ` | `constant` | **The three A.5 pairs**: low 125+250, mid 500+1000, high 2000+4000 Hz. | `room.OCTAVE_PAIRS_HZ['mid']` |
| `MID_FREQUENCY_OCTAVES_HZ` | `constant` | **(500, 1000) Hz**, the octave route of Clause 9.1 to T30,mid. | `room.MID_FREQUENCY_OCTAVES_HZ` |
| `MID_FREQUENCY_THIRD_OCTAVES_HZ` | `constant` | **(400, 500, 630, 800, 1000, 1250) Hz**, the other route Clause 9.1 prints, and the one a one-third-octave analysis takes. | `room.MID_FREQUENCY_THIRD_OCTAVES_HZ` |
| `TEST_REPORT_ITEMS` | `constant` | **The fifteen items Clause 9.2 says a test report shall include**, a) to o), in order. Clause 9 is normative. | `len(room.TEST_REPORT_ITEMS)` → `15` |
| `AuditoriumWarning` | `warning class` | **A measurement outside the conditions ISO 3382-1 prints for it.**<br>• emitted for a room response cut short of the 30 dB of A.2.1<br>• for a response of either kind that ends before its lowest band's filter has rung down<br>• and for a free-field distance under 3 m | `warnings.simplefilter('error', room.AuditoriumWarning)` |
| `REFERENCE_DISTANCE_M` | `constant` | **10.0 m**, the free-field distance G is referenced to (ISO 3382-1 A.2.1). | `room.REFERENCE_DISTANCE_M` → `10.0` |
| `MINIMUM_REFERENCE_DISTANCE_M` | `constant` | **3.0 m**, the shortest distance Eqs. (A.4)/(A.8) are printed for. | `room.MINIMUM_REFERENCE_DISTANCE_M` → `3.0` |
| `MAXIMUM_DIRECTIVITY_STEP_DEG` | `constant` | **12.5 deg**, the coarsest bearing step the note to Eq. (A.4) allows. | `room.MAXIMUM_DIRECTIVITY_STEP_DEG` → `12.5` |
| `SOUND_STRENGTH_POWER_OFFSET_DB` | `constant` | **31.0 dB**, the printed offset of Eq. (A.9); 10 lg(4 pi 10^2) = 30.9921 dB rounded. | `room.SOUND_STRENGTH_POWER_OFFSET_DB` → `31.0` |
| `DIFFUSE_FIELD_REFERENCE_OFFSET_DB` | `constant` | **37.0 dB**, the printed offset of Eq. (A.5); 10 lg(16 pi 10^2) = 37.0127 dB rounded. | `room.DIFFUSE_FIELD_REFERENCE_OFFSET_DB` → `37.0` |
| `open_plan_metrics` | `function` | **Open-plan office metrics (ISO 3382-3).**<br>• `positions_m`: Source distances [m] (≥ 4)<br>• `spl_a_speech`: A-weighted speech level per position [dB]<br>• `sti_values`: STI per position | `m = room.open_plan_metrics(r, lp, sti)`<br><br>• `OpenPlanResult` |
| `plot_open_plan_geometry` | `function` | **Open-plan measurement line to scale.**<br>• `positions` [m] (1-D)<br>• `rd`, `rp` [m] (markers)<br>• `language` | `plot_open_plan_geometry([2, 4, 6, 8, 12, 16], rd=6.5, rp=13.0)`<br><br>• Also `OpenPlanResult.plot_geometry()` |
| `OpenPlanResult` | `dataclass` | **Open-plan single numbers.**<br>• `d2s`: Spatial decay rate [dB/doubling]<br>• `lp_as_4m`: Speech level at 4 m [dB]<br>• `rd`: Distraction distance [m]<br>• `rp`: Privacy distance [m] | `m.d2s, m.rd, m.rp`<br><br>• `nan` when undefined |
| `image_source_rir` | `function` | **Image-source room impulse response (Kuttruff 4.1 / Vorländer 11).**<br>• `dimensions`: `(Lx, Ly, Lz)` [m]<br>• `source`/`receiver`: `(x, y, z)` [m]<br>• `absorption`: scalar / (6,) per-wall / per-band / (6, n) [0, 1]<br>• `fs` [Hz], `max_order` (Default: 20)<br>• `air_attenuation`: intensity `m` [1/m]<br>• `frequencies` [Hz] for a per-band RIR | `res = room.image_source_rir((7,5,3), (2,1.6,1.5), (5.2,3.4,1.7), 0.12, fs=48000)`<br><br>• `ImageSourceResult` |
| `ImageSourceResult` | `dataclass` | **Synthetic RIR by image sources.**<br>• `ir`: sampled RIR (1D or per-band)<br>• exact reflection table `times`/`distances`/`orders`/`amplitudes`/`image_positions`<br>• `direct_time` [s]<br>• `.plot()`, `.plot_geometry()` (room plan with the image lattice): reflectogram | `res.ir, res.times, res.orders`<br>`res.plot()` |
| `audible_image_count` / `reflection_density` | `function` | **Shoebox image count (Kuttruff Eq. 9.23) and reflection density (Eq. 4.6).**<br>• `audible_image_count(order)`: `(2/3)(2i³+3i²+4i)`<br>• `reflection_density(t, volume, speed_of_sound=343)`: `4πc³t²/V` | `audible_image_count(10)  # 1560`<br>`reflection_density(0.1, 120.0)` |
| `steady_state_field` | `function` | **Steady-state room field (Bies 6.4).**<br>• `sound_power_level` `Lw` [dB]<br>• `surface_area` `S` [m²], `mean_absorption` `ᾱ` (0, 1)<br>• `distances` [m] (Default: 0.1–10 rc)<br>• `directivity` `Q` (Default: 1)<br>• `characteristic_impedance` [Pa·s/m] for the ρc term | `f = room.steady_state_field(90.0, 100.0, 0.2)`<br><br>• `SteadyFieldResult` |
| `SteadyFieldResult` | `dataclass` | **SPL vs distance, direct/reverberant/total.**<br>• `distances` [m]<br>• `direct`/`reverberant`/`total` [dB]<br>• `critical_distance` [m], `room_constant` [m²]<br>• `.plot()` | `f.total, f.critical_distance`<br>`f.plot()` |
| `room_constant` / `sabine_absorption_area` / `critical_distance` / `schroeder_frequency` / `steady_state_spl` / `SOURCE_POWER_MODELS` | `function` / `mapping` | **Steady-field building blocks (Bies 6.43/6.44, Kuttruff 3.44/5.44, VDI 2081-1 Eq. 36/37).**<br>• `room_constant(S, ᾱ)` = `Sᾱ/(1-ᾱ)` [m²]<br>• `sabine_absorption_area(V, T, speed_of_sound=343)` = `24 ln10/c₀ · V/T` [m²]<br>• `critical_distance(R \| absorption_area=A, directivity=1)` = `√(QR/16π)`, or `√(QA/16π)` from the absorption area [m]<br>• `schroeder_frequency(T, V)` = `2000√(T/V)` [Hz]<br>• `steady_state_spl(Lw, r, R \| absorption_area=A, directivity=1, source_model='constant_power')` = `Lw + 10 lg(Q/4πr² + 4/R)`, with `4/A` in place of `4/R` from the absorption area [dB]; `r=None` gives the reverberant field alone; exactly one absorption measure, `directivity` scalar or per band<br>• `SOURCE_POWER_MODELS`: `'constant_power'` / `'constant_volume'` (Π₀Q, conservative) / `'constant_pressure'` (Π₀/Q), Norton Table 4.5 | `R = room.room_constant(100, 0.2)`<br>`critical_distance(R)`<br>`steady_state_spl(90, None, R)` |
| `room_modes` | `function` | **Normal modes of a rectangular room (Long, Architectural Acoustics 2e, Eq. 8.43).**<br>• `dimensions`: `(lx, ly, lz)` [m]<br>• `max_frequency` [Hz] (Default: 200)<br>• `speed_of_sound` [m/s] (Default: 343)<br>• `reverberation_time` [s] (optional, adds the Schroeder frequency) | `m = room.room_modes((7, 5, 3), max_frequency=100.0)`<br><br>• `RoomModesResult` |
| `RoomModesResult` | `dataclass` | **Sorted mode list of a shoebox.**<br>• `orders`: `(N, 3)` `(nx, ny, nz)`<br>• `frequencies` [Hz], ascending<br>• `kinds`: 'axial'/'tangential'/'oblique'<br>• `volume`, `surface_area`, `edge_length`, `schroeder_frequency`<br>• `count_by_kind()`, `density(f)`<br>• `.plot()`: mode ladder by family + modal density | `m.frequencies[0], m.count_by_kind()`<br>`m.plot()` |
| `room_mode_frequency` / `room_mode_count` / `room_modal_density` | `function` | **Mode building blocks (Long Eqs. 8.43, 8.45, 8.46).**<br>• `room_mode_frequency(orders, dimensions)` = `(c0/2)√((nx/lx)²+(ny/ly)²+(nz/lz)²)` [Hz]<br>• `room_mode_count(f, dimensions)`: Morse/Pierce smooth count<br>• `room_modal_density(f, dimensions)` [modes/Hz] | `room_mode_frequency((1, 0, 0), (7, 5, 3))`<br>`room_modal_density(1000.0, (7, 5, 3))` |
| `MODE_KINDS` | `constant` | **Mode families, strongest first: `('axial', 'tangential', 'oblique')`.** | `MODE_KINDS[0]  # 'axial'` |
| `crowd_noise` | `function` | **Self-generated crowd noise vs occupancy (Long Ch. 17, Eqs. 17.50–17.52).**<br>• `absorption_areas`: total room absorption [m²] (scalar or 1-D)<br>• `talkers`: occupancy axis N (Default: 1..20)<br>• `distance` r [m] (Default: 1.2), `sound_power_level` Lw [dB] (Default: 70), `directivity` Q (Default: 2) | `c = room.crowd_noise([20.0, 190.0])`<br><br>• `CrowdNoiseResult` |
| `CrowdNoiseResult` | `dataclass` | **Crowd self-noise result.**<br>• `talkers`, `absorption_areas`, `levels` [dB] (areas × talkers)<br>• `signal_level` [dB], `communication_level` [dB], `distance`, `sound_power_level`, `directivity`<br>• `speech_to_noise()` [dB]<br>• `.plot()`: level vs occupancy per absorption | `c.levels, c.signal_level`<br>`c.plot()` |
| `speech_direct_level` / `crowd_noise_level` / `speech_to_noise_ratio` / `absorption_per_table` | `function` | **Crowd-noise building blocks (Long Eqs. 17.50–17.54).**<br>• `speech_direct_level(r)` = `Lw + 10 lg(Q/4πr²)` [dB]<br>• `crowd_noise_level(N, A)` = `Lw + 10 lg N + 10 lg(4/A)` [dB]<br>• `speech_to_noise_ratio(r, A_tab)` [dB]<br>• `absorption_per_table(r, L_SN)` [m²]: the inverse | `crowd_noise_level(20, 20.0)  # 76`<br>`absorption_per_table(1.0, -6.0)  # 6.31` |
| `NORMAL_VOICE_POWER_LEVEL` / `TALKER_DIRECTIVITY` / `COMMUNICATION_SNR` / `PRIVACY_SNR` | `constant` | **Crowd-noise defaults (Long Ch. 17).**<br>• 70 dB re 1 pW per talker, Q = 2<br>• −6 dB communication limit (Eq. 17.53), −9 dB privacy limit (Eq. 17.54) | `absorption_per_table(1.0, COMMUNICATION_SNR)` |
| `sound_distribution_value` / `reference_distribution_value` / `ISO14257_REFERENCE_DISTANCE_M` / `FREE_FIELD_OFFSET_DB` | `function` / `constant` | **The curve a workroom is judged by, ISO 14257 Eqs. (1) and (2).**<br>• `sound_distribution_value(levels, power_levels)`: D = L_p − L_W, the level at a position referred to the power of the source that made it<br>• `reference_distribution_value(distances)`: D_ref = 20 lg(r_0/r) − 11 dB, the free field the same source would give, with r_0 = 1 m<br>• the 11 dB is 10 lg(4 π r_0²) rounded, which is why a free field slopes 6 dB per doubling and starts where it does | `d = room.sound_distribution_value(levels, 110.8)`<br>`room.reference_distribution_value([2.0, 4.0])  # -17.02, -23.04` |
| `spectrum_distribution_value` / `normalized_distribution_value` / `PINK_NOISE_WEIGHTS_DB` / `NORMALIZED_OFFSET_DB` | `function` / `mapping` / `constant` | **The six bands collapsed into one number, Eqs. (3) and (4).**<br>• `spectrum_distribution_value(values, machine_power_levels)`: the curve weighted by the spectrum of the machine that will stand there<br>• `normalized_distribution_value(values)`: the same sum with A-weighted pink noise fixed as the spectrum, Table 1, minus the printed 6,2 dB; the six printed weights sum to 6,251 5 dB, so a flat curve comes back 0,05 dB high, and `spectrum_distribution_value(values, list(PINK_NOISE_WEIGHTS_DB.values()))` is the exact normalisation Annex C used<br>• 4.2.3 says why that spectrum is a normalisation and not an average machine: real spectra are too varied for an average to mean anything | `room.normalized_distribution_value(d_by_band)` |
| `spatial_decay_rate` / `DECADE_TO_DOUBLING` | `function` / `constant` | **DL2, the rate of spatial decay per distance doubling, Eq. (5).**<br>• the least-squares slope of D against lg r, times 0,3, sign flipped so a decay is positive<br>• 6 dB is the free field; a workroom gives less, and how much less is what the room is worth<br>• `DECADE_TO_DOUBLING` is the printed 0,3, which is lg 2 rounded | `room.spatial_decay_rate(d, distances)  # 4.39` |
| `level_excess` / `mean_level_excess` / `level_excess_at` / `EVALUATION_DISTANCES_M` | `function` / `mapping` | **DLf, how far the room sits above a free field, Eqs. (6) to (8).**<br>• `level_excess`: D − D_ref at every position<br>• `mean_level_excess`: the average of Eq. (7), a trapezoid over lg r, so the wide gaps of a logarithmic distribution weigh what they should<br>• `level_excess_at`: the height of the fitted line over the free-field line at one distance, which a single outlying position moves much less<br>• `EVALUATION_DISTANCES_M`: 4 m, 10 m and 30 m, the conventional distances 6.4.3 reads the line at | `room.mean_level_excess(d, distances)  # 6.73` |
| `spatial_decay_curve` / `SpatialDecayResult` | `function` / `dataclass` | **One region of the path, with both descriptors, clause 6.**<br>• `region`: 'near', 'middle', 'far' or 'whole'; `near_limit_m` d₁ and `far_limit_m` d₂ place the boundaries<br>• result: `distances_m`, `distribution_values_db`, `reference_values_db`, `level_excess_db`, `decay_rate_db`, `mean_excess_db`, `region`, `band_hz`<br>• `.plot()`: the curve, the free field it is judged by, and the fitted slope | `res = room.spatial_decay_curve(d, distances, region="middle")`<br><br>• `res.decay_rate_db`, `res.mean_excess_db` |
| `distance_region` / `NEAR_REGION_START_M` / `TYPICAL_NEAR_LIMIT_M` / `TYPICAL_FAR_LIMIT_M` / `PREFERRED_MIDDLE_LIMIT_M` | `function` / `constant` | **The three distance ranges of 6.2.**<br>• near from 1 m to d₁, middle from d₁ to d₂, far beyond d₂, with 5 m and 16 m the typical pair<br>• the middle region is the one health and safety work reads, and 6.2 b) asks for it to reach 24 m whenever the room allows<br>• distances are measured from the acoustical centre of the source | `room.distance_region(12.0)  # 'middle'` |
| `floor_reference_value` / `corrected_distribution_value` / `SOURCE_ON_FLOOR_HEIGHT_M` | `function` / `constant` | **Taking the source's own curve back out, Annex B.**<br>• `floor_reference_value(distances, source_height_m=…, path_height_m=…)`: D_ref plus 10 lg(1 + r²/(r² + 4 h_S h_P)), which is Eq. (B.4)'s 3 dB for a source on the floor<br>• `corrected_distribution_value(values, measured_reference, distances, …)`: Eq. (B.1) swaps the measured free-field curve of that source for the theoretical one, so what is left is the room<br>• a source is "on the floor" at 0,5 m or under, which is where the half-space form applies | `room.corrected_distribution_value(d, d_free, distances, source_height_m=0.0)` |
| `omnidirectionality_tolerance_db` / `OMNIDIRECTIONAL_TOLERANCE_DB` / `OMNIDIRECTIONAL_RAMP_HZ` / `MAX_DIRECTIVITY_INDEX_DB` / `ADJACENT_BAND_LIMIT_DB` / `STABILITY_TOLERANCE_DB` | `function` / `constant` / `mapping` | **What makes a source fit for the test, Annex A.**<br>• ± 2 dB up to 630 Hz, a linear rise to ± 8 dB at 1 kHz and ± 8 dB from there to 5 kHz, taken across the three one-third-octave bands that span the rise<br>• the source's own spectrum may not step more than 8 dB between adjacent one-third octaves, and its output must hold to 1 dB below 160 Hz and 0,5 dB above 200 Hz | `room.omnidirectionality_tolerance_db(800.0)  # 5.0` |
| `SPATIAL_DECAY_BANDS_HZ` / `ISO14257_MIN_SIGNAL_TO_BACKGROUND_DB` / `ISO14257_PREFERRED_SIGNAL_TO_BACKGROUND_DB` / `MIN_SOURCE_TO_WALL_M` | `constant` | **The conditions of clause 5, as numbers.**<br>• the six octave bands from 125 Hz to 4 kHz the curve is measured in<br>• the source at least 10 dB over the background at every position; between 6 dB and 10 dB an ISO 3744 correction is made, and under 6 dB there is no measurement<br>• the acoustical centre of the source at least 3 m from any wall or reflecting object other than the floor | `room.SPATIAL_DECAY_BANDS_HZ  # (125.0, ..., 4000.0)` |
| `check_background_margin` / `BackgroundMarginCheck` | `function` / `dataclass` | **Does the source stand clear of the background? 5.1.4.**<br>• `levels_db` with the source running and `background_levels_db` without it, one octave band at a time<br>• result: `margins_db`, `needs_correction` (under 10 dB and over 6 dB, where the clause asks for the ISO 3744 correction), `unusable` (6 dB or less, which it offers no correction for), `satisfied`<br>• the verdict is returned and never applied: the correction belongs to the standard that prints it<br>• Emitted by `room.spatial_decay`: `SpatialDecayWarning` when any margin is under 10 dB<br>• `BackgroundMarginCheck` takes `margins_db`; `needs_correction`, `unusable`, `satisfied` are read-only, read from them | `check = room.check_background_margin(levels, background)`<br>`check.satisfied  # False` |
| `SpatialDecayWarning` | `warning class` | **The measurement is outside a condition ISO 14257 states.**<br>• a region holding the two positions a regression needs and no more, so the rate is the line through them (5.3.2)<br>• a margin over the background under the 10 dB of 5.1.4<br>• `level_excess_at` reading the fitted line outside the distances it was fitted over, which the 30 m of 6.4.3 asks of a path that stops at 24 m<br>• Emitted by `room.spatial_decay` | `warnings.simplefilter('error', SpatialDecayWarning)` |
| `prediction_method` / `PREDICTION_METHODS` / `PredictionMethod` | `function` / `mapping` / `dataclass` | **The four ways ISO 11690-3 lets you predict a workroom, Table 4.**<br>• '1' is the diffuse-field method, for a room whose field may be treated as diffuse; '2a', '2b' and '2c' are geometrical, in growing order of what they model<br>• `PredictionMethod`: `category`, `family`, `rooms`, and the detail levels Table E.1 asks it to be fed (`room_detail`, `fitting_detail`, `source_detail`) | `room.prediction_method("2b").family  # 'geometrical'` |
| `detail_is_sufficient` / `DetailVerdict` / `RECOMMENDED_DETAIL` | `function` / `dataclass` / `mapping` | **Whether the data in hand is what the method asks for, Table E.1.**<br>• `detail_is_sufficient(category, room_detail=…, fitting_detail=…, source_detail=…)`<br>• verdict: `satisfied`, and `room_ok` / `fittings_ok` / `sources_ok` so a refusal says which of the three is short<br>• the annex is a recommendation, so this reports rather than raises<br>• `DetailVerdict` takes `category`, `room_detail`, `fitting_detail`, `source_detail`; `satisfied`, `room_ok`, `fittings_ok`, `sources_ok` are read-only, read from them | `room.detail_is_sufficient("2c", room_detail=2, fitting_detail=2, source_detail=1)` |
| `ROOM_DETAIL_LEVELS` / `FITTING_DETAIL_LEVELS` / `SOURCE_DETAIL_LEVELS` | `mapping` | **How much of the room, the fittings and the sources a model carries, Tables 1 to 3.**<br>• room: from the volume and one mean absorption coefficient up to the actual shape with absorption distributed over it<br>• fittings: from ignored up to their real shape and location, with shielding and reflection<br>• sources: omnidirectional points, points with a directivity, complex sources | `room.ROOM_DETAIL_LEVELS[2]` |
| `fitting_density` | `function` | **q = S/4V, the density of the fittings, NOTE 3 of 6.2.2.**<br>• `surface_area_m2`: the total surface of everything standing in the room<br>• `volume_m3`: the volume they stand in | `room.fitting_density(480.0, 1200.0)  # 0.1` |
| `workstation_level_increase` / `workstation_level` / `total_workstation_level` | `function` | **What the room adds at the machine's own workstation, Annex C.**<br>• `workstation_level_increase(sound_power_level_db=…, emission_level_db=…, absorption_area_m2=…)`: 10 lg(1 + 4S/A) with S = 10^((L_WA − L_pA)/10), the room reflecting back what the machine emits<br>• `workstation_level`: the emission level with that increase on it<br>• `total_workstation_level(contributions, existing_level_db=…)`: the energy sum of every machine, and of what was already there | `room.workstation_level(sound_power_level_db=95.0, emission_level_db=85.0, absorption_area_m2=200.0)` |
| `typical_decay_range` / `typical_excess_range` / `TYPICAL_DECAY_RANGE_DB` / `TYPICAL_EXCESS_RANGE_DB` | `function` / `mapping` | **What 4.3 says the two descriptors usually are, region by region.**<br>• DL2: 5 dB to 6 dB near, 2 dB to 5 dB in the middle, over 6 dB far away<br>• DLf: 2 dB to 10 dB in the middle region, which is the one the clause prints a range for<br>• an open bound comes back as `None`, so a range is a pair to read rather than a limit to enforce | `room.typical_decay_range("middle")  # (2.0, 5.0)` |
| `airborne_insulation` | `function` | **Field airborne insulation (ISO 16283-1).**<br>• `l1`/`l2`: Source/receiving levels [dB], 1D or (positions, bands)<br>• `t2`: Receiving-room T per band [s]<br>• `area`: Partition S [m²] (for R')<br>• `volume`: Receiving V [m³] (for R')<br>• `t0`: Reference T0 [s] (Default: 0.5)<br>• `frequencies` [Hz] (required with either low-frequency argument)<br>• `source_low_frequency` / `receiver_low_frequency`: `LowFrequencyProcedure` per room (ISO 16283-1 Clause 8)<br>• Warns (`LowFrequencyWarning`) when `volume` rounds below 25 m³, `frequencies` names 50/63/80 Hz and no `receiver_low_frequency` is given | `ins = building.airborne_insulation(l1, l2, t2, area=10, volume=50)`<br><br>• `AirborneInsulationResult` |
| `weighted_rating` | `function` | **Single-number rating + C/Ctr (ISO 717-1).**<br>• `values_by_band`: 16 thirds or 5 octaves [dB], or a mapping of band centre in Hz to dB such as a catalogue row's `.spectrum()`: read band by band, a missing rating band refused, never filled<br>• `bands`: 'third-octave', 'octave' or None (a mapping holding a one-third-octave band that is not an octave centre is read as thirds) | `w = building.weighted_rating(R)`<br><br>• `WeightedRatingResult` (Rw, C, Ctr) |
| `weighted_rating_extended` | `function` | **Rating + enlarged-range terms (ISO 717-1 Annex B).**<br>• `values_by_band` [dB] with `frequencies` [Hz] (None = the 16 core bands)<br>• `one_decimal`: 0.1 dB shift + one-decimal reductions for uncertainty statements (Default: False) | `ext = building.weighted_rating_extended(r, freqs)`<br><br>• `ExtendedWeightedRatingResult` (rating, c, ctr, c_50_3150 … ctr_100_5000) |
| `ExtendedWeightedRatingResult` | `dataclass` | **Weighted rating with the enlarged-range adaptation terms (ISO 717-1 Annex B).**<br>• `rating` + `c`, `ctr`<br>• `c_50_3150`, `c_50_5000`, `c_100_5000` and the `ctr_` twins<br>• `core`: the base `WeightedRatingResult` | `res = building.weighted_rating_extended(freqs, r)` |
| `db_hr_global_index` | `function` | **A-weighted global index Ix = −10 lg Σ 10^((Lx,i−Xi)/10) (CTE DB-HR Annex A, A.5-A.7).**<br>• `band_values` Xi [dB] over the 18 bands 100 Hz-5 kHz<br>• `spectrum`: 'pink','traffic','railway','aircraft'<br>• `frequencies` [Hz], `name` | `idx = building.db_hr_global_index(r, "pink")`<br><br>• `DbHrGlobalIndexResult` |
| `ra` | `function` | **RA for pink noise (DB-HR Annex A).**<br>• `reduction_index` R or R' [dB]; `frequencies` | `ra(r_prime).intermediate  # 51.4 dBA` |
| `ra_tr` | `function` | **RA,tr for road-traffic noise (DB-HR Annex A).**<br>• `reduction_index` [dB]; `frequencies` | `ra_tr(r).reported` |
| `dnt_a` | `function` | **DnT,A between rooms, pink noise (Formula A.7).**<br>• `level_difference` DnT [dB]; `frequencies` | `dnt_a(dnt).reported` |
| `d2m_nt_a` | `function` | **D2m,nT,A of a facade (Formula A.5).**<br>• `level_difference` D2m,nT [dB]; `frequencies`<br>• `spectrum`: 'pink' (Default) or 'railway'<br>• Clause 3.1.3.4 point 1: the quantity a railway-dominant site is assessed in | `d2m_nt_a(d, spectrum='railway').name  # 'D2m,nT,A'` |
| `d2m_nt_atr` | `function` | **D2m,nT,Atr of a facade (Formula A.6).**<br>• `level_difference` D2m,nT [dB]; `frequencies`<br>• `spectrum`: 'traffic' (Default) or 'aircraft'<br>• Railway noise is D2m,nT,A via (A.5): use `d2m_nt_a` | `d2m_nt_atr(d).intermediate  # 32.8 dBA` |
| `DbHrGlobalIndexResult` | `dataclass` | **A DB-HR A-weighted global index.**<br>• `value` (exact), `intermediate` (1 decimal), `reported` (integer, 3.1.3.1 point 4)<br>• `name`, `spectrum`, `reference`<br>• `frequencies`, `band_values`, `spectrum_levels`, `band_contributions`<br>• `.plot()` | `idx.value, idx.intermediate, idx.reported` |
| `DB_HR_FREQUENCIES` | `constant` | **The eighteen 1/3-octave centres of DB-HR Annex A, 100 Hz to 5 kHz.** | `DB_HR_FREQUENCIES[0]  # 100.0` |
| `DB_HR_NORMALISED_SPECTRA` | `constant` | **Normalised A-weighted source spectra [dBA] of Annex A Tables A.2-A.5.**<br>'pink' (A.5), 'traffic' (A.3), 'railway' (A.4, equal to A.3), 'aircraft' (A.2) | `DB_HR_NORMALISED_SPECTRA["pink"]` |
| `window_size_correction` | `function` | **Window-size correction of RA / RA,tr [dB] (CTE Catálogo de Elementos Constructivos).**<br>• `area` [m²]: 0 up to 2,7; −1 to 3,6; −2 to 4,6; −3 above | `26 + building.window_size_correction(4.0)  # 24 dBA` |
| `db_hr_facade_requirement` | `function` | **Required D2m,nT,Atr (DB-HR Table 2.1).**<br>• `ld` [dBA], `building_use`, `room_type`<br>• `dominant_noise`: 'road','railway','aircraft' (+4 dBA)<br>• `quiet_facade`: assess with Ld − 10 dBA | `db_hr_facade_requirement(62, "residential", "bedrooms")  # 32 dBA` |
| `db_hr_airborne_requirement` | `function` | **Airborne requirements between rooms (DB-HR 2.1.1).**<br>• `receiving_room`: 'protected'/'habitable'<br>• `source_room`: 'same_unit','other_unit','installations','activity'<br>• `shared_opening`: the RA pair on the door/window and its enclosure | `(req,) = building.db_hr_airborne_requirement("protected", "other_unit")  # 50 dBA` |
| `db_hr_party_wall_requirement` | `function` | **Party wall between two buildings (DB-HR 2.1.1 c), alternatives.**<br>• `quantity`: 'D2m,nT,Atr' (40 dBA per leaf) or 'DnT,A' (50 dBA for both) | `db_hr_party_wall_requirement()` |
| `db_hr_impact_requirement` | `function` | **Impact requirement L'nT,w (DB-HR 2.1.2).**<br>• `receiving_room`, `source_room` (65 dB against another use unit, 60 dB otherwise) | `db_hr_impact_requirement("protected", "other_unit")  # ≤ 65 dB` |
| `db_hr_reverberation_requirement` | `function` | **Reverberation / absorption requirement (DB-HR 2.2).**<br>• `room_use`: 'classroom','restaurant','common_area' (or aliases)<br>• `furnished`: classroom with seating (0,5 s) | `db_hr_reverberation_requirement("classroom")  # ≤ 0.7 s` |
| `DbHrRequirement` | `dataclass` | **A single DB-HR performance requirement.**<br>• `quantity`, `limit`, `direction` ('min'/'max'), `unit`<br>• `decimals`: rounding before the comparison<br>• `reference`, `description` | `req.quantity, req.limit` |
| `check_db_hr_requirement` | `function` | **Check an achieved value against a requirement.**<br>• `value`, `requirement`<br>• Rounds as DB-HR prescribes, then compares | `check_db_hr_requirement(32.8, req)`<br><br>• `DbHrCheck` |
| `DbHrCheck` | `dataclass` | **A DB-HR requirement checked.**<br>• `requirement`, `value`, `reported`, `margin`, `complies`<br>• takes `requirement`, `value`; `reported`, `margin`, `complies` are read-only, read from them | `chk.reported, chk.complies` |
| `assess_db_hr` | `function` | **Check a set of (value, requirement) pairs.**<br>• `items` | `assess_db_hr([(33.0, req)])`<br><br>• `DbHrAssessment` |
| `DbHrAssessment` | `dataclass` | **A set of DB-HR requirement checks.**<br>• `checks`; `.complies`<br>• `.plot()` | `a.complies` |
| `energy_average_level` | `function` | **Energy-average level (ISO 16283-1 (9)).**<br>• `levels`: Levels [dB] to average<br>• `axis`: Averaging axis (Default: -1) | `L = building.energy_average_level([60, 66])`<br><br>• `10 lg( mean(10^(Li/10)) )` |
| `AirborneInsulationResult` | `dataclass` | **Field insulation per band.**<br>• `d`: Level difference D [dB]<br>• `dnt`: Standardized DnT [dB]<br>• `r_prime`: Apparent R' [dB] or None<br>• `l1`, `l2`, `t2`, `t0`: retained measurement chain (or None)<br>• `source_low_frequency`, `receiver_low_frequency`: `LowFrequencyResult` or None<br>• `.report(path, quantity='dnt'/'r_prime', ...)`: ISO 16283-1 field test report (Annex B form) with the ISO 717-1 rating → PDF | `res.report("DnTw.pdf", metadata=ReportMetadata(requirement=50.0))` |
| `WeightedRatingResult` | `dataclass` | **Weighted rating result.**<br>• `rating`: Rw/DnT,w … [dB], int<br>• `c`: Spectrum term C, int<br>• `ctr`: Spectrum term Ctr, int<br>• `unfavourable_sum`: [dB]<br>• `band_centers`: Measured-curve centres [Hz] or None<br>• `measured`: Measured band values [dB] or None<br>• `shifted_reference`: Shifted Table 3 reference [dB] or None | `w.rating, w.c, w.ctr` |
| `impact_insulation` | `function` | **Field impact insulation (ISO 16283-2).**<br>• `li`: Impact SPL [dB], 1D or (positions, bands)<br>• `t2`: Receiving-room T per band [s]<br>• `volume`: Receiving V [m³] (for L'n)<br>• `t0`: Reference T0 [s] (Default: 0.5)<br>• `frequencies` [Hz] (required with `low_frequency`)<br>• `low_frequency`: receiving-room `LowFrequencyProcedure` (ISO 16283-2 Clause 8)<br>• Warns (`LowFrequencyWarning`) when `volume` rounds below 25 m³, `frequencies` names 50/63/80 Hz and no `low_frequency` is given | `imp = building.impact_insulation(li, t2, volume=50)`<br><br>• `ImpactInsulationResult` (`l_n_t`, `l_n`) |
| `weighted_impact_rating` | `function` | **Single-number impact rating + CI (ISO 717-2).**<br>• `values_by_band`: 16 thirds (100-3150 Hz) or 5 octaves (125-2000 Hz) [dB], or a mapping of band centre in Hz to dB, read as `weighted_rating` reads one<br>• `bands`: 'third-octave', 'octave' or None | `r = building.weighted_impact_rating(imp.l_n_t)`<br><br>• `ImpactRatingResult` (Ln,w, CI); octave rating carries the -5 dB rule |
| `weighted_impact_rating_extended` | `function` | **Impact rating + CI,50-2500 (ISO 717-2:2020 A.2.1 NOTE).**<br>• `values_by_band` [dB] with `frequencies` [Hz] (None = the 16 core bands)<br>• `one_decimal`: 0.1 dB shift (reproduces Ln,r,0,w = 77.6, CI,r,0 = -10.3 of A.2.2) (Default: False) | `ext = building.weighted_impact_rating_extended(ln, freqs)`<br><br>• `ExtendedImpactRatingResult` (rating, ci, ci_50_2500) |
| `ExtendedImpactRatingResult` | `dataclass` | **Weighted impact rating with CI,50-2500 (ISO 717-2:2020 A.2.1).**<br>• `rating`, `ci`, `ci_50_2500`<br>• `core`: the base `ImpactRatingResult` | `res = building.weighted_impact_rating_extended(freqs, ln)` |
| `weighted_impact_improvement` | `function` | **Weighted improvement ΔLw or ΔLt,w (ISO 717-2:2020 Clauses 5 and 6).**<br>• `delta_l`: 16 one-third-octave ΔL (100-3150 Hz) [dB], or a mapping of band centre in Hz to ΔL holding those 16 bands<br>• `reference_floor`: 'heavyweight' / 'lightweight_1' / 'lightweight_2' / 'lightweight_3' (Default: 'heavyweight')<br>• `one_decimal`: 0.1 dB shift, one-decimal result (Default: False)<br>Rates Ln,r = Ln,r,0 − ΔL on the Table 4 curve: ΔLw = Ln,r,0,w − Ln,r,w | `weighted_impact_improvement(delta_l, reference_floor='lightweight_3')`<br><br>• ΔLw [dB], int (e.g. 19), or float with `one_decimal` |
| `impact_improvement_adaptation_term` | `function` | **Spectrum adaptation term CI,Δ or CIΔ,t (ISO 717-2:2020 Formulas (A.4) and (A.6)).**<br>• `delta_l`: 16 one-third-octave ΔL (100-3150 Hz) [dB], or a mapping of band centre in Hz to ΔL holding those 16 bands<br>• `reference_floor` (Default: 'heavyweight'), `one_decimal` (Default: False)<br>CI,Δ = CI,r,0 − CI,r (CI,r,0 = −11 dB; CI,t,r,0 = 0 / −3 dB on the lightweight floors); ISO 16251-1 clause 8 e), ISO 10140-1:2021 H.5 h) | `impact_improvement_adaptation_term(delta_l)`<br><br>• CI,Δ [dB], int, or float with `one_decimal` |
| `impact_improvement` | `function` | **Floor-covering improvement ΔL (ISO 16251-1).**<br>• `bare`, `with_covering`: acceleration levels L0/L1 per band [dB]<br>• `frequencies` [Hz] (a clause 6.3 spectrum is rated on its 100-3150 Hz sub-range)<br>• `background`: optional Lb per band [dB] (Formula 2) | `res = building.impact_improvement(l0, l1, f)`<br><br>• `FloorCoveringImprovementResult` |
| `acceleration_level` | `function` | **Vibratory acceleration level La (ISO 16251-1 Formula 1).**<br>• `acceleration`: RMS a per band [m/s²]<br>• `reference`: a0 (Default: 1e-6) | `acceleration_level(1e-3)  # 60 dB` |
| `background_corrected_level` | `function` | **Background correction (ISO 16251-1 Formula 2).**<br>• `signal_and_background`, `background` [dB] | `L, limited = building.background_corrected_level(lp, lb)`<br><br>• (corrected [dB], limit-of-measurement mask) |
| `improvement_octave_bands` | `function` | **Thirds → octaves for ΔL (ISO 16251-1 Formula 5).**<br>• `improvement`, `frequencies` (whole octave triplets) | `f_oct, dl_oct = building.improvement_octave_bands(dl, f)` |
| `FloorCoveringImprovementResult` | `dataclass` | **Floor-covering improvement (ISO 16251-1).**<br>• `improvement` ΔL [dB], `delta_lw`, `ci_delta` (or None)<br>• `background_margin_db`: smallest margin over the background per band [dB] (or None)<br>• `limited`: > ΔL mask, the margin under the 6 dB of Formula (2); `.octave_bands()`, `.plot()`<br>• takes `frequencies`, `improvement`, `delta_lw`, `ci_delta`, `background_margin_db`; `limited` is read-only, read from them | `res.delta_lw, res.ci_delta` |
| `ImpactImprovementRatingResult` | `dataclass` | **A covering's ΔLw with both adaptation terms (ISO 717-2:2020 Formula (2), Clause A.2.2).**<br>• `delta_lw`, `ci_delta` (CI,Δ, Formula (A.4)) and `ci_r` (CI,r = CI,r,0 − CI,Δ, CI,r,0 = −11 dB), whole decibels<br>• `band_centers` (the 16 thirds 100-3150 Hz), `improvement` (ΔL as given)<br>• refuses a `ci_r` that is not −11 − `ci_delta`; `.plot()` draws ΔL with the three numbers in the title, and an axis that keeps a negative band in view | `r = row.rating()  # an ImpactImprovementSpectrum`<br>`r.delta_lw, r.ci_delta, r.ci_r`<br><br>• `ImpactImprovementSpectrum` |
| `ImpactInsulationResult` | `dataclass` | **Impact insulation per band.**<br>• `l_n_t`: Standardized L'nT [dB]<br>• `l_n`: Normalized L'n [dB] or None<br>• `li`, `t2`, `t0`: retained measurement chain (or None)<br>• `low_frequency`: `LowFrequencyResult` or None<br>• `.report(path, quantity='l_n_t'/'l_n', ...)`: ISO 16283-2 field test report (Annex C form) with the ISO 717-2 rating → PDF | `imp.report("LnTw.pdf", metadata=ReportMetadata(requirement=58.0))` |
| `ImpactRatingResult` | `dataclass` | **Weighted impact rating.**<br>• `rating`: Ln,w/L'n,w/L'nT,w [dB], int<br>• `ci`: Spectrum term CI, int<br>• `unfavourable_sum`: [dB]<br>• `band_centers`: Measured-curve centres [Hz] or None<br>• `measured`: Measured impact levels [dB] or None<br>• `shifted_reference`: Shifted impact reference [dB] or None | `r.rating, r.ci` |
| `ReportMetadata` | `dataclass` | **Metadata for the accredited ISO 717 `.report()` PDF fiche.**<br>• All fields optional; only the supplied ones render<br>• `specimen`, `client`, `manufacturer`, `product`, `test_room`, `instrumentation`, `calibration`, `mounting`, `measurement_standard`, `test_date`, `separating_element`, `test_signal`<br>• numeric (finite, positive): `area`, `mass_per_area`, `source_volume`, `receiving_volume`, `temperature_c`, `relative_humidity_percent`, `static_pressure_kpa`, `requirement`; `curing_time_h` (finite, not negative)<br>• `laboratory`, `operator`, `report_id`, `notes` | `w.report("f.pdf", metadata=ReportMetadata(area=10.0, requirement=52.0))` |
| `facade_insulation` | `function` | **Field façade insulation (ISO 16283-3).**<br>• `l1_2m`/`l2`: Level 2 m in front / receiving levels [dB], 1D or (positions, bands)<br>• `t2`: Receiving-room T per band [s]<br>• `area`: Element S [m²], `volume`: Receiving V [m³], `surface_level`: L1,s [dB] (all three for R')<br>• `method`: 'loudspeaker' (−1.5 dB) / 'road_traffic' (−3 dB)<br>• `t0`: Reference T0 [s] (Default: 0.5)<br>• `frequencies` [Hz] (required with `low_frequency`)<br>• `low_frequency`: receiving-room `LowFrequencyProcedure` (ISO 16283-3 Clause 7.3); loudspeaker methods only<br>• Warns (`LowFrequencyWarning`) when a loudspeaker-method `volume` rounds below 25 m³, `frequencies` names 50/63/80 Hz and no `low_frequency` is given | `fac = building.facade_insulation(l1_2m, l2, t2, volume=50, area=11.5, surface_level=ls)`<br><br>• `FacadeInsulationResult` |
| `FacadeInsulationResult` | `dataclass` | **Façade insulation per band.**<br>• `d_2m`: Level difference D2m [dB]<br>• `d_2m_nt`: Standardized D2m,nT [dB]<br>• `d_2m_n`: Normalized D2m,n [dB] or None<br>• `r_prime`: Apparent R'45°/R'tr,s [dB] or None<br>• `frequencies` [Hz] or None<br>• `method`: the incidence correction used<br>• `low_frequency`: `LowFrequencyResult` or None<br>• `.plot()` | `fac.d_2m_nt, fac.r_prime` |
| `LowFrequencyProcedure` | `dataclass` | **ISO 16283 low-frequency measurements of one room (Clause 8 / 7.3).**<br>• `volume`: Room V [m³]; must round below 25 m³<br>• `corner_levels`: (corners, 3) or (positions, corners, 3) at 50/63/80 Hz [dB]<br>• `reverberation_63_octave`: 63 Hz octave T [s] (receiving room, Clause 10.4 / 8.4) | `lf = building.LowFrequencyProcedure(volume=18.0, corner_levels=c, reverberation_63_octave=0.72)` |
| `low_frequency_procedure_applies` | `function` | **The printed 25 m³ trigger.**<br>• `volume`: Room V [m³], rounded to the nearest cubic metre (half away from zero)<br>• True only for a rounded volume strictly below 25 m³ | `building.low_frequency_procedure_applies(18.0)  # True` |
| `corner_level` | `function` | **Corner level L_Corner (ISO 16283-1 (12) / -2 (15)).**<br>• `corner_levels`: (corners, bands) or (positions, corners, bands) [dB]<br>• Highest corner per band, then energy-averaged over source positions | `lc = building.corner_level(corners)` |
| `low_frequency_level` | `function` | **Combination L_LF (ISO 16283-1 (13) / -2 (16) / -3 (5)).**<br>• `level`: Default-procedure L [dB]<br>• `corner`: L_Corner [dB]<br>• `10 lg[(10^(0,1 Lc) + 2·10^(0,1 L))/3]` | `llf = building.low_frequency_level(l, lc)` |
| `apply_low_frequency_procedure` | `function` | **Run the procedure over a whole band vector.**<br>• `level`, `frequencies`, `procedure`<br>• `reverberation_time`: measured T per band (receiving room)<br>• `room`: 'receiving' (Clause 10.4 applies) or 'source' | `res = building.apply_low_frequency_procedure(l2, f, lf, reverberation_time=t2)` |
| `LowFrequencyResult` | `dataclass` | **What the procedure did to one room.**<br>• `levels`, `reverberation_time`: full band vectors after substitution<br>• `l_default`, `l_corner`, `l_lf`: the three-band chain [dB]<br>• `low_frequency_bands` [Hz], `volume` [m³], `reverberation_63_octave` [s]<br>• `.plot()` | `res.l_lf, res.reverberation_time` |
| `LOW_FREQUENCY_BANDS` | `tuple` | **The three one-third-octave bands the procedure covers** (50, 63, 80 Hz). | `building.LOW_FREQUENCY_BANDS` |
| `LOW_FREQUENCY_VOLUME_LIMIT` | `float` | **Room volume the procedure stops at**, 25 m³ to the nearest cubic metre, strictly. | `building.LOW_FREQUENCY_VOLUME_LIMIT  # 25.0` |
| `LowFrequencyWarning` | `warning class` | **An ISO 16283 low-frequency requirement the measurement does not meet.**<br>• Fewer corners than the printed minimum of four; the arithmetic is unaffected<br>• A room under the 25 m³ trigger whose 50/63/80 Hz bands are about to be answered from the default procedure alone, which Clause 8.1 forbids and which does move the number<br>• Filter the two apart by message, not by class | `warnings.simplefilter('error', building.LowFrequencyWarning)`<br>Emitted by `building.measurement.low_frequency` |
| `lab_airborne_insulation` | `function` | **Laboratory airborne insulation (ISO 10140-2).**<br>• `l1`/`l2`: Source/receiving levels [dB], 1D or (positions, bands)<br>• `t2`: Receiving-room T per band [s]<br>• `area`: Free test-opening S [m²]<br>• `volume`: Receiving V [m³] | `lab = building.lab_airborne_insulation(l1, l2, t2, area=10, volume=50)`<br><br>• `LabAirborneInsulationResult` |
| `lab_impact_insulation` | `function` | **Laboratory impact insulation (ISO 10140-3).**<br>• `li`: Tapping-machine impact SPL [dB], 1D or (positions, bands)<br>• `t2`: Receiving-room T per band [s]<br>• `volume`: Receiving V [m³] | `imp = building.lab_impact_insulation(li, t2, volume=50)`<br><br>• `LabImpactInsulationResult` |
| `lab_lining_improvement` | `function` | **Improvement of airborne sound insulation by a lining (ISO 10140-1:2021 Annex G).**<br>• `r_without_db` / `r_with_db`: R of the basic element without / with the lining per band [dB]<br>• `frequencies_hz`: Band centres [Hz]<br>• `basic_element`: 'heavy_wall' / 'heavy_floor' / 'lightweight_wall', or None for another element (Default: 'heavy_wall') | `res = building.lab_lining_improvement(r0, r1, f)`<br><br>• `LabLiningImprovementResult` (ΔR, ΔRw on the reference curve, ΔRw,direct) |
| `LabLiningImprovementResult` | `dataclass` | **ΔR per band with its single numbers.**<br>• `delta_r_db`, `r_without_db`, `r_with_db`, `frequencies_hz`, `basic_element`<br>• `rating`: `ReductionImprovementRating` on the element's reference curve, or None<br>• `delta_rw_direct_db`, `delta_rw_c_direct_db`, `delta_rw_ctr_direct_db`: ISO 717-1:2020 Formula (D.2), or None<br>• `.octave_bands()`, `.plot()` | `res.rating.delta_rw, res.delta_rw_direct_db` |
| `weighted_reduction_improvement` | `function` | **Lining rating on a standard basic element (ISO 717-1:2020 Annex D, Formulas (D.3) and (D.4)).**<br>• `delta_r`: ΔR per band [dB]<br>• `frequencies`: Band centres [Hz], 50-5000 Hz with the 16 core bands (Default: None = the 16 core bands)<br>• `basic_element`: 'heavy_wall' / 'heavy_floor' / 'lightweight_wall' (Default: 'heavy_wall')<br>• `one_decimal`: 0.1 dB shift and one-decimal differences (Default: False) | `r = building.weighted_reduction_improvement(dr, f)`<br><br>• `ReductionImprovementRating` |
| `ReductionImprovementRating` | `dataclass` | **ΔRw, Δ(Rw + C), Δ(Rw + Ctr) and every enlarged-range difference the bands reach.**<br>• `basic_element`; `.index`: 'heavy' / 'light' (ISO 717-1:2020 D.3)<br>• `without_lining` / `with_lining`: the two `ExtendedWeightedRatingResult`<br>• `.plot()` | `r.delta_rw, r.index` |
| `LINING_REFERENCE_ELEMENTS` | `mapping` | **Rref,without of the three standard basic elements (ISO 717-1:2020 Table E.1), 50-5000 Hz [dB].**<br>'heavy_wall', 'heavy_floor', 'lightweight_wall' → {band [Hz]: R [dB]}, read-only | `building.LINING_REFERENCE_ELEMENTS['heavy_wall'][500.0]  # 48.5` |
| `IMPACT_REFERENCE_FLOORS` | `mapping` | **Ln,r,0 and Ln,t,r,0 of the four reference floors (ISO 717-2:2020 Table 4), 100-3150 Hz [dB].**<br>'heavyweight', 'lightweight_1', 'lightweight_2', 'lightweight_3' → {band [Hz]: level [dB]}, read-only; No 1 and No 2 share one curve | `building.IMPACT_REFERENCE_FLOORS['lightweight_3'][1000.0]  # 74.0` |
| `check_lining_curing` | `function` | **Is the basic element settled for the two measurements? (ISO 10140-1:2021 G.4).**<br>• `curing_time_days`: End of construction to first measurement [d]<br>• `time_lag_days`: Between the two measurements [d]<br>• `required_curing_days` (Default: 14) | `building.check_lining_curing(3.0, 1.0).passes  # True`<br><br>• `LiningCuringCheck` |
| `LiningCuringCheck` | `dataclass` | **The G.4 verdict: two weeks of curing, or a lag of at most a third of it.**<br>• `cured`, `lag_within_third`, `passes`; `.earliest_start_days`<br>• No truth value (`bool()` raises); `.plot()`<br>• takes `curing_time_days`, `time_lag_days`, `required_curing_days`; `cured`, `lag_within_third`, `passes` are read-only, read from them | `check.passes` |
| `lab_floor_covering_improvement` | `function` | **Improvement of impact sound insulation by a floor covering (ISO 10140-1:2021 Annex H, Formula (H.1)).**<br>• `l_n0_db` / `l_n_db`: Ln of the reference floor without / with the covering [dB]<br>• `frequencies_hz`: Band centres [Hz]<br>• `reference_floor`: 'heavyweight' / 'lightweight_1' / 'lightweight_2' / 'lightweight_3' (Default: 'heavyweight') | `cov = building.lab_floor_covering_improvement(ln0, ln, f, reference_floor='lightweight_1')`<br><br>• `LabFloorCoveringImprovementResult` |
| `LabFloorCoveringImprovementResult` | `dataclass` | **ΔL per band with ΔLw or ΔLt,n,w.**<br>• `improvement_db`, `delta_lw_db`, `ci_delta_db`; `.designation`<br>• `reference_rating` (Ln,r,w, CI,r) and `bare_rating` (Ln,0,w, CI,0) of H.5 i)<br>• `.octave_bands()` (Formula (H.2)), `.plot(rating_range=False)`<br>• `.report(path, metadata=..., verbose=False, language='en')`: the form of ISO 10140-1:2021 Figure H.4 → PDF | `cov.designation, cov.delta_lw_db` |
| `joint_sound_reduction_index` | `function` | **Sound reduction index of joints per metre (ISO 10140-1:2021 Formula (J.1)).**<br>• `l1_db` / `l2_db`: Source / receiving-room level [dB], 1D or (positions, bands)<br>• `absorption_m2`: Receiving-room A per band [m²]<br>• `joint_length_m`: Length l of the joint [m] | `building.joint_sound_reduction_index([95.0], [48.6], [12.4], joint_length_m=5.4)`<br><br>• Rs per band [dB] |
| `lab_joint_insulation` | `function` | **A joint corrected for its test arrangement (ISO 10140-1:2021 J.1, Formula (J.2), ISO 10140-2:2021 A.3).**<br>• `r_s_measured_db`: R's per band [dB]<br>• `r_s_max_db`: Rs,max of the sealed arrangement [dB]<br>• `frequencies_hz`: Band centres [Hz]<br>• `joint_length_m`: Kept for the form (Default: None)<br>• `limit_at_maximum`: Set the bands within 3 dB of Rs,max to Rs,max (Default: True) | `seal = building.lab_joint_insulation(r1, rmax, f, joint_length_m=5.4)`<br><br>• `LabJointInsulationResult` |
| `LabJointInsulationResult` | `dataclass` | **Rs per band with its regime and single numbers.**<br>• `r_s_db`, `r_s_measured_db`, `r_s_max_db`, `limit_at_maximum`; `regime` ('uncorrected' / 'corrected' / 'limit' / 'maximum') is read-only, read from them, and `r_s_db` is held to the J.1 rule it names; `.minimum_value`, `.indicative`<br>• `rating` (Rs,w, C, Ctr), `c_100_5000_db`, `ctr_100_5000_db`, `max_rating`, `open_band_rating`; `.bracketed`; `.r_s_w_db`, `.r_s_w_c_db`, `.r_s_w_ctr_db`<br>• `.octave_bands()`, `.plot()`<br>• `.report(path, metadata=..., verbose=False, language='en')`: the form of ISO 10140-1:2021 Figure J.7 → PDF | `seal.rating.rating, seal.bracketed` |
| `JointOpenBandRating` | `dataclass` | **The single numbers with the indicative bands taken as infinitely high (ISO 10140-1:2021 J.1).**<br>• `open_frequencies_hz`, `r_s_w_db`, `c_db`, `ctr_db`, `c_100_5000_db`, `ctr_100_5000_db` (None when unbounded); `.plot()` | `seal.open_band_rating.r_s_w_db` |
| `check_joint_test_element` | `function` | **Is the joint long and narrow enough? (ISO 10140-1:2021 J.2.1, J.2.2).**<br>• `joint_length_m`: Longer than 1 m [m]<br>• `joint_width_mm`: At most 50 mm [mm]<br>• `window_or_door_gap`: At least 5,0 m for a window or door gap (Default: False) | `building.check_joint_test_element(5.4, 5.0, window_or_door_gap=True).passes  # True`<br><br>• `JointTestElementCheck` |
| `JointTestElementCheck` | `dataclass` | **The J.2 verdict.**<br>• `length_ok`, `width_ok`, `passes`<br>• No truth value (`bool()` raises); `.plot()`<br>• takes `joint_length_m`, `joint_width_mm`, `window_or_door_gap`; `length_ok`, `width_ok`, `passes` are read-only, read from them | `check.passes` |
| `check_gap_width` | `function` | **The gap width from four readings or more within 0,3 mm (ISO 10140-1:2021 J.2.2).**<br>• `readings_mm`: Gap widths read along the joint [mm] | `building.check_gap_width([5.1, 4.9, 5.0, 5.2]).gap_width_mm  # 5.05`<br><br>• `GapWidthCheck` |
| `GapWidthCheck` | `dataclass` | **The averaged gap width and its verdict.**<br>• `gap_width_mm`, `spread_mm`, `enough_positions`, `uniform`, `passes`<br>• No truth value (`bool()` raises); `.plot()`<br>• takes `readings_mm`; `gap_width_mm`, `spread_mm`, `enough_positions`, `uniform`, `passes` are read-only, read from them | `gap.gap_width_mm, gap.passes` |
| `joint_gap_series` | `function` | **A variable slit at its gap widths (ISO 10140-1:2021 J.4, J.5.2 h) and i)).**<br>• `gap_widths_mm`: Gap width of each result [mm]<br>• `results`: `LabJointInsulationResult` per width, each rated<br>• `nominal_gap_mm`: bn (Default: 5.0)<br>• `minimum_gap_mm`: bmin (Default: None) | `series = building.joint_gap_series([3.0, 5.0, 8.0], results)`<br><br>• `JointGapSeries` |
| `JointGapSeries` | `dataclass` | **Rs,w, Rs,w + C and Rs,w + Ctr against the gap width.**<br>• `gap_widths_mm`, `r_s_w_db`, `r_s_w_c_db`, `r_s_w_ctr_db`, `results`; `.working_range_mm`<br>• `.single_number(quantity)`, `.at_gap(gap_mm, quantity)`<br>• `.plot(quantity='r_s_w_ctr')` (Figure J.8), `.plot_octave_bands()` (Figure J.9, with the sealed element as Rs,max) | `series.at_gap(7.0)` |
| `check_joint_gap_series` | `function` | **Was the slit measured at bn, bmin and bn + 3? (ISO 10140-1:2021 J.4).**<br>• `series`: The `JointGapSeries` of the slit; a width within 0,3 mm of a required one counts as it, and an unnamed bmin fails | `building.check_joint_gap_series(series).passes  # True`<br><br>• `JointGapSeriesCheck` |
| `JointGapSeriesCheck` | `dataclass` | **The three gap widths of J.4 and the verdict.**<br>• `nominal_measured`, `minimum_measured`, `working_range_measured`, `passes`; `.tolerance_mm`<br>• No truth value (`bool()` raises); `.plot()`<br>• takes `gap_widths_mm`, `nominal_gap_mm`, `minimum_gap_mm`; `nominal_measured`, `minimum_measured`, `working_range_measured`, `passes` are read-only, read from them | `widths.passes` |
| `heavy_impact_improvement` | `function` | **Floor-covering improvement under the rubber ball (ISO 10140-1:2021 H.6.1, Formula (H.3)).**<br>• `l_i_fmax_0_db` / `l_i_fmax_db`: Li,Fmax without / with the covering [dB]<br>• `frequencies_hz`: Band centres [Hz] | `building.heavy_impact_improvement(l0, l1, f).improvement_db`<br><br>• `HeavyImpactImprovementResult` |
| `HeavyImpactImprovementResult` | `dataclass` | **ΔLr per band.**<br>• `improvement_db`, `l_i_fmax_0_db`, `l_i_fmax_db`, `frequencies_hz`; `.plot()` | `res.improvement_db` |
| `rainfall_sound` | `function` | **Sound intensity level of a specimen under artificial rain (ISO 10140-1:2021 K.4.2, Formula (K.1)).**<br>• `l_pr_db`: Room-averaged SPL [dB], (bands,) or (positions, bands) added energetically<br>• `reverberation_time_s`: Test-room T [s]; `frequencies_hz` [Hz]<br>• `volume_m3`: Test-room V [m³]; `excited_area_m2`: Se [m²]<br>• `background_db`: ISO 10140-4 correction (Default: None)<br>• `reference_correction`: `RainfallReferenceCorrection` or ΔLIc per band [dB] (Default: None) | `rain = building.rainfall_sound(lpr, t, f, volume_m3=62.0, excited_area_m2=1.875)`<br><br>• `RainfallSoundResult` |
| `rainfall_sound_from_intensity` | `function` | **The same level by direct intensity (ISO 10140-1:2021 K.4.3, Formula (K.4)).**<br>• `l_im_db`: Intensity level over the surface [dB]; `frequencies_hz` [Hz]<br>• `measuring_area_m2`: Sm [m²]; `excited_area_m2`: Se [m²]<br>• `reference_correction` (Default: None) | `building.rainfall_sound_from_intensity(lim, f, measuring_area_m2=4.0, excited_area_m2=1.875)`<br><br>• `RainfallSoundResult` |
| `RainfallSoundResult` | `dataclass` | **LI per band with LIA and the normalized levels.**<br>• `l_i_db`; `l_ia_db` (Formula (K.2) over the 18 bands 100-5000 Hz, or None); `method`<br>• `correction_db`, `l_i_norm_db`, `l_ia_norm_db` (Formula (K.5)), or None<br>• `.octave_bands(normalized=False)` (Formula (K.3)), `.sound_power_levels(specimen_area_m2)`, `.plot()` | `rain.l_ia_db, rain.l_ia_norm_db` |
| `rainfall_reference_correction` | `function` | **Laboratory correction ΔLIc from the reference glass pane (ISO 10140-5:2021 Annex I).**<br>• `l_i_ref_db`: LI,ref of the pane [dB]<br>• `structural_reverberation_time_s`: Ts [s]<br>• `frequencies_hz`: Bands of Table I.1 (Default: None = all 18) | `corr = building.rainfall_reference_correction(li_ref, t_s)`<br><br>• `RainfallReferenceCorrection` |
| `RainfallReferenceCorrection` | `dataclass` | **η, LI,m,ref and ΔLIc per band (Formulas (I.1) to (I.3)).**<br>• `loss_factor`, `reference_loss_factor`, `l_i_m_ref_db`, `l_ic_ref_db`, `correction_db`; `.plot()` | `corr.correction_db` |
| `rainfall_rate` | `function` | **Rainfall rate from the water collected (ISO 10140-5:2021 H.2.3).**<br>• `collected_volume_litres` [L], `collection_area_m2` [m²], `duration_s` [s] | `building.rainfall_rate(3.1, 0.08, 3600.0)  # 38.75 mm/h` |
| `verify_rain_generator` | `function` | **Does the generator make the rain of Table H.1? (ISO 10140-5:2021 H.1).**<br>• `rainfall_rate_mm_h`: Measured rate [mm/h], within ±2 mm/h<br>• `rain_type`: 'heavy' / 'intense' (Default: 'heavy')<br>• `drop_diameters_mm` / `fall_velocities_m_s`: Drop samples, half within ±0.5 mm / ±1 m/s (Default: None) | `building.verify_rain_generator(38.75).passes  # True`<br><br>• `RainGeneratorVerification` |
| `RainGeneratorVerification` | `dataclass` | **The H.1 verdict.**<br>• `rate_ok`, `drops_ok`, `velocities_ok`, `passes`; `.nominal`<br>• No truth value (`bool()` raises); `.plot()`<br>• takes `rain_type`, `rainfall_rate_mm_h`, `drop_diameters_mm`, `fall_velocities_m_s`; `rate_deviation_mm_h`, `rate_ok`, `drop_share`, `drops_ok`, `velocity_share`, `velocities_ok`, ... are read-only, read from them | `check.passes` |
| `ARTIFICIAL_RAIN` / `ArtificialRain` | `mapping` / `dataclass` | **The two artificial rains (ISO 10140-5:2021 Tables H.1 and H.2).**<br>• 'intense' (15 mm/h, 2 mm, 4 m/s) and 'heavy' (40 mm/h, 5 mm, 7 m/s), with the tank and the H.1 tolerances | `building.ARTIFICIAL_RAIN['heavy'].rainfall_rate_mm_h  # 40.0` |
| `RAINFALL_CLASSIFICATION` / `RainfallType` | `mapping` / `dataclass` | **The four classes of natural rain (ISO 10140-1:2021 Table K.1).**<br>• 'moderate', 'intense', 'heavy', 'cloudburst'; each quantity a (lower, upper) pair, None for an open end | `building.RAINFALL_CLASSIFICATION['heavy'].rainfall_rate_mm_h  # (None, 40.0)` |
| `RAINFALL_A_WEIGHTING` | `mapping` | **The 18 C_j of ISO 10140-1:2021 Table K.2 [dB], 100-5000 Hz.**<br>• The IEC 61672-1 A-weighting at the exact midband frequencies, rounded to 0,1 dB; read-only | `building.RAINFALL_A_WEIGHTING[100.0]  # -19.1` |
| `RAINFALL_REFERENCE_LOSS_FACTOR_DB` / `RAINFALL_REFERENCE_INTENSITY_DB` | `mapping` | **ISO 10140-5:2021 Table I.1: 10 lg(ηref) and LIc,ref of the reference pane [dB], 100-5000 Hz.**<br>• Read-only; the result's `reference_loss_factor` is the linear ηref | `building.RAINFALL_REFERENCE_INTENSITY_DB[2500.0]  # 51.0` |
| `intensity_sound_reduction` | `function` | **Intensity sound reduction index RI (ISO 15186-1 Formula (7)).**<br>• `lp1`: Source-room level [dB], 1D or (positions, bands)<br>• `l_in`: Normal intensity level over the surface [dB]<br>• `measurement_area`: Surface Sm [m²], `area`: Specimen S [m²]<br>• `kc`: Adaptation term per band [dB] for RI,M (Default: None) | `res = building.intensity_sound_reduction(lp1, l_in, measurement_area=12, area=10)`<br><br>• `IntensityReductionResult` (`r_i`, `r_i_modified`, `rating`, `rating_modified`) |
| `adaptation_term_kc` | `function` | **Adaptation term Kc (ISO 15186-1 Annex B).**<br>• `frequencies`: Midband frequencies [Hz]<br>• `boundary_area`/`volume`: Room Sb2/V2 for Formula (B.1); omit both for the 10 lg(1+61,4/f) approximation (B.2) | `kc = building.adaptation_term_kc(freqs)`<br><br>• Kc per band [dB] |
| `intensity_element_normalized_difference` | `function` | **Intensity element normalized level difference DI,n,e (ISO 15186-1 Formula (8)).**<br>• `lp1`/`l_in`: Source level / surface intensity level [dB]<br>• `measurement_area`: Surface Sm [m²]<br>• `n`: Element units N (Default: 1) | `d = building.intensity_element_normalized_difference(lp1, l_in, measurement_area=10)`<br><br>• `IntensityElementNormalizedResult` (`d_i_n_e`, `rating`) |
| `surface_pressure_intensity_indicator` / `combine_subareas` | `function` | **Surface indicator FpI and subarea combination (ISO 15186-1 Formulas (10)-(12)).**<br>• `lp`/`l_in`: Surface pressure / intensity levels [dB]<br>• `combine_subareas(l_in, measurement_area)`: `(subareas, bands)` levels + per-subarea areas (negative area = reverse-flow subarea, Clause 6.4.6) | `fpi = building.surface_pressure_intensity_indicator(lp, l_in)`<br><br>• `FpI` array; `(LIn, Sm = Σ abs(Smi))` |
| `IntensityReductionResult` / `IntensityElementNormalizedResult` | `dataclass` | **ISO 15186-1 intensity insulation results.**<br>• `r_i` / `r_i_modified` per band with `rating` / `rating_modified`<br>• `d_i_n_e` per band with `rating` | `res = building.intensity_sound_reduction(...)` |
| `low_frequency_intensity_reduction` | `function` | **Low-frequency intensity sound reduction index RI (ISO 15186-3 Formula (7)).**<br>• `lp_surface`: Level over the surface of the specimen [dB], 1D or (positions, bands)<br>• `l_in`: Normal intensity level over the measurement surface [dB]<br>• `measurement_area`: Surface Sm [m²], `area`: Specimen S [m²]<br>• `l_p`: Receiving-side pressure on the measurement surface [dB] for FpI (Default: None)<br>• `frequencies`: 50 Hz to 160 Hz only (Clause 6.6) (Default: None)<br>• `absorbing_specimen_surface`: Tightens the Clause 6.4.2 limit to 6 dB (Default: False) | `res = building.low_frequency_intensity_reduction(lps, l_in, measurement_area=12.6, area=10)`<br><br>• `LowFrequencyIntensityResult` (`r_i`, `surface_pressure_intensity_indicator`, `qualified`, `indicator_limit`) |
| `low_frequency_element_normalized_difference` | `function` | **Low-frequency element normalized level difference DI,n,e (ISO 15186-3 Formula (8)).**<br>• `lp_surface`/`l_in`: Surface level / measurement-surface intensity level [dB]<br>• `measurement_area`: Surface Sm [m²]<br>• `elements`: Element units N, added as +10 lg N (Default: 1)<br>• `l_p`: Receiving-side pressure on the measurement surface [dB] for FpI (Default: None)<br>• `frequencies`: 50 Hz to 160 Hz only (Clause 1.1) (Default: None)<br>• `absorbing_specimen_surface`: Tightens the Clause 6.4.2 limit to 6 dB (Default: False) | `d = building.low_frequency_element_normalized_difference(lps, l_in, measurement_area=2.0)`<br><br>• `LowFrequencyElementResult` (`d_i_n_e`, `surface_pressure_intensity_indicator`, `qualified`, `indicator_limit`) |
| `limp_panel_reduction_index` | `function` | **Calculated limp-panel sound reduction index (ISO 15186-3 Annex A, Formulas (A.1)-(A.5)).**<br>• `frequencies`: Mid-band frequencies [Hz]<br>• `surface_mass`: Panel mass m [kg/m²], `area`: Panel S [m²] (≥ 1 m²)<br>• `temperature_c`/`static_pressure_pa`: Climate of (A.4) and (A.5) (Default: 23 °C, 101 300 Pa) | `r = building.limp_panel_reduction_index(freqs, surface_mass=10.0, area=10.0)`<br><br>• `R` array [dB]; a measurement must agree within 4,0 dB from 50 Hz to 160 Hz |
| `LowFrequencyIntensityResult` / `LowFrequencyElementResult` | `dataclass` | **ISO 15186-3 low-frequency intensity results.**<br>• `r_i` / `d_i_n_e` per band, no rating (six bands cannot feed ISO 717-1)<br>• `surface_pressure_intensity_indicator` and `qualified`, or `None` when `l_p` was not given<br>• `indicator_limit`: The Clause 6.4.2 limit the bands were judged by, 10 dB or 6 dB<br>• `LowFrequencyElementResult` takes `d_i_n_e`, `surface_pressure_intensity_indicator`, `frequencies`, `measurement_area`, `elements`, `absorbing_specimen_surface`; `qualified` is read-only, read from them<br>• `LowFrequencyIntensityResult` takes `r_i`, `surface_pressure_intensity_indicator`, `frequencies`, `area`, `measurement_area`, `absorbing_specimen_surface`; `qualified` is read-only, read from them | `res = building.low_frequency_intensity_reduction(...)` |
| `reverberation_index` / `estimate_reverberation_index` | `function` | **Survey reverberation index k (ISO 10052:2021 Clause 3.3 / Table 4).**<br>• `reverberation_index(t)`: k = 10 lg(T/0.5) per band<br>• `estimate_reverberation_index(volume, room)`: k from Table 4 (`room`: `kitchen`/`bathroom`/`furnished`/`a`-`h`/`a+e`...); `weighted=True` for the A/C column | `k = building.reverberation_index(t)`<br><br>• k per band [dB] |
| `survey_airborne_insulation` | `function` | **Survey airborne insulation (ISO 10052:2021 Clauses 3.2-3.6).**<br>• `l1`/`l2`: source/receiving levels [dB]<br>• `reverberation_index`: k per band [dB]<br>• `volume` (for Dn/R'), `area` (R', V/7.5 rule) | `res = building.survey_airborne_insulation(l1, l2, k, volume=50, area=12)`<br><br>• `SurveyAirborneResult` (`d`, `d_nt`, `d_n`, `r_prime`, `rating`, `r_prime_rating`) |
| `survey_impact_insulation` / `survey_facade_insulation` | `function` | **Survey impact & façade insulation (ISO 10052:2021 Clauses 3.7-3.9 / 3.13-3.15).**<br>• `li` (impact) or `l1_2m`/`l2` (façade), `reverberation_index`, `volume` | `imp = building.survey_impact_insulation(li, k, volume=50)`<br><br>• `SurveyImpactResult` / `SurveyFacadeResult` |
| `survey_service_equipment_level` | `function` | **Service-equipment noise LXY (ISO 10052:2021 Clauses 3.16-3.18).**<br>• `measurements`: three A/C-weighted positions [dB]<br>• `reverberation_index`: k (scalar or per band)<br>• `volume` (for LXY,n) | `se = building.survey_service_equipment_level([35, 30, 32], 3.0, volume=50)`<br><br>• `SurveyServiceEquipmentResult` (`l_xy`, `l_xy_nt`, `l_xy_n`) |
| `SurveyAirborneResult` / `SurveyImpactResult` / `SurveyFacadeResult` / `SurveyServiceEquipmentResult` | `dataclass` | **ISO 10052 survey-method results.**<br>• per-band quantities (`d`, `d_nt`, `d_n`, `r_prime`; `l_i`, `l_nt`, `l_n`; `d_2m`...; `l_xy`...)<br>• weighted `rating` where the method defines one | `res = building.survey_airborne_insulation(...)` |
| `service_equipment_level` / `ServiceEquipmentResult` | `function` / `dataclass` | **Service-equipment sound pressure level, engineering method (ISO/DIS 16032:2023, the draft of the second edition).**<br>• `levels_db`: band levels of every reading, `(readings, bands)` [dB]; `frequencies_hz` [Hz]<br>• `quantity`: 'Smax' / 'Fmax' / 'eq' (Table 1)<br>• `background_db` (Clause 9), `reverberation_time_s` and `volume_m3` (Formulae (5) and (6), 50-5000 Hz only), `reference_reverberation_time_s` (0.5 s)<br>• `band`: 'third' / 'octave'; `a_weighting_range`: 'restricted' (50-5000 Hz) / 'extended' (25-10 000 Hz)<br>• `.plot()`<br>• `standardizable` is read-only, read from the band centres and `band` (7.7) | `res = building.service_equipment_level(levels, freqs, quantity='eq', reverberation_time_s=t)`<br><br>• `ratings` keyed by Table 1 (`'LA,eq'`, `'LA,eq,nT'`, `'LC,eq'`...), `average_db`, `corrected_db`, `standardized_db`, `normalized_db`, `upper_limit('A')`, `unstandardized_bands_hz`, `reproducibility_db`, `weighted_reproducibility_db` (Table 2: 0.8 dB A, 1.2 dB C) |
| `service_equipment_background_correction` / `ServiceEquipmentBackgroundResult` | `function` / `dataclass` | **Background correction of ISO/DIS 16032:2023 Clause 9.**<br>• `levels_db`, `background_db` [dB], one per band<br>• none at 10 dB or more, Formula (8) from 4 dB, held at 2.2 dB below 4 dB (an upper limit)<br>• `.plot()`<br>• `ServiceEquipmentBackgroundResult` takes `measured_db`, `background_db`, `frequencies_hz`; `difference_db`, `regime`, `correction_db`, `corrected_db` are read-only, read from them | `bg = building.service_equipment_background_correction([50, 48], [38, 45])`<br><br>• `corrected_db`, `correction_db`, `regime`, `limited`, `influenced` |
| `check_position_spread` / `PositionSpreadCheck` | `function` / `dataclass` | **How many positions: the ladder of ISO/DIS 16032:2023 7.4.1.**<br>• `levels_db`: 3, 6 or 9 uncorrected A-weighted readings (corner, 2, 3, then corner, 4, 5 and corner, 6, 7)<br>• spread up to 3.0 dB, under 6.0 dB, under 9.0 dB<br>• `.plot()` | `chk = building.check_position_spread([35.0, 32.1, 36.2])`<br><br>• `levels_db` is its only field; read-only from it: `stage`, `spread_db`, `limit_db`, `passes`, `action` ('proceed' / 'add_positions' / 'interrupt'), `next_positions`, `corner_standard_deviation_db` |
| `check_service_equipment_positions` / `ServiceEquipmentPositionCheck` / `loudest_corner` | `function` / `dataclass` | **Where the microphones go (ISO/DIS 16032:2023 7.2 and 7.3).**<br>• `room_dimensions_m`, `corner_position_m`, `room_positions_m`, `source_positions_m` [m]; `small_room`; `corner_obstacle_distance_m` [m], measured on site<br>• 1.0 m between positions (1.5 m preferred), 1.5 m from sources, 0.50 m (0.30 m) from surfaces, 0.5-2.0 m high; corner 0.5-1.5 m high and at least 0.2 m from any obstacle<br>• `loudest_corner(c_weighted_levels_db, excluded=...)`: position 1<br>• `.plot()`<br>• `ServiceEquipmentPositionCheck` takes `room_dimensions_m`, `corner_position_m`, `room_positions_m`, `source_positions_m`, `small_room`, `corner_obstacle_distance_m`; `separation_m`, `surface_distance_m`, `source_distance_m`, `heights_m`, `corner_height_m`, `corner_wall_distances_m`, ... are read-only, read from them | `pos = building.check_service_equipment_positions((5, 4, 2.6), (0.5, 0.5, 0.5), [(2.5, 2, 1.2), (4, 3.2, 1.5)])`<br><br>• `passes`, `separation_ok`, `surface_ok`, `source_ok`, `height_ok`, `corner_obstacle_ok` |
| `additional_microphone_position` | `function` | **The extra position for a source in the room (ISO/DIS 16032:2023 7.9).**<br>• `room_dimensions_m`, `source_position_m` [m]<br>• `mounting`: 'wall' (1 m in front of the source, 1.5 m high) / 'ceiling' (1.5 m high, directly below)<br>• the reading there is reported separately, never standardized, never averaged with positions 1, 2 and 3 | `p = building.additional_microphone_position((4.2, 3.4, 2.5), (0.6, 3.0, 2.5), mounting='ceiling')`<br><br>• `(x, y, z)` [m] |
| `verify_calibration_deviation` / `CalibrationDeviationResult` | `function` / `dataclass` | **May the instrumentation be used, by its calibrations (ISO/DIS 16032:2023 Clause 5).**<br>• `calibration_levels_db`: this measurement's calibrator readings, beginning and end [dB]<br>• `previous_levels_db`: earlier calibrations of the instrumentation [dB]<br>• each reading held to every calibration before it; more than 0.5 dB takes the equipment out of use<br>• `.plot()` | `cal = building.verify_calibration_deviation([94.0, 94.2], previous_levels_db=[93.9])`<br><br>• `passes`, `deviations_db`, `largest_deviation_db`, `limit_db` |
| `check_background_duration` / `BackgroundDurationCheck` | `function` / `dataclass` | **The background measured over approximately 30 s (ISO/DIS 16032:2023 7.6).**<br>• `durations_s`: the measurement time of each background equivalent level [s]<br>• `tolerance_s` (required): the departure from 30 s, either way, accepted as approximate [s]; the draft prints none<br>• every departure reported<br>• `.plot()` | `dur = building.check_background_duration([30.0, 28.0], tolerance_s=2.0)`<br><br>• `passes`, `departures_s`, `largest_departure_s`, `within_tolerance` |
| `check_varying_background` / `VaryingBackgroundCheck` | `function` / `dataclass` | **A result that stands without correction for a varying background (NOTE to ISO/DIS 16032:2023 Clause 9).**<br>• `background_maximum_db`: background maximum at the corner, per band [dB]; `equipment_levels_db` [dB]<br>• `observation_time_s`: 10 min to 15 min [s]; `frequencies_hz` [Hz], for the plot<br>• 10 dB or more below in every band<br>• `.plot()` | `var = building.check_varying_background([30.0], [45.0], observation_time_s=720.0)`<br><br>• `passes`, `margin_db`, `margin_ok`, `observation_ok` |
| `check_measurement_disturbance` / `MeasurementDisturbanceCheck` | `function` / `dataclass` | **Disturbed measurement periods (ISO/DIS 16032:2023 Clause 9).**<br>• `maximum_levels_db`, `equivalent_levels_db`: a mid-range band, one per period [dB]<br>• maximum less than 5 dB above the equivalent level<br>• `.plot()` | `per = building.check_measurement_disturbance([44.0, 48.9], [40.3, 41.1])`<br><br>• `passes`, `differences_db`, `undisturbed`, `disturbed_periods` |
| `check_instrument_agreement` / `InstrumentAgreementCheck` | `function` / `dataclass` | **The calculation against the instrument (NOTE to ISO/DIS 16032:2023 7.8).**<br>• `result`: a `ServiceEquipmentResult`<br>• `instrument_levels_db`: the instrument's value per single number, keyed `'LA,eq'`, `'LC,eq'`... [dB]; several readings are energy-averaged<br>• more than 2 dB apart: the calculation is checked<br>• `.plot()` | `agr = building.check_instrument_agreement(res, {'LA,eq': 45.6})`<br><br>• `passes`, `differences_db`, `disagreeing`, `calculated_db`, `instrument_db` |
| `SERVICE_EQUIPMENT_WEIGHTING` / `SERVICE_EQUIPMENT_REPRODUCIBILITY` / `SERVICE_EQUIPMENT_WEIGHTED_REPRODUCIBILITY` | `mapping` | **Annex A and Clause 10 of ISO/DIS 16032:2023.**<br>• Table A.1 A- and C-weighting [dB] by band width and centre; the one-third-octave C cells the draft misprints (25 Hz, 1600-10 000 Hz) are IEC 61672-1<br>• Table 2 reproducibility standard deviation [dB] per band, and 0.8 dB (A) / 1.2 dB (C) | `building.SERVICE_EQUIPMENT_WEIGHTING['third']['C'][4000.0]  # -0.8` |
| `SERVICE_EQUIPMENT_OPERATING_CONDITIONS` / `OperatingCondition` | `mapping` / `dataclass` | **Operating conditions and cycles of ISO/DIS 16032:2023 Annex B.**<br>• taps, showers, baths, water closets, ventilation, heating, cooling, lifts, rubbish chutes, auxiliary equipment, car park doors, other equipment and the activities of B.10 (`'unknown_source'`)<br>• `clause`, `maximum_level`, `equivalent_level`, `nominal_integration_time_s` (30 s or a cycle), `parameters` | `building.SERVICE_EQUIPMENT_OPERATING_CONDITIONS['lift'].parameters['repetitions_min']  # 3.0` |
| `background_correction` | `function` | **Background-noise correction (ISO 10140-4 §4.3).**<br>• `signal_and_background`: Combined Lsb per band [dB]<br>• `background`: Lb per band [dB]<br>• 6–15 dB margin corrected, ≤6 dB capped at 1.3 dB, ≥15 dB unchanged | `L = building.background_correction(lsb, lb)`<br><br>• Corrected levels [dB] (`LabInsulationWarning` at the limit of measurement) |
| `LabAirborneInsulationResult` | `dataclass` | **Laboratory airborne result.**<br>• `r`: Sound reduction index R [dB]<br>• `absorption`: A = 0.16 V/T [m²]<br>• `rating`: `WeightedRatingResult` or None<br>• `.plot()` (needs the rating)<br>• `.report(path, ...)`: ISO 10140-2 laboratory test report with the ISO 717-1 rating → PDF (also needs the rating; 16 one-third-octave or 5 octave bands) | `lab.r, lab.rating.rating` |
| `LabImpactInsulationResult` | `dataclass` | **Laboratory impact result.**<br>• `l_n`: Normalized impact level Ln [dB]<br>• `absorption`: A [m²]<br>• `rating`: `ImpactRatingResult` or None<br>• `.plot()` (needs the rating)<br>• `.report(path, ...)`: ISO 10140-3 laboratory test report with the ISO 717-2 rating → PDF (also needs the rating; 16 one-third-octave or 5 octave bands) | `imp.l_n, imp.rating.rating` |
| `LabInsulationWarning` | `warning class` | **Limit-of-measurement condition (ISO 10140-4).**<br>Emitted by `background_correction` when a band's signal-to-background margin is ≤ 6 dB (fixed 1.3 dB cap applied) | `warnings.simplefilter('error', LabInsulationWarning)` |
| `predicted_airborne_insulation` | `function` | **Predicted apparent airborne R'w (EN 12354-1 Formula 26).**<br>• `r_direct`: Separating-element Rs,w [dB]<br>• `flanking_paths`: sequence of `FlankingPath` (Default: ())<br>• `delta_r_direct`: Lining ΔRDd,w [dB] (Default: 0) | `res = building.predicted_airborne_insulation(r_direct=57, flanking_paths=paths)`<br><br>• `AirbornePredictionResult` |
| `predicted_impact_insulation` | `function` | **Predicted apparent impact L'n,w (EN 12354-2 Formula 21).**<br>• `ln_w_eq`: Bare-floor equivalent Ln,w,eq [dB]<br>• `delta_l_w`: Covering improvement ΔLw [dB] (Default: 0)<br>• `k_correction`: Flanking K [dB] (Default: 0) | `imp = building.predicted_impact_insulation(ln_w_eq=76.2, delta_l_w=33, k_correction=2)`<br><br>• `ImpactPredictionResult` |
| `junction_vibration_reduction` | `function` | **Vibration reduction index Kij (EN 12354-1 Annex E.3-E.9).**<br>• `junction_type`: 'rigid_cross'/'rigid_t'/'flexible_t'/'lightweight_facade'/'lightweight_double_homogeneous'/'lightweight_double_coupled'/'corner'/'thickness_change'<br>• `path`: 'through' (K13) / 'corner' (K12=K23) / 'double_leaf' (K24)<br>• `mass_ratio`: m'⊥,i/m'i<br>• `frequency` [Hz] (Default: 500), `f1` [Hz] (Default: 125) | `k = building.junction_vibration_reduction('rigid_cross', 'through', 1.61)`<br><br>• Kij [dB] |
| `junction_min_vibration_reduction` | `function` | **Minimum Kij,min (EN 12354-1 Formula 29).**<br>• `coupling_length`: lf [m]<br>• `s_i`, `s_j`: Element areas [m²] | `kmin = building.junction_min_vibration_reduction(4.5, 11.5, 11.5)`<br><br>• Kij,min [dB] |
| `flanking_path` | `function` | **One flanking path Rij,w (EN 12354-1 Formula 28a).**<br>• `label`, `kind`: 'Ff'/'Df'/'Fd'<br>• `r_source`/`r_receive`: element indices [dB]<br>• `k_ij` [dB], `separating_area` Ss [m²], `coupling_length` lf [m]<br>• `delta_r` [dB] (Default: 0), `kij_min` [dB] clamp (Default: None) | `p = building.flanking_path(label='f', kind='Ff', r_source=49, r_receive=49, k_ij=12.4, separating_area=11.5, coupling_length=4.5)`<br><br>• `FlankingPath` |
| `flanking_element` | `function` | **The three paths (Ff, Df, Fd) of one flanking element.**<br>• `label`, `r_flanking`, `r_separating` [dB]<br>• `k_ff`/`k_fd`/`k_df` [dB]<br>• `separating_area` Ss [m²], `coupling_length` lf [m]<br>• `delta_r_ff`/`delta_r_fd`/`delta_r_df` [dB] (Default: 0)<br>• `flanking_area` SF [m²] (Default: None): enables the automatic Kij,min clamp (Clause 4.4.2 / Formula 29) | `ff, df, fd = building.flanking_element(label='floor', r_flanking=49, r_separating=57, k_ff=12.4, k_fd=8.9, k_df=8.9, separating_area=11.5, coupling_length=4.5)` |
| `combine_linings` | `function` | **Combine two lining improvements (EN 12354-1 Formulas 30/31).**<br>• `delta_a`, `delta_b` [dB] (pass 0 for a single lining) | `dr = building.combine_linings(14.0, 14.0)`<br><br>• max(a,b) + min(a,b)/2 = 21.0 [dB] |
| `equivalent_impact_level` | `function` | **Bare-floor equivalent Ln,w,eq (EN 12354-2 Annex B).**<br>• `mass_per_area`: m' [kg/m²] | `lneq = building.equivalent_impact_level(322.0)`<br><br>• 164 − 35 lg(m') = 76.2 [dB] |
| `impact_flanking_correction` | `function` | **Flanking correction K (EN 12354-2 Table 1).**<br>• `separating_mass`, `flanking_mass` [kg/m²] (nearest tabulated) | `k = building.impact_flanking_correction(322.0, 145.0)`<br><br>• K = 2 [dB], int |
| `standardized_impact_level` | `function` | **Standardized L'nT,w (EN 12354-2 Formula 3, exact 0.032·V form).**<br>• `l_prime_n_w`: L'n,w [dB]<br>• `volume`: Receiving V [m³] (Annex E.3's V/30 is the standard's own rounding) | `lnt = building.standardized_impact_level(45.2, 50.0)`<br><br>• L'nT,w = 43.2 [dB] |
| `standardized_level_difference` | `function` | **DnT,w from R'w (EN 12354-1 Formula 5b, exact 0.32·V/Ss form).**<br>• `r_prime_w`: R'w [dB]<br>• `volume` V [m³], `separating_area` Ss [m²] | `dnt = building.standardized_level_difference(52.2, 50.0, 11.5)`<br><br>• DnT,w = 53.6 → 54 [dB] |
| `facade_sound_reduction` | `function` | **Predicted façade insulation D2m,nT (EN 12354-3 Formula 10/13).**<br>• `elements`: sequence of `FacadeElement`<br>• `area`: Façade S [m²], `volume`: Receiving V [m³]<br>• `delta_l_fs`: ΔLfs [dB] (Default: 0), `bands`<br>• `frequencies`: band centres [Hz] (Default: None; length must equal the band count), carried on the result for plotting | `fac = building.facade_sound_reduction(elements, area=11.3, volume=50.0, bands="octave")`<br><br>• `FacadePredictionResult` |
| `plot_facade_elements` | `function` | **Composite façade elevation, element areas to scale.**<br>• `elements`: `FacadeElement` sequence<br>• `language` | `plot_facade_elements(elements)`<br><br>• Also `FacadePredictionResult.plot_geometry()` |
| `FacadePredictionResult` | `dataclass` | **Predicted façade airborne insulation (EN 12354-3:2000).**<br>• `r_prime`, `r_45`, `r_tr_s`, `d_2m_nt` per band<br>• `r_tr_s_w`, `d_2m_nt_w`, `c_tr` single numbers | `res = building.facade_sound_reduction(...)` |
| `radiated_sound_power` | `function` | **Radiated sound power LW (EN 12354-4 Formula 2/3).**<br>• `elements`, `lp_in`: Inside Lp,in [dB]<br>• `area`: Segment S [m²]<br>• `c_d`: Cd [dB] (Default: -6), `r_prime_cap`: optional R' cap [dB] (Default: None; the Annex G example footnote uses 40), `octave_bands` | `seg = building.radiated_sound_power(elements, lp_in=lp, area=200.0, c_d=-5.0)`<br><br>• `RadiatedPowerResult` |
| `RadiatedPowerResult` | `dataclass` | **Sound power radiated outside by a façade segment (EN 12354-4).**<br>• `l_w`, `r_prime` per band<br>• `l_w_dba`: A-weighted total | `res = building.radiated_sound_power(...)` |
| `outdoor_attenuation` | `function` | **Finite radiating-side attenuation A'tot (EN 12354-4 Annex E).**<br>• `width`, `height`: Side dimensions [m]<br>• `distance`: Perpendicular d [m] | `a = building.outdoor_attenuation(60.0, 10.0, 5.0)`<br><br>• A'tot = 26.3 [dB] |
| `outdoor_level` | `function` | **Exterior level Lp (EN 12354-4 Formula E.1).**<br>• `l_w`: Radiated LW [dB], scalar or per-side<br>• `attenuation`: A'tot [dB], scalar or per-side | `lp = building.outdoor_level(62.9, 26.3)`<br><br>• Lp = 36.6 [dB] |
| `facade_shape_level_difference` | `function` | **Façade-shape term ΔLfs (EN 12354-3 Annex C, Figure C.2).**<br>• `shape`: 'plane_facade'/'gallery_2'…'gallery_5'/'balcony_6'…'balcony_8'/'terrace_open'/'terrace_closed'<br>• `line_of_sight` h [m] (Default: 0), `absorption` αw (Default: 0.3, interpolated) | `dlfs = building.facade_shape_level_difference('balcony_6', line_of_sight=2.0, absorption=0.6)`<br><br>• ΔLfs = 1 [dB] |
| `FacadeElement` | `dataclass` | **One façade transmission path (EN 12354-3/-4).**<br>• give exactly one of `r`: area element [dB] / `dn_e`: small element [dB] / `insertion_loss`: opening [dB]<br>• `area`: Sᵢ [m²] (for `r` / `insertion_loss`) | `FacadeElement("window", area=4.5, r=[23, 22, 30, 36, 37])` |
| `AirbornePredictionResult` | `dataclass` | **Predicted airborne insulation.**<br>• `r_prime_w`: Apparent R'w [dB]<br>• `r_direct_w`: Direct RDd,w [dB]<br>• `paths`: tuple of `PathContribution`<br>• `dominant`: highest-energy path | `res.r_prime_w, res.dominant.label` |
| `ImpactPredictionResult` | `dataclass` | **Predicted impact insulation.**<br>• `l_prime_n_w`: Apparent L'n,w [dB]<br>• `ln_w_eq`, `delta_l_w`, `k_correction` [dB] | `imp.l_prime_n_w` |
| `FlankingPath` | `dataclass` | **One flanking transmission path.**<br>• `label`, `kind`: 'Ff'/'Df'/'Fd'<br>• `r_ij_w`: Flanking index Rij,w [dB] | `p.r_ij_w` |
| `HomogeneousElement` | `dataclass` | **A Type A homogeneous element of the ISO 12354 detailed model.**<br>• `label`, `area` S [m²], `length1`/`length2` [m]<br>• `mass_per_area` m' [kg/m²], `critical_frequency` fc [Hz]<br>• `internal_loss_factor` ηint (Default: 0.01)<br>• `perimeter_absorption` Σ lk αk [m] (Default: 0)<br>• `density` ρ [kg/m³] / `longitudinal_velocity` cL [m/s] (Default: None; enable the Formula B.10 plateau) | `floor = building.HomogeneousElement('floor', 20.0, 5.0, 4.0, 484.0, 76.8, 0.005, 2.66, 2200.0, 3800.0)` |
| `HomogeneousElement.from_solid` | `classmethod` | **The element a layer of a solid's catalogue row makes.**<br>• `row`: a `solids.SolidMaterial`, published or read from a catalogue file of your own<br>• `thickness_m` t [m]; `internal_loss_factor` ηint, never read from the row, which may hold four<br>• `area_m2` S [m²], `length1_m` / `length2_m` [m], `perimeter_absorption_m` Σ lk αk [m] (Default: 0), `label` (Default: the row's name)<br>• `fluid`: the air whose c0 enters fc (Default: `EN_12354_AIR`, 340 m/s)<br>`m' = ρ t` and `fc = c0²/(1.8 cL t)` (ISO 12354-1:2017, Formula (B.2)), with cL the row's plate speed, the quasi-longitudinal phase velocity of Table B.3; the density and the plate speed are read through `.printed()`, so a range or an empty cell is refused in the page's terms | `floor = building.HomogeneousElement.from_solid(concrete, thickness_m=0.22, internal_loss_factor=0.005, area_m2=20.0, length1_m=5.0, length2_m=4.0)`<br><br>• `floor.critical_frequency  # 76.8…` |
| `in_situ_element` | `function` | **Whole in-situ chain of one element, per band (ISO 12354-1 Clause 4.2.2).**<br>• `element`: `HomogeneousElement`, `frequencies` [Hz]<br>• `bands`: 'third'/'octave', `resonant_only` (Default: False)<br>• `fluid`: `Fluid` (Default: `EN_12354_AIR`, the Annex A speed of sound with the Annex B density) | `el = building.in_situ_element(floor, bands)` (`floor` is a `HomogeneousElement`)<br><br>• `InSituElementResult` |
| `EN_12354_AIR` | `Fluid` | **The air the EN/ISO 12354 detailed model is written around.**<br>340 m/s (Annex A), 1,29 kg/m³ (Annex B)<br>• the `fluid` default of `in_situ_element`, `in_situ_total_loss_factor` and `perimeter_absorption_coefficient`<br>• a `phonometry.fluids.Fluid`: pass a computed one to predict in the air of the building instead of the air of the standard | `building.EN_12354_AIR.speed_of_sound  # 340.0` |
| `InSituElementResult` | `dataclass` | **Per-band in-situ element description.**<br>• `radiation_factor` σ, `forced_radiation_factor` σf<br>• `total_loss_factor` ηtot,situ, `reverberation_time` Ts,situ [s]<br>• `absorption_length` asitu [m]<br>• `sound_reduction_index` Rsitu [dB], `impact_level` Ln,situ [dB]<br>• `.plot()` | `el.sound_reduction_index, el.absorption_length` |
| `bending_radiation_factor` | `function` | **Radiation factor for free bending waves σ (ISO 12354-1 Formulae B.4-B.6).**<br>• `frequencies` [Hz], `critical_frequency` fc [Hz]<br>• `length1`, `length2` [m], `speed_of_sound` [m/s] | `s = building.bending_radiation_factor(f, critical_frequency=76.8, length1=5.0, length2=4.0)`<br><br>• σ ≤ 2 per band |
| `forced_radiation_factor` | `function` | **Radiation factor for forced waves σf (Formula B.3, Table B.1).**<br>• `frequencies` [Hz], `length1`, `length2` [m], `speed_of_sound` | `sf = building.forced_radiation_factor(f, length1=3.75, length2=2.65)`<br><br>• σf ≤ 2 per band |
| `calculated_sound_reduction_index` | `function` | **R of a homogeneous element (Formulae B.2/B.10).**<br>• `frequencies`, `mass_per_area` m', `critical_frequency` fc<br>• `total_loss_factor`, `radiation_factor`, `forced_radiation_factor`<br>• `bands`, `resonant_only` (Default: False)<br>• `density`, `longitudinal_velocity` (Default: None; high-frequency plateau) | `r = building.calculated_sound_reduction_index(f, mass_per_area=484, critical_frequency=76.8, total_loss_factor=eta, radiation_factor=s, forced_radiation_factor=sf)` |
| `bare_floor_impact_level` | `function` | **Ln of a bare monolithic floor (ISO 12354-2 Formula B.2).**<br>• `frequencies`, `mass_per_area` m'<br>• `structural_reverberation_time` Ts [s], `radiation_factor` σ | `ln = building.bare_floor_impact_level(f, mass_per_area=484, structural_reverberation_time=ts, radiation_factor=s)`<br><br>• 155 − 30 lg m' + 10 lg Ts + 10 lg σ + 10 lg(f/fref) |
| `reciprocity_impact_level` | `function` | **Ln from R by reciprocity (ISO 12354-2 Formulae B.3/B.4).**<br>• `sound_reduction_index` [dB], `frequencies` [Hz]<br>• `bands`: 'third' (38) / 'octave' (43) | `ln = building.reciprocity_impact_level(r, f)`<br><br>• R + Ln = 38 + 30 lg f |
| `perimeter_absorption_coefficient` | `function` | **Bending-wave absorption at one border αk (Formula C.4).**<br>• `critical_frequencies` fc,j [Hz] of the connected elements<br>• `vibration_reduction_indices` Kij [dB] | `a = building.perimeter_absorption_coefficient([92.6, 92.6], [6.4, 6.4])`<br><br>• Σ √(fc,j/fref)·10^(−Kij/10) |
| `in_situ_total_loss_factor` | `function` | **ηtot,situ (Formula C.1).**<br>• `frequencies`, `internal_loss_factor` ηint, `mass_per_area`, `area`<br>• `critical_frequency`, `radiation_factor`<br>• `perimeter_absorption` Σ lk αk [m], `fluid` (Default: `EN_12354_AIR`) | `eta = building.in_situ_total_loss_factor(f, internal_loss_factor=0.005, mass_per_area=484, area=20, critical_frequency=76.8, radiation_factor=s, perimeter_absorption=2.66)` |
| `laboratory_total_loss_factor` | `function` | **ηtot,lab ≈ ηint + m'/(485 √f) (Formula C.3).**<br>• `frequencies`, `mass_per_area`, `internal_loss_factor` (Default: 0.01) | `eta = building.laboratory_total_loss_factor(f, mass_per_area=484)` |
| `structural_reverberation_time` | `function` | **Ts = 2,2/(f ηtot) (Formula C.1).**<br>• `frequencies` [Hz], `total_loss_factor` ηtot | `ts = building.structural_reverberation_time(f, eta)`<br><br>• Ts per band [s] |
| `in_situ_reduction_index` / `in_situ_impact_level` | `function` | **Laboratory → in-situ transfer (Formula 9 / Part 2 Formula 5).**<br>• `sound_reduction_index` or `impact_level` [dB]<br>• `situ_reverberation_time`, `laboratory_reverberation_time` [s] | `r = building.in_situ_reduction_index(r_lab, ts_situ, ts_lab)`<br><br>• R − 10 lg(Ts,situ/Ts,lab); Ln + 10 lg(...) |
| `in_situ_equivalent_absorption_length` | `function` | **asitu = 2,2 π² S √(fref/f)/(co Ts,situ) (Formula 11).**<br>• `frequencies`, `area` S [m²], `situ_reverberation_time` [s], `speed_of_sound` | `a = building.in_situ_equivalent_absorption_length(f, area=20.0, situ_reverberation_time=ts)` |
| `in_situ_velocity_level_difference` | `function` | **Dv,ij,situ = Kij − 10 lg(lij/√(ai aj)), ≥ 0 dB (Formula 10).**<br>• `vibration_reduction_index` Kij [dB]<br>• `coupling_length` lij [m], `absorption_length_i`/`absorption_length_j` [m] | `dv = building.in_situ_velocity_level_difference(6.4, coupling_length=4.0, absorption_length_i=ai, absorption_length_j=aj)` |
| `direct_reduction_index` / `direct_impact_level` | `function` | **Direct paths (Formula 14 / Part 2 Formula 11).**<br>• `separating_index` Rs,situ or `floor_level` Ln,situ [dB]<br>• `delta_r_source`/`delta_r_receiving`, or `delta_l`/`delta_l_ceiling` [dB] | `rdd = building.direct_reduction_index(r_situ, delta_r_source=dl)`<br><br>• RDd; Ln,d |
| `flanking_reduction_index` | `function` | **Flanking Rij per band, Type A (Formula 15).**<br>• `index_i`, `index_j` [dB], `velocity_level_difference` Dv,ij,situ [dB]<br>• `separating_area` Ss, `area_i` Si, `area_j` Sj [m²]<br>• `delta_r_i`, `delta_r_j` [dB] | `rij = building.flanking_reduction_index(index_i=ri, index_j=rj, velocity_level_difference=dv, separating_area=20.0, area_i=20.0, area_j=11.0)` |
| `flanking_impact_level` | `function` | **Flanking Ln,ij per band, Type A (ISO 12354-2 Formula 12).**<br>• `floor_level` Ln,situ, `index_i`, `index_j`, `velocity_level_difference`<br>• `area_i`, `area_j` [m²], `delta_l`, `delta_r_j` [dB] | `lnij = building.flanking_impact_level(floor_level=ln, index_i=ri, index_j=rj, velocity_level_difference=dv, area_i=20.0, area_j=11.0)` |
| `flanking_reduction_index_from_normalized_difference` / `flanking_impact_level_from_normalized_difference` | `function` | **Type B flanking paths from Dv,ij,n (Formula 17 / Part 2 Formula 14).**<br>• element indices [dB], `normalized_velocity_level_difference` [dB]<br>• `separating_area` (airborne) or `area_i` (impact) [m²], `coupling_length` lij [m] | `rij = building.flanking_reduction_index_from_normalized_difference(index_i=ri, index_j=rj, normalized_velocity_level_difference=dvn, separating_area=20.0, coupling_length=4.0)` |
| `flanking_reduction_index_from_flanking_level` | `function` | **Rij from a measured Dn,f (Formula 16).**<br>• `flanking_level_difference` Dn,f [dB]<br>• `separating_area` Ss [m²], `coupling_length` lij [m]<br>• `laboratory_coupling_length` llab [m] (4.5 ceilings, 2.5 façades)<br>• `reference_absorption_area` A0 [m²] (Default: 10) | `rij = building.flanking_reduction_index_from_flanking_level(dnf, separating_area=10.44, coupling_length=2.41, laboratory_coupling_length=2.5)` |
| `flanking_impact_level_from_flanking_level` | `function` | **Ln,ij from a measured Ln,f (ISO 12354-2 Formula 13).**<br>• `normalized_flanking_impact_level` Ln,f,ij,situ [dB]<br>• `area` Si, `laboratory_area` Si,lab [m²]<br>• `coupling_length` lij, `laboratory_coupling_length` llab [m] | `lnij = building.flanking_impact_level_from_flanking_level(lnf, area=20.0, laboratory_area=10.0, coupling_length=4.0, laboratory_coupling_length=4.5)` |
| `resonant_sound_reduction_index` | `function` | **R* for resonant transmission only (Formula B.1/B.2).**<br>• `sound_reduction_index` [dB], `frequencies` [Hz]<br>• `critical_frequency` fc [Hz], `correction` [dB] (Default: 8, applied below fc) | `rstar = building.resonant_sound_reduction_index(r, f, critical_frequency=2200.0)` |
| `floating_floor_improvement` | `function` | **ΔL of a floating floor (ISO 12354-2 Formulae C.1/C.3).**<br>• `frequencies` [Hz], `resonance_frequency` fo = 160 √(s'/m') [Hz]<br>• `slope`: 30 (screed) or 40 (asphalt/dry) | `dl = building.floating_floor_improvement(f, resonance_frequency=52.8)`<br><br>• 30 lg(f/fo), 0 at and below fo |
| `hammer_impact_velocity` | `function` | **ISO tapping-machine impact velocity vo = √(2 g h) (Hopkins Eq. 3.85).**<br>• `drop_height` h [m] (Default: 0.04), `gravity` g [m/s²] | `hammer_impact_velocity()`<br><br>• 0.886 [m/s] |
| `plate_contact_stiffness` | `function` | **Hammer contact stiffness of a plate material K = 2 r E/(1 − ν²) (Hopkins Eq. 3.97).**<br>• `youngs_modulus` E [Pa]<br>• `poisson_ratio` ν (Default: 0.2), `radius` r [m] (Default: 0.015) | `k = building.plate_contact_stiffness(3.05e10)`<br><br>• K [N/m] |
| `covering_contact_stiffness` | `function` | **Hammer contact stiffness of a soft covering K = E π r²/d (Hopkins Eq. 3.98).**<br>• `youngs_modulus` E [Pa], `thickness` d [m]<br>• `radius` r [m] (Default: 0.015) | `k = building.covering_contact_stiffness(1.4e6, 0.005)`<br><br>• K [N/m] |
| `tapping_cut_off_frequency` | `function` | **Force-spectrum cut-off fco (Hopkins Eqs. 3.101/3.102).**<br>• `contact_stiffness` K [N/m], `impedance` Zdp [N.s/m]<br>• `mass` m [kg] (Default: 0.5) | `fco = building.tapping_cut_off_frequency(k, z)`<br><br>• fco [Hz], under- or over-critical branch |
| `hammer_limiting_frequency` | `function` | **flimit = Zdp/(2 π m), above which the hammer mass limits the power input (Hopkins Eq. 3.106).**<br>• `impedance` Zdp [N.s/m], `mass` m [kg] | `hammer_limiting_frequency(1637.0)`<br><br>• 521 [Hz] |
| `force_pulse` | `function` | **Single-impact force pulse F1(t) (Hopkins Eqs. 3.95/3.96).**<br>• `time` t [s], `contact_stiffness` K [N/m], `impedance` Zdp [N.s/m]<br>• `mass` m [kg], `impact_velocity` vo [m/s] | `f = building.force_pulse(t, k, z)`<br><br>• F1(t) [N] |
| `short_pulse_mean_square_force` | `function` | **F²rms = 3.9 B for a short impact (Hopkins Eq. 3.92).**<br>• `frequencies` [Hz], `band`: 'third'/'octave' | `short_pulse_mean_square_force(500.0)` |
| `tapping_force_spectrum` | `function` | **Force spectrum of the ISO tapping machine (Hopkins 3.6.3.1).**<br>• `frequencies` [Hz], `contact_stiffness` K [N/m], `impedance` Zdp [N.s/m]<br>• `mass`, `impact_rate` fi, `impact_velocity` vo, `band` | `res = building.tapping_force_spectrum(f, k, z)`<br><br>• `TappingForceResult` |
| `TappingForceResult` | `dataclass` | **Tapping-machine force spectrum on one walking surface.**<br>• `peak_force` \|Fn\| [N], `mean_square_force` [N²], `power_input` [W], `power_input_level` [dB]<br>• `cut_off_frequency`, `limiting_frequency` [Hz], `lower_limit`/`upper_limit` [N]<br>• `.plot()`<br>• takes the spectra, `contact_stiffness`, `impedance`, `band` and `mass_kg` (Default: 0.5); `over_critical` (K m ≥ 4 Zdp², Hopkins Eq. 3.95) is read-only, read from them, and the frequencies, the spectrum and the power input are held to that regime | `res.cut_off_frequency, res.over_critical` |
| `covering_improvement` | `function` | **Predicted ΔL of a soft floor covering, ΔL = 20 lg(\|Fn\|without/\|Fn\|with) (Hopkins Eq. 4.114).**<br>• `frequencies` [Hz], `covering_stiffness`, `plate_stiffness` [N/m], `impedance` [N.s/m] | `res = building.covering_improvement(f, kc, kp, z)`<br><br>• `CoveringImprovementResult` |
| `CoveringImprovementResult` | `dataclass` | **Soft-covering improvement prediction.**<br>• `improvement` ΔL [dB], `two_line` (0 dB below fco, 12 dB/oct above)<br>• `cut_off_frequency`, `bare_cut_off_frequency` [Hz], `bare`/`covered` force spectra<br>• `.plot()` | `res.improvement, res.two_line` |
| `floating_floor_resonance_frequency` | `function` | **fo = 160 √(s'/m') of a floating floor (ISO 12354-2 Formula C.2).**<br>• `dynamic_stiffness` s' [N/m³], `mass_per_area` m' [kg/m²] | `floating_floor_resonance_frequency(8e6, 73.5)`<br><br>• 52.8 [Hz] |
| `combined_dynamic_stiffness` | `function` | **s'tot = (Σ 1/s'i)⁻¹ for stacked resilient layers (ISO 12354-2 Formula C.6).**<br>• `layers`: s'i [N/m³] | `combined_dynamic_stiffness([8e6, 8e6])`<br><br>• 4e6 [N/m³] |
| `double_floating_floor_resonances` | `function` | **The two resonances of a double floating floor (Hopkins Eq. 4.125).**<br>• `lower_stiffness`, `lower_mass_per_area`, `upper_stiffness`, `upper_mass_per_area` | `double_floating_floor_resonances(7.25e6, 12.78, 7.25e6, 12.78)`<br><br>• (74, 194) [Hz] |
| `weighted_floating_floor_improvement` | `function` | **ΔLw of a floating floor (ISO 12354-2 Formulae C.4/C.5).**<br>• `mass_per_area` m' [kg/m²], `dynamic_stiffness` s' [N/m³]<br>• `floor`: 'screed' (C.4) or 'asphalt' (C.5) | `weighted_floating_floor_improvement(73.5, 8e6)`<br><br>• 32.2 [dB] |
| `floating_floor_improvement_spectrum` | `function` | **ΔL(f) of a floating floor above fo.**<br>• `frequencies` [Hz], `resonance_frequency` fo [Hz]<br>• `model`: 'en12354' (30 lg), 'cremer' (40 lg) or 'cremer_hammer' (+10 lg[1 + (f/flimit)²])<br>• `limiting_frequency`, `mass_per_area`, `dynamic_stiffness` | `res = building.floating_floor_improvement_spectrum(f, resonance_frequency=52.8)`<br><br>• `FloatingFloorImprovementResult` |
| `FloatingFloorImprovementResult` | `dataclass` | **Floating-floor improvement prediction.**<br>• `improvement` ΔL [dB], `resonance_frequency` [Hz], `model`, `slope` [dB/decade]<br>• `limiting_frequency` [Hz] or None, `delta_lw` [dB] or None<br>• `.plot()` | `res.improvement, res.delta_lw` |
| `resilient_mount_improvement` | `function` | **ΔL of a floating floor on discrete mounts, 30 dB/decade (Vér; Hopkins Eq. 4.118, Vigran Eq. 8.45).**<br>• `frequencies` [Hz], `impedance` Zdp1 [N.s/m], `mass_per_area` ρs1 [kg/m²]<br>• `loss_factor` η1, `mount_stiffness` k [N/m], `mount_density` N' [1/m²] | `dl = building.resilient_mount_improvement(f, impedance=3.8e5, mass_per_area=115.0, loss_factor=0.02, mount_stiffness=2e6, mount_density=4.0)` |
| `lining_resonance_frequency` | `function` | **fo of a lining on a basic element (ISO 12354-1 Formulae D.1/D.2).**<br>• `base_mass_per_area` m'1, `lining_mass_per_area` m'2 [kg/m²]<br>• exactly one of `dynamic_stiffness` s' [N/m³] (D.1) or `cavity_depth` d [m] (D.2) | `lining_resonance_frequency(51.0, 6.3, dynamic_stiffness=65e6)`<br><br>• 542 [Hz] |
| `weighted_lining_improvement` | `function` | **ΔRw of an interior lining (ISO 12354-1 Table D.1).**<br>• `resonance_frequency` fo [Hz] (30-5000, rounded to the third-octave centre)<br>• `base_rating` Rw [dB] | `weighted_lining_improvement(100.0, 40.0)`<br><br>• 14.4 [dB] |
| `lining_improvement` | `function` | **Single-number ratings of an additional layer (ISO 12354-1 Formulae D.3-D.7).**<br>• `resonance_frequency` fo [Hz]<br>• `system`: 'mineral_wool' (D.3), 'foam' (D.4) or 'studs' (D.7)<br>• `anchors` (D.5), `glued_area` %So (D.6) | `res = building.lining_improvement(100.0)`<br><br>• `LiningImprovementResult` |
| `LiningImprovementResult` | `dataclass` | **Annex D single-number ratings of an additional layer.**<br>• `delta_rw`, `delta_ra`, `delta_ratr` [dB], `.ratings` tuple<br>• `resonance_frequency` [Hz], `system`, `anchors`, `glued_area`<br>• `.plot()` | `res.delta_rw, res.ratings` |
| `lining_improvement_in_situ` | `function` | **Laboratory → field transfer of a lining rating (ISO 12354-1 Formula D.8).**<br>• `laboratory_improvement` ΔRlab [dB], `resonance_frequency` fo [Hz], `base_rating_in_situ` Rw,situ [dB] | `lining_improvement_in_situ(10.0, 100.0, 60.0)` |
| `TAPPING_HAMMER_MASS` / `TAPPING_DROP_HEIGHT` / `TAPPING_IMPACT_RATE` / `TAPPING_HAMMER_RADIUS` | `constant` | **ISO tapping-machine constants**: hammer mass 0.5 kg, drop height 0.04 m, impact rate 10 Hz, assumed contact radius 0.015 m. | `TAPPING_HAMMER_MASS  # 0.5` |
| `airborne_flanking_path` / `impact_flanking_path` | `function` | **Build one flanking path from two in-situ elements.**<br>• `label`, `kind` ('Ff'/'Df'/'Fd', airborne only)<br>• `element_i`/`element_j` (or `floor`/`element_j`): `InSituElementResult`<br>• `vibration_reduction_index` Kij [dB], `coupling_length` lij [m]<br>• `separating_area` Ss [m²] (airborne), `delta_r_*` / `delta_l` [dB] | `p = building.airborne_flanking_path(label='D1', kind='Df', element_i=el, element_j=wall, vibration_reduction_index=6.4, coupling_length=4.0, separating_area=20.0)` (`el`, `wall` are `InSituElementResult`)<br><br>• `BandPath` |
| `BandPath` | `dataclass` | **One per-band transmission path of the detailed model.**<br>• `label`, `kind`: 'Dd'/'Ff'/'Df'/'Fd'<br>• `values`: Rij or Ln,ij per band [dB] | `p.values` |
| `detailed_airborne_prediction` / `detailed_impact_prediction` | `function` | **Combine the paths into R' / L'n per band (ISO 12354-1 Formulae 1-4 / -2 Formula 1).**<br>• `frequencies` [Hz]<br>• `direct_index` RDd or `direct_level` Ln,d [dB]<br>• `flanking_paths`: sequence of `BandPath`, `direct_label`, `bands` | `res = building.detailed_airborne_prediction(f, direct_index=rdd, flanking_paths=paths)` (`rdd` from `direct_reduction_index`, `paths` of `BandPath`)<br><br>• `DetailedAirborneResult` / `DetailedImpactResult` |
| `DetailedAirborneResult` / `DetailedImpactResult` | `dataclass` | **Per-band detailed prediction (ISO 12354-1/-2:2017 Clause 4.2).**<br>• `r_prime` or `l_prime_n` per band [dB]<br>• `paths`: tuple of `BandPath` (direct first), `fractions`: energy share per path and band<br>• `dominant`: the leading path in each band<br>• `rating`: `WeightedRatingResult` / `ImpactRatingResult` or None<br>• `.plot()`: per-band path-contribution bars<br>• `.report(path, ...)`: one-page EN/ISO 12354 detailed prediction fiche → PDF | `res.r_prime, res.dominant, res.rating.rating` |
| `PathContribution` | `dataclass` | **A path with its energy share.**<br>• `label`, `kind`: 'Dd'/'Ff'/'Df'/'Fd'<br>• `r_w`: Path index [dB]<br>• `fraction`: share of transmitted energy (0–1) | `c.r_w, c.fraction` |
| `vibration_reduction_index` | `function` | **Measured vibration reduction index Kij (ISO 10848 Formula 13/14).**<br>• `velocity_level_difference`: direction-averaged D̄v,ij [dB]<br>• `junction_length` lij [m], `area_i`/`area_j` [m²]<br>• `frequencies` [Hz], `structural_reverberation_time_i`/`_j` [s] (both → Formula 13; else simplified 14)<br>• `speed_of_sound` (Default: 343)<br>• `modal_overlap`: per-band M; M < 0.25 bands bracketed and excluded from K̄ij (ISO 10848-4 Clause 9) | `res = building.vibration_reduction_index(dbar, 4.0, 12.0, 10.0, frequencies=f, structural_reverberation_time_i=0.35, structural_reverberation_time_j=0.40)`<br><br>• `VibrationReductionResult` |
| `direction_averaged_level_difference` | `function` | **Direction average D̄v,ij = ½(Dv,ij+Dv,ji) (ISO 10848 Formula 11).**<br>• `dv_ij`, `dv_ji` [dB] | `dbar = building.direction_averaged_level_difference(dv_ij, dv_ji)` |
| `velocity_level_difference` | `function` | **Velocity level difference Dv,ij = Lv,i−Lv,j (ISO 10848 Formula 8).**<br>• `source_level`, `receive_level` [dB] | `dv = building.velocity_level_difference(lv_i, lv_j)` |
| `equivalent_absorption_length` | `function` | **Equivalent absorption length aj (ISO 10848 Formula 12).**<br>• `area` Sj [m²], `structural_reverberation_time` Ts [s], `frequencies` [Hz]<br>• `speed_of_sound` (Default: 343) | `a = building.equivalent_absorption_length(10.0, 0.5, f)` |
| `total_loss_factor` | `function` | **Total loss factor η = 2.2/(f·Ts) (ISO 10848 Clause 7.3.1).**<br>• `frequencies` [Hz], `structural_reverberation_time` [s] | `eta = building.total_loss_factor(f, ts)` |
| `normalized_flanking_level_difference` | `function` | **Airborne Dn,f = L1−L2−10 lg(A/A0) (ISO 10848 Formula 4).**<br>• `source_level` L1, `receive_level` L2 [dB]<br>• `absorption_area` A [m²]<br>• `reference_area` A0 (Default: 10) | `res = building.normalized_flanking_level_difference(l1, l2, a)`<br><br>• `FlankingLevelDifferenceResult` |
| `normalized_flanking_impact_level` | `function` | **Impact Ln,f = L2+10 lg(A/A0) (ISO 10848 Formula 5).**<br>• `receive_level` L2 [dB], `absorption_area` A [m²]<br>• `reference_area` A0 (Default: 10) | `res = building.normalized_flanking_impact_level(l2, a)`<br><br>• `FlankingImpactLevelResult` |
| `vibration_reduction_index_from_flanking` | `function` | **Indirect Kij from Dn,f (ISO 10848 Clause 4.3.1).**<br>• `normalized_flanking_level_difference` Dn,f, `reduction_index_i`/`_j` Ri/Rj [dB]<br>• `junction_length`, `area_i`/`area_j`, `absorption_length_i`/`_j` | `k = building.vibration_reduction_index_from_flanking(dnf, ri, rj, 2.0, 10.0, 12.0, ai, aj)`<br><br>• Kij [dB] |
| `critical_frequency` | `function` | **Thin-plate critical frequency fc = c0²/(1.8·cL·h·π) (ISO 10848 Formula 20).**<br>• `longitudinal_wave_speed` cL [m/s], `thickness` h [m]<br>• `speed_of_sound` (Default: 343) | `fc = building.critical_frequency(5500.0, 0.2)` |
| `strong_coupling_satisfied` | `function` | **Strong-coupling validity check (ISO 10848 Formula 15).**<br>• `velocity_level_difference` D̄v,ij [dB]<br>• `mass_i`/`mass_j` [kg/m²], `critical_frequency_i`/`_j` [Hz] | `ok = building.strong_coupling_satisfied(dbar, 20, 20, 100, 100)`<br><br>• bool per band |
| `modal_density` | `function` | **Modal density n = π·S·fc/c0² (ISO 10848-4 Formula 5).**<br>• `area` S [m²], `critical_frequency` fc [Hz]<br>• `speed_of_sound` (Default: 343) | `n = building.modal_density(10.0, 200.0)` |
| `modal_overlap_factor` | `function` | **Modal overlap M = 2.2·n/Ts (ISO 10848-4 Formula 6).**<br>• `area`, `critical_frequency`, `structural_reverberation_time` [s] | `m = building.modal_overlap_factor(10.0, 200.0, ts)  # feed building.vibration_reduction_index(modal_overlap=m)` |
| `band_mode_count` | `function` | **In-band mode count N = 0.23·f·n (ISO 10848-4 Formula 4).**<br>• `frequencies` [Hz], `area`, `critical_frequency` | `n5 = building.band_mode_count(f, 10.0, 200.0)  # N≥5 OK` |
| `VibrationReductionResult` | `dataclass` | **Measured Kij (ISO 10848).**<br>• `frequencies` [Hz] (or None), `k_ij` [dB]<br>• `single_number`: mean K̄ij 200–1250 Hz (thirds) / 125–1000 Hz (octaves), or None<br>• `bracketed`: M < 0.25 flags (or None)<br>• `.octave_bands()`, `.plot()`<br>• takes `frequencies`, `k_ij`, `modal_overlap`, `band_type` (the band set stated, as `.octave_bands()` states it; `None`, what `vibration_reduction_index` leaves, reads it from the spacing); `bracketed`, `single_number` are read-only, read from them | `res.k_ij, res.single_number` |
| `FlankingLevelDifferenceResult` | `dataclass` | **Normalized flanking level difference Dn,f (ISO 10848).**<br>• `d_n_f` [dB], `rating`: Dn,f,w (or None)<br>• `.plot()` | `res.d_n_f, res.rating` |
| `FlankingImpactLevelResult` | `dataclass` | **Normalized flanking impact level Ln,f (ISO 10848).**<br>• `l_n_f` [dB], `rating`: Ln,f,w (or None)<br>• `.plot()` | `res.l_n_f, res.rating` |
| `PUBLISHED_TRANSMISSION_LOSS` | `mapping` | **Two hundred and fifty-five measured constructions from ten published tables, keyed `'<table>/<row>'`.**<br>• Bies 5e **Table 7.6**, nine groups from sheet panels and sandwich panels through masonry, stud partitions, glazing and doors to floors<br>• ASHRAE Chapter 49 **Table 40**, nine machine equipment room walls, floors and ceilings with the Sound Transmission Class the page prints beside each one<br>• Rossing (2014) **Table 11.4**, twenty-three common partitions in six bands with an STC<br>• Harris 3e **Tables 31.2, 31.3 and 31.5 to 31.9**, a hundred and twenty-nine STC ratings with no band: stud walls, block walls, doors, sealed windows and floor-ceiling systems, one row per condition the page rates, the condition in `variant`<br>• each row carries the `thickness_mm` and the `surface_density_kg_m2` the page prints beside the description, which is what tells apart six windows all called "Single glass in heavy frame"<br>• the book calls the values representative, says they come from tests published by manufacturers and laboratories, and names no standard, no mounting and no source per row; the qualifier it does give is field incidence<br>• what a formula does not give you: the same 280 mm brick wall is 40 dB at 500 Hz on strip ties and 55 dB on expanded metal ties<br>• the transcription was made twice, from the rendered pages, by readers who never saw each other's work | `row = building.PUBLISHED_TRANSMISSION_LOSS['bies-2017-table-7-6/6_mm_steel_plate_6mm']`<br>`row.spectrum()[500]  # 41 dB`<br><br>• `TransmissionLossSpectrum`, `transmission_loss_named` |
| `TransmissionLossSpectrum` | `dataclass` | **One construction of a published table, with its transmission loss in each octave band.**<br>• `transmission_loss_63_db` … `transmission_loss_8000_db`, in decibels, `None` where the page prints a dash<br>• `thickness_mm`, `surface_density_kg_m2`: the two columns Bies prints beside the description; two rows carry no weight and say so<br>• `sound_transmission_class`: the single-number rating a page prints where it prints one, kept because an STC is computed from third octaves and these seven or eight bands do not give it back; seven tables print nothing else<br>• `block_mass_kg`: the mass of one masonry block where a page prints it, which is not a surface density<br>• `refers_to_row`: the row a printed "Igual que 8" inherits from; resolve with `PUBLISHED_TRANSMISSION_LOSS[f'{row.table}/{row.refers_to_row}']`<br>• `.bands()`, `.spectrum()` → `{band_hz: db}`, `.transmission_loss_db(band_hz)` narrows or refuses, naming the row and the band<br>• a measurement of one construction in one laboratory, not a property of a material | `row.transmission_loss_db(63)  # ValueError: the page prints a dash there`<br><br>• `PUBLISHED_TRANSMISSION_LOSS` |
| `SoundReductionSpectrum` | `dataclass` | **One element of a laboratory report, with its sound reduction index R per one-third octave (ISO 10140-2) and the ISO 717-1 single numbers it prints.**<br>• `sound_reduction_index_50_db` … `sound_reduction_index_5000_db`, 21 bands, `None` where the report prints none<br>• `weighted_sound_reduction_index_db` (Rw), `spectrum_adaptation_term_db` (C), `traffic_spectrum_adaptation_term_db` (Ctr) and the six Annex B terms `spectrum_adaptation_term_50_3150_db` … `traffic_spectrum_adaptation_term_100_5000_db`, as printed<br>• `surface_density_kg_m2`, `thickness_mm`, `construction`<br>• `.rating()` → `ExtendedWeightedRatingResult` from every band printed: Rw, C and Ctr from 100-3150 Hz (refused, naming the band, when one is missing) and each Annex B term whose bands are all printed, `None` otherwise<br>• read from a file, a printed number the bands do not give is noted beside the catalogue, never changed<br>• a laboratory's R, not a book's field-incidence loss (`TransmissionLossSpectrum`) | `row.rating().rating  # Rw worked out again`<br>`row.sound_reduction_index_db(500)`<br><br>• `ImpactImprovementSpectrum`, `weighted_rating_extended` |
| `ImpactImprovementSpectrum` | `dataclass` | **One floor covering or floating floor of a report, with its reduction of impact sound pressure level ΔL per one-third octave (ISO 10140-1 Annex H, Equation (H.1), the levels measured by ISO 10140-3) and the ISO 717-2 single numbers it prints.**<br>• `impact_improvement_50_db` … `impact_improvement_5000_db`, 21 bands<br>• `weighted_impact_improvement_db` (ΔLw), `reference_floor_adaptation_term_db` (CI,r), `impact_improvement_adaptation_term_db` (CI,Δ), as printed<br>• `.rating()` → `ImpactImprovementRatingResult` from the 16 bands 100-3150 Hz, refused, naming the band, when one is missing<br>• ΔLw has a field of its own: it is never read from `ImpactInsulation.impact_sound_improvement_db`, an average over frequency<br>• `predicted_impact_insulation(ln_w_eq=..., delta_l_w=row.printed('weighted_impact_improvement_db'))` takes it, or refuses with what the sheet printed | `row.rating().delta_lw`<br>`row.printed('weighted_impact_improvement_db')`<br><br>• `ImpactImprovementRatingResult`, `SoundReductionSpectrum` |
| `TRANSMISSION_LOSS_BANDS_HZ` | `constant` | **The octave bands a published transmission loss table can print: 63 Hz to 8 kHz.**<br>• `(63, 125, 250, 500, 1000, 2000, 4000, 8000)`; Bies fills the six middle bands on every row and leaves the ends empty on about forty | `building.TRANSMISSION_LOSS_BANDS_HZ` |
| `transmission_loss_named` | `function` | **Every construction whose printed description contains a fragment.**<br>• `name`: matched without case against the description the page prints, and nothing else<br>• `'door'` answers with the rows that carry the word, not with Bies's hollow flush panel described without it, nor with the Spanish `'puerta'` of Harris<br>• `catalogue=`: the rows to search instead of `PUBLISHED_TRANSMISSION_LOSS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_TRANSMISSION_LOSS \| mine`; a row of another class is refused by its key (`TypeError`) | `[r.thickness_mm for r in building.transmission_loss_named('Concrete, reinforced')]  # [100, 200, 300]`<br><br>• `PUBLISHED_TRANSMISSION_LOSS` |
| `PUBLISHED_IMPACT_INSULATION` | `mapping` | **Seventy-one rows of measured impact insulation, keyed `'<table>/<row>'`.**<br>• Harris 3e **Tables 32.1 to 32.8**: forty-two floor-ceiling constructions with their IIC, and six elastic surface treatments with the improvement each adds over a hard massive floor<br>• Harris (1977) **Tables 19.2 to 19.4**: twenty-three floor finishes, floating screeds and timber floors on bare concrete, with the average improvement in impact sound insulation in decibels, keyed by a slug of the description<br>• Tables 32.1 to 32.7 are keyed by the row number the page prints in its own column, `'1'` to `'38'`, with a lettered pair such as `'34A'`/`'34B'` where a construction is printed as two rows, each with its own description and rating; the six treatments of Table 32.8 and every 1977 row are keyed by a slug of the description<br>• single numbers and nothing per band: these pages print no impact sound pressure level, no octave, no third octave and no reference curve<br>• Chapter 32 is collected measurements from a 1967 report for the Federal Housing Administration, except Table 32.8, which credits a 1963 paper by Zeller; the 1977 tables credit nothing; no laboratory, no test standard and no uncertainty is named for any row<br>• what a formula does not give you: the same reinforced concrete slab is IIC 25 bare and 80 under a wool carpet on a rubber underlay | `row = building.PUBLISHED_IMPACT_INSULATION['harris-1995-tables-32-1-to-32-8/4']`<br>`row.impact_insulation_class  # 80`<br><br>• `ImpactInsulation`, `impact_insulation_named` |
| `ImpactInsulation` | `dataclass` | **One floor-ceiling construction, or one surface treatment, as its page prints it.**<br>• `impact_insulation_class`: the IIC of a whole assembly, dimensionless, from Tables 32.1 to 32.7<br>• `impact_insulation_class_improvement`: the delta-IIC a treatment adds, from Table 32.8 alone; no row carries both, because a difference between two ratings is not a rating<br>• `impact_sound_improvement_db`: the 1977 edition's average improvement in impact sound insulation, in decibels, a level difference and neither of the two above; `added_load_pa` is the load a floor of Table 19.4 was measured under, printed in kg/cm² and held in pascals<br>• `refers_to_row`: twelve descriptions are printed in full and refer to another row rather than repeating the structural floor; resolve with `PUBLISHED_IMPACT_INSULATION[f'{row.table}/{row.refers_to_row}']`<br>• `has_section_drawing`: the "Esquema" cell is a drawing with no textual equivalent, so that is all the row records of it<br>• `layer_density_kg_m3`: a mass density the running description buries, on the three rows that print one; it is one layer's, which is why it says layer, and row 35A serves none because the page prints that cell twice and the two printings disagree<br>• `misprinted`: seventeen rows carry a pair whose two halves are not each other, registered in `docs/ERRATA.md`; the printed description is kept whole beside the mark<br>• `attributed_to`: every row of Chapter 32 names the credit of its own table, because Tables 32.1 to 32.7 are a 1967 NBS survey and Table 32.8 a 1963 paper by Zeller; the 1977 rows credit nothing | `row.why_missing('impact_insulation_class')  # the page does not give it` |
| `impact_insulation_named` | `function` | **Every row whose printed description contains a fragment.**<br>• `name`: matched without case against the description, which is the only thing these tables name a construction by<br>• the descriptions are in the language of the page, and a fragment crosses the two tables: `'linóleo'` answers with four floors that carry a linoleum finish and the five treatments of Table 32.8<br>• `catalogue=`: the rows to search instead of `PUBLISHED_IMPACT_INSULATION`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_IMPACT_INSULATION \| mine`; a row of another class is refused by its key (`TypeError`) | `building.impact_insulation_named('baldosa de vinilo')  # one row`<br><br>• `PUBLISHED_IMPACT_INSULATION` |
| `mass_law_transmission_loss` / `field_incidence_correction` | `function` | **Panel mass law TL (Bies Eq. 7.40/7.42).**<br>• `frequency` [Hz], `mass_per_area` m'' [kg/m²]<br>• `incidence`: 'normal'/'field', `band`: 'third' (−5.5 dB) / 'octave' (−4.0 dB), or `field_correction` [dB] (Norton uses a flat 5 dB)<br>• +6 dB/octave and +6 dB/mass doubling | `tl = building.mass_law_transmission_loss(500, 20)` |
| `single_panel_transmission_loss` | `function` | **Single-panel R, Sharp's method (Bies 7.2.4.1).**<br>• `frequency` [Hz], `mass_per_area` [kg/m²]<br>• `critical_frequency` fc [Hz] or `bending_stiffness` B' [N·m]<br>• `loss_factor` η, `band`, `coincidence_model`: 'sharp' (Bies 7.44) / 'cremer' (Norton 3.110) | `r = building.single_panel_transmission_loss(f, 15, critical_frequency=2100)`<br><br>• `SoundReductionResult` |
| `plateau_transmission_loss` / `PLATEAU_MATERIALS` | `function` / `mapping` | **Plateau (Watters) TL estimate (Norton & Karczub 3.9.1, Table 3.1).**<br>• `frequency` [Hz]; `material` + `thickness_mm`, or `mass_per_area` + `plateau_height` + `frequency_ratio`<br>• `material`: a name in `PLATEAU_MATERIALS`, or a `solids.PlateauMaterial` row, published or read from a catalogue of your own, whose three numbers are read through `printed()` (a bound or a word is refused with what the row holds); an explicit number replaces the material's, which is then not read<br>• field-incidence mass law → horizontal coincidence plateau (point A to B) → 10 dB/octave<br>• `PLATEAU_MATERIALS`: 8 materials as (kg/m² per mm, plateau dB, B/A) | `r = building.plateau_transmission_loss(f, material='brick', thickness_mm=110)`<br><br>• `SoundReductionResult` with `plateau_height`, `plateau_start`, `plateau_end` |
| `orthotropic_transmission_loss` | `function` | **Orthotropic (ribbed / corrugated) panel R (Vigran 6.5.3; Bies 7.2.4.5).**<br>• `frequency` [Hz], `mass_per_area` m'' [kg/m²]<br>• `critical_frequency_lower` fc1 / `critical_frequency_upper` fc2 [Hz]<br>• `method`: 'integral' (Vigran Eq. 6.111 double integral, uses `loss_factor` η) / 'heckl' (Bies Fig. 7.9b design chart, needs fc2 > 4·fc1)<br>• `area` S [m²] (Bies Eq. 7.36 limit) or `limiting_angle_deg` θL [deg] (Default: 78) | `r = building.orthotropic_transmission_loss(f, 7.5, critical_frequency_lower=400, critical_frequency_upper=4000)`<br><br>• `SoundReductionResult` with `critical_frequency_upper` |
| `orthotropic_critical_frequencies` | `function` | **Coincidence range (fc1, fc2) of an orthotropic panel (Vigran Eq. 6.107).**<br>• `mass_per_area` m'' [kg/m²]<br>• `bending_stiffness_1` / `bending_stiffness_2` [N·m] (order irrelevant)<br>• `speed_of_sound` (Default: 343.0)<br>• the stiffest direction gives the lowest fc | `fc1, fc2 = building.orthotropic_critical_frequencies(8.5, 17.5, 2202)`<br><br>• `(float, float)` [Hz], sorted |
| `corrugated_plate_stiffness` / `corrugated_plate_mass_factor` | `function` | **Equivalent stiffnesses and developed length of a sinusoidal corrugation (Vigran Eq. 3.115, Timoshenko & Woinowsky-Krieger).**<br>• `thickness` h, `corrugation_amplitude` H, `corrugation_wavelength` L [m]<br>• `youngs_modulus` E [Pa], `poisson_ratio` ν (Default: 0.3)<br>• the mass factor is the arc length of one period over the period | `bx, bz, bxz = building.corrugated_plate_stiffness(1e-3, 0.01, 0.1, youngs_modulus=2.1e11)`<br>`m = 7.8 * building.corrugated_plate_mass_factor(0.01, 0.1)`<br><br>• `(Bx, Bz, Bxz)` [N·m]; factor ≥ 1 |
| `orthotropic_plate_resonance` | `function` | **Eigenfrequency of a simply supported orthotropic plate (Vigran Eq. 3.113 = Bies Eq. 7.27, Hearmon 1959).**<br>• `mode_x` i, `mode_z` n (≥ 1)<br>• `length_x` a, `length_z` b [m], `mass_per_area` m'' [kg/m²]<br>• `bending_stiffness_x` / `_z` / `_xz` [N·m]<br>• the panel TL models are valid above ≈ 1.5·f₁,₁ | `orthotropic_plate_resonance(1, 1, length_x=1.0, length_z=1.0, mass_per_area=7.8, bending_stiffness_x=b, bending_stiffness_z=b, bending_stiffness_xz=b)`<br><br>• [Hz] |
| `double_wall_transmission_loss` / `mass_spring_mass_resonance` | `function` | **Double-wall R (Bies 7.2.6, Eq. 7.62-7.64).**<br>• `mass1`/`mass2` [kg/m²], `gap` d [m]<br>• `cavity_medium`: porous fill (`PorousMediumResult`) lowers f0<br>• below f0 = total-mass law; f0 = mass-air-mass resonance | `r = building.double_wall_transmission_loss(f, 12, 12, 0.1)`<br><br>• `SoundReductionResult` |
| `heavy_impact_source_specification` / `heavy_impact_source_limits` / `HeavyImpactSourceSpec` / `HEAVY_IMPACT_SOURCES` / `HEAVY_IMPACT_OCTAVE_BANDS` | `function` / `dataclass` / `mapping` / `tuple` | **Standard heavy and soft impact source (ISO 16283-2 Table A.1, JIS A 1418-2 Tables A.1/A.2).**<br>• `source`: 'rubber_ball' / 'bang_machine'<br>• printed LFE per octave 31.5-500 Hz with tolerance, drop height, effective mass, restitution, 20 ± 2 ms contact time | `spec = building.heavy_impact_source_specification('rubber_ball')`<br>`f, lo, hi = building.heavy_impact_source_limits('bang_machine')` |
| `check_heavy_impact_source` / `HeavyImpactSourceCheck` | `function` / `dataclass` | **Source conformance against the printed spectrum.**<br>• `force_exposure_level`: five octave-band LFE [dB re 1 N]<br>• `source`: 'rubber_ball' / 'bang_machine'<br>• `.plot()` | `chk = building.check_heavy_impact_source([39, 31, 23, 17, 12.5])`<br><br>• `HeavyImpactSourceCheck` (`passes`, `deviation`, `within_tolerance`) |
| `impact_force_exposure_level` | `function` | **Impact force exposure level LFE (ISO 16283-2 Formula (A.1)).**<br>• `force` F(t) [N] (1-D record of one impact), `fs` [Hz]<br>• `reference_force` F0 (Default: 1 N), `reference_time` Tref (Default: 1 s) | `lfe = building.impact_force_exposure_level(force, 200_000)`<br><br>• [dB re 1 N] |
| `standardized_maximum_impact_level` / `fast_reverberation_correction` / `StandardizedMaximumImpactResult` | `function` / `dataclass` | **Standardized maximum impact level L'i,Fmax,V,T (ISO 16283-2 Formulae (4)-(6)).**<br>• `level` Li,Fmax [dB], `volume` V [m³], `reverberation_time` T [s]<br>• `reference_time` T0 (Default: 0.5 s), `reference_volume` V0 (Default: 50 m³)<br>• the Fast correction is exactly 0 dB at T = T0<br>• `.plot()` | `res = building.standardized_maximum_impact_level(li, 41.4, t)`<br><br>• `StandardizedMaximumImpactResult` |
| `heavy_impact_octave_levels` | `function` | **One-third-octave to octave synthesis (ISO 16283-2 Formula (20)).**<br>• `level`: thirds in ascending order, length a multiple of 3 | `oct = building.heavy_impact_octave_levels(thirds)`<br><br>• [dB] |
| `a_weighted_maximum_impact_level` / `HEAVY_IMPACT_A_WEIGHTING` / `AWeightedMaximumImpactResult` | `function` / `mapping` / `dataclass` | **A-weighted maximum impact level XiA,Fmax (ISO 717-2 Annex D, Formula (D.1)).**<br>• `level`: 12 thirds (50-630 Hz) or 4 octaves (63-500 Hz) [dB]<br>• `band`: 'third' / 'octave' (inferred from the length)<br>• Table D.3 corrections, rounded half-up<br>• `.plot()` | `res = building.a_weighted_maximum_impact_level([65.3, 64.5, 58.0, 55.8])`<br><br>• `AWeightedMaximumImpactResult` (`rating` = 55 dB) |
| `normalized_ceiling_attenuation` | `function` | **Normalized ceiling attenuation Dn,c (ISO 140-9 clause 3.3).**<br>• `level_source` L1, `level_receiving` L2 [dB], `absorption_area` A [m²]<br>• `reference_area` A0 (Default: 10 m² ISO; ASTM E1414 uses 12 m²) | `dnc = building.normalized_ceiling_attenuation(l1, l2, a)` |
| `ceiling_attenuation_class` / `CEILING_ATTENUATION_CONTOUR` / `CeilingAttenuationResult` | `function` / `mapping` / `dataclass` | **Ceiling attenuation class CAC (ASTM E413-22 clause 5, via ASTM E1414).**<br>• `attenuation` Dn,c: 16 thirds 125-4000 Hz [dB]<br>• data rounded to integers (5.2), Σ deficiencies ≤ 32 dB, max ≤ 8 dB<br>• `.plot()` | `res = building.ceiling_attenuation_class(dnc)`<br><br>• `CeilingAttenuationResult` (`rating`, `deficiencies`) |
| `plenum_flanking_reduction_index` / `partition_referenced_reduction_index` / `PlenumFlankingResult` | `function` / `dataclass` | **Suspended-ceiling plenum flanking path Rcl (Vigran Eqs. (9.13), (9.18)-(9.20)).**<br>• `reduction_index_source` RS / `_receiving` RR [dB]<br>• `ceiling_length` LR, `plenum_height` h [m]<br>• `sidewalls`: 'reflecting' (ε = 2) / 'absorbing' (ε = 1)<br>• `attenuation_source` / `_receiving` m [1/m] switch to Eq. (9.18)<br>• `.plot()` | `res = building.plenum_flanking_reduction_index(rs, rr, ceiling_length=4.75, plenum_height=0.43)`<br><br>• `PlenumFlankingResult` |
| `wall_tie_stiffness` / `wall_tie_stiffness_per_area` / `WALL_TIE_STIFFNESS` | `function` / `mapping` | **Dynamic stiffness of masonry wall ties (Hopkins Table A4).**<br>• `tie`: 'butterfly' (1.7 MN/m) / 'double_triangle' (16.1) / 'vertical_twist' (94.0) at 50 mm, 'vertical_twist_100mm' (43.4)<br>• `ties_per_area` n [1/m²] → N·k/S [N/m³] for `tie_stiffness_per_area` | `s = building.wall_tie_stiffness_per_area(2.5, 'vertical_twist_100mm')`<br><br>• feeds `mass_spring_mass_resonance` / `double_wall_transmission_loss` |
| `wall_tie_coupling_loss_factor` / `WallTieCouplingResult` | `function` / `dataclass` | **Structure-borne coupling of a tie array (Hopkins Eqs. 4.87/4.88).**<br>• `frequency` [Hz], `mass1`/`mass2` [kg/m²], `bending_stiffness1`/`2` [N·m]<br>• `ties_per_area` n [1/m²], `tie`: name, k [N/m], or None (rigid, Yc = 0)<br>• `.plot()` | `res = building.wall_tie_coupling_loss_factor(f, 150, 170, b1, b2, ties_per_area=2.5, tie='butterfly')`<br><br>• `WallTieCouplingResult` |
| `plot_double_wall_geometry` | `function` | **Mass-spring-mass cross-section to scale.**<br>• `mass1`, `mass2` [kg/m²], `gap` [m]<br>• `resonance_frequency` [Hz] (annotation)<br>• `language` | `plot_double_wall_geometry(8.8, 8.8, 0.1)`<br><br>• Also `SoundReductionResult.plot_geometry()` (double-wall results) |
| `SoundReductionResult` | `dataclass` | **Predicted R(f) of a construction (Bies 7.2).**<br>• `transmission_loss` R [dB], `transmission_coefficient` τ<br>• `critical_frequency` / `critical_frequency_upper` (orthotropic fc1/fc2) / `resonance_frequency`<br>• `.rating()` → Rw (ISO 717-1), `.plot()` | `res.transmission_loss, res.rating().rating` |
| `slit_transmission_coefficient` / `slit_resonance_frequencies` | `function` | **Straight slit τ (Hopkins Eq. 4.99, Gomperts).**<br>• `frequency` [Hz], `width` w [m], `depth` d [m]<br>• `field`: 'diffuse'/'normal', `position`: 'mid'/'edge'<br>• maxima at d+2e = zλ/2 | `res = building.slit_transmission_coefficient(f, 0.002, 0.1)`<br><br>• `ApertureTransmissionResult` |
| `circular_aperture_transmission_coefficient` | `function` | **Circular hole τ (Hopkins Eq. 4.102, Wilson-Soroka).**<br>• `frequency` [Hz], `radius` a [m], `depth` d [m]<br>• τ → 1 for a large hole | `res = building.circular_aperture_transmission_coefficient(f, 0.01, 0.002)`<br><br>• `ApertureTransmissionResult` |
| `plot_aperture_geometry` | `function` | **Wall-aperture section to scale.**<br>• `depth` d [m]<br>• Exactly one of `width` w / `radius` [m]<br>• `language` | `plot_aperture_geometry(0.1, width=0.003)`<br><br>• Also `ApertureTransmissionResult.plot_geometry()` |
| `composite_transmission_loss` / `transmission_loss_from_coefficient` | `function` | **Composite R of parallel elements (Hopkins Eq. 4.92).**<br>• `areas` Sₙ [m²], `reduction_indices` Rₙ [dB] (1-D or (N, bands))<br>• a bare opening (Sₐ/S) caps R at 10 lg(S/Sₐ) | `r = building.composite_transmission_loss([0.99, 0.01], [55, 0])` |
| `ApertureTransmissionResult` | `dataclass` | **Slit / hole transmission (Hopkins 4.3.10).**<br>• `transmission_coefficient` τ, `transmission_loss` R = −10 lg(τ)<br>• `kind`: 'slit'/'circular', `.plot()` | `res.transmission_loss` |
| `band_uncertainty` | `function` | **One-third-octave standard uncertainty u (ISO 12999-1 Tables 2/4/6).**<br>• `measurand`: 'airborne'/'impact'/'impact_reduction'<br>• `situation`: 'A'/'B'/'C'<br>• `upper_limit`: σR95 (airborne A, Annex D) (Default: False) | `u = building.band_uncertainty('airborne', 'B')`<br><br>• `BandUncertainty` |
| `single_number_uncertainty` | `function` | **Single-number standard uncertainty u (ISO 12999-1 Tables 3/5/7).**<br>• `quantity`: 'r_w'/'ln_w'/'delta_lw' (+ aliases, +c/+ctr variants)<br>• `situation`: 'A'/'B'/'C'<br>• `upper_limit` (Default: False) | `u = building.single_number_uncertainty('r_w', 'B')`<br><br>• u [dB] (0.9) |
| `single_number_uncertainty_uncorrelated` | `function` | **Uncorrelated single-number u from bands (ISO 12999-1 Formula B.2).**<br>• `band_uncertainties`: per-band u_i [dB]<br>• `reference_differences`: L_i − R_i [dB] | `u = building.single_number_uncertainty_uncorrelated(u_i, d_i)`<br><br>• Energy-weighted quadrature u [dB] |
| `maximum_repeatability_standard_deviation` | `function` | **Max repeatability σx per band (ISO 12999-1 Table 1).**<br>• (no parameters) | `b = building.maximum_repeatability_standard_deviation()`<br><br>• `BandUncertainty` (lab self-verification) |
| `insulation_coverage_factor` | `function` | **Coverage factor k (ISO 12999-1 Table 8).**<br>• `confidence`: fraction (Default: 0.95)<br>• `one_sided` (Default: False) | `k = building.insulation_coverage_factor(0.95)`<br><br>• 1.96 (two-sided) / 1.65 (one-sided) |
| `insulation_expanded_uncertainty` | `function` | **Expanded uncertainty U = k·u (ISO 12999-1 Formula 2).**<br>• `u` [dB]<br>• `coverage`: fraction (Default: 0.95)<br>• `one_sided` (Default: False); enforces k ≥ 1 | `U = building.insulation_expanded_uncertainty(0.9)`<br><br>• 1.764 [dB] |
| `uncertain_value` | `function` | **Attach U to a rating (ISO 12999-1 Clause 8).**<br>• `value` [dB], `quantity`, `situation`<br>• `coverage` (Default: 0.95), `one_sided` (Default: False), `upper_limit` (Default: False) | `uv = building.uncertain_value(52.0, 'rprime_w', 'B')`<br><br>• `UncertainValue` (value ± U) |
| `combine_uncertainties` | `function` | **Quadrature combination (ISO 12999-1 Formula C.2).**<br>• `*components`: non-negative u_i [dB] | `uc = building.combine_uncertainties(1.0, 0.6)`<br><br>• sqrt(Σ u_i²) = 1.166 [dB] |
| `prediction_input_uncertainty` | `function` | **Prediction input uncertainty (ISO 12999-1 Formula A.1).**<br>• `sigma_reproducibility`, `sigma_product` [dB]<br>• `n`: measurements (≥ 1) | `u = building.prediction_input_uncertainty(1.8, 1.0, 3)`<br><br>• sqrt((σR²+σp²)/n + σp²) [dB] |
| `reduce_by_independent_measurements` | `function` | **Reduce u by m measurements (ISO 12999-1 Formula A.7).**<br>• `u` [dB]<br>• `m`: independent measurements (≥ 1) | `ur = building.reduce_by_independent_measurements(1.0, 4)`<br><br>• u/√m = 0.5 [dB] |
| `satisfies_lower_requirement` | `function` | **Conformity to a minimum (ISO 12999-1 Formula 5).**<br>• `value`, `expanded_uncertainty_value`, `requirement` [dB] | `ok = building.satisfies_lower_requirement(52.0, 1.485, 50.0)`<br><br>• True when value − U > requirement |
| `satisfies_upper_requirement` | `function` | **Conformity to a maximum (ISO 12999-1 Formula 4).**<br>• `value`, `expanded_uncertainty_value`, `requirement` [dB] | `ok = building.satisfies_upper_requirement(45.0, 1.5, 50.0)`<br><br>• True when value + U < requirement |
| `BandUncertainty` | `dataclass` | **Per-band standard uncertainty (ISO 12999-1).**<br>• `measurand`, `situation`<br>• `frequencies` [Hz], `uncertainties` [dB]<br>• `upper_limit`: σR95 flag<br>• `.to_arrays()` | `b.frequencies, b.uncertainties` |
| `UncertainValue` | `dataclass` | **A value with its expanded uncertainty.**<br>• `value`, `standard_uncertainty`, `expanded_uncertainty` [dB]<br>• `coverage_factor`, `confidence`, `one_sided`<br>• `.lower` = y − U, `.upper` = y + U | `uv.lower, uv.upper` |
| `COVERAGE_FACTORS` | `mapping` | **Table 8 coverage factors (read-only).**<br>Keyed by `(confidence, one_sided)` → k | `COVERAGE_FACTORS[(0.95, False)]  # 1.96` |
| `sound_absorption_coefficient_uncertainty` | `function` | **Absorption-coefficient uncertainty αs (ISO 12999-2 Table 1, Formula 1).**<br>• `alpha`, `frequencies` [Hz] (1/3-oct 63–5000)<br>• `condition`: 'reproducibility'/'repeatability'<br>• `confidence` (Default: 0.95) | `r = materials.sound_absorption_coefficient_uncertainty(a_s, f)`<br><br>• `AbsorptionUncertaintyResult` |
| `equivalent_area_uncertainty` | `function` | **Equivalent-area uncertainty AT (ISO 12999-2 Formula 2, S = 10 m²).**<br>• `area`, `frequencies` [Hz]<br>• `condition`, `confidence` (Default: 0.95) | `r = materials.equivalent_area_uncertainty(a_t, f)`<br><br>• `AbsorptionUncertaintyResult` |
| `practical_coefficient_uncertainty` | `function` | **Practical-coefficient uncertainty αp (ISO 12999-2 Table 2, Formula 4).**<br>• `alpha_p`, `frequencies` [Hz] (octave 250–4000)<br>• `condition`, `confidence` (Default: 0.95) | `r = materials.practical_coefficient_uncertainty(a_p, f)`<br><br>• `AbsorptionUncertaintyResult` |
| `weighted_coefficient_uncertainty` | `function` | **Weighted-coefficient uncertainty αw (ISO 12999-2 Formulae 6/7).**<br>• `alpha_w` (carried for the interval)<br>• `condition`, `confidence` | `weighted_coefficient_uncertainty(0.70)`<br><br>• σR = 0.035 / σr = 0.020 |
| `single_number_rating_uncertainty` | `function` | **DLα,NRD uncertainty (ISO 12999-2 Formulae 8/9, EN 1793-1).**<br>• `dl_alpha` [dB] (≥ 0)<br>• `condition`, `confidence` | `single_number_rating_uncertainty(8.1)`<br><br>• σR = 0.10·DLα / σr = 0.02·DLα |
| `absorption_coverage_factor` | `function` | **Coverage factor k (ISO 12999-2 Table 3, rounded).**<br>• `confidence`: 0.68/0.80/0.90/0.95/0.99/0.999 | `absorption_coverage_factor(0.95)  # 2.0` |
| `AbsorptionUncertaintyResult` | `dataclass` | **Absorption uncertainty (ISO 12999-2).**<br>• `standard_uncertainty` u, `expanded_uncertainty` U = k·u<br>• `reported_expanded_uncertainty` (Clause 8 rounding)<br>• `.lower`, `.upper`, `.plot()` | `r.reported_expanded_uncertainty` |
| `sound_power_pressure` | `function` | **Sound power from surface pressure (ISO 3744/3746).**<br>• `levels_positions`: (NM, NB) SPL [dB]<br>• `surface`: 'hemisphere' / 'box'<br>• `radius` [m] or `dimensions`+`distance` [m]<br>• `reflecting_planes`: 1/2/3 (Default: 1)<br>• `background_levels`: for K1<br>• `frequencies` [Hz]: for LWA<br>• `room`: `RoomEnvironment` for K2 (Default: None → free field)<br>• `grade`: 'engineering' (Default) / 'survey'<br>• `omc_uncertainty` [dB] (Default: 0) | `res = emission.sound_power_pressure(levels, 'hemisphere', radius=1.5, frequencies=f)`<br><br>• `SoundPowerResult` |
| `measurement_positions` | `function` | **Hemisphere mic coordinates (ISO 3744 Annex B).**<br>• `surface`: 'hemisphere'<br>• `radius` [m]<br>• `reflecting_planes`: 1/2/3<br>• `tones`: Table B.1 vs B.2 (Default: True)<br>• `grade`: 'engineering'/'survey' | `xyz = emission.measurement_positions('hemisphere', radius=1.5)`<br><br>• (N, 3) coordinates [m] |
| `plot_microphone_positions` | `function` | **3-D microphone array on its measurement surface.**<br>• `positions`: (N, 3) [m] from `measurement_positions`/`precision_positions`<br>• `radius` [m] (Default: largest norm)<br>• `language` | `plot_microphone_positions(emission.measurement_positions('hemisphere', radius=2.0), radius=2.0)`<br><br>• Numbered points + hemisphere/sphere wireframe + reflecting plane |
| `emission_sound_pressure_level` | `function` | **L_p at a work station: the reading less both corrections (ISO 11201 Eq. 7, ISO 11202 Eq. 10, ISO 11204 Eq. 9).**<br>• `measured_level_db` [dB]<br>• `background_correction_db` K1 [dB], `local_correction_db` K3 [dB]<br>Never for a peak level: neither correction is permitted on one | `emission.emission_sound_pressure_level(76.9, local_correction_db=3.7)  # 73.2` |
| `background_noise_correction_at_workstation` | `function` | **K1 with the ISO 11200 group's own thresholds.**<br>• `measured_level_db`, `background_level_db` [dB]<br>• `grade`: 'engineering' (6 dB floor) / 'survey' (3 dB)<br>Past 15 dB of margin K1 is zero; below the floor it is held there and the level becomes an upper bound | `k1, held = emission.background_noise_correction_at_workstation(79.0, 70.0)` |
| `local_environmental_correction` | `function` | **K3, the piecewise correction of ISO 11202 Eq. (A.5) and ISO 11204 Eqs. (A.2)/(A.5).**<br>• `ratio`: the dimensionless z<br>7 dB for z ≤ 0,2, −10 lg z up to 1, then 0; continuous where the cap takes over | `emission.local_environmental_correction(0.5)  # 3.01` |
| `environmental_ratio_from_k2` | `function` | **z from the environmental correction of the test room (ISO 11202 Eq. A.4, ISO 11204 Eq. A.3).**<br>• `environmental_correction_db` K2 [dB]<br>• `directivity_index_db` [dB] (Default: 0)<br>With no directivity K3 comes out equal to K2 | `emission.environmental_ratio_from_k2(3.73)` |
| `environmental_ratio_from_absorption` | `function` | **The same z from the equivalent absorption area (ISO 11204 Eq. A.6).**<br>• `absorption_area_m2` A, `measurement_surface_m2` S_M<br>• `directivity_index_db` [dB] (Default: 0)<br>Identically equal to the K2 route under the ISO 3744 definition of K2 | `emission.environmental_ratio_from_absorption(47.0, 16.0)` |
| `grade_from_local_correction` | `function` | **The accuracy grade K3 earns (ISO 11202 A.1.3).**<br>• `local_correction_db` [dB]; the worst band decides<br>4 dB or less is grade 2, more is grade 3 | `emission.grade_from_local_correction(3.7)  # 'engineering'` |
| `operating_standard_deviation` | `function` | **sigma_omc of repeated readings, Equation (C.1).**<br>• `levels_db`: at least two readings [dB]<br>Sample standard deviation, 1/(N−1), as printed; see `docs/ERRATA.md` on the two Annex B tables | `emission.operating_standard_deviation([79.0, 80.2, 82.9])  # 2.0` |
| `total_standard_deviation` | `function` | **sigma_tot = sqrt(sigma_R0² + sigma_omc²).**<br>• `reproducibility_db` of the method, `operating_db` of the machine [dB] | `emission.total_standard_deviation(1.5, 1.0)  # 1.80` |
| `emission_expanded_uncertainty` | `function` | **U = k·sigma_tot for the ISO 11200 group.**<br>• `total_standard_deviation_db` [dB]<br>• `coverage_factor` (Default: 1.6, what the worked examples print) | `emission.emission_expanded_uncertainty(1.8)  # 2.88` |
| `subinterval_level` | `function` | **One level for a cycle of operating periods of different lengths.**<br>• `levels_db`, `durations_s`<br>Energy average weighted by duration, not by count | `emission.subinterval_level([80.0, 90.0], [10.0, 1.0])` |
| `EmissionPressureResult` | `dataclass` | **An emission sound pressure level and the two corrections behind it.**<br>• `level_db`, `measured_level_db`, `background_correction_db`, `local_correction_db`<br>• `grade`, `upper_bound`, `standard`<br>• `.plot()`: the reading, both corrections and what is left, as a waterfall<br>• takes `level_db`, `measured_level_db`, `background_correction_db`, `local_correction_db`, `grade`, `background_margin_db`, `standard`; `upper_bound` is read-only, read from them | `res.level_db, res.upper_bound` |
| `NEGLIGIBLE_BACKGROUND_MARGIN_DB` / `MINIMUM_BACKGROUND_MARGIN_DB` | `constant` / `mapping` | **The two background thresholds of the group: 15 dB above which K1 is zero, and the 6 dB (grade 2) / 3 dB (grade 3) floor a determination may be claimed from.** | `emission.MINIMUM_BACKGROUND_MARGIN_DB['engineering']  # 6.0` |
| `MAX_K3_DB` / `GRADE_2_MAX_K3_DB` | `constant` | **The 7 dB cap on K3, and the 4 dB above which the result is grade 3 rather than grade 2.** | `emission.GRADE_2_MAX_K3_DB  # 4.0` |
| `DEFAULT_COVERAGE_FACTOR` | `constant` | **k = 1,6, the factor the ISO 11200 group's worked examples print.** | `emission.DEFAULT_COVERAGE_FACTOR  # 1.6` |
| `background_noise_correction` | `function` | **Background correction K1 (ISO 3744 Eq. 16).**<br>• `source_levels` [dB]<br>• `background_levels` [dB]<br>• `grade`: 'engineering'/'survey' | `k1 = emission.background_noise_correction(src, bg)`<br><br>• K1 per band [dB] |
| `environmental_correction` | `function` | **Environmental correction K2 (ISO 3744 Eq. A.2).**<br>• `surface_area` S [m²]<br>• `absorption_area` A, or `reverberation_time`+`volume`, or `mean_absorption_coefficient`+`room_surface` | `k2 = emission.environmental_correction(14.1, reverberation_time=0.6, volume=300)`<br><br>• K2 [dB] |
| `SoundPowerResult` | `dataclass` | **Surface-pressure sound power.**<br>• `sound_power_level` [dB]<br>• `surface_pressure_level`, `mean_pressure_level` [dB]<br>• `background_correction`, `environmental_correction` [dB]<br>• `directivity_index` [dB] `(NM, NB)`<br>• `surface_area` [m²]<br>• `sound_power_level_a` [dB]<br>• `uncertainty` [dB]<br>• `grade`<br>• `declare(...)` → `NoiseEmissionDeclaration` | `res.sound_power_level, res.sound_power_level_a` |
| `RoomEnvironment` | `dataclass` | **Room data behind K2 (ISO 3744 Annex A), for `sound_power_pressure`.**<br>• `absorption_area` A [m²]<br>• `reverberation_time` T [s] + `volume` V [m³] (Eq. A.3)<br>• `mean_absorption_coefficient` α + `room_surface` Sv [m²] (Eq. A.7)<br>All Default: None; the empty environment is a free field (K2 = 0) | `RoomEnvironment(reverberation_time=0.6, volume=300)` |
| `sound_energy_pressure` | `function` | **Sound energy level LJ of a burst from surface single event levels (ISO 3744 8.3 / ISO 3746 8.4).**<br>• `levels_positions`: (NM, NB) single event levels, or (Ne, NM, NB) per event [dB]<br>• `surface`, `radius` / `dimensions`+`distance`, `reflecting_planes`: as `sound_power_pressure`<br>• `events`: Ne encompassed by one reading (Eq. 20)<br>• `background_levels` [dB] + `integration_time` T [s] (required together): K1 over the same window<br>• `frequencies` [Hz]: for LJA<br>• `room`: `RoomEnvironment` for K2<br>• `grade`, `omc_uncertainty` | `lj = emission.sound_energy_pressure(events, 'hemisphere', radius=2.0, frequencies=f)`<br><br>• `SoundEnergyResult` |
| `SoundEnergyResult` | `dataclass` | **Surface single-event sound energy.**<br>• `frequencies` [Hz] (or `None`)<br>• `sound_energy_level` [dB re 1 pJ]<br>• `surface_event_level`, `mean_event_level` [dB]<br>• `background_correction`, `environmental_correction` [dB]<br>• `directivity_index` (NM, NB)<br>• `surface_area` [m²]<br>• `sound_energy_level_a` [dB]<br>• `uncertainty` [dB], `grade`<br>• `events` (a count)<br>• `integration_time` [s] | `lj.sound_energy_level, lj.sound_energy_level_a` |
| `mean_single_event_level` | `function` | **Level of one event from Ne events (ISO 3744 Eq. 19/20).**<br>• `levels`: per-event levels on the first axis (Eq. 19), or one reading of `events` events (Eq. 20) [dB]<br>• `events`: Ne of one reading (Default: None) | `emission.mean_single_event_level(per_event)`<br>`emission.mean_single_event_level(reading, events=5)` |
| `reference_atmosphere_correction` | `function` | **Annex G corrections C1, C2 to 101.325 kPa and 23 °C (ISO 3744 Eq. G.1/G.3).**<br>• `temperature_c` [°C]<br>• `static_pressure_kpa` [kPa], or `altitude` [m] via Eq. G.2 | `corr = emission.reference_atmosphere_correction(8.0, altitude=1200.0)`<br><br>• `ReferenceAtmosphereCorrection` |
| `ReferenceAtmosphereCorrection` | `dataclass` | **The two Annex G corrections.**<br>• `c1`, `c2`, `total` [dB]<br>• `static_pressure_kpa` [kPa], `temperature_c` [°C] | `lj_ref = lj.sound_energy_level + corr.total` |
| `OperatingModeDeclaration` | `dataclass` | **ISO 4871 dual-number values for one operating mode.**<br>• `mode`: column label<br>• `sound_power_level` L_WA [dB re 1 pW]<br>• `sound_power_uncertainty` K_WA [dB]<br>• `emission_pressure_level` L_pA, `emission_pressure_uncertainty` K_pA [dB] (optional)<br>• `verification_level` L_1 [dB] (optional)<br>• `declared_sound_power_level`: L_WAd = L_WA + K_WA (3.15)<br>• `verified`: L_1 ≤ L_WAd (6.2, combined form)<br>• `verified_dual`: L_1 ≤ round(L_WA) + round(K_WA) (6.2, dual-number form) | `OperatingModeDeclaration('Mode 1', 88.0, 2.0)` |
| `DeclarationForm` | `constant` | **The `form` literal of `NoiseEmissionDeclaration` (ISO 4871 clause 6).**<br>• `'dual-number'`: L_WA and K_WA declared as a pair (Default)<br>• `'single-number'`: the declared L_WAd alone | `NoiseEmissionDeclaration(modes, form='single-number')` |
| `NoiseEmissionDeclaration` | `dataclass` | **ISO 4871:1996 noise emission declaration (machinery).**<br>• `modes`: `OperatingModeDeclaration` per mode<br>• `machine`, `operating_conditions` (clause 5)<br>• `noise_test_code`, `basic_standards` (clause 5 b)<br>• `form`: 'dual-number' (Default) / 'single-number'<br>• `.report(path, ...)`: ISO 4871 fiche → PDF | `NoiseEmissionDeclaration((m1, m2), machine='...').report('iso4871.pdf')` |
| `sound_power_reverberation` | `function` | **Reverberation-room LW, direct (ISO 3741).**<br>• `levels`: mean room SPL [dB] (1D or (NM, NB))<br>• `t60` [s]<br>• `volume` V [m³]<br>• `surface_area` S [m²]<br>• `frequencies` [Hz] (required)<br>• `background_levels`: for K1<br>• `temperature_c` [°C] (Default: 23)<br>• `static_pressure_kpa` [kPa] (Default: 101.325) | `rev = emission.sound_power_reverberation(lp, t60, 200, 220, f)`<br><br>• `ReverberationSoundPowerResult` |
| `reverberation_background_correction` | `function` | **The background-noise correction K1 of ISO 3741:2010 Eq. (14), on its own.**<br>• `levels`, `background_levels`, `frequencies`, all per band [dB, dB, Hz]<br>• `K1 = −10 lg(1 − 10^(−0.1 ΔL))`, with the qualification of 9.1.2: the lower criterion is 6 dB at 200 Hz and below and at 6.3 kHz and above and 10 dB between them, below it the correction is held there and the answer is an upper bound, and at 15 dB and over there is nothing to correct<br>• the standards that ask for a correction in accordance with ISO 3741, ISO 11957 four times over, call this rather than repeat it | `emission.reverberation_background_correction(lp, bg, f)`<br><br>• K1 [dB] |
| `sound_power_comparison` | `function` | **Reverberation-room LW, comparison (ISO 3741).**<br>• `levels`, `levels_ref`: room SPL [dB]<br>• `lw_ref`: reference-source LW [dB], or its `ReferenceSourceCalibration` (ISO 6926), read in one-third octave bands<br>• `frequencies` [Hz] (required with a calibration)<br>• `background_levels`, `background_levels_ref`<br>• `temperature_c`, `static_pressure_kpa` | `cmp = emission.sound_power_comparison(lp, lp_ref, lw_ref)`<br><br>• `ReverberationSoundPowerResult` (method='comparison') |
| `ReverberationSoundPowerResult` | `dataclass` | **Reverberation-room sound power.**<br>• `frequencies` [Hz] (or `None`)<br>• `sound_power_level` [dB]<br>• `mean_pressure_level` [dB]<br>• `absorption_area` [m²]<br>• `waterhouse_correction` [dB]<br>• `background_correction`, `c1`, `c2` [dB]<br>• `speed_of_sound` [m/s]<br>• `sound_power_level_a` [dB]<br>• `method` | `rev.sound_power_level, rev.waterhouse_correction` |
| `sound_power_in_situ` | `function` | **In situ LW by comparison with a reference sound source (ISO 3747).**<br>• `levels`: (n, bands) L'pi(ST) [dB]<br>• `levels_ref`: (n, bands) or (m, n, bands) L'pi(RSS) [dB]<br>• `lw_ref`: calibrated LW(RSS) [dB], per band or per location, or its `ReferenceSourceCalibration` (ISO 6926), summed into octaves<br>• `frequencies` [Hz] (octaves 63 Hz–8 kHz, required; 63 Hz only where the environment and instrumentation suit it, Table D.1 footnote a)<br>• `background_levels`, `background_levels_ref`: for K1 (8.1 rules)<br>• `temperature_c` [°C] (Default: 23), `static_pressure_kpa` [kPa] (Default: 101.325)<br>• `conditions`: `GradeConditions(excess_levels, directivity_range)` for the Table 2 grade<br>• `sigma_omc` [dB], `coverage_factor` (Default: 2) | `res = emission.sound_power_in_situ(lp, lp_ref, lw_ref, f, background_levels=lb)`<br><br>• `InSituSoundPowerResult` |
| `sound_energy_in_situ` | `function` | **In situ LJ of an impulsive source (ISO 3747 clauses 8.4, 8.5).**<br>• `event_levels`: (n, N, bands) events one at a time, or (n, bands) with `events=N`<br>• `integration_time` [s]: carries Lp(B) to the event interval (Eq. 14)<br>• the rest as `sound_power_in_situ` | `res = emission.sound_energy_in_situ(le, lp_ref, lw_ref, f, background_levels=lb)`<br><br>• `InSituSoundPowerResult` (quantity='energy') |
| `GradeConditions` | `dataclass` | **The two conditions Table 2 reads for the accuracy grade (ISO 3747).**<br>• `excess_levels`: ΔLfA at each microphone position [dB] (Annex A)<br>• `directivity_range`: half-width of the A-weighted directivity survey [dB] (7.2)<br>Either one left out leaves the determination at survey grade | `emission.GradeConditions(excess_levels=[8.2, 7.6, 8.9, 8.0], directivity_range=4.0)` |
| `InSituSoundPowerResult` | `dataclass` | **In situ comparison result (ISO 3747).**<br>• `frequencies` [Hz]<br>• `sound_power_level` / `sound_energy_level` [dB] (the other NaN)<br>• `mean_source_level`, `mean_reference_level`, `reference_levels`, `reference_power_level` [dB]<br>• `background_correction` (n, bands), `background_correction_ref` (m, n, bands) [dB]<br>• `background_requirement_met` per band<br>• `c2` [dB], `grade`, `sigma_r0`, `sigma_omc`, `sigma_tot`, `expanded_uncertainty`, `coverage_factor`<br>• `sound_power_level_a` / `sound_energy_level_a` [dB], `quantity`<br>• `.sound_power_level_ref`, `.sound_energy_level_ref` (Annex C)<br>• `.plot()`<br>• takes `frequencies`, `sound_power_level`, `sound_energy_level`, `mean_source_level`, `mean_reference_level`, `reference_levels`, `reference_power_level`, `background_correction`, `background_correction_ref`, `background_margin_db`, `background_margin_ref_db`, `c2`, `excess_levels_db`, `directivity_range_db`, `sigma_omc`, `coverage_factor`, `sound_power_level_a`, `sound_energy_level_a`, `quantity`; `background_requirement_met`, `upper_bound`, `grade`, `sigma_r0`, `sigma_tot`, `expanded_uncertainty` are read-only, read from them | `res.sound_power_level, res.background_requirement_met` |
| `excess_sound_pressure_level` | `function` | **Excess of sound pressure level over the free field ΔLf (ISO 3747 Eq. A.1).**<br>• `level` Lp(RSS),r [dB], `lw_ref` LW(RSS) [dB], `distance` r [m]; broadcast | `emission.excess_sound_pressure_level(76.5, 92.5, 3.0)  # 4.54 dB` |
| `static_pressure_from_altitude` | `function` | **Static pressure from the site altitude (ISO 3747 Eq. C.2).**<br>• `altitude` Ha [m] | `emission.static_pressure_from_altitude(640.0)  # 93.87 kPa` |
| `sound_power_hard_walled` | `function` | **LW of a small movable source in a hard-walled test room, by comparison with a reference sound source (ISO 3743-1 Eq. 14).**<br>• `levels`: (NM, bands), (NS, NM, bands) or one traverse (bands,) L'p(ST) [dB]<br>• `levels_ref`: (NM, bands) or (bands,) L'p(RSS) [dB]; `lw_ref`: calibrated LW(RSS) [dB]<br>• `frequencies` [Hz]: octaves 125 Hz–8 kHz (63 Hz under the Table B.1 footnote)<br>• `background_levels`, `background_levels_ref`: K1 of Eq. (13) on the means, 1,3 dB below a 6 dB margin<br>• `temperature_c` [°C], `static_pressure_kpa` [kPa]: C2 of Annex A<br>• `sigma_omc_db` [dB], `coverage_factor` (Default: 2) | `res = emission.sound_power_hard_walled(lp, lp_ref, lw_ref, f, background_levels=lb)`<br><br>• `HardWalledSoundPowerResult` |
| `sound_energy_hard_walled` | `function` | **LJ of a source that emits bursts, in a hard-walled test room (ISO 3743-1 Eq. 20).**<br>• `event_levels`: (Ne, NM, bands) one event at a time, or (NM, bands) with `events=Ne`; a source-location axis may precede NM<br>• `background_levels` [dB] + `integration_time_s` T [s] (required together): the background as its exposure over T<br>• the rest as `sound_power_hard_walled` | `res = emission.sound_energy_hard_walled(le, lp_ref, lw_ref, f, background_levels=lb, integration_time_s=10.0)`<br><br>• `HardWalledSoundPowerResult` (quantity='energy') |
| `HardWalledSoundPowerResult` | `dataclass` | **Hard-walled test room result (ISO 3743-1).**<br>• `frequencies` [Hz], `sound_power_level` / `sound_energy_level` [dB] (the other NaN)<br>• `mean_source_level`, `mean_reference_level`, `mean_background_level`, `reference_power_level` [dB]<br>• `background_correction`, `background_correction_ref` [dB], `background_requirement_met` per band<br>• `c2` [dB], `sigma_r0` (Table 3) per band, `sigma_r0_a`, `sigma_omc`, `coverage_factor`<br>• `.sigma_tot`, `.expanded_uncertainty` (and `_a`), `.sound_power_level_ref` (Annex A)<br>• `.plot()`<br>• takes `frequencies`, `sound_power_level`, `sound_energy_level`, `mean_source_level`, `mean_reference_level`, `mean_background_level`, `reference_power_level`, `background_correction`, `background_correction_ref`, `background_margin_db`, `background_margin_ref_db`, `c2`, `sigma_r0`, `sigma_r0_a`, `sigma_omc`, `coverage_factor`, `sound_power_level_a`, `sound_energy_level_a`, `quantity`, `microphone_positions`, `source_positions`; `background_requirement_met`, `upper_bound` are read-only, read from them | `res.sound_power_level, res.expanded_uncertainty_a` |
| `check_hard_walled_room` / `HardWalledRoomCheck` | `function` / `dataclass` | **Is this room a hard-walled test room? (ISO 3743-1 4.2 to 4.4).**<br>• `orientation_levels`: the eight orientation means of a directional source [dB]<br>• `frequencies` [Hz]: octaves 125 Hz–8 kHz<br>• `volume_m3`, `reference_box_m` (three dimensions), `absorption_coefficients` (optional)<br>• `.passes`, `.band_adequate` (spread within Table 3), `.volume_adequate`, `.box_fits`, `.surfaces_hard`, `.plot()` | `emission.check_hard_walled_room(lp8, f, volume_m3=60.0, reference_box_m=[0.6, 0.5, 0.4]).passes` |
| `hard_walled_source_locations` / `SourceLocationPlan` | `function` / `dataclass` | **Source locations from the preliminary survey (ISO 3743-1 7.4, Table 2).**<br>• `levels`: (NM ≥ 6, bands) [dB], `frequencies` [Hz]<br>• sM of Eq. (7) → 1, 2, or 2 plus 2 in another room<br>• `SourceLocationPlan`: `standard_deviation_db`, `source_locations`, `additional_room_locations`, `spectral_character` (Part 2, read-only, read from `standard_deviation_db` and the 2,3 dB and 4 dB of 9.5), `.required_source_locations`, `.plot()` | `emission.hard_walled_source_locations(survey, f).source_locations` |
| `reproducibility_from_round_robin` | `function` | **sigma'_R0 = sqrt(sigma'_tot² − sigma'_omc²) of a round robin (ISO 3743-1 Eq. 24; ISO 3743-2 Formula 14 prints a plus, see `docs/ERRATA.md`).**<br>• `total_db`, `operating_db` [dB]; warns above sigma_tot/√2 | `emission.reproducibility_from_round_robin(2.5, 1.5)  # 2.0` |
| `sound_power_special_room` | `function` | **LW in a special reverberation test room, direct method (ISO 3743-2 Formula 9).**<br>• `levels`: (NM, bands), (NS, NM, bands) or (bands,) [dB]; `frequencies` [Hz]<br>• `volume_m3`, `nominal_reverberation_time_s` Tnom [s]<br>• `background_levels`: Table 4 at each position<br>• `a_weighted_levels`, `a_weighted_background_levels`: LWA by Formula (9) directly<br>• `temperature_c`, `static_pressure_kpa`, `sigma_omc_db`, `coverage_factor` | `res = emission.sound_power_special_room(lp, f, volume_m3=70.0, nominal_reverberation_time_s=0.73)`<br><br>• `SpecialRoomSoundPowerResult` |
| `sound_power_special_room_comparison` | `function` | **LW in a special reverberation test room, comparison method (ISO 3743-2 Formula 10).**<br>• `levels`, `levels_ref` (≥ 6 positions), `lw_ref`, `frequencies`<br>• `background_levels`, `background_levels_ref`: Table 4<br>• `temperature_c`, `static_pressure_kpa`, `sigma_omc_db`, `coverage_factor` | `emission.sound_power_special_room_comparison(lp, lp_ref, lw_ref, f)`<br><br>• `SpecialRoomSoundPowerResult` (method='comparison') |
| `SpecialRoomSoundPowerResult` | `dataclass` | **Special reverberation test room result (ISO 3743-2).**<br>• `sound_power_level`, `mean_pressure_level`, `background_correction` [dB], `background_requirement_met`<br>• `mean_reference_level`, `reference_power_level` (comparison), `volume_m3`, `nominal_reverberation_time_s` (direct)<br>• `sound_power_level_a` (Annex F), `sound_power_level_a_direct`, `mean_a_weighted_level`<br>• `c2`, `sigma_r0` (Table 5), `.expanded_uncertainty_a`, `.plot()`<br>• takes `frequencies`, `sound_power_level`, `mean_pressure_level`, `background_correction`, `background_margin_db`, `background_margin_ref_db`, `mean_reference_level`, `reference_power_level`, `volume_m3`, `nominal_reverberation_time_s`, `c2`, `sigma_r0`, `sigma_r0_a`, `sigma_omc`, `coverage_factor`, `sound_power_level_a`, `sound_power_level_a_direct`, `mean_a_weighted_level`, `background_margin_a_db`, `method`, `microphone_positions`, `source_positions`; `background_requirement_met`, `background_requirement_met_a` are read-only, read from them | `res.sound_power_level_a, res.expanded_uncertainty_a` |
| `special_room_background_correction` | `function` | **The stepped background correction of ISO 3743-2 Table 4.**<br>• `levels`, `background_levels` [dB], broadcast<br>2 dB at 4–5 dB, 1 dB at 6–8 dB, 0,5 dB at 9–10 dB, 0 above; read at the nearest whole decibel | `emission.special_room_background_correction(80.0, 74.5)  # 1.0` |
| `reverberation_parameter` | `function` | **R = 1 + 257/(f V^(1/3)) of ISO 3743-2 Formula (1), or 1 + cS/(8Vf) (NOTE).**<br>• `frequencies` [Hz], `volume_m3`; `surface_area_m2` + `speed_of_sound` [m/s] for the NOTE | `emission.reverberation_parameter([1000.0], 70.0)  # 1.06` |
| `check_special_room_reverberation` / `SpecialRoomReverberationCheck` | `function` / `dataclass` | **Does the reverberation time follow the prescribed curve? (ISO 3743-2 6.2, 6.3, 6.6).**<br>• `reverberation_time_s`, `frequencies` [Hz], `volume_m3`<br>• `nominal_reverberation_time_s`: given, or centred within 0,9–1,1 R Tnom (0,8–1,2 above 6,3 kHz)<br>• `method`: 'direct' (300 m³ ceiling with the 8 kHz octave) / 'comparison'<br>• the four climate values of Formula (2), optional<br>• `.passes`, `.band_within`, `.nominal_in_range`, `.plot()` | `emission.check_special_room_reverberation(t, f3, volume_m3=70.0).nominal_reverberation_time_s` |
| `check_special_room_surfaces` / `SpecialRoomSurfaceCheck` | `function` / `dataclass` | **The surface treatment of ISO 3743-2 6.4.**<br>• `surface_absorption_coefficients`: (walls and ceiling, bands); `floor_absorption_coefficients`; `frequencies`<br>• `surface_areas_m2` for an area-weighted mean<br>• `.surfaces_uniform` (0,5–1,5 times the mean), `.floor_reflective` (< 0,06), `.passes`, `.plot()` | `emission.check_special_room_surfaces(alpha, alpha_floor, f).passes` |
| `check_special_room_suitability` / `SpecialRoomSuitabilityCheck` | `function` / `dataclass` | **The reference-source evaluation of ISO 3743-2 6.7 (Table 1).**<br>• `measured_power_levels` [dB], `frequencies` 125 Hz–8 kHz<br>• `calibrated_power_levels`: the levels [dB], or the ISO 6926 `ReferenceSourceCalibration`, read at `temperature_c`, `static_pressure_kpa` of the test as LW − C2 (ISO 6926 8.4)<br>• ±5 dB at 125 Hz, ±3 dB 250 Hz–4 kHz, ±4 dB at 8 kHz; `.difference_db`, `.passes`, `.plot()` | `emission.check_special_room_suitability(lw_room, calibration, f, temperature_c=20.0, static_pressure_kpa=98.0).passes` |
| `special_room_source_locations` | `function` | **Source locations from the survey of ISO 3743-2 9.4 (Table 3) and the spectral character of 9.5.**<br>• `levels`: six positions [dB]; `frequencies` 125 Hz–8 kHz<br>• `microphone_positions`: 3, 6 (Default) or 12, the column of Table 3<br>• `a_weighted_levels`: the A-weighted row | `emission.special_room_source_locations(survey, f).spectral_character`<br><br>• `SourceLocationPlan` |
| `sound_energy_reverberation` | `function` | **Reverberation-room LJ of a single event, direct (ISO 3741 9.2.4, Eq. 30).**<br>• `levels`: single event levels, 1D, (NM, NB) or (Ne, NM, NB) [dB]<br>• `t60` [s], `volume` V [m³], `surface_area` S [m²], `frequencies` [Hz]<br>• `events`: Ne of one reading (Eq. 23)<br>• `background_levels` [dB] + `integration_time` T [s]: per-position K1i over the same window<br>• `temperature_c`, `static_pressure_kpa` | `lj = emission.sound_energy_reverberation(slams, t60, 200, 220, f)`<br><br>• `ReverberationSoundEnergyResult` |
| `sound_energy_comparison` | `function` | **Reverberation-room LJ of a single event, comparison (ISO 3741 9.2.5, Eq. 31).**<br>• `levels`: single event levels of the source under test<br>• `levels_ref`, `lw_ref`: the steady reference source (`lw_ref` may be its `ReferenceSourceCalibration`)<br>• `frequencies`, `events`, `background_levels` + `integration_time`, `background_levels_ref`<br>• `temperature_c`, `static_pressure_kpa` | `lj = emission.sound_energy_comparison(slams, lp_ref, lw_ref, frequencies=f)`<br><br>• `ReverberationSoundEnergyResult` (method='comparison') |
| `ReverberationSoundEnergyResult` | `dataclass` | **Reverberation-room sound energy of a single event.**<br>• `frequencies` [Hz] (or `None`)<br>• `sound_energy_level` [dB re 1 pJ]<br>• `mean_event_level` [dB]<br>• `absorption_area` [m²], `waterhouse_correction` [dB]<br>• `background_correction`, `c1`, `c2` [dB]<br>• `speed_of_sound` [m/s]<br>• `sound_energy_level_a` [dB]<br>• `method`, `events` (a count)<br>• `integration_time` [s] | `lj.sound_energy_level, lj.method` |
| `octave_band_levels` | `function` | **Octave-band levels from one-third-octave bands (ISO 3741 Annex F, Eq. F.1/F.4).**<br>• `levels` [dB], bands on the last axis<br>• `frequencies` [Hz]: nominal thirds 50 Hz to 10 kHz, complete triplets per octave | `octaves, lj_oct = emission.octave_band_levels(lj.sound_energy_level, f)` |
| `sound_power_in_duct` | `function` | **In-duct sound power of a fan (ISO 5136).**<br>• `levels`: SPL [dB], `(positions, bands)` or an averaged `(bands,)`<br>• `frequencies` [Hz]: nominal thirds 50 Hz-20 kHz (required)<br>• `duct_diameter_m` d [m], 0.15-2<br>• `flow_velocity` U [m/s], < 0 inlet, > 0 outlet<br>• `shield`: 'sampling-tube' (Default)/'nose-cone'/'foam-ball'<br>• `microphone_correction` C1, `shield_correction` C2 [dB]<br>• `temperature_c` [°C] (Default: 20), `static_pressure_kpa` [kPa] (Default: 101.325) | `duct = emission.sound_power_in_duct(lp, f, 0.63, 12.0)`<br><br>• `InDuctSoundPowerResult` |
| `flow_modal_correction` | `function` | **Mean-flow and modal correction C3,4 (ISO 5136 Eq. 7 / Eq. 8).**<br>• `frequencies` [Hz]: nominal thirds<br>• `flow_velocity` U [m/s], signed<br>• `duct_diameter_m` [m]: selects the Annex A table<br>• `shield`: sampling tube polynomial (Annex A) or the omni-directional Eq. 8<br>• `speed_of_sound` [m/s] (Default: 340, Eq. 8 only) | `c34 = emission.flow_modal_correction(f, 15.0, 0.5)`<br><br>• C3,4 per band [dB] |
| `in_duct_reproducibility` | `function` | **Reproducibility σR per band (ISO 5136 Table 2 / Table 3).**<br>• `frequencies` [Hz]: nominal thirds 50 Hz-20 kHz<br>• 12.5-20 kHz: the extrapolated Table 3 values | `s = emission.in_duct_reproducibility(f)`<br><br>• σR per band [dB]; U95 = 2 σR (clause 9.2) |
| `InDuctSoundPowerResult` | `dataclass` | **In-duct sound power.**<br>• `frequencies` [Hz]<br>• `sound_power_level` [dB], `sound_power_level_a` [dB]<br>• `mean_pressure_level`, `corrected_pressure_level` [dB]<br>• `microphone_correction`, `shield_correction`, `flow_modal_correction`, `combined_correction` [dB]<br>• `reproducibility_standard_deviation`, `expanded_uncertainty` [dB]<br>• `information_only_band`: > 10 kHz or \|U\| > 40 m/s, read-only, read from `frequencies` and `flow_velocity`<br>• `duct_diameter_m`, `duct_area`, `characteristic_impedance`, `speed_of_sound`, `flow_velocity`, `shield` | `duct.sound_power_level, duct.flow_modal_correction` |
| `plant_measurement_contour` | `function` | **Measurement contour round a multisource industrial plant (ISO 8297 9.1 to 9.4).**<br>• `plant_outline_m`, `contour_m`: polygons in plan coordinates [m], the contour enclosing the plant without touching it<br>• `characteristic_height_m` H [m], from `plant_characteristic_height_m`<br>• `position_count` (Default: the fewest that meet Dm ≤ 2 d̄ of 9.1.1 c)), `omitted_positions`: layout indices left out (9.1.2.4) | `c = emission.plant_measurement_contour(plant, ring, characteristic_height_m=6.0)`<br><br>• `PlantMeasurementContour` |
| `PlantMeasurementContour` | `dataclass` | **The contour, its positions and the plan quantities.**<br>• `positions_m`, `microphone_directions` (9.4), `distances_m` d_i, `nearest_perimeter_points_m`, `aspect_angles_deg`, `largest_aspect_angle_deg` (9.1.1 b)<br>• `plant_area_m2` Sp, `measurement_area_m2` Sm, `contour_length_m` l, `position_spacing_m` Dm, `mean_distance_m` d̄, `distance_ratio`<br>• `prescribed_microphone_height_m` (9.3), `mean_distance_limits_m` (9.1.1 a), `largest_plant_dimension_m` (1.2), `plant_centre_m`, `minimum_receiver_distance_m` (0.2 a)<br>• `.sound_power(levels_db, frequencies_hz, ...)` runs clause 10 with this geometry | `c.mean_distance_m, c.sound_power(lp, f)` |
| `plant_sound_power` | `function` | **Sound power level of a plant, clause 10 of ISO 8297.**<br>• `levels_db`: SPL [dB], `(positions, bands)`<br>• `frequencies_hz`: octaves 31.5 Hz-8 kHz<br>• `measurement_area_m2`, `contour_length_m`, `microphone_height_m`, `mean_distance_m`, `plant_area_m2`<br>• `background_levels_db` (Table 2, refused below 6 dB)<br>• `directional_microphone_angle_deg` θ, (0°, 90°] (Default: None, omnidirectional)<br>• `temperature_c`, `relative_humidity_percent` (Default: None, Table 3 at 15 °C and 70 %) | `res = emission.plant_sound_power(lp, f, measurement_area_m2=4e4, contour_length_m=800.0, microphone_height_m=10.0, mean_distance_m=25.0, plant_area_m2=1.5e4)`<br><br>• `PlantSoundPowerResult`; `SoundPowerWarning` when 10.2 caps a level |
| `PlantSoundPowerResult` | `dataclass` | **The steps of clause 10, derived from the readings.**<br>• `mean_level_db`, `capped`, `corrected_mean_level_db` (10.1 to 10.3)<br>• `area_term_db`, `near_field_term_db`, `microphone_term_db`, `air_absorption_db_per_m`, `air_absorption_term_db` (10.4 to 10.7)<br>• `sound_power_level_db`, `a_weighted_sound_power_level_db`, `a_weighted_bands_hz` (10.8, 10.9)<br>• `background_margin_db`, `background_correction_db`, `levels_db` (9.5.4)<br>• `distance_ratio`, `uncertainty_db` (Table 1) | `res.sound_power_level_db, res.uncertainty_db` |
| `check_plant_measurement` / `PlantMeasurementCheck` / `PlantRequirement` | `function` / `dataclass` / `dataclass` | **May clause 10 be applied here? ISO 8297 1.2, 6 b), 7.1, 9.1, 9.3, 9.5.1 and 10.2.**<br>• `contour`: a `PlantMeasurementContour`; `sound_power`: its determination (Default: None, the arrangement alone); `measurement_time_s` (Default: None)<br>• `passes` over the requirements that are not advisory; `failures`, `deviations` (advisory rows to report: the height of 9.3, the preferred 10 dB background, 10.2, the approximate 320 m); `requirement(key)`<br>• `PlantRequirement`: `clause`, `value`, `comparison`, `limit`, `unit`, `holds`, `advisory`, `margin`<br>• truth value raises: read `passes` | `chk = emission.check_plant_measurement(c, res)`<br>`chk.passes` |
| `partial_plant_contributions` / `PartialPlantContributions` | `function` / `dataclass` | **Parts of an industrial area measured on their own contours, put together (ISO 8297 0.2 b).**<br>• `parts`: `PlantSoundPowerResult` over the same bands; `names` (Default: Part 1, Part 2, ...)<br>• `total_level_db` (energy sum), `contribution_db`, `a_weighted_part_levels_db`, `a_weighted_total_db`, `a_weighted_contribution_db` | `emission.partial_plant_contributions([a, b]).a_weighted_contribution_db` |
| `plant_characteristic_height_m` | `function` | **Characteristic height H of a plant (ISO 8297 9.2 c), NOTE 7).**<br>• `source_heights_m` h_k [m]<br>• `low_source_count`: sources below 2 m taken at 1 m, 0 or at least 10 (Default: 0) | `H = emission.plant_characteristic_height_m([4.0, 10.0], low_source_count=12)` |
| `plant_microphone_height_m` / `plant_mean_distance_limits_m` / `plant_steady_reading_db` | `function` / `function` / `function` | **The numbers of 9.3, 9.1.1 a) and 9.5.2.**<br>• h = max(H + 0.025 √Sm, 5 m)<br>• (max(0.05 √Sp, 5 m), min(0.5 √Sp, 35 m)): d̄ above the first, at most the second<br>• arithmetic mean of the maximum and minimum of a needle swinging less than 5 dB | `emission.plant_microphone_height_m(8.0, 4e4)` |
| `plant_background_correction_db` / `PLANT_BACKGROUND_CORRECTION_DB` | `function` / `mapping` | **Background correction of ISO 8297 Table 2.**<br>• 1 dB for 6 to 8 dB, 0.5 dB for 9 to 10 dB, 0 above 10 dB; below 6 dB the measurement is invalid (`ValueError`)<br>• between rows: nearest whole decibel, halves up | `emission.plant_background_correction_db(8.2)` |
| `plant_air_absorption_db_per_m` / `PLANT_AIR_ABSORPTION_DB_PER_M` | `function` / `mapping` | **Air absorption α of ISO 8297 10.7 [dB/m].**<br>• no weather: Table 3 as printed (15 °C, 70 %)<br>• `temperature_c`, `relative_humidity_percent`: ISO 3891 Annex A (SAE ARP 866A) at the octave-centre third, through `aircraft.arp866a_attenuation`; 31.5 Hz stays 0 | `emission.plant_air_absorption_db_per_m(f, temperature_c=25.0, relative_humidity_percent=40.0)` |
| `plant_method_uncertainty_db` / `PLANT_METHOD_UNCERTAINTY_DB` | `function` / `mapping` | **Uncertainty of ISO 8297 Table 1, (lower, upper) [dB].**<br>• keyed by d̄/√Sp: 0.05, 0.1, 0.2, 0.5; a ratio between rows takes the row below, the wider interval<br>• outside 0.05 to 0.5: `ValueError` | `emission.plant_method_uncertainty_db(0.24)` |
| `high_frequency_sound_power` | `function` | **Sound power in the 16 kHz octave band, direct method (ISO 9295 Formula (6), clauses 6 and 7).**<br>• `pressure_levels_db`: Lp(ST) [dB], `(bands,)` or `(N, bands)` averaged by Formula (1)<br>• `frequencies_hz` [Hz]: one per band, 11.2-22.4 kHz<br>• `room_constant_m2` R [m²], scalar or per band<br>• `temperature_c` [°C] (Default: 23), `static_pressure_kpa` [kPa] (Default: 101.325): C1 + C2 of ISO 3741 (clause 10.1)<br>• `tonal` (Default: False) | `res = emission.high_frequency_sound_power(lp, frequencies_hz=f, room_constant_m2=r)`<br><br>• `HighFrequencySoundPowerResult` (method='direct') |
| `high_frequency_sound_power_comparison` | `function` | **Sound power in the 16 kHz octave band against a reference sound source (ISO 9295 Formulae (8) and (9)).**<br>• `pressure_levels_db`: Lp(ST) [dB]<br>• `frequencies_hz` [Hz]<br>• `reference_pressure_levels_db`: Lp(FAR) [dB]<br>• `reference_sound_power_levels_db`: LW(FAR) [dB re 1 pW], per band, or per hertz for tones; for broadband noise it may be the `ReferenceSourceCalibration` (ISO 6926)<br>• `noise_bandwidth_hz` ΔF [Hz]: selects Formula (9); ≤ 112 Hz for an FFT<br>• `temperature_c`, `static_pressure_kpa`: C2 of ISO 3741 | `res = emission.high_frequency_sound_power_comparison(lp, frequencies_hz=f, reference_pressure_levels_db=lp_ref, reference_sound_power_levels_db=lw_ref, noise_bandwidth_hz=12.5)` |
| `room_constant_from_reverberation_time` | `function` | **Room constant from the measured reverberation time (ISO 9295 Formulae (4), (5)).**<br>• `reverberation_time_s` T [s], scalar or per band<br>• `volume_m3` V [m³], `surface_area_m2` S [m²] | `r = emission.room_constant_from_reverberation_time([0.70, 0.42, 0.26], volume_m3=200.0, surface_area_m2=210.0)`<br><br>• R per band [m²] |
| `room_absorption_coefficient` | `function` | **Room absorption coefficient from the reverberation time, Eyring (ISO 9295 Formula (5)).**<br>• `reverberation_time_s` T [s]<br>• `volume_m3` V [m³], `surface_area_m2` S [m²]<br>• 1 - exp(-0.16 V/(S T)) | `emission.room_absorption_coefficient(0.42, volume_m3=200.0, surface_area_m2=210.0)` |
| `room_constant_from_air_absorption` | `function` | **Room constant from the calculated air absorption (ISO 9295 Formula (7)).**<br>• `frequencies_hz` [Hz]<br>• `volume_m3` V [m³], `surface_area_m2` S [m²]<br>• `temperature_c` [°C], `relative_humidity_percent` [%] (required), `static_pressure_kpa` [kPa] (Default: 101.325)<br>• 8αV/(1 - 8αV/S); warns below 10 kHz, refuses 8αV/S ≥ 1 | `r = emission.room_constant_from_air_absorption(f, volume_m3=200.0, surface_area_m2=210.0, temperature_c=23.0, relative_humidity_percent=50.0)` |
| `air_absorption_np_per_m` | `function` | **Air absorption coefficient α in nepers per metre (ISO 9295 Annex A).**<br>• `frequencies_hz` [Hz], 50 Hz-22.4 kHz without advisory<br>• `temperature_c` [°C], `relative_humidity_percent` [%] (required), `static_pressure_kpa` [kPa] (Default: 101.325)<br>• ISO 9613-1 without the 8.686 | `emission.air_absorption_np_per_m(16000.0, temperature_c=23.0, relative_humidity_percent=50.0)  # 0.0383 Np/m` |
| `minimum_analyzer_bandwidth_hz` | `function` | **Narrowest analyser bandwidth for a tone under a moving microphone (ISO 9295 Formula (2)).**<br>• `tone_frequency_hz` f [Hz]<br>• `microphone_speed_m_s` v [m/s], `speed_of_sound` c [m/s]<br>• Δf = 2 f v / c | `emission.minimum_analyzer_bandwidth_hz(15625.0, microphone_speed_m_s=0.196, speed_of_sound=345.5)` |
| `tone_level_from_sidebands` | `function` | **Total level of a tone from its sidebands (ISO 9295 Formula (3)).**<br>• `sideband_levels_db` [dB re 20 µPa]<br>• the energy sum | `emission.tone_level_from_sidebands([42.9, 41.3, 38.0])  # 45.9 dB` |
| `free_field_absorption_correction` | `function` | **Air absorption correction K_α = r α of the free-field method (ISO 9295 Formula (10)).**<br>• `frequencies_hz` [Hz]<br>• `radius_m` r [m]: zero at 2 m or less (clause 9.8)<br>• `temperature_c` [°C], `relative_humidity_percent` [%], `static_pressure_kpa` [kPa] (Default: 101.325) | `k = emission.free_field_absorption_correction(f, radius_m=2.5, temperature_c=23.0, relative_humidity_percent=50.0)` |
| `high_frequency_levels_to_determine` | `function` | **The sound power levels to determine for a type of noise (ISO 9295 Table 3).**<br>• `noise_125_hz_to_8_khz`: `'broadband'`, `'narrowband'` or `'none'`<br>• `noise_16_khz_octave`: `'none'`, `'broadband'`, `'discrete_tone'` or `'multiple_tones'`<br>• returns a tuple of `'a_weighted_sound_power_level'`, `'one_third_octave_band_levels'`, `'tone_level_and_frequency'`, `'tone_levels_within_10_db'`<br>• `ValueError` for the two combinations the table has no row for | `emission.high_frequency_levels_to_determine(noise_125_hz_to_8_khz='broadband', noise_16_khz_octave='multiple_tones')` |
| `HighFrequencySoundPowerResult` | `dataclass` | **Sound power in the 16 kHz octave band (ISO 9295).**<br>• `frequencies` [Hz]<br>• `sound_power_level` [dB re 1 pW], at the reference meteorological conditions<br>• `mean_pressure_level` [dB]<br>• `room_constant` [m²] (direct) or `reference_sound_power_level`, `reference_pressure_level` [dB] (comparison)<br>• `noise_bandwidth_hz`, `c1`, `c2` [dB], `method`, `tonal`<br>• `within_10_db_of_maximum`: the tones clause 13 c) reports<br>• `.plot()` | `res.sound_power_level, res.within_10_db_of_maximum`<br>`res.plot()` |
| `TurbineReferenceBox` | `dataclass` | **One reference box of a turbine set (IEC 61063 7.1).**<br>• `length_m` along the shaft, `width_m`, `height_m` above the reflecting plane [m]<br>• `label` (Default: ''): what it encloses | `emission.TurbineReferenceBox(5.0, 5.0, 4.5, 'LP')` |
| `turbine_measurement_surface` | `function` | **Measurement surface of a turbine set and its area S (IEC 61063 7.1, Equation (1)).**<br>• `reference_boxes`: the boxes in order along the shaft<br>• the parallelepipeds stand d = 1 m out: 2 m wider, 1 m taller, 1 m longer at each end of the set<br>• S = 2 hmax bmax + Σ li (2 hi + bi) | `s = emission.turbine_measurement_surface(boxes)`<br><br>• `TurbineMeasurementSurface` |
| `TurbineMeasurementSurface` | `dataclass` | **The measurement surface of a turbine set (IEC 61063 7.1).**<br>• `reference_boxes`, `lengths_m`, `widths_m`, `heights_m` [m]<br>• `area_m2`: S of Equation (1) [m²]<br>• `enveloping_area_m2`: the exact stepped area, equal to S when the sections nest [m²]<br>• `x_edges_m`, `max_height_m`, `max_width_m`, `measurement_distance_m`<br>• `.plot(view='plan' or 'elevation')` | `s.area_m2, s.enveloping_area_m2`<br>`s.plot()` |
| `turbine_microphone_positions` | `function` | **Key and additional microphone positions of Figure 2 (IEC 61063 7.2).**<br>• `surface`: a `TurbineMeasurementSurface`<br>• `microphone_height_m` [m]: the row round the sides, up to the lowest parallelepiped<br>• `spacing_m` [m]: the largest distance between neighbours<br>• `turbine_boxes` (Default: 1): boxes on the turbine side of the coupling plane<br>• `include_overhead` (Default: True): False deletes them (NOTE of 7.2.2)<br>• the side row and the overhead line are divided each on its own<br>• warns `SoundPowerWarning` when a reference box gets no position on its long sides | `a = emission.turbine_microphone_positions(s, microphone_height_m=1.5, spacing_m=2.0, turbine_boxes=2)`<br><br>• `TurbineMicrophoneArray` |
| `TurbineMicrophoneArray` | `dataclass` | **The microphone positions on a turbine measurement surface (IEC 61063 Figure 2).**<br>• `positions_m`: (N, 3) x along the shaft, y across, z up [m]<br>• `labels`: '1' to '5' for the key positions, '' otherwise<br>• `overhead_mask`, `key_mask`, `count`<br>• `positions_per_box`, `every_box_sampled` (7.2.2, per reference box)<br>• `.plot(view='plan' or 'elevation')` | `a.positions_m[a.key_mask]`<br>`a.plot()` |
| `turbine_background_correction` | `function` | **Background correction of IEC 61063 Table 2 (clause 8.1).**<br>• `level_difference_db` [dB]: level operating less background, scalar or per position<br>• the stepped table: 3 dB at 3, 2 dB at 4-5, 1 dB at 6-8, 0.5 dB at 9-10, 0 above 10 dB as measured; from 3 to 10 dB the difference is read in whole decibels<br>• below 3 dB: 3 dB, the result an upper limit (4.2) | `emission.turbine_background_correction([4.0, 12.0])  # [2. 0.]` |
| `turbine_environmental_correction` | `function` | **Environmental correction K of a test room (IEC 61063 Figure A.3, A.3.1).**<br>• `surface_area_m2` S [m²]<br>• `absorption_area_m2` A [m²], or `volume_m3` V [m³] with `reverberation_time_s` T [s]: A = 0.16 V/T<br>• K = 10 lg[1 + 4/(A/S)] | `k = emission.turbine_environmental_correction(s.area_m2, volume_m3=40000.0, reverberation_time_s=2.5)`<br><br>• `TurbineEnvironmentalCorrection` |
| `turbine_reference_source_correction` | `function` | **Environmental correction K = LW - LWr from a reference sound source (IEC 61063 A.3.2).**<br>• `sound_power_levels_db`: the determinations of LW [dB], two up to 10 m of machine, four above<br>• `calibrated_level_db` LWr [dB re 1 pW]<br>• `machine_length_m` [m] | `k = emission.turbine_reference_source_correction([95.4, 96.2], calibrated_level_db=93.0, machine_length_m=8.0)` |
| `TurbineEnvironmentalCorrection` | `dataclass` | **The environmental correction K of a test room (IEC 61063 8.2, Annex A).**<br>• `environmental_correction_db` K [dB]<br>• `method`: 'absorption' or 'reference source'<br>• `surface_area_m2`, `absorption_area_m2` [m²] or `reference_levels_db`, `calibrated_level_db` [dB]<br>• `ratio`: A/S, or None<br>• `.plot()`: Figure A.3 with the room | `k.environmental_correction_db, k.ratio`<br>`k.plot()` |
| `check_turbine_test_environment` | `function` | **Does the test environment qualify for IEC 61063 (A.3.3, 4.3)?**<br>• `correction`: a `TurbineEnvironmentalCorrection` (Default: None)<br>• `environmental_correction_db` K [dB] (Default: None): in its place, 0 outdoors (A.4); give one of the two<br>• `wind_speed_m_s` [m/s] (Default: None, indoors): below 6 m/s, a windscreen above 1 m/s | `c = emission.check_turbine_test_environment(k)`<br><br>• `TurbineTestEnvironmentCheck` |
| `TurbineTestEnvironmentCheck` | `dataclass` | **The qualification of an IEC 61063 test environment.**<br>• `environmental_correction_db`, `ratio`<br>• `correction_ok`: K ≤ 7 dB (A.3.3)<br>• `wind_speed_m_s`, `wind_ok`, `windscreen_advised` (4.3)<br>• `passes`; `bool()` raises<br>• `.plot()`: Figure A.3 with the 7 dB limit<br>• takes `environmental_correction_db`, `ratio`, `wind_speed_m_s`; `correction_ok`, `wind_ok`, `windscreen_advised` are read-only, read from them | `c.passes`<br>`c.plot()` |
| `turbine_sound_power` | `function` | **Surface sound pressure level and sound power level of a turbine set (IEC 61063 8.1 to 8.4, Equations (2), (3)).**<br>• `pressure_levels_db` LpAi [dB], at least 4 positions<br>• `surface_area_m2` S [m²]<br>• `background_levels_db` [dB], or None when not determined (required)<br>• `environmental_correction_db` K [dB] (required)<br>• `overhead_mask` (Default: None)<br>• warns `SoundPowerWarning` on a background within 3 dB or K above 7 dB | `r = emission.turbine_sound_power(lp, surface_area_m2=s.area_m2, background_levels_db=bg, environmental_correction_db=k.environmental_correction_db)`<br><br>• `TurbineSoundPowerResult` |
| `TurbineSoundPowerResult` | `dataclass` | **An IEC 61063 determination.**<br>• `pressure_levels_db`, `background_levels_db`, `background_corrections_db`, `corrected_levels_db` [dB]<br>• `surface_pressure_level_db` [dB re 20 µPa], `sound_power_level_db` [dB re 1 pW]<br>• `reported_sound_power_level_db`: whole decibels (9.4 g)<br>• `upper_limit` (4.2), `conforms`<br>• `arithmetic_mean_db`, `arithmetic_mean_allowed` (NOTE of 8.3)<br>• `overhead_effect_db`, `overhead_may_be_deleted` (NOTE of 7.2.2)<br>• `.plot(position_labels=None)`: the array's labels number the key bars | `r.sound_power_level_db, r.reported_sound_power_level_db`<br>`r.plot(position_labels=a.labels)` |
| `turbine_noise_declaration` | `function` | **The minimum report of IEC 61063 clause 10.**<br>• `determinations`: one `TurbineSoundPowerResult` per operating condition<br>• `turbine`, `noise_control`, `measured_at`: clause 10 a) and f)<br>• `tonal`: selects the Table 1 standard deviation<br>• refuses a determination that is not in full conformity | `d = emission.turbine_noise_declaration({'100 % load': r}, turbine='60 MW set', noise_control='none', measured_at='2026-09-25 10:30', tonal=False)`<br><br>• `TurbineNoiseDeclaration` |
| `TurbineNoiseDeclaration` | `dataclass` | **The report of an IEC 61063 measurement.**<br>• `operating_conditions`, `position_levels_db`, `surface_pressure_levels_db`, `sound_power_levels_db` [dB re 1 pW]<br>• `reported_sound_power_levels_db`: whole decibels (9.4 g)<br>• `statement`: the conformity statement of clause 10<br>• `standard_deviation_db`: Table 1, 5 dB tonal, 4 dB broadband<br>• `loudest_condition` (6.2), found before the rounding<br>• `.plot()` | `d.statement, d.reported_sound_power_levels_db`<br>`d.plot()` |
| `sound_power_intensity` | `function` | **Sound power by intensity scanning (ISO 9614-2).**<br>• `normal_intensity`: (N_seg, N_bands) [W/m²]<br>• `areas`: segment Si [m²]<br>• `normal_intensity_2`: 2nd sweep (criterion 3)<br>• `pressure_levels`: for FpI<br>• `pressure_residual_index`: δpI0 [dB]<br>• `frequencies` [Hz]<br>• `band_type`: 'third' (Default)/'octave'<br>• `grade`: 'engineering'/'survey'<br>• `repeatability_limit`: override s | `ir = emission.sound_power_intensity(scan1, areas, frequencies=f, band_type='octave')`<br><br>• `SoundPowerIntensityResult` |
| `SoundPowerIntensityResult` | `dataclass` | **Scanning sound power.**<br>• `partial_power`, `partial_power_level`<br>• `sound_power` [W], `sound_power_level` [dB] (NaN where `negative_band`)<br>• `negative_band`: per-band bool (True where P ≤ 0)<br>• `surface_pressure_intensity_index` (FpI)<br>• `negative_partial_power_index` (F+/-)<br>• `repeatability`, `dynamic_capability_index` (Ld)<br>• `achieved_grade`, `a_weighting_omitted_bands`<br>• `surface_area`, `sound_power_level_a`, `grade`<br>• takes `frequencies`, `partial_power`, `surface_pressure_intensity_index`, `repeatability`, `pressure_residual_index_db`, `surface_area`, `band_type`, `grade`, `repeatability_limit_db`; `partial_power_level`, `sound_power`, `sound_power_level`, `negative_band`, `negative_partial_power_index`, `dynamic_capability_index`, `achieved_grade`, `a_weighting_omitted_bands`, `sound_power_level_a` are read-only, read from them | `ir.sound_power_level, ir.achieved_grade` |
| `sound_power_intensity_points` | `function` | **Sound power at discrete points (ISO 9614-1).**<br>• `normal_intensity`: (N, N_bands) signed Ini [W/m²]<br>• `areas`: segment Si [m²]<br>• `pressure_levels`: Lpi for F2/F3<br>• `pressure_residual_index`: δpI0 [dB] (criterion 1)<br>• `temporal_intensity`: M short-time samples (F1)<br>• `frequencies` [Hz] (criterion 2, Table B.2)<br>• `band_type`: 'third' (Default)/'octave'<br>• `grade`: 'precision'/'engineering' (Default)/'survey' | `dp = emission.sound_power_intensity_points(i_n, areas, frequencies=f, band_type='octave')`<br><br>• `DiscretePointIntensityResult` |
| `DiscretePointIntensityResult` | `dataclass` | **Discrete-point sound power.**<br>• `partial_power` Pi = Ini·Si (Eq. 11)<br>• `sound_power` [W], `sound_power_level` [dB] (NaN where `not_applicable_band`, clause 9.2)<br>• `f1`…`f4`: Annex A indicators<br>• `dynamic_capability_index` (Ld), `criterion_1`, `negative_power_within_limit`, `criterion_2`, `minimum_positions` (C·F4²)<br>• `achieved_grade` per band ('precision'/'engineering'/'none')<br>• `confidence_interval` (Eq. B.3), `expanded_uncertainty` (2s at the grade achieved, clause 10.6; NaN where none was)<br>• `surface_area`, `positions`, `sound_power_level_a`, `a_weighting_omitted_bands`<br>• `field_nonuniformity_a`, `achieved_grade_a`, `grade`<br>• `.required_actions()` → Table B.3 codes, `.plot()`<br>• takes `frequencies`, `normal_intensity`, `segment_areas_m2`, `f1`, `f2`, `f3`, `f4`, `pressure_residual_index_db`, `band_type`, `grade`; `partial_power`, `sound_power`, `sound_power_level`, `not_applicable_band`, `dynamic_capability_index`, `criterion_1`, ... are read-only, read from them | `dp.achieved_grade, dp.required_actions()` |
| `ActionCode` | `enum` | **ISO 9614-1 Table B.3 corrective actions.**<br>• `.value`: the printed letter `a`…`e`<br>• `.criterion`: the Table B.3 row<br>• `.action`: what to change | `[a.value for a in dp.required_actions()[0]]` |
| `position_count_factor` | `function` | **Criterion-2 factor C (ISO 9614-1 Table B.2).**<br>• `grade`: 'precision'/'engineering'/'survey'<br>• `frequency` [Hz], or `None` for the A-weighted row (grade 3 only)<br>• `band_type`: 'third' (Default)/'octave' | `C = emission.position_count_factor('engineering', 1000.0)`<br><br>• per-band C for grades 1/2; grade 3 raises (A-weighted only) |
| `determination_standard_deviation` | `function` | **Standard deviation s (ISO 9614-1 Table 2).**<br>• `grade`, `frequency` (or `None` for A-weighted), `band_type`<br>• footnote 1: the true LW lies within ±2s at 95 % | `s = emission.determination_standard_deviation('precision', 1000.0)` |
| `error_factor` | `function` | **Error factor Δ (ISO 9614-1 Table B.1).**<br>• `grade`<br>• `a_weighted`: read the A-weighted row (grade 3 only) (Default: False) | `d = emission.error_factor('engineering')`<br><br>• 0.20 / 0.29 / 0.60 |
| `normal_intensity_from_levels` | `function` | **Signed Ini from printed levels (ISO 9614-1 clause 9.1).**<br>• `levels`: XX [dB]<br>• `negative`: the `(-)` of the print, broadcast per position | `i_n = emission.normal_intensity_from_levels(lvl, negative=mask)`<br><br>• Ini = ±I0·10^(XX/10) [W/m²] |
| `partial_power_concentration` | `function` | **Optional procedure of ISO 9614-1 8.3.2/B.1.3.**<br>• `normal_intensity`, `areas`: one band<br>• `grade`: selects Δ (Table B.1) | `c = emission.partial_power_concentration(i_n, areas)`<br><br>• `PartialPowerConcentration` |
| `PartialPowerConcentration` | `dataclass` | **Concentrated positive partial power.**<br>• `positions` N, `subset_positions` Nα, `subset_area` Sα<br>• `power_fraction` α, `subset_nonuniformity` F4(α), `remainder_nonuniformity` F4(1−α)<br>• `error_factor` Δ, `subset_error_factor` Δα<br>• `additional_positions` N* (Eq. B.4) | `c.additional_positions` |
| `absorption_area` | `function` | **Equivalent absorption area (ISO 354 Eq. 5/7).**<br>• `t60`: T [s]<br>• `volume` V [m³]<br>• `temperature_c` [°C] (Default: 20)<br>• `speed_of_sound` [m/s] (overrides temperature)<br>• `m`: air attenuation [1/m] (Default: 0) | `A = materials.absorption_area(t60, volume=200)`<br><br>• A [m²] |
| `absorption_coefficient` | `function` | **Sound absorption coefficient (ISO 354 Eq. 9).**<br>• `t1`, `t2`: empty / with-specimen T [s]<br>• `volume` V [m³]<br>• `sample_area` S [m²]<br>• `temperature1_c`/`temperature2_c` [°C]<br>• `speed_of_sound1`/`2`, `m1`/`m2` | `a = materials.absorption_coefficient(t1, t2, 200, 10.8)`<br><br>• α_s (unclamped, may exceed 1) |
| `attenuation_from_alpha` | `function` | **ISO 9613-1 α → m (ISO 354 8.1.2.1).**<br>• `alpha`: attenuation [dB/m] | `m = materials.attenuation_from_alpha(0.01)`<br><br>• m = α/(10 lg e) [1/m] |
| `measure_sound_absorption` | `function` | **Reverberation-room absorption measurement (ISO 354 Eq. 5/7/8/9).**<br>• `frequencies` [Hz], `t_empty` T1 [s], `t_specimen` T2 [s]<br>• `volume` V [m³], `area` S [m²]<br>• `temperature_c` [°C] (Default: 20), `relative_humidity_percent` [%]<br>• `speed_of_sound` [m/s], `m` [1/m] (Default: 0) | `r = materials.measure_sound_absorption(f, t1, t2, volume=200, area=10.8)`<br><br>• `SoundAbsorptionMeasurement` |
| `SoundAbsorptionMeasurement` | `dataclass` | **Reverberation-room sound absorption (ISO 354).**<br>• `frequencies` [Hz], `t_empty`/`t_specimen` [s]<br>• `volume`, `area`, `temperature_c`, `relative_humidity_percent`, `speed_of_sound`<br>• `air_attenuation` m [1/m]<br>• `absorption_area_empty` A1, `absorption_area_with_specimen` A2 [m²]<br>• `alpha_s` (unclamped)<br>• `.equivalent_absorption_area` AT = A2−A1<br>• `.plot()` / `.report()` | `r.alpha_s, r.equivalent_absorption_area` |
| `air_attenuation` | `function` | **Atmospheric attenuation coefficient α (ISO 9613-1 Eq. 5).**<br>• `frequencies` [Hz]<br>• `temperature_c` [°C] (Default: 20)<br>• `relative_humidity_percent` [%] (Default: 50)<br>• `atmospheric_pressure_kpa` [kPa] (Default: 101.325)<br>• `exact_midband`: snap to Table 1 midbands (Default: False) | `a = environment.air_attenuation([1000, 4000], 20, 50)`<br><br>• α [dB/m] (×1000 = dB/km); out-of-range warns |
| `air_attenuation_m` | `function` | **ISO 354 power attenuation m from conditions (ISO 9613-1 + ISO 354).**<br>• Same parameters as `air_attenuation` | `m = environment.air_attenuation_m([1000, 4000], 20, 50)`<br><br>• m = α/(10 lg e) [1/m] |
| `AtmosphericAbsorptionWarning` | `warning class` | **ISO 9613-1 out-of-range advisory.**<br>Emitted by `air_attenuation` when temperature/humidity/frequency leave the tabulated ranges or pressure exceeds 200 kPa, and by `emission.air_absorption_np_per_m` (so also by `emission.room_constant_from_air_absorption` and `emission.free_field_absorption_correction`) outside 50 Hz to 22.4 kHz, the ISO 9613-1 range as ISO 9295 Annex A extends it, or outside its temperature and humidity ranges; the result still returns | `warnings.simplefilter('error', AtmosphericAbsorptionWarning)` |
| `atmospheric_attenuation` | `function` | **Plottable ISO 9613-1 attenuation-coefficient curve.**<br>• Same parameters as `air_attenuation`<br>• `distance` d [m] (optional; enables total attenuation) | `res = environment.atmospheric_attenuation([1000, 4000], 20, 50)`<br><br>• `AtmosphericAttenuation`; `res.plot()` |
| `AtmosphericAttenuation` | `dataclass` | **Atmospheric attenuation result (ISO 9613-1).**<br>• `frequencies` [Hz]<br>• `attenuation_coefficient` α [dB/m]<br>• `temperature_c`, `relative_humidity_percent`, `atmospheric_pressure_kpa`<br>• `distance` [m] or `None`<br>• `.total_attenuation` A = α·d [dB] (ISO 9613-2 Aatm) or `None`<br>• `.plot()`: α (dB/km) vs frequency | `res.attenuation_coefficient, res.total_attenuation` |
| `geometric_divergence` | `function` | **Geometrical divergence Adiv (ISO 9613-2 Eq. 7).**<br>• `distance` d [m] | `a = environment.geometric_divergence(100.0)`<br><br>• 20 lg(d/d₀) + 11 = 51 dB at 100 m |
| `atmospheric_absorption` | `function` | **Atmospheric absorption term Aatm (ISO 9613-2 Eq. 8)**, α at the exact base-10 midbands (the Table 2 convention).<br>• `distance` d [m]<br>• `frequencies` [Hz] (snapped to exact midbands)<br>• `temperature_c`/`relative_humidity_percent`/`atmospheric_pressure_kpa` | `aatm = environment.atmospheric_absorption(200, bands)`<br><br>• α·d per band [dB] |
| `ground_attenuation` | `function` | **Ground effect Agr, general method (ISO 9613-2 7.3.1, Eq. 9).**<br>• `distance` d, `source_height` hs, `receiver_height` hr [m]<br>• `frequencies` [Hz]<br>• `ground_source`/`ground_middle`/`ground_receiver` G ∈ [0,1]<br>• `projected_distance` dp [m] | `agr = environment.ground_attenuation(200, 2, 2, bands, 1, 1, 1)`<br><br>• As+Ar+Am per band [dB] (negative = gain) |
| `ground_attenuation_alternative` | `function` | **Ground effect Agr, A-weighted method (ISO 9613-2 7.3.2, Eq. 10).**<br>• `distance` d [m]<br>• `mean_height` hm [m] | `agr = environment.ground_attenuation_alternative(200, 2)`<br><br>• 4.8 − (2hm/d)·(17+300/d) ≥ 0 [dB] |
| `directivity_omega` | `function` | **Solid-angle directivity index DΩ (ISO 9613-2 Eq. 11).**<br>• `source_height` hs, `receiver_height` hr, `projected_distance` dp [m] | `dw = environment.directivity_omega(1.5, 1.5, 200)`<br><br>• 0…~3 dB (add to Dc for the 7.3.2 method) |
| `region_ground_factors` | `function` | **Ground factors of the three regions of a path over mixed ground (ISO/TR 17534-3 6.2.5).**<br>• `segment_lengths` [m], `segment_ground_factors` G, in order from the source<br>• `source_height` hs, `receiver_height` hr [m] | `g = environment.region_ground_factors([40.9, 102.2, 51.1], [0.9, 0.5, 0.2], 1, 4)`<br><br>• `GroundFactors` (Gs, Gm, Gr), each a length-weighted mean over its region |
| `mean_path_height` | `function` | **Mean path height hm above a ground profile (ISO 9613-2 Figure 3).**<br>• `profile_distances` [m], strictly increasing, `profile_heights` [m]<br>• `source_height` hs, `receiver_height` hr [m]<br>• `distance` d [m] (Default: the slant distance the profile implies) | `hm = environment.mean_path_height([0, 112.4, 178.8, 194.2], [0, 0, 10, 10], 1, 4)`<br><br>• hm = F/d [m], for the 7.3.2 method |
| `Barrier` | `dataclass` | **Barrier diffraction geometry (ISO 9613-2 7.4).**<br>• `source_to_edge` dss, `edge_to_receiver` dsr [m]<br>• `parallel_distance` a [m] (Default: 0)<br>• `edge_separation` e [m] (Default: None → single diffraction)<br>• `ground_reflections_by_image` (Default: False → C₂=20)<br>• `lateral` (Default: False → top-edge)<br>• `line_of_sight_clear` (Default: False; True gives z the negative sign of Eq. 16 when the sight line passes above the edge) | `b = environment.Barrier(source_to_edge=101, edge_to_receiver=101)`<br><br>• `.is_double` when e is given |
| `barrier_attenuation` | `function` | **Barrier diffraction Dz (ISO 9613-2 Eq. 14).**<br>• `barrier`: `Barrier`<br>• `distance` d [m]<br>• `frequencies` [Hz] | `dz = environment.barrier_attenuation(b, 200, bands)`<br><br>• 10 lg[3+(C₂/λ)C₃ z Kmet], capped 20/25 dB; 10 lg 3 at grazing (z = 0), decaying to ≥ 0 for negative z |
| `measured_insertion_loss_direct` / `measured_insertion_loss_indirect` / `MeasuredBarrierInsertionLoss` | `function` / `function` / `dataclass` | **What a barrier is worth once it is built, ISO 10847 8.2.1 and 8.2.2.**<br>• direct: D_IL = (L_ref,A − L_ref,B) − (L_r,A − L_r,B), the reference microphone normalising whatever the source did differently between campaigns<br>• indirect: the "before" pair comes from an equivalent site, which makes it an estimate, and each campaign carries its receiver correction C_r<br>• `receiver_type_before` / `receiver_type_after`: 'hemi_free_field' (Default, 0 dB) or 'reflecting_surface' (6 dB)<br>• result: `insertion_loss_db`, `method`, the four spectra and the two corrections, `.plot()` | `environment.measured_insertion_loss_direct(ref_b, ref_a, rec_b, rec_a, frequencies=f)` |
| `barrier_background_correction_db` / `ISO10847_BACKGROUND_CORRECTIONS_DB` / `ISO10847_MINIMUM_BACKGROUND_MARGIN_DB` / `ISO10847_PREFERRED_BACKGROUND_MARGIN_DB` | `function` / `mapping` / `constant` | **Table 3 of ISO 10847, in decibels to add.**<br>• 2 dB comes off at a margin of 4 or 5 dB, 1 dB from 6 to 9 dB, nothing from 10 dB up, which is the margin 6.4 asks for in the first place<br>• the column reads "correction to be made to", so the values are negative and are added, where ISO 11820 prints the same physical thing positive and subtracts it<br>• under 4 dB the results "are not valid", which is a refusal | `environment.barrier_background_correction_db([5.0, 7.0])  # -2.0, -1.0` |
| `wind_class` / `WIND_CLASSES` / `MAXIMUM_WIND_SPEED_M_S` / `WIND_VECTOR_TOLERANCE_M_S` / `TEMPERATURE_TOLERANCE_C` / `CLOUD_COVER_CLASSES` | `function` / `mapping` / `constant` | **The weather the two campaigns have to share, ISO 10847 Table 1 and 6.2.**<br>• the vector component of the wind on the source-to-receiver line: positive downwind, negative upwind<br>• downwind 1 m/s to 5 m/s and calm ± 1 m/s over any distance; the upwind class exists over short distances alone<br>• past 5 m/s no measurement is made, which is a refusal rather than a class<br>• the two campaigns must agree within 2 m/s on the component and 10 °C on the temperature, and the cloud cover is recorded in the four classes of Table 2 | `environment.wind_class(2.5)  # 'downwind'` |
| `is_short_distance` / `SHORT_DISTANCE_RATIO` / `LONG_DISTANCE_M` / `CLOSE_SOURCE_DISTANCE_M` / `POINT_SOURCE_DIVERGENCE_DB` / `LINE_SOURCE_DIVERGENCE_DB` | `function` / `constant` | **Short distance or long? ISO 10847 6.3.1, and what hangs on it.**<br>• (H_s + H_R)/(d₁ + d₂) > 0,1 for the "before" campaign, and both of (H_s + H)/d₁ and (H + H_R)/d₂ > 0,1 for the "after" one<br>• the inequalities are strict, so exactly 0,1 is not a short distance<br>• only a short distance may be measured into the wind; beyond 250 m the standard stops claiming the method at all<br>• 6 dB per doubling for a point source and 3 dB for a line one, the divergence the geometry is read against | `environment.is_short_distance(source_height_m=1.0, receiver_height_m=1.5, barrier_height_m=4.0, source_to_barrier_m=10.0, barrier_to_receiver_m=20.0)` |
| `reference_microphone_height_m` / `REFERENCE_MICROPHONE_CLEARANCE_M` / `REFERENCE_ELEVATION_INCREMENT_DEG` / `MINIMUM_RECEIVER_HEIGHT_M` / `MINIMUM_REPETITIONS` | `function` / `constant` | **Where the two microphones stand, ISO 10847 7.2.2 and 7.3.**<br>• the reference microphone at least 1,5 m above the top edge of the barrier, measured from its highest point where the top is not a straight edge<br>• for a source region nearer than 15 m the NOTE raises it further, until the elevation angle exceeds the angle to the top by 10°; the NOTE never lowers it, so this returns the higher of H + 1,5 m and d tan(arctan(H/d) + 10°)<br>• where the top already stands 80° or more above the source region no height reaches the 10°: the clearance is returned and a `BarrierInSituWarning` emitted<br>• a receiver stands at 1,2 m or higher, and the measurement is repeated at least three times | `environment.reference_microphone_height_m(4.0, source_to_barrier_m=8.0)` |
| `hemi_free_field_distance_m` / `HEMI_FREE_FIELD_DISTANCE_M` / `HEMI_FREE_FIELD_DISTANCE_FACTOR` / `RECEIVER_CORRECTIONS_DB` / `EQUIVALENT_SURROUNDINGS_RADIUS_M` / `EQUIVALENT_SECTOR_DEG` | `function` / `constant` / `mapping` | **What makes a receiver position a free field, and a site an equivalent one, ISO 10847 8.1.2 and 6.1.**<br>• `min(30 m, 2 d)` to any vertical reflecting surface, so a receiver close behind the barrier needs less clearance rather than more, the two rules crossing at 15 m<br>• a microphone against a facade instead carries the 6 dB of `RECEIVER_CORRECTIONS_DB`<br>• an equivalent site matches over 30 m around the receiver and over a 60° sector towards the source | `environment.hemi_free_field_distance_m(10.0)  # 20.0` |
| `ISO10847_OCTAVE_BAND_RANGE_HZ` / `ISO10847_OCTAVE_BAND_EXTENDED_RANGE_HZ` / `ISO10847_THIRD_OCTAVE_BAND_RANGE_HZ` / `ISO10847_THIRD_OCTAVE_BAND_EXTENDED_RANGE_HZ` | `constant` | **The bands ISO 10847 measures in, clause 5.**<br>• 63 Hz to 4 kHz in octaves and 50 Hz to 5 kHz in one-third octaves<br>• the extended ranges reach 8 kHz and 10 kHz where the source or the barrier asks for them | `environment.ISO10847_OCTAVE_BAND_RANGE_HZ  # (63.0, 4000.0)` |
| `BarrierInSituWarning` | `warning class` | **The measurement is outside a condition ISO 10847 states.**<br>• a distance past 250 m, a reference microphone with less clearance than 7.2.2 asks for, a receiver lower than 1,2 m, campaigns whose weather does not match | `warnings.catch_warnings()`<br>Emitted by `environment.propagation.barrier_in_situ` |
| `meteorological_correction` | `function` | **Meteorological correction Cmet (ISO 9613-2 Eq. 21/22).**<br>• `projected_distance` dp, `source_height` hs, `receiver_height` hr [m]<br>• `c0`: factor C₀ [dB] | `c = environment.meteorological_correction(200, 1.5, 1.5, 2.0)`<br><br>• C₀[1 − 10(hs+hr)/dp] ≥ 0 [dB] |
| `outdoor_propagation_attenuation` | `function` | **Total octave-band attenuation A (ISO 9613-2 Eq. 4).**<br>• `distance` d, `source_height` hs, `receiver_height` hr [m]<br>• `frequencies` [Hz]<br>• `ground_source`/`ground_middle`/`ground_receiver` G<br>• `barrier`: `Barrier` or None<br>• `temperature_c`/`relative_humidity_percent`/`atmospheric_pressure_kpa` (Default: 20 °C/70 %/101.325 kPa, a Table 2 reference atmosphere)<br>• `projected_distance` dp [m] | `att = environment.outdoor_propagation_attenuation(200, 2, 2, bands, 1, 1, 1)`<br><br>• `OutdoorAttenuation` term breakdown |
| `predicted_receiver_level` | `function` | **Predicted octave-band receiver level (ISO 9613-2 Eq. 3/6).**<br>• `sound_power_level` Lw [dB]<br>• `geometry`: `PropagationGeometry`<br>• `frequencies` [Hz]<br>• `ground`: `GroundFactors`, `barrier`: `Barrier`, `atmosphere`: `AtmosphericConditions`<br>• `directivity`: `DirectivityCorrection`<br>• `c0`: subtract Cmet (Default: None) | `lp = environment.predicted_receiver_level(lw, environment.PropagationGeometry(200, 2, 2), frequencies=bands)`<br><br>• LfT(DW) = Lw + Dc − A per band [dB] |
| `OutdoorAttenuation` | `dataclass` | **Per-band ISO 9613-2 attenuation breakdown.**<br>• `frequencies` [Hz]<br>• `a_div`, `a_atm`, `a_gr`, `a_bar` [dB]<br>• `a_total` = Adiv+Aatm+Agr+Abar [dB]<br>• `d_omega` [dB]<br>• `.report()` one-page ISO 9613-2 prediction fiche (pass a `SourceEmission` for the A-weighted receiver level) | `att.a_div, att.a_bar, att.a_total` |
| `SourceEmission` | `dataclass` | **Source emission for the receiver-level fiche (ISO 9613-2 Eq. 3), report-time only.**<br>• `sound_power_level` Lw [dB]<br>• `directivity_index` Di [dB] (Default: 0)<br>• `d_omega` DΩ [dB] (Default: 0)<br>• `cmet` Cmet [dB] (Default: None) | `att.report("f.pdf", source_emission=environment.SourceEmission(lw))` |
| `PropagationGeometry` | `dataclass` | **Source-to-receiver geometry of the ISO 9613-2 path.**<br>• `distance` d [m]<br>• `source_height` hs, `receiver_height` hr [m]<br>• `projected_distance` dp [m] (Default: None → √(d²−(hs−hr)²)) | `PropagationGeometry(200.0, 1.5, 1.5)` |
| `GroundFactors` | `dataclass` | **Ground factors G of the three regions (ISO 9613-2 7.3.1).**<br>• `source` Gs, `middle` Gm, `receiver` Gr ∈ [0,1] (Default: 0, hard ground) | `GroundFactors(1.0, 1.0, 1.0)  # porous` |
| `AtmosphericConditions` | `dataclass` | **Air state behind Aatm (ISO 9613-2 Eq. 8).**<br>• `temperature_c` [°C] (Default: 20)<br>• `relative_humidity_percent` [%] (Default: None → 70)<br>• `atmospheric_pressure_kpa` [kPa] (Default: 101.325) | `AtmosphericConditions(temperature_c=15.0)` |
| `DirectivityCorrection` | `dataclass` | **Directivity correction Dc = Di + DΩ (ISO 9613-2 Eq. 3).**<br>• `index` Di [dB] (Default: 0)<br>• `d_omega` DΩ [dB] (Default: 0) | `DirectivityCorrection(index=3.0)` |
| `DEFAULT_FREQUENCIES` | `tuple` | **ISO 9613-2 nominal octave bands.**<br>(no parameters) | `DEFAULT_FREQUENCIES  # (63, …, 8000)` |
| `verify_calculation_results` / `CalculationVerification` / `CERTIFIED_RESULT_TOLERANCE_DB` | `function` / `dataclass` / `constant` | **Is a program's result inside the limits of every certified result? The TRC form of ISO 17534-1 (clause 7.1, Tables B.1 and B.2).**<br>• `results_db`, `lower_limits_db`, `upper_limits_db` [dB], one per row (a band or a total of a test case)<br>• `labels`: a name per row (Default: "1", "2", …)<br>• a limit is included: a deviation that reaches the tolerance does not exceed it<br>• `CERTIFIED_RESULT_TOLERANCE_DB`: 0.05 dB round a result given to two decimals (Table A.5, note a)<br>• result: `inside` per row, `passes`, `failing_labels`, `deviations_db`, `margins_db`, `.plot()`; `bool()` raises | `v = environment.verify_calculation_results(r, lo, up, labels=bands)`<br>`v.passes` |
| `ranking_positions` / `RANKING_POSITIONS` / `MINIMUM_SAMPLE_SIZE` | `function` / `mapping` / `constant` | **Ranking positions of the 0,1- and 0,9-quantiles of a sorted sample (ISO 17534-1 C.4).**<br>• `sample_size` N, at least 20 (C.2)<br>• Table C.1 from 20 to 50 values, symmetric: R(q0,9) = N + 1 − R(q0,1)<br>• above 50, Formulas (C.1) IP((N + 4)/10) and (C.2) IP(9N/10) + 1, which give one rank less than the symmetric rule when N ends in 1 to 5; the seam at 50 comes from DIN 45687 and is kept as printed | `environment.ranking_positions(25)  # (2, 24)`<br>`environment.ranking_positions(51)  # (5, 46)` |
| `level_difference_quantiles` / `LevelDifferenceQuantiles` | `function` / `dataclass` | **The characteristic values q0,1 and q0,9 of a sample of level differences (ISO 17534-1 C.4 and C.5).**<br>• `level_differences_db` [dB], at least 20, in any order; for a modified configuration, its levels minus the reference configuration's (5.2.3, 7.2)<br>• result: `sorted_differences_db`, `rank_q01`, `rank_q09`, `q01_db`, `q09_db`, `from_table`, and the `mean_db` and `standard_deviation_db` of C.5 (N − 1 degrees of freedom), `.plot()` | `q = environment.level_difference_quantiles(d)`<br>`q.q01_db, q.q09_db  # (-1.0, 3.0) for the C.4 example` |
| `uniform_sample_indices` / `contour_sample_chainages_m` / `SAMPLE_CLEARANCE_M` / `RECOMMENDED_SAMPLE_RATIO` / `SoftwareQualityWarning` | `function` / `constant` / `warning class` | **Where the sample of ISO 17534-1 Annex C is taken (C.2, C.3).**<br>• `uniform_sample_indices(point_count, sample_size, horizontal_clearances_m=None)`: the ordinals IP((i − 0,5) N/M), counted from zero, of the points left once those under 2 m from a source or obstacle are dropped<br>• `SoftwareQualityWarning` when fewer than one point in a hundred is sampled (C.2 recommends 1:100)<br>• `contour_sample_chainages_m(total_length_m, sample_size)`: IP((i − 0,5) L/M) along the sound contours, in whole metres | `environment.uniform_sample_indices(2000, 20)`<br>`environment.contour_sample_chainages_m(1000.0, 20)` |
| `round_robin_precision` / `RoundRobinPrecision` | `function` / `dataclass` | **The precision of a method across programs, from a round robin (ISO 17534-1 4.5.2 and A.3).**<br>• `levels_db`: (N receivers, M participants) [dB], N ≥ 20, M ≥ 2<br>• result: `mean_levels_db` (arithmetic), `deviations_db` dL(n,m), `max_abs_deviations_db` \|dL(n)\|max, `rank_q09`, `q09_db` (the result of the round robin), `.plot()` (Figure A.3) | `environment.round_robin_precision(levels).q09_db` |
| `railway_source_power` | `function` | **CNOSSOS-EU railway source line power at the two source heights (Directive 2002/49/EC Annex II, 2.3.1).**<br>• `traffic`: one `RailwayVehicle` or a sequence<br>• `track`: the `RailwayTrack` of the section<br>• `psi`/`phi` [deg]: receiver angles (Default: 0 / 90, broadside)<br>• `reference_time` Tref (Default: 12)<br>• `minimum_speed` [km/h] (Default: 50, or 30 for a tram; 0 switches the floor off)<br>• `interpolation` (`RoughnessInterpolation`), `directivity_edition` (`DirectivityEdition`) | `res = environment.railway_source_power(environment.RailwayVehicle(stock, 96.0, 160.0), track)`<br><br>• `RailwayEmissionResult` |
| `RailwayEmissionResult` | `dataclass` | **CNOSSOS-EU railway source-line power per metre.**<br>• `third_octave_frequencies` (50…10000 Hz), `frequencies` (63…8000 Hz)<br>• `heights` (0.5, 4.0) m<br>• `third_octave_line_power` (2, 24), `line_power` (2, 8) [dB re 1 pW/m]<br>• `total_line_power` (8,)<br>• `components`: rolling / traction / aerodynamic / bridge, per height<br>• `.plot()` | `res.total_line_power, res.components["rolling"]` |
| `RailwayVehicle` | `dataclass` | **One vehicle of the traffic on a track section.**<br>• `stock`: `RollingStock`<br>• `flow_rate` Q [veh/h], `speed` v [km/h]<br>• `condition`: `RunningCondition`<br>• `idling_time` Tidle | `RailwayVehicle(stock, flow_rate=96.0, speed=160.0)` |
| `RollingStock` | `dataclass` | **Appendix G data of one vehicle type.**<br>• `axles` Na<br>• `wheel_roughness`, `contact_filter`: (wavelengths [mm], levels [dB])<br>• `wheel_transfer`, `superstructure_transfer`: 24 bands [dB/axle]<br>• `traction`, `aerodynamic`: (source A, source B)<br>• `aerodynamic_alpha` (Default: 50)<br>• `tram` (Default: False) | `RollingStock(axles=4, wheel_roughness=..., ...)` |
| `RailwayTrack` | `dataclass` | **Appendix G data of one track section.**<br>• `rail_roughness`, `impact_roughness`: (wavelengths [mm], levels [dB])<br>• `track_transfer`, `bridge_transfer`: 24 bands [dB/axle]<br>• `joint_density` nl [1/m] (Default: 0.01)<br>• `squeal_excess` [dB], `length` L [m] (Default: 100) | `RailwayTrack(rail_roughness=..., track_transfer=...)` |
| `roughness_to_frequency` | `function` | **Resample a roughness spectrum from wavelength onto frequency, λ = v/f with v in m/s (Annex II 2.3.2 as corrected in 2018).**<br>• `levels` [dB], `wavelengths` [mm], `speed` [km/h]<br>• `frequencies` [Hz], `interpolation` | `lr = environment.roughness_to_frequency(levels, lam, 160.0)` |
| `total_effective_roughness` | `function` | **Total effective roughness LR,TOT (Annex II 2.3.7).**<br>• `rail`, `wheel`, `filter_`: 24 bands [dB] | `ltot = environment.total_effective_roughness(rail, wheel, a3)`<br><br>• 10 lg(10^(LrTR/10)+10^(LrVEH/10)) + A3 |
| `impact_roughness` | `function` | **Impact roughness at a joint density (Annex II 2.3.12).**<br>• `single`: Table G-4 on the frequency grid [dB]<br>• `joint_density` nl [1/m] | `li = environment.impact_roughness(single, 0.03)`<br><br>• + 10 lg(nl/0.01) |
| `rolling_sound_power` | `function` | **One rolling-noise component (Annex II 2.3.8 to 2.3.10).**<br>• `roughness` LR,TOT, `transfer` LH [dB]<br>• `axles` Na | `lw = environment.rolling_sound_power(ltot, environment.track_transfer("M/M"), 4)`<br><br>• LR,TOT + LH + 10 lg(Na) |
| `curve_squeal_excess` | `function` | **Curve-squeal excess added to rolling noise (as replaced by (EU) 2021/1226 pt (4)(b)).**<br>• `radius` R [m]<br>• `tram`, `turnout` (Default: False)<br>• `track_length` ltrack [m] (Default: 50) | `curve_squeal_excess(280.0)  # 8.0 dB` |
| `horizontal_directivity` | `function` | **Horizontal dipole directivity (Annex II 2.3.15).**<br>• `phi` [deg]<br>• `frequencies` [Hz] | `horizontal_directivity(90.0)  # 0 dB broadside` |
| `vertical_directivity` | `function` | **Vertical directivity of source A or B (Annex II 2.3.16/2.3.17).**<br>• `psi` [deg], `frequencies` [Hz]<br>• `height` 1 or 2<br>• `aerodynamic` (height 2 only)<br>• `edition`: `DirectivityEdition` | `vertical_directivity(30.0)` |
| `aerodynamic_sound_power` | `function` | **Aerodynamic sound power at a speed (Annex II 2.3.13/2.3.14 with Table G-6).**<br>• `speed` v [km/h] (Default: 300)<br>• `reference`: (source A, source B) at v0<br>• `alpha` (Default: 50) | `low, high = environment.aerodynamic_sound_power(320.0)` |
| `octave_bands_from_third_octaves` | `function` | **Energy-sum 24 1/3-octave levels into the 8 octave bands (Annex II 2.3.2).**<br>• `levels` [dB] | `octave_bands_from_third_octaves(res.third_octave_line_power[0])` |
| `wheel_roughness` | `function` | **Wheel roughness Lr,VEH of Table G-1a.**<br>• `brake`: `BrakeType` | `lam, lr = environment.wheel_roughness(BrakeType.NON_TREAD)` |
| `rail_roughness` | `function` | **Rail roughness Lr,TR of Table G-1b (as replaced by (EU) 2021/1226).**<br>• `roughness`: `RailRoughnessClass` (only E and M are tabulated) | `lam, lr = environment.rail_roughness(RailRoughnessClass.NORMAL)` |
| `contact_filter` | `function` | **Contact filter A3 of Table G-2 (as replaced by (EU) 2021/1226).**<br>• `filter_`: `ContactFilter` or (wheel load [kN], wheel diameter [mm]) | `lam, a3 = environment.contact_filter(ContactFilter.LOAD_50_DIAMETER_920)` |
| `track_transfer` | `function` | **Track transfer function LH,TR of Table G-3a (as replaced by (EU) 2021/1226).**<br>• `track`: `TrackTransferClass` or its column code | `track_transfer("M/M")  # 24 bands [dB/axle]` |
| `wheel_transfer` | `function` | **Wheel transfer function LH,VEH of Table G-3b.**<br>• `diameter_mm`: `WheelDiameter` or the diameter_mm [mm] | `wheel_transfer(920.0)` |
| `superstructure_transfer` | `function` | **Superstructure transfer LH,VEH,SUP of Table G-3c (freight only; 0,0 dB everywhere).**<br>(no parameters) | `superstructure_transfer()` |
| `impact_roughness_single` | `function` | **Single-impact roughness of Table G-4 (as replaced by (EU) 2021/1226), for nl = 0,01 per m.**<br>(no parameters) | `lam, li = environment.impact_roughness_single()` |
| `traction_sound_power` | `function` | **Traction sound power of Table G-5; constant speed and idling are equal.**<br>• `vehicle`: `TractionVehicle` | `low, high = environment.traction_sound_power(TractionVehicle.ELECTRIC_LOCO)` |
| `bridge_transfer` | `function` | **Bridge transfer function LH,bridge of Table G-7 (as replaced by (EU) 2021/1226).**<br>• `bridge`: `BridgeType` | `bridge_transfer(BridgeType.PLUS_10_DBA)` |
| `VehicleDescriptor` | `dataclass` | **Four-digit vehicle descriptor of Table [2.3.a].**<br>• `vehicle_type`, `axles`, `brake`, `measure`<br>• `.from_code()`, `.code` | `VehicleDescriptor.from_code("a4cn")` |
| `TrackDescriptor` | `dataclass` | **Six-digit track descriptor of Table [2.3.b].**<br>• `base`, `roughness`, `pad`, `measure`, `joints`, `curvature`<br>• `.from_code()`, `.code` | `TrackDescriptor.from_code("BMSNNH")` |
| `VehicleType` | `enum` | **Digit 1 of the vehicle descriptor.**<br>`HIGH_SPEED` (h), `SELF_PROPELLED` (m), `HAULED` (p), `CITY_TRAM` (c), `DIESEL_LOCO` (d), `ELECTRIC_LOCO` (e), `FREIGHT` (a), `OTHER` (o) | `VehicleType.FREIGHT` |
| `BrakeType` | `enum` | **Digit 3 of the vehicle descriptor.**<br>`CAST_IRON` (c), `COMPOSITE` (k), `NON_TREAD` (n) | `BrakeType.CAST_IRON` |
| `WheelMeasure` | `enum` | **Digit 4 of the vehicle descriptor.**<br>`NONE` (n), `DAMPERS` (d), `SCREENS` (s), `OTHER` (o) | `WheelMeasure.DAMPERS` |
| `TrackBase` | `enum` | **Digit 1 of the track descriptor.**<br>`BALLAST` (B), `SLAB` (S), `BALLASTED_BRIDGE` (L), `NON_BALLASTED_BRIDGE` (N), `EMBEDDED` (T), `OTHER` (O) | `TrackBase.BALLAST` |
| `RailRoughnessClass` | `enum` | **Digit 2 of the track descriptor.**<br>`WELL_MAINTAINED` (E), `NORMAL` (M), `NOT_WELL_MAINTAINED` (N), `BAD` (B) | `RailRoughnessClass.NORMAL` |
| `RailPad` | `enum` | **Digit 3 of the track descriptor, the rail-pad dynamic stiffness.**<br>`SOFT` (S, 150-250 MN/m), `MEDIUM` (M, 250-800 MN/m), `HARD` (H, 800-1 000 MN/m) | `RailPad.MEDIUM` |
| `TrackMeasure` | `enum` | **Digit 4 of the track descriptor.**<br>`NONE` (N), `RAIL_DAMPER` (D), `LOW_BARRIER` (B), `ABSORBER_PLATE` (A), `EMBEDDED_RAIL` (E), `OTHER` (O) | `TrackMeasure.RAIL_DAMPER` |
| `RailJoints` | `enum` | **Digit 5 of the track descriptor.**<br>`NONE` (N), `SINGLE` (S), `TWO` (D), `MORE` (M) | `RailJoints.SINGLE` |
| `TrackCurvature` | `enum` | **Digit 6 of the track descriptor.**<br>`STRAIGHT` (N), `LOW` (L), `MEDIUM` (M), `HIGH` (H) | `TrackCurvature.HIGH` |
| `TrackTransferClass` | `enum` | **Columns of Table G-3a (track base / rail pad).**<br>`MONOBLOCK_SOFT`, `MONOBLOCK_MEDIUM`, `MONOBLOCK_HARD`, `BIBLOCK_SOFT`, `BIBLOCK_MEDIUM`, `BIBLOCK_HARD`, `WOODEN`, `DIRECT_FASTENING` | `TrackTransferClass.WOODEN` |
| `WheelDiameter` | `enum` | **Columns of Table G-3b, the wheel diameter [mm].**<br>`MM_920`, `MM_840`, `MM_680`, `MM_1200` | `WheelDiameter.MM_920` |
| `ContactFilter` | `enum` | **Columns of Table G-2, (wheel load [kN], wheel diameter [mm]).**<br>`LOAD_50_DIAMETER_360`, `LOAD_50_DIAMETER_680`, `LOAD_50_DIAMETER_920`, `LOAD_25_DIAMETER_920`, `LOAD_100_DIAMETER_920` | `ContactFilter.LOAD_25_DIAMETER_920` |
| `TractionVehicle` | `enum` | **Columns of Table G-5.**<br>`DIESEL_LOCO_800`, `DIESEL_LOCO_2200`, `DIESEL_MULTIPLE_UNIT`, `ELECTRIC_LOCO`, `ELECTRIC_MULTIPLE_UNIT` | `TractionVehicle.DIESEL_LOCO_2200` |
| `BridgeType` | `enum` | **Columns of Table G-7, labelled by the A-weighted bridge excess.**<br>`PLUS_10_DBA`, `PLUS_15_DBA` | `BridgeType.PLUS_15_DBA` |
| `RunningCondition` | `enum` | **Running condition c of Annex II 2.3.2.**<br>`CONSTANT` (1), `IDLING` (2) | `RunningCondition.IDLING` |
| `DirectivityEdition` | `enum` | **Which text of the vertical directivity (2.3.16) to evaluate.**<br>`CURRENT` ((EU) 2021/1226: zero for ψ ≤ 0), `ORIGINAL_2015` (absolute-value bars over the whole range) | `DirectivityEdition.ORIGINAL_2015` |
| `RoughnessInterpolation` | `enum` | **How a roughness spectrum is resampled from wavelength onto frequency (Annex II gives prose, not a formula).**<br>`PROPORTIONAL` (levels, the Commission reference module's rule), `ENERGY` (energies) | `RoughnessInterpolation.ENERGY` |
| `RAILWAY_THIRD_OCTAVE_BANDS` | `tuple` | **The 24 1/3-octave bands of the railway source (50 Hz…10 kHz).**<br>(no parameters) | `RAILWAY_THIRD_OCTAVE_BANDS` |
| `RAILWAY_OCTAVE_BANDS` | `tuple` | **The 8 octave bands handed to propagation (63 Hz…8 kHz).**<br>(no parameters) | `RAILWAY_OCTAVE_BANDS` |
| `RAILWAY_SOURCE_HEIGHTS` | `tuple` | **Heights of the two equivalent source lines (Annex II 2.3.1).**<br>(no parameters) | `RAILWAY_SOURCE_HEIGHTS  # (0.5, 4.0)` |
| `RAILWAY_MINIMUM_SPEED` | `float` | **Speed floor used to determine the total effective roughness [km/h].**<br>(no parameters) | `RAILWAY_MINIMUM_SPEED  # 50.0` |
| `TRAM_MINIMUM_SPEED` | `float` | **The same floor for trams and light metro [km/h].**<br>(no parameters) | `TRAM_MINIMUM_SPEED  # 30.0` |
| `AERODYNAMIC_THRESHOLD_SPEED` | `float` | **Speed above which aerodynamic noise is relevant [km/h].**<br>(no parameters) | `AERODYNAMIC_THRESHOLD_SPEED  # 200.0` |
| `AERODYNAMIC_REFERENCE_SPEED` | `float` | **Reference speed v0 of Annex II 2.3.13/2.3.14 [km/h].**<br>(no parameters) | `AERODYNAMIC_REFERENCE_SPEED  # 300.0` |
| `REFERENCE_JOINT_DENSITY` | `float` | **Joint density Table G-4 is given for [1/m].**<br>(no parameters) | `REFERENCE_JOINT_DENSITY  # 0.01` |
| `road_source_power` | `function` | **CNOSSOS-EU road source line power (Directive 2002/49/EC Annex II, 2.2.1).**<br>• `traffic`: one `RoadTraffic` or a sequence, at most one per category<br>• `surface`: `RoadSurface`, its description or a `RoadSurfaceCoefficients` (Default: reference surface)<br>• `temperature_c` tau [°C] (Default: 20)<br>• `road_slope_percent` s [%] (Default: 0, positive uphill)<br>• `studded_months` Ts (Default: 0)<br>• `junction_distance` x [m], `junction_type` (`JunctionType`)<br>• `coefficients`: Appendix F database (Default: `ROAD_COEFFICIENTS`) | `res = environment.road_source_power([environment.RoadTraffic(RoadVehicleCategory.LIGHT, 1200, 50)])`<br><br>• `RoadEmissionResult` |
| `RoadTraffic` | `dataclass` | **Traffic of one vehicle category on a source line.**<br>• `category`: `RoadVehicleCategory`<br>• `flow_rate` Qm [veh/h]<br>• `speed` vm [km/h] (powers frozen below 20 km/h)<br>• `studded_fraction` Qstud,ratio (Default: 0, category 1 only) | `RoadTraffic(RoadVehicleCategory.HEAVY, 45.0, 50.0)` |
| `RoadEmissionResult` | `dataclass` | **CNOSSOS-EU road source-line power per metre.**<br>• `frequencies` [Hz] (63…8000)<br>• `categories`<br>• `rolling`, `propulsion`, `vehicle_power`, `line_power`: (N_cat, 8) [dB]<br>• `total_line_power` [dB re 1 pW/m]<br>• `source_height` (0.05 m)<br>• `.a_weighted_line_power` [dB(A)]<br>• `.plot()` | `res.total_line_power, res.a_weighted_line_power` |
| `road_vehicle_sound_power` | `function` | **Single-vehicle sound power LW,i,m (Annex II 2.2.2/2.2.3).**<br>• `category`, `speed` [km/h]<br>• same surface/temperature/gradient/studded/junction parameters as `road_source_power` | `lw = environment.road_vehicle_sound_power("1", 90.0)`<br><br>• 8 octave bands [dB]; category 4 takes propulsion alone |
| `road_rolling_noise` | `function` | **Rolling-noise sound power LWR,i,m (Annex II 2.2.4/2.2.5).**<br>• `category`, `speed` [km/h]<br>• `surface`, `temperature_c`, `studded_fraction`, `studded_months`, `junction_distance`, `junction_type`, `coefficients` | `lwr = environment.road_rolling_noise("1", 90.0, temperature_c=5.0)`<br><br>• AR + BR·lg(v/70) + ΔLWR per band |
| `road_propulsion_noise` | `function` | **Propulsion-noise sound power LWP,i,m (Annex II 2.2.11/2.2.12).**<br>• `category`, `speed` [km/h]<br>• `surface`, `road_slope_percent`, `junction_distance`, `junction_type`, `coefficients` | `lwp = environment.road_propulsion_noise("3", 80.0, road_slope_percent=-8.0)`<br><br>• AP + BP·(v−70)/70 + ΔLWP per band |
| `road_surface_coefficients` | `function` | **Table F-4 row of a road surface (as replaced by (EU) 2021/1226).**<br>• `surface`: `RoadSurface` or its description | `row = environment.road_surface_coefficients(RoadSurface.THIN_LAYER_A)`<br><br>• `RoadSurfaceCoefficients` |
| `RoadSurfaceCoefficients` | `dataclass` | **One Table F-4 row.**<br>• `name`<br>• `alpha`: per category, 8 bands [dB]<br>• `beta`: per category<br>• `speed_range` (vmin, vmax) [km/h] or `None` | `row.alpha["1"], row.beta["1"], row.speed_range` |
| `RoadEmissionCoefficients` | `dataclass` | **Appendix F database (Tables F-1 to F-3 + Km).**<br>• `rolling_a`/`rolling_b`/`propulsion_a`/`propulsion_b`: per category, 8 bands<br>• `studded_a`/`studded_b` (Table F-2)<br>• `junction_c` (Table F-3)<br>• `temperature_k` Km [dB/°C] | `ROAD_COEFFICIENTS.rolling_a["1"]` |
| `ROAD_COEFFICIENTS` | `dataclass` | **The consolidated Appendix F database.**<br>Tables F-1/F-4 as replaced by (EU) 2021/1226, F-2/F-3 as published in (EU) 2015/996 | `ROAD_COEFFICIENTS.propulsion_a["3"]` |
| `RoadVehicleCategory` | `enum` | **Vehicle categories of Table [2.2.a].**<br>`LIGHT` (1), `MEDIUM_HEAVY` (2), `HEAVY` (3), `MOPEDS` (4a), `MOTORCYCLES` (4b) | `RoadVehicleCategory.HEAVY.value  # '3'` |
| `RoadSurface` | `enum` | **The fifteen road surfaces of Table F-4.**<br>`REFERENCE`, `ONE_LAYER_ZOAB`, `TWO_LAYER_ZOAB`, `TWO_LAYER_ZOAB_FINE`, `SMA_NL5`, `SMA_NL8`, `BRUSHED_DOWN_CONCRETE`, `OPTIMISED_BRUSHED_DOWN_CONCRETE`, `FINE_BROOMED_CONCRETE`, `WORKED_SURFACE`, `HARD_ELEMENTS_HERRINGBONE`, `HARD_ELEMENTS_NOT_HERRINGBONE`, `QUIET_HARD_ELEMENTS`, `THIN_LAYER_A`, `THIN_LAYER_B` | `RoadSurface.QUIET_HARD_ELEMENTS` |
| `JunctionType` | `enum` | **Junction types k of Table F-3.**<br>`NONE` (0), `CROSSING` (1), `ROUNDABOUT` (2) | `JunctionType.ROUNDABOUT` |
| `line_source_segment_power` | `function` | **Point-source power of a segment of source line (arithmetic; the split is outside the scope of Annex II 2.5.3).**<br>• `line_power` [dB re 1 pW/m]<br>• `length` dL [m] | `lw = environment.line_source_segment_power(res.total_line_power, 20.0)`<br><br>• L'W,eq,line + 10 lg(dL) |
| `CNOSSOS_A_WEIGHTING` | `tuple` | **Octave-band A-weighting AWCf,i printed by Annex II 2.5.5 as amended by (EU) 2021/1226.**<br>(no parameters) | `CNOSSOS_A_WEIGHTING  # (-26.2, …, -1.1)` |
| `ROAD_OCTAVE_BANDS` | `tuple` | **CNOSSOS-EU road source octave bands (63 Hz…8 kHz, per the 2018 corrigendum to 2.2.1).**<br>(no parameters) | `ROAD_OCTAVE_BANDS` |
| `ROAD_REFERENCE_SPEED` / `ROAD_REFERENCE_TEMPERATURE` / `ROAD_SOURCE_HEIGHT` | `float` | **Reference conditions of Annex II 2.2.**<br>vref = 70 km/h, tauref = 20 °C, source height 0,05 m | `ROAD_REFERENCE_SPEED  # 70.0` |
| `statistical_pass_by` | `function` | **Statistical Pass-By method of a road surface (ISO 11819-1:1997, 9.1 to 9.5).**<br>• `vehicle_categories` (`"1"` cars, `"2a"` dual-axle, `"2b"` multi-axle heavy) / `speeds_kmh` / `max_levels_db` (LAFmax): one row per pass-by<br>• `road_speed_category`: `"low"`\|`"medium"`\|`"high"` (Table 1 reference speeds and weights)<br>• `corrected_vehicle_sound_levels_db`: temperature-corrected L_veh (9.4 gives no method)<br>• `reference_db`: reference surface SPBI or its three L_veh (clause 10)<br>• `weighting_factors`: other proportions, summing to 1<br>• 7.3 counts and 9.3 speed windows emit `StatisticalPassByWarning` | `res = environment.statistical_pass_by(cats, v, L, road_speed_category="medium")`<br><br>• `StatisticalPassByResult` |
| `StatisticalPassByResult` | `dataclass` | **Vehicle sound levels and index of one surface.**<br>• `regressions` (per category) / `vehicle_sound_levels_db` / `index_db` (unrounded)<br>• `reported_vehicle_sound_levels_db` / `reported_index_db` (one decimal, half up)<br>• `corrected_index_db` / `reference_index_db` / `.difference_db` / `.corrected_difference_db`<br>• `.index_confidence_interval_db` / `.meets_minimum_counts` / `.reference_speeds_in_window`<br>• `.plot()`: the three clouds, their lines and L_veh | `res.reported_index_db` |
| `pass_by_regression` | `function` | **Least-squares line of LAFmax on lg v for one category, read at the reference speed (9.1, 9.2).**<br>• `speeds_kmh` / `max_levels_db`<br>• `vehicle_category` / `road_speed_category` | `reg = environment.pass_by_regression(v, L, vehicle_category="1", road_speed_category="medium")`<br><br>• `PassByRegression` |
| `PassByRegression` | `dataclass` | **One category's line and the clause 13 item 29 statistics.**<br>• `intercept_db` / `slope_db_per_decade` / `correlation`<br>• `level_standard_deviation_db` / `residual_standard_deviation_db` (n − 2) / `lg_speed_standard_deviation`<br>• `.vehicle_sound_level_db` / `.reported_vehicle_sound_level_db` / `.mean_speed_kmh` (10^mean lg v)<br>• `.speed_window_kmh` / `.reference_speed_in_window` (9.3) / `.meets_minimum_count` (7.3)<br>• `.confidence_interval_db` (95 %, Student t) / `.plot()` | `reg.vehicle_sound_level_db` |
| `statistical_pass_by_index` | `function` | **SPBI of three vehicle sound levels (9.5).**<br>• `vehicle_sound_levels_db`: keyed `"1"`, `"2a"`, `"2b"`<br>• `road_speed_category` / `weighting_factors` | `environment.statistical_pass_by_index({"1": 78.5, "2a": 81.1, "2b": 83.8}, road_speed_category="medium")  # 79.946…` |
| `normalized_reference_levels` | `function` | **L_veh of a normalized reference surface: the average of several surfaces (10.2, Annex D).**<br>• `surface_levels_db`: surface label → the three L_veh | `normalized_reference_levels(SPB_ANNEX_D_SURFACES_DB)` |
| `StatisticalPassByWarning` | `warning class` | **ISO 11819-1 advisory.**<br>Emitted when a category falls short of the 7.3 minimum count or its reference speed leaves the 9.3 window | `warnings.simplefilter('error', StatisticalPassByWarning)` |
| `SPB_REFERENCE_SPEEDS_KMH` / `SPB_WEIGHTING_FACTORS` | `mapping` | **Table 1: reference speeds [km/h] and weighting factors Wx, by road speed then vehicle category.** | `SPB_REFERENCE_SPEEDS_KMH["medium"]["1"]  # 80.0` |
| `SPB_VEHICLE_STANDARD_DEVIATIONS_DB` / `SPB_CONFIDENCE_INTERVALS_DB` | `mapping` | **Table 2: expected spread of individual vehicles about L_veh and the 95 % interval it leaves [dB].** | `SPB_CONFIDENCE_INTERVALS_DB["1"]  # 0.3` |
| `SPB_MINIMUM_VEHICLE_COUNTS` / `SPB_SPEED_WINDOW_STANDARD_DEVIATIONS` | `mapping` | **7.3 minimum vehicles for classification (`"2"` is 2a and 2b together) and the 9.3 window in standard deviations of speed.** | `SPB_MINIMUM_VEHICLE_COUNTS["2"]  # 80` |
| `SPB_ANNEX_D_SURFACES_DB` / `SPB_NORMALIZED_REFERENCE_DB` | `mapping` | **Annex D: the seven surfaces of the example reference case and their average row [dB], medium speed range.** | `SPB_NORMALIZED_REFERENCE_DB["2b"]  # 84.0` |
| `SPB_VEHICLE_CATEGORIES` / `SPB_ROAD_SPEED_CATEGORIES` | `constant` | **The category labels the method uses: `("1", "2a", "2b")` and `("low", "medium", "high")`.** | `SPB_VEHICLE_CATEGORIES` |
| `SPB_REFERENCE_AIR_TEMPERATURE_C` | `float` | **9.4: the air temperature L_veh should be corrected to [°C].** | `SPB_REFERENCE_AIR_TEMPERATURE_C  # 20.0` |
| `pass_by_measurement` | `function` | **The pass-by quantities of one record (ISO 3095:2013, 6.5 and 6.6.3).**<br>• `signal`: pressure in Pa, unweighted, or a `Signal`; `fs`<br>• `start_s` / `end_s`: T1 and T2 of the measurement interval<br>• `pass_by_time_s`: Tp, to spread the energy of the interval over (TEL of ISO 3095:2005)<br>• `front_passing_s` / `rear_passing_s`: for the 10 dB margins of 6.6.3 | `rec = environment.pass_by_measurement(p, fs, start_s=4.0, end_s=9.0)`<br><br>• `PassByMeasurement` |
| `PassByMeasurement` | `dataclass` | **One pass-by record.**<br>• `times_s` / `levels_db` (LpAF(t))<br>• `equivalent_level_db` (LpAeq,T) / `max_level_db` (LpAFmax)<br>• `.exposure_level_db` (SEL) / `.normalized_level_db` (TEL, or Formula B.1)<br>• `.start_margin_db` / `.end_margin_db` / `.recording_interval_sufficient` / `.plot()` | `rec.equivalent_level_db` |
| `pass_by_time` | `function` | **Tp = l/v (ISO 3095:2005, 3.14).**<br>• `unit_length_m`<br>• `speed_kmh` | `environment.pass_by_time(200.0, speed_kmh=144.0)  # 5.0` |
| `transit_exposure_level` | `function` | **TEL = LpAeq,T + 10 lg(T/Tp) (ISO 3095:2005, Formula 10).**<br>• `equivalent_level_db`<br>• `measurement_time_s` / `pass_by_time_s` | `environment.transit_exposure_level(84.0, measurement_time_s=12.0, pass_by_time_s=5.0)` |
| `stationary_unit_level` | `function` | **Length-weighted energy average of a stationary mesh (ISO 3095, Formulae 1 to 3).**<br>• `levels_db`: one per position<br>• `lengths_m`: the length each position stands for | `environment.stationary_unit_level([60, 66], [4, 12])` |
| `stationary_test` | `function` | **The stationary test: Formula 1 per set, the rounded mean of the sets (5.8.1).**<br>• `levels_db`: one row per set (at least three), one column per position<br>• `lengths_m` | `res = environment.stationary_test(levels, lengths)`<br><br>• `StationaryTestResult` |
| `StationaryTestResult` | `dataclass` | **A stationary test.**<br>• `.set_levels_db` / `.mean_level_db` / `.reported_level_db`<br>• `.position_spreads_db` / `.valid` (9.3) / `.plot()` | `res.reported_level_db` |
| `STATIONARY_END_POSITION_LENGTH_M` | `float` | **The (π/2) × 7,5 m an end position stands for in Formula 1 [m].** | `STATIONARY_END_POSITION_LENGTH_M  # 11.78…` |
| `rolling_stock_test` | `function` | **Constant-speed, starting and braking tests: the highest rounded mean of three runs per position (6.7.1, 7.5.4, 7.6.4, 8.7).**<br>• `samples_db`: position name → runs<br>• `method`: one of `ROLLING_STOCK_TEST_METHODS` | `environment.rolling_stock_test({"left": [80.2, 80.9, 81.4], "right": [81.6, 82.4, 81.9]})`<br><br>• `RollingStockTestResult` |
| `RollingStockTestResult` | `dataclass` | **A test of three runs per position.**<br>• `.mean_levels_db` / `.reported_levels_db` / `.spreads_db`<br>• `.valid` (9.3) / `.governing_position` / `.final_level_db` / `.plot()` | `res.final_level_db  # 82.0` |
| `ROLLING_STOCK_TEST_METHODS` | `constant` | **`("constant_speed", "acceleration_maximum", "acceleration_averaged", "braking")`.** | `ROLLING_STOCK_TEST_METHODS` |
| `type_test_speeds` | `function` | **6.6.2: 80 km/h and v_max above 80 km/h, v_max alone below.**<br>• `max_speed_kmh` | `environment.type_test_speeds(160.0)  # (80.0, 160.0)` |
| `PREFERRED_PASS_BY_SPEEDS_KMH` | `tuple` | **6.6.2: the preferred speeds of additional tests [km/h], as printed.** | `PREFERRED_PASS_BY_SPEEDS_KMH[-1]  # 350.0` |
| `acceleration_test_positions` | `function` | **7.5.1.1 and Figure 10: the microphone positions of the maximum level starting test, in m behind the front of the unit.**<br>• `unit_length_m` | `environment.acceleration_test_positions(108.0)  # [-10, 17, 44]` |
| `minimum_curve_radius` | `function` | **6.2.2: 1 000 m to 70 km/h, 3 000 m to 120 km/h, 5 000 m above.**<br>• `speed_kmh` | `environment.minimum_curve_radius(100.0)  # 3000.0` |
| `impulsiveness_rise_speed` | `function` | **Annex A: the steepest rise of the LpAF(t) slopes that climb 10 dB.**<br>• `times_s` / `levels_db` | `r = environment.impulsiveness_rise_speed(rec.times_s, rec.levels_db)`<br><br>• `RiseSpeedResult` |
| `RiseSpeedResult` | `dataclass` | **The slopes and their rise speeds.**<br>• `slopes` / `rise_speeds_db_per_s`<br>• `.rise_speed_db_per_s` (`None` when no slope climbs 10 dB) / `.plot()` | `r.rise_speed_db_per_s` |
| `check_adjacent_vehicle_neutrality` | `function` | **6.3.4: is the adjacent vehicle neutral, LpAeq,Tp1 no more than 2,0 dB over LpAeq,Tp, rounded to a decimal?**<br>• `with_adjacent_level_db` / `unit_level_db` | `environment.check_adjacent_vehicle_neutrality(83.0, 81.1).passes`<br><br>• `AdjacentVehicleNeutrality` |
| `AdjacentVehicleNeutrality` | `dataclass` | **The neutrality verdict.**<br>• `.difference_db` / `.passes` (no truth value) / `.plot()` | `v.passes` |
| `background_level_increase` | `function` | **Formula D.1: what a steady background adds, for an excess above 3 dB.**<br>• `measured_level_db` / `background_level_db` (one value or per band) | `environment.background_level_increase(60.0, 55.0)  # 1.65` |
| `check_small_roughness_deviations` | `function` | **Annex C: may a track over the roughness limit be used? The effect of the exceedance on the pass-by level, at most 1 dB.**<br>• `roughness`: the quadratic average of the rails<br>• `noise_levels_db` / `frequencies_hz`: the A-weighted pass-by spectrum<br>• `speed_kmh` / `limit_db` (Figure 2) | `c = environment.check_small_roughness_deviations(r, L, frequencies_hz=f, speed_kmh=80.0)`<br><br>• `SmallRoughnessDeviation` |
| `SmallRoughnessDeviation` | `dataclass` | **The Annex C chain.**<br>• `corrected_roughness_levels_db` (C.1) / `roughness_correction_db` (C.2)<br>• `.revised_noise_levels_db` (C.3) / `.impact_db` (C.4)<br>• `.exceeded` / `.passes` (no truth value) / `.plot()` | `c.impact_db` |
| `roughness_comparability` | `function` | **Annex E: bound what the roughness of two tracks could change in a pass-by level.**<br>• `roughness_1` / `roughness_2`<br>• `noise_levels_1_db` / `noise_levels_2_db` / `frequencies_hz` / `speed_kmh` | `e = environment.roughness_comparability(r1, r2, L1, L2, frequencies_hz=f, speed_kmh=80.0)`<br><br>• `RoughnessComparability` |
| `RoughnessComparability` | `dataclass` | **The four differences of Formula E.4 and the bound of E.5.**<br>• `level_differences_db` / `.bound_db`<br>• `.envelope_min` / `.envelope_max` (E.1) / `.plot()` | `e.bound_db` |
| `check_reference_track` | `function` | **6.2: is this a reference track for the constant-speed test?**<br>• `roughness`: one spectrum per rail or line (a Method B line needs 15 m analysed, EN 15610 7.4.3) / `decay_rates`: vertical and lateral<br>• `speed_kmh` / `curve_radius_m` / `track_gradient_ratio`<br>• `small_deviations`: the Annex C verdict of this speed on the quadratic average of the rails, which accepts a small exceedance (another speed or roughness is refused)<br>• `roughness_limit_db` / `decay_limits_db_per_m` | `chk = environment.check_reference_track([r1, r2], [vert, lat], speed_kmh=160.0)`<br><br>• `ReferenceTrackCheck` |
| `ReferenceTrackCheck` | `dataclass` | **The track verdict.**<br>• `conditions` (one `TrackCondition` per requirement) / `.failed`<br>• `roughness_limit_db` / `decay_limits_db_per_m` (read-only copies) / `small_deviations` (the Annex C verdict the limit rested on, else `None`)<br>• `curve_radius_m` / `track_gradient_ratio` (6.2.2, or `None`)<br>• `.passes` (no truth value) / `.plot(panel="roughness" \| "decay")`<br>• takes `speed_kmh`, `roughness`, `decay_rates`, `roughness_limit_db`, `decay_limits_db_per_m`, `small_deviations`, `curve_radius_m`, `track_gradient_ratio`; `conditions`, `failed`, `passes` are read-only, read from them | `chk.passes` |
| `TrackCondition` | `dataclass` | **One requirement of 6.2 and whether it holds.**<br>• `clause` / `requirement` / `holds` (`None` when not judged) / `detail` | `chk.conditions[0].holds` |
| `REFERENCE_TRACK_ROUGHNESS_LIMIT_DB` | `mapping` | **Figure 2: the roughness limit, nominal wavelength [m] → dB re 1 µm, 0,4 m to 3,15 mm.** | `REFERENCE_TRACK_ROUGHNESS_LIMIT_DB[0.01]  # -8.0` |
| `REFERENCE_TRACK_DECAY_LIMITS_DB_PER_M` | `mapping` | **Figure 3: the decay-rate lower limits, direction → nominal frequency [Hz] → dB/m, 250 Hz to 5 kHz.** | `REFERENCE_TRACK_DECAY_LIMITS_DB_PER_M["lateral"][1000.0]  # 0.2` |
| `pass_by_uncertainty` | `function` | **Annex G: u_c = √Σu², U = 2 u_c, and the reading plus the mean value corrections.**<br>• `reading_db`<br>• `inputs`: `metrology.Quantity` per input (value = ΔLp, uncertainty = u)<br>• `coverage_factor` | `environment.pass_by_uncertainty(55.0, inputs)`<br><br>• `PassByUncertainty` |
| `PassByUncertainty` | `dataclass` | **An Annex G budget.**<br>• `.level_db` / `.combined_uncertainty_db` / `.expanded_uncertainty_db`<br>• `.variance_ratios` (Figure G.1) / `.plot()` | `u.expanded_uncertainty_db` |
| `acoustic_roughness_spectrum` | `function` | **EN 15610:2009 7.2 to 7.4: the one-third octave band roughness of a record, Method A.**<br>• `roughness_um` / `sample_spacing_m` (1 mm or less)<br>• `spike_removal` / `curvature_processing`<br>• `segment_length_m`: at least 1 m | `s = environment.acoustic_roughness_spectrum(r, sample_spacing_m=1e-3)`<br><br>• `AcousticRoughnessSpectrum` |
| `AcousticRoughnessSpectrum` | `dataclass` | **A roughness spectrum, longest wavelength first.**<br>• `wavelengths_m` / `levels_db` (dB re 1 µm)<br>• `record_length_m` (for Method B, the length analysed) / `segment_count`<br>• `method`: `"A"`, `"B"` or `None`<br>• `.bands` / `.level_at(wavelength_m)` / `.plot(limit_db=...)` | `s.level_at(0.01)` |
| `filtered_roughness_spectrum` | `function` | **EN 15610:2009 7.4.3: the one-third octave band roughness of a record through digital filters, Method B.**<br>• `roughness_um` / `sample_spacing_m` (1 mm or less, a whole number of samples per metre)<br>• `spike_removal` / `curvature_processing`<br>• 2 m discarded at either end, so a record of at least 5 m | `s = environment.filtered_roughness_spectrum(r, sample_spacing_m=1e-3)`<br><br>• `AcousticRoughnessSpectrum` |
| `roughness_filter_bank` | `function` | **EN 15610 7.4.3: the one-third octave filters of Method B, class 0 of EN 61260:1995, every band at the record's own rate.**<br>• `sample_spacing_m`<br>• `longest_wavelength_m`: 0,5 m by default, as in the Annex B listing | `bank = environment.roughness_filter_bank(sample_spacing_m=1e-3)`<br><br>• `filters.OctaveFilterBank` |
| `remove_roughness_spikes` | `function` | **EN 15610 7.2: narrow upward spikes replaced by straight lines.**<br>• `roughness_um` / `sample_spacing_m` | `environment.remove_roughness_spikes(r, sample_spacing_m=1e-3)` |
| `curvature_processed_roughness` | `function` | **EN 15610 7.3: the record as a wheel of 0,375 m radius rides it.**<br>• `roughness_um` / `sample_spacing_m` / `curve_radius_m` | `environment.curvature_processed_roughness(r, sample_spacing_m=1e-3)` |
| `redistributed_band_energies` | `function` | **EN 15610 Annex C: band energies shared among other bands by the width they cover.**<br>• `source_lower` / `source_upper` / `energies`<br>• `target_lower` / `target_upper` | `environment.redistributed_band_energies(lo, hi, e, tlo, thi)` |
| `average_roughness_spectra` | `function` | **EN 15610 7.6: the mean square average of spectra, band by band.**<br>• `spectra` | `environment.average_roughness_spectra([s1, s2])` |
| `roughness_measurement_lines` | `function` | **EN 15610 6.4.3: the lines a rail is measured on, by its reference width.**<br>• `reference_width_mm` | `environment.roughness_measurement_lines(25.0)  # (3, 5.0)` |
| `track_decay_rate` | `function` | **EN 15461:2008+A1:2010 Formula 1: the decay rate from the responses along the rail.**<br>• `responses`: magnitudes, one row per position, the direct one first<br>• `frequencies_hz` / `distances_m` (Figure 2 grid when omitted) / `sleeper_spacing_m`<br>• `direction`: `"vertical"` or `"lateral"` | `d = environment.track_decay_rate(A, frequencies_hz=f)`<br><br>• `TrackDecayRate` |
| `TrackDecayRate` | `dataclass` | **The decay rates of one direction.**<br>• `frequencies_hz` / `decay_rates_db_per_m` / `distances_m` / `responses`<br>• `.minimum_measurable_db_per_m` (Formula 2) / `.suitable` / `.far_field_drops_db` / `.far_field_sufficient`<br>• `.rate_at(frequency_hz)` / `.plot(limit_db_per_m=...)` | `d.rate_at(1000.0)` |
| `track_decay_excitation_positions` | `function` | **EN 15461 Figure 2: the 29 hammer positions in metres.**<br>• `sleeper_spacing_m` (0,6 m by default) | `environment.track_decay_excitation_positions()[-1]  # 39.6` |
| `TRACK_DECAY_EXCITATION_INDICES` / `TRACK_DECAY_DIRECTIONS` | `constant` | **The Figure 2 grid in sleeper bays, 0 to 66, and `("vertical", "lateral")`.** | `TRACK_DECAY_EXCITATION_INDICES[-1]  # 66.0` |
| `ground_effect` | `function` | **Spherical-wave ground effect ΔL (Weyl-Van der Pol; Attenborough 2e Eq. 2.40, Salomons Eq. 3.4).**<br>• `frequencies` [Hz], `source_height` hs, `receiver_height` hr, `distance` [m]<br>• `impedance` (normalized) or `flow_resistivity` σ [Pa·s/m²]<br>• `model` 'delany_bazley'/'miki' | `r = environment.ground_effect(bands, 1, 1.5, 50, flow_resistivity=2e5)`<br><br>• `SphericalGroundResult` (ΔL, Q, Rp, F) |
| `GroundSurface` | `dataclass` | **One ground surface as one published table prints it.**<br>• `flow_resistivity_pa_s_m2` is an **effective** resistivity: the number that makes a rigid-framed ground model reproduce a measured attenuation, so it carries the fit it came from<br>• `porosity` (a fraction), `water_content_percent`, `porosity_decay_rate_per_m`: what Cox tabulates beside it; the six porosities Cox prints in per cent in a column of fractions are `None`, and `.why_missing('porosity')` quotes them<br>• `iso_9613_ground_factor`, `nmpb_ground_factor`, `harmonoise_class`: the class rows, where the two models disagree on two of the eight classes<br>• The hedges every catalogue row has: `ranges`, `reported`, `unquantified`, `uncertainty`, `approximate`, `variant`<br>• `.medium(f, model='delany_bazley' \| 'miki', fluid=PUBLISHED_AIR)` → `PorousMediumResult`, the half-space `ground_effect` takes as `impedance`, `barrier_insertion_loss` as `ground_impedance` and `atmospheric_parabolic_equation` as `impedance`; the resistivity is read through `.printed()`, and a row the page marks as fitted with one model goes into that model only | `g = environment.PUBLISHED_GROUND['bies-2017-table-5-1/sugar_snow']`<br>`g.printed('flow_resistivity_pa_s_m2')`<br><br>• `g.source` prints the page |
| `PUBLISHED_GROUND` | `mapping` | **A hundred and five ground surfaces from three published tables, keyed `'<table>/<row>'`.**<br>• Bies 5e Table 5.1, thirty-four measured surfaces, and Table 5.2, the eight classes A to H with the ISO 9613-2 and NMPB-2008 ground factors<br>• Cox & D'Antonio 3e Table 6.7, sixty-three rows: the same surface fitted with three different models is three rows, because the fit is part of the quantity<br>• Seven surfaces both books take from Embleton (1983) come out to the same digits through two different printed units<br>• One cell of Cox prints `1.7.3 × 10⁵`, with two decimal points; it is kept as the page printed it and answers `None` | `environment.PUBLISHED_GROUND['bies-2017-table-5-2/normal_uncompacted_ground']`<br><br>• `GroundSurface`, `ground_surfaces_named` |
| `ground_surfaces_named` | `function` | **Every row for a surface name, across the tables.**<br>• `name` as a table prints it, matched without regard to case<br>• Returns every reading rather than choosing one: the spread between books is the answer<br>• `catalogue=`: the rows to search instead of `PUBLISHED_GROUND`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_GROUND \| mine`; a row of another class is refused by its key (`TypeError`) | `environment.ground_surfaces_named('Sugar snow')`<br><br>• `(GroundSurface, ...)` |
| `spherical_reflection_coefficient` | `function` | **Spherical-wave reflection coefficient Q = Rp + (1−Rp)F(w) (Attenborough Eq. 2.40c; Salomons Eq. D.58).**<br>• `frequencies`, `normalized_impedance`, `source_height`, `receiver_height`, `distance` | `q = environment.spherical_reflection_coefficient(bands, 12-6j, 1, 1.5, 50)` |
| `SphericalGroundResult` | `dataclass` | **Spherical-wave ground-effect result.**<br>• `excess_attenuation` ΔL [dB re free field]<br>• `reflection_coefficient` Q, `plane_reflection_coefficient` Rp, `boundary_loss` F<br>• `r_direct`, `r_reflected` [m]<br>• `.plot()` | `r.excess_attenuation, r.reflection_coefficient` |
| `fresnel_number` | `function` | **Barrier Fresnel number N = (2/λ)(A+B−d) (Bies 5e Eq. 5.134).**<br>• `source_to_edge` A, `edge_to_receiver` B, `direct_distance` d [m]<br>• `frequencies` [Hz] | `n = environment.fresnel_number(101, 101, 200, bands)` |
| `kurze_anderson_attenuation` | `function` | **Kurze-Anderson barrier attenuation (Bies Eq. 5.138).**<br>• `fresnel_number` N | `kurze_anderson_attenuation(0.0)  # 5 dB` |
| `barrier_insertion_loss` | `function` | **Barrier insertion loss: Kurze-Anderson / exact half-plane / coherent ground four-path (Attenborough Ch. 9, Bies 5.3.5-5.3.7).**<br>• `frequencies`, `source_height`, `barrier_distance`, `barrier_height`, `receiver_distance`, `receiver_height`<br>• `method` 'exact'/'kurze_anderson'<br>• `thickness` e [m] (thick barrier)<br>• `ground_impedance` or `ground_flow_resistivity` | `il = environment.barrier_insertion_loss(bands, 1, 50, 4, 100, 1.5, ground_flow_resistivity=2e5)`<br><br>• `BarrierInsertionLoss` |
| `TRAFFIC_NOISE_BANDS_HZ` / `NORMALISED_TRAFFIC_NOISE_SPECTRUM_DB` / `NORMALISED_RAILWAY_NOISE_SPECTRUM_DB` / `SPECTRA` | `constant` | **The eighteen one-third octave bands from 100 Hz to 5 kHz, and the two spectra a device is rated against: EN 1793-3 Table 1 for a road and EN 16272-3-1 Table 1 for a railway.** `SPECTRA` maps `'road'` and `'railway'` to them. | `environment.NORMALISED_TRAFFIC_NOISE_SPECTRUM_DB[10]  # -8.0 dB at 1 kHz` |
| `sound_absorption_rating` / `airborne_insulation_rating` | `function` | **EN 1793-1 Clause 5, EN 1793-2 Clause 5.2 and EN 16272-3-1 Clauses 5 and 6: what a noise reducing device is declared by.**<br>• `sound_absorption_rating(absorption_coefficients, spectrum='road')`: `DLα`, the energy the device does not send back, capped by the 0,99 ratio limit both standards put on it<br>• `airborne_insulation_rating(sound_reduction_index_db, spectrum='road')`: `DL_R`, the energy it does not pass<br>• `spectrum='railway'` swaps in EN 16272-3-1 Clauses 5 and 6, which are the same formulas on the railway table and print no category ladder<br>• both return a `RoadDeviceRating` carrying the unrounded value, the reported integer and, for a road device, its Annex A category | `environment.airborne_insulation_rating([32.0] * 18).category  # 'B3'` |
| `RoadDeviceRating` | `dataclass` | **One declared rating: `rating`, `reported`, `category` (`None` for a railway device and for reflection), `quantity` (`'absorption'`, `'insulation'` or `'reflection'`), `spectrum`, `bands_hz`, `values`, `weights`, `lowest_band_hz`.**<br>• `.plot()` draws the per-band input against the spectrum that weights it, hatching the bands a reflection rating leaves out | `rating.plot()` |
| `ABSORPTION_RATIO_LIMIT` / `ABSORPTION_CATEGORIES` / `INSULATION_CATEGORIES` | `constant` | **The 0,99 ceiling of EN 1793-1 Clause 5, and the two Annex A category ladders (A1 to A5, B1 to B4) read off the reported integer.** | `environment.ABSORPTION_RATIO_LIMIT  # 0.99` |
| `RoadDeviceWarning` | `warning class` | **Emitted when the weighted absorption ratio reaches the 0,99 limit, so the rating is the limit rather than the measurement.** | `warnings.catch_warnings()` |
| `sound_reflection_rating` | `function` | **EN 1793-5 Clause 5.8, Formula (12): `DL_RI`, the sound reflection index weighted by the EN 1793-3 spectrum from the lowest reliable band.**<br>• `reflection_indices`: the eighteen `RI` values; a band below `lowest_band_hz` may be `nan`<br>• `lowest_band_hz` (Default: 200 Hz, the qualification sample of 4 m by 4 m); a 3,5 m barrier reports `DL_RI (400 - 5 000 Hz)`<br>• the ratio is capped at 0,99 as the clause says, with a `RoadDeviceWarning`; no category ladder | `environment.sound_reflection_rating([0.1] * 18).rating  # 10.0 dB` |
| `reflection_index` / `ReflectionIndexResult` | `function` / `dataclass` | **EN 1793-5 Formula (1): the sound reflection index `RI` per one-third octave band from the impulse responses of the nine microphones.**<br>• `in_front_irs`, `free_field_irs`: `(9, N)` for one grid position or `(positions, 9, N)`; `fs`<br>• `speed_of_sound` places the reflected window; `window_length_s` (6,0 ms, one or nine) from 200 Hz, `low_band_window_length_s` (7,9 ms) and `low_band_microphones` (1 to 6) below it<br>• `directivity_corrections`: `C_dir,k` as `(9, 18)`, or `None`; `C_geo,k` from the geometry and `C_gain,k` of Formula (4), which divides<br>• result: `reflection_index`, `position_values`, `microphone_values`, `gain_corrections`, `subtraction_reductions_db`, `rating` (`DL_RI`), `expanded_uncertainty()`, `.plot()` | `environment.reflection_index(front, free, 48000.0, speed_of_sound=343.0)` |
| `reflection_index_from_positions` | `function` | **The declared index from the index of each grid position, their band-by-band mean (5.6.2.3, Annex B Table B.1).**<br>• `position_values`: `(positions, 18)`, `nan` where a band was not measured<br>• `lowest_band_hz` (Default: 200 Hz) | `environment.reflection_index_from_positions(rows).rating.reported  # 8 for Table B.1` |
| `subtract_direct_sound` / `DirectSoundSubtraction` | `function` / `dataclass` | **EN 1793-5 5.5.4: the free-field record aligned onto the in-front one to a fiftieth of a sample, scaled to its peak and subtracted.**<br>• the shift is a phase ramp over the record's own transform, within two samples either way<br>• result: `residual` (the reflection), `aligned_free_field`, `shift_samples`, `amplitude_factor`, `reduction_db` (`R_sub`, Formula (6)), `.plot()`<br>• an `R_sub` below 10 dB emits a `BarrierReflectionWarning` | `environment.subtract_direct_sound(front[4], free[4], 48000.0).reduction_db` |
| `adrienne_reflection_window` / `adrienne_low_frequency_limit_hz` | `function` | **The Adrienne window of EN 1793-5 5.5.5 and the low frequency limit it allows.**<br>• the window: a 0,5 ms left half of the Blackman-Harris window of Formula (7), a flat part, and a right half 3/7 of the flat part; the marker point is sample `round(0.5e-3 * fs)`<br>• the limit: the first notch of the continuous window's spectrum, the indicator of Garai and Guidorzi (2000): 162,5 Hz for 7,9 ms, 216,5 Hz for 6,0 ms | `environment.adrienne_low_frequency_limit_hz(7.9e-3)  # 162.55 Hz` |
| `ADRIENNE_STANDARD_LENGTH_S` / `ADRIENNE_SHORT_LENGTH_S` / `ADRIENNE_CALIBRATION_LENGTH_S` / `REFLECTION_LOW_BAND_MICROPHONES` | `constant` | **The three window lengths EN 1793-5 prints: 7,9 ms below 200 Hz, 6,0 ms from 200 Hz, 1,3 ms for the gain check of 5.5.1; and the microphones 1 to 6 averaged below 200 Hz.** | `environment.ADRIENNE_SHORT_LENGTH_S  # 0.006` |
| `source_directivity_corrections` | `function` | **EN 1793-5 Formula (3): `C_dir,k` per microphone and band, from free-field records at the microphone positions and on the specular paths, at the same distance from the loudspeaker.**<br>• returns a read-only `(9, 18)` array for `reflection_index(directivity_corrections=...)` | `environment.source_directivity_corrections(on_axis, specular, 48000.0)` |
| `reflection_grid_paths_m` / `geometric_divergence_corrections` / `reflection_sampled_area_radius_m` | `function` | **The geometry of the grid: the direct and the specular path to each microphone (Table 2), `C_geo,k = (d_r,k/d_i,k)²` (Formula (2)) and the maximum sampled area (Formula (8)).**<br>• `source_distance_m`, `microphone_distance_m`, `grid_spacing_m` default to 1,50 m, 0,25 m and 0,40 m<br>• the sampled area takes the window length and `speed_of_sound`: 1,96 m for 7,9 ms at 340 m/s (5.6.1 NOTE 1) | `environment.geometric_divergence_corrections()[4]  # 1.96` |
| `REFLECTION_SOURCE_DISTANCE_M` / `REFLECTION_MICROPHONE_DISTANCE_M` / `REFLECTION_GRID_SPACING_M` / `REFLECTION_GRID_DISTANCES` / `REFLECTION_PATH_DIFFERENCES_M` / `REFLECTION_PATH_TOLERANCE_M` | `constant` / `mapping` | **The fixed geometry of EN 1793-5 (1,50 m, 0,25 m, 0,40 m), Table 2 as printed (`d_i,k`, `d_r,k`, `C_geo,k` per microphone) and Table 3 as printed (`Δd_k5`, `Δd_k`) with its 25 mm tolerance.** | `environment.REFLECTION_PATH_DIFFERENCES_M[5]  # (0.0, 0.5)` |
| `reflection_low_frequency_limit` / `ReflectionFrequencyLimit` | `function` / `dataclass` | **How far down a device of a given size can be measured, EN 1793-5 5.5.7.**<br>• `device_height_m`; `speed_of_sound`; `device_length_m` adds the side edges; `source_height_m` (Default: half the height)<br>• each microphone's longest window ends where the ground reflection or an edge diffraction arrives, and its limit is that window's first notch; Figure 14 prints only curves, and this construction is the one of the method's authors<br>• result: `window_length_s`, `low_frequency_limit_hz`, `limiting_component`, `.plot()` | `environment.reflection_low_frequency_limit(4.0, speed_of_sound=340.0)` |
| `check_reflection_grid_position` / `ReflectionGridCheck` | `function` / `dataclass` | **The two position checks of EN 1793-5 against Table 3: 5.6.2.5 (`check='relative'`, loudspeaker against grid) and 5.6.2.6 (`check='grid'`, grid against the reference plane).**<br>• `time_delays_s`: nine delays; `speed_of_sound` turns them into path differences (Formulas (10) and (11))<br>• result: `check` and `path_differences_m`; read-only from Table 3: `nominal_m`, `deviations_m`, `within` (±25 mm), `passes`; `.plot()`; it has no truth value | `environment.check_reflection_grid_position(delays, speed_of_sound=343.0).passes` |
| `REFLECTION_INDEX_PRECISION` / `REFLECTION_RATING_PRECISION_DB` | `mapping` | **Table A.1 of EN 1793-5: the standard deviations of repeatability and reproducibility of `RI` per band and of `DL_RI`, each `(median, low, high)`, from the QUIESST inter-laboratory test.** | `environment.REFLECTION_INDEX_PRECISION[100.0]['reproducibility']  # (0.27, 0.23, 0.32)` |
| `BarrierReflectionWarning` | `warning class` | **A reflection measurement EN 1793-5 flags as suspect: an `R_sub` below 10 dB (5.5.4), a gain factor more than 20 % from 1 (5.5.1), a sample rate below 44 kHz (5.5.2).** | `warnings.catch_warnings()`<br>Emitted by `environment.propagation.barrier_reflection` |
| `plot_barrier_geometry` | `function` | **Source-barrier-receiver section to scale.**<br>• `source_height`, `barrier_distance`, `barrier_height`, `receiver_distance`, `receiver_height` [m]<br>• `thickness` [m] (Default: None → thin screen)<br>• `language` | `plot_barrier_geometry(source_height=1.5, barrier_distance=5.0, barrier_height=3.0, receiver_distance=20.0, receiver_height=1.5)`<br><br>• Direct + diffracted paths, path difference annotated; also `BarrierInsertionLoss.plot_geometry()` |
| `BarrierInsertionLoss` | `dataclass` | **Per-band barrier insertion loss.**<br>• `insertion_loss` [dB], `fresnel_number`, `method`, `ground`<br>• `.plot()` (IL vs frequency) | `il.insertion_loss` |
| `linear_sound_speed_profile` | `function` | **Linear effective sound-speed profile c_eff(z) = c0 + g·z (Salomons Sec. 4.2).**<br>• `gradient_per_s` g [s⁻¹]<br>• `ground_speed` c0 [m/s], `max_height` [m] | `p = environment.linear_sound_speed_profile(0.1)`<br><br>• `EffectiveSoundSpeedProfile` |
| `log_linear_sound_speed_profile` | `function` | **Logarithmic surface-layer profile c_eff(z) = c0 + b·ln(1+z/z0) (Salomons Eq. 4.5).**<br>• `b` [m/s] (downward > 0)<br>• `ground_speed` c0, `roughness_length` z0, `max_height` [m], `n_points` | `p = environment.log_linear_sound_speed_profile(1.0)`<br><br>• `EffectiveSoundSpeedProfile` |
| `EffectiveSoundSpeedProfile` | `dataclass` | **Effective sound-speed profile c_eff(z).**<br>• `heights` z [m], `sound_speeds` [m/s], `description`<br>• `.speed_at(z)`, `.plot()` | `p.speed_at(10.0)` |
| `ray_curvature_radius` | `function` | **Radius of curvature of a ray in a linear gradient_per_s Rc = c0/(&#124;g&#124; cos θ0) (Salomons Sec. 4.4).**<br>• `gradient_per_s` g [s⁻¹]<br>• `ground_speed` c0 [m/s], `launch_angle_deg` θ0 | `ray_curvature_radius(0.1)  # 3430 m` |
| `shadow_zone_distance` | `function` | **Shadow-boundary distance in upward refraction √(2Rc)(√hs+√hr) (Salomons Sec. 4.4).**<br>• `gradient_per_s` g < 0 [s⁻¹]<br>• `source_height` hs, `receiver_height` hr [m]<br>• `ground_speed` c0 | `shadow_zone_distance(-0.1, 2, 2)` |
| `atmospheric_ray_paths` | `function` | **Ray tracing through a refracting atmosphere (Snell's law, Salomons Eq. 4.3).**<br>• `profile`: `EffectiveSoundSpeedProfile`<br>• `source_height` [m], `launch_angles_deg`<br>• `max_range` [m], `n_steps` | `r = environment.atmospheric_ray_paths(p, source_height=2, launch_angles_deg=[-2,0,2])`<br><br>• `AtmosphericRayResult` |
| `AtmosphericRayResult` | `dataclass` | **Ray-tracing solution.**<br>• `ranges`, `heights`, `travel_times` [s]<br>• `turning_points`, `ground_reflections`<br>• `.plot()` (ray paths) | `r.heights, r.turning_points` |
| `atmospheric_parabolic_equation` | `function` | **Relative-level field from the Green's Function PE (Salomons App. H).**<br>• `frequency_hz`, `profile`, `source_height` [m]<br>• `impedance` or `flow_resistivity` σ, `model`<br>• `max_range`/`max_height`/`range_step`/`height_step` [m] | `pe = environment.atmospheric_parabolic_equation(500, p, source_height=2, flow_resistivity=2e5)`<br><br>• `AtmosphericPEResult` |
| `AtmosphericPEResult` | `dataclass` | **GFPE relative-level field (dB re free field).**<br>• `ranges`, `heights`, `relative_level` (z×r)<br>• `normalized_impedance`<br>• `.level_at_height(z)`, `.plot()` | `pe.level_at_height(2.0)` |
| `task_based_exposure` | `function` | **Task-based daily exposure LEX,8h + U (ISO 9612 Clause 9).**<br>• `tasks`: sequence of `Task`<br>• `instrument`: 'class1'/'class2'/'personal_exposimeter' (Default)<br>• `u3` [dB] (Default: 1.0)<br>• `include_duration_uncertainty` (Default: True)<br>• `warn` (Default: True) | `res = hearing.task_based_exposure(tasks)`<br><br>• `ExposureResult` with per-task breakdown |
| `job_based_exposure` | `function` | **Job-based daily exposure LEX,8h + U (ISO 9612 Clause 10).**<br>• `samples` Lp,A,eqT [dB]<br>• `effective_duration_hours` Te [h]<br>• `instrument`, `u3`<br>• `n_workers`/`sample_duration_hours`: Table 1 check | `res = hearing.job_based_exposure(samples, 7.5)`<br><br>• `ExposureResult` (Eq C.9 / Table C.4 budget) |
| `full_day_exposure` | `function` | **Full-day daily exposure LEX,8h + U (ISO 9612 Clause 11).**<br>• `samples` whole-day Lp,A,eqT [dB]<br>• `effective_duration_hours` Te [h]<br>• `instrument`, `u3`, `warn` | `res = hearing.full_day_exposure(samples, 9.25)`<br><br>• `ExposureResult`; 3 samples spanning ≥3 dB advise |
| `Task` | `dataclass` | **One task of a task-based measurement (ISO 9612 Clause 9).**<br>• `samples` [dB], `duration_hours` [h]<br>• `duration_samples`/`duration_range` (for u1b)<br>• `label`, `instrument` | `Task(samples=(80.1, 82.2), duration_hours=5.0)` |
| `ExposureResult` | `dataclass` | **Daily exposure and uncertainty (ISO 9612).**<br>• `lex_8h` [dB]<br>• `combined_standard_uncertainty` u [dB]<br>• `expanded_uncertainty` U = 1.65 u [dB]<br>• `upper_limit` = LEX,8h + U [dB]<br>• `strategy`, `sampling_advisory`, `instrument`, `tasks`<br>• `.report(path, ...)`: ISO 9612 Clause 15 measurement report with the Directive 2003/10/EC assessment → PDF<br>• takes `lex_8h`, `combined_standard_uncertainty`, `expanded_uncertainty`, `strategy`, `coverage_factor`, `lp_aeqte`, `effective_duration_hours`, `u1`, `c1u1`, `u2`, `u3`, `n_samples`, `instrument`, `tasks`, `sample_range_db`, `n_workers`, `sample_duration_hours`; `sampling_advisory` is read-only, read from them | `res.report("lex.pdf", metadata=ReportMetadata(client="..."))` |
| `TaskContribution` | `dataclass` | **Per-task breakdown inside `ExposureResult.tasks` (ISO 9612 Clause 9).**<br>• `label`, `lp_aeqt` (Eq. 7), `duration_hours`<br>• `lex_8h_contribution` (Eq. 8) [dB]<br>• uncertainty terms `u1a`, `u1b`, `c1a`, `c1b`, `u2`, `u3`<br>• takes `label`, `lp_aeqt`, `duration_hours`, `lex_8h_contribution`, `n_samples`, `sample_range_db`, `u1a`, `c1a`, `u1b`, `c1b`, `u2`, `u3`; `spread_advisory` is read-only, read from them | `res.tasks[0].lex_8h_contribution` |
| `table_c4_contribution` | `function` | **Sampling contribution c₁u₁ [dB] from Table C.4 (ISO 9612 job/full-day).**<br>• `n_samples`: N (clamped to [3, 30])<br>• `u1`: sampling standard uncertainty [dB]<br>• bilinear interpolation, anchored at u₁ = 0 | `table_c4_contribution(6, 2.0)  # 1.4` |
| `minimum_cumulative_duration_hours` | `function` | **Minimum cumulative measurement duration [h] (ISO 9612 Table 1).**<br>• `n_workers`: group size n_G (> 40 → 17 h; the standard advises splitting the group) | `minimum_cumulative_duration_hours(18)  # 10.75` |
| `COVERAGE_FACTOR` | `float` | **ISO 9612 coverage factor k = 1.65 (Clause 14).**<br>One-sided 95 % confidence: U = 1.65 u, upper limit LEX,8h + U | `COVERAGE_FACTOR  # 1.65` |
| `real_ear_attenuation` | `function` | **The attenuation of a protector on a panel of subjects, its spread and its uncertainty (ISO 4869-1 4.6 and Annex A).**<br>• `attenuation_db`: `(subjects, bands)` individual attenuations [dB], or `open_threshold_db` with `occluded_threshold_db` (4.6.2: occluded minus open)<br>• `frequencies` [Hz] (Default: 125 Hz to 8 kHz for seven bands, from 63 Hz for eight)<br>• u = s/√N, U95 = 2u, at full precision | `r = hearing.real_ear_attenuation(grid)`<br><br>• `RealEarAttenuationResult`; `r.attenuation_db` feeds `assumed_protection_value`, `hml_rating` and `snr_rating` unchanged |
| `RealEarAttenuationResult` | `dataclass` | **ISO 4869-1 measurement.**<br>• `attenuation_db`, `mean_db`, `standard_deviation_db`, `standard_uncertainty_db`, `expanded_uncertainty_db` [dB]<br>• `frequencies` [Hz], `subjects`<br>• `.plot()`: mean attenuation downwards on the IEC 60263 grid, Clause 6 l) | `r.expanded_uncertainty_db` |
| `assess_attenuation_difference` | `function` | **Do two attenuation measurements differ significantly? (ISO 4869-1 Annex B).**<br>• `first`, `second`: a `RealEarAttenuationResult` or its means [dB]<br>• `first_expanded_uncertainty_db`, `second_expanded_uncertainty_db`: U95 for bare means [dB]<br>• significant when \|m1 − m2\| > √(U95,1² + U95,2²) | `d = hearing.assess_attenuation_difference(r1, r2)`<br><br>• `AttenuationDifferenceResult` (`difference_db`, `criterion_db`, `significant`, `significant_frequencies`, `.plot()`) |
| `AttenuationDifferenceResult` | `dataclass` | **Annex B verdict per band.**<br>• `difference_db`, `criterion_db` [dB], `significant` per band, `any_significant`<br>• no truth value: read `significant`<br>• `.plot()`<br>• takes `first_mean_db`, `second_mean_db`, `first_expanded_uncertainty_db`, `second_expanded_uncertainty_db`, `frequencies`; `difference_db`, `criterion_db`, `significant` are read-only, read from them | `d.significant_frequencies` |
| `minimum_significant_difference` | `function` | **√2·U95, the minimum difference for two equal uncertainties (ISO 4869-1 B.1.1, B.2).**<br>• `expanded_uncertainty_db` [dB], a number or an array<br>• B.1.1 feeds it the rounded 2,3 dB of Table A.2 and prints 3,3 dB | `hearing.minimum_significant_difference(2.3)  # 3.25` |
| `reat_expanded_uncertainty` | `function` | **Typical U95 per band from Table A.2 (within a laboratory) or B.2 (between laboratories).**<br>• `frequencies` [Hz]<br>• `protector`: 'earplug' or 'earmuff'<br>• `between_laboratories` (Default: False) | `hearing.reat_expanded_uncertainty([250, 8000], protector='earplug')` |
| `ProtectorUncertaintyBudget` | `dataclass` | **The three standard uncertainties of Table A.1: `method_db`, `equipment_db`, `environment_db` [dB].**<br>• `combined_db` = root sum of squares, `expanded_db` = 2u, both derived | `hearing.REAT_WITHIN_LABORATORY_UNCERTAINTY['earmuff']['250 Hz up to 4 kHz'].expanded_db` |
| `REAT_WITHIN_LABORATORY_UNCERTAINTY` / `REAT_BETWEEN_LABORATORY_UNCERTAINTY` | `mapping` | **Tables A.2 and B.2 of ISO 4869-1: the typical budget by protector ('earplug', 'earmuff') and frequency range.** | `hearing.REAT_BETWEEN_LABORATORY_UNCERTAINTY['earplug']` |
| `REAT_FREQUENCY_RANGES` | `constant` | **The three columns of Tables A.2 and B.2: 'below 250 Hz', '250 Hz up to 4 kHz', 'above 4 kHz'.** | `hearing.REAT_FREQUENCY_RANGES` |
| `REAT_FIELD_VARIATION_LIMITS` | `constant` | **Table 1 of ISO 4869-1: (lowest free-field rejection, allowable field variation) [dB].**<br>25 → 20, 20 → 15, 15 → 10, 10 → 5; below 10 dB the microphone is not suitable | `hearing.REAT_FIELD_VARIATION_LIMITS[0]  # (25.0, 20.0)` |
| `allowable_field_variation` | `function` | **Table 1 lookup.**<br>• `free_field_rejection_db` [dB]; below 10 dB raises | `hearing.allowable_field_variation(18.0)  # 10.0` |
| `check_reat_sound_field` | `function` | **Is the test site's sound field diffuse enough? (ISO 4869-1 4.2.2).**<br>• `position_levels_db`: levels at 'front', 'back', 'left', 'right', 'up', 'down' [dB]<br>• `reference_levels_db` [dB]<br>• `rotation_levels_db` with `free_field_rejection_db` for b), from 500 Hz | `c = hearing.check_reat_sound_field(levels, reference)`<br><br>• `ReatSoundFieldCheck` |
| `ReatSoundFieldCheck` | `dataclass` | **4.2.2 verdict.**<br>• `uniform` (±2,5 dB), `balanced` (right-left 3 dB), `diffuse` (Table 1) per band<br>• `directionality_judged`: whether b) was measured<br>• `passes` needs a) and b); no truth value<br>• `.plot()` | `c.passes` |
| `assumed_protection_value` | `function` | **Assumed protection value APVfx = mf − α·sf (ISO 4869-2 Clause 5, Formula (1)).**<br>• `attenuation`: `(subjects, bands)` ISO 4869-1 grid [dB]<br>• `performance`: 50/75/80/84/90/95/98 % from Table 1 (Default: 84)<br>• `frequencies`: mid-band [Hz] (Default: the eight octaves from 63 Hz) | `apv = hearing.assumed_protection_value(grid)`<br><br>• `AssumedProtectionResult` (`apv`, `mean_attenuation`, `standard_deviation`, `alpha`, `subjects`) |
| `octave_band_protected_level` | `function` | **Effective A-weighted level, octave-band method (ISO 4869-2 Formula (2)).**<br>• `noise_levels`: unweighted octave-band levels [dB]<br>• `apv`: assumed protection values or the result carrying them<br>• `a_weighting`: [dB] (Default: IEC 61672-1 Table 3) | `res = hearing.octave_band_protected_level(noise, apv)`<br><br>• `ProtectedLevelResult` (`effective_level`, `reported_level`, `noise_reduction`, `band_levels`) |
| `hml_rating` / `hml_protected_level` | `function` | **H, M and L values and their application (ISO 4869-2 Clause 7).**<br>• `hml_rating(attenuation, performance=84)`: Formulae (3)-(15) over the eight reference noises of Table 2<br>• `hml_protected_level(l_p_a, l_p_c, rating)`: Formulae (16)-(18), consuming the rounded triple | `res = hearing.hml_protected_level(104.0, 103.0, hearing.hml_rating(grid))`<br><br>• `HMLRatingResult` (`high`, `medium`, `low`, `reported`, `subject_h/m/l`, `predicted_reduction`) |
| `snr_rating` / `snr_protected_level` | `function` | **Single number rating and its application (ISO 4869-2 Clause 8).**<br>• `snr_rating(attenuation, performance=84)`: Formulae (19)-(22) against the pink noise of Table 3<br>• `snr_protected_level(rating, l_p_c=...)`: Formula (23); or `l_p_a=` with `c_minus_a=` for Formula (24) | `res = hearing.snr_protected_level(hearing.snr_rating(grid), l_p_c=103.0)`<br><br>• `SNRRatingResult` (`snr`, `reported`, `subject_snr`, `mean`, `standard_deviation`) |
| `AssumedProtectionResult` / `HMLRatingResult` / `SNRRatingResult` / `ProtectedLevelResult` | `dataclass` | **ISO 4869-2 protector results.**<br>• Ratings expose the unrounded fit and `reported`, the integer the standard publishes<br>• `ProtectedLevelResult.reported_level` rounds halves away from zero, not to even | `apv = hearing.assumed_protection_value(grid)` |
| `PROTECTION_PERFORMANCES` | `dict` | **Table 1: the constant α for each protection performance x (ISO 4869-2).**<br>50 → 0.00, 75 → 0.67, 80 → 0.84, 84 → 1.00, 90 → 1.28, 95 → 1.64, 98 → 2.00 | `hearing.PROTECTION_PERFORMANCES[84]` |
| `PROTECTOR_OCTAVE_BANDS` / `PROTECTOR_A_WEIGHTING` | `tuple` | **The eight octave bands of Formula (2) and frequency weighting A at them.**<br>63 Hz to 8 kHz; the weighting is IEC 61672-1:2013 Table 3, which ISO 4869-2 reprints as its Table B.1 | `hearing.PROTECTOR_OCTAVE_BANDS` |
| `HML_REFERENCE_NOISES` / `HML_REFERENCE_C_MINUS_A` / `HML_REFERENCE_D` | `tuple` | **Table 2: the eight reference noises the HML method is fitted on.**<br>A-weighted octave-band levels 125 Hz to 8 kHz, their (LpC − LpA) and the empirical weights d | `hearing.HML_REFERENCE_NOISES` |
| `active_insertion_loss` | `function` | **The active insertion loss of an ANR earmuff, its lower ear and its uncertainty (ISO 4869-6 5.4, 5.5 b) and Annex A).**<br>• `passive_levels_db`, `active_levels_db`: MIRE levels, `(subjects, 2, bands)` [dB], left ear first<br>• or `insertion_loss_db` per ear, or already the lower ear<br>• `frequencies` [Hz] (Default: the one-third octaves 50 Hz or 100 Hz to 10 kHz, or the octaves 63 Hz or 125 Hz to 8 kHz, by count) | `ail = hearing.active_insertion_loss(passive_levels_db=off, active_levels_db=on)`<br><br>• `ActiveInsertionLossResult` |
| `ActiveInsertionLossResult` | `dataclass` | **ISO 4869-6 active insertion loss.**<br>• `insertion_loss_db` (lower ear), `per_ear_db`<br>• `mean_db`, `standard_deviation_db`, `standard_uncertainty_db`, `expanded_uncertainty_db` [dB]<br>• `.plot()` | `ail.expanded_uncertainty_db` |
| `anr_total_attenuation` | `function` | **Total attenuation of an ANR earmuff and its ISO 4869-2 ratings at 84 % (ISO 4869-6 5.5).**<br>• `reat`: ISO 4869-1 result or `(subjects, octaves)` grid, 63 Hz or 125 Hz to 8 kHz<br>• `insertion_loss`: `ActiveInsertionLossResult` or a grid on the one-third octaves<br>• passive side interpolated linearly in hertz, as ISO's calculation example does | `anr = hearing.anr_total_attenuation(reat, ail)`<br><br>• `AnrTotalAttenuationResult` (`total_octave_db`, `assumed_protection`, `hml`, `snr`) |
| `AnrTotalAttenuationResult` | `dataclass` | **ISO 4869-6 total attenuation.**<br>• `total_octave_db` (Formula (1)), `total_third_octave_db`, `reat_third_octave_db`, `insertion_loss_db` [dB]<br>• `assumed_protection`, `hml`, `snr` at 84 %<br>• `.plot()` | `anr.hml.reported` |
| `assess_anr_linearity` | `function` | **Up to what external level does an ANR earmuff stay linear? (ISO 4869-6 5.4.4).**<br>• `external_levels_db`: 5 dB steps up to 110 dB<br>• `ear_levels_db`: 125 Hz octave level at the ear, external levels on the last axis<br>• or `ear_third_octave_levels_db` (100, 125, 160 Hz on the last axis) | `hearing.assess_anr_linearity([90, 95, 100], ears).maximum_linear_level_db`<br><br>• `AnrLinearityResult` |
| `AnrLinearityResult` | `dataclass` | **5.4.4 verdict.**<br>• `maximum_linear_level_db`, `increments_db`, `linear` per ear and step<br>• `passes`, `linear_to_110_db`; no truth value<br>• `.plot()` | `lin.maximum_linear_level_db` |
| `ANR_WITHIN_LABORATORY_UNCERTAINTY` | `constant` | **Table A.2 of ISO 4869-6: the typical budget of the mean active insertion loss (0.6, 0.3, 0.4 dB) as a `ProtectorUncertaintyBudget`.** | `hearing.ANR_WITHIN_LABORATORY_UNCERTAINTY.expanded_db  # 1.56` |
| `PINK_NOISE_A_WEIGHTED` | `tuple` | **Table 3: the pink noise the SNR method is defined against.**<br>A-weighted octave-band levels 125 Hz to 8 kHz of a pink noise whose C-weighted level is 100 dB | `hearing.PINK_NOISE_A_WEIGHTED` |
| `earmuff_insertion_loss` | `function` | **The insertion loss of an earmuff on the acoustic test fixture, and its uncertainty (ISO 4869-3 5.4, Annex B).**<br>• `open_levels_db`, `occluded_levels_db`: one spectrum or one per fitting [dB]<br>• `frequencies` [Hz] (Default: 63 Hz to 8 kHz, 22 bands)<br>• `isolation_cup_levels_db`: 5.3's 10 dB check<br>• `fixture_uncertainty_db`, `sound_field_uncertainty_db`, `equipment_uncertainty_db` (Default: 0.3, 0.5, 0.2)<br>• a screening quantity, not the real-ear attenuation ISO 4869-2 takes | `il = hearing.earmuff_insertion_loss(open_levels, fittings)`<br><br>• `EarmuffInsertionLossResult` (`insertion_loss_db`, `reported_db`, `expanded_uncertainty_db`, `budget(f)`) |
| `EarmuffInsertionLossResult` | `dataclass` | **Insertion loss per band, per fitting, with the Annex B uncertainty and the checks of 5.3 and 5.4.3.**<br>• `repetitions_sufficient`, `floor_adequate`, `level_stable`, `response_smooth`<br>• `.plot()` draws it increasing downwards (Clause 6) | `il.reported_db` |
| `InsertionLossUncertaintyBudget` | `dataclass` | **The five standard uncertainties of ISO 4869-3 Table B.1 [dB].**<br>• `combined_db` (B.2), `expanded_db` = 2u | `il.budget(1000.0).expanded_db` |
| `EARMUFF_INSERTION_LOSS_UNCERTAINTY` | `constant` | **ISO 4869-3 Table B.1: the typical budget, u = 1.3 dB, U = 2.6 dB.** | `hearing.EARMUFF_INSERTION_LOSS_UNCERTAINTY.expanded_db  # 2.55` |
| `EARMUFF_TEST_BANDS_HZ` | `constant` | **The 22 one-third-octave bands of ISO 4869-3 5.3, 63 Hz to 8 kHz** [Hz]. | `hearing.EARMUFF_TEST_BANDS_HZ` |
| `check_random_incidence_field` | `function` | **Is the random-incidence field of the test site good enough? (ISO 4869-3 5.2.2).**<br>• the diffuse-field check of ISO 8253-2 5.3 with this standard's Table 1<br>• `front_to_random_index_db` may be per band, NaN where unsuitable (the fixture itself, Table A.1) | `c = hearing.check_random_incidence_field(six, ref, directional_levels_db=d, front_to_random_index_db=5.0)`<br><br>• `DiffuseSoundFieldCheck` |
| `RANDOM_INCIDENCE_VARIATION_LIMITS` | `constant` | **ISO 4869-3 Table 1: (lowest front-to-random index, allowable variation) [dB].**<br>5 → 5 (the text's "at least 5 dB"), 4 → 4; below 4 dB not suitable | `hearing.RANDOM_INCIDENCE_VARIATION_LIMITS` |
| `ATF_FRONT_TO_RANDOM_INDEX_DB` | `mapping` | **ISO 4869-3 Table A.1: the front-to-random index of a fixture with a WS1P microphone, 500 Hz to 8 kHz** [dB]. | `hearing.ATF_FRONT_TO_RANDOM_INDEX_DB[2000.0]  # 6.3` |
| `check_plane_progressive_wave` | `function` | **Is the plane progressive wave of the test site good enough? (ISO 4869-3 5.2.3).**<br>• `end_face_levels_db`: `(2, bands)` [dB], within 2 dB<br>• `facing_levels_db`, `facing_away_levels_db`, `front_to_rear_index_db` (> 15 dB): at least 10 dB from 500 Hz | `hearing.check_plane_progressive_wave(faces, facing_levels_db=f, facing_away_levels_db=a, front_to_rear_index_db=18.0)`<br><br>• `PlaneProgressiveWaveCheck` |
| `verify_fixture_isolation` | `function` | **Does the test fixture isolate its microphone well enough? (ISO 4869-3 5.1.4).**<br>• `open_levels_db`, `cup_levels_db` [dB]<br>• at least 50 dB (63 Hz to 250 Hz), 65 dB (315 Hz to 4 kHz), 55 dB above | `hearing.verify_fixture_isolation(open_levels, cup_levels)`<br><br>• `FixtureIsolationCheck` (`isolation_db`, `required_db`, `passes`) |
| `PlaneProgressiveWaveCheck` / `FixtureIsolationCheck` | `dataclass` | **ISO 4869-3 test-site verdicts, band by band; `bool()` raises.** | `c.passes` |
| `INSTRUMENT_U2` | `mapping` | **Instrument standard uncertainty u2 [dB] (ISO 9612 Table C.5).**<br>Keyed by `'class1'` (0.7), `'class2'` (1.5), `'personal_exposimeter'` (1.5) | `INSTRUMENT_U2['class1']  # 0.7` |
| `OccupationalExposureWarning` | `warning class` | **ISO 9612 sampling advisory.**<br>Emitted for the 3 dB task spread (Clause 9.3), c₁u₁ > 3.5 dB (Clause 10.4) or a short Table 1 cumulative duration | `warnings.simplefilter('error', OccupationalExposureWarning)` |
| `SoundPowerWarning` | `warning class` | **ISO 3744/3746/3741/9614-2/9295 qualification issue.**<br>Emitted when the background margin is below the criterion, K2 exceeds the validity limit, a band's power is negative, or the room fails qualification; levels are then upper bounds. Under ISO 9295 it is also emitted for a band outside the 16 kHz octave (11.2 kHz to 22.4 kHz), for a room constant taken from the air absorption below 10 kHz (clause 7.2), and for an FFT noise bandwidth wider than 112 Hz (clause 8.5.2) | `warnings.simplefilter('error', SoundPowerWarning)` |
| `AbsorptionWarning` | `warning class` | **ISO 354 advisory.**<br>Emitted for a room below 150 m³, a sample area outside 10-12 m², an out-of-range temperature, or a non-physical α_s ≤ 0; the result still returns | `warnings.simplefilter('error', AbsorptionWarning)` |
| `speech_intelligibility_index` | `function` | **Speech Intelligibility Index (ANSI S3.5-1997, any of its four band procedures).**<br>• `speech_spectrum`: equivalent speech spectrum levels [dB SPL] on the procedure's bands, or a vocal-effort name 'normal'/'raised'/'loud'/'shout' ('normal' only outside the one-third-octave procedure)<br>• `noise_spectrum`: equivalent noise spectrum levels [dB SPL] (Default: None → quiet, −80 dB)<br>• `threshold`: equivalent hearing threshold [dB HL] (Default: None → 0)<br>• `method`: one of `SII_METHODS` (Default: 'one-third-octave')<br>• `band_importance`: alternative `Ii` per band (Default: None → the procedure's table) | `res = speech.speech_intelligibility_index("normal", noise_spectrum=[40.0]*18)`<br><br>• `SIIResult`; `res.sii` = 0.066 |
| `standard_speech_spectrum` | `function` | **Standard speech spectrum level by vocal effort (ANSI S3.5-1997 Table 3).**<br>• `vocal_effort`: 'normal', 'raised', 'loud' or 'shout' (Default: 'normal') | `u = speech.standard_speech_spectrum('raised')`<br><br>• 18 band levels [dB SPL] |
| `standard_speech_spectra` | `function` | **Plottable standard speech spectra by vocal effort (ANSI S3.5-1997 Table 3).**<br>• `vocal_efforts`: a name or sequence of 'normal'/'raised'/'loud'/'shout' (Default: the full family) | `res = speech.standard_speech_spectra()`<br><br>• `StandardSpeechSpectrum`; `res.plot()` |
| `StandardSpeechSpectrum` | `dataclass` | **Standard speech spectrum result.**<br>• `frequencies`: the 18 band centres [Hz]<br>• `vocal_efforts`: the efforts carried<br>• `levels`: `Ui` per effort, `(len(vocal_efforts), 18)` [dB SPL]<br>• `.plot()`: the speech spectrum level vs one-third-octave band, one line per effort | `res.levels, res.vocal_efforts` |
| `SIIResult` | `dataclass` | **SII result.**<br>• `sii`: index in [0, 1]<br>• `band_audibility`: Ai per band (§5.8)<br>• `band_importance`: Ii used<br>• `frequencies` [Hz]<br>• `speech_spectrum` / `disturbance` / `masking`: Ei′ / Di / Zi per band [dB]<br>• `level_distortion`: Li per band (§5.7)<br>• `method`: the band procedure used<br>• `.plot()` | `res.sii, res.band_audibility` |
| `SII_METHODS` | `constant` | **The four ANSI S3.5-1997 band procedures, in the order of its Tables 1 to 4.**<br>`('critical-band', 'equally-contributing', 'one-third-octave', 'octave')`, i.e. 21, 17, 18 and 6 bands | `for m in SII_METHODS: ...` |
| `sii_procedure` | `function` | **Tabulated band table of one ANSI S3.5-1997 band procedure (Tables 1–4).**<br>• `method`: one of `SII_METHODS` (Default: 'one-third-octave') | `proc = speech.sii_procedure('octave')`<br><br>• `SIIProcedure`; `proc.plot()` |
| `SIIProcedure` | `dataclass` | **ANSI S3.5-1997 band-procedure constants.**<br>• `method`: the procedure name<br>• `frequencies`: nominal band centres [Hz]<br>• `band_edges`: band limits [Hz], one more than the band count<br>• `band_importance`: `Ii`<br>• `internal_noise`: `Xi` [dB SPL]<br>• `speech_spectrum`: `Ui`, normal vocal effort [dB SPL]<br>• `.plot()`: `Ii` stepped over the band limits | `proc.band_importance, proc.band_edges` |
| `stoi` | `function` | **Short-time objective intelligibility STOI / ESTOI (Taal et al. 2011; Jensen & Taal 2016).**<br>• `clean`: clean reference (1D)<br>• `degraded`: degraded/processed signal (1D, same length)<br>• `fs` [Hz] (resampled to 10 kHz internally)<br>• `extended`: use ESTOI (Default: False) | `d = speech.stoi(clean, degraded, fs)`<br><br>• `STOIResult`; `d.value` in ~[0, 1] (1 if identical) |
| `STOIResult` | `dataclass` | **STOI / ESTOI result.**<br>• `value`: the intelligibility index<br>• `extended`: True for ESTOI<br>• `segment_scores`: per-segment intermediate<br>• `band_scores`: per-band mean correlation (STOI; None for ESTOI)<br>• `band_frequencies` [Hz]<br>• `fs` (10 kHz)<br>• `.plot()` | `res.value, res.band_scores` |
| `thd` | `function` | **Total harmonic distortion (IEC 60268-3 14.12.2–3).**<br>• `signal` (1D), `fs` [Hz]<br>• `fundamental` [Hz] (Default: None → largest peak)<br>• `kind`: 'F' rel. fundamental or 'R' rel. total RMS (Default: 'F')<br>• `n_harmonics` (Default: 10)<br>• `window` (Default: 'hann') | `thd(sig, fs, 1000.0, kind="F")`<br><br>• ratio (0..) |
| `harmonic_distortion` | `function` | **nth-order harmonic distortion dₙ (IEC 60268-3 14.12.5).**<br>• `signal`, `fs`, `fundamental` [Hz], `order` n (≥ 2) | `harmonic_distortion(sig, fs, fundamental=1000.0, order=2)`<br><br>• ratio (aₙ rel. total RMS) |
| `thd_plus_noise` | `function` | **THD+N ratio (AES17-2015 6.3.1).**<br>• `signal`, `fs`, `fundamental` (Default: None)<br>• `notch_q`: effective Q of the applied notch, 1.2–3 (Default: 2.0)<br>• `bandwidth`: AES17 chain upper edge [Hz] (Default: 20000; None = full Nyquist); 20 Hz high-pass included<br>• `as_db`: 20·lg(ratio) dB (Default: False)<br>• `window`: FFT window for auto-detection (Default: 'hann') | `thd_plus_noise(sig, fs, 1000.0)`<br><br>• ratio, or dB if `as_db` |
| `sinad` | `function` | **Signal-to-noise-and-distortion ratio, dB (derived from AES17 THD+N).**<br>• `signal`, `fs`, `fundamental` (Default: None), `notch_q` (Default: 2.0), `bandwidth` (Default: 20000)<br>= −(THD+N in dB) | `sinad(sig, fs, 1000.0)`<br><br>• SINAD [dB] |
| `dynamic_range` | `function` | **Dynamic range (AES17-2015 6.4.1), dB CCIR-RMS.**<br>• `signal`, `fs`, `fundamental` (Default: None → 997 Hz)<br>• `notch_q` (Default: 2.0), `bandwidth` (Default: 20000)<br>• `full_scale`: digital full-scale peak amplitude (Default: 1.0)<br>= full-scale sine / CCIR-RMS-weighted notched residual | `dynamic_range(out, fs, 997.0)`<br><br>• dB CCIR-RMS |
| `idle_channel_noise` | `function` | **Idle channel noise level (AES17-2015 6.4.2), dBFS CCIR-RMS.**<br>• `signal` (idle output, 1D), `fs`<br>• `bandwidth` (Default: 20000)<br>• `full_scale` (Default: 1.0)<br>= CCIR-RMS-weighted RMS re full scale | `idle_channel_noise(idle, fs)`<br><br>• dBFS CCIR-RMS (−inf for digital zero) |
| `weighted_thd` | `function` | **Weighted THD (IEC 60268-3 14.12.11).**<br>• `signal`, `fs`, `fundamental` (Default: None)<br>• `weighting`: '468' (ITU-R BS.468-4 / IEC 60268-1, the 14.12.11 network), 'A' or 'C' (Default: '468')<br>• `notch_q` (Default: 2.0)<br>• valid for fundamentals 31.5–400 Hz | `weighted_thd(sig, fs, 100.0)`<br><br>• ratio |
| `itu_r_468_weighting` | `function` | **ITU-R BS.468-4 weighting response (clause 1, Fig. 1a).**<br>• `frequencies` [Hz] (≥ 0)<br>• the Fig. 1a network evaluated in closed form, which Table 1 samples to 0.1 dB; DC → −inf | `itu_r_468_weighting([6300.0])  # +12.2167`<br><br>• dB re 1 kHz |
| `modulation_distortion` | `function` | **Modulation distortion d_m,2 / d_m,3 (IEC 60268-3 14.12.7).**<br>• `signal`, `fs`, `f_low` [Hz], `f_high` [Hz]<br>• arithmetic sideband sums over the f₂ amplitude (14.12.7.2 g–h) | `modulation_distortion(sig, fs, f_low=60.0, f_high=7000.0).d2`<br><br>• `ModulationDistortionResult` |
| `ModulationDistortionResult` | `dataclass` | **Modulation distortion result.**<br>• `d2` / `d3`: the IEC per-order values<br>• `smpte`: combined-RMS analyzer convention (not an IEC quantity) | `res.d2, res.d3, res.smpte` |
| `difference_frequency_distortion` | `function` | **Difference-frequency distortion d_d,n (IEC 60268-3 14.12.8).**<br>• `signal`, `fs`, `f1` < `f2` [Hz]<br>• `order`: 2 or 3 (Default: 2)<br>• ref. U₂,ref = 2·U₂,f₂; 3rd order sums arithmetically | `difference_frequency_distortion(sig, fs, f1=13e3, f2=14e3, order=2)`<br><br>• ratio |
| `total_difference_frequency_distortion` | `function` | **Total difference-frequency distortion (IEC 60268-3 14.12.10).**<br>• `signal`, `fs`<br>• `f1` (Default: 8000), `f2` (Default: 11950) [Hz]<br>= √(a²_{f₂−f₁} + a²_{2f₁−f₂}) / (a_{f₁} + a_{f₂}) | `total_difference_frequency_distortion(sig, fs)`<br><br>• ratio |
| `dynamic_intermodulation_distortion` | `function` | **Dynamic intermodulation DIM (IEC 60268-3 14.12.9).**<br>• `signal`, `fs`<br>• `f_sine` [Hz] (Default: 15000)<br>• `f_square` [Hz] (Default: 3150) | `dynamic_intermodulation_distortion(sig, fs)`<br><br>• ratio (products rel. 15 kHz sine) |
| `harmonic_analysis` | `function` | **Full harmonic analysis (THD, THD+N, SINAD).**<br>• `signal`, `fs`, `fundamental` (Default: None)<br>• `n_harmonics` (Default: 10), `notch_q` (Default: 2.0), `bandwidth` (Default: 20000)<br>• `window`: FFT window (Default: 'hann') | `res = electroacoustics.harmonic_analysis(sig, fs, 1000.0)`<br><br>• `HarmonicDistortionResult` |
| `HarmonicDistortionResult` | `dataclass` | **Harmonic analysis result.**<br>• `fundamental` [Hz]<br>• `harmonic_frequencies` / `harmonic_amplitudes`<br>• `thd_f` / `thd_r` / `thd_plus_noise`: ratios<br>• `sinad_db` [dB]<br>• `.plot()`: annotated harmonic spectrum | `res.thd_f, res.sinad_db` |
| `transfer_function` | `function` | **Frequency-response estimate H1/H2 (Bendat & Piersol).**<br>• `x` (input), `y` (output), `fs` [Hz]<br>• `estimator`: 'H1' or 'H2' (Default: 'H1')<br>• `nperseg` (Default: None), `overlap` (Default: 0.5) | `res = electroacoustics.transfer_function(x, y, fs)`<br><br>• `FrequencyResponseResult` |
| `coherence` | `function` | **Ordinary coherence γ² (Bendat & Piersol).**<br>• `x`, `y`, `fs` [Hz]<br>• `nperseg` (Default: None), `overlap` (Default: 0.5)<br>= \|Gxy\|²/(Gxx·Gyy) ∈ [0, 1] | `f, g = electroacoustics.coherence(x, y, fs)` |
| `FrequencyResponseResult` | `dataclass` | **Frequency-response result.**<br>• `frequencies` [Hz]<br>• `response`: complex H(f)<br>• `magnitude_db` / `phase` [rad]<br>• `coherence`: γ²(f)<br>• `estimator`<br>• `.plot()`: Bode + coherence | `res.magnitude_db, res.coherence` |
| `synchronized_sweep_signal` | `function` | **Synchronized exponential sweep (Novak et al. 2015, Eqs. 47/49).**<br>• `fs`, `f1` < `f2` [Hz], `seconds` (quantized by the rounding)<br>• `amplitude` (Default: 1.0), `fade` (Default: 0.0)<br>Rate L = round(f1·T̃/ln(f2/f1))/f1 → f1·L integer, so a L·ln(n) shift equals the nth harmonic and harmonic phases become system properties | `x = electroacoustics.synchronized_sweep_signal(48000, 20.0, 6000.0, 4.0)`<br><br>• sweep samples (duration L·ln(f2/f1)) |
| `swept_sine_distortion` | `function` | **Harmonic separation and THD(f) from one sweep (Farina 2000 / Novak et al. 2015).**<br>• `recorded`, `fs`, plus the generator parameters `f1`, `f2`, `seconds`<br>• `method`: 'synchronized' (Default; analytic deconvolution, meaningful phases) / 'farina' (classical ESS, magnitudes only)<br>• `n_harmonics` (Default: 5), `ir_length` (Default: largest power of two fitting the closest arrivals)<br>• `amplitude` (Default: 1.0), `fade` (Default: generator default), `remove_dc` (Default: True) | `res = electroacoustics.swept_sine_distortion(y, fs, 20.0, 6000.0, 4.0)`<br><br>• `SweptSineDistortionResult` |
| `SweptSineDistortionResult` | `dataclass` | **Swept-sine harmonic separation.**<br>• `frequencies` [Hz], `harmonic_responses`: complex H₁..H_N, `harmonic_irs` (windowed, centred), `delays` L·ln(n) [s]<br>• `thd_frequencies` [Hz], `thd`, `distortion_ratios`: \|Hₙ(n·f)\|/\|H₁(f)\| per order<br>• `fs`, `f1`, `f2`, `duration`, `rate` L, `method`, `n_harmonics`<br>• `.plot()`: \|Hₙ\| magnitudes + THD(f) | `res.thd, res.harmonic_responses` |
| `radiating_piston` | `function` | **Radiation of a rigid baffled circular piston (Beranek & Mellow §4.19/§13.7).**<br>• `radius` a [m], `frequencies` [Hz]<br>• `speed_of_sound` (Default: 343), `density` (Default: 1.206)<br>• `angles_rad`: directivity polar angles_rad [rad] (Default: None) | `res = electroacoustics.radiating_piston(0.1, freqs)`<br><br>• `RadiatingPistonResult` |
| `plot_piston_geometry` | `function` | **Baffled piston to scale, optional far-field lobe.**<br>• `radius` a [m]<br>• `angles_rad` [rad] + `directivity` (linear), together<br>• `lobe_label`, `language` | `plot_piston_geometry(0.1, angles_rad=ang, directivity=d)`<br><br>• Also `RadiatingPistonResult.plot_geometry(frequency_index=...)` |
| `piston_resistance` / `piston_reactance` | `function` | **Normalized piston radiation impedance R1 = 1−2J1(x)/x, X1 = 2H1(x)/x, x = 2ka (Beranek & Mellow Eqs. 13.117/13.118).** | `piston_resistance(2.0)  # 0.4233` |
| `piston_directivity` | `function` | **Far-field piston directivity 2·J1(ka·sinθ)/(ka·sinθ).**<br>• `ka`, `theta` [rad] | `piston_directivity(5.0, 0.3)` |
| `piston_directivity_pattern` | `function` | **Far-field directivity (beam) pattern of one or more baffled pistons.**<br>• `ka` (scalar or 1-D)<br>• `angles_rad` [rad] (Default: front hemisphere −90°…+90°) | `p = electroacoustics.piston_directivity_pattern([3, 8, 16])`<br><br>• `PistonDirectivity` |
| `RadiatingPistonResult` | `dataclass` | **Piston radiation result.**<br>• `ka`, `resistance`/`reactance`, `radiation_resistance`/`radiation_reactance` [N·s/m], `radiation_mass` = 8ρa³/3 [kg], `directivity_index` [dB], `directivity`<br>• `.plot()`: R1/X1 vs ka | `res.radiation_mass` |
| `PistonDirectivity` | `dataclass` | **Piston directivity-pattern result.**<br>• `angles_rad` [rad], `ka`, `directivity` (linear), `directivity_db`<br>• `.plot()`: polar beam pattern in dB (family over ka) | `p.plot()` |
| `loudspeaker_characteristics` | `function` | **Rated loudspeaker characteristics for an IEC 60268-5 report.**<br>• `frequencies`, `spl_db` (on-axis SPL), `rated_impedance` R [Ω]<br>• `input_voltage` (Default: √R → 1 W), `distance` (Default: 1 m), `sensitivity_band`, `tolerance_db`<br>• `impedance`, `distortion` panels<br>• `directivity`: `LoudspeakerDirectivity` (23), `ratings`: `LoudspeakerRatings` (18/19) | `res = electroacoustics.loudspeaker_characteristics(f, spl, 8.0)`<br><br>• `LoudspeakerCharacteristics` |
| `LoudspeakerDirectivity` | `dataclass` | **Directional characteristics of the loudspeaker (IEC 60268-5 Clause 23).**<br>• `piston`: a `RadiatingPistonResult` computed with `angles_rad`, or `polar` = (angles_deg, relative_db)<br>• `frequency` [Hz], `index_db` (directivity index, 23.3) | `LoudspeakerDirectivity(piston=res, frequency=2000.0)` |
| `LoudspeakerRatings` | `dataclass` | **Manufacturer-stated ratings (IEC 60268-5 Clauses 18 and 19).**<br>• `frequency_range` (lo, hi) [Hz] (19.1), also the band the 16.1 minimum impedance is scanned over<br>• `noise_power` [W] (18.1), `sinusoidal_power` [W] (18.4), `resonance_frequency` [Hz] (19.2) | `LoudspeakerRatings(frequency_range=(45.0, 22000.0))` |
| `LoudspeakerCharacteristics` | `dataclass` | **Loudspeaker rated-characteristics result (IEC 60268-5).**<br>• `sensitivity_level_db` (1 W/1 m, 20.3/20.4), `effective_range` (21.2), `reference_level_db`, `characteristic_sensitivity_pa`, `minimum_impedance`<br>• `.report()`: IEC 60268-5 fiche (graphs to IEC 60263) | `res.effective_range` |
| `feedback_stability` | `function` | **Gain before feedback of a reinforcement loop (Long, Architectural Acoustics 2e, Eqs. 18.16–18.24).**<br>• `open_loop_gain` Zs [dB] (≈ −6 in an auditorium)<br>• `level_loudspeaker_at_microphone` L(H-M) [dB]<br>• `level_loudspeaker_at_listener` L(H-L) [dB]<br>• `microphone_directivity` DM(θ) [dB] (Default: 0)<br>• `open_microphones` Nm (Default: 1), `stability_margin` [dB] (Default: 10) | `res = electroacoustics.feedback_stability(-6.0, 76.0, 80.0)`<br><br>• `FeedbackStabilityResult` |
| `FeedbackStabilityResult` | `dataclass` | **Gain structure and stability verdict.**<br>• `open_loop_gain`, `feedback_loop_gain`, `nom_correction`, `loop_gain` [dB]<br>• `margin`, `headroom`, `stability_margin` [dB], `is_stable`<br>• `maximum_open_loop_gain`, `maximum_level_at_microphone` [dB]<br>• `.plot()`: gain bars against the oscillation and margin lines<br>• takes `open_loop_gain`, `feedback_loop_gain`, `nom_correction`, `loop_gain`, `stability_margin`, `margin`, `headroom`, `maximum_open_loop_gain`, `maximum_level_at_microphone`, `level_loudspeaker_at_microphone`, `level_loudspeaker_at_listener`, `microphone_directivity`, `open_microphones`; `is_stable` is read-only, read from them | `res.is_stable, res.headroom`<br>`res.plot()` |
| `feedback_loop_gain` / `open_microphone_correction` | `function` | **Feedback building blocks (Long Eqs. 18.18, 18.23).**<br>• `feedback_loop_gain(L_HM, L_HL, microphone_directivity=0)` = `L(H-M) − L(H-L) + DM(θ)` [dB]<br>• `open_microphone_correction(Nm)` = `10 lg Nm` [dB] | `open_microphone_correction(4)  # 6.02` |
| `plot_sound_reinforcement_geometry` | `function` | **Schematic of the feedback loop with each path length annotated.**<br>• `talker_distance`, `microphone_distance`, `listener_distance` [m]<br>• `language` | `plot_sound_reinforcement_geometry(0.3, 4.0, 12.0)` |
| `DEFAULT_STABILITY_MARGIN` / `CARDIOID_RELATIVE_DIRECTIVITY` | `constant` | **Reinforcement defaults (Long Ch. 18).**<br>• 10 dB feedback stability margin for an equalised system<br>• −2 dB cardioid directivity toward the loudspeaker relative to the talker | `feedback_stability(-6.0, 78.0, 80.0, microphone_directivity=CARDIOID_RELATIVE_DIRECTIVITY)` |
| `microphone_characteristics` | `function` | **Rated microphone characteristics for an IEC 60268-4 report.**<br>• `frequencies`, `response_db` (free-field, re the reference frequency), `sensitivity_mv_per_pa` M [mV/Pa]<br>• `reference_frequency` (Default: 1 kHz), `tolerance_db` (Default: 2)<br>• `directivity`: `MicrophoneDirectivity` (13), `noise`: `MicrophoneNoise` (17), `overload`: `MicrophoneOverload` (14.2/15.2), `electrical`: `MicrophoneElectrical` (9/10) | `res = electroacoustics.microphone_characteristics(f, resp, 12.5)`<br><br>• `MicrophoneCharacteristics` |
| `MicrophoneDirectivity` | `dataclass` | **Directional characteristics of the microphone (IEC 60268-4 Clause 13).**<br>• `polar` = (angles_deg, relative_db) (13.1)<br>• `frequency` [Hz], `index_db` (directivity index, 13.2; computed from `polar` when omitted) | `MicrophoneDirectivity(polar=(ang, cardioid), frequency=1000.0)` |
| `MicrophoneNoise` | `dataclass` | **Inherent noise of the microphone (IEC 60268-4 Clause 17).**<br>• `voltage` U_N [V] (17.2 b) **or** `equivalent_level_db` [dB SPL] (17.1), not both<br>• `weighting`: "A" (Default) or "468", the ITU-R BS.468-4 quasi-peak figure; `spectrum` = (frequencies, band_levels_db) | `MicrophoneNoise(voltage=1.25e-6)` |
| `MicrophoneOverload` | `dataclass` | **Overload sound pressure and the distortion it is read from (IEC 60268-4 14.2/15.2).**<br>• `distortion` = (spl_db, thd_percent) (14.2)<br>• `thd_percent` limit (Default: 1), `spl_db` (stated overload level; read off the curve when omitted) | `MicrophoneOverload(distortion=(spl, thd), thd_percent=0.5)` |
| `MicrophoneElectrical` | `dataclass` | **Electrical impedance and rated power supply (IEC 60268-4 Clauses 10/9).**<br>• `rated_impedance` [Ω] (10.2), `minimum_load_impedance` [Ω] (10.3)<br>• `powering` (9.1), `supply_current_ma` [mA] (9.1) | `MicrophoneElectrical(rated_impedance=150.0, powering="Phantom P48 (IEC 61938)")` |
| `MicrophoneCharacteristics` | `dataclass` | **Microphone rated-characteristics result (IEC 60268-4).**<br>• `sensitivity_level_db` = 20·lg(M / 1 V/Pa) (11.1), `effective_range` (12.2), `directivity_index_db` (13.2.2), `equivalent_noise_level_db` (17.2), `max_spl_db` (15.2), `signal_to_noise_ratio_db`, `diffuse_field_sensitivity_level_db`<br>• `.report()`: IEC 60268-4 fiche (graphs to IEC 60263) | `res.sensitivity_level_db` |
| `REFERENCE_FIELD_STRENGTH_A_PER_M` | `constant` | **The reference magnetic field strength of IEC 60118-4:2014 3.1, 0,4 A/m.**<br>• 400 mA/m is 0 dB; every level of the standard is referred to it | `electroacoustics.REFERENCE_FIELD_STRENGTH_A_PER_M  # 0.4` |
| `field_strength_level` / `field_strength` | `function` | **Level of a magnetic field strength re 400 mA/m, and its inverse (IEC 60118-4 3.1).**<br>• `field_strength_level(field_strength_a_per_m)` = 20·lg(H / 0,4 A/m) [dB]<br>• `field_strength(level_db)` [A/m]; −12 dB is the 100 mA/m of 4.3 | `electroacoustics.field_strength_level(0.1)  # -12.04` |
| `magnetic_flux_density` | `function` | **Flux density in air of a field strength (IEC 60118-4 E.6).**<br>• `field_strength_a_per_m` [A/m]<br>= μ₀H [T], μ₀ = 4π × 10⁻⁷ H/m (E.6 prints 1,256 µT for 1 A/m, see errata) | `electroacoustics.magnetic_flux_density(1.0)  # 1.2566e-06` |
| `telecoil_response` | `function` | **Relative response of a telecoil off its axis (IEC 60118-4 E.2, Figure E.6).**<br>• `angle_deg` [°] between the coil axis and the field<br>= 20·lg\|cos θ\| [dB]; −3 dB at 45°, −9,3 dB at 70° | `electroacoustics.telecoil_response(45.0)  # -3.01` |
| `field_strength_meter` | `function` | **Read a field strength record like the true-RMS meter of IEC 60118-4 6.1.3.**<br>• `x` [A/m], `fs` [Hz]<br>• keyword-only: `weighting` 'Z' (flat, 6.1.2) or 'A' (the noise of clause 7 and 10.4) (Default: 'Z')<br>• 125 ms "F" exponential averaging | `r = electroacoustics.field_strength_meter(h, 48000)`<br><br>• `FieldStrengthReading` |
| `FieldStrengthReading` | `dataclass` | **What the meter reads.**<br>• `fs` [Hz], `weighting`, `times_s` [s], `levels_db` [dB re 400 mA/m]<br>• `maximum_db`: the maximum indication 8.2.7 reads, `equivalent_db`: the level of the mean square [dB]<br>• `.plot()`: the time-weighted level against the 0 dB reference | `r.maximum_db` |
| `band_limit_response` | `function` | **Response of the band limiting of the pink noise (IEC 60118-4 6.4).**<br>• `frequencies_hz` [Hz]<br>• third-order Butterworth high-pass and low-pass, −3 dB at 75 Hz and 6,5 kHz: −0,71 dB at 100 Hz, −0,82 dB at 5 kHz (NOTE 2 prints them exchanged, see errata) | `electroacoustics.band_limit_response([100.0, 5000.0])` |
| `loop_test_noise` | `function` | **The pink noise test signal of IEC 60118-4 6.4 and IEC 62489-1 5.4.8.2 b).**<br>• `fs` [Hz] (above 13 kHz), `seconds` [s]<br>• keyword-only: `rms` (Default: 1.0), `seed` (Default: None)<br>• band-limited 75 Hz to 6,5 kHz and clipped at 4 times its RMS: a peak-to-peak ratio of 18,1 dB, which meets both standards | `x = electroacoustics.loop_test_noise(48000, 60.0, seed=1)` |
| `combi_signal` | `function` | **The combi signal of IEC 60118-4 6.6 and Table 2.**<br>• `fs` [Hz]<br>• keyword-only: `sine_seconds` (≥ 1 s), `noise_seconds` (≥ 4 s and ≥ 4 × the sine), `cycles` (Default: 1), `seed`<br>• 1 kHz bursts at 0 dB with 5 ms ramps, pink noise at −6 dB, every transition at a zero crossing | `x = electroacoustics.combi_signal(48000, cycles=3, seed=1)` |
| `small_volume_measurement_points` | `function` | **The measurement points of a refuge or a counter (IEC 60118-4 clause 9 as amended, Figures 2 and 3).**<br>• `layout`: 'refuge_small' (Figure 2 a), 'refuge_large' (2 b) or 'counter' (3)<br>• shape (heights, points, 3) [m]: x across, y into the standing area, z the height (1,2 m and 1,7 m; 1,2 m, 1,45 m and 1,7 m for a counter) | `p = electroacoustics.small_volume_measurement_points("counter")` |
| `assess_background_noise` | `function` | **Class the magnetic background noise of a site (IEC 60118-4 7.2).**<br>• `noise_levels_db`: A-weighted, loop off [dB re 400 mA/m]<br>• keyword-only: `noise_is_tonal` withholds the 22 dB relaxation (Default: False)<br>• the reference signal-to-noise ratio at the noisiest point: above 47 dB ideal, 32 dB the recommended minimum, 22 dB for short periods | `a = electroacoustics.assess_background_noise([-40.0, -36.5])`<br><br>• `BackgroundNoiseAssessment` |
| `BackgroundNoiseAssessment` | `dataclass` | **The 7.2 recommendation on a site.**<br>• `noise_levels_db`, `reference_signal_to_noise_ratio_db` [dB]<br>• `category`: 'ideal' / 'acceptable' / 'tolerable_for_short_periods' / 'below_tolerable'; `report_required` below 32 dB; `noise_is_tonal`<br>• `.plot()`: each point against the 47, 32 and 22 dB lines<br>• takes `noise_levels_db`, `noise_is_tonal`; `reference_signal_to_noise_ratio_db`, `category`, `report_required` are read-only, read from them | `a.category` |
| `verify_induction_loop_system` | `function` | **Verify an installed loop over its useful magnetic field volume (IEC 60118-4 8.2.7, 8.3.7, 8.4.3, 10.4.7 as amended).**<br>• `field_strength_levels_db` at each selected point [dB re 400 mA/m]<br>• keyword-only: `specified_level_db` (Default: 0, the 8.2.7 level for a sine or the combi signal); `frequencies_hz` and `response_db` together (100 Hz, 1 kHz and 5 kHz at least); `background_noise_levels_db` (loop off) and `system_noise_levels_db` (system on, inputs muted), paired point by point; `noise_is_tonal` (Default: False)<br>• the specified level reached at one point at least; ±3 dB of it everywhere; ±3 dB of 1 kHz from 100 Hz to 5 kHz; −47 dB above a 47 dB ratio, else 1 dB over the loop-off level (at exactly 47 dB too, see errata) | `v = electroacoustics.verify_induction_loop_system(levels, frequencies_hz=f, response_db=r)`<br><br>• `InductionLoopVerification` |
| `verify_small_volume_system` | `function` | **Verify a refuge, call-point or counter loop (IEC 60118-4 9.4 and 9.5 as amended).**<br>• `field_strength_levels_db`: (2, 6) for a refuge, (3, 3) for a counter, in the order of `small_volume_measurement_points`; any shape for 'refuge_useful_volume' or 'counter_useful_volume'<br>• keyword-only: `layout`; `heights_m` for a useful volume, one per point, which has to include every height of 9.2 or 9.3; `standing_area_levels_db` (Default: None); `frequencies_hz` and `response_db`<br>• ±6 dB at every point, 0 dB reached at one, nowhere above +8 dB (Annex A.4's +12 dB at 1,45 m is not applied, see errata) | `v = electroacoustics.verify_small_volume_system(levels, layout="counter")`<br><br>• `InductionLoopVerification` |
| `InductionLoopVerification` | `dataclass` | **The verdict on an installed system.**<br>• `clause` ('8' or '9'), `layout`, `requirements` (one `LoopRequirement` each), `background_noise` (a recommendation, not in the verdict)<br>• `.passes`; `bool()` raises; `.failed`, `.requirement(name)`<br>• `.plot()`: the worst margin of every requirement | `v.passes`<br>`v.requirement("frequency_response").worst_margin_db` |
| `LoopRequirement` | `dataclass` | **One requirement judged on every value it covers.**<br>• `name`, `clause`, `values_db`, `lower_db`, `upper_db` [dB], one limit pair per value<br>• `.margins_db`, `.worst_margin_db`, `.passes`; `bool()` raises<br>• `.plot()`: each value against its limits | `v.requirements[0].margins_db` |
| `OVERLOAD_TEST_FREQUENCIES` | `mapping` | **Table 4 of IEC 60118-4:2014/A1:2017, keyed 'transient_speech', 'speech' and 'music'.**<br>• each value an `OverloadTestFrequency`: 1,25 kHz / 2,5 kHz, 1,6 kHz / 3,15 kHz (the default), 2 kHz / 4 kHz | `electroacoustics.OVERLOAD_TEST_FREQUENCIES["speech"].test_frequency_hz  # 3150.0` |
| `OverloadTestFrequency` | `dataclass` | **One row of Table 4.**<br>• `programme`, `power_bandwidth_limit_hz` [Hz], `test_frequency_hz` [Hz] | `electroacoustics.OVERLOAD_TEST_FREQUENCIES["music"].power_bandwidth_limit_hz  # 2000.0` |
| `verify_amplifier_overload` | `function` | **Verify the overload test of IEC 60118-4 10.3 as amended on the compliance voltage.**<br>• `required_current_a` [A] at 1 kHz, `impedance` (a `LoopImpedance`), `compliance_voltage_v` [V]<br>• keyword-only: `programme` (Default: 'speech'), `current_response` (an `AmplifierFrequencyResponse`; Default: None, a flat current)<br>• 7 dB below the required current, swept from 1 kHz to where the loop voltage doubles or to the Table 4 frequency, whichever is higher, and judged at the Table 4 frequency (10.3.3) | `v = electroacoustics.verify_amplifier_overload(3.0, z, 12.0)`<br><br>• `AmplifierOverloadVerification` |
| `AmplifierOverloadVerification` | `dataclass` | **The overload test and its verdict.**<br>• `programme`, `test_current_a` [A], `doubling_frequency_hz`, `end_frequency_hz` [Hz], `frequencies_hz`, `voltage_v` [V], `test_frequency_voltage_v` [V] at the Table 4 frequency, `compliance_voltage_v` [V]<br>• `.passes` and `.headroom_db` at the Table 4 frequency; `.max_voltage_v` over the whole sweep, not judged; `bool()` raises<br>• `.plot()`: the loop voltage along the sweep against the compliance voltage, the judged voltage marked | `v.headroom_db` |
| `rectangular_loop_field` | `function` | **Magnetic field of a rectangular loop at any points, by Biot and Savart.**<br>• `current_a` [A], `length_m`, `width_m` [m], `x_m`, `y_m`, `z_m` [m] (broadcast; loop in z = 0, centred)<br>• keyword-only: `turns` (Default: 1)<br>• exact for filaments; reproduces IEC 60118-4 E.1 at the centre of a square and the curves of its Figure E.2 b) | `f = electroacoustics.rectangular_loop_field(3.0, 10.0, 20.0, x, 0.0, 1.2)`<br><br>• `LoopField` |
| `LoopField` | `dataclass` | **The field of a loop at a set of points.**<br>• `current_a`, `length_m`, `width_m`, `turns`, `x_m`, `y_m`, `z_m`<br>• `h_x_a_per_m`, `h_y_a_per_m`, `h_z_a_per_m` [A/m]; `.magnitude_a_per_m`; `.level_db(component)` [dB re 400 mA/m]<br>• `.plot(component="z")`: the level along the points with the ±3 dB band | `f.level_db("z")` |
| `loop_centre_field` | `function` | **Field at the centre of a loop, in its plane (IEC 60118-4 E.1).**<br>• `current_a` [A], `length_m` [m]<br>• keyword-only: `width_m` (Default: None, a square; √(d₁d₂) for a rectangle), `turns`<br>= 2√2·N·I/(π d) [A/m] | `electroacoustics.loop_centre_field(3.0, 5.0)  # 0.540` |
| `loop_current` | `function` | **Current a loop needs for a field strength above its centre (IEC 62489-1 5.4.10.2).**<br>• `length_m`, `width_m` [m]<br>• keyword-only: `height_m` (Default: 1.4), `field_strength_a_per_m` (Default: 0.4), `turns`<br>• the exact on-axis Biot-Savart field, inverted; reproduces the currents of IEC 60118-4 Figure H.1 | `electroacoustics.loop_current(10.0, 20.0)` |
| `loop_dimensions` | `function` | **Largest loop an amplifier's current drives to 400 mA/m at 1,4 m (IEC 62489-1 5.4.11).**<br>• `current_a` [A]<br>• keyword-only: `aspect_ratio` (Default: 1; 3 for the second loop of 5.4.11.1), `height_m`, `field_strength_a_per_m`, `turns`<br>• returns `(short_side_m, long_side_m)` [m] | `electroacoustics.loop_dimensions(5.0, aspect_ratio=3.0)` |
| `loop_resistance` | `function` | **Resistance of a copper loop (IEC 62489-1 B.2, IEC 60028).**<br>• `perimeter_m` [m], `conductor_area_mm2` [mm²]<br>• keyword-only: `turns`, `conductor_temperature_c` (Default: 20)<br>= ρNl/a with 1/58 Ω·mm²/m at 20 °C and 0,00393 per °C; reproduces the resistances of Table B.1 | `electroacoustics.loop_resistance(60.0, 1.5)  # 0.690` |
| `rectangular_loop_inductance` | `function` | **Inductance of a rectangular loop of round wire (Grover, Formula (58)).**<br>• `length_m`, `width_m` [m], `conductor_area_mm2` [mm²]<br>• keyword-only: `turns` (N² coupling), `internal_inductance` (Default: True; False reproduces four inductances of Table B.1) | `electroacoustics.rectangular_loop_inductance(10.0, 20.0, 1.5, internal_inductance=False)  # 1.09e-4` |
| `loop_impedance` | `function` | **Impedance of a loop, series R and L (IEC 62489-1 5.4.3.2, IEC 60118-4 E.3).**<br>• `resistance_ohm` [Ω], `inductance_h` [H]<br>• keyword-only: `frequencies_hz` (Default: one-third octaves 50 Hz to 10 kHz) | `z = electroacoustics.loop_impedance(0.69, 109e-6)`<br><br>• `LoopImpedance` |
| `LoopImpedance` | `dataclass` | **The loop as a load.**<br>• `resistance_ohm`, `inductance_h`, `frequencies_hz`, `impedance_ohm`<br>• `.corner_frequency_hz` = R/(2πL), where \|Z\| = √2·R; `.at(frequency_hz)`; `.drive_voltage(current_a, frequency_hz)` = I\|Z\| [V]<br>• `.plot()`: \|Z\| against frequency | `z.drive_voltage(3.0, 2000.0)` |
| `maximum_output_current` | `function` | **Maximum (distortion-limited) output current of an amplifier (IEC 62489-1 5.4.7).**<br>• `resistor_voltage_v` [V] across the resistive part of the rated load at each step, ascending; `thd_percent` [%] there<br>• keyword-only: `load_resistance_ohm` [Ω], `rated_thd_percent` [%] (5.4.6)<br>• the current U/R where the THD first reaches the rating, interpolated between steps | `m = electroacoustics.maximum_output_current(u, thd, load_resistance_ohm=0.69, rated_thd_percent=1.0)`<br><br>• `MaximumOutputCurrent` |
| `MaximumOutputCurrent` | `dataclass` | **The distortion-limited output current and the steps it is read from.**<br>• `resistor_voltage_v` [V], `load_current_a` [A], `thd_percent` [%], `load_resistance_ohm` [Ω], `rated_thd_percent` [%], `maximum_current_a` [A]<br>• `.plot()`: the THD against the load current, with the rating and the maximum | `m.maximum_current_a` |
| `compliance_voltage` | `function` | **Compliance voltage of an amplifier (IEC 62489-1 5.4.8).**<br>• `voltage_v`: the load voltage over at least 60 s of the specified pink noise [V]<br>= mean of the positive and negative peak magnitudes / √2 [V] | `electroacoustics.compliance_voltage(v)` |
| `equivalent_input_noise_voltage` / `amplifier_signal_to_noise_ratio` | `function` | **Noise of an amplifier (IEC 62489-1 5.4.9).**<br>• `equivalent_input_noise_voltage(source_emf_v, output_current_a, noise_current_a)` = U·Iₙ/I [V]<br>• `amplifier_signal_to_noise_ratio(rated_current_a, noise_current_a)` = 10·lg(Iᵣ²/Iₙ²) [dB] | `electroacoustics.amplifier_signal_to_noise_ratio(5.0, 0.005)  # 60.0` |
| `amplifier_frequency_response` | `function` | **Frequency response of an amplifier into its load (IEC 62489-1 5.4.12).**<br>• `frequencies_hz` [Hz] ascending, with 1000 Hz; `output_current_a` [A] | `r = electroacoustics.amplifier_frequency_response(f, i)`<br><br>• `AmplifierFrequencyResponse` |
| `AmplifierFrequencyResponse` | `dataclass` | **The current response, 0 dB at 1 kHz (5.4.12.3).**<br>• `frequencies_hz` [Hz], `output_current_a` [A], `response_db` [dB]<br>• `.at(frequency_hz)`: log-frequency interpolation inside the measured range<br>• `.plot()`: the response with the ±3 dB band | `r.at(3150.0)` |
| `agc_characteristic` | `function` | **Output/input characteristic and AGC range of an amplifier (IEC 62489-1 5.4.13).**<br>• `source_emf_db` ascending [dB], `output_level_db` [dB re the rated maximum output current]<br>• the widest input span over which the output changes by at most 3 dB, against the 32 dB 5.4.13.4 recommends | `a = electroacoustics.agc_characteristic(u_db, i_db)`<br><br>• `AgcCharacteristic` |
| `AgcCharacteristic` | `dataclass` | **The steady-state characteristic.**<br>• `source_emf_db`, `output_level_db`, `agc_range_db`, `agc_range_start_db`, `agc_range_end_db` [dB]<br>• `.recommended_range_db` (32 dB)<br>• `.plot()`: output against input with the range shaded, as Figure A.1 | `a.agc_range_db` |
| `quadrature_phase_error` | `function` | **Maximum deviation from 90° between two loop currents (IEC 62489-1 5.4.14).**<br>• `frequencies_hz` [Hz], `phase_difference_deg` [°]; either loop may lead<br>• judged over 100 Hz to 5 kHz | `q = electroacoustics.quadrature_phase_error(f, phi)`<br><br>• `QuadraturePhaseError` |
| `QuadraturePhaseError` | `dataclass` | **The phase error of a quadrature network.**<br>• `frequencies_hz`, `phase_difference_deg`, `deviation_deg`, `max_deviation_deg` [°], `max_deviation_frequency_hz` [Hz]<br>• `.level_increase_db` = 20·lg(1 + sin δ), `.level_decrease_db` = 20·lg(1 − sin δ) [dB] (5.4.14.1 prints 0,72 dB for both, see errata)<br>• `.plot()`: the deviation against frequency | `q.max_deviation_deg` |
| `neck_loop_characteristics` | `function` | **Input voltage, input impedance and frequency response of a neck loop (IEC 62489-1 clause 9, Annex E).**<br>• `frequencies_hz` [Hz] with 1000 Hz, `field_strength_level_db` on the jig [dB re 400 mA/m], `impedance_ohm` [Ω] (complex allowed)<br>• keyword-only: `input_voltage_v` [V] the field was measured with | `n = electroacoustics.neck_loop_characteristics(f, lvl, z, input_voltage_v=0.5)`<br><br>• `NeckLoopCharacteristics` |
| `NeckLoopCharacteristics` | `dataclass` | **What clause 9 states for a neck loop.**<br>• `reference_input_voltage_v` [V] for 400 mA/m at 1 kHz (9.1), `minimum_impedance_ohm` over 100 Hz to 5 kHz rounded to the ohm (9.2.1), `response_db` [dB], `frequencies_3db_hz` [Hz] (9.3.3)<br>• `.plot()`: the response on the jig | `n.reference_input_voltage_v` |
| `NECK_LOOP_TYPES` | `mapping` | **The two neck-loop types of the draft Annex D (prEN 62489-1:2010/prA2:2017, a draft), keyed 1 and 2.**<br>• each value a `NeckLoopType`: type 1, for sources of two primary 1,5 V cells and higher voltage supplies, 32 Ω ± 5 %; type 2, with a transformer or an amplifier, at least 32 Ω; both 400 mA/m with at most 1,06 V | `electroacoustics.NECK_LOOP_TYPES[1].max_input_voltage_v  # 1.06` |
| `NeckLoopType` | `dataclass` | **One type of the draft Annex D.**<br>• `description`, `min_dc_resistance_ohm`, `max_dc_resistance_ohm` [Ω], `max_input_voltage_v` [V] | `electroacoustics.NECK_LOOP_TYPES[2].min_dc_resistance_ohm  # 32.0` |
| `verify_neck_loop` | `function` | **Verify a neck loop against one type of the draft Annex D (prA2:2017, a draft).**<br>• `dc_resistance_ohm` [Ω], `input_voltage_v` [V] for 400 mA/m on the jig<br>• keyword-only: `neck_loop_type` 1 or 2 (Default: 1) | `v = electroacoustics.verify_neck_loop(32.4, 0.9)`<br><br>• `NeckLoopVerification` |
| `NeckLoopVerification` | `dataclass` | **The verdict on a neck loop.**<br>• `neck_loop_type`, `dc_resistance_ohm` [Ω], `input_voltage_v` [V], `limits` (a `NeckLoopType`)<br>• `.resistance_passes`, `.voltage_passes`, `.passes`; `bool()` raises<br>• `.plot()`: each value as a share of its limit | `v.passes` |
| `SIMULATED_PROGRAMME_SPECTRUM` | `mapping` | **Table II of IEC 60268-1:1985, the power spectrum of the simulated programme signal, keyed by the nominal one-third-octave frequency 20 Hz to 20 kHz.**<br>• each value a `ProgrammeSpectrumBand`: 0 dB from 250 Hz to 800 Hz, −13,5 dB at 20 Hz, −21,6 dB at 20 kHz; ±0,5 dB in the middle to ±3 dB at the ends<br>• neither 1988 amendment touches Clause 7 | `electroacoustics.SIMULATED_PROGRAMME_SPECTRUM[20000.0].relative_level_db  # -21.6` |
| `ProgrammeSpectrumBand` | `dataclass` | **One row of Table II.**<br>• `relative_level_db`, `tolerance_plus_db`, `tolerance_minus_db` [dB], the tolerances as printed (positive) | `electroacoustics.SIMULATED_PROGRAMME_SPECTRUM[1000.0].tolerance_plus_db  # 0.6` |
| `programme_signal_filter` | `function` | **Transfer function of the filter of IEC 60268-1:1985 Figure 2, the ladder that turns pink noise into the programme signal.**<br>• `frequencies_hz` [Hz], any shape<br>• the voltage across the 10 kΩ over the source e.m.f.; the source impedance is part of the 430 Ω and the 10 kΩ is the whole output shunt | `h = electroacoustics.programme_signal_filter([1000.0])` |
| `simulated_programme_signal` | `function` | **The simulated programme signal of IEC 60268-1:1985 Clause 7: stationary Gaussian noise with the spectrum of Table II.**<br>• `fs` [Hz], `seconds` [s]<br>• keyword-only: `rms` (Default: 1.0); `spectrum` 'table' (Default: every band on its printed level) or 'figure_2' (pink noise through Figure 2); `peak_to_rms` clips to that ratio, 1,8 to 2,2 for IEC 60268-7 8.3.2 (Default: None, no clipping); `seed` | `x = electroacoustics.simulated_programme_signal(48000, 30.0, seed=1)` |
| `check_programme_signal` | `function` | **Is a one-third-octave spectrum the programme signal of IEC 60268-1 Table II?**<br>• `frequencies_hz` [Hz], nominal or exact base-ten centres; `band_levels_db` [dB] on any reference<br>• judged up to a constant: passes when one level places every band inside its tolerance; only the bands given are judged | `c = electroacoustics.check_programme_signal(f, levels)`<br><br>• `ProgrammeSignalCheck` |
| `ProgrammeSignalCheck` | `dataclass` | **A spectrum judged against Table II.**<br>• `frequencies_hz`, `band_levels_db`, `offset_db` (the middle of the window of levels that fit), `relative_levels_db`, `tolerance_plus_db`, `tolerance_minus_db`<br>• `.deviations_db`, `.margin_db`, `.binding_bands_hz`, `.passes`; `bool()` raises<br>• `.plot()`: the referred bands inside the tolerances | `c.margin_db` |
| `HeadphoneClassification` | `dataclass` | **The classification of a headphone by IEC 60268-7:2010 Clause 4.**<br>• `principle`, `earphone_type`, `coupling`, `radiation` (one letter each), `impedance_ohm` [Ω], `channels` (1 to 9)<br>• `.code` ('60268-7-IEC-DCSC-32R0-2'), `.description` | `electroacoustics.HeadphoneClassification("D", "C", "S", "C", 32.0, 2).code` |
| `TRANSDUCER_PRINCIPLES` / `EARPHONE_TYPES` / `ACOUSTIC_COUPLINGS` / `BACK_RADIATIONS` | `mapping` | **The four letters of the IEC 60268-7 code, each letter to its meaning (Clause 4).**<br>• principle D, E, F, M, P, S; type C, E, H, I, M, S, T; coupling L (open) or S (closed); radiation C (closed-back) or O (open-back) | `electroacoustics.EARPHONE_TYPES["E"]  # 'intra-concha'` |
| `impedance_code` | `function` | **The impedance in the "mantissa and exponent" form of the code (Clause 4).**<br>• `impedance_ohm`: a whole number of ohms<br>• the exponent takes every trailing zero: 8 Ω '08R0', 32 Ω '32R0', 600 Ω '06R2' as printed | `electroacoustics.impedance_code(600)  # '06R2'` |
| `parse_classification_code` | `function` | **Read a code of the form 60268-7-IEC-XXXX-NNRN-N.**<br>• spaces around the hyphens, as the clause lays it out, are ignored | `electroacoustics.parse_classification_code("60268-7-IEC-DCSC-32R0-2")`<br><br>• `HeadphoneClassification` |
| `verify_rated_impedance` | `function` | **Verify a headphone's rated impedance against the measured modulus (IEC 60268-7 8.2).**<br>• `frequencies_hz` [Hz], `impedance_ohm` [Ω] (complex allowed)<br>• keyword-only: `rated_impedance_ohm` [Ω], `rated_frequency_range_hz` (lower, upper) [Hz]<br>• the lowest modulus in the rated range at least 80 % of the rated value; dips below it up to 20 kHz listed to be stated; coverage of 20 Hz to 20 kHz | `v = electroacoustics.verify_rated_impedance(f, z, rated_impedance_ohm=32.0, rated_frequency_range_hz=(20.0, 20000.0))`<br><br>• `RatedImpedanceVerification` |
| `RatedImpedanceVerification` | `dataclass` | **The verdict of 8.2.1 b).**<br>• `frequencies_hz`, `impedance_ohm`, `rated_impedance_ohm`, `rated_frequency_range_hz`<br>• `.limit_ohm`, `.minimum_ohm`, `.minimum_frequency_hz`, `.minimum_ratio`, `.frequencies_to_state_hz`, `.covers_measurement_range`, `.passes`; `bool()` raises<br>• `.plot()`: the modulus with the rated value and its 80 % | `v.minimum_ratio` |
| `characteristic_voltage` | `function` | **The source e.m.f. that gives 94 dB in the coupler (IEC 60268-7 8.3.3).**<br>• `source_emf_v` [V] of a reading, `sound_pressure_level_db` it gave [dB re 20 µPa]<br>• the linear scaling E 10^((94 − L)/20); with the level of the whole programme signal it is 8.3.4 | `electroacoustics.characteristic_voltage(0.1, 98.0)  # 0.0631` |
| `programme_signal_level` | `function` | **The level of the programme signal from its one-third-octave bands (IEC 60268-7 Figure 3 NOTE).**<br>• `frequencies_hz` [Hz], `band_levels_db` [dB re 20 µPa]<br>• keyword-only: `a_weighted` (Default: False), `free_field_response_db` of the head and torso simulator, compensated by its inverse (Default: None)<br>• the power sum of the bands with the IEC 61672-1 A-weighting at each exact centre | `electroacoustics.programme_signal_level(f, levels, a_weighted=True)` |
| `programme_characteristic_voltage` | `function` | **The simulated programme signal characteristic voltage (IEC 60268-7 8.3.4, and 8.3.5 corrected).**<br>• `source_emf_v` [V] per fitting, `frequencies_hz` [Hz], `band_levels_db` (fittings, bands) [dB re 20 µPa]<br>• keyword-only: `a_weighted`, `free_field_response_db` (8.3.5)<br>• each fitting scaled to 94 dB, the e.m.f.s averaged (8.3.5 g, 3 to 5 fittings) | `p = electroacoustics.programme_characteristic_voltage(0.1, f, levels)`<br><br>• `ProgrammeCharacteristicVoltage` |
| `ProgrammeCharacteristicVoltage` | `dataclass` | **The 8.3.4 or 8.3.5 characteristic.**<br>• `frequencies_hz`, `band_levels_db`, `source_emf_v`, `corrections_db`, `a_weighted`, `free_field_compensated`<br>• `.levels_db`, `.voltages_v`, `.characteristic_voltage_v`, `.fittings_conform`, `.band_levels_at_characteristic_db`<br>• `.plot()`: the band levels whose power sum is 94 dB | `p.characteristic_voltage_v` |
| `headphone_input_power` / `headphone_source_emf` | `function` | **The power that corresponds to a source e.m.f., and back (IEC 60268-7 8.4).**<br>• `source_emf_v` [V] or `input_power_w` [W]<br>• keyword-only: `rated_impedance_ohm`, `rated_source_impedance_ohm` [Ω]<br>• the power in a pure resistance equal to the rated impedance through the rated source impedance, E² R/(R + Rs)² | `electroacoustics.headphone_source_emf(1e-3, rated_impedance_ohm=32.0, rated_source_impedance_ohm=120.0)  # 0.850` |
| `working_sound_pressure_level` | `function` | **The working sound pressure level of IEC 60268-7 8.5.2 b) to d).**<br>• `sound_pressure_level_db` [dB re 20 µPa] read at `source_emf_v` [V]<br>• keyword-only: `rated_impedance_ohm`, `rated_source_impedance_ohm` [Ω]<br>• scaled to the e.m.f. that dissipates 1 mW in the rated impedance | `electroacoustics.working_sound_pressure_level(98.0, 0.1, rated_impedance_ohm=32.0, rated_source_impedance_ohm=120.0)` |
| `check_limiting_test_signal` | `function` | **Is this the clipped programme signal of IEC 60268-7 8.3.2.2 b)?**<br>• `signal` (1-D or `Signal`), `fs` [Hz]<br>• a peak-to-RMS ratio from 1,8 to 2,2 and the spectrum of IEC 60268-1 Table II in every band below the Nyquist frequency | `c = electroacoustics.check_limiting_test_signal(x, 48000)`<br><br>• `LimitingTestSignalCheck` |
| `LimitingTestSignalCheck` | `dataclass` | **The verdict on the limiting voltages' test signal.**<br>• `peak_to_rms`, `spectrum` (a `ProgrammeSignalCheck`)<br>• `.peak_to_rms_passes`, `.passes`; `bool()` raises<br>• `.plot()`: the spectrum against Table II with the ratio | `c.peak_to_rms` |
| `protection_voltage` | `function` | **The protection voltage of a headphone's protective device from a level sweep (IEC 60268-7 8.3.6).**<br>• `source_emf_v` [V] ascending, `sound_pressure_level_db` [dB re 20 µPa]<br>• where the sensitivity has changed 1 dB from the first step, interpolated in 20 lg E | `p = electroacoustics.protection_voltage(e, levels)`<br><br>• `ProtectionVoltage` |
| `ProtectionVoltage` | `dataclass` | **A protective device's operating point.**<br>• `source_emf_v`, `sound_pressure_level_db`, `protection_voltage_v` (None if not reached)<br>• `.sensitivity_change_db`, `.measurement_voltages_v` (1 dB either side, 8.3.6.2 b)<br>• `.plot()`: the sensitivity change against the e.m.f. | `p.protection_voltage_v` |
| `coupler_frequency_response` | `function` | **The coupler or ear simulator frequency response (IEC 60268-7 8.6.2).**<br>• `frequencies_hz` [Hz], `sound_pressure_level_db` [dB re 20 µPa]<br>• keyword-only: `rated_frequency_range_hz` to judge the coverage (Default: None) | `r = electroacoustics.coupler_frequency_response(f, levels)`<br><br>• `CouplerFrequencyResponse` |
| `CouplerFrequencyResponse` | `dataclass` | **The level against frequency at the rated e.m.f.**<br>• `frequencies_hz`, `sound_pressure_level_db`, `rated_frequency_range_hz`<br>• `.covers_rated_range`, `.relative_response_db(reference_frequency_hz=500.0)`<br>• `.plot(iec_scale=True)`: 50 dB the length of a decade (8.6.2.2 c) | `r.relative_response_db()` |
| `crosstalk_attenuation` | `function` | **The crosstalk attenuation of a multi-channel headphone (IEC 60268-7 8.12).**<br>• `frequencies_hz` [Hz], `driven_level_db`, `other_level_db` [dB re 20 µPa] in the same coupler | `c = electroacoustics.crosstalk_attenuation(f, driven, other)`<br><br>• `CrosstalkAttenuation` |
| `CrosstalkAttenuation` | `dataclass` | **The difference of the two levels against frequency.**<br>• `frequencies_hz`, `driven_level_db`, `other_level_db`<br>• `.attenuation_db`, `.minimum_db`<br>• `.plot()` | `c.minimum_db` |
| `field_comparison_response` | `function` | **The free-field or diffuse-field comparison frequency response (IEC 60268-7 8.6.3, 8.6.4).**<br>• `frequencies_hz` [Hz] with the reference band, `field_level_db` [dB re 20 µPa] per band (or per person), `source_emf_v` (persons, bands) [V] for equal loudness<br>• keyword-only: `field` 'free' or 'diffuse'; `reference_frequency_hz` (Default: 500, the standard measuring frequency of 7.2 b)<br>• 20 lg(p/E) referred to the reference band, per person | `r = electroacoustics.field_comparison_response(f, 70.0, e, field="free")`<br><br>• `FieldComparisonResponse` |
| `FieldComparisonResponse` | `dataclass` | **The responses of a panel of test persons.**<br>• `field`, `frequencies_hz`, `response_db` (persons, bands), `reference_frequency_hz`<br>• `.persons`, `.mean_db`, `.standard_deviation_db`, `.meets_panel_size` (8 persons), `.qualifies_as_reference` (16 persons)<br>• `.plot()`: the mean as bars with each band's standard deviation | `r.mean_db` |
| `ear_canal_frequency_response` | `function` | **The ear canal sound pressure level frequency response, Formula (1) (IEC 60268-7 8.6.5).**<br>• `frequencies_hz` [Hz] with 500 Hz, `earphone_levels_db` and `sound_field_levels_db` (persons, 2, bands) [dB]: the two fittings c), d) and the two sound-field readings b), e)<br>• keyword-only: `reference_frequency_hz` (Default: 500) | `r = electroacoustics.ear_canal_frequency_response(f, le, ls)`<br><br>• `EarCanalFrequencyResponse` |
| `EarCanalFrequencyResponse` | `dataclass` | **Formula (1) for each person and the panel.**<br>• `frequencies_hz`, `earphone_levels_db`, `sound_field_levels_db`, `reference_frequency_hz`<br>• `.response_db`, `.mean_db`, `.standard_deviation_db`, `.persons`, `.meets_panel_size`; `.fitting_difference_db` and `.fittings_consistent` (2,5 dB, item f); `.level_match_db` and `.levels_matched` (3 dB, item c)<br>• `.plot()` | `r.fittings_consistent` |
| `verify_ear_canal_microphone` | `function` | **Verify a probe microphone for the ear canal (IEC 60268-7 Annex B a to e).**<br>• keyword-only: `entrance_area_mm2` (≤ 5 mm²), `canal_section_area_mm2` (less than 0,6 of `ear_canal_area_mm2`, Default: 45 mm²), `volume_mm3` (< 130 mm³), `pink_noise_band_levels_db` (neighbours within 3 dB), `open_levels_db` and `sealed_levels_db` (sealed 15 dB below) | `v = electroacoustics.verify_ear_canal_microphone(entrance_area_mm2=4.0, ...)`<br><br>• `EarCanalMicrophoneVerification` |
| `EarCanalMicrophoneVerification` | `dataclass` | **The verdict of Annex B.**<br>• `entrance_area_mm2`, `canal_section_area_mm2`, `ear_canal_area_mm2`, `volume_mm3`, `neighbour_difference_db`, `sealed_attenuation_db`<br>• `.area_ratio`, `.requirements` (item letter to verdict), `.passes`; `bool()` raises<br>• `.plot()`: each item as a share of its limit | `v.requirements["e"]` |
| `headphone_modulation_signal` / `headphone_difference_frequency_signal` | `function` | **The distortion test signals of IEC 60268-7 8.7.3 and 8.7.4.**<br>• `fs` [Hz], `seconds` [s]; keyword-only `rated_source_emf_v` [V]; for the second also `upper_frequency_hz` [Hz]<br>• 70 Hz and 600 Hz in the ratio 4:1 with the rated peak (−1,9 dB and −14,0 dB, NOTE 1); two tones 80 Hz apart at half the rated voltage each; read with `modulation_distortion` and `difference_frequency_distortion` | `x = electroacoustics.headphone_modulation_signal(48000, 1.0, rated_source_emf_v=1.0)` |
| `expansion_chamber` | `function` | **Expansion-chamber silencer TL/IL (Bies Eq. 8.111, four-pole).**<br>• `frequencies`, `length` L, `chamber_area`, `pipe_area`<br>• `source_impedance`/`radiation_impedance` (Default: None → no IL) | `res = noise_control.expansion_chamber(f, 0.3, 0.04, 0.01)`<br><br>• `ReactiveSilencerResult` |
| `plot_silencer_geometry` | `function` | **To-scale silencer cross-section.**<br>• `kind`: the `ReactiveSilencerResult.kind` strings<br>• Chamber: `length`, `chamber_area`, `pipe_area` (+ `inlet_extension`/`outlet_extension`)<br>• Branch: `duct_area` + Helmholtz (`neck_area`, `neck_length`, `cavity_volume`) or quarter-wave (`length`, `branch_area`)<br>• `language` | `plot_silencer_geometry('expansion chamber', length=0.3, chamber_area=0.03, pipe_area=0.005)`<br><br>• Equivalent circular diameters 2·√(S/π); also `ReactiveSilencerResult.plot_geometry()` |
| `helmholtz_resonator` / `quarter_wave_resonator` | `function` | **Side-branch resonator silencers (Bies Eqs. 8.46/8.44).**<br>• Helmholtz: `duct_area`, `neck_area`, `neck_length`, `cavity_volume`<br>• Quarter-wave: `duct_area`, `length`, `branch_area` | `quarter_wave_resonator(f, 0.01, 1.5, 2e-3)` |
| `extended_tube_chamber` | `function` | **Extended-inlet/outlet expansion chamber (Bies §8.9.7); reduces to `expansion_chamber` at zero extension.**<br>• `length`, `chamber_area`, `pipe_area`, `inlet_extension`, `outlet_extension` | `extended_tube_chamber(f, 0.4, 0.04, 0.01, inlet_extension=0.1)` |
| `transmission_loss` | `function` | **Transmission loss of a four-pole element (Munjal Eq. (3.27), no flow).**<br>• `transfer_matrix` T, shape `(n_freq, 2, 2)`<br>• `inlet_area` S_in / `outlet_area` S_out [m²]<br>• `speed_of_sound` / `density`<br>• The anechoic termination is part of the definition, so this describes the element alone | `transmission_loss(t, inlet_area=0.01, outlet_area=0.01)` |
| `insertion_loss` | `function` | **Insertion loss of a four-pole element for stated end impedances.**<br>• `transfer_matrix` T<br>• `source_impedance` Z_s, `radiation_impedance` Z_r [Pa·s/m³]<br>• Unlike the transmission loss it depends on the source and the termination, which is what makes it the number a client hears | `insertion_loss(t, source_impedance=zs, radiation_impedance=zr)` |
| `duct_matrix` / `shunt_matrix` / `cascade` | `function` | **The four-pole primitives the silencers are assembled from (Bies Eqs. 8.143/8.144).**<br>• `duct_matrix(frequencies, length, area, ...)`: a straight duct<br>• `shunt_matrix(branch_impedance)`: a side branch of impedance Z_b<br>• `cascade(*matrices)`: multiplies elements inlet to outlet | `t = noise_control.cascade(noise_control.duct_matrix(f, 0.1, s), noise_control.shunt_matrix(z))` |
| `helmholtz_impedance` / `quarter_wave_impedance` | `function` | **Side-branch impedances to feed `shunt_matrix` (Bies Eqs. 8.152/8.146).**<br>• Helmholtz: `neck_area`, `neck_length`, `cavity_volume`, `resistance`<br>• Quarter-wave: `length`, `area`<br>• `speed_of_sound` / `density` | `shunt_matrix(noise_control.helmholtz_impedance(f, 1e-3, 0.05, 2e-3))` |
| `ReactiveSilencerResult` | `dataclass` | **Reactive-silencer result.**<br>• `frequencies`, `transmission_loss`, `insertion_loss` (or None), `transfer_matrix`, `kind`, `resonances`<br>• `.plot()`: TL/IL vs frequency | `res.transmission_loss` |
| `SilencerChain` | `class` | **Hand-built four-pole chain that keeps the geometry it was given.**<br>• `SilencerChain(frequencies, speed_of_sound=…, density=…)`<br>• `.duct(length, area)` and `.shunt(branch_impedance, label=…)` in order, each returning the chain<br>• `.transfer_matrix`, `.result(inlet_area=…, outlet_area=…)`, `.plot_geometry()` | `SilencerChain(f).duct(0.3, 0.031).shunt(zb).duct(0.6, 0.126)`<br><br>• Ducts drawn to scale, shunts marked as branch points |
| `SilencerChainElement` | `dataclass` | **One recorded element of a `SilencerChain`.**<br>• `matrix`, plus whatever geometry the call was handed: `length` and `area` for a duct, neither for a shunt<br>• `label`, `shorting_frequency` (where the branch impedance is least), `.is_duct` | `chain.elements[0].area` |
| `substitution_insertion_loss` | `function` | **The measured insertion loss of ISO 7235 Eq. (1) and ISO 11691 Eq. (1): the level without the silencer minus the level with it.**<br>• `substitution_level` (the series run with the substitution duct), `object_level` (the series run with the test object) [dB]<br>• `reverberation_times`: optionally `(T_1, T_2)` [s], adding the `10 lg(T_2/T_1)` of ISO 7235 6.3; one value stands for every band<br>• the two standards number the series the opposite way round; the argument names are neither numbering | `noise_control.substitution_insertion_loss(sub, obj)` |
| `octave_insertion_loss` | `function` | **ISO 11691 Eq. (2): three one-third octaves folded into their octave on the transmitted energy.**<br>• `insertion_loss` [dB], a multiple of three bands in ascending order<br>• `-10 lg[(10^-D1/10 + 10^-D2/10 + 10^-D3/10)/3]`, so the leakiest third decides the octave: 30, 30 and 5 dB give 9.7 dB, not 21.7 | `noise_control.octave_insertion_loss([30.0, 30.0, 5.0])  # 9.744` |
| `microphone_spread_limit` / `microphone_positions_required` / `ISO7235_SPREAD_LIMITS` | `function` / `function` / `constant` | **ISO 7235 Table 6 and the rule of 6.2.1 it serves: when three microphone positions in a test duct are not enough.**<br>• `microphone_spread_limit(frequency)`: 10 dB at 50 and 63 Hz, 8 at 80 and 100, 7 at 125, 6 from 160 up<br>• `microphone_positions_required(levels, frequency)`: `3` or `5`, from the spread of exactly three levels<br>• the printed last row says `> 160`, leaving the 160 Hz band with no limit; read here as 160 and above (see the errata) | `noise_control.microphone_positions_required([70.0, 74.0, 79.0], 125.0)  # 5` |
| `measurement_reproducibility` / `measurement_expanded_uncertainty` / `ISO7235_REPRODUCIBILITY` / `ISO7235_COVERAGE_FACTOR` | `function` / `function` / `table` / `constant` | **ISO 7235 Table 7 and 7.9: how repeatable the measurement is, and the uncertainty that goes on the report.**<br>• `frequency` [Hz], `quantity`: `'insertion_loss'` (Default), `'transmission_loss'` or `'intensity'`<br>• insertion loss 1.5/1/2/3 dB by band range, transmission loss a flat 3, intensity 3/1.5/1/1 and stopping at 5 kHz<br>• the expanded uncertainty is `ISO7235_COVERAGE_FACTOR = 2` times the deviation, for 95 % coverage | `noise_control.measurement_expanded_uncertainty(4000.0)  # 6.0 dB` |
| `survey_reproducibility` / `ISO11691_REPRODUCIBILITY` | `function` / `constant` | **ISO 11691 Table 1: 2 dB up to the 1.25 kHz one-third octave and 3 dB above it.**<br>• `frequency` [Hz]<br>• the standard offers no interlaboratory result of its own and says this estimate is what makes it a survey method | `noise_control.survey_reproducibility(1000.0)  # 2.0 dB` |
| `substitution_area_ratio` / `SURVEY_AREA_RATIO_RANGE` / `SURVEY_MAX_VELOCITY_M_S` / `SURVEY_DIAMETER_RANGE_M` / `SURVEY_BAND_RANGE_HZ` / `SilencerMeasurementWarning` | `function` / `range` / `constant` / `range` / `range` / `warning class` | **The scope ISO 11691 writes for its own survey method.**<br>• `substitution_area_ratio(duct_area, element_area)` [m²], warning outside the 0.6 to 1.7 of 4.5<br>• design velocity up to 15 m/s (1.1), circular diameters 80 mm to 2 m, one-third octaves from 50 Hz to 10 kHz | `noise_control.substitution_area_ratio(0.09, 0.09)  # 1.0`<br>Emitted by `noise_control.silencer_measurement` |
| `open_end_transmission_loss` / `open_end_reflection_coefficient` / `RADIATION_SOLID_ANGLES` | `function` / `function` / `mapping` | **ISO 7235 Eqs. (B.3) and (B.4): what the open end of a duct keeps in, and the reflection that is the same fact said the other way.**<br>• `frequency` [Hz], `area` S [m²], `solid_angle_sr` Ω [sr] (Default: 2π), `speed_of_sound` [m/s]<br>• `D_td = 10 lg[1 + Ω/(4πf√S/c)²]`, `r = [(1/Ω)(4πf√S/c)² + 1]^(−1/2)`, and the two close through `D_td = −10 lg(1 − r²)`<br>• `RADIATION_SOLID_ANGLES` is Table B.1, the same five values as ISO 5135 Table 1: A 2π, B π, C 4π, D 2π, E 4π<br>• the same physics as `end_reflection_loss_closed_form`, which raises the same argument to 1.88 rather than to 2 | `noise_control.open_end_transmission_loss(bands, 0.0962)` |
| `measured_transmission_loss` / `flow_noise_power_level` | `function` | **ISO 7235 Eqs. (6) and (7): the two quantities the open-end loss is needed for.**<br>• `measured_transmission_loss(insertion_loss, open_end_loss)`: `D_t = D_i + D_td`, the transmission loss of an air-terminal unit<br>• `flow_noise_power_level(pressure_level, open_end_loss, room_correction)`: `L_W = L_p + D_td + C`, with `L_p` uncorrected for background as 6.4 requires and `C` from ISO 3741 | `noise_control.measured_transmission_loss(d_i, d_td)` |
| `modal_filter_cut_on` / `CIRCULAR_CUT_ON_COEFFICIENT` / `RECTANGULAR_CUT_ON_COEFFICIENT` / `MODAL_FILTER_ATTENUATION_DB` | `function` / `constant` / `constant` / `constant` | **ISO 7235 Eqs. (4) and (5): where higher-order modes start in the duct the modal filter is connected to.**<br>• exactly one of `diameter_m` d or `larger_dimension` H [m], plus `speed_of_sound`<br>• `0.59 c/d` and `0.5 c/H`; the rectangular constant is exact, the circular one sits 0.67 % above the Bessel eigenvalue that `circular_duct_cut_on` uses<br>• `MODAL_FILTER_ATTENUATION_DB = (3.0, 5.0)`, the minimum longitudinal attenuation of 5.2.2.3 below and above it | `noise_control.modal_filter_cut_on(diameter_m=0.4)  # 506 Hz` |
| `normal_air_density` / `ISO7235_GAS_CONSTANT` / `ISO7235_ABSOLUTE_ZERO_OFFSET` | `function` / `constant` / `constant` | **ISO 7235 Eqs. (10), (21) and (22): the gas law with the standard's own two constants.**<br>• `static_gauge_pressure_pa` p_s1 [Pa, relative to ambient], `ambient_pressure_pa` p_a [Pa absolute], `temperature_c` θ [°C]<br>• `R = 287` and `θ + 273`, both as printed rather than 287.05 and 273.15; together 0.069 % high at 20 °C, and both cancel in the pressure loss coefficient | `noise_control.normal_air_density(200.0, 101325.0, 20.0)  # 1.2073` |
| `volume_flow_rate` / `dynamic_pressure` / `total_pressure` / `DENSITY_RATIO_RANGE` | `function` / `function` / `function` / `constant` | **ISO 7235 Eqs. (8), (9), (11), (13), (16), (19) and (20): the flow quantities the pressure loss coefficient is built from.**<br>• `volume_flow_rate(mass_flow, density)`: q_V = q_m/ρ, with ρ the normalised density of Eq. (10) when the meter and the object leave `DENSITY_RATIO_RANGE` (0.98 to 1.02)<br>• `dynamic_pressure(volume_flow, area, density)`: `(ρ/2)(q_V/S)²`, the velocity head<br>• `total_pressure(static_pressure, volume_flow, area, density)`: static plus dynamic in one plane | `noise_control.dynamic_pressure(1.0, 0.0962, 1.2)  # 64.8 Pa` |
| `total_pressure_loss` / `pressure_loss_coefficient` / `average_pressure_loss_coefficient` | `function` | **ISO 7235 Eqs. (12), (14), (17) and (18): what an object costs to push air through, in velocity heads.**<br>• `total_pressure_loss(static_pressure_loss_pa, inlet_dynamic_pressure_pa, inlet_area, outlet_area)`: adds `p_d1[1 − (S_1/S_2)²]`, which vanishes when the two ducts match<br>• `pressure_loss_coefficient(total_loss, inlet_dynamic_pressure_pa)`: ζ, the same number at every flow rate the object sees the same flow pattern at, warning at 10 Pa and below<br>• `average_pressure_loss_coefficient(object_static, object_dynamic, substitution_static, substitution_dynamic)`: Eq. (18), a substitution average over each series' own flow rates, warning below five points | `noise_control.pressure_loss_coefficient(45.0, 64.8)  # 0.694` |
| `upstream_straight_length` / `MINIMUM_FLOW_RATES` / `MINIMUM_PRESSURE_DIFFERENCE_PA` / `UPSTREAM_STRAIGHT_DIAMETERS` / `UPSTREAM_STRAIGHT_MIN_M` / `VELOCITY_PROFILE_TOLERANCE_PERCENT` | `function` / `constant` | **ISO 7235 6.5.2.1 and 6.5.2.2.1: what a flow measurement needs before it counts.**<br>• `upstream_straight_length(area)`: max(5 d_e, 2 m) with `d_e = √(4S/π)`, the two rules crossing at a 0.4 m equivalent diameter<br>• five airflow rates per series, the lowest above 10 Pa, and a velocity profile uniform to ±10 % excluding 15 mm from the walls | `noise_control.upstream_straight_length(0.5)  # 3.99 m` |
| `duct_sound_power_level` | `function` | **ISO 5135 Eq. (1): from what the room heard back to what the duct carries.**<br>• `room_sound_power_level` L_W [dB] from ISO 3741, `end_reflection_loss` ΔL_r [dB]<br>• ISO 5135 Eq. (2) is ISO 7235 Eq. (B.3) written out, so `open_end_transmission_loss` supplies both, and their two solid-angle tables agree entry for entry<br>• the NOTE to Table 1 offers a transmission element to ISO 7235 as an alternative to correcting at all | `noise_control.duct_sound_power_level(lw, d_td)` |
| `fit_operating_line` / `OperatingLine` / `EXTRAPOLATION_MAX_DEVIATION_DB` / `EXTRAPOLATION_RANGE_FACTORS` / `REPORTING_RESOLUTION_DB` | `function` / `dataclass` / `constant` | **ISO 5135 5.5.2: the least-squares line a level is read off at a duty the laboratory did not measure at.**<br>• `duty` q_V [m³/s] or Δp_t [Pa], `levels` [dB], at least two points at more than one duty<br>• result: `slope` [dB/decade], `intercept`, `maximum_deviation`, `smallest_duty`, `largest_duty`, `valid_range` (half to twice), `.level_at(duty)`, `.plot()`<br>• warns past the 3 dB of 5.5.2, and again when a duty is read outside the range the clause allows; 8 k) reports to half a decibel | `noise_control.fit_operating_line(q, lwa).level_at(0.3)` |
| `end_reflection_loss` / `elbow_insertion_loss` | `function` | **HVAC duct end reflection & bend insertion loss (Bies Tables 8.14/8.11, ASHRAE).**<br>• end: `frequencies`, `diameter_m`, `termination` 'flush'/'free'<br>• elbow: `frequencies`, `width`, `bend_type`, `vanes`, `lined` | `end_reflection_loss(bands, 0.3)`<br><br>• `HvacSpectrumResult` |
| `plenum_attenuation` | `function` | **Plenum-chamber TL by Wells' method (Bies Eq. 8.275).**<br>• `exit_area`, `line_of_sight`, `wall_area`, `mean_absorption`, `angle_rad` | `plenum_attenuation(0.1, 1.0, 20.0, 0.2)  # dB` |
| `plot_plenum_geometry` | `function` | **Plenum section honouring r and θ exactly.**<br>• `exit_area` S_out [m²], `line_of_sight` r [m], `wall_area` S_w [m²]<br>• `angle_rad` θ [rad] (Default: 0)<br>• `language` | `plot_plenum_geometry(0.09, 1.2, 6.0, angle_rad=0.35)`<br><br>• Box fixed by r/θ, S_out mouth to scale, S_w annotated |
| `flow_noise_straight_duct` / `flow_noise_bend` | `function` | **HVAC flow-generated (self) noise sound power (VDI 2081, Bies Eqs. 8.251/8.254).**<br>• `frequencies`, `flow_velocity`, `area` (+ `height` for the bend) | `flow_noise_straight_duct(bands, 10.0, 0.04)`<br><br>• `HvacSpectrumResult` |
| `flow_noise_straight_duct_overall` | `function` | **Overall flow noise of a straight run (VDI 2081 Equations (16) and (17)).**<br>• `flow_velocity` v, `area` S<br>• `weighting='Z'` gives `7 + 50 lg v + 10 lg S`, `'A'` gives `-25 + 70 lg v + 10 lg S`<br>• the octave levels of `flow_noise_straight_duct` do not sum back to it: Figure 16 is a shape, not a partition | `flow_noise_straight_duct_overall(5.83, 0.2)`<br><br>• 38.3 |
| `HvacSpectrumResult` | `dataclass` | **Per-frequency HVAC attenuation or regenerated Lw.**<br>• `frequencies`, `values`, `quantity`, `label`<br>• `.plot()` | `res.values` |
| `fan_sound_power` | `function` | **Octave-band fan sound power from the operating point, by either method (Long Eq. 13.1 / ASHRAE 1987, or VDI 2081 Blatt 1 Eqs. (13)/(15)).**<br>• `model`: `'ashrae'` (Default) or `'vdi2081'`; each takes its own arguments, and the two pressures are different quantities<br>• `volume_flow` Q [m³/s]<br>• ASHRAE: `fan_static_pressure_pa` P [Pa gauge]<br>• `fan_type` (Table 13.5 rows: `'forward_curved'`, `'airfoil_large'`, `'radial_high'`, `'vaneaxial_hub_low'`, `'tubeaxial_small'`, `'propeller'` …)<br>• `relative_efficiency_percent` [% of peak] (Default: 80 → C_EFF 6 dB), `blade_frequency`<br>• VDI 2081: `fan_total_pressure_pa` Δp_t [Pa], `assembly` (`'rr'`/`'t'`/`'am'`), `fan_speed_rpm` n [min⁻¹], `specific_sound_power_level` L_WSM (Default: 34/36/42 dB by assembly), `blade_count` z, `relative_flow` V̇/V̇_opt (Default: 1)<br>• `frequencies` | `fan_sound_power(2.36, fan_static_pressure_pa=498.0)`<br><br>• `HvacSpectrumResult`; prefer AMCA 300 manufacturer data |
| `octave_band_limits` / `VDI2081_SPECTRAL_CORRECTION` | `function` / `array` | **Octave limits from an A-weighted room requirement (VDI 2081 Blatt 2 Eq. (1)).**<br>• `a_weighted_limit_db` L_A [dB], `frequencies`<br>• L_Okt,max = L_A + K_A, with K_A the inverse A-weighting less the 5 dB the guideline allows for the sum of eight octaves<br>• `VDI2081_SPECTRAL_CORRECTION`: K_A = 21, 11, 4, −2, −5, −6, −6, −4 dB | `noise_control.octave_band_limits(25.0)`<br><br>• `HvacSpectrumResult` (46, 36, 29, 23, 20, 19, 19, 21 dB) |
| `fan_efficiency_correction` / `blade_passing_frequency` / `fan_casing_attenuation` | `function` | **The three side terms of the fan model (Long Tables 13.6/13.7/13.8, Eq. 13.4).**<br>• `fan_efficiency_correction(relative_efficiency_percent=80.0)` → C_EFF [dB] (6,0 at 80 %)<br>• `blade_passing_frequency(rotational_speed, blades)` = rpm·N/60 [Hz]<br>• `fan_casing_attenuation(frequencies)` → casing-radiated attenuation | `blade_passing_frequency(1200.0, 12)  # 240 Hz` |
| `HvacWarning` | `warning class` | **A relative efficiency below the 50 % floor Long Table 13.6 is tabulated from.**<br>The table's worst-case row is returned, which is where a caller who passed a fraction such as 0,8 instead of 80 also lands; the two are indistinguishable from the value alone | `warnings.simplefilter("error", noise_control.HvacWarning)`<br>Emitted by `noise_control.hvac` |
| `unlined_rectangular_duct_attenuation` / `unlined_circular_duct_attenuation` | `function` | **Straight unlined sheet-metal duct attenuation (Long Eqs. 14.9-14.11, Table 14.1).**<br>• rectangular: `frequencies`, `width`, `height`, `length`, `wrapped` (fibreglass blanket doubles 63-250 Hz)<br>• circular: `frequencies`, `length` (about a tenth of the rectangular loss) | `unlined_rectangular_duct_attenuation(bands, 0.9, 0.6, 1.5)`<br><br>• `HvacSpectrumResult` |
| `lined_rectangular_duct_attenuation` / `lined_circular_duct_attenuation` | `function` | **Lined-duct insertion loss, Reynolds (1990) regressions (Long Eqs. 14.12/14.13, Tables 14.2/14.3).**<br>• rectangular: `frequencies`, `width`, `height`, `length`, `lining_thickness`, `include_unlined`<br>• circular: `frequencies`, `diameter_m`, `length`, `lining_thickness`<br>• Flanking caps a run at 40 dB | `lined_rectangular_duct_attenuation(None, 0.46, 0.30, 1.8, 0.025)` |
| `flexible_duct_insertion_loss` | `function` | **Lined round flexible duct IL (Long Table 14.4, ASHRAE 1995), 63 Hz-4 kHz.**<br>• `frequencies`, `diameter_m` (100-406 mm), `length` (0.9-3.7 m)<br>• Interpolated over length and log diameter_m | `flexible_duct_insertion_loss(None, 0.305, 1.8)` |
| `splitter_silencer_insertion_loss` | `function` | **Parallel-splitter (dissipative) silencer IL: each airway a lined duct of half the splitter thickness, combined by Bies Eq. (8.241).**<br>• `frequencies`, `height`, `length`, `airway_widths` (scalar or per airway), `splitter_thickness`<br>• Prefer the manufacturer's dynamic insertion loss | `splitter_silencer_insertion_loss(None, 0.6, 1.5, [0.1]*3, 0.2)` |
| `silencer_self_noise` | `function` | **Regenerated (self) noise of a splitter silencer (Long Eq. 14.31 + Table 14.8, Fry 1988).**<br>• `frequencies`, `airway_velocity` V [m/s], `passages` N, `height` H [m]<br>L_W = 55·lg V + 10·lg N + 10·lg(H/1 mm) − 45 | `silencer_self_noise(None, 10.0, 4, 0.9)` |
| `section_change_loss` | `function` | **Reflection at a sudden change of duct section (VDI 2081 6.3, Figure 26).**<br>• `upstream_area` S1, `downstream_area` S2; the loss is `10 lg (r+1)²/(4r)` in `r = S1/S2`<br>• a sudden reduction reflects in every band; a sudden increase only below the limit frequency of the upstream duct, so `shape` and `upstream_size` are needed for it<br>• `cap` (Default: 5 dB, VDI 3733's recommendation) | `noise_control.section_change_loss(bands, 0.5, 0.2, shape='round')`<br><br>• 0.88 dB |
| `split_loss` | `function` | **Branch power-division loss at a duct split (Long Eq. 14.17), returned as a positive attenuation.**<br>• `main_area` S_m [m²], `branch_areas` [m²], `branch` index | `split_loss(0.6, [0.15]*4)  # 6.02 dB` |
| `end_reflection_loss_closed_form` / `equivalent_diameter` | `function` | **Reynolds' closed-form duct end reflection (Long Eqs. 14.14-14.16); the alternative to the `end_reflection_loss` table look-up (`method='long'`).**<br>• `frequencies`, `diameter_m`, `termination` 'flush'/'free'<br>• `equivalent_diameter(area)` = √(4S/π) for a rectangular duct | `end_reflection_loss(bands, 0.3, method='long')` |
| `diffuser_sound_power` | `function` | **Regenerated (self) noise of a grille, register or diffuser (Long Eqs. 13.27-13.33, Reynolds 1990).**<br>• `frequencies`, `face_area` S_G [m²], `volume_flow` Q [m³/s], `pressure_drop_pa` ΔP [Pa]<br>• `shape` 'rectangular'/'round', `count` n (adds 10·lg n)<br>• 18 dB per doubling of approach velocity; peak band at f_P = 48.8·U_G | `diffuser_sound_power(None, 0.372, 0.147, 12.4)` |
| `air_terminal_velocity_limit` / `air_terminal_damper_correction` | `function` | **Screening checks for grilles, registers and diffusers (ASHRAE 2019 Ch. 49 Tables 9/10); a measured device spectrum to ASHRAE Standard 70 beats both.**<br>• `air_terminal_velocity_limit(design_criterion, opening='supply'/'return')` [m/s]<br>• `air_terminal_damper_correction(pressure_ratio, location='diffuser_neck'/'plenum_inlet'/'supply_duct')` [dB] | `air_terminal_velocity_limit(30)  # 2.2 m/s` |
| `room_effect` | `function` | **Room effect: the drop from the sound power at the terminal device to the level in the room (Long Eq. 14.40, VDI 2081-1 Eq. 36), as a positive attenuation.**<br>• `distance` r [m]<br>• `room_constant` R [m²] or `absorption_area` A [m²], exactly one, scalar or per band<br>• `directivity` Q (Default: 2, flush in a ceiling), scalar or per band | `room_effect(3.0, room.room_constant(S, alpha))`<br>`room_effect(1.5, absorption_area=20.0, directivity=q_per_band)` |
| `duct_path` | `function` | **End-to-end duct-borne cascade, fan to room (Long Table 14.9; AHRI 885 Table 8).**<br>• `frequencies`, `source_level` L_W, `elements` (`DuctElement` list)<br>• `room_effect`, `criterion` 'NC'/'RC', `target`, `self_noise_floor` (Default: 0 dB)<br>• `section`/`flow_velocity` → plane-wave validity warning | `duct_path(bands, lw, elements, room_effect=6.0, target=30)`<br><br>• `DuctPathResult` |
| `DuctElement` / `DuctPathStage` | `dataclass` | **One path element and its computed rows.**<br>• `DuctElement`: `label`, `attenuation` (positive loss; scalar, array or `HvacSpectrumResult`), `self_noise` L_W, `code`<br>• `DuctPathStage`: `attenuation`, `attenuated` (the *Sum* row), `self_noise`, `levels` (the *Combined* row) | `DuctElement('Silencer', il, sn, code='3')` |
| `DuctPathResult` | `dataclass` | **Duct-borne noise path result.**<br>• `received_level`, `stages`, `room_effect`, `criterion`, `target`, `contributions`<br>• `.rating` (NC/RC), `.criterion_curve`, `.exceedance`, `.meets_target`<br>• `.table()`: the printed sheet, row by row<br>• `.plot()`: the cascade vs the criterion curve; `.report()`: one-page sheet | `res.meets_target` |
| `combine_duct_paths` | `function` | **Energy sum of the received spectra of several paths (supply + return).**<br>• `paths`, `criterion`, `target`, `label` | `combine_duct_paths([supply, ret])`<br><br>• `DuctPathResult` with `contributions` |
| `room_to_room_transmission` | `function` | **Room-to-room chain: source-room level → partition TL → receiving-room absorption → criterion (Norton Eq. 4.101, `NR = TL − 10 lg[S_w/(S₂α₂ + τS_w)]`).**<br>• `frequencies`, `transmission_loss`, `partition_area` S_w [m²], `receiving_absorption` S₂α₂ [m²]<br>• `source`: `SourceRoom`<br>• `include_partition_transmission` (the τS_w term)<br>• `criterion`: `DesignCriterion`, `label`<br>• `receiver_distance_m` [m]: adds the direct field of the partition at that distance, Barron (2003) Eqs. (7-71) and (7-72), g = 1/4 inside r* = (S_w/2π)^½ and S_w/(8πr₂²) beyond it; `None` (Default) is the reverberant field alone | `room_to_room_transmission(bands, tl, 24.0, a2, source=noise_control.SourceRoom(level=lp1), criterion=noise_control.DesignCriterion(target=45))`<br><br>• `RoomToRoomResult` |
| `RoomToRoomResult` | `dataclass` | **Room-to-room chain result.**<br>• `source_level`, `transmission_loss`, `receiving_absorption`, `noise_reduction`, `received_level`<br>• `.rating` (NC/RC), `.criterion_curve`, `.exceedance`, `.meets_target`<br>• `.required_transmission_loss`: the partition TL that just meets the criterion, at `receiver_distance_m` when one was given<br>• `.table()`: the rows of the hand calculation; `.plot()`: both spectra, the curve and NR | `res.required_transmission_loss` |
| `SourceRoom` | `dataclass` | **The source room of the room-to-room chain (Norton 4.7, Table 4.5).**<br>• `level` L_p1 [dB], or `power_level` L_W [dB] + `room_constant` R₁ [m²]<br>• `directivity` Q (Default: 1)<br>• `model`: 'constant_power' (Default) / 'constant_volume' / 'constant_pressure' | `SourceRoom(power_level=lw, room_constant=r1, directivity=4.0, model='constant_volume')` |
| `DesignCriterion` | `dataclass` | **The design criterion of a composed chain.**<br>• `family`: 'NC' (Default) / 'RC'<br>• `target` (Default: None → no verdict)<br>• `flanking_penalty` [dB] (Default: 0) | `DesignCriterion(target=45.0, flanking_penalty=3.0)` |
| `circular_duct_cut_on` / `rectangular_duct_cut_on` | `function` | **Higher-order acoustic mode cut-on with mean flow (Norton & Karczub Eqs. 7.6-7.10, Table 7.1).**<br>• circular: `diameter_m`, `flow_velocity`, `speed_of_sound`, `count` (≤ 12)<br>• rectangular: `width`, `height`, …<br>• Flow lowers every cut-on by √(1 − M²) and shifts it to k_x = −Mκ/√(1 − M²) | `circular_duct_cut_on(0.254, flow_velocity=200.0)`<br><br>• `DuctModeResult` |
| `DuctModeResult` | `dataclass` | **Duct cut-on result.**<br>• `modes` (p, q), `cut_on`, `cut_on_no_flow`, `axial_wavenumber`, `mach`<br>• `.plane_wave_limit`: the lowest cut-on<br>• `.plot()`: the cut-on ladder with and without flow | `res.plane_wave_limit` |
| `plane_wave_limit` / `PlaneWaveWarning` | `function` / `warning class` | **The frequency above which a duct stops carrying plane waves only, and the warning the plane-wave results raise past it.**<br>• `plane_wave_limit(diameter_m=…)`, or `width`/`height`, or `area`<br>• `flow_velocity`, `speed_of_sound`<br>• Emitted by `duct_path(section=…)` and by every `ReactiveSilencerResult` | `plane_wave_limit(width=0.65, height=0.4)  # 264 Hz` |
| `DuctWallSpectrum` | `dataclass` | **One duct wall of one printed table, in one of the two directions.**<br>• `transmission_loss_63_db` … `transmission_loss_8000_db`, in decibels, and `direction` says whether they are the sound leaving the duct or the sound entering it<br>• `shape`: what the table's own title calls the duct, `'rectangular'`, `'round'`, `'flat oval'` or `'circular'`; the chapter uses two words for one geometry<br>• `first_side_mm` / `second_side_mm` in the order the page prints them, or `diameter_mm`, and `duct_length_m` for the two tables that print a length per row<br>• `sheet_metal_gauge`: the US gauge exactly as printed, asterisk and all; the chapter converts one of the six these tables use, `'16 ga (1.6 mm thickness)'` on folio 49.37, and none of the other five, so no thickness is offered<br>• `.is_breakout`, `.is_break_in`, `.bands()`, `.spectrum()` → `{band_hz: db}`, `.transmission_loss_db(band_hz)` narrows or refuses<br>• `ranges` + `bounded_below` for a cell written `>45`, whose open end is empty because a transmission loss has no ceiling, and `unquantified` for one printed as a rule the chapter never explains; a value the page puts in parentheses is held as printed and the mark is recorded in `note` | `row = noise_control.duct_wall_named('305 × 305 mm')[0]`<br>`row.direction  # 'breakout'`<br>`row.transmission_loss_db(63)  # 21 dB`<br><br>• `PUBLISHED_DUCT_TRANSMISSION_LOSS`, `duct_wall_named` |
| `PUBLISHED_DUCT_TRANSMISSION_LOSS` | `mapping` | **Forty-six duct walls over six published tables, keyed `'<table>/<row>'`.**<br>• ASHRAE Chapter 49 **Tables 29 to 34** (PDF pages 914-916): breakout for rectangular, round and flat oval ducts, then break-in for the same three<br>• one row per printed row and one quantity per row: the round tables measure 200, 350, 560 and 810 mm at 4.6 m for breakout and 203, 356, 559 and 813 mm at 4.57 m for break-in, so there is no construction that carries both<br>• only the two measured tables say so in their titles, and they are the two that carry the bounds and the parenthesised values the background sound left; the other four say nothing about how they were obtained<br>• no table carries a source line, and every row credits the sentence of running text that credits it, in `attributed_to['table']`<br>• machine equipment room walls are not here: Table 40 of the same chapter is an ordinary partition and is published from `building.PUBLISHED_TRANSMISSION_LOSS` | `noise_control.PUBLISHED_DUCT_TRANSMISSION_LOSS['ashrae-2019-tables-29-to-34/t30_long_seam_200_gage_26']`<br><br>• `DuctWallSpectrum`, `duct_wall_named` |
| `duct_wall_named` | `function` | **Every duct wall whose printed label contains the text.**<br>• `name`: part of a row label with the unit its column heading carries, `'610 mm'`, `'305 × 1220'`, matched without case<br>• one size is printed by a breakout table and by a break-in table, so the plain answer is two rows that are two different quantities; read `direction` to tell them apart<br>• `catalogue=`: the rows to search instead of `PUBLISHED_DUCT_TRANSMISSION_LOSS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_DUCT_TRANSMISSION_LOSS \| mine`; a row of another class is refused by its key (`TypeError`) | `noise_control.duct_wall_named('305 × 305 mm')  # two rows, two quantities`<br><br>• `PUBLISHED_DUCT_TRANSMISSION_LOSS` |
| `DUCT_WALL_BANDS_HZ` | `constant` | **The octave bands a duct-wall table can print: 63 Hz to 8 kHz.**<br>• `(63, 125, 250, 500, 1000, 2000, 4000, 8000)`; the two rectangular tables print all eight, and the round, circular and flat oval ones stop at 4 kHz and leave the last field empty on every row | `noise_control.DUCT_WALL_BANDS_HZ[-1]  # 8000` |
| `enclosure_insertion_loss` / `ENCLOSURE_MODELS` | `function` / `mapping` | **Machine-enclosure insertion loss IL = R − C (Bies Eqs. 7.103/7.111); panel R supplied by the caller, never predicted.**<br>• `panel_transmission_loss` (per-band array or callable of f)<br>• `external_area`, `internal_area`, `internal_absorption`<br>• `frequencies` (required for a callable R)<br>• `model`: `ENCLOSURE_MODELS` (`'bies'` keeps the 0.3 floor of Eq. 7.111, `'norton'` the bare `C = 10 lg(S_E/R_i)` of Eq. 4.115) | `enclosure_insertion_loss(R, 6.0, 5.0, 0.3)`<br><br>• `EnclosureResult` |
| `enclosure_required_transmission_loss` | `function` | **The same equation solved for the panel R: `R = IL + C` (Norton Eq. 4.115 design use).**<br>• `insertion_loss` (required IL per band, e.g. the room level minus an NC curve)<br>• `external_area`, `internal_area`, `internal_absorption`, `frequencies`, `model` | `enclosure_required_transmission_loss(lp1 - nc45, 38.75, 59.5, alpha)`<br><br>• `EnclosureResult` whose `panel_transmission_loss` is the required R |
| `sound_power_insulation` / `sound_pressure_insulation` / `reciprocity_insulation` / `artificial_source_insulation` | `function` | **What an enclosure is worth once it is built, ISO 11546-1 and -2 Eqs. (1) to (5).**<br>• `sound_power_insulation(level_without, level_with, frequencies=…)`: D_W band by band, and D_WA from the A-weighted totals or from an explicit pair<br>• `sound_pressure_insulation(…)`: the same subtraction on a level at a stated position, D_p and D_pA<br>• `reciprocity_insulation(external_levels, internal_levels, …)`: D_pr of part 1 clause 7.2, for an enclosure that cannot be measured with its machine<br>• `artificial_source_insulation(without_by_position, with_by_position, …)`: the tapping plate of Annex A, averaged over source positions arithmetically, which is the standard's own word and not the energy mean used elsewhere<br>• `condition`: 'laboratory' (part 1, for declaration) or 'in-situ' (part 2, for acceptance); `base_standard`: the row of Table 1 the levels came from | `noise_control.sound_power_insulation(lw_off, lw_on, frequencies=f)`<br><br>• `EnclosureInsulationResult` |
| `EnclosureInsulationResult` | `dataclass` | **The insertion loss of an enclosure, band by band.**<br>• `frequencies` [Hz], `level_without`, `level_with`, `insulation` [dB]<br>• `quantity`: 'sound_power', 'sound_pressure' or 'reciprocity'; `a_weighted_insulation` [dB]<br>• `condition`, `source_kind`, `base_standard`, `band_fraction`<br>• `.rounded()`: the integers clause 9.4 reports; `.plot()`: the two runs, the area between them and the difference | `res.rounded(), res.a_weighted_insulation` |
| `weighted_insulation` / `WeightedEnclosureInsulation` | `function` / `dataclass` | **The single-number rating of an insertion loss, 7.4 of part 1 and 7.3 of part 2.**<br>• `insulation` over the 16 one-third-octave rating bands or the 5 octave ones [dB], `quantity`, `band_fraction`<br>• ISO 717-1 with D_W or D_pr written where that standard writes R, delegated to `building.weighted_rating` rather than re-derived<br>• result: `rating`, `c`, `ctr`, `unfavourable_sum`, `band_centres_hz`, `quantity` | `noise_control.weighted_insulation(d_w[:16]).rating` |
| `estimated_a_weighted_insulation` | `function` | **What an enclosure would be worth against a stated spectrum, Annex C of part 1 and Annex D of part 2.**<br>• `spectrum_levels` L_i [dB], `insulation` D_i [dB], `frequencies` [Hz]<br>• `D_WA,e = L_A − 10 lg Σ 10^(0.1 (L_i − A_i − D_i))`, with A_i the printed attenuation, so A_i = −C_k against this library's band corrections<br>• both terms are built from the same table, so the answer cannot disagree with its own inputs and an insulation of zero returns exactly zero | `noise_control.estimated_a_weighted_insulation(spectrum, d_w, frequencies=f)` |
| `applicable_methods` / `MethodEntry` | `function` / `dataclass` | **Table 1 of ISO 11546 as data: which base standard may be used, and what it can give.**<br>• `condition`: 'laboratory' (Default) or 'in-situ'; `source_kind`: 'actual' (Default), 'reciprocity' or 'artificial'<br>• each row carries `base_standard`, `quantities`, `subclause` and `band_values`: a survey-grade determination hands back an A-weighted number and nothing per band, so D_W cannot be declared from it<br>• the reciprocity method exists in part 1 only, and asking for it in situ is refused | `noise_control.applicable_methods(condition='in-situ')` |
| `test_environment_applicability` / `TestEnvironmentApplicability` / `TEST_ENVIRONMENT_REQUIREMENTS` / `ROOM_ABSORPTION_ESTIMATES` | `function` / `dataclass` / `mapping` / `mapping` | **Is this room good enough for that base standard? Annex C of ISO 11546-2.**<br>• `base_standard`, `mean_absorption_coefficient` α, `room_surface_area_m2` S_V, `measurement_surface_area_m2` S<br>• `S_V/S = 4/((10^(K2/10) − 1) α)`, which is Figure C.1 in closed form, cross-checked against `emission.environmental_correction`<br>• `TEST_ENVIRONMENT_REQUIREMENTS` is Table C.1, the K2 ceiling and the background margin of each standard; ISO 3743-1 and ISO 3747 state no K2 at all<br>• `ROOM_ABSORPTION_ESTIMATES` is Table C.2, the seven room descriptions and their α, for when nobody measured it | `noise_control.test_environment_applicability(base_standard='ISO 3744', mean_absorption_coefficient=0.15, room_surface_area_m2=520.0, measurement_surface_area_m2=14.1)` |
| `leak_ratio` / `seal_ratio` / `fill_ratio` / `source_position_clearance_m` | `function` | **The four ratios and distances the two standards define in words.**<br>• `leak_ratio(opening_area_m2, interior_surface_area_m2)`: θ, the openings over the interior surface; an opening with an effective silencer is not one<br>• `seal_ratio(leak)`: ψ = 1/θ, the same fact for a catalogue that prefers it<br>• `fill_ratio(source_volume_m3, interior_volume_m3)`: φ, how much of the enclosure the source fills<br>• `source_position_clearance_m(shortest_inner_dimension_m)`: 0,2 d, so the tapping plate is never against the panel it excites | `noise_control.seal_ratio(noise_control.leak_ratio(0.02, 6.0))  # 300` |
| `UNRESTRICTED_ENCLOSURE_VOLUME_M3` / `ARTIFICIAL_SOURCE_MAX_FILL_RATIO` / `ARTIFICIAL_SOURCE_LEAK_RATIO_ADVISORY` / `ARTIFICIAL_SOURCE_PLATE_MM` / `ARTIFICIAL_SOURCE_DROP_MM` / `ARTIFICIAL_SOURCE_STANDOFF_MM` / `ARTIFICIAL_SOURCE_EXAMPLE_LWA_DB` / `SOURCE_WALL_CLEARANCE_FACTOR` | `constant` | **The numbers of clause 1, clause 4 and Annex A of ISO 11546.**<br>• clause 1 applies the part without restriction to a free-standing enclosure smaller than 2 m³, and lets a larger one be measured with its actual source while the base standard's own volume limit is met; the artificial source fills at most a quarter of the interior, and clause 4 would rather keep the leak ratio under 2 %<br>• the Annex A source is a 4 mm steel plate of 800 mm by 300 mm, dropped 40 mm onto a 60 mm standoff<br>• the spectrum Annex B prints as an illustration totals 110 dB(A), and it was measured on a 600 mm plate rather than on the Annex A one (see the errata)<br>• the plate stands 0,2 d from any wall | `noise_control.ARTIFICIAL_SOURCE_PLATE_MM` |
| `MANDATORY_BAND_RANGE_HZ` / `PREFERRED_BAND_RANGE_HZ` | `mapping` | **The band range ISO 11546 and ISO 11957 require, and the one they would rather have, keyed by band fraction.**<br>• required: 100 Hz to 5 kHz in one-third octaves, 125 Hz to 4 kHz in octaves<br>• preferred: 50 Hz to 10 kHz and 63 Hz to 8 kHz<br>• a spectrum that does not cover the required range raises the warning of its own standard | `noise_control.MANDATORY_BAND_RANGE_HZ[3]  # (100.0, 5000.0)` |
| `EnclosureInsulationWarning` / `CabinInsulationWarning` | `warning class` | **The measurement is outside a condition ISO 11546 or ISO 11957 states.**<br>• a band range short of the required one, a base standard that gives only an A-weighted value, a margin under 6 dB over the background<br>• a room-to-cabin volume ratio under 20, a lowest band outside the range clause 6.2 covers | `warnings.simplefilter('error', CabinInsulationWarning)`<br>Emitted by `noise_control.enclosure_insulation` |
| `cabin_insulation` / `CabinInsulationResult` | `function` / `dataclass` | **What a cabin keeps out, ISO 11957 Eqs. (1), (2) and (3).**<br>• `room_levels`, `cabin_levels` [dB], `frequencies` [Hz], `band_fraction`<br>• `method`: 'laboratory' (Default), 'in-situ-loudspeaker' or 'in-situ-actual-noise'; the in-situ pair carries the prime of definition 3.6<br>• `room_background_levels` / `cabin_background_levels`: taken off by the ISO 3741 correction 6.4 asks for<br>• `a_weighted_room_level` / `a_weighted_cabin_level`: Eq. (3), defined for the actual-noise method alone, and refused under any other<br>• result: `insulation`, `symbol`, `a_weighted_insulation`, `internal_noise_level`, `.rounded()`, `.plot()`; `apparent` is read-only, read from `method`, which also decides whether `a_weighted_insulation` can be given | `noise_control.cabin_insulation(room, cabin, frequencies=f)` |
| `weighted_cabin_insulation` / `WeightedCabinInsulation` | `function` / `dataclass` | **The single-number rating of a cabin, ISO 11957 clause 8.**<br>• `insulation` over the rating bands [dB], `apparent`, `band_fraction`<br>• ISO 717-1 with D_p or D'_p written where that standard writes R<br>• clause 4 calls this the preferred single number and then warns against reading too much into it, because what a cabin is worth depends on the spectrum it stands in | `noise_control.weighted_cabin_insulation(d_p[:16]).rating` |
| `estimated_cabin_noise_insulation` / `internal_noise_level` | `function` | **Annex A and 6.7 of ISO 11957: the cabin against a stated spectrum, and the noise it makes on its own.**<br>• `estimated_cabin_noise_insulation(spectrum_levels, insulation, frequencies=…)`: `D_pA,e = L_A − 10 lg Σ 10^(0.1 (L_i − A_i − D_pi))`, the same identity and the same A_i sign as the enclosure annexes<br>• `internal_noise_level(levels, background_level=…)`: L_pA, the energy mean over the 0,3 m sphere with the external sources off<br>• the background rule of 6.7 is not the one of 6.4: the correction is made only while the margin stays between 6 dB and 10 dB, and below 6 dB the answer is an upper bound | `noise_control.internal_noise_level([58.2, 59.1, 58.7], background_level=51.0)` |
| `check_source_positions` / `SourcePositionCheck` / `MIN_SOURCE_POSITIONS_IN_SITU` / `MAX_SOURCE_POSITIONS_IN_SITU` | `function` / `dataclass` / `constant` | **Were there enough loudspeaker positions? ISO 11957 7.2.1.**<br>• `insulation_by_position`: D'_p in octave bands, one row per source position<br>• the number of positions shall be at least the largest difference in decibels between any two of them, three to begin with and six at most<br>• result: `positions_used`, `max_octave_spread_db`, `required_positions`, `satisfied`, `exceeds_maximum`, the last of which 7.2.1 says shall be stated in the report<br>• the clause says octave bands, so one-third-octave data is folded at the level and not at the difference | `noise_control.check_source_positions(d_p_by_position).satisfied` |
| `check_band_flatness` / `BandFlatnessCheck` / `BAND_FLATNESS_LIMIT_DB` / `DEFAULT_BAND_FLATNESS_LIMIT_DB` | `function` / `dataclass` / `mapping` / `constant` | **Is the driving spectrum flat enough inside each octave? ISO 11957 6.4 and 7.2.1.**<br>• `third_octave_levels` [dB], `frequencies` [Hz], read three bands to an octave<br>• 6 dB in the octave of 125 Hz, 5 dB in the one of 250 Hz, 4 dB above; nothing is printed below 125 Hz, so `limit_db` is `nan` there and the octave counts as satisfied<br>• result: `octave_centres_hz`, `spread_db`, `limit_db`, `satisfied`, `.all_satisfied` | `noise_control.check_band_flatness(lp, frequencies=f).all_satisfied` |
| `minimum_cabin_clearance_m` / `WALL_CLEARANCE_FACTOR` / `LOW_BAND_CLEARANCE_M` / `LOW_BAND_CLEARANCE_RANGE_HZ` | `function` / `constant` | **How far the cabin stands from the room, ISO 11957 6.2.**<br>• `lowest_band_frequency_hz`, `speed_of_sound` [m/s] (Default: 343)<br>• half a wavelength at the lowest band of interest, from the walls, the ceiling and any diffusing element alike<br>• from 50 Hz to 80 Hz the clause fixes a flat 2 m instead, which at 50 Hz is less than the half wavelength above it would have asked for: the low-frequency sentence relaxes the rule rather than tightening it, and it is written as printed (see the errata) | `noise_control.minimum_cabin_clearance_m(100.0)  # 1.715 m` |
| `uncertainty_conditions` / `CabinUncertainty` / `MIN_ROOM_TO_CABIN_VOLUME_RATIO` / `STATED_UNCERTAINTY_BAND_RANGE_HZ` / `INCREASED_UNCERTAINTY_BAND_RANGE_HZ` / `IN_SITU_EXCESS_STANDARD_DEVIATION_DB` | `function` / `dataclass` / `constant` | **What ISO 11957 clause 10 is willing to say about a measurement.**<br>• `room_volume_m3`, `cabin_volume_m3`, `method`<br>• in the laboratory the uncertainty of ISO 3741 carries over from 250 Hz to 10 kHz, while the room is at least 20 times the volume of the cabin; from 50 Hz to 200 Hz, and below that ratio, a larger uncertainty is expected<br>• the loudspeaker method in situ adds about 2 dB to the standard deviation<br>• for the actual-noise method the clause states nothing and sends a declared value to ISO 4871, so `stateable` is `False`<br>• `CabinUncertainty` takes `method`, `volume_ratio`; `ratio_satisfied`, `stateable`, `stated_band_range_hz`, `increased_uncertainty_band_range_hz`, `excess_standard_deviation_db` are read-only, read from them | `noise_control.uncertainty_conditions(room_volume_m3=300.0, cabin_volume_m3=12.0)` |
| `MIN_LOUDSPEAKER_SEPARATION_M` / `MIN_SOURCE_TO_CABIN_M` / `MIN_SOURCE_TO_MICROPHONE_M` / `MIN_SOURCE_TO_MICROPHONE_IN_SITU_M` / `MAX_MICROPHONE_TO_CABIN_M` / `MIN_MICROPHONE_HEIGHT_M` / `OPERATOR_SPHERE_RADIUS_M` / `OPERATOR_PATH_INCLINATION_DEG` / `INTERNAL_NOISE_CENTRE_HEIGHT_M` / `INTERNAL_NOISE_CENTRE_TOLERANCE_M` / `MIN_FIXED_MICROPHONE_POSITIONS` / `MIN_LOUDSPEAKER_POSITIONS` | `constant` | **The geometry of ISO 11957 6.4, 6.5 and 7.4, as numbers rather than as prose.**<br>• loudspeakers at least 3 m apart and 2 m from the cabin; 2 m from a microphone in the laboratory and 3 m in situ, which is a deliberate difference<br>• in a large room with a short reverberation time, no microphone further than 5 m from the outside of the cabin<br>• inside, no position closer than 0,2 d to a surface and none below 1 m; with a defined operator position, three points on a sphere of radius 0,3 m, or a path inclined 45°<br>• for the internal noise level the centre of that sphere is 1,55 m ± 0,075 m above the floor<br>• at least six fixed microphone positions and two loudspeaker positions in the laboratory; 7.4 fixes the microphones at exactly six | `noise_control.OPERATOR_SPHERE_RADIUS_M  # 0.3` |
| `MAX_LEAK_RATIO` / `MIN_SIGNAL_TO_BACKGROUND_DB` / `PREFERRED_SIGNAL_TO_BACKGROUND_DB` / `INTERNAL_NOISE_CORRECTION_WINDOW_DB` | `constant` | **The four thresholds ISO 11957 states as conditions rather than as advice.**<br>• clause 1 applies the standard to a cabin of leak ratio 2 % or less, where ISO 11546 only prefers the same figure<br>• 6 dB over the background, and preferably more than 12 dB, in every band of interest<br>• 6.7 corrects the internal noise level only while the margin is between 6 dB and 10 dB | `noise_control.MAX_LEAK_RATIO  # 0.02` |
| `in_situ_transmission_loss` / `in_situ_insertion_loss` / `SilencerInSituResult` | `function` / `function` / `dataclass` | **What a silencer is worth where it stands, ISO 11820 Eqs. (19) and (21).**<br>• `in_situ_transmission_loss(source_levels_db, receiver_levels_db, source_area_m2=, receiver_area_m2=)`: D_ts = D_tps + 10 lg(S₂/S₁) + K₂ − K₁<br>• `in_situ_insertion_loss(levels_without_db, levels_with_db, area_without_m2=, area_with_m2=)`: the same form with the two runs of Eq. (3) in place of the two sides<br>• each area and `field_correction_difference_db` [dB] take one value or one per band: the area of a diffuse room is a quarter of its absorption and moves with T, so pass what `reverberant_surface_area_m2` returns<br>• `case`: which installation of Figure 1 the numbers came from, checked against the quantity<br>• result: `loss_db`, `level_difference_db`, `area_term_db` and `field_correction_difference_db` (always per band), `quantity`, `.plot()` | `noise_control.in_situ_transmission_loss(l2, l1, source_area_m2=0.9, receiver_area_m2=18.0)` |
| `installation_case` / `InstallationCase` / `INSTALLATION_CASES` | `function` / `dataclass` / `mapping` | **The twenty installations of Figure 1 as data, with the area rules clause 9 gives each.**<br>• `number` 1 to 20, `source_side` / `receiver_side`: 'duct', 'room' or 'outdoors'<br>• `quantity`: 'transmission' for 1 to 16, 'insertion' for 17 to 20<br>• `source_area_rule` / `receiver_area_rule`: the duct cross-section, a quarter of the room absorption, a hemisphere or the aperture in the wall | `noise_control.installation_case(7).receiver_area_rule` |
| `transmission_level_difference_db` / `insertion_level_difference_db` / `mean_sound_pressure_level_db` | `function` | **The level differences ISO 11820 builds everything else from, Eqs. (1), (3) and (2).**<br>• `transmission_level_difference_db(source_levels_db, receiver_levels_db)`: across the silencer<br>• `insertion_level_difference_db(levels_without_db, levels_with_db)`: between the run without it and the run with it<br>• `mean_sound_pressure_level_db(levels_db)`: the energy mean over the measuring points | `noise_control.mean_sound_pressure_level_db([71.2, 73.4, 72.0])` |
| `sound_power_level_db` / `reverberant_surface_area_m2` / `SABINE_AREA_COEFFICIENT` | `function` / `function` / `constant` | **From a mean level to a sound power, Eqs. (5), (7), (9) and (11), and the area a reverberant room stands in for, Eqs. (6), (10) and (12).**<br>• `L_W = L̄_p + 10 lg(S/S₀) + K`, with S₀ = 1 m² and S whichever area the case calls for<br>• `reverberant_surface_area_m2(volume_m3, reverberation_time_s, speed_of_sound=340.0)`: S = 6 ln10 V / (c T), a quarter of the Sabine absorption area<br>• `SABINE_AREA_COEFFICIENT` is that 6 ln10, the 13,8 the three equations share | `noise_control.reverberant_surface_area_m2(320.0, t20)` |
| `extraneous_corrected_mean_level_db` / `silencer_background_correction_db` / `ISO11820_BACKGROUND_CORRECTIONS_DB` / `MAXIMUM_EXTRANEOUS_CORRECTION_DB` / `ISO11820_MINIMUM_BACKGROUND_MARGIN_DB` / `ISO11820_NEGLIGIBLE_BACKGROUND_MARGIN_DB` | `function` / `function` / `mapping` / `constant` | **The two routes ISO 11820 offers around extraneous sound, 9.1.1 to 9.1.3.**<br>• `extraneous_corrected_mean_level_db(levels_db, extraneous_levels_db)`: the energy subtraction of Eqs. (17) and (18), and whether it hit the 3 dB cap past which the quantity is not determined, judged on the margin of the two energy means as Table 1 draws it: a 3 dB margin, a 3,02 dB correction, is still determined<br>• `silencer_background_correction_db(level_difference_db)`: Table 1, in decibels to take off, stepped from 3 dB at a margin of 3 dB to 0,5 dB at 9 or 10<br>• a margin under 3 dB is refused; above 10 dB nothing is corrected, and 10 dB itself still takes off 0,5 dB | `noise_control.silencer_background_correction_db([4.0, 9.0])  # 2.0, 0.5` |
| `temperature_field_correction_db` / `TYPICAL_FIELD_CORRECTION_LIMIT_DB` / `ISO11820_SOUND_SPEED_M_S` | `function` / `constant` | **What a difference of temperature does to the field correction, Eqs. (20) and (22).**<br>• `K₂ − K₁ = 5 lg[(273 + θ₁)/(273 + θ₂)]`, the standard's own 273 rather than 273,15<br>• the same expression serves the insertion measurement, with the with-silencer run as the receiver side<br>• NOTE 4 expects K to stay under 3 dB in absolute value once the areas are the ones 3.3 and 3.4 define | `noise_control.temperature_field_correction_db(receiver_temperature_c=20.0, source_temperature_c=120.0)` |
| `octave_levels_from_third_octave_db` / `ISO11820_OCTAVE_BAND_RANGE_HZ` / `ISO11820_OCTAVE_BAND_EXTENDED_RANGE_HZ` / `ISO11820_THIRD_OCTAVE_BAND_RANGE_HZ` / `ISO11820_THIRD_OCTAVE_BAND_EXTENDED_RANGE_HZ` | `function` / `constant` | **The bands ISO 11820 measures in, 9.1.5 and 8.1.**<br>• `octave_levels_from_third_octave_db(levels_db)`: threes folded into octaves, the route the clause allows when the narrower bands were measured<br>• 63 Hz to 4 kHz in octaves, 50 Hz to 5 kHz in one-third octaves, with the extended ranges the clause names for a silencer that works outside them | `noise_control.octave_levels_from_third_octave_db(third_octave_levels)` |
| `total_pressure_loss_pa` / `static_pressure_difference_pa` / `velocity_pressure_pa` / `flow_velocity_m_s` / `gas_density_kg_m3` / `silencer_flow_velocity_m_s` / `ISO11820_GAS_CONSTANT` / `ISO11820_AIR_GAS_CONSTANT` / `ISO11820_AMBIENT_PRESSURE_PA` / `VELOCITY_UNIFORMITY_TOLERANCE_PERCENT` | `function` / `constant` | **The flow side of the measurement, Eqs. (13) to (16) and (27) to (31).**<br>• pressure loss Δp_T, the static difference Δp_S behind a change of area, the velocity pressure and the velocity it stands for<br>• `gas_density_kg_m3(temperature_c=, molar_mass_kg_kmol=None)`: ρ = M p_amb / [R (273 + θ)], with R/M = 287 N m per kg K for air<br>• `silencer_flow_velocity_m_s`: the upstream mean velocity scaled by S_u/S_f, which is the velocity the regenerated noise answers to<br>• 9.2 asks the velocity profile to be uniform within 10 % | `noise_control.gas_density_kg_m3(temperature_c=120.0)` |
| `measurement_distance_upstream_m` / `measurement_distance_downstream_m` / `UPSTREAM_DISTANCE_DIAMETERS` / `DOWNSTREAM_DISTANCE_COEFFICIENTS` | `function` / `constant` | **Where the measurement surfaces stand along the duct, Eqs. (15) and (16).**<br>• upstream: one and a half equivalent diameters of the measurement cross-section<br>• downstream: 12 √S_d − 10 √S_f, which can fall to zero for a silencer whose free area is most of the duct, and 8.3.1 then sends the parties to agree<br>• S_f is the free cross-section, which NOTE 18 warns is not the intake one | `noise_control.measurement_distance_downstream_m(0.9, 0.45)` |
| `SilencerInSituWarning` | `warning class` | **The measurement is outside a condition ISO 11820 states.**<br>• a downstream distance the geometry cannot give, a field correction past what NOTE 4 expects, a velocity profile outside the 10 % the standard asks for | `warnings.catch_warnings()`<br>Emitted by `noise_control.silencer_in_situ` |
| `screen_attenuation` / `ScreenInSituResult` | `function` / `dataclass` | **What a removable screen is worth where it stands, ISO 11821 clauses 5.8 and 5.9.**<br>• `unscreened_levels_db`, `screened_levels_db` [dB], `frequencies` [Hz], `distance_m`<br>• `source_kind`: 'actual' (Default) or 'artificial'<br>• `a_weighted_unscreened_level_db` / `a_weighted_screened_level_db`: the pair of 5.9, refused with an artificial source because the spectrum would be the loudspeaker's<br>• result: `attenuation_db`, `a_weighted_attenuation_db`, `.plot()`<br>• `.rounded()` and `.rounded_a_weighted()`: the whole decibels 7.4 c) reports, an exact half to the even one | `noise_control.screen_attenuation(without, with_screen, frequencies=f)` |
| `background_corrected_level_db` / `BACKGROUND_CORRECTION_WINDOW_DB` / `ISO11821_MINIMUM_BACKGROUND_MARGIN_DB` / `ISO11821_PREFERRED_BACKGROUND_MARGIN_DB` | `function` / `constant` | **The background correction ISO 11821 boxes, clause 5.7.**<br>• `L_p = 10 lg(10^(L_ps/10) − 10^(L_pb/10))`, the plain energy subtraction, band by band and position by position<br>• over 10 dB of margin nothing is corrected; under 6 dB the conditions are "not acceptable", which is a refusal, because the background it names includes wind noise<br>• where ISO 11820 corrects from a stepped table, this standard prints the formula | `noise_control.background_corrected_level_db(levels, background)` |
| `directivity_index_db` / `DIRECTIVITY_POSITIONS` / `DIRECTIVITY_INDEX_LIMIT_DB` / `DIRECTIVITY_CIRCLE_RADIUS_M` | `function` / `constant` | **Is this loudspeaker omnidirectional enough? ISO 11821 definition 3.10 and 5.2.2.**<br>• twelve positions evenly spaced on a horizontal circle of about 1,5 m radius<br>• `DI_i = L₃₆₀ − L₃₀,i`, the logarithmic mean less the position, so the index is positive where the position is quieter than the mean<br>• the source qualifies while no position falls more than 8 dB below the mean | `noise_control.directivity_index_db(levels_at_twelve)` |
| `microphone_distances_m` / `SCREEN_DISTANCE_FACTORS` / `MINIMUM_MICROPHONE_DISTANCE_M` / `MINIMUM_SCREEN_DIMENSION_M` | `function` / `constant` | **Where the microphones stand in front of a screen, ISO 11821 5.5.2.**<br>• a quarter, a half, once and twice the screen height, never closer than 1 m, so for a low screen the two nearest positions coincide<br>• NOTE 2 reads the spread: the smallest attenuation at the most remote position, the largest at the nearest<br>• a screen under 1,5 m in either dimension is outside the standard, and that is reported | `noise_control.microphone_distances_m(3.0)` |
| `impulse_mean_level_db` / `IMPULSE_REPEATS` / `IMPULSE_REPEAT_DEVIATION_DB` / `IMPULSE_INVALID_DEVIATION_DB` | `function` / `constant` | **A single-impulse source, ISO 11821 5.6.2.1.**<br>• at least three repeats with the S time weighting, and the **arithmetic** mean of them, which is what the clause asks for<br>• a spread past 3 dB asks for three more repeats, which is reported<br>• a spread past 5 dB makes the measurement invalid, which is refused | `noise_control.impulse_mean_level_db([88.1, 89.4, 87.9])` |
| `ISO11821_BAND_RANGE_HZ` / `OPERATOR_HEIGHT_M` / `OPERATOR_HEIGHT_TOLERANCE_M` / `OUTDOOR_RANGE_M` / `ENGINEERING_STANDARD_DEVIATION_DB` | `mapping` / `constant` | **The conditions ISO 11821 states as numbers.**<br>• 100 Hz to 5 kHz in one-third octaves, 125 Hz to 4 kHz in octaves<br>• a microphone stands at 1,55 m ± 0,075 m where no operator height is given, in the sphere of 0,3 m radius the cabin standard also prints<br>• outdoors the method reaches 25 m from the screen, and its standard deviation of reproducibility is 2 dB, which is engineering grade | `noise_control.ISO11821_BAND_RANGE_HZ[3]  # (100.0, 5000.0)` |
| `ScreenInSituWarning` | `warning class` | **The measurement is outside a condition ISO 11821 states.**<br>• a screen smaller than 1,5 m, a spread of repeats past 3 dB, a distance past the 25 m the outdoor method reaches | `warnings.catch_warnings()`<br>Emitted by `noise_control.screen_in_situ` |
| `valve_aerodynamic_noise` | `function` | **Control valve aerodynamic noise, the whole of IEC 60534-8-3 Clause 5.**<br>• `stream`: a `GasStream`, `valve`: a `ValveTrim`, `pipe`: a `DownstreamPipe`<br>• the three groups are the standard's own reading order: the operating point, the valve at that travel, and the pipe the noise comes out of | `res = noise_control.valve_aerodynamic_noise(stream, valve, pipe)`<br><br>• `AerodynamicValveNoise` |
| `AerodynamicValveNoise` | `dataclass` | **What Clause 5 says about one operating point.**<br>• `boundaries`, `pressure_ratio` x, `vena_contracta_pressure_pa` [Pa]; `regime` (1 to 5) is read-only, read from the ratio and the boundaries<br>• by name only: `specific_heat_ratio`, `pressure_recovery`, `efficiency_correction`, which hold the boundaries, `mach` and `acoustical_efficiency` to that regime<br>• `jet_diameter_m` [m], `mach`, `acoustical_efficiency`, `stream_power` / `sound_power` [W], `sound_power_level` [dB]<br>• `peak_frequency` [Hz], `outlet_mach`, `pipe_mach`, `velocity_correction` [dB], `internal_level` [dB]<br>• `frequencies` and the three band arrays, plus `external_level`, the A-weighted single number of Eq. (25) [dB(A)] at 1 m | `res.regime, res.external_level` |
| `GasStream` / `ValveTrim` / `DownstreamPipe` | `dataclass` | **The three groups of input IEC 60534-8-3 reads.**<br>• `GasStream`: `mass_flow` [kg/s], `inlet_pressure_pa` / `outlet_pressure_pa` [Pa], `inlet_density` [kg/m3], `inlet_temperature_k` [K], `specific_heat_ratio`, `molecular_mass` [kg/kmol]<br>• `ValveTrim`: `flow_coefficient` C, `style_modifier` F_d, `pressure_recovery` F_L or F_LP/F_p, `outlet_diameter_m` D [m], `efficiency_correction` A_eta and `strouhal_number` St_p from Table 4, `coefficient` 'Cv' (Default) or 'Kv'<br>• `DownstreamPipe`: `internal_diameter_m` D_i [m], `wall_thickness` t_S [m], `density` [kg/m3], and the printed defaults `speed_of_sound`, `air_sound_speed`, `atmospheric_pressure_pa`, `standard_pressure_pa` | `noise_control.ValveTrim(flow_coefficient=90.0, ...)` |
| `pressure_ratio_boundaries` / `RegimeBoundaries` | `function` / `dataclass` | **The four pressure ratios of Eqs. (3) to (7) that cut Clause 5.2 into five regimes.**<br>• `specific_heat_ratio`, `pressure_recovery`<br>• `vena_contracta` x_vcc, `critical` x_C, `break_point` x_B, `constant_efficiency` x_CE, `recovery` alpha | `noise_control.pressure_ratio_boundaries(1.22, 0.8)` |
| `flow_regime` | `function` | **Which of the five regimes a pressure ratio falls in (Clause 5.2).**<br>• `pressure_ratio` x, `boundaries`<br>• Each interval closed at the top; regime V starts strictly above x_CE, as the clause prints it and not as Table 3 does | `noise_control.flow_regime(0.52, bounds)  # 3` |
| `valve_style_modifier` | `function` | **F_d of Eqs. (8a) to (8c): the hydraulic diameter of one passage over the diameter of the equivalent single orifice.**<br>• `passage_area` A [m2], `wetted_perimeter` l_w [m], `passages` N_o | `noise_control.valve_style_modifier(0.00137, 0.181, 6)  # 0.30` |
| `jet_diameter_m` | `function` | **D_j of Eq. (9), the length scale the peak frequency is set by.**<br>• `flow_coefficient` C, `style_modifier` F_d, `pressure_recovery`<br>• `coefficient`: 'Cv' (Default) or 'Kv' | `noise_control.jet_diameter_m(90.0, 0.30, 0.805)  # m` |
| `internal_spectrum` | `function` | **Eq. (19): the internal level spread over the third-octave bands around the peak.**<br>• `internal_level` [dB], `peak_frequency` [Hz], `frequencies` [Hz]<br>• Falls as f^-2.5 above the peak and f^1.7 below it | `noise_control.internal_spectrum(155.3, 7778.0, bands)` |
| `pipe_transmission_loss` | `function` | **Eq. (20a): what the pipe wall keeps in, band by band (negative).**<br>• `frequencies` [Hz]<br>• `internal_diameter_m`, `wall_thickness`, `valve_outlet_diameter_m` [m]<br>• `downstream_density` [kg/m3], `downstream_sound_speed` [m/s], `pipe_density` [kg/m3]<br>• `pipe_sound_speed`, `air_sound_speed`, `atmospheric_pressure_pa`, `standard_pressure_pa` | `noise_control.pipe_transmission_loss(bands, internal_diameter_m=0.2, ...)` |
| `coincidence_frequencies` / `PipeFrequencies` | `function` / `dataclass` | **The ring and two coincidence frequencies of Eqs. (21) to (23) that shape the transmission loss.**<br>• `internal_diameter_m`, `wall_thickness`, `downstream_sound_speed`<br>• `ring` f_r, `internal_coincidence` f_o, `external_coincidence` f_g | `noise_control.coincidence_frequencies(0.2, 0.008, 408.0)` |
| `multistage_trim_conditions` / `MultistageConditions` | `function` / `dataclass` | **Clause 6.3: what a multistage trim hands Clause 5 in place of the valve inlet (Eqs. (27) to (29)).**<br>• `inlet_pressure_pa`, `outlet_pressure_pa` [Pa], `inlet_density` [kg/m3]<br>• `flow_coefficient` C of the valve, `last_stage_coefficient` C_n<br>• result: `flow_coefficient`, `stagnation_pressure_pa` p_n, `stagnation_density` rho_n, and `equation`: which of '28a', '28b', '28c' NOTE 3 selected | `noise_control.multistage_trim_conditions(inlet_pressure_pa=7e6, ...)` |
| `last_stage_flow_coefficient` / `LAST_STAGE_AREA_CONSTANTS` | `function` / `constant` | **Eq. (27): C_n = N_16 A_n, the flow coefficient of the last stage from its total flow area.**<br>• `total_area` A_n [m2]<br>• `coefficient`: 'Cv' (Default) or 'Kv', selecting N_16 from Table 1<br>6.3 asks for this only when the manufacturer states no C_n | `noise_control.last_stage_flow_coefficient(6.44e-3)` → `315` |
| `multiple_passage_jet_diameter` / `MAXIMUM_PASSAGE_ASPECT` | `function` / `constant` | **Eq. (26): the jet diameter of a single-stage, many-passage trim, where [0.9 - 0.06 l/d] replaces the pressure recovery factor.**<br>• `flow_coefficient`, `style_modifier`, `passage_length` l [m], `passage_diameter_m` d [m]<br>• `coefficient`: 'Cv' (Default) or 'Kv'<br>• l/d capped at **4** by NOTE 1, since the bracket would reach zero at 15 | `noise_control.multiple_passage_jet_diameter(90.0, 0.094, 0.02, 0.01)` |
| `stage_level_correction` | `function` | **Eq. (31): what the stages before the last one add back.**<br>• `last_stage_level` L_pi,n [dB], `stages` n (≥ 2), `inlet_pressure_pa` p_1, `stagnation_pressure_pa` p_n [Pa]<br>`L_pi = L_pi,n + 10 lg(p_1/p_n)/(n-1)^0.125`, so the stage count barely moves it | `noise_control.stage_level_correction(150.0, 3, 7e6, 2.1e6)` |
| `expander_noise` / `ExpanderNoise` | `function` / `dataclass` | **Clause 7: what the flow leaving the valve outlet makes (Eqs. (34) to (42)).**<br>• `frequencies` [Hz]<br>• `mass_flow`, `downstream_density`, `downstream_sound_speed`<br>• `internal_diameter_m` D_i, `throat_diameter_m` d_i (the smaller of valve outlet and expander inlet) [m]<br>• `velocity_correction` L_g [dB], `expander`<br>• result: `pipe_velocity` (capped at Mach 0.8), `inlet_velocity` (capped at c_2), `mach`, `stream_power`, `acoustical_efficiency`, `sound_power`, `peak_frequency`, `internal_level`, `band_internal_level` | `noise_control.expander_noise(bands, mass_flow=0.89, ...)` |
| `Expander` / `DEFAULT_EXPANDER` | `dataclass` / `constant` | **The transition piece downstream of the valve, limited by 7.1 to 30 degrees of total included angle.**<br>• `contraction` beta (Default: 0.93, the NOTE 1 figure for straight pattern globe valves; some rotary valves reach 0.7)<br>• `efficiency_correction` A_eta (Default: -3.0, Table 4's own *expander* row)<br>• `strouhal_number` St_p (Default: 0.2) | `noise_control.Expander(contraction=0.7)` |
| `combine_internal_levels` | `function` | **Eq. (43): two spectra at the same pipe wall, added in energy.**<br>• `*levels`: two or more band level arrays of one shape [dB]<br>The valve trim and the outlet flow are two sources inside one pipe, and only the sum crosses the wall | `noise_control.combine_internal_levels(trim, outlet)` |
| `ValveNoiseWarning` | `warning class` | **A valve read outside the conditions IEC 60534-8-3 prints for it.**<br>• emitted when the valve outlet passes the Mach 0.3 of NOTE 1 to Eq. (15) and no `expander` was given, so the second source is missing from the answer | `warnings.simplefilter('error', noise_control.ValveNoiseWarning)` |
| `EXPANDER_PIPE_MACH_LIMIT` / `GLOBE_CONTRACTION_COEFFICIENT` | `constant` | **0.8**, the Mach number Eq. (34) caps the downstream pipe velocity at, and **0.93**, the contraction coefficient NOTE 1 to Eq. (35) gives for straight pattern globe valves. | `noise_control.EXPANDER_PIPE_MACH_LIMIT` |
| `VALVE_ACOUSTIC_STYLES` | `constant` | **Table 4**: (A_eta, St_p) for the thirteen valve styles the table prints, from the globe parabolic plug to the expander. | `noise_control.VALVE_ACOUSTIC_STYLES['globe ported cage']` → `(-3.8, 0.2)` |
| `FLOW_COEFFICIENT_CONSTANTS` | `constant` | **Table 1**: N_14 for the two flow coefficients, `{'Cv': 4.6e-3, 'Kv': 4.9e-3}`. Both are rounded to two digits, so the same valve rated either way differs by 1 %. | `noise_control.FLOW_COEFFICIENT_CONSTANTS` |
| `AERODYNAMIC_A_WEIGHTING_DB` | `constant` | **Table 7**: the A weighting the standard prints for its own 33 bands, which Eq. (25) sums with. | `noise_control.AERODYNAMIC_A_WEIGHTING_DB[19]` → `0.0` |
| `MACH_LIMIT_STANDARD_TRIM` / `PIPE_WALL_MACH_LIMIT` | `constant` | **0.3** in both cases: the valve outlet Mach number above which Clause 5 gives way to Clause 7 (NOTE 1 to Eq. (15)), and the ceiling NOTE 2 puts on the pipe Mach number before Eq. (16). | `noise_control.MACH_LIMIT_STANDARD_TRIM` |
| `AIR_SOUND_SPEED_M_S` / `PIPE_SOUND_SPEED_M_S` | `constant` | **343 m/s** and **5000 m/s**, the values NOTES 3 and 4 print for the coincidence frequencies; the second is why Clause 1 restricts the method to steel pipe. | `noise_control.PIPE_SOUND_SPEED_M_S` |
| `STANDARD_ATMOSPHERE_PA` | `constant` | **101325 Pa**, the atmosphere Eqs. (20a) and (20c) are printed for. It is p_a and p_s both, which the standard keeps apart because a pipe can run at one and be rated at the other. | `noise_control.STANDARD_ATMOSPHERE_PA` |
| `STRUCTURAL_LOSS_REFERENCE_HZ` / `UNIVERSAL_GAS_CONSTANT` | `constant` | **1.0 Hz**, the f_s of Eq. (20c) that the equation never names again, and **8314 J/(kmol K)**, paired with a molecular mass in kg/kmol as Eqs. (10) and (14) are written for. | `noise_control.UNIVERSAL_GAS_CONSTANT` |
| `REGIME_SUBSONIC` / `REGIME_CHOKED` / `REGIME_SUPERSONIC` / `REGIME_SHOCK` / `REGIME_CONSTANT_EFFICIENCY` / `REGIME_COUNT` | `constant` | **1 to 5**, the five regimes of Clause 5.2 by the number it prints, and their count. | `res.regime == noise_control.REGIME_SHOCK` |
| `valve_hydrodynamic_noise` | `function` | **Control valve hydrodynamic noise, the whole of IEC 60534-8-4 Clauses 4 and 5.**<br>• `stream`: a `LiquidStream`, `valve`: a `LiquidTrim`, `pipe`: a `LiquidPipe`<br>• `strouhal_form`: 'annex' (Default) or 'clause', the two printings of Eq. (12)<br>• `frequency` (Default: the 50 Hz to 20 kHz thirds of 5.4.1) | `res = noise_control.valve_hydrodynamic_noise(stream, valve, pipe)`<br><br>• `HydrodynamicValveNoise` |
| `LiquidStream` / `LiquidTrim` / `LiquidPipe` | `dataclass` | **The three groups of input IEC 60534-8-4 reads.**<br>• `LiquidStream`: `mass_flow` [kg/s], `inlet_pressure_pa` / `outlet_pressure_pa` / `vapour_pressure_pa` [Pa], `density` [kg/m3], `speed_of_sound` [m/s]<br>• `LiquidTrim`: `flow_coefficient` C, `style_modifier` F_d, `pressure_recovery` F_L, `incipient_ratio` x_Fz, `power_ratio` r_W (Table 2), `valve_diameter_m` d and `seat_diameter_m` d_o [m], `coefficient` 'Cv' (Default) or 'Kv'<br>• `LiquidPipe`: `internal_diameter_m` D_i [m], `wall_thickness` t_p [m], `density` [kg/m3], and the printed defaults `speed_of_sound`, `air_density`, `air_sound_speed` | `noise_control.LiquidTrim(flow_coefficient=90.0, ...)` |
| `HydrodynamicValveNoise` | `dataclass` | **What IEC 60534-8-4 says about one operating point on a liquid line.**<br>• `pressure_ratio` x_F, `differential`, `inlet_pressure_pa`, `vapour_pressure_pa` and `cavitation_differential` [Pa], `incipient_ratio` / `corrected_ratio`<br>• `regime` ('turbulent' / 'cavitating', cavitating when Δp exceeds x_Fzp1 (p1 − pv), 5.1) is read-only, read from them; x_F and x_Fzp1 are held to Eqs. (1) and (3c), x_F stays below 1, and the cavitation fields are given exactly when it is cavitating<br>• `jet_diameter_m` [m], `velocity` U_vc [m/s], `stream_power` / `sound_power` [W], `turbulent_efficiency` / `cavitation_efficiency`<br>• `internal_level` [dB], `strouhal_number`, `turbulent_peak` / `cavitation_peak` [Hz]<br>• `pipe_ring_frequency` [Hz], `reference_transmission_loss`, `turbulent_transmission_loss`, `cavitation_transmission_loss`, `transmission_loss` [dB]<br>• `frequencies` and the three band arrays, plus `external_level` at 1 m, which the standard labels A-weighted although neither Eq. (18a) nor (18b) applies a weighting | `res.regime, res.external_level` |
| `differential_pressure_ratio` / `cavitation_differential` | `function` | **Eqs. (1) and (2): how far towards flashing the operating point is, and the differential the jet velocity is computed from.**<br>• keyword-only: `inlet_pressure_pa`, `outlet_pressure_pa`, `vapour_pressure_pa` [Pa]; the second also takes `pressure_recovery`<br>• x_F = (p1 - p2)/(p1 - p_v); Delta p_c is the lesser of p1 - p2 and F_L^2 (p1 - p_v) | `noise_control.differential_pressure_ratio(inlet_pressure_pa=1e6, outlet_pressure_pa=8e5, vapour_pressure_pa=2320.0)  # 0.2005` |
| `incipient_cavitation_ratio` / `multihole_incipient_cavitation_ratio` / `corrected_incipient_ratio` | `function` | **Eqs. (3a), (3b) and (3c): where cavitation becomes audible.**<br>• (3a): `flow_coefficient`, `style_modifier`, `pressure_recovery`, `coefficient` 'Cv' (Default) / 'Kv'<br>• (3b): `passages` N_o, `hole_diameter_m` d_H [m], `pressure_recovery`<br>• (3c) moves x_Fz from the 6e5 Pa the charts are drawn at to the working `inlet_pressure_pa`<br>4.2 asks for a value measured to IEC 60534-8-2; these are the estimates it offers instead | `noise_control.incipient_cavitation_ratio(90.0, 0.42, 0.92)  # 0.2543` |
| `vena_contracta_velocity` / `mechanical_stream_power` | `function` | **Eqs. (5) and (6): the jet velocity and the stream power it carries.**<br>• `differential` Delta p_c [Pa], `density` [kg/m3], `pressure_recovery`<br>• `mass_flow` [kg/s], `velocity` [m/s], `pressure_recovery` | `noise_control.vena_contracta_velocity(2e5, 997.0, 0.92)  # 21.77 m/s` |
| `turbulent_efficiency` / `cavitation_efficiency` | `function` | **Eqs. (8) and (9): the two acoustical efficiencies the sound power is a fraction of.**<br>• turbulent: `velocity`, `speed_of_sound`; 1e-4 at U_vc = c_L and linear below it<br>• cavitating (keyword-only): `turbulent`, `differential`, `choked_differential`, `pressure_ratio`, `corrected_ratio`<br>Exactly zero on the threshold, so the two regimes meet without a step | `noise_control.turbulent_efficiency(21.77, 1400.0)  # 1.555e-6` |
| `internal_sound_pressure_level` | `function` | **Eq. (10): the level inside, at the pipe wall.**<br>• keyword-only: `sound_power` W_a [W], `density` and `speed_of_sound` of the liquid, `internal_diameter_m` D_i [m]<br>The liquid's impedance is in the numerator, which is why a water line runs 150 dB inside | `noise_control.internal_sound_pressure_level(sound_power=0.00234, density=997.0, speed_of_sound=1400.0, internal_diameter_m=0.1071)` |
| `jet_strouhal_number` / `turbulent_peak_frequency` / `cavitation_peak_frequency` | `function` | **Eqs. (12), (11) and (13): where the noise sits in frequency.**<br>• `jet_strouhal_number` (keyword-only): `flow_coefficient`, `style_modifier`, `pressure_recovery`, `corrected_ratio`, `valve_diameter_m`, `seat_diameter_m`, `inlet_pressure_pa`, `vapour_pressure_pa`, `coefficient`, `form` 'annex' (Default) / 'clause'<br>• `turbulent_peak_frequency(strouhal_number, velocity, jet)`<br>• `cavitation_peak_frequency(turbulent_peak, pressure_ratio, corrected_ratio)`: six times the turbulent peak on the threshold, falling from there | `noise_control.cavitation_peak_frequency(654.35, 0.3508, 0.2386)` |
| `pipe_ring_frequency` / `reference_transmission_loss` / `transmission_loss_correction` | `function` | **Eqs. (14), (15), (16b) and (22b): the pipe wall.**<br>• `pipe_ring_frequency(internal_diameter_m, pipe_sound_speed=5000)`<br>• `reference_transmission_loss(internal_diameter_m, wall_thickness, pipe_density=…, air_density=…, …)`, negative by construction and therefore added downstream<br>• `transmission_loss_correction(frequency, ring)`: one expression for both printed equations, scalar or per band | `noise_control.reference_transmission_loss(0.1071, 0.0036, pipe_density=7800.0)  # -44.7 dB` |
| `cavitation_transmission_loss` | `function` | **Eq. (17): what cavitation does to the wall.**<br>• `turbulent_loss` [dB]; keyword-only `turbulent_peak`, `cavitation_peak` [Hz], `efficiency_ratio`<br>• `pressure_ratio` and `corrected_ratio` apply the NOTE's floor, which keeps the cavitating loss from falling below the turbulent one within 0.1 of the threshold | `noise_control.cavitation_transmission_loss(-71.84, turbulent_peak=654.35, cavitation_peak=1088.94, efficiency_ratio=0.377)` |
| `turbulent_distribution` / `cavitation_distribution` / `band_internal_levels` | `function` | **Eqs. (20a), (20b), (19a) and (19b): the internal level, band by band.**<br>• the two distributions take `frequency` and their own peak, and return a dB correction<br>• `band_internal_levels(frequency, internal_level, *, turbulent_peak, cavitation_peak=None, cavitation_fraction=0.0)` weights the two by their share of the sound power<br>Turbulent: 3 dB per octave up, 9 dB down. Cavitating: 4.5 dB both ways | `noise_control.band_internal_levels(bands, 156.5, turbulent_peak=654.4, cavitation_peak=1088.9, cavitation_fraction=0.377)` |
| `stage_conditions` / `StageConditions` / `combine_stage_levels` | `function` / `dataclass` / `function` | **Clause 6: Eqs. (23a) to (24b), (26) and (27) for a multistage trim.**<br>• `stage_conditions` (keyword-only): `inlet_pressure_pa`, `outlet_pressure_pa`, `vapour_pressure_pa`, `stage_coefficients` C_i, `flow_coefficient` C<br>• each stage takes a share of the differential in inverse proportion to its own C_i squared, the series law 1/C^2 = sum(1/C_i^2)<br>• `StageConditions`: `inlet_pressure_pa`, `outlet_pressure_pa`, `pressure_ratio`<br>• `combine_stage_levels(*levels)`: the energy sum of Eq. (27) | `noise_control.stage_conditions(inlet_pressure_pa=1e6, outlet_pressure_pa=4e5, vapour_pressure_pa=2320.0, stage_coefficients=[156.0]*3, flow_coefficient=90.0)` |
| `last_stage_differential` / `uniform_passage_style_modifier` / `last_stage_seat_diameter_mm` | `function` | **6.3.2: the fixed multistage device, where only the last stage is calculated.**<br>• `last_stage_differential` (keyword-only, Eq. (28)) caps the differential at the *cavitation threshold* of the last stage, not at F_L^2 as Eq. (2) does<br>• `uniform_passage_style_modifier(passages)` = 1/sqrt(N_o), Eq. (29)<br>• `last_stage_seat_diameter_mm(flow_coefficient, coefficient='Cv')`: the unnumbered 5.2 sqrt(N_34 C_n), which returns **millimetres** for a symbol Clause 3 declares in metres (see `docs/ERRATA.md`) | `noise_control.uniform_passage_style_modifier(16)  # 0.25` |
| `ACOUSTIC_POWER_RATIOS` / `CAPACITY_SCALE_CONSTANTS` | `constant` | **Table 2**: r_W for the twelve valves and fittings the table prints, a quarter for the globes and rotaries, a half for the butterflies, one for an expander. **Table 1**: N_34, `{'Cv': 1.17, 'Kv': 1.0}` | `noise_control.ACOUSTIC_POWER_RATIOS['globe parabolic plug']  # 0.25` |
| `STROUHAL_CONSTANTS` / `REFERENCE_INLET_PRESSURE_PA` / `CAVITATION_FLOOR_WIDTH` / `AIR_DENSITY_KG_M3` | `constant` | **The two printings of Eq. (12)**, `{'annex': 0.036, 'clause': 0.02}`; **6e5 Pa**, the inlet pressure x_Fz is drawn at; **0.1**, the width in x_F of the band the NOTE to Eq. (17) floors the efficiency ratio in; **1.293 kg/m3** for the air outside the pipe | `noise_control.STROUHAL_CONSTANTS['annex']` |
| `EnclosureResult` | `dataclass` | **Enclosure insertion-loss result.**<br>• `panel_transmission_loss`, `correction` C, `insertion_loss`, `room_constant`, `external_area`, `internal_area`<br>• `.plot()` | `res.insertion_loss` |
| `program_loudness` | `function` | **EBU R 128 measurement set of a programme (BS.1770-5 + Tech 3341/3342).**<br>• `x`: signal (1D mono or 2D [channels, samples], 1.0 = 0 dBFS)<br>• `fs` [Hz]<br>• `weights`: per-channel Gi (Default: Table 3 by channel count)<br>• `momentary_step` [s] (Default: 0.01), `short_term_step` [s] (Default: 0.1)<br>• `oversample`: true-peak factor (Default: None → reaches 192 kHz) | `res = broadcast.program_loudness(x, fs)`<br><br>• `ProgramLoudnessResult` |
| `integrated_loudness` | `function` | **Programme (integrated) loudness with the two-stage gate (BS.1770-5 Annex 1).**<br>• `x`, `fs` [Hz]<br>• `weights` (Default: Table 3 by channel count)<br>Absolute gate −70 LKFS, relative −10 LU | `integrated_loudness(x, fs)  # LUFS` |
| `loudness_range` | `function` | **Loudness range LRA (EBU Tech 3342).**<br>• `short_term_loudness`: S readings [LUFS] at ≥ 10 Hz<br>Cascaded gate (−70 LUFS abs, −20 LU rel), 10th-95th percentile spread | `loudness_range(res.short_term)  # LU` |
| `true_peak_level` | `function` | **True-peak level (BS.1770-5 Annex 2).**<br>• `x` (1.0 = 0 dBFS), `fs` [Hz]<br>• `oversample`: factor ≥ 1 (Default: None → smallest reaching 192 kHz, 4 at 48 kHz) | `true_peak_level(x, fs)  # dBTP`<br>Scalar for 1D, per-channel array for 2D |
| `k_weighting` | `function` | **Apply the two-stage K-weighting pre-filter (BS.1770-5 Annex 1).**<br>• `x`, `fs` [Hz]<br>Spherical-head shelf + RLB high-pass | `y = broadcast.k_weighting(x, fs)` |
| `k_weighting_coefficients` | `function` | **K-weighting biquads (Tables 1-2).**<br>• `fs` [Hz] (≥ 16 kHz)<br>Verbatim tables at 48 kHz; analog-prototype redesign elsewhere | `(b1, a1), (b2, a2) = broadcast.k_weighting_coefficients(fs)` |
| `k_weighting_response` | `function` | **K-weighting magnitude frequency response (BS.1770-5 Annex 1).**<br>• `fs` [Hz] (≥ 16 kHz, Default: 48000)<br>• `frequencies` [Hz] (Default: None → `n` log points 10 Hz→Nyquist), `n` (Default: 512)<br>Evaluates the Table 1-2 biquads with `freqz` | `k_weighting_response().plot()`<br><br>• `KWeightingResponse` |
| `channel_weight` | `function` | **Position-dependent channel weight Gi (BS.1770-5 Annex 3, Table 4).**<br>• `azimuth` [deg], `elevation` [deg] (Default: 0)<br>1.41 for mid-layer side positions, 1.0 elsewhere | `channel_weight(110, 0)  # 1.41` |
| `DEFAULT_CHANNEL_WEIGHTS` | `dict` | **Table 3 weights by channel count.**<br>1/2/5/6 channels; 5.1 order L, R, C, LFE, Ls, Rs with the LFE at 0.0 (excluded) | `DEFAULT_CHANNEL_WEIGHTS[6]` |
| `ProgramLoudnessResult` | `dataclass` | **EBU Mode measurement result.**<br>• `integrated` [LUFS], `loudness_range` [LU], `true_peak` [dBTP]<br>• `momentary` / `short_term` series with `momentary_time` / `short_term_time` [s]<br>• `max_momentary` / `max_short_term` [LUFS]<br>• `relative_threshold`, `lra_low` / `lra_high` [LUFS]<br>• `true_peak_per_channel` [dBTP], `channel_weights`, `fs`<br>• `.plot()`: M/S over time with I and LRA annotated<br>• `.report(path, *, tolerance='qc'/'live')`: R 128 fiche (±0.2 LU item i / ±1.0 LU item h) | `res.integrated, res.loudness_range` |
| `KWeightingResponse` | `dataclass` | **K-weighting magnitude frequency response (BS.1770-5 Annex 1).**<br>• `frequencies` [Hz], `magnitude_db` (combined) [dB]<br>• `shelf_db` (stage 1, +4 dB shelf), `highpass_db` (stage 2, RLB) [dB]<br>• `fs` [Hz]<br>• `.plot()`: magnitude vs frequency (log axis) with the two stages | `k_weighting_response().magnitude_db` |
| `quasi_peak_meter` | `function` | **ITU-R BS.468-4 clause 2 quasi-peak reading of a record, in dBqps.**<br>• `x`: 1-D record, or a `Signal`<br>• `fs` [Hz]<br>• `weighted`: run the clause 1 network first (Default: True; False is the clause 2.4 mode)<br>• `reference`: level reference in the record's own unit (Default: None → 0.775 V; required for a calibrated Signal, whose samples are pascals)<br>Reading = the maximum of the needle over the record, so the record must include the decay | `res = broadcast.quasi_peak_meter(x, fs)`<br><br>• `QuasiPeakResult` |
| `QuasiPeakResult` | `dataclass` | **Quasi-peak reading of one record (BS.468-4 clause 2).**<br>• `reading` (record's unit), `level_db`, `reference`<br>• `trace`: the needle, sample for sample with the record<br>• `fs` [Hz], `weighted`<br>• `.times` [s], `.level_unit`: `'dBqps'` only against the 0.775 V of clause 2.6<br>• `.plot()`: the trace with the reading marked<br>• no `.report()`: BS.468-4 prescribes no report format | `res.reading, res.level_unit` |
| `verify_quasi_peak_dynamics` | `function` | **Check the detector against the eleven acceptance windows of Tables 2 and 3.**<br>• `fs` [Hz] (Default: 48000)<br>• keyword-only: `ballistics`, the chain to check (Default: `BS468_BALLISTICS`)<br>Builds the clause 2.1 and 2.2 stimuli (5 kHz, integral periods, through the network) and reads each against the steady tone | `rep = broadcast.verify_quasi_peak_dynamics()`<br><br>• `QuasiPeakDynamicsResult` |
| `QuasiPeakDynamicsResult` | `dataclass` | **The eleven acceptance windows of clause 2, read on one chain.**<br>• `fs` [Hz], `passes`<br>• `worst_margin_db`: smallest of the eleven margins [dB]<br>• `worst_deviation_db`: largest departure from a printed reference [dB]<br>• `stimuli`: eleven read-only rows of `stimulus`, `table`, `reading_percent`, `lower_percent`, `reference_percent`, `upper_percent`, `deviation_db`, `margin_db`, each reading beside the window Table 2 or Table 3 prints<br>• no `.report()`: BS.468-4 prescribes no report format<br>• takes `fs`, `readings_percent` (the eleven readings, Table 2 then Table 3); `stimuli`, `passes`, `worst_margin_db`, `worst_deviation_db` are read-only, read from them | `rep.passes, rep.worst_margin_db` |
| `BS468_BALLISTICS` / `QuasiPeakBallistics` | `constant` / `dataclass` | **The three time constants of the quasi-peak chain, in seconds (a fit to the eleven reference readings, printed nowhere in BS.468-4).**<br>• `charge` 1.4096 ms, `discharge` 293.20 ms (the peak rectifier)<br>• `reading_device` 139.99 ms (clause 2.5's symmetric indicator)<br>The tables identify them only to within a factor of 1.88, 1.61 and 2.09 -- marginal ranges, not a box | `BS468_BALLISTICS.discharge` |
| `DBQPS_REFERENCE` | `float` | **The 0.775 V r.m.s. of clause 2.6**, the steady 1 kHz sine that reads 0 dBqps and fixes the scale of the whole instrument | `DBQPS_REFERENCE  # 0.775` |
| `sound_pressure_level` | `function` | **Underwater SPL (ISO 18405), dB re 1 µPa.**<br>• `pressure`: signal (1D) [Pa]<br>• `reference`: p₀ (Default: 1e-6) | `sound_pressure_level(p)` |
| `sound_exposure_level` | `function` | **Underwater SEL (ISO 18405/18406), dB re 1 µPa²·s.**<br>• `pressure` (1D) [Pa]<br>• `fs` [Hz]<br>• `reference`: E₀ (Default: 1e-12) | `sound_exposure_level(p, fs)` |
| `peak_sound_pressure_level` | `function` | **Zero-to-peak level (ISO 18406), dB re 1 µPa.**<br>• `pressure` (1D) [Pa]<br>• `reference` (Default: 1e-6) | `peak_sound_pressure_level(p)` |
| `UNDERWATER_REFERENCE_PRESSURE` / `UNDERWATER_REFERENCE_EXPOSURE` | `float` | **ISO 18405 reference quantities.**<br>Reference pressure p0 = 1 µPa [Pa] and reference exposure E0 = 1 µPa²·s [Pa²·s] | `UNDERWATER_REFERENCE_PRESSURE  # 1e-06` |
| `underwater_to_in_air_spl` / `in_air_to_underwater_spl` | `function` | **Re-reference a level between 1 µPa and 20 µPa (∓26.02 dB).**<br>• `level` [dB]<br>Reference change only, not an energy equivalence. | `underwater_to_in_air_spl(120.0)` |
| `radiated_noise_level` | `function` | **Ship radiated noise level (ISO 17208-1), dB re 1 µPa·m.**<br>• `rms_pressure_pa` [Pa]<br>• `distance` [m]<br>= 20·lg(p/p₀)+20·lg(r/r₀) | `radiated_noise_level(2e-6, 100.0)` |
| `hydrophone_depths` | `function` | **ISO 17208-1 hydrophone depths from depression angles_deg.**<br>• `cpa_distance` [m]<br>• `angles_deg` (Default: (15,30,45)) [deg]<br>= cpa·tan(angle_deg) | `hydrophone_depths(100.0)` |
| `source_level_uncertainty` | `function` | **Tabulated source-level uncertainty (ISO 17208-2).**<br>• `frequency` [Hz]<br>5 dB ≤100 Hz / 3 dB 125 Hz–16 kHz / 4 dB >16 kHz | `source_level_uncertainty(1000.0)  # 3.0` |
| `monopole_source_level` | `function` | **Equivalent monopole source level (ISO 17208-2).**<br>• `rnl`: RNL [dB re 1 µPa·m] (scalar/array)<br>• `frequency` [Hz]<br>• `draught` D [m]<br>• `speed_of_sound` (Default: 1500) [m/s]<br>Ls = LRN + ΔL, d_s = 0.7·D | `res = underwater.monopole_source_level(rnl, f, 6.0)`<br><br>• `ShipSourceLevelResult` |
| `ShipSourceLevelResult` | `dataclass` | **Ship source-level result.**<br>• `frequencies` [Hz]<br>• `radiated_noise_level` / `surface_correction` / `source_level` [dB]<br>• `source_depth` [m] / `speed_of_sound` [m/s]<br>• `.plot()`: RNL/Ls/ΔL vs frequency | `res.source_level, res.surface_correction` |
| `single_strike_sel` | `function` | **Single-strike SEL (ISO 18406), dB re 1 µPa²·s.**<br>• `pressure`: one strike (1D) [Pa]<br>• `fs` [Hz] | `single_strike_sel(p, fs)` |
| `cumulative_sel` | `function` | **Cumulative SEL over strikes (ISO 18406).**<br>• `single_sels`: per-strike SELs [dB]<br>= 10·lg(Σ 10^(SELₙ/10)) | `cumulative_sel([170, 176, 173])` |
| `cumulative_sel_identical` | `function` | **Cumulative SEL of N identical strikes.**<br>• `sel_ss` [dB]<br>• `n_strikes` N (≥ 1)<br>= sel_ss + 10·lg(N) | `cumulative_sel_identical(180.0, 50)` |
| `pile_strike_metrics` | `function` | **Per-strike pile-driving metrics (ISO 18406).**<br>• `pressure`: one strike (1D) [Pa]<br>• `fs` [Hz] | `res = underwater.pile_strike_metrics(p, fs)`<br><br>• `PileStrikeResult` |
| `sound_speed_profile` | `function` | **Sound-speed profile over a depth column.**<br>• `depths` (1D, increasing) [m]<br>• `temperatures_c` / `salinities`: array or scalar<br>• `model` / `latitude` | `sound_speed_profile(z, T, S)`<br><br>• `SoundSpeedProfile` |
| `SoundSpeedProfile` | `dataclass` | **Sound-speed profile.**<br>• `depth` [m] / `speed_of_sound` [m/s] / `gradient_per_s` [(m/s)/m]<br>• `model`<br>• `.plot()`: speed vs depth (depth down) | `prof.speed_of_sound, prof.gradient_per_s` |
| `spreading_loss` | `function` | **Geometrical spreading loss, dB.**<br>• `range_m` [m] (scalar/array)<br>• `law`: `"spherical"` / `"cylindrical"` / `"practical"`<br>• `transition_range` [m] (for `"practical"`) | `spreading_loss(1000.0)` |
| `seawater_absorption` | `function` | **Volume absorption α, dB/km.**<br>• `frequency_hz` [Hz] (scalar/array)<br>• `temperature_c` [°C] / `salinity` [ppt] / `depth` [m] / `ph`<br>• `model`: `"francois-garrison"` (default) / `"ainslie-mccolm"` / `"thorp"` | `seawater_absorption(10e3)` |
| `propagation_loss` | `function` | **Propagation loss PL = spreading + α·R, α in dB/km and R in km.**<br>• `range_m` [m] / `frequency_hz` [Hz]<br>• `law` / `temperature_c` / `salinity` / `depth` / `ph` / `model` / `transition_range` | `propagation_loss(r, 10e3)`<br><br>• `PropagationLossResult` |
| `PropagationLossResult` | `dataclass` | **Propagation-loss result.**<br>• `range_m` [m] / `pl` / `spreading` / `absorption` [dB]<br>• `frequency` [Hz] / `absorption_coefficient` [dB/km]<br>• `law` / `model`<br>• `.plot()`: PL vs range | `res.pl, res.absorption_coefficient` |
| `array_directivity_index` | `function` | **Directivity index of an unshaded line array (Ainslie 2010 Eqs. 6.49–6.57).**<br>• `array_length_m` L, `wavelength_m` λ<br>• `steer_angle_rad` ψ from broadside (Default: 0)<br>• DI = 10 log₁₀(4π/δΩ); also the **array gain** in isotropic noise, which is the case the sonar equation assumes<br>• 10 log₁₀(2L/λ) at broadside, 3 dB more at endfire, → 0 dB as L/λ → 0 | `underwater.array_directivity_index(50.0, 1.5)  # 18.3` |
| `detection_threshold` | `function` | **Detection threshold at 50 % detection probability (Ainslie 2010 Eq. 11.22).**<br>• `false_alarm_probability` p_fa, in (0, ½)<br>• DT = 10 log₁₀(log₂[1/(2 p_fa)]) − 0,8 dB, base two<br>• ±0,1 dB for p_fa < 10⁻² with one-dominant-plus-Rayleigh statistics; diverges at ½ | `underwater.detection_threshold(1e-4)  # 10.09` |
| `passive_sonar_equation` | `function` | **Passive sonar equation.**<br>• `source_level` / `propagation_loss` / `noise_level` [dB]<br>• `directivity_index` / `detection_threshold` (Default: 0)<br>SE = SL − PL − (NL − DI) − DT | `passive_sonar_equation(140, 80, 60)`<br><br>• `SonarEquationResult` |
| `active_sonar_equation` | `function` | **Active (monostatic) sonar equation.**<br>• `source_level` / `propagation_loss` / `target_strength` / `noise_level` [dB]<br>• `directivity_index` / `detection_threshold` / `reverberation_level`<br>noise-limited SE = SL − 2·PL + TS − (NL − DI) − DT; with `reverberation_level` → SE = SL − 2·PL + TS − RL − DT | `active_sonar_equation(220, 70, 15, 60)`<br><br>• `SonarEquationResult` |
| `SonarEquationResult` | `dataclass` | **Sonar-equation result.**<br>• `mode` / `signal_excess` / `snr` [dB] / `figure_of_merit` [dB]<br>• `propagation_loss` / `source_level` / `noise_level` / `directivity_index` / `detection_threshold` [dB]<br>• `target_strength` [dB or None] / `reverberation_limited`<br>• `.plot()`: signal excess vs PL | `res.signal_excess, res.figure_of_merit` |
| `critical_angle` | `function` | **Critical grazing angle φc = arccos(c1/c2), degrees.**<br>• `c1` / `c2` [m/s] (needs `c2 > c1`) | `critical_angle(1500, 1650)` |
| `reflection_coefficient` | `function` | **Complex seabed Rayleigh reflection coefficient.**<br>• `grazing_angle_deg` [°] (scalar/array)<br>• `rho1` / `c1` / `rho2` / `c2` | `reflection_coefficient(30, rho1=1000, c1=1500, rho2=1900, c2=1650)` |
| `bottom_reflection_loss` | `function` | **Seabed reflection loss BL = −20·lg\|R\|, dB.**<br>• `grazing_angle_deg` [°]<br>• `rho1` (Default: 1000) / `c1` (Default: 1500) / `rho2` / `c2` | `bottom_reflection_loss(phi, rho2=1900, c2=1650)`<br><br>• `BottomLossResult` |
| `BottomLossResult` | `dataclass` | **Seabed reflection result.**<br>• `grazing_angle_deg` [°] / `reflection_loss` [dB]<br>• `reflection_coefficient` [complex] / `critical_angle_deg` [° or None]<br>• `.plot()`: bottom loss vs grazing angle | `res.reflection_loss, res.critical_angle_deg` |
| `seabed_reflection` | `function` | **Plottable seabed reflection coefficient (Rayleigh).**<br>• `grazing_angle_deg` [°]<br>• `rho1` (Default: 1000) / `c1` (Default: 1500) / `rho2` / `c2` | `seabed_reflection(phi, rho2=1900, c2=1650)`<br><br>• `SeabedReflection` |
| `SeabedReflection` | `dataclass` | **Seabed reflection-coefficient result.**<br>• `grazing_angle_deg` [°] / `reflection_coefficient` [complex]<br>• `magnitude` \|R\| / `bottom_loss` [dB] / `critical_angle_deg` [° or None]<br>• `rho1` / `c1` / `rho2` / `c2`<br>• `.plot()`: \|R\| vs grazing angle | `res.magnitude, res.critical_angle_deg` |
| `wind_noise_spectrum` | `function` | **Wenz wind noise (rule of fives), dB re 1 µPa²/Hz.**<br>• `frequency_hz` [Hz] / `wind_speed_knots` [kn] | `wind_noise_spectrum(1000, 5)` |
| `thermal_noise_spectrum` | `function` | **Mellen thermal noise, dB re 1 µPa²/Hz.**<br>• `frequency_hz` [Hz]<br>• `temperature_c` (Default: 16.85) / `density` (Default: 1025) / `speed_of_sound` (Default: 1500) | `thermal_noise_spectrum(5e4)` |
| `ocean_ambient_noise` | `function` | **Composite ambient-noise spectrum (wind + thermal [+ shipping]).**<br>• `frequency_hz` [Hz] / `wind_speed_knots` [kn]<br>• `shipping` [dB or None] / `temperature_c` / `density` / `speed_of_sound` | `ocean_ambient_noise(f, wind_speed_knots=10)`<br><br>• `AmbientNoiseResult` |
| `AmbientNoiseResult` | `dataclass` | **Ambient-noise result.**<br>• `frequencies` [Hz] / `spectrum_level` [dB re 1 µPa²/Hz]<br>• `wind` / `thermal` / `shipping` [dB or None]<br>• `wind_speed_knots` [kn]<br>• `.plot()`: composite + components vs frequency | `res.spectrum_level` |
| `ship_source_spectrum` | `function` | **Predicted ship source-level spectrum.**<br>• `speed_knots` (Default: 12) / `length_m` (Default: 100)<br>• `vessel_class` (Default: `"containership"`) / `model`: `"jomopans-echo"` (default) / `"randi"` / `"wales-heitmeyer"`<br>• `frequency_hz` (Default: decidecade 10 Hz–31.5 kHz) | `ship_source_spectrum(18, 300, vessel_class="containership")`<br><br>• `ShipTrafficSpectrum` |
| `ShipTrafficSpectrum` | `dataclass` | **Ship source-spectrum result.**<br>• `frequencies` [Hz] / `source_psd` [dB re 1 µPa²/Hz at 1 m] / `band_level` [dB re 1 µPa m]<br>• `model` / `vessel_class` / `speed_knots` / `length_m`<br>• `.plot()`: source PSD vs frequency | `res.source_psd, res.band_level` |
| `VESSEL_CLASSES` | `tuple` | **The 13 JOMOPANS-ECHO vessel classes.** | `"bulker" in VESSEL_CLASSES` |
| `normal_modes` | `function` | **Normal-mode propagation loss (range-independent).**<br>• `frequency_hz` / `depths` [m] / `sound_speeds` [m/s]<br>• `source_depth` / `receiver_depth` [m] / `ranges_m` / `density` / `bottom`: `"pressure-release"`\|`"rigid"` / `n_depth_points` | `normal_modes(50, [0,200], [1500,1500], source_depth=50, receiver_depth=100)`<br><br>• `NormalModeResult` |
| `ray_trace` | `function` | **Ray tracing and travel times through a sound-speed profile (vectorised).**<br>• `depths` [m] / `sound_speeds` [m/s]<br>• `source_depth` [m] / `launch_angles_deg` / `max_range` [m] / `n_steps`<br>• `bathymetry`: a `(ranges_m, depths_m)` polyline pair, or `None` for a level bottom | `ray_trace(z, c, source_depth=1000, launch_angles_deg=[-10,0,10])`<br><br>• `RayTraceResult` |
| `eigenrays` | `function` | **Eigenrays connecting a traced fan's source to one receiver.**<br>• `trace`: a `RayTraceResult` / `receiver_range` [m] / `receiver_depth` [m]<br>• `bottom`: `"pressure-release"`\|`"rigid"`\|`FluidSeabed`<br>• `max_arrivals` (earliest kept) / `n_steps` | `eigenrays(fan, receiver_range=5e3, receiver_depth=60)`<br><br>• `EigenrayResult` |
| `gaussian_beams` | `function` | **Gaussian beam PL field: finite at caustics, graded into shadow zones.**<br>• `frequency_hz` / `depths` [m] / `sound_speeds` [m/s]<br>• `source_depth` [m] / `max_range` [m] / `range_step` [m] / `ranges_m` / `receiver_depths_m`<br>• `fan`: a `BeamFan` / `bottom`: `"pressure-release"`\|`"rigid"`\|`FluidSeabed`<br>• `absorption`: model name\|`VolumeAbsorption`\|`None` / `bathymetry`: `(ranges_m, depths_m)`\|`None` | `gaussian_beams(300, [0,1000], [1500,1500], source_depth=300)`<br><br>• `GaussianBeamResult` |
| `BeamFan` | `dataclass` | **The launch fan of `gaussian_beams`.**<br>• `max_angle_deg` (Default: 80) / `n_beams` (Default: overlap condition) / `beam_width` W₀ [m] (Default: per launch angle) | `BeamFan(max_angle_deg=45.0)` |
| `FluidSeabed` | `dataclass` | **A lossy fluid seabed, passed as the `bottom` of `eigenrays`/`gaussian_beams`.**<br>• `density` ρ₂ [kg/m³] / `speed_of_sound` c₂ [m/s] / `water_density` ρ₁ (Default: 1000) | `FluidSeabed(density=1800, speed_of_sound=1700)` |
| `VolumeAbsorption` | `dataclass` | **Seawater volume absorption: a model and its water.**<br>• `model`: `"francois-garrison"`\|`"ainslie-mccolm"`\|`"thorp"`<br>• `temperature_c` [°C] / `salinity` [ppt] / `ph` | `VolumeAbsorption("thorp")` |
| `parabolic_equation` | `function` | **Split-step Fourier parabolic-equation PL field.**<br>• `frequency_hz` / `depths` [m] / `sound_speeds` [m/s]<br>• `source_depth` [m] / `max_range` [m] / `range_step` [m] / `n_depth_points` | `parabolic_equation(50, [0,200], [1500,1500], source_depth=50)`<br><br>• `ParabolicEquationResult` |
| `NormalModeResult` | `dataclass` | **Normal-mode result.**<br>• `frequency` / `wavenumbers` [rad/m] / `mode_depths` [m] / `mode_functions`<br>• `ranges` [m] / `propagation_loss` [dB] / `receiver_depth` / `source_depth`<br>• `.plot()`: PL vs range | `res.wavenumbers, res.propagation_loss` |
| `RayTraceResult` | `dataclass` | **Ray-tracing result.**<br>• `launch_angles_deg` [°] `(n_rays,)`<br>• `ranges` [m] / `depths` [m] / `travel_times` [s] (all `(n_rays, n_steps)`)<br>• `source_depth` / `water_depth` [m]<br>• `.plot()`: ray paths | `res.ranges, res.depths, res.travel_times` |
| `EigenrayResult` | `dataclass` | **Eigenray arrival list, earliest first.**<br>• `launch_angles_deg` / `arrival_angles_deg` [°] / `travel_times` [s] / `amplitudes` (complex, re 1 m)<br>• `surface_reflections` / `bottom_reflections` / `caustic_crossings` (per arrival)<br>• `receiver_range` / `receiver_depth` / `source_depth` / `water_depth` [m]<br>• `.plot()`: per-path loss stems vs delay | `res.travel_times, res.amplitudes` |
| `GaussianBeamResult` | `dataclass` | **Gaussian beam result.**<br>• `frequency` / `ranges` [m] / `depths` [m]<br>• `propagation_loss` [dB] and `pressure` (both `(n_depths, n_ranges)`)<br>• `launch_angles_deg` [°] / `ray_ranges` / `ray_depths` [m] / `beam_widths` [m] / `wavefront_curvatures` [1/m] (all `(n_beams, n_steps)`)<br>• `initial_beam_widths` [m] `(n_beams,)` / `source_depth` / `water_depth` [m]<br>• `.plot()`: PL field | `res.propagation_loss, res.beam_widths` |
| `ParabolicEquationResult` | `dataclass` | **Parabolic-equation result.**<br>• `frequency` / `ranges` [m] / `depths` [m]<br>• `propagation_loss` [dB] `(n_depths, n_ranges)` / `source_depth`<br>• `.plot()`: PL field | `res.propagation_loss` |
| `PileStrikeResult` | `dataclass` | **Pile-strike result.**<br>• `single_strike_sel` [dB re 1 µPa²·s]<br>• `peak_spl` / `spl` [dB re 1 µPa]<br>• `pulse_duration` [s]<br>• `pressure` [Pa] / `fs` [Hz]<br>• `.plot()`: waveform + cumulative energy | `res.single_strike_sel, res.peak_spl` |
| `strike_sel_spectrum` | `function` | **Band-resolved single-strike SEL (ISO 18406).**<br>• `pressure`: one strike (1D) [Pa] / `fs` [Hz]<br>• `fraction`: 1 or 3 (Default: 3) / `limits` [Hz] (Default: (10, 20000))<br>Parseval band split of ∫p²dt | `strike_sel_spectrum(p, fs)`<br><br>• `StrikeSelSpectrum` |
| `StrikeSelSpectrum` | `dataclass` | **Band-resolved strike SEL.**<br>• `frequencies` [Hz] / `band_sel` [dB re 1 µPa²·s]<br>• `total_sel` / `broadband_sel` [dB] / `fraction` / `fs` [Hz]<br>• `.plot()`: band SEL vs frequency | `spec.frequencies, spec.band_sel` |
| `weston_propagation_loss` | `function` | **Weston shallow-water regimes: PL = −10·lg F (Ainslie §9.1.1.2).**<br>• `range_m` [m] / `frequency_hz` [Hz] / `water_depth` H [m]<br>• `seabed`: `"sand"` (default) / `"mud"` / `WestonSeabed`<br>• `speed_of_sound` (Default: 1500) / `source_depth` / `receiver_depth` [m]<br>• `critical_angle_deg` [°] / `reflection_loss_gradient_value_np_per_rad` [Np/rad] overrides | `weston_propagation_loss(r, 250, 50)`<br><br>• `WestonPropagationResult` |
| `WestonPropagationResult` | `dataclass` | **Weston regime result.**<br>• `range_m` [m] / `propagation_loss` [dB re 1 m²] / `propagation_factor` [m⁻²]; `regime` is read-only, read from `range_m` and `boundaries`, and `propagation_loss` is held to the law of the regime in force<br>• `spherical` / `cylindrical` / `mode_stripping` / `single_mode` / `multipath` [dB]<br>• `boundaries` / `frequency` / `water_depth` / `source_depth` / `receiver_depth` / `seabed`<br>• `.plot()`: composite loss + each regime law | `res.propagation_loss, res.regime` |
| `weston_regime_boundaries` | `function` | **Range boundaries of the four Weston regimes.**<br>• `frequency_hz` [Hz] / `water_depth` [m]<br>• `seabed` / `speed_of_sound` / `critical_angle_deg` / `reflection_loss_gradient_value_np_per_rad` | `weston_regime_boundaries(250, 50)`<br><br>• `WestonRegimeBoundaries` |
| `WestonRegimeBoundaries` | `dataclass` | **Weston regime boundaries.**<br>• `spherical_to_cylindrical` / `cylindrical_to_mode_stripping` / `mode_stripping_to_single_mode` [m]<br>• `critical_angle_deg` [rad] / `reflection_loss_gradient` [Np/rad] / `effective_depth` [m]<br>• `cutoff_frequency` [Hz] / `mode_count` | `b.cylindrical_to_mode_stripping` |
| `reflection_loss_gradient` | `function` | **Seabed reflection loss gradient η (Ainslie Eqs. 9.51/9.53), Np/rad.**<br>• `seabed`: `"sand"` (default) / `"mud"` / `WestonSeabed`<br>• `frequency_hz` [Hz] (refracting seabeds only) | `reflection_loss_gradient("sand")  # 0.278` |
| `critical_grazing_angle` | `function` | **ψc = arccos(c_w/c_sed), radians (0 when none exists).**<br>• `sound_speed_ratio` c_sed/c_w | `critical_grazing_angle(1.20)` |
| `effective_depth` | `function` | **Weston effective water depth He (Ainslie Eq. 9.55), m.**<br>• `water_depth` [m] / `frequency_hz` [Hz]<br>• `seabed` / `speed_of_sound` | `effective_depth(50, 250)` |
| `waveguide_cutoff_frequency` | `function` | **Shallow-water cut-off frequency fc (Ainslie Eq. 9.60), Hz.**<br>• `water_depth` [m]<br>• `seabed` / `speed_of_sound` | `waveguide_cutoff_frequency(50)` |
| `loss_parameter` | `function` | **Sediment loss parameter ε = β/(40·π·lg e) (Ainslie Eq. 9.23).**<br>• `attenuation_db_per_wavelength` β [dB/λ] | `loss_parameter(0.88)  # 0.0161` |
| `WestonSeabed` | `dataclass` | **Characteristic seabed (Ainslie Table 9.1).**<br>• `name` / `grain_size` Mz / `sound_speed_ratio` / `density_ratio`<br>• `attenuation_db_per_wavelength` [dB/λ] / `loss_parameter` ε / `sound_speed_gradient_per_s` c′ [s⁻¹] | `WESTON_SEABEDS["sand"].density_ratio` |
| `WESTON_SEABEDS` | `dict` | **Ainslie Table 9.1 seabeds: `"sand"` (Mz 1.5) and `"mud"` (Mz 8).** | `WESTON_SEABEDS["mud"]` |
| `WESTON_REGIMES` | `tuple` | **Regime labels in range order.**<br>`"spherical"`, `"cylindrical"`, `"mode-stripping"`, `"single-mode"` | `WESTON_REGIMES[2]` |
| `detection_range` | `function` | **Range where the closed-form PL equals the figure of merit, m.**<br>• `figure_of_merit` [dB] / `frequency_hz` [Hz]<br>• `law` / `transition_range` / `temperature_c` / `salinity` / `depth` / `ph` / `model`<br>• `max_range` (Default: 500000) [m] / `n_points` (Default: 400) | `detection_range(82.7, 50e3)`<br><br>• `DetectionRangeResult` |
| `DetectionRangeResult` | `dataclass` | **Detection-range result.**<br>• `detection_range` [m] / `figure_of_merit` [dB] / `frequency` [Hz]<br>• `range_m` [m] / `propagation_loss` [dB] / `absorption_coefficient` [dB/km]<br>• `law` / `model`<br>• `.plot()`: PL vs FOM with the crossing | `res.detection_range` |
| `detection_range_from_curve` | `function` | **Detection range read off any computed PL curve, m.**<br>• `figure_of_merit` [dB] / `range_m` [m] / `propagation_loss` [dB]<br>• `crossing`: `"first"` (default) / `"last"` | `detection_range_from_curve(60, nm.ranges, nm.propagation_loss)` |
| `auditory_weighting` | `function` | **Marine-mammal auditory weighting W(f), dB.**<br>• `frequency_hz` [Hz] / `group`: hearing-group code<br>• `guidance`: `"nmfs-2024"` (default) / `"nmfs-2018"` / `"southall-2019"` | `auditory_weighting(1000, "LF")`<br><br>• `AuditoryWeightingResult` |
| `AuditoryWeightingResult` | `dataclass` | **Auditory weighting result.**<br>• `frequencies` [Hz] / `weighting` W(f) [dB] / `exposure_function` E(f) [dB]<br>• `parameters` / `guidance` / `group` / `weighted_tts_onset` Tw = K + C [dB]<br>• `.plot()`: W(f) vs frequency | `res.weighting, res.weighted_tts_onset` |
| `weighting_parameters` | `function` | **Weighting/exposure parameters of one hearing group.**<br>• `group` / `guidance` | `weighting_parameters("OW", guidance="nmfs-2024")`<br><br>• `WeightingParameters` |
| `WeightingParameters` | `dataclass` | **Weighting-function parameters.**<br>• `group` / `guidance` / `description`<br>• `a` / `b` / `f1_khz` / `f2_khz` / `c_db` / `c_db_as_printed` / `k_db` [dB]<br>• `in_air` / `hearing_range_hz` | `p.a, p.f1_khz, p.c_db` |
| `hearing_groups` | `function` | **Hearing-group codes of a guidance version.**<br>• `guidance` (Default: `"nmfs-2024"`)<br>Codes are not portable between versions | `hearing_groups("southall-2019")` |
| `WEIGHTING_GUIDANCE` | `tuple` | **Selectable guidance versions.**<br>`"nmfs-2024"`, `"nmfs-2018"`, `"southall-2019"` | `WEIGHTING_GUIDANCE[0]` |
| `exposure_criteria` | `function` | **Published TTS and injury onset criteria.**<br>• `group` / `guidance`<br>• `impulsive` (Default: False) | `exposure_criteria("VHF", impulsive=True)`<br><br>• `ExposureCriteria` |
| `ExposureCriteria` | `dataclass` | **TTS / injury onset criteria.**<br>• `group` / `guidance` / `impulsive`<br>• `tts_sel` / `injury_sel` / `tts_peak_spl` / `injury_peak_spl` [dB or None]<br>• `injury_label` (`"PTS"` / `"AUD INJ"`) / `sel_reference` / `peak_reference` / `source` | `crit.injury_sel, crit.injury_peak_spl` |
| `weighted_exposure` | `function` | **Weight a band spectrum, accumulate it and compare with the criteria.**<br>• `frequency_hz` [Hz] / `band_sel` [dB] / `group`<br>• `guidance` / `impulsive` (Default: True) / `n_events` (Default: 1) / `peak_spl` [dB] | `weighted_exposure(f, sel, "LF", n_events=3000)`<br><br>• `WeightedExposureResult` |
| `WeightedExposureResult` | `dataclass` | **Weighted-exposure assessment.**<br>• `frequencies` [Hz] / `band_sel` / `weighting` / `weighted_band_sel` [dB]<br>• `unweighted_sel` / `weighted_sel` / `cumulative_sel` [dB] / `peak_spl` [dB or None] / `n_events`<br>• `sel_margin` / `tts_margin` / `peak_margin` / `tts_peak_margin` [dB or None]<br>• `exceeds_injury` / `exceeds_tts` / `guidance` / `group`<br>• keyword-only `impulsive`, which selects the criteria; read-only `criteria`<br>• `.plot()`: weighted spectrum vs criteria<br>• takes `frequencies`, `band_sel`, `weighting`, `weighted_band_sel`, `unweighted_sel`, `weighted_sel`, `cumulative_sel`, `peak_spl`, `n_events`, `sel_margin`, `tts_margin`, `peak_margin`, `tts_peak_margin`, `guidance`, `group`, `impulsive`; `exceeds_injury`, `exceeds_tts` are read-only, read from them | `res.cumulative_sel, res.exceeds_injury` |
| `group_audiogram` | `function` | **Marine-mammal group audiogram (Southall et al. 2019 Eq. 1), dB.**<br>• `frequency_hz` [Hz] / `group`<br>• `normalized` (Default: False → Table 2; True → Table 3) | `group_audiogram(f, "VHF")`<br><br>• `AudiogramResult` |
| `orca_audiogram` | `function` | **Killer-whale audiogram (Ainslie Eq. 11.159), dB re 1 µPa.**<br>• `frequency_hz` [Hz], 500 Hz to 80 kHz<br>Three-branch fit; 39.0 dB at 22.6 kHz, 51.2 dB at 50 kHz | `orca_audiogram(50e3)`<br><br>• `AudiogramResult` |
| `AudiogramResult` | `dataclass` | **Hearing-threshold result.**<br>• `frequencies` [Hz] / `threshold` [dB]<br>• `group` / `source` / `in_air`<br>• `best_frequency` [Hz] / `best_threshold` [dB]<br>• `.plot()`: threshold vs frequency | `res.threshold, res.best_threshold` |
| `audiogram_parameters` | `function` | **Fit parameters of a published group audiogram.**<br>• `group` / `normalized` | `audiogram_parameters("HF")`<br><br>• `AudiogramParameters` |
| `AudiogramParameters` | `dataclass` | **Group-audiogram fit parameters.**<br>• `group` / `t0` [dB] / `f1_khz` / `f2_khz` [kHz] / `a` [dB/decade] / `b`<br>• `r_squared` / `in_air` | `p.t0, p.f1_khz` |
| `AUDIOGRAM_GROUPS` | `tuple` | **Groups with a published audiogram (no LF: F1 is never printed).**<br>HF, VHF, SI, PCW, OCW, PCA, OCA | `"VHF" in AUDIOGRAM_GROUPS` |
| `BEST_HEARING_FREQUENCY_KHZ` | `dict` | **Southall Table 4 f0 per group (original, normalized) [kHz].** | `BEST_HEARING_FREQUENCY_KHZ["HF"]` |
| `ORCA_AUDIOGRAM_RANGE_KHZ` | `tuple` | **Validity range of Ainslie Eq. (11.159): (0.5, 80) kHz.** | `ORCA_AUDIOGRAM_RANGE_KHZ[1]  # 80.0` |
| `perceived_noisiness` | `function` | **Per-band perceived noisiness (ICAO Annex 16 App. 2), noys.**<br>• `spl`: 24 one-third-octave band levels 50 Hz–10 kHz [dB] | `perceived_noisiness(spl)` |
| `NOY_BANDS` | `array` | **The 24 noy one-third-octave bands [Hz] (ICAO Annex 16 App. 2).**<br>50 Hz to 10 kHz | `NOY_BANDS[0]  # 50.0` |
| `perceived_noise_level` | `function` | **Perceived noise level PNL (ICAO Annex 16), PNdB.**<br>• `spl`: 24 band levels [dB]<br>= 40 + (10/lg2)·lg N | `perceived_noise_level(spl)` |
| `tone_correction` | `function` | **Tone correction C (ICAO Annex 16, slope method), dB.**<br>• `spl`: 24 band levels [dB]<br>1.5 dB threshold, cap 6⅔ dB | `tone_correction(spl)` |
| `effective_perceived_noise_level` | `function` | **EPNL from a spectral time history (ICAO Annex 16), EPNdB.**<br>• `spectra`: (K, 24) band levels [dB]<br>• `dt` (Default: 0.5) [s]<br>• `reference_time` (Default: 10) [s]<br>• `procedure`: 'aeroplane' (tone correction from 80 Hz, Default) / 'helicopter' (from 50 Hz, App. 2 4.3.1)<br>EPNL = PNLTM + D | `res = aircraft.effective_perceived_noise_level(spectra)`<br><br>• `EPNLResult` |
| `epnl_from_pnlt` | `function` | **EPNL + 10 dB-down limits from a PNLT series (ICAO Annex 16).**<br>• `pnlt`: PNLT(k) [PNdB]<br>• `dt` (Default: 0.5) [s]<br>• `reference_time` (Default: 10) [s] | `epnl, pnltm, kf, kl = aircraft.epnl_from_pnlt(pnlt)` |
| `EPNLResult` | `dataclass` | **EPNL result.**<br>• `frequencies` [Hz] / `times` [s]<br>• `pnl` / `tone_correction` / `pnlt` [PNdB, dB]<br>• `pnltm` / `duration_correction` / `epnl`<br>• `band_limits` (kF, kL)<br>• `.plot()`: PNL/PNLT time history | `res.epnl, res.pnltm, res.band_limits` |
| `verify_aircraft_noise_system` | `function` | **IEC 61265 measurement-system verification.**<br>• `directional`: {f: {angle: \|Δsens\| dB}} (Table 1)<br>• `frequency_response` / `linearity` / `resolution`<br>filters via `verify_filter_class` | `res = verify_aircraft_noise_system(directional=meas)`<br><br>• `AircraftSystemComplianceResult` |
| `AircraftSystemComplianceResult` | `dataclass` | **IEC 61265 verdict on a measurement chain.**<br>• `passes`: conjunction of the checks, `False` over no measurement<br>• `checks`: one read-only row per checked quantity, with `quantity`, the printed `limit`, the measured `value` and `ok`<br>• takes `directional`, `frequency_response`, `linearity`, `resolution` (the measurements, held as read-only copies); `checks`, `passes` are read-only, read from them and the tables of the standard | `res.passes, res.checks` |
| `sae_band_attenuation` | `function` | **One-third-octave-band atmospheric absorption (SAE ARP 5534).**<br>• `frequencies` [Hz] / `path_length` [m]<br>• `temperature_c` (Default: 25) / `relative_humidity_percent` (Default: 70) / `atmospheric_pressure_kpa` (Default: 101.325)<br>δ_B from pure-tone δ_t=α·s (α: ISO 9613-1 terms, ARP 5534 Eq. 6 saturation pressure) | `sae_band_attenuation(freqs, 7620.0)`<br><br>• `AircraftBandAttenuation` |
| `AircraftBandAttenuation` | `dataclass` | **Aircraft band-absorption result.**<br>• `frequencies` [Hz] / `band_attenuation` [dB] / `midband_attenuation` [dB] / `coefficient` [dB/m]<br>• `path_length` / `temperature_c` / `relative_humidity_percent` / `atmospheric_pressure_kpa`<br>• `.plot()`: band vs pure-tone mid-band | `res.band_attenuation` |
| `arp866a_attenuation` | `function` | **One-third-octave-band absorption by SAE ARP 866A (ISO 3891:1978 Annex A.2).**<br>• `frequencies_hz`: bands 50 Hz to 10 kHz<br>• `temperature_c` / `relative_humidity_percent` (keyword-only, no default)<br>• `eta_interpolation`: 'quadratic' (Default, reproduces ISO 3891 Table 10) or 'linear' (ECAC Doc 29 Table D-3b)<br>f0 of Table 2 (lower band edge above 4 kHz); rate independent of pressure and path | `arp866a_attenuation(NOY_BANDS, temperature_c=10, relative_humidity_percent=80)`<br><br>• `Arp866aAttenuation` |
| `Arp866aAttenuation` | `dataclass` | **SAE ARP 866A coefficient result.**<br>• `frequencies_hz` / `evaluation_frequencies_hz` f0 [Hz] / `delta` δ / `eta` η(δ)<br>• `coefficient_db_per_100m` [dB/100 m] / `temperature_c` / `relative_humidity_percent` / `eta_interpolation`<br>• `.path_attenuation_db(path_length_m)` [dB] / `.plot()`: α vs frequency | `res.path_attenuation_db(304.8)` |
| `npd_level` | `function` | **NPD event-level interpolation (ECAC Doc 29 §4.2).**<br>• `powers` / `distances` [m] / `levels` [dB] (shape P×D)<br>• `power` / `distance` [m]<br>linear in power (Eq. 4-3), log-linear in distance (Eq. 4-4) | `npd_level(P, D, L, 16000, 1500)` |
| `npd_curve` | `function` | **NPD level over a distance sweep at one power.**<br>• `powers` / `distances` / `levels`<br>• `power` / `query_distances` (Default: log sweep) | `npd_curve(P, D, L, 20000)`<br><br>• `NpdLevelResult` |
| `NpdLevelResult` | `dataclass` | **NPD distance-sweep result.**<br>• `distances` [m] / `levels` [dB] / `power`<br>• `table_distances` / `table_levels`<br>• `.plot()`: level vs slant distance | `res.distances, res.levels` |
| `lateral_attenuation` | `function` | **Excess lateral attenuation Λ(β,ℓ) (ECAC Doc 29 Eq. 4-18/4-19).**<br>• `elevation_deg` β / `lateral_m` ℓ | `lateral_attenuation(10, 500)` |
| `engine_installation_correction` | `function` | **Engine-install lateral directivity ΔI(φ) (Eq. 4-15/4-16).**<br>• `depression_deg` φ / `mounting`: `"wing"`\|`"fuselage"`\|`"propeller"` | `engine_installation_correction(20, "wing")` |
| `duration_correction` | `function` | **Duration correction ΔV = 10·lg(Vref/Vseg) (Eq. 4-14).**<br>• `reference_speed` / `segment_speed` | `duration_correction(82.3, 90)` |
| `noise_fraction` | `function` | **Finite-segment noise fraction ΔF (Eq. 4-20).**<br>• `q` [m] / `segment_length` λ [m] / `scaled_distance` dλ [m] | `noise_fraction(0, 5000, 100)` |
| `impedance_adjustment` | `function` | **Acoustic-impedance adjustment of NPD data (Eq. 4-6/4-7).**<br>• `temperature_c` [°C] / `atmospheric_pressure_kpa` [kPa]<br>= 10·lg(ρc/409.81); +0.074 dB at ISA | `impedance_adjustment(15, 101.325)` |
| `start_of_roll_directivity` | `function` | **Start-of-roll rearward directivity ΔSOR (Eq. 4-22/4-24/4-25).**<br>• `azimuth_deg` ψ (arccos q/dSOR) / `distance_m` dSOR<br>• `engine`: `"jet"`\|`"turboprop"`; 0 ahead (ψ<90°) | `start_of_roll_directivity(120, 300, "jet")` |
| `AerodromeAtmosphere` | `dataclass` | **Aerodrome air of the Doc 29 impedance adjustment (Eq. 4-6/4-7).**<br>• `temperature_c` [°C] (15) / `atmospheric_pressure_kpa` [kPa] (101.325) | `AerodromeAtmosphere(25.0, 100.0)` |
| `FlightSegmentState` | `dataclass` | **What each flight-path segment is doing (one entry per segment).**<br>• `ground_roll` / `landing_roll` masks / `bank` ε [°] (§4.5.2) | `FlightSegmentState(ground_roll=gr)` |
| `event_level` | `function` | **Single-event SEL/LAmax of a flight path at a receiver (Eq. 4-8/4-10/4-11).**<br>• `path` (N,5): x,y,z,power,speed / `observer` (x,y,z)<br>• NPD `powers` / `distances` / `exposure_levels` / `maximum_levels`<br>• `reference_speed` / `mounting` / `metric`: `"exposure"`\|`"maximum"`<br>• `atmosphere`: `AerodromeAtmosphere` / `segments`: `FlightSegmentState` | `event_level(path, obs, P, D, SEL, LMAX)`<br><br>• `FlyoverResult` |
| `noise_contour` | `function` | **Single-event noise level over a ground grid → contour.**<br>• `path` / NPD tables / `x` / `y` grids [m]<br>• `reference_speed` / `mounting` / `metric`<br>• `atmosphere`: `AerodromeAtmosphere` / `segments`: `FlightSegmentState` | `noise_contour(path, P, D, SEL, LMAX, x=gx, y=gy)`<br><br>• `NoiseContourResult` |
| `FlyoverResult` | `dataclass` | **Single-event result.**<br>• `level` [dB] / `metric` / `segment_levels` [dB] / `observer`<br>• `.plot()`: per-segment contributions | `res.level` |
| `NoiseContourResult` | `dataclass` | **Ground-grid contour result.**<br>• `x` / `y` [m] / `levels` [dB] (Ny×Nx) / `metric`<br>• `.plot()`: filled contours | `res.levels` |
| `load_anp_database` | `function` | **Load an EASA ANP fleet database (NPD curves + default profiles).**<br>• `path`: CSV export directory, or `None` for the bundled curated subset | `db = aircraft.load_anp_database()`<br><br>• `AnpDatabase` |
| `AnpDatabase` | `class` | **Parsed ANP database wiring real aircraft into the Doc 29 chain.**<br>• `.aircraft(id)` / `.aircraft_ids` / `.npd_curves(id, op, metric)` / `.profile(id, op, profile_id=)`<br>• `.spectral_class(id)` / `.spectral_class_ids` / `.revised_npd_curves(id, op, metric, temperature_c=, relative_humidity_percent=)` (Appendix D)<br>• `.event_level(id, obs, op)` / `.noise_contour(id, op, x=, y=)`; `relative_humidity_percent=` / `absorption=` recalculate the NPD tables for the field's air | `db.noise_contour("747100", "departure", x=gx, y=gy)`<br><br>• `AnpAircraft` |
| `AnpAircraft` | `dataclass` | **One ANP aircraft type: metadata + NPD/profile access + Doc 29 wiring.**<br>• `aircraft_id` / `description` / `engine_type` / `num_engines` / `weight_class` / `mounting` / `npd_id`<br>• `approach_spectral_class_id` / `departure_spectral_class_id`<br>• `.npd_curves(op, metric)` / `.spectral_class(op)` / `.revised_npd_curves(op, metric, ...)` / `.profile(op)` / `.event_level(obs, op)` / `.noise_contour(op, x=, y=)` | `db.aircraft("747100").mounting` |
| `AnpNpdCurves` | `dataclass` | **ANP NPD curves for one aircraft, metric and operation.**<br>• `powers` / `distances` [m] / `levels` [dB] (P×D) / `metric` / `operation`<br>• `.level(power, distance)` / `.plot()`: level vs slant distance | `db.npd_curves("747100", "departure", "SEL")` |
| `AnpProfile` | `dataclass` | **ANP default fixed-point trajectory as a Doc 29 flight path.**<br>• `path` (N,5): x,y,z,power,speed [SI] / `ground_roll` / `landing_roll` masks<br>• `.plot()`: altitude vs along-track distance | `db.profile("747100", "departure").path` |
| `SpectralClass` | `dataclass` | **One ANP spectral class (ECAC Doc 29 Vol. 2 G4.3).**<br>• `class_id` / `operation` A\|D / `description`<br>• `frequencies_hz` [Hz] / `levels_db` [dB] at 1000 ft, 70 dB at 1 kHz<br>• `.plot()`: band level vs frequency | `db.spectral_class(103).levels_db` |
| `SAE_AIR1845_ATTENUATION_DB_PER_100M` | `constant` | **ECAC Doc 29 Table D-1: SAE AIR-1845 average attenuation rates [dB/100 m] that normalise the ANP NPD data.**<br>Keyed by nominal band [Hz], 50 Hz to 10 kHz | `SAE_AIR1845_ATTENUATION_DB_PER_100M[1000.0]  # 0.59` |
| `npd_atmosphere_increment` | `function` | **NPD increment ΔL for a non-reference atmosphere (ECAC Doc 29 Vol. 2 Appendix D, Eqs. D-1 to D-4).**<br>• `spectrum`: `SpectralClass` or 24 levels at 1000 ft [dB]<br>• `temperature_c` / `relative_humidity_percent` (keyword-only) / `atmospheric_pressure_kpa` (Default: 101.325)<br>• `absorption`: 'arp5534' (Default) or 'arp866a' / `distances_m` (Default: the ten NPD distances) | `npd_atmosphere_increment(sc, temperature_c=10, relative_humidity_percent=80)`<br><br>• `NpdAtmosphereIncrement` |
| `NpdAtmosphereIncrement` | `dataclass` | **Appendix D increment and its tables.**<br>• `frequencies_hz` / `distances_m` / `spectrum_db` / `source_spectrum_db` (Eq. D-1)<br>• `reference_attenuation_db` / `specified_attenuation_db` (bands × distances)<br>• `reference_levels_dba` / `specified_levels_dba` / `increment_db` ΔL [dB]<br>• `.plot()`: ΔL vs distance / `.plot_attenuation(distance_m=)`: both atmospheres vs frequency | `inc.increment_db` |
| `revise_npd_curves` | `function` | **NPD curves recalculated for a specified atmosphere (Appendix D).**<br>• `curves`: `AnpNpdCurves` / `spectrum`: its spectral class<br>• `temperature_c` / `relative_humidity_percent` / `atmospheric_pressure_kpa` / `absorption` | `revise_npd_curves(curves, sc, temperature_c=10, relative_humidity_percent=80)`<br><br>• `RevisedNpdCurves` |
| `RevisedNpdCurves` | `dataclass` | **Original and revised NPD curves.**<br>• `original` / `revised` (`AnpNpdCurves`, feeds `event_level`) / `increment`<br>• `.plot()`: revised over original vs slant distance | `rev.revised.level(P, d)` |
| `Aerodrome` | `dataclass` | **Aerodrome, weather and runway of a Doc 29 Appendix B profile.**<br>• `elevation_ft` / `temperature_c` / `sea_level_pressure_inhg` / `headwind_kt` (8) / `runway_gradient_ratio`<br>• `.temperature_ratio()` θ / `.pressure_ratio()` δ / `.density_ratio()` σ / `.pressure_altitude_ft()` h (Eq. B-1..B-8) | `Aerodrome(elevation_ft=1000.0, temperature_c=25.0)` |
| `PerformanceAircraft` | `dataclass` | **One aeroplane's Appendix B coefficient set.**<br>• `engines` N / `max_static_thrust_lb` / `max_landing_weight_lb` / `.approach_weight_lb` (0.9·MLW)<br>• `jet_coefficients` / `propeller_coefficients` / `aerodynamic_coefficients` / `.flap(op, id)` | `db.performance_aircraft("A320-211")` |
| `JetEngineCoefficients` | `dataclass` | **Corrected net thrust polynomial E+F·Vc+Ga·h+Gb·h²+H·T (Eq. B-9).**<br>• `e` [lb] / `f` [lb/kt] / `ga` [lb/ft] / `gb` [lb/ft²] / `h` [lb/°C] | `JetEngineCoefficients(25000, -25, 0.3, 1e-5, 0)` |
| `PropellerEngineCoefficients` | `dataclass` | **Propeller thrust (326·η·Pp/Vt)/δ (Eq. B-12).**<br>• `efficiency` η / `power_hp` Pp per engine | `PropellerEngineCoefficients(0.85, 9500)` |
| `AerodynamicCoefficients` | `dataclass` | **One flap configuration (ANP aerodynamic table).**<br>• `drag_ratio` R / `ground_roll_coefficient` B [ft/lb] / `speed_coefficient` C or D [kt/√lb]<br>• a missing coefficient is `None`, not zero | `AerodynamicCoefficients(drag_ratio=0.07)` |
| `DepartureStep` | `dataclass` | **One ANP departure procedural step (Doc 29 B6.1).**<br>• `step_type`: Takeoff\|Climb\|Accelerate\|Level\|Level-Accelerate / `thrust_rating` / `flap_id`<br>• `end_altitude_ft` / `rate_of_climb_ft_per_min` / `end_calibrated_airspeed_kt` / `energy_share_percent` / `distance_ft` / `bank_angle_deg` | `DepartureStep("Climb", "MaxTakeoff", "5", 1500.0)` |
| `ApproachStep` | `dataclass` | **One ANP approach procedural step (Doc 29 B7.1).**<br>• `step_type`: Descend\|Descend-Decel\|Descend-Idle\|Level\|Level-Decel\|Level-Idle\|Land\|Decelerate / `flap_id`<br>• `start_altitude_ft` / `start_calibrated_airspeed_kt` / `descent_angle_deg` / `touchdown_roll_ft` / `distance_ft` / `start_thrust_percent` | `ApproachStep("Descend", "30", 1000.0, 135.0, 3.0)` |
| `departure_profile` | `function` | **Fly a departure procedure into a flight profile (Doc 29 B6).**<br>• `aircraft` / `steps` (first must be a Take-off) / `weight_lb` / `aerodrome` | `departure_profile(acft, steps, weight_lb=W, aerodrome=apt)`<br><br>• `FlightProfile` |
| `approach_profile` | `function` | **Fly an approach procedure into a flight profile (Doc 29 B7).**<br>• `aircraft` / `steps` (one Land step anchors distance 0) / `aerodrome` / `weight_lb` (0.9·MLW)<br>• solved backwards from touchdown: distances are negative until the runway | `approach_profile(acft, steps, aerodrome=apt)`<br><br>• `FlightProfile` |
| `FlightProfile` | `dataclass` | **A flown procedure as an ordered Doc 29 flight profile.**<br>• `points` / `.distance_ft` / `.altitude_ft` / `.true_airspeed_kt` / `.corrected_net_thrust_lb`<br>• `.plot()`: height and thrust vs distance | `db.flight_profile("A320-211", "D", aerodrome=apt)` |
| `ProfilePoint` | `dataclass` | **One profile point in the standard's units.**<br>• `distance_ft` (signed) / `altitude_ft` AFE / `true_airspeed_kt` / `corrected_net_thrust_lb` per engine<br>• thrust may be negative: an idle descent is drag | `profile.points[0].corrected_net_thrust_lb` |
| `RotorcraftHemisphere` | `dataclass` | **Rotorcraft noise hemisphere source (ECAC Doc 32).**<br>• `frequencies` [Hz] / `azimuth` φ / `polar` θ [°] / `levels` [dB] (A×P×F) / `distance` (60 m)<br>• `.plot()`: fore-aft directivity / `.mirrored()`: φ → −φ (Eq. 2) | `h.levels` |
| `hemisphere_source_level` | `function` | **Interpolated source level L(fc,φ,θ) (Eq. 13-15).**<br>• `hemisphere` / `azimuth_deg` φ / `polar_deg` θ<br>• energy-bilinear + nearest-bin fill | `hemisphere_source_level(h, 0, 90)` |
| `hover_ring_hemisphere` | `function` | **Hemisphere from a ground-ring hover measurement (§A.3.5).**<br>• `frequencies` [Hz] / `bearings` [°] / `levels` (B×F) [dB] / `distance` (70 m)<br>• constant-φ extension; `mapping`: `"constant_phi"`\|`"bearing"` | `hover_ring_hemisphere(f, brg, L)` |
| `hover_derived_hemisphere` | `function` | **HOGE/idle hemisphere derived from in-ground hover (Table 3).**<br>• `condition`: `"out_of_ground_hover"`\|`"reduced_rpm_idle"`\|`"full_rpm_idle"`<br>• `offset_db` measured Approach 2 difference (default: +12/−12/−2.5 dB) | `hover_derived_hemisphere(h, "full_rpm_idle")` |
| `spherical_spreading_adjustment` | `function` | **ΔLs = −20·lg(r/60) (ECAC Doc 32 Eq. 24).**<br>• `distance` r [m] | `spherical_spreading_adjustment(600)` |
| `atmospheric_adjustment` | `function` | **ΔLa = −α(f)·(r−60) (Eq. 26/27; ISO 9613-1 α; Table 4).**<br>• `frequencies` [Hz] / `distance` r [m]<br>• `temperature_c` / `relative_humidity_percent` / `atmospheric_pressure_kpa` | `atmospheric_adjustment(f, 1060)` |
| `ground_effect_adjustment` | `function` | **ΔLg over an impedance plane (Chien-Soroka, Eq. 28-35).**<br>• `frequencies` / `source_height` / `receiver_height` / `horizontal_distance`<br>• `flow_resistivity` σ or CNOSSOS class `"A"`-`"H"` | `ground_effect_adjustment(f, 150, 1.5, 500)` |
| `flight_condition_weights` | `function` | **Hemisphere blend weights for a flight condition (NORAH2 Eq. 3-10).**<br>• database `airspeeds` / `path_angles_deg` [°] + query `airspeed` / `path_angle_deg`<br>• Delaunay triangle blend inside the hull, nearest outside<br>• `scaling_factor` Ffc (2) / `triangles` lookup table | `flight_condition_weights(V, G, 60, 2.5)` |
| `interpolated_source_level` | `function` | **Source level between hemispheres (Eq. 8/10 over Eq. 13).**<br>• `hemispheres` + database conditions + query condition<br>• `azimuth_deg` φ / `polar_deg` θ | `interpolated_source_level(hs, V, G, 60, 2.5, 0, 90)` |
| `flight_path_kinematics` | `function` | **Track kinematics by central differences (Eq. 16-21).**<br>• `times` [s] / `positions` (N,3) [m]<br>• Vg, VA, heading, curvature, bank Φ = atan(K·Vg²/g), path angle γ | `flight_path_kinematics(t, xyz)`<br><br>• `FlightPathKinematics` |
| `FlightPathKinematics` | `dataclass` | **Track kinematics result.**<br>• `ground_speed` / `airspeed` [m/s] / `heading` / `bank_angle_deg` / `path_angle_deg` [°] / `curvature` [rad/m]<br>• `.plot()`: speed and angle profiles | `kin.airspeed` |
| `RotorcraftAtmosphere` | `dataclass` | **Air of a rotorcraft event (Eq. 26/27).**<br>• `temperature_c` [°C] (25) / `relative_humidity_percent` [%] (70) / `atmospheric_pressure_kpa` [kPa] (101.325)<br>• `atmospheric_method`: `"iso9613"`\|`"sae"` | `RotorcraftAtmosphere(atmospheric_method="sae")` |
| `RotorcraftGround` | `dataclass` | **Ground under a rotorcraft event (§A.4.3-A.4.5).**<br>• `receiver_height` [m] (1.2) / `ground_elevation` [m] / `flow_resistivity` σ or class<br>• `terrain` (x, y, z model) + `terrain_resolution` [m] | `RotorcraftGround(flow_resistivity="D")` |
| `RotorcraftTrackState` | `dataclass` | **Per-point flight state overriding the derived kinematics (Eq. 16-21).**<br>• `airspeed` / `path_angle_deg` / `heading` / `bank_angle_deg`, scalar or (N,) | `RotorcraftTrackState(heading=180.0)` |
| `FlightConditionInterpolation` | `dataclass` | **How a flight condition blends the database hemispheres (Eq. 3-10).**<br>• `scaling_factor` Ffc (2) / `triangles` lookup table | `FlightConditionInterpolation(triangles=tri)` |
| `rotorcraft_event_level` | `function` | **Single-event time history and metrics at a receiver (Doc 32 §6.1).**<br>• `hemispheres` + conditions / `times` / `positions` / `receiver` (x,y)<br>• `level_offset` [dB] (Eq. 2 substitution)<br>• `ground`: `RotorcraftGround` / `atmosphere`: `RotorcraftAtmosphere`<br>• `track_state`: `RotorcraftTrackState` / `interpolation`: `FlightConditionInterpolation` | `rotorcraft_event_level(hs, V, G, t, xyz, (x, y))`<br><br>• `RotorcraftEventResult` |
| `RotorcraftEventResult` | `dataclass` | **Single-event result.**<br>• `times` (recorded) / `band_levels` / `a_levels` [dB(A)]<br>• `la_max` / `sel` / `sel_10db` / `pnlt` / `pnltm` / `epnl`<br>• `.plot()`: LA(t) history with the 10 dB-down window | `res.sel, res.epnl` |
| `rotorcraft_noise_contour` | `function` | **Single-event SEL/LASmax over a ground grid (Doc 32 §6.3).**<br>• event inputs + `x` / `y` grids [m]<br>• `metric`: `"exposure"`\|`"maximum"`<br>• `ground`: `RotorcraftGround`, whose `flow_resistivity` / `ground_elevation` also take one value per grid point | `rotorcraft_noise_contour(hs, V, G, t, xyz, x=gx, y=gy)`<br><br>• `RotorcraftNoiseContourResult` |
| `RotorcraftNoiseContourResult` | `dataclass` | **Rotorcraft ground-grid contour result.**<br>• `x` / `y` [m] / `levels` [dB(A)] (Ny×Nx) / `metric`<br>• `.plot()`: filled contours | `res.levels` |
| `mean_ground_plane` | `function` | **Mean ground plane of a terrain section (NORAH2 Eq. 36-40).**<br>• `distances` / `heights` [m] (polyline)<br>• continuous least squares in closed form | `mean_ground_plane(d, z)`<br><br>• `MeanGroundPlaneResult` |
| `MeanGroundPlaneResult` | `dataclass` | **Fitted plane.**<br>• `slope` a / `intercept` b [m]<br>• `.height(d)` / `.equivalent_height(d, z)` (orthogonal)<br>• `.plot()`: section + plane | `res.slope` |
| `mean_flow_resistivity` | `function` | **Log-mean flow resistivity along a path (Eq. 41).**<br>• `lengths` [m] / `resistivities` [Pa·s/m²] per segment | `mean_flow_resistivity(d, sig)` |
| `diffraction_attenuation` | `function` | **Pure diffraction ΔLd per band (Eq. 42-44).**<br>• `path_difference` δ [m] (negative allowed) / `edge_height` h0 [m]<br>• `edge_span` e (C″, multiple edges) / `capped` (25 dB) | `diffraction_attenuation(f, 0.5, edge_height=10)` |
| `terrain_screening_adjustment` | `function` | **Ground + screening over a vertical section (§A.4.4-A.4.5).**<br>• `source` / `receiver` (d, z) [m] / `distances` / `heights` (terrain)<br>• `flow_resistivity`: value, class or per segment (Eq. 41)<br>• clear path → mean-plane ground effect; blocked → rubber band + Eq. 45-47 | `terrain_screening_adjustment(f, S, R, d, z)`<br><br>• `TerrainScreeningResult` |
| `TerrainScreeningResult` | `dataclass` | **Section result.**<br>• `adjustment` [dB] (replaces the flat ΔLg) / `path_difference` δ [m] / `diffraction_points`<br>• `screened` (terrain strictly above the line of sight) is read-only, read from `source`, `receiver`, `distances`, `heights`; the section runs from the source to the receiver, and `path_difference` and `diffraction_points` are the path difference and the diffracting edges of the rubber band stretched over it (NaN and no edge when the line of sight is clear)<br>• `.plot()`: section geometry | `res.adjustment` |
| `slant_distance` | `function` | **Rotor-centre-to-microphone slant distance (IEC 61400-11).**<br>• `hub_height` H [m]<br>• `rotor_diameter_m` D [m]<br>• `rotor_axis` (Default: "horizontal" → R0 = H+D/2, Formula 1; "vertical" → R0 = H+D, Formula 2)<br>= √(H² + R0²) | `slant_distance(80.0, 100.0)` |
| `apparent_sound_power_level` | `function` | **Apparent sound power level (IEC 61400-11 Formula 26), dB re 1 pW.**<br>• `band_levels`: background-corrected A-weighted band SPL [dB]<br>• `r1`: slant distance [m]<br>= L_p − 6 + 10·lg(4π R1²/S0) | `apparent_sound_power_level(levels, r1)` |
| `wind_turbine_tonality` | `function` | **Tonal audibility from a narrowband spectrum (IEC 61400-11), with the 9.5.2 possible-tone screening; tone lines and La anchor to the highest classified line (9.5.3/9.5.4).**<br>• `levels` [dB] / `frequencies` [Hz]: 1-D, equal length (≥ 3), strictly increasing and uniformly spaced (narrowband), covering the whole critical band<br>• `tone_frequency`: optional [Hz] (≥ 20 Hz) | `res = environment.wind_turbine_tonality(levels, freqs)`<br><br>• `WindTurbineTonalityResult` |
| `WindTurbineTonalityResult` | `dataclass` | **Wind-turbine tonality result.**<br>• `tone_frequency` [Hz] / `critical_bandwidth` [Hz]<br>• `tone_level` / `masking_level` / `tonality` [dB]<br>• `audibility_criterion` / `tonal_audibility` [dB]<br>• `is_audible` / `has_identified_tone` (False → exclude from 9.5.1 bin averaging)<br>• `.plot()`: spectrum + critical band + masking<br>• takes `tone_frequency`, `critical_bandwidth`, `tone_level`, `masking_level`, `tonality`, `audibility_criterion`, `tonal_audibility`, `frequencies`, `levels`, `candidate_frequency_hz`; `has_identified_tone` (9.5.2 to 9.5.4 over the spectrum) and `is_audible` are read-only, read from them, and the Formula 30 to 34 numbers are held to the spectrum about the candidate line | `res.tonal_audibility, res.is_audible` |
| `WindTurbineNoiseWarning` | `warning class` | **IEC 61400-11 advisory.**<br>Emitted when the tonality inputs leave the standard's stated domain of validity | `warnings.simplefilter('error', WindTurbineNoiseWarning)` |
| `power_law_wind_speed` / `wind_shear_exponent` / `logarithmic_wind_speed` | `function` | **Wind speed at another height (IEC TS 61400-11-2 Annex K, IEC 61400-11 Annex D).**<br>• `power_law_wind_speed(V_ref, height_m=, reference_height_m=, shear_exponent=)` = V_ref (z/z_ref)^α, Equation (K.1), Table K.1<br>• `wind_shear_exponent(V, V_ref, height_m=, reference_height_m=)` = ln(V/V_ref)/ln(z/z_ref), Equation (K.2), Table K.2<br>• `logarithmic_wind_speed(V_ref, height_m=, reference_height_m=, roughness_length_m=0.05)`: the logarithmic profile over the reference roughness length z0ref = 0.05 m (3.31; IEC 61400-11 Equation (29)) with which 9.3.2.1 brings a hub-height wind speed to 10 m | `power_law_wind_speed(9.0, height_m=10, reference_height_m=120, shear_exponent=0.2)` |
| `wind_shear_profile` | `function` | **Power-law profile through two measured wind speeds (K.4.3).**<br>• `lower_speed_m_s` / `upper_speed_m_s` [m/s]<br>• `lower_height_m` [m] (10) / `upper_height_m` [m] | `environment.wind_shear_profile(5.0, 9.0, upper_height_m=120.0)`<br><br>• `WindShearProfile` |
| `WindShearProfile` | `dataclass` | **Wind profile through two heights.**<br>• `heights_m` / `speeds_m_s` / `shear_exponent` / `typical` (−0.1 ≤ α ≤ 0.5)<br>• `.speed_at(height_m)`<br>• `.plot()`: power law and logarithmic profile through the points<br>• takes `heights_m`, `speeds_m_s`, `shear_exponent`; `typical` is read-only, read from them | `profile.speed_at(100.0)` |
| `REFERENCE_ROUGHNESS_LENGTH_M` / `ROUGHNESS_LENGTHS_M` / `TYPICAL_WIND_SHEAR_EXPONENT_RANGE` | `constant` / `mapping` / `constant` | **Annex K constants.**<br>• z0ref = 0.05 m (3.31)<br>• Table K.3: terrain → roughness length [m]<br>• (−0.1, 0.5): the shear exponents Table K.2 keeps | `ROUGHNESS_LENGTHS_M["Farmland with some vegetation"]` |
| `bin_sound_levels` | `function` | **Interval levels per wind speed bin and sector (10.1, 10.3).**<br>• `levels_db` / `wind_speeds_m_s` / optional `wind_directions_deg`<br>• `averaging`: `"energy"` (Equation (1)) or `"arithmetic"` (Equation (8), statistical levels)<br>• `type_b_uncertainty_db`: Equation (3), one or per interval<br>• `bin_width_m_s` (1) / `sector_width_deg` (30, north-centred) | `total = environment.bin_sound_levels(levels, speeds)`<br><br>• `BinnedSoundLevels` |
| `BinnedSoundLevels` | `dataclass` | **Bin averages and their uncertainty.**<br>• `wind_speeds_m_s` / `wind_directions_deg` / `counts`<br>• `mean_levels_db` / `type_a_uncertainty_db` (Eq. (2)/(9)) / `type_b_uncertainty_db` (Eq. (4)) / `combined_uncertainty_db` (Eq. (5))<br>• `bin_width_m_s` / `sector_width_deg`: the widths binned with<br>• `.background_corrected(background)` → `TurbineSoundLevels` over the shared bins (same widths required)<br>• `.plot()`: interval scatter and bin averages | `total.background_corrected(background)` |
| `turbine_sound_levels` | `function` | **Background subtracted bin by bin (Equations (6), (7) and 11.7).**<br>• `total_levels_db` / `background_levels_db`<br>• `total_uncertainty_db` / `background_uncertainty_db` / `wind_speeds_m_s` / `wind_directions_deg`<br>• ≥ 3 dB: logarithmic subtraction; ≥ 0 dB and < 3 dB: the suggested 3 dB correction; background above: undetermined (NaN) | `environment.turbine_sound_levels([45.0], [40.0])`<br><br>• `TurbineSoundLevels` |
| `TurbineSoundLevels` | `dataclass` | **Background-corrected turbine levels.**<br>• `total_levels_db` / `background_levels_db` / `level_differences_db` / `turbine_levels_db` / `turbine_uncertainty_db`<br>• `regimes`: `BackgroundCorrectionRegime` per bin, read-only, read from the total and the background; the difference, the turbine level and the NaN of an undetermined bin are held to it<br>• `wind_speeds_m_s` / `wind_directions_deg`: the bin of each row, or `None`<br>• `.plot()`: total, background and turbine per bin, each direction sector apart in its own colour | `res.turbine_levels_db` |
| `BackgroundCorrectionRegime` | `enum` | **Which rule of 11.7 a bin followed.**<br>`LOGARITHMIC` / `THREE_DB` / `UNDETERMINED` | `res.regimes[0] is BackgroundCorrectionRegime.THREE_DB` |
| `predicted_receptor_level` | `function` | **A prediction summed over the turbines, with its uncertainty (10.3.4).**<br>• `turbine_levels_db` / `sound_power_uncertainty_db`<br>• `prediction_model_uncertainty_db` (2) / `modelling_uncertainty_db` (0.5)<br>= energy sum; Equation (10) level-weighted, Equation (11) in quadrature | `environment.predicted_receptor_level([35, 32, 28], 1.5)`<br><br>• `PredictedReceptorLevel` |
| `PredictedReceptorLevel` | `dataclass` | **Predicted receptor level.**<br>• `level_db` / `propagated_uncertainty_db` / `combined_uncertainty_db`<br>• `.plot()`: turbine contributions and the total | `res.combined_uncertainty_db` |
| `PREDICTION_MODEL_UNCERTAINTY_DB` / `MODELLING_UNCERTAINTY_DB` / `TYPE_B_UNCERTAINTY_EXAMPLES_DB` | `constant` / `constant` / `mapping` | **10.3 uncertainty values.**<br>• 2 dB (ISO 9613-2 or Nord2000 downwind to 3 km to 5 km) / 0.5 dB<br>• Table 3: component → (range, standard uncertainty) [dB] | `TYPE_B_UNCERTAINTY_EXAMPLES_DB["calibration"]` |
| `sound_relevant_turbines` | `function` | **The turbines that set the binning wind speed (9.3.2.3).**<br>• `predicted_levels_db`: each turbine at the receptor<br>• quietest left out while the total drops 1.0 dB or less | `environment.sound_relevant_turbines(levels)`<br><br>• `SoundRelevantTurbines` |
| `SoundRelevantTurbines` | `dataclass` | **Sound relevant turbines.**<br>• `relevant` / `indices` (loudest first) / `total_level_db` / `relevant_level_db`<br>• `.binning_wind_speed_m_s(speeds)`: their arithmetic mean<br>• `.plot()`: levels loudest first, turbines numbered from 1, with the energy sum of the loudest<br>• takes `predicted_levels_db`; `relevant`, `total_level_db`, `relevant_level_db` are read-only, read from them | `res.binning_wind_speed_m_s(speeds)` |
| `wind_turbine_low_frequency_level` | `function` | **Low frequency sound by Equation (C.1) (Annex C).**<br>• `sound_power_levels_db`: one row per turbine<br>• `distance_m` l / `hub_height_m` h<br>• `frequencies_hz` (10 Hz to 200 Hz) / `ground_correction_db` / `air_attenuation_db_per_km` (Table C.2) / `facade_insulation_db` / `a_weighted` (True) | `environment.wind_turbine_low_frequency_level(lw, distance_m=600, hub_height_m=120)`<br><br>• `LowFrequencyLevel` |
| `LowFrequencyLevel` | `dataclass` | **Outdoor and indoor low frequency levels.**<br>• band terms of Table C.4 / `outdoor_levels_db` / `indoor_levels_db`<br>• `outdoor_level_db` / `indoor_level_db`: energy sums<br>• `.plot()` | `res.indoor_level_db` |
| `LOW_FREQUENCY_BANDS_HZ` / `LOW_FREQUENCY_GROUND_CORRECTION_DB` / `LOW_FREQUENCY_AIR_ATTENUATION_DB_PER_KM` | `array` | **Table C.2, 10 Hz to 200 Hz.**<br>• onshore ground correction, class D [dB]<br>• air attenuation [dB/km] as printed: the Danish order's 80 % cells to 100 Hz, ISO 9613-1 at 70 % above | `LOW_FREQUENCY_AIR_ATTENUATION_DB_PER_KM[7]  # 0.07` |
| `LOW_FREQUENCY_FACADE_INSULATION_DB` / `LOW_FREQUENCY_GROUND_IMPEDANCE_CLASSES` / `SWEDISH_LOW_FREQUENCY_LIMITS_DB` | `mapping` | **Tables C.3, C.1 and C.5.**<br>• facade insulation examples [dB]<br>• impedance classes A to H → `GroundImpedanceClass`<br>• the Swedish criterion curve, 31.5 Hz to 200 Hz [dB] | `LOW_FREQUENCY_FACADE_INSULATION_DB["Denmark lightweight"]` |
| `GroundImpedanceClass` | `dataclass` | **One row of Table C.1.**<br>• `flow_resistivity_kpa_s_m2` / `nordtest_classes_kpa_s_m2` / `description` | `LOW_FREQUENCY_GROUND_IMPEDANCE_CLASSES["D"]` |
| `sound_emergence` | `function` | **The emergence criterion per wind speed class (Equation (J.1)).**<br>• `ambient_levels_db` / `background_levels_db` / `wind_speeds_m_s` | `environment.sound_emergence([40.0], [36.0])`<br><br>• `SoundEmergence` |
| `SoundEmergence` | `dataclass` | **Emergence per class.**<br>• `emergence_db` = L_Amb − L_Rés<br>• `.plot()` | `res.emergence_db` |
| `amplitude_modulation_adjustment` | `function` | **The amplitude modulation adjustment of Figure A.1 [dB].**<br>• `modulation_depth_db`: 0 below 3 dB, 3 dB at 3 dB, rising to 5 dB at 10 dB, 5 dB above | `environment.amplitude_modulation_adjustment(6.5)  # 4.0` |
| `wind_turbine_rating_level` | `function` | **Rating level with the most severe adjustment alone (A.1).**<br>• `equivalent_level_db`<br>• `tonal_adjustment_db` / `amplitude_modulation_adjustment_db` / `impulsive_adjustment_db` | `environment.wind_turbine_rating_level(40.0, tonal_adjustment_db=2.0)`<br><br>• `WindTurbineRatingLevel` |
| `WindTurbineRatingLevel` | `dataclass` | **Rating level.**<br>• `adjustments_db` / `governing` / `rating_level_db`<br>• `.plot()`: the three adjustments, the governing one hatched | `res.rating_level_db` |
| `upper_tone_search_frequency` | `function` | **Top of the search for tones at a receptor (12.5.2.4, Table 7).**<br>• `distance_m`<br>• `temperature_c` / `relative_humidity_percent` / `atmospheric_pressure_kpa` (101.325)<br>= lowest band ISO 9613-1 attenuates by 20 dB over the distance, else 10 kHz | `environment.upper_tone_search_frequency(600.0, temperature_c=10.0, relative_humidity_percent=50.0)`<br><br>• `ToneSearchLimit` |
| `ToneSearchLimit` | `dataclass` | **Tone search limit.**<br>• `upper_frequency_hz` / `frequencies_hz` / `attenuation_db`<br>• `.plot()`: band attenuation and the 20 dB line | `res.upper_frequency_hz` |
| `TONE_SEARCH_BANDS_HZ` | `array` | **The one-third-octave centres searched, 50 Hz to 10 kHz.** | `TONE_SEARCH_BANDS_HZ[-1]  # 10000.0` |
| `amplitude_modulation_band_levels` | `function` | **Band-limited 100 ms levels of one AM band (13.6.2.1.1).**<br>• `band_levels_db`: one row per 100 ms, one column per band<br>• `frequencies_hz` / `band` (1 to 3, or 4 to 6 of Annex G.3)<br>• `weighting`: `"A"` (already weighted) or `"Z"` (A-weighting applied) | `environment.amplitude_modulation_band_levels(logged, freqs, band=2, weighting="Z")` |
| `amplitude_modulation_block` | `function` | **One 10 s block of clause 13 (13.6.2.3).**<br>• `levels_db`: 100 values of 100 ms<br>• `modulation_frequency_range_hz`: range of the fundamental within 0.3 Hz to 1.6 Hz | `environment.amplitude_modulation_block(x, modulation_frequency_range_hz=(0.4, 0.9))`<br><br>• `ModulationBlock` |
| `ModulationBlock` | `dataclass` | **10 s block analysis.**<br>• `status` / `valid` / `fundamental_frequency_hz` / `prominence` (Eq. (13))<br>• `harmonic_frequencies_hz` / `included_frequencies_hz` / `power_spectrum` (Eq. (12))<br>• `detrended_db` / `reconstructed_db` / `modulation_depth_db` (L5 − L95)<br>• `excluded`: the practitioner's exclusion (13.6.2.2)<br>• `.plot(kind="spectrum" \| "series")`<br>• `status` is read-only, read from `prominence`, the threshold of 4 and `excluded` | `block.modulation_depth_db` |
| `ModulationBlockStatus` | `enum` | **Why a 10 s block counts or not.**<br>`VALID` / `NO_PEAK` / `LOW_PROMINENCE` / `EXCLUDED` | `block.status is ModulationBlockStatus.VALID` |
| `amplitude_modulation_period` | `function` | **The 10 min AM rating (13.6.3).**<br>• `levels_db`: 6 000 values of 100 ms<br>• `modulation_frequency_range_hz` / `excluded_blocks` (60 flags) | `environment.amplitude_modulation_period(x, modulation_frequency_range_hz=(0.4, 0.9))`<br><br>• `ModulationPeriod` |
| `ModulationPeriod` | `dataclass` | **10 min rating.**<br>• `blocks` / `modulation_depths_db` / `valid_blocks` / `rated` (≥ 30)<br>• `rating_db`: 90th percentile of the valid depths, else 0 dB<br>• `mean_modulation_frequency_hz` / `mode_modulation_frequency_hz`<br>• `.plot()`<br>• takes `blocks`; `modulation_depths_db`, `fundamental_frequencies_hz`, `valid_blocks`, `rated`, `rating_db`, `mean_modulation_frequency_hz`, ... are read-only, read from them | `period.rating_db` |
| `bin_amplitude_modulation` | `function` | **10 min ratings per bin, worst band chosen (13.6.4).**<br>• `ratings_db`: one row per period, one column per band<br>• `wind_speeds_m_s` / optional `wind_directions_deg`<br>• `bands` ((1, 2, 3)) / `excluded` / `sector_width_deg` (30) | `environment.bin_amplitude_modulation(r, speeds, directions)`<br><br>• `BinnedModulation` |
| `BinnedModulation` | `dataclass` | **Binned AM ratings.**<br>• `mean_ratings_db` (zeros included) / `type_a_uncertainty_db` / `counts` / `nonzero_counts` / `exceedance_percent` (3, 6, 9 dB)<br>• `selected_bands` / `selected_ratings_db`<br>• `.plot()` | `binned.selected_bands` |
| `AM_FREQUENCY_BANDS_HZ` / `AM_EXCEEDANCE_THRESHOLDS_DB` / `AM_MODULATION_FREQUENCY_LIMITS_HZ` | `mapping` / `constant` / `constant` | **Clause 13 bands and limits.**<br>• band → its seven one-third-octave centres [Hz]<br>• (3, 6, 9) dB of 13.7<br>• (0.3, 1.6) Hz of 13.2 | `AM_FREQUENCY_BANDS_HZ[2]` |
| `AM_SAMPLE_INTERVAL_S` / `AM_BLOCK_SAMPLES` / `AM_PERIOD_BLOCKS` / `AM_MINIMUM_VALID_BLOCKS` / `AM_PROMINENCE_THRESHOLD` | `constant` | **Clause 13 numbers.**<br>0.1 s / 100 samples / 60 blocks / 30 valid blocks / prominence 4 | `AM_PROMINENCE_THRESHOLD  # 4.0` |
| `noise_criterion` | `function` | **NC rating, clause 5.2.2 two-step (ANSI/ASA S12.2-2019).**<br>• `levels`: octave-band SPL [dB] (the 10 bands 16 Hz–8 kHz without `frequencies`)<br>• `frequencies`: optional band centres [Hz] (subset allowed) | `nc = room.noise_criterion(levels)`<br><br>• `NCResult`; NC-(SIL) designation, tangency when exceeded |
| `room_criterion` | `function` | **RC Mark II rating (ANSI/ASA S12.2-2019 Annex D).**<br>• `levels`: octave-band SPL [dB]<br>• `frequencies`: optional band centres [Hz] | `rc = room.room_criterion(levels)`<br><br>• `RCResult`; LMF average + 'N'/'R'/'H'/'RH' tag |
| `nc_curve` | `function` | **NC curve levels (Table 1).**<br>• `index`: NC designation 15–70 (intermediate values interpolated band by band) | `nc_curve(35)  # [82, 71, 60, ...]`<br><br>• 10 band levels [dB], 16 Hz–8 kHz |
| `rc_curve` | `function` | **RC Mark II curve (Table D.1).**<br>• `index`: RC designation (value at 1000 Hz) | `rc_curve(35)`<br><br>• −5 dB/octave line, 10 bands [dB] |
| `NCResult` | `dataclass` | **NC rating result.**<br>• `rating`: NC designation (NaN outside NC-15…NC-70, see `out_of_range`)<br>• `sil`, `tangency_rating`, `method`, `label`<br>• `governing_frequency`: tangency band [Hz]<br>• `frequencies` [Hz], `levels` [dB]<br>• `.plot()` | `nc.rating, nc.label` |
| `RCResult` | `dataclass` | **RC Mark II result.**<br>• `rating`: LMF rounded [dB], int<br>• `lmf`: 500/1000/2000 Hz average [dB]<br>• `classification`: 'N'/'R'/'H'/'RH'<br>• `reference_curve` [dB], `frequencies` [Hz], `levels` [dB]<br>• `.plot()` | `rc.rating, rc.classification` |
| `age_threshold` | `function` | **Age-related hearing threshold distribution (ISO 7029:2017).**<br>• `age`: years (≥ 18)<br>• `sex`: 'male'/'female' (Default: 'male')<br>• `fractile`: population fractile in (0, 1) (Default: 0.5)<br>• `frequencies`: subset of the 11 audiometric frequencies [Hz] (Default: None → 125–8000 Hz) | `at = hearing.age_threshold(60, 'male')`<br><br>• `AgeThresholdResult`; median at 4 kHz = 20.2 dB |
| `AUDIOMETRIC_FREQUENCIES` | `ndarray` | **The eleven audiometric frequencies of ISO 389-7:2005 Table 1** [Hz], the axis every threshold in this module is aligned with. | `hearing.AUDIOMETRIC_FREQUENCIES  # 125 ... 8000` |
| `FIELDS` | `tuple` | **The listening fields `reference_threshold` accepts**: `'free-field'`, `'diffuse-field'`. | `hearing.FIELDS` |
| `SEXES` | `tuple` | **The populations `age_threshold` accepts** (ISO 7029:2017 tabulates the two separately): `'male'`, `'female'`. | `hearing.SEXES` |
| `reference_threshold` | `function` | **Reference threshold of hearing, 0 dB HL (ISO 389-7:2005 Table 1).**<br>• `field`: 'free-field' or 'diffuse-field' (Default: 'free-field')<br>• `frequencies`: optional subset [Hz] | `t = hearing.reference_threshold()`<br><br>• dB SPL per audiometric frequency (1 kHz → 2.4) |
| `RETSPL_FREQUENCIES_HZ` / `EARPHONES` / `EARPHONE_COUPLERS` | `constant` | **ISO 389-1 Tables 1 and 2: the twenty-three test frequencies, the three earphone cases the standard prints a reference level for, and the coupler each of them is calibrated on.** | `hearing.EARPHONE_COUPLERS['TDH 39']  # 'IEC 60303 acoustic coupler'` |
| `earphone_reference_level` / `hearing_level_to_coupler_spl` | `function` | **ISO 389-1:1998: what 0 dB HL is on a supra-aural earphone, and what an audiogram is worth in the coupler.**<br>• `earphone_reference_level(earphone, frequencies)`: the RETSPL, for `'DT 48'` or `'TDH 39'` (Table 1, IEC 60303 coupler) or `'other supra-aural'` (Table 2, IEC 60318 artificial ear)<br>• `hearing_level_to_coupler_spl(hearing_level, earphone, frequencies)`: the audiogram plus that reference, which is all hearing level means | `hearing.earphone_reference_level('TDH 39', [1000.0])`<br><br>• `array([7.])` dB |
| `AgeThresholdResult` | `dataclass` | **Age threshold distribution.**<br>• `age`, `sex`, `fractile`<br>• `frequencies` [Hz]<br>• `median`: deviation from age 18 [dB]<br>• `spread_upper` / `spread_lower`: half-Gaussian su/sl [dB]<br>• `threshold`: value at `fractile` [dB]<br>• `.plot()` | `at.median, at.threshold` |
| `check_audiometric_ambient_noise` | `function` | **Is the test room quiet enough for the audiometry? (ISO 8253-1 Clause 11, ISO 8253-2 Clause 6).**<br>• `levels_db`: one-third-octave ambient levels at the subject's head [dB]<br>• `presentation`: 'air' (Table 2), 'bone' (Table 4) or 'sound field' (ISO 8253-2 Table 2) (Default: 'air')<br>• `lowest_test_frequency_hz`: 125, 250 or, for air, 500 (Default: 125)<br>• `earphone` / `earphone_attenuation_db`, `lowest_hearing_level_db`, `allowed_threshold_shift_db` (2 or 5)<br>• `frequencies`, `noise_floor_db` (11.1's 6 dB margin) | `c = hearing.check_audiometric_ambient_noise(levels)`<br><br>• `AmbientNoiseCheck` (`limits_db`, `exceedance_db`, `lowest_measurable_hearing_level_db`, `passes`) |
| `ambient_noise_limits` | `function` | **The maximum permissible ambient levels of a test room, every adjustment of 11.1 applied.**<br>• same keywords as the check; + (A_earphone − A_supra-aural) from Table 3, + the lowest hearing level, + 8 dB for a +5 dB shift | `hearing.ambient_noise_limits('air', earphone='ER-3A')` |
| `AmbientNoiseCheck` | `dataclass` | **Room verdict.**<br>• `within` per band, `covers_all_bands`, `floor_limited`<br>• `passes` needs every band of the table; `bool()` raises | `c.passes` |
| `AMBIENT_NOISE_BANDS_HZ` | `constant` | **The 25 one-third-octave mid-frequencies of ISO 8253-1 Tables 2 to 4, 31.5 Hz to 8 kHz** [Hz]. | `hearing.AMBIENT_NOISE_BANDS_HZ[0]  # 31.5` |
| `AIR_CONDUCTION_AMBIENT_LIMITS_DB` / `BONE_CONDUCTION_AMBIENT_LIMITS_DB` | `mapping` | **ISO 8253-1 Tables 2 and 4: L_S,max by lowest test frequency (125, 250, 500 Hz for air; 125, 250 Hz for bone)** [dB], read-only arrays. | `hearing.BONE_CONDUCTION_AMBIENT_LIMITS_DB[125.0][21]  # 2.0 at 4 kHz` |
| `EARPHONE_ATTENUATION_DB` | `mapping` | **ISO 8253-1 Table 3: average attenuation of 'supra-aural', 'ER-3A' and 'HDA 200' earphones** [dB]; NaN where the HDA 200 prints none (below 63 Hz). | `hearing.EARPHONE_ATTENUATION_DB['ER-3A']` |
| `ascending_method_threshold` | `function` | **Hearing threshold level by the ascending method (ISO 8253-1 6.2.3.2, 6.2.4.2).**<br>• `ascent_levels_db`: the response level of each ascent [dB], or `presentation_levels_db` with `responses`, replayed against the 5 dB up / 10 dB down steps<br>• `shortened` (two out of three)<br>• `familiarization_level_db`: checks or gives the first tone (10 dB below) | `r = hearing.ascending_method_threshold([30, 35, 30, 30])`<br><br>• `AscendingThresholdResult` (`threshold_db`, `determined`, `next_level_db`, `series_exhausted`, `doubtful`) |
| `bracketing_method_threshold` | `function` | **Hearing threshold level by the bracketing method (ISO 8253-1 6.2.4.3).**<br>• `ascent_levels_db`, `descent_levels_db`: lowest response levels [dB]<br>• mean of the two averages, rounded to the nearest 5 dB step (a tie goes up) | `hearing.bracketing_method_threshold([30, 30, 35], [30, 35, 35]).threshold_db  # 35.0`<br><br>• `BracketingThresholdResult` (`complete`, `repeat_advised`) |
| `automatic_audiometry_threshold` | `function` | **Hearing threshold level from an automatic recording (ISO 8253-1 6.3.5).**<br>• `reversal_levels_db`: levels at the tracing's reversals, in order [dB]<br>• drops the first reversal and both ends of excursions of 3 dB or less; mean of peaks and valleys rounded up | `hearing.automatic_audiometry_threshold(reversals).threshold_db`<br><br>• `AutomaticThresholdResult` (`peaks_db`, `valleys_db`, `doubtful`) |
| `sweep_audiometry_threshold` | `function` | **Hearing threshold levels from a sweep-frequency tracing (ISO 8253-1 7.5).**<br>• `reversal_frequencies` [Hz], `reversal_levels_db` [dB]<br>• `frequencies` [Hz] (Default: the audiometric frequencies the sweep spans)<br>• three nearest peaks and valleys on a log axis; running average of six reversals | `hearing.sweep_audiometry_threshold(f, levels)`<br><br>• `SweepThresholdResult` (`threshold_db`, `running_frequencies`, `running_threshold_db`, `less_reliable`) |
| `AscendingThresholdResult` / `BracketingThresholdResult` / `AutomaticThresholdResult` / `SweepThresholdResult` | `dataclass` | **ISO 8253-1 threshold results, each with the reliability test its clause writes (a span over 10 dB) and `.plot()`.**<br>• `AscendingThresholdResult` takes `ascent_levels_db`, `shortened`, `next_level_db`, `presentation_levels_db`, `responses`; `threshold_db`, `determined`, `series_exhausted` are read-only, read from them<br>• `AutomaticThresholdResult` takes `reversal_levels_db`, `mean_db`, `threshold_db`; `is_peak` and `retained` (6.3.5 a)) are read-only, read from the levels, and the mean and the threshold are held to the reversals kept<br>• `SweepThresholdResult`: `is_peak` is read-only, read from `reversal_levels_db`, and every column is held to the reversals | `r.threshold_db` |
| `audiometric_uncertainty` | `function` | **The typical uncertainty budget of a hearing threshold level (ISO 8253-1 A.3).**<br>• `frequency` [Hz], `conduction`: 'air' or 'bone', `masked`<br>• `level_step_db` (Default: 5), `environment_db` (Default: 2), `tester_db`, `subject_db`, `special_db` | `b = hearing.audiometric_uncertainty(1000.0)`<br><br>• `AudiometricUncertaintyBudget`; `b.combined_db` 4.88, `b.expanded_db` 9.76 (Table A.2: 4,9 and 10) |
| `AudiometricUncertaintyBudget` | `dataclass` | **The eight standard uncertainties of Table A.1 [dB].**<br>• `combined_db` = root sum of squares (A.2), `expanded_db` = 2u | `b.components_db` |
| `check_retest_agreement` | `function` | **Does the repeat measurement confirm the first? (ISO 8253-1 6.2.3.2 Step 3).**<br>• `first_db`, `repeat_db`: the two hearing threshold levels [dB]<br>• `frequency_hz` [Hz] (Default: 1000) | `c = hearing.check_retest_agreement(25.0, 35.0)`<br><br>• `RetestAgreementCheck` (`difference_db`, `passes` within 5 dB, `retest_further_frequencies` at 10 dB or more) |
| `RetestAgreementCheck` | `dataclass` | **Repeat verdict.**<br>• `passes`: 5 dB or less either way; `bool()` raises<br>• `.plot()`: the two measurements over the band 5 dB either side of the first | `c.passes` |
| `audiogram_cautions` | `function` | **Flag the levels of an audiogram that call for caution (ISO 8253-1 6.2.3.2, 8.4).**<br>• `frequencies` [Hz]<br>• `air_conduction_db` / `bone_conduction_db`: one ear's hearing threshold levels [dB]<br>• `vibrator_placement`: 'mastoid' (Default) or 'forehead' (10 dB lower) | `a = hearing.audiogram_cautions(f, air_conduction_db=air)`<br><br>• `AudiogramCautions` (`cross_hearing` at 40 dB or more, `vibrotactile`, `any_caution`) |
| `AudiogramCautions` | `dataclass` | **The cautions per frequency.**<br>• `vibrotactile_levels_db`: NaN where 8.4 gives none<br>• `.plot()`: the audiogram with the flagged levels crossed | `a.cross_hearing` |
| `VIBROTACTILE_HEARING_LEVELS_DB` | `mapping` | **ISO 8253-1 8.4: the average vibrotactile threshold of a bone vibrator on the mastoid, 40, 60 and 70 dB at 250 Hz, 500 Hz and 1 kHz** [dB]; about 10 dB lower for forehead placement. | `hearing.VIBROTACTILE_HEARING_LEVELS_DB[500.0]  # 60.0` |
| `check_free_sound_field` / `check_quasi_free_sound_field` | `function` | **Is the test room's sound field free (ISO 8253-2 5.2) or quasi-free (5.4)?**<br>• `lateral_levels_db`: 'left', 'right', 'up', 'down' at 0.15 m [dB]; `reference_levels_db` [dB]<br>• `front_levels_db`, `back_levels_db`: on the reference axis at 0.15 m (free) or 0.10 m (quasi-free) [dB]<br>• `loudspeaker_distance_m` (at least 1 m) | `c = hearing.check_quasi_free_sound_field(lateral, ref, front_levels_db=f, back_levels_db=b, loudspeaker_distance_m=1.5)`<br><br>• `FreeSoundFieldCheck` (`usable_frequencies`, `passes`) |
| `check_diffuse_sound_field` | `function` | **Is the test room's sound field diffuse? (ISO 8253-2 5.3).**<br>• `position_levels_db`: the six positions at 0.15 m [dB]; `reference_levels_db` [dB]<br>• `directional_levels_db` with `front_to_random_index_db`, from 500 Hz (Table 1) | `c = hearing.check_diffuse_sound_field(six, ref, directional_levels_db=d, front_to_random_index_db=5.0)`<br><br>• `DiffuseSoundFieldCheck` |
| `FreeSoundFieldCheck` / `DiffuseSoundFieldCheck` | `dataclass` | **Sound-field verdicts, band by band.**<br>• `passes` only with every requirement judged; `bool()` raises<br>• the diffuse one is also what `check_random_incidence_field` returns<br>• the free one reads `axis_offset_m` (0.15 m or 0.10 m) and `inverse_distance_difference_db` from `field` and `loudspeaker_distance_m`, not as fields | `c.passes` |
| `DIFFUSE_FIELD_VARIATION_LIMITS` | `constant` | **ISO 8253-2 Table 1: (lowest front-to-random index, allowable variation) [dB].**<br>5 → 5, 4.5 → 4.5, 4 → 4; below 4 dB the microphone is not suitable | `hearing.DIFFUSE_FIELD_VARIATION_LIMITS[1]  # (4.5, 4.5)` |
| `SOUND_FIELD_AMBIENT_BANDS_HZ` | `constant` | **The 27 one-third-octave mid-frequencies of ISO 8253-2 Table 2, 31.5 Hz to 12.5 kHz** [Hz]. | `hearing.SOUND_FIELD_AMBIENT_BANDS_HZ[-1]  # 12500.0` |
| `SOUND_FIELD_AMBIENT_LIMITS_DB` | `mapping` | **ISO 8253-2 Table 2: L_max for sound field audiometry by lowest test frequency (125, 250 Hz)** [dB]; ISO 8253-1 Table 4 less 3 dB up to 8 kHz. | `hearing.SOUND_FIELD_AMBIENT_LIMITS_DB[125.0][21]  # -1.0 at 4 kHz` |
| `INCIDENCE_CORRECTION_FREQUENCIES_HZ` / `INCIDENCE_CORRECTIONS_DB` | `constant` | **ISO 8253-2 Table B.1: the increase at the ear nearer an off-axis loudspeaker, 45° and 90°, 125 Hz to 12.5 kHz** [Hz], [dB]. | `hearing.INCIDENCE_CORRECTIONS_DB[90.0]` |
| `incidence_correction` | `function` | **Table B.1 lookup.**<br>• `frequencies` [Hz], each listed<br>• `incidence_angle_deg`: 45 or 90 | `hearing.incidence_correction([1000.0], incidence_angle_deg=45)  # [4.]` |
| `nipts` | `function` | **Noise-induced permanent threshold shift (ISO 1999:2013 §6.3).**<br>• `l_ex`: LEX,8h [dB]<br>• `years`: exposure duration (10–40 established; 1–10 extrapolated by Formula 3)<br>• `fractile`: (0, 1) (Default: 0.5)<br>• `frequencies`: subset [Hz] (Default: None → 500–6000 Hz) | `n = hearing.nipts(95.0, 20.0)`<br><br>• `NiptsResult`; N50 at 4 kHz = 23.0 dB |
| `htlan` | `function` | **Threshold associated with age and noise, H′ = H + N − HN/120 (ISO 1999 Formula 1).**<br>• `age`: years (≥ 18), `sex`: 'male'/'female'<br>• `l_ex`: LEX,8h [dB], `years`<br>• `fractile`: (0, 1) applied to both components (Default: 0.5)<br>• `frequencies` | `h = hearing.htlan(60, 'male', 95.0, 20.0)`<br><br>• `HtlanResult`; H′ at 4 kHz = 39.3 dB |
| `NiptsResult` | `dataclass` | **NIPTS distribution.**<br>• `l_ex`, `years`, `fractile`<br>• `frequencies` [Hz]<br>• `median`: N50 (Formula 2/3) [dB]<br>• `value`: NIPTS at `fractile` (Formula 4/5) [dB]<br>• `spread_upper` / `spread_lower`: du/dl [dB]<br>• `.plot()` | `n.median, n.value` |
| `HtlanResult` | `dataclass` | **Combined HTLAN result.**<br>• `age`, `sex`, `l_ex`, `years`, `fractile`<br>• `frequencies` [Hz]<br>• `htla`: age component H [dB]<br>• `nipts`: noise component N [dB]<br>• `threshold`: combined H′ [dB]<br>• `.plot()` | `h.htla, h.nipts, h.threshold` |
| `combine_age_and_noise` | `function` | **Age and noise components combined, H′ = H + N − HN/120 (ISO 1999 Formula 1).**<br>• `htla`: age-associated threshold H [dB]<br>• `nipts_value`: noise-induced shift N [dB]<br>• both taken at the same population percentage; exposed for the user-supplied database B of clause 6.2.3 | `combine_age_and_noise(36.0, 19.0)  # 49.3`<br><br>• ISO 1999 Annex C: 19 − 36·19/120 = 13.3 dB of shift remains |
| `NoiseInducedHearingLossWarning` | `warning class` | **ISO 1999 domain advisory.**<br>Emitted outside the validated domain: exposure duration beyond 1–40 yr (§6.3.1), fractile in the tails ISO calls unreliable (Q &lt; 5 % or &gt; 95 %, §6.3.2), or LEX,8h above the 100 dB of Annex D | `warnings.simplefilter('error', NoiseInducedHearingLossWarning)` |
| `predicted_prominence` | `function` | **Predicted prominence P of an impulse (NT ACOU 112 Formula 1).**<br>• `onset_rate`: slope of the A/F level onset [dB/s] (> 0; qualifies above 10 dB/s)<br>• `level_difference`: level rise over the onset [dB] (> 0) | `predicted_prominence(50.0, 20.0)  # 7.7`<br><br>• P = 3 lg(rate) + 2 lg(diff) |
| `impulse_adjustment` | `function` | **LAeq adjustment KI (Formula 2).**<br>• `prominence`: P | `impulse_adjustment(7.7)  # 4.86`<br><br>• 1.8(P − 5) dB for P > 5, else 0 |
| `impulse_prominence` | `function` | **Governing prominence and adjustment of a set of impulses (clauses 7–8); only onset rates > 10 dB/s qualify (clause 4.5).**<br>• `onset_rates` [dB/s]<br>• `level_differences` [dB] | `r = environment.impulse_prominence([50, 120], [20, 15])`<br><br>• `ImpulseProminenceResult` (P = 8.59, KI = 6.46 dB) |
| `rating_level` | `function` | **Rating level LAr,T over a reference time (clause 8 Note 1).**<br>• `laeq`: LAeq,N per sub-interval [dB]<br>• `adjustment`: KI,N per sub-interval [dB]<br>• `durations`, `reference_time`: same time unit | `rating_level([55, 60], [0, 4.9], [20, 10], 30)  # 60.9` |
| `ImpulseProminenceResult` | `dataclass` | **Impulse-prominence verdict.**<br>• `onset_rates` [dB/s], `level_differences` [dB]<br>• `per_impulse`: P of each impulse<br>• `qualifies`: onset rate > 10 dB/s mask (clause 4.5)<br>• `prominence`: governing (highest qualifying) P<br>• `adjustment`: KI of the governing qualifying impulse [dB] (0 when none qualifies)<br>• `.plot()`<br>• takes `onset_rates`, `level_differences`, `assessment_period_min`; `per_impulse`, `qualifies`, `prominence`, `adjustment` are read-only, read from them | `r.prominence, r.adjustment` |
| `ImpulseProminenceWarning` | `warning class` | **NT ACOU 112 advisory.**<br>Emitted when a supplied level rise does not qualify as an impulse (clause 4.5) | `warnings.simplefilter('error', ImpulseProminenceWarning)` |
| `impulsive_sound_adjustment` | `function` | **Objective impulsive-sound adjustment from a calibrated signal (ISO/PAS 1996-3:2022).**<br>• `signal`: sound pressure [Pa], `fs` [Hz]<br>• `dt`: LpAF sampling interval [s] (10–25 ms; Default 0.02)<br>• `onset_rate_method`: 'least_squares' or 'upper_half' pass-by variant<br>• `calibration_offset` [dB], `laeq` [dB] | `r = environment.impulsive_sound_adjustment(sig, fs)`<br><br>• `ImpulsiveSoundResult` (P, KI, category) |
| `sound_pressure_level_history` | `function` | **A-weighted, F time-weighted level history LpAF (ISO/PAS 1996-3 Clause 4).**<br>• `signal` [Pa], `fs` [Hz]<br>• `dt`: sampling interval [s] (10–25 ms; Default 0.02)<br>• `reference_pressure_pa` [Pa], `calibration_offset` [dB] | `t, lpaf = environment.sound_pressure_level_history(sig, fs)` |
| `detect_onsets` | `function` | **Detect LpAF onsets: start/end points, level difference and least-squares onset rate (ISO/PAS 1996-3 Clause 4, procedures a–d).**<br>• `levels`: LpAF [dB], `dt` [s]<br>• `onset_rate_method`: 'least_squares' / 'upper_half' | `onsets = environment.detect_onsets(lpaf, 0.02)` |
| `LevelHistory` | `dataclass` | **A frequency- and time-weighted level trace with its time axis.**<br>• `times` [s], `levels` [dB], `dt` [s]<br>• unpacks as `(times, levels)` for the callers that always did | `hist = environment.sound_pressure_level_history(sig)`<br>`hist.plot()`  # the L_pAF trace |
| `ImpulsiveSoundResult` | `dataclass` | **Objective impulsive-sound verdict (ISO/PAS 1996-3).**<br>• `times` [s], `levels`: LpAF [dB], `dt` [s]<br>• `onsets`: detected `ImpulseOnset`s<br>• `prominence`: governing P, `adjustment`: KI [dB]<br>• `category`: 'not impulsive' / 'regular impulsive' / 'highly impulsive'<br>• `laeq`, `adjusted_laeq` [dB]<br>• `.governing_onset`, `.plot()`<br>• takes `times`, `levels`, `dt`, `onsets`, `laeq`; `prominence`, `adjustment`, `category`, `adjusted_laeq` are read-only, read from them | `r.adjustment, r.category` |
| `ImpulseOnset` | `dataclass` | **A single detected LpAF onset (ISO/PAS 1996-3 Clause 3).**<br>• `index_start`/`index_end`, `time_start`/`time_end` [s]<br>• `level_start`/`level_end` [dB]<br>• `level_difference`: LD = Le − Ls [dB]<br>• `onset_rate`: OR [dB/s]<br>• `prominence`: P, `qualifies`: OR > 10 dB/s<br>• takes `index_start`, `index_end`, `time_start`, `time_end`, `level_start`, `level_end`, `onset_rate`; `level_difference`, `prominence`, `qualifies` are read-only, read from them | `o.onset_rate, o.level_difference` |
| `ImpulsiveSoundWarning` | `warning class` | **ISO/PAS 1996-3 advisory.**<br>Emitted when no onset with a gradient above 10 dB/s is found (adjustment is 0 dB) | `warnings.simplefilter('error', ImpulsiveSoundWarning)` |
| `frequency_weighted_sel` | `function` | **Frequency-weighted single-event sound exposure level from band levels (ISO 13474:2009 Equation (5)).**<br>• `band_levels_db`: band levels L_E(j) [dB] on the last axis; leading axes kept, so `(N_atm, N_exc, n_bands)` gives every replica at once<br>• `weighting_db`: weighting w(j) of each band [dB] (A, C or any other) | `environment.frequency_weighted_sel(bands_db, a_weighting_db)`<br><br>• 10 lg Σ 10^(0.1 (L_E(j) + w(j))) [dB] |
| `replica_probabilities` | `function` | **Probability of each replica atmosphere, the product of its two class probabilities (ISO 13474 Equation (14)).**<br>• `absorption_probabilities`: one per atmospheric-absorption class<br>• `excess_attenuation_probabilities`: one per excess-attenuation class | `p = environment.replica_probabilities([1.0], p_exc)`<br><br>• array `(N_atm, N_exc)` |
| `long_term_sel` | `function` | **Long-term average single-event sound exposure level (ISO 13474 Equation (7)), or the rating level with K (Equation (8)).**<br>• `levels_db`: L_E,w,k,l of each replica [dB], any shape<br>• `probabilities`: same shape, summing to one<br>• `rating_adjustment_db`: K for highly impulsive sound [dB] (Default: 0) | `environment.long_term_sel(levels_db, p)`<br><br>• Annex A LT1 = 37.0 dB |
| `turbulence_level_shift` | `function` | **Shift Δμ of each Gaussian subclass, σ² ln 10 / 20 (ISO 13474 Equation (22) in closed form).**<br>• `sigma_db`: standard deviation of the turbulent spread [dB] | `environment.turbulence_level_shift(5.0)  # 2.878`<br><br>• [dB] |
| `sel_distribution` | `function` | **Statistical distribution of the single-event sound exposure level (ISO 13474:2009 clause 5, Equations (10) to (25)).**<br>• `levels_db`: L_E,w of each replica atmosphere [dB], any shape<br>• `probabilities`: same shape, summing to one<br>• `sigma_db`: turbulent spread [dB] (Default: 5.0, the value clause 5 says is typical)<br>• `subclasses`: N_sub per class (Default: 10, as Annex A) | `d = environment.sel_distribution(levels_db, p)`<br><br>• `SelDistribution` |
| `SelDistribution` | `dataclass` | **The ISO 13474 distribution: sorted classes, their boundaries and densities, and the spread density.**<br>• `levels_db`, `probabilities`, `lower_bounds_db` / `upper_bounds_db` [dB], `class_densities_per_db` [1/dB] (Equations (10) to (15))<br>• `subclass_centres_db` [dB], `sigma_db`, `level_shift_db` [dB], `subclasses` (Equations (17) to (22))<br>• `long_term_level_db` (Equation (7), LT1) and `distribution_long_term_level_db` (Equation (A.4), LT2) [dB]<br>• `replicas`: the input replicas of each class<br>• `.class_density(x_db)`, `.density(x_db)`, `.exceedance(x_db)` (Equation (24)), `.exceedance_level(percent)` (Equation (25))<br>• `.plot(view='classes' / 'density' / 'exceedance')` | `d.exceedance_level(50.0)  # 31.5 dB`<br>`d.plot(view='exceedance')` |
| `PERCEIVED_AFFECTIVE_QUALITY_ATTRIBUTES` | `constant` | **The eight attributes of the perceived affective quality, part 2 of Method A (ISO/TS 12913-2 Figure C.4), in printed order.**<br>pleasant, chaotic, vibrant, uneventful, calm, annoying, eventful, monotonous: the variables p, ch, v, u, ca, a, e, m of ISO/TS 12913-3 Formulas (A.1) and (A.2) | `environment.PERCEIVED_AFFECTIVE_QUALITY_ATTRIBUTES[0]  # 'pleasant'` |
| `QuestionnaireScale` | `dataclass` | **One scale of the soundscape questionnaire as ISO/TS 12913-2 Annex C prints it (misprints included).**<br>• `method` (`"A"`/`"B"`), `part`, `figure`, `subject`<br>• `question`, `instruction`, `items`<br>• `categories`: left to right, `scale_values`: Table A.1 or B.1<br>• `continuous`: a mark anywhere on the scale (Method B) | `environment.METHOD_A_SCALES[2].categories[0]  # 'Strongly agree'` |
| `METHOD_A_SCALES` | `mapping` | **Method A of ISO/TS 12913-2 (C.3.1), part number to `QuestionnaireScale`.**<br>1: sound source identification (Figure C.2), 2: perceived affective quality (C.4), 3: assessment of the surrounding sound environment (C.5), 4: appropriateness (C.6); scale values of ISO/TS 12913-3 Table A.1 (parts 1 and 4 run 1 to 5 from the left, parts 2 and 3 run 5 to 1) | `environment.METHOD_A_SCALES[3].scale_values  # (5, 4, 3, 2, 1)` |
| `METHOD_A_ALTERNATIVE_PART_1` | `constant` | **Figure C.3 of ISO/TS 12913-2, the three-source alternative to Figure C.2 for part 1.**<br>A `QuestionnaireScale` with the categories and scale values of Figure C.2 | `environment.METHOD_A_ALTERNATIVE_PART_1.items[0]` |
| `METHOD_B_SCALES` | `constant` | **The four continuous-category scales of Figure C.7, part 1 of Method B (ISO/TS 12913-2 C.3.2.3).**<br>A tuple of `QuestionnaireScale`: loud, unpleasant, appropriate, visit again; scale value 1 at the left-hand tick to 5 at the right-hand one (Table B.1) | `environment.METHOD_B_SCALES[0].question  # 'How loud is it here?'` |
| `METHOD_B_MAXIMUM_SOURCES` | `constant` | **The most sound sources a participant may rank in part 2 of Method B (ISO/TS 12913-2 C.3.2.4).** | `environment.METHOD_B_MAXIMUM_SOURCES  # 8` |
| `PLEASANTNESS_EVENTFULNESS_RANGE` | `constant` | **Half-range of the coordinates of Formulas (A.1) and (A.2), 4 + √32 ≈ 9.66 (ISO/TS 12913-3 A.3).**<br>Dividing by it maps P and E to ±1 | `environment.PLEASANTNESS_EVENTFULNESS_RANGE  # 9.657` |
| `method_a_scale_values` | `function` | **Scale value of a ticked Method A box (ISO/TS 12913-3 Table A.1).**<br>• `positions`: box counted from the left, 1 to 5 (NaN for a blank)<br>• `part`: 1 to 4 (parts 2 and 3 run 5 to 1) | `environment.method_a_scale_values([1, 5], part=2)  # [5., 1.]` |
| `method_a_summary` | `function` | **Median and range of Method A scale values per site and item (ISO/TS 12913-3 A.2, Table A.1).**<br>• `scale_values`: mapping item to values, 1-D array (parts 3, 4) or `(responses, items)` array<br>• `part`: 1 to 4<br>• `sites`: site of each response (Default: one site `"all"`) | `s = environment.method_a_summary(values, part=2, sites=sites)`<br><br>• `MethodASummary` |
| `MethodASummary` | `dataclass` | **Ordinal statistics of Method A per site and item.**<br>• `part`, `items`, `sites`<br>• `medians`, `minima`, `maxima`, `ranges`, `counts`: shape `(sites, items)`<br>• `.plot()` | `s.medians[0], s.ranges[0]` |
| `pleasantness_eventfulness` | `function` | **Pleasantness P and eventfulness E per respondent and per site (ISO/TS 12913-3 A.3, Formulas (A.1) and (A.2)).**<br>• `scale_values`: the eight attributes of part 2, mapping or `(respondents, 8)` array, 5 = strongly agree<br>• `sites`: site of each respondent (Default: one site `"all"`)<br>• `central_tendency`: `"median"` (A.2) or `"mean"` of each attribute per site | `pe = environment.pleasantness_eventfulness(values, sites=sites)`<br><br>• `PleasantnessEventfulness` |
| `PleasantnessEventfulness` | `dataclass` | **The two soundscape dimensions of Figure A.1.**<br>• `sites`, `attribute_values`: per-site statistic of each attribute<br>• `pleasantness`, `eventfulness`: per site, in ±9.66<br>• `respondent_pleasantness`, `respondent_eventfulness`, `respondent_sites`, `respondent_counts`<br>• `.normalized_pleasantness`, `.normalized_eventfulness`: in ±1<br>• `.plot(normalized=True, respondents=False)`: the model of Figure A.1 | `pe.normalized_pleasantness`<br>`pe.plot(respondents=True)` |
| `spearman_rank_correlation` | `function` | **Spearman's rank correlation for ordinal data (ISO/TS 12913-3 A.4, Formula (A.3) untied, (A.4) tied).**<br>• `x`, `y`: paired values, at least three pairs<br>• `alternative`: `"two-sided"` (Default), `"greater"`, `"less"` | `c = environment.spearman_rank_correlation(site_p, laeq)`<br><br>• `SoundscapeCorrelation` with r and its p-value (Student t, n − 2 degrees of freedom) |
| `pearson_correlation` | `function` | **Pearson's correlation for interval data (ISO/TS 12913-3 B.3, Formulas (B.1) and (B.2), covariance over n).**<br>• `x`, `y`: paired values, at least three pairs<br>• `alternative`: `"two-sided"` (Default), `"greater"`, `"less"` | `c = environment.pearson_correlation(mean_rating, laeq)`<br><br>• `SoundscapeCorrelation` |
| `SoundscapeCorrelation` | `dataclass` | **A correlation coefficient with its probability value.**<br>• `method`: `"spearman"` / `"pearson"`, `formula`: `"(A.3)"`, `"(A.4)"` or `"(B.1)"`<br>• `coefficient`, `p_value`, `t_statistic`, `degrees_of_freedom`, `alternative`<br>• `x`, `y`, `x_ranks`, `y_ranks` (Spearman), `.n`<br>• `.plot()` | `c.coefficient, c.p_value` |
| `method_b_scale_values` | `function` | **Scale value of a mark on a Method B continuous-category scale, 1 + 4f to one decimal (ISO/TS 12913-3 B.2).**<br>• `marked_fraction`: position from the left-hand tick (0) to the right-hand one (1) | `environment.method_b_scale_values(0.62)  # 3.5` |
| `method_b_summary` | `function` | **Mean, standard deviation and confidence interval of Method B ratings per site (ISO/TS 12913-3 B.2, Table B.1).**<br>• `scale_values`: mapping scale to values, 1-D array or `(responses, scales)` array of the Figure C.7 scales<br>• `sites`: site of each response<br>• `confidence_level` (Default: 0.95) | `b = environment.method_b_summary(values, sites=sites)`<br><br>• `MethodBSummary` |
| `MethodBSummary` | `dataclass` | **Interval statistics of Method B per site and scale.**<br>• `items`, `sites`<br>• `means`, `standard_deviations` (n − 1), `confidence_lower` / `confidence_upper` (Student t), `medians`, `counts`<br>• `confidence_level`<br>• `.plot()` | `b.means[0], b.confidence_upper[0]` |
| `method_b_source_ranking` | `function` | **Median and range of the rank of each recognised sound source (ISO/TS 12913-3 B.2, ISO/TS 12913-2 C.3.2.4).**<br>• `rankings`: per participant, the sources listed, most noticeable first, at most eight<br>• `sites`: site of each participant | `r = environment.method_b_source_ranking([["traffic", "birds"], ["birds"]])`<br><br>• `SourceRanking` |
| `SourceRanking` | `dataclass` | **Ordinal statistics of the source ranking per site.**<br>• `sources`, `sites`, `participants`<br>• `median_ranks`, `lowest_ranks`, `highest_ranks`, `rank_ranges`, `mentions`: shape `(sites, sources)`<br>• `.plot()` | `r.sources, r.median_ranks[0]` |
| `SoundscapeParticipants` | `dataclass` | **ISO/TS 12913-2 A.2 a) to e): how the participants were selected, residents or visitors, lay or expert, age and gender distribution, other relevant information.**<br>Every item required; an empty one raises naming its clause | `environment.SoundscapeParticipants(selection="...", ...)` |
| `SoundscapeAcousticEnvironment` | `dataclass` | **ISO/TS 12913-2 A.3 a) to h): the studied acoustic environment.**<br>• `environment_type`: `"real"`, `"recorded"`, `"virtual"`<br>• `sound_sources`, `weather_and_wind`, `time_of_year_and_day`, `measurement_points`<br>• `measurement_results`: the seven results of A.3 f) by symbol (LAeq,T, LCeq,T, LAF5,T, LAF95,T, N5, N95, Nrmc)<br>• `site_description` (field or recorded), `recording_and_reproduction` (recorded or virtual) | `environment.SoundscapeAcousticEnvironment(..., measurement_results=bi.reporting_results())` |
| `SoundscapeDataCollection` | `dataclass` | **ISO/TS 12913-2 A.4 a) to e): how the perception data were collected.**<br>• `methods`, `questions`, `language`, `instrument_copy` (required)<br>• `rating_scale_construction`, `behaviour_observation` (when the study used them) | `environment.SoundscapeDataCollection(methods="...", ...)` |
| `SoundscapeReport` | `dataclass` | **The minimum reporting requirements of ISO/TS 12913-2 Annex A (normative), checked when built.**<br>• `participants` (A.2), `acoustic_environment` (A.3), `data_collection` (A.4) | `environment.SoundscapeReport(participants, environment_record, collection)` |
| `BINAURAL_PARAMETERS` | `mapping` | **ISO/TS 12913-3 Table D.1, row name to `BinauralParameter`.**<br>`"sound_pressure_level"`, `"loudness"`, `"sharpness"`, `"tonality"`, `"roughness"`, `"fluctuation_strength"` | `environment.BINAURAL_PARAMETERS["loudness"].metrics` |
| `BinauralParameter` | `dataclass` | **One row of Table D.1.**<br>• `parameter`, `metrics` (the printed symbols), `average_allowed`, `reference` | `environment.BINAURAL_PARAMETERS["roughness"].reference  # '[32]'` |
| `binaural_indicators` | `function` | **Every metric of ISO/TS 12913-3 Table D.1 at each ear, with the representative value of D.2.**<br>• `x`: equalized binaural recording `(2, samples)`, left first, or a two-channel `Signal`<br>• `fs` [Hz], `calibration_factor` (to Pa)<br>• `field`: `"free"` (Default) or `"diffuse"`<br>• `parameters`: rows of Table D.1 (Default: all)<br>• sharpness S5/Saverage/S95 reported as not implemented; recordings under 3 min or 44.1 kHz emit `SoundscapeWarning` | `bi = environment.binaural_indicators(x, 48000, parameters=("sound_pressure_level", "loudness"))`<br><br>• `BinauralIndicators` |
| `BinauralIndicators` | `dataclass` | **The binaural analysis of a recording.**<br>• `metrics`: symbol to `BinauralMetric`, in Table D.1 order<br>• `not_implemented`: symbol to the reason<br>• `parameters`, `fs` [Hz], `duration_s` [s], `field`<br>• `.representative(symbol)`, `.reporting_results()` (ISO/TS 12913-2 A.3 f))<br>• `.plot(parameter=None)` | `bi.representative("LAeq,T")`<br>`bi.plot(parameter="loudness")` |
| `BinauralMetric` | `dataclass` | **One metric at both ears.**<br>• `symbol`, `parameter`, `left`, `right`, `unit`, `method`<br>• `.representative`: the higher ear (D.2), `.mean`: their average | `bi.metrics["N5"].representative` |
| `SoundscapeWarning` | `warning class` | **ISO/TS 12913-2 Annex D advisory.**<br>Emitted for a recording shorter than the 3 min of D.3 or sampled below the 44.1 kHz of D.6 | `warnings.simplefilter('error', SoundscapeWarning)` |
| `multiple_shock_assessment` | `function` | **Full multiple-shock assessment from seat acceleration (ISO 2631-5:2018).**<br>• `acceleration`: vertical seat az(t) [m/s²], `fs` [Hz]<br>• `start_age`: years, `years`: exposure years, `days_per_year`<br>• `exposure_time` / `measurement_time`: scale Dz to a daily dose (Default: None)<br>• `sex`: 'male'/'female' (Default: 'male')<br>• `mz`: MPa per m/s² (Default: sex-specific) | `res = vibration.multiple_shock_assessment(az, fs, start_age=25, years=30, days_per_year=220)`<br><br>• `MultipleShockResult` |
| `seat_to_spine_transfer` | `function` | **Seat-to-spine transfer function H(ω) (clause 5.2 Formula 1).**<br>• `frequencies` [Hz] | `H = vibration.seat_to_spine_transfer(freqs)`<br><br>• Complex response; unity at 0 Hz |
| `spinal_response` | `function` | **Vertical spinal response Az(t) (Formula 2).**<br>• `acceleration`: seat az(t) [m/s²]<br>• `fs` [Hz] | `Az = vibration.spinal_response(az, fs)`<br><br>• Same length as the input [m/s²] |
| `response_peaks` | `function` | **Positive response peaks Az,i (clause 5.3).**<br>• `response`: Az(t) | `peaks = vibration.response_peaks(Az)`<br><br>• Maxima between zero crossings [m/s²] |
| `dose_from_peaks` | `function` | **Acceleration dose Dz from peaks (Formula 3).**<br>• `peaks`: Az,i [m/s²] | `dz = vibration.dose_from_peaks(peaks)`<br><br>• Dz = 1.07 (Σ Az,i⁶)^(1/6) [m/s²] |
| `acceleration_dose` | `function` | **Acceleration dose Dz from a time history (Formulas 2 + 3).**<br>• `acceleration`: seat az(t) [m/s²], `fs` [Hz] | `dz = vibration.acceleration_dose(az, fs)`<br><br>• Dz [m/s²] |
| `daily_dose` | `function` | **Daily dose Dzd (Formula 4).**<br>• `dose`: Dz [m/s²]<br>• `exposure_time` td / `measurement_time` tm: same unit | `daily_dose(4.0, 8.0, 2.0)  # 5.04`<br><br>• Dz (td/tm)^(1/6) [m/s²] |
| `daily_dose_multi` | `function` | **Daily dose from several exposure conditions (Formula 5).**<br>• `doses`: Dz,j [m/s²]<br>• `exposure_times` / `measurement_times`: per condition | `dzd = vibration.daily_dose_multi(dz, td, tm)`<br><br>• [Σ Dz,j⁶ (td,j/tm,j)]^(1/6) [m/s²] |
| `compression_dose` | `function` | **Daily compressive stress Sd (Annex C Formula C.1).**<br>• `daily_dose_value`: Dzd [m/s²]<br>• `mz`: MPa per m/s² (Default: 0.029, 82 kg male) | `compression_dose(5.0)  # 0.145`<br><br>• Sd = mz·Dzd [MPa] |
| `static_stress` | `function` | **Static compressive stress Sstat = mz·9.81 (Annex C).**<br>• `mz` (Default: 0.029) | `static_stress()  # 0.284`<br><br>• [MPa] |
| `ultimate_strength` | `function` | **Ultimate lumbar strength Su at an age (Formula C.4).**<br>• `age`: years<br>• `sex`: 'male'/'female' (Default: 'male') | `ultimate_strength(45.0)  # 4.41`<br><br>• 6.75 − Sage·age [MPa] |
| `injury_risk` | `function` | **Cumulative injury stress variable R (Formula C.3).**<br>• `daily_compression`: Sd [MPa]<br>• `start_age`, `years`, `days_per_year`<br>• `sex`, `mz` | `R = vibration.injury_risk(0.5, start_age=25, years=30, days_per_year=220)  # 0.509` |
| `injury_probability` | `function` | **Probability of lumbar injury P(R) (Formula C.5, Weibull).**<br>• `risk`: R<br>• `sex` (Default: 'male') | `injury_probability(0.509)  # 0.0389`<br><br>• 1 − exp(−(R/α)^β) in 0–1 |
| `MultipleShockResult` | `dataclass` | **Multiple-shock health assessment.**<br>• `acceleration_dose` Dz, `daily_dose` Dzd [m/s²]<br>• `compression_dose` Sd [MPa]<br>• `risk` R, `probability` P(R)<br>• `sex`, `start_age`, `years`, `days_per_year`<br>• `peaks` [m/s²], `risk_thresholds`: R at 10/50/90 % (Table C.2)<br>• `.plot()` | `res.risk, res.probability` |
| `object_fraction` | `function` | **Object fraction ψ of an enclosed space (EN 12354-6 Formula 3).**<br>• `object_volumes` [m³]<br>• `volume`: empty space V [m³] | `object_fraction([12.0, 8.0], 500.0)  # 0.04` |
| `hard_object_absorption` | `function` | **Equivalent absorption area of a hard object (Formula 4).**<br>• `object_volume`: Vobj [m³] | `hard_object_absorption(8.0)  # 4.0`<br><br>• Aobj = Vobj^(2/3) [m²] |
| `air_absorption_area` | `function` | **Equivalent absorption area of the air (Formula 2).**<br>• `m`: power attenuation of air [Np/m]<br>• `volume` V [m³]<br>• `object_fraction` ψ (Default: 0.0) | `air_absorption_area(0.001, 500.0)  # 2.0`<br><br>• Aair = 4mV(1 − ψ) [m²] |
| `equivalent_absorption_area` | `function` | **Total equivalent sound absorption area (Formula 1).**<br>• `surfaces`: sequence of (area, absorption_coefficient) pairs (coefficient scalar or per band)<br>• `objects`: object areas Aobj [m²] (Default: ())<br>• `air_area`: Aair [m²] (Default: 0.0) | `A = room.equivalent_absorption_area([(100.0, 0.03), (50.0, 0.6)], objects=[4.0], air_area=2.0)  # 39.0` |
| `reverberation_time` | `function` | **Reverberation time from the absorption area (Formula 5).**<br>• `absorption_area` A [m²]<br>• `volume` V [m³]<br>• `object_fraction` ψ (Default: 0.0)<br>• `speed_of_sound` c0 [m/s] (Default: 345.6 → factor 0.16) | `reverberation_time(39.0, 500.0)  # 2.05`<br><br>• T = 55.3/c0 · V(1 − ψ)/A [s] |
| `enclosed_space_reverberation` | `function` | **Predicted A and T per octave band (EN 12354-6 Clause 4).**<br>• `surfaces`: (area, per-band α) pairs<br>• `volume` V [m³]<br>• `objects` [m²], `object_fraction` ψ<br>• `air_condition`: air-attenuation key, e.g. '20C_50-70' (Default: None → neglect air)<br>• `frequencies` [Hz] (Default: 125–8000 Hz octaves)<br>• `speed_of_sound` [m/s] | `res = room.enclosed_space_reverberation(surfaces, 500.0, air_condition="20C_50-70")`<br><br>• `ReverberationResult` |
| `ReverberationResult` | `dataclass` | **Enclosed-space absorption result.**<br>• `frequencies` [Hz]<br>• `absorption_area`: A per band [m²]<br>• `reverberation_time`: T per band [s]<br>• `volume` [m³], `object_fraction`<br>• `.plot()` | `res.absorption_area, res.reverberation_time` |
| `sabine_reverberation_time` / `eyring_reverberation_time` / `millington_sette_reverberation_time` | `function` | **Statistical RT prediction (T = k·V/(term + 4mV), k = 24 ln10 / c0).**<br>• `volume` V [m³]<br>• `surfaces`: (area, α) pairs (α scalar or per band)<br>• `air_attenuation`: m [Np/m] (Default: 0.0; see `air_attenuation_m`)<br>• `speed_of_sound` (Default: 343 → k = 0.161)<br>Term: Sabine ΣSᵢαᵢ · Eyring −S·ln(1−ᾱ) · Millington −ΣSᵢln(1−αᵢ) | `eyring_reverberation_time(120.0, [(40,0.2),(40,0.2),(24,0.2),(24,0.2),(15,0.2),(15,0.2)])  # 0.548 s` |
| `fitzroy_reverberation_time` / `arau_puchades_reverberation_time` | `function` | **Anisotropic RT prediction for a shoebox room.**<br>• `dimensions`: (Lx, Ly, Lz) [m]<br>• `absorptions`: mean α of the (x, y, z) wall pairs (scalar or per band)<br>• `air_attenuation` [Np/m], `speed_of_sound`<br>Fitzroy = area-weighted arithmetic mean of the three axial Eyring times; Arau-Puchades = geometric mean (Acustica 65, 1988) | `arau_puchades_reverberation_time((8,5,3), (0.5,0.1,0.1))  # 0.812 s` |
| `mean_absorption` | `function` | **Area-weighted mean absorption ᾱ = ΣSᵢαᵢ / ΣSᵢ.**<br>• `surfaces`: (area, α) pairs | `mean_absorption([(90.0, 0.1), (10.0, 0.9)])  # 0.18` |
| `reverberation_time_models` | `function` | **All five RT models for a shoebox room, per band.**<br>• `dimensions` (Lx, Ly, Lz) [m]<br>• `absorptions`: (αx, αy, αz) wall-pair means (scalar or per band)<br>• `air_attenuation` [Np/m], `frequencies` [Hz], `speed_of_sound` | `res = room.reverberation_time_models((10,7,3.5), (ax, ay, az), frequencies=f)`<br><br>• `ReverberationModelResult` |
| `ReverberationModelResult` | `dataclass` | **Five-model RT comparison.**<br>• `frequencies` [Hz]<br>• `sabine`/`eyring`/`millington_sette`/`fitzroy`/`arau_puchades`: T per band [s]<br>• `volume` [m³], `surface_area` [m²]<br>• `.models`: dict keyed by name<br>• `.plot()` | `res.arau_puchades, res.models['Fitzroy']` |
| `apparent_dynamic_stiffness` | `function` | **Apparent dynamic stiffness s't (EN 29052-1 Formula 4).**<br>• `resonant_frequency_hz` fr [Hz] (scalar/array)<br>• `total_mass_per_area_kg_m2` m't [kg/m²]<br>s't = 4π²·m't·fr² [N/m³] | `apparent_dynamic_stiffness(25.0, 200.0)  # 4.935e6 N/m³` |
| `plot_dynamic_stiffness_rig` | `function` | **Resonance rig to scale.**<br>• `specimen_side` (Default: 0.2 m), `specimen_thickness` (Default: 0.02 m)<br>• `load_mass` (Default: 8 kg)<br>• `language` | `plot_dynamic_stiffness_rig()` |
| `enclosed_gas_stiffness` | `function` | **Enclosed-gas dynamic stiffness s'a (EN 29052-1 Formula 7).**<br>• `thickness_m` d [m]<br>• `porosity` ε (0-1)<br>• `atmospheric_pressure_pa` p₀ [Pa] (Default: 1e5 = 0,1 MPa)<br>s'a = p₀/(d·ε); NOTE ≈ 111/d MN/m³ (d in mm) | `enclosed_gas_stiffness(0.020, 0.9)  # 5.56e6 N/m³` |
| `installed_dynamic_stiffness` | `function` | **Installed s' by airflow resistivity (EN 29052-1 clause 8.2).**<br>• `apparent_stiffness_n_m3` s't [N/m³]<br>• `airflow_resistivity_kpa_s_m2` r [kPa·s/m²], by name only<br>• `gas_stiffness_n_m3` s'a [N/m³] (Default: None; required below r = 100)<br>r≥100 → s't · 10≤r<100 → s't+s'a · r<10 → s't if s'a negligible else nan (warns) | `installed_dynamic_stiffness(20e6, airflow_resistivity_kpa_s_m2=50.0, gas_stiffness_n_m3=3e6)  # 23e6` |
| `natural_frequency` | `function` | **Floating-floor natural frequency f0 (EN 29052-1 Formula 2).**<br>• `dynamic_stiffness_n_m3` s' of the installed layer [N/m³] (scalar/array)<br>• `mass_per_area_kg_m2` m' [kg/m²]<br>f0 = (1/2π)√(s'/m') | `natural_frequency(10e6, 120.0)  # 45.9 Hz` |
| `floating_floor_resonance` | `function` | **Full EN 29052-1 chain → result.**<br>• `resonant_frequency_hz`, `total_mass_per_area_kg_m2`, `floor_mass_per_area_kg_m2`<br>• `airflow_resistivity_kpa_s_m2` (Default: inf), `thickness_m`, `porosity`, `atmospheric_pressure_pa` | `res = materials.floating_floor_resonance(25.0, 200.0, 120.0)`<br><br>• `DynamicStiffnessResult` |
| `ResilientLayer` / `PUBLISHED_RESILIENT_LAYERS` / `resilient_layer` | `dataclass` / `mapping` / `function` | **A resilient layer as a catalogue row, and the fifteen of Hopkins Table A3 (printed p. 610).**<br>• keyed `'<table>/<row>'`: `'hopkins-2007-table-a3/<material>_<density>_<thickness>'`, e.g. `'hopkins-2007-table-a3/mineral_wool_rock_60_30'`<br>• optional `dynamic_stiffness_n_m3` s′ of the installed layer and `apparent_dynamic_stiffness_n_m3` s′t of the test specimen [N/m³], `density_kg_m3`, `thickness_mm`, plus every hedge of `CatalogueRow`; Table A3 prints s′ and fills only the first<br>• `.natural_frequency(mass_per_area_kg_m2, *, airflow_resistivity_pa_s_m2=None, gas_stiffness_n_m3=None)` → f₀ [Hz] (Formula 2); a row with only s′t needs r [Pa·s/m²] and, below 100 kPa·s/m², s′a, and goes through clause 8.2; without r it raises `CatalogueError`<br>• Measured specimens, not declared product values: design with the manufacturer's s′ to EN 29052-1 | `layer = materials.resilient_layer('hopkins-2007-table-a3/mineral_wool_rock_60_30')`<br>`layer.natural_frequency(mass_per_area_kg_m2=100.0)  # 50.3 Hz` |
| `ResilientMaterial` | `dataclass` | **One resilient material's dynamic modulus, as a page printed it.**<br>• `dynamic_youngs_modulus_pa` [Pa], `density_kg_m3` [kg/m³], `static_load_pa` [Pa] (about 2 kPa, the load it was measured under)<br>• printed as ranges, held in `ranges`; a layer's `s'` is the modulus over its thickness | `rock = materials.resilient_moduli_named('rock wool')[0]`<br>`rock.ranges['dynamic_youngs_modulus_pa']  # (270000.0, 330000.0)`<br><br>• `PUBLISHED_RESILIENT_MODULI`, `resilient_moduli_named` |
| `PUBLISHED_RESILIENT_MODULI` | `mapping` | **Six resilient materials' dynamic moduli, keyed `'<table>/<row>'`.**<br>• Vigran (2008) **Table 8.3** (PDF page 339): glass wool, two rock wools, polystyrene and polyurethane foam, cork<br>• the modulus rises with the static load, by about 30 % from 2 to 4 kPa for rock wool, so it describes a layer under that load | `len(materials.PUBLISHED_RESILIENT_MODULI)  # 6`<br><br>• `ResilientMaterial`, `resilient_moduli_named` |
| `resilient_moduli_named` | `function` | **Every resilient material whose name contains the text.**<br>• `name`: matched without case; `'rock wool'` answers with both rock wools, which only their densities tell apart<br>• empty when nothing matches<br>• `catalogue=`: the rows to search instead of `PUBLISHED_RESILIENT_MODULI`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_RESILIENT_MODULI \| mine`; a row of another class is refused by its key (`TypeError`) | `len(materials.resilient_moduli_named('rock wool'))  # 2`<br><br>• `PUBLISHED_RESILIENT_MODULI` |
| `DynamicStiffnessResult` | `dataclass` | **Dynamic-stiffness measurement result.**<br>• `apparent_stiffness`/`gas_stiffness`/`dynamic_stiffness` [N/m³]<br>• `resonant_frequency` [Hz], `floor_mass_per_area` [kg/m²]<br>• `natural_frequency` [Hz]<br>• `.plot()` | `res.dynamic_stiffness, res.natural_frequency` |
| `DynamicStiffnessWarning` | `warning class` | **EN 29052-1 advisory.**<br>Emitted when the enclosed-gas term makes s′ unresolvable (clause 8.2) | `warnings.simplefilter('error', DynamicStiffnessWarning)` |
| `convert_frf` | `function` | **Convert between any two FRFs (ISO 7626-1 Table 1).**<br>• `value`: complex FRF value(s) of kind *source*<br>• `frequency` f [Hz] (scalar/array, broadcast)<br>• `source`/`target`: `receptance`/`mobility`/`accelerance`/`dynamic_stiffness`/`impedance`/`apparent_mass`<br>Pivots through the receptance H | `convert_frf(2e-3, 80.0, "mobility", "impedance")  # 500 N.s/m` |
| `FRF_UNITS` | `mapping` | **SI unit per FRF form (ISO 7626-1 Table 1, read-only).**<br>Keyed by `'receptance'`, `'mobility'`, `'accelerance'`, ... | `FRF_UNITS['mobility']  # 'm/(N·s)'` |
| `sdof_receptance` / `sdof_mobility` / `sdof_accelerance` | `function` | **Closed-form SDOF resonator FRFs (ISO 7626-1 Table 1 / 3.1.2 definitions).**<br>• `frequency` f [Hz] (scalar/array)<br>• `mass` m [kg], `stiffness` k [N/m], `damping` c [N·s/m]<br>H = 1/(k − ω²m + jωc); Y = jωH; A = −ω²H | `sdof_mobility(10.07, 2.0, 8000.0, 5.0)  # |Y|=1/c on resonance` |
| `resonance_frequency` | `function` | **Undamped SDOF natural frequency (closed form).**<br>• `mass` m [kg], `stiffness` k [N/m]<br>f0 = (1/2π)√(k/m) | `resonance_frequency(2.0, 8000.0)  # 10.07 Hz` |
| `rigid_mass_calibration_check` | `function` | **Operational rigid-mass calibration (ISO 7626-2 7.5.2).**<br>• `frf`: measured FRF (complex or magnitude)<br>• `frequencies` [Hz], `mass` m [kg]<br>• `quantity`: 'accelerance' (\|A\| = 1/m) / 'mobility' (\|Y\| = 1/(ωm))<br>• the ±5 % of 7.5.2 is fixed and read as `.tolerance` | `res = vibration.rigid_mass_calibration_check(frf, f, 10.0)`<br><br>• `RigidMassCalibrationResult` |
| `RigidMassCalibrationResult` | `dataclass` | **Rigid-mass calibration verdict (ISO 7626-2 7.5.2).**<br>• `frequencies` [Hz], `measured`/`expected`/`deviation` per band<br>• `within_tolerance`: per-band flags, `passes`: overall<br>• `mass` [kg], `quantity`, `tolerance` | `res.passes, res.deviation` |
| `random_error_percent` | `function` | **Normalized random error of an averaged FRF (ISO 7626-2 Annex A).**<br>• `coherence`: γ² per frequency, in (0, 1]<br>• `n_averages`: n ≥ 1<br>ε = √((1−γ²)/(2nγ²)) [%]; 8.1.3 requires < 5 % at resonances | `random_error_percent(0.8, 75)  # 4.08 %` |
| `sdof_mobility_result` | `function` | **SDOF driving-point mobility → result.**<br>• `frequency` f [Hz] (array)<br>• `mass`, `stiffness`, `damping` | `res = vibration.sdof_mobility_result(f, 2.0, 8000.0, 5.0)`<br><br>• `MobilityResult` |
| `MobilityResult` | `dataclass` | **Mobility FRF over frequency (ISO 7626-1).**<br>• `frequencies` [Hz], `mobility` Y [m/(N·s)]<br>• `driving_point`: bool (i = j)<br>• `.magnitude` / `.phase`<br>• `.to(target)`: any Table-1 kind<br>• `.plot()`: |Y(f)| with the resonance marked | `res.magnitude, res.to("impedance")` |
| `impact_mobility` | `function` | **Mobility from impact records, averaged over impacts (ISO 7626-5 8.6).**<br>• `force` [N], `response` [m/s², m/s or m]: one record, or one per row<br>• `fs` [Hz], `response_quantity`: 'acceleration' / 'velocity' / 'displacement' (Default: 'acceleration')<br>• `force_window_s`, `force_window_start_s`, `force_window_taper_s` [s] (Default: no force window)<br>• `exponential_decay_rate_per_s` a [1/s] (Default: 0), `exponential_on_force` (Default: True, Formula (A.2))<br>H = ΣXF\*/Σ\|F\|², γ² = \|ΣXF\*\|²/(Σ\|F\|²·Σ\|X\|²); warns (`ImpactExcitationWarning`) when the force window removes an impact (6.4) | `res = vibration.impact_mobility(forces, accels, 4096.0, exponential_decay_rate_per_s=20.0)`<br><br>• `ImpactMobilityResult` |
| `ImpactMobilityResult` | `dataclass` | **Mobility averaged over impacts at one point (ISO 7626-5).**<br>• `frequencies` [Hz], `mobility` Y [m/(N·s)] as measured (window included), `coherence` γ², `force_energy_spectral_density` G_FF [N²·s/Hz]<br>• `impacts`, `exponential_decay_rate_per_s`, `response_quantity`, `driving_point`<br>• `.magnitude` / `.phase` / `.to(target)` / `.mobility_result`<br>• `.fit_mode(band_hz)`: the mode in a band, knowing the window<br>• `.plot()`: \|Y(f)\| over γ²; `.report()`: the ISO 7626 fiche, naming ISO 7626-5 | `res.fit_mode((30.0, 50.0)).correction.damping_ratio` |
| `force_window` / `exponential_window` / `exponential_decay_rate` | `function` | **The windows of 8.5.**<br>• `force_window(n_samples, fs, *, width_s, start_s=0, taper_s=0)`: unity over the pulse, exactly zero elsewhere (8.5.1); the half-cosine taper lies outside the unity part<br>• `exponential_window(n_samples, fs, *, decay_rate_per_s)`: e^(−at) from unity at the start of the record (8.5.2)<br>• `exponential_decay_rate(n_samples, fs, *, final_value)`: a = −ln(w_end)·fs/(N − 1), the rate that ends the record at `final_value` | `vibration.exponential_decay_rate(4096, 4096.0, final_value=0.05)  # 2.996 1/s` |
| `energy_spectral_density` | `function` | **One-sided energy spectral density of a transient (ISO 7626-5 3.3, 3.4).**<br>• `record` (1-D), `fs` [Hz]<br>G = 2\|X(f)\|², X the DFT scaled by Δt; DC and Nyquist not doubled [unit²·s/Hz] | `f, g = vibration.energy_spectral_density(force, 4096.0)` |
| `single_mode_fit` | `function` | **One mode fitted over a band: the damping estimate Annex A needs.**<br>• `frequencies` [Hz], `frf` (complex), `band_hz` (f_low, f_high), by name only<br>• `kind`: 'accelerance' / 'mobility' / 'receptance' (Default: 'mobility'); `exponential_decay_rate_per_s` [1/s] (Default: 0)<br>(b₀ + b₁s + b₂s²)/(s² + a₁s + a₀), reweighted (Sanathanan-Koerner); exact for a single-degree-of-freedom structure | `fit = vibration.single_mode_fit(f, y, band_hz=(30.0, 50.0))`<br><br>• `SingleModeFitResult` |
| `SingleModeFitResult` | `dataclass` | **One fitted mode: pole, residue and a direct term.**<br>• `frequencies`, `frf`, `pole_rad_s` p = −σ̂ + jω_d, `residue`, `direct_term`, `kind`, `exponential_decay_rate_per_s`<br>• `.damped_natural_frequency_hz`, `.apparent_damping_ratio` ζ̂<br>• `.correction`: its `ExponentialWindowCorrection`<br>• `.fitted_frf(f)`, `.corrected_frf(f)` (the pole moved back by a), `.corrected_mobility(f)`<br>• `.plot()` | `fit.corrected_mobility(f)` |
| `exponential_window_correction` | `function` | **The window's damping taken away (ISO 7626-5 Formula (A.3)).**<br>• `damped_natural_frequency_hz` f_r [Hz], `apparent_damping_ratio` ζ̂_r, per mode<br>• `exponential_decay_rate_per_s` a [1/s], by name only<br>ζ_r = ζ̂_r − a/ω_r; the peak is multiplied by ζ̂_r/ζ_r; refuses a/ω_r ≥ ζ̂_r | `vibration.exponential_window_correction(40.0, 0.03, exponential_decay_rate_per_s=5.0).damping_ratio  # [0.0101]`<br><br>• `ExponentialWindowCorrection` |
| `ExponentialWindowCorrection` | `dataclass` | **An Annex A correction, mode by mode.**<br>• `damped_natural_frequency_hz` [Hz], `apparent_damping_ratio`, `exponential_decay_rate_per_s` [1/s]<br>• `.window_damping_ratio` a/ω_r, `.damping_ratio` (A.3), `.peak_correction_factor` ζ̂/ζ<br>• `.exact_damping_ratio`: the pole moved back by a; (A.3) is its first order and differs by about (ζ̂³ − ζ³)/2<br>• `.plot()` | `correction.peak_correction_factor` |
| `check_double_hit` | `function` | **One impact in the record, or a double hit? (ISO 7626-5 6.4).**<br>• `force`: one unwindowed record [N], `fs` [Hz]<br>• `threshold_ratio`: the fraction of the largest force an excursion must exceed to count (Default: 0.1, the library's: a missed second pulse of the same shape ripples the spectrum by 1.74 dB at most, a softer and longer rebound by more; run it on the unfiltered force, since a steep anti-aliasing filter can ring above the threshold) | `vibration.check_double_hit(force, 4096.0).passes`<br><br>• `DoubleHitCheck` |
| `DoubleHitCheck` | `dataclass` | **The impacts in a force record (6.4, Figure 5).**<br>• `force`, `fs`, `impact_indices`, `threshold_ratio`<br>• `.impacts`, `.impact_times_s`, `.impact_peaks`, `.secondary_ratio` r, `.delay_s` τ, `.notch_spacing_hz` 1/τ, `.ripple_db` 20 lg[(1 + r)/(1 − r)]<br>• `.passes`: a single impact; no truth value<br>• `.plot()` | `check.notch_spacing_hz` |
| `check_force_spectrum` | `function` | **Does the force spectrum cover the frequency range of interest? (ISO 7626-5 6.2, 6.3).**<br>• `force` [N], `fs` [Hz], `frequency_range_hz` (f_low, f_high)<br>• `max_drop_db` [dB], required: the part prints no limit<br>The fall of G_FF from its highest to its lowest value inside the range | `vibration.check_force_spectrum(force, 4096.0, frequency_range_hz=(0.0, 400.0), max_drop_db=10.0).drop_db`<br><br>• `ForceSpectrumCheck` |
| `ForceSpectrumCheck` | `dataclass` | **A force spectrum against the caller's limit.**<br>• `frequencies` [Hz], `energy_spectral_density` [N²·s/Hz], `frequency_range_hz`, `max_drop_db`<br>• `.drop_db`, `.level_db`, `.energy_fraction_above` (6.3), `.passes`; no truth value<br>• `.plot()` | `check.energy_fraction_above` |
| `check_overload` | `function` | **Did the channel stay inside its linear range? (ISO 7626-5 8.4).**<br>• `record` (1-D), `fs` [Hz], `full_scale`: the maximum for linear operation, in the record's unit<br>Passes when every sample stays below full scale; a filtered record can hide saturation, so pass the widest band available | `vibration.check_overload(accel, 4096.0, full_scale=50.0).headroom_db`<br><br>• `OverloadCheck` |
| `OverloadCheck` | `dataclass` | **A record against its full scale (8.4).**<br>• `record`, `fs`, `full_scale`<br>• `.peak`, `.clipped_samples`, `.headroom_db`, `.passes`; no truth value<br>• `.plot()` | `check.clipped_samples` |
| `check_response_decay` | `function` | **Has the response decayed enough within the record? (ISO 7626-5 8.3, 8.5.2).**<br>• `response`: one unwindowed record, `fs` [Hz]<br>• `exponential_window` (Default: False): the end limit is 1 % without one and 25 % with one, compared to a whole per cent<br>• `segment_s` [s] (Default: a tenth of the record), `start_s` [s] (Default: 0)<br>• `force` (Default: None): the force record of the impact; the highest peak is then sought after the pulse, leaving the mass line out | `vibration.check_response_decay(accel, 4096.0, force=force).end_ratio`<br><br>• `ResponseDecayCheck` |
| `ResponseDecayCheck` | `dataclass` | **The decay a record reached (8.3, 8.5.2).**<br>• `record`, `fs`, `segment_s`, `exponential_window`, `start_s`<br>• `.peak`, `.peak_time_s`, `.end_ratio` (the level at the last sample), `.last_segment_ratio`, `.midpoint_ratio` (the 10 % check of 8.5.2), `.limit_ratio`, `.passes`; no truth value<br>• `.plot()` | `check.midpoint_ratio` |
| `check_coherence` | `function` | **Is the coherence high, over enough impacts? (ISO 7626-5 9.1).**<br>• `result`: an `ImpactMobilityResult`, `frequency_range_hz` (f_low, f_high)<br>• `exclude_hz`: bands left out of the verdict, such as anti-resonances (9.1 NOTE 1)<br>• `minimum_coherence` (Default: 0.9, to be exceeded), `minimum_records` (Default: 5, the fewest records 9.1 trusts a high coherence from) | `vibration.check_coherence(res, frequency_range_hz=(10.0, 400.0)).passes`<br><br>• `CoherenceCheck` |
| `CoherenceCheck` | `dataclass` | **The coherence against 9.1.**<br>• `frequencies` [Hz], `coherence`, `judged`, `impacts`, `minimum_coherence`, `minimum_records`<br>• `.high`, `.enough_records`, `.random_error_percent` (ISO 7626-2 Annex A), `.passes`; no truth value<br>• `.plot()` | `check.random_error_percent` |
| `verify_channel_match` | `function` | **Do two analyser channels match in gain and phase? (ISO 7626-5 8.1).**<br>• `frequencies` [Hz], `response`: complex response between two channels fed one broad-band signal<br>• `frequency_range_hz` (f_low, f_high)<br>\|H\| within ±5 % of unity and its phase within ±5°, bounds included | `vibration.verify_channel_match(f, h, frequency_range_hz=(10.0, 1000.0)).passes`<br><br>• `ChannelMatchVerification` |
| `ChannelMatchVerification` | `dataclass` | **Channel-to-channel gain and phase match (8.1).**<br>• `frequencies` [Hz], `response`<br>• `.magnitude_deviation`, `.phase_deg`, `.magnitude_within`, `.phase_within`, `.passes`; no truth value<br>• `.plot()` | `verification.phase_deg` |
| `RESPONSE_END_RATIO` / `RESPONSE_MIDPOINT_RATIO` / `WINDOWED_RESPONSE_END_RATIO` | `constant` | **The decay of ISO 7626-5 8.3 and 8.5.2.**<br>0.01 at the end of the record without a window; 0.1 at its midpoint (the convenient check); 0.25 of natural decay before an exponential window | `WINDOWED_RESPONSE_END_RATIO  # 0.25` |
| `HIGH_COHERENCE` / `COHERENCE_RECORDS` | `constant` | **What ISO 7626-5 9.1 calls a high coherence, and the records it needs.**<br>0.9 (greater than); 5, the lower end of "five to ten" | `HIGH_COHERENCE  # 0.9` |
| `CHANNEL_MAGNITUDE_TOLERANCE` / `CHANNEL_PHASE_TOLERANCE_DEG` | `constant` | **Channel-to-channel tolerances of ISO 7626-5 8.1.**<br>0.05 (±5 % of unity) and 5.0 (±5° of phase) | `CHANNEL_PHASE_TOLERANCE_DEG  # 5.0` |
| `ImpactExcitationWarning` | `warning class` | **ISO 7626-5 advisory.**<br>Emitted when a force window removes an impact the record holds (6.4). Subclass of `PhonometryWarning` | `warnings.simplefilter('error', ImpactExcitationWarning)` |
| `transfer_stiffness_level` / `loss_factor` | `function` | **Transfer-stiffness level & loss factor (ISO 10846-2/-3 3.17, -1 3.8).**<br>• `transfer_stiffness_level(k, reference=1.0)`: Lₖ = 20 lg(\|k\|/k₀) [dB re 1 N/m]<br>• `loss_factor(k)`: η = Im(k)/Re(k) | `transfer_stiffness_level(1e6)  # 120 dB` |
| `transfer_stiffness_direct` | `function` | **Direct method (ISO 10846-2).**<br>• `blocking_force` F₂,b [N]<br>• `input_displacement` u₁ [m]<br>k₂,₁ = F₂,b/u₁ | `transfer_stiffness_direct(5.0, 1e-6)  # 5e6 N/m` |
| `transfer_stiffness_indirect` | `function` | **Indirect method (ISO 10846-3 Formula 1).**<br>• `frequency` f [Hz] (scalar/array)<br>• `transmissibility` T = u₂/u₁ (complex)<br>• `blocking_mass` m₂ [kg]<br>• `flange_mass` m_f [kg] (Default: 0.0)<br>k₂,₁ = −(2πf)²(m₂+m_f)T; warns (`TransferStiffnessWarning`) where \|T\| > 0.1 (Inequality 2: ΔL1,2 < 20 dB) | `transfer_stiffness_indirect(500.0, 0.01, blocking_mass=10.0)` |
| `TRANSMISSIBILITY_LIMIT` | `float` | **Indirect-method validity limit (ISO 10846-3 6.1, Inequality 2).**<br>0.1: \|T\| ≤ 0.1 ⇔ ΔL1,2 ≥ 20 dB keeps Formula (1) within 1 dB (12 %) | `TRANSMISSIBILITY_LIMIT  # 0.1` |
| `REFERENCE_STIFFNESS` | `float` | **Reference stiffness k0 for the level Lk [N/m] (ISO 10846-2/-3, 3.17).**<br>1.0 | `REFERENCE_STIFFNESS  # 1.0` |
| `blocking_force_ratio` | `function` | **Delivered/blocking force ratio (ISO 10846-1 Eq. 6).**<br>• `driving_point_stiffness` k₂,₂ [N/m] (complex)<br>• `termination_stiffness` k_t [N/m] (complex, non-zero)<br>F₂/F₂,b = 1/(1 + k₂,₂/k_t); within 10 % of 1 for \|k₂,₂\| < 0.1\|k_t\| | `blocking_force_ratio(1e5, 1e6)  # 0.909` |
| `base_transmissibility` | `function` | **Mass-loaded Kelvin-Voigt transmissibility (model).**<br>• `frequency` f [Hz]<br>• `mass` m [kg], `stiffness` k [N/m], `damping` c [N·s/m] (Default: 0.0)<br>T = (k+jωc)/(k−ω²m+jωc) | `base_transmissibility(f, 8.0, 1e6, 120.0)` |
| `indirect_transfer_stiffness_result` | `function` | **Indirect-method sweep → result.**<br>• `frequency` f [Hz] (array)<br>• `transmissibility` T (complex)<br>• `blocking_mass` m₂ [kg], `flange_mass` (Default: 0.0) | `res = vibration.indirect_transfer_stiffness_result(f, t, 8.0)`<br><br>• `TransferStiffnessResult` |
| `TransferStiffnessResult` | `dataclass` | **Dynamic transfer stiffness over frequency (ISO 10846).**<br>• `frequencies` [Hz], `transfer_stiffness` k₂,₁ [N/m]<br>• `blocking_mass` m₂ [kg] or None<br>• `valid`: lines that meet Inequality (2), \|T\| ≤ 0.1, read from `transmissibility` (indirect method), or None (direct method)<br>• `.magnitude` / `.levels` (dB re 1 N/m) / `.loss_factor`<br>• `.to(target)`: "impedance"/"apparent_mass"<br>• `.band_average()`: `BandAveragedStiffness` over the valid lines<br>• `.plot()`: Lₖ(f)<br>• takes `frequencies`, `transfer_stiffness`, `blocking_mass`, `transmissibility`; `valid` is read-only, read from them | `res.levels, res.band_average().levels` |
| `band_averaged_stiffness` | `function` | **One-third-octave band average of a narrow-band stiffness (ISO 10846-2 F. 6, -3 F. 7, -4 F. 11, -5 F. 6).**<br>• `frequencies` [Hz] (distinct), `stiffness` k [N/m] (complex)<br>• `valid`: lines that enter the average (Default: every line)<br>k_av = {(1/n) Σ \|k(fᵢ)\|²}^½ over n ≥ 5 lines per base-ten band; a band of one to four valid lines is NaN and warns (`TransferStiffnessWarning`) | `bands = vibration.band_averaged_stiffness(f, k)`<br><br>• `BandAveragedStiffness` |
| `BandAveragedStiffness` | `dataclass` | **One-third-octave band averages of a stiffness (ISO 10846).**<br>• `nominal_frequencies` (ISO 266) / `center_frequencies` (exact midband) [Hz]<br>• `stiffness` k_av [N/m], NaN where fewer than five lines; `line_counts`<br>• `.determined`, `.levels` L_k,av [dB re 1 N/m]<br>• `.plot()`: the band levels, undetermined bands marked | `bands.levels, bands.determined` |
| `MIN_FREQUENCIES_PER_BAND` | `constant` | **Fewest lines a band average is taken over (every part's band average: "a minimum of n = 5 frequencies").**<br>5 | `MIN_FREQUENCIES_PER_BAND  # 5` |
| `TransferStiffnessWarning` | `warning class` | **ISO 10846 advisory.**<br>Emitted when an adequacy condition fails (\|T\| > 0.1, ΔL₁,₂ < 20 dB, unwanted input within 15 dB, m₀ over its limit) or a band holds fewer than five lines. Subclass of `PhonometryWarning` | `warnings.simplefilter('error', TransferStiffnessWarning)` |
| `check_blocked_output` / `check_unwanted_input` | `function` | **Is the output blocked, and the input unidirectional? (ISO 10846-5 Inequalities 1 and 2; -2 Ineq. 1 and 3, -3 Ineq. 2 and 5, -4 Ineq. 2 and 7).**<br>• `frequencies` [Hz]<br>• `check_blocked_output(f, input_acceleration_level_db, output_acceleration_level_db)`: L_a1 − L_a2 ≥ 20 dB<br>• `check_unwanted_input(f, excitation_level_db, unwanted_level_db)`: ≥ 15 dB; one row per direction, the loudest decides<br>Warns (`TransferStiffnessWarning`) where the condition fails | `vibration.check_blocked_output(f, la1, la2).passes`<br><br>• `LevelDifferenceCheck` |
| `LevelDifferenceCheck` | `dataclass` | **A level-difference condition judged frequency by frequency.**<br>• `frequencies` [Hz], `difference_db`, `limit_db` (20 or 15), `condition` ("blocked_output"/"unwanted_input")<br>• `.holds` per frequency, `.passes`; no truth value<br>• `.plot()` | `check.holds` |
| `check_output_mass` | `function` | **Is the mass in front of the output force transducers light enough? (ISO 10846-4 Inequality 3, -2 Inequality 2).**<br>• `frequencies` [Hz], `output_mass_kg` m₀ [kg]<br>• `output_force_level_db` L_F2 re 1 µN, `output_acceleration_level_db` L_a2 re 1 µm/s²<br>m₀ ≤ 0.06·10^(L_F2/20)/10^(L_a2/20) kg = 0.06 \|F₂\|/\|a₂\|; warns (`TransferStiffnessWarning`) where it fails | `vibration.check_output_mass(f, 0.4, lf2, la2).passes`<br><br>• `OutputMassCheck` |
| `OutputMassCheck` | `dataclass` | **The output mass against its ISO 10846-4 Inequality (3) limit.**<br>• `frequencies` [Hz], `output_mass_kg`, `output_apparent_mass_kg` \|F₂\|/\|a₂\| [kg]<br>• read-only `mass_limit_kg` = 0.06 \|F₂\|/\|a₂\| [kg]<br>• `.holds`, `.passes`; `.inertia_ratio` r = m₀\|a₂\|/\|F₂\|; `.bias_bound_db` −20 lg(1 − r), 0.54 dB on the bound (NOTE 1: 0.5 dB)<br>• `.plot()` | `check.bias_bound_db` |
| `effective_blocking_mass` | `function` | **Effective mass of a blocking mass (ISO 10846-4 Formula 6, -3 Formula 4).**<br>• `frequencies` [Hz] (increasing), `force_n` F₂, `first_acceleration_m_s2` a′₁, `second_acceleration_m_s2` a″₁ (phasors)<br>• `blocking_mass_kg` m₂ [kg], by name only<br>m₂,eff = \|2F₂/(a′₁ + a″₁)\| | `vibration.effective_blocking_mass(f, F, a1, a2, blocking_mass_kg=20.0)`<br><br>• `EffectiveBlockingMass` |
| `EffectiveBlockingMass` | `dataclass` | **Effective blocking mass and its upper limit f₃ (ISO 10846-4 Inequality 5, -3 Inequality 3).**<br>• `frequencies` [Hz], `effective_mass_kg`, `blocking_mass_kg` [kg]<br>• `.deviation_db` 20 lg(m₂,eff/m₂); `.upper_frequency_limit_hz` f₃, the 1 dB crossing from 40 Hz up (None if never); `.valid`; `.ignored_below_hz` (40)<br>• `.plot()` | `em.upper_frequency_limit_hz` |
| `driving_point_stiffness` | `function` | **Dynamic driving-point stiffness (ISO 10846-5 Formula 3).**<br>• `frequencies` [Hz] (increasing; lines from 1 Hz to 20 Hz needed)<br>• `input_force_n` F₁, `input_acceleration_m_s2` a₁ (phasors)<br>• `output_acceleration_m_s2`, `unwanted_acceleration_m_s2` (Default: None): check Inequalities 1 and 2 and exclude the lines that fail<br>k₁,₁ = −(2πf)² F₁/a₁ | `res = vibration.driving_point_stiffness(f, F1, a1)`<br><br>• `DrivingPointStiffnessResult` |
| `DrivingPointStiffnessResult` | `dataclass` | **Driving-point stiffness and the transfer stiffness it stands for (ISO 10846-5 6.2, Formulas 6 and 7).**<br>• `frequencies` [Hz], `driving_point_stiffness` k₁,₁ [N/m], `adequate` (or None), read from the two level differences<br>• `.levels`, `.loss_factor`; `.low_frequency_level_db` (1 Hz to 20 Hz); `.threshold_level_db` (2 dB below)<br>• `.upper_limiting_frequency_hz` f_UL (None if never reached); `.valid`<br>• `.band_average()`: k_av(1,1) ≈ k_av(2,1) within 2 dB<br>• `.plot()`<br>• takes `frequencies`, `driving_point_stiffness`, `blocked_output_difference_db`, `unwanted_input_difference_db`; `adequate` is read-only, read from them | `res.upper_limiting_frequency_hz, res.band_average().levels` |
| `driving_point_uncertainty` | `function` | **Uncertainty budget of a driving-point band level (ISO 10846-5 Annex B, Table B.1).**<br>• `band_level_db` L̂_k,av [dB re 1 N/m]<br>• `repeatability_range_db` 2p [dB], by name only (u_rep = p/√3)<br>• `signal_uncertainty_db` (0.3), `instrumentation_uncertainty_db` (0.5), `test_rig_uncertainty_db` (1/(2√3)), `discrepancy_uncertainty_db` (2/√3), `linearity_uncertainty_db` (1.5/(2√3))<br>Built on `metrology.combine_uncertainty`; U = 2u (B.3) | `vibration.driving_point_uncertainty(118.0, repeatability_range_db=0.6).expanded_uncertainty_db`<br><br>• `DrivingPointUncertainty` |
| `DrivingPointUncertainty` | `dataclass` | **An ISO 10846-5 Annex B budget.**<br>• `budget`: the `metrology.UncertaintyResult`, one row per Formula (B.1) input<br>• `.band_level_db`, `.combined_uncertainty_db` (B.2), `.coverage_factor` (2), `.expanded_uncertainty_db` (B.3)<br>• `.plot()`: the contributions with u and U | `u.expanded_uncertainty_db` |
| `infinite_plate_impedance` / `infinite_plate_mobility` / `infinite_plate_point_mobility` | `function` | **Thin-plate point mobility Z = C√(B'm'') (Cremer Table 5.1).**<br>• `bending_stiffness` B' [N·m], `mass_per_area` m'' [kg/m²]<br>• `location`: 'centre' (C=8) / 'edge' (C=3.5); real, frequency-independent | `infinite_plate_impedance(1e4, 10)`<br><br>• float or `MobilityResult` |
| `infinite_beam_mobility` / `infinite_beam_impedance` / `infinite_beam_moment_mobility` / `infinite_beam_point_mobility` | `function` | **Slender-beam point mobility Y = (1−j)/(4m'cB) (Cremer Table 5.1).**<br>• `frequency` [Hz], `bending_stiffness` B [N·m²], `mass_per_length` m' [kg/m]<br>• `location`: 'centre'/'end'; 45°, ∝ ω^−½ | `infinite_beam_mobility(100, 200, 5)`<br><br>• complex or `MobilityResult` |
| `beam_bending_wave_speed` / `plate_bending_wave_speed` | `function` | **Free bending wave speed, cB = (B ω²/m')^¼ for a beam and (B' ω²/m'')^¼ for a plate.**<br>• `frequency` [Hz]<br>• beam: `bending_stiffness` B = EI [N·m²], `mass_per_length` m' [kg/m]<br>• plate: `bending_stiffness` B' [N·m], `mass_per_area` m'' [kg/m²]<br>• ∝ √f, so it crosses the speed of sound at fc | `plate_bending_wave_speed(500.0, 4.2e3, 20.0)` |
| `longitudinal_rod_mobility` | `function` | **Point mobility of an infinite rod, Y = 1/(ρ cL S) (Cremer Table 5.1).**<br>• `density` ρ [kg/m³], `longitudinal_wave_speed` cL [m/s], `cross_section_area` S [m²]<br>• Real and frequency-independent, unlike the bending mobilities | `longitudinal_rod_mobility(7800.0, 5100.0, 1e-4)` |
| `longitudinal_rod_impedance` / `injected_power` / `plate_bending_stiffness` | `function` | **Rod point impedance ρcₗS; injected power W = ½\|F\|²Re{Y} (Cremer 5.23); plate B' = Eh³/12(1−ν²).** | `injected_power(10.0, y)` |
| `radiation_efficiency` / `coincidence_frequency` | `function` | **Plate radiation efficiency σ(f) (Hopkins 2.9, Leppington/Maidanik).**<br>• `frequency` [Hz], `length_x`/`length_y` [m], `critical_frequency` fc [Hz]<br>• `boundary`: 'simply_supported'/'clamped', `baffle`: 'infinite'/'perpendicular'<br>• σ → 1 above fc; fc = (c₀²/2π)√(m''/B') | `radiation_efficiency(f, 1.5, 1.25, 2100)`<br><br>• `RadiationEfficiencyResult` |
| `plot_plate_geometry` | `function` | **Baffled rectangular plate to scale.**<br>• `length_x`, `length_y` [m]<br>• `boundary` (title label)<br>• `language` | `plot_plate_geometry(1.2, 0.8)`<br><br>• Also `RadiationEfficiencyResult.plot_geometry()` |
| `RadiationEfficiencyResult` | `dataclass` | **Plate radiation efficiency over frequency (Hopkins 2.9.4).**<br>• `radiation_efficiency` σ, `radiation_index` 10 lg σ [dB]<br>• `critical_frequency` fc, `.plot()`; feeds `sound_power_from_vibration` as ε | `res.radiation_efficiency` |
| `junction_transmission` | `function` | **Bending-wave transmission of a rigid plate junction (Hopkins 5.2.1.3, Cremer 1973, Craik 1981/1996).**<br>• `junction`: 'X'/'T1'/'T2'/'L'<br>• two plates' `thickness` h, `wave_speed` cL, `surface_density` ρs<br>• `angles_deg` grid (Default: 0–90°) | `junction_transmission('X', 0.1, 3200, 240, 0.1, 3200, 240)`<br><br>• `JunctionTransmissionResult` |
| `plot_junction_geometry` | `function` | **Plate junction (L/T1/T2/X) to scale.**<br>• `junction`, `thickness1`, `thickness2` [m]<br>• `language` | `plot_junction_geometry('X', 0.14, 0.2)`<br><br>• Also `JunctionTransmissionResult.plot_geometry()` |
| `JunctionTransmissionResult` | `dataclass` | **Angle-resolved bending-wave transmission at a rigid junction (Hopkins 5.2.1.3).**<br>• `chi`, `psi`, `critical_frequency1`/`critical_frequency2` fc [Hz], `angles_deg`, `corner` τ12(θ), `straight` τ13(θ) or None<br>• `corner_average`/`straight_average` (Eq. 5.6), `corner_reduction_index` Kij (symmetric), `.plot()` | `res.corner_average  # 1/12 for identical X` |
| `junction_wave_parameters` | `function` | **Wave parameters χ, ψ of a plate pair (Hopkins 5.10/5.11).**<br>• two plates' h [m], cL [m/s], ρs [kg/m²]<br>• χ = √(h₁cL₁/h₂cL₂) = √(fc₂/fc₁), ψ = h₂cL₂ρs₂/(h₁cL₁ρs₁) | `junction_wave_parameters(0.1, 3200, 240, 0.2, 3200, 480)  # (√0.5, 4)` |
| `corner_transmission_coefficient` / `straight_transmission_coefficient` | `function` | **τ12(θ) around a corner (Hopkins 5.12) / τ13(θ) across a straight section (5.13).**<br>• `angle_rad` θ [rad], `chi`, `psi`, `junction`<br>• corner is 0 for χ < sinθ; straight only for 'X'/'T1' | `corner_transmission_coefficient(0.0, 1.0, 1.0, 'X')  # 1/8` |
| `inline_transmission_coefficient` | `function` | **Normal-incidence transmission across an in-line junction (Hopkins 5.14, Cremer 1973).**<br>• `chi`, `psi`; τ = 1 for identical plates | `inline_transmission_coefficient(1.0, 1.0)  # 1.0` |
| `angular_average_transmission_coefficient` | `function` | **Diffuse-field angular average ∫₀^{π/2} τ(θ)cosθ dθ (Hopkins 5.6).**<br>• `chi`, `psi`, `junction`, `section`: 'corner'/'straight' | `angular_average_transmission_coefficient(1.0, 1.0, 'X')  # 1/12` |
| `coupling_loss_factor` | `function` | **SEA coupling loss factor from τ (Hopkins 2.154).**<br>• `transmission_coefficient` τ, `group_velocity` cg [m/s]<br>• `junction_length` L [m], `frequency` f [Hz], `plate_area` S [m²]<br> η = cg·L·τ/(2π²fS) | `coupling_loss_factor(1/12, 200, 4, 500, 10)` |
| `right_angle_transmission_coefficient` | `function` | **τ12 of a right-angle plate junction, closed form (Norton & Karczub 6.53-6.55).**<br>• `thickness1`, `thickness2` [m]; `density1`/`density2` [kg/m³], `wave_speed1`/`wave_speed2` [m/s]<br>• `incidence`: 'random' (Default, Eq. 6.55) / 'normal' (Eq. 6.53)<br>• feed to `coupling_loss_factor` with cg = 2cB to get Norton Eq. (6.52) | `right_angle_transmission_coefficient(0.003, 0.0055, density1=2700, density2=2700, wave_speed1=5432, wave_speed2=5432)` |
| `point_connection_coupling_loss_factor` | `function` | **η12 of plates joined at N points (bolts/rivets/spot welds) (Norton & Karczub 6.56).**<br>• `frequency` [Hz], `n_connections` N<br>• `thickness1`/`thickness2` [m], `surface_density1`/`surface_density2` [kg/m²], `wave_speed1`/`wave_speed2` [m/s], `plate_area1` S1 [m²]<br>• falls as 1/f (a line junction falls as 1/√f) | `point_connection_coupling_loss_factor(f, 12, thickness1=0.003, ...)` |
| `power_injection_clf` | `function` | **Experimental SEA: CLFs from one drive plus reciprocity (Norton & Karczub 6.8/6.15).**<br>• `frequency` [Hz], `energy1`/`energy2` E = M⟨v²⟩ [J]<br>• `internal_loss_factor1`/`2`, `modal_density1`/`2` [1/Hz]<br>• η12 = η2·E2/(E1 − E2·n1/n2), η21 = η12·n1/n2 | `power_injection_clf(500, 0.087, 0.013, 4.4e-3, 2.4e-3, 0.557, 0.606)`<br><br>• `PowerInjectionResult` |
| `power_injection_matrix` | `function` | **Two-drive power-injection inversion (no reciprocity assumed).**<br>• `frequency` [Hz], `energies` (2, 2, nb) [J], `input_powers` (2, nb) [W]<br>• returns all four loss factors; reciprocity becomes a check | `power_injection_matrix(f, e, p)`<br><br>• `PowerInjectionResult` |
| `PowerInjectionResult` | `dataclass` | **Loss-factor budget of a two-subsystem SEA model.**<br>• `coupling_loss_factor12`/`21`, `internal_loss_factor1`/`2`, `energy1`/`2`, `input_power1`/`2`, `modal_density1`/`2`, `method`<br>• `input_power`, `dissipated_power`, `transmitted_power`, `coupling_strength` η12/η1, `modal_density_ratio`, `.plot()` | `res.coupling_loss_factor12, res.input_power` |
| `flat_plate_modal_density` / `bar_modal_density` / `beam_modal_density` | `function` | **Modal densities of structural elements (Norton & Karczub 6.23-6.25).**<br>• plate: n = S√12/(2cL·t) (equals π·S·fc/c₀² exactly)<br>• bar: n = 2L/cL; beam: n = L(ρA/EI)^¼/√(2πf) (falls with f) | `flat_plate_modal_density(8.73, 0.005, 5432.3)  # 0.557 /Hz` |
| `cylindrical_shell_modal_density` / `ring_frequency` | `function` | **Average modal density of a thin-walled cylinder (Norton & Karczub 6.26-6.29, Szechenyi).**<br>• `frequency` [Hz], `area` S [m²], `thickness` t [m], `mean_radius` a [m], `longitudinal_wave_speed` cL [m/s], `band`: 'octave'/'third'<br>• three regimes about fr = cL/(2πa) | `cylindrical_shell_modal_density(500, 9.42, 0.003, 0.75, 5432.3)` |
| `seat_factor` / `seat_transmission` / `SeatTransmissionResult` | `function` / `dataclass` | **What a seat does to the vibration under it (ISO 10326-1 Formula (2)).**<br>• `seat_factor(a_wS, a_wP)`: the SEAT factor, below 1 when the seat attenuates<br>• `seat_transmission(seat_runs, platform_runs)`: one test from its runs, each set averaged only if it holds the ± 5 % of 10.2.1<br>• `.seat_factor`, `.attenuates`, `.corrected_acceleration(intended)`, `.plot()` | `vibration.seat_transmission([0.72, 0.70, 0.71], [1.02, 1.00, 0.99]).seat_factor`<br><br>• 0.708 |
| `corrected_seat_acceleration` / `resonance_transmissibility` | `function` | **The corrected seat magnitude and the resonance ratio (ISO 10326-1 Clause 10).**<br>• `corrected_seat_acceleration(a_wS, a_wP, intended)`: the seat magnitude scaled to the input the test intended (10.2.3, Formula (4); the printed Formula (3) is an identity, see the errata)<br>• `resonance_transmissibility(a_S, a_P)`: Formula (5), the damping test at the suspension resonance | `vibration.corrected_seat_acceleration(0.70, 1.00, 1.10)  # 0.77` |
| `mean_of_test_runs` / `RUN_AGREEMENT_TOLERANCE` / `TEST_RUNS` | `function` / `constant` | **The three runs a seat test is made of (ISO 10326-1 10.2.1, 10.3).**<br>• the arithmetic mean of runs that agree within ± 5 % of it, and a refusal when they do not<br>• `tolerance=` tightens the band for an application standard that asks for less | `vibration.mean_of_test_runs([1.02, 1.00, 0.99])  # 1.003` |
| `DAMPING_TEST_MASS_KG` / `DAMPING_TEST_MASS_TOLERANCE` / `ACTIVE_DAMPING_TEST_MASS_KG` / `UNITY_TRANSMISSION` | `constant` | **The masses and the neutral value of ISO 10326-1.**<br>• 75 kg ± 1 % of inert mass for the damping test (10.3)<br>• 60 kg where the suspension is actively damped (9.5.1)<br>• 1, the ratio at which the seat passes the vibration through unchanged, which says nothing about it being rigid; Clause 11 leaves acceptance values to the application standard | `vibration.DAMPING_TEST_MASS_KG  # 75.0` |
| `guideline_velocity` / `BUILDING_CLASSES` | `function` / `constant` | **Guideline peak velocity for a structural-vibration assessment (DIN 4150-3 Tables 1 and 3).**<br>Keeping to a value meets the standard's criterion and certifies nothing; exceeding one is not a finding of damage<br>• `building_class`: `'commercial'`, `'residential'` or `'sensitive'`<br>• `frequency` [Hz], needed only at the foundation for short-term vibration<br>• `location`: `'foundation'` or `'top_floor'`; `duration`: `'short_term'` or `'long_term'`<br>• `massive_structure=True` doubles the commercial row (5.1) | `vibration.guideline_velocity('residential', 30)  # 10.0 mm/s` |
| `pipeline_guideline_velocity` / `PIPELINE_MATERIALS` | `function` / `constant` | **Guideline peak velocity on a buried pipeline (DIN 4150-3 Table 2).**<br>• `material`: `'welded_steel'` 100, `'concrete_or_flanged_metal'` 80, `'masonry_or_plastic'` 50 mm/s<br>• `duration='long_term'` halves them, which is the reduction 6.3 allows | `vibration.pipeline_guideline_velocity('welded_steel')  # 100.0` |
| `assess_building_vibration` / `DamageAssessment` | `function` / `dataclass` | **One measured peak velocity against its guideline value.**<br>• `velocity_mm_s` plus the same `building_class`, `frequency_hz`, `location` and `duration`, and keyword-only `massive_structure` (5.1)<br>• read-only `.guideline_mm_s`, `.ratio`, `.within_guideline`, `.plot()` drawing Bild 1 with the measurement on it | `vibration.assess_building_vibration(4.2, building_class='residential', frequency_hz=18).ratio  # 0.6` |
| `bending_stress` / `storey_fundamental_frequency` | `function` | **From a velocity to a stress, and the storey estimate (DIN 4150-3 6.2 and 6.4).**<br>• `bending_stress(peak_velocity_m_s, dynamic_modulus_pa=, density_kg_m3=, load_ratio=, mode_factor=)`, Formula (1); note the m/s<br>• `storey_fundamental_frequency(n)` = 10/n Hz, from about five storeys up | `vibration.bending_stress(0.01, dynamic_modulus_pa=3e10, density_kg_m3=2400)`<br><br>• 1.47e5 Pa |
| `BuildingDamageWarning` | `warning class` | **A DIN 4150-3 rule used outside the range the standard offers it for.**<br>Emitted by `storey_fundamental_frequency` below `STOREY_FREQUENCY_MIN_STOREYS`, where 10/n is an extrapolation rather than the rule of 6.4 | `warnings.simplefilter("error", vibration.BuildingDamageWarning)` |
| `foundation_guideline_curve` | `function` | **Bild 1 as two arrays, ready to plot.**<br>• `building_class`, and `frequency` to sample elsewhere than the four printed corners<br>• returns `(frequency_hz, guideline_mm_s)` | `vibration.foundation_guideline_curve('sensitive')`<br><br>• (1, 10, 50, 100) Hz, (3, 3, 8, 10) mm/s |
| `SHORT_TERM_FOUNDATION_MM_S` / `FOUNDATION_FREQUENCIES_HZ` / `SHORT_TERM_TOP_FLOOR_MM_S` / `LONG_TERM_TOP_FLOOR_MM_S` / `PIPELINE_MM_S` | `constant` | **The three printed tables of DIN 4150-3, as data.**<br>• Table 1 at the foundation, by class, at 1, 10, 50 and 100 Hz<br>• Table 1 in the topmost floor plane: 40 / 15 / 8 mm/s<br>• Table 3, long-term: 10 / 5 / 2.5 mm/s; Table 2, pipelines: 100 / 80 / 50 mm/s | `vibration.SHORT_TERM_FOUNDATION_MM_S['residential']  # (5.0, 5.0, 15.0, 20.0)` |
| `FLOOR_VERTICAL_MM_S` / `MASSIVE_STRUCTURE_FACTOR` / `PIPELINE_LONG_TERM_FACTOR` / `BENDING_STRESS_CONSTANT` / `STOREY_FREQUENCY_NUMERATOR_HZ` / `STOREY_FREQUENCY_MIN_STOREYS` | `constant` | **The numbers DIN 4150-3 prints in sentences rather than in tables.**<br>• 20 mm/s vertical for a floor (5.2); the factor 2 for massive engineering structures (5.1)<br>• the 50 % of 6.3; the 1,73 of Formula (1)<br>• the 10 Hz and the five storeys of 6.4 | `vibration.FLOOR_VERTICAL_MM_S  # 20.0` |
| `fundamental_period` / `fundamental_frequency` / `PERIOD_MODELS` | `function` / `constant` | **Empirical fundamental translation mode of a building (ISO 4866 Annex D).**<br>• `fundamental_period` returns `T` in **seconds**, `fundamental_frequency` returns `f` in **hertz**<br>• `model`: `'storeys'` (T = 0,1 n), `'height'` (T = k₁h), `'height_width'` (T = k₂h/√b), `'slenderness'` (T = k₃(h/√b)√(h/(h+b)))<br>• `storeys`, `height_m`, `width_m` as the model needs them, and only those: an argument the form does not use is refused<br>• `coefficient` defaults to the middle of the range D.2 prints for that form | `vibration.fundamental_frequency('height_width', height_m=60, width_m=20)`<br><br>• 0.76 Hz |
| `height_fundamental_frequency` / `HEIGHT_FREQUENCY_CONSTANT_HZ_M` / `HEIGHT_PERIOD_COEFFICIENT_S_PER_M` | `function` / `constant` | **The fit ISO 4866 D.2 closes with, to 163 measured buildings.**<br>• `f = 46/h` hertz, or `T = 0,022 h` seconds, scalar or array<br>• D.3 goes on to report that computed frequencies correlate with measurement worse than this line does | `vibration.height_fundamental_frequency(46)  # 1.0 Hz` |
| `empirical_frequency_bounds` / `EMPIRICAL_FREQUENCY_TOLERANCE` | `function` / `constant` | **The error an empirical prediction carries (ISO 4866 D.2).**<br>• ± 50 %, which the annex calls not uncommon and typical of empirical formulae<br>• returns `(lower, upper)` in hertz | `vibration.empirical_frequency_bounds(2.0)  # (1.0, 3.0)` |
| `estimate_fundamental_frequency` / `BuildingFrequencyEstimate` | `function` / `dataclass` | **One prediction with the coefficient and band it carries.**<br>• `.frequency_hz`, `.period_s`, `.model`, `.coefficient`, `.height_m`<br>• `.bounds_hz` the ± 50 % band, `.plot()` Figure D.1 with the estimate on it | `vibration.estimate_fundamental_frequency('height', height_m=46).bounds_hz` |
| `PERIOD_COEFFICIENT_RANGES` / `STOREY_PERIOD_COEFFICIENT_S` / `DAMPING_RATIO_RANGE` | `constant` | **What ISO 4866 Annex D prints as ranges rather than values, damping included: it reports measurements and offers no estimator.**<br>• k₁ 0,014 to 0,03, k₂ 0,087 to 0,109, k₃ 0,06 to 0,08 (D.2)<br>• the storey rule as a period, 0,1 s per storey<br>• damping measured between 0,5 % and 2,1 % of critical, with no predictor at all (D.4) | `vibration.PERIOD_COEFFICIENT_RANGES['height']  # (0.014, 0.03)` |
| `ZoneBoundaries` / `evaluation_zone` | `class` / `function` | **Evaluation zones of machine vibration (ISO 20816-1 6.3.2.3).**<br>• `ZoneBoundaries(a_b, b_c, c_d)`: the three boundaries, rising, in whichever quantity the applicable part states<br>• `evaluation_zone(magnitude, boundaries)` → `'A'`/`'B'`/`'C'`/`'D'`; a magnitude on a boundary is the top of the zone below | `z = vibration.ZoneBoundaries(2.8, 7.1, 11.2)`<br>`vibration.evaluation_zone(3.4, z)  # 'B'` |
| `allowable_velocity` | `function` | **Frequency-shaped velocity criterion (ISO 20816-1 Figure 9, Formula C.1).**<br>• `frequency` f [Hz]<br>• `constant_velocity_mm_s` vA [mm/s], `zone_factor` Zbound (see `ZONE_LIMIT_FACTORS`: 1 / 2.56 / 6.4)<br>• `corner_low_hz` fx, `corner_high_hz` fy [Hz]<br>• `exponent_low` k, `exponent_high` m (Default: 1, constant displacement below and constant acceleration above) | `vibration.allowable_velocity(100, constant_velocity_mm_s=1.12, corner_low_hz=10, corner_high_hz=1000)` |
| `VectorChangeResult` | `dataclass` | **A change in vibration between two steady states (ISO 20816-1 Annex D).**<br>• `magnitude` the change itself, `phase_deg` its direction<br>• `initial` / `final` the two states as (magnitude, phase)<br>• `magnitude_change`: what a magnitude-only comparison would have reported<br>• `.plot(unit='mm/s')`: the polar diagram of Figure D.1 | `vibration.vibration_vector_change(3, 40, 2.5, 180).plot(unit='mm/s')` |
| `vibration_vector_change` | `function` | **Change in vibration read as a vector (ISO 20816-1 Annex D).**<br>• `initial_magnitude`, `initial_phase_deg`, `final_magnitude`, `final_phase_deg`<br>• `.magnitude` the real change, `.magnitude_change` what a magnitude comparison reports | `vibration.vibration_vector_change(3, 40, 2.5, 180)`<br><br>• 5.17 mm/s against −0.5 |
| `TYPICAL_BOUNDARY_LADDER_MM_S` / `TYPICAL_ZONE_BOUNDARY_RANGES_MM_S` / `ZONE_LIMIT_FACTORS` | `constant` | **ISO 20816-1 Table C.1 and Annex C.2.**<br>• the ladder of 14 preferred magnitudes, 0.28 to 45 mm/s<br>• the typical range of each boundary: A/B 0.71–4.5, B/C 1.8–9.3, C/D 4.5–14.7 mm/s<br>• the zone factors of Formula (C.1): A 1, B 2.56, C 6.4 | `vibration.TYPICAL_ZONE_BOUNDARY_RANGES_MM_S['B/C']  # (1.8, 9.3)` |
| `MachineZoneLimits` / `INDUSTRIAL_MACHINE_ZONES` | `dataclass` / `constant` | **Zone boundaries of the industrial-machine tables (ISO 10816-3 Tables A.1 and A.2).**<br>• keyed by `(group, support)`: `'group_1'` above 300 kW to 50 MW, `'group_2'` above 15 kW to 300 kW; `'rigid'` or `'flexible'`<br>• `.displacement_um` and `.velocity_mm_s`, each a `ZoneBoundaries`<br>• broad-band r.m.s. from 10 Hz to 1 kHz, or from 2 Hz below 600 r/min | `vibration.INDUSTRIAL_MACHINE_ZONES['group_2', 'rigid'].velocity_mm_s.b_c  # 2.8` |
| `industrial_machine_zone` | `function` | **Grade an industrial machine against its table (ISO 10816-3 5.2.3).**<br>• `group`, `support`<br>• `displacement_um` and/or `velocity_mm_s`, whichever was measured<br>• with both, the more restrictive grading applies<br>• scalar in, letter out; array in, one letter per reading | `vibration.industrial_machine_zone('group_2', 'rigid', displacement_um=50, velocity_mm_s=2.0)  # 'C'` |
| `is_significant_change` / `alarm_limit` / `trip_limit` | `function` | **Operational limits with numbers (ISO 10816-3 5.3 and 5.4).**<br>• `is_significant_change(change, zone_b_upper)`: more than a quarter of the upper limit of zone B, up or down<br>• `alarm_limit(baseline, zone_b_upper)`: that quarter above the baseline, capped at 1.25 times the limit<br>• `trip_limit(zone_c_upper)`: 1.25 times the upper limit of zone C | `vibration.alarm_limit(0.9, 2.8)  # 1.6`<br>`vibration.trip_limit(4.5)  # 5.625` |
| `SIGNIFICANT_CHANGE_FRACTION` / `OPERATIONAL_LIMIT_HEADROOM` | `constant` | **The two fractions the operational limits are built from (ISO 10816-3 5.3, 5.4.1 and 5.4.2).**<br>• `SIGNIFICANT_CHANGE_FRACTION` = 0.25, of the upper limit of zone B<br>• `OPERATIONAL_LIMIT_HEADROOM` = 1.25, the multiple neither limit should exceed | `vibration.OPERATIONAL_LIMIT_HEADROOM * 4.5  # 5.625` |
| `GEAR_UNIT_ZONES` / `gear_unit_zone_boundaries` | `constant` / `function` | **Gear-unit zone boundaries (ISO 20816-9 Tables 2, 3 and 4).**<br>• keyed by quantity, then by rating number: `'displacement'` (shaft relative peak-to-peak, µm), `'velocity'` (housing r.m.s., mm/s), `'acceleration'` (housing true peak, m/s²)<br>• every row is three consecutive rungs of one ladder, with the rating as the B/C boundary<br>• a rating with no printed row is refused, not interpolated | `vibration.gear_unit_zone_boundaries('velocity', 8.0).as_tuple`<br><br>• (5.0, 8.0, 12.5) |
| `GearUnitRatings` / `GEAR_UNIT_CLASSES` | `dataclass` / `constant` | **The classification of typical gear units (ISO 20816-9 Table 5).**<br>• keyed by `(class, subclass)`: class `'I'` to `'IV'`, subclass `'a'`, `'b_low'` or `'b_high'`<br>• `.displacement`, `.velocity`, `.acceleration`; the last is `None` on every b) row, where the table prints no information | `vibration.GEAR_UNIT_CLASSES['III', 'a'].velocity  # 8.0` |
| `gear_shaft_displacement_limit` / `gear_housing_velocity_limit` | `function` | **The two rating curves of ISO 20816-9 Annex A.**<br>• Figure A.1: flat to 50 Hz, then 10 dB per decade down<br>• Figure A.2: flat from 45 Hz to 1590 Hz, then 14 dB per decade down on both sides, which is Formula (C.1) of Part 1 with those corners | `vibration.gear_housing_velocity_limit(3000, rating=8.0)`<br><br>• 5.13 mm/s |
| `GEAR_DISPLACEMENT_CORNER_HZ` / `GEAR_DISPLACEMENT_SLOPE_DB_PER_DECADE` / `GEAR_VELOCITY_CORNERS_HZ` / `GEAR_VELOCITY_SLOPE_DB_PER_DECADE` / `GEAR_ACCEPTANCE_HEADROOM` | `constant` | **The numbers the notes under Figures A.1 and A.2 print, and the acceptance ceiling of 8.3.**<br>• 50 Hz and 10 dB per decade for displacement<br>• 45 Hz to 1590 Hz and 14 dB per decade for velocity<br>• 1.25, the multiple of the A/B boundary an acceptance criterion should not normally exceed | `vibration.GEAR_VELOCITY_CORNERS_HZ  # (45.0, 1590.0)` |
| `bearing_fault_frequencies` | `function` | **Rolling-bearing kinematic fault lines (Norton & Karczub 8.4-8.14).**<br>• `speed_rpm` N, `n_elements` Z, `element_diameter` d, `pitch_diameter` D<br>• `contact_angle_deg` φ, `rotating_race`: 'inner'/'outer'<br>• lines: shaft, FTF, FTF_rel, BSF, BDF, BPFO, BPFI; BPFO + BPFI = Z·fs | `bearing_fault_frequencies(2000, 15, 6, 34, contact_angle_deg=12.96)  # BPFO 207 Hz`<br><br>• `FaultFrequencyResult` |
| `gear_mesh_frequencies` | `function` | **Gear-mesh frequency and sideband family (Norton & Karczub 8.3).**<br>• `speed_rpm`, `n_teeth`; `harmonics`, `sidebands`, `sideband_rate` [Hz]<br>• GMF = N·fs, sidebands at k·GMF ± m·f_mod | `gear_mesh_frequencies(1500, 28, sidebands=2)`<br><br>• `FaultFrequencyResult` |
| `induction_motor_frequencies` | `function` | **Motor electrical and rotor-slot lines (Norton & Karczub 8.19/8.20).**<br>• `speed_rpm`, `poles` p, `rotor_bars` R; `slip` s or `supply_frequency` fe<br>• `slot_harmonics`, `sidebands`<br>• lines: 1x, 2x, fe, 2fe, f_slip, FP, fsh = R·fs | `induction_motor_frequencies(3600, 6, 60)  # 2fe 360 Hz, fsh 3600 Hz`<br><br>• `FaultFrequencyResult` |
| `blade_pass_frequencies` | `function` | **Fan/pump blade-pass tones and lobed patterns (Norton & Karczub 8.15-8.18).**<br>• `speed_rpm`, `n_blades`; `harmonics`, `n_vanes` V, `lobe_orders`<br>• BPF = n·N·fs; lobes mL = nN ± kV turning at nN·fs/mL | `blade_pass_frequencies(3500, 6, n_vanes=4)  # BPF 350 Hz`<br><br>• `FaultFrequencyResult` |
| `FaultFrequencyResult` / `FaultLine` / `combine_fault_lines` / `shaft_rate` | `dataclass` / `function` | **Predicted fault lines of one machine element.**<br>• `lines` (name, frequency, order, family, description), `shaft_rate`, `source`<br>• `res['BPFO']`, `names`, `frequencies`, `orders`, `as_dict()`, `harmonics(name, n)`, `within(low, high)`<br>• `.plot(spectrum=envelope_result)` overlays the lines on a measured envelope spectrum | `res['BPFO']  # 207.0` |
| `wave_vibration_reduction_index` | `function` | **Wave-approach vibration reduction index Kij (Hopkins 5.116).**<br>• `transmission_coefficient` τ, `critical_frequency_receiver` fc_j [Hz]<br>Kij = 10 lg(1/τ) + 5 lg(fc_j/f_ref), f_ref = 1000 Hz (symmetric: Kij = Kji) | `wave_vibration_reduction_index(1/12, 1000.0)  # 10.8 dB` |
| `velocity_level` / `velocity_level_from_acceleration` | `function` | **Vibratory velocity level (ISO/TS 7849-1 Eq. 3/8).**<br>• `velocity_level(v, reference=5e-8)`: 20 lg(v/v₀) [dB]<br>• `velocity_level_from_acceleration(a_peak, f)`: 20 lg(â/(2πf·v₀·√2)) (sinusoidal calibration) | `velocity_level_from_acceleration(9.81, 100.0)  # 106.9 dB` |
| `REFERENCE_VELOCITY` | `float` | **Reference velocity v0 [m/s] (ISO/TS 7849-1).**<br>5e-8 | `REFERENCE_VELOCITY  # 5e-08` |
| `NORMALIZED_IMPEDANCE` | `float` | **Normalized characteristic impedance Zc,n of air [N·s/m³] (23 °C, 101,3 kPa).**<br>411.0 | `NORMALIZED_IMPEDANCE  # 411.0` |
| `mean_velocity_level` | `function` | **Mean surface velocity level (ISO/TS 7849-1 Eq. 10/11).**<br>• `levels` L_v,i [dB]<br>• `areas` S_i (Eq. 11) or None → energetic mean (Eq. 10) | `mean_velocity_level([60, 66, 63])` |
| `radiation_factor` | `function` | **A-weighted radiation factor ε (ISO/TS 7849 Eq. 4/8).**<br>• `sound_power` P [W], `area` S [m²]<br>• `mean_square_velocity` ⟨v²⟩ [(m/s)²]<br>• `impedance` Z_c (Default: 411 N·s/m³)<br>ε = P/(Z_c·⟨v²⟩·S) | `radiation_factor(3e-4, 2.0, 1e-6)  # 0.365` |
| `radiated_sound_power_level` | `function` | **Sound power level from vibration (ISO/TS 7849-1 Eq. 12, -2 Eq. 15).**<br>• `velocity_level` L_v [dB]<br>• `area` S [m²]<br>• `radiation_factor` ε (Default: 1.0 → Part 1 upper limit)<br>L_W = L_v + 10 lg(S/S₀) + 10 lg(ε) + 10 lg(411/400) | `radiated_sound_power_level(80.0, 1.6)` |
| `extraneous_velocity_correction` | `function` | **Correction K1A for extraneous vibration (ISO/TS 7849-1 Table 2).**<br>• `level_difference` ΔLv [dB]; ΔLv≥10→0, ΔLv<3→3 | `extraneous_velocity_correction(6.0)  # 1.0 dB` |
| `sound_power_from_vibration` | `function` | **Bundle a vibration → power determination.**<br>• `velocity_level` L_v per band [dB]<br>• `area` S [m²], `radiation_factor` ε (Default: 1.0)<br>• `frequencies` [Hz] or None | `res = emission.sound_power_from_vibration(lv, 1.6, radiation_factor=eps, frequencies=f)`<br><br>• `VibrationSoundPowerResult` |
| `VibrationSoundPowerResult` | `dataclass` | **Sound power radiated by surface vibration (ISO/TS 7849).**<br>• `velocity_level` / `sound_power_level` / `radiation_factor` per band<br>• `area` S [m²], `frequencies` [Hz] or None<br>• `.total_level`: band-summed L_W [dB]<br>• `.plot()` | `res.sound_power_level, res.total_level` |
| `spatial_mean_velocity_level` / `plate_loss_factor` | `function` | **Reception-plate helpers (EN 15657 Formula 12/13).**<br>• `spatial_mean_velocity_level(levels)`: 10 lg(mean 10^(Lv,i/10)) [dB]<br>• `plate_loss_factor(f, Ts)`: η = 2.2/(f·Ts) | `spatial_mean_velocity_level([78, 80, 82])` |
| `mean_free_velocity_level` | `function` | **Mean free velocity level (ISO 9611:1996 eq. (9)).**<br>• `levels`: free-velocity levels at the N contact points [dB re 5e-8 m/s]<br>Energy mean over positions | `mean_free_velocity_level([70, 72, 74])  # 72.3 dB` |
| `structure_borne_power_level` | `function` | **Reception-plate injected power level (EN 15657 Formula 14).**<br>• `velocity_level` L_v [dB re 1e-9 m/s]<br>• `frequency` f [Hz], `mass_per_area` m [kg/m²], `area` S [m²]<br>• `loss_factor` η > 0<br>L_Ws = 10 lg(2πfηmS) + L_v − 60 (plate-specific; convert via Formulae 15/17 before EN 12354-5) | `structure_borne_power_level(80, 1000, 10, 1, 0.01)  # 47.98 dB` |
| `equivalent_blocked_force_level` / `characteristic_reception_plate_power` | `function` | **Source quantities (EN 15657 Formulae 15/17).**<br>• `equivalent_blocked_force_level(L_Ws_low, Y_plate)`: L_Fb,eq = L_Ws − 10 lg(Re Y/Y0) [dB re 1e-6 N]<br>• `characteristic_reception_plate_power(L_Fb,eq)`: L_Wsn = L_Fb,eq + 10 lg(Y_R,∞,low/Y0), Y_R,∞,low = 5e-6 m/(N·s) | `lwsn = building.characteristic_reception_plate_power(building.equivalent_blocked_force_level(61.7, 5.34e-6))` |
| `equivalent_free_velocity_level` / `source_mobility_from_levels` | `function` | **Source quantities (EN 15657 Formulae 18/19).**<br>• `equivalent_free_velocity_level(L_Ws_high, Y_plate)`: L_vf,eq [dB re 1e-9 m/s]<br>• `source_mobility_from_levels(L_vf,eq, L_Fb,eq)`: \|Y_S,eq\| [m/(N·s)] | `y_s = building.source_mobility_from_levels(lvf, lfb)` |
| `reception_plate_power` | `function` | **Reception-plate determination → result (EN 15657 clause 7).**<br>• `velocity_level` L_v (per band), `frequency` [Hz]<br>• `mass_per_area`, `area`<br>• `loss_factor` η **or** `reverberation_time` Ts | `res = building.reception_plate_power(lv, f, 600, 2.0, reverberation_time=0.8)`<br><br>• `StructureBornePowerResult` |
| `StructureBornePowerResult` | `dataclass` | **Reception-plate injected structure-borne power (EN 15657).**<br>• `power_level` L_Ws / `velocity_level` / `loss_factor` per band<br>• `mass_per_area`, `area`, `frequencies` [Hz] or None<br>• `.total_level`: band-summed L_Ws [dB]<br>• `.plot()` | `res.power_level, res.total_level` |
| `coupling_term` / `coupling_term_force_source` / `coupling_term_velocity_source` | `function` | **Coupling term D_C (EN 12354-5 Formula 19b/c/d).**<br>• `coupling_term(Ys, Yi, transfer_mobility=0)`: 10 lg(\|Ys+Yi+Yk\|²/(\|Ys\|·Re Yi))<br>• force source: 10 lg(\|Ys\|/Re Yi)<br>• velocity source: −10 lg(\|Ys\|·Re Zi) | `coupling_term(2e-4+1e-4j, 3e-5+1e-5j)` |
| `installed_structure_borne_power_level` | `function` | **Installed power (EN 12354-5 Formula 18b).**<br>• `characteristic_power_level` L_Ws,c [dB] (the converted EN 15657 level, not the raw Formula 14 plate power)<br>• `coupling_term` D_C [dB]<br>L_Ws,inst = L_Ws,c − D_C | `installed_structure_borne_power_level(82.0, 8.5)` |
| `installed_power_from_reception_plate` | `function` | **Annex I mobility correction (EN 12354-5).**<br>• `reception_plate_level` L_Ws,n [dB]<br>• `receiver_mobility` Y_∞,i [m/(N·s)]<br>• `plate_mobility` Y_∞,rec (Default: 5e-6)<br>L_Ws,inst = L_Ws,n + 10 lg(Y_∞,i/Y_∞,rec); with the source mobility it yields L_Ws,c | `installed_power_from_reception_plate(67.6, 1.25e-6)  # -6 dB` |
| `structure_borne_pressure_level_path` / `total_structure_borne_pressure_level` | `function` | **Path & total normalised SPL (EN 12354-5 Formula 18a/17).**<br>• path: L_Ws,inst − D_sa − R_ij,ref − 10 lg(S/S0) − 10 lg(A0/4)<br>• total: 10 lg(Σ 10^(L/10)) over paths (axis 0) | `total_structure_borne_pressure_level(path_levels)` |
| `REFERENCE_AREA` | `float` | **Reference area S0 = A0 [m²] (EN 12354-5 Formula 18a).**<br>10.0 | `REFERENCE_AREA  # 10.0` |
| `installed_source_prediction` | `function` | **Full installed-source prediction → result (EN 12354-5).**<br>• `characteristic_power_level` L_Ws,c, `coupling_term` D_C<br>• `paths`: dicts with `adjustment_term`, `flanking_reduction_index`, `element_area`<br>• `frequencies` [Hz] or None | `res = building.installed_source_prediction(lwc, dc, paths, frequencies=f)`<br><br>• `InstalledSourceResult` |
| `InstalledSourceResult` | `dataclass` | **Installed structure-borne sound prediction (EN 12354-5).**<br>• `path_levels` (paths×bands), `total_level` L_n,s per band<br>• `installed_power_level` per band, `frequencies` [Hz] or None<br>• `.overall_level`: band-summed total [dB]<br>• `.plot()`: the cascade | `res.total_level, res.overall_level` |
| `typical_element_mobility` / `TABLE_D1_QUANTITIES` | `function` / `dict` | **Mobility of typical construction elements (EN 12354-5 Table D.1).**<br>• `structure`: `'mass'` [2πfM]⁻¹, `'bar_end'` [ρcLS]⁻¹, `'beam'` [7,6ρtw√(cLtf)]⁻¹, `'plate'` [2,3cLρt²]⁻¹, `'pipe'` [63ρtr√(cLrf)]⁻¹, `'mass_spring'`<br>• the row's own describing quantities as keywords; `TABLE_D1_QUANTITIES` lists them<br>• `frequency` [Hz] for the four rows whose expression contains f, rejected by the other two | `typical_element_mobility('plate', density=2300, longitudinal_velocity=3800, thickness=0.14)  # 2.54e-6 m/(N·s)` |
| `tapping_machine_force_level` / `TABLE_F1_FORCE_LEVEL` / `TABLE_F1_OCTAVE_BANDS` | `function` / `tuple` | **ISO tapping machine force level (EN 12354-5 Table F.1).**<br>• octave bands 31,5 Hz to 4 kHz: 139, 142, 145, 148, 151, 154, 156, 156 dB re 1e-6 N (the caption prints "re 1 pN"; see ERRATA)<br>• substitution source of clause D.1.2.3, low-mobility receiving structures | `tapping_machine_force_level()` |
| `tapping_machine_force_level_estimate` | `function` | **Closed form printed under Table F.1 (EN 12354-5).**<br>• `frequency` f [Hz], `bandwidth` `'octave'` (2,5f) or `'third'` (0,8f)<br>L_F = 10 lg(k f/10⁻¹²) dB re 1e-6 N; tracks the table only up to about 1000 Hz | `tapping_machine_force_level_estimate(1000, bandwidth='third')  # 149.03 dB` |
| `tapping_machine_characteristic_power_level` / `tapping_machine_coupling_term` | `function` | **Tapping machine as a force source (EN 12354-5 Formulae D.9a/D.9b).**<br>• power: L_Ws,c = L_F − 5 − 10 lg f (≈115 dB re 1 pW per 1/3 octave)<br>• coupling: −10 lg(ωMYi) + 10 lg[1 + (ωMYi)²], `hammer_mass` M (Default: 0,5 kg) | `tapping_machine_coupling_term(500.0, 1.07e-6)` |
| `structure_to_airborne_adjustment` | `function` | **Adjustment term D_sa (EN 12354-5 Formula F.3).**<br>• `frequency` f [Hz], `critical_frequency` fc [Hz], `mass_per_area` m [kg/m²]<br>• `radiation_factor` σ (Default: 1.0)<br>D_sa = 10 lg(400 fc σ/(m f²)); normally negative, and Formula 18a subtracts it | `structure_to_airborne_adjustment(500.0, 200.0, 92.0)  # -24.6 dB` |
| `multi_junction_adjustment` / `MINIMUM_MULTI_JUNCTION_KIJ` | `function` / `float` | **Multi-junction ΔK (EN 12354-5 clause F.1).**<br>• `junctions` ≥ 1 → 0 dB (single), 4 dB (two), 6 dB (three or more)<br>• the resulting Kij is floored at `MINIMUM_MULTI_JUNCTION_KIJ` = −5.0 dB | `multi_junction_adjustment(2)  # 4.0` |
| `air` | `function` | **Humid air (IEC 61094-2:2009 Annex F, CIPM-2007).**<br>• `temperature_c` t [°C], required<br>• `static_pressure_pa` p_s [Pa] (Default: None → 101 325, warns)<br>• `relative_humidity_percent` H [%] (Default: None → 50, warns)<br>• `co2_mole_fraction` x_c (Default: None → 0,000 4, silent) | `f = fluids.air(temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `Fluid`; rho = 1.1860848 kg/m³, c0 = 345.86652 m/s |
| `Fluid` | `dataclass` | **One fluid at one state, and what its model fixed there.**<br>• `temperature_c`, `static_pressure_pa`, `composition`, `model`, `validity`, `properties`<br>• accessors `density`, `speed_of_sound`, `heat_capacity_ratio`, `viscosity`, `thermal_diffusivity`, `thermal_conductivity`, `specific_heat_capacity`<br>• closed by identity: `characteristic_impedance`, `kinematic_viscosity`, and `prandtl_number` unless the model printed one of its own, which wins | `f.characteristic_impedance  # rho c` |
| `PUBLISHED_FLUIDS` | `mapping` | **The fluid states this library has read from a published page, keyed `'<table>/<row>'`.**<br>• Bies 5e **Table C.1** prints three fluids before its solids: air at 20 °C, fresh water at 20 °C and sea water at 13 °C<br>• Each names its page, with the printed folio, in its `model`, because for a transcribed state the table is what produced it<br>• The four airs that sit elsewhere in the tree are deliberately not here: each belongs beside the model or standard that fixes it, and gathering them would make the medium depend on three of the domains that stand on it<br>• Not a table to look values up in: air at measured conditions is `air()` and sea water is `sea_water()` | `fluids.PUBLISHED_FLUIDS['bies-2017-table-c1-fluids/fresh_water'].speed_of_sound  # 1497.0`<br><br>• `Fluid` |
| `Gas` | `dataclass` | **One gas of a published table: the two numbers that close its state.**<br>• `molar_mass_kg_mol` M [kg/mol], `heat_capacity_ratio` γ, plus the hedges every catalogue row carries<br>• `ideal_state(temperature_c=..., static_pressure_pa=...)` → `Fluid`, carrying the row's page in its `model`<br>• a gas has no one density or speed of sound, which is why this is not a `Fluid` and not in `PUBLISHED_FLUIDS` | `fluids.PUBLISHED_GASES['bies-2017-table-c2/methane'].ideal_state(temperature_c=20.0).speed_of_sound  # 447.9`<br><br>• `ideal_gas`, `Fluid` |
| `PUBLISHED_GASES` | `mapping` | **The gases this library has read from a published page, keyed `'<table>/<row>'`.**<br>• Bies 5e **Table C.2** prints thirty-seven gases and Hopkins **Table A1** six, and both print air<br>• each row holds the molar mass and the ratio of specific heats, which between them close every state the gas can be in<br>• six cells of Table C.2 are not served: four molar masses that do not belong to the molecule their row names and two ratios outside what the quantity can be, each refusing with what the page prints and pointing at `docs/ERRATA.md`<br>• saturated steam prints an interval, 1,25 to 1,32, so it has no single ratio and says so | `fluids.PUBLISHED_GASES['hopkins-2007-table-a1/argon'].heat_capacity_ratio  # 1.67`<br><br>• `Gas` |
| `gases_named` | `function` | **Every row for a gas name, across the tables.**<br>• `name`: the gas as a table prints it, matched without case and ignoring a parenthesis, so `'air'` finds `'Air (dry)'`<br>• returns both books' readings rather than choosing: carbon dioxide is 1,30 in one and 1,33 in the other<br>• `catalogue=`: the rows to search instead of `PUBLISHED_GASES`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_GASES \| mine`; a row of another class is refused by its key (`TypeError`) | `[g.table for g in fluids.gases_named('air')]  # ['bies-2017-table-c2', 'hopkins-2007-table-a1']`<br><br>• `PUBLISHED_GASES` |
| `NonlinearityParameter` | `dataclass` | **One published value of the nonlinearity parameter B/A, with the conditions it was measured at.**<br>• `b_over_a`: B/A, dimensionless; the coefficient of nonlinearity is 1 + B/(2A)<br>• `temperature_c` [°C]; `static_pressure_pa` [Pa] only on the rows of the one table that prints a pressure, `year` only on the one that prints a year<br>• `attributed_to['row']`: the paper the measurement comes from, spelled out from the chapter's reference list (`attributed_to['table']` on Table 8.2, whose caption credits one paper for every cell); `uncertainty['b_over_a']`: the plus-or-minus where the page prints one | `row = fluids.nonlinearity_named('mercury')[0]`<br>`row.b_over_a, row.temperature_c  # (7.8, 30)`<br><br>• `PUBLISHED_NONLINEARITY`, `nonlinearity_named` |
| `PUBLISHED_NONLINEARITY` | `mapping` | **A hundred and sixty-four published values of B/A, keyed `'<table>/<row>'`.**<br>• Rossing (2014) **Tables 8.1 to 8.4**: pure water from 0 to 100 °C, water up to 50 MPa, organic liquids, liquid metals and liquefied gases<br>• one row per measurement, so a substance measured by several papers is several rows that do not agree: at 30 °C water is 5.18 to 5.38<br>• not a model: nothing interpolates between temperatures or papers | `fluids.PUBLISHED_NONLINEARITY['rossing-2014-table-8-2/water_30c_50mpa'].b_over_a  # 5.82`<br><br>• `NonlinearityParameter`, `nonlinearity_named` |
| `nonlinearity_named` | `function` | **Every B/A value whose substance name contains the text.**<br>• `name`: matched without case against the name the page prints; `'water'` answers with Tables 8.1 and 8.2 and the sea water of Table 8.4<br>• empty when nothing matches, which is not an error<br>• `catalogue=`: the rows to search instead of `PUBLISHED_NONLINEARITY`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_NONLINEARITY \| mine`; a row of another class is refused by its key (`TypeError`) | `len(fluids.nonlinearity_named('water'))  # 81`<br><br>• `PUBLISHED_NONLINEARITY` |
| `characteristic_impedance` | `function` | **Characteristic impedance rho c [Pa·s/m].**<br>• `density` ρ [kg/m³]<br>• `speed_of_sound` c [m/s]<br>The medium's own quantity, so it moved here from the impedance tube that used to publish it; `Fluid` exposes the same thing as a property | `fluids.characteristic_impedance(1.186, 343.2)  # 407.04` |
| `sea_water` | `function` | **Sea water at one point of the ocean.**<br>• `temperature_c` T [°C], required<br>• `salinity_psu` S (Default: 35)<br>• `depth_m` (Default: 0)<br>• `latitude_deg` (Default: 45)<br>• `sound_speed_model`: `unesco` (default), `del_grosso`, `mackenzie`, `medwin` | `fluids.sea_water(temperature_c=10.0)`<br><br>• `Fluid`; rho = 1027.04 kg/m³, c = 1489.83 m/s. No heat-capacity ratio: no source here prints one |
| `sea_water_density` | `function` | **Density of sea water (Ainslie 2010 Eq. 4.6, after Pierce 1989).**<br>• `temperature_c` T [°C]<br>• `salinity_psu` S<br>• `absolute_pressure_pa` P_w [Pa], **absolute** | `fluids.sea_water_density(temperature_c=10.0, salinity_psu=35.0, absolute_pressure_pa=101989.16)  # 1027.04`<br><br>• ρ [kg/m³] |
| `sea_water_sound_speed` | `function` | **Speed of sound in sea water, m/s.**<br>• `temperature_c` [°C] / `salinity` [ppt] / `depth` [m]<br>• `model`: `"unesco"` (default) / `"del_grosso"` / `"mackenzie"` / `"medwin"`<br>• `latitude` (Default: 45) | `fluids.sea_water_sound_speed(25, 35, 1000)` |
| `depth_to_absolute_pressure_pa` | `function` | **Absolute static pressure at a depth (Ainslie 2010 Eq. 4.11).**<br>• `depth_m` z [m]<br>• `latitude_deg` (Default: 45)<br>Not zero at the surface: Eq. (4.11) puts 98 066,5 x 1,04 = 101 989,16 Pa there, which is Ainslie's own reference and 664 Pa above the 101 325 Pa standard atmosphere | `fluids.depth_to_absolute_pressure_pa(depth_m=0.0)  # 101989.16` |
| `depth_to_gauge_pressure_mpa` | `function` | **Gauge pressure at a depth (Leroy & Parthiot 1998).**<br>• `depth_m` Z [m]<br>• `latitude_deg` (Default: 45)<br>Zero at the surface; what the UNESCO and Del Grosso sound speeds want | `fluids.depth_to_gauge_pressure_mpa(depth_m=1000.0)  # 10.106` |
| `FluidWarning` | `warning class` | **State outside the domain its model states for itself.**<br>Annex F states 15 °C to 27 °C, 60 kPa to 110 kPa, 10 % to 90 % RH; outside it the result is an extrapolation, not a refusal | `warnings.simplefilter("error", fluids.FluidWarning)`<br>Emitted by `fluids.air` |
| `FluidAssumptionWarning` | `warning class` | **A condition the caller did not supply was assumed.**<br>Names the assumed values and what they are worth; passing every condition silences it | `warnings.simplefilter("error", fluids.FluidAssumptionWarning)`<br>Emitted by `fluids.air` |
| `FluidPropertyUnavailable` | `exception` | **A quantity the model does not determine.**<br>Raised instead of returning a number no source printed; names the model and what it does fix | `f.density  # on a model that fixes only a speed of sound` |
| `plate_longitudinal_speed` / `youngs_modulus_from_plate_speed` | `function` / `function` | **Quasi-longitudinal wave speed along a plate, and back (Hopkins Eq. 2.21).**<br>• `youngs_modulus_pa` E [Pa] or `longitudinal_speed_m_s` cL [m/s]<br>• `density_kg_m3` ρ, `poisson_ratio` ν between -1 and 1<br>• cL = sqrt(E / (ρ (1 - ν²))): the value the building-acoustics tables print | `solids.plate_longitudinal_speed(2.0e11, density_kg_m3=7800.0, poisson_ratio=0.28)  # 5274.6` |
| `beam_longitudinal_speed` / `youngs_modulus_from_beam_speed` | `function` / `function` | **Quasi-longitudinal wave speed along a beam, and back (Hopkins Eq. 2.20).**<br>• `youngs_modulus_pa` E [Pa] or `longitudinal_speed_m_s` cL [m/s]<br>• `density_kg_m3` ρ<br>• cL = sqrt(E / ρ): a beam is unconstrained on its sides, so ν does not appear | `solids.beam_longitudinal_speed(2.0e11, density_kg_m3=7800.0)  # 5063.7` |
| `bulk_longitudinal_speed` / `youngs_modulus_from_bulk_speed` | `function` / `function` | **Pure longitudinal wave speed in an unbounded solid, and back (Norton & Karczub Eq. 1.225).**<br>• `youngs_modulus_pa` E [Pa] or `longitudinal_speed_m_s` cL' [m/s]<br>• `density_kg_m3` ρ, `poisson_ratio` ν between -1 and 0.5<br>• cL' = sqrt(E (1 - ν) / (ρ (1 + ν)(1 - 2ν))): the speed an elastic solver integrates, not the one a plate table prints | `solids.bulk_longitudinal_speed(2.0e11, density_kg_m3=7800.0, poisson_ratio=0.28)  # 5724.8` |
| `thickness_critical_frequency_product` / `DEFAULT_SPEED_OF_SOUND_M_S` | `function` / `float` | **The `h f_c` column of a materials table, from the plate wave speed.**<br>• `plate_speed_m_s` cL,p [m/s]<br>• `speed_of_sound` c0 [m/s] (Default: 343)<br>• h f_c = c0² sqrt(12) / (2 π cL,p), the exact constant: the rounded 1.8 of ISO 12354-1 misses Hopkins Table A2 by 0.8 % | `solids.thickness_critical_frequency_product(5270.0)  # 12.31 m Hz, Table A2 prints 12.3` |
| `SolidMaterial` | `dataclass` | **One row of a published materials table, with what the cell said.**<br>• Every quantity optional, because no two books print the same columns; `.why_missing(field)` says what the page had instead<br>• Three speeds are three fields: `bar_longitudinal_speed_m_s`, `plate_longitudinal_speed_m_s` and `bulk_longitudinal_speed_m_s`, and `longitudinal_speed_m_s` holds the one a page prints without saying which, because at ν = 0,3 the plate speed is 4,8 % above the bar speed and the bulk speed 16 % above it<br>• Four loss factors: `flexural_loss_factor`, `longitudinal_loss_factor`, `in_situ_loss_factor`, and `loss_factor` for a page that prints one and does not say which<br>• `basis`, `approximate`, `ranges`, `bounded_above`, `unquantified`: what the cell was, when it was not a value; `basis[field]` is `'estimated'` for a cell the page marks as an estimate<br>• `derived`: field → how this library computed it; `borrowed`: field → the material a book took it from<br>• `attributed_to`: per-cell credit; `variant`: which specimen, when a page prints several under one name<br>• `.basis_of(field)`, `.is_approximate(field)`, `.is_derived(field)`, `.printed(field)` to narrow or be refused | `steel = solids.PUBLISHED_SOLIDS['hopkins-2007-table-a2/steel']`<br>`steel.youngs_modulus_pa  # 1.996e11, derived`<br><br>• `steel.attributed_to['flexural_loss_factor']  # 'Heckl, 1981'` |
| `PUBLISHED_SOLIDS` | `mapping` | **Two hundred and nineteen published solids from six books, keyed `'<table>/<row>'`.**<br>• Hopkins **Table A2**, twenty-five building materials (PDF pages 635-636)<br>• Cremer 3e **Table 4.3**, thirteen metals over fifteen rows (PDF page 201), the one table that prints E, G, ν and both speeds together<br>• Mechel **Table 3**, thirty-eight construction materials, plastics and metals (PDF pages 544-545), with no Poisson ratio, so its rows stop at the bar speed<br>• Bies 5e **Table C.1**, one hundred and five metals, building materials, woods, plastics and honeycomb panels (PDF pages 747-750), whose loss factor column is two quantities and not a range<br>• Long 2e **Table 12.1**, eighteen building materials credited to Beranek and Ver (PDF page 487), and Arau-Puchades **Table 4.1**, seventeen over eighteen rows (PDF page 129), neither of which says which longitudinal wave it prints<br>• The key names the table because four of them print a steel and they are not the same steel<br>• Only four of Hopkins' twenty-five Poisson ratios are measurements; the rest carry the book's 'Estimate' footnote and say so<br>• Not a specification: block densities vary by manufacturer, which is why the pages print ranges | `solids.PUBLISHED_SOLIDS['cremer-2005-table-4-3/gold']`<br><br>• `SolidMaterial`, `solids_named` |
| `solids_named` | `function` | **Every row for a material, across the tables.**<br>• Matches `SolidMaterial.name` without regard to case; empty when no page names it<br>• Comparing two books has to be a deliberate act: a lookup returning one steel would be choosing between published values for you<br>• `catalogue=`: the rows to search instead of `PUBLISHED_SOLIDS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_SOLIDS \| mine`; a row of another class is refused by its key (`TypeError`) | `solids.solids_named('Steel')  # two rows, two tables`<br><br>• `PUBLISHED_SOLIDS` |
| `DampingMaterial` | `dataclass` | **One commercial damping material, with the temperature and the frequency its loss factor peaks at.**<br>• `max_loss_factor` is the greatest loss factor the material reaches, not the loss factor at any temperature you happen to have<br>• `peak_temperature_at_10_hz_c`, `peak_temperature_at_100_hz_c`, `peak_temperature_at_1000_hz_c`: where that peak sits at each frequency the table prints, because the band moves up in temperature as the material is worked faster<br>• `youngs_modulus_max_pa` at the stiff end, `youngs_modulus_min_pa` at the soft end, `youngs_modulus_transition_pa` in the band where the loss factor peaks, which is the one that belongs beside it<br>• `loss_modulus_max_pa` is the imaginary part, about `max_loss_factor * youngs_modulus_transition_pa`<br>• `.peak_temperature_c(frequency_hz)` refuses a frequency the table does not print rather than reading the nearest column<br>• `converted`: the page is in degrees Fahrenheit and psi, so every converted cell keeps the figure and the unit the page prints, `('3e5', 'psi')` | `ear = solids.damping_named('EAR C-1002')[0]`<br>`ear.peak_temperature_c(100)  # where its peak sits at 100 Hz`<br><br>• `PUBLISHED_DAMPING`, `damping_named` |
| `PUBLISHED_DAMPING` | `mapping` | **Seventeen commercial damping materials, keyed `'<table>/<row>'`.**<br>• Vér & Beranek 2e **TABLE 14.1** (PDF page 599), the only table in this library where a loss factor carries the temperature and the frequency that decide it<br>• Every other loss factor here is a single number with neither, which is a property of a material only in the sense that a photograph is a property of a room<br>• Not measurements: the page's own footnote says the values were read off published curves, and the text says to get damping data from the supplier<br>• Three cells are corrupted in the printing, are registered in `docs/ERRATA.md` and are refused rather than guessed | `solids.PUBLISHED_DAMPING['ver-beranek-2006-table-14-1/ear_c_1002']`<br><br>• `DampingMaterial`, `damping_named` |
| `damping_named` | `function` | **Every damping material whose name contains the text.**<br>• Matches `DampingMaterial.name` without regard to case; empty when no page names it<br>• A tuple and not one row, because a name can be printed by more than one table<br>• `catalogue=`: the rows to search instead of `PUBLISHED_DAMPING`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_DAMPING \| mine`; a row of another class is refused by its key (`TypeError`) | `solids.damping_named('3M')  # five rows`<br><br>• `PUBLISHED_DAMPING` |
| `DampingTreatment` | `dataclass` | **One damping treatment, rated by the decay rate of the chapter's standard steel panel.**<br>• `decay_rate_db_s` [dB/s] at 160 Hz on a 50 × 50 × 0,6 cm plate, `temperature_c` [°C], `adhered_area_percent` [%], `surface_density_kg_m2` [kg/m²]<br>• a decay rate is the treatment on that plate, not a property of the material; at 160 Hz the plate's loss factor is the rate over 4 368, and it is not computed here<br>• two rows print "No" for the bonded area, which `why_missing` hands back | `row = solids.damping_treatments_named('metal')[0]`<br>`row.decay_rate_db_s  # 400`<br><br>• `PUBLISHED_DAMPING_TREATMENTS`, `damping_treatments_named` |
| `PUBLISHED_DAMPING_TREATMENTS` | `mapping` | **Eight asphalt felt damping treatments, keyed `'<table>/<row>'`.**<br>• Harris (1977) **Table 14.2** (PDF page 496): one to four plies, plain, punched or notched, bonded or loose, under carpet or a metal sheet<br>• most decay rates printed as a range, from 1 dB/s to 400 | `len(solids.PUBLISHED_DAMPING_TREATMENTS)  # 8`<br><br>• `DampingTreatment`, `damping_treatments_named` |
| `damping_treatments_named` | `function` | **Every damping treatment whose description contains the text.**<br>• `name`: matched without case against the Spanish description the page prints<br>• empty when nothing matches<br>• `catalogue=`: the rows to search instead of `PUBLISHED_DAMPING_TREATMENTS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_DAMPING_TREATMENTS \| mine`; a row of another class is refused by its key (`TypeError`) | `len(solids.damping_treatments_named('muescado'))  # 3`<br><br>• `PUBLISHED_DAMPING_TREATMENTS` |
| `SolidNonlinearity` | `dataclass` | **One solid's ultrasonic nonlinearity parameter, as a page printed it.**<br>• `nonlinearity_parameter`: the page's β_avg = −(3 + K3/K2), averaged over the [100], [110] and [111] directions; dimensionless<br>• comparable with a liquid's B/A + 2, not with its B/A<br>• `bonding`: covalent, ionic, metallic, van der Waals or isotropic, in the page's words | `solids.solid_nonlinearity_named('NaCl')[0].nonlinearity_parameter  # 14.6`<br><br>• `PUBLISHED_SOLID_NONLINEARITY`, `solid_nonlinearity_named` |
| `PUBLISHED_SOLID_NONLINEARITY` | `mapping` | **Eight solids' nonlinearity parameters, keyed `'<table>/<row>'`.**<br>• Rossing (2014) **Table 6.5** (PDF page 261)<br>• five rows are crystal structures or bonding classes, three name a material; fused silica is the one negative value | `len(solids.PUBLISHED_SOLID_NONLINEARITY)  # 8`<br><br>• `SolidNonlinearity`, `solid_nonlinearity_named` |
| `solid_nonlinearity_named` | `function` | **Every solid whose printed name contains the text.**<br>• `name`: matched without case; `'FCC'` answers with both face-centred cubic rows<br>• empty when nothing matches<br>• `catalogue=`: the rows to search instead of `PUBLISHED_SOLID_NONLINEARITY`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_SOLID_NONLINEARITY \| mine`; a row of another class is refused by its key (`TypeError`) | `len(solids.solid_nonlinearity_named('FCC'))  # 2`<br><br>• `PUBLISHED_SOLID_NONLINEARITY` |
| `OrthotropicWood` | `dataclass` | **One wood's orthotropic plate constants, as a page printed them.**<br>• By Rossing's Eq. (15.86): `plate_stiffness_d1_pa` = Ex/12μ along the grain, `plate_stiffness_d3_pa` = Ey/12μ across it, `plate_stiffness_d2_pa` = νxy·Ey/6μ the Poisson coupling and `plate_stiffness_d4_pa` = Gxy/3 the twisting stiffness, in pascals<br>• Not moduli: D1 is the along-grain modulus over 12μ, so none of them compares with `SolidMaterial.youngs_modulus_pa`, and the plate thickness enters separately<br>• `relative_scaling_factor` is the fourth root of D1 over D3, as the page prints it: the stretch across the grain of the equivalent isotropic plate<br>• `.basis_of(field)` answers `'estimated'` for the cells the caption calls intelligent guesses rather than measurements | `maple = solids.orthotropic_wood_named('maple')[0]`<br>`maple.basis_of('plate_stiffness_d2_pa')  # 'estimated'`<br><br>• `PUBLISHED_ORTHOTROPIC_WOOD`, `orthotropic_wood_named` |
| `PUBLISHED_ORTHOTROPIC_WOOD` | `mapping` | **Two orthotropic woods, keyed `'<table>/<row>'`.**<br>• Rossing (2014) **Table 15.5** (PDF page 632), after Woodhouse, whom every row credits<br>• The only wood here that is not isotropic: spruce is thirteen times stiffer along the grain than across it (D1 over D3)<br>• Maple's printed scaling factor does not follow from its own row, and the defect is registered in `docs/ERRATA.md` | `solids.PUBLISHED_ORTHOTROPIC_WOOD['rossing-2014-table-15-5/spruce']`<br><br>• `OrthotropicWood`, `orthotropic_wood_named` |
| `orthotropic_wood_named` | `function` | **Every orthotropic wood whose name contains the text.**<br>• Matches `OrthotropicWood.name` without regard to case; empty when no page names it<br>• `catalogue=`: the rows to search instead of `PUBLISHED_ORTHOTROPIC_WOOD`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_ORTHOTROPIC_WOOD \| mine`; a row of another class is refused by its key (`TypeError`) | `solids.orthotropic_wood_named('spruce')`<br><br>• `PUBLISHED_ORTHOTROPIC_WOOD` |
| `PlateauMaterial` | `dataclass` | **One material's plateau-method constants, as a page printed them.**<br>• `surface_density_per_mm_kg_m2` is the density divided by a thousand, kept in the unit the method uses it in<br>• `coincidence_height_db` is the height of the plateau: the transmission loss the method draws as a horizontal line over the coincidence region<br>• `plateau_frequency_ratio` is the width of the plateau, the page's B/A<br>• a row goes to `building.plateau_transmission_loss` as its `material`, one of these or one of your own | `al = solids.plateau_material_named('alumin')[0]`<br>`al.surface_density_per_mm_kg_m2 * 3  # kg/m2 of a 3 mm sheet`<br><br>• `PUBLISHED_PLATEAU_DATA`, `plateau_material_named` |
| `PUBLISHED_PLATEAU_DATA` | `mapping` | **Eight materials' plateau-method constants, keyed `'<table>/<row>'`.**<br>• Norton & Karczub 2e **Table 3.1** (PDF page 261)<br>• What the plateau method needs to sketch a single panel's transmission loss without solving the plate model, and what `building.PLATEAU_MATERIALS` and `building.plateau_transmission_loss` read | `solids.PUBLISHED_PLATEAU_DATA['norton-karczub-2003-table-3-1/steel']`<br><br>• `PlateauMaterial`, `plateau_material_named` |
| `plateau_material_named` | `function` | **Every plateau-method material whose name contains the text.**<br>• Matches `PlateauMaterial.name` without regard to case; empty when no page names it<br>• `catalogue=`: the rows to search instead of `PUBLISHED_PLATEAU_DATA`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_PLATEAU_DATA \| mine`; a row of another class is refused by its key (`TypeError`) | `solids.plateau_material_named('glass')`<br><br>• `PUBLISHED_PLATEAU_DATA` |
| `ideal_gas` / `MOLAR_GAS_CONSTANT` / `IDEAL_GAS_VALIDITY` | `function` / `float` / `str` | **A gas from the two numbers a gas table prints.**<br>• `temperature_c` t [°C], required<br>• `heat_capacity_ratio` γ (> 1: it is c_p/c_v and c_p − c_v is the gas constant), `molar_mass_kg_mol` M [kg/mol], required<br>• `static_pressure_pa` p [Pa] (Default: None → 101 325, warns)<br>• c = sqrt(γRT/M) and ρ = pM/(RT), so a gas that is not air or water is computed rather than typed<br>• the density is light by 1 − Z, the compressibility factor's distance from unity: 0,7 % for CO₂ and 2 % for SF₆<br>• no viscosity, no thermal conductivity and no Prandtl number: nothing in the closure determines them | `fluids.ideal_gas(temperature_c=20.0, heat_capacity_ratio=1.67, molar_mass_kg_mol=0.040, static_pressure_pa=101300.0)`<br><br>• `Fluid`; c = 319.0 m/s, rho = 1.663 kg/m³, which is Hopkins Table A1 for argon |
| `DEFAULT_STATIC_PRESSURE_PA` | `float` | **One standard atmosphere [Pa].**<br>101325.0 | `DEFAULT_STATIC_PRESSURE_PA  # 101325.0` |
| `DEFAULT_RELATIVE_HUMIDITY_PERCENT` | `float` | **Humidity assumed when none is supplied [%].**<br>50.0. There is no standard humidity: Annex F's own examples use 50 % and 65 % | `DEFAULT_RELATIVE_HUMIDITY_PERCENT  # 50.0` |
| `DEFAULT_CO2_MOLE_FRACTION` | `float` | **CO₂ mole fraction assumed when none is supplied.**<br>0.0004, the value Clause F.2 recommends for laboratory conditions | `DEFAULT_CO2_MOLE_FRACTION  # 0.0004` |
| `ISO1683_REFERENCE_VALUES` | `mapping` | **The ISO 1683:2015 reference values every level is counted from, keyed `[medium][quantity]`.**<br>• `'gas'`, Table 1: `sound_pressure` 20 µPa, `sound_exposure` (20 µPa)² s, `sound_power` 1 pW, `sound_energy` 1 pJ, `sound_intensity` 1 pW/m²<br>• `'liquid'`, Table 2: the same five re 1 µPa and 1 µPa² s, `particle_displacement` 1 pm, `particle_velocity` 1 nm/s, `particle_acceleration` 1 µm/s² and `distance` 1 m<br>• `'solid'`, Table 3: `displacement` 1 pm, `velocity` 1 nm/s, `acceleration` 1 µm/s², `force` 1 µN, and `velocity_alternative` 50 nm/s from note b<br>• every `value` in SI; the private references of the package read it, and `scripts/check_reference_values.py` keeps them doing so | `metrology.ISO1683_REFERENCE_VALUES['gas']['sound_pressure'].value  # 2e-05` |
| `ReferenceValue` | `dataclass` | **One row of the ISO 1683 table.**<br>• `quantity`, `medium` ('gas' / 'liquid' / 'solid'), `value` [in `unit`], `unit` (SI), `printed` (as the page prints it, prefix and all), `table` ('Table 1' to 'Table 3', or 'Table 3, note b') | `row = metrology.ISO1683_REFERENCE_VALUES['solid']['force']`<br><br>• `row.value, row.unit  # (1e-06, 'N')` |
| `verify_conformance` | `function` | **The conformance rule of IEC TC 29 (IEC 60942:2017 5.1.15, IEC 61672-1:2013 5.1.21).**<br>• `deviation`: measured deviation from the design goal, signed<br>• `uncertainty`: actual expanded uncertainty, 95 % coverage<br>• `acceptance_limits`: one number for ±, or `(lower, upper)`, one end of which may be open (`(70.0, math.inf)` for a stop-band minimum)<br>• `max_uncertainty`: maximum-permitted expanded uncertainty<br>• `unit`: label for the figure (Default: `'dB'`)<br>Conforms when the deviation is within the limits AND the uncertainty within the maximum, both inclusive; the uncertainty is not added to the deviation | `v = metrology.verify_conformance(-1.2, uncertainty=0.3, acceptance_limits=(-1.2, 1.0), max_uncertainty=0.5)`<br><br>• `v.passes  # True` (IEC 61672-1 Table C.1, example 7) |
| `ConformanceVerification` | `dataclass` | **One deviation judged by the TC 29 rule.**<br>• `deviation`, `uncertainty`, `lower_limit`, `upper_limit`, `max_uncertainty`, `unit`<br>• `passes`, `deviation_within_limits`, `uncertainty_within_maximum`<br>• `outcome` 1 to 4 (E.2.2 / C.2.2) and `reason`, worded as Tables E.1 and C.1 print it<br>• `share_of_acceptance_limit`, `share_of_max_uncertainty`<br>• no truth value: `bool(v)` raises; `.plot()` draws it as Figure E.1 | `v.outcome, v.reason` |
| `verify_sound_calibrator` | `function` | **A sound calibrator against IEC 60942:2017.**<br>• `calibrator_class`: `'LS'`, `'LS/M'`, `'1'`, `'1/M'` or `'2'` (Table 1)<br>• `measurements`: a `SoundCalibratorMeasurements`<br>• `nominal_frequency_hz`: selects the rows of Tables 2, 5, 7, A.1, A.3 and A.4; refused where the class has no limit (5.1.2)<br>• `environmental_test`: `'full'` (Tables 5 and 6) or `'abbreviated'` (A.6.4.7) (Default: `'full'`)<br>Every requirement given is judged by `verify_conformance` | `res = metrology.verify_sound_calibrator('1', record, nominal_frequency_hz=1000.0)`<br><br>• `SoundCalibratorVerification` |
| `SoundCalibratorMeasurements` | `dataclass` | **What a laboratory measured on a calibrator.**<br>• one pair per requirement, deviation and expanded uncertainty: `level_deviation_db`, `fluctuation_db`, `frequency_deviation_percent`, `distortion_percent`, `supply_voltage_deviation_db`, `environmental_level_deviation_db`, `environmental_level_in_band_deviation_db`, `environmental_frequency_deviation_percent`, `field_immunity_deviation_db`, each with its `..._uncertainty_...`<br>• `static_pressure_correction_db`: the manufacturer's correction for an LS/M or 1/M pistonphone, added to the level<br>• each field one number or one per condition; `.pairs(requirement)` | `metrology.SoundCalibratorMeasurements(level_deviation_db=0.12, level_uncertainty_db=0.10)` |
| `SoundCalibratorRequirement` | `dataclass` | **One IEC 60942 requirement, judged on each of its measurements.**<br>• `name`, `clause`, `tables`, `verifications` (one `ConformanceVerification` each)<br>• `passes`, `unit`, `acceptance_limits`, `max_uncertainty`<br>• no truth value; `.plot()` draws its measurements as Figure E.1 | `res.requirement('level').passes` |
| `SoundCalibratorVerification` | `dataclass` | **The IEC 60942:2017 verdict on one calibrator setting.**<br>• `calibrator_class`, `nominal_frequency_hz`, `environmental_test`, `measurements`<br>• `requirements` in the order of `CALIBRATOR_REQUIREMENTS`; `requirement(name)`, `failed`<br>• `passes`: every requirement measured passes (False when nothing was measured)<br>• no truth value; `.plot()` draws the share of each allowance used | `res.passes, res.failed` |
| `CalibratorTableRow` | `dataclass` | **One row of an IEC 60942 table keyed by a range of nominal frequencies.**<br>• `lower_hz`, `upper_hz`, `includes_lower`, `includes_upper` (as the printed "> 63 to < 160" says)<br>• `class_ls`, `class_1`, `class_2`, `None` where the table prints a dash<br>• `.contains(nominal_frequency_hz)`, `.for_class(calibrator_class)` | `metrology.LEVEL_ACCEPTANCE_LIMITS_DB[2].class_1  # 0.25` |
| `CALIBRATOR_CLASSES` | `constant` | **IEC 60942:2017 Table 1 classes and designations**: `('LS', 'LS/M', '1', '1/M', '2')` | `'1/M' in metrology.CALIBRATOR_CLASSES` |
| `CALIBRATOR_REQUIREMENTS` | `constant` | **The requirements `verify_sound_calibrator` grades**: `'level'`, `'fluctuation'`, `'frequency'`, `'distortion'`, `'supply_voltage'`, `'environmental_level'`, `'environmental_level_in_band'`, `'environmental_frequency'`, `'field_immunity'` | `metrology.CALIBRATOR_REQUIREMENTS[0]  # 'level'` |
| `LEVEL_ACCEPTANCE_LIMITS_DB` | `tuple` | **IEC 60942:2017 Table 2, sound pressure level** [dB]: 0.10 / 0.25 / 0.40 (LS / 1 / 2) from 160 Hz to 1.25 kHz; class 1 alone elsewhere, 0.30 to 0.50 dB | `metrology.LEVEL_ACCEPTANCE_LIMITS_DB[2].class_2  # 0.4` |
| `FLUCTUATION_ACCEPTANCE_LIMITS_DB` | `tuple` | **IEC 60942:2017 Table 2, short-term level fluctuation** [dB]: 0.03 / 0.07 / 0.15 from 160 Hz to 1.25 kHz; class 1 0.20 dB to 63 Hz and 0.10 dB below 160 Hz | `metrology.FLUCTUATION_ACCEPTANCE_LIMITS_DB[0].class_1  # 0.2` |
| `SUPPLY_VOLTAGE_ACCEPTANCE_LIMITS_DB` | `mapping` | **IEC 60942:2017 Table 3, effect of supply voltage** [dB]: LS 0.02, 1 0.06, 2 0.16 | `metrology.SUPPLY_VOLTAGE_ACCEPTANCE_LIMITS_DB['1']  # 0.06` |
| `FREQUENCY_ACCEPTANCE_LIMITS_PERCENT` | `mapping` | **IEC 60942:2017 Table 4, frequency** [% of the specified frequency]: LS 0.7, 1 0.7, 2 1.7 | `metrology.FREQUENCY_ACCEPTANCE_LIMITS_PERCENT['2']  # 1.7` |
| `ENVIRONMENTAL_LEVEL_ACCEPTANCE_LIMITS_DB` | `tuple` | **IEC 60942:2017 Table 5, level over the environmental range** [dB]: 0.10 / 0.25 / 0.40 from 160 Hz to 1.25 kHz; class 1 0.25 to 0.60 dB elsewhere | `metrology.ENVIRONMENTAL_LEVEL_ACCEPTANCE_LIMITS_DB[-1].class_1  # 0.6` |
| `ENVIRONMENTAL_FREQUENCY_ACCEPTANCE_LIMITS_PERCENT` | `mapping` | **IEC 60942:2017 Table 6, frequency over the environmental range** [%]: LS 0.7, 1 0.7, 2 1.7 | `metrology.ENVIRONMENTAL_FREQUENCY_ACCEPTANCE_LIMITS_PERCENT['LS']  # 0.7` |
| `DISTORTION_ACCEPTANCE_LIMITS_PERCENT` | `tuple` | **IEC 60942:2017 Table 7, maximum total distortion + noise** [%]: 2.0 / 2.5 / 3.0 from 160 Hz to 1.25 kHz; class 1 3.0 elsewhere | `metrology.DISTORTION_ACCEPTANCE_LIMITS_PERCENT[1].class_ls  # 2.0` |
| `LEVEL_MAX_UNCERTAINTY_DB` | `tuple` | **IEC 60942:2017 Table A.1, generated level** [dB, 95 %]: 0.10 / 0.15 / 0.35 from 160 Hz to 1.25 kHz; class 1 0.20 to 0.50 dB elsewhere | `metrology.LEVEL_MAX_UNCERTAINTY_DB[2].class_1  # 0.15` |
| `FLUCTUATION_MAX_UNCERTAINTY_DB` | `tuple` | **IEC 60942:2017 Table A.1, short-term fluctuation** [dB, 95 %]: 0.02 / 0.03 / 0.05 from 160 Hz to 1.25 kHz | `metrology.FLUCTUATION_MAX_UNCERTAINTY_DB[2].class_ls  # 0.02` |
| `FREQUENCY_MAX_UNCERTAINTY_PERCENT` | `mapping` | **IEC 60942:2017 Table A.2, frequency** [%, 95 %]: 0.2 for every class | `metrology.FREQUENCY_MAX_UNCERTAINTY_PERCENT['1']  # 0.2` |
| `DISTORTION_MAX_UNCERTAINTY_PERCENT` | `tuple` | **IEC 60942:2017 Table A.3, total distortion + noise** [%, 95 %]: 0.5 / 0.5 / 1.0 from 160 Hz to 1.25 kHz; class 1 1.0 elsewhere | `metrology.DISTORTION_MAX_UNCERTAINTY_PERCENT[1].class_2  # 1.0` |
| `ENVIRONMENTAL_LEVEL_MAX_UNCERTAINTY_DB` | `tuple` | **IEC 60942:2017 Table A.4, level over the environmental range** [dB, 95 %]: 0.10 / 0.15 / 0.20 from 160 Hz to 1.25 kHz; manufacturer's corrections included, Table A.1 excluded | `metrology.ENVIRONMENTAL_LEVEL_MAX_UNCERTAINTY_DB[1].class_2  # 0.2` |
| `ENVIRONMENTAL_FREQUENCY_MAX_UNCERTAINTY_PERCENT` | `mapping` | **IEC 60942:2017 Table A.5, frequency over the environmental range** [%, 95 %]: 0.2 for every class | `metrology.ENVIRONMENTAL_FREQUENCY_MAX_UNCERTAINTY_PERCENT['2']  # 0.2` |
| `SUPPLY_VOLTAGE_MAX_UNCERTAINTY_DB` | `mapping` | **IEC 60942:2017 A.5.5.7 and A.5.5.8, supply-voltage difference** [dB, 95 %]: LS 0.02, 1 and 2 0.04 | `metrology.SUPPLY_VOLTAGE_MAX_UNCERTAINTY_DB['2']  # 0.04` |
| `FIELD_IMMUNITY_ACCEPTANCE_LIMITS_DB` | `mapping` | **IEC 60942:2017 5.9.4.2, level change in a power- or radio-frequency field** [dB]: LS 0.10, 1 0.25, 2 0.45 | `metrology.FIELD_IMMUNITY_ACCEPTANCE_LIMITS_DB['1']  # 0.25` |
| `FIELD_IMMUNITY_MAX_UNCERTAINTY_DB` | `mapping` | **IEC 60942:2017 A.7.4.8, that level change** [dB, 95 %]: 0.05 for every class, the field measurement excluded | `metrology.FIELD_IMMUNITY_MAX_UNCERTAINTY_DB['LS']  # 0.05` |
| `ABBREVIATED_LEVEL_REDUCTIONS_DB` | `mapping` | **IEC 60942:2017 A.6.4.7, reduction of the Table 5 limits in the abbreviated test** [dB]: LS 0.05, 1 0.05, 2 0.10 | `metrology.ABBREVIATED_LEVEL_REDUCTIONS_DB['2']  # 0.1` |
| `ABBREVIATED_FREQUENCY_ACCEPTANCE_LIMITS_PERCENT` | `mapping` | **IEC 60942:2017 A.6.4.7, frequency limits of the abbreviated test** [%]: LS 0.5, 1 0.5, 2 1.3 | `metrology.ABBREVIATED_FREQUENCY_ACCEPTANCE_LIMITS_PERCENT['2']  # 1.3` |
| `adjustment_factors` | `function` | **Adjustment factors K(φ) of one plane of readings (IEC 61183:1994 Formulas (6), (7), (A.1), (A.2)).**<br>• `step_deg`: the angular step Δφ [°], dividing 180° into at least two steps<br>• `planes`: the number of planes n, Δα = 180°/n (Default: 2, the X-Y and X-Z planes of Annex A; 4 halves every factor, NOTE 2 of A.6; 1 doubles it, Formula (A.4))<br>• the 360/Δφ factors from 0°, read-only; with the poles in every plane's sum they add up to 1<br>• warns `SphereDivisionWarning` above the 3 % of A.1.6 | `metrology.adjustment_factors(10.0)[[0, 1, 9]].round(5)`<br><br>• `[0.00095 0.00378 0.02179]`, Table A.1 |
| `largest_element_fraction` | `function` | **The largest element a set of incidence angles divides the sphere into (IEC 61183 A.1.6, A.1.7).**<br>• `step_deg` [°], `planes` (Default: 2)<br>• the ring element nearest 90° or the polar cap, whichever is larger; one plane is judged on the two-plane division it stands for | `metrology.largest_element_fraction(10.0)  # 0.02179, the 2,2 % of A.1.7` |
| `SphereDivisionWarning` | `warning class` | **The angular step leaves an element larger than 3 % of the sphere.**<br>Emitted by `adjustment_factors`, `directivity_factor` and `axisymmetric_directivity_factor` (IEC 61183 A.1.6) | `warnings.simplefilter('error', metrology.SphereDivisionWarning)` |
| `directivity_factor` | `function` | **Directivity factor from readings in two or more planes (IEC 61183 Formula (A.3)).**<br>• `levels_db`: L(φ) [dB], one row per plane, each at φ = 0, Δφ, …, 360° − Δφ: `(2, 36)` for Annex A<br>• `reference_level_db`: L_rd [dB] (Default: None → the first plane's reading at 0°)<br>• the readings at 0° and 180° enter every plane's sum, so an omnidirectional meter reads γ = 1; counted once, 10 lg γ would come out 0,008 dB high for that meter and more for a directional one | `d = metrology.directivity_factor(levels)`<br><br>• `DirectivityFactor`; `d.directivity_index_db` |
| `axisymmetric_directivity_factor` | `function` | **Directivity factor of a rotationally symmetric meter from one plane (IEC 61183 Formula (A.4)).**<br>• `levels_db`: L(φ, h) [dB], 1-D, at φ = 0, Δφ, …<br>• `reference_level_db` [dB] (Default: None → the reading at 0°) | `metrology.axisymmetric_directivity_factor(levels[0])`<br><br>• `DirectivityFactor` |
| `equal_area_directivity_factor` | `function` | **Directivity factor from 38 equal-area elements (IEC 61183 Formula (A.5)).**<br>• `horizontal_levels_db`: 20 readings [dB] at the directions of `equal_area_incidence_angles`<br>• `vertical_levels_db`: 18 readings [dB], the same without the poles<br>• `reference_level_db` [dB] (Default: None → the horizontal reading at 0°) | `metrology.equal_area_directivity_factor(h_db, v_db)`<br><br>• `DirectivityFactor`, every weight 1/38 |
| `equal_area_incidence_angles` | `function` | **The 38 directions of the equal-area division (IEC 61183, note to A.1.8).**<br>• each direction halves its element's area in polar angle: φk = arccos[1 − (4k − 1)/19]<br>• returns (horizontal, vertical) [°], 20 and 18, read-only<br>• the note prints 77,9° and 282,1° where this gives 77,85° and 282,15° (errata) | `h, v = metrology.equal_area_incidence_angles()`<br>`h[4].round(1)  # 77.8` |
| `DirectivityFactor` | `dataclass` | **The directivity factor of a meter at one frequency.**<br>• `incidence_angles_deg`, `plane_angles_deg` [°], `levels_db` [dB], `weights`: one entry per reading, read-only<br>• `reference_level_db` [dB], `gamma`, `largest_element_fraction`, `formula` ('A.3' / 'A.4' / 'A.5'), each checked when built<br>• `.directivity_index_db` = 10 lg γ [dB], `.relative_levels_db` [dB]<br>• `.plot(view=)`: 'response' (polar, one curve per plane) / 'weights' | `d.gamma, d.directivity_index_db` |
| `random_incidence_sensitivity` | `function` | **Random-incidence sensitivity level, band by band (IEC 61183 Formulas (1), (A.6)).**<br>• `frequencies_hz` [Hz], increasing<br>• `free_field_level_db`: G_F = L_rd − L_o [dB]<br>• `directivity_index_db`: 10 lg γ [dB]; either may be one value for every band<br>• G_RI = G_F − 10 lg γ | `r = metrology.random_incidence_sensitivity([1000, 8000], 0.0, [0.05, 2.45])`<br><br>• `RandomIncidenceSensitivity` |
| `RandomIncidenceSensitivity` | `dataclass` | **G_F, 10 lg γ and G_RI at each frequency.**<br>• `frequencies_hz` [Hz], `free_field_level_db`, `directivity_index_db`, `random_incidence_level_db` [dB], read-only<br>• `.correction_db` = G_RI − G_F [dB]<br>• `.plot(view=)`: 'levels' / 'correction' | `r.correction_db  # [-0.05 -2.45]` |
| `diffuse_field_sensitivity` | `function` | **Diffuse-field sensitivity level by comparison with a reference meter (IEC 61183 Formulas (8) to (11)).**<br>• `frequencies_hz` [Hz]; `indicated_level_db` L_D and `reference_indicated_level_db` L_D,ref [dB]<br>• exactly one of `reference_random_incidence_level_db` (9), `reference_free_field_level_db` (10) or `reference_pressure_level_db` (11) [dB]<br>• `reference_directivity_index_db` with (10), `reference_diffuse_pressure_difference_db` with (11) [dB] (Default: None → `IEC61183_TABLE_B1` at each preferred frequency) | `metrology.diffuse_field_sensitivity(f, l_d, l_ref, reference_pressure_level_db=0.0)`<br><br>• `DiffuseFieldSensitivity` |
| `DiffuseFieldSensitivity` | `dataclass` | **The comparison of IEC 61183 clause 5, route by route.**<br>• `frequencies_hz` [Hz], `indicated_level_db`, `reference_indicated_level_db`, `reference_sensitivity_level_db`, `reference_correction_db` [dB], `route` ('random_incidence' / 'free_field' / 'pressure')<br>• `.level_difference_db` ΔG_D, `.reference_diffuse_field_level_db` G_D,ref, `.diffuse_field_level_db` G_D [dB]<br>• `.plot()`: the three against frequency | `dd.diffuse_field_level_db` |
| `IEC61183_TABLE_B1` | `mapping` | **IEC 61183:1994 Table B.1, the type LS2aP/LS2F microphone, keyed by preferred frequency [Hz].**<br>• 25 Hz to 20 kHz; the row printed "25 to 800" at each preferred frequency it covers<br>• each value a `ReferenceMicrophoneRow`; rounded to 0,05 dB by the table | `metrology.IEC61183_TABLE_B1[8000.0].directivity_index_db  # 2.45` |
| `ReferenceMicrophoneRow` | `dataclass` | **One row of Table B.1.**<br>• `directivity_index_db`: 10 lg γ_ref [dB]<br>• `diffuse_pressure_difference_db`: Δ_DP, diffuse-field less pressure sensitivity level [dB] | `metrology.IEC61183_TABLE_B1[16000.0].diffuse_pressure_difference_db  # 3.05` |
| `exact_frequencies` | `function` | **Exact base-ten frequencies between two limits (IEC 62585 Annex H, Formula (H.1)).**<br>• `lowest_hz`, `highest_hz` [Hz], inclusive<br>• `fraction`: the step-width designator b (Default: 12, the one-twelfth octaves of Table H.1; 1 the exact octaves, 3 the thirds)<br>• f_x = 1000 · 10^(3x/10b) [Hz], read-only | `metrology.exact_frequencies(1000, 10000)[31] / 1000  # 5.956621` |
| `adjustment_value` | `function` | **The adjustment value at the calibration check frequency (IEC 62585 Annex A).**<br>• `frequencies_hz` [Hz], the check frequency among them; `free_field_indicated_level_db` [dB] before the adjustment; `calibrator_reading_db`: L4′ on the calibrator at the same sensitivity [dB]<br>• keyword-only: `calibrator_level_db` L1 [dB]; `incident_level_db` [dB] (Default: None → L1); `tolerance_db` [dB], infinite where a band does not pull the fit (Default: None → equal weights); `pressure_indicated_level_db` [dB] (Default: None); `check_frequency_hz` (Default: 1000)<br>• least-squares fit s = −Σ w d / Σ w, w = 1/t² (the module's reading of a text with no formula); ΔL = L1 − (L4′ + s) | `a = metrology.adjustment_value(f, l_ff, 94.35, calibrator_level_db=94.0)`<br><br>• `AdjustmentValue`; `a.adjustment_db` |
| `AdjustmentValue` | `dataclass` | **The free-field response before the adjustment and what the fit makes of it.**<br>• `frequencies_hz` [Hz], `free_field_deviation_db` [dB], `calibrator_level_db`, `calibrator_reading_db` [dB], `check_frequency_hz` [Hz], `tolerance_db`, `pressure_deviation_db` [dB] or None, read-only<br>• derived, never stored: `.weights`, `.sensitivity_adjustment_db` s, `.calibrator_indicated_level_db` L4, `.adjustment_db` ΔL, `.check_frequency_offset_db` L2 − L1, `.free_field_indicated_level_db` L2, `.pressure_indicated_level_db` L3, `.pressure_to_free_field_correction_db` [dB]<br>• `.plot()`: the deviation before and after, with the tolerances | `a.sensitivity_adjustment_db, a.check_frequency_offset_db` |
| `sound_calibrator_correction` | `function` | **Free-field corrections for a multi-frequency sound calibrator (IEC 62585 Annex D, Formula (D.7)).**<br>• `frequencies_hz` [Hz]; `slm_free_field_level_db`, `reference_free_field_level_db`, `slm_calibrator_level_db`, `reference_calibrator_level_db` [dB]: L_ind1 to L_ind4, one value per frequency or one row per determination<br>• keyword-only: `reference_free_field_correction_db` C_FF,RM from IEC/TS 61094-7 [dB]; `free_field_level_difference_db`, `calibrator_level_difference_db` [dB] (Default: 0); `microphones`: the microphone of each row, so the range is taken over the microphones (Default: None, each row its own) | `c = metrology.sound_calibrator_correction(f, l1, l2, l3, l4, reference_free_field_correction_db=c_rm)`<br><br>• `FreeFieldCorrection`, clause 12 |
| `comparison_coupler_correction` | `function` | **Free-field corrections for a comparison coupler (IEC 62585 Annex E, Formula (E.6)).**<br>• as `sound_calibrator_correction`, with `slm_coupler_level_db` and `reference_coupler_level_db` [dB], named by what each reading is of (Formula (E.6) exchanges the two labels of Figure E.1, an erratum)<br>• keyword-only: `coupler_level_difference_db`: the level at the meter less that at the reference [dB] (Default: 0); `microphones` (Default: None) | `metrology.comparison_coupler_correction(f, l1, l2, l_slm, l_rm, reference_free_field_correction_db=c_rm)`<br><br>• `FreeFieldCorrection`, clause 13 |
| `electrostatic_actuator_correction` | `function` | **Free-field corrections normalised at the check frequency, for an electrostatic actuator (IEC 62585 Annex F, Formula (F.13)).**<br>• `frequencies_hz` [Hz]; `slm_free_field_level_db`, `reference_free_field_level_db`, `slm_actuator_level_db` [dB]<br>• keyword-only: `reference_sensitivity_level_db` S_RM [dB re 1 V/Pa]; `reference_channel_gain_db` G_RC [dB] (Default: 0); `actuator_level_db` L_EA [dB] (Default: 0); `free_field_level_difference_db` [dB] (Default: 0); `check_frequency_hz` f0 (Default: 1000); `microphones` (Default: None)<br>• zero at f0 | `metrology.electrostatic_actuator_correction(f, l1, l2, l3, reference_sensitivity_level_db=s_rm)`<br><br>• `FreeFieldCorrection`, clause 14 |
| `FreeFieldCorrection` | `dataclass` | **The corrections of every determination, their mean and their range.**<br>• `frequencies_hz` [Hz], `corrections_db` (determinations × frequencies) [dB], `reference_correction_db` [dB], `source` ('sound_calibrator' / 'comparison_coupler' / 'electrostatic_actuator'), `check_frequency_hz` (actuator only), `microphones` (one label per row, or None), read-only<br>• `.correction_db` mean, `.microphone_corrections_db` the mean of each microphone, `.range_db` over the microphones, largest less smallest [dB], `.determinations`, `.microphone_count`, `.formula` ('D.7' / 'E.6' / 'F.13'), `.clause` (12 / 13 / 14)<br>• `.plot()`: the mean, the range band and the reference's part | `c.correction_db, c.range_db, c.clause` |
| `correction_uncertainty_budget` | `function` | **The uncertainty budget of a correction, 15 components of Table I.1 (IEC 62585 Annex I).**<br>• `values_db`: the value of each component as Table I.2 states it, keyed 'a1' to 'a15' [dB]<br>• keyword-only: `repeatability_dof` of a15; `frequency_hz` [Hz]; `correction_db` [dB] (Default: 0); `static_pressure_kpa` [kPa]: below 97 adds the clause 6 component, outside 80 to 105 refused (Default: None); `additional_components`: further `Quantity` objects (Default: none); `coverage` (Default: 0.95)<br>• on `combine_uncertainty`, sensitivities ±1, Welch-Satterthwaite dof, Student k | `b = metrology.correction_uncertainty_budget(table_i2, repeatability_dof=2, frequency_hz=1000)`<br><br>• `b.coverage_factor  # 2.042 (Table I.2 prints 2,11, an erratum)` |
| `CorrectionUncertaintyBudget` | `dataclass` | **One budget at one frequency.**<br>• `frequency_hz` [Hz], `descriptors`, `symbols`, `values_db` [dB], `divisors`, `dofs`, `uncertainty` (the `UncertaintyResult`, refused unless it is the combination of the columns), `coverage`, read-only<br>• `.standard_uncertainties_db`, `.combined_uncertainty_db`, `.expanded_uncertainty_db` [dB], `.effective_dof`, `.coverage_factor`, `.correction_db`<br>• `.plot()`: one bar per component, Type A apart, with u_c, k and U | `b.combined_uncertainty_db, b.effective_dof  # 0.0590 29.98` |
| `IEC62585_TABLE_I1` | `mapping` | **IEC 62585:2012 Table I.1, the likely components of the uncertainty of a correction, keyed 'a1' to 'a15'.**<br>• each value an `UncertaintyComponentRow`: the symbol, the description, the distribution and the divisor (√3 rectangular, 2 for C_FF,RM, 1 for the repeatability) | `metrology.IEC62585_TABLE_I1["a7"].divisor  # 2.0` |
| `UncertaintyComponentRow` | `dataclass` | **One row of Table I.1.**<br>• `symbol`, `description`, `distribution` ('rectangular' / 'normal'), `divisor` | `metrology.IEC62585_TABLE_I1["a15"].symbol  # 'Repeatability'` |
| `maximum_expanded_uncertainty` | `function` | **The maximum permitted expanded uncertainty of a correction (IEC 62585 clauses 9 to 14).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `clause`, 9 to 14 (10 from 63 Hz only)<br>• 0,25 dB to 4 kHz and 0,35 dB above (9); 0,25, 0,35 to 8 kHz, 0,45 (10); 0,20, 0,30 (11); 0,25, 0,35 below 10 kHz, 0,50 from 10 kHz (12 to 14) [dB], read-only; a frequency within 2 % of a boundary reads as it | `metrology.maximum_expanded_uncertainty([3981.07, 10000.0], clause=12)  # [0.25 0.5]` |
| `verify_correction_uncertainty` | `function` | **Verify the expanded uncertainties of a set of corrections against the maxima of their clause (IEC 62585 clauses 5, 9 to 14).**<br>• `frequencies_hz` [Hz]; `expanded_uncertainty_db` [dB]<br>• keyword-only: `clause`; `correction_db` [dB] and `coverage_factor`, for the clause 15 documentation (Default: None); `correction_range_db` [dB], clauses 12 to 14 only (Default: None)<br>• a value equal to its maximum passes, and one that reaches it through floating-point arithmetic | `v = metrology.verify_correction_uncertainty(f, u, clause=c.clause, correction_range_db=c.range_db)`<br><br>• `CorrectionUncertaintyVerification` |
| `CorrectionUncertaintyVerification` | `dataclass` | **The verdict of one clause on a set of corrections.**<br>• `clause`, `frequencies_hz` [Hz], `expanded_uncertainty_db`, `correction_db`, `coverage_factor`, `correction_range_db` [dB], read-only<br>• `.maximum_uncertainty_db` [dB], derived from the clause<br>• `.passes`; `bool()` raises; `.uncertainty_passes`, `.range_passes`, `.margin_db`, `.failing_frequencies_hz`, `.subject`<br>• `.plot()`: U and the range against the stepped maximum<br>• `.report(path, *, metadata=None)`: one-page PDF fiche of clause 15 n) and o) | `v.passes`<br>`v.report("iec62585.pdf")` |
| `verify_sound_level_meter_periodic` | `function` | **The periodic tests of a sound level meter, IEC 61672-3:2013, on a laboratory's results.**<br>• `meter_class`: 1 or 2<br>• `measurements`: a `SoundLevelMeterPeriodicMeasurements`<br>• keyword-only: `pattern_approval_public`, whether the model's IEC 61672-2 approval is public (Default: False); `corrections_in_manual`, whether the acoustical correction data came from the instruction manual (Default: False); `features`, a `SoundLevelMeterFeatures` declaring the optional features the meter has or lacks (Default: None, none declared)<br>Each clause (12 to 21) judged by `verify_conformance` with the limits of IEC 61672-1:2013 and the maxima of its Table B.1; the statement is the one Clause 22 r), s) or t) prescribes | `res = metrology.verify_sound_level_meter_periodic(1, record)`<br><br>• `SoundLevelMeterPeriodicVerification` |
| `SoundLevelMeterPeriodicMeasurements` | `dataclass` | **What a laboratory measured in the periodic tests of a sound level meter**, each graded result with its expanded uncertainty under the matching `*_uncertainties_db` / `*_uncertainty_db` field, every field keyword-only and `None` when not measured:<br>• records: the environment (7), `calibration_check_initial_db` and `calibration_check_adjusted_db` (10), `self_noise_microphone_db` and `self_noise_electrical_db` (11)<br>• `acoustic_weighting_deviations_db` at 125 Hz and 8 kHz (12) and `electrical_weighting_deviations_db` keyed `'A'` / `'C'` / `'Z'` at the octaves of 13.4 (13), each with its uncertainty without the manufacturer's correction data (`*_without_correction_data_db`, 4.4) optional<br>• `weighting_at_1khz_deviations_db` keyed `'C'` / `'Z'` and `time_weighting_at_1khz_deviations_db` keyed `'S'` / `'eq'` (14); `long_term_stability_db` (15)<br>• clause 16 at 8 kHz: `linearity_deviations_db` with `linearity_levels_db`, the anticipated level of each step, and the procedure of 16.2 and 16.3: `linear_operating_range_db` (lower, upper) [dB], `linearity_starting_point_db`, and `linearity_overload_level_db` and `linearity_under_range_level_db`, the steps that first indicated overload and under-range<br>• clause 17 at 1 kHz: `range_linearity_deviations_db`, a mapping `{'17.3': ..., '17.4': ...}`: 17.3 one value per level range besides the reference one (NaN where the reference level is not displayed), 17.4 one value per level range, the reference one first<br>• `toneburst_responses_db` keyed `'F'` / `'S'` / `'E'` (18); `c_peak_differences_db` with `c_peak_overload_indicated` (19); `overload_difference_db` with `overload_latched` (20); `high_level_stability_db` (21)<br>• NaN where a result was not measured | `metrology.SoundLevelMeterPeriodicMeasurements(range_linearity_deviations_db={'17.3': [0.1], '17.4': [0.1, -0.2]}, range_linearity_uncertainties_db={'17.3': [0.18], '17.4': [0.18, 0.18]})` |
| `SoundLevelMeterFeatures` | `dataclass` | **Which optional design features of IEC 61672-1 a meter has, and how many level ranges, for the completeness of IEC 61672-3 8.1.**<br>• keyword-only, each `True` (the meter has it), `False` (it lacks it) or `None` (not declared, the default): `c_weighting`, `z_weighting`, `f_time_weighting`, `s_time_weighting`, `time_averaged`, `sound_exposure_level`, `c_weighted_peak`<br>• keyword-only `level_ranges`: the number of level ranges, a whole number from 1 (1 takes Clause 17 out; more is how many 17.4 covers, and 17.3 besides the reference one), or `None` (not declared, the default)<br>• a feature declared present owes its tests; one declared absent takes its clauses out, and with it the one IEC 61672-1 makes depend on it: no C weighting means no C-weighted peak (5.1.10), no F means no S (5.1.9); one neither declared nor shown by a result keeps the verdict from passing<br>• refuses C-weighted peak without C (5.1.10), S without F (5.1.9), and a meter with no indication, F, a time-averaged display and sound exposure level all `False` (5.1.9) | `metrology.SoundLevelMeterFeatures(level_ranges=1, c_weighted_peak=False)` |
| `SoundLevelMeterPeriodicRequirement` | `dataclass` | **One requirement of IEC 61672-3, judged on each of its results.**<br>• `name`, `clause`, `tables`, `labels`, `verifications` (one `ConformanceVerification` each, on the deviation from the design goal), `checks` (the yes/no requirements of 16.4, 19 and 20), `over_maximum_by_correction_data` (4.4)<br>• `passes`, `unusable` (4.3), `failed`, `title`<br>• no truth value; `.plot()` draws Figure C.1, or the margins for Clause 13 | `res.requirement('toneburst').failed` |
| `SoundLevelMeterPeriodicVerification` | `dataclass` | **The IEC 61672-3:2013 verdict on the periodic tests of a sound level meter.**<br>• `meter_class`, `pattern_approval_public`, `corrections_in_manual`, `measurements`, `requirements`, `features`; `requirement(name)`<br>• `missing` and `incomplete` (what 8.1 makes a complete test), `undeclared` (the optional features neither declared nor shown), `not_applicable` (the clauses the declared features take out), `conditions_outside` (7.1), `unusable` (4.3), `over_maximum_by_correction_data` (4.4), `failed`<br>• `passes`; `statement`, the text of 22 r), s) or t), or a notice for a test outside 7.1 (checked first), an unusable result or an incomplete record<br>• no truth value; `.plot()` gives each graded clause one slot: every result's margin to its limits a dash, and the result that decides the clause marked over them | `res.passes, res.statement` |
| `SLM_PERIODIC_REQUIREMENTS` | `constant` | **The requirements `verify_sound_level_meter_periodic` grades**, in the order of IEC 61672-3: `'acoustic_weighting'`, `'electrical_weighting'`, `'weighting_at_1khz'`, `'time_weighting_at_1khz'`, `'long_term_stability'`, `'level_linearity'`, `'range_linearity'`, `'toneburst'`, `'c_peak'`, `'overload'`, `'high_level_stability'` | `metrology.SLM_PERIODIC_REQUIREMENTS[7]  # 'toneburst'` |
| `IEC61672_TABLE_4` | `mapping` | **IEC 61672-1:2013 Table 4, the reference 4 kHz toneburst responses and their limits**, keyed `'F'` (L_AFmax − L_A, 12 rows), `'S'` (L_ASmax − L_A, 9 rows) and `'E'` (L_AE − L_A, 12 rows), each a tuple of `ToneburstReference` | `metrology.IEC61672_TABLE_4['F'][-1].reference_response_db  # -27.0` |
| `ToneburstReference` | `dataclass` | **One row of Table 4.**<br>• `duration_ms`, `reference_response_db` [dB], `class_1_limits_db`, `class_2_limits_db` as `(lower, upper)` [dB]; `limits_db(meter_class)` | `metrology.IEC61672_TABLE_4['F'][-1].limits_db(2)  # (-5.0, 1.5)` |
| `IEC61672_TABLE_5` | `tuple` | **IEC 61672-1:2013 Table 5, the reference differences L_Cpeak − L_C and their limits**, five `PeakReference` rows in the printed order; the periodic test uses the last three | `metrology.IEC61672_TABLE_5[2].reference_difference_db  # 3.4` |
| `PeakReference` | `dataclass` | **One row of Table 5.**<br>• `signal` ('one cycle' / 'positive half cycle' / 'negative half cycle'), `nominal_frequency_hz` [Hz], `reference_difference_db` [dB], `class_1_limits_db`, `class_2_limits_db` [dB]; `limits_db(meter_class)` | `metrology.IEC61672_TABLE_5[3].limits_db(1)  # (-1.0, 1.0)` |
| `IEC61672_TABLE_B1` | `tuple` | **IEC 61672-1:2013 Table B.1, the maximum-permitted uncertainties for a coverage probability of 95 %**, 32 `MaxUncertaintyRow` in the printed order, the F and S decay rates of 5.8.2 as two rows in dB/s | `[r.max_uncertainty for r in metrology.IEC61672_TABLE_B1 if r.reference == '5.8.3']  # [0.2]` |
| `MaxUncertaintyRow` | `dataclass` | **One row of Table B.1.**<br>• `requirement`, `reference` (as printed), `max_uncertainty` [`unit`], `unit` ('dB' / 'dB/s'), `lower_hz`, `upper_hz`, `includes_lower` for the rows banded by frequency; `contains(frequency_hz)` | `metrology.IEC61672_TABLE_B1[12].contains(16000.0)  # True` |
| `ACOUSTIC_TEST_FREQUENCIES_HZ` | `constant` | **IEC 61672-3:2013 12.7: 125 Hz and 8 kHz**, where the acoustical test determines the weighting relative to 1 kHz | `metrology.ACOUSTIC_TEST_FREQUENCIES_HZ  # (125.0, 8000.0)` |
| `ELECTRICAL_TEST_FREQUENCIES_HZ` | `mapping` | **IEC 61672-3:2013 13.4 by class**: the nine octaves from 63 Hz to 16 kHz for class 1, the eight to 8 kHz for class 2 | `metrology.ELECTRICAL_TEST_FREQUENCIES_HZ[2][-1]  # 8000.0` |
| `TONEBURST_TEST_DURATIONS_MS` | `mapping` | **IEC 61672-3:2013 18.5 to 18.7**: 200 ms, 2 ms and 0.25 ms for `'F'` and `'E'`, 200 ms and 2 ms for `'S'` | `metrology.TONEBURST_TEST_DURATIONS_MS['S']  # (200.0, 2.0)` |
| `PERIODIC_TEST_ENVIRONMENT` | `mapping` | **IEC 61672-3:2013 7.1**: 80 kPa to 105 kPa, 20 °C to 26 °C, 25 % to 70 %, keyed by the record field of each | `metrology.PERIODIC_TEST_ENVIRONMENT['air_temperatures_c']  # (20.0, 26.0)` |
| `simultaneous_comparison` | `function` | **Sensitivity level by comparison with both microphones in the field at once (IEC 61094-5 5.1.2 and Annex C; IEC 61094-8 5.3).**<br>• `frequencies_hz` [Hz]; `reference_sensitivity_level_db` L_ref [dB re 1 V/Pa]<br>• `channel_difference_db` L_C12, reference on channel 1, and `interchanged_channel_difference_db` L_C21 [dB], one row per determination; 20 lg R_V = -(L_C12 - L_C21)/2 (C.3); required for `field="pressure"` (Default: None)<br>• keyword-only: `field` ('pressure' / 'free_field', Default: 'pressure'); `pressure_level_difference_db` 20 lg R_P [dB] (Default: 0); `corrections_db` by name [dB]; `reference_environment` (added) and `test_environment` (subtracted), `EnvironmentalSensitivityCorrection`; `reference_free_field_difference_db` [dB], free field only; `expanded_uncertainty_db` [dB] (all Default: None)<br>• `phase`: a `SimultaneousComparisonPhase` (5.1.1) (Default: None, a calibration of the level alone) | `c = metrology.simultaneous_comparison(f, l_ref, l_c12, l_c21)`<br><br>• `ComparisonCalibration` |
| `SimultaneousComparisonPhase` | `dataclass` | **The phase inputs of a simultaneous comparison (IEC 61094-5 5.1.1, IEC 61094-8 5.1), all keyword-only.**<br>• `reference_sensitivity_phase_deg` φ_ref [°]<br>• `channel_phase_difference_deg` Φ_C12 and `interchanged_channel_phase_difference_deg` Φ_C21 [°], one row per determination, the second given exactly as the interchanged level reading is (Default: None); arg R_V = -(Φ_C12 - Φ_C21)/2 taken in one turn<br>• `pressure_phase_difference_deg` arg R_P [°] (Default: None, 0) | `metrology.SimultaneousComparisonPhase(reference_sensitivity_phase_deg=phi_ref, channel_phase_difference_deg=p12, interchanged_channel_phase_difference_deg=p21)` |
| `sequential_comparison` | `function` | **Sensitivity level by comparison with the microphones in the field in turn (IEC 61094-5 5.1.3 and Annex B; IEC 61094-8 5.2 and A.2).**<br>• `frequencies_hz` [Hz]; `reference_sensitivity_level_db` [dB re 1 V/Pa]; `reference_output_level_db` 20 lg V_ref, `test_output_level_db` 20 lg V_test [dB], one row per determination<br>• keyword-only: `monitor`: a `MonitorReadings` (Default: None, no monitor); 20 lg R_V = 20 lg(V_test/V_mon,2) - 20 lg(V_ref/V_mon,1)<br>• `field`, `pressure_level_difference_db`, `corrections_db`, `reference_environment`, `test_environment`, `reference_free_field_difference_db`, `expanded_uncertainty_db` as in `simultaneous_comparison`<br>• `phase`: a `SequentialComparisonPhase` (Default: None, a calibration of the level alone; the monitor's phases need it) | `metrology.sequential_comparison(f, l_ref, v_ref, v_test, field="free_field")`<br><br>• `ComparisonCalibration` |
| `MonitorReadings` | `dataclass` | **The monitor microphone's readings in a sequential comparison (IEC 61094-5 5.1.3, IEC 61094-8 A.2), all keyword-only.**<br>• `reference_level_db` 20 lg V_mon,1 and `test_level_db` 20 lg V_mon,2 [dB], in the measurements of the reference and of the test microphone, one row per determination<br>• `reference_phase_deg` φ_mon,1 and `test_phase_deg` φ_mon,2 [°], both or neither (Default: None) | `metrology.MonitorReadings(reference_level_db=l_m1, test_level_db=l_m2)` |
| `SequentialComparisonPhase` | `dataclass` | **The phase inputs of a sequential comparison (IEC 61094-5 5.1.1, IEC 61094-8 5.1), all keyword-only.**<br>• `reference_sensitivity_phase_deg` φ_ref [°]<br>• `reference_output_phase_deg` and `test_output_phase_deg` [°], one row per determination, each taken re the monitor's phase when the `MonitorReadings` carries it; arg R_V = (φ_test - φ_mon,2) - (φ_ref - φ_mon,1)<br>• `pressure_phase_difference_deg` arg R_P [°] (Default: None, 0) | `metrology.SequentialComparisonPhase(reference_sensitivity_phase_deg=phi_ref, reference_output_phase_deg=p_ref, test_output_phase_deg=p_test)` |
| `ComparisonCalibration` | `dataclass` | **The sensitivity level of a microphone calibrated by comparison, L_test = L_ref + 20 lg R_V - 20 lg R_P + Σ C_j (IEC 61094-5 D.2).**<br>• `frequencies_hz` [Hz], `reference_sensitivity_level_db`, `output_level_differences_db` (determinations × frequencies), `pressure_level_difference_db` [dB], `corrections_db` (read-only mapping) [dB], `field`, `excitation`, `expanded_uncertainty_db` [dB] or None; keyword-only `reference_sensitivity_phase_deg`, `output_phase_differences_deg` (determinations × frequencies), `pressure_phase_difference_deg` [°], all None for a calibration of the level alone<br>• `.sensitivity_level_db` [dB re 1 V/Pa], `.sensitivity_mv_per_pa` [mV/Pa], `.output_level_difference_db`, `.correction_db` [dB], `.determinations`, `.standard`; `.output_phase_difference_deg` and `.sensitivity_phase_deg` φ_test = φ_ref + arg R_V - arg R_P [°] (None without phases)<br>• `.plot(quantity='level' / 'phase')`: L_test with its U band and the reference's level (its free-field level, L_ref plus the free-field difference, against a pressure-calibrated reference in a free field), or φ_test and φ_ref | `c.sensitivity_level_db, c.standard  # ..., 'IEC 61094-5:2016'` |
| `environmental_sensitivity_correction` | `function` | **First-order correction of a sensitivity level between two sets of environmental conditions (IEC 61094-5 6.6, IEC 61094-8 7.6).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `static_pressure_kpa` [kPa], `temperature_c` [°C], `relative_humidity_percent` [%], where the level is wanted; `static_pressure_coefficient_db_per_kpa` [dB/kPa] and `temperature_coefficient_db_per_k` [dB/K], the microphone's own (IEC 61094-2 Annex D units); `humidity_coefficient_db_per_percent` [dB/%] (Default: 0); `reference_static_pressure_kpa`, `reference_temperature_c`, `reference_relative_humidity_percent` (Default: 101.325 kPa, 23.0 °C, 50 %, clause 4) | `metrology.environmental_sensitivity_correction(f, static_pressure_kpa=97.0, temperature_c=26.0, relative_humidity_percent=40.0, static_pressure_coefficient_db_per_kpa=-0.005, temperature_coefficient_db_per_k=0.003)`<br><br>• `EnvironmentalSensitivityCorrection` |
| `EnvironmentalSensitivityCorrection` | `dataclass` | **C_env = δp (p_s - p_s,0) + δt (t - t_0) + δH (H - H_0), at each frequency.**<br>• `frequencies_hz` [Hz], the conditions and the reference conditions, the three coefficient columns, read-only<br>• `.static_pressure_term_db`, `.temperature_term_db`, `.humidity_term_db`, `.correction_db` [dB]<br>• `.plot()`: the three terms and the total | `e.correction_db` |
| `jig_diameter_correction` | `function` | **Corrections of a WS3 microphone against an LS2aP in the jig of Figure A.4 (IEC 61094-5 Table A.1).**<br>• `frequencies_hz` [Hz], rows of the table, an exact base-ten frequency within 2 % reading as its row (Default: None, the 14 rows from 1 kHz to 20 kHz)<br>• refuses a frequency the table does not print | `metrology.jig_diameter_correction([8000.0]).correction_db  # [-0.235]`<br><br>• `JigDiameterCorrection` |
| `JigDiameterCorrection` | `dataclass` | **The Table A.1 corrections at the frequencies asked for.**<br>• `frequencies_hz` [Hz], `correction_db` [dB], read-only<br>• `.expanded_uncertainty_db` [dB], a tenth of the correction (NOTE); `.standard_uncertainty_db` [dB], its half, read with the k = 2 of 7.9 and D.2 since the 10 % comes without one, the special-case component of Table D.1<br>• `.plot()`: the corrections and their band | `j.expanded_uncertainty_db` |
| `diameter_sound_field_correction` | `function` | **The correction of a test microphone smaller than its reference, facing it across a narrow gap, by the model IEC 61094-5 6.5 refers to (Barham et al. 2014, the origin of Table A.1).**<br>• `frequencies_hz` [Hz], each below both resonance frequencies<br>• keyword-only: `reference_radius_m`, `test_diaphragm_radius_m`, `test_outer_radius_m`, `separation_m` [m]; `reference_resonance_frequency_hz`, `test_resonance_frequency_hz` [Hz]; `temperature_c` [°C] (Default: 23.0), `static_pressure_kpa` [kPa] (Default: 101.325), `relative_humidity_percent` [%] (Default: 50), the Annex F air its speed of sound comes from; `gas` (Default: None)<br>• read with Formula (4) less 1 and the annulus of Formula (2) from the outer radius, the readings that give Table A.1 (an erratum) | `metrology.diameter_sound_field_correction([20000.0], reference_radius_m=4.65e-3, test_diaphragm_radius_m=2.065e-3, test_outer_radius_m=2.975e-3, separation_m=0.5e-3, reference_resonance_frequency_hz=22e3, test_resonance_frequency_hz=100e3).correction_db  # [-1.434]`<br><br>• `DiameterSoundFieldCorrection` |
| `DiameterSoundFieldCorrection` | `dataclass` | **The model's correction for microphones of different diameters.**<br>• `frequencies_hz` [Hz], `ratio` and `doubled_separation_ratio` R_P (complex), read-only; the geometry and `speed_of_sound` [m/s]<br>• `.correction_db` [dB], -20 lg\|R_P\|, added to the test microphone's level; `.doubled_separation_correction_db` [dB]; `.separation_change_db` [dB], the change A.2 names as approximately the uncertainty of Table A.1; `.phase_difference_deg` [°]<br>• `.plot()`: the correction and the correction at twice the separation | `model.separation_change_db` |
| `verify_jig_or_coupler` | `function` | **Validate a jig or a coupler: a pressure calibration made in it against another calibration of the same microphone, by comparison elsewhere or by reciprocity (IEC 61094-5 6.7).**<br>• `calibration`: the `ComparisonCalibration` from the jig or coupler; `validation`: a `ComparisonCalibration` or a `ReciprocityCalibration`, both in a pressure field and with an expanded uncertainty<br>• keyword-only: `microphone`, the index of the microphone in a reciprocity calibration (Default: None); `shared_standard_uncertainty_db`, the standard uncertainty [dB] the two calibrations share, a common reference microphone or chain, one value or one per frequency of `calibration` (Default: 0, independent)<br>• compared at the frequencies the two share; agreement within the expanded uncertainty of the difference, the library's reading (the clause prints no criterion): the root-sum-square of the two less the shared part, `U_Delta = sqrt(U_cal^2 + U_val^2 - 2 (k u_sh)^2)`, that is `k = 2` times the root of `u_cal^2 + u_val^2 - 2 u_sh^2` (GUM 5.2.2 with the covariance of F.1.2.3)<br>• only a part that enters both levels with the same sign and size: the pairs through the third microphone of a joint reciprocity calibration enter with opposite signs and are not taken<br>• raises ValueError for a shared part above either calibration's standard uncertainty | `v = metrology.verify_jig_or_coupler(jig, coupler, shared_standard_uncertainty_db=0.025)`<br><br>• `JigCouplerVerification` |
| `JigCouplerVerification` | `dataclass` | **The verdict on a jig or a coupler.**<br>• `frequencies_hz` [Hz]; `calibration_level_db`, `validation_level_db` [dB re 1 V/Pa]; `calibration_uncertainty_db`, `validation_uncertainty_db` [dB]; `validation` ('comparison' / 'reciprocity'); `unvalidated_frequencies_hz` [Hz]; keyword-only `shared_standard_uncertainty_db` [dB] (Default: 0), read-only<br>• `.difference_db`, `.expanded_uncertainty_db` [dB], `.normalised_difference`, `.correlation_coefficient`, `.agrees`, `.failing_frequencies_hz` [Hz]<br>• `.passes`: every shared frequency agrees; `bool()` raises<br>• `.plot()`: the difference inside the band of its expanded uncertainty, the independent band dotted when a part is shared | `v.passes`, `v.failing_frequencies_hz` |
| `comparison_uncertainty_budget` | `function` | **The uncertainty budget of a comparison calibration at one frequency (IEC 61094-5 Annex D; IEC 61094-8 8.8, Table 2).**<br>• `standard_uncertainties_db`: each component a standard uncertainty [dB] or a `Quantity`, keyed as `IEC61094_5_TABLE_D1` (pressure) or `IEC61094_8_TABLE_2` (free field); a subset is allowed<br>• keyword-only: `frequency_hz` [Hz]; `field` (Default: 'pressure'); `additional_components`: named `Quantity` objects (Default: none); `coverage_factor` (Default: 2)<br>• on `combine_uncertainty`, sensitivities 1, U = k u_c | `b = metrology.comparison_uncertainty_budget(d1, frequency_hz=2000.0)`<br><br>• `b.expanded_uncertainty_db  # 0.087 (D.3 prints 0,08, an erratum)` |
| `ComparisonUncertaintyBudget` | `dataclass` | **One comparison budget at one frequency.**<br>• `frequency_hz` [Hz], `field`, `names`, `components`, `standard_uncertainties_db` [dB], `uncertainty` (the `UncertaintyResult`, refused unless it is their root-sum-square), `coverage_factor`<br>• `.combined_uncertainty_db`, `.expanded_uncertainty_db`, `.linear_combined_uncertainty_db` [dB], `.standard`<br>• `.plot()`: one bar per component, with u_c, k and U | `b.combined_uncertainty_db  # 0.0437` |
| `IEC61094_5_TABLE_D1` | `mapping` | **IEC 61094-5:2016 Table D.1, the example budget at 2 kHz, keyed 'reference', 'capacitance', 'non_linearity', 'impedance', 'polarizing_voltage', 'repeatability', 'drift', 'rounding'.**<br>• each value a `ComparisonUncertaintyRow` with the printed standard uncertainty and, for the seven rows that state one, the stated value and its divisor (√3 or 2); the repeatability states none | `metrology.IEC61094_5_TABLE_D1["drift"].standard_uncertainty_db  # 0.017` |
| `IEC61094_8_TABLE_2` | `mapping` | **IEC 61094-8:2012 Table 2, the 12 typical uncertainty components, keyed 'reference' to 'repeatability'.**<br>• each value a `ComparisonUncertaintyRow` with its subclause references; the table prints no values | `metrology.IEC61094_8_TABLE_2["positioning"].subclauses  # ('7.3', '8.4')` |
| `ComparisonUncertaintyRow` | `dataclass` | **One row of Table D.1 or Table 2.**<br>• `component` as printed, `subclauses`, `stated_db` [dB], `divisor`, `standard_uncertainty_db` [dB] (the last three None for Table 2; `stated_db` and `divisor` None for the repeatability of Table D.1) | `metrology.IEC61094_5_TABLE_D1["reference"].divisor  # 2.0` |
| `IEC61094_5_TABLE_A1` | `mapping` | **IEC 61094-5:2016 Table A.1, the WS3 corrections in the jig of Figure A.4, keyed by frequency [Hz].**<br>• 1 kHz to 20 kHz, -0.004 dB to -1.443 dB | `metrology.IEC61094_5_TABLE_A1[20000.0]  # -1.443` |
| `IEC61094_8_TABLE_1` | `mapping` | **IEC 61094-8:2012 Table 1, the ways the reference microphone can be calibrated, keyed 'primary_free_field', 'primary_pressure', 'secondary_pressure', 'secondary_free_field', 'electrostatic_actuator'.**<br>• each value a `ReferenceCalibrationRow` | `metrology.IEC61094_8_TABLE_1["primary_pressure"].expanded_uncertainty_10khz_db  # 0.4` |
| `ReferenceCalibrationRow` | `dataclass` | **One row of Table 1.**<br>• `microphone_types`, `method`, `references`, `expanded_uncertainty_1khz_db`, `expanded_uncertainty_10khz_db` [dB, k = 2] | `metrology.IEC61094_8_TABLE_1["primary_free_field"].references  # ('IEC 61094-3',)` |
| `free_field_region` | `function` | **The effective free-field region of a time window, A = d + τc (IEC 61094-8 B.1).**<br>• `source_distance_m` d [m], `window_time_s` τ [s]<br>• keyword-only: `temperature_c` [°C], `static_pressure_kpa` [kPa], `relative_humidity_percent` [%] (Default: 23.0, 101.325, 50, clause 4); c from the IEC 61094-2 Annex F air | `metrology.free_field_region(1.0, 0.005).major_axis_m  # 2.73`<br><br>• `FreeFieldRegion` |
| `FreeFieldRegion` | `dataclass` | **The prolate spheroid with the source and the microphone at its foci.**<br>• `source_distance_m` [m], `window_time_s` [s], `speed_of_sound` [m/s]<br>• `.major_axis_m` A, `.semi_minor_axis_m` b, `.rod_clearance_m` τc/2 [m]<br>• `.plot()`: the region as Figure B.1 draws it | `r.semi_minor_axis_m  # 1.27` |
| `reflection_free_window_s` | `function` | **The longest time window that keeps a reflection out of the effective free-field region, τ = (L - d)/c (IEC 61094-8 B.1, B.1.3 a)).**<br>• `source_distance_m` d [m], `reflected_path_m` L [m], the shortest path by the reflector<br>• keyword-only: `temperature_c` [°C], `static_pressure_kpa` [kPa], `relative_humidity_percent` [%] (Default: clause 4) | `metrology.reflection_free_window_s(1.0, 1.48)  # 0.00139` |
| `time_selective_response` | `function` | **The frequency response of the direct sound through a time window (IEC 61094-8 B.1.3, Formula (B.2)).**<br>• `impulse_response` (one value per sample), `sample_rate_hz` [Hz]<br>• keyword-only: `window_start_s`, `window_end_s` [s] from the start of the record; `window_shape` ('tukey' / 'hann' / 'hamming' / 'rectangular', Default: 'tukey'); `taper_fraction` (Default: 0.25); `excitation`: a `RectangularPulse` divided out (Default: None) | `ts = metrology.time_selective_response(h, 96000.0, window_start_s=0.0025, window_end_s=0.006)`<br><br>• `TimeSelectiveResponse` |
| `TimeSelectiveResponse` | `dataclass` | **An impulse response, its time window and its transform.**<br>• `impulse_response`, `sample_rate_hz` [Hz], `window_start_s`, `window_end_s` [s], `window_shape`, `taper_fraction`, `excitation`, read-only<br>• `.time_s`, `.window`, `.windowed_impulse_response`, `.window_length_s` [s], `.frequency_resolution_hz` [Hz]<br>• `.response_at(f)` H(f) by (B.2), `.level_db_at(f)` [dB], `.phase_deg_at(f)` [°], `.record_response_at(f)` without the window<br>• `.free_field_region(d, arrival_time_s)`: the region of the window, τ from the arrival<br>• `.plot(quantity='impulse' / 'response')` | `ts.level_db_at([1000.0, 10000.0])` |
| `stepped_sine_impulse_response` | `function` | **The impulse response of a stepped-sine measurement (IEC 61094-8 B.2, Formula (B.3)).**<br>• `frequencies_hz` [Hz], k Δf from 0 Hz, equally spaced; `response` H(k Δf), complex<br>• the negative frequencies are the conjugates; N = 2K + 1 samples at N Δf | `metrology.stepped_sine_impulse_response(np.arange(0.0, 24001.0, 120.0), h).duration_s  # 0.00833`<br><br>• `SteppedSineImpulseResponse` |
| `SteppedSineImpulseResponse` | `dataclass` | **The impulse response of a stepped sine.**<br>• `frequency_step_hz` Δf [Hz], `impulse_response`, read-only<br>• `.sample_rate_hz` [Hz], `.duration_s` 1/Δf [s] (B.2.2), `.time_s`<br>• `.plot()` | `ir.impulse_response, ir.sample_rate_hz` |
| `rectangular_pulse` | `function` | **The rectangular pulse of the direct impulse method (IEC 61094-8 B.6.1, Formula (B.10)).**<br>• `duration_s` T = 2b [s] (Formula (B.10) is the spectrum of a pulse lasting 2b, which the text calls b, an erratum)<br>• keyword-only: `amplitude_v` a [V] (Default: 1) | `metrology.rectangular_pulse(5e-6, amplitude_v=10.0).level_db_at([20000.0])  # [-0.143]`<br><br>• `RectangularPulse` |
| `RectangularPulse` | `dataclass` | **A pulse of duration T and amplitude a.**<br>• `duration_s` [s], `amplitude_v` [V]<br>• `.half_duration_s` b, `.first_zero_hz` 1/(2b) [Hz], `.area_v_s` 2ab [V·s]<br>• `.spectrum_at(f)` X(f) of (B.10), `.level_db_at(f)` re X(0) [dB]<br>• `.plot(upper_frequency_hz=...)` | `metrology.rectangular_pulse(5e-6).half_duration_s  # 2.5e-06` |
| `rectangular_pulse_duration_s` | `function` | **The pulse duration whose first spectral zero lies a factor above the frequencies of interest (IEC 61094-8 B.6.1).**<br>• `upper_frequency_hz` [Hz]<br>• keyword-only: `zero_ratio` (Default: 10, "approximately an order of magnitude") | `metrology.rectangular_pulse_duration_s(20000.0)  # 5e-06` |
| `impedance_pressure_ratio` | `function` | **The pressure ratio two microphones of different acoustic impedance see, R_P = (V_x + V_e,ref)/(V_x + V_e,test) (IEC 61094-5 7.4, 7.5).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `reference_equivalent_volume_m3`, `test_equivalent_volume_m3` [m³], complex, such as `ReciprocityMicrophone.complex_equivalent_volume_m3(f)` gives them (IEC 61094-2 E.4)<br>• exactly one of `coupling_equivalent_volume_m3` [m³], a closed coupler (IEC 61094-2 Formula (3)), or `coupling_impedance_pa_s_m3` [Pa·s/m³], the air in series with each microphone (Table D.1, the circuit of Jarvis 1996, which `air_gap_series_impedance_pa_s_m3` gives) | `rp = metrology.impedance_pressure_ratio(f, reference_equivalent_volume_m3=v1, test_equivalent_volume_m3=v2, coupling_equivalent_volume_m3=600e-9)`<br><br>• `ImpedancePressureRatio` |
| `ImpedancePressureRatio` | `dataclass` | **The pressure ratio of different acoustic impedances.**<br>• `frequencies_hz` [Hz], `ratio` R_P (complex), `coupling` ('coupler' / 'series'), `coupling_equivalent_volume_m3` [m³], read-only<br>• `.level_difference_db` [dB] and `.phase_difference_deg` [°], the pressure ratio of a comparison<br>• `.standard_uncertainty_db` [dB], the level read as a rectangular semi-range (Table D.1)<br>• `.plot(quantity='level' / 'phase')` | `rp.standard_uncertainty_db` |
| `air_gap_series_impedance_pa_s_m3` | `function` | **The impedance of the air between two microphones in series with each, Z_x = Z_L + Z_L Z_c/(Z_L + Z_c), by the symmetric-coupler circuit of Jarvis (1996) Appendix B, the reference [2] of IEC 61094-5 Table D.1 and 7.4.**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `gap_length_m`, `gap_radius_m` [m]; `temperature_c` [°C] (Default: 23.0), `static_pressure_kpa` [kPa] (Default: 101.325), `relative_humidity_percent` [%] (Default: 50), the Annex F air its density and ratio of specific heats come from; `gas` (Default: None)<br>• returns a read-only complex array [Pa·s/m³] | `z_x = metrology.air_gap_series_impedance_pa_s_m3(f, gap_length_m=2e-3, gap_radius_m=6.35e-3)`<br><br>• passed to `impedance_pressure_ratio(..., coupling_impedance_pa_s_m3=z_x)` |
| `pressure_reciprocity` | `function` | **Pressure sensitivities of three microphones calibrated in pairs in a coupler (IEC 61094-2:2009 5.7.1, Formula (7)).**<br>• `frequencies_hz` [Hz]; `electrical_transfer_impedances_ohm` Z_e,12, Z_e,23, Z_e,31, complex [Ω]; `acoustic_transfer_impedances` Z_a,12, Z_a,23, Z_a,31, each a `CouplerTransferImpedance` or complex [Pa·s/m³]<br>• keyword-only: `corrections_db` by name [dB], added to every level (Default: None); `expanded_uncertainty_db` [dB] (Default: None)<br>• products M_i M_j = Z_e,ij/Z_a,ij; M_1 = (P_12 P_31/P_23)^½ on the branch continuous in frequency with a non-negative real part at the lowest one, M_2 = P_12/M_1, M_3 = P_31/M_1 | `c = metrology.pressure_reciprocity(f, (ze12, ze23, ze31), (za12, za23, za31))`<br><br>• `ReciprocityCalibration` |
| `pressure_reciprocity_pair` | `function` | **Pressure sensitivities of two microphones and an auxiliary sound source (IEC 61094-2:2009 5.7.2, Formula (8)).**<br>• `frequencies_hz` [Hz]; `electrical_transfer_impedance_ohm` Z_e,12 [Ω]; `acoustic_transfer_impedance` Z_a,12; `sensitivity_ratio` M_1/M_2, complex<br>• keyword-only: `corrections_db`, `expanded_uncertainty_db` as in `pressure_reciprocity` | `metrology.pressure_reciprocity_pair(f, ze12, za12, r12)`<br><br>• `ReciprocityCalibration` of two microphones |
| `free_field_reciprocity` | `function` | **Free-field sensitivities of three microphones calibrated in pairs (IEC 61094-3:2016 5.7.1, Formula (8), with the factor -j of Formula (7)).**<br>• `frequencies_hz` [Hz]; `electrical_transfer_impedances_ohm` Z_e,12, Z_e,23, Z_e,31 [Ω]<br>• keyword-only: `diaphragm_distances_m` d_m,12, d_m,23, d_m,31 [m]; `temperature_c` [°C], `static_pressure_pa` [Pa], `relative_humidity_percent` [%]; `acoustic_centres_m` of microphones 1 to 3, positive in front of the diaphragm, a value or one per frequency [m] (Default: 0, the diaphragms); `dispersion` in k = ω/c (Default: True, IEC 61094-2 F.3 NOTE); `corrections_db`, `expanded_uncertainty_db` | `metrology.free_field_reciprocity(f, (ze12, ze23, ze31), diaphragm_distances_m=(0.3, 0.25, 0.2), temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `ReciprocityCalibration` |
| `free_field_reciprocity_pair` | `function` | **Complex free-field sensitivities of two microphones and an auxiliary sound source (IEC 61094-3:2016 5.7.2, Formula (9), complex since COR1).**<br>• `frequencies_hz` [Hz]; `electrical_transfer_impedance_ohm` [Ω]; `sensitivity_ratio` r_12<br>• keyword-only: `diaphragm_distance_m` [m], the three conditions, `acoustic_centres_m` (two), `dispersion`, `corrections_db`, `expanded_uncertainty_db` | `metrology.free_field_reciprocity_pair(f, ze12, r12, diaphragm_distance_m=0.2, temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `ReciprocityCalibration` of two microphones |
| `free_field_transfer_impedance` | `function` | **The electrical transfer impedance two microphones of known free-field sensitivity give (IEC 61094-3:2016 Formula (D.1)).**<br>• `frequencies_hz` [Hz]; `sensitivity_1_v_per_pa`, `sensitivity_2_v_per_pa` [V/Pa], complex<br>• keyword-only: `diaphragm_distance_m` [m], the three conditions, `acoustic_centres_m`, `dispersion` | `metrology.free_field_transfer_impedance(f, m1, m2, diaphragm_distance_m=0.2, temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• U_2/i_1 [Ω], complex |
| `ReciprocityCalibration` | `dataclass` | **The complex sensitivities of microphones calibrated by reciprocity (IEC 61094-2 5.7, IEC 61094-3 5.7).**<br>• `frequencies_hz` [Hz], `sensitivity_v_per_pa` (microphones × frequencies, complex) [V/Pa], `products_v2_per_pa2` (pairs × frequencies) [V²/Pa²], `field` ('pressure' / 'free_field'), `method` ('three_microphones' / 'auxiliary_source'), `corrections_db` (read-only mapping) [dB], `expanded_uncertainty_db` [dB] or None<br>• `.sensitivity_level_db` [dB re 1 V/Pa], `.sensitivity_mv_per_pa` [mV/Pa], `.phase_deg` [°, 0 to 360], `.correction_db`, `.microphones`, `.standard`<br>• `.plot()`: the level of each microphone with its U band | `c.sensitivity_level_db, c.phase_deg, c.standard  # ..., 'IEC 61094-2:2009'` |
| `coupler_transfer_impedance` | `function` | **The acoustic transfer impedance of a coupler closed by two microphones (IEC 61094-2:2009 5.4 to 5.6).**<br>• `frequencies_hz` [Hz], `coupler` (`PlaneWaveCoupler` / `LargeVolumeCoupler`), `transmitter`, `receiver` (`ReciprocityMicrophone`)<br>• keyword-only: `temperature_c` [°C], `static_pressure_pa` [Pa], `relative_humidity_percent` [%]; `gas` a `Fluid` for a coupler not filled with air (Default: None, Annex F air); `heat_conduction_method` 'exact' / 'approximation' for E_V (Default: 'exact')<br>• large-volume: Formula (3) with Δ_H (A.1); plane-wave: Formula (4) with (A.3) to (A.5) and the excess volume of each front cavity (7.3.3.1); both divided by Δ_C (6) | `za = metrology.coupler_transfer_impedance(f, coupler, m1, m2, temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `CouplerTransferImpedance` |
| `CouplerTransferImpedance` | `dataclass` | **The transfer impedance of a coupler and its corrections.**<br>• `frequencies_hz` [Hz], `coupler`, `adiabatic_impedance_pa_s_m3` Z′_a,12 and `heat_conducting_impedance_pa_s_m3` Z″_a,12 [Pa·s/m³], `capillary_correction` Δ_C, `heat_conduction` (`HeatConductionCorrection` or None), all read-only<br>• `.transfer_impedance_pa_s_m3` Z″/Δ_C, `.heat_conduction_correction_db`, `.capillary_correction_db` [dB]<br>• `.plot()`: both corrections against frequency | `za.transfer_impedance_pa_s_m3` |
| `PlaneWaveCoupler` | `dataclass` | **A plane-wave coupler (IEC 61094-2 C.2, Table C.1).**<br>• `length_m` E [m], `diameter_m` C [m], `capillary` (`CapillaryTube` or None) | `metrology.PlaneWaveCoupler(length_m=7.5e-3, diameter_m=18.6e-3)` |
| `LargeVolumeCoupler` | `dataclass` | **A large-volume coupler (IEC 61094-2 C.3, Table C.2, Figure C.2).**<br>• `length_m` E [m], `diameter_m` C [m], `port_length_m` F [m], the bore between each microphone face and the cavity; `capillary`; `volume_m3` [m³] and `surface_area_m2` [m²] of the cavity when measured (Default: None, the closed cylinder)<br>• `.cavity_volume_m3`, `.cavity_surface_m2`; `.closed_volume_m3(mics)` [m³] and `.closed_surface_m2(mics)` [m²] with the bores and the front cavities of two microphones | `metrology.LargeVolumeCoupler(length_m=12.55e-3, diameter_m=42.88e-3, port_length_m=0.80e-3)` |
| `CapillaryTube` | `dataclass` | **Identical open capillary tubes (IEC 61094-2 5.6, Annex B).**<br>• `length_m` l_C [m], `radius_m` a_t [m], `count` n (Default: 1) | `metrology.CapillaryTube(length_m=0.05, radius_m=1 / 6000, count=2)` |
| `ReciprocityMicrophone` | `dataclass` | **The parameters of a laboratory standard microphone that enter the transfer impedance (IEC 61094-2 7.3.3, Annex E).**<br>• `equivalent_volume_m3` V_eq [m³], `resonance_frequency_hz` f_0 [Hz], `loss_factor` d, `front_cavity_volume_m3` [m³], `front_cavity_depth_m` [m], `front_cavity_diameter_m` [m], `thread_area_m2` [m²] (Default: 0)<br>• `.compliance_m3_per_pa`, `.mass_kg_m4`, `.resistance_pa_s_m3`; `.complex_equivalent_volume_m3(f)` V_e [m³] and `.acoustic_impedance_pa_s_m3(f)` Z_a [Pa·s/m³], complex | `m.acoustic_impedance_pa_s_m3([1000.0])` |
| `microphone_acoustic_impedance` | `function` | **The acoustic impedance of a microphone from its electrical admittance (IEC 61094-2 E.4, Formula (E.1)).**<br>• `electrical_admittance_s` Y [S], `blocked_impedance_ohm` Z_e,0 [Ω], `pressure_sensitivity_v_per_pa` M_p [V/Pa], complex<br>• Z_a = (Z_e,0 − 1/Y)/M_p² | `metrology.microphone_acoustic_impedance(y, ze0, mp)`<br><br>• Z_a [Pa·s/m³], complex |
| `temperature_transfer_function` | `function` | **Gerber's E_V of a cylindrical cavity (IEC 61094-2 A.2, Formula (A.2), Table A.1).**<br>• `length_to_diameter_ratio` R; `x` X = f l²/(κ α_t)<br>• keyword-only: `method` 'exact' (the full solution of [A.1], every entry of Table A.1 to 0.00001; Default) or 'approximation' (Formula (A.2)) | `metrology.temperature_transfer_function(1.0, 100.0)  # (0.97179+0.02758j)` |
| `heat_conduction_correction` | `function` | **The heat-conduction correction Δ_H = κ/(1 + (κ − 1)E_V) of a closed cavity (IEC 61094-2 5.5, A.2).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `volume_m3` [m³], `surface_area_m2` [m²], `length_to_diameter_ratio`, `gas` (`Fluid`), `method` (Default: 'exact') | `metrology.heat_conduction_correction(f, volume_m3=v, surface_area_m2=s, length_to_diameter_ratio=0.3, gas=fluids.air(temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0))`<br><br>• `HeatConductionCorrection` |
| `HeatConductionCorrection` | `dataclass` | **Δ_H at each frequency.**<br>• `frequencies_hz` [Hz], `length_to_diameter_ratio`, `volume_to_surface_m` l [m], `x`, `transfer_function` E_V, `heat_capacity_ratio`, `method`<br>• `.volume_factor` Δ_H, `.correction_db` 20 lg\|Δ_H\| [dB]<br>• `.plot()` | `h.volume_factor` |
| `capillary_tube_impedance` | `function` | **The input impedance of an open capillary tube (IEC 61094-2 Formulas (B.1) to (B.3)).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `length_m` [m], `radius_m` [m], `gas` (`Fluid`)<br>• the 0.1667 mm radius of Tables B.1 and B.2 is 1/6 mm | `metrology.capillary_tube_impedance([20.0], length_m=0.05, radius_m=1 / 6000, gas=fluids.air(temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0))`<br><br>• `CapillaryTubeImpedance` |
| `CapillaryTubeImpedance` | `dataclass` | **The impedance of a capillary tube.**<br>• `frequencies_hz` [Hz], `length_m`, `radius_m` [m], `propagation_coefficient_per_m` γ [1/m], `wave_impedance_pa_s_m3` Z_a,t [Pa·s/m³]<br>• `.impedance_pa_s_m3` Z_a,C = Z_a,t tanh γl_C<br>• `.plot()`: real and imaginary parts in GPa·s/m³ | `t.impedance_pa_s_m3 / 1e9  # GPa·s/m³` |
| `large_volume_wave_motion_correction` | `function` | **The wave-motion correction of the large-volume coupler for LS1P microphones (IEC 61094-2 Table C.3).**<br>• `frequencies_hz` [Hz], 0 up to 800 Hz, interpolated in lg f between rows, refused above 2500 Hz<br>• keyword-only: `speed_of_sound_ratio` of the gas to air, for hydrogen (Default: 1) | `metrology.large_volume_wave_motion_correction([2000.0]).correction_db  # [-0.06]`<br><br>• `WaveMotionCorrection` |
| `WaveMotionCorrection` | `dataclass` | **Table C.3 at the frequencies asked for.**<br>• `frequencies_hz` [Hz], `correction_db` [dB], `speed_of_sound_ratio`; `interpolated` is read-only, read from the frequencies and the ratio, and `correction_db` is held to Table C.3 there<br>• `.plot()` | `w.correction_db` |
| `check_coupler` | `function` | **Do the coupler formulas of IEC 61094-2 hold for this calibration?**<br>• `frequencies_hz` [Hz], `coupler`, `microphones`<br>• keyword-only: the three conditions, `gas`, `heat_conduction_method`<br>• A.3: ω ρ a² > 100 η at the lowest frequency; A.2: 0.125 < R < 8 and X > 5 with the approximation, a frequency below 20 Hz reported; Annex F domain; C.2: 0.5 ≤ R ≤ 0.75 reported | `metrology.check_coupler(f, coupler, mics, temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0).passes`<br><br>• `CouplerCheck` |
| `CouplerCheck` | `dataclass` | **Whether the coupler formulas apply.**<br>• `coupler`, `length_to_diameter_ratio`, `ratio_recommended` (advisory), `broadband_margin`, `lowest_x`, `approximation_valid`, `full_solution_advised` (advisory), `conditions_valid`, `lowest_frequency_hz` [Hz]<br>• `.broadband_valid`; `passes`; `bool()` raises<br>• `.plot()`: each condition re its limit<br>• takes `coupler`, `length_to_diameter_ratio`, `broadband_margin`, `lowest_x`, `lowest_frequency_hz`, `heat_conduction_method`, `temperature_c`, `static_pressure_pa`, `relative_humidity_percent`, `in_air`; `ratio_recommended`, `approximation_valid`, `full_solution_advised`, `conditions_valid` are read-only, read from them | `c.passes` |
| `coupler_parameter_uncertainty` | `function` | **The uncertainty components of the acoustic transfer impedance, one parameter at a time (IEC 61094-2 7.5).**<br>• `frequencies_hz` [Hz], `coupler`, `microphones` (three), `uncertainties` (`CouplerInputUncertainties`)<br>• keyword-only: the three conditions; `microphone` 1 to 3 (Default: 1); `gas` (`Fluid`, Default: humid air; refuses an uncertainty on the conditions); `heat_conduction_method` | `metrology.coupler_parameter_uncertainty(f, coupler, mics, metrology.CouplerInputUncertainties(u_coupler_length_m=5e-6), temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `CouplerParameterUncertainty` |
| `CouplerInputUncertainties` | `dataclass` | **The standard uncertainty of each input quantity of the coupler transfer impedance (IEC 61094-2 7.3.2, 7.3.3), moved one at a time by 7.5.**<br>• keyword-only, all Default: 0: `u_coupler_length_m`, `u_coupler_diameter_m` [m], `u_coupler_volume_m3` [m³], `u_coupler_surface_area_m2` [m²], `u_capillary_length_m`, `u_capillary_radius_m` [m], `u_static_pressure_pa` [Pa], `u_temperature_k` [K], `u_relative_humidity_percent` [%], `u_front_cavity_depth_m` [m], `u_front_cavity_volume_m3`, `u_equivalent_volume_m3` [m³], `u_resonance_frequency_hz` [Hz], `u_loss_factor`<br>• a microphone parameter is the uncertainty on each of the three<br>Refuses an uncertainty that is negative or not finite | `metrology.CouplerInputUncertainties(u_coupler_length_m=3e-6, u_temperature_k=0.05)` |
| `CouplerParameterUncertainty` | `dataclass` | **The components the coupler parameters contribute.**<br>• `frequencies_hz` [Hz], `components_db` keyed by `IEC61094_2_TABLE_1` [dB], `microphone`<br>• `.plot()` | `reciprocity_uncertainty_budget(f, p.components_db)` |
| `reciprocity_uncertainty_budget` | `function` | **The uncertainty budget of a reciprocity calibration as a function of frequency (IEC 61094-2 7.5, IEC 61094-3 7.8).**<br>• `frequencies_hz` [Hz]; `standard_uncertainties_db` keyed by Table 1 of the field, a value or one per frequency [dB]<br>• keyword-only: `field` 'pressure' / 'free_field' (Default: 'pressure'); `additional_components_db` (Default: None); `coverage_factor` k (Default: 2) | `metrology.reciprocity_uncertainty_budget(f, {"voltage_ratio": 0.003})`<br><br>• `ReciprocityUncertaintyBudget` |
| `ReciprocityUncertaintyBudget` | `dataclass` | **A reciprocity budget.**<br>• `frequencies_hz` [Hz], `field`, `names`, `components`, `standard_uncertainties_db` (components × frequencies) [dB], `coverage_factor`<br>• `.combined_uncertainty_db`, `.expanded_uncertainty_db`, `.linear_combined_uncertainty_db` [dB], `.standard`<br>• `.plot()` | `b.expanded_uncertainty_db` |
| `IEC61094_2_TABLE_1` | `mapping` | **IEC 61094-2:2009 Table 1, the 35 uncertainty components, keyed 'series_impedance' to 'temperature_corrections'.**<br>• each a `ReciprocityUncertaintyRow` | `metrology.IEC61094_2_TABLE_1['coupler_volume'].subclauses  # ('7.3.2.1', '7.3.2.2')` |
| `IEC61094_3_TABLE_1` | `mapping` | **IEC 61094-3:2016 Table 1, the 23 uncertainty components, keyed 'series_impedance' to 'temperature_corrections'.** | `metrology.IEC61094_3_TABLE_1['air_attenuation'].subclauses  # ('7.4', 'Annex B')` |
| `ReciprocityUncertaintyRow` | `dataclass` | **One row of Table 1.**<br>• `component` as printed, `group`, `subclauses` | `row.component` |
| `IEC61094_2_TABLE_C1` | `mapping` | **IEC 61094-2:2009 Table C.1, the nominal dimensions of plane-wave couplers, keyed 'LS1P', 'LS2aP', 'LS2bP'.** | `metrology.IEC61094_2_TABLE_C1['LS1P'].coupler_diameter_mm  # 18.6` |
| `IEC61094_2_TABLE_C2` | `mapping` | **IEC 61094-2:2009 Table C.2, the nominal dimensions of large-volume couplers, keyed by type, ± 0.03 mm on C, E and F.** | `metrology.IEC61094_2_TABLE_C2['LS1P'].coupler_length_mm  # 12.55` |
| `CouplerDimensions` | `dataclass` | **One column of Table C.1 or C.2, in mm as printed.**<br>• `microphone_diameter_mm` A, `front_cavity_diameter_mm` B, `coupler_diameter_mm` C, `front_cavity_depth_mm` D, `coupler_length_mm` or `coupler_length_range_mm` E, `port_length_mm` F, `tolerance_mm` | `d.coupler_length_range_mm` |
| `IEC61094_2_TABLE_C3` | `mapping` | **IEC 61094-2:2009 Table C.3, the wave-motion corrections of the air-filled large-volume coupler for LS1P, keyed by frequency [Hz], in dB.**<br>• 0 up to 800 Hz, -0.087 dB at 2500 Hz | `metrology.IEC61094_2_TABLE_C3[2500.0]  # -0.087` |
| `reciprocity_air_attenuation` | `function` | **The air attenuation coefficient of a free-field reciprocity calibration (IEC 61094-3 Annex B, Steps 1 to 5).**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `temperature_c` [°C], `static_pressure_pa` [Pa], `relative_humidity_percent` [%]<br>• Step 1 with the coefficient of IEC 61094-2 Table F.2 (an erratum) | `metrology.reciprocity_air_attenuation([10000.0], temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `ReciprocityAirAttenuation` |
| `ReciprocityAirAttenuation` | `dataclass` | **α and its parts.**<br>• `frequencies_hz` [Hz], the conditions, `water_vapour_mole_fraction`, `oxygen_relaxation_hz`, `nitrogen_relaxation_hz` [Hz], `speed_of_sound` [m/s], `classical_np_per_m`, `oxygen_np_per_m`, `nitrogen_np_per_m` [Np/m]<br>• `.attenuation_np_per_m`, `.attenuation_db_per_m`, `.dispersive_speed_of_sound` (IEC 61094-2 F.3 NOTE), `.within_stated_accuracy` (the ±10 % domain of B.2)<br>• `.plot()` | `a.attenuation_db_per_m` |
| `acoustic_centre` | `function` | **The acoustic centre of a microphone from the inverse-distance law (IEC 61094-3 6.5).**<br>• `distances_m` [m], at least three; `sound_pressures_pa` [Pa or any proportional unit]<br>• keyword-only: `attenuation_np_per_m` α (Default: 0) | `metrology.acoustic_centre(r, p).position_m`<br><br>• `AcousticCentre` |
| `AcousticCentre` | `dataclass` | **The least-squares line through 1/\|p\|.**<br>• `distances_m` [m], `inverse_readings`, `slope`, `intercept`<br>• `.position_m` −b/a [m], positive towards the observation points<br>• `.plot()` | `c.position_m` |
| `check_free_field_arrangement` | `function` | **Is this the free-field arrangement IEC 61094-3 recommends?**<br>• `frequencies_hz` [Hz]<br>• keyword-only: `diaphragm_distances_m` [m], `microphone_diameter_m` [m], the three conditions, `support_length_m` [m] (Default: None)<br>• 7.3: distance > 10 diameters and 6.4: support ≥ 20 diameters, as recommended; B.2: accuracy domain; Annex A: 150 mm to 500 mm reported | `metrology.check_free_field_arrangement(f, diaphragm_distances_m=(0.2,), microphone_diameter_m=13.2e-3, temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0).passes`<br><br>• `FreeFieldArrangementCheck` |
| `FreeFieldArrangementCheck` | `dataclass` | **The verdict on a free-field arrangement.**<br>• `diaphragm_distances_m`, `microphone_diameter_m`, `distances_ok`, `support_length_m`, `support_ok`, `annex_a_range` (advisory), `attenuation_accuracy`<br>• `passes`; `bool()` raises<br>• `.plot()`: each distance and the support re its limit, the failing conditions in the title<br>• takes `diaphragm_distances_m`, `microphone_diameter_m`, `support_length_m`, `air_attenuation`; `distances_ok`, `support_ok`, `annex_a_range`, `attenuation_accuracy` are read-only, read from them | `c.passes` |
| `free_field_parameter_uncertainty` | `function` | **The uncertainty components of the free-field acoustic transfer impedance, one parameter at a time (IEC 61094-3 7.8).**<br>• `frequencies_hz` [Hz], `uncertainties` (`FreeFieldInputUncertainties`)<br>• keyword-only: `diaphragm_distances_m` [m], the three conditions, `acoustic_centres_m`; `microphone`; `dispersion` | `metrology.free_field_parameter_uncertainty(f, metrology.FreeFieldInputUncertainties(u_distance_m=1e-4), diaphragm_distances_m=(0.3, 0.25, 0.2), temperature_c=23.0, static_pressure_pa=101325.0, relative_humidity_percent=50.0)`<br><br>• `FreeFieldParameterUncertainty` |
| `FreeFieldInputUncertainties` | `dataclass` | **The standard uncertainty of each input quantity of the free-field transfer impedance (IEC 61094-3 Table 1), moved one at a time by 7.8.**<br>• keyword-only, all Default: 0: `u_distance_m` [m], `u_acoustic_centre_m` [m] one value or one per frequency, `u_static_pressure_pa` [Pa], `u_temperature_k` [K], `u_relative_humidity_percent` [%], `u_air_attenuation_ratio` as a fraction of α (B.2: 0.1/√3)<br>Refuses an uncertainty that is negative or not finite | `metrology.FreeFieldInputUncertainties(u_distance_m=1e-4, u_acoustic_centre_m=5e-4)` |
| `FreeFieldParameterUncertainty` | `dataclass` | **The components the free-field parameters contribute.**<br>• `frequencies_hz` [Hz], `components_db` keyed by `IEC61094_3_TABLE_1` [dB], `microphone`<br>• `.plot()` | `reciprocity_uncertainty_budget(f, p.components_db, field="free_field")` |
| `combine_uncertainty` | `function` | **GUM law of propagation of uncertainty (ISO/IEC Guide 98-3 clause 5).**<br>• `model`: measurement function f(x1…xN)<br>• `quantities`: input `Quantity` objects, in argument order<br>• `correlation`: optional N×N matrix r_ij (Default: None → uncorrelated; non-identity with finite input dof → effective dof undefined, `expanded()` needs `coverage_factor_override`) | `u = metrology.combine_uncertainty(lambda a, b: a*b, [metrology.Quantity(10.0, 0.1), metrology.Quantity(5.0, 0.2)])`<br><br>• `UncertaintyResult`; uc = 2.062 |
| `monte_carlo` | `function` | **Monte Carlo propagation (Guide 98-3-1, Supplement 1).**<br>• `model`: vectorised f(x1…xN)<br>• `quantities`: input `Quantity` objects<br>• `trials`: M ≥ 2 (Default: 1000000; fixed, no adaptive 7.9)<br>• `coverage`: interval probability (Default: 0.95)<br>• `seed`: reproducibility (Default: None)<br>• inputs sampled independently (no 6.4.8 multivariate path) | `mc = metrology.monte_carlo(model, quantities, seed=1)`<br><br>• `MonteCarloResult` (mean, u, coverage interval) |
| `rectangular` | `function` | **Type B quantity, rectangular PDF (GUM 4.3.7).**<br>• `value`, `half_width` a, `name` | `rectangular(20.0, 0.5)`<br><br>• `Quantity` with u = a/√3 = 0.289 |
| `triangular` | `function` | **Type B quantity, triangular PDF (GUM 4.3.9).**<br>• `value`, `half_width` a, `name` | `triangular(20.0, 0.5)`<br><br>• `Quantity` with u = a/√6 |
| `u_shaped` | `function` | **Type B quantity, U-shaped (arcsine) PDF.**<br>• `value`, `half_width` a, `name` | `u_shaped(20.0, 0.5)`<br><br>• `Quantity` with u = a/√2 |
| `coverage_factor` | `function` | **Coverage factor k from the t-distribution (GUM clause 6, Annex G).**<br>• `coverage`: coverage probability in (0, 1) (Default: 0.95)<br>• `dof`: effective degrees of freedom (Default: inf → the normal quantile) | `metrology.coverage_factor()  # 1.960`<br>`metrology.coverage_factor(0.95, dof=10)  # 2.228` |
| `expanded_uncertainty` | `function` | **k and U = k·uc(y) of a GUM result (clause 6).**<br>• `result`: an `UncertaintyResult`<br>• `coverage` (Default: 0.95)<br>The same answer as `result.expanded(coverage)`, as a function | `k, U = metrology.expanded_uncertainty(u)` |
| `Quantity` | `dataclass` | **Input quantity of a measurement model (GUM clause 4).**<br>• `value`: estimate xi<br>• `uncertainty`: u(xi) ≥ 0<br>• `distribution`: 'gaussian'/'rectangular'/'triangular'/'u-shaped' (Default: 'gaussian')<br>• `dof`: degrees of freedom (Default: inf)<br>• `name`: budget label | `Quantity(94.0, 0.3, name="calibrator")` |
| `UncertaintyResult` | `dataclass` | **GUM propagation result.**<br>• `value`: y = f(x1…xN)<br>• `combined_uncertainty`: uc(y)<br>• `sensitivities`: ci = ∂f/∂xi<br>• `contributions`: \|ci\|·u(xi)<br>• `effective_dof`: Welch–Satterthwaite<br>• `names`<br>• `.plot()`: uncertainty budget | `u.combined_uncertainty, u.contributions` |
| `MonteCarloResult` | `dataclass` | **Monte Carlo result.**<br>• `value`: sample mean<br>• `standard_uncertainty`: sample std<br>• `interval`: (low, high) coverage interval (§7.7)<br>• `coverage`, `trials` | `mc.value, mc.interval` |
| `UncertaintyWarning` | `warning class` | **GUM propagation advisory.**<br>Emitted when a propagation falls back outside its nominal assumptions | `warnings.simplefilter('error', UncertaintyWarning)` |
| `trend_test` | `function` | **Nonparametric trend test on a sequence (Bendat & Piersol 4.5.2).**<br>• `values`: ≥ 10 observations or estimates<br>• `method`: 'reverse_arrangements' (Default; Table A.6 acceptance regions, exact Mahonian p-value to N = 100) / 'runs' (about the median, exact Wald–Wolfowitz distribution; median ties discarded)<br>• `alpha`: two-sided significance (Default: 0.05) | `res = metrology.trend_test(values)`<br><br>• `TrendTestResult`; B&P Example 4.4: A = 86, accepted in (64, 125] |
| `TrendTestResult` | `dataclass` | **Trend-test verdict.**<br>• `statistic`: reverse arrangements A or runs r<br>• `bounds`: acceptance region (lower, upper], `p_value`, `trend_free`<br>• `mean`, `std`: null moments (Eqs. 4.54–4.55)<br>• `values`, `method`, `n`, `alpha`, `median` (runs-classification median)<br>• `.plot()`: tested sequence with the verdict<br>• takes `values`, `method`, `statistic`, `n`, `mean`, `std`, `p_value`, `alpha`, `median`; `bounds`, `trend_free` are read-only, read from them | `res.statistic, res.bounds, res.trend_free` |
| `stationarity_test` | `function` | **Stationarity test on segment statistics (Bendat & Piersol 10.3.1.1).**<br>• `x`, `fs`<br>• `n_segments` (Default: 20, as B&P Example 10.3), `statistic`: 'mean_square' (Default) / 'rms' / 'mean' / 'variance'<br>• `method`, `alpha` as `trend_test`<br>Trailing samples beyond equal segments are discarded | `res = metrology.stationarity_test(x, fs)`<br><br>• `StationarityTestResult` |
| `StationarityTestResult` | `dataclass` | **Stationarity verdict on a record.**<br>• `segment_values`, `segment_times` [s], `segment_duration` [s]<br>• `count`, `bounds`, `p_value`, `stationary`, `mean`, `std`<br>• `statistic`, `method`, `alpha`, `n_segments`, `fs`<br>• `.plot()`: segment sequence with the verdict<br>• takes `segment_values`, `segment_times`, `statistic`, `method`, `count`, `mean`, `std`, `p_value`, `alpha`, `n_segments`, `segment_duration`, `fs`; `bounds`, `stationary` are read-only, read from them | `res.stationary, res.segment_values` |
| `level_crossing_rate` | `function` | **Level-crossing rates vs the Rice expectation (Bendat & Piersol 5.5.1).**<br>• `x`, `fs` (mean removed first; oversample the band)<br>• `levels` [signal units] (Default: 13 levels over ±3 RMS)<br>• `nperseg`: Welch length for the spectral moments<br>Gaussian: N0 = 2√(m2/m0), Na = N0·exp(−a²/2σ²) | `res = metrology.level_crossing_rate(x, fs)`<br><br>• `LevelCrossingResult` |
| `LevelCrossingResult` | `dataclass` | **Crossing rates (both slopes).**<br>• `levels`, `rates` [1/s], `rice_rates` [1/s]<br>• `zero_crossing_rate`, `zero_crossing_rate_rice`, `apparent_frequency` [Hz] = N0/2<br>• `sigma`, `duration` [s], `fs`<br>• `.plot()`: measured dots vs the Rice curve | `res.zero_crossing_rate, res.apparent_frequency` |
| `peak_statistics` | `function` | **Peak rate, irregularity factor and peak heights (Bendat & Piersol 5.5.2–5.5.4).**<br>• `x`, `fs` (mean removed; band-limit before: m4 weights G(f) by f⁴)<br>• `nperseg`: Welch length for the moments<br>M = √(m4/m2), r = N0/2M ∈ (0, 1] | `res = metrology.peak_statistics(x, fs)`<br><br>• `PeakStatisticsResult` |
| `PeakStatisticsResult` | `dataclass` | **Peak (maxima) statistics.**<br>• `peak_rate`, `peak_rate_rice` [1/s], `zero_crossing_rate_rice`, `irregularity_factor`<br>• `peak_values`: sorted standardized heights z = a/σ<br>• `.peak_exceedance(z)` / `.peak_density(z)`: Rice mixture (Eqs. 5.217/5.223; Rayleigh at r = 1, Gaussian at r → 0)<br>• `.plot()`: empirical exceedance vs the Rice curves | `res.irregularity_factor, res.peak_exceedance(4.0)` |
| `power_spectral_density` | `function` | **Welch PSD with statistical error analysis (Bendat & Piersol Ch. 8).**<br>• `x`, `fs`<br>• `window` (Default: 'hann'), `nperseg` (Default: bin spacing of at most 4 Hz; the resolution bandwidth Be also depends on the taper ENBW), `overlap` (Default: 0.5)<br>• `scaling`: 'density' [units²/Hz] / 'spectrum' [units²]<br>• `confidence`: chi-square CI level (Default: 0.95) | `res = signals.power_spectral_density(x, fs)`<br><br>• `SpectralDensityResult` (psd, CI, nd, ε) |
| `cross_spectral_density` | `function` | **Welch cross-spectral density with magnitude/phase errors (Eqs. 9.33/9.52).**<br>• `x`, `y`, `fs`<br>• `window`, `nperseg`, `overlap`, `scaling` as above | `res = signals.cross_spectral_density(x, y, fs)`<br><br>• `CrossSpectralDensityResult` |
| `coherent_output_spectrum` | `function` | **Gvv = γ²·Gyy, noise remainder and spectral SNR (Eqs. 9.55–9.56, 9.73).**<br>• `x` (input), `y` (output), `fs`<br>• `window`, `nperseg`, `overlap`, `scaling` as above | `res = signals.coherent_output_spectrum(x, y, fs)`<br><br>• `CoherentOutputSpectrumResult` |
| `fractional_octave_smoothing` | `function` | **Constant-power 1/n-octave smoothing of a spectrum.**<br>• `frequencies`, `values`<br>• `fraction`: the n of 1/n octave (Default: 3)<br>• `domain`: 'power'/'amplitude'/'db' (Default: 'power') | `s = signals.fractional_octave_smoothing(f, psd, 3.0)`<br><br>• smoothed array, same domain; flat spectra unchanged |
| `miso_coherence` | `function` | **Multiple & partial coherence of a MISO system (Bendat & Piersol Ch. 7).**<br>• `inputs`: q input records, q ≥ 2 (sequence of 1-D arrays or a (q, n) array), `output`, `fs`<br>• `order`: conditioning order (Default: 0..q−1)<br>• `window`, `nperseg`, `overlap`, `scaling` as above | `res = signals.miso_coherence([x1, x2], y, fs)`<br><br>• `MISOCoherenceResult` |
| `MISOCoherenceResult` | `dataclass` | **Multiple/partial coherence of q correlated inputs and one output.**<br>• `ordinary_coherence` (q×F), `multiple_coherence` γ²y:x, `partial_coherence` (q×F, conditioned per `order`)<br>• `coherent_output_spectra` Gvi (q×F, Σ Gvi + `noise_psd` = `output_psd`)<br>• `multiple_coherence_random_error` (Eq. 9.98), `coherent_output_random_error` (Eq. 9.100)<br>• `.dominant_input()`: per-band index of the strongest source<br>• `.plot()`: coherent output spectra + coherences | `res.multiple_coherence, res.dominant_input()` |
| `resolution_bias_error` | `function` | **First-order resolution bias at a resonance peak, εb ≈ −(Be/Br)²/3 (Eq. 8.141).**<br>• `resolution_bandwidth` Be [Hz]<br>• `half_power_bandwidth` Br [Hz] | `resolution_bias_error(1.0, 4.0)  # -1/48` |
| `noise_signal` | `function` | **Colored Gaussian noise with an exact power-law PSD slope.**<br>• `fs`, `seconds` (Default: 1.0)<br>• `color`: 'white'/'pink'/'red'/'blue'/'violet' (0/−3.01/−6.02/+3.01/+6.02 dB/oct)<br>• `rms` (Default: 1.0)<br>• `seed`: bit-reproducible per seed | `pink = signals.noise_signal(48000, 10.0, color='pink', seed=7)` |
| `tone_burst` | `function` | **IEC 60268-1 tone burst (Clause A2): zero-crossing start, integral full periods.**<br>• `fs`, `frequency`, `cycles`<br>• `amplitude` (Default: 1.0)<br>• `repetitions` + `repetition_rate` [bursts/s]: repetitive train (Clause A2.2)<br>• `pre_silence`, `post_silence` [s] | `res = signals.tone_burst(48000, 5000, 25, repetition_rate=10, repetitions=4)`<br><br>• `ToneBurstResult` |
| `resample_signal` | `function` | **Polyphase resampling with an explicit anti-alias spec (Kaiser FIR designed here).**<br>• `x`, `fs`, `fs_new` (rational ratio, e.g. 160/147)<br>• `stopband_attenuation_db` (Default: 120)<br>• `transition_width`: fraction of the smaller Nyquist (Default: 0.05)<br>• `max_denominator` (Default: 1000) | `res = signals.resample_signal(x, 44100, fs_new=48000)`<br><br>• `ResampledSignalResult` (signal + designed taps) |
| `fractional_delay` | `function` | **Band-limited delay by a fractional number of samples (phase ramp).**<br>• `x`, `delay` [samples] (fractional, negative = advance)<br>• `mode`: 'linear' (zero-padded, for transients; Default) / 'circular' (periodic records, machine-exact on bin-centered tones) | `y = signals.fractional_delay(x, 0.37)` |
| `window_metrics` | `function` | **Figures of merit of any scipy window (Harris 1978).**<br>• `window`: name or (name, param) tuple<br>• `n`: length (Default: 1024), DFT-even sampling as in Welch | `m = signals.window_metrics('hann', 2048)`<br><br>• `WindowMetricsResult` |
| `multitaper_psd` | `function` | **Thomson multitaper PSD from one whole record (Percival & Walden Ch. 7).**<br>• `x`, `fs`<br>• `time_half_bandwidth`: NW (Default: 4), `n_tapers`: K (Default: 2·NW−1, capped at 2·NW)<br>• `adaptive`: Thomson weights (Default: True)<br>• `scaling`, `confidence` as above | `res = signals.multitaper_psd(x, fs)`<br><br>• `MultitaperSpectralDensityResult` |
| `ToneBurstResult` | `dataclass` | **Tone-burst record.**<br>• `signal`, `envelope` (rectangular gate), `fs`<br>• `burst_seconds`, `burst_samples`, `onset_sample`<br>• `repetition_rate`, `period_samples`, `duty_cycle`<br>• `.plot()`: waveform + gating envelope | `res.signal, res.duty_cycle` |
| `ResampledSignalResult` | `dataclass` | **Resampled record with its anti-alias design.**<br>• `signal`, `fs`, `original_fs`, `up`, `down`<br>• `filter_taps`, `n_taps`, `passband_edge_hz`, `stopband_edge_hz`<br>• `stopband_attenuation_db`, `transition_width` | `res.signal, res.stopband_attenuation_db` |
| `WindowMetricsResult` | `dataclass` | **Window figures of merit.**<br>• `enbw_bins`, `.enbw_hz(fs)`, `coherent_gain`<br>• `scalloping_loss_db`, `worst_case_processing_loss_db` (positive losses)<br>• `highest_sidelobe_db` (negative, re main lobe), `mainlobe_width_3db_bins`<br>• `.plot()`: window + spectrum with metrics marked | `m.enbw_bins  # 1.5 for Hann` |
| `SpectralDensityResult` | `dataclass` | **Welch PSD with its statistical quality.**<br>• `frequencies`, `psd`, `ci_lower`/`ci_upper`, `confidence`<br>• `random_error` = 1/√nd, `n_segments`, `n_averages` (effective nd), `degrees_of_freedom`<br>• `resolution_bandwidth` Be [Hz]<br>• `.plot()`: PSD in dB with the CI band | `res.psd, res.n_averages, res.random_error` |
| `MultitaperSpectralDensityResult` | `dataclass` | **Multitaper PSD with per-frequency dof.**<br>• `frequencies`, `psd`, `ci_lower`/`ci_upper`, `confidence`<br>• `degrees_of_freedom` ν(f), `random_error` = √(2/ν)<br>• `weights` (K×F), `eigenvalues` λk, `time_half_bandwidth`, `n_tapers`, `resolution_bandwidth` 2W [Hz], `adaptive`<br>• `.plot()`: density with the CI band | `res.psd, res.degrees_of_freedom` |
| `CrossSpectralDensityResult` | `dataclass` | **Welch CSD with per-bin errors.**<br>• `csd` (complex), `magnitude`, `phase` (unwrapped), `coherence`<br>• `magnitude_random_error`, `phase_std` [rad]<br>• `.plot()`: magnitude, phase ±σ, coherence | `res.magnitude, res.phase_std` |
| `CoherentOutputSpectrumResult` | `dataclass` | **SISO output decomposition.**<br>• `output_psd` Gyy, `coherent_psd` Gvv, `noise_psd` Gnn<br>• `snr`, `snr_db`, `random_error` (Eq. 9.73), `snr_random_error`, `coherence_bias`<br>• `.plot()`: spectra + SNR panel | `res.coherent_psd, res.snr_db` |
| `spectrogram` | `function` | **Calibrated STFT power spectrogram (B&P 12.6.4.2): the Welch segmentation without the averaging.**<br>• `x`, `fs`<br>• `window`, `nperseg`, `overlap`, `scaling` as above<br>Column mean = Welch PSD bin by bin; a tone reads A²/2 ('spectrum') in every column | `res = signals.spectrogram(x, fs, nperseg=1024, overlap=0.75)`<br><br>• `SpectrogramResult` |
| `zoom_fft` | `function` | **Narrow-band spectrum on a fine grid via chirp-Z (B&P 11.5.4).**<br>• `x`, `fs`, `f_min`, `f_max`<br>• `n_points` (Default: one per record resolution fs/N)<br>• `window` (Default: 'hann')<br>Tone on an analysis frequency reads amplitude A / power A²/2 exactly | `res = signals.zoom_fft(x, fs, f_min=980.0, f_max=1016.0)`<br><br>• `ZoomFFTResult` |
| `SpectrogramResult` | `dataclass` | **STFT power over the time-frequency plane.**<br>• `times`, `frequencies`, `power` (freq × time)<br>• `time_resolution` T_B [s], `resolution_bandwidth` Be [Hz], `random_error` (= 1, unaveraged), `n_segments`, `hop`<br>• `.plot()`: dB image (raster) | `res.power[:, 0], res.time_resolution` |
| `ZoomFFTResult` | `dataclass` | **Zoom spectrum with amplitude calibration.**<br>• `frequencies`, `spectrum` (complex, \|·\| = tone amplitude), `amplitude`, `power` (= A²/2)<br>• `bin_spacing` (grid) vs `resolution_bandwidth` Be (true resolution)<br>• `.plot()`: power in dB over the band | `res.frequencies[res.amplitude.argmax()]` |
| `correlation` | `function` | **Auto/cross-correlation via zero-padded FFT (B&P 11.4.2).**<br>• `x`, `y` (Default: None → autocorrelation), `fs`<br>• `normalization`: 'biased' (1/N) / 'unbiased' (1/(N−\|r\|)) / 'coefficient' (ρ ∈ [−1, 1]) (Default: 'unbiased')<br>• `max_lag` [s] (Default: full N−1) | `res = signals.correlation(x, y, fs, normalization='coefficient')`<br><br>• `CorrelationResult` |
| `correlation_random_error` | `function` | **ε[R̂xy(τ)] = [1+ρ⁻²]^½/√(2BT) (Eqs. 8.109/8.112).**<br>• `coefficient` ρxy(τ)<br>• `signal_bandwidth` B [Hz], `duration` T [s]<br>Valid for T ≥ 10·\|τ\|, BT ≥ 5 | `correlation_random_error(1/11, 100.0, 5.0)  # 0.349 (Example 8.5)` |
| `time_delay` | `function` | **TDE: direct correlator, GCC (Knapp & Carter) or phase slope (Eq. 5.101b).**<br>• `x`, `y`, `fs`<br>• `method`: 'gcc' (Default) / 'direct' / 'phase'<br>• `weighting`: 'none'/'roth'/'scot'/'phat' (Default)/'ml' (Table I)<br>• `window`, `nperseg`, `overlap`: shared Welch core ('gcc'/'phase')<br>• `max_delay` [s], `interpolation`: 'parabolic' (Default)/'none', `upsample` (Default: 1)<br>• `signal_bandwidth` [Hz]: enables the Eq. 8.129 delay uncertainty | `res = signals.time_delay(x, y, fs, weighting='phat', upsample=16)`<br><br>• `TimeDelayResult` |
| `impulse_response_delay` | `function` | **Sub-sample IR delay [s]: peak location refined by local upsampling + parabola.**<br>• `ir`, `fs`<br>• `reference`: optional IR the delay is measured against (direct correlator)<br>• `interpolation` (Default: 'parabolic'), `upsample` (Default: 8) | `t0 = signals.impulse_response_delay(ir, fs)  # ~1e-3-sample accuracy` |
| `align_impulse_responses` | `function` | **Align an IR onto a reference by its estimated sub-sample delay.**<br>• `ir`, `reference`, `fs`<br>• `interpolation`, `upsample` as above<br>Exact band-limited fractional shift (zero-padded phase ramp) | `res = signals.align_impulse_responses(ir_b, ir_a, fs)`<br><br>• `AlignedImpulseResponseResult` |
| `envelope` | `function` | **Hilbert envelope, instantaneous phase & frequency (B&P Ch. 13).**<br>• `x`, `fs`<br>• `decimation_factor` (Default: 1)<br>• `antialias`: zero-phase FIR decimation (Default: True; False = plain subsampling, the ECMA-internal convention) | `res = signals.envelope(x, fs, decimation_factor=32)`<br><br>• `EnvelopeResult` |
| `CorrelationResult` | `dataclass` | **Correlation estimate.**<br>• `lags` [s], `values`, `coefficient` (always carried), `normalization`, `kind`<br>• `.random_error(signal_bandwidth)`: per-lag ε (Eqs. 8.109/8.112)<br>• `.plot()` | `res.lags, res.values, res.random_error(2000.0)` |
| `TimeDelayResult` | `dataclass` | **Time-delay estimate.**<br>• `delay` [s], `delay_samples` (fractional), `method`, `weighting`<br>• `lags`, `correlation` (the searched curve), `peak_correlation` ρ̂xy<br>• `delay_std` (Eq. 8.129), `delay_interval` ±2σ (Eq. 8.130) with `signal_bandwidth`<br>• `.plot()`: correlation with the delay marked | `res.delay, res.delay_std` |
| `AlignedImpulseResponseResult` | `dataclass` | **Aligned IR pair.**<br>• `aligned`, `reference`, `delay` [s], `delay_samples`<br>• `.plot()`: overlay | `res.aligned, res.delay_samples` |
| `EnvelopeResult` | `dataclass` | **Envelope analysis.**<br>• `times` [s], `envelope`, `phase` [rad, unwrapped], `instantaneous_frequency` [Hz]<br>• `fs` (output rate), `signal`, `signal_fs`, `decimation_factor`, `antialias`<br>• `.plot()`: signal + envelope, instantaneous frequency | `res.envelope, res.instantaneous_frequency` |
| `envelope_spectrum` | `function` | **Amplitude spectrum of the envelope: modulations as lines (B&P 13.3).**<br>• `x`, `fs`<br>• `kind`: 'magnitude' (Default) / 'squared' (square-law detector, Fig. 13.11)<br>• `window` (Default: 'hann', coherent-gain corrected), `nfft`<br>• `remove_dc` (Default: True; mean kept in `mean_level`)<br>AM tone A0, m: line A0·m at fm ('magnitude') | `res = signals.envelope_spectrum(x, fs)`<br><br>• `EnvelopeSpectrumResult` |
| `EnvelopeSpectrumResult` | `dataclass` | **Envelope spectrum.**<br>• `frequencies` [Hz], `amplitude` (line heights), `mean_level`, `kind`<br>• `times`, `envelope` (detector output), `window`, `remove_dc`, `fs`, `nfft`<br>• `.plot()`: envelope + spectrum | `res.amplitude, res.mean_level` |
| `time_synchronous_average` | `function` | **Extract a periodic waveform of known period_s by time domain averaging (McFadden 1987 Eq. 5).**<br>• `x`, `fs`, `period_s` [s] (one revolution)<br>• `n_averages`: whole periods to average (Default: as many as the record holds; choose N so N·q is integer to place a comb node on an interfering order q)<br>• `n_harmonics`: comb-response span (Default: 8)<br>Non-integer fs·period_s aligned by band-limited fractional delay | `res = signals.time_synchronous_average(x, fs, period_s=1/32)`<br><br>• `SynchronousAverageResult` |
| `SynchronousAverageResult` | `dataclass` | **Time synchronous average.**<br>• `period_waveform`, `times` [s], `residual`, `residual_rms`<br>• `n_averages`, `samples_per_period`, `period_s`, `fs`; `interpolated` (fs·period_s not a whole number) is read-only, read from `fs` and `period_s`<br>• `noise_reduction_db` = 10·log₁₀N, `amplitude_snr_gain` = √N<br>• `comb_frequencies` [Hz], `comb_response` (\|C(f)\|)<br>• `.plot()`: averaged waveform + comb filter | `res.period_waveform, res.noise_reduction_db` |
| `comb_filter_response` | `function` | **Magnitude of the N-period_s synchronous-averaging comb filter (McFadden 1987 Eq. 8).**<br>• `frequencies` [Hz], `period_s` [s], `n_averages`<br>\|C(f)\| = \|sin(N·π·f·T)/(N·sin(π·f·T))\|: unit teeth at harmonics k/T, nodes at j/(N·T) | `c = signals.comb_filter_response(freqs, 1/32, 20)` |
| `regularized_inverse_filter` | `function` | **Kirkeby frequency-dependent regularized inversion (Kirkeby & Nelson 1999 Eq. (17)).**<br>• `response`: measured IR (array or `ImpulseResponseResult`; its `fs` rides along)<br>• `fs`: Sample rate [Hz]<br>• `f_range`: (f1, f2) equalized to unity (Required)<br>• `regularization_inside` (Default: 1e-6) / `regularization_outside` (Default: 1.0), fractions of max\|H\|²<br>• `transition_octaves` (Default: 1/3), `n_fft`, `delay` (Default: n_fft//2) | `inv = signals.regularized_inverse_filter(ir, f_range=(100, 10000))`<br><br>• `InverseFilterResult` |
| `InverseFilterResult` | `dataclass` | **Regularized inverse filter.**<br>• `inverse` (time domain), `spectrum` (with modeling delay), `response_spectrum`, `regularization` = ε(f), `frequencies`, `f_range`, `delay`, `fs`<br>• `flatness_db`: worst in-band deviation of \|H·H_inv\| from 0 dB<br>• `max_gain_db`: out-of-band boost (≤ the 1/(2√ε) cap)<br>• `.apply(x)`: equalize, delay removed; `.plot()` | `flat = inv.apply(recording)` |
| `cepstrum` | `function` | **Power/real/complex cepstrum (Havelock Chs. 27/87).**<br>• `x`, `fs`<br>• `kind`: 'power' (Default, IDFT of ln\|X\|²) / 'real' (ln\|X\|) / 'complex' (invertible, phase unwrapped)<br>• `nfft`: even, ≥ record (Default: record length)<br>Echo a at t0: rahmonics (−1)^(n+1)·aⁿ/n at n·t0 | `res = signals.cepstrum(x, fs, kind='complex')`<br><br>• `CepstrumResult` |
| `CepstrumResult` | `dataclass` | **Cepstrum.**<br>• `quefrencies` [s], `cepstrum`, `kind`, `fs`, `nfft`, `linear_phase_samples`<br>• `.invert()`: homomorphic round trip (complex kind only)<br>• `.plot()`: cepstrum vs quefrency | `res.cepstrum, res.invert()` |
| `lifter` | `function` | **Lifter a log spectrum: envelope vs fine structure (Havelock Ch. 27).**<br>• `x`, `fs`, `cutoff` [s]<br>• `mode`: 'lowpass' (Default, spectral envelope) / 'highpass' (ripple)<br>• `nfft`<br>Modes exactly complementary in dB | `res = signals.lifter(x, fs, cutoff=0.004)`<br><br>• `LifterResult` |
| `LifterResult` | `dataclass` | **Liftered log spectrum.**<br>• `frequencies` [Hz], `spectrum_db`, `liftered_db`<br>• `quefrencies`, `cepstrum` (real), `cutoff`, `mode`, `fs`, `nfft`<br>• `.plot()`: cepstrum + cutoff, spectrum overlay | `res.liftered_db` |
| `echo_detection` | `function` | **Echo delay + reflection coefficient off the power cepstrum.**<br>• `x`, `fs`<br>• `min_quefrency` [s] (Default: 16 samples), `max_quefrency` [s] (Default: nfft/2)<br>• `nfft`<br>Peak height = a exactly for one in-record echo | `res = signals.echo_detection(ir, fs, min_quefrency=0.002)`<br><br>• `EchoDetectionResult` |
| `EchoDetectionResult` | `dataclass` | **Detected echo.**<br>• `delay` [s], `delay_samples`, `reflection_coefficient`<br>• `quefrencies`, `cepstrum`, `search_range`, `fs`, `nfft`<br>• `.plot()`: cepstrum with the peak marked | `res.delay, res.reflection_coefficient` |
| `minimum_phase` | `function` | **Minimum-phase response from \|H\| via the real cepstrum (B&P 13.1.4).**<br>• `response`: one-sided response or plain magnitude, rfft layout (DC–Nyquist)<br>• `oversample`: trig-interpolated cepstral anti-aliasing factor (Default: 8)<br>Input phase ignored; magnitude zeros floored at 1e-15 of the peak | `h_min = signals.minimum_phase(np.abs(H))`<br><br>• complex minimum-phase response, same bins |
| `group_delay` | `function` | **Group delay τ_g = −(1/2π)·dφ/df of a sampled response.**<br>• `response`: one-sided complex, rfft layout<br>• `fs` [Hz]<br>Unwrapped phase, central differences; needs < π phase advance per bin | `tau = signals.group_delay(H, fs)  # seconds` |
| `excess_phase` | `function` | **Excess (all-pass) phase: unwrap(arg H) − φ_min.**<br>• `response`: one-sided complex, rfft layout<br>• `oversample` (Default: 8)<br>0 for minimum phase, −2πf·t₀ for pure latency; the realizability limit of any stable causal inverse | `phi_x = signals.excess_phase(H)  # rad, 0 at DC` |
| `phase_decomposition` | `function` | **Minimum-phase / all-pass decomposition of a response.**<br>• `response`: one-sided complex, rfft layout (e.g. `np.fft.rfft(ir)`)<br>• `fs` [Hz]<br>• `oversample` (Default: 8) | `res = signals.phase_decomposition(np.fft.rfft(ir), fs)`<br><br>• `PhaseDecompositionResult` |
| `PhaseDecompositionResult` | `dataclass` | **Phase decomposition.**<br>• `frequencies` [Hz], `magnitude`, `phase` (measured, unwrapped, 0 at DC)<br>• `minimum_phase`, `excess_phase` [rad], `group_delay`, `excess_group_delay` [s]<br>• `minimum_phase_response` (complex), `fs`<br>• `.plot()`: magnitude, phases, group delays | `res.excess_phase, res.excess_group_delay` |
| `sound_power_anechoic` | `function` | **Precision sound power in an (hemi-)anechoic room (ISO 3745:2012).**<br>• `levels_positions`: (NM, NB) position levels [dB]<br>• `surface`: 'sphere'/'hemisphere'<br>• `radius` r [m]<br>• `background_levels` + `frequencies`: for K1i<br>• `areas`: partial areas Si (Eq. 13) (Default: equal-area Eq. 12)<br>• `temperature_c` [°C] (Default: 23), `static_pressure_kpa` [kPa] (Default: 101.325)<br>• `air_absorption_coefficient`: α(f) [dB/m] for C3<br>• `sigma_omc` [dB] (Default: 0), `coverage_factor` k (Default: 2.0)<br>• `room_qualification`: the `check_free_field` verdict of the room; warns beyond its radius or range | `res = emission.sound_power_anechoic(levels, 'hemisphere', radius=2.0, frequencies=f)`<br><br>• `PrecisionSoundPowerResult` |
| `PrecisionSoundPowerResult` | `dataclass` | **ISO 3745 sound power result.**<br>• `sound_power_level` [dB], `sound_power_level_a` [dB]<br>• `surface_pressure_level`, `mean_pressure_level` [dB]<br>• `background_correction`: K1i (NM, NB) [dB]<br>• `c1`, `c2`, `c3`: meteorological corrections [dB]<br>• `directivity_index` DIi, `non_uniformity_index` VIr [dB]<br>• `surface_area` [m²], `surface`<br>• `uncertainty`, `uncertainty_bands`, `coverage_factor`<br>• `.plot()` | `res.sound_power_level, res.uncertainty` |
| `precision_positions` | `function` | **ISO 3745 microphone coordinates (Annex D/E).**<br>• `surface`: 'sphere' (Table D.1) / 'hemisphere' (Tables E.1/E.2)<br>• `radius` r [m]<br>• `array`: 'general'/'broadband' (Default: 'general')<br>• `count`: 20 or 40 (Default: 40) | `xyz = emission.precision_positions('hemisphere', radius=2.0)`<br><br>• (40, 3) coordinates [m] |
| `precision_background_correction` | `function` | **Per-position background correction K1i (ISO 3745 Eq. 11).**<br>• `source_levels` / `background_levels`: (NM, NB) [dB]<br>• `frequencies` [Hz]: per-band criterion (10 dB for 250–5000 Hz, 6 dB outside) | `k1 = emission.precision_background_correction(src, bg, f)`<br><br>• K1i [dB]; clamped + `SoundPowerWarning` below the criterion |
| `meteorological_corrections` | `function` | **Corrections C1, C2, C3 (ISO 3745 Eq. 14 block).**<br>• `temperature_c` θ [°C] (Default: 23), `static_pressure_kpa` ps [kPa] (Default: 101.325)<br>• `air_absorption_coefficient`: α(f) [dB/m] for C3 (Default: None → C3 = 0)<br>• `radius` r [m] (Default: 1.0) | `met = emission.meteorological_corrections(temperature_c=23.0, static_pressure_kpa=101.325)`<br><br>• `MeteorologicalCorrection`; C1 = −0.128 dB, C2 = 0 at reference |
| `MeteorologicalCorrection` | `dataclass` | **C1/C2/C3 corrections.**<br>• `c1`: reference-quantity correction [dB]<br>• `c2`: radiation-impedance correction [dB]<br>• `c3`: air-absorption correction [dB], scalar or per band | `met.c1, met.c2, met.c3` |
| `precision_uncertainty` | `function` | **Expanded uncertainty U = k·√(σR0² + σomc²) (ISO 3745 Eq. 24/25).**<br>• `sigma_r0`: reproducibility (Tables 2/3) [dB]<br>• `sigma_omc` [dB] (Default: 0.0)<br>• `coverage_factor` k (Default: 2.0; 1.6 one-sided) | `precision_uncertainty(0.5)  # 1.0`<br><br>• U [dB], scalar or per band |
| `MicrophoneTraverse` | `dataclass` | **One straight microphone traverse (ISO 26101 5.1.3.2).**<br>• `positions_m`: (N, 3) points [m], z up, reflecting plane z = 0<br>• `levels_db`: (N, NF) L'pi [dB], `nan` where a point was not measured at a frequency, finite elsewhere<br>• `monitor_levels_db`: monitor microphone for Formula (1), finite at every measured point and in its first row (Default: None)<br>• `background_levels_db`: per point or one row, finite at every measured point (Default: None, 5.1.2.2 c) unjudged)<br>• `name`: a label for the path (Default: '')<br>• `targets`: what the path is selected towards, among 'dihedral corner', 'trihedral corner', 'boundary centre', 'closest boundary', 'unique features' (A.3.3 a) to e), Default: none)<br>• `.along(direction, distances_m, levels_db, start_m=..., name=..., targets=...)` builds a straight path | `t = emission.MicrophoneTraverse.along((1, 1, 1), d, lp, background_levels_db=bg)` |
| `inverse_square_law_deviations` | `function` | **Deviations from the inverse square law of one test source (ISO 26101 Formulae (1) to (4)).**<br>• `traverses`: the `MicrophoneTraverse` list<br>• `frequencies_hz` [Hz]<br>• `room`: 'anechoic' / 'hemi-anechoic' (Table A.1)<br>• `origin_m` (Default: frame origin) or `source_box_m`: origin searched inside the source volume (5.1.3.2, amended ISO 3745 A.3.3)<br>b is the midpoint of the admissible interval over the longest qualifying run: the exact maximum of the qualified distance | `fit = emission.inverse_square_law_deviations(ts, frequencies_hz=f, room='hemi-anechoic')`<br><br>• `InverseSquareLawResult` |
| `InverseSquareLawResult` | `dataclass` | **ISO 26101 analysis of one test source.**<br>• `origin_m`, `origin_fitted`, `source_box_m`<br>• `traverse_names`, `traverse_targets` (A.3.3), `positions_m` [m]<br>• `distances_m`, `levels_db`, `deviations_db` ΔLpi per traverse<br>• `background_margin_db` (5.1.2.2 c)), `source_stability_db` (largest monitor excursion)<br>• `source_strength_db` b, `initial_source_strength_db` (Formula (3))<br>• `traverse_radius_m` (NT, NF), `band_radius_m` [m], checked against the radii the levels qualify<br>• read-only `tolerance_db` (Table A.1 of the room)<br>• `maximum_qualified_radius_m`, `largest_deviation_db`<br>• `.plot(frequency_hz=...)` | `fit.maximum_qualified_radius_m`<br>`fit.plot(frequency_hz=1000)` |
| `check_free_field` | `function` | **Is the room anechoic or hemi-anechoic enough for ISO 3745? (Annex A as Amd 1:2017 wrote it).**<br>• `results`: one `InverseSquareLawResult` per test source<br>• `bandwidth`: 'discrete-frequency' / 'broadband' (A.4.1)<br>• `source_directionality`: `verify_source_directionality` result(s) (Default: None, unjudged)<br>• `measurement_radius_m` [m] (Default: None)<br>• `reflecting_plane_absorption_coefficient` (0 to 1), `reflecting_plane_margin_m` [m] (A.2.5, hemi-anechoic)<br>• `paths_in_working_area`: True / False, a declaration of A.3.3 (Default: None, unjudged)<br>• `speed_of_sound` [m/s] (Default: 343) | `chk = emission.check_free_field(fit, bandwidth='discrete-frequency', source_directionality=d)`<br><br>• `FreeFieldCheck` |
| `FreeFieldCheck` | `dataclass` | **Verdict of ISO 3745 Annex A with the ISO 26101 clauses it defers to.**<br>• `room`, `bandwidth`, `results`, `measurement_radius_m`<br>• `frequencies_hz`, `band_radius_m`, `maximum_qualified_radius_m` (A.2.4)<br>• per band: `points_met`, `equal_spacing_met`, `spacing_met` (A.4.3), `iso26101_spacing_met` (ISO 26101 A.4.3), `length_met` (5.1.4.3), `background_met`, `directionality_met`, `band_met`<br>• `traverse_count_met`, `path_targets_met`, `working_area_met`, `path_angles_met` (A.3.3), `reflecting_plane_met` (A.2.5)<br>• `full_frequency_range`, `conforming_range_hz`, `conforming_radius_m`, `not_judged`<br>• `passes` (full conformity), `discrete_frequency`<br>• `.plot()`<br>• takes `bandwidth`, `results`, `source_directionality`, `measurement_radius_m`, `reflecting_plane_absorption_coefficient`, `reflecting_plane_margin_m`, `paths_in_working_area`, `speed_of_sound`; `room`, `frequencies_hz`, `band_radius_m`, `maximum_qualified_radius_m`, `points_met`, `equal_spacing_met`, ... are read-only, read from them | `chk.passes, chk.conforming_range_hz` |
| `verify_source_directionality` | `function` | **May this source qualify the room? (ISO 26101 Annex B, Table B.1).**<br>• `levels_db`: (32 or 64 positions, NF) [dB] at the B.3.2 positions<br>• `frequencies_hz` [Hz]: one-third octave bands<br>• `room`: 'anechoic' / 'hemi-anechoic' | `d = emission.verify_source_directionality(lp, frequencies_hz=f, room='hemi-anechoic')`<br><br>• `SourceDirectionalityResult` |
| `SourceDirectionalityResult` | `dataclass` | **Test source directionality (ISO 26101 B.4).**<br>• `mean_level_db`, `maximum_positive_deviation_db`, `maximum_negative_deviation_db`, `tolerance_db`<br>• `within_tolerance` per band, `passes`<br>• `.plot()` | `d.passes` |
| `directionality_positions` | `function` | **Microphone positions of the directionality test (ISO 26101 B.3.2, Figure B.1).**<br>• `room`: 32 positions (hemi-anechoic) or 64 (anechoic)<br>• `radius_m` [m] (Default: 1.5) | `xyz = emission.directionality_positions('hemi-anechoic')`<br><br>• (32, 3) [m] |
| `inverse_square_law_tolerance_db` | `function` | **Table A.1 of ISO 26101 and of the amended ISO 3745.**<br>• `frequencies_hz` [Hz], read in their one-third octave band<br>• `room` | `emission.inverse_square_law_tolerance_db([1000.0], room='anechoic')  # [1.0]` |
| `directionality_tolerance_db` | `function` | **Table B.1 of ISO 26101.**<br>• `frequencies_hz` [Hz]<br>• `room` | `emission.directionality_tolerance_db([12500.0], room='anechoic')  # [5.0]` |
| `qualification_frequencies_hz` | `function` | **The frequencies ISO 3745 A.2.3 evaluates.**<br>• `low_hz` (Default: 100), `high_hz` (Default: 10 000)<br>One-third octaves below 125 Hz and above 4 kHz, octaves between | `emission.qualification_frequencies_hz()  # 11 frequencies` |
| `reference_source_calibration` | `function` | **Calibrate a reference sound source in a hemi-anechoic room (ISO 6926 clause 8, Formula (2)).**<br>• `levels_db`: (positions, bands) on the 2 m hemisphere [dB]<br>• `frequencies_hz`: one-third octaves 50 Hz-20 kHz<br>• `arrangement`: 'paths' / 'fixed' (Table 2 column)<br>• `background_levels_db`, `maximum_levels_db` (traverse maxima, 8.3.2)<br>• `conditions`: `CalibrationConditions` of the air (Default: None, the reference conditions of clause 4 with no air absorption)<br>• `radiation` / `knee_frequency_hz` / `c2_db`: C2 (Annex A or manufacturer)<br>• `intensity_sound_power_level_db`: Annex B low-frequency alternative<br>• `room_qualification`: `FreeFieldCheck` (8.1)<br>• `coverage_factor` (Default: 1.96) | `cal = emission.reference_source_calibration(lp, frequencies_hz=f, arrangement='fixed')`<br><br>• `ReferenceSourceCalibration` |
| `CalibrationConditions` | `dataclass` | **The air of a calibration on the 2 m hemisphere (ISO 6926 8.4).**<br>• `temperature_c` [°C] (Default: 23), `static_pressure_kpa` [kPa] (Default: 101.325): for C1 and the Annex A C2<br>• `air_absorption_db_per_m` [dB/m]: a(f) of ISO 9613-1 per band or one value, for C3 (Default: None, C3 = 0)<br>Refuses a temperature, pressure or absorption Formula (2) cannot read | `emission.CalibrationConditions(temperature_c=20.0, static_pressure_kpa=98.6, air_absorption_db_per_m=alpha)` |
| `ReferenceSourceCalibration` | `dataclass` | **Calibrated sound power of a reference sound source (ISO 6926 8.4).**<br>• `sound_power_level_db` [dB re 1 pW] at the reference conditions, `surface_pressure_level_db`<br>• `directivity_index_db`, `maximum_directivity_index_db`<br>• `c1_db`, `c2_db`, `c3_db`, `expanded_uncertainty_db`, `coverage_factor`<br>• `intensity_bands`, `intensity_agreement`, `room_qualified`<br>• `arrangement`, `radiation` and `knee_frequency_hz` of the Annex A C2 (None with the manufacturer's)<br>• `sound_power_level_a_db` over `a_weighted_range_hz`, `a_weighted_expanded_uncertainty_db`<br>• `.sound_power_level_at(f, bandwidth=..., temperature_c=..., static_pressure_kpa=...)`: what a comparison method reads, LW - C2 at the conditions of a test when they are given<br>• `.plot()`<br>• takes `frequencies_hz`, `surface_pressure_level_db`, `directivity_index_db`, `c1_db`, `c2_db`, `c3_db`, `expanded_uncertainty_db`, `coverage_factor`, `arrangement`, `radiation`, `knee_frequency_hz`, `intensity_sound_power_level_db`, `room_qualification`; `sound_power_level_db`, `intensity_bands`, `intensity_agreement`, `room_qualified` are read-only, read from them | `cal.sound_power_level_at([125, 250], bandwidth='octave')` |
| `verify_reference_sound_source` | `function` | **May this source be declared a reference sound source? (ISO 6926 clause 5).**<br>• `calibration`: `ReferenceSourceCalibration` or LW per band [dB]<br>• `frequencies_hz` (plain levels only)<br>• `repeated_levels_db`: (3, bands) LW or (5, bands) Lp (Default: None, 5.2 unjudged)<br>• `supply_variation_db`: largest change over the declared supply range [dB], one or per band (Default: None, 5.2 unjudged)<br>• `directivity_index_db` (plain levels only)<br>• `reverberation_rooms_only` (Default: False) | `v = emission.verify_reference_sound_source(cal, repeated_levels_db=rep)`<br><br>• `ReferenceSoundSourceVerdict` |
| `ReferenceSoundSourceVerdict` | `dataclass` | **Clause 5 of ISO 6926.**<br>• `sound_power_level_db` per band<br>• `repeatability_db` σr against `repeatability_limit_db` (Table 1)<br>• `supply_variation_db` against `supply_limit_db` (5.2)<br>• `adjacent_step_db`, `adjacent_limit_db`, `core_range_db` against `core_range_limit_db`, `extended_range_db` against `extended_range_limit_db` (5.4)<br>• `directivity_index_db` against `directivity_limit_db` (5.5), `reverberation_rooms_only`<br>• `stability_met`, `supply_met`, `spectrum_met`, `directivity_met`, `frequency_range_met`, `not_judged`, `passes`<br>• `.plot()` | `v.passes, v.spectrum_met` |
| `verify_reference_source_drift` | `function` | **Has the source drifted beyond 2,83 times Table 1? (ISO 6926 5.6).**<br>• `reference_levels_db`, `latest_levels_db`: per band [dB]<br>• `frequencies_hz` [Hz] | `emission.verify_reference_source_drift(old, new, frequencies_hz=f).recalibration_required`<br><br>• `ReferenceSourceDriftResult` |
| `ReferenceSourceDriftResult` | `dataclass` | **Drift of a reference sound source.**<br>• `change_db`, `limit_db`<br>• `passes`, `recalibration_required`<br>• `.plot()` | `drift.recalibration_required` |
| `repeatability_standard_deviation` | `function` | **σr under repeatability conditions (ISO 6926 Formula (1)).**<br>• `levels_db`: (N, bands) repeated levels [dB]<br>About the energy average of the N repetitions | `emission.repeatability_standard_deviation([80.0, 80.2, 79.9])` |
| `radiation_impedance_correction` | `function` | **C2 of ISO 6926 Annex A.**<br>• `temperature_c` [°C], `static_pressure_kpa` [kPa]<br>• `radiation`: 'unknown' (7,5 lg) / 'monopole' (15 lg below, 5 lg above the knee) / 'dipole' (25 lg above the knee)<br>• `frequencies_hz`, `knee_frequency_hz` (monopole, dipole) | `emission.radiation_impedance_correction(temperature_c=30.0, static_pressure_kpa=95.0)` |
| `knee_frequency` | `function` | **Knee frequency f_k = c/(2π d0) (ISO 6926 Formula (A.1)).**<br>• `d0_m` [m]<br>• `speed_of_sound` [m/s] (Default: 343) | `emission.knee_frequency(0.2)  # 273 Hz` |
| `reference_source_reproducibility_db` | `function` | **σR of a calibration (ISO 6926 Table 2).**<br>• `frequencies_hz` [Hz]<br>• `environment`: 'hemi-anechoic' / 'reverberation-room'<br>• `arrangement`: 'paths' / 'fixed' (hemi-anechoic)<br>• `bandwidth`: 'one-third-octave' / 'octave' | `emission.reference_source_reproducibility_db([1000.0], environment='hemi-anechoic', arrangement='fixed')  # [0.5]` |
| `sound_power_intensity_precision` | `function` | **Sound power by intensity scanning, precision (ISO 9614-3:2002).**<br>• `partial_intensity`: (N, NB) signed In,i [W/m²]<br>• `areas`: partial areas Si [m²]<br>• `frequencies` [Hz]: for LWA<br>• `temperature_c` [°C] (Default: 23), `barometric_pressure_pa` [Pa] (Default: 101325): for LW0 (Eq. 10) | `res = emission.sound_power_intensity_precision(In, areas, frequencies=f)`<br><br>• `PrecisionIntensityResult` |
| `PrecisionIntensityResult` | `dataclass` | **ISO 9614-3 scanning result.**<br>• `partial_power`: Pi = In,i·Si [W]<br>• `sound_power` P, `sound_power_level` LW [dB] (NaN where P ≤ 0)<br>• `sound_power_level_normalized`: LW0 [dB]<br>• `not_applicable_band`: per-band bool<br>• `surface_area` [m²], `sound_power_level_a` [dB]<br>• `.plot()`<br>• takes `frequencies`, `partial_power`, `surface_area`, `temperature_c`, `barometric_pressure_pa`; `sound_power`, `sound_power_level`, `sound_power_level_normalized`, `not_applicable_band`, `sound_power_level_a` are read-only, read from them | `res.sound_power_level, res.not_applicable_band` |
| `precision_field_indicators` | `function` | **ISO 9614-3 Annex B field indicators.**<br>• `segment_intensity`: (N, NB) signed In,j [W/m²]<br>• `segment_pressure_levels`: (N, NB) Lpj [dB]<br>• `time_window_intensity`: (M, NB) for FT (Default: None) | `fi = emission.precision_field_indicators(In, lp)`<br><br>• `PrecisionFieldIndicators` |
| `PrecisionFieldIndicators` | `dataclass` | **Annex B indicators (per band).**<br>• `ft`: temporal variability (= F1) or None<br>• `f_pi_unsigned`: F_pIn unsigned (= F2)<br>• `f_pi_signed`: F_pIn signed (= F3), ≥ unsigned<br>• `fs`: field non-uniformity FS (= F4) | `fi.f_pi_signed, fi.fs` |
| `precision_qualification` | `function` | **The five ISO 9614-3 Annex C acceptance criteria.**<br>• `indicators`: `PrecisionFieldIndicators`<br>• `scan_intensity_level_1`/`_2`: LIn per scan [dB] (criterion 1)<br>• `pressure_residual_index`: δpI0 [dB] (criterion 2, K = 10)<br>• `field_nonuniformity_1`/`_2`: FS per scan density (criterion 5)<br>• `frequencies` [Hz] or `repeatability_limit`: Table 1 limit s | `q = emission.precision_qualification(fi, pressure_residual_index=18.0)`<br><br>• `PrecisionCriteria` |
| `PrecisionCriteria` | `dataclass` | **Annex C pass/fail per band.**<br>• `criterion_1`…`criterion_5`: bool arrays or None where not evaluable<br>• `qualified`: conjunction of criteria 1–4 or None<br>• takes `indicators`, `scan_intensity_level_1`, `scan_intensity_level_2`, `frequencies`, `repeatability_limit_db`, `pressure_residual_index_db`, `field_nonuniformity_1`, `field_nonuniformity_2`; `criterion_1`, `criterion_2`, `criterion_3`, `criterion_4`, `criterion_5`, `qualified` are read-only, read from them | `q.qualified, q.criterion_2` |
| `plane_wave_frequency_range` | `function` | **Working plane-wave range (f_l, f_u) (ISO 10534-2 §4.2–4.5).**<br>• `spacing` s [m]<br>• `speed_of_sound` c0 [m/s]<br>• `diameter_m` d [m] (Default: None → spacing bound only)<br>• `shape`: 'circular'/'rectangular'/'square' (Default: 'circular') | `plane_wave_frequency_range(0.05, 343.2, diameter_m=0.1)  # (343.2, 1990.6)`<br><br>• [Hz] |
| `plane_wave_frequency_range_astm` | `function` | **Working plane-wave range (f_l, f_u) (ASTM E2611-19 6.2.3–6.2.5, 6.5.4).**<br>• `spacing` s [m]<br>• `speed_of_sound` c [m/s]<br>• `diameter_m` d [m] (Default: None → spacing bound only)<br>• `shape`: 'circular'/'rectangular'/'square' (Default: 'circular') | `plane_wave_frequency_range_astm(0.05, 343.2, diameter_m=0.1)  # (68.6, 2011.2)`<br><br>• [Hz]; f_u s < 0.40 c, f_u d < 0.586 c (0.500 rectangular) |
| `plot_impedance_tube_geometry` | `function` | **To-scale side view of the ISO 10534-2 tube.**<br>• `spacing` s, `x1` [m]<br>• `diameter_m` d [m], `shape` (Default: 'circular')<br>• `sample_thickness` [m] (Default: 50 mm nominal)<br>• `language` | `plot_impedance_tube_geometry(spacing=0.05, x1=0.15, diameter_m=0.10)`<br><br>• Dimensioned drawing + plane-wave range; also `ImpedanceTubeResult.plot_geometry()` |
| `plot_transmission_tube_geometry` | `function` | **To-scale side view of the ASTM E2611 tube.**<br>• `l1`, `s1`, `l2`, `s2`, `thickness` [m]<br>• `diameter_m` d [m], `shape` (Default: 'circular')<br>• `language` | `plot_transmission_tube_geometry(l1=0.10, s1=0.05, l2=0.20, s2=0.05, thickness=0.05, diameter_m=0.10)`<br><br>• Four microphones + termination; also `TransferMatrix.plot_geometry()` |
| `speed_of_sound_iso10534` | `function` | **Speed of sound (ISO 10534-2 Eq. 5).**<br>• `temperature_c` t [°C] | `speed_of_sound_iso10534(temperature_c=19.85)  # 343.2`<br><br>• c0 = 343.2 √(T/293) [m/s], T = 273.15 + t |
| `air_density_iso10534` | `function` | **Air density (ISO 10534-2 Eq. 7).**<br>• `temperature_c` t [°C]<br>• `atmospheric_pressure_kpa` [kPa] (Default: 101.325) | `air_density_iso10534(temperature_c=19.85)  # 1.186`<br><br>• ρ [kg/m³] |
| `speed_of_sound_astm` | `function` | **Speed of sound (ASTM E2611-19 Eq. 4).**<br>• `temperature_c` T [°C] | `speed_of_sound_astm(temperature_c=20.0)  # 343.2`<br><br>• 20.047 √(273.15 + T) [m/s] |
| `air_density_astm` | `function` | **Air density (ASTM E2611-19 Eq. 5).**<br>• `temperature_c` T [°C]<br>• `atmospheric_pressure_kpa` P [kPa] (Default: 101.325) | `air_density_astm(temperature_c=20.0)  # 1.202`<br><br>• ρ [kg/m³] |
| `hydraulic_diameter` | `function` | **Hydraulic diameter of a rectangular tube, 4A/P (ISO 10534-2 A.2.1.5).**<br>• `width` w [m]<br>• `height` h [m] | `hydraulic_diameter(0.08, 0.04)  # 0.0533`<br><br>• d_h = 2wh/(w + h) [m]; feed to `tube_attenuation_constant` |
| `tube_attenuation_constant` | `function` | **Lower-bound tube attenuation k0″ (ISO 10534-2 Eq. A.18).**<br>• `frequency` f [Hz]<br>• `speed_of_sound` c0 [m/s]<br>• `diameter_m` d [m] (hydraulic for rectangular) | `tube_attenuation_constant(1000.0, 343.2, 0.1)  # 0.0179`<br><br>• [Np/m] |
| `tube_wavenumber` | `function` | **Complex wavenumber k0 = k0′ − j k0″ (ISO 10534-2 §2.6).**<br>• `frequency` f [Hz]<br>• `speed_of_sound` c0 [m/s]<br>• `attenuation`: k0″ [Np/m] (Default: None → lossless) | `tube_wavenumber(1000.0, 343.2, attenuation=0.018)`<br><br>• 18.308 − 0.018j [1/m] |
| `mic_calibration_factor` | `function` | **Microphone-mismatch calibration factor Hc (ISO 10534-2 Eq. 10).**<br>• `h12_config1`: H12 in the standard configuration<br>• `h12_config2`: H12 with the microphones interchanged | `hc = materials.mic_calibration_factor(h12_a, h12_b)`<br><br>• Hc = √(H12ᴵ/H12ᴵᴵ) (complex) |
| `apply_mic_calibration` | `function` | **Apply the calibration factor (Eq. 13).**<br>• `h12_uncorrected`<br>• `calibration_factor`: Hc | `h12 = materials.apply_mic_calibration(h12_raw, hc)`<br><br>• H12 = H12,raw/Hc |
| `reflection_factor` | `function` | **Complex reflection factor at the sample surface (ISO 10534-2 Eq. 17).**<br>• `h12`: corrected transfer function<br>• `spacing` s [m]<br>• `x1`: sample to the farther microphone [m]<br>• `wavenumber`: complex k0 | `r = materials.reflection_factor(h12, spacing=0.05, x1=0.15, wavenumber=k0)`<br><br>• r = (H12 − HI)/(HR − H12)·e^(+2jk0x1) |
| `absorption_from_reflection` | `function` | **Normal-incidence absorption coefficient (Eq. 18).**<br>• `reflection`: complex r | `absorption_from_reflection(0.5)  # 0.75`<br><br>• α = 1 − \|r\|² |
| `surface_impedance` | `function` | **Absolute surface impedance Z (Eq. 19).**<br>• `reflection`: complex r<br>• `characteristic_impedance`: ρc0 [rayl] | `surface_impedance(0.5, 407.0)  # 1221`<br><br>• Z = ρc0(1 + r)/(1 − r) [rayl] |
| `normalized_surface_impedance` | `function` | **Normalised surface impedance Z/(ρc0) (Eq. 19).**<br>• `reflection`: complex r | `normalized_surface_impedance(0.5)  # 3.0` |
| `normalized_surface_admittance` | `function` | **Normalised surface admittance Gρc0 (Eq. 20).**<br>• `reflection`: complex r | `normalized_surface_admittance(0.5)  # 0.333`<br><br>• (1 − r)/(1 + r) |
| `two_microphone_impedance` | `function` | **Full two-microphone reduction (ISO 10534-2 Clause 7).**<br>• `h12`: corrected transfer function<br>• `frequency` f [Hz]<br>• `spacing` s [m], `x1` [m]<br>• `speed_of_sound` c0 [m/s], `characteristic_impedance` ρc0 [rayl]<br>• `attenuation`: k0″ [Np/m] (Default: None)<br>• `diameter_m` + `shape`: activate the plane-wave range check | `res = materials.two_microphone_impedance(h12, frequency=f, spacing=0.05, x1=0.15, speed_of_sound=343.2, characteristic_impedance=407.0)`<br><br>• `ImpedanceTubeResult` |
| `ImpedanceTubeResult` | `dataclass` | **Two-microphone result per frequency.**<br>• `frequencies` [Hz]<br>• `reflection`: complex r (Eq. 17)<br>• `surface_impedance` [rayl], `normalized_impedance` (Eq. 19)<br>• `absorption`: α = 1 − \|r\|² (Eq. 18)<br>• Retains `spacing`, `x1`, `diameter_m`, `shape` when supplied | `res.absorption, res.normalized_impedance` |
| `ImpedanceTubeWarning` | `warning class` | **ISO 10534-2 advisory.**<br>Emitted by `two_microphone_impedance` for frequencies outside the plane-wave working range (Eqs. 1–4); the results are still returned | `warnings.simplefilter('error', ImpedanceTubeWarning)` |
| `standing_wave_ratio_from_level` | `function` | **Standing-wave ratio from ΔL (ISO 10534-1 Eq. 15).**<br>• `level_difference`: Lmax − Lmin [dB] | `standing_wave_ratio_from_level(20.0)  # 10.0`<br><br>• s = 10^(ΔL/20) |
| `standing_wave_reflection_magnitude` | `function` | **Reflection magnitude from the SWR (Eq. 14).**<br>• `swr`: s ≥ 1 | `standing_wave_reflection_magnitude(10.0)  # 0.818`<br><br>• \|r\| = (s − 1)/(s + 1) |
| `standing_wave_reflection` | `function` | **Complex reflection factor from the standing wave (Eqs. 17–23).**<br>• `swr`: s<br>• `first_min_distance`: x_min1 [m]<br>• `wavelength`: λ0 [m] | `standing_wave_reflection(10.0, 0.05, 0.4)  # -0.818j`<br><br>• phase φ = π(4x_min1/λ0 − 1) |
| `standing_wave_absorption` | `function` | **Absorption from the SWR (Eqs. 9 + 14).**<br>• `swr`: s ≥ 1 | `standing_wave_absorption(10.0)  # 0.331`<br><br>• α = 4s/(s + 1)² |
| `standing_wave_normalized_impedance` | `function` | **Normalised impedance from the standing wave (Eqs. 24–26).**<br>• `swr`, `first_min_distance` [m], `wavelength` [m] | `standing_wave_normalized_impedance(10.0, 0.05, 0.4)`<br><br>• 0.198 − 0.98j |
| `wave_decomposition` | `function` | **Decompose the field into (A, B, C, D) (ASTM E2611-19 Eqs. 17–20).**<br>• `h1`…`h4`: microphone transfer functions<br>• `l1`, `s1`, `l2`, `s2`: geometry [m]<br>• `wavenumber` k<br>• `diameter_m` + `shape`: activate the plane-wave range check | `A, B, C, D = materials.wave_decomposition(h1, h2, h3, h4, l1=0.2, s1=0.05, l2=0.2, s2=0.05, wavenumber=k)`<br><br>• Forward/backward amplitudes, both sides |
| `face_quantities` | `function` | **Face pressures and velocities (Eq. 21).**<br>• `a`, `b`, `c`, `d`: wave amplitudes<br>• `wavenumber` k, `thickness` d [m], `characteristic_impedance` ρc | `p0, pd, u0, ud = materials.face_quantities(A, B, C, D, wavenumber=k, thickness=0.05, characteristic_impedance=407.0)` |
| `transfer_matrix_two_load` | `function` | **Two-load transfer matrix (ASTM E2611-19 Eqs. 17–22).**<br>• `load_a`, `load_b`: (H1, H2, H3, H4) per termination<br>• `l1`, `s1`, `l2`, `s2`, `thickness` [m]<br>• `wavenumber`, `characteristic_impedance`<br>• `frequencies` (retained for `.plot()`), `diameter_m` + `shape`: range check | `T = materials.transfer_matrix_two_load(load_a, load_b, l1=0.2, s1=0.05, l2=0.2, s2=0.05, thickness=0.05, wavenumber=k, characteristic_impedance=407.0)`<br><br>• `TransferMatrix` |
| `transfer_matrix_one_load` | `function` | **One-load transfer matrix, symmetric specimen (Eqs. 23–24).**<br>• `load`: (H1, H2, H3, H4)<br>• Same geometry/frequency/range-check parameters as `transfer_matrix_two_load` | `T = materials.transfer_matrix_one_load(load, l1=0.2, s1=0.05, l2=0.2, s2=0.05, thickness=0.05, wavenumber=k, characteristic_impedance=407.0)`<br><br>• Requires reciprocity + symmetry |
| `air_layer_transfer_matrix` | `function` | **Analytic loss-free air-layer matrix (validation reference).**<br>• `wavenumber` k<br>• `thickness` d [m]<br>• `characteristic_impedance` ρc [rayl] | `T = materials.air_layer_transfer_matrix(k, 0.05, 407.0)`<br><br>• det(T) = 1, T11 = T22 |
| `TransferMatrix` | `dataclass` | **Acoustic transfer matrix [[T11, T12], [T21, T22]] (ASTM E2611-19 Eq. 16).**<br>• `t11`, `t12`, `t21`, `t22`: complex, scalar or per frequency<br>• Solver-built matrices retain `l1`/`s1`/`l2`/`s2`, `thickness`, `diameter_m`, `shape`, `frequencies`, `air_characteristic_impedance` (so `.plot()` needs no arguments) | `T.t11, T.t12` |
| `airflow_resistance` | `function` | **Airflow resistance R = Δp/qv (ISO 9053-1:2018 §3.1).**<br>• `pressure_drop_pa` Δp [Pa]<br>• `volume_flow_rate` qv [m³/s] | `airflow_resistance(2.0, 0.0005)  # 4000.0`<br><br>• [Pa·s/m³] |
| `specific_airflow_resistance` | `function` | **Specific airflow resistance Rs (§3.2).**<br>• `resistance` R + `area` A, **or** `pressure_drop_pa` Δp + `velocity` u | `specific_airflow_resistance(4000.0, 0.01)  # 40.0`<br><br>• Rs = R·A = Δp/u [Pa·s/m] |
| `airflow_resistivity` | `function` | **Airflow resistivity σ = Rs/d (§3.3).**<br>• `specific_resistance` Rs [Pa·s/m]<br>• `thickness` d [m] | `airflow_resistivity(40.0, 0.05)  # 800.0`<br><br>• [Pa·s/m²] |
| `linear_airflow_velocity` | `function` | **Linear airflow velocity u = qv/A (§3.4).**<br>• `volume_flow_rate` qv [m³/s]<br>• `area` A [m²] | `linear_airflow_velocity(5e-6, 0.01)  # 0.0005`<br><br>• [m/s] |
| `static_airflow_resistance` | `function` | **Stepwise static-method determination (ISO 9053-1 §7.5).**<br>• `velocities` u [m/s], `pressure_drops_pa` Δp [Pa] (≥ 2 steps)<br>• `area` A [m²]<br>• `thickness` d [m] (Default: None → no σ)<br>• `evaluation_velocity` [m/s] (Default: 0.0005) | `res = materials.static_airflow_resistance([0.0005, 0.001, 0.002], [0.02, 0.041, 0.086], 0.01, 0.05)`<br><br>• `StaticAirflowResult` (Rs = 40.0, σ = 800) |
| `StaticAirflowResult` | `dataclass` | **Static-method result at the evaluation velocity.**<br>• `resistance` R [Pa·s/m³], `specific_resistance` Rs [Pa·s/m]<br>• `resistivity` σ [Pa·s/m²] or None<br>• `evaluation_velocity` [m/s], `pressure_drop_pa` [Pa]<br>• `linear_coefficient` a (zero-velocity Rs), `quadratic_coefficient` b | `res.specific_resistance, res.resistivity` |
| `piston_volume_flow_rate` | `function` | **RMS piston volume flow qv = 2πf·h·AP (ISO 9053-2 §6.2).**<br>• `frequency` f [Hz]<br>• `stroke_amplitude` h [m]<br>• `piston_area` AP [m²] | `piston_volume_flow_rate(2.0, 0.005, 0.01)  # 0.000628`<br><br>• [m³/s] |
| `alternating_airflow_resistance` | `function` | **Alternating-method resistance (ISO 9053-2:2020 Formula 2).**<br>• `level_specimen` Lps / `level_termination` Lpt [dB]<br>• `piston_stroke_specimen` hs / `piston_stroke_termination` ht [m]<br>• `frequency` f [Hz] (1–4 Hz), `cavity_volume` V [m³]<br>• `static_pressure_pa` [Pa] (Default: 101325)<br>• `kappa_prime` κ′ (Default: 1.4; use `effective_kappa` for Annex A conformity)<br>• `background_level` Lpb [dB] (Default: None) | `r = materials.alternating_airflow_resistance(78.0, 60.0, piston_stroke_specimen=5e-3, piston_stroke_termination=5e-4, frequency=2.0, cavity_volume=7.854e-4)`<br><br>• R [Pa·s/m³]; `AirflowResistanceWarning` when criteria fail |
| `ANNEX_A_AIR` | `Fluid` | **The air of the ISO 9053-2:2020 Annex A.3 reference state (23 °C, 101 325 Pa, 50 % RH).**<br>345,866 52 m/s, 1,186 084 8 kg/m³, κ = 1,400 757 3, plus the conductivity and specific heat Clause F.6 gives<br>• the default of `thermal_boundary_layer_thickness` and `effective_kappa`; pass a computed `fluids.air()` to work in the air of the laboratory instead | `materials.ANNEX_A_AIR.speed_of_sound  # 345.86652` |
| `thermal_boundary_layer_thickness` | `function` | **Thermal boundary-layer thickness b (ISO 9053-2 Formulas A.4/A.5).**<br>• `frequency` f [Hz]<br>• Air properties (Default: Annex A.3 values) | `thermal_boundary_layer_thickness(2.0)  # 0.00183`<br><br>• [m] |
| `effective_kappa` | `function` | **Effective ratio of specific heats κ′ (Formula A.7).**<br>• `cavity_surface` S [m²], `cavity_volume` V [m³]<br>• `frequency` f [Hz]<br>• Air properties (Default: Annex A.3 values) | `effective_kappa(0.0471, 7.854e-4, 2.0)  # 1.37`<br><br>• The Annex A.3 worked example |
| `delany_bazley` | `function` | **Delany–Bazley one-parameter porous model (Mechel 2e G.11; Bies 5e Table D.1).**<br>• `frequency` f [Hz]<br>• `flow_resistivity` σ [Pa·s/m²]<br>• `coefficients`: preset name or (C1…C8) (Default: 'delany_bazley' rockwool/fibreglass)<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`, 343.0 m/s and 1.205 kg/m³)<br>• Warns outside 0.01 < X < 1 (X = ρf/σ) | `med = materials.delany_bazley(f, 20000.0)`<br><br>• `PorousMediumResult` |
| `miki` | `function` | **Miki (1990) positive-real revision of Delany–Bazley.**<br>• `frequency` f [Hz]<br>• `flow_resistivity` σ [Pa·s/m²]<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`)<br>• Stays passive below the fit range; warns outside 0.01 < f/σ < 1 | `med = materials.miki(f, 20000.0)`<br><br>• `PorousMediumResult` |
| `johnson_champoux_allard` | `function` | **JCA five-parameter rigid-frame model (Cox & D'Antonio 3e Eqs. 6.19–6.25).**<br>• `frequency` f [Hz], `flow_resistivity` σ [Pa·s/m²]<br>• `porosity` φ, `tortuosity` T = α∞<br>• `viscous_length` Λ / `thermal_length` Λ′ [m]<br>• `fluid`: `Fluid` carrying the air state the model needs, viscosity, Prandtl number, ratio of specific heats and static pressure (Default: `PUBLISHED_AIR`) | `med = materials.johnson_champoux_allard(f, 20000.0, porosity=0.98, tortuosity=1.05, viscous_length=8.7e-5, thermal_length=1.7e-4)`<br><br>• `PorousMediumResult` |
| `limp_frame` | `function` | **Limp-frame correction of any rigid-frame model (Allard & Atalla 2e Eqs. 11.53-11.55, Panneton 2007).**<br>• `medium`: a rigid-frame `PorousMediumResult`<br>• `frame_density` ρ₁ [kg/m³] (bulk density of the frame)<br>• `porosity` φ (Default: 1.0)<br>• keeps K_e, corrects ρ_e; → ρ_t = ρ₁ + φρ₀ as ω → 0 and → rigid as ρ₁ → ∞ | `soft = materials.limp_frame(jca, frame_density=30.0, porosity=0.98)`<br><br>• `PorousMediumResult`, model 'materials.limp_frame(...)' |
| `decoupling_frequency` | `function` | **Zwikker-Kosten decoupling frequency Fd (Allard & Atalla 2e Sect. 11.3.4 / Eq. 6.90).**<br>• `flow_resistivity` σ [Pa·s/m²]<br>• `porosity` φ, `frame_density` ρ₁ [kg/m³]<br>• Fd = σφ²/(2πρ₁): above it the frame stands still | `gw = materials.PUBLISHED_POROUS['allard-2009-table-6-1/domisol_coffrage']`<br>`decoupling_frequency(gw.printed('flow_resistivity_pa_s_m2'), porosity=gw.printed('porosity'), frame_density=gw.printed('frame_density_kg_m3'))  # 43.27`<br><br>• [Hz] |
| `limp_frame_applicable` / `LIMP_FRAME_CRITERIA` | `function` / `mapping` | **Published rule of thumb for treating a frame as limp (Allard & Atalla 2e pp. 253-254).**<br>• `frame_bulk_modulus` K_c [Pa]<br>• `criterion`: 'doutres' (0.2, Default) / 'beranek' (0.05)<br>• `fluid_bulk_modulus` K_f [Pa] (Default: 101325, isothermal air) → the book's "bulk modulus lower than 20 kPa" | `limp_frame_applicable(20e3)  # True`<br><br>• `bool` |
| `biot_waves` | `function` | **The three Biot waves of a poroelastic layer (Allard & Atalla 2e Eqs. 6.67–6.84).**<br>• `medium`: the **rigid-frame** `PorousMediumResult` of the pores<br>• `porosity` φ, `tortuosity` α∞<br>• `frame_density` ρ₁ [kg/m³], `shear_modulus` N [Pa] (complex, Im ≥ 0)<br>• `poisson_ratio` ν (Default: 0) | `w = materials.biot_waves(jca, porosity=0.94, tortuosity=1.06, frame_density=130.0, shear_modulus=2.2e6*(1+0.1j))`<br><br>• `BiotWavesResult` |
| `BiotWavesResult` | `dataclass` | **Two compressional waves and one shear wave.**<br>• `compressional_wavenumber_1` / `_2`, `shear_wavenumber` δ [rad/m]<br>• `velocity_ratio_1` / `_2` / `_3` μ (fluid over frame)<br>• `elastic_p` / `_q` / `_r` P, Q, R [Pa]; `density_11` / `_12` / `_22`<br>• `.airborne_wavenumber`, `.frame_borne_wavenumber`, `.airborne_velocity_ratio`, `.frame_borne_velocity_ratio`, `.airborne_is_second`<br>• `.plot()`: the three wavenumbers vs frequency | `w.airborne_wavenumber, w.plot()` |
| `biot_surface_impedance` | `function` | **Hard-backed Biot layer at normal incidence, closed form (Allard & Atalla 2e Eqs. 6.107–6.108).**<br>• `waves`: a `BiotWavesResult`<br>• `thickness` l [m]<br>• Glued backing; one layer; normal incidence only | `zs = materials.biot_surface_impedance(w, 0.10)`<br><br>• complex [Pa·s/m] |
| `poroelastic_transfer_matrix` | `function` | **6×6 layer matrix `[T p] = [Γ(−h)][Γ(0)]⁻¹` (Allard & Atalla 2e Eq. 11.34, Table 11.1).**<br>• `waves`, `thickness` h [m]<br>• `transverse_wavenumber` kt = k sin θ [rad/m] (Default: 0)<br>• Field vector [v1s, v3s, v3f, σ33s, σ13s, σ33f] | `t = materials.poroelastic_transfer_matrix(w, 0.05)`<br><br>• (n, 6, 6) complex |
| `frame_bulk_modulus` | `function` | **Bulk modulus Kb of the frame in vacuum (Allard & Atalla 2e Eq. 6.29).**<br>• `shear_modulus` N [Pa], `poisson_ratio` ν<br>• Kb = 2N(ν+1)/(3(1−2ν)); feeds `limp_frame_applicable` | `frame_bulk_modulus(2.2e6, 0.0)`<br><br>• complex [Pa] |
| `frame_elastic_coefficient` | `function` | **Longitudinal coefficient Kc of the frame in vacuum (Allard & Atalla 2e Eq. 6.111).**<br>• `shear_modulus` N [Pa], `poisson_ratio` ν<br>• Kc = 2(1−ν)N/(1−2ν) = Kb + 4N/3 | `frame_elastic_coefficient(2.2e6, 0.0)  # 4.4e6`<br><br>• complex [Pa] |
| `frame_quarter_wave_resonance` | `function` | **λ/4 frame resonance of a glued layer (Allard & Atalla 2e Eq. 6.110).**<br>• `thickness` l [m]<br>• `shear_modulus` N, `poisson_ratio` ν, `frame_density` ρ₁<br>• fr = (1/4l)√(Re(Kc)/ρ₁): the peak no equivalent fluid produces | `frame_quarter_wave_resonance(0.10, shear_modulus=2.2e6*(1+0.1j), poisson_ratio=0.0, frame_density=130.0)  # 459.9`<br><br>• [Hz] |
| `PorousMediumResult` | `dataclass` | **Equivalent-fluid characterisation.**<br>• `characteristic_impedance` Zc [Pa·s/m], `wavenumber` k [rad/m] (Im < 0)<br>• `effective_density`, `bulk_modulus` (surface-normalised)<br>• `.normalized_impedance`, `.normalized_wavenumber`<br>• `.plot()`: normalised Zc/k components | `med.characteristic_impedance, med.plot()` |
| `PorousMaterial` | `dataclass` | **One row of a published table of porous-material parameters.**<br>• Every quantity optional, because no two tables print the same columns; `.why_missing(field)` says what the page had instead, and `.printed(field)` narrows or refuses<br>• `flow_resistivity_pa_s_m2`, `porosity`, `tortuosity`, `viscous_length_um`, `thermal_length_um`, `thermal_permeability_m2`, `frame_density_kg_m3`, `thickness_mm`<br>• `youngs_modulus_pa`, `shear_modulus_pa` (**real**), `poisson_ratio`, `structural_loss_factor`: a page printing `N(1 + jη)` has printed `shear_modulus_pa` and `structural_loss_factor`<br>• `approximate`, `ranges`, `bounded_above`, `reported`, `unquantified`: what the cell was, when it was not a value<br>• `derived`: field → how this library computed it; `attributed_to`: per-cell credit; `variant`: which specimen, when a page prints several under one name<br>• `.medium(f)` → `PorousMediumResult`; `.frame_constants()` → (N, ν) with N complex, refusing a row without its loss factor rather than reading it as 0<br>• Not a material database: a real specimen is characterised to ISO 9053 and ISO 10534-2 | `foam = materials.PUBLISHED_POROUS['allard-2009-table-13-1/foam']`<br>`med = foam.medium(f)`<br><br>• `foam.source` prints the page |
| `PUBLISHED_POROUS` | `mapping` | **A hundred and ninety-four porous rows from twenty-six published tables, keyed `'<table>/<row>'`.**<br>• Two kinds of row: a **specimen** is one measured sample with every parameter a model needs, and a **compiled** row is one quantity over a class of material, almost always an interval<br>• Allard & Atalla 2e, the specimen rows of nineteen tables over eight chapters, each one the input to a worked example of the book<br>• Cox & D'Antonio 3e Tables 6.2, 6.3, 6.5, 6.8 and 6.9 and Mechel 2e Sect. G.1 and G.11, compiled from the literature; seven of the eight porosity ranges Cox credits to Mechel match Mechel's own page to the digit<br>• The key names the table because the book prints one foam in four chapters and one glass wool in two, sometimes with a column the other page leaves out<br>• Table 6.1 prints the glass wool's shear modulus in N/cm², Table 11.8 prints the same specimen's Young's modulus in pascals, and `E/(2(1+ν))` reconciles them<br>• Table 9.1 prints its lengths in millimetres and Table 13.1 in metres; all of them are stored in micrometres<br>• Table 11.5 prints the word 'model' where a screen's tortuosity would go, and the row keeps the word rather than a number<br>• The plates, septa and impervious screens these pages also print are not porous materials and are not here | `materials.PUBLISHED_POROUS['allard-2009-table-11-2/soft_fibrous']`<br><br>• `PorousMaterial`, `porous_materials_named` |
| `porous_materials_named` | `function` | **Every row for a specimen name, across the tables.**<br>• Matches `PorousMaterial.name` without regard to case; empty when no page names it<br>• Five pages print a 'Foam' and they are five different foams, so a lookup returning one would be choosing between published parameter sets for you<br>• `catalogue=`: the rows to search instead of `PUBLISHED_POROUS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_POROUS \| mine`; a row of another class is refused by its key (`TypeError`) | `materials.porous_materials_named('Foam')  # five rows, five tables`<br><br>• `PUBLISHED_POROUS` |
| `ResistiveSheet` | `dataclass` | **One thin resistive facing, with the flow resistance of one square metre of it.**<br>• `specific_flow_resistance_pa_s_m` is `R_s` = Δp/v, per unit **area** [Pa·s/m], the N·s/m³ of the page and the mks rayl of an older literature; it is not the per-metre `flow_resistivity_pa_s_m2` of `PorousMaterial`, and the two differ by a thickness<br>• `normalized_flow_resistance` is the same resistance over ρ₀c₀, as two of the tables print it; `.reference_impedance_pa_s_m()` divides one column by the other and gives back the impedance that table used<br>• `wires_per_cm`, `wire_diameter_um`, `thickness_mm`, `mass_per_area_kg_m2`, `nonlinearity_factor`: what each table describes its facing by<br>• `surface_density_g_m2` is the same mass per unit area under the heading and in the unit the cloth table prints it in, g/m²; `weave_construction` is that table's weave, held as the text it is, `'60 × 58'`, two counts over a length the page never states<br>• `table` says which of the three printed tables the row came from; the maker is in `attributed_to['row']` on the cloth table, which credits one per row, and in `attributed_to['table']` on the sintered one, which credits one for all eleven | `mesh = materials.resistive_sheet_named('80')[0]`<br>`mesh.specific_flow_resistance_pa_s_m  # 24.6 Pa·s/m`<br><br>• `PUBLISHED_FLOW_RESISTANCE`, `resistive_sheet_named` |
| `PUBLISHED_FLOW_RESISTANCE` | `mapping` | **Twenty-nine thin resistive facings from three published tables, keyed `'<table>/<row>'`.**<br>• Vér & Beranek 2e **TABLE 8.5** (PDF page 266), five woven wire mesh cloths; **TABLE 8.6** (PDF page 267), thirteen glass fibre cloths; **TABLE 8.7** (PDF page 267), eleven sintered porous metal sheets, one data file and one citation each<br>• A resistance per unit area [Pa·s/m], for the facing over an absorber, and not the flow resistivity [Pa·s/m²] of `PUBLISHED_POROUS`<br>• TABLE 8.7 prints its two resistance columns once per block and blank beneath; the value is carried down and each row that received it names the row it came from<br>• The surface density of TABLE 8.6 is held as the page prints it, in g/m², and its `note` carries the oz/yd² beside it: the two printings disagree by about eleven per cent on all thirteen rows, one wrong factor, and the page does not say which column has it<br>• Not a specification: the pages give no measurement method, no laboratory and no standard, and the values are the linear part of the resistance, for low particle velocity only | `materials.PUBLISHED_FLOW_RESISTANCE['ver-beranek-2006-table-8-7/sintered_fm_122']`<br><br>• `ResistiveSheet`, `resistive_sheet_named` |
| `resistive_sheet_named` | `function` | **Every facing a page labels with this name, matched whole.**<br>• Matches `ResistiveSheet.name` without regard to case, and whole rather than in part, because these pages name their rows by mesh count and product code: a partial match would answer `'12'` with a mesh, two cloths and four sintered sheets<br>• A tuple and not one row, because a name can be printed by more than one table<br>• `catalogue=`: the rows to search instead of `PUBLISHED_FLOW_RESISTANCE`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_FLOW_RESISTANCE \| mine`; a row of another class is refused by its key (`TypeError`) | `materials.resistive_sheet_named('FM 122')`<br><br>• `PUBLISHED_FLOW_RESISTANCE` |
| `AbsorptionSpectrum` | `dataclass` | **One finish of a published absorption table, with its Sabine coefficient in each octave band.**<br>• `absorption_coefficient_63` … `absorption_coefficient_8000`: one field per band, the band's centre frequency in hertz as the suffix, `None` where the page prints no value<br>• `.bands()` the bands the row prints; `.spectrum()` → `{band_hz: coefficient}`; `.absorption_coefficient(band_hz)` narrows or refuses, naming the row and the band<br>• `mounting`: the ASTM C423 mounting the page prints beside the row, `'A'`, `'E400'`, `'F'` or empty; the same board on two mounts is two rows, because the airspace behind it changes what it does<br>• thickness and density stay in `name` and `variant` as the page prints them; the hedges of every catalogue row apply band by band<br>• a measurement of a specimen in a room, not a property of a material: representative, never a specification | `row = materials.PUBLISHED_ABSORPTION['bies-2017-table-6-2/carpet_heavy_on_concrete']`<br>`row.spectrum()  # {125: 0.02, 250: 0.06, ...}`<br><br>• `PUBLISHED_ABSORPTION`, `AbsorptionAreaSpectrum` |
| `PracticalAbsorptionSpectrum` | `dataclass` | **One specimen of a data sheet, with its practical absorption coefficient αp per octave (ISO 11654 Clause 4.1) and the rating it prints.**<br>• `practical_absorption_coefficient_125` … `practical_absorption_coefficient_4000`, six octaves; 125 Hz is held and never rated (Clause 1)<br>• `weighted_absorption_coefficient` (αw), `shape_indicator` (the letters, `'MH'`), `absorption_class`, `noise_reduction_coefficient`, as printed<br>• `mounting` (`'A'`, `'E-200'`, ISO 354 Annex B), `thickness_mm`, `construction_depth_mm` (ISO 11654 Clause 5.4: room surface to the exposed face, the absorber included)<br>• `.rating()` → `AbsorptionRatingResult` from 250-4000 Hz, a missing band refused<br>• read from a file, a value above 1.00 or off the steps of 0.05 and a printed rating the bands do not give are noted beside the catalogue; the cells stay as printed<br>• αp, not the Sabine α of a book (`AbsorptionSpectrum`) nor the one-third-octave αs of a report | `row.rating().rating_label  # '0.60(M)'`<br>`row.practical_absorption_coefficient(500)`<br><br>• `ThirdOctaveAbsorptionSpectrum`, `weighted_absorption` |
| `ThirdOctaveAbsorptionSpectrum` | `dataclass` | **One specimen of a test report, with its sound absorption coefficient αs per one-third octave (ISO 354), 50 Hz to 10 kHz.**<br>• `absorption_coefficient_50` … `absorption_coefficient_10000`, 24 bands, above 1 as measured (diffraction effects, ISO 354 3.9 NOTE 2), never capped<br>• the rating and specimen fields of `PracticalAbsorptionSpectrum`<br>• `.practical()` → `PracticalAbsorptionSpectrum`, each octave whose three thirds are printed worked out by Clause 4.1 and marked in `derived` (naming the bases when they mix); an octave missing a third stays empty and says why, and so does one with a negative third, never read as 0<br>• `.rating()` → `AbsorptionRatingResult` from the 15 thirds 200-5000 Hz, which it keeps; a negative third among them is refused, naming the band<br>• `.absorption_coefficient(band_hz)`, `.values_at(frequencies_hz)` | `row.practical().spectrum()`<br>`row.rating().rating_label`<br><br>• `PracticalAbsorptionSpectrum`, `weighted_absorption_from_third_octave` |
| `AbsorptionAreaSpectrum` | `dataclass` | **A row a table prints as an equivalent absorption area per person, per seat or per cubic metre of air rather than as a coefficient.**<br>• `absorption_area_63_m2` … `absorption_area_8000_m2`, in square metres per unit of `per`, which is `'person'` for an audience row<br>• kept apart from the coefficients because it is added to a room's absorption, not multiplied by a surface, and the unit is in the field name so it cannot be mistaken for one<br>• a row in sabins has been converted, and `converted[field]` keeps the page's figure and its unit, `('4.0', 'sabins')` | `materials.PUBLISHED_ABSORPTION_AREAS['bies-2017-table-6-2/audience_per_person_seated'].spectrum()[500]  # 0.44 m² per person`<br><br>• `PUBLISHED_ABSORPTION_AREAS` |
| `ABSORPTION_BANDS_HZ` | `constant` | **The octave bands an absorption table can print: 63 Hz to 8 kHz.**<br>• `(63, 125, 250, 500, 1000, 2000, 4000, 8000)`; a table prints six or seven of them and the others stay empty on every row | `materials.ABSORPTION_BANDS_HZ` |
| `PUBLISHED_ABSORPTION` | `mapping` | **Four hundred and fifty-five absorption coefficient rows from five published tables, keyed `'<table>/<row>'`.**<br>• Bies 5e **Table 6.2**, fifty-nine rows in eight groups, two of which are areas per person and live in `PUBLISHED_ABSORPTION_AREAS`<br>• Long 2e **Table 7.1**, a hundred and two rows in eleven groups, with an ASTM C423 mounting on sixty-two of them and fifteen finishes printed on two mounts<br>• Cox & D'Antonio 3e **Appendix A**, a hundred and sixty-one rows in twenty-two groups, compiled from twenty-nine sources and credited row by row in `attributed_to`; every cell of it is a number<br>• Arau-Puchades (1999) **Tabla 6.1**, ninety-six of its ninety-nine numbered rows, names in Spanish as printed, two of them intervals in `ranges`; the three that are the air attenuation coefficient m in reciprocal metres are not served<br>• Everest 4e **Appendix**, forty-one rows in three groups, each with the source the page prints beside it in a column of its own; two rows the page marks with a dash carry no credit<br>• the book says the values are selected from the literature, that reverberation times from them are approximate only, and that manufacturer's data or a measurement is better<br>• the transcription was made twice, from the rendered pages, by readers who never saw each other's work, and compared cell by cell before either was kept<br>• of the ten finishes both books describe, five agree in every band and five differ in exactly one cell, which is why `absorption_named` returns every match rather than choosing one | `materials.PUBLISHED_ABSORPTION['bies-2017-table-6-2/glass_heavy_plate'].absorption_coefficient(125)  # 0.18`<br><br>• `AbsorptionSpectrum`, `absorption_named` |
| `PUBLISHED_ABSORPTION_AREAS` | `mapping` | **The four rows the same pages print as an absorption area rather than a coefficient, keyed `'<table>/<row>'`.**<br>• Bies 5e Table 6.2 prints an audience seated and standing as $S\bar{\alpha}$ in square metres, the quantity of its Equation (6.78)<br>• Long 2e Table 7.1 prints a musician with his instrument, in bare figures its note reads as sabins, and the air itself at 50 % relative humidity, in sabins per 1000 cubic feet; both are converted to square metres and marked converted | `materials.PUBLISHED_ABSORPTION_AREAS['bies-2017-table-6-2/audience_per_person_standing'].per  # 'person'`<br><br>• `AbsorptionAreaSpectrum` |
| `absorption_named` | `function` | **Every coefficient row whose printed name contains a fragment.**<br>• `name`: a fragment, matched without case, because a finish is described rather than named and no two books describe one the same way<br>• `'carpet'` answers with every carpet of every table, and the caller reads the names to pick the one that is theirs<br>• `catalogue=`: the rows to search instead of `PUBLISHED_ABSORPTION`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_ABSORPTION \| mine`; a row of another class is refused by its key (`TypeError`) | `[r.name for r in materials.absorption_named('carpet')]  # twenty-one carpets; 'moqueta' finds the Spanish ones`<br><br>• `PUBLISHED_ABSORPTION` |
| `Carpet` | `dataclass` | **One carpet as a page printed it: its pile, what it is laid on, and its NRC.**<br>• `noise_reduction_coefficient`, the mean absorption at 250 to 2000 Hz; no band can be recovered from it<br>• `pile_weight_kg_m2` [kg/m²], `pile_height_mm` [mm], `pile_surface` and `fibre` in the page's words, `mounting` (bare concrete or a hair pad)<br>• four pile weights whose two printed halves disagree are `misprinted` and serve nothing | `row = materials.carpets_named('nylon')[0]`<br>`row.noise_reduction_coefficient  # 0.5`<br><br>• `PUBLISHED_CARPETS`, `carpets_named` |
| `PUBLISHED_CARPETS` | `mapping` | **Nineteen carpets, keyed `'<table>/<row>'`.**<br>• Harris 3e **Table 30.2** (PDF page 704), eleven on bare concrete, NRC 0,25 to 0,55, and **Table 30.3** (PDF pages 704 to 705), eight on a hair pad, NRC 0,40 to 0,70<br>• credited to the American Carpet and Rug Institute, the chapter's Reference 5 | `len(materials.PUBLISHED_CARPETS)  # 19`<br><br>• `Carpet`, `carpets_named` |
| `carpets_named` | `function` | **Every carpet whose construction, surface or fibre contains the text.**<br>• `name`: matched without case against the Spanish words the page prints, so `'nylon'`, `'lana'` or `'de nudo'`<br>• empty when nothing matches<br>• `catalogue=`: the rows to search instead of `PUBLISHED_CARPETS`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_CARPETS \| mine`; a row of another class is refused by its key (`TypeError`) | `len(materials.carpets_named('nylon'))  # 3`<br><br>• `PUBLISHED_CARPETS` |
| `porosity_from_bulk_density` | `function` | **Open porosity of a fibrous material from its two densities (Hopkins 2007 Eq. 1.160, printed p. 80).**<br>• `bulk_density_kg_m3` ρ [kg/m³], `fibre_density_kg_m3` ρ_fibre [kg/m³]<br>• φ = 1 − ρ/ρ_fibre; holds for solid fibres with a binder of negligible mass<br>• Refuses a bulk density at or above the fibre density | `materials.porosity_from_bulk_density(60.0, fibre_density_kg_m3=2 600.0)  # 0.977`<br><br>• φ, between 0 and 1 |
| `airflow_resistivity_from_bulk_density` / `FibreResistivityFit` | `function` / `class` | **Airflow resistivity of a mineral wool from its bulk density (Hopkins 2007 Eq. 1.165, printed p. 81).**<br>• `bulk_density_kg_m3` ρ [kg/m³]<br>• `fit`: a published `FibreResistivityFit` carrying `k1`, `k2`, `fibre_diameter_um` and the bulk-density range it was fitted over<br>• r = k₁ρ^(1+k₂)/d² with d in micrometres<br>• Warns outside the fitted range: it is a regression through measured points, not a law | `materials.airflow_resistivity_from_bulk_density(60.0, fit=materials.ROCK_WOOL_LONGITUDINAL_FIT)  # 23 226`<br><br>• σ [Pa·s/m²] |
| `ROCK_WOOL_LATERAL_FIT` / `ROCK_WOOL_LONGITUDINAL_FIT` / `ROCK_WOOL_FIBRE_DENSITY_KG_M3` | `constant` | **The rock wool of Hopkins Fig. 1.49, as its page prints it (printed p. 81).**<br>• lateral k₁ = 353, k₂ = 0,63 over 31 to 155 kg/m³<br>• longitudinal k₁ = 780, k₂ = 0,59 over 38 to 162 kg/m³<br>• fibre diameter 4,75 µm, fibre density 2 600 kg/m³<br>• Mineral wool is anisotropic: the longitudinal resistivity is the higher of the two | `materials.ROCK_WOOL_LATERAL_FIT.k1  # 353.0`<br><br>• `FibreResistivityFit`, `float` |
| `viscous_characteristic_length` | `function` | **Λ from the three parameters that are measured routinely (Allard & Atalla 2e Eq. 5.25, printed p. 80).**<br>• `flow_resistivity_pa_s_m2` σ, `porosity` φ, `tortuosity` α∞<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`), for its viscosity<br>• `shape_factor` c (Default: 1.0)<br>• Λ = (8ηα∞/(σφ))^½/c; within a factor of two on 18 of the 23 specimens the book prints with all four columns, and nowhere near a carpet | `materials.viscous_characteristic_length(40 000.0, porosity=0.94, tortuosity=1.06)  # 6.4e-05`<br><br>• Λ [m] |
| `fibre_characteristic_lengths` / `FibreCharacteristicLengths` | `function` / `class` | **Both lengths of a fibrous layer from its geometry (Allard & Atalla 2e Eqs. 5.29 and 5.30, printed p. 81).**<br>• `fibre_radius_m` R [m], `bulk_density_kg_m3` ρ, `fibre_density_kg_m3` ρ_fibre [kg/m³]<br>• Λ = Rρ_fibre/(2ρ), Λ′ = 2Λ, the fibre length per unit volume eliminated through its own definition<br>• A different model from `viscous_characteristic_length`, and the lower estimate of the two throughout | `materials.fibre_characteristic_lengths(2.375e-6, bulk_density_kg_m3=60.0, fibre_density_kg_m3=2 600.0)`<br><br>• `FibreCharacteristicLengths`: `viscous_length_m`, `thermal_length_m` |
| `DELANY_BAZLEY_COEFFICIENTS` | `mapping` | **Bies 5e Table D.1 coefficient presets (C1…C8).**<br>'delany_bazley' (rockwool/fibreglass), 'garai_pompoli' (polyester), 'dunn_davern' / 'wu' (foams) | `DELANY_BAZLEY_COEFFICIENTS['garai_pompoli']` |
| `DELANY_BAZLEY_VALIDITY` | `tuple` | **Stated fit range in X = ρf/σ.**<br>(0.01, 1.0) | `DELANY_BAZLEY_VALIDITY  # (0.01, 1.0)` |
| `MIKI_VALIDITY` | `tuple` | **Miki fit range in f/σ.**<br>(0.01, 1.0) | `MIKI_VALIDITY  # (0.01, 1.0)` |
| `PUBLISHED_AIR` | `Fluid` | **The air the Johnson-Champoux-Allard model was published with.**<br>343.0 m/s, 1.205 kg/m³, 1.84·10⁻⁵ Pa·s, Pr = 0.71, γ = 1.4, 101325 Pa<br>• a `phonometry.fluids.Fluid`: pass a computed one to depart from the published constants<br>• the `fluid` argument of the slow-sound and metadiffuser models defaults to it | `PUBLISHED_AIR.density  # 1.205` |
| `layered_absorber` | `function` | **Transfer-matrix multilayer prediction at one angle_rad (Cox & D'Antonio Eq. 2.29; Bies Eq. D.95; Mechel D.4).**<br>• `frequency` f [Hz]<br>• `layers`: stack from the incidence side (`AirLayer`, `PorousLayer`, `PoroelasticLayer`, `PerforatedPlateLayer`, `MicroperforatedPlateLayer`, `MembraneLayer`)<br>• `angle_rad` θ [rad] (Default: 0)<br>• `termination`: 'rigid'/'free'/complex Z [Pa·s/m] (Default: 'rigid')<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`) | `res = materials.layered_absorber(f, [materials.PorousLayer(0.05, med)])`<br><br>• `LayeredAbsorberResult` |
| `plot_absorber_stack` | `function` | **To-scale cross-section of a layer stack.**<br>• `layers`: front layer first (or a single layer)<br>• `language` | `plot_absorber_stack(layers)`<br><br>• Dimensioned drawing, rigid backing at right; also `LayeredAbsorberResult.plot_geometry()` and `layer.plot()` |
| `LayeredAbsorberResult` | `dataclass` | **Oblique-incidence prediction.**<br>• `surface_impedance` Zs, `normalized_impedance`<br>• `reflection` R(θ), `absorption` α(θ)<br>• `transfer_matrix`: (2, 2, n) chain matrix (det = 1)<br>• `.plot()`: α(f) with \|R\| overlaid | `res.absorption, res.surface_impedance` |
| `diffuse_field_absorption` | `function` | **Random-incidence (Paris) absorption (Mechel D.5 Eq. 9).**<br>• `frequency`, `layers`, `termination` as `layered_absorber`<br>• `angle_limit_rad` [rad] (Default: π/2; 75°–87° truncations in use)<br>• `quadrature_points` (Default: 64, Gauss–Legendre) | `dif = materials.diffuse_field_absorption(f, layers)`<br><br>• `DiffuseFieldAbsorptionResult` |
| `DiffuseFieldAbsorptionResult` | `dataclass` | **Paris-integral result.**<br>• `absorption`: α_dif(f)<br>• `angle_limit_rad` [rad]<br>• `.plot()` | `dif.absorption` |
| `statistical_absorption` | `function` | **Closed-form Paris integral, locally reacting plane (Mechel D.5 Eq. 10).**<br>• `normalized_impedance` z = Zs/(ρc) (Re z > 0)<br>• `angle_limit_rad` [rad] (Default: π/2)<br>• Maximum over passive z is the published 0.951 | `statistical_absorption(1.567 + 0j)  # 0.951` |
| `AirLayer` | `dataclass` | **Plain air gap.**<br>• `thickness` d [m] (0 allowed → transparent) | `AirLayer(0.05)` |
| `PorousLayer` | `dataclass` | **Porous layer.**<br>• `thickness` d [m]<br>• `medium`: `PorousMediumResult` on the solver frequency grid | `PorousLayer(0.05, med)` |
| `PoroelasticLayer` | `dataclass` | **Porous layer with an elastic frame (full Biot theory).**<br>• `thickness` d [m]<br>• `medium`: the **rigid-frame** `PorousMediumResult` on the solver grid<br>• `porosity` φ, `tortuosity` α∞, `frame_density` ρ₁ [kg/m³]<br>• `shear_modulus` N [Pa] (complex), `poisson_ratio` ν (Default: 0)<br>• Switches `layered_absorber` to the global-matrix assembly; `transfer_matrix` is then NaN | `PoroelasticLayer(0.05, med, 0.94, 1.06, 130.0, 2.2e6*(1+0.1j))` |
| `PerforatedPlateLayer` | `dataclass` | **Rigid perforated plate.**<br>• `thickness` t, `hole_radius` a [m]<br>• `open_area` ε (0–1)<br>• `end_correction` δ per end (Default: None → Fok/Nesterov of ε) | `PerforatedPlateLayer(0.006, 0.0025, 0.05)` |
| `MicroperforatedPlateLayer` | `dataclass` | **Maa microperforated plate.**<br>• `thickness` t, `hole_radius` a [m] (submillimetre)<br>• `open_area` ε<br>• `end_correction` δ (Default: 0.85) | `MicroperforatedPlateLayer(0.0002, 0.0001, 0.005)` |
| `MembraneLayer` | `dataclass` | **Limp impervious membrane.**<br>• `surface_density` m [kg/m²]<br>• `resistance` r [Pa·s/m] (Default: 0) | `MembraneLayer(5.0)` |
| `perforated_plate_impedance` | `function` | **Perforated-plate transfer impedance (Cox & D'Antonio Eqs. 7.6/7.12).**<br>• `frequency`, `thickness`, `hole_radius`, `open_area`, `end_correction`<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`) | `z = materials.perforated_plate_impedance(f, thickness=0.006, hole_radius=0.0025, open_area=0.05)`<br><br>• complex [Pa·s/m] |
| `microperforated_plate_impedance` | `function` | **Maa's exact MPP impedance (Cox & D'Antonio Eqs. 7.33–7.35).**<br>• `frequency`, `thickness`, `hole_radius`, `open_area`<br>• `end_correction` δ (Default: 0.85)<br>• Bessel circular-capillary kernel | `z = materials.microperforated_plate_impedance(f, thickness=0.0002, hole_radius=0.0001, open_area=0.005)`<br><br>• complex [Pa·s/m] |
| `membrane_impedance` | `function` | **Membrane transfer impedance r + jωm (Cox Eq. 7.14; Bies Eq. D.96).**<br>• `frequency`, `surface_density` m [kg/m²]<br>• `resistance` r (Default: 0) | `z = materials.membrane_impedance(f, surface_density=5.0)`<br><br>• complex [Pa·s/m] |
| `perforation_end_correction` | `function` | **End-correction factor δ(ε) = 0.85(1 − 1.47√ε + 0.47ε^1.5) (Cox Table 7.1).**<br>• `open_area` ε | `perforation_end_correction(0.05)  # 0.575`<br><br>• per orifice end |
| `helmholtz_resonance_frequency` | `function` | **Shallow-cavity perforate resonance (Cox Eq. 7.4).**<br>• `cavity_depth` d, `plate_thickness` t, `hole_radius` a [m]<br>• `open_area` ε, `end_correction` δ<br>• `speed_of_sound` | `helmholtz_resonance_frequency(cavity_depth=0.025, plate_thickness=0.006, hole_radius=0.0025, open_area=0.05)`<br><br>• f0 = (c/2π)√(ε/(t′d)) [Hz] |
| `membrane_resonance_frequency` | `function` | **Membrane mass-spring resonance (Cox Eqs. 7.9/7.10).**<br>• `surface_density` m [kg/m²], `cavity_depth` d [m]<br>• `isothermal` (Default: False)<br>• `fluid`: `Fluid`; the isothermal spring divides by the fluid's own ratio of specific heats (Default: `PUBLISHED_AIR`) | `membrane_resonance_frequency(surface_density=5.0, cavity_depth=0.05)  # ≈120`<br><br>• ≈ 60/√(md) (50/√(md) isothermal) [Hz] |
| `PorousAbsorberWarning` | `warning class` | **Porous-model advisory.**<br>Emitted when the Delany–Bazley / Miki regressions are evaluated outside their published fit range; values are still returned | `warnings.simplefilter('error', PorousAbsorberWarning)` |
| `slit_helmholtz_absorber` | `function` | **Slit panel loaded with Helmholtz resonators (Jiménez et al. Appl. Sci. 2017).**<br>• `frequency` f [Hz], `resonators`: one/many `HelmholtzResonator`<br>• `slit_height` h, `lattice_step` a, `period_m` d [m]<br>• `angle_rad` θ [rad] (Default: 0)<br>• `end_correction`, `slit_radiation` (Default: True)<br>• visco-thermal slit + square-duct losses | `res = materials.slit_helmholtz_absorber(f, hr, slit_height=1e-3, lattice_step=3e-2, period_m=5e-2)`<br><br>• `SlitResonatorAbsorberResult` |
| `plot_slit_absorber_geometry` | `function` | **To-scale cross-section of one period_m of the slit panel.**<br>• `resonators` (one per lattice step)<br>• `slit_height` h, `lattice_step` a, `period_m` d [m]<br>• `language` | `plot_slit_absorber_geometry([hr], slit_height=1e-3, lattice_step=0.03, period_m=0.05)`<br><br>• Also `SlitResonatorAbsorberResult.plot_geometry()` |
| `plot_helmholtz_resonator_geometry` | `function` | **To-scale cross-section of a square-section Helmholtz resonator.**<br>• `resonator`: `HelmholtzResonator`<br>• `language` | `plot_helmholtz_resonator_geometry(hr)`<br><br>• Also `HelmholtzResonator.plot()` |
| `SlitResonatorAbsorberResult` | `dataclass` | **Slow-sound panel prediction.**<br>• `surface_impedance` Z = T11/T21, `normalized_impedance`<br>• `reflection` R(θ), `absorption` α = 1 − \|R\|²<br>• `effective_wavenumber`, `effective_impedance`<br>• `transfer_matrix`: (2, 2, n)<br>• `.plot()`: α(f) with \|R\| overlaid | `res.absorption, res.plot()` |
| `critical_coupling_design` | `function` | **Solve geometry for perfect absorption at a frequency (critical coupling, Eq. 9).**<br>• `target_frequency` f0 [Hz], base `resonator`<br>• `lattice_step` a, `period_m` d [m], `angle_rad` θ<br>• tunes cavity length + slit height so the reflection zero is real<br>• warns if α does not reach ≈1 | `d = materials.critical_coupling_design(300.0, hr, lattice_step=3e-2, period_m=5e-2)`<br><br>• `CriticalCouplingResult` |
| `CriticalCouplingResult` | `dataclass` | **Perfect-absorption design outcome.**<br>• `resonator`, `slit_height`: solved geometry<br>• `absorption` (≈1), `normalized_impedance` (≈1)<br>• `converged` (the solve met its tolerance inside its bounds, and `absorption` exceeds 0.999; refused beside a lower absorption), `target_frequency`, `angle_rad` | `d.resonator, d.slit_height, d.absorption` |
| `HelmholtzResonator` | `dataclass` | **Square-cross-section Helmholtz resonator.**<br>• `neck_length` l_n, `neck_side` w_n [m]<br>• `cavity_length` l_c, `cavity_side` w_c [m] | `HelmholtzResonator(1e-3, 3e-3, 30e-3, 27e-3)` |
| `helmholtz_resonator_impedance` | `function` | **Resonator acoustic impedance Z_HR with visco-thermal losses (Jiménez et al. APL 2016 Eq. A23).**<br>• `frequency`, `resonator`<br>• `slit_height`, `lattice_step` for neck→slit end correction<br>• `end_correction` (Default: True) | `z = materials.helmholtz_resonator_impedance(f, hr)`<br><br>• complex [Pa·s/m³] |
| `slit_effective_properties` | `function` | **Narrow-slit visco-thermal ρ_s, κ_s (Stinson 1991; Eq. 6).**<br>• `frequency`, `slit_height` h [m]<br>• `fluid`: `Fluid` (Default: `PUBLISHED_AIR`)<br>• limit jωρ_s → 12η/h² as ω → 0 | `rho_s, kap_s = materials.slit_effective_properties(f, slit_height=1.2e-3)` |
| `rectangular_duct_properties` | `function` | **Square-duct visco-thermal ρ, κ (Stinson 1991; Eqs. 7–8).**<br>• `frequency`, `side` [m]<br>• `sum_terms` (Default: 40)<br>• limit jωρ → 28.454η/side² as ω → 0 | `rho, kap = materials.rectangular_duct_properties(f, side=3e-3)` |
| `SlowSoundAbsorberWarning` | `warning class` | **Slow-sound absorber advisory.**<br>Emitted when `critical_coupling_design` cannot reach perfect absorption within tolerance | `warnings.simplefilter('error', SlowSoundAbsorberWarning)` |
| `AirflowResistanceWarning` | `warning class` | **ISO 9053 advisory.**<br>Emitted for a velocity above the 15 mm/s static limit, a piston frequency outside 1–4 Hz, or a failed Formula 3/4 validity criterion | `warnings.simplefilter('error', AirflowResistanceWarning)` |
| `practical_absorption_coefficient` | `function` | **Practical coefficients αp (ISO 11654 §4.1).**<br>• `third_octave_alpha_s`: 15 one-third-octave αs, 200–5000 Hz (sequence or mapping keyed by band) | `ap = materials.practical_absorption_coefficient(alpha_s)`<br><br>• 5 octave values (250–4000 Hz), 0.05 steps, capped at 1.00 |
| `weighted_absorption` | `function` | **Weighted absorption αw + class (ISO 11654 §4.2).**<br>• `alpha_p`: the 5 octave practical coefficients | `w = materials.weighted_absorption([0.25, 0.7, 0.95, 1.0, 0.85])`<br><br>• `AbsorptionRatingResult` (αw = 0.55, class D, 'MH') |
| `weighted_absorption_from_third_octave` | `function` | **αw from 15 one-third-octave αs, retaining them for the fiche (ISO 11654 §4.1–4.2).**<br>• `third_octave_alpha_s`: 15 αs, 200–5000 Hz (sequence or mapping keyed by band) | `w = materials.weighted_absorption_from_third_octave(alpha_s)`<br><br>• `AbsorptionRatingResult` carrying `third_octave_alpha_s` / `third_octave_bands` |
| `absorption_class` | `function` | **Sound absorption class (Table B.1).**<br>• `alpha_w`: multiple of 0.05 in [0, 1] | `absorption_class(0.7)  # 'C'`<br><br>• 'A'–'E' or 'Not classified' |
| `AbsorptionRatingResult` | `dataclass` | **αw rating result.**<br>• `alpha_w`: shifted curve read at 500 Hz<br>• `shape_indicator`: 'L'/'M'/'H' concatenation or ''<br>• `absorption_class`: 'A'–'E'/'Not classified'<br>• `shift`, `unfavourable_sum` (≤ 0.10)<br>• `band_centers` [Hz], `measured`, `shifted_reference`<br>• `.plot()` | `w.alpha_w, w.absorption_class` |
| `OCTAVE_BANDS` | `tuple` | **ISO 11654 octave rating bands [Hz].**<br>(250, 500, 1000, 2000, 4000) | `OCTAVE_BANDS  # (250, ..., 4000)` |
| `THIRD_OCTAVE_BANDS` | `tuple` | **ISO 11654 one-third-octave input bands [Hz].**<br>200 Hz to 5000 Hz (15 bands) | `THIRD_OCTAVE_BANDS[0]  # 200` |
| `REFERENCE_CURVE` | `mapping` | **ISO 11654 Figure 1 reference curve (read-only).**<br>Keyed by octave band [Hz] → coefficient | `REFERENCE_CURVE[250]  # 0.8` |
| `check_ceiling_specimen` / `CeilingSpecimenCheck` / `TARGET_SPECIMEN_AREA_M2` / `TEST_OBJECT_SIZE_M` / `TYPE_E_DEPTH_MM` / `MAX_DEFLECTION_MM` | `function` / `dataclass` / `constant` | **The test arrangement EN 16487 fixes, clause 4.**<br>• 10,80 m² of specimen, laid out in 0,6 m by 0,6 m objects, so a laboratory's own room does not change the answer<br>• mounting type E hangs it 200 mm below the ceiling; the panels may sag no more than 5 mm<br>• `support_width_mm`, `support_height_mm`, `support_centre_distance_m`: the support units of 4.1.1.2.3.6; `relative_humidity_percent`: one value per measurement, each held to the 50 % of 4.2.2<br>• check: `deflection_ok`, `substructure_ok`, `fixture_ok`, `supports_ok`, `humidity_ok` (`None` without a humidity) and `satisfied` over them; `area_error_m2` and `ce_marking_depth` reported and not judged, since the area is a target and the 200 mm is the CE marking depth<br>• `CeilingSpecimenCheck` takes `area_m2`, `mounting`, `depth_mm`, `deflection_mm`, `substructure_width_mm`, `substructure_height_mm`, `fixture_density_kg_m2`, `support_width_mm`, `support_height_mm`, `support_centre_distance_m`, `lowest_relative_humidity_percent`; `area_error_m2`, `deflection_ok`, `substructure_ok`, `fixture_ok`, `supports_ok`, `humidity_ok`, ... are read-only, read from them | `materials.check_ceiling_specimen(area_m2=10.8, mounting="E", depth_mm=200.0)` |
| `mounting_type` / `MOUNTING_TYPES` / `SUBSTRUCTURE_LIMITS_MM` / `SUBSTRUCTURE_SPACING_M` / `SUPPORT_SECTION_MM` / `MIN_SUPPORT_SPACING_M` / `MIN_FIXTURE_DENSITY_KG_M2` / `MIN_ROOM_EDGE_ANGLE_DEG` | `function` / `mapping` / `constant` | **How the specimen hangs, and on what.**<br>• the four mountings of EN ISO 354 Annex B this code uses: A against a hard surface, B glued with a 3 mm space, E suspended, J a discrete absorber<br>• the exposed substructure at most 30 mm wide and 50 mm deep, on a 0,6 m grid, hung from 50 mm by 50 mm supports at least 1,2 m apart, the section and centre distance of which `check_ceiling_specimen` judges<br>• a fixture counts as part of the specimen from 20 kg/m², and the specimen edges sit at least 10° off the room's own; the grid and the angle are targets and not judged | `materials.mounting_type("E")` |
| `air_absorption_correction` / `AIR_CORRECTION_LIMIT` / `MIN_RELATIVE_HUMIDITY_PERCENT` | `function` / `constant` | **What the air in the room absorbs, 4.2.1.**<br>• 4V(m₂ − m₁)/S, as an absorption coefficient, from the attenuation with and without the specimen<br>• over 0,05 the result is not reported: the air is doing too much of the absorbing to attribute it to the ceiling<br>• the room is held at 50 % relative humidity or more, which is what keeps that term small at 4 kHz; `check_ceiling_specimen(relative_humidity_percent=...)` judges it for each measurement | `materials.air_absorption_correction(volume_m3=200.0, specimen_area_m2=10.8, attenuation_with=m2, attenuation_empty=m1)` |
| `reproducibility_uncertainty` / `CEILING_UNCERTAINTY` / `WEIGHTED_UNCERTAINTY` / `EN16487_COVERAGE_FACTOR` | `function` / `mapping` / `constant` | **What two laboratories will differ by, Table 1.**<br>• the reproducibility standard deviation band by band: 0,23 at 125 Hz and 250 Hz, then 0,11, 0,10, 0,10 and 0,13 up to 4 kHz<br>• 0,08 for the weighted single number α_w<br>• expanded with k = 2,8, which is the factor the standard prints rather than the usual 2 | `materials.reproducibility_uncertainty()  # one per octave band` |
| `SuspendedCeilingWarning` | `warning class` | **The test arrangement is outside a condition EN 16487 states.**<br>• a deflection over 5 mm, a substructure over 30 mm by 50 mm, a fixture under 20 kg/m², a type E plenum that is not 200 mm, an air correction over 0,05<br>• the specimen area is not one of them: 4.1.1.1.1 asks for "as close to 10,80 m² as possible", which is a target rather than a tolerance, so the check reports the difference and leaves the judgement to the laboratory | `warnings.simplefilter('error', SuspendedCeilingWarning)`<br>Emitted by `materials.absorbers.suspended_ceilings` |
| `speed_of_sound_iso17497` | `function` | **Speed of sound (ISO 17497-1 Eq. 2).**<br>• `temperature_c` t [°C] | `speed_of_sound_iso17497(temperature_c=20.0)  # 343.2`<br><br>• 343.2 √((273.15 + t)/293.15) [m/s] |
| `air_attenuation_coefficient` | `function` | **Energy attenuation m from ISO 9613-1 α (ISO 17497-1 Eq. 3).**<br>• `pressure_attenuation_db_per_m`: α [dB/m] | `air_attenuation_coefficient(0.005)  # 0.00115`<br><br>• m ≈ α/4.343 [1/m] |
| `random_incidence_absorption` | `function` | **Random-incidence absorption αs (ISO 17497-1 Eq. 1).**<br>• `volume` V [m³], `area` S [m²]<br>• `c1`/`T1`: static base plate, no sample<br>• `c2`/`T2`: with the test sample<br>• `m1`/`m2`: air attenuation [1/m] (Default: 0) | `a_s = materials.random_incidence_absorption(200.0, 10.8, c1=343.0, t1=2.5, c2=343.2, t2=1.8)  # 0.463` |
| `specular_absorption_coefficient` | `function` | **Specular absorption αspec (Eq. 4).**<br>• `volume`, `area`<br>• `c3`/`T3`: rotating base plate, no sample<br>• `c4`/`T4`: sample on the rotating turntable<br>• `m3`/`m4` (Default: 0) | `a_spec = materials.specular_absorption_coefficient(200.0, 10.8, c3=c3, t3=t3, c4=c4, t4=t4)`<br><br>• Includes the energy lost to scattering |
| `scattering_coefficient` | `function` | **Random-incidence scattering coefficient s (Eq. 5).**<br>• `alpha_spec`, `alpha_s`<br>• `truncate_negative`: clip s < 0 to 0 (Default: True); s > 1 is kept | `scattering_coefficient(0.45, 0.30)  # 0.214`<br><br>• s = (αspec − αs)/(1 − αs) |
| `scattering_coefficient_spectrum` | `function` | **Scattering spectrum s(f) (Eq. 5).**<br>• `frequencies`: one-third-octave centres [Hz]<br>• `specular_absorption`, `random_absorption`: per band<br>• `truncate_negative` (Default: True) | `res = materials.scattering_coefficient_spectrum(f, a_spec, a_s)`<br><br>• `ScatteringResult` |
| `ScatteringResult` | `dataclass` | **Scattering spectrum result.**<br>• `frequencies` [Hz]<br>• `scattering`: s per band<br>• `random_incidence`: αs, `specular`: αspec<br>• `.plot()` | `res.scattering` |
| `base_plate_scattering` | `function` | **Scattering of the base plate alone (Eq. 6).**<br>• `volume`, `area`<br>• `c1`/`T1`: static, `c3`/`T3`: rotating<br>• `m1`/`m3` (Default: 0) | `s_base = materials.base_plate_scattering(200.0, 10.8, c1=c1, t1=t1, c3=c3, t3=t3)`<br><br>• Quality metric vs Table 1 |
| `check_base_plate_scattering` | `function` | **Verify the base plate against Table 1 (Clause 6.2).**<br>• `scattering`: mapping by band [Hz] or 18 values ordered as `BASE_PLATE_BANDS` | `check_base_plate_scattering(s_base)  # ()`<br><br>• Offending band centres; `ScatteringDiffusionWarning` if any |
| `BASE_PLATE_BANDS` | `tuple` | **ISO 17497-1 base-plate check bands [Hz].**<br>100 Hz to 5000 Hz (18 one-third octaves) | `BASE_PLATE_BANDS[0]  # 100` |
| `BASE_PLATE_MAX_SCATTERING` | `mapping` | **Table 1 base-plate scattering limits (read-only).**<br>Keyed by band [Hz] → maximum s | `BASE_PLATE_MAX_SCATTERING[500]  # 0.05` |
| `reverberation_time_uncertainty` | `function` | **Standard uncertainty of a mean T (ISO 17497-1 Eq. A.1).**<br>• `times`: N ≥ 2 spatially-averaged measurements [s] | `reverberation_time_uncertainty([2.31, 2.28, 2.35])  # 0.0203`<br><br>• Standard error of the mean [s] |
| `absorption_coefficient_uncertainty` | `function` | **Uncertainty of a Sabine coefficient (Eqs. A.3/A.4).**<br>• `volume`, `area`<br>• `speed_of_sound` [m/s]<br>• `T_a`/`u_a`, `T_b`/`u_b`: the two situations [s] | `u_alpha = materials.absorption_coefficient_uncertainty(200.0, 10.8, speed_of_sound=343.2, t_a=2.5, u_a=0.02, t_b=1.8, u_b=0.02)` |
| `scattering_coefficient_uncertainty` | `function` | **Uncertainty of the scattering coefficient (Eq. A.5).**<br>• `alpha_spec`, `alpha_s`<br>• `u_alpha_spec`, `u_alpha_s` | `u = materials.scattering_coefficient_uncertainty(0.45, 0.30, 0.02, 0.02)`<br><br>• `ScatteringUncertainty` (U = 2u, 95 %) |
| `ScatteringUncertainty` | `dataclass` | **Scattering uncertainty result.**<br>• `u_scattering`: combined standard u_s<br>• `expanded`: U = 2u_s | `u.u_scattering, u.expanded` |
| `PUBLISHED_SCATTERING` | `mapping` | **Forty-six measured surfaces from a published table, keyed `'<table>/<row>'`.**<br>• Cox & D'Antonio 3e **Appendix D**, nine groups from sinusoidal corrugation and battens through blocks, pyramids and grooves to hemispheres and vegetation<br>• measured at full or model scale according to **ISO 17497-1**, and credited row by row to the seven papers the appendix lists; the book says nothing else about them<br>• the only one of the book's four appendices whose numbers were measured rather than computed<br>• how wide the method is: the same battens read 0.28 and 0.44 at 630 Hz in two papers, and one cell of the table is 1.17<br>• the transcription was made twice, from the rendered pages, by readers who never saw each other's work | `row = materials.PUBLISHED_SCATTERING['cox-2017-appendix-d/pyramids_h_30_5_cm_l_b_h']`<br>`row.spectrum()[2000]  # 0.58`<br><br>• `ScatteringCoefficientSpectrum`, `scattering_named` |
| `ScatteringCoefficientSpectrum` | `dataclass` | **One surface of a published table, with its scattering coefficient in each one-third octave band.**<br>• `scattering_coefficient_100` … `scattering_coefficient_5000`, dimensionless, `None` where the page prints a dash or nothing<br>• `.bands()`, `.spectrum()` → `{band_hz: s}`, `.scattering_coefficient(band_hz)` narrows or refuses, naming the row and the band<br>• the geometry is in `name` as the page prints it and the family is in `group`, because `'h = w = 10 cm, L = 2h'` means nothing on its own | `row.scattering_coefficient(5000)  # ValueError: the page prints a dash there`<br><br>• `PUBLISHED_SCATTERING` |
| `SCATTERING_BANDS_HZ` | `constant` | **The one-third octave bands a published scattering table can print: 100 Hz to 5 kHz.**<br>• `(100, 125, 160, ..., 4000, 5000)`, eighteen of them; twenty of Cox's rows stop at 4 kHz and ten print a dash there | `materials.SCATTERING_BANDS_HZ[-1]  # 5000` |
| `scattering_named` | `function` | **Every surface whose description or group heading contains a fragment.**<br>• `name`: matched without case against both, because the useful word is usually in the heading<br>• `'pyramid'` answers with four rows, two of which the page describes identically<br>• `catalogue=`: the rows to search instead of `PUBLISHED_SCATTERING`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_SCATTERING \| mine`; a row of another class is refused by its key (`TypeError`) | `len(materials.scattering_named('vegetation'))  # 6`<br><br>• `PUBLISHED_SCATTERING` |
| `PUBLISHED_DIFFUSION` | `mapping` | **Twenty-nine surfaces at three angles each, from a published table, keyed `'<table>/<row>'`.**<br>• Cox & D'Antonio 3e **Appendix B**, seven sections from periodicity and depth through triangles and semiellipses to Schroeder diffusers<br>• normalized diffusion coefficients of **ISO 17497-2**, computed with a 2D boundary element model and not measured, which is the difference between this table and `PUBLISHED_SCATTERING`<br>• the page prints three lines per surface, headed 0, 57 and Random, so a surface is three rows and `variant` says which<br>• what an array does that one device does not: one semicylinder is 0.77 at 1 kHz at random incidence and twelve of it are 0.22<br>• the transcription was made twice, from the rendered pages, by readers who never saw each other's work | `row = materials.PUBLISHED_DIFFUSION['cox-2017-appendix-b/2_30_cm_deep_semicylinders_random']`<br>`row.spectrum()[5000]  # 0.65`<br><br>• `NormalizedDiffusionSpectrum`, `diffusion_named` |
| `NormalizedDiffusionSpectrum` | `dataclass` | **One surface at one angle of incidence, with its coefficient in each one-third octave band.**<br>• `diffusion_coefficient_100` … `diffusion_coefficient_5000`, dimensionless; this appendix fills every cell<br>• `angle_of_incidence_deg`: 0 or 57, and `None` on a random incidence row, which is a mean over ten angles and is none of them<br>• `.bands()`, `.spectrum()` → `{band_hz: d}`, `.diffusion_coefficient(band_hz)` narrows or refuses<br>• `group` carries the numbered section heading, which is where the geometry a row is short for is printed | `row.why_missing('angle_of_incidence_deg')  # the page prints "Random" there`<br><br>• `PUBLISHED_DIFFUSION` |
| `DIFFUSION_BANDS_HZ` | `constant` | **The one-third octave bands a published diffusion coefficient table can print: 100 Hz to 5 kHz.**<br>• `(100, 125, 160, ..., 4000, 5000)`, the same eighteen the scattering tables use, and Cox's appendix fills all of them on all eighty-seven rows | `materials.DIFFUSION_BANDS_HZ[0]  # 100` |
| `diffusion_named` | `function` | **Every surface whose description or section heading contains a fragment.**<br>• `name`: matched without case against both, because the geometry is in the heading<br>• a surface answers with its three angles, so `'12 periods, 7.32 m wide'` gives three rows<br>• `catalogue=`: the rows to search instead of `PUBLISHED_DIFFUSION`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_DIFFUSION \| mine`; a row of another class is refused by its key (`TypeError`) | `[r.variant for r in materials.diffusion_named('12 periods, 7.32 m wide')]`<br>`# ['normal', '57 degrees', 'random']`<br><br>• `PUBLISHED_DIFFUSION` |
| `PUBLISHED_PREDICTED_SCATTERING` | `mapping` | **A hundred and nineteen rows of computed scattering, keyed `'<table>/<row>'`.**<br>• Cox & D'Antonio 3e **Tables C.1, C.2 and C.3**: two three-dimensional predictions at normal and random incidence over 250 Hz to 4 kHz, and one two-dimensional one over 100 Hz to 5 kHz at 0, 56.9 and random incidence<br>• kept apart from `PUBLISHED_SCATTERING`, which is measured, so that a solver's number and a reverberation room's cannot be mixed unnoticed; no key is shared and the classes differ<br>• the two three-dimensional tables are credited to Lee and Sakuma (2015), which the appendix prints as a source line under each<br>• the book's own warnings about the coefficient, which reads absorption as scattering and redirection as dispersion, are in the `about` of each table | `row = materials.PUBLISHED_PREDICTED_SCATTERING['cox-2017-table-c1/sinusoidal_cross_section_h_4_cm_l_20_cm']`<br>`row.model  # 'three-dimensional boundary element prediction'`<br><br>• `PredictedScatteringSpectrum`, `predicted_scattering_named` |
| `PredictedScatteringSpectrum` | `dataclass` | **One predicted surface at one angle, with its coefficient in each one-third octave band.**<br>• `scattering_coefficient_100` … `scattering_coefficient_5000`, dimensionless; the three-dimensional tables leave the four lowest empty and say why<br>• `angle_of_incidence_deg`: 0 or 56.9, and `None` where the page prints a word, "Random" or "All/any", which `why_missing` tells apart<br>• `model`: the solver behind the row, which is what separates these from the measured ones<br>• `.bands()`, `.spectrum()`, `.scattering_coefficient(band_hz)` | `row.scattering_coefficient(100)  # ValueError: the page has nothing there`<br><br>• `PUBLISHED_PREDICTED_SCATTERING` |
| `predicted_scattering_named` | `function` | **Every predicted surface whose description or heading contains a fragment.**<br>• `name`: matched without case against both, because the topology is in the heading<br>• `'batten'` answers with sixteen rows across two tables<br>• `catalogue=`: the rows to search instead of `PUBLISHED_PREDICTED_SCATTERING`, such as a catalogue of your own from `io.read_catalogue` or `PUBLISHED_PREDICTED_SCATTERING \| mine`; a row of another class is refused by its key (`TypeError`) | `len(materials.predicted_scattering_named('sinusoidal cross-section'))  # 12`<br><br>• `PUBLISHED_PREDICTED_SCATTERING` |
| `directional_diffusion_coefficient` | `function` | **Directional diffusion coefficient d_θ (ISO 17497-2 Formulas 5/6).**<br>• `levels`: n ≥ 2 reflected SPL [dB] (−inf = zero energy)<br>• `area_weights`: Ni (Formula 8) (Default: None → equal-area Formula 5) | `directional_diffusion_coefficient([-10., -12., -15., -11., -13.])  # 0.854` |
| `directional_diffusion` | `function` | **Polar response + its coefficient.**<br>• `angles_deg` [°], `levels` [dB]<br>• `weights`: Ni (Default: None) | `res = materials.directional_diffusion(angles_deg, levels)`<br><br>• `DiffusionResult` |
| `plot_goniometer_geometry` | `function` | **Free-field diffusion goniometer in plan, to scale.**<br>• `source_distance` (Default: 10 m), `receiver_radius` (Default: 5 m)<br>• `angular_step` (Default: 5°, 37 microphones)<br>• `sample_width` [m] (Default: 0.6)<br>• `language` | `plot_goniometer_geometry()` |
| `DiffusionResult` | `dataclass` | **Polar diffusion result.**<br>• `angles_deg` [°], `levels` [dB]<br>• `coefficient`: d_θ (autocorrelation)<br>• `.plot()`, `.report()` | `res.coefficient` |
| `diffusion_spectrum` | `function` | **Diffusion spectrum d(f) (ISO 17497-2 Clause 8.5).**<br>• `frequencies`: one-third-octave centres [Hz]<br>• `diffusion`: d per band (directional, or random-incidence via Clause 8.4)<br>• `normalized`: d_n per band (Default: None) | `res = materials.diffusion_spectrum(f, d, normalized=d_n)`<br><br>• `DiffusionSpectrum` |
| `DiffusionSpectrum` | `dataclass` | **Diffusion spectrum result.**<br>• `frequencies` [Hz]<br>• `diffusion`: d per band<br>• `normalized`: d_n per band or None<br>• `.plot()`, `.report()` | `res.diffusion` |
| `normalized_diffusion_coefficient` | `function` | **Normalised coefficient d_θ,n (Formula 7).**<br>• `d_theta`: test surface<br>• `d_theta_reference`: flat reference | `normalized_diffusion_coefficient(0.6, 0.2)  # 0.5`<br><br>• (d − d_r)/(1 − d_r) |
| `area_factors` | `function` | **Per-receiver area weights Ni (Clause 8.3 Formula 8).**<br>• `elevations`: θ [°], 0–90<br>• `delta_theta` [°]<br>• `delta_phi` [°] (Default: None → `delta_theta`) | `n_i = materials.area_factors([0, 15, 30, 45, 60, 75, 90], delta_theta=15.0)`<br><br>• Dimensionless, min 1 |
| `random_incidence_diffusion` | `function` | **Random-incidence diffusion coefficient d (Clause 8.4).**<br>• `directional_coefficients`: d_θ per source<br>• `weights`: source weights (Default: None → equal; 2-D uses `TWO_DIMENSIONAL_SOURCE_WEIGHTS`) | `d = materials.random_incidence_diffusion(d_thetas, weights=TWO_DIMENSIONAL_SOURCE_WEIGHTS)` |
| `TWO_DIMENSIONAL_SOURCE_WEIGHTS` | `tuple` | **ISO 17497-2 single-plane source weights.**<br>(1, 3, 3, 3, 3) for 0°, ±30°, ±60° | `TWO_DIMENSIONAL_SOURCE_WEIGHTS` |
| `ScatteringDiffusionWarning` | `warning class` | **ISO 17497 advisory.**<br>Emitted for out-of-range scattering/diffusion measurement conditions (e.g. a base plate over the Table 1 limits) | `warnings.simplefilter('error', ScatteringDiffusionWarning)` |
| `quadratic_residue_sequence` | `function` | **Quadratic residue sequence s_n (Cox & D'Antonio Eq. 10.2).**<br>• `prime`: odd prime generator N | `quadratic_residue_sequence(7)  # [0 1 4 2 2 4 1]`<br><br>• s_n = n² mod N |
| `qrd_well_depths` | `function` | **QRD well depths d_n (Cox & D'Antonio Eq. 10.3).**<br>• `prime`: generator N<br>• `design_frequency` f0 [Hz]<br>• `speed_of_sound` c [m/s] (Default: 343) | `qrd_well_depths(7, 500.0)  # d_max 0.196 m`<br><br>• d_n = s_n λ0/(2N) |
| `plot_qrd_geometry` | `function` | **To-scale QRD well profile.**<br>• `depths` d_n [m], `well_width` w [m]<br>• `repetitions` (Default: 1), `fin_width` [m] (Default: w/12)<br>• `language` | `plot_qrd_geometry(materials.qrd_well_depths(7, 500.0), 0.12, repetitions=2)`<br><br>• Also `DiffuserPolarResponse.plot_geometry()` |
| `MetadiffuserWell` | `dataclass` | **One slit of a metadiffuser panel (Jiménez et al. Sci. Rep. 2017).**<br>• `slit_height` h [m]<br>• `resonators`: tuple of `HelmholtzResonator`, face to backing<br>• `None` in a well sequence = flat rigid strip (R = 1) | `MetadiffuserWell(14.7e-3, (hr, hr))`<br><br>• lattice a = L/M |
| `metadiffuser_reflection` | `function` | **Per-well reflection spectra R_n(f) of a metadiffuser.**<br>• `frequency` f [Hz], `wells`: `MetadiffuserWell`/`None` sequence<br>• `depth` L, `period_m` d [m]; `angle_deg` θ [rad] (Default: 0)<br>• `resonator_geometry` `"slit"`/`"square"` (Default: slit)<br>• 2-D visco-thermal TMM per slit | `panel = materials.metadiffuser_reflection(f, wells, depth=0.02, period_m=0.07)`<br><br>• `MetadiffuserResult` |
| `MetadiffuserResult` | `dataclass` | **Metadiffuser spectra, one reflection row per well.**<br>• `reflection` (N, F), `well_absorption` (N, F)<br>• `absorption`: face average 1 − mean\|R_n\|²<br>• retains `wells`/`depth`/`period_m` | `panel.plot()`; `panel.plot_geometry()`<br><br>• `.plot()` α per well; `.plot_geometry()` panel section |
| `metadiffuser_polar_response` | `function` | **Far-field polar response of a metadiffuser at one frequency.**<br>• `frequency` f [Hz], `wells`, `depth` L, `period_m` d [m]<br>• `angles_deg` [°], `source_angle_deg` ψ [°], `repetitions` (Default: 1)<br>• Fraunhofer of R_n(f), no obliquity factor (Sci. Rep. Eq. (1)) | `pol = materials.metadiffuser_polar_response(2000.0, wells, depth=0.02, period_m=0.07, repetitions=6)`<br><br>• `DiffuserPolarResponse` |
| `metadiffuser_diffusion_spectrum` | `function` | **Normalized diffusion spectrum d_n(f) of a metadiffuser.**<br>• `frequencies` [Hz], `wells`, `depth` L, `period_m` d [m]<br>• normalised against the same-footprint flat panel<br>• ISO 17497-2 directional coefficient per band | `metadiffuser_diffusion_spectrum(f, wells, depth=0.02, period_m=0.07)`<br><br>• `DiffusionSpectrum` |
| `plot_metadiffuser_panel_geometry` | `function` | **To-scale metadiffuser panel cross-section.**<br>• `wells`, `depth` L, `period_m` d [m]<br>• numbered slits, resonators shelved into the septum<br>• `language` | `plot_metadiffuser_panel_geometry(wells, depth=0.02, period_m=0.07)`<br><br>• Also `MetadiffuserResult.plot_geometry()` |
| `predict_diffuser_polar_response` | `function` | **Predicted far-field polar response (Cox & D'Antonio Eq. 5.8).**<br>• `well_width` w [m], `frequency` f [Hz]<br>• `depths` d_n [m] or `reflection` R_n (exactly one)<br>• `angles_deg` [°] (Default: semicircle), `source_angle_deg` ψ [°]<br>• `repetitions` Np (Default: 1) | `s = materials.predict_diffuser_polar_response(0.10, 2000.0, depths=d, repetitions=5)`<br><br>• `DiffuserPolarResponse` |
| `predicted_diffusion_spectrum` | `function` | **Predicted diffusion spectrum d(f) of a design.**<br>• `well_width` [m], `frequencies` [Hz]<br>• `depths` d_n [m]<br>• `repetitions` (Default: 1)<br>• `normalize`: also d_n vs flat reference (Default: True) | `res = materials.predicted_diffusion_spectrum(0.10, f, depths=d, repetitions=5)`<br><br>• `DiffusionSpectrum` |
| `DiffuserPolarResponse` | `dataclass` | **Predicted diffuser polar response.**<br>• `frequency` [Hz]<br>• `angles_deg` [°], `levels` [dB] (peak at 0)<br>• `coefficient`: d_θ<br>• `.plot()` | `s.coefficient` |
| `DEFAULT_POLAR_ANGLES` | `tuple` | **ISO 17497-2 single-plane receiver angles.**<br>−90° to 90° in 5° steps (37 receivers) | `DEFAULT_POLAR_ANGLES[0]  # -90` |
| `adrienne_window` | `function` | **Adrienne temporal window (ISO 13472-1 Clause 6.4).**<br>• `fs` [Hz]<br>• `flat_duration` [s] (Default: 0.005)<br>• `leading_duration` [s] (Default: 0.0005), `trailing_duration` [s] (Default: 0.005)<br>• `leading_edge`/`trailing_edge`: 'blackman-harris' or 'cosine-squared' | `w = materials.adrienne_window(48000)`<br><br>• Rising edge + flat top + falling edge, peak 1.0 |
| `geometric_spreading_factor` | `function` | **Geometrical-spreading factor Kr (Clause 4.1).**<br>• `source_height` ds [m] (Default: 1.25)<br>• `mic_height` dm [m] (Default: 0.25) | `geometric_spreading_factor()  # 0.6667`<br><br>• Kr = (ds − dm)/(ds + dm) |
| `geometric_spreading_factor_angle` | `function` | **Oblique factor Kr,θ (Annex F).**<br>• `incidence_angle_rad` θ [rad]<br>• `source_height`, `mic_height` | `geometric_spreading_factor_angle(np.pi/6)  # 0.764` |
| `reflected_path_delay` | `function` | **Reflected-path delay Δτ = 2dm/c (Annex C).**<br>• `mic_height` dm [m] (Default: 0.25)<br>• `speed_of_sound` c [m/s] (Default: 340.0) | `reflected_path_delay()  # 0.001471`<br><br>• [s] |
| `insitu_reflection_factor` | `function` | **Complex reflection factor r(f) (ISO 13472-1 Clause 4.1).**<br>• `incident_ir` / `reflected_ir`: windowed impulse responses<br>• `source_height`, `mic_height` [m]<br>• `incidence_angle_rad` [rad] (Default: 0)<br>• `fs` + `delay`: undo the reflected-path offset (Default: None)<br>• `n`: FFT length | `r = materials.insitu_reflection_factor(hi, hr, fs=48000, delay=dtau)`<br><br>• (1/Kr)·Hr(f)/Hi(f) at the rfft bins |
| `insitu_absorption_from_reflection` | `function` | **α from the reflection factor (Clause 4.1).**<br>• `reflection`: complex r | `alpha = materials.insitu_absorption_from_reflection(r)`<br><br>• α = 1 − \|r\|² |
| `power_reflection_coefficient` | `function` | **Power reflection factor QW(f), direct energy route.**<br>• `incident_ir`, `reflected_ir`<br>• `source_height`, `mic_height`, `incidence_angle_rad`, `n` | `qw = materials.power_reflection_coefficient(hi, hr)`<br><br>• (1/Kr²)\|Hr/Hi\|², offset-independent |
| `insitu_absorption_coefficient` | `function` | **Narrow-band absorption α(f) (Clause 4.1).**<br>• Same parameters as `power_reflection_coefficient` | `alpha = materials.insitu_absorption_coefficient(hi, hr)`<br><br>• α = 1 − QW(f) |
| `one_third_octave_absorption` | `function` | **Aggregate narrow-band α into one-third octaves.**<br>• `frequency` [Hz], `absorption`<br>• `f_min` (Default: 250), `f_max` (Default: 4000; 1600 for Part 2) [Hz]<br>• `clip_negative` (Default: True) | `fc, ab = materials.one_third_octave_absorption(f, alpha)`<br><br>• Band centres + linear-averaged α (nan if empty) |
| `insitu_absorption_spectrum` | `function` | **End-to-end in-situ spectrum (ISO 13472-1).**<br>• `incident_ir`, `reflected_ir`, `fs` [Hz]<br>• geometry + `incidence_angle_rad`<br>• `f_min`/`f_max` [Hz], `clip_negative` | `res = materials.insitu_absorption_spectrum(hi, hr, 48000)`<br><br>• `InsituAbsorptionResult` |
| `plot_insitu_geometry` | `function` | **In-situ absorption set-up to scale.**<br>• `source_height` (Default: 1.25 m), `mic_height` (Default: 0.25 m)<br>• `sampled_radius` (Default: 1.34 m)<br>• `language` | `plot_insitu_geometry()`<br><br>• Also `InsituAbsorptionResult.plot_geometry()` |
| `InsituAbsorptionResult` | `dataclass` | **In-situ absorption spectrum.**<br>• `frequencies`: one-third-octave centres [Hz]<br>• `absorption`: α per band (nan when empty)<br>• `.plot()` | `res.absorption` |
| `absorption_reference_corrected` | `function` | **Reference-corrected road absorption (Annex B).**<br>• `road_reflection` / `reference_reflection`: measured Qp (complex, same geometry) | `alpha = materials.absorption_reference_corrected(q_road, q_ref)`<br><br>• 1 − \|Qp,road/Qp,ref\|²; removes chain error and Kr |
| `max_sampled_area_radius` | `function` | **Maximum sampled-area radius (Annex A).**<br>• `window_width` Tw [s]<br>• `source_height`, `mic_height`, `speed_of_sound` | `max_sampled_area_radius(0.005)  # 1.34`<br><br>• [m], the Annex A worked example |
| `msa_major_axis` | `function` | **Major axis of the oblique sampled ellipsoid (Annex F).**<br>• `window_width` Tw [s]<br>• `projected_distance` dp [m]<br>• `source_height`, `mic_height`, `speed_of_sound` | `msa_major_axis(0.005, 0.0)  # 3.2`<br><br>• a = cTw + √((ds + dm)² + dp²) [m] |
| `spot_tube_upper_frequency` | `function` | **Spot-tube upper frequency (ISO 13472-2 §5.4.1).**<br>• `diameter_m` d [m]<br>• `speed_of_sound` (Default: 340.0) | `spot_tube_upper_frequency(0.1)  # 1972`<br><br>• f_u = 0.58c0/d [Hz] |
| `spot_microphone_spacing_bounds` | `function` | **Spacing bounds (s_min, s_max) (§5.4.2).**<br>• `speed_of_sound` (Default: 340.0)<br>• `f_min` (Default: 220), `f_max` (Default: 1800) [Hz] | `spot_microphone_spacing_bounds()  # (0.0773, 0.085)`<br><br>• [m], brackets the nominal 81 mm |
| `check_spot_frequency_range` | `function` | **Advise outside 250–1600 Hz (ISO 13472-2 Scope).**<br>• `frequency` [Hz] | `check_spot_frequency_range(f)`<br><br>• `RoadAbsorptionWarning` out of range |
| `spot_internal_loss_correction` | `function` | **Internal-loss (system) correction (Annex A).**<br>• `measured_absorption`, `system_absorption`: same bands<br>• `clip_negative` (Default: True) | `spot_internal_loss_correction([0.12, 0.10], [0.02, 0.03])  # [0.1, 0.07]`<br><br>• Subtractive Part-2 correction |
| `DEFAULT_SOURCE_HEIGHT` | `float` | **ISO 13472-1 mandatory source height ds [m].**<br>1.25 | `DEFAULT_SOURCE_HEIGHT  # 1.25` |
| `DEFAULT_MIC_HEIGHT` | `float` | **ISO 13472-1 mandatory microphone height dm [m].**<br>0.25 | `DEFAULT_MIC_HEIGHT  # 0.25` |
| `DEFAULT_SPEED_OF_SOUND` | `float` | **Default speed of sound for the road methods [m/s].**<br>340.0 | `DEFAULT_SPEED_OF_SOUND  # 340.0` |
| `PART1_FREQUENCY_RANGE` | `tuple` | **ISO 13472-1 valid band range [Hz].**<br>(250.0, 4000.0) | `PART1_FREQUENCY_RANGE` |
| `SPOT_FREQUENCY_RANGE` | `tuple` | **ISO 13472-2 valid band range [Hz].**<br>(250.0, 1600.0) | `SPOT_FREQUENCY_RANGE` |
| `SPOT_NARROW_BAND_RANGE` | `tuple` | **ISO 13472-2 narrow-band range [Hz].**<br>(220.0, 1800.0) | `SPOT_NARROW_BAND_RANGE` |
| `RoadAbsorptionWarning` | `warning class` | **ISO 13472 advisory.**<br>Emitted for frequencies outside the valid in-situ road-absorption ranges; results there are advisory | `warnings.simplefilter('error', RoadAbsorptionWarning)` |
| `frequency_weighting` | `function` | **Vibration frequency weighting H(f) (ISO 8041-1:2017 Formula 5).**<br>• `name`: one of `WEIGHTING_NAMES`<br>• `frequencies` [Hz] (> 0) | `wr = vibration.frequency_weighting('Wk', [1.0, 8.0, 63.0])`<br><br>• `WeightingResponse`; \|H\| = [0.482, 1.036, 0.186] |
| `weighting_factors` | `function` | **Weighting factors \|H(f)\| (the Wi of ISO 2631-1 Eq. 9).**<br>• `name`, `frequencies` [Hz] | `weighting_factors('Wh', [16.0])`<br><br>• Magnitude per frequency |
| `apply_weighting` | `function` | **Apply a weighting to a time signal (frequency domain, exact response).**<br>• `signal`: acceleration (1D) [m/s²]<br>• `fs` [Hz]<br>• `name`: one of `WEIGHTING_NAMES` | `aw_t = vibration.apply_weighting(a, fs, name="Wk")`<br><br>• Weighted signal, same length (circular FFT filtering) |
| `WeightingResponse` | `dataclass` | **Weighting response.**<br>• `name`<br>• `frequencies` [Hz]<br>• `response`: complex H<br>• `magnitude`, `magnitude_db` [dB]<br>• `.plot()` | `wr.magnitude, wr.magnitude_db` |
| `WEIGHTING_NAMES` | `tuple` | **ISO 8041-1 weighting names.**<br>('Wb', 'Wc', 'Wd', 'We', 'Wf', 'Wh', 'Wj', 'Wk', 'Wm') | `'Wk' in WEIGHTING_NAMES  # True` |
| `weighted_acceleration` | `function` | **Weighted r.m.s. from a band spectrum (ISO 2631-1 Eq. 9 / ISO 5349-1 Eq. A.1).**<br>• `band_accelerations`: ai per band [m/s²]<br>• `frequencies`: band centres [Hz]<br>• `weighting`: name | `ws = vibration.weighted_acceleration([0.1, 0.3, 0.2], [4.0, 8.0, 16.0], 'Wk')`<br><br>• `WeightedSpectrum`; aw = 0.36 m/s² |
| `WeightedSpectrum` | `dataclass` | **Weighted band spectrum.**<br>• `frequencies` [Hz], `band_accelerations` [m/s²]<br>• `weighting_name`, `weighting_factors`<br>• `weighted`: Wi·ai [m/s²]<br>• `overall`: aw [m/s²]<br>• `.plot()` | `ws.overall` |
| `running_rms` | `function` | **Running r.m.s. of a weighted signal (ISO 2631-1 Eqs. 2/3).**<br>• `signal` [m/s²], `fs` [Hz]<br>• `integration_time` τ [s] (Default: 1.0)<br>• `method`: 'linear' (Eq. 2) or 'exponential' (Eq. 3) (Default: 'linear') | `env = vibration.running_rms(aw_t, fs)`<br><br>• aw(t0) per sample [m/s²] |
| `mtvv` | `function` | **Maximum transient vibration value (Eq. 4).**<br>• `signal` [m/s²], `fs` [Hz]<br>• `integration_time` [s] (Default: 1.0) | `mtvv(aw_t, fs)`<br><br>• max aw(t0) [m/s²] |
| `vibration_dose_value` | `function` | **Vibration dose value VDV (Eq. 5).**<br>• `signal`: weighted acceleration [m/s²]<br>• `fs` [Hz] | `vdv = vibration.vibration_dose_value(aw_t, fs)`<br><br>• (∫aw⁴dt)^(1/4) [m/s^1.75] |
| `motion_sickness_dose_value` | `function` | **Motion sickness dose value MSDV (ISO 2631-1 clause 9).**<br>• `signal`: Wf-weighted acceleration [m/s²]<br>• `fs` [Hz] | `msdv = vibration.motion_sickness_dose_value(aw_t, fs)`<br><br>• (∫aw²dt)^(1/2) [m/s^1.5] |
| `crest_factor` | `function` | **Crest factor of a weighted signal (clause 6.2.1).**<br>• `signal` [m/s²] | `crest_factor(aw_t)`<br><br>• peak/r.m.s.; `HumanVibrationWarning` above 9 |
| `vibration_total_value` | `function` | **Vibration total value av/ahv (ISO 2631-1 Eq. 10).**<br>• `components`: axis-weighted r.m.s. [m/s²]<br>• `k`: per-axis factors (Default: None → 1, the ISO 5349-1 vector sum) | `vibration_total_value([0.3, 0.4, 0.5], k=[1.4, 1.4, 1.0])  # 0.86`<br><br>• √(Σ kj²awj²) [m/s²] |
| `wbv_exposure_basis` | `function` | **Whole-body A(8) basis of Directive 2002/44/EC (Annex Part B).**<br>• `a_wx`, `a_wy`: Wd-weighted axis r.m.s. [m/s²]<br>• `a_wz`: Wk-weighted axis r.m.s. [m/s²] | `wbv_exposure_basis(0.35, 0.28, 0.62)  # 0.62`<br><br>• max(1.4·awx, 1.4·awy, awz) [m/s²], the dominant axis (not the vector total av) |
| `daily_exposure` | `function` | **Daily exposure A(8) for one operation (ISO 5349-1 Eq. 2).**<br>• `total_value`: ahv (hand-arm) or aw,max (whole-body) [m/s²]<br>• `duration_s`: T [s] | `daily_exposure(3.0, 4*3600)  # 2.12`<br><br>• ahv √(T/8h) [m/s²] |
| `partial_exposure` | `function` | **Partial exposure Ai(8) of one operation (Eq. 2).**<br>• `total_value` [m/s²], `duration_s` [s] | `partial_exposure(3.0, 2*3600)  # 1.5` |
| `combine_partial_exposures` | `function` | **Combine partial exposures (Eq. 3).**<br>• `partials`: Ai(8) [m/s²] | `combine_partial_exposures([1.5, 2.1])  # 2.58`<br><br>• √(Σ Ai(8)²) [m/s²] |
| `hav_daily_exposure` | `function` | **A(8) for several operations (ISO 5349-1 Eq. 3).**<br>• `total_values`: ahvi [m/s²]<br>• `durations_s`: Ti [s] | `hav_daily_exposure([3.0, 5.0], [2*3600, 3600])  # 2.32` |
| `energy_equivalent_acceleration` | `function` | **Energy-equivalent magnitude aw,e (ISO 2631-1 Eq. B.3).**<br>• `magnitudes` [m/s²], `durations_s` [s] | `energy_equivalent_acceleration([0.5, 1.0], [3600, 1800])  # 0.707` |
| `hav_vwf_lifetime_years` | `function` | **Years to 10 % vibration-white-finger prevalence (ISO 5349-1 Eq. C.1).**<br>• `a8`: A(8) [m/s²] (> 0) | `hav_vwf_lifetime_years(2.5)  # 12.0`<br><br>• Dy = 31.8 A(8)^−1.06 [years] |
| `exposure_assessment` | `function` | **Assess a daily exposure (Directive 2002/44/EC Article 3).**<br>• `value`: A(8) [m/s²] or VDV [m/s^1.75]<br>• `kind`: 'hav'/'wbv'<br>• `metric`: 'a8' (Default) or 'vdv' (whole-body only) | `ea = vibration.exposure_assessment(3.0, kind='hav')`<br><br>• `ExposureAssessment` (zone 'action') |
| `ExposureAssessment` | `dataclass` | **Directive assessment.**<br>• `value`, `kind`, `metric`<br>• `action_value` (EAV), `limit_value` (ELV)<br>• `exceeds_action`, `exceeds_limit`<br>• `zone`: 'below action'/'action'/'limit' | `ea.zone, ea.exceeds_limit` |
| `daily_vibration_exposure` | `function` | **A(8) from several operations, assessed (ISO 5349 + Directive).**<br>• `total_values` [m/s²], `durations_s` [s]<br>• `kind`: 'hav'/'wbv'<br>• `labels` (Default: None → 'op 1', …) | `res = vibration.daily_vibration_exposure([3.0, 5.0], [2*3600, 3600], kind='hav')`<br><br>• `DailyVibrationExposure` (A(8) = 2.32) |
| `DailyVibrationExposure` | `dataclass` | **Assessed daily exposure.**<br>• `a8` [m/s²]<br>• `labels`, `total_values`, `durations_s`, `partials`<br>• `assessment`: `ExposureAssessment`<br>• `.plot()` | `res.a8, res.assessment.zone` |
| `HumanVibrationWarning` | `warning class` | **Human-vibration advisory.**<br>Emitted for a crest factor above 9 (ISO 2631-1 6.2.2) or other out-of-range measurement conditions | `warnings.simplefilter('error', HumanVibrationWarning)` |
| `verify_weighting` / `WeightingVerification` | `function` / `dataclass` | **Does a vibration meter's frequency weighting meet ISO 8041-1 (Tables 4 and 5)?**<br>• `name`, `frequencies` [Hz], `measured_factors` (linear, not dB)<br>• `expanded_uncertainty_percent`: the testing laboratory's own U, which extends the measured deviation (13.1 and 14.1); Default `None`, the bare deviation<br>• `.passes`, `.deviation_percent`, `.failing_frequencies_hz`, `.worst_deviation_percent`, `.expanded_uncertainty_percent`, `.plot()`<br>• the weighting only: indication, linearity, overload and the environmental tests are hardware measurements this does not stand in for | `vibration.verify_weighting('Wk', [16.0], [0.86]).passes  # True (+11.9 %, inside +12 %)` |
| `verify_phase_response` / `PhaseVerification` | `function` / `dataclass` | **Does its phase response meet the phase column of ISO 8041-1 Table 5?**<br>• `name`, `frequencies_hz` (ascending), `measured_phase_deg` on the continuous branch Annex B prints<br>• `.characteristic_deviation_deg` (Formula (6), one per adjacent pair, attributed to the lower frequency), `.deviation_deg`, `.tolerance_deg`, `.passes`, `.peak_deviation_percent`, `.plot()`<br>• only for a meter reporting a parameter not based on r.m.s. values (Table 5 footnote a) | `vibration.verify_phase_response('Wk', [8.0, 10.0, 12.5], phases).passes` |
| `characteristic_phase_deviation` / `peak_deviation_percent` | `function` | **The two formulae the phase criterion is made of.**<br>• Formula (6): `abs((f_n Δφ_{n+1} − f_{n+1} Δφ_n) / (f_{n+1} − f_n))` [degrees], N − 1 values<br>• Formula (H.4): the peak-value deviation that costs, `0,48 sin Δφ0 × 100 %`, an approximation Annex H limits to Δφ0 below 30° | `vibration.peak_deviation_percent(12.0)  # 9.98 %` |
| `NOMINAL_FREQUENCY_RANGE_HZ` | `constant` | **The nominal frequency range of each weighting (ISO 8041-1 Table 1).**<br>• `Wh` 8 to 1 000, whole-body 0,5 to 80, `Wm` 1 to 80, `Wf` 0,1 to 0,5<br>• the printed round numbers, not the band centres `10**(k/10)` Annex B tabulates at | `vibration.NOMINAL_FREQUENCY_RANGE_HZ['Wm']  # (1.0, 80.0)` |
| `ISO8041_COVERAGE_FACTOR` / `MAX_EXPANDED_UNCERTAINTY_PERCENT` | `constant` | **What a testing laboratory's uncertainty is expanded with, and how far it may reach.**<br>• `k = 2` (13.1 and 14.1; 12.1 prints "no less than 2"), named for its standard because `hearing.COVERAGE_FACTOR` is a different one (1,65, ISO 9612)<br>• the maximum permitted expanded uncertainty per test clause, e.g. 4,5 % for 12.11.2 and 0,01 % for the timing clauses | `vibration.MAX_EXPANDED_UNCERTAINTY_PERCENT['12.13']  # 3.0 %` |
| `PVEM_MAX_EXPANDED_UNCERTAINTY_PERCENT` | `constant` | **The same limits for a personal vibration exposure meter (ISO 8041-2:2021 clauses 12 and 13).**<br>• keyed by the Part 2 clause number: 11 figures over 10 clauses (12.10.2 prints one for the reference range and one for the other ranges), each 12.x figure the one Part 1 prints for the same clause<br>• 13.9 is Part 2's periodic verification (5 %), not Part 1's one-off indication test (2 %), which is why each part has its own table | `vibration.PVEM_MAX_EXPANDED_UNCERTAINTY_PERCENT['12.11.2']  # 4.5 %` |
| `weighting_tolerance_percent` / `phase_tolerance_degrees` | `function` | **The band ISO 8041-1 Table 5 allows, region by region.**<br>• `+12 %` / `−11 %` in the central region, `+26 %` / `−21 %` in the skirts, no lower limit in the tails<br>• the phase band applies only to a meter reporting a parameter not based on r.m.s. values (Table 5 footnote a), which is why it is a separate call | `vibration.weighting_tolerance_percent('Wk', [16.0])  # (12.0, -11.0)` |
| `TRANSITION_FREQUENCIES_HZ` / `CENTRAL_TOLERANCE_PERCENT` / `SKIRT_TOLERANCE_PERCENT` / `TAIL_TOLERANCE_PERCENT` / `UNCONSTRAINED_BELOW` | `constant` | **Tables 4 and 5 of ISO 8041-1, as data.**<br>• the four transition frequencies per weighting, built from the printed `10**(k/10)` exponents<br>• the three bands, each `(upper %, lower %, phase °)`<br>• `−100 %`, which is the absence of a lower limit rather than a wide one | `vibration.TRANSITION_FREQUENCIES_HZ['Wk']`<br><br>• (0.251, 0.631, 63.1, 158.5) Hz |
| `REFERENCE_FREQUENCY_HZ` / `REFERENCE_ACCELERATION_M_S2` / `reference_indication` | `constant` / `function` | **The ISO 8041-1 Table 1 reference conditions.**<br>• the calibration frequency per weighting, from the radians per second the standard prints<br>• the reference r.m.s. acceleration, 1 m/s² whole-body, 10 hand-transmitted, 0,1 low-frequency<br>• `reference_indication(name)` is their product with the weighting factor there, which is what a conforming meter shows | `vibration.reference_indication('Wh')  # 2.02 m/s²` |
| `indication_tolerance_percent` / `INDICATION_TOLERANCE_PERCENT` / `LOW_FREQUENCY_INDICATION_TOLERANCE_PERCENT` / `LOW_FREQUENCY_WEIGHTING` | `function` / `constant` | **How far the indication itself may sit from the truth (ISO 8041-1 Table 2).**<br>• 4 % at the reference frequency, and 5 % for the low-frequency whole-body case, which is `Wf` | `vibration.indication_tolerance_percent('Wf')  # 5.0` |
| `PVEM_INDICATION_TOLERANCES_PERCENT` | `constant` | **Table 2 of a personal vibration exposure meter (ISO 8041-2:2021).**<br>• `'indication'` 4 %, `'low-frequency indication'` 5 %, `'weighting consistency'` 3 %: the first two rows of the Part 1 table<br>• no running r.m.s. row, because Part 2 5.13 declares the running r.m.s. not applicable to a PVEM | `vibration.PVEM_INDICATION_TOLERANCES_PERCENT['weighting consistency']  # 3.0` |
| `band_limiting_response` / `band_limiting_factors` / `apply_band_limiting` | `function` | **The band-limiting stage of a weighting on its own (ISO 8041-1 Formulae (1) and (2)).**<br>• the two-pole Butterworth high-pass and low-pass pair every weighting starts with, without the transition and step stages<br>• `apply_band_limiting(signal, fs=None, *, name)` filters with it, which is what the band-limiting row of the burst tables is measured on | `vibration.band_limiting_factors('Wk', [1.0])`<br><br>• 0.9874 |
| `band_limited_weighting_factor` / `WEIGHTING_CONSISTENCY_TOLERANCE_PERCENT` | `function` / `constant` | **The weighting factor a band-limited channel actually shows (ISO 8041-1 Table 2, row 2).**<br>• the design goal times the band-limiting response, which is what a meter indicates when both stages are in the path<br>• the 3 % row 2 allows between the two | `vibration.band_limited_weighting_factor('Wk', [16.0])` |
| `running_rms_decay_time` | `function` | **How long the running r.m.s. takes to fall to 10 % of its steady value (ISO 8041-1 5.13).**<br>• `integration_time_s`, and `method` selecting linear or exponential averaging<br>• the quantity Table 11 prints, timed from the moment the signal is shut off | `vibration.running_rms_decay_time(1.0, method='linear')` |
| `verify_running_rms_decay` / `RunningRmsDecayVerification` / `RUNNING_RMS_DECAY_RATE_DB_PER_S` / `RUNNING_RMS_DECAY_TIME_S` / `RUNNING_RMS_CONSISTENCY_TOLERANCE_PERCENT` | `function` / `dataclass` / `constant` | **Does the running r.m.s. decay at the printed rate (ISO 8041-1 Tables 10 and 11)?**<br>• `measured_time_s`, with `integration_time_s` and `method` keyword-only<br>• `.passes`, `.printed_time_s`, `.tolerance_s`, `.lower_time_s`, `.upper_time_s`, `.deviation_s`, `.plot()`<br>• the decay in decibels per second and the time to fall, per integration time, for linear and exponential averaging<br>• the 2 % the indication may differ by | `vibration.RUNNING_RMS_DECAY_RATE_DB_PER_S[1]`<br><br>• (1.0, 3.8, 4.9) s, dB, dB |
| `verify_signal_burst_response` / `SignalBurstVerification` | `function` / `dataclass` | **A meter's response to the saw-tooth burst of ISO 8041-1 5.9 (Tables 7 to 9).**<br>• `application`, `weighting`, the measured indications per burst length<br>• `.passes`, `.deviation_percent`, `.failing_cycle_counts`, `.plot()`<br>• graded on a zero-state simulation, which is what the printed tables come from | `vibration.verify_signal_burst_response('whole-body', 'Wk', measured)` |
| `sawtooth_burst` / `signal_burst_indications` / `SawtoothBurstTest` / `SAWTOOTH_BURST_TESTS` | `function` / `dataclass` / `constant` | **The burst signal itself and what a conforming meter reads from it (Table 6).**<br>• `sawtooth_burst(...)` builds the waveform: angular frequency, start time, cycle count, repeat and total duration<br>• the three applications, 500 rad/s hand-arm, 100 whole-body and 2,5 low-frequency | `vibration.SAWTOOTH_BURST_TESTS['whole-body'].cycle_counts`<br><br>• (1, 2, 4, 8, 16) |
| `SIGNAL_BURST_RESPONSE` / `BURST_TOLERANCE_PERCENT` / `BAND_LIMITING` | `constant` | **Tables 7, 8 and 9 as data, and the tolerance each column carries.**<br>• 228 printed cells keyed by `(application, weighting, cycles)`, with `None` for the continuous row<br>• 10 % on the r.m.s. and MTVV columns, 12 % on VDV<br>• `'band-limiting'` names the row measured with the weighting stages out of the path | `vibration.BURST_TOLERANCE_PERCENT['vdv']  # 12.0` |
| `REFERENCE_ACCELERATION` | `float` | **Vibration reference acceleration [m/s²].**<br>1e-6 (ISO 1683 acceleration level reference) | `REFERENCE_ACCELERATION  # 1e-06` |
| `REFERENCE_DURATION_S` | `float` | **Daily-exposure reference duration T0 [s].**<br>28800 (8 h) | `REFERENCE_DURATION_S  # 28800.0` |
| `HAV_EAV_A8` | `float` | **Hand-arm exposure action value [m/s²].**<br>2.5 (Directive 2002/44/EC) | `HAV_EAV_A8  # 2.5` |
| `HAV_ELV_A8` | `float` | **Hand-arm exposure limit value [m/s²].**<br>5.0 | `HAV_ELV_A8  # 5.0` |
| `WBV_EAV_A8` | `float` | **Whole-body A(8) action value [m/s²].**<br>0.5 | `WBV_EAV_A8  # 0.5` |
| `WBV_ELV_A8` | `float` | **Whole-body A(8) limit value [m/s²].**<br>1.15 | `WBV_ELV_A8  # 1.15` |
| `WBV_EAV_VDV` | `float` | **Whole-body VDV action value [m/s^1.75].**<br>9.1 | `WBV_EAV_VDV  # 9.1` |
| `WBV_ELV_VDV` | `float` | **Whole-body VDV limit value [m/s^1.75].**<br>21.0 | `WBV_ELV_VDV  # 21.0` |
| `measure_vibration_immission` / `VibrationMeterReading` | `function` / `dataclass` | **What a DIN 45669-1 vibration meter displays for one record (5.1.6).**<br>• `velocity_mm_s` [mm/s], `fs_hz` [Hz]<br>• keyword-only: `working_range` (`'building'` 1-80 Hz, Default; `'railway'` 4-315 Hz), `takt_duration_s` (Default: 30)<br>• `.peak_velocity_mm_s`, `.kbf`, `.kbf_max`, `.takt_maxima`, `.kbf_takt_rms`, `.measuring_time_s`, `.averaging_time_s`, `.above_detection_limit`, `.plot()`<br>• start the record before the event: a record that opens at full amplitude leaves the filter's switch-on transient in the max-hold | `r = vibration.measure_vibration_immission(v, 2048.0)`<br><br>• `r.kbf_max`, `r.kbf_takt_rms` |
| `kb_signal` / `kbf_signal` | `function` | **The KB signal and the weighted vibration severity (3.10.1, Formula (1)).**<br>• `KB(t)` is the velocity band-limited, frequency-weighted and normalised by 1 mm/s, so it is dimensionless<br>• `KB_F(t)` is its running r.m.s. with τ = 0,125 s ("Fast")<br>• keyword-only: `working_range`, and `time_constant_s` for a comparison the standard does not allow a meter | `vibration.kbf_signal(v, 2048.0).max()  # KB_Fmax` |
| `takt_maxima` / `takt_maximum_rms` | `function` | **The clock maxima and their r.m.s., Formula (2).**<br>• one maximum per whole 30 s clock interval; a part-interval is dropped (5.1.6.4)<br>• a maximum at or below 0,1 enters the sum as zero and its interval still counts in N | `vibration.takt_maximum_rms([0.8, 0.05])  # 0.566` |
| `band_limitation_response` / `kb_weighting_response` | `function` | **Formulae (3) and (4), complex, at the frequencies asked for.**<br>• two-pole Butterworth pairs at `0,8 f_u` and `f_o / 0,8`, and the 5,6 Hz pole that makes the KB weighting<br>• the magnitudes are Formulae (5) and (6) | `abs(vibration.kb_weighting_response([16.0]))  # 0.944` |
| `verify_vibration_meter` / `VibrationMeterVerification` | `function` / `dataclass` | **Does a meter's amplitude response meet DIN 45669-1 Tables 2 and 3?**<br>• `frequencies_hz`, `measured_response` (any consistent unit: only the shape is graded)<br>• keyword-only: `weighting` (`'kb'` Default, or `'unweighted'`), `working_range`, `reference_frequency_hz` (Default: 16)<br>• `.deviation_percent` (Formula (7)), `.lower_percent`, `.upper_percent`, `.within_tolerance`, `.passes`, `.worst_frequency_hz`, `.plot()`<br>• the response only: Clause 6 also asks for linearity, overload and the environmental tests | `vibration.verify_vibration_meter(f, measured).passes` |
| `response_tolerance_percent` / `RESPONSE_TOLERANCE_LOWER_PERCENT` / `RESPONSE_TOLERANCE_UPPER_PERCENT` | `function` / `constant` | **Tables 2 and 3, as bands of the working range.**<br>• 10 % from `1,25 f_u` to `0,8 f_o`, 20 % out to `0,5 f_u` and `2 f_o`<br>• 100 % below that band is the absence of a lower limit, and the upper limit applies only where the response is above 0,01 | `vibration.response_tolerance_percent([100.0])`<br><br>• (20.0, 20.0) % |
| `assessment_weighting_response` / `assessment_weighting_taps` | `function` | **The three Annex E weighting filters (Table E.1).**<br>• the target magnitude is the guideline curve of DIN 4150-3 Table 1 inverted and normalised to its 1-10 Hz value<br>• `assessment_weighting_taps(fs_hz, *, building_class, numtaps=None)` designs the symmetric FIR the annex asks for, which has the linear phase a peak measurement needs | `vibration.assessment_weighting_response([50.0], building_class='residential')`<br><br>• 0.333 |
| `assessment_velocity` / `assess_short_term_vibration` / `AssessmentVelocity` | `function` / `dataclass` | **Short-term vibration on a building judged without a dominant frequency (Annex E).**<br>• `velocity_mm_s` [mm/s], `fs_hz` [Hz], keyword-only `building_class` and `numtaps`<br>• `.assessment_velocity_mm_s` = `\|v_Bn\|max`, `.guide_value_mm_s`, `.ratio`, `.within_guideline`, `.plot()`<br>• the verdict reads like DIN 4150-3: keeping to the value is what the standard promises about, exceeding it moves the question to Clauses 4.2 to 4.4 | `vibration.assess_short_term_vibration(v, 2048.0, building_class='residential').within_guideline` |
| `dominant_frequency` / `DominantFrequency` | `function` / `dataclass` | **The dominant frequency of a short-term event (Annex D).**<br>• `method='zero_crossing'` (Default: the crossings around the largest amplitude are half a period apart) or `'fourier'`<br>• `.frequency_hz`, `.method`, `.candidates` (the two largest spectral values, Fourier only)<br>• the two can disagree, which is the ambiguity Annex E removes | `vibration.dominant_frequency(v, 2048.0).frequency_hz` |
| `WORKING_RANGES_HZ` / `BAND_LIMIT_CORNER_FACTOR` / `KB_CORNER_HZ` / `KB_TIME_CONSTANT_S` | `constant` | **The four numbers the chain is built from (5.2.3, 3.10.1.2).**<br>• 1 Hz to 80 Hz for buildings and 4 Hz to 315 Hz next to a railway<br>• the 0,8 between a band limit and its filter corner, the 5,6 Hz of the weighting and the 0,125 s of the running r.m.s. | `vibration.WORKING_RANGES_HZ['railway']  # (4.0, 315.0)` |
| `TAKT_DURATION_S` / `TAKT_SUPPRESSION_THRESHOLD` / `KB_DETECTION_LIMIT` / `VELOCITY_DETECTION_LIMIT_MM_S` | `constant` | **The clock interval and the limits below which a meter promises nothing.**<br>• 30 s per clock interval (5.1.6.4), and the 0,1 of Formula (2)<br>• 0,05 mm/s on the peak velocity and 0,02 on the weighted vibration severity (5.2.2) | `vibration.TAKT_DURATION_S  # 30.0` |
| `KB_REFERENCE_FREQUENCY_HZ` / `KB_REFERENCE_INDICATIONS` / `KB_INDICATION_TOLERANCE_PERCENT` | `constant` | **The reference conditions of 5.2.10 and what they must show (6.2.3.12).**<br>• a 1 mm/s sine at 16 Hz, and the four values it produces: 1,00 mm/s, 0,667, 0,680 and 0,680<br>• 4 % is how far the display may sit from them | `vibration.KB_REFERENCE_INDICATIONS['kbf_max']  # 0.68` |
| `KB_TEST_INDICATIONS` / `KB_PULSE_RESPONSE_PERCENT` | `constant` | **Table 9 and Table 8, as data.**<br>• the `KB_F`, `KB_Fmax` and `KB_FTm` a 1 mm/s sine shows at 1, 5,6, 31,5, 80 and 315 Hz<br>• Corrigendum 1's redraft of the burst table: eight burst durations of an 80 Hz sine and the `KB_Fmax` each shows as a percentage of the continuous display<br>• the `\|v\|max` row of Table 9 is not here; it contradicts Formula (5), see `docs/ERRATA.md` | `vibration.KB_TEST_INDICATIONS[31.5]`<br><br>• (0.693, 0.7, 0.7) |
| `ASSESSMENT_GUIDE_VALUES_MM_S` / `ASSESSMENT_WEIGHTING_TOLERANCE` | `constant` | **Table E.2 and the band Table E.1 allows a realised filter.**<br>• 20, 5 and 3 mm/s, one per building class, independent of frequency<br>• 5 % either side of the target magnitude | `vibration.ASSESSMENT_GUIDE_VALUES_MM_S['sensitive']  # 3.0` |
| `check_loose_mounting` / `MountingCheck` | `function` / `dataclass` | **May the transducer be set down without fastening? (DIN 45669-2 5.3.2, 5.3.3)**<br>• `peak_acceleration_m_s2` [m/s²], `upper_frequency_hz` [Hz], keyword-only `direction` (`'vertical'` or `'horizontal'`) and `surface` (`'hard'` Default, `'soft'`)<br>• `.acceptable`, `.frequency_limit_hz` (100 vertical, 40 horizontal), `.peak_acceleration_limit_m_s2` (3), `.device` (what it stands on: rounded feet, or the spiked device on a covering) | `vibration.check_loose_mounting(1.2, 63.0, direction='horizontal').acceptable  # False` |
| `instrument_confidence_limit_percent` / `INSTRUMENT_CONFIDENCE_LIMITS_PERCENT` | `function` / `constant` | **Table 3 of DIN 45669-2: how far a conforming meter may still be from the truth.**<br>• `quantity` `'rms'` (15 %, 25 %) or `'peak'` (20 %, 35 %), `accuracy_class` 1 (Default) or 2<br>• the classes are those of the 1995 Part 1; the 2010 edition dropped them, so class 1 is the column for a meter of today | `vibration.instrument_confidence_limit_percent('peak')  # 20.0` |
| `mass_loading_ratio` / `MASS_LOADING_RATIO_LIMIT` | `function` / `constant` | **7.2.4: the mass the transducer adds to the object, at most a hundredth.**<br>• `coupled_mass_kg` [kg], keyword-only `vibrating_mass_kg` [kg]<br>• the ratio to compare with 0.01 | `vibration.mass_loading_ratio(2.5, vibrating_mass_kg=600.0)  # 0.0042` |
| `LOOSE_MOUNTING_LIMITS_HZ` / `LOOSE_MOUNTING_PEAK_ACCELERATION_M_S2` / `WAX_MOUNTING_HORIZONTAL_LIMIT_HZ` / `SPIKED_DEVICE_MASS_KG` | `constant` | **The mounting numbers of DIN 45669-2.**<br>• 100 Hz vertically and 40 Hz horizontally for a loose transducer, at up to 3 m/s² peak<br>• 80 Hz for the horizontal component on a sensitive hard surface with adhesive wax (Table 1)<br>• about 2.5 kg for the spiked device with the transducer (5.3.3.1) | `vibration.LOOSE_MOUNTING_LIMITS_HZ['horizontal']  # 40.0` |
| `GROUND_COUPLING_DEVIATION_DB` / `EMISSION_POINT_TRACK_DISTANCE_M` / `CLEARANCE_TO_DISTURBING_BODY_FACTOR` | `constant` | **The placement numbers of 5.1.4 and 5.3.4.1.**<br>• up to 15 dB from the ground coupling alone<br>• 8 m from the nearest track for a railway emission point, and at least 1.5 times the largest dimension of a disturbing body away from it | `vibration.GROUND_COUPLING_DEVIATION_DB  # 15.0` |
| `assess_people_in_buildings` / `PeopleAssessment` | `function` / `dataclass` | **The verdict of DIN 4150-2 Clause 6.2 on one immission (Figure 2).**<br>• `kb_fmax`, `guide` (a `GuideValues`), keyword-only `kb_ftr` (needed only when the verdict comes down to it), `source` (`'general'` Default, `'road'`, `'railway'`, `'urban_railway'`, `'quarry_blasting'`), `rare_short_events`<br>• `KB_Fmax` at or below `A_u` is met, and so, as a rule, is one above it by up to the 15 % of 5.4 (Example 3), flagged in `.within_uncertainty`; above `A_o` is not, unless the source is a railway or the events are rare; between, `KB_FTr` against `A_r`<br>• `.complies`, `.criterion` (`'A_u'`, `'A_o'` or `'A_r'`), `.within_uncertainty`, `.plot()`<br>• compared at the decimals the guide value is printed with, half up, which is how Example 4 reads 0,154 as 0,15<br>• `PeopleAssessment` takes `kb_fmax`, `kb_ftr`, `guide`, `source`, `rare_short_events`; `complies`, `criterion`, `within_uncertainty` are read-only, read from them | `vibration.assess_people_in_buildings(0.47, g, kb_ftr=0.154).complies  # True` |
| `guide_values` / `GuideValues` / `GUIDE_VALUES` | `function` / `dataclass` / `constant` | **Table 1: the guide values by kind of area, day and night.**<br>• `area` `'industrial'`, `'commercial'`, `'mixed'`, `'residential'` or `'sensitive'`; keyword-only `time_of_day` (`'day'` Default, `'night'`) and `source`<br>• `.a_u`, `.a_o`, `.a_r`; an urban surface railway raises `A_u` and `A_r` by 1,5 (6.5.3.3); quarry blasting under the conditions of 6.5.1 takes the daytime `A_o` of row 1 in a mixed or residential area | `vibration.guide_values('residential').a_r  # 0.07` |
| `construction_guide_values` / `CONSTRUCTION_GUIDE_VALUES` / `CONSTRUCTION_STAGES` | `function` / `constant` | **Table 2: a construction site by working days and stage, with the interpolation of Figure 3.**<br>• `duration_days`, whole working days 1 to 78, keyword-only `stage` (`'I'` Default, `'II'`, `'III'`) and `area` (not `'sensitive'`, to which 6.5.4.2 says the table does not apply)<br>• 2 to 6 days interpolated between the one-day column and the column that starts at 7, at the two decimals Figure 3 prints; `A_o` 5, or 6 in a commercial or industrial area | `vibration.construction_guide_values(4).a_u  # 0.6` |
| `assessment_vibration_severity` / `admissible_exposure_s` | `function` | **Formulae (4a), (4b) and (5): `KB_FTr` over the assessment period, and the exposure `A_r` allows.**<br>• `kb_ftm` and `exposure_s` [s], one per stretch; keyword-only `time_of_day` and `in_rest_time` (weight 2, day only)<br>• `admissible_exposure_s(kb_ftm, a_r)` is (4b) turned around, as Example 2 does it | `vibration.assessment_vibration_severity([0.16, 0.39], [21600, 5400])  # 0.154` |
| `railway_takt_maximum_rms` / `railway_takt_spread` / `railway_assessment_severity` / `RailwayAssessment` / `admissible_trains_per_hour` | `function` / `dataclass` | **Annex A: a railway by classes of train, and Figure D.1.**<br>• (A.1) `KB_FTm` over the clock intervals a class occupies, (A.2) the spread of its square, (A.3) `KB_FTr` weighted by the intervals each class occupies of the 1920 or 960 of the period, with `.lower` and `.upper` from a `spread`<br>• `admissible_trains_per_hour(kb_ftm, a_r)` = `120 (A_r / KB_FTm)²`, one interval per train | `vibration.railway_assessment_severity([0.82, 0.22], [288, 192]).kb_ftr  # 0.325` |
| `kb_from_peak_velocity` / `kb_fmax_from_peak_velocity` / `PEAK_TO_KB_FACTORS` | `function` / `constant` | **Clause 7: an estimate of `KB_Fmax` from an unweighted record, Formulae (6) and (7) with Table 3.**<br>• `peak_velocity_mm_s` [mm/s], `frequency_hz` [Hz], keyword-only `kind` (the row of Table 3, `'harmonic'` to `'single_event'`)<br>• `KB = v_max / (√2 √(1 + (5,6 Hz / f)²))`, times `c_F` | `vibration.kb_fmax_from_peak_velocity(4.0, 14.0, kind='single_event_resonant')  # 2.10` |
| `ASSESSMENT_PERIOD_S` / `ASSESSMENT_TAKT_COUNT` / `DAY_REST_TIME_S` / `REST_TIME_WEIGHT` / `KB_UNCERTAINTY_PERCENT` | `constant` | **The times and the weights of DIN 4150-2.**<br>• 16 h by day and 8 h by night (3.7.3), 1920 and 960 clock intervals (Annex A)<br>• 4 h of rest hours in the day (3.7.4), the weight 2 of Formula (5), the 15 % of 5.4 | `vibration.ASSESSMENT_TAKT_COUNT['night']  # 960` |
| `RARE_EVENTS_PER_DAY` / `BLASTING_EXCEPTION_KB_FMAX` / `CONSTRUCTION_BLASTING_A_O` / `URBAN_RAILWAY_FACTOR` / `RAILWAY_NIGHT_INVESTIGATION_KB` | `constant` | **The source-specific numbers of 6.5.**<br>• up to 3 short events a day are judged on `A_o` alone; quarry blasting under the conditions of 6.5.1 may reach 8 a few times a year; a site's blasting is held to `A_o` = 8<br>• 1,5 on `A_u` and `A_r` for an urban surface railway; by night a clock maximum above 0,6 on a surface line or 0,3 underground is a reason to look into the cause (6.5.3.5) | `vibration.URBAN_RAILWAY_FACTOR  # 1.5` |
| `GUIDE_VALUES_2023` / `ROAD_EXISTING_TOLERANCE_FACTOR` / `ROAD_NIGHT_INVESTIGATION_KB` / `INDUCED_SEISMIC_PEAK_FACTOR` / `BLASTING_MAX_PER_WEEK` / `induced_seismic_kb_fmax` | `constant` / `function` | **What E DIN 4150-2:2023-08 changes: Table 1 with the night `A_u` of a mixed area at 0,1, and two sources of its own.**<br>• `guide_values(..., edition='2023')` reads the draft, and its `GuideValues` carry the edition and the period, which `assess_people_in_buildings` follows: no shortcut inside the 15 % above `A_u`, a railway compared with `A_o` and a road by night not, with a clock maximum above 0,6 as a reason to look into the cause (6.5.2), `source='road_existing'` with `A_u` and `A_r` tolerated 1,5 times over (6.5.2), `source='induced_seismic'` held by night to the daytime `A_o` (6.5.1.3)<br>• `induced_seismic_kb_fmax(peak_velocity_mm_s)` = 0,44 `v_max`; at most 15 blasts a week where successive ones count as one | `vibration.guide_values('mixed', time_of_day='night', edition='2023').a_u  # 0.1` |
| `train_category_rms` / `train_kb_fmax` / `railway_kb_fmax` | `function` | **E DIN 4150-2:2023-08 6.5.3.2, Formulae (5), (7) and (8): a railway by category of train.**<br>• `train_category_rms(kb_fti_zug)`: the r.m.s. of one clock maximum per passage, nothing zeroed below 0,1<br>• `train_kb_fmax(kb_ftm_zug)`: 1,5 times the r.m.s. of each category; `railway_kb_fmax` the largest of them, the `KB_Fmax` of the line | `vibration.train_category_rms([0.379, 0.369, 0.348])  # 0.366` |
| `train_assessment_severity` / `train_weighting_factor` / `TRAIN_WEIGHTING_FACTORS` / `TRAIN_KINDS` / `TRAIN_KB_FMAX_FACTOR` | `function` / `constant` | **Formula (6) and Table 2 of the draft, and Formula (11) and Table E.1 of E DIN 45672-3:2023-02.**<br>• `train_assessment_severity(kb_ftm_zug, trains, *, alpha, time_of_day)`: each category weighted by its trains out of the 1920 or 960 intervals and by `alpha`; a category at or below 0,1 counts as zero<br>• `train_weighting_factor(kind, *, alignment)`: 0,7 for a tram on the surface to 1,3 for a freight train over 600 m | `vibration.train_assessment_severity([0.24, 0.44], [28, 8], alpha=[0.9, 1.0])  # 0.039` |
| `railway_guide_values` / `RAILWAY_NEW_LINE_NIGHT_A_O` / `assess_railway_change` / `RailwayChange` / `RAILWAY_CHANGE_TOLERANCE_PERCENT` | `function` / `constant` / `dataclass` | **6.5.3.5 and 6.5.3.6 of the draft: a line to be built new, and one to be altered.**<br>• `railway_guide_values(area, *, time_of_day, alignment)`: Table 1 with the night `A_o` of a new line, 0,6 on the surface, 0,3 underground outside an industrial or commercial area<br>• `assess_railway_change(*, kb_fmax_before, kb_fmax_after, kb_ftr_before, kb_ftr_after, guide, time_of_day)`: met where the planned case keeps to `A_u`, or to `A_o` and `A_r`, or exceeds those by an increase under 25 %, every condition that applies holding, as the draft's Example 9 does; `.complies`, `.kb_fmax_met`, `.kb_ftr_met`, `.kb_ftr_increase_percent`<br>• `RailwayChange` takes `kb_fmax_before`, `kb_fmax_after`, `kb_ftr_before`, `kb_ftr_after`, `guide`, `time_of_day`; `kb_fmax_increase_percent`, `kb_ftr_increase_percent`, `kb_fmax_met`, `kb_ftr_met`, `complies` are read-only, read from them | `vibration.railway_guide_values('mixed', time_of_day='night').a_o  # 0.6` |
| `predict_floor_spectrum` / `predict_train_category` / `TrainCategoryPrediction` | `function` / `dataclass` | **E DIN 45672-3:2023-02 Formula (1) and the chain of Clause 7: the spectrum a floor will feel, and the KB values from it.**<br>• `predict_floor_spectrum(emission_db, *, ground_db, foundation_db, floor_db, mitigation_db)`: every term added, band by band, so a mitigation goes in negative<br>• `predict_train_category(emission_db, *, frequencies_hz, ...)` runs (1), the Table 2 weighting (8), the sum (9), 1,5 times it (10) and 3 times that (12): `.floor_db`, `.weighted_db`, `.sum_level_db`, `.kb_ftm`, `.kb_fmax`, `.peak_velocity_mm_s`, `.plot()` | `vibration.predict_train_category(emission, ground_db=bb, floor_db=df).kb_ftm` |
| `kb_weighted_levels_db` / `takt_maximum_kb` / `peak_velocity_from_kb_mm_s` / `velocity_spectrum_um_s` / `KB_WEIGHTING_TABLE_DB` / `KB_ASSESSMENT_BANDS_HZ` / `TAKT_MAXIMUM_FACTOR` / `PEAK_VELOCITY_FACTOR` | `function` / `constant` | **Clause 7 of E DIN 45672-3 piece by piece.**<br>• Table 2, the KB weighting rounded to a tenth of a decibel from 4 Hz to 80 Hz, added by `kb_weighted_levels_db(levels_db, frequencies_hz)`<br>• `takt_maximum_kb(weighted_levels_db)` = `c_T1 v_0 10^(L/20)` with `c_T1` = 1 and `v_0` = 5·10⁻⁵ mm/s (Formula (9)); `peak_velocity_from_kb_mm_s(kb_fmax_zug)` = 3 times it (Formula (12)); `velocity_spectrum_um_s(levels_db)` in micrometres per second (Formula (13)) | `vibration.takt_maximum_kb([78.1])  # 0.4018` |
| `rescale_emission_for_speed` / `ground_transmission_db` / `ground_attenuation_coefficient_per_m` / `SPEED_RESCALING_LIMIT` / `GEOMETRIC_DECAY_EXPONENT_RANGE` | `function` / `constant` | **Clauses 5.2 and 5.3 of E DIN 45672-3: the emission at another speed and the way through the ground.**<br>• `rescale_emission_for_speed(levels_db, *, speed_from_km_h, speed_to_km_h)`: 20 lg of the ratio, for a change of up to 30 % (Formula (3))<br>• `ground_transmission_db(frequencies_hz, *, distance_m, reference_distance_m, exponent, damping_ratio, shear_wave_speed_m_s)`: spreading with `n`, usually 0,2 to 0,4 on the surface, and damping with `alpha_R` = 2π f D / c_s (Formulae (4) to (6)) | `vibration.ground_transmission_db([8.0], distance_m=20.0, reference_distance_m=10.0, exponent=0.3)  # -1.81` |
| `ground_to_floor_transfer_db` / `ground_to_foundation_transfer_db` / `foundation_to_floor_transfer_db` / `GROUND_TO_FLOOR_DB` / `GROUND_TO_FOUNDATION_DB` / `FOUNDATION_TO_FLOOR_DB` / `FOUNDATION_TO_FLOOR_RATIOS` / `FLOOR_NATURAL_FREQUENCIES_HZ` / `PREDICTION_BAND_CENTRES_HZ` | `function` / `constant` | **Annex A of E DIN 45672-3: the six tables of level differences into and inside a building.**<br>• ground to floor (Tables A.1 and A.2) for a concrete or timber floor by its natural frequency, one column per frequency, for every storey<br>• ground to foundation (Tables A.3 and A.4) for a basement or a ground floor, as `'mean'`, `'lower'` or `'upper'`<br>• foundation to floor (Tables A.5 and A.6) against the ratio of the band to the natural frequency, interpolated in decibels over the logarithm of the ratio, `nan` where the print has none | `vibration.ground_to_floor_transfer_db('concrete', floor_natural_frequency_hz=8.0)[3]  # 15.0` |
| `point_to_line_transition_distance_m` / `line_source_correction_db` / `train_decay_exponent` / `train_velocity_ratio` / `LINE_SOURCE_EXPONENT_CORRECTION` / `RECOMMENDED_DISTANCES_M` | `function` / `constant` | **Annex B and Table 1 of E DIN 45672-3: a train is a line of point sources, and how far a prediction should reach.**<br>• `R_0` = `L² / lambda` (Formula (B.1)); `20 n_Korr lg(r / r_0)` with `n_Korr` 0,3 or 0,5 by how the point decay was fitted (Formula (B.2)); the exponent of a train and the piecewise decay of Figure B.1<br>• the distances of Table 1: 25 m from a surface tram to 200 m from freight on soft ground | `vibration.train_decay_exponent(1.0)  # 0.7` |
| `far_field_velocity_mm_s` / `geometric_exponent` / `reference_distance_m` / `attenuation_coefficient_per_m` / `material_damping_factor` / `SOURCE_EXPONENTS` / `TRAIN_CHAIN_EXPONENT_RANGE` / `LOOSE_GROUND_DAMPING_RATIO` | `function` / `constant` | **DIN 4150-1:2001-06 Clause 4.2: how far vibration carries through the ground.**<br>• `far_field_velocity_mm_s(reference_velocity_mm_s, distance_m, *, reference_distance_m, exponent, attenuation_per_m)`: Formula (2), spreading with the exponent of Figure 1 and damping with `alpha` = 2π D / lambda, beyond `R_1` = `a/2 + lambda_R` (Formula (1))<br>• `geometric_exponent(*, geometry, character, wave)`: 0, 0,5, 1 or 1,5; a train decays with 0,3 to 0,5; loose ground has a damping ratio of 0,01 at most in a first estimate | `vibration.far_field_velocity_mm_s(0.44, [80.0], reference_distance_m=13.0, exponent=1.0, attenuation_per_m=0.005)  # 0.051` |
| `soil_building_natural_frequency_hz` / `soil_building_frequency_guide_hz` / `foundation_transfer_max` / `floor_transfer_max` / `storey_frequency_hz` / `LOOSE_GROUND_SYSTEM_DAMPING` / `FOUNDATION_TRANSFER_ABOVE_RESONANCE` / `FLOOR_DAMPING_RATIO_RANGE` / `MEDIUM_SOIL_SHEAR_WAVE_SPEED_M_S` / `STOREY_FORMULA_MIN_STOREYS` | `function` / `constant` | **DIN 4150-1 Clause 4.3: the building on its ground.**<br>• Formula (3), the natural frequency of the building as a mass on the spring of the ground, about 15 Hz for one or two storeys, 8 Hz to 12 Hz for two to six and under 8 above six on medium ground (`c_s` 150 to 200 m/s), two storeys taking the union of the two ranges it is printed in<br>• the most a foundation passes at resonance, `1 / (2 D_0)` = 2 for loose ground, and 0,5 above it; the most a floor amplifies, `1 / (2 D_1)` = 10 to 25 for concrete; `10 / n` Hz for the lowest horizontal mode of `n` ≥ 5 storeys (Formula (4)) | `vibration.floor_transfer_max(0.02)  # 25.0` |
| `blast_peak_velocity_mm_s` / `impact_peak_velocity_mm_s` / `fall_energy_kj` / `BLASTING_RELEVANT_DISTANCE_M` | `function` / `constant` | **DIN 4150-1 Clause 5.1: single events in the far field.**<br>• `blast_peak_velocity_mm_s(charge_kg, distance_m, *, coefficient_mm_s, charge_exponent, distance_exponent)`: `k (L/L_0)^b (R/R_0)^-m` with constants from trial blasts (Formula (5))<br>• `impact_peak_velocity_mm_s(fall_energy_kj, distance_m, *, coefficient_mm_s, distance_exponent)`: the same with the root of the fall energy `G h` (Formula (6)); quarry blasting is rarely relevant beyond 1500 m, construction blasting beyond 400 m | `vibration.fall_energy_kj(25506.0, drop_height_m=70.0)  # 1.79e6` |
| `track_excitation_frequency_hz` / `RAIL_SUPPORT_SPACING_M` / `VEHICLE_NATURAL_FREQUENCIES_HZ` / `TRACK_TRANSMITTED_BANDS_HZ` / `RAIL_INFLUENCE_RANGE_M` / `MACHINE_FREQUENCY_BANDS_HZ` | `function` / `constant` | **DIN 4150-1 Clauses 5.3 and 5.4: what a track and a machine excite at.**<br>• `f_A` = `v_Z / d` and its multiples for sleepers 0,6 m to 0,9 m apart; the car body at 1 Hz to 3 Hz and the bogie at 6 Hz to 10 Hz whatever the speed; ballast passes 40 Hz to 80 Hz, a mass-spring system 5 Hz to 20 Hz; rail vibration reaches 80 m<br>• counter-blow hammers 4 Hz to 8 Hz, forging presses 5 Hz to 15 Hz sideways, frame saws 4 Hz to 8 Hz | `vibration.track_excitation_frequency_hz(20.0, spacing_m=0.6)  # [33.3]` |
| `machine_hall_velocity_mm_s` / `machine_count_correction` / `MACHINE_COUNT_CORRECTION` / `MACHINE_COUNT_AXIS` | `function` / `constant` | **DIN 4150-1 Clause 5.4.2, Formula (7) and Figure 3: a hall of similar machines.**<br>• `machine_hall_velocity_mm_s(reference_velocity_mm_s, machine_count, *, reference_count)`: `chi v_B sqrt(N)`, measured with `N_B` of them running<br>• `chi` is printed only as a nomogram, for `N_B` of 3, 5, 10, 30, 60 or 100 from 4 to 100 machines, and is here as the curves read off the page at a five-hundredth | `vibration.machine_hall_velocity_mm_s(0.44, [60.0], reference_count=3)  # 1.0` |
| `evaluate_train_passage` / `TrainPassage` | `function` / `dataclass` | **One train passage reduced the way DIN 45672-2 reduces it (Clauses 5 to 7).**<br>• `velocity_mm_s` [mm/s] as the transducer gives it, `fs_hz` [Hz], an integer<br>• keyword-only: `t2_s` (the passage, read off the record), `t1_s` (Default: 4 s centred on the peak, never longer than `T₂`), `t3_s` (Default: the whole record), `upper_band_hz` (Default: 315; down to 80)<br>• `.intervals_s`, `.interval_rms_mm_s`, `.peak_velocity_mm_s`, `.running_rms_max_mm_s`, `.kbf_max`, `.event_velocity_mm_s`, `.event_level_db`, `.band_centres_hz`, `.band_interval_levels_db` (one row per stretch), `.band_max_levels_db`, `.plot()`, `.plot_spectrum()`<br>• the record goes through the railway band limitation of DIN 45669-1 before anything is read | `p = vibration.evaluate_train_passage(v, 2048, t2_s=(6.75, 23.25))`<br><br>• `p.event_velocity_mm_s`, `p.band_max_levels_db` |
| `running_velocity_rms` / `running_velocity_level` / `running_acceleration_level` | `function` | **Formulae (1) to (3): the running r.m.s. with τ = 125 ms, and its levels.**<br>• levels re `v₀ = 5·10⁻⁸ m/s` and `a₀ = 10⁻⁶ m/s²`<br>• started from rest: the mean square is 14 % short after 2τ and 2 % after 4τ, the r.m.s. about half that | `vibration.running_velocity_level(v, 2048)[-1]` |
| `interval_rms` / `centred_interval` | `function` | **Formulae (4) and (5), and the stretch `T₁` of Clause 5 a).**<br>• `interval_rms(values, fs_hz, interval_s=(start, end))`: handed the velocity it is Formula (4), handed the running r.m.s. it is Formula (5)<br>• `centred_interval(v, fs_hz, duration_s=4)`: the largest amplitude in the middle, moved rather than cut where the record ends | `vibration.interval_rms(v, 2048, interval_s=(8.0, 20.0))` |
| `event_velocity` / `event_velocity_level` / `combined_event_velocity` | `function` | **Formulae (8) to (10): the event value referred to an hour, its level, and an hour of passages.**<br>• `v_E = ṽ₃ √(T₃ / 3600 s)`, from `interval_rms_mm_s` and `duration_s`<br>• the passages of an hour add in square | `vibration.event_velocity(0.1, 36.0)  # 0.01` |
| `passage_average_velocity` / `passage_average_level` | `function` | **Clause 9: the energy average over repeated passages.**<br>• r.m.s. values as the root of the mean square, levels as the level of the mean energy<br>• keyword-only `axis`: `passage_average_level(spectra, axis=0)` averages third-octave spectra band by band | `vibration.passage_average_level([60, 70])  # 67.40` |
| `amplitude_distribution` / `AmplitudeDistribution` | `function` / `dataclass` | **Formula (11): the amplitude distribution density and its cumulative function (Clause 6.3).**<br>• keyword-only `bins` (Default: 101, equal bins across the range of the stretch)<br>• `.edges_mm_s`, `.density_per_mm_s`, `.cumulative` | `vibration.amplitude_distribution(v).cumulative[-1]  # 1.0` |
| `narrowband_psd` / `passage_energy_spectral_density` / `spectral_density_level` | `function` | **Formulae (12) to (14), and the level Figure 7 draws.**<br>• `narrowband_psd(v, fs_hz, resolution_hz=1.25)`: Welch with a Hanning window and half a block of overlap, as a `SpectralDensityResult`<br>• `passage_energy_spectral_density(psd, duration_s)`: Formula (13) as printed, `G₂ T₂ / 2`, a two-sided density<br>• `spectral_density_level(psd)`: `10 lg(G / G₀)` with `G₀ = (5·10⁻⁸ m/s)²/Hz` | `vibration.narrowband_psd(v, 2048).nperseg / 2048  # 0.8` |
| `third_octaves_from_narrowband` / `THIRD_OCTAVE_LINES` / `NARROWBAND_RESOLUTION_HZ` | `function` / `constant` | **Formula (23) with Table 1: a narrow-band spectrum back into third octaves.**<br>• each band takes its Table 1 count of lines, the ones nearest its nominal centre on a logarithmic axis: the lines inside the nominal edges wherever the count is what they hold<br>• six lines fall between bands and five are in two, as nominal edges leave them; a band the spectrum does not hold whole is left out<br>• refuses a spectrum not spaced 1,25 Hz, the spacing the counts are written for | `c, rms = vibration.third_octaves_from_narrowband(f, psd)` |
| `velocity_psd_from_voltage` / `elastic_insertion_loss` / `band_sum_level` | `function` | **Annex A and Annex B.**<br>• Annex A: a density in V²/Hz divided by `κ_A² κ_V²`, keyword-only `sensitivity_v_per_mm_s` and `gain`<br>• (B.1) the insertion loss of an elastic element, `L₁ − L₂` per band, which is also the difference spectrum of (B.2)<br>• (B.3) the energy sum of the bands | `vibration.band_sum_level([60, 60])  # 63.01` |
| `VELOCITY_LEVEL_REFERENCE_MM_S` / `EVENT_REFERENCE_DURATION_S` / `T1_DURATION_S` / `PASSAGE_BANDS_HZ` | `constant` | **The numbers DIN 45672-2 is built from.**<br>• `v₀ = 5·10⁻⁸ m/s`, here 5e-5 mm/s (Formula (2); the 50 nm/s of note b of ISO 1683:2015 Table 3, 34 dB from its 1 nm/s)<br>• 3600 s, the hour of Formula (8), and 4 s, the recommended `T₁`<br>• 4 Hz to 315 Hz, the third-octave range of 7.2 | `vibration.VELOCITY_LEVEL_REFERENCE_MM_S  # 5e-05` |
| `poisson_ratio_from_wave_speeds` / `shear_modulus_from_wave_speed` / `youngs_modulus_from_wave_speeds` | `function` | **DIN 45672-1 Clause 4.5: the ground's constants from its two wave speeds.**<br>• Formula (3) `ν = (v_p² − 2v_s²) / (2(v_p² − v_s²))` and Formula (5) `G = v_s² ρ`<br>• `E = 2G(1 + ν)`, not the printed `E = v_p² ρ`, which is the P-wave modulus; see `docs/ERRATA.md`<br>• speeds in m/s, keyword-only `density_kg_m3` | `vibration.poisson_ratio_from_wave_speeds(400.0, 180.0)  # 0.373` |
| `compression_wave_speed` / `shear_strain_amplitude` | `function` | **Formula (1) corrected, and Formula (4).**<br>• `v_p = √(2G(1 − ν) / (ρ(1 − 2ν)))`, the continuum; the print is short of the factor 2<br>• `γ̂ = v̂ / v_s`, with the velocity amplitude in m/s | `vibration.shear_strain_amplitude(2e-4, shear_wave_speed_m_s=180.0)` |
| `GROUND_WAVE_SPEED_RANGES_M_S` / `SHEAR_STRAIN_LINEAR_LIMIT` | `constant` | **What Clause 4.5 gives for natural ground.**<br>• compression waves 200-2000 m/s and shear waves 10-1000 m/s<br>• `10⁻⁴`: the shear strain up to which Figure 1 has the modulus about constant | `vibration.SHEAR_STRAIN_LINEAR_LIMIT  # 0.0001` |
| `fdtd_simulation` | `function` | **2D acoustic FDTD wave simulation (staggered grid, leapfrog).**<br>• `c`: sound-speed map [m/s], `(ny, nx)` array or scalar with `shape`<br>• `dx`: grid spacing [m]<br>• `duration`: physical time to simulate [s]<br>• `sources`: `GaussianPulse` \| `CWSource` \| `SignalSource` list<br>• `probes`: `(ix, iy)` pressure-probe cells<br>• `boundaries`: `"rigid"` \| `"absorbing"` \| per-side mapping (name or real impedance [Pa·s/m])<br>• `obstacle_mask`: boolean `(ny, nx)` rigid-cell map / `rho` / `cfl` / `damping` / `absorbing_layer_cells` / `snapshot_every` | `res = simulation.fdtd_simulation(343, 0.01, 0.02, shape=(200, 300), sources=[simulation.GaussianPulse(ix=60, iy=100, half_width_s=3e-4)], probes=[(200, 100)])`<br><br>• `FDTDResult` |
| `FDTDResult` | `dataclass` | **FDTD simulation result.**<br>• `times` [s] / `pressures` [Pa] per probe / `probes` / `probe_positions` [m]<br>• `dx` / `dt` / `shape` / `size` [m] / `sources` / `snapshots` / `snapshot_times` / `obstacle_mask`<br>• `.plot()`: probe histories; `.plot(kind="snapshot")`: pressure field | `res.pressures, res.times`<br>`res.plot()` |
| `FDTD2D` | `class` | **FDTD stepping engine (frame-by-frame access).**<br>• `c` [m/s] / `dx` [m] / `rho` [kg/m³] / `cfl` / `shape`<br>• `sponge_width` / `sponge_sides` / `sponge_reflection` / `damping`<br>• `edge_impedance`: per-side real impedance [Pa·s/m] / `obstacle_mask` | `sim = simulation.FDTD2D(343, 0.01, shape=(200, 300))`<br>`sim.add_source(src); sim.step(); sim.run(400, record_every=10)`<br>• `sim.p` / `sim.vx` / `sim.vy` / `sim.dt` / `sim.time` / `sim.energy()`<br>• `sim.plot_geometry(probes=...)`: draw the configured domain before running<br>• `sim.add_plane_wave(direction, center=..., width=..., wavelength=...)`: one-way plane packet initial condition<br>• `sim.add_contour_probe(ix0, ix1, iy0, iy1, frequencies=...)`: on-the-fly `p`/`v_n` phasor capture on a closed contour |
| `GaussianPulse` | `dataclass` | **Gaussian pulse source for the FDTD solver.**<br>• `ix` / `iy`: source cell<br>• `width` [s] / `t0` [s] (Default: `4*width`) / `amplitude` [Pa] | `GaussianPulse(ix=60, iy=100, half_width_s=3e-4)` |
| `PlaneWaveSource` | `dataclass` | **Sustained one-way plane wave injected on a line (TF/SF style).**<br>• `direction`: 'down'/'up'/'left'/'right' (travel)<br>• `waveform`: callable t → p_inc(t) [Pa] (reuse a point source's `.value`)<br>• `offset`: line position in cells from the launch edge (place it just inside a sponge)<br>• `amplitude` (Default: 1.0) | `sim.add_source(simulation.PlaneWaveSource('down', simulation.CWSource(0, 0, frequency=1000.0).value, offset=22))`<br><br>• Transversely plane to machine precision; ~1e-4 residual behind the line |
| `CWSource` | `dataclass` | **Continuous sine source with raised-cosine onset for the FDTD solver.**<br>• `ix` / `iy`: source cell<br>• `frequency` [Hz] / `amplitude` [Pa] / `ramp_cycles` | `CWSource(ix=25, iy=25, frequency=170)` |
| `SignalSource` | `dataclass` | **Arbitrary sampled waveform source for the FDTD solver.**<br>• `ix` / `iy`: source cell<br>• `samples` [Pa] / `fs` [Hz] / `amplitude`<br>Linearly interpolated onto the simulation time steps | `SignalSource(ix=60, iy=100, samples=sig, fs=48000)` |
| `ContourProbe` | `class` | **On-the-fly DFT of `p` and `v_n` on a closed rectangular contour.**<br>Created by `FDTD2D.add_contour_probe`; complex accumulators per point and frequency, so CW runs store no time histories<br>• `positions` / `normals` / `frequencies` / `samples`<br>• `.reset()`: restart accumulation once the field is steady<br>• `.phasors(frequency)`: the captured `ContourPhasors` | `probe = sim.add_contour_probe(90, 470, 90, 345, frequencies=[2000.0])`<br>`sim.run(steps); probe.reset(); sim.run(window)`<br>`ph = probe.phasors(2000.0)` |
| `ContourPhasors` | `dataclass` | **Steady-state `p` and `v_n` phasors on a closed contour (`exp(+jωt)`).**<br>• `frequency` [Hz] / `positions` `(n, 2)` [m] / `normals` (outward)<br>• `pressure` [Pa] / `normal_velocity` [m/s] (complex) / `segment` [m]<br>• `.subtract(reference)`: scattered = total − incident phasors | `scattered = total.subtract(reference)` |
| `far_field_from_contour` | `function` | **2D near-to-far-field transformation (Kirchhoff-Helmholtz integral).**<br>• `contour`: `ContourPhasors`<br>• `angles_deg` [deg]: observation directions `(cos a, sin a)` in grid axes<br>• `distance`: `None` (far-field pattern `F(a)`, `p → F e^{−jkr}/√r`) or a radius [m] for the exact Hankel evaluation<br>• `origin`: phase-reference point<br>• `fluid`: `Fluid` (Default: `SIMULATION_AIR`, the medium the solver runs in) | `F = simulation.far_field_from_contour(ph, np.arange(-180, 180, 2), origin=(xc, yc))`<br><br>• Complex pattern, one value per angle_deg |
| `elastic_fdtd_simulation` | `function` | **2D elastic P-SV FDTD wave simulation (velocity-stress, Virieux staggered grid).**<br>• `c_p` / `c_s`: wave-speed maps [m/s], `(ny, nx)` arrays or scalars with `shape` (`c_s = 0` marks fluid cells)<br>• `dx`: grid spacing [m] / `duration` [s] / `rho`: density map [kg/m³]<br>• `sources`: `ExplosionSource` \| `ForceSource` list<br>• `recording`: `ElasticRecording` (probe cells and fields, snapshot cadence and field)<br>• `boundaries`: `ElasticBoundaries` (the four sides and the sponge thickness)<br>• `obstacle_mask` / `cfl` / `damping` | `res = simulation.elastic_fdtd_simulation(6320, 3130, 0.001, 5e-5, rho=2700, shape=(300, 600), sources=[simulation.ForceSource(ix=300, iy=0, direction='y', waveform=simulation.GaussianPulse(0, 0, half_width_s=8e-6).value)], boundaries=simulation.ElasticBoundaries({'top': 'free'}))`<br><br>• `ElasticFDTDResult` |
| `ElasticFDTDResult` | `dataclass` | **Elastic FDTD simulation result.**<br>• `times` [s] / `signals` `(n_probes, n_fields, n_steps+1)` / `probe_fields` / `probes` / `probe_positions` [m]<br>• `dx` / `dt` / `shape` / `size` [m] / `sources` / `snapshots` / `snapshot_times` / `snapshot_field` / `obstacle_mask` / `free_sides`<br>• `.plot()`: probe histories; `.plot(kind="snapshot")`: recorded field | `res.signals, res.times`<br>`res.plot()` |
| `ElasticRecording` | `dataclass` | **What an elastic FDTD run records.**<br>• `probes`: `(ix, iy)` cells (Default: none)<br>• `probe_fields`: `("p" \| "vx" \| "vy", ...)` (Default: `("vy",)`)<br>• `snapshot_every` steps (Default: None)<br>• `snapshot_field` (Default: `"p"`) | `ElasticRecording(probes=[(300, 0)], snapshot_every=50, snapshot_field='vy')` |
| `ElasticBoundaries` | `dataclass` | **How the four edges of the elastic domain end.**<br>• `sides`: `"rigid"` (Default) \| `"absorbing"` \| `"free"` (stress-imaging surface) \| per-side mapping<br>• `absorbing_layer_cells` (Default: 20) | `ElasticBoundaries({'top': 'free'}, absorbing_layer_cells=40)` |
| `ElasticFDTD2D` | `class` | **Elastic P-SV stepping engine (frame-by-frame access).**<br>• `c_p` / `c_s` [m/s] / `dx` [m] / `rho` [kg/m³] / `cfl` / `shape`<br>• `free_sides`: traction-free surfaces (stress imaging)<br>• `sponge_width` / `sponge_sides` / `sponge_reflection` / `damping` / `obstacle_mask` | `sim = simulation.ElasticFDTD2D(6320, 3130, 0.001, rho=2700, shape=(300, 600), free_sides='top')`<br>`sim.add_source(src); sim.step(); sim.run(400, record_every=10)`<br>• `sim.txx` / `sim.tyy` / `sim.txy` / `sim.vx` / `sim.vy` / `sim.p` / `sim.lam` / `sim.mu` / `sim.dt` / `sim.time` / `sim.energy()`<br>• `sim.collocated(field)`: one field interpolated to cell centres |
| `ElasticFDTD2D.from_regions` | `classmethod` | **Layered/embedded set-ups from named materials (no manual maps).**<br>• `shape`: `(ny, nx)` / `dx` [m]<br>• `background`: `Material`, `(c_p, c_s, rho)` or a solid's catalogue row filling the grid<br>• `regions`: `(where, material)` pairs painted in order (`where`: boolean mask or numpy index)<br>• remaining kwargs forwarded to the constructor | `sim = ElasticFDTD2D.from_regions((300, 600), 0.001, background=WATER, regions=[(np.s_[150:, :], STEEL)])` |
| `Material` | `dataclass` | **Isotropic medium as wave speeds and density (frozen).**<br>• `c_p` [m/s] / `c_s` [m/s] (`0` marks a fluid) / `rho` [kg/m³]<br>• `is_fluid`: `c_s == 0`<br>Must satisfy `c_p² ≥ 2 c_s²` (non-negative λ)<br>Wherever one is taken, a solid's catalogue row is taken too: its `bulk_longitudinal_speed_m_s`, `transverse_speed_m_s` and `density_kg_m3`, read through `.printed()`; never its plate or bar speed | `Material(c_p=5958, c_s=3184.7, rho=7850)` |
| `SIMULATION_AIR` | `Fluid` | **The air the acoustic solvers run in.**<br>343.0 m/s, 1.2 kg/m³, the `AIR` `Material` written as a fluid<br>• the `fluid` default of `far_field_from_contour`<br>• a `phonometry.fluids.Fluid`: pass a computed one, or a water, to transform out of the medium the run actually used | `simulation.SIMULATION_AIR.density  # 1.2` |
| `AIR` / `WATER` / `STEEL` / `ALUMINIUM` / `CONCRETE` | `Material` | **Named media, the three solids read off Bies 5e Table C.1.**<br>air 343/0/1.2, water 1480/0/1000, steel 5958/3184.7/7850, aluminium 6450.5/3098.7/2700, concrete 3726.8/2282.2/2400 (c_p/c_s/ρ)<br>• each solid's density is printed and its two speeds follow from the modulus and Poisson ratio beside it | `ElasticFDTD2D.from_regions((240, 480), 0.005, background=WATER, regions=[(np.s_[120:, :], STEEL)])` |
| `scholte_speed` | `function` | **Exact Scholte interface-wave speed of a fluid over an elastic half-space.**<br>• `fluid`: `Material` with `c_s = 0` (or triple)<br>• `solid`: `Material` with `c_s > 0`, or a solid's catalogue row (its bulk speeds and density)<br>Root of the exact characteristic equation (Brekhovskikh & Godin Eq. 4.4.20); non-dispersive, below both the fluid speed and the solid shear speed | `scholte_speed(WATER, STEEL)  # 1479.6`<br><br>• v [m/s] |
| `ExplosionSource` | `dataclass` | **Isotropic (explosive) stress source for the elastic solver.**<br>• `ix` / `iy`: source cell<br>• `waveform`: callable t → injected pressure [Pa] (reuse a point source's `.value`)<br>• `amplitude` (Default: 1.0)<br>Pressure-like sign: equal `-s(t)` increments on both normal stresses | `ExplosionSource(ix=250, iy=250, waveform=simulation.GaussianPulse(0, 0, half_width_s=8e-6).value)` |
| `ForceSource` | `dataclass` | **Directional body-force source for the elastic solver.**<br>• `ix` / `iy`: staggered velocity node<br>• `direction`: `'x'` \| `'y'`<br>• `waveform`: callable t → line force [N/m] / `amplitude`<br>A vertical force under a free surface reproduces Lamb's problem | `ForceSource(ix=300, iy=0, direction='y', amplitude=1e6, waveform=simulation.GaussianPulse(0, 0, half_width_s=8e-6).value)` |
| `PhonometryWarning` | `warning class` | **Base class for all phonometry warnings.**<br>Emitted by every module through the subclass of its own domain, so catching this one catches every library advisory at once | `warnings.simplefilter('error', PhonometryWarning)` |
| `FilterBankWarning` | `warning class` | **Fractional-octave filter-bank advisory.**<br>Emitted for filter-bank processing pitfalls | `warnings.simplefilter('error', FilterBankWarning)` |
| `TonalityWarning` | `warning class` | **Tonality advisory.**<br>Emitted for biased tonality estimates (e.g. coarse FFT resolution) | `warnings.simplefilter('error', TonalityWarning)` |
| `STIWarning` | `warning class` | **STI/STIPA advisory.**<br>Emitted for suspect speech-intelligibility measurements or inputs | `warnings.simplefilter('error', STIWarning)` |
| `__version__` | `str` | **Package version string.**<br>(no parameters) | `phonometry.__version__  # '4.0.0rc1'` |
| `.plot()` | `method` | **One-line canonical figure on every result object (soft matplotlib dependency).**<br>Available on `ZwickerLoudness`, `MooreGlasbergLoudness`, `MooreGlasbergTimeVaryingLoudness`, `EcmaLoudness`, `EcmaTonality`, `EcmaRoughness`, `PsychoacousticAnnoyanceResult`, `FluctuationStrengthResult`, `ProgramLoudnessResult`, `KWeightingResponse`, `STIResult`, `SIIResult`, `SIIProcedure`, `StandardSpeechSpectrum`, `NCResult`, `RCResult`, `AgeThresholdResult`, `NiptsResult`, `HtlanResult`, `ImpulseProminenceResult`, `ImpulsiveSoundResult`, `SelDistribution`, `LevelDifferenceQuantiles`, `RoundRobinPrecision`, `CalculationVerification`, `DirectivityFactor`, `RandomIncidenceSensitivity`, `DiffuseFieldSensitivity`, `AdjustmentValue`, `FreeFieldCorrection`, `CorrectionUncertaintyBudget`, `CorrectionUncertaintyVerification`, `ComparisonCalibration`, `EnvironmentalSensitivityCorrection`, `JigDiameterCorrection`, `DiameterSoundFieldCorrection`, `JigCouplerVerification`, `ComparisonUncertaintyBudget`, `FreeFieldRegion`, `ReciprocityCalibration`, `ReciprocityUncertaintyBudget`, `CouplerTransferImpedance`, `HeatConductionCorrection`, `CapillaryTubeImpedance`, `WaveMotionCorrection`, `CouplerCheck`, `CouplerParameterUncertainty`, `ReciprocityAirAttenuation`, `AcousticCentre`, `FreeFieldArrangementCheck`, `FreeFieldParameterUncertainty`, `SoundLevelMeterPeriodicRequirement`, `SoundLevelMeterPeriodicVerification`, `FieldStrengthReading`, `BackgroundNoiseAssessment`, `InductionLoopVerification`, `LoopRequirement`, `AmplifierOverloadVerification`, `LoopField`, `LoopImpedance`, `AmplifierFrequencyResponse`, `AgcCharacteristic`, `QuadraturePhaseError`, `MaximumOutputCurrent`, `NeckLoopCharacteristics`, `NeckLoopVerification`, `ProgrammeSignalCheck`, `RatedImpedanceVerification`, `ProgrammeCharacteristicVoltage`, `LimitingTestSignalCheck`, `ProtectionVoltage`, `CouplerFrequencyResponse`, `CrosstalkAttenuation`, `FieldComparisonResponse`, `EarCanalFrequencyResponse`, `EarCanalMicrophoneVerification`, `MultipleShockResult`, `ImpulseResponseResult`, `DecayCurve`, `RoomAcousticsResult`, `ReverberationResult`, `ReverberationModelResult`, `DynamicStiffnessResult`, `MobilityResult`, `TransferStiffnessResult`, `BandAveragedStiffness`, `LevelDifferenceCheck`, `OutputMassCheck`, `EffectiveBlockingMass`, `DrivingPointStiffnessResult`, `DrivingPointUncertainty`, `VibrationSoundPowerResult`, `StructureBornePowerResult`, `InstalledSourceResult`, `WeightedRatingResult`, `ImpactRatingResult`, `ImpactImprovementRatingResult`, `FacadeInsulationResult`, `LabAirborneInsulationResult`, `LabImpactInsulationResult`, `SoundPowerResult`, `SoundEnergyResult`, `ReverberationSoundPowerResult`, `ReverberationSoundEnergyResult`, `InSituSoundPowerResult`, `InDuctSoundPowerResult`, `PlantMeasurementContour`, `PlantSoundPowerResult`, `PlantMeasurementCheck`, `PartialPlantContributions`, `HighFrequencySoundPowerResult`, `InverseSquareLawResult`, `FreeFieldCheck`, `SourceDirectionalityResult`, `ReferenceSourceCalibration`, `ReferenceSoundSourceVerdict`, `ReferenceSourceDriftResult`, `TurbineMeasurementSurface`, `TurbineMicrophoneArray`, `TurbineEnvironmentalCorrection`, `TurbineTestEnvironmentCheck`, `TurbineSoundPowerResult`, `TurbineNoiseDeclaration`, `SoundPowerIntensityResult`, `DiscretePointIntensityResult`, `PrecisionSoundPowerResult`, `PrecisionIntensityResult`, `IntensityResult`, `UncertaintyResult`, `AbsorptionRatingResult`, `ScatteringResult`, `DiffusionResult`, `DiffusionSpectrum`, `InsituAbsorptionResult`, `WeightingResponse`, `WeightedSpectrum`, `Signal` and `DailyVibrationExposure`.<br>• `ax`: existing Axes, or None to build a fresh figure (Default: None)<br>• returns the Matplotlib `Axes` (an array of Axes for multi-panel figures); never calls `plt.show()`<br>• needs matplotlib (`pip install phonometry[plot]`) | `res.plot()`<br>`decay_curve(ir, fs).plot()` |

## Notes

- `zero_phase=True` (in `OctaveFilterBank.filter` and `spectrogram`) filters
  forward-backward (`sosfiltfilt`): no group delay, doubled effective
  attenuation, offline analysis only. Incompatible with `stateful=True`. The
  passband also 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 reserve
  zero-phase for when the temporal envelope matters (e.g. reverberation decay).
- `mode='peak'` includes the filter's onset transient; a tone that starts
  abruptly can overshoot by ~1 dB. See [Calibration and dBFS](https://docs.jmrp.io/phonometry/signals/metrology/calibration/).
- `octave_filter()` caches filter bank designs internally (32 entries), so
  repeated calls with the same parameters skip the design phase. For explicit
  control use `OctaveFilterBank`.
- The 3.1 aliases are gone, as their notices said they would be in 4.0:
  `octavefilter`, `getansifrequencies`, `normalizedfreq`,
  `calculate_sensitivity`, the bare `coverage_factor` and
  `expanded_uncertainty` of ISO 12999-1, the `OCTAVE_BANDS_HZ`,
  `THIRD_OCTAVE_BANDS_HZ` and `BASE_PLATE_BANDS_HZ` constants,
  `BAND_CENTRES`, `ExposureWarning`, and the `sample_rate`, `humidity` and
  `room_volume` keywords. Use `octave_filter`, `nominal_frequencies`,
  `normalized_frequencies`, `sensitivity`, `insulation_coverage_factor`,
  `insulation_expanded_uncertainty`, `OCTAVE_BANDS`, `THIRD_OCTAVE_BANDS`,
  `BASE_PLATE_BANDS`, `phonometry.speech.sii.BAND_CENTERS`,
  `OccupationalExposureWarning`, `fs`,
  `relative_humidity_percent` and `volume`.
