DSP - Filtrage dans le domaine fréquentiel par la FFT
J'ai joué un peu avec le Exocortex mise en œuvre de la FFT, mais je vais avoir quelques problèmes.
Chaque fois que je modifie l'amplitude de la fréquence des bacs avant l'appel de la iFFT le signal résultant contient quelques clics et pops, surtout quand les basses fréquences sont présentes dans le signal (tels que la batterie ou basses). Cependant, cela ne se produit pas si je l'atténuation de toutes les bacs par le même facteur.
Laissez-moi vous donner un exemple de la mémoire tampon de sortie de 4-exemple de la FFT:
//Bin 0 (DC)
FFTOut[0] = 0.0000610351563
FFTOut[1] = 0.0
//Bin 1
FFTOut[2] = 0.000331878662
FFTOut[3] = 0.000629425049
//Bin 2
FFTOut[4] = -0.0000381469727
FFTOut[5] = 0.0
//Bin 3, this is the first and only negative frequency bin.
FFTOut[6] = 0.000331878662
FFTOut[7] = -0.000629425049
La sortie est composé de paires de chars, chacun représentant le réel et imaginay parties d'une seule cellule. Donc, bin 0 (tableau d'indices 0, 1) représentent les parties réelles et imaginaires de la DC fréquence. Comme vous pouvez le voir, les bacs 1 et 3 ont les mêmes valeurs, (sauf pour le signe de la Gi partie), donc je suppose que bin 3 est le premier négatif de fréquence, et enfin un index (4, 5) serait le dernier de fréquence positif bin.
Ensuite pour atténuer la fréquence bin 1 c'est ce que je fais:
//Attenuate the 'positive' bin
FFTOut[2] *= 0.5;
FFTOut[3] *= 0.5;
//Attenuate its corresponding negative bin.
FFTOut[6] *= 0.5;
FFTOut[7] *= 0.5;
Pour les tests, je suis en utilisant une résolution de 1024-longueur de la FFT et j'ai toujours fournir tous les échantillons, donc pas de 0-rembourrage est nécessaire.
//Attenuate
var halfSize = fftWindowLength /2;
float leftFreq = 0f;
float rightFreq = 22050f;
for( var c = 1; c < halfSize; c++ )
{
var freq = c * (44100d /halfSize);
//Calc. positive and negative frequency indexes.
var k = c * 2;
var nk = (fftWindowLength - c) * 2;
//This kind of attenuation corresponds to a high-pass filter.
//The attenuation at the transition band is linearly applied, could
//this be the cause of the distortion of low frequencies?
var attn = (freq < leftFreq) ?
0 :
(freq < rightFreq) ?
((freq - leftFreq) /(rightFreq - leftFreq)) :
1;
//Attenuate positive and negative bins.
mFFTOut[ k ] *= (float)attn;
mFFTOut[ k + 1 ] *= (float)attn;
mFFTOut[ nk ] *= (float)attn;
mFFTOut[ nk + 1 ] *= (float)attn;
}
Évidemment, je suis en train de faire quelque chose de mal, mais ne peut pas comprendre ce qu'.
Je ne veux pas utiliser la FFT sortie comme un moyen de générer un ensemble de SAPIN coefficients depuis que je suis en train de mettre en œuvre un très dynamique de base de l'égaliseur.
Quelle est la façon correcte de filtre dans le domaine fréquentiel? ce que je suis absent?
Aussi, est-il vraiment nécessaire pour atténuer des fréquences négatives ainsi? J'ai vu une FFT de mise en œuvre où nég. valeurs de la fréquence sont mis à zéro avant de synthèse.
Merci d'avance.
- Vous semblez supposer que passe-haut de filtrage est fait en prenant un fenêtré DFT, en multipliant les coefficients et la prise de la transformation inverse ("resyntehsis"). Eh bien, ce n'est pas la manière habituelle. Vous devriez lire d'abord les principes de base du traitement numérique du signal, ou poser une question plus concrète. dspguide.com/pdfbook.htm
- Je ne suis pas en supposant que quelque chose en particulier en ce qui concerne le filtre passe-haut mais le filtrage dans le domaine fréquentiel, je pensais que c'était clair que c'est juste un exemple. Aussi, de ne pas être "de façon habituelle" n'a pas pour effet d'invalider ma question. Tout ce que je demande est une explication quant à pourquoi je fais ces étranges distorsions après la synthèse, et ce n'est pas expliqué dans ce livre, et c'est pourquoi je pose la question ici. Je ne pense pas que cela mérite un downvote, vraiment.
- Votre question est raisonnable, mais vos doutes sont d'ordre conceptuel et non liés à la programmation (ni même Matlab programmation), mais les principes fondamentaux de la DSP et de la DFT. Pour répondre à ça, il faut copier-coller deux ou trois chapitres de traitement numérique du signal livre.
Vous devez vous connecter pour publier un commentaire.
Il y a deux problèmes: l'utilisation de la FFT, et le filtre particulier.
De filtrage est traditionnellement mis en œuvre en tant que produit de convolution dans le domaine temporel. Vous avez raison que le fait de multiplier les spectres de l'entrée et de filtrer les signaux en est l'équivalent. Toutefois, lorsque vous utilisez la transformée de Fourier Discrète (DFT) (mis en œuvre avec un algorithme de transformée de Fourier Rapide pour la vitesse), vous avez réellement calculer un échantillonnage de la version du spectre. Cela a beaucoup de conséquences, mais l'une des plus pertinentes pour le filtrage est l'implication que le domaine temporel du signal est périodique.
Voici un exemple. Considérons un sinusoïdale du signal d'entrée
x
avec 1,5 cycles dans la période, et un simple filtre passe-bash
. Dans Matlab/Octave syntaxe:Et voici le graphique:
Le glitch au début du bloc n'est pas ce que nous attendons tous. Mais si vous considérez
fft(x)
, c'est logique. La transformée de Fourier Discrète suppose que le signal est périodique dans le bloc de transformation. Aussi loin que la DFT sait, nous avons demandé pour la transformation d'une période de ceci:Cela conduit à la première considération importante lors de filtrage avec DFTs: vous êtes en fait la mise en œuvre de la convolution circulaire, pas de convolution linéaire. Donc le "glitch" dans le premier graphique n'est pas vraiment un problème si l'on considère les mathématiques. Alors la question devient: est-il un moyen de contourner la périodicité? La réponse est oui: l'utilisation overlap-save traitement. Essentiellement, vous devez calculer N-produits longs comme ci-dessus, mais seulement de garder N/2 points.
Et voici le graphique de
ycorrect
:Cette image fait sens - nous nous attendre à un démarrage transitoire du filtre, le résultat s'installe dans l'état d'équilibre sinusoïdale de réponse. Notez que maintenant
x
peut être arbitrairement longue. La limitation estNproc > 2*min(length(x),length(h))
.Maintenant sur la deuxième question: le filtre particulier. Dans votre boucle, vous devez créer un filtre qui du spectre est essentiellement
H = [0 (1:511)/512 1 (511:-1:1)/512]';
Si vous nehraw = real(ifft(H)); plot(hraw)
, vous obtenez:Il est difficile à voir, mais il y a un tas de non-zéro points à l'extrême bord gauche du graphique, puis un groupe de plus à l'extrême droite. En utilisant l'Octave intégré dans
freqz
fonction de regarder la réponse en fréquence nous voir (en faisantfreqz(hraw)
):L'ampleur de la réponse a beaucoup de rides de la passe-haut de l'enveloppe vers le bas à zéro. Encore une fois, la périodicité inhérents à la DFT est à l'œuvre. Aussi loin que la DFT est concerné,
hraw
se répète encore et encore. Mais si vous prenez une période dehraw
, commefreqz
n', son spectre est assez différent de l'périodique de la version.Donc, nous allons définir un nouveau signal:
hrot = [hraw(513:end) ; hraw(1:512)];
Nous il suffit de tourner le raw DFT de sortie à faire en continu à l'intérieur du bloc. Maintenant, regardons la réponse en fréquence à l'aide defreqz(hrot)
:Beaucoup mieux. L'souhaité enveloppe est là, sans ondulations. Bien sûr, la mise en œuvre n'est pas si simple maintenant, vous devez faire un complexe de multiplier par
fft(hrot)
plutôt que de simplement mise à l'échelle de chaque complexe bin, mais au moins vous aurez le droit de réponse.Noter que pour la vitesse, vous feriez habituellement pré-calculer la TFD du collier de
h
, je l'ai laissé seul dans la boucle de comparer plus facilement avec l'original.x
en supposantx
est périodique avec une période deN
, oùN
est la transformation taille de bloc. La transformation inverse calcule une période du signal périodique dont le spectre est donné en entrée. Par conséquent, la transformation et son inverse produire le signal d'origine.Votre principal problème est que fréquences ne sont pas bien définies sur des intervalles de temps courts. Cela est particulièrement vrai pour les basses fréquences, ce qui est pourquoi vous remarquez que le problème est là.
Par conséquent, lorsque vous prenez vraiment courts segments du son train, et puis vous filtrez les, le filtre segments habitude de filtre de manière à produire une forme d'onde continue, et vous entendez les sauts entre les segments et c'est ce qui génère les clics de vous ici.
Par exemple, un certains nombre raisonnable: je commence avec une forme d'onde à 27,5 Hz (A0 sur un piano), numérisé à 44100 Hz, il va ressembler à ceci (où la partie rouge est de 1024 échantillons de long):
Donc tout d'abord nous allons commencer avec un passe-bas de 40 hz. Donc, puisque la fréquence d'origine est inférieur à 40 hz, un filtre passe-bas avec une 40Hz de coupure ne devrait pas vraiment avoir aucun effet, et nous allons obtenir un résultat qui correspond presque exactement à l'entrée. Droit? Faux, faux, faux – et c'est en gros la base de votre problème. Le problème c'est que pour les courtes sections de la idée de 27,5 Hz n'est pas clairement défini, et ne peut pas être représentée dans la DFT.
Que 27,5 Hz n'est pas particulièrement significatif dans le court segment peut être vu en regardant la DFT dans la figure ci-dessous. Notez que bien que le plus long segment de la DFT (points noirs) montre un pic à 27,5 Hz, le court (points rouges) ne fonctionne pas.
Clairement, le filtrage en dessous de 40 hz, sera juste de capturer le décalage DC, et le résultat de l'40 hz filtre passe-bas est en vert dans le tableau ci-dessous.
La courbe bleue (prises avec un 200 Hz cut-off) est de commencer à correspondre beaucoup mieux. Mais notez que ce n'est pas les basses fréquences qui font qu'il correspond bien, mais l'inclusion de hautes fréquences. Il n'est pas jusqu'à ce que nous incluons toutes les fréquences possibles dans le segment court, jusqu'à 22KHz que nous avons finalement obtenir une bonne représentation de l'origine de l'onde sinusoïdale.
La raison de tout cela est qu'un petit segment d'un 27,5 Hz onde sinusoïdale est pas une 27,5 Hz sinusoïdale, et c'est DFT n'a pas beaucoup à faire avec 27,5 Hz.
Êtes-vous d'atténuer la valeur de la DC fréquence de l'échantillon à zéro? Il semble que vous n'êtes pas d'en atténuer les effets dans votre exemple. Puisque vous êtes à la mise en œuvre d'un filtre passe-haut, vous devez définir la valeur DC à zéro en tant que bien.
Ceci pourrait expliquer la faible fréquence distorsion. Vous avez beaucoup de l'ondulation dans la bande de fréquence de réponse dans les basses fréquences, si le contrôleur de valeur est différente de zéro en raison de la grande transition.
Voici un exemple dans MATLAB/Octave pour démontrer ce qui se passe:
Avis que, dans mon code, je suis entrain de créer un exemple de la valeur DC non-zéro, suivi par un changement brusque de zéro, puis une rampe vers le haut. Je puis prendre la IFFT à transformer dans le domaine temporel. Puis-je effectuer un zéro-collier de fft (ce qui est fait automatiquement par MATLAB quand vous passez par une fft de taille plus grande que le signal d'entrée) sur le domaine temporel du signal. Le zéro-padding dans le domaine du temps, les résultats de l'interpolation dans le domaine des fréquences. Avec cela, nous pouvons voir comment le filtre répondra entre les échantillons du filtre.
L'une des choses les plus importantes à retenir est que même si vous êtes réglage de la réponse du filtre des valeurs à des fréquences données en atténuant les sorties de la DFT, ce qui garantit rien pour les fréquences se produisant entre les points d'échantillonnage. Cela signifie que la plus abrupte vos modifications, plus de dépassement et d'oscillation entre les échantillons va se produire.
Maintenant pour répondre à votre question sur la façon dont ce filtrage doit être fait. Il y a un certain nombre de façons, mais la plus simple à mettre en œuvre et de comprendre, c'est la conception de la fenêtre de la méthode. Le problème avec votre conception actuelle est que la largeur de la transition est énorme. La plupart du temps, vous voudrez aussi rapide de transitions que possible, avec aussi peu d'ondulation que possible.
Dans le code suivant, je vais créer un filtre idéal et afficher la réponse:
Avis qu'il y a beaucoup d'oscillation provoquée par les changements brutaux.
La FFT ou de transformée de Fourier Discrète est une version échantillonnée de la transformée de Fourier. La transformée de Fourier est appliquée à un signal sur la plage continue -l'infini à l'infini, tandis que la DFT est appliquée sur un nombre fini d'échantillons. Cette en effet les résultats dans un carré de fenêtrage (troncature) dans le domaine temporel lors de l'utilisation de la DFT depuis nous ne nous occupons que d'un nombre fini d'échantillons. Malheureusement, la TFD d'un signal carré est une sinc fonction du type de (sin(x)/x).
Le problème avec le fait d'avoir des transitions nettes dans votre filtre (passe de 0 à 1 dans un échantillon), c'est que cela a une très longue réponse dans le domaine temporel, qui est tronquée par une fenêtre carrée. Donc, pour aider à minimiser ce problème, on peut multiplier le signal du domaine temporel par une plus progressive de la fenêtre. Si l'on multiplie une fenêtre de hanning en ajoutant la ligne:
après la prise de la IFFT, on obtient cette réponse:
Donc je vous conseille d'essayer de mettre en œuvre la conception de la fenêtre de la méthode, car il est assez simple (il existe de meilleures façons, mais ils obtiennent plus compliqué). Puisque vous êtes à la mise en œuvre d'un égaliseur, je suppose que vous voulez être en mesure de modifier les atténuations à la volée, je vous suggère de calculer et de stocker le filtre dans le domaine fréquentiel à chaque fois qu'il y a un changement dans les paramètres, et alors vous pouvez simplement l'appliquer à chaque entrée de la mémoire tampon audio par la prise de la fft de la mémoire tampon d'entrée, en multipliant par votre domaine de fréquence du filtre échantillons, et en effectuant ensuite la ifft pour revenir à l'époque de domaine. Ce sera beaucoup plus efficace que toutes les branches que vous faites pour chaque échantillon.
D'abord, à propos de la normalisation: qui est connu (non) question. La DFT/IDFT aurait besoin d'un facteur de 1/sqrt(N) (en dehors de la norme cosinus/sinus facteurs) dans chacun (directe et inverse) afin de les rendre simmetric et vraiment inversible. Une autre possibilité est de diviser l'un d'eux (le direct, ou l'inverse) par N, c'est une question de confort et de goût. Souvent la FFT routines de ne pas effectuer cette normalisation, l'utilisateur est tenu d'en être conscient et de normaliser, comme il préfère. Voir
Deuxième: dans un (dire) 16 point de DFT, ce que vous appelez la bin 0 correspond à la fréquence nulle (DC), bin 1 low freq... bin 4 moyen freq, bin 8 à la fréquence la plus élevée et bacs de 9...15 à la "des fréquences négatives". En vous exemple, alors, bin 1 est à la fois la fréquence basse et moyenne fréquence. En dehors de cette considération, il n'y a rien de conceptuellement mal dans votre "péréquation". Je ne comprends pas ce que tu veux dire par "le signal est déformé dans les basses fréquences". Comment observez-vous que ?