Comment implémenter la corrélation croisée pour prouver que deux fichiers audio sont similaires?

58

Je dois faire une corrélation croisée de deux fichiers audio pour prouver qu'ils sont similaires. J'ai pris la FFT des deux fichiers audio et leurs valeurs de spectre de puissance dans des tableaux distincts.

Comment devrais-je continuer à les corréler et prouver qu'ils sont semblables? Y a-t-il une meilleure façon de le faire? Toutes les idées de base me seront utiles pour apprendre et l’appliquer.

Lorem Ipsum
la source
Compte tenu de la corrélation croisée de deux vecteurs de signaux aléatoires. Comment implémentez-vous l'inverse pour obtenir les deux vecteurs dans MATLAB. John Muhehe

Réponses:

56

La corrélation croisée et la convolution sont étroitement liées. En bref, pour faire la convolution avec des FFT, vous

  1. touchez les signaux d’entrée (ajoutez des zéros à la fin de sorte qu’au moins la moitié de l’onde soit "vierge")
  2. prendre la FFT des deux signaux
  3. multiplier les résultats ensemble (multiplication élément par élément)
  4. faire la FFT inverse

conv(a, b) = ifft(fft(a_and_zeros) * fft(b_and_zeros))

Vous devez faire le remplissage à zéro car la méthode FFT est en fait une corrélation croisée circulaire , ce qui signifie que le signal est renvoyé aux extrémités. Vous ajoutez donc suffisamment de zéros pour supprimer le chevauchement, afin de simuler un signal nul à l'infini.

Pour obtenir une corrélation croisée au lieu d'une convolution, vous devez soit inverser dans le temps l'un des signaux avant d'effectuer la FFT, soit prendre le conjugué complexe de l'un des signaux après la FFT:

  • corr(a, b) = ifft(fft(a_and_zeros) * fft(b_and_zeros[reversed]))
  • corr(a, b) = ifft(fft(a_and_zeros) * conj(fft(b_and_zeros)))

selon ce qui est le plus facile avec votre matériel / logiciel. Pour l'autocorrélation (corrélation croisée d'un signal avec lui-même), il est préférable de faire le conjugué complexe, car il suffit alors de calculer la FFT une seule fois.

Si les signaux sont réels, vous pouvez utiliser de vraies FFT (RFFT / IRFFT) et économiser la moitié de votre temps de calcul en ne calculant que la moitié du spectre.

Vous pouvez également économiser du temps de calcul en utilisant une taille plus grande que celle pour laquelle la FFT est optimisée (par exemple, un nombre à 5 valeurs lisses pour FFTPACK, un nombre à 13 valeurs en douceur pour FFTW ou une puissance de 2 pour une implémentation matérielle simple).

Voici un exemple de corrélation FFT en Python comparée à la corrélation force brute: https://stackoverflow.com/a/1768140/125507

Cela vous donnera la fonction de corrélation croisée, qui est une mesure de la similarité par rapport au décalage. Pour obtenir le décalage auquel les ondes sont "alignées", il y aura un pic dans la fonction de corrélation:

pic de la fonction de corrélation

La valeur x du pic est le décalage, qui peut être négatif ou positif.

J'ai seulement vu cela utilisé pour trouver le décalage entre deux vagues. Vous pouvez obtenir une estimation plus précise du décalage (meilleure que la résolution de vos échantillons) en utilisant une interpolation parabolique / quadratique sur le pic.

Pour obtenir une valeur de similarité comprise entre -1 et 1 (une valeur négative indiquant que l'un des signaux diminue à mesure que l'autre augmente), vous devez redimensionner l'amplitude en fonction de la longueur des entrées, de la longueur de la FFT, de votre implémentation FFT particulière. mise à l'échelle, etc. L'autocorrélation d'une onde avec elle-même vous donnera la valeur de correspondance maximale possible.

Notez que cela ne fonctionnera que sur les vagues qui ont la même forme. Si elles ont été échantillonnées sur un matériel différent ou si du bruit est ajouté, mais si elles ont toujours la même forme, cette comparaison fonctionnera, mais si la forme de l’onde a été modifiée par filtrage ou par décalage de phase, elle peut sembler identique, mais gagnée. ne pas corréler aussi bien.

