基于 ACF 结果求基频的算法

信息处理 频率 算法 自相关 沥青 峰值检测
2022-02-01 16:52:11

我正在开发一种用于基频跟踪的软件。为此,我设计了一个计算信号自相关的函数和第二个函数,该函数根据自相关结果找到对应于基频的峰值。

但是我写的代码不是很可靠。我想知道的是:哪些算法对于基频峰值搜索是可靠的?

编辑

到目前为止,在 MATLAB 中完成时,我的自相关图如下所示: 全记录 ACF 图

不过我是用C实现的,因为我的软件是用C的,如下:

 91     for(;i < *length;i++) {
 92         for(j = i;j < *length + i;j++) {
 93             if(j > i) {
 94                 sum += 0;
 95             } else {
 96                 sum += samples[i] * samples[j];
 97             }
 98         }
 99 
100         result[i] = sum;
101         sum = 0.0f;
102     }

i0. _ 我也相信这段代码没问题。

在 MATLAB 中近似上面的图,我看到了,其中标记的峰值将是我的基频(我正在测试的音符是 E2)

窗口 ACF 图

正如我们从这个情节中看到的

标记的第二个峰值

我正在处理的信号是准周期性的,这些峰值之间的差异实际上导致了 E2 的基频 注意:两者之间的距离是 389 - 193 == 196(从 MATLAB 绘图的拖放获得的值),其中,除以我的 16 kHz 采样率,得到 0.01225,这将是我的波形周期。反转这个值,我得到 81.6326530612 Hz,这非常接近我对 E2 的预期 82.41 Hz。

但是,我很难在代码中找到这两个峰值,因为我不确定要比较什么来确定我发现的峰值实际上是这两个峰值。

2个回答

我假设您的信号是音频和谐波,并且您没有在同时播放多个音调的情况下进行多次 F0 估计。在这种情况下,有一些更简单的方法。短时自相关函数的归一化。r(lag) = (1/N)*sum(x(n)*x(n+lag) N 是 x(n) 的长度 F0 是从对应于最大 r(滞后)在预定义的范围内(例如,您的范围可能是从 20 到 250,因此在滞后 196 处,您有一个最大值,再次使用这个范围)。为了避免检测到周期的整数倍,短滞后优于长的。这是一个 C 函数,可能值得一玩。

void autocorr(  
    float *r,       /* (output) autocorrelation vector */ 
    const float *x, /* (input) data vector */ 
    int N,          /* length of data vector */ 
    int order       /* largest lag for calculated  
                      autocorrelations */ 
)
{ 
    int     lag, n;
    float   sum; 

    for (lag = 0; lag <= order; lag++) { 
        sum = 0; 
        for (n = 0; n < N - lag; n++) { 
            sum += x[n] * x[n+lag]; 
        } 
        r[lag] = sum/N; 
    } 
} 

检测峰值的另一种方法是中心削波。在你的 autocorr 函数之后,你可以编写如下代码:

y(n) = a(n) - C,如果 a(n) >= C

y(n) = a(n) + C,如果 a(n) <= -C

y(n) = 0 否则。

C 是自校正向量的最大幅度的某个百分比。

我在上面向您展示的只是非常基本的东西,因为 F0 分析可能非常复杂(可能是人们没有回答的原因)。您可以在语音编解码器书籍或音乐转录书籍中找到更多信息。

如果您进行频谱时间自相关,您可能会获得更好的结果。这涉及将信号分成多个频带并在每个频带上执行 ACF。对所有波段的自相关求和可以提供更清晰的峰值,从而提供更可靠的估计。f0

有关更多信息,请参阅 Licklider 的“音高感知的双重理论”。