快速卷积算法
我需要对两个一维信号进行卷积,一个平均有 500 个点(这个是汉宁窗函数),另一个有 125000 个点。每次运行,我需要应用三倍的卷积运算。我已经有一个基于 scipy 文档运行的实现。如果你愿意的话,你可以在这里看到代码(Delphi 代码在前面):
function Convolve(const signal_1, signal_2 : ExtArray) : ExtArray;
var
capital_k : Integer;
capital_m : Integer;
smallest : Integer;
y : ExtArray;
n : Integer;
k : Integer;
lower, upper : Integer;
begin
capital_k := Length(signal_1) + Length(signal_2) - 1;
capital_m := Math.Max(Length(signal_1), Length(signal_2));
smallest := Math.Min(Length(signal_1), Length(signal_2));
SetLength(y, capital_k);
for n := 0 to Length(y) - 1 do begin
y[n] := 0;
lower := Math.Max(n - capital_m, 0);
upper := Math.Min(n, capital_k);
for k := lower to upper do begin
if (k >= Length(signal_1)) or (n - k >= Length(signal_2)) then
Continue;
y[n] := y[n] + signal_1[k] * signal_2[n - k];
end;
end;
Result := Slice(y,
Floor(smallest / 2) - 1,
Floor(smallest / 2) - 1 + capital_m);
end;
问题是,这个实现太慢了。整个过程大约需要五分钟。我想知道是否可以找到一种更快的计算方法。
I need to convolve two one dimensional signals, one has on average 500 points (This one is a Hanning window function), the other 125000. Per run, I need to apply three times the convolution operation. I already have an implementation running based on the documentation of scipy. You can see the code here if you want to (Delphi code ahead):
function Convolve(const signal_1, signal_2 : ExtArray) : ExtArray;
var
capital_k : Integer;
capital_m : Integer;
smallest : Integer;
y : ExtArray;
n : Integer;
k : Integer;
lower, upper : Integer;
begin
capital_k := Length(signal_1) + Length(signal_2) - 1;
capital_m := Math.Max(Length(signal_1), Length(signal_2));
smallest := Math.Min(Length(signal_1), Length(signal_2));
SetLength(y, capital_k);
for n := 0 to Length(y) - 1 do begin
y[n] := 0;
lower := Math.Max(n - capital_m, 0);
upper := Math.Min(n, capital_k);
for k := lower to upper do begin
if (k >= Length(signal_1)) or (n - k >= Length(signal_2)) then
Continue;
y[n] := y[n] + signal_1[k] * signal_2[n - k];
end;
end;
Result := Slice(y,
Floor(smallest / 2) - 1,
Floor(smallest / 2) - 1 + capital_m);
end;
The problem is, this implementation is too slow. The whole procedure takes about five minutes. I was wondering if I can find a faster way of computing that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
快速卷积可以使用 FFT 进行。对两个输入信号进行 FFT(使用适当的零填充),在频域中相乘,然后进行逆 FFT。对于较大的 N(通常 N > 100),这比直接方法更快。
Fast convolution can be carried out using FFTs. Take the FFT of both input signals (with appropriate zero padding), multiply in the frequency domain, then do an inverse FFT. For large N (typically N > 100) this is faster than the direct method.
有很多快速卷积算法。他们中的大多数使用 FFT 例程,例如 FFTW。这是因为像卷积这样的运算(在时域中)减少为频域中的乘法(频域表示)。当前需要大约 5 分钟(根据您自己的估计)的卷积运算在您使用 FFT 例程实现卷积后可能只需要几秒钟。
此外,如果滤波器的长度和信号的长度之间存在很大差异,您可能还需要考虑使用重叠保存或重叠添加。更多信息请参见此处。如果在 Delphi 中编码不是最重要的问题,那么您可能想要使用 C/C++,只要 FFTW 和其他一些库在 C/C++ 中可用(不确定 scipy 或 Delphi)。
There are a lot of fast convolution algorithms out there. Most of them use FFT routines such as FFTW. This is because an operation like convolution (in the time domain) reduces to multiplication (of the frequency domain representations) in the frequency domain. A convolution operation that currently takes about 5 minutes (by your own estimates) may take as little as a few seconds once you implement convolution with FFT routines.
Also, if there is a big difference between the length of your filter and the length of your signal, you may also want to consider using Overlap-Save or Overlap-Add. More information here. If coding in Delphi is not an overriding concern, you might want to use C/C++ if only for the reason that FFTW and some other libraries are available in C/C++ (not sure about scipy or Delphi).