Создание банков фильтров MFCC так же, как примитивы производительности Intel

Я пытаюсь построить треугольные фильтры для генерации MFCC. У меня есть существующий код, основанный на IPP 6, но, поскольку IPP 8 уже в пути, я бы очень хотел получить реализацию, которая работает и не зависит от старой, теперь не поддерживаемой, библиотеки.

Я сгенерировал соответствующие центральные частоты в мелком масштабе (плюс 2 на каждом конце).

Затем я пытаюсь построить фильтры следующим образом:

std::vector< std::vector< float > > ret;
int numFilters  = freqPositions.size() - 2;

for( int f = 1; f < numFilters + 1; f++ )
{
float freqLow   = freqPositions[f - 1];
float freqMid   = freqPositions[f];
float freqHigh  = freqPositions[f + 1];

float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples + 1);
float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples + 1);
float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples + 1);

std::vector< float > fbank;
for( int s = 0; s < (numSamples + 1); s++ )
{
if      ( s >= binLow && s < binMid )
{
const float fAmpl   = (s - binLow) / (float)(binMid - binLow);
fbank.push_back( fAmpl );
}
else if ( s >= binMid && s <= binHigh )
{
const float fAmpl   = 1.0f - ((s - binMid) / (float)(binHigh - binMid));
fbank.push_back( fAmpl );
}
else
{
fbank.push_back( 0.0f );
}

}

ret.push_back( fbank );
}

Затем я по частям умножаю вышеупомянутые векторы на результаты FFT (где bin 0 — это смещение 0 Гц или DC Offset bin) и складываю их (по существу, произведение точек).

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

Я что-то не так делаю?

Весь процесс состоит в том, чтобы взять БПФ, вычислить величины возвращенного комплексного вектора (std :: abs) и затем применить банки фильтров, которые вычисляются, как указано выше. Код выглядит следующим образом:

std::vector< float > ApplyFilterBanks( std::vector< std::vector< float > >& filterBanks, std::vector< float >& fftMags )
{
std::vector< float > ret;
for( int fb = 0; fb < (int)filterBanks.size(); fb++ )
{
float res = 0.0f;
Vec::Dot( res, &filterBanks[fb].front(), &fftMags.front(), filterBanks[fb].size() );
ret.push_back( res );
}
return ret;
}

{
const int kFFTSize      = 1 << mFFT.GetFFTOrder();
const int kFFTSizeDiv2  = kFFTSize >> 1;
std::vector< float > audioToFFT;
audioToFFT.reserve( kFFTSize );
std::copy( pAudio, pAudio + numSamples, std::back_inserter( audioToFFT ) );
audioToFFT.resize( kFFTSize );

std::vector< float > hammingWindow( numSamples );
Vec::BuildHammingWindow( hammingWindow );
Vec::Multiply( &audioToFFT.front(), &audioToFFT.front(), &hammingWindow.front(), numSamples );

std::vector< std::complex< float > > fftResult( kFFTSize + 1 );

// FFT the incoming audio.
mFFT.ForwardFFT( &fftResult.front(), &audioToFFT.front(), kFFTSize );

// Calculate the magnitudes of the resulting FFT.
Vec::Magnitude( &audioToFFT.front(), &fftResult.front(), kFFTSizeDiv2 + 1 );
//Vec::Multiply( &audioToFFT.front(), &audioToFFT.front(), &audioToFFT.front(), kFFTSizeDiv2 + 1 );

// Apply the MFCC filter banks.
std::vector< float > filtered   = ApplyFilterBanks( mFilterBanks, audioToFFT );
}

Вот график, где Series 1 — это мои MFCC, а Series 2 — это IPP:

Мои MFCCs против IPP's

После этапов регистрации и подъема (которые я подтвердил, что они работают так же, как и IPP), результаты становятся еще более неправильными.

Любые идеи и указатели будут высоко оценены!

редактироватьСледует отметить, что здесь есть некоторая документация по функциям IPP:

http://software.intel.com/sites/products/documentation/hpc/ipp/ipps/ipps_ch8/functn_MelFBankInitAlloc.html

Это кажется, чтобы показать математику. Я не уверен, однако, что именно yk и ck являются …

1

Решение

Хорошо, я справился с этой задачей намного лучше.

Я нашел 2 проблемы, во-первых:

float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples + 1);
float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples + 1);
float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples + 1);

должно быть:

float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples);
float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples);
float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples);

и во-вторых, я неправильно рассчитывал свои шаги в пространстве. Я делал следующее:

const float melStep     = melDiff / (numFilterBanks + 2);

когда я должен был делать:

const float melStep     = melDiff / (numFilterBanks + 1);

Теперь мои результаты, хотя и не идентичны, теперь показывают НАМНОГО лучшее соответствие:

Предварительный журнал и отмененные MFCC

И финальные MFCCs:

Финал MFCC

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]