我试图在"有效"中实现一维卷积。 C ++中的模式(Matlab定义)。
看起来很简单,但我还没能找到用C ++(或其他任何我能适应的语言)的代码。如果我的矢量大小是一个幂,我可以使用2D卷积,但我想找到一些适用于任何输入和内核的东西。
那么如何在"有效"中执行1维卷积?模式,给定大小为I的输入向量和大小为K的内核(输出通常应为大小为I-K + 1的向量)。
也接受伪代码。
答案 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
。
(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
。
答案 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()。