Numerische Bestimmung und Verhalten der VNS von EQ-Plattformen

Status
Es sind keine weiteren Antworten möglich.

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.

Segmentebenen.gif
Segmente.gif


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.

Konstruktion.png


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).

Segmente.png


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.

Ellipsen.png


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.

Lageroffset.png


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.

Geschwindigkeit.png


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
 
Nachtrag: Berechnung mit reduzierter Anzahl an Parametern für bereits konstruierte Plattformen sowie Abspeichern einer PDF im 1:1 Maßstab:

1670772718136.png



Python:
import matplotlib.pyplot as plt
import numpy as np
from scipy.linalg import expm, norm
import copy
import pathlib
from mpl_toolkits.axes_grid1 import Divider, Size

###############################################################
# PARAMETER

param = {}

# Vorgegeben
param['B']  = 478               # Abstand zwischen Südlager und Schnittlinie Segmentmitten (Definiert durch Senkrechte der Segmente zum Südlager)
param['f_'] = np.radians(22)    # Winkel zwischen Nord-Süd Achse und Segmentmitten
param['a_'] = np.radians(48.5)  # Breitengrad
param['H']  = 35                # Höhe der Plattform über den Nordlagern ohne Auslenkung
param['Hmin'] = 4               # Mindesthöhe der Segmente (Kürzen der Spitzen)

# Abgeleitet
param['F']  = param['B'] * np.tan(param['f_'])                    # Halber Abstand der Segmentmitten
param['J']  = param['B'] + param['F'] * np.tan(param['f_'])       # Abstand zwischen Südlager und gedachter Nordspitze

