我试图从声源中提取基本频率。也许有人在向麦克风唱歌A3,所以我想检测〜110Hz
我的方法是:
(Peak [0] .power = 1063.343750,.freq = 2032.715088 (Peak [1] .power = 1047.764893,.freq = 3070.605225 (Peak [2] .power = 1014.986877,.freq = 5925.878418 (Peak [3] .power = 1011.707825,.freq = 6963.769043 (Peak [4] .power = 1009.152954,.freq = 4022.363037 (Peak [5] .power = 995.199585,.freq = 4974.120605 (Peak [6] .power = 987.243713,.freq = 8087.792480 (Peak [7] .power = 533.514832,.freq = 908.691833
谐波峰值对:(0,1)= 2/3,错误:0.00468 => f0 @ 1019.946289 谐波峰值对:(0,2)= 1/3,错误:0.00969 => f0 @ 2004.003906 谐波峰值对:(0,3) = 2/7,错误:0.00618 => f0 @ 1005.590820 谐波峰值对:(0,4)= 1/2,错误:0.00535 => f0 @ 2021.948242 谐波峰值对:(0,5)= 2/5,错误:0.00866 => f0 @ 1005.590820 谐波峰值对:(0,6)= 1/4,错误:0.00133 => f0 @ 2027.331543 谐波峰值对:(0,7)= 9/4,错误:0.01303 => f0 @ 226.515106
我的问题是:如何设计一种算法,可以将上述基本信号正确地识别为〜1000Hz?
绝对不能保证〜1000处的值会比〜2000或〜3000等处的值更高。甚至不能保证会有〜1000项。我们可能有〜5000 x一个条目,〜4000 x三个条目,〜3000 x 2条目以及几个假值浮动,就像上面列表中的226一样。
我想我可以再次重复该过程,以清除建议的基本原理,这些基本原理与列表的其余部分不“协调”。这至少可以摆脱虚假的价值…
可能是我什至没有问正确的问题。也许这整个方法糟透了。但是我认为选择最强的峰并提取与该峰相关的一组谐波是有意义的。
理论上应该产生一定比例的负载,比如说如果最强的原始峰是三次谐波,那么这组峰应该包含3/1 3/2 3/3 3/4 3/5 3/6 3/7等…尽管可能会丢失一些。
实际上,我感觉它总是会成为强度最大的基波或一次谐波。但我不知道我是否可以依靠…
这么多的因素,这使我无法自拔。对于这样一个麻烦的问题,我事先表示歉意。希望我可以死后整理一下。
我找到了一个相当简单的解决方案,它的计算能力很低。
它涉及给每个间隙一个接近度分数。
要计算间隙i的接近度得分,我只需对所有j!= i求和1 / {dist(gap_i,gap_j)+1}
我设置+1以避免被零除。这样,如果两个值几乎相等,则它们将获得1分,并且随着差距的增加,该得分将变为0
但是,如果间隙j几乎恰好是间隙i的两倍,则也应将其视为非常接近。所以我首先获得最接近gap_j / gap_i的整数(可能需要交换以使gap_j更大),然后将gap_j除以该整数,然后考虑dist(gap_i,fiddled_gap_j)
如果例如gap_j〜= 2 * gap_i,那么我要小心提高Gap_i的得分,而不是gap_j
这样可以很好地获得合理准确的候选人。再经过两次处理应该可以很容易地改进该值。我想的第一件事是根据成功的候选人对价值进行平均。然后大概一秒钟创建一个泛函(f)函数,并使用从先前计算的点开始的某种Newton-Raphson过程来隔离局部最大值。
无论如何,下面是代码:
float ascertain_f0(PEAK * peaks, POTENTIAL_HARMONIC * pH, int phCount) { int gaps = phCount; // enumerate GAPS GAP gap [ MAX_POTENTIAL_HARMONICS ]; gap[0].len = peaks[pH[0].peakQ].freq; for (int i=1; i < gaps; i++) { int a = pH[i-1].peakQ, b = pH[i].peakQ; gap[i].len = peaks[b].freq - peaks[a].freq; } for (int i=0; i < gaps; i++) gap[i].score = 0.; // find best scoring gap for (int i=0; i < gaps; i++) for (int j=0; j < gaps; j++) { if (i == j) continue; float a = gap[i].len; float B_ = gap[j].len; if (a > B_) continue; // a < B_ int multiplier = closestInt(B_ / a); float b = B_ / multiplier; float dist = fabs(b - a); float sc = 1. / (dist + 1.); gap[i].score += sc; if (multiplier == 1) gap[j].score += sc; } int best = 0; for (int i=1; i < gaps; i++) if (gap[i].score > gap[best].score) best = i; return gap[best].len; }