2013-07-19 3 views
3

Im essayer d'estimer la fréquence fondamentale à partir d'un fichier .wav qui contient un enregistrement de la parole de 1 mot.Java - Questions à estimer la fréquence fondamentale

Ce que j'ai essayé de faire est de lire le fichier avec audioInputStream. Le format est PCM_SIGNED 44100.0 Hz, 16 bits, stéréo, 4 octets/image, little-endian.

Par conséquent, j'ai fait un nouveau tampon pour contenir un seul canal. Ce code permet d'obtenir que:

double [] audioRight = new double[audioBytes.length/2]; 
for(int i = 0, k = 0; i <= audioBytes.length-1; i+=4, k+=2){ 
    audioRight[k]=audioBytes[i]; 
    audioRight[k+1]=audioBytes[i+1]; 
} 

Ensuite, les données ont été déplacés vers un fftBuffer, ce qui est deux fois la taille, puis un DFT est appliqué. La bibliothèque utilisée est JTransform. la fonction utilisée s'appelle realForwardFull.

DoubleFFT_1D fftDo= new DoubleFFT_1D(audioLeft.length); 
double[] fftBuffer = new double [audioLeft.length*2]; 

for (int i = 0; i < audioLeft.length; i++){ 
    fftBuffer[i] = audioLeft[i]; 
} 
fftDo.realForwardFull(fftBuffer); 

Cela donne une liste de nombres complexes que j'utilise pour calculer l'amplitude/amplitude de chaque nombre complexe afin de rendre un spectre de puissance.

La formule utilisée pour obtenir l'amplitude Amplitude = sqrt (IM IM + RE RE).

Cela fournit un tableau d'amplitudes auxquelles j'applique la méthode de sommation harmonique. La somme harmonique est celle où l'indice + 3 harmoniques qui donne la somme la plus élevée est l'indice qui représente la fréquence fondamentale.

double top_sum = 0; 
double first_index = 0; 
double sum = 0; 
double f_0 = 0; 
double FR = audioInputStream.getFormat().getSampleRate()/2/ampBuffer.length; 

for (int i = 50; i <= ampBuffer.length/4-1; i++){ 
sum = ampBuffer[i]+ampBuffer[i*2]+ampBuffer[i*3]+ampBuffer[i*4]; 
    if (top_sum < sum){ 
top_sum=sum; 
first_index = i; 

Cet index doit cependant être mappé à la fréquence correcte domnain. Pour ma compréhension cela devrait être fait en disant (index/fttBuffer.length) * sampleRate.

Ceci fournit une estimation de la fréquence fondamentale.

Le résultat n'est cependant pas "correct". J'ai plusieurs fichiers .wav différents à tester, et avec la plupart d'entre eux le résultat est en dehors de la fourchette attendue. Pour les mêmes voix féminines, trois mots différents donnent les résultats 40, 13 et 360. Les trois résultats devraient être compris entre 250 et 350 environ.

Parmi les problèmes qui, à mon avis, sont à l'origine de cette situation sont les valeurs du tampon d'amplitude. Lorsque tracé le graphique ne montre pas de pics clairs qui représente les harmoncis.

est ici une image du graphique:

Amplitudes http://i39.tinypic.com/29wkg7.png

Je sais que cela a beaucoup d'informations, mais je crois que plus d'informations, il est plus facile de comprendre ce qui a été fait. RECAP: Ce dont je ne suis pas sûr, ce sont les données d'amplitude. Est-ce que les valeurs ont un sens? Sont-ils tracés correctement? Ai-je besoin de faire quelque chose avec les données avant de chercher les harmoncis et de trouver la fréquence fondamentale?

J'ai envisagé d'appliquer une sorte de fenêtrage, parce que je soupçonne qu'une fuite pourrait être la raison pour laquelle les pics que l'intrigue a ne sont pas harmoniques les uns aux autres.

Toute aide ou suggestion serait appréciée. En avance, merci pour votre aide!

EDIT: Pour tenter de ce qui a été suggéré:

ByteBuffer buf = ByteBuffer.wrap(audioBytes); 
     buf.order(ByteOrder.LITTLE_ENDIAN); 
     double[] audio = new double[audioBytes.length/2]; 


     for(int i = 0; i < audioBytes.length/2; i++) { 
      short s = buf.getShort(); 
      double mono = (double) s; 
      double mono_norm = mono/32768.0; 

      audio[i]=mono_norm; 


     } 

maintenant un canal des données pcm doivent être enregistrées dans le tableau audio [].

+0

16 bits est 2 octets. Où convertissez-vous 2 octets little-endian en 1 double valeur? – hotpaw2

+0

Merci pour votre réponse. Je n'ai pas fait ça. Quel est le but de le faire? et avez-vous une suggestion quant à la façon dont cela peut être fait en Java? –

+0

@ hotpaw2 J'ai modifié le post original en essayant d'appliquer ce que vous avez suggéré. Est-ce que c'est ce que vous vouliez dire? ça ne semble pas résoudre mon problème, si je l'ai fait c'est correct. –

Répondre

1

Quelques conseils généraux:

Vous dites que vous essayez d'estimer la frquency fondamentale d'un mot parlé. Un "mot" se compose de plusieurs consonnes et voyelles (ou mieux phonemes). Chacune des "voyelles" aura une fréquence fondamentale différente et dans la plupart des cas, la fréquence changera même au sein d'une voyelle (qui génère la "mélodie" de nos phrases). Thius signifie que vous devez estimer la fréquence fondamentale/hauteur d'un très court intervalle du discours et assurez-vous que vous regardez une voyelle (les consonnes sont une forme de bruit et ont des composantes cycliques).

Donc le premier sterp devrait être de générer un spectogramme de votre mot.

Ensuite, vous pouvez calculer les FFT à court terme des parties intéressantes et procéder à la sommation harmonique. Cependant, vous obtiendrez de meilleurs résultats avec une fonction d'autocorrélation à court terme.

Autres choses à rechercher: Pitch-Detection, Cepstrum