endolithe
la source
3
Le remplissage zéro doit être au moins égal à N = taille (a) + taille (b) -1, de préférence arrondi à une puissance supérieure à 2. Pour obtenir une valeur comprise entre -1 et 1, divisez par la norme (a) * norm (b ), qui donne le cosinus de l'angle entre les deux vecteurs dans l'espace N pour le retard donné (c'est-à-dire le décalage circulaire modulo N). Aux décalages extrêmes, il n'y a pas beaucoup d'échantillons qui se chevauchent (un seul à l'extrême), donc diviser par la norme (a) * norm (b) va biaiser ces corrélations vers 0 (c'est-à-dire montrer leur orthogonalité relative dans l'espace N). .
Eryk dim
1
Je pense qu'il peut y avoir une erreur dans la description. La multiplication des FFT ne devrait-elle pas donner à la FFT la convolution des signaux, pas à la FFT de la corrélation croisée ? D'après ce que je comprends, pour obtenir la FFT de la corrélation croisée, il est nécessaire d'utiliser le conjugué complexe de l'un des vecteurs FFT dans les multiplications terme par terme avant de prendre l'iFFT.
Dilip Sarwate
@DilipSarwate: Oui, vous avez raison. Vous pouvez également inverser un signal dans la direction du temps, ce que j'ai ajouté à la réponse.
endolith
1
"Pourquoi le retournement du temps est-il difficile à faire en matériel?" Dans de nombreux cas, les données sont stockées dans des tableaux systoliques dans l'attente que les calculs soient locaux , c'est-à-dire que , stocké dans la cellule ème, n'interagit qu'avec ses voisins les plus proches . Envoi à la cellule # et envoyer à la cellule # , et de faire cela pour tous l' augmentation des coûts de câblage, les retards de câblage (et par conséquent , réduit la fréquence d'horloge maximale possible), et aussi, parce que tous les les fils doivent se croiser, ce qui crée des problèmes de routage. Cela devrait être évité si possible, et dans ce cas, il est évitable.i x [ ± i ] x [ i ] ( N - i ) x [ N - i ] i ix[i]ix[±i]x[i](Ni)x[Ni]ii
Dilip Sarwate
1
@Leo multiplication par élément. Tableau n-par-1 x tableau n-par-1 = tableau n-par-1 J'ai appelé cela "échantillon par échantillon" dans la réponse.
endolith
17

La corrélation est un moyen d'exprimer la similarité de deux séries temporelles (échantillons audio dans votre cas) en un seul nombre. C'est une adaptation de la covariance qui est implémentée comme suit:

period = 1/sampleFrequency;
covariance=0;

for (iSample = 0; iSample<nSamples; iSample++)
    covariance += (timeSeries_1(iSample)*timeSeries_2(iSample))/period;
    //Dividing by `period` might not even be necessary

La corrélation est la version normalisée de la covariance, qui est la covariance divisée par le produit des écarts-types des deux séries temporelles. La corrélation produira un 0 lorsqu'il n'y a pas de corrélation (totalement différente) et un 1 pour une corrélation totale (totalement similaire).

Vous pouvez imaginer que deux échantillons sonores peuvent être similaires mais ne sont pas synchronisés. C'est là qu'intervient la corrélation croisée . Vous calculez la corrélation entre les séries temporelles dans lesquelles l'une d'elles est décalée d'un échantillon:

for (iShift=0; iShift<nSamples; iShift++)
    xcorr(iShift) = corr(timeSeries_1, timeSeries_2_shifted_one_sample);

Ensuite, recherchez la valeur maximale dans la corrsérie et vous avez terminé. (ou arrêtez-vous si vous avez trouvé une corrélation suffisante) Bien sûr, il y a un peu plus. Vous devez implémenter l'écart-type, gérer un peu la mémoire et implémenter les fonctions de décalage. Si tous vos échantillons audio ont la même longueur, vous pouvez vous en sortir sans normaliser la covariance et procéder au calcul de la covariance croisée.

Une relation intéressante avec votre question précédente : l'analyse de Fourier est simplement une adaptation de la covariance croisée. Plutôt que de décaler une série temporelle et de calculer les covariances avec l'autre signal, vous calculez les covariances entre un signal et un certain nombre d'ondes (co) sinusoïdales de fréquences différentes. Tout est basé sur le même principe.

