Speech Intelligibility Index
Standards: ANSI S3.5Key references: French & Steinberg 1947
The Speech Intelligibility Index predicts how much of a speech signal is
audible, and therefore intelligible, to a listener in a given noise and hearing
condition. It reduces a speech spectrum, a noise spectrum and a hearing
threshold to a single number in [0, 1]: 0 when nothing useful reaches the
listener, 1 when the whole speech-bearing spectrum is audible. This page
covers all four band procedures of ANSI S3.5-1997 (R2017): the
one-third-octave-band method (18 bands from 160 Hz to 8000 Hz), which is
the default and the one sections 1 to 4 work through, and the critical-band,
equally-contributing critical-band and octave-band methods of section 5.
1. Inputs and the band-importance function
Section titled “1. Inputs and the band-importance function”All three inputs are equivalent spectrum levels (ANSI S3.5-1997 clauses 3.11 and 3.55) sampled at the 18 one-third-octave band centres: the speech spectrum level , the noise spectrum level (both in dB SPL) and the hearing threshold (in dB HL). Each band contributes to intelligibility in proportion to its band-importance function (ANSI S3.5-1997 Table 3, average speech material), which sums to one across the 18 bands.
from phonometry import speech
# The standard normal-effort speech spectrum (Table 3) in quiet, normal hearing.result = speech.speech_intelligibility_index("normal")print(round(result.sii, 3)) # 0.996 (nearly everything audible)print(round(speech.sii.BAND_IMPORTANCE.sum(), 6)) # 1.0
result.plot() # per-band audibility and its weighted contribution (needs matplotlib)With no noise and a normal hearing threshold the standard speech spectrum is almost fully audible, so the index is close to one; the small deficit is the listener’s own self-speech masking.
The importance function is where the perceptual knowledge of the standard lives. It descends from the articulation experiments behind French and Steinberg’s articulation index: listeners scored nonsense syllables heard through filters that removed one part of the spectrum at a time, and the drop in score measures how much intelligibility each band carries. The outcome is strikingly unequal, and unrelated to where the speech energy sits: the five bands from 1250 Hz to 3150 Hz carry about 43 % of intelligibility (the place and manner cues of consonants live there), while the five lowest bands, 160 Hz to 400 Hz, carry about 11 % even though they hold nearly half of the speech power. from Table 3 is the average-speech compromise; the standard’s Annex B tabulates alternative importance functions for specific test materials (nonsense syllables, monosyllabic word lists, short passages), which shift weight according to how much redundancy the material offers.
Band levels are not spectrum levels
Section titled “Band levels are not spectrum levels”This is the trap that silently ruins an SII computed from measured data. An equivalent spectrum level is the level the band would have if its energy were spread over 1 Hz, so a one-third-octave band level from an analyser becomes a spectrum level by subtracting ten times the logarithm of the band width in hertz:
The widths need not be memorised: every procedure object carries its own band edges, so the conversion is two lines for any of the four methods.
import numpy as np
# `speech` is the import of the first snippet on this page.proc = speech.sii_procedure("one-third-octave")widths = np.diff(proc.band_edges) # hertz, band by bandprint(np.round(10 * np.log10(widths), 1)[[0, 8, 17]]) # [15.5 23.5 32.7]
band_levels = np.full(18, 55.0) # what an analyser reportsspectrum_levels = band_levels - 10 * np.log10(widths)print(round(float(spectrum_levels[8]), 1)) # 31.5 dB at 1 kHzSo the correction runs from 15.5 dB at 160 Hz to 32.7 dB at 8 kHz for the one-third-octave procedure, and is 28.5 dB at 1 kHz for the octave procedure — that is, a measured 55 dB band level at 1 kHz is a 31.5 dB spectrum level, not a 55 dB one. Feed band levels straight in and both the speech and the noise are 15 to 33 dB too high, band by band, and the failure is silent: the index stays inside and the audibility plot still looks plausible.
Two things follow. The threshold input is not converted: it is a hearing threshold level in dB HL, a level difference rather than a per-hertz quantity. And there is a cheap sanity check: because a spectrum level is per hertz, a white noise has the same equivalent noise spectrum level in every band of every procedure, whereas its band levels rise by 3 dB per octave. If an SII comes out exactly 0 for ordinary office noise, or exactly 1 with noise present, suspect band levels entered as spectrum levels; a quick check is that the standard’s own normal-effort speech spectrum peaks at 34.8 dB near 250 Hz, so any speech input more than about 15 dB above that is a band level.
Where the three spectra come from
Section titled “Where the three spectra come from”The reason the three inputs can be combined at all is that they describe the same point in space. ANSI S3.5-1997 defines the equivalent speech and noise spectrum levels at the position corresponding to the centre of the listener’s head, midway between the ears, with the listener absent — both are field quantities at an unoccupied listening position. So: measure the noise there with the talker or source of interest silent, and the speech there with the talker at the real distance and vocal effort.
Three consequences worth writing into a report. The tabulated vocal-effort
spectra of section 4 are the standard’s reference speech, excellent for
design and comparison but not a substitute for a measured when the real
listening condition is at another distance or in a reverberant space. Levels
recorded at the eardrum, in a coupler or under headphones are not equivalent
free-field levels and have to be transformed back before they can be used.
And threshold= is the listener’s pure-tone hearing threshold level in dB HL
at the 18 band centres and belongs to one ear, so state which ear it is and
how the audiogram was put onto those centres, which section 3.2 returns to.
2. Masking and the band-audibility function
Section titled “2. Masking and the band-audibility function”The procedure (ANSI S3.5-1997 clause 5) turns the inputs into a per-band audibility. Speech masks itself downward from each band (); the larger of that and the external noise, , spreads upward in frequency with a level-dependent slope to give the equivalent masking spectrum level (clause 5.4):
The masking is combined with the equivalent internal noise (, the reference internal noise shifted by the hearing loss) into the equivalent disturbance (clause 5.6), and the band-audibility function is the speech-to-disturbance ratio scaled into (clause 5.8):
At speech levels well above normal effort a level-distortion factor of clause 5.7 (unity for the standard spectra used on this page) reduces further; phonometry applies it automatically.
Every array in that chain is on the result, so the whole of clause 5 can be drawn for a case where the spread of masking does the work — a fan or a duct that puts all its energy below 450 Hz:
The band audibility is a position inside a 30 dB window: at the bottom edge the band is fully masked, at the top fully audible, and in between it is a straight line. The window is centred on , and follows , which is the point of the figure — there is no noise at all above 400 Hz, yet the masking at 1 kHz is 23 dB, spread upward from the low bands. That upward skirt is what makes the SII more than a band-by-band signal-to-noise ratio, and it is the term the octave procedure of section 5 drops.
Show the code for this figure
import matplotlib.pyplot as plt
# `np` and `speech` come from the snippets above.freqs = speech.sii_procedure("one-third-octave").frequenciesnoise = np.where(freqs <= 450.0, 60.0, 0.0) # all the energy below 450 Hzres = speech.speech_intelligibility_index("normal", noise)print(round(res.sii, 2), round(float(res.masking[8]), 1)) # 0.6 23.2
pos = np.arange(freqs.size)fig, ax = plt.subplots(figsize=(10.4, 6.0))ax.fill_between(pos, res.disturbance - 15, res.disturbance + 15, alpha=0.25)ax.plot(pos, res.speech_spectrum, "o-", label="speech Ei'")ax.plot(pos, noise, "s--", label="external noise Ni'")ax.plot(pos, res.masking, "^-", label="equivalent masking Zi")ax.twinx().plot(pos, res.band_audibility) # the audibility on the rightax.legend()plt.show()3. The index in noise
Section titled “3. The index in noise”3.1 In noise
Section titled “3.1 In noise”The Speech Intelligibility Index is the band-importance-weighted sum of the band audibilities (ANSI S3.5-1997 clause 6):
import numpy as npfrom phonometry import speech
speech_spectrum = speech.standard_speech_spectrum("normal")# A descending broadband masking noise (an office/ventilation-like spectrum).noise = np.array([38.0, 37.0, 36.0, 34.0, 32.0, 30.0, 28.0, 26.0, 24.0, 22.0, 20.0, 18.0, 16.0, 14.0, 12.0, 10.0, 8.0, 6.0])
result = speech.speech_intelligibility_index(speech_spectrum, noise)print(round(result.sii, 2)) # 0.46print(result.band_audibility.round(2)) # per-band Ai
result.plot() # the figure below: Ai and the weighted contribution per bandShow the code for this figure
import numpy as npimport matplotlib.pyplot as pltfrom phonometry import speech
speech_spectrum = speech.standard_speech_spectrum("normal")noise = np.array([38.0, 37.0, 36.0, 34.0, 32.0, 30.0, 28.0, 26.0, 24.0, 22.0, 20.0, 18.0, 16.0, 14.0, 12.0, 10.0, 8.0, 6.0])result = speech.speech_intelligibility_index(speech_spectrum, noise)
# One line:result.plot()plt.show()
# By hand, mirroring what SIIResult.plot() draws:pos = np.arange(result.frequencies.size)weighted = result.band_audibility * result.band_importancefig, ax = plt.subplots()ax.bar(pos, result.band_audibility, color="#c6dbef", label=r"Band audibility $A_i$")ax.bar(pos, weighted / weighted.max(), width=0.5, color="#1f77b4", label=r"Importance-weighted $I_i\,A_i$ (scaled)")ax.set_xticks(pos)ax.set_xticklabels([f"{f:g}" for f in result.frequencies], rotation=45, ha="right")ax.set_xlabel("One-third-octave band [Hz]")ax.set_ylabel("Band audibility")ax.set_title(f"SII = {result.sii:.2f}")ax.legend()plt.show()Reading the number. The SII is the importance-weighted fraction of the
speech spectrum that is audible, so 0.46 means that roughly half of what
carries intelligibility is getting through. It is a proportion of audibility,
not of words: ANSI S3.5 maps the index to intelligibility only through transfer
functions specific to the speech material and the listeners, which is why the
same 0.5 supports high sentence scores and much lower nonsense-syllable scores.
Never quote an SII as “X % intelligible” without naming the material. As
practical anchors, above about 0.75 is the design target where unfamiliar
material must be understood — the same ladder that makes requirement=0.75 a
reasonable value in the fiche of section 7; 0.45 to 0.75 is workable for
familiar material in a known context; below about 0.3 speech communication
cannot be relied on. And mind the resolution: the inputs are measured spectra
with their own uncertainty, so differences of a few hundredths are noise. When
two conditions score alike, the per-band audibility profile — not the scalar —
is the part that tells you what to fix.
3.2 With a raised hearing threshold
Section titled “3.2 With a raised hearing threshold”A raised hearing threshold (threshold=) lifts the equivalent internal noise
and lowers the index, exactly as added masking noise does. The input is a
pure-tone hearing threshold level in dB HL at the 18 band centres, for one ear.
The SIIResult also
carries the per-band masking , disturbance , audibility and
importance , and its .plot() renders the figure above.
The same speech and noise heard by a listener with a sloping high-frequency loss shows what that costs, band by band:
Show the code for this figure
import numpy as npimport matplotlib.pyplot as pltfrom phonometry import speech
# The same speech and office noise as above, heard through a sloping# high-frequency loss (hearing threshold levels at the 18 band centres).speech_spectrum = speech.standard_speech_spectrum("normal")noise = np.array([38.0, 37.0, 36.0, 34.0, 32.0, 30.0, 28.0, 26.0, 24.0, 22.0, 20.0, 18.0, 16.0, 14.0, 12.0, 10.0, 8.0, 6.0])threshold = np.array([5.0, 5.0, 5.0, 5.0, 8.0, 10.0, 12.0, 15.0, 18.0, 22.0, 28.0, 35.0, 42.0, 48.0, 55.0, 60.0, 65.0, 70.0])res = speech.speech_intelligibility_index(speech_spectrum, noise, threshold=threshold)print(round(res.sii, 3)) # 0.358 (0.458 with normal hearing)
# One line: the same audibility bars, now limited by the hearing threshold.res.plot()plt.show()The loss removes the bands that carry the consonant cues, which is why the index falls by a fifth while the level of the speech has not changed at all. This is the practical use of the SII in audiology and in noise control for occupied spaces: a target index can be met either by lowering the noise or by restoring audibility (amplification), and the band profile says which bands the effort has to go into.
Getting a threshold array onto the SII grid. The age-related thresholds of
ISO 7029 are a convenient
population input, but the two standards are tabulated on different grids and
the transfer is the caller’s decision, not an automatic one. ISO 7029 returns
eleven audiometric frequencies (125 to 8000 Hz) while the one-third-octave
SII procedure needs eighteen values at 160 Hz to 8000 Hz, and ANSI S3.5
defines no interpolation — the page’s own “Not covered” block says no
resampling between band sets is provided. So make the choice explicit:
interpolate the audiometric thresholds on a logarithmic frequency axis onto the
SII band centres, or take the nearest audiometric frequency for each band, and
say which in the report. There is a second mismatch: age_threshold returns
the deviation from the median 18-year-old, which is a hearing threshold level
in dB HL only if that baseline is taken as 0 dB HL — an assumption worth
stating, and one to drop entirely when a real audiogram exists, since measured
dB HL values can be fed directly. Finally, mind the direction of the error: a
coarse interpolation smooths away the 3 kHz to 6 kHz notch that a noise-exposed
audiogram carries, and those are bands with high importance weight, so the SII
comes out optimistic.
4. Vocal effort
Section titled “4. Vocal effort”Talkers raise their voice in noise, and the standard gives four standard speech spectra for the vocal efforts normal, raised, loud and shout (ANSI S3.5-1997 Table 3). Passing the effort name selects the corresponding spectrum; speaking louder lifts the whole spectrum and, in a fixed noise, raises the index.
import numpy as npfrom phonometry import speech
# The same broadband noise, four vocal efforts.noise = np.array([48.0, 47.0, 46.0, 44.0, 42.0, 40.0, 38.0, 36.0, 34.0, 32.0, 30.0, 28.0, 26.0, 24.0, 22.0, 20.0, 18.0, 16.0])for effort in speech.sii.VOCAL_EFFORTS: print(effort, round(speech.speech_intelligibility_index(effort, noise).sii, 2))# normal 0.12 | raised 0.36 | loud 0.59 | shout 0.79
print(speech.standard_speech_spectrum("loud")[8]) # 42.16 dB SPL at 1 kHzThe four spectra are also available as one plottable result:
standard_speech_spectra() returns a StandardSpeechSpectrum carrying the band
centre frequencies and the per-effort band levels, and its .plot() draws them
as one labelled family on the one-third-octave band axis.
Show the code for this figure
import numpy as npimport matplotlib.pyplot as pltfrom phonometry import speech
# One line: the whole ANSI S3.5-1997 Table 3 family.speech.standard_speech_spectra().plot()plt.show()
# By hand, mirroring what StandardSpeechSpectrum.plot() draws:res = speech.standard_speech_spectra()pos = np.arange(res.frequencies.size)fig, ax = plt.subplots()for effort, levels in zip(res.vocal_efforts, res.levels): ax.plot(pos, levels, "o-", label=effort.capitalize())ax.set_xticks(pos)ax.set_xticklabels([f"{f:g}" for f in res.frequencies], rotation=45, ha="right")ax.set_xlabel("One-third-octave band [Hz]")ax.set_ylabel("Speech spectrum level [dB SPL]")ax.legend()plt.show()The same four spectra feed the index: in a fixed broadband noise, each higher vocal effort lifts the speech spectrum and raises the SII.
Show the code for this figure
import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.ticker import NullFormatterfrom phonometry import speech
# The four ANSI S3.5-1997 Table 3 spectra and the fixed broadband noise above.noise = np.array([48.0, 47.0, 46.0, 44.0, 42.0, 40.0, 38.0, 36.0, 34.0, 32.0, 30.0, 28.0, 26.0, 24.0, 22.0, 20.0, 18.0, 16.0])efforts = speech.sii.VOCAL_EFFORTS # ("normal", "raised", "loud", "shout")freqs = speech.sii.BAND_CENTERS # the 18 one-third-octave band centres
fig, (ax_s, ax_i) = plt.subplots(1, 2, figsize=(12, 5))
# Left: each higher vocal effort lifts the whole speech spectrum.for effort in efforts: ax_s.plot(freqs, speech.standard_speech_spectrum(effort), "o-", label=effort.capitalize())ax_s.set_xscale("log")ax_s.set_xticks(list(freqs))ax_s.set_xticklabels([f"{f:g}" for f in freqs], rotation=45, ha="right")ax_s.xaxis.set_minor_formatter(NullFormatter())ax_s.set_xlabel("One-third-octave band [Hz]")ax_s.set_ylabel("Speech spectrum level [dB SPL]")ax_s.legend()
# Right: the SII each spectrum reaches in the fixed noise.sii = [speech.speech_intelligibility_index(e, noise).sii for e in efforts]pos = np.arange(len(efforts))ax_i.bar(pos, sii)ax_i.set_xticks(pos)ax_i.set_xticklabels([e.capitalize() for e in efforts])ax_i.set_ylim(0.0, 1.0)ax_i.set_ylabel("Speech Intelligibility Index")plt.show()The vocal-effort names work anywhere a speech spectrum is expected, including as
the first argument to speech_intelligibility_index.
5. The four band procedures
Section titled “5. The four band procedures”The standard’s own title is plural, and so is the standard: ANSI S3.5-1997
defines four band procedures. They differ only in the band table and in how
the upward spread of masking is expressed, and method= selects one. The
default is the one-third-octave procedure used above.
method= | Bands | Band centres | Band limits | Constants | Spread of masking |
|---|---|---|---|---|---|
"critical-band" | 21 | 150 Hz to 8500 Hz | 100 Hz to 9500 Hz | Table 1 | between tabulated band limits |
"equally-contributing" | 17 | 350 Hz to 5800 Hz | 300 Hz to 6400 Hz | Table 2 | between tabulated band limits |
"one-third-octave" | 18 | 160 Hz to 8000 Hz | 143 Hz to 8980 Hz (computed) | Table 3 | between band centre frequencies |
"octave" | 6 | 250 Hz to 8000 Hz | 177 Hz to 11314 Hz | Table 4 | none |
The two columns are sii_procedure(method).frequencies and .band_edges; only
the one-third-octave limits are computed from the centres rather than tabulated.
Every procedure runs the same chain as section 2: self-speech masking, the upward spread of masking, the equivalent internal noise and disturbance, the level-distortion factor and the band-audibility function, weighted by that procedure’s own band-importance function. The masking slope is one formula throughout, with the band width in hertz. The critical-band and equally-contributing procedures spread the masking from the upper limit of the masker band up to the centre frequency of the masked band; the one-third-octave procedure writes that same geometry in terms of the band centres, which is where its printed and dB come from. The octave-band procedure carries no spread of masking at all: an octave band is already wider than the spread being modelled, so its equivalent masking spectrum level is the equivalent noise spectrum level itself.
The four band-importance functions are one underlying distribution sampled at
four resolutions, so the wider the bands, the larger each . Each function
sums to one, except Table 2’s, which prints 0.0588 in each of its 17 bands
and so sums to 0.9996.
Show the code for this figure
import numpy as npimport matplotlib.pyplot as pltfrom phonometry import SII_METHODS, sii_procedure
# One line: each procedure's own .plot() steps its Ii over its band limits.fig, ax = plt.subplots(figsize=(10, 6))for method in SII_METHODS: sii_procedure(method).plot(ax=ax, linewidth=1.8)plt.show()
# By hand, mirroring what SIIProcedure.plot() draws:fig, ax = plt.subplots()for method in SII_METHODS: proc = sii_procedure(method) ii = proc.band_importance ax.plot(proc.band_edges, np.append(ii, ii[-1]), drawstyle="steps-post", label=method)ax.set_xscale("log")ax.set_xlabel("Frequency [Hz]")ax.set_ylabel(r"Band importance $I_i$")ax.set_ylim(bottom=0.0)ax.legend()plt.show()Because an equivalent spectrum level is a per-hertz quantity, a white noise has the same equivalent noise spectrum level in every band of every procedure, which makes the four directly comparable:
import numpy as npfrom phonometry import speech
for method in speech.SII_METHODS: n_bands = speech.sii_procedure(method).frequencies.size result = speech.speech_intelligibility_index( "normal", np.full(n_bands, 25.0), method=method ) print(method, n_bands, round(result.sii, 3))# critical-band 21 0.343# equally-contributing 17 0.333# one-third-octave 18 0.350# octave 6 0.369The four agree to within about 0.04 on the same listening situation. The octave procedure reads highest because it drops the spread of masking, which is exactly the risk it carries: feed it a strong low-frequency noise and it will not see that noise reaching up into the speech-bearing bands.
The agreement above is a property of the stimulus, not of the procedures. On white noise all four track each other; on a masker that lives below 450 Hz the three procedures that carry the upward spread of masking collapse together while the octave procedure does not move at all — 0.81 index units apart at the loudest point, which is most of the scale. An octave-band SII under low-frequency-dominated noise is an upper bound, not an estimate.
Show the code for this figure
levels = np.arange(45.0, 80.1, 1.0)for method in ("critical-band", "equally-contributing", "one-third-octave", "octave"): proc = speech.sii_procedure(method) curve = [speech.speech_intelligibility_index( proc.speech_spectrum, np.where(np.asarray(proc.frequencies) <= 450.0, x, 0.0), method=method).sii for x in levels] print(method, round(curve[0], 3), round(curve[-1], 3))# critical-band 0.736 0.03# equally-contributing 0.753 0.026# one-third-octave 0.777 0.067# octave 0.882 0.872Which procedure to use.
"one-third-octave"is the working default: the finest resolution the standard offers, the only table that carries all four vocal-effort speech spectra, and the resolution measurement data usually arrives in."critical-band"follows the auditory filter. Its 21 bands are the classical critical bands, so it is the procedure to pair with critical-band models of masking or loudness, and the only one that reaches down to 100 Hz."equally-contributing"gives all 17 of its bands the same importance over 300 Hz to 6400 Hz, so the index reads directly as the fraction of equally-important bands that are audible. That makes it fast to check by hand, and it is the presentation closest to the articulation-index tradition the SII grew out of."octave"is for octave-band data, which is what sound level meters, HVAC selections and building-acoustics reports routinely give. Use it when that is all you have, and read it knowing the spread of masking is missing.
An alternative band-importance function. band_importance= replaces the
procedure’s tabulated with one of your own, which is how the standard’s
Annex B functions for particular speech test materials (nonsense syllables,
monosyllabic word lists, short passages) are applied. It changes the weighting
only: the audibility chain, and therefore result.band_audibility, is
untouched.
res = speech.speech_intelligibility_index( "normal", np.full(6, 25.0), method="octave", band_importance=[0.0, 0.0, 1.0, 0.0, 0.0, 0.0], # all the weight at 1 kHz)print(round(res.sii, 3)) # 0.5 (the 1 kHz octave band alone)The tabulated constants. sii_procedure(method) returns an SIIProcedure
carrying that procedure’s band centre frequencies, band limits, band-importance
function, reference internal noise spectrum level and normal-effort standard
speech spectrum level; its .plot() draws the band-importance function as a
step over the band limits, which is the figure above. Tables 1, 2 and 4 print
all four vocal-effort columns in the standard, but only their normal-effort
column is carried here, so "raised", "loud" and "shout" are available on
the one-third-octave procedure alone.
octave = speech.sii_procedure("octave")print(octave.frequencies) # [ 250. 500. 1000. 2000. 4000. 8000.]print(octave.band_importance) # [0.0617 0.1671 0.2373 0.2648 0.2142 0.0549]
# Table 2 is critical bands 3 to 19 of Table 1, weighted equally.equal = speech.sii_procedure("equally-contributing")print(equal.band_edges[0], equal.band_edges[-1]) # 300.0 6400.0print(equal.band_importance.sum().round(4)) # 0.99966. SII or STI?
Section titled “6. SII or STI?”The two speech metrics answer different questions from different measurements, and each is blind to what the other captures:
| SII (ANSI S3.5) | STI (IEC 60268-16) | |
|---|---|---|
| Question answered | Is enough of the speech spectrum audible at the listener’s ear? | How much of the speech envelope does the transmission channel preserve? |
| Inputs | Speech, noise and hearing-threshold spectra (18 one-third-octave equivalent spectrum levels) | An impulse response (indirect) or a STIPA recording through the channel (direct) |
| Band machinery | Band-importance weighting applied to the band audibility | Modulation transfer function per octave band, converted to an effective SNR |
| Captures | Steady noise, upward spread of masking, hearing loss, vocal effort, level distortion | Reverberation, echoes, noise and (measured directly) non-linear processing |
| Blind to | Reverberation and any time-domain smearing: a fully audible but hopelessly reverberant channel still scores high | Individual hearing status: hearing-impaired listeners need specific corrections |
| Typical use | Audiology, hearing aids and protectors, noise-control targets at a listener position | PA systems, intercoms and rooms: rating a transmission channel end to end |
The same space can pass one and fail the other. A quiet, highly reverberant
atrium is an SII near 1 with a poor STI; a dry office flooded by ventilation
noise can rate an acceptable STI from its impulse response while the SII (and
the noise-aware STI, via snr= or level=) reveals that little of the speech
spectrum clears the noise. When both mechanisms are in play, compute both; the
inputs are cheap once the room and the noise have been measured. See the
Speech Transmission Index guide for
the STI side.
7. ANSI S3.5-1997 report (.report())
Section titled “7. ANSI S3.5-1997 report (.report())”SIIResult.report(path) renders a one-page PDF fiche laid out like a
speech-audibility report: a standard-basis line, an optional metadata header
block, a per-one-third-octave-band table of the equivalent speech spectrum
, the Table 3 band-importance function and the band-audibility
function beside the audibility and importance-weighted contribution bars
(the result’s own .plot()), the boxed SII = X single number, an optional
verdict row and a footer with the fixed disclaimer. It uses the same
ReportMetadata container and rendering engine as the
ISO 717 insulation fiche;
a supplied requirement is read as the minimum required SII (a higher SII
passes). verbose=True adds the equivalent disturbance spectrum level
column. Rendering needs reportlab and, for the figure the fiche embeds,
matplotlib (pip install "phonometry[report,plot]"); only engine="reportlab"
is supported. Pass language="es" for a Spanish fiche.
from phonometry import ReportMetadata, speech
res = speech.speech_intelligibility_index(speech_spectrum, noise, threshold=threshold)res.report( "sii_fiche.pdf", metadata=ReportMetadata( specimen="Conversational speech in low-frequency ambient noise", measurement_standard="ANSI S3.5-1997", laboratory="Phonometry Reference Laboratory", requirement=0.75, # minimum required SII (a higher SII passes) ),)The example fiche is regenerated with make reports and kept rendered in the
repository; click the preview to open the PDF.

One-page speech-intelligibility-index fiche: a metadata header, a one-third-octave-band table of the equivalent speech spectrum, band importance and band audibility, the audibility bars, the boxed SII = 0.851 single-number result and a PASS verdict against a 0.75 minimum.
What this guide covers
Section titled “What this guide covers”Covered
All four band procedures of ANSI S3.5-1997 (R2017): the critical-band method (21 bands, Table 1), the equally-contributing critical-band method (17 bands, Table 2), the one-third-octave-band method (18 bands, Table 3, the default) and the octave-band method (6 bands, Table 4). For each: the equivalent speech, noise and hearing-threshold spectrum levels, the band-importance function and standard speech spectrum level, the self-speech masking, upward spread of masking, level-distortion factor and band-audibility function of clause 5, and the index of clause 6.
speech_intelligibility_index(withmethod=andband_importance=),sii_procedure,standard_speech_spectrumandstandard_speech_spectraimplement these, andSIIResult.report(path)renders the ANSI S3.5-1997 fiche for whichever procedure was used.Not covered
The standard speech spectra for raised, loud and shout vocal effort are carried for the one-third-octave procedure only; Tables 1, 2 and 4 are implemented with their normal-effort column, which is the column the level-distortion factor of clause 5.7 needs. The tabulated band-importance functions are the average-speech compromise of each table; Annex B’s alternative importance functions for specific test materials (nonsense syllables, monosyllabic word lists, short passages) are not shipped as constants, but any importance function can be applied with
band_importance=. No resampling between the four band sets is provided: each procedure is fed spectra on its own bands. The Speech Transmission Index, a different metric for a transmission channel rather than listener audibility, is covered separately in the Speech Transmission Index guide.
See also
Section titled “See also”- Speech Transmission Index: the STI/STIPA transmission index that the SII complements.
- Loudness and Sound Quality Metrics: loudness, sharpness and the perception metrics of what the listener hears.
- Filter Banks: the one-third-octave bands the SII is evaluated on.
- Levels: the spectrum and band levels behind the equivalent spectrum-level inputs.
- API reference:
speech.sii. - Theory: Speech Intelligibility Index (ANSI S3.5): the band-importance weighting of ANSI S3.5 and the audibility function it multiplies.
Quick answers
Section titled “Quick answers”Which frequency bands matter most for speech intelligibility?
Section titled “Which frequency bands matter most for speech intelligibility?”In the one-third-octave-band method of ANSI S3.5-1997, the band-importance function (Table 3, average speech material) sums to one across 18 bands from 160 Hz to 8000 Hz. The five bands from 1250 Hz to 3150 Hz carry about 43 % of intelligibility (the consonant cues), while the five lowest bands, 160 Hz to 400 Hz, carry about 11 % despite holding nearly half of the speech power.
How is the Speech Intelligibility Index calculated?
Section titled “How is the Speech Intelligibility Index calculated?”The SII of ANSI S3.5-1997 clause 6 is the band-importance-weighted sum of the band audibilities, , over 18 one-third-octave bands. Each band audibility is (clause 5.8), where is the equivalent speech spectrum level and the equivalent disturbance combining external noise, upward spread of masking and the equivalent internal noise. The index lies in .
Which of the four ANSI S3.5 band procedures should I use?
Section titled “Which of the four ANSI S3.5 band procedures should I use?”ANSI S3.5-1997 defines four, quoted here by band centre: critical band
(21 bands, centres 150 Hz to 8500 Hz), equally-contributing critical band
(17 bands, centres 350 Hz to 5800 Hz), one-third octave (18 bands, centres
160 Hz to 8000 Hz) and octave (6 bands, centres 250 Hz to 8000 Hz). Use method="one-third-octave" by default: it is the finest
resolution and the only procedure whose table carries the raised, loud and
shout speech spectra. Use method="critical-band" to align the index with a
critical-band (Bark) masking or loudness model, method="equally-contributing"
when the index should read as the fraction of equally-important bands that are
audible, and method="octave" when octave-band data is all that was measured,
remembering that the octave procedure carries no upward spread of masking and
so reads high under strong low-frequency noise.
When should I use the SII instead of the STI?
Section titled “When should I use the SII instead of the STI?”Use the SII (ANSI S3.5) when the question is whether enough of the speech spectrum is audible at the listener’s ear: it captures steady noise, upward spread of masking, hearing loss and vocal effort, but it is blind to reverberation. The STI (IEC 60268-16) rates a transmission channel, how much of the speech modulation a room or sound system preserves. When both mechanisms are in play, compute both.
References
Section titled “References”- American National Standards Institute. (1997). American National Standard Methods for the Calculation of the Speech Intelligibility Index (ANSI S3.5-1997 (R2017)). Acoustical Society of America. The four band procedures: critical band (21 bands, Table 1), equally-contributing critical band (17 bands, Table 2), one-third octave (18 bands, Table 3) and octave (6 bands, Table 4), each with its band-importance function, standard speech spectrum level and reference internal noise; the masking, disturbance and band-audibility procedure (clause 5) and the index (clause 6).
- French, N. R., & Steinberg, J. C. (1947). Factors governing the intelligibility of speech sounds. The Journal of the Acoustical Society of America, 19(1), 90-119. https://doi.org/10.1121/1.1916407The articulation-band experiments that the band-importance function of section 1 descends from.