2013-07-13 2 views
1

Я пытаюсь создать простую приложение для определения высоты тона для телефона Android. Я получил телефон, чтобы отобразить график значений автокорреляции, которые я вычислил, которые хранятся в одномерном массиве удвоений. Теперь мне нужно выяснить, как обнаружить повторяющиеся шаблоны в массиве. Вот скриншот автокорреляционного графа со мной напевая устойчивый шаг:Обнаружение общего шаблона локальных максимумов в массиве 1D Java

screenshot of my autocorrelation graph when humming a steady pitch

Я попытался реализациями рекурсивного пикового ознакомительного алгоритма 1D массивов данных в этом слайде палубе: http://courses.csail.mit.edu/6.006/spring11/lectures/lec02.pdf, но я вышел из памяти ошибок на Android.

Далее я попытался реализовать что-то вроде этого алгоритма для поиска второй производной: https://stackoverflow.com/a/3869172, но значения автокорреляции, поступающие с телефона, настолько нервничают, что он находит слишком много минимумов и максимумов.

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

В принципе, мне нужна помощь в выяснении того, как я могу найти общие максимумы (на самом деле только первый, вероятно, будет в порядке) повторяющегося шаблона. На скриншоте выше шаблон представляет собой высокий пик, за которым следуют два более коротких пика. Мне нужно знать, когда произойдет второй высокий пик, чтобы я мог рассчитать высоту.

+0

Средние или медные фильтры могут сгладить ваш сигнал. определите длину окна, которая соответствует вашим потребностям. – dervish

ответ

0

Чтобы ответить на мой собственный вопрос, вот что я в итоге сделал. (Извините, мне потребовалось столько времени, чтобы вернуться к этому вопросу, чтобы опубликовать ответ.)

double frequency = findFrequency(lowPassFilter(signal)); 

private double findFrequency(double[] signal) { 
    int[] signs = new int[signal.length]; 
    for (int i = 0; i < signal.length - 1; i++) { 
     double diff = signal[i+1] - signal[i]; 
     if (diff < 0) { 
      signs[i] = -1; 
     } else if (diff == 0) { 
      signs[i] = 0; 
     } else { 
      signs[i] = 1; 
     } 
    } 
    int[] secondDerivatives = new int[signs.length]; 
    for (int i = 0; i < signs.length - 1; i++) { 
     secondDerivatives[i] = signs[i+1] - signs[i]; 
    } 
    double biggestSoFar = 0.0; 
    int indexOfBiggestSoFar = 0; 
    for (int i = 0; i < secondDerivatives.length; i++) { 
     if (secondDerivatives[i] == -2 && signal[i] > biggestSoFar) { 
      biggestSoFar = signal[i]; 
      indexOfBiggestSoFar = i; 
     } 
    } 
    return 1/(double)indexOfBiggestSoFar * AudioListener.SAMPLE_RATE; 
} 

private double[] lowPassFilter(double[] signal) { 
    double alpha = 0.15; 
    for (int i = 1; i < signal.length; i++) { 
     signal[i] = signal[i] + alpha * (signal[i] - signal[i-1]); 
    } 
    return signal; 
} 
0

Вы пытаетесь оценить частоту пиков амплитуды в данных выборки. Вы можете сделать это без необходимости вручную оценивать пики и затем настраивать частоту. Вместо этого вы можете использовать быстрое преобразование Фурье, это преобразуется из графика амплитуды во времени в график частоты во времени. Существует хорошее описание концепции в целом здесь http://en.wikipedia.org/wiki/Fast_Fourier_transform

... и есть несколько библиотек Java, которые реализуют преобразование включая Apache Commons Math - http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/transform/FastFourierTransformer.html и JTransform - https://sites.google.com/site/piotrwendykier/software/jtransforms

Смежные вопросы