Skip to content

Predicting the noise a distant source delivers to a receiver outdoors is a book-keeping exercise: start from the source sound power and subtract, band by band, every mechanism that attenuates the sound on its way: spherical spreading, the air itself, the ground, and any barrier in between. This page covers the two parts of ISO 9613 that supply those terms: ISO 9613-1, the pure-tone atmospheric absorption coefficient , and ISO 9613-2, the general method that assembles with divergence, ground and screening into an octave-band prediction. The atmospheric coefficient also closes the loop with room acoustics, since ISO 354 defers its air power-attenuation coefficient entirely to .

Air is not lossless. A propagating tone bleeds energy into shear viscosity and heat conduction (the classical and rotational losses that grow as ) and into the vibrational relaxation of the oxygen and nitrogen molecules, each an energy store that resonates near a humidity- and temperature-dependent relaxation frequency. ISO 9613-1:1993, Eq. (5) collects all of this into the pure-tone attenuation coefficient , in decibels per metre:

with the oxygen and nitrogen relaxation frequencies , (Eq. (3)/(4)), the reference conditions K and kPa (Clause 4.2), and the molar water-vapour concentration obtained from the relative humidity by the Annex B psychrometric conversion. Two features dominate the shape: at low frequency , so it rises steeply; and near each relaxation frequency the matching term peaks and rolls off. Between them climbs about two decades from 50 Hz to 10 kHz, and, because humidity sets , sweeping the humidity moves a relaxation peak across the band, so the driest air is not always the least absorbing.

ISO 9613-1 pure-tone atmospheric attenuation coefficient alpha in dB/km against frequency on log-log axes, for four temperature and humidity combinations, showing the f-squared low-frequency growth and the humidity-dependent relaxation roll-offISO 9613-1 pure-tone atmospheric attenuation coefficient alpha in dB/km against frequency on log-log axes, for four temperature and humidity combinations, showing the f-squared low-frequency growth and the humidity-dependent relaxation roll-off

The dry 20 °C / 10 % curve absorbs most at mid frequencies, but the humid curves overtake it below ~200 Hz: the relaxation signature.

Show the code for this figure
import matplotlib.pyplot as plt
import numpy as np
from phonometry import environment
freqs = np.geomspace(50.0, 10000.0, 400)
fig, ax = plt.subplots()
for temp, rh in [(20.0, 50.0), (20.0, 10.0), (0.0, 70.0), (30.0, 80.0)]:
ax.loglog(freqs, environment.air_attenuation(freqs, temp, rh) * 1000.0,
label=f"{temp:g} °C, {rh:g} % RH")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Attenuation coefficient alpha [dB/km]")
ax.legend()
plt.show()
import numpy as np
from phonometry import environment
bands = [63, 125, 250, 500, 1000, 2000, 4000, 8000] # octave-band centres [Hz]
# Pure-tone attenuation coefficient alpha [dB/m] at 20 °C, 50 % RH, one atmosphere
alpha = environment.air_attenuation(bands, temperature=20.0, relative_humidity=50.0)
print(np.round(alpha * 1000.0, 2)) # in dB/km, as Table 1 tabulates
# [ 0.12 0.44 1.31 2.73 4.66 9.89 29.67 105.29]
# Reproduce an ISO 9613-1 Table 1 cell exactly (10 °C, 70 %, 1 kHz)
cell = environment.air_attenuation(1000.0, 10.0, 70.0, exact_midband=True) * 1000.0
print(round(float(cell), 2)) # 3.66 (dB/km, Table 1)
# Feed real conditions into the ISO 354 power attenuation coefficient m [1/m]
m = environment.air_attenuation_m([1000.0, 4000.0], temperature=20.0, relative_humidity=50.0)
print(np.round(m, 5)) # [0.00107 0.00683]

air_attenuation returns dB/m (Table 1 prints dB/km, i.e. ); it is fully vectorized over frequencies with scalar temperature, humidity and pressure. Passing exact_midband=True snaps each requested frequency onto the exact one-third-octave midband (Eq. (6), Note 5) used to compute Table 1, so the library reproduces every tabulated point to under 0.4 %, the standard’s own three-significant-figure precision, far inside its stated % accuracy (Clause 7.1). Inputs outside the tabulated ranges (−20…+50 °C, 10…100 % RH, 50…10 000 Hz, or above the 200 kPa validity envelope) still compute but raise an AtmosphericAbsorptionWarning; non-physical inputs (non-positive frequency, humidity outside 0…100 %, sub-absolute-zero temperature) raise ValueError. air_attenuation_m composes with the ISO 354 conversion so an ISO 354 caller can feed real atmospheric conditions straight into absorption_area / absorption_coefficient instead of hand-entering .

air_attenuation() / air_attenuation_m() parameters

Section titled “air_attenuation() / air_attenuation_m() parameters”
ParameterType / shapeUnitsRange / defaultNotes
frequenciesscalar or 1D arrayHz> 0Vectorized; 50–10 000 Hz tabulated
temperaturefloat°Cdefault 20.0−20…+50 tabulated; outside warns
relative_humidityfloat%default 50.010…100 tabulated; [0, 100] allowed
pressurefloatkPadefault 101.325≤ 200 valid (Clause 7); above warns
exact_midbandbooldefault FalseSnap to (reproduces Table 1)

