This commit is contained in:
2026-02-09 21:28:10 +01:00
parent ee895f95a9
commit 0ac49902af
11 changed files with 29903 additions and 29329 deletions

View File

@@ -13,7 +13,7 @@ class Genauigkeitsmaße:
Die Klasse stellt Methoden zur Verfügung für:
- Berechnung der a-posteriori Standardabweichung der Gewichtseinheit s
- Berechnung der a-posteriori Standardabweichung der Gewichtseinheit σ̂
- Berechnung des Helmertschen Punktfehlers (2D/3D),
- Berechnung der Standardellipse (Helmertschen Fehlerellipse),
- Berechnung der Konfidenzellipse auf Basis eines Konfidenzniveaus (alpha) mit Skalierung über die F-Verteilung,
@@ -25,19 +25,19 @@ class Genauigkeitsmaße:
@staticmethod
def berechne_sigma0apost(v: np.ndarray, P: np.ndarray, r: int, print_ausgabe = True) -> float:
"""
Berechnet die a-posteriori Standardabweichung der Gewichtseinheit s₀.
Berechnet die a-posteriori Standardabweichung der Gewichtseinheit σ̂₀.
Die a-posteriori Standardabweichung dient als Qualitätsmaß für die
Ausgleichung nach der Methode der kleinsten Quadrate. Dabei beschreibt
r die Redundanz (Freiheitsgrade).
:param v: Residuenvektor der Beobachtungen.
:type v: numpy.ndarray
:type v: np.ndarray
:param P: Gewichtsmatrix der Beobachtungen.
:type P: numpy.ndarray
:type P: np.ndarray
:param r: Redundanz bzw. Anzahl der Freiheitsgrade der Ausgleichung.
:type r: int
:return: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:return: a-posteriori Standardabweichung der Gewichtseinheit σ̂₀.
:rtype: float
"""
@@ -50,12 +50,12 @@ class Genauigkeitsmaße:
@staticmethod
def helmert_punktfehler(Qxx, s0_apost, unbekannten_liste):
def helmert_punktfehler(Qxx: np.ndarray, sigma0_apost: float, unbekannten_liste: list) -> pd.DataFrame:
"""
Berechnet den Helmertschen Punktfehler (2D/3D) anhand der Standardabweichungen der Koordinaten der Punkte.
Aus der Kofaktor-Matrix der Unbekannten Qxx werden die Kofaktoren punktweise ausgelesen. Durch Multiplikation
mit der a-posteriori Standardabweichung der Gewichtseinheit s₀ werden die Standardabweichungen je Koordinate
mit der a-posteriori Standardabweichung der Gewichtseinheit σ̂₀ werden die Standardabweichungen je Koordinate
(σx, σy, σz) sowie der Helmert'sche Punktfehler σP berechnet:
Die Punktzuordnung erfolgt über die Symbolnamen der Unbekanntenliste.
@@ -63,14 +63,13 @@ class Genauigkeitsmaße:
Ergebnisse als Tabelle ausgegeben und in eine Excel-Datei exportiert.
:param Qxx: Kofaktor-Matrix der Unbekannten.
:type Qxx: numpy.ndarray
:param s0_apost: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:type s0_apost: float
:type Qxx: np.ndarray
:param sigma0_apost: a-posteriori Standardabweichung der Gewichtseinheit σ̂₀.
:type sigma0_apost: float
:param unbekannten_liste: Liste der Unbekannten.
:type unbekannten_liste: list
:return: Tabelle mit Standardabweichungen und Helmertschem Punktfehler je Punkt.
:rtype: pandas.DataFrame
:raises ValueError: Wenn eine ungültige Dimension (nicht 2 oder 3) eingegeben wird.
"""
dim = int(input("Helmertscher Punktfehler (2 = 2D, 3 = 3D): "))
diagQ = np.diag(Qxx)
@@ -98,17 +97,17 @@ class Genauigkeitsmaße:
except StopIteration:
qz = 0.0
sx = s0_apost * np.sqrt(qx)
sy = s0_apost * np.sqrt(qy)
sz = s0_apost * np.sqrt(qz) if dim == 3 else 0
sx = sigma0_apost * np.sqrt(qx)
sy = sigma0_apost * np.sqrt(qy)
sz = sigma0_apost * np.sqrt(qz) if dim == 3 else 0
sP = s0_apost * np.sqrt(qx + qy + qz)
sP = sigma0_apost * np.sqrt(qx + qy + qz)
daten.append([pid, float(sx), float(sy), float(sz), float(sP)])
except:
continue
helmert_punktfehler = pd.DataFrame(daten, columns=["Punkt", "σx", "σy", "σz", f"σP_{dim}D"])
mittel_sP = helmert_punktfehler[f"σP_{dim}D"].mean()
helmert_punktfehler = pd.DataFrame(daten, columns=["Punkt", "σ̂x", "σ̂y", "σ̂z", f"σ̂P_{dim}D"])
mittel_sP = helmert_punktfehler[f"σ̂P_{dim}D"].mean()
print(f"Mittlerer Helmert-Punktfehler über alle Punkte: {mittel_sP:.4f} [m]")
display(HTML(helmert_punktfehler.to_html(index=False)))
helmert_punktfehler.to_excel(r"Netzqualitaet\Standardabweichungen_Helmertscher_Punktfehler.xlsx",index=False)
@@ -117,9 +116,9 @@ class Genauigkeitsmaße:
@staticmethod
def standardellipsoid(Qxx, s0_apost, unbekannten_liste):
def standardellipsoid(Qxx: np.ndarray, sigma0_apost: float, unbekannten_liste: list) -> pd.DataFrame:
"""
Berechnet Achsenlängen des Fehlerellipsoids (a, b, c) sowie den 2D-Richtungswinkel θ aus Qxx und s₀ a posteriori.
Berechnet Achsenlängen des Fehlerellipsoids (a, b, c) sowie den 2D-Richtungswinkel θ aus Qxx und σ̂₀ a posteriori.
Für jeden Punkt wird aus der Kofaktor-Matrix der Unbekannten Qxx die 3×3-Submatrix
der Koordinaten (X, Y, Z) gebildet. Daraus werden zunächst die Standardabweichungen
@@ -137,9 +136,9 @@ class Genauigkeitsmaße:
Die Ergebnisse werden tabellarisch ausgegeben und in eine Excel-Datei exportiert.
:param Qxx: Kofaktor-Matrix der Unbekannten.
:type Qxx: numpy.ndarray
:param s0_apost: A-posteriori Standardabweichung der Gewichtseinheit s₀.
:type s0_apost: float
:type Qxx: np.ndarray
:param sigma0_apost: A-posteriori Standardabweichung der Gewichtseinheit σ̂₀.
:type sigma0_apost: float
:param unbekannten_liste: Liste der Unbekannten.
:type unbekannten_liste: list
:return: Tabelle mit Standardabweichungen (σx, σy, σz), Ellipsoid-Halbachsen (a, b, c) und Richtungswinkel θ je Punkt.
@@ -165,18 +164,18 @@ class Genauigkeitsmaße:
Q_sub = Qxx[np.ix_(indices, indices)]
# Standardabweichungen
sx = s0_apost * np.sqrt(Q_sub[0, 0])
sy = s0_apost * np.sqrt(Q_sub[1, 1])
sz = s0_apost * np.sqrt(Q_sub[2, 2])
sx = sigma0_apost * np.sqrt(Q_sub[0, 0])
sy = sigma0_apost * np.sqrt(Q_sub[1, 1])
sz = sigma0_apost * np.sqrt(Q_sub[2, 2])
# Eigenwertzerlegung
eigenwerte, eigenvektoren = np.linalg.eigh(Q_sub)
eigenwerte = np.sort(eigenwerte)[::-1]
# Halbachsen
s_a = s0_apost * np.sqrt(eigenwerte[0]) # Große Halbachse a
s_b = s0_apost * np.sqrt(eigenwerte[1]) # Mittlere Halbachse b
s_c = s0_apost * np.sqrt(eigenwerte[2]) # Kleine Halbachse c
s_a = sigma0_apost * np.sqrt(eigenwerte[0]) # Große Halbachse a
s_b = sigma0_apost * np.sqrt(eigenwerte[1]) # Mittlere Halbachse b
s_c = sigma0_apost * np.sqrt(eigenwerte[2]) # Kleine Halbachse c
# Richtungswinkel theta in gon:
qyx = Q_sub[1, 0]
@@ -192,10 +191,10 @@ class Genauigkeitsmaße:
])
except:
continue
standardellipsoid = pd.DataFrame(daten, columns=["Punkt", "σx [m]", "σy [m]", "σz [m]", "Halbachse a [m]", "Halbachse b [m]", "Halbachse c [m]", "θ [gon]"])
standardellipsoid["σx [m]"] = standardellipsoid["σx [m]"].astype(float).round(4)
standardellipsoid["σy [m]"] = standardellipsoid["σy [m]"].astype(float).round(4)
standardellipsoid["σz [m]"] = standardellipsoid["σz [m]"].astype(float).round(4)
standardellipsoid = pd.DataFrame(daten, columns=["Punkt", "σ̂x [m]", "σ̂y [m]", "σ̂z [m]", "Halbachse a [m]", "Halbachse b [m]", "Halbachse c [m]", "θ [gon]"])
standardellipsoid["σ̂x [m]"] = standardellipsoid["σ̂x [m]"].astype(float).round(4)
standardellipsoid["σ̂y [m]"] = standardellipsoid["σ̂y [m]"].astype(float).round(4)
standardellipsoid["σ̂z [m]"] = standardellipsoid["σ̂z [m]"].astype(float).round(4)
standardellipsoid["Halbachse a [m]"] = standardellipsoid["Halbachse a [m]"].astype(float).round(4)
standardellipsoid["Halbachse b [m]"] = standardellipsoid["Halbachse b [m]"].astype(float).round(4)
standardellipsoid["Halbachse c [m]"] = standardellipsoid["Halbachse c [m]"].astype(float).round(4)
@@ -207,23 +206,34 @@ class Genauigkeitsmaße:
@staticmethod
def konfidenzellipsoid(Qxx, s0_apost, unbekannten_liste, R, ausgabe_erfolgt):
def konfidenzellipsoid(Qxx: np.ndarray, sigma0_apost: float, unbekannten_liste: list, R: int, ausgabe_erfolgt: bool) -> tuple[pd.DataFrame, float]:
"""
Berechnet die Konfidenzellipse für Punkte aus Qxx und einem Konfidenzniveau.
Berechnet die Konfidenzellipsoid für Punkte aus Qxx und einem Konfidenzniveau.
Auf Basis der Kovarianz-Matrix der Unbekannten Qxx und der a-posteriori
Standardabweichung der Gewichtseinheit s₀ werden für jeden Punkt die Parameter
der Konfidenzellipse berechnet. Das Konfidenzniveau wird mittels einer Eingabe
über alpha gewählt (Standard: 0.05 für 95%).
Standardabweichung der Gewichtseinheit σ̂₀ werden für jeden Punkt die Parameter
des Konfidenzellipsoids berechnet. Das Konfidenzniveau wird mittels einer Eingabe
über alpha festgelegt (Standard: 0.05 für 95%).
Die Punktzuordnung erfolgt über die Symbolnamen der Unbekanntenliste (z.B. X1, Y1).
Für jeden Punkt wird die 3×3-Submatrix der Koordinaten (X, Y, Z) aus Qxx gebildet.
Über eine Eigenwertzerlegung dieser Submatrix werden die drei Hauptachsen des
Fehlerellipsoids bestimmt. Die Halbachsen des Konfidenzellipsoids ergeben sich aus:
- Aₖ: große Halbachse des Konfidenzellipsoids,
- Bₖ: mittlere Halbachse des Konfidenzellipsoids,
- Cₖ: kleine Halbachse des Konfidenzellipsoids,
unter Verwendung eines Faktors aus der F-Verteilung in Abhängigkeit vom
Konfidenzniveau und den Freiheitsgraden.
Die Punktzuordnung erfolgt über die Symbolnamen der Unbekanntenliste.
Optional wird die Tabelle ausgegeben und als Excel-Datei exportiert, abhängig von
ausgabe_erfolgt.
:param Qxx: Kofaktor-Matrix der geschätzten Unbekannten.
:type Qxx: numpy.ndarray
:param s0_apost: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:type s0_apost: float
:type Qxx: np.ndarray
:param sigma0_apost: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:type sigma0_apost: float
:param unbekannten_liste: Liste der Unbekannten.
:type unbekannten_liste: list
:param R: Redundanz (Freiheitsgrade) für die F-Verteilung.
@@ -232,7 +242,6 @@ class Genauigkeitsmaße:
:type ausgabe_erfolgt: bool
:return: Tabelle der Konfidenzellipse je Punkt, verwendetes alpha.
:rtype: tuple[pandas.DataFrame, float]
:raises ValueError: Wenn alpha nicht in (0, 1) liegt oder nicht in float umgewandelt werden kann.
"""
alpha_input = input("Irrtumswahrscheinlichkeit α wählen (z.B. 0.05, 0.01) [Standard=0.05]: ")
if alpha_input.strip() == "":
@@ -259,18 +268,18 @@ class Genauigkeitsmaße:
Q_sub = Qxx[np.ix_(indices, indices)]
# Standardabweichungen
sx = s0_apost * np.sqrt(Q_sub[0, 0])
sy = s0_apost * np.sqrt(Q_sub[1, 1])
sz = s0_apost * np.sqrt(Q_sub[2, 2])
sx = sigma0_apost * np.sqrt(Q_sub[0, 0])
sy = sigma0_apost * np.sqrt(Q_sub[1, 1])
sz = sigma0_apost * np.sqrt(Q_sub[2, 2])
# Eigenwertzerlegung
eigenwerte, eigenvektoren = np.linalg.eigh(Q_sub)
eigenwerte = np.sort(eigenwerte)[::-1]
# Halbachsen des Konfidenzellipoid
A_K = k * s0_apost * np.sqrt(eigenwerte[0])
B_K = k * s0_apost * np.sqrt(eigenwerte[1])
C_K = k * s0_apost * np.sqrt(eigenwerte[2])
A_K = k * sigma0_apost * np.sqrt(eigenwerte[0])
B_K = k * sigma0_apost * np.sqrt(eigenwerte[1])
C_K = k * sigma0_apost * np.sqrt(eigenwerte[2])
# Richtungswinkel theta in gon:
qyx = Q_sub[1, 0]
@@ -288,7 +297,7 @@ class Genauigkeitsmaße:
except:
continue
konfidenzellipoid = pd.DataFrame(daten, columns=["Punkt", "σx [m]", "σy [m]", "σz [m]", "Halbachse a_k [m]", "Halbachse b_k [m]", "Halbachse c_k [m]", "θ [gon]"])
konfidenzellipoid = pd.DataFrame(daten, columns=["Punkt", "σ̂x [m]", "σ̂y [m]", "σ̂z [m]", "Halbachse a_k [m]", "Halbachse b_k [m]", "Halbachse c_k [m]", "θ [gon]"])
if ausgabe_erfolgt == False:
display(HTML(konfidenzellipoid.to_html(index=False)))
konfidenzellipoid.to_excel(r"Netzqualitaet\Konfidenzellipoid.xlsx", index=False)
@@ -296,7 +305,7 @@ class Genauigkeitsmaße:
@staticmethod
def konfidenzellipsen_enu(a, b, ausgabe_parameterschaetzung, liste_unbekannte, ausgleichungsergebnis, s0apost, r_gesamt):
def konfidenzellipsen_enu(a: float, b: float, ausgabe_parameterschaetzung: dict, liste_unbekannte: list, ausgleichungsergebnis: dict, sigma0apost: float, r_gesamt: int) -> tuple[pd.DataFrame, np.ndarray]:
"""
Berechnet Konfidenzellipsen im lokalen ENU-System aus einer ins ENU-System transformierten Qxx-Matrix.
@@ -317,13 +326,12 @@ class Genauigkeitsmaße:
:type liste_unbekannte: list
:param ausgleichungsergebnis: Dictionary der geschätzten Punktkoordinaten (XYZ) zur ENU-Referenzbildung.
:type ausgleichungsergebnis: dict
:param s0apost: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:type s0apost: float
:param sigma0apost: a-posteriori Standardabweichung der Gewichtseinheit s₀.
:type sigma0apost: float
:param r_gesamt: Redundanz (Freiheitsgrade) für die Konfidenzberechnung.
:type r_gesamt: int
:return: Tabelle der Konfidenzellipse im ENU-System, Rotationsmatrix R0 der ENU-Transformation.
:rtype: tuple[pandas.DataFrame, numpy.ndarray]
:raises KeyError: Wenn ``ausgabe_parameterschaetzung`` keinen Eintrag ``"Q_xx"`` enthält.
"""
berechnungen = Berechnungen.Berechnungen(a, b)
@@ -342,7 +350,7 @@ class Genauigkeitsmaße:
# 2) Konfidenzellipoid im ENU-System
Konfidenzellipse_ENU, alpha = Genauigkeitsmaße.konfidenzellipsoid(
Qxx_enu,
s0apost,
sigma0apost,
liste_unbekannte,
r_gesamt,
ausgabe_erfolgt = True
@@ -350,16 +358,16 @@ class Genauigkeitsmaße:
# 3) Spaltennamen anpassen
Konfidenzellipse_ENU = Konfidenzellipse_ENU.rename(columns={
"σx [m]": "σE [m]",
"σy [m]": "σN [m]",
"σz [m]": "σU [m]",
"σ̂x [m]": "σ̂E [m]",
"σ̂y [m]": "σ̂N [m]",
"σ̂z [m]": "σ̂U [m]",
"θ [gon]": "θ_EN [gon]"
})
# 4) Runden und Anzeigen
Konfidenzellipse_ENU["σE [m]"] = Konfidenzellipse_ENU["σE [m]"].round(6)
Konfidenzellipse_ENU["σN [m]"] = Konfidenzellipse_ENU["σN [m]"].round(6)
Konfidenzellipse_ENU["σU [m]"] = Konfidenzellipse_ENU["σU [m]"].round(6)
Konfidenzellipse_ENU["σ̂E [m]"] = Konfidenzellipse_ENU["σ̂E [m]"].round(6)
Konfidenzellipse_ENU["σ̂N [m]"] = Konfidenzellipse_ENU["σ̂N [m]"].round(6)
Konfidenzellipse_ENU["σ̂U [m]"] = Konfidenzellipse_ENU["σ̂U [m]"].round(6)
Konfidenzellipse_ENU["Halbachse a_k [m]"] = Konfidenzellipse_ENU["Halbachse a_k [m]"].round(4)
Konfidenzellipse_ENU["Halbachse b_k [m]"] = Konfidenzellipse_ENU["Halbachse b_k [m]"].round(4)
Konfidenzellipse_ENU["Halbachse c_k [m]"] = Konfidenzellipse_ENU["Halbachse c_k [m]"].round(4)
@@ -390,15 +398,7 @@ class Plot:
"""
@staticmethod
def netzplot_ellipsen(
Koord_ENU,
unbekannten_labels,
beobachtungs_labels,
df_konf_ellipsen_enu,
skalierung,
n_ellipse_pts=60,
titel="Netzplot im ENU-System mit Konfidenzellipsen"
):
def netzplot_ellipsen(Koord_ENU: dict[str, tuple[float, float, float]], unbekannten_labels: list, beobachtungs_labels: list, df_konf_ellipsen_enu: pd.DataFrame, skalierung: float, n_ellipse_pts: int = 60, titel: str = "Netzplot im ENU-System mit Konfidenzellipsen") -> go.Figure:
"""
Erstellt einen Netzplot im ENU-System inklusive Konfidenzellipsen, Netzpunkten und Beobachtungslinien.
@@ -430,7 +430,6 @@ class Plot:
:type titel: str
:return: Plotly-Figure-Objekt mit Netz, Beobachtungen und Ellipsen.
:rtype: plotly.graph_objects.Figure
:raises ValueError: Wenn weder "θ_EN [gon]" noch "θ [gon]" im DataFrame vorhanden ist.
"""
namen = [str(s).strip() for s in unbekannten_labels]
@@ -546,7 +545,7 @@ class Plot:
return plot
def plot_speichere_aktuelle_ansicht(plot, dateiname=r"Netzqualitaet\netzplot_ellipsen_zoom_ansicht.png"):
def plot_speichere_aktuelle_ansicht(plot: go.Figure, dateiname: str = r"Netzqualitaet\netzplot_ellipsen_zoom_ansicht.png") -> None:
"""
Speichert die aktuell dargestellte Plot-Ansicht als Bilddatei.
@@ -564,7 +563,6 @@ class Plot:
:type dateiname: str
:return: None
:rtype: None
:raises OSError: Wenn die Bilddatei nicht geschrieben werden kann (z.B. fehlender Pfad oder fehlendes Kaleido).
"""
aktuelles_layout = plot.layout