Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/gsl/fft.pyx
4069 views
1
"""
2
Fast Fourier Transforms using GSL.
3
4
5
AUTHORS:
6
William Stein (2006-9) - initial file (radix2)
7
D. Joyner (2006-10) - Minor modifications (from radix2 to general case
8
and some documentation).
9
10
"""
11
12
#*****************************************************************************
13
# Copyright (C) 2006 William Stein <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# This code is distributed in the hope that it will be useful,
18
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
# General Public License for more details.
21
#
22
# The full text of the GPL is available at:
23
#
24
# http://www.gnu.org/licenses/
25
#*****************************************************************************
26
27
include '../ext/stdsage.pxi'
28
29
import sage.plot.all
30
import sage.libs.pari.all
31
from sage.rings.integer import Integer
32
from sage.rings.complex_number import ComplexNumber
33
34
def FastFourierTransform(size, base_ring=None):
35
"""
36
EXAMPLES::
37
38
sage: a = FastFourierTransform(128)
39
sage: for i in range(1, 11):
40
... a[i] = 1
41
... a[128-i] = 1
42
sage: a[:6:2]
43
[(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
44
sage: a.plot().show(ymin=0)
45
sage: a.forward_transform()
46
sage: a.plot().show()
47
"""
48
return FastFourierTransform_complex(int(size))
49
50
FFT = FastFourierTransform
51
52
cdef class FastFourierTransform_base:
53
pass
54
55
cdef class FastFourierTransform_complex(FastFourierTransform_base):
56
57
def __init__(self, size_t n, size_t stride=1):
58
self.n = n
59
self.stride = stride
60
self.data = <double*> sage_malloc(sizeof(double)*(2*n))
61
cdef int i
62
for i from 0 <= i < 2*n:
63
self.data[i] = 0
64
65
def __dealloc__(self):
66
sage_free(self.data)
67
68
def __len__(self):
69
return self.n
70
71
def __setitem__(self, size_t i, xy):
72
# just set real for now
73
if i < 0 or i >= self.n:
74
raise IndexError
75
if isinstance(xy, (tuple, ComplexNumber)):
76
self.data[2*i] = xy[0]
77
self.data[2*i+1] = xy[1]
78
else:
79
self.data[2*i] = xy
80
81
def __getitem__(self, i):
82
if isinstance(i, slice):
83
start, stop, step = i.indices(self.n)
84
return list(self)[start:stop:step]
85
else:
86
if i < 0 or i >= self.n:
87
raise IndexError
88
return self.data[2*i], self.data[2*i+1]
89
90
def __repr__(self):
91
return str(list(self))
92
93
def _plot_polar(self, xmin, xmax, **args):
94
cdef int i
95
v = []
96
97
pari = sage.libs.pari.all.pari
98
point = sage.plot.all.point
99
pi = pari('Pi')
100
s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3.
101
102
for i from xmin <= i < xmax:
103
z = pari('%s + I*%s'%(self.data[2*i], self.data[2*i+1]))
104
mag = z.abs()
105
if mag > 0:
106
arg = z.arg()*s
107
else:
108
arg = 0
109
if i > 0:
110
v.append(point([(i-1, prev_mag), (i,mag)], hue=arg, **args))
111
prev_mag = mag
112
return sum(v)
113
114
def _plot_rect(self, xmin, xmax, **args):
115
cdef int i
116
cdef double pr_x, x, h
117
v = []
118
119
point = sage.plot.all.point
120
121
for i from xmin <= i < xmax:
122
x = self.data[2*i]
123
h = self.data[2*i+1]
124
if i > 0:
125
v.append(point([(i-1, pr_x), (i,x)], hue=h, **args))
126
pr_x = x
127
return sum(v)
128
129
def plot(self, style='rect', xmin=None, xmax=None, **args):
130
"""
131
INPUT:
132
style -- 'rect': height represents real part, color represents imaginary part
133
-- 'polar': height represents absolute value
134
**args -- passed on to the line plotting function.
135
"""
136
if xmin is None:
137
xmin = 0
138
else:
139
xmin = int(xmin)
140
if xmax is None:
141
xmax = self.n
142
else:
143
xmax = int(xmax)
144
if style == 'rect':
145
return self._plot_rect(xmin, xmax, **args)
146
elif style == 'polar':
147
return self._plot_polar(xmin, xmax, **args)
148
else:
149
raise ValueError, "unknown style '%s'"%style
150
151
def forward_transform(self):
152
"""
153
Compute the in-place forward Fourier transform of this data
154
using the Cooley-Tukey algorithm. If the number of sample
155
points in the input is a power of 2 then the function
156
gsl_fft_complex_radix2_forward is automatically called.
157
Otherwise, gsl_fft_complex_forward is called.
158
"""
159
cdef gsl_fft_complex_wavetable * wt
160
cdef gsl_fft_complex_workspace * mem
161
N = Integer(self.n)
162
e = N.exact_log(2)
163
if N==2**e:
164
gsl_fft_complex_radix2_forward(self.data, self.stride, self.n)
165
if N!=2**e:
166
#cdef gsl_fft_complex_wavetable * wt
167
#cdef gsl_fft_complex_workspace * mem
168
mem = gsl_fft_complex_workspace_alloc(self.n)
169
wt = gsl_fft_complex_wavetable_alloc(self.n)
170
gsl_fft_complex_forward(self.data, self.stride, self.n, wt, mem)
171
gsl_fft_complex_workspace_free(mem)
172
gsl_fft_complex_wavetable_free(wt)
173
174
def inverse_transform(self):
175
"""
176
Compute the in-place forward Fourier transform of this data
177
using the Cooley-Tukey algorithm. If the number of sample
178
points in the input is a power of 2 then the function
179
gsl_fft_complex_radix2_inverse is automatically called.
180
Otherwise, gsl_fft_complex_inverse is called.
181
182
EXAMPLES::
183
184
sage: a = FastFourierTransform(125)
185
sage: b = FastFourierTransform(125)
186
sage: for i in range(1, 60): a[i]=1
187
sage: for i in range(1, 60): b[i]=1
188
sage: a.forward_transform()
189
sage: a.inverse_transform()
190
sage: (a.plot()+b.plot())
191
"""
192
cdef gsl_fft_complex_wavetable * wt
193
cdef gsl_fft_complex_workspace * mem
194
N = Integer(self.n)
195
e = N.exact_log(2)
196
if N==2**e:
197
gsl_fft_complex_inverse(self.data, self.stride, self.n, wt, mem)
198
if N!=2**e:
199
mem = gsl_fft_complex_workspace_alloc(self.n)
200
wt = gsl_fft_complex_wavetable_alloc(self.n)
201
gsl_fft_complex_inverse(self.data, self.stride, self.n, wt, mem)
202
gsl_fft_complex_workspace_free(mem)
203
gsl_fft_complex_wavetable_free(wt)
204
205
def backward_transform(self):
206
"""
207
Compute the in-place backwards Fourier transform of this data
208
using the Cooley-Tukey algorithm. This is the same as "inverse"
209
but lacks normalization so that backwards*forwards(f) = n*f.
210
211
EXAMPLES::
212
213
sage: a = FastFourierTransform(125)
214
sage: b = FastFourierTransform(125)
215
sage: for i in range(1, 60): a[i]=1
216
sage: for i in range(1, 60): b[i]=1
217
sage: a.forward_transform()
218
sage: a.backward_transform()
219
sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011)
220
"""
221
cdef gsl_fft_complex_wavetable * wt
222
cdef gsl_fft_complex_workspace * mem
223
N = Integer(self.n)
224
e = N.exact_log(2)
225
if N==2**e:
226
gsl_fft_complex_backward(self.data, self.stride, self.n, wt, mem)
227
if N!=2**e:
228
mem = gsl_fft_complex_workspace_alloc(self.n)
229
wt = gsl_fft_complex_wavetable_alloc(self.n)
230
gsl_fft_complex_backward(self.data, self.stride, self.n, wt, mem)
231
gsl_fft_complex_workspace_free(mem)
232
gsl_fft_complex_wavetable_free(wt)
233
234
cdef class FourierTransform_complex:
235
pass
236
237
cdef class FourierTransform_real:
238
pass
239
240
241
242