Analysieren Sie Audio mit Fast Fourier Transform

109

Ich versuche, einen grafischen Spektrumanalysator in Python zu erstellen.

Ich lese gerade 1024 Bytes eines 16-Bit-Dual-Channel-Audiostreams mit 44.100 Hz Abtastrate und mittle die Amplitude der beiden Kanäle zusammen. Jetzt habe ich eine Reihe von 256 signierten Shorts. Ich möchte jetzt ein fft auf diesem Array mit einem Modul wie numpy vorformen und das Ergebnis verwenden, um den grafischen Spektrumanalysator zu erstellen, der zu Beginn nur 32 Balken beträgt.

Ich habe die Wikipedia-Artikel über schnelle Fourier-Transformation und diskrete Fourier-Transformation gelesen, bin mir aber immer noch nicht sicher, was das resultierende Array darstellt. So sieht das Array aus, nachdem ich mit numpy ein fft auf meinem Array durchgeführt habe:

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
   4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
   2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
  -2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
  -1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
  -4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
   1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
  -2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
  -2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
  -1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
  -1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
  -2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
   3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

Ich frage mich, was genau diese Zahlen darstellen und wie ich diese Zahlen für jeden der 32 Balken in einen Prozentsatz einer Höhe umwandeln würde. Sollte ich auch die 2 Kanäle zusammen mitteln?

user19745
quelle

Antworten:

209

Das Array, das Sie anzeigen, sind die Fourier-Transformationskoeffizienten des Audiosignals. Diese Koeffizienten können verwendet werden, um den Frequenzinhalt des Audios zu erhalten. Die FFT ist für Eingabefunktionen mit komplexen Werten definiert, sodass die Koeffizienten, die Sie erhalten, imaginäre Zahlen sind, obwohl Ihre Eingabe nur reelle Werte sind. Um die Leistungsmenge in jeder Frequenz zu erhalten, müssen Sie die Größe des FFT-Koeffizienten für jede Frequenz berechnen. Dies ist nicht nur die reale Komponente des Koeffizienten, Sie müssen auch die Quadratwurzel der Summe des Quadrats seiner realen und imaginären Komponenten berechnen. Das heißt, wenn Ihr Koeffizient a + b * j ist, ist seine Größe sqrt (a ^ 2 + b ^ 2).

Nachdem Sie die Größe jedes FFT-Koeffizienten berechnet haben, müssen Sie herausfinden, zu welcher Audiofrequenz jeder FFT-Koeffizient gehört. Eine N-Punkt-FFT gibt Ihnen den Frequenzinhalt Ihres Signals bei N gleich beabstandeten Frequenzen ab 0 an, da Ihre Abtastfrequenz 44100 Abtastungen / s beträgt. und die Anzahl der Punkte in Ihrer FFT beträgt 256, Ihr Frequenzabstand beträgt 44100/256 = 172 Hz (ungefähr)

Der erste Koeffizient in Ihrem Array ist der Frequenzkoeffizient 0. Das ist im Grunde der durchschnittliche Leistungspegel für alle Frequenzen. Der Rest Ihrer Koeffizienten zählt von 0 in Vielfachen von 172 Hz bis zu 128. In einer FFT können Sie nur Frequenzen bis zur Hälfte Ihrer Abtastpunkte messen. Lesen Sie diese Links im Nyquist-Frequenz- und Nyquist-Shannon-Abtasttheorem, wenn Sie ein Vielfraß zur Bestrafung sind und wissen müssen, warum, aber das grundlegende Ergebnis ist, dass Ihre niedrigeren Frequenzen in den höherfrequenten Buckets repliziert oder aliasiert werden . Die Frequenzen beginnen also bei 0, erhöhen sich für jeden Koeffizienten um 172 Hz bis zum N / 2-Koeffizienten und verringern sich dann um 172 Hz bis zum N - 1-Koeffizienten.

Das sollten genug Informationen sein, um Ihnen den Einstieg zu erleichtern. Wenn Sie eine viel zugänglichere Einführung in FFTs wünschen als auf Wikipedia angegeben, können Sie versuchen, die digitale Signalverarbeitung zu verstehen: 2nd Ed. . Es war sehr hilfreich für mich.

Das ist es also, was diese Zahlen darstellen. Die Umrechnung in einen Prozentsatz der Höhe könnte durch Skalieren jeder Frequenzkomponentengröße mit der Summe aller Komponentengrößen erfolgen. Dies würde Ihnen jedoch nur eine Darstellung der relativen Häufigkeitsverteilung geben und nicht die tatsächliche Leistung für jede Frequenz. Sie könnten versuchen, die für eine Frequenzkomponente maximal mögliche Größe zu skalieren, aber ich bin mir nicht sicher, ob dies sehr gut angezeigt wird. Der schnellste Weg, um einen funktionsfähigen Skalierungsfaktor zu finden, besteht darin, mit lauten und leisen Audiosignalen zu experimentieren, um die richtige Einstellung zu finden.

Schließlich sollten Sie die beiden Kanäle zusammen mitteln, wenn Sie den Frequenzinhalt des gesamten Audiosignals als Ganzes anzeigen möchten. Sie mischen das Stereo-Audio in Mono-Audio und zeigen die kombinierten Frequenzen an. Wenn Sie zwei separate Anzeigen für die rechte und linke Frequenz wünschen, müssen Sie die Fourier-Transformation für jeden Kanal separat durchführen.

A. Levy
quelle
1
Ich kann meistens nur zu komplizierte Erklärungen der FFT online finden. Dies war eine großartige und einfache Erklärung, wie sich die Anzahl der abgetasteten Punkte auf die Ergebnisse der FFT auswirkt. Danke dafür!
Echoortung
26

Obwohl dieser Thread Jahre alt ist, fand ich ihn sehr hilfreich. Ich wollte nur meinen Beitrag an jeden richten, der dies findet und versucht, etwas Ähnliches zu schaffen.

Die Unterteilung in Balken sollte nicht wie von Anti vorgeschlagen erfolgen, indem die Daten gleichmäßig auf der Grundlage der Anzahl der Balken aufgeteilt werden. Am nützlichsten wäre es, die Daten in Oktavteile zu unterteilen, wobei jede Oktave doppelt so häufig ist wie die vorherige. (dh 100 Hz sind eine Oktave über 50 Hz, was eine Oktave über 25 Hz ist).

Je nachdem, wie viele Takte Sie möchten, teilen Sie den gesamten Bereich in 1 / X-Oktavbereiche auf. Basierend auf einer bestimmten Mittenfrequenz von A auf dem Balken erhalten Sie die oberen und unteren Grenzen des Balkens aus:

upper limit = A * 2 ^ ( 1 / 2X )
lower limit = A / 2 ^ ( 1 / 2X )

Um die nächste angrenzende Mittenfrequenz zu berechnen, verwenden Sie eine ähnliche Berechnung:

next lower =  A / 2 ^ ( 1 / X )
next higher = A * 2 ^ ( 1 / X )

Anschließend mitteln Sie die Daten, die in diese Bereiche passen, um die Amplitude für jeden Balken zu erhalten.

Zum Beispiel: Wir möchten in 1/3 Oktavenbereiche unterteilen und beginnen mit einer Mittenfrequenz von 1 kHz.

Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9

Bei 44100 Hz und 1024 Abtastwerten (43 Hz zwischen jedem Datenpunkt) sollten die Werte 21 bis 26 gemittelt werden (890,9 / 43 = 20,72 ~ 21 und 1122,5 / 43 = 26,10 ~ 26).

(1/3 Oktavbalken würden ungefähr 30 Takte zwischen ~ 40 Hz und ~ 20 kHz ergeben). Wie Sie jetzt herausfinden können, werden wir mit zunehmender Höhe einen größeren Zahlenbereich mitteln. Niedrige Balken enthalten normalerweise nur 1 oder eine kleine Anzahl von Datenpunkten. Während die höheren Balken der Durchschnitt von Hunderten von Punkten sein können. Der Grund dafür ist, dass 86 Hz eine Oktave über 43 Hz sind ... während 10086 Hz fast genauso klingen wie 10043 Hz.

Erik A.
quelle
10

Was Sie haben, ist eine Probe mit einer Zeitdauer von 256/44100 = 0,00580499 Sekunden. Dies bedeutet, dass Ihre Frequenzauflösung 1 / 0,00580499 = 172 Hz beträgt. Die 256 Werte, die Sie von Python erhalten, entsprechen im Grunde den Frequenzen von 86 Hz bis 255 * 172 + 86 Hz = 43946 Hz. Die Zahlen, die Sie herausholen, sind komplexe Zahlen (daher das "j" am Ende jeder zweiten Zahl).

EDITIERT: FESTE FALSCHE INFORMATIONEN

Sie müssen die komplexen Zahlen in Amplitude umwandeln, indem Sie das Quadrat (i 2 + j 2 ) berechnen, wobei i und j der Real- bzw. Imaginärteil sind.

Wenn Sie 32 Takte haben möchten, sollten Sie, soweit ich weiß, den Durchschnitt von vier aufeinanderfolgenden Amplituden nehmen und 256/4 = 32 Takte erhalten, wie Sie möchten.

Antti Huima
quelle
4
Bitte beachten Sie, dass wenn c eine komplexe Zahl ist, sqrt (c.real 2 + c.imag 2) == abs (c)
tzot
0

FFT gibt N komplexe Werte zurück, die von Ihnen berechnet werden können module=sqrt(real_part^2+imaginary_part^2). Um den Wert für jedes Band zu erhalten, müssen Sie die Module über alle Harmonischen innerhalb des Bandes summieren. Unten sehen Sie ein Beispiel für einen 10-bar-Spektrumanalysator. Der c-Code muss umbrochen werden, um ein pyd python-Modul zu erhalten.

float *samples_vett;
float *out_filters_vett;
int Nsamples;
float band_power = 0.0;
float harmonic_amplitude=0.0;
int i, out_index;

out_index=0;


for (i = 0; i < Nsamples / 2 + 1; i++)       
        {
            if (i == 1 || i == 2 || i == 4 || i == 8 || i == 17 || i == 33 || i == 66 || i == 132 || i == 264 || i == 511)
            {
                out_filters_vett[out_index] = band_power; 
                band_power = 0; 
                out_index++;  
            }

            harmonic_amplitude = sqrt(pow(ttfr_out_vett[i].r, 2) + pow(ttfr_out_vett[i].i, 2));
            band_power += harmonic_amplitude;

        }

Ich habe einen ganzen 10-LED-Balkenspektrumanalysator von Python entworfen und hergestellt. Anstatt die nunmpy-Bibliothek zu verwenden (zu groß und nutzlos, um nur die FFT zu erhalten), wurde ein Python-Pyd-Modul (nur 27 KB) erstellt, um die FFT zu erhalten und das gesamte Audiospektrum in Bänder aufzuteilen.

Zusätzlich wurde zum Lesen des ausgegebenen Audios ein Loopback-WASapi-Portaudio-Pyd-Modul erstellt. Sie können das Projekt (Blockdiagramm) im Bild 10BarsSpectrumAnalyzerWithWASapi.jpg sehen

Ich habe gerade ein Tutorial-Video auf meinem YouTube-Kanal hinzugefügt: Wie man eine sehr intelligente Python Spectrum Analyzer 10-LED-Leiste entwirft und erstellt


quelle