Как определить тон строки из FFT

Я получил спектр от преобразования Фурье. Это выглядит так:звуковая спектрограмма, созданная проходящей полицией
Полиция просто проходила рядом

Цвет представляет интенсивность.
Ось X - это время.
Ось Y - это частота - где 0 сверху.

В то время как свист или полицейская сирена оставляют только один след, многие другие тона, похоже, содержат много гармонических частот.

звуковая спектрограмма настроенной гитары EHGDAEЭлектрогитара подключена прямо к микрофону (стандартная настройка)

Очень плохо то, что, как вы можете видеть, нет большой интенсивности - есть 2-3 частоты, которые почти равны.
Я написал алгоритм обнаружения пиков, чтобы выделить самый значительный пик:

    function findPeaks(data, look_range, minimal_val) {
      if(look_range==null)
        look_range = 10;
      if(minimal_val == null)
        minimal_val = 20;
      //Array of peaks            
      var peaks = [];
      //Currently the max value (that might or might not end up in peaks array)
      var max_value = 0;
      var max_value_pos = 0;
      //How many values did we check without changing the max value
      var smaller_values = 0;
      //Tmp variable for performance
      var val;
      var lastval=Math.round(data.averageValues(0,4));
      //console.log(lastval);
      for(var i=0, l=data.length; i<l; i++) {
        //Remember the value for performance and readibility
        val = data[i];

        //If last max value is larger then the current one, proceed and remember
        if(max_value>val) {
          //iterate the ammount of values that are smaller than our champion
          smaller_values++;
          //If there has been enough smaller values we take this one for confirmed peak
          if(smaller_values > look_range) {
            //Remember peak
            peaks.push(max_value_pos);
            //Reset other variables
            max_value = 0;
            max_value_pos = 0;
            smaller_values = 0;
          }
        }
        //Only take values when the difference is positive (next value is larger)
        //Also aonly take values that are larger than minimum thresold
        else if(val>lastval && val>minimal_val) {
          //Remeber this as our new champion
          max_value = val;
          max_value_pos = i;
          smaller_values = 0;
          //console.log("Max value: ", max_value);
        }           
        //Remember this value for next iteration
        lastval = val;
      }
      //Sort peaks so that the largest one is first
      peaks.sort(function(a, b) {return -data[a]+data[b];});
      //if(peaks.length>0)
      //  console.log(peaks);
      //Return array
      return peaks;
    }

Идея состоит в том, чтобы пройтись по данным и запомнить значение, превышающее пороговое значение minimal_val, Если следующий look_range значения меньше, чем выбранное значение, оно считается пиковым. Этот алгоритм не очень умный, но его очень легко реализовать.

Тем не менее, он не может сказать, какая основная частота строки, как я и ожидал:

Гитарные струны теперь с выделенной самой сильной частотой
Красные точки выделяют самый сильный пик

Вот jsFiddle, чтобы увидеть, как это действительно работает (или, скорее, не работает).

1 ответ

То, что вы видите в спектре струнного тона, - это набор гармоник в

f0, 2*f0, 3*f0, ...

с f0 является основной частотой или высотой тона вашей струны.

Для оценки f0 по спектру (выход FFT, значение abs, вероятно, логарифмический) вы должны искать не самый сильный компонент, а расстояние между всеми этими гармониками.

Один очень хороший способ сделать это - второе (обратное) БПФ (абс, реальное) спектра. Это дает сильную линию при t0 == 1/f0.

Последовательность fft -> abs() -> fft-1 эквивалентна вычислению функции автокорреляции (ACF) благодаря теореме Винера – Хинчина.

Точность такого подхода зависит от длины FFT (или ACF) и вашей частоты дискретизации. Вы можете значительно улучшить точность, если интерполируете "реальный" максимум между точками выборки результата, используя функцию sinc.

Для еще лучших результатов вы можете исправить промежуточный спектр: большинство звуков имеют средний розовый спектр. Если вы усиливаете более высокие частоты (в соответствии с обратным розовым спектром) перед обратным БПФ, АКФ будет "лучше" (в большей степени учитывается высшая гармоника, что повышает точность).

Другие вопросы по тегам