air_attenuation returns in dB/m; air_attenuation_m returns in 1/m for ISO 354.

A plottable result: atmospheric_attenuation()

Section titled “A plottable result: atmospheric_attenuation()”

For a figure or a quick look, atmospheric_attenuation() wraps the same coefficient in a small AtmosphericAttenuation result. It carries the frequency grid, the coefficient and the atmospheric conditions, and exposes .plot() for the classic -versus-frequency curve (drawn in dB/km, the Table 1 unit, on a linear ordinate over a logarithmic frequency axis). Passing a distance also records the total attenuation , in decibels, over that path as total_attenuation, the ISO 9613-2 of Eq. (8).

from phonometry import environment
res = environment.atmospheric_attenuation(
[63, 125, 250, 500, 1000, 2000, 4000, 8000],
temperature=20.0, relative_humidity=50.0,
)
res.plot() # alpha in dB/km against frequency (needs matplotlib)
ISO 9613-1 pure-tone atmospheric attenuation coefficient alpha in dB/km against frequency, on a linear decibel ordinate over a logarithmic frequency axis, for the reference 20 degrees Celsius and 50 percent relative humidity atmosphere, produced by the AtmosphericAttenuation result plot methodISO 9613-1 pure-tone atmospheric attenuation coefficient alpha in dB/km against frequency, on a linear decibel ordinate over a logarithmic frequency axis, for the reference 20 degrees Celsius and 50 percent relative humidity atmosphere, produced by the AtmosphericAttenuation result plot method

On a linear decibel ordinate the coefficient stays near zero up to about 1 kHz and then climbs steeply, passing 20 dB/km near 3 kHz and reaching over 150 dB/km by 10 kHz at the reference 20 °C / 50 % RH atmosphere.

Show the code for this figure
import matplotlib.pyplot as plt
import numpy as np
from phonometry import environment
# One line: the coefficient curve straight from the result.
res = environment.atmospheric_attenuation(
np.geomspace(50.0, 10000.0, 400), temperature=20.0, relative_humidity=50.0,
)
res.plot()
plt.show()
# Or by hand from air_attenuation (dB/m, so scale by 1000 for dB/km):
freqs = np.geomspace(50.0, 10000.0, 400)
fig, ax = plt.subplots()
ax.semilogx(freqs, environment.air_attenuation(freqs, 20.0, 50.0) * 1000.0)
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Attenuation coefficient alpha [dB/km]")
plt.show()

2. General method of calculation (ISO 9613-2)

Section titled “2. General method of calculation (ISO 9613-2)”

ISO 9613-2:1996 predicts the octave-band level at a receiver downwind of a point source (or under the equivalent moderate temperature inversion, Clause 5). The equivalent-continuous downwind level is

(Eq. (3)/(4)) where is the octave-band sound power level, the directivity correction (directivity index plus a solid-angle index ), and the total attenuation. The library implements the four general terms of Clause 7; the informative (foliage, industrial sites, housing; Annex A) and reflections off vertical obstacles (Clause 7.5) are not implemented: the standard treats them as informative and they are left to the caller.

Every equation below is written for a point source, so the first modelling step is turning a real plant into a set of them (Clause 4). An extended source — a road, a rail line, an industrial site — is divided into sections, a line source into line sections and an area source into area sections, each carrying its own sound power and directivity and each represented by a point source at its centre. A group of point sources may then be collapsed into a single equivalent point source in the middle of the group, but only when all three of the standard’s conditions hold: the sources have approximately the same strength and the same height above the local ground plane, the propagation conditions from each of them to the receiver are the same, and the distance from the equivalent source to the receiver exceeds twice the largest dimension of the group (). If , or if the propagation conditions differ between sub-sources — one screened by a building, another not — Clause 4 requires the group to be split back into its components.

Applied to the case this section runs: a compressor hall whose radiating surfaces span 30 m collapses into one point source only beyond 60 m, so the 200 m receiver below is legitimate while a 50 m receiver on the same site is not, and there the hall has to be modelled face by face. The sound power itself is out of scope: it comes from a measurement of the ISO 3740 family or from the supplier’s declaration, in the eight octave bands from 63 Hz to 8 kHz. When only an A-weighted is available, the standard’s own fallback (Clause 1, Note 1) is to evaluate the attenuation terms at 500 Hz and apply them to that single number — an estimate, not a band prediction. The two CNOSSOS-EU emission guides, road and rail, stop exactly where this rule starts: both deliver a sound power per metre of source line and both declare the segmentation out of scope, so choosing the segment length and summing the segments energetically is the caller’s engineering decision.

The geometry of the screening term fixes the vocabulary: the diffraction edge splits the source-to-receiver distance into and , and the extra path length over the edge is . When the line of sight passes above the top edge, the standard gives a negative sign (Barrier(line_of_sight_clear=True)) and Eq. (14) still applies with : falls continuously from dB at grazing incidence to zero as the clearance deepens, never below zero.

