TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

ゼロパティングを使用して自己相関関数でのピッチ推定の精度を向上する

前回の日記で自己相関関数によるピッチ推定の精度をN倍の位置のピークを使用することで向上できることを示した。

Nを大きくすることで精度を高めることができるが、Nの上限はフレーム長により制限される。

単純にフレーム長を長くした場合、応答性とのトレードオフとなる。

応答性を変えずにフレーム長を大きくする手法としてゼロパティングがある。(以前の日記参照)

ここでは、ゼロパティングを使用してフレーム長を大きくした場合のピッチ推定の誤差について検証する。

フレーム長を2倍にしてゼロパティングを行い、周波数の範囲を100Hzから900Hzとして、N倍位置のピークから推定したピッチの誤差をcent単位で求める。

size = 8192
t = np.arange(0, size) / fs
han = np.hanning(size)

errors = []
fset = np.linspace(100, 900, 8001)
for f in fset:
    y = np.sin(2 * np.pi * f * t)
    y[size/2:]=0 # ゼロパディング
    Y = np.fft.fft(y*han)
    acf = np.fft.ifft(abs(Y)**2)
    n = pick_peak(np.real(acf[0:size/2]))
    n1 = n
    for N in range(2, int(size / 2 / n1) - 1):
        nn = int(n*N)-10 + pick_peak(np.real(acf[int(n*N)-10:int(n*N)+10]))
        n = nn / N
    f0 = fs / n
    cent = (math.log(f0, 2) - math.log(f, 2)) * 12 * 100
    errors.append(cent)
plt.plot(fset, errors)
plt.show()

f:id:TadaoYamaoka:20170114120638p:plain

比較のために、前回の日記で検証したゼロパディングを行わない場合の誤差のグラフは以下の通りとなる。

f:id:TadaoYamaoka:20170114104521p:plain

100Hzあたりの低い周波数では、誤差のばらつきが大きくなっているが、高い周波数では、ゼロパティングを行った方が誤差が抑えられている。

1cent程度の誤差が求められる音楽のチューニング用途では不十分であるが、ゼロパティングを使用することである程度ピッチ推定の精度を高めることができる。