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}
a: {a * 1000:.2f} mm
" f"b: {b * 1000:.2f} mm
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