Analice el audio con la Transformada rápida de Fourier

109

Estoy tratando de crear un analizador de espectro gráfico en Python.

Actualmente estoy leyendo 1024 bytes de un flujo de audio de frecuencia de muestreo de 44,100 Hz de doble canal de 16 bits y promediando la amplitud de los 2 canales juntos. Así que ahora tengo una serie de 256 cortos firmados. Ahora quiero preformar un fft en esa matriz, usando un módulo como numpy, y usar el resultado para crear el analizador de espectro gráfico, que, para comenzar, será solo de 32 barras.

He leído los artículos de Wikipedia sobre Transformada rápida de Fourier y Transformada discreta de Fourier, pero todavía no tengo claro qué representa la matriz resultante. Así es como se ve la matriz después de realizar un fft en mi matriz 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...

Me pregunto qué representan exactamente estos números y cómo convertiría estos números en un porcentaje de una altura para cada una de las 32 barras. Además, ¿debería promediar los 2 canales juntos?

user19745
fuente

Respuestas:

209

La matriz que está mostrando son los coeficientes de transformada de Fourier de la señal de audio. Estos coeficientes se pueden utilizar para obtener el contenido de frecuencia del audio. La FFT se define para funciones de entrada con valores complejos, por lo que los coeficientes que obtenga serán números imaginarios aunque su entrada sea todos valores reales. Para obtener la cantidad de potencia en cada frecuencia, debe calcular la magnitud del coeficiente FFT para cada frecuencia. Este no es solo el componente real del coeficiente, debe calcular la raíz cuadrada de la suma del cuadrado de sus componentes real e imaginario. Es decir, si su coeficiente es a + b * j, entonces su magnitud es sqrt (a ^ 2 + b ^ 2).

Una vez que haya calculado la magnitud de cada coeficiente FFT, debe averiguar a qué frecuencia de audio pertenece cada coeficiente FFT. Una FFT de N puntos le dará el contenido de frecuencia de su señal en N frecuencias igualmente espaciadas, comenzando en 0. Porque su frecuencia de muestreo es 44100 muestras / seg. y el número de puntos en su FFT es 256, su espaciado de frecuencia es 44100/256 = 172 Hz (aproximadamente)

El primer coeficiente de su matriz será el coeficiente de frecuencia 0. Ese es básicamente el nivel de potencia promedio para todas las frecuencias. El resto de sus coeficientes contará desde 0 en múltiplos de 172 Hz hasta llegar a 128. En una FFT, solo puede medir frecuencias hasta la mitad de sus puntos de muestra. Lea estos enlaces sobre la frecuencia de Nyquist y el teorema de muestreo de Nyquist-Shannon si es un glotón para el castigo y necesita saber por qué, pero el resultado básico es que sus frecuencias más bajas se replicarán o alias en los cubos de frecuencias más altas. Entonces, las frecuencias comenzarán desde 0, aumentarán en 172 Hz para cada coeficiente hasta el coeficiente N / 2, luego disminuirán en 172 Hz hasta el coeficiente N - 1.

Esa debería ser información suficiente para comenzar. Si desea una introducción mucho más accesible a las FFT que la que se ofrece en Wikipedia, puede intentar Comprender el procesamiento de señales digitales: 2da edición. . Fue muy útil para mí.

Entonces eso es lo que representan esos números. La conversión a un porcentaje de altura se puede hacer escalando cada magnitud de componente de frecuencia por la suma de todas las magnitudes de componente. Aunque, eso solo le daría una representación de la distribución de frecuencia relativa, y no la potencia real para cada frecuencia. Podría intentar escalar por la máxima magnitud posible para un componente de frecuencia, pero no estoy seguro de que se muestre muy bien. La forma más rápida de encontrar un factor de escala viable sería experimentar con señales de audio fuertes y suaves para encontrar la configuración correcta.

Finalmente, debe promediar los dos canales juntos si desea mostrar el contenido de frecuencia de toda la señal de audio como un todo. Está mezclando el audio estéreo en audio mono y mostrando las frecuencias combinadas. Si desea dos pantallas separadas para las frecuencias derecha e izquierda, deberá realizar la Transformada de Fourier en cada canal por separado.

A. Levy
fuente
1
La mayoría de las veces solo puedo encontrar explicaciones demasiado complicadas de FFT en línea, esta fue una explicación excelente y simple de cómo el número de puntos muestreados afecta los resultados de la FFT. ¡Gracias por esto!
ecolocalización
26

Aunque este hilo tiene años, lo encontré muy útil. Solo quería dar mi opinión a cualquiera que encuentre esto y esté tratando de crear algo similar.

En cuanto a la división en barras, esto no debe hacerse como sugiere antti, dividiendo los datos por igual en función del número de barras. Lo más útil sería dividir los datos en partes de octavas, siendo cada octava el doble de la frecuencia de la anterior. (es decir, 100 Hz es una octava por encima de 50 Hz, que es una octava por encima de 25 Hz).

Dependiendo del número de compases que desee, divida todo el rango en rangos de octava de 1 / X. Basado en una frecuencia central dada de A en la barra, obtienes los límites superior e inferior de la barra de:

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

Para calcular la siguiente frecuencia central adyacente, utilice un cálculo similar:

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

Luego, promedia los datos que se ajustan a estos rangos para obtener la amplitud de cada barra.

Por ejemplo: Queremos dividir en rangos de 1/3 de octavas y comenzamos con una frecuencia central de 1 kHz.

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

Dadas 44100hz y 1024 muestras (43hz entre cada punto de datos) debemos promediar los valores de 21 a 26. (890.9 / 43 = 20.72 ~ 21 y 1122.5 / 43 = 26.10 ~ 26)

(Las barras de 1/3 de octava le darían alrededor de 30 barras entre ~ 40 Hz y ~ 20 kHz). Como puede deducir a estas alturas, a medida que subimos, promediaremos un rango mayor de números. Las barras bajas generalmente solo incluyen 1 o una pequeña cantidad de puntos de datos. Mientras que las barras más altas pueden ser el promedio de cientos de puntos. La razón es que 86 hz es una octava por encima de 43 hz ... mientras que 10086 hz suena casi igual que 10043 hz.

Erik A.
fuente
10

lo que tienes es una muestra cuya duración en el tiempo es 256/44100 = 0.00580499 segundos. Esto significa que su resolución de frecuencia es 1 / 0.00580499 = 172 Hz. Los 256 valores que obtienes de Python corresponden a las frecuencias, básicamente, de 86 Hz a 255 * 172 + 86 Hz = 43946 Hz. Los números que obtiene son números complejos (de ahí la "j" al final de cada segundo número).

EDITADO: INFORMACIÓN INCORRECTA CORREGIDA

Necesita convertir los números complejos en amplitud calculando la raíz cuadrada (i 2 + j 2 ) donde i y j son las partes real e imaginaria, resp.

Si desea tener 32 barras, por lo que tengo entendido, debería tomar el promedio de cuatro amplitudes sucesivas, obteniendo 256/4 = 32 barras como desee.

Antti Huima
fuente
4
Tenga en cuenta que, si c es un número complejo, sqrt (c.real 2 + c.imag 2) == abs (c)
tzot
0

FFT devuelve N valores complejos, ¿cuál de ustedes puede calcular module=sqrt(real_part^2+imaginary_part^2)? Para obtener el valor de cada banda, debe sumar los módulos sobre todos los armónicos dentro de la banda. A continuación puede ver un ejemplo sobre un analizador de espectro de 10 barras. El código c debe ajustarse para obtener un módulo 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;

        }

Diseñé e hice un analizador de espectro completo de 10 barras LED de Python. En lugar de usar la biblioteca nunmpy (demasiado grande e inútil para obtener solo la FFT), se creó un módulo pyd de Python (solo 27 KB) para obtener la FFT y dividir todo el espectro de audio en bandas.

Además, para leer el audio de salida se creó un módulo pyd de WASapi portaudio de loopback. Puedes ver el proyecto (diagrama de bloques) en la imagen 10BarsSpectrumAnalyzerWithWASapi.jpg

Acabo de agregar un video tutorial en mi canal de YouTube: cómo diseñar y hacer una barra LED de Python Spectrum Analyzer 10 muy inteligente


fuente