Commit f65e5429 by Christian Rohlfing

### - added real sampling

- bugfix in ient_nb
parent 8b3f80ac
This diff is collapsed.
This diff is collapsed.
 { "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "source_hidden": true } }, "outputs": [], "source": [ "# Copyright 2019 Institut für Nachrichtentechnik, RWTH Aachen University\n", "%matplotlib widget\n", "\n", "from ipywidgets import interact, interactive, fixed, HBox, VBox\n", "import ipywidgets as widgets\n", "from IPython.display import clear_output, display, HTML\n", "\n", "from ient_nb.ient_plots import *\n", "from ient_nb.ient_transforms import *\n", "from ient_nb.ient_signals import *\n", "\n", "signals_t = {'cos-Funktion': lambda t: np.cos(2 * np.pi * t),\n", " 'sin-Funktion': lambda t: np.sin(2 * np.pi * t),\n", " 'si-Funktion': lambda t: si(2 * np.pi * t),\n", " 'Rechteckimpuls': lambda t: rect(t / 1.05),\n", " 'Dreieckimpuls': tri}\n", "\n", "signals_f = {'cos-Funktion': lambda f, F: np.isin(f/F, f[findIndOfLeastDiff(f/F, [-1, 1])]/F) * 0.5,\n", " 'sin-Funktion': lambda f, F: np.isin(f/F, f[findIndOfLeastDiff(f/F, [1])]/F) / 2j - np.isin(f/F, f[findIndOfLeastDiff(f/F, [-1])]/F) / 2j,\n", " 'si-Funktion': lambda f, F: 1/(2*np.abs(F))*rect(f / (2*F)),\n", " 'Rechteckimpuls': lambda f, F: 1/np.abs(F)*si(np.pi * f / F),\n", " 'Dreieckimpuls': lambda f, F: 1/np.abs(F)*si(np.pi * f/F) ** 2}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " \n", "
\n", "\n", "\n", "# Reale Abtastung\n", "\n", "Im Gegensatz zur [idealen Abtastung](GDET3%20Ideale%20Abtastung.ipynb) werden hier zwei Verfahren zur realen Abtastung betrachtet.\n", "\n", "## Shape-top Abtastung\n", "\n", "Abtastung in Intervallen endlicher Dauer $T_0$ mit Abstand $T=\\frac{1}{r}$\n", "\n", "$$\n", "s_0(t) \n", "= s(t) \\cdot \\sum\\limits_{n=-\\infty}^\\infty \\mathrm{rect}\\left(\\frac{t-nT}{T_0}\\right) \n", "= s(t) \\cdot \\left[\\mathrm{rect}\\left(\\frac{t}{T_0}\\right) \\ast \\sum\\limits_{n=-\\infty}^\\infty \\delta(t-nT) \\right]\n", "$$\n", "\n", "Im Frequenzbereich\n", "$$\n", "S_0(f) \n", "= 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]\n", "=\n", "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]\n", "$$\n", "\n", "Grenzübergang liefert ideale Abtastung: $\\lim\\limits_{T_0\\rightarrow 0}\\left(\\frac{1}{T_0}s_0(t)\\right) = s_\\mathrm{a}(t)$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Flat-top Abtastung\n", "\n", "Abtastung in Intervallen endlicher Dauer und um $T=\\frac{1}{r}$ gehaltene Signalwerte\n", "\n", "$$\n", "s_0(t) \n", "= s_\\mathrm{a}(t) \\ast \\mathrm{rect}\\left(\\frac{t}{T}-\\frac{1}{2}\\right)\n", "= \\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)\n", "$$\n", "\n", "Im Frequenzbereich\n", "$$\n", "S_0(f) \n", "= S_\\mathrm{a}(f) \\cdot T \\cdot \\mathrm{si}(\\pi f T) \\cdot \\mathrm{e}^{-\\mathrm{j}\\pi f T}\n", "= \\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}\n", "$$\n", "\n", "Dieses Verfahren wird häufig in Analog-Digital-Wandlern eingesetzt." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Abtastung\n", "\n", "Zunächst wird [ideale Abtastung](GDET3%20Ideale%20Abtastung.ipynb) wiederholt mit \n", "$s_\\mathrm{a}(t) = \\sum\\limits_{n=-\\infty}^\\infty s(nT)\\cdot\\delta(t-nT)$ und Spektrum \n", "$S_\\mathrm{a}(f) = \\frac{1}{T} \\sum\\limits_{k=-\\infty}^\\infty S(f-kr)$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Construction of s(t) and corresponding spectrum S(f)\n", "t,deltat = np.linspace(-10,10,50001, retstep=True) # t-axis\n", "f,deltaf = np.linspace(-50,50,len(t), retstep=True) # f-axis\n", "\n", "F = 0.9 # frequency of the signal\n", "s = lambda t: signals_t['cos-Funktion'](t*F); \n", "S = lambda f: signals_f['cos-Funktion'](f, F);\n", "\n", "# Ideal sampling\n", "# Construction of sa(t) and Sa(f)\n", "r = 2; T = 1/r; # sampling rate\n", "\n", "## Time domain\n", "nT, snT = ient_sample(t, s(t), T)\n", "\n", "## Frequency domain\n", "Sa = np.zeros_like(S(f))\n", "kMax = 16 # number of k values in sum for Sa(f), should be infinity :)\n", "for k in np.arange(-kMax, kMax+1): # evaluate infinite sum only for 2*kMax+1 elements \n", " Sa += S(f-k/T)\n", "Sa = Sa/T\n", "fSadirac = f[np.where(Sa)]; Sadirac = Sa[np.where(Sa)]\n", "\n", "# Plot\n", "fig, axs = plt.subplots(2,1)\n", "ax = axs[0]; ax.set_title('Zeitbereich');\n", "ax.plot(t, s(t), color='rwth', linestyle='--', label=r'$s(t)$');\n", "ient_plot_dirac(ax, nT, snT, 'rot', label=r'$s_\\mathrm{a}(t)$')\n", "ax.set_xlabel(r'$\\rightarrow t$'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax);\n", "\n", "ax = axs[1]; ax.set_title('Frequenzbereich');\n", "ient_plot_dirac(ax, fSadirac, Sadirac, 'rot', label=r'$S_\\mathrm{a}(f)$');\n", "ient_plot_dirac(ax, f[np.where(S(f))], S(f)[np.where(S(f))], 'rwth', label=r'$S(f)$');\n", "ax.set_xlim([-7.5,7.5]); ax.legend(loc=2);\n", "ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);\n", "txt,_=ient_annotate_xtick(ax, r'$r=2$', r, -.15, 'black'); txt.get_bbox_patch().set_alpha(1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nun wird das abgetastete Signal $s_0(t)$ im Zeitbereich betrachtet, welches mittels Flat-top Abtastung erzeugt wurde.\n", "$$\n", "s_0(t) \n", "= s_\\mathrm{a}(t) \\ast \\mathrm{rect}\\left(\\frac{t}{T}-\\frac{1}{2}\\right)\n", "= \\sum\\limits_{n=-\\infty}^\\infty s(nT) \\mathrm{rect}\\left(\\frac{t}{T}-\\frac{1}{2}-nT\\right)\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Time-Domain\n", "s0 = np.zeros_like(t) # sum of rects\n", "Nmax = np.ceil(t[-1]/T) # Parts of the infinite rect sum, should be infinity :)\n", "for n in np.arange(-Nmax,Nmax+1):\n", " s0 = s0 + rect((t-n*T)/T-0.5) * s(n*T)\n", "\n", "# Plot\n", "fig, ax = plt.subplots(); ax.set_title('Zeitbereich')\n", "ax.plot(t, s(t), 'rwth', linestyle='--', label=r'$s(t)$'); ax.plot(t, s0, 'rot', label=r'$s_0(t)$')\n", "ax.set_xlabel(r'$\\rightarrow t$'); ax.set_xlim([-2.9, 2.9]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nun $S_0(f)$ im Frequenzbereich\n", "$$\n", "S_0(f) \n", "= S_\\mathrm{a}(f) \\cdot T \\mathrm{si}(\\pi f T) \\cdot \\mathrm{e}^{-j\\pi f T}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Frequency domain\n", "S_si = T*si(np.pi*T*f)\n", "S_exp = np.exp(-1j*np.pi*f*T)\n", "S0 = Sa * S_si * S_exp\n", "\n", "# Plot\n", "fig, axs = plt.subplots(2,1); \n", "ax = axs[0]; ax.set_title('Betrag')\n", "ax.plot(f, np.abs(S_si*S_exp), 'k--', label=r'$|T\\mathrm{si}(\\pi f T)e^{-\\mathrm{j}\\pi f T}|$')\n", "fS0dirac = f[np.where(S0)]; S0dirac = S0[np.where(S0)]\n", "ient_plot_dirac(ax, fS0dirac, np.abs(S0dirac), 'rot', label=r'$|S_0(f)$|');\n", "ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);\n", "\n", "ax = axs[1]; ax.set_title('Phase')\n", "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}$')\n", "ient_stem(ax, fS0dirac, np.angle(S0dirac), 'rot', label=r'$\\angle S_0(f)$')\n", "ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Rekonstruktion\n", "\n", "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 zum Ausgleich nötig\n", "$$\n", "H_\\mathrm{eq}(f) = \\frac{1}{T \\cdot \\mathrm{si}(\\pi f T) \\cdot \\mathrm{e}^{-j\\pi f T}}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Reconstruction filters #plt.close('all')\n", "## Ideal Low pass to crop the base band\n", "H_lp = rect(f/(r+0.001)) # ideal low pass between -r/2 and r/2\n", "## Equalizing filter to compensate the influence of si(...) and exp(...) terms in S_0(f)\n", "H_eq = 1/(T*si(np.pi*T*f) * np.exp(-1j*np.pi*f*T))\n", "## Overall reconstruction filter\n", "H = H_lp * H_eq\n", "\n", "# Plot\n", "fig,axs = plt.subplots(2,1)\n", "ax = axs[0]\n", "ax.plot(f, np.abs(H_eq), 'k--', linewidth=1, label=r'$|H_\\mathrm{eq}(f)|$')\n", "ax.plot(f, np.abs(H), 'k', label=r'$|H(f)|$')\n", "ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_ylim([-.1,21]);\n", "ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);\n", "\n", "ax = axs[1]\n", "ax.plot(f, np.angle(H_eq), 'k--', linewidth=1, label=r'$\\angle H_\\mathrm{eq}(f)$')\n", "ax.plot(f, np.angle(H)*H_lp, 'k', label=r'$\\angle H(f)$')\n", "ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); #ax.set_ylim([-.1,11]);\n", "ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Demo" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "source_hidden": true } }, "outputs": [], "source": [ "T0 = T/4 # width of rects for shape-top sampling\n", "\n", "plt.close(); fig, axs = plt.subplots(4, 1); fig.canvas.layout.height = '800px'; plt.tight_layout();\n", "@widgets.interact(sampling_type=widgets.Dropdown(options=['Shape-top', 'Flat-top'], description=r'Art der Abtastung:', style=ient_wdgtl_style),\n", " s_type=widgets.Dropdown(options=list(signals_t.keys()), description=r'Wähle $s(t)$:'),\n", " F=widgets.FloatSlider(min=0.1, max=2, value=0.9, step=.1, description=r'$F$', style=ient_wdgtl_style, continuous_update=False))\n", "def update_plots(sampling_type, s_type, F):\n", " global S0, S0dirac\n", " s = lambda t: signals_t[s_type](t*F); \n", " S = lambda f: signals_f[s_type](f, F);\n", " nT, snT = ient_sample(t, s(t), T)\n", " \n", " # Construct sampled signal\n", " if sampling_type == 'Shape-top':\n", " u = np.zeros_like(t) # sum of rects\n", " for n in np.arange(-Nmax,Nmax+1):\n", " u = u + rect((t-n*T)/T0)\n", " s0 = s(t) * u\n", " elif sampling_type == 'Flat-top':\n", " s0 = np.zeros_like(t) # sum of rects\n", " for n in np.arange(-Nmax,Nmax+1):\n", " s0 = s0 + rect((t-n*T)/T-0.5) * s(n*T)\n", " \n", " # Construct sampled spectrum\n", " if sampling_type == 'Shape-top':\n", " S0 = np.zeros_like(S(f))\n", " for k in np.arange(-kMax, kMax+1): # evaluate infinite sum only for 2*kMax+1 elements \n", " S0 += S(f-k/T) * si(np.pi*T0*k/T)\n", " S0 = S0*T0/T\n", " elif sampling_type == 'Flat-top':\n", " Sa = np.zeros_like(S(f))\n", " for k in np.arange(-kMax, kMax+1): # evaluate infinite sum only for 2*kMax+1 elements \n", " Sa += S(f-k/T)\n", " S0 = Sa * si(np.pi*T*f) * np.exp(-1j*np.pi*f*T)\n", " \n", " # Reconstruct g(t)\n", " if sampling_type == 'Shape-top':\n", " H = H_lp\n", " G = S0 * H * T / T0;\n", " elif sampling_type == 'Flat-top':\n", " H = H_lp * H_eq * T\n", " G = S0 * H\n", " g = ient_idft(G); \n", " g = np.fft.ifftshift(np.real(g)); # IDFT\n", " \n", " # Sample for plot\n", " if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':\n", " fS0dirac = f[np.where(S0)]; S0dirac = S0[np.where(S0)]\n", " fSdirac = f[np.where(S(f))]; Sdirac = S(f)[np.where(S(f))]\n", " fGdirac = f[np.where(G)]; Gdirac = G[np.where(G)]\n", " if s_type == 'sin-Funktion':\n", " Sdirac = np.imag(Sdirac); S = lambda f: np.imag(signals_f[s_type](f, F)); \n", " G = np.imag(G); Gdirac = np.imag(Gdirac)\n", " else:\n", " Sdirac = np.real(Sdirac); S0 = np.real(S0); G = np.real(G); Gdirac = np.real(Gdirac)\n", " else:\n", " g /= (len(f)/(2*f[-1])) # Parseval :)\n", " S0dirac = np.zeros_like(f)\n", " G = np.real(G)\n", " \n", " if sampling_type == 'Shape-top': # normalize to T0 for plotting reasons\n", " S0 = S0/T0\n", " S0dirac = S0dirac/T0\n", " \n", " # Plot\n", " if not axs[0].lines: # Call plot() and decorate axes. Usually, these functions take some processing time\n", " ax = axs[0]; ax.set_title('Zeitbereich');\n", " ax.plot(t, s(t), 'rwth', linestyle='--', label=r'$s(t)$'); \n", " ax.plot(t, s0, 'rot', label=r'$s_0(t)$')\n", " ax.set_xlabel(r'$\\rightarrow t$'); \n", " ax.set_xlim([-2.9, 2.9]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax);\n", " \n", " ax = axs[1]; ax.set_title('Frequenzbereich');\n", " ax.plot(f, np.abs(H), '-', color='black', label=r'$|H(f)|$')\n", " if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':\n", " ax.plot(f, np.ones_like(f)*np.nan, '-', color='rot', label=r'$|S_0(f)|$');\n", " ient_plot_dirac(ax, fS0dirac, np.abs(S0dirac), 'rot');\n", " else:\n", " ax.plot(f, np.abs(S0), '-', color='rot', label=r'$|S_0(f)|$'); \n", " ient_plot_dirac(ax, [], [], 'rot');\n", " ax.plot(f, S(f), color='rwth', linestyle='--', linewidth=1, label=r'$S(f)$')\n", " ax.set_xlim([-7.5,7.5]); ax.set_ylim([-1,2]); ax.legend(loc=2);\n", " ax.set_xlabel(r'$\\rightarrow f$'); ient_grid(ax); ient_axis(ax);\n", " txt,_=ient_annotate_xtick(ax, r'$r=2$', r, -.15, 'black'); txt.get_bbox_patch().set_alpha(1);\n", " txt,_=ient_annotate_xtick(ax, r'$f_\\mathrm{g}$', r/2, -.15, 'black'); txt.get_bbox_patch().set_alpha(1);\n", " \n", " ax = axs[2];\n", " if s_type == 'cos-Funktion' or s_type == 'sin-Funktion':\n", " ax.plot(f, np.ones_like(f)*np.nan, '-', color='grun'); \n", " ient_plot_dirac(ax, fGdirac, Gdirac, 'grun');\n", " else:\n", " ax.plot(f, G, '-', color='grun'); \n", " ient_plot_dirac(ax, [], [], 'rot');\n", " ax.set_xlabel(r'$\\rightarrow f$'); ax.set_ylabel(r'$\\uparrow G(f)$', bbox=ient_wbbox);\n", " ax.set_xlim([-7.5,7.5]); ient_grid(ax); ient_axis(ax);\n", " \n", " ax = axs[3]; ax.set_title('Zeitbereich (nach Rekonstruktion)');\n", " ax.plot(t, s(t), color='rwth', linestyle='--', label=r'$s(t)$');\n", " ax.plot(t/deltat/(f[-1]*2), g, 'grun', label=r'$g(t)$');\n", " ax.set_xlabel(r'$\\rightarrow t$'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax);\n", " plt.tight_layout()\n", " else:\n", " axs[0].lines[0].set_ydata(s(t)); axs[0].lines[1].set_ydata(s0); axs[1].lines[-3].set_ydata(S(f)); \n", " axs[1].lines[0].set_ydata(np.abs(H))\n", " if s_type == 'cos-Funktion' or s_type == 'sin-Funktion': # dirac plot\n", " ient_dirac_set_data(axs[1].containers, fS0dirac, np.abs(S0dirac));\n", " axs[1].lines[1].set_ydata(np.ones_like(f)*np.nan); \n", " ient_dirac_set_data(axs[2].containers, fGdirac, Gdirac); axs[2].lines[0].set_ydata(np.ones_like(f)*np.nan);\n", " else:\n", " axs[1].lines[1].set_ydata(np.abs(S0)); ient_dirac_set_data(axs[1].containers, [], []); \n", " axs[2].lines[0].set_ydata(G); ient_dirac_set_data(axs[2].containers, [], []);\n", " \n", " axs[3].lines[0].set_ydata(s(t)); axs[3].lines[1].set_ydata(g);\n", " \n", " if s_type == 'sin-Funktion': # Adapt labels\n", " axs[1].lines[-3].set_label(r'$\\mathrm{Im}\\{S(f)\\}$');\n", " axs[2].yaxis.label.set_text(r'$\\uparrow \\mathrm{Im}\\{G(f)\\}$');\n", " else:\n", " axs[1].lines[-3].set_label(r'$S(f)$')\n", " axs[2].yaxis.label.set_text(r'$\\uparrow G(f)$');\n", " axs[1].legend(loc=2)\n", " \n", " tmp = np.concatenate((np.abs(S0),np.abs(S0dirac))); ient_update_ylim(axs[1], tmp, 0.19, np.max(np.abs(tmp))); ient_update_ylim(axs[2], G, 0.19, np.max(G));\n", " ient_update_ylim(axs[3], np.concatenate((s(t),g)), 0.19, np.max(np.concatenate((s(t),g))));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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). \n", "\n", "Please attribute the work as follows: \n", "*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." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 4 }
 %% Cell type:code id: tags:  python # Copyright 2019 Institut für Nachrichtentechnik, RWTH Aachen University %matplotlib widget from ipywidgets import interact, interactive, fixed, HBox, VBox import ipywidgets as widgets from IPython.display import clear_output, display, HTML from ient_nb.ient_plots import * from ient_nb.ient_transforms import * from ient_nb.ient_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[findIndOfLeastDiff(f/F, [-1, 1])]/F) * 0.5, 'sin-Funktion': lambda f, F: np.isin(f/F, f[findIndOfLeastDiff(f/F, [1])]/F) / 2j - np.isin(f/F, f[findIndOfLeastDiff(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:
# Reale Abtastung Im Gegensatz zur [idealen Abtastung](GDET3%20Ideale%20Abtastung.ipynb) werden hier zwei Verfahren zur realen Abtastung betrachtet. ## Shape-top Abtastung Abtastung in Intervallen endlicher Dauer $T_0$ mit Abstand $T=\frac{1}{r}$ $$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 $$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]$$ Grenzübergang liefert 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 Abtastung in Intervallen endlicher Dauer und um $T=\frac{1}{r}$ gehaltene Signalwerte $$s_0(t) = 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)$$ Im Frequenzbereich $$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}$$ Dieses Verfahren wird häufig in Analog-Digital-Wandlern eingesetzt. %% Cell type:markdown id: tags: ### Abtastung Zunächst wird [ideale Abtastung](GDET3%20Ideale%20Abtastung.ipynb) wiederholt mit $s_\mathrm{a}(t) = \sum\limits_{n=-\infty}^\infty s(nT)\cdot\delta(t-nT)$ und Spektrum $S_\mathrm{a}(f) = \frac{1}{T} \sum\limits_{k=-\infty}^\infty S(f-kr)$. %% 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 = ient_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 fig, axs = plt.subplots(2,1) ax = axs[0]; ax.set_title('Zeitbereich'); ax.plot(t, s(t), color='rwth', linestyle='--', label=r'$s(t)$'); ient_plot_dirac(ax, nT, snT, 'rot', label=r'$s_\mathrm{a}(t)$') ax.set_xlabel(r'$\rightarrow t$'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax); ax = axs[1]; ax.set_title('Frequenzbereich'); ient_plot_dirac(ax, fSadirac, Sadirac, 'rot', label=r'$S_\mathrm{a}(f)$'); ient_plot_dirac(ax, f[np.where(S(f))], S(f)[np.where(S(f))], 'rwth', label=r'$S(f)$'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\rightarrow f$'); ient_grid(ax); ient_axis(ax); txt,_=ient_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)$$ %% 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(); ax.set_title('Zeitbereich') ax.plot(t, s(t), 'rwth', linestyle='--', label=r'$s(t)$'); ax.plot(t, s0, 'rot', label=r'$s_0(t)$') ax.set_xlabel(r'$\rightarrow t$'); ax.set_xlim([-2.9, 2.9]); ax.legend(loc=2); ient_grid(ax); ient_axis(ax);  %% Cell type:markdown id: tags: Nun $S_0(f)$ im Frequenzbereich $$S_0(f) = S_\mathrm{a}(f) \cdot T \mathrm{si}(\pi f T) \cdot \mathrm{e}^{-j\pi f T}$$ %% 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 fig, axs = plt.subplots(2,1); 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)] ient_plot_dirac(ax, fS0dirac, np.abs(S0dirac), 'rot', label=r'$|S_0(f)$|'); ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\rightarrow f$'); ient_grid(ax); ient_axis(ax); 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}$') ient_stem(ax, fS0dirac, np.angle(S0dirac), 'rot', label=r'$\angle S_0(f)$') ax.set_xlim([-7.5,7.5]); ax.legend(loc=2); ax.set_xlabel(r'$\rightarrow f$'); ient_grid(ax); ient_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 zum Ausgleich nötig $$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) 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$'); ient_grid(ax); ient_axis(ax);