module NumRu::FFTW3
Ruby wrapper of FFTW3, a fast discrete Fourier transform library. www.fftw.org
Features¶ ↑
-
Uses NArray (github.com/masa16/narray). (Also it supports NumRu::NArray as well, if this library is compiled to use it).
-
Multi-dimensional complex and real FFT.
-
Supports both double and single float transforms.
How to use¶ ↑
Copy and paste the following code line-by-line using irb. Or you can run it by saving it in a file fftw3test.rb (say) and executing “ruby fftw3test.rb”.
require "numru/fftw3" include NumRu na = NArray.float(8,6) # float -> will be coerced to complex na[1,1]=1 # <example 1: complex FFT on all dimensions > fc = FFTW3.fft(na, FFTW3::FORWARD)/na.length # forward 2D FFT and normalization nc = FFTW3.fft(fc, FFTW3::BACKWARD) # backward 2D FFT (complex) --> nb = nc.real # should be equal to na except round errors p (nb - na).abs.max # => 8.970743058303247e-17 (sufficiently small) # <example 2: complex FFT on all dimensions > # Same as example 1 but using more user-friendly wrapper of FFTW3.fft fc = FFTW3.fft_fw(na) # forward 2D FFT and normalization nc = FFTW3.fft_bk(fc) # backward 2D FFT (complex) --> nb = nc.real # should be equal to na except round errors p (nb - na).abs.max # => 8.970743058303247e-17 (sufficiently small) # <example 3: complex FFT along a dimension > fc = FFTW3.fft_fw(na, 0) # forward 1D FFT along the first dim nc = FFTW3.fft_bk(fc, 0) # backward 1D FFT along the first dim p (nc.real - na).abs.max # => 1.1102230246251565e-16 (sufficiently small) # <example 4: complex FFT along a dimension > fc = FFTW3.fft_fw(na, 1) # forward 1D FFT along the second dim # <example 5: real FFT along a dimension > fc = FFTW3.fft_r2r(na, FFTW3::RODFT00, 0) # not normalized sine transform along the 1st dim len = 2*(na.shape[0]+1) # this is the supposed length of this transformation nc = FFTW3.fft_r2r(fc/len, FFTW3::RODFT00, 0) # forward==backward transformation p (nc-na).abs.max # => 2.220446049250313e-16 (sufficiently small) # <example 5b: real FFT on all dimensions > fc = FFTW3.fft_r2r(na, FFTW3::REDFT11) # unnormalized cosine transform len = 4*na.length # from (2*na.shape[0]) * (2*na.shape[1]) nc = FFTW3.fft_r2r(fc/len, FFTW3::REDFT11) # forward==backward transformation p (nc-na).abs.max # => 6.228190483314256e-17 (sufficiently small)
See the FFTW3 manual for the kinds of supported real FFTs. See Ch.2 of www.fftw.org/fftw3_doc/ (www.fftw.org/fftw3.pdf). Virtually all kinds are supported!
Constants
- BACKWARD
Specifier of backward complex FFT. Integer equal to 1.
- DHT
Specifier of real FFT kind. Discrete Hartley Transform
- FORWARD
Specifier of forward complex FFT. Integer equal to -1.
- HC2R
Specifier of real FFT kind. “halfcomplex” to real
- R2HC
Specifier of real FFT kind. real to “halfcomplex”
- REDFT00
Specifier of real FFT kind. cosine (even) transform; logical data length 2*(n-1); inverse is itself
- REDFT01
Specifier of real FFT kind. cosine (even) transform; logical data length 2*n; inverse is REDFT10
- REDFT10
Specifier of real FFT kind. cosine (even) transform; logical data length 2*n; inverse is REDFT01
- REDFT11
Specifier of real FFT kind. cosine (even) transform; logical data length 2*n; inverse is itself
- RODFT00
Specifier of real FFT kind. sine (odd) transform; logical data length 2*(n+1); inverse is itself
- RODFT01
Specifier of real FFT kind. sine (odd) transform; logical data length 2*n; inverse is RODFT10
- RODFT10
Specifier of real FFT kind. sine (odd) transform; logical data length 2*n; inverse is RODFT01
- RODFT11
Specifier of real FFT kind. sine (odd) transform; logical data length 2*n; inverse is itself
- VERSION
Public Class Methods
Conducts complex FFT (unnormalized). You can use more user-friendly wrappers #fft_fw and fft_bk.
ARGUMENTS
-
narray (NArray or NArray-compatible Array) : array to be transformed. If real, coerced to complex before transformation. If narray is single-precision and the single-precision version of FFTW3 is installed (before installing this module), this method does a single-precision transform. Otherwise, a double-precision transform is used.
-
dir (FORWARD (which is simply equal to -1; referable as NumRu::FFTW3::FORWARD) or BACKWARD (which is simply 1) ) : the direction of FFT, forward if FORWARD and backward if BACKWARD.
-
optional 3rd, 4th,… arguments (Integer) : Specifies dimensions to apply FFT. For example, if 0, the first dimension is transformed (1D FFT); If -1, the last dimension is used (1D FFT); If 0,2,4, the first, third, and fifth dimensions are transformed (3D FFT); If entirely omitted, ALL DIMENSIONS ARE SUBJECT TO FFT, so 3D FFT is done with a 3D array.
RETURN VALUE
-
a complex NArray
NOTE
-
As in FFTW, return value is NOT normalized. Thus, a consecutive forward and backward transform would multiply the size of data used for transform. You can normalize, for example, the forward transform FFTW.fft(narray, -1, 0, 1) (FFT regarding the first (dim 0) & second (dim 1) dimensions) by dividing with (narray.shape*narray.shape). Likewise, the result of FFTW.fft(narray, -1) (FFT for all dimensions) can be normalized by narray.length.
static VALUE na_fftw3(int argc, VALUE *argv, VALUE self) { VALUE val; volatile VALUE v1; struct NARRAY *a1; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])"); } val = argv[0]; v1 = na_to_narray(val); GetNArray(v1,a1); if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){ return( na_fftw3_float(argc, argv, self) ); } else { return( na_fftw3_double(argc, argv, self) ); } }
Conducts real FFT (unnormalized).
ARGUMENTS
-
narray (NArray or NArray-compatible Array) : array to be transformed. Cannot be complex.
-
kind : specifies the kind of FFT. One of the following: R2HC, HC2R, DHT, REDFT00, REDFT01, REDFT10, REDFT11, RODFT00, RODFT01, RODFT10, or RODFT11 (referable as NumRu::FFTW3::REDFT10). See Ch.2 of www.fftw.org/fftw3_doc/ (www.fftw.org/fftw3.pdf).
-
optional 3rd, 4th,… arguments (Integer) : See ::fft.
RETURN VALUE
-
a real NArray
NOTE
-
As in FFTW, return value is NOT normalized, and the length needed normalize is different for each kind.
static VALUE na_fftw3_r2r(int argc, VALUE *argv, VALUE self) { VALUE val; volatile VALUE v1; struct NARRAY *a1; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])"); } val = argv[0]; v1 = na_to_narray(val); GetNArray(v1,a1); if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){ return( na_fftw3_r2r_float(argc, argv, self) ); } else { return( na_fftw3_r2r_double(argc, argv, self) ); } }
Public Instance Methods
Backward complex FFT
This method simply calls FFW3.fft(na, FFW3::BACKWARD, *dims)
# File lib/numru/fftw3.rb, line 98 def fft_bk(na, *dims) fft(na, BACKWARD, *dims) end
Forward complex FFT with normalization
This calls FFW3.fft(na, FFW3::FORWARD, *dims) and normalizes the result by dividing by the length
# File lib/numru/fftw3.rb, line 82 def fft_fw(na, *dims) fc = fft(na, FORWARD, *dims) if dims.length == 0 len = na.total else len = 1 shape = na.shape dims.each{|d| len *= shape[d]} end fc / len end