import numpy as np import plotly.graph_objects as go from scipy.stats import f as f_dist import pandas as pd 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) def helmert_punktfehler(Qxx, s0_apost, unbekannten_liste, dim=3): diagQ = np.diag(Qxx) daten = [] n_punkte = len(unbekannten_liste) // 3 for i in range(n_punkte): sym_x = str(unbekannten_liste[3 * i]) # z.B. "X10009" punkt = sym_x[1:] # -> "10009" qx = diagQ[3 * i] qy = diagQ[3 * i + 1] qz = diagQ[3 * i + 2] sx = s0_apost * np.sqrt(qx) sy = s0_apost * np.sqrt(qy) sz = s0_apost * np.sqrt(qz) if dim == 2: sP = s0_apost * np.sqrt(qx + qy) else: sP = s0_apost * np.sqrt(qx + qy + qz) daten.append([ punkt, float(sx), float(sy), float(sz), float(sP) ]) helmert_punktfehler = pd.DataFrame(daten, columns=["Punkt", "σx", "σy", "σz", f"σP_{dim}D"]) return helmert_punktfehler def standardellipse(Qxx, s0_apost, unbekannten_liste, dim_labels=3): Qxx = np.asarray(Qxx, float) data = [] n_punkte = len(unbekannten_liste) // dim_labels for i in range(n_punkte): sym_x = str(unbekannten_liste[dim_labels * i]) # z.B. "X10009" punkt = sym_x[1:] # -> "10009" ix = dim_labels * i iy = dim_labels * i + 1 # 2x2-Kofaktorblock Qxx_ = Qxx[ix, ix] Qyy_ = Qxx[iy, iy] Qyx_ = Qxx[iy, ix] # Standardabweichungen der Koordinatenkomponenten sx = s0_apost * np.sqrt(Qxx_) sy = s0_apost * np.sqrt(Qyy_) sxy = (s0_apost ** 2) * Qyx_ # k und Eigenwerte (Q_dmax, Q_dmin) k = np.sqrt((Qxx_ - Qyy_) ** 2 + 4 * (Qyx_ ** 2)) Q_dmax = 0.5 * (Qxx_ + Qyy_ + k) Q_dmin = 0.5 * (Qxx_ + Qyy_ - k) # Halbachsen (Standardabweichungen entlang Hauptachsen) s_max = s0_apost * np.sqrt(Q_dmax) s_min = s0_apost * np.sqrt(Q_dmin) # Richtungswinkel theta (Hauptachse) in rad: theta_rad = 0.5 * np.arctan2(2 * Qyx_, (Qxx_ - Qyy_)) # in gon theta_gon = theta_rad * (200 / np.pi) if theta_gon < 0: theta_gon += 200.0 data.append([ punkt, float(sx), float(sy), float(sxy), float(s_max), float(s_min), float(theta_gon) ]) standardellipse = pd.DataFrame(data, columns=["Punkt", "σx", "σy", "σxy", "s_max", "s_min", "θ [gon]"]) return standardellipse def konfidenzellipse(Qxx, s0_apost, unbekannten_liste, R, alpha=0.05): Qxx = np.asarray(Qxx, float) data = [] n_punkte = len(unbekannten_liste) // 3 # X,Y,Z je Punkt angenommen k = float(np.sqrt(2.0 * f_dist.ppf(1.0 - alpha, 2, R))) for i in range(n_punkte): punkt = str(unbekannten_liste[3 * i])[1:] # "X10009" -> "10009" ix = 3 * i iy = 3 * i + 1 Qxx_ = Qxx[ix, ix] Qyy_ = Qxx[iy, iy] Qxy_ = Qxx[iy, ix] # = Qyx # k für Eigenwerte kk = np.sqrt((Qxx_ - Qyy_) ** 2 + 4 * (Qxy_ ** 2)) Q_dmax = 0.5 * (Qxx_ + Qyy_ + kk) Q_dmin = 0.5 * (Qxx_ + Qyy_ - kk) # Standard-Halbachsen (1-sigma) s_max = s0_apost * np.sqrt(Q_dmax) s_min = s0_apost * np.sqrt(Q_dmin) # Orientierung (Hauptachse) in gon theta_rad = 0.5 * np.arctan2(2 * Qxy_, (Qxx_ - Qyy_)) theta_gon = theta_rad * (200 / np.pi) if theta_gon < 0: theta_gon += 200.0 # Konfidenz-Halbachsen a_K = k * s_max b_K = k * s_min data.append([punkt, float(a_K), float(b_K), float(theta_gon)]) konfidenzellipsen = pd.DataFrame(data, columns=["Punkt", "a_K", "b_K", "θ [gon]"]) return konfidenzellipsen @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