File: gibbs_phenomenon.py

package info (click to toggle)
sympy 0.7.5-3
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 26,576 kB
  • ctags: 27,948
  • sloc: python: 213,240; xml: 359; makefile: 117; sh: 53; lisp: 4
file content (154 lines) | stat: -rwxr-xr-x 3,690 bytes parent folder | download
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()