【发布时间】:2017-01-06 22:07:22
【问题描述】:
我正在尝试从麦克风输入中获取音高。首先,我通过 FFT 将信号从时域分解到频域。在执行 FFT 之前,我已将汉明窗应用于信号。然后我得到了 FFT 的复杂结果。然后我将结果传递给谐波乘积频谱,在其中对结果进行下采样,然后将下采样的峰值相乘,并给出一个复数值。那我应该怎么做才能得到基频呢?
public float[] HarmonicProductSpectrum(Complex[] data)
{
Complex[] hps2 = Downsample(data, 2);
Complex[] hps3 = Downsample(data, 3);
Complex[] hps4 = Downsample(data, 4);
Complex[] hps5 = Downsample(data, 5);
float[] array = new float[hps5.Length];
for (int i = 0; i < array.Length; i++)
{
checked
{
array[i] = data[i].X * hps2[i].X * hps3[i].X * hps4[i].X * hps5[i].X;
}
}
return array;
}
public Complex[] Downsample(Complex[] data, int n)
{
Complex[] array = new Complex[Convert.ToInt32(Math.Ceiling(data.Length * 1.0 / n))];
for (int i = 0; i < array.Length; i++)
{
array[i].X = data[i * n].X;
}
return array;
}
我已经尝试使用,
magnitude[i] = (float)Math.Sqrt(array[i] * array[i] + (data[i].Y * data[i].Y));
在 HarmonicProductSpectrum 方法的 for 循环中。然后尝试使用最大的 bin,
float max_mag = float.MinValue;
float max_index = -1;
for (int i = 0; i < array.Length / 2; i++)
if (magnitude[i] > max_mag)
{
max_mag = magnitude[i];
max_index = i;
}
然后我尝试使用频率来获取频率,
var frequency = max_index * 44100 / 1024;
但是对于 A4 音符(440 Hz),我得到了像 1248.926、1205,859、2454.785 这样的垃圾值,而这些值看起来不像 A4 的谐波。
非常感谢您的帮助。
【问题讨论】:
-
你能把你正在使用的音频文件放到网上吗?我想看看这个,用 Python 等高级语言复制你的算法,因为你很可能有算法问题,但我想确保我使用的是相同的“A4 笔记”和你一样(我对音乐一无所知????)。
-
在 windows 设置中仔细检查麦克风的采样率,它可能是
48,000而不是你在最后一行的44,100,这会将你的 1249 数字变成 1360,即只有 8% 的谐波而不是 17%..耸耸肩,看起来不对,但需要检查。 -
@AhmedFasih A4 note 谢谢艾哈迈德 :)
-
@Quantic 是的,它是 44100。我知道 FFT 是正确的,因为一旦我使用幅度获得最大 bin 的频率,它会为 440Hz 的 A4 音符提供 437.5Hz 和 445.312Hz。我想执行 HPS 以获得更好的频率分辨率
-
引用:“八度音阶错误很常见(检测有时八度音阶太高)。要更正,请应用此规则:如果低于最初选择的音高的第二个峰值幅度大约是所选音高的 1/2并且幅度比高于阈值(例如,5 个谐波为 0.2),然后选择较低的八度音阶峰值作为当前帧的音高”。
标签: c# signal-processing fft audio-processing pitch