ISO 9613-2 source-barrier-receiver geometry: a point source at height hs, a barrier whose top edge splits the path into dss and dsr, and a receiver at height hr, with the blocked direct ray and the diffracted ray over the edge, the path difference z and the Dz formulaISO 9613-2 source-barrier-receiver geometry: a point source at height hs, a barrier whose top edge splits the path into dss and dsr, and a receiver at height hr, with the blocked direct ray and the diffracted ray over the edge, the path difference z and the Dz formula
  • Geometrical divergence dB, m (Eq. (7)): spherical spreading from a point source. Exactly 51 dB at 100 m, +6 dB per distance doubling. The () sets the level at the 1 m reference distance.
  • Atmospheric absorption (Eq. (8)) with the ISO 9613-1 coefficient, negligible at low frequency and dominant at 8 kHz over long paths. is evaluated at the exact base-10 midband behind each nominal band label (7 943.3 Hz for “8 kHz”), the convention behind the ISO 9613-2 Table 2 coefficients (the nominal-frequency evaluation runs ~1.3 % high at 8 kHz). The ISO 9613-2 functions default to 20 °C and 70 % relative humidity (one of the Table 2 reference atmospheres the standard tabulates) while air_attenuation itself defaults to the ISO 9613-1 usual 50 %.
  • Ground effect (Eq. (9)) sums a source, receiver and middle region, each from the Table 3 functions and its ground factor (0 = hard/reflective, 1 = porous/absorbing). A negative is a net gain from constructive ground reflection.
  • Screening by a barrier is the diffraction insertion loss (Eq. (14)), capped at 20 dB (single edge) or 25 dB (double edge). For a top-edge barrier the ground effect of the screened path folds into it, (Eq. (12), Note 13); for a lateral barrier and the ground term is retained (Eq. (13)).

, and are not a vague softness: each is the porous fraction of a region whose extent the standard fixes (7.3.1, figure 1). Measured along the ground-plane distance , the source region runs from the source towards the receiver (capped at ), the receiver region runs back from the receiver, and the middle region is whatever is left between them. Hard cover — paving, water, ice, concrete, tamped ground — is ; porous cover — grass, trees, farmland — is ; a mixed region takes the fraction of its length that is porous.

Section to scale of a 200 m path with a source and a receiver 1.5 m above the ground: the source region shaded over the first 45 m as 30 times hs, the receiver region shaded over the last 45 m as 30 times hr, and the 110 m middle region between them hatched into 70 m of grass and 40 m of asphalt with Gm = 70/110 = 0.64; a formula box gives q = 1 minus 30 times (hs plus hr) over dp and an inset repeats the same path at 60 m where the source and receiver regions overlap, q = 0 and the middle region does not existSection to scale of a 200 m path with a source and a receiver 1.5 m above the ground: the source region shaded over the first 45 m as 30 times hs, the receiver region shaded over the last 45 m as 30 times hr, and the 110 m middle region between them hatched into 70 m of grass and 40 m of asphalt with Gm = 70/110 = 0.64; a formula box gives q = 1 minus 30 times (hs plus hr) over dp and an inset repeats the same path at 60 m where the source and receiver regions overlap, q = 0 and the middle region does not exist

On the 200 m example of this section ( m, so ) that is a 45 m source region, a 45 m receiver region and 110 m of middle: setting all three factors to 1.0 claims the whole 200 m is grass. A path leaving the plant across a 20 m concrete apron takes , and a middle region of 70 m of grass and 40 m of asphalt takes .

The middle region can also disappear. Table 3, note 2 defines when and below it, and is proportional to : with these two heights the threshold sits at m, so on a 60 m path ground_middle is ignored entirely — passing 0.0 or 1.0 returns the identical , silently. The same gives the sanity check for the whole term. Over hard ground everywhere dB and in every band, so the 200 m path must return dB () and the 60 m path the familiar dB of a perfectly reflecting plane. Run that check before trusting a ground factor: it is the one case with a closed-form answer. Water and ice count as hard ground for the fit, but ISO 9613-2 does not claim to cover propagation over water at all.

outdoor_propagation_attenuation assembles the four terms into an OutdoorAttenuation result whose per-band arrays sum, band by band, to a_total, so the divergence, atmospheric, ground and barrier contributions stay separable. The stacked breakdown makes the frequency character obvious: the barrier helps most at high frequency (short wavelength) until it saturates at the cap, atmospheric absorption bites only at 8 kHz, and the ground dip lives in the mid bands.

ISO 9613-2 per-octave-band attenuation breakdown as a stacked bar of Adiv, Aatm, Agr and Abar with the total A overlaid, for a 200 m path over porous ground with a 4 m barrierISO 9613-2 per-octave-band attenuation breakdown as a stacked bar of Adiv, Aatm, Agr and Abar with the total A overlaid, for a 200 m path over porous ground with a 4 m barrier

The four terms are signed and sum to the total: divergence is a flat 57.0 dB at 200 m, the barrier saturates at its 20 dB cap from 2 kHz up, the air only bites at 8 kHz (18.7 dB of the 95.8 dB total), and the ground is a gain of 4.65 dB at 63 Hz — which is why the barrier there has to spend before it buys anything.

