113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
import numpy as np
|
|
import plotly.graph_objects as go
|
|
from scipy.stats import f as f_dist
|
|
|
|
|
|
class Genauigkeitsmaße:
|
|
|
|
|
|
@staticmethod
|
|
def berechne_s0apost(v: np.ndarray, P: np.ndarray, r: int) -> float:
|
|
vTPv_matrix = v.T @ P @ v
|
|
vTPv = float(vTPv_matrix.item())
|
|
s0apost = np.sqrt(vTPv / r)
|
|
return float(s0apost)
|
|
|
|
|
|
@staticmethod
|
|
def berechne_helmert_punktfehler_3D(Qxx_matrix: np.ndarray, s0apost: float, punkt_namen: list) -> dict:
|
|
helmert_punktfehler_ergebnisse_3D = {}
|
|
diag_Q = np.diag(Qxx_matrix)
|
|
if len(diag_Q) < len(punkt_namen) * 3:
|
|
raise ValueError("Die Matrix Qxx ist zu klein für die Anzahl der Punkte (3D erwartet).")
|
|
for i, name in enumerate(punkt_namen):
|
|
idx_x, idx_y, idx_z = 3 * i, 3 * i + 1, 3 * i + 2
|
|
q_xx, q_yy, q_zz = diag_Q[idx_x], diag_Q[idx_y], diag_Q[idx_z]
|
|
helmert_punktfehler_3D = s0apost * np.sqrt(q_xx + q_yy + q_zz)
|
|
helmert_punktfehler_ergebnisse_3D[name] = round(float(helmert_punktfehler_3D), 4)
|
|
return helmert_punktfehler_ergebnisse_3D
|
|
|
|
|
|
@staticmethod
|
|
def berechne_standardellipsen(Qxx: np.ndarray, s0: float, punkt_namen: list):
|
|
standardellipsen = []
|
|
for i, name in enumerate(punkt_namen):
|
|
ix, iy = 3 * i, 3 * i + 1
|
|
qxx, qyy, qxy = Qxx[ix, ix], Qxx[iy, iy], Qxx[ix, iy]
|
|
k = np.sqrt((qxx - qyy) ** 2 + 4 * qxy ** 2)
|
|
qa, qb = 0.5 * (qxx + qyy + k), 0.5 * (qxx + qyy - k)
|
|
a, b = s0 * np.sqrt(qa), s0 * np.sqrt(qb)
|
|
theta = 0.5 * np.arctan2(2 * qxy, qxx - qyy)
|
|
standardellipsen.append({
|
|
"name": name, "a": a, "b": b, "theta": theta, "prob": 0.39 # Standard ca. 39%
|
|
})
|
|
return standardellipsen
|
|
|
|
|
|
@staticmethod
|
|
def berechne_konfidenzellipsen(Qxx: np.ndarray, s0: float, r: int, punkt_namen: list,
|
|
wahrscheinlichkeit: float = 0.95):
|
|
# Quantil der F-Verteilung (df1=2 für die Ebene, df2=r für Redundanz)
|
|
f_quantil = f_dist.ppf(wahrscheinlichkeit, 2, r)
|
|
k_faktor = np.sqrt(2 * f_quantil)
|
|
|
|
standard_ellipsen = Genauigkeitsmaße.berechne_standardellipsen(Qxx, s0, punkt_namen)
|
|
konfidenz_ellipsen = []
|
|
for ell in standard_ellipsen:
|
|
konfidenz_ellipsen.append({
|
|
"name": ell['name'],
|
|
"a": ell['a'] * k_faktor,
|
|
"b": ell['b'] * k_faktor,
|
|
"theta": ell['theta'],
|
|
"prob": wahrscheinlichkeit,
|
|
"k_faktor": k_faktor
|
|
})
|
|
return konfidenz_ellipsen
|
|
|
|
|
|
@staticmethod
|
|
def plot_ellipsen(punkt_coords: dict, ellipsen_parameter: list, scale: float = 1000):
|
|
fig = go.Figure()
|
|
|
|
# Titel dynamisch anpassen
|
|
prob = ellipsen_parameter[0].get('prob', 0)
|
|
titel = "Standard-Fehlerellipsen" if prob < 0.4 else f"{prob * 100:.0f}% Konfidenzellipsen"
|
|
|
|
for p in ellipsen_parameter:
|
|
name = p['name']
|
|
x0, y0 = punkt_coords[name][0], punkt_coords[name][1]
|
|
a, b, theta = p['a'], p['b'], p['theta']
|
|
|
|
t = np.linspace(0, 2 * np.pi, 100)
|
|
xs, ys = a * scale * np.cos(t), b * scale * np.sin(t)
|
|
|
|
x_plot = x0 + xs * np.cos(theta) - ys * np.sin(theta)
|
|
y_plot = y0 + xs * np.sin(theta) + ys * np.cos(theta)
|
|
|
|
# Punkt
|
|
fig.add_trace(go.Scatter(
|
|
x=[x0], y=[y0], mode='markers+text',
|
|
name=f"Punkt {name}", text=[name], textposition="top right",
|
|
marker=dict(size=8, color='black')
|
|
))
|
|
|
|
# Ellipse
|
|
fig.add_trace(go.Scatter(
|
|
x=x_plot, y=y_plot, mode='lines',
|
|
name=f"Ellipse {name}",
|
|
line=dict(color='blue' if prob > 0.4 else 'red', width=2,
|
|
dash='dash' if prob > 0.4 else 'solid'),
|
|
fill='toself',
|
|
fillcolor='rgba(0, 0, 255, 0.1)' if prob > 0.4 else 'rgba(255, 0, 0, 0.1)',
|
|
hoverinfo='text',
|
|
text=(f"Punkt: {name}<br>a: {a * 1000:.2f} mm<br>"
|
|
f"b: {b * 1000:.2f} mm<br>Theta: {np.degrees(theta):.2f}°")
|
|
))
|
|
|
|
fig.update_layout(
|
|
title=titel,
|
|
xaxis_title="Rechtswert (E) [m]", yaxis_title="Hochwert (N) [m]",
|
|
yaxis=dict(scaleanchor="x", scaleratio=1),
|
|
template="plotly_white", showlegend=True
|
|
)
|
|
return fig |