БПФ на iPhone, чтобы игнорировать фоновый шум и найти более низкие частоты
Я реализовал проект Demetri's Pitch Detector для iPhone и столкнулся с двумя проблемами. 1) любой фоновый шум посылает бананам показания частоты и 2) звуки более низкой частоты не передаются правильно. Я пытался настроить свою гитару, и пока работали более высокие струны - тюнер не мог правильно различить низкий E.
Код Pitch Detection находится в RIOInterface.mm и выглядит примерно так...
// get the data
AudioUnitRender(...);
// convert int16 to float
Convert(...);
// divide the signal into even-odd configuration
vDSP_ctoz((COMPLEX*)outputBuffer, 2, &A, 1, nOver2);
// apply the fft
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
// convert split real form to split vector
vDSP_ztoc(&A, 1, (COMPLEX *)outputBuffer, 2, nOver2);
Затем Деметрий определяет "доминирующую" частоту следующим образом:
float dominantFrequency = 0;
int bin = -1;
for (int i=0; i<n; i+=2) {
float curFreq = MagnitudeSquared(outputBuffer[i], outputBuffer[i+1]);
if (curFreq > dominantFrequency) {
dominantFrequency = curFreq;
bin = (i+1)/2;
}
}
memset(outputBuffer, 0, n*sizeof(SInt16));
// Update the UI with our newly acquired frequency value.
[THIS->listener frequencyChangedWithValue:bin*(THIS->sampleRate/bufferCapacity)];
Для начала я считаю, что мне нужно применить ФИЛЬТР НИЗКОГО ПРОХОДА... но я не эксперт FFT и не уверен, где именно и как это сделать для данных, возвращаемых функциями vDSP. Я также не уверен, как повысить точность кода на низких частотах. Похоже, существуют другие алгоритмы для определения доминирующей частоты, но, опять же, ищем толчок в правильном направлении при использовании данных, возвращаемых платформой Apple Accelerate.
ОБНОВИТЬ:
Ускоряющая структура на самом деле имеет некоторые оконные функции. Я настраиваю основное окно вот так
windowSize = maxFrames;
transferBuffer = (float*)malloc(sizeof(float)*windowSize);
window = (float*)malloc(sizeof(float)*windowSize);
memset(window, 0, sizeof(float)*windowSize);
vDSP_hann_window(window, windowSize, vDSP_HANN_NORM);
который я затем применяю, вставив
vDSP_vmul(outputBuffer, 1, window, 1, transferBuffer, 1, windowSize);
перед функцией vDSP_ctoz. Затем я изменяю оставшуюся часть кода, чтобы использовать 'TransferBuffer' вместо outputBuffer... но до сих пор не заметил каких-либо существенных изменений в окончательном предположении основного тона.
4 ответа
Высота тона не совпадает с частотой пиковой величины (это то, что БПФ в структуре ускорения может дать вам напрямую). Таким образом, любой детектор пиковой частоты не будет надежным для оценки основного тона. Фильтр нижних частот не поможет, если нота имеет отсутствующий или очень слабый фундаментальный (часто встречающийся в некоторых звуках голоса, фортепиано и гитары) и / или множество мощных обертонов в своем спектре.
Посмотрите на широкополосный спектр или спектрограф ваших музыкальных звуков, и вы увидите проблему.
Другие методы обычно необходимы для более надежной оценки музыкального тона. Некоторые из них включают в себя методы автокорреляции (AMDF, ASDF), кепструм / кепстральный анализ, спектр гармонических произведений, фазовый вокодер и / или составные алгоритмы, такие как RAPT (надежный алгоритм для отслеживания основного тона) и YAAPT. БПФ полезен только как часть некоторых из вышеуказанных методов.
По крайней мере, вам нужно применить оконную функцию к данным вашей временной области, прежде чем вычислять БПФ. Без этого шага спектр мощности будет содержать артефакты (см.: спектральная утечка), которые будут препятствовать вашим попыткам извлечения информации о тоне.
Простого окна Ханна (иначе Ханнинга) должно быть достаточно.
Функция частотной характеристики iPhone падает ниже 100 - 200 Гц (см. Пример: http://blog.faberacoustical.com/2009/ios/iphone/iphone-microphone-frequency-response-comparison/).
Если вы пытаетесь обнаружить основной режим низкой гитарной струны, микрофон может выступать в качестве фильтра и подавлять интересующую вас частоту. Есть несколько вариантов, если вы заинтересованы в использовании данных fft, которые вы можете получить - Вы можете поместить данные в частотной области вокруг заметки, которую вы пытаетесь обнаружить, так что все, что вы можете видеть, это первый режим, даже если он имеет меньшую величину, чем более высокие режимы (т.е. имеет переключатель для настройки первой строки и размещения ее в этом режиме).
Или вы можете фильтровать низкие частоты звуковых данных - вы можете сделать это либо во временной области, либо даже проще, поскольку у вас уже есть данные в частотной области, в частотной области. Очень простой фильтр низких частот во временной области состоит в создании фильтра скользящих средних во времени. Очень простой фильтр нижних частот в частотной области - это умножение значений БПФ на вектор с единицами в низкочастотном диапазоне и линейным (или даже ступенчатым) понижением на более высоких частотах.
Какова ваша частота дискретизации и размер блока? Низкий E составляет около 80 Гц, поэтому вам нужно убедиться, что ваш блок захвата достаточно длинный, чтобы захватывать много циклов на этой частоте. Это связано с тем, что преобразование Фурье делит частотный спектр на элементы шириной несколько Гц. Например, если вы производите выборку на частоте 44,1 кГц и имеете выборку во временной области 1024 точки, каждая ячейка будет иметь ширину 44100/1024 = 43,07 Гц. Таким образом, низкий E будет во втором бункере. По множеству причин (связанных со спектральной утечкой и природой конечных временных блоков), практически говоря, вы должны рассматривать первые 3 или 4 бина данных в результате БПФ с крайним подозрением.
Если вы уменьшите частоту дискретизации до 8 кГц, тот же самый размер блока даст вам интервалы шириной 7,8125 Гц. Теперь низкий Е будет в 10-м или 11-м бине, что намного лучше. Вы также можете использовать более длинный размер блока.
И, как указывает Пол Р., вы ДОЛЖНЫ использовать окно для уменьшения спектральной утечки.