Iterative Verschiebung einer Kurve

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
herttim
User
Beiträge: 19
Registriert: Mittwoch 8. Dezember 2021, 14:18

Hallo zusammen,

ich bin noch recht am Anfang mit meinen Python-Kenntnissen, daher würde ich mich sehr freuen, falls ihr mir bei dem folgenden Problem weiterhelfen könntet: :cry:

Ich habe folgendes Programm geschrieben, bei dem 2 Kurven über einen csv-Import eingelesen werden können.
Jetzt möchte ich im nächsten Schritt die Kurve "Kegelrolle" so lange iterativ verschieben, bis sie an zwei Punkten die Kurve "Innenring" berührt.
Leider bin ich mir nicht sicher wie ich das ganze umsetzen kann, also wie diese schrittweise Verschiebung der Kurve realisiert werden kann, bis eine vorgegebene Bedingung erfüllt ist.

Vielen Dank im Voraus.


Programm aktueller Stand zum Einlesen und plotten der zwei Kurven:

Code: Alles auswählen

import tkinter
import tkinter as tk
import pandas as pd
import numpy as np
import matplotlib as mtpl
import matplotlib.pyplot as plt
import csv
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
                                               NavigationToolbar2Tk)
from tkinter.filedialog import asksaveasfile
from tkinter.filedialog import askopenfilename
from matplotlib.figure import Figure
from tkinter import ttk
from tkinter import *