# 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_'] * 10, 0))) + \
                        "_B-" + str(int(param['B'])) + \
                        "_F-" + str(int(param['F'])) + \
                        "_H-" + str(int(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__":
        
    # 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']])
    rot_vectors = copy.deepcopy(vectors)
    new_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 > param['Hmin']:
            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']))

        # Erster geschriebener Punkt definiert die Ecken
        if len(segmentpos) == 1:
            new_rot_vectors['osteck'] = rot_vectors['ostref']
            new_rot_vectors['westeck'] = rot_vectors['nordspitze'] + np.linalg.norm(new_rot_vectors['osteck'] - rot_vectors['nordspitze']) * (rot_vectors['westsegment'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['westsegment'] - rot_vectors['nordspitze'])
        
        # Letzter geschriebener Punkt definiert die Innenkanten (einfach jedesmal überschreiben)
        new_rot_vectors['ostinnen'] = rot_vectors['ostref']
        new_rot_vectors['westinnen'] = rot_vectors['nordspitze'] + np.linalg.norm(new_rot_vectors['ostinnen'] - rot_vectors['nordspitze']) * (rot_vectors['westsegment'] - rot_vectors['nordspitze']) / np.linalg.norm(rot_vectors['westsegment'] - rot_vectors['nordspitze'])
    
    if not segmentwinkel:
        print("Kein einziger Punkt des Segments wurde gezeichnet!")
        print("Interrupt!")
        sys.exit()

    # Rotiere gemerkte Punkte zurück
    vectors['osteck']    = rot_vectors['suedlager'] + rot_around(new_rot_vectors['osteck']    - rot_vectors['suedlager'], -np.radians(segmentwinkel[0]),  rot_vectors['erdachse'] - rot_vectors['suedlager'])
    vectors['westeck']   = rot_vectors['suedlager'] + rot_around(new_rot_vectors['westeck']   - rot_vectors['suedlager'], -np.radians(segmentwinkel[0]),  rot_vectors['erdachse'] - rot_vectors['suedlager'])
    vectors['ostinnen']  = rot_vectors['suedlager'] + rot_around(new_rot_vectors['ostinnen']  - rot_vectors['suedlager'], -np.radians(segmentwinkel[-1]), rot_vectors['erdachse'] - rot_vectors['suedlager'])
    vectors['westinnen'] = rot_vectors['suedlager'] + rot_around(new_rot_vectors['westinnen'] - rot_vectors['suedlager'], -np.radians(segmentwinkel[-1]), rot_vectors['erdachse'] - rot_vectors['suedlager'])

    # Print
    print("Maximale Auslenkung: " + str(round(segmentwinkel[0],1)) + "° (" + str(int(2 * segmentwinkel[0] / 360 * 1436.07)) + " Minuten)")
    print("Segmentlänge außen: " + str(round(segmentpos[0],1)))
    print("Segmentlänge innen: " + str(round(abs(segmentpos[-1]),1)))
    print("Segmentlänge gesamt: " + str(round(segmentpos[0] + abs(segmentpos[-1]),1)))
    print("Abstand Südlager - Verbindungslinie Segmentecken:       " + str(round(np.linalg.norm(vectors['osteck'] + 0.5 * (vectors['westeck'] - vectors['osteck']) - vectors['suedlager']),1)))
    print("Abstand Südlager - Verbindungslinie Segmentmitten:      " + str(round(np.linalg.norm(vectors['ostsegment'] + 0.5 * (vectors['westsegment'] - vectors['ostsegment']) - vectors['suedlager']),1)))
    print("Abstand Südlager - Verbindungslinie Segmentinnenkanten: " + str(round(np.linalg.norm(vectors['ostinnen'] + 0.5 * (vectors['westinnen'] - vectors['ostinnen']) - vectors['suedlager']),1)))

    # 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")



    ###############################################################
    # PDF des Segments

        # din a4
        din_a4_width_mm  = 297
        din_a4_height_mm = 210
        din_a4_width_inches  = din_a4_width_mm  / 25.4
        din_a4_height_inches = din_a4_height_mm / 25.4
        ax_rel_width  = 0.9
        ax_rel_height = 0.9
        
        # real units
        fig1 = plt.figure(figsize = (din_a4_width_inches, din_a4_height_inches))
        h = [Size.Fixed((1-ax_rel_width)  / 2 * din_a4_width_inches),  Size.Fixed(ax_rel_width  * din_a4_width_inches)]
        v = [Size.Fixed((1-ax_rel_height) / 2 * din_a4_height_inches), Size.Fixed(ax_rel_height * din_a4_height_inches)]
        divider = Divider(fig1, (0, 0, 1, 1), h, v, aspect=False)
        ax = fig1.add_axes(divider.get_position(),axes_locator=divider.new_locator(nx=1, ny=1))
        ax.set_xlim(-din_a4_width_mm  * ax_rel_width  / 2, din_a4_width_mm  * ax_rel_width  / 2)
        ax.set_ylim(-din_a4_height_mm * ax_rel_height * 0.05, din_a4_height_mm * ax_rel_height * 0.95)
        plt.gca().invert_yaxis()
        ax.xaxis.tick_top()

        plt.plot(segmentpos, segmenthoehe, linewidth = 0.5, color = 'black')
        plt.plot([0,0],[-din_a4_height_mm * ax_rel_height * 0.05, din_a4_height_mm * ax_rel_height * 0.95], linewidth=0.5, color='black', linestyle='--')
        plt.text(segmentpos[-2]+3,param['H']/2,BASENAME.replace("_",",  ").replace("-",": "),va='bottom',ha='left') 
       
        pathlib.Path('./images/').mkdir(parents=True, exist_ok=True)
        fig1.savefig("./images/" + BASENAME  + ".pdf")
        plt.close(fig1)

    ###############################################################
    # 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
        fig2, 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()
 
Hi Clemens @NablaDelta ,

ich bin nicht fit in Python.
Kannst du mir kurz erklären wie ich die Python Scripts zum Laufen bringe.

Ich habe das Script einfach in die Python Shell 2.7.18 "gepastet". Geht das so?
Es kam auch folgender Fehler:

Traceback (most recent call last):
File "<pyshell#0>", line 3, in <module>
import matplotlib.pyplot as plt
ImportError: No module named matplotlib.pyplot

Wäre nett wenn du einfach deine Entwicklungsumgebung und notwendige Libraries und Schritte kurz beschreibst.

Gruß
Peter
 
Hi Clemens @NablaDelta ,

so, mal wieder mit Python beschäftigt. ;)

Die Libraries habe ich mit pip installiert.

Aber ich bekomme jetzt diesen Fehler:
Traceback (most recent call last):
File "C:\Daten\Astronomie\Segmente.py", line 75, in <module>
pathlib.Path('./data/').mkdir(parents=True, exist_ok=True)
TypeError: mkdir() got an unexpected keyword argument 'exist_ok'

Liegt das an Python 2.7 statt 3?

Gruß
Peter
 
Hallo Peter,

ziemlich sicher, ja. Versuch mal oben
Python:
import os
hinzuzufügen (sollte nicht installiert werden müssen) und außerdem die entsprechenden Zeilen (gibt 4 Stück für data und images) durch folgendes zu ersetzen:
Python:
if not os.path.exists('./data/'):
    os.makedirs('./data/')
Bei "images" natürlich mit './images/'.

Gib gerne Bescheid ob es funktioniert, dann poste ich auch den kompletten Python 2-fähigen Code :)
 
Trotzdem noch eine kurze Anleitung: Entsprechenden Code kopieren und in einer Textdatei mit der Endung .py an einem beliebigen Ort und mit beliebigem Name abspeichern. Unter Download Python Python herunterladen und installieren. Kommandozeile öffnen (Windows-Taste + "Eingabeaufforderung" oder "cmd") und das matplotlib-Package mit folgendem Befehl installieren:
Code:
python -m pip install matplotlib
Ganz oben im Python-Code werden immer die benutzten Packages erwähnt, evtl. müssen andere analog installiert werden, falls später beim Ausführen eine entsprechende Fehlermeldung kommt.
Nun das Python-Skript ausführen. Dazu entweder in der Kommandozeile zum Pfad der Python-Datei navigieren, oder im Explorer den Pfad öffnen und in der Pfadeingabe "cmd" + Enter eingeben, das öffnet die Kommandozeile im entsprechenden Pfad.
1670881050009.png

Dann schlicht und einfach
Code:
python DATEINAME.py
eingeben. Im Idealfall läuft das Programm durch, ansonsten die Fehlermeldung lesen (hoffentlich nur ein Paket das fehlt, s.o.). Viel Erfolg!

PS: Wem das mit der Kommandozeile auf Dauer zu umständlich ist, aber auch nicht gleich eine riesige Entwicklungsumgebung installieren möchte, dem kann ich den super schlanken Thonny Editor empfehlen. Damit kann man wie mit Notepad den Code einfach editieren und das Programm mit einem Klick starten.
 
Zuletzt bearbeitet:
Hi Clemens @NablaDelta ,

danke für deine Hilfe.

Ich will übrigens mit deinem Skript meine Segmente überprüfen. Ich glaube nämlich, dass die für einen falschen Winkel sind.
Das PDF kann man doch so ausdrucken, dass es dem echten Segment entspricht/entsprechen sollte. Oder?

Ich brauche übrigens Python2 wegen dem Scripting von SharpCap. Das nutzt Python2. Wobei ich mal schauen müsste, ob Robin Glover es inzwischen auf Python3 upgedatet hat.

Kann man eigentlich beide Python Versionen parallel installieren?
Ich wollte mir das nicht antun, da es vielleicht Konflikte gibt.
Wäre dann das Einfachste.

Ich habe die Änderungen durchgeführt. Jetzt gibt es folgenden Fehler:

Traceback (most recent call last):
File "C:\Daten\Astronomie\Segmente.py", line 271, in <module>
fig2, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize = (5, 5))
File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 1187, in subplots
gridspec_kw=gridspec_kw)
File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1369, in subplots
axarr[row, col] = self.add_subplot(gs[row, col], **subplot_kw)
File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1239, in add_subplot
self, *args, **kwargs)
File "C:\Python27\lib\site-packages\matplotlib\projections\__init__.py", line 91, in process_projection_requirements
projection_class = get_projection_class(projection)
File "C:\Python27\lib\site-packages\matplotlib\projections\__init__.py", line 65, in get_projection_class
raise ValueError("Unknown projection '%s'" % projection)
ValueError: Unknown projection '3d'

