room.auditorium
La referencia de la API se publica en inglés en los dos idiomas: se genera a partir de los docstrings del código, que son su texto original.
Auditorium measures derived from impulse responses (ISO 3382-1:2009, Annex A).
Annex A is informative. Nothing about the sound strength is normative in ISO 3382-1:2009: not Equations (A.1) to (A.9), not the 1 dB just-noticeable difference of Table A.1, not the typical range. What the annex fixes is the definition everyone quotes, and that is what this module implements.
Reverberation time says what the room does to energy over time and nothing about how loud the room is. Sound strength, G, is the quantity that does: the energy of the measured impulse response against the energy the same source puts out at 10 m in a free field (A.2.1, Equation (A.1)). It is one of the two measures in Table A.1 that need a calibrated source, the other being the late lateral sound level of A.2.5, which is referred to the same place; and it is the reason the annex spends four equations on how to obtain that free-field reference when there is no anechoic room 10 m across to measure it in.
The three printed routes to the reference are all here, and they are routes to the same number:
- measure at a distance
d >= 3 mand correct by the inverse square law, Equations (A.4) and (A.8); - measure the source in a reverberation room of known absorption area, Equation (A.5);
- take the source’s sound power level and subtract the free-field spread, Equation (A.9).
The last two carry printed integers, 37 dB and 31 dB, and both are the correctly rounded value of a closed form: is 37,0127 dB and is 30,9921 dB. Rounded to whole decibels they land 6 dB apart, where the exact offsets are dB apart, so the reverberation-room route and the sound-power route cannot agree to better than 0,0206 dB. That is 2 % of the 1 dB just-noticeable difference Table A.1 prints for G, and this module reproduces the standard’s integers rather than the closed forms: a library that quietly used 30,9921 dB would disagree with every hand calculation done from the printed page.
Both closed forms hold at a characteristic impedance of exactly , which is the value that makes the three reference quantities consistent: pW, the reference sound power. Neither equation prints that caveat. Air at 20 degrees and 101,325 kPa is nearer , worth 0,14 dB, an order of magnitude more than either rounding: the offsets are a convention of the decibel scales, not a property of the air in the hall, and this module does not make them follow the weather.
Auto-generated from the source docstrings by
scripts/generate_api_docs.py(make api-docs). Do not edit by hand.
AuditoriumQuantity
Section titled “AuditoriumQuantity”AuditoriumQuantity( symbol: str, aspect: str, averaging_bands_hz: tuple[float, ...], just_noticeable_difference: float | None, *, relative_jnd: bool, typical_range: tuple[float, float], energy_averaged: bool, unit: str,)One row of ISO 3382-1:2009, Table A.1.
symbol is the quantity as the table prints it, aspect the
subjective listener aspect it is grouped under, and
averaging_bands_hz the octave bands its single number is the average
over, which is not the same set for every row: five quantities
average two bands and two average four.
just_noticeable_difference is None for the late lateral sound
level, whose JND the table prints as “Not known”; it is a fraction
rather than an absolute difference when relative_jnd is True, which
is only the early decay time’s “Rel. 5 %”. energy_averaged is True
only for the late lateral level, which footnote a sends to
Equation (A.17) while every other row is averaged arithmetically.
typical_range is the pair the table prints, and footnote b conditions
it: frequency-averaged values at single positions in unoccupied concert
and multi-purpose halls up to 25 000 m³. It is not a range for one band,
for an occupied hall, or for a spatial average.
AuditoriumWarning
Section titled “AuditoriumWarning”A measurement outside the conditions ISO 3382-1:2009 prints for it.
DIFFUSE_FIELD_REFERENCE_OFFSET_DB
Section titled “DIFFUSE_FIELD_REFERENCE_OFFSET_DB”Constant (float).
DIFFUSE_FIELD_REFERENCE_OFFSET_DB = 37.0DIRECTIVITY_ARC_DEG
Section titled “DIRECTIVITY_ARC_DEG”Constant (float).
DIRECTIVITY_ARC_DEG = 30.0directivity_energy_average
Section titled “directivity_energy_average”directivity_energy_average( levels: ArrayLike, axis: int = -1,) -> NDArray[np.float64] | floatAverage a free-field measurement over bearings around the source.
The note under ISO 3382-1:2009, Equation (A.4) asks for the free-field reference to be measured all the way round the source and combined as an energy mean, so that the source’s own directivity does not decide the reference level:
An arithmetic mean of the decibel values is a different number, and a lower one, for any source that is not omnidirectional.
The note asks for the measurement “at every 12,5 degrees”, and 12,5
degrees does not divide 360: 28 steps stop at 350 degrees and 29
overshoot to 362,5. There is no set of bearings that follows the
printed instruction literally, so what this function checks is what
the instruction can mean, a uniform sampling of the full turn no
coarser than the printed step: N >= 29 bearings, 360/N degrees
apart. The 5 degree survey of 4.2.1, which the same standard uses for
the source directivity of Table 1, does divide 360 exactly, into 72.
The mean itself is the one
phonometry.building.energy_average_level computes; this
function adds the bearing count the note constrains, and averages one
band per row when it is handed a two-dimensional survey.
Parameters
| Name | Description |
|---|---|
levels | The levels measured at the bearings, in dB, one per bearing, evenly spaced around the source. A two-dimensional array averages one band per row (or per column, see axis), which is the shape the rest of this module works in. |
axis | Axis the bearings run along; the last by default. |
Returns: Their energy mean, in dB: a float for a single turn, an array with axis removed for several.
Raises
| Exception | When |
|---|---|
| ValueError | If fewer than ceil(360 / 12,5) = 29 bearings lie along axis, or the levels are empty or non-finite. |
DIRECTIVITY_STEP_DEG
Section titled “DIRECTIVITY_STEP_DEG”Constant (float).
DIRECTIVITY_STEP_DEG = 5.0DIRECTIVITY_SURVEY_DISTANCE_M
Section titled “DIRECTIVITY_SURVEY_DISTANCE_M”Constant (float).
DIRECTIVITY_SURVEY_DISTANCE_M = 1.5EARLY_ENERGY_LIMIT_S
Section titled “EARLY_ENERGY_LIMIT_S”Constant (float).
EARLY_ENERGY_LIMIT_S = 0.08early_lateral_energy_fraction
Section titled “early_lateral_energy_fraction”early_lateral_energy_fraction( ir: Signal | list[float] | NDArray[np.float64], lateral_ir: Signal | list[float] | NDArray[np.float64], fs: int | None = None, *, weighting: str = 'squared', limits: tuple[float, float] | None = (125.0, 4000.0), fraction: int = 1,) -> LateralEnergyResultEarly lateral energy fraction of a pair of responses, per band.
ISO 3382-1:2009, Equation (A.14), the share of the first 80 ms that arrives from the side:
and Equation (A.15), the cosine-weighted variant that A.2.4 calls subjectively more accurate:
The modulus in (A.15) is printed and it matters: the figure-of-eight response changes sign with the side a reflection comes from, so without it two mirror-image reflections cancel to zero instead of adding.
The two lower limits differ. The numerator starts at 5 ms because the null of the figure-of-eight microphone is pointed at the source and the 5 ms keeps whatever leaks through it out of the lateral share; the denominator starts at 0 because the direct sound belongs to the total.
Time zero comes from the omnidirectional response. A figure-of-eight
microphone aimed as A.2.4 asks has no direct sound to trigger on, so its
own onset would land on the first strong reflection and shift both
limits by that much. Both integrals here are timed from the direct sound
of ir, band by band.
Parameters
| Name | Description |
|---|---|
ir | Impulse response measured with the omnidirectional microphone at the measurement point (1D). |
lateral_ir | Impulse response measured at the same point with a figure-of-eight microphone whose null points at the source (1D). |
fs | Sample rate in Hz. Required for bare arrays; a Signal brings its own. |
weighting | "squared" for , Equation (A.14), whose contributions vary as the square of the cosine of the angle of incidence; "cosine" for , Equation (A.15), whose contributions vary as the cosine itself. |
limits | (f_min, f_max) band-centre limits in Hz; default the octave bands 125 Hz to 4 kHz. Table A.1 averages this quantity over 125 Hz to 1 kHz. None measures the broadband responses. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). |
Returns: A LateralEnergyResult with one entry per band.
Raises
| Exception | When |
|---|---|
| ValueError | If weighting is not one of LATERAL_WEIGHTINGS, if a response is not one-dimensional or is silent, if the two responses do not split into the same number of bands or are of different lengths, or if they are too short for the 80 ms window. |
EARLY_LATERAL_WINDOW_S
Section titled “EARLY_LATERAL_WINDOW_S”Constant (tuple).
EARLY_LATERAL_WINDOW_S = (0.005, 0.08)EARLY_SUPPORT_WINDOW_S
Section titled “EARLY_SUPPORT_WINDOW_S”Constant (tuple).
EARLY_SUPPORT_WINDOW_S = (0.02, 0.1)free_field_reference_level
Section titled “free_field_reference_level”free_field_reference_level( level: ArrayLike, distance: float,) -> NDArray[np.float64] | floatFree-field level at 10 m from one measured at another distance.
ISO 3382-1:2009, Equations (A.4) and (A.8), which are the same inverse-square correction written once for the exposure level and once for the stationary-source pressure level:
Both are printed for a point “d (>= 3 m) from the source”, far enough
for the free field to have taken over; a shorter distance raises
AuditoriumWarning.
The note under (A.4) adds that the measurement is to be repeated around
the source and energy-averaged, “at every 12,5 degrees”, to average out
the source’s own directivity. Feed this function the averaged level,
not one bearing; directivity_energy_average is that mean, and
its docstring says what the printed step does and does not determine.
Parameters
| Name | Description |
|---|---|
level | The level measured at distance, in dB. Any shape. |
distance | Source-to-microphone distance of that measurement, in metres. |
Returns: The level referred to 10 m, in dB, in the shape of level.
Raises
| Exception | When |
|---|---|
| ValueError | If distance is not a positive, finite length. |
gliding_directivity_deviation
Section titled “gliding_directivity_deviation”gliding_directivity_deviation(levels: ArrayLike) -> NDArray[np.float64]Deviation of each gliding arc from the whole-turn reference (4.2.1).
ISO 3382-1:2009, 4.2.1 qualifies a source by averaging its free-field output over “gliding” 30 degree arcs and comparing each of them with the reference, which is “a 360 degree energetic average in the measurement plane”. Where no turntable is available it asks for measurements every 5 degrees, and for gliding averages “each covering six neighbouring points”, which is 30 degrees of a 72-point survey.
Both averages here are energetic, which is what the printed word makes
of the reference and what the arcs must therefore be for the comparison
to mean anything. The standard does not say so of the arcs, and it does
not say whether the six points of a window lead, trail or straddle their
arc either; the window here starts at each measured bearing and runs
forwards, and it wraps, so a survey of N bearings gives N
deviations.
Parameters
| Name | Description |
|---|---|
levels | Sound pressure levels around the source, in dB, one per bearing, evenly spaced over a full turn. |
Returns: One deviation per bearing, in dB, of the arc that starts there against the whole-turn reference.
Raises
| Exception | When |
|---|---|
| ValueError | If the bearings do not divide the arc a whole number of times, or there are too few of them to make one. |
IACC_EARLY_WINDOW_S
Section titled “IACC_EARLY_WINDOW_S”Constant (tuple).
IACC_EARLY_WINDOW_S = (0.0, 0.08)IACC_JND
Section titled “IACC_JND”Constant (float).
IACC_JND = 0.075IACC_LATE_START_S
Section titled “IACC_LATE_START_S”Constant (float).
IACC_LATE_START_S = 0.08IACC_SEARCH_S
Section titled “IACC_SEARCH_S”Constant (float).
IACC_SEARCH_S = 0.001interaural_cross_correlation
Section titled “interaural_cross_correlation”interaural_cross_correlation( left: Signal | list[float] | NDArray[np.float64], right: Signal | list[float] | NDArray[np.float64], fs: int | None = None, *, window: tuple[float, float | None] = (0.0, None), limits: tuple[float, float] | None = (125.0, 4000.0), fraction: int = 1,) -> InterauralCorrelationResultInteraural cross correlation of a binaural response, per band.
ISO 3382-1:2009, Equation (B.1) defines the normalised function
and Equation (B.2) takes the coefficient from it:
Both the square root and the modulus are printed, and both matter. The root is what bounds the function by one; a text layer that drops it leaves a quantity that is not a correlation at all. The modulus is what makes two anti-phase ears give 1 rather than 0, which is the answer that matches what they describe, two signals as dissimilar as they can be only in sign.
B.4 puts three windows to it. The general form runs from the direct
sound to a time of the order of the reverberation time, which is the
default here; IACC_EARLY_WINDOW_S is the early coefficient and
IACC_LATE_START_S starts the reverberant one. Time zero is the
direct sound, located on the two channels together so that a listener
turned away from the source does not move it.
Parameters
| Name | Description |
|---|---|
left | Impulse response at the entrance to the left ear canal (1D). |
right | Impulse response at the entrance to the right ear canal (1D), of the same length. |
fs | Sample rate in Hz. Required for bare arrays; a Signal brings its own. |
window | (t_1, t_2) in seconds from the direct sound, with t_2 None for the end of the response. |
limits | (f_min, f_max) band-centre limits in Hz; default the octave bands 125 Hz to 4 kHz, which is the range B.4 names. None correlates the broadband responses. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). |
Returns: An InterauralCorrelationResult with one entry per band.
Raises
| Exception | When |
|---|---|
| ValueError | If a response is not one-dimensional or is silent, if the two channels are of different lengths, if the window starts before the direct sound or is empty or reversed, or if a band has no energy inside it. |
InterauralCorrelationResult
Section titled “InterauralCorrelationResult”InterauralCorrelationResult( frequencies: NDArray[np.float64] | None, coefficient: NDArray[np.float64], delay: NDArray[np.float64], lag: NDArray[np.float64], correlation: NDArray[np.float64],)Per-band interaural cross correlation (ISO 3382-1:2009, Annex B).
frequencies holds the exact band centre frequencies in Hz, or is
None for a broadband measurement. coefficient is the IACC of
Equation (B.2), the largest magnitude the normalised correlation
function reaches inside the +/-1 ms search window, and delay the lag
in seconds at which it reaches it: positive when the right ear is the
later of the two, because (B.1) evaluates the right channel at
.
lag and correlation carry the function itself over the search
window, one row per band, so it can be drawn rather than summarised.
B.4 assumes a just-noticeable difference of 0,075.
InterauralCorrelationResult.plot()
Section titled “InterauralCorrelationResult.plot()”InterauralCorrelationResult.plot( ax: Axes | None = None, *, language: str = 'en', **kwargs: Any,) -> AxesPlot the correlation function over the search window, per band.
Requires matplotlib (pip install phonometry[plot]); returns the
Axes.
late_lateral_average
Section titled “late_lateral_average”late_lateral_average(levels: ArrayLike) -> floatFrequency-average the late lateral level over its four octave bands.
ISO 3382-1:2009, Equation (A.17):
The 0,25 is one quarter, so this is an energy mean and four equal band values return that value unchanged. It is the one exception footnote a of Table A.1 makes: every other quantity in that table is averaged arithmetically over its bands, and only is averaged over energy. The four bands are the 125 Hz, 250 Hz, 500 Hz and 1 kHz octaves, in that order.
Parameters
| Name | Description |
|---|---|
levels | The four octave-band values of , in dB, in the order of LATE_LATERAL_AVERAGE_BANDS_HZ. |
Returns: in dB.
Raises
| Exception | When |
|---|---|
| ValueError | If four values are not given, or they are not finite. |
LATE_LATERAL_AVERAGE_BANDS_HZ
Section titled “LATE_LATERAL_AVERAGE_BANDS_HZ”Constant (tuple).
LATE_LATERAL_AVERAGE_BANDS_HZ = (125.0, 250.0, 500.0, 1000.0)late_lateral_sound_level
Section titled “late_lateral_sound_level”late_lateral_sound_level( ir: Signal | list[float] | NDArray[np.float64], lateral_ir: Signal | list[float] | NDArray[np.float64], reference_ir: Signal | list[float] | NDArray[np.float64] | None = None, fs: int | None = None, *, reference_level: ArrayLike | None = None, limits: tuple[float, float] | None = (125.0, 4000.0), fraction: int = 1,) -> LateLateralResultLate lateral sound level of a measured response, per band.
ISO 3382-1:2009, Equation (A.16), the level of the lateral energy that arrives after the early window, against the same free-field reference the sound strength uses:
Where is a fraction and cancels its own
calibration, is a level and does not: it needs the
calibrated omnidirectional source of A.2.1 and a free-field reference,
which reaches this function the same two ways it reaches
sound_strength. It also needs the relative sensitivity of the
two microphones to have been calibrated in a free field (A.3.2).
Time zero comes from the omnidirectional response, for the reason
given under early_lateral_energy_fraction: a figure-of-eight
microphone aimed as A.2.5 asks has no direct sound to trigger on, and an
80 ms boundary placed on its first reflection is not the printed one.
ir supplies that time zero and nothing else.
Parameters
| Name | Description |
|---|---|
ir | Impulse response measured with the omnidirectional microphone at the measurement point (1D), for its direct sound. |
lateral_ir | Impulse response measured at the same point with a figure-of-eight microphone whose null points at the source (1D). |
reference_ir | Impulse response of the same source at 10 m in a free field (1D). Mutually exclusive with reference_level. |
fs | Sample rate in Hz. Required for bare arrays; a Signal brings its own. |
reference_level | The free-field reference exposure level in dB, as a scalar or one value per band. Mutually exclusive with reference_ir. |
limits | (f_min, f_max) band-centre limits in Hz; default the octave bands 125 Hz to 4 kHz. Equation (A.17) averages this quantity over 125 Hz to 1 kHz. None measures the broadband responses. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). |
Returns: A LateLateralResult with one entry per band.
Raises
| Exception | When |
|---|---|
| ValueError | If neither or both reference forms are given, if a response is not one-dimensional or is silent, if the two hall responses are of different lengths, or if they are too short to reach the 80 ms boundary. |
LATE_LATERAL_START_S
Section titled “LATE_LATERAL_START_S”Constant (float).
LATE_LATERAL_START_S = 0.08LATE_SUPPORT_WINDOW_S
Section titled “LATE_SUPPORT_WINDOW_S”Constant (tuple).
LATE_SUPPORT_WINDOW_S = (0.1, 1.0)LateLateralResult
Section titled “LateLateralResult”LateLateralResult( frequencies: NDArray[np.float64] | None, levels: NDArray[np.float64], reference_level: NDArray[np.float64],)Per-band late lateral sound level (ISO 3382-1:2009, A.2.5).
frequencies holds the exact band centre frequencies in Hz, or is
None for a broadband measurement. levels is
in dB (Equation (A.16)) and reference_level the sound
pressure exposure level of the free-field response at 10 m it is
referred to, however that was obtained. Table A.1 gives
a typical range of -14 dB to +1 dB over the 125 Hz to 1 kHz
octave bands and no just-noticeable difference at all: “Not known”.
LateLateralResult.plot()
Section titled “LateLateralResult.plot()”LateLateralResult.plot( ax: Axes | None = None, *, language: str = 'en', **kwargs: Any,) -> AxesPlot the per-band late lateral level against the Table A.1 range.
Requires matplotlib (pip install phonometry[plot]); returns the
Axes.
LATERAL_WEIGHTINGS
Section titled “LATERAL_WEIGHTINGS”Constant (tuple).
LATERAL_WEIGHTINGS = ('squared', 'cosine')LateralEnergyResult
Section titled “LateralEnergyResult”LateralEnergyResult( frequencies: NDArray[np.float64] | None, energy_fraction: NDArray[np.float64], weighting: str,)Per-band early lateral energy fraction (ISO 3382-1:2009, A.2.4).
frequencies holds the exact band centre frequencies in Hz, or is
None for a broadband measurement. energy_fraction is
or depending on
weighting, which is "squared" for Equation (A.14) and
"cosine" for Equation (A.15). Both are dimensionless and Table A.1
gives them a just-noticeable difference of 0,05 and a typical range of
0,05 to 0,35 over the 125 Hz to 1 kHz octave bands.
LateralEnergyResult.plot()
Section titled “LateralEnergyResult.plot()”LateralEnergyResult.plot( ax: Axes | None = None, *, language: str = 'en', **kwargs: Any,) -> AxesPlot the per-band lateral fraction against the Table A.1 range.
Requires matplotlib (pip install phonometry[plot]); returns the
Axes.
MAX_SOURCE_DIRECTIVITY_DEVIATION_DB
Section titled “MAX_SOURCE_DIRECTIVITY_DEVIATION_DB”Constant (mapping).
MAX_SOURCE_DIRECTIVITY_DEVIATION_DB = {125.0: 1.0, 250.0: 1.0, 500.0: 1.0, 1000.0: 3.0, 2000.0: 5.0, 4000.0: 6.0}MAXIMUM_DIRECTIVITY_STEP_DEG
Section titled “MAXIMUM_DIRECTIVITY_STEP_DEG”Constant (float).
MAXIMUM_DIRECTIVITY_STEP_DEG = 12.5MID_FREQUENCY_OCTAVES_HZ
Section titled “MID_FREQUENCY_OCTAVES_HZ”Constant (tuple).
MID_FREQUENCY_OCTAVES_HZ = (500.0, 1000.0)MID_FREQUENCY_THIRD_OCTAVES_HZ
Section titled “MID_FREQUENCY_THIRD_OCTAVES_HZ”Constant (tuple).
MID_FREQUENCY_THIRD_OCTAVES_HZ = (400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0)minimum_receiver_positions
Section titled “minimum_receiver_positions”minimum_receiver_positions(seats: ArrayLike) -> NDArray[np.float64] | floatFewest microphone positions a hall of a given size wants (Table A.2).
ISO 3382-1:2009, Table A.2 prints three pairs, 500 seats to 6 positions, 1 000 to 8 and 2 000 to 10. They lie exactly on a straight line in the logarithm of the seat count, two positions per doubling:
which reproduces all three printed integers to the last bit. A.4 caps what that line may be used for: it asks for “a minimum of between 6 and 10 representative microphone positions”, so the result is clamped to the range the table covers, and this function will not extrapolate a 5 000-seat arena to thirteen positions on the strength of three rows.
A.4 also says the positions are to be evenly distributed over all audience seating areas, and that a hall broken into separate areas such as balconies and under-balcony areas will need more than this.
Parameters
| Name | Description |
|---|---|
seats | The number of seats in the hall. |
Returns: The minimum number of positions, not rounded, clamped to the 6 to 10 the table and A.4 between them authorise.
Raises
| Exception | When |
|---|---|
| ValueError | If a seat count is not a positive, finite number. |
MINIMUM_REFERENCE_DISTANCE_M
Section titled “MINIMUM_REFERENCE_DISTANCE_M”Constant (float).
MINIMUM_REFERENCE_DISTANCE_M = 3.0octave_pair_averages
Section titled “octave_pair_averages”octave_pair_averages( values: ArrayLike, frequency: ArrayLike,) -> dict[str, float]The low, mid and high pair averages of ISO 3382-1:2009, A.5.
A more concise presentation than a full band table: the 125 Hz and 250 Hz results averaged into a low-frequency one, 500 Hz and 1 kHz into a mid-frequency one, and 2 kHz and 4 kHz into a high-frequency one, all arithmetically.
This is a different product from the single number of
single_number_average, and the two must not be confused. They
coincide for the five quantities Table A.1 averages over 500 Hz and
1 kHz, and they do not for the lateral ones, whose single number spans
four bands. A.5 also warns that lateral energy fractions in the 4 kHz
octave are not usually thought to be subjectively important, so the high
pair means little for them.
Parameters
| Name | Description |
|---|---|
values | Per-band values, one per entry of frequency. |
frequency | The band centre frequencies in Hz. |
Returns: {"low": ..., "mid": ..., "high": ...} in the values’ unit.
Raises
| Exception | When |
|---|---|
| ValueError | If the two arrays disagree in length, or if the band axis does not carry all six octaves from 125 Hz to 4 kHz. |
OCTAVE_PAIRS_HZ
Section titled “OCTAVE_PAIRS_HZ”Constant (mapping).
OCTAVE_PAIRS_HZ = {'low': (125.0, 250.0), 'mid': (500.0, 1000.0), 'high': (2000.0, 4000.0)}perceptibly_different
Section titled “perceptibly_different”perceptibly_different( symbol: str, first: ArrayLike, second: ArrayLike,) -> boolWhether two values of a quantity differ by its Table A.1 JND.
The comparison is absolute for every quantity but the early decay time, whose JND the table prints as “Rel. 5 %”, a fraction of the value rather than a difference in seconds. The late lateral sound level has no JND at all, printed as “Not known”, and this function refuses to invent one.
Parameters
| Name | Description |
|---|---|
symbol | The quantity, as TABLE_A1 keys it. "J_LFC" is taken too: Table A.1 prints the early lateral energy fraction as one row, “J_LF or J_LFC”, so both weightings of early_lateral_energy_fraction share its four bands, its just-noticeable difference and its typical range. |
first | One value, in the quantity’s unit. |
second | The other, of the same shape. |
Returns: True when the two differ by at least the just-noticeable difference, so a listener could be expected to hear it.
Raises
| Exception | When |
|---|---|
| ValueError | If the symbol is not one Table A.1 prints, or if the table prints no just-noticeable difference for it. |
REFERENCE_DISTANCE_M
Section titled “REFERENCE_DISTANCE_M”Constant (float).
REFERENCE_DISTANCE_M = 10.0reverberation_room_reference_level
Section titled “reverberation_room_reference_level”reverberation_room_reference_level( reverberation_room_level: ArrayLike, absorption_area: ArrayLike,) -> NDArray[np.float64] | floatFree-field reference level at 10 m from a reverberation-room measurement.
ISO 3382-1:2009, Equation (A.5):
with m². The route exists because a room 10 m across
and anechoic is rarer than a reverberation room: the source is measured
in the diffuse field instead, and the absorption area converts that
reading into the free-field one. A follows from the room’s
reverberation time through Sabine’s formula, Equation (A.6), which the
library publishes as
phonometry.room.sabine_absorption_area. Watch the constant when
reproducing a hand calculation: (A.6) prints ,
which is at m/s, while
that function defaults to 343 m/s and so to 0,1611. The difference moves
by 0,030 dB; pass speed_of_sound=345.39 to get
the printed constant back.
The printed 37 dB is dB rounded; see the module docstring for what that rounding costs.
(A.5) also carries no Waterhouse correction, unlike the reverberation-room sound power method of ISO 3741 that it otherwise mirrors. The omitted is worth over a decibel in the 125 Hz band of a small room, above the 1 dB just-noticeable difference Table A.1 gives G. That is a property of the printed method, and this function reproduces the method rather than quietly improving it.
Parameters
| Name | Description |
|---|---|
reverberation_room_level | Spatial-average sound pressure exposure level measured in the reverberation room, in dB. The standard calls this too, which is the same symbol it gave the level measured in the hall under test a page earlier; substituting (A.5) into (A.1) as printed would cancel the hall out of G altogether. The two roles get different names here, and docs/ERRATA.md carries the rest. |
absorption_area | Equivalent sound absorption area of that room, in m², broadcast against reverberation_room_level. |
Returns: The reference exposure level at 10 m, in dB.
Raises
| Exception | When |
|---|---|
| ValueError | If the absorption area is not a positive, finite area. |
single_number_average
Section titled “single_number_average”single_number_average( symbol: str, values: ArrayLike, frequency: ArrayLike,) -> floatThe Table A.1 single number of one auditorium quantity.
Footnote a of ISO 3382-1:2009, Table A.1 makes this the arithmetical
average over the octave bands the table names for that quantity, with
one exception: the late lateral sound level, which
late_lateral_average energy-averages through Equation (A.17).
A.5 asks for the index “m” to be applied to the symbol of the result.
The band set is per quantity and is not always the mid pair. The sound strength, early decay time, clarity, definition and centre time average the 500 Hz and 1 kHz octaves; the lateral quantities average 125 Hz to 1 kHz, four bands. A.5 prints both cases as examples for exactly that reason, over two bands and over four, and an accessor that hard-codes the mid pair is wrong for half the table.
Parameters
| Name | Description |
|---|---|
symbol | The quantity, as TABLE_A1 keys it. "J_LFC" is taken too: Table A.1 prints the early lateral energy fraction as one row, “J_LF or J_LFC”, so both weightings of early_lateral_energy_fraction share its four bands, its just-noticeable difference and its typical range. |
values | Its per-band values, one per entry of frequency. |
frequency | The band centre frequencies in Hz, as a result carries them. |
Returns: The single number, in the quantity’s own unit.
Raises
| Exception | When |
|---|---|
| ValueError | If the symbol is not one Table A.1 prints, if the two arrays disagree in length, or if the band axis does not carry every band the quantity averages. |
sound_pressure_exposure_level
Section titled “sound_pressure_exposure_level”sound_pressure_exposure_level( ir: Signal | list[float] | NDArray[np.float64], fs: int | None = None, *, limits: tuple[float, float] | None = (125.0, 4000.0), fraction: int = 1,) -> NDArray[np.float64] | floatSound pressure exposure level of an impulse response, per band.
ISO 3382-1:2009, Equation (A.2):
with s and uPa. Time zero is the start of the direct sound (A.2.1), found per band with the A.3.4 trigger, and the integral runs to the end of the response supplied.
A.2.1 asks that end to lie at or beyond the point where the decay curve
has fallen 30 dB. Whether a room response reaches it is visible in the
dynamic_range of
phonometry.room.room_parameters, and
sound_strength raises AuditoriumWarning when it does
not; this function evaluates whatever it is given, because the same
equation is (A.3) applied to a free-field response, which has no
reverberant decay to reach 30 dB of.
This is the quantity Equations (A.3) to (A.5) also operate on: the same function applied to the free-field response at 10 m gives .
Parameters
| Name | Description |
|---|---|
ir | Measured impulse response (1D). A phonometry.io.Signal brings its calibration, which is applied; a bare array is read as pascals, so its exposure level is only referenced to 20 uPa if the samples already are. |
fs | Sample rate in Hz. Required for a bare array; a Signal brings its own, and an explicit value that disagrees with it raises instead of silently winning. |
limits | (f_min, f_max) band-centre limits in Hz; default the octave bands 125 Hz to 4 kHz (ISO 3382-1:2009, 5.1). None integrates the broadband response as a single band. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). |
Returns: The exposure level in dB, one entry per band, or a float for a broadband response.
Raises
| Exception | When |
|---|---|
| ValueError | If the response is not one-dimensional or is silent, if limits is malformed, or if a band has no energy. |
sound_strength
Section titled “sound_strength”sound_strength( ir: Signal | list[float] | NDArray[np.float64], reference_ir: Signal | list[float] | NDArray[np.float64] | None = None, fs: int | None = None, *, reference_level: ArrayLike | None = None, limits: tuple[float, float] | None = (125.0, 4000.0), fraction: int = 1,) -> SoundStrengthResultSound strength G of a measured impulse response, per band.
ISO 3382-1:2009, Equation (A.1):
Equation (A.7) is the same difference between stationary-source levels
rather than exposure levels, which is why this function accepts the
reference either as a second impulse response or as a level already in
hand: exactly one of reference_ir and reference_level is
required. A level obtained from
free_field_reference_level,
reverberation_room_reference_level or, through
sound_strength_from_power, from the source’s power level, goes
in the second slot.
Both responses are split into the same bands and each is integrated from its own direct sound, so a common gain on the pair cancels exactly. A gain applied to only one of them does not: the two recordings must share a calibration, which is the whole reason G needs a calibrated source where every other measure in Table A.1 does not.
Parameters
| Name | Description |
|---|---|
ir | Impulse response measured in the room under test (1D). |
reference_ir | Impulse response of the same source at 10 m in a free field (1D). Mutually exclusive with reference_level. |
fs | Sample rate in Hz. Required for bare arrays; a Signal brings its own. |
reference_level | The free-field reference exposure level in dB, as a scalar or one value per band. Mutually exclusive with reference_ir. |
limits | (f_min, f_max) band-centre limits in Hz; default the octave bands 125 Hz to 4 kHz (ISO 3382-1:2009, 5.1). None measures the broadband response as a single band. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). |
Returns: A SoundStrengthResult with one entry per band.
Raises
| Exception | When |
|---|---|
| ValueError | If neither or both reference forms are given, if a response is not one-dimensional or is silent, or if reference_level does not broadcast onto the band axis. |
sound_strength_from_power
Section titled “sound_strength_from_power”sound_strength_from_power( pressure_level: ArrayLike, power_level: ArrayLike,) -> NDArray[np.float64] | floatSound strength from the source’s sound power level.
ISO 3382-1:2009, Equation (A.9):
The third route to G, and the only one that needs no free-field
measurement at all: the 31 dB is the spread of a point source over the
sphere of radius 10 m, dB,
rounded. A.2.1 asks for the source’s power level to be measured to
ISO 3741, which the library implements in
phonometry.emission.sound_power.
Parameters
| Name | Description |
|---|---|
pressure_level | Sound pressure level at the measurement point in the room under test, in dB. |
power_level | Sound power level of the source, in dB, broadcast against pressure_level. |
Returns: The sound strength G, in dB.
SOUND_STRENGTH_POWER_OFFSET_DB
Section titled “SOUND_STRENGTH_POWER_OFFSET_DB”Constant (float).
SOUND_STRENGTH_POWER_OFFSET_DB = 31.0SoundStrengthResult
Section titled “SoundStrengthResult”SoundStrengthResult( frequencies: NDArray[np.float64] | None, strength: NDArray[np.float64], exposure_level: NDArray[np.float64], reference_level: NDArray[np.float64],)Per-band sound strength G and the two levels it is the difference of.
frequencies holds the exact band centre frequencies in Hz, or is
None for a broadband measurement, in which case every array has
length 1. strength is G in dB (ISO 3382-1:2009, Equation (A.1)),
exposure_level the sound pressure exposure level of the response
measured in the room (Equation (A.2)) and reference_level that of
the free-field response at 10 m (Equation (A.3)), however it was
obtained. All three are in decibels and strength is exactly
exposure_level - reference_level.
SoundStrengthResult.plot()
Section titled “SoundStrengthResult.plot()”SoundStrengthResult.plot( ax: Axes | None = None, *, language: str = 'en', **kwargs: Any,) -> Axes | np.ndarrayPlot the per-band sound strength against the Table A.1 range.
With ax given, only the strength panel is drawn on it; otherwise a
second panel shows the two levels G is the difference of. Requires
matplotlib (pip install phonometry[plot]); returns the
Axes (or an array of two).
source_directivity_limit
Section titled “source_directivity_limit”source_directivity_limit(centre: float) -> floatThe Table 1 limit for one octave band, in dB.
Parameters
| Name | Description |
|---|---|
centre | Nominal octave band centre frequency in Hz. |
Returns: The maximum deviation from omnidirectionality the table prints.
Raises
| Exception | When |
|---|---|
| ValueError | If Table 1 has no row for that band. It prints six, 125 Hz to 4 kHz, and a survey in the 63 Hz or 8 kHz octave has no printed limit to be held to rather than the nearest one. |
STAGE_DIRECT_WINDOW_S
Section titled “STAGE_DIRECT_WINDOW_S”Constant (tuple).
STAGE_DIRECT_WINDOW_S = (0.0, 0.01)stage_support
Section titled “stage_support”stage_support( ir: Signal | list[float] | NDArray[np.float64], fs: int | None = None, *, limits: tuple[float, float] | None = (250.0, 2000.0), fraction: int = 1,) -> StageSupportResultEarly and late stage support of a platform response, per band.
ISO 3382-1:2009, Equations (C.1) and (C.2), the reflected energy a musician hears from the platform against the direct sound of their own instrument:
Both are measured with the source and the microphone 1,0 m apart on the platform, at the same height, with nothing reflecting within 2 m (C.2.1 and C.2.3). Because they share a denominator, their difference is a property of the hall alone and does not depend on how loud the direct sound was.
Two limits are in the equations and not in the prose. C.2.1
describes the early support as “the reflected energy within the first
0,1 s”, but (C.1) starts at 20 ms, discarding the 10 ms to 20 ms
interval; C.2.2 describes the late support as “the reflected energy
after the first 0,1 s” with no upper bound, but (C.2) stops at one
second, which matters in any hall whose reverberation time is longer
than that. The equations govern, and docs/ERRATA.md records the rest.
Parameters
| Name | Description |
|---|---|
ir | Impulse response measured on the platform (1D), 1,0 m from the acoustic centre of an omnidirectional source. |
fs | Sample rate in Hz. Required for a bare array; a Signal brings its own. |
limits | (f_min, f_max) band-centre limits in Hz; default the 250 Hz to 2 kHz octave bands C.2.4 averages over. None measures the broadband response. |
fraction | Bandwidth fraction (1 = octave, 3 = one-third octave). C.2.4 asks for octave bands. |
Returns: A StageSupportResult with one entry per band.
Raises
| Exception | When |
|---|---|
| ValueError | If the response is not one-dimensional or is silent, if a band has no energy, or if the response is shorter than the one second Equation (C.2) integrates to. |
STAGE_SUPPORT_BANDS_HZ
Section titled “STAGE_SUPPORT_BANDS_HZ”Constant (tuple).
STAGE_SUPPORT_BANDS_HZ = (250.0, 500.0, 1000.0, 2000.0)STAGE_SUPPORT_DISTANCE_M
Section titled “STAGE_SUPPORT_DISTANCE_M”Constant (float).
STAGE_SUPPORT_DISTANCE_M = 1.0STAGE_SUPPORT_HEIGHTS_M
Section titled “STAGE_SUPPORT_HEIGHTS_M”Constant (tuple).
STAGE_SUPPORT_HEIGHTS_M = (1.0, 1.5)STAGE_SUPPORT_POSITIONS
Section titled “STAGE_SUPPORT_POSITIONS”Constant (int).
STAGE_SUPPORT_POSITIONS = 3STAGE_SUPPORT_SINGLE_NUMBER_STANDARD_DEVIATION_DB
Section titled “STAGE_SUPPORT_SINGLE_NUMBER_STANDARD_DEVIATION_DB”Constant (float).
STAGE_SUPPORT_SINGLE_NUMBER_STANDARD_DEVIATION_DB = 0.3STAGE_SUPPORT_STANDARD_DEVIATION_DB
Section titled “STAGE_SUPPORT_STANDARD_DEVIATION_DB”Constant (float).
STAGE_SUPPORT_STANDARD_DEVIATION_DB = 1.0StageSupportResult
Section titled “StageSupportResult”StageSupportResult( frequencies: NDArray[np.float64] | None, early: NDArray[np.float64], late: NDArray[np.float64],)Per-band stage support (ISO 3382-1:2009, Annex C).
frequencies holds the exact band centre frequencies in Hz, or is
None for a broadband measurement. early is
in dB (Equation (C.1)) and late
in dB (Equation (C.2)), both referred to the
same direct sound. Table C.1 gives their typical ranges as -24 dB to
-8 dB and -24 dB to -10 dB and prints “Not known” for both
just-noticeable differences, so this module has none.
StageSupportResult.plot()
Section titled “StageSupportResult.plot()”StageSupportResult.plot( ax: Axes | None = None, *, language: str = 'en', **kwargs: Any,) -> AxesPlot both supports per band against the Table C.1 ranges.
Requires matplotlib (pip install phonometry[plot]); returns the
Axes.
TABLE_A1
Section titled “TABLE_A1”Constant (mapping).
TEST_REPORT_ITEMS
Section titled “TEST_REPORT_ITEMS”Constant (tuple).
TEST_REPORT_ITEMS = ('a statement that the measurements were made in conformity with ISO 3382-1', 'name and place of the room tested', 'sketch plan of the room, with an indication of the scale', 'volume of the room, with an explanation of how it is defined if the room is not completely enclosed', 'for rooms for speech and music, the number and type of seats, their upholstery and covering, and which parts of the seat are covered', 'a description of the shape and material of the walls and the ceiling', 'state or states of occupancy during measurements, and the number of occupants', 'condition of any variable equipment, such as curtains, public-address or electronic reverberation enhancement systems', 'for theatres, whether the safety curtain or decorative curtains were up or down', 'description, where appropriate, of the stage furnishing, including any concert enclosure', 'temperature and relative humidity in the room during the measurement', 'description of measuring apparatus, source and microphones, and whether tape recorders were employed', 'description of the sound signal used', 'coverage chosen, including the source and microphone positions and their heights, preferably shown on a plan', 'date of measurement and name of the measuring organization')