LambdaOmega
Aktives Mitglied
Hallo zusammen,
vor einigen Jahren habe ich wie viele andere meine erste EQ-Plattform nach Reiner Vogels super Anleitungen gebaut und seitdem in Verwendung. Ich bin alles andere als ein großer Bastler und dennoch funktioniert die Plattform bei mir auf Anhieb 1A und ich kann die Anleitungen jedem empfehlen!
Was mich jedoch schon immer etwas gestört hat, ist, dass man sich (ich mir?) die Form der vertical north segments (VNS) nicht analytisch herleiten kann und man in der Praxis die genäherten Ellipsensegmente verwendet und so gut wie gar nicht einschätzen kann wie weit man von der optimalen Form entfernt ist. Auch das genaue Verhalten der Segmente (Auflagepunkt und Geschwindigkeit) sind schwierig einzuschätzen. Dass die Ellipsensegmente funktionieren habe ich wie erwähnt selbst erfahren und will ich überhaupt nicht bestreiten, bitte nicht falsch verstehen
Aus reinem Interesse habe ich mir die Form und das Verhalten der VNS mal mit Python numerisch vorgenommen.
Vorgehen
Zur Bestimmung der Segmente habe ich eine Plattform mit Segmentenebenen, zwei Nordlager auf der Bodenebene und ein Südlager mit Erdachse in einer gewissen Höhe definiert, und die Plattform um die Erdachse gedreht. Der Schnittpunkt der Nordlager mit den Segmentebenen definiert den Kontaktpunkt zwischen Segmenten und Lager, der minimale Abstand zur Segment-Oberkante ist die positionsabhängige Segmenthöhe, die bei variabler Plattformneigung die Form des Segments definiert.
Konstruktion der Plattform
Die Maße der Plattform sind analog zu Reiner Vogels Planung wie im folgenden Bild bestimmt (ähnliche Namensgebung). Vorgegeben werden neben dem Breitengrad die Maße B1, E, D und die Höhe H der Plattform über den Lagern. Statt E und D könnte man alternativ auch direkt F angeben. Zur Berechnung der Maße siehe Anfang im Code unten. Wenn nicht gerade variiert, habe ich für die folgenden Vergleiche B1 = 500 mm, E = 250 mm, D = 140 mm, H = 30 mm und den Breitengrad 40° verwendet. Inklusive der abgeleiteten sind die Parameter dieser Plattform B1: 500, E: 250, D: 140, alpha: 40.0, H: 30, C1: 383, C: 457, gamma: 33.1, C2: 74, B2: 57, B: 557, F: 180, beta: 17.9, G: 535, I: 247, J: 615.
Vergleich der numerischen Segmentformen
Nun kann man die formgebenden Parametern variieren, um qualitativ den Einfluss auf die Segmente zu testen. Die Innenkante der Segmente ist durch den gleichen Kippwinkel wie bei der Spitze bestimmt. Man beachte dass dadurch der Auflagepunkt der Lager nicht in der horizontalen Mitte der Segmente sitzt, sondern Richtung außen (Spitze) verschoben ist, ein Aspekt den man beim Montieren beachten sollte. Außerdem sind die Segmente nach dieser Methode nicht auf die Länge D beschränkt. Höhere Breitengrade führen natürlich zu flacheren Segmenten, genauso längere Plattformen. Interessant ist, dass sich bei einer größeren Höhe der Plattform die Segmentform (ganz) leicht ändert, ansonsten würden sich die Segmente perfekt aneinander anschmiegen, was nicht der Fall ist (siehe Spitzen und Innenkanten).
Vergleich mit Ellipsen
Nun will man natürlich die Segmente erstmal gerne mit den entsprechenden Ellipsen vergleichen. Da die Plattform analog konstruiert ist, ist das Berechnen der Ellipse selbst kein Problem (die Ellipse der oben genannten Referenz-Plattform hat einen horizontalen Durchmesser von 2*480 mm und einen vertikalen Durchmesser von 2*350 mm). Schwierig wird es allerdings beim horizontalen Verschieben der Ellipse, um sie ohne Auslenkung auf das Lager zu setzen. Wie zuvor erwähnt kann man das Lager eigentlich nicht einfach D/2 von der Segmentspitze entfernt platzieren, da die Laufstrecke zur Spitze immer länger ist als zur Innenkante. Ich habe die Lager einfach trotzdem mal D/2 von der Segmentspitze entfernt platziert, da ich nicht wüsste wie man die genaue Verschiebung berechnen kann. Hinweise sind mir hier sehr willkommen - wird der beschriebene Offset in der Praxis ignoriert? Im folgenden Bild also der Vergleich der numerischen Segmente mit den Ellipsen. Passt bis auf die Ränder bei Breitengraden zwischen 40° und 50° meines Erachtens erstaunlich gut und bestätigt die positiven Erfahrungen mit den Ellipsensegmenten. Bei größeren und kleineren Breitengraden gibt es stärkere Abweichungen, die aber zum Teil an der fehlerhaften Position der Lager an den Ellipsen liegen dürften.
Auflagepunkt
Durch das Kippen der Segmente wandert der Auflagepunkt der Segmente auf den Lagern leicht, weshalb man die Dicke der Segmente klein halten sollte. Der Auflagepunkt bei Auslenkung Richtung Segmentspitze wandert erst etwas nach innen (Richtung Südlager, negativer Offset), bevor er wie bei Auslenkung Richtung Innenseite stets nach außen wandert (positiver Offset). Um den Offset zu minimieren helfen kleine Breitengrade und kurze Plattformlängen. Eine größere Plattformhöhe ändert fast nur das Minimum aber nicht die Form der Parabel.
Positionsabhängige Nachführ-Geschwindigkeit
Die Geschwindigkeit, mit der die Segmente auf den Lagern ablaufen, ändert sich leicht mit der Auslenkung. Auch hier ist das Minimum nicht bei 0 Grad Auslenkung zu finden, sondern Richtung Segmentspitze versetzt. Sind beide Nordlager mit Motoren ausgestattet ist eine um 0 Grad Auslenkung symmetrische Funktion vorteilhafter, da sich das andere Segment stets beim entsprechenden negativen Winkel befindet. Eine asymmetrische Funktion führt also zwingend zu einem Schlupf bei einem der Lager, wenn beiden Motoren gleich schnell drehen. Der Schlupf ist bei hohen Breitengraden, langen Plattformen und geringen Plattformhöhen minimiert. Abgesehen davon ist natürlich eine kleinere Variation der Geschwindigkeit gewünscht, worauf Plattformlänge und -höhe jedoch keinen Einfluss haben, lediglich bei kleineren Breitengraden ist die Nachführ-Geschwindigkeit etwas stabiler. Generell sind 1% Abweichung aber vermutlich nur sehr selten bemerkbar.
Fazit
Die Segmente lassen sich relativ einfach numerisch berechnen, was allerdings nur in Spezialfällen wirklich notwendig ist. In den meisten Fällen sind die konstruierten Ellipsensegmente sehr nah an der optimalen Form und die Positionierung des Segments an der Plattform bzw. auf dem Lager dürfte die größte Unsicherheit darstellen (mir nicht mal theoretisch klar, siehe weiter oben). Vielleicht sind ja aber die Kurven zum Auflagepunkt und der Nachführ-Geschwindigkeit für den einen oder anderen doch ganz interessant mal gesehen zu haben
Python-Code
Ein großer Teil ist nur die Ellipse und das Zeichnen mit verschiedenen Optionen und kann ggf. weggelassen werden.
Viele Grüße,
Clemens
vor einigen Jahren habe ich wie viele andere meine erste EQ-Plattform nach Reiner Vogels super Anleitungen gebaut und seitdem in Verwendung. Ich bin alles andere als ein großer Bastler und dennoch funktioniert die Plattform bei mir auf Anhieb 1A und ich kann die Anleitungen jedem empfehlen!
Was mich jedoch schon immer etwas gestört hat, ist, dass man sich (ich mir?) die Form der vertical north segments (VNS) nicht analytisch herleiten kann und man in der Praxis die genäherten Ellipsensegmente verwendet und so gut wie gar nicht einschätzen kann wie weit man von der optimalen Form entfernt ist. Auch das genaue Verhalten der Segmente (Auflagepunkt und Geschwindigkeit) sind schwierig einzuschätzen. Dass die Ellipsensegmente funktionieren habe ich wie erwähnt selbst erfahren und will ich überhaupt nicht bestreiten, bitte nicht falsch verstehen
Vorgehen
Zur Bestimmung der Segmente habe ich eine Plattform mit Segmentenebenen, zwei Nordlager auf der Bodenebene und ein Südlager mit Erdachse in einer gewissen Höhe definiert, und die Plattform um die Erdachse gedreht. Der Schnittpunkt der Nordlager mit den Segmentebenen definiert den Kontaktpunkt zwischen Segmenten und Lager, der minimale Abstand zur Segment-Oberkante ist die positionsabhängige Segmenthöhe, die bei variabler Plattformneigung die Form des Segments definiert.
Konstruktion der Plattform
Die Maße der Plattform sind analog zu Reiner Vogels Planung wie im folgenden Bild bestimmt (ähnliche Namensgebung). Vorgegeben werden neben dem Breitengrad die Maße B1, E, D und die Höhe H der Plattform über den Lagern. Statt E und D könnte man alternativ auch direkt F angeben. Zur Berechnung der Maße siehe Anfang im Code unten. Wenn nicht gerade variiert, habe ich für die folgenden Vergleiche B1 = 500 mm, E = 250 mm, D = 140 mm, H = 30 mm und den Breitengrad 40° verwendet. Inklusive der abgeleiteten sind die Parameter dieser Plattform B1: 500, E: 250, D: 140, alpha: 40.0, H: 30, C1: 383, C: 457, gamma: 33.1, C2: 74, B2: 57, B: 557, F: 180, beta: 17.9, G: 535, I: 247, J: 615.
Vergleich der numerischen Segmentformen
Nun kann man die formgebenden Parametern variieren, um qualitativ den Einfluss auf die Segmente zu testen. Die Innenkante der Segmente ist durch den gleichen Kippwinkel wie bei der Spitze bestimmt. Man beachte dass dadurch der Auflagepunkt der Lager nicht in der horizontalen Mitte der Segmente sitzt, sondern Richtung außen (Spitze) verschoben ist, ein Aspekt den man beim Montieren beachten sollte. Außerdem sind die Segmente nach dieser Methode nicht auf die Länge D beschränkt. Höhere Breitengrade führen natürlich zu flacheren Segmenten, genauso längere Plattformen. Interessant ist, dass sich bei einer größeren Höhe der Plattform die Segmentform (ganz) leicht ändert, ansonsten würden sich die Segmente perfekt aneinander anschmiegen, was nicht der Fall ist (siehe Spitzen und Innenkanten).
Vergleich mit Ellipsen
Nun will man natürlich die Segmente erstmal gerne mit den entsprechenden Ellipsen vergleichen. Da die Plattform analog konstruiert ist, ist das Berechnen der Ellipse selbst kein Problem (die Ellipse der oben genannten Referenz-Plattform hat einen horizontalen Durchmesser von 2*480 mm und einen vertikalen Durchmesser von 2*350 mm). Schwierig wird es allerdings beim horizontalen Verschieben der Ellipse, um sie ohne Auslenkung auf das Lager zu setzen. Wie zuvor erwähnt kann man das Lager eigentlich nicht einfach D/2 von der Segmentspitze entfernt platzieren, da die Laufstrecke zur Spitze immer länger ist als zur Innenkante. Ich habe die Lager einfach trotzdem mal D/2 von der Segmentspitze entfernt platziert, da ich nicht wüsste wie man die genaue Verschiebung berechnen kann. Hinweise sind mir hier sehr willkommen - wird der beschriebene Offset in der Praxis ignoriert? Im folgenden Bild also der Vergleich der numerischen Segmente mit den Ellipsen. Passt bis auf die Ränder bei Breitengraden zwischen 40° und 50° meines Erachtens erstaunlich gut und bestätigt die positiven Erfahrungen mit den Ellipsensegmenten. Bei größeren und kleineren Breitengraden gibt es stärkere Abweichungen, die aber zum Teil an der fehlerhaften Position der Lager an den Ellipsen liegen dürften.
Auflagepunkt
Durch das Kippen der Segmente wandert der Auflagepunkt der Segmente auf den Lagern leicht, weshalb man die Dicke der Segmente klein halten sollte. Der Auflagepunkt bei Auslenkung Richtung Segmentspitze wandert erst etwas nach innen (Richtung Südlager, negativer Offset), bevor er wie bei Auslenkung Richtung Innenseite stets nach außen wandert (positiver Offset). Um den Offset zu minimieren helfen kleine Breitengrade und kurze Plattformlängen. Eine größere Plattformhöhe ändert fast nur das Minimum aber nicht die Form der Parabel.
Positionsabhängige Nachführ-Geschwindigkeit
Die Geschwindigkeit, mit der die Segmente auf den Lagern ablaufen, ändert sich leicht mit der Auslenkung. Auch hier ist das Minimum nicht bei 0 Grad Auslenkung zu finden, sondern Richtung Segmentspitze versetzt. Sind beide Nordlager mit Motoren ausgestattet ist eine um 0 Grad Auslenkung symmetrische Funktion vorteilhafter, da sich das andere Segment stets beim entsprechenden negativen Winkel befindet. Eine asymmetrische Funktion führt also zwingend zu einem Schlupf bei einem der Lager, wenn beiden Motoren gleich schnell drehen. Der Schlupf ist bei hohen Breitengraden, langen Plattformen und geringen Plattformhöhen minimiert. Abgesehen davon ist natürlich eine kleinere Variation der Geschwindigkeit gewünscht, worauf Plattformlänge und -höhe jedoch keinen Einfluss haben, lediglich bei kleineren Breitengraden ist die Nachführ-Geschwindigkeit etwas stabiler. Generell sind 1% Abweichung aber vermutlich nur sehr selten bemerkbar.
Fazit
Die Segmente lassen sich relativ einfach numerisch berechnen, was allerdings nur in Spezialfällen wirklich notwendig ist. In den meisten Fällen sind die konstruierten Ellipsensegmente sehr nah an der optimalen Form und die Positionierung des Segments an der Plattform bzw. auf dem Lager dürfte die größte Unsicherheit darstellen (mir nicht mal theoretisch klar, siehe weiter oben). Vielleicht sind ja aber die Kurven zum Auflagepunkt und der Nachführ-Geschwindigkeit für den einen oder anderen doch ganz interessant mal gesehen zu haben
Python-Code
Ein großer Teil ist nur die Ellipse und das Zeichnen mit verschiedenen Optionen und kann ggf. weggelassen werden.
Python:
import matplotlib.pyplot as plt
import numpy as np
from scipy.linalg import expm, norm
import copy
import pathlib
###############################################################
# PARAMETER
param = {}
# Vorgegeben
param['B1'] = 500 # Abstand zwischen Südlager und Schnittlinie Kreissegmentebene
param['E'] = 250 # Halber Abstand zwischen den Ecken, definiert gemeinsam mit D den halben Abstand der Segmentmitten F
param['D'] = 140 # Lauffläche
param['a_'] = np.radians(40) # Breitengrad
param['H'] = 30 # Höhe der Plattform über den Nordlagern
# Abgeleitet
param['C1'] = param['B1'] * np.cos(param['a_']) # Anteil Radius Kreissegment oberhalb Bezugsebene
param['C'] = np.sqrt((param['E'])**2 + param['C1']**2) # Radius Kreissegment
param['g_'] = np.arcsin(param['E'] / param['C']) # Winkel zur Segmentspitze in Kreissegmentebene
param['C2'] = param['C'] - param['C1'] # Anteil Radius Kreissegment unterhalb Bezugsebene
param['B2'] = param['C2'] * np.cos(param['a_']) # Erweiterung Abstand von Südlager durch Drehung um horizontale Achse (Senkrechtstellung)
param['B'] = param['B1'] + param['B2'] # Abstand von Südlager nach Drehung um horizontale Achse
param['F'] = param['E'] - param['D'] / 2 # Halber Abstand zwischen Segmentmitten
param['b_'] = np.arctan(param['F'] / (param['B'])) # Winkel zwischen Nord-Süd-Achse und den Segmentmitten (für zweite Ellipsen-Streckung)
param['G'] = param['B'] - param['D'] / 2 * np.sin(param['b_']) # Nord-Süd Komponente der Segmentspitzen nach Drehung um vertikale Achse
param['I'] = param['F'] + param['D'] / 2 * np.cos(param['b_']) # Halber Abstand der Segmentspitzen nach Drehung um vertikale Achse
param['J'] = param['B'] + param['F'] * np.tan(param['b_']) # Abstand gedachte Nordspitze nach Senkrechtdrehung
# Ansicht
MAX_THETA_SEGMENTE = 30
LOOP_THETAS = [0]
#LOOP_THETAS = np.arange(10,-10.5,-0.5)
ELLIPSE_OFFSET = 0
VIEW_SEGMENTEBENEN = 0
VIEW_LAGER = 0
SHOW_PLOT = 1
# Namen
BASENAME = "Segment" + "_BG_" + str(int(round(180 / np.pi * param['a_'], 0))) + \
"_B1_" + str(param['B1']) + \
"_E_" + str(param['E']) + \
"_D_" + str(param['D']) + \
"_H_" + str(param['H'])
###############################################################
# HILFSFUNKTIONEN
def rot_around(vec, theta, axis):
return np.dot(expm(np.cross(np.eye(3), axis/norm(axis)*theta)), vec)
def points_to_coordinates(*points):
x = []
y = []
z = []
for i in range(len(points)):
x.append(points[i][0])
y.append(points[i][1])
z.append(points[i][2])
return x,y,z
def line_plane_intersection(plane_p1, plane_p2, plane_p3, line_dir, line_point):
plane_normal = np.cross(plane_p2 - plane_p1, plane_p3 - plane_p1)
dot_prod = np.dot(plane_normal, line_dir)
if abs(dot_prod) < 1e-8:
return [0,0,0]
v = line_point - plane_p1
f = - np.dot(plane_normal, v) / dot_prod
return v + f * line_dir + plane_p1
def perp_point(point_a1, point_b1, point_b2):
point_b_norm = (point_b2 - point_b1) / np.linalg.norm(point_b2 - point_b1)
v = point_a1 - point_b1
t = np.dot(v, point_b_norm)
return point_b1 + t * point_b_norm
if __name__ == "__main__":
###############################################################
# ELLIPSEN-SEGMENTE
# Berechnung der Ellipse
ellipse_x = []
ellipse_y = []
x_segmentspitze = 0
for t in np.arange(-180,0,0.2):
ellipse_x.append(param['C'] / np.cos(param['b_']) * np.cos(np.radians(t)))
ellipse_y.append(param['C'] * np.cos(param['a_']) * np.sin(np.radians(t)))
# Verschiebe Ellipse vertikal und bestimme Segmentspitzen
ellipse_y = [y + param['C'] * np.cos(param['a_']) * np.cos(param['g_']) for y in ellipse_y]
for n in range(len(ellipse_y)):
if len(ellipse_y) > 1:
if ellipse_y[n - 1] < 0 and ellipse_y[n] >= 0:
x_segmentspitze = ellipse_x[n]
# Verschiebe Ellipse horizontal sodass Lauffläche um x = 0 herum
ellipse_x = [x - x_segmentspitze + param['D'] / 2 - ELLIPSE_OFFSET for x in ellipse_x]
# Speichern der Ellipse
pathlib.Path('./data/').mkdir(parents=True, exist_ok=True)
with open("./data/" + BASENAME + "_Ellipse.dat", 'w') as f:
for i in range(len(ellipse_x)):
f.write("%.6f" % (ellipse_x[i]) + "\t")
f.write("%.6f" % (ellipse_y[i]) + "\n")
# Parameter speichern
pathlib.Path('./data/').mkdir(parents=True, exist_ok=True)
with open("./data/" + BASENAME + "_Parameter.dat", 'w') as f:
for key in param:
if key[-1] == "_":
f.write(str(key) + ": \t" + "%.1f" % (param[key] * 180 / np.pi) + "\n")
print(str(key) + ": " + "%.1f" % (param[key] * 180 / np.pi))
else:
f.write(str(key) + ": \t" + "%.0f" % (param[key]) + "\n")
print(str(key) + ": " + "%.0f" % (param[key]))
###############################################################
# DEFINITION DER PLATTFORM
vectors = {}
vectors['suedlager'] = np.array([0, 0, param['H']])
vectors['erdachse'] = vectors['suedlager'] + param['B'] * np.array([np.cos(param['a_']), 0, np.sin(param['a_'])])
vectors['nordspitze'] = np.array([param['J'], 0, param['H']])
vectors['nordlot'] = np.array([param['J'], 0, 0])
vectors['ostlager'] = np.array([param['B'], -param['F'], 0])
vectors['westlager'] = np.array([param['B'], +param['F'], 0])
vectors['ostsegment'] = np.array([param['B'], -param['F'], param['H']])
vectors['westsegment'] = np.array([param['B'], +param['F'], param['H']])
vectors['osteck'] = np.array([param['G'], -param['I'], param['H']])
vectors['westeck'] = np.array([param['G'], +param['I'], param['H']])
rot_vectors = copy.deepcopy(vectors)
###############################################################
# BERECHNUNG DER SEGMENTE
segmentpos = []
segmenthoehe = []
segmentwinkel = []
segmentgeschwindigkeit = []
segmentlageroffset = []
for th in np.arange(MAX_THETA_SEGMENTE, -MAX_THETA_SEGMENTE-0.05, -0.05):
for key in vectors:
if not key in ['suedlager','erdachse','ostlager','westlager']:
rot_vectors[key] = vectors['suedlager'] + rot_around(vectors[key] - vectors['suedlager'], np.radians(th), vectors['erdachse'] - vectors['suedlager'])
# Die folgenden zwei Zeilen ist der Kern der ganzen Berechnung
# Es wird erst geschaut, wo der Lagerstrahl die Segmentebene schneidet, man bekommt einen Kontaktpunkt zwischen Lager und Segment
# Anschließend wird vom Kontaktpunkt senkrecht auf die Segmentoberkante projiziert, um die Referenzposition des Kontakts für das Segment zu erhalten
# Die Kontaktpunkte und Referenzpositionen die man bei verschiedenen Winkeln (th) erhält, definieren die Segmentform
# Die Berechnung wird nur für die Ostseite durchgeführt, die Westseite ist gespiegelt gleich
rot_vectors['ostkontakt'] = line_plane_intersection(rot_vectors['ostsegment'], rot_vectors['nordspitze'], rot_vectors['nordlot'], rot_vectors['ostlager'], rot_vectors['ostlager'])
rot_vectors['ostref'] = perp_point(rot_vectors['ostkontakt'], rot_vectors['ostsegment'], rot_vectors['nordspitze'])
this_segmentpos = np.linalg.norm(rot_vectors['ostref'] - rot_vectors['ostsegment'])
this_segmenthoehe = np.linalg.norm(rot_vectors['ostkontakt'] - rot_vectors['ostref'])
# Im Prinzip sind Referenzpositionen und Segmenthöhen einfache Abstände zwischen Punkten,
# für eine stabile Berechnung auch in Extremfällen müssen jedoch die Vorzeichen ordentlich bestimmt werden
if np.linalg.norm(rot_vectors['ostref'] - rot_vectors['nordspitze']) < np.linalg.norm(rot_vectors['ostsegment'] - rot_vectors['nordspitze']):
this_segmentpos = -this_segmentpos
if rot_vectors['ostref'][2] < 0:
this_segmenthoehe = -this_segmenthoehe
# Außen nicht über Plattformebene
if not this_segmenthoehe > 0:
continue
# Innen nicht über Symmetrieachse
if abs(this_segmentpos) > np.linalg.norm(rot_vectors['ostsegment'] - rot_vectors['nordspitze']):
continue
# Innen nicht weiter als nötig (von außen vorgegeben)
if segmentwinkel:
if abs(th) > abs(segmentwinkel[0]):
continue
# Wenn nicht übersprungen, in Listen schreiben
segmentpos.append(this_segmentpos)
segmenthoehe.append(this_segmenthoehe)
segmentwinkel.append(th)
if not segmentgeschwindigkeit:
segmentgeschwindigkeit.append(0)
else:
segmentgeschwindigkeit.append(np.sqrt((segmentpos[-2]-segmentpos[-1])**2 + (segmenthoehe[-2]-segmenthoehe[-1])**2) / (segmentwinkel[-2]-segmentwinkel[-1]) * 360 / 24)
if np.linalg.norm(rot_vectors['ostkontakt']) > np.linalg.norm(rot_vectors['ostlager']):
segmentlageroffset.append(np.linalg.norm(rot_vectors['ostkontakt'] - rot_vectors['ostlager']))
else:
segmentlageroffset.append(-np.linalg.norm(rot_vectors['ostkontakt'] - rot_vectors['ostlager']))
# Merke außerdem Punkt der Innenkante bei minimaler Position (nur zum Zeichnen ohne Nordspitze)
rot_vectors['ostinnen'] = rot_vectors['ostref']
rot_vectors['westinnen'] = rot_vectors['nordspitze'] + np.linalg.norm(rot_vectors['ostinnen'] - rot_vectors['nordspitze']) * (rot_vectors['westeck'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['westeck'] - rot_vectors['nordspitze'])
if not segmentwinkel:
print("Kein einziger Punkt des Segments wurde gezeichnet!")
print("Interrupt!")
sys.exit()
# Rotiere Innenpunkte zurück
vectors['ostinnen'] = rot_vectors['suedlager'] + rot_around(rot_vectors['ostinnen'] - rot_vectors['suedlager'], -np.radians(segmentwinkel[-1]), rot_vectors['erdachse'] - rot_vectors['suedlager'])
vectors['westinnen'] = rot_vectors['suedlager'] + rot_around(rot_vectors['westinnen'] - rot_vectors['suedlager'], -np.radians(segmentwinkel[-1]), rot_vectors['erdachse'] - rot_vectors['suedlager'])
# Anfang und Ende der Segmente auf Höhe Null
segmentpos.insert(0, segmentpos[0])
segmentpos.append(segmentpos[-1])
segmentpos.append(segmentpos[0])
segmenthoehe.insert(0, 0)
segmenthoehe.append(0)
segmenthoehe.append(0)
segmentgeschwindigkeit[0] = 2 * segmentgeschwindigkeit[1] - segmentgeschwindigkeit[2]
segmentgeschwindigkeit_norm = [x/min(segmentgeschwindigkeit) for x in segmentgeschwindigkeit]
# Ausgeben und abspeichern
pathlib.Path('./data/').mkdir(parents=True, exist_ok=True)
with open("./data/" + BASENAME + "_Segment.dat", 'w') as f:
for i in range(len(segmentpos)):
f.write("%.6f" % segmentpos[i] + "\t")
f.write("%.6f" % -segmenthoehe[i] + "\n")
with open("./data/" + BASENAME + "_Geschwindigkeit.dat", 'w') as f:
for i in range(len(segmentwinkel)):
f.write("%.6f" % segmentwinkel[i] + "\t")
f.write("%.6f" % segmentgeschwindigkeit[i] + "\n")
with open("./data/" + BASENAME + "_Geschwindigkeit_norm.dat", 'w') as f:
for i in range(len(segmentwinkel)):
f.write("%.6f" % segmentwinkel[i] + "\t")
f.write("%.6f" % segmentgeschwindigkeit_norm[i] + "\n")
with open("./data/" + BASENAME + "_Lageroffset.dat", 'w') as f:
for i in range(len(segmentwinkel)):
f.write("%.6f" % segmentwinkel[i] + "\t")
f.write("%.6f" % segmentlageroffset[i] + "\n")
###############################################################
# ZEICHNEN-WINKELSCHLEIFE
for THETA in LOOP_THETAS:
THETA = THETA + 0.00001 # vertical surfaces impossible to plot
# Gehe zu Zeichnen-Position
for key in vectors:
if not key in ['suedlager','erdachse','ostlager','westlager']:
rot_vectors[key] = vectors['suedlager'] + rot_around(vectors[key] - vectors['suedlager'], np.radians(THETA), vectors['erdachse'] - vectors['suedlager'])
rot_vectors['ostkontakt'] = line_plane_intersection(rot_vectors['ostsegment'], rot_vectors['nordspitze'], rot_vectors['nordlot'], rot_vectors['ostlager'], rot_vectors['ostlager'])
rot_vectors['westkontakt'] = line_plane_intersection(rot_vectors['westsegment'], rot_vectors['nordspitze'], rot_vectors['nordlot'], rot_vectors['westlager'], rot_vectors['westlager'])
rot_vectors['ostref'] = perp_point(rot_vectors['ostkontakt'], rot_vectors['osteck'], rot_vectors['nordspitze'])
rot_vectors['westref'] = perp_point(rot_vectors['westkontakt'], rot_vectors['westeck'], rot_vectors['nordspitze'])
# Erzeuge Figure
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize = (5, 5))
# Plattformebene
[x,y,z] = points_to_coordinates(
rot_vectors['suedlager'],
rot_vectors['osteck'],
rot_vectors['ostinnen'],
rot_vectors['westinnen'],
rot_vectors['westeck'],
)
ax.plot_trisurf(x,y,z, color='grey', alpha=0.4)
# Plattform-Kanten
[x,y,z] = points_to_coordinates([0,0,0], rot_vectors['suedlager'])
ax.plot(x,y,z, linewidth=1, color='grey')
[x,y,z] = points_to_coordinates(rot_vectors['suedlager'], rot_vectors['osteck'])
ax.plot(x,y,z, linewidth=1, color='grey')
[x,y,z] = points_to_coordinates(rot_vectors['suedlager'], rot_vectors['westeck'])
ax.plot(x,y,z, linewidth=1, color='grey')
[x,y,z] = points_to_coordinates(rot_vectors['osteck'], rot_vectors['ostinnen'])
ax.plot(x,y,z, linewidth=1, color='grey')
[x,y,z] = points_to_coordinates(rot_vectors['westeck'], rot_vectors['westinnen'])
ax.plot(x,y,z, linewidth=1, color='grey')
[x,y,z] = points_to_coordinates(rot_vectors['ostinnen'], rot_vectors['westinnen'])
ax.plot(x,y,z, linewidth=1, color='grey')
# Erdachse
[x,y,z] = points_to_coordinates(rot_vectors['suedlager'], rot_vectors['erdachse'])
ax.plot(x,y,z, linewidth=1, color='red')
# Nordlager
[x,y,z] = points_to_coordinates(0.9 * rot_vectors['ostlager'], 1.1 * rot_vectors['ostlager'])
ax.plot(x,y,z, linewidth=1, color='blue')
[x,y,z] = points_to_coordinates(0.9 * rot_vectors['westlager'], 1.1 * rot_vectors['westlager'])
ax.plot(x,y,z, linewidth=1, color='blue')
# Segmentebenen
if VIEW_SEGMENTEBENEN:
[x,y,z] = points_to_coordinates(
rot_vectors['nordspitze'],
rot_vectors['osteck'] + 0.2 * (rot_vectors['osteck'] - rot_vectors['nordspitze']),
rot_vectors['osteck'] + 0.2 * (rot_vectors['osteck'] - rot_vectors['nordspitze']) + 2 * (rot_vectors['nordlot'] - rot_vectors['nordspitze']),
rot_vectors['nordspitze'] + 2 * (rot_vectors['nordlot'] - rot_vectors['nordspitze']),
)
ax.plot_trisurf(x,y,z, color='green', alpha=0.4)
[x,y,z] = points_to_coordinates(
rot_vectors['nordspitze'],
rot_vectors['westeck'] + 0.2 * (rot_vectors['westeck'] - rot_vectors['nordspitze']),
rot_vectors['westeck'] + 0.2 * (rot_vectors['westeck'] - rot_vectors['nordspitze']) + 2 * (rot_vectors['nordlot'] - rot_vectors['nordspitze']),
rot_vectors['nordspitze'] + 2 * (rot_vectors['nordlot'] - rot_vectors['nordspitze']),
)
ax.plot_trisurf(x,y,z, color='green', alpha=0.4)
[x,y,z] = points_to_coordinates(rot_vectors['ostkontakt'], rot_vectors['ostref'])
ax.plot(x,y,z, linewidth=1, color='green')
[x,y,z] = points_to_coordinates(rot_vectors['westkontakt'], rot_vectors['westref'])
ax.plot(x,y,z, linewidth=1, color='green')
# Segmente
else:
# Ostsegment
segmentpunkte_x = []
segmentpunkte_y = []
segmentpunkte_z = []
for i in range(len(segmentpos)):
ref = rot_vectors['ostsegment'] + segmentpos[i] * (rot_vectors['ostsegment'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['ostsegment'] - rot_vectors['nordspitze'])
punkt = ref + segmenthoehe[i] * (rot_vectors['nordlot'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['nordlot'] - rot_vectors['nordspitze'])
segmentpunkte_x.append(punkt[0])
segmentpunkte_y.append(punkt[1])
segmentpunkte_z.append(punkt[2])
ax.plot_trisurf(segmentpunkte_x,segmentpunkte_y,segmentpunkte_z, color='green', alpha=0.6)
ax.plot(segmentpunkte_x,segmentpunkte_y,segmentpunkte_z, linewidth=1, color='green')
# Westsegment
segmentpunkte_x = []
segmentpunkte_y = []
segmentpunkte_z = []
for i in range(len(segmentpos)):
ref = rot_vectors['westsegment'] + segmentpos[i] * (rot_vectors['westsegment'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['westsegment'] - rot_vectors['nordspitze'])
punkt = ref + segmenthoehe[i] * (rot_vectors['nordlot'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['nordlot'] - rot_vectors['nordspitze'])
segmentpunkte_x.append(punkt[0])
segmentpunkte_y.append(punkt[1])
segmentpunkte_z.append(punkt[2])
ax.plot_trisurf(segmentpunkte_x,segmentpunkte_y,segmentpunkte_z, color='green', alpha=0.6)
ax.plot(segmentpunkte_x,segmentpunkte_y,segmentpunkte_z, linewidth=1, color='green')
# Limits
boxwidth = param['B'] +100
ax.set_xlim(-5, -5+boxwidth)
ax.set_ylim(-boxwidth/2, boxwidth/2)
ax.set_zlim(0, boxwidth)
if VIEW_LAGER == 1:
v = rot_vectors['ostlager']
ax.set_xlim(v[0]-5, v[0]+5)
ax.set_ylim(v[1]-5, v[1]+5)
ax.set_zlim(v[2]-5, v[2]+5)
# Lagerebene
[x,y,z] = points_to_coordinates(
[ax.get_xlim()[0],ax.get_ylim()[0],0],
[ax.get_xlim()[0],ax.get_ylim()[1],0],
[ax.get_xlim()[1],ax.get_ylim()[0],0],
[ax.get_xlim()[1],ax.get_ylim()[1],0]
)
ax.plot_trisurf(x,y,z, color='grey', alpha=0.1)
# Ansichten
ax.set_axis_off()
views = {'1_oblique': [22, -30], '2_front': [-2.5, 0], '3_top': [90, 0], '4_side': [-2.5, -88], '5_lager': [0, -17]}
# Speichern
pathlib.Path('./images/').mkdir(parents=True, exist_ok=True)
THETA = THETA - 0.000001
for key in views.keys():
ax.view_init(views[key][0], views[key][1])
plt.savefig("./images/" + BASENAME + "_SE_" + str(VIEW_SEGMENTEBENEN) + "_VIEW_" + str(key) +
"_TH_" + "%04d" % ((THETA+100)*10) + ".png",
bbox_inches='tight',pad_inches = 0, dpi=300)
ax.view_init(views['1_oblique'][0], views['1_oblique'][1])
if len(LOOP_THETAS) == 1 and SHOW_PLOT:
plt.show()
else:
plt.close()
Viele Grüße,
Clemens