zusammenfügen 02.2.
This commit is contained in:
@@ -1,91 +1,85 @@
|
||||
import sympy as sp
|
||||
import numpy as np
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Tuple, Iterable, Any
|
||||
from Export import Export
|
||||
import numpy as np
|
||||
import sympy as sp
|
||||
from typing import Dict, Iterable
|
||||
|
||||
from Datenbank import Datenbankzugriff
|
||||
from Export import Export
|
||||
|
||||
@dataclass
|
||||
class StochastischesModell:
|
||||
"""Stochastisches Modell zur Aufstellung und Auswertung von Varianz-Kovarianz-Matrizen.
|
||||
|
||||
Die Klasse stellt Methoden zur Verfügung für:
|
||||
|
||||
- symbolischen Aufbau der Varianz-Kovarianz-Matrix der Beobachtungen Qll,
|
||||
- numerische Substitution von Qll aus der Datenbank,
|
||||
- symbolischen und numerischen Aufbau der Zusatz-Varianz-Kovarianz-Matrix QAA für Anschlusspunkte (weiche Lagerung, lA_*),
|
||||
- Ableitung zentraler Matrizen der Ausgleichung (P, Qxx, Qll_dach, Qvv) als Hilfsfunktionen.
|
||||
|
||||
Die Grundidee ist, die stochastischen Zusammenhänge zunächst symbolisch abzubilden (SymPy) und anschließend
|
||||
mit Datenbankwerten zu substituieren.
|
||||
"""
|
||||
|
||||
n_beob: int
|
||||
sigma_beob: Iterable[float] =None #σ a priori der einzelnen Beobachtung
|
||||
gruppe_beob: Iterable[int] =None #Gruppenzugehörigkeit jeder Beobachtung (Distanz, Richtung, GNSS, Nivellement,...,)
|
||||
sigma0_gruppe: Dict[int, float] = field(default_factory=dict) #σ0² für jede Gruppe
|
||||
sigma_beob: Iterable[float] =None #σ a priori der einzelnen Beobachtung
|
||||
gruppe_beob: Iterable[int] =None #Gruppenzugehörigkeit jeder Beobachtung (Distanz, Richtung, GNSS, Nivellement,...,)
|
||||
sigma0_gruppe: Dict[int, float] = field(default_factory=dict) #σ0² für jede Gruppe
|
||||
|
||||
|
||||
def __post_init__(self):
|
||||
# Defaults setzen
|
||||
if self.sigma_beob is None:
|
||||
self.sigma_beob = [1.0] * int(self.n_beob)
|
||||
def __init__(self, pfad_datenbank: str) -> None:
|
||||
"""Initialisiert das stochastische Modell.
|
||||
|
||||
if self.gruppe_beob is None:
|
||||
self.gruppe_beob = [1] * int(self.n_beob)
|
||||
|
||||
# In SymPy-Spaltenvektoren umwandeln
|
||||
#self.sigma_beob = sp.Matrix(list(self.sigma_beob))
|
||||
#self.gruppe_beob = sp.Matrix(list(self.gruppe_beob))
|
||||
|
||||
# Dimension prüfen
|
||||
#if self.sigma_beob.rows != self.gruppe_beob.rows:
|
||||
# raise ValueError("sigma_beob und gruppe_beob müssen gleich viele Einträge haben.")
|
||||
|
||||
#if self.sigma_beob.rows != int(self.n_beob):
|
||||
# raise ValueError("n_beob passt nicht zur Länge von sigma_beob / gruppe_beob.")
|
||||
|
||||
# Fehlende Gruppen mit sigma0_sq = 1.0 ergänzen
|
||||
#unique_groups = sorted({int(g) for g in self.gruppe_beob})
|
||||
#for g in unique_groups:
|
||||
# if g not in self.sigma0_gruppe:
|
||||
# self.sigma0_gruppe[g] = 1.0
|
||||
|
||||
# In NumPy-Spaltenvektoren umwandeln
|
||||
self.sigma_beob = np.asarray(list(self.sigma_beob), dtype=float).reshape(-1, 1)
|
||||
self.gruppe_beob = np.asarray(list(self.gruppe_beob), dtype=int).reshape(-1, 1)
|
||||
|
||||
# Dimension prüfen
|
||||
if self.sigma_beob.shape[0] != self.gruppe_beob.shape[0]:
|
||||
raise ValueError("sigma_beob und gruppe_beob müssen gleich viele Einträge haben.")
|
||||
|
||||
if self.sigma_beob.shape[0] != int(self.n_beob):
|
||||
raise ValueError("n_beob passt nicht zur Länge von sigma_beob / gruppe_beob.")
|
||||
|
||||
# Fehlende Gruppen mit sigma0_sq = 1.0 ergänzen
|
||||
unique_groups = sorted({int(g) for g in self.gruppe_beob.flatten()})
|
||||
for g in unique_groups:
|
||||
if g not in self.sigma0_gruppe:
|
||||
self.sigma0_gruppe[g] = 1.0
|
||||
Speichert den Pfad zur SQLite-Datenbank, initialisiert den Datenbankzugriff und legt Cache-Variablen an,
|
||||
die in den numerischen Auswertungen zur Rechenzeitersparnis wiederverwendet werden.
|
||||
|
||||
:param pfad_datenbank: Pfad zur SQLite-Datenbank.
|
||||
:type pfad_datenbank: str
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
self.pfad_datenbank = pfad_datenbank
|
||||
self.func_Qll_numerisch = None
|
||||
self.liste_symbole_lambdify = None
|
||||
self.db_zugriff = Datenbankzugriff(self.pfad_datenbank)
|
||||
|
||||
def Qll_symbolisch(self, liste_beobachtungen_symbolisch: list) -> sp.Matrix:
|
||||
"""Erstellt die symbolische Varianz-Kovarianz-Matrix Qll der Beobachtungen.
|
||||
|
||||
#def berechne_Qll(self) -> Tuple[sp.Matrix, sp.Matrix]:
|
||||
# n = self.n_beob
|
||||
# Q_ll = sp.zeros(n, n)
|
||||
# P = sp.zeros(n, n)
|
||||
# for i in range(self.n_beob):
|
||||
# sigma_i = self.sigma_beob[i, 0] #σ-Wert der i-ten Beobachtung holen
|
||||
# g = int(self.gruppe_beob[i, 0]) #Gruppenzugehörigkeit der Beobachtung bestimmen
|
||||
# sigma0_sq = self.sigma0_gruppe[g] #Den Varianzfaktor der Gruppe holen
|
||||
# q_ii = sigma_i**2 #σ² berechnen
|
||||
# Q_ll[i, i] = q_ii #Diagonale
|
||||
# return Q_ll
|
||||
Aus den symbolischen Beobachtungskennungen wird die Beobachtungsart abgeleitet (Tachymeter: SD/R/ZW,
|
||||
GNSS: gnssbx/gnssby/gnssbz, Geometrisches Nivellement: niv). Für jede Beobachtung wird eine symbolische Varianzgleichung
|
||||
aufgestellt und in Qll eingetragen.
|
||||
|
||||
def Qll_symbolisch(self, pfad_datenbank: str, liste_beobachtungen_symbolisch: list) -> sp.Matrix:
|
||||
Berücksichtigte Gleichungen:
|
||||
|
||||
- Tachymeter SD: σ = sqrt(σ_konstant² + (σ_streckenprop * SD / 1 000 000)²), Varianz = varkomp * σ²
|
||||
- Tachymeter R/ZW: σ = sqrt(σ_konstant² + (σ_konstant_SD / SD)²), Varianz = varkomp * σ²
|
||||
- GNSS: Diagonale und Korrelationen je Basislinie aus cxx/cyy/czz und cxy/cxz/cyz, jeweils skaliert mit s0²
|
||||
- Nivellement: σ = sqrt(n_wechselpunkte * σ_konstant² + σ_streckenprop² * distanz / 1000), Varianz = varkomp * σ²
|
||||
|
||||
Die symbolische Matrix wird als CSV-Datei in Zwischenergebnisse\\Qll_Symbolisch.csv exportiert.
|
||||
|
||||
:param liste_beobachtungen_symbolisch: Liste der symbolischen Beobachtungskennungen.
|
||||
:type liste_beobachtungen_symbolisch: list
|
||||
:return: Symbolische Varianz-Kovarianz-Matrix Qll.
|
||||
:rtype: sp.Matrix
|
||||
"""
|
||||
liste_standardabweichungen_symbole = []
|
||||
|
||||
# Vorbereitung und Abfrage der notwendigen Listen und Dictionaries
|
||||
liste_beobachtungen_symbolisch = [str(b) for b in liste_beobachtungen_symbolisch]
|
||||
liste_beobachtungen_symbolisch = [b for b in liste_beobachtungen_symbolisch if not b.startswith("lA_")]
|
||||
Qll = sp.zeros(len(liste_beobachtungen_symbolisch), len(liste_beobachtungen_symbolisch))
|
||||
dict_beobachtungenID_instrumenteID = self.db_zugriff.get_instrumenteID_beobachtungenID_dict()
|
||||
|
||||
db_zugriff = Datenbankzugriff(pfad_datenbank)
|
||||
dict_beobachtungenID_instrumenteID = db_zugriff.get_instrumenteID_beobachtungenID_dict()
|
||||
|
||||
# Aufstellen der Symbolischen Gleichungen für die Einträge in der Qll-Matrix jeder Beobachtungsgruppe
|
||||
for i, beobachtung_symbolisch_i in enumerate(liste_beobachtungen_symbolisch):
|
||||
aufgeteilt_i = beobachtung_symbolisch_i.split("_")
|
||||
|
||||
beobachtungenID_i = int(aufgeteilt_i[0])
|
||||
instrumenteID_i = dict_beobachtungenID_instrumenteID[beobachtungenID_i]
|
||||
|
||||
# SD = Schrägdistanzen | R = Richtung | ZW = Zenitwinkel
|
||||
# varkomp = Varianzkomponentenschätzung (Ist noch keine Erfolgt, ist dieser Faktor = 1
|
||||
if aufgeteilt_i[1] == "SD" or aufgeteilt_i[1] == "R" or aufgeteilt_i[1] == "ZW":
|
||||
|
||||
beobachtungsart_i = str(aufgeteilt_i[1])
|
||||
@@ -120,6 +114,7 @@ class StochastischesModell:
|
||||
|
||||
Qll[i, i] = (varianzkompontenschaetzung) * sigma ** 2
|
||||
|
||||
# Setzen der 0-Einträge in der Qll-Matrix
|
||||
for j in range(i + 1, len(liste_beobachtungen_symbolisch)):
|
||||
beobachtung_symbolisch_j = liste_beobachtungen_symbolisch[j]
|
||||
aufgeteilt_j = beobachtung_symbolisch_j.split("_")
|
||||
@@ -128,8 +123,10 @@ class StochastischesModell:
|
||||
if beobachtungsart_i == "SD" and beobachtungsart_j == "SD":
|
||||
Qll[i, j] = 0
|
||||
Qll[j, i] = 0
|
||||
|
||||
# GNSS
|
||||
# s0, sowie die kovarianzen cxx, ... entstammen direkt LeicaGeooffice
|
||||
if aufgeteilt_i [1] == "gnssbx" or aufgeteilt_i[1] == "gnssby" or aufgeteilt_i[1] == "gnssbz":
|
||||
#beobachtungenID_i = int(aufgeteilt_i[0])
|
||||
beobachtungsart_i = str(aufgeteilt_i[1])
|
||||
varianzkompontenschaetzung = sp.Symbol(
|
||||
f"varkomp_{instrumenteID_i}_GNSS-Rover_Basislinienbeobachtungen")
|
||||
@@ -185,9 +182,8 @@ class StochastischesModell:
|
||||
liste_standardabweichungen_symbole.append(czz)
|
||||
Qll[i, i] = (varianzkompontenschaetzung) * (czz * (s0 ** 2))
|
||||
|
||||
# Geometrisches Nivellement
|
||||
if aufgeteilt_i[1] == "niv":
|
||||
#beobachtungenID_i = int(aufgeteilt_i[0])
|
||||
#instrumenteID_i = dict_beobachtungenID_instrumenteID[beobachtungenID_i]
|
||||
beobachtungsart_i = str(aufgeteilt_i[1])
|
||||
|
||||
varianzkompontenschaetzung = sp.Symbol(
|
||||
@@ -198,6 +194,7 @@ class StochastischesModell:
|
||||
nivellement_distanz = sp.Symbol(f"niv_distanz_{beobachtungenID_i}")
|
||||
nivellement_anz_wechselpunkte = sp.Symbol(f"niv_anz_wechselpunkte_{beobachtungenID_i}")
|
||||
|
||||
# Berechnen der Standardabweichung unter Einbeziehung der Anzahl Wechselpunkte
|
||||
sigma = sp.sqrt(nivellement_anz_wechselpunkte * stabw_apriori_konstant ** 2 + stabw_apriori_streckenprop ** 2 * nivellement_distanz / 1000)
|
||||
liste_standardabweichungen_symbole.append(sigma)
|
||||
|
||||
@@ -206,24 +203,49 @@ class StochastischesModell:
|
||||
Export.matrix_to_csv(r"Zwischenergebnisse\Qll_Symbolisch.csv", liste_beobachtungen_symbolisch, liste_beobachtungen_symbolisch, Qll, "Qll")
|
||||
return Qll
|
||||
|
||||
def Qll_numerisch(self, pfad_datenbank: str, Qll_Matrix_Symbolisch: sp.Matrix, liste_beobachtungen_symbolisch: list) -> np.Matrix:
|
||||
def Qll_numerisch(self, Qll_Matrix_Symbolisch: sp.Matrix, liste_beobachtungen_symbolisch: list) -> np.Matrix:
|
||||
"""Erstellt eine numerische Varianz-Kovarianz-Matrix aus einer symbolischen Qll-Matrix.
|
||||
|
||||
Es werden die zur Substitution benötigten Werte aus der Datenbank abgefragt und den in Qll vorkommenden Symbolen zugeordnet,
|
||||
u. a.:
|
||||
|
||||
- Genauigkeiten (stabw_apriori_konstant / stabw_apriori_streckenprop) je Instrument und Beobachtungsart,
|
||||
- Varianzkomponenten (varkomp_*) je Instrument und Beobachtungsgruppe,
|
||||
- gemessene Tachymeter-Distanzen SD_* zur Bildung der Winkel-/Zenitwinkel-Ansätze,
|
||||
- GNSS-Kovarianzen cxx, cxy, cxz, cyy, cyz, czz sowie s0 je Basislinie,
|
||||
- Geomtrisches Nivellement-Strecken und Anzahl Wechsel-/Standpunkte.
|
||||
|
||||
Die Methode prüft, ob alle freien Symbole der Qll-Matrix substituierbar sind.
|
||||
Zur Rechenzeitersparnis wird ein Lambdify-Cache geführt. Die Matrix wird anschließend gezielt
|
||||
über Nicht-Null-Einträge befüllt, um unnötige Auswertung von Nullzellen zu vermeiden.
|
||||
|
||||
Die numerische Matrix wird als CSV-Datei in Zwischenergebnisse\\Qll_Numerisch.csv exportiert.
|
||||
|
||||
:param Qll_Matrix_Symbolisch: Symbolische Varianz-Kovarianz-Matrix Qll.
|
||||
:type Qll_Matrix_Symbolisch: sp.Matrix
|
||||
:param liste_beobachtungen_symbolisch: Liste der symbolischen Beobachtungskennungen.
|
||||
:type liste_beobachtungen_symbolisch: list
|
||||
:return: Numerische Varianz-Kovarianz-Matrix Qll als Numpy-Array.
|
||||
:rtype: np.Matrix
|
||||
:raises ValueError: Falls Symbole in Qll_Matrix_Symbolisch enthalten sind, für die keine Substitutionen vorhanden sind.
|
||||
"""
|
||||
liste_beobachtungen_symbolisch = [str(b).strip() for b in liste_beobachtungen_symbolisch]
|
||||
liste_beobachtungen_symbolisch = [b for b in liste_beobachtungen_symbolisch if not b.startswith("lA_")]
|
||||
|
||||
db_zugriff = Datenbankzugriff(pfad_datenbank)
|
||||
dict_genauigkeiten = db_zugriff.get_genauigkeiten_dict()
|
||||
dict_beobachtungenID_instrumenteID = db_zugriff.get_instrumenteID_beobachtungenID_dict()
|
||||
# Abfragen der Zahlen zu den Symbolen aus der Datenbank
|
||||
dict_genauigkeiten = self.db_zugriff.get_genauigkeiten_dict()
|
||||
|
||||
liste_beobachtungen_tachymeter = db_zugriff.get_beobachtungen_from_beobachtungenid()
|
||||
liste_beobachtungen_gnss = db_zugriff.get_beobachtungen_gnssbasislinien()
|
||||
liste_beobachtungen_nivellement = db_zugriff.get_beobachtungen_nivellement()
|
||||
|
||||
liste_varianzkomponenten = db_zugriff.get_varianzkomponentenschaetzung()
|
||||
liste_beobachtungen_tachymeter = self.db_zugriff.get_beobachtungen_from_beobachtungenid()
|
||||
liste_beobachtungen_gnss = self.db_zugriff.get_beobachtungen_gnssbasislinien()
|
||||
liste_beobachtungen_nivellement = self.db_zugriff.get_beobachtungen_nivellement()
|
||||
liste_varianzkomponenten = self.db_zugriff.get_varianzkomponentenschaetzung()
|
||||
|
||||
# Erstellen eines Dicts mit der zuordnung beobachtungenID : Distanz
|
||||
dict_beobachtungenID_distanz = {}
|
||||
for standpunkt, zielpunkt, beobachtungenID, beobachtungsgruppeID, tachymeter_richtung, tachymeter_zenitwinkel, tachymeter_distanz in liste_beobachtungen_tachymeter:
|
||||
dict_beobachtungenID_distanz[int(beobachtungenID)] = tachymeter_distanz
|
||||
|
||||
# Erstellen eines Dicts mit den Genauigkeiten aus der Tabelle Genauigkeiten
|
||||
dict_genauigkeiten_neu = {}
|
||||
for genauigkeitenID, eintrag in dict_genauigkeiten.items():
|
||||
instrumenteID = int(eintrag[0])
|
||||
@@ -235,6 +257,7 @@ class StochastischesModell:
|
||||
|
||||
substitutionen = {}
|
||||
|
||||
# Erstellen eines Dicts mit den konstanten Anteilen der Standardabweichungen aus der Datenbank
|
||||
dict_konstante_sd = {}
|
||||
for (instrumenteID, beobachtungsart), (stabw_apriori_konstant,
|
||||
stabw_apriori_streckenprop) in dict_genauigkeiten_neu.items():
|
||||
@@ -242,9 +265,11 @@ class StochastischesModell:
|
||||
if stabw_apriori_konstant is not None:
|
||||
dict_konstante_sd[instrumenteID] = float(stabw_apriori_konstant)
|
||||
|
||||
# Zuordnen des numerischen Varianzfaktors zum entsprechenden Symbol für die Substitution
|
||||
for (varianzkomponenteID, instrumenteID, beobachtungsgruppe, varianz_varianzkomponentenschaetzung) in liste_varianzkomponenten:
|
||||
substitutionen[sp.Symbol(f"varkomp_{instrumenteID}_{beobachtungsgruppe.strip()}")] = float(varianz_varianzkomponentenschaetzung)
|
||||
|
||||
# Zuordnen der numerischen Genauigkeitsangaben aus der Datenbank zum entsprechenden Symbol für die Substitution
|
||||
for (instrumenteID, beobachtungsart), (stabw_apriori_konstant,
|
||||
stabw_apriori_streckenprop) in dict_genauigkeiten_neu.items():
|
||||
|
||||
@@ -257,7 +282,6 @@ class StochastischesModell:
|
||||
elif beobachtungsart == "Geometrisches_Nivellement":
|
||||
beobachtungsart_kurz = "niv"
|
||||
|
||||
|
||||
if stabw_apriori_konstant is not None:
|
||||
substitutionen[sp.Symbol(f"stabw_apriori_konstant_{beobachtungsart_kurz}_{instrumenteID}")] = float(stabw_apriori_konstant)
|
||||
if stabw_apriori_streckenprop is not None:
|
||||
@@ -266,17 +290,12 @@ class StochastischesModell:
|
||||
wert = wert / 1000.0
|
||||
substitutionen[sp.Symbol(f"stabw_apriori_streckenprop_{beobachtungsart_kurz}_{instrumenteID}")] = wert
|
||||
|
||||
# --- DEBUG NIV Genauigkeiten (einmalig) ---
|
||||
for k, v in substitutionen.items():
|
||||
ks = str(k)
|
||||
if "stabw_apriori_streckenprop_niv_" in ks or "stabw_apriori_konstant_niv_" in ks:
|
||||
print("DEBUG", ks, "=", v)
|
||||
|
||||
for instrumenteID, wert in dict_konstante_sd.items():
|
||||
substitutionen[sp.Symbol(f"stabw_apriori_konstant_SD_{instrumenteID}")] = float(wert)
|
||||
|
||||
liste_beobachtungen_symbolisch = [str(b) for b in liste_beobachtungen_symbolisch]
|
||||
|
||||
# Zuordnen der numerischen gemessenen Distanz aus der Datenbank zum entsprechenden Symbol für die Substitution
|
||||
for beobachtung_symbolisch in liste_beobachtungen_symbolisch:
|
||||
aufgeteilt = beobachtung_symbolisch.split("_")
|
||||
beobachtungenID = int(aufgeteilt[0])
|
||||
@@ -285,7 +304,7 @@ class StochastischesModell:
|
||||
if distanz is not None:
|
||||
substitutionen[sp.Symbol(f"SD_{beobachtungenID}")] = float(distanz)
|
||||
|
||||
#GNSS Basislinien
|
||||
# Zuordnen der numerischen GNSS-Bestandteile aus der Tabelle Beobachtungen zum entsprechenden Symbol für die Substitution
|
||||
for gnss_beobachtungen in liste_beobachtungen_gnss:
|
||||
beobachtungenID = gnss_beobachtungen[0]
|
||||
gnss_s0 = gnss_beobachtungen[6]
|
||||
@@ -313,7 +332,7 @@ class StochastischesModell:
|
||||
substitutionen[sp.Symbol(f"niv_anz_wechselpunkte_{beobachtungenID}")] = float(niv_anz_standpkte)
|
||||
substitutionen[sp.Symbol(f"niv_distanz_{beobachtungenID}")] = float(niv_strecke)
|
||||
|
||||
#Qll_numerisch = Qll_Matrix_Symbolisch.xreplace(substitutionen)
|
||||
# Substituieren mit der Methode lambdify
|
||||
if (self.func_Qll_numerisch is None) or (set(self.liste_symbole_lambdify) != set(substitutionen.keys())):
|
||||
self.liste_symbole_lambdify = sorted(substitutionen.keys(), key=lambda s: str(s))
|
||||
self.func_Qll_numerisch = sp.lambdify(
|
||||
@@ -323,14 +342,13 @@ class StochastischesModell:
|
||||
cse=True
|
||||
)
|
||||
|
||||
# Ausgeben der fehlenden Substitutionen
|
||||
fehlend = sorted(list(Qll_Matrix_Symbolisch.free_symbols - set(substitutionen.keys())), key=lambda s: str(s))
|
||||
if fehlend:
|
||||
raise ValueError(
|
||||
f"Qll_numerisch: Fehlende Substitutionen ({len(fehlend)}): {[str(s) for s in fehlend[:80]]}")
|
||||
|
||||
#liste_werte = [substitutionen[s] for s in self.liste_symbole_lambdify]
|
||||
#Qll_numerisch = np.asarray(self.func_Qll_numerisch(*liste_werte), dtype=float)
|
||||
|
||||
# Eingrenzen der Substitution auf nicht 0 Zellen
|
||||
rows = int(Qll_Matrix_Symbolisch.rows)
|
||||
cols = int(Qll_Matrix_Symbolisch.cols)
|
||||
|
||||
@@ -349,12 +367,6 @@ class StochastischesModell:
|
||||
|
||||
eintrag_num = eintrag.xreplace(substitutionen)
|
||||
|
||||
if hasattr(eintrag_num, "free_symbols") and len(eintrag_num.free_symbols) > 0:
|
||||
rest = sorted(list(eintrag_num.free_symbols), key=lambda s: str(s))
|
||||
raise ValueError(
|
||||
f"Qll_numerisch: Eintrag [{i},{j}] bleibt symbolisch. Rest-Symbole: {[str(s) for s in rest[:20]]}"
|
||||
)
|
||||
|
||||
Qll_numerisch[i, j] = float(eintrag_num)
|
||||
|
||||
Export.matrix_to_csv(
|
||||
@@ -367,15 +379,28 @@ class StochastischesModell:
|
||||
|
||||
return Qll_numerisch
|
||||
|
||||
def QAA_symbolisch(self, liste_beobachtungen_symbolisch: list, pfad_datenbank: str) -> np.Matrix:
|
||||
def QAA_symbolisch(self, liste_beobachtungen_symbolisch: list) -> np.Matrix:
|
||||
"""Erstellt die symbolische Varianz-Kovarianz-Matrix QAA der Anschlusspunkte (weiche Lagerung).
|
||||
|
||||
Es werden ausschließlich Beobachtungen berücksichtigt, deren Kennung mit "lA_" beginnt. Für jede Anschlussbedingung
|
||||
wird eine (symbolische) Standardabweichung StabwAA_* angesetzt und mit der Varianzkomponente der Beobachtungsgruppe
|
||||
"Anschlusspunkte" multipliziert.
|
||||
|
||||
Die symbolische Matrix wird als CSV-Datei in Zwischenergebnisse\\QAA_Symbolisch.csv exportiert.
|
||||
|
||||
:param liste_beobachtungen_symbolisch: Liste der symbolischen Beobachtungskennungen.
|
||||
:type liste_beobachtungen_symbolisch: list
|
||||
:return: Symbolische Varianz-Kovarianz-Matrix QAA.
|
||||
:rtype: sp.Matrix
|
||||
"""
|
||||
liste_standardabweichungen_symbole = []
|
||||
liste_beobachtungen_symbolisch = [str(b) for b in liste_beobachtungen_symbolisch]
|
||||
liste_beobachtungen_symbolisch = [b for b in liste_beobachtungen_symbolisch if b.startswith("lA_")]
|
||||
Qll = sp.zeros(len(liste_beobachtungen_symbolisch), len(liste_beobachtungen_symbolisch))
|
||||
|
||||
db_zugriff = Datenbankzugriff(pfad_datenbank)
|
||||
instrumente_id_anschlusspunkte = db_zugriff.get_instrument_liste("Anschlusspunkte")[0][0]
|
||||
instrumente_id_anschlusspunkte = self.db_zugriff.get_instrument_liste("Anschlusspunkte")[0][0]
|
||||
|
||||
# Erstellen der Symbolischen Gleichungen für die QAA-Matrix
|
||||
for i, beobachtung_symbolisch_i in enumerate(liste_beobachtungen_symbolisch):
|
||||
aufgeteilt_i = beobachtung_symbolisch_i.split("_")
|
||||
datumskoordinate = str(aufgeteilt_i[1])
|
||||
@@ -394,17 +419,32 @@ class StochastischesModell:
|
||||
Export.matrix_to_csv(r"Zwischenergebnisse\QAA_Symbolisch.csv", liste_beobachtungen_symbolisch, liste_beobachtungen_symbolisch, Qll, "Qll")
|
||||
return Qll
|
||||
|
||||
def QAA_numerisch(self, pfad_datenbank: str, QAA_Matrix_Symbolisch: sp.Matrix, liste_beobachtungen_symbolisch: list) -> np.Matrix:
|
||||
def QAA_numerisch(self, QAA_Matrix_Symbolisch: sp.Matrix, liste_beobachtungen_symbolisch: list) -> np.Matrix:
|
||||
"""Erstellt eine numerische Matrix aus einer symbolischen QAA-Matrix.
|
||||
|
||||
Es werden die numerischen Standardabweichungen der Anschlussbedingungen sowie die Varianzkomponente der Gruppe
|
||||
"Anschlusspunkte" aus der Datenbank abgefragt und substituiert. Zur Rechenzeitersparnis wird ein Lambdify-Cache geführt,
|
||||
der bei Änderung der Symbolmenge neu aufgebaut.
|
||||
|
||||
Die numerische Matrix wird als CSV-Datei in Zwischenergebnisse\\QAA_Numerisch.csv exportiert.
|
||||
|
||||
:param QAA_Matrix_Symbolisch: Symbolische Varianz-Kovarianz-Matrix QAA.
|
||||
:type QAA_Matrix_Symbolisch: sp.Matrix
|
||||
:param liste_beobachtungen_symbolisch: Liste der symbolischen Beobachtungskennungen.
|
||||
:type liste_beobachtungen_symbolisch: list
|
||||
:return: Numerische Varianz-Kovarianz-Matrix QAA als Numpy-Array.
|
||||
:rtype: np.Matrix
|
||||
"""
|
||||
# Symbolische Listen
|
||||
liste_beobachtungen_symbolisch = [str(b).strip() for b in liste_beobachtungen_symbolisch]
|
||||
liste_beobachtungen_symbolisch = [b for b in liste_beobachtungen_symbolisch if b.startswith("lA_")]
|
||||
|
||||
db_zugriff = Datenbankzugriff(pfad_datenbank)
|
||||
dict_stabwAA_vorinfo = db_zugriff.get_stabw_AA_Netzpunkte()
|
||||
|
||||
liste_varianzkomponenten = db_zugriff.get_varianzkomponentenschaetzung()
|
||||
# Abfrage der numerischen Werte aus der Datenbank
|
||||
dict_stabwAA_vorinfo = self.db_zugriff.get_stabw_AA_Netzpunkte()
|
||||
liste_varianzkomponenten = self.db_zugriff.get_varianzkomponentenschaetzung()
|
||||
|
||||
# Zuordnen des Symbols zum numerischen Wert
|
||||
substitutionen = {}
|
||||
|
||||
for koordinate, stabwAA in dict_stabwAA_vorinfo.items():
|
||||
substitutionen[sp.Symbol(str(koordinate).strip())] = float(stabwAA)
|
||||
|
||||
@@ -412,11 +452,13 @@ class StochastischesModell:
|
||||
varianz_varianzkomponentenschaetzung) in liste_varianzkomponenten:
|
||||
substitutionen[sp.Symbol(f"varkomp_{instrumenteID}_Anschlusspunkte")] = float(varianz_varianzkomponentenschaetzung)
|
||||
|
||||
# Speichern der MAtrix in einer Instanzvariablen
|
||||
if not hasattr(self, "func_QAA_numerisch"):
|
||||
self.func_QAA_numerisch = None
|
||||
if not hasattr(self, "liste_symbole_lambdify_QAA"):
|
||||
self.liste_symbole_lambdify_QAA = []
|
||||
|
||||
# Substituieren
|
||||
if (self.func_QAA_numerisch is None) or (set(self.liste_symbole_lambdify_QAA) != set(substitutionen.keys())):
|
||||
self.liste_symbole_lambdify_QAA = sorted(substitutionen.keys(), key=lambda s: str(s))
|
||||
self.func_QAA_numerisch = sp.lambdify(
|
||||
@@ -440,21 +482,66 @@ class StochastischesModell:
|
||||
return QAA_numerisch
|
||||
|
||||
@staticmethod
|
||||
def berechne_P(Q_ll):
|
||||
def berechne_P(Q_ll: np.ndarray) -> np.ndarray:
|
||||
"""Berechnet die Gewichtsmatrix P aus einer Varianz-Kovarianz-Matrix Qll.
|
||||
|
||||
Die Gewichtsmatrix wird als Inverse von Qll gebildet: P = inv(Qll).
|
||||
|
||||
:param Q_ll: Varianz-Kovarianz-Matrix der Beobachtungen.
|
||||
:type Q_ll: np.ndarray
|
||||
:return: Gewichtsmatrix P.
|
||||
:rtype: np.ndarray
|
||||
"""
|
||||
P = np.linalg.inv(Q_ll)
|
||||
return P
|
||||
|
||||
@staticmethod
|
||||
def berechne_Q_xx(N):
|
||||
def berechne_Q_xx(N: np.ndarray) -> np.ndarray:
|
||||
"""Berechnet die Kofaktormatrix der Unbekannten Qxx aus der Normalgleichungsmatrix N.
|
||||
|
||||
Die Kofaktormatrix wird als Inverse der Normalgleichungsmatrix gebildet: Qxx = inv(N).
|
||||
Vor der Inversion wird geprüft, ob N quadratisch ist.
|
||||
|
||||
:param N: Normalgleichungsmatrix.
|
||||
:type N: np.ndarray
|
||||
:return: Kofaktormatrix der Unbekannten Qxx.
|
||||
:rtype: np.ndarray
|
||||
:raises ValueError: Falls N nicht quadratisch ist.
|
||||
"""
|
||||
if N.shape[0] != N.shape[1]:
|
||||
raise ValueError("N muss eine quadratische Matrix sein")
|
||||
Qxx = np.linalg.inv(N)
|
||||
return Qxx
|
||||
|
||||
def berechne_Q_ll_dach(A, Q_xx):
|
||||
@staticmethod
|
||||
def berechne_Q_ll_dach(A: np.ndarray, Q_xx: np.ndarray) -> np.ndarray:
|
||||
"""Berechnet die (geschätzte) Varianz-Kovarianz-Matrix der Beobachtungen Qll_dach.
|
||||
|
||||
Die Matrix wird gemäß Qll_dach = A @ Qxx @ A.T gebildet.
|
||||
|
||||
:param A: Jacobi-Matrix.
|
||||
:type A: np.ndarray
|
||||
:param Q_xx: Kofaktormatrix der Unbekannten.
|
||||
:type Q_xx: np.ndarray
|
||||
:return: Geschätzte Varianz-Kovarianz-Matrix der Beobachtungen Qll_dach.
|
||||
:rtype: np.ndarray
|
||||
"""
|
||||
Q_ll_dach = A @ Q_xx @ A.T
|
||||
return Q_ll_dach
|
||||
|
||||
def berechne_Qvv(Q_ll, Q_ll_dach):
|
||||
@staticmethod
|
||||
def berechne_Qvv(Q_ll: np.ndarray, Q_ll_dach: np.ndarray) -> np.ndarray:
|
||||
"""Berechnet die Varianz-Kovarianz-Matrix der Residuen Qvv.
|
||||
|
||||
Die Residuenkovarianz wird als Differenz aus Beobachtungs-Kovarianz und dem durch das Modell erklärten Anteil gebildet:
|
||||
Qvv = Qll - Qll_dach.
|
||||
|
||||
:param Q_ll: Varianz-Kovarianz-Matrix der Beobachtungen.
|
||||
:type Q_ll: np.ndarray
|
||||
:param Q_ll_dach: Geschätzte Varianz-Kovarianz-Matrix der Beobachtungen.
|
||||
:type Q_ll_dach: np.ndarray
|
||||
:return: Varianz-Kovarianz-Matrix der Residuen Qvv.
|
||||
:rtype: np.ndarray
|
||||
"""
|
||||
Q_vv = Q_ll - Q_ll_dach
|
||||
return Q_vv
|
||||
Reference in New Issue
Block a user