Commit 3f0aad80 authored by Hafiz Emin Kosar's avatar Hafiz Emin Kosar
Browse files

- added run instructions to all notebooks

parent a87cce94
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
import ipywidgets as widgets
from ipywidgets import interact, interactive
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
import scipy.special
import scipy.signal
import rwth_nb.plots.mpl_decorations as rwth_plots
from rwth_nb.misc.signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Auto- und Kreuzkorrelationsfunktion von Energiesignalen
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
### Energiesignal
Ein Signal $s(t)$ heißt Energiesignal, wenn seine Signalenergie endlich ist, es gilt also
$$E_s = \int\limits_{-\infty}^\infty |s(t)|^2 \mathrm{d} t < \infty \text{ .}$$
Viele wichtige Signale haben keine endliche Gesamtenergie, z. B. alle periodischen Signale, die Sprungfunktion oder zeitlich nicht begrenzte Zufallssignale. Für Signale mit Dirac-Impulsen ist die Energie nicht definiert.
### Kreuzkorrelationsfunktion
Für zwei Energiesignale $s(t)$ und $g(t)$ kann die *Kreuzkorrelationsfunktion* berechnet werden. Diese zeigt an, wie ähnlich sich zwei Signale bei unterschiedlichen Verschiebungen $\tau$ sind.
$$
\varphi_{sg}^\mathrm{E}(\tau)
= \int\limits_{-\infty}^\infty s^\ast(t) g(t+\tau)\mathrm{d}t
\stackrel{t\rightarrow -t}{=} \int\limits_{-\infty}^\infty s(-t)^\ast g(\tau-t) \mathrm{d} t
= s^\ast(-\tau) \ast g(\tau)
= \left[\varphi_{gs}^\mathrm{E}(-\tau)\right]^\ast
$$
Die Kreuzkorrelationsfunktionen $\varphi_{sg}^\mathrm{E}(\tau)$ und $\varphi_{gs}^\mathrm{E}(\tau)$ sind also zueinander zeitgespiegelt und konjugiert-komplex.
Für die Berechnung der Kreuzkorrelationsfunktion müssen die beiden Signale nicht zwingend Energiesignale sein, es ist ausreichend, dass das Integral berechnet werden kann. Man beachte hier auch die Ähnlichkeit zur Faltung zweier Signale, bei der Berechnung kann entsprechend vorgegangen werden.
### Autokorrelationsfunktion
Die Autokorrelationsfunktion entspricht der Kreuzkorrelationsfunktion, wenn $g(t) = s(t)$ gilt. Sie zeigt an, wie ähnlich ein Signal sich selber bei einer zeitlichen Verschiebung $\tau$ ist
$$
\varphi_{ss}^\mathrm{E}(\tau)
= \int\limits_{-\infty}^\infty s^\ast(t) s(t+\tau)\mathrm{d}t \text{.}
$$
Die Autokorrelationsfunktion besitzt folgende allgemeingültige Eigenschaften:
* Die Autokorrelationsfunktion ist immer eine gerade Funktion.
* Den maximalen Wert nimmt eine Autokorrelationsfunktion für $\tau=0$ an, da in diesem Fall größte Ähnlichkeit vorliegt.
* Das Maximum der Autokorrelationsfunktion eines Energiesignals ist gleich seiner Energie
$$\varphi_{ss}^\mathrm{E}(0)=E_s \text{.}$$
* Bei zeitlich begrenzten Signalen hat die Autokorrelationsfunktion die doppelte Breite des Signals.
%% Cell type:markdown id: tags:
## Interaktive Demo
Die interaktive Demo ermöglicht es, sich die Kreuz- und Autokorrelation für verschiedene Signale anzusehen.
$$
\varphi_{sg}^\mathrm{E}(\tau)
= s^\ast(-\tau) \ast g(\tau)
= g(\tau) \ast s^\ast(-\tau)
= \int\limits_{-\infty}^\infty g(t) s^\ast(t-\tau) \mathrm{d} t
$$
Es ist auch möglich, eine eigene Funktion $s_0(t)$ zu definieren.
%% Cell type:code id: tags:
``` python
s_0 = lambda t: rect(t/2-1/2)*(-t)
```
%% Cell type:code id: tags:
``` python
def correlation(s, g):
# Correlate s and g numerically
return sp.signal.convolve(np.conj(s(-t)),g(t), mode='full')*deltat
fs = 2000 # Samplingrate
(t,deltat) = np.linspace(-8,8, 16*fs, retstep=True) # Zeitachse
(tau,deltatau) = np.linspace(-16,16, 2*len(t)-1, retstep=True) # Korrelation
signal_types = {'Rechteck' : rect,
'Dreieck' : tri,
'Sprungfunktion' : unitstep,
'si-Funktion' : lambda t: si(t*np.pi),
'Exponentialimpuls' : lambda t: unitstep(t)*np.exp(-t),
'Gauß-Signal' : gauss,
'Doppelrechteck' : lambda t: rect(t*2+0.5)-rect(t*2-0.5),
'Rampe' : lambda t: t*rect(t-0.5),
'Versch. Rechteck' : lambda t: -rect(t-0.5),
'Eigene Kreation' : s_0,
}
```
%% Cell type:markdown id: tags:
Wähle Signale für $s(t)$ und $g(t)$ im Drop-Down-Menü aus. Für beide Signale kann auch die Breite $T$ und die Verschiebung $t_0$ angepasst werden. Die jeweiligen Signale werden dann in der nachfolgenden Abbildung angezeigt.
%% Cell type:code id: tags:
``` python
fig0, axs0 = plt.subplots(1, 2, figsize=(8,2))
@widgets.interact(s_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $s(t)$:'),
s_T=widgets.FloatSlider(min=0.5, max=4, value=1, step=.1, description=r'Dehnung T', style=rwth_plots.wdgtl_style),
s_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=rwth_plots.wdgtl_style),
g_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $g(t)$:'),
g_T=widgets.FloatSlider(min=0.5, max=4, value=1, step=.1, description=r'Dehnung T', style=rwth_plots.wdgtl_style),
g_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=rwth_plots.wdgtl_style))
def update_signals(s_type, s_T, s_t0, g_type, g_T, g_t0):
global s, g, phi_sg # reused in second interactive plot
s = lambda t: signal_types[s_type]((t-s_t0)/s_T);
g = lambda t: signal_types[g_type]((t-g_t0)/g_T);
phi_sg = correlation(s, g) # numerical correlation
if not axs0[0].lines: # plot s(t) and g(t)
ax = axs0[0]; ax.plot(t, s(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)$')
ax.set_xlim([-2.9, 2.9]); ax.set_ylim([-1.19, 1.19]); rwth_plots.axis(ax); rwth_plots.grid(ax);
ax = axs0[1]; ax.plot(t, g(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow g(t)$')
ax.set_xlim(axs0[0].get_xlim()); ax.set_ylim(axs0[0].get_ylim()); rwth_plots.axis(ax); rwth_plots.grid(ax);
else: # update lines
axs0[0].lines[0].set_ydata(s(t));
axs0[1].lines[0].set_ydata(g(t));
try: # if convolution figure is already opened, update s(t)
if axs[0].lines:
axs[0].lines[0].set_ydata((g(t)));
rwth_plots.update_ylim(axs[0], np.concatenate((g(t), s(t))), 0.19, 5); rwth_plots.update_ylim(axs[1], phi_sg, 0.19, 5);
update_plot(-2); # update correlation plot
except: pass
rwth_plots.update_ylim(axs0[0], s(t), 0.19, 5); rwth_plots.update_ylim(axs0[1], g(t), 0.19, 5);
```
%% Cell type:markdown id: tags:
In der nachfolgenden Grafik kann für die beiden oben ausgewählten Funktionen nun das Ergebnis der Kreuzkorrelationsfunktion betrachtet werden. Hierfür muss der Schieberegler von links nach rechts geschoben werden. Wenn das Kästchen bei Integrand angeklickt ist, wird die aktuell überlappende Fläche der beiden Funktionen gestrichelt angezeigt. Diese entspricht dem Wert der Kreuzkorrelationsfunktion. Dies kann im unteren Teil der Grafik interaktiv betrachtet werden.
%% Cell type:code id: tags:
``` python
fig, axs=plt.subplots(2, 1, figsize=(8, 8 / rwth_plots.fig_aspect))
@widgets.interact(tau_shft=widgets.FloatSlider(min=-4, max=4, value=-2, step=.1, description=r'Verschiebung $\tau$', style=rwth_plots.wdgtl_style),
show_integrand=widgets.Checkbox(value=True, description='Zeige Integrand', style=rwth_plots.wdgtl_style))
def update_plot(tau_shft, show_integrand=True):
tau_ind = np.where(tau>=tau_shft); tau_ind = tau_ind[0][0]; phi_plot = phi_sg.copy(); phi_plot[tau_ind:] = np.nan; # hide g(t') with t'>t
sg = np.conj(s(t-tau_shft))*g(t) # integrand
if not axs[0].lines: # Call plot() and decorate axes. Usually, these functions take some processing time
ax = axs[0]; ax.plot(t, g(t), 'rwth:blue', label=r'$g(t)$'); # plot g(t)
ax.plot(t, np.conj(s(t-tau_shft)), 'rwth:green', label=r'$s^\ast(t-\tau)$'); # plot s(t-tau)
ax.plot(t, sg, '--', color='rwth:orange', lw=1, label=r'$g(t)s^\ast(t-\tau)$'); # plot integrand
rwth_plots.annotate_xtick(ax, r'$\tau$', tau_shft, -0.1, 'rwth:blue', 15); # mark t on tau axis
ax.fill_between(t, 0, sg, facecolor="none", hatch="//", edgecolor='rwth:black', linewidth=0.0); # hatch common area
ax.set_xlabel(r'$\rightarrow t$');
ax.set_xlim([-4.2,4.2]); rwth_plots.update_ylim(ax, np.concatenate((g(t), s(t))), 0.19, 5);
ax.legend(); rwth_plots.axis(ax); rwth_plots.grid(ax);
ax = axs[1]; ax.plot(tau, phi_plot); # plot phi_sg(tau)
ax.plot([tau_shft, tau_shft], [0, phi_sg[tau_ind]], 'ko--', lw=1);
ax.set_xlabel(r'$\rightarrow \tau$');
ax.set_ylabel(r'$\uparrow \varphi_{sg}^\mathrm{E}(\tau) = \int g(t) s^\ast(t-\tau)\mathrm{d}t$');
ax.set_xlim(axs[0].get_xlim()); rwth_plots.update_ylim(ax, phi_sg, 0.19, 5);
rwth_plots.axis(ax); rwth_plots.grid(ax); fig.tight_layout();
else: # Replace only xdata and ydata since plt.plot() takes longer time
ax = axs[0]; ax.lines[1].set_ydata(np.conj(s(t-tau_shft))); ax.lines[2].set_ydata(sg); # update signals
ax.texts[0].set_x(tau_shft); ax.lines[3].set_xdata([tau_shft,tau_shft]) # update labels
if ax.collections: ax.collections[0].remove(); # update integrand
if show_integrand: ax.fill_between(t,0,sg, facecolor="none", hatch="//", edgecolor='rwth:black', linewidth=0.0);
ax = axs[1]; ax.lines[0].set_ydata(phi_plot); # update signals
ax.lines[1].set_xdata([tau_shft, tau_shft]); ax.lines[1].set_ydata([0, phi_sg[tau_ind]]); # update labels
axs[0].lines[2].set_visible(show_integrand)
```
%% Cell type:markdown id: tags:
## Aufgaben
* Wähle zwei gleiche Funktionen aus. Überprüfe die oben angegebenen Eigenschaften der Autokorrelationsfunktion. Variiere hierbei die Funktionen und betrachte die Autokorrelationsfunktion verschiedener Signale.
* Wie ändert sich das Ergebnis, wenn die Breite eines der beiden Signale sich ändert?
* Wähle zwei verschiedene Signale aus und beobachte, wo in diesen Fällen die maximale Kreuzkorrelation auftritt. Kannst du erklären, warum?
%% Cell type:markdown id: tags:
---
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Diskrete Fourier-Transformation
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
# Einleitung
Die Fourier-Transformation zeitdiskreter Signale $s(n)$ ergibt ein frequenzkontinuierliches Spektrum $S_a(f)$. Dieses Spektrum kann bei einer numerischen Berechnung aber nur für endlich viele diskrete Frequenzen berechnet werden. Deswegen wurde die *diskrete Fouriertransformation (DFT)* eingeführt, die von vornherein einem zeitdiskreten Signal ein frequenzdiskretes Spektrum zuordnet. Diese DFT ist in der Signalverarbeitung besonders bedeutungsvoll geworden, weil für ihre Berechnung in Form der *schnellen Fourier-Transformation (FFT)* sehr effiziente Algorithmen zur Verfugung stehen. Die diskrete Fouriertransformation kombiniert die Abtastung im Zeit- und im Frequenzbereich. Im Grunde genommen ist die DFT aber das zeitdiskrete ̈Äquivalent zur Fourier-Reihenentwicklung, d. h. die analysierten abgetasteten Signale werden implizit so interpretiert, als seien sie periodisch fortgesetzt.
Das zeitdiskrete Signal $s_d(n)$ sei auf $M$, in diesem Fall $M=17$ Werte begrenzt. Der nachfolgende Plot zeigt das verwendete Signal. Es wird angenommen, dass dieses Signal sich periodisch mit der Periode $M$ wiederholt.
%% Cell type:code id: tags:
``` python
M = 17
n = np.arange(0, M)
k = n
n
```
%% Cell type:code id: tags:
``` python
sd = np.array([1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1]) # s(n)
hd = sd
# Plot
fig,ax = plt.subplots()
rwth_plots.stem(ax, n, sd, 'rwth:blue')
ax.set_xlabel(r'$\rightarrow n$', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow s_\mathrm{d}(n)$', bbox=rwth_plots.wbbox);
ax.set_ylim([-0.09,1.09]); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
Für das dargestellte Signal $s_d(n)$ kann nun mittels der diskreten Fouriertransformation das Spektrum
$$
\displaystyle S_d(k)=\sum_{n=0}^{M-1}s_d(n)\mathrm{e}^{-\mathrm{j}2\pi kFn} \quad k=0,...,M-1
$$
berechnet werden. Dies ist in der nachfolgenden Abbildung zu sehen. Da das Spektrum $S_d(k)$ ebenfalls periodisch ist, reicht die Berechnung der $M$ Spektralwerte einer Periode aus. Tatsächlich realisiert wird die Berechnung hier mittels der FFT. J
%% Cell type:code id: tags:
``` python
M = len(n)
Sd = np.real(np.fft.fft(sd, M)) # np.real() discards very small negative values
Hd = np.real(np.fft.fft(hd, M))
# Plot
fig,ax = plt.subplots()
rwth_plots.stem(ax, k, Sd, 'rwth:blue')
ax.set_xlabel(r'$\rightarrow k$', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow S_\mathrm{d}(k)$', bbox=rwth_plots.wbbox);
ax.set_ylim([-1.9,7.9]); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
Für die Rücktransformation in den Zeitbereich gilt dann
$$
\displaystyle s_d(n)=\frac{1}{M}\sum_{k=0}^{M-1}S_d(k)\mathrm{e}^{\mathrm{j}2\pi kFn} \quad n=0,...,M-1 \text{ .}
$$
## Faltung durch Multiplikation im Frequenzbereich
Auch bei der DFT ist es möglich, die Faltung durch Multiplikation im Frequenzbereich durchzuführen. Im folgenden Beispiel wird das Spektrum $S_d(k)$ mit sich selbst multipliziert, was einer Faltung des Signals $s_d(n)$ mit sich selbst entspricht. In der folgenden Abbildung sieht man zunächst das resultierende Spektrum $G_d(k)$ und das durch Rücktransformation gewonnene Signal $g_d(n)$. Da $s_d(n)$ diskrete Rechteckimpulse waren, sind hier nun diskrete Dreieckimpulse zu erkennen, welche sich aus der Faltung der Rechteckimpulse ergeben.
%% Cell type:code id: tags:
``` python
Gd = Sd * Hd
# Plot
gd = np.real(np.fft.ifft((Gd)))
fig,axs = plt.subplots(2,1)
ax = axs[0]; rwth_plots.stem(ax,k,Gd, 'rwth:blue')
ax.set_xlabel(r'$\rightarrow k$', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow G_\mathrm{d}(k)$', bbox=rwth_plots.wbbox);
ax.set_ylim([-1,59]); rwth_plots.axis(ax)
ax = axs[1]; rwth_plots.stem(ax,n,gd, 'rwth:blue')
ax.set_xlabel(r'$\rightarrow n$', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow g_\mathrm{d}(n)$', bbox=rwth_plots.wbbox);
ax.set_ylim([-0.09,8.9]); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
---
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ipywidgets import interact, interactive
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
from rwth_nb.misc.signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Elementarsignale
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
Ein Signal ist im Allgemeinen die Darstellung des Amplitudenverlaufs einer physikalischen Größe, wie z. B. einer elektrische Spannung, Feldstärke oder auch eines Schalldrucks, Helligkeitsverlaufs, Lichtpegels usw. Häufig werden als Signale Zeitfunktionen solcher Größen benutzt, aber auch andere Abhängigkeiten,wie z. B. Ortsabhängigkeiten bei Bildsignalen, sind möglich. Speziell in der Nachrichtentechnik hat das Signal als Träger einer dem Empfänger unbekannten Information zumeist Zufallscharakter. Aufbauelemente (Elementarkomponenten) solcher Zufallssignale sind aber häufig die determinierten Signale, deren Verlauf zumindest im Prinzip durch einen geschlossenen Ausdruck vollständig beschrieben werden kann.
Ein Elementarsignal ist ein Signal mit einer besonders einfachen Form. Sie können technisch oft recht einfach erzeugt werden und werden vielfach auch zur Ermittlung der Eigenschaften von Systemen verwendet.
Im Folgenden werden einige Elementarsignale aufgeführt.
%% Cell type:markdown id: tags:
## Signale
### Gauß-Signal
Ein Beispiel für ein Elementarsignal, das durch einen algebraischen Ausdruck ausgedrückt wird, ist das Gaußsignal $\displaystyle s(t) = \mathrm{e}^{\pi t^2}$.
%% Cell type:code id: tags:
``` python
fig,ax = plt.subplots(1,1); ax.plot(t, gauss(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\mathrm{e}^{-\pi t^2}$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.75, 2.75]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Sprungfunktion
Die Sprungfunktion wird beschrieben durch
$\epsilon(t)=\begin{cases}
0\quad\text{für}\ t<0 \\
1\quad\text{für}\ t\geq 0 \text{ .}
\end{cases}$
Ein Beispiel für eine Sprungfunktion ist der Spannungsverlauf an einem Ohm’schen Widerstand, der zur Zeit $t= 0$ an eine Gleichspannungsquelle geschaltet wird.
%% Cell type:code id: tags:
``` python
fig,ax = plt.subplots(1,1); ax.plot(t, unitstep(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\epsilon(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Rechteckimpuls
Der Rechteckimpuls wird definiert als
$\mathrm{rect}(t) = \begin{cases}
1\quad\text{für}\ |t| \leq 1/2\\
0\quad\text{für}\ |t| > 1/2\text{ .}
\end{cases}$
%% Cell type:code id: tags:
``` python
fig,ax = plt.subplots(1,1); ax.plot(t, rect(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\mathrm{rect}(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Dreieckimpuls
Der Dreieckimpuls wird definiert als
$\Lambda(t) = \begin{cases}
1-|t|\quad\text{für}\ |t|\leq 1\\
0\quad\text{für}\ |t| > 1\text{ .}
\end{cases}$
%% Cell type:code id: tags:
``` python
fig,ax = plt.subplots(1,1); ax.plot(t, tri(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\Lambda(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### si-Funktion
Die si-Funktion ist definiert als $\displaystyle \mathrm{si}(t) = \frac{\sin(t)}{t}$
Die si-Funktion ist auch als Spaltfunktion bekannt, da in optischen Systemen und Antennensystemen ein Spalt als räumliche rect-Funktion beschrieben werden kann (Bracewell, 1986). Sie hat außerdem die besondere Eigenschaft, sich bei Faltung mit sich selbst zu reproduzieren: $\mathrm{si(\pi t)} = \mathrm{si(\pi t)} * \mathrm{si(\pi t)}$
%% Cell type:code id: tags:
``` python
fig,ax = plt.subplots(1,1); ax.plot(t, si(np.pi*t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\mathrm{si}(\pi t)$', bbox=rwth_plots.wbbox)
ax.set_xlim([-5.5,5.5]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
## Zeitverschiebung, -dehnung und -spiegelung
%% Cell type:markdown id: tags:
Jedes Signal $s(t)$ kann verschoben, gedehnt/gestaucht und/oder gespiegelt werden. Im Folgenden werden die Effekte dieser Operationen auf das Signal verdeutlicht. Als grundlegende Form wird
$\displaystyle s\left(\pm\frac{t-t_0}{T}\right)$
gewählt. Hierbei steht $t_0$ für die Verschiebung des Signals, $T$ für die Dehnung/Stauchung und $\pm$ beschreibt die Spiegelung.
### Zeitverschiebung
Als Beispiel wird ein verschobener Rechteckimpuls $s(t) = \mathrm{rect}\left(t-\frac{1}{2}\right)$ betrachtet. Die Funktion $\mathrm{rect}(t)$ hat die Breite 1 und ist um $0$ zentriert, der um $t_0=\frac{1}{2}$ verschobene Rechteckimpuls ist in Abbildung 6 dargestellt.
#### Aufgabe
Verändere den Wert $t_0$. Wie ändert sich die geplottete Funktion? Was passiert für negative Werte von $t_0$?
%% Cell type:code id: tags:
``` python
s = lambda t: rect(t-1/2)
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, s(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Dehnung/Stauchung
Als nächstes wird die Dehnung eines Rechteckimpulses betrachet. Dies geschieht über den Faktor $T$. Die folgende Abbildung zeigt den mit $T=2$ gedehnten Rechteckimpuls $s(t) = \mathrm{rect}\left(\frac{t}{2}\right)$. Der normale Rechteckimpuls hat die Breite 1, der hier dargestellte erhält entsprechend die Breite $T \cdot 1=2$.
#### Aufgabe
Ändere den Wert für $T$. Was passiert mit der dargestellten Funktion? Was passiert für Werte von $|T| < 1$?
Ersetze den Rechteckimpuls durch einen Dreiecksimpuls $\Lambda(t) = \begin{cases}
1-|t|\quad\text{für}\ |t|\leq 1\\
0\quad\text{für}\ |t| > 1\text{ .}
\end{cases}$.
Ersetze hierfür rect durch tri. Wie breit wird die dargestellte Funktion für $T=2$?
%% Cell type:code id: tags:
``` python
s = lambda t: rect(t/2)
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, s(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Zeitspiegelung
Zur Verdeutlichung der Zeitspiegelung wird das in der folgenden Abbildung dargestellte Signal $s(t) = t \cdot \mathrm{rect}\left(t-\frac{1}{2}\right)$ betrachtet.
%% Cell type:code id: tags:
``` python
s = lambda t: rect(t-0.5)*t
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, s(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Betrachte nun $s(-t)$ in der folgenden Abbildung. Das negative Vorzeichen bewirkt eine Spiegelung des Signals an der y-Achse.
%% Cell type:code id: tags:
``` python
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, s(-t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(-t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
## Amplitudenfaktor
Bisher wurde bei allen Signalen $a \cdot s(\frac{t-t_0}{T})$ angenommen, dass der Amplitudenfaktor $a = 1$ beträgt.
Durch Ändern von $a$ kann eine Dehnung/Stauchung der Ordinate bewirkt werden.
%% Cell type:code id: tags:
``` python
a = 3/2
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, a * rect(t), 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow a \cdot s(t)$', bbox=rwth_plots.wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Zur Verdeutlichung des Amplitudenfaktors sowie der Zeitverschiebung, -dehnung und -spiegelung ist zusätzlich eine [interaktive Demo](GDET3%20Zeitverschiebung-Dehnung%20GUI.ipynb) verfügbar.
%% Cell type:markdown id: tags:
---
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
import ipywidgets as widgets
from ipywidgets import interact, interactive, fixed, Layout
import matplotlib.pyplot as plt
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
from rwth_nb.misc.signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Fourier-Reihenkoeffizienten
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
%% Cell type:markdown id: tags:
## Einleitung
Im Folgenden soll die periodische Rechteckfunktion
$$s_\mathrm{p}(t) =
\mathrm{rect}\left(\frac{t}{T_1}\right) \ast
\sum_{n=-\infty}^\infty \delta(t-nT)
$$
durch eine *endliche* Fourier-Summe $s_{\mathrm{p},N}(t)$ approximiert werden.
%% Cell type:code id: tags:
``` python
t = np.linspace(-3,3,10000) # t-axis
T = 1; F = 1/T; # periodicity T
T1 = T/2
# Parts of the infinite rect sum
Nmax = 3 # should be infinity :-)
s = np.zeros_like(t)
for n in np.arange(-Nmax,Nmax+1):
s = s + rect((t-n)/T1)
# Plot
fig,ax = plt.subplots(figsize=(6,3)); ax.plot(t, s, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s_{\mathrm{p}}(t)$');
ax.set_xlim([-2.9, 2.9]); ax.set_ylim([0, 1.09]); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Die zugehörigen Fourier-Reihenkoeffizienten lassen sich (wie im Buch) berechnen zu
$$
S_\mathrm{p}(k)
=
\frac{\sin\left(k\pi\frac{T_1}{T}\right)}{k\pi}\quad\text{mit }k\neq 0
$$
und
$$
S_\mathrm{p}(k=0) = \frac{T_1}{T}\text{.}
$$
Im Folgenden ist $T=\frac{1}{F} = 1$.
Im Zeitbereich kann die Fourier-Summe durch eine endliche Summe (Summation bis zu $\pm N$ anstelle $\pm \infty$) wie folgt angenähert werden:
$$
s_{\mathrm{p},N}(t)
=
\sum_{k=-N}^N S_\mathrm{p}(k) \mathrm{e}^{\mathrm{j} 2 \pi k F t}
\text{ .}
$$
Da $s_\mathrm{p}(t)$ hier ein reelles Signal ist (und damit $S_\mathrm{p}(-k) = S_\mathrm{p}^\ast(k)$ gilt), kann es somit über den Gleichanteil und die Fourier-Koeffizienten durch
$$
s_{\mathrm{p},N}(t)
=
S_\mathrm{p}(0) + 2 \sum_{k=1}^N \mathrm{Re}\left\{ S_\mathrm{p}(k) \mathrm{e}^{\mathrm{j} 2 \pi k F t} \right\}
$$
beschrieben werden.
Zunächst für ein einfaches Beispiel mit $N=4$:
%% Cell type:code id: tags:
``` python
N = 4
k = np.arange(0,N)
# Fourier series coefficients
Sp = np.zeros(N)
Sp[0] = T1/T # k=0
Sp[1::] = np.sin(k[1::]*np.pi*T1/T)/(k[1::]*np.pi) # k > 0
# Plot
fig,ax = plt.subplots(); rwth_plots.stem(ax, k, Sp, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow k$'); ax.set_ylabel(r'$\uparrow S_{\mathrm{P}}(k)$'); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Abgebildet sind die Koeffizienten $Sp_p(k)$ für $k=0,...,3$. Aus diesen vier Koeffizienten wird nun das Ursprungssignal angenähert.
Die folgende Abbildung zeigt die einzelnen Summanden
$
2 \mathrm{Re}\left\{ S_\mathrm{p}(k) \mathrm{e}^{\mathrm{j} 2 \pi k F t} \right\}
$
sowie das Resultat $s_{\mathrm{p},N}(t)$:
%% Cell type:code id: tags:
``` python
# Approximated time signal
sp = Sp[0]*np.ones_like(t) # DC
fig,axs = plt.subplots(2,1); colors = ['rwth:green', 'rwth:magenta', 'rwth:orange']; ax = axs[0];
ax.plot(t,sp, 'rwth:blue-50', linestyle='--', label=r'$S_\mathrm{p}(0)$')
legend = np.array([r'$k==0$'])
for kIter in k[1::]:
spIter = 2*np.real(Sp[kIter]*np.exp(2j*np.pi*kIter*F*t));
sp = sp + spIter;
# Plot
ax.plot(t,spIter, color=colors[kIter-1], linestyle='--', label=r'$k={}$'.format(kIter))
ax.set_xlabel(r'$\rightarrow t$'); ax.legend(loc='lower left');
ax.set_xlim([-1.6,1.6]); ax.set_ylim([-1.1,1.1]); rwth_plots.axis(ax);
ax = axs[1]; ax.plot(t, sp)
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s_{\mathrm{P},N}(t)$');
ax.set_xlim([-1.6,1.6]); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Die verwendeten Koeffizienten erzeugen Signalanteile mit ansteigender Frequenz.
Obwohl für die Rekonstruktion nur vier Koeffizienten verwendet wurden, ist die Annäherung an das ursprüngliche Rechtecksignal zu erkennen. Für eine klarere Darstellung der Ecken im Signal fehlen die hochfrequenten Anteil der höheren Koeffizienten. In der folgenden Demonstration kann dieser Effekt anschaulich betrachtet werden.
%% Cell type:markdown id: tags:
## Demo
Die Demonstration ermöglicht die Untersuchung des Einflusses der Anzahl der zur Rekonstruktion verwendeten Koeffizienten $N$ und der Breite $T_1$ des verwendeten Rechtecks.
Über den Slider können verschiedene Werte für $N$ und $T_1$ eingestellt werden. Die gestrichelte schwarze Linie in der oberen Abbildung zeigt das zu approximierende Ausgangssignal, die blaue Linie die errechnete Annäherung unter Verwendung von $N$ Koeffizienten. Die verwendeten Koeffizienten sind in der unteren Abbildung dargestellt.
%% Cell type:code id: tags:
``` python
fig,axs = plt.subplots(2,1);
@widgets.interact(N=widgets.IntSlider(min=1, max=50, step=1, description='$N$', continuous_update=False),
T1=widgets.FloatSlider(min=0.125, max=.75, step=0.125, value=.5, description='$T_1$',
continuous_update=False, readout_format='.3f',))
def update_plot(N, T1):
# Snippet of time signal
s = np.zeros_like(t)
for n in np.arange(-Nmax,Nmax+1):
s = s + rect((t-n)/T1)
# Fourier series coefficients
k = np.arange(0,N)
Sp = np.zeros(N)
Sp[0] = T1/T
Sp[1::] = np.sin(k[1::]*np.pi*T1/T)/(k[1::]*np.pi)
# Approximated time signal
sp = Sp[0]*np.ones_like(t) # DC
for kIter in k[1::]:
sp = sp + 2*np.real(Sp[kIter]*np.exp(2j*np.pi*kIter*F*t));
k = np.concatenate((-k[::-1],k[1::]));
Sp = np.concatenate((Sp[::-1],Sp[1::]))
# Plot
if not axs[0].lines: # create plot
ax = axs[0]; ax.plot(t, s, 'k--')
ax.plot(t, sp, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s_{\mathrm{P},N}(t)$');
ax.set_xlim([-1.6,1.6]); ax.set_ylim([-.2, 1.2]); rwth_plots.axis(ax);
ax = axs[1]; rwth_plots.stem(ax, k, Sp, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow k$'); ax.set_ylabel(r'$\uparrow S_{\mathrm{P}}(k)$');
rwth_plots.axis(ax); ax.set_ylim([-.29,.89])
else: # update plot
axs[0].lines[0].set_ydata(s); axs[0].lines[1].set_ydata(sp);
rwth_plots.stem_set_data(axs[1].containers[0], k, Sp);plt.show()
axs[1].set_xlim([-N+.5, N-.5])
```
%% Cell type:markdown id: tags:
## Aufgaben
* Variiere $N$ und halte $T_1=0.5$ konstant. Wieviele Koeffizienten erhält man für $N=10$ und wie sind diese angeordnet? Warum?
* Ab welchem $N$ ist annähernd die Struktur des Ausgangssignals zu erkennen?
* Setze $N=50$. Wie verhält sich das rekonstruierte Signal an den Ecken des Rechteckimpulses? Warum?
* Variiere nun $T_1$. Setze $N=7$ und beobachte, was mit den Koeffizienten passiert, wenn $T_1$ kleine oder große Werte annimmt. Was passiert mit dem approximierten Signal?
* Für welche Kombination der Werte $N$ und $T_1$ kann die angenäherte Stuktur des Ausgangssignal erkannt werden? Warum?
%% Cell type:markdown id: tags:
---
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, [Institut für Nachrichtentechnik](http://www.ient.rwth-aachen.de), RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ipywidgets import interact, interactive, fixed, HBox, VBox
import ipywidgets as widgets
from IPython.display import clear_output, display, HTML
import matplotlib.pyplot as plt
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
import rwth_nb.misc.transforms as rwth_transforms
from rwth_nb.misc.signals import *
```
%% Cell type:code id: tags:
``` python
t = np.linspace(-10, 10, 10001); f = np.linspace(-10, 10, 10001) # time and frq domain
s = tri # use predefined triangle function from ient_signals
S = lambda f: np.sinc(5*f/np.pi) # alternatively define own signals
def x_mirrored_around_zero(maxval, inc=1):
x = np.arange(inc, maxval + inc, inc)
return np.r_[-x[::-1], 0, x]
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Ideale Abtastung
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
Dieses Notebook soll die ideale Abtastung veranschaulichen.
![Blockdiagramm](figures/sampling_block_diagram.png)
Das zeitkontinuierliche Signal $s(t)$ wird zu Zeitpunkten $nT$ mit Abtastperiode $T$ abgetastet. Das resultierende, ideal abgetastete Signal
$$s_\mathrm{a}(t) = \sum\limits_{n=-\infty}^\infty s(nT) \delta(t-nT)$$
besteht aus Dirac-Impulsen, positioniert an den Zeitpunkten $nT$ und gewichtet mit dem Funktionswerten $s(nT)$. Die zugehörige Fourier-Transformierte $S_{\mathrm{a}}(f)$ wird aus periodischen Wiederholungen des Signalspektrums $S(f)$ zusammengesetzt:
$$S_\mathrm{a}(f) = \frac{1}{T}\sum\limits_{k=-\infty}^\infty S\left(f-\frac{k}{T}\right) \text{.}$$
Die Wiederholungen sind bei Vielfachen der Abtastrate $r=\frac{1}{T}$ positioniert und mit $r=\frac{1}{T}$ gewichtet.
Zur Rückgewinnung wird ein Rekonstruktionsfilter $h_\mathrm{TP}(t)$ eingesetzt, welches im Idealfall die die spektrale Kopie bei $k=0$ (auch Basisband genannt) aus $S_\mathrm{a}(f)$ rekonstruieren soll.
Hier wird das ideale Tiefpassfilter
$$H_\mathrm{TP}(f)=\mathrm{rect}\left(\frac{f}{2 f_\mathrm{g}}\right)$$ mit Grenzfrequenz $f_\mathrm{g} = \frac{r}{2}$ verwendet.
Zur Rückgewinnung im Spektralbereich wird dieser ideale Tiefpass mit dem Spektrums des abgetasteten Signals $S_{\mathrm{a}}(f)$ multipliziert. Das Spektrum des rekonstruierten Signals ist somit
$$G(f)=S_\mathrm{a}(f) \cdot H_\mathrm{TP}(f) \cdot T\text{.}$$
Das rekonstuierte Signal im Zeitbereich $g(t)$ wird dann durch Rücktransformation gewonnen.
%% Cell type:markdown id: tags:
## Demo
Im Folgenden wird ein ideales Abtastsystem mit fester Abtastrate $r=2$ angenommen. Das ideale Rekonstruktionsfilter wird mit $f_\mathrm{g} = \frac{r}{2} = 1$ verwendet.
Zur Auswahl stehen die folgenden Signale $s(t)$, deren Frequenz $F$ variabel ist.
* $s(t) = \cos(2 \pi F t)$ mit $S(f) = \frac{1}{2}\delta(f-F)+\frac{1}{2}\delta(f+F)$,
* $s(t) = \sin(2 \pi F t)$ mit $S(f) = \frac{1}{2\mathrm{j}}\delta(f-F)-\frac{1}{2\mathrm{j}}\delta(f+F)$,
* $s(t) = \mathrm{si}(2 \pi F t)$ mit $S(f) = \frac{1}{2 |F|}\mathrm{rect}\left(\frac{f}{2F}\right)$,
* $s(t) = \mathrm{rect} (F t)$ mit $S(f) = \frac{1}{|F|}\mathrm{si}\left(\frac{\pi f}{F}\right)$ und
* $s(t) = \Lambda(F t)$ mit $S(f) = \frac{1}{|F|}\mathrm{si}^2\left(\frac{\pi f}{F}\right)$.
Achtung: Die letzten beiden Signale $s(t)$, Rechteck- und Dreieckimpuls, haben unendlich ausgedehnte Spektren $S(f)$. Daher ist eine fehlerfreie Rekonstruktion prinzipiell nicht möglich!
Zunächst werden $s(t)$ und $s_\mathrm{a}(t)$ im Zeitbereich betrachtet. Weiterhin wird das zu $s_\mathrm{a}(t)$ gehörige Spektrum $S_\mathrm{a}(f)$ dargestellt. In der gleichen Abbildung ist die Übertragungsfunktion $H_\mathrm{TP}(f)$ des Rekonstruktionsfilters gezeigt.
Das Spektrum des rekonstruierten Signal $G(f)=S_\mathrm{a}(f) \cdot H_\mathrm{TP}(f) \cdot T$ wird in der nächsten Abbildung dargestellt.
In der letzten Abbildung wird nun das rekonstruierte Signal $g(t)$ gezeigt. Im Alias-freien Fall für cos-, sin- und si-Funktion gilt $g(t)=s(t)$.
%% Cell type:code id: tags:
``` python
r = 2; T = 1/r; # sampling frequency
signals_t = {'cos-Funktion': lambda t: np.cos(2 * np.pi * t),
'sin-Funktion': lambda t: np.sin(2 * np.pi * t),
'si-Funktion': lambda t: si(2 * np.pi * t),
'Rechteckimpuls': lambda t: rect(t / 1.05),
'Dreieckimpuls': tri}
signals_f = {'cos-Funktion': lambda f, F: np.isin(f/F, f[find_ind_least_diff(f/F, [-1, 1])]/F) * 0.5,
'sin-Funktion': lambda f, F: np.isin(f/F, f[find_ind_least_diff(f/F, [1])]/F) / 2j - np.isin(f/F, f[find_ind_least_diff(f/F, [-1])]/F) / 2j,
'si-Funktion': lambda f, F: 1/(2*np.abs(F))*rect(f / (2*F)),
'Rechteckimpuls': lambda f, F: 1/np.abs(F)*si(np.pi * f / F),
'Dreieckimpuls': lambda f, F: 1/np.abs(F)*si(np.pi * f/F) ** 2}
#f = t;
t,deltat = np.linspace(-10,10,50001, retstep=True) # t-axis
f,deltaf = np.linspace(-50,50,len(t), retstep=True) # f-axis
kMax = 16 # number of k values in sum for Sa(f)
# Plot
plt.close(); fig, axs = plt.subplots(4, 1, **rwth_plots.landscape); plt.tight_layout();
@widgets.interact(s_type=widgets.Dropdown(options=list(signals_t.keys()), description=r'Wähle $s(t)$:'),
F=widgets.FloatSlider(min=0.1, max=2, value=0.9, step=.1, description=r'$F$', style=rwth_plots.wdgtl_style, continuous_update=False))
def update_plots(s_type, F):
s = lambda t: signals_t[s_type](t*F);
S = lambda f: signals_f[s_type](f, F);
nT, snT = rwth_transforms.sample(t, s(t), T)
# Construct sampled spectrum
Sa = np.zeros_like(S(f))
for k in np.arange(-kMax, kMax+1): # evaluate infinite sum only for 2*kMax+1 elements
Sa += S(f-k/T)
Sa = Sa/T
# Reconstruct g(t)
H_lp = rect(f/(r+0.001)) # reconstruction filter
G = Sa * H_lp * T; # reconstruction
g = rwth_transforms.idft(G);
g = np.fft.ifftshift(np.real(g)); # IDFT
# Sample
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':
fSadirac = f[np.where(Sa)]; Sadirac = Sa[np.where(Sa)]
fSdirac = f[np.where(S(f))]; Sdirac = S(f)[np.where(S(f))]
fGdirac = f[np.where(G)]; Gdirac = G[np.where(G)]
if s_type == 'sin-Funktion':
Sadirac = np.imag(Sadirac); Sdirac = np.imag(Sdirac); S = lambda f: np.imag(signals_f[s_type](f, F)); Sa = np.imag(Sa); G = np.imag(G); Gdirac = np.imag(Gdirac)
else:
g /= (len(f)/(2*f[-1])) # Parseval :)
# Plot
if not axs[0].lines: # Call plot() and decorate axes. Usually, these functions take some processing time
ax = axs[0]; ax.set_title('Zeitbereich');
ax.plot(t, s(t), color='rwth:blue', linestyle='--', label=r'$s(t)$');
rwth_plots.plot_dirac(ax, nT, snT, 'rwth:red', label=r'$s_\mathrm{a}(t)$')
ax.set_xlabel(r'$\rightarrow t$');
ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); rwth_plots.grid(ax); rwth_plots.axis(ax);
ax = axs[1]; ax.set_title('Frequenzbereich');
ax.plot(f, H_lp, '-', color='black', label=r'$H_\mathrm{TP}(f)$')
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':
ax.plot(f, np.ones_like(f)*np.nan, '-', color='rwth:red', label=r'$S_a(f)$');
rwth_plots.plot_dirac(ax, fSadirac, Sadirac, 'rwth:red');
else:
ax.plot(f, Sa, '-', color='rwth:red', label=r'$S_a(f)$');
rwth_plots.plot_dirac(ax, [], [], 'rwth:red');
ax.plot(f, S(f), color='rwth:blue', linestyle='--', linewidth=1, label=r'$S(f)$')
ax.set_xlim([-7.5,7.5]); ax.set_ylim([-1,2]); ax.legend(loc=2);
ax.set_xlabel(r'$\rightarrow f$'); rwth_plots.grid(ax); rwth_plots.axis(ax);
txt,_=rwth_plots.annotate_xtick(ax, r'$r=2$', r, -.15, 'black'); txt.get_bbox_patch().set_alpha(1);
txt,_=rwth_plots.annotate_xtick(ax, r'$f_\mathrm{g}$', r/2, -.15, 'black'); txt.get_bbox_patch().set_alpha(1);
ax = axs[2];
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':
ax.plot(f, np.ones_like(f)*np.nan, '-', color='rwth:green');
rwth_plots.plot_dirac(ax, fGdirac, Gdirac, 'rwth:green');
else:
ax.plot(f, G, '-', color='rwth:green');
rwth_plots.plot_dirac(ax, [], [], 'rwth:red');
ax.set_xlabel(r'$\rightarrow f$'); ax.set_ylabel(r'$\uparrow G(f)=S_\mathrm{a}(f) \cdot H_\mathrm{TP}(f) \cdot T$', bbox=rwth_plots.wbbox);
ax.set_xlim([-7.5,7.5]); rwth_plots.grid(ax); rwth_plots.axis(ax);
ax = axs[3]; ax.set_title('Zeitbereich (nach Rekonstruktion)');
ax.plot(t, s(t), color='rwth:blue', linestyle='--', label=r'$s(t)$');
ax.plot(t/deltat/(f[-1]*2), g, 'rwth:green', label=r'$g(t)$');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); rwth_plots.grid(ax); rwth_plots.axis(ax);
plt.tight_layout()
else:
axs[0].lines[0].set_ydata(s(t)); axs[1].lines[-3].set_ydata(S(f));
rwth_plots.dirac_set_data(axs[0].containers, nT, snT)
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion': # dirac plot
rwth_plots.dirac_set_data(axs[1].containers, fSadirac, Sadirac); axs[1].lines[1].set_ydata(np.ones_like(f)*np.nan);
rwth_plots.dirac_set_data(axs[2].containers, fGdirac, Gdirac); axs[2].lines[0].set_ydata(np.ones_like(f)*np.nan);
else:
axs[1].lines[1].set_ydata(Sa); rwth_plots.dirac_set_data(axs[1].containers, [], []);
axs[2].lines[0].set_ydata(G); rwth_plots.dirac_set_data(axs[2].containers, [], []);
axs[3].lines[0].set_ydata(s(t)); axs[3].lines[1].set_ydata(g);
if s_type == 'sin-Funktion': # Adapt labels
axs[1].lines[1].set_label(r'$\mathrm{Im}\{S_\mathrm{a}(f)\}$'); axs[1].lines[-3].set_label(r'$\mathrm{Im}\{S(f)\}$');
axs[2].yaxis.label.set_text(r'$\uparrow \mathrm{Im}\{G(f)=S_\mathrm{a}(f) \cdot H_\mathrm{TP}(f) \cdot T\}$');
else:
axs[1].lines[1].set_label(r'$S_\mathrm{a}(f)$'); axs[1].lines[-3].set_label(r'$S(f)$')
axs[2].yaxis.label.set_text(r'$\uparrow G(f)=S_\mathrm{a}(f) \cdot H_\mathrm{TP}(f) \cdot T$');
axs[1].legend(loc=2)
rwth_plots.update_ylim(axs[1], Sa, 0.19, np.max(Sa)); rwth_plots.update_ylim(axs[2], G, 0.19, np.max(G));
rwth_plots.update_ylim(axs[3], np.concatenate((s(t),g)), 0.19, np.max(np.concatenate((s(t),g))));
```
%% Cell type:markdown id: tags:
## Aufgaben
* Wähle eine cos-Funktion für $s(t)$ und setze $F$ auf die kleinstmögliche Größe. Im Spektrum ist die Frequenz des Cosinus zu erkennen und im Zeitbereich wird dieser perfekt rekonstruiert. Erhöhe nun $F$ schrittweise. Beobachte das Spektrum. Was passiert und warum?
* Betrachte das Spektrum für $F=1$. Vergleiche die Höhe der Diracs mit denen für $F=0.9$ und $F=1.1$. Wie ist der Unterschied zu erklären?
* Für $F\geq 1$ wird das Signal nicht mehr perfekt rekonstruiert. Dieser Effekt nennt sich Aliasing. Wie verhält sich das rekonstruierte Signal bei größer werdendem $F$?
* Betrachte abschließend $F=2$. Was passiert hier?
* Wähle nun eine sin-Funktion und untersuche dieselben Dinge, wie zuvor für die cos-Funktion. Wie ist das Ergebnis für $F=1$ und $F=2$ zu erklären?
* Betrachte die si-Funktion. Das Spektrum der si-Funktion ist ein Rechteck. Was passiert, wenn $F$ größere Werte annimmt? Warum?
* Setze $F=1$. Kann aus $S_a(f)$ prinzipiell das ursprüngliche Signal rekonstruiert werden? Warum wird das Signal trotzdem perfekt rekonstruiert?
* Betrachte $F \leq 1$. Welche Form nimmt $G(f)$ an und wie wirkt sich das auf das rekonstruierte Signal aus?
Nun wird der Rechteckimpuls und der Dreiecksimpuls betrachtet. Im Gegensatz zu den vorherigen Funktionen ist das Spektrum hier, wie bereits oben erwähnt, unendlich ausgedehnt. Daher ist eine fehlerfreie Rekonstruktion prinzipiell nicht möglich.
* Starte wieder mit dem kleinstmöglichen $F$. Betrachte das Spektrum des abgetasteten Signals $S_{\mathrm{a}}(f)$ und das Spektrum nach Anwendung des Rekonstruktionsfilters $G(f)$. Wie müsste $G(f)$ für fehlerfreie Rekonstruktion aussehen? Was erzeugt den Unterschied?
* Erhöhe nun $F$ schrittweise und betrachte die Änderung von $S_{\mathrm{a}}(f)$, $G(f)$ und $g(t)$. Ab welchem $F$ ist das Ausgangssignal nicht mehr zu erkennen?
* Was passiert für $F \leq 1$ und wie erklärt sich das?
* Führe dieselben Überlegungen für den Dreiecksimpuls aus. Wie erklärt sich das unterschiedliche Verhalten?
%% Cell type:markdown id: tags:
___
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Emin Kosar, Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
import ipywidgets as widgets
from ipywidgets import interact, interactive
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
import scipy.special
import scipy.signal
import rwth_nb.plots.mpl_decorations as rwth_plots
from rwth_nb.misc.signals import *
rect_pulse = lambda t, Tr=0.5 : ((t+.25) % 1)< Tr
def correlation(s, g):
# Correlate s and g numerically
return sp.signal.convolve(np.conj(np.flipud(s)), g, mode='full')/(len(t))
fs = 200 # Samplingrate
(t,deltat) = np.linspace(-50,50, 100*fs, retstep=True) # Zeitachse
(tau,deltatau) = np.linspace(-100,100, 2*len(t)-1, retstep=True) # Korrelation
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Korrelationsempfänger
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
Wird ein bekanntes Signal bei Übertragung über einen Kanal gestört, kann es bei starker Überlagerung durch Rauschen schwierig sein, dieses wieder zu entdecken. Trotzdem soll das Signal entdeckt und bezüglich Amplitude und Dauer geschätzt werden. Bei Störung durch weißes Rauschen ist die optimale Lösung für dieses Problem ein sogenannter Korrelationsempfänger. Dieser nutzt ein Korrelationsverfahren, bei dem das gestörte Signal mit einem ungestörten Mustersignal verglichen wird. Genutzt wird dies zum Beispiel für Synchronisierung oder Radarortung, ebenso ist es hiermit möglich, mehrere Signale auf einem gemeinsamen Kanal zu übertragen.
Dieses Verfahren soll hier veranschaulicht werden.
%% Cell type:markdown id: tags:
Das in der nächsten Abbildung dargestellte Signal $s(t)$ ist ein Burst-Signal
$$
s(t) = \sin(2\pi F t) \cdot \sum_n \mathrm{rect}\left(\frac{t}{D}-\frac{1}{2}-nT\right)
$$
%% Cell type:code id: tags:
``` python
T = 3 # Periode in Sekunden
D = 1 # Burstdauer in Sekunden
F = 2 # Frequenz des Sinus in Hertz
A = 1 # Amplitude
s = A*np.sin(2*np.pi*F*t)*rect_pulse(t/T-.25, D/T)
# Plot
fig,ax = plt.subplots(1,1); ax.plot(t, s, 'rwth:blue'); ax.plot(t, rect_pulse(t/T-.25, D/T), 'k--')
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox)
ax.set_xlim([-4.5,5.25]); ax.set_ylim([-1.2,1.2]); rwth_plots.grid(ax); rwth_plots.axis(ax);
rwth_plots.annotate_distance(ax, r'$D$', (0,-1.1), (D,-1.1))
rwth_plots.annotate_distance(ax, r'$T$', (0,-.9), (T,-.9))
```
%% Cell type:markdown id: tags:
In der nächsten Abbildung ist das Störsignal $n(t)$ und die zugehörige Verteilungsdichte $p_n(x)$ dargestellt. $n(t)$ ist gleichverteiltes weißes Rauschen im Amplitudenwertebereich $-1$ und $1$.
%% Cell type:code id: tags:
``` python
n = np.random.uniform(-1, 1, len(t))
x = np.linspace(-5,5, 1024)
pn_hist, bins = np.histogram(n, bins=100, range=(-2, 2), density=True)
x_nhist = (bins[:-1] + bins[1:])/2 # x-axis
# Plot
fig,axs = plt.subplots(2,1);
ax = axs[0]; ax.plot(t, n, 'rwth:blue');
ax.set_ylabel(r'$\uparrow {}^k n(t)$', bbox=rwth_plots.wbbox); ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox);
ax.set_xlim([-4.5,5.25]); rwth_plots.axis(ax);
ax = axs[1]; rwth_plots.stem(ax, x_nhist, pn_hist, 'rwth:black-50', markerfmt=" ");
ax.plot(x, 0.5*rect(x/2), 'rwth:blue')
ax.set_ylabel(r'$\uparrow p_n(x)$', bbox=rwth_plots.wbbox); ax.set_xlabel(r'$\rightarrow x$', bbox=rwth_plots.wbbox);
ax.set_xlim([-1.75,1.75]); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
## Interaktive Demo
In dieser interaktiven Demo soll nun betrachtet werden, wie man mit Hilfe der Korrelation das Nutzsignal $s(t)$ detektieren kann.
Dargestellt sind auf der rechten Seite das Nutzsignal $s(t)$ und das Störsignal $n(t)$. Die beiden Signale werden nun überlagert und das Summensignal $g(t) = s(t) + n(t)$ betrachtet, dies ist oben links abgebildet.
Ebenfalls dargestellt ist die Autokorrelationsfunktion $\varphi_{gg}(\tau)$.
Mit Hilfe der Schieberegler können nun verschiedene Variationen des Signals dargestellt werden. Der erste Schieberegler ändert die Frequenz $F$ von $s(t)$, der zweite die Dauer $D$ und der dritte die Periode $T$ mit der die Anteile von $s(t)$ wiederholt werden.
Über den letzten Schieberegler kann das Signal-zu-Rausch-Verhältnisse (SNR) eingestellt werden.
%% Cell type:code id: tags:
``` python
fig,axs = plt.subplots(2,2, **rwth_plots.landscape, gridspec_kw = {'width_ratios':[2, 1]})
Twdgt = widgets.FloatSlider(min=1, max=20, value=10, step=1, description=r'Periode T', style=rwth_plots.wdgtl_style)
Dwdgt = widgets.FloatSlider(min=0.5, max=10, value=5, step=.5, description=r'Dauer D', style=rwth_plots.wdgtl_style)
def update_x_range(*args):
Dwdgt.max = Twdgt.value
Twdgt.observe(update_x_range, 'value')# D ist an den Wert von T gekoppelt, da D immer kleiner gleich T
@interact(F=widgets.FloatSlider(min=1, max=20, value=1, step=1, description=r'Frequenz F', style=rwth_plots.wdgtl_style),
D=Dwdgt, T=Twdgt,
SNR=widgets.FloatSlider(min=-50, max=50, value=-10, step=1, description=r'SNR', style=rwth_plots.wdgtl_style))
def update_plot(F, D, T, SNR):
# Empfänger: Burst-Signal
A = 10**(SNR/20)*np.sqrt(2/3);
s = A*rect_pulse(t/T-.25, D/T)*np.sin(2*np.pi*F*t)
# Kanal: Additives weißes Rauschen
g = s + n
# Empfänger: Korrelation
phi_gg = correlation(g, g)
if not axs[0,0].lines:
ax = axs[0,0]; ax.plot(t, g, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$', bbox=rwth_plots.wbbox);
ax.set_ylabel(r'$\uparrow g(t) = s(t)+n(t)$', bbox=rwth_plots.wbbox); rwth_plots.axis(ax);
ax = axs[0, 1]; ax.plot(t, s, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$', bbox=rwth_plots.wbbox);
ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox); rwth_plots.axis(ax);
ax = axs[1,0]; ax.plot(tau, phi_gg, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow \tau$', bbox=rwth_plots.wbbox);
ax.set_ylabel(r'$\uparrow \varphi_{gg}(\tau)$', bbox=rwth_plots.wbbox); rwth_plots.axis(ax);
ax = axs[1, 1]; ax.plot(t, n, 'rwth:blue');
ax.set_xlabel(r'$\rightarrow t$', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow n(t)$', bbox=rwth_plots.wbbox);
rwth_plots.update_ylim(ax,n,.25,1000); rwth_plots.axis(ax); fig.tight_layout();
else:
axs[0,0].lines[0].set_ydata(g); axs[0,1].lines[0].set_ydata(s); axs[1,0].lines[0].set_ydata(phi_gg);
axs[0,0].set_xlim([-2.1*T,2.1*T]); rwth_plots.update_ylim(axs[0,0], g, .5*np.max(np.abs(g)), 1e6);
axs[0,1].set_xlim(axs[0,0].get_xlim()); rwth_plots.update_ylim(axs[0,1], s, .5*np.max(np.abs(s)), 1e6)
axs[1,0].set_xlim(axs[0,0].get_xlim()); rwth_plots.update_ylim(axs[1,0], phi_gg[int(len(phi_gg)/2+1):-int(len(phi_gg)/4)], .5*np.max(np.abs(phi_gg[int(len(phi_gg)/2+1):-int(len(phi_gg)/4)])), 1e6)
axs[1,1].set_xlim(axs[0,0].get_xlim());
```
%% Cell type:markdown id: tags:
## Aufgaben
* Betrachte $g(t)$ und $\varphi_{gg}(\tau)$ für die voreingestellten Startwerte. Vergleiche den Bereich, in dem sich $s(t)$ befindet. Wie stellt sich dies in der Korrelationsfunktion dar?
* Variiere nun die Frequenz $F$. Wie ändern sich $g(t)$ und $\varphi_{gg}(\tau)$?
* Was passiert, wenn $D$ sehr große Werte annimmt? Warum?
* Welchen Einfluss hat die Periode $T$?
Abschließend wird nun der Einfluss des Signal-zu-Rauschverhältnisses betrachtet.
* Starte mit kleinen Werten für das SNR und erhöhe es schrittweise. Was passiert mit dem Signal? Was passiert mit der Korrelationsfunktion?
* Probiere aus, für welche Konstellationen von $F$, $D$, $T$ und $SNR$ aus dem Korrelationssignal noch genügend Information gewonnen werden kann um Position und Dauer des Originalsignals zu identifizieren.
%% Cell type:markdown id: tags:
____
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ipywidgets import interact, interactive, fixed, HBox, VBox
import ipywidgets as widgets
from IPython.display import clear_output, display, HTML
from IPython.display import Markdown as md
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
from rwth_nb.misc.signals import *
import rwth_nb.misc.transforms as rwth_transforms
from src.laplace.laplace_plot import pzPoint, pzPlot
t = np.linspace(-6,6,1024)
f = np.linspace(-6,6,1024)
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Laplace-Transformation
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
%% Cell type:markdown id: tags:
Beispiele
## Beispiele
$s_1(t) = \mathrm{e}^{-bt}\cdot\epsilon(t)$
transformiert sich zu
$S_1(p) = \frac{1}{b+p}$ mit Konvergenzbereich $\mathrm{Re}\{p\}>\mathrm{Re}\{-b\}$
%% Cell type:code id: tags:
``` python
b = 2
pp = np.array([-b]); pz = np.array([])
roc = np.array([-b, np.inf])
fig,axs = plt.subplots(1,2, **rwth_plots.landscape)
# Laplace-Bereich
ax = axs[0]; rwth_plots.plot_lroc(ax, roc)
ax.plot(np.real(pp), np.imag(pp), **rwth_plots.style_poles); ax.plot(np.real(pp), -np.imag(pp), **rwth_plots.style_poles)
ax.set_xlabel(r'$\rightarrow \mathrm{Re}$'); ax.set_ylabel(r'$\uparrow \mathrm{Im}$');
ax.set_xlim(-5, 5); ax.set_ylim(-5, 5); rwth_plots.grid(ax); rwth_plots.axis(ax)
# Zeitbereich
s1, _, _ = rwth_transforms.ilaplace_ht(t, 1, pp, pz, [1], [], roc)
ax = axs[1]; ax.plot(t, np.real(s1), **rwth_plots.style_graph);
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s_1(t)$'); rwth_plots.grid(ax); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
Da der Konvergenzbereich die imaginäre Achse umschließt, existiert auch die Fouriertransformierte $S_1(f)$:
%% Cell type:code id: tags:
``` python
# Frequenzbereich
S1f = rwth_transforms.ilaplace_Hf(f, 1, pp, pz, [1], [], dB=False)
fig, ax = plt.subplots(1,1)
ax.plot(f, S1f, **rwth_plots.style_graph);
ax.set_xlabel(r'$\rightarrow f$'); ax.set_ylabel(r'$\uparrow S_1(f)$');
ax.set_xlim([-5.5,5.5]); ax.set_ylim([-0.1,0.55]); rwth_plots.grid(ax); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
$s_2(t) = -\mathrm{e}^{-bt}\cdot\epsilon(-t)$
transformiert sich zu
$S_2(p) = \frac{1}{b+p}$ mit Konvergenzbereich $\mathrm{Re}\{p\}<\mathrm{Re}\{-b\}$:
%% Cell type:code id: tags:
``` python
roc = np.array([-np.inf, -b])
fig,axs = plt.subplots(1,2, **rwth_plots.landscape)
# Laplace-Bereich
ax = axs[0]; rwth_plots.plot_lroc(ax, roc); rwth_plots.annotate_order(ax, pp, [1]);
ax.plot(np.real(pp), np.imag(pp), **rwth_plots.style_poles); ax.plot(np.real(pp), -np.imag(pp), **rwth_plots.style_poles)
ax.set_xlabel(r'$\rightarrow \mathrm{Re}$'); ax.set_ylabel(r'$\uparrow \mathrm{Im}$');
ax.set_xlim(-5, 5); ax.set_ylim(-5, 5); rwth_plots.axis(ax); rwth_plots.grid(ax)
# Zeitbereich
s2, _, _ = rwth_transforms.ilaplace_ht(t, 1, pp, pz, [1], [], roc)
ax = axs[1]; ax.plot(t, np.real(s2), **rwth_plots.style_graph);
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s_2(t)$');
ax.set_ylim([-45,5]); rwth_plots.grid(ax); rwth_plots.axis(ax)
```
%% Cell type:markdown id: tags:
Da in diesem Fall der Konvergenzbereich links vom linkesten Pol liegt und somit nicht die imaginäre Achse beinhaltet, existiert die Fouriertransformierte nicht.
Eine ausführlichere Demo zur Laplacetransformation findet man [hier](GDET3%20Laplace-Transformation%20GUI.ipynb).
%% Cell type:markdown id: tags:
___
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Emin Kosar, Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......
%% Cell type:code id: tags:
``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
highlight_args = {'color':'rwth:red', 'marker':'o'}; arrow_args = {'width':1,'headlength':10,'headwidth':10,'fc':'rwth:red'}
anno_args = {'color':'rwth:red-50', 'linestyle':'--', 'arrowstyle':"-", 'coordsA':'data', 'coordsB':'data'}
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Primer Komplexe Zahlen
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
%% Cell type:markdown id: tags:
## Einleitung
Eine komplexe Zahl kann auch als Zeiger interpretiert werden, der sich in einer komplexen Ebene um den Koordinatenursprung dreht. Dies soll hier kurz veranschaulicht werden.
Als Beispiel wird eine reellwertige Wechselspannung
$$
u(t)
=
B \cos(2\pi F t + \phi)
$$
mit Frequenz $F$ und Scheitelwert $B$ betrachtet. Mit dem Spannungszeiger
$$
\mathbf{u}
=
B \mathrm{e}^{\mathrm{j} \phi}
$$
kann $u(t)$ wie folgt beschrieben werden:
$$
u(t)
=
\mathrm{Re}\left\{
\mathbf{u} \cdot \mathrm{e}^{\mathrm{j}2\pi F t}
\right\}
=
\mathrm{Re}\left\{
B \mathrm{e}^{\mathrm{j} \phi} \cdot \mathrm{e}^{\mathrm{j}2\pi F t}
\right\}
=
B \cos(2\pi F t + \phi)
\text{.}$$
Im Folgenden wird $B=F=1$ betrachtet.
%% Cell type:markdown id: tags:
## Demo Zeigerdiagramm
In dieser Demo wird die Interpretation einer komplexen Zahl als Zeiger deutlich gemacht. Die Länge des Zeigers ist konstant. Durch Verschieben des Schiebereglers kann die Phase $\phi$ von
$$
u(t)
=
\mathrm{Re}\left\{
B \mathrm{e}^{\mathrm{j} \phi} \cdot \mathrm{e}^{\mathrm{j}2\pi F t}
\right\}
=
B \cos(2\pi F t + \phi)
\qquad
\text{mit }
\mathbf{u}
=
B \mathrm{e}^{\mathrm{j} \phi}
$$
variiert werden, dies bewirkt eine Drehung des Drehzeigers.
Links oben ist der komplexe Drehzeiger dargestellt, rechts davon die Abbildung des aktuellen Zeigers auf die imaginäre Achse, unten die auf die reelle Achse.
Des Weiteren interessant ist das Verhalten der Phase, welches in der vierten Abbildung dargestellt wird. Die Phase ist definiert als
$$
\varphi(t)=\mathrm{arctan}\frac{\mathrm{Im}\{\mathbf{u}\}}{\mathrm{Re}\{\mathbf{u}\}}\pm k\cdot \pi \quad \text{mit}\quad k=\left\{
\begin{array}{l l}
0, \quad \text{für } \mathrm{Re}\{\mathbf{u}\}\geq 0 \\
1, \quad \text{für } \mathrm{Re}\{\mathbf{u}\}< 0
\end{array}
\right\}\text{.}
$$
Hierbei muss beachtet werden, in welchem Quadrant sich der Zeiger aktuell befindet, je nachdem muss das Plus oder das Minus in der Gleichung berücksichtigt werden. Ist der Realteil positiv, befindet sich der Zeiger im ersten oder vierten Quadranten und die Phase läuft entlang der mittleren Linie im Plot. Ist der Realteil negativ, also wenn der Zeiger im zweiten oder dritten Quadranten ist, befindet man sich auf einer der beiden anderen Kurven. Dies ist abhängig vom Imaginärteil. Befindet sich der Zeiger im zweiten Quadranten, ist der Imaginärteil positiv und in der Formel muss $+\pi$ gerechnet werden. Befindet sich der Zeiger im dritten Quadranten, ist der Imaginärteil negativ und in der Formel muss $-\pi$ gerechnet werden.
Dieses Springen kann sehr schön in der Abbildung verfolgt werden.
%% Cell type:code id: tags:
``` python
t = np.linspace(-2,2,5001);
x = np.linspace(-10,10,5001);
F = 1; B = 1;
fig,axs=plt.subplots(2,2,figsize=(6, 6)); fig.tight_layout();
@widgets.interact(phiPi = widgets.FloatSlider(min=-5, max=5, step=0.05, value=0,
description='$\phi/\pi$:', continuous_update=True),
show_lines = widgets.Checkbox(value=True, description='Zeige Hilfslinien', style=rwth_plots.wdgtl_style))
def update_plot(phiPi, show_lines):
global u_versor
phi = phiPi*np.pi
u_versor = B*np.exp(1J*phi)
u_compl = u_versor * np.exp(2J*F*np.pi*t)
ur = np.real(u_versor); ui = np.imag(u_versor)
ku = (ur<0)*(-1)**(ui<0)
xyP = (ur, ui); xyR = (ur, 0); xyI = (0, ui);
if not axs[0,0].lines: # create plots
# Complex number at time t0
ax = axs[0,0]; rwth_plots.axis(ax); ax.axis('equal'); ax00 = ax;
an = np.linspace(0, 2 * np.pi, 100); ax.plot(np.cos(an), np.sin(an), 'rwth:black-50')
ax.annotate("", xy=(np.real(u_versor),np.imag(u_versor)), xytext=(0, 0), arrowprops=arrow_args)
ax.set_xlabel(r'$\rightarrow \mathrm{Re}\{\mathbf{u} \}$'); ax.set_ylabel(r'$\uparrow \mathrm{Im}\{\mathbf{u}\}$')
# Imaginary part
ax = axs[0,1]; ax.plot(t, np.imag(u_compl), 'rwth:black-50'); ax.plot(0, np.imag(u_versor), **highlight_args); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow \mathrm{Im}\left\{\mathbf{u} \cdot \mathrm{e}^{\mathrm{j}2\pi F t}\right\}$'); ax.set_zorder(-1)
# Real part
ax = axs[1,0]; ax.plot(np.real(u_compl),t, 'rwth:black-50'); ax.plot(np.real(u_versor), 0, **highlight_args); rwth_plots.axis(ax);
ax.set_ylabel(r'$\downarrow t$'); ax.set_xlabel(r'$\rightarrow u(t) = \mathrm{Re}\left\{\mathbf{u} \cdot \mathrm{e}^{\mathrm{j}2\pi F t}\right\}$', bbox=rwth_plots.wbbox);
ax.invert_yaxis(); ax.set_zorder(-1)
# Angle
ax = axs[1,1]; rwth_plots.axis(ax);
ax.plot(x, np.arctan(x), 'rwth:blue');
x_ind = np.where(x>0); x_ind = x_ind[0][0]; tmp = np.arctan(x)+np.pi; tmp[x_ind:] = np.nan; ax.plot(x, tmp, 'rwth:blue')
x_ind = np.where(x<0); x_ind = x_ind[0][-1]; tmp = np.arctan(x)-np.pi; tmp[:x_ind] = np.nan; ax.plot(x, tmp, 'rwth:blue')
ax.plot(np.imag(u_versor)/np.real(u_versor), phi, **highlight_args);
ax.set_xlim([-7.5,7.5])
ax.set_xlabel(r'$\rightarrow \mathrm{Im} / \mathrm{Re}$'); ax.set_ylabel(r'$\uparrow \angle\{\mathbf{u}\}$');
ax.set_yticks([-np.pi, -np.pi/2, np.pi/2, np.pi]); ax.yaxis.set_ticklabels([r'$-\pi$',r'$-\pi/2$',r'$\pi/2$', r'$\pi$'])
#fig.tight_layout(); # hide last axis and tighten layout
else: # update plots
annotations = [child for child in axs[0,0].get_children() if isinstance(child, matplotlib.text.Annotation)]
annotations[0].remove()
axs[0,0].annotate("", xy=(np.real(u_versor),np.imag(u_versor)), xytext=(0, 0), arrowprops=arrow_args)
axs[0,1].lines[0].set_ydata(np.imag(u_compl)); axs[0,1].lines[1].set_ydata(np.imag(u_versor))
axs[1,0].lines[0].set_xdata(np.real(u_compl)); axs[1,0].lines[1].set_xdata(np.real(u_versor))
axs[1,1].lines[3].set_ydata(np.arctan(ui/ur)+ku*np.pi); axs[1,1].lines[3].set_xdata(ui / ur)
annotations = [child for child in axs[0,0].get_children() if isinstance(child, matplotlib.patches.ConnectionPatch)]
if len(annotations): annotations[0].remove(); annotations[1].remove();
if show_lines:
con = ConnectionPatch(xyA=xyP, xyB=xyI, axesA=axs[0,0], axesB=axs[0,1],**anno_args); axs[0,0].add_artist(con)
con = ConnectionPatch(xyA=xyP, xyB=xyR, axesA=axs[0,0], axesB=axs[1,0],**anno_args); axs[0,0].add_artist(con)
axs[1,0].set_xlim(axs[0,0].get_xlim()); axs[0,1].set_ylim(axs[0,0].get_ylim())
```
%% Cell type:markdown id: tags:
___
This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources) (OER). Feel free to use the notebook for your own purposes. The code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
Please attribute the work as follows:
*Christian Rohlfing, Übungsbeispiele zur Vorlesung "Grundgebiete der Elektrotechnik 3 - Signale und Systeme"*, gehalten von Jens-Rainer Ohm, 2020, Institut für Nachrichtentechnik, RWTH Aachen University.
......