Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/functions/spike_function.py
4036 views
1
2
3
import math
4
5
from sage.plot.all import line
6
from sage.modules.free_module_element import vector
7
from sage.rings.all import RDF
8
9
class SpikeFunction:
10
"""
11
Base class for spike functions.
12
13
INPUT:
14
15
- ``v`` - list of pairs (x, height)
16
17
- ``eps`` - parameter that determines approximation to a true spike
18
19
OUTPUT:
20
21
a function with spikes at each point ``x`` in ``v`` with the given height.
22
23
EXAMPLES::
24
25
sage: spike_function([(-3,4),(-1,1),(2,3)],0.001)
26
A spike function with spikes at [-3.0, -1.0, 2.0]
27
28
Putting the spikes too close together may delete some::
29
30
sage: spike_function([(1,1),(1.01,4)],0.1)
31
Some overlapping spikes have been deleted.
32
You might want to use a smaller value for eps.
33
A spike function with spikes at [1.0]
34
35
Note this should normally be used indirectly via
36
``spike_function``, but one can use it directly::
37
38
sage: from sage.functions.spike_function import SpikeFunction
39
sage: S = SpikeFunction([(0,1),(1,2),(pi,-5)])
40
sage: S
41
A spike function with spikes at [0.0, 1.0, 3.141592653589793]
42
sage: S.support
43
[0.0, 1.0, 3.141592653589793]
44
"""
45
def __init__(self, v, eps=0.0000001):
46
"""
47
Initializes base class SpikeFunction.
48
49
EXAMPLES::
50
51
sage: S = spike_function([(-3,4),(-1,1),(2,3)],0.001); S
52
A spike function with spikes at [-3.0, -1.0, 2.0]
53
sage: S.height
54
[4.0, 1.0, 3.0]
55
sage: S.eps
56
0.00100000000000000
57
"""
58
if len(v) == 0:
59
v = [(0,0)]
60
v = [(float(x[0]), float(x[1])) for x in v]
61
v.sort() # makes sure spike locations are in ascending order so we don't need an absolute value to catch overlaps
62
notify = False
63
64
for i in reversed(range(len(v)-1)):
65
if v[i+1][0] - v[i][0] <= eps:
66
notify = True
67
del v[i+1]
68
69
if notify:
70
print "Some overlapping spikes have been deleted."
71
print "You might want to use a smaller value for eps."
72
73
self.v = v
74
self.eps = eps
75
self.support = [float(x[0]) for x in self.v]
76
self.height = [float(x[1]) for x in self.v]
77
78
def __repr__(self):
79
"""
80
String representation of a spike function.
81
82
EXAMPLES::
83
84
sage: spike_function([(-3,4),(-1,1),(2,3)],0.001)
85
A spike function with spikes at [-3.0, -1.0, 2.0]
86
"""
87
return "A spike function with spikes at %s"%self.support
88
89
def _eval(self, x):
90
"""
91
Evaluates spike function. Note that when one calls
92
the function within the tolerance, the return value
93
is the full height at that point.
94
95
EXAMPLES::
96
97
sage: S = spike_function([(0,5)],eps=.001)
98
sage: S(0)
99
5.0
100
sage: S(.1)
101
0.0
102
sage: S(.01)
103
0.0
104
sage: S(.001)
105
5.0
106
"""
107
eps = self.eps
108
x = float(x)
109
for i in range(len(self.support)):
110
z = self.support[i]
111
if z - eps <= x and x <= z + eps:
112
return self.height[i], i
113
return float(0), -1
114
115
def __call__(self, x):
116
"""
117
Called when spike function is used as callable function.
118
119
EXAMPLES::
120
121
sage: S = spike_function([(0,5)],eps=.001)
122
sage: S(0)
123
5.0
124
sage: S(.1)
125
0.0
126
sage: S(.01)
127
0.0
128
sage: S(.001)
129
5.0
130
"""
131
return self._eval(x)[0]
132
133
def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds):
134
"""
135
Plot of (absolute values of) Fast Fourier Transform of
136
the spike function with given number of samples.
137
138
EXAMPLES::
139
140
sage: S = spike_function([(-3,4),(-1,1),(2,3)]); S
141
A spike function with spikes at [-3.0, -1.0, 2.0]
142
sage: P = S.plot_fft_abs(8)
143
sage: p = P[0]; p.ydata
144
[5.0, 5.0, 3.367958691924177, 3.367958691924177, 4.123105625617661, 4.123105625617661, 4.759921664218055, 4.759921664218055]
145
"""
146
w = self.vector(samples = samples, xmin=xmin, xmax=xmax)
147
xmin, xmax = self._ranges(xmin, xmax)
148
z = w.fft()
149
k = vector(RDF, [abs(z[i]) for i in range(int(len(z)/2))])
150
return k.plot(xmin=0, xmax=1, **kwds)
151
152
def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds):
153
"""
154
Plot of (absolute values of) Fast Fourier Transform of
155
the spike function with given number of samples.
156
157
EXAMPLES::
158
159
sage: S = spike_function([(-3,4),(-1,1),(2,3)]); S
160
A spike function with spikes at [-3.0, -1.0, 2.0]
161
sage: P = S.plot_fft_arg(8)
162
sage: p = P[0]; p.ydata
163
[0.0, 0.0, -0.211524990023434..., -0.211524990023434..., 0.244978663126864..., 0.244978663126864..., -0.149106180027477..., -0.149106180027477...]
164
"""
165
w = self.vector(samples = samples, xmin=xmin, xmax=xmax)
166
xmin, xmax = self._ranges(xmin, xmax)
167
z = w.fft()
168
k = vector(RDF, [(z[i]).arg() for i in range(int(len(z)/2))])
169
return k.plot(xmin=0, xmax=1, **kwds)
170
171
def vector(self, samples=2**16, xmin=None, xmax=None):
172
"""
173
Creates a sampling vector of the spike function in question.
174
175
EXAMPLES::
176
177
sage: S = spike_function([(-3,4),(-1,1),(2,3)],0.001); S
178
A spike function with spikes at [-3.0, -1.0, 2.0]
179
sage: S.vector(16)
180
(4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
181
"""
182
v = vector(RDF, samples) # creates vector of zeros of length 2^16
183
xmin, xmax = self._ranges(xmin, xmax)
184
delta = (xmax - xmin)/samples
185
w = int(math.ceil(self.eps/delta))
186
for i in range(len(self.support)):
187
x = self.support[i]
188
if x > xmax:
189
break
190
h = self.height[i]
191
j = int((x - xmin)/delta)
192
for k in range(j, min(samples, j+w)):
193
v[k] = h
194
return v
195
196
def _ranges(self, xmin, xmax):
197
"""
198
Quickly find appropriate plotting interval.
199
200
EXAMPLES::
201
202
sage: S = spike_function([(-1,1),(1,40)])
203
sage: S._ranges(None,None)
204
(-1.0, 1.0)
205
"""
206
width = (self.support[-1] + self.support[0])/float(2)
207
if xmin is None:
208
xmin = self.support[0] - width/float(5)
209
if xmax is None:
210
xmax = self.support[-1] + width/float(5)
211
if xmax <= xmin:
212
xmax = xmin + 1
213
return xmin, xmax
214
215
def plot(self, xmin=None, xmax=None, **kwds):
216
"""
217
Special fast plot method for spike functions.
218
219
EXAMPLES::
220
221
sage: S = spike_function([(-1,1),(1,40)])
222
sage: P = plot(S)
223
sage: P[0]
224
Line defined by 8 points
225
"""
226
v = []
227
xmin, xmax = self._ranges(xmin, xmax)
228
x = xmin
229
eps = self.eps
230
while x < xmax:
231
y, i = self._eval(x)
232
v.append( (x, y) )
233
if i != -1:
234
x0 = self.support[i] + eps
235
v.extend([(x0,y), (x0,0)])
236
if i+1 < len(self.support):
237
x = self.support[i+1] - eps
238
v.append( (x, 0) )
239
else:
240
x = xmax
241
v.append( (xmax, 0) )
242
else:
243
new_x = None
244
for j in range(len(self.support)):
245
if self.support[j] - eps > x:
246
new_x = self.support[j] - eps
247
break
248
if new_x is None:
249
new_x = xmax
250
v.append( (new_x, 0) )
251
x = new_x
252
L = line(v, **kwds)
253
L.xmin(xmin-1); L.xmax(xmax)
254
return L
255
256
257
258
spike_function = SpikeFunction
259
260