Wahrscheinlich wieder ein Versions Fehler.
Falls du eine einfache Lösung hast, wäre das nett. Danke dir.
Ansonsten installiere ich halt Python3. Ist ja sowieso empfehlenswert.

Gruß
Peter
 
Hi,

ich bin jetzt zum Starten/Entwickeln von Python Code auf Visual Studio Code umgestiegen.
VSC ist inzwischen mein "GoTo" für Arduino und andere Sprachen. Hat halt alles schön integriert und viele automatische Konfiguration, so dass erstmal alles läuft.

In VSC muss man die Python Extension und einen Python Interpreter/Laufzeit installieren.
Man hat dann eine schöne Entwicklungsumgebung für Python.
Den Python Interpreter bietet VSC über den MS Store direkt an. Das habe ich einfach benutzt damit gleich alles richtig integriert ist.
Es ist natürlich ein Python 3.

Die Skripte von Clemens laufen damit in VSC.

Jetzt muss ich nur noch das erzeugte PDF so auf den DIN A4 Laser von HP ausdrucken, dass die gedruckten Masse den berechneten entsprechen.

Gruß
Peter
 
Hallo Leute,
ich hatte eine VNS EQ Plattform. Leicht, niedrig, sehr steif, gut zu transportieren, super für visuell.
Für Planetenfotografie mit kleinem Sensor aber wegen mangelnder Nachführpräzission aber nur sehr bedingt nutzbar. Nun bin ich seit einem halben Jahr umgestiegen auf eine EQPF mit Kreissegmenten. Schwer, wackelig,teuer, aber enorm präzise und daher um Welten besser für Planetenfotografie.
CS Mike
 
