2013-02-04 4 views
1

가속 프레임 워크를 사용하여 케스 트럼 분석의 피크 값을 찾으려고합니다. 프레임의 끝이나 끝 부분에서 언제나 최고 값을 얻습니다. 마이크에서 오디오를 실시간으로 분석하고 있습니다. 이 코드에 무슨 문제가 있습니까?프레임 워크를 가속 케스트 케스트 피크 찾기

OSStatus microphoneInputCallback (void       *inRefCon, 
           AudioUnitRenderActionFlags *ioActionFlags, 
           const AudioTimeStamp   *inTimeStamp, 
           UInt32      inBusNumber, 
           UInt32      inNumberFrames, 
           AudioBufferList    *ioData){ 

// get reference of test app we need for test app attributes 
TestApp *this = (TestApp *)inRefCon; 
COMPLEX_SPLIT complexArray = this->fftA; 
void *dataBuffer = this->dataBuffer; 
float *outputBuffer = this->outputBuffer; 
FFTSetup fftSetup = this->fftSetup; 

uint32_t log2n = this->fftLog2n; 
uint32_t n = this->fftN; // 4096 
uint32_t nOver2 = this->fftNOver2; 
uint32_t stride = 1; 
int bufferCapacity = this->fftBufferCapacity; // 4096 
SInt16 index = this->fftIndex; 

OSStatus renderErr; 

// observation objects 
float *observerBufferRef = this->observerBuffer; 
int observationCountRef = this->observationCount; 

renderErr = AudioUnitRender(rioUnit, ioActionFlags, 
          inTimeStamp, bus1, inNumberFrames, this->bufferList); 
if (renderErr < 0) { 
    return renderErr; 
} 

// Fill the buffer with our sampled data. If we fill our buffer, run the 
// fft. 
int read = bufferCapacity - index; 
if (read > inNumberFrames) { 
    memcpy((SInt16 *)dataBuffer + index, this->bufferList->mBuffers[0].mData, inNumberFrames*sizeof(SInt16)); 
    this->fftIndex += inNumberFrames; 

} else { 


    // If we enter this conditional, our buffer will be filled and we should PERFORM FFT. 
    memcpy((SInt16 *)dataBuffer + index, this->bufferList->mBuffers[0].mData, read*sizeof(SInt16)); 

    // Reset the index. 
    this->fftIndex = 0; 

    /*************** FFT ***************/ 

    //multiply by window 
    vDSP_vmul((SInt16 *)dataBuffer, 1, this->window, 1, this->outputBuffer, 1, n); 

    // We want to deal with only floating point values here. 
    vDSP_vflt16((SInt16 *) dataBuffer, stride, (float *) outputBuffer, stride, bufferCapacity); 

    /** 
    Look at the real signal as an interleaved complex vector by casting it. 
    Then call the transformation function vDSP_ctoz to get a split complex 
    vector, which for a real signal, divides into an even-odd configuration. 
    */ 
    vDSP_ctoz((COMPLEX*)outputBuffer, 2, &complexArray, 1, nOver2); 

    // Carry out a Forward FFT transform. 
    vDSP_fft_zrip(fftSetup, &complexArray, stride, log2n, FFT_FORWARD); 

    vDSP_ztoc(&complexArray, 1, (COMPLEX *)outputBuffer, 2, nOver2); 


    complexArray.imagp[0] = 0.0f; 
    vDSP_zvmags(&complexArray, 1, complexArray.realp, 1, nOver2); 
    bzero(complexArray.imagp, (nOver2) * sizeof(float)); 

    // scale 
    float scale = 1.0f/(2.0f*(float)n); 
    vDSP_vsmul(complexArray.realp, 1, &scale, complexArray.realp, 1, nOver2); 

    // step 2 get log for cepstrum 
    float *logmag = malloc(sizeof(float)*nOver2); 
    for (int i=0; i < nOver2; i++) 
     logmag[i] = logf(sqrtf(complexArray.realp[i])); 


    // configure float array into acceptable input array format (interleaved) 
    vDSP_ctoz((COMPLEX*)logmag, 2, &complexArray, 1, nOver2); 

    // create cepstrum 
    vDSP_fft_zrip(fftSetup, &complexArray, stride, log2n-1, FFT_INVERSE); 




    //convert interleaved to real 
    float *displayData = malloc(sizeof(float)*n); 
    vDSP_ztoc(&complexArray, 1, (COMPLEX*)displayData, 2, nOver2); 



    float dominantFrequency = 0; 
    int currentBin = 0; 
    float dominantFrequencyAmp = 0; 

    // find peak of cepstrum 
    for (int i=0; i < nOver2; i++){ 
     //get current frequency magnitude 

     if (displayData[i] > dominantFrequencyAmp) { 
      // DLog("Bufferer filled %f", displayData[i]); 
      dominantFrequencyAmp = displayData[i]; 
      currentBin = i; 
     } 
    } 

    DLog("currentBin : %i amplitude: %f", currentBin, dominantFrequencyAmp); 

} 
return noErr; 

}

+0

평균? 창문 말이니? 창당 하나의 진폭 측정 만있을 것입니다 ... – iluvcapra

+0

