Files
Masterprojekt_V3/Funktionales_Modell.py
2026-02-09 21:28:10 +01:00

999 lines
54 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import numpy as np
from numpy import ndarray, dtype
import sympy as sp
from sympy import MutableDenseMatrix
from sympy.matrices.expressions.matexpr import MatrixElement
from typing import Any
from Berechnungen import Berechnungen
from Datenbank import Datenbankzugriff
from Export import Export
from Koordinatentransformationen import Transformationen
class FunktionalesModell:
"""Aufstellung von Beobachtungsgleichungen und der Jacobi-Matrix.
Die Klasse stellt Methoden zur Verfügung für:
- symbolische Aufstellung der Jacobi-Matrix für Tachymeter-, GNSS- und Nivellementbeobachtungen,
- numerische Auswertung der symbolischen Jacobi-Matrix über Substitutionen und Lambdify,
- Aufbau des Beobachtungsvektors (numerisch) und des Näherungs-Beobachtungsvektors (symbolisch/numerisch),
- Aufbau des Unbekanntenvektors (symbolisch/numerisch) inklusive Iterationsfortschreibung,
- Berechnung des Verbesserungsvektors dl = l f(x0) mit Winkel-Normierung für Richtungen,
- Erstellung und Aktualisierung eines Substitutions-Dictionaries für alle im Modell verwendeten Symbole.
Die grundlegende Funktionsweise der Matrixdefinition lautet:
1) Einmaligen Aufbauen der Symbolischen Matrix einmalig
2) In jeder Iteration Substituieren der Symbolischen Matrizen in Numerische np.ndarray
"""
def __init__(self, pfad_datenbank: str, a: float, b: float, pfad_tif_quasigeoidundulation: str = None) -> None:
"""Initialisiert das funktionale Modell.
Legt die Ellipsoidparameter a und b fest, initialisiert Hilfsklassen (Berechnungen, Datenbankzugriff, Transformationen)
und erzeugt das Substitutions-Dictionary für das geozentrisch-kartesische System.
:param pfad_datenbank: Pfad zur SQLite-Datenbank.
:type pfad_datenbank: str
:param a: Große Halbachse a des Referenzellipsoids in Meter.
:type a: float
:param b: Kleine Halbachse b des Referenzellipsoids in Meter.
:type b: float
:param pfad_tif_quasigeoidundulation: Pfad zu Quasigeoidundulationsdaten als GeoTIFF vom BKG für Transformationen (optional).
:type pfad_tif_quasigeoidundulation: str | None
:return: None
:rtype: None
"""
self.pfad_datenbank = pfad_datenbank
self.a = a
self.b = b
self.berechnungen = Berechnungen(self.a, self.b)
self.db_zugriff = Datenbankzugriff(self.pfad_datenbank)
self.trafos = Transformationen(pfad_datenbank)
self.pfad_tif_quasigeoidundulation = pfad_tif_quasigeoidundulation
self.substitutionen_dict = self.dict_substitutionen_uebergeordnetes_system()
self.dict_punkt_symbole = {}
self.liste_symbole_lambdify = sorted(self.substitutionen_dict.keys(), key=lambda s: str(s))
self.func_beob0 = None
self.func_A0 = None
self.func_u0 = None
self.liste_beobachtungsvektor_symbolisch = None
def jacobi_matrix_symbolisch(self, datumsfestlegung: str = None, liste_unbekannte_datumsfestlegung: list = None) -> tuple[MutableDenseMatrix | MatrixElement | list[Any] | Any, list[Any], list[Any]] | None:
"""Erstellt die symbolische Jacobi-Matrix (A-Matrix) für die Ausgleichung.
Es werden die in der Datenbank vorhandenen Beobachtungen (Tachymeter: Distanz/Richtung/Zenitwinkel,
GNSS: Basislinienkomponenten bx/by/bz, Geometrisches Nivellement: dh) eingelesen, daraus die benötigten Unbekannten
(X, Y, Z je Punkt sowie Orientierungen O je Richtungs-Beobachtungsgruppe) aufgebaut und anschließend
die symbolischen Gleichungen zur Jacobi-Matrix zusammengesetzt.
Bei datumsfestlegung == "weiche Lagerung" werden Unbekannte so umsortiert, dass die zur Lagerung
zu verwendenden Unbekannten rechts stehen. Zusätzlich werden die Gleichungen der Anschlusspunkte (lA_*) als
Zusatzzeilen an A angehängt.
Die symbolische Jacobi-Matrix wird als CSV in Zwischenergebnisse\\Jacobi_Matrix_Symbolisch.csv exportiert.
:param datumsfestlegung: Art der Datumsfestlegung (aktuell nur "weiche Lagerung").
:type datumsfestlegung: str | None
:param liste_unbekannte_datumsfestlegung: Liste der Symbolnamen der zur Lagerung zu verwendenden Unbekannten (z. B. ["X100", "Y100", "Z100"]).
:type liste_unbekannte_datumsfestlegung: list | None
:return: Tupel aus symbolischer Jacobi-Matrix, Liste der Unbekannten (Symbole) und Liste der Zeilenbeschriftungen (Beobachtungskennungen). Falls keine Beobachtungen vorliegen: None.
:rtype: tuple[MutableDenseMatrix | MatrixElement | list[Any] | Any, list[Any], list[Any]] | None
"""
# Über die liste_beobachtungsarten wird festgelegt, welche Beobachtungsarten in der Ausgleichung verwendet werden.
liste_beobachtungsarten = ["tachymeter_distanz", "tachymeter_richtung", "tachymeter_zenitwinkel", "gnss_basislinien", "geometrisches_nivellement"]
# Initialisieren der zu befüllenden Listen
liste_beobachtungen_rohdaten_gnssbasislinien = []
liste_beobachtungen_rohdaten_tachymeter = []
liste_beobachtungen_rohdaten_nivellement = []
liste_punktnummern =[]
liste_orientierungsunbekannte = []
# Für jede Beobachtungsart wird aus der Datenbank abgefragt, welche Beobachtungen vorliegen. Von diesen werden der Stand- und Zielpunkt gespeichert, um diese im weiteren Verlauf dieser Methode zu verarbeiten.
for beobachtungsart in liste_beobachtungsarten:
#Tachymeter Block
if beobachtungsart.startswith("tachymeter"):
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_puntknummern_beobachtungen_tachymeter(beobachtungsart)
for beobachtungenID, beobachtungsgruppeID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
liste_beobachtungen_rohdaten_tachymeter.append(
(beobachtungsart, beobachtungenID, beobachtungsgruppeID, standpunkt, zielpunkt)
)
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
if beobachtungsart == "tachymeter_richtung":
if beobachtungsgruppeID not in liste_orientierungsunbekannte:
liste_orientierungsunbekannte.append(beobachtungsgruppeID)
#GNSS Block
if beobachtungsart == "gnss_basislinien":
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_bx")
for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
standpunkt = str(standpunkt).strip()
zielpunkt = str(zielpunkt).strip()
liste_beobachtungen_rohdaten_gnssbasislinien.append(("gnssbx", beobachtungenID, standpunkt, zielpunkt))
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_by")
for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
standpunkt = str(standpunkt).strip()
zielpunkt = str(zielpunkt).strip()
liste_beobachtungen_rohdaten_gnssbasislinien.append(("gnssby", beobachtungenID, standpunkt, zielpunkt))
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_bz")
for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
standpunkt = str(standpunkt).strip()
zielpunkt = str(zielpunkt).strip()
liste_beobachtungen_rohdaten_gnssbasislinien.append(("gnssbz", beobachtungenID, standpunkt, zielpunkt))
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
if beobachtungsart == "geometrisches_nivellement":
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_nivellement_beobachtungen_punktnummern()
for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
standpunkt = str(standpunkt).strip()
zielpunkt = str(zielpunkt).strip()
liste_beobachtungen_rohdaten_nivellement.append(
(beobachtungsart, beobachtungenID, standpunkt, zielpunkt))
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
# Erstellen der Symbole für die Unbekannten (X, Y, Z und Orientierung)
liste_unbekannte = []
for punkt in liste_punktnummern:
X, Y, Z = sp.symbols(f"X{punkt} Y{punkt} Z{punkt}")
self.dict_punkt_symbole[punkt] = (X, Y, Z)
liste_unbekannte.append(X)
liste_unbekannte.append(Y)
liste_unbekannte.append(Z)
dict_orientierung_symbole = {}
for orientierungsunbekannte in liste_orientierungsunbekannte:
O = sp.symbols(f"O{orientierungsunbekannte}")
dict_orientierung_symbole[orientierungsunbekannte] = O
liste_unbekannte.append(O)
# Erstellen der Symbolischen Gleichungen für die Jacobimatrix
liste_beobachtungsgleichungen_distanz =[]
liste_zeilenbeschriftungen_distanz = []
liste_A_richtung_zeilen = []
liste_zeilenbeschriftungen_richtung = []
liste_A_zenitwinkel_zeilen = []
liste_zeilenbeschriftungen_zenitwinkel = []
liste_beobachtungsgleichungen_gnssbasislinien = []
liste_zeilenbeschriftungen_gnssbasislinien = []
liste_A_nivellement_zeilen = []
liste_zeilenbeschriftungen_nivellement = []
if liste_beobachtungen_rohdaten_tachymeter != []:
for beobachtungsart, beobachtungenID, beobachtungsgruppeID, standpunkt, zielpunkt in liste_beobachtungen_rohdaten_tachymeter:
# Symbole erstellen
X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
B_sp, L_sp = sp.symbols(f"B{standpunkt} L{standpunkt}")
azimut_berechnet = sp.symbols(f"azimut_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
zw_berechnet = sp.symbols(f"zw_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
s_berechnet = sp.symbols(f"strecke_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
# Symbolische Gleichungen aufstellen
if beobachtungsart == "tachymeter_distanz":
beobachtungsgleichung = sp.sqrt((X_zp - X_sp) ** 2 + (Y_zp - Y_sp) ** 2 + (Z_zp - Z_sp) ** 2)
liste_beobachtungsgleichungen_distanz.append(beobachtungsgleichung)
liste_zeilenbeschriftungen_distanz.append(
f"{beobachtungenID}_SD_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
elif beobachtungsart == "tachymeter_richtung":
d_r_dX_zp = (
(sp.sin(B_sp) * sp.cos(L_sp) * sp.sin(azimut_berechnet) - sp.sin(L_sp) * sp.cos(azimut_berechnet)) / (
s_berechnet * sp.sin(zw_berechnet)))
d_r_dX_sp = - d_r_dX_zp
d_r_dY_zp = (
(sp.sin(B_sp) * sp.sin(L_sp) * sp.sin(azimut_berechnet) + sp.cos(L_sp) * sp.cos(azimut_berechnet)) / (
s_berechnet * sp.sin(zw_berechnet)))
d_r_dY_sp = - d_r_dY_zp
d_r_dZ_zp = ((-sp.cos(B_sp) * sp.sin(azimut_berechnet) / (s_berechnet * sp.sin(zw_berechnet))))
d_r_dZ_sp = - d_r_dZ_zp
d_r_dO_sp = -1
zeile_A_Matrix = []
# Symbolische Gleichungen zur Jacobimatrix hinzufügen
for punkt in liste_punktnummern:
if punkt == standpunkt:
zeile_A_Matrix.extend([d_r_dX_sp, d_r_dY_sp, d_r_dZ_sp])
elif punkt == zielpunkt:
zeile_A_Matrix.extend([d_r_dX_zp, d_r_dY_zp, d_r_dZ_zp])
else:
zeile_A_Matrix.extend([0, 0, 0])
for orientierung in liste_orientierungsunbekannte:
if orientierung == beobachtungsgruppeID:
zeile_A_Matrix.append(d_r_dO_sp)
else:
zeile_A_Matrix.append(0)
liste_A_richtung_zeilen.append(zeile_A_Matrix)
liste_zeilenbeschriftungen_richtung.append(
f"{beobachtungenID}_R_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}"
)
elif beobachtungsart == "tachymeter_zenitwinkel":
# Symbolische Gleichungen aufstellen
d_r_dX_zp = ((X_zp - X_sp) * sp.cos(zw_berechnet) - s_berechnet * sp.cos(B_sp) * sp.cos(L_sp)) / (s_berechnet ** 2 * sp.sin(zw_berechnet))
d_r_dX_sp = - d_r_dX_zp
d_r_dY_zp = ((Y_zp - Y_sp) * sp.cos(zw_berechnet) - s_berechnet * sp.cos(B_sp) * sp.sin(L_sp)) / (s_berechnet ** 2 * sp.sin(zw_berechnet))
d_r_dY_sp = - d_r_dY_zp
d_r_dZ_zp = ((Z_zp - Z_sp) * sp.cos(zw_berechnet) - s_berechnet * sp.sin(B_sp)) / (s_berechnet ** 2 * sp.sin(zw_berechnet))
d_r_dZ_sp = - d_r_dZ_zp
zeile_A_Matrix = []
# Symbolische Gleichungen zur Jacobimatrix hinzufügen
for punkt in liste_punktnummern:
if punkt == standpunkt:
zeile_A_Matrix.extend([d_r_dX_sp, d_r_dY_sp, d_r_dZ_sp])
elif punkt == zielpunkt:
zeile_A_Matrix.extend([d_r_dX_zp, d_r_dY_zp, d_r_dZ_zp])
else:
zeile_A_Matrix.extend([0, 0, 0])
for orientierung in liste_orientierungsunbekannte:
zeile_A_Matrix.append(0)
liste_A_zenitwinkel_zeilen.append(zeile_A_Matrix)
liste_zeilenbeschriftungen_zenitwinkel.append(
f"{beobachtungenID}_ZW_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}"
)
# GNSS-Basislinien
if liste_beobachtungen_rohdaten_gnssbasislinien != []:
for beobachtungsart, beobachtungenID, standpunkt, zielpunkt in liste_beobachtungen_rohdaten_gnssbasislinien:
# Symbolische Gleichungen aufstellen
X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
if beobachtungsart == "gnssbx":
beobachtungsgleichung_bx = X_zp - X_sp
liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_bx)
liste_zeilenbeschriftungen_gnssbasislinien.append(
f"{beobachtungenID}_gnssbx_{standpunkt}_{zielpunkt}")
if beobachtungsart == "gnssby":
beobachtungsgleichung_by = Y_zp - Y_sp
liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_by)
liste_zeilenbeschriftungen_gnssbasislinien.append(
f"{beobachtungenID}_gnssby_{standpunkt}_{zielpunkt}")
if beobachtungsart == "gnssbz":
beobachtungsgleichung_bz = Z_zp - Z_sp
liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_bz)
liste_zeilenbeschriftungen_gnssbasislinien.append(
f"{beobachtungenID}_gnssbz_{standpunkt}_{zielpunkt}")
# Geometrisches Nivellement
if liste_beobachtungen_rohdaten_nivellement != []:
for beobachtungsart, beobachtungenID, standpunkt, zielpunkt in liste_beobachtungen_rohdaten_nivellement:
# Symbolische Gleichungen aufstellen
B_sp, L_sp = sp.symbols(f"B{standpunkt} L{standpunkt}")
B_zp, L_zp = sp.symbols(f"B{zielpunkt} L{zielpunkt}")
if beobachtungsart == "geometrisches_nivellement":
d_r_dX_zp = sp.cos(B_zp) * sp.cos(L_zp)
d_r_dX_sp = -sp.cos(B_sp) * sp.cos(L_sp)
d_r_dY_zp = sp.cos(B_zp) * sp.sin(L_zp)
d_r_dY_sp = -sp.cos(B_sp) * sp.sin(L_sp)
d_r_dZ_zp = sp.sin(B_zp)
d_r_dZ_sp = -sp.sin(B_sp)
# Symbolische Gleichungen zur Jacobimatrix hinzufügen
zeile_A_Matrix = []
for punkt in liste_punktnummern:
if punkt == standpunkt:
zeile_A_Matrix.extend([d_r_dX_sp, d_r_dY_sp, d_r_dZ_sp])
elif punkt == zielpunkt:
zeile_A_Matrix.extend([d_r_dX_zp, d_r_dY_zp, d_r_dZ_zp])
else:
zeile_A_Matrix.extend([0, 0, 0])
for orientierung in liste_orientierungsunbekannte:
zeile_A_Matrix.append(0)
liste_A_nivellement_zeilen.append(zeile_A_Matrix)
liste_zeilenbeschriftungen_nivellement.append(
f"{beobachtungenID}_niv_{standpunkt}_{zielpunkt}"
)
# Jacobimatrix aus den einzelnen Listen zusammensetzen, Sy,bolischen Unbekanntenvektor erstellen
if liste_beobachtungsgleichungen_distanz:
f_matrix_dist = sp.Matrix(liste_beobachtungsgleichungen_distanz)
unbekanntenvektor = sp.Matrix(liste_unbekannte)
A_dist = f_matrix_dist.jacobian(unbekanntenvektor)
else:
A_dist = None
if liste_A_richtung_zeilen:
A_richtung = sp.Matrix(liste_A_richtung_zeilen)
else:
A_richtung = None
if liste_A_zenitwinkel_zeilen:
A_zenitwinkel = sp.Matrix(liste_A_zenitwinkel_zeilen)
else:
A_zenitwinkel = None
if liste_beobachtungsgleichungen_gnssbasislinien:
f_matrix_gnss = sp.Matrix(liste_beobachtungsgleichungen_gnssbasislinien)
unbekanntenvektor = sp.Matrix(liste_unbekannte)
A_gnssbasislinien = f_matrix_gnss.jacobian(unbekanntenvektor)
else:
A_gnssbasislinien = None
if liste_A_nivellement_zeilen:
A_nivellement = sp.Matrix(liste_A_nivellement_zeilen)
else:
A_nivellement = None
A_gesamt = None
# liste_zeilenbeschriftungen_gesamt enthält die Symbolischen Beobachtungen
liste_zeilenbeschriftungen_gesamt = []
if A_dist is not None:
A_gesamt = A_dist
liste_zeilenbeschriftungen_gesamt.extend(liste_zeilenbeschriftungen_distanz)
if A_richtung is not None:
if A_gesamt is None:
A_gesamt = A_richtung
else:
A_gesamt = A_gesamt.col_join(A_richtung)
liste_zeilenbeschriftungen_gesamt.extend(liste_zeilenbeschriftungen_richtung)
if A_zenitwinkel is not None:
if A_gesamt is None:
A_gesamt = A_zenitwinkel
else:
A_gesamt = A_gesamt.col_join(A_zenitwinkel)
liste_zeilenbeschriftungen_gesamt.extend(liste_zeilenbeschriftungen_zenitwinkel)
if A_gnssbasislinien is not None:
if A_gesamt is None:
A_gesamt = A_gnssbasislinien
else:
A_gesamt = A_gesamt.col_join(A_gnssbasislinien)
liste_zeilenbeschriftungen_gesamt.extend(liste_zeilenbeschriftungen_gnssbasislinien)
if A_nivellement is not None:
if A_gesamt is None:
A_gesamt = A_nivellement
else:
A_gesamt = A_gesamt.col_join(A_nivellement)
liste_zeilenbeschriftungen_gesamt.extend(liste_zeilenbeschriftungen_nivellement)
if A_gesamt is None:
return None
# Wenn eine weiche Lagerung erfolgt, werden die Unbekannten umsortiert, sodass die für die Lagerung zu verwendenden Unbekannten rechts in der Matrix aufgeführt werden.
# Zudem werden für die Anschlusspunkte weiter Gleichungen als "Beobachtungen" unten an die Jacobimatrix angefügt.
if datumsfestlegung == "weiche Lagerung":
if liste_unbekannte_datumsfestlegung is not None and liste_unbekannte_datumsfestlegung != []:
liste_unbekannte_alt = list(liste_unbekannte)
liste_unbekannte_datumsfestlegung = [str(u).strip() for u in liste_unbekannte_datumsfestlegung]
idx_rechts = []
for name in liste_unbekannte_datumsfestlegung:
for i, sym in enumerate(liste_unbekannte_alt):
if str(sym) == name and i not in idx_rechts:
idx_rechts.append(i)
break
idx_links = [i for i in range(len(liste_unbekannte_alt)) if i not in idx_rechts]
vertauschung = idx_links + idx_rechts
A_gesamt = A_gesamt[:, vertauschung]
liste_unbekannte = [liste_unbekannte_alt[i] for i in vertauschung]
# Zusatzgeleichungen der weichen Lagerung für die Anschlusspunkte
anzhl_einheitsmatrix = len(liste_unbekannte_datumsfestlegung)
if anzhl_einheitsmatrix > 0:
nullenmatrix = sp.zeros(anzhl_einheitsmatrix, A_gesamt.shape[1] - anzhl_einheitsmatrix)
einheitsmatrix = sp.eye(anzhl_einheitsmatrix)
A_weiche_Lagerung = nullenmatrix.row_join(einheitsmatrix)
A_gesamt = A_gesamt.col_join(A_weiche_Lagerung)
for unbekannte_datumsfestlegung in liste_unbekannte_datumsfestlegung:
liste_zeilenbeschriftungen_gesamt.append(f"lA_{unbekannte_datumsfestlegung}")
# Symbolische Liste der Unbekannten speichern
self.liste_unbekanntenvektor_symbolisch = liste_unbekannte
# Symbolische Jacobimatrix speichern
Export.matrix_to_csv(r"Zwischenergebnisse\Jacobi_Matrix_Symbolisch.csv", liste_unbekannte,
liste_zeilenbeschriftungen_gesamt, A_gesamt, "Beobachtung")
return A_gesamt, liste_unbekannte, liste_zeilenbeschriftungen_gesamt
def jacobi_matrix_numerisch(self, A_symbolisch: sp.Matrix, koordinatenart: str,
liste_unbekannte: list = None,
liste_zeilenbeschriftungen_gesamt: list = None,
iterationsnummer: int = 0) -> ndarray[tuple[Any, ...], dtype[Any]] | None:
"""Erstellt eine numerische Matrix aus einer symbolischen Jacobi-Matrix.
Es wird sympy.lambdify verwendet, um die symbolische Matrix
mit den aktuellen Substitutionen effizient als Numpy-Array auszuwerten. Die Lambdify-Funktion wird
gecached (self.func_A0), um Rechenzeit bei Ausführen mehrerer Iterationen zu sparen.
Die numerische Jacobi-Matrix wird als CSV in den Ordner Zwischenergebnisse exportiert.
:param A_symbolisch: Symbolische Jacobi-Matrix.
:type A_symbolisch: sp.Matrix
:param koordinatenart: Bezeichnung der Koordinatenart (aktuell implementiert: "naeherung_us").
:type koordinatenart: str
:param liste_unbekannte: Liste der Unbekannten (Symbole) in der Spaltenreihenfolge.
:type liste_unbekannte: list | None
:param liste_zeilenbeschriftungen_gesamt: Liste der Zeilenbeschriftungen (Beobachtungskennungen).
:type liste_zeilenbeschriftungen_gesamt: list | None
:param iterationsnummer: Iterationsnummer für Dateinamen der Zwischenergebnisse.
:type iterationsnummer: int
:return: Numerische Jacobi-Matrix als Numpy-Array.
:rtype: ndarray[tuple[Any, ...], dtype[Any]] | None
:raises ValueError: Falls Symbole in A_symbolisch enthalten sind, für die keine Substitutionen vorhanden sind.
"""
# Symbolischen Beobachtungsvektor als Instanzvariable speichern
self.liste_beobachtungsvektor_symbolisch = [str(x) for x in liste_zeilenbeschriftungen_gesamt]
# Wenn es sich um geozentrisch-kartesischen Koordinaten handelt, wird die Sympy-Methode Lambdify verwendet, um die Symbole aus der vorherigen Methode jacobi_matrix_symbolisch in Numerische Zahlen umzuwandeln.
# Zur Ersparnis von Rechenzeit werden die numerischen Zahlen als Numpy-Werte behandelt.
if koordinatenart == "naeherung_us":
if self.func_A0 is None:
self.func_A0 = sp.lambdify(
self.liste_symbole_lambdify,
A_symbolisch,
modules="numpy",
cse=True
)
# Überprüfung, ob alle in der Symbolischen Matrix enthaltenen Symbole substituiert werden können. Ist ein Symbol nicht durch einen numerischen Wert ersetzbar, wird eine Fehlermeldung ausgegeben.
fehlend = [s for s in self.liste_symbole_lambdify if s not in self.substitutionen_dict]
if fehlend:
raise ValueError(f"Fehlende Substitutionen in A: {[str(s) for s in fehlend[:30]]}")
liste_werte = [self.substitutionen_dict[s] for s in self.liste_symbole_lambdify]
A_numerisch = np.asarray(self.func_A0(*liste_werte), dtype=float)
Export.matrix_to_csv(fr"Zwischenergebnisse\{iterationsnummer}Jacobi_Matrix_Numerisch.csv", liste_unbekannte,
liste_zeilenbeschriftungen_gesamt, A_numerisch, "Beobachtung")
return A_numerisch
else:
print(f"Die Koordinatenart {koordinatenart} ist noch nicht im Programm implementiert!")
def beobachtungsvektor_numerisch(self, liste_beobachtungsvektor_symbolisch: list) -> MutableDenseMatrix:
"""Erstellt den numerischen Beobachtungsvektor aus symbolischen Beobachtungskennungen.
Die Einträge des symbolischen Beobachtungsvektors werden über self.substitutionen_dict substituiert.
Anschlusspunkte der weichen Lagerung (lA_*) werden gesondert behandelt, indem das Präfix entfernt wird.
Der numerische Beobachtungsvektor wird als CSV-Datei in Zwischenergebnisse\\Beobachtungsvektor_Numerisch.csv exportiert.
:param liste_beobachtungsvektor_symbolisch: Liste symbolischer Beobachtungsbezeichnungen (Strings).
:type liste_beobachtungsvektor_symbolisch: list
:return: Numerischer Beobachtungsvektor als SymPy-Matrix (Spaltenvektor).
:rtype: MutableDenseMatrix
"""
liste_beobachtungsvektor_numerisch = []
for beobachtung_symbolisch in liste_beobachtungsvektor_symbolisch:
beobachtung_symbolisch = str(beobachtung_symbolisch).strip()
# Die Anschlusspunkte für die weiche Lagerung (lA) werden gesondert bearbeitet, weil die Symbole anders aufgebaut sind.
if beobachtung_symbolisch.startswith("lA_"):
beobachtung_symbolisch = str(beobachtung_symbolisch.split("_", 1)[1]).strip()
# Substituieren des symbolischen Beobachtungsvektors
liste_beobachtungsvektor_numerisch.append(self.substitutionen_dict[sp.Symbol(beobachtung_symbolisch)])
beobachtungsvektor_numerisch = sp.Matrix(liste_beobachtungsvektor_numerisch)
Export.matrix_to_csv(r"Zwischenergebnisse\Beobachtungsvektor_Numerisch.csv", [""], liste_beobachtungsvektor_symbolisch, beobachtungsvektor_numerisch, "Beobachtungsvektor")
return beobachtungsvektor_numerisch
def beobachtungsvektor_naeherung_symbolisch(self, liste_beobachtungsvektor_symbolisch: list) -> sp.Matrix:
"""Erstellt den symbolischen Näherungs-Beobachtungsvektor f(x0).
Aus den Beobachtungskennungen werden Stand-/Zielpunkte und Beobachtungsarten abgeleitet und die
entsprechenden symbolischen Beobachtungsgleichungen aufgebaut (z. B. geometrische Distanz, GNSS-Differenzen,
Richtungs-/Zenitwinkel-Symbole, Geometrisches Nivellement über Normalhöhen).
Der symbolische Näherungs-Beobachtungsvektor wird als CSV <-Datei in Zwischenergebnisse\\Beobachtungsvektor_Näherung_Symbolisch.csv exportiert.
:param liste_beobachtungsvektor_symbolisch: Liste symbolischer Beobachtungskennungen (Strings).
:type liste_beobachtungsvektor_symbolisch: list
:return: Symbolischer Näherungs-Beobachtungsvektor als SymPy-Matrix.
:rtype: sp.Matrix
"""
liste_beobachtungsgleichungen = []
self.dict_punkt_symbole = {}
liste_punktnummern = []
# Speichern der Punktnummern der Stand- und Zeilpunkte der Beobachtungen, um daraus später die Symbole für die Unbekannten zu erstellen.
for beobachtung_symbolisch in liste_beobachtungsvektor_symbolisch:
aufgeteilt = str(beobachtung_symbolisch).strip().split("_")
if aufgeteilt[0] == "lA":
continue
if aufgeteilt [1] == "SD" or aufgeteilt [1] == "R" or aufgeteilt [1] == "ZW":
standpunkt = str(aufgeteilt[3])
zielpunkt = str(aufgeteilt[4])
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
if aufgeteilt[1] == "gnssbx" or aufgeteilt[1] == "gnssby" or aufgeteilt[1] == "gnssbz":
standpunkt = str(aufgeteilt[2])
zielpunkt = str(aufgeteilt[3])
if standpunkt not in liste_punktnummern:
liste_punktnummern.append(standpunkt)
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
# Erstellen der Symbole für die Unbekannten
for punkt in liste_punktnummern:
X, Y, Z = sp.symbols(f"X{punkt} Y{punkt} Z{punkt}")
self.dict_punkt_symbole[str(punkt)] = (X, Y, Z)
for beobachtung_symbolisch in liste_beobachtungsvektor_symbolisch:
beobachtung_symbolisch = str(beobachtung_symbolisch).strip()
aufgeteilt = beobachtung_symbolisch.split("_")
if aufgeteilt[0] == "lA":
anschlusspunkt = str(aufgeteilt[1])
liste_beobachtungsgleichungen.append(sp.Symbol(anschlusspunkt))
continue
if aufgeteilt[1] == "SD" or aufgeteilt[1] == "R" or aufgeteilt[1] == "ZW":
beobachtungsart = aufgeteilt[1] # "SD", "R", "ZW"
beobachtungsgruppeID = aufgeteilt[2]
standpunkt = str(aufgeteilt[3]).strip()
zielpunkt = str(aufgeteilt[4]).strip()
# Hinzufügen der Symbole zum dict_punkt_symbole als Vorbereitung auf die spätere Substitution der Symbole durch numerische Werte
X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
# Aufstellen der Symbolischen Gleichungen
dX = X_zp - X_sp
dY = Y_zp - Y_sp
dZ = Z_zp - Z_sp
if beobachtungsart == "SD":
s_geom = sp.sqrt(dX ** 2 + dY ** 2 + dZ ** 2)
liste_beobachtungsgleichungen.append(s_geom)
elif beobachtungsart == "R":
r_sp_zp = sp.Symbol(f"richtung_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
liste_beobachtungsgleichungen.append(r_sp_zp)
elif beobachtungsart == "ZW":
zw_sp_zp = sp.Symbol(f"zw_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
liste_beobachtungsgleichungen.append(zw_sp_zp)
if aufgeteilt[1] == "gnssbx" or aufgeteilt[1] == "gnssby" or aufgeteilt[1] == "gnssbz":
beobachtungsart = aufgeteilt[1]
standpunkt = str(aufgeteilt[2]).strip()
zielpunkt = str(aufgeteilt[3]).strip()
X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
dX = X_zp - X_sp
dY = Y_zp - Y_sp
dZ = Z_zp - Z_sp
if beobachtungsart == "gnssbx":
liste_beobachtungsgleichungen.append(dX)
if beobachtungsart == "gnssby":
liste_beobachtungsgleichungen.append(dY)
if beobachtungsart == "gnssbz":
liste_beobachtungsgleichungen.append(dZ)
if aufgeteilt[1] == "niv":
standpunkt = str(aufgeteilt[2]).strip()
zielpunkt = str(aufgeteilt[3]).strip()
nh_sp = sp.Symbol(f"NH{standpunkt}")
nh_zp = sp.Symbol(f"NH{zielpunkt}")
niv_sp_zp = nh_zp - nh_sp
liste_beobachtungsgleichungen.append(niv_sp_zp)
# Finalisieren des Symbolischen Beobachtungsvektors und exportieren als csv-Datei.
beobachtungsvektor_naeherung_symbolisch = sp.Matrix(liste_beobachtungsgleichungen)
Export.matrix_to_csv(r"Zwischenergebnisse\Beobachtungsvektor_Näherung_Symbolisch.csv", [""],
liste_beobachtungsvektor_symbolisch, beobachtungsvektor_naeherung_symbolisch, "Beobachtungsvektor")
return beobachtungsvektor_naeherung_symbolisch
def beobachtungsvektor_naeherung_numerisch(self, liste_beobachtungsvektor_symbolisch: list,
beobachtungsvektor_naeherung_symbolisch: sp.Matrix,
iterationsnummer: int = 0) -> ndarray[tuple[int, int], Any]:
"""Erstellt einen numerischen Vektor aus dem smbolischen Näherungs-Beobachtungsvektor.
Es wird sympy.lambdify verwendet, um den in beobachtungsvektor_naeherung_symbolisch erzeugten
symbolischen Vektor effizient als Numpy-Array auszuwerten. Die Lambdify-Funktion wird gecached
(self.func_beob0), um Rechenzeit in Iterationen zu sparen.
Der numerische Näherungs-Beobachtungsvektor wird als CSV-Datei im Ordner Zwischenergebnisse exportiert.
:param liste_beobachtungsvektor_symbolisch: Liste symbolischer Beobachtungskennungen (Strings).
:type liste_beobachtungsvektor_symbolisch: list
:param beobachtungsvektor_naeherung_symbolisch: Symbolischer Näherungs-Beobachtungsvektor f(x0).
:type beobachtungsvektor_naeherung_symbolisch: sp.Matrix
:param iterationsnummer: Iterationsnummer für Dateinamen der Zwischenergebnisse.
:type iterationsnummer: int
:return: Numerischer Näherungs-Beobachtungsvektor als Numpy-Array (Spaltenvektor).
:rtype: ndarray[tuple[int, int], Any]
"""
# Es wird die Sympy-Methode Lambdify verwendet, um die Symbole aus der vorherigen Methode beobachtungsvektor_naeherung_symbolisch in Numerische Zahlen umzuwandeln.
# Zur Ersparnis von Rechenzeit werden die numerischen Zahlen als Numpy-Werte behandelt.
if self.func_beob0 is None:
self.func_beob0 = sp.lambdify(
self.liste_symbole_lambdify,
beobachtungsvektor_naeherung_symbolisch,
modules="numpy",
cse=True
)
liste_werte = [self.substitutionen_dict[s] for s in self.liste_symbole_lambdify]
beobachtungsvektor_naeherung_numerisch = np.asarray(self.func_beob0(*liste_werte),
dtype=float).reshape(-1, 1)
Export.matrix_to_csv(fr"Zwischenergebnisse\{iterationsnummer}_Beobachtungsvektor_Näherung_Numerisch_Iteration0.csv", [""],
liste_beobachtungsvektor_symbolisch, beobachtungsvektor_naeherung_numerisch,
"Beobachtungsvektor")
return beobachtungsvektor_naeherung_numerisch
def unbekanntenvektor_symbolisch(self, liste_unbekannte: list) -> sp.Matrix:
"""Erstellt den symbolischen Unbekanntenvektor.
Der Unbekanntenvektor wird als SymPy-Matrix aufgebaut und als CSV-Datei in
Zwischenergebnisse\\Unbekanntenvektor_Symbolisch.csv exportiert.
:param liste_unbekannte: Liste der Unbekannten (Symbole).
:type liste_unbekannte: list
:return: Symbolischer Unbekanntenvektor als SymPy-Matrix.
:rtype: sp.Matrix
"""
unbekanntenvektor_symbolisch = sp.Matrix(liste_unbekannte)
Export.matrix_to_csv(r"Zwischenergebnisse\Unbekanntenvektor_Symbolisch.csv", [""], liste_unbekannte, unbekanntenvektor_symbolisch,
"Unbekanntenvektor")
return(unbekanntenvektor_symbolisch)
def unbekanntenvektor_numerisch(self, liste_unbekanntenvektor_symbolisch: list,
unbekanntenvektor_symbolisch: sp.Matrix,
dX_Vektor: np.ndarray = None,
unbekanntenvektor_numerisch_vorherige_Iteration: np.ndarray = None,
iterationsnummer: int = 0) -> ndarray[tuple[int, int], Any] | ndarray[tuple[Any, ...], dtype[Any]]:
"""Erstellt den numerischen Unbekanntenvektor jeder Iteration.
Wenn keine Iterationsfortschreibung übergeben wird (dX_Vektor und unbekanntenvektor_numerisch_vorherige_Iteration sind None),
werden die aktuellen Substitutionen genutzt und daraus der numerische Unbekanntenvektor aufgebaut.
Wenn dX_Vektor und ein Unbekanntenvektor der vorherigen Iteration übergeben werden, wird der neue
Unbekanntenvektor aus der Summe gebildet: x_neu = x_alt + dX.
Anschließend wird self.substitutionen_dict auf Basis des neuen Unbekanntenvektors aktualisiert.
Der numerische Unbekanntenvektor wird als CSV-Datei in den Ordner Zwischenergebnisse exportiert.
:param liste_unbekanntenvektor_symbolisch: Liste der Unbekannten (Symbole) in der Reihenfolge des numerischen Vektors.
:type liste_unbekanntenvektor_symbolisch: list
:param unbekanntenvektor_symbolisch: Symbolischer Unbekanntenvektor.
:type unbekanntenvektor_symbolisch: sp.Matrix
:param dX_Vektor: Verbesserungsvektor der aktuellen Iteration (optional).
:type dX_Vektor: np.ndarray | None
:param unbekanntenvektor_numerisch_vorherige_Iteration: Numerischer Unbekanntenvektor der vorherigen Iteration (optional).
:type unbekanntenvektor_numerisch_vorherige_Iteration: np.ndarray | None
:param iterationsnummer: Iterationsnummer für Dateinamen der Zwischenergebnisse.
:type iterationsnummer: int
:return: Numerischer Unbekanntenvektor als Numpy-Array
:rtype: ndarray[tuple[int, int], Any] | ndarray[tuple[Any, ...], dtype[Any]]
"""
self.liste_unbekanntenvektor_symbolisch = liste_unbekanntenvektor_symbolisch
# Überprüfung, ob dX und der unbekanntenvektor aus der vorhigen Iteration übergeben wurden. Wenn ja, wird daraus der neue unbekanntenvektor nach der Iteration berechnet.
if dX_Vektor is None and unbekanntenvektor_numerisch_vorherige_Iteration is None:
unbekanntenvektor_numerisch = np.asarray(
[[float(self.substitutionen_dict[sym])] for sym in self.liste_unbekanntenvektor_symbolisch],
dtype=float
).reshape(-1, 1)
else:
unbekanntenvektor_numerisch_vorherige_Iteration = np.asarray(
unbekanntenvektor_numerisch_vorherige_Iteration, dtype=float).reshape(-1, 1)
dX_Vektor = np.asarray(dX_Vektor, dtype=float).reshape(-1, 1)
unbekanntenvektor_numerisch = unbekanntenvektor_numerisch_vorherige_Iteration + dX_Vektor
# Aktualisieren des Dictionaries für die Subsitutionen in den anderen Methoden.
self.substitutionen_dict = self.dict_substitutionen_uebergeordnetes_system(unbekanntenvektor_numerisch)
Export.matrix_to_csv(fr"Zwischenergebnisse\{iterationsnummer}_Unbekanntenvektor_Numerisch.csv", [""],
liste_unbekanntenvektor_symbolisch, unbekanntenvektor_numerisch,
"Unbekanntenvektor")
return unbekanntenvektor_numerisch
def unbekanntenvektor_numerisch_to_dict_unbekanntenvektor(self, liste_unbekanntenvektor_symbolisch: list, unbekanntenvektor_numerisch: np.ndarray) -> dict:
"""Wandelt einen numerischen Unbekanntenvektor in ein Koordinatendictionary um.
Aus dem numerischen Unbekanntenvektor werden für alle Punkte die Koordinaten (X, Y, Z) extrahiert
und als sp.Matrix([X, Y, Z]) in einem Dictionary gespeichert.
:param liste_unbekanntenvektor_symbolisch: Liste der Unbekannten (Symbole) in der Reihenfolge des numerischen Vektors.
:type liste_unbekanntenvektor_symbolisch: list
:param unbekanntenvektor_numerisch: Numerischer Unbekanntenvektor.
:type unbekanntenvektor_numerisch: np.ndarray
:return: Dictionary {punktnummer: sp.Matrix([X, Y, Z])}.
:rtype: dict
"""
unbekanntenvektor_numerisch = np.asarray(unbekanntenvektor_numerisch, dtype=float).reshape(-1, 1)
idx = {str(sym): i for i, sym in enumerate(liste_unbekanntenvektor_symbolisch)}
punktnummern = []
for symbol in liste_unbekanntenvektor_symbolisch:
name = str(symbol)
if name.startswith("X"):
pn = name[1:]
if pn not in punktnummern:
punktnummern.append(pn)
# Annahme: Für jeden Punkt, für den eine X-Koordinate vorliegt, gibt es auch immer zwingend eine Y- und Z-Koordinate
dict_koordinaten = {}
for pn in punktnummern:
iX = idx.get(f"X{pn}", None)
iY = idx.get(f"Y{pn}", None)
iZ = idx.get(f"Z{pn}", None)
if iX is None or iY is None or iZ is None:
continue
dict_koordinaten[pn] = sp.Matrix([
float(unbekanntenvektor_numerisch[iX, 0]),
float(unbekanntenvektor_numerisch[iY, 0]),
float(unbekanntenvektor_numerisch[iZ, 0]),
])
return dict_koordinaten
def berechnung_dl(self, beobachtungsvektor_numerisch: np.ndarray, beobachtungsvektor_naeherung_numerisch: sp.Matrix,
liste_beobachtungsvektor_symbolisch: list = None, iterationsnummer: int = 0) -> np.ndarray:
"""Berechnet den Verbesserungsvektor dl = l f(x0).
Der Vektor wird als Differenz aus numerischem Beobachtungsvektor und numerischem Näherungs-Beobachtungsvektor gebildet.
Für Richtungsbeobachtungen wird dl normiert.
Der Vektor dl wird als CSV-Datei in den Ordner Zwischenergebnisse exportiert.
:param beobachtungsvektor_numerisch: Numerischer Beobachtungsvektor l.
:type beobachtungsvektor_numerisch: np.ndarray
:param beobachtungsvektor_naeherung_numerisch: Numerischer Näherungs-Beobachtungsvektor f(x0).
:type beobachtungsvektor_naeherung_numerisch: sp.Matrix
:param liste_beobachtungsvektor_symbolisch: Optional: Liste der Beobachtungskennungen.
:type liste_beobachtungsvektor_symbolisch: list | None
:param iterationsnummer: Iterationsnummer für Dateinamen der Zwischenergebnisse.
:type iterationsnummer: int
:return: Verbesserungsvektor dl.
:rtype: np.ndarray
"""
dl = beobachtungsvektor_numerisch - beobachtungsvektor_naeherung_numerisch
# Umwandeln in einen Numpy-Array, um Rechenzeit im Vergleich zu einer sympy.MAtrix zu sparen
dl = np.asarray(dl, dtype=float)
# Wird keine liste_beobachtungsvektor_symbolisch übergeben, wird diese aus der Instanzvariable verwendet.
if liste_beobachtungsvektor_symbolisch is None:
liste_beobachtungsvektor_symbolisch = self.liste_beobachtungsvektor_symbolisch
for i, name in enumerate(liste_beobachtungsvektor_symbolisch):
if "_R_" in str(name):
dl[i] = np.arctan2(np.sin(dl[i]), np.cos(dl[i]))
Export.matrix_to_csv(
fr"Zwischenergebnisse\{iterationsnummer}_dl.csv",
[""],
liste_beobachtungsvektor_symbolisch,
dl.reshape(-1, 1),
"dl"
)
return dl
def dict_substitutionen_uebergeordnetes_system(self,
unbekanntenvektor_aus_iteration: np.ndarray = None) -> dict[Any, Any]:
"""Erstellt das Substitutions-Dictionary für das geozentrisch-kartesische System.
Es werden (abhängig davon, ob ein Unbekanntenvektor aus einer Iteration übergeben wurde) die aktuellen
Koordinaten und daraus abgeleitete Größen erzeugt und als Substitutionen abgelegt, u. a.:
- Punktkoordinaten X*, Y*, Z* sowie geodätische Breite B* und Länge L*,
- berechnete Größen aus Tachymeterbeziehungen (Azimut, Richtung, Zenitwinkel, Schrägstrecke),
- Normalhöhen NH (über Transformationen),
- Beobachtungssymbole der Messungen (Tachymeter, GNSS, Nivellement),
- Orientierungsunbekannte O.
:param unbekanntenvektor_aus_iteration: Optionaler numerischer Unbekanntenvektor einer Iteration zur Aktualisierung der Substitutionen.
:type unbekanntenvektor_aus_iteration: np.ndarray | None
:return: Dictionary mit SymPy-Symbolen als Key und numerischen Werten als Value.
:rtype: dict[Any, Any]
"""
if unbekanntenvektor_aus_iteration is None:
dict_koordinaten = self.db_zugriff.get_koordinaten("naeherung_us")
else:
dict_koordinaten = self.unbekanntenvektor_numerisch_to_dict_unbekanntenvektor(
self.liste_unbekanntenvektor_symbolisch,
unbekanntenvektor_aus_iteration
)
for punktnummer, matrix in dict_koordinaten.items():
dict_koordinaten[punktnummer] = [float(matrix[0]), float(matrix[1]), float(matrix[2])]
# Abfragen der Beobachtungen der einzelnen Beobachtungsarten aus der Tabelle Beobachtungen
liste_beobachtungen_tachymeter = self.db_zugriff.get_beobachtungen_from_beobachtungenid()
liste_beobachtungen_gnssbasislinien = self.db_zugriff.get_beobachtungen_gnssbasislinien()
liste_beobachtungen_nivellemente = self.db_zugriff.get_beobachtungen_nivellement()
liste_azimut_richtungen, dict_orientierungen = self.berechnungen.berechnung_richtung_azimut_zenitwinkel(self.pfad_datenbank, dict_koordinaten)
# Erstellen von Dictionaries für die weitere Verarbeitung
dict_koordinaten_xyz_kopie = {pn: [v[0], v[1], v[2]] for pn, v in dict_koordinaten.items()}
dict_koordinaten_B_L = self.berechnungen.geodätische_breite_laenge(dict_koordinaten_xyz_kopie)
punktnummern_niv = set()
for beobachtungenID, pn_sp, pn_zp, niv_dh, niv_strecke, niv_anz_standpkte in liste_beobachtungen_nivellemente:
punktnummern_niv.add(str(pn_sp).strip())
punktnummern_niv.add(str(pn_zp).strip())
dict_koordinaten_niv = {}
for pn in punktnummern_niv:
if pn in dict_koordinaten:
dict_koordinaten_niv[pn] = dict_koordinaten[pn]
dict_koordinaten_utm = self.trafos.ecef_to_utm(
dict_koordinaten_niv,
self.pfad_tif_quasigeoidundulation)
# Zuweisen der Symbole zu dem jeweiligen numerischen Wert. Gespeichert wird dies in einem Dictionary.
substitutionen = {}
for punktnummer, vektor in dict_koordinaten_B_L.items():
X_sym, Y_sym, Z_sym, B_sym, L_Sym = sp.symbols(
f"X{punktnummer} Y{punktnummer} Z{punktnummer} B{punktnummer} L{punktnummer}")
substitutionen[X_sym] = float(vektor[0][0])
substitutionen[Y_sym] = float(vektor[0][1])
substitutionen[Z_sym] = float(vektor[0][2])
substitutionen[B_sym] = float(vektor[1])
substitutionen[L_Sym] = float(vektor[2])
for beobachtungsgruppeID, standpunkt, zielpunkt, azimut, richtung, zenitwinkel, schraegstrecke, orientierung in liste_azimut_richtungen:
richtung_sym = sp.symbols(f"richtung_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
substitutionen[richtung_sym] = float(richtung)
azimut_sym = sp.symbols(f"azimut_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
substitutionen[azimut_sym] = float(azimut)
zenitwinkel_sym = sp.symbols(f"zw_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
substitutionen[zenitwinkel_sym] = float(zenitwinkel)
schraegstrecke_sym = sp.symbols(f"strecke_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
substitutionen[schraegstrecke_sym] = float(schraegstrecke)
for punktnummer, koordinaten_utm in dict_koordinaten_utm.items():
normalhoehe_sym = sp.symbols(f"NH{punktnummer}")
substitutionen[normalhoehe_sym] = float(koordinaten_utm[2])
for standpunkt, zielpunkt, beobachtungenID, beobachtungsgruppeID, tachymeter_richtung, tachymeter_zenitwinkel, tachymeter_distanz in liste_beobachtungen_tachymeter:
alpha = sp.symbols(f"{beobachtungenID}_R_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
zw = sp.symbols(f"{beobachtungenID}_ZW_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
s = sp.symbols(f"{beobachtungenID}_SD_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
if tachymeter_richtung is None and tachymeter_zenitwinkel is None and tachymeter_distanz is None:
continue
substitutionen[alpha] = float(tachymeter_richtung)
substitutionen[zw] = float(tachymeter_zenitwinkel)
substitutionen[s] = float(tachymeter_distanz)
for beobachtungenID, punktnummer_sp, punktnummer_zp, gnss_bx, gnss_by, gnss_bz, gnss_s0, gnss_cxx, gnss_cxy, gnss_cxz, gnss_cyy, gnss_cyz, gnss_czz in liste_beobachtungen_gnssbasislinien:
beobachtungenID = str(beobachtungenID).strip()
punktnummer_sp = str(punktnummer_sp).strip()
punktnummer_zp = str(punktnummer_zp).strip()
bx = sp.symbols(f"{beobachtungenID}_gnssbx_{punktnummer_sp}_{punktnummer_zp}")
by = sp.symbols(f"{beobachtungenID}_gnssby_{punktnummer_sp}_{punktnummer_zp}")
bz = sp.symbols(f"{beobachtungenID}_gnssbz_{punktnummer_sp}_{punktnummer_zp}")
if gnss_bx is None and gnss_by is None and gnss_bz is None:
continue
substitutionen[bx] = float(gnss_bx)
substitutionen[by] = float(gnss_by)
substitutionen[bz] = float(gnss_bz)
for beobachtungenID, punktnummer_sp, punktnummer_zp, niv_dh, niv_strecke, niv_anz_standpkte in liste_beobachtungen_nivellemente:
beobachtungenID = str(beobachtungenID).strip()
punktnummer_sp = str(punktnummer_sp).strip()
punktnummer_zp = str(punktnummer_zp).strip()
niv = sp.symbols(f"{beobachtungenID}_niv_{punktnummer_sp}_{punktnummer_zp}")
if niv_dh is None:
continue
substitutionen[niv] = float(niv_dh)
if unbekanntenvektor_aus_iteration is not None:
dict_O = self.unbekanntenvektor_numerisch_to_dict_orientierungen(
self.liste_unbekanntenvektor_symbolisch,
unbekanntenvektor_aus_iteration
)
for orientierungs_id, wert in dict_O.items():
substitutionen[sp.Symbol(f"O{orientierungs_id}")] = float(wert)
else:
for beobachtungsgruppeID, standpunkt, zielpunkt, azimut, richtung, zenitwinkel, schraegstrecke, orientierung in liste_azimut_richtungen:
O_sym = sp.Symbol(f"O{beobachtungsgruppeID}")
if O_sym not in substitutionen:
substitutionen[O_sym] = orientierung
return substitutionen
def unbekanntenvektor_numerisch_to_dict_orientierungen(self, liste_unbekanntenvektor_symbolisch: list,
unbekanntenvektor_numerisch: np.ndarray) -> dict[Any, Any]:
"""Extrahiert Orientierungsparameter aus einem numerischen Unbekanntenvektor in ein Dictionary.
Alle Unbekannten, deren Symbolname mit "O" beginnt, werden als als Dictionary in der Form {orientierungs_id: wert} zurückgegeben.
:param liste_unbekanntenvektor_symbolisch: Liste der Unbekannten (Symbole) in der Reihenfolge des numerischen Vektors.
:type liste_unbekanntenvektor_symbolisch: list
:param unbekanntenvektor_numerisch: Numerischer Unbekanntenvektor.
:type unbekanntenvektor_numerisch: np.ndarray
:return: Dictionary der Orientierungen je Beobachtungsgruppe.
:rtype: dict[Any, Any]
"""
dict_O = {}
unbekanntenvektor_numerisch = np.asarray(unbekanntenvektor_numerisch, dtype=float).reshape(-1, 1)
for i, symbol in enumerate(liste_unbekanntenvektor_symbolisch):
name = str(symbol)
if name.startswith("O"):
orientierungs_id = name[1:]
dict_O[orientierungs_id] = float(unbekanntenvektor_numerisch[i, 0])
return dict_O