Show the code for this figure
import matplotlib.pyplot as plt
import numpy as np
from phonometry import environment
bands = np.array([63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0, 8000.0])
barrier = environment.Barrier(source_to_edge=101.0, edge_to_receiver=101.0)
att = environment.outdoor_propagation_attenuation(
200.0, 1.5, 1.5, bands, ground_source=1.0, ground_middle=1.0,
ground_receiver=1.0, barrier=barrier, temperature=15.0,
relative_humidity=70.0,
)
# One line — the same stacked breakdown with the total overlaid:
att.plot()
# By hand:
x = np.arange(len(bands))
fig, ax = plt.subplots()
# Separate positive and negative baselines: a negative term (Agr is a net
# gain at 63 Hz here) stacks below zero, and the signed heights sum to a_total.
pos_bottom = np.zeros(len(bands))
neg_bottom = np.zeros(len(bands))
for term, label in [(att.a_div, "Adiv — divergence"),
(att.a_atm, "Aatm — atmospheric"),
(att.a_gr, "Agr — ground"),
(att.a_bar, "Abar — barrier")]:
ax.bar(x, term, bottom=np.where(term >= 0.0, pos_bottom, neg_bottom),
label=label)
pos_bottom += np.maximum(term, 0.0)
neg_bottom += np.minimum(term, 0.0)
ax.plot(x, att.a_total, "D-", color="black", label="A — total")
ax.set_xticks(x)
ax.set_xticklabels([f"{b:g}" for b in bands])
ax.set_xlabel("Octave-band centre frequency [Hz]")
ax.set_ylabel("Attenuation A [dB]")
ax.legend()
plt.show()
import numpy as np
from phonometry import environment
bands = [63, 125, 250, 500, 1000, 2000, 4000, 8000] # octave-band centres [Hz]
# A point source and receiver 1.5 m high, 200 m apart over porous ground
# (G = 1), screened midway by a barrier that raises the path over its top edge
# (dss = dsr ~ 101 m). Geometry feeds the pathlength-difference equations.
barrier = environment.Barrier(source_to_edge=101.0, edge_to_receiver=101.0)
att = environment.outdoor_propagation_attenuation(
200.0, source_height=1.5, receiver_height=1.5, frequencies=bands,
ground_source=1.0, ground_middle=1.0, ground_receiver=1.0,
barrier=barrier, temperature=15.0, relative_humidity=70.0,
)
print(np.round(att.a_div, 1)) # [57. 57. 57. 57. 57. 57. 57. 57.] divergence
print(np.round(att.a_gr, 2)) # [-4.65 2.34 13.79 9.76 1.3 -0. -0. -0. ]
print(np.round(att.a_bar, 2)) # [13.78 8.89 0. 6.69 18.01 20. 20. 20. ]
print(np.round(att.a_total, 1)) # [66.2 68.3 71. 73.9 77.1 78.8 82.3 95.8]
att.plot() # the stacked breakdown above (needs matplotlib)
# Predicted receiver level from an octave-band sound power Lw = 95 dB
lw = np.full(len(bands), 95.0)
lp = environment.predicted_receiver_level(
lw,
environment.PropagationGeometry(200.0, 1.5, 1.5), # d, hs, hr
frequencies=bands,
ground=environment.GroundFactors(1.0, 1.0, 1.0), # Gs, Gm, Gr
barrier=barrier,
atmosphere=environment.AtmosphericConditions(
temperature=15.0, relative_humidity=70.0),
)
print(np.round(lp, 1)) # [28.8 26.7 24. 21.1 17.9 16.2 12.7 -0.8]
# Dz on its own: the diffraction insertion loss of Eq. (14), before Eq. (12)
dz = environment.barrier_attenuation(barrier, 200.0, bands)
print(np.round(dz, 2)) # [ 9.13 11.24 13.73 16.45 19.31 20. 20. 20. ]
print(np.allclose(att.a_bar, np.maximum(dz - att.a_gr, 0.0))) # True
Waterfall chart over the eight octave bands from a flat 95 dB source sound power level down to the predicted downwind receiver level, with one descending step per attenuation term: divergence, atmospheric absorption, ground effect and barrier screening, the ground step rising instead of falling at 63 Hz, and the final level marked in each bandWaterfall chart over the eight octave bands from a flat 95 dB source sound power level down to the predicted downwind receiver level, with one descending step per attenuation term: divergence, atmospheric absorption, ground effect and barrier screening, the ground step rising instead of falling at 63 Hz, and the final level marked in each band

Where the 95 dB of source power goes, band by band: divergence spends the same 57.0 dB everywhere, the barrier is worth nothing at 250 Hz and 20 dB above 2 kHz, and at 8 kHz the air alone removes 18.7 dB and takes the receiver level below 0 dB. The 63 Hz column is the only one where a step goes up: the ground returns 4.65 dB before the barrier takes it away again.

Show the code for this figure
import matplotlib.pyplot as plt
import numpy as np
# `att`, `bands` and `lw` are the objects the snippet above already built.
level = lw.copy()
fig, ax = plt.subplots()
for term, label in [(att.a_div, "-Adiv"), (att.a_atm, "-Aatm"),
(att.a_gr, "-Agr"), (att.a_bar, "-Abar")]:
ax.bar(np.arange(len(bands)), -term, bottom=level, label=label)
level = level - term
ax.plot(np.arange(len(bands)), level, "D-", color="black", label="LfT(DW)")
ax.set_xticks(np.arange(len(bands)))
ax.set_xticklabels([f"{b:g}" for b in bands])
ax.set_xlabel("Octave-band centre frequency [Hz]")
ax.set_ylabel("Level [dB]")
ax.legend()
plt.show()

