Audit pass 4c: final identifier sweep against the naming convention (#113)
* refactor: final identifier sweep against the naming convention
Audit batch 4c — the remaining non-conforming identifiers, closing the
library-wide rename batch:
- public constants drop the unit suffix (units belong in docstrings):
OCTAVE_BANDS, THIRD_OCTAVE_BANDS (absorption_rating) and
BASE_PLATE_BANDS (scattering_diffusion), with PEP 562 __getattr__
shims in the home modules and at the package root; plain import stays
warning-free (verified with -W error)
- sii.BAND_CENTRES -> BAND_CENTERS (American spelling, module shim);
the private road_absorption centres constant renames directly
- ExposureWarning -> OccupationalExposureWarning; the module
__getattr__ returns the same class object so isinstance/except and
warning filters via the old name keep matching
- multiple_shock_vibration reuses hearing.SEXES instead of a private
duplicate
- tests/reference_data.py families gain their standard designations
(ANSIS3_5_*, ANSIS12_2_*, NTACOU112_*, ISO7029_*, ISO389_7_*)
- misleading test files renamed: test_parametrized_signals.py (it never
tested parametric_filters) and test_loudness_contours.py (1:1 with
its module); scripts/gen_llms.py -> generate_llms.py (workflow and
Makefile updated)
- conformance internals catch up (_chk_impulse_*) and an internal use
of the deprecated expanded_uncertainty alias is migrated
Flagged and deliberately left: REFERENCE_DURATION_S (the mixed-units
carve-out applies - seconds and hours coexist in the exposure API) and
the private British 'unfavourable' constants (ISO 717/11654 normative
wording; private tables are named after the standard).
Six new alias tests (root and module access, class identity, the
AttributeError path).
* test: anchor the renamed band tables value-by-value
The tests around the renamed constants asserted lengths or spot values;
they now pin every element (nominal one-third-octave and base-plate
bands, the SII band centers, and the per-impulse Formula 1 values),
verified against the code, so an accidental table edit cannot pass
(Gemini).
feat: underwater seabed reflection, ambient noise and ship-traffic source levels (#149)
* feat: underwater seabed reflection, ambient noise and ship-traffic source levels
Second half of the closed-form underwater propagation sub-phase (P1), building
on the transmission-loss/sound-speed/sonar core:
- seabed_reflection: fluid-fluid Rayleigh reflection coefficient (Medwin & Clay),
critical grazing angle arccos(c1/c2) and bottom loss BL = -20 lg|R|.
- ocean_ambient_noise: Wenz-framework spectrum levels, energy-summing wind noise
(rule of fives) and Mellen thermal noise, with an optional caller-supplied
shipping term.
- ship_traffic_noise: predicted ship source-level spectra from vessel class,
speed and length via JOMOPANS-ECHO (MacGillivray & de Jong 2021, default,
validated to the authors' File S1 reference calculator within 0.01 dB), plus
RANDI 3.1 and Wales & Heitmeyer (2002).
Each module exposes a frozen result dataclass with .plot(), a conformance check
with an independent oracle, one figure in four language/theme variants, and full
English docs plus EN/ES site guides. Conformance 179/179; full suite 2450 passed.
* refactor: address PR review feedback on underwater modules
- seabed_reflection: guard the c1 == c2 & grazing = 0 singular limit
(0/0 -> normal-incidence coefficient) so |R| never returns NaN; add test.
- ocean_ambient_noise: allow a calm sea (wind_speed_knots = 0) to return -inf
(zero energy contribution) rather than raising; add test.
- Migrate the three modules' input validation to the shared _validation helpers
(new require_positive_array enforces finite, positive, 1-D); removes
duplicated hand-rolled checks.
- Clarify units: source spectral-density is "dB re 1 µPa²/Hz at 1 m" (not the
ambiguous "/Hz m") in the plot label, figure, api-reference and docs; scope the
plane-wave reference note so it no longer claims to cover source levels; note
the wind-noise validity range (500 Hz-5 kHz) for the wide-range Wenz example.
- Label the wind/thermal component curves in the ambient-noise figure.
Kept the conformance thermal oracle's hardcoded physical constants (Boltzmann,
1 µPa) for clean-room independence from the module under test. Conformance
179/179; full suite 2452 passed.
* fix: SonarCloud float-equality and long-title docs-deploy failures
- seabed_reflection / ocean_ambient_noise: avoid float equality checks
(SonarCloud S1244). Detect the seabed 0/0 singular limit via np.isnan of the
result instead of comparing the denominator to 0.0; gate the calm-sea branch
with require_non_negative + a relational check.
- Shorten four site-guide titles so the rendered "<title> | phonometry" stays
within the 70-char html-validate limit (long-title), which was blocking the
docs deployment: the two underwater-propagation guides (EN/ES, lengthened in
this PR) and the two pre-existing wind-turbine-noise guides (EN/ES). The full
detail stays in each guide's description.
feat: underwater seabed reflection, ambient noise and ship-traffic source levels (#149)
* feat: underwater seabed reflection, ambient noise and ship-traffic source levels
Second half of the closed-form underwater propagation sub-phase (P1), building
on the transmission-loss/sound-speed/sonar core:
- seabed_reflection: fluid-fluid Rayleigh reflection coefficient (Medwin & Clay),
critical grazing angle arccos(c1/c2) and bottom loss BL = -20 lg|R|.
- ocean_ambient_noise: Wenz-framework spectrum levels, energy-summing wind noise
(rule of fives) and Mellen thermal noise, with an optional caller-supplied
shipping term.
- ship_traffic_noise: predicted ship source-level spectra from vessel class,
speed and length via JOMOPANS-ECHO (MacGillivray & de Jong 2021, default,
validated to the authors' File S1 reference calculator within 0.01 dB), plus
RANDI 3.1 and Wales & Heitmeyer (2002).
Each module exposes a frozen result dataclass with .plot(), a conformance check
with an independent oracle, one figure in four language/theme variants, and full
English docs plus EN/ES site guides. Conformance 179/179; full suite 2450 passed.
* refactor: address PR review feedback on underwater modules
- seabed_reflection: guard the c1 == c2 & grazing = 0 singular limit
(0/0 -> normal-incidence coefficient) so |R| never returns NaN; add test.
- ocean_ambient_noise: allow a calm sea (wind_speed_knots = 0) to return -inf
(zero energy contribution) rather than raising; add test.
- Migrate the three modules' input validation to the shared _validation helpers
(new require_positive_array enforces finite, positive, 1-D); removes
duplicated hand-rolled checks.
- Clarify units: source spectral-density is "dB re 1 µPa²/Hz at 1 m" (not the
ambiguous "/Hz m") in the plot label, figure, api-reference and docs; scope the
plane-wave reference note so it no longer claims to cover source levels; note
the wind-noise validity range (500 Hz-5 kHz) for the wide-range Wenz example.
- Label the wind/thermal component curves in the ambient-noise figure.
Kept the conformance thermal oracle's hardcoded physical constants (Boltzmann,
1 µPa) for clean-room independence from the module under test. Conformance
179/179; full suite 2452 passed.
* fix: SonarCloud float-equality and long-title docs-deploy failures
- seabed_reflection / ocean_ambient_noise: avoid float equality checks
(SonarCloud S1244). Detect the seabed 0/0 singular limit via np.isnan of the
result instead of comparing the denominator to 0.0; gate the calm-sea branch
with require_non_negative + a relational check.
- Shorten four site-guide titles so the rendered "<title> | phonometry" stays
within the 70-char html-validate limit (long-title), which was blocking the
docs deployment: the two underwater-propagation guides (EN/ES, lengthened in
this PR) and the two pre-existing wind-turbine-noise guides (EN/ES). The full
detail stays in each guide's description.
feat: underwater sound propagation (transmission loss, sound speed, sonar equation) (#148)
* feat(underwater): speed of sound in sea water (UNESCO / Del Grosso / Mackenzie)
sea_water_sound_speed() with three selectable equations (UNESCO/Chen-Millero
Wong-Zhu ITS-90 default, Del Grosso 1974, Mackenzie 1981), depth_to_pressure()
(Leroy-Parthiot 1998) and a SoundSpeedProfile with .plot(). Oracles: the
canonical Mackenzie check value 1550.744 m/s and mutual agreement of the three
equations to <1 m/s in their common domain.
* feat(underwater): transmission loss (spreading + volume absorption)
spreading_loss() (spherical/cylindrical/practical), seawater_absorption() with
Francois-Garrison (default), Ainslie-McColm and Thorp models, and
transmission_loss() -> TransmissionLossResult with .plot(). Oracles: closed-form
spreading recomputation, inline recomputation of each absorption formula, and
Francois-Garrison <-> Ainslie-McColm agreement within 10%.
* feat(underwater): sonar equation (passive and active)
passive_sonar_equation() (SE = SL - TL - (NL - DI) - DT) and
active_sonar_equation() (monostatic, noise- or reverberation-limited, 2.TL)
-> SonarEquationResult with signal excess, SNR, figure of merit and .plot().
Oracle: a hand-worked Urick/Etter term balance.
* test(underwater): conformance domain for transmission-loss propagation
Six checks: Mackenzie canonical sound speed (1550.744 m/s), UNESCO<->Mackenzie
cross-model agreement, spherical spreading, Thorp absorption, Ainslie-McColm<->
Francois-Garrison agreement, and the passive-sonar figure of merit. 174/174.
* docs(underwater): figures for TL, sound-speed profile and sonar equation
Three propagation figures x4 variants (light/dark x EN/ES): transmission loss
with the spreading/absorption split, the UNESCO sound-speed profile with the
sound-channel axis, and the passive sonar equation's signal excess vs TL.
* docs(underwater): guide, API reference, indices and sidebar for propagation
New EN docs page + EN/ES site guides for transmission loss, sea-water sound
speed and the sonar equation; api-reference rows for the new public symbols;
README and docs/README index entries; astro sidebar item under Underwater
acoustics.
* fix(underwater): Del Grosso pressure conversion (bar → kg/cm² multiplies)
Subagent review caught an inverted unit conversion: bar → kg/cm² is ×1.019716
(1 bar = 1.019716 kg/cm²), not ÷. With the fix Del Grosso at 10 °C/35 ‰/1000 m
gives 1506.31 m/s, agreeing with UNESCO (1506.52) and Mackenzie (1506.26) to
<0.3 m/s (was 1505.68). Update the cross-model test value and add an independent
Del Grosso conformance check (175/175).
* docs(underwater): address PR review (breadcrumb, examples, api-reference)
- add the documentation-index breadcrumb + descriptive H1 to the propagation
guide (repo convention)
- make the guide's absorption example self-contained (index the array, print α)
- clarify SonarEquationResult.noise_level (masking is RL when reverberation-
limited) and document Thorp's <50 kHz validity
- api-reference: add the reverberation-limited active formula and the full
SonarEquationResult field list
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
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
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