Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/reports/hvac_duct_noise_example.pdf
Binary file not shown.
Binary file added .github/reports/hvac_duct_noise_example.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/reports/reactive_silencer_example.pdf
Binary file not shown.
Binary file added .github/reports/reactive_silencer_example.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
the metadata `requirement` adds a PASS/FAIL verdict (a higher SII passes).
`verbose=True` adds the equivalent disturbance spectrum level `Di` column;
`language="es"` renders the Spanish fiche.
- Noise-control performance reports via `.report()` on the three
`noise_control` result types, each a one-page PDF laid out with a per-band
table beside the result's own plot, a boxed single-number performance figure
and an optional PASS/FAIL verdict:
- `EnclosureResult.report()`: a machine-enclosure insertion-loss fiche (Bies,
Hansen & Howard, Engineering Noise Control 5th ed., section 7.4.2). The
per-band table lists the supplied panel transmission loss `R`, the interior
build-up correction `C` and the net insertion loss `IL = R - C`; the boxed
figure is the mean insertion loss over the analysis bands with the external
and internal surface areas. A declared minimum via the metadata
`requirement` passes when the mean insertion loss meets it (more is
better); `verbose=True` adds the interior room constant `R_i` column.
- `ReactiveSilencerResult.report()`: a reactive-silencer transmission-loss
fiche (Munjal, Acoustics of Ducts and Mufflers 2nd ed., Eq. (3.27); Bies,
Hansen & Howard, sections 8.8-8.9). The per-band table lists the
transmission loss `TL` and, when end impedances were supplied, the
insertion loss `IL`; the boxed figure is the mean transmission loss with
the peak transmission loss and the device kind. A declared minimum passes
when the mean transmission loss meets it (more is better).
- `HvacSpectrumResult.report()`: an HVAC duct-noise-spectrum fiche (Bies,
Hansen & Howard, Chapter 8; VDI 2081-1). A regenerated-noise spectrum boxes
the A-weighted sound power level `L_WA` (dB(A) re 1 pW) with the overall
unweighted total, and a declared limit passes at or below it (lower is
better); an attenuation spectrum boxes the mean attenuation, and a declared
minimum passes at or above it. `verbose=True` adds the A-weighting
correction and A-weighted band-level columns for a regenerated-noise
spectrum.

All three accept an optional metadata header (client, equipment, test
environment, instrumentation, climate, date), state their method basis, and
render in English or Spanish (`language="es"`).
- `StructureBornePowerResult.report()`: a one-page PDF structure-borne sound
power characterization fiche for the power a piece of building service
equipment injects into a reception plate (EN 15657:2018 reception-plate
Expand Down
107 changes: 107 additions & 0 deletions scripts/generate_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -2414,6 +2414,110 @@ def _sii_example() -> Tuple[object, ReportMetadata, str]:
requirement=0.75, # SII = 0.851 >= 0.75 -> PASS (good audibility)
)
return result, metadata, "ansi_s3_5_sii_example.pdf"
def _enclosure_example() -> Tuple[object, ReportMetadata, str]:
"""Enclosure fiche: the insertion loss of a machine enclosure (Bies 7.4.2).

A documented clean-room case combining a supplied octave-band panel
transmission loss R = [18, 22, 28, 33, 38, 42, 45] dB (a sheet-steel
enclosure) with an interior of mean absorption alpha_i = 0.30, external
surface area S_E = 24 m2 and internal surface area S_i = 30 m2. The interior
room constant R_i = S_i alpha_i / (1 - alpha_i) = 30 x 0.3 / 0.7 = 12.86 m2,
the build-up correction C = 10 lg(0.3 + S_E / R_i) = 10 lg(0.3 + 24/12.86)
= 3.4 dB and the net insertion loss IL = R - C (Bies, Hansen & Howard,
Engineering Noise Control 5th ed., Eqs. (7.103), (7.111)), giving a mean
insertion loss of 28.9 dB over the seven octave bands. The requirement is a
plausible minimum mean insertion loss the example clears (more is better).
"""
freqs = np.array([63, 125, 250, 500, 1000, 2000, 4000], dtype=float)
panel_r = np.array([18, 22, 28, 33, 38, 42, 45], dtype=float)
result = ph.enclosure_insertion_loss(
panel_r, 24.0, 30.0, 0.30, frequencies=freqs
)
metadata = ReportMetadata(
specimen="Sheet-steel close-fitting machine enclosure",
client="Example client",
manufacturer="Example enclosures",
test_room="Machine hall, line 3 (example)",
instrumentation="Class 1 SLM (IEC 61672-1), octave bank",
measurement_standard="Bies & Hansen 7.4.2",
temperature=21.0,
relative_humidity=45.0,
pressure=101.2,
test_date="2026-07-22",
laboratory="Phonometry reference example",
operator="phonometry",
report_id="EXAMPLE-ENCLOSURE",
requirement=20.0,
)
return result, metadata, "enclosure_insertion_loss_example.pdf"


