C++学习|CUFFT计算一维傅里叶变换

本文介绍了如何在CUDA环境中使用CUFFT库进行一维傅里叶变换,包括CUFFT库的介绍、CUFFTW与FFTW的集成以及在CUDA项目配置中的注意事项,还提供了GPU使用状态监控的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言:之前实现了CPU运行一维傅里叶变换,最近要改成GPU加速一维傅里叶变换,于是有了此篇作为记录,方便以后查阅。

CUFFT库介绍

CUFFT(CUDA Fast Fourier Transform):CUDA提供了一系列的函数帮助开发者进行快速傅里叶变换的运算。

CUFFT库构成:两个子库分别是CUFFT和CUFFTW。

  • CUFFTW:提供了一些接口,使得用户使用FFTW库(CPU快速傅里叶变换库,FFTW3文章有讲解过安装和使用)编写的程序能够运行在GPU上。其实意思就是FFTW CPU编写的代码可以用在CUFFTW GPU,因为它们的接口名字相同。这提高使用FFTW现有代码的可移植性。
  • CUFFT:是纯CUDA接口的快速傅里叶变换库。

CUFFTW计算一维傅里叶变换

使用的傅里变换的函数和CPU的FFTW3一摸一样,但是要改动一些地方。

  • cuda配置的时候,“项目-属性-连接器-输入lib”的部分还要加上cufftw.lib,不然无法解析fftw函数。
  • 头文件fftw3.h改成cufftw.h。
  • 还要进行GPU内存管理。
  • 因为涉及到GPU内存管理所以要写在cu文件下(一开始犯糊涂,直接在cpp文件改了,结果发现和CPU运行的速度一样)。

.cu文件代码:

#include"cuda.cuh"
#include <cuda_runtime.h>
#include<device_launch_parameters.h>
#include <stdio.h>
#include<cufftw.h>

void fftFun(int n, double *in, double* out) {
    // FFTW默认使用双精度浮点数,所以这里用double
    // 傅里叶变换数据
    fftw_complex* DataIn = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n);
    fftw_complex* DataOut = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n);
    fftw_plan Plan = fftw_plan_dft_1d(n, DataIn, DataOut, FFTW_FORWARD, FFTW_ESTIMATE);
    // 数据从cpu拷贝到gpu
    for (int i = 0; i < n; i++) {
        DataIn[i][0] = in[i];
    }
    // 进行傅里叶变换
    fftw_execute(Plan);
    // 数据从GPU拷贝回GPU
    for (int i = 0; i < n / 2; i++) {
        out[i] = sqrt(DataOut[i][0]*DataOut[i][0] + DataOut[i][1]*DataOut[i][1])/(n/2);// 计算振幅
    }
    // 销毁
    fftw_free(DataIn);
	fftw_free(DataOut);
	fftw_destroy_plan(Plan);
    return;
}

判断CUDA是否有用上

  1. 可以在任务管理器中看程序运行后CUDA调用GPU的情况。
    在这里插入图片描述

  2. nvidia-smi,打开cmd命令行输入nvidia-smi即可查看NVIDIA GPU使用状况。
    在这里插入图片描述

    • GPU:本机中的GPU编号,从0开始。
    • Fan:风扇转速(0%-100%),N/A表示没有风扇。
    • Name:GPU名字/类型。
    • Temp:GPU温度。
    • Perf:性能状态,从P0(最大性能)到P12(最小性能)。
    • Pwr:Usager/Cap:GPU功耗,Usage表示用了多少,Cap表示总共多少。
    • Volatile GPU-UTil:GPU使用率。
    • Uncorr. ECC:是否开启错误检查和纠错技术,0/DISABLED,1/ENABLED。
    • Processes:GPU表示占用那个编号GPU,每个进程占用的显存使用率和进程号等。

    实时刷新指令:nvidia-smi -l 1

CUFFT计算一维傅里叶变换

注意的点:

  • cuda配置的时候,“项目-属性-连接器-输入lib”的部分还要加上cufft.lib,不然无法解析fftw函数。
  • 头文件加上cufft.h。
  • 在.cu文件中编写,因为涉及到GPU内存管理。

.cu文件核心函数:

void fftFun(int n, cufftComplex* in, cufftComplex* out) {
    // 傅里叶变换数据
    // 这里cufftComplex是单精度的,如果要用双精度改为cufftDoubleComplex
    cufftComplex* DataIn, * DataOut;
    cudaMalloc((void**)&DataIn, sizeof(cufftComplex) * n);
    cudaMalloc((void**)&DataOut, sizeof(cufftComplex) * n);
    cufftHandle Plan;
    cufftPlan1d(&Plan, n, CUFFT_C2C, 1);// 双精度cufftPlan1d(&Plan, n, CUFFT_Z2Z, 1);
    // 把CPU数据复制到GPU
    cudaMemcpy(in, DataIn, n* sizeof(cufftComplex), cudaMemcpyHostToDevice);
    // 傅里叶变换
    // CUFFT_FORWARD为正向FFT,CUFFT_INVERSE为逆向FFT
    cufftExecC2C(Plan, DataIn, DataOut, CUFFT_FORWARD);// 双精度cufftExecZ2Z(Plan, DataIn, DataOut, CUFFT_FORWARD);
    // 把GPU数据复制到CPU
    cudaMemcpy(DataOut, out, n * sizeof(cufftComplex), cudaMemcpyDeviceToHost);
    // 销毁GPU开辟的东西
    cufftDestroy(Plan);
    cudaFree(DataIn);
    cudaFree(DataOut);
    return;
}

.cpp文件main函数

int main()
{
	// 输入n,再输入n个要进行傅里叶变换的采样点
	int n;
	cin >> n;
	// CPU的傅里叶变换数据分配内存
	// 双精度改为cufftDoubleComplex
	cufftComplex* in = (cufftComplex*)malloc(n * sizeof(cufftComplex));
	cufftComplex* out = (cufftComplex*)malloc(n * sizeof(cufftComplex));
	for (int i = 0; i < n; i++) {
		cin >> in[i].x;
		in[i].y = 0;
	}
	fftFun(n, in, out);
	// 输出傅里叶变换后的振幅,傅里叶变换左右对称所以只需要n/2个点
	for (int i = 0; i < n/2; i++) {
		cout << sqrt(out[i].x * out[i].x + out[i].y * out[i].y) / (n / 2) << " ";;// 计算振幅
	}
	cout << endl; 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值