-Erarbeitung einer Python-Simulation in Anlehnung an Max Seddigs Forschung-
Gruppenmitglieder: Jasper Mittag, Maxine Krause, Max Liebscher
TO DO:
-Fokus auf Seddigs Temperatur-Auseinandersetzung
-Ausgestaltung des Programms? Wärmestrahlung?
-Code-Ausschnitte? Gesamter Code!!
-Fazit
-Abstimmung zusammengetragener Textabschnitte aufeinander
Die Beschäftigung mit einigen historischen Texten zur Brownschen Bewegung in Vorbereitung auf die Projektphase rückte die Bedeutung der Temperatur in unseren Fokus. Insbesondere in Hinblick auf die kinetische Gastheorie, deren Validierung ein zentrales Thema in der Beschäftigung mit der auch als „Wärmebewegung“ bezeichneten Brownschen Bewegung für die zu Beginn des 20.Jahrhunderts Forschenden darstellte, wurde deutlich: War die zufällige Bewegung der Teilchen Ursache der noch nicht anerkannten kinetischen Theorie der Wärme und ihres Molekül- und Atom-Begriffs, so würde sie auch den Beweis dieser darstellen können.
In unserem Projekt haben wir uns mit dem Einfluss der Temperatur auf die Brownsche Bewegung beschäftigt und das Ganze in Python simuliert. Unser Ziel war es den Einfluss auf die Teilchengeschwindigkeit durch die Veränderung der Temperatur zu zeigen. Wir haben zunächst ein Teilchenbad erschaffen, wo die Teilchen an den Wänden und gegenseitig an anderen Teilchen abstoßen. Anfangs haben wir das mit Turtle simuliert und sind dann später zu Pygame übergegangen.
Anfangs wollten wir die Temperatur als konstanten Faktor einbauen, und daraus immer die Geschwindigkeit berechnen, wir sind aber in der Projektphase zu dem Schluss gekommen, dass es besser wäre die Geschwindigkeit durch eine Art Heizdraht zu beeinflussen, sprich dass von einer Wand für eine gewisse Zeit zusätzliche „Wärmeenergie“ in das Teilchenbad gegeben wird, wodurch die Teilchen, die mit der Wand stoßen schneller werden. Eine Idee war anfangs auch die Temperaturänderung durch einen Slider zu regeln, was wir aber aufgrund mangelnder Zeit nicht geschafft haben einzubauen.
1904 widmete Max Seddig sich, auf der Suche nach einem experimentellen Beweis der kinetischen Wärmetheorie, erstmals der Abhängigkeit von Teilchenbewegung und absoluter Temperatur. Bis diese 1907 zu einem Abschluss kommen sollten, hatte Einstein als Ergebnis seiner theoretischen Auseinandersetzung die Proportionalität zwischen Start- und Zielpunkt einer Teilchenbewegung und der Wurzel aus Temperatur / Reibungskoeffizient der Flüssigkeit hervorgebracht, die Seddig schließlich experimentell nachzuweisen versuchte.
Zum Ziel führte Seddig in seinen Versuchen ein mit einem „mikrophotographischen Apparat“ verbundenes Ultramikroskop, in das durch eine automatische Belichtungsvorrichtung im Abstand von 1/10 Sekunde zwei 1/40 Sekunde andauernde Lichtblitze die zweifache Abbildungen eines Teilchens, vor und nach zurücklegen einer zu untersuchenden Strecke bei bestimmter Temperatur in genanntem festen Zeitintervall ermöglichte. Grund für die zwei Einzelbelichtungen anstelle der Belichtung des gesamten Weges, den das Teilchen zurücklegte, war die Notwendigkeit die durch die Belichtung entstehende Erwärmung der Suspension auf ein Minimum zu reduzieren.
Nicht zuletzt weil Seddig auf geliehene Mikroskope zurückgreifen musste, die es pfleglich zu behandeln galt, war er in den Möglichkeiten der Erhitzung seiner Präparate, der auch das Mikroskop selbst ausgesetzt gewesen wäre, eingeschränkt. Schließlich stellte eine auf einer Glasplatte angebrachte und mit Praffinöl benetzte Platindrahtschleife, die mit einem sehr dünnen, als Objektträger einer Zinnoberpulver-Suspension fungierenden Glas bedeckte wurde, als Heizkörper. Ein Thermoelement in der Schleife ermittelte die Temperatur.
Als Ergebnis erhielt Seddig Werte, die im Mittel 6% größere Teilchenbewegungen, als aufgrund Einsteins theoretischer Annahme erwartet, verzeichneten. Seddig erklärt dies über die Tatsache, dass durch ausstrahlende Wärme die suspendierten Teilchen stärker erwärmt würden und durch Abgabe dieser Wärme an ihre direkte Umgebung mehr Bewegung verzeichneten, als es die gemessene Durchschnittstemperatur der Suspension vermuten ließe. Unter dieser Deutung der Abweichungen sieht Seddig seine Ergebnisse als experimentelle Bestätigung der kinetischen Wärmetheorie an.
In Anlehnung an Seddigs Experiment entsteht für unser Projekt die Idee, die untere Grenze unserer Teilchenbad-Simulation mit einer „Heizfunktion“ zu versehen. Stoßen Teilchen an diese Grenze, wird ihre Geschwindigkeit im Sinne einer „Erwärmung“ erhöht.
Zuerst haben wir die Simulation eines Teilchenbads mit dem Turtle-Paket programmiert. Diese Version lief noch sehr langsam, war rucklig und hatte einige Bugs. In dieser Version hatten wir aber schon Massen für die Teilchen und die Formel für den Elastischen Stoß eingebaut.
Wir haben uns dann relativ schnell dazu entschieden auf das Paket Pygame umzusteigen. Es war zunächst eine Herausforderung sich in die Syntax von Pygame einzuarbeiten, das hat aber nach einiger Zeit gut geklappt. Unsere erste Version in Pygame lief schon deutlich flüssiger als die in Turtle und wir haben auch ein größeres und massereicheres Brownsches Teilchen eingefügt. Dort hat aber die Kollision gar nicht mehr funktioniert, die Teilchen sind alle durcheinander durchgeflogen.
Wir haben, um den Code zu verstehen, den Grund-Code von Marcel nachprogrammiert, dieser war ebenfalls in Pygame geschrieben. Dafür haben wir eine Weile benötigt: ca. bis zum 13.03.2023. Jasper hatte die Idee, sich in dem Projekt mit dem Zusammenhang von Temperatur auf die Brownsche Bewegung zu befassen. Herr Dr. Jähnert hat unserer Gruppe dann mehrere Quellen zur Verfügung gestellt, welche von Seddig verfasst wurden und sich mit der Temperaturabhängigkeit der Brownschen Bewegung befassen. In einer der Quellen wurde ein Versuch beschrieben, in welchem die Temperatur auf eine Suspension mithilfe eines Heizdrahtes verändert/eingestellt wurde. Diese Quelle war unsere Hauptquelle. Wir haben uns dann entschieden, einen Heizdraht in unsere Grundversion des Codes einzubauen. Dies wurde erreicht in dem wir bei der Kollision der Teilchen mit einer bestimmten Wand auf den Geschwindigkeitsvektor des jeweiligen Teilchen proportionsgerecht einen gewissen Faktor addiert haben, dieser heißt im Code „v_add“.
Weiter haben wir eingebaut, dass nach Abbruch der Simulation die Geschwindigkeiten der einzelnen Teichen Festgehalten wird und in gerundeter Form als Balkendiagramm geplottet wird. In diesem Balkendiagramm wurde die Anzahl der Teichen über den zugehörigen Geschwindigkeiten aufgetragen. Es ergab sich, so man die Simulation einige zeit laufen ließ, dass eine Verteilung in dem Diagramm entstand, welche grob der Maxwell-Boltzmann-Verteilung ähnelte.
import random import numpy as np import pygame import matplotlib.pyplot as plt import collections pygame.init() # Fenster festlegen WIDTH, HEIGHT = 700, 400 WIN = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Brownsche Bewegung") # Farbwerte RED = (255, 82, 32) BLACK = (0, 0, 0) BLUE = (23, 2, 255) WHITE = (255, 255, 255) GREEN = (50, 205, 50) YELLOW = (255, 255, 0) FPS = 60 # Werte für Teilchen ballAmount = 100 ballRadius = 3 ballColor = BLUE ballMasse = 10 SPEED = 2 BROWNSCHES_TEILCHEN_COLOR = RED BROWNSCHES_TEILCHEN_RADIUS = 10 BROSCNHES_TEILCHEN_MASSE = 50 class Teilchen: def __init__(self, color, radius, masse): self.color = color self.radius = radius # zufällige Postion zuordnen self.x = random.randint(radius, WIDTH - radius) self.y = random.randint(radius, HEIGHT - radius) self.xy = np.array([self.x, self.y]) # zufälliger normierter Geschwindigkeitsvektor self.vxy = np.array([random.uniform(-1, 1), random.uniform(-1, 1)]) norm = np.sqrt(self.vxy[0]**2 + self.vxy[1]**2) self.vxy = self.vxy / norm self.masse = masse # Zeitschritt self.speed = SPEED def draw(self, win): '''zeichnet das Teilchen ins Fenster''' pygame.draw.circle(win, self.color, (self.x, self.y), self.radius) def move(self): """neue Koordinaten werden berechnet durch Multiplikation vom Geschwindigkeitsvektor und dem Zeitschritt""" self.x += self.vxy[0] * self.speed self.y += self.vxy[1] * self.speed def borderCollision(self, stepcount): """"Kollision mit einer Wand""" if self.x >= WIDTH - self.radius: self.x = WIDTH - self.radius self.vxy[0] *= -1 elif self.x <= self.radius: self.x = self.radius self.vxy[0] *= -1 if self.y >= HEIGHT - self.radius: self.y = HEIGHT - self.radius self.vxy[1] *= -1 elif self.y <= self.radius: self.y = self.radius self.vxy[1] *= -1 if stepcount <= 500: """wenn das Teilchen weniger als 400 Schritte gemacht hat und an die obere border stößt, wird der Geschwindigkeitsvektor um einen bestimmten Betrag erhöht""" v_add = 1 betrag = np.sqrt(self.vxy[0]**2 + self.vxy[1]**2) betrag_neu = betrag + v_add verhaeltnis = self.vxy[0] / self.vxy[1] if self.vxy[0] > 0: self.vxy[0] = np.sqrt(((verhaeltnis**2) * (betrag_neu**2)) / (verhaeltnis**2 +1)) self.vxy[1] = self.vxy[0] / verhaeltnis elif self.vxy[0] < 0: self.vxy[0] = -np.sqrt(((verhaeltnis**2) * (betrag_neu**2)) / (verhaeltnis**2 +1)) self.vxy[1] = self.vxy[0] / verhaeltnis else: self.vxy[1] += v_add def ballCollision(self, ball2): # Zwischenspeichern der Koordinaten x_b1 = self.x y_b1 = self.y x_b2 = ball2.x y_b2 = ball2.y sv_x = ball2.x - self.x sv_y = ball2.y - self.y distance = np.sqrt(sv_x**2 + sv_y**2) if distance <= self.radius + ball2.radius: vxy_b1 = self.vxy vxy_b2 = ball2.vxy # zurücksetzen der Koordinaten auf die im Zwischenspeicher self.x = x_b1 self.y = y_b1 ball2.x = x_b2 ball2.y = y_b2 """Berechnen der neuen Geschwindigkeitsvektoren durch Formel für den elastischen Stoß""" self.vxy = (self.masse * vxy_b1 + ball2.masse * (2 * vxy_b2 - vxy_b1)) / (self.masse + ball2.masse) ball2.vxy = (ball2.masse * vxy_b2 + self.masse * (2 * vxy_b1 - vxy_b2)) / (self.masse + ball2.masse) def draw(win, balls): win.fill(BLACK) for ball in balls: ball.draw(win) pygame.display.update() def main(): run = 1 # Teilchenobjekte in eine Liste schreiben balls = [] for i in range(ballAmount): ball = "ball"+str(i) ball = Teilchen(ballColor, ballRadius, ballMasse) balls.append(ball) brownschesTeilchen = Teilchen(BROWNSCHES_TEILCHEN_COLOR, BROWNSCHES_TEILCHEN_RADIUS, BROSCNHES_TEILCHEN_MASSE) balls.append(brownschesTeilchen) global stepcount stepcount = 0 while run: draw(WIN, balls) pygame.time.Clock().tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: run = 0 break for ball in balls: ball.borderCollision(stepcount) for i in range(balls.index(ball) + 1, len(balls)): ball.ballCollision(balls[i]) ball.move() # zählt jeden Schritt, den ein einzelnes Teilchen macht stepcount += 1 # erstellt Liste aus allen Geschwindigkeiten und gibt sie aus wenn das Programm geschlossen wird vballs_list = [] for ball in balls: vnorm = np.sqrt(ball.vxy[0]**2 + ball.vxy[1]**2) vballs_list.append(round(vnorm)) print(vballs_list) # erstellt dictionary, das Anzahl der Geschwindigkeiten zählt vcounter = collections.Counter(vballs_list) print(vcounter) # Schlüssel mit dem maximalen Wert aus dem dictionary vcounter häufigkeiten = vcounter.items() häufigkeiten = sorted(häufigkeiten) x, y = zip(*häufigkeiten) plt.plot(x, y) plt.show() pygame.quit() if __name__ == '__main__': main()