1. Introduction

Le but de ce projet est de réaliser, sous Matlab, un reconnaisseur vocal basé sur l'algorithme "Dynamic Time Warping" appellé plus communément DTW. Le cadre de travail de ce reconnaisseur est de travailler avec des mots isolés, un petit vocabulaire et un seul locuteur. La reconnaissance nécessite au prélable une analyse acoustique, qui se fera au moyen d'une analyse LPC (Linear Predictive Coding). Une base de données de dix échantillons préenregistrés, à savoir le nom de dix villes belges sert de référence pour réaliser la comparaison. Le test de validité de notre application s'effectue en tentant de reconnaître des échantillons différents enregistrés par le même locuteur.

Nous allons comparer différentes variantes d'analyse afin d'observer leurs performances mais aussi la charge de calculs qu'elles impliquent. Nous complèterons cette étude par une analyse de l'influence du bruit sur les méthodes. 

Pour nous aider dans cette conception nous utiliserons les bibliothèques VoiceBox et Signal pour Matlab. L'ensemble des scripts réalisés se trouvent en annexe.

- Echantillons de référence :    Bruxelles, Mons, Namur, Liège, Charleroi, Anvers, Bruges, Arlon, Hasselt et Ostende.

- Echantillons de test :             Bruxelles, Mons, Namur, Liège, Charleroi, Anvers, Bruges, Arlon, Hasselt et Ostende.

.

2. Principes théoriques de reconnaissance

2.1. Reconnaissance par déformation temporelle linéaire

Afin d'effectuer cette analyse, il est d'abord nécessaire d'effectuer une analyse LPC qui nous permet d'extraire les coefficients de prédiction ai. Cette analyse sera réalisée en prenant une tranche de 30ms du signal toutes les 10ms. A chacune de ces tranches, on appliquera une fenêtre de Hamming et ensuite on réalisera l'analyse LPC proprement dite. Une fois réalisée l'analyse de tous les échantillons,  il est assez simple de pouvoir comparer les ai ou plus exactement de mesurer la distance de l'échantillon à identifier vis-à-vis des échantillons de référence. Il est à noter qu'afin d'éviter des calculs inutiles, les coefficients de référence sont calculés une fois pour toute et sauvés dans un fichier. L'ensemble des tests réalisés sera exposé dans la partie 3.

Cependant, si l'on veut parler de distance entre deux vecteurs, il est nécessaire d'avoir des vecteurs de dimension identique. C'est pourquoi, avant de calculer la distance, on établit une correspondance linéaire des axes du temps. Cette solution consiste simplement à associer plusieurs vecteurs de référence à un seul vecteur d'entrée (ou inversément selon la séquence la plus longue).

La figure 1 illustre ce principe. X représente le vecteur à reconnaître et Yk un des vecteurs de référence.

figure 1

Cette étape terminée, on peut calculer la distance de l'échantillon à tester par rapport à l'ensemble des références. On utilise dans ce cas la distance euclidienne. D'autres distances plus performantes, tenant compte de la variance des coefficients par exemple comme la distance de Mahalanobis, aurait pu être envisagée mais nous nous limitons à cette distance qui est la plus simple à calculer et qui permet d'obtenir des résultats satifaisants.

distance euclidienne entre 2 vecteurs

Une fois les dix distances obtenues, il suffit de rechercher la plus petite parmi celles-ci et de donner à l'utilisateur le résultat de la ville correspondante. On note à ce stade que cette reconnaissance s'effectue au préalable avec des échantillons préformatés, c'est-à-dire, où les blancs de début et fin d'échantillons ont été éliminés.

Cette technique est la plus simple à mettre en oeuvre, mais elle ne tient pas compte des variations temporelles de la voix. En effet, un locuteur ne prononce jamais deux fois le même mot de la même façon. L'approche qui va suivre nous permet de faire face à ce problème.

2.2. Reconnaissance par déformation temporelle dynamique (DTW)

Afin d'adapter au mieux l'algorithme à la parole, il serait intéressant de disposer d'un outil qui puisse tenir compte des compressions et extensions temporelles qui sont observées lors de la prononciation plus ou moins rapide au sein d'un mot. L'algorithme DTW ( Dynamic Time Warping ) tient compte de ce phénomène. Le principe de base est d'essayer de trouver le chemin optimal à parcourir parmi l'ensemble des distances entre les vecteurs.

