Orthotropic panel insulation and the limp-frame equivalent fluid - #438
Conversation
There was a problem hiding this comment.
Sorry @jmrplens, your pull request is larger than the review limit of 150000 diff characters
|
This pull request exceeds the fair usage size limit for the Bito Code Review Agent trial. Please reduce the PR size or upgrade to a paid plan. Contact support@bito.in for assistance. Learn more |
📝 WalkthroughWalkthroughThe pull request adds orthotropic corrugated-panel transmission models and limp-frame porous-medium corrections, exposes their APIs, adds validation and conformance checks, generates supporting figures, and updates English, Spanish, API, release, and conformance documentation. ChangesOrthotropic panel modeling
Limp-frame porous modeling
Release and conformance metadata
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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 |
Reviewer's GuideAdds orthotropic (ribbed/corrugated) panel transmission models and limp-frame porous equivalent fluid support, with full API exposure, plotting updates, documentation, figures, and conformance tests to numerically anchor the new physics. Flow diagram for orthotropic panel transmission pipelineflowchart LR
corrugated_geometry["corrugated geometry (thickness, amplitude, wavelength, E, nu)"] --> corrugated_plate_stiffness
corrugated_geometry --> corrugated_plate_mass_factor
corrugated_plate_stiffness --> orthotropic_critical_frequencies
corrugated_plate_mass_factor --> orthotropic_critical_frequencies
orthotropic_critical_frequencies --> orthotropic_transmission_loss
orthotropic_transmission_loss --> SoundReductionResult
SoundReductionResult --> plot_sound_reduction["plot_sound_reduction (shades coincidence range fc1..fc2)"]
Flow diagram for rigid-frame to limp-frame porous absorber pipelineflowchart LR
porous_input["material data (sigma, porosity, geometry)"] --> johnson_champoux_allard
johnson_champoux_allard --> PorousMediumResult_rigid["PorousMediumResult (rigid frame)"]
PorousMediumResult_rigid --> limp_frame
limp_frame --> PorousMediumResult_limp["PorousMediumResult (limp frame)"]
PorousMediumResult_limp --> PorousLayer
PorousLayer --> layered_absorber
layered_absorber --> DiffuseFieldAbsorptionResult["DiffuseFieldAbsorptionResult / absorption"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
aa8a060 to
5fddd4a
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@llms-full.txt`:
- Line 2539: Update the orthotropic_plate_resonance example to avoid the
undefined b argument by reusing the existing flat_b variable or defining b
before the function call; keep all three bending-stiffness parameters
consistent.
In `@scripts/generate_graphs.py`:
- Around line 8441-8445: Update the English caption in the ax.text call to an
f-string that interpolates the existing local porosity, resistivity, and
frame_density parameters, matching the established Spanish caption pattern.
Preserve the wording, units, formatting, and plot styling while removing the
hard-coded numeric values.
In `@site/src/content/docs/reference/api/building/panel-transmission.md`:
- Line 492: Fix the documentation resolver’s attribute disambiguation so
SoundReductionResult.critical_frequency resolves to the SoundReductionResult
attribute rather than the module-level flanking_transmission.critical_frequency
function. Then regenerate the API documentation for the orthotropic-integral and
orthotropic-heckl return description, ensuring the generated link targets the
SoundReductionResult section.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: cde0fcaa-fe89-474a-8603-5dccd5f952f4
⛔ Files ignored due to path filters (8)
.github/images/limp_frame_effective_density.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_dark.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es_dark.svgis excluded by!**/*.svg
📒 Files selected for processing (33)
.zenodo.jsonCHANGELOG.mddocs/CONFORMANCE.mddocs/api-reference.mddocs/getting-started.mddocs/panel-sound-insulation.mddocs/porous-absorbers.mdllms-full.txtllms.txtscripts/conformance_report.pyscripts/generate_graphs.pysite/public/llms/llms-absorbers.txtsite/public/llms/llms-insulation-design.txtsite/public/llms/llms-start.txtsite/src/content/docs/es/guides/panel-sound-insulation.mdxsite/src/content/docs/es/guides/porous-absorbers.mdxsite/src/content/docs/es/index.mdxsite/src/content/docs/es/reference/conformance.mdsite/src/content/docs/guides/panel-sound-insulation.mdxsite/src/content/docs/guides/porous-absorbers.mdxsite/src/content/docs/index.mdxsite/src/content/docs/reference/api/building/panel-transmission.mdsite/src/content/docs/reference/api/materials/porous-absorber.mdsite/src/content/docs/reference/conformance.mdsrc/phonometry/__init__.pysrc/phonometry/_plot/building.pysrc/phonometry/building/__init__.pysrc/phonometry/building/panel_transmission.pysrc/phonometry/materials/__init__.pysrc/phonometry/materials/porous_absorber.pytests/building/test_orthotropic_panels.pytests/materials/test_limp_frame.pytests/reference_data.py
| ax.text(0.015, 0.03, | ||
| "Soft fibrous layer: porosity 0.98, " | ||
| "flow resistivity 25 kPa s/m², frame density 30 kg/m³", | ||
| transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5, | ||
| color=COLOR_FG) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Derive the caption from the parameters instead of retyping them.
porosity, resistivity and frame_density are already local; the literal caption will silently disagree with the curves if any of them is edited. The Spanish pattern captures the values, so an f-string is transparent to the translation pass.
♻️ Proposed refactor
- ax.text(0.015, 0.03,
- "Soft fibrous layer: porosity 0.98, "
- "flow resistivity 25 kPa s/m², frame density 30 kg/m³",
- transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5,
- color=COLOR_FG)
+ ax.text(0.015, 0.03,
+ f"Soft fibrous layer: porosity {porosity:g}, "
+ f"flow resistivity {resistivity / 1e3:g} kPa s/m², "
+ f"frame density {frame_density:g} kg/m³",
+ transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5,
+ color=COLOR_FG)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ax.text(0.015, 0.03, | |
| "Soft fibrous layer: porosity 0.98, " | |
| "flow resistivity 25 kPa s/m², frame density 30 kg/m³", | |
| transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5, | |
| color=COLOR_FG) | |
| ax.text(0.015, 0.03, | |
| f"Soft fibrous layer: porosity {porosity:g}, " | |
| f"flow resistivity {resistivity / 1e3:g} kPa s/m², " | |
| f"frame density {frame_density:g} kg/m³", | |
| transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5, | |
| color=COLOR_FG) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/generate_graphs.py` around lines 8441 - 8445, Update the English
caption in the ax.text call to an f-string that interpolates the existing local
porosity, resistivity, and frame_density parameters, matching the established
Spanish caption pattern. Preserve the wording, units, formatting, and plot
styling while removing the hard-coded numeric values.
5fddd4a to
f78b3c5
Compare
Numerical conformance report✅ 484/484 conformance checks pass across 55 domains and 325 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% (10/10)
✅ Levels & dosimetry: 100% (9/9)
✅ Room & building acoustics: 100% (60/60)
✅ Room acoustics: 100% (16/16)
✅ Psychoacoustics: 100% (14/14)
✅ Speech transmission (IEC 60268-16): 100% (10/10)
✅ System measurement (Golay / Kirkeby / Mueller-Massarani): 100% (5/5)
✅ Intensity & sound power: 100% (10/10)
✅ 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% (14/14)
✅ 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)
✅ Impulsive-sound prominence (ISO/PAS 1996-3): 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% (6/6)
✅ 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% (20/20)
✅ Calibrated spectral analysis (Bendat & Piersol): 100% (12/12)
✅ Multiple-input coherence (Bendat & Piersol): 100% (5/5)
✅ Time-frequency analysis (Bendat & Piersol): 100% (3/3)
✅ Correlation, time delay and envelope (B&P / Knapp & Carter): 100% (7/7)
✅ Cepstrum, liftering and envelope spectrum (Havelock / B&P): 100% (3/3)
✅ Time synchronous averaging (McFadden 1987): 100% (5/5)
✅ Data qualification and Rice statistics (Bendat & Piersol): 100% (8/8)
✅ Underwater acoustics (ISO 18405/17208/18406): 100% (6/6)
✅ Underwater sound propagation (transmission loss): 100% (16/16)
✅ Underwater propagation regimes (Weston flux theory): 100% (3/3)
✅ Marine-mammal auditory weighting (NMFS / Southall): 100% (4/4)
✅ Underwater numerical propagation (modes / rays / PE): 100% (4/4)
✅ Aircraft noise (ICAO Annex 16 / IEC 61265): 100% (15/15)
✅ 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% (14/14)
✅ Slow-sound perfect absorbers (Jimenez et al. Appl. Sci. 2017): 100% (3/3)
✅ Program loudness (ITU-R BS.1770 / EBU R 128): 100% (8/8)
✅ 2D FDTD wave simulation (Attenborough & Van Renterghem 2021, Ch. 4): 100% (4/4)
✅ Swept-sine distortion & phase utilities (Farina / Novak): 100% (7/7)
✅ Spherical ground & barriers (Attenborough / Salomons / Bies): 100% (7/7)
✅ Panel & aperture sound insulation (Bies / Hopkins / Cremer): 100% (17/17)
✅ Bending-wave plate-junction transmission (Cremer / Craik / Hopkins): 100% (6/6)
✅ Atmospheric refraction (Salomons rays / GFPE): 100% (3/3)
✅ Electroacoustics: 100% (9/9)
✅ Industrial noise control: 100% (22/22)
Tests & coverage — 41718 tests, 0 failures (✅ all green)
Conformance harness: |
f78b3c5 to
73c1725
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #438 +/- ##
==========================================
+ Coverage 96.86% 96.88% +0.01%
==========================================
Files 242 242
Lines 36273 36413 +140
==========================================
+ Hits 35137 35277 +140
Misses 1136 1136 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (1)
site/src/content/docs/reference/api/building/panel-transmission.md (1)
499-499: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winResolver bug still present:
critical_frequencylink points to the wrong target.This was previously flagged and marked "Addressed", but the same broken link persists here:
critical_frequencystill resolves to/phonometry/reference/api/building/flanking-transmission/#critical_frequency(the unrelated module-level function) instead of theSoundReductionResultattribute, while the siblingcritical_frequency_upperlink on the same line was correctly fixed to#soundreductionresult. The generator's attribute-disambiguation fix appears to only cover the newly added attribute name, not the pre-existing collision withflanking_transmission.critical_frequency.🔧 Suggested doc-generator fix (scripts/generate_api_docs.py)
Ensure the resolver prefers a member match on the enclosing return type (
SoundReductionResult) over a same-named module-level function elsewhere in the package when resolving:attr:~SoundReductionResult.critical_frequency`` references, then regenerate this page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/src/content/docs/reference/api/building/panel-transmission.md` at line 499, Fix the documentation resolver used for the return description so the critical_frequency link resolves to the SoundReductionResult member rather than flanking_transmission.critical_frequency. Update the attribute-disambiguation logic in the relevant generator flow to prefer members of the enclosing return type, then regenerate this page while preserving the existing critical_frequency_upper link.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/panel-sound-insulation.md`:
- Around line 338-343: Hyphenate “78 degree limiting angle” as “78-degree
limiting angle” in docs/panel-sound-insulation.md (338-343) and
site/src/content/docs/guides/panel-sound-insulation.mdx (386-391). Regenerate
site/public/llms/llms-insulation-design.txt (1126-1131) from the corrected
source; do not edit it manually. The Spanish mirror requires no change.
In `@llms-full.txt`:
- Around line 23790-23792: Update the mounting discussion in the passage around
“Neither accounts for mounting” to explicitly state that bonded materials are
unsuitable for both rigid-frame and limp-frame equivalent-fluid models, and
require modeling the frame–structure coupling instead.
In `@scripts/conformance_report.py`:
- Around line 6893-6914: Align the provenance comment above _AA_TABLE_11_2 and
_chk_limp_decoupling_frequency with the actual checks: identify the three checks
using the _AA_TABLE_11_2 material as the prose limits on printed page 253, and
identify _chk_limp_decoupling_frequency as the separate closed-form Table 6.1
glass-wool anchor using its hardcoded inputs. Do not rename or alter the
constants or calculations.
- Around line 7580-7592: The _chk_corrugated_plate_mode_22 check currently
passes only at the numeric tolerance boundary. Update its numeric() expectation
and tolerance so the computed f22 aligns robustly with Vigran’s printed 102.1 Hz
reference, using a tight tolerance appropriate for the calculation rather than
relying on 102.0 ±0.1.
In `@site/src/content/docs/es/guides/porous-absorbers.mdx`:
- Line 260: Update the ThemeImage `src` in the Spanish porous absorbers guide to
use the translated `limp_frame_effective_density_es.svg` asset instead of the
English-labelled `limp_frame_effective_density.svg`; leave the existing alt text
and image attributes unchanged.
In `@site/src/content/docs/reference/api/materials/porous-absorber.md`:
- Line 510: Update the source docstring for the porous absorber API, including
the porosity default and the values at the corresponding criterion entry, to use
decimal points consistently with the signature and LIMP_FRAME_CRITERIA. Then
regenerate the English reference page so the rendered values appear as 1.0, 0.2,
and 0.05; retain decimal commas only where reproducing standard text.
---
Duplicate comments:
In `@site/src/content/docs/reference/api/building/panel-transmission.md`:
- Line 499: Fix the documentation resolver used for the return description so
the critical_frequency link resolves to the SoundReductionResult member rather
than flanking_transmission.critical_frequency. Update the
attribute-disambiguation logic in the relevant generator flow to prefer members
of the enclosing return type, then regenerate this page while preserving the
existing critical_frequency_upper link.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 20365c03-d3dd-485b-ab6b-5a6d1f197eb1
⛔ Files ignored due to path filters (8)
.github/images/limp_frame_effective_density.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_dark.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es_dark.svgis excluded by!**/*.svg
📒 Files selected for processing (36)
.zenodo.jsonCHANGELOG.mddocs/CONFORMANCE.mddocs/api-reference.mddocs/getting-started.mddocs/panel-sound-insulation.mddocs/porous-absorbers.mddocs/references.mdllms-full.txtllms.txtscripts/conformance_report.pyscripts/generate_graphs.pysite/public/llms/llms-absorbers.txtsite/public/llms/llms-insulation-design.txtsite/public/llms/llms-start.txtsite/src/content/docs/es/guides/panel-sound-insulation.mdxsite/src/content/docs/es/guides/porous-absorbers.mdxsite/src/content/docs/es/index.mdxsite/src/content/docs/es/reference/bibliography.mdsite/src/content/docs/es/reference/conformance.mdsite/src/content/docs/guides/panel-sound-insulation.mdxsite/src/content/docs/guides/porous-absorbers.mdxsite/src/content/docs/index.mdxsite/src/content/docs/reference/api/building/panel-transmission.mdsite/src/content/docs/reference/api/materials/porous-absorber.mdsite/src/content/docs/reference/bibliography.mdsite/src/content/docs/reference/conformance.mdsrc/phonometry/__init__.pysrc/phonometry/_plot/building.pysrc/phonometry/building/__init__.pysrc/phonometry/building/panel_transmission.pysrc/phonometry/materials/__init__.pysrc/phonometry/materials/porous_absorber.pytests/building/test_orthotropic_panels.pytests/materials/test_limp_frame.pytests/reference_data.py
| *The trade corrugating makes, on Vigran's own geometry. Below $f_{c1}$ the two | ||
| panels are within about 2 dB of each other (the corrugated one slightly higher: | ||
| it is 9 % heavier, and the diffuse-field integral uses a 78 degree limiting | ||
| angle rather than Sharp's 5.5 dB band correction). Across the coincidence range | ||
| the corrugated sheet gives away up to 13 dB, and $R_w$ falls from 28 dB to | ||
| 25 dB, for a panel that is stiffer and barely heavier.* |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Hyphenate the compound modifier "78-degree limiting angle". The same figure caption is authored once and mirrored into the site guide and the generated llms text, so the missing hyphen appears three times; fix it at the source and regenerate.
docs/panel-sound-insulation.md#L338-L343: change "a 78 degree limiting angle" to "a 78-degree limiting angle".site/src/content/docs/guides/panel-sound-insulation.mdx#L386-L391: apply the same wording change to the English caption.site/public/llms/llms-insulation-design.txt#L1126-L1131: regenerate this mirror so the caption picks up the fix rather than editing it by hand.
The Spanish mirror needs no change ("un ángulo límite de 78 grados").
🧰 Tools
🪛 LanguageTool
[grammar] ~340-~340: Use a hyphen to join words.
Context: ...and the diffuse-field integral uses a 78 degree limiting angle rather than Sharp'...
(QB_NEW_EN_HYPHEN)
📍 Affects 3 files
docs/panel-sound-insulation.md#L338-L343(this comment)site/src/content/docs/guides/panel-sound-insulation.mdx#L386-L391site/public/llms/llms-insulation-design.txt#L1126-L1131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/panel-sound-insulation.md` around lines 338 - 343, Hyphenate “78 degree
limiting angle” as “78-degree limiting angle” in docs/panel-sound-insulation.md
(338-343) and site/src/content/docs/guides/panel-sound-insulation.mdx (386-391).
Regenerate site/public/llms/llms-insulation-design.txt (1126-1131) from the
corrected source; do not edit it manually. The Spanish mirror requires no
change.
Source: Linters/SAST tools
| @register(_PANEL, "Vigran Eqs. (3.113)/(3.115), printed p. 96", | ||
| "Corrugated 1 mm steel plate (H = 10 mm, L = 100 mm), f(2,2)") | ||
| def _chk_corrugated_plate_mode_22() -> Outcome: | ||
| b_x, b_z, b_xz = ph.corrugated_plate_stiffness( | ||
| 1.0e-3, 0.010, 0.100, youngs_modulus=2.1e11, poisson_ratio=0.3 | ||
| ) | ||
| mass = 7.8 * ph.corrugated_plate_mass_factor(0.010, 0.100) | ||
| f22 = ph.orthotropic_plate_resonance( | ||
| 2, 2, length_x=1.0, length_z=1.0, mass_per_area=mass, | ||
| bending_stiffness_x=b_x, bending_stiffness_z=b_z, | ||
| bending_stiffness_xz=b_xz, | ||
| ) | ||
| return numeric(102.0, f22, 0.1, unit="Hz", places=2) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Recompute f(2,2) for the corrugated plate and show the deviation from 102.0,
# and print numeric()'s comparison semantics (strict < vs <=).
fd -t f 'conformance_report.py' -x rg -n -A 25 'def numeric\('
fd -t f 'panel_transmission.py' -x rg -n -A 6 'def corrugated_plate_mass_factor|def corrugated_plate_stiffness|def orthotropic_plate_resonance'Repository: jmrplens/phonometry
Length of output: 2183
🏁 Script executed:
#!/bin/bash
set -e
python3 - <<'PY'
import sys
sys.path.insert(0, ".")
import phonometry as ph
args = (1.0e-3, 0.010, 0.100)
kwargs = {"youngs_modulus": 2.1e11, "poisson_ratio": 0.3}
b_x, b_z, b_xz = ph.corrugated_plate_stiffness(*args, **kwargs)
mass = 7.8 * ph.corrugated_plate_mass_factor(*args[:2])
f22 = ph.orthotropic_plate_resonance(
2, 2, length_x=1.0, length_z=1.0, mass_per_area=mass,
bending_stiffness_x=b_x, bending_stiffness_z=b_z,
bending_stiffness_xz=b_xz,
)
expected = 102.0
tol = 0.1
print("b_x=", b_x)
print("b_z=", b_z)
print("b_xz=", b_xz)
print("mass=", mass)
print("f22=", repr(f22))
print("f22_rounded=", f"{f22:.1f}")
print("delta=", repr(f22 - expected))
print("abs_delta=", abs(f22 - expected))
print("tol_limit=", tol)
print("passes_boundary_0_1=", abs(f22 - expected) <= tol)
print("passes_boundary_0_0999=", abs(f22 - expected) <= tol - 1e-14)
PYRepository: jmrplens/phonometry
Length of output: 280
🏁 Script executed:
#!/bin/bash
set -e
echo "== package hints =="
git ls-files | rg '(^|/)(pyproject\.toml|setup\.py|setup\.cfg|phonometry\.py|panel_transmission\.py|conformance_report\.py)$' || true
echo "== relevant source snippets =="
sed -n '1,160p' scripts/conformance_report.py
echo "-----"
sed -n '560,695p' scripts/panel_transmission.py
echo "-----"
sed -n '7568,7600p' scripts/conformance_report.pyRepository: jmrplens/phonometry
Length of output: 5890
🏁 Script executed:
#!/bin/bash
set -e
sed -n '560,695p' src/phonometry/building/panel_transmission.py
echo "-----"
sed -n '7568,7600p' scripts/conformance_report.py
echo "-----"
echo "== orthotropic references =="
rg -n "corru|orthotropic_plate_resonance|ellipe" scripts/conformance_report.py src/phonometry/building/panel_transmission.pyRepository: jmrplens/phonometry
Length of output: 12067
🏁 Script executed:
#!/bin/bash
set -e
python3 - <<'PY'
from scipy.special import ellipe
h, H, L = 1.0e-3, 0.010, 0.100
E, nu = 2.1e11, 0.3
rho_flat = 7.8
q = 2.0 * 3.141592653589793 * H / L
q2 = q * q
mass_factor = float(2.0 / 3.141592653589793 * (1.0 + q2)**0.5 * ellipe(q2 / (1.0 + q2)))
mass = rho_flat * mass_factor
shape = (3.141592653589793 * H / L) ** 2
flat = E * h**3 / 12.0
Bx = flat / ((1.0 - nu**2) * (1.0 + shape))
Bz = 0.5 * E * H**2 * h * (1.0 - 0.81 / (1.0 + 2.5 * (H / L) ** 2))
Bxz = flat / (1.0 + nu) * (1.0 + shape)
m = 1.0
n = 1.0
a = length_x = 1.0
b = length_z = 1.0
f22 = (3.141592653589793 / (2 * mass**0.5)) * (
(m**4 * Bx / a**4) + (n**4 * Bz / b**4) + 2 * m**2 * n**2 * Bxz / (a**2 * b**2)
)**0.5
for x in ("mass", "mass_factor", "Bx", "Bz", "Bxz", "f22"):
print(f"{x} = {locals()[x]!r}")
for expected, tol in [(102.0, 0.1), (102.1, 0.05), (102.1, 0.1)]:
print(f"expected={expected} tol={tol} passes={'pass' if abs(locals()['f22'] - expected) <= tol else 'fail'}")
PYRepository: jmrplens/phonometry
Length of output: 275
🏁 Script executed:
#!/bin/bash
set -e
python3 - <<'PY'
# Recreate the library formulas from source without importing the package.
import math
def ellipe(m):
# scipy.special.ellipe is the complete elliptic integral of the second kind,
# E(m), not E(phi, m). Use numpy's standard polynomial approximation for
# a narrow checked range: m = (2*pi*H/L)^2 / (1 + (2*pi*H/L)^2)
# for H=0.010, L=0.100.
m = float(m)
# Use the built-in scipy approximation only if available; otherwise raise.
import importlib.util
if importlib.util.find_spec("scipy.special") is not None:
import importlib
special = importlib.import_module("scipy.special")
return special.ellipe(m)
raise RuntimeError("scipy unavailable")
h, H, L = 1.0e-3, 0.010, 0.100
E, nu = 2.1e11, 0.3
rho_flat = 7.8
q = 2.0 * math.pi * H / L
q2 = q * q
mass_factor = float(2.0 / math.pi * math.sqrt(1.0 + q2) * ellipe(q2 / (1.0 + q2)))
mass = rho_flat * mass_factor
shape = (math.pi * H / L) ** 2
flat = E * h**3 / 12.0
Bx = flat / ((1.0 - nu**2) * (1.0 + shape))
Bz = 0.5 * E * H**2 * h * (1.0 - 0.81 / (1.0 + 2.5 * (H / L) ** 2))
Bxz = flat / (1.0 + nu) * (1.0 + shape)
m = n = 1.0
a = b = 1.0
f22 = (math.pi / (2 * mass**0.5)) * (
(m**4 * Bx / a**4) + (n**4 * Bz / b**4) + 2 * m**2 * n**2 * Bxz / (a**2 * b**2)
)**0.5
print(f"mass_factor = {mass_factor!r}")
print(f"mass = {mass!r}")
print(f"Bx = {Bx!r}")
print(f"Bz = {Bz!r}")
print(f"Bxz = {Bxz!r}")
print(f"f22 = {f22!r}")
print(f"f22_rounded_1dp = {f22:.1f}")
print(f"|f22-102.0| = {abs(f22 - 102.0)!r}")
print(f"|f22-102.1| = {abs(f22 - 102.1)!r}")
print("passes_102_0_tol_0_1 =", abs(f22 - 102.0) <= 0.1, f"delta={f22 - 102.0:.15f}")
print("passes_102_1_tol_0_05 =", abs(f22 - 102.1) <= 0.05, f"delta={f22 - 102.1:.15f}")
PYRepository: jmrplens/phonometry
Length of output: 444
🌐 Web query:
scipy.special.ellipe complete elliptic integral of second kind documentation
💡 Result:
The scipy.special.ellipe function calculates the complete elliptic integral of the second kind [1][2]. Definition The function is defined by the integral: E(m) = integral from 0 to pi/2 of [1 - m sin(t)^2]^(1/2) dt [1][2] Parameters - m (array_like): The parameter of the elliptic integral [1][2]. Note that this parameterization uses m = k^2, where k is the modulus [1]. Care should be taken as other conventions use the complementary parameter (1 - m) or the modular angle (sin^2(alpha) = m) [1][2]. - out (ndarray, optional): An optional output array for the function values [1][2]. Returns - Returns the scalar or ndarray value of the elliptic integral [1][2]. Technical Details - Implementation: It is a wrapper for the Cephes routine ellpe [1][2]. - Computation: For m > 0, it uses a tenth-order polynomial approximation involving log(1-m) [1][2]. For m < 0, it employs the relationship E(m) = E(m / (m - 1)) * sqrt(1 - m) [1][2]. - Applications: It is commonly used to calculate the circumference of an ellipse with semi-major axis a and semi-minor axis b, where the eccentricity squared is e_sq = 1.0 - b^2/a^2, and the circumference is given by 4 * a * scipy.special.ellipe(e_sq) [1][2].
Citations:
- 1: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.ellipe.html
- 2: https://scipy.github.io/devdocs/reference/generated/scipy.special.ellipe.html
Avoid relying on this check passing exactly at the tolerance boundary.
numeric() uses abs(delta) <= tol, but this f(2,2) check targets 102.0 ±0.1 while Vigran’s worked example prints 102.1. The current check will pass by virtue of the boundary condition, and small numeric drift can flip the result. Align the expected/computed pair (for example, expect 102.1 with a tight tolerance) or widen the tolerance comfortably beyond the printed/reference deviation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/conformance_report.py` around lines 7580 - 7592, The
_chk_corrugated_plate_mode_22 check currently passes only at the numeric
tolerance boundary. Update its numeric() expectation and tolerance so the
computed f22 aligns robustly with Vigran’s printed 102.1 Hz reference, using a
tight tolerance appropriate for the calculation rather than relying on 102.0
±0.1.
| `limp_frame` recibe un `PorousMediumResult` y devuelve otro, así que encaja | ||
| directamente en un `PorousLayer` de la pila. | ||
|
|
||
| <ThemeImage src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/limp_frame_effective_density.svg" alt="Densidad efectiva normalizada frente a la frecuencia de 0 a 2000 hercios para una capa fibrosa blanda, comparando los modelos de esqueleto rígido y flexible. La parte real del esqueleto rígido es una línea discontinua plana en 1,2 mientras su parte imaginaria se hunde por debajo del borde inferior del gráfico bajo la frecuencia de desacoplo de 127 hercios, marcada con una línea vertical punteada. La parte real del esqueleto flexible parte de la densidad total aparente de 25,9 en cero hercios y cae suavemente hasta la línea del esqueleto rígido hacia los 1500 hercios, mientras su parte imaginaria baja hasta menos 12 cerca de 130 hercios y luego se confunde con la curva de esqueleto rígido" width="88%" loading="lazy" /> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm whether an "_es" translated variant of this figure is produced anywhere in the pipeline.
rg -n "limp_frame_effective_density" --hidden -g '!.git'Repository: jmrplens/phonometry
Length of output: 157
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repo files relevant to docs/images/graphs:"
git ls-files | rg '(^site/src/content/docs/es/guides/porous-absorbers\.mdx$|scripts/generate_graphs\.py$|\.github/images/.*limp_frame|images/.*limp_frame)' || true
echo
echo "Occurrences of limp_frame_effective_density in tracked files:"
git ls-files -z | xargs -0 rg -n "limp_frame_effective_density" || true
echo
echo "Occurrences of effective_density_es suffix:"
git ls-files -z | xargs -0 rg -n "effective_density_es|esqueleto rígido, parte real|A Limp Frame Carries Its Own Inertia" || trueRepository: jmrplens/phonometry
Length of output: 6911
Point the Spanish limp-frame chart at the _es image.
scripts/generate_graphs.py provides translated annotations for this figure, and limp_frame_effective_density_es.svg exists, but this Spanish guide still loads the English-labelled limp_frame_effective_density.svg.
🌐 Proposed fix
- <ThemeImage src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/limp_frame_effective_density.svg" alt="..." width="88%" loading="lazy" />
+ <ThemeImage src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/limp_frame_effective_density_es.svg" alt="..." width="88%" loading="lazy" />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <ThemeImage src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/limp_frame_effective_density.svg" alt="Densidad efectiva normalizada frente a la frecuencia de 0 a 2000 hercios para una capa fibrosa blanda, comparando los modelos de esqueleto rígido y flexible. La parte real del esqueleto rígido es una línea discontinua plana en 1,2 mientras su parte imaginaria se hunde por debajo del borde inferior del gráfico bajo la frecuencia de desacoplo de 127 hercios, marcada con una línea vertical punteada. La parte real del esqueleto flexible parte de la densidad total aparente de 25,9 en cero hercios y cae suavemente hasta la línea del esqueleto rígido hacia los 1500 hercios, mientras su parte imaginaria baja hasta menos 12 cerca de 130 hercios y luego se confunde con la curva de esqueleto rígido" width="88%" loading="lazy" /> | |
| <ThemeImage src="https://raw.githubusercontent.com/jmrplens/phonometry/main/.github/images/limp_frame_effective_density_es.svg" alt="Densidad efectiva normalizada frente a la frecuencia de 0 a 2000 hercios para una capa fibrosa blanda, comparando los modelos de esqueleto rígido y flexible. La parte real del esqueleto rígido es una línea discontinua plana en 1,2 mientras su parte imaginaria se hunde por debajo del borde inferior del gráfico bajo la frecuencia de desacoplo de 127 hercios, marcada con una línea vertical punteada. La parte real del esqueleto flexible parte de la densidad total aparente de 25,9 en cero hercios y cae suavemente hasta la línea del esqueleto rígido hacia los 1500 hercios, mientras su parte imaginaria baja hasta menos 12 cerca de 130 hercios y luego se confunde con la curva de esqueleto rígido" width="88%" loading="lazy" /> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/content/docs/es/guides/porous-absorbers.mdx` at line 260, Update the
ThemeImage `src` in the Spanish porous absorbers guide to use the translated
`limp_frame_effective_density_es.svg` asset instead of the English-labelled
`limp_frame_effective_density.svg`; leave the existing alt text and image
attributes unchanged.
| | :--- | :--- | | ||
| | `medium` | A rigid-frame [`PorousMediumResult`](/phonometry/reference/api/materials/porous-absorber/#porousmediumresult) (its `effective_density` is `rho_eq` and its `bulk_modulus` is kept). | | ||
| | `frame_density` | Bulk density of the frame `rho1`, in kg/m3 (> 0). | | ||
| | `porosity` | Open porosity `phi` (0 \< phi \<= 1, Default: 1,0, the high-porosity assumption of the one-parameter models). | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use decimal points for API parameter values.
The English API page renders actual defaults and criterion values as 1,0, 0,2, and 0,05, while the signature and LIMP_FRAME_CRITERIA use 1.0, 0.2, and 0.05. This is ambiguous and can mislead users.
Update the source docstring and regenerate this page:
-`porosity` | Open porosity `phi` (0 \< phi \<= 1, Default: 1,0, the high-porosity assumption of the one-parameter models). |
+`porosity` | Open porosity `phi` (0 \< phi \<= 1, Default: 1.0, the high-porosity assumption of the one-parameter models). |
...
-`criterion` | Key into [`LIMP_FRAME_CRITERIA`](/phonometry/reference/api/materials/porous-absorber/#limp_frame_criteria), `"doutres"` (Default, 0,2) or `"beranek"` (0,05). |
+`criterion` | Key into [`LIMP_FRAME_CRITERIA`](/phonometry/reference/api/materials/porous-absorber/#limp_frame_criteria), `"doutres"` (Default, 0.2) or `"beranek"` (0.05). |Based on learnings: non-standard numeric values in English API prose should use decimal points, while decimal commas are reserved for reproduced standard text.
Also applies to: 549-549
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/content/docs/reference/api/materials/porous-absorber.md` at line
510, Update the source docstring for the porous absorber API, including the
porosity default and the values at the corresponding criterion entry, to use
decimal points consistently with the signature and LIMP_FRAME_CRITERIA. Then
regenerate the English reference page so the rendered values appear as 1.0, 0.2,
and 0.05; retain decimal commas only where reproducing standard text.
Source: Learnings
jmrplens
left a comment
There was a problem hiding this comment.
Independent review against the printed sources (Vigran 2008, Hopkins 2007, Bies/Hansen/Howard 5e, Allard & Atalla 2e), with every oracle recomputed from the books rather than from the branch. The automated reviewers produced nothing actionable on this diff, so this was done as a full adversarial pass: transcription checks digit by digit, independent recomputation of every pinned value, mutation testing of the new oracles, and the house-rules checklist.
Blocking
Nothing blocking. I looked hard for transcription errors, for a rearranged limp-frame formula that only agrees at the limits, and for an implementation error hiding behind the documented Heckl-versus-integral gap, and found none. Details below so the basis for that conclusion is on the record.
Non-blocking
-
CHANGELOG.md (Unreleased, limp-frame entry): misquoted book prose. The entry puts
the book's "softer than about 20 kPa"in quotation marks. Allard & Atalla, printed p. 253, actually prints "the limp model is applicable for materials having a bulk modulus lower than 20 kPa". The docstring oflimp_frame_applicablequotes it correctly; the CHANGELOG (the only shipped text with the wrong wording, the PR body has it too but does not ship) should either quote verbatim or drop the quotation marks. -
orthotropic_transmission_loss: thehecklroute skips input validation that theintegralroute enforces. Insrc/phonometry/building/panel_transmission.pythemethod="heckl"branch returns before thearea/limiting_anglechecks, soorthotropic_transmission_loss(..., method="heckl", area=-5.0, limiting_angle=170.0)succeeds silently (verified on the branch), while the same call on the integral route raises. Meanwhileloss_factoris validated as positive even on the heckl route, where it is equally unused. Either validate all three uniformly before branching or document that the heckl route ignoresareaandlimiting_anglethe way the docstring already documentsloss_factor. Cosmetic, but the asymmetry will confuse someone.
Verified correct
Hopkins Table A2 (printed p. 608, pdf 635): all 25 (cL, h.fc) pairs in tests/reference_data.py match the printed table digit for digit, row order included; I also confirmed the identity h.fc = c0^2 sqrt(12) / (2 pi cL) is density- and Poisson-independent, so each row is a real check. Worst printed-rounding deviation is 0.048 m.Hz against the 0.06 tolerance, so the margin is thin but correct.
Vigran worked example (printed p. 96, pdf 118): recomputed independently from Eqs (3.109)/(3.113)/(3.115) as printed: flat 4.93 / 19.73 Hz, corrugated 25.52 / 102.09 Hz with the developed-length mass (factor 1.0924, which I verified equals both the elliptic closed form and the numeric arc length), and 26.68 / 106.70 Hz with the flat 7.8 kg/m2. The claimed discrimination of corrugated_plate_mass_factor is real: the difference (1.15 Hz and 4.6 Hz) dwarfs the 0.05 / 0.1 Hz test tolerances. Eq. (3.115) is transcribed exactly, including the 0.81 and 5/2 constants and the footnoted Blevins misprint warning.
Bies constants and equations: Eqs (7.30), (7.31), (7.36), (7.38), (7.58), (7.59), (7.60) and the Fig. 7.9(b) caption (printed pp. 377-384) all match the implementation and the four printed constants -54, -13.2, -17 and -23 dB. The exact values 10 lg(2 pi^2/414) = -13.2167 and 10 lg(2/414) = -23.159 pinned in the tests are correct, and point A reproduces 20 lg(fc1 m) - 54 to 0.12 dB with the 5.5 dB field correction, inside the stated 0.15 dB rounding tolerance.
The Heckl-versus-integral gap is a book property, not a defect. At eta -> 0 the Eq. (7.59) branch sits +4.0 to +4.9 dB above the diffuse-field integral across the 500 Hz to 2000 Hz plateau of the Fig. 6.27 case (and the gap grows, not shrinks, if the limiting angle is pushed to 90 degrees, so the 78 degree cutoff is not the cause). Vigran's own Figure 6.27 (printed p. 254) draws Heckl's approximation above its 1 % integral by the same few dB. The integral itself is bracketed on both sides by exact checks that pass: below fc1 it reproduces the elementary mass-law integral to 1e-6 dB, and above 2 fc2 it converges on Eq. (7.60) to under 0.3 dB. Documenting the plateau gap as the accuracy of Heckl's approximation is the right call.
Limp frame (A&A 11.3.4): the implementation is the printed Eq. (11.55) verbatim, (rho_t rho_eq - rho0^2)/(rho_t + rho_eq - 2 rho0) with rho_t = rho1 + phi rho0, not a rearrangement; I checked the printed page directly, and the claimed +6 pdf-to-printed offset of chapter 11 is correct (pdf 259 = printed 253), as are +9 in chapter 6 and the Table 11.2 and Table 6.1 parameter sets. One honesty note the test file already half-makes, stated fully here: the two prose limits alone do not pin the rho0^2 and 2 rho0 terms; a sign-flipped variant satisfies the heavy-frame limit, the omega -> 0 limit and even the 1/rho1 residual scaling (which I confirmed analytically: the residual is -(rho_eq - rho0)^2 / (rho_t + rho_eq - 2 rho0)). What pins those terms is the direct transcription test plus a human reading of the printed equation, which this review supplies. The decoupling frequency 43.27 Hz from Eq. (6.90) (printed p. 126) with the Table 6.1 glass wool recomputes to 43.2706 Hz, and the Beranek 0.05 / Doutres 0.2 / 20 kPa thresholds are as printed on p. 253.
Mutation testing: six deliberate mutations each killed at least one test: a Hopkins row (12.3 -> 12.5), the 2 pi^2 of the Eq. (7.59) branch, the mass factor forced to 1, the 5/2 constant of Bz, the sign of 2 rho0 in the limp density, and sqrt(fc1 fc2) -> fc1 in the Eq. (7.60) branch. The oracles are live.
Composition and house rules: orthotropic_transmission_loss (both methods), single_panel_transmission_loss and plateau_transmission_loss all return SoundReductionResult and all reach .rating() through the same ISO 717-1 path; critical_frequency_upper is appended last with a None default, and the full suite run locally on this head (6844 passed, 69 skipped, no failures) plus the six-platform CI confirm no existing consumer breaks. The ten conformance rows are 6 + 4 as stated, honestly labelled where they are limit-anchors rather than printed digits. EN and ES guide sections are structurally identical and numerically identical token for token (after normalising the Spanish decimal comma in comments). No em-dashes in any added prose, no assert in src/, no module-level level-2 relative imports in _plot/, docs/api-reference.md covers all nine new __all__ names, both new figures come from generate_graphs.py, and the new SVGs are vector-only with the generic sans-serif family.
Two physics additions from the books, both closing a visible hole in models that were isotropic-only or rigid-frame-only. **Orthotropic (ribbed and corrugated) panels** in `building/panel_transmission.py`, from Vigran, Building Acoustics, Sections 3.7.3.3 and 6.5.3, cross-read against Bies, Hansen & Howard 5e Section 7.2.4.5. Cladding that is stiff along the corrugations and limp across them has no single coincidence frequency but a whole range: `orthotropic_critical_frequencies` returns the pair (fc1, fc2) from the two principal bending stiffnesses (Eq. 6.107), and `orthotropic_transmission_loss` predicts the flattened R(f) over it, either by numerically averaging the azimuth-dependent transmission coefficient of Heckl (1960) and Hansen (1993) over the diffuse field (Eqs 6.108 to 6.111 = Bies Eqs 7.30, 7.31 and 7.38, with the size-dependent limiting angle of Bies Eq. 7.36 or a fixed one) or by Heckl's closed-form design chart (`method="heckl"`, Bies Fig. 7.9(b) and Eqs 7.59 and 7.60), which needs no loss factor but requires fc2 > 4 fc1 for its four construction points to stay in order. `SoundReductionResult` gains `critical_frequency_upper` and `.plot()` shades the coincidence range, so the new path composes with the existing Sharp physical model and the plateau estimate on the same axes and through the same ISO 717-1 rating. For the sinusoidal profile, `corrugated_plate_stiffness` gives the Timoshenko and Woinowsky-Krieger equivalent stiffnesses (Eq. 3.115) and `corrugated_plate_mass_factor` the developed-length increase in surface density that has to accompany them; `orthotropic_plate_resonance` is the eigenfrequency of a simply supported orthotropic plate (Eq. 3.113 = Bies Eq. 7.27, after Hearmon 1959), whose lowest mode bounds the validity of both transmission models. **Limp-frame equivalent fluid** (`limp_frame`, `decoupling_frequency`, `limp_frame_applicable` in `materials/porous_absorber.py`), from Allard & Atalla, Propagation of Sound in Porous Media 2e Section 11.3.4, Eqs 11.53 to 11.55 after Panneton (2007). Delany-Bazley, Miki and Johnson-Champoux-Allard all assume a motionless frame, which only holds above the Zwikker-Kosten decoupling frequency. Below it a light frame (felts, screens, aeronautic-grade fibreglass) is dragged along by the pore fluid and its inertia has to be carried. `limp_frame` corrects the effective density of any rigid-frame `PorousMediumResult`, keeps its bulk modulus, and returns another `PorousMediumResult` that drops straight into a `PorousLayer` of the transfer-matrix stack. `limp_frame_applicable` and `LIMP_FRAME_CRITERIA` carry the published rules of thumb for when a frame may be treated as limp at all. Oracles. The orthotropic side is digit-anchored: Vigran's own worked example (a 1 mm steel plate 1 m by 1 m, 4,9 and 19,7 Hz flat, 25,5 and 102 Hz corrugated, which only come out with the developed-length mass), the printed design-chart constants of Bies Fig. 7.9(b) (-54, -13,2, -17 and -23 dB for rho c = 414), the 25 h.fc products of Hopkins Table A2, and the exact reduction of the diffuse integral to its elementary mass-law form and of the orthotropic impedance to Cremer's isotropic one. The limp-frame side is closed-form and limit-anchored, not digit-oracled: Allard & Atalla publishes no table of computed limp densities (its only numeric output table is the Rayleigh-wave Table 10.2), so the checks are the printed closed form, the book's own two exact limits (a heavy frame recovers the already-oracled rigid-frame result digit for digit; the density converges on the apparent total density rho_t = rho1 + phi rho0 as the frequency falls, where the rigid model diverges) and the decoupling frequency of their Table 6.1 glass wool, 43,27 Hz. Ten new conformance rows. Two figures and new sections in the panel-insulation and porous-absorber guides, English and Spanish.
73c1725 to
097b339
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (1)
scripts/generate_graphs.py (1)
8443-8447: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDerive the caption from the local variables instead of retyping them (still unresolved).
porosity,resistivityandframe_densityare already local (line 8396); the literal caption will silently disagree with the plotted curves if any of them is edited.♻️ Proposed fix
ax.text(0.015, 0.03, - "Soft fibrous layer: porosity 0.98, " - "flow resistivity 25 kPa s/m², frame density 30 kg/m³", + f"Soft fibrous layer: porosity {porosity:g}, " + f"flow resistivity {resistivity / 1e3:g} kPa s/m², " + f"frame density {frame_density:g} kg/m³", transform=ax.transAxes, va="bottom", ha="left", fontsize=8.5, color=COLOR_FG)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/generate_graphs.py` around lines 8443 - 8447, Update the caption in the ax.text call to interpolate the local porosity, resistivity, and frame_density variables instead of hard-coded values, preserving the existing labels, units, formatting, and plot styling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 79-82: Update the numeric literals in the English release notes,
including the referenced range, to use decimal points consistently instead of
decimal commas: 4.9, 19.7, 25.5, -13.2, 0.05, 0.2, and 43.27. Preserve the
surrounding wording and values.
In `@scripts/generate_graphs.py`:
- Around line 11927-11934: Update the caption construction in the info block to
derive the corrugation height and pitch from the local amplitude and pitch
variables, converting metres to millimetres for display. Replace the hardcoded
9% with a formatted percentage calculated from the existing mass_corr/mass_flat
ratio, while preserving the surrounding fc and mass formatting.
In `@site/src/content/docs/reference/api/building/panel-transmission.md`:
- Around line 159-165: Update the API source docstrings for the affected
defaults, including the entries corresponding to poisson_ratio and the
additional lines around the cited range, to use Python decimal-point notation
such as 0.3, 0.01, and 78.0 instead of comma decimals. Regenerate the
panel-transmission reference page so its rendered defaults match the callable
signatures.
In `@site/src/content/docs/reference/api/materials/porous-absorber.md`:
- Around line 539-558: Align the documented applicability boundary with
limp_frame_applicable: either change the prose criteria to use “≤” and state
that equality is accepted, or update the implementation to reject equality.
Ensure the parameter and Returns descriptions consistently use the same
inclusive or strict threshold semantics.
In `@src/phonometry/materials/porous_absorber.py`:
- Around line 135-142: Update the limp-frame applicability API around
LIMP_FRAME_CRITERIA and limp_frame to accept porosity and evaluate the general
porosity-dependent FSIr expression instead of exposing criterion="doutres" as a
universal Kc/Kf <= 0.2 test. If retaining the shortcut, explicitly scope or
rename it as a high-porosity rule of thumb; then update the corresponding test
cases in test_limp_frame.py and reporting logic in conformance_report.py to pass
porosity and validate the revised behavior.
---
Duplicate comments:
In `@scripts/generate_graphs.py`:
- Around line 8443-8447: Update the caption in the ax.text call to interpolate
the local porosity, resistivity, and frame_density variables instead of
hard-coded values, preserving the existing labels, units, formatting, and plot
styling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 01e77305-5a52-4b05-a399-00255b65332f
⛔ Files ignored due to path filters (8)
.github/images/limp_frame_effective_density.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_dark.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es.svgis excluded by!**/*.svg.github/images/limp_frame_effective_density_es_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_dark.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es.svgis excluded by!**/*.svg.github/images/orthotropic_transmission_loss_es_dark.svgis excluded by!**/*.svg
📒 Files selected for processing (36)
.zenodo.jsonCHANGELOG.mddocs/CONFORMANCE.mddocs/api-reference.mddocs/getting-started.mddocs/panel-sound-insulation.mddocs/porous-absorbers.mddocs/references.mdllms-full.txtllms.txtscripts/conformance_report.pyscripts/generate_graphs.pysite/public/llms/llms-absorbers.txtsite/public/llms/llms-insulation-design.txtsite/public/llms/llms-start.txtsite/src/content/docs/es/guides/panel-sound-insulation.mdxsite/src/content/docs/es/guides/porous-absorbers.mdxsite/src/content/docs/es/index.mdxsite/src/content/docs/es/reference/bibliography.mdsite/src/content/docs/es/reference/conformance.mdsite/src/content/docs/guides/panel-sound-insulation.mdxsite/src/content/docs/guides/porous-absorbers.mdxsite/src/content/docs/index.mdxsite/src/content/docs/reference/api/building/panel-transmission.mdsite/src/content/docs/reference/api/materials/porous-absorber.mdsite/src/content/docs/reference/bibliography.mdsite/src/content/docs/reference/conformance.mdsrc/phonometry/__init__.pysrc/phonometry/_plot/building.pysrc/phonometry/building/__init__.pysrc/phonometry/building/panel_transmission.pysrc/phonometry/materials/__init__.pysrc/phonometry/materials/porous_absorber.pytests/building/test_orthotropic_panels.pytests/materials/test_limp_frame.pytests/reference_data.py
| Anchored on Vigran's own worked example (a 1 mm steel plate 1 m by 1 m: 4,9 | ||
| and 19,7 Hz flat, 25,5 and 102 Hz corrugated, which only come out with the | ||
| developed-length mass), on the printed design-chart constants of Bies | ||
| Fig. 7.9(b) (-54, -13,2, -17 and -23 dB for `rho c` = 414), on the 25 `h fc` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use decimal points in the English release notes.
These numeric literals mix decimal commas with English prose. Use 4.9, 19.7, 25.5, -13.2, 0.05, 0.2, and 43.27 consistently.
Proposed fix
- 4,9 and 19,7 Hz flat, 25,5 and 102 Hz corrugated
+ 4.9 and 19.7 Hz flat, 25.5 and 102 Hz corrugated
- Fig. 7.9(b) (-54, -13,2, -17 and -23 dB
+ Fig. 7.9(b) (-54, -13.2, -17 and -23 dB
- `|Kc/Kf| < 0,05` and the 0,2
+ `|Kc/Kf| < 0.05` and the 0.2
- Table 6.1 glass wool, 43,27 Hz
+ Table 6.1 glass wool, 43.27 HzAlso applies to: 100-110
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` around lines 79 - 82, Update the numeric literals in the
English release notes, including the referenced range, to use decimal points
consistently instead of decimal commas: 4.9, 19.7, 25.5, -13.2, 0.05, 0.2, and
43.27. Preserve the surrounding wording and values.
| info = [ | ||
| (f"1 mm steel sheet, m'' = {mass_flat:.1f} kg/m², flat " | ||
| f"fc = {flat_fc / 1000.0:.1f} kHz"), | ||
| (f"corrugated H = 10 mm, L = 100 mm, m'' = {mass_corr:.1f} kg/m², " | ||
| f"fc1 = {fc1:.0f} Hz, fc2 = {fc2 / 1000.0:.1f} kHz"), | ||
| (f"worst penalty {penalty:.0f} dB at {nominal[worst]:g} Hz, " | ||
| "for a stiffer and only 9 % heavier panel"), | ||
| ] |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Same caption-drift pattern as the limp-frame figure: hardcode H/L/9 % from the local variables.
amplitude (0.010 m), pitch (0.100 m) and the mass_corr/mass_flat ratio are already computed locally (lines 11873-11881), but the caption spells out "H = 10 mm, L = 100 mm" and "9 %" as literals instead of interpolating them, unlike the neighboring fc1/fc2/mass f-strings in the same block.
♻️ Proposed fix
info = [
(f"1 mm steel sheet, m'' = {mass_flat:.1f} kg/m², flat "
f"fc = {flat_fc / 1000.0:.1f} kHz"),
- (f"corrugated H = 10 mm, L = 100 mm, m'' = {mass_corr:.1f} kg/m², "
+ (f"corrugated H = {amplitude * 1000:g} mm, L = {pitch * 1000:g} mm, "
+ f"m'' = {mass_corr:.1f} kg/m², "
f"fc1 = {fc1:.0f} Hz, fc2 = {fc2 / 1000.0:.1f} kHz"),
(f"worst penalty {penalty:.0f} dB at {nominal[worst]:g} Hz, "
- "for a stiffer and only 9 % heavier panel"),
+ f"for a stiffer and only "
+ f"{(mass_corr / mass_flat - 1) * 100:.0f} % heavier panel"),
]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/generate_graphs.py` around lines 11927 - 11934, Update the caption
construction in the info block to derive the corrugation height and pitch from
the local amplitude and pitch variables, converting metres to millimetres for
display. Replace the hardcoded 9% with a formatted percentage calculated from
the existing mass_corr/mass_flat ratio, while preserving the surrounding fc and
mass formatting.
| | `thickness` | Sheet thickness `h`, in m (> 0). | | ||
| | `corrugation_amplitude` | Corrugation amplitude `H`, in m (> 0). | | ||
| | `corrugation_wavelength` | Corrugation wavelength `L`, in m (> 0). | | ||
| | `youngs_modulus` | Young's modulus `E`, in Pa (> 0). | | ||
| | `poisson_ratio` | Poisson's ratio `nu` (Default: 0,3). | | ||
|
|
||
| **Returns:** The triple `(Bx, Bz, Bxz)` in N.m. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use Python decimal syntax for API defaults.
0,3, 0,01, and 78,0 conflict with the callable signatures’ 0.3, 0.01, and 78.0. Update the source docstrings and regenerate this page.
Based on learnings: non-standard numeric values representing Python defaults should use decimal points.
Also applies to: 487-497
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/content/docs/reference/api/building/panel-transmission.md` around
lines 159 - 165, Update the API source docstrings for the affected defaults,
including the entries corresponding to poisson_ratio and the additional lines
around the cited range, to use Python decimal-point notation such as 0.3, 0.01,
and 78.0 instead of comma decimals. Regenerate the panel-transmission reference
page so its rendered defaults match the callable signatures.
Source: Learnings
| Both published criteria compare the bulk modulus of the frame *in vacuum* | ||
| `K_c` with that of the fluid in the pores `K_f` (Allard & Atalla 2e, | ||
| printed pp. 253-254): Beranek (1947) requires `|K_c/K_f| < 0.05`, and the | ||
| frame structural interaction study of Doutres et al. (2007) relaxes it to | ||
| `|K_c/K_f| < 0.2`. With `K_f` taken as the isothermal bulk modulus of | ||
| air, `P0 = 101,3 kPa`, the relaxed criterion is the book's statement that | ||
| "the limp model is applicable for materials having a bulk modulus lower | ||
| than 20 kPa". Neither criterion accounts for boundary or mounting | ||
| conditions, and the book notes that a thin light foam decoupled from a | ||
| vibrating structure by an air gap behaves limply well above the limit. | ||
|
|
||
| **Parameters** | ||
|
|
||
| | Name | Description | | ||
| | :--- | :--- | | ||
| | `frame_bulk_modulus` | Bulk modulus of the frame in vacuum `K_c`, in Pa (>= 0; pass `abs(K_c)` for a complex modulus). | | ||
| | `criterion` | Key into [`LIMP_FRAME_CRITERIA`](/phonometry/reference/api/materials/porous-absorber/#limp_frame_criteria), `"doutres"` (Default, 0,2) or `"beranek"` (0,05). | | ||
| | `fluid_bulk_modulus` | Bulk modulus of the pore fluid `K_f`, in Pa (Default: 101 325, the isothermal value for air). | | ||
|
|
||
| **Returns:** `True` when `|K_c/K_f|` does not exceed the threshold. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Align the applicability boundary with the implementation.
The prose specifies |K_c/K_f| < threshold, but limp_frame_applicable returns true at equality and the return text says “does not exceed.” Document <= or make the implementation strict.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/content/docs/reference/api/materials/porous-absorber.md` around
lines 539 - 558, Align the documented applicability boundary with
limp_frame_applicable: either change the prose criteria to use “≤” and state
that equality is accepted, or update the implementation to reject equality.
Ensure the parameter and Returns descriptions consistently use the same
inclusive or strict threshold semantics.
| #: Published upper limits on ``|K_c / K_f|`` (frame-in-vacuum bulk modulus over | ||
| #: pore-fluid bulk modulus) below which the limp-frame equivalent fluid of | ||
| #: :func:`limp_frame` may be used, from Allard & Atalla 2e printed pp. 253-254: | ||
| #: ``"beranek"`` is Beranek's (1947) original 0,05 and ``"doutres"`` the 0,2 | ||
| #: to which Doutres et al. (2007) relaxed it with their frame structural | ||
| #: interaction criterion (which, with ``K_f`` approximated by the isothermal | ||
| #: value of air ``P0 = 101,3 kPa``, is the book's "lower than 20 kPa"). | ||
| LIMP_FRAME_CRITERIA: Mapping[str, float] = {"beranek": 0.05, "doutres": 0.2} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not expose the high-porosity Doutres shortcut as a general applicability test.
criterion="doutres" evaluates only Kc/Kf <= 0.2 for every material. The primary criterion depends on porosity, while the 0.2 ratio is the near-unity-porosity simplification calibrated for specific absorption/radiation configurations, thicknesses, and frequencies. Add porosity and evaluate the general FSIr expression, or explicitly scope/rename this API as a high-porosity rule of thumb. Update tests/materials/test_limp_frame.py Lines 272-289 and scripts/conformance_report.py Lines 6959-6971 accordingly. (espace2.etsmtl.ca)
Also applies to: 501-532
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/phonometry/materials/porous_absorber.py` around lines 135 - 142, Update
the limp-frame applicability API around LIMP_FRAME_CRITERIA and limp_frame to
accept porosity and evaluate the general porosity-dependent FSIr expression
instead of exposing criterion="doutres" as a universal Kc/Kf <= 0.2 test. If
retaining the shortcut, explicitly scope or rename it as a high-porosity rule of
thumb; then update the corresponding test cases in test_limp_frame.py and
reporting logic in conformance_report.py to pass porosity and validate the
revised behavior.
|
|
Bito Automatic Review Skipped – PR Already Merged |



Two physics additions from the books, both closing a hole in models that were
isotropic-only or rigid-frame-only.
Orthotropic (ribbed and corrugated) panels
building/panel_transmission.py, from Vigran, Building Acoustics, Sections3.7.3.3 and 6.5.3, cross-read against Bies, Hansen & Howard 5e Section 7.2.4.5
(whose Eqs 7.30, 7.31 and 7.38 are an independent transcription of Vigran's
Eqs 6.108, 6.109 and 6.111, which is how I checked mine).
Cladding that is stiff along the corrugations and limp across them has no single
coincidence frequency but a whole range.
orthotropic_critical_frequenciesreturns the pair
(fc1, fc2)from the two principal bending stiffnesses(Eq. 6.107), and
orthotropic_transmission_losspredicts the flattenedR(f)over it by either published route:
method="integral"averages the azimuth-dependent transmission coefficientof Heckl (1960) and Hansen (1993) over the diffuse field numerically. It is
the only route that responds to the loss factor. Near-grazing angles are
excluded either by the size-dependent limiting angle of Bies Eq. 7.36 (pass
area) or by a fixed one (78 degrees by default, Sharp's value, which isVigran's
sin^2 phi = 0.96).method="heckl"is Heckl's closed form foreta = 0, the design chart ofBies Fig. 7.9(b): field-incidence mass law below
fc1/2, Eq. 7.59 across thecoincidence range, Eq. 7.60 above
2 fc2, straight lines inlog10 facrossthe two gaps. It needs no loss factor and no numerical work, but it requires
fc2 > 4 fc1for its four construction points to stay ordered, and it raisesa
ValueErrorpointing atmethod="integral"when they would not.SoundReductionResultgainscritical_frequency_upperand.plot()shades thecoincidence range, so the orthotropic path composes with the existing Sharp
physical model and with the plateau estimate on one axes and through the same
ISO 717-1 rating. For the sinusoidal profile,
corrugated_plate_stiffnessgivesthe Timoshenko and Woinowsky-Krieger equivalent stiffnesses (Eq. 3.115, whose
Bxzis the pure twisting term, with noBx nu_zcontribution, unlike thegeneral Eq. 3.114) and
corrugated_plate_mass_factorthe developed-lengthincrease in surface density that has to accompany them.
orthotropic_plate_resonanceis the eigenfrequency of a simply supportedorthotropic plate (Eq. 3.113 = Bies Eq. 7.27, after Hearmon 1959), whose lowest
mode bounds the validity of both transmission models.
Limp-frame equivalent fluid
limp_frame,decoupling_frequencyandlimp_frame_applicableinmaterials/porous_absorber.py, from Allard & Atalla, Propagation of Sound inPorous Media 2e Section 11.3.4, Eqs 11.53 to 11.55, after Panneton (2007).
Delany-Bazley, Miki and Johnson-Champoux-Allard all assume a motionless frame,
which only holds above the Zwikker-Kosten decoupling frequency
Fd = sigma phi^2 / (2 pi rho1). Below it a light frame (felts, screens,aeronautic-grade fibreglass) is dragged along by the pore fluid and its inertia
has to be carried by the equivalent fluid.
limp_framecorrects the effectivedensity of any rigid-frame
PorousMediumResult, keeps its bulk modulus, andreturns another
PorousMediumResult, so it drops straight into aPorousLayerof the transfer-matrix stack.
limp_frame_applicableandLIMP_FRAME_CRITERIAcarry the published rules of thumb for when a frame may be treated as limp at
all (Beranek's
|Kc/Kf| < 0.05, the 0.2 to which Doutres et al. 2007 relaxedit, and the "bulk modulus lower than 20 kPa" that the latter becomes for air).
Oracles: what is digit-pinned and what is not
The orthotropic side is digit-anchored.
gives
f(1,1) = 4.9Hz andf(2,2) = 19.7Hz flat, andf(1,1) = 25.5Hzand
f(2,2) = 102Hz once corrugated 20 mm deep at a 100 mm pitch. Fourpublished values, and the corrugated pair only comes out with the
developed-length surface density the same paragraph warns about; with the flat
7.8 kg/m2 the same formulas return 26.7 Hz and 106.7 Hz. That is what pins the
mass factor.
-54 dB at point A, -13.2 dB across the coincidence branch, -17 dB at point D
and -23 dB on the recovery branch, all stated for
rho c = 414. Each isrecovered by subtracting the leading terms from the computed TL.
h.fcrows of Hopkins Table A2 (printed p. 608), added totests/reference_data.pyas the shared source for both the test and theconformance report: a multi-row check on the isotropic coincidence frequency
the orthotropic pair generalises.
fc1the double integral collapses totau = ln((1+q^2)/(1+q^2(1-u)))/q^2, which it reproduces to 1e-6 dB; and asfc2 -> fc1the orthotropic impedance becomes Cremer's isotropic one, checkedagainst an independently evaluated single integral.
The limp-frame side is transcription-anchored, not digit-oracled, and it is
worth being exact about what that means. Allard & Atalla publishes exactly one
table of computed numbers in the whole book (Table 10.2, Rayleigh waves in a
frame in vacuum), and it is not a surface impedance: every
prediction-versus-measurement pair in the porous chapters, Fig. 11.2 included,
is a figure. No other source checked (Cox & D'Antonio, Mechel, Atalla & Sgard,
the round-robin and Biot literature) tabulates a limp effective density, surface
impedance or absorption coefficient for a fully specified material.
What pins the model is the printed Eq. 11.55 itself, restated term by term
in
test_limp_effective_density_matches_the_printed_closed_formindependentlyof the implementation, and behind that test a human reading of the printed page.
The two limits the book states in prose are verified as well, but they are
weaker than their names suggest and it is better to say so than to let them
carry weight they do not bear: neither constrains the
rho0^2and2 rho0terms. A sign-flipped variant of Eq. 11.55 satisfies the heavy-frame limit,
the
omega -> 0limit and the1/rho1scaling of the heavy-frame residual,whose analytic value is
-(rho_eq - rho0)^2 / (rho_t + rho_eq - 2 rho0). Theystay in the suite because they would catch a broken composition or a wrong
rho_t, not because they identify the form.Ordered by what each check is actually worth:
(printed p. 124), where pure arithmetic gives 43.27 Hz: exact, and independent
of everything above;
than 20 kPa" the second becomes for air;
rho1grows thecorrection vanishes and the rigid-frame result comes back, the residual
falling as
1/rho1) and the low-frequency limit (the rigid-frame densitydiverges as
sigma/(j omega)while the limp one converges on the apparenttotal density
rho_t = rho1 + phi rho0): corroboration, not identification,for the reason above.
Ten new conformance rows, six under the panel section and four under the porous
one. The
limp_framedocstring, the test module docstring, the CHANGELOG entryand both guide sections all state plainly that the transcription is the anchor
and that the limits corroborate rather than pin it.
Two notes on the source, for whoever reads the equations next. The pdf-to-printed
page offset of Allard & Atalla is not constant: it is +6 in chapter 11 (pdf
259 is printed 253), against +9 in chapter 6 and +7 in chapter 10. And the
paragraph carrying the applicability rules straddles a page break, so the
Beranek 0.05 threshold is on printed p. 253 while the Doutres 0.2 and the
"bulk modulus lower than 20 kPa" it implies for air are on printed p. 254
(pdf 260); the citations now say
pp. 253-254where they cover both.Figures and docs
Two figures via
scripts/generate_graphs.py, in the usual four variants, bothclearing
check_figures.pyandcheck_figure_contrast.py:orthotropic_transmission_loss: Vigran's own corrugated geometry against aflat sheet of the same material and thickness. Identical within 2 dB below
fc1, then up to 13 dB worse across the coincidence range,Rwfalling from28 dB to 25 dB for a panel that is stiffer and 9 % heavier. The caption is
explicit that the small low-frequency offset is the extra mass plus the
different limiting-angle conventions of the two schemes, not a model
discrepancy.
limp_frame_effective_density: the Table 11.2 material under both models, theview of the book's own Fig. 11.2, with the decoupling frequency and
rho_tmarked. The two curves merging above the decoupling frequency is the figure's
own check on the correction.
New sections in the panel-insulation and porous-absorber guides, English and
Spanish, both with the double snippet and the caveats the sources attach (below
0.7 fc1the Heckl branch underestimatesRon small panels; real corrugatedcladding shows a 2 kHz to 4 kHz dip caused by resonances of the panel sections
between the ribs, which neither route predicts; only the sinusoidal profile has
equivalent stiffnesses here, trapezoidal cladding needs its own).
Gates
ruff check .,mypy src scripts,bandit -r src(0 issues at everyseverity), the full
pytestsuite (6884 passed, 69 skipped),check_figures.py(1636 figures),
check_figure_contrast.py,check_api_reference.py,check_conformance_claims.pyand regenerated conformance, api-docs, sitereports and llms, all green locally on the rebased head.
Rebased onto
mainat 9499d9f. The conformance report regenerates to484/484 checks across 55 domains and 325 standards (main is at 474/55/316;
this branch adds ten checks and nine standards), and the six hand-written count
sites are re-fixed from that regenerated report and re-checked with
scripts/check_conformance_claims.py:.zenodo.json,docs/getting-started.md,both landing-page meta descriptions and the JSON-LD
descriptionof bothconformance pages.
Review follow-ups
Two non-blocking points from the review, both fixed:
orthotropic_transmission_lossvalidatedareaandlimiting_angleonly onthe integral route, so
method="heckl", area=-5.0, limiting_angle=170.0wasaccepted silently while the same call raised on the other route. The three
ignored-by-one-route arguments (
loss_factor,area,limiting_angle) arenow validated together before the method branch, the docstring says which
route uses each and that all are validated regardless, and a new
parametrised test pins identical rejection on both routes.
The book prints "a bulk modulus lower than 20 kPa"; the quotation is
corrected there and in
docs/api-reference.md, which carried the samewording.
Summary by Sourcery
Add orthotropic panel sound insulation modelling and limp-frame equivalent fluid support, with corresponding API, figures, documentation, tests, and conformance checks.
New Features:
Enhancements:
Documentation:
Tests:
Summary by CodeRabbit