UNIVERSITÀ POLITECNICA DELLE MARCHE FACOLTÀ DI INGEGNERIA Corso di Laurea Specialistica in Ingegneria delle Telecomunicazioni Algoritmi per Applicazioni Multimediali Implementazione in Nu-Tech di un VAD in tempo reale basato sulle statistiche di ordine superiore e sull’algoritmo EM Online Titolare del corso: Chiar.mo Prof. FRANCESCO PIAZZA Tesina di: Relatore: Giovanni Pelliccioni Marco Malatesta Prof. STEFANO SQUARTINI Anno Accademico 2008-2009 Abstract In questo lavoro è stato studiato e implementato un nuovo metodo per la realizzazione di un Rilevatore di Attività Vocale (Voice Activity Detection, VAD) in tempo reale. Il lavoro deriva dall’analisi proposta nell’articolo Voice Activity Detection Based on High Order Statistics and Online EM Algorithm [1] il quale viene presentato, integrato con nozioni teoriche e ampliato nella parte riguardante la decisione nel capitolo 1 e 2. Il metodo proposto è basato su un parametro denominato caratteristica (feature), ricavato dalle Statistiche di Ordine Superiore (High Order Statistics, HOS) e, per migliorare la sua robustezza ai rumori non gaussiani, dai picchi di autocorrelazione normalizzata. La caratteristica è anche finalizzata alla distinzione tra il segnale vocale in campo lontano e in campo vicino, ovvero il parlatore situato rispettivamente lontano e vicino al microfono. A differenza dei classici approcci VAD, questo non si basa esclusivamente sul livello di energia. La classificazione tra segnale vocale e ciò che è considerato rumore, tra cui il parlato in campo lontano, è incentrata su una modifica dell’algoritmo EM affinché sia utilizzabile in tempo reale (EM Online). È stato aggiunto un criterio di decisione per integrare lo studio presentato dagli autori dell’articolo al fine di ottenere un’implementazione del VAD più efficiente. Vengono forniti e confrontati in MATLAB e in C, sfruttando la piattaforma NuTech, i risultati ottenuti dalle implementazioni dell’algoritmo. Indice INDICE ........................................................................................................................................................3 CAPITOLO 1 ..............................................................................................................................................5 INTRODUZIONE ......................................................................................................................................5 1.1 RILEVATORE DI ATTIVITÀ VOCALE ..................................................................................................5 1.2 PRESENTAZIONE DEL METODO ........................................................................................................6 CAPITOLO 2 ..............................................................................................................................................8 STRUTTURA DEL VAD BASATO SULLE STATISTICHE DI ORDINE SUPERIORE E SULL’EM ONLINE ...................................................................................................................................8 2.1 ANALISI LPC E CALCOLO DEL RESIDUO ..........................................................................................9 2.1.1 Linear Predictive Coding ......................................................................................................9 2.1.2 Calcolo del residuo LPC .....................................................................................................11 2.2 ESTRAZIONE DEL PICCO DI AUTOCORRELAZIONE ..........................................................................12 2.3 STATISTICHE DI ORDINE SUPERIORE PER LA RILEVAZIONE DEL PARLATO: LA KURTOSI ................13 2.3.1 Proprietà del segnale vocale nei casi vicino e lontano dal microfono ...............................13 2.3.2 Definizione delle Statistiche di Ordine Superiore (HOS) ...................................................15 2.3.3 La kurtosi e la forma della distribuzione ............................................................................16 2.3.4 Calcolo della feature ..........................................................................................................18 2.4 EM ONLINE...................................................................................................................................21 2.4.1 Apprendimento con variabili nascoste: l’algoritmo EM.....................................................21 2.4.2 Approccio teorico all’EM Online: apprendimento non controllato....................................24 2.4.3 Realizzazione real time dell’algoritmo EM: l’EM Online ..................................................28 2.5 RISULTATI SPERIMENTALI DELL’ARTICOLO DI RIFERIMENTO.........................................................30 2.5.1 Struttura di valutazione ......................................................................................................30 2.5.2 Valutazione su dati autoprodotti .........................................................................................31 2.5.3 Valutazione sul database CENSREC-1 ...............................................................................33 2.6 IL CUORE DEL VAD: LA DECISIONE ...............................................................................................35 CAPITOLO 3 ............................................................................................................................................45 RISULTATI SPERIMENTALI...............................................................................................................45 3.1 PARAMETRI E RISULTATI IN MATLAB .........................................................................................45 3.2 RISULTATI SULLA PIATTAFORMA NU-TECH ..................................................................................55 3.2.1 Risorse di calcolo impiegate dall’algoritmo .......................................................................60 3.3 CONFRONTO TRA MATLAB E NU-TECH ......................................................................................62 3.4 TEMPI DI CONVERGENZA DEI PARAMETRI DEL VAD .....................................................................65 3.5 PRESTAZIONI DELL’ALGORITMO VAD PER DIVERSI SNR ..............................................................70 3.5.1 Ulteriore miglioramento dell’algoritmo per bassi SNR......................................................91 CAPITOLO 4 ............................................................................................................................................96 CONCLUSIONI........................................................................................................................................96 APPENDICE .............................................................................................................................................99 LISTATI DELL’ALGORITMO .............................................................................................................99 A. B. LISTATO IN MATLAB ..................................................................................................................99 LISTATO IN C ..............................................................................................................................107 BIBLIOGRAFIA ....................................................................................................................................119 4 Capitolo 1 Introduzione 1.1 Rilevatore di attività vocale Il VAD (Voice Activity Detection) rileva automaticamente le parole dai segnali audio, è un problema classico nell’elaborazione del segnale vocale. Ad esempio, è spesso usato come un’interfaccia per il riconoscimento automatico delle parole (ASR) [2]. È stata data recentemente attenzione al problema perché l’efficacia dell’interfaccia VAD è cruciale per le prestazioni del riconoscitore vocale negli ambienti rumorosi; quando il rumore di sottofondo è alto, il numero degli errori di inserzione diventano maggiori [3], e avere un VAD immune ai rumori ambientali può significativamente ridurre il rate delle parole errate (WER: Word Error Rate). Il VAD è utile anche in altri impieghi come la codifica del parlato e il riconoscimento del parlatore. Il lavoro qui descritto tratta dell’individuazione del parlato nel contesto di interazione uomo-uomo. Questa situazione pone molte sfide principalmente perché alcune delle assunzioni solitamente fatte per l’ASR o per la codifica vocale, come il segnale che contiene parlato per la maggior parte del tempo, non sono verificate nell’interazione uomo a uomo. Perciò un algoritmo VAD deve fare i conti con questa poca densità temporale (sparsity). Inoltre quando molte persone sono coinvolte dovrebbe essere in grado di distinguere i diversi parlatori. Una soluzione a questo problema è quella di usare un array di microfoni [4]. Se fosse possibile usare registrazioni fatte con microfoni vicino ai parlatori, la distinzione tra chi indossa il microfono e le altre persone sarebbe possibile qualora si trovasse una caratteristica il cui comportamento fosse diverso a seconda che il parlato sia vicino o lontano al microfono. Il lavoro qui presentato segue proprio questo approccio. Infatti anche quando la registrazione del parlato da vicino è disponibile, la semplice strategia basata sull’energia dà risultati insoddisfacenti [5], principalmente a causa della sovrapposizione di più voci nello stesso canale e della variazione delle condizioni di rumore. 1.2 Presentazione del metodo Il metodo di cui si parla nell’articolo [1] alla base di questo lavoro contiene una nuova caratteristica incentrata sulle statistiche di alto ordine (HOS) per distinguere tra il parlato in campo lontano e in campo vicino, e uno schema di classificazione online non controllato basato sull’algoritmo Online EM (Expectation Maximization) per far fronte alla variazione della condizione di rumore e il cambiamento della proporzione del parlato. Le HOS possono essere definite dai momenti di una variabile aleatoria, e danno l’informazione che è assente dai più comuni momenti usati che sono media e varianza. L’utilizzo delle HOS per il VAD è stato suggerito per esempio in [6], la cui strategia è stata raffinata in [7]. È stato mostrato in [6] che l’HOS del residuo LPC è una funzione crescente del numero di armoniche nel segnale, usando un modello sinusoidale del parlato [8]. Siccome le HOS sono immuni al rumore gaussiano, possono essere usate per il VAD in alcuni ambienti rumorosi, come quelli gaussiani. Ad ogni modo le HOS sono sensibili ad altri tipi di rumori come i rumori transitori (i rumori che hanno un’energia elevata e sono ben localizzati nel tempo, che possono capitare per esempio quando c’è un contatto fisico con il microfono). Nell’articolo [1] le HOS sono combinate con un’altra metrica, derivata dall’autocorrelazione normalizzata, per migliorare la loro robustezza ai rumori di tipo non gaussiani. Delle HOS così migliorate sarà studiata l’efficacia nel distinguere il parlato in campo vicino e in campo lontano. Verrà proposto anche un nuovo schema per la classificazione in tempo reale attraverso l’uso dell’EM online. Questo metodo ha il vantaggio di stimare in tempo reale il rumore e il livello del parlato contemporaneamente alla classificazione, senza dipendere da uno schema di stima del SNR indipendente come quello usato nel VAD G.729B [9]. La Figura 1 visualizza lo schema a blocchi di principio presentato in [1]: come prima cosa 6 il segnale vocale viene suddiviso in frames i quali sono pre-processati e passano attraverso l’analisi LPC, il residuo della quale è usato come ingresso al resto del metodo. La kurtosi e l’autocorrelazione normalizzata, il cui picco principale viene estratto, sono calcolate, combinate tra loro e usate come ingresso dell’algoritmo EM online, che fa la classificazione e l’aggiornamento del modello simultaneamente. Speech signal LPC analysis Autocorrelation Kurtosis Peak Picking Online EM Result Figura 1. Schema dell’algoritmo proposto nell’articolo [1] 7 Capitolo 2 Struttura del VAD basato sulle Statistiche di Ordine Superiore e sull’EM Online In questo capitolo si entra nel merito della teoria e della procedura che permette la realizzazione del VAD in questione. In Figura 2 è visibile il suo schema a blocchi completo, cioè con la parte relativa alla decisione aggiunta con questo lavoro. Concettualmente il VAD può essere suddiviso in 5 grandi sezioni: • l’analisi LPC per il calcolo del residuo; • l’autocorrelazione del residuo LPC per l’estrazione del picco; • il calcolo della kurtosi del residuo LPC e la feature; • l’algoritmo EM Online; • la decisione. Speech signal LPC analysis Autocorrelation Kurtosis Peak picking Online EM Decision VAD Figura 2. Schema a blocchi completo del VAD. 2.1 Analisi LPC e calcolo del residuo 2.1.1 Linear Predictive Coding La codifica di predizione lineare (Linear Predictive Coding) è un efficiente e pratico metodo per ottenere voce artificiale. La sua efficienza è dovuta alla velocità dell’algoritmo di analisi e al basso requisito di banda per i segnali codificati. La sua efficacia è legata all’intelligibilità del segnale vocale decodificato. L'idea alla base dell'analisi predittiva è che un campione di parlato è rappresentabile come combinazione lineare dei campioni ad esso precedenti, ovvero: 1 ̂ 2 ‐ rappresenta il campione vero all’ n-esima posizione, mentre ̂ dove 1 rappresenta la sua stima, combinazione lineare dei campioni precedenti. Viene poi indicato con l’errore di predizione corrispondente ad un predittore di ordine P e cioè realizzato con P coefficienti: ‐ ̂ La determinazione dei coefficienti 2 viene fatta in modo ottimo, minimizzando il valore atteso del quadrato dell’errore: | | ‐ ‐ 3 quindi basterà minimizzare rispetto ad essi il valore dell’errore quadratico medio e dunque imporre che | | 2 1, … , ‐ : 1 ‐ ‐ 2 ‐ 0 4 Queste equazioni corrispondono alla condizione di ortogonalità. Se l’errore di predizione è minimo, deve essere incorrelato con i dati utilizzati per calcolarlo; infatti, se ci fosse correlazione, si contraddirebbe l’ipotesi che l’errore sia minimo, in quanto i dati potrebbero essere utilizzati meglio per ridurre ancora di più l’errore. Le equazioni (4) vengono dette equazioni di Yule-Walker, dai ricercatori che per primi le utilizzarono, e potrebbero essere riscritte in questo modo: 9 ‐ dove, ignorando l’operatore di coniugio essendo con 0, 1, … , 5 reale, si ha che: 0, … , –1 6 è l’autocorrelazione del segnale. Le equazioni di Yule-Walker possono essere viste anche in forma matriciale, considerando la simmetria dell’autocorrelazione di un segnale reale: 7 Per risolvere questo sistema, si usa solitamente un algoritmo dai costi computazionali molto contenuti, l’algoritmo di Levinson-Durbin [22]. L’analisi spettrale autoregressiva fornisce un metodo per calcolare un filtro tutti poli che, applicato ad un rumore bianco, ne sagomi lo spettro in modo da riprodurre quello della sequenza esaminata. La predizione lineare non fa altro che applicare gli stessi metodi per il procedimento inverso, ovvero sbiancare il segnale tramite un filtro a media mobile. Quindi i parametri trovati conterranno l’informazione spettrale del segnale in ingresso e, riprodotti in un filtro IIR alimentato da rumore gaussiano bianco, riporteranno al segnale precedente, a patto che l’ordine della predizione sia sufficientemente alto. In Figura 3 viene mostrato questo ragionamento, si può dimostrare che, nel caso in cui , sarà statisticamente uguale e quindi l’errore di predizione sarà bianco. È possibile quindi scrivere: ‐ dove 8 è un segnale gaussiano bianco. Ora si può passare ad analizzare l’implementazione della codifica vera e propria. Dall’equazione (2) si nota che l’errore di predizione è l’uscita di un sistema la cui funzione di trasferimento è il seguente polinomio monico: 1 ‐ 9 10 1 sn sequenza colorata sequenza bianca errore di predizione equazioni di Yule-Walker parametri del filtro Figura 3. Schema di predizione. Comparando l’equazione (9) con la (8), è possibile affermare che se il segnale vocale obbedisce esattamente al modello dell’equazione (8), allora di predizione . Così il filtro sarà un filtro inverso per il sistema di produzione del parlato, ad esempio: 10 dove g è una costante moltiplicativa opportuna. L’ipotesi principale per applicare l’analisi LPC al parlato è il fatto che questo si mantenga all’incirca stazionario per un periodo di tempo; si può dimostrare che, avendo in ingresso un segnale campionato a 8 KHz, la stazionarietà sarà mantenuta per circa 128-256 campioni, ovvero 16-32 ms. Quindi, una volta segmentato il segnale in intervalli verrà applicata a ciascun frame un’analisi di predizione lineare, con un numero di coefficienti solitamente variabile tra 8 e 14, lo standard LPC-10 ne utilizza 10 poiché per il tratto vocale umano P=10 è una buona stima dei gradi di libertà che sono necessari per rappresentare la maggior parte delle espressioni. 2.1.2 Calcolo del residuo LPC Nella trattazione attuale, seguendo quanto fatto nell’articolo [1], viene utilizzato come segnale d’ingresso al VAD un segnale vocale campionato a 8KHz. Come mostrato in Figura 4, questo viene elaborato in frames da 256 campioni (32 ms) con un 11 overlap del 50%. Su ogni frame si effettua l’analisi LPC descritta in generale nel paragrafo precedente con N=P. Vengono restituiti i coefficienti che permettono di costituire il seguente filtro A’(z) che sintetizza la voce: ‐ . 11 Infatti per continuare con lo studio deve essere calcolato il residuo eseguendo la differenza tra il segnale originale e quello artificiale. Si ricostruisce il segnale sintetico ponendo in ingresso al filtro i 256 campioni del segnale originale; essi rappresentano la miglior eccitazione per il filtro di sintesi. frame vocale (256 campioni) frame ricostruito equazioni di Yule-Walker + - ∑ residuo LPC parametri del filtro Figura 4. Schema del blocco LPC analysis. 2.2 Estrazione del picco di autocorrelazione Il residuo LPC segue due percorsi paralleli, uno di questi è il calcolo della sua autocorrelazione normalizzata con in cascata l’estrazione del picco. 1 Infatti l’autocorrelazione normalizzata, 1 0 2 , fatta sui N=256 campioni di residuo, fornisce valori compresi tra -1 e 1, ove 1 è il massimo ottenuto per un ritardo k nullo. 12 Ai fini dell’algoritmo il picco significativo non è quello a ritardo nullo, ma quello più elevato tra tutti gli altri. Questo picco, denominato mx, verrà prelevato e successivamente abbinato ad un altro parametro del sistema per proseguire nello studio del VAD. 2.3 Statistiche di Ordine Superiore per la rilevazione del parlato: la kurtosi 2.3.1 Proprietà del segnale vocale nei casi vicino e lontano dal microfono Molte caratteristiche sono state proposte per il VAD, ad esempio l’energia, l’autocorrelazione, i picchi di cepstrum [11], e MFCC [12]. L’obiettivo è trovare una caratteristica la cui distribuzione fondamentale è diversa per il segnale vocale e per quello non vocale. Inoltre l’obiettivo è quello di rilevare solamente il parlato in campo vicino perciò la caratteristica deve essere anche in grado di distinguere tra campo vicino e campo lontano. La proprietà più ovvia per individuare il parlato in campo vicino e in campo lontano sarebbe l’energia, ma questa non si comporta come ci si aspetterebbe; le principali cause di deterioramento delle prestazioni negli algoritmi che si basano semplicemente sull’energia si identificano [5] nella sovrapposizione vocale in un canale e nelle variazioni delle condizioni di rumore. Inoltre, come notato in [13], la normalizzazione della caratteristica per quanto riguarda l’energia è molto importante per il VAD online. Per queste ragioni ci si concentra sulle caratteristiche indipendenti dall’energia. Si riporta in Figura 5 il residuo LPC del parlato in campo vicino e in campo lontano, poiché è noto essere legato con l’eccitazione glottale. Il segnale è stato registrato con due microfoni, uno in campo vicino e l’altro in campo lontano, e viene mostrato l’estratto da entrambi i microfoni sincronizzato nel tempo. In entrambi i casi, l’inviluppo spettrale (colonna in mezzo) è simile, e gli impulsi corrispondenti alle variazioni del flusso d’aria così come la loro periodicità sono visibili nel residuo LPC (colonna a destra). Ma nel caso del parlato in campo vicino, il residuo LPC non è 13 relativamente disturbato dal rumore e gli impulsi hanno un’ampiezza molto più forte sulla media. Così, nel parlato in campo vicino, l’ampiezza del segnale x(t) è o fuori il range [-σ, σ] o circa 0 (ad esempio | | ). Nell’altro caso, per il parlato in campo lontano, l’ampiezza è più probabile che sia nell’intorno di σ (ad esempio| | ). Figura 5. Paragone tra parlato lontano (in alto) e vicino (in basso). Le due registrazioni appartengono allo stesso segnale. La colonna a sinistra mostra lo spettrogramma di circa un secondo di segnale, quella in mezzo mostra lo spettro e quella a destra riporta il residuo LPC di un particolare estratto della registrazione. La linea tratteggiata rappresenta la deviazione standard del segnale. Ci sono diverse spiegazioni per questa differenza: primo perché l’SNR è più basso per voci distanti e in quanto tale è incluso nel rumore, e inoltre, a causa della riverberazione, la distribuzione del suo residuo LPC è più somigliante ad una gaussiana. Un’altra possibile spiegazione per questa differenza potrebbe essere l’effetto di prossimità del microfono. La maggior parte dei microfoni per il campo vicino sono direzionali, e poiché quelli direzionali usano due diaframmi, ciò causa l’effetto di prossimità di questi microfoni. Questo effetto aumenta lo spettro di bassa intensità del segnale ricevuto per i segnali vicini (pochi centimetri distanti dal microfono). In conclusione, la distribuzione del residuo LPC è più probabile che abbia valori estremi (lontani dalla media, o vicini alla media) nel caso di campo vicino piuttosto che nel caso di campo lontano. Seguendo questa proprietà, la distinzione tra parlato in campo vicino e in campo lontano si riduce alla distinzione tra una distribuzione con un picco e coda alta e una distribuzione con un elevato medio-range. La kurtosi, che è una delle HOS, è una statistica standard usata per questo intento. 14 2.3.2 Definizione delle Statistiche di Ordine Superiore (HOS) Come accennato nel paragrafo 1.2, per stimare la kurtosi, che è uno dei pilastri della procedura per la realizzazione del VAD, viene utilizzato il residuo LPC dal quale la si ricava attraverso media e varianza. Prima di approfondire l’analisi della kurtosi però, viene definita la famiglia da cui deriva cioè le High Order Statistics. Le HOS, anche chiamate cumulanti, di variabili casuali X sono definite dalla funzione generatrice dei cumulanti Ψ: Φ t ! 12 cioè, la funzione generatrice dei cumulanti è definita come il logaritmo della funzione generatrice dei momenti Φ, e il cumulante di ordine n, Kn, è l’n-esimo coefficiente dell’espansione di Taylor diviso per n!. C’è una relazione diretta tra i cumulanti di una variabile casuale X e i suoi momenti centrali. Per i primi quattro cumulanti queste relazioni sono: 0 13 14 15 3 16 Il cumulante di ordine 2 è semplicemente la varianza. Le statistiche di alto ordine più comuni, la skewness sX e la kurtosi kX, sono definite come la versione normalizzata dei cumulanti rispettivamente di ordine 3 e 4, con il fattore di normalizzazione σn, dove σ è la deviazione standard e n l’ordine delle statistiche: ⁄ ⁄ ⁄ ⁄ 17 3 18 Un motivo per questa definizione è la proprietà di additività per le variabili casuali indipendenti, che è una diretta conseguenza della proprietà della funzione generatrice dei momenti per le variabili casuali indipendenti. Un’altra diretta conseguenza è che tutti i cumulanti di ordine n ≥ 3 sono 0 per le variabili casuali gaussiane, poiché la funzione generatrice dei cumulanti di una variabile gaussiana è un polinomio di ordine 2. 15 2.3.3 La kurtosi e la forma della distribuzione La kurtosi è stata usata a lungo in letteratura statistica come una misura di nongaussianeità, come una misura di forma a picchi o a code per una variabile casuale [14], [15]. Infatti la kurtosi nel linguaggio della statistica indica un allontanamento dalla normalità distributiva, rispetto alla quale si verifica un andamento più piatto e a code ampie (distribuzione platicurtica) o un andamento più appuntito e con code piccole (distribuzione leptocurtica). Una distribuzione con la stessa kurtosi della distribuzione normale è chiamata mesocurtica. Si ricorda che la più nota misura della kurtosi è l'indice di Fisher (19), ottenuto facendo il rapporto tra il momento centrale di ordine 4 e la varianza al quadrato (o deviazione standard alla quarta). Il valore della kurtosi kx corrispondente alla distribuzione normale (gaussiana) è 0 qualora si utilizzi, come nell’articolo [1] e di conseguenza anche in questo lavoro, la formula (20) in cui si sottrae 3 all’indice di Fisher. 4 4 19 3 20 Schematicamente, se il coefficiente di kurtosi è: • > 0 la curva si definisce leptocurtica, cioè più "appuntita" di una normale. • < 0 la curva si definisce platicurtica, cioè più "piatta" di una normale. • = 0 la curva si definisce normocurtica o mesocurtica, cioè "piatta" come una normale. Un esempio grafico è dato dalla Figura 6 in cui sono rappresentate due distribuzioni con la stessa varianza, con approssimativamente la stessa asimmetria ma con differenze marcate nell'indice di kurtosi. Figura 6. Esempio grafico dei due tipi di distribuzione: leptocurtica e platicurtica. 16 Dato che il primo e il secondo momento di una variabile casuale X possono essere visti semplicemente come un parametro di traslazione e di scala, rispettivamente, le HOS contengono informazione sulla forma della distribuzione. La kurtosi misura sia il picco che la coda delle variabili casuali, e entrambe queste caratteristiche devono essere tenute in considerazione quando si confrontano due variabili casuali [14]. Più formalmente, per due variabili casuali simmetriche X e Y di uguale media e varianza, se ci sono a e b tali che ,| | | | , 21 mentre , | | , 22 allora il momento di quarto ordine di X è più alto di quello di Y (vedi [15] per una dimostrazione). Presa una variabile casuale gaussiana come riferimento, un esempio di distribuzione che ha code più pesanti e che è più appuntita rispetto a una gaussiana è la distribuzione di Laplace, come raffigurato in Figura 7. Laddove una gaussiana ha una kurtosi uguale a 0, la distribuzione di Laplace ha una kurtosi uguale a 3 (sia la distribuzione di Laplace che la gaussiana hanno una kurtosi che è indipendente dai loro parametri). Figura 7. Paragone tra la distribuzione più appuntita e con coda più pesante (Laplace) rispetto alla gaussiana. Entrambe hanno stessa media(0) e varianza(1), sono simmetriche, ma Laplace ha kurtosi 3 rispetto a 0 della gaussiana. L’area riempita sottolinea i ranges in cui i valori sono più probabili per Laplace. 17 2.3.4 Calcolo della feature Seguendo le discussioni sopra, ci si aspetta che la kurtosi sia un candidato in grado di distinguere tra parlato in campo vicino e in campo lontano. Per l’esempio in Figura 5 la kurtosi è 15,4 per il parlato in campo vicino, e 0.4 per il parlato in campo lontano. Ad ogni modo, come già notato in [6], usare direttamente le HOS per il VAD non è efficace, per parecchie ragioni; gli stimatori standard per la kurtosi, basati su uno stimatore a campione di momenti, convergono lentamente sul vero valore e sono sensibili alle deviazioni estreme; inoltre, i rumori non-gaussiani potrebbero non avere un basso valore di kurtosi. Infatti, i rumori tipici in condizioni di campo vicino come i rumori di contatto, che sono di natura altamente transitoria, hanno una kurtosi grande. Figura 8. Campione di registrazione autoprodotta del segnale vocale con rumore naturale. Lo spettrogramma(in alto), l’energia(la seconda), la log-kurtosi(la terza) e la caratteristica proposta(la quarta). Le aree evidenziate sono parlato che deve essere individuato. Questo è osservato in Figura 8 la quale rappresenta un estratto di 37 secondi registrati con un microfono in campo vicino: il segnale contiene per lo più parlato che inizia 18 attorno ai 17 secondi, ma tutto l’inizio del segnale contiene voce di sottofondo, le cui basse linee spettrali di frequenza possono essere viste sullo spettrogramma. Lo spettrogramma contiene anche rumori transienti attorno ai 9-10 secondi, che sono visibili sia sullo spettrogramma che sul grafico dell’energia. La Figura 8 mostra inoltre che la kurtosi si comporta in maniera differente per il parlato in campo lontano e quello in campo vicino: è principalmente a basso valore e stabile per il parlato lontano, invece ha alti valori per il parlato vicino. Comunque la kurtosi ha alcuni spikes, in particolare per i rumori transienti attorno ai 9 secondi. Per migliorare la proprietà sopra, viene proposto un metodo per potenziare la kurtosi contro i rumori transienti lasciando inalterato il suo comportamento desiderato per distinguere il parlato in campo lontano dal parlato in campo vicino; questa viene combinata con il picco di autocorrelazione normalizzata. L’autocorrelazione è un buon segnale per indicare il tono, ed è abbastanza robusto ai rumori transitori; per queste ragioni è stato spesso usato per il VAD (per esempio in [16]). Per migliorare l’immunità alla variazione dell’energia del segnale si usa l’autocorrelazione normalizzata a[k] per un frame X = (xt) = {x0 , … , xN-1} data dalle seguente formula: 1 1 0 23 2 Per segnali periodici in T campioni l’autocorrelazione ha massimi per ritardi multipli di T. Si rileva un picco se il suo valore è molto più grande dei suoi vicini più prossimi da entrambi i lati (scartando il primo picco a 0, che è sempre uguale a 1 per definizione di autocorrelazione normalizzata). A causa del processo di normalizzazione, i picchi per rumori a bassa energia possono sembrare avere uno spettro marcato (un esempio di tale rumore è il rumore del motore). Inoltre non può essere usato da solo per rilevare le parole del parlatore principale dalle voci di sottofondo. Comunque, in questo studio, il motivo per cui si usa l’autocorrelazione è che i suoi picchi hanno una bassa ampiezza per i rumori transitori, i quali sono i rumori più problematici quando si usano le HOS. Dunque la combinazione del picco di autocorrelazione mx con la kurtosi kx del residuo LPC permette di ottenere la nuova caratteristica (feature) fx come segue: log 1 24 19 Si impiega il logaritmo della kurtosi per dare un comportamento più gaussiano alla caratteristica, questo sarà più utile per la classificazione, e inoltre compensa alti valori che possono capitare per frames in campo vicino di voci forti. La kurtosi migliorata è mostrata in Figura 8, dove il miglioramento sulla kurtosi originale è evidente. Infatti ha ancora bassi valori per il parlato in campo lontano ed è più stabile per frames rumorosi. Un altro esempio, preso dal set di dati CENSREC-1, è mostrato in Figura 9, dove è possibile osservare le stesse caratteristiche. In particolare si nota che la kurtosi migliorata è più robusta ai rumori che si manifestano nei primi 5 secondi (essi corrispondono a rumori di passi di qualcuno che cammina); il miglioramento confrontato con la kurtosi semplice è anche evidente sulla seconda e sulla quinta sezione del parlato. Figura 9. Campione di segnale vocale da CENSREC-1 (alto SNR). Lo spettrogramma(in alto), l’energia(la seconda), la log-kurtosi(la terza) e la caratteristica proposta(la quarta). 20 2.4 EM Online 2.4.1 Apprendimento con variabili nascoste: l’algoritmo EM Reti Bayesiane, variabili latenti, miscugli gaussiani, algoritmo EM Una rete bayesiana è un modo di rappresentare un problema attraverso ragionamenti probabilistici, essa modella relazioni tra i vari nodi della rete attraverso distribuzioni congiunte di probabilità. Molti problemi reali hanno variabili nascoste, talvolta chiamate anche variabili latenti, che non sono osservabili nei dati, ma si possono apprendere. Ad esempio, le cartelle mediche spesso includono i sintomi osservati, le terapie applicate e talvolta i risultati ottenuti, ma molto raramente è inclusa anche l’osservazione diretta della malattia stessa. 2 2 2 2 Dieta Fumo 2 2 Esercizio Fumo Dieta Esercizio Sintomo3 54 Sintomo1 Sintomo2 Sintomo3 Malattia Cardiaca 6 Sintomo1 6 6 Sintomo2 486 162 (a) (b) Figura 10. Esempio di modello diagnostico immaginario per le malattie cardiache. Se la malattia non è osservabile, perché non costruire un modello che non tenga conto di essa? Si può fare il seguente esempio per chiarire il concetto: nella Figura 10 viene riportato un piccolo modello diagnostico immaginario per le malattie cardiache. Ci sono tre fattori di predisposizione alla malattia osservabili e tre sintomi osservabili. Si suppone che ogni variabile possa assumere 3 possibili valori: nessuno, moderato e severo. Rimuovere la variabile nascosta dalla rete (a) dà come risultato la rete (b); 21 appare evidente che il numero di parametri aumenta drasticamente. Così le variabili latenti possono ridurre drasticamente il numero di parametri necessari per specificare una rete bayesiana. Questo a sua volta riduce drasticamente le quantità di dati necessari per apprendere i parametri. Le variabili nascoste sono importanti, ma effettivamente complicano l’apprendimento. Nella Figura 10(a) ad esempio, non è chiaro come apprendere la distribuzione condizionata di Malattia Cardiaca dati i suoi genitori, perché non se ne conoscono i valori nei vari casi; lo stesso problema si ha per l’apprendimento delle distribuzioni dei sintomi. L’algoritmo Expectation - Maximization, o EM, risolve questo problema in un modo molto generale. Esso è usato in una grande varietà di problemi di apprendimento. Clustering non supervisionato: apprendere miscugli di gaussiane Il problema del clustering non supervisionato consiste nel discernere categorie multiple in una collezione di oggetti. Il problema è non supervisionato perché le etichette delle categorie non sono date. Ad esempio si può ipotizzare di registrare gli spettri di centomila stelle: è possibile chiedersi se tali spettri identificano tipi diversi di stelle, e se fosse così, quanti sono e quali sono le loro caratteristiche. Sono conosciuti da tutti i termini quali “gigante rossa” e “nana bianca”, ma le stelle non hanno un cartellino identificativo; per distinguere tali categorie gli astronomi hanno dovuto eseguire un clustering non supervisionato. Il clustering non supervisionato parte dai dati. Dall’insieme di dati si deve cercare di capire quale distribuzione di probabilità potrebbe aver generato quei dati. Il clustering presume che i dati siano generati da una distribuzione miscuglio P. Tale distribuzione ha k componenti, ognuno dei quali è una distribuzione. Un dato si ottiene scegliendo per prima cosa uno dei componenti e quindi generando un campione da esso. Sia C la variabile casuale che denota il componente con valori 1,…,k; la distribuzione miscuglio è data da | 25 22 in cui x si riferisce ai valori degli attributi per un determinato dato. Nel caso di dati continui, una scelta naturale per le distribuzioni dei componenti è la gaussiana multivariata, che genera la famiglia di distribuzioni nota come miscuglio di gaussiane. I parametri di un miscuglio di gaussiane sono (il peso di ogni (la media di ogni componente) e Σ componente), (la covarianza di ogni componente). Il problema del clustering non supervisionato quindi è ricostruire un modello a miscuglio partendo dai dati. Se si conoscesse il componente che genera ogni dato sarebbe facile ricostruire le gaussiane costituenti il miscuglio: basterebbe selezionare tutti i dati derivati da ogni componente e adattare i parametri della distribuzione. Sapendo i parametri di ogni componente si potrebbe, almeno in senso probabilistico, assegnare ogni dato ad un preciso componente. Il problema sta nel fatto che non si conoscono né gli assegnamenti né i parametri. L’idea base dell’EM è fingere di conoscere i parametri del modello e quindi inferire la probabilità che ogni dato appartenga a ogni componente. Fatto ciò è possibile riadattare ciascun componente all’intero insieme di dati, dopo aver pesato ogni punto in base alla probabilità che esso appartenga effettivamente a tale componente. Il processo itera fino alla convergenza. Essenzialmente quello che si fa è “completare” i dati inferendo distribuzioni di probabilità sulle variabili nascoste (il componente a cui appartiene ogni dato) in base al modello corrente. Per un miscuglio di gaussiane si inizializzano arbitrariamente i parametri del modello a miscuglio, dopodiché si iterano i seguenti passi. 1. , la probabilità che il sia stato generato dal componente i. Per la regola di Bayes, dato | nel punto . Il termine | è semplicemente la probabilità della i-esima gaussiana e il termine esima gaussiana. Viene definito 2. | Passo E: viene calcolata la probabilità è il peso della i- . Passo M: si calcola la nuova media, covarianza e peso dei componenti come segue: 23 Σ 26 Il passo E da expectation, può essere visto come il calcolo dei valori attesi indicatori nascosti , dove ogni vale 1 se il dato degli è stato generato dall’i-esimo componente e 0 in caso contrario. Il passo M da maximization, calcola i nuovi valori dei parametri che massimizzano la verosimiglianza logaritmica dei dati in base ai valori attesi degli indicatori nascosti. 2.4.2 Approccio teorico controllato all’EM Online: apprendimento non Alcuni algoritmi VAD fanno la soglia della caratteristica, con una soglia il cui valore è generalmente calcolato dal livello di rumore di sottofondo stimato; la classificazione del frame, parlato o non-parlato, è poi convertita nei limiti del segnale vocale attraverso una macchina-stato (anche chiamata hangover); per un algoritmo VAD non controllato è la via più diretta per la classificazione (per esempio [17]). Qui viene proposto uno schema di classificazione non controllata ma senza basarsi direttamente su una soglia, la quale richiederebbe una stima del livello di rumore. Supponendo che ogni classe (parlato e non parlato) abbia una distribuzione probabilistica, un’ottima decisione potrebbe essere quella di scegliere la classe che massimizza p(class|X); questa è una classificazione di massimo a posteriori (MAP). Qui p(X|class) è modellata come un densità parametrica p(.;θ), e si prova a stimare il parametro stabilito θ. Il metodo che si usa è un raggruppamento parametrico, come rappresentato in Figura 11. Scegliendo una distribuzione gaussiana per p(.;θ), il modello è una semplice mescolanza binaria di gaussiane, dove ogni componente della mescolanza rappresenta una classe (una per il parlato, una per il non-parlato). 24 L’algoritmo di massimizzazione del valore atteso (EM) [18] stima modelli parametrici con variabili latenti basato sul principio di massima verosimiglianza. In questo caso, la variabile latente è la classe di appartenenza C. Figura 11. Istogramma della kurtosi migliorata per lo stesso estratto di Figura 8 e un semplice modello di miscuglio a 2 componenti stimato dall’algoritmo EM standard (la variabile latente ha due stati, parlato o non parlato). L’algoritmo EM è un algoritmo iterativo e ogni iterazione i richiede due passi: il passo E, dove il valore atteso condizionato del logaritmo della probabilità per il dato completo (X,C) ottenuto dal dato osservato X è calcolato così: , ; 27 | ; e il passo M, dove J è massimizzata rispetto a θ per dare un nuovo set di parametri stimati per il passo i 28 La chiave dell’algoritmo EM è che lo schema sopra garantisce che il logaritmo della probabilità per il dato osservato X al punto θi è più alto che al punto θi-1, e che J ha una forma chiusa per un’ampia classe di modelli, inclusi i miscugli finiti dei modelli esponenziali, come i modelli di miscuglio gaussiano. Nel caso di miscugli finiti, e date T osservazioni Indipendenti e Identicamente Distribuite (IID) X = {Xt} = {X1, . . . , XT}, il calcolo di è ridotto al calcolo di | ; per tutti t e c, dove Ct è la variabile latente corrispondente a Xt e c è una scelta di appartenenza. Il nuovo 25 parametro θi può poi essere calcolato da ζ e dalle statistiche che dipendono direttamente dai dati; nel caso di modelli di miscugli gaussiani, loro sono Xt e Xt2. In altre parole (ζti, Xt, Xt2) sono Statistiche Sufficienti (SS) per θi-1. Per quanto riguarda la classificazione online, questa non può essere usata direttamente perché il passo E richiede l’intero insieme dei dati X. Per esempio, nell’EM standard, la media del componente c al passo i μi(c) è data da: 29 Invece, deve essere trovato un metodo per aggiornare μt (e altri parametri del modello) al frame t dai dati osservati Xt e dai precedenti parametri stimati θt-1. Come notato in [19], ci sono stati diversi approcci a questo problema. Viene adottato lo stesso schema proposto in [19] e [20]; le quantità di interesse per il passo E sono sostituite da un approssimazione stocastica e il passo M viene mantenuto uguale. Nell’EM online, si sostituisce ogni statistica mediata su ζ con la sua approssimazione stocastica, la quale è aggiornata ogni volta che un nuovo frame è dato in pasto all’algoritmo. Per quanto riguarda la media, la statistica ∑ rimpiazzata da è , che è aggiornato ad ogni nuovo frame: 30 1 Da notare che il suffisso i per ζ è stato tolto, mentre il passo e l’indice del frame rimangono gli stessi per l’EM online; inoltre, le statistiche approssimate ora dipendono da c tramite ζt(c). Questa approssimazione è poi inserita dentro lo stimatore della media dato dall’EM standard (equazione 29): ̂ 31 Così, invece di mediare le statistiche ζt · Xt per tutte le t in una volta, l’EM online media successivamente tra il frame corrente e il frame precedente, e il termine può essere visto come l’errore di approssimazione della procedura [21]. Le condizioni sulla sequenza γt tali che la procedura sopra converga sono date in ([19], 1 La notazione che verrà introdotta dal prossimo paragrafo, per essere più chiara ed aderente al codice, subirà le seguenti variazioni: ; ; _; . I parametri relativi al frame precedente qui indicati con t-1 saranno poi indicati con il suffisso _p. 26 [20]); una revisione più completa della teoria che sta dietro questo tipo di procedure è data in [21]. Come per lo standard EM, c’è bisogno di inizializzare l’algoritmo. Sono possibili diverse strategie. La strategia più semplice, usata anche in questo lavoro, è di inizializzare usando valori casuali; un’altra soluzione, adottata nell’articolo [1], è basata su un algoritmo k-mean per inizializzare le medie, con i pesi per una distribuzione cluster equiprobabile. Viene poi calcolata la varianza per ogni cluster. L’algoritmo kmean è eseguito su un piccolo sottoinsieme di dati per ogni segnale: il primo secondo di ogni segnale vocale elaborato. Per dare un’idea riguardo l’adattamento online dell’EM, vengono graficati in Figura 12 i parametri delle due componenti. Figura 12. Lo spettrogramma del segmento audio(la prima), la kurtosi migliorata(la seconda), le medie(la terza), le varianze(la quarta), e i pesi(la quinta) dei componenti come stimato dall’EM online (la linea tratteggiata per il parlato, la linea piena per il rumore). Sebbene le due medie abbiano un valore quasi uguale nei tre secondi iniziali, dove il parlato non è presente, è possibile osservare che il modello effettivamente si adatta al segnale quando è presente nel segnale stesso qualche voce in campo vicino. Il parlato è sempre supposto essere il componente con la media più alta. 27 Per quanto riguarda il costo computazionale, lo standard EM può essere diviso in tre parti (per ogni iterazione i): calcolare le responsabilità ζit (c), calcolare le Statistiche Sufficienti (ζit, Xt, Xt2), e aggiornare il modello a miscuglio (equazione 29 e la sua equivalente per le matrici dei pesi e della covarianza). Solo il calcolo delle SS è differente nell’EM online (equazione 30), ma la differenza è trascurabile in termini di quantità di calcolo. Il costo d’esecuzione dell’EM online su un certo insieme di dati è quindi circa uguale a quello di una iterazione dell’EM. Poiché l’EM online è un algoritmo ricorsivo, e le caratteristiche sono calcolate frame dopo frame, esso ha una latenza di un frame una volta che è stato inizializzato. 2.4.3 Realizzazione real time dell’algoritmo EM: l’EM Online Considerando il caso della trattazione in esame, occorre distinguere due classi c: una che indica il parlato e l’altra che indica il non parlato. Ognuna di esse ha una distribuzione probabilistica di verificarsi per ogni frame del segnale vocale in ingresso. Ogni frame, come detto sopra, è caratterizzato dalla sua feature fx. Come anticipato, attraverso una distribuzione di probabilità gaussiana, il modello è un semplice miscuglio binario di gaussiane (Figura 13) e il problema è quello di massimizzare tale densità a seconda della classe di appartenenza: p(Xt|classe), dove Xt è la feature stimata, è ricavata dalla distribuzione al passo precedente. Figura 13. Miscuglio binario di gaussiane derivato da uno dei file di test usato per provare l’algoritmo. 28 Essendo gaussiana, la densità è caratterizzata dai parametri media e varianza , sono proprio questi che devono essere aggiornati, quindi stimati, e massimizzati. In generale la procedura seguita dall’algoritmo può essere rappresentata dal diagramma a stati di Figura 14. P(Xt |classe=1) Classe 1 P(classe=1|fx) fx P(classe=2|fx) Classe 2 P(Xt |classe=2) Figura 14. Diagramma a stati dell’EM On-line. Per ogni valore della caratteristica fx generato dalla trama corrente esiste una probabilità di appartenere a una classe o all’altra. Per le due classi vengono generate due stime con le quali è possibile aggiornare i parametri di interesse, medie e varianze. Tutto ciò si traduce matematicamente nei passi sottostanti ricavati dal [20] pag. 413. La feature stimata è data da _ _ dove _ 32 _ è la probabilità P(classe=c|fx) espressa dal rapporto tra il valore della gaussiana considerata con i parametri relativi ad una classe, corrispondente a fx, e la somma dei valori di entrambe _ _ 33 con _ 2 , e 1 _ 1 _ 2 2 _ 2 2 34 , _ 36 dedotto dal riferimento [19] con 0.5 35 1. 29 È necessario stimare anche la probabilità _ per poter aggiornare la media e la varianza ottenendo così la probabilità stimata _ _ _ . 37 La media quindi è così calcolata: 38 . , stimato Prima di calcolare la varianza bisogna ottenere un ulteriore parametro come segue: _ _ _ , 39 a questo punto si desume la varianza: . 40 Grazie alla media e alla varianza appena ricavati si può passare allo step riguardante la decisione della classe di appartenenza, trattata in dettaglio nel paragrafo 2.6. Inoltre i parametri attuali permettono il passaggio alla successiva iterazione dell’algoritmo EM Online. 2.5 Risultati sperimentali dell’articolo di riferimento 2.5.1 Struttura di valutazione È stato valutato il metodo proposto ed è stato confrontato con diversi algoritmi. Vengono usati 2 set di prove. Un insieme di dati autoprodotti che consistono in registrazioni da vicino fatte in un luogo all’aperto. Con l’intenzione di fare un confronto, è stato anche usato il database CENSREC-1-C [10]. Per entrambi i set di prova il segnale vocale è suddiviso in frames vocali di 32 ms con un overlap di 16ms (ad esempio 256 campioni ad un rate di campionamento di 8kHz, 50% di overlap), e esattamente lo stesso algoritmo (ad esempio nessuna sintonia per il sistema hangover). Come una misura di valutazione, si usano gli errori di classificazione a livello del frame, cioè: • False Rejection Rate (FRR), definita come 30 N° di frames del parlato persi N° di frames del parlato • False Alarm Rate (FAR), definito come N° di frames del parlato non rilevati correttamente N° di frames non parlato • Global Error Rate (GER), definito come N° di frames persi quelli non rilevati correttamente N° di frames 2.5.2 Valutazione su dati autoprodotti I dati prelevati nel luogo all’aperto sono stati registrati nelle seguenti condizioni: le persone sono state dotate di cuffie equipaggiate con un microfono (headset). Parlavano con altre persone di presentazioni del poster. I dati audio sono stati registrati su un altro dispositivo embedded simile ad un PC, portato da ogni persona (il flusso del suono è stato convertito in digitale ed è stato registrato sull’hard disk del dispositivo). I dati contengono diversi tipi di rumore (aria condizionata, altre persone, auto che viaggiano sulla strada, ecc.). Il set della prova contiene circa 45 minuti di dati audio, divisi in circa 30 files di uguale lunghezza. I files sono differenti per parlatori, sesso, linguaggio (principalmente Giapponese ma anche Inglese), densità di parlato e SNR (compreso tra 10 e 25dB). Per ogni file del set di prova l’algoritmo online EM proposto è stato inizializzato con i dati del primo secondo. L’obiettivo di questa valutazione è di stabilire se il metodo proposto può adattarsi al diverso SNR e alle condizioni di bassa densità di parlato (sparsity). Il rapporto di frames vocali in questi dati varia dal 10 al 90%, con in media il 33% di parlato. Viene confrontato il metodo proposto con metodi che rimpiazzano la kurtosi migliorata con altre caratteristiche: l’energia e la kurtosi. I risultati sono riassunti nella Tabella 1. Tabella 1. Frame Error Rates per l’algoritmo proposto (prima riga), usando l’EM online sull’energia (seconda), e usando l’EM online sulla kurtosi (terza). 31 La kurtosi migliorata ottiene un significativo miglioramento di FAR e GER, mentre ha un valore leggermente peggiore di FRR rispetto all’energia. Viene anche mostrato che la kurtosi da sola non è efficace. Figura 15. Risultati dell’algoritmo VAD proposto(a sinistra) in funzione del rapporto parlato/non parlato, confrontato con il metodo basato sull’energia (a destra). Le linee tratteggiate mostrano la deviazione standard di ogni criterio, e la linea solida mostra la media su tutti i files del database. Per avere un’idea più precisa della robustezza dello schema di classificazione proposto nei confronti della sparsity, viene fornito in Figura 15 il Frame Error Rates in funzione della percentuale del parlato (ad esempio il rapporto parlato/non-parlato) per ogni file. Dal momento che il metodo proposto e il metodo basato sull’energia si comportano in modo simile per segnali dove il parlato è dominante, il FAR aumenta significativamente per l’algoritmo basato sull’energia nel caso di segnali meno densi di parlato. Inoltre la linea tratteggiata, che rappresenta la deviazione standard dell’error rate sull’insieme completo di dati, mostra che il metodo proposto è meno sensibile alla variazione della densità, perciò dà risultati più stabili. 32 Si confronta anche l’efficienza dell’EM online rispetto all’algoritmo standard EM. Entrambi usavano la kurtosi migliorata come una caratteristica. I risultati sono riassunti nella Tabella 2. Si trova che l’EM online dà prestazioni simili all’EM offline. Tabella 2. Paragone tra l’EM online e lo standard EM. 2.5.3 Valutazione sul database CENSREC-1 Con l’intenzione di fare un confronto, viene anche testato il metodo proposto su un database pubblico, il CENSREC-1 [10]. Questo database consiste di enunciazioni in Giapponese di cifre contigue rumorose. Le registrazioni sono state fatte in due tipi di ambienti rumorosi (strada e ristorante), e alto (SNR>10dB) e basso rapporto segnalerumore (-5≤SNR≤10dB). Per ognuna di queste condizioni sono disponibili le registrazioni da vicino e da lontano [10]. L’algoritmo usato è esattamente lo stesso della sezione precedente, e l’online EM è stato inizializzato con il primo secondo per ogni file del database. Per primo, i risultati delle registrazioni da vicino per molte condizioni di rumore sono date in Tabella 3. Ogni caso ha una lunghezza totale approssimativamente di 30 minuti. Dalla Tabella 3 si osserva che le figure sono quasi uguali per basso e alto SNR in entrambi gli ambienti, ristorante e strada, nel caso di registrazione da vicino. Sembra essere più importante il tipo di rumore che la condizione di SNR. Tabella 3. Frame error rates per il metodo proposto su registrazioni da vicino del CENSREC-1-C. 33 Inoltre si confronta il metodo proposto con un metodo che usa come caratteristica l’energia invece della kurtosi migliorata. I risultati sono riportati in Tabella 4, la quale conferma che la kurtosi migliorata dà prestazioni migliori rispetto all’energia. Tabella 4. Frame error rates per il metodo basato sull’energia su registrazioni da vicino del CENSREC-1C. Infine, come suggerito dagli sviluppatori del CENSREC, è mostrato un confronto con la linea base assieme alla sua ROC per registrazioni da lontano, nonostante questo metodo sia indirizzato alla condizione di parlato da vicino. La ROC è calcolata per la media tra basso e alto SNR, ed è graficata in Figura 16. Figura 16. ROC della linea base rispetto a quella del metodo proposto, in condizioni di registrazioni da lontano (mediato su basso e alto SNR). 34 La linea base usa un semplice algoritmo basato sull’energia [10]. Si può notare che questo metodo della linea base è un algoritmo offline e la classificazione è fatta a posteriori conoscendo l’intero segnale. Questo dà alla linea base un vantaggio, ad ogni modo l’algoritmo proposto supera in prestazione la linea base. 2.6 Il cuore del VAD: la decisione Dall’articolo emerge che la classe che identifica il parlato è quella a media maggiore ma non viene esplicitamente fatta menzione sul criterio di scelta frame per frame della classe. Si intuisce solamente che il VAD vero è proprio viene realizzato attraverso il confronto tra le due probabilità che si attribuiscono di volta in volta alle classi. Infatti inizialmente la strada battuta per l’implementazione è stata quella di inserire la feature nell’argomento della gaussiana calcolata con i parametri (media e varianza) attuali, cioè appena stimati, e ricavare le probabilità come descritto nella (33). Questa valutazione conduce però ad un scelta non ottima, in effetti si è verificato attraverso opportune prove che il parlato non veniva riconosciuto adeguatamente perché, nello spazio di tempo che esso occupava, la decisione tendeva ad essere troppo “frastagliata”, ovvero si presentavano, anche se non consecutivamente, numerosi frames di parlato persi che rendevano non intellegibile il discorso. Mentre per quanto riguarda il non-parlato la scelta poteva ritenersi accettabile, in quanto la maggior parte dei frames considerati non-parlato venivano correttamente riconosciuti (Figura 17). Il frastagliamento osservabile in Figura 17 è dovuto al continuo alternarsi delle probabilità delle due classi (Figura 18). Nella Figura 19 è inoltre riportato l’andamento delle medie associate al parlato (in verde) e al non-parlato (in rosso). Si è così deciso di trovare altre soluzioni che implementassero la scelta coinvolgendo i vari parametri dello studio: confrontare le probabilità delle due classi con soglie differenti (una per il parlato una per il non-parlato), confrontare la media maggiore (quella del parlato) con una soglia mobile, valutare l’andamento crescente o decrescente (che sembrava monotono) della media, della feature stimata e delle chi, perché questi andamenti corrispondono al parlato e al non-parlato anche se non in maniera monotona, 35 tutte soluzioni che avevano in comune lo stesso difetto del frastagliamento riscontrato nella decisione di riferimento. segnale vocale x (blue), feature fx (magenta), vad (black) 2 1.5 1 0.5 0 -0.5 0 10 20 30 40 50 Tempo [s] 60 Figura 17. Decisione (VAD: 1 per il parlato, 0 per il non-parlato), in nero, fatta in base al confronto tra le probabilità delle due classi su un segnale vocale (blu) con un SNR=30dB. La feature del segnale è rappresentata in magenta. feature fx (magenta), prob1(red) e prob2(green) 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 Numero iterazioni 2500 3000 3500 Figura 18. Andamento delle probabilità delle due classi, in questo caso il verde indica il parlato e il rosso il non parlato per lo stesso segnale vocale di Figura 17. In magenta la feature. 36 feature fx (magenta), media1(red) e media2(green) 2 1.5 1 0.5 0 -0.5 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 19. Andamento delle medie delle due classi, in questo caso il verde indica il parlato, essendo maggiore, e il rosso il non parlato, per lo stesso segnale vocale di Figura 17. In magenta la feature. Quindi si è cercato di agire sulla elevata variabilità della decisione stessa proponendo un metodo di scelta a maggioranza su una finestra dispari di frames, passando poi come diretta conseguenza a una scelta basata sulla media delle decisioni di ogni frame. Queste soluzioni miglioravano un po’ la variabilità del VAD ma l’intelligibilità del segnale vocale rimaneva ancora scarsa. Da qui si è tornati ad analizzare le probabilità e ad applicare ad esse una soglia (per il parlato) dopo aver effettuato un filtraggio per stabilizzarle. Questa soglia, essendo sulla probabilità, ha un range di valori compreso tra 0 e 1, dove 0 indica l’incertezza che un frame sia parlato, ovvero qualsiasi frame viene considerato parlato e quindi non viene fatta alcuna distinzione tra le due classi, e 1 indica la certezza che il frame sia parlato, tuttavia ciò è massimamente discriminante nel senso che vengono considerati parlato solo i frames di cui si è sicuri che siano parlato. Come filtro si è pensato sempre ad una media su n probabilità precedenti e la decisione veniva fatta confrontandola con una soglia opportuna. In particolare il numero n di probabilità che è stato adottato è pari a 4, ovvero si è implementato un filtro FIR di questo tipo: 37 1 2 3 ⁄4 41 si riporta in Figura 20 l’andamento dell’ampiezza della risposta in frequenza realizzata tramite il pacchetto FDATool del MATLAB. Chiaramente l’operazione di media è un filtraggio passa - basso. Il tutto ha condotto a discreti risultati rendendo meno frastagliate le probabilità (Figura 21) e di conseguenza la decisione (Figura 22), ma ancora il segnale vocale parlato rimaneva non del tutto intelligibile. Il frastagliamento comunque dipende fortemente dalla caratteristica fx che, se in una visione globale distingue bene tra parlato e non-parlato (come è possibile osservare dalle Figura 8, Figura 9 e Figura 12), è evidente che è molto variabile nella finestra temporale individuata dal parlato. Per cui risulta difficile trovare una scelta real time corretta in queste condizioni, dato che probabilità e feature sono ovviamente correlate dall’algoritmo EM online. Una buona decisione può essere ottenuta migliorando la caratteristica fx in questa maniera: nella finestra temporale che indica il parlato dovrebbero essere innalzati quei valori di fx che per ampiezza si abbassano al livello del non-parlato. Figura 20. Filtro passa - basso FIR del terzo ordine usato per mediare le probabilità. 38 feature fx (magenta), probFIR1(red) e probFIR2(green) 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 21. Andamento delle probabilità delle due classi dopo il filtraggio FIR, come sopra il verde indica il parlato e il rosso il non parlato per lo stesso segnale vocale di Figura 17. In magenta la feature. segnale x(blue), feature fx(magenta), vad(black) 2 1.5 1 0.5 0 -0.5 0 10 20 30 40 50 Tempo [s] 60 Figura 22. Decisione (VAD: 1 per il parlato, 0 per il non-parlato), in nero, fatta sulla probabilità calcolata dalla feature fx e filtrata con il FIR. Così si è iniziato a filtrare la feature dapprima con lo stesso filtro usato per le probabilità, poi con un filtro mediano, ma in entrambi i casi il VAD non era pronto, 39 ovvero era affetto da una piccola latenza che faceva perdere la parte iniziale di una frase. Il giusto compromesso tra media e prontezza è stato raggiunto con un filtro IIR. Di seguito si riportano le figure dei 3 filtri IIR testati: Figura 23. Filtro IIR del primo ordine. Figura 24. Filtro IIR del secondo ordine. 40 Figura 25. Filtro IIR del terzo ordine. I filtri riportati sono rispettivamente del primo, del secondo e del terzo ordine. Per quanto riguarda il primo filtro dall’equazione alle differenze ⁄2 1 42 è possibile ricavare la sua funzione di rete 1 1 2 1 2 1 43 . Per il secondo ordine invece yn 2 yn 2 yn 1 xn 44 2 la funzione di rete risulta essere 1 1 1 4 2 1 4 1 2 45 . Mentre per il terzo ordine 3 2 2 2 1 46 2 la funzione di rete diventa 1 1 1 4 1 2 1 8 2 1 8 3 . 47 41 feature fx(magenta) e feature migliorata fxp(cyan) 2 1.5 1 0.5 0 -0.5 0 500 1000 1500 2000 Numero iterazioni 2500 3000 3500 Figura 26. Differenza tra la feature originale(magenta) e quella filtrata con l’IIR(cyan) relativa al segnale vocale di Figura 17. Alla fine la scelta è ricaduta sul filtro IIR del terzo ordine e la differenza tra la feature originale e quella filtrata è apprezzabile in Figura 26 dove si nota la minor oscillazione della caratteristica migliorata. feature migliorata fxp(cyan), prob1(red) e prob2(green) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 Numero iterazioni 2500 3000 3500 Figura 27. Probabilità calcolate con la feature migliorata fxp e senza il filtraggio FIR. 42 È inoltre evidente il fatto che tra parlato e non parlato vi è una maggior distinzione tra i valori più alti della feature che ne indicano il non parlato e quelli più bassi che ne indicano il parlato. feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 Numero iterazioni 2500 3000 3500 Figura 28. Probabilità calcolate con la feature migliorata fxp e filtrate FIR. segnale x(blue), feature migliorata fxp(cyan), vad(black) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 Tempo [s] 60 Figura 29. Decisione (VAD: 1 per il parlato, 0 per il non-parlato), in nero, fatta sul segnale vocale di Figura 17. In cyan la caratteristica migliorata. 43 Questa nuova caratteristica, data in pasto alla decisione fatta con il filtraggio FIR delle probabilità, permette la realizzazione di un VAD con ottime prestazioni. A tal proposito si vuol far osservare in Figura 27 le probabilità calcolate con la feature migliorata fxp e senza il filtraggio FIR. In Figura 28 si può notare il miglioramento definitivo apportato alle probabilità delle due classi da entrambi i filtraggi. Infine, come si può vedere nella Figura 29, viene riportata la decisione elaborata sul file oggetto degli esempi citati. L’unica incertezza nella decisione è nella parte iniziale tra il secondo 1 e 2 in quanto l’algoritmo non ha ancora iniziato la convergenza poiché ancora non è iniziato il parlato. Proprio il tema della convergenza verrà approfondito in seguito nel paragrafo 3.4. 44 Capitolo 3 Risultati sperimentali In questo capitolo si vuole evidenziare, attraverso alcuni grafici, l’andamento di tutti i parametri e tutti i risultati dell’algoritmo esaminato. Inoltre si vogliono valutare le prestazioni relative all’algoritmo e alla sua implementazione. 3.1 Parametri e risultati in MATLAB Viene preso in esame un file wave audio standard di parlato maschile a 8KHz che è stato opportunamente modificato aggiungendo silenzi di diversa durata per ricreare le condizioni suggerite nell’articolo [1], cioè la condizione di sparsity che descriverebbe adeguatamente un segnale vocale riferito ad un individuo in una conversazione tra più persone. Al file audio è stato aggiunto rumore AWGN tale che il rapporto segnale rumore risulti di 60dB ed è stato processato come descritto nei capitoli precedenti, qui vengono riportati i vari parametri caratterizzanti l’algoritmo. La media è uno dei parametri più importanti perché indica la classe del parlato: si ribadisce infatti che il parlato è quello che ha la media maggiore. Questa viene calcolata attraverso i parametri feature stimata (X_t) e probabilità stimata (chi). I tre andamenti sono osservabili rispettivamente in Figura 30, Figura 31 e Figura 32 per il file audio descritto sopra. feature fx(magenta), mu1(red) e mu2(green) con alpha=0.9 2 1. 1 0. 0 0 500 100 150 200 250 300 350 Numero Iterazioni Figura 30. Andamento delle medie associate alle due classi per il file audio con un SNR=60dB. feature fx(magenta), Xt1(red) e Xt2(green) con alpha=0.9 2 1. 1 0. 0 0 500 100 150 200 250 300 350 Numero Iterazioni Figura 31. Andamento delle features stimate associate alle due classi per il file audio con un SNR=60dB. 46 feature fx(magenta), chi1(red) e chi2(green) con alpha=0.9 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 32. Andamento delle probabilità stimate associate alle due classi per il file audio con un SNR=60dB. feature fx(magenta), variance1(red) e variance2(green) 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 33. Andamento delle varianze associate alle due classi per il file audio con un SNR=60dB. Alpha=0.9. 47 feature fx(magenta), Xt1quadro(red) e Xt2quadro(green) 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 34. Andamento delle features quadro stimate associate alle due classi per il file audio con un SNR=60dB. Alpha=0.9. Un ulteriore importante parametro per la modellazione delle gaussiane nel miscuglio binario è la varianza, questa e il parametro feature stimata quadro (X_t_quadro) da cui si ricava sono riportate in Figura 33 e Figura 34. Si vuole fare notare ora come agisce il parametro di convergenza alpha sui parametri media, probabilità stimata e varianza. Nelle figure sopra, l’elaborazione è stata eseguita con un alpha pari a 0.9. Si può osservare come per un alpha pari a 0.6 (Figura 35, Figura 36, Figura 37) questi parametri tendono ad essere meno separati e meno stabili, di conseguenza la decisione risulta essere più variabile. Al contrario ponendo alpha = 0.98 (Figura 38, Figura 39, Figura 40) si verifica un solo distacco che tende a mantenere una maggiore separazione per tutte le iterazioni e di conseguenza c’è una maggiore stabilizzazione dei parametri. Per quanto riguarda la decisione invece occorre tener conto del parametro soglia. Infatti la soglia agisce sulla probabilità filtrata relativa al parlato e migliora l’intelligibilità del segnale vocale in presenza di rumori più elevati (più bassi SNR). Questo avviene ovviamente, essendo le due probabilità parlato/non-parlato in relazione 48 tra loro, a spese di un più che accettabile incremento di errore nel riconoscimento del non-parlato. Le prestazioni relative verranno presentate nel paragrafo 3.5 dove si confronta il VAD in condizioni di diversi SNR. feature fx(magenta), mu1(red) e mu2(green) con alpha=0.6 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 35. Andamento delle medie per alpha=0.6 per il file audio con un SNR=60dB. feature fx(magenta), chi1(red) e chi2(green) con alpha=0.6 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 36. Andamento delle probabilità stimate per alpha=0.6 per il file audio con un SNR=60dB. 49 feature fx(magenta), variance1(red) e variance2(green) con alpha=0.6 2 1. 1 0. 0 0 50 100 150 200 250 300 350 Numero Iterazioni Figura 37. Andamento delle varianze per alpha=0.6 per il file audio con un SNR=60dB. feature fx(magenta), mu1(red) e mu2(green) con alpha=0.98 2 1. 1 0. 0 0 50 100 150 200 2500 3000 3500 Numero Iterazioni Figura 38. Andamento delle medie per alpha=0.98 per il file audio con un SNR=60dB. 50 feature fx(magenta), chi1(red) e chi2(green) con alpha=0.98 2 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 39. Andamento delle probabilità stimate per alpha=0.98 per il file audio con un SNR=60dB. feature fx(magenta), variance1(red) e variance2(green) con alpha=0.98 2 1. 1 0. 0 0 50 100 150 200 2500 3000 3500 Numero Iterazioni Figura 40. Andamento delle varianze per alpha=0.98 per il file audio con un SNR=60dB. 51 Per chiarire graficamente il discorso sulla decisione vengono riportate in Figura 41, Figura 42 e Figura 43 le probabilità filtrate FIR su cui si effettua la scelta della classe di appartenenza. feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.6 1.2 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 41. Andamento delle probabilità filtrate FIR delle due classi per alpha=0.6 per il file audio con un SNR=60dB. In cyan la feature migliorata. feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.9 1.2 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 42. Andamento delle probabilità filtrate FIR delle due classi per alpha=0.9 per il file audio con un SNR=60dB. In cyan la feature migliorata. 52 feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.98 1.2 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 2500 3000 3500 Numero Iterazioni Figura 43. Andamento delle probabilità filtrate FIR delle due classi per alpha=0.98 per il file audio con un SNR=60dB. In cyan la feature migliorata. Infine i risultati delle prove per i diversi alpha con una soglia pari a 0.5 sono riportati nelle seguenti figure (Figura 44, Figura 45, Figura 46). segnale x(blue), feature migliorata fxp(cyan), vad(black) con alpha=0.6 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 0 10 20 30 40 50 Tempo 60 Figura 44. VAD con un alpha=0.6 applicato al file audio con SNR=60dB. 53 segnale x(blue), feature migliorata fxp(cyan), vad(black) con alpha=0.9 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 0 10 20 30 40 50 Tempo [s] Figura 45. VAD con un alpha=0.9 applicato al file audio con SNR=60dB. 60 segnale x(blue), feature migliorata fxp(cyan), vad(black) con alpha=0.98 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 0 10 20 30 40 50 Tempo [s] 60 Figura 46. VAD con un alpha=0.98 applicato al file audio con SNR=60dB. La freccia rossa in Figura 44 vuole indicare l’instabilità che già si presenta nel VAD con un alpha pari a 0.6 applicato al file audio con rumore pressoché inesistente (SNR=60dB). 54 3.2 Risultati sulla piattaforma Nu-Tech In questo paragrafo si riportano i risultati dell’implementazione vera e propria: quella realizzata in C e riprodotta utilizzando il framework Nu-Tech. Tale piattaforma permette di elaborare in tempo reale il flusso dei dati in ingresso alla scheda audio del PC su cui è installato. Oltre a ciò permette di processare anche dati in maniera off-line. In questo caso infatti, per provare la congruenza con quanto scritto in MATLAB, si propone per prima cosa una prova off-line utilizzando lo stesso file wave con SNR=60dB testato nel MATLAB (paragrafo 3.1). Per questo motivo nella voce Driver della finestra Settings del Nu-Tech si sono impostati i valori necessari alla scheda audio per l’elaborazione del file, cioè frequenza di campionamento pari a 8KHz e Frame Size uguale a 1024. Tale Frame Size è il minimo valore di campioni che la scheda audio usata può supportare a quella frequenza di campionamento per far in modo che questo algoritmo sia il più possibile in tempo reale (si ha la minima latenza tra ingresso e uscita). Qui di seguito vengono visualizzate le impostazioni del driver della scheda audio (Figura 47), il setup della prova off-line (Figura 48) e i suoi risultati (Figura 49). Figura 47. Impostazione della frequenza di campionamento e della dimensione del frame di lavoro del Nu-Tech. È visibile anche il nome della scheda audio utilizzata per i tests. 55 Figura 48. Setup utilizzato per le prove offline. Il nome del blocco NUT che implementa l’algoritmo è VADonHOS. Figura 49. Prova off-line del VAD con alpha=0.9 e soglia=0.5 applicato al file audio con SNR=60dB. In questo caso l’uscita del VAD è stata registrata utilizzando il blocco FileWrite anziché essere ascoltata. Per quanto riguarda la prova in tempo reale il suo setup in Nu-Tech è stato realizzato come in Figura 50. 56 Figura 50. Setup utilizzato per le prove real time. Si è usata una cuffia headset con microfono (stesso strumento usato nell’articolo [1]), il microfono è stato inserito in ingresso alla scheda audio Realtek AC97 Audio e le cuffie poste nella sua uscita. Il notebook utilizzato è dotato di processore Intel Pentium 4 2.8GHz con 512Mbyte di memoria RAM. Le impostazioni software sono le stesse della prova off-line con la differenza che in ingresso al blocco VAD ora c’è il flusso audio proveniente dal microfono invece che dal blocco FileRead. Inoltre a monte del VAD è stato inserito un filtro passa-alto per eliminare la fastidiosa componente continua intrinseca nell’hardware utilizzato. Questo bias provoca un innalzamento della feature fx nella parte che indica il non parlato avvicinando così i valori della X_t relativi alle due classi. Ciò compromette tutti gli altri parametri tra cui media e varianza, le quali generano due gaussiane vicine e simili tra loro rendendo meno distinguibili le due classi. Questo fenomeno può essere spiegato considerando che la kurtosi, che agisce su fx, dipende dalla media del residuo LPC, la quale in caso di rumore biased è maggiore del caso unbiased. Siccome la media del residuo LPC per la voce è più alta di quella che riguarda il non-parlato, nel caso di presenza della componente continua di fondo tale differenza si abbassa. Il filtro passa-alto usato è il NUT disponibile nel Nu-Tech denominato Filter, i cui parametri sono stati impostati come visibile nella Figura 51. è un filtro FIR in frequenza di lunghezza 10 con frequenza di taglio a 20Hz. I risultati della prova real time invece sono riportati nella Figura 52. 57 Figura 51. Impostazione del filtro passa-alto in ingresso al VAD. Figura 52. Prova real time del VAD con alpha=0.98 e soglia=0.5 dopo 11 minuti e 20 secondi circa di conversazione. Si è voluto effettuare un’ulteriore prova per testare la bontà dell’algoritmo anche per qualità più elevate, cioè si è innalzata la frequenza di campionamento a 32KHz. Inizialmente (Figura 53) si è lasciata l’implementazione dell’algoritmo uguale al caso 8KHz ma la latenza era troppo elevata. Per diminuire il ritardo ingresso-uscita si è 58 dovuto modificare la lunghezza del buffer di lavoro raddoppiandola, passando cioè ad un frame di elaborazione lungo 512 campioni con il solito overlap al 50% (Figura 54). Figura 53. Prova real time a 32KHz del VAD con alpha=0.98 e soglia=0.2 dopo 2 minuti e 30 secondi circa di conversazione. Figura 54. Prova real time a 32KHz del VAD con alpha=0.98 e soglia=0.5 dopo 8 minuti e 30 secondi circa di conversazione. Ora il blocco NUT utilizzato è VADonHOS_512 che implementa l’algoritmo con un frame di lavoro di 512 campioni. 59 Per eseguire la prova a 32KHz alla voce Driver della finestra Settings del Nu-Tech si è dovuto cambiare oltre alla frequenza di campionamento anche il Frame Size, il cui valore minimo adatto alla prova e permesso dalla scheda audio diventa 4096. La scheda audio, a seconda della frequenza di campionamento, supporta dei valori minimi di Frame Size. Infatti questa può permettere un valore di Frame Size anche minore di quelli impostati ma non sarebbero stati adatti al caso in esame poiché, per come è stato scritto il codice in C, il Frame Size deve essere un multiplo esatto del frame di lavoro altrimenti ci sarebbe un numero di campioni persi, cioè non elaborati, per ogni Frame Size, pari al resto della divisione tra Frame Size e il frame di lavoro. 3.2.1 Risorse di calcolo impiegate dall’algoritmo Le prestazioni in termini di impiego della CPU con cui si è realizzata la prova sono evidenziate in rosso nelle Figura 55, Figura 56, Figura 57 e Figura 58. Il Nu-Tech permette di visualizzare questo valore in termini di percentuale nella finestra Transport Panel. Per il caso off-line e real time a 8KHz la CPU viene impiegata al 2,2% circa, per il caso a 32KHz la percentuale sale al 9,5% mentre per quello con la stessa frequenza di campionamento ma frame di lavoro a 512 campioni sale al 15,3% circa. Figura 55. Percentuale d’impiego della CPU richiesta dalla totalità dei blocchi usati per la prova off-line. 60 Figura 56. Percentuale d’impiego della CPU richiesta dalla totalità dei blocchi usati per la prova real time. Figura 57. Percentuale d’impiego della CPU richiesta dalla totalità dei blocchi usati per la prova real time con frequenza di campionamento a 32KHz e con il frame di lavoro originale (256 campioni). 61 Figura 58. Percentuale d’impiego della CPU richiesta dalla totalità dei blocchi usati per la prova real time con frequenza di campionamento a 32KHz e con il frame di lavoro lungo 512 campioni. 3.3 Confronto tra MATLAB e Nu-Tech In questo paragrafo viene mostrato un confronto tra i valori dei parametri media e varianza, i più significativi, che si ottengono nei due ambienti di lavoro utilizzati, cioè MATLAB e Nu-Tech, entrambi eseguiti in debugging (per il Nu-Tech il debugging è effettuato con il Visual Studio 2005). La comparazione viene fatta per evidenziare la loro congruenza anche dopo molte iterazioni. Come segnale vocale di prova viene preso il file wave audio standard di parlato maschile a 8KHz opportunamente modificato già descritto nel paragrafo 3.1, ma questa volta l’aggiunta di rumore bianco gaussiano porta a 20dB il suo rapporto segnalerumore. I numeri di iterazioni che vengono considerati sono 1, 1000, 2000 e 3000 che temporalmente corrispondono a 16ms, 16s, 32s e 48s. Nel primo caso (Figura 59) l’uguaglianza si ha fino alla ottava cifra dopo la virgola per entrambe le medie e per la varianza del secondo andamento e salgono a nove per la varianza del primo andamento. 62 Figura 59. Confronto tra i valori dei parametri in MATLAB e in Nu-Tech dopo una iterazione. Figura 60. Confronto tra i valori dei parametri in MATLAB e in Nu-Tech dopo 1000 iterazioni. 63 Nel secondo caso (Figura 60) l’uguaglianza per la media e per la varianza dell’andamento 1 arriva fino all’ottava cifra dopo la virgola mentre scende alla settima per la media e per la varianza dell’andamento 2. Nel terzo caso (Figura 61) le cifre uguali dopo la virgola sono sette per la media del primo andamento e per la varianza del secondo andamento, sono sei nella media dell’andamento 2 ma sono dieci nella varianza dell’andamento 1. Figura 61. Confronto tra i valori dei parametri in MATLAB e in Nu-Tech dopo 2000 iterazioni. Nell’ultimo caso analizzato (Figura 62) le cifre uguali dopo la virgola salgono a otto per la media del primo andamento e per la varianza del secondo andamento, rimangono sempre sei nella media dell’andamento 2 e passano a nove nella varianza dell’andamento 1. 64 Figura 62. Confronto tra i valori dei parametri in MATLAB e in Nu-Tech dopo 3000 iterazioni. 3.4 Tempi di convergenza dei parametri del VAD L’algoritmo, essendo adattativo e di apprendimento, può raggiungere velocemente la convergenza dei suoi parametri aumentando la rapidità con cui essi tendono ad assumere un range di valori stabili e tali da essere considerati separati per ogni classe, inoltre deve essere in grado di discernere velocemente tra le due situazioni, parlato e non parlato, in un certo periodo iniziale in cui l’algoritmo le apprende dai parametri e dai dati che elabora nella fase iniziale. Per quanto riguarda la rapidità con cui i parametri convergono verso un range di valori di regime, essa dipende, come già osservato nel paragrafo 3.1, da alpha che per valori bassi, vicino a 0.5, provoca una convergenza lenta, mentre per valori alti, sopra 0.9, genera una convergenza rapida. 65 Per il secondo aspetto, la capacità di decidere velocemente, si deve tener presente che, per poter apprendere, l’algoritmo VAD necessita di processare per opportuni istanti iniziali sia frames di parlato sia frames di non parlato, in modo da permettere una iniziale separazione tra i parametri relativi a ogni classe. Infatti se ci fosse per il periodo iniziale solo parlato o non-parlato, l’algoritmo otterrebbe dei valori di media e di varianza simili per ogni classe, non riuscendo così a discriminarle in maniera corretta. Così la decisione sarebbe nuovamente frastagliata, dato che la piccola differenza tra i parametri delle due classi genererebbe una scelta dipendente dal modo in cui la feature migliorata influisce sulle gaussiane. Queste sarebbero infatti simili, alte e schiacciate o basse e spanciate, e poco distanti tra loro avendo medie quasi uguali. Infatti solamente dopo aver confrontato le due medie è possibile effettuare la decisione. Perciò è importante che esse siano sufficientemente distaccate per poter affermare che l’algoritmo è giunto a convergenza. feature fx(magenta), mu1(red) e mu2(green) 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 200 400 600 800 1000 1200 1400 1600 Numero iterazioni Figura 63. Andamento delle medie associate alle due classi per il file audio che inizia con il parlato (SNR=60dB, alpha=0.9). Tutto questo è verificabile attraverso i grafici sottostanti che, in Figura 63, Figura 64, Figura 65 e Figura 66 mostrano un esempio in cui l’algoritmo è applicato ad una sequenza che inizia per circa 18 secondi di parlato, mentre in Figura 67, Figura 68, Figura 69 e Figura 70 mostrano un esempio in cui l’algoritmo è applicato ad una 66 sequenza che inizia per circa 5 secondi di non parlato. Il file wave in questione è lo stesso file di partenza (voce maschile a 8KHz) utilizzato nelle prove precedenti, con la differenza che in questo caso è stato solo aggiunto silenzio dopo (per 10 secondi) e prima (per 4 secondi). Inoltre al file wave è stato aggiunto rumore bianco gaussiano tale da condurre ad un SNR pari a 60dB. feature fx(magenta), chi1(red) e chi2(green) 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 200 400 600 800 1000 1200 1400 1600 Numero iterazioni Figura 64. Andamento delle probabilità stimate associate alle due classi per il file audio che inizia con il parlato (SNR=60dB, alpha=0.9). feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 200 400 600 80 1000 1200 1400 1600 Numero iterazioni Figura 65. Andamento delle probabilità filtrate associate alle due classi per il file audio che inizia con il parlato (SNR=60dB, alpha=0.9). 67 segnale x(blue), feature migliorata fxp(cyan), vad(black) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 0 5 10 15 20 25 Tempo [s] Figura 66. VAD applicato al file audio che inizia con il parlato (SNR=60dB). Le frecce rosse indicano l’errore dovuto alla non convergenza. Alpha=0.9, soglia=0.5. feature fx(magenta), mu1(red) e mu2(green) 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 200 400 600 800 1000 1200 1400 Numero Figura 67. Andamento delle medie associate alle due classi per il file audio che inizia con il non-parlato (SNR=60dB, alpha=0.9). 68 feature fx(magenta), chi1(red) e chi2(green) 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 200 400 600 800 1000 1200 1400 Numero iterazioni Figura 68. Andamento delle probabilità stimate associate alle due classi per il file audio che inizia con il non-parlato (SNR=60dB, alpha=0.9). feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) 1.2 1 0.8 0.6 0.4 0.2 0 0 200 400 600 800 1000 1200 1400 Numero iterazioni Figura 69. Andamento delle probabilità filtrate associate alle due classi per il file audio che inizia con il non-parlato (SNR=60dB, alpha=0.9). 69 segnale x(blue), feature migliorata fxp(cyan), vad(black) 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 0 2 4 6 8 10 12 14 16 18 20 22 Tempo [s] Figura 70. VAD applicato al file audio che inizia con il non-parlato (SNR=60dB). La freccia rossa indica l’errore dovuto alla non convergenza. Alpha=0.9, soglia=0.5. In pratica viene mostrato come l’algoritmo impieghi pochissimo tempo per separare i suoi parametri dal momento in cui si passa da una situazione iniziale prolungata, cioè di almeno 3-4 secondi, di non-parlato o parlato all’altra. 3.5 Prestazioni dell’algoritmo VAD per diversi SNR Per dare una valutazione delle prestazioni dell’algoritmo si sono confrontati i risultati relativi ad un segnale vocale in cui è stato aggiunto di volta in volta, in misura sempre crescente, rumore bianco gaussiano, con il risultato ottenuto processando lo stesso segnale vocale ma con un SNR pari a 60dB. Perciò si considera quest’ultimo file audio quello che genera il risultato ideale, cioè un VAD in grado di distinguere tra parlato e non parlato senza sbagliare. Visto che viene considerato VAD un segnale binario in cui lo zero indica il non parlato e l’uno indica il parlato per ogni frame elaborato, è possibile effettuare una differenza tra il risultato di riferimento e i risultati in prova. Questa operazione conduce a tre valori corrispondenti a tre casi: 70 • il frame di parlato o di non parlato è individuato correttamente quindi la differenza tra il VAD di riferimento e il VAD a più basso SNR è 0; • il frame di parlato del VAD di riferimento non viene riconosciuto nel VAD in prova dunque la differenza è pari a 1; • il frame di non parlato del VAD di riferimento non viene riconosciuto nel VAD in prova dunque la differenza è pari a -1. Contare il numero di volte in cui capitano questi casi conduce a tre diversi indicatori: percentuale di frames correttamente rilevati, percentuale di frames parlato sbagliati e percentuale di frames non parlato sbagliati. Bisogna inizialmente sapere il numero dei frames totali del segnale vocale analizzato. Poi bisogna calcolare il numero di 0, quindi di frames non parlato, e di 1, quindi di frames parlato, presenti nel VAD di riferimento. Infine si possono fare i seguenti rapporti per trovare i tre indicatori: • • • % ° 0 100 ; ° ° % ° % 1 100 ; 1 ° ° ‐1 100 ‐1 . Questi calcoli sono stati effettuati in MATLAB nella funzione StatVAD.m di cui si riporta solo la parte che permette di calcolare gli indicatori in quanto la parte del calcolo del VAD è stata già riportata in VADonHOS.m in appendice. stats=vad2-vad1; %il 2 è il file di riferimento for i=1:length(vad1) if stats(i)== 0 framecorretti = framecorretti+1; end if stats(i)== -1 framenonparlatosbag = framenonparlatosbag+1; end if stats(i)== 1 frameparlatosbag = frameparlatosbag+1; end end frametotali=length(vad2); %conta frames totali for i=1:length(vad2) if vad2(i)== 0 framenonparlatot = framenonparlatot+1; %conta frames non parlato else if vad2(i)==1 frameparlatot = frameparlatot+1; %conta frames parlato end end end 71 Framerightperc = 100*(framecorretti/frametotali); %frames corretti Frameparlatosbagperc = 100*(frameparlatosbag/frameparlatot); %frames parlato sbagliati Framenonparlatosbagperc = 100*(framenonparlatosbag/framenonparlatot); %frames non parlato sbagliati end Il segnale vocale con un SNR di 60dB che genera il VAD di riferimento è stato elaborato con una soglia pari a 0.5 e un alpha pari a 0.9. Questo è sembrato un ottimo compromesso per le due variabili. Infatti, dato che la scelta di considerare un frame parlato dipende dalla probabilità, è ragionevole pensare che una probabilità più vicina ad 1 possa imporre che il frame sia di parlato, mentre una probabilità più vicino allo 0 impone che non sia vero che il frame sia di parlato. Per cui spostare la soglia verso 1 o verso 0 implica considerare rispettivamente che ci sia una minore o maggiore possibilità che il frame sia di parlato. Nel caso di SNR alto come 60dB è plausibile pensare che ci sia la stessa possibilità di stabilire che sia vero che il frame sia di parlato oppure no e quindi impostare la soglia a 0.5. Alpha a 0.9 invece permette di trovare il giusto compromesso di convergenza in caso di basso rumore. Il risultato di questa elaborazione è stato anche ascoltato per confermare l’ottima decisione dell’algoritmo e la sua perfetta intelligibilità. Nelle seguenti tabelle sono riportati i dati relativi agli indicatori definiti in precedenza calcolati sullo stesso segnale vocale con diversi SNR, diversi alpha e diverse soglie, riferiti al VAD considerato ideale. SNR (dB) FrameCorretti% 60 95,227 55 95,253 50 94,347 45 95,360 40 91,867 35 94,080 30 90,560 25 90,907 20 84,400 15 79,973 10 66,613 5 45,333 alpha = 0.6, soglia = 0.5 Frame non-parlato sbagliati% 5,971 6,261 7,304 5,623 11,130 5,217 12,000 7,710 14,957 7,188 8,812 32,232 Frame parlato sbagliati% 3,753 3,457 4,247 3,802 5,580 6,519 7,259 10,272 16,148 30,963 54,321 73,778 Tabella 5. Prestazioni del VAD con alpha=0.6 e soglia=0.5 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. 72 SNR (dB) FrameCorretti% 60 100,000 55 98,987 50 97,600 45 97,573 40 96,987 35 97,760 30 97,200 25 95,200 20 92,640 15 85,387 10 72,533 5 59,040 alpha = 0.9, soglia = 0.5 Frame non-parlato sbagliati% 0,000 1,391 3,826 2,841 3,130 0,522 0,058 1,565 0,000 0,058 0,000 3,652 Frame parlato sbagliati% 0,000 0,691 1,185 2,074 2,914 3,704 5,136 7,556 13,630 27,012 50,864 72,741 Tabella 6. Prestazioni del VAD con alpha=0.9 e soglia=0.5 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. In questa tabella è possibile notare il VAD di riferimento per SNR = 60dB. SNR (dB) FrameCorretti% 60 100,000 55 98,987 50 97,600 45 97,573 40 96,987 35 97,760 30 97,627 25 96,533 20 94,667 15 90,347 10 81,840 5 60,320 alpha = 0.9, soglia = 0.25 Frame non-parlato sbagliati% 0,000 1,391 3,826 2,841 3,130 0,522 1,739 1,971 2,319 2,899 7,826 62,203 Frame parlato sbagliati% 0,000 0,691 1,185 2,074 2,914 3,704 2,914 4,741 7,901 15,407 26,963 20,494 Tabella 7. Prestazioni del VAD con alpha=0.9 e soglia=0.25 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. SNR (dB) FrameCorretti% 30 97,867 25 97,147 20 95,360 15 90,800 10 82,080 5 65,413 alpha = 0.98, soglia = 0.25 Frame non-parlato sbagliati% 0,812 0,406 0,406 0,986 4,290 45,681 Frame parlato sbagliati% 3,259 4,938 8,247 16,198 29,531 25,136 Tabella 8. Prestazioni del VAD con alpha=0.98 e soglia=0.25 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. 73 SNR (dB) FrameCorretti% 30 97,947 25 97,200 20 95,947 15 91,440 10 82,560 5 56,907 alpha = 0.98, soglia = 0.2 Frame non-parlato sbagliati% 1,275 0,812 0,928 3,014 14,841 92,638 Frame parlato sbagliati% 2,716 4,494 6,716 13,284 19,654 0,889 Tabella 9. Prestazioni del VAD con alpha=0.98 e soglia=0.2 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. Frame corretti % 100 80 70 60 soglia=0.5 alpha=0.6 soglia=0.25 alpha=0.9 soglia=0.2 alpha=0.98 soglia=0.5 alpha=0.9 soglia=0.25 alpha=0.98 Frame corretti % 90 50 40 60 50 40 30 20 10 0 SNR [dB] Figura 71. Andamento della percentuale dei frames correttamente rilevati al diminuire del SNR. Nella Figura 71 si può notare come all’aumentare del rumore ci sia un progressivo degrado delle prestazioni dell’algoritmo intese come riduzione dei frames correttamente rilevati con conseguente diminuzione dell’intelligibilità del parlato. In particolare se si osserva la curva per alpha=0.6 si vede come questa sia sempre più bassa rispetto al riferimento di circa 7-8% con andamenti variabili. Questa curva conferma l’instabilità che questo valore per questo parametro genera sulla convergenza dell’algoritmo e ciò suggerisce di mantenere alpha piuttosto vicino all’unità. Per alpha 0.9 le curve con 74 SNR superiore a 30dB hanno, anche variando la soglia, uguali prestazioni che sono superiori al 97%, questo significa che il VAD riconosce i frames quasi allo stesso modo del VAD di riferimento con SNR pari a 60dB. Scendendo sotto i 30dB di SNR si può notare come l’effetto dell’aumento di alpha e della diminuzione della soglia faccia aumentare sensibilmente la percentuale dei frames correttamente rilevati, in particolare proprio la diminuzione della soglia fa aumentare le prestazioni maggiormente rispetto all’aumento di alpha. Fino a 10dB, anche grazie all’ascolto dei files a cui si applica l’algoritmo del VAD con le situazioni descritte, si riesce a mantenere una intelligibilità sufficiente a capire il discorso, in generale si può affermare che fino a 15dB di SNR il VAD funziona correttamente. Frames di non parlato sbagliati % 100 soglia=0.5 alpha=0.9 soglia=0.25 alpha=0.98 90 80 70 60 50 40 30 20 Frames di non parlato sbagliati % soglia=0.5 alpha=0.6 soglia=0.25 alpha=0.9 soglia=0.2 alpha=0.98 10 0 60 50 40 30 SNR [dB] 20 10 0 Figura 72. Andamento della percentuale dei frames di non-parlato sbagliati al diminuire del SNR. Analizzando la Figura 72 è possibile studiare l’andamento della percentuale dei frames di non-parlato sbagliati al diminuire del SNR. Si nota che per valori di alpha prossimi all’unità il VAD riconosce meglio il non-parlato in quanto tende a dare una probabilità che il frame non-parlato sia parlato quasi 0. Infatti se si passa per un valore di soglia pari a 0.25 da alpha=0.9 a alpha=0.98 è evidente una diminuzione percentuale 75 dei frames di non-parlato sbagliati. Grazie a questo fenomeno, in condizioni più rumorose, è possibile abbassare la soglia e permettere il riconoscimento di più frames di parlato a discapito di un modesto peggioramento nel riconoscimento del non-parlato. Frames di parlato sbagliati % 100 soglia=0.5 alpha=0.9 soglia=0.25 alpha=0.98 90 80 70 60 50 40 30 Frames di parlato sbagliati % soglia=0.5 alpha=0.6 soglia=0.25 alpha=0.9 soglia=0.2 alpha=0.98 20 10 0 60 50 40 30 SNR [dB] 20 10 0 Figura 73. Andamento della percentuale dei frames di parlato sbagliati al diminuire del SNR. Per quanto riguarda le Figura 73 e Figura 74 qui si ha l’andamento della percentuale dei frames di parlato sbagliati al diminuire del SNR. I grafici confermano che per basse soglie, con alpha prossimo all’unità, si ha un miglioramento nel riconoscimento del parlato. Sempre considerando le curve per soglia pari a 0.25 ma con alpha=0.9 e alpha=0.98 si osserva che in questo caso si ha un modesto aumento percentuale di frames di parlato sbagliati. Se si porta la soglia a un valore di 0.2 invece la curva migliora anche rispetto all’andamento con soglia=0.25 e alpha=0.9. Quindi è possibile affermare che alpha è un parametro che agisce meglio nel riconoscimento del nonparlato affetto da rumore mentre la soglia è un parametro che agisce meglio sul riconoscimento del parlato affetto da rumore. Per tale ragione si è deciso di lasciar libero il loro cambiamento nell’utilizzo nella piattaforma Nu-Tech. Una ulteriore osservazione può essere fatta se si osserva come a 5dB di SNR sembrerebbero 76 migliorare decisamente le prestazioni nel riconoscimento del parlato. In realtà si deve considerare che l’eccessivo rumore tende a portare le probabilità attorno a 0.5 creando una grossa indecisione. Avendo valori di soglia inferiori a 0.5 ciò comporta che si faccia passare come parlato la maggior parte dei frames quindi, se è vero che i frames di parlato vengono riconosciuti è anche vero che i frames di non-parlato non vengono eliminati provocando un funzionamento non corretto del VAD. Comunque questo è visibile dalla Figura 71 dove per SNR=5dB la percentuale dei frames correttamente identificati scende al 60% a causa dell’elevata percentuale di frames di non-parlato sbagliati (fino a oltre il 90% per alpha=0.98 e soglia=0.2) come mostrato in Figura 72. Frames di parlato sbagliati % 40 soglia=0.5 alpha=0.6 30 soglia=0.25 alpha=0.9 soglia=0.25 alpha=0.98 25 soglia=0.2 alpha=0.98 20 15 10 Frames di parlato sbagliati % 35 soglia=0.5 alpha=0.9 5 0 35 30 25 20 15 SNR [dB] 10 5 0 Figura 74. Zoom sull’andamento della percentuale dei frames di parlato sbagliati al diminuire del SNR. A conferma di quanto affermato sulle prestazioni dell’algoritmo applicato a files audio con diversi SNR per diversi valori delle variabili che caratterizzano il VAD, vengono riportate di seguito alcune figure (dalla Figura 75 alla Figura 86) che permettono un confronto visivo sulle medie, sulle probabilità e naturalmente sul VAD. Le figure che possono essere considerate di riferimento poiché riguardano il file wave con SNR=60dB si trovano nel paragrafo 3.1 e vanno dalla Figura 30 alla Figura 46. 77 SNR 25dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.6 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 25dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.9 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 25dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.98 1.5 1 0.5 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 75. Andamento delle medie associato alle due classi per lo stesso file audio con SNR=25dB per tre diversi valori di alpha. In magenta la feature. 78 SNR 25dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.6 1 0.8 0.6 0.4 0.2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 25dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.9 1 0,75 0,5 soglia 0,25 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 25dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.98 1 0,75 0,5 soglia 0,25 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 76. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=25dB per tre diversi valori di alpha. In cyan la feature migliorata. 79 segnale x(blue) SNR 25dB, feature migliorata fxp(cyan), vad(black) con alpha=0.6 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 25dB, feature migliorata fxp(cyan), vad(black) con alpha=0.9 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 25dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.25 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo [s] Figura 77. VAD con tre diversi valori di alpha e due diverse soglie applicato allo stesso file audio con SNR=25dB. Dove non esplicitamente indicato la soglia è 0.5. 80 SNR 20dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.6 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 20dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.9 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 20dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.98 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 78. Andamento delle medie associato alle due classi per lo stesso file audio con SNR=20dB per tre diversi valori di alpha. In magenta la feature. 81 SNR 20dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.6 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 20dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.9 1 0,75 0,5 soglia 0,25 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 20dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.98 1 0,75 0,5 soglia 0,25 soglia 0,2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 79. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=20dB per tre diversi valori di alpha. In cyan la feature migliorata. 82 segnale x(blue) SNR 20dB, feature migliorata fxp(cyan), vad(black) con alpha=0.6 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 20dB, feature migliorata fxp(cyan), vad(black) con alpha=0.9 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 20dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.25 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] Figura 80. VAD con tre diversi valori di alpha e una diversa soglia applicato allo stesso file audio con SNR=20dB. Dove non esplicitamente indicato la soglia è 0.5. 83 SNR 15dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 15dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.9 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 15dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.98 1.4 1.2 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 81. Andamento delle medie associato alle due classi per lo stesso file audio con SNR=15dB per tre diversi valori di alpha. In magenta la feature. 84 SNR 15dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.6 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 15dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.9 1 0,75 0,5 soglia 0,25 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 15dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.98 1 0,75 0,5 soglia 0,25 soglia 0,2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 82. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=15dB per tre diversi valori di alpha. In cyan la feature migliorata. 85 segnale x(blue) SNR 15dB, feature migliorata fxp(cyan), vad(black) con alpha=0.9 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 15dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.25 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 15dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.2 1 0. 0. 0. 0. 0 - 0 1 2 3 4 5 6 Tempo Figura 83. VAD con tre diversi valori di alpha e due diverse soglie applicato allo stesso file audio con SNR=15dB. Dove non esplicitamente indicato la soglia è 0.5. 86 SNR 10dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.6 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 10dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.9 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 10dB: feature fx(magenta), mu1(red) e mu2(green) con alpha=0.98 1 0.8 0.6 0.4 0.2 0 -0.2 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 84. Andamento delle medie associato alle due classi per lo stesso file audio con SNR=10dB per tre diversi valori di alpha. In magenta la feature. 87 SNR 10dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.6 1 0.8 0.6 0.4 0.2 0 - 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 10dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.9 1 0,75 0, soglia 0,25 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni SNR 10dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con alpha=0.98 1 0,75 0,5 soglia 0,25 soglia 0,2 0 0 500 1000 1500 2000 2500 3000 3500 Numero iterazioni Figura 85. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=10dB per tre diversi valori di alpha. In cyan la feature migliorata. 88 segnale x(blue) SNR 10dB, feature migliorata fxp(cyan), vad(black) con alpha=0.9 e soglia=0.25 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 10dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.25 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] segnale x(blue) SNR 10dB, feature migliorata fxp(cyan), vad(black) con alpha=0.98 e soglia=0.2 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 0 10 20 30 40 50 60 Tempo [s] Figura 86. VAD con due diversi valori di alpha e due diverse soglie applicato allo stesso file audio con SNR=10dB. 89 Infine (Figura 87, Figura 88, Figura 89) è mostrata anche l’applicazione del VAD ad alcuni files audio con diverso SNR nella piattaforma Nu-tech. Figura 87. Risultato in Nu-Tech del VAD applicato al file audio di test. SNR=20dB, alpha=0.98, soglia=0.25. Figura 88. Risultato in Nu-Tech del VAD applicato al file audio di test. SNR=15dB, alpha=0.98, soglia=0.2. 90 Figura 89. Risultato in Nu-Tech del VAD applicato al file audio di test. SNR=10dB, alpha=0.98, soglia=0.2. 3.5.1 Ulteriore miglioramento dell’algoritmo per bassi SNR Si è voluto testare l’algoritmo per bassi SNR con la modifica effettuata nel paragrafo 3.2 per l’elaborazione in tempo reale ma lasciando inalterata a 8KHz la frequenza di campionamento. Viene cioè solamente raddoppiata la lunghezza della trama di lavoro che passa quindi da 256 campioni a 512. SNR (dB) FrameCorretti% 60 93,947 55 94,587 50 94,213 45 94,533 40 95,280 35 95,280 30 96,027 25 97,253 20 97,413 15 95,973 10 92,293 5 80,453 trama 512, alpha = 0.99, soglia 0.18 Frame non-parlato sbagliati% Frame parlato sbagliati% 13,043 0,099 11,652 0,099 12,464 0,099 11,768 0,099 9,971 0,247 9,739 0,444 7,942 0,593 4,754 1,037 4,232 1,185 2,145 5,630 0,638 13,728 11,304 26,568 Tabella 10. Prestazioni del VAD con una trama lunga 512 campioni, alpha=0.99 e soglia=0.18 applicato al file audio di test al variare del SNR. Percentuali calcolate come indicate nel paragrafo 3.5. 91 Come si nota dalla Tabella 10 e dal conseguente grafico delle prestazioni in Figura 90, per SNR inferiori ai 20dB c’è un notevole aumento percentuale delle prestazioni in termini di frames correttamente rilevati. Frame corretti % 100 80 soglia=0.5 alpha=0.6 70 soglia=0.5 alpha=0.9 60 soglia=0.25 alpha=0.9 Frame corretti % 90 soglia=0.25 alpha=0.98 50 soglia=0.2 alpha=0.98 trama 512 soglia=0.18 alpha=0.99 40 60 50 40 30 SNR [dB] 20 10 0 Figura 90. Andamento della percentuale dei frames correttamente rilevati al diminuire del SNR. Frames di non parlato sbagliati % 90 soglia=0.5 alpha=0.9 80 soglia=0.25 alpha=0.9 soglia=0.25 alpha=0.98 70 soglia=0.2 alpha=0.98 60 trama 512 soglia=0.18 alpha=0.99 50 40 30 20 Frames di non parlato sbagliati % 100 soglia=0.5 alpha=0.6 10 0 60 50 40 30 SNR [dB] 20 10 0 Figura 91. Andamento della percentuale dei frames di non-parlato sbagliati al diminuire del SNR. 92 Dai grafici di Figura 91 e Figura 92 si vede come il netto miglioramento sia dato da un maggior riconoscimento di frames di parlato il che permette un apprezzabile aumento dell’intelligibilità delle parole diminuendo il frastagliamento. Frames di parlato sbagliati % 100 soglia=0.5 alpha=0.6 soglia=0.25 alpha=0.9 80 soglia=0.25 alpha=0.98 70 soglia=0.2 alpha=0.98 60 trama 512 soglia=0.18 alpha=0.99 50 40 30 20 Frames di parlato sbagliati % 90 soglia=0.5 alpha=0.9 10 0 60 50 40 30 SNR [dB] 20 10 0 Figura 92. Andamento della percentuale dei frames di parlato sbagliati al diminuire del SNR. SNR 15dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con trama 512 e alpha=0.99 1 0,8 0,6 0,4 0,25 soglia 0,18 0 0 200 400 600 800 1000 1200 1400 1600 1800 Numero Iterazioni Figura 93. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=15dB usato nel paragrafo 3.5 per un frame di elaborazione pari a 512 campioni ed un alpha=0.99. In cyan la feature migliorata. 93 segnale x(blue) SNR 15dB, feature migliorata fxp(cyan), vad(black) con trama 512, alpha=0.99 e soglia=0.18 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo [s] Figura 94. VAD con trama di lavoro di 512 campioni, alpha=0.99 e soglia=0.18 applicato allo stesso file audio con SNR=15dB usato nel paragrafo 3.5. Il tutto è ben visibile se si confrontano rispettivamente per un SNR=15dB la Figura 82 e la Figura 83 con la Figura 93 e la Figura 94, mentre per un SNR=10dB si devono confrontare la Figura 85 e la Figura 86 con la Figura 95 e la Figura 96. SNR 10dB: feature migliorata fxp(cyan), probFIR1(red) e probFIR2(green) con trama 512 e alpha=0.99 1 0,8 0,6 0,4 0,25 soglia 0,18 0 0 200 400 600 800 1000 1200 1400 1600 1800 Numero Iterazioni Figura 95. Andamento delle probabilità filtrate FIR delle due classi per lo stesso file audio con SNR=10dB usato nel paragrafo 3.5 per un frame di elaborazione pari a 512 campioni ed un alpha=0.99. In cyan la feature migliorata. 94 segnale x(blue) SNR 10dB, feature migliorata fxp(cyan), vad(black) con trama 512, alpha=0.99 e soglia=0.18 1 0.5 0 -0.5 0 10 20 30 40 50 60 Tempo Figura 96. VAD con trama di lavoro di 512 campioni, alpha=0.99 e soglia=0.18 applicato allo stesso file audio con SNR=10dB usato nel paragrafo 3.5. 95 Capitolo 4 Conclusioni È stato proposto un nuovo metodo real time per il VAD. Il metodo usa le statistiche di ordine superiore migliorate attraverso una caratteristica pesata dall’autocorrelazione per migliorare l’immunità ai rumori non-gaussiani. È stato inoltre studiato l’uso delle HOS per discriminare il parlato in campo vicino e in campo lontano, che è un problema importante nelle interazioni tra più persone. Sono stati proposti e analizzati diversi metodi decisionali per effettuare la scelta di classificazione tra parlato e non parlato. La classificazione è fatta real time da un metodo di cluster online basato sull’algoritmo EM. Il passo E è rimpiazzato da un’approssimazione stocastica ricorsiva per permettere all’algoritmo di cambiare il suo stato ad ogni nuovo frame, perciò fornisce una stima del rumore senza richiedere uno schema separato per la stima del SNR. Il metodo è stato implementato e valutato sia in Matlab che in linguaggio C attraverso la piattaforma Nu-Tech confrontando i risultati ottenuti elaborando un file a cui viene aggiunto rumore AWGN a diversi SNR con un VAD di riferimento. Sono state fatte anche prove real time ed è stata confermata la robustezza dell’algoritmo alla poca densità del parlato. E’ stato effettuato un confronto sui parametri dell’algoritmo in Matlab e in C riscontrando una congruenza numerica fino alla sesta cifra dopo la virgola. Si sono evidenziate le caratteristiche dell’algoritmo, i miglioramenti apportati attraverso i filtraggi delle probabilità e i filtraggi della feature, i problemi dovuti alle polarizzazioni intrinseche della schede audio, e le soluzioni per risolverli. E’ stato mostrato l’uso della soglia sulla probabilità e l’uso del parametro alpha di convergenza evidenziando che in condizioni di elevata rumorosità la soglia può essere abbassata, rendendo intelligibile il parlato, ma introducendo anche frames di rumore che vengono percepiti. Questi parametri sono stati lasciati liberi e impostabili dall’utente finale per lasciare la massima libertà di ottimizzazione in tutte le condizioni di rumorosità. Sono stati provati diversi setup di prova per analizzare le risorse di calcolo in termini di impiego di CPU richieste dall’algoritmo. Sono stati effettuate prove per verificare la prontezza e la convergenza dei parametri che caratterizzano il VAD stabilendo che l’alpha deve essere maggiore di 0.9 al fine di ottenere un’immediata convergenza dell’algoritmo. E’ stata raddoppiata la lunghezza del frame di lavoro che spinge l’algoritmo a lavorare in maniera soddisfacente, a livello di intelligibilità, fino a bassissimi SNR (10dB). Figura 97. Risultato in Nu-Tech del VAD con frame di lavoro lungo 512 campioni applicato al file audio di test. SNR=10dB, alpha=0.99, soglia=0,18. Questo schema potrebbe essere ulteriormente migliorato. Ad esempio provando ad inizializzare i parametri dell’EM Online attraverso l’algoritmo k-mean anziché inizializzarli a caso a discapito di un ritardo nell’elaborazione di qualche istante. 97 La stima dell’EM online non è affidabile fino a che qualche dato che rappresenta il parlato non è disponibile, perché essendo adattativo l’algoritmo deve apprendere le due situazioni. Considerando esplicitamente una conoscenza a priori e confrontando i modelli, il trattamento Bayesiano dell’EM online potrebbe risolvere questo problema e fornire una migliore precisione. Infine si potrebbe migliorare l’algoritmo aumentando la lunghezza del frame di lavoro e massimizzandola fino ad ottenere decisioni ottime per alti livelli di rumore. 98 Appendice Listati dell’algoritmo Vengono riportate le implementazioni scritte in codice MATLAB e in C dell’algoritmo VAD. A. Listato in MATLAB Sono state scritte diverse funzioni per rendere chiaro, modulare e portabile l’algoritmo coerentemente con lo schema a blocchi di Figura 2. La funzione principale con cui far partire l’algoritmo è VADonHOS.m riportata di seguito, i valori iniziali caricati per i parametri sono riferiti alla Figura 11. Il file wave va caricato come argomento nella funzione. VADonHOS.m function VADonHOS(file) clc; %pulisce la Command Window [campioni,Fs] = leggiwave(file); %file è il file wave da elaborare x=[zeros(128,1);campioni]; %aggiunti 128 zeri all'inizio per congruenza con il Nu-Tech %stampa delle informazioni sul file wave fprintf('La frequenza di campionamento del segnale è %gHz\n',Fs); fprintf('Il file è lungo %g campioni e dura %g secondi\n',length(x),length(x)/Fs); %Si devono analizzare trame di 256 campioni con un overlap del 50%, quindi bisogna iterare per un numero di volte pari alla lunghezza di x diviso 128 campioni meno uno (meno uno perché ogni finestra, la trama, è compresa tra due valori dei puntatori che indicano l'iterazione). Num_iterazioni = fix(length(x)/128) - 1; %la funzione fix restituisce il numero intero approssimato per difetto fprintf('Il numero di iterazioni eseguite sono %d\n',Num_iterazioni); punt=1; %inizializzazione del puntatore che permette di prendere le trame da analizzare %%%%%%%%%%%%%%% Inizializzazione dei parametri per l'algoritmo EM online %%%%%%%%%%%%%%% %I parametri sono vettori di due elementi perché corrispondono ai due valori che identificano le classi parlato e non parlato. %I parametri che si riferiscono all'iterzione precedende vengono indicati con il suffisso "_p". %N.B.: le due medie e le due varianze iniziali non possono essere uguali tra loro altrimenti l'algoritmo non separerebbe i due andamenti. alpha=0.9; %compreso tra 0.5 e 1, agisce sulla funzione gamma_t=(n+1)^(-alpha) mu_p=[0.05,0.8]; %"mu" identifica la media della gaussiana variance_p=[0.155,1.9]; %"variance" identifica la varianza della gaussiana X_t_p=[0.02,0.48]; %"X_t" corrisponde a X circonflesso di t (stima di fx) chi_p=[0.4,0.6]; %"chi" corrisponde al simbolo greco chi X_t_quadro_p=[0.0645,1.78]; %"X_t" corrisponde alla stima di fx al quadrato %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %Inizializzazione dei vettori necessari a salvare i valori dei parametri tra le iterazioni per stampare e/o graficare i risultati f_xstamp=zeros(1,Num_iterazioni); X_t_1stamp=zeros(1,Num_iterazioni); X_t_2stamp=zeros(1,Num_iterazioni); chi_1stamp=zeros(1,Num_iterazioni); chi_2stamp=zeros(1,Num_iterazioni); mu_1stamp=zeros(1,Num_iterazioni); mu_2stamp=zeros(1,Num_iterazioni); X_t_quadro_1stamp=zeros(1,Num_iterazioni); X_t_quadro_2stamp=zeros(1,Num_iterazioni); variance_1stamp=zeros(1,Num_iterazioni); variance_2stamp=zeros(1,Num_iterazioni); vad=zeros(1,Num_iterazioni); prob_1stamp=zeros(1,Num_iterazioni); prob_2stamp=zeros(1,Num_iterazioni); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %Inizializzazione vettori e parametri per la decisione (versione modificata dell'algoritmo originale) f_x_p2=0; f_x_p1=0; f_x_p=0; f_x_pstamp=zeros(1,Num_iterazioni); p1=[0,0]; p2=[0,0]; p3=[0,0]; sommap_1stamp=zeros(1,Num_iterazioni); sommap_2stamp=zeros(1,Num_iterazioni); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Inizio iterazioni %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for n=1:Num_iterazioni [x256,punt] = trama(x,punt); %prepara la trama da 256 campioni saltando alla successiva dopo 128 campioni (overlap 50%) e = res_lpc(x256); %calcola il residuo lpc della trama n-esima [ac_causale,peak] = peak_picking(e); %estrae il picco massimo dell'autocorrelazione normalizzata del residuo escluso il picco per ritardo zero m_x = peak; %copia il valore del picco nella notazione usata nell'articolo expt = my_expt(e); %calcola la media del residuo v = my_variance(e,expt); %calcola la varianza del residuo k_x = my_kurtosis(e,expt,v); %calcola la kurtosi del residuo prendendo anche in ingresso la sua media e la sua varianza f_x = m_x*log(1 + k_x); %calcola la caratteristica(feature): una kurtosi migliorata f_xstamp(n) = f_x; %salva il valore attuale della feature fx gamma_t = (n+1)^(-alpha); %calcola gamma_t %%%%%%%%%%%%%%%%%%%%%%%%%%% Calcolo parametri %%%%%%%%%%%%%%%%%%%%%%%%%%% %si ottengono i parametri stimati per ogni classe(parlato/non parlato) 100 [X_t,chi,mu,X_t_quadro,variance]=em_online(f_x,mu_p,variance_p,X_t_p,gamma_t,chi_p,X_t_q uadro_p); %viene salvato ogni parametro su due vettori(classi parlato/non parlato) per stampare e/o graficare i valori di ogni iterazione X_t_1stamp(n)=X_t(1); X_t_2stamp(n)=X_t(2); chi_1stamp(n)=chi(1); chi_2stamp(n)=chi(2); mu_1stamp(n)=mu(1); mu_2stamp(n)=mu(2); X_t_quadro_1stamp(n)=X_t_quadro(1); X_t_quadro_2stamp(n)=X_t_quadro(2); variance_1stamp(n)=variance(1); variance_2stamp(n)=variance(2); %%%%%%%%%Filtraggio IIR del 3° ordine della caratteristica fx%%%%%%%%% f_x_p1=(f_x_p2+f_x_p1)/2; f_x_p2=f_x_p1; f_x_p=(f_x_p1+f_x_p)/2; f_x_p1=f_x_p; f_x_p=(f_x_p+f_x)/2; %caratteristica migliorata fxp per la decisione f_x_pstamp(n)=f_x_p; %stampa della fxp necessaria per la visualizzazione %%%%%%%%%%%%%%%%%%%%%Decisione della classe:il VAD%%%%%%%%%%%%%%%%%%%%% [prob,p1,p2,p3,sommap,vad(n)]=decisione(f_x_p,p1,p2,p3,mu,variance); %%%%%%%%%%%%%%%%%%%%%Stampe delle probailità%%%%%%%%%%%%%%%%%%%%% prob_1stamp(n)=prob(1); %probabilità non filtrata FIR prob_2stamp(n)=prob(2); %probabilità non filtrata FIR sommap_1stamp(n)=sommap(1); %probabilità filtrata FIR sommap_2stamp(n)=sommap(2); %probabilità filtrata FIR %%%%%%%%%Aggiornamento dei parametri per la prossima iterazione%%%%%%%% for c=1:2 X_t_p(c) = X_t(c); chi_p(c) = chi(c); mu_p(c) = mu(c); X_t_quadro_p(c) = X_t_quadro(c); variance_p(c) = variance(c); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% GRAFICI %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %grafica la caratteristica fx e quella migliorata fxp per la decisione figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,f_x_pstamp, 'cyan'); xlabel('Numero iterazioni'); title('feature fx(magenta) e feature migliorata fxp(cyan)'); %grafica la caratteristica fx e le sue stime X_t figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,X_t_1stamp, 'red'); plot(1:Num_iterazioni,X_t_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature fx(magenta), X_t_1(red) e X_t_2(green)') %grafica la caratteristica fx e le chi figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,chi_1stamp, 'red'); plot(1:Num_iterazioni,chi_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature fx(magenta), chi_1(red) e chi_2(green)') 101 %grafica la caratteristica fx e le medie figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,mu_1stamp, 'red'); plot(1:Num_iterazioni,mu_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature fx(magenta), mu_1(red) e mu_2(green)') %grafica la caratteristica fx e le X_t_quadro figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,X_t_quadro_1stamp, 'red'); plot(1:Num_iterazioni,X_t_quadro_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature fx(magenta), X_tquadro_1(red) e X_tquadro_2(green)') %grafica la caratteristica fx e le varianze figure plot(1:Num_iterazioni,f_xstamp, 'magenta'); hold all plot(1:Num_iterazioni,variance_1stamp, 'red'); plot(1:Num_iterazioni,variance_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature fx(magenta), variance_1(red) e variance_2(green)') %grafica la caratteristica migliorata fxp e le probabilità non filtrate figure plot(1:Num_iterazioni,f_x_pstamp, 'cyan'); hold all plot(1:Num_iterazioni,prob_1stamp, 'red'); plot(1:Num_iterazioni,prob_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature migliorata fxp(cyan), prob_1(red) e prob_2(green)') %grafica la caratteristica migliorata fxp e le probabilità filtrate FIR figure plot(1:Num_iterazioni,f_x_pstamp, 'cyan'); hold all plot(1:Num_iterazioni,sommap_1stamp, 'red'); plot(1:Num_iterazioni,sommap_2stamp, 'green'); xlabel('Numero iterazioni'); title('feature migliorata fxp(cyan), probFIR_1(red) e probFIR_2(green)') %grafica il segnale nel tempo con la caratteristica migliorata fxp sovrapposta e il VAD figure plot([1:length(x)]/Fs,x); %segnale d'ingresso nel tempo(secondi) hold all f_x_pmantenuto=zeros(1,(Num_iterazioni+1)*128); %feature migliorata fxp paragonabile temporalmente con il segnale %fprintf('f_x_mantenuto è lungo %g\n',length(f_x_mantenuto)); for k=0:(Num_iterazioni-1) for l=1:128 f_x_pmantenuto(128*k+l)=f_x_pstamp(k+1); end end plot([1:(Num_iterazioni+1)*128]/Fs,f_x_pmantenuto,'cyan'); vad_stamp=zeros(1,(Num_iterazioni+1)*128); %vad %fprintf('vad_stamp è lungo %g\n',length(vad_stamp)); for k=0:(Num_iterazioni-1) for l=1:128 vad_stamp(k*128+l)=vad(k+1); end end plot([1:(Num_iterazioni+1)*128]/Fs,vad_stamp, 'black'); xlabel('Tempo [s]'); title('segnale x(blue), feature migliorata fxp(cyan), vad(black)') 102 %togliere il commento se si vuole ascoltare il risultato %{ %%%%%%%%Ascolto dell'elaborazione dell'algoritmo VAD sul file wave%%%%%%%% xplay=zeros((Num_iterazioni+1)*128,1); for i=1:(Num_iterazioni+1)*128 xplay(i)=x(i)*vad_stamp(i); end wavplay(xplay,Fs); %} %togliere i commenti nel caso si volgiano graficare i vari parametri %confrontabili con il segnale vocale nel tempo %{ f_xmantenuto=zeros(1,(Num_iterazioni+1)*128); %feature fx paragonabile temporalmente con il segnale for k=0:(Num_iterazioni-1) for l=1:128 f_xmantenuto(128*k+l)=f_x_pstamp(k+1); end end %feature stimata X_t figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_xmantenuto,'magenta'); %feature fx paragonabile temporalmente con il segnale X_t_1=zeros(1,Num_iterazioni*128); X_t_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 X_t_1(128*k+l)=X_t_1stamp(k+1); X_t_2(128*k+l)=X_t_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,X_t_1, 'red'); plot([1:Num_iterazioni*128]/Fs,X_t_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature fx(magenta), X_t_1(red) e X_t_2(green)') %probabilità stimate chi figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_xmantenuto,'magenta'); %feature fx paragonabile temporalmente con il segnale chi_1=zeros(1,Num_iterazioni*128); chi_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 chi_1(128*k+l)=chi_1stamp(k+1); chi_2(128*k+l)=chi_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,chi_1, 'red'); plot([1:Num_iterazioni*128]/Fs,chi_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature fx(magenta), chi_1(red) e chi_2(green)') %medie mu figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_xmantenuto,'magenta'); %feature fx paragonabile temporalmente con il segnale mu_1=zeros(1,Num_iterazioni*128); mu_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 mu_1(128*k+l)=mu_1stamp(k+1); mu_2(128*k+l)=mu_2stamp(k+1); end 103 end plot([1:Num_iterazioni*128]/Fs,mu_1, 'red'); plot([1:Num_iterazioni*128]/Fs,mu_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature fx(magenta), mu_1(red) e mu_2(green)') %feature quadro stimate X_t_quadro figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_xmantenuto,'magenta'); %feature fx paragonabile temporalmente con il segnale X_t_quadro_1=zeros(1,Num_iterazioni*128); X_t_quadro_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 X_t_quadro_1(128*k+l)=X_t_quadro_1stamp(k+1); X_t_quadro_2(128*k+l)=X_t_quadro_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,X_t_quadro_1, 'red'); plot([1:Num_iterazioni*128]/Fs,X_t_quadro_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature fx(magenta), X_tquadro_1(red) e X_tquadro_2(green)') %varianze variance figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_xmantenuto,'magenta'); %feature fx paragonabile temporalmente con il segnale variance_1=zeros(1,Num_iterazioni*128); variance_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 variance_1(128*k+l)=variance_1stamp(k+1); variance_2(128*k+l)=variance_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,variance_1, 'red'); plot([1:Num_iterazioni*128]/Fs,variance_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature fx(magenta), variance_1(red) e variance_2(green)') %probabilità non filtrate FIR prob figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_x_pmantenuto,'cyan'); %feature fx paragonabile temporalmente con il segnale prob_1=zeros(1,Num_iterazioni*128); prob_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) for l=1:128 prob_1(128*k+l)=prob_1stamp(k+1); prob_2(128*k+l)=prob_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,prob_1, 'red'); plot([1:Num_iterazioni*128]/Fs,prob_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature migliorata fxp(cyan), prob_1(red) e prob_2(green)') %probabilità filtrate FIR sommap figure plot([1:length(x)]/Fs,x); hold all plot([1:(Num_iterazioni+1)*128]/Fs,f_x_pmantenuto,'cyan'); %feature fx paragonabile temporalmente con il segnale sommap_1=zeros(1,Num_iterazioni*128); sommap_2=zeros(1,Num_iterazioni*128); for k=0:(Num_iterazioni-1) 104 for l=1:128 sommap_1(128*k+l)=sommap_1stamp(k+1); sommap_2(128*k+l)=sommap_2stamp(k+1); end end plot([1:Num_iterazioni*128]/Fs,sommap_1, 'red'); plot([1:Num_iterazioni*128]/Fs,sommap_2, 'green'); xlabel('Tempo [s]'); title('segnale x(blue), feature migliorata fxp(cyan), probFIR_1(red) e probFIR_2(green)') %} end leggiwave.m function [x,Fs]= leggiwave(file) [x,Fs]=wavread(file); %wavplay(x,Fs); %da togliere il commento per sentire il file originale end trama.m %Trama prelevata dal vettore x, il quale contiene i campioni di ingresso del segnale function [x256,punt]= trama(x,punt) %restituisce i 256 valori della trama e il puntatore alla successiva x256=x(punt:punt+255); %punt va inizializzato fuori della funzione e funge da puntatore punt=punt+128; %riporta l'indice alla trama successiva con un overlap del 50% end res_lpc.m function [e]= res_lpc(x256) %calcola il residuo lpc della trama e lo restituisce in e lpc_coeff=lpc(x256,10); %calcolo dei coefficienti lpc usati per la ricostruzione del segnale: %essendo l'ordine p=10, il numero dei coefficienti lpc è p+1=11, con il primo coefficiente sempre uguale a 1. %Per ricostruire il frame occorre filtrare con un FIR di ordine p così costruito: FIR_coeff=[0 -lpc_coeff(2:end)] est_x256 = filter([0 -lpc_coeff(2:end)],1,x256); %stima del frame di 256 campioni (32ms a 8kHz) e = x256 - est_x256; %calcolo del residuo end peak_picking.m %Calcola l'autocorrelazione normalizzata del residuo ed estrae il valore del picco massimo escluso il picco per ritardo zero function [ac_causale,peak] = peak_picking(e) [acs,lags] = xcorr(e,'coeff'); %calcola l'autocorrelazione normalizzata ac_causale = acs(length(e)+1 : end); %sono presi solo i valori positivi di tau(lags) escluso lo zero peak=0; for i=1:length(ac_causale) if ac_causale(i) >= peak %prende solo il picco positivo peak = ac_causale(i); end end end my_expt.m %%%%%%%%%%%%%%%%% Calcola la media statistica (Expectation) %%%%%%%%%%%%%%%%% function [expt] = my_expt(e) 105 tmp=0; for i=1:length(e) tmp=e(i)+tmp ; %somma tutti i valori del vettore "e" end expt=tmp/length(e); %media end my_variance.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%Calcola la varianza%%%%%%%%%%%%%%%%%%%%%%%%%%%% %in questo caso del residuo "e" function [v] = my_variance(e,media) %"media" è la media del vettore "e" tmp=0; for i=1:length(e) tmp=(e(i)-media)^2 + tmp; %somma il quadrato di tutti i valori del vettore "e" meno media end v = tmp/length(e); %varianza end my_kurtosis.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%%Calcola la kurtosi%%%%%%%%%%%%%%%%%%%%%%%%%%%% %in questo caso del residuo "e" function [k] = my_kurtosis(e,media,v) %"media" e "v" sono la media e la varianza del vettore "e" for i=1:length(e) val_int(i)=(e(i)-media)^4 ; %calcolo del vettore su cui fare la media end k=(my_expt(val_int))/(v^2) -3; %kurtosi end em_online.m %Esegue un passo dell'algoritmo EM ONLINE per ogni classe(parlato/non parlato) function [X_t,chi,mu,X_t_quadro,variance]=em_online(f_x,mu_p,variance_p,X_t_p,gamma_t,chi_p,X_t_q uadro_p) p_gauss=zeros(1,2); P_i=zeros(1,2); X_t=zeros(1,2); chi=zeros(1,2); mu=zeros(1,2); X_t_quadro=zeros(1,2); variance=zeros(1,2); for c=1:2 p_gauss(c) = 1/sqrt(2*pi*variance_p(c)) * exp((-1/2)*((f_xmu_p(c))^2)/variance_p(c)); end psum=p_gauss(1)+p_gauss(2); for c=1:2 P_i(c) = p_gauss(c)/psum; X_t(c) = X_t_p(c) + gamma_t*(P_i(c)*f_x - X_t_p(c)); chi(c) = chi_p(c) + gamma_t*(P_i(c) - chi_p(c)); mu(c) = X_t(c)/chi(c); X_t_quadro(c) = X_t_quadro_p(c)+ gamma_t*(P_i(c)*(f_x^2) - X_t_quadro_p(c)); %CONVERGE SOLO per gamma_t=(n+1)^(-alpha); variance(c)= abs(X_t_quadro(c)/chi(c) - mu(c)^2); %infatti con gamma_t=(n)^(-alpha) e per n=1, porta una varianza nulla (f_x^2 - f_x^2) %if variance(c) <= 0.000001 %per evitare che si blocchi con una divisione per 0 % variance(c) = 0.00001; %end end %if abs(mu(1)-mu(2)) <= 0.000000001 %soluzione al caso in cui le medie non si separino % mu(1)=0.1+mu(2); end 106 decisione.m %Il VAD:viene decisa la classe(parlato/non parlato) della trama function [prob,p1,p2,p3,sommap,vad]=decisione(f_x_p,p1,p2,p3,mu,variance) sommap=zeros(1,2); p_gauss_attuale=zeros(1,2); prob=zeros(1,2); for c=1:2 p_gauss_attuale(c) = 1/sqrt(2*pi*variance(c)) * exp((-1/2)*((f_x_pmu(c))^2)/variance(c)); end psum=p_gauss_attuale(1)+p_gauss_attuale(2); for c=1:2 prob(c)=p_gauss_attuale(c)/psum; sommap(c)=(prob(c)+p1(c)+p2(c)+p3(c))/4; p3(c)=p2(c); p2(c)=p1(c); p1(c)=prob(c); end soglia=0.5; if mu(1) >= mu(2) %l'indice 1 classifica il parlato if sommap(1) >= soglia vad=1; %allora è parlato else %sommap(1) < soglia vad=0; %allora è rumore end else %mu(2) > mu(1) quindi l'indice 2 classifica il parlato if sommap(2) >= soglia vad=1; %allora è parlato else %sommap(2) < soglia vad=0; %allora è rumore end end end B. Listato in C Plugin.h #pragma once #include "LEEffect.h" #include <math.h> #include "ipp.h" #include "ipps.h" #define PLAYBUFFER_TXT "PlayBuffer" #define SCALAR_TXT "Scalar" #define VECTOR_TXT "Vector" #define VARLEN_TXT "VarLen" #define #define #define #define INT16_TXT INT32_TXT FLT32_TXT DBL64_TXT "Integer 16bit" "Integer 32bit" "Float 32bit" "double 64bit" #define DATATYPEBITMASK VECTOR|SCALAR|BUFFSTREAMING|VARLEN #define DATALENBITMASK DATAINT32|DATAINT16|DATAINT8|DATAFLOAT32|DATADOUBLE64|CUSTOM #define WIDTHDEF 75 #define WORK_BUFFERSIZE 128 #define ORDERLPC 10 107 #define IDXALPHA 1 #define IDXTHRESHOLD 2 #define PI 3.141592653589793 class PlugIn : public LEEffect { public: PlugIn(InterfaceType _CBFunction,void * _PlugRef,HWND ParentDlg); ~PlugIn(void) { } void __stdcall LESetName(char *Name); void __stdcall LEPlugin_Init(); int __stdcall LEPlugin_Process(PinType **Input,PinType **Output,LPVOID ExtraInfo); void __stdcall LEPlugin_Delete(void); bool __stdcall LEInfoIO(int index,int type, char *StrInfo); int __stdcall int __stdcall int __stdcall LEGetNumInput();}; int __stdcall LEGetNumOutput();}; LEGetNumInput(){return LEEffect::LEGetNumInput();}; LEGetNumOutput(){return LEEffect::LEGetNumOutput();}; LESetNumInput(int Val,PinType *TypeNewIn=0){return LESetNumOutput(int Val,PinType *TypeNewOut=0){return void __stdcall LESetParameter(int Index,void *Data,LPVOID bBroadCastInfo); int __stdcall LEGetParameter(int Index,void *Data); int __stdcall LESetDefPin(int index,int type, PinType *Info) { if (type==OUTPUT) { int FrameSz=CBFunction(this,NUTS_GETFRAME_RATE,0,(LPVOID)AUDIOPROC); Info->DataType=PLAYBUFFER; Info->Exclusive=true; Info->DataLen=FrameSz; Info->MaxDataLen=FrameSz; return OUTPUT; } if (type==INPUT) { int FrameSz=CBFunction(this,NUTS_GETFRAME_RATE,0,(LPVOID)AUDIOPROC); Info->DataType=PLAYBUFFER; Info->Exclusive=true; Info->DataLen=FrameSz; Info->MaxDataLen=FrameSz; return INPUT; } return -1; }; HWND __stdcall LEGetWndSet(){return 0;}; int __stdcall LEWinSetStatusChange(int NewStatus){return 0;}; void __stdcall LESaveSetUp(); void __stdcall LELoadSetUp(); void __stdcall LESampleRateChange(int NewVal,int TrigType){}; void __stdcall LEFrameSizeChange (int NewVal,int TrigType){}; 108 void __stdcall LEConnectionChange(int IOType,int Index,bool Connected){}; int __stdcall LEExtraInfoPinChange(int IOType,int Index,PinExtraInfoType ExInfo){return 0;}; void __stdcall LERTWatchInit(); private: // dichiarazione delle variabili e delle funzioni per VAD // dichiarazione delle variabili per VAD typedef struct { double mu[2]; double variance[2]; double X_t[2]; double chi[2]; double X_t_quadro[2]; } Parametri; Parametri par_p,par; double m_x, expt, var, k_x, f_x, f_x_p, f_x_p1, f_x_p2; double Alpha; double Threshold; double gamma_t, psum; int i,n_prec; double double double double *InputBuffer; *InputBufferOld; *OutputBuffer; *WorkBuffer; double *AutocorrWB; float *AutocorrWB_32f; float *LPCcoeff_32f; double *LPCcoeff; float *RC_lpc; float *pRREnergy; double *FIRcoeff; double *speechLPC; double *ResidualLPC; double *AutC; double *val_int; //valore di argomento per la kurtosis double *p_gauss, *P_i; double *p1, *p2, *p3; // dichiarazione delle funzioni per VAD void my_FIR(const Ipp64f* WorkBuffer, Ipp64f* FIRcoeff, Ipp64f* speechLPC) { //speechLPC è il segnale stimato int i; for (i=0; i<=2*WORK_BUFFERSIZE-1; i++) { if (i==0) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]; else if (i==1) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]; else if (i==2) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]; else if (i==3) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]; else if (i==4) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]; else if (i==5) 109 speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]; else if (i==6) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]+WorkBuffer[i-6]*FIRcoeff[6]; else if (i==7) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]+WorkBuffer[i-6]*FIRcoeff[6]+WorkBuffer[i7]*FIRcoeff[7]; else if (i==8) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]+WorkBuffer[i-6]*FIRcoeff[6]+WorkBuffer[i7]*FIRcoeff[7]+WorkBuffer[i-8]*FIRcoeff[8]; else if (i==9) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]+WorkBuffer[i-6]*FIRcoeff[6]+WorkBuffer[i7]*FIRcoeff[7]+WorkBuffer[i-8]*FIRcoeff[8]+WorkBuffer[i-9]*FIRcoeff[9]; else //if (i>=10) speechLPC[i]=WorkBuffer[i]*FIRcoeff[0]+WorkBuffer[i1]*FIRcoeff[1]+WorkBuffer[i-2]*FIRcoeff[2]+WorkBuffer[i-3]*FIRcoeff[3]+WorkBuffer[i4]*FIRcoeff[4]+WorkBuffer[i-5]*FIRcoeff[5]+WorkBuffer[i-6]*FIRcoeff[6]+WorkBuffer[i7]*FIRcoeff[7]+WorkBuffer[i-8]*FIRcoeff[8]+WorkBuffer[i-9]*FIRcoeff[9]+WorkBuffer[i10]*FIRcoeff[10]; }; return ; }; double Peak_Picking(const double* ResidualLPC) { double Peak=0, AutCorMax=0; int n,k,i; //calcolo della autocorrelazione normalizzata ippsZero_64f(AutC, 2*WORK_BUFFERSIZE); //for (n=0; n<=2*WORK_BUFFERSIZE1; n++) AutC[n]=0; for (n=0; n<=2*WORK_BUFFERSIZE-1; n++){ AutCorMax+=ResidualLPC[n]*ResidualLPC[n]; }; for (k=0; k<=2*WORK_BUFFERSIZE-1; k++){ for (n=k; n<=2*WORK_BUFFERSIZE-1; n++){ AutC[k]+= ResidualLPC[n]*ResidualLPC[n-k]; }; AutC[k]=AutC[k]/AutCorMax; }; //estrazione del picco di autocorrelazione escluso il picco per ritardo zero for (i=1; i<= 2*WORK_BUFFERSIZE-1; i++){ if (AutC[i]>=Peak) Peak=AutC[i]; }; return Peak; }; //funzione che calcola l'expectation di un vettore double my_expt(const double* ResidualLPC){ double expt=0; int i; for (i=0; i<=2*WORK_BUFFERSIZE-1; i++){ expt+=ResidualLPC[i]; }; expt/=2*WORK_BUFFERSIZE;//expt=expt/(2*WORK_BUFFERSIZE) return expt; }; //funzione che calcola la varianza a partire da un vettore e dal suo valor medio double my_variance(const double* ResidualLPC, const double expt){ 110 double variance=0; int i; for (i=0; i<=2*WORK_BUFFERSIZE-1; i++){ variance+=(ResidualLPC[i]-expt)*(ResidualLPC[i]-expt); }; variance/=2*WORK_BUFFERSIZE; return variance; }; //funzione che calcola la kurtosi a partire da un vettore dal suo valor medio e dalla sua varianza double my_kurtosis(const double* ResidualLPC, const double expt, const double variance){ double kurtosis=0; int i; for (i=0; i<=2*WORK_BUFFERSIZE-1; i++){ val_int[i]=(ResidualLPC[i]-expt)*(ResidualLPC[i]expt)*(ResidualLPC[i]-expt)*(ResidualLPC[i]-expt); }; kurtosis=my_expt(val_int)/(variance*variance)-3; return kurtosis; }; //funzione che numera le iterazioni int number_iteration(int n_prec){ n_prec++; return n_prec; }; //funzione che implementa l'algoritmo EM online void em_online(double f_x, double gamma_t, Parametri *par_p, Parametri *par){ int c; double p_gauss[2],psum, P_i[2]; for (c=0; c<=1; c++) p_gauss[c]=(1/sqrt(2*PI*par_p->variance[c]))*exp((-pow(f_x-par_p>mu[c],2))/(2*par_p->variance[c])); psum=p_gauss[0]+p_gauss[1]; for (c=0; c<=1; c++) P_i[c]=p_gauss[c]/psum; //calcola la probabilità di ogni classe(parlato o non parlato) for (c=0; c<=1 ; c++){ par->X_t[c]= par_p->X_t[c] + gamma_t*(P_i[c]*f_x - par_p->X_t[c]); //X_t aggiornati in par par->chi[c]= par_p->chi[c] + gamma_t*(P_i[c] - par_p->chi[c]); //chi aggiornati in par par->mu[c]= par->X_t[c]/par->chi[c]; //mu aggiornati in par par->X_t_quadro[c]= par_p->X_t_quadro[c] + gamma_t*(P_i[c]*(pow(f_x,2)) - par_p->X_t_quadro[c]); //X_t_quadro aggiornati in par par->variance[c]= fabs(par->X_t_quadro[c]/par->chi[c] - (pow(par>mu[c],2))); //variance aggiornati in par //if (par->variance[c]<=0.000001) // nel caso si blocchi l'algoritmo // par->variance[c]=0.00001; }; //if (abs(par->mu[1]-par->mu[2])<=0.000000001) //nel caso in cui le medie non si separino // par->mu[1]=0.1+par->mu[2]; return ; }; //funzione che implementa la decisione per stabilire se un frame è di parlato o no void decisione(Parametri par, double *OutputBuffer, double *InputBuffer, double f_x_p, double *p1, double *p2, double *p3){ int c; double psum, p_gauss[2]={0,0}, sommap[2]={0,0}; for (c=0; c<=1 ; c++) p_gauss[c]=(1/sqrt(2*PI*par.variance[c]))*exp((-pow(f_x_ppar.mu[c],2))/(2*par.variance[c])); psum=p_gauss[0]+p_gauss[1]; for (c=0;c<=1;c++) { P_i[c]=p_gauss[c]/psum; 111 sommap[c]=(P_i[c]+p1[c]+p2[c]+p3[c])/4; p3[c]=p2[c]; p2[c]=p1[c]; p1[c]=P_i[c]; }; if (par.mu[0]>=par.mu[1]) //il parlato è identificato dall'indice 0 if (sommap[0]>=Threshold) memcpy(OutputBuffer, InputBuffer, (WORK_BUFFERSIZE)*sizeof(double)); else ippsZero_64f(OutputBuffer, WORK_BUFFERSIZE); else //il parlato è identificato dall'indice 1 if (sommap[1]>=Threshold) memcpy(OutputBuffer, InputBuffer, (WORK_BUFFERSIZE)*sizeof(double)); else ippsZero_64f(OutputBuffer, WORK_BUFFERSIZE); return ; }; //funzione che aggiorna i paramentri dell'algoritmo EM online void ParUpdate(Parametri *par, Parametri *par_p){ int i; for (i=0; i<=1 ; i++){ par_p->mu[i]=par->mu[i]; par_p->variance[i]=par->variance[i]; par_p->X_t[i]=par->X_t[i]; par_p->chi[i]=par->chi[i]; par_p->X_t_quadro[i]=par->X_t_quadro[i]; }; return ; }; double SetAlphaValue(double NewValue); double GetAlphaValue(); double SetThresholdValue(double NewValue1); double GetThresholdValue(); }; //////////////////////////////////////////////////////////////////////////////////////// //// //////////////////////////////////// LOADER /////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //// LEEffect * __stdcall LoadEffect(InterfaceType _CBFunction,void *PlugRef,HWND ParentDlg) { return new PlugIn(_CBFunction,PlugRef,ParentDlg); } //////////////////////////////////////////////////////////////////////////////////////// //// ///////////////////////////////// GetStartUpInfo ////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //// void __stdcall LENUTSDefProps(char *NameEffect,int *Width, void *data) { strncpy(NameEffect,"VADonHOS",MAXNAME); 112 *Width=WIDTHDEF; if (data!=0) { StartUpNUTSProps *Info=(StartUpNUTSProps *)data; Info->NumInStartUp=1; Info->NumOutStartUp=1; } } Plugin.cpp #include #include #include #include #include #include #include #include "StdAfx.h" ".\plugin.h" <stdio.h> <stdlib.h> <math.h> "ipp.h" "ipps.h" "ippsc.h" PlugIn::PlugIn(InterfaceType _CBFunction,void * _PlugRef,HWND ParentDlg): LEEffect(_CBFunction,_PlugRef,ParentDlg) { //inizializzazione dei parametri iniziali quando verrà caricato il plug in //(costruttore dove allocare una volta per tutte le variabili, altrimenti lo mettiamo nella init) Alpha=0.9; Threshold=0.5; } int __stdcall PlugIn::LEPlugin_Process(PinType **Input,PinType **Output,LPVOID ExtraInfo) { int nSample; int n, index_i=0, index_j=0; //gestione della process suddivide il frame dato in pasto dalla scheda audio in altri sottoframe while(index_i < Input[0]->DataLen) { nSample = min(WORK_BUFFERSIZE - index_j, Input[0]->DataLen-index_i ); memcpy( &InputBuffer[index_j], &((double*)Input[0]->DataBuffer)[index_i], nSample*sizeof(double) ); memcpy( &((double*)Output[0]->DataBuffer)[index_i], &OutputBuffer[index_j], nSample*sizeof(double) ); index_i += nSample; index_j += nSample; if(index_j == WORK_BUFFERSIZE) { index_j = 0; // EXAMPLE with 50% OVERLAP-and-SAVE STRUCTURE memcpy( WorkBuffer, InputBufferOld, WORK_BUFFERSIZE*sizeof(double)); //memcopy copia n elementi dal secondo argomento al primo(in questo caso 128 elementi) memcpy( &WorkBuffer[WORK_BUFFERSIZE], InputBuffer, WORK_BUFFERSIZE*sizeof(double));// copia n elementi nella seconda parte di workbuffer memcpy( InputBufferOld, InputBuffer, WORK_BUFFERSIZE*sizeof(double));// copia inputbuffer in inputbufferold per la successiva iterazione for (i=0; i<=2*WORK_BUFFERSIZE-1; i++) WorkBuffer[i]/=32768; 113 ippsAutoCorr_64f(WorkBuffer, 2*WORK_BUFFERSIZE, AutocorrWB, ORDERLPC+1); //calcola l'autocorrelazione del frame(prende la parte positiva dell'autocorrelazione, da 0 a 255) ippsConvert_64f32f(AutocorrWB, AutocorrWB_32f , ORDERLPC+1); //casting di AutocorrWB da double a float ippsLevinsonDurbin_G729_32f(AutocorrWB_32f, ORDERLPC ,LPCcoeff_32f, RC_lpc, pRREnergy); //genera i coefficenti LPC ippsConvert_32f64f(LPCcoeff_32f, LPCcoeff, ORDERLPC+1); //casting di LPCcoeff da float a double FIRcoeff[0]=0; for (i=1 ; i<=ORDERLPC; i++) FIRcoeff[i]=(-1)*LPCcoeff[i]; //generazione dei tappi del filtro con i coefficenti LPC per sintetizzare il segnale d'ingresso my_FIR( WorkBuffer, FIRcoeff, speechLPC); //calcola attraverso il filtro LPC il segnale sintetizzato eccitandolo con il segnale d'ingresso for (i=0; i<=2*WORK_BUFFERSIZE-1 ; i++) ResidualLPC[i]=WorkBuffer[i]-speechLPC[i]; //calcolo del residuo LPC m_x=Peak_Picking( ResidualLPC); //preleva il picco dell'autocorrelazione del residuo LPC expt=my_expt(ResidualLPC); //calcola la media var=my_variance( ResidualLPC, expt); //calcola la varianza k_x=my_kurtosis( ResidualLPC, expt, var); //calcola la kurtosi f_x=m_x*log(1+k_x); //calcola la caratteristica(feature) f_x: la kurtosi migliorata n=number_iteration(n_prec); //parametro che tiene conto del numero di iterazioni e utilizzato per gamma_t gamma_t=pow(n,-Alpha); //calcola gamma di t: parametro che agisce sulla velocità di convergenza dell'algoritmo EM online //filtro iir del terzo ordine per la kurtosi migliorata necessario per effettuare una decisione efficiente f_x_p=(((f_x_p2+f_x_p1)/2+f_x_p)/2+f_x)/2; f_x_p2=f_x_p1; f_x_p1=f_x_p; em_online(f_x, gamma_t, &par_p, &par); //esegue un passo dell'algoritmo em online decisione( par, OutputBuffer, InputBuffer, f_x_p, p1, p2, p3); //esegue la decisione sul tipo di classe (parlato o non parlato) ParUpdate( &par, &par_p); //aggiorna i parametri per l'iterazione successiva n_prec=n; //memorizza il valore di iterazione per il ciclo successivo }; //fine if }; //fine while index_i=0; return COMPLETED; } void __stdcall PlugIn::LEPlugin_Init() { //va caricata qui l'allocazione e l'inizializzazione dei vettori; //non serve allocare variabili perchè sono già iniziallizzate nello stack (come le variabili di tipo struttura) WorkBuffer = (double*) malloc((2*WORK_BUFFERSIZE)*sizeof(double)); InputBufferOld = (double*) malloc(WORK_BUFFERSIZE*sizeof(double)); InputBuffer = (double*) malloc(WORK_BUFFERSIZE*sizeof(double)); OutputBuffer = (double*) malloc(WORK_BUFFERSIZE*sizeof(double)); AutocorrWB = (double*) malloc((ORDERLPC+1)*sizeof(double)); AutocorrWB_32f = (float*) malloc((ORDERLPC+1)*sizeof(float)); LPCcoeff_32f = (float*) malloc((ORDERLPC+1)*sizeof(float)); LPCcoeff = (double*) malloc((ORDERLPC+1)*sizeof(double)); RC_lpc = (float*) malloc((ORDERLPC)*sizeof(float)); pRREnergy = (float*) malloc((ORDERLPC+1)*sizeof(float)); 114 FIRcoeff = (double*) malloc((ORDERLPC+1)*sizeof(double)); speechLPC = (double*) malloc((2*WORK_BUFFERSIZE)*sizeof(double)); ResidualLPC = (double*) malloc((2*WORK_BUFFERSIZE)*sizeof(double)); AutC = (double*) malloc((2*WORK_BUFFERSIZE)*sizeof(double)); val_int = (double*) malloc((2*WORK_BUFFERSIZE)*sizeof(double)); p_gauss = (double*) malloc(2*sizeof(double)); P_i = (double*) malloc(2*sizeof(double)); p1 = (double*) malloc(2*sizeof(double)); p2 = (double*) malloc(2*sizeof(double)); p3 = (double*) malloc(2*sizeof(double)); ippsZero_64f(WorkBuffer, 2*WORK_BUFFERSIZE); ippsZero_64f(InputBufferOld, WORK_BUFFERSIZE); ippsZero_64f(InputBuffer, WORK_BUFFERSIZE); ippsZero_64f(AutocorrWB, ORDERLPC+1); ippsZero_32f(AutocorrWB_32f, ORDERLPC+1); ippsZero_32f(LPCcoeff_32f, ORDERLPC+1); ippsZero_64f(LPCcoeff, ORDERLPC+1); ippsZero_32f(RC_lpc, ORDERLPC); //La funzione LPC la dà comunque in uscita ma non serve nel nostro caso ippsZero_32f(pRREnergy, ORDERLPC+1); //La funzione LPC la dà comunque in uscita ma non serve nel nostro caso n_prec=1; gamma_t=0; psum=0; p_gauss[0]=0; p_gauss[1]=0; p1[0]=0; p1[1]=0; p2[0]=0; p2[1]=0; p3[0]=0; p3[1]=0; P_i[0]=0; P_i[1]=0; m_x=0; expt=0; var=0; k_x=0; f_x=0; f_x_p=0; f_x_p1=0; f_x_p2=0; par_p.mu[0]=0.050000000000; par_p.variance[0]=0.155000000000; par_p.X_t[0]=0.020; par_p.chi[0]=0.40; par_p.X_t_quadro[0]=0.06450; par_p.mu[1]=0.800000000000; par_p.variance[1]=1.900000000000; par_p.X_t[1]=0.480; par_p.chi[1]=0.60; par_p.X_t_quadro[1]=1.780; } void __stdcall PlugIn::LEPlugin_Delete() { free(WorkBuffer); free(InputBufferOld); free(InputBuffer); free(OutputBuffer); 115 free(AutocorrWB); free(AutocorrWB_32f); free(LPCcoeff_32f); free(LPCcoeff); free(RC_lpc); free(pRREnergy); free(FIRcoeff); free(speechLPC); free(ResidualLPC); free(AutC); free(val_int); free(p_gauss); free(P_i); free(p1); free(p2); free(p3); } bool __stdcall PlugIn::LEInfoIO(int index,int type, char *StrInfo) { if ((type==INPUT) && (index==0)) sprintf(StrInfo,"Speech[%d]",index); if ((type==OUTPUT) && (index==0)) sprintf(StrInfo,"VAD[%d]",index); return true; } void __stdcall PlugIn::LESetName(char *Name) { strncpy(Name,"VADonHOS",MAXNAME); } double PlugIn::SetAlphaValue(double NewValue) { if (NewValue!=Alpha) { CBFunction(this,NUTS_GETSECURETIME,NUTSSECURE,0); Alpha=NewValue; CBFunction(this,NUTS_RELEASESECURETIME,NUTSSECURE,0); CBFunction(this,NUTS_UPDATERTWATCH,IDXALPHA,0); } return Alpha; } double PlugIn::SetThresholdValue(double NewValue1) { if (NewValue1!=Threshold) { CBFunction(this,NUTS_GETSECURETIME,NUTSSECURE,0); Threshold=NewValue1; CBFunction(this,NUTS_RELEASESECURETIME,NUTSSECURE,0); CBFunction(this,NUTS_UPDATERTWATCH,IDXTHRESHOLD,0); } return Threshold; } double PlugIn::GetAlphaValue() { return Alpha; } 116 double PlugIn::GetThresholdValue() { return Threshold; } void __stdcall PlugIn::LESetParameter(int Index,void *Data,LPVOID bBroadCastInfo) { if (Index==IDXALPHA) { double NewValue=*((double*)Data); SetAlphaValue(NewValue); } if (Index==IDXTHRESHOLD) { double NewValue1=*((double*)Data); SetThresholdValue(NewValue1); } } int { __stdcall PlugIn::LEGetParameter(int Index,void *Data) if (Index==IDXALPHA) { *((double*)Data)=GetAlphaValue(); } if (Index==IDXTHRESHOLD) { *((double*)Data)=GetThresholdValue(); } return 0; } void __stdcall PlugIn::LESaveSetUp() { double AlphaTmp=GetAlphaValue(); CBFunction(this,NUTS_WRITEFILE,sizeof(double),&AlphaTmp); double ThresholdTmp=GetThresholdValue(); CBFunction(this,NUTS_WRITEFILE,sizeof(double),&ThresholdTmp); } void __stdcall PlugIn::LELoadSetUp() { double AlphaTmp; CBFunction(this,NUTS_READFILE,sizeof(double),&AlphaTmp); SetAlphaValue(AlphaTmp); double ThresholdTmp; CBFunction(this,NUTS_READFILE,sizeof(double),&ThresholdTmp); SetThresholdValue(ThresholdTmp); } void __stdcall PlugIn::LERTWatchInit() { WatchType NewWatch; memset(&NewWatch,0,sizeof(WatchType)); NewWatch.EnableWrite=true; NewWatch.LenByte=sizeof(double); NewWatch.TypeVar=WTC_DOUBLE; NewWatch.IDVar=IDXALPHA; sprintf(NewWatch.VarName,"Alpha"); CBFunction(this,NUTS_ADDRTWATCH,0,(LPVOID)&NewWatch); WatchType NewWatch1; memset(&NewWatch1,0,sizeof(WatchType)); NewWatch1.EnableWrite=true; NewWatch1.LenByte=sizeof(double); NewWatch1.TypeVar=WTC_DOUBLE; NewWatch1.IDVar=IDXTHRESHOLD; sprintf(NewWatch1.VarName,"Threshold"); 117 CBFunction(this,NUTS_ADDRTWATCH,0,(LPVOID)&NewWatch1); } 118 Bibliografia [1] D. Cournapeau and T. Kawahara “Voice Activity Detection Based on High Order Statistics and Online EM Algorithm” IEICE Trans. Inf. & Syst., Vol. E91–D, NO.12 December 2008. [2] L.R. Rabiner and B.H. Juang, “Fundamentals of speech recognition” Prentice Hall, 1993. [3] B. Kingsbury, G. Saon, L. Mangu, M. Padmanabhan, and R. Sarikaya, “Robust speech recognition in noisy environments: The 2001 IBM Spine evaluation system” ICASSP, 2002. [4] G. Lathoud and I. McCowan, “Location based speaker segmentation" Proc. 2003 IEEE International Conference on Acoustics, Speech, and Signal Processing (ICASSP-03), 2003. [5] T. Pfau, D. Ellis, and A. Stolcke, “Multispeaker speech activity detection for the ICSI meeting recorder” Proc. IEEE Automatic Speech Recognition and Understanding Workshop, 2001. [6] E. Nemer, R. Goubran, and S. Mahmoud, “Robust voice activity detection using higher-order statistics in the LPC residual domain” IEEE Trans. Speech Audio Process., vol.9, no.3, pp.217–231, 2001. [7] K. Li, M.S.S. Swamy, and M.O. Ahmad, “An improved voice activity detection using high order statistics” IEEE Trans. Speech Audio Process., vol.13, no.5, pp.965–974, 2005. [8] R.J. McAulay and T.F. Quatieri, “Speech analysis/synthesis based on a sinusoidal representation” IEEE Trans. Acoust. Speech Signal Process., vol.34, no.4, pp.744– 754, 1986. [9] “ITU-T: A silence compression scheme for G.729 optimized for terminals conforming to recommendation v.70, annex B.” Nov. 1996. [10] N. Kitaoka, T. Yamada, S. Tsuge, C. Miyajima, T. Nishiura, M. Nakayama, Y. Denda,M. Fujimoto, K. Yamamoto, T. Takiguchi, and S. Nakamura, “CENSREC-1- C: Development of evaluation framework for voice activity detection under noisy environment” IPSJ SIG Technical Report, 2006. [11] S. Ahmadi and A.S. Spanias, “Cepstrum-based pitch detection using a new statistical V/UV classification algorithm” IEEE Trans. Speech Audio Process., vol.7, no.3, pp.333–338, May 1999. [12] J.K. Shah, A.N. Iyer, B.Y. Smolenski, and R.E. Yantorno, “Robust voiced unvoiced classification using novel features and Gaussian mixture model” IEEE ICASSP’04, 2004. [13] Q. Li, J. Zheng, Q. Zhou, and C.H. Lee, “A robust, real-time endpoint detector with energy normalization for ASR in adverse environments” ICASSP01, IEEE, 2001. [14] L.T. DeCarlo, “On the meaning and use of kurtosis” Psychological Method, vol.2, pp.292–303, 1997. [15] H.M. Finucan, “A note on kurtosis” J. Royal Statistical Society. Series B (Methodological), vol.26, pp.111–112, 1964. [16] S. Basu, “A linked-HMM model for robust voicing and speech detection” IEEE Int. Conf. Acoustics, Speech, and Signal Processing (ICASSP ’03), 2003. [17] I. Shafran and R. Rose, “Robust speech detection and segmentation for real-time ASR applications” IEEE Int. Conf. Acoustics, Speech, and Signal Processing (ICASSP ’03), pp.432–435, 2003. [18] A.P. Dempster, N.M. Laird, and D.B. Rubin, “Maximum likelihood from incomplete data via the EM algorithm” J. Royal Statistical Society. Series B (Methodological), vol.39, pp.1–38, 1977. [19] O. Cappe, M. Charbit, and E. Moulines, “Recursive EM algorithm with applications to DOA estimation” Proc. 2006 IEEE International Conference on Acoustics, Speech, and Signal Processing, ICASSP 2006, 2006. [20] M. Sato and S. Ishii, “On-line EM algorithm for the normalized Gaussian network” Neural Comput., vol.12, pp.407–432, 2000. [21] H.J. Kushner and G.G. Yin, Stochastic approximation algorithms and applications, Springer-Verlag, 1997. [22] Levinson N., The Wiener Root Mean Square (RMS) Error Criterion in Filter Design and Prediction, Journal of Mathematics and Physics, vol. 25, pp. 214-218, 1947. 120 [23] Russell Stuart J., Norvig Peter, “Intelligenza artificiale – Un approccio moderno” vol. 2, Pearson Education Italia. [24] Deitel H., Deitel P., “C corso completo di programmazione” Apogeo. 121