from dataclasses import dataclass import numpy as np from scipy import stats from scipy.stats import norm import pandas as pd @dataclass class Zuverlaessigkeit: def gesamtredundanz(n, u): r = n - u return r def berechne_R(Q_vv, P): R = Q_vv @ P return R #Redundanzmatrix def berechne_ri(R): ri = np.diag(R) EVi = 100.0 * ri return ri, EVi #Redundanzanteile def klassifiziere_ri(ri): #Klassifizierung der Redundanzanteile if ri < 0.01: return "nicht kontrollierbar" elif ri < 0.10: return "schlecht kontrollierbar" elif ri < 0.30: return "ausreichend kontrollierbar" elif ri < 0.70: return "gut kontrollierbar" else: return "nahezu vollständig redundant" def globaltest(r_gesamt, sigma0_apost, sigma0_apriori, alpha): T_G = (sigma0_apost ** 2) / (sigma0_apriori ** 2) F_krit = stats.f.ppf(1 - alpha, r_gesamt, 10 ** 9) H0 = T_G <= F_krit if H0: interpretation = ( "Nullhypothese H₀ angenommen.\n" ) else: interpretation = ( "Nullhypothese H₀ verworfen!\n" "Dies kann folgende Gründe haben:\n" "→ Es befinden sich grobe Fehler im Datenmaterial.\n" "→ Das funktionale Modell ist fehlerhaft.\n" "→ Das stochastische Modell ist zu optimistisch." ) return { "r_gesamt": r_gesamt, "sigma0_apost": sigma0_apost, "sigma0_apriori": sigma0_apriori, "alpha": alpha, "T_G": T_G, "F_krit": F_krit, "H0_angenommen": H0, "Interpretation": interpretation, } def lokaltest_innere_Zuverlaessigkeit(v, Q_vv, ri, labels, s0_apost, alpha, beta): v = np.asarray(v, float).reshape(-1) Q_vv = np.asarray(Q_vv, float) ri = np.asarray(ri, float).reshape(-1) labels = list(labels) # Standardabweichungen der Residuen qv = np.diag(Q_vv).astype(float) s_vi = float(s0_apost) * np.sqrt(qv) # Quantile k und kA (zweiseitig), k = float(norm.ppf(1 - alpha / 2)) kA = float(norm.ppf(1 - beta)) # (Testmacht 1-β) # Nichtzentralitätsparameter δ0 nzp = k + kA # Normierte Verbesserung NV NV = np.abs(v) / s_vi # Grenzen für v_i v_grenz = k * s_vi v_min = -v_grenz v_max = v_grenz # Grobfehlerabschätzung: ri_safe = np.where(ri == 0, np.nan, ri) GF = -v / ri_safe # Grenzwert für die Aufdeckbarkeit eines GF (GRZW) GRZW_i = (s_vi / ri_safe) * k auffaellig = NV > k Lokaltest_innere_Zuv = pd.DataFrame({ "Beobachtung": labels, "v_i": v, "r_i": ri, "s_vi": s_vi, "k": k, "NV_i": NV, "auffaellig": auffaellig, "v_min": v_min, "v_max": v_max, "GF_i": GF, "GRZW_v": v_grenz, # = k*s_vi "GRZW_i": GRZW_i, # = (s_vi/r_i)*k "alpha": alpha, "beta": beta, "kA": kA, "δ0": nzp, }) return Lokaltest_innere_Zuv def EinflussPunktlage(df_lokaltest): df = df_lokaltest.copy() r = df["r_i"].astype(float).to_numpy() GF = df["GF_i"].astype(float).to_numpy() nzp = df["δ0"].astype(float).to_numpy() EF = np.sqrt((1 - r) / r) * nzp EP = (1 - r) * GF df["δ0"] = nzp df["EF_i"] = EF df["EP_i"] = EP EinflussPunktlage = df[["Beobachtung", "r_i", "GF_i", "EF_i", "EP_i", "δ0", "alpha", "beta"]] return EinflussPunktlage def aeussere_zuverlaessigkeit_EF(Qxx, A, P, s0_apost, GRZW, labels): Qxx = np.asarray(Qxx, float) A = np.asarray(A, float) P = np.asarray(P, float) GRZW = np.asarray(GRZW, float).reshape(-1) labels = list(labels) B = Qxx @ (A.T @ P) EF = np.empty_like(GRZW, dtype=float) # Für jede Beobachtung i: ∇x_i = B[:,i] * GRZW_i # EF_i^2 = (GRZW_i^2 * B_i^T Qxx^{-1} B_i) / s0^2 for i in range(len(GRZW)): bi = B[:, i] # (u,) y = np.linalg.solve(Qxx, bi) # = Qxx^{-1} bi EF2 = (GRZW[i] ** 2) * float(bi @ y) / (float(s0_apost) ** 2) EF[i] = np.sqrt(EF2) df = pd.DataFrame({ "Beobachtung": labels, "GRZW_i": GRZW, "EF_i": EF }) return df