从潜在谐波中确定基频的算法
我试图从声源中提取基本频率。也许有人在向麦克风唱歌A3,所以我想检测〜110Hz
我的方法是:
- FFT 1024浮点数
- 使用每个档位的相位来准确确定其精确频率
- 确定峰(通常为50个左右)
- 最先订购它们
(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
- (MARKER1)从最大声开始,然后将其与所有其余峰匹配,因此,如果我有N个峰,则此时我将拥有N-1个峰对
- 检查每个峰对的谐波;即,它与某个分数a / b有多接近,即我们可以找到b <20的a / b使得| peakA.freq / peakB.freq-a / b | <0.01(这将匹配高达20的谐波)
- 现在,我们有了一个完善的峰列表,这些峰被认为是相互谐波的
谐波峰值对:(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;
}
以上是 从潜在谐波中确定基频的算法 的全部内容, 来源链接: utcz.com/qa/412940.html