diff --git a/semester3/numcs/numcs-summary.pdf b/semester3/numcs/numcs-summary.pdf index adfdf8c..50b7e24 100644 Binary files a/semester3/numcs/numcs-summary.pdf and b/semester3/numcs/numcs-summary.pdf differ diff --git a/semester3/numcs/parts/01_interpolation/00_polynomial/00_intro.tex b/semester3/numcs/parts/01_interpolation/00_polynomial/00_intro.tex index 49c57e4..92731e4 100644 --- a/semester3/numcs/parts/01_interpolation/00_polynomial/00_intro.tex +++ b/semester3/numcs/parts/01_interpolation/00_polynomial/00_intro.tex @@ -12,12 +12,13 @@ Die $x_i$ heissen Stützstellen/Knoten, für welche $\tilde{f}(x_i) = y_i$ gelte \quad x_i, y_i \in \mathbb{R} \end{align*} -Normalerweise stellt $f$ eine echte Messung dar, d.h. macht es Sinn anzunehmen dass $f$ glatt ist. +Normalerweise stellt $f$ eine echte Messung dar, d.h. es macht Sinn anzunehmen dass $f$ glatt ist. Die informelle Problemstellung oben lässt sich durch Vektorräume formalisieren: -$f \in \mathcal{V}$, wobei $\mathcal{V}$ ein Vektorraum mit $\dim(\mathcal{V}) = \infty$ ist. \\ -Wir suchen d.h. $\tilde{f}$ in einem Unterraum $\mathcal{V}_n$ mit endlicher $\dim(\mathcal{V}_n) = n$. +$f \in \mathcal{V}$, wobei $\mathcal{V}$ ein Vektorraum mit $\dim(\mathcal{V}) = \infty$ ist. + +Wir suchen also $\tilde{f}$ in einem Unterraum $\mathcal{V}_n$ mit endlicher $\dim(\mathcal{V}_n) = n$. Sei $B_n = \{b_1,\ldots,b_n\}$ eine Basis für $\mathcal{V}_n$. Dann lässt sich der Bezug zwischen $f$ und $\tilde{f} = f_n(x)$ so ausdrücken: \begin{align*} @@ -26,7 +27,7 @@ Dann lässt sich der Bezug zwischen $f$ und $\tilde{f} = f_n(x)$ so ausdrücken: \setLabelNumber{all}{1} \inlineremark Unterräume $\mathcal{V}_n$ existieren nicht nur für Polynome, wir beschränken uns aber auf $b_j(x) = x^{i-1}$. -Andere Möglichkeiten: $b_j = \cos((j-1)\cos^-1(x))$ \textit{(Chebyshev)} oder $b_j = e^{i2\pi j x}$ \textit{(Trigonometrisch)} +Andere Möglichkeiten: $b_j = \cos((j-1)\cos^{-1}(x))$ \textit{(Chebyshev)} oder $b_j = e^{i2\pi j x}$ \textit{(Trigonometrisch)} \fancytheorem{Peano} $f$ stetig $\implies \exists p(x)$ welches $f$ in $||\cdot||_\infty$ beliebig gut approximiert. diff --git a/semester3/numcs/parts/01_interpolation/00_polynomial/03_lagrange-and-barzycentric-formula.tex b/semester3/numcs/parts/01_interpolation/00_polynomial/03_lagrange-and-barzycentric-formula.tex index 55c354f..800d274 100644 --- a/semester3/numcs/parts/01_interpolation/00_polynomial/03_lagrange-and-barzycentric-formula.tex +++ b/semester3/numcs/parts/01_interpolation/00_polynomial/03_lagrange-and-barzycentric-formula.tex @@ -52,35 +52,35 @@ Man berechnet die baryzentrischen Gewichte $\lambda_k$ folgendermassen: oder das ganze mithilfe von Numpy: \begin{code}{python} def barycentric_weights(x: np.ndarray) -> np.ndarray: - n = len(x) - # Initialize to zeros - barweight = np.ones(n) - for k in range(n): - # Vectorized differences between $x_k$ and all $x$s - differences = x[k] - x - # Remove the $k$-th element (and handle edge cases for $k = 0$ and $k = n - 1$) - if k < n - 1 and k > 0: - diff_processed = np.concatenate((differences[:k], differences[(k + 1) :])) - barweight[k] = 1 / np.prod(diff_processed) - elif k == 0: - barweight[k] = 1 / np.prod(differences[1:]) - else: - barweight[k] = 1 / np.prod(differences[:k]) - return barweight + n = len(x) + # Initialize to zeros + barweight = np.ones(n) + for k in range(n): + # Vectorized differences between $x_k$ and all $x$s + differences = x[k] - x + # Remove the $k$-th element (and handle edge cases for $k = 0$ and $k = n - 1$) + if k < n - 1 and k > 0: + diff_processed = np.concatenate((differences[:k], differences[(k + 1) :])) + barweight[k] = 1 / np.prod(diff_processed) + elif k == 0: + barweight[k] = 1 / np.prod(differences[1:]) + else: + barweight[k] = 1 / np.prod(differences[:k]) + return barweight \end{code} Gleiche funktion, etwas kürzer: \begin{code}{python} def barycentric_weights(x: np.ndarray) -> np.ndarray: - n = len(x) - w = np.ones(n) # = barweight - # Compute the (non-inverted) product, avoiding case (x[i] - x[i]) = 0 - for i in range(0, n, 1): - if (i-1 > 0): w[0:(i-1)] *= (x[0:(i-1)] - x[i]) - if (i+1 < n): w[i+1:n] *= (x[i+1:n] - x[i]) - # Invert all at once - return 1/w + n = len(x) + w = np.ones(n) # = barweight + # Compute the (non-inverted) product, avoiding case (x[i] - x[i]) = 0 + for i in range(0, n, 1): + if (i-1 > 0): w[0:(i-1)] *= (x[0:(i-1)] - x[i]) + if (i+1 < n): w[i+1:n] *= (x[i+1:n] - x[i]) + # Invert all at once + return 1/w \end{code} Mit dem können wir dann ein Polynom mit der baryzentrischen Interpolationsformel interpolieren: @@ -102,32 +102,33 @@ Eine weitere Anwendung der Formel ist als Ausganspunkt für die Spektralmethode \begin{code}{python} def interp_barycentric( - data_point_x: np.ndarray, - data_point_y: np.ndarray, - barweight: np.ndarray, - x: np.ndarray + data_point_x: np.ndarray, + data_point_y: np.ndarray, + barweight: np.ndarray, + x: np.ndarray ): - p_x = np.zeros_like(x) - n = data_point_x.shape[0] + p_x = np.zeros_like(x) + n = data_point_x.shape[0] - for i in range(x.shape[0]): - # Separate sums to divide in the end - upper_sum = 0 - lower_sum = 0 - for k in range(n): - frac = barweight[k] / (x[i] - data_point_x[k]) - upper_sum += frac * data_point_y[k] - lower_sum += frac - p_x[i] = upper_sum / lower_sum + for i in range(x.shape[0]): + # Separate sums to divide in the end + upper_sum = 0 + lower_sum = 0 + for k in range(n): + frac = barweight[k] / (x[i] - data_point_x[k]) + upper_sum += frac * data_point_y[k] + lower_sum += frac + p_x[i] = upper_sum / lower_sum - return p_x + return p_x \end{code} % ──────────────────────────────────────────────────────────────────── \newpage \subsubsection{Fehler} -Falls an den Stützstellen $x_i$ durch beispielsweise ungenaue Messungen unpräzise Werte $\tilde{y_i}$ haben, so entsteht logischerweise auch ein unpräzises Polynom $\tilde{p}(x)$. +Falls wir an den Stützstellen $x_i$ durch beispielsweise ungenaue Messungen unpräzise Werte $\tilde{y_i}$ haben, +so entsteht logischerweise auch ein unpräzises Polynom $\tilde{p}(x)$. Verglichen in der Lagrange-Basis zum korrekten Interpolationspolynom $p(x)$ ergibt sich folgender Fehler: \begin{align*} |p(x) - \tilde{p}(x)| = \left| \sum_{i = 0}^{n} (y_i - \tilde{y_i}) l_i(x) \right| \leq \max_{i = 0, \ldots, n} |y_i - \tilde{y_i}| \cdot \sum_{i = 0}^{n} |l_i(x)| diff --git a/semester3/numcs/parts/01_interpolation/01_trigonometric/01_dft/02_fftshift.tex b/semester3/numcs/parts/01_interpolation/01_trigonometric/01_dft/02_fftshift.tex index 41408d3..2c0f4b0 100644 --- a/semester3/numcs/parts/01_interpolation/01_trigonometric/01_dft/02_fftshift.tex +++ b/semester3/numcs/parts/01_interpolation/01_trigonometric/01_dft/02_fftshift.tex @@ -1,8 +1,8 @@ \subsubsection{DFT in Numpy} -Sei $y$ in der Standardbasis, und $c = \mathcal{F}_N(y)$, also $y$ in der trig. Basis. +Sei $y$ in der Standardbasis, und $c = \mathcal{F}_N(y)$, also $y$ in der trigonometrischen Basis. \begin{align*} - c = F_N \times y = \texttt{fft}(y)\quad \text{\textit{(DFT in numpy)}} & y = \frac{1}{N}F_N^Hc = \texttt{ifft}(c)\quad \textit{(Inverse DFT in numpy)} + c = F_N \times y = \texttt{fft}(y)\quad \text{\textit{(DFT in numpy)}} & & y = \frac{1}{N}F_N^Hc = \texttt{ifft}(c)\quad \textit{(Inverse DFT in numpy)} \end{align*} Um zur ursprünglichen Darstellung des trig. Polynoms zurück zu kommen, müssen wir die Koeffizienten umsortieren: \\ diff --git a/semester3/numcs/parts/01_interpolation/01_trigonometric/04_error-estimation.tex b/semester3/numcs/parts/01_interpolation/01_trigonometric/04_error-estimation.tex index b984429..b31e2e9 100644 --- a/semester3/numcs/parts/01_interpolation/01_trigonometric/04_error-estimation.tex +++ b/semester3/numcs/parts/01_interpolation/01_trigonometric/04_error-estimation.tex @@ -93,6 +93,7 @@ wie in der untenstehenden Abbildung \ref{fig:aliasing} zu sehen: \caption{Aliasing für $f(t) = \cos(2\pi \cdot 19t)$. (Abbildung 3.5.10 aus dem Vorlesungsdokument von Prof. V. Gradinaru, Seite 100)} \label{fig:aliasing} \end{figure} + Für unser Signal bedeutet das also, dass wir eine Art Verzerrung auf der Aufnahme haben, oder für Autoräder, dass es so scheint, als würden sich die Räder rückwärts drehen. \begin{theorem}[]{Fehlerabschätzung} diff --git a/semester3/numcs/parts/01_interpolation/01_trigonometric/05_dft-chebyshev.tex b/semester3/numcs/parts/01_interpolation/01_trigonometric/05_dft-chebyshev.tex index f8baa2e..15b14bf 100644 --- a/semester3/numcs/parts/01_interpolation/01_trigonometric/05_dft-chebyshev.tex +++ b/semester3/numcs/parts/01_interpolation/01_trigonometric/05_dft-chebyshev.tex @@ -47,7 +47,7 @@ Auf Seite 102 im Skript findet sich auch eine effiziente Implementation dessen. \inlineremark Die Formel in Satz 2.4.16 (und in der eben erwähnten Implementierung) sind nichts anderes als eine Version der DCT (Discrete Cosine Transform). Dies ist eine günstigere, aber beschränktere Variante der DFT, mit der nur reellwertige, gerade Funktionen interpoliert werden können. -\innumpy benutzen wir \texttt{scipy.fft.dct}. Dazu müssen die Mesungen in den Punkten $x_j = \cos\left( (j + 0.5) \cdot \frac{\pi}{N} \right)$ +\innumpy benutzen wir \texttt{scipy.fft.dct}. Dazu müssen die Mesungen in den Punkten $x_j = \cos\left( (j + 0.5) \cdot \frac{\pi}{N} \right)$ sein. \inlineremark Die Chebyshev-Koeffizienten $c_j$ können folgendermassen berechnet werden: \rmvspace