This commit is contained in:
parent
99a706ac56
commit
ea01adc26a
2 changed files with 24 additions and 20 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Die Operation einer #gls("puf") beinhaltet zwei verschiedene Arbeitsschritte: *Enrollment* und *Reconstruction*.\
|
Das Betreiben einer #gls("puf") beinhaltet zwei verschiedene Arbeitsschritte: *Enrollment* und *Reconstruction*.\
|
||||||
Als Enrollment wird die erste Messung des Verhaltens des Schaltkreises bezeichnet.
|
Als Enrollment wird die erste Messung des Verhaltens des Schaltkreises bezeichnet.
|
||||||
Diese kann direkt in der Fertigungsstätte des Schaltkreises durchgeführt werden.
|
Diese kann direkt in der Fertigungsstätte des Schaltkreises durchgeführt werden.
|
||||||
Da bis zu diesem Punkt noch keine andere Messung mit dem Schaltkreis durchgeführt worden ist, können die Ergebnisse aus diesem Schritt als unveränderlichen Referenzwert für das Geheimnis des Schaltkreises angenommen werden.
|
Da bis zu diesem Punkt noch keine andere Messung mit dem Schaltkreis durchgeführt worden ist, können die Ergebnisse aus diesem Schritt als unveränderlichen Referenzwert für das Geheimnis des Schaltkreises angenommen werden.
|
||||||
|
|
@ -12,7 +12,7 @@ Anschließend wird aus den Messergebnissen mittels eines Quantisierungsprozesses
|
||||||
Reconstruction bezeichnet jede weitere Messung des Verhaltens des Schaltkreises.
|
Reconstruction bezeichnet jede weitere Messung des Verhaltens des Schaltkreises.
|
||||||
Da Messfehler in diesem Schritt nicht ausgeschlossen werden können, ist davon auszugehen, dass das hier gemessene Geheimnis nicht mit dem Referenz-Geheimnis bzw. dem geheimen Schlüssel nach der Enrollment Phase vollständig übereinstimmt.
|
Da Messfehler in diesem Schritt nicht ausgeschlossen werden können, ist davon auszugehen, dass das hier gemessene Geheimnis nicht mit dem Referenz-Geheimnis bzw. dem geheimen Schlüssel nach der Enrollment Phase vollständig übereinstimmt.
|
||||||
Die Anzahl der Bits, die zwischen diesen beiden Schlüsseln verschieden ist, ist als Bitfehlerrate definiert.
|
Die Anzahl der Bits, die zwischen diesen beiden Schlüsseln verschieden ist, ist als Bitfehlerrate definiert.
|
||||||
Zusätzlich ist davon auszugehen, dass die Messwerte einer #gls("puf")
|
Zusätzlich ist davon auszugehen, dass die Messwerte einer #gls("puf")
|
||||||
normalverteilt und mittelwertfrei sind.
|
normalverteilt und mittelwertfrei sind.
|
||||||
|
|
||||||
Die Ausgangslage der Praxis stellt die Bachelorarbeit "Towards Efficient Helper Data Algorithms for Multi-Bit PUF Quantization" da.
|
Die Ausgangslage der Praxis stellt die Bachelorarbeit "Towards Efficient Helper Data Algorithms for Multi-Bit PUF Quantization" da.
|
||||||
|
|
@ -20,7 +20,7 @@ Konkret wurden in der Arbeit zwei verschiedene Methoden zur Verbesserung der Bit
|
||||||
Die erste Methode beschreibt eine Verallgemeinerung der #gls("tmhdt") @tmhd1.
|
Die erste Methode beschreibt eine Verallgemeinerung der #gls("tmhdt") @tmhd1.
|
||||||
Mit Hilfe von #gls("tmhdt") werden zwei verschiedene Quantisiererfunktionen definiert. Während der Enrollment Phase wird anschließend entschieden, welche der beiden Funktionen ein verlässlicheres Ergebnis bei wiederholten Messergebnissen hervorrufen wird.
|
Mit Hilfe von #gls("tmhdt") werden zwei verschiedene Quantisiererfunktionen definiert. Während der Enrollment Phase wird anschließend entschieden, welche der beiden Funktionen ein verlässlicheres Ergebnis bei wiederholten Messergebnissen hervorrufen wird.
|
||||||
Die #gls("smhdt") verallgemeinert dieses Konzept auf die Quantisierung mit mehr als einem Bit @smhd.
|
Die #gls("smhdt") verallgemeinert dieses Konzept auf die Quantisierung mit mehr als einem Bit @smhd.
|
||||||
Da mit der Publikation von Fischer @smhd bereits eine mögliche Implementation von #gls("smhdt") vorgestellt wurde, bildet die in der Arbeit vorgelegte Implementierung eine Basis um die Performanz der zweiten vorgestellten Methode einordnen zu können.
|
Da mit der Publikation von Fischer @smhd bereits eine mögliche Implementation von #gls("smhdt") vorgestellt wurde, bildet die in der Arbeit vorgelegte Implementierung eine Basis um die Performanz der zweiten vorgestellten Methode einordnen zu können.
|
||||||
|
|
||||||
Im zweiten Teil der Arbeit wurde ein neuer Ansatz zur Verbesserung der Fehlerrate implementiert und genauer analysiert.
|
Im zweiten Teil der Arbeit wurde ein neuer Ansatz zur Verbesserung der Fehlerrate implementiert und genauer analysiert.
|
||||||
Die Grundlage der neuen Methode ergibt sich aus der natürlichen Beschaffenheit der Standardnormalverteilung.
|
Die Grundlage der neuen Methode ergibt sich aus der natürlichen Beschaffenheit der Standardnormalverteilung.
|
||||||
|
|
@ -29,7 +29,7 @@ Da der Erwartungswert einer mittelwertfreien Normalverteilung bei $0$ liegt und
|
||||||
Dieses Problem wird in @bach_original_1 grafisch verdeutlicht.
|
Dieses Problem wird in @bach_original_1 grafisch verdeutlicht.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
include("../graphics/background/sign-based-overlay.typ"),
|
include("../graphics/background/sign-based-overlay.typ"),
|
||||||
caption: [1-bit Quantisierer mit normalverteilten Eingangswerten]
|
caption: [1-bit Quantisierer mit normalverteilten Eingangswerten]
|
||||||
)<bach_original_1>
|
)<bach_original_1>
|
||||||
|
|
||||||
|
|
@ -52,18 +52,18 @@ Mathematisch lässt sich dies durch die Maximierung des Betrags der Funktion aus
|
||||||
$ max_(h_1, h_2, h_3) |f(bold(x), bold(h))| $<eq:1bit_opt>
|
$ max_(h_1, h_2, h_3) |f(bold(x), bold(h))| $<eq:1bit_opt>
|
||||||
|
|
||||||
@eq:1bit_opt definiert hiermit die Funktion zur Optimierung der Eingangwerte vor dem Quantisierer für den 1-bit Fall.
|
@eq:1bit_opt definiert hiermit die Funktion zur Optimierung der Eingangwerte vor dem Quantisierer für den 1-bit Fall.
|
||||||
Jedoch wird die Definition dieser Funktion für eine Vorbereitung der Quantisierung höherer Ordnung um einiges komplexer.
|
Jedoch wird die Definition dieser Funktion für eine Vorbereitung der Quantisierung höherer Ordnung um einiges komplexer.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
include("../graphics/background/two-bit-enroll.typ"),
|
include("../graphics/background/two-bit-enroll.typ"),
|
||||||
caption: [2-bit Quantisierer Funktion]
|
caption: [2-bit Quantisierer Funktion]
|
||||||
)<fig:2bit_quant>
|
)<fig:2bit_quant>
|
||||||
|
|
||||||
Anstelle einer Quantisierung basierend auf dem Vorzeichen des Eingangswertes, wie in @bach_original_1 ist bei einer Quantisierung höherer Ordnung eine mehrstufige Entscheidungsfunktion mit mehreren Grenzen wie in @fig:2bit_quant notwendig.
|
Anstelle einer Quantisierung basierend auf dem Vorzeichen des Eingangswertes, wie in @bach_original_1 ist bei einer Quantisierung höherer Ordnung eine mehrstufige Entscheidungsfunktion mit mehreren Grenzen wie in @fig:2bit_quant notwendig.
|
||||||
Es stellt sich nun die Frage, wie man die Grenzen $g_1$ und $g_2$ aus @fig:2bit_quant wählt, um die Optimierung des 1-bit Falles aus @fig:bach_1_optimal auf Fälle höherer Bit-Ordnung zu übertragen.
|
Es stellt sich nun die Frage, wie man die Grenzen $g_1$ und $g_2$ aus @fig:2bit_quant wählt, um die Optimierung des 1-bit Falles aus @fig:bach_1_optimal auf Fälle höherer Bit-Ordnung zu übertragen.
|
||||||
|
|
||||||
Die ersten Ansätze der Bachelorarbeit beinhalteten zunächst ein naives Raten der möglichen Grenzen für die Quantisierung basierend auf einer Schätzung der Form der resultierenden Verteilung.
|
Die ersten Ansätze der Bachelorarbeit beinhalteten zunächst ein naives Raten der möglichen Grenzen für die Quantisierung basierend auf einer Schätzung der Form der resultierenden Verteilung.
|
||||||
Zunächst wurde ein globales Optimierungsverfahren untersucht, bei dem nach einer ersten Optimierung nach der maximalen Distanz zu allen Grenzen, neue Grenzen basierend auf einer empirischen kumulativen Wahrscheinlichkeitsdichtefunktion definiert werden. Dieser Prozess wurde anschließend über mehrere Iterationen hinweg durchgeführt, um ein stabiles Ergebnis Wahrscheinlichkeitsverteilungen zu erhalten.
|
Zunächst wurde ein globales Optimierungsverfahren untersucht, bei dem nach einer ersten Optimierung nach der maximalen Distanz zu allen Grenzen, neue Grenzen basierend auf einer empirischen kumulativen Wahrscheinlichkeitsdichtefunktion definiert werden. Dieser Prozess wurde anschließend über mehrere Iterationen hinweg durchgeführt, um ein stabiles Ergebnis Wahrscheinlichkeitsverteilungen zu erhalten.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
grid(
|
grid(
|
||||||
|
|
@ -86,7 +86,7 @@ grid(
|
||||||
@fig:bach_instability zeigt die Ergebnisse dieses iterativen Prozesses zu verschiedenen Zeitpunkten.
|
@fig:bach_instability zeigt die Ergebnisse dieses iterativen Prozesses zu verschiedenen Zeitpunkten.
|
||||||
Wegen des sehr instabilen Verhaltens der Verteilungen auch über mehrere Iterationen hinweg wurde eine zweite, konvergierende Methode untersucht.
|
Wegen des sehr instabilen Verhaltens der Verteilungen auch über mehrere Iterationen hinweg wurde eine zweite, konvergierende Methode untersucht.
|
||||||
|
|
||||||
Anstelle die Gewichtungen zu wählen, dass die resultierende Summe möglichst weit weg von allen Grenzen liegt, sollen die Summen möglichst genau die Mitten zwischen den Grenzen treffen und so implizit möglichst weit weg von den Grenzen liegen.
|
Anstelle die Gewichtungen zu wählen, dass die resultierende Summe möglichst weit weg von allen Grenzen liegt, sollen die Summen möglichst genau die Mitten zwischen den Grenzen treffen und so implizit möglichst weit weg von den Grenzen liegen.
|
||||||
Diese Methode hatte zwar den Vorteil, dass die hervorgehenden Verteilungen zu einer festen Verteilung konvergieren, jedoch zeigte eine spätere Analyse keine signifikante Verbesserung der Bitfehlerrate auf.
|
Diese Methode hatte zwar den Vorteil, dass die hervorgehenden Verteilungen zu einer festen Verteilung konvergieren, jedoch zeigte eine spätere Analyse keine signifikante Verbesserung der Bitfehlerrate auf.
|
||||||
|
|
||||||
Ziel der Ingenieurspraxis ist nun, eine mögliche Lösung für das Problem der Konvergenz dieses Ansatzes zu finden und mit anderen Methoden zur Verbesserung der Bitfehlerrate zu vergleichen.
|
Ziel der Ingenieurspraxis ist nun, eine mögliche Lösung für das Problem der Konvergenz dieses Ansatzes zu finden und mit anderen Methoden zur Verbesserung der Bitfehlerrate zu vergleichen.
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,11 @@ Aufgrund der Nähe der Themen hat sich eine Recherche zu den "k-Means Clustering
|
||||||
==== Vergleiche der Algorithmen mit dem gestellten Problem
|
==== Vergleiche der Algorithmen mit dem gestellten Problem
|
||||||
|
|
||||||
Sowohl die hier vorgestellten Methoden, als auch die "k-Means Clustering" und EM Algorithmen lösen ein Optimierungsproblem mittels eines iterativen Verfahrens.
|
Sowohl die hier vorgestellten Methoden, als auch die "k-Means Clustering" und EM Algorithmen lösen ein Optimierungsproblem mittels eines iterativen Verfahrens.
|
||||||
Der EM-Algorithmus befasst sich mit der Schätzung von Parametern in statistischen Modellen, insbesondere wenn der vorgegebene Datensatz unvollständig ist, während der "k-Means" Algorithmus darauf abzielt, Daten in Cluster zu gruppieren. Besonderes bei letzterem ähnelt die Clusterbildung sehr dem hier gestellten Problem.
|
Der EM-Algorithmus befasst sich mit der Schätzung von Parametern in statistischen Modellen, insbesondere wenn der vorgegebene Datensatz unvollständig ist.
|
||||||
|
Währenddessen zielt der "k-Means" Algorithmus darauf ab, Daten in Cluster zu gruppieren.
|
||||||
|
Besonderes bei letzterem ähnelt die Clusterbildung sehr dem hier gestellten Problem.
|
||||||
Ein entscheidender Unterschied ist, dass bei k-Means Datenpunkte nur einer vorgegebenen Anzahl an Clustern zugewiesen werden.
|
Ein entscheidender Unterschied ist, dass bei k-Means Datenpunkte nur einer vorgegebenen Anzahl an Clustern zugewiesen werden.
|
||||||
Eine Beschränkung, welche Datenpunkte in welches Cluster fallen, wird durch den Algorithmus nicht implementiert, wäre aber für eine Verbesserung der Eingangswerte vor der Quantisierung notwendig
|
Eine Beschränkung, welche Datenpunkte in welches Cluster fallen, wird durch den Algorithmus nicht implementiert, wäre aber für eine Verbesserung der Eingangswerte vor der Quantisierung notwendig, da sonst die Gleichverteilung der quantisierten Symbole nicht garantiert werden kann.
|
||||||
|
|
||||||
|
|
||||||
Wenngleich diese Publikationen keinen direkten Weg zur Lösung der Problemstellung der Praxis bieten konnten, stellten sie ein gutes Grundverständnis für diese Art von Problem dar.
|
Wenngleich diese Publikationen keinen direkten Weg zur Lösung der Problemstellung der Praxis bieten konnten, stellten sie ein gutes Grundverständnis für diese Art von Problem dar.
|
||||||
|
|
@ -26,12 +28,12 @@ Wenngleich diese Publikationen keinen direkten Weg zur Lösung der Problemstellu
|
||||||
|
|
||||||
=== Festlegung der verwendeten Toolings
|
=== Festlegung der verwendeten Toolings
|
||||||
|
|
||||||
Aufgrund der großen Effizienz und der gut ausgebauten Möglichkeit zur funktionalen Programmierung, wurde als Programmiersprache für das Projekt -- zur Implementierung der Algorithmen und Simulation der Bitfehlerrate -- Julia gewählt.
|
Aufgrund ihrer hohen Effizienz und der umfangreichen Unterstützung für funktionale Programmierung wurde für das Projekt, das die Implementierung der Algorithmen und die Simulation der Bitfehlerrate umfasst, die Programmiersprache Julia ausgewählt.
|
||||||
Im weiteren Verlauf der Praxis wurde zusätzlich für die verbesserte Möglichkeit der Visualisierung der Ergebnisse das Pluto Framework -- ein Julia-Pendant zu Jupyter Notebooks -- mit einbezogen.
|
Im weiteren Verlauf der Praxis wurde zusätzlich für die verbesserte Möglichkeit der Visualisierung der Ergebnisse das Pluto Framework -- ein Julia-Pendant zu Jupyter Notebooks -- mit einbezogen.
|
||||||
|
|
||||||
== Durchführung und Projektdokumentation
|
== Durchführung und Projektdokumentation
|
||||||
|
|
||||||
Für eine effiziente und übersichtliche Implementierung der Algorithmen und Simulationen wurde zunächst diverse Hilfsfunktionen in Julia implementiert. #figure(
|
Für eine effiziente und übersichtliche Implementierung der Algorithmen und Simulationen wurden zunächst diverse Hilfsfunktionen in Julia implementiert. #figure(
|
||||||
caption: "Generierung von allen möglichen Linearkombinationen"
|
caption: "Generierung von allen möglichen Linearkombinationen"
|
||||||
)[
|
)[
|
||||||
```julia
|
```julia
|
||||||
|
|
@ -57,10 +59,10 @@ Anschließend wurde die betragsmäßige Optimierung, welche in @bach_original_1
|
||||||
|
|
||||||
=== Rekursiver Ansatz
|
=== Rekursiver Ansatz
|
||||||
|
|
||||||
Als nächste Möglichkeit für den Multi-Bit Fall ist ein rekursiver Ansatz des Problems implementiert worden. Hierfür werden die Eingangswerte zunächst mit der betragsmäßigen Optimierung verarbeitet um so eine "optimale" Verteilung für den 1-bit Fall zu konstruieren. Anschließend wird die Verteilung in zwei symmetrische Unterverteilungen aufgeteilt, und jeweils deren Mittelwert bestimmt.
|
Als nächste Möglichkeit für den Multi-Bit Fall, ist ein rekursiver Ansatz des Problems implementiert worden. Hierfür werden die Eingangswerte zunächst mit der betragsmäßigen Optimierung verarbeitet um so eine "optimale" Verteilung für den 1-bit Fall zu konstruieren. Anschließend wird die Verteilung in zwei symmetrische Unterverteilungen aufgeteilt, und jeweils deren Mittelwert bestimmt.
|
||||||
Anschließend werden für jede Summe der jeweiligen Unterverteilungen zusätzliche fraktionierte Gewichtungen auf die bereits bestehenden Gewichtungen aufaddiert.
|
Daraufhin werden für jede Summe der jeweiligen Unterverteilungen zusätzliche fraktionierte Gewichtungen auf die bereits bestehenden Gewichtungen aufaddiert.
|
||||||
Basierend auf der Mittelwertbestimmung werden zusätzliche Grenzen definiert, anhand deren die aufkommenden neuen Summen mit fraktionierte Gewichtungen optimal gewählt werden.
|
Aufbauend auf die Mittelwertbestimmung werden zusätzliche Grenzen definiert, anhand deren die aufkommenden neuen Summen mit fraktionierten Gewichtungen optimal gewählt werden.
|
||||||
Basierend auf der Anzahl $m$ an Bits die aus einer Summe extrahiert werden sollen wird dieses Verfahren $m$-Mal mit allen entstehenden Unterverteilungen durchgeführt.
|
Basierend auf der Anzahl $m$ an Bits die aus einer Summe extrahiert werden sollen, wird dieses Verfahren $m$-Mal mit allen entstehenden Unterverteilungen durchgeführt.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
include("../graphics/execution/recursive.typ"),
|
include("../graphics/execution/recursive.typ"),
|
||||||
|
|
@ -70,8 +72,10 @@ Basierend auf der Anzahl $m$ an Bits die aus einer Summe extrahiert werden soll
|
||||||
@fig:bach_recursive_algo zeigt das grundsätzliche Schema für den Rekursiven Algorithmus auf.
|
@fig:bach_recursive_algo zeigt das grundsätzliche Schema für den Rekursiven Algorithmus auf.
|
||||||
Zu Beginn werden die anfänglichen Eingangswerte nach der Methode zur Betragsoptimierung verarbeitet.
|
Zu Beginn werden die anfänglichen Eingangswerte nach der Methode zur Betragsoptimierung verarbeitet.
|
||||||
Anschließend wird die Verteilung in zwei symmetrische Unterverteilungen aufgeteilt.
|
Anschließend wird die Verteilung in zwei symmetrische Unterverteilungen aufgeteilt.
|
||||||
*n1* beschreibt das Skalar, welches in allen möglichen Kombinationen auf die Helperdaten der Linearkombinationen von *u1* addiert bzw. subtrahiert werden.
|
Für jede neue Unterverteilung jeweils eine neue Quantisierergrenze über den Median dieser Unterverteilung definiert.
|
||||||
Um die nächsten beiden Unterverteilungen eines Knotens zu bestimmen, wird ermittelt, welche der neuen möglichen Linearkombinationen mit zusätzlichen Gewichtungen am weitesten Weg von einer
|
*n1* beschreibt das Skalar, welches in allen möglichen Kombinationen auf die Helperdaten der Linearkombinationen von *u1* addiert bzw. subtrahiert wird.
|
||||||
|
Aus den neu gefundenen möglichen Linearkombinationen wird nun diejenige gewählt, welche möglichst weit weg von den neu definierten Grenzen liegt.
|
||||||
|
Dieses Verfahren wird nun iterativ auf jeder weitere Unterverteilung angewendet bis die Anzahl der Verteilungen $log_2(m)$ entspricht, wobei $m$ die Anzahl der zu quantisierenden Bits definiert.
|
||||||
|
|
||||||
Ein erstes positives Ergebnis hier war die schnelle Konvergenz der Verteilung und die Gleichverteilung der quantisierten Symbole, da in jeden Grenzbereich möglichst gleich viele Summen gelegt worden sind. @fig:bach_recursive_dist zeigt das Ergebnis des rekursiven Ansatzes für die Quantisierung von 2 Bit.
|
Ein erstes positives Ergebnis hier war die schnelle Konvergenz der Verteilung und die Gleichverteilung der quantisierten Symbole, da in jeden Grenzbereich möglichst gleich viele Summen gelegt worden sind. @fig:bach_recursive_dist zeigt das Ergebnis des rekursiven Ansatzes für die Quantisierung von 2 Bit.
|
||||||
|
|
||||||
|
|
@ -114,7 +118,7 @@ Direkt im Anschluss wurde über Pearson's Chi-square Test die Gleichverteilung
|
||||||
Da diese Brute-Force Operation sehr rechenaufwendig ist, wurden die bereits in Julia implementierten Lösungen für parallel Computing eingesetzt und die Berechnung der idealen Grenzen auf einem Computer mit hoher Rechenkapazität ausgelagert.
|
Da diese Brute-Force Operation sehr rechenaufwendig ist, wurden die bereits in Julia implementierten Lösungen für parallel Computing eingesetzt und die Berechnung der idealen Grenzen auf einem Computer mit hoher Rechenkapazität ausgelagert.
|
||||||
|
|
||||||
Damit das parallele Rechnen eine signifikante Verbesserung in der Rechengeschwindigkeit erzielt, gab es einige Punkte zu beachten:
|
Damit das parallele Rechnen eine signifikante Verbesserung in der Rechengeschwindigkeit erzielt, gab es einige Punkte zu beachten:
|
||||||
- Für einen festgelegten Datensatz ändern sich die möglichen gewichteten Summen nicht wären der Ausführung des Algorithmus', also können diese vorab berechnet und gespeichert werden.
|
- Für einen festgelegten Datensatz ändern sich die möglichen gewichteten Summen nicht während der Ausführung des Algorithmus', also können diese vorab berechnet und gespeichert werden.
|
||||||
- Das Verwenden der "pmap" Funktion zur parallelen Ausführung des Optimierungsalgorithmus hat den Rechenprozess um ca. $700"ms"$ verlangsamt. \
|
- Das Verwenden der "pmap" Funktion zur parallelen Ausführung des Optimierungsalgorithmus hat den Rechenprozess um ca. $700"ms"$ verlangsamt. \
|
||||||
Eine effizientere Lösung besteht darin, bei der Ausführung des Julia Skripts die Anzahl an Threads vorzudefinieren und die jeweiligen Funktionen mit dem "\@everywhere" Flag zu markieren, damit sie von den verschiedenen Threads aufgerufen werden können.
|
Eine effizientere Lösung besteht darin, bei der Ausführung des Julia Skripts die Anzahl an Threads vorzudefinieren und die jeweiligen Funktionen mit dem "\@everywhere" Flag zu markieren, damit sie von den verschiedenen Threads aufgerufen werden können.
|
||||||
#figure(
|
#figure(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue