2014-08-30 23 views
1

J'utilise audiorecorder pour enregistrer le son et faire un peu de traitement en pseudo-temps sur le téléphone android. Je suis confronté à un problème entre la FFT et la convolution du signal audio: J'effectue FFT sur un signal connu (une forme d'onde sinusoïdale), et je trouve toujours correctement la tonalité unique qu'il contient, en utilisant la FFT.convolution du signal audio

Maintenant, je veux faire la même chose en utilisant une convolution (c'est un exercice): J'effectue 5000 convolutions de ce signal en utilisant 5000 filtres. Chaque filtre est une forme d'onde sinusoïdale sur une fréquence différente entre 0 et 5000 Hz. Puis, je recherche le pic pour chaque sortie de convolution. De cette façon, je devrais trouver le pic maximum quand j'utilise le filtre avec le même ton contenu sur le signal. Enfait avec une tonalité de 2kHz je peux trouver le maximum avec le filtre 2kHz. Le problème est que quand je reçois une tonalité de 4kHz, je trouve le maximum sur la convolution avec le filtre 4200Hz (alors que la FFT fonctionne toujours bien) Est-ce mathématiquement possible? quel est le problème dans ma convolution?

C'est la fonction de convolution que je l'ai écrit:

//i do the convolution and return the max 
//IN is the array with the signal 
//DATASIZE is the size of the array IN 
//KERNEL is the filter containing the sine at the selected frequency 

int convolveAndGetPeak(short[] in,int dataSize, double[] kernel) { 
     //per non rischiare l'overflow, il kernel deve avere un ampiezza massima pari a 1/10 del max 
     int i, j, k; 
     int kernelSize=kernel.length; 
     int tmpSignalAfterFilter=0; 
     double out; 

     // convolution from out[0] to out[kernelSize-2] 
     //iniziamo 
     for(i=0; i < kernelSize - 1; ++i) 
     { 
      out = 0; // init to 0 before sum 

      for(j = i, k = 0; j >= 0; --j, ++k) 
       out += in[j] * kernel[k]; 

      if (Math.abs((int) out)>tmpSignalAfterFilter){ 
       tmpSignalAfterFilter=Math.abs((int) out); 
      } 
     } 

     // start convolution from out[kernelSize-1] to out[dataSize-1] (last) 
     //iniziamo da dove eravamo arrivati 
     for(; i < dataSize; ++i) 
     { 
      out = 0; // initialize to 0 before accumulate 

      for(j = i, k = 0; k < kernelSize; --j, ++k) 
       out += in[j] * kernel[k]; 

      if (Math.abs((int) out)>tmpSignalAfterFilter){ 
       tmpSignalAfterFilter=Math.abs((int) out); 
      } 

     } 


     return tmpSignalAfterFilter; 
    } 

le noyau, utilisé comme filtre, est généré de cette façon:

//curFreq is the frequency of the filter in Hz 
//kernelSamplesSize is the desired length of the filter (number of samples), for time precision reasons i'm using 20 samples length. 
//sampleRate is the sampling frequency 

double[] generateKernel(int curFreq,int kernelSamplesSize,int sampleRate){ 
    double[] curKernel= new double[kernelSamplesSize] ; 

    for (int kernelIndex=0;kernelIndex<curKernel.length;kernelIndex++){ 
     curKernel[kernelIndex]=Math.sin((double)kernelIndex * ((double)(2*Math.PI) * (double)curFreq/(double)sampleRate)); //the part that makes this a sine wave.... 
    } 
    return curKernel; 

} 

si vous voulez essayer une convolution, les données contenues dans le réseau IN est la suivante: http://www.tr3ma.com/Dati/signal.txt

Note 1: la fréquence d'échantillonnage est 44100Hz

Note2: la tonalité contenue dans le signal est une tonalité unique de 4 kHz (même si la convolution a le pic maximal avec un filtre 4200Hz.

EDIT: J'ai également répété le test sur une feuille Excel. le résultat est le même (bien sûr, j'utilise le même algorithme) et les algorithmes me semblent être corrects ... c'est la feuille excel que j'ai préparée, si vous préférez travailler sur excel: http://www.tr3ma.com/Dati/convolutions.xlsm

Répondre

0

il semble tout correct, à part le nombre d'échantillons du noyau (le filtre). Augmenter la taille du filtre, le résultat est plus précis. Je ne sais pas comment calculer la bande passante de ce filtre mais il me semble clair que c'est une question de bande passante du filtre. Ainsi, la bande passante du filtre dépend également du nombre d'échantillons du filtre utilisé dans la convolution, en référence à la fréquence d'échantillonnage (et peut également être en référence à la fréquence de tonalité). Malheureusement, je ne peux pas augmenter trop le nombre d'échantillons de mon filtre, sinon le téléphone ne peut pas effectuer le filtrage en temps réel. Note: j'ai besoin de la convolution parce que j'ai besoin d'identifier le moment précis où le son a été tiré.

EDIT: j'ai fait une comparaison entre le filtre avec 20 échantillons et le filtre avec 40 échantillons. Je ne connais pas la formule pour obtenir la bande passante de Fitler mais il est clair, dans l'image suivante, la différence entre les 2 filtres.

EDIT2: QUELQUES JOURS APRÈS AVOIR AFFICHÉ LA SOLUTION JE TROUVES COMMENT CALCULER LA BANDE PASSANTE DE CE FILTRE: C'EST JUSTE L'INVERSE DE LA DURÉE DU FILTRE.SO dans l'exemple un noyau de 40 échantillons à 44100KhZ A UNE DURÉE D'ENVIRON 907uS, le filtre de bande passante, AVEC CE NOYAU ET UNE FENÊTRE DE LA MÊME LONGUEUR EST 1/907uS = 1,1KhZ http://www.tr3ma.com/Dati/convolution.JPG

1

Vous changez la bande passante a) La longueur de votre noyau (par exemple une longueur t de 5ms produit une largeur de bande approximative de f> = 200Hz, estimée avec 1/0.005 parce que Δt · Δf> = 1, voir "Heisenberg") et

b) la fonction de fenêtre (que vous devez absolument mettre en œuvre pour rendre votre algorithme de travail dans les applications du monde réel parce que sinon dans certains cas, de certains lobes secondaires sorties de filtre pourraient produire m l'énergie du minerai que le lobe principal de la sortie de filtre attendue).

Mais vous avez un autre problème: vous devez convoluer avec un 2ème noyau composé d'ondes cosinus (ce qui signifie que vous avez besoin des mêmes ondes que dans le 1er noyau mais décalées de 90 degrés). Pourquoi donc? Parce qu'avec seulement le noyau sinusoïdal, vous obtenez une modulation dépendant de la phase des sorties de filtre (par exemple si la différence de phase entre le signal d'entrée et l'onde de noyau de fréquence identique est de 90 degrés, vous obtenez l'amplitude 0).

Enfin, vous combinons les sorties des deux noyaux avec Pythagore.

+0

VRAIMENT INTÉRESSANT. MERCI DE VOTRE CONTRIBUTION, JE CONTINUERAIS D'ETUDIER. J'ai trouvé comment calculer la bande passante quelques jours après avoir posé la question, et la solution. JE N'AI PAS BIEN COMPRIS LE DEUXIÈME NOYAU AVEC COSINE. Je vais étudier à nouveau. MERCI – Gaucho

+0

MAINTENANT JE VOUS compris pourquoi parler CONVOLUTION AVEC UN DEUXIÈME COSINUS, mais dans mon cas, j'ai juste besoin IDENTIFIER LE PREMIER SOMMET DE LA SORTIE Convolution, JE NE BESOIN D'UNE SORTIE CONTINUE. – Gaucho

+0

EN OUTRE, UNE SECONDE CONVOLUTION AUGMENTE TROP LE TEMPS DE TRAITEMENT. CONSIDERONS QUE JUSQU'A MAINTENANT JE CONSERVE PLUS DE TEMPS POUR TRAITER LE SIGNAL, QUE LE TEMPS DES ECHANTILLONS REÇUS. SO À convolve TOUS LES STREAMING JE FORCÉ SAUTER QUELQUES PIECES DE SIGNAL, RÉDUIRE MA PRECISION TIME – Gaucho