From 4c99a2ec3b06d863372d74de7a285084b4a22779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 04:08:55 +0200 Subject: [PATCH 1/3] Give underwater three families The domain was thirteen flat modules covering the three questions an underwater problem asks, so it now answers them in that order: sources for what makes the sound, propagation for how it gets there, bioacoustics for who hears it. The ISO 18405 quantities and the sonar equation stay at the root, because all three families are written in their terms. The IEC 61043 intensity-instrument class check moves with them, from metrology to emission, next to the intensity chain it verifies. That was the one API section reaching into a second package to stay coherent. The namespace is untouched: the package exports the same 82 names and the ten old module paths keep working until 5.0. The path that was the propagation module is now the family package, which exports what the module did. --- CHANGELOG.md | 31 ++++ docs/ERRATA.md | 8 +- docs/api-reference.md | 7 +- docs/atmospheric-refraction.md | 2 +- docs/underwater-solvers.md | 2 +- llms-full.txt | 21 +-- llms.txt | 10 +- scripts/api_taxonomy.py | 36 +++-- scripts/conformance_report.py | 6 +- scripts/generate_api_docs.py | 2 +- site/public/llms/llms-simulation.txt | 2 +- site/public/llms/llms-underwater.txt | 2 +- .../docs/es/guides/atmospheric-refraction.mdx | 2 +- .../docs/es/guides/marine-mammal-exposure.mdx | 2 +- .../docs/es/guides/underwater-acoustics.mdx | 2 +- .../docs/es/guides/underwater-propagation.mdx | 2 +- .../docs/es/guides/underwater-solvers.mdx | 2 +- site/src/content/docs/es/reference/errata.md | 8 +- .../docs/guides/atmospheric-refraction.mdx | 2 +- .../docs/guides/marine-mammal-exposure.mdx | 2 +- .../docs/guides/underwater-acoustics.mdx | 2 +- .../docs/guides/underwater-propagation.mdx | 2 +- .../docs/guides/underwater-solvers.mdx | 2 +- .../reference/api/environment/refraction.md | 4 +- site/src/content/docs/reference/api/index.md | 24 ++-- .../api/power/intensity-compliance.md | 4 +- .../docs/reference/api/power/intensity.md | 2 +- ...cean-ambient-noise.md => ambient-noise.md} | 14 +- ...ine-mammal-audiograms.md => audiograms.md} | 24 ++-- .../{propagation.md => closed-form.md} | 18 +-- ...{numerical-propagation.md => numerical.md} | 18 +-- .../api/underwater/pile-driving-noise.md | 8 +- .../api/underwater/seabed-reflection.md | 2 +- .../api/underwater/ship-radiated-noise.md | 2 +- .../api/underwater/ship-traffic-noise.md | 6 +- .../api/underwater/sonar-equation.md | 8 +- .../reference/api/underwater/sound-speed.md | 2 +- ...arine-mammal-weighting.md => weighting.md} | 28 ++-- .../api/underwater/weston-regimes.md | 4 +- site/src/content/docs/reference/errata.md | 8 +- site/src/generated/api-sidebar.mjs | 10 +- src/phonometry/__init__.py | 112 +++++++-------- src/phonometry/_compat.py | 43 ++++-- src/phonometry/_plot/emission.py | 129 ++++++++++++++++- src/phonometry/_plot/metrology.py | 120 ---------------- src/phonometry/_plot/underwater.py | 58 ++++---- src/phonometry/_report/iec61043.py | 6 +- src/phonometry/emission/__init__.py | 18 ++- src/phonometry/emission/intensity.py | 2 +- .../intensity_compliance.py | 4 +- .../environment/propagation/refraction.py | 4 +- src/phonometry/metrology/__init__.py | 33 ++--- src/phonometry/underwater/__init__.py | 132 +++++++++--------- .../underwater/bioacoustics/__init__.py | 52 +++++++ .../audiograms.py} | 6 +- .../weighting.py} | 10 +- .../underwater/propagation/__init__.py | 87 ++++++++++++ .../closed_form.py} | 4 +- .../numerical.py} | 16 +-- .../{ => propagation}/seabed_reflection.py | 10 +- .../{ => propagation}/sound_speed.py | 4 +- .../{ => propagation}/weston_regimes.py | 8 +- src/phonometry/underwater/sonar_equation.py | 2 +- src/phonometry/underwater/sources/__init__.py | 58 ++++++++ .../ambient_noise.py} | 6 +- .../{ => sources}/pile_driving_noise.py | 18 +-- .../{ => sources}/ship_radiated_noise.py | 6 +- .../{ => sources}/ship_traffic_noise.py | 8 +- tests/conftest.py | 2 +- tests/emission/test_emission_plot_i18n.py | 47 +++++++ .../test_intensity_compliance.py | 0 tests/metrology/test_metrology_plot_i18n.py | 18 --- tests/test_deprecated_aliases.py | 11 ++ .../test_audiograms.py} | 2 +- .../test_weighting.py} | 6 +- .../test_closed_form.py} | 0 .../test_numerical.py} | 2 +- .../test_seabed_reflection.py | 2 +- .../test_sound_speed.py} | 2 +- .../{ => propagation}/test_weston_regimes.py | 6 +- .../test_ambient_noise.py} | 2 +- .../{ => sources}/test_pile_driving_noise.py | 0 .../{ => sources}/test_ship_radiated_noise.py | 2 +- .../{ => sources}/test_ship_traffic_noise.py | 4 +- .../test_ainslie_worked_examples.py | 4 +- tests/underwater/test_underwater_plot_i18n.py | 8 +- 86 files changed, 863 insertions(+), 554 deletions(-) rename site/src/content/docs/reference/api/underwater/{ocean-ambient-noise.md => ambient-noise.md} (90%) rename site/src/content/docs/reference/api/underwater/{marine-mammal-audiograms.md => audiograms.md} (84%) rename site/src/content/docs/reference/api/underwater/{propagation.md => closed-form.md} (89%) rename site/src/content/docs/reference/api/underwater/{numerical-propagation.md => numerical.md} (93%) rename site/src/content/docs/reference/api/underwater/{marine-mammal-weighting.md => weighting.md} (92%) rename src/phonometry/{metrology => emission}/intensity_compliance.py (99%) create mode 100644 src/phonometry/underwater/bioacoustics/__init__.py rename src/phonometry/underwater/{marine_mammal_audiograms.py => bioacoustics/audiograms.py} (98%) rename src/phonometry/underwater/{marine_mammal_weighting.py => bioacoustics/weighting.py} (98%) create mode 100644 src/phonometry/underwater/propagation/__init__.py rename src/phonometry/underwater/{propagation.py => propagation/closed_form.py} (99%) rename src/phonometry/underwater/{numerical_propagation.py => propagation/numerical.py} (98%) rename src/phonometry/underwater/{ => propagation}/seabed_reflection.py (97%) rename src/phonometry/underwater/{ => propagation}/sound_speed.py (99%) rename src/phonometry/underwater/{ => propagation}/weston_regimes.py (99%) create mode 100644 src/phonometry/underwater/sources/__init__.py rename src/phonometry/underwater/{ocean_ambient_noise.py => sources/ambient_noise.py} (98%) rename src/phonometry/underwater/{ => sources}/pile_driving_noise.py (95%) rename src/phonometry/underwater/{ => sources}/ship_radiated_noise.py (98%) rename src/phonometry/underwater/{ => sources}/ship_traffic_noise.py (96%) create mode 100644 tests/emission/test_emission_plot_i18n.py rename tests/{metrology => emission}/test_intensity_compliance.py (100%) rename tests/underwater/{test_marine_mammal_audiograms.py => bioacoustics/test_audiograms.py} (99%) rename tests/underwater/{test_marine_mammal_weighting.py => bioacoustics/test_weighting.py} (99%) rename tests/underwater/{test_underwater_propagation.py => propagation/test_closed_form.py} (100%) rename tests/underwater/{test_numerical_propagation.py => propagation/test_numerical.py} (99%) rename tests/underwater/{ => propagation}/test_seabed_reflection.py (99%) rename tests/underwater/{test_underwater_sound_speed.py => propagation/test_sound_speed.py} (99%) rename tests/underwater/{ => propagation}/test_weston_regimes.py (98%) rename tests/underwater/{test_ocean_ambient_noise.py => sources/test_ambient_noise.py} (98%) rename tests/underwater/{ => sources}/test_pile_driving_noise.py (100%) rename tests/underwater/{ => sources}/test_ship_radiated_noise.py (98%) rename tests/underwater/{ => sources}/test_ship_traffic_noise.py (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 376914a76..a5040eb7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1036,6 +1036,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/). the same 251 names, and the nineteen pre-split module paths keep working until 5.0. +- `phonometry.underwater` has three families, along the three questions an + underwater problem asks. `underwater.sources` is what makes the sound: + ISO 17208 ship radiated noise, shipping traffic, impact pile driving and the + wind and thermal noise the sea makes on its own. `underwater.propagation` is + how it gets there: closed-form transmission loss, Weston's regimes, the + numerical solvers (normal modes, rays, parabolic equation), the seabed it + reflects off and the sound speed profile it travels through. + `underwater.bioacoustics` is who hears it: marine mammal audiograms and the + regulatory auditory weighting and exposure criteria built on them. The + ISO 18405 quantities and the sonar equation stay at the root, because all + three families are written in their terms. + + Four modules lose a word the family now says: `ocean_ambient_noise`, + `marine_mammal_audiograms`, `marine_mammal_weighting` and + `numerical_propagation` become `sources.ambient_noise`, + `bioacoustics.audiograms`, `bioacoustics.weighting` and + `propagation.numerical`. The module that was `underwater.propagation` is + `propagation.closed_form`, and the name it vacated is the family package, + which exports everything the module did: that path keeps working without a + notice, since a package cannot be shadowed by an alias that warns. + + Nothing moves in the namespace: `from phonometry import underwater` exports + the same 82 names, and the ten pre-split module paths keep working until 5.0. + +- The IEC 61043 intensity-instrument class check is + `phonometry.emission.intensity_compliance`, next to the intensity chain it + verifies, rather than in `phonometry.metrology`. It was the one section of + the API reference that had to reach into a second package to stay coherent, + and now no section does. Reading the names from `metrology` still works + until 5.0, with the usual notice. + - `phonometry.psychoacoustics` has two families, along the split every text on sound quality makes. `psychoacoustics.loudness` holds how loud a sound is: the four models (ISO 532-1 Zwicker, ISO 532-2 Moore-Glasberg, the diff --git a/docs/ERRATA.md b/docs/ERRATA.md index 251b5ae26..384efa92d 100644 --- a/docs/ERRATA.md +++ b/docs/ERRATA.md @@ -1085,7 +1085,7 @@ which is the check that enforces the rule; see de las bandas de octava") carves out octave-only processors as a special case. Both are redundant if every class 2 processor is an octave-band one. - **Library behaviour:** implements the EN/IEC reading. - [`verify_intensity_class`](../src/phonometry/metrology/intensity_compliance.py) + [`verify_intensity_class`](../src/phonometry/emission/intensity_compliance.py) treats the full 22-band one-third-octave set as attesting either class, and the 7-band octave set (63 Hz to 4 kHz) as a class 2 alternative that never attests class 1, with both branches pinned by regression tests @@ -2067,7 +2067,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](../src/phonometry/underwater/weston_regimes.py) + [`weston_regimes.py`](../src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2102,7 +2102,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](../src/phonometry/underwater/marine_mammal_weighting.py) + [`marine_mammal_weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2171,7 +2171,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](../src/phonometry/underwater/marine_mammal_weighting.py), + in [`marine_mammal_weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/docs/api-reference.md b/docs/api-reference.md index c72e82570..cfc756556 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -26,18 +26,18 @@ contour = aircraft.noise_contour(path, powers, distances, sel, lmax, x=gx, y=gy) | :--- | :--- | | `phonometry.filters` | Octave and fractional-octave filter banks, frequency weightings and time weighting, parametric EQ, IEC 61260-1 and IEC 61672-1 class verification | | `phonometry.signals` | Levels (Leq, LAeq, percentiles), Welch and multitaper spectra, coherence, time-frequency, correlation, envelope, cepstrum, phase, synchronous averaging, test signals | -| `phonometry.metrology` | Calibration, GUM uncertainty and Monte Carlo, data qualification (stationarity, trends, peak statistics), IEC 61043 intensity class | +| `phonometry.metrology` | Calibration, GUM uncertainty and Monte Carlo, data qualification (stationarity, trends, peak statistics) | | `phonometry.psychoacoustics` | Two families: `loudness` (ISO 532-1 Zwicker, ISO 532-2 and ISO 532-3 Moore-Glasberg, ECMA-418-2, ISO 226 equal-loudness contours) and `quality` (sharpness, roughness, fluctuation strength, tonality, tone audibility, annoyance), plus the ERB scale both measure on | | `phonometry.speech` | Speech Transmission Index (IEC 60268-16), Speech Intelligibility Index (ANSI S3.5), STOI and ESTOI | | `phonometry.hearing` | Audiometric thresholds (ISO 7029/389-7), noise-induced hearing loss (ISO 1999), occupational exposure (ISO 9612) | -| `phonometry.emission` | Sound power (ISO 3740 family), sound intensity, vibration-based power | +| `phonometry.emission` | Sound power (ISO 3740 family), sound intensity and the IEC 61043 instrument class it is measured with, vibration-based power | | `phonometry.room` | Room acoustics (ISO 3382), impulse responses, open-plan, room-noise criteria, reverberation prediction, EN 12354-6 | | `phonometry.building` | Three subgroups: `measurement` (field, laboratory, survey and intensity methods with their ISO 717 ratings and ISO 12999 uncertainty), `prediction` (EN 12354 global and detailed models, facades, panels, apertures, plenums and resilient layers) and `regulation` (national codes) | | `phonometry.materials` | Four families by what the material does: `absorbers` (ISO 354, ISO 11654, ISO 12999-2, impedance tube ISO 10534-2, airflow resistance ISO 9053, porous and multilayer models, Biot, slow-sound metamaterials), `diffusers` (Schroeder design, metadiffusers, scattering and diffusion ISO 17497), `surfaces` (in-situ road absorption ISO 13472) and `resilient` (dynamic stiffness EN 29052-1) | | `phonometry.vibration` | Three families: `structural` (mobility ISO 7626, plate junctions, radiation, experimental SEA, transfer stiffness ISO 10846), `human` (ISO 2631/5349/8041 exposure and multiple shocks) and `machinery` (fault frequencies and condition monitoring) | | `phonometry.environment` | Three subgroups: `sources` (CNOSSOS road and rail emission, wind-turbine apparent sound power), `propagation` (ISO 9613-1/-2, ground effect and barriers, refraction by ray tracing and the parabolic equation) and `assessment` (ISO 1996-1/-2 rating and measurement, impulsive prominence, RD 1367/2007) | | `phonometry.aircraft` | EPNL (ICAO Annex 16), SAE ARP 5534 absorption, airport contours (ECAC Doc 29), rotorcraft (ECAC Doc 32) | -| `phonometry.underwater` | ISO 18405/17208/18406 levels, propagation and Weston regimes, sound speed, sonar equation and detection range, seabed, ambient and ship-traffic noise, marine-mammal audiograms and regulatory auditory weighting, numerical solvers | +| `phonometry.underwater` | Three families: `sources` (ISO 17208 ship radiated noise, traffic, pile driving, wind and thermal ambient noise), `propagation` (closed-form and Weston transmission loss, normal modes, rays and the parabolic equation, seabed reflection, sound speed) and `bioacoustics` (marine-mammal audiograms and regulatory auditory weighting), over the ISO 18405 quantities and the sonar equation at the root | | `phonometry.electroacoustics` | Distortion (IEC 60268-3 / AES17), transfer function and coherence, radiating piston | | `phonometry.noise_control` | Reactive silencers (four-pole method), HVAC duct attenuation, machine-enclosure insertion loss | | `phonometry.broadcast` | Programme loudness and true peak (ITU-R BS.1770-5, EBU R 128 with Tech 3341/3342) | @@ -60,6 +60,7 @@ warns and delegates as well. | `phonometry.materials.porous_absorber` | `phonometry.materials.absorbers.porous` | 5.0 | | `phonometry.environmental` | `phonometry.environment` | 5.0 | | `phonometry.psychoacoustics.loudness_zwicker` | `phonometry.psychoacoustics.loudness.zwicker` | 5.0 | +| `phonometry.underwater.ocean_ambient_noise` | `phonometry.underwater.sources.ambient_noise` | 5.0 | | Name | Type | Description (Inputs) | Usage Snippet (Outputs) | | :--- | :--- | :--- | :--- | diff --git a/docs/atmospheric-refraction.md b/docs/atmospheric-refraction.md index 9bd79690e..903b85562 100644 --- a/docs/atmospheric-refraction.md +++ b/docs/atmospheric-refraction.md @@ -9,7 +9,7 @@ and wind change with height, and this **refracts** sound: rays curve, and over a few hundred metres the received level can swing by tens of decibels. This page covers `phonometry.environment.propagation.refraction`, the refracting-atmosphere counterpart of the ocean solvers in -[`phonometry.underwater.numerical_propagation`](underwater-solvers.md): a +[`phonometry.underwater.propagation.numerical`](underwater-solvers.md): a **ray model** and a **parabolic-equation (PE)** solver, both clean-room from Salomons, *Computational Atmospheric Acoustics* (2001) and Attenborough & Van Renterghem, *Predicting Outdoor Sound* 2e (2021, Ch. 11). diff --git a/docs/underwater-solvers.md b/docs/underwater-solvers.md index 955956d73..6bd84688d 100644 --- a/docs/underwater-solvers.md +++ b/docs/underwater-solvers.md @@ -345,7 +345,7 @@ compute the field. Green's-function PE marched over ground impedance instead of a seabed. - [2D FDTD wave simulation](fdtd-simulation.md): the time-domain alternative behind the SOFAR ducting animation of the propagation guide. -- API reference: [`underwater.numerical_propagation`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical-propagation/). +- API reference: [`underwater.propagation.numerical`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical/). ## References diff --git a/llms-full.txt b/llms-full.txt index 4fde8edb6..504321b0b 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -376,17 +376,17 @@ The generated API reference, one page per module. Fetch these only when a specif - [speech/sii](https://jmrplens.github.io/phonometry/reference/api/speech/sii/) - [speech/sti](https://jmrplens.github.io/phonometry/reference/api/speech/sti/) - [underwater/acoustics](https://jmrplens.github.io/phonometry/reference/api/underwater/acoustics/) -- [underwater/marine-mammal-audiograms](https://jmrplens.github.io/phonometry/reference/api/underwater/marine-mammal-audiograms/) -- [underwater/marine-mammal-weighting](https://jmrplens.github.io/phonometry/reference/api/underwater/marine-mammal-weighting/) -- [underwater/numerical-propagation](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical-propagation/) -- [underwater/ocean-ambient-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ocean-ambient-noise/) +- [underwater/ambient-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ambient-noise/) +- [underwater/audiograms](https://jmrplens.github.io/phonometry/reference/api/underwater/audiograms/) +- [underwater/closed-form](https://jmrplens.github.io/phonometry/reference/api/underwater/closed-form/) +- [underwater/numerical](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical/) - [underwater/pile-driving-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/pile-driving-noise/) -- [underwater/propagation](https://jmrplens.github.io/phonometry/reference/api/underwater/propagation/) - [underwater/seabed-reflection](https://jmrplens.github.io/phonometry/reference/api/underwater/seabed-reflection/) - [underwater/ship-radiated-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ship-radiated-noise/) - [underwater/ship-traffic-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ship-traffic-noise/) - [underwater/sonar-equation](https://jmrplens.github.io/phonometry/reference/api/underwater/sonar-equation/) - [underwater/sound-speed](https://jmrplens.github.io/phonometry/reference/api/underwater/sound-speed/) +- [underwater/weighting](https://jmrplens.github.io/phonometry/reference/api/underwater/weighting/) - [underwater/weston-regimes](https://jmrplens.github.io/phonometry/reference/api/underwater/weston-regimes/) - [vibration/diagnostics](https://jmrplens.github.io/phonometry/reference/api/vibration/diagnostics/) - [vibration/experimental-sea](https://jmrplens.github.io/phonometry/reference/api/vibration/experimental-sea/) @@ -2239,18 +2239,18 @@ contour = aircraft.noise_contour(path, powers, distances, sel, lmax, x=gx, y=gy) | :--- | :--- | | `phonometry.filters` | Octave and fractional-octave filter banks, frequency weightings and time weighting, parametric EQ, IEC 61260-1 and IEC 61672-1 class verification | | `phonometry.signals` | Levels (Leq, LAeq, percentiles), Welch and multitaper spectra, coherence, time-frequency, correlation, envelope, cepstrum, phase, synchronous averaging, test signals | -| `phonometry.metrology` | Calibration, GUM uncertainty and Monte Carlo, data qualification (stationarity, trends, peak statistics), IEC 61043 intensity class | +| `phonometry.metrology` | Calibration, GUM uncertainty and Monte Carlo, data qualification (stationarity, trends, peak statistics) | | `phonometry.psychoacoustics` | Two families: `loudness` (ISO 532-1 Zwicker, ISO 532-2 and ISO 532-3 Moore-Glasberg, ECMA-418-2, ISO 226 equal-loudness contours) and `quality` (sharpness, roughness, fluctuation strength, tonality, tone audibility, annoyance), plus the ERB scale both measure on | | `phonometry.speech` | Speech Transmission Index (IEC 60268-16), Speech Intelligibility Index (ANSI S3.5), STOI and ESTOI | | `phonometry.hearing` | Audiometric thresholds (ISO 7029/389-7), noise-induced hearing loss (ISO 1999), occupational exposure (ISO 9612) | -| `phonometry.emission` | Sound power (ISO 3740 family), sound intensity, vibration-based power | +| `phonometry.emission` | Sound power (ISO 3740 family), sound intensity and the IEC 61043 instrument class it is measured with, vibration-based power | | `phonometry.room` | Room acoustics (ISO 3382), impulse responses, open-plan, room-noise criteria, reverberation prediction, EN 12354-6 | | `phonometry.building` | Three subgroups: `measurement` (field, laboratory, survey and intensity methods with their ISO 717 ratings and ISO 12999 uncertainty), `prediction` (EN 12354 global and detailed models, facades, panels, apertures, plenums and resilient layers) and `regulation` (national codes) | | `phonometry.materials` | Four families by what the material does: `absorbers` (ISO 354, ISO 11654, ISO 12999-2, impedance tube ISO 10534-2, airflow resistance ISO 9053, porous and multilayer models, Biot, slow-sound metamaterials), `diffusers` (Schroeder design, metadiffusers, scattering and diffusion ISO 17497), `surfaces` (in-situ road absorption ISO 13472) and `resilient` (dynamic stiffness EN 29052-1) | | `phonometry.vibration` | Three families: `structural` (mobility ISO 7626, plate junctions, radiation, experimental SEA, transfer stiffness ISO 10846), `human` (ISO 2631/5349/8041 exposure and multiple shocks) and `machinery` (fault frequencies and condition monitoring) | | `phonometry.environment` | Three subgroups: `sources` (CNOSSOS road and rail emission, wind-turbine apparent sound power), `propagation` (ISO 9613-1/-2, ground effect and barriers, refraction by ray tracing and the parabolic equation) and `assessment` (ISO 1996-1/-2 rating and measurement, impulsive prominence, RD 1367/2007) | | `phonometry.aircraft` | EPNL (ICAO Annex 16), SAE ARP 5534 absorption, airport contours (ECAC Doc 29), rotorcraft (ECAC Doc 32) | -| `phonometry.underwater` | ISO 18405/17208/18406 levels, propagation and Weston regimes, sound speed, sonar equation and detection range, seabed, ambient and ship-traffic noise, marine-mammal audiograms and regulatory auditory weighting, numerical solvers | +| `phonometry.underwater` | Three families: `sources` (ISO 17208 ship radiated noise, traffic, pile driving, wind and thermal ambient noise), `propagation` (closed-form and Weston transmission loss, normal modes, rays and the parabolic equation, seabed reflection, sound speed) and `bioacoustics` (marine-mammal audiograms and regulatory auditory weighting), over the ISO 18405 quantities and the sonar equation at the root | | `phonometry.electroacoustics` | Distortion (IEC 60268-3 / AES17), transfer function and coherence, radiating piston | | `phonometry.noise_control` | Reactive silencers (four-pole method), HVAC duct attenuation, machine-enclosure insertion loss | | `phonometry.broadcast` | Programme loudness and true peak (ITU-R BS.1770-5, EBU R 128 with Tech 3341/3342) | @@ -2273,6 +2273,7 @@ warns and delegates as well. | `phonometry.materials.porous_absorber` | `phonometry.materials.absorbers.porous` | 5.0 | | `phonometry.environmental` | `phonometry.environment` | 5.0 | | `phonometry.psychoacoustics.loudness_zwicker` | `phonometry.psychoacoustics.loudness.zwicker` | 5.0 | +| `phonometry.underwater.ocean_ambient_noise` | `phonometry.underwater.sources.ambient_noise` | 5.0 | | Name | Type | Description (Inputs) | Usage Snippet (Outputs) | | :--- | :--- | :--- | :--- | @@ -3486,7 +3487,7 @@ and wind change with height, and this **refracts** sound: rays curve, and over a few hundred metres the received level can swing by tens of decibels. This page covers `phonometry.environment.propagation.refraction`, the refracting-atmosphere counterpart of the ocean solvers in -[`phonometry.underwater.numerical_propagation`](https://jmrplens.github.io/phonometry/guides/underwater-solvers/): a +[`phonometry.underwater.propagation.numerical`](https://jmrplens.github.io/phonometry/guides/underwater-solvers/): a **ray model** and a **parabolic-equation (PE)** solver, both clean-room from Salomons, *Computational Atmospheric Acoustics* (2001) and Attenborough & Van Renterghem, *Predicting Outdoor Sound* 2e (2021, Ch. 11). @@ -42318,7 +42319,7 @@ compute the field. Green's-function PE marched over ground impedance instead of a seabed. - [2D FDTD wave simulation](https://jmrplens.github.io/phonometry/guides/fdtd-simulation/): the time-domain alternative behind the SOFAR ducting animation of the propagation guide. -- API reference: [`underwater.numerical_propagation`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical-propagation/). +- API reference: [`underwater.propagation.numerical`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical/). ## References diff --git a/llms.txt b/llms.txt index cfc22b298..74015f344 100644 --- a/llms.txt +++ b/llms.txt @@ -376,17 +376,17 @@ The generated API reference, one page per module. Fetch these only when a specif - [speech/sii](https://jmrplens.github.io/phonometry/reference/api/speech/sii/) - [speech/sti](https://jmrplens.github.io/phonometry/reference/api/speech/sti/) - [underwater/acoustics](https://jmrplens.github.io/phonometry/reference/api/underwater/acoustics/) -- [underwater/marine-mammal-audiograms](https://jmrplens.github.io/phonometry/reference/api/underwater/marine-mammal-audiograms/) -- [underwater/marine-mammal-weighting](https://jmrplens.github.io/phonometry/reference/api/underwater/marine-mammal-weighting/) -- [underwater/numerical-propagation](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical-propagation/) -- [underwater/ocean-ambient-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ocean-ambient-noise/) +- [underwater/ambient-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ambient-noise/) +- [underwater/audiograms](https://jmrplens.github.io/phonometry/reference/api/underwater/audiograms/) +- [underwater/closed-form](https://jmrplens.github.io/phonometry/reference/api/underwater/closed-form/) +- [underwater/numerical](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical/) - [underwater/pile-driving-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/pile-driving-noise/) -- [underwater/propagation](https://jmrplens.github.io/phonometry/reference/api/underwater/propagation/) - [underwater/seabed-reflection](https://jmrplens.github.io/phonometry/reference/api/underwater/seabed-reflection/) - [underwater/ship-radiated-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ship-radiated-noise/) - [underwater/ship-traffic-noise](https://jmrplens.github.io/phonometry/reference/api/underwater/ship-traffic-noise/) - [underwater/sonar-equation](https://jmrplens.github.io/phonometry/reference/api/underwater/sonar-equation/) - [underwater/sound-speed](https://jmrplens.github.io/phonometry/reference/api/underwater/sound-speed/) +- [underwater/weighting](https://jmrplens.github.io/phonometry/reference/api/underwater/weighting/) - [underwater/weston-regimes](https://jmrplens.github.io/phonometry/reference/api/underwater/weston-regimes/) - [vibration/diagnostics](https://jmrplens.github.io/phonometry/reference/api/vibration/diagnostics/) - [vibration/experimental-sea](https://jmrplens.github.io/phonometry/reference/api/vibration/experimental-sea/) diff --git a/scripts/api_taxonomy.py b/scripts/api_taxonomy.py index a52b478c7..b8e246733 100644 --- a/scripts/api_taxonomy.py +++ b/scripts/api_taxonomy.py @@ -17,16 +17,12 @@ - every module appears in exactly one section; - each section only contains modules from the subpackages declared for it in - ``_SECTION_SUBPACKAGES``. Two sections deliberately span more than one - parent: ``filters`` adds the package top level (``phonometry`` itself), - and ``power`` includes - ``metrology.intensity_compliance`` (the IEC 61043 class checker sits with - the other instrument-conformance code but documents the intensity chain - the rest of the section measures with). + ``_SECTION_SUBPACKAGES``. One section deliberately spans more than one + parent: ``filters`` adds the package top level (``phonometry`` itself). Section keys are subpackage names wherever the taxonomy allows it, so a reader who knows where a function lives in the code can predict where its -page lives. The three sections listed above are the exceptions, and they are +page lives. The section listed above is the exception, and it is deliberate. The generator additionally checks the taxonomy against reality: every module @@ -248,18 +244,18 @@ class Section: label_es="Acústica submarina", modules=( "phonometry.underwater.acoustics", - "phonometry.underwater.propagation", - "phonometry.underwater.weston_regimes", - "phonometry.underwater.sound_speed", + "phonometry.underwater.propagation.closed_form", + "phonometry.underwater.propagation.weston_regimes", + "phonometry.underwater.propagation.sound_speed", "phonometry.underwater.sonar_equation", - "phonometry.underwater.ocean_ambient_noise", - "phonometry.underwater.seabed_reflection", - "phonometry.underwater.ship_radiated_noise", - "phonometry.underwater.ship_traffic_noise", - "phonometry.underwater.pile_driving_noise", - "phonometry.underwater.marine_mammal_audiograms", - "phonometry.underwater.marine_mammal_weighting", - "phonometry.underwater.numerical_propagation", + "phonometry.underwater.sources.ambient_noise", + "phonometry.underwater.propagation.seabed_reflection", + "phonometry.underwater.sources.ship_radiated_noise", + "phonometry.underwater.sources.ship_traffic_noise", + "phonometry.underwater.sources.pile_driving_noise", + "phonometry.underwater.bioacoustics.audiograms", + "phonometry.underwater.bioacoustics.weighting", + "phonometry.underwater.propagation.numerical", ), ), Section( @@ -271,7 +267,7 @@ class Section: "phonometry.emission.sound_power_intensity", "phonometry.emission.sound_power_reverberation", "phonometry.emission.intensity", - "phonometry.metrology.intensity_compliance", + "phonometry.emission.intensity_compliance", "phonometry.emission.vibration_sound_power", "phonometry.emission.declaration", ), @@ -341,7 +337,7 @@ class Section: "environment": ("environment",), "aeroacoustics": ("aircraft",), "underwater": ("underwater",), - "power": ("emission", "metrology"), + "power": ("emission",), "electroacoustics": ("electroacoustics",), "noise_control": ("noise_control",), "broadcast": ("broadcast",), diff --git a/scripts/conformance_report.py b/scripts/conformance_report.py index 2e91e737e..50f196efe 100644 --- a/scripts/conformance_report.py +++ b/scripts/conformance_report.py @@ -6471,7 +6471,7 @@ def _chk_uwp_del_grosso_printed_check() -> Outcome: # Oracle: the printed ITS-90 check table of the refit the module # implements (J. Acoust. Soc. Am. 97(3), 1995); the table lists pressure # in bars, Del Grosso's polynomial takes kg/cm² (1 bar = 1.019716 kg/cm²). - from phonometry.underwater.sound_speed import _del_grosso + from phonometry.underwater.propagation.sound_speed import _del_grosso got = float(_del_grosso(20.0, 35.0, 500.0 * 1.019716)) return numeric(1603.679, got, 1e-3, unit="m/s", places=3) @@ -6562,7 +6562,7 @@ def _chk_uwp_unesco_canonical() -> Outcome: # Published canonical check of the UNESCO algorithm; the module implements # the Wong-Zhu ITS-90 refit, so T90 = T68/1.00024 and the tolerance covers # the published refit residual. - from phonometry.underwater.sound_speed import _unesco + from phonometry.underwater.propagation.sound_speed import _unesco got = float(_unesco(40.0 / 1.00024, 40.0, 1000.0)) return numeric(1731.995, got, 0.02, unit="m/s", places=3) @@ -6577,7 +6577,7 @@ def _chk_uwp_medwin_derivative() -> Outcome: # Oracle: Ainslie prints "∂c/∂T ≈ 4.6 − 0.110·T", i.e. 3.5 m/s per °C at # 10 °C (printed p. 20). The cubic term sits inside the brackets the # published derivative excludes, so it is removed before comparing. - from phonometry.underwater.sound_speed import sea_water_sound_speed + from phonometry.underwater.propagation.sound_speed import sea_water_sound_speed h = 1e-5 grad = (sea_water_sound_speed(10.0 + h, 35.0, 0.0, model="medwin") diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py index e80447d1b..2c65159bb 100644 --- a/scripts/generate_api_docs.py +++ b/scripts/generate_api_docs.py @@ -801,7 +801,7 @@ def build_model() -> tuple[list[ModuleDoc], dict[str, str], list[str]]: ), "phonometry.underwater_acoustics": "phonometry.underwater.acoustics", "phonometry.underwater_propagation": "phonometry.underwater.propagation", - "phonometry.underwater_sound_speed": "phonometry.underwater.sound_speed", + "phonometry.underwater_sound_speed": "phonometry.underwater.propagation.sound_speed", } diff --git a/site/public/llms/llms-simulation.txt b/site/public/llms/llms-simulation.txt index 534a802c5..46ba1660b 100644 --- a/site/public/llms/llms-simulation.txt +++ b/site/public/llms/llms-simulation.txt @@ -16,7 +16,7 @@ and wind change with height, and this **refracts** sound: rays curve, and over a few hundred metres the received level can swing by tens of decibels. This page covers `phonometry.environment.propagation.refraction`, the refracting-atmosphere counterpart of the ocean solvers in -[`phonometry.underwater.numerical_propagation`](https://jmrplens.github.io/phonometry/guides/underwater-solvers/): a +[`phonometry.underwater.propagation.numerical`](https://jmrplens.github.io/phonometry/guides/underwater-solvers/): a **ray model** and a **parabolic-equation (PE)** solver, both clean-room from Salomons, *Computational Atmospheric Acoustics* (2001) and Attenborough & Van Renterghem, *Predicting Outdoor Sound* 2e (2021, Ch. 11). diff --git a/site/public/llms/llms-underwater.txt b/site/public/llms/llms-underwater.txt index c261aacd4..abefe8b0c 100644 --- a/site/public/llms/llms-underwater.txt +++ b/site/public/llms/llms-underwater.txt @@ -1216,7 +1216,7 @@ compute the field. Green's-function PE marched over ground impedance instead of a seabed. - [2D FDTD wave simulation](https://jmrplens.github.io/phonometry/guides/fdtd-simulation/): the time-domain alternative behind the SOFAR ducting animation of the propagation guide. -- API reference: [`underwater.numerical_propagation`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical-propagation/). +- API reference: [`underwater.propagation.numerical`](https://jmrplens.github.io/phonometry/reference/api/underwater/numerical/). ## References diff --git a/site/src/content/docs/es/guides/atmospheric-refraction.mdx b/site/src/content/docs/es/guides/atmospheric-refraction.mdx index 5aab81110..e7ec55483 100644 --- a/site/src/content/docs/es/guides/atmospheric-refraction.mdx +++ b/site/src/content/docs/es/guides/atmospheric-refraction.mdx @@ -30,7 +30,7 @@ con la altura, porque la temperatura y el viento cambian con la altura, y esto nivel recibido puede variar en decenas de decibelios. Esta página cubre `phonometry.environment.propagation.refraction`, el homólogo para atmósfera refractante de los solvers oceánicos de -[`phonometry.underwater.numerical_propagation`](/phonometry/es/guides/underwater-solvers/): +[`phonometry.underwater.propagation.numerical`](/phonometry/es/guides/underwater-solvers/): un **modelo de rayos** y un solver de **ecuación parabólica (PE)**. Que la refracción importe es, sobre todo, cuestión de distancia. Un gradiente diff --git a/site/src/content/docs/es/guides/marine-mammal-exposure.mdx b/site/src/content/docs/es/guides/marine-mammal-exposure.mdx index b5b7e537a..3e34008fc 100644 --- a/site/src/content/docs/es/guides/marine-mammal-exposure.mdx +++ b/site/src/content/docs/es/guides/marine-mammal-exposure.mdx @@ -320,4 +320,4 @@ estático. La propagación de la fuente al receptor pertenece a - [Propagación del sonido submarino](/phonometry/es/guides/underwater-propagation/): la pérdida por transmisión y la maquinaria de cifra de mérito que convierte un criterio en una distancia. -- Referencia de API: [`underwater.marine_mammal_weighting`](/phonometry/es/reference/api/underwater/marine-mammal-weighting/) y [`underwater.marine_mammal_audiograms`](/phonometry/es/reference/api/underwater/marine-mammal-audiograms/). +- Referencia de API: [`underwater.bioacoustics.weighting`](/phonometry/es/reference/api/underwater/weighting/) y [`underwater.bioacoustics.audiograms`](/phonometry/es/reference/api/underwater/audiograms/). diff --git a/site/src/content/docs/es/guides/underwater-acoustics.mdx b/site/src/content/docs/es/guides/underwater-acoustics.mdx index 379c69677..8f638fe77 100644 --- a/site/src/content/docs/es/guides/underwater-acoustics.mdx +++ b/site/src/content/docs/es/guides/underwater-acoustics.mdx @@ -259,5 +259,5 @@ ningún otro lugar de phonometry. ## Véase también -- Referencia de la API: [`underwater.acoustics`](/phonometry/es/reference/api/underwater/acoustics/), [`underwater.pile_driving_noise`](/phonometry/es/reference/api/underwater/pile-driving-noise/) y [`underwater.ship_radiated_noise`](/phonometry/es/reference/api/underwater/ship-radiated-noise/). +- Referencia de la API: [`underwater.acoustics`](/phonometry/es/reference/api/underwater/acoustics/), [`underwater.sources.pile_driving_noise`](/phonometry/es/reference/api/underwater/pile-driving-noise/) y [`underwater.sources.ship_radiated_noise`](/phonometry/es/reference/api/underwater/ship-radiated-noise/). - El modelado general de propagación submarina (rayos, modos normales, ecuación parabólica) se cubre en [Solvers numéricos de propagación submarina](/phonometry/es/guides/underwater-solvers/). diff --git a/site/src/content/docs/es/guides/underwater-propagation.mdx b/site/src/content/docs/es/guides/underwater-propagation.mdx index 7742db334..54f1aed2e 100644 --- a/site/src/content/docs/es/guides/underwater-propagation.mdx +++ b/site/src/content/docs/es/guides/underwater-propagation.mdx @@ -638,4 +638,4 @@ aportar un espectro de tráfico propio, por ejemplo con los solvers de modos normales, trazado de rayos y ecuación parabólica para los casos en que estas formas cerradas no bastan, y la guía de selección de modelo. -- Referencia de la API: [`underwater.propagation`](/phonometry/es/reference/api/underwater/propagation/) y [`underwater.sound_speed`](/phonometry/es/reference/api/underwater/sound-speed/). +- Referencia de la API: [`underwater.propagation.closed_form`](/phonometry/es/reference/api/underwater/closed-form/) y [`underwater.propagation.sound_speed`](/phonometry/es/reference/api/underwater/sound-speed/). diff --git a/site/src/content/docs/es/guides/underwater-solvers.mdx b/site/src/content/docs/es/guides/underwater-solvers.mdx index ffcef16b8..df91fef2c 100644 --- a/site/src/content/docs/es/guides/underwater-solvers.mdx +++ b/site/src/content/docs/es/guides/underwater-solvers.mdx @@ -395,7 +395,7 @@ física del lecho elástico que estos solvers fluidos dejan fuera, véase - [Simulación de ondas FDTD 2D](/phonometry/es/guides/fdtd-simulation/): la alternativa en el dominio del tiempo tras la animación del canal SOFAR de la guía de propagación. -- Referencia de la API: [`underwater.numerical_propagation`](/phonometry/es/reference/api/underwater/numerical-propagation/). +- Referencia de la API: [`underwater.propagation.numerical`](/phonometry/es/reference/api/underwater/numerical/). ## Respuestas rápidas diff --git a/site/src/content/docs/es/reference/errata.md b/site/src/content/docs/es/reference/errata.md index a7ec735de..793fdf0ae 100644 --- a/site/src/content/docs/es/reference/errata.md +++ b/site/src/content/docs/es/reference/errata.md @@ -1120,7 +1120,7 @@ which is the check that enforces the rule; see de las bandas de octava") carves out octave-only processors as a special case. Both are redundant if every class 2 processor is an octave-band one. - **Library behaviour:** implements the EN/IEC reading. - [`verify_intensity_class`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/metrology/intensity_compliance.py) + [`verify_intensity_class`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/emission/intensity_compliance.py) treats the full 22-band one-third-octave set as attesting either class, and the 7-band octave set (63 Hz to 4 kHz) as a class 2 alternative that never attests class 1, with both branches pinned by regression tests @@ -2102,7 +2102,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/weston_regimes.py) + [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2137,7 +2137,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/marine_mammal_weighting.py) + [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2206,7 +2206,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/marine_mammal_weighting.py), + in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/site/src/content/docs/guides/atmospheric-refraction.mdx b/site/src/content/docs/guides/atmospheric-refraction.mdx index 3b708ef81..c3f50328f 100644 --- a/site/src/content/docs/guides/atmospheric-refraction.mdx +++ b/site/src/content/docs/guides/atmospheric-refraction.mdx @@ -30,7 +30,7 @@ rays curve, and over a few hundred metres the received level can swing by tens of decibels. This page covers `phonometry.environment.propagation.refraction`, the refracting-atmosphere counterpart of the ocean solvers in -[`phonometry.underwater.numerical_propagation`](/phonometry/guides/underwater-solvers/): +[`phonometry.underwater.propagation.numerical`](/phonometry/guides/underwater-solvers/): a **ray model** and a **parabolic-equation (PE)** solver. Whether refraction matters is mostly a question of range. A representative diff --git a/site/src/content/docs/guides/marine-mammal-exposure.mdx b/site/src/content/docs/guides/marine-mammal-exposure.mdx index d75774581..b00f9112a 100644 --- a/site/src/content/docs/guides/marine-mammal-exposure.mdx +++ b/site/src/content/docs/guides/marine-mammal-exposure.mdx @@ -318,4 +318,4 @@ from source to receiver belongs to - [Underwater sound propagation](/phonometry/guides/underwater-propagation/): the transmission loss and figure-of-merit machinery that turns a criterion into a range. -- API reference: [`underwater.marine_mammal_weighting`](/phonometry/reference/api/underwater/marine-mammal-weighting/) and [`underwater.marine_mammal_audiograms`](/phonometry/reference/api/underwater/marine-mammal-audiograms/). +- API reference: [`underwater.bioacoustics.weighting`](/phonometry/reference/api/underwater/weighting/) and [`underwater.bioacoustics.audiograms`](/phonometry/reference/api/underwater/audiograms/). diff --git a/site/src/content/docs/guides/underwater-acoustics.mdx b/site/src/content/docs/guides/underwater-acoustics.mdx index 742458a87..873393ab0 100644 --- a/site/src/content/docs/guides/underwater-acoustics.mdx +++ b/site/src/content/docs/guides/underwater-acoustics.mdx @@ -250,5 +250,5 @@ phonometry. ## See also -- API reference: [`underwater.acoustics`](/phonometry/reference/api/underwater/acoustics/), [`underwater.pile_driving_noise`](/phonometry/reference/api/underwater/pile-driving-noise/) and [`underwater.ship_radiated_noise`](/phonometry/reference/api/underwater/ship-radiated-noise/). +- API reference: [`underwater.acoustics`](/phonometry/reference/api/underwater/acoustics/), [`underwater.sources.pile_driving_noise`](/phonometry/reference/api/underwater/pile-driving-noise/) and [`underwater.sources.ship_radiated_noise`](/phonometry/reference/api/underwater/ship-radiated-noise/). - General underwater propagation modelling (ray, normal mode, parabolic equation) is covered in [Underwater propagation solvers](/phonometry/guides/underwater-solvers/). diff --git a/site/src/content/docs/guides/underwater-propagation.mdx b/site/src/content/docs/guides/underwater-propagation.mdx index 54ac4b7b2..7e2aa25e0 100644 --- a/site/src/content/docs/guides/underwater-propagation.mdx +++ b/site/src/content/docs/guides/underwater-propagation.mdx @@ -631,4 +631,4 @@ model; supply a shipping spectrum yourself, for instance from - [Underwater propagation solvers](/phonometry/guides/underwater-solvers/): the normal-mode, ray-tracing and parabolic-equation solvers for the cases where these closed forms are not enough, and the model-selection guidance. -- API reference: [`underwater.propagation`](/phonometry/reference/api/underwater/propagation/) and [`underwater.sound_speed`](/phonometry/reference/api/underwater/sound-speed/). +- API reference: [`underwater.propagation.closed_form`](/phonometry/reference/api/underwater/closed-form/) and [`underwater.propagation.sound_speed`](/phonometry/reference/api/underwater/sound-speed/). diff --git a/site/src/content/docs/guides/underwater-solvers.mdx b/site/src/content/docs/guides/underwater-solvers.mdx index 43ea60395..9eb00dcfd 100644 --- a/site/src/content/docs/guides/underwater-solvers.mdx +++ b/site/src/content/docs/guides/underwater-solvers.mdx @@ -374,7 +374,7 @@ seabed physics these fluid solvers leave out, see - [2D FDTD wave simulation](/phonometry/guides/fdtd-simulation/): the time-domain alternative behind the SOFAR ducting animation of the propagation guide. -- API reference: [`underwater.numerical_propagation`](/phonometry/reference/api/underwater/numerical-propagation/). +- API reference: [`underwater.propagation.numerical`](/phonometry/reference/api/underwater/numerical/). ## Quick answers diff --git a/site/src/content/docs/reference/api/environment/refraction.md b/site/src/content/docs/reference/api/environment/refraction.md index c0fa9fb6a..ebd041092 100644 --- a/site/src/content/docs/reference/api/environment/refraction.md +++ b/site/src/content/docs/reference/api/environment/refraction.md @@ -15,7 +15,7 @@ predicts that refraction with two complementary models, clean-room from Salomons, *Computational Atmospheric Acoustics* (Springer, 2001) and Attenborough & Van Renterghem, *Predicting Outdoor Sound* (2e, CRC, 2021, Ch. 11), and it is the refracting-atmosphere counterpart of the range-independent -ocean solvers in [`phonometry.underwater.numerical_propagation`](/phonometry/reference/api/underwater/numerical-propagation/): +ocean solvers in [`phonometry.underwater.propagation.numerical`](/phonometry/reference/api/underwater/numerical/): * [`atmospheric_ray_paths`](/phonometry/reference/api/environment/refraction/#atmospheric_ray_paths) -- geometrical acoustics. Integrates Snell's law for sound rays (Salomons Eq. (4.3)) with a fixed-step Runge-Kutta scheme, @@ -151,7 +151,7 @@ slowness $\zeta = \sin(\gamma)/c$; with the range-invariant $\xi = \cos(\gamma_0)/c(z_s)$ the equations are $dz/dr = \zeta/\xi$ and $d\zeta/dr = -(dc/dz)/(c^3 \xi)$, the same ray core as the ocean -[`ray_trace`](/phonometry/reference/api/underwater/numerical-propagation/#ray_trace) (with a ground +[`ray_trace`](/phonometry/reference/api/underwater/numerical/#ray_trace) (with a ground reflection in place of the sea surface). The travel time accumulates $dt/dr = 1/(\xi c^2)$. diff --git a/site/src/content/docs/reference/api/index.md b/site/src/content/docs/reference/api/index.md index 3a014fcb7..d08df01ee 100644 --- a/site/src/content/docs/reference/api/index.md +++ b/site/src/content/docs/reference/api/index.md @@ -195,18 +195,18 @@ La referencia de la API se genera a partir de los docstrings del código (en ing | Module | Summary | | :--- | :--- | | [`underwater.acoustics`](/phonometry/reference/api/underwater/acoustics/) | Underwater-acoustics reference levels (ISO 18405:2017). | -| [`underwater.propagation`](/phonometry/reference/api/underwater/propagation/) | Underwater sound propagation: transmission loss (closed-form). | -| [`underwater.weston_regimes`](/phonometry/reference/api/underwater/weston-regimes/) | Weston's shallow-water propagation regimes (flux theory). | -| [`underwater.sound_speed`](/phonometry/reference/api/underwater/sound-speed/) | Speed of sound in sea water (empirical equations). | +| [`underwater.propagation.closed_form`](/phonometry/reference/api/underwater/closed-form/) | Underwater sound propagation: transmission loss (closed-form). | +| [`underwater.propagation.weston_regimes`](/phonometry/reference/api/underwater/weston-regimes/) | Weston's shallow-water propagation regimes (flux theory). | +| [`underwater.propagation.sound_speed`](/phonometry/reference/api/underwater/sound-speed/) | Speed of sound in sea water (empirical equations). | | [`underwater.sonar_equation`](/phonometry/reference/api/underwater/sonar-equation/) | The sonar equation (passive and active), in decibels. | -| [`underwater.ocean_ambient_noise`](/phonometry/reference/api/underwater/ocean-ambient-noise/) | Ocean ambient-noise spectrum levels (Wenz framework). | -| [`underwater.seabed_reflection`](/phonometry/reference/api/underwater/seabed-reflection/) | Plane-wave reflection at the seabed (fluid-fluid Rayleigh model). | -| [`underwater.ship_radiated_noise`](/phonometry/reference/api/underwater/ship-radiated-noise/) | Ship radiated noise and equivalent monopole source level (ISO 17208-1/-2). | -| [`underwater.ship_traffic_noise`](/phonometry/reference/api/underwater/ship-traffic-noise/) | Predicted source-level spectrum of shipping traffic (semi-empirical models). | -| [`underwater.pile_driving_noise`](/phonometry/reference/api/underwater/pile-driving-noise/) | Radiated underwater sound from percussive pile driving (ISO 18406:2017). | -| [`underwater.marine_mammal_audiograms`](/phonometry/reference/api/underwater/marine-mammal-audiograms/) | Marine-mammal hearing thresholds (group audiograms and the orca audiogram). | -| [`underwater.marine_mammal_weighting`](/phonometry/reference/api/underwater/marine-mammal-weighting/) | Regulatory auditory weighting and exposure criteria for marine mammals. | -| [`underwater.numerical_propagation`](/phonometry/reference/api/underwater/numerical-propagation/) | Numerical models of underwater sound propagation (range-independent ocean). | +| [`underwater.sources.ambient_noise`](/phonometry/reference/api/underwater/ambient-noise/) | Ocean ambient-noise spectrum levels (Wenz framework). | +| [`underwater.propagation.seabed_reflection`](/phonometry/reference/api/underwater/seabed-reflection/) | Plane-wave reflection at the seabed (fluid-fluid Rayleigh model). | +| [`underwater.sources.ship_radiated_noise`](/phonometry/reference/api/underwater/ship-radiated-noise/) | Ship radiated noise and equivalent monopole source level (ISO 17208-1/-2). | +| [`underwater.sources.ship_traffic_noise`](/phonometry/reference/api/underwater/ship-traffic-noise/) | Predicted source-level spectrum of shipping traffic (semi-empirical models). | +| [`underwater.sources.pile_driving_noise`](/phonometry/reference/api/underwater/pile-driving-noise/) | Radiated underwater sound from percussive pile driving (ISO 18406:2017). | +| [`underwater.bioacoustics.audiograms`](/phonometry/reference/api/underwater/audiograms/) | Marine-mammal hearing thresholds (group audiograms and the orca audiogram). | +| [`underwater.bioacoustics.weighting`](/phonometry/reference/api/underwater/weighting/) | Regulatory auditory weighting and exposure criteria for marine mammals. | +| [`underwater.propagation.numerical`](/phonometry/reference/api/underwater/numerical/) | Numerical models of underwater sound propagation (range-independent ocean). | ## Sound power and intensity @@ -216,7 +216,7 @@ La referencia de la API se genera a partir de los docstrings del código (en ing | [`emission.sound_power_intensity`](/phonometry/reference/api/power/sound-power-intensity/) | Sound power level of a noise source by sound-intensity **scanning**: ISO 9614-2:1996 (engineering, grade 2; survey/control, grade 3). | | [`emission.sound_power_reverberation`](/phonometry/reference/api/power/sound-power-reverberation/) | Sound power level of a noise source measured in a reverberation test room: ISO 3741:2010 (precision method, accuracy grade 1). | | [`emission.intensity`](/phonometry/reference/api/power/intensity/) | Two-microphone (p-p) sound intensity per IEC 61043:1993 and the ISO 9614-1:1993 field indicators. | -| [`metrology.intensity_compliance`](/phonometry/reference/api/power/intensity-compliance/) | IEC 61043:1993 sound-intensity instrument class verification. | +| [`emission.intensity_compliance`](/phonometry/reference/api/power/intensity-compliance/) | IEC 61043:1993 sound-intensity instrument class verification. | | [`emission.vibration_sound_power`](/phonometry/reference/api/power/vibration-sound-power/) | Airborne sound power from surface vibration (ISO/TS 7849-1/-2:2009). | | [`emission.declaration`](/phonometry/reference/api/power/declaration/) | ISO 4871:1996 declaration of noise emission values of machinery and equipment. | diff --git a/site/src/content/docs/reference/api/power/intensity-compliance.md b/site/src/content/docs/reference/api/power/intensity-compliance.md index 0d94b7629..42737513c 100644 --- a/site/src/content/docs/reference/api/power/intensity-compliance.md +++ b/site/src/content/docs/reference/api/power/intensity-compliance.md @@ -1,5 +1,5 @@ --- -title: "metrology.intensity_compliance" +title: "emission.intensity_compliance" description: "IEC 61043:1993 sound-intensity instrument class verification." sidebar: label: "intensity_compliance" @@ -239,7 +239,7 @@ IntensityInstrumentComplianceResult.plot( Plot the measured `delta_pI0` over the Table 2 class masks. -See `phonometry._plot.metrology.plot_intensity_class`. Requires +See `phonometry._plot.emission.plot_intensity_class`. Requires matplotlib (`pip install phonometry[plot]`) and returns the `Axes`. diff --git a/site/src/content/docs/reference/api/power/intensity.md b/site/src/content/docs/reference/api/power/intensity.md index bb269f30b..2ef3a726c 100644 --- a/site/src/content/docs/reference/api/power/intensity.md +++ b/site/src/content/docs/reference/api/power/intensity.md @@ -59,7 +59,7 @@ the instrument is adequate for a measurement when $L_d > F_2$ (criterion 1, Annex B equation (B.1)). The residual index $\delta_{pI0}$ that feeds it is classified against IEC 61043:1993 Table 2 by -[`phonometry.metrology.intensity_compliance.intensity_class_compliance`](/phonometry/reference/api/power/intensity-compliance/#intensity_class_compliance). +[`phonometry.emission.intensity_compliance.intensity_class_compliance`](/phonometry/reference/api/power/intensity-compliance/#intensity_class_compliance). > Auto-generated from the source docstrings by `scripts/generate_api_docs.py` (`make api-docs`). Do not edit by hand. diff --git a/site/src/content/docs/reference/api/underwater/ocean-ambient-noise.md b/site/src/content/docs/reference/api/underwater/ambient-noise.md similarity index 90% rename from site/src/content/docs/reference/api/underwater/ocean-ambient-noise.md rename to site/src/content/docs/reference/api/underwater/ambient-noise.md index a4a86f77a..c1b084fbd 100644 --- a/site/src/content/docs/reference/api/underwater/ocean-ambient-noise.md +++ b/site/src/content/docs/reference/api/underwater/ambient-noise.md @@ -1,8 +1,8 @@ --- -title: "underwater.ocean_ambient_noise" +title: "underwater.sources.ambient_noise" description: "Ocean ambient-noise spectrum levels (Wenz framework)." sidebar: - label: "ocean_ambient_noise" + label: "ambient_noise" --- Ocean ambient-noise spectrum levels (Wenz framework). @@ -10,17 +10,17 @@ Ocean ambient-noise spectrum levels (Wenz framework). Deep-water ambient-noise **spectrum levels** (dB re 1 µPa²/Hz) from the two physically grounded components of the Wenz curves: -* [`wind_noise_spectrum`](/phonometry/reference/api/underwater/ocean-ambient-noise/#wind_noise_spectrum) -- wind / sea-surface (Knudsen) noise via Wenz's +* [`wind_noise_spectrum`](/phonometry/reference/api/underwater/ambient-noise/#wind_noise_spectrum) -- wind / sea-surface (Knudsen) noise via Wenz's "rule of fives", $\mathrm{NL} = 51.02 - (5/3) \cdot 10 (\log_{10} f - \log_{10}(U/5))$ (`f` in kHz, `U` in knots; the historical 25 dB anchor is re 20 µPa and becomes $25 + 20 \log_{10}(20)$ re 1 µPa), valid over roughly 500 Hz-5 kHz. -* [`thermal_noise_spectrum`](/phonometry/reference/api/underwater/ocean-ambient-noise/#thermal_noise_spectrum) -- the molecular thermal-noise limit (Mellen +* [`thermal_noise_spectrum`](/phonometry/reference/api/underwater/ambient-noise/#thermal_noise_spectrum) -- the molecular thermal-noise limit (Mellen 1952), $\langle p^2(f) \rangle = 4 \pi k T \rho f^2 / c$ (Pa²/Hz), dominant above ~50 kHz. -[`ocean_ambient_noise`](/phonometry/reference/api/underwater/ocean-ambient-noise/#ocean_ambient_noise) energy-sums the enabled components (and an optional -caller-supplied shipping spectrum) into a composite [`AmbientNoiseResult`](/phonometry/reference/api/underwater/ocean-ambient-noise/#ambientnoiseresult) +[`ocean_ambient_noise`](/phonometry/reference/api/underwater/ambient-noise/#ocean_ambient_noise) energy-sums the enabled components (and an optional +caller-supplied shipping spectrum) into a composite [`AmbientNoiseResult`](/phonometry/reference/api/underwater/ambient-noise/#ambientnoiseresult) with a `.plot()` of the Wenz-style curves. The low-frequency turbulence band and a built-in distant-shipping model are out @@ -101,7 +101,7 @@ components, plus an optional caller-supplied shipping spectrum. | `density` | Water density, in kg/m³. | | `sound_speed` | Sound speed, in m/s. | -**Returns:** An [`AmbientNoiseResult`](/phonometry/reference/api/underwater/ocean-ambient-noise/#ambientnoiseresult). +**Returns:** An [`AmbientNoiseResult`](/phonometry/reference/api/underwater/ambient-noise/#ambientnoiseresult). **Raises** diff --git a/site/src/content/docs/reference/api/underwater/marine-mammal-audiograms.md b/site/src/content/docs/reference/api/underwater/audiograms.md similarity index 84% rename from site/src/content/docs/reference/api/underwater/marine-mammal-audiograms.md rename to site/src/content/docs/reference/api/underwater/audiograms.md index 67bd430f3..9ae82862d 100644 --- a/site/src/content/docs/reference/api/underwater/marine-mammal-audiograms.md +++ b/site/src/content/docs/reference/api/underwater/audiograms.md @@ -1,15 +1,15 @@ --- -title: "underwater.marine_mammal_audiograms" +title: "underwater.bioacoustics.audiograms" description: "Marine-mammal hearing thresholds (group audiograms and the orca audiogram)." sidebar: - label: "marine_mammal_audiograms" + label: "audiograms" --- Marine-mammal hearing thresholds (group audiograms and the orca audiogram). Two independent published descriptions of how well a marine mammal hears: -* [`group_audiogram`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#group_audiogram) -- the **group audiogram** of Southall et al. (2019), +* [`group_audiogram`](/phonometry/reference/api/underwater/audiograms/#group_audiogram) -- the **group audiogram** of Southall et al. (2019), a four-parameter band-pass fit (their Equation 1, after Finneran 2016) $$ @@ -18,7 +18,7 @@ Two independent published descriptions of how well a marine mammal hears: with the group parameters of their Table 2 (absolute thresholds) and Table 3 (normalised to 0 dB at best sensitivity). -* [`orca_audiogram`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#orca_audiogram) -- the killer-whale (*Orcinus orca*) audiogram of +* [`orca_audiogram`](/phonometry/reference/api/underwater/audiograms/#orca_audiogram) -- the killer-whale (*Orcinus orca*) audiogram of Wensveen & Van Roij (2007) as printed in Ainslie, *Principles of Sonar Performance Modelling* (Springer 2010), Equation (11.159), a **three-branch** power law over 0.5 to 80 kHz fitted to the measurements of Hall & Johnson @@ -34,14 +34,14 @@ $A = 20$ dB/decade, $B = 3.2$, $F_2 = 9.4$ kHz and $T_0 = 53.2$ dB (0.8 dB normalised) in prose but never prints $F_1$, only the criterion used to choose it. The group is therefore absent from -[`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogram_groups) rather than reconstructed by guesswork. +[`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/audiograms/#audiogram_groups) rather than reconstructed by guesswork. ::: Group codes follow Southall et al.: `HF` and `VHF` cetaceans, `SI` sirenians, `PCW`/`OCW` phocid and otariid carnivores in water and `PCA`/`OCA` the same in air. Beware that NMFS (2018) calls the Southall `HF` group `MF` and the Southall `VHF` group `HF`; see -[`phonometry.underwater.marine_mammal_weighting`](/phonometry/reference/api/underwater/marine-mammal-weighting/). +[`phonometry.underwater.bioacoustics.weighting`](/phonometry/reference/api/underwater/weighting/). > Auto-generated from the source docstrings by `scripts/generate_api_docs.py` (`make api-docs`). Do not edit by hand. @@ -69,10 +69,10 @@ Fit parameters of a published group audiogram. | Name | Description | | :--- | :--- | -| `group` | Hearing-group code, one of [`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogram_groups) (case-insensitive). | +| `group` | Hearing-group code, one of [`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/audiograms/#audiogram_groups) (case-insensitive). | | `normalized` | Return the Table 3 normalised fit instead of the Table 2 absolute one. | -**Returns:** The [`AudiogramParameters`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogramparameters) for that group. +**Returns:** The [`AudiogramParameters`](/phonometry/reference/api/underwater/audiograms/#audiogramparameters) for that group. **Raises** @@ -181,10 +181,10 @@ Table 3 (`normalized=True`). | Name | Description | | :--- | :--- | | `frequency_hz` | Frequency or frequencies, in Hz (strictly positive). | -| `group` | Hearing-group code, one of [`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogram_groups). | +| `group` | Hearing-group code, one of [`AUDIOGRAM_GROUPS`](/phonometry/reference/api/underwater/audiograms/#audiogram_groups). | | `normalized` | Use the normalised fit (0 dB at best sensitivity). | -**Returns:** An [`AudiogramResult`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogramresult). +**Returns:** An [`AudiogramResult`](/phonometry/reference/api/underwater/audiograms/#audiogramresult). **Raises** @@ -218,9 +218,9 @@ third branch**; evaluating the second one there returns 50.5 dB instead. | Name | Description | | :--- | :--- | -| `frequency_hz` | Frequency or frequencies, in Hz, within [`ORCA_AUDIOGRAM_RANGE_KHZ`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#orca_audiogram_range_khz) scaled to hertz. | +| `frequency_hz` | Frequency or frequencies, in Hz, within [`ORCA_AUDIOGRAM_RANGE_KHZ`](/phonometry/reference/api/underwater/audiograms/#orca_audiogram_range_khz) scaled to hertz. | -**Returns:** An [`AudiogramResult`](/phonometry/reference/api/underwater/marine-mammal-audiograms/#audiogramresult) in dB re 1 µPa. +**Returns:** An [`AudiogramResult`](/phonometry/reference/api/underwater/audiograms/#audiogramresult) in dB re 1 µPa. **Raises** diff --git a/site/src/content/docs/reference/api/underwater/propagation.md b/site/src/content/docs/reference/api/underwater/closed-form.md similarity index 89% rename from site/src/content/docs/reference/api/underwater/propagation.md rename to site/src/content/docs/reference/api/underwater/closed-form.md index cf8d74ac1..ddcc2efff 100644 --- a/site/src/content/docs/reference/api/underwater/propagation.md +++ b/site/src/content/docs/reference/api/underwater/closed-form.md @@ -1,8 +1,8 @@ --- -title: "underwater.propagation" +title: "underwater.propagation.closed_form" description: "Underwater sound propagation: transmission loss (closed-form)." sidebar: - label: "propagation" + label: "closed_form" --- Underwater sound propagation: transmission loss (closed-form). @@ -10,17 +10,17 @@ Underwater sound propagation: transmission loss (closed-form). Transmission loss `TL` (dB) is the sum of geometrical spreading and volume absorption: -* [`spreading_loss`](/phonometry/reference/api/underwater/propagation/#spreading_loss) -- geometrical spreading, $20 \log_{10} R$ +* [`spreading_loss`](/phonometry/reference/api/underwater/closed-form/#spreading_loss) -- geometrical spreading, $20 \log_{10} R$ (spherical), $10 \log_{10} R$ (cylindrical) or spherical-then-cylindrical (`"practical"`). -* [`seawater_absorption`](/phonometry/reference/api/underwater/propagation/#seawater_absorption) -- the volume absorption coefficient +* [`seawater_absorption`](/phonometry/reference/api/underwater/closed-form/#seawater_absorption) -- the volume absorption coefficient $\alpha$ in dB/km, from three coexisting formulations selectable through `model`: Francois & Garrison (1982, the default and reference), Ainslie & McColm (1998, a legible simplification of it) and Thorp (1967, a frequency-only form). -* [`transmission_loss`](/phonometry/reference/api/underwater/propagation/#transmission_loss) -- the total +* [`transmission_loss`](/phonometry/reference/api/underwater/closed-form/#transmission_loss) -- the total $\mathrm{TL} = \text{spreading} + \alpha R$ versus range, - returned as a [`TransmissionLossResult`](/phonometry/reference/api/underwater/propagation/#transmissionlossresult) with a `.plot()`. + returned as a [`TransmissionLossResult`](/phonometry/reference/api/underwater/closed-form/#transmissionlossresult) with a `.plot()`. Sources (clean-room, implemented from the published equations): Francois & Garrison, JASA 72 (1982) via Medwin & Clay; Ainslie & McColm, JASA 103 (1998); @@ -127,15 +127,15 @@ $\mathrm{TL} = \text{spreading} + \alpha R$ versus range. | :--- | :--- | | `range_m` | Range(s) from the source, in metres (scalar or array). | | `frequency_hz` | Acoustic frequency, in Hz. | -| `law` | Spreading law (see [`spreading_loss`](/phonometry/reference/api/underwater/propagation/#spreading_loss)). | +| `law` | Spreading law (see [`spreading_loss`](/phonometry/reference/api/underwater/closed-form/#spreading_loss)). | | `temperature` | Temperature `T`, in degrees Celsius. | | `salinity` | Salinity `S`, in parts per thousand. | | `depth` | Depth, in metres. | | `ph` | Acidity (default 8). | -| `model` | Absorption model (see [`seawater_absorption`](/phonometry/reference/api/underwater/propagation/#seawater_absorption)). | +| `model` | Absorption model (see [`seawater_absorption`](/phonometry/reference/api/underwater/closed-form/#seawater_absorption)). | | `transition_range` | Transition range for the `"practical"` law, in m. | -**Returns:** A [`TransmissionLossResult`](/phonometry/reference/api/underwater/propagation/#transmissionlossresult). +**Returns:** A [`TransmissionLossResult`](/phonometry/reference/api/underwater/closed-form/#transmissionlossresult). **Raises** diff --git a/site/src/content/docs/reference/api/underwater/numerical-propagation.md b/site/src/content/docs/reference/api/underwater/numerical.md similarity index 93% rename from site/src/content/docs/reference/api/underwater/numerical-propagation.md rename to site/src/content/docs/reference/api/underwater/numerical.md index 74866faf6..d28e4a80c 100644 --- a/site/src/content/docs/reference/api/underwater/numerical-propagation.md +++ b/site/src/content/docs/reference/api/underwater/numerical.md @@ -1,22 +1,22 @@ --- -title: "underwater.numerical_propagation" +title: "underwater.propagation.numerical" description: "Numerical models of underwater sound propagation (range-independent ocean)." sidebar: - label: "numerical_propagation" + label: "numerical" --- Numerical models of underwater sound propagation (range-independent ocean). Three complementary numerical solvers for the acoustic field in a horizontally-stratified ocean waveguide, complementing the closed-form -transmission loss of [`phonometry.underwater.propagation`](/phonometry/reference/api/underwater/propagation/): +transmission loss of `phonometry.underwater.propagation`: -* [`normal_modes`](/phonometry/reference/api/underwater/numerical-propagation/#normal_modes) -- the normal-mode expansion. Solves the depth-separated +* [`normal_modes`](/phonometry/reference/api/underwater/numerical/#normal_modes) -- the normal-mode expansion. Solves the depth-separated Sturm-Liouville eigenvalue problem by finite differences and assembles the transmission loss from the propagating modes. -* [`ray_trace`](/phonometry/reference/api/underwater/numerical-propagation/#ray_trace) -- ray tracing. Integrates the ray-trajectory equations +* [`ray_trace`](/phonometry/reference/api/underwater/numerical/#ray_trace) -- ray tracing. Integrates the ray-trajectory equations through a sound-speed profile (Runge-Kutta), returning the ray paths. -* [`parabolic_equation`](/phonometry/reference/api/underwater/numerical-propagation/#parabolic_equation) -- the standard (Tappert) parabolic equation, solved +* [`parabolic_equation`](/phonometry/reference/api/underwater/numerical/#parabolic_equation) -- the standard (Tappert) parabolic equation, solved with the split-step Fourier algorithm, returning the transmission-loss field. All three are implemented clean-room from Jensen, Kuperman, Porter & Schmidt, @@ -78,7 +78,7 @@ to resolve it). | `bottom` | `"pressure-release"` (default) or `"rigid"`. | | `n_depth_points` | Number of finite-difference depth points. Default (`None`): derived from the physics as $\max(400, \operatorname{ceil}(60 D f / c_{\mathrm{min}}))$, which keeps the near-cutoff eigenvalue error small at any frequency/depth combination, capped at 20 000 points (very high $f D$ products exceed the cap; the near-cutoff warning then indicates whether the capped grid suffices, and an explicit `n_depth_points` overrides the cap). | -**Returns:** A [`NormalModeResult`](/phonometry/reference/api/underwater/numerical-propagation/#normalmoderesult). +**Returns:** A [`NormalModeResult`](/phonometry/reference/api/underwater/numerical/#normalmoderesult). **Raises** @@ -173,7 +173,7 @@ calibration itself is exact to ~1e-4 dB at the default `range_step`. | `range_step` | Range marching step $\Delta r$, in metres. | | `n_depth_points` | Number of depth points (interior sine-transform grid). | -**Returns:** A [`ParabolicEquationResult`](/phonometry/reference/api/underwater/numerical-propagation/#parabolicequationresult). +**Returns:** A [`ParabolicEquationResult`](/phonometry/reference/api/underwater/numerical/#parabolicequationresult). **Raises** @@ -249,7 +249,7 @@ surface (`z = 0`) and the bottom (`z = water_depth`). | `max_range` | Maximum horizontal range to trace, in metres. | | `n_steps` | Number of integration steps per ray. | -**Returns:** A [`RayTraceResult`](/phonometry/reference/api/underwater/numerical-propagation/#raytraceresult). +**Returns:** A [`RayTraceResult`](/phonometry/reference/api/underwater/numerical/#raytraceresult). **Raises** diff --git a/site/src/content/docs/reference/api/underwater/pile-driving-noise.md b/site/src/content/docs/reference/api/underwater/pile-driving-noise.md index 0be2a9d27..6ebf5c4f3 100644 --- a/site/src/content/docs/reference/api/underwater/pile-driving-noise.md +++ b/site/src/content/docs/reference/api/underwater/pile-driving-noise.md @@ -1,5 +1,5 @@ --- -title: "underwater.pile_driving_noise" +title: "underwater.sources.pile_driving_noise" description: "Radiated underwater sound from percussive pile driving (ISO 18406:2017)." sidebar: label: "pile_driving_noise" @@ -21,7 +21,7 @@ hammer strike. ISO 18406 characterises them with: * [`strike_sel_spectrum`](/phonometry/reference/api/underwater/pile-driving-noise/#strike_sel_spectrum) -- the same single-strike SEL resolved into fractional-octave bands (ISO 18406 6.4.2.2), the input a marine-mammal assessment needs: feed it to - [`weighted_exposure`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighted_exposure) to + [`weighted_exposure`](/phonometry/reference/api/underwater/weighting/#weighted_exposure) to obtain the weighted cumulative SEL of a piling campaign and its margin against the regulatory injury and TTS criteria. @@ -198,7 +198,7 @@ falls outside `limits`. Bands narrower than the FFT bin spacing `fs/n` contain no bin and are reported as `-inf` dB (see [`StrikeSelSpectrum`](/phonometry/reference/api/underwater/pile-driving-noise/#strikeselspectrum)); the result can be handed straight to -[`weighted_exposure`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighted_exposure). +[`weighted_exposure`](/phonometry/reference/api/underwater/weighting/#weighted_exposure). **Parameters** @@ -237,7 +237,7 @@ Single-strike sound exposure level resolved into fractional-octave bands. | Name | Description | | :--- | :--- | | `frequencies` | Nominal band centre frequencies, in Hz. | -| `band_sel` | Per-band single-strike SEL, in dB re 1 µPa²·s. A band that contains no discrete-spectrum bin -- which happens whenever the band is narrower than the FFT bin spacing `fs/n`, i.e. in the lowest bands of a short record -- holds no energy at all and is reported as `-inf`, the level of zero exposure. That is the neutral element of an energy sum, so such bands pass straight through [`weighted_exposure`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighted_exposure) without contributing. | +| `band_sel` | Per-band single-strike SEL, in dB re 1 µPa²·s. A band that contains no discrete-spectrum bin -- which happens whenever the band is narrower than the FFT bin spacing `fs/n`, i.e. in the lowest bands of a short record -- holds no energy at all and is reported as `-inf`, the level of zero exposure. That is the neutral element of an energy sum, so such bands pass straight through [`weighted_exposure`](/phonometry/reference/api/underwater/weighting/#weighted_exposure) without contributing. | | `total_sel` | Energy sum of `band_sel` over the covered bands, in dB re 1 µPa²·s. | | `broadband_sel` | The broadband single-strike SEL of the whole record, in dB re 1 µPa²·s (equal to `total_sel` when the bands span the signal's whole occupied spectrum). | | `fraction` | Bandwidth fraction (1 for octaves, 3 for one-third octaves). | diff --git a/site/src/content/docs/reference/api/underwater/seabed-reflection.md b/site/src/content/docs/reference/api/underwater/seabed-reflection.md index c3aa3642d..a72adb74e 100644 --- a/site/src/content/docs/reference/api/underwater/seabed-reflection.md +++ b/site/src/content/docs/reference/api/underwater/seabed-reflection.md @@ -1,5 +1,5 @@ --- -title: "underwater.seabed_reflection" +title: "underwater.propagation.seabed_reflection" description: "Plane-wave reflection at the seabed (fluid-fluid Rayleigh model)." sidebar: label: "seabed_reflection" diff --git a/site/src/content/docs/reference/api/underwater/ship-radiated-noise.md b/site/src/content/docs/reference/api/underwater/ship-radiated-noise.md index 0322c0416..838855fa5 100644 --- a/site/src/content/docs/reference/api/underwater/ship-radiated-noise.md +++ b/site/src/content/docs/reference/api/underwater/ship-radiated-noise.md @@ -1,5 +1,5 @@ --- -title: "underwater.ship_radiated_noise" +title: "underwater.sources.ship_radiated_noise" description: "Ship radiated noise and equivalent monopole source level (ISO 17208-1/-2)." sidebar: label: "ship_radiated_noise" diff --git a/site/src/content/docs/reference/api/underwater/ship-traffic-noise.md b/site/src/content/docs/reference/api/underwater/ship-traffic-noise.md index c5a9b9c32..0548dc06e 100644 --- a/site/src/content/docs/reference/api/underwater/ship-traffic-noise.md +++ b/site/src/content/docs/reference/api/underwater/ship-traffic-noise.md @@ -1,5 +1,5 @@ --- -title: "underwater.ship_traffic_noise" +title: "underwater.sources.ship_traffic_noise" description: "Predicted source-level spectrum of shipping traffic (semi-empirical models)." sidebar: label: "ship_traffic_noise" @@ -23,8 +23,8 @@ implements three, selectable through `model`: All three return an equivalent-monopole source spectral-density level (dB re 1 µPa²/Hz at 1 m, source depth 6 m) and the decidecade-band source level (dB re 1 µPa m). The predicted spectrum can be used as the `shipping` input of -[`phonometry.underwater.ocean_ambient_noise.ocean_ambient_noise`](/phonometry/reference/api/underwater/ocean-ambient-noise/#ocean_ambient_noise) or placed at range -with [`phonometry.underwater.propagation.transmission_loss`](/phonometry/reference/api/underwater/propagation/#transmission_loss). +[`phonometry.underwater.sources.ambient_noise.ocean_ambient_noise`](/phonometry/reference/api/underwater/ambient-noise/#ocean_ambient_noise) or placed at range +with [`phonometry.underwater.propagation.transmission_loss`](/phonometry/reference/api/underwater/closed-form/#transmission_loss). Source (clean-room, implemented from the equations, validated against the authors' own Excel reference implementation, File S1): MacGillivray, A.; diff --git a/site/src/content/docs/reference/api/underwater/sonar-equation.md b/site/src/content/docs/reference/api/underwater/sonar-equation.md index 8844bb522..722b67269 100644 --- a/site/src/content/docs/reference/api/underwater/sonar-equation.md +++ b/site/src/content/docs/reference/api/underwater/sonar-equation.md @@ -30,7 +30,7 @@ a transmission-loss law at $\mathrm{TL} = \mathrm{FOM}$ gives the range at which the detection probability is 50 %: * [`detection_range`](/phonometry/reference/api/underwater/sonar-equation/#detection_range) inverts the closed-form loss of - [`phonometry.underwater.propagation`](/phonometry/reference/api/underwater/propagation/) (spreading plus volume absorption), + `phonometry.underwater.propagation` (spreading plus volume absorption), which is strictly increasing with range and therefore has a single crossing; * [`detection_range_from_curve`](/phonometry/reference/api/underwater/sonar-equation/#detection_range_from_curve) reads the crossing off any computed loss curve -- a normal-mode, parabolic-equation or Weston-regime prediction -- @@ -104,7 +104,7 @@ Range at which the closed-form transmission loss equals the figure of merit. Solves $\mathrm{TL}(r) = \mathrm{FOM}$ for the loss of -[`transmission_loss`](/phonometry/reference/api/underwater/propagation/#transmission_loss), which is +[`transmission_loss`](/phonometry/reference/api/underwater/closed-form/#transmission_loss), which is strictly increasing in range, so the root is unique. A **one-way** figure of merit works for both sonar modes: the active figure of merit returned by [`active_sonar_equation`](/phonometry/reference/api/underwater/sonar-equation/#active_sonar_equation) is already the maximum allowable one-way loss. @@ -115,13 +115,13 @@ merit works for both sonar modes: the active figure of merit returned by | :--- | :--- | | `figure_of_merit` | Maximum allowable one-way transmission loss, in dB. | | `frequency_hz` | Acoustic frequency, in Hz. | -| `law` | Spreading law (see [`spreading_loss`](/phonometry/reference/api/underwater/propagation/#spreading_loss)). | +| `law` | Spreading law (see [`spreading_loss`](/phonometry/reference/api/underwater/closed-form/#spreading_loss)). | | `transition_range` | Transition range for the `"practical"` law, in m. | | `temperature` | Temperature `T`, in degrees Celsius. | | `salinity` | Salinity `S`, in parts per thousand. | | `depth` | Depth, in metres. | | `ph` | Acidity (default 8). | -| `model` | Absorption model (see [`seawater_absorption`](/phonometry/reference/api/underwater/propagation/#seawater_absorption)). | +| `model` | Absorption model (see [`seawater_absorption`](/phonometry/reference/api/underwater/closed-form/#seawater_absorption)). | | `max_range` | Upper bound of the search, in metres. | | `n_points` | Number of ranges kept on the returned loss curve. | diff --git a/site/src/content/docs/reference/api/underwater/sound-speed.md b/site/src/content/docs/reference/api/underwater/sound-speed.md index 3dc44c966..8b63dd6ff 100644 --- a/site/src/content/docs/reference/api/underwater/sound-speed.md +++ b/site/src/content/docs/reference/api/underwater/sound-speed.md @@ -1,5 +1,5 @@ --- -title: "underwater.sound_speed" +title: "underwater.propagation.sound_speed" description: "Speed of sound in sea water (empirical equations)." sidebar: label: "sound_speed" diff --git a/site/src/content/docs/reference/api/underwater/marine-mammal-weighting.md b/site/src/content/docs/reference/api/underwater/weighting.md similarity index 92% rename from site/src/content/docs/reference/api/underwater/marine-mammal-weighting.md rename to site/src/content/docs/reference/api/underwater/weighting.md index 651358024..a6f0ea1dd 100644 --- a/site/src/content/docs/reference/api/underwater/marine-mammal-weighting.md +++ b/site/src/content/docs/reference/api/underwater/weighting.md @@ -1,8 +1,8 @@ --- -title: "underwater.marine_mammal_weighting" +title: "underwater.bioacoustics.weighting" description: "Regulatory auditory weighting and exposure criteria for marine mammals." sidebar: - label: "marine_mammal_weighting" + label: "weighting" --- Regulatory auditory weighting and exposure criteria for marine mammals. @@ -39,9 +39,9 @@ mid-frequency cetaceans `MF` and the porpoise-type group `HF`; NMFS 2024 and Southall call the same two `HF` and `VHF`. Each guidance version only accepts its own codes. -The module exposes the weighting itself ([`auditory_weighting`](/phonometry/reference/api/underwater/marine-mammal-weighting/#auditory_weighting)), the -published thresholds ([`exposure_criteria`](/phonometry/reference/api/underwater/marine-mammal-weighting/#exposure_criteria)) and the assessment chain -([`weighted_exposure`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighted_exposure)), which weights a band spectrum, accumulates it over +The module exposes the weighting itself ([`auditory_weighting`](/phonometry/reference/api/underwater/weighting/#auditory_weighting)), the +published thresholds ([`exposure_criteria`](/phonometry/reference/api/underwater/weighting/#exposure_criteria)) and the assessment chain +([`weighted_exposure`](/phonometry/reference/api/underwater/weighting/#weighted_exposure)), which weights a band spectrum, accumulates it over a number of events and reports the exceedance of each applicable criterion. Implemented clean-room from the three documents; validated against the worked @@ -83,7 +83,7 @@ Auditory weighting function `W(f)` of a marine-mammal hearing group. | `group` | Hearing-group code as used by `guidance`. | | `guidance` | `"nmfs-2024"` (default, current), `"nmfs-2018"` or `"southall-2019"`. | -**Returns:** An [`AuditoryWeightingResult`](/phonometry/reference/api/underwater/marine-mammal-weighting/#auditoryweightingresult). +**Returns:** An [`AuditoryWeightingResult`](/phonometry/reference/api/underwater/weighting/#auditoryweightingresult). **Raises** @@ -114,7 +114,7 @@ Auditory weighting and exposure functions of one hearing group. | `frequencies` | Frequencies, in Hz. | | `weighting` | Weighting-function amplitude `W(f)`, in dB ($\le 0$). | | `exposure_function` | Exposure function $E(f) = K + C - W(f)$, in dB (the frequency-dependent TTS-onset level). | -| `parameters` | The [`WeightingParameters`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weightingparameters) used. | +| `parameters` | The [`WeightingParameters`](/phonometry/reference/api/underwater/weighting/#weightingparameters) used. | | `guidance` | The guidance version. | | `group` | Hearing-group code. | | `weighted_tts_onset` | $T_w = K + C$, the minimum of the exposure function, in dB. | @@ -153,7 +153,7 @@ Published TTS and injury onset criteria of a hearing group. | `guidance` | `"nmfs-2024"` (default), `"nmfs-2018"` or `"southall-2019"`. | | `impulsive` | Return the impulsive-noise criteria (dual metric: a weighted SEL and an unweighted peak SPL) instead of the non-impulsive ones. | -**Returns:** An [`ExposureCriteria`](/phonometry/reference/api/underwater/marine-mammal-weighting/#exposurecriteria). +**Returns:** An [`ExposureCriteria`](/phonometry/reference/api/underwater/weighting/#exposurecriteria). **Raises** @@ -213,7 +213,7 @@ Hearing-group codes defined by a guidance version. | Name | Description | | :--- | :--- | -| `guidance` | One of [`WEIGHTING_GUIDANCE`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighting_guidance). | +| `guidance` | One of [`WEIGHTING_GUIDANCE`](/phonometry/reference/api/underwater/weighting/#weighting_guidance). | **Returns:** The group codes, in the order the source tabulates them. @@ -242,7 +242,7 @@ Weight a band spectrum, accumulate it and compare it with the criteria. The per-band single-event sound exposure levels are weighted with -[`auditory_weighting`](/phonometry/reference/api/underwater/marine-mammal-weighting/#auditory_weighting), summed on an energy basis and accumulated over +[`auditory_weighting`](/phonometry/reference/api/underwater/weighting/#auditory_weighting), summed on an energy basis and accumulated over `n_events` identical events ($+10 \log_{10} N$, the ISO 18406 Formula 9 identity used by [`cumulative_sel_identical`](/phonometry/reference/api/underwater/pile-driving-noise/#cumulative_sel_identical)). The result is compared with the group's TTS and injury onset criteria; the @@ -261,7 +261,7 @@ dual-metric rule requires. | `n_events` | Number of identical accumulated events, $\ge 1$. | | `peak_spl` | Unweighted zero-to-peak sound pressure level of the loudest single event, in dB; enables the peak-SPL half of the dual metric. | -**Returns:** A [`WeightedExposureResult`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weightedexposureresult). +**Returns:** A [`WeightedExposureResult`](/phonometry/reference/api/underwater/weighting/#weightedexposureresult). **Raises** @@ -309,7 +309,7 @@ Weighted exposure of a spectrum against a hearing group's criteria. | `cumulative_sel` | `weighted_sel` plus $10 \log_{10}(N)$ for the `n_events` accumulated events, in dB. | | `peak_spl` | The unweighted peak sound pressure level supplied, in dB (`None` when not given). | | `n_events` | Number of accumulated events (e.g. hammer strikes). | -| `criteria` | The [`ExposureCriteria`](/phonometry/reference/api/underwater/marine-mammal-weighting/#exposurecriteria) compared against. | +| `criteria` | The [`ExposureCriteria`](/phonometry/reference/api/underwater/weighting/#exposurecriteria) compared against. | | `sel_margin` | `cumulative_sel - injury_sel`, in dB (`None` when the criterion is not published); positive means the criterion is exceeded. | | `tts_margin` | `cumulative_sel - tts_sel`, in dB (or `None`). | | `peak_margin` | `peak_spl - injury_peak_spl`, in dB (or `None`). | @@ -357,9 +357,9 @@ Weighting/exposure parameters of one hearing group. | Name | Description | | :--- | :--- | | `group` | Hearing-group code as used by `guidance` (case-insensitive). | -| `guidance` | One of [`WEIGHTING_GUIDANCE`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weighting_guidance). | +| `guidance` | One of [`WEIGHTING_GUIDANCE`](/phonometry/reference/api/underwater/weighting/#weighting_guidance). | -**Returns:** The [`WeightingParameters`](/phonometry/reference/api/underwater/marine-mammal-weighting/#weightingparameters) row. +**Returns:** The [`WeightingParameters`](/phonometry/reference/api/underwater/weighting/#weightingparameters) row. **Raises** diff --git a/site/src/content/docs/reference/api/underwater/weston-regimes.md b/site/src/content/docs/reference/api/underwater/weston-regimes.md index b7f145ad1..179995d36 100644 --- a/site/src/content/docs/reference/api/underwater/weston-regimes.md +++ b/site/src/content/docs/reference/api/underwater/weston-regimes.md @@ -1,5 +1,5 @@ --- -title: "underwater.weston_regimes" +title: "underwater.propagation.weston_regimes" description: "Weston's shallow-water propagation regimes (flux theory)." sidebar: label: "weston_regimes" @@ -32,7 +32,7 @@ transmission loss for a point source in free water. The regime formulae are energy-flux (incoherent) results: they describe the range-averaged field, not its modal interference. That is exactly what makes -them a usable cross-check for [`phonometry.underwater.numerical_propagation`](/phonometry/reference/api/underwater/numerical-propagation/) +them a usable cross-check for [`phonometry.underwater.propagation.numerical`](/phonometry/reference/api/underwater/numerical/) -- the range average of a normal-mode or parabolic-equation field over many interference cycles converges on the cylindrical-spreading law, with $\psi_c = \pi/2$ for a totally reflecting (pressure-release) bottom. diff --git a/site/src/content/docs/reference/errata.md b/site/src/content/docs/reference/errata.md index 5ce854f6a..856d090d7 100644 --- a/site/src/content/docs/reference/errata.md +++ b/site/src/content/docs/reference/errata.md @@ -1111,7 +1111,7 @@ which is the check that enforces the rule; see de las bandas de octava") carves out octave-only processors as a special case. Both are redundant if every class 2 processor is an octave-band one. - **Library behaviour:** implements the EN/IEC reading. - [`verify_intensity_class`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/metrology/intensity_compliance.py) + [`verify_intensity_class`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/emission/intensity_compliance.py) treats the full 22-band one-third-octave set as attesting either class, and the 7-band octave set (63 Hz to 4 kHz) as a class 2 alternative that never attests class 1, with both branches pinned by regression tests @@ -2093,7 +2093,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/weston_regimes.py) + [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2128,7 +2128,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/marine_mammal_weighting.py) + [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2197,7 +2197,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/marine_mammal_weighting.py), + in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/site/src/generated/api-sidebar.mjs b/site/src/generated/api-sidebar.mjs index a4326a65c..45400b493 100644 --- a/site/src/generated/api-sidebar.mjs +++ b/site/src/generated/api-sidebar.mjs @@ -204,18 +204,18 @@ export const apiSidebar = { collapsed: true, items: [ 'reference/api/underwater/acoustics', - 'reference/api/underwater/propagation', + 'reference/api/underwater/closed-form', 'reference/api/underwater/weston-regimes', 'reference/api/underwater/sound-speed', 'reference/api/underwater/sonar-equation', - 'reference/api/underwater/ocean-ambient-noise', + 'reference/api/underwater/ambient-noise', 'reference/api/underwater/seabed-reflection', 'reference/api/underwater/ship-radiated-noise', 'reference/api/underwater/ship-traffic-noise', 'reference/api/underwater/pile-driving-noise', - 'reference/api/underwater/marine-mammal-audiograms', - 'reference/api/underwater/marine-mammal-weighting', - 'reference/api/underwater/numerical-propagation', + 'reference/api/underwater/audiograms', + 'reference/api/underwater/weighting', + 'reference/api/underwater/numerical', ], }, { diff --git a/src/phonometry/__init__.py b/src/phonometry/__init__.py index 01e21d7f3..c5228d221 100644 --- a/src/phonometry/__init__.py +++ b/src/phonometry/__init__.py @@ -455,6 +455,15 @@ sound_intensity, temporal_variability_indicator, ) +from .emission.intensity_compliance import ( + IntensityInstrumentComplianceResult, + instrument_class_from_components, + intensity_class_compliance, + phase_mismatch_from_residual_index, + residual_index_from_phase_mismatch, + residual_index_limits, + verify_intensity_class, +) from .emission.sound_power import ( MeteorologicalCorrection, PrecisionCriteria, @@ -959,15 +968,6 @@ stationarity_test, trend_test, ) -from .metrology.intensity_compliance import ( - IntensityInstrumentComplianceResult, - instrument_class_from_components, - intensity_class_compliance, - phase_mismatch_from_residual_index, - residual_index_from_phase_mismatch, - residual_index_limits, - verify_intensity_class, -) from .metrology.uncertainty import ( MonteCarloResult, Quantity, @@ -1319,7 +1319,7 @@ sound_pressure_level, underwater_to_in_air_spl, ) -from .underwater.marine_mammal_audiograms import ( +from .underwater.bioacoustics.audiograms import ( AUDIOGRAM_GROUPS, BEST_HEARING_FREQUENCY_KHZ, ORCA_AUDIOGRAM_RANGE_KHZ, @@ -1329,7 +1329,7 @@ group_audiogram, orca_audiogram, ) -from .underwater.marine_mammal_weighting import ( +from .underwater.bioacoustics.weighting import ( WEIGHTING_GUIDANCE, AuditoryWeightingResult, ExposureCriteria, @@ -1341,7 +1341,13 @@ weighted_exposure, weighting_parameters, ) -from .underwater.numerical_propagation import ( +from .underwater.propagation.closed_form import ( + TransmissionLossResult, + seawater_absorption, + spreading_loss, + transmission_loss, +) +from .underwater.propagation.numerical import ( NormalModeResult, ParabolicEquationResult, RayTraceResult, @@ -1349,28 +1355,7 @@ parabolic_equation, ray_trace, ) -from .underwater.ocean_ambient_noise import ( - AmbientNoiseResult, - ocean_ambient_noise, - thermal_noise_spectrum, - wind_noise_spectrum, -) -from .underwater.pile_driving_noise import ( - PileStrikeResult, - StrikeSelSpectrum, - cumulative_sel, - cumulative_sel_identical, - pile_strike_metrics, - single_strike_sel, - strike_sel_spectrum, -) -from .underwater.propagation import ( - TransmissionLossResult, - seawater_absorption, - spreading_loss, - transmission_loss, -) -from .underwater.seabed_reflection import ( +from .underwater.propagation.seabed_reflection import ( BottomLossResult, SeabedReflection, bottom_reflection_loss, @@ -1378,33 +1363,13 @@ reflection_coefficient, seabed_reflection, ) -from .underwater.ship_radiated_noise import ( - ShipSourceLevelResult, - hydrophone_depths, - monopole_source_level, - radiated_noise_level, - source_level_uncertainty, -) -from .underwater.ship_traffic_noise import ( - VESSEL_CLASSES, - ShipTrafficSpectrum, - ship_source_spectrum, -) -from .underwater.sonar_equation import ( - DetectionRangeResult, - SonarEquationResult, - active_sonar_equation, - detection_range, - detection_range_from_curve, - passive_sonar_equation, -) -from .underwater.sound_speed import ( +from .underwater.propagation.sound_speed import ( SoundSpeedProfile, depth_to_pressure, sea_water_sound_speed, sound_speed_profile, ) -from .underwater.weston_regimes import ( +from .underwater.propagation.weston_regimes import ( WESTON_REGIMES, WESTON_SEABEDS, WestonPropagationResult, @@ -1418,6 +1383,41 @@ weston_propagation_loss, weston_regime_boundaries, ) +from .underwater.sonar_equation import ( + DetectionRangeResult, + SonarEquationResult, + active_sonar_equation, + detection_range, + detection_range_from_curve, + passive_sonar_equation, +) +from .underwater.sources.ambient_noise import ( + AmbientNoiseResult, + ocean_ambient_noise, + thermal_noise_spectrum, + wind_noise_spectrum, +) +from .underwater.sources.pile_driving_noise import ( + PileStrikeResult, + StrikeSelSpectrum, + cumulative_sel, + cumulative_sel_identical, + pile_strike_metrics, + single_strike_sel, + strike_sel_spectrum, +) +from .underwater.sources.ship_radiated_noise import ( + ShipSourceLevelResult, + hydrophone_depths, + monopole_source_level, + radiated_noise_level, + source_level_uncertainty, +) +from .underwater.sources.ship_traffic_noise import ( + VESSEL_CLASSES, + ShipTrafficSpectrum, + ship_source_spectrum, +) from .vibration.human.exposure import ( HAV_EAV_A8, HAV_ELV_A8, diff --git a/src/phonometry/_compat.py b/src/phonometry/_compat.py index 37df8cb97..273bea756 100644 --- a/src/phonometry/_compat.py +++ b/src/phonometry/_compat.py @@ -140,16 +140,17 @@ "phonometry.aircraft_noise": "phonometry.aircraft.aircraft_noise", "phonometry.airport_noise": "phonometry.aircraft.airport_noise", "phonometry.rotorcraft_noise": "phonometry.aircraft.rotorcraft_noise", - "phonometry.numerical_propagation": "phonometry.underwater.numerical_propagation", - "phonometry.ocean_ambient_noise": "phonometry.underwater.ocean_ambient_noise", - "phonometry.pile_driving_noise": "phonometry.underwater.pile_driving_noise", - "phonometry.seabed_reflection": "phonometry.underwater.seabed_reflection", - "phonometry.ship_radiated_noise": "phonometry.underwater.ship_radiated_noise", - "phonometry.ship_traffic_noise": "phonometry.underwater.ship_traffic_noise", + "phonometry.numerical_propagation": "phonometry.underwater.propagation.numerical", + "phonometry.ocean_ambient_noise": "phonometry.underwater.sources.ambient_noise", + "phonometry.pile_driving_noise": "phonometry.underwater.sources.pile_driving_noise", + "phonometry.seabed_reflection": "phonometry.underwater.propagation.seabed_reflection", + "phonometry.ship_radiated_noise": "phonometry.underwater.sources.ship_radiated_noise", + "phonometry.ship_traffic_noise": "phonometry.underwater.sources.ship_traffic_noise", "phonometry.sonar_equation": "phonometry.underwater.sonar_equation", "phonometry.underwater_acoustics": "phonometry.underwater.acoustics", - "phonometry.underwater_propagation": "phonometry.underwater.propagation", - "phonometry.underwater_sound_speed": "phonometry.underwater.sound_speed", + "phonometry.underwater_propagation": + "phonometry.underwater.propagation.closed_form", + "phonometry.underwater_sound_speed": "phonometry.underwater.propagation.sound_speed", "phonometry.distortion": "phonometry.electroacoustics.distortion", "phonometry.frequency_response": "phonometry.electroacoustics.frequency_response", # @@ -191,6 +192,8 @@ "phonometry.metrology.signals": "phonometry.signals.test_signals", "phonometry.metrology.random_data": "phonometry.metrology.data_qualification", + "phonometry.metrology.intensity_compliance": + "phonometry.emission.intensity_compliance", "phonometry.hearing.sti": "phonometry.speech.sti", "phonometry.hearing.sii": "phonometry.speech.sii", "phonometry.hearing.objective_intelligibility": @@ -327,6 +330,30 @@ "phonometry.psychoacoustics.quality.tone_audibility", "phonometry.psychoacoustics.psychoacoustic_annoyance": "phonometry.psychoacoustics.quality.annoyance", + "phonometry.underwater.marine_mammal_audiograms": + "phonometry.underwater.bioacoustics.audiograms", + "phonometry.underwater.marine_mammal_weighting": + "phonometry.underwater.bioacoustics.weighting", + "phonometry.underwater.numerical_propagation": + "phonometry.underwater.propagation.numerical", + "phonometry.underwater.weston_regimes": + "phonometry.underwater.propagation.weston_regimes", + "phonometry.underwater.seabed_reflection": + "phonometry.underwater.propagation.seabed_reflection", + "phonometry.underwater.sound_speed": + "phonometry.underwater.propagation.sound_speed", + "phonometry.underwater.ship_radiated_noise": + "phonometry.underwater.sources.ship_radiated_noise", + "phonometry.underwater.ship_traffic_noise": + "phonometry.underwater.sources.ship_traffic_noise", + "phonometry.underwater.pile_driving_noise": + "phonometry.underwater.sources.pile_driving_noise", + "phonometry.underwater.ocean_ambient_noise": + "phonometry.underwater.sources.ambient_noise", + # ``underwater.propagation`` is not in this table: the name now belongs to + # the family package, which re-exports everything the module of that name + # exported. An alias would have to shadow a real package to warn, and + # shadowing it is exactly what must not happen. } #: The two generations, each with the release that deprecated it and the one diff --git a/src/phonometry/_plot/emission.py b/src/phonometry/_plot/emission.py index 922b90399..0bc790675 100644 --- a/src/phonometry/_plot/emission.py +++ b/src/phonometry/_plot/emission.py @@ -20,12 +20,17 @@ _new_axes, _plot_band_level_bars, _sound_power_designation, + format_frequency_axis, + theme_fill, ) if TYPE_CHECKING: from matplotlib.axes import Axes from ..emission.intensity import FieldIndicators, IntensityResult + from ..emission.intensity_compliance import ( + IntensityInstrumentComplianceResult, + ) from ..emission.sound_power import SoundPowerResult from ..emission.sound_power_intensity import SoundPowerIntensityResult from ..emission.sound_power_reverberation import ReverberationSoundPowerResult @@ -36,6 +41,12 @@ #: text. ``_t`` returns the English key unchanged for any language other #: than ``"es"``, so the English output is byte-for-byte identical to the #: pre-i18n renderers. +#: Shared frequency-axis label of the spectral renderers. +_FREQ_LABEL = "Frequency [Hz]" +#: Y-axis label of the residual-index plots (identical in both languages, +#: the symbol carries the meaning). +_LABEL_RESIDUAL_INDEX = r"$\delta_{pI0}$ [dB]" + _STRINGS: dict[str, str] = { "Band": "Banda", "Sound power level LW [dB]": "Nivel de potencia acústica LW [dB]", @@ -57,12 +68,25 @@ "Field non-uniformity F4": "No uniformidad del campo F4", "Dimensionless indicators F1, F4": "Indicadores adimensionales F1, F4", "ISO 9614-1 field indicators": "Indicadores de campo ISO 9614-1", + "Class {cls} pass region": "Región de aceptación clase {cls}", + "Class 1 minimum": "Mínimo clase 1", + "Class 2 minimum": "Mínimo clase 2", + r"Measured $\delta_{pI0}$": r"$\delta_{pI0}$ medido", + "Below the class {cls} minimum": "Bajo el mínimo de clase {cls}", + _LABEL_RESIDUAL_INDEX: _LABEL_RESIDUAL_INDEX, + "IEC 61043 Table 2 — {device}, {spacing} mm separation": + "Tabla 2 de IEC 61043 — {device}, separación de {spacing} mm", + "probe": "sonda", + "processor": "procesador", + "complete instrument": "instrumento completo", + "Frequency [Hz]": "Frecuencia [Hz]", } -def _t(text: str, language: str = "en") -> str: +def _t(text: str, language: str = "en", **fmt: Any) -> str: """Localise a fixed string; English is returned verbatim (byte-identical).""" - return _STRINGS.get(text, text) if language == "es" else text + s = _STRINGS.get(text, text) if language == "es" else text + return s.format(**fmt) if fmt else s def plot_sound_power( @@ -315,3 +339,104 @@ def plot_vibration_sound_power( ) localize_axes(ax, language) return ax + + +_DEVICE_LABELS = { + "probe": "probe", + "processor": "processor", + "instrument": "complete instrument", +} + + +def plot_intensity_class( + result: IntensityInstrumentComplianceResult, ax: Axes | None = None, *, + language: str = "en", **kwargs: Any +) -> Axes: + """Measured pressure-residual intensity index over the IEC 61043 masks. + + Draws the measured ``delta_pI0`` per one-third-octave band against the + Table 2 class 1 and class 2 *minima* for the device kind, already rescaled + to the microphone separation in use. Because the requirement is a floor, + the pass region of the reference class (the achieved class, or class 2 when + the chain complies with neither) lies *above* its mask and is shaded, + following the same convention as :func:`plot_filter_class`. + + The bands that cost the chain the *next* class up are ringed: for a class 2 + chain those are the bands under the class 1 minimum, and for a chain that + meets no class those are the bands under the class 2 minimum. A class 1 + chain clears everything, so nothing is ringed. + + :param result: An + :class:`~phonometry.emission.intensity_compliance.IntensityInstrumentComplianceResult`. + :param ax: Existing axes, or ``None`` to create a figure. + :param language: Label language, ``"en"`` (default) or ``"es"``. + :param kwargs: Forwarded to the measured-curve ``plot`` call. + :return: The axes. + """ + from .._i18n import localize_axes + + ax = ax if ax is not None else _new_axes() + freqs = np.asarray(result.frequency, dtype=np.float64) + measured = np.asarray(result.residual_index, dtype=np.float64) + class1 = np.asarray(result.limit_class1, dtype=np.float64) + class2 = np.asarray(result.limit_class2, dtype=np.float64) + cls = result.reference_class() + mask = class1 if cls == 1 else class2 + + y_bot = float(np.floor(min(measured.min(), class2.min()) - 2.0)) + y_top = float(np.ceil(max(measured.max(), class1.max()) + 3.0)) + + # Opaque, because the fiche renders this plot through svglib, which drops + # alpha: a translucent fill would come out as a solid block over the + # measured curve. theme_fill mixes the page towards the hue instead, so the + # region reads the same way on either background. + ax.fill_between( + freqs, mask, y_top, step="mid", facecolor=theme_fill(_C_TERTIARY, ax), + edgecolor="none", zorder=0, + label=_t("Class {cls} pass region", language, cls=cls), + ) + # Both Table 2 masks in the same amber, class 1 solid and class 2 dashed, + # as the published intensity-analyser displays draw them. + ax.plot(freqs, class1, drawstyle="steps-mid", color=_C_SECONDARY, lw=1.3, + label=_t("Class 1 minimum", language)) + ax.plot(freqs, class2, drawstyle="steps-mid", color=_C_SECONDARY, lw=1.3, + ls="--", label=_t("Class 2 minimum", language)) + + kwargs.setdefault("color", _C_PRIMARY) + kwargs.setdefault("lw", 1.6) + kwargs.setdefault("marker", "o") + kwargs.setdefault("ms", 3.0) + kwargs.setdefault("drawstyle", "steps-mid") + kwargs.setdefault("label", _t(r"Measured $\delta_{pI0}$", language)) + ax.plot(freqs, measured, **kwargs) + + # Ring the bands that block the next class up: class 1 for a class 2 chain, + # class 2 for a chain that meets neither. A class 1 chain has none. + marked_cls = 1 if result.overall_class == 2 else 2 + marked_mask = class1 if marked_cls == 1 else class2 + failing = ( + np.zeros(freqs.shape, dtype=bool) + if result.overall_class == 1 + else measured < marked_mask - 1e-9 + ) + if np.any(failing): + ax.plot( + freqs[failing], measured[failing], ls="", marker="o", ms=6.0, + mfc="none", mew=1.6, color=_C_REFERENCE, + label=_t("Below the class {cls} minimum", language, cls=marked_cls), + ) + + format_frequency_axis(ax, float(freqs.min()), float(freqs.max())) + ax.set_xlim(float(freqs.min()) / 1.15, float(freqs.max()) * 1.15) + ax.set_ylim(y_bot, y_top) + ax.set_xlabel(_t(_FREQ_LABEL, language)) + ax.set_ylabel(_t(_LABEL_RESIDUAL_INDEX, language)) + ax.set_title( + _t("IEC 61043 Table 2 — {device}, {spacing} mm separation", language, + device=_t(_DEVICE_LABELS[result.device], language), + spacing=f"{result.spacing * 1000.0:g}") + ) + ax.legend(loc="lower right", fontsize="small") + ax.grid(True, which="both", alpha=0.3) + localize_axes(ax, language) + return ax diff --git a/src/phonometry/_plot/metrology.py b/src/phonometry/_plot/metrology.py index 14756d923..c15dbf5c7 100644 --- a/src/phonometry/_plot/metrology.py +++ b/src/phonometry/_plot/metrology.py @@ -16,9 +16,6 @@ StationarityTestResult, TrendTestResult, ) - from ..metrology.intensity_compliance import ( - IntensityInstrumentComplianceResult, - ) from ..metrology.uncertainty import MonteCarloResult, UncertaintyResult from .common import ( @@ -26,19 +23,12 @@ _C_PRIMARY, _C_PRIMARY_LIGHT, _C_REFERENCE, - _C_SECONDARY, - _C_TERTIARY, _LEGEND_UPPER_RIGHT, _new_axes, - format_frequency_axis, - theme_fill, ) #: Shared frequency-axis label of the spectral renderers. _FREQ_LABEL = "Frequency [Hz]" -#: Y-axis label of the residual-index plots (identical in both languages, -#: the symbol carries the meaning). -_LABEL_RESIDUAL_INDEX = r"$\delta_{pI0}$ [dB]" #: Spanish translations of the fixed strings rendered by the metrology #: ``.plot()`` renderers, keyed by their verbatim English text. ``_t`` @@ -47,17 +37,6 @@ #: renderers. _STRINGS: dict[str, str] = { "Frequency [Hz]": "Frecuencia [Hz]", - "Class {cls} pass region": "Región de aceptación clase {cls}", - "Class 1 minimum": "Mínimo clase 1", - "Class 2 minimum": "Mínimo clase 2", - r"Measured $\delta_{pI0}$": r"$\delta_{pI0}$ medido", - "Below the class {cls} minimum": "Bajo el mínimo de clase {cls}", - _LABEL_RESIDUAL_INDEX: _LABEL_RESIDUAL_INDEX, - "IEC 61043 Table 2 — {device}, {spacing} mm separation": - "Tabla 2 de IEC 61043 — {device}, separación de {spacing} mm", - "probe": "sonda", - "processor": "procesador", - "complete instrument": "instrumento completo", r"Contribution to combined uncertainty $|c_i|\,u(x_i)$": r"Contribución a la incertidumbre combinada $|c_i|\,u(x_i)$", "GUM uncertainty budget — y = {value}": @@ -112,105 +91,6 @@ def _t(text: str, language: str = "en", **fmt: Any) -> str: return s.format(**fmt) if fmt else s -_DEVICE_LABELS = { - "probe": "probe", - "processor": "processor", - "instrument": "complete instrument", -} - - -def plot_intensity_class( - result: IntensityInstrumentComplianceResult, ax: Axes | None = None, *, - language: str = "en", **kwargs: Any -) -> Axes: - """Measured pressure-residual intensity index over the IEC 61043 masks. - - Draws the measured ``delta_pI0`` per one-third-octave band against the - Table 2 class 1 and class 2 *minima* for the device kind, already rescaled - to the microphone separation in use. Because the requirement is a floor, - the pass region of the reference class (the achieved class, or class 2 when - the chain complies with neither) lies *above* its mask and is shaded, - following the same convention as :func:`plot_filter_class`. - - The bands that cost the chain the *next* class up are ringed: for a class 2 - chain those are the bands under the class 1 minimum, and for a chain that - meets no class those are the bands under the class 2 minimum. A class 1 - chain clears everything, so nothing is ringed. - - :param result: An - :class:`~phonometry.metrology.intensity_compliance.IntensityInstrumentComplianceResult`. - :param ax: Existing axes, or ``None`` to create a figure. - :param language: Label language, ``"en"`` (default) or ``"es"``. - :param kwargs: Forwarded to the measured-curve ``plot`` call. - :return: The axes. - """ - from .._i18n import localize_axes - - ax = ax if ax is not None else _new_axes() - freqs = np.asarray(result.frequency, dtype=np.float64) - measured = np.asarray(result.residual_index, dtype=np.float64) - class1 = np.asarray(result.limit_class1, dtype=np.float64) - class2 = np.asarray(result.limit_class2, dtype=np.float64) - cls = result.reference_class() - mask = class1 if cls == 1 else class2 - - y_bot = float(np.floor(min(measured.min(), class2.min()) - 2.0)) - y_top = float(np.ceil(max(measured.max(), class1.max()) + 3.0)) - - # Opaque, because the fiche renders this plot through svglib, which drops - # alpha: a translucent fill would come out as a solid block over the - # measured curve. theme_fill mixes the page towards the hue instead, so the - # region reads the same way on either background. - ax.fill_between( - freqs, mask, y_top, step="mid", facecolor=theme_fill(_C_TERTIARY, ax), - edgecolor="none", zorder=0, - label=_t("Class {cls} pass region", language, cls=cls), - ) - # Both Table 2 masks in the same amber, class 1 solid and class 2 dashed, - # as the published intensity-analyser displays draw them. - ax.plot(freqs, class1, drawstyle="steps-mid", color=_C_SECONDARY, lw=1.3, - label=_t("Class 1 minimum", language)) - ax.plot(freqs, class2, drawstyle="steps-mid", color=_C_SECONDARY, lw=1.3, - ls="--", label=_t("Class 2 minimum", language)) - - kwargs.setdefault("color", _C_PRIMARY) - kwargs.setdefault("lw", 1.6) - kwargs.setdefault("marker", "o") - kwargs.setdefault("ms", 3.0) - kwargs.setdefault("drawstyle", "steps-mid") - kwargs.setdefault("label", _t(r"Measured $\delta_{pI0}$", language)) - ax.plot(freqs, measured, **kwargs) - - # Ring the bands that block the next class up: class 1 for a class 2 chain, - # class 2 for a chain that meets neither. A class 1 chain has none. - marked_cls = 1 if result.overall_class == 2 else 2 - marked_mask = class1 if marked_cls == 1 else class2 - failing = ( - np.zeros(freqs.shape, dtype=bool) - if result.overall_class == 1 - else measured < marked_mask - 1e-9 - ) - if np.any(failing): - ax.plot( - freqs[failing], measured[failing], ls="", marker="o", ms=6.0, - mfc="none", mew=1.6, color=_C_REFERENCE, - label=_t("Below the class {cls} minimum", language, cls=marked_cls), - ) - - format_frequency_axis(ax, float(freqs.min()), float(freqs.max())) - ax.set_xlim(float(freqs.min()) / 1.15, float(freqs.max()) * 1.15) - ax.set_ylim(y_bot, y_top) - ax.set_xlabel(_t(_FREQ_LABEL, language)) - ax.set_ylabel(_t(_LABEL_RESIDUAL_INDEX, language)) - ax.set_title( - _t("IEC 61043 Table 2 — {device}, {spacing} mm separation", language, - device=_t(_DEVICE_LABELS[result.device], language), - spacing=f"{result.spacing * 1000.0:g}") - ) - ax.legend(loc="lower right", fontsize="small") - ax.grid(True, which="both", alpha=0.3) - localize_axes(ax, language) - return ax def plot_uncertainty_budget( result: UncertaintyResult, ax: Axes | None = None, *, language: str = "en", **kwargs: Any diff --git a/src/phonometry/_plot/underwater.py b/src/phonometry/_plot/underwater.py index 659ed684b..bb5677b86 100644 --- a/src/phonometry/_plot/underwater.py +++ b/src/phonometry/_plot/underwater.py @@ -24,25 +24,31 @@ if TYPE_CHECKING: from matplotlib.axes import Axes - from ..underwater.marine_mammal_audiograms import AudiogramResult - from ..underwater.marine_mammal_weighting import ( + from ..underwater.bioacoustics.audiograms import AudiogramResult + from ..underwater.bioacoustics.weighting import ( AuditoryWeightingResult, WeightedExposureResult, ) - from ..underwater.numerical_propagation import ( + from ..underwater.propagation.closed_form import TransmissionLossResult + from ..underwater.propagation.numerical import ( NormalModeResult, ParabolicEquationResult, RayTraceResult, ) - from ..underwater.ocean_ambient_noise import AmbientNoiseResult - from ..underwater.pile_driving_noise import PileStrikeResult, StrikeSelSpectrum - from ..underwater.propagation import TransmissionLossResult - from ..underwater.seabed_reflection import BottomLossResult, SeabedReflection - from ..underwater.ship_radiated_noise import ShipSourceLevelResult - from ..underwater.ship_traffic_noise import ShipTrafficSpectrum + from ..underwater.propagation.seabed_reflection import ( + BottomLossResult, + SeabedReflection, + ) + from ..underwater.propagation.sound_speed import SoundSpeedProfile + from ..underwater.propagation.weston_regimes import WestonPropagationResult from ..underwater.sonar_equation import DetectionRangeResult, SonarEquationResult - from ..underwater.sound_speed import SoundSpeedProfile - from ..underwater.weston_regimes import WestonPropagationResult + from ..underwater.sources.ambient_noise import AmbientNoiseResult + from ..underwater.sources.pile_driving_noise import ( + PileStrikeResult, + StrikeSelSpectrum, + ) + from ..underwater.sources.ship_radiated_noise import ShipSourceLevelResult + from ..underwater.sources.ship_traffic_noise import ShipTrafficSpectrum #: Axis label and legend placement reused by several renderers in this module #: (kept as named constants so the literal appears once). @@ -142,7 +148,7 @@ def plot_ship_source_level( frequency, with the Lloyd's-mirror correction ``ΔL`` on a twin axis. :param result: A - :class:`~phonometry.underwater.ship_radiated_noise.ShipSourceLevelResult`. + :class:`~phonometry.underwater.sources.ship_radiated_noise.ShipSourceLevelResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the source-level ``semilogx`` call. @@ -193,7 +199,7 @@ def plot_pile_strike( the normalised cumulative energy with the 5 %/95 % pulse-duration bounds below. With ``ax`` given, only the waveform panel is drawn on it. - :param result: A :class:`~phonometry.underwater.pile_driving_noise.PileStrikeResult`. + :param result: A :class:`~phonometry.underwater.sources.pile_driving_noise.PileStrikeResult`. :param ax: Existing axes for the waveform panel, or ``None`` for a fresh two-panel figure. :param language: Label language, ``"en"`` (default) or ``"es"``. @@ -248,7 +254,7 @@ def plot_sound_speed_profile( ) -> Axes: """Sound-speed profile: speed vs depth, with depth increasing downward. - :param result: A :class:`~phonometry.underwater.sound_speed.SoundSpeedProfile`. + :param result: A :class:`~phonometry.underwater.propagation.sound_speed.SoundSpeedProfile`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the profile ``plot`` call. @@ -342,7 +348,7 @@ def plot_bottom_loss( ) -> Axes: """Bottom reflection loss versus grazing angle, marking the critical angle. - :param result: A :class:`~phonometry.underwater.seabed_reflection.BottomLossResult`. + :param result: A :class:`~phonometry.underwater.propagation.seabed_reflection.BottomLossResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the bottom-loss ``plot`` call. @@ -374,7 +380,7 @@ def plot_seabed_reflection( Draws ``|R|`` on a linear grazing-angle axis, marking the critical angle when the sediment is faster than the water. - :param result: A :class:`~phonometry.underwater.seabed_reflection.SeabedReflection`. + :param result: A :class:`~phonometry.underwater.propagation.seabed_reflection.SeabedReflection`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the magnitude ``plot`` call. @@ -404,7 +410,7 @@ def plot_ambient_noise( ) -> Axes: """Composite ambient-noise spectrum and its components versus frequency. - :param result: An :class:`~phonometry.underwater.ocean_ambient_noise.AmbientNoiseResult`. + :param result: An :class:`~phonometry.underwater.sources.ambient_noise.AmbientNoiseResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the composite-level ``plot`` call. @@ -438,7 +444,7 @@ def plot_ship_traffic_spectrum( ) -> Axes: """Predicted ship source spectral-density level versus frequency. - :param result: A :class:`~phonometry.underwater.ship_traffic_noise.ShipTrafficSpectrum`. + :param result: A :class:`~phonometry.underwater.sources.ship_traffic_noise.ShipTrafficSpectrum`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the source-PSD ``plot`` call. @@ -470,7 +476,7 @@ def plot_normal_modes( ) -> Axes: """Normal-mode transmission loss versus range (loss increasing downward). - :param result: A :class:`~phonometry.underwater.numerical_propagation.NormalModeResult`. + :param result: A :class:`~phonometry.underwater.propagation.numerical.NormalModeResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the transmission-loss ``plot`` call. @@ -497,7 +503,7 @@ def plot_ray_trace(result: RayTraceResult, ax: Axes | None = None, *, language: **kwargs: Any) -> Axes: """Ray paths through the water column (depth increasing downward). - :param result: A :class:`~phonometry.underwater.numerical_propagation.RayTraceResult`. + :param result: A :class:`~phonometry.underwater.propagation.numerical.RayTraceResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to each ray ``plot`` call. @@ -528,7 +534,7 @@ def plot_parabolic_equation( """Parabolic-equation transmission-loss field (range x depth). :param result: A - :class:`~phonometry.underwater.numerical_propagation.ParabolicEquationResult`. + :class:`~phonometry.underwater.propagation.numerical.ParabolicEquationResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to ``imshow``. @@ -600,7 +606,7 @@ def plot_weston_regimes( """Composite Weston propagation loss with each regime's law and boundaries. :param result: A - :class:`~phonometry.underwater.weston_regimes.WestonPropagationResult`. + :class:`~phonometry.underwater.propagation.weston_regimes.WestonPropagationResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the composite-loss ``plot`` call. @@ -652,7 +658,7 @@ def plot_marine_mammal_audiogram( """Hearing threshold versus frequency with the point of best sensitivity. :param result: An - :class:`~phonometry.underwater.marine_mammal_audiograms.AudiogramResult`. + :class:`~phonometry.underwater.bioacoustics.audiograms.AudiogramResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the threshold ``plot`` call. @@ -681,7 +687,7 @@ def plot_auditory_weighting( """Auditory weighting function of a marine-mammal hearing group. :param result: An - :class:`~phonometry.underwater.marine_mammal_weighting.AuditoryWeightingResult`. + :class:`~phonometry.underwater.bioacoustics.weighting.AuditoryWeightingResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the weighting ``plot`` call. @@ -708,7 +714,7 @@ def plot_weighted_exposure( """Unweighted and weighted band spectra against the exposure criteria. :param result: A - :class:`~phonometry.underwater.marine_mammal_weighting.WeightedExposureResult`. + :class:`~phonometry.underwater.bioacoustics.weighting.WeightedExposureResult`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the weighted-spectrum ``plot`` call. @@ -747,7 +753,7 @@ def plot_strike_sel_spectrum( """Per-band single-strike sound exposure level of a pile strike. :param result: A - :class:`~phonometry.underwater.pile_driving_noise.StrikeSelSpectrum`. + :class:`~phonometry.underwater.sources.pile_driving_noise.StrikeSelSpectrum`. :param ax: Existing axes, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the band-level ``plot`` call. diff --git a/src/phonometry/_report/iec61043.py b/src/phonometry/_report/iec61043.py index 315402a6e..098b5369b 100644 --- a/src/phonometry/_report/iec61043.py +++ b/src/phonometry/_report/iec61043.py @@ -2,7 +2,7 @@ """IEC 61043 residual-index class-verification fiche (reportlab renderer). Renders an -:class:`~phonometry.metrology.intensity_compliance.IntensityInstrumentComplianceResult` +:class:`~phonometry.emission.intensity_compliance.IntensityInstrumentComplianceResult` to a one-page PDF laid out like an accredited electroacoustic verification certificate. The section order is the one published accredited acoustic calibration certificates use: identification of the item calibrated, customer, @@ -70,7 +70,7 @@ class and the class that band meets) and the mask-overlay plot on the right, from .metadata import ReportMetadata if TYPE_CHECKING: - from ..metrology.intensity_compliance import ( + from ..emission.intensity_compliance import ( IntensityInstrumentComplianceResult, ) @@ -285,7 +285,7 @@ def render_iec61043_report( """Render an IEC 61043 class-verification fiche to a PDF at ``path``. :param result: An - :class:`~phonometry.metrology.intensity_compliance.IntensityInstrumentComplianceResult` + :class:`~phonometry.emission.intensity_compliance.IntensityInstrumentComplianceResult` carrying the per-band verdicts and the masks they were judged against. :param path: Destination path of the PDF file. :param metadata: Optional :class:`ReportMetadata`; ``None`` produces a bare diff --git a/src/phonometry/emission/__init__.py b/src/phonometry/emission/__init__.py index 138294cb6..5147134aa 100644 --- a/src/phonometry/emission/__init__.py +++ b/src/phonometry/emission/__init__.py @@ -21,6 +21,15 @@ sound_intensity, temporal_variability_indicator, ) +from .intensity_compliance import ( + IntensityInstrumentComplianceResult, + instrument_class_from_components, + intensity_class_compliance, + phase_mismatch_from_residual_index, + residual_index_from_phase_mismatch, + residual_index_limits, + verify_intensity_class, +) from .sound_power import ( MeteorologicalCorrection, PrecisionCriteria, @@ -62,11 +71,12 @@ ) __all__ = [ - "NORMALIZED_IMPEDANCE", +"NORMALIZED_IMPEDANCE", "REFERENCE_VELOCITY", "TEMPORAL_VARIABILITY_LIMIT", "DeclarationForm", "FieldIndicators", + "IntensityInstrumentComplianceResult", "IntensityResult", "MeteorologicalCorrection", "NoiseEmissionDeclaration", @@ -85,9 +95,12 @@ "environmental_correction", "extraneous_velocity_correction", "field_indicators", + "instrument_class_from_components", + "intensity_class_compliance", "mean_velocity_level", "measurement_positions", "meteorological_corrections", + "phase_mismatch_from_residual_index", "plot_microphone_positions", "plot_pp_probe_geometry", "precision_background_correction", @@ -97,6 +110,8 @@ "precision_uncertainty", "radiated_sound_power_level", "radiation_factor", + "residual_index_from_phase_mismatch", + "residual_index_limits", "sound_intensity", "sound_power_anechoic", "sound_power_comparison", @@ -108,4 +123,5 @@ "temporal_variability_indicator", "velocity_level", "velocity_level_from_acceleration", + "verify_intensity_class", ] diff --git a/src/phonometry/emission/intensity.py b/src/phonometry/emission/intensity.py index dada69102..5380cab2c 100644 --- a/src/phonometry/emission/intensity.py +++ b/src/phonometry/emission/intensity.py @@ -52,7 +52,7 @@ (criterion 1, Annex B equation (B.1)). The residual index :math:`\delta_{pI0}` that feeds it is classified against IEC 61043:1993 Table 2 by -:func:`phonometry.metrology.intensity_compliance.intensity_class_compliance`. +:func:`phonometry.emission.intensity_compliance.intensity_class_compliance`. """ from __future__ import annotations diff --git a/src/phonometry/metrology/intensity_compliance.py b/src/phonometry/emission/intensity_compliance.py similarity index 99% rename from src/phonometry/metrology/intensity_compliance.py rename to src/phonometry/emission/intensity_compliance.py index 6f10c6d40..6ca60a8fe 100644 --- a/src/phonometry/metrology/intensity_compliance.py +++ b/src/phonometry/emission/intensity_compliance.py @@ -472,14 +472,14 @@ def plot( ) -> Axes: """Plot the measured ``delta_pI0`` over the Table 2 class masks. - See :func:`phonometry._plot.metrology.plot_intensity_class`. Requires + See :func:`phonometry._plot.emission.plot_intensity_class`. Requires matplotlib (``pip install phonometry[plot]``) and returns the :class:`~matplotlib.axes.Axes`. :param language: Label language, ``"en"`` (default) or ``"es"``. """ from .._i18n import check_language - from .._plot.metrology import plot_intensity_class + from .._plot.emission import plot_intensity_class check_language(language) return plot_intensity_class(self, ax=ax, language=language, **kwargs) diff --git a/src/phonometry/environment/propagation/refraction.py b/src/phonometry/environment/propagation/refraction.py index 81538770e..7b289344d 100644 --- a/src/phonometry/environment/propagation/refraction.py +++ b/src/phonometry/environment/propagation/refraction.py @@ -10,7 +10,7 @@ Salomons, *Computational Atmospheric Acoustics* (Springer, 2001) and Attenborough & Van Renterghem, *Predicting Outdoor Sound* (2e, CRC, 2021, Ch. 11), and it is the refracting-atmosphere counterpart of the range-independent -ocean solvers in :mod:`phonometry.underwater.numerical_propagation`: +ocean solvers in :mod:`phonometry.underwater.propagation.numerical`: * :func:`atmospheric_ray_paths` -- geometrical acoustics. Integrates Snell's law for sound rays (Salomons Eq. (4.3)) with a fixed-step Runge-Kutta scheme, @@ -344,7 +344,7 @@ def atmospheric_ray_paths( :math:`\xi = \cos(\gamma_0)/c(z_s)` the equations are :math:`dz/dr = \zeta/\xi` and :math:`d\zeta/dr = -(dc/dz)/(c^3 \xi)`, the same ray core as the ocean - :func:`~phonometry.underwater.numerical_propagation.ray_trace` (with a ground + :func:`~phonometry.underwater.propagation.numerical.ray_trace` (with a ground reflection in place of the sea surface). The travel time accumulates :math:`dt/dr = 1/(\xi c^2)`. diff --git a/src/phonometry/metrology/__init__.py b/src/phonometry/metrology/__init__.py index 8b0bf1eb2..db316d01d 100644 --- a/src/phonometry/metrology/__init__.py +++ b/src/phonometry/metrology/__init__.py @@ -1,11 +1,12 @@ # Copyright (c) 2026. Jose Manuel Requena Plens """metrology domain of phonometry (see module docstrings). -Narrowed in 4.0 to the transverse metrology: calibration, GUM uncertainty, -data qualification and the IEC 61043 intensity-instrument class check. The -filter banks and weightings moved to :mod:`phonometry.filters` and the general -signal analysis to :mod:`phonometry.signals`; reading either from here still -works until 5.0. +Narrowed in 4.0 to the transverse metrology: calibration, GUM uncertainty and +data qualification. The filter banks and weightings moved to +:mod:`phonometry.filters`, the general signal analysis to +:mod:`phonometry.signals` and the IEC 61043 intensity-instrument class check +to :mod:`phonometry.emission.intensity_compliance`, which is what it verifies; +reading any of them from here still works until 5.0. """ from __future__ import annotations @@ -22,15 +23,6 @@ stationarity_test, trend_test, ) -from .intensity_compliance import ( - IntensityInstrumentComplianceResult, - instrument_class_from_components, - intensity_class_compliance, - phase_mismatch_from_residual_index, - residual_index_from_phase_mismatch, - residual_index_limits, - verify_intensity_class, -) from .uncertainty import ( MonteCarloResult, Quantity, @@ -44,12 +36,15 @@ ) #: Names that left this namespace in 4.0 keep resolving from here until 5.0. -_MOVED_TO = ("phonometry.filters", "phonometry.signals") +_MOVED_TO = ( + "phonometry.filters", + "phonometry.signals", + "phonometry.emission.intensity_compliance", +) __getattr__ = _namespace_shim(__name__, _MOVED_TO) __all__ = [ "CalibrationWarning", - "IntensityInstrumentComplianceResult", "LevelCrossingResult", "MonteCarloResult", "PeakStatisticsResult", @@ -60,21 +55,15 @@ "UncertaintyWarning", "calculate_sensitivity", "combine_uncertainty", - "instrument_class_from_components", - "intensity_class_compliance", "level_crossing_rate", "monte_carlo", "peak_statistics", - "phase_mismatch_from_residual_index", "rectangular", - "residual_index_from_phase_mismatch", - "residual_index_limits", "sensitivity", "stationarity_test", "trend_test", "triangular", "u_shaped", - "verify_intensity_class", ] #: ``__getattr__`` is invisible to ``dir()``; keep the moved names listed diff --git a/src/phonometry/underwater/__init__.py b/src/phonometry/underwater/__init__.py index 1d4a97e6f..ff823fc12 100644 --- a/src/phonometry/underwater/__init__.py +++ b/src/phonometry/underwater/__init__.py @@ -1,8 +1,18 @@ # Copyright (c) 2026. Jose Manuel Requena Plens -"""underwater domain of phonometry (see module docstrings).""" +"""underwater domain of phonometry (see module docstrings). + +Three families since 4.0, along the three questions an underwater problem +asks: :mod:`~phonometry.underwater.sources` for what makes the sound, +:mod:`~phonometry.underwater.propagation` for how it gets there, and +:mod:`~phonometry.underwater.bioacoustics` for who hears it. The ISO 18405 +quantities and the sonar equation stay at the root, because all three +families are written in their terms. Every public name is still exported +here, so ``from phonometry import underwater`` reads as it did. +""" from __future__ import annotations +from .._compat import _namespace_dir, _namespace_shim from .acoustics import ( UNDERWATER_REFERENCE_EXPOSURE, UNDERWATER_REFERENCE_PRESSURE, @@ -12,76 +22,59 @@ sound_pressure_level, underwater_to_in_air_spl, ) -from .marine_mammal_audiograms import ( +from .bioacoustics import ( AUDIOGRAM_GROUPS, BEST_HEARING_FREQUENCY_KHZ, ORCA_AUDIOGRAM_RANGE_KHZ, + WEIGHTING_GUIDANCE, AudiogramParameters, AudiogramResult, - audiogram_parameters, - group_audiogram, - orca_audiogram, -) -from .marine_mammal_weighting import ( - WEIGHTING_GUIDANCE, AuditoryWeightingResult, ExposureCriteria, WeightedExposureResult, WeightingParameters, + audiogram_parameters, auditory_weighting, exposure_criteria, + group_audiogram, hearing_groups, + orca_audiogram, weighted_exposure, weighting_parameters, ) -from .numerical_propagation import ( +from .propagation import ( + WESTON_REGIMES, + WESTON_SEABEDS, + BottomLossResult, NormalModeResult, ParabolicEquationResult, RayTraceResult, + SeabedReflection, + SoundSpeedProfile, + TransmissionLossResult, + WestonPropagationResult, + WestonRegimeBoundaries, + WestonSeabed, + bottom_reflection_loss, + critical_angle, + critical_grazing_angle, + depth_to_pressure, + effective_depth, + loss_parameter, normal_modes, parabolic_equation, ray_trace, -) -from .ocean_ambient_noise import ( - AmbientNoiseResult, - ocean_ambient_noise, - thermal_noise_spectrum, - wind_noise_spectrum, -) -from .pile_driving_noise import ( - PileStrikeResult, - StrikeSelSpectrum, - cumulative_sel, - cumulative_sel_identical, - pile_strike_metrics, - single_strike_sel, - strike_sel_spectrum, -) -from .propagation import ( - TransmissionLossResult, + reflection_coefficient, + reflection_loss_gradient, + sea_water_sound_speed, + seabed_reflection, seawater_absorption, + sound_speed_profile, spreading_loss, transmission_loss, -) -from .seabed_reflection import ( - BottomLossResult, - SeabedReflection, - bottom_reflection_loss, - critical_angle, - reflection_coefficient, - seabed_reflection, -) -from .ship_radiated_noise import ( - ShipSourceLevelResult, - hydrophone_depths, - monopole_source_level, - radiated_noise_level, - source_level_uncertainty, -) -from .ship_traffic_noise import ( - VESSEL_CLASSES, - ShipTrafficSpectrum, - ship_source_spectrum, + waveguide_cutoff_frequency, + weston_propagation_loss, + weston_regime_boundaries, ) from .sonar_equation import ( DetectionRangeResult, @@ -91,25 +84,26 @@ detection_range_from_curve, passive_sonar_equation, ) -from .sound_speed import ( - SoundSpeedProfile, - depth_to_pressure, - sea_water_sound_speed, - sound_speed_profile, -) -from .weston_regimes import ( - WESTON_REGIMES, - WESTON_SEABEDS, - WestonPropagationResult, - WestonRegimeBoundaries, - WestonSeabed, - critical_grazing_angle, - effective_depth, - loss_parameter, - reflection_loss_gradient, - waveguide_cutoff_frequency, - weston_propagation_loss, - weston_regime_boundaries, +from .sources import ( + VESSEL_CLASSES, + AmbientNoiseResult, + PileStrikeResult, + ShipSourceLevelResult, + ShipTrafficSpectrum, + StrikeSelSpectrum, + cumulative_sel, + cumulative_sel_identical, + hydrophone_depths, + monopole_source_level, + ocean_ambient_noise, + pile_strike_metrics, + radiated_noise_level, + ship_source_spectrum, + single_strike_sel, + source_level_uncertainty, + strike_sel_spectrum, + thermal_noise_spectrum, + wind_noise_spectrum, ) __all__ = [ @@ -196,3 +190,9 @@ "weston_regime_boundaries", "wind_noise_spectrum", ] + +#: No public name left this namespace in 4.0, but the modules did, so +#: ``underwater.seabed_reflection`` has to keep resolving to its alias module +#: until 5.0: the import registers it, the attribute read needs this. +__getattr__ = _namespace_shim(__name__) +__dir__ = _namespace_dir(__name__, __all__) diff --git a/src/phonometry/underwater/bioacoustics/__init__.py b/src/phonometry/underwater/bioacoustics/__init__.py new file mode 100644 index 000000000..908fd77bc --- /dev/null +++ b/src/phonometry/underwater/bioacoustics/__init__.py @@ -0,0 +1,52 @@ +# Copyright (c) 2026. Jose Manuel Requena Plens +"""underwater.bioacoustics subdomain of phonometry: who hears the sound. + +Marine mammal audiograms and the regulatory auditory weighting and exposure +criteria built on them. +""" + +from __future__ import annotations + +from .audiograms import ( + AUDIOGRAM_GROUPS, + BEST_HEARING_FREQUENCY_KHZ, + ORCA_AUDIOGRAM_RANGE_KHZ, + AudiogramParameters, + AudiogramResult, + audiogram_parameters, + group_audiogram, + orca_audiogram, +) +from .weighting import ( + WEIGHTING_GUIDANCE, + AuditoryWeightingResult, + ExposureCriteria, + WeightedExposureResult, + WeightingParameters, + auditory_weighting, + exposure_criteria, + hearing_groups, + weighted_exposure, + weighting_parameters, +) + +__all__ = [ + "AUDIOGRAM_GROUPS", + "BEST_HEARING_FREQUENCY_KHZ", + "ORCA_AUDIOGRAM_RANGE_KHZ", + "WEIGHTING_GUIDANCE", + "AudiogramParameters", + "AudiogramResult", + "AuditoryWeightingResult", + "ExposureCriteria", + "WeightedExposureResult", + "WeightingParameters", + "audiogram_parameters", + "auditory_weighting", + "exposure_criteria", + "group_audiogram", + "hearing_groups", + "orca_audiogram", + "weighted_exposure", + "weighting_parameters", +] diff --git a/src/phonometry/underwater/marine_mammal_audiograms.py b/src/phonometry/underwater/bioacoustics/audiograms.py similarity index 98% rename from src/phonometry/underwater/marine_mammal_audiograms.py rename to src/phonometry/underwater/bioacoustics/audiograms.py index 7777cb659..b25223003 100644 --- a/src/phonometry/underwater/marine_mammal_audiograms.py +++ b/src/phonometry/underwater/bioacoustics/audiograms.py @@ -34,7 +34,7 @@ sirenians, ``PCW``/``OCW`` phocid and otariid carnivores in water and ``PCA``/``OCA`` the same in air. Beware that NMFS (2018) calls the Southall ``HF`` group ``MF`` and the Southall ``VHF`` group ``HF``; see -:mod:`phonometry.underwater.marine_mammal_weighting`. +:mod:`phonometry.underwater.bioacoustics.weighting`. """ from __future__ import annotations @@ -166,8 +166,8 @@ class AudiogramResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the hearing threshold versus frequency.""" - from .._i18n import check_language - from .._plot.underwater import plot_marine_mammal_audiogram + from ..._i18n import check_language + from ..._plot.underwater import plot_marine_mammal_audiogram return plot_marine_mammal_audiogram(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/marine_mammal_weighting.py b/src/phonometry/underwater/bioacoustics/weighting.py similarity index 98% rename from src/phonometry/underwater/marine_mammal_weighting.py rename to src/phonometry/underwater/bioacoustics/weighting.py index 1090d0771..227082a41 100644 --- a/src/phonometry/underwater/marine_mammal_weighting.py +++ b/src/phonometry/underwater/bioacoustics/weighting.py @@ -369,8 +369,8 @@ class AuditoryWeightingResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the weighting function versus frequency.""" - from .._i18n import check_language - from .._plot.underwater import plot_auditory_weighting + from ..._i18n import check_language + from ..._plot.underwater import plot_auditory_weighting return plot_auditory_weighting(self, ax=ax, language=check_language(language), **kwargs) @@ -504,8 +504,8 @@ class WeightedExposureResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the unweighted and weighted band spectra with the criteria.""" - from .._i18n import check_language - from .._plot.underwater import plot_weighted_exposure + from ..._i18n import check_language + from ..._plot.underwater import plot_weighted_exposure return plot_weighted_exposure(self, ax=ax, language=check_language(language), **kwargs) @@ -543,7 +543,7 @@ def weighted_exposure( :param band_sel: Per-band single-event SEL, in dB re 1 µPa²·s (or dB re (20 µPa)²·s for an in-air group); same length. ``-inf`` is accepted for a band that carries no energy, which is what - :func:`~phonometry.underwater.pile_driving_noise.strike_sel_spectrum` + :func:`~phonometry.underwater.sources.pile_driving_noise.strike_sel_spectrum` returns for bands narrower than its FFT bin spacing; such a band adds nothing to the energy sum. Both input arrays are copied, so the result never aliases the caller's data. diff --git a/src/phonometry/underwater/propagation/__init__.py b/src/phonometry/underwater/propagation/__init__.py new file mode 100644 index 000000000..8b261b500 --- /dev/null +++ b/src/phonometry/underwater/propagation/__init__.py @@ -0,0 +1,87 @@ +# Copyright (c) 2026. Jose Manuel Requena Plens +"""underwater.propagation subdomain of phonometry: how the sound gets there. + +The closed-form transmission loss of ISO 18405 and Weston's regimes, the +numerical solvers (normal modes, rays, parabolic equation), the seabed +reflection they bounce off and the sound speed profile they travel through. +""" + +from __future__ import annotations + +from .closed_form import ( + TransmissionLossResult, + seawater_absorption, + spreading_loss, + transmission_loss, +) +from .numerical import ( + NormalModeResult, + ParabolicEquationResult, + RayTraceResult, + normal_modes, + parabolic_equation, + ray_trace, +) +from .seabed_reflection import ( + BottomLossResult, + SeabedReflection, + bottom_reflection_loss, + critical_angle, + reflection_coefficient, + seabed_reflection, +) +from .sound_speed import ( + SoundSpeedProfile, + depth_to_pressure, + sea_water_sound_speed, + sound_speed_profile, +) +from .weston_regimes import ( + WESTON_REGIMES, + WESTON_SEABEDS, + WestonPropagationResult, + WestonRegimeBoundaries, + WestonSeabed, + critical_grazing_angle, + effective_depth, + loss_parameter, + reflection_loss_gradient, + waveguide_cutoff_frequency, + weston_propagation_loss, + weston_regime_boundaries, +) + +__all__ = [ + "WESTON_REGIMES", + "WESTON_SEABEDS", + "BottomLossResult", + "NormalModeResult", + "ParabolicEquationResult", + "RayTraceResult", + "SeabedReflection", + "SoundSpeedProfile", + "TransmissionLossResult", + "WestonPropagationResult", + "WestonRegimeBoundaries", + "WestonSeabed", + "bottom_reflection_loss", + "critical_angle", + "critical_grazing_angle", + "depth_to_pressure", + "effective_depth", + "loss_parameter", + "normal_modes", + "parabolic_equation", + "ray_trace", + "reflection_coefficient", + "reflection_loss_gradient", + "sea_water_sound_speed", + "seabed_reflection", + "seawater_absorption", + "sound_speed_profile", + "spreading_loss", + "transmission_loss", + "waveguide_cutoff_frequency", + "weston_propagation_loss", + "weston_regime_boundaries", +] diff --git a/src/phonometry/underwater/propagation.py b/src/phonometry/underwater/propagation/closed_form.py similarity index 99% rename from src/phonometry/underwater/propagation.py rename to src/phonometry/underwater/propagation/closed_form.py index 9b7fb00a1..37477492d 100644 --- a/src/phonometry/underwater/propagation.py +++ b/src/phonometry/underwater/propagation/closed_form.py @@ -206,8 +206,8 @@ class TransmissionLossResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the transmission loss versus range with its two contributions.""" - from .._i18n import check_language - from .._plot.underwater import plot_transmission_loss + from ..._i18n import check_language + from ..._plot.underwater import plot_transmission_loss return plot_transmission_loss(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/numerical_propagation.py b/src/phonometry/underwater/propagation/numerical.py similarity index 98% rename from src/phonometry/underwater/numerical_propagation.py rename to src/phonometry/underwater/propagation/numerical.py index 30abd33b0..d88873e33 100644 --- a/src/phonometry/underwater/numerical_propagation.py +++ b/src/phonometry/underwater/propagation/numerical.py @@ -33,7 +33,7 @@ import numpy as np -from .._internal.validation import require_positive +from ..._internal.validation import require_positive if TYPE_CHECKING: from matplotlib.axes import Axes @@ -96,8 +96,8 @@ class NormalModeResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the transmission loss versus range (loss increasing downward).""" - from .._i18n import check_language - from .._plot.underwater import plot_normal_modes + from ..._i18n import check_language + from ..._plot.underwater import plot_normal_modes return plot_normal_modes(self, ax=ax, language=check_language(language), **kwargs) @@ -118,7 +118,7 @@ def _propagating_band( if np.any(prop & (eigvals <= 10.0 * fd_floor)): import warnings - from .._internal.warnings import PhonometryWarning + from ..._internal.warnings import PhonometryWarning warnings.warn( "normal_modes: retained near-cutoff mode(s) lie within 10x the" @@ -306,8 +306,8 @@ class RayTraceResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the ray paths (depth increasing downward).""" - from .._i18n import check_language - from .._plot.underwater import plot_ray_trace + from ..._i18n import check_language + from ..._plot.underwater import plot_ray_trace return plot_ray_trace(self, ax=ax, language=check_language(language), **kwargs) @@ -431,8 +431,8 @@ class ParabolicEquationResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the transmission-loss field (depth increasing downward).""" - from .._i18n import check_language - from .._plot.underwater import plot_parabolic_equation + from ..._i18n import check_language + from ..._plot.underwater import plot_parabolic_equation return plot_parabolic_equation(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/seabed_reflection.py b/src/phonometry/underwater/propagation/seabed_reflection.py similarity index 97% rename from src/phonometry/underwater/seabed_reflection.py rename to src/phonometry/underwater/propagation/seabed_reflection.py index 66c4f1017..be379eb74 100644 --- a/src/phonometry/underwater/seabed_reflection.py +++ b/src/phonometry/underwater/propagation/seabed_reflection.py @@ -38,7 +38,7 @@ import numpy as np -from .._internal.validation import require_positive +from ..._internal.validation import require_positive if TYPE_CHECKING: from matplotlib.axes import Axes @@ -130,8 +130,8 @@ class BottomLossResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the bottom loss versus grazing angle with the critical angle.""" - from .._i18n import check_language - from .._plot.underwater import plot_bottom_loss + from ..._i18n import check_language + from ..._plot.underwater import plot_bottom_loss return plot_bottom_loss(self, ax=ax, language=check_language(language), **kwargs) @@ -227,8 +227,8 @@ def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) - :param kwargs: Forwarded to the ``|R|`` curve ``plot`` call. :return: The axes. """ - from .._i18n import check_language - from .._plot.underwater import plot_seabed_reflection + from ..._i18n import check_language + from ..._plot.underwater import plot_seabed_reflection return plot_seabed_reflection(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/sound_speed.py b/src/phonometry/underwater/propagation/sound_speed.py similarity index 99% rename from src/phonometry/underwater/sound_speed.py rename to src/phonometry/underwater/propagation/sound_speed.py index 90f13540d..bf364cde6 100644 --- a/src/phonometry/underwater/sound_speed.py +++ b/src/phonometry/underwater/propagation/sound_speed.py @@ -288,8 +288,8 @@ class SoundSpeedProfile: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the sound-speed profile (speed vs depth, depth increasing down).""" - from .._i18n import check_language - from .._plot.underwater import plot_sound_speed_profile + from ..._i18n import check_language + from ..._plot.underwater import plot_sound_speed_profile return plot_sound_speed_profile(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/weston_regimes.py b/src/phonometry/underwater/propagation/weston_regimes.py similarity index 99% rename from src/phonometry/underwater/weston_regimes.py rename to src/phonometry/underwater/propagation/weston_regimes.py index 0a26f9421..62c77c5d7 100644 --- a/src/phonometry/underwater/weston_regimes.py +++ b/src/phonometry/underwater/propagation/weston_regimes.py @@ -27,7 +27,7 @@ The regime formulae are energy-flux (incoherent) results: they describe the range-averaged field, not its modal interference. That is exactly what makes -them a usable cross-check for :mod:`phonometry.underwater.numerical_propagation` +them a usable cross-check for :mod:`phonometry.underwater.propagation.numerical` -- the range average of a normal-mode or parabolic-equation field over many interference cycles converges on the cylindrical-spreading law, with :math:`\psi_c = \pi/2` for a totally reflecting (pressure-release) bottom. @@ -57,7 +57,7 @@ import numpy as np from scipy.special import erf -from .._internal.validation import require_positive +from ..._internal.validation import require_positive if TYPE_CHECKING: from matplotlib.axes import Axes @@ -457,8 +457,8 @@ class WestonPropagationResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the composite loss with each regime's law and the boundaries.""" - from .._i18n import check_language - from .._plot.underwater import plot_weston_regimes + from ..._i18n import check_language + from ..._plot.underwater import plot_weston_regimes return plot_weston_regimes(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/sonar_equation.py b/src/phonometry/underwater/sonar_equation.py index a87878728..65da72107 100644 --- a/src/phonometry/underwater/sonar_equation.py +++ b/src/phonometry/underwater/sonar_equation.py @@ -286,7 +286,7 @@ def detection_range( """ from scipy.optimize import brentq - from .propagation import transmission_loss + from .propagation.closed_form import transmission_loss fom = _finite(figure_of_merit, "figure_of_merit") rmax = _finite(max_range, "max_range") diff --git a/src/phonometry/underwater/sources/__init__.py b/src/phonometry/underwater/sources/__init__.py new file mode 100644 index 000000000..9c4846b81 --- /dev/null +++ b/src/phonometry/underwater/sources/__init__.py @@ -0,0 +1,58 @@ +# Copyright (c) 2026. Jose Manuel Requena Plens +"""underwater.sources subdomain of phonometry: what makes the sound. + +Ship radiated noise (ISO 17208), shipping traffic, impact pile driving and the +wind and thermal ambient noise the sea makes on its own. +""" + +from __future__ import annotations + +from .ambient_noise import ( + AmbientNoiseResult, + ocean_ambient_noise, + thermal_noise_spectrum, + wind_noise_spectrum, +) +from .pile_driving_noise import ( + PileStrikeResult, + StrikeSelSpectrum, + cumulative_sel, + cumulative_sel_identical, + pile_strike_metrics, + single_strike_sel, + strike_sel_spectrum, +) +from .ship_radiated_noise import ( + ShipSourceLevelResult, + hydrophone_depths, + monopole_source_level, + radiated_noise_level, + source_level_uncertainty, +) +from .ship_traffic_noise import ( + VESSEL_CLASSES, + ShipTrafficSpectrum, + ship_source_spectrum, +) + +__all__ = [ + "VESSEL_CLASSES", + "AmbientNoiseResult", + "PileStrikeResult", + "ShipSourceLevelResult", + "ShipTrafficSpectrum", + "StrikeSelSpectrum", + "cumulative_sel", + "cumulative_sel_identical", + "hydrophone_depths", + "monopole_source_level", + "ocean_ambient_noise", + "pile_strike_metrics", + "radiated_noise_level", + "ship_source_spectrum", + "single_strike_sel", + "source_level_uncertainty", + "strike_sel_spectrum", + "thermal_noise_spectrum", + "wind_noise_spectrum", +] diff --git a/src/phonometry/underwater/ocean_ambient_noise.py b/src/phonometry/underwater/sources/ambient_noise.py similarity index 98% rename from src/phonometry/underwater/ocean_ambient_noise.py rename to src/phonometry/underwater/sources/ambient_noise.py index 4cbd2c40b..c60c5be1f 100644 --- a/src/phonometry/underwater/ocean_ambient_noise.py +++ b/src/phonometry/underwater/sources/ambient_noise.py @@ -33,7 +33,7 @@ import numpy as np -from .._internal.validation import ( +from ..._internal.validation import ( require_non_negative, require_positive, require_positive_array, @@ -140,8 +140,8 @@ class AmbientNoiseResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the composite spectrum and its components versus frequency.""" - from .._i18n import check_language - from .._plot.underwater import plot_ambient_noise + from ..._i18n import check_language + from ..._plot.underwater import plot_ambient_noise return plot_ambient_noise(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/pile_driving_noise.py b/src/phonometry/underwater/sources/pile_driving_noise.py similarity index 95% rename from src/phonometry/underwater/pile_driving_noise.py rename to src/phonometry/underwater/sources/pile_driving_noise.py index 1b6d2e352..facae060f 100644 --- a/src/phonometry/underwater/pile_driving_noise.py +++ b/src/phonometry/underwater/sources/pile_driving_noise.py @@ -17,7 +17,7 @@ * :func:`strike_sel_spectrum` -- the same single-strike SEL resolved into fractional-octave bands (ISO 18406 6.4.2.2), the input a marine-mammal assessment needs: feed it to - :func:`~phonometry.underwater.marine_mammal_weighting.weighted_exposure` to + :func:`~phonometry.underwater.bioacoustics.weighting.weighted_exposure` to obtain the weighted cumulative SEL of a piling campaign and its margin against the regulatory injury and TTS criteria. """ @@ -29,7 +29,7 @@ import numpy as np -from .acoustics import ( +from ..acoustics import ( _positive, _validate_pressure, peak_sound_pressure_level, @@ -134,8 +134,8 @@ class PileStrikeResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes | NDArray[Any]: """Plot the strike waveform and its cumulative energy.""" - from .._i18n import check_language - from .._plot.underwater import plot_pile_strike + from ..._i18n import check_language + from ..._plot.underwater import plot_pile_strike return plot_pile_strike(self, ax=ax, language=check_language(language), **kwargs) @@ -151,7 +151,7 @@ class StrikeSelSpectrum: a short record -- holds no energy at all and is reported as ``-inf``, the level of zero exposure. That is the neutral element of an energy sum, so such bands pass straight through - :func:`~phonometry.underwater.marine_mammal_weighting.weighted_exposure` + :func:`~phonometry.underwater.bioacoustics.weighting.weighted_exposure` without contributing. :ivar total_sel: Energy sum of ``band_sel`` over the covered bands, in dB re 1 µPa²·s. @@ -171,8 +171,8 @@ class StrikeSelSpectrum: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the per-band single-strike SEL.""" - from .._i18n import check_language - from .._plot.underwater import plot_strike_sel_spectrum + from ..._i18n import check_language + from ..._plot.underwater import plot_strike_sel_spectrum return plot_strike_sel_spectrum(self, ax=ax, language=check_language(language), **kwargs) @@ -196,7 +196,7 @@ def strike_sel_spectrum( Bands narrower than the FFT bin spacing ``fs/n`` contain no bin and are reported as ``-inf`` dB (see :class:`StrikeSelSpectrum`); the result can be handed straight to - :func:`~phonometry.underwater.marine_mammal_weighting.weighted_exposure`. + :func:`~phonometry.underwater.bioacoustics.weighting.weighted_exposure`. :param pressure: Sound-pressure time series of one strike (1-D), in Pa. :param fs: Sample rate, in Hz. @@ -205,7 +205,7 @@ def strike_sel_spectrum( :return: A :class:`StrikeSelSpectrum`. :raises ValueError: If the inputs are invalid. """ - from ..filters.frequencies import nominal_frequencies + from ...filters.frequencies import nominal_frequencies sig = _validate_pressure(pressure, min_samples=2) fs_v = _positive(fs, "fs") diff --git a/src/phonometry/underwater/ship_radiated_noise.py b/src/phonometry/underwater/sources/ship_radiated_noise.py similarity index 98% rename from src/phonometry/underwater/ship_radiated_noise.py rename to src/phonometry/underwater/sources/ship_radiated_noise.py index 5183dd36d..5b8d6c7a3 100644 --- a/src/phonometry/underwater/ship_radiated_noise.py +++ b/src/phonometry/underwater/sources/ship_radiated_noise.py @@ -29,7 +29,7 @@ import numpy as np -from .acoustics import UNDERWATER_REFERENCE_PRESSURE, _positive +from ..acoustics import UNDERWATER_REFERENCE_PRESSURE, _positive if TYPE_CHECKING: from matplotlib.axes import Axes @@ -156,8 +156,8 @@ class ShipSourceLevelResult: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot RNL, source level and the ΔL surface correction vs frequency.""" - from .._i18n import check_language - from .._plot.underwater import plot_ship_source_level + from ..._i18n import check_language + from ..._plot.underwater import plot_ship_source_level return plot_ship_source_level(self, ax=ax, language=check_language(language), **kwargs) diff --git a/src/phonometry/underwater/ship_traffic_noise.py b/src/phonometry/underwater/sources/ship_traffic_noise.py similarity index 96% rename from src/phonometry/underwater/ship_traffic_noise.py rename to src/phonometry/underwater/sources/ship_traffic_noise.py index d852df81c..e0e227517 100644 --- a/src/phonometry/underwater/ship_traffic_noise.py +++ b/src/phonometry/underwater/sources/ship_traffic_noise.py @@ -18,7 +18,7 @@ All three return an equivalent-monopole source spectral-density level (dB re 1 µPa²/Hz at 1 m, source depth 6 m) and the decidecade-band source level (dB re 1 µPa m). The predicted spectrum can be used as the ``shipping`` input of -:func:`phonometry.underwater.ocean_ambient_noise.ocean_ambient_noise` or placed at range +:func:`phonometry.underwater.sources.ambient_noise.ocean_ambient_noise` or placed at range with :func:`phonometry.underwater.propagation.transmission_loss`. Source (clean-room, implemented from the equations, validated against the @@ -36,7 +36,7 @@ import numpy as np -from .._internal.validation import require_positive, require_positive_array +from ..._internal.validation import require_positive, require_positive_array if TYPE_CHECKING: from matplotlib.axes import Axes @@ -154,8 +154,8 @@ class ShipTrafficSpectrum: def plot(self, ax: Axes | None = None, *, language: str = "en", **kwargs: Any) -> Axes: """Plot the predicted source spectral-density level versus frequency.""" - from .._i18n import check_language - from .._plot.underwater import plot_ship_traffic_spectrum + from ..._i18n import check_language + from ..._plot.underwater import plot_ship_traffic_spectrum return plot_ship_traffic_spectrum(self, ax=ax, language=check_language(language), **kwargs) diff --git a/tests/conftest.py b/tests/conftest.py index 2791ca154..fb76fe966 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -41,7 +41,7 @@ def pytest_configure(config): "tests/psychoacoustics/quality/test_fluctuation_strength_ecma.py", "tests/psychoacoustics/loudness/test_moore_glasberg_time.py", "tests/psychoacoustics/loudness/test_zwicker.py", - "tests/underwater/test_numerical_propagation.py", + "tests/underwater/propagation/test_numerical.py", "tests/filters/test_iec61260_report.py", "tests/room/test_room_ir.py", "tests/test_golden_baseline.py", diff --git a/tests/emission/test_emission_plot_i18n.py b/tests/emission/test_emission_plot_i18n.py new file mode 100644 index 000000000..c36dbeb00 --- /dev/null +++ b/tests/emission/test_emission_plot_i18n.py @@ -0,0 +1,47 @@ +# Copyright (c) 2026. Jose Manuel Requena Plens + +"""EN/ES language option of the emission ``.plot()`` renderers. + +Each result exposes ``plot(language=...)``; ``"es"`` must produce Spanish +labels/titles and ``language="xx"`` must raise a clear ``ValueError``. The +English default is covered elsewhere (and must stay byte-identical). +""" + +from __future__ import annotations + +import matplotlib + +matplotlib.use("Agg") + +import matplotlib.pyplot as plt +import numpy as np +import pytest + +from phonometry.emission.intensity_compliance import ( + intensity_class_compliance, + residual_index_limits, +) + + +def _labels(obj: object) -> str: + axes = obj if isinstance(obj, np.ndarray) else [obj] + parts = [] + for a in axes: + parts += [a.get_xlabel(), a.get_ylabel()] + leg = a.get_legend() + if leg is not None: + parts += [t.get_text() for t in leg.get_texts()] + return " || ".join(parts) + + +def test_intensity_class_es() -> None: + freqs, class1, _ = residual_index_limits("probe") + res = intensity_class_compliance(class1 + 1.0, freqs, device="probe") + ax = res.plot(language="es") + assert "Tabla 2 de IEC 61043" in ax.get_title() + assert "sonda" in ax.get_title() + assert "Mínimo clase 1" in _labels(ax) + assert "Región de aceptación clase 1" in _labels(ax) + plt.close("all") + with pytest.raises(ValueError): + res.plot(language="xx") diff --git a/tests/metrology/test_intensity_compliance.py b/tests/emission/test_intensity_compliance.py similarity index 100% rename from tests/metrology/test_intensity_compliance.py rename to tests/emission/test_intensity_compliance.py diff --git a/tests/metrology/test_metrology_plot_i18n.py b/tests/metrology/test_metrology_plot_i18n.py index 98b941656..92ae7178d 100644 --- a/tests/metrology/test_metrology_plot_i18n.py +++ b/tests/metrology/test_metrology_plot_i18n.py @@ -69,24 +69,6 @@ def test_monte_carlo_es() -> None: plt.close("all") -def test_intensity_class_es() -> None: - from phonometry.metrology.intensity_compliance import ( - intensity_class_compliance, - residual_index_limits, - ) - - freqs, class1, _ = residual_index_limits("probe") - res = intensity_class_compliance(class1 + 1.0, freqs, device="probe") - ax = res.plot(language="es") - assert "Tabla 2 de IEC 61043" in ax.get_title() - assert "sonda" in ax.get_title() - assert "Mínimo clase 1" in _labels(ax) - assert "Región de aceptación clase 1" in _labels(ax) - plt.close("all") - with pytest.raises(ValueError): - res.plot(language="xx") - - def test_trend_test_es_and_bad_language() -> None: values = [5.2, 6.2, 3.7, 6.4, 3.9, 4.0, 3.9, 5.3, 4.0, 4.6, 5.9, 6.5, 4.3, 5.7, 3.1, 5.6, 5.2, 3.9, 6.2, 5.0] diff --git a/tests/test_deprecated_aliases.py b/tests/test_deprecated_aliases.py index 4964ac3dc..b0311e5d0 100644 --- a/tests/test_deprecated_aliases.py +++ b/tests/test_deprecated_aliases.py @@ -491,6 +491,17 @@ def test_pre_move_module_path_still_imports(path: str) -> None: "phonometry.psychoacoustics.tonality", "phonometry.psychoacoustics.tonality_ecma", "phonometry.psychoacoustics.tone_audibility", + "phonometry.underwater.marine_mammal_audiograms", + "phonometry.underwater.marine_mammal_weighting", + "phonometry.underwater.numerical_propagation", + "phonometry.underwater.ocean_ambient_noise", + "phonometry.underwater.pile_driving_noise", + "phonometry.underwater.seabed_reflection", + "phonometry.underwater.ship_radiated_noise", + "phonometry.underwater.ship_traffic_noise", + "phonometry.underwater.sound_speed", + "phonometry.underwater.weston_regimes", + "phonometry.metrology.intensity_compliance", ] diff --git a/tests/underwater/test_marine_mammal_audiograms.py b/tests/underwater/bioacoustics/test_audiograms.py similarity index 99% rename from tests/underwater/test_marine_mammal_audiograms.py rename to tests/underwater/bioacoustics/test_audiograms.py index 4744b2bf0..eb3fa7fda 100644 --- a/tests/underwater/test_marine_mammal_audiograms.py +++ b/tests/underwater/bioacoustics/test_audiograms.py @@ -23,7 +23,7 @@ import numpy as np import pytest -from phonometry.underwater.marine_mammal_audiograms import ( +from phonometry.underwater.bioacoustics.audiograms import ( AUDIOGRAM_GROUPS, BEST_HEARING_FREQUENCY_KHZ, AudiogramResult, diff --git a/tests/underwater/test_marine_mammal_weighting.py b/tests/underwater/bioacoustics/test_weighting.py similarity index 99% rename from tests/underwater/test_marine_mammal_weighting.py rename to tests/underwater/bioacoustics/test_weighting.py index 7e3e5efb1..e1f10461c 100644 --- a/tests/underwater/test_marine_mammal_weighting.py +++ b/tests/underwater/bioacoustics/test_weighting.py @@ -25,7 +25,7 @@ import numpy as np import pytest -from phonometry.underwater.marine_mammal_weighting import ( +from phonometry.underwater.bioacoustics.weighting import ( WEIGHTING_GUIDANCE, AuditoryWeightingResult, auditory_weighting, @@ -192,7 +192,7 @@ def test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db(group: str) the in-water groups the sentence names, which is where the rule is validated against published values. """ - from phonometry.underwater.marine_mammal_audiograms import ( + from phonometry.underwater.bioacoustics.audiograms import ( BEST_HEARING_FREQUENCY_KHZ, group_audiogram, ) @@ -217,7 +217,7 @@ def test_the_plus_159_rule_rejects_the_printed_in_air_peak_values() -> None: so it corroborates the errata without depending on it. Note that 154.4 rounds to 154, not to the corrected 155; see docs/ERRATA.md. """ - from phonometry.underwater.marine_mammal_audiograms import ( + from phonometry.underwater.bioacoustics.audiograms import ( BEST_HEARING_FREQUENCY_KHZ, group_audiogram, ) diff --git a/tests/underwater/test_underwater_propagation.py b/tests/underwater/propagation/test_closed_form.py similarity index 100% rename from tests/underwater/test_underwater_propagation.py rename to tests/underwater/propagation/test_closed_form.py diff --git a/tests/underwater/test_numerical_propagation.py b/tests/underwater/propagation/test_numerical.py similarity index 99% rename from tests/underwater/test_numerical_propagation.py rename to tests/underwater/propagation/test_numerical.py index 4a22d1aae..4a89e5a5b 100644 --- a/tests/underwater/test_numerical_propagation.py +++ b/tests/underwater/propagation/test_numerical.py @@ -15,7 +15,7 @@ import numpy as np import pytest -from phonometry.underwater.numerical_propagation import ( +from phonometry.underwater.propagation.numerical import ( NormalModeResult, ParabolicEquationResult, RayTraceResult, diff --git a/tests/underwater/test_seabed_reflection.py b/tests/underwater/propagation/test_seabed_reflection.py similarity index 99% rename from tests/underwater/test_seabed_reflection.py rename to tests/underwater/propagation/test_seabed_reflection.py index d227f6144..76242462b 100644 --- a/tests/underwater/test_seabed_reflection.py +++ b/tests/underwater/propagation/test_seabed_reflection.py @@ -16,7 +16,7 @@ import numpy as np import pytest -from phonometry.underwater.seabed_reflection import ( +from phonometry.underwater.propagation.seabed_reflection import ( BottomLossResult, SeabedReflection, bottom_reflection_loss, diff --git a/tests/underwater/test_underwater_sound_speed.py b/tests/underwater/propagation/test_sound_speed.py similarity index 99% rename from tests/underwater/test_underwater_sound_speed.py rename to tests/underwater/propagation/test_sound_speed.py index a87602566..8ed3bd211 100644 --- a/tests/underwater/test_underwater_sound_speed.py +++ b/tests/underwater/propagation/test_sound_speed.py @@ -18,7 +18,7 @@ import numpy as np import pytest -from phonometry.underwater.sound_speed import ( +from phonometry.underwater.propagation.sound_speed import ( _KGCM2_PER_BAR, SoundSpeedProfile, _del_grosso, diff --git a/tests/underwater/test_weston_regimes.py b/tests/underwater/propagation/test_weston_regimes.py similarity index 98% rename from tests/underwater/test_weston_regimes.py rename to tests/underwater/propagation/test_weston_regimes.py index 2e575c55c..dd822a898 100644 --- a/tests/underwater/test_weston_regimes.py +++ b/tests/underwater/propagation/test_weston_regimes.py @@ -5,7 +5,7 @@ §9.1.1.2, printed pp. 452-458 -- the closed forms of Equations (9.42) to (9.61), the seabed properties of Table 9.1 (printed p. 454) and the exact energy-flux limit of an ideal waveguide, used here to cross-check the numerical -solvers of ``phonometry.underwater.numerical_propagation``. +solvers of ``phonometry.underwater.propagation.numerical``. """ from __future__ import annotations @@ -18,8 +18,8 @@ import pytest from scipy.special import erf -from phonometry.underwater.numerical_propagation import normal_modes, parabolic_equation -from phonometry.underwater.weston_regimes import ( +from phonometry.underwater.propagation.numerical import normal_modes, parabolic_equation +from phonometry.underwater.propagation.weston_regimes import ( WESTON_REGIMES, WESTON_SEABEDS, WestonPropagationResult, diff --git a/tests/underwater/test_ocean_ambient_noise.py b/tests/underwater/sources/test_ambient_noise.py similarity index 98% rename from tests/underwater/test_ocean_ambient_noise.py rename to tests/underwater/sources/test_ambient_noise.py index 0fdb82179..5d158971b 100644 --- a/tests/underwater/test_ocean_ambient_noise.py +++ b/tests/underwater/sources/test_ambient_noise.py @@ -16,7 +16,7 @@ import numpy as np import pytest -from phonometry.underwater.ocean_ambient_noise import ( +from phonometry.underwater.sources.ambient_noise import ( AmbientNoiseResult, ocean_ambient_noise, thermal_noise_spectrum, diff --git a/tests/underwater/test_pile_driving_noise.py b/tests/underwater/sources/test_pile_driving_noise.py similarity index 100% rename from tests/underwater/test_pile_driving_noise.py rename to tests/underwater/sources/test_pile_driving_noise.py diff --git a/tests/underwater/test_ship_radiated_noise.py b/tests/underwater/sources/test_ship_radiated_noise.py similarity index 98% rename from tests/underwater/test_ship_radiated_noise.py rename to tests/underwater/sources/test_ship_radiated_noise.py index 7e8e04fd2..4330e44e6 100644 --- a/tests/underwater/test_ship_radiated_noise.py +++ b/tests/underwater/sources/test_ship_radiated_noise.py @@ -21,7 +21,7 @@ radiated_noise_level, source_level_uncertainty, ) -from phonometry.underwater.ship_radiated_noise import _surface_correction +from phonometry.underwater.sources.ship_radiated_noise import _surface_correction def _delta_l(u: float) -> float: diff --git a/tests/underwater/test_ship_traffic_noise.py b/tests/underwater/sources/test_ship_traffic_noise.py similarity index 98% rename from tests/underwater/test_ship_traffic_noise.py rename to tests/underwater/sources/test_ship_traffic_noise.py index 372dea5d6..e19afef50 100644 --- a/tests/underwater/test_ship_traffic_noise.py +++ b/tests/underwater/sources/test_ship_traffic_noise.py @@ -16,7 +16,7 @@ import numpy as np import pytest -from phonometry.underwater.ship_traffic_noise import ( +from phonometry.underwater.sources.ship_traffic_noise import ( VESSEL_CLASSES, ShipTrafficSpectrum, ship_source_spectrum, @@ -171,7 +171,7 @@ def test_ship_traffic_plot_smoke() -> None: def test_randi_reproduces_report_table_2( length_ft: float, speed_kn: float, levels: dict[float, float], ) -> None: - from phonometry.underwater.ship_traffic_noise import _randi + from phonometry.underwater.sources.ship_traffic_noise import _randi f = np.array(sorted(levels)) got = _randi(f, speed_kn, length_ft * 0.3048) diff --git a/tests/underwater/test_ainslie_worked_examples.py b/tests/underwater/test_ainslie_worked_examples.py index b49dbac65..e85fca9fd 100644 --- a/tests/underwater/test_ainslie_worked_examples.py +++ b/tests/underwater/test_ainslie_worked_examples.py @@ -30,7 +30,7 @@ import numpy as np import pytest -from phonometry.underwater.marine_mammal_audiograms import orca_audiogram +from phonometry.underwater.bioacoustics.audiograms import orca_audiogram from phonometry.underwater.sonar_equation import ( DetectionRangeResult, active_sonar_equation, @@ -266,7 +266,7 @@ def test_both_solvers_return_zero_when_the_target_is_undetectable_everywhere() - def test_detection_range_from_curve_bridges_a_numerical_model() -> None: """The solver reads a detection range off a normal-mode transmission loss.""" - from phonometry.underwater.numerical_propagation import normal_modes + from phonometry.underwater.propagation.numerical import normal_modes depths = np.array([0.0, 100.0]) speeds = np.array([1500.0, 1500.0]) diff --git a/tests/underwater/test_underwater_plot_i18n.py b/tests/underwater/test_underwater_plot_i18n.py index 2b897fbfc..a767f8cf8 100644 --- a/tests/underwater/test_underwater_plot_i18n.py +++ b/tests/underwater/test_underwater_plot_i18n.py @@ -10,8 +10,8 @@ import pytest from phonometry.underwater import seabed_reflection -from phonometry.underwater.ocean_ambient_noise import ocean_ambient_noise from phonometry.underwater.sonar_equation import passive_sonar_equation +from phonometry.underwater.sources.ambient_noise import ocean_ambient_noise def _result() -> object: @@ -66,7 +66,7 @@ def test_seabed_reflection_plot_labels() -> None: def test_weston_regime_plot_labels() -> None: import numpy as np - from phonometry.underwater.weston_regimes import weston_propagation_loss + from phonometry.underwater.propagation.weston_regimes import weston_propagation_loss res = weston_propagation_loss(np.logspace(1.0, 5.0, 60), 250.0, 50.0, seabed="sand") ax = res.plot() @@ -87,8 +87,8 @@ def test_weston_regime_plot_labels() -> None: def test_marine_mammal_plot_labels() -> None: import numpy as np - from phonometry.underwater.marine_mammal_audiograms import group_audiogram - from phonometry.underwater.marine_mammal_weighting import ( + from phonometry.underwater.bioacoustics.audiograms import group_audiogram + from phonometry.underwater.bioacoustics.weighting import ( auditory_weighting, weighted_exposure, ) From 0cb803144cab5fa1a77bd2da91bed273ac405dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 04:27:10 +0200 Subject: [PATCH 2/3] Answer the review of the underwater split Two errata entries labelled their links with the filenames the split renamed, and the moved exposure test carried composite assertions. --- docs/ERRATA.md | 6 +++--- site/src/content/docs/es/reference/errata.md | 6 +++--- site/src/content/docs/reference/errata.md | 6 +++--- tests/underwater/bioacoustics/test_weighting.py | 15 ++++++++++----- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/ERRATA.md b/docs/ERRATA.md index 384efa92d..064ce41da 100644 --- a/docs/ERRATA.md +++ b/docs/ERRATA.md @@ -2067,7 +2067,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](../src/phonometry/underwater/propagation/weston_regimes.py) + [`propagation/weston_regimes.py`](../src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2102,7 +2102,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py) + [`bioacoustics/weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2171,7 +2171,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py), + in [`bioacoustics/weighting.py`](../src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/site/src/content/docs/es/reference/errata.md b/site/src/content/docs/es/reference/errata.md index 793fdf0ae..aebb6bc80 100644 --- a/site/src/content/docs/es/reference/errata.md +++ b/site/src/content/docs/es/reference/errata.md @@ -2102,7 +2102,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) + [`propagation/weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2137,7 +2137,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) + [`bioacoustics/weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2206,7 +2206,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), + in [`bioacoustics/weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/site/src/content/docs/reference/errata.md b/site/src/content/docs/reference/errata.md index 856d090d7..73a8d105f 100644 --- a/site/src/content/docs/reference/errata.md +++ b/site/src/content/docs/reference/errata.md @@ -2093,7 +2093,7 @@ which is the check that enforces the rule; see (Eqs. (9.42) to (9.47)), and PDF page 487, printed p. 457, 250 dpi (Eqs. (9.54) to (9.57)). - **Library behaviour:** `weston_regime_boundaries` in - [`weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) + [`propagation/weston_regimes.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/propagation/weston_regimes.py) implements the derivation-consistent $k^2H_e^2H/(9\pi\eta)$, which is also what keeps $\theta_\text{eff}$ defined with $H$ everywhere the module evaluates Eq. (9.47). The @@ -2128,7 +2128,7 @@ which is the check that enforces the rule; see published weighted TTS onset of the same row ($179\ \text{dB} = K + C$ with $K = 178$) is unaffected by the third digit. - **Library behaviour:** - [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) + [`bioacoustics/weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py) implements 1,36 and keeps the printed 1,37 available as `WeightingParameters.c_db_as_printed`, so an assessment that must reproduce the published table verbatim still can. Pinned by @@ -2197,7 +2197,7 @@ which is the check that enforces the rule; see printed p. 570, 250 dpi (the errata's reprinted Table 7, with PCA 123 / 155 / 138 / 161 and OCA 146 / 170 / 161 / 176). - **Library behaviour:** the errata-corrected values are the ones implemented - in [`marine_mammal_weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), + in [`bioacoustics/weighting.py`](https://github.com/jmrplens/phonometry/blob/main/src/phonometry/underwater/bioacoustics/weighting.py), pinned by `test_southall_table_7_errata_values_are_implemented`, with the +159 dB rule itself checked against the audiogram in `test_southall_impulsive_peak_spl_is_threshold_at_f0_plus_159_db` for the diff --git a/tests/underwater/bioacoustics/test_weighting.py b/tests/underwater/bioacoustics/test_weighting.py index e1f10461c..baeb68d7f 100644 --- a/tests/underwater/bioacoustics/test_weighting.py +++ b/tests/underwater/bioacoustics/test_weighting.py @@ -145,7 +145,8 @@ def test_southall_impulsive_sel_offset_from_the_non_impulsive_table() -> None: """"181 dB re 1 µPa²s for non-impulsive TTS onset −11 dB" (printed p. 155).""" cont = exposure_criteria("PCW", guidance="southall-2019") imp = exposure_criteria("PCW", guidance="southall-2019", impulsive=True) - assert cont.tts_sel is not None and imp.tts_sel is not None + assert cont.tts_sel is not None + assert imp.tts_sel is not None assert imp.tts_sel - cont.tts_sel == pytest.approx(-11.0, abs=1e-9) @@ -161,9 +162,11 @@ def test_impulsive_injury_offsets_are_15_db_sel_and_6_db_peak(guidance: str) -> """ for group in hearing_groups(guidance): row = exposure_criteria(group, guidance=guidance, impulsive=True) - assert row.tts_sel is not None and row.injury_sel is not None + assert row.tts_sel is not None + assert row.injury_sel is not None assert row.injury_sel - row.tts_sel == pytest.approx(15.0, abs=1e-9) - assert row.tts_peak_spl is not None and row.injury_peak_spl is not None + assert row.tts_peak_spl is not None + assert row.injury_peak_spl is not None assert row.injury_peak_spl - row.tts_peak_spl == pytest.approx(6.0, abs=1e-9) @@ -336,7 +339,8 @@ def test_peak_spl_criterion_is_compared_unweighted() -> None: res = weighted_exposure([1000.0], [100.0], "VHF", impulsive=True, peak_spl=210.0) assert res.peak_margin == pytest.approx(8.0, abs=1e-9) assert res.exceeds_injury is True - assert res.sel_margin is not None and res.sel_margin < 0.0 + assert res.sel_margin is not None + assert res.sel_margin < 0.0 def test_an_exposure_exactly_at_the_criterion_counts_as_exceeding_it() -> None: @@ -359,7 +363,8 @@ def test_peak_spl_can_trip_tts_alone_and_the_margin_says_so() -> None: res = weighted_exposure([1000.0], [100.0], "VHF", impulsive=True, peak_spl=199.0) assert res.tts_peak_margin == pytest.approx(3.0, abs=1e-9) assert res.peak_margin == pytest.approx(-3.0, abs=1e-9) - assert res.tts_margin is not None and res.tts_margin < 0.0 + assert res.tts_margin is not None + assert res.tts_margin < 0.0 assert res.exceeds_tts is True assert res.exceeds_injury is False From c9dee442972f66bb720a14aa5fde1ac5a09d5b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 04:48:28 +0200 Subject: [PATCH 3/3] Answer the second review of the underwater split Two module cross-references named the family package after the module of that name became it, so both degraded to plain code on the published pages, and the package docstring credited ISO 18405 for a loss it does not define. The metrology notice now steers to the emission namespace rather than to a module inside it, the constants the moved renderer took with it are gone from the module it left, and the migration table shows the cross-package move. --- docs/api-reference.md | 1 + llms-full.txt | 1 + scripts/generate_api_docs.py | 3 ++- .../content/docs/reference/api/underwater/numerical.md | 2 +- .../docs/reference/api/underwater/sonar-equation.md | 2 +- src/phonometry/_plot/emission.py | 10 +++++----- src/phonometry/_plot/metrology.py | 4 ---- src/phonometry/emission/__init__.py | 2 +- src/phonometry/metrology/__init__.py | 2 +- src/phonometry/underwater/propagation/__init__.py | 7 ++++--- src/phonometry/underwater/propagation/numerical.py | 2 +- src/phonometry/underwater/sonar_equation.py | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index cfc756556..d4c99decb 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -61,6 +61,7 @@ warns and delegates as well. | `phonometry.environmental` | `phonometry.environment` | 5.0 | | `phonometry.psychoacoustics.loudness_zwicker` | `phonometry.psychoacoustics.loudness.zwicker` | 5.0 | | `phonometry.underwater.ocean_ambient_noise` | `phonometry.underwater.sources.ambient_noise` | 5.0 | +| `phonometry.metrology.intensity_compliance` | `phonometry.emission.intensity_compliance` | 5.0 | | Name | Type | Description (Inputs) | Usage Snippet (Outputs) | | :--- | :--- | :--- | :--- | diff --git a/llms-full.txt b/llms-full.txt index 504321b0b..7d622be41 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -2274,6 +2274,7 @@ warns and delegates as well. | `phonometry.environmental` | `phonometry.environment` | 5.0 | | `phonometry.psychoacoustics.loudness_zwicker` | `phonometry.psychoacoustics.loudness.zwicker` | 5.0 | | `phonometry.underwater.ocean_ambient_noise` | `phonometry.underwater.sources.ambient_noise` | 5.0 | +| `phonometry.metrology.intensity_compliance` | `phonometry.emission.intensity_compliance` | 5.0 | | Name | Type | Description (Inputs) | Usage Snippet (Outputs) | | :--- | :--- | :--- | :--- | diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py index 2c65159bb..145999e76 100644 --- a/scripts/generate_api_docs.py +++ b/scripts/generate_api_docs.py @@ -800,7 +800,8 @@ def build_model() -> tuple[list[ModuleDoc], dict[str, str], list[str]]: "phonometry.environment.assessment.measurement" ), "phonometry.underwater_acoustics": "phonometry.underwater.acoustics", - "phonometry.underwater_propagation": "phonometry.underwater.propagation", + "phonometry.underwater_propagation": + "phonometry.underwater.propagation.closed_form", "phonometry.underwater_sound_speed": "phonometry.underwater.propagation.sound_speed", } diff --git a/site/src/content/docs/reference/api/underwater/numerical.md b/site/src/content/docs/reference/api/underwater/numerical.md index d28e4a80c..ecca3c357 100644 --- a/site/src/content/docs/reference/api/underwater/numerical.md +++ b/site/src/content/docs/reference/api/underwater/numerical.md @@ -9,7 +9,7 @@ Numerical models of underwater sound propagation (range-independent ocean). Three complementary numerical solvers for the acoustic field in a horizontally-stratified ocean waveguide, complementing the closed-form -transmission loss of `phonometry.underwater.propagation`: +transmission loss of [`phonometry.underwater.propagation.closed_form`](/phonometry/reference/api/underwater/closed-form/): * [`normal_modes`](/phonometry/reference/api/underwater/numerical/#normal_modes) -- the normal-mode expansion. Solves the depth-separated Sturm-Liouville eigenvalue problem by finite differences and assembles the diff --git a/site/src/content/docs/reference/api/underwater/sonar-equation.md b/site/src/content/docs/reference/api/underwater/sonar-equation.md index 722b67269..0932f00ce 100644 --- a/site/src/content/docs/reference/api/underwater/sonar-equation.md +++ b/site/src/content/docs/reference/api/underwater/sonar-equation.md @@ -30,7 +30,7 @@ a transmission-loss law at $\mathrm{TL} = \mathrm{FOM}$ gives the range at which the detection probability is 50 %: * [`detection_range`](/phonometry/reference/api/underwater/sonar-equation/#detection_range) inverts the closed-form loss of - `phonometry.underwater.propagation` (spreading plus volume absorption), + [`phonometry.underwater.propagation.closed_form`](/phonometry/reference/api/underwater/closed-form/) (spreading plus volume absorption), which is strictly increasing with range and therefore has a single crossing; * [`detection_range_from_curve`](/phonometry/reference/api/underwater/sonar-equation/#detection_range_from_curve) reads the crossing off any computed loss curve -- a normal-mode, parabolic-equation or Weston-regime prediction -- diff --git a/src/phonometry/_plot/emission.py b/src/phonometry/_plot/emission.py index 0bc790675..36ab28efe 100644 --- a/src/phonometry/_plot/emission.py +++ b/src/phonometry/_plot/emission.py @@ -36,17 +36,17 @@ from ..emission.sound_power_reverberation import ReverberationSoundPowerResult from ..emission.vibration_sound_power import VibrationSoundPowerResult -#: Spanish translations of the fixed labels/titles/legends rendered by the -#: emission-domain ``.plot()`` renderers, keyed by their verbatim English -#: text. ``_t`` returns the English key unchanged for any language other -#: than ``"es"``, so the English output is byte-for-byte identical to the -#: pre-i18n renderers. #: Shared frequency-axis label of the spectral renderers. _FREQ_LABEL = "Frequency [Hz]" #: Y-axis label of the residual-index plots (identical in both languages, #: the symbol carries the meaning). _LABEL_RESIDUAL_INDEX = r"$\delta_{pI0}$ [dB]" +#: Spanish translations of the fixed labels/titles/legends rendered by the +#: emission-domain ``.plot()`` renderers, keyed by their verbatim English +#: text. ``_t`` returns the English key unchanged for any language other +#: than ``"es"``, so the English output is byte-for-byte identical to the +#: pre-i18n renderers. _STRINGS: dict[str, str] = { "Band": "Banda", "Sound power level LW [dB]": "Nivel de potencia acústica LW [dB]", diff --git a/src/phonometry/_plot/metrology.py b/src/phonometry/_plot/metrology.py index c15dbf5c7..f54991966 100644 --- a/src/phonometry/_plot/metrology.py +++ b/src/phonometry/_plot/metrology.py @@ -27,16 +27,12 @@ _new_axes, ) -#: Shared frequency-axis label of the spectral renderers. -_FREQ_LABEL = "Frequency [Hz]" - #: Spanish translations of the fixed strings rendered by the metrology #: ``.plot()`` renderers, keyed by their verbatim English text. ``_t`` #: returns the English key unchanged for any language other than ``"es"``, #: so the English output is byte-for-byte identical to the pre-i18n #: renderers. _STRINGS: dict[str, str] = { - "Frequency [Hz]": "Frecuencia [Hz]", r"Contribution to combined uncertainty $|c_i|\,u(x_i)$": r"Contribución a la incertidumbre combinada $|c_i|\,u(x_i)$", "GUM uncertainty budget — y = {value}": diff --git a/src/phonometry/emission/__init__.py b/src/phonometry/emission/__init__.py index 5147134aa..2b2b54320 100644 --- a/src/phonometry/emission/__init__.py +++ b/src/phonometry/emission/__init__.py @@ -71,7 +71,7 @@ ) __all__ = [ -"NORMALIZED_IMPEDANCE", + "NORMALIZED_IMPEDANCE", "REFERENCE_VELOCITY", "TEMPORAL_VARIABILITY_LIMIT", "DeclarationForm", diff --git a/src/phonometry/metrology/__init__.py b/src/phonometry/metrology/__init__.py index db316d01d..991abe0b3 100644 --- a/src/phonometry/metrology/__init__.py +++ b/src/phonometry/metrology/__init__.py @@ -39,7 +39,7 @@ _MOVED_TO = ( "phonometry.filters", "phonometry.signals", - "phonometry.emission.intensity_compliance", + "phonometry.emission", ) __getattr__ = _namespace_shim(__name__, _MOVED_TO) diff --git a/src/phonometry/underwater/propagation/__init__.py b/src/phonometry/underwater/propagation/__init__.py index 8b261b500..9fdb3575e 100644 --- a/src/phonometry/underwater/propagation/__init__.py +++ b/src/phonometry/underwater/propagation/__init__.py @@ -1,9 +1,10 @@ # Copyright (c) 2026. Jose Manuel Requena Plens """underwater.propagation subdomain of phonometry: how the sound gets there. -The closed-form transmission loss of ISO 18405 and Weston's regimes, the -numerical solvers (normal modes, rays, parabolic equation), the seabed -reflection they bounce off and the sound speed profile they travel through. +The closed-form transmission loss (spreading plus seawater absorption) and +Weston's regimes, the numerical solvers (normal modes, rays, parabolic +equation), the seabed reflection they bounce off and the sound speed profile +they travel through. """ from __future__ import annotations diff --git a/src/phonometry/underwater/propagation/numerical.py b/src/phonometry/underwater/propagation/numerical.py index d88873e33..76e6f5927 100644 --- a/src/phonometry/underwater/propagation/numerical.py +++ b/src/phonometry/underwater/propagation/numerical.py @@ -4,7 +4,7 @@ Three complementary numerical solvers for the acoustic field in a horizontally-stratified ocean waveguide, complementing the closed-form -transmission loss of :mod:`phonometry.underwater.propagation`: +transmission loss of :mod:`phonometry.underwater.propagation.closed_form`: * :func:`normal_modes` -- the normal-mode expansion. Solves the depth-separated Sturm-Liouville eigenvalue problem by finite differences and assembles the diff --git a/src/phonometry/underwater/sonar_equation.py b/src/phonometry/underwater/sonar_equation.py index 65da72107..c48819f69 100644 --- a/src/phonometry/underwater/sonar_equation.py +++ b/src/phonometry/underwater/sonar_equation.py @@ -28,7 +28,7 @@ range at which the detection probability is 50 %: * :func:`detection_range` inverts the closed-form loss of - :mod:`phonometry.underwater.propagation` (spreading plus volume absorption), + :mod:`phonometry.underwater.propagation.closed_form` (spreading plus volume absorption), which is strictly increasing with range and therefore has a single crossing; * :func:`detection_range_from_curve` reads the crossing off any computed loss curve -- a normal-mode, parabolic-equation or Weston-regime prediction --