Ir al contenido

Construye un sonómetro

Normas aplicables: IEC 61672IEC 61260IEC 60942

Un sonómetro no es un algoritmo, sino una breve cadena de ellos, e IEC 61672-1 especifica cada etapa. phonometry implementa cada etapa como una función independiente y componible; esta página las ensambla, en orden, en un sonómetro funcional. Todos los fragmentos se ejecutan tal cual (las señales se sintetizan para que la página sea autocontenida), y cada etapa enlaza con la guía de fondo que la explica por completo.

La cadena del sonómetro de esta página: el tono del calibrador alimenta a sensitivity() para obtener el factor en pascales por unidad digital, la grabación de medición se une a él como presión calibrada y de ahí salen tres ramas de lectura, weighting_filter con time_weighting para el LAF(t) de pantalla y los niveles percentiles, laeq, sel y lc_peak para los niveles integrados, y octave_filter para el espectro en tercios de octava, cerradas por verify_weighting_class y verify_filter_class frente a los límites de aceptación de la Tabla 3 de IEC 61672-1 y la Tabla 1 de IEC 61260-1La cadena del sonómetro de esta página: el tono del calibrador alimenta a sensitivity() para obtener el factor en pascales por unidad digital, la grabación de medición se une a él como presión calibrada y de ahí salen tres ramas de lectura, weighting_filter con time_weighting para el LAF(t) de pantalla y los niveles percentiles, laeq, sel y lc_peak para los niveles integrados, y octave_filter para el espectro en tercios de octava, cerradas por verify_weighting_class y verify_filter_class frente a los límites de aceptación de la Tabla 3 de IEC 61672-1 y la Tabla 1 de IEC 61260-1

Es la misma cadena que IEC 61672-1 dibuja para el instrumento físico: el calibrador de clase 1 ancla el micrófono a 94 dB a 1 kHz, y cada etapa posterior es una función de esta página.

Cadena del sonómetro según IEC 61672-1: un calibrador acústico de clase 1 a 94 dB y 1 kHz acoplado al micrófono de medición con su pantalla antiviento, seguido de las cuatro etapas del instrumento: micrófono y preamplificador, ponderación frecuencial A, C o Z, cuadrado con la ponderación temporal exponencial F o S de 125 ms o 1 s, y la pantalla con LAF(t) en dB re 20 µPaCadena del sonómetro según IEC 61672-1: un calibrador acústico de clase 1 a 94 dB y 1 kHz acoplado al micrófono de medición con su pantalla antiviento, seguido de las cuatro etapas del instrumento: micrófono y preamplificador, ponderación frecuencial A, C o Z, cuadrado con la ponderación temporal exponencial F o S de 125 ms o 1 s, y la pantalla con LAF(t) en dB re 20 µPa

Los fragmentos de esta página se apoyan unos en otros: ejecútalos de arriba abajo en una misma sesión (o pega la página entera en un script).

Un sonómetro necesita dos grabaciones de la misma cadena de entrada: el tono de calibrador que ancla los números digitales a pascales, y la propia medición. Aquí ambas se sintetizan para que puedas ejecutar la página en cualquier parte; en una medición real proceden de tu micrófono.

import numpy as np
from phonometry import filters, metrology, signals
fs = 48000
# Tono de calibrador: 94 dB SPL = 1 Pa RMS a 1 kHz (IEC 60942).
# Sintetizado aquí; en campo, graba unos segundos de tu calibrador.
calibrator = np.sqrt(2) * np.sin(2 * np.pi * 1000 * np.arange(3 * fs) / fs)
# Medición "de calle": 10 s de ruido rosa de fondo más un evento de 1 s a
# 1 kHz, tipo bocina, para que los niveles estadísticos tengan algo que separar.
recording = signals.noise_signal(fs, 10.0, color="pink", rms=0.02, seed=7)
recording[4 * fs : 5 * fs] += 0.2 * np.sqrt(2) * np.sin(
2 * np.pi * 1000 * np.arange(fs) / fs
)

