Commit 04bc17ab authored by Hafiz Emin Kosar's avatar Hafiz Emin Kosar
Browse files

- updated copyright and added separation line to each notebook

parent bb5be608
%% 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 scipy as sp
import scipy.special
import scipy.signal
from ient_nb.ient_plots import *
from ient_nb.ient_signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Auto- und Kreuzkorrelationsfunktion von Energiesignalen
## 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=ient_wdgtl_style),
s_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=ient_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=ient_wdgtl_style),
g_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=ient_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');
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]); ient_axis(ax); ient_grid(ax);
ax = axs0[1]; ax.plot(t, g(t), 'rwth');
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()); ient_axis(ax); ient_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)));
ient_update_ylim(axs[0], np.concatenate((g(t), s(t))), 0.19, 5); ient_update_ylim(axs[1], phi_sg, 0.19, 5);
update_plot(-2); # update correlation plot
except: pass
ient_update_ylim(axs0[0], s(t), 0.19, 5); ient_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,6),) # gridspec_kw = {'width_ratios':[3, 1]}
@widgets.interact(tau_shft=widgets.FloatSlider(min=-4, max=4, value=-2, step=.1, description=r'Verschiebung $\tau$', style=ient_wdgtl_style),
show_integrand=widgets.Checkbox(value=True, description='Zeige Integrand', style=ient_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', label=r'$g(t)$'); # plot g(t)
ax.plot(t, np.conj(s(t-tau_shft)), 'grun', label=r'$s^\ast(t-\tau)$'); # plot s(t-tau)
ax.plot(t, sg, '--', color='orange', lw=1, label=r'$g(t)s^\ast(t-\tau)$'); # plot integrand
ient_annotate_xtick(ax, r'$\tau$', tau_shft, -0.1, 'rwth', 15); # mark t on tau axis
ax.fill_between(t, 0, sg, facecolor="none", hatch="//", edgecolor='k', linewidth=0.0); # hatch common area
ax.set_xlabel(r'$\rightarrow t$');
ax.set_xlim([-4.2,4.2]); ient_update_ylim(ax, np.concatenate((g(t), s(t))), 0.19, 5);
ax.legend(); ient_grid(ax); ient_axis(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()); ient_update_ylim(ax, phi_sg, 0.19, 5);
ient_axis(ax); ient_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='k', 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, 2019, Institut für Nachrichtentechnik, RWTH Aachen University.
*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, HBox, VBox
from IPython.display import clear_output, display, HTML
from scipy import signal # convolution
from ient_nb.ient_plots import *
from ient_nb.ient_signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Demonstrator Diskrete Faltung
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
%% Cell type:markdown id: tags:
## Einleitung
Ein diskretes Signal ist ein Signal, welches nur für ganzzahlige Werte $n$ einen Wert annimmt und sonst Null ist. Auch für die Elementarsignale existieren jeweils zeitdiskrete Versionen. Diese Demonstration nutzt einige davon.
Diskrete Signale können genau wie kontinuierliche Signale gefaltet werden.
Im Folgenden wird die diskrete Faltung
$$g(n)=s(n)\ast h(n)=\sum_{m=-\infty}^{\infty}s(m)h(n-m)$$
betrachtet und veranschaulicht.
## Demo
In der Demonstration stehen verschiedene Signale für $s(n)$ und $h(n)$ zur Verfügung.
$s(n)$ und $h(n)$ können gewählt werden als zeitdiskrete Varianten von:
* Dirac-Impuls $\delta(n)$
* Sprungfunktion $\epsilon(n)$
* Exponentialimpuls $\epsilon(n)\cdot\mathrm{b}^{n}$
* Rechteckfunktion $rect(n) = \epsilon(n+M)-\epsilon(n-M-1)$
* Eigene Kreation
Unter der folgenden Abbildungen können diese Funktionen ausgewählt werden und, falls gewünscht, eine Verschiebung um $n_0$ eingestellt werden. Für den Exponentialimpuls ist ebenfalls der Faktor $b$ variierbar, für die Rechteckfunktion ist die Breite $M$ wählbar. In der Abbildung können dann die gewählten Funktionen mit ihren Parametern betrachtet werden.
Zusätzlich zu Elementarsignalen kann auch eine frei definierbare Funktion $s_0(n)$ zur Faltung verwendet werden.
%% Cell type:code id: tags:
``` python
s_0 = lambda n: gauss(n)*unitstep(n)
```
%% Cell type:code id: tags:
``` python
n = np.linspace(-10, 10, 21)
m = np.linspace(-40, 40, 81) # m Achse
n0 = -2
container_s = container_h = None
def convolution(s, h):
# Convolve s and h numerically
return signal.convolve(s(m), h(m), mode='same')
signal_types = {'Dirac-Impuls' : lambda n, b, M: np.where(n==0, 1, 0),
'Sprungfunktion' : lambda n, b, M: np.where(n>=0, 1, 0),
'Exponentialimpuls' : lambda n, b, M: unitstep(n)*b**n,
'Rechteck' : lambda n, b, M: unitstep(n+M) - unitstep(n-M-1),
'Eigene Kreation s0(n)' : lambda n, b, M: s_0(n)
}
fig0, axs0 = plt.subplots(1, 2, figsize=(ient_fig_width, ient_fig_width/4));
def update_signals(s_type, s_n0, h_type, h_n0, b_s, b_h, M_s, M_h):
# show widgets according to chosen s and h
w_b_s.layout.visibility = 'visible' if s_type == 'Exponentialimpuls' else 'hidden'; w_M_s.layout.visibility = 'visible' if s_type == 'Rechteck' else 'hidden'
w_b_h.layout.visibility = 'visible' if h_type == 'Exponentialimpuls' else 'hidden'; w_M_h.layout.visibility = 'visible' if h_type == 'Rechteck' else 'hidden'
# calculate s(m-n0) and h(m-n0)
global s, h, gn, container_s, container_h # reused in second interactive plot
s = lambda m: signal_types[s_type]((m-s_n0), b_s, M_s); # s(m-n0)
h = lambda m: signal_types[h_type]((m-h_n0), b_h, M_h); # h(m-n0)
gn = convolution(s, h) # numerical convolution
# update second plot if existing
try:
global n0
update_plot(n0)
except NameError:
pass
# display s and h plots
if container_s is None:
# plot s
ax = axs0[0];
container_s = ient_stem(ax, m, s(m), 'rwth')
ax.set_xticks(np.arange(-10, 11, step=2))
ax.set_xlabel(r'$\rightarrow n$'); ax.set_ylabel(r'$\uparrow s(n)$')
ax.set_xlim([-10.9, 10.9]); ient_axis(ax); ient_grid(ax);
# plot h
ax = axs0[1];
container_h = ient_stem(ax, m, h(m), 'rwth')
ax.set_xticks(np.arange(-10, 11, step=2))
ax.set_xlabel(r'$\rightarrow n$'); ax.set_ylabel(r'$\uparrow h(n)$')
ax.set_xlim(axs0[0].get_xlim()); ient_axis(ax); ient_grid(ax);
else:
ient_stem_set_ydata(container_s, s(m))
ient_stem_set_ydata(container_h, h(m))
# update limits
ient_update_ylim(axs0[0], s(m), .19)
ient_update_ylim(axs0[1], h(m), .19)
# Widgets
w_s_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $s(n)$:', style=ient_wdgtl_style)
w_s_n0=widgets.FloatSlider(min=-5, max=5, value=0, step=1, description=r'Verschiebung $n_0$', style=ient_wdgtl_style)
w_h_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $h(n)$:', style=ient_wdgtl_style)
w_h_n0=widgets.FloatSlider(min=-5, max=5, value=0, step=1, description=r'Verschiebung $n_0$', style=ient_wdgtl_style)
w_b_s=widgets.FloatSlider(min=.1, max=1, value=.5, step=.1, description=r'$b_s$', style=ient_wdgtl_style)
w_b_h=widgets.FloatSlider(min=.1, max=1, value=.5, step=.1, description=r'$b_h$', style=ient_wdgtl_style)
w_M_s=widgets.FloatSlider(min=0, max=5, value=1, step=1, description=r'$M_s$', style=ient_wdgtl_style)
w_M_h=widgets.FloatSlider(min=0, max=5, value=1, step=1, description=r'$M_h$', style=ient_wdgtl_style)
w = widgets.interactive(update_signals, s_type=w_s_type, s_n0=w_s_n0, h_type=w_h_type, h_n0 =w_h_n0, b_s=w_b_s, b_h=w_b_h, M_s=w_M_s, M_h=w_M_h)
display(widgets.HBox((widgets.VBox((w_s_type, w_s_n0, w_b_s, w_M_s)), widgets.VBox((w_h_type, w_h_n0, w_b_h, w_M_h), layout=Layout(margin='0 0 0 100px'))))); w.update();
```
%% Cell type:markdown id: tags:
Anschließend kann hier die Faltung $g(n)=s(n)\ast h(n)$ der zuvor eingestellten Funktionen betrachtet werden.
Über den Schieberegler kann der Wert für $n$ verändert werden und die Funktion $h(n-m)$ bewegt sich in der oberen Grafik. In der unteren Grafik ist das resultierende Ausgangssignal $g(n)$ zu sehen.
%% Cell type:code id: tags:
``` python
fig, axs = plt.subplots(2, 1, **ient_landscape)
global n0
container_ss = container_hh = container_gg = None
@widgets.interact(n=widgets.FloatSlider(min=-10, max=10, value=n0, step=1, description='Verschiebung $n$', style=ient_wdgtl_style))
def update_plot(n):
global container_ss, container_hh, container_gg
global n0
n0 = n
n_ind = np.where(m>=n); n_ind = n_ind[0][0]; g_plot = gn.copy(); g_plot[n_ind+1:] = 0; # hide g(n') with n'>n
if container_gg is None:
# plot g = s * h
ax = axs[1]
container_gg = ient_stem(ax, m, g_plot)
if container_ss is not None:
# update data
ient_stem_set_ydata(container_ss, s(m))
ient_stem_set_ydata(container_hh, h(n-m))
ient_stem_set_ydata(container_gg, g_plot)
# update labels
ax = axs[0]
ax.texts[0].set_x(n); ax.lines[3].set_xdata([n,n])
ax = axs[1]
ax.texts[0].set_x(n); ax.lines[2].set_xdata([n,n]); ax.texts[0].set_y(np.min(ax.get_ylim()));
ax.lines[3].set_xdata([n, n]); ax.lines[3].set_ydata([0, gn[n_ind]]);
else:
# plot s and h
ax = axs[0]; # s and h axis
container_ss = ient_stem(ax, m, s(m), 'grun', label=r'$s(m)$')
container_ss[0].set_markerfacecolor('none');
container_ss[0].set_markersize(8);
container_ss[0].set_markeredgewidth(2);
container_hh = ient_stem(ax, m, h(n-m), 'rwth', label=r'$h(n-m)$')
# configure axis settings
ax.set_xlabel(r'$\rightarrow m$');
ax.set_xlim([-10.2,10.2]);
ax.set_xticks(np.arange(-10, 11, step=2))
ax.legend(); ient_grid(ax); ient_axis(ax);
ient_annotate_xtick(ax, r'$n$', n, -0.1, 'rwth', 15); # mark n on m axis
# configure g axis settings
ax = axs[1]
ax.set_xlabel(r'$\rightarrow n$'); ax.set_ylabel(r'$\uparrow g(n)=s(n)\ast h(n)$');
ax.set_xlim(axs[0].get_xlim())
ax.set_xticks(np.arange(-10, 11, step=2))
ient_grid(ax); ient_axis(ax);
ient_annotate_xtick(ax, r'$n$', n, np.min(ax.get_ylim()), 'black', 15);
ax.plot([n, n], [0, gn[n_ind]], 'ko--', lw=1);
# update limits
if np.all(gn>0):
gn[0] = 0
ient_update_ylim(axs[0], np.concatenate([s(m), h(n-m)]), .19, ymax = 1e3)
ient_update_ylim(axs[1], gn, np.max(np.abs(gn))/10, ymax = 1e3)
```
%% Cell type:markdown id: tags:
## Aufgaben
Wähle zunächst für $s(n)$ den Dirac-Impuls und für $h(n)$ verschiedene Funktionen aus.
* Beobachte das Faltungsergebnis. Ab welchem $n$ ist ein Ergebnis zu sehen? Was passiert, wenn du eine der Funktionen verschiebst?
* Wie sieht das Ergebnis für zwei Rechteckfunktionen aus? Wie für zwei Sprungfunktionen?
Wähle nun zwei Rechteckfunktionen mit $M>2$.
* Bewege den Schieberegler langsam von links nach rechts. An welcher Stelle tritt der erste Wert des Faltungsergebnisses auf? Wie hoch ist dieser Wert?
* Bewege den Schieberegler eins weiter nach rechts. Nun überlagern sich die beiden Signalen an zwei Positionen. Wie hoch ist der Wert des Faltungsergebnisses nun?
* Bewege den Schieberegler weiter, bis die beiden Funktionen sich vollständig überlagern. Was passiert, wenn nun der Schieberegler weiter nach rechts geschoben wird? Wie hoch ist der Wert des Faltungsergebnisses?
%% 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, Emin Kosar, Ü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 2019 Institut für Nachrichtentechnik, RWTH Aachen University
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ient_nb.ient_plots import *
```
%% Cell type:markdown id: tags:
<div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Diskrete Fourier-Transformation
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()
ient_stem(ax, n, sd, 'rwth')
ax.set_xlabel(r'$\rightarrow n$', bbox=ient_wbbox); ax.set_ylabel(r'$\uparrow s_\mathrm{d}(n)$', bbox=ient_wbbox);
ax.set_ylim([-0.09,1.09]); ient_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()
ient_stem(ax, k, Sd, 'rwth')
ax.set_xlabel(r'$\rightarrow k$', bbox=ient_wbbox); ax.set_ylabel(r'$\uparrow S_\mathrm{d}(k)$', bbox=ient_wbbox);
ax.set_ylim([-1.9,7.9]); ient_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]; ient_stem(ax,k,Gd, 'rwth')
ax.set_xlabel(r'$\rightarrow k$', bbox=ient_wbbox); ax.set_ylabel(r'$\uparrow G_\mathrm{d}(k)$', bbox=ient_wbbox);
ax.set_ylim([-1,59]); ient_axis(ax)
ax = axs[1]; ient_stem(ax,n,gd, 'rwth')
ax.set_xlabel(r'$\rightarrow n$', bbox=ient_wbbox); ax.set_ylabel(r'$\uparrow g_\mathrm{d}(n)$', bbox=ient_wbbox);
ax.set_ylim([-0.09,8.9]); ient_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, 2019, Institut für Nachrichtentechnik, RWTH Aachen University.
*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 2019 Institut für Nachrichtentechnik, RWTH Aachen University
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget
from ipywidgets import interact, interactive
import ipywidgets as widgets
from ient_nb.ient_plots import *
from ient_nb.ient_signals import *
```
%% Cell type:markdown id: tags:
<div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Elementarsignale
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');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\mathrm{e}^{-\pi t^2}$', bbox=ient_wbbox)
ax.axis('equal'); ax.set_xlim([-2.75, 2.75]); ient_grid(ax); ient_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');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)=\epsilon(t)$', bbox=ient_wbbox)
ax.axis('equal'); ax.set_xlim([-2.25,2.25]); ient_grid(ax); ient_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}$