预强调缩放?

信息处理 lpc 预处理
2022-02-01 05:50:23

我正在使用 LPC 进行语音合成,我最初实现了一个预加重滤波器:

+(void)processBuffer:(Buffer *)buffer {
    float alpha = -0.9375f;
    for (int i = 1; i < buffer.size; i++) {
        buffer.samples[i] += buffer.samples[i - 1] * alpha;
    }
}

发现我的输出音频失真了,所以我添加了一些代码来缩放值,所以现在看起来像这样:

+(void)processBuffer:(Buffer *)buffer {
    float preEnergy = [self energyFor:buffer];

    float alpha = -0.9375f;
    for (int i = 1; i < buffer.size; i++) {
        buffer.samples[i] += buffer.samples[i - 1] * alpha;
    }

    [self scaleBuffer:buffer preEnergy:preEnergy postEnergy:[self energyFor:buffer]];
}

+(void)scaleBuffer:(Buffer *)buffer preEnergy:(double)preEnergy postEnergy:(double)postEnergy {
    float scale = sqrt(preEnergy / postEnergy);

    for (int i = 0; i < buffer.size; i++) {
        buffer.samples[i] *= scale;
    }
}

+(float)energyFor:(Buffer *)buffer {
    double sum = 0.0;

    for (int i = 0; i < buffer.size; i++) {
        sum += buffer.samples[i] * buffer.samples[i];
    }
    return sum; 
}

我发现我正在生成的语音听起来仍然不是很好,所以我只是想知道我对这个过滤器的实现是否可以?有没有人看到我做错了什么或者这看起来不错?

2个回答

最明显的问题是它buffer.samples[0]永远不会被过滤,因为for循环从 1 变为 size-1。这是在处理数据缓冲区而不是无限流的软件中​​实现 FIR 滤波器的固有问题。在更一般的情况下,您的过滤器具有 N 个状态,您需要存储 N-1 个状态,以便它们可以在过滤器的下一次调用中使用。由于您的过滤器只有两个抽头,并且实现比一般解决方案要简单得多。

// state is a member variable of the class initialized to zero.
float alpha = -0.9375f;
buffer.samples[0] += state * alpha;
for (int i = 1; i < buffer.size; i++) {
    buffer.samples[i] += buffer.samples[i - 1] * alpha;
}
state = buffer.samples[buffer.size-1]; // store for the next time.

缩放

您的滤波器在通带中具有接近 2 倍的增益,这可能会导致您出现问题。我怀疑样本需要保持在 -1 到 1 的范围内。想象样本是 [...,1,-1,1,-1,...] 的流(这恰好是正弦波采样率/2)。您的过滤器输出将是 [...,-1+1*-0.98,1+-1*-0.98,...] 大约是 [...,-2,2,-2,2, ...]

通过该缓冲区的滤波器增益缩放每个连续缓冲区的策略是一个好主意,但它具有每次调用它时产生不同缩放因子的不幸属性。这可能会在每个缓冲区之间引入瞬态。

最好在设计时分析滤波器并选择一个常数来进行缩放。

在你的情况下,这将是 1/2。

// state is a member variable of the class initialized to zero.
float alpha = -0.9375f;
buffer.samples[0] += state * alpha;
buffer.samples[0] *= 0.5;
for (int i = 1; i < buffer.size; i++) {
    buffer.samples[i] += buffer.samples[i - 1] * alpha;
    buffer.samples[i] *= 0.5;
}
state = buffer.samples[buffer.size-1]; // store for the next time.

当然,如果您想要增益,请忽略这部分。

原来我遇到的问题与我实现了 IIR 滤波器而不是 FIR 的事实有关。

double unmodifiedPreviousSample = buffer.samples[0];
double tempSample;
for (int i = 1; i < buffer.size; i++) {
    tempSample = buffer.samples[i];
    buffer.samples[i] += (alpha * unmodifiedPreviousSample);
    unmodifiedPreviousSample = tempSample;
}

一旦我做了这个改变,信号中的所有低频都被删除了,听起来很棒。