理论:时间域卷积=频率域乘法(一维卷积为例)
数组列向量
在使用一维线性存储数据时,需要特别注意行和列的问题,在C语言中,通常习惯以行主序进行存储,而当把数据传入cufft库函数时会默认变成列主序存储。不过这也不需要我们进行显示的将C语言主机端的行主序变为列主序,主要cufft中的句柄进行参数设置即可,后面会举例说明。
补零
在使用cufft库中fft对向量计算卷积前,首先要对向量进行补零,使向量长度与卷积后的长度相同,并且补零的方式也会对计算结果产生影响。
(1)如果在向量尾部进行补零,频率域相乘在经过傅里叶反变换后,与直接卷积计算结果相同。
(2)而如果在向量头部补零,或者头部和尾部同时补零,频率域相乘在经过傅里叶反变换后,还需要进行圆周移位才能与直接卷积计算结果相同,具体移位的长度和向量头部补零的个数有关。
数据大小
(1)CUDA的cufft库中,如果是对实数离散信号进行fft变化,只会保留N/2+1个数据,因为实数信号变换后的频谱是对称的,也就是fft结果数组不需要与原数组大小相同,大约一半即可,可能cuda是出于节省内存的原因加入了这样的操作,不过这不会影响后续的频率域乘法计算以及ifft逆变换计算。
(2)再经过fft逆变换时,matlab中会默认将得到的结果除以向量长度,cuda中不会进行该操作,需要手动进行,并且要注意频率域乘法不改变逆变换之后的除数,除数仍然是原来实数向量长度。

举例说明cufft计算过程
//设置句柄
cufftHandle plan1, plan2;
int n[1] = { length };
int inembed[2] = { length,width };
int onembed[2] = { length/2+1,width };
cufftPlanMany(&plan1, 1, n, inembed, width, 1, onembed, width, 1, CUFFT_R2C, width);
上面就是对数据列向量进行fft变换时的句柄设置方法,cufftPlanMany参数意义如下:1、句柄名称。2、维数(上述为一维)。3、要变换信号的长度(当然如果是二维就还有宽度)。4、输入数组的大小。5、同一个信号相邻两个采样点的距离(上述输入为一维行主序,进行列的一维变换,所以相邻采样的距离即为数组宽度)。6、相邻信号同一采样位置(比如第i个采样点)的距离。7、输出数组的大小。8、9与5、6类似,只是变成输出的。10、变化类型(上述为实数到复数)。11、要变化的信号总个数。
cufftExecR2C(plan1, indata, outcuff);
设置号句柄后就可以使用上述函数进行变换,注意句柄和变换函数的统一,以及整个计算中实数和复数的区分。
逆变换的设置就是类似的了,改变输入输出和变换类型即可,最后不要忘了除以信号长度。
cufftPlanMany(&plan2, 1, n, onembed, width, 1, inembed, width, 1, CUFFT_C2R, width);
cufftExecC2R(plan2, incuff, outdata);
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删