def _silencer_example() -> Tuple[object, ReportMetadata, str]:
"""Silencer fiche: the transmission loss of an expansion chamber (four-pole).

A documented clean-room case: a simple expansion chamber of length L = 0.5 m
and area S_exp = 0.08 m2 between pipes of area S_duct = 0.01 m2 (area ratio
m = 8), sampled at the octave-band centres 63 Hz to 4 kHz by the plane-wave
four-pole method (Munjal, Acoustics of Ducts and Mufflers 2nd ed., Eq.
(3.27); Bies, Hansen & Howard, Engineering Noise Control 5th ed., Eq.
(8.111)). The transmission loss matches the closed form
TL = 10 lg[1 + (1/4)(m - 1/m)^2 sin^2(kL)], peaking near
10 lg[1 + (1/4)(8 - 1/8)^2] = 12.2 dB, with a mean of 8.9 dB over the seven
bands. The requirement is a plausible minimum mean transmission loss the
example clears (more is better).
"""
freqs = np.array([63, 125, 250, 500, 1000, 2000, 4000], dtype=float)
result = ph.noise_control.silencers.expansion_chamber(
freqs, 0.5, 0.08, 0.01
)
metadata = ReportMetadata(
specimen="Simple expansion-chamber muffler (m = 8)",
client="Example client",
manufacturer="Example silencers",
test_room="Duct acoustics rig (example)",
instrumentation="Two-microphone transfer-matrix bench",
measurement_standard="Munjal Eq. (3.27)",
temperature=20.0,
pressure=101.3,
test_date="2026-07-22",
laboratory="Phonometry reference example",
operator="phonometry",
report_id="EXAMPLE-SILENCER",
requirement=6.0,
)
return result, metadata, "reactive_silencer_example.pdf"


def _hvac_example() -> Tuple[object, ReportMetadata, str]:
"""HVAC fiche: the flow-generated noise of a straight duct (VDI 2081-1).

A documented clean-room case: the flow-generated octave-band sound power
level of a straight duct carrying air at U = 12 m/s in a cross-section of
S = 0.04 m2, L_WB = 7 + 50 lg U + 10 lg S - 2 - 26 lg(1.14 + 0.02 f / U)
dB re 1 pW (VDI 2081-1; Bies, Hansen & Howard, Engineering Noise Control
5th ed., Eq. (8.251)). Combining the seven octave bands with the ISO 3744
Annex E A-weighting corrections gives the A-weighted sound power level
L_WA = 38.8 dB(A) re 1 pW (overall unweighted L_W = 47.0 dB). The
requirement is a plausible maximum A-weighted level the example clears
(lower is better).
"""
freqs = np.array([63, 125, 250, 500, 1000, 2000, 4000], dtype=float)
result = ph.noise_control.hvac.flow_noise_straight_duct(freqs, 12.0, 0.04)
metadata = ReportMetadata(
specimen="Straight supply duct, 0.04 m2 cross-section",
client="Example client",
test_room="Air-handling plant room (example)",
instrumentation="In-duct sound power (ISO 5136 method)",
measurement_standard="VDI 2081-1",
temperature=21.0,
pressure=101.2,
test_date="2026-07-22",
laboratory="Phonometry reference example",
operator="phonometry",
report_id="EXAMPLE-HVAC",
requirement=45.0,
)
return result, metadata, "hvac_duct_noise_example.pdf"


