zusammenfügen 02.2.

This commit is contained in:
2026-02-02 20:01:37 +01:00
parent 774acc3854
commit 4e7c55500b
11 changed files with 62593 additions and 2121 deletions

View File

@@ -1,30 +1,55 @@
from typing import Any
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 Datenbank import Datenbankzugriff
import sympy as sp
from Export import Export
from Berechnungen import Berechnungen
import numpy as np
import importlib
from Datenbank import Datenbankzugriff
from Export import Export
from Koordinatentransformationen import Transformationen
from pathlib import Path
import pandas as pd
import numpy as np
import sympy as sp
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.asarrays
"""
def __init__(self, pfad_datenbank: str, a: float, b: float, pfad_tif_quasigeoidundolation: 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_quasigeoidundolation: Pfad zu Quasigeoidundulationsdaten als GeoTIFF vom BKG für Transformationen (optional).
:type pfad_tif_quasigeoidundolation: 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_quasigeoidundolation = pfad_tif_quasigeoidundolation
self.substitutionen_dict = self.dict_substitutionen_uebergeordnetes_system()
@@ -35,25 +60,43 @@ class FunktionalesModell:
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:
#liste_beobachtungsarten = ["tachymeter_distanz", "tachymeter_richtung", "tachymeter_zenitwinkel"]
"""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"]
#liste_beobachtungsarten = ["tachymeter_distanz", "tachymeter_richtung", "tachymeter_zenitwinkel", "gnss_basislinien"]
db_zugriff = Datenbankzugriff(self.pfad_datenbank)
# 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 = db_zugriff.get_beobachtungen_id_beobachtungsgruppe_standpunkt_zielpunkt(beobachtungsart)
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(
@@ -68,23 +111,10 @@ class FunktionalesModell:
if beobachtungsart == "tachymeter_richtung":
if beobachtungsgruppeID not in liste_orientierungsunbekannte:
liste_orientierungsunbekannte.append(beobachtungsgruppeID)
#GNSS Block
#if beobachtungsart == "gnss_basislinien":
# liste_id_standpunkt_zielpunkt = db_zugriff.get_gnss_beobachtungen_punktnummern()
# for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
# standpunkt = str(standpunkt).strip()
# zielpunkt = str(zielpunkt).strip()
# liste_beobachtungen_rohdaten_gnssbasislinien.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)
#GNSS Block
if beobachtungsart == "gnss_basislinien":
liste_id_standpunkt_zielpunkt = db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_bx")
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()
@@ -94,7 +124,7 @@ class FunktionalesModell:
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
liste_id_standpunkt_zielpunkt = db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_by")
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()
@@ -104,7 +134,7 @@ class FunktionalesModell:
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
liste_id_standpunkt_zielpunkt = db_zugriff.get_gnss_beobachtungen_punktnummern("gnss_bz")
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()
@@ -116,7 +146,7 @@ class FunktionalesModell:
if beobachtungsart == "geometrisches_nivellement":
liste_id_standpunkt_zielpunkt = db_zugriff.get_nivellement_beobachtungen_punktnummern()
liste_id_standpunkt_zielpunkt = self.db_zugriff.get_nivellement_beobachtungen_punktnummern()
for beobachtungenID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
standpunkt = str(standpunkt).strip()
@@ -129,13 +159,7 @@ class FunktionalesModell:
if zielpunkt not in liste_punktnummern:
liste_punktnummern.append(zielpunkt)
#if liste_beobachtungen_rohdaten_tachymeter == []:
# return None
#dict_punkt_symbole = {}
# Erstellen der Symbole für die Unbekannten (X, Y, Z und Orientierung)
liste_unbekannte = []
for punkt in liste_punktnummern:
@@ -151,6 +175,7 @@ class FunktionalesModell:
dict_orientierung_symbole[orientierungsunbekannte] = O
liste_unbekannte.append(O)
# Erstellen der Symbolischen Gleichungen für die Jacobimatrix
liste_beobachtungsgleichungen_distanz =[]
liste_zeilenbeschriftungen_distanz = []
@@ -161,39 +186,30 @@ class FunktionalesModell:
liste_zeilenbeschriftungen_zenitwinkel = []
liste_beobachtungsgleichungen_gnssbasislinien = []
liste_A_gnssbasislinien_zeilen = []
liste_zeilenbeschriftungen_gnssbasislinien = []
liste_beobachtungsgleichungen_nivellement = []
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}")
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}")
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":
# for beobachtungenID, beobachtungsgruppeID, standpunkt, zielpunkt in liste_id_standpunkt_zielpunkt:
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)))
@@ -207,6 +223,8 @@ class FunktionalesModell:
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])
@@ -228,7 +246,7 @@ class FunktionalesModell:
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))
@@ -237,6 +255,8 @@ class FunktionalesModell:
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])
@@ -253,27 +273,10 @@ class FunktionalesModell:
f"{beobachtungenID}_ZW_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}"
)
#if liste_beobachtungen_rohdaten_gnssbasislinien != []:
# for beobachtungsart, beobachtungenID, standpunkt, zielpunkt in liste_beobachtungen_rohdaten_gnssbasislinien:
# X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
# X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
# if beobachtungsart == "gnss_basislinien":
# beobachtungsgleichung_bx = X_zp - X_sp
# beobachtungsgleichung_by = Y_zp - Y_sp
# beobachtungsgleichung_bz = Z_zp - Z_sp
# liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_bx)
# liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_by)
# liste_beobachtungsgleichungen_gnssbasislinien.append(beobachtungsgleichung_bz)
# liste_zeilenbeschriftungen_gnssbasislinien.append(
# f"{beobachtungenID}_gnssbx_{standpunkt}_{zielpunkt}")
# liste_zeilenbeschriftungen_gnssbasislinien.append(
# f"{beobachtungenID}_gnssby_{standpunkt}_{zielpunkt}")
# liste_zeilenbeschriftungen_gnssbasislinien.append(
# f"{beobachtungenID}_gnssbz_{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]
@@ -296,10 +299,10 @@ class FunktionalesModell:
f"{beobachtungenID}_gnssbz_{standpunkt}_{zielpunkt}")
# Geometrisches Nivellement
if liste_beobachtungen_rohdaten_nivellement != []:
for beobachtungsart, beobachtungenID, standpunkt, zielpunkt in liste_beobachtungen_rohdaten_nivellement:
X_sp, Y_sp, Z_sp = self.dict_punkt_symbole[standpunkt]
X_zp, Y_zp, Z_zp = self.dict_punkt_symbole[zielpunkt]
# 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}")
@@ -312,6 +315,7 @@ class FunktionalesModell:
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:
@@ -329,6 +333,7 @@ class FunktionalesModell:
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)
@@ -354,15 +359,13 @@ class FunktionalesModell:
A_gnssbasislinien = None
if liste_A_nivellement_zeilen:
#f_matrix_nivellement = sp.Matrix(liste_beobachtungsgleichungen_nivellement)
#unbekanntenvektor = sp.Matrix(liste_unbekannte)
#A_nivellement = f_matrix_nivellement.jacobian(unbekanntenvektor)
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:
@@ -400,9 +403,9 @@ class FunktionalesModell:
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":
vertauschung = list(range(len(liste_unbekannte)))
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]
@@ -420,7 +423,7 @@ class FunktionalesModell:
A_gesamt = A_gesamt[:, vertauschung]
liste_unbekannte = [liste_unbekannte_alt[i] for i in vertauschung]
# Zusatzgeleichungen der weichen Lagerung
# 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)
@@ -430,24 +433,49 @@ class FunktionalesModell:
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_zahlen_iteration_0(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:
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":
#A_numerisch = A_symbolisch.xreplace(self.substitutionen_dict)
if self.func_A0 is None:
#self.liste_symbole_lambdify = sorted(self.substitutionen_dict.keys(), key=lambda s: str(s))
self.func_A0 = sp.lambdify(
self.liste_symbole_lambdify,
A_symbolisch,
@@ -455,45 +483,43 @@ class FunktionalesModell:
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:
Export.matrix_to_csv(
r"Zwischenergebnisse\fehlende_substitutionen_A.csv",
[""],
[str(s) for s in fehlend],
sp.Matrix([[str(s)] for s in fehlend]),
"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 = sp.Matrix(self.func_A0(*liste_werte))
A_numerisch = np.asarray(self.func_A0(*liste_werte), dtype=float)
Export.matrix_to_csv(fr"Zwischenergebnisse\{iterationsnummer}Jacobi_Matrix_Numerisch_Iteration0.csv", liste_unbekannte,
Export.matrix_to_csv(fr"Zwischenergebnisse\{iterationsnummer}Jacobi_Matrix_Numerisch.csv", liste_unbekannte,
liste_zeilenbeschriftungen_gesamt, A_numerisch, "Beobachtung")
condA = float(np.linalg.cond(A_numerisch))
rankA = int(np.linalg.matrix_rank(A_numerisch))
Export.matrix_to_csv(
fr"Zwischenergebnisse\{iterationsnummer}_Jacobi_Matrix_Stats.csv",
[""],
["condA", "rankA"],
np.array([[condA], [rankA]], dtype=float),
"Wert"
)
return A_numerisch
else:
print("Koordinaten noch nicht implementiert!")
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)
@@ -501,10 +527,24 @@ class FunktionalesModell:
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":
@@ -528,6 +568,7 @@ class FunktionalesModell:
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)
@@ -541,60 +582,30 @@ class FunktionalesModell:
continue
if aufgeteilt[1] == "SD" or aufgeteilt[1] == "R" or aufgeteilt[1] == "ZW":
#beobachtungen_ID = aufgeteilt[0]
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
s = sp.sqrt(dX ** 2 + dY ** 2 + dZ ** 2) # Schrägstrecke
B_sp = sp.Symbol(f"B{standpunkt}")
L_sp = sp.Symbol(f"L{standpunkt}")
if beobachtungsart == "SD":
s_geom = sp.sqrt(dX ** 2 + dY ** 2 + dZ ** 2)
liste_beobachtungsgleichungen.append(s_geom)
elif beobachtungsart == "R":
#O_sp = sp.Symbol(f"O_{beobachtungsgruppeID}")
r_sp_zp = sp.Symbol(f"richtung_berechnet_{beobachtungsgruppeID}_{standpunkt}_{zielpunkt}")
# Lokales System: x_loc = Nord, y_loc = Ost
#x_loc = (-sp.sin(B_sp) * sp.cos(L_sp)) * dX + (-sp.sin(B_sp) * sp.sin(L_sp)) * dY + (sp.cos(B_sp)) * dZ
#y_loc = (-sp.sin(L_sp)) * dX + (sp.cos(L_sp)) * dY
#a12 = sp.atan2(y_loc, x_loc)
# Richtung nach Otepka: r = a12 - O
liste_beobachtungsgleichungen.append(r_sp_zp)
elif beobachtungsart == "ZW":
#dX = X_zp - X_sp
#dY = Y_zp - Y_sp
#dZ = Z_zp - Z_sp
#s_geom = sp.sqrt(dX ** 2 + dY ** 2 + dZ ** 2)
#z_loc = (sp.cos(B_sp) * sp.cos(L_sp)) * dX + (sp.cos(B_sp) * sp.sin(L_sp)) * dY + (sp.sin(B_sp)) * dZ
#zw = sp.acos(z_loc / s_geom)
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":
@@ -617,7 +628,6 @@ class FunktionalesModell:
liste_beobachtungsgleichungen.append(dZ)
if aufgeteilt[1] == "niv":
beobachtungsart = aufgeteilt[1]
standpunkt = str(aufgeteilt[2]).strip()
zielpunkt = str(aufgeteilt[3]).strip()
@@ -628,18 +638,36 @@ class FunktionalesModell:
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_iteration0(self, liste_beobachtungsvektor_symbolisch: list,
beobachtungsvektor_naeherung_symbolisch: sp.Matrix,
iterationsnummer: int = 0) -> ndarray[tuple[int, int], Any]:
#beobachtungsvektor_naeherung_numerisch_iteration0 = beobachtungsvektor_naeherung_symbolisch.xreplace(self.substitutionen_dict)
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.liste_symbole_lambdify = sorted(self.substitutionen_dict.keys(), key=lambda s: str(s))
self.func_beob0 = sp.lambdify(
self.liste_symbole_lambdify,
beobachtungsvektor_naeherung_symbolisch,
@@ -648,17 +676,26 @@ class FunktionalesModell:
)
liste_werte = [self.substitutionen_dict[s] for s in self.liste_symbole_lambdify]
#beobachtungsvektor_naeherung_numerisch_iteration0 = sp.Matrix(self.func_beob0(*liste_werte))
beobachtungsvektor_naeherung_numerisch_iteration0 = np.asarray(self.func_beob0(*liste_werte),
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_iteration0,
liste_beobachtungsvektor_symbolisch, beobachtungsvektor_naeherung_numerisch,
"Beobachtungsvektor")
return beobachtungsvektor_naeherung_numerisch_iteration0
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")
@@ -666,64 +703,82 @@ class FunktionalesModell:
def unbekanntenvektor_numerisch(self, liste_unbekanntenvektor_symbolisch: list,
unbekanntenvektor_symbolisch: sp.Matrix,
dX_Vektor: np.Matrix = None,
unbekanntenvektor_neumerisch_vorherige_Iteration: np.Matrix = None,
dX_Vektor: np.asarray = None,
unbekanntenvektor_numerisch_vorherige_Iteration: np.asarray = 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.asarray | None
:param unbekanntenvektor_numerisch_vorherige_Iteration: Numerischer Unbekanntenvektor der vorherigen Iteration (optional).
:type unbekanntenvektor_numerisch_vorherige_Iteration: np.asarray | 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
#if not hasattr(self, "liste_unbekanntenvektor_symbolisch"):
# self.liste_unbekanntenvektor_symbolisch = liste_unbekanntenvektor_symbolisch
if dX_Vektor is None and unbekanntenvektor_neumerisch_vorherige_Iteration is None:
#unbekanntenvektor_numerisch = unbekanntenvektor_symbolisch.xreplace(self.substitutionen_dict)
#if self.func_u0 is None:
# self.func_u0 = sp.lambdify(
# self.liste_symbole_lambdify,
# unbekanntenvektor_symbolisch,
# modules="numpy",
# cse=True
# )
# Ü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)
#liste_werte = [self.substitutionen_dict[s] for s in self.liste_symbole_lambdify]
#unbekanntenvektor_numerisch = sp.Matrix(self.func_u0(*liste_werte))
#unbekanntenvektor_numerisch = np.asarray(self.func_u0(*liste_werte), dtype=float).reshape(-1, 1)
else:
#unbekanntenvektor_numerisch = unbekanntenvektor_neumerisch_vorherige_Iteration + dX_Vektor
unbekanntenvektor_neumerisch_vorherige_Iteration = np.asarray(
unbekanntenvektor_neumerisch_vorherige_Iteration, dtype=float).reshape(-1, 1)
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
unbekanntenvektor_numerisch = unbekanntenvektor_neumerisch_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_Iteration0.csv", [""],
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.Matrix) -> dict:
dict_unbekanntenvektor_numerisch = {}
#index = 0
"""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.Matrix
: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 sym in liste_unbekanntenvektor_symbolisch:
name = str(sym)
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)
@@ -739,19 +794,33 @@ class FunktionalesModell:
float(unbekanntenvektor_numerisch[iZ, 0]),
])
#dict_unbekanntenvektor_numerisch[punktnummer] = sp.Matrix([
# float(unbekanntenvektor_numerisch[index, 0]),
# float(unbekanntenvektor_numerisch[index + 1, 0]),
# float(unbekanntenvektor_numerisch[index + 2, 0])
#])
#index += 3
return dict_koordinaten
def berechnung_dl(self, beobachtungsvektor_numerisch: np.Matrix, beobachtungsvektor_naeherung_numerisch: sp.Matrix,
liste_beobachtungsvektor_symbolisch: list = None, iterationsnummer: int = 0) -> np.Matrix:
liste_beobachtungsvektor_symbolisch: list = None, iterationsnummer: int = 0) -> np.asarray:
"""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.Matrix
: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.asarray
"""
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
@@ -770,11 +839,25 @@ class FunktionalesModell:
return dl
def dict_substitutionen_uebergeordnetes_system(self,
unbekanntenvektor_aus_iteration: np.Matrix = None) -> dict[Any, Any]:
db_zugriff = Datenbankzugriff(self.pfad_datenbank)
berechnungen = Berechnungen(self.a, self.b)
unbekanntenvektor_aus_iteration: np.asarray = 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.asarray | 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 = db_zugriff.get_koordinaten("naeherung_us")
dict_koordinaten = self.db_zugriff.get_koordinaten("naeherung_us")
else:
dict_koordinaten = self.unbekanntenvektor_numerisch_to_dict_unbekanntenvektor(
self.liste_unbekanntenvektor_symbolisch,
@@ -784,13 +867,15 @@ class FunktionalesModell:
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)
liste_beobachtungen_tachymeter = db_zugriff.get_beobachtungen_from_beobachtungenid()
liste_beobachtungen_gnssbasislinien = db_zugriff.get_beobachtungen_gnssbasislinien()
liste_beobachtungen_nivellemente = db_zugriff.get_beobachtungen_nivellement()
liste_azimut_richtungen, dict_orientierungen = 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 = berechnungen.geometrische_breite_laenge(dict_koordinaten_xyz_kopie)
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:
@@ -806,8 +891,8 @@ class FunktionalesModell:
dict_koordinaten_niv,
self.pfad_tif_quasigeoidundolation)
# 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}")
@@ -818,10 +903,6 @@ class FunktionalesModell:
substitutionen[B_sym] = float(vektor[1])
substitutionen[L_Sym] = float(vektor[2])
#for beobachtungsgruppeID, orientierung in dict_orientierungen.items():
# O_sym = sp.symbols(f"O_{beobachtungsgruppeID}")
# substitutionen[O_sym] = float(orientierung)
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)
@@ -839,8 +920,6 @@ class FunktionalesModell:
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}")
@@ -852,7 +931,6 @@ class FunktionalesModell:
substitutionen[alpha] = float(tachymeter_richtung)
substitutionen[zw] = float(tachymeter_zenitwinkel)
substitutionen[s] = float(tachymeter_distanz)
#substitutionen[sp.Symbol(f"O{beobachtungsgruppeID}")] = 0.0
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()
@@ -890,10 +968,6 @@ class FunktionalesModell:
for orientierungs_id, wert in dict_O.items():
substitutionen[sp.Symbol(f"O{orientierungs_id}")] = float(wert)
else:
#for standpunkt, zielpunkt, beobachtungenID, beobachtungsgruppeID, *_ in liste_beobachtungen_tachymeter:
# O_sym = sp.Symbol(f"O{beobachtungsgruppeID}")
# if O_sym not in substitutionen:
# substitutionen[O_sym] = 0
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:
@@ -902,7 +976,18 @@ class FunktionalesModell:
return substitutionen
def unbekanntenvektor_numerisch_to_dict_orientierungen(self, liste_unbekanntenvektor_symbolisch: list,
unbekanntenvektor_numerisch: np.Matrix) -> dict[Any, Any]:
unbekanntenvektor_numerisch: np.asarray) -> 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.asarray
: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):
@@ -911,5 +996,4 @@ class FunktionalesModell:
orientierungs_id = name[1:]
dict_O[orientierungs_id] = float(unbekanntenvektor_numerisch[i, 0])
return dict_O
return dict_O