Communauté
la source
1
Vous avez mentionné que 0 n'est pas une corrélation et 1 est le total des corrélations. Je veux juste noter que -1 est complet négativement corrélé. Comme dans, -1 implique que l'échantillon 1 est l'opposé de l'échantillon 2. Si vous y réfléchissez sur un graphique X, Y, il s'agit d'une ligne avec une pente positive par rapport à une ligne avec une pente négative. Et à mesure que vous vous rapprochez de 0, la ligne devient "plus grosse".
Kellenjb
@kellenjb, oui, mais je dirais probablement que c'est la magnitude de la corrélation qui vous intéresse le plus. Un 1 ou un -1 signifie que les signaux se touchent directement.
Kortuk
14

Dans le traitement du signal, la corrélation croisée (xcorr dans MATLAB) est une opération de convolution avec l'une des deux séquences inversée. Comme l’inversion temporelle correspond à une conjugaison complexe dans le domaine fréquentiel, vous pouvez utiliser la TFD pour calculer la corrélation croisée comme suit:

R_xy = ifft(fft(x,N) * conj(fft(y,N)))

où N = taille (x) + taille (y) - 1 (de préférence arrondi à une puissance égale à 2) est la longueur de la TFD.

La multiplication des DFT équivaut à une convolution circulaire dans le temps. La mise à zéro des deux vecteurs à la longueur N empêche les composantes décalées circulairement de y de se chevaucher avec x, ce qui rend le résultat identique à la convolution linéaire de x et à l'inverse du temps y.

Un décalage de 1 correspond à un décalage circulaire droit de y, tandis qu'un décalage de -1 correspond à un décalage circulaire gauche. La corrélation croisée est simplement la séquence de produits de points pour tous les décalages. Basés sur un ordre fft standard, ceux-ci seront dans un tableau auquel on peut accéder comme suit. Les indices 0 à taille (x) -1 sont les décalages positifs. Les indices de taille N (y) +1 à N-1 sont les décalages négatifs dans l'ordre inverse. (En Python, les retards négatifs sont facilement accessibles avec des indices négatifs tels que R_xy [-1].)

Vous pouvez considérer les x et y remplis de zéros comme des vecteurs à N dimensions. Le produit scalaire de x et y pour un décalage donné est |x|*|y|*cos(theta). Les normes de x et y étant constantes pour les déplacements circulaires, leur division ne laisse que le cosinus variable de l'angle thêta. Si x et y (pour un retard donné) sont orthogonaux dans l'espace N, la corrélation est 0 (c'est-à-dire que thêta = 90 degrés). S'ils sont co-linéaires, la valeur est 1 (corrélation positive) ou -1 (corrélation négative, c'est-à-dire thêta = 180 degrés). Ceci conduit à la corrélation croisée normalisée à l'unité:

R_xy = ifft(fft(x,N) * conj(fft(y,N))) / (norm(x) * norm(y))

Ceci peut être rendu non biaisé en recalculant les normes uniquement pour les parties qui se chevauchent, mais vous pouvez également effectuer le calcul complet dans le domaine temporel. En outre, vous verrez différentes versions de la normalisation. Au lieu d'être normalisée à l'unité, la corrélation croisée est parfois normalisée par M (biaisé), où M = max (taille (x), taille (y)) ou M- | m | (une estimation non biaisée du décalage de mois).

Pour une signification statistique maximale, la moyenne (biais DC) doit être supprimée avant de calculer la corrélation. Ceci est appelé la covariance croisée (xcov dans MATLAB):

x2 = x - mean(x)
y2 = y - mean(y)
phi_xy = ifft(fft(x2,N) * conj(fft(y2,N))) / (norm(x2) * norm(y2))
Eryk Sun
la source
Est-ce que cela signifie que la taille finale du tableau devrait être 2*size (a) + size(b) - 1ou 2*size (b) + size (a) - 1? Mais dans les deux cas, les deux tableaux matelassés sont de tailles différentes. Quelle est la conséquence de remplir avec trop de zéros?
@RobertK Le tableau de corrélation croisée doit avoir une longueur au moins égale à la somme des longueurs de a et b (moins un), comme le dit eryksun dans sa réponse. Pour simplifier, on considère souvent que la longueur est le double de la longueur du vecteur le plus long (parfois arrondi à la puissance immédiatement supérieure pour utiliser une FFT efficace). Le choix est utile lorsque le client décide tardivement qu'il souhaite également l'autocorrélation du vecteur le plus long. Une conséquence du remplissage avec trop de zéros est un calcul supplémentaire, mais des mises en œuvre FFT plus efficaces pourraient l’améliorer. 2
Dilip Sarwate
@ RobertKJ: Vous glissez le blong a, avec une sortie par équipe, un chevauchement minimum d'un échantillon. Cela produit size(a)des décalages positifs et size(b) - 1des décalages négatifs. Utilisation de la transformée inverse du produit de TFD à N points, les indices à 0travers size(a)-1les retards positifs et les indices à N-size(b)+1travers N-1sont les décalages négatifs dans l' ordre inverse.
Eryk Sun
3

Si vous utilisez Matlab, essayez la fonction de corrélation croisée:

c= xcorr(x,y)

Voici la documentation Matlab:

xcorrestime la séquence de corrélation croisée d'un processus aléatoire. L'autocorrélation est traitée comme un cas particulier.

...

c = xcorr(x,y)renvoie la séquence de corrélation croisée dans un vecteur de longueur 2 * N-1, où xet ysont des Nvecteurs de longueur ( N > 1). Si xet yne sont pas de même longueur, le vecteur le plus court est complété à zéro à la longueur du vecteur le plus long.

corrélation http://www.mathworks.com/help/toolbox/signal/ref/eqn1263487323.gif

smashtastic
la source
Le lien semble être brisé.
Danijel
2

Un moyen simple et rapide de comparer des fichiers audio. Prenez le fichier audio, faites-en une copie dans une copie, collez-le côte à côte dans 2 canaux stéréo, inversez la phase sur l'une des pistes stéréo, alignez les deux fichiers au début en mode zoom, assurez-vous que le les deux fichiers ont la même amplitude au début, puis jouez, s'il y a un silence total, les deux fichiers sont identiques, s'il y a une différence, vous l'entendrez très clairement !.

utilisateur31971
la source
1

Comme la plupart des gens ici l'ont écrit, vous devriez utiliser la corrélation.

Il suffit de prendre 2 facteurs à l’étude:

  1. Si le volume est mis à l'échelle différemment, vous devez normaliser la corrélation.
  2. S'il y a une mise à l'échelle du temps, vous pouvez utiliser Dynamic Time Warping.
David
la source
1

Pour les signaux non périodiques (taille (y) -1) doit être soustrait de l'index de R_xy pour obtenir le décalage réel.

N = taille (x) + taille (y) - 1;

retard = [0, N] - (taille (y) - 1);

Patrick
la source
0

Le moyen le plus simple de déterminer la différence, IMO, consiste à soustraire les deux signaux audio du domaine temporel. S'ils sont égaux, le résultat à chaque instant sera égal à zéro. S'ils ne sont pas égaux, la différence entre eux sera laissée après la soustraction et vous pourrez l'écouter directement. Une mesure rapide de leur similarité serait la valeur RMS de cette différence. Cela se fait souvent en mixage audio et en mastering pour entendre la différence d’un fichier MP3 vs WAV par exemple. (Inverser la phase d’un signal et l’ajouter équivaut à soustraire. C’est la méthode utilisée lorsque cela est fait dans le logiciel DAW.) Ils doivent être parfaitement alignés dans le temps pour que cela fonctionne. S'ils ne le sont pas, vous pouvez développer un algorithme pour les aligner, tels que la détection des dix pics les plus élevés, le calcul du décalage moyen des pics et le décalage d'un signal.

Transformer vers le domaine fréquentiel et comparer les spectres de puissance des signaux comme vous le proposez ignore certaines informations du domaine temporel. Par exemple, l'audio joué en inverse aurait le même spectre que s'il était joué en avant. Ainsi, deux signaux audio très différents pourraient avoir exactement le même spectre.

Martin Vandepas
la source