#: Every example fiche the repository keeps rendered. New report kinds append
Expand Down Expand Up @@ -2465,6 +2569,9 @@ def _sii_example() -> Tuple[object, ReportMetadata, str]:
_flanking_impact_level_example,
_sti_example,
_sii_example,
_enclosure_example,
_silencer_example,
_hvac_example,
]


Expand Down
46 changes: 46 additions & 0 deletions site/src/content/docs/reference/api/noise_control/enclosures.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,49 @@ Plot the panel `R`, correction `C` and net insertion loss.

Requires matplotlib (`pip install phonometry[plot]`); returns the
`Axes`.

### EnclosureResult.report()

```python
EnclosureResult.report(
path: str,
*,
metadata: ReportMetadata | None = None,
engine: str = 'reportlab',
verbose: bool = False,
language: str = 'en',
) -> str
```

Render a machine-enclosure insertion-loss fiche to `path`.

Writes a one-page enclosure-performance sheet: the method-basis line
naming the Bies, Hansen & Howard insertion-loss model
(Engineering Noise Control 5th ed., section 7.4.2), an optional metadata
header (client, enclosed machine, test environment, instrumentation,
climate, date), a per-band table (nominal frequency, the supplied panel
transmission loss `R`, the interior build-up correction `C` and the
net insertion loss `IL = R - C`) beside the `R`, `C` and `IL`
curves, the boxed mean insertion loss over the analysis bands with the
external and internal surface areas, an optional verdict row against a
declared minimum, and a method-basis strip stating
`IL = R - C` with `C = 10 lg(0.3 + S_E / R_i)`.

**Parameters**

