Analise áudio usando Fast Fourier Transform

109

Estou tentando criar um analisador de espectro gráfico em python.

No momento, estou lendo 1.024 bytes de um fluxo de áudio de taxa de amostragem de canal duplo de 16 bits e 44.100 Hz e calculando a média da amplitude dos 2 canais juntos. Portanto, agora tenho uma matriz de 256 shorts assinados. Agora quero pré-formar um fft nessa matriz, usando um módulo como numpy, e usar o resultado para criar o analisador de espectro gráfico, que, para começar, terá apenas 32 barras.

Eu li os artigos da Wikipedia sobre Fast Fourier Transform e Discrete Fourier Transform, mas ainda não estou certo do que a matriz resultante representa. Esta é a aparência da matriz depois que eu pré-formo um fft na minha 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...

Estou me perguntando o que exatamente esses números representam e como eu converteria esses números em uma porcentagem de uma altura para cada uma das 32 barras. Além disso, devo calcular a média dos 2 canais juntos?

user19745
fonte

Respostas:

209

A matriz que você está mostrando são os coeficientes da transformada de Fourier do sinal de áudio. Esses coeficientes podem ser usados ​​para obter o conteúdo de frequência do áudio. O FFT é definido para funções de entrada de valores complexos, então os coeficientes que você obtém serão números imaginários, mesmo que sua entrada seja todos valores reais. Para obter a quantidade de potência em cada frequência, você precisa calcular a magnitude do coeficiente FFT para cada frequência. Este não é apenas o componente real do coeficiente, você precisa calcular a raiz quadrada da soma do quadrado de seus componentes real e imaginário. Ou seja, se seu coeficiente é a + b * j, então sua magnitude é sqrt (a ^ 2 + b ^ 2).

Depois de calcular a magnitude de cada coeficiente FFT, você precisa descobrir a qual frequência de áudio cada coeficiente FFT pertence. Um ponto N FFT fornecerá o conteúdo de frequência do seu sinal em N frequências igualmente espaçadas, começando em 0. Porque sua frequência de amostragem é 44100 amostras / s. e o número de pontos em seu FFT é 256, seu espaçamento de frequência é 44100/256 = 172 Hz (aproximadamente)

O primeiro coeficiente em sua matriz será o coeficiente de frequência 0. Esse é basicamente o nível de potência médio para todas as frequências. O resto de seus coeficientes contará de 0 em múltiplos de 172 Hz até você chegar a 128. Em um FFT, você só pode medir frequências até a metade de seus pontos de amostra. Leia estas links na frequência de Nyquist e Nyquist-Shannon Sampling Theorem se você é um glutão de castigo e precisa saber o porquê, mas o resultado básico é que as frequências mais baixas vão ser replicados ou alias nos baldes de freqüência mais alta. Portanto, as frequências começarão de 0, aumentarão em 172 Hz para cada coeficiente até o coeficiente N / 2 e, em seguida, diminuirão em 172 Hz até o coeficiente N - 1.

Isso deve ser informação suficiente para você começar. Se desejar uma introdução muito mais acessível aos FFTs do que a fornecida na Wikipedia, você pode tentar Entendendo o Processamento de Sinal Digital: 2ª Ed . Foi muito útil para mim.

Então é isso que esses números representam. A conversão para uma porcentagem da altura pode ser feita escalando cada magnitude do componente de frequência pela soma de todas as magnitudes do componente. No entanto, isso daria apenas uma representação da distribuição de frequência relativa, e não a potência real de cada frequência. Você poderia tentar dimensionar pela magnitude máxima possível para um componente de frequência, mas não tenho certeza se isso seria exibido muito bem. A maneira mais rápida de encontrar um fator de escala viável seria experimentar em sinais de áudio altos e baixos para encontrar a configuração certa.

Finalmente, você deve calcular a média dos dois canais juntos se quiser mostrar o conteúdo da frequência de todo o sinal de áudio como um todo. Você está mixando o áudio estéreo em áudio mono e mostrando as frequências combinadas. Se você quiser duas exibições separadas para as frequências direita e esquerda, precisará realizar a Transformação de Fourier em cada canal separadamente.

