Commit 41d8534b authored by Hafiz Emin Kosar's avatar Hafiz Emin Kosar
Browse files

- typos

parent c2b5f47c
%% 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
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal # convolution
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>
# 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)$
* Sprungfunktion $\varepsilon(n)$
* Exponentialimpuls $\varepsilon(n)\cdot\mathrm{b}^{n}$
* Rechteckfunktion $rect(n) = \varepsilon(n+M)-\varepsilon(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.
Unter der folgenden Abbildung 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=(rwth_plots.fig_width, rwth_plots.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 = rwth_plots.stem(ax, m, s(m), 'rwth:blue')
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]); rwth_plots.axis(ax); rwth_plots.grid(ax);
# plot h
ax = axs0[1];
container_h = rwth_plots.stem(ax, m, h(m), 'rwth:blue')
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()); rwth_plots.axis(ax); rwth_plots.grid(ax);
else:
rwth_plots.stem_set_ydata(container_s, s(m))
rwth_plots.stem_set_ydata(container_h, h(m))
# update limits
rwth_plots.update_ylim(axs0[0], s(m), .19)
rwth_plots.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=rwth_plots.wdgtl_style)
w_s_n0=widgets.FloatSlider(min=-5, max=5, value=0, step=1, description=r'Verschiebung $n_0$', style=rwth_plots.wdgtl_style)
w_h_type=widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $h(n)$:', style=rwth_plots.wdgtl_style)
w_h_n0=widgets.FloatSlider(min=-5, max=5, value=0, step=1, description=r'Verschiebung $n_0$', style=rwth_plots.wdgtl_style)
w_b_s=widgets.FloatSlider(min=.1, max=1, value=.5, step=.1, description=r'$b_s$', style=rwth_plots.wdgtl_style)
w_b_h=widgets.FloatSlider(min=.1, max=1, value=.5, step=.1, description=r'$b_h$', style=rwth_plots.wdgtl_style)
w_M_s=widgets.FloatSlider(min=0, max=5, value=1, step=1, description=r'$M_s$', style=rwth_plots.wdgtl_style)
w_M_h=widgets.FloatSlider(min=0, max=5, value=1, step=1, description=r'$M_h$', style=rwth_plots.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, **rwth_plots.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=rwth_plots.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 = rwth_plots.stem(ax, m, g_plot)
if container_ss is not None:
# update data
rwth_plots.stem_set_ydata(container_ss, s(m))
rwth_plots.stem_set_ydata(container_hh, h(n-m))
rwth_plots.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 = rwth_plots.stem(ax, m, s(m), 'rwth:green', label=r'$s(m)$')
container_ss[0].set_markerfacecolor('none');
container_ss[0].set_markersize(8);
container_ss[0].set_markeredgewidth(2);
container_hh = rwth_plots.stem(ax, m, h(n-m), 'rwth:blue', 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(); rwth_plots.grid(ax); rwth_plots.axis(ax);
rwth_plots.annotate_xtick(ax, r'$n$', n, -0.1, 'rwth:blue', 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))
rwth_plots.grid(ax); rwth_plots.axis(ax);
rwth_plots.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
rwth_plots.update_ylim(axs[0], np.concatenate([s(m), h(n-m)]), .19, ymax = 1e3)
rwth_plots.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 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.
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
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.
%% 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, 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 *
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}
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Reale Abtastung
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
Im Gegensatz zur [idealen Abtastung](GDET3%20Ideale%20Abtastung.ipynb) werden hier zwei Verfahren zur realen Abtastung betrachtet. Tatsächlich kann nicht mit einem idealen Dirac an einem definierten Zeitpunkt abgetastet werden. Im Folgenden werden zwei Verfahren der Abtastung, die *Shape-top Abtastung* und die *Flat-top Abtastung* beschrieben.
## Shape-top Abtastung
Bei der Shape-top Abtastung wird das kontinuierliche Signal $s(t)$ mit Abstand $T=\frac{1}{r}$ abgetastet.
Anstatt einer Diracfolge wird eine Folge schmaler Rechteckimpulse mit endlicher Dauer $T_0$ verwendet. Das abgetastete Signal $s_0(t)$ ergibt sich zu
$$
s_0(t)
= s(t) \cdot \sum\limits_{n=-\infty}^\infty \mathrm{rect}\left(\frac{t-nT}{T_0}\right)
= s(t) \cdot \left[\mathrm{rect}\left(\frac{t}{T_0}\right) \ast \sum\limits_{n=-\infty}^\infty \delta(t-nT) \right].
$$
Im Frequenzbereich folgt durch Transformation
$$
S_0(f)
= S(f) \ast \left[T_0 \mathrm{si}\left(\pi T_0 f\right) \cdot \frac{1}{T}\sum_{k=-\infty}^\infty \delta(f-kr)\right]
=
S(f) \ast \left[\frac{T_0}{T} \sum_{k=-\infty}^\infty \delta\left(f-\frac{k}{T}\right) \mathrm{si} \left(\pi T_0 \frac{k}{T}\right) \right]\text{.}
$$
Auch hier entstehen wie bei der idealen Abtastung spektrale Kopien, welche um $\frac{k}{T}$ zentriert sind. Jede spektrale Kopie wird mit einem von $f$ unabhängigen Faktor $\mathrm{si} \left(\pi T_0 \frac{k}{T}\right)$ skaliert.
Der Grenzübergang $T_0\rightarrow 0$ liefert hier die ideale Abtastung: $\lim\limits_{T_0\rightarrow 0}\left(\frac{1}{T_0}s_0(t)\right) = s_\mathrm{a}(t)$.
%% Cell type:markdown id: tags:
## Flat-top Abtastung
Bei der Flat-top Abtastung wird in Intervallen endlicher Dauer abgetastet und der Signalwert dann um $T=\frac{1}{r}$ gehalten. Dieses Verfahren wird häufig in Analog-Digital-Wandlern eingesetzt. Das abgetastete Signal $s_0(t)$ ergibt sich somit zu
$$
s_0(t)
= \sum\limits_{n=-\infty}^\infty s(nT) \mathrm{rect}\left(\frac{t}{T}-\frac{1}{2}-nT\right)
= s_\mathrm{a}(t) \ast \mathrm{rect}\left(\frac{t}{T}-\frac{1}{2}\right)
= \left[s(t) \cdot \sum\limits_{n=-\infty}^\infty \delta(t-nT)\right] \ast \mathrm{rect}\left(\frac{t}{T}\right)\ast \delta\left(t-\frac{T}{2}\right) \text{.}
$$
Im Frequenzbereich folgt dann
$$
S_0(f)
= S_\mathrm{a}(f) \cdot T \cdot \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-\mathrm{j}\pi f T}
= \left[S(f) \ast \sum\limits_{k=-\infty}^\infty \delta(f-kr)\right] \cdot \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-\mathrm{j}\pi f T}\text{.}
$$
In der Demonstration kann der Unterschied zwischen der Shape-top und der Flat-top Abtastung nocheinmal anschaulich betrachtet werden.
In der Demonstration kann der Unterschied zwischen der Shape-top und der Flat-top Abtastung noch einmal anschaulich betrachtet werden.
%% Cell type:markdown id: tags:
## Beispiel
### Abtastung
Zunächst wird nocheinmal die [ideale Abtastung](GDET3%20Ideale%20Abtastung.ipynb) wiederholt. In der Abbildung ist als gestrichelte Linie das Signal $s(t)$ dargestellt, das zugehörige Spektrum in blau. Das Signal wird mit Abtastrate $r=2$ abgetastet.
Zunächst wird noch einmal die [ideale Abtastung](GDET3%20Ideale%20Abtastung.ipynb) wiederholt. In der Abbildung ist als gestrichelte Linie das Signal $s(t)$ dargestellt, das zugehörige Spektrum in blau. Das Signal wird mit Abtastrate $r=2$ abgetastet.
Das abgetastete Signal
$s_\mathrm{a}(t) = \sum\limits_{n=-\infty}^\infty s(nT)\cdot\delta(t-nT)$ und das Spektrum des abgetasteten Signals
$S_\mathrm{a}(f) = \frac{1}{T} \sum\limits_{k=-\infty}^\infty S(f-kr)$ sind ebenfalls abgebildet.
Das Spektrum des abgetasteten Signals zeigt die für die Abtastung typischen spektralen Wiederholungen.
%% Cell type:code id: tags:
``` python
# Construction of s(t) and corresponding spectrum S(f)
t,deltat = np.linspace(-10,10,50001, retstep=True) # t-axis
f,deltaf = np.linspace(-50,50,len(t), retstep=True) # f-axis
F = 0.9 # frequency of the signal
s = lambda t: signals_t['cos-Funktion'](t*F);
S = lambda f: signals_f['cos-Funktion'](f, F);
# Ideal sampling: Construction of sa(t) and Sa(f)
r = 2; T = 1/r; # sampling rate
## Time domain
nT, snT = rwth_transforms.sample(t, s(t), T)
## Frequency domain
Sa = np.zeros_like(S(f))
kMax = 16 # number of k values in sum for Sa(f), should be infinity :)
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
fSadirac = f[np.where(Sa)]; Sadirac = Sa[np.where(Sa)]
# Plot
## Time domain
fig, axs = plt.subplots(2,1, **rwth_plots.landscape)
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);
## Frequency domain
ax = axs[1]; ax.set_title('Frequenzbereich');
rwth_plots.plot_dirac(ax, fSadirac, Sadirac, 'rwth:red', label=r'$S_\mathrm{a}(f)$');
rwth_plots.plot_dirac(ax, f[np.where(S(f))], S(f)[np.where(S(f))], 'rwth:blue', label=r'$S(f)$');
ax.set_xlim([-7.5,7.5]); 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);
```
%% Cell type:markdown id: tags:
Nun wird das abgetastete Signal $s_0(t)$ im Zeitbereich betrachtet, welches mittels Flat-top Abtastung erzeugt wurde:
$$
s_0(t)
= s_\mathrm{a}(t) \ast \mathrm{rect}\left(\frac{t}{T}-\frac{1}{2}\right)
= \sum\limits_{n=-\infty}^\infty s(nT) \mathrm{rect}\left(\frac{t}{T}-\frac{1}{2}-nT\right).
$$
Die Abtastrate ist ebenfalls $r=2$.
Für die Flat-top Abtastung charakteristisch wird der Signalwert bis zum nächsten Abtastwert gehalten.
%% Cell type:code id: tags:
``` python
# Time-Domain
s0 = np.zeros_like(t) # sum of rects
Nmax = np.ceil(t[-1]/T) # Parts of the infinite rect sum, should be infinity :)
for n in np.arange(-Nmax,Nmax+1):
s0 = s0 + rect((t-n*T)/T-0.5) * s(n*T)
# Plot
fig, ax = plt.subplots(**rwth_plots.landscape); ax.set_title('Zeitbereich')
ax.plot(t, s(t), 'rwth:blue', linestyle='--', label=r'$s(t)$'); ax.plot(t, s0, 'rwth:red', label=r'$s_0(t)$')
ax.set_xlabel(r'$\rightarrow t$'); ax.set_xlim([-2.9, 2.9]); ax.legend(loc=2); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Dies hat im Frequenzbereich zur Konsequenz, dass die spektralen Kopien mit $T \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-j\pi f T}$ gewichtet werden.
$S_0(f)$ ergibt sich also zu
$$
S_0(f)
= S_\mathrm{a}(f) \cdot T \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-j\pi f T}.
$$
Die nachfolgende Abbildung verdeutlicht diesen Effekt.
%% Cell type:code id: tags:
``` python
# Frequency domain
S_si = T*si(np.pi*T*f)
S_exp = np.exp(-1j*np.pi*f*T)
S0 = Sa * S_si * S_exp
# Plot
## Magnitude
fig, axs = plt.subplots(2,1, **rwth_plots.landscape);
ax = axs[0]; ax.set_title('Betrag')
ax.plot(f, np.abs(S_si*S_exp), 'k--', label=r'$|T\mathrm{si}(\pi f T)e^{-\mathrm{j}\pi f T}|$')
fS0dirac = f[np.where(S0)]; S0dirac = S0[np.where(S0)] # sample S0 and f
rwth_plots.plot_dirac(ax, fS0dirac, np.abs(S0dirac), 'rwth:red', label=r'$|S_0(f)$|');
ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\rightarrow f$'); rwth_plots.grid(ax); rwth_plots.axis(ax);
## Phase
ax = axs[1]; ax.set_title('Phase')
ax.plot(f, np.angle(S_si*S_exp), 'k--', label=r'$\angle T\mathrm{si}(\pi f T)e^{-\mathrm{j}\pi f T}$')
rwth_plots.stem(ax, fS0dirac, np.angle(S0dirac), 'rwth:red', label=r'$\angle S_0(f)$')
ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\rightarrow f$'); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Rekonstruktion
Durch die Multiplikation von $S_\mathrm{a}(f)$ mit $T \cdot \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-j\pi f T}$ wird das Spektrum $S_0(f)$ im Basisband verzerrt. So ist es nicht möglich, $S(f)$ mittels eines einfachen idealen Tiefpasses zu rekonstruieren. Zusätzlich ist ein Filter nötig, welches diesen Faktor ausgleicht, dieses ist in der folgenden Abbildung dargestellt.
$$
H_\mathrm{eq}(f) = \frac{1}{T \cdot \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-j\pi f T}}
$$
%% Cell type:code id: tags:
``` python
# Reconstruction filters #plt.close('all')
## Ideal Low pass to crop the base band
H_lp = rect(f/(r+0.001)) # ideal low pass between -r/2 and r/2
## Equalizing filter to compensate the influence of si(...) and exp(...) terms in S_0(f)
H_eq = 1/(T*si(np.pi*T*f) * np.exp(-1j*np.pi*f*T))
## Overall reconstruction filter
H = H_lp * H_eq
# Plot
fig,axs = plt.subplots(2,1, **rwth_plots.landscape)
ax = axs[0]
ax.plot(f, np.abs(H_eq), 'k--', linewidth=1, label=r'$|H_\mathrm{eq}(f)|$')
ax.plot(f, np.abs(H), 'k', label=r'$|H(f)|$')
ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_ylim([-.1,21]);
ax.set_xlabel(r'$\rightarrow f$'); rwth_plots.grid(ax); rwth_plots.axis(ax);
ax = axs[1]
ax.plot(f, np.angle(H_eq), 'k--', linewidth=1, label=r'$\angle H_\mathrm{eq}(f)$')
ax.plot(f, np.angle(H)*H_lp, 'k', label=r'$\angle H(f)$')
ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); #ax.set_ylim([-.1,11]);
ax.set_xlabel(r'$\rightarrow f$'); rwth_plots.grid(ax); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Dieses Filter wird nun zur Rekonstruktion angewendet.
Das rekonstruierte Signal unter Verwendung des ausgleichenden Filters ist unten abgebildet. Das Originalsignal konnte erfolgreich rekonstruiert werden.
%% Cell type:code id: tags:
``` python
G = S0 * H*T;
g = rwth_transforms.idft(G); g = np.fft.ifftshift(np.real(g)); # IDFT
G = np.real(G); # discards small imaginary numbers close to zero
# Plot
fig, axs = plt.subplots(2, 1, **rwth_plots.landscape)
ax = axs[0]; fGdirac = f[np.where(G)]; Gdirac = G[np.where(G)]
rwth_plots.plot_dirac(ax, fGdirac, Gdirac, 'rwth:green');
ax.set_xlabel(r'$\rightarrow f$'); ax.set_ylabel(r'$\uparrow G(f)$', bbox=rwth_plots.wbbox);
ax.set_xlim([-7.5,7.5]); rwth_plots.grid(ax); rwth_plots.axis(ax);
ax = axs[1]; ax.plot(t, s(t), color='rwth:blue', linestyle='--', label=r'$s(t)$');
ax.plot(t/deltat/(f[-1]*2), g, color='rwth:green', linestyle='-', 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);
```
%% Cell type:markdown id: tags:
## Demo
In der folgenden interaktiven Demonstration kann nun betrachtet werden, was der Unterschied zwischen der Flat-top und der Shape-top Abtastung ist.
Dargestellt sind untereinander:
* der Zeitbereich mit dem Originalsignal und dem abgestasteten Signal
* der zugehörige Frequenzbereich mit dem Originalspektrum, dem Spektrum des abgetasteten Signal und dem Rekonstruktionsfilter
* das rekonstruierte Spektrum
* das rekonstruierte Signal im Zeitbereich.
Im Drop-Down-Menü kann die Art der Abtastung (Shape-top oder Flat-top) sowie die abzutastende Funktion (Cosinus-, Sinus-und si-Funktion, sowie Rechteck- oder Dreieckimpuls) ausgewählt werden.
Über den Schieberegler kann $F$ geändert werden, was bei Cosinus-, Sinus- und si-Funktion die Frequenz und bei Rechteck- und Dreieckimpuls die Breite beeinflusst.
%% Cell type:code id: tags:
``` python
T0 = T/4 # width of rects for shape-top sampling
fig, axs = plt.subplots(4, 1, **rwth_plots.landscape); plt.tight_layout();
@widgets.interact(sampling_type=widgets.Dropdown(options=['Shape-top', 'Flat-top'], description=r'Art der Abtastung:', style=rwth_plots.wdgtl_style),
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(sampling_type, 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 signal
if sampling_type == 'Shape-top':
u = np.zeros_like(t) # sum of rects
for n in np.arange(-Nmax,Nmax+1):
u = u + rect((t-n*T)/T0)
s0 = s(t) * u
elif sampling_type == 'Flat-top':
s0 = np.zeros_like(t) # sum of rects
for n in np.arange(-Nmax,Nmax+1):
s0 = s0 + rect((t-n*T)/T-0.5) * s(n*T)
# Construct sampled spectrum
if sampling_type == 'Shape-top':
S0 = np.zeros_like(S(f))
for k in np.arange(-kMax, kMax+1): # evaluate infinite sum only for 2*kMax+1 elements
S0 += S(f-k/T) * si(np.pi*T0*k/T)
S0 = S0*T0/T
elif sampling_type == 'Flat-top':
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)
S0 = Sa * si(np.pi*T*f) * np.exp(-1j*np.pi*f*T)
# Reconstruct g(t)
if sampling_type == 'Shape-top':
H = H_lp
G = S0 * H * T / T0;
elif sampling_type == 'Flat-top':
H = H_lp * H_eq * T
G = S0 * H
g = rwth_transforms.idft(G);
g = np.fft.ifftshift(np.real(g)); # IDFT
# Sample for plot
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':
fS0dirac = f[np.where(S0)]; S0dirac = S0[np.where(S0)]
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':
Sdirac = np.imag(Sdirac); S = lambda f: np.imag(signals_f[s_type](f, F));
G = np.imag(G); Gdirac = np.imag(Gdirac)
else:
Sdirac = np.real(Sdirac); S0 = np.real(S0); G = np.real(G); Gdirac = np.real(Gdirac)
else:
g /= (len(f)/(2*f[-1])) # Parseval :)
S0dirac = np.zeros_like(f)
G = np.real(G)
if sampling_type == 'Shape-top': # normalize to T0 for plotting reasons
S0 = S0/T0
S0dirac = S0dirac/T0
# 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), 'rwth:blue', linestyle='--', label=r'$s(t)$');
ax.plot(t, s0, 'rwth:red', label=r'$s_0(t)$')
ax.set_xlabel(r'$\rightarrow t$');
ax.set_xlim([-2.9, 2.9]); ax.legend(loc=2); rwth_plots.grid(ax); rwth_plots.axis(ax);
ax = axs[1]; ax.set_title('Frequenzbereich');
ax.plot(f, np.abs(H), '-', color='rwth:black', label=r'$|H(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_0(f)|$');
rwth_plots.plot_dirac(ax, fS0dirac, np.abs(S0dirac), 'rwth:red');
else:
ax.plot(f, np.abs(S0), '-', color='rwth:red', label=r'$|S_0(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, 'rwth:black'); txt.get_bbox_patch().set_alpha(1);
txt,_=rwth_plots.annotate_xtick(ax, r'$f_\mathrm{g}$', r/2, -.15, 'rwth: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)$', 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[0].lines[1].set_ydata(s0); axs[1].lines[-3].set_ydata(S(f));
axs[1].lines[0].set_ydata(np.abs(H))
if s_type == 'cos-Funktion' or s_type == 'sin-Funktion': # dirac plot
rwth_plots.dirac_set_data(axs[1].containers, fS0dirac, np.abs(S0dirac));
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(np.abs(S0)); 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[-3].set_label(r'$\mathrm{Im}\{S(f)\}$');
axs[2].yaxis.label.set_text(r'$\uparrow \mathrm{Im}\{G(f)\}$');
else:
axs[1].lines[-3].set_label(r'$S(f)$')
axs[2].yaxis.label.set_text(r'$\uparrow G(f)$');
axs[1].legend(loc=2)
tmp = np.concatenate((np.abs(S0),np.abs(S0dirac),np.abs(H))); rwth_plots.update_ylim(axs[1], tmp, 0.19, np.max(np.abs(tmp))); 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 beliebige Funktion aus.
* Wie sieht das abgetastete Signal mit Shape-top Abtastung aus und wie mit Flat-top Abtastung?
* Welche Auswirkungen hat die Abtastungsart auf das Spektrum und die Rekonstruktion?
* Variiere $F$. Was passiert?
* Führe diese Beobachtung für unterschiedliche Funktionen aus.
%% 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, interact_manual
import ipywidgets as widgets
from scipy.io import wavfile # wavfile
from scipy.signal import freqz, hilbert
import numpy as np
import matplotlib.pyplot as plt
import rwth_nb.plots.mpl_decorations as rwth_plots
import rwth_nb.misc.transforms as rwth_transforms
import rwth_nb.misc.media as rwth_media
import rwth_nb.misc.filters as rwth_filters
```
%% Cell type:markdown id: tags:
<div>
<img src="figures/rwth_ient_logo@2x.png" style="float: right;height: 5em;">
</div>
# Äquivalenter Tiefpass
Zum Starten: Im Menü: Run <span class="fa-chevron-right fa"></span> Run All Cells auswählen.
## Einleitung
Dieses Notebook beschäftigt sich mit den Auswirkungen von Tiefpass- und Bandpassfilterung, sowie Modulation auf ein Signal. Als Beispiel wird ein Sprachsignal verwendet. Dies hat den Vorteil, dass man sich die Auswirkung der verschiedenen Methoden direkt anhören kann. Hierzu einfach auf den Playbutton unter den Abbildungen klicken.
## Sprachsignal
Zunächst wird das Sprachsignal $s(t)$ eingelesen, dessen Fourier-Transformierte $S(f)$ wird berechnet und beides wird im nachfolgenden Plot dargestellt.
Bei reellwertigen Signalen $s(t)$, wie hier der Fall, ist das Spektrum $S(f)$ eine gerade
komplexe Funktion mit $S(-f)=S^\ast(f)$.
Des Weiteren ist im Spektrum zu erkennen, dass viele Anteile im niederfrequenten Bereich vorhanden sind.
%% Cell type:code id: tags:
``` python
fs, data = wavfile.read('data/krawehl_krawehl.wav'); data = data[int(3.25*fs):int(4.5*fs),0] # crop and mono
s = 0.99*data/np.max(np.abs(data)) # Normalisieren
(t, deltat) = np.linspace(0, len(s)/fs, len(s), retstep=True) # time axis in seconds
S, f = rwth_transforms.dft(s, fs) # Fourier transform
# Plot
fix, axs = plt.subplots(2,1, **rwth_plots.landscape)
ax = axs[0]; ax.plot(t, s, 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow s(t)$', bbox=rwth_plots.wbbox);
ax = axs[1]; ax.plot(f/1000, np.abs(S), 'rwth:blue'); rwth_plots.axis(ax); ax.set_xlim([-7.5, 7.5]);
ax.set_xlabel(r'$\rightarrow f$ [kHz]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow |S(f)|$');
rwth_media.audio_play(s, fs, r'$s(t)$')
```
%% Cell type:markdown id: tags:
## Tiefpassfilterung
Um ein Tiefpasssignal $\tilde{s}(t)$ zu erhalten, wird $s(t)$ mit einem Butterworth-Tiefpass gefiltert. Der Frequenzgang des Filters ist in der folgenden Abbildung dargestellt. Die Grenzfrequenz liegt bei $f_\mathrm{g}=3\,\mathrm{kHz}$ und ist mit einer gestrichelten Linie dargestellt.
Nachfolgend ist das Signal $\tilde{s}(t)$, sowie das zugehörige Spektrum $|\tilde{S}(f)|$ geplottet. Der Effekt der Tiefpassfilterung ist im Spektrum deutlich zu erkennen. Ab der Grenzfrequenz $f_\mathrm{g}=3\,\mathrm{kHz}$ werden die Frequenzanteile deutlich gedämpft.
Im Vergleich zum Originalsprachsignal hört sich das neue Signal deutlich gedämpft an, ist aber noch gut zu verstehen.
%% Cell type:code id: tags:
``` python
fg = 3000
b, a = rwth_filters.butter_lowpass(fg, fs) # generate filter coefficients
_, H = freqz(b, a, worN=int(len(t)/2+1)) # compute H(f)=H(z=e^(j 2 pi f)) out of b, a
f = np.linspace(0, fs/2, len(H));
# Plot
fig,ax = plt.subplots(1,1); ax.plot(f/1000, np.abs(H), 'rwth:blue');
ax.axvline(fg/1000, color='rwth:black', linestyle='--',lw=0.5); # cutoff frequency
ax.set_xlabel(r'$\rightarrow f$ [kHz]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow |H_\mathrm{TP}(f)|$');
ax.set_xlim([0,7.5]); ax.set_ylim([-.25,1.19]); rwth_plots.axis(ax);
```
%% Cell type:code id: tags:
``` python
s_tilde = rwth_filters.filter(s, b, a)
# Plot
fig,axs = plt.subplots(2,1, **rwth_plots.landscape); ax = axs[0]; ax.plot(t, s_tilde, 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow \tilde{s}(t)$', bbox=rwth_plots.wbbox);
S_tilde, f = rwth_transforms.dft(s_tilde, fs);
ax = axs[1]; ax.plot(f/1000, np.abs(S_tilde), 'rwth:blue'); ax.set_xlim([-7.5, 7.5]); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow f$ [kHz]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow |\tilde{S}(f)|$');
rwth_media.audio_play(s_tilde, fs, r'$\tilde{s}(t)$')
```
%% Cell type:markdown id: tags:
## Modulation
Da oft eine Übertragung eines Signals im höherfrequenten Bereich gewünscht ist, viele wichtige Signalanteile sich jedoch im tieffrequenten Bereich befinden, kann das Signal mit einem sogenannten Trägersignal moduliert werden. Hier wird als Beispiel mit einem Cosinus der Frequenz $f_0$ moduliert und es entsteht das Signal
$$m(t) = \tilde{s}(t) \cdot \cos(2\pi f_0 t)\text{ .}$$
Für die Trägerfrequenz wird hier $f_0=6\,\mathrm{kHz}$ gewählt.
Die folgende Abbildung zeigt einen kurzen Ausschnitt aus dem Signal $\tilde{s}(t)$, das Cosinussignal für diesen Zeitausschnitt, sowie das entstehende modulierte Signal $m(t)$.
%% Cell type:code id: tags:
``` python
f0 = 6000
m = s_tilde * np.cos(2*np.pi*f0*t)
# Plot
fig,axs = plt.subplots(3,1);
ax = axs[0]; ax.plot(t*1000, s_tilde, 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_title(r'$\tilde{s}(t)$');
ax = axs[1]; ax.plot(t*1000, np.cos(2*np.pi*f0*t), 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_title(r'$\cos(2 \pi f_0 t)$');
ax = axs[2]; ax.plot(t*1000, m, 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_title(r'$m(t)=\tilde{s}(t)\cos(2 \pi f_0 t)$');
[ax.set_xlim([400,410]) for ax in axs];
```
%% Cell type:markdown id: tags:
Die nächste Abbildung zeigt das gesamte Zeitsignal $m(t)$ und dessen Spektrum $M(f)$. Der Effekt der Modulation ist im Spektrum deutlich zu erkennen. Wo zuvor die Komponenten im niederfrequenten Bereich lagen, sind nun zwei verschobene Spektren zu erkennen, die sich bei der Trägerfrequenz $f_0=6\,\mathrm{kHz}$ befinden. Hört man sich nun das Sprachsignal an, ist vom Original nur noch wenig zu hören, da sich die Information nun im höherfrequenten Bereich befindet. Um das Originalsignal zurückzugewinnen, muss es demoduliert und damit wieder in den niederfrequenten Bereich verschoben werden.
%% Cell type:code id: tags:
``` python
fig,axs = plt.subplots(2,1, **rwth_plots.landscape); ax = axs[0]; ax.plot(t, m, 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow m(t)$');
M, f = rwth_transforms.dft(m, fs); ax = axs[1]; ax.plot(f/1000, np.abs(M), 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow f$ [kHz]'); ax.set_ylabel(r'$\uparrow |M(f)|$'); ax.set_xlim([-12,12])
rwth_media.audio_play(m, fs, r'$m(t)$')
```
%% Cell type:markdown id: tags:
## Äquivalentes Tiefpasssignal
Die Übertragungsfunktion eines Bandpasssystems $H(f)$ kann durch die Übertragungsfunktion $H_{\mathrm{T}}(f)$ ein äquivalentes Tiefpasssystem zusammen mit einer Frequenz $f_0$ beschrieben werden. Hierzu wird zunächst die Übertragungsfunktion $H(f)$ auf positive Frequenzen begrenzt, mit dem Faktor 2 multipliziert und zur Bildung von $H_{\mathrm{T}}(f)$ um eine geeignete Frequenz, die Trägerfrequenz $f_0$ genannt wird, in Richtung negativer Frequenzen verschoben.
Die Übertragungsfunktion eines Bandpasssystems $H(f)$ kann durch die Übertragungsfunktion $H_{\mathrm{T}}(f)$ eines äquivalentes Tiefpasssystems zusammen mit einer Frequenz $f_0$ beschrieben werden. Hierzu wird zunächst die Übertragungsfunktion $H(f)$ auf positive Frequenzen begrenzt, mit dem Faktor 2 multipliziert und zur Bildung von $H_{\mathrm{T}}(f)$ um eine geeignete Frequenz, die Trägerfrequenz $f_0$ genannt wird, in Richtung negativer Frequenzen verschoben.
Please register or sign in to reply
Dies hat zum Einen rechnerische Vorteile, zum Anderen kann dies schaltungstechnisch genutzt werden. Praktische Anwendungen findet dieses Verfahren beispielsweise in der Empfängertechnik und der Messtechnik, sowie bei der Realisierung von Bandpass-Übertragungssystemen mittels digitaler Signalverarbeitungsmethoden mit möglichst geringer Taktrate.
%% Cell type:markdown id: tags:
Im Folgenden wird die Berechnung des äquivalenten Tiefpasssignals $m_\mathrm{T}(t)$ bezüglich Mittenfrequenz $f_0$ des reellwertigen Bandpasssignals $m(t)$ erklärt und mit Hilfe der Abbildungen deutlich gemacht.
Zunächst wird nur die rechte Seite (rechtsseitige Frequenzanteile) des Spektrums $M(f)$ behalten
$$M_+(f) = M(f) \varepsilon(f) \text{.}$$
Im Zeitbereich wird das korrespondierende $m_+(t)$ auch analytische Komponente genannt.
Mit $\mathcal{F}^{-1}\{\varepsilon(f)\} = \frac{1}{2}\delta(t) + \mathrm{j}\frac{1}{2 \pi t}$ erhält man
$$m_+(t) = \frac{1}{2} m(t) + \frac{\mathrm{j}}{2}s(t) \ast \frac{1}{\pi t} \text{.}$$
Die analytische Komponente $m_+(t)$ kann bei reellwertigen Signalen über die Hilbert-Transformation gewonnen werden.
In der Abbildung ist dieses Vorgehen zu erkennen: Der obere Plot zeigt das rechtsseitige Spektrum, direkt darunter ist die analytische Komponente zu sehen.
%% Cell type:markdown id: tags:
Nun wird $M_+(f)$, die rechtsseitigen Frequenzanteile von $M(f)$, um $f_0$ nach links verschoben:
$$M_\mathrm{T}(f) = 2 M_+(f) \ast \delta(f+f_0) \text{.}$$
So erhält man das äquivalente Tiefpasssignal $m_\mathrm{T}(t)$ des Bandpasssignals $m(t)$
$$m_\mathrm{T}(t)=2 m_+(t) \mathrm{e}^{-\mathrm{j}2\pi f_0 t} \text{.}$$
Das äquivalente Tiefpasssignal, sowie das zugehörige Spektrum, sind ebenfalls in der Abbildung dargestellt.
%% Cell type:code id: tags:
``` python
def calculate_eq_lp(s, f0): # s: BP signal, f0: center frequency
""""
g = signal.hilbert(s) is NOT calculating the Hilbert transform,
but the scaled analytic component g=2*s_plus using the Hilbert transform,
such that Re{g(t)} = s(t) and Im{g(t)} = s(t) * 1/(pi t)
"""
s_plus = 0.5*hilbert(s) # analytic component
s_T = 2*s_plus*np.exp(-2*1J*np.pi*f0*t) # modulate to get equivalent lowpass signal
return s_T, s_plus
m_T, m_plus = calculate_eq_lp(m, f0); m_T = np.real(m_T);
M_T, f = rwth_transforms.dft(m_T, fs); M_plus,_ = rwth_transforms.dft(m_plus, fs);
# Plot
fig,axs = plt.subplots(2,1, **rwth_plots.landscape);
ax = axs[0]; ax.plot(f/1000, np.abs(M_plus), 'rwth:blue'); rwth_plots.axis(ax); ax.set_title('Rechtsseitiges Spektrum')
ax.set_xlabel(r'$\rightarrow f$ [kHz]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow |M_+(f)|$');
ax = axs[1]; rwth_plots.axis(ax); ax.set_title('Analytische Komponente')
ax.plot(t, np.real(m_plus), 'rwth:blue', label=r'$\mathrm{Re}\{m_+(t)\}$'); ax.plot(t, np.imag(m_plus), 'rwth:green', label=r'$\mathrm{Im}\{m_+(t)\}$');
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.legend();
fig,axs = plt.subplots(2,1, **rwth_plots.landscape); ax = axs[0]; ax.plot(t, m_T, 'rwth:blue'); rwth_plots.axis(ax); ax.set_title('Äquivalentes Tiefpasssignal')
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow m_\mathrm{T}(t)$', bbox=rwth_plots.wbbox);
ax = axs[1]; ax.plot(f/1000, np.abs(M_T), 'rwth:blue'); rwth_plots.axis(ax);
ax.set_xlabel(r'$\rightarrow f$ [kHz]', bbox=rwth_plots.wbbox); ax.set_ylabel(r'$\uparrow |M_\mathrm{T}(f)|$');
rwth_media.audio_play(m_T, fs, r'$m_\mathrm{T}(t)$')
```
%% Cell type:markdown id: tags:
Es sei noch einmal darauf hingewiesen, dass einem gegebenen Bandpasssystem mit reeller Impulsantwort beliebig viele äquivalente Tiefpasssysteme mit unterschiedlichen Übertragungsfunktionen $H_{\mathrm{T}}(f)$ bzw. Impulsantworten $h_{\mathrm{T}}(t)$ zugeordnet werden können, da die Zuordnung von $H(f)$ zu $H_{\mathrm{T}}(f)$ abhängig von der Trägerfrequenz $f_0$ ist.
%% Cell type:markdown id: tags:
Der Betrag $|m_\mathrm{T}(t)|$ des äquivalenten Tiefpasssignals $m_\mathrm{T}(t)$ wird auch als Einhüllende von $m(t)$ bezeichnet. Warum dies so ist, kann in der folgenden Grafik anschaulich betrachtet werden:
%% Cell type:code id: tags:
``` python
# Plot
fig, axs = plt.subplots(2, 1, **rwth_plots.landscape);
ax = axs[0]; ax.plot(t, m, 'rwth:blue', label=r'$m(t)$');
ax.plot(t, np.abs(m_T), 'rwth:green', label=r'$|m_\mathrm{T}(t)|$');
ax.set_xlabel(r'$\rightarrow t$ [s]', bbox=rwth_plots.wbbox);
ax.legend(); rwth_plots.axis(ax);
ax = axs[1]; ax.plot(t*1000, m, 'rwth:blue', label=r'$g(t)$'); rwth_plots.axis(ax);
ax.plot(t*1000, np.abs(m_T), 'rwth:green', label=r'$|m_\mathrm{T}(t)|$');
ax.set_xlim([400,410]); ax.set_xlabel(r'$\rightarrow t$ [ms]', bbox=rwth_plots.wbbox);
```
%% 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.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment