ускорить поиск пика кепстра фреймворка

Я пытаюсь найти пиковые значения анализа кепстра с помощью ускоренной структуры. Я всегда получаю пиковые значения в конце или в начале кадров. Я анализирую это в режиме реального времени, получая звук с микрофона. Что не так с этим моим кодом? Мой код ниже:

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;

}


person ryback3    schedule 04.02.2013    source источник
comment
Когда вы говорите в начале или в конце кадров, что вы имеете в виду? Вы имеете в виду окна? Будет только одно измерение амплитуды на окно...   -  person iluvcapra    schedule 05.02.2013
comment
да, я имею в виду окно, когда буфер достигает размера fft, код начинает анализ fft и ceptrum   -  person ryback3    schedule 05.02.2013
comment
Когда вы говорите в конце или в начале, я не понимаю, так как у вас должно быть только одно значение с плавающей запятой на корзину для каждого окна...   -  person iluvcapra    schedule 05.02.2013
comment
я имею в виду начальный индекс значения displayData [i] или конечный индекс значения displayData [i], в котором хранится амплитуда кепстра. Итак, как вы говорите, начальное или конечное значение бина каждого окна. Я все еще не мог найти свою ошибку   -  person ryback3    schedule 05.02.2013


Ответы (1)


Я не работал с Accelerate Framework, но ваш код, похоже, предпринимает правильные действия для расчета кепстра.

Кепстр реальных акустических сигналов, как правило, имеет очень большую постоянную составляющую, большой пик на частоте, близкой к нулевой [так в оригинале]. Просто игнорируйте часть кепстра, близкую к постоянному току, и ищите пики выше частоты 20 Гц (выше quefrency Cepstrum_Width/20Hz).

Если входной сигнал содержит серию очень близко расположенных обертонов, кепстр также будет иметь большой пик на конце высокой частоты.

Например, на приведенном ниже графике показан кепстр ядра Дирихле N = 128 и ширины = 4096, спектр которого представляет собой серию очень близко расположенных обертонов.

Dirichlet_Kernel_N128_Width4096

Вы можете использовать статический синтетический сигнал для тестирования и отладки кода. Хорошим выбором в качестве тестового сигнала является любая синусоида с основной частотой F и несколькими обертонами, точно кратными F.

Ваша Cepstra должна выглядеть примерно так, как показано в следующих примерах.

Сначала синтетический сигнал.

На приведенном ниже графике показан кепстр синтетической устойчивой ноты E2, синтезированной с использованием типичного компонента, близкого к постоянному току, основной частоты 82,4 Гц и 8 гармоник с целыми кратными 82,4 Гц. Синтетическая синусоида была запрограммирована на генерацию 4096 отсчетов.

Обратите внимание на заметный не постоянный пик на 12,36. Ширина кепстра составляет 1024 (выход второго БПФ), поэтому пик соответствует 1024/12,36 = 82,8 Гц, что очень близко к истинной основной частоте 82,4 Гц.

Кепстр синтетической банкноты E2

Теперь настоящий акустический сигнал.

На графике ниже показан кепстр ноты E2 настоящей акустической гитары. Сигнал не был обработан окном до первого БПФ. Обратите внимание на заметный пик без постоянного тока при 542,9. Ширина кепстра составляет 32768 (выход второго БПФ), поэтому пик соответствует 32768/542,9 = 60,4 Гц, что довольно далеко от истинной основной частоты 82,4 Гц.

Кепстр акустической гитары E2 note, не оконный

На приведенном ниже графике показан кепстр той же реальной ноты E2 акустической гитары, но на этот раз сигнал был обработан окном Ханна до первого БПФ. Обратите внимание на заметный пик без постоянного тока на уровне 268,46. Ширина кепстра составляет 32768 (выход второго БПФ), поэтому пик соответствует 32768/268,46 = 122,1 Гц, что еще дальше от истинной основной частоты 82,4 Гц.

Кепстр акустической гитары, нота E2, Ханн в окне

Нота E2 акустической гитары, используемая для этого анализа, была записана на частоте 44,1 кГц с помощью высококачественного микрофона в студийных условиях, она практически не содержит фонового шума, других инструментов или голосов и постобработки.

Использованная литература:

Данные реального звукового сигнала, генерация синтетического сигнала, графики, БПФ и кепстральный анализ были выполнены здесь: Музыкальный инструмент кепстр

person Babson    schedule 15.02.2013
comment
Бэбсон, спасибо за очень подробный ответ, он мне очень помог. На первом графике у вас есть пик в ячейке 1024. Каково на этот раз значение, соответствующее времени? Например, ваша частота дискретизации 44100. Каждый бин занимает 1/44100. Итак, 1024 * (1/44100) дает временную стоимость кепстра? Это правда? - person ryback3; 15.02.2013
comment
Время, в которое происходят сигнальные события, не может быть определено ни по данным Spectrum, ни по данным Cepstrum. Если вам нужно определить время события сигнала по отношению к частоте, вы должны рассчитать спектрограмму сигнала и выбрать соответствующий размер окна для кратковременного БПФ, используемого для расчета спектрограммы. Тщательно построенная и должным образом настроенная спектрограмма позволит вам определить интересующие вас временные события, связанные с частотой. - person Babson; 15.02.2013