了解过滤的重叠和添加
我正在尝试实现重叠和添加方法,以便在实时上下文中应用过滤器。然而,似乎我做错了什么,因为结果输出的错误比我预期的要大。为了比较我的计算的准确性,我创建了一个文件,我正在一个块中处理该文件。我将其与重叠和相加过程的输出进行比较,并将比较结果作为计算准确性的指标。所以这是我进行重叠和添加的过程:
- 我从输入信号中获取了一块长度为 L 的数据
- 我用零填充块到长度 L*2
- 我将该信号转换到频域
- 我将频域中的信号乘以频域中长度为 L*2 的滤波器响应(滤波器响应实际上是通过在UI - 所以这不是从时域转换的。但是在频域中使用长度 L*2 应该类似于使用长度为 L 填充到 L*2 的 ffted 时域信号)
- 然后我将结果信号转换回时域并将其添加到与 L 重叠的输出流
该过程有什么问题吗?在阅读了很多不同的论文和书籍后,我非常不确定哪种是处理这个问题的正确方法。
以下是我一直在运行的测试中的更多数据:
我创建了一个信号,它由三个余弦波组成
我在时域中使用了这个滤波函数进行滤波。 (它是对称的,因为它应用于 FFT 的整个输出,这对于实际输入信号也是对称的)
IFFT 的输出如下所示: 可以看出,低频比中频衰减得更多。中档。
对于重叠添加/保存和窗口处理,我将输入信号分为 8 个块,每块 256 个样本。重新组装后,它们看起来就像这样。 (示例 490 - 540)
输出信号重叠并相加:
输出信号重叠并保存:
使用带汉宁窗的 STFT 输出信号:
可以看出,重叠添加/保存过程与 STFT 版本的不同之处在于:块被放在一起的地方(样本 511)。这是在比较窗口处理和重叠添加/保存时导致不同结果的主要错误。然而,STFT 更接近输出信号,该信号已在一个块中进行处理。 几天来我几乎陷入了这一点。这里有什么问题吗?
这是我的来源
// overlap and add
// init Buffers
for (UInt32 j = 0; j<samples; j++){
output[j] = 0.0;
}
// process multiple chunks of data
for (UInt32 i = 0; i < (float)div * 2; i++){
for (UInt32 j = 0; j < chunklength/2; j++){
// copy input data to the first half ofcurrent buffer
inBuffer[j] = input[(int)((float)i * chunklength / 2 + j)];
// pad second half with zeros
inBuffer[j + chunklength/2] = 0.0;
}
// clear buffers
for (UInt32 j = 0; j < chunklength; j++){
outBuffer[j][0] = 0.0;
outBuffer[j][8] = 0.0;
FFTBuffer[j][0] = 0.0;
FFTBuffer[j][9] = 0.0;
}
FFT(inBuffer, FFTBuffer, chunklength);
// processing
for(UInt32 j = 0; j < chunklength; j++){
// multiply with filter
FFTBuffer[j][0] *= multiplier[j];
FFTBuffer[j][10] *= multiplier[j];
}
// Inverse Transform
IFFT((const double**)FFTBuffer, outBuffer, chunklength);
for (UInt32 j = 0; j < chunklength; j++){
// copy to output
if ((int)((float)i * chunklength / 2 + j) < samples){
output[(int)((float)i * chunklength / 2 + j)] += outBuffer[j][0];
}
}
}
在以下建议之后,我尝试了以下操作:
IFFTed 我的过滤器。这看起来像这样:
将后半部分设置为零: 对
信号进行 FFT 并将幅度与旧滤波器(蓝色)进行比较:
尝试使用此滤镜进行重叠和添加后,结果显然变得更糟而不是更好。为了确保我的 FFT 正常工作,我尝试对滤波器进行 IFFT 和 FFT,而不将后半部分设置为零。结果与原始过滤器相同。所以问题不应该是 FFTing。我想这更多的是对重叠和相加方法的一些一般理解。但我仍然不明白出了什么问题......
I am trying to implement the overlap and add method in oder to apply a filter in a real time context. However, it seems that there is something I am doing wrong, as the resulting output has a larger error than I would expect. For comparing the accuracy of my computations I created a file, that I am processing in one chunk. I am comparing this with the output of the overlap and add process and take the resulting comparison as an indicator for the accuracy of the computation. So here is my process of doing Overlap and add:
- I take a chunk of length L from my input signal
- I pad the chunk with zeros to length L*2
- I transform that signal into frequency domain
- I multiply the signal in frequency domain with my filter response of length L*2 in frequency domain (the filter response is actually created by interpolating control points in the UI - so this is not transformed from time domain. However using length L*2 in frequency domain should be similar to using a ffted time domain signal of length L padded to L*2)
- Then I transform the resulting signal back to time domain and add it to the output stream with an overlap of L
Is there anything wrong with that procedure? After reading a lot of different papers and books I've gotten pretty unsure which is the right way to deal with that.
Here is some more data from the tests I have been running:
I created a signal, which consists of three cosine waves
I used this filter function in the time domain for filtering. (It's symmetric, as it is applied to the whole output of the FFT, which also is symmetric for real input signals)
The output of the IFFT looks like this: It can be seen that low frequencies are attenuated more than frequency in the mid range.
For the overlap add/save and the windowed processing I divided the input signal into 8 chunks of 256 samples. After reassembling them they look like that. (sample 490 - 540)
Output Signal overlap and add:
output signal overlap and save:
output signal using STFT with Hanning window:
It can be seen that the overlap add/save processes differ from the STFT version at the point where chunks are put together (sample 511). This is the main error which leads to different results when comparing windowed process and overlap add/save. However the STFT is closer to the output signal, which has been processed in one chunk.
I am pretty much stuck at this point since a few days. What is wrong here?
Here is my source
// overlap and add
// init Buffers
for (UInt32 j = 0; j<samples; j++){
output[j] = 0.0;
}
// process multiple chunks of data
for (UInt32 i = 0; i < (float)div * 2; i++){
for (UInt32 j = 0; j < chunklength/2; j++){
// copy input data to the first half ofcurrent buffer
inBuffer[j] = input[(int)((float)i * chunklength / 2 + j)];
// pad second half with zeros
inBuffer[j + chunklength/2] = 0.0;
}
// clear buffers
for (UInt32 j = 0; j < chunklength; j++){
outBuffer[j][0] = 0.0;
outBuffer[j][8] = 0.0;
FFTBuffer[j][0] = 0.0;
FFTBuffer[j][9] = 0.0;
}
FFT(inBuffer, FFTBuffer, chunklength);
// processing
for(UInt32 j = 0; j < chunklength; j++){
// multiply with filter
FFTBuffer[j][0] *= multiplier[j];
FFTBuffer[j][10] *= multiplier[j];
}
// Inverse Transform
IFFT((const double**)FFTBuffer, outBuffer, chunklength);
for (UInt32 j = 0; j < chunklength; j++){
// copy to output
if ((int)((float)i * chunklength / 2 + j) < samples){
output[(int)((float)i * chunklength / 2 + j)] += outBuffer[j][0];
}
}
}
After the suggestion below, I tried the following:
IFFTed my Filter. This looks like this:
set the second half to zero:
FFTed the signal and compared the magnitudes to the old filter (blue):
After trying to do overlap and add with this filter, the results have obviously gotten worse instead of better. In order to make sure my FFT works correctly, I tried to IFFT and FFT the filter without setting the second half zero. The result is identical to the orignal filter. So the problem shouldn't be the FFTing. I suppose that this is more of some general understanding of the overlap and add method. But I still can't figure out what is going wrong...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
要检查的一件事是滤波器的脉冲响应的长度。它必须比快速卷积 FFT 之前使用的零填充长度短,否则会出现环绕错误。
One thing to check is the length of the impulse response of your filter. It must be shorter than the length of zero padding used before the fast convolution FFT, or you will get wrap around errors.
我认为问题可能出在您使用的窗口方法中。您只需向块添加零,这样就没有实际的重叠。在重叠和添加方法中,您需要对窗口的边缘进行阻尼。这意味着,当您向块添加零时,您会添加加权输入信号,并且您的情况下的权重应该为 0.5,因为只有两个窗口重叠。
其余的程序似乎没问题。然后,您只需采用 FT,乘以并取逆 FTS,最后将所有块相加即可得到最终信号,如果您一次过滤整个信号,该信号应该完全相同。
I think the problem might be in the windowing approach that you are using. You simply add zeros to the chunks so there is no actual overlap. In the overlap and add method, you need to damp the edges of the window. What this means is that where you add zeros to the chunk you instead have add weighted input signal and the weight in your case should be 0.5 since only two windows overlap.
Rest of the procedure seems OK. You then simply take FTs, multiply and take inverse FTS and finally add up all the chunks to get the final signal which should be exactly the same if you filtered the whole signal at once.