Plus précisément, pour chaque référence Yk, on considérera donc une matrice D de dimension (N * J(k)) (où N et J(k) sont respectivement le nombre de vecteurs dans la séquence de test et de référence). A chaque entrée (n, j) de cette matrice on y associe la distance locale d(xn, yjk) définie comme précédemment. Pour rechercher la meilleure distance D(X, Yk) entre la séquence de test X et la séquence de référence Yk, il suffit alors de rechercher le "chemin" dans cette matrice D de façon à minimiser la somme des distances locales rencontrées pour aller d'un point initial (1,1), correspondant au début des deux séquences, à un point final (N,J(k)), correspondant à la fin des deux séquences.

La mise en oeuvre de cet algorithme se fait alors de façon simple, et on peut montrer que la distance optimale est obtenue en calculant, pour chaque entrée (n, j) la distance accumulée D(n, j) correspondant à la distance optimale que l'on obtient en comparant les deux sous-séquences correspondant aux n premiers vecteurs de test et aux j premiers vecteurs de référence. En vertu du principe de programmation dynamique, on peut alors facilement montrer que cette distance peut se calculer en utilisant la récurrence suivante :

                           D(n, j) = d(n, j) +  minp(n, j) {D(p(n, j))}

   avec :     - p(n,j) : ensemble des prédécesseurs possibles de l'élément (n,j)

                 - D(n,j) : distance globale

                 - d(n,j) : distance locale

La figure illustre un chemin parcouru entre deux vecteurs de longueur différente.

figure 2

Les prédécesseurs sont choisis afin d'obtenir une trajectoire monotone et plausible. Celle-ci doit rester le plus possible près de la diagonale. Un choix de prédécesseur possible est par exemple celui illustré à la figure 3. D'autres choix sont possibles mais celui-ci est le plus simple. On peut également associer des pénalités aux prédécesseurs moins probables afin de favoriser le meilleur chemin.

 figure 3

n : indice temporel de la fenêtre de test

j : indice temporel de la fenêtre de référence

L'algorithme implémenté tient compte des zones où le calcul des distances est obsolète. C'est ainsi que la zone supérieure gauche et la zone inférieure droite ne sont pas calculées. Les distances locales associées sont mises à une valeur très élevée afin que le chemin n'y passe pas.

Il est à noter que les coefficients ai n'ont aucune signification physique et ne sont que des facteurs de pondération dans une combinaison linéaire tentant de prédire l'echantillon suivant. Ils sont très sensibles aux variations du spectre de la voix. En effet, une faible variation de l'enveloppe spectrale peut entraîner de grands changements dans ces coefficients. La robustesse de cette méthode est donc faible et les résultats obtenus (exposés au point 3), bien qu'honorables, pourront encore être améliorés.

A nouveau, c'est la distance minimale, parmi les dix distances globales calculées, qui permet de déterminer la ville reconnue.

2.3. Reconnaissance par DTW et utilisation des coefficients parcor

Toujours dans le but d'améliorer la qualité du processus de reconnaissance, on va cette fois non plus modifier la méthode de calcul de la distance mais remplacer les coefficients ai par les ki qui sont en fait les coefficients parcor (pour corrélation partielle) . On va donc ainsi modifier la méthode de représentation de l'information. Pour cela, on effectuera sous matlab une conversion des paramètres ai vers les paramètres ki à l'aide de la fonction " LPCAR2RF". On calculera ensuite les distances par le DTW de manière identique à ce qui a été réalisé dans le paragraphe précédent. Les coefficients de parcor présentent l'avantage d'avoir une plus petite sensibilité aux écarts que les ai. Ils proviennent de l'algorithme de Levinson et peuvent être interprétés physiquement comme le quotient de surfaces de tubes acoustiques en série formant le conduit vocal. 

Il existe une correspondance biunivoque entre ce type de coefficients (ki) et ceux de prédiction (ai) et peuvent donc être calculés à partir de ceux-ci et inversément. Tout ceci a pour conséquence d'améliorer la qualité de la reconnaissance quand elle est basée sur le calcul des ki puisque que l'on représente l'information sous une meilleure forme.

2.4. Reconnaissance par DTW et utilisation des coefficients cepstraux

Ici comme dans le paragraphe précédent, on ne modifie pas la méthode de calcul de la distance  mais on remplace les coefficients ai par les coefficients cepstraux, à savoir les ci. Le cepstre est basé sur une connaissance du mécanisme de production de la parole. On part de l’hypothèse que la suite d'échantillons constituant le signal vocal est le résultat de la convolution du signal de la source par le filtre correspondant au conduit. Il est possible, par un filtrage temporel (liftrage), de séparer dans le signal, la contribution de la source de celle du conduit. Les premiers coefficients cepstraux contiennent l’information relative au conduit. Cette contribution devient négligeable à partir d’un échantillon n0. Les pics périodiques visibles au-delà de n0, reflètent les impulsions de la source. 

Comme précédemment, on va modifier la méthode de représentation de l'information. Pour cela, on effectuera sous matlab une conversion des paramètres ai vers les paramètres ci à l'aide de la fonction " LPCAR2CC". On calculera ensuite les distances cumulées par le DTW de manière identique à ce qui a été réalisé dans le paragraphe, précédemment. Ces coefficients permettent d'améliorer nettement la qualité de la reconnaissance.

 

3. Tests de reconnaissance

Pour la comparaison des différentes méthodes de traitement testées sur les échantillons non bruités, nous nous sommes basés sur les distances séparant le mot testé et les différentes références de la base de données. En effet, une distance minimale nous fournit une confiance maximale, l'indicateur retenu est l'inverse de la distance. Cette dernière est normalisée par rapport au maximum des inverses des distances. On appelera cet indicateur "niveau de confiance". Cette normalisation est également nécessaire afin de permettre la comparaison entre les distances obtenues par la déformation temporelle linéaire et la DTW.

niveau de confiance (%) = 100 * [id / max(id)]

Cette technique est appliquée afin de tester la reconnaissance des échantillons (Arlon, Charleroi, Bruxelles). La cote de 100% est donc attribuée à l'élément reconnu. L'analyse de ces comparatifs met donc en évidence le pouvoir discriminant des diverses méthodes. Celui-ci, d'une manière générale, augmente au fur et à mesure que l'on applique les quatres méthodes vues précédemment. On ajoute également une reconnaissance sans détection de blancs en utilisant une déformation temporelle linéaire, afin de visualiser l'influence de cette détection.

Il est à noter que l'effacement des blancs a été effectué au moyen d'un éditeur de son externe à Matlab. C'est également via ce logiciel que l'ensemble des sons a été normalisé.




Reconnaissance du mot "Arlon"


Reconnaissance du mot "Bruxelles"


Reconnaissance du mot "Charleroi"

 

Les tests ci-dessus sont des tests de laboratoire. Elles sont toutes efficaces avec détection de blancs néanmoins la déformation temporelle linéaire sans détection de blancs montre déjà ses faiblesses. Afin de départager les différentes techniques, il est utile de procéder à une étude de RSB qui nous placera dans un cadre plus réel, c'est à dire en présence de bruit.

4. Etude de l'influence du bruit

4.1. Position du problème

Le pouvoir discriminant est une qualité essentielle de la reconnaissance, il est impératif de montrer la fiabilité des méthodes dans des conditions réelles d'utilisation c'est-à-dire en présence de bruit dans le signal à reconnaître. En effet, les conditions des tests précédents étaient idéales : utilisation d'un micro de qualité et abscence de bruit ambiant. C'est pour cette raison que nous avons tout d'abord volontairement ajouté du bruit à nos échantillons et cela pour différentes valeurs de RSB et dans un second temps, nous avons mis en évidence le taux de reconnaissance des diverses méthodes pour un RSB fixé. 

4.2. Méthodologie de bruitage

Pour bruiter nos échantillons, nous superposons à notre échantillon un bruit blanc de moyenne nulle et de variance unitaire. Celui-ci est obtenu par utilisation de la fonction randn() fournie dans Matlab. Le vecteur ainsi généré est de longueur identique à celle de l'échantillon. Afin de pouvoir introduire la notion de RSB, et vu que l'amplitude de notre bruit blanc est supérieure à celle de notre échantillon, nous divisons le vecteur de bruit blanc par une constante gamma avant superposition à l'échantillon. Ceci nous permettra donc d'ajuster la variance du bruit blanc, puisque le coefficient gamma modifie de manière inversément quadratique la variance. Le RSB est donc ajustable à notre guise. 

                Soit x : vecteur échantillon

                Randn () -->  bruit blanc  -->  bruit blanc/gamma -> x+(bb/gamma) 

                => RSB = fct (gamma)

4.3. Calcul du RSB

Le calcul du RSB ne peut se faire que sur un signal stationnaire et le signal de parole ne l'est pas.Le RSB total du signal donc est obtenu en effectuant la moyenne des RSB obtenus pour des tranches de 30 ms du signal échantillonné. C'est pourquoi, nous allons découper l'échantillon en tranches de 30 ms et calculer le RSB pour chacune de ces tranches. En réalisant une moyenne de toutes ces valeurs, nous obtiendrons le RSB global du signal.

Cependant, un problème subsiste. Ce RSB n'est pas représentatif puisqu'il fait appel à une moyenne sur un ensemble restreint d'éléments. Néanmoins une solution existe. Elle consiste à prendre le même locuteur et à lui faire réaliser un échantillon de durée plus longue (typiquement 1 minute). Sur cet échantillon, nous calculons le RSB et nous obtenons ainsi un RSB plus représentatif. Cette solution présente néanmoins un inconvénient pour des amplitudes élevées du bruit blanc. En effet, un signal de parole comporte des blancs au sein d'un texte et même au sein d'un  mot. Pour s'en rendre compte, il suffit d'observer l'oscillogramme d'un signal de parole. Pour un niveau important de bruit, le niveau du bruit dépasse le niveau du signal, pour une zone de silence. C'est pour cette raison qu'à ces instants, on observe un RSB négatif.  Il est à noter que l'énergie moyenne du signal d'une minute est inférieure à ceux des échantillons en raison de silence plus nombreux. Tout ceci nous amène à avoir un RSB d'une valeur inférieure à la réalité lorsque gamma diminue. Afin d'améliorer cette situation, nous avons, lors du calcul de la moyenne du RSB, négligé les valeurs négatives de RSB. Nous constatons ainsi une une valeur plus correcte du RSB lorsque gamma diminue.

Afin d'y voir plus clair, nous calculerons, pour un gamma fixé, le RSB moyen pour les dix échantillons testés. Celui-ci sera utilisé comme ordre de grandeur. Il faut donc considérer le RSB de l'échantillon d'une minute comme base de comparaison mais sa valeur est plus indicative que significative.

+ =

4.4. Essais

Le tableau ci-dessous présente l'influence du bruit sur les différentes méthodes utilisées.

Pour chacune des méthodes, les dix mots ont été bruité avec un RSB donné et une reconnaissance a été effectuée. Les nombres à droite des méthodes représentent le nombre de mots correctement reconnus.

RSB échantillon 1 min (dB)

90

80

70

60

50

40

30

20

15

10

2,6

-4

RSB échantillon 1 min sans blanc (dB)

101

95

90

86

80

72

65

58

54

50

45

40

RSB moyen sur 10 échantilllons (dB) 

106

97

87

78

68

59

49

40

36

33

25

19

Déformation linéaire

10

10

9

8

8

5

5

4

1

1

1

1

DTW - ai

10

10

10

10

9

9

7

5

3

2

2

1

DTW - Coeff Parcor

10

10

10

10

10

9

7

7

6

3

3

3

DTW - Coeff Cepstraux

10

10

10

10

10

10

10

10

9

8

6

4

Nous constatons que pour des valeurs en amplitude de bruit faible, toutes nos méthodes sont performantes, mais lorsque celui-ci augmente, elles vont successivement toutes "décrocher". On constate que la méthode qui consiste à utiliser une déformation temporelle linéaire se révèle peu efficace dès que le bruit atteint un niveau seuil relativement faible. Cette méthode se révèle donc vraiment inefficace pour des conditions non optimales de prise de son du locuteur. La reconnaissance par DTW nous amène une amélioration qui se ressent au niveau de la sensibilité au bruit. En effet, calculer les ai et utiliser une DTW permet de gagner une vingtaine de décibels de sensibilité au bruit. L'utilisation des coefficients parcor permet encore de gagner une dizaine de décibels.Cependant, c'est l'utilisation des coefficients cepstraux qui fait apparaître une nette amélioration de la reconnaissance en présence de bruit. Effectivement, on gagne encore une trentaine de décibels en utilisant ce type de coefficients.

Nous observons que le RSB calculé sur l'échantillon d'une minute n'est pas réaliste mais que le RSB moyen réalisé sur l'ensemble des échantillons l'est plus. Un mot est toujours reconnu : Hasselt. En effet, ce mot est mot fortement non voisé et s'apparente donc à du bruit. En présence de signal amplement bruité, ce dernier est donc identifié a cette ville.



- Echantillons Bruges :    Bruges RSB = 80dB, Bruges RSB = 30dB, Bruges RSB = -4dB

- Echantillons Hasselt :    Hasselt RSB = 80dB, Hasselt RSB = 30dB, Hasselt RSB = -4dB

 

5. Comparaison du nombre d'opérations réalisées

S'il est vrai que les coefficients de parcor présentent un avantage majeur au niveau du pouvoir discriminant et de la sensibilité au bruit, il est tout de même nécessaire de comparer ce que ces diverses méthodes engendrent comme charge de calcul lors d'un processus de reconnaissance vocale.

En observant ce graphique qui présente, pour trois villes différentes, le nombre d'opérations nécessaires pour chacune des quatre méthodes implémentées, on constate que, bien que la déformation temporelle linéaire ne soit pas une méthode très performante, elle ne nécessite pas une charge de calcul importante. Qui plus est, on constate même au travers de cet exemple que c'est le calcul de la DTW qui engendre énormément de calculs car la conversion de coefficients ai en  ki ou ci ne change pas grand chose au niveau charge de travail. Parmis ces trois dernières méthodes, la DTW avec les coefficients parcor est certainement, au vu de ce graphique, la méthode nécessitant le plus de charge de travail.

 

6. Conclusion

Ce travail a permis de visualiser quelques méthodes de reconnaissance vocale, d'estimer leur qualité et de pouvoir visualiser quelles étaient leurs sensibilités au bruit. On constate que parmi ces méthodes, une seule semble pouvoir offrir un service de meilleure qualité. Il s'agit de la méthode du calcul des coefficients cepstraux et de calcul de la distance au travers d'une DTW. 

Ce projet a également permis de constater que ces techniques pouvaient être appréhendées au travers d'un outil de développement simple tel que Matlab. Il également clair que si nos blancs ont été manuellement retirés , dans une application réelle, il faudrait prévoir la mise en place d'un détecteur d'instants de parole. Dans un processus temps réel, il faudra tenir compte de la charge de calcul élevée engendrée par le calcul de la DTW. Il faudrait donc faire appel à des langages plus performants tel que le C pour permettre d'embarquer de tels algorithmes dans les GSM par exemple.


7. Références

-    "An Introductory Course on Speech Processing", T. Dutoit, FPMs

-    "Traitment de la parole", R. Boite, H. Bourlard, T. Dutoit, Joël Hancq et H. Leich.

-     "Etude et reconnaissance de la parole", Philippe Alluin , http://perso.aricia.fr/alluin/parole/

8. Annexe - Scripts Matlab

8.1. Création des références

% Calcul des coefficients ai de l'analyse LPC pour chaque référence

a01 = analyselpc('01_bruxelles.wav');
a02 = analyselpc('02_mons.wav');
a03 = analyselpc('03_namur.wav');
a04 = analyselpc('04_liege.wav');
a05 = analyselpc('05_charleroi.wav');
a06 = analyselpc('06_anvers.wav');
a07 = analyselpc('07_bruges.wav');
a08 = analyselpc('08_arlon.wav');
a09 = analyselpc('09_hasselt.wav');
a10 = analyselpc('10_ostende.wav');

