47. Fourier series: supplemental material#

Executing the following cell loads a non-default css style for the notebook.

import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
from IPython.core.display import HTML
from ipywidgets import interact
from numpy import heaviside as u
from numpy import pi


def css_styling():
    try:
        with open("tma4125.css") as f:
            styles = f.read()
            return HTML(styles)
    except FileNotFoundError:
        pass  # Do nothing


# Comment out next line and execute this cell to restore the default notebook style
css_styling()

We need some boilerplate code for arrays, plotting and nice widgets.

%matplotlib inline

plt.rcParams["figure.figsize"] = [10, 5]

47.1. Examples of Fourier series#

First we define some plotting functions which will visualize the N-th partial sum for a given function f. The examples below show how to use it.

def plot_partial_sum(f, x, S_N, N, title=""):
    y = f(x)
    s_N = S_N(x, N)
    plt.plot(x, y, label="$f$")
    plt.plot(x, s_N, label="$S_N$")
    plt.title(title)
    plt.legend()
    plt.xlabel("x")
    plt.ylabel("$S_N(x)$")
    plt.show()

47.1.1. Example 1: f(x)=|x|#

In Assignment 3, you will show that N-th partial sum of the trigonometric series for the function f(x)=|x| is

SN(f)(x)=π2+n=1N2πn2(1+(1)n)cos(nx)
x = np.linspace(-1.0 * np.pi, 1.0 * np.pi, 1000)  # Interval
f = lambda x: np.abs(x)  # Define f

# Define partial sum


def S_N(x, N):
    s = np.pi / 2.0 * np.ones_like(x)
    for n in range(1, N + 1):
        s += 2 / (np.pi * n**2) * (-1 + (-1) ** n) * np.cos(n * x)
    return s


title = "$f(x) = |x|$"

# Define a helper function
pps = lambda N: plot_partial_sum(f, x, S_N, N, title)
slider = widgets.IntSlider(min=0, max=20, step=1, description="Order N", value=0)
interact(pps, N=slider)
0
<function __main__.<lambda>(N)>

47.1.2. Example 2: f(x)=x#

In Assignment 3, you will show that N-th partial sum of the trigonometric series for the function f(x)=x is

SN(f)(x)=n=1N2n(1)n+1sin(nx)
# Interval
x = np.linspace(-3 * np.pi, 3 * np.pi, 1000)

# Define f
f = lambda x: np.piecewise(
    x,
    [abs(x + 2 * np.pi) < np.pi, abs(x) < np.pi, abs(x - 2 * np.pi) < np.pi],
    [lambda x: x + 2 * np.pi, lambda x: x, lambda x: x - 2 * np.pi],
)


# Define partial sum
def S_N(x, N):
    s = np.pi / 2.0 * np.zeros_like(x)
    for n in range(1, N + 1):
        s += 2.0 / n * (-1) ** (n + 1) * np.sin(n * x)
    return s


title = "$f(x) = x$"

# Define a helper function
pps = lambda N: plot_partial_sum(f, x, S_N, N, title)
interact(pps, N=slider)
0
<function __main__.<lambda>(N)>

47.1.3. Example 2#

The function f is given \begin{equation*} f(x) = \left{ \begin{array}{rl} 1 &\text{ if } 0 < x < \pi, \ -1 &\text{ if } -\pi < x < 0 \end{array} \right. \end{equation*}

It Fourier series is \begin{equation*} f \sim \sum_{n=1}^\infty \dfrac{2}{\pi n} \left( 1 + (-1)^{n+1} \right) \sin(nx) \end{equation*}

# Interval
x = np.linspace(-3 * np.pi, 3 * np.pi, 1000)


# Define f
f = (
    lambda x: -1 * u(x + 3 * pi, 0)
    + 2 * u(x + 2 * pi, 0)
    - 2 * u(x + pi, 0)
    + 2 * u(x, 0)
    - 2 * u(x - pi, 0)
    + 2 * u(x - 2 * pi, 0)
)

# Define partial sum


def S_N(x, N):
    s = np.pi / 2.0 * np.zeros_like(x)
    for n in range(1, N + 1):
        s += 2.0 / (np.pi * n) * (1 + (-1) ** (n + 1)) * np.sin(n * x)
    return s


title = "$f(x)$"

# Define a helper function
pps = lambda N: plot_partial_sum(f, x, S_N, N, title)
slider = widgets.IntSlider(min=0, max=20, step=1, description="Order N", value=0)
interact(pps, N=slider)
0
<function __main__.<lambda>(N)>

47.2. The Dirichlet kernel#

We plot the Dirichlet Kernel DN(x) for various N:

# Note that there is a (removable) singularity at x = 0.
D_N = lambda x, N: np.sin((N + 0.5) * x) / np.sin(0.5 * x)


def plot_dirichlet_kernel(N):
    x = np.linspace(-np.pi, np.pi, 10000)
    y = D_N(x, N)
    plt.plot(x, y)
    plt.title("Dirichlet kernel $D_N$ for various $N$")
    plt.xlabel("x")
    plt.ylabel("$D_N(x)$")
    plt.show()
slider = widgets.IntSlider(min=0, max=10, step=1, description="Order N", value=1)

interact(plot_dirichlet_kernel, N=slider)
1
<function __main__.plot_dirichlet_kernel(N)>
slider = widgets.IntSlider(min=5, max=100, step=5, description="Order N", value=5)

interact(plot_dirichlet_kernel, N=slider)
5
<function __main__.plot_dirichlet_kernel(N)>
%matplotlib notebook
for N in [3, 10, 20]:
    x = np.linspace(-np.pi, np.pi, 10000)
    y = D_N(x, N)
    plt.plot(x, y, label=f"N = {N}")

plt.title("Dirichlet kernel $D_N$ for various $N$")
plt.xlabel("$x$")
plt.ylabel("$D_N(x)$")
plt.legend()
plt.show()