Hi Mike,
Für Planetenfotografie mit kleinem Sensor aber wegen mangelnder Nachführpräzission aber nur sehr bedingt nutzbar.
Kann ich bei meiner VNS Plattform von Martini nicht bestätigen.
Hatte Jupiter sogar mit dem grossen 20 Zöller mit 2105mm Brennweite und mit der ASI294 gefilmt. Blieb gut im ROI. Aber es war nur ein Test, da ich kein Planeten Fotograf bin.

Was hattest du für eine Brennweite und Sensor?

Nun bin ich seit einem halben Jahr umgestiegen auf eine EQPF mit Kreissegmenten. Schwer, wackelig,teuer, aber enorm präzise und daher um Welten besser für Planetenfotografie.
Für was steht EQPF schon wieder?
Wo gibt es so eine Plattform oder Bauplan?

Wackelig und trotzdem präziser?

Gruß
Peter
 
Hi Peter,
Sensorgröße 5.6x3.2mm,mit ROI natürlich kleiner. Brennweite mit ADC, zirka 10m.
EQPF steht für "equatorial platform".
Bauplan hab ich keinen, gibts in Ungarn bei Triangulum. Präziser in der Nachführung. Firecapture gleicht die Wackelei beim Scharfstellen am Planeten aus.
CS Mike
 
Hi zusammen,
hallo Clemens,

danke für den super Artikel.

Justmy2cents zu meinen Erfahrungen (EQPF o_O - ich hasse Abkürzungen, die nicht zuerst eingeführen/erklärt werden - dann erst verwenden bitte).

Ich habe mega schlechte Erfahrungen mit einer GEOPTIK EARTHA gemacht. Schwer (da hebste Dir nen Bruch), wackelte wie ein Kuhschwanz (3-5 mm beim 16 Zoll/F4), Motor/Getriebe-Kombi mit sehr viel Spiel. Fazit: nur mit Modifikationen zu gebrauchen. Und am Ende ist die Arduino-Steuerung in Flammen aufgegangen (na ja, in Qualm). Und der Gummitrieb rutschte regelmäßig durch. Das war nix und machte Modifikationen notwendig:


Am Ende ist sie mittlerweile zugunsten einer Martini-Plattform verkauft worden. Weniger ist manchmal mehr. Die habe ich dieses Jahr am Gederner See gebraucht erstanden. Lediglich die Steuerung habe ich an ein Kabel gelegt, damit man die Geschwindigkeit einfacher regeln kann, ohne auf dem Boden rumzukriechen. Und die Platte habe ich etwas verstärkt. Die muss wirklich verwindungssteif sein (also die beiden seitlichen, äußersten Auflagepunkte auf den Kreissegmenten in Bezug auf die Mittelachse) - sonst führt das wieder zu Instabilität. Aus meinen Erfahrungen mit dem recht schweren 16-Zöller (F4) kann ich sagen, eine EQ-Plattform sollte aus meiner Sicht daher
  • einen niedrigen Schwerpunkt haben
  • verwindungssteife, nicht federnde Auflagepunkte für den Dobson bieten (also eine verwindungssteife Auflageplatte haben, so dass die Auflagepunkte nicht verkippen)
  • eine gut zugängliche Geschwindigkeitssteuerung (am besten vom Okular aus bedienbar)
  • einen Endschalter (mit akustischer oder optischer Warnung)
  • am besten eine motorische Rückstellung (das ist nicht ganz trivial, wenn man keinen Schrittmotor verwendet - bei einem einfachen Getriebemotor quasi nicht möglich)
  • wenig Spiel beim Getriebe (beim Durchschwingen bleibt sonst die Plattform eine Zeitlang "stehen")
  • Man sollte das Teil auf einen nicht-schwingenden Boden aufstellen (Gehwegplatten drunter)!

