GDET3 Faltung GUI.ipynb 14.9 KB
Newer Older
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
1
2
{
 "cells": [
3
4
  {
   "cell_type": "code",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
5
   "execution_count": null,
Christian Rohlfing's avatar
Christian Rohlfing committed
6
   "metadata": {
7
8
9
10
    "hide_input": true,
    "jupyter": {
     "source_hidden": true
    }
Christian Rohlfing's avatar
Christian Rohlfing committed
11
   },
12
13
   "outputs": [],
   "source": [
14
    "# Copyright 2020 Institut für Nachrichtentechnik, RWTH Aachen University\n",
15
    "%matplotlib widget\n",
16
17
    "\n",
    "import ipywidgets as widgets\n",
18
    "from ipywidgets import interact, interactive, fixed, Layout\n",
19
20
    "from IPython.display import clear_output, display, HTML\n",
    "\n",
21
    "from scipy import signal # convolution\n",
22
    "\n",
23
    "\n",
24
    "from ient_nb.ient_plots import *\n",
25
    "from ient_nb.ient_signals import *"
26
27
   ]
  },
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
28
29
30
31
32
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div>\n",
Hafiz Emin Kosar's avatar
Hafiz Emin Kosar committed
33
    "    <img src=\"ient_nb/figures/rwth_ient_logo@2x.png\" style=\"float: right;height: 5em;\">\n",
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
34
35
    "</div>\n",
    "\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
36
    "# Demonstrator Faltung\n",
37
    "\n",
38
    "Zum Starten: Im Menü: Run <span class=\"fa-chevron-right fa\"></span> Run All Cells auswählen.\n",
39
    "\n",
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
40
    "## Einleitung\n",
41
42
43
    "\n",
    "Im Folgenden wird das Faltungsintegral\n",
    "$$g(t)\n",
44
    "= s(t)\\ast h(t)\n",
45
46
47
    "= \\int\\limits_{-\\infty}^{\\infty} s(\\tau) h(t-\\tau) \\,\\mathrm{d}\\tau\n",
    "$$\n",
    "betrachtet."
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
48
49
50
51
52
53
54
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Demo\n",
55
    "\n",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
56
57
58
    "Wähle $s(t)$ und $h(t)$ sowie jeweils Verschiebung $t_0$ und Dehnungsfaktor $T$ für beide Signale: $s\\left(\\frac{t-t_0}{T}\\right)$ und $h\\left(\\frac{t-t_0}{T}\\right)$.\n",
    "\n",
    "Zusätzlich zu Elementarsignalen kann auch eine frei definierbare Funktion $s_0(t)$ zur Faltung verwendet werden."
59
60
61
62
   ]
  },
  {
   "cell_type": "code",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
63
   "execution_count": null,
64
65
66
67
   "metadata": {},
   "outputs": [],
   "source": [
    "s_0 = lambda t: rect(t/2-1/2)*(-t)"
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
68
69
70
71
   ]
  },
  {
   "cell_type": "code",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
72
   "execution_count": null,
Christian Rohlfing's avatar
Christian Rohlfing committed
73
   "metadata": {
74
75
76
77
    "hide_input": true,
    "jupyter": {
     "source_hidden": true
    }
Christian Rohlfing's avatar
Christian Rohlfing committed
78
   },
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
79
80
   "outputs": [],
   "source": [
81
82
83
    "def convolution(s, h):\n",
    "    # Convolve s and h numerically\n",
    "    return signal.convolve(s(tau), h(tau), mode='same')*deltat\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
84
    "\n",
85
86
    "(tau,deltat) = np.linspace(-15, 15, 10001, retstep=True) # tau axis\n",
    "interval_cnt = 0; # Interval counter for stepwise plot\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
87
    "\n",
88
89
90
91
92
93
94
95
96
97
98
99
100
    "# Signals\n",
    "signal_types = {\n",
    "    'Rechteck'           : rect,  \n",
    "    'Dreieck'            : tri, \n",
    "    'Sprungfunktion'     : unitstep, \n",
    "    'si-Funktion'        : lambda t: si(t*np.pi), \n",
    "    'Exponentialimpuls'  : lambda t: unitstep(t)*np.exp(-t),\n",
    "    'Gauß-Signal'        : gauss, \n",
    "    'Doppelrechteck'     : lambda t: rect(t*2+0.5)-rect(t*2-0.5),\n",
    "    'Rampe'              : lambda t: t*rect(t-0.5), \n",
    "    'Versch. Rechteck'   : lambda t: -rect(t-0.5),\n",
    "    'Eigene Kreation s0(t)' : s_0,\n",
    "}\n",
101
102
    "\n",
    "# Plot\n",
103
    "fig0, axs0 = plt.subplots(1, 2, figsize=(12,2))\n",
104
    "def update_signals(s_type, s_T, s_t0, h_type, h_T, h_t0):\n",
105
106
107
    "    # Get s(t) and h(t)\n",
    "    global s, h, gt, intervals_g # reused in second interactive plot\n",
    "    s = lambda tau: signal_types[s_type]((tau-s_t0)/s_T); # signal on time axis (shifted by t0 and stretched by T)\n",
108
    "    h = lambda tau: signal_types[h_type]((tau-h_t0)/h_T);\n",
109
110
    "    #intervals_s = np.array(signal_intervals[w_s_type.value])*s_T + s_t0; # get signal intervals and map to time axis (shifted by t0 and stretched by T)\n",
    "    #intervals_h = np.array(signal_intervals[w_h_type.value])*h_T + h_t0;\n",
111
112
    "    intervals_s,_,_ = find_intervals(s(tau), tau, 0.49*np.max(np.abs(s(tau)))/deltat, deltat)\n",
    "    intervals_h,_,_ = find_intervals(h(tau), tau, 0.49*np.max(np.abs(h(tau)))/deltat, deltat)\n",
113
114
    "    \n",
    "    # Get g(t) = s(t) \\ast h(t)\n",
115
    "    gt = convolution(s, h) # numerical convolution\n",
116
117
118
    "    intervals_g = np.unique(np.tile(intervals_h, len(intervals_s)) + np.repeat(intervals_s, len(intervals_h))) # intervals of g(t)\n",
    "    if intervals_g.size == 0: # \n",
    "        intervals_g = np.concatenate([intervals_s, intervals_h])\n",
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
119
    "    \n",
120
    "    # Plot\n",
121
    "    if not axs0[0].lines: # plot s(t) and g(t)\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
122
123
    "        ax = axs0[0]; ax.plot(tau, s(tau), 'rwth');\n",
    "        ax.set_xlabel(r'$\\rightarrow t$'); ax.set_ylabel(r'$\\uparrow s(t)$')\n",
124
    "        ax.set_xlim([-2.9, 2.9]); ax.set_ylim([-1.19, 1.19]);  ient_axis(ax); ient_grid(ax);\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
125
126
127
    "        \n",
    "        ax = axs0[1]; ax.plot(tau, h(tau), 'rwth');\n",
    "        ax.set_xlabel(r'$\\rightarrow t$'); ax.set_ylabel(r'$\\uparrow h(t)$')\n",
128
    "        ax.set_xlim(axs0[0].get_xlim()); ax.set_ylim(axs0[0].get_ylim()); ient_axis(ax); ient_grid(ax);  fig0.tight_layout();\n",
129
    "    else: # update lines\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
130
131
    "        axs0[0].lines[0].set_ydata(s(tau)); \n",
    "        axs0[1].lines[0].set_ydata(h(tau));\n",
132
133
    "    try: # if convolution figure is already opened, update s(tau)\n",
    "        if axs[0].lines:\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
134
135
136
    "            axs[0].lines[1].set_ydata(s(tau));\n",
    "            ient_update_ylim(axs[0], np.concatenate((h(tau), s(tau))), 0.19, 5); ient_update_ylim(axs[1], gt, 0.19, 5);\n",
    "            update_plot(-2) # update convolution plot\n",
137
138
    "            update_plot_intervals() # update interval lines\n",
    "            \n",
139
    "    except: pass\n",
140
141
142
143
144
145
146
147
148
149
150
    "    ient_update_ylim(axs0[0], s(tau), 0.19, 5);  ient_update_ylim(axs0[1], h(tau), 0.19, 5);\n",
    "    \n",
    "# Widgets\n",
    "w_s_type = widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $s(t)$:')\n",
    "w_s_T = widgets.FloatSlider(min=0.5, max=4, value=1, step=.1, description=r'Dehnung T', style=ient_wdgtl_style)\n",
    "w_s_t0 = s_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=ient_wdgtl_style)\n",
    "w_h_type = widgets.Dropdown(options=list(signal_types.keys()), description=r'Wähle $h(t)$:')\n",
    "w_h_T = widgets.FloatSlider(min=0.5, max=4, value=1, step=.1, description=r'Dehnung T', style=ient_wdgtl_style)\n",
    "w_h_t0 = s_t0=widgets.FloatSlider(min=-2, max=2, value=0, step=.1, description=r'Verschiebung $t_0$', style=ient_wdgtl_style)\n",
    "w = widgets.interactive(update_signals, s_type=w_s_type, s_T=w_s_T, s_t0=w_s_t0, h_type=w_h_type, h_T=w_h_T, h_t0 = w_h_t0)\n",
    "display(widgets.HBox((widgets.VBox((w_s_type, w_s_T, w_s_t0)), widgets.VBox((w_h_type, w_h_T, w_h_t0), layout=Layout(margin='0 0 0 100px'))))); w.update();"
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
151
152
153
154
155
156
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
Iris Heisterklaus's avatar
Iris Heisterklaus committed
157
    "... und betrachte hier das Faltungsergebnis:"
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
158
159
160
161
   ]
  },
  {
   "cell_type": "code",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
162
   "execution_count": null,
Christian Rohlfing's avatar
Christian Rohlfing committed
163
   "metadata": {
164
165
166
167
    "hide_input": true,
    "jupyter": {
     "source_hidden": true
    }
Christian Rohlfing's avatar
Christian Rohlfing committed
168
   },
Iris Heisterklaus's avatar
Iris Heisterklaus committed
169
   "outputs": [],
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
170
   "source": [
171
    "fig, axs = plt.subplots(2, 1,  figsize=(12, 12/ient_fig_aspect)) # gridspec_kw = {'width_ratios':[3, 1]}\n",
172
173
174
    "t_w = widgets.FloatSlider(min=-4, max=4, value=-2, step=.1, description='Verschiebung $t$', style=ient_wdgtl_style)\n",
    "intervals_gt = np.array([t_w.min, t_w.max])\n",
    "@widgets.interact(t=t_w, \n",
175
    "                  show_integrand=widgets.Checkbox(value=True, description='Zeige Integrand', style=ient_wdgtl_style))\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
176
    "def update_plot(t, show_integrand=True):\n",
177
    "    global interval_cnt, intervals_gt\n",
178
    "    t_ind = np.where(tau>=t); t_ind = t_ind[0][0]; g_plot = gt.copy(); g_plot[t_ind:] = np.nan; # hide g(t') with t'>t\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
179
    "    sh = s(tau)*h(t-tau) # integrand\n",
180
181
182
    "    interval_cnt = np.argwhere((intervals_gt[1:] > t) & (intervals_gt[:-1] <= t)); # interval\n",
    "    interval_cnt = 0 if interval_cnt.size == 0 else interval_cnt[0][0]; # check for end of interval\n",
    "        \n",
Christian Rohlfing's avatar
Christian Rohlfing committed
183
    "    if not axs[0].lines: # Call plot() and decorate axes. Usually, these functions take some processing time\n",
184
    "        ax = axs[0]; ax.plot(tau, h(t-tau), 'rwth', label=r'$h(t-\\tau)$'); # plot h(t-tau)\n",
185
    "        ax.plot(tau, s(tau), 'grun', label=r'$s(\\tau)$'); # plot s(tau)\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
186
187
188
    "        ax.plot(tau, sh, '--', color='orange', lw=1, label=r'$s(\\tau)h(t-\\tau)$'); # plot integrand\n",
    "        ient_annotate_xtick(ax, r'$t$', t, -0.1, 'rwth', 15); # mark t on tau axis\n",
    "        ax.fill_between(tau, 0, sh, facecolor=\"none\", hatch=\"//\", edgecolor='k', linewidth=0.0); # hatch common area\n",
189
190
191
    "        ax.set_xlabel(r'$\\rightarrow \\tau$');\n",
    "        ax.set_xlim([-4.2,4.2]); ient_update_ylim(ax, np.concatenate((h(tau), s(tau))), 0.19, 5);\n",
    "        ax.legend(); ient_grid(ax); ient_axis(ax);\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
192
    "        \n",
193
    "        ax = axs[1]; ax.plot(tau, g_plot); # plot g(t)\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
194
    "        ax.plot([t, t], [0, gt[t_ind]], 'ko--', lw=1);\n",
195
    "        ax.set_xlabel(r'$\\rightarrow t$'); ax.set_ylabel(r'$\\uparrow g(t)=s(t)\\ast h(t)$'); \n",
196
197
    "        ax.set_xlim(axs[0].get_xlim()); ient_update_ylim(ax, gt, 0.19, 5);\n",
    "        ient_grid(ax); ient_axis(ax); fig.tight_layout(); #plt.subplots_adjust(wspace=.1,hspace=.1)\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
198
199
    "        \n",
    "    else: # Replace only xdata and ydata since plt.plot() takes longer time\n",
200
201
202
    "        ax = axs[0]; ax.lines[0].set_ydata(h(t-tau)); ax.lines[2].set_ydata(sh); # update signals\n",
    "        ax.texts[0].set_x(t); ax.lines[3].set_xdata([t,t]) # update labels\n",
    "        if ax.collections: ax.collections[0].remove(); # update integrand\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
203
    "        if show_integrand: ax.fill_between(tau,0,sh, facecolor=\"none\", hatch=\"//\", edgecolor='k', linewidth=0.0);\n",
204
205
    "        ax = axs[1]; ax.lines[0].set_ydata(g_plot); # update signals\n",
    "        ax.lines[1].set_xdata([t, t]); ax.lines[1].set_ydata([0, gt[t_ind]]); # update labels\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
206
    "\n",
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    "    axs[0].lines[2].set_visible(show_integrand)\n",
    "    \n",
    "ax_intervals = axs[1].twinx(); ax_intervals.set_visible(False)\n",
    "def update_plot_intervals():\n",
    "    # Update interval lines\n",
    "    ax_intervals.clear(); ax_intervals.axis('off');\n",
    "    for x in intervals_g:\n",
    "        ax_intervals.axvline(x, color=rwth_colors['rot'],linestyle='--',lw=1)\n",
    "    try:\n",
    "        toggle_stepwise(stepwise.value)\n",
    "    except: pass\n",
    "\n",
    "update_plot_intervals()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Verschiebung $t$ kann automatisch abgespielt werden. Eine schrittweise Betrachtung ist ebenfalls möglich."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "def update_t_slider(ti):\n",
    "    global interval_cnt\n",
    "\n",
    "    if interval_cnt > len(intervals_gt)-2:\n",
    "        interval_cnt = 0\n",
    "    \n",
    "    tmin = intervals_gt[interval_cnt]; tmax = intervals_gt[interval_cnt+1];\n",
    "    t_w.value = tmin + ti/100*(tmax-tmin) # Update float slider\n",
    "    \n",
    "def reset_t_slider(b):\n",
    "    global interval_cnt\n",
    "    play._playing = False\n",
    "    interval_cnt = 0\n",
    "    intslider.value = 0\n",
    "    stepwise.value = False\n",
    "    update_t_slider(0)\n",
    "    \n",
    "def update_stepwise(args):\n",
    "    visible = args['new']\n",
    "    toggle_stepwise(visible)\n",
    "    \n",
    "def toggle_stepwise(visible):\n",
    "    global intervals_gt\n",
    "    ax_intervals.set_visible(visible)\n",
    "    if visible:\n",
    "        intervals_gt = np.hstack([t_w.min, intervals_g, t_w.max ])\n",
    "    else:\n",
    "        intervals_gt = np.array([t_w.min, t_w.max])\n",
    "    \n",
    "        \n",
    "# Widget\n",
    "play = widgets.Play(value=0, min=0, max=100,step=10, description=\"Press play\", show_repeat=False)\n",
    "stepwise =widgets.Checkbox(value=False, description='Schrittweise')\n",
    "reset = widgets.Button(description=\"Reset\"); reset.on_click(reset_t_slider);\n",
    "intslider = widgets.IntSlider(description='Fortschritt') # Dummy slider in integer format, to be mapped to float slider\n",
    "status = widgets.Label(value='Nothing')\n",
    "widgets.jslink((play, 'value'), (intslider, 'value')) # Link dummy slider to player\n",
    "\n",
    "#def update_t_limits(args):\n",
    "#    status.value = str(np.round(intslider.value)) + \" \" + str(t_w.value) + \" \" + str(interval_cnt) + \" \" + str(args['old']) + \" \" + str(args['new']);\n",
    "#play.observe(update_t_limits, '_playing')\n",
    "\n",
    "stepwise.observe(update_stepwise, 'value')\n",
    "widgets.interactive(update_t_slider, ti = intslider); intslider.layout.display = 'none';\n",
    "widgets.HBox([play, stepwise, reset, intslider])#, status"
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
284
285
   ]
  },
