Nun, es hängt alles von dem Frequenzbereich, nachdem Sie sind. Eine FFT arbeitet mit 2^n Samples und liefert Ihnen 2^(n-1) reelle und imaginäre Zahlen. Ich muss zugeben, dass ich ziemlich unklar bin, was genau diese Werte darstellen (ich habe einen Freund, der versprochen hat, alles mit mir durchzugehen anstelle eines Kredits, den ich ihm gemacht habe, als er finanzielle Probleme hatte;)) ein Winkel um einen Kreis. Effektiv liefern sie Ihnen einen Arccos des Winkelparameters für einen Sinus und einen Kosinus für jedes Frequenzfach, aus dem die ursprünglichen 2^n Abtastwerte perfekt rekonstruiert werden können.
Wie auch immer, dies hat den großen Vorteil, dass Sie die Größe berechnen können, indem Sie den euklidischen Abstand der Real- und Imaginärteile nehmen (sqrtf ((real * real) + (imag * imag))). Dadurch erhalten Sie einen unnormierten Abstandswert. Dieser Wert kann dann verwendet werden, um eine Größe für jedes Frequenzband zu bilden.
Also nehmen wir eine Bestellung 10 FFT (2^10). Sie geben 1024 Samples ein. Sie fasten diese Samples und Sie erhalten 512 imaginäre und reelle Werte zurück (die bestimmte Reihenfolge dieser Werte hängt von dem verwendeten FFT-Algorithmus ab). Das bedeutet, dass für eine 44.1Khz Audiodatei jeder Bin 44100/512 Hz oder ~ 86Hz pro Bin repräsentiert. Eine Sache, die sich davon abheben sollte ist, dass, wenn Sie mehr Samples verwenden (von dem, was Zeit oder Raumdomäne genannt wird, wenn Sie mit mehrdimensionalen Signalen wie Bildern arbeiten), eine bessere Frequenzrepräsentation erhalten). Wie auch immer du opferst für den anderen. Das ist genau die Art und Weise, wie die Dinge laufen und du musst damit leben.
Grundsätzlich müssen Sie die Frequenzbins und die zeitliche/räumliche Auflösung abstimmen, um die gewünschten Daten zu erhalten.
Zuerst ein bisschen Nomenklatur. Die 1024 Zeitdomänen-Beispiele, auf die ich früher Bezug nahm, werden als Ihr Fenster bezeichnet. Im Allgemeinen, wenn Sie diese Art von Prozess durchführen, möchten Sie das Fenster um einen gewissen Betrag schieben, um die nächsten 1024 Samples zu erhalten, die Sie FFT haben. Die naheliegende Sache wäre, die Beispiele 0-> 1023, dann 1024-> 2047 usw. zu nehmen. Dies liefert leider nicht die besten Ergebnisse. Idealerweise sollten Sie die Fenster zu einem gewissen Grad überlappen, damit Sie im Laufe der Zeit eine gleichmäßigere Frequenzänderung erhalten. Am häufigsten wird das Fenster um eine halbe Fenstergröße verschoben. dh Ihr erstes Fenster wird 0-> 1023 sein, das zweite 512-> 1535 und so weiter und so fort.
Das bringt nun ein weiteres Problem auf. Während diese Information für eine perfekte inverse FFT-Signalrekonstruktion sorgt, ergibt sich das Problem, dass Frequenzen gewissermaßen in Surround-Bins münden. Um dieses Problem zu lösen, kamen einige Mathematiker (viel intelligenter als ich) auf das Konzept einer window function. Die Fensterfunktion sorgt für eine weit bessere Frequenzisolierung im Frequenzbereich, führt jedoch zu einem Informationsverlust im Zeitbereich (dh es ist unmöglich, das Signal nach Verwendung einer Fensterfunktion, AFAIK, perfekt wieder aufzubauen).
Jetzt gibt es verschiedene Arten von Fensterfunktionen, angefangen vom rechteckigen Fenster (effektiv nichts mit dem Signal zu tun) bis zu verschiedenen Funktionen, die eine weit bessere Frequenzisolierung bieten (obwohl einige auch die umliegenden Frequenzen zerstören könnten, die Sie interessieren könnten! !). Es gibt leider keine Einheitsgröße für alle, aber ich bin ein großer Fan (für Spektrogramme) der Blackmann-Harris-Fensterfunktion. Ich denke, es gibt die besten Ergebnisse!
Wie bereits erwähnt, bietet die FFT jedoch ein unnormalisiertes Spektrum. Um das Spektrum zu normalisieren (nach der euklidischen Abstandsberechnung) müssen Sie alle Werte durch einen Normierungsfaktor dividieren (ich gehe genauer auf here).
Diese Normalisierung liefert Ihnen einen Wert zwischen 0 und 1. Sie können also einfach diesen Wert um 100 multiplizieren, um Ihren Maßstab von 0 bis 100 zu erhalten.
Dies ist jedoch nicht, wo es endet. Das Spektrum, das Sie daraus erhalten, ist eher unbefriedigend. Dies liegt daran, dass Sie die Größe mit einer linearen Skala betrachten. Leider hört das menschliche Ohr eine logarithmische Skala. Dies verursacht eher Probleme mit dem Aussehen eines Spektrogramms/Spektrums.
Um das zu umgehen, müssen Sie diese 0 zu 1 Werte (ich nenne es "x") auf die Dezibelskala umrechnen. Die Standardumwandlung ist 20.0f * log10f(x). Dies liefert Ihnen dann einen Wert, wobei 1 zu 0 konvertiert wurde und 0 zu -infinity konvertiert wurde. Eure Größen sind jetzt in der entsprechenden logarithmischen Skala. Aber es ist nicht immer so hilfreich.
An dieser Stelle müssen Sie in die ursprüngliche Bittiefe des Samples schauen. Bei 16-Bit-Sampling erhalten Sie einen Wert zwischen 32767 und -32768. Das heißt, Ihr dynamic range ist fabsf (20.0f * log10f (1.0f/65536.0f)) oder ~ 96.33dB. Jetzt haben wir diesen Wert.
Nehmen Sie die Werte, die wir aus der obigen dB-Berechnung erhalten haben. Fügen Sie diesen Wert -96,33 hinzu. Offensichtlich ist die maximale Amplitude (0) jetzt 96,33. Jetzt didivde durch den gleichen Wert und Sie haben jetzt einen Wert von -unendlich bis 1,0f. Klemmen Sie das untere Ende auf 0 und Sie haben jetzt einen Bereich von 0 bis 1 und multiplizieren Sie das mit 100 und Sie haben Ihren letzten 0 bis 100 Bereich.
Und das ist viel mehr ein Monster Beitrag als ich ursprünglich beabsichtigt hatte, aber sollte Ihnen eine gute Grundlage in wie ein gutes Spektrum/Spektrogramm für ein Eingangssignal zu erzeugen.
und atmen
Weiterführende Literatur (für Menschen, andere als die Original-Poster, die es bereits gefunden hat):
Converting an FFT to a spectogram
bearbeiten: Als Nebenwirkung fand ich Kuss FFT viel einfacher zu verwenden, ist mein Code, um ein Vorwärtsfft durchzuführen, wie folgt:
CFFT::CFFT(unsigned int fftOrder) :
BaseFFT(fftOrder)
{
mFFTSetupFwd = kiss_fftr_alloc(1 << fftOrder, 0, NULL, NULL);
}
bool CFFT::ForwardFFT(std::complex<float>* pOut, const float* pIn, unsigned int num)
{
kiss_fftr(mFFTSetupFwd, pIn, (kiss_fft_cpx*)pOut);
return true;
}
Goz, du bist ernsthaft mein Held. Tausend Dank für die Hilfe. Ich lese es jetzt und werde versuchen, umzusetzen, was du morgen beschrieben hast :) –
@ThomasKobberPanum: Keine probs :) – Goz
Hallo Goz, ich habe meinen Code bisher gepostet. Ich habe die Überlappung noch nicht implementiert. Ich versuche nur, einige normalisierte Werte zu bekommen, um damit anzufangen. Ich kann nicht sehen, was ich falsch mache? Ich bekomme immer noch diese riesigen Zahlen, was sinnvoll ist, da der Normalizer-Wert ziemlich niedrig ist ... aber irgendwie muss es inkorrekt sein? –