| Name | Description |
| :--- | :--- |
| `path` | Destination path of the PDF file. |
| `metadata` | Optional [`ReportMetadata`](/phonometry/reference/api/building/insulation/#reportmetadata) supplying the header (`client`, `specimen` the enclosed machine, `test_room` the test environment, `instrumentation`, `temperature`, `relative_humidity`, `pressure`, `test_date`), the footer identity (`laboratory`, `operator`, `report_id`, `notes`) and, via `requirement`, a declared minimum mean insertion loss (more insertion loss is better). The surface areas come from the result itself. |
| `engine` | Rendering back end; only `"reportlab"` is supported. |
| `verbose` | When `True` the per-band table adds the interior room constant `R_i` column. |
| `language` | Fiche language: `"en"` (default) or `"es"`. |

**Returns:** The written `path` as a `str`.

**Raises**

| Exception | When |
| :--- | :--- |
| ValueError | If `engine` is not `"reportlab"` or `language` is unknown. |
| ImportError | If reportlab (or, for the figure, matplotlib) is not installed (`pip install phonometry[report]`). |
46 changes: 46 additions & 0 deletions site/src/content/docs/reference/api/noise_control/hvac.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,52 @@ Plot the quantity against a continuous log-frequency axis.

Requires matplotlib (`pip install phonometry[plot]`).

### HvacSpectrumResult.report()

```python
HvacSpectrumResult.report(
path: str,
*,
metadata: ReportMetadata | None = None,
engine: str = 'reportlab',
verbose: bool = False,
language: str = 'en',
) -> str
```

Render an HVAC duct-noise-spectrum fiche to `path`.

Writes a one-page HVAC-noise sheet: the method-basis line naming the
reported quantity and the Bies, Hansen & Howard chapter (Engineering
Noise Control 5th ed., Chapter 8), an optional metadata header (client,
duct element, test environment, instrumentation, climate, date), a
per-band table (nominal frequency and the reported quantity) beside the
spectrum, the boxed single-number result (for a regenerated-noise
spectrum the A-weighted sound power level `L_WA` re 1 pW with the
overall unweighted total; for an attenuation spectrum the mean
attenuation with its band range), an optional verdict row against a
declared limit, and a method-basis strip stating the reported quantity's
relation.

**Parameters**

| Name | Description |
| :--- | :--- |
| `path` | Destination path of the PDF file. |
| `metadata` | Optional [`ReportMetadata`](/phonometry/reference/api/building/insulation/#reportmetadata) supplying the header (`client`, `specimen` the duct element, `test_room` the test environment, `instrumentation`, `temperature`, `relative_humidity`, `pressure`, `test_date`), the footer identity (`laboratory`, `operator`, `report_id`, `notes`) and, via `requirement`, a declared maximum A-weighted sound power level for a regenerated-noise spectrum (lower is better) or a declared minimum mean attenuation for an attenuation spectrum (more is better). |
| `engine` | Rendering back end; only `"reportlab"` is supported. |
| `verbose` | When `True` a regenerated-noise table adds the A-weighting correction and the A-weighted band level columns. |
| `language` | Fiche language: `"en"` (default) or `"es"`. |

**Returns:** The written `path` as a `str`.

**Raises**

| Exception | When |
| :--- | :--- |
| ValueError | If `engine` is not `"reportlab"` or `language` is unknown. |
| ImportError | If reportlab (or, for the figure, matplotlib) is not installed (`pip install phonometry[report]`). |

## plenum_attenuation

```python
Expand Down
47 changes: 47 additions & 0 deletions site/src/content/docs/reference/api/noise_control/silencers.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,50 @@ Plot the transmission (and insertion) loss against frequency.

Requires matplotlib (`pip install phonometry[plot]`); returns the
`Axes`.

### ReactiveSilencerResult.report()

```python
ReactiveSilencerResult.report(
path: str,
*,
metadata: ReportMetadata | None = None,
engine: str = 'reportlab',
verbose: bool = False,
language: str = 'en',
) -> str
```

Render a reactive-silencer transmission-loss fiche to `path`.

Writes a one-page silencer-performance sheet: the method-basis line
naming the plane-wave four-pole (transfer-matrix) method (Munjal,
Acoustics of Ducts and Mufflers 2nd ed., Eq. (3.27); Bies, Hansen &
Howard, Engineering Noise Control 5th ed., sections 8.8-8.9), an
optional metadata header (client, device, test environment,
instrumentation, climate, date), a per-band table (nominal frequency,
the transmission loss `TL` and, when computed, the insertion loss
`IL`) beside the `TL` (and `IL`) curves, the boxed mean
transmission loss over the analysis bands with the peak transmission
loss and the device kind, an optional verdict row against a declared
minimum, and a method-basis strip stating the four-pole
transmission-loss relation.

**Parameters**

| Name | Description |
| :--- | :--- |
| `path` | Destination path of the PDF file. |
| `metadata` | Optional [`ReportMetadata`](/phonometry/reference/api/building/insulation/#reportmetadata) supplying the header (`client`, `specimen` the device, `test_room` the test environment, `instrumentation`, `temperature`, `relative_humidity`, `pressure`, `test_date`), the footer identity (`laboratory`, `operator`, `report_id`, `notes`) and, via `requirement`, a declared minimum mean transmission loss (more transmission loss is better). |
| `engine` | Rendering back end; only `"reportlab"` is supported. |
| `verbose` | Accepted for signature symmetry with the other fiches; the silencer table already shows the insertion loss when it was computed. |
| `language` | Fiche language: `"en"` (default) or `"es"`. |

**Returns:** The written `path` as a `str`.

**Raises**

| Exception | When |
| :--- | :--- |
| ValueError | If `engine` is not `"reportlab"` or `language` is unknown. |
| ImportError | If reportlab (or, for the figure, matplotlib) is not installed (`pip install phonometry[report]`). |
Loading