如何进行一维“有效”卷积?

时间:2014-07-01 20:45:52

标签: c++ math convolution

我试图在"有效"中实现一维卷积。 C ++中的模式(Matlab定义)。

看起来很简单,但我还没能找到用C ++(或其他任何我能适应的语言)的代码。如果我的矢量大小是一个幂,我可以使用2D卷积,但我想找到一些适用于任何输入和内核的东西。

那么如何在"有效"中执行1维卷积?模式,给定大小为I的输入向量和大小为K的内核(输出通常应为大小为I-K + 1的向量)。

也接受伪代码。

3 个答案:

答案 0 :(得分:9)

您可以使用以下任一实现:

完全卷积:

template<typename T>
std::vector<T>
conv(std::vector<T> const &f, std::vector<T> const &g) {
  int const nf = f.size();
  int const ng = g.size();
  int const n  = nf + ng - 1;
  std::vector<T> out(n, T());
  for(auto i(0); i < n; ++i) {
    int const jmn = (i >= ng - 1)? i - (ng - 1) : 0;
    int const jmx = (i <  nf - 1)? i            : nf - 1;
    for(auto j(jmn); j <= jmx; ++j) {
      out[i] += (f[j] * g[i - j]);
    }
  }
  return out; 
}

f:第一个序列(1D信号)。

g:第二个序列(1D信号)。

返回大小为std::vector的{​​{1}},这是离散卷积的结果。 Cauchy产品f.size() + g.size() - 1

LIVE DEMO

有效卷积:

(f * g) = (g * f)

template<typename T> std::vector<T> conv_valid(std::vector<T> const &f, std::vector<T> const &g) { int const nf = f.size(); int const ng = g.size(); std::vector<T> const &min_v = (nf < ng)? f : g; std::vector<T> const &max_v = (nf < ng)? g : f; int const n = std::max(nf, ng) - std::min(nf, ng) + 1; std::vector<T> out(n, T()); for(auto i(0); i < n; ++i) { for(int j(min_v.size() - 1), k(i); j >= 0; --j) { out[i] += min_v[j] * max_v[k]; ++k; } } return out; } :第一个序列(1D信号)。

f:第二个序列(1D信号)。

返回大小为g的{​​{1}},这是有效(即没有填充)离散卷积的结果。 Cauchy产品std::vector

LIVE DEMO

答案 1 :(得分:1)

我不明白你为什么需要实现卷积功能。 Matlab没有内置的1D卷积功能吗?

将它放在一边,您可以在给定傅立叶变换函数的情况下实现卷积。您需要注意输入和输出向量的长度。结果的长度为I + K - 1(不是I - K + 1,对吧?)。将每个输入向量用零扩展为N,其中N是2的幂大于或等于I + K - 1。对输入进行傅里叶变换,然后逐个元素地对结果进行多次转换。对该产品进行逆傅里叶变换,并返回第一个I + K - 1元素(抛弃其余元素)。这就是你的卷积。

你可能需要在某处放置1/N的比例因子,因为没有普遍认可的傅立叶变换缩放,我不记得Matlab为此所采用的。

答案 2 :(得分:1)

为了在 std :: vector 上执行1-D有效卷积(为了示例,我们将其称为 vec ,并且大小 l 的输出向量 outvec )足以通过正确设置循环参数来创建正确的边界,然后像往常一样执行卷积,即:< / p>

for(size_t i = K/2; i < l - K/2; ++i)
{
    outvec[i] = 0.0;
    for(size_t j = 0; j < K+1; j++)
    {
         outvec[i - K/2] += invec[i - K/2 + j] * kernel[j];
    }
} 

请注意 i 的起始值和最终值。

适用于任何大小的任何1-D内核 - 前提是内核的大小不比向量大;)

请注意,我已经使用了您所描述的变量 K ,但就我个人而言,我会理解&#39;尺寸&#39;不同 - 我想是一个品味的问题。在该示例中,核向量的总长度是K + 1。我还假设 outvec 已经有 l - K 元素(BTW:输出向量有l - K个元素,而不是l - K + 1,因为你有写的),所以不需要 push_back()