martedì 11 luglio 2017

Le rane, ovvero come visualizzare uno spettrogramma in python

Qualche settimana fa ero per campi e, affascinato, ho registrato il gracidare delle rane...



Dopo il momento contemplativo uno potrebbe chiedersi... ma quante rane ci sono in questo audio? Ovvero, quante rane stavamo ascoltando?

Il primo passo che ho pensato è fare un'analisi dello spettrogramma, tanto per capire come sono composti questi suoni.

Ma cos'è uno spettrogramma? Secondo Wikipedia, uno spettrogramma è:

Uno spettrogramma è la rappresentazione grafica dell'intensità di un suono in funzione del tempo e della frequenza o, in altre parole, è la rappresentazione grafica della funzione reale i delle variabili reali t ed f: i(t,f).

In pratica, uno spettrogramma è una rappresentazione dell'andamento in frequenza di un segnale al variare del tempo.

La cosa essenziale da capire è che spettrogramma rappresenta abbastanza bene il modo in cui viene sollecitato il nostro sistema uditivo da un suono che varia nel tempo.

Ad esempio, su wikipedia vediamo l'esempio di uno spettrogramma dei suoni vocalici "a" ed "i" pronunciati da un madrelingua italiano e relative forme d'onda

Spettrogramma dei suoni vocalici 'a' ed 'i'

Nella parte alta si vede lo spettrogramma, mentre nella parte bassa le oscillazioni sonore. Mentre la visualizzazione delle oscillazioni non ci permette di fare un'analisi qualitativa con semplicità, vedendo lo spettrogramma si può notare come nella pronuncia della vocale 'i' (rispetto ad 'a') aumentino le componenti in alta frequenza e diminuiscano quelle in bassa.

Si possono fare diverse prove divertenti con il telefonino mediante l'app Spectral View che permette di visualizzare lo spettrogramma dei suoni intercettati dal microfono. E' interessante provare a pronunciare delle parole, cantare, suonare delle note, o semplicemente stare in silenzio.

Tornando alle nostre rane,

Vediamo come realizzare uno spettrogramma con python

Cerchiamo/installiamo il package che ci serve

Cercando su google un package che fa al caso mio, ho trovato subito scipy, e in particolare la funzione spectrogram
https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.signal.spectrogram.html

Oltretutto c'è anche un bell'esempio.

Scaricando su Python 2.7 (quello dove avevo già installato numpy in precedenza)

execfile("scipy-signal-spectrogram-1.py")

verifichiamo che il package scipy/numpy funziona a dovere.

(Non) leggere il file MP3

Partiamo dunque da un file mp3 di 1' 16'' con le rane registrate, più qualche (pochi) rumori di sottofondo, registrato dal mio cell l'altra notte...
Dove si trova una libreria mp3 per leggere i dati in python e passarli a numpy? Cercando un po' tramite google non si trova niente di molto agevole (anche perché ci vogliono dei codec proprietari, da quanto ho capito) perciò è più semplice muoversi per vie alternative.

Ad esempio, si possono convertire il file nel formato WAV. Cercando online, trovo un convertitore molto buono e semplice http://online-audio-converter.com/

Si passa così da un file di mp3 di 828k ad un file wav di ben 13Mb!!!

A questo punto è possibile utilizzare la libreria wave inclusa in python, che fornisce le funzionalità di base per leggere e scrivere i file wav.


Prime visualizzazioni


Visualizziamo adesso il primo grafico ottenuto utilizzando i parametri standard
f, t, Sxx = signal.spectrogram(left, framerate)plt.pcolormesh(t, f, Sxx)
ottenendo questo risultato:




poco dettagli e poco entusiasmante.. si intravede comunque una specie di segnale ritmico, con una variazione all'inizio (parlato) che potrebbe benissimo essere il nostro segnale. Da questo possiamo dedurre che probabilmente il macchinario di visualizzazione funziona nel complesso, ed è solo un problema di tuning.

Se infatti, invece di visualizzare la funzione Sxx, passiamo ad una visualizzazione logaritmica otteniamo una visualizzazione con un bel numero di dettagli. Per migliorare ulteriormente la visualizzazione ci concentriamo sulla banda di frequenze più ristretta dei 20KHz di default (cioè quella indotta dal campionamento):
lSxx=np.log(Sxx+1) f8 = f[f<=8000]lS8 = lSxx[f<=8000,:]plt.pcolormesh(t, f8, lS8)
Otteniamo un bel grafico


che ci mostra come il grafico che avevamo ottenuto originariamente mostrasse solo la punta dell'iceberg...
Adesso possiamo associare con una certa agevolezza le "parole" e le pause del canto delle rane (che si sentono nell'audio) al ritmo che si vede nel grafico.


Perfezioniamo la visualizzazione

Possiamo migliorare ulteriormente la visualizzazione dell'audio impostando anche le frequenze (asse delle ordinate) su una scala logaritmica. In questa maniera vengono discriminate meglio le basse frequenze e compresse le alte, ottenendo una visualizzazione che rispecchia maggiormente la sensibilità auditiva.




A questo punto, ci semplifichiamo il compito di far corrispondere quello che vediamo a quello che udiamo nel file audio.

Provando ad associare le singole tipologie di versi (ce ne sono almeno due: uno più prolungato che passa da una alta frequenza a una bassa, ed il classico "cra") Vediamo che, mentre con il primo grafico non riuscivamo, aumentando la capacità di discriminazione del grafico mediante la rappresentazione logaritmica della frequenza, riusciamo a separare che separerebbero meglio i due tipi di suono. Infatti uno è prevalentemente in alta frequenza (anche se poi va in bassa), l'altro in bassa.

NOTA: Possiamo esprimere matematicamente il concetto dicendo che il nostro segnale è esprimibile come una somma
Sig_tot = H_0 * Sum(sigma(t-tn)) + H_1*Sum(sigma(t-tn)) +  N(t)
Dove H_0 ed H_1 sono le forme dei due versi (quello prolungato ed il "cra") che si ripetono nel in instanti diversi, più i rumori di fondo.

Ascoltando (e guardando) osserviamo che tra i secondi 25 e 27 abbiamo una coppia di suoni lungo-corto che ci potrebbero essere utili come template per costruire un sistema di pattern recognition.



Possiamo inoltre osservare che durante l’intervallo di silenzio che precede la coppia lungo-corto (24s-25.5s) la componente sonora compresa tra i 100 e i 200Hz non si attenua. Infatti ascoltando con un po’ di attenzione il silenzio si sente in sottofondo il suono delle cicale. Anche questo è un suono aggiuntivo che non ci interessa.



Ora che abbiamo trovato il modo di visualizzare il segnale audio, potremmo anche pensare di cercare il modo di recuperare i singoli versi, mediante tecniche opportune.
La procedura vista fino a qui può essere adattata per visualizzare un qualsiasi canto animale, per esempio quello degli uccelli. Nel caso dell'usignolo vedremmo anche le variazioni di intonazione.


Quindi proseguendo...

Pattern recognition https://www.toptal.com/machine-learning/machine-learning-theory-an-introductory-primer

Sarebbero da provare anche le librerie Friture per l’analisi, audiere per ascoltare i samples identificati.
In generale, c’è una collezione di librerie (comprese quelle di feature extraction,utili per il machine learning) qui: https://wiki.python.org/moin/PythonInMusic


Nessun commento:

Posta un commento

Archivio blog