barrier_attenuation returns itself — the raw diffraction insertion loss of Eq. (14) — which is not what the composite reports. For a top-edge barrier a_bar is np.maximum(dz - a_gr, 0) (Eq. (12), Note 13), and the equality printed above is the cleanest way to see that the ground effect is spent rather than kept: at 250 Hz the screened path had 13.79 dB of ground attenuation and 13.73 dB of diffraction, so the barrier contributes exactly nothing. is also where the 20 dB single-edge and 25 dB double-edge caps bite, so printing it is how a reader learns that the wall has saturated and extra height buys nothing (here, from 2 kHz upwards). Only for a lateral barrier (lateral=True, Eq. (13)) does a_bar equal .

predicted_receiver_level composes with the DirectivityCorrection (index d_omega). Pass c0= to subtract the meteorological correction (Eq. (21)/(22)) band by band for a long-term average; note that the standard applies to the A-weighted level, so the per-band form here is a convenience, not a literal reading of Clause 8.

When only the A-weighted receiver level matters and the sound travels over porous or mostly-porous ground (and is not a pure tone), 7.3.2 offers a simpler closed form (Eq. (10), negative results clamped to zero), paired with the solid-angle index (Eq. (11)) that must then be added to . These are exposed as ground_attenuation_alternative and directivity_omega, but they are not auto-wired into outdoor_propagation_attenuation (which always uses the general per-region method of 7.3.1); combine them by hand when the alternative method is appropriate.

is not the average of the two end heights. Figure 3 defines it as , where is the area enclosed between the straight source-receiver line and the ground profile: over flat ground it reduces to , over a cutting it collapses towards zero, and over a valley crossed by a high path it grows well beyond either end height. That single term is how the alternative method absorbs terrain shape, and reading it as a height is the mistake that flatters a prediction. Note the direction of the clamp: is capped below at 0, so a path riding high above the ground earns no ground attenuation at all (at m, m still gives 3.32 dB but m at 50 m gives 0.00 dB), while a grazing path earns the full 4.8 dB. The three validity conditions travel with the formula: the A-weighted level alone, porous or mostly-porous ground, and no pure tone. Anything else goes back to the per-region method of 7.3.1.

from phonometry import environment
# Alternative ground term (mean path height hm = F/d = 2 m, d = 200 m)
print(round(environment.ground_attenuation_alternative(200.0, 2.0), 2)) # 4.43 dB
# The clamp: a high path over a short distance earns nothing at all
print(round(environment.ground_attenuation_alternative(50.0, 8.0), 2)) # 0.0 dB
# Its companion solid-angle index (add to Dc when using Eq. (10))
print(round(environment.directivity_omega(1.5, 1.5, 200.0), 2)) # 3.01 dB
# Long-term meteorological correction (C0 = 2 dB) to subtract from LAT(DW)
print(round(environment.meteorological_correction(200.0, 1.5, 1.5, 2.0), 2)) # 1.7 dB

Every entry of Table 3 is an engineering fit to one physical picture: the receiver hears two copies of the source, the direct ray and a reflection that arrives exactly as if it were radiated by an image source mirrored below the ground plane. The two copies interfere according to the path difference (about for a grazing far-field path): in phase they add up to dB; at over a rigid plane they cancel into a sharp dip.

A point source at height hs and a receiver microphone at height hr over a hatched ground plane; a straight direct ray r1 connects them and a reflected ray bounces at the specular point with equal grazing angles; the reflection is unfolded as a dashed straight ray r2 from a ghosted image source mirrored below the ground, and the annotations give the path difference delta = r2 minus r1, the interference phase 2 pi delta over lambda plus the reflection phase, the in-phase gain of up to +6 dB and the deep dip at half a wavelength over hard groundA point source at height hs and a receiver microphone at height hr over a hatched ground plane; a straight direct ray r1 connects them and a reflected ray bounces at the specular point with equal grazing angles; the reflection is unfolded as a dashed straight ray r2 from a ghosted image source mirrored below the ground, and the annotations give the path difference delta = r2 minus r1, the interference phase 2 pi delta over lambda plus the reflection phase, the in-phase gain of up to +6 dB and the deep dip at half a wavelength over hard ground

Over acoustically hard ground () the reflection coefficient stays close to in every octave, the long-wavelength sum is fully constructive, and the general method duly returns dB in each band. Porous ground turns the reflection coefficient complex and angle-dependent (for a point source near grazing incidence, the spherical-wave coefficient of the Chien-Soroka solution, with a ground-wave term no plane-wave picture captures): part of the reflection flips phase, and the destructive notch lands in the 250 to 1000 Hz octaves. That notch is precisely what the to height-and-distance functions of Table 3 parameterize, with blending the hard and porous behaviours. The same two-ray geometry carries over to aircraft lateral attenuation and to every ray-based outdoor model; Salomons and Attenborough & Van Renterghem develop the full theory that the engineering fit compresses.

A negative (a net gain) is plain interference: the ground-reflected wave adds to the direct one. Below, a 400 Hz source 1.5 m over rigid ground builds the lobe pattern of that interference, and the level sampled on an arc converges to the two-path image-source model, dips included.