예, 버퍼가 fftsize에 도달하면 코드가 fft 및 ceptrum 분석을 시작합니다. – ryback3

+0

"끝에서 또는 처음에"라고 말하면 이해가되지 않습니다. 왜냐하면 당신은 윈도우 당 bin 당 오직 하나의 float 값을 가져야하기 때문에 ... – iluvcapra

답변

0

나는 가속화 프레임 워크와 함께 일하지 않은,하지만 당신의 코드는 켑 스트 럼을 계산하기 위해 적절한 조치를 취하고있는 것으로 보인다 : 내 코드는 다음과 같습니다.

실제 음향 신호의 st 스트 럼은 매우 큰 DC 구성 요소를 가지므로 경향이 매우 높고 0 초에 가까운 위상을 나타냅니다 [sic]. Cepstrum의 DC 부분을 무시하고 20 Hz 주파수 이상의 피크를 찾습니다 (Cepstrum_Width/20Hz의 대기 상태 이상).

입력 신호에 매우 밀접하게 배음 된 일련의 배음이 포함되어있는 경우에도 퀘스트 럼은 높은 큐 프리퀀시 끝에 큰 피크를 갖습니다.

예를 들어, 아래 그림은 N = 128 및 Width = 4096의 Dirichlet 커널의 셉 스트 럼을 보여주는데, 스펙트럼은 일련의 매우 밀접한 배음입니다.

Dirichlet_Kernel_N128_Width4096

당신은 당신의 코드를 테스트하고 디버그하는 정적 합성 신호를 사용할 수 있습니다. 테스트 신호에 대한 좋은 선택은 근본적인 F와 F의 정확한 정수 배수에 여러 배음이있는 사인 곡선입니다.

Cepstra는 다음 예제와 유사해야합니다.

먼저 합성 신호.

다음 플롯은 82.4Hz의 기본 DC 성분과 일반적인 82.4Hz의 8 배 고조파를 사용하여 합성 된 합성 정상 상태 E2 노트의 st 스트 럼을 보여줍니다. 합성 사인 곡선은 4096 개의 샘플을 생성하도록 프로그래밍되었습니다.

12.36에서 현저한 비 -DC 피크를 관찰하십시오. Cepstrum 너비는 1024 (두 번째 FFT의 출력)이므로 피크는 1024/12.36 = 82.8 Hz에 해당하며 실제 기본 주파수 인 82.4 Hz에 매우 가깝습니다.

Cepstrum of synthetic E2 note

이제 실제 음향 신호.

아래의 그림은 실제 어쿠스틱 기타의 E2 노트의 셉 스트 럼을 보여줍니다. 신호는 첫 번째 FFT 이전에 창으로 표시되지 않았습니다. 542.9에서 현저한 non-DC 피크를 관찰하십시오. Cepstrum 너비는 32768 (두 번째 FFT의 출력)이므로 피크는 32768/542.9 = 60.4 Hz에 해당하며 실제 기본 주파수 인 82.4 Hz에서 상당히 떨어져 있습니다.

Cepstrum of acoustic guitar E2 note, not windowed

아래의 그래프는 같은 실제 어쿠스틱 기타의 E2 노트의 켑 스트 럼을 보여 주지만, 신호가에서 Hann이었다 이번에는 첫번째 FFT 이전에, 윈도우를. 268.46에 눈에 띄는 비 -DC 피크를 관찰하십시오. Cepstrum 너비는 32768 (두 번째 FFT의 출력)이므로, 피크는 32768/268.46 = 122.1 Hz에 해당하며 이는 기본 주파수 인 82.4 Hz에서 훨씬 더 멀리 떨어져 있습니다.이 분석에 사용

Cepstrum of acoustic guitar E2 note, Hann windowed

어쿠스틱 기타의 E2 노트가 스튜디오 조건에서 고품질의 마이크 44.1 kHz로 샘플링, 그것은 본질적으로 제로 배경 잡음, 다른 악기 나 목소리없이 사후 처리를 포함한다.

참고 :

실제 오디오 신호 데이터, 합성 신호 생성, 플롯, FFT, 그리고 캡스 트럼 분석은 여기에 행해졌 다 : Musical instrument cepstrum 당신이 당신에게 무엇을 "프레임"시작 또는 끝에서 말을

+0

Babson이 너를 매우 자세히 대답 해 준 덕분에 나에게 많은 도움이되었다. 전나무 음모에 빈 (bin) 1024에 피크가 있습니다.이 시간에 해당하는 값은 무엇입니까? 샘플 속도는 44100입니다. 각 bin은 1/44100입니다. 그래서 1024 * (1/44100)는 셉 스트 럼 빈의 시간 가치를 제공합니까? 사실입니까? – ryback3

+0

신호 이벤트가 발생하는 시간은 스펙트럼 또는 C 스트 럼 데이터에서 확인할 수 없습니다. 주파수와 관련된 신호 이벤트의 시간을 분석해야하는 경우 신호의 분광을 계산해야하며 분광 프로그램을 계산하는 데 사용되는 단시간 FFT에 적절한 창 크기를 선택해야합니다. 주의 깊게 제작되고 적절히 조정 된 스펙트로 그램은 주파수와 관련된 관심사의 시간적 사건을 해결할 수있게합니다. – Babson