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.