286
287
288
289
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
290
291
    "### Aufgaben:\n",
    "\n",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
292
    "* Bewege den Schieberegler für $t$ und betrachte das entstehende Faltungsintegral. Wie sind die zugehörigen Integralsgrenzen und welche Intervalle (vgl. Notebook zur Faltung) sind zu beobachten?\n",
293
    "* Wähle zwei Rechtecke unterschiedlicher Breite aus. Wie sieht das entstehende Signal aus? Wie breit ist es? Was passiert, wenn eins der Rechtecke um $t_0$ verschoben wird?\n",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
294
295
    "* Welche Höhe bei $t=0$ hat das Resultat der Faltung $g(t) = \\mathrm{rect}\\left(\\frac{t}{2}\\right)\\ast \\mathrm{rect}\\left(\\frac{t}{2}\\right)$? Überprüfe die Überlegungen mit Hilfe der entsprechenden Funktionen in der Demo.\n",
    "* Gilt das Kommutativgesetz $s(t) \\ast h(t) = h(t) \\ast s(t)$?\n",
296
    "* Wie sieht das Faltungsergebnis zweier si-Funktionen aus? Wie das Ergebnis zweier Gaußfunktionen?\n",
Iris Heisterklaus's avatar
Iris Heisterklaus committed
297
    "* Reale Rechteckimpulse weisen nur eine endliche Flankensteilheit auf. Diese können beispielsweise mit $s(t)=\\mathrm{rect}(t)*\\mathrm{rect}(t/T)$ oder $s(t)=\\mathrm{rect}(t)*\\Lambda(\\frac{t}{T})$ beschrieben werden. Betrachte diese Fälle für $|T|<\\frac{1}{2}$. Wie hängen Gesamtdauer und Dauer der Anstiegsflanke von $T$ ab?"
298
299
   ]
  },
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
300
301
  {
   "cell_type": "markdown",
Hafiz Emin Kosar's avatar
Hafiz Emin Kosar committed
302
303
304
   "metadata": {
    "hidePrompt": true
   },
Christian Rohlfing's avatar
Christian Rohlfing committed
305
   "source": [
306
    "---\n",
Christian Rohlfing's avatar
Christian Rohlfing committed
307
308
309
    "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",
310
    "*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."
Christian Rohlfing's avatar
Christian Rohlfing committed
311
   ]
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  }
 ],
 "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",
330
   "version": "3.8.1"
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
331
332
333
  }
 },
 "nbformat": 4,
334
 "nbformat_minor": 4
Christian Rohlfing's avatar
- init  
Christian Rohlfing committed
335
}