我正在尝试检测用吉他演奏的 B3 音符的音高。音频可以在这里找到。
如您所见,基本音高约为 250Hz,对应于 B3 音符。
它还包含大量谐波,这就是我选择从这里使用 HPS 的原因。我正在使用此代码来检测音高:
def freq_from_hps(signal, fs):
"""Estimate frequency using harmonic product spectrum
Low frequency noise piles up and overwhelms the desired peaks
"""
N = len(signal)
signal -= mean(signal) # Remove DC offset
# Compute Fourier transform of windowed signal
windowed = signal * kaiser(N, 100)
# Get spectrum
X = log(abs(rfft(windowed)))
# Downsample sum logs of spectra instead of multiplying
hps = copy(X)
for h in arange(2, 9): # TODO: choose a smarter upper limit
dec = decimate(X, h)
hps[:len(dec)] += dec
# Find the peak and interpolate to get a more accurate peak
i_peak = argmax(hps[:len(dec)])
i_interp = parabolic(hps, i_peak)[0]
# Convert to equivalent frequency
return fs * i_interp / N # Hz
我的采样率为 40000。但是,我得到的结果不是接近 250Hz(B3 注意),而是 0.66Hz。这怎么可能?
我还尝试了来自同一个 repo 的自相关方法,但我也得到了不好的结果,比如 10000Hz。
感谢一个答案,我知道我必须应用一个滤波器来去除信号中的低频。我怎么做?是否有多种方法可以做到这一点,推荐哪一种?
状态更新:
答案提出的高通滤波器正在工作。如果我在我的音频信号的答案中应用该函数,它会正确显示大约 245Hz。但是,我想过滤整个信号,而不仅仅是它的一部分。一个音符可能位于信号的中间,或者一个信号包含多个音符(我知道一个解决方案是开始检测,但我很想知道为什么这不起作用)。这就是我编辑代码以返回的原因filtered_audio
。
问题是,如果我这样做,即使噪音已被正确消除(见截图)。结果我得到 0.05。