计算相位传播的问题(在 C 中)

信息处理 fft 声音的 阶段 C
2022-02-03 16:42:30

我正在用 C 语言编写相位声码器,用于时间拉伸音频信号。当前唯一不起作用的是相位传播。

  1. 我从输入信号中获取重叠帧,应用窗口函数并执行 FFT。
  2. 然后我计算相位传播(我坚持的那个)
  3. 最后,我执行 iFFT 并重叠添加具有不同跳数大小的输出帧。

如果我跳过第 2 步,即相位传播,则输出声音会正确地进行时间拉伸,但我可以听到移相器效果。我的假设是缺失的部分将纠正这一点。但是,当我应用当前的实现时,声音会严重失真。

如果有人可以就如何实现相位校正提供一些好的指导,我将不胜感激。

问的可能太多了,但如果你看到一些奇怪的东西,这是我目前的实现。

// _prevPhaseX[] = FFT phases from previous frame (n-1) (propagation input)
// _prevPhaseY[] = FFT phases from previous frame (n-1) (propagation output)
// _phase[] has the FFT phase information from current frame
static int first = 1;
if (first)
{
    first = 0;
    for (int k=0; k<half; k++)          // half = window length/2 = number of bins
    {
        _prevPhaseX[k] = _phase[k];
        _prevPhaseY[k] = _phase[k];
    }
}
else
{
    // int length = window length - e.g. 1024 
    // float Ra = analysis hop size - e.g. 256
    // float Rs = synthesis hop size - e.g. 512
    // float PI = PI
    // float DPI = 2*PI
    for (int k=1; k<half; k++)
    {
        // compute Delta Phi(k)
        float phase = _phase[k];
        float omega = DPI*(float)k/(float)length;  // length vs length/2?
        float phasediff = phase - _prevPhaseX[k] - Ra*omega;
        _prevPhaseX[k] = phase;   // Save value for next frame

        // get principal argument
        while (phasediff>PI) phasediff -=DPI;
        while (phasediff<-PI) phasediff +=DPI;

        float freq = omega + (phasediff)/Ra;
        _phase[k] = _prevPhaseY[k] + Rs*freq;
        _prevPhaseY[k] = _phase[k];   // Save value for next frame
    }
} 
// the _phase[] vector (and magnitude[]) goes to IFFT (after conv. to rectangluar)

谢谢!

2个回答

您不想逐个执行此操作。 这是 Miller Puckette 的一篇论文,对这个问题具有开创性意义。你想要做的是识别特定的频率分量(也许频谱中的每个波瓣都是一个特定的频率分量)并将整个nth lobbyejϕn 在哪里ϕn=ωn Tnωn是频率n组件和Tn是对该分量的时间调整,以使其相位与前一帧中的相应分量相匹配。

每个 bin 乘以ejϕn,但对于大多数 bin,该因子与相邻 bin 的因子相同。

我认为您的代码的一个问题是_phase[k]是当前输入帧的相位,而_prevPhase[k]指前一个输出帧。但是,我认为您应该通过比较当前输入帧和之前的输入帧,而不是当前输入帧和之前的输出帧来计算相位差。因此,您需要两个用于过去阶段的变量,一个用于输入阶段,一个用于输出阶段。

还有一件事:你应该增加你的 FFT 大小。为了Rs=512您的 FFT 大小可能至少应为2048.

如果您将链接发布到输入信号的一小段以及两个相应的输出信号(一个有相位修改,一个没有相位修改),也会很有帮助。然后可能更容易判断问题是什么。