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: %% Cell type:code id: tags:
``` python ``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University # Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget %matplotlib widget
import ipywidgets as widgets import ipywidgets as widgets
from ipywidgets import interact, interactive from ipywidgets import interact, interactive
import scipy as sp import scipy as sp
import scipy.special import scipy.special
import scipy.signal import scipy.signal
from ient_nb.ient_plots import * from ient_nb.ient_plots import *
from ient_nb.ient_signals import * from ient_nb.ient_signals import *
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<div> <div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;"> <img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div> </div>
# Auto- und Kreuzkorrelationsfunktion von Energiesignalen # Auto- und Kreuzkorrelationsfunktion von Energiesignalen
## Einleitung ## Einleitung
### Energiesignal ### Energiesignal
Ein Signal $s(t)$ heißt Energiesignal, wenn seine Signalenergie endlich ist, es gilt also 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{ .}$$ $$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. 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 ### 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. 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) \varphi_{sg}^\mathrm{E}(\tau)
= \int\limits_{-\infty}^\infty s^\ast(t) g(t+\tau)\mathrm{d}t = \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 \stackrel{t\rightarrow -t}{=} \int\limits_{-\infty}^\infty s(-t)^\ast g(\tau-t) \mathrm{d} t
= s^\ast(-\tau) \ast g(\tau) = s^\ast(-\tau) \ast g(\tau)
= \left[\varphi_{gs}^\mathrm{E}(-\tau)\right]^\ast = \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. 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. 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 ### 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 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) \varphi_{ss}^\mathrm{E}(\tau)
= \int\limits_{-\infty}^\infty s^\ast(t) s(t+\tau)\mathrm{d}t \text{.} = \int\limits_{-\infty}^\infty s^\ast(t) s(t+\tau)\mathrm{d}t \text{.}
$$ $$
Die Autokorrelationsfunktion besitzt folgende allgemeingültige Eigenschaften: Die Autokorrelationsfunktion besitzt folgende allgemeingültige Eigenschaften:
* Die Autokorrelationsfunktion ist immer eine gerade Funktion. * 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. * 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 * Das Maximum der Autokorrelationsfunktion eines Energiesignals ist gleich seiner Energie
$$\varphi_{ss}^\mathrm{E}(0)=E_s \text{.}$$ $$\varphi_{ss}^\mathrm{E}(0)=E_s \text{.}$$
* Bei zeitlich begrenzten Signalen hat die Autokorrelationsfunktion die doppelte Breite des Signals. * Bei zeitlich begrenzten Signalen hat die Autokorrelationsfunktion die doppelte Breite des Signals.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Interaktive Demo ## Interaktive Demo
Die interaktive Demo ermöglicht es, sich die Kreuz- und Autokorrelation für verschiedene Signale anzusehen. Die interaktive Demo ermöglicht es, sich die Kreuz- und Autokorrelation für verschiedene Signale anzusehen.
$$ $$
\varphi_{sg}^\mathrm{E}(\tau) \varphi_{sg}^\mathrm{E}(\tau)
= s^\ast(-\tau) \ast g(\tau) = s^\ast(-\tau) \ast g(\tau)
= g(\tau) \ast s^\ast(-\tau) = g(\tau) \ast s^\ast(-\tau)
= \int\limits_{-\infty}^\infty g(t) s^\ast(t-\tau) \mathrm{d} t = \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. Es ist auch möglich, eine eigene Funktion $s_0(t)$ zu definieren.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
s_0 = lambda t: rect(t/2-1/2)*(-t) s_0 = lambda t: rect(t/2-1/2)*(-t)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def correlation(s, g): def correlation(s, g):
# Correlate s and g numerically # Correlate s and g numerically
return sp.signal.convolve(np.conj(s(-t)),g(t), mode='full')*deltat return sp.signal.convolve(np.conj(s(-t)),g(t), mode='full')*deltat
fs = 2000 # Samplingrate fs = 2000 # Samplingrate
(t,deltat) = np.linspace(-8,8, 16*fs, retstep=True) # Zeitachse (t,deltat) = np.linspace(-8,8, 16*fs, retstep=True) # Zeitachse
(tau,deltatau) = np.linspace(-16,16, 2*len(t)-1, retstep=True) # Korrelation (tau,deltatau) = np.linspace(-16,16, 2*len(t)-1, retstep=True) # Korrelation
signal_types = {'Rechteck' : rect, signal_types = {'Rechteck' : rect,
'Dreieck' : tri, 'Dreieck' : tri,
'Sprungfunktion' : unitstep, 'Sprungfunktion' : unitstep,
'si-Funktion' : lambda t: si(t*np.pi), 'si-Funktion' : lambda t: si(t*np.pi),
'Exponentialimpuls' : lambda t: unitstep(t)*np.exp(-t), 'Exponentialimpuls' : lambda t: unitstep(t)*np.exp(-t),
'Gauß-Signal' : gauss, 'Gauß-Signal' : gauss,
'Doppelrechteck' : lambda t: rect(t*2+0.5)-rect(t*2-0.5), 'Doppelrechteck' : lambda t: rect(t*2+0.5)-rect(t*2-0.5),
'Rampe' : lambda t: t*rect(t-0.5), 'Rampe' : lambda t: t*rect(t-0.5),
'Versch. Rechteck' : lambda t: -rect(t-0.5), 'Versch. Rechteck' : lambda t: -rect(t-0.5),
'Eigene Kreation' : s_0, 'Eigene Kreation' : s_0,
} }
``` ```
%% Cell type:markdown id: tags: %% 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. 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: %% Cell type:code id: tags:
``` python ``` python
fig0, axs0 = plt.subplots(1, 2, figsize=(8,2)) 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)$:'), @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_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), 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_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_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)) 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): 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 global s, g, phi_sg # reused in second interactive plot
s = lambda t: signal_types[s_type]((t-s_t0)/s_T); s = lambda t: signal_types[s_type]((t-s_t0)/s_T);
g = lambda t: signal_types[g_type]((t-g_t0)/g_T); g = lambda t: signal_types[g_type]((t-g_t0)/g_T);
phi_sg = correlation(s, g) # numerical correlation phi_sg = correlation(s, g) # numerical correlation
if not axs0[0].lines: # plot s(t) and g(t) if not axs0[0].lines: # plot s(t) and g(t)
ax = axs0[0]; ax.plot(t, s(t), 'rwth'); ax = axs0[0]; ax.plot(t, s(t), 'rwth');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow s(t)$') 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.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 = axs0[1]; ax.plot(t, g(t), 'rwth');
ax.set_xlabel(r'$\rightarrow t$'); ax.set_ylabel(r'$\uparrow g(t)$') 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); ax.set_xlim(axs0[0].get_xlim()); ax.set_ylim(axs0[0].get_ylim()); ient_axis(ax); ient_grid(ax);
else: # update lines else: # update lines
axs0[0].lines[0].set_ydata(s(t)); axs0[0].lines[0].set_ydata(s(t));
axs0[1].lines[0].set_ydata(g(t)); axs0[1].lines[0].set_ydata(g(t));
try: # if convolution figure is already opened, update s(t) try: # if convolution figure is already opened, update s(t)
if axs[0].lines: if axs[0].lines:
axs[0].lines[0].set_ydata((g(t))); 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); 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 update_plot(-2); # update correlation plot
except: pass except: pass
ient_update_ylim(axs0[0], s(t), 0.19, 5); ient_update_ylim(axs0[1], g(t), 0.19, 5); 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: %% 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. 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: %% Cell type:code id: tags:
``` python ``` python
fig, axs=plt.subplots(2, 1, figsize=(8,6),) # gridspec_kw = {'width_ratios':[3, 1]} 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), @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)) show_integrand=widgets.Checkbox(value=True, description='Zeige Integrand', style=ient_wdgtl_style))
def update_plot(tau_shft, show_integrand=True): 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 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 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 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 = 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, 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 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 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.fill_between(t, 0, sg, facecolor="none", hatch="//", edgecolor='k', linewidth=0.0); # hatch common area
ax.set_xlabel(r'$\rightarrow t$'); 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.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.legend(); ient_grid(ax); ient_axis(ax);
ax = axs[1]; ax.plot(tau, phi_plot); # plot phi_sg(tau) 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.plot([tau_shft, tau_shft], [0, phi_sg[tau_ind]], 'ko--', lw=1);
ax.set_xlabel(r'$\rightarrow \tau$'); 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_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); 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(); ient_axis(ax); ient_grid(ax); fig.tight_layout();
else: # Replace only xdata and ydata since plt.plot() takes longer time 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 = 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 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 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); 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 = 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 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) axs[0].lines[2].set_visible(show_integrand)
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Aufgaben ## 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. * 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? * 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? * 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: %% 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). 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: 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: %% Cell type:code id: tags:
``` python ``` python
# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University # Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University
%matplotlib widget %matplotlib widget
import ipywidgets as widgets import ipywidgets as widgets
from ipywidgets import interact, interactive, fixed, Layout, HBox, VBox from ipywidgets import interact, interactive, fixed, Layout, HBox, VBox
from IPython.display import clear_output, display, HTML from IPython.display import clear_output, display, HTML
from scipy import signal # convolution from scipy import signal # convolution
from ient_nb.ient_plots import * from ient_nb.ient_plots import *
from ient_nb.ient_signals import * from ient_nb.ient_signals import *
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<div> <div>
<img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;"> <img src="ient_nb/figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div> </div>
# Demonstrator Diskrete Faltung # Demonstrator Diskrete Faltung
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen. Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Einleitung ## 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. 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. Diskrete Signale können genau wie kontinuierliche Signale gefaltet werden.
Im Folgenden wird die diskrete Faltung Im Folgenden wird die diskrete Faltung
$$g(n)=s(n)\ast h(n)=\sum_{m=-\infty}^{\infty}s(m)h(n-m)$$ $$g(n)=s(n)\ast h(n)=\sum_{m=-\infty}^{\infty}s(m)h(n-m)$$
betrachtet und veranschaulicht. betrachtet und veranschaulicht.
## Demo ## Demo
In der Demonstration stehen verschiedene Signale für $s(n)$ und $h(n)$ zur Verfügung. 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: $s(n)$ und $h(n)$ können gewählt werden als zeitdiskrete Varianten von:
* Dirac-Impuls $\delta(n)$ * Dirac-Impuls $\delta(n)$
* Sprungfunktion $\epsilon(n)$ * Sprungfunktion $\epsilon(n)$
* Exponentialimpuls $\epsilon(n)\cdot\mathrm{b}^{n}$ * Exponentialimpuls $\epsilon(n)\cdot\mathrm{b}^{n}$
* Rechteckfunktion $rect(n) = \epsilon(n+M)-\epsilon(n-M-1)$ * Rechteckfunktion $rect(n) = \epsilon(n+M)-\epsilon(n-M-1)$
* Eigene Kreation * 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. 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. Zusätzlich zu Elementarsignalen kann auch eine frei definierbare Funktion $s_0(n)$ zur Faltung verwendet werden.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
s_0 = lambda n: gauss(n)*unitstep(n) s_0 = lambda n: gauss(n)*unitstep(n)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
n = np.linspace(-10, 10, 21) n = np.linspace(-10, 10, 21)
m = np.linspace(-40, 40, 81) # m Achse m = np.linspace(-40, 40, 81) # m Achse
n0 = -2 n0 = -2
container_s = container_h = None container_s = container_h = None
def convolution(s, h): def convolution(s, h):
# Convolve s and h numerically # Convolve s and h numerically
return signal.convolve(s(m), h(m), mode='same') return signal.convolve(s(m), h(m), mode='same')
signal_types = {'Dirac-Impuls' : lambda n, b, M: np.where(n==0, 1, 0), 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), 'Sprungfunktion' : lambda n, b, M: np.where(n>=0, 1, 0),
'Exponentialimpuls' : lambda n, b, M: unitstep(n)*b**n, 'Exponentialimpuls' : lambda n, b, M: unitstep(n)*b**n,
'Rechteck' : lambda n, b, M: unitstep(n+M) - unitstep(n-M-1), 'Rechteck' : lambda n, b, M: unitstep(n+M) - unitstep(n-M-1),
'Eigene Kreation s0(n)' : lambda n, b, M: s_0(n) '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)); 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): 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 # 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_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' 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) # calculate s(m-n0) and h(m-n0)
global s, h, gn, container_s, container_h # reused in second interactive plot 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) 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) h = lambda m: signal_types[h_type]((m-h_n0), b_h, M_h); # h(m-n0)
gn = convolution(s, h) # numerical convolution gn = convolution(s, h) # numerical convolution
# update second plot if existing # update second plot if existing
try: try:
global n0 global n0
update_plot(n0) update_plot(n0)
except NameError: except NameError:
pass pass
# display s and h plots # display s and h plots
if container_s is None: if container_s is None:
# plot s # plot s
ax = axs0[0]; ax = axs0[0];
container_s = ient_stem(ax, m, s(m), 'rwth') container_s = ient_stem(ax, m, s(m), 'rwth')
ax.set_xticks(np.arange(-10, 11, step=2)) ax.set_xticks(np.arange(-10, 11, step=2))
ax.set_xlabel(r'$\rightarrow n$'); ax.set_ylabel(r'$\uparrow s(n)$') 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); ax.set_xlim([-10.9, 10.9]); ient_axis(ax); ient_grid(ax);
# plot h # plot h
ax = axs0[1]; ax = axs0[1];
container_h = ient_stem(ax, m, h(m), 'rwth') container_h = ient_stem(ax, m, h(m), 'rwth')
ax.set_xticks(np.arange(-10, 11, step=2)) ax.set_xticks(np.arange(-10, 11, step=2))
ax.set_xlabel(r'$\rightarrow n$'); ax.set_ylabel(r'$\uparrow h(n)$') 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); ax.set_xlim(axs0[0].get_xlim()); ient_axis(ax); ient_grid(ax);
else: else:
ient_stem_set_ydata(container_s, s(m)) ient_stem_set_ydata(container_s, s(m))
ient_stem_set_ydata(container_h, h(m)) ient_stem_set_ydata(container_h, h(m))
# update limits # update limits
ient_update_ylim(axs0[0], s(m), .19) ient_update_ylim(axs0[0], s(m), .19)
ient_update_ylim(axs0[1], h(m), .19) ient_update_ylim(axs0[1], h(m), .19)
# Widgets # Widgets
w_s_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $s(n)$:', style=ient_wdgtl_style) 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_s_n0=widgets.FloatSlider(min=-5, max=5, value=0, step=1, description=r'Verschiebung $n_0$', style=ient_wdgtl_style)
<