Cheers, Axel
 
Zuletzt bearbeitet:
Hi Peter,
Sensorgröße 5.6x3.2mm,mit ROI natürlich kleiner. Brennweite mit ADC, zirka 10m.
EQPF steht für "equatorial platform".
Bauplan hab ich keinen, gibts in Ungarn bei Triangulum. Präziser in der Nachführung. Firecapture gleicht die Wackelei beim Scharfstellen am Planeten aus.
CS Mike
Hi Mike, (@MikeWölle) , aahhh ok.

Da musst du aber dazu sagen, dass wir hier von einer 2500,- € Plattform reden und die eine ST4-Nachführung sowie eine DEC-Nachführung besitzt. Das ist ja eine komplett andere Liga :) Vom Gewicht (30 KG!) ganz zu schweigen, welches die TEPP hat. Und konstruktiv geht die auch in eine komplett andere Richtung. Das sind Kreissegmente, die schräggestellt sind (wie bei der Geoptik EARTHA). Zudem noch verstellbar für verschiedene Breitengrade. Das wäre aber einen andereren Thread wert, mal über diese Plattform zu berichten.

CS Axel
 
Zuletzt bearbeitet:
Hi,

so ich habe mit dem Python Script von Clemens @NablaDelta für meine Martini Plattform die Segmente berechnet und mit den echten verglichen/geprüft.
Wie ich mir schon gedacht, bzw festgestellt habe, weil ich beim Polar Alignment die Plattform im Süden extrem hochstellen musste, sind das Segmente für 54Grad Breite. Ich bin auf 47 Grad Breite.

Zuerst hatte ich das PDF über den Drucker ausgedruckt. Da hat man dann, wie erwartet, das Problem, dass der Druck korrekt skaliert sein muss.
Standardmäsig war er das bei mir nicht. Aber man kann durch die Markierungen auf dem Blatt einen manuellen Skalierungsfaktor finden der korrekt sein sollte.

Ich habe aber dann nicht mehr den Druck benutzt, da ich festgestellt habe, man kann die Segmente viel besser direkt am Bildschirm überprüfen. Auch da muss man dann manuell skalieren bis es passt.

Noch ne Frage an Clemens @NablaDelta :
Verstehe ich das jetzt richtig, dass das Script "nur" Ellipsenausschnitte berechnet?
Ellipsenausschnitte sind ja ein ganz klein wenig falsch. Wie falsch, weiss ich nicht richtig.
Könnte man die wirklich korrekte Kurve auch berechnen?

Gruß
Peter
 
Hallo Peter,

nein, das Skript berechnet bereits die absolut ideale Form der Segmente. Die Berechnung der Ellipsensegmente im ersten Code war nur zum Vergleich und ist im zweiten komplett rausgenommen.

Zum Drucken im korrekten Maßstab: Eigentlich sollte es bei jedem Druckertreiber die Option "Tatsächliche Größe" geben, ohne dass man manuell etwas skalieren muss?

1671792452685.png


Viele Grüße
Clemens
 
Huhu,

das Script ist ja Wahnsinn! Klasse.

Einen Unterschied der Segmente wegen der Höhenvariation sollte es bei dem Kegelschnitt eigentlich nicht geben. Bzw sollte es den nur geben, wenn du die Kegelspitze am Südlager fest hältst und dieser nicht mit der Nordlagerhöhe variierst. Kann das sein? Ich denke, dass macht aber konstruktiv nicht so viel Sinn. Die Plattformoberseite sollte in Waage sein, wenn sie genau in der Mitte steht.

Könnte man irgendwie noch einbauen, dass der Kegel genau durch den Schwerpunkt des Teleskops geführt werden kann. Durch Eingabe der Schwerpunkthöhe? Dann kann man meiner Erfahrung nach auch ein 20 kg Teleskop mit einem kleinen Finger auf den Rollen hin und her schubsen.
Dann solltest du eigentlich alles mit dem Script abgedeckt haben. Dann muss man die Stücke nur noch an der exakten Position anbauen. Vielleicht kannst du dazu ebenfalls eine PDF genieren. Ich habe mir dafür ein Projektor auf Maßstab gebracht und das ganze auf Holz gezeichnet. Ein A4 Blatt eingezeichnet auf die eigentliche Skizze hilft beim finden des Maßstabs zum Abzeichnen.

Ich habe mal meine Plattform als PDF angehangen.


Viele Grüße

Sebastian
 

Anhänge

Hallo Sebastian,

danke für das Lob und die Anregung!

Einen Unterschied der Segmente wegen der Höhenvariation sollte es bei dem Kegelschnitt eigentlich nicht geben. Bzw sollte es den nur geben, wenn du die Kegelspitze am Südlager fest hältst und dieser nicht mit der Nordlagerhöhe variierst. Kann das sein? Ich denke, dass macht aber konstruktiv nicht so viel Sinn.

Der Unterschied ist ja nur ganz minimal und wie bereits erwähnt kann ich mir die Bewegung bei gedrehten Segmenten sehr schlecht vorstellen, wir haben hier ja keine Kegelschnitte mehr. Ich denke es hängt mit dem Verkippen der Segmente zusammen, welches ja auch höhenabhängig ist.

Da man wie beim Segmentwinkel und der Plattformbreite auch bei der Schwerpunktshöhe und der Plattformlänge nur einen der beiden Parameter frei wählen kann, habe ich nun ein interaktives Programm kompiliert. Dann muss man auch Python nicht mehr installieren bzw. mit Python 2 kämpfen ;)

Bevor ich eventuelle weitere Versionen hier immer wieder im Forum als neuen Eintrag poste, habe ich das Programm außerdem (neben einem älteren) auf eine spontan gebastelte Webseite gepackt: https://nabladelta.wixsite.com/astro/eq-plattform (ich hoffe Zugang und Download funktionieren :)).

Gerne ausgiebig testen und mir Fehler oder Komplikationen melden wenn es welche gibt :) Bin gespannt was ihr meint.

Viele Grüße,
Clemens
 
Hi Clemens @NablaDelta ,

echt klasse. Dein Programm funktioniert. Danke.

Bin am Ausprobieren.

Meine Plattform ist wohl für 54 Grad. Da passt die Kurve mit den echten Segmenten am besten.
Das ist für meinen Standort mit 47 Grad viel zu hoch.
Das war auch das Problem beim Polar-Alignment. Ich musste die Plattform im Süden sehr stark anheben.

Gruß
Peter
 
Huhu,
ich bin Linux-Nutzer... müsste ich mal mit Wine oder in einer VM probieren. Vielleicht kannst du es als Webservice auf deiner Webseite einbinden? Mit Python Flask drum rum, sollte recht schnell gelöst sein; du scheinst ja Python sehr gut zu beherrschen.

Der Unterschied ist ja nur ganz minimal und wie bereits erwähnt kann ich mir die Bewegung bei gedrehten Segmenten sehr schlecht vorstellen, wir haben hier ja keine Kegelschnitte mehr. Ich denke es hängt mit dem Verkippen der Segmente zusammen, welches ja auch höhenabhängig ist.
Puh, ganz ehrlich: Ich habe meine CAT-Zeichnung drei mal neu gemacht, weil ich da mit dem Kegelschnitt Verständnisprobleme hatte. Leider hilft da auch das Forum nicht weiter, es hat eigentlich jeder den Schnitt nicht ganz korrekt ausgeführt. Jedoch für den Zweck ausreichend. Das ist jetzt das erstmal Mal, dass ich sehe, dass jemand die Krümmung nach hinten mit berücksichtigt. Daher bin ich sehr interessiert, es mit meiner CAT-Zeichnung abzugleichen und evtl. Abweichungen bei mir oder dir zu aufzudecken oder einfach nur zu validieren, dass es richtig ist :)

Hier mal zur Veranschaulichung, die beiden Ellipsenstücke laufen auf dem Kegel entlang. Es sind Kegelschnitte... dazu müsste ich zur Veranschaulichung den Kegel zum Scheiden nur verlängern:
1672253784598.png


Vielleicht kannst du mal meine Maße durchgeben:
BG: 51,3 °
Schwerpunkt: 375 mm
Länge aber eigentlich eher "Länge SW": 480 mm
Breite ergibt sich bei mir aus Winkel SW und länge SW.
Segmentwinkel SW: 36
Höhe: 35 mm
Hmin: 15mm

Um es jetzt mit dir abzugleichen, müsste ich glaube im CAT eine Plane auf den Schnittpunktpunkt SW/Ellipse legen und mir es zweidimensional anschauen? Oder? Meine Ellipsenstücke sind aus dem 3D-Drucker und der macht einfach die Krümmung mit (zur Veranschaulichung):
Polausrichtung mit Dobson EQ Plattform - Welche Möglichkeiten gibt es?

Aber ich denke, dass bekommen wir trotzdem validiert, da es auf der besprochenen Plane so aussehen sollte wie deine Integration... Vielleicht bin ich auch nur wirr :D

Viele Grüße

Sebastian
 
Hallo Sebastian,

Webservice ist leider nicht drin da ich nicht selbst hoste sondern einen Anbieter gewählt habe. Ich kann es dir aber gerne mal berechnen und das Ergebnis per PN senden. Mit BG 51,3° und Schwerpunkt 375 mm komme ich allerdings bereits auf eine Länge von 769 mm und die "Länge SW" wäre noch größer?

Nette CAT-Ansicht :) Natürlich sind es noch Kegelschnitte solange man das Verkippen der Segmente bei Auslenkung vernachlässigt. Da ohne Auslenkung die Segmente senkrecht auf den Lagern stehen sollte in erster Ordnung (also die Steigung) hier mit dem Kegelschnitt übereinstimmen. Bei größeren Auslenkungen kann es aber durch das Verkippen zu Abweichungen vom Kegelschnitt kommen.

Bestimmst du mit CAT die Segmente durch die Kegelschnitte ohne Auslenkung oder lenkst du deine Plattform wie im GIF meines ersten Posts aus und "schreibst" so Schritt für Schritt die Segmente? Ich denke nur letzteres führt zu 100% korrekten Segmenten.

Ich kann nicht aufhören zu betonen: Die Verkippung ist vermutlich in unseren Breitengraden in der Praxis wirklich nicht relevant und eine rein theoretische Überlegung. Mein Programm hat vermutlich lediglich für das Berechnen von Segmenten für existierende Plattformen (ohne die Notwendigkeit die Ellipsen-Konstruktion erst zurückrechnen zu müssen) wirklich praktische Relevanz :)

Viele Grüße
Clemens
 
Ich kann nicht aufhören zu betonen: Die Verkippung ist vermutlich in unseren Breitengraden in der Praxis wirklich nicht relevant und eine rein theoretische Überlegung.
Ja, das kann wohl sein. Selbst wenn man es auf den µm genau Lasern lassen würde, es würde wohl dann daran scheitern, dass man es dann auf eine Holzkonstruktion mit Messmitteln wie Zollstock aufbringt oder ähnlichem.

Also erstmal muss ich mich entschuldigen, es sollte natürlich CAD heißen und im speziellen FreeCAD. Da habe ich mich wohl von den Baustellenvideos auf dem Monitor nebenan, für meinen Sohn, ablenken lassen. :)

Also mein Verständnis der Sache war, der Kegel (die mittlere Achse) zeigt Richtung Pol und die Plattform muss sich um diese Achse drehen. Im CAD kann ich zeigen, dass sich die Ellipsenstücke über den Rand des oben gezeigten Kegels drehen.

Da ohne Auslenkung die Segmente senkrecht auf den Lagern stehen sollte in erster Ordnung (also die Steigung) hier mit dem Kegelschnitt übereinstimmen. Bei größeren Auslenkungen kann es aber durch das Verkippen zu Abweichungen vom Kegelschnitt kommen.
Vielleicht weiß ich was du meinst: Der Kegel oben bildet ein Kreisfläche. Durch den Winkel bildet sich eine kurzes Ellipsenstück, die Ellipse ist aber nur lokal gültig. Wobei das bei der kurzen Rollenauflage so wäre, als wenn ich die Ellipse drehe und .... nun hört meine Vorstellungskraft auf :ROFLMAO:

Puh, ich hatte gehofft das Thema damals komplett nachvollzogen zu haben... es kommen schon wieder Zweifel auf.

Wieso wird die Plattform so lang? Wahrscheinlich hältst du an einem Parameter fest, den man noch variieren könnte?!

Viele Grüße

Sebastian
 
Wieso wird die Plattform so lang? Wahrscheinlich hältst du an einem Parameter fest, den man noch variieren könnte?!
Ne sorry, liegt an mir... ich habe damals die Maße vom Mittelpunkt des gezeigten Kegels, aber herunter projiziert auf die Plattform, bezogen (ist dann wieder eine Ellipse). Umgerechnet auf deine Koordinaten vom Südlager aus, sollten es nicht 36 Grad sondern 24,85° sein.
 
Hi Sebastian @Counterfeiter ,

du kannst doch unter Linux das originale Python Script von Clemens @NablaDelta laufen lassen, oder nicht?
Hatte ich ja unter Windows auch gemacht.

Gruß
Peter
 
Bevor ich eventuelle weitere Versionen hier immer wieder im Forum als neuen Eintrag poste, habe ich das Programm außerdem (neben einem älteren) auf eine spontan gebastelte Webseite gepackt: https://nabladelta.wixsite.com/astro/eq-plattform (ich hoffe Zugang und Download funktionieren :)).
Hi Clemens,

nur so als Tipp: für Quellcode und auch für alles andere (Doku in einer Readme auch mit Bildern) eignet sich GitHub: Let’s build from here wirklich am Besten. Kannst natürlich auch Homepages basteln - doch warum das Rad neu erfinden. Eine Versionierung und einfachen Download für alle erreichst du auf diese Weise mit minimalem Aufwand :) Kost nix und wird wirklich weltweit nicht nur von Programmierern verwendet (das Git-Gedöns brauchst du erstmal gar nicht, ist aber praktisch, wenn du wirklich mit Quellcode arbeiten willst). Einarbeitungszeit: gering. Einfach loslegen, dem Wizard folgen, eine Readme bearbeiten (einfacher Markdown), die gleichzeitig als Landingpage dient. Eine Lizenz einfügen (am besten OpenSource mit Namensnennung) und Zeugs in Unterordner hochladen.

Ein gutes Neues Jahr.
LG Axel
 
Sehr cool... Es läuft auch (fast alles) unter Linux! Vielleicht noch eine Lizens hinzufügen, dann könnte ich z.B. eine requirements.txt pull requesten...

Oder so:
Code:
imageio
matplotlib
numpy
scipy

Qt5 fehlt noch in der Auflistung, konnte ich aber nicht testen, weil es Unstimmigkeiten mit den GUI Backends gab. Ich hatte das jetzt noch nicht aufgelöst. Wahrscheinlich brauche ich das Python Tkinter package dennoch.
 
Lizenz ist jetzt vorhanden :y: Ja für das GIF und die direkte 3D-Anzeige benötigt es unterschiedliche Backends (Agg und Qt5Agg), die sollten aber beide mit matplotlib schon installiert sein? Um tkinter kommst du sicher nicht drum herum ;)
Am schwierigsten war imageio, das image reshape der GIFs hat bei mir nur mit der imageio Version 2.10.5 anstatt der aktuellen funktioniert.
 
Ich stöbere gerade mal wieder in den Archiven … sehr sehr cool geworden. Eine selbstgebaute VNS mit DEC Achse steht in den Startlöchern …

Ich frage mich nur grade, wie ich die Daten auf die Frösmaschine bekomme, aber dazu muss ich mir erstmal deine ganzen Outputdaten ansehen. STL wäre fein :-)
 
Status
Es sind keine weiteren Antworten möglich.
Zurück
Oben