ruby-fftw3 0.4a
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +21 -0
- data/LICENSE.txt +34 -0
- data/Rakefile +38 -0
- data/ToDo +4 -0
- data/doc/ruby-fftw3.html +116 -0
- data/doc/ruby-fftw3.rd +115 -0
- data/extconf.rb +50 -0
- data/na_fftw3.c +285 -0
- data/test/complexFFT.rb +38 -0
- metadata +92 -0
data/ChangeLog
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Tue Apr 19 2011 T Horinouchi
|
2
|
+
* version 0.4 released (cvs tag ruby-fftw3-0_4)
|
3
|
+
* doc/ruby-fftw3.rd and doc/ruby-fftw3.html : updated
|
4
|
+
* na_fftw3.c: added rb_require("narray"); -- then you do
|
5
|
+
not need to require "narray" separately.
|
6
|
+
* test/complexFFT.rb: removed the first line: require "narray"
|
7
|
+
* LICENSE.txt: changed --> BSD 2-clause license
|
8
|
+
Thu Mar 24 2011 T Horinouchi
|
9
|
+
* version 0.3 released (cvs tag ruby-fftw3-0_3)
|
10
|
+
* LICENSE.txt: added
|
11
|
+
Mon Jun 7 2004 T Horinouchi < T Koshiro
|
12
|
+
* version 0.2 released (cvs tag ruby-fftw3-0_2)
|
13
|
+
* extconf.rb: improved
|
14
|
+
Mon Jun 7 2004 T Horinouchi
|
15
|
+
* renamed to ruby-fftw. Started a new cvs module ruby-fftw3.
|
16
|
+
Fri Nov 20 2003 T Horinouchi
|
17
|
+
* version 0.1 released
|
18
|
+
Thu Nov 20 2003 T Horinouchi
|
19
|
+
* na_fftw3.c: debug of na_fftw3_float
|
20
|
+
Tue Nov 18 2003 T Horinouchi
|
21
|
+
* created. version 0.0
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Ruby-FFTW3 is copyrighted free software by Takeshi Horinouchi and GFD
|
2
|
+
Dennou Club (http://www.gfd-dennou.org/).
|
3
|
+
|
4
|
+
Copyright 2001 (C) Takeshi Horinouchi and GFD Dennou Club
|
5
|
+
(http://www.gfd-dennou.org/) All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
8
|
+
modification, are permitted provided that the following conditions are
|
9
|
+
met:
|
10
|
+
|
11
|
+
1. Redistributions of source code must retain the above copyright
|
12
|
+
notice, this list of conditions and the following disclaimer.
|
13
|
+
|
14
|
+
2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
notice, this list of conditions and the following disclaimer in
|
16
|
+
the documentation and/or other materials provided with the
|
17
|
+
distribution.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY GFD DENNOU CLUB AND CONTRIBUTORS ``AS IS''
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
21
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
22
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
23
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
24
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
The views and conclusions contained in the software and documentation
|
32
|
+
are those of the authors and should not be interpreted as representing
|
33
|
+
official policies, either expressed or implied, of Takeshi Horinouchi
|
34
|
+
and GFD Dennou Club.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
|
3
|
+
NAME = 'ruby-fftw3'
|
4
|
+
VER = '0.4a'
|
5
|
+
|
6
|
+
PKG_FILES = FileList[
|
7
|
+
'**',
|
8
|
+
'doc/**/*',
|
9
|
+
'test/**/*'
|
10
|
+
]
|
11
|
+
|
12
|
+
spec = Gem::Specification.new do |s|
|
13
|
+
s.name = NAME
|
14
|
+
s.version = VER
|
15
|
+
s.authors = ["Takeshi Horinouchi"]
|
16
|
+
s.email = ['eriko@gfd-dennou.org']
|
17
|
+
s.homepage = 'http://www.gfd-dennou.org/arch/ruby/products/ruby-fftw3/'
|
18
|
+
s.licenses = ["Takeshi Horinouchi", "GFD Dennou Club"]
|
19
|
+
s.platform = Gem::Platform::RUBY
|
20
|
+
s.summary = %q{The Ruby interface of the FFTW (ver 3) library}
|
21
|
+
s.description = %q{Fast Fourier Transforms by using FFTW Ver.3}
|
22
|
+
|
23
|
+
s.files = PKG_FILES.to_a
|
24
|
+
#s.require_paths = ['lib']
|
25
|
+
#s.test_files = Dir.glob("test/*")
|
26
|
+
#s.has_rdoc = true
|
27
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.6")
|
28
|
+
s.add_runtime_dependency(%q<narray>, [">= 0"])
|
29
|
+
#s.add_runtime_dependency(%q<narray_miss>, [">= 0"])
|
30
|
+
#s.extra_rdoc_files = ['README']
|
31
|
+
|
32
|
+
s.extensions << "extconf.rb"
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
36
|
+
pkg.gem_spec = spec
|
37
|
+
pkg.need_tar = true
|
38
|
+
end
|
data/ToDo
ADDED
data/doc/ruby-fftw3.html
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
<?xml version="1.0" ?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
6
|
+
<head>
|
7
|
+
<title>ruby-fftw3.rd</title>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<h1><a name="label-0" id="label-0">module NumRu::FFTW3</a></h1><!-- RDLabel: "module NumRu::FFTW3" -->
|
11
|
+
<p>Fast Fourier Transforms by using <a href="http://www.fftw.org">FFTW</a> Ver.3.</p>
|
12
|
+
<p>Takeshi Horinouchi</p>
|
13
|
+
<p>(C) Takeshi Horinouchi / GFD Dennou Club,
|
14
|
+
2003</p>
|
15
|
+
<p>NO WARRANTY</p>
|
16
|
+
<h2><a name="label-1" id="label-1">Features</a></h2><!-- RDLabel: "Features" -->
|
17
|
+
<ul>
|
18
|
+
<li>Uses <a href="http://www.ruby-lang.org/en/raa-list.rhtml?name=NArray">NArray</a>.</li>
|
19
|
+
<li>Multi-dimensional complex FFT. (Real data are coerced to complex).</li>
|
20
|
+
<li>Supports both double and single float transforms.</li>
|
21
|
+
<li>Not normalized as in FFTW</li>
|
22
|
+
</ul>
|
23
|
+
<h2><a name="label-2" id="label-2">Features yet to be introduced</a></h2><!-- RDLabel: "Features yet to be introduced" -->
|
24
|
+
<ul>
|
25
|
+
<li>Sine / cosine transforms</li>
|
26
|
+
<li>User choice of optimization levels (i.e., FFTW_MEASURE etc in
|
27
|
+
addition to FFTW_ESTIMATE).</li>
|
28
|
+
<li>Multi-threaded FFT3 support -- don't know whether it's really feasible.</li>
|
29
|
+
</ul>
|
30
|
+
<h2><a name="label-3" id="label-3">Installation</a></h2><!-- RDLabel: "Installation" -->
|
31
|
+
<ul>
|
32
|
+
<li>Install <a href="http://www.fftw.org">FFTW</a> Ver.3.
|
33
|
+
<ul>
|
34
|
+
<li>NOTE:
|
35
|
+
To activate the single-float transform, you have to install FFTW3 with
|
36
|
+
the single-float compilation, in addition to the default double-float
|
37
|
+
version. This can be done by configuring FFTW3 with
|
38
|
+
the --enable-float option, and install it again. The single-float
|
39
|
+
version will coexist with the double-float version.
|
40
|
+
If you do not install the single-float version, FFT is always done
|
41
|
+
with the double precision, which is not bad if you are not time- and
|
42
|
+
memory-conscious.</li>
|
43
|
+
</ul></li>
|
44
|
+
<li>Install <a href="http://www.ruby-lang.org/en/raa-list.rhtml?name=NArray">NArray</a>.</li>
|
45
|
+
<li><p>Then, install this library as follows (replace "version" with
|
46
|
+
the actual version number):</p>
|
47
|
+
<pre>% tar xvzf fftw3-version.tar.gz
|
48
|
+
% cd fftw3-version
|
49
|
+
% ruby extconf.rb
|
50
|
+
% make
|
51
|
+
% make site-install</pre>
|
52
|
+
<p>Or</p>
|
53
|
+
<pre>% make install</pre>
|
54
|
+
<p>(If you are using Ruby 1.8, make install is the same make site-install.)</p></li>
|
55
|
+
</ul>
|
56
|
+
<h2><a name="label-4" id="label-4">How to use</a></h2><!-- RDLabel: "How to use" -->
|
57
|
+
<p>See the following peice of code. (Install this library and copy and
|
58
|
+
paste the following to the interactive shell irb).</p>
|
59
|
+
<pre>require "numru/fftw3"
|
60
|
+
include NumRu
|
61
|
+
|
62
|
+
na = NArray.float(8,6) # float -> will be corced to complex
|
63
|
+
na[1,1]=1
|
64
|
+
|
65
|
+
# <example 1>
|
66
|
+
fc = FFTW3.fft(na, -1)/na.length # forward 2D FFT and normalization
|
67
|
+
nc = FFTW3.fft(fc, 1) # backward 2D FFT (complex) -->
|
68
|
+
nb = nc.real # should be equal to na except round errors
|
69
|
+
|
70
|
+
# <example 2>
|
71
|
+
fc = FFTW3.fft(na, -1, 0) / na.shape[0] # forward FFT with the first dim
|
72
|
+
|
73
|
+
# <example 3>
|
74
|
+
fc = FFTW3.fft(na, -1, 1) / na.shape[1] # forward FFT with the second dim</pre>
|
75
|
+
<h2><a name="label-5" id="label-5">API Reference</a></h2><!-- RDLabel: "API Reference" -->
|
76
|
+
<h3><a name="label-6" id="label-6">Module methods</a></h3><!-- RDLabel: "Module methods" -->
|
77
|
+
<dl>
|
78
|
+
<dt><a name="label-7" id="label-7"><code>fft(<var>narray</var>, <var>dir</var> [,<var>dim</var>,<var>dim</var>,...])</code></a></dt><!-- RDLabel: "fft" -->
|
79
|
+
<dd>
|
80
|
+
<p>Complex FFT.</p>
|
81
|
+
<p>The 3rd, 4th,... arguments are optional.</p>
|
82
|
+
<p>ARGUMENTS</p>
|
83
|
+
<ul>
|
84
|
+
<li>narray (NArray or NArray-compatible Array) : array to be
|
85
|
+
transformed. If real, coerced to complex before transformation.
|
86
|
+
If narray is single-precision and the single-precision
|
87
|
+
version of FFTW3 is installed (before installing this module),
|
88
|
+
this method does a single-precision transform.
|
89
|
+
Otherwise, a double-precision transform is used.</li>
|
90
|
+
<li>dir (-1 or 1) : forward transform if -1; backward transform if 1.</li>
|
91
|
+
<li>optional 3rd, 4th,... arguments (Integer) : Specifies dimensions
|
92
|
+
to apply FFT. For example, if 0, the first dimension is
|
93
|
+
transformed (1D FFT); If -1, the last dimension is used (1D FFT);
|
94
|
+
If 0,2,4, the first, third, and fifth dimensions
|
95
|
+
are transformed (3D FFT); If entirely omitted, ALL DIMENSIONS
|
96
|
+
ARE SUBJECT TO FFT, so 3D FFT is done with a 3D array.</li>
|
97
|
+
</ul>
|
98
|
+
<p>RETURN VALUE</p>
|
99
|
+
<ul>
|
100
|
+
<li>a complex NArray</li>
|
101
|
+
</ul>
|
102
|
+
<p>NOTE</p>
|
103
|
+
<ul>
|
104
|
+
<li>As in FFTW, return value is NOT normalized. Thus, a consecutive
|
105
|
+
forward and backward transform would multiply the size of
|
106
|
+
data used for transform. You can normalize, for example,
|
107
|
+
the forward transform FFTW.fft(narray, -1, 0, 1)
|
108
|
+
(FFT regarding the first (dim 0) & second (dim 1) dimensions) by
|
109
|
+
dividing with (narray.shape[0]*narray.shape[1]). Likewise,
|
110
|
+
the result of FFTW.fft(narray, -1) (FFT for all dimensions)
|
111
|
+
can be normalized by narray.length.</li>
|
112
|
+
</ul></dd>
|
113
|
+
</dl>
|
114
|
+
|
115
|
+
</body>
|
116
|
+
</html>
|
data/doc/ruby-fftw3.rd
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
=module NumRu::FFTW3
|
2
|
+
|
3
|
+
Fast Fourier Transforms by using ((<FFTW|URL:http://www.fftw.org>)) Ver.3.
|
4
|
+
|
5
|
+
Takeshi Horinouchi
|
6
|
+
|
7
|
+
(C) Takeshi Horinouchi / GFD Dennou Club,
|
8
|
+
2003
|
9
|
+
|
10
|
+
NO WARRANTY
|
11
|
+
|
12
|
+
==Features
|
13
|
+
|
14
|
+
* Uses ((<NArray|URL:http://www.ruby-lang.org/en/raa-list.rhtml?name=NArray>)).
|
15
|
+
* Multi-dimensional complex FFT. (Real data are coerced to complex).
|
16
|
+
* Supports both double and single float transforms.
|
17
|
+
* Not normalized as in FFTW
|
18
|
+
|
19
|
+
==Features yet to be introduced
|
20
|
+
|
21
|
+
* Sine / cosine transforms
|
22
|
+
* User choice of optimization levels (i.e., FFTW_MEASURE etc in
|
23
|
+
addition to FFTW_ESTIMATE).
|
24
|
+
* Multi-threaded FFT3 support -- don't know whether it's really feasible.
|
25
|
+
|
26
|
+
==Installation
|
27
|
+
|
28
|
+
* Install ((<FFTW|URL:http://www.fftw.org>)) Ver.3.
|
29
|
+
|
30
|
+
* NOTE:
|
31
|
+
To activate the single-float transform, you have to install FFTW3 with
|
32
|
+
the single-float compilation, in addition to the default double-float
|
33
|
+
version. This can be done by configuring FFTW3 with
|
34
|
+
the --enable-float option, and install it again. The single-float
|
35
|
+
version will coexist with the double-float version.
|
36
|
+
If you do not install the single-float version, FFT is always done
|
37
|
+
with the double precision, which is not bad if you are not time- and
|
38
|
+
memory-conscious.
|
39
|
+
|
40
|
+
* Install ((<NArray|URL:http://www.ruby-lang.org/en/raa-list.rhtml?name=NArray>)).
|
41
|
+
|
42
|
+
* Then, install this library as follows (replace "version" with
|
43
|
+
the actual version number):
|
44
|
+
|
45
|
+
% tar xvzf fftw3-version.tar.gz
|
46
|
+
% cd fftw3-version
|
47
|
+
% ruby extconf.rb
|
48
|
+
% make
|
49
|
+
% make site-install
|
50
|
+
Or
|
51
|
+
% make install
|
52
|
+
(If you are using Ruby 1.8, make install is the same make site-install.)
|
53
|
+
|
54
|
+
==How to use
|
55
|
+
|
56
|
+
See the following peice of code. (Install this library and copy and
|
57
|
+
paste the following to the interactive shell irb).
|
58
|
+
|
59
|
+
require "numru/fftw3"
|
60
|
+
include NumRu
|
61
|
+
|
62
|
+
na = NArray.float(8,6) # float -> will be corced to complex
|
63
|
+
na[1,1]=1
|
64
|
+
|
65
|
+
# <example 1>
|
66
|
+
fc = FFTW3.fft(na, -1)/na.length # forward 2D FFT and normalization
|
67
|
+
nc = FFTW3.fft(fc, 1) # backward 2D FFT (complex) -->
|
68
|
+
nb = nc.real # should be equal to na except round errors
|
69
|
+
|
70
|
+
# <example 2>
|
71
|
+
fc = FFTW3.fft(na, -1, 0) / na.shape[0] # forward FFT with the first dim
|
72
|
+
|
73
|
+
# <example 3>
|
74
|
+
fc = FFTW3.fft(na, -1, 1) / na.shape[1] # forward FFT with the second dim
|
75
|
+
|
76
|
+
==API Reference
|
77
|
+
|
78
|
+
===Module methods
|
79
|
+
|
80
|
+
---fft(narray, dir [,dim,dim,...])
|
81
|
+
|
82
|
+
Complex FFT.
|
83
|
+
|
84
|
+
The 3rd, 4th,... arguments are optional.
|
85
|
+
|
86
|
+
ARGUMENTS
|
87
|
+
* narray (NArray or NArray-compatible Array) : array to be
|
88
|
+
transformed. If real, coerced to complex before transformation.
|
89
|
+
If narray is single-precision and the single-precision
|
90
|
+
version of FFTW3 is installed (before installing this module),
|
91
|
+
this method does a single-precision transform.
|
92
|
+
Otherwise, a double-precision transform is used.
|
93
|
+
* dir (-1 or 1) : forward transform if -1; backward transform if 1.
|
94
|
+
* optional 3rd, 4th,... arguments (Integer) : Specifies dimensions
|
95
|
+
to apply FFT. For example, if 0, the first dimension is
|
96
|
+
transformed (1D FFT); If -1, the last dimension is used (1D FFT);
|
97
|
+
If 0,2,4, the first, third, and fifth dimensions
|
98
|
+
are transformed (3D FFT); If entirely omitted, ALL DIMENSIONS
|
99
|
+
ARE SUBJECT TO FFT, so 3D FFT is done with a 3D array.
|
100
|
+
|
101
|
+
RETURN VALUE
|
102
|
+
* a complex NArray
|
103
|
+
|
104
|
+
NOTE
|
105
|
+
* As in FFTW, return value is NOT normalized. Thus, a consecutive
|
106
|
+
forward and backward transform would multiply the size of
|
107
|
+
data used for transform. You can normalize, for example,
|
108
|
+
the forward transform FFTW.fft(narray, -1, 0, 1)
|
109
|
+
(FFT regarding the first (dim 0) & second (dim 1) dimensions) by
|
110
|
+
dividing with (narray.shape[0]*narray.shape[1]). Likewise,
|
111
|
+
the result of FFTW.fft(narray, -1) (FFT for all dimensions)
|
112
|
+
can be normalized by narray.length.
|
113
|
+
|
114
|
+
|
115
|
+
|
data/extconf.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "rubygems" unless defined?(Gem)
|
2
|
+
require "mkmf"
|
3
|
+
|
4
|
+
#dir_config('narray',$sitearchdir,$sitearchdir)
|
5
|
+
hoge = Gem::GemPathSearcher.new.find("narray")
|
6
|
+
narray_fullname = hoge.full_name
|
7
|
+
narray_installpath = hoge.installation_path
|
8
|
+
narray_include = "#{narray_installpath}/gems/#{narray_fullname}/"
|
9
|
+
narray_lib = "#{narray_installpath}/gems/#{narray_fullname}/"
|
10
|
+
dir_config('narray',narray_include,narray_lib)
|
11
|
+
|
12
|
+
dir_config('fftw3','/usr/local')
|
13
|
+
|
14
|
+
if ( ! ( have_header("narray.h") && have_header("narray_config.h") ) ) then
|
15
|
+
print <<-EOS
|
16
|
+
** configure error **
|
17
|
+
Header narray.h or narray_config.h is not found. If you have these files in
|
18
|
+
/narraydir/include, try the following:
|
19
|
+
|
20
|
+
% ruby extconf.rb --with-narray-include=/narraydir/include
|
21
|
+
|
22
|
+
EOS
|
23
|
+
exit(-1)
|
24
|
+
end
|
25
|
+
|
26
|
+
if ( ! ( have_header("fftw3.h") && have_library("fftw3") ) ) then
|
27
|
+
print <<EOS
|
28
|
+
** configure error **
|
29
|
+
Header fftw3.h or the compiled fftw3 library is not found.
|
30
|
+
If you have the library installed under /fftw3dir (that is, fftw3.h is
|
31
|
+
in /fftw3dir/include and the library in /fftw3dir/lib/),
|
32
|
+
try the following:
|
33
|
+
|
34
|
+
% ruby extconf.rb --with-fftw3-dir=/fftw3dir
|
35
|
+
|
36
|
+
Alternatively, you can specify the two directory separately
|
37
|
+
with --with-fftw3-include and --with-fftw3-lib.
|
38
|
+
EOS
|
39
|
+
exit(-1)
|
40
|
+
end
|
41
|
+
|
42
|
+
if have_library("fftw3f")
|
43
|
+
$CFLAGS += ' -DFFTW3_HAS_SINGLE_SUPPORT'
|
44
|
+
end
|
45
|
+
|
46
|
+
if /cygwin|mingw/ =~ RUBY_PLATFORM
|
47
|
+
have_library("narray") || raise("ERROR: narray library is not found")
|
48
|
+
end
|
49
|
+
|
50
|
+
create_makefile("numru/fftw3")
|
data/na_fftw3.c
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
/*
|
2
|
+
na_fftw3.c
|
3
|
+
|
4
|
+
FFT using FFTW Ver.3 (www.fftw.org)
|
5
|
+
|
6
|
+
(C) Takeshi Horinouchi
|
7
|
+
NO WARRANTY.
|
8
|
+
|
9
|
+
*/
|
10
|
+
|
11
|
+
#include <ruby.h>
|
12
|
+
#include "narray.h"
|
13
|
+
#include <fftw3.h>
|
14
|
+
|
15
|
+
VALUE rb_mFFTW3;
|
16
|
+
VALUE mNumRu;
|
17
|
+
|
18
|
+
static VALUE
|
19
|
+
#ifdef FFTW3_HAS_SINGLE_SUPPORT
|
20
|
+
na_fftw3_double(int argc, VALUE *argv, VALUE self)
|
21
|
+
/* to be called by na_fftw3 */
|
22
|
+
#else
|
23
|
+
na_fftw3(int argc, VALUE *argv, VALUE self)
|
24
|
+
/* to be called directly */
|
25
|
+
#endif
|
26
|
+
{
|
27
|
+
VALUE val, vdir;
|
28
|
+
struct NARRAY *a1, *a2;
|
29
|
+
int i, dir, *shape, *bucket;
|
30
|
+
fftw_plan p;
|
31
|
+
fftw_complex *in, *out;
|
32
|
+
volatile VALUE v1, v2;
|
33
|
+
|
34
|
+
if (argc<2){
|
35
|
+
rb_raise(rb_eArgError, "Usage: fftw(narray, direction [,dim0,dim1,...])");
|
36
|
+
}
|
37
|
+
val = argv[0];
|
38
|
+
vdir = argv[1];
|
39
|
+
|
40
|
+
dir = NUM2INT(vdir);
|
41
|
+
if ( dir != 1 && dir != -1 ){
|
42
|
+
rb_raise(rb_eArgError, "direction should be 1 or -1");
|
43
|
+
}
|
44
|
+
v1 = na_cast_object(val, NA_DCOMPLEX);
|
45
|
+
GetNArray(v1,a1);
|
46
|
+
v2 = na_make_object( NA_DCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) );
|
47
|
+
GetNArray(v2,a2);
|
48
|
+
|
49
|
+
shape = ALLOCA_N(int, a2->rank);
|
50
|
+
for (i=0; i<a2->rank; i++){
|
51
|
+
shape[i] = a2->shape[a2->rank-1-i];
|
52
|
+
}
|
53
|
+
in = (fftw_complex*)a1->ptr;
|
54
|
+
out = (fftw_complex*)a2->ptr;
|
55
|
+
|
56
|
+
if (argc==2) {
|
57
|
+
/* apply FFT to all dimensions */
|
58
|
+
p = fftw_plan_dft( a2->rank, shape,
|
59
|
+
in, out, dir, FFTW_ESTIMATE );
|
60
|
+
} else {
|
61
|
+
/* apply FFT to selected dimensions (by using the Guru interface) */
|
62
|
+
{ /* introduce a new scope for additonal local variables */
|
63
|
+
int fft_rank, howmany_rank, ib, j, jf, je, dim;
|
64
|
+
fftw_iodim *fft_dims, *howmany_dims;
|
65
|
+
int *dimids;
|
66
|
+
fft_rank = argc - 2;
|
67
|
+
fft_dims = ALLOCA_N(fftw_iodim, fft_rank);
|
68
|
+
dimids = ALLOCA_N(int, fft_rank);
|
69
|
+
howmany_rank = fft_rank + 1;
|
70
|
+
howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank);
|
71
|
+
|
72
|
+
for (i=2;i<argc;i++){
|
73
|
+
dim = NUM2INT(argv[i]);
|
74
|
+
if (dim<0) dim += a2->rank; /* negative: count from the end */
|
75
|
+
if (dim<0 || dim>=a2->rank){
|
76
|
+
rb_raise(rb_eArgError, "dimension < 0 or >= rank");
|
77
|
+
}
|
78
|
+
dimids[i-2] = a2->rank - 1 - dim;
|
79
|
+
if ( i>2 && dimids[i-2] == dimids[i-3] ){
|
80
|
+
rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
/* bukcet sort in increasing order */
|
85
|
+
bucket = ALLOCA_N(int,a2->rank);
|
86
|
+
for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
|
87
|
+
for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
|
88
|
+
for(j=0,i=0; j<a2->rank; j++) {
|
89
|
+
if (bucket[j]==1){
|
90
|
+
dimids[i] = j;
|
91
|
+
i++;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
for(j=0; j<fft_rank; j++){
|
96
|
+
fft_dims[j].n = shape[ dimids[j] ];
|
97
|
+
fft_dims[j].is = 1;
|
98
|
+
for (i=dimids[j]+1 ; i<a2->rank ; i++){
|
99
|
+
fft_dims[j].is *= shape[i];
|
100
|
+
}
|
101
|
+
fft_dims[j].os = fft_dims[j].is;
|
102
|
+
/* printf("fft_ %d n:%d is:%d\n",j,
|
103
|
+
fft_dims[j].n,fft_dims[j].is);*/
|
104
|
+
}
|
105
|
+
for(j=0; j<=fft_rank; j++){
|
106
|
+
howmany_dims[j].n = 1;
|
107
|
+
jf = (j==0) ? 0 : (dimids[j-1]+1) ;
|
108
|
+
je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
|
109
|
+
for (i=jf; i<je; i++){
|
110
|
+
howmany_dims[j].n *= shape[i];
|
111
|
+
}
|
112
|
+
howmany_dims[j].is = 1;
|
113
|
+
if (j<fft_rank){
|
114
|
+
for (i=dimids[j]; i<a2->rank; i++){
|
115
|
+
howmany_dims[j].is *= shape[i];
|
116
|
+
}
|
117
|
+
}
|
118
|
+
howmany_dims[j].os = howmany_dims[j].is;
|
119
|
+
/* printf("how_ %d n:%d is:%d\n",j,
|
120
|
+
howmany_dims[j].n,howmany_dims[j].is); */
|
121
|
+
}
|
122
|
+
|
123
|
+
p = fftw_plan_guru_dft( fft_rank, fft_dims,
|
124
|
+
howmany_rank, howmany_dims,
|
125
|
+
in, out, dir, FFTW_ESTIMATE );
|
126
|
+
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
fftw_execute(p);
|
131
|
+
fftw_destroy_plan(p);
|
132
|
+
|
133
|
+
return v2;
|
134
|
+
}
|
135
|
+
|
136
|
+
#ifdef FFTW3_HAS_SINGLE_SUPPORT
|
137
|
+
|
138
|
+
/* sourse code generation of na_fftw3_float:
|
139
|
+
Copy na_fftw3_double, and replace
|
140
|
+
fftw --> fftwf
|
141
|
+
DCOMPLEX --> SCOMPLEX
|
142
|
+
*/
|
143
|
+
static VALUE
|
144
|
+
na_fftw3_float(int argc, VALUE *argv, VALUE self)
|
145
|
+
{
|
146
|
+
VALUE val, vdir;
|
147
|
+
struct NARRAY *a1, *a2;
|
148
|
+
int i, dir, *shape, *bucket;
|
149
|
+
fftwf_plan p;
|
150
|
+
fftwf_complex *in, *out;
|
151
|
+
volatile VALUE v1, v2;
|
152
|
+
|
153
|
+
if (argc<2){
|
154
|
+
rb_raise(rb_eArgError, "Usage: fftw(narray, direction [,dim0,dim1,...])");
|
155
|
+
}
|
156
|
+
val = argv[0];
|
157
|
+
vdir = argv[1];
|
158
|
+
|
159
|
+
dir = NUM2INT(vdir);
|
160
|
+
if ( dir != 1 && dir != -1 ){
|
161
|
+
rb_raise(rb_eArgError, "direction should be 1 or -1");
|
162
|
+
}
|
163
|
+
v1 = na_cast_object(val, NA_SCOMPLEX);
|
164
|
+
GetNArray(v1,a1);
|
165
|
+
v2 = na_make_object( NA_SCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) );
|
166
|
+
GetNArray(v2,a2);
|
167
|
+
|
168
|
+
shape = ALLOCA_N(int, a2->rank);
|
169
|
+
for (i=0; i<a2->rank; i++){
|
170
|
+
shape[i] = a2->shape[a2->rank-1-i];
|
171
|
+
}
|
172
|
+
in = (fftwf_complex*)a1->ptr;
|
173
|
+
out = (fftwf_complex*)a2->ptr;
|
174
|
+
|
175
|
+
if (argc==2) {
|
176
|
+
/* apply FFT to all dimensions */
|
177
|
+
p = fftwf_plan_dft( a2->rank, shape,
|
178
|
+
in, out, dir, FFTW_ESTIMATE );
|
179
|
+
} else {
|
180
|
+
/* apply FFT to selected dimensions (by using the Guru interface) */
|
181
|
+
{ /* introduce a new scope for additonal local variables */
|
182
|
+
int fft_rank, howmany_rank, ib, j, jf, je, dim;
|
183
|
+
fftw_iodim *fft_dims, *howmany_dims;
|
184
|
+
int *dimids;
|
185
|
+
fft_rank = argc - 2;
|
186
|
+
fft_dims = ALLOCA_N(fftw_iodim, fft_rank);
|
187
|
+
dimids = ALLOCA_N(int, fft_rank);
|
188
|
+
howmany_rank = fft_rank + 1;
|
189
|
+
howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank);
|
190
|
+
|
191
|
+
for (i=2;i<argc;i++){
|
192
|
+
dim = NUM2INT(argv[i]);
|
193
|
+
if (dim<0) dim += a2->rank; /* negative: count from the end */
|
194
|
+
if (dim<0 || dim>=a2->rank){
|
195
|
+
rb_raise(rb_eArgError, "dimension < 0 or >= rank");
|
196
|
+
}
|
197
|
+
dimids[i-2] = a2->rank - 1 - dim;
|
198
|
+
if ( i>2 && dimids[i-2] == dimids[i-3] ){
|
199
|
+
rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
/* bukcet sort in increasing order */
|
204
|
+
bucket = ALLOCA_N(int,a2->rank);
|
205
|
+
for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
|
206
|
+
for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
|
207
|
+
for(j=0,i=0; j<a2->rank; j++) {
|
208
|
+
if (bucket[j]==1){
|
209
|
+
dimids[i] = j;
|
210
|
+
i++;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
for(j=0; j<fft_rank; j++){
|
215
|
+
fft_dims[j].n = shape[ dimids[j] ];
|
216
|
+
fft_dims[j].is = 1;
|
217
|
+
for (i=dimids[j]+1 ; i<a2->rank ; i++){
|
218
|
+
fft_dims[j].is *= shape[i];
|
219
|
+
}
|
220
|
+
fft_dims[j].os = fft_dims[j].is;
|
221
|
+
/* printf("fft_ %d n:%d is:%d\n",j,
|
222
|
+
fft_dims[j].n,fft_dims[j].is);*/
|
223
|
+
}
|
224
|
+
for(j=0; j<=fft_rank; j++){
|
225
|
+
howmany_dims[j].n = 1;
|
226
|
+
jf = (j==0) ? 0 : (dimids[j-1]+1) ;
|
227
|
+
je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
|
228
|
+
for (i=jf; i<je; i++){
|
229
|
+
howmany_dims[j].n *= shape[i];
|
230
|
+
}
|
231
|
+
howmany_dims[j].is = 1;
|
232
|
+
if (j<fft_rank){
|
233
|
+
for (i=dimids[j]; i<a2->rank; i++){
|
234
|
+
howmany_dims[j].is *= shape[i];
|
235
|
+
}
|
236
|
+
}
|
237
|
+
howmany_dims[j].os = howmany_dims[j].is;
|
238
|
+
/* printf("how_ %d n:%d is:%d\n",j,
|
239
|
+
howmany_dims[j].n,howmany_dims[j].is); */
|
240
|
+
}
|
241
|
+
|
242
|
+
p = fftwf_plan_guru_dft( fft_rank, fft_dims,
|
243
|
+
howmany_rank, howmany_dims,
|
244
|
+
in, out, dir, FFTW_ESTIMATE );
|
245
|
+
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
fftwf_execute(p);
|
250
|
+
fftwf_destroy_plan(p);
|
251
|
+
|
252
|
+
return v2;
|
253
|
+
}
|
254
|
+
|
255
|
+
static VALUE
|
256
|
+
na_fftw3(int argc, VALUE *argv, VALUE self)
|
257
|
+
{
|
258
|
+
VALUE val;
|
259
|
+
volatile VALUE v1;
|
260
|
+
struct NARRAY *a1;
|
261
|
+
|
262
|
+
if (argc<2){
|
263
|
+
rb_raise(rb_eArgError, "Usage: fftw(narray, direction [,dim0,dim1,...])");
|
264
|
+
}
|
265
|
+
val = argv[0];
|
266
|
+
v1 = na_to_narray(val);
|
267
|
+
GetNArray(v1,a1);
|
268
|
+
if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){
|
269
|
+
return( na_fftw3_float(argc, argv, self) );
|
270
|
+
} else {
|
271
|
+
return( na_fftw3_double(argc, argv, self) );
|
272
|
+
}
|
273
|
+
|
274
|
+
}
|
275
|
+
|
276
|
+
#endif
|
277
|
+
|
278
|
+
void
|
279
|
+
Init_fftw3()
|
280
|
+
{
|
281
|
+
rb_require("narray");
|
282
|
+
mNumRu = rb_define_module("NumRu");
|
283
|
+
rb_mFFTW3 = rb_define_module_under(mNumRu, "FFTW3");
|
284
|
+
rb_define_module_function(rb_mFFTW3, "fft", na_fftw3, -1);
|
285
|
+
}
|
data/test/complexFFT.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "numru/fftw3"
|
2
|
+
include NumRu
|
3
|
+
|
4
|
+
print "\n**TEST** all dimensions\n\n"
|
5
|
+
|
6
|
+
na = NArray.float(8,4).fill(1) # will be corced to complex
|
7
|
+
na[1,1]=5
|
8
|
+
p na
|
9
|
+
fc = FFTW3.fft(na, -1)/na.length
|
10
|
+
p fc
|
11
|
+
p fc.real
|
12
|
+
|
13
|
+
p FFTW3.fft(fc, 1).real
|
14
|
+
|
15
|
+
print "\n**TEST** single float (treated as single if lib fftw3f exits)\n"
|
16
|
+
print " --- see http://www.fftw.org/fftw3_doc/Precision.html for more info\n\n"
|
17
|
+
na = NArray.sfloat(8,4).indgen!
|
18
|
+
fc = FFTW3.fft(na, -1)/na.length
|
19
|
+
p fc
|
20
|
+
p FFTW3.fft(fc, 1).real
|
21
|
+
|
22
|
+
print "\n**TEST** dimension selection\n\n"
|
23
|
+
|
24
|
+
fc = FFTW3.fft(na, -1, 0)/na.shape[0]
|
25
|
+
p fc
|
26
|
+
p FFTW3.fft(fc, 1, 0).real
|
27
|
+
fc = FFTW3.fft(na, -1, 1)/na.shape[1]
|
28
|
+
p fc
|
29
|
+
p FFTW3.fft(fc, 1, 1).real
|
30
|
+
|
31
|
+
na = NArray.float(4,3,8,3)
|
32
|
+
na[1,1,1,0]= 1
|
33
|
+
p( fc=FFTW3.fft(na, -1, 0,2) / (na.shape[0]*na.shape[2]) )
|
34
|
+
p( fc=FFTW3.fft(na, -1, 1) / na.shape[1] )
|
35
|
+
p( fc=FFTW3.fft(na, -1, 0,1,2) / (na.shape[0]*na.shape[1]*na.shape[2]) )
|
36
|
+
p FFTW3.fft(fc, 1, 0,1,2).real
|
37
|
+
|
38
|
+
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-fftw3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 3517852
|
5
|
+
prerelease: true
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4a
|
9
|
+
version: 0.4a
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Takeshi Horinouchi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-06-28 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: narray
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Fast Fourier Transforms by using FFTW Ver.3
|
35
|
+
email:
|
36
|
+
- eriko@gfd-dennou.org
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions:
|
40
|
+
- extconf.rb
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- Rakefile
|
45
|
+
- LICENSE.txt
|
46
|
+
- ChangeLog
|
47
|
+
- extconf.rb
|
48
|
+
- ToDo
|
49
|
+
- na_fftw3.c
|
50
|
+
- doc/ruby-fftw3.html
|
51
|
+
- doc/ruby-fftw3.rd
|
52
|
+
- test/complexFFT.rb
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://www.gfd-dennou.org/arch/ruby/products/ruby-fftw3/
|
55
|
+
licenses:
|
56
|
+
- Takeshi Horinouchi
|
57
|
+
- GFD Dennou Club
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 1
|
71
|
+
- 6
|
72
|
+
version: "1.6"
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">"
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 25
|
79
|
+
segments:
|
80
|
+
- 1
|
81
|
+
- 3
|
82
|
+
- 1
|
83
|
+
version: 1.3.1
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.7
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: The Ruby interface of the FFTW (ver 3) library
|
91
|
+
test_files: []
|
92
|
+
|