A 2D FDTD simulation of a 400 Hz point source 1.5 metres above rigid ground. The direct and ground-reflected wavefronts interfere and a lobe pattern forms, the ghosted image source below the ground explains the geometry, and the level sampled on an 8 metre arc converges to the two-path image-source model with its predicted nulls.

Download the animation (WebM)

A 2D FDTD simulation of a 400 Hz point source 1.5 metres above rigid ground. The direct and ground-reflected wavefronts interfere and a lobe pattern forms, the ghosted image source below the ground explains the geometry, and the level sampled on an 8 metre arc converges to the two-path image-source model with its predicted nulls.

Download the animation (WebM)

The Barrier dataclass describes the diffraction geometry directly, which is the cleanest match to Eq. (14)/(16)/(17). Single diffraction (a thin screen) leaves edge_separation=None (); giving the edge spacing e selects double (thick-barrier) diffraction with the factor of Eq. (15) and the 25 dB cap. ground_reflections_by_image=True switches from 20 to 40 (reflections handled by image sources), and lateral=True selects vertical-edge diffraction (Eq. (13), , ground term retained).

The simulation below shows why grows with frequency: against the same 2.5 m screen, a 100 Hz wavefront () diffracts over the edge and fills the shadow zone, while at 500 Hz the shadow is deep and sharp. A barrier only works when the wavelength is short next to the path difference.

A 2D FDTD simulation of a point source behind a thin 2.5 metre rigid barrier on reflecting ground, at 100 Hz and 500 Hz side by side. The long wavelength diffracts over the edge and fills the shadow zone with an insertion loss near 8 dB, while the short wavelength is cast into a deep clean shadow of about 17 dB.

Download the animation (WebM)

A 2D FDTD simulation of a point source behind a thin 2.5 metre rigid barrier on reflecting ground, at 100 Hz and 500 Hz side by side. The long wavelength diffracts over the edge and fills the shadow zone with an insertion loss near 8 dB, while the short wavelength is cast into a deep clean shadow of about 17 dB.

Download the animation (WebM)

outdoor_propagation_attenuation() parameters

Section titled “outdoor_propagation_attenuation() parameters”
ParameterType / shapeUnitsRange / defaultNotes
distancefloatm> 0Straight-line source–receiver distance
source_height / receiver_heightfloatm≥ 0, above ground
frequencies1D arrayHzdefault 8 octaves 63–8000DEFAULT_FREQUENCIES
ground_source / ground_middle / ground_receiverfloat[0, 1], default 0.0Ground factor (0 hard, 1 porous)
barrierBarrier or Nonedefault NoneScreening obstacle
temperature / relative_humidity / pressurefloat°C / % / kPa20 / 70 / 101.325Passed to
projected_distancefloat or Nonemdefault Ground-plane

Returns an OutdoorAttenuation with a_div, a_atm, a_gr, a_bar, a_total and d_omega, all one value per band; its .plot() draws the stacked per-band breakdown with the total overlaid (the figure above).

FieldTypeUnitsDefaultNotes
source_to_edgefloatm, source to first edge
edge_to_receiverfloatm, (last) edge to receiver
parallel_distancefloatm0.0Component parallel to the edge
edge_separationfloat or NonemNone; given ⇒ double diffraction (25 dB cap)
ground_reflections_by_imageboolFalseTrue
lateralboolFalseTrue ⇒ vertical-edge diffraction (Eq. (13))
line_of_sight_clearboolFalseTrue ⇒ the sight line passes above the top edge: the path difference takes a negative sign and (text after Eq. (16))

What “favourable propagation conditions” means

Section titled “What “favourable propagation conditions” means”

ISO 9613-2 does not predict the level under the weather of the moment. Every equation assumes conditions favourable to propagation (Clause 5): wind blowing from source to receiver (within about 45° of the connecting line, at roughly 1 to 5 m/s measured 3 to 11 m above ground), or the moderate ground-based temperature inversion of a clear, calm night, which curves sound rays downward the same way. Downward refraction closes the acoustic shadow zones that upwind or neutral atmospheres would form, so the predicted is close to the highest level the geometry can deliver: over a year the actual level is usually lower and rarely meaningfully higher. The choice is deliberate. Complaints arrive on the still nights when a distant plant is clearly audible, not on the gusty afternoons when it vanishes, and a method that predicts the audible case protects the assessment. The long-term average is recovered by subtracting (Eq. (21)/(22)), whose encodes how often the wind actually favours the path (about dB when half the time is favourable, values above 2 dB already exceptional, Notes 20/22). The stated to dB accuracy (Table 5) holds under favourable conditions, for broadband sources, up to 1000 m; beyond that the standard makes no accuracy claim at all.

