Este es mi detector de ronquidos de nuevo.
Me he vuelto bastante bueno detectando una señal cuando hay algo allí: puedo rastrear desde un ronquido que se despega de la pared hasta la respiración que ni siquiera puedes escuchar en la grabación. El problema es que no puedo decir cuándo la señal ha caído por debajo del nivel detectable y la aplicación solo está "escuchando cosas". Y, desafortunadamente, los ronquidos / respiración a menudo son lo suficientemente irregulares que es poco probable que una autocorrelación simple o un esquema de tiempo de intervalo similar ayude mucho. (Y en realidad es probable que en algunos casos el ruido sea más regular que la respiración).
Entonces, ¿hay algún truco que me falte para descubrir cuando no hay señal? Parece que me encuentro con un lugar difícil aquí, dado que la "señal" es tan ruidosa para empezar.
(Y tal vez esto esté relacionado con otro problema que estoy teniendo: extrañamente, no puedo medir con precisión (ni siquiera aproximadamente) el nivel de la señal incluso cuando es bastante alto. Dado que necesito usar promedios y proporciones para detectar la señal de todos modos, el tipo de información de nivel se pierde. Estoy buscando algunos trucos para reconstituirlo).
Técnica básica
(Para Yoda)
La señal de audio se muestrea (generalmente a 8000Hz, por varias razones), luego se FFT en 1024 bloques. (En mis experimentos, los filtros de Hamming y los bloques superpuestos parecen tener poco efecto, aunque pueden revisarse más adelante).
El FFT se divide en "bandas" (actualmente 5, ligeramente sesgadas en tamaño para colocar más detalles en el extremo inferior) y se suma la "diferencia espectral" y el nivel de cada banda. Los promedios a largo plazo de los valores de límite máximo se utilizan como "umbrales", y se utilizan ajustes de sesgo adicionales para mantener una tasa de "sobre umbral" de aproximadamente el 20%.
Cada valor "por encima del umbral" tiene un peso de 1 (por debajo del umbral tiene un peso de 0), pero luego ese peso se ajusta por la "variabilidad" aparente (aproximadamente a 2 Hz) en la banda, para dar más peso a las bandas que llevan una señal más aparente.
Se suman los pesos de las bandas y luego se suman los pesos sumados de los bloques posteriores durante aproximadamente un segundo para producir una "puntuación" continua. Esto se compara nuevamente con un umbral promedio en ejecución (más varias heurísticas) para detectar el inicio / desplazamiento del ronquido.
Actualizar
De repente se me ocurrió que si mi algoritmo mantiene efectivamente una señal de nivel constante (según mi problema de nivel de señal), la forma de medir efectivamente la SNR es midiendo el ruido cuando no hay señal.
Convenientemente, los ronquidos son intermitentes, con mucho "aire muerto" en el medio. Y ya estoy detectando los sobres ronquidos. ¡Así que cualquier cosa fuera del sobre (entre el final de un ronquido y el comienzo del siguiente) es presumiblemente ruido! Esto puedo (con un grado modesto de precisión / repetibilidad) medir. (Por supuesto, se necesitaron tres intentos para llegar a un algoritmo medio decente; la realidad nunca coincide con la teoría).
Así que todavía no tengo la respuesta completa, pero he progresado.
(Si bien la técnica anterior me da un proxy bastante bueno para SNR, todavía tengo problemas para estimar el nivel de señal real. Mis indicaciones de "nivel relativo" pueden estar fuera de la escala para una respiración apenas audible y más o menos para un sonajero de ventana. Necesito algún tipo de proxy para el nivel absoluto).