wk1write('a01.dat',a01);
wk1write('a02.dat',a02);
wk1write('a03.dat',a03);
wk1write('a04.dat',a04);
wk1write('a05.dat',a05);
wk1write('a06.dat',a06);
wk1write('a07.dat',a07);
wk1write('a08.dat',a08);
wk1write('a09.dat',a09);
wk1write('a10.dat',a10);

8.2. Analyse LPC

function a = analyselpc(fichier)

[x,Fe] = readwav(fichier,'s');

% Calcul d'une fenêtre de Hamming de 30 ms
fen_ham = hamming(3*Fe/100);

% Création d'un vecteur de tranche de 30 ms toutes les 10 ms
x_sg=[];
for i =1:(floor(length(x)/(Fe/100))-2)
x_sg = [x_sg ; x((i-1)*Fe/100:(i+2)*Fe/100)];
end
x_sg=[x_sg ; x(Fe/100*(floor(length(x)/(Fe/100))-2):length(x))];

% Analyse LPC sur des tranches de 30 ms
a = lpcauto(x_sg,10,3*Fe/100,fen_ham);

8.3. Calcul de la distance euclienne

function distance = distvect(a,b)

% Calcul de la distance euclidenne entre 2 vecteurs de taille differente provenant d'une analyse LPC
[long_a,pole]=size(a);
[long_b,pole]=size(b);

distance = 0;

if long_a > long_b

% Initialisation
pente = long_a/long_b;