class ProfilierungImport:
    
    def __init__(self):
        global window
        self.window = tk.Tk()
        self.window.title("Toleranzanalyse Kontaktgeometrie")
        self.window.geometry("400x220")
        self.window.resizable(True,True)
        
        def ImportIRCSV():
            global x1,y1
            
            x1 = []
            y1 = []
            
            with open(askopenfilename(), "r") as csv_file_path_IR:
                plots = csv.reader((line.replace(',','.') for line in csv_file_path_IR), csv_file_path_IR, delimiter=";")
                for row in plots:
                    x1.append(float(row[0]))
                    y1.append(float(row[1]))
                    
        def ImportKRCSV():
            global x2,y2
            
            x2 = []
            y2 = []
            
            with open(askopenfilename(), "r") as csv_file_path_KR:
                plots = csv.reader((line.replace(',','.') for line in csv_file_path_KR), csv_file_path_KR, delimiter=";")
                for row in plots:
                    x2.append(float(row[0]))
                    y2.append(float(row[1]))
        
        def RotIR():
            global x1_versch, y1_versch

            alpha1 = -5.6767128
            
            valueX = [10, 36]
            
            x1_array = np.array(x1)
            y1_array = np.array(y1)
            
            x1_kor = x1_array - x1[0]
            y1_kor = y1_array - y1[0]
            
            x1_versch = x1_kor * np.cos(np.radians(alpha1)) - y1_kor * np.sin(np.radians(alpha1))
            y1_versch = x1_kor * np.sin(np.radians(alpha1)) + y1_kor * np.cos(np.radians(alpha1))
            
            print(x1_kor, y1_kor)
            print(x1_versch, y1_versch)
            
            alpha2 = -4.088817418
            
            x2_array = np.array(x2)
            y2_array = np.array(y2)
            
            x2_kor = x2_array - x2[0]
            y2_kor = y2_array - y2[0]
            
            x2_versch = (x2_kor * np.cos(np.radians(alpha2)) - y2_kor * np.sin(np.radians(alpha2))) 
            y2_versch = (x2_kor * np.sin(np.radians(alpha2)) + y2_kor * np.cos(np.radians(alpha2))) 
            
            x1list = x1_versch.tolist()
            y1list = y1_versch.tolist()
            x2list = x2_versch.tolist()
            y2list = y2_versch.tolist()
            
            x2res = [x + float(VerschX.get()) for x in x2list]
            y2res = [x + float(VerschY.get()) for x in y2list]
            
            #plt.plot(x1_versch, y1_versch)
            fig = plt.figure()
            ax = fig.add_subplot(111)
            ax.plot(x1list, y1list)
            ax.plot(x2res, y2res)
            plt.xlabel('Messpunkt')
            plt.ylabel('Profilierung [mm]')
            plt.title('Laufbahnprofilierung')
            plt.show()
            
            fig, axs = plt.subplots(2, 3)
            axs[0, 0].plot(x1list, y1list)
            axs[0, 0].set_title('Innenring')
            axs[0, 0].grid(linestyle='dotted', color='grey')
            axs[0, 1].plot(x2res, y2res, 'tab:orange')
            axs[0, 1].set_title('Kegelrolle')
            axs[0, 1].grid(linestyle='dotted', color='grey')
            axs[1, 0].plot(x1list, y1list, x2res, y2res, 'tab:orange')
            axs[1, 0].set_title('Kontaktgeometrie')
            axs[1, 0].grid(linestyle='dotted', color='grey')
            axs[1, 1].plot(x1list, y1list, x2res, y2res, 'tab:orange')
            axs[1, 1].set_title('Profilierung')
            axs[1, 1].set_xlim([12.5, 34.5])
            axs[1, 1].set_ylim([-1.48, -1.42])
            axs[1, 1].grid(linestyle='dotted', color='grey')
            axs[0, 2].plot(x1list, y1list, x2res, y2res, 'tab:orange')
            axs[0, 2].set_title('Kontaktgeometrie')
            axs[0, 2].set_xlim([9.52, 9.56])
            axs[0, 2].set_ylim([-2, 2])
            axs[0, 2].grid(linestyle='dotted', color='grey')
            axs[1, 2].plot(x1list, y1list, x2res, y2res, 'tab:orange')
            axs[1, 2].set_title('Kontaktgeometrie')
            axs[1, 2].set_xlim([36, 39])
            axs[1, 2].set_ylim([-2, 2])
            axs[1, 2].grid(linestyle='dotted', color='grey')
            
            new_window = tk.Tk()
            new_window.title("Toleranzanalyse Profilierung")
            new_window.geometry("1200x900")
            new_window.resizable(True,True)
        
            canvas = FigureCanvasTkAgg(fig, new_window)
            canvas.draw()
            canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
            
            toolbar = NavigationToolbar2Tk(canvas, new_window)
            toolbar.update()
            canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
                    
        ImportIR = tk.Button(self.window, text="Import IR", width=12, bg="#CCCCCC", command=ImportIRCSV)
        ImportIR.grid(row=0, column=0, padx=30, pady=2, sticky="n")
        
        ImportKR = tk.Button(self.window, text="Import KR", width=12, bg="#CCCCCC", command=ImportKRCSV)
        ImportKR.grid(row=1, column=0, padx=30, pady=2, sticky="n")
        
        Plot = tk.Button(self.window, text='Plot', width=12, bg='#CCCCCC', command=RotIR)
        Plot.grid(row=0, column=1, padx=30, pady=2, sticky='n')
        
        Save = tk.Button(self.window, text='Speichern', width=12, bg='#CCCCCC')
        Save.grid(row=4, column=0, padx=30, pady=2, sticky='n')
        
        Load = tk.Button(self.window, text='laden...', width=12, bg='#CCCCCC')
        Load.grid(row=5, column=0, padx=30, pady=2, sticky='n')
        
        VerschiebungX = Label(self.window, text="Verschiebung x [mm]", width=15)
        VerschiebungX.grid(row=2, column=0, sticky="n", padx=8)
        
        VerschiebungY = Label(self.window, text="Verschiebung y [mm]", width=15)
        VerschiebungY.grid(row=3, column=0, sticky="n", padx=8)
        
        VerschX = StringVar(value="38.423")
        Entry(self.window, textvariable = VerschX, 
              justify = RIGHT, width="10").grid(row=2, column=1, sticky="n", padx=8)
        
        VerschY = StringVar(value="3.39")
        Entry(self.window, textvariable = VerschY, 
              justify = RIGHT, width="10").grid(row=3, column=1, sticky="n", padx=8)
        
        self.window.mainloop()
ProfilierungImport()
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

