feat(noise_control): feed a predicted panel R into the machine-enclosure model#235
Conversation
Reviewer's GuideThis PR extends machine-enclosure insertion loss calculations to accept panel prediction result objects directly, wires them in via a structural protocol without creating a package dependency, adds tests around the new bridge behavior, and updates documentation and changelog to reflect the expanded API and namespaces table corrections. Sequence diagram for enclosure_insertion_loss with panel prediction resultsequenceDiagram
actor Caller
participant Building as building
participant NoiseControl as noise_control
Caller->>Building: single_panel_transmission_loss(...)
Building-->>Caller: SoundReductionResult
Caller->>NoiseControl: enclosure_insertion_loss(panel_transmission_loss=SoundReductionResult, external_area, internal_area, internal_absorption, frequencies=None)
NoiseControl->>NoiseControl: isinstance(panel_transmission_loss, PanelTransmissionResult)
alt frequencies is None
NoiseControl->>NoiseControl: frequencies = panel_transmission_loss.frequencies
end
NoiseControl->>NoiseControl: panel_transmission_loss = np.asarray(panel_transmission_loss.transmission_loss)
NoiseControl->>NoiseControl: freqs = _resolve_frequencies(frequencies)
NoiseControl->>NoiseControl: r = _resolve_panel_r(panel_transmission_loss, freqs)
NoiseControl-->>Caller: EnclosureInsertionLossResult
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Review limit reached
Next review available in: 23 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthrough
ChangesPanel result bridge
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant single_panel_transmission_loss
participant PanelTransmissionResult
participant enclosure_insertion_loss
single_panel_transmission_loss->>PanelTransmissionResult: provide transmission_loss and frequencies
PanelTransmissionResult->>enclosure_insertion_loss: pass structured panel result
enclosure_insertion_loss->>enclosure_insertion_loss: extract arrays and resolve frequencies
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request enables enclosure_insertion_loss to directly accept a panel prediction result (such as SoundReductionResult or ApertureTransmissionResult) for its panel_transmission_loss argument. This is achieved by introducing a structurally matched PanelTransmissionResult protocol, avoiding a direct dependency on the building package. The documentation, API reference, and CHANGELOG are updated accordingly. The review feedback recommends replacing the runtime isinstance check on the @runtime_checkable protocol with a safer and more performant duck-typing check using hasattr (while excluding common sequence types), which also allows removing the @runtime_checkable decorator and its import.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| from collections.abc import Callable | ||
| from dataclasses import dataclass | ||
| from typing import TYPE_CHECKING, Any | ||
| from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable |
There was a problem hiding this comment.
Applied. Switched to explicit duck typing: the result is matched with hasattr on 'transmission_loss' and 'frequencies' while excluding ndarray/list/tuple, and the @runtime_checkable decorator and its import are removed (the Protocol stays as the type hint). Behaviour is unchanged for arrays, callables and the real SoundReductionResult / ApertureTransmissionResult inputs, verified end to end.
| @runtime_checkable | ||
| class PanelTransmissionResult(Protocol): |
There was a problem hiding this comment.
Since we can replace the runtime isinstance check with a safer and faster duck-typing check using hasattr, we no longer need the PanelTransmissionResult protocol to be @runtime_checkable. Removing this decorator avoids the runtime overhead of setting up the runtime-checkable protocol machinery.
| @runtime_checkable | |
| class PanelTransmissionResult(Protocol): | |
| class PanelTransmissionResult(Protocol): |
There was a problem hiding this comment.
Applied. Switched to explicit duck typing: the result is matched with hasattr on 'transmission_loss' and 'frequencies' while excluding ndarray/list/tuple, and the @runtime_checkable decorator and its import are removed (the Protocol stays as the type hint). Behaviour is unchanged for arrays, callables and the real SoundReductionResult / ApertureTransmissionResult inputs, verified end to end.
| if not callable(panel_transmission_loss) and isinstance( | ||
| panel_transmission_loss, PanelTransmissionResult | ||
| ): |
There was a problem hiding this comment.
Using isinstance with a @runtime_checkable protocol has significant runtime overhead because it performs dynamic attribute resolution on every call. Additionally, it introduces a testing hazard when using unittest.mock.Mock objects, as standard mocks dynamically return True for any hasattr check, causing isinstance(mock, PanelTransmissionResult) to unexpectedly evaluate to True and subsequently crash when accessing attributes.
A more robust and performant approach is to use standard Python duck-typing by checking for the required attributes directly, while explicitly excluding common sequence types like numpy.ndarray, list, and tuple.
if (
not callable(panel_transmission_loss)
and not isinstance(panel_transmission_loss, (np.ndarray, list, tuple))
and hasattr(panel_transmission_loss, "transmission_loss")
and hasattr(panel_transmission_loss, "frequencies")
):There was a problem hiding this comment.
Applied. Switched to explicit duck typing: the result is matched with hasattr on 'transmission_loss' and 'frequencies' while excluding ndarray/list/tuple, and the @runtime_checkable decorator and its import are removed (the Protocol stays as the type hint). Behaviour is unchanged for arrays, callables and the real SoundReductionResult / ApertureTransmissionResult inputs, verified end to end.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #235 +/- ##
=======================================
Coverage 95.96% 95.96%
=======================================
Files 146 146
Lines 19262 19270 +8
=======================================
+ Hits 18485 18493 +8
Misses 777 777 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Numerical conformance report✅ 354/354 conformance checks pass across 44 domains and 225 standards - filters class 1 - weightings within IEC 61672-1 class 1. Each row pins a standard clause to its expected normative value and the value the library computes. Every section below is collapsible and stays collapsed while all of its rows pass; a section with any failing row opens automatically. ✅ Numerical validation - filters & weightings: class showcase (IEC 61260-1 · IEC 61672-1 · ISO 7196)IEC 61260-1:2014 class per filter architecture (order 6, one-third-octave, 100 Hz-10 kHz, fs = 48 kHz). For each architecture the table shows, at its binding band, the measured relative attenuation and the class-1 limit it must clear, so the number and the range it must sit in are both visible. A positive margin means the acceptance limits are met with that much room.
Only Butterworth (the library default) and Chebyshev-II are class-compliant architectures. Chebyshev-I and elliptic trade the mask for passband ripple, and Bessel for a maximally-flat group delay (soft rolloff); they cannot satisfy the IEC 61260-1 Class 1/2 attenuation mask by construction, so they are labelled By design - this is expected, not a failure or regression. Frequency-weighting conformance (A/C: IEC 61672-1 Table 3; G: ISO 7196 A.3). The max deviation from nominal is informational (it falls at a frequency extreme where the tolerance is widest and asymmetric); compliance is judged at the binding frequency - the one with the least headroom - where the deviation, the applicable tolerance band and the headroom are shown together.
✅ Filters & weightings: 100% (7/7)
✅ Levels & dosimetry: 100% (6/6)
✅ Room acoustics: 100% (12/12)
✅ Psychoacoustics: 100% (12/12)
✅ Speech transmission (IEC 60268-16): 100% (9/9)
✅ Intensity & sound power: 100% (4/4)
✅ Room & building acoustics: 100% (51/51)
✅ Building prediction & uncertainty: 100% (15/15)
✅ Outdoor propagation & occupational exposure: 100% (10/10)
✅ Materials: absorption, airflow & impedance: 100% (6/6)
✅ Scattering & diffusion (ISO 17497): 100% (5/5)
✅ In-situ road absorption (ISO 13472): 100% (3/3)
✅ Precision sound power (ISO 3745 / 9614-3): 100% (4/4)
✅ Human vibration (ISO 8041 / 2631 / 5349): 100% (15/15)
✅ Speech intelligibility (ANSI S3.5-1997): 100% (7/7)
✅ Objective intelligibility (STOI / ESTOI): 100% (3/3)
✅ Impulsive-sound prominence (NT ACOU 112): 100% (2/2)
✅ Room noise (ANSI S12.2-2019): 100% (3/3)
✅ Hearing threshold (ISO 7029 / ISO 389-7): 100% (3/3)
✅ Measurement uncertainty (GUM / Supplement 1): 100% (7/7)
✅ Noise-induced hearing loss (ISO 1999): 100% (3/3)
✅ Multiple-shock whole-body vibration (ISO 2631-5): 100% (6/6)
✅ Sound absorption in enclosed spaces (EN 12354-6): 100% (2/2)
✅ Prominent discrete tones (ECMA-418-1): 100% (2/2)
✅ Tonal audibility (ISO/PAS 20065): 100% (11/11)
✅ Psychoacoustic annoyance & fluctuation strength (Fastl & Zwicker): 100% (3/3)
✅ Electroacoustics: distortion & frequency response: 100% (14/14)
✅ Calibrated spectral analysis (Bendat & Piersol): 100% (6/6)
✅ Correlation, time delay and envelope (B&P / Knapp & Carter): 100% (7/7)
✅ Underwater acoustics (ISO 18405/17208/18406): 100% (6/6)
✅ Underwater sound propagation (transmission loss): 100% (15/15)
✅ Underwater numerical propagation (modes / rays / PE): 100% (4/4)
✅ Aircraft noise (ICAO Annex 16 / IEC 61265): 100% (14/14)
✅ Rotorcraft noise (ECAC Doc 32 / NORAH2): 100% (12/12)
✅ Wind-turbine noise (IEC 61400-11): 100% (3/3)
✅ Porous & multilayer absorbers (Mechel / Bies / Cox & D'Antonio): 100% (10/10)
✅ Program loudness (ITU-R BS.1770 / EBU R 128): 100% (8/8)
✅ 2D FDTD wave simulation (Attenborough & Van Renterghem 2021, Ch. 4): 100% (2/2)
✅ Swept-sine distortion & phase utilities (Farina / Novak): 100% (7/7)
✅ Spherical ground & barriers (Attenborough / Salomons / Bies): 100% (6/6)
✅ Panel & aperture sound insulation (Bies / Hopkins / Cremer): 100% (11/11)
✅ Atmospheric refraction (Salomons rays / GFPE): 100% (3/3)
✅ Electroacoustics: 100% (6/6)
✅ Industrial noise control: 100% (9/9)
Tests & coverage — 24378 tests, 0 failures (✅ all green)
Conformance harness: |
…e input enclosure_insertion_loss already took the panel transmission loss R as a per-band array or a callable of frequency. It now also accepts a panel prediction result (a building SoundReductionResult or ApertureTransmissionResult) matched structurally via a Protocol, reading its per-band R and band centres. This keeps a predicted R and a measured R interchangeable at the enclosure input without introducing any dependency of noise_control on building.
… subpackage count The Namespaces table was missing the phonometry.noise_control row and the prose still said thirteen subpackages; there are fifteen. Also note atmospheric refraction under environmental and the radiating piston under electroacoustics.
Detect the panel prediction result with hasattr on transmission_loss and frequencies (excluding array-likes) instead of isinstance against a runtime_checkable Protocol, dropping the runtime-check machinery. The Protocol stays as the type hint. Behaviour is unchanged for arrays, callables and real SoundReductionResult / ApertureTransmissionResult inputs.
4dc9cc2 to
cccce9b
Compare
|



enclosure_insertion_losscombines a panel transmission lossRwith the interior absorption to give the net insertion loss of a machine enclosure. Until now the panelRhad to be passed as a per-band array or a callable of frequency. It now also accepts a panel prediction result directly, so a predictedRand a measuredRare interchangeable at the enclosure input.A
SoundReductionResult(fromsingle_panel_transmission_loss/double_wall_transmission_loss) or anApertureTransmissionResult(fromcomposite_transmission_lossand the slit/aperture models) is matched structurally through aProtocol, reading its per-bandRand its band centres. This is duck-typed on purpose:noise_controlgains no import dependency onbuilding, and the package-architecture test still forbids that edge.Also a small documentation pass on the API reference: the Namespaces table was missing the
phonometry.noise_controlrow and still said thirteen subpackages (there are fifteen); atmospheric refraction and the radiating piston are now noted under their namespaces.https://claude.ai/code/session_01LnezkUn2wvXJ9LFKoYhdyd
Summary by CodeRabbit
New Features
enclosure_insertion_lossnow accepts panel prediction results directly, alongside per-band arrays and callables.Documentation
Tests