Я пытаюсь построить треугольные фильтры для генерации 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 );
}
Затем я кусочно умножаю вышеуказанные векторы на результаты БПФ (где интервал 0 - это интервал смещения 0 Гц или постоянного тока) и складываю их (по сути, скалярное произведение).
Этот кажется работает достаточно хорошо, но результаты, которые я получаю по сравнению с 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 );
}
Вот график, где серия 1 - это мои MFCC, а серия 2 - это IPP:
После этапов регистрации и подъема (которые, как я подтвердил, работают так же, как и этапы IPP) результаты еще более неверны.
Любые идеи и указатели будут высоко оценены!
Изменить: я должен отметить, что здесь есть некоторая документация по функциям IPP:
Кажется, это показывает математику. Однако я не уверен, что именно такое yk и ck ...