我不知道是否有人可以将我推荐给ANSI C中的1D线性convolution代码片段而不是重新发明轮子?我在谷歌搜索和堆栈溢出,但在C中找不到任何我可以使用的东西。
例如,对于数组A,B和C,所有双精度,其中A和B是输入,C是输出,长度为len_A
,len_B
和{{1} }, 分别。
我的阵列尺寸很小,因此不需要通过FFT实现快速卷积的任何速度增加。寻找简单的计算。
答案 0 :(得分:20)
以下是:
#include <stddef.h>
#include <stdio.h>
void convolve(const double Signal[/* SignalLen */], size_t SignalLen,
const double Kernel[/* KernelLen */], size_t KernelLen,
double Result[/* SignalLen + KernelLen - 1 */])
{
size_t n;
for (n = 0; n < SignalLen + KernelLen - 1; n++)
{
size_t kmin, kmax, k;
Result[n] = 0;
kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
for (k = kmin; k <= kmax; k++)
{
Result[n] += Signal[k] * Kernel[n - k];
}
}
}
void printSignal(const char* Name,
double Signal[/* SignalLen */], size_t SignalLen)
{
size_t i;
for (i = 0; i < SignalLen; i++)
{
printf("%s[%zu] = %f\n", Name, i, Signal[i]);
}
printf("\n");
}
#define ELEMENT_COUNT(X) (sizeof(X) / sizeof((X)[0]))
int main(void)
{
double signal[] = { 1, 1, 1, 1, 1 };
double kernel[] = { 1, 1, 1, 1, 1 };
double result[ELEMENT_COUNT(signal) + ELEMENT_COUNT(kernel) - 1];
convolve(signal, ELEMENT_COUNT(signal),
kernel, ELEMENT_COUNT(kernel),
result);
printSignal("signal", signal, ELEMENT_COUNT(signal));
printSignal("kernel", kernel, ELEMENT_COUNT(kernel));
printSignal("result", result, ELEMENT_COUNT(result));
return 0;
}
输出:
signal[0] = 1.000000
signal[1] = 1.000000
signal[2] = 1.000000
signal[3] = 1.000000
signal[4] = 1.000000
kernel[0] = 1.000000
kernel[1] = 1.000000
kernel[2] = 1.000000
kernel[3] = 1.000000
kernel[4] = 1.000000
result[0] = 1.000000
result[1] = 2.000000
result[2] = 3.000000
result[3] = 4.000000
result[4] = 5.000000
result[5] = 4.000000
result[6] = 3.000000
result[7] = 2.000000
result[8] = 1.000000
答案 1 :(得分:3)
未经测试,但似乎可以正常运行......
void conv(const double v1[], size_t n1, const double v2[], size_t n2, double r[])
{
for (size_t n = 0; n < n1 + n2 - 1; n++)
for (size_t k = 0; k < max(n1, n2); k++)
r[n] += (k < n1 ? v1[k] : 0) * (n - k < n2 ? v2[n - k] : 0);
}
答案 2 :(得分:0)
因为我们正在对2个有限长度序列进行卷积,因此如果执行循环卷积而不是线性卷积,则实现了期望的频率响应。循环卷积的一个非常简单的实现将获得与Alex给出的算法相同的结果。
#define MOD(n, N) ((n<0)? N+n : n)
......
......
for(n=0; n < signal_Length + Kernel_Length - 1; n++)
{
out[n] = 0;
for(m=0; m < Kernel_Length; m++)
{
out[n] = h[m] * x[MOD(n-m, N)];
}
}
答案 3 :(得分:0)
我使用了@ Mehrdad的方法,并创建了以下的anwer:
void conv(const double v1[], size_t n1, const double v2[], size_t n2, double r[])
{
for (size_t n = 0; n < n1 + n2 - 1; n++)
for (size_t k = 0; k < max(n1, n2) && n >= k; k++)
r[n] += (k < n1 ? v1[k] : 0) * (n - k < n2 ? v2[n - k] : 0);
}
当第二个循环k
大于n
时索引超出下限的问题,因此,猜测应该有额外的条件来阻止它。