고속 푸리에 변환을 사용하여 오디오 분석


109

파이썬으로 그래픽 스펙트럼 분석기를 만들려고합니다.

저는 현재 1024 바이트의 16 비트 듀얼 채널 44,100Hz 샘플 속도 오디오 스트림을 읽고 두 채널의 진폭을 함께 평균화하고 있습니다. 이제 256 개의 부호있는 단락이 있습니다. 이제 numpy와 같은 모듈을 사용하여 해당 어레이에서 fft를 수행하고 그 결과를 사용하여 그래픽 스펙트럼 분석기를 만들려고합니다. 시작은 32 바입니다.

Fast Fourier Transform 및 Discrete Fourier Transform에 대한 위키피디아 기사를 읽었지만 결과 배열이 무엇을 나타내는 지 아직 명확하지 않습니다. 다음은 numpy를 사용하여 배열에서 fft를 수행 한 후 배열이 어떻게 생겼는지입니다.

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

이 숫자가 정확히 무엇을 나타내는 지,이 숫자를 32 개의 막대 각각에 대한 높이의 백분율로 변환하는 방법이 궁금합니다. 또한 두 채널을 함께 평균해야합니까?

답변:


209

표시되는 배열은 오디오 신호의 푸리에 변환 계수입니다. 이러한 계수는 오디오의 주파수 콘텐츠를 가져 오는 데 사용할 수 있습니다. FFT는 복잡한 값의 입력 함수에 대해 정의되므로 입력이 모두 실제 값이더라도 얻을 수있는 계수는 허수입니다. 각 주파수의 전력량을 얻으려면 각 주파수에 대한 FFT 계수의 크기를 계산해야합니다. 입니다 하지 계수의 단지 실제 구성 요소, 당신은 실수 및 허수 성분의 제곱의 합의 제곱근을 계산해야합니다. 즉, 계수가 a + b * j이면 그 크기는 sqrt (a ^ 2 + b ^ 2)입니다.

각 FFT 계수의 크기를 계산 한 후에는 각 FFT 계수가 속한 오디오 주파수를 파악해야합니다. N 포인트 FFT는 0부터 시작하여 동일한 간격의 N 주파수에서 신호의 주파수 성분을 제공합니다. 샘플링 주파수는 44100 샘플 / 초이기 때문입니다. FFT의 포인트 수는 256이고 주파수 간격은 44100/256 = 172Hz (대략)입니다.

배열의 첫 번째 계수는 0 주파수 계수입니다. 그것은 기본적으로 모든 주파수에 대한 평균 전력 레벨입니다. 나머지 계수는 172Hz의 배수로 0에서 128에 도달 할 때까지 카운트됩니다. FFT에서는 샘플 포인트의 절반까지만 주파수를 측정 할 수 있습니다. 처벌의 열성 인이고 그 이유를 알아야하는 경우 Nyquist FrequencyNyquist-Shannon Sampling Theorem 에서이 링크를 읽으십시오 .하지만 기본 결과는 더 낮은 주파수가 더 높은 주파수 버킷에서 복제되거나 앨리어싱 된다는 것 입니다. 따라서 주파수는 0에서 시작하여 N / 2 계수까지 각 계수에 대해 172Hz 증가한 다음 N-1 계수까지 172Hz 감소합니다.

시작하기에 충분한 정보 여야합니다. Wikipedia에서 제공하는 것보다 훨씬 더 접근하기 쉬운 FFT 소개를 원한다면 디지털 신호 처리 이해 : 2nd Ed. . 저에게 매우 도움이되었습니다.

이것이 그 숫자가 나타내는 것입니다. 높이의 백분율로 변환하는 것은 모든 구성 요소 크기의 합으로 각 주파수 구성 요소 크기를 조정하여 수행 할 수 있습니다. 비록 그것은 당신에게 상대적인 주파수 분포의 표현을 제공 할 뿐이며 각 주파수에 대한 실제 전력은 아닙니다. 주파수 구성 요소에 대해 가능한 최대 크기로 스케일링을 시도 할 수 있지만 이것이 잘 표시되는지는 모르겠습니다. 실행 가능한 스케일링 계수를 찾는 가장 빠른 방법은 크고 부드러운 오디오 신호를 실험하여 올바른 설정을 찾는 것입니다.

마지막으로 전체 오디오 신호의 주파수 내용을 전체적으로 표시하려면 두 채널을 함께 평균화해야합니다. 스테레오 오디오를 모노 오디오로 믹싱하고 결합 된 주파수를 표시합니다. 오른쪽 및 왼쪽 주파수에 대해 두 개의 개별 디스플레이를 원하는 경우 각 채널에서 개별적으로 푸리에 변환을 수행해야합니다.


1
나는 대부분 온라인에서 FFT에 대한 지나치게 복잡한 설명 만 찾을 수 있습니다. 이것은 샘플링 된 포인트 수가 FFT의 결과에 어떻게 영향을 미치는지에 대한 훌륭하고 간단한 설명이었습니다. 감사합니다!
echolocation

26

이 스레드는 오래되었지만 매우 유용하다는 것을 알았습니다. 나는 이것을 발견하고 비슷한 것을 만들려고 노력하는 모든 사람에게 내 의견을주고 싶었습니다.

막대로의 분할에 관해서는 막대의 수를 기준으로 데이터를 균등하게 분할하여이 작업을 수행해서는 안됩니다. 가장 유용한 방법은 데이터를 옥타브 부분으로 나누는 것입니다. 각 옥타브는 이전 주파수의 두 배입니다. (즉, 100hz는 50hz보다 한 옥타브, 25hz보다 한 옥타브).

원하는 마디 수에 따라 전체 범위를 1 / X 옥타브 범위로 나눕니다. 막대에서 A의 주어진 중심 주파수를 기반으로 막대의 상한 및 하한을 다음에서 얻습니다.

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

다음 인접 중심 주파수를 계산하려면 비슷한 계산을 사용합니다.

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

그런 다음이 범위에 맞는 데이터를 평균하여 각 막대의 진폭을 구합니다.

예를 들어, 1/3 옥타브 범위로 나누고 싶고 1khz의 중심 주파수로 시작합니다.

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

44100hz 및 1024 개의 샘플 (각 데이터 포인트 사이의 43hz)이 주어지면 21에서 26까지의 값을 평균화해야합니다. (890.9 / 43 = 20.72 ~ 21 및 1122.5 / 43 = 26.10 ~ 26)

(1/3 옥타브 바는 ~ 40hz와 ~ 20khz 사이에서 약 30 바를 얻을 수 있습니다). 지금까지 알 수 있듯이, 우리가 더 높아질수록 더 넓은 범위의 숫자를 평균화 할 것입니다. 낮은 막대는 일반적으로 1 개 또는 적은 수의 데이터 포인트 만 포함합니다. 높은 막대는 평균 수백 개의 포인트가 될 수 있습니다. 그 이유는 86hz가 43hz보다 높은 옥타브이기 때문입니다 .10086hz는 10043hz와 거의 동일하게 들립니다.


10

당신이 가진 것은 256/44100 = 0.00580499 초의 길이를 가진 샘플입니다. 즉, 주파수 해상도는 1 / 0.00580499 = 172Hz입니다. 파이썬에서 얻은 256 개의 값은 기본적으로 86Hz에서 255 * 172 + 86Hz = 43946Hz까지의 주파수에 해당합니다. 당신이 얻는 숫자는 복소수입니다 (따라서 매초 숫자의 끝에있는 "j").

수정 됨 : 잘못된 정보 수정

sqrt (i 2 + j 2 ) 를 계산하여 복소수를 진폭으로 변환해야합니다. 여기서 i와 j는 실수 부와 허수 부, resp입니다.

32 개의 바를 갖고 싶다면, 내가 아는 한 4 개의 연속 된 진폭의 평균을 취하여 원하는대로 256/4 = 32 바를 얻어야합니다.


4
c가 복소수이면 sqrt (c.real 2 + c.imag 2) == abs (c)
tzot

0

FFT는 module=sqrt(real_part^2+imaginary_part^2). 각 대역의 값을 얻으려면 대역 내부의 모든 고조파에 대한 모듈을 합산해야합니다. 아래에서 10 바 스펙트럼 분석기에 대한 예를 볼 수 있습니다. pyd python 모듈을 얻으려면 c 코드를 래핑해야합니다.

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;

        }

저는 Python으로 전체 10 개의 LED 바 스펙트럼 분석기를 설계하고 만들었습니다. 대신 nunmpy 라이브러리 (너무 크고 FFT 만 얻기에는 쓸모가 없음)를 사용하기 위해 FFT를 얻고 전체 오디오 스펙트럼을 대역으로 분할하기위한 python pyd 모듈 (단 27KB)이 생성되었습니다.

또한 출력 오디오를 읽기 위해 루프백 WASapi portaudio pyd 모듈이 생성되었습니다. 10BarsSpectrumAnalyzerWithWASapi.jpg 이미지에서 프로젝트 (블록 다이어그램)를 볼 수 있습니다.

내 YouTube 채널에 튜토리얼 비디오를 추가했습니다 : 매우 스마트 한 Python Spectrum Analyzer 10 Led Bar를 설계하고 만드는 방법

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.