forked from sympy/sympy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
gibbs_phenomenon.py
executable file
·154 lines (119 loc) · 3.6 KB
/
gibbs_phenomenon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
"""
This example illustrates the Gibbs phenomenon.
It also calculates the Wilbraham-Gibbs constant by two approaches:
1) calculating the fourier series of the step function and determining the
first maximum.
2) evaluating the integral for si(pi).
See:
* http://en.wikipedia.org/wiki/Gibbs_phenomena
"""
from sympy import var, sqrt, integrate, conjugate, seterr, Abs, pprint, I, pi,\
sin, cos, sign, Plot, lambdify, Integral, S
#seterr(True)
x = var("x", real=True)
def l2_norm(f, lim):
"""
Calculates L2 norm of the function "f", over the domain lim=(x, a, b).
x ...... the independent variable in f over which to integrate
a, b ... the limits of the interval
Example:
>>> from sympy import Symbol
>>> from gibbs_phenomenon import l2_norm
>>> x = Symbol('x', real=True)
>>> l2_norm(1, (x, -1, 1))
sqrt(2)
>>> l2_norm(x, (x, -1, 1))
sqrt(6)/3
"""
return sqrt(integrate(Abs(f)**2, lim))
def l2_inner_product(a, b, lim):
"""
Calculates the L2 inner product (a, b) over the domain lim.
"""
return integrate(conjugate(a)*b, lim)
def l2_projection(f, basis, lim):
"""
L2 projects the function f on the basis over the domain lim.
"""
r = 0
for b in basis:
r += l2_inner_product(f, b, lim) * b
return r
def l2_gram_schmidt(list, lim):
"""
Orthonormalizes the "list" of functions using the Gram-Schmidt process.
Example:
>>> from sympy import Symbol
>>> from gibbs_phenomenon import l2_gram_schmidt
>>> x = Symbol('x', real=True) # perform computations over reals to save time
>>> l2_gram_schmidt([1, x, x**2], (x, -1, 1))
[sqrt(2)/2, sqrt(6)*x/2, 3*sqrt(10)*(x**2 - 1/3)/4]
"""
r = []
for a in list:
if r == []:
v = a
else:
v = a - l2_projection(a, r, lim)
v_norm = l2_norm(v, lim)
if v_norm == 0:
raise ValueError("The sequence is not linearly independent.")
r.append(v/v_norm)
return r
def integ(f):
return integrate(f, (x, -pi, 0)) + integrate(-f, (x, 0, pi))
def series(L):
"""
Normalizes the series.
"""
r = 0
for b in L:
r += integ(b)*b
return r
def msolve(f, x):
"""
Finds the first root of f(x) to the left of 0.
The x0 and dx below are taylored to get the correct result for our
particular function --- the general solver often overshoots the first
solution.
"""
f = lambdify(x, f)
x0 = -0.001
dx = 0.001
while f(x0 - dx) * f(x0) > 0:
x0 = x0 - dx
x_max = x0 - dx
x_min = x0
assert f(x_max) > 0
assert f(x_min) < 0
for n in range(100):
x0 = (x_max + x_min)/2
if f(x0) > 0:
x_max = x0
else:
x_min = x0
return x0
def main():
#L = l2_gram_schmidt([1, cos(x), sin(x), cos(2*x), sin(2*x)], (x, -pi, pi))
#L = l2_gram_schmidt([1, cos(x), sin(x)], (x, -pi, pi))
# the code below is equivalen to l2_gram_schmidt(), but faster:
L = [1/sqrt(2)]
for i in range(1, 100):
L.append(cos(i*x))
L.append(sin(i*x))
L = [f/sqrt(pi) for f in L]
f = series(L)
print "Fourier series of the step function"
pprint(f)
#Plot(f.diff(x), [x, -5, 5, 3000])
x0 = msolve(f.diff(x), x)
print "x-value of the maximum:", x0
max = f.subs(x, x0).evalf()
print "y-value of the maximum:", max
g = max*pi/2
print "Wilbraham-Gibbs constant :", g.evalf()
print "Wilbraham-Gibbs constant (exact):", \
Integral(sin(x)/x, (x, 0, pi)).evalf()
if __name__ == "__main__":
main()