我试图实现Simulating ocean water (PDF)中概述的iWave水面模拟,最后有一个代码提取。
特定方法是使用卷积核计算垂直导数
for(int ix = 6; ix < iwidth - 6; ix++)
{
for(int iy = 6; iy < iheight - 6; iy++)
{
int index = ix + iwidth * iy;
float vd = 0;
// apply convolution
for(int iix = -6; iix <= 6; iix++)
{
for(int iiy = -6; iiy <= 6; iiy++)
{
int iindex = ix + iix + iwidth * (iy + iiy);
vd += kernel[iix + 6, iiy + 6] * height[iindex];
}
}
vertical_derivative[index] = vd;
}
}
在每个高度点(一个扁平的2x2阵列)卷积内核(2x2数组大小为13) 用于计算垂直导数。 当高度网格的大小(128x128)时,实时交互变得太慢,但我想要一个更大的网格。我怎么能加快速度呢?
答案 0 :(得分:1)
进行卷积的一种更快的方法是利用身份FT(conv(f,g))= FT(f)FT(g),即两个函数的卷积的傅立叶变换是傅立叶变换的逐点积。因此conv(f,g)= FT ^ -1(FT(f)FT(g))其中FT ^ -1是逆傅立叶变换。使用快速傅里叶变换。
答案 1 :(得分:1)
我同意以某种方式使用显卡获得最高增益。
但请注意两种方法:
只需使用Parallel.For
内置语言功能;这将在CPU上并行化,并且非常易于使用。
const int convolutionWidth = 6;
Parallel.For(convolutionWidth, iwidth - convolutionWidth, ix =>
{
for (int iy = convolutionWidth; iy < iheight - convolutionWidth; iy++)
{
int index = ix + iwidth * iy;
float vd = 0;
// apply convolution
for (int iix = -convolutionWidth; iix <= convolutionWidth; iix++)
{
int iindex = ix + iix + iwidth * (iy - convolutionWidth);
for (int iiy = -convolutionWidth; iiy <= convolutionWidth; iiy++)
{
vd += kernel[iix + convolutionWidth, iiy + convolutionWidth] * height[iindex];
iindex += iwidth;
}
}
vertical_derivative[index] = vd;
}
});
答案 2 :(得分:0)
使用SIMD功能(如果您的硬件支持),这种情况可以高度优化。
但是,CLR目前尚未使用完整的SIMD功能。对于实验用途,您可以下载支持RyuJit
的(see this link for more info)主要思想是重构一下你的数据格式,以便为你的操作使用向量(而不仅仅是数字)
加速可以令人印象深刻(最高可达x6,具体取决于您的硬件)。