Du importierst tkinter auf drei verschiedene Arten, wobei Du fast nur eine (die richtige) Art verwendest.
Pandas wird importiert, aber nicht verwendet. `mtpl` wird auch nicht verwendet.

`global` darf man nicht verwenden; `window` wird gar nicht erst definiert. Du definiertst eine Klasse, die gar keine ist. Funktionen verschachtelt man nicht und __init__ ist zum initialisieren da, nicht dass das ewig läuft. `global` ersetzt man durch Instanzattribute. `ImportIRCSV` und `ImportKRCSV` sind identisch, das sollte eigentlich nur eine Funktion sein.
Auch die Rechnungen, die du mit x1/y1 und x2/y2 machst, sind fast identisch, also sollte das auch in *einer* Funktion stehen.
Es darf nur eine tk.Tk-Instanz geben, weitere Fenster macht man mit TopLevel.

Benutzt keine kryptischen Abkürzungen, kor? versch? Warum steht da KR statt Kegelrolle? Variablennamen werden komplett klein geschrieben.

Wenn es nur um Verschiebung geht, dann kannst Du doch die Verschiebung an zwei Punkten einfach berechnen. Was genau ist denn das Ziel?
herttim
User
Beiträge: 19
Registriert: Mittwoch 8. Dezember 2021, 14:18

@Sirius3
Es soll möglich sein, auch zukünftig mehrere Kurven einzulesen, die sich an einer unterschiedlichen Position im KOS befinden können.
Somit wäre ein Automatismus, welcher eine Verschiebung der Kurven realisierte, ohne jedes mal eine individuelle Berechnung anstellen zu müssen, sehr hilfreich.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich nehme mal an, KOS soll Koordinatensystem heissen? Warum muss man das abkuerzen? Und warum das, und nicht jedes zweite andere Wort? Automat. zur Verschb von Kurv realis., o jedesmal indiv. Ber. anstellen zu m? Schau, viele Zeichen gespart!

Wie dem auch sei - allgemein ist das doch gar nicht loesbar. Es ist ja einfach sich Beispiele auszudenken, die mehrere Loesungen haben, die auch nicht durch zB ein Minimumskriterium unterscheidbar sind. ZB eine Gerade und eine punktsymetrische kubische Funktion, welche die Gerade immer schneidet, aber wahlweise nach oben oder nach unten um den gleichen Betrag verschoben werden kann, um die Bedingung von zwei Schnittpunkten zu erfuellen.

Da musst du denke ich ein bisschen weiter ausholen, wie dein Problemraum eigentlich aussieht.
herttim
User
Beiträge: 19
Registriert: Mittwoch 8. Dezember 2021, 14:18

Die Funktionen sind von ihrer Art relativ fix (bis auf kleine Änderungen). Vielleicht zur Besseren verständnis: Die Funktionen/Kurven stellen Messschriebe der genannten Bauteile (Kegelrolle/Innenring) dar. Somit kommt es nur zu minimalen Toleranzabweichungen.

Problem ist nur: Die Messmaschine gibt die Koordinaten des Messchriebs sehr unterschiedlich aus, je nach Position der Messaufnahme --> d.h. die Kurve der Kegelrolle liegt für jede Messung nicht an der gleichen Position im Koordinatensystem (KOS).

Prinzipiell lässt sich das Problem recht einfach lösen, so muss man nur die Kurve der Kegelrolle so weit verschieben, bis sie 2 definierte Punkte der Kurve Innenring berührt. Damit das System quasi in x-y-Richtung definiert ist.
Leider fehlt mir dort aber das know-how in Python, das entsprechend umzusetzen, bzw. einen ersten Ansatz auszuarbeiten :(
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kannst du mal ein Beispielbild einstellen? Darstellen kannst du ja schon. Das wuerde das erleichtern, sich das vorzustellen. Dazu das Bild bei einem Dienst wie imgur hochladen, und einfach den Link einkopieren. Oder fancy die URL des eigentlichen Bildes bestimmen, und in [img]-tags packen. Ist aber leider recht fummelig, darum reicht mir auch ein Link.
Benutzeravatar
__blackjack__
User
Beiträge: 13124
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@__deets__: Fummlig? Imgur bietet doch an die URL zum Bild in verschiedenen Formaten in die Zwischenablage zu kopieren. Unter anderem BBCode.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
herttim
User
Beiträge: 19
Registriert: Mittwoch 8. Dezember 2021, 14:18

@__deets__: Hier die URL für das Bild in imgur: https://imgur.com/a/utwEmEh
derElch
User
Beiträge: 33
Registriert: Sonntag 25. Februar 2018, 13:14

Hallo herttim,

mit den Bildern, kann man sich das Problem ganz gut vorstellen. Danke.

Wie "sauber" sind denn die Daten einzelnen Vermessung? Also kann man davon ausgehen das die Koordinaten der einzelnen Messungen der Teile zu einander recht ähnlich sind? Da du ja von Aufnahmen für die Messmaschine sprichst?

Mein Ansatz wäre:
  • Alle Messpunkte auf ein gemeinsames Maß bringen, zB. 1/1000mm (oder gleich auf 0,1µm) durch lineare Interpolation.
  • Finden des Koordinatenursprungs von der Kegelrolle (vertikal: x<10 und y 10 bis 4) daraus eine Senkrechte erstellen, horizontal x: 15 bis 30; y -2 bis 0). Schnittpunkt der Geraden ist dein Koordinatenursprung.
  • Analog dazu für den Innenring
  • Dann die beiden übereinander legen bei gleichem Ursprung
  • Feintuning: die Kegelrolle so lange um eine Schrittweite erhöhen bis die Schnittmenge beider Linien 2 gemeinsame Punkte hat. (Daher auch die die gleiche Rasterung)
Was eventuell auch ginge, wäre eine Verschieben mit einer inpolygon-Prüfung. Da hätte ich persönlich bedenken aufgrund der Menge an Messpunkten.

btw.: Ich persönlich finde das Problem wirklich interessant. :)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

__blackjack__ hat geschrieben: Mittwoch 2. März 2022, 00:14 @__deets__: Fummlig? Imgur bietet doch an die URL zum Bild in verschiedenen Formaten in die Zwischenablage zu kopieren. Unter anderem BBCode.
Kannte ich nicht. Können wir das vielleicht irgendwo in eine Hilfe schreiben oder so? Weil das schon ein wiederkehrendes Thema ist.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

herttim hat geschrieben: Mittwoch 2. März 2022, 07:32 @__deets__: Hier die URL für das Bild in imgur: https://imgur.com/a/utwEmEh
Also ich sehe da eine Reihe von Bildern, bei denen mir teilweise unklar ist, woher die Daten kommen. Vor allem unten Mitte, und unten rechts. Und ich glaube auch nicht, dass man hier eine Strategie für alle fahren kann.

Unten links ist am klarsten zuzuordnen. Und da würde ich es mit einem Verfahren aus der Computer Vision probieren, welche das Problem als Fehlermininimierungsproblem betrachtet. Nämlich “Template matching”. Das berechnet fur zwei Bilder, von denen eines das such Bild, und das andere (kleinere) das Template darstellt, den Ort im Bild, wo die am meisten übereinstimmen. Hier sieht man, wie das geht: https://docs.opencv.org/3.4/d4/dc6/tuto ... ching.html

Wenn du deine Kegelrolle als Template nimmst, und die zb auch noch noch etwas modifizierst, indem du nur den unteren Teil (der sich ja trivial aus der kleinsten Koordinate + einem konstanten Offset berechnen lässt) über den innenring als suchbild laufen lässt, sollte das denke ich ganz gut klappen.

Ein anderer Ansatz wären zb Hugh Lines. Dadurch kannst du eine Menge von Linien pro Kontur bestimmen, und dann Kandidaten für zb die beiden Laufflächen bestimmen, und dadurch die y Koordinate der Verschiebung bestimmen. Und dann einfach die (relativ) senkrechten Linien ausrichten.
Antworten