Interpolation

4.1.2. Interpolation#

Hide code cell source
import numpy as np
np.set_printoptions(precision=2, linewidth=65)

import matplotlib.pyplot as plt
plt.rc('figure', dpi=150)

import seaborn as sns
sns.set()
sns.set_style('ticks')
sns.set_context("notebook", font_scale=1.2, rc={"lines.linewidth": 1.2})

import scipy

Bei der Bildung der Ober- und Untersumme wurde die zu integrierende Funktion durch einen konstanten Wert in den Teilintervallen zwischen den Stützstellen angenähert. Eine genauere Berechnung des Integrals kann durch eine bessere Interpolation erfolgen. Dazu eignen sich Polynome, da diese leicht zu Integrieren sind.

Trapezregel#

Die Trapezregel beruht auf der Annäherung der zu integrierenden Funktion durch Geraden, d.h. Polynome vom Grad 1, auf den Teilintervallen. Die Approximation des Integralwertes ergibt sich entsprechend aus den Flächeninhalten der so entstandenen Trapeze.

Wie im vorhergehenden Kapitel wird das Verfahren anhand folgender Funktion demonstriert

\[ \sf I = \int_0^2\sin(3x) + 2x \ dx \]
def fkt(x):
    return np.sin(3*x) + 2*x

# Daten für die Visualisierung
x = np.linspace(0, 2, 100)
y = fkt(x)

# Exakte Lösung
I_exakt = (-1/3*np.cos(3*2) + 2**2) - (-1/3)

Bildung der Stützpunkte:

n = 5

xi = np.linspace(0, 2, n)
yi = fkt(xi)

Zunächst erfolgt noch die Visualisierung des Verfahrens.

plt.plot(x, y, label='Funktion')
plt.scatter(xi, yi, label='Stützstellen', c='C3')
plt.plot(xi, yi, label='Approximation', c='C1')

plt.vlines(xi, ymin=0, ymax=yi, color='C1', alpha=0.3)

plt.grid()
plt.legend();
../../../_images/485334a94a4cc73d87d04656a2eab5001dd9601bd24a2f4078fda60ac8217dbf.png

Die Integration selbst kann mittels der Funktion scipy.integrate.trapz ausgeführt werden.

res = scipy.integrate.trapz(yi, xi)
print(f"Integralwert mit {n} Stützstellen: {res:.4f}")
Integralwert mit 5 Stützstellen: 4.0107
/tmp/ipykernel_6250/2607466481.py:1: DeprecationWarning: 'scipy.integrate.trapz' is deprecated in favour of 'scipy.integrate.trapezoid' and will be removed in SciPy 1.14.0
  res = scipy.integrate.trapz(yi, xi)

Der so ermittelte Wert nähert sich dem exakten Wert mit zunehmender Anzahl der Stützstellen.

n_max = 50
ns = np.arange(2, n_max, 1, dtype=int)
tr = np.zeros(len(ns))

for i, n in enumerate(ns):
    xi = np.linspace(0, 2, n)
    yi = fkt(xi)
    tr[i] = scipy.integrate.trapz(yi, xi)
/tmp/ipykernel_6250/3326232058.py:8: DeprecationWarning: 'scipy.integrate.trapz' is deprecated in favour of 'scipy.integrate.trapezoid' and will be removed in SciPy 1.14.0
  tr[i] = scipy.integrate.trapz(yi, xi)
plt.plot(ns, tr)
plt.axhline(y=I_exakt, color='C3', alpha=0.3)

plt.xlabel('Anzahl der Stützstellen n')
plt.ylabel('Integralwert')

plt.grid();
../../../_images/f0e504360b48234a9022884c45888ff045acb44912c596ccdfa1463bfebdd906.png
plt.plot(ns, np.abs(tr-I_exakt))

plt.xlabel('Anzahl der Stützstellen n')
plt.ylabel('Differenz zum exakten Wert')

# plt.xscale('log')
plt.yscale('log')

plt.grid();
../../../_images/97b56fbefa9eff356c6cb49074a5985e4a5d5815d8a588103da2cff7192231f3.png

Simpsonregel#

Die Verwendung eines Polynoms vom zweiten Grad führt zur Simpsonregel. Hierzu wird die Funktion an einem Zwischenwert, mittig im Teilintervall, ausgewertet und zusammen mit den Werten an den Stützstellen zur Bestimmung der Polynomkoeffizienten verwendet.

Anhand des obigen Beispiels wird die Simpsonregel visuell demonstriert.

n = 5

xi = np.linspace(0, 2, n)
yi = fkt(xi)
plt.plot(x, y, label='Funktion')
plt.scatter(xi, yi, label='Stützstellen', c='C3')

# Bestimmung und Plotten der Polynome
for i in range(n-1):
    dx = xi[i+1] - xi[i]
    cx = (xi[i] + xi[i+1]) / 2
    cy = fkt(cx)

    P = np.polyfit([xi[i], cx, xi[i+1]], [yi[i], cy, yi[i+1]], 2)
    
    Px = np.linspace(xi[i], xi[i+1], 20)
    Py = np.polyval(P, Px)
    
    label=None
    if i==0: 
        label='Approximation'
    
    plt.plot(Px, Py, color='C1', label=label)

plt.vlines(xi, ymin=0, ymax=yi, color='C1', alpha=0.3)

plt.grid()
plt.legend();
../../../_images/7d21a5e8fe21cd0777f02aeb48a0e672c30786fe21a5277e09fcc1c34e68f7e8.png

Die Simpsonregel ist bereits in der Funktion scipy.integrate.simps implementiert. Im Folgenden wird nur die Differenz zur Trapezregel demonstriert.

n_max = 50
ns = np.arange(3, n_max, 2, dtype=int)
si = np.zeros(len(ns))
tr = np.zeros(len(ns))

for i, n in enumerate(ns):
    xi = np.linspace(0, 2, n)
    yi = fkt(xi)
    si[i] = scipy.integrate.simps(yi, xi)
    tr[i] = scipy.integrate.trapz(yi, xi)
/tmp/ipykernel_6250/1089908967.py:9: DeprecationWarning: 'scipy.integrate.simps' is deprecated in favour of 'scipy.integrate.simpson' and will be removed in SciPy 1.14.0
  si[i] = scipy.integrate.simps(yi, xi)
/tmp/ipykernel_6250/1089908967.py:10: DeprecationWarning: 'scipy.integrate.trapz' is deprecated in favour of 'scipy.integrate.trapezoid' and will be removed in SciPy 1.14.0
  tr[i] = scipy.integrate.trapz(yi, xi)
plt.plot(ns, np.abs(tr-I_exakt), label='Trapezregel')
plt.plot(ns, np.abs(si-I_exakt), label='Simpsonregel')

plt.xlabel('Anzahl der Stützstellen n')
plt.ylabel('Differenz zum exakten Wert')

# plt.xscale('log')
plt.yscale('log')

plt.legend()
plt.grid();
../../../_images/702b7273ad21ef2a0e4982a298fc144a061207ccd5bd75fb8118d50e08ca237d.png