0
# FFT Operations
1
2
GPU-accelerated Fast Fourier Transform operations using cuFFT library. Provides complete discrete Fourier transform functionality including 1D, 2D, and N-D transforms for both complex-to-complex and real-to-complex transformations.
3
4
## Capabilities
5
6
### Discrete Fourier Transform
7
8
```python { .api }
9
def fft(a, n=None, axis=-1, norm=None):
10
"""
11
Compute 1-D discrete Fourier Transform.
12
13
Parameters:
14
- a: input array
15
- n: length of transformed axis
16
- axis: axis over which to compute FFT
17
- norm: normalization mode ('backward', 'ortho', 'forward')
18
19
Returns:
20
cupy.ndarray: transformed array
21
"""
22
23
def ifft(a, n=None, axis=-1, norm=None):
24
"""
25
Compute 1-D inverse discrete Fourier Transform.
26
27
Parameters:
28
- a: input array
29
- n: length of transformed axis
30
- axis: axis over which to compute IFFT
31
- norm: normalization mode
32
33
Returns:
34
cupy.ndarray: inverse transformed array
35
"""
36
37
def fft2(a, s=None, axes=(-2, -1), norm=None):
38
"""
39
Compute 2-D discrete Fourier Transform.
40
41
Parameters:
42
- a: input array
43
- s: shape of transformed axes
44
- axes: axes over which to compute FFT
45
- norm: normalization mode
46
47
Returns:
48
cupy.ndarray: 2-D transformed array
49
"""
50
51
def ifft2(a, s=None, axes=(-2, -1), norm=None):
52
"""
53
Compute 2-D inverse discrete Fourier Transform.
54
55
Parameters:
56
- a: input array
57
- s: shape of transformed axes
58
- axes: axes over which to compute IFFT
59
- norm: normalization mode
60
61
Returns:
62
cupy.ndarray: 2-D inverse transformed array
63
"""
64
65
def fftn(a, s=None, axes=None, norm=None):
66
"""
67
Compute N-D discrete Fourier Transform.
68
69
Parameters:
70
- a: input array
71
- s: shape of transformed axes
72
- axes: axes over which to compute FFT
73
- norm: normalization mode
74
75
Returns:
76
cupy.ndarray: N-D transformed array
77
"""
78
79
def ifftn(a, s=None, axes=None, norm=None):
80
"""
81
Compute N-D inverse discrete Fourier Transform.
82
83
Parameters:
84
- a: input array
85
- s: shape of transformed axes
86
- axes: axes over which to compute IFFT
87
- norm: normalization mode
88
89
Returns:
90
cupy.ndarray: N-D inverse transformed array
91
"""
92
```
93
94
### Real FFT
95
96
```python { .api }
97
def rfft(a, n=None, axis=-1, norm=None):
98
"""
99
Compute 1-D discrete Fourier Transform for real input.
100
101
Parameters:
102
- a: input array (real)
103
- n: length of transformed axis
104
- axis: axis over which to compute FFT
105
- norm: normalization mode
106
107
Returns:
108
cupy.ndarray: transformed array (complex)
109
"""
110
111
def irfft(a, n=None, axis=-1, norm=None):
112
"""
113
Compute 1-D inverse discrete Fourier Transform for real output.
114
115
Parameters:
116
- a: input array (complex)
117
- n: length of transformed axis
118
- axis: axis over which to compute IFFT
119
- norm: normalization mode
120
121
Returns:
122
cupy.ndarray: inverse transformed array (real)
123
"""
124
125
def rfft2(a, s=None, axes=(-2, -1), norm=None):
126
"""
127
Compute 2-D discrete Fourier Transform for real input.
128
129
Parameters:
130
- a: input array (real)
131
- s: shape of transformed axes
132
- axes: axes over which to compute FFT
133
- norm: normalization mode
134
135
Returns:
136
cupy.ndarray: 2-D transformed array (complex)
137
"""
138
139
def irfft2(a, s=None, axes=(-2, -1), norm=None):
140
"""
141
Compute 2-D inverse discrete Fourier Transform for real output.
142
143
Parameters:
144
- a: input array (complex)
145
- s: shape of transformed axes
146
- axes: axes over which to compute IFFT
147
- norm: normalization mode
148
149
Returns:
150
cupy.ndarray: 2-D inverse transformed array (real)
151
"""
152
153
def rfftn(a, s=None, axes=None, norm=None):
154
"""
155
Compute N-D discrete Fourier Transform for real input.
156
157
Parameters:
158
- a: input array (real)
159
- s: shape of transformed axes
160
- axes: axes over which to compute FFT
161
- norm: normalization mode
162
163
Returns:
164
cupy.ndarray: N-D transformed array (complex)
165
"""
166
167
def irfftn(a, s=None, axes=None, norm=None):
168
"""
169
Compute N-D inverse discrete Fourier Transform for real output.
170
171
Parameters:
172
- a: input array (complex)
173
- s: shape of transformed axes
174
- axes: axes over which to compute IFFT
175
- norm: normalization mode
176
177
Returns:
178
cupy.ndarray: N-D inverse transformed array (real)
179
"""
180
```
181
182
### Hermitian FFT
183
184
```python { .api }
185
def hfft(a, n=None, axis=-1, norm=None):
186
"""
187
Compute 1-D discrete Fourier Transform of Hermitian input.
188
189
Parameters:
190
- a: input array (Hermitian symmetric)
191
- n: length of transformed axis
192
- axis: axis over which to compute FFT
193
- norm: normalization mode
194
195
Returns:
196
cupy.ndarray: transformed array (real)
197
"""
198
199
def ihfft(a, n=None, axis=-1, norm=None):
200
"""
201
Compute 1-D inverse discrete Fourier Transform to produce Hermitian output.
202
203
Parameters:
204
- a: input array (real)
205
- n: length of transformed axis
206
- axis: axis over which to compute IFFT
207
- norm: normalization mode
208
209
Returns:
210
cupy.ndarray: inverse transformed array (Hermitian)
211
"""
212
```
213
214
### Helper Functions
215
216
```python { .api }
217
def fftfreq(n, d=1.0):
218
"""
219
Return discrete Fourier Transform sample frequencies.
220
221
Parameters:
222
- n: window length
223
- d: sample spacing
224
225
Returns:
226
cupy.ndarray: sample frequencies
227
"""
228
229
def rfftfreq(n, d=1.0):
230
"""
231
Return sample frequencies for real FFT.
232
233
Parameters:
234
- n: window length
235
- d: sample spacing
236
237
Returns:
238
cupy.ndarray: sample frequencies for real FFT
239
"""
240
241
def fftshift(x, axes=None):
242
"""
243
Shift zero-frequency component to center of spectrum.
244
245
Parameters:
246
- x: input array
247
- axes: axes over which to shift
248
249
Returns:
250
cupy.ndarray: shifted array
251
"""
252
253
def ifftshift(x, axes=None):
254
"""
255
Inverse of fftshift.
256
257
Parameters:
258
- x: input array
259
- axes: axes over which to shift
260
261
Returns:
262
cupy.ndarray: shifted array
263
"""
264
```
265
266
### Configuration
267
268
```python { .api }
269
# FFT configuration module
270
import cupy.fft.config
271
272
# Planning and caching controls available through config module
273
```
274
275
## Usage Examples
276
277
### Basic 1-D FFT
278
279
```python
280
import cupy as cp
281
import numpy as np
282
283
# Create sample signal
284
t = cp.linspace(0, 1, 1000)
285
freq1, freq2 = 5, 20 # Hz
286
signal = cp.sin(2*cp.pi*freq1*t) + 0.5*cp.sin(2*cp.pi*freq2*t)
287
288
# Add noise
289
noise = 0.1 * cp.random.randn(len(t))
290
noisy_signal = signal + noise
291
292
# Compute FFT
293
fft_result = cp.fft.fft(noisy_signal)
294
frequencies = cp.fft.fftfreq(len(t), t[1] - t[0])
295
296
# Magnitude spectrum
297
magnitude = cp.abs(fft_result)
298
299
# Find peaks (transfer to CPU for analysis)
300
magnitude_cpu = cp.asnumpy(magnitude)
301
freq_cpu = cp.asnumpy(frequencies)
302
```
303
304
### 2-D FFT for Image Processing
305
306
```python
307
import cupy as cp
308
309
# Create or load 2D image data
310
image = cp.random.random((256, 256))
311
312
# Compute 2-D FFT
313
fft2d = cp.fft.fft2(image)
314
315
# Shift zero frequency to center
316
fft2d_shifted = cp.fft.fftshift(fft2d)
317
318
# Magnitude and phase
319
magnitude = cp.abs(fft2d_shifted)
320
phase = cp.angle(fft2d_shifted)
321
322
# Apply frequency domain filter (low-pass)
323
rows, cols = image.shape
324
crow, ccol = rows//2, cols//2
325
mask = cp.zeros((rows, cols))
326
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
327
328
# Apply mask
329
filtered_fft = fft2d_shifted * mask
330
331
# Inverse transform
332
filtered_fft_ishifted = cp.fft.ifftshift(filtered_fft)
333
filtered_image = cp.fft.ifft2(filtered_fft_ishifted)
334
filtered_image = cp.real(filtered_image) # Take real part
335
```
336
337
### Real FFT for Efficiency
338
339
```python
340
import cupy as cp
341
342
# For real-valued signals, use rfft for efficiency
343
real_signal = cp.random.randn(1024)
344
345
# Real FFT (more efficient than complex FFT)
346
rfft_result = cp.fft.rfft(real_signal)
347
348
# Only positive frequencies are computed
349
n_pos_freq = len(rfft_result)
350
print(f"Original length: {len(real_signal)}, FFT length: {n_pos_freq}")
351
352
# Recover original signal
353
recovered_signal = cp.fft.irfft(rfft_result)
354
355
# Check reconstruction accuracy
356
reconstruction_error = cp.linalg.norm(real_signal - recovered_signal)
357
print(f"Reconstruction error: {reconstruction_error}")
358
```
359
360
### N-D FFT
361
362
```python
363
import cupy as cp
364
365
# 3-D data (e.g., volumetric data)
366
volume_data = cp.random.random((64, 64, 64))
367
368
# 3-D FFT
369
fft3d = cp.fft.fftn(volume_data)
370
371
# Compute magnitude spectrum
372
magnitude_spectrum = cp.abs(fft3d)
373
374
# FFT along specific axes only
375
fft_xy = cp.fft.fft2(volume_data, axes=(0, 1)) # FFT in X-Y plane for each Z
376
377
# Real 3-D FFT for real input
378
real_volume = cp.random.randn(32, 32, 32)
379
rfft3d = cp.fft.rfftn(real_volume)
380
```
381
382
### Convolution using FFT
383
384
```python
385
import cupy as cp
386
387
# Create signals
388
signal = cp.random.randn(1000)
389
kernel = cp.array([1, -1, 1, -1, 1]) / 5 # Simple kernel
390
391
# Pad for full convolution
392
n = len(signal) + len(kernel) - 1
393
signal_padded = cp.zeros(n)
394
signal_padded[:len(signal)] = signal
395
kernel_padded = cp.zeros(n)
396
kernel_padded[:len(kernel)] = kernel
397
398
# FFT-based convolution
399
signal_fft = cp.fft.fft(signal_padded)
400
kernel_fft = cp.fft.fft(kernel_padded)
401
convolved_fft = signal_fft * kernel_fft
402
convolved = cp.fft.ifft(convolved_fft)
403
convolved = cp.real(convolved) # Take real part
404
405
# Compare with direct convolution (on CPU)
406
signal_cpu = cp.asnumpy(signal)
407
kernel_cpu = cp.asnumpy(kernel)
408
direct_conv = np.convolve(signal_cpu, kernel_cpu, mode='full')
409
```
410
411
### Spectral Analysis
412
413
```python
414
import cupy as cp
415
416
# Generate test signal with multiple frequencies
417
fs = 1000 # Sampling frequency
418
t = cp.arange(0, 1, 1/fs)
419
f1, f2, f3 = 10, 50, 120 # Frequencies in Hz
420
421
signal = (cp.sin(2*cp.pi*f1*t) +
422
0.5*cp.sin(2*cp.pi*f2*t) +
423
0.2*cp.sin(2*cp.pi*f3*t))
424
425
# Add noise
426
signal += 0.1 * cp.random.randn(len(t))
427
428
# Windowing (Hann window)
429
window = cp.hanning(len(signal))
430
windowed_signal = signal * window
431
432
# Compute FFT
433
fft_result = cp.fft.fft(windowed_signal)
434
freqs = cp.fft.fftfreq(len(signal), 1/fs)
435
436
# Power spectral density
437
psd = cp.abs(fft_result)**2
438
439
# Find positive frequencies only
440
positive_freq_mask = freqs >= 0
441
positive_freqs = freqs[positive_freq_mask]
442
positive_psd = psd[positive_freq_mask]
443
```
444
445
### Frequency Domain Filtering
446
447
```python
448
import cupy as cp
449
450
# Create noisy signal
451
t = cp.linspace(0, 1, 1000)
452
clean_signal = cp.sin(2*cp.pi*10*t) # 10 Hz signal
453
noise = 0.5 * cp.sin(2*cp.pi*60*t) # 60 Hz noise
454
noisy_signal = clean_signal + noise
455
456
# FFT
457
signal_fft = cp.fft.fft(noisy_signal)
458
freqs = cp.fft.fftfreq(len(t), t[1] - t[0])
459
460
# Design low-pass filter (cutoff at 20 Hz)
461
cutoff_freq = 20
462
filter_mask = cp.abs(freqs) <= cutoff_freq
463
464
# Apply filter in frequency domain
465
filtered_fft = signal_fft * filter_mask
466
467
# Inverse FFT to get filtered signal
468
filtered_signal = cp.fft.ifft(filtered_fft)
469
filtered_signal = cp.real(filtered_signal)
470
471
# Compare signals
472
print(f"Original SNR: {cp.var(clean_signal) / cp.var(noise)}")
473
residual_noise = filtered_signal - clean_signal
474
print(f"Filtered SNR: {cp.var(clean_signal) / cp.var(residual_noise)}")
475
```