Analizza l'audio utilizzando la trasformata rapida di Fourier


109

Sto cercando di creare un analizzatore di spettro grafico in Python.

Attualmente sto leggendo 1024 byte di un flusso audio con frequenza di campionamento a doppio canale a 16 bit 44.100 Hz e sto calcolando la media dell'ampiezza dei 2 canali insieme. Quindi ora ho una serie di 256 cortometraggi firmati. Ora voglio preformare un fft su quell'array, usando un modulo come numpy, e usare il risultato per creare l'analizzatore di spettro grafico, che, per iniziare, sarà solo di 32 barre.

Ho letto gli articoli di Wikipedia sulla Trasformata di Fourier veloce e Trasformata di Fourier discreta, ma non sono ancora chiaro cosa rappresenti l'array risultante. Questo è l'aspetto dell'array dopo aver preformato un fft sul mio array usando numpy:

   [ -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...

Mi chiedo cosa rappresentino esattamente questi numeri e come convertirò questi numeri in una percentuale di altezza per ciascuna delle 32 barre. Inoltre, dovrei fare la media dei 2 canali insieme?

Risposte:


209

La matrice che stai mostrando è i coefficienti della trasformata di Fourier del segnale audio. Questi coefficienti possono essere utilizzati per ottenere il contenuto in frequenza dell'audio. La FFT è definita per funzioni di input con valori complessi, quindi i coefficienti che ottieni saranno numeri immaginari anche se i tuoi input sono tutti valori reali. Per ottenere la quantità di potenza in ciascuna frequenza, è necessario calcolare l'ampiezza del coefficiente FFT per ciascuna frequenza. Questa non è solo la componente reale del coefficiente, è necessario calcolare la radice quadrata della somma del quadrato delle sue componenti reali e immaginarie. Cioè, se il tuo coefficiente è a + b * j, la sua grandezza è sqrt (a ^ 2 + b ^ 2).

Dopo aver calcolato l'ampiezza di ogni coefficiente FFT, è necessario capire a quale frequenza audio appartiene ciascun coefficiente FFT. Un punto N FFT ti darà il contenuto di frequenza del tuo segnale a N frequenze equidistanti, a partire da 0. Perché la tua frequenza di campionamento è 44100 campioni / sec. e il numero di punti nella tua FFT è 256, la tua spaziatura di frequenza è 44100/256 = 172 Hz (circa)

Il primo coefficiente nell'array sarà il coefficiente di frequenza 0. Questo è fondamentalmente il livello di potenza medio per tutte le frequenze. Il resto dei coefficienti verrà conteggiato da 0 in multipli di 172 Hz fino ad arrivare a 128. In una FFT, è possibile misurare solo frequenze fino alla metà dei punti di campionamento. Leggi questi collegamenti sulla frequenza di Nyquist e sul teorema del campionamento di Nyquist-Shannon se sei un ghiotto di punizione e hai bisogno di sapere perché, ma il risultato di base è che le tue frequenze più basse verranno replicate o aliasate nei segmenti delle frequenze più alte. Quindi le frequenze inizieranno da 0, aumenteranno di 172 Hz per ciascun coefficiente fino al coefficiente N / 2, quindi diminuiranno di 172 Hz fino al coefficiente N - 1.

Dovrebbero essere sufficienti informazioni per iniziare. Se desideri un'introduzione agli FFT molto più accessibile di quella fornita su Wikipedia, potresti provare Understanding Digital Signal Processing: 2nd Ed. . È stato molto utile per me.

Quindi questo è ciò che rappresentano quei numeri. La conversione in una percentuale di altezza può essere eseguita scalando l'ampiezza di ciascuna componente di frequenza per la somma di tutte le grandezze dei componenti. Tuttavia, ciò ti darebbe solo una rappresentazione della distribuzione di frequenza relativa e non la potenza effettiva per ciascuna frequenza. Potresti provare a ridimensionare in base all'intensità massima possibile per un componente di frequenza, ma non sono sicuro che sarebbe visualizzato molto bene. Il modo più rapido per trovare un fattore di scala praticabile sarebbe sperimentare su segnali audio forti e deboli per trovare l'impostazione giusta.

Infine, dovresti fare la media dei due canali insieme se vuoi mostrare il contenuto di frequenza dell'intero segnale audio nel suo insieme. Stai mixando l'audio stereo in audio mono e stai mostrando le frequenze combinate. Se desideri due display separati per le frequenze destra e sinistra, dovrai eseguire la trasformata di Fourier su ciascun canale separatamente.


1
Per lo più riesco a trovare solo spiegazioni eccessivamente complicate di FFT online, questa è stata una spiegazione semplice e fantastica di come il numero di punti campionati influenzi i risultati della FFT. Grazie per questo!
ecolocalizzazione

26

Sebbene questo thread abbia anni, l'ho trovato molto utile. Volevo solo dare il mio contributo a chiunque lo trovi e stia cercando di creare qualcosa di simile.

Per quanto riguarda la divisione in barre, ciò non dovrebbe essere fatto come suggerisce antti, dividendo i dati equamente in base al numero di barre. Il più utile sarebbe dividere i dati in parti di ottava, ciascuna ottava essendo il doppio della frequenza della precedente. (es. 100 Hz è un'ottava sopra 50 Hz, ovvero un'ottava sopra 25 Hz).

A seconda di quante battute si desidera, si divide l'intera gamma in intervalli di 1 / X ottava. Sulla base di una data frequenza centrale di A sulla barra, ottieni i limiti superiore e inferiore della barra da:

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

Per calcolare la successiva frequenza centrale adiacente si utilizza un calcolo simile:

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

Quindi fai la media dei dati che rientrano in questi intervalli per ottenere l'ampiezza di ciascuna barra.

Ad esempio: vogliamo dividere in intervalli di 1/3 di ottave e iniziamo con una frequenza centrale di 1 kHz.

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

Dati 44100 hz e 1024 campioni (43 hz tra ogni punto dati) dovremmo calcolare la media dei valori da 21 a 26 (890,9 / 43 = 20,72 ~ 21 e 1122,5 / 43 = 26,10 ~ 26)

(Barre di 1/3 di ottava ti porterebbero circa 30 battute tra ~ 40 hz e ~ 20 khz). Come puoi capire ormai, man mano che andiamo più in alto, faremo la media di un intervallo di numeri più ampio. Le barre basse in genere includono solo 1 o un numero limitato di punti dati. Mentre le barre più alte possono essere la media di centinaia di punti. Il motivo è che 86 hz è un'ottava sopra 43 hz ... mentre 10086 hz suona quasi come 10043 hz.


10

quello che hai è un campione la cui lunghezza nel tempo è 256/44100 = 0,00580499 secondi. Ciò significa che la risoluzione della frequenza è 1 / 0,00580499 = 172 Hz. I 256 valori che ottieni da Python corrispondono alle frequenze, in pratica, da 86 Hz a 255 * 172 + 86 Hz = 43946 Hz. I numeri che ottieni sono numeri complessi (da qui la "j" alla fine di ogni secondo numero).

MODIFICATO: RISOLTO INFORMAZIONI ERRATE

È necessario convertire i numeri complessi in ampiezza calcolando sqrt (i 2 + j 2 ) dove i e j sono le parti reali e immaginarie, rispettivamente.

Se vuoi avere 32 barre, per quanto ho capito dovresti prendere la media di quattro ampiezze successive, ottenendo 256/4 = 32 barre come vuoi.


4
Nota che, se c è un numero complesso, sqrt (c.real 2 + c.imag 2) == abs (c)
tzot

0

FFT restituisce N valori complessi che di voi possono calcolare module=sqrt(real_part^2+imaginary_part^2). Per ottenere il valore per ogni banda devi sommare i moduli di tutte le armoniche all'interno della banda. Di seguito puoi vedere un esempio di un analizzatore di spettro a 10 barre. Il codice c deve essere avvolto per ottenere un modulo pyd python.

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;

        }

Ho progettato e realizzato un intero analizzatore di spettro a 10 barre a led di Python. Invece per utilizzare la libreria nunmpy (troppo grande e inutile per ottenere solo l'FFT) è stato creato un modulo pyd python (solo 27KB) per ottenere l'FFT e per dividere l'intero spettro audio in bande.

Inoltre, per leggere l'audio in uscita è stato creato un modulo loopback WASapi portaudio pyd. Potete vedere il progetto (diagramma a blocchi) nell'immagine 10BarsSpectrumAnalyzerWithWASapi.jpg

Ho appena aggiunto un video tutorial sul mio canale YouTube: come progettare e realizzare una barra a 10 Led Python Spectrum Analyzer molto intelligente

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.