A. Levy
fonte
1
Na maioria das vezes, só consigo encontrar explicações excessivamente complicadas sobre FFT online. Essa foi uma explicação excelente e simples de como o número de pontos amostrados afeta os resultados da FFT. Obrigado por isso!
ecolocalização de
26

Embora este tópico tenha anos, achei-o muito útil. Eu só queria dar minha opinião a qualquer pessoa que descobrir isso e estiver tentando criar algo semelhante.

Quanto à divisão em barras, isso não deve ser feito como o antti sugere, dividindo os dados igualmente com base no número de barras. O mais útil seria dividir os dados em oitavas, cada oitava sendo o dobro da frequência da anterior. (ou seja, 100 Hz é uma oitava acima de 50 Hz, que é uma oitava acima de 25 Hz).

Dependendo de quantos compassos você deseja, você divide toda a gama em intervalos de 1 / X oitava. Com base em uma determinada frequência central de A na barra, você obtém os limites superior e inferior da barra de:

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

Para calcular a próxima frequência central adjacente, você usa um cálculo semelhante:

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

Em seguida, você calcula a média dos dados que se enquadram nessas faixas para obter a amplitude de cada barra.

Por exemplo: Queremos dividir em intervalos de 1/3 oitavas e começamos com uma frequência central de 1 khz.

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

Dadas amostras de 44100 Hz e 1024 (43 Hz entre cada ponto de dados), devemos calcular a média dos valores de 21 a 26. (890,9 / 43 = 20,72 ~ 21 e 1122,5 / 43 = 26,10 ~ 26)

(Barras de 1/3 de oitava gerariam cerca de 30 compassos entre ~ 40 Hz e ~ 20 kHz). Como você pode perceber agora, à medida que subimos, teremos a média de um intervalo maior de números. Barras baixas normalmente incluem apenas 1 ou um pequeno número de pontos de dados. Enquanto as barras mais altas podem ter a média de centenas de pontos. A razão é que 86 Hz é uma oitava acima de 43 Hz ... enquanto 10086 Hz soa quase o mesmo que 10043 Hz.

Erik A.
fonte
10

o que você tem é uma amostra cuja duração no tempo é 256/44100 = 0,00580499 segundos. Isso significa que sua resolução de frequência é 1 / 0,00580499 = 172 Hz. Os 256 valores que você obtém do Python correspondem às frequências, basicamente, de 86 Hz a 255 * 172 + 86 Hz = 43946 Hz. Os números que você obtém são números complexos (daí o "j" no final de cada segundo número).

EDITADO: INFORMAÇÕES ERRADAS FIXAS

Você precisa converter os números complexos em amplitude calculando o sqrt (i 2 + j 2 ) onde i e j são as partes reais e imaginárias, resp.

Se você quiser ter 32 barras, você deve, pelo que entendi, tirar a média de quatro amplitudes sucessivas, obtendo 256/4 = 32 barras como você deseja.

Antti Huima
fonte
4
Observe que, se c for um número complexo, sqrt (c.real 2 + c.imag 2) == abs (c)
tzot
0

FFT retorna N valores complexos que podem ser calculados module=sqrt(real_part^2+imaginary_part^2). Para obter o valor de cada banda, você deve somar os módulos sobre todos os harmônicos dentro da banda. Abaixo você pode ver um exemplo sobre um analisador de espectro de 10 barras. O código c deve ser encapsulado para obter um 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;

        }

Eu projetei e fiz um analisador de espectro de barras inteiro de 10 led da Python. Em vez de usar a biblioteca nunmpy (muito grande e inútil para obter apenas o FFT), foi criado um módulo python pyd (apenas 27 KB) para obter o FFT e dividir todo o espectro de áudio em bandas.

Além disso, para ler a saída de áudio, foi criado um módulo loopback WASapi portaudio pyd. Você pode ver o projeto (diagrama de blocos) na imagem 10BarsSpectrumAnalyzerWithWASapi.jpg

Acabei de adicionar um vídeo tutorial no meu canal do YouTube: como projetar e fazer uma barra de LED 10 do Python Spectrum Analyzer muito inteligente


fonte