Init
This commit is contained in:
446
.ipynb_checkpoints/U00_Intro-checkpoint.ipynb
Normal file
446
.ipynb_checkpoints/U00_Intro-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
445
.ipynb_checkpoints/U00_Intro.en-checkpoint.ipynb
Normal file
445
.ipynb_checkpoints/U00_Intro.en-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
1254
.ipynb_checkpoints/U01_DSP_Basics-checkpoint.ipynb
Normal file
1254
.ipynb_checkpoints/U01_DSP_Basics-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
1256
.ipynb_checkpoints/U01_DSP_Basics.en-checkpoint.ipynb
Normal file
1256
.ipynb_checkpoints/U01_DSP_Basics.en-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
116
.ipynb_checkpoints/U02_1_Input.en-checkpoint.ipynb
Normal file
116
.ipynb_checkpoints/U02_1_Input.en-checkpoint.ipynb
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d709b880",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Input"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5f40e11b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here you can download the input files (right click / save as...):\n",
|
||||
"* <a href=_static/2024-03-16-16k.in download>2024-03-16</a>\n",
|
||||
"* <a href=_static/2023-04-20-16k.in download>2023-04-20</a>\n",
|
||||
"* <a href=_static/2023-06-15-16k.in download>2023-06-15</a>\n",
|
||||
"* <a href=_static/2024-03-14-16k.in download>2023-03-14</a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6ab69020",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In diesem Projekt arbeiten wir mit Audio-Daten.\n",
|
||||
"Um das Einlesen möglichst unkompliziert zu halten, stellen wir die Eingabe in einem einfachen Format bereit:\n",
|
||||
"\n",
|
||||
"```{admonition} Format\n",
|
||||
"Die erste Zeile enthält $n$, die Anzahl der Samples ($0 \\leq n < 2^{32}$).\n",
|
||||
"\n",
|
||||
"Danach folgen $n$ Zeilen mit jeweils einem Sample $x$ als ganze Zahl ($-2^{15} \\leq x < 2^{15}$)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Die Abtastrate $f_S$ ist dabei 16640 Hz.\n",
|
||||
"\n",
|
||||
"## Beispiel\n",
|
||||
"```\n",
|
||||
"10\n",
|
||||
"623\n",
|
||||
"-310\n",
|
||||
"-273\n",
|
||||
"3404\n",
|
||||
"4745\n",
|
||||
"655\n",
|
||||
"-454\n",
|
||||
"3463\n",
|
||||
"3375\n",
|
||||
"-5350\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```{note}\n",
|
||||
"Die Werte der Samples sind hier zwar ganze Zahlen, aber für den Rest des Projekts ergibt es Sinn sie hier schon in Floating-Point Werte umzuwandeln.\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cfcac6c9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Visualisierung\n",
|
||||
"\n",
|
||||
"In diesem Projekt kann es sehr hilfreich sein, sich nach jedem Arbeitsschritt das Ergebnis zu visualisieren.\n",
|
||||
"Das können wir zum Beispiel so tun:\n",
|
||||
"- Das Signal enthält 2 Zeilen mit je 2080 Pixeln pro Sekunde. Mit $f_S = 16640\\text{Hz}$ haben wir also 4 Samples pro Pixel.\n",
|
||||
"- Wir nehmen jedes 4. Sample, falls es komplex ist berechnen wir den Betrag $(a + ib \\mapsto \\sqrt{a^2+b^2} =\\mathrel{\\vcenter{:}} v)$.\n",
|
||||
"- Wir finden $v_{min}$ und $v_{max}$, den kleinsten bzw. größten so erhaltenen Wert.\n",
|
||||
" Dann skalieren wir jedes $v$ nach $255 \\cdot (v - v_{min}) / (v_{max} - v_{min})$.\n",
|
||||
" Damit bekommen wir einen Wert zwischen 0 und 255.\n",
|
||||
"- Diese Werte können wir jetzt als Pixel in einer Bilddatei abspeichern.\n",
|
||||
" Dazu können wir zum Beispiel das [](pgm-format) benutzen.\n",
|
||||
" \n",
|
||||
"```{figure} img/reference/raw_full_scaled.webp\n",
|
||||
"---\n",
|
||||
"name: fig:raw_full.en\n",
|
||||
"---\n",
|
||||
"Visualisierung direkt nach dem Einlesen.\n",
|
||||
"Man kann das Bild fast schon erkennen, es ist aber noch sehr dunkel.\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```{figure} img/reference/raw_detail.webp\n",
|
||||
"---\n",
|
||||
"name: fig:raw_detail.en\n",
|
||||
"---\n",
|
||||
"Detailansicht.\n",
|
||||
"Hier sieht man deutliche vertikale Streifen, die von der Modulation auf den 2.4kHz Carrier kommen.\n",
|
||||
"```"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"celltoolbar": "Tags",
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.11.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
112
.ipynb_checkpoints/U02_2_Freq_Shift.en-checkpoint.ipynb
Normal file
112
.ipynb_checkpoints/U02_2_Freq_Shift.en-checkpoint.ipynb
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e67c2a43",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Frequenz-Shift"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6482d25c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```{figure} img/reference/raw_waterfall.webp\n",
|
||||
"---\n",
|
||||
"name: fig:raw_waterfall.en\n",
|
||||
"---\n",
|
||||
"Wasserfall-Diagramm. Wir können die beiden Kopien des Spektrums bei $\\pm2.4\\text{kHz}$ erkennen.\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cbe50415",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Als ersten Schritt wollen wir die Kopie des Spektrums bei 2.4kHz \"auf die 0\" verschieben.\n",
|
||||
"\n",
|
||||
"Im Frequenz-Bereich können wir diese Verschiebung als eine Faltung mit einem Peak bei -2.4kHz darstellen.\n",
|
||||
"Wie können wir so einen Peak erzeugen?\n",
|
||||
"\n",
|
||||
"Wir erinnern uns:\n",
|
||||
"$\\sin(2\\pi f t)$ und $\\cos(2\\pi f t)$ hatten Peaks bei $\\pm f$.\n",
|
||||
"\n",
|
||||
"Genauer gesagt:\n",
|
||||
"```{math}\n",
|
||||
"\\begin{align*}\n",
|
||||
"\\sin(2\\pi f_0 t) \\,&\\circ\\!\\!-\\!\\!\\bullet\\, \\left\\{\\begin{array}{rcl}\n",
|
||||
" \\frac{1}{2}i &∶& f = -f_0 \\\\\n",
|
||||
" -\\frac{1}{2}i &:& f = f_0 \\\\\n",
|
||||
" 0 &:& \\text{sonst} \\\\\n",
|
||||
"\\end{array}\\right. \\\\\n",
|
||||
"\\cos(2\\pi f_0 t) \\,&\\circ\\!\\!-\\!\\!\\bullet\\, \\left\\{\\begin{array}{rcl}\n",
|
||||
" \\frac{1}{2} &∶& f \\in \\{-f_0, f_0\\} \\\\\n",
|
||||
" 0 &:& \\text{sonst} \\\\\n",
|
||||
"\\end{array}\\right. \\\\\n",
|
||||
"\\end{align*}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Damit haben wir jeweils zwei Peaks.\n",
|
||||
"Wir können Sinus und Cosinus aber geschickt kombinieren so dass sich einer davon aufhebt:\n",
|
||||
"Wenn wir den Sinus mit $i$ multiplizieren bekommen wir:\n",
|
||||
"```{math}\n",
|
||||
"i \\cdot \\sin(2\\pi f_0 t) \\,&\\circ\\!\\!-\\!\\!\\bullet\\, \\left\\{\\begin{array}{rcl}\n",
|
||||
" i \\cdot \\frac{1}{2}i = -\\frac{1}{2} &∶& f = -f_0 \\\\\n",
|
||||
" i \\cdot -\\frac{1}{2}i = \\frac{1}{2} &:& f = f_0 \\\\\n",
|
||||
" 0 &:& \\text{sonst} \\\\\n",
|
||||
"\\end{array}\\right.\n",
|
||||
"```\n",
|
||||
"Und wenn wir jetzt noch den Cosinus addieren:\n",
|
||||
"```{math}\n",
|
||||
"\\cos(2\\pi f_0 t) + i\\sin(2\\pi f_0 t) \\,&\\circ\\!\\!-\\!\\!\\bullet\\, \\left\\{\\begin{array}{rcl}\n",
|
||||
" \\frac{1}{2} -\\frac{1}{2} = 0 &∶& f = -f_0 \\\\\n",
|
||||
" \\frac{1}{2} + \\frac{1}{2} = 1 &:& f = f_0 \\\\\n",
|
||||
" 0 &:& \\text{sonst} \\\\\n",
|
||||
"\\end{array}\\right.\n",
|
||||
"```\n",
|
||||
"Damit haben wir genau den Peak bei $f_0$.\n",
|
||||
"\n",
|
||||
"```{note}\n",
|
||||
"Den Ausdruck $\\cos(x) + i\\sin(x)$ habt ihr vielleicht schon mal in der [Eulerschen Formel](https://de.wikipedia.org/wiki/Eulersche_Formel) gesehen.\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Um den Frequenz-Shift durchzuführen, können wir also einfach in der Zeit-Domain (= auf den Samples) mit dieser Funktion multiplizieren.\n",
|
||||
"Dazu gehen wir so vor:\n",
|
||||
"- Für jedes Sample $s$ berechnen wir den aktuellen Zeitpunkt $t$.\n",
|
||||
" Durch die Abtastrate $f_S = 16640\\text{Hz}$ wissen wir, dass der Zeitabstand zwischen zwei Samples genau $1/16640\\text{s}$ ist.\n",
|
||||
"- Dann berechnen wir $\\cos(2\\pi \\cdot -2400 \\cdot t) + i \\cdot \\sin(2\\pi \\cdot -2400 \\cdot t)$ und erhalten einen komplexen Wert $a + bi$.\n",
|
||||
"- Diesen multiplizieren wir mit $s$ und erhalten $a \\cdot s + (b \\cdot s)i$ und speichern ihn als neues, komplexes Sample.\n",
|
||||
"\n",
|
||||
"```{note}\n",
|
||||
"Für dieses Projekt reicht es theoretisch aus, komplexe Zahlen als Paare von jeweils zwei reelle Zahlen zu speichern.\n",
|
||||
"In manchen Programmiersprachen gibt es aber auch explizite Typen, um komplexe Zahlen darzustellen, z.B. [std::complex](https://en.cppreference.com/w/cpp/numeric/complex) in C++.\n",
|
||||
"In Python kann man sie sogar einfach mit `a + b * 1j` erzeugen.\n",
|
||||
"```"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.11.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
318
.ipynb_checkpoints/U02_3_Low_Pass.en-checkpoint.ipynb
Normal file
318
.ipynb_checkpoints/U02_3_Low_Pass.en-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
79
.ipynb_checkpoints/U02_4_Sync.en-checkpoint.ipynb
Normal file
79
.ipynb_checkpoints/U02_4_Sync.en-checkpoint.ipynb
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f611b5a0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Synchronisierung"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0c5468d3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Aktuell sind die Samples noch als komplexe Zahlen dargestellt.\n",
|
||||
"Um weiter mit ihnen arbeiten zu können, nehmen wir jeweils den Betrag:\n",
|
||||
"```{math}\n",
|
||||
"s = a + bi \\mapsto |s| = \\sqrt{a^2 + b^2}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Hier eine Visualisierung des soweit verarbeiteten Signals:\n",
|
||||
"```{figure} img/reference/filtered_full_scaled.webp\n",
|
||||
"---\n",
|
||||
"name: fig:filtered_full_scaled.en\n",
|
||||
"---\n",
|
||||
"Gefiltertes Signal.\n",
|
||||
"Wir sehen dass die Sync-Streifen gebogen sind.\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Die Sync-Patterns markieren jeweils den Anfang einer Zeile.\n",
|
||||
"Um das Bild \"gerade zu ziehen\" müssen wir sie finden.\n",
|
||||
"\n",
|
||||
"Dazu gehen wir so vor:\n",
|
||||
"- Sync A hat das Pattern `000011001100110011001100110011000000000`.\n",
|
||||
" Wir haben 4 Samples pro Pixel, also auch pro 0/1 im Pattern.\n",
|
||||
" Dieses Pattern wollen wir suchen.\n",
|
||||
" Das funktioniert hier am besten, wenn wir sowohl das Pattern als auch die Samples in den Wertebereich zwischen $-1$ und $1$ skalieren.\n",
|
||||
" Für jede `0` im Pattern nehmen wir also 4 mal die $-1$, und für jede `1` nehmen wir 4 mal die $1$.\n",
|
||||
" Diese Sequenz von 39 * 4 = 156 Werten speichern wir als $p$.\n",
|
||||
"- Jetzt betrachten wir Blöcke $x$ von 8320 Samples.\n",
|
||||
" Wir finden Minimum $x_{min}$ und Maximum $x_{max}$ im Block, und skalieren so dass das Minimum bei $-1$ ist und das Maximum bei $1$:\n",
|
||||
" ```{math}\n",
|
||||
" x[n] \\mapsto -1 + 2 \\cdot \\frac{x[n] - x_{min}}{x_{max} - x_{min}}\n",
|
||||
" ```\n",
|
||||
"- Wir wollen die Position finden, die \"am meisten\" mit dem Pattern übereinstimmt.\n",
|
||||
" Also iterieren wir über alle Startpositionen $i$ im Block, 0 bis (8320-156).\n",
|
||||
" Für jede davon berechnen wir\n",
|
||||
" ```{math}\n",
|
||||
" z = \\sum_{n=0}^{156} x[i + n] \\cdot p[n]\n",
|
||||
" ```\n",
|
||||
" Die Position bei der $z$ am größten ist, ist die mit der besten Übereinstimmung.\n",
|
||||
"- So können wir für jede Zeile die Anfangsposition finden.\n",
|
||||
" Von dort aus gehen wir in Viererschritten über die Samples, um die Pixelwerte für die Zeile zu erhalten."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.11.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
129
.ipynb_checkpoints/U02_5_Output.en-checkpoint.ipynb
Normal file
129
.ipynb_checkpoints/U02_5_Output.en-checkpoint.ipynb
Normal file
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "af12be1c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Ausgabe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8de61e70",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Wir haben jetzt Werte für die Pixel des Bildes, aber sie sind noch nicht im richtigen Bereich:\n",
|
||||
"Sie müssen am Ende nämlich zwischen 0 und 255 liegen.\n",
|
||||
"\n",
|
||||
"Um sie zu richtig zu skalieren, verwenden wir den \"Space and Marker\" Teil des Bildformats:\n",
|
||||
"\n",
|
||||
"```{figure} img/apt_frame_format.webp\n",
|
||||
"---\n",
|
||||
"name: fig:frame_format_output.en\n",
|
||||
"---\n",
|
||||
"Wieder das APT Bildformat.\n",
|
||||
"Nach Sync A (39 Pixel breit) folgt ein 47 Pixel breiter Space mit schwarzen Pixeln.\n",
|
||||
"Analog dazu sind in der zweiten Hälfte des Bildes der ebenfalls 39 Pixel breite Sync B und ein 47 Pixel breiter Space mit weißen Pixeln.\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Der Sync A folgende Space hat (bis auf den Minute Marker) weiße Pixel, und der Space nach Sync B schwarze.\n",
|
||||
"Die Minute Marker ignorieren wir hier einfach :)\n",
|
||||
"\n",
|
||||
"Um die Pixelwerte in den richtigen Bereich zu skalieren können wir so vorgehen:\n",
|
||||
"- Wir berechnen das Schwarz-Level $v_b$ indem wir den Durchschnitt (oder den [Median](https://de.wikipedia.org/wiki/Median)) aller Pixelwerte im ersten Space nehmen.\n",
|
||||
"- Das gleiche tun wir für den Weiß-Level $v_w$ mit dem zweiten Space.\n",
|
||||
"- Jetzt bilden wir jeden Pixelwert $v$ auf $(v - v_b) / (v_w - v_b)$ ab.\n",
|
||||
"- Damit sind die Werte zwischen $v_b$ und $v_w$ in den Bereich zwischen 0 und 1 gewandert.\n",
|
||||
"- Alle Werte kleiner als 0 oder größer als 1 werden auf 0 bzw. 1 begrenzt.\n",
|
||||
"- Jetzt müssen wir nur noch jeden Wert mit 255 multiplizieren."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "436e60e1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"(pgm-format)=\n",
|
||||
"## PGM-Format\n",
|
||||
"\n",
|
||||
"```{note}\n",
|
||||
"Wer möchte, kann natürlich gerne ein anderes Format benutzen, oder eine Bibliothek wie [Pillow](https://python-pillow.org/) oder [SDL](https://www.libsdl.org/).\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Um das fertige Bild in eine Datei zu schreiben, können wir zum Beispiel dieses sehr einfache Dateiformat benutzen:\n",
|
||||
"\n",
|
||||
"```{admonition} Format\n",
|
||||
"Die erste Zeile enthält den String `P2`.\n",
|
||||
"\n",
|
||||
"Die zweite Zeile enthält zwei positive Integer $w$ und $h$, die Breite $(w)$ und Höhe $(h)$ des Bildes $(w = 2080, h \\approx 1400)$.\n",
|
||||
"\n",
|
||||
"Die dritte Zeile enthält einen positiven Integer $v_{max} = 255$.\n",
|
||||
"\n",
|
||||
"Danach folgen $h$ Zeilen mit jeweils $w$ Pixelwerten $v$ als Integer $(0 \\leq v \\leq v_{max})$.\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1ab1434e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Beispiel\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"P2\n",
|
||||
"6 7\n",
|
||||
"255\n",
|
||||
" 0 6 12 18 24 30\n",
|
||||
" 6 240 235 230 30 36\n",
|
||||
"12 235 24 30 220 42\n",
|
||||
"18 230 235 220 42 48\n",
|
||||
"24 225 36 42 210 54\n",
|
||||
"30 220 215 210 54 60\n",
|
||||
"36 42 48 54 60 66\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c2c9a6b9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```{note}\n",
|
||||
"Das PGM-Format ist nur für Bilder in Graustufen, aber es gibt auch z.B. das PPM-Format für farbige Bilder.\n",
|
||||
"[Hier](https://en.wikipedia.org/wiki/Netpbm) könnt ihr mehr dazu lesen.\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d16219b2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Wenn wir unsere Pixelwerte so in eine Datei mit `.pgm`-Endung speichern, können wir sie mit einem Grafikprogramm wie z.B. [GIMP](https://www.gimp.org/) anschauen."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.11.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
320
.ipynb_checkpoints/U02_Project.en-checkpoint.ipynb
Normal file
320
.ipynb_checkpoints/U02_Project.en-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user