Este é o meu detector de ronco novamente.
Fiquei muito bom em detectar um sinal quando há algo lá - pode rastrear desde um ronco de parede até a respiração que você nem consegue ouvir na gravação. O problema é que não sei dizer quando o sinal caiu abaixo do nível detectável e o aplicativo está apenas "ouvindo coisas". E, infelizmente, o ronco / respiração geralmente é irregular o suficiente para que uma autocorrelação simples ou um esquema de temporização de intervalo semelhante dificilmente ajude muito. (E é realmente provável que, em alguns casos, o ruído seja mais regular do que a respiração.)
Então, existem alguns truques que estou perdendo para descobrir quando não há sinal? Parece que sou contra um lugar difícil aqui, dado que o "sinal" é tão barulhento para começar.
(E talvez isso esteja relacionado a outro problema que estou tendo: estranhamente, não consigo medir com precisão (ou até aproximadamente)) o nível do sinal, mesmo quando bastante alto. Como preciso usar médias e proporções para detectar o sinal de qualquer maneira, as informações de nível são perdidas. Estou procurando alguns truques para reconstituí-las.)
Técnica básica
(Para Yoda)
O sinal de áudio é amostrado (geralmente em 8000Hz, por várias razões) e, em seguida, FFTed em 1024 blocos. (Nas minhas experiências, os filtros de Hamming e os blocos sobrepostos parecem ter pouco efeito, embora possam ser revistos mais tarde.)
O FFT é dividido em "bandas" (atualmente 5, com um tamanho ligeiramente inclinado para colocar mais detalhes na extremidade baixa) e a "diferença espectral" e o nível de cada banda são somados. As médias de longo prazo dos valores de pico limitado são usadas como "limites" e outros ajustes de polarização são usados para manter uma taxa de "acima do limite" de aproximadamente 20%.
Cada valor "acima do limite" recebe um peso de 1 (abaixo do limite recebe um peso de 0), mas esse peso é ajustado pela aparente "variabilidade" (aproximadamente 2Hz) na banda, para dar mais peso às bandas que carregam sinal mais aparente.
Os pesos das bandas são somados e, em seguida, os pesos somados dos blocos subsequentes são somados por cerca de um segundo para produzir uma "pontuação" corrente. Isso é novamente comparado a um limite médio de execução (mais várias heurísticas) para detectar o início / deslocamento do ronco.
Atualizar
De repente, ocorreu-me que, se meu algoritmo mantiver efetivamente um sinal de nível constante (por meu problema de nível de sinal), a maneira de medir efetivamente o SNR é medindo o ruído quando não há sinal.
Convenientemente, os roncos são intermitentes, com muito "ar morto" no meio. E eu já estou detectando os envelopes roncos. Portanto, qualquer coisa fora do envelope (entre o final de um ronco e o início do próximo) é presumivelmente ruído! Isso eu posso (com algum grau modesto de precisão / repetibilidade) medir. (Foram necessárias três tentativas para criar um algoritmo meio decente, é claro - a realidade nunca corresponde à teoria.)
Portanto, ainda não tenho a resposta completa, mas fiz progressos.
(Embora a técnica acima me dê um proxy bastante bom para o SNR, ainda estou tendo problemas para estimar o nível real do sinal. Minhas indicações de "nível relativo" podem estar fora da escala para uma respiração quase inaudível e mais ou menos para um barulho de janela. Preciso de algum tipo de proxy para o nível absoluto.)