Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Building acoustics II: facade insulation (ISO 16283-3), laboratory measurement (ISO 10140), prediction with flanking (EN 12354) and uncertainty (ISO 12999-1) (#88)
* feat: ISO 16283-3 facade sound insulation
Add facade_insulation() and FacadeInsulationResult for field facade sound
insulation per ISO 16283-3: the global-method level difference D2m and its
standardized (D2m,nT) and normalized (D2m,n) forms, plus the element-method
apparent sound reduction index R'45 (loudspeaker, -1,5 dB) / R'tr,s (road
traffic, -3 dB). Reuses the ISO 16283-1 energy-averaging helpers, the
Sabine absorption area, and the ISO 717-1 airborne weighted_rating engine
unchanged for the single-number rating. Adds a per-band .plot() profile and
exports.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: ISO 16283-3 draft-edition caveat and symmetric R' validation
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 10140 laboratory airborne and impact sound insulation
Add src/phonometry/lab_insulation.py, the laboratory counterpart of the
field ISO 16283 family:
- lab_airborne_insulation: R = L1 - L2 + 10 lg(S/A) with A = 0,16 V/T
(ISO 10140-2:2010 Formula (2); ISO 10140-4:2010 Formula (5)).
- lab_impact_insulation: Ln = Li + 10 lg(A/A0), A0 = 10 m²
(ISO 10140-3:2010 Formula (1)).
- background_correction: ISO 10140-4:2010 Clause 4.3 Formula (4) with the
6/15 dB criteria and the 1,3 dB limit-of-measurement cap.
Single-number Rw / Ln,w with C, Ctr, CI reuse the verified ISO 717-1/2
weighted_rating / weighted_impact_rating engines; position energy
averaging reuses _as_band_levels. 29 new closed-form / identity tests.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: reconcile facade citations with published ISO 16283-3:2016
The facade module was drafted from ISO/DIS 16283-3:2014; its docstrings
cited draft formula numbers with a caveat to reconcile against the
published edition. Reconciled against ISO 16283-3:2016(E) (First edition
2016-02-01):
- Clause numbers are edition-stable: the field-quantity definitions keep
3.12 (R'45deg), 3.13 (R'tr,s), 3.14 (D2m), 3.15 (D2m,nT), 3.16 (D2m,n),
3.17 (A=0,16V/T), and 9.5.1 (surface-level averaging).
- Formula numbers differ: in the 2016 edition the Clause 3 defining
formulas are UNNUMBERED (inline in the term definitions); the numbered
formulas (1)-(21) live in the procedural clauses. The surface-level
energy-average is Formula (7) in 2016 (was Formula (20) in the DIS).
- Dropped the invalid draft Formula (2)-(7) citations from the field-
quantity docstrings and the draft-edition reconciliation caveat.
- Constants and formula bodies are unchanged (-1,5 dB / -3 dB, A0=10 m2,
T0=0,5 s, A=0,16V/T, band ranges): no numeric change; 22 facade tests
green.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: EN 12354-1/2 building acoustic performance prediction with flanking
Implement the EN 12354:2000 simplified single-number prediction model for
apparent airborne (R'w) and impact (L'n,w) sound insulation, including direct
plus flanking transmission (Ff/Df/Fd paths) and the Annex E vibration-reduction
index Kij for rigid cross, rigid T, flexible-interlayer and lightweight-facade
junctions.
Airborne Formula (26)/(27)/(28a) with l0=1 m, Kij,min (29), lining composition
(30)/(31); impact Formula (21) with bare-floor Ln,w,eq (164-35 lg m'), Table 1
flanking correction K, and standardized L'nT,w (3). Results expose per-path
energy contributions so the dominant flanking path is visible.
Validated against the standards' worked examples: Part 1 Annex H.3 airborne
(R'w = 52 dB, 13 paths; +floating-floor 53 dB) and Part 2 Annex E.3 impact
(L'n,w = 45 dB, L'nT,w = 43 dB); all four Annex H junctions reproduce Kij.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 12999-1 building acoustics measurement uncertainty
Add building_uncertainty module implementing ISO 12999-1:2020 standard
uncertainties for sound-insulation quantities: per-band and single-number
values for airborne (Tables 2/3), impact (Tables 4/5) and floor-covering
reduction (Tables 6/7), across measurement situations A/B/C (Clause 5.2),
plus the Annex D sigma_R95 upper limits, Table 1 max repeatability and
Table 8 coverage factors.
Expansion U = k*u with k >= 1 (Clause 8), one-sided factors for conformity
checks (Formulae 4/5), and combination rules from Annexes A/B/C (prediction
input A.1, quadrature A.2/C.2, m-measurement reduction A.7, uncorrelated
single-number B.2). Composable UncertainValue attaches value +- U without
touching the rating dataclasses.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: numpy-stub-agnostic annotations for the two env-dependent mypy sites
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* refactor: PR-B review minors — anchors, Kij floor, uncertainty polish
- Table 3 r_w+ctr_50_5000 σsitu(B)=1.0 verified digit-by-digit against the
ISO 12999-1:2020(E) page image; anomalous but normative (comment added).
- Anchor the ISO 10140 rating tests to independent literals (Rw=54, Ln,w=58 —
reference-curve shape + the 32 dB / 16-band = 2 dB ISO 717 shift).
- background_correction: cross-ref sound_power.background_noise_correction and
document the negative-margin (Lb > Lsb) cap at Lsb−1.3.
- flanking_path: optional kij_min clamp for EN 12354-1 Clause 4.4.2 (Kij≥Kij,min),
documented on flanking_element; tested clamped vs unclamped (H.3 unaffected).
- impact_flanking_correction: comment on nearest-neighbour + tie-to-lower.
- Export COVERAGE_FACTORS (Table 8) as public API.
- single_number_uncertainty: note impact situation A is an estimate (Table 5 fn a).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: conformance checks for facade, lab insulation, EN 12354 and ISO 12999
Add six numerical conformance checks for the PR-B building-acoustics
standards, following the established registry pattern (single source of
truth in tests/reference_data.py, clause citations, honest tolerances):
- ISO 16283-3:2016 Clause 3.12: facade R'45 isolates the -1.5 dB
oblique-incidence correction on an S=A constructed case (exact).
- ISO 10140-2:2021 Formula (2): lab airborne R laid on the ISO 717-1
reference shape (S=A) -> Rw = 54 (the +2-shift analytic anchor).
- EN 12354-1:2000 Annex H.3: airborne prediction R'w = 52 from the 13
transmission paths (direct + 12 flanking), the branch's strongest oracle.
- EN 12354-2:2000 Annex E.3: impact prediction L'n,w = 45 (76-33+2).
- ISO 12999-1:2020 Table 2: airborne band uncertainty, situation A @
1 kHz = 1.8 dB (digit-exact), and Clause 8/Table 8 expanded
uncertainty U = 1.96 u = 2.352 dB (exact k=1.96 arithmetic).
Facade and lab checks join "Room & building acoustics"; the EN 12354 /
ISO 12999 checks form a new "Building prediction & uncertainty" domain.
Registry grows 26 -> 32 checks across 7 domains. Shared expected values
and the Annex H.3 input table move into reference_data.py so the report
and tests cannot drift; a consistency test pins them to the published
worked-example results. docs/CONFORMANCE.md regenerated via make conformance.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: building acoustics II — facade, laboratory, prediction and uncertainty (EN)
Extend the Room & Building Acoustics guide with facade insulation
(ISO 16283-3), laboratory characterisation (ISO 10140), flanking-transmission
performance prediction (EN 12354-1/2) and measurement uncertainty
(ISO 12999-1), with executed snippets reproducing the EN 12354-1 Annex H.3
(R'w = 52 dB) and Annex E.3 (L'n,w = 45 dB) worked examples. Add the matching
theory subsections, API-reference rows for every new public name, README and
landing-page entries (29 -> 33 standards), and CHANGELOG. EN docs and site
twins keep byte-identical code blocks.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: flanking-paths diagram, prediction and uncertainty figures
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: gemelas ES de edificación II (fachadas, laboratorio, predicción, incertidumbre)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: PR-B final-review fixes — count, GitHub-safe math, edition alignment
Landing count corrected to 34 standards (slash-part convention); the
GitHub-unsafe math spacing tokens reintroduced by the new building
sections are scrubbed from the docs/ tree and its site twins; the whole
ISO 10140-2 citation chain aligned to the verified :2010 edition; plus
the six minor documentation-precision fixes from the final review.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: PR 88 review round 1 — isfinite idiom, heading levels, frequencies validation
- building_prediction._check_finite: replace 'v != v or v in (inf,-inf)'
NaN idiom with math.isfinite for SonarCloud (same behavior, cleaner).
- room-acoustics docs (EN docs + site, ES site): relevel the three
parameter-table headings that skipped H2->H4 to H3 (MD001).
- insulation.facade_insulation: validate 'frequencies' length against the
band count, raising a clear ValueError instead of deferring a matplotlib
shape error to plot(). lab_insulation/building_uncertainty have no such
gap (no user-supplied frequencies stored). Regenerated llms-full.txt.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 4a: concept-based names for the four unpublished modules (#111)
* refactor: concept-based names for the four unpublished modules
Audit batch 4a — the four modules named after standard numbers were all
merged after v3.0.0 and never published, so they rename cleanly (no
deprecation shims), aligned with their documentation pages:
- iso1999 -> noise_induced_hearing_loss
- iso2631_5 -> multiple_shock_vibration
- ntacou112 -> impulse_prominence
- en12354_6 -> enclosed_space_absorption
- class ImpulseProminence -> ImpulseProminenceResult
Everything that referenced the old module paths moves with them: package
imports/__all__, the plotting layer (including plot_en12354_6 ->
plot_enclosed_space_absorption), the test files (1:1 names, history
preserved), the conformance checks and the figure/diagram generator
functions (generate_nihl -> generate_noise_induced_hearing_loss for
consistency). Committed image basenames stay unchanged (published docs
link them).
CONTRIBUTING.md gains the validated Naming Conventions section (per-group
table + deprecation mechanics: NEP 23-format DeprecationWarning, PEP 562
module __getattr__ shims, the sklearn deprecated-kwarg sentinel, removal
only in majors) so the drift that produced the standard-number names
cannot recur.
* docs: align the deprecation policy with the implemented shims
- CONTRIBUTING: the stacklevel rule now says what it is for (point at
the caller's line: 2 direct, 3 via a shared helper) instead of a
literal that contradicted the existing helper-based shims (CodeRabbit)
- the insulation_* deprecation messages carry the NEP 23 version
metadata (deprecated since 3.1, removal in 4.0)
Gemini's FutureWarning suggestion is declined again: the ecosystem
research (NEP 23, scipy) settles DeprecationWarning for renames;
FutureWarning is reserved for behavior changes.
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4a: concept-based names for the four unpublished modules (#111)
* refactor: concept-based names for the four unpublished modules
Audit batch 4a — the four modules named after standard numbers were all
merged after v3.0.0 and never published, so they rename cleanly (no
deprecation shims), aligned with their documentation pages:
- iso1999 -> noise_induced_hearing_loss
- iso2631_5 -> multiple_shock_vibration
- ntacou112 -> impulse_prominence
- en12354_6 -> enclosed_space_absorption
- class ImpulseProminence -> ImpulseProminenceResult
Everything that referenced the old module paths moves with them: package
imports/__all__, the plotting layer (including plot_en12354_6 ->
plot_enclosed_space_absorption), the test files (1:1 names, history
preserved), the conformance checks and the figure/diagram generator
functions (generate_nihl -> generate_noise_induced_hearing_loss for
consistency). Committed image basenames stay unchanged (published docs
link them).
CONTRIBUTING.md gains the validated Naming Conventions section (per-group
table + deprecation mechanics: NEP 23-format DeprecationWarning, PEP 562
module __getattr__ shims, the sklearn deprecated-kwarg sentinel, removal
only in majors) so the drift that produced the standard-number names
cannot recur.
* docs: align the deprecation policy with the implemented shims
- CONTRIBUTING: the stacklevel rule now says what it is for (point at
the caller's line: 2 direct, 3 via a shared helper) instead of a
literal that contradicted the existing helper-based shims (CodeRabbit)
- the insulation_* deprecation messages carry the NEP 23 version
metadata (deprecated since 3.1, removal in 4.0)
Gemini's FutureWarning suggestion is declined again: the ecosystem
research (NEP 23, scipy) settles DeprecationWarning for renames;
FutureWarning is reserved for behavior changes.
Advanced metrology: G-weighting, ISO 226 contours, ECMA-418-1 tonality, ISO 1996 Lden, IEC 60942:2017 (#76)
* feat: update calibrator validation to IEC 60942:2017 (Ed. 4)
The 2017 edition changes the short-term level fluctuation method (5.3.3):
|max - mean| and |min - mean| against the mean F-time-weighted level, and
tightens the class 1 limit in 160-1250 Hz from 0.10 dB (2003 Table 1) to
0.07 dB (2017 Table 2), with relaxed limits at low frequencies where the
F time-weighting itself ripples. calculate_sensitivity() gains a
frequency= parameter selecting the Table 2 row; max_fluctuation_db=None
now resolves the class 1 limit automatically.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: G frequency weighting for infrasound (ISO 7196:1995)
WeightingFilter/weighting_filter accept curve='G': four zeros at the
origin and the four complex pole pairs of ISO 7196 Table 1 (p. 2),
normalized to 0 dB at 10 Hz per clause 4, bilinear-mapped (no
oversampling needed: the curve acts on 0.25-315 Hz where the plain
design is already exact). CI verifies the response against every
Table 2 nominal value at the exact base-10 third-octave frequencies
(+-0.3 dB) plus the 12 and 24 dB/octave slopes. sel()/ln_levels()
accept 'G' transparently. New docs section EN/ES with an autogenerated
figure (light+dark) overlaying the Table 2 nominals.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 226:2023 normal equal-loudness-level contours
equal_loudness_contour(phon) implements Formula (1) at the 29 preferred
third-octave frequencies of Table 1 (transcribed from the official PDF,
p. 4); loudness_level(spl, frequency) is the exact inverse (Formula 2);
hearing_threshold() exposes the T_f column. Validity enforced per clause
4.1 (20-90 phon, 80 above 4 kHz) and no interpolation between tabulated
frequencies (the standard defines none). Verified in CI against spot
values of the informative Annex B tables B.1/B.2 (+-0.05 dB/phon) plus
the 1 kHz identity and full round-trip. Docs EN/ES with the classic
contour-family figure (light+dark).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: prominent discrete tones - TNR and PR per ECMA-418-1:2024
tone_to_noise_ratio() implements clause 11 (Hann/RMS-averaged FFT, tone
band above the connecting line per Formula 9, masking noise rescaled to
the critical bandwidth per Formula 10, proximate-tone combination per
clause 11.6 Formulae 14-16) and prominence_ratio() implements clause 12
(middle band vs contiguous bands with the fitted Table 2/3 edges of
Formulae 21-22, the 20 Hz-truncated 100 Hz-rescaled lower band of
Formula 24 below 171.4 Hz). Both return a ToneAssessment with the
frequency-dependent prominence criteria (Formulae 12-13 / 25-26).
Critical bands per clause 10 Formulae 2-8. Verified against every
worked example printed in the standard (dfc, band edges, proximity
spacing) and against analytic tones-in-white-noise. Note: the inline
condition printed next to Formula (23) contradicts the clause 12.5
prose (typo in the standard); the prose governs.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: environmental noise descriptors per ISO 1996-1:2016
lden() (3.6.4: +5 dB evening / +10 dB night, default 12/4/8 h periods,
adjustable per country), ldn() (3.6.5, defaults 15/9 h) and
composite_rating_level() (6.5 Formulae 5-6: arbitrary periods with
source/character adjustments, e.g. Table A.1). All reduce to the same
composite form and are verified against hand-computed formula values,
the constant-level analytic offset and period-sum validation.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: changelog for the advanced metrology feature set
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: address advanced-metrology review feedback
- calibration: IEC 60942:2017 Table 2 row boundaries corrected (160 Hz
belongs to the 0.07 dB row, 63 Hz to the 0.20 dB row) with a boundary
regression test
- tonality: tone-band edge walk is safe when the peak sits at a spectrum
boundary; _band_power raises a clear ValueError when the resolution
leaves a band empty (instead of dividing by zero); _fitted_edge clips
marginally out-of-range peaks to the table span
- environmental: composite_rating_level materializes its input (safe for
generators) and rejects an empty period list
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: address second review round
- changelog/docstring wording: the two deviations are each compared
against the limit (not a ratio); 0.07 dB applies at and above 160 Hz
- environmental: periods accepts any Iterable (matches the generator
support and test)
- loudness_contours: document that the 1e-6 relative tolerance only
absorbs float representation error and cannot cross table rows
- tonality: validate resolution_hz > 0 and tone_freq > 0 up front
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: create diagram output dir, hook generate_diagrams into make graphs
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: fourth review round - validation and boundary wording
- composite_rating_level rejects non-finite period durations
- _averaged_spectrum raises a clear error for absurdly coarse
resolution_hz (fewer than 16 samples per segment)
- calibration docs/docstrings state the exact Table 2 boundaries
(0.20 dB at or below 63 Hz; note: the 160 Hz code boundary was
already correct from the previous round)
- weighting page frontmatter mentions G (ISO 7196)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: scope the class 1 HF-accuracy claim to A/C/Z, credit ISO 7196 for G
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 1: hard bugs in docs, figures and plotting (#108)
* fix: first pass of audit findings (docs, figures, plotting)
Documentation:
- fix the Spanish filter-figure regression: _showfilter gains a close
flag and the generator saves through themed_path after drawing, so the
translation pass runs on the finished figure; restore the two
_ES_EXACT keys removed in #82 (they are emitted by filter_design, not
by the script)
- repair the broken building-acoustics.md link in the enclosed-space
guide (the repo split lives in room-acoustics.md)
- make the multiple-shock and intensity snippets self-contained: define
az/fs with a synthetic shock train (verified outputs 20.94 m/s2,
R=0.46, probability 0.03) and import numpy with stated outputs
(F2=3.41, Ld=8.0), in the repo doc and both site languages
- decimal points in the English Formula texts (1.07, 55.3) that had
kept the Spanish comma
Figures:
- stop drawing data series in the grid colour (invisible on light
backgrounds): time-weighting input burst, hearing-threshold 20 yr and
NIPTS 10 yr curves, and the unweighted/partial bars now use a visible
neutral grey; regenerate the 15 affected figure sets
Plotting layer:
- plot_facade_insulation forwards user kwargs to the primary D2m,nT
curve only, so label=/color= no longer raise or merge the four curves;
the kwargs-forwarding test now covers the facade plot
- harden three edge cases: all-masked SII (zero contribution no longer
divides 0/0), empty per-impulse prominence, and nearest-band lookup
for the NC governing marker instead of float equality
- sharpness normalization sanity guards raise RuntimeError instead of
AssertionError
* refactor: address review feedback on the NC marker and facade test
- plot_noise_criterion: pick the nearest valid (non-NaN) band and place
the governing marker on that band's frequency so x and y stay paired;
skip the marker if every level is NaN (Copilot)
- add an explicit regression test for plot_facade_insulation(label=...),
which used to raise TypeError (Copilot)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4a: concept-based names for the four unpublished modules (#111)
* refactor: concept-based names for the four unpublished modules
Audit batch 4a — the four modules named after standard numbers were all
merged after v3.0.0 and never published, so they rename cleanly (no
deprecation shims), aligned with their documentation pages:
- iso1999 -> noise_induced_hearing_loss
- iso2631_5 -> multiple_shock_vibration
- ntacou112 -> impulse_prominence
- en12354_6 -> enclosed_space_absorption
- class ImpulseProminence -> ImpulseProminenceResult
Everything that referenced the old module paths moves with them: package
imports/__all__, the plotting layer (including plot_en12354_6 ->
plot_enclosed_space_absorption), the test files (1:1 names, history
preserved), the conformance checks and the figure/diagram generator
functions (generate_nihl -> generate_noise_induced_hearing_loss for
consistency). Committed image basenames stay unchanged (published docs
link them).
CONTRIBUTING.md gains the validated Naming Conventions section (per-group
table + deprecation mechanics: NEP 23-format DeprecationWarning, PEP 562
module __getattr__ shims, the sklearn deprecated-kwarg sentinel, removal
only in majors) so the drift that produced the standard-number names
cannot recur.
* docs: align the deprecation policy with the implemented shims
- CONTRIBUTING: the stacklevel rule now says what it is for (point at
the caller's line: 2 direct, 3 via a shared helper) instead of a
literal that contradicted the existing helper-based shims (CodeRabbit)
- the insulation_* deprecation messages carry the NEP 23 version
metadata (deprecated since 3.1, removal in 4.0)
Gemini's FutureWarning suggestion is declined again: the ecosystem
research (NEP 23, scipy) settles DeprecationWarning for renames;
FutureWarning is reserved for behavior changes.
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Advanced metrology: G-weighting, ISO 226 contours, ECMA-418-1 tonality, ISO 1996 Lden, IEC 60942:2017 (#76)
* feat: update calibrator validation to IEC 60942:2017 (Ed. 4)
The 2017 edition changes the short-term level fluctuation method (5.3.3):
|max - mean| and |min - mean| against the mean F-time-weighted level, and
tightens the class 1 limit in 160-1250 Hz from 0.10 dB (2003 Table 1) to
0.07 dB (2017 Table 2), with relaxed limits at low frequencies where the
F time-weighting itself ripples. calculate_sensitivity() gains a
frequency= parameter selecting the Table 2 row; max_fluctuation_db=None
now resolves the class 1 limit automatically.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: G frequency weighting for infrasound (ISO 7196:1995)
WeightingFilter/weighting_filter accept curve='G': four zeros at the
origin and the four complex pole pairs of ISO 7196 Table 1 (p. 2),
normalized to 0 dB at 10 Hz per clause 4, bilinear-mapped (no
oversampling needed: the curve acts on 0.25-315 Hz where the plain
design is already exact). CI verifies the response against every
Table 2 nominal value at the exact base-10 third-octave frequencies
(+-0.3 dB) plus the 12 and 24 dB/octave slopes. sel()/ln_levels()
accept 'G' transparently. New docs section EN/ES with an autogenerated
figure (light+dark) overlaying the Table 2 nominals.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 226:2023 normal equal-loudness-level contours
equal_loudness_contour(phon) implements Formula (1) at the 29 preferred
third-octave frequencies of Table 1 (transcribed from the official PDF,
p. 4); loudness_level(spl, frequency) is the exact inverse (Formula 2);
hearing_threshold() exposes the T_f column. Validity enforced per clause
4.1 (20-90 phon, 80 above 4 kHz) and no interpolation between tabulated
frequencies (the standard defines none). Verified in CI against spot
values of the informative Annex B tables B.1/B.2 (+-0.05 dB/phon) plus
the 1 kHz identity and full round-trip. Docs EN/ES with the classic
contour-family figure (light+dark).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: prominent discrete tones - TNR and PR per ECMA-418-1:2024
tone_to_noise_ratio() implements clause 11 (Hann/RMS-averaged FFT, tone
band above the connecting line per Formula 9, masking noise rescaled to
the critical bandwidth per Formula 10, proximate-tone combination per
clause 11.6 Formulae 14-16) and prominence_ratio() implements clause 12
(middle band vs contiguous bands with the fitted Table 2/3 edges of
Formulae 21-22, the 20 Hz-truncated 100 Hz-rescaled lower band of
Formula 24 below 171.4 Hz). Both return a ToneAssessment with the
frequency-dependent prominence criteria (Formulae 12-13 / 25-26).
Critical bands per clause 10 Formulae 2-8. Verified against every
worked example printed in the standard (dfc, band edges, proximity
spacing) and against analytic tones-in-white-noise. Note: the inline
condition printed next to Formula (23) contradicts the clause 12.5
prose (typo in the standard); the prose governs.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: environmental noise descriptors per ISO 1996-1:2016
lden() (3.6.4: +5 dB evening / +10 dB night, default 12/4/8 h periods,
adjustable per country), ldn() (3.6.5, defaults 15/9 h) and
composite_rating_level() (6.5 Formulae 5-6: arbitrary periods with
source/character adjustments, e.g. Table A.1). All reduce to the same
composite form and are verified against hand-computed formula values,
the constant-level analytic offset and period-sum validation.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: changelog for the advanced metrology feature set
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: address advanced-metrology review feedback
- calibration: IEC 60942:2017 Table 2 row boundaries corrected (160 Hz
belongs to the 0.07 dB row, 63 Hz to the 0.20 dB row) with a boundary
regression test
- tonality: tone-band edge walk is safe when the peak sits at a spectrum
boundary; _band_power raises a clear ValueError when the resolution
leaves a band empty (instead of dividing by zero); _fitted_edge clips
marginally out-of-range peaks to the table span
- environmental: composite_rating_level materializes its input (safe for
generators) and rejects an empty period list
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: address second review round
- changelog/docstring wording: the two deviations are each compared
against the limit (not a ratio); 0.07 dB applies at and above 160 Hz
- environmental: periods accepts any Iterable (matches the generator
support and test)
- loudness_contours: document that the 1e-6 relative tolerance only
absorbs float representation error and cannot cross table rows
- tonality: validate resolution_hz > 0 and tone_freq > 0 up front
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: create diagram output dir, hook generate_diagrams into make graphs
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: fourth review round - validation and boundary wording
- composite_rating_level rejects non-finite period durations
- _averaged_spectrum raises a clear error for absurdly coarse
resolution_hz (fewer than 16 samples per segment)
- calibration docs/docstrings state the exact Table 2 boundaries
(0.20 dB at or below 63 Hz; note: the 160 Hz code boundary was
already correct from the previous round)
- weighting page frontmatter mentions G (ISO 7196)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: scope the class 1 HF-accuracy claim to A/C/Z, credit ISO 7196 for G
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Room and building acoustics: ISO 18233, ISO 3382-1/2/3, ISO 16283-1 + ISO 717-1 (#81)
* feat: ISO 18233 sweep/MLS impulse-response acquisition
Add src/phonometry/room_ir.py implementing the ISO 18233:2006
deterministic-excitation IR front end: exponential sine sweep with exact
analytic phase (Annex B), linear spectral-division deconvolution with a
Farina inverse-filter option for harmonic separation (B.5), and
maximum-length-sequence generation (LFSR, orders 2-20) with circular
cross-correlation recovery (Annex A).
Validated against closed forms: known IIR bandpass recovered within 0.1 dB
in band (sweep and MLS), ideal chain to a band-limited delta, +3 dB SNR per
sweep-duration doubling (B.6), and all MLS orders verified as true
maximum-length sequences (autocorrelation L / -1).
433 passed, 12 skipped; ruff, mypy --strict and bandit clean.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 3382 room acoustic parameters from impulse responses
Add src/phonometry/room_acoustics.py implementing ISO 3382-1:2009 and
ISO 3382-2:2008 analysis of measured impulse responses:
- decay_curve(): Schroeder backward integration of the squared IR
(5.3.3, Eq. 1) with background-noise truncation at the noise/slope
crossing and exponential tail compensation (Eq. 3), broadband or per
IEC 61260 fractional-octave band.
- room_parameters(): per-band EDT (0/-10 dB, A.2.2), T20 (-5/-25 dB)
and T30 (-5/-35 dB) by least-squares fits (ISO 3382-2 Annex C),
clarity C50/C80 (Eq. A.10), definition D50 (Eq. A.11) and centre
time Ts (Eq. A.13), octave bands 125 Hz-4 kHz by default with a
one-third-octave option and a broadband mode.
- Validity flags per the 5.3.3 dynamic-range criterion (noise at least
evaluation range + 15 dB below the IR maximum: 25/35/45 dB) plus the
Annex B curvature indicator C = 100*(T30/T20 - 1).
Tests validate against closed forms for exponential decays (EDT = T20 =
T30 = T within 1 %; C_te = 10*lg(exp(13.8155*te/T) - 1); D50 =
1 - exp(-0.6908/T); Ts = T/13.8155), the exact C50/D50 relation
(Eq. A.12), double-slope decays (EDT < T20 < T30) and noise-driven
validity-flag behaviour, with tolerances far below the Table A.1 JNDs.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* chore: move figure/diagram generators to scripts/
generate_graphs.py and generate_diagrams.py join benchmark_filters.py
and gen_llms.py in scripts/, where dev tooling already lives. Updated
the Makefile graphs target, the sys.path bootstrap in the graph guard
tests and in generate_graphs.py itself (src/ is now one level up), the
CONTRIBUTING instructions and the theme-images.css pointer. Verified:
module loads from the new location and regenerating the SVG diagrams
produces byte-identical output.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 3382-3 open-plan office spatial metrics
Add open_plan_metrics() computing the ISO 3382-3:2012 single-number
quantities from a line of workstation measurements: spatial decay rate
D2,S and nominal speech level Lp,A,S,4m (Clause 6.2, Eq.5; 2-16 m
positions on a log-distance regression) and distraction/privacy
distances rD/rP (Clause 6.3; STI-vs-distance linear regression crossing
0,50 and 0,20). Returns a frozen OpenPlanResult; validates the minimum
of four positions (5.2.2) and equal array lengths.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: ISO 16283-1 field insulation and ISO 717-1 weighted ratings
Add phonometry.insulation implementing field airborne sound insulation
(ISO 16283-1:2014) and single-number weighted ratings with C/Ctr
(ISO 717-1):
- airborne_insulation: per-band level difference D (Formula (1)),
standardized level difference DnT = D + 10 lg(T/T0) (Formula (2)) and
apparent sound reduction index R' = D + 10 lg(S/A), A = 0,16 V/T
(Formula (4)/(5)); energy-averages microphone positions (Formula (9)).
- weighted_rating: reference-curve shifting method (Clause 4.4, Table 3)
with the 32,0/10,0 dB unfavourable-deviation bound, plus C/Ctr from the
Table 4 spectra (Clause 4.5). Reference values, spectra and method are
identical in the 2013 and 2020 editions.
- energy_average_level: ISO 16283-1 Formula (9) helper.
Verified against the ISO 717-1 Annex C worked example (Rw(C;Ctr) =
30(-2;-3), unfavourable sum 31,8 dB) and exact-bound / tipping edge
cases. 20 new tests; make check green (484 passed, 12 skipped).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: room & building acoustics guide, theory, API and landing (EN)
New "Room & building acoustics" guide (docs/ + Starlight twin) covering the
full measurement chain: ISO 18233 swept-sine/MLS impulse-response acquisition,
ISO 3382-1/2 decay analysis and room parameters (EDT/T20/T30/C50/C80/D50/Ts),
ISO 3382-3 open-plan speech metrics, and ISO 16283-1 / ISO 717-1 field
insulation with weighted ratings. Adds the matching theory section (Schroeder
integration, regression windows, C/D/Ts, D2,S, DnT/R', reference-curve method),
API-reference rows for all new public names, sidebar entry, README highlight +
docs row, EN landing card, CHANGELOG entries, docs index row, and regenerated
llms-full.txt. All snippets validated; site build and make check green.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: Schroeder, ISO 717-1 rating and insulation-setup figures
Add three room/building-acoustics documentation figure sets (each in
en/es x light/dark):
- schroeder_decay: synthetic IR, Schroeder backward integration with
EDT/T20/T30 regressions and evaluation ranges (ISO 3382); annotated
values match room_parameters.
- insulation_rating: ISO 717-1 Annex C example with shifted reference
curve, unfavourable-deviation shading and Rw read at 500 Hz; Rw, C,
Ctr and the unfavourable sum come from weighted_rating.
- diagram_insulation_setup: ISO 16283-1 airborne setup plan view with
the normative minimum distances (clauses 7.6 and 7.2.2).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: gemelas ES de acústica de salas y edificación
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: terminología UNE — ponderación temporal en lugar de balística (ES)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: markdown/README parity with the site + llms guide coverage
Scrub GitHub-unsafe display math (\, thin-spaces and escaped \{ \}) from
docs/intensity.md and docs/psychoacoustics.md — the only two guides that
missed the GitHub-safe math conversion of PRs #78/#79 — matching the safe
forms already used in docs/theory.md. Align calibration's sensitivity
symbol/formula to the site ($S$, single-line \qquad).
Extend scripts/gen_llms.py PAGES with the three omitted guides
(psychoacoustics, intensity, room-acoustics) and regenerate llms.txt /
llms-full.txt so AI-facing artifacts cover all 14 docs pages.
The guides/references were otherwise already in parity (didactic code
comments, theory sections, tables, and figures from PRs #77/#80 all
present); docs/README index and README highlights/table verified complete.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: final-review findings — open_plan validation, limits rename, Farina caveat, MLS averaging test
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: ISO 18233 measurement-chain diagram and guide fixes
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: fix sweep_signal cross-reference in Farina caveat
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: PR 81 review round 1 — inverse-filter guards, truncation threshold, IR input validation, docs pipeline wording
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: blank lines around CONTRIBUTING fence (MD031)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit-driven accuracy, robustness and didactic improvements across the library (#82)
* fix: audit wave A — inter-sample LCpeak, cheby2 class-1 default, 144 kHz weighting target
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: audit wave A — decay validity thresholds, variant sharpness anchors, N5 phase, STIPA warning, Farina guard
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: audit wave B — self-contained snippets, tables, sharpness/open-plan figures, orphans
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: audit wave C — remaining minors and optimizations across the library
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: document the audit-wave parameters across guides and API tables
Cover the public parameters added in the audit fix waves across all three
documentation trees (docs/, site EN, site ES):
- lc_peak(..., oversample=8): inter-sample peak recovery (levels guide + API)
- calculate_sensitivity(..., narrowband=False): coherent tone estimator
(calibration guide + API)
- sound_intensity(..., bias_correct=False): finite-difference bias correction
(intensity guide + API)
- room_parameters/decay_curve(..., zero_phase=False): 125 Hz short-T bias
(room-acoustics guide + API)
- OctaveFilterBank/octavefilter attenuation default 60 -> 72 and cheby2
class-1 note (filter-banks guide + API)
- STIPA < 15 s UserWarning (psychoacoustics guide + API)
Also refresh dependent behaviour notes: ln_levels attack skip 2*tau -> 5*tau,
T20/T30 validity thresholds 35/45 -> 46/54 dB, and the zero-phase broadband
~0.2-0.3 dB band-level caveat. Regenerated llms-full.txt.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: truthfulness fixes from the final audit-branch review
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: 2000 Hz, not 2 ms, in the N5/N10 docstring
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: PR 82 review round 1 — bias-correction cutoff, parabolic-peak guard, complexity, snippet self-containment
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Docs usability: measurement-role snippet clarity, one-line result plots, responsive figures (#86)
* fix: responsive figure sizing — full-width on mobile, 92% plots on desktop (plan 16 T4)
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: snippet clarity wave — recording/excitation convention (plan 16 T1)
Apply the recording/excitation naming convention from the P16 audit across
the calibration, intensity, block-processing, time-weighting, levels,
weighting and room-acoustics guides (docs/ + EN guides + ES guides).
- calibration: ref_signal->calibrator_recording, signal->recording (J1 cascade)
- intensity: probe-recording synth + swap-in disclosure on p1/p2
- block-processing / time-weighting: audio_blocks provenance comments
- levels / time-weighting / weighting: signal->recording, provenance upgraded to convention
- room-acoustics: play/record framing on sweep/recorded; synthetic-IR stand-in note
EN docs/guides kept code-identical; ES mirrored with UNE wording.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* feat: one-line canonical plots on result objects (plan 16 T2)
Add a thin plot(ax=None, **kwargs) method to each result dataclass that
renders the essence of its guide's canonical figure in one line, following
the sklearn/statsmodels/librosa pattern. matplotlib stays a soft dependency:
importing phonometry and computing works without it; .plot() raises a clear
ImportError with install guidance. Rendering lives in a new lazy _plotting
module; dataclass methods are thin delegates.
Covers ZwickerLoudness, STIResult, WeightedRatingResult/ImpactRatingResult,
RoomAcousticsResult, SoundPowerResult/ReverberationSoundPowerResult/
SoundPowerIntensityResult, IntensityResult and a new frozen DecayCurve
(returned by decay_curve, tuple-unpackable for backward compat). Rating
results gain band_centers/measured/shifted_reference fields for the figure.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: plot kwargs forwarding, deterministic invalid-band test, octave-impact annotation
- _plot_rating now accepts **kwargs and forwards to the measured curve, so
result.plot(linewidth=2) no longer raises TypeError; parametrized test
covers every public .plot() forwarding a benign kwarg to its primary artist.
- Replace skip-if-all-valid room-acoustics invalid-band test with a directly
constructed RoomAcousticsResult (500 Hz band flagged invalid); assert exactly
the flagged bars are hatched and greyed.
- plot_impact_rating keeps the shifted-reference curve normatively honest
(ref - shift) and marks/annotates the 500 Hz read value with the ISO 717-2
Clause 4.3.2 -5 dB octave rule instead of distorting the curve.
- Move _bar_width next to its only consumer, plot_intensity.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: .plot() one-liners and figure-code collapsibles (plan 16 T3)
Add one-line res.plot() mentions to every guide section whose result type
gained .plot() in T2, and figure-code collapsibles (both the one-liner and
the manual matplotlib path) under the five .plot()-backed data figures.
Document .plot() availability and the DecayCurve return type in the API
reference and CHANGELOG. EN docs + EN/ES site; llms-full.txt regenerated.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: collapsibles for STI-vs-T60 and open-plan figures
Controller follow-up to plan 16 T3: the two figures are reproducible with
public API only. STI-vs-T60 sweeps sti_from_impulse_response over synthetic
exponential IRs at a 10-point T60 grid; the open-plan collapsible rebuilds
the D2,S regression and rD/rP crossings from the OpenPlanResult fields.
EN docs + EN/ES site; executed on Agg; llms-full.txt regenerated.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: final-review polish — result-field docs, comment hygiene, naming
Document band_centers/measured/shifted_reference on WeightedRatingResult
and ImpactRatingResult (CHANGELOG + EN/ES API tables), strip internal plan
tags from theme-images.css and test_result_plots.py, note that [plot] also
powers result .plot() methods, tighten the plot_zwicker_loudness docstring
to say the two-panel layout only occurs when ax is None, sentence-case the
intensity provenance comments, and rename the shadowed impact rating var to
res_imp on the room-acoustics pages.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* fix: PR 86 review round 1 — log-axis bars, style kwargs overrides, snippet physics and notation
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
Audit pass 3: shared validation, energy math, types and warning base (#110)
* refactor: shared validation, energy-math, types and warning base
Audit batch 3 — retire the per-module reinventions of the same private
infrastructure, with numerically identical behavior (the full suite's
pinned worked-example values and the byte-stable conformance report are
unchanged):
- _validation.py grows require_positive / require_non_negative /
require_fraction / require_choice (all NaN-rejecting, quoted-parameter
messages); en12354_6 and iso2631_5 drop their local equivalents
- new _levels_math.py (energy_mean / energy_sum / weighted_energy_mean)
replaces the two duplicated _energy_average helpers and the inline
energy combinations in sound_power, sound_power_intensity,
sound_power_reverberation, occupational_exposure, intensity and
insulation; the weighted denominator respects the reduction axis so
axis-varying weights stay correct
- new _types.py (Real alias, as_float_or_array) replaces four duplicate
alias definitions and thirteen copies of the scalar-or-array return
idiom
- new _warnings.py with PhonometryWarning: all eleven warning classes
rebase onto it so users can filter the whole library at once; bare
UserWarning sites gain proper categories (FilterBankWarning,
STIWarning, TonalityWarning, ImpulseResponseWarning) and the
category-less frequencies warning is fixed
- the byte-identical _check_grade and _validate_conditions duplicates
are merged into single definitions
Deliberately NOT migrated (subtly different math, noted in the audit):
the SII masking composition, the NT ACOU 112 reference-time-normalized
rating and the exposure-weighted sum in occupational_exposure.
* refactor: address review feedback on the shared helpers
- the scalar validators reject infinities too (math.isfinite), matching
their own 'finite' docstrings and the isfinite validators elsewhere
(Copilot)
- as_float_or_array accepts scalars via np.ndim instead of assuming an
ndarray (Gemini)
- energy_mean computes through np.mean, bit-identical to sum/n at every
call-site shape (verified) and robust to tuple axes at runtime
(Gemini)
Audit pass 4b: deprecation-cycle renames of published API (#112)
* refactor: deprecation-cycle renames of published API
Audit batch 4b — the published names that violate the naming convention
gain canonical replacements, with the old names working for one cycle
(NEP 23 DeprecationWarning: deprecated since 3.1, removal in 4.0):
- module loudness -> loudness_zwicker, with a PEP 562 __getattr__ shim
(plain 'import phonometry' emits no warning)
- renamed keywords via the sklearn sentinel, positional compatibility
preserved: road_absorption sample_rate -> fs; outdoor_propagation
humidity -> relative_humidity; sound_power room_volume -> volume
- legacy PyOctaveBand names normalized: octave_filter,
nominal_frequencies, normalized_frequencies and sensitivity are the
canonical implementations; octavefilter, getansifrequencies,
normalizedfreq and calculate_sensitivity delegate with a warning via
the shared _warn_renamed helper
- public string enums annotated with Literal (sex, field, presentation,
method) - annotation only, runtime validation untouched
Tests, scripts, docs and site sweep to the canonical names (~310
occurrences in 46 files); tests/test_deprecated_aliases.py pins every
alias with pytest.warns plus delegation equality and the both-given /
missing-required error paths.
* fix: address review feedback on the deprecation batch
- an explicit room_volume=None (the old default) no longer trips the
deprecation warning; only a real value through the alias warns, with
a regression test (Copilot)
- the calibration snippets stop shadowing the imported sensitivity()
with their result variable, in the repo doc and both site languages
(Copilot)
FutureWarning declined again with the rationale posted on the PR:
DeprecationWarning is the ecosystem norm for renames (NEP 23, scipy),
now codified in CONTRIBUTING.
* fix: second-pass review feedback on the deprecation batch
- loudness_zwicker validates calibration_factor through the shared
require_positive, closing the NaN/inf-permeable check (CodeRabbit)
- test names catch up with the octave_filter and sensitivity renames
(CodeRabbit)
- markdownlint MD022 blank line before the ES calibration heading
(CodeRabbit)
feat: measurement uncertainty (GUM ISO/IEC Guide 98-3:2008 + Monte Carlo Supplement 1) (#102)
Adds a `phonometry.uncertainty` module implementing the two propagation methods of the GUM:
* Law of propagation of uncertainty (ISO/IEC Guide 98-3:2008, clause 5) — `combine_uncertainty` builds the combined standard uncertainty from central-difference sensitivity coefficients, with optional input correlations (validated for shape, symmetry, unit diagonal and positive-semidefiniteness), Welch-Satterthwaite effective degrees of freedom (Annex G.4) and the expanded uncertainty U = k*uc (clause 6).
* Monte Carlo method (ISO/IEC Guide 98-3-1:2008, Supplement 1, clause 7) — `monte_carlo` propagates the input PDFs and returns the estimate, its standard uncertainty and the probabilistically symmetric coverage interval (clause 7.7).
Type B quantities from a half-width: `rectangular` (a/sqrt3), `triangular` (a/sqrt6), `u_shaped` (a/sqrt2). Results expose `.expanded()` and `.plot()` (uncertainty budget).
Validated against the Guides' worked examples: additive uc=2.0 (Suppl. 1, 9.2), coverage factor k=2.92 at p=0.99/v=16 (Table G.2), Welch-Satterthwaite v_eff=40 (Annex G.4), Monte Carlo interval [-3.88, 3.88] (Suppl. 1, 9.2.3). Conformance 79/79.
Includes the budget/Monte-Carlo figure, the two-lane GUM-vs-Monte-Carlo diagram (EN/ES, light/dark), the repo doc and the EN/ES site guides under a new "Metrology & uncertainty" section.