¿Quieres saber qué me lleva al análisis de paisajes sonoros?
Es un campo que combina ciencia, creatividad y exploración de una manera que pocos otros lo hacen. En primer lugar, Tu laboratorio está donde te lleven tus pies – Un sendero forestal, un parque de la ciudad o un camino de montaña remoto pueden convertirse en espacios para el descubrimiento científico e investigación acústica. En segundo lugar, Monitorear un área geográfica elegida se trata de creatividad. La innovación está en el corazón de la investigación de audio ambiental, ya sea que esté organizando un dispositivo personalizado, ocultando sensores en toldos de árboles o utilizando energía solar para configuraciones fuera de la red. Finalmente, El gran volumen de datos es realmente increíble, Y como sabemos, en el análisis espacial, todos los métodos son un juego justo. Desde horas de llamadas animales hasta el sutil zumbido de la maquinaria urbana, los datos acústicos recopilados pueden ser vastos y complejos, y eso abre la puerta a usar todo, desde el aprendizaje profundo hasta los sistemas de información geográfica (SIG) para darle sentido a todo.
Después de mis aventuras anteriores con Análisis de paisaje sonoro de uno de los ríos de PoloniaDecidí elevar la barra y el diseño e implementar una solución capaz de analizar paisajes sonoros en tiempo real. En esta publicación de blog, encontrará una descripción del método propuesto, junto con algún código que alimente todo el proceso, principalmente utilizando un Transformador de espectrograma de audio (AST) para la clasificación de sonido.
Métodos
Configuración
Hay muchas razones por las cuales, en este caso particular, elegí usar una combinación de Frambuesa pi 4 y audiomótico. Créeme, probé una amplia gama de dispositivos, desde modelos menos hambrientos de energía del Frambuesa pi familia, a través de varias versiones de Arduino, incluida la Portentatodo el camino al Nano Jetson. Y ese fue solo el comienzo. Elegir el micrófono correcto resultó ser aún más complicado.
Finalmente, fui con el Pi 4 B (4GB RAM) Debido a su rendimiento sólido y su consumo de energía relativamente bajo (~700 mAh Al ejecutar mi código). Además, combinarlo con el audiomóel en modo de micrófono USB me dio mucha flexibilidad durante la creación de prototipos. Audiomoz es un dispositivo poderoso con una gran cantidad de opciones de configuración, por ejemplo, una tasa de muestreo de 8 kHz a impresionantes 384 kHz. Tengo la fuerte sensación de que, a la larga, esta será una elección perfecta para mis estudios de paisaje sonoro.
Capturando el sonido
La captura de audio de un micrófono USB usando Python resultó ser sorprendentemente problemático. Después de luchar con varias bibliotecas por un tiempo, decidí recurrir al buen viejo Linux arecord. Todo el mecanismo de captura de sonido está encapsulado con el siguiente comando:
arecord -d 1 -D plughw:0,7 -f S16_LE -r 16000 -c 1 -q /tmp/audio.wav
Estoy utilizando deliberadamente un dispositivo complementario para habilitar la conversión automática en caso de que me gustaría introducir cualquier cambio en el Micrófono USB configuración. AST se ejecuta 16 kHz Muestras, por lo que la grabación y el muestreo de audiomoth se establecen en este valor.
Presta atención al generador en el código. Es importante que el dispositivo capture continuamente audio en los intervalos de tiempo que especifique. Su objetivo era almacenar solo la muestra de audio más reciente en el dispositivo y descartarla después de la clasificación. Este enfoque será especialmente útil más adelante durante los estudios a mayor escala en áreas urbanas, ya que ayuda a garantizar la privacidad de las personas y se alinea con Cumplimiento de GDPR.
import asyncio
import re
import subprocess
from tempfile import TemporaryDirectory
from typing import Any, AsyncGenerator
import librosa
import numpy as np
class AudioDevice:
def __init__(
self,
name: str,
channels: int,
sampling_rate: int,
format: str,
):
self.name = self._match_device(name)
self.channels = channels
self.sampling_rate = sampling_rate
self.format = format
@staticmethod
def _match_device(name: str):
lines = subprocess.check_output(['arecord', '-l'], text=True).splitlines()
devices = [
f'plughw:{m.group(1)},{m.group(2)}'
for line in lines
if name.lower() in line.lower()
if (m := re.search(r'card (\d+):.*device (\d+):', line))
]
if len(devices) == 0:
raise ValueError(f'No devices found matching `{name}`')
if len(devices) > 1:
raise ValueError(f'Multiple devices found matching `{name}` -> {devices}')
return devices[0]
async def continuous_capture(
self,
sample_duration: int = 1,
capture_delay: int = 0,
) -> AsyncGenerator[np.ndarray, Any]:
with TemporaryDirectory() as temp_dir:
temp_file = f'{temp_dir}/audio.wav'
command = (
f'arecord '
f'-d {sample_duration} '
f'-D {self.name} '
f'-f {self.format} '
f'-r {self.sampling_rate} '
f'-c {self.channels} '
f'-q '
f'{temp_file}'
)
while True:
subprocess.check_call(command, shell=True)
data, sr = librosa.load(
temp_file,
sr=self.sampling_rate,
)
await asyncio.sleep(capture_delay)
yield data
Clasificación
Ahora por la parte más emocionante.
Uso del transformador de espectrograma de audio (AST) y el excelente Cara de abrazo Ecosistema, podemos analizar eficientemente el audio y clasificar segmentos detectados en más de 500 categorías.
Tenga en cuenta que he preparado el sistema para admitir varios modelos previamente capacitados. Por defecto, uso MIT/AST-Finetuned-Audioset-10–10–0.4593ya que ofrece los mejores resultados y funciona bien en la Raspberry Pi 4. Sin embargo, ONNX-Community/AST-Finetuned-Audioset-10–10–0.4593-onnx También vale la pena explorar, especialmente su versión cuantificadaque requiere menos memoria y sirve los resultados de inferencia más rápido.
Puede notar que no estoy limitando el modelo a una sola etiqueta de clasificación, y eso es intencional. En lugar de asumir que solo una fuente de sonido está presente en un momento dado, aplico un función sigmoidía a los logits del modelo para obtener Probabilidades independientes para cada clase. Esto permite que el modelo exprese confianza en múltiples etiquetas simultáneamenteque es crucial para paisajes sonoros del mundo real donde las fuentes superpuestas, como las aves, el viento y el tráfico distante, a menudo ocurren juntas. Tomando el los cinco mejores resultados Asegura que el sistema capture los eventos de sonido más probables en la muestra sin obligar a una decisión de ganadores.
from pathlib import Path
from typing import Optional
import numpy as np
import pandas as pd
import torch
from optimum.onnxruntime import ORTModelForAudioClassification
from transformers import AutoFeatureExtractor, ASTForAudioClassification
class AudioClassifier:
def __init__(self, pretrained_ast: str, pretrained_ast_file_name: Optional[str] = None):
if pretrained_ast_file_name and Path(pretrained_ast_file_name).suffix == '.onnx':
self.model = ORTModelForAudioClassification.from_pretrained(
pretrained_ast,
subfolder='onnx',
file_name=pretrained_ast_file_name,
)
self.feature_extractor = AutoFeatureExtractor.from_pretrained(
pretrained_ast,
file_name=pretrained_ast_file_name,
)
else:
self.model = ASTForAudioClassification.from_pretrained(pretrained_ast)
self.feature_extractor = AutoFeatureExtractor.from_pretrained(pretrained_ast)
self.sampling_rate = self.feature_extractor.sampling_rate
async def predict(
self,
audio: np.array,
top_k: int = 5,
) -> pd.DataFrame:
with torch.no_grad():
inputs = self.feature_extractor(
audio,
sampling_rate=self.sampling_rate,
return_tensors='pt',
)
logits = self.model(**inputs).logits[0]
proba = torch.sigmoid(logits)
top_k_indices = torch.argsort(proba)[-top_k:].flip(dims=(0,)).tolist()
return pd.DataFrame(
{
'label': [self.model.config.id2label[i] for i in top_k_indices],
'score': proba[top_k_indices],
}
)
Para ejecutar la versión ONNX del modelo, debe agregar Óptimo a sus dependencias.
Nivel de presión de sonido
Junto con la clasificación de audio, captura información en el nivel de presión sonora. Este enfoque no solo identifica qué hizo el sonido pero también obtiene información sobre que fuertemente Cada sonido estaba presente. De esa manera, el modelo captura una representación más rica y más realista de la escena acústica y eventualmente puede usarse para detectar información de contaminación acústica de grano más fino.
import numpy as np
from maad.spl import wav2dBSPL
from maad.util import mean_dB
async def calculate_sound_pressure_level(audio: np.ndarray, gain=10 + 15, sensitivity=-18) -> np.ndarray:
x = wav2dBSPL(audio, gain=gain, sensitivity=sensitivity, Vadc=1.25)
return mean_dB(x, axis=0)
La ganancia (preamplificador + amp), la sensibilidad (db/v) y vadc (v) se establecen principalmente para audiomólo y se confirman experimentalmente. Si está utilizando un dispositivo diferente, debe identificar estos valores refiriéndose a la especificación técnica.
Almacenamiento
Los datos de cada sensor se sincronizan con una base de datos PostgreSQL cada 30 segundos. El prototipo actual de Monitor SoundScape Urban usa una conexión Ethernet; Por lo tanto, no estoy restringido en términos de carga de red. El dispositivo para áreas más remotas sincronizará los datos cada hora utilizando una conexión GSM.
label score device sync_id sync_time
Hum 0.43894055 yor 9531b89a-4b38-4a43-946b-43ae2f704961 2025-05-26 14:57:49.104271
Mains hum 0.3894045 yor 9531b89a-4b38-4a43-946b-43ae2f704961 2025-05-26 14:57:49.104271
Static 0.06389702 yor 9531b89a-4b38-4a43-946b-43ae2f704961 2025-05-26 14:57:49.104271
Buzz 0.047603738 yor 9531b89a-4b38-4a43-946b-43ae2f704961 2025-05-26 14:57:49.104271
White noise 0.03204195 yor 9531b89a-4b38-4a43-946b-43ae2f704961 2025-05-26 14:57:49.104271
Bee, wasp, etc. 0.40881288 yor 8477e05c-0b52-41b2-b5e9-727a01b9ec87 2025-05-26 14:58:40.641071
Fly, housefly 0.38868183 yor 8477e05c-0b52-41b2-b5e9-727a01b9ec87 2025-05-26 14:58:40.641071
Insect 0.35616025 yor 8477e05c-0b52-41b2-b5e9-727a01b9ec87 2025-05-26 14:58:40.641071
Speech 0.23579548 yor 8477e05c-0b52-41b2-b5e9-727a01b9ec87 2025-05-26 14:58:40.641071
Buzz 0.105577625 yor 8477e05c-0b52-41b2-b5e9-727a01b9ec87 2025-05-26 14:58:40.641071
Resultados
Una aplicación separada, construida utilizando Racionalizar y Tramamenteaccede a estos datos. Actualmente, muestra información sobre la ubicación del dispositivo, el SPL temporal (nivel de presión de sonido), las clases de sonido identificadas y una gama de índices acústicos.
Y ahora estamos listos para irnos. El plan es extender la red de sensores y alcanzar alrededor de 20 dispositivos dispersos por varios lugares de mi ciudad. Pronto estará disponible más información sobre una implementación de sensores de área más grande.
Además, estoy recopilando datos de un sensor implementado y planeo compartir el paquete de datos, el tablero y el análisis en una próxima publicación de blog. Usaré un enfoque interesante que garantiza una inmersión más profunda en la clasificación de audio. La idea principal es coincidir con diferentes niveles de presión de sonido con las clases de audio detectadas. Espero encontrar una mejor manera de describir la contaminación acústica. Así que estén atentos para un desglose más detallado pronto.
Mientras tanto, puedes leer el papel preliminar En mis estudios de paisajes sonoros (los auriculares son obligatorios).
Esta publicación fue revisada y editada usando Gramática Para mejorar la gramática y la claridad.