The screening term is the easiest one to over-trust; four fine points decide whether a real barrier delivers its computed :

  • The caps are physical, not editorial. is capped at 20 dB for single and 25 dB for double diffraction no matter how tall the wall, because atmospheric turbulence scatters sound into the shadow zone and sets a ceiling that extra height cannot buy back. An insertion loss beyond roughly 20 dB is enclosure territory, not screen territory. Eq. (14) itself is a smoothed engineering curve in the tradition of Maekawa’s screen chart, an empirical fit over three decades of Fresnel number .
  • quietly erodes distant barriers. The meteorological factor (Eq. (18)) discounts the screening because the same downward-curved rays that make conditions favourable also pass over the top edge. Within 100 m of source-receiver distance (Note 17), but for a long path with a small path difference it can strip several decibels off a barrier that looks generous on the section drawing.
  • Double diffraction is a modest bonus. A thick obstacle (two edges separated by ) raises from 1 toward 3 (Eq. (15)), worth at most about dB extra plus the higher 25 dB cap. A building modelled as a double edge only earns that bonus if both edges really are continuous and the roof between them is closed.
  • The ground effect is spent, not kept. For a top-edge barrier the standard folds the screened path’s ground effect into the diffraction: (Eq. (12), Note 13). Over porous ground that was already providing 5 to 10 dB of in the mid bands, the net gain of building the barrier is correspondingly smaller than its nominal ; the two effects do not stack.
Two panels on the ISO 9613-2 screening term. Left: the diffraction insertion loss Dz at 500 Hz against barrier height for a 200 m path, one curve for a single edge, one for a double edge with an edge separation of 2 m and one for the single edge with the meteorological factor Kmet, with the 20 dB and 25 dB caps drawn as horizontal ceilings the curves run into. Right: Dz against octave-band frequency for a 4 m screen next to Abar = Dz minus Agr over porous ground, the gap between the two curves being the ground effect the barrier has to spend before it buys anything, and Abar clamped at zero in the 250 Hz bandTwo panels on the ISO 9613-2 screening term. Left: the diffraction insertion loss Dz at 500 Hz against barrier height for a 200 m path, one curve for a single edge, one for a double edge with an edge separation of 2 m and one for the single edge with the meteorological factor Kmet, with the 20 dB and 25 dB caps drawn as horizontal ceilings the curves run into. Right: Dz against octave-band frequency for a 4 m screen next to Abar = Dz minus Agr over porous ground, the gap between the two curves being the ground effect the barrier has to spend before it buys anything, and Abar clamped at zero in the 250 Hz band

Left: extra height stops paying once meets its cap — beyond about 7 m of screen on this path the single-edge curve is flat at 20 dB, and has already taken 1 to 2 dB off it at 200 m. Right: the two curves are the same barrier; the gap between them is , and where the ground was already worth more than the diffraction (the 250 Hz octave) the net is zero.

Show the code for this figure
import matplotlib.pyplot as plt
import numpy as np
# `environment` is the module imported by the section 1 snippet.
heights = np.linspace(1.6, 12.0, 60)
single, double = [], []
for h in heights:
# A screen midway on a 200 m path; dss = dsr from the geometry.
leg = float(np.hypot(100.0, h - 1.5))
single.append(float(environment.barrier_attenuation(
environment.Barrier(source_to_edge=leg, edge_to_receiver=leg),
200.0, [500.0])[0]))
double.append(float(environment.barrier_attenuation(
environment.Barrier(source_to_edge=leg, edge_to_receiver=leg,
edge_separation=2.0), 200.0, [500.0])[0]))
fig, ax = plt.subplots()
ax.plot(heights, single, label="Single edge")
ax.plot(heights, double, label="Double edge, e = 2 m")
ax.axhline(20.0, linestyle=":", label="20 dB cap")
ax.axhline(25.0, linestyle=":", label="25 dB cap")
ax.set_xlabel("Barrier height [m]")
ax.set_ylabel("Dz at 500 Hz [dB]")
ax.legend()
plt.show()

The clear-sight case the vocabulary paragraph describes is one call away, and it is worth running once: does not drop to zero the moment the sight line clears the edge, it decays from dB over the first few centimetres of path difference.

for extra in (0.0, 0.001, 0.010, 0.050): # path difference above the edge [m]
clear = environment.Barrier(source_to_edge=100.0 + extra / 2,
edge_to_receiver=100.0 + extra / 2,
line_of_sight_clear=True)
print(round(float(environment.barrier_attenuation(clear, 200.0, [500.0])[0]), 3))
# 4.771, 4.728, 4.323, 1.845 dB at 500 Hz

An obstacle must also qualify as a barrier at all (Clause 7.4): surface density at least 10 kg/m², a closed surface without large gaps, and a horizontal extent normal to the path larger than the wavelength. A slatted fence or a short container screens far less than Eq. (14) promises.

Two frameworks dominate outdoor noise prediction in Europe, and they answer different questions:

  • ISO 9613-2 is a general engineering attenuation method: given the octave-band sound power of any source you can decompose into point sources, it returns the favourable-condition receiver level. Source emission is out of scope; the sound power comes from measurement (the ISO 3740 family) or from the equipment supplier. It is the workhorse of industrial-plant and environmental impact predictions assessed with ISO 1996-2.
  • CNOSSOS-EU (Common Noise Assessment Methods in Europe) is the mandatory common framework for the strategic noise maps of the Environmental Noise Directive 2002/49/EC, adopted as its Annex II by Commission Directive (EU) 2015/996. It bundles emission models for road, rail and industrial sources (and delegates aircraft to ECAC Doc 29) with its own propagation part derived from the French NMPB 2008 method, producing the / indicators the Directive reports. This library implements the CNOSSOS-EU emission half on CNOSSOS-EU road emission and CNOSSOS-EU rail emission; the CNOSSOS-EU propagation method of 2.5 is not implemented, so carrying a CNOSSOS line power through the ISO 9613-2 chain on this page is an engineering estimate and not the normative chain the Directive prescribes.

The propagation parts disagree by design, not by accident. CNOSSOS-EU evaluates every path twice, once under a homogeneous atmosphere and once under favourable (downward-refracting) conditions, and combines the two long-term with the local occurrence probability of favourable conditions per path direction; ISO 9613-2 computes only the favourable case and subtracts a scalar . The ground effect in CNOSSOS-EU is built from a path-averaged ground factor over a fitted mean plane, with expressions that change between the two atmospheres, where ISO 9613-2 uses the fixed three-region Table 3. Diffraction, too, follows a different formulation that couples the ground effect on each side of the edge. Run both on the same geometry and the octave-band results can differ by several decibels, each internally consistent. The practical rule: END strategic maps and anything that must be comparable across EU member states use CNOSSOS-EU; a plant permit, a compliance prediction against a measured sound power, or work under regulations that cite ISO 9613 use this module. (ISO published a revised ISO 9613-2 in 2024; this library implements the 1996 edition, the one most national regulations and the validation literature still reference.)

See the Theory page for the full derivation, the Room Acoustics guide for how feeds ISO 354, and the Occupational Noise Exposure guide for the ISO 9612 occupational exposure that consumes A-weighted levels.

Both outdoor-propagation results render a one-page PDF prediction fiche. They are clearly labelled predictions, not measurements: the sheet states the meteorological and ground assumptions and, for the barrier, names the actual diffraction model behind the number.

OutdoorAttenuation.report(path) boxes the octave-band range of the total attenuation on its own; pass a SourceEmission (the source sound power and directivity) to add the source power and downwind level to the table and box the A-weighted downwind level at the receiver instead. A limit level supplied through the metadata requirement then adds a PASS/FAIL verdict (a lower level is better). Pass language="es" for the Spanish fiche.

import numpy as np
from phonometry import (
Barrier,
ReportMetadata,
SourceEmission,
outdoor_propagation_attenuation,
)
freqs = np.array([63, 125, 250, 500, 1000, 2000, 4000, 8000], dtype=float)
lw = np.array([95, 100, 103, 105, 104, 101, 95, 88], dtype=float)
result = outdoor_propagation_attenuation(
200.0, 4.0, 2.0, freqs, 1.0, 1.0, 1.0,
barrier=Barrier(source_to_edge=105.0, edge_to_receiver=105.0),
temperature=10.0, relative_humidity=70.0,
)
result.report(
"outdoor_attenuation.pdf",
metadata=ReportMetadata(
specimen="Industrial fan plant (point source)",
test_room="Nearest dwelling facade",
requirement=50.0, # maximum acceptable A-weighted downwind level
),
source_emission=SourceEmission(sound_power_level=lw),
)
ISO 9613-2 outdoor propagation example report (PDF)

One-page ISO 9613-2 prediction fiche: a metadata header with the propagation distance, a per-band table of the source power level Lw and the divergence, atmospheric, ground and barrier attenuation terms with the total A and the downwind level LfT(DW), the attenuation-breakdown plot and the boxed A-weighted downwind level LAT(DW) = 29.9 dB with a PASS verdict against a 50 dB limit.

Download the report (PDF)

Outdoor propagation fiche (OutdoorAttenuation.report), the A-weighted downwind level at the receiver.

Before committing the fiche, result.plot() draws the same per-band attenuation breakdown interactively (the stacked figure of section 2).

BarrierInsertionLoss.report(path) boxes the mean insertion loss over the octave bands; a minimum required insertion loss supplied through requirement adds a PASS/FAIL verdict (a higher insertion loss is better).

import numpy as np
from phonometry import ReportMetadata, barrier_insertion_loss
freqs = np.array([63, 125, 250, 500, 1000, 2000, 4000, 8000], dtype=float)
# hs = 1 m, barrier 4 m high at 50 m, receiver 1.5 m high at 100 m *from the
# source*; method="exact" is the wave-theoretic rigid half-plane the fiche names.
result = barrier_insertion_loss(freqs, 1.0, 50.0, 4.0, 100.0, 1.5, method="exact")
result.report(
"barrier_insertion_loss.pdf",
metadata=ReportMetadata(
specimen="Roadside noise barrier, 4 m high",
requirement=8.0, # minimum required mean insertion loss
),
)
Barrier insertion loss example report (PDF)

One-page barrier insertion-loss prediction fiche: a metadata header naming the ground model, a per-band table of the insertion loss, the insertion-loss spectrum plot and the boxed mean insertion loss IL = 12.9 dB with a PASS verdict against an 8 dB minimum. The basis line names the wave-theoretic rigid-screen diffraction model, a complement to the ISO 9613-2 screening term.

Download the report (PDF)

Barrier insertion loss fiche (BarrierInsertionLoss.report), the mean insertion loss over the octave bands.

Here too result.plot() previews the insertion-loss spectrum of the fiche; the ground and barriers guide draws the same result against the exact half-plane and coherent-ground models.