Dies ist eine alte Version des Dokuments!
Jakob Berschneider, Emma Galow
Unser Projektziel ist es, das Verhalten verschiedener Balkenbrücken abhängig von verschiedenen Ausgangsbedingungen zu simulieren. Dabei soll der Benutzer selbst einstellen können, welches Material verbaut wurde, wie die Belastung ist und wie die Brücke konstruiert ist. Mit der Software soll es möglich sein, zu überprüfen, ob die Brücke stabil ist und eine Belastung aushalten würde. Das Ergebnis soll dann entsprechend visualisiert werden.
Wir haben uns für das Projekt dafür entschieden, dass wir uns zunächst auf zweidimensionale Fachwerkbrücken beschränken. Außerdem soll das Programm für den Nutzer bereits die Lagerung der Brücke festlegen (Festlager auf der linken Seite und Loslager auf der rechten Seite). Die Brückenkonstruktionen sollen statisch bestimmt sein, was durch das Programm überprüft werden soll. Diese Annahmen erleichtern uns die Berechnung der Lager-und Stabkräfte und die Implementierung im Code.
Das ideale Fachwerk besteht aus Stäben, Lagern und Knoten. Sind die Stäbe eines Stabwerks nur auf Druck oder Zug beansprucht, so spricht man von einem Fachwerk. Die Knoten sind die Endpunkte der Stäbe, in denen mehrere Stäbe freibeweglich und gelenkig verbunden werden. An den Lagern werden Kräfte aus dem Stabwerk selbst an die Umgebung übertragen. Abhängig von der Anzahl der verschiedenen Kraftkomponenten ergibt sich die Wertigkeit der Lager(einwertig, zweiwertig usw.)
Bei einem idealen Fachwerk sind alle Stäbe reibungsfrei gelenkig verbunden. Zudem greifen alle Kräfte nur in den Knoten an, weswegen man auch davon ausgehen muss, dass die Stäbe gewichtlos sind. Die Stäbe selbst werden nur auf Normalkraft(Kraft in Richtung der Stabachse) beansprucht. Stäbe sind auf Zug bei positiver Normalkraft und auf Druck bei negativer Normalkraft belastet.
Durch die statische Bestimmtheit lässt sich überprüfen, ob sich ein System mechanischen Gleichgewicht befindet. Mechanisches Gleichgewicht herrscht vor, wenn die Summe aller einwirkenden Kräfte (horizontal, vertikal und Drehmoment) gleich Null ist. Das heißt, die statische Bestimmtheit gibt Auskunft darüber, ob ein System in seiner Beweglichkeit eingeschränkt ist z.B. durch Lager oder Gelenke.
Die notwendige Bedingung für statische Bestimmtheit ist, dass die Zahl der Freiheitsgrade gleich der Summe der Wertigkeiten aller Lager und Verbindungselemente ist. Ein Tragwerk ist statisch bestimmt, wenn alle Lagerreaktionen eindeutig aus den Gleichgewichtsbedingungen bestimmt werden können. Die Anzahl der Freiheitsgrade ist die Zahl der unabhängigen Bewegungsmöglichkeiten eines Körpers. Ein Punkt im Raum hat bspw. 3 Freiheitsgrade, während ein starrer Körper im Raum Raum 6 Freiheitsgrade hat.
Die notwendige Bedingung für statische Bestimmtheit bei Stabwerken ist: $2k = s + r$. Wobei k die Anzahl der Knoten, s die Anzahl der Stäbe und r die Anzahl der Lagerreaktionen(Wertigkeit) ist. Die hinreichende Bedingung für statische Bestimmtheit bei Stabwerken ergibt sich aus Bildungsgesetzen und Polplan. Für einfache Stabwerke gilt das Bildungsgesetz, dass von einem starren Körper ein einer Knoten durch zwei Stäbe, die nicht auf einer Geraden liegen, angeschlossen wird. Man kann das beliebig fortsetzen. Beim Polplan darf der geometrische Ort (Wirkungslinie Loslager) nicht durch den Pol (Festlager / Schnittpunkt zweier geometrischer Orte) verlaufen, damit das System statisch bestimmt sein kann.
Das Knotenpunktverfahren ist das allgemeine Standardverfahren zur Ermittlung der Stabkräfte in einem Fachwerk:
Wir haben folgende Bibliotheken eingebunden:
Während uns numpy und math schon aus dem Crashkurs bekannt waren, mussten wir uns in pygame zunächst einarbeiten. Mit Hilfe von pygame ist es möglich, Grafiken zu bewegen, Töne abzuspielen oder auch Eingaben, wie z.B. Mausklicks oder Tastendrücke, abzufragen. tbc
Bevor die einzelnen Stab-und Lagerkräfte bestimmt werden können, muss zunächst die statische Bestimmtheit überprüft werden. Im Code haben wir das in der Funktion statisch_bestimmt umgesetzt:
def statisch_bestimmt(): points = [] points.append(knotenpunkte[0]) for i in knotenpunkte[2:]: points.append(tuple(i)) # Anzahl einzigartiger Knotenpunkte, Liste einzigartiger Knotenpunkte amount_knoten = len(set(points)) knoten = list(set(points)) # Alle Verbindungen zwischen 2 Punkten connections = [] for i in range(len(points) - 1): if [points[i], points[i+1]] and [points[i+1], points[i]] not in connections: connections.append([points[i], points[i+1]]) # Alle Verbindungen werden geordnet for i in connections: if i[0][0] > i[1][0]: i[0], i[1] = i[1], i[0] # Parameter, ob das System statisch bestimmt ist statisch = True # notwendige Bedingung der statischen Bestimmtheit if 2 * amount_knoten != len(connections) + 3: return False # Es werden alle Verbindungen von jeweils 2 Verbindungspunkten in Listen gespeichert und die Schnittmenge wird zusammengeführt for i in connections: connected = [] connected1 = [] connected2 = [] for k in connections: if i != k: if i[0] == k[0]: connected1.append(k[1]) if i[0] == k[1]: connected1.append(k[0]) if i[1] == k[0]: connected2.append(k[1]) if i[1] == k[1]: connected2.append(k[0]) connected1 = set(connected1) connected2 = set(connected2) connected = connected1 & connected2 connected = list(connected) # Es wird überprüft, ob die Konstruktion statisch bestimmt ist if len(connected) > 2 or len(connected) == 0: return False break if len(connected) == 2 and i[0][0] != i[1][0]: m = ((i[1][1] - i[0][1])/(i[1][0] - i[0][0])) if connected[0][1] > m * connected[0][0] + i[0][1] - m * i[0][0] and connected[1][1] > m * connected[1][0] + i[0][1] - m * i[0][0]: return False break if connected[0][1] < m * connected[0][0] + i[0][1] - m * i[0][0] and connected[1][1] < m * connected[1][0] + i[0][1] - m * i[0][0]: return False break if len(connected) == 2 and i[0][0] == i[1][0]: if (connected[0][0] > i[0][0] and connected[1][0] > i[0][0]) or (connected[0][0] < i[0][0] and connected[1][0] < i[0][0]): return False break if statisch: return True
Zunächst wird eine Liste connections erstellt, in der alle vorhandenen Verbindungen zwischen zwei Punkten, jeweils aufsteigend nach x-Wert geordnet, gespeichert werden. Dann wird die notwendige Bedingung für statische Bestimmtheit abgefragt.
Entsprechend der hinreichenden Bedingung für statische Bestimmtheit darf es höchstens einen gemeinsamen Verbindungspunkt oberhalb und unterhalb der Wirkungslinie eines Stabes geben. Auch um Überschneidungen von Stäben zu verhindern. Durch die Funktion wird für jeden Stab in der Konstruktion überprüft, welche gemeinsamen Verbindungspunkte beide Stabpunkte haben. Dazu wird für beide Stabpunkte eine Liste (connected1 und connected2) mit allen Verbindungspunkten erstellt. Die Schnittmenge der beiden Listen wird dann in connected gespeichert und abschließend wird überprüft, ob es höchstens einen Verbindungspunkt oberhalb und unterhalb der Verbindung gibt. Dazu werden die beiden Stabpunkte jeweils als Punkte einer linearen Funktion betrachtet. Die Verbindungspunkte in connected werden, dann danach untersucht, ob zwei Punkte oberhalb oder unterhalb dieser Funktion liegen bzw. bei einer Senkrechten rechts und links von dieser.
Für die Berechnung der Stab-und Lagerkräfte haben wir uns am Knotenpunktverfahren orientiert. Dazu haben wir zwei numpy-Arrays erstellt (N, y), um das Gleichungssystem mit np.linalg.solve(N, y) zu lösen. Den Aufbau des Gleichungssystems kann man sich folgender Maßen vorstellen:
Anhand dieser Struktur lässt sich auch erkennen, dass es im Vergleich zum Knotenpunktverfahren wie zuvor beschrieben einige Vereinfachungen gibt. So sind viele Zwischenschritte, die beim händischen Lösungsverfahren den Prozess erleichtern, nicht mehr nötig. Das heißt, man muss die Knoten und Stäbe nicht mehr nummerieren oder zuvor die Auflagerreaktionen und Nullstäbe bestimmen, da dies alles in einem Schritt als Gleichungssystem berechnet wird. Anhand dieser Struktur kann man auch sehen, dass die statische Bestimmtheit insofern wichtig ist, als dass es gleich viele Unbekannte wie Gleichung gibt, um das Gleichungssystem zu lösen. Der Lösungsvektor $x$ hat $s+k$ Unbekannte und es gibt insgesamt $2*k$ Gleichungen.
Die Berechnung wird mit der Funktion click_berechnen durchgeführt.
def click_berechnen(): points = [] points.append(knotenpunkte[0]) for i in knotenpunkte[2:]: points.append(tuple(i)) force_val = kraft_liste start_cords = knotenpunkte[0] end_cords = knotenpunkte[1] force_cords = kraft_punkt_liste # Maximal zulässige Belastungen A_x_zul = lagerkraft_betrag A_y_zul = lagerkraft_betrag B_y_zul = lagerkraft_betrag stab_zul = stabkraft_betrag # Richtung der Kraft force_dir = kraft_dir # Anzahl einzigartiger Knotenpunkte, Liste einzigartiger Knotenpunkte amount_knoten = len(set(points)) knoten = list(set(points)) # Alle Verbindungen zwischen 2 Punkten connections = [] for i in range(len(points) - 1): if [points[i], points[i+1]] and [points[i+1], points[i]] not in connections: connections.append([points[i], points[i+1]]) # Arrays zur Berechnung der Stab-und Lagerkräfte N = np.zeros((amount_knoten * 2, amount_knoten * 2)) y = np.zeros((amount_knoten * 2)) # Stabrichtung s_dir = (0, 0) # Berechnung der Werte der Arrays zur Berechnung der Stab-und Lagerkräfte for i in range(len(knoten)): for j in range(len(connections)): if knoten[i] in connections[j]: if knoten[i] == connections[j][0]: s_dir = vector(connections[j]) if knoten[i] == connections[j][1]: s_dir = vector([connections[j][1], connections[j][0]]) N[i * 2, j] = s_dir[0] / (np.sqrt(s_dir[0] ** 2 + s_dir[1] ** 2)) N[i * 2 + 1, j] = s_dir[1] / (np.sqrt(s_dir[0] ** 2 + s_dir[1] ** 2)) if knoten[i] == end_cords: N[i * 2 + 1, len(connections) + 2] = 1 if knoten[i] == start_cords: N[i * 2, len(connections)] = 1 N[i * 2 + 1, len(connections) + 1] = 1 for k in range(len(force_val)): print(knoten[i]) print(force_cords[k]) if knoten[i] == tuple(force_cords[k]): y[i * 2] += - f_x(force_dir[k], force_val[k]) y[i * 2 + 1] += - f_y(force_dir[k], force_val[k]) # Array mit den Ergebnissen, die vorderen Einträge geben die einzelnen Stabkräfte an, die letzten drei die Auflagerkräfte staebe = np.linalg.solve(N, y) stabil = True for i in staebe[:amount_knoten * 2 - 3]: if abs(i) > stab_zul: stabil = False print("Belastung zu groß (Stabkraft)") if abs(staebe[amount_knoten * 2 - 3]) > A_x_zul: stabil = False print("Belastung zu groß (Ax)") if abs(staebe[amount_knoten * 2 - 2]) > A_y_zul: stabil = False print("Belastung zu groß (Ay)") if abs(staebe[amount_knoten * 2 - 1]) > B_y_zul: stabil = False print("Belastung zu groß (By)") if stabil: meldung_stabil() else: meldung_instabil()
Das Programm weist immer noch ein paar kleine Defizite auf. So kann man beispielsweise noch keine Zahleneingabe abbrechen oder eine gerade geschrieben Zahl löschen. Auch die Reset-Funktion arbeitet an manchen Stellen noch nicht so, wie sie es eigentlich soll. …
Weiterführende Ideen wären zum einen die Umsetzung des ganzen im dreidimensionalen Raum. Auch eine Ausweitung auf andere Brückentypen wie Hängebrücken oder Balkenbrücken wäre denkbar. Außerdem könnte man noch versuchen, die Finite Elemente Methode, die unteranderem die Verformung von Festkörpern untersucht, mit einzubringen, um die Ergebnisse genauer und auch realistischer werden zu lassen. …