2014-09-22 6 views
0
이 코드를 사용

(애플의 audioRouch 샘플 기준) :iOS를 얻는 방법 FFT로 주파수 크기가 빨라 집니까?

void FFTHelper::ComputeFFT(Float32* inAudioData, Float32* outFFTData) 
{ 
    if (inAudioData == NULL || outFFTData == NULL) return; 

    // Generate a split complex vector from the real data 
    vDSP_ctoz((COMPLEX *)inAudioData, 2, &mDspSplitComplex, 1, mFFTLength); 

    // Take the fft and scale appropriately 
    vDSP_fft_zrip(mSpectrumAnalysis, &mDspSplitComplex, 1, mLog2N, kFFTDirection_Forward); 
    vDSP_vsmul(mDspSplitComplex.realp, 1, &mFFTNormFactor, mDspSplitComplex.realp, 1, mFFTLength); 
    vDSP_vsmul(mDspSplitComplex.imagp, 1, &mFFTNormFactor, mDspSplitComplex.imagp, 1, mFFTLength); 

    // Zero out the nyquist value 
    mDspSplitComplex.imagp[0] = 0.0; 

    // Complex vector magnitudes squared; single precision. 
    // Calculates the squared magnitudes of complex vector A. 
    vDSP_zvmags(&mDspSplitComplex, 1, outFFTData, 1, mFFTLength); 

} 

는 가장 간단한에 FFT를 계산하기 - (1 개 단위에 의해 이동) 1Hz의 부비동 파 :

Float32 waveFreq   = 1.0; 
    int  samplesCount  = 1024; 
    Float32 samplesPerSecond = 1000;  //sample rate 
    Float32 dt = 1/samplesPerSecond; 
    Float32 sd = M_PI * 2.0 * waveFreq; 

    FFTHelper *mFFTHelper = new FFTHelper(samplesCount); 

    Float32 NyquistMaxFreq = samplesPerSecond/2.0; 
    Float32 fftDataSize  = samplesCount/2.0; 

    Float32 *sinusoidOriginal = (Float32 *)malloc(sizeof(Float32) * samplesCount); 
    Float32 *outFFTData = (Float32 *)malloc(sizeof(Float32) * fftDataSize); 

    // 2. Generate sin samples: 
    for (int i = 0; i < samplesCount; i++) { 

     Float32 x = dt * i; 
     sinusoidOriginal[i] = sin(sd * x) + 1; 
     [originalPlot addVector2D:GLVector2DMake(x, sinusoidOriginal[i])]; 
    } 

    mFFTHelper->ComputeFFT(sinusoidOriginal, outFFTData); 

    for (int i = 0; i < fftDataSize; i++) { 

      Float32 hz = ((Float32)i/(Float32)fftDataSize) * NyquistMaxFreq; 
      GLfloat mag = outFFTData[i]; 
      [fftPlot addVector2D:GLVector2DMake(hz, 0)]; 
      [fftPlot addVector2D:GLVector2DMake(hz, mag)]; 

    } 

내가 얻을 결과는 다음과 같습니다

enter image description here

,536,913,632 10

검은 선은 FTT의 플로터 결과로, 해당 주파수에서 수평으로 배치됩니다. DC 값 (왼쪽에서 첫 번째 검정색 선)은 정상적으로 보입니다. y = sin (x) + 1 수직 오프셋을 올바르게 나타냅니다.

그러나 sinus 방정식에있는 유일한 주파수를 나타내는 두 번째 검은 선인 은 크기 = 1이 아니며 정확히 1Hz에 머 무르지 않습니까?

누구나 입력 신호에서 FFT 결과를 크기 단위로 변환 할 수있는 vDSP 기능을 사용할 수 있습니까?

답변

2

짧은 대답은 : https://stackoverflow.com/a/19966776/468812 를 그리고 그것은 좋은,하지만 :

은이 곳에서 내 대답에서 코드를 사용하는 것

당신은 당신의 신호에 이러한 추가 주파수를 피할 수 없다.

생성하는 신호 (sin 파형)는 무한 신호입니다. "자르기"와 "신호 조각 만 사용"하면 양 끝 부분에 "클리핑 노이즈"가 발생합니다.

그러나 FFT보다 큰 입력 청크와 using windowing을 사용하면 잡음을 최소화 할 수 있습니다. Accelerate Framework는 훌륭하고 간단한 윈도우 기능을 제공합니다. (예 : Hann Function, vDSP_hann_window) 큰 입력 청크도 사용하십시오. 입력이 클수록 주파수 검출이 정확합니다.

this article, google : Spectral Leakage, window function을 참조하십시오.