diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6dd75a16f..e1f81509a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -92,6 +92,13 @@ jobs: # step and is worthless once it is not. run: pnpm run check:icons working-directory: site + - name: Check the guides index lists every guide + # The page the Start topic offers as the map of the library is written + # by hand, and it had drifted to 100 of 104 links while stating 104 in + # the prose and in its own meta description, in both languages. Cheap, + # so it runs before the build rather than after it. + run: pnpm run check:guides + working-directory: site - name: Check EN/ES translation parity run: node scripts/check-i18n-parity.mjs working-directory: site @@ -124,6 +131,13 @@ jobs: # all green. run: pnpm run check:sidebar working-directory: site + - name: Check the landing, the contrast and the language bar + # Three audits that existed and ran for nobody: the colour tokens of + # both themes against the contrast floor, the landing page's headings + # and grid at ten viewport and font-size combinations, and the + # behaviour of the language suggestion bar. They share one preview. + run: pnpm run check:visual + working-directory: site # Only the branch that publishes needs the tarball. A pull request has # already got what it came for once the checks above have run. - uses: actions/upload-pages-artifact@v5 diff --git a/docs/materials/absorbers/porous-absorbers.md b/docs/materials/absorbers/porous-absorbers.md index e91310b3f..e0541377d 100644 --- a/docs/materials/absorbers/porous-absorbers.md +++ b/docs/materials/absorbers/porous-absorbers.md @@ -425,7 +425,7 @@ $|\mu_a| > 40$ above 50 Hz, and $\mu_b$ falls from 1.0 at 50 Hz to 0.82 at even though the printed sentence says "the ratio modulus": the model gives $\mu_b(1500) = 0.811 + 0.473j$, whose real part is 1.1 % from the printed value while its modulus, 0.939, is 14.5 % away. That is recorded in -[Errata](/phonometry/reference/errata/), along with the parameter sweep that +[Errata](../../ERRATA.md), along with the parameter sweep that fails to bring $|\mu_b|$ anywhere near 0.82. The impedance peak of the book's thinner sample is printed as 860 Hz and comes out at 863.5 Hz under the $\mathrm{Im}(Z_s)$ peak rule. Everything else, including the whole diff --git a/scripts/api_taxonomy.py b/scripts/api_taxonomy.py index ea1d73abf..4d96b6928 100644 --- a/scripts/api_taxonomy.py +++ b/scripts/api_taxonomy.py @@ -416,7 +416,7 @@ def module_section(module: str) -> Section: def _parent_subpackage(module: str) -> str: - """``phonometry.signals.levels`` -> ``signal``; top level -> ``""``.""" + """``phonometry.signals.levels`` -> ``signals``; top level -> ``""``.""" parts = module.split(".") return parts[1] if len(parts) > 2 else "" diff --git a/site/package.json b/site/package.json index 5105ce5cc..daca53d40 100644 --- a/site/package.json +++ b/site/package.json @@ -4,20 +4,22 @@ "version": "1.0.0", "private": true, "scripts": { - "prebuild": "node scripts/stage-media.mjs && node scripts/copy-llms.mjs", - "postbuild": "node scripts/add-sitemap-lastmod.mjs && node scripts/fix-redirect-doctype.mjs && node scripts/optimize-images.mjs && node scripts/emit-page-markdown.mjs", + "build": "astro build", + "check:guides": "node scripts/check-guides-index.mjs", "check:i18n": "node scripts/check-i18n-parity.mjs", + "check:icons": "node scripts/icon-sheet.mjs --check", "check:math": "node scripts/check-math-render.mjs", "check:sidebar": "node scripts/with-preview.mjs -- node scripts/check-sidebar.mjs", + "check:visual": "node scripts/with-preview.mjs -- sh -c 'node scripts/check-contrast.mjs && node scripts/check-home-headings.mjs && node scripts/check-lang-suggest.mjs'", "dev": "astro dev", - "build": "astro build", - "identity:sync": "node scripts/sync-identity.mjs", - "preview": "astro preview", "html-validate": "html-validate 'dist/**/*.html'", - "pa11y": "node scripts/with-preview.mjs -- ./node_modules/.bin/pa11y-ci", - "lighthouse": "node scripts/lighthouse-audit.mjs", "icons:sheet": "node scripts/icon-sheet.mjs", - "check:icons": "node scripts/icon-sheet.mjs --check" + "identity:sync": "node scripts/sync-identity.mjs", + "lighthouse": "node scripts/lighthouse-audit.mjs", + "pa11y": "node scripts/with-preview.mjs -- ./node_modules/.bin/pa11y-ci", + "postbuild": "node scripts/add-sitemap-lastmod.mjs && node scripts/fix-redirect-doctype.mjs && node scripts/optimize-images.mjs && node scripts/emit-page-markdown.mjs", + "prebuild": "node scripts/stage-media.mjs && node scripts/copy-llms.mjs", + "preview": "astro preview" }, "dependencies": { "@astrojs/starlight": "^0.41.5", @@ -34,6 +36,7 @@ "devDependencies": { "html-validate": "^11.5.6", "lighthouse": "^13.4.1", - "pa11y-ci": "^4.1.1" + "pa11y-ci": "^4.1.1", + "puppeteer": "24.43.1" } } diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml index 6a4618841..8d73bc46f 100644 --- a/site/pnpm-lock.yaml +++ b/site/pnpm-lock.yaml @@ -48,6 +48,9 @@ importers: pa11y-ci: specifier: ^4.1.1 version: 4.1.1(supports-color@10.2.2)(typescript@5.9.3) + puppeteer: + specifier: 24.43.1 + version: 24.43.1(supports-color@10.2.2)(typescript@5.9.3) packages: diff --git a/site/scripts/check-guides-index.mjs b/site/scripts/check-guides-index.mjs new file mode 100644 index 000000000..805d299ba --- /dev/null +++ b/site/scripts/check-guides-index.mjs @@ -0,0 +1,143 @@ +// The guides index lists every guide, and says how many there are. +// +// start/guides.md is what the Start topic offers as the map of the library, and +// it is written by hand. Nothing checked it, so it drifted: it linked 100 of the +// 104 guides while stating 104 in the prose and again in the frontmatter +// description, in both languages. Two substantial features were reachable only +// from the sidebar, and the page contradicted itself in the text a search engine +// quotes. +// +// Both halves are checked here. The links, because a guide that is not on the +// map is as good as unwritten for a reader who starts there; and the count, +// because a number in prose is a claim like any other. The spelled-out form is +// checked too, since it is the half nobody remembers to update. +// +// Usage: node scripts/check-guides-index.mjs +import { readFileSync, readdirSync, statSync } from 'node:fs'; +import { dirname, join, relative } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { topics } from '../src/data/topics.mjs'; + +const here = dirname(fileURLToPath(import.meta.url)); +const CONTENT = join(here, '..', 'src', 'content', 'docs'); + +/** + * The topics whose pages are guides: every one that teaches, which is every + * topic except the three carrying no teaching prose. Derived rather than + * listed, for the same reason the byline derives it (src/components/PageTitle). + */ +const NOT_A_DOMAIN = new Set(['start', 'reference', 'api']); +const DOMAINS = topics.map((topic) => topic.id).filter((id) => id && !NOT_A_DOMAIN.has(id)); + +/** Every markdown file under `dir`, at any depth. */ +function walk(dir, out = []) { + for (const name of readdirSync(dir)) { + const full = join(dir, name); + if (statSync(full).isDirectory()) walk(full, out); + else if (/\.mdx?$/.test(name)) out.push(full); + } + return out; +} + +/** The guide routes of one locale, in tree order, without the index pages. */ +function guideRoutes(root) { + const routes = []; + for (const domain of DOMAINS) { + for (const file of walk(join(root, domain)).sort()) { + const route = relative(root, file).replace(/\.mdx?$/, ''); + if (!/(^|\/)index$/.test(route)) routes.push(route); + } + } + return routes; +} + +/** A count in words, in the two languages the site publishes. */ +function spell(n, lang) { + const table = { + en: { + units: ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', + 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', + 'eighteen', 'nineteen'], + tens: ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'], + }, + es: { + units: ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve', + 'diez', 'once', 'doce', 'trece', 'catorce', 'quince', 'dieciséis', 'diecisiete', + 'dieciocho', 'diecinueve'], + tens: ['', '', 'veinte', 'treinta', 'cuarenta', 'cincuenta', 'sesenta', 'setenta', + 'ochenta', 'noventa'], + }, + }[lang]; + const below100 = (v) => + v < 20 + ? table.units[v] + : table.tens[Math.floor(v / 10)] + + (v % 10 ? (lang === 'es' ? ' y ' : '-') + table.units[v % 10] : ''); + if (n < 100) return below100(n); + const rest = n % 100; + const hundreds = Math.floor(n / 100); + if (lang === 'es') { + const head = hundreds === 1 ? (rest ? 'ciento' : 'cien') : `${table.units[hundreds]}cientos`; + return rest ? `${head} ${below100(rest)}` : head; + } + // "a hundred and four" and "one hundred and four" are both the number; the + // page uses the first, and a rewrite to the second should not fail a check + // about arithmetic. + const head = hundreds === 1 ? '(?:a|one) hundred' : `${table.units[hundreds]} hundred`; + return rest ? `${head} and ${below100(rest)}` : head; +} + +const LOCALES = [ + { lang: 'en', root: CONTENT, word: 'guides' }, + { lang: 'es', root: join(CONTENT, 'es'), word: 'guías' }, +]; + +let failures = 0; +const fail = (message) => { + console.error(`FAIL ${message}`); + failures += 1; +}; +const ok = (message) => console.log(`ok ${message}`); + +for (const { lang, root, word } of LOCALES) { + const routes = guideRoutes(root); + const index = readFileSync(join(root, 'start', 'guides.md'), 'utf8'); + + // The route has to appear as a link destination, not merely as text: a slug + // in a code block or a comment would satisfy a plain substring while giving + // the reader nothing to select. + const prefix = lang === 'es' ? '/phonometry/es/' : '/phonometry/'; + const missing = routes.filter((route) => !index.includes(`](${prefix}${route}/)`)); + if (missing.length > 0) { + fail(`${lang}: ${missing.length} guide(s) the index does not link: ${missing.join(', ')}`); + } else { + ok(`${lang}: the index links all ${routes.length} guides`); + } + + // Every number that introduces the word, in the prose and in the frontmatter + // description, has to be the number of guides there are. + const digits = [...index.matchAll(new RegExp(String.raw`(\d{2,4})\s+${word}`, 'g'))].map((m) => + Number(m[1]), + ); + const wrong = digits.filter((n) => n !== routes.length); + if (digits.length === 0) fail(`${lang}: the index states no count`); + else if (wrong.length > 0) { + fail(`${lang}: the index says ${[...new Set(wrong)].join(', ')} where there are ${routes.length}`); + } else { + ok(`${lang}: every count it states in figures says ${routes.length}`); + } + + // And the same number in words, which is the half nobody updates. + // `spell` returns a pattern rather than one spelling, since a number has more + // than one correct wording and the check is about the arithmetic. + const written = spell(routes.length, lang); + if (new RegExp(String.raw`\b${written}\s+${word}`, 'i').test(index)) { + ok(`${lang}: the count in words agrees with ${routes.length}`); + } else { + fail(`${lang}: the index does not say "${written} ${word}" anywhere, so its count in words has drifted from ${routes.length}`); + } +} + +console.log(`\n${failures} failing check(s).`); +process.exit(failures ? 1 : 0); diff --git a/site/scripts/check-home-headings.mjs b/site/scripts/check-home-headings.mjs index 8d5fb9cf3..5b4d9c4dc 100644 --- a/site/scripts/check-home-headings.mjs +++ b/site/scripts/check-home-headings.mjs @@ -176,7 +176,14 @@ for (const c of CASES) { } await page.setViewport({ width: c.width, height: c.height, deviceScaleFactor: SHOTS ? 2 : 1 }); await page.goto(`${BASE}${BASE_PATH}${c.path}`, { waitUntil: 'domcontentloaded', timeout: 90000 }); - await page.addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }); + // Only the dev server renders this toolbar, so against a preview of `dist` + // the rule matches nothing. The call itself is not free of consequence: the + // execution context can be replaced between the navigation and it, and the + // rejection failed a whole run once for a style rule that had nothing to + // hide. Losing it costs nothing, so it is allowed to fail. + await page + .addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }) + .catch(() => {}); await new Promise((r) => setTimeout(r, 500)); const { problems, root, wrapped } = await page.evaluate(audit); diff --git a/site/scripts/check-lang-suggest.mjs b/site/scripts/check-lang-suggest.mjs index 93b692723..54db035de 100644 --- a/site/scripts/check-lang-suggest.mjs +++ b/site/scripts/check-lang-suggest.mjs @@ -139,7 +139,14 @@ expect( await new Promise((r) => setTimeout(r, 400)); // The dev server parks its toolbar in the middle of the bottom edge, and // it hit-tests. It is not part of the site. - await page.addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }); + // Only the dev server renders this toolbar, so against a preview of `dist` + // the rule matches nothing. The call itself is not free of consequence: the + // execution context can be replaced between the navigation and it, and the + // rejection failed a whole run once for a style rule that had nothing to + // hide. Losing it costs nothing, so it is allowed to fail. + await page + .addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }) + .catch(() => {}); const hits = await page.evaluate(() => { // A regression that keeps the bar off screen is exactly what this check // is for, so report it as a failed hit test rather than throwing a raw diff --git a/site/scripts/check-page-chips.mjs b/site/scripts/check-page-chips.mjs index d691d072b..4a184a90f 100644 --- a/site/scripts/check-page-chips.mjs +++ b/site/scripts/check-page-chips.mjs @@ -113,7 +113,14 @@ async function landing({ path, viewport, theme, banner }) { banner ? (path.startsWith('/es/') ? ['en-US', 'en'] : ['es-ES', 'es']) : null, ); await page.goto(`${BASE}${BASE_PATH}${path}`, { waitUntil: 'networkidle0', timeout: 90000 }); - await page.addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }); + // Only the dev server renders this toolbar, so against a preview of `dist` + // the rule matches nothing. The call itself is not free of consequence: the + // execution context can be replaced between the navigation and it, and the + // rejection failed a whole run once for a style rule that had nothing to + // hide. Losing it costs nothing, so it is allowed to fail. + await page + .addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }) + .catch(() => {}); const out = await page.evaluate(async (wantBanner) => { const wait = (ms) => new Promise((r) => setTimeout(r, ms)); const bar = document.getElementById('lang-suggest'); diff --git a/site/scripts/check-sidebar.mjs b/site/scripts/check-sidebar.mjs index aec99c372..decf67deb 100644 --- a/site/scripts/check-sidebar.mjs +++ b/site/scripts/check-sidebar.mjs @@ -262,7 +262,14 @@ async function open(path, { phone = false } = {}) { const page = await context.newPage(); await page.setViewport(phone ? { width: 390, height: 844 } : { width: 1440, height: 900 }); await page.goto(`${BASE}${BASE_PATH}${path}`, { waitUntil: 'networkidle0', timeout: 90000 }); - await page.addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }); + // Only the dev server renders this toolbar, so against a preview of `dist` + // the rule matches nothing. The call itself is not free of consequence: the + // execution context can be replaced between the navigation and it, and the + // rejection failed a whole run once for a style rule that had nothing to + // hide. Losing it costs nothing, so it is allowed to fail. + await page + .addStyleTag({ content: 'astro-dev-toolbar{display:none !important}' }) + .catch(() => {}); if (phone) { await page.evaluate(() => document.querySelector('starlight-menu-button button')?.click()); await new Promise((r) => setTimeout(r, 300)); diff --git a/site/scripts/shared/audit.mjs b/site/scripts/shared/audit.mjs index 0fb77c5d6..015f50776 100644 --- a/site/scripts/shared/audit.mjs +++ b/site/scripts/shared/audit.mjs @@ -24,11 +24,12 @@ export const BASE_PATH = basePath; /** * The puppeteer package. * - * It is in the tree because pa11y-ci depends on it, not because we declare it, - * so under pnpm's default layout it is not linked into site/node_modules and a - * plain import does not find it. Normal resolution first (which is what works - * under `node-linker=hoisted`, npm and yarn), then the virtual store, then one - * actionable error. + * It is a declared dev dependency now. It used to be in the tree only because + * pa11y-ci depends on it, which under pnpm's default layout does not link it + * into site/node_modules at all: a plain import did not find it, and five + * checks rested on a package that a pa11y-ci upgrade could have taken away + * without a word. The store lookup below is kept because it costs nothing and + * still answers the case where the declared copy is not linked. */ export function loadPuppeteer() { const require = createRequire(import.meta.url); diff --git a/site/src/content/docs/es/start/guides.md b/site/src/content/docs/es/start/guides.md index f7f15f368..5fcd2fff3 100644 --- a/site/src/content/docs/es/start/guides.md +++ b/site/src/content/docs/es/start/guides.md @@ -318,6 +318,10 @@ ANSI/ASA S12.2 y ASTM E413/E1414. - [Transmisión por flancos en laboratorio (ISO 10848)](/phonometry/es/buildings/insulation/flanking-lab/): el índice de reducción de vibraciones de unión y las diferencias de niveles de flanco medidas en una instalación de ensayo. +- [Fuentes de impacto pesadas y blandas (ISO 16283-2)](/phonometry/es/buildings/insulation/heavy-impact-sources/): + la pelota de caucho y la máquina de neumático: el nivel de exposición a la + fuerza de impacto que las especifica, la comprobación de laboratorio que tienen + que pasar y el número único del anexo D de ISO 717-2. - [Índices globales de aislamiento (ISO 717)](/phonometry/es/buildings/insulation/insulation-ratings/): los motores de curva de referencia aéreo y de impactos con $C$, $C_{tr}$ y $C_I$, los términos de rango ampliado y la ficha de ISO 717. @@ -334,6 +338,10 @@ ANSI/ASA S12.2 y ASTM E413/E1414. - [Predicción del aislamiento acústico (EN 12354)](/phonometry/es/buildings/design/insulation-prediction/): el aislamiento in situ a ruido aéreo y de impactos entre recintos a partir de datos de elementos, con sus caminos de flancos. +- [Predicción detallada por bandas (ISO 12354)](/phonometry/es/buildings/design/detailed-prediction/): + la misma predicción banda a banda en vez de como un solo número: datos in situ + de elemento y de unión, el índice por flancos y el nivel de impactos, y la + contribución de cada camino a R'w y L'n,w. - [Predicción del aislamiento de paneles](/phonometry/es/buildings/design/panel-sound-insulation/): la ley de masa y la caída de coincidencia, las paredes dobles, rendijas y aberturas, la eficiencia de radiación de placas y las movilidades puntuales. @@ -446,6 +454,10 @@ IEC 61400-11. la fuente viaria común europea del Anexo II 2.2: potencia acústica de rodadura y propulsión por categoría de vehículo y potencia direccional por metro de línea fuente. +- [Emisión de la fuente ferroviaria CNOSSOS-EU](/phonometry/es/environment/sources/cnossos-rail-emission/): + la fuente ferroviaria del anexo II 2.3: rugosidad y filtro de contacto, ruido + de impacto, chirrido en curva, tracción y ruido aerodinámico, y las dos líneas + de fuente equivalentes. - [Efecto suelo esférico y barreras avanzadas](/phonometry/es/environment/propagation/ground-barriers/): el coeficiente de reflexión de Weyl-Van der Pol sobre suelo de impedancia finita y la difracción en barreras desde la teoría ondulatoria. @@ -491,6 +503,11 @@ ISO 17208-1/-2, ISO 18406 y JOMOPANS-ECHO. los solvers de modos normales, trazado de rayos y ecuación parabólica de la guía de ondas estratificada, y cómo elegir modelo de propagación. +- [Exposición a ruido de mamíferos marinos](/phonometry/es/underwater/marine-mammal-exposure/): + la cara auditiva de ese ruido: los audiogramas de grupo, las funciones de + ponderación reglamentarias con su versión de guía, y la exposición de una + campaña de hincado frente a los criterios de lesión. + ## [Fuentes y dispositivos](/phonometry/es/devices/) Potencia acústica, intensidad, declaraciones de emisión, electroacústica y diff --git a/site/src/content/docs/start/guides.md b/site/src/content/docs/start/guides.md index cfbd0838f..a009e75e6 100644 --- a/site/src/content/docs/start/guides.md +++ b/site/src/content/docs/start/guides.md @@ -304,6 +304,10 @@ ISO 12999-1, ISO 10052, ANSI/ASA S12.2 and ASTM E413/E1414. - [Laboratory Flanking Transmission (ISO 10848)](/phonometry/buildings/insulation/flanking-lab/): the junction vibration reduction index and the flanking level differences measured on a test facility. +- [Heavy and Soft Impact Sources (ISO 16283-2)](/phonometry/buildings/insulation/heavy-impact-sources/): + the rubber ball and the bang machine: the impact force exposure level that + specifies them, the laboratory check they have to pass, and the single number + of ISO 717-2 Annex D. - [Insulation Ratings (ISO 717)](/phonometry/buildings/insulation/insulation-ratings/): the airborne and impact reference-curve engines with $C$, $C_{tr}$ and $C_I$, the enlarged-range terms and the ISO 717 fiche. @@ -319,6 +323,10 @@ ISO 12999-1, ISO 10052, ANSI/ASA S12.2 and ASTM E413/E1414. - [Predicting Sound Insulation (EN 12354)](/phonometry/buildings/design/insulation-prediction/): in-situ airborne and impact insulation between rooms from element data, with their flanking paths. +- [Detailed Per-Band Prediction (ISO 12354)](/phonometry/buildings/design/detailed-prediction/): + the same prediction band by band rather than as one number: in-situ element and + junction data, the flanking index and impact level, and the per-path + contributions behind R'w and L'n,w. - [Predicting Panel Sound Insulation](/phonometry/buildings/design/panel-sound-insulation/): the mass law and coincidence dip, double walls, slits and apertures, plate radiation efficiency and point mobilities. @@ -423,6 +431,10 @@ SAE ARP 5534, ECAC Doc 29/32 and IEC 61400-11. - [CNOSSOS-EU road traffic source emission](/phonometry/environment/sources/cnossos-road-emission/): the common EU road source of Annex II 2.2: rolling and propulsion sound power per vehicle category and the directional power per metre of source line. +- [CNOSSOS-EU railway source emission](/phonometry/environment/sources/cnossos-rail-emission/): + the rail source of Annex II 2.3: roughness and the contact filter, impact + noise, curve squeal, traction and aerodynamic noise, and the two equivalent + source lines. - [Spherical ground effect and advanced barriers](/phonometry/environment/propagation/ground-barriers/): the Weyl-Van der Pol reflection coefficient over finite-impedance ground, and wave-theoretic barrier diffraction. @@ -467,6 +479,11 @@ JOMOPANS-ECHO. the normal-mode, ray-tracing and parabolic-equation solvers of the stratified waveguide, and how to choose a propagation model. +- [Marine-mammal noise exposure](/phonometry/underwater/marine-mammal-exposure/): + the hearing side of that noise: the group audiograms, the regulatory weighting + functions with their guidance version, and the exposure of a pile-driving + campaign against the injury criteria. + ## [Sources and devices](/phonometry/devices/) Sound power, intensity, emission declarations, electroacoustics and programme diff --git a/site/src/data/topics.mjs b/site/src/data/topics.mjs index 863e790d5..52fba75af 100644 --- a/site/src/data/topics.mjs +++ b/site/src/data/topics.mjs @@ -275,8 +275,7 @@ export const topics = [ 'vibration/structural/mechanical-mobility', 'vibration/structural/junction-transmission', 'vibration/structural/transfer-stiffness', - 'devices/emission/vibration-sound-power', - ], + ], }, { label: 'Human vibration', @@ -383,6 +382,7 @@ export const topics = [ 'devices/emission/sound-power', 'devices/emission/sound-power-pressure', 'devices/emission/sound-power-reverberation', + 'devices/emission/vibration-sound-power', 'devices/emission/sound-power-intensity', ], }, diff --git a/src/phonometry/_compat.py b/src/phonometry/_compat.py index 10bc9beef..fd1dea253 100644 --- a/src/phonometry/_compat.py +++ b/src/phonometry/_compat.py @@ -46,7 +46,7 @@ #: Old module path -> relocated module path for the 4.0 taxonomy. The #: oversized ``metrology`` catch-all became three packages: the normalized #: frequency selectivity in ``filters``, the general signal analysis in -#: ``signal``, and the transverse metrology that gives the package its name. +#: ``signals``, and the transverse metrology that gives the package its name. _MOVED_4X: dict[str, str] = { "phonometry.metrology.core": "phonometry.filters.core", "phonometry.metrology.filter_design": "phonometry.filters.design",