for i=1:long_b
j = round(pente*i);
distance = distance + sqrt((a(j,:)-b(i,:))*(a(j,:)-b(i,:))');
end
else
pente = long_b/long_a;
for j=1:long_a
i = round(pente*j);
distance = distance + sqrt((a(j,:)-b(i,:))*(a(j,:)-b(i,:))');
end
end

8.4. Calcul de la DTW

function distance = distdtw(a_test,a_ref)

% Calcul le chemin optimum selon l'algo de la DTW entre deux tableaux de vecteurs
% [dist] = distdtw(a_test,a_ref)


[long_ref,pole] = size(a_ref);
[long_test,pole] = size(a_test);

dist_local=zeros(long_ref,1);
dist_acc=zeros(long_ref,2);

% Initialisation : Calcul de la 1ère colonne

dist_local(1,1) = sqrt((a_ref(1,:)-a_test(1,:))*(a_ref(1,:)-a_test(1,:))');

dist_acc(1,2) = dist_local(1,1);

for i=2:long_ref
dist_acc(i,2) = 1e12;
end

% Calcul pour l'ensemble de la matrice

for k=2:long_test
% Copie de la colonne de droite dans la colonne de gauche
dist_acc(:,1)=dist_acc(:,2);
% Calcul des nouvelles distances uniquement dans la zone autorisée

a = round(2*k+long_ref-2*long_test);
b = round(-1+2*k);

for l = max([a 1]): min([b long_ref])
dist_local(l,1) = sqrt((a_ref(l,:)-a_test(k,:))*(a_ref(l,:)-a_test(k,:))');
end

% Calcul des distances accumulées uniquement dans la zone autorisée
if a < 2
dist_acc(1,2) = dist_local(1,1) + dist_acc(1,1);
else
dist_acc(1,2) = 1e12;
end

for l = 2:(a-1)
dist_acc(l,2) = 1e12;
end

for l = max([2,a]): min([long_ref,b])
dist_acc(l,2) = dist_local(l,1)+min([dist_acc(l-1,2) dist_acc(l,1) dist_acc(l-1,1)]);
end

for l = (b+1):long_ref
dist_acc(l,2) = 1e12;
end
end

distance = dist_acc(long_ref,2);

8.5. Reconnaissance par déformation temporelle linéaire

function [nom,dist] = analyse1(fichier)

a01 = wk1read('a01.dat');
a02 = wk1read('a02.dat');
a03 = wk1read('a03.dat');
a04 = wk1read('a04.dat');
a05 = wk1read('a05.dat');
a06 = wk1read('a06.dat');
a07 = wk1read('a07.dat');
a08 = wk1read('a08.dat');
a09 = wk1read('a09.dat');
a10 = wk1read('a10.dat');
nom_ref=['bruxelles'; 'mons '; 'namur '; 'liege '; 'charleroi'; 'anvers '; 'bruges '; 'arlon '; 'hasselt '; 'ostende '];

a_test = analyselpc(fichier);

dist = [distvect(a_test,a01); distvect(a_test,a02); distvect(a_test,a03);distvect(a_test,a04); distvect(a_test,a05); distvect(a_test,a06); distvect(a_test,a07); distvect(a_test,a08); distvect(a_test,a09); distvect(a_test,a10)];

[nb,indice]=min(dist);

nom = nom_ref(indice,:);

8.6. Reconnaissance par DTW

function [nom,dist] = analyse1(fichier)

a01 = wk1read('a01.dat');
a02 = wk1read('a02.dat');
a03 = wk1read('a03.dat');
a04 = wk1read('a04.dat');
a05 = wk1read('a05.dat');
a06 = wk1read('a06.dat');
a07 = wk1read('a07.dat');
a08 = wk1read('a08.dat');
a09 = wk1read('a09.dat');
a10 = wk1read('a10.dat');
nom_ref=['bruxelles'; 'mons '; 'namur '; 'liege '; 'charleroi'; 'anvers '; 'bruges '; 'arlon '; 'hasselt '; 'ostende '];

a_test = analyselpc(fichier);

dist = [distvect(a_test,a01); distvect(a_test,a02); distvect(a_test,a03);distvect(a_test,a04); distvect(a_test,a05); distvect(a_test,a06); distvect(a_test,a07); distvect(a_test,a08); distvect(a_test,a09); distvect(a_test,a10)];

[nb,indice]=min(dist);

nom = nom_ref(indice,:);

8.7. Reconnaissance par DTW avec coefficients parcor

function [nom,dist] = analyse3(fichier)

% Analyse DTW sur les coefficients ki (parcor)
a01 = wk1read('a01.dat');
a02 = wk1read('a02.dat');
a03 = wk1read('a03.dat');
a04 = wk1read('a04.dat');
a05 = wk1read('a05.dat');
a06 = wk1read('a06.dat');
a07 = wk1read('a07.dat');
a08 = wk1read('a08.dat');
a09 = wk1read('a09.dat');
a10 = wk1read('a10.dat');
nom_ref=['bruxelles'; 'mons '; 'namur '; 'liege '; 'charleroi'; 'anvers '; 'bruges '; 'arlon '; 'hasselt '; 'ostende '];

% Conversion ai -> ki
k01=lpcar2rf(a01);
k02=lpcar2rf(a02);
k03=lpcar2rf(a03);
k04=lpcar2rf(a04);
k05=lpcar2rf(a05);
k06=lpcar2rf(a06);
k07=lpcar2rf(a07);
k08=lpcar2rf(a08);
k09=lpcar2rf(a09);
k10=lpcar2rf(a10);

a_test = analyselpc(fichier);
k_test = lpcar2rf(a_test);

dist = [ distdtw(k_test,k01) ; distdtw(k_test,k02) ; distdtw(k_test,k03) ; distdtw(k_test,k04) ; distdtw(k_test,k05) ; distdtw(k_test,k06) ; distdtw(k_test,k07) ; distdtw(k_test,k08) ; distdtw(k_test,k09) ; distdtw(k_test,k10)];

[nb,indice]=min(dist);

nom = nom_ref(indice,:);

8.8. Reconnaissance par DTW avec coefficients cepstraux

function [nom,dist] = analyse4(fichier)

% Analyse DTW sur les coefficients ci (coefficients cepstraux)
% Création des ai sur les vecteurs de référence

a01 = wk1read('a01.dat');
a02 = wk1read('a02.dat');
a03 = wk1read('a03.dat');
a04 = wk1read('a04.dat');
a05 = wk1read('a05.dat');
a06 = wk1read('a06.dat');
a07 = wk1read('a07.dat');
a08 = wk1read('a08.dat');
a09 = wk1read('a09.dat');
a10 = wk1read('a10.dat');
nom_ref=['bruxelles'; 'mons '; 'namur '; 'liege '; 'charleroi'; 'anvers '; 'bruges '; 'arlon '; 'hasselt '; 'ostende '];

% Conversion ai -> ci
c01=lpcar2cc(a01);
c02=lpcar2cc(a02);
c03=lpcar2cc(a03);
c04=lpcar2cc(a04);
c05=lpcar2cc(a05);
c06=lpcar2cc(a06);
c07=lpcar2cc(a07);
c08=lpcar2cc(a08);
c09=lpcar2cc(a09);
c10=lpcar2cc(a10);

a_test = analyselpc(fichier);
c_test = lpcar2cc(a_test);

dist = [ distdtw(c_test,c01) ; distdtw(c_test,c02) ; distdtw(c_test,c03) ; distdtw(c_test,c04) ; distdtw(c_test,c05) ; distdtw(c_test,c06) ; distdtw(c_test,c07) ; distdtw(c_test,c08) ; distdtw(c_test,c09) ; distdtw(c_test,c10)];

[nb,indice]=min(dist);

nom = nom_ref(indice,:);

8.9. Calcul du RSB sur un échantillon de 1 minute pour un gamma donné

[x,Fe] = readwav('fred1min.wav','s');
%Prédétermination du rapport signal sur bruit pour le test
rapport=18;
%Ce rapport permet de faire varier le RSB
bb=randn(length(x),1);
bb=bb/rapport;
rs=0;
j=1;
%Calcul du RSB : moyenne des RSB de tranche de 30ms
for i =1:(floor(length(x)/(3*Fe/100)))
int1 = [ x((i-1)*3*Fe/100:(i)*3*Fe/100)];
int2 = [ bb((i-1)*3*Fe/100:(i)*3*Fe/100)];
rsb=10*(log((var(int1))^2/(var(int2))^2));
if rsb<0;
rsb=0;
else rsb>0;
j=j+1;
end
rs=rs+rsb;
end
%Valeur du RSB pour un rapport déterminé
rsb=rs/j
close all
figure
plot(x)
figure
plot(bb)
x=x+bb;
figure
plot(x)

8.10. Analyse LPC modifiée afin d'obtenir un signal bruité suivant le rapport précalculé

function a = analyselpc(fichier)

% Calcul une analyse LPC d'un échantillon donné
% Le calcul se fait sur des tranches de 30 ms auxquelles on applique une fenêtre de Hamming
% Les tranches se font toutes les 10ms

[x,Fe] = readwav(fichier,'s');

close all;
rapport=18;
bb=randn(length(x),1);
bb=bb/rapport;
figure
rs=0;
j=1;
for i =1:(floor(length(x)/(3*Fe/100)))
int1 = [ x((i-1)*3*Fe/100:(i)*3*Fe/100)];
int2 = [ bb((i-1)*3*Fe/100:(i)*3*Fe/100)];
rsb=10*(log((var(int1))^2/(var(int2))^2));
j=j+1;
rs=rs+rsb;
end
rsb=rs/j
x=bb+x;

figure
plot(x);

% Calcul d'une fenêtre de Hamming de 30 ms
fen_ham = hamming(3*Fe/100);

% Création d'un vecteur de tranche de 30 ms toutes les 10 ms
x_sg=[];
for i =1:(floor(length(x)/(Fe/100))-2)
x_sg = [x_sg ; x((i-1)*Fe/100:(i+2)*Fe/100)];
end
x_sg=[x_sg ; x(Fe/100*(floor(length(x)/(Fe/100))-2):length(x))];

% Analyse LPC sur des tranches de 30 ms
a = lpcauto(x_sg,10,3*Fe/100,fen_ham);

8.11. Comparatif du nombre d'opérations en virgule flottante

test='test_10b.wav';
flops(0);
[nom,d1]=analyse1(test);
f = flops;
nom

flops(0);
[nom,d2]=analyse2(test);
nom
f = [f flops];

flops(0);
[nom,d3]=analyse3(test);
nom
f = [f flops];

flops(0);
[nom,d4]=analyse4(test);
nom
f = [f flops]

d1=1./d1;
d1=d1/max(d1)*100;
d2=1./d2;
d2=d2/max(d2)*100;
d3=1./d3;
d3=d3/max(d3)*100;
d4=1./d4;
d4=d4/max(d4)*100;

d=[d1 d2 d3 d4]