feat: installed structure-borne sound from equipment (EN 12354-5)
Add the EN 12354-5:2009 prediction of the receiving-room sound pressure
level from building service equipment that injects structure-borne sound
into the building. Final PR of the structural vibroacoustics series (#16),
closing the chain source (EN 15657) -> coupling (ISO 10846 / ISO 7626
mobilities) -> building transmission.
New module `installed_structure_borne`:
- `coupling_term` DC = 10 lg(|Ys+Yi+Yk|^2/(|Ys| Re{Yi})) (Formula 19b/e),
with force-source (19c) and velocity-source (19d) limits.
- `installed_structure_borne_power_level` LWs,inst = LWs,c - DC (18b).
- `structure_borne_pressure_level_path` Ln,s,ij = LWs,inst - Dsa - Rij,ref
- 10 lg(Si/S0) - 10 lg(A0/4) (18a, S0 = A0 = 10 m2) and
`total_structure_borne_pressure_level` energetic path sum (17).
- `InstalledSourceResult` (`.overall_level`, `.plot()`) and
`installed_source_prediction` for a multi-path prediction.
The source and receiver mobilities/impedances are those of
mechanical_mobility and transfer_stiffness; LWs,c comes from EN 15657.
Conformance is anchored on the coupling-term force-source limit, the
installed-power identity and the area/absorption terms of Formula 18a;
Dsa and Rij,ref are inputs (measurement / EN 12354-1 / Annexes D, F)
(137/137).
Adds the cascade figure (characteristic -> installed -> paths -> total),
the EN/ES guides, the docs index and api-reference rows, and the sidebar
entry.
feat: installed structure-borne sound from equipment (EN 12354-5)
Add the EN 12354-5:2009 prediction of the receiving-room sound pressure
level from building service equipment that injects structure-borne sound
into the building. Final PR of the structural vibroacoustics series (#16),
closing the chain source (EN 15657) -> coupling (ISO 10846 / ISO 7626
mobilities) -> building transmission.
New module `installed_structure_borne`:
- `coupling_term` DC = 10 lg(|Ys+Yi+Yk|^2/(|Ys| Re{Yi})) (Formula 19b/e),
with force-source (19c) and velocity-source (19d) limits.
- `installed_structure_borne_power_level` LWs,inst = LWs,c - DC (18b).
- `structure_borne_pressure_level_path` Ln,s,ij = LWs,inst - Dsa - Rij,ref
- 10 lg(Si/S0) - 10 lg(A0/4) (18a, S0 = A0 = 10 m2) and
`total_structure_borne_pressure_level` energetic path sum (17).
- `InstalledSourceResult` (`.overall_level`, `.plot()`) and
`installed_source_prediction` for a multi-path prediction.
The source and receiver mobilities/impedances are those of
mechanical_mobility and transfer_stiffness; LWs,c comes from EN 15657.
Conformance is anchored on the coupling-term force-source limit, the
installed-power identity and the area/absorption terms of Formula 18a;
Dsa and Rij,ref are inputs (measurement / EN 12354-1 / Annexes D, F)
(137/137).
Adds the cascade figure (characteristic -> installed -> paths -> total),
the EN/ES guides, the docs index and api-reference rows, and the sidebar
entry.
Audit pass 11b: Tier-1 documentation animations (#122)
* Audit pass 11b: Tier-1 documentation animations
Add the four Tier-1 animation clips the audit prioritised — level-vs-time
phenomena the library already computes, rendered deterministically by
generate_graphs.py:
- time-weighting ballistics: the Fast/Slow/Impulse detectors chasing a tone
burst, Impulse decaying slowest (IEC 61672-1);
- onset detection: an L_AF history with the >10 dB/s onset highlighted and
OR/LD/P/KI shown live (NT ACOU 112);
- instantaneous intensity: p·u flowing for a progressive wave vs sloshing
about zero for a standing wave (IEC 61043);
- Schroeder backward integration: the decay curve emerging from the tail,
ending with the T20/T30 lines (ISO 3382).
Each is produced in the four language x theme variants as a compact WebM for
the site (embedded as an autoplaying, looping <video>) and, for English, an
animated GIF for the GitHub docs. A new `_translate_str` localises the
per-frame labels (the clips never pass through themed_path), the site gains
<video> theme-switching CSS, and `make animations` (kept out of CI, since
video is not byte-reproducible) regenerates them.
* Address review of the animations PR
- generate_animations: fail fast with a clear message when ffmpeg is absent
(Gemini).
- Schroeder _fit: guard against fewer than two points in a T20/T30 range and
a non-decaying slope, and keep xmax robust when a fit is unavailable
(Copilot).
- Site <video>s: add native `controls` (a keyboard-accessible pause/stop for
the looping motion, WCAG 2.2.2) and move the description to `title`, dropping
the `role="img"`/`aria-label` pair so the controls stay exposed to assistive
tech (CodeRabbit).
- Spanish: "energy sloshes" -> "la energía va y viene" (technical register;
ES intensity clips regenerated) (CodeRabbit).
- Group `no-autoplay` with the other `no-*` html-validate rules (CodeRabbit).
* Fix stale 'no controls' comment in theme-images.css
The Tier-1 <video>s now carry native controls; update the shared CSS comment
to match (CodeRabbit).
docs: restructure into docs/, slim PyPI-safe README, bilingual Starlight site with theme-aware figures (#61)
* docs: split README content into docs/ topic pages
11 topic pages under docs/ (guides + reference), including the new
levels/spectrogram documentation and a Why PyOctaveBand page distilled
from the issue #38 IEC 61672-1 compliance analysis.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: add auto-generated figures for levels/spectrogram/zero-phase docs
Four new generate_* functions (spectrogram example, LN levels over the
Fast envelope, zero-phase group-delay comparison, A-weighting HF accuracy),
a 'make graphs' target, and a CONTRIBUTING section formalizing that every
docs image must come from generate_graphs.py.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: slim README to hook + quick start with absolute links (PyPI-safe)
The README is the PyPI landing page and PyPI does not resolve relative
links, so every link (docs pages, website, CONTRIBUTING, LICENSE) is now
absolute. The Documentation section sits right after installation with a
per-page table. Full content lives in docs/ and on the website.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs(site): scaffold Astro/Starlight with en/es i18n, KaTeX, and English content
Starlight site under site/ with base /PyOctaveBand for GitHub Pages,
locale-aware sidebar, KaTeX math rendering, and the 11 English pages
ported from docs/ (links rewritten to site routes, GitHub alerts
converted to Starlight asides).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: generate all figures in light and dark themes
generate_graphs.py now renders every figure twice (light + _dark suffix)
via a theme switch (dark_background style, foreground color swap).
- docs/ (GitHub): <picture> with prefers-color-scheme sources.
- site/ (Starlight): dual img.light-only/.dark-only following the theme
toggle via [data-theme] CSS.
- README keeps plain light images (PyPI sanitizes <picture>).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs(site): add complete Spanish translation
Full natural translation of all 12 pages (landing, getting started,
7 guides, 3 reference pages) with theme-aware images and es/ routes.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* ci: deploy Starlight docs site to GitHub Pages
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* ci: bump actions to latest, dependabot cooldown 0, refresh all dependencies
- Workflows: checkout v7; docs.yml to setup-node v6, pnpm/action-setup v6,
upload-pages-artifact v5, deploy-pages v5 (pnpm stays 11.x).
- Dependabot: cooldown 0 days on all ecosystems, stop ignoring pip
minor/patch updates (grouped), add npm ecosystem for site/.
- Python deps to latest: scipy 1.18, matplotlib 3.11, numba 0.66,
mypy 2.1, ruff 0.15.20, pytest 9.1. numpy capped <2.5 in the dev/CI
environment because numba 0.66 requires it (users without the [perf]
extra are unaffected).
- Site deps to latest: astro 7.0.6, starlight 0.41.3, katex 0.17, sharp 0.35.
- Repo configured via API: homepage -> docs site URL, GitHub Pages enabled
with build_type=workflow (no manual post-merge step needed anymore).
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: address review feedback (dependabot schema, snippets, workflow hardening)
- dependabot: remove cooldown blocks (default-days minimum is 1; no
cooldown IS the zero-delay behavior).
- docs.yml: scope pages/id-token permissions to the deploy job only and
set persist-credentials: false on checkout (third-party install scripts
run in the build job).
- Snippets: add missing numpy import, define the bank in the zero-phase
example, linspace endpoint=False (docs + site EN/ES + README).
- tsconfig: exclude node_modules and .astro explicitly.
- A-weighting +2.00 constant kept: verified numerically that
20*log10(RA(1000)) = -1.99986, so +2.00 yields 0.0001 dB at 1 kHz;
the suggested +2.06 would introduce a +0.06 dB offset.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
docs: content enrichment (4 new figures, diagrams, equations) + full SEO/GEO layer (#66)
* docs: add group-delay, IEC toneburst, block-continuity and class-mask figures
Four new auto-generated figures (light+dark) wired into the filter-banks,
time-weighting, why-pyoctaveband and block-processing pages (docs/ EN +
site EN/ES), including a new 'Verifying the IEC 61260-1 class' section
documenting verify_filter_class with the acceptance-mask overlay.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: remove unreferenced legacy filter_fraction_* images
Leftovers from the pre-restructure README naming; nothing references
them (docs, site, scripts). Light/dark figure parity is now exact 26/26.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs(site): GEO layer - robots.txt AI opt-in, llms.txt generation, mermaid
- robots.txt: universal allow + Content-Signal + explicit opt-in for 14 AI
crawlers + sitemap pointer.
- scripts/gen_llms.py generates llms.txt (structured project context with
AI-assistant install notes) and llms-full.txt (all docs pages inline);
committed at root, republished to the site via prebuild copy and
regenerated in the docs workflow for freshness. New 'make llms' target.
- astro-mermaid (+ mermaid) with autoTheme for the new calibration and
multirate diagrams; starlight-links-validator and lastUpdated enabled.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs(site): SEO/GEO layer complete - JSON-LD, per-page heads, quality gates
- Site-wide JSON-LD @graph (Person with canonical jmrp.io identity incl.
ORCID, WebSite, SoftwareApplication with single-sourced version and
feature list, SoftwareSourceCode) + og/twitter/author/theme metas,
rel=me links, PGP key, manifest, Bing verification (Google property
already verified).
- Head.astro: per-page TechArticle (+speakable) and locale-aware
BreadcrumbList linked into the @graph, canonical URLs, twitter tags.
Footer.astro maintainer block. favicon.svg + PWA manifest.
- Quality gates: sitemap lastmod stamping (git dates, postbuild), EN/ES
i18n parity check, html-validate and pa11y (WCAG2AA) wired into the
docs workflow with fetch-depth: 0.
- Accessibility sweep: descriptive EN/ES alt text on all 147 figure
references; site uses style width (valid HTML), GitHub docs keep the
width attribute.
- Splash landing now shows the mobile menu button (route middleware
enables the sidebar; CSS hides the pane on desktop to keep the hero).
- og-image: designed 1200x630 card (gpt-image-2 via inference.sh, adapted
and committed); matplotlib generator kept as documented fallback.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: fix extraneous f-prefix and duplicate canonical link
Starlight already emits the canonical URL; Head.astro no longer adds a
second one.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs(site): WCAG2AA - convert deprecated table align attributes to CSS
pa11y flagged 158 deprecated align attributes from markdown table
alignment; the rehypeTableAlign plugin (ported from the reference site)
rewrites them to text-align styles. 10/10 audited URLs now pass WCAG2AA.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf
* docs: address review feedback (robustness, Table 4 consistency, llms links)
- version regex accepts single/double quotes; rehypeTableAlign appends to
existing styles; routeData guards undefined starlightRoute; Footer lang
detection handles /es without trailing slash; pa11y script kills by PID
(job control unavailable in some CI shells).
- why-pyoctaveband: the toneburst table is Table 4 in IEC 61672-1:2013
(Table 3 is the weightings) - fixed the stale issue-#38 wording, and
softened 'peaking exactly' to 'within 0.1 dB' (EN/ES).
- gen_llms.py absolutizes docs-relative links so llms-full.txt resolves
as a flat artifact.
- Intentionally NOT changed: docs/ keeps the width attribute on images
(GitHub strips style attributes); the site uses style widths.
Claude-Session: https://claude.ai/code/session_013kkVt3nxi9svp1an28uHxf