Un sonómetro construido en software hereda todos los defectos del fichero que se le entrega, y hay tres ajustes del grabador que deciden si los números de abajo significan algo. Fija la ganancia de entrada a mano y bloquéala. El control automático de ganancia, la limitación y la supresión de ruido mueven todos ellos la sensibilidad que el paso siguiente mide una sola vez y que el paso 4 aplica luego a todas las muestras, así que cualquiera de los tres anula la calibración en silencio. Graba PCM sin comprimir, a 24 bits y a 48 kHz o más. Un códec con pérdida redistribuye la energía en alta frecuencia que informa la etapa de tercios de octava del paso 5, y un fichero a 44,1 kHz no deja banda alguna por encima de 22 kHz sobre la que sostener la ponderación A de clase 1 del paso 3 cerca de 16 kHz. Elige la ganancia a partir del evento más ruidoso que la medida tenga que poder demostrar, dejando unos 12 dB de margen por encima de su pico: el del paso 4 lee el verdadero pico entre muestras, y una sola racha saturada lo invalida, y con él el .

Hay otras dos decisiones que son de la sesión y no del grabador. Graba el tono del calibrador por esa misma cadena bloqueada inmediatamente antes y inmediatamente después de la medición, para que el par acote la deriva que comprueba el paso 7; un factor medido otro día, o después de mover un control de ganancia, no es una calibración de este fichero. En exteriores, mantén el paravientos puesto y apunta el micrófono en la dirección de referencia que supone su calibración de campo libre.

Una hoja de campo que merece copiarse:

  • Ganancia fijada a mano y anotada; AGC, limitador y supresión de ruido desactivados.
  • PCM sin comprimir, 24 bits, kHz, un canal por micrófono.
  • Margen de pico de unos 12 dB sobre el evento más ruidoso previsto.
  • Tono de calibrador antes y después, misma ganancia, misma cadena, misma sesión.
  • Paravientos puesto, micrófono en trípode, dirección de referencia hacia la fuente.
  • Frecuencia de muestreo, ajuste de ganancia e identificadores del micrófono y del calibrador registrados.

2. Calibra: da significado físico a las muestras

Sección titulada «2. Calibra: da significado físico a las muestras»

Las muestras digitales son adimensionales; el factor de sensibilidad las convierte a pascales. sensitivity() lo calcula a partir de la grabación del calibrador y, de paso, valida la estabilidad a corto plazo de la grabación igual que IEC 60942 cualifica el propio calibrador, de modo que un micrófono mal acoplado se detecta aquí en lugar de corromper todos los niveles posteriores.

cal = metrology.sensitivity(calibrator, target_spl=94.0, fs=fs)
# cal está en Pa por unidad digital; todas las funciones de nivel lo aceptan
# como calibration_factor. Para este tono sintético vale ≈1,0.

Guía de fondo: Calibración y dBFS, que cubre la comprobación de estabilidad que esta llamada ejecuta sobre la grabación del calibrador, la regla del formato entero y el modo digital dBFS que se usa cuando no existe referencia física. Sin ningún calibrador, el factor puede calcularse a partir de la sensibilidad nominal de la cadena en vez de medirse — un micrófono de sensibilidad nominal mV/Pa a través de un preamplificador de ganancia lineal hacia un convertidor cuyo fondo de escala es voltios da pascales por unidad digital —, pero un factor nominal arrastra la tolerancia de la hoja de características y no los ±0,4 dB de un calibrador de clase 1, así que no puede informarse como una medición calibrada.

3. Pondera: frecuencia y tiempo (IEC 61672-1)

Sección titulada «3. Pondera: frecuencia y tiempo (IEC 61672-1)»

El sonómetro nunca muestra la presión en bruto. La señal pasa primero por la ponderación frecuencial A (la curva de respuesta del oído de IEC 61672-1), se eleva al cuadrado y se suaviza con el detector exponencial Fast (constante de tiempo de 125 ms). El resultado es el nivel móvil que sigue la pantalla de un sonómetro, :

pressure = cal * recording # unidades digitales -> Pa
weighted = filters.weighting_filter(pressure, fs, curve="A")
envelope = filters.time_weighting(weighted, fs, mode="fast") # media cuadrática en Pa^2
laf_t = 10 * np.log10(np.maximum(envelope, 1e-12) / (2e-5) ** 2)
# laf_t alcanza unos 80 dB durante el evento y se asienta cerca de 55 dB entre medias.

Una ráfaga tonal excita el detector exponencial RC: el condensador se carga y se descarga mientras las agujas Fast, Slow e Impulse siguen cada una su propia balística, y las tres trazas de nivel se van construyendo debajo para mostrar el ataque rápido, el promedio lento y la retención asimétrica del impulso.

Descargar la animación (WebM)

Una ráfaga tonal excita el detector exponencial RC: el condensador se carga y se descarga mientras las agujas Fast, Slow e Impulse siguen cada una su propia balística, y las tres trazas de nivel se van construyendo debajo para mostrar el ataque rápido, el promedio lento y la retención asimétrica del impulso.

Descargar la animación (WebM)

La aguja del clip es esa llamada a time_weighting: un paso bajo de primer orden que se carga y se descarga sobre la señal al cuadrado. Las tres agujas se diferencian en un solo número, la constante de tiempo, y por eso Fast atrapa un evento que Slow suaviza hasta borrarlo. Rara vez escribirás esta cadena a mano: todas las funciones de nivel del paso siguiente aplican la ponderación frecuencial internamente, y los niveles percentiles reconstruyen por ti esta envolvente Fast. Las métricas de energía (, SEL) integran directamente la señal ponderada al cuadrado, sin balística ninguna — y por eso no muestran ningún movimiento de aguja al que seguir. La cadena se muestra aquí porque es la pantalla del sonómetro.

Guías de fondo: Ponderación frecuencial (A, C, Z) y Ponderación temporal, que desmonta este mismo clip frente a la tabla de ráfagas tonales de IEC 61672-1.

4. Integra: los números que da un sonómetro

Sección titulada «4. Integra: los números que da un sonómetro»

Una sola pasada sobre la grabación calibrada produce las lecturas estándar: el equivalente en energía, los niveles percentiles que describen cómo fluctuó el nivel ( es el fondo, los eventos), el nivel de exposición sonora que normaliza el evento a un segundo, y el pico con ponderación C para contenido impulsivo.

la_eq = signals.laeq(recording, fs, calibration_factor=cal) # ≈70,2 dB
ln = signals.ln_levels(
recording, fs, n=(10, 50, 90), weighting="A", calibration_factor=cal
) # L10 ≈78,0, L50 ≈55,1, L90 ≈54,9
lae = signals.sel(recording, fs, weighting="A", calibration_factor=cal) # ≈80,2
lc_pk = signals.lc_peak(recording, fs, calibration_factor=cal) # ≈84,4
print(f"LAeq {la_eq:.1f} dB | L10 {ln[10]:.1f} | L90 {ln[90]:.1f} "
f"| LAE {lae:.1f} | LCpeak {lc_pk:.1f}")

Fíjate en la aritmética que codifican los números. El segundo del evento mide 80,0 dB por sí solo y los nueve segundos de fondo 55,0 dB, así que en energía el evento aporta y el fondo : una razón de unos 35:1, o 15,5 dB. La ventaja de 25 dB del evento gana a los 9,5 dB () que el fondo recupera por duración, y por eso el de 10 s de 70,2 dB queda solo 0,1 dB por encima de los 70,0 dB que daría el evento solo repartido sobre esos mismos 10 s: el fondo es casi invisible en el promedio energético. El es ese más dB, toda la energía comprimida en un segundo. Los percentiles se leen al revés: el evento ocupa exactamente el 10 % del registro, así que sube el a 78,0 dB y deja el en 54,9 dB, el nivel de fondo.

Historial de nivel ponderado A con respuesta Fast de la grabación de diez segundos de esta página, que sube desde unos 55 dB de fondo rosa hasta 80 dB durante el evento de un segundo en el segundo cuatro, con líneas horizontales en LAeq 70,2 dB, L10 78,0 dB, L50 55,1 dB y L90 54,9 dB, el segundo del evento sombreado, y una anotación que dice LAE 80,2 dB, toda la energía del evento comprimida en un segundoHistorial de nivel ponderado A con respuesta Fast de la grabación de diez segundos de esta página, que sube desde unos 55 dB de fondo rosa hasta 80 dB durante el evento de un segundo en el segundo cuatro, con líneas horizontales en LAeq 70,2 dB, L10 78,0 dB, L50 55,1 dB y L90 54,9 dB, el segundo del evento sombreado, y una anotación que dice LAE 80,2 dB, toda la energía del evento comprimida en un segundo

Las lecturas de este paso dibujadas sobre la grabación que las produjo: el segundo del evento sube el y el , y deja el y el sobre el fondo.

Mostrar el código de esta figura
import matplotlib.pyplot as plt
t = np.arange(recording.size) / fs
fig, ax = plt.subplots(figsize=(9, 4))
ax.axvspan(4.0, 5.0, color="C1", alpha=0.15)
ax.plot(t, laf_t, linewidth=0.8, label="$L_{AF}(t)$")
for value, name, style in [(la_eq, "LAeq", "--"), (ln[10], "L10", ":"),
(ln[50], "L50", "-."), (ln[90], "L90", (0, (5, 1)))]:
ax.axhline(value, linestyle=style, linewidth=1.0,
label=f"{name} = {value:.1f} dB")
ax.annotate(f"LAE = {lae:.1f} dB: toda la energía del evento en 1 s",
xy=(4.5, lae), xytext=(5.6, lae + 2),
arrowprops={"arrowstyle": "->"})
ax.set(xlabel="Tiempo [s]", ylabel="Nivel [dB re 20 µPa]", xlim=(0, 10))
ax.legend(loc="lower right", ncols=2)
plt.show()

Guía de fondo: Niveles integrados y estadísticos, que añade el nivel máximo con ponderación temporal que da esta misma traza laf_t, la dosis de ruido y los espectrogramas de octava; el y los niveles de evaluación continúan en Niveles ambientales.

5. Filtra en bandas: la vista de espectro (IEC 61260-1)

Sección titulada «5. Filtra en bandas: la vista de espectro (IEC 61260-1)»

Un sonómetro de clase 1 con juego de filtros da niveles de banda. octave_filter descompone la señal calibrada en bandas de fracción de octava cuyo diseño está anclado a los bordes de banda de IEC 61260-1; nominal=True las etiqueta con las frecuencias preferentes que leerías en un instrumento.

spl, bands = filters.octave_filter(
recording, fs, fraction=3, nominal=True,
calibration=filters.LevelCalibration(factor=cal),
)
# 33 niveles de banda de tercio de octava en dB SPL, etiquetados '12.5' ... '20k'.
# La banda '1k' contiene el evento: ≈70 dB, con sus vecinas ≈25 dB por debajo.
print(dict(zip(bands, np.round(spl, 1))))

Estos son niveles de banda sin ponderar (Z): octave_filter se ejecutó sobre recording y no sobre la señal weighted del paso 3, así que su suma energética reproduce el sin ponderar y no el del paso 4. Esa suma es la comprobación de coherencia que merece la pena hacer una vez en cada medición:

print(f"suma de las bandas Z {10 * np.log10(np.sum(10 ** (spl / 10))):.1f} dB")
print(f"Leq(Z) {signals.leq(recording, calibration_factor=cal):.1f} dB")
# suma de las bandas Z 70.3 dB
# Leq(Z) 70.4 dB

La décima o dos de defecto es la energía que queda fuera del rango de análisis de 12,5 Hz a 20 kHz más la forma de los bordes de banda. Una discrepancia mayor que medio decibelio aproximadamente apunta a un error de calibración o de frecuencia de muestreo, no a los filtros.

Para obtener un espectro ponderado A, filtra en bandas la señal ya ponderada del paso 3 en lugar de la grabación en bruto:

spl_a, _ = filters.octave_filter(weighted, fs, fraction=3, nominal=True)
print(f"suma de las bandas A {10 * np.log10(np.sum(10 ** (spl_a / 10))):.1f} dB")
# suma de las bandas A 70.2 dB -> el LAeq del paso 4, con una centésima de decibelio

Esa identidad cierra el círculo entre las dos mitades del sonómetro: la etapa de ponderación y la etapa de filtrado miden la misma energía.

Treinta y tres niveles de banda de tercio de octava de la grabación de esta página en forma de gráfica escalonada de 12,5 Hz a 20 kHz, con las bandas sin ponderar planas en torno a 43 dB y la banda de 1 kHz resaltada en 70 dB, dibujadas junto al espectro ponderado A de la misma grabación, que cae por debajo de 500 Hz y por encima de 4 kHzTreinta y tres niveles de banda de tercio de octava de la grabación de esta página en forma de gráfica escalonada de 12,5 Hz a 20 kHz, con las bandas sin ponderar planas en torno a 43 dB y la banda de 1 kHz resaltada en 70 dB, dibujadas junto al espectro ponderado A de la misma grabación, que cae por debajo de 500 Hz y por encima de 4 kHz

La misma grabación leída en bandas, sin ponderar y con ponderación A. El ruido rosa da niveles de banda de fracción de octava casi constantes, así que el suelo plano es el fondo y la única barra que sobresale 27 dB por encima es el evento; la ponderación A inclina ese suelo sin tocar la banda de 1 kHz, donde la curva A vale 0 dB.

Mostrar el código de esta figura
_, centres = filters.octave_filter(recording, fs, fraction=3) # centros exactos
fig, ax = plt.subplots(figsize=(9, 4))
ax.step(centres, spl, where="mid", label="Z (sin ponderar)")
ax.step(centres, spl_a, where="mid", linestyle="--", label="Ponderación A")
ax.axvspan(891.3, 1122.5, color="C1", alpha=0.15) # la banda de 1 kHz
ax.set(xscale="log", xlabel="Frecuencia central de banda [Hz]",
ylabel="Nivel de banda [dB re 20 µPa]")
ax.legend(loc="lower center")
plt.show()

Guías de fondo: Bancos de filtros para las arquitecturas de filtro y el modo de fase cero, Procesado por bloques para streaming, y Multicanal y rendimiento para arrays.

6. Verifica: ¿es este sonómetro de clase 1?

Sección titulada «6. Verifica: ¿es este sonómetro de clase 1?»

Un instrumento real solo es un «sonómetro de clase 1» cuando sus ponderaciones y filtros superan los límites de aceptación de las normas. La biblioteca incluye los mismos verificadores que se aplica a sí misma en CI: verify_weighting_class barre un WeightingFilter contra los límites de la Tabla 3 de IEC 61672-1, y verify_filter_class barre un OctaveFilterBank contra los límites de la Tabla 1 de IEC 61260-1.

wf = filters.WeightingFilter(fs, curve="A")
print(filters.verify_weighting_class(wf)["overall_class"]) # 1
bank = filters.OctaveFilterBank(fs, fraction=3)
print(filters.verify_filter_class(bank)["overall_class"]) # 1

Los veredictos también llegan por banda, de modo que puedes ver exactamente dónde un diseño se saldría de su corredor de clase. Guías de fondo: Ponderación frecuencial (sección de verificación de clase) y Verificación de clase de filtros (la máscara de la Tabla 1, la clase 0 y la ficha de conformidad).

El paso 6 verificó el diseño de las etapas de ponderación y de filtrado. No dice nada del fichero. Un sonómetro de hardware se niega a mostrar un nivel del que no puede responder: el apartado 5.11 de IEC 61672-1 hace obligatorio un indicador de sobrecarga (el 5.11.5 lo enclava siempre que se estén midiendo niveles promediados en el tiempo o de exposición), y el apartado 5.12 añade una indicación de rango inferior. Un sonómetro montado a base de funciones no tiene ninguno de los dos, así que tres comprobaciones sobre la grabación los sustituyen, y cada una de las tres da un número que debe figurar en el informe.

# (a) Sobrecarga: cualquier racha de dos o más muestras clavadas a fondo de escala.
at_full_scale = np.flatnonzero(np.abs(recording) >= 1.0 - 1e-6)
runs = (np.split(at_full_scale, np.flatnonzero(np.diff(at_full_scale) > 1) + 1)
if at_full_scale.size else [])
clipped_runs = sum(1 for run in runs if run.size >= 2)
# (b) Rango inferior: la misma cadena capturando su propio ruido (cápsula ficticia).
self_noise = signals.noise_signal(fs, 3.0, color="pink", rms=2e-4, seed=11)
margin = la_eq - signals.laeq(self_noise, fs, calibration_factor=cal)
# (c) Deriva: el tono del calibrador grabado otra vez tras la medición.
calibrator_post = 0.985 * calibrator # un 1,5 % más bajo en esta sesión
cal_post = metrology.sensitivity(calibrator_post, target_spl=94.0, fs=fs)
drift = abs(20 * np.log10(cal_post / cal))
print(f"rachas saturadas {clipped_runs} | margen S/R {margin:.1f} dB "
f"| deriva {drift:.2f} dB")
# rachas saturadas 0 | margen S/R 55.3 dB | deriva 0.13 dB

Rechaza el registro si existe cualquier racha saturada, exige al menos 10 dB de margen sobre el ruido propio de la cadena (por debajo de eso, el está leyendo el preamplificador y no el fondo), y mantén la diferencia de sensibilidad entre el antes y el después dentro del umbral de 0,5 dB de la guía de calibración, que además explica por qué esa misma diferencia es el término de deriva del balance de incertidumbre.

Aprende la huella del fallo que el nivel de banda ancha esconde. La saturación apenas mueve el (recortar duramente un tono de 1 kHz al 80 % de su pico cuesta 0,9 dB) mientras inyecta una escalera de armónicos impares que sube la banda de tercio de octava de 3,15 kHz en 37 dB, la de 5 kHz en 37 dB y la de 8 kHz en 25 dB. Un espectro de tercios de octava con picos regularmente espaciados por encima de lo que la fuente puede radiar de forma plausible es saturación mientras no se demuestre lo contrario. El fallo contrario no se le parece en nada: una señal muy por debajo del rango del convertidor da un espectro que apenas cambia cuando se apaga la fuente, que es lo que caza la comprobación (b).

  • Cubierto

    Esta página compone etapas ya implementadas en otras guías en la cadena que describe IEC 61672-1:2013: la ponderación frecuencial A y la ponderación temporal exponencial Fast, el , los niveles percentiles, el nivel de exposición sonora y el pico con ponderación C, los filtros de banda de octava de IEC 61260-1:2014 de octave_filter, y los límites de aceptación de clase de la Tabla 3 (ponderación) y la Tabla 1 (filtro) que comprueban verify_weighting_class y verify_filter_class. Cada guía de fondo indica su propia cobertura en detalle.

  • No cubierto

    verify_weighting_class y verify_filter_class comprueban el diseño de respuesta en frecuencia de los filtros digitales frente a las tablas de las normas; no realizan los ensayos de evaluación de patrón de IEC 61672-2:2013 que necesita un instrumento físico para su aprobación de tipo, como el ruido autogenerado, el rango de linealidad, la indicación de sobrecarga o la respuesta direccional, ni los ensayos periódicos de IEC 61672-3:2013 que recibe un instrumento en servicio. Un veredicto de clase de esta página describe el algoritmo, no un aparato construido, y las tres comprobaciones del paso 7 criban la grabación, no el instrumento. Los ensayos de conformidad del calibrador de IEC 60942:2017 tampoco se ejecutan aquí; consulta la guía de calibración para lo que sensitivity() comprueba y lo que no.

El sonómetro construido aquí es el tronco; el resto del núcleo crece de él.

  • International Electrotechnical Commission. (2013). Electroacoustics — Sound level meters — Part 1: Specifications (IEC 61672-1:2013). El plano del instrumento montado en esta página: la ponderación frecuencial A y la ponderación temporal exponencial Fast de la cadena de niveles, el pico con ponderación C y el nivel de exposición sonora, y los límites de aceptación de clase de la Tabla 3 que comprueba verify_weighting_class.
  • International Electrotechnical Commission. (2014). Electroacoustics — Octave-band and fractional-octave-band filters — Part 1: Specifications (IEC 61260-1:2014). Los filtros de bandas de fracción de octava de la etapa de espectro, y los límites de aceptación de clase de la Tabla 1 que comprueba verify_filter_class.
  • International Electrotechnical Commission. (2017). Electroacoustics — Sound calibrators (IEC 60942:2017). El calibrador acústico que supone la etapa de sensibilidad: el nivel principal de 94 dB y la comprobación de estabilidad a corto plazo aplicada a la grabación de referencia.