#!/usr/bin/env python3 """ Debug-Skript für Netzausgleichung Prüft Punktevergleich und findet Fehler """ import sys import math sys.path.insert(0, '/home/ubuntu/trimble_geodesy') from modules.jxl_parser import JXLParser from modules.network_adjustment import NetworkAdjustment def main(): # Lade JXL jxl_path = "/home/ubuntu/trimble_geodesy/test_data/Baumschulenstr_93.jxl" parser = JXLParser() parser.parse(jxl_path) print("=" * 80) print("DEBUG: NETZAUSGLEICHUNG") print("=" * 80) # Zeige Winkeleinheit print(f"\n### JXL Einstellungen:") print(f" Winkeleinheit: {parser.angle_units}") # NetworkAdjustment initialisieren adj = NetworkAdjustment(parser) # Beobachtungen extrahieren adj.extract_observations() adj.initialize_points() # Debug: Zeige Beobachtungen print(f"\n### Beobachtungen ({len(adj.observations)} total):") dir_obs = [o for o in adj.observations if o.obs_type == 'direction'] dist_obs = [o for o in adj.observations if o.obs_type == 'distance'] zen_obs = [o for o in adj.observations if o.obs_type == 'zenith'] print(f" Richtungen: {len(dir_obs)}") print(f" Strecken: {len(dist_obs)}") print(f" Zenitwinkel: {len(zen_obs)}") print("\n### Beispiel-Beobachtungen (erste 5 Richtungen):") for obs in dir_obs[:5]: print(f" {obs.from_station} -> {obs.to_point}: {obs.value:.6f} gon (std: {obs.std_dev:.6f})") print("\n### Beispiel-Beobachtungen (erste 5 Strecken):") for obs in dist_obs[:5]: print(f" {obs.from_station} -> {obs.to_point}: {obs.value:.4f} m (std: {obs.std_dev:.6f})") # Koordinaten vor Ausgleichung speichern coords_before = {} for name, pt in adj.points.items(): coords_before[name] = (pt.x, pt.y, pt.z) print(f"\n### Punkte ({len(adj.points)} total):") for name, pt in sorted(adj.points.items()): print(f" {name}: X={pt.x:.4f}, Y={pt.y:.4f}, Z={pt.z:.4f}") # Festpunkte setzen ref_points = parser.get_reference_points() print(f"\n### Referenzpunkte (5xxx): {ref_points}") for name in ref_points: adj.set_fixed_point(name) # Falls keine Referenzpunkte, erste Station als Festpunkt if not adj.fixed_points: print("WARNUNG: Keine Referenzpunkte gefunden!") stations = list(parser.stations.values()) if stations: first_station = min(stations, key=lambda s: s.timestamp) adj.set_fixed_point(first_station.name) print(f" -> Setze {first_station.name} als Festpunkt") print(f"\n### Festpunkte: {adj.fixed_points}") # Zeige berechnete Orientierungen print(f"\n### Berechnete Orientierungen pro Station:") for station_name, orientation in sorted(adj.orientations.items()): print(f" {station_name}: {orientation:.4f} gon") # Konsistenzprüfung print("\n" + "=" * 80) print("KONSISTENZPRÜFUNG") print("=" * 80) consistency = adj.check_consistency() print(f"\n### Ergebnis: {'✅ KONSISTENT' if consistency['consistent'] else '❌ INKONSISTENT'}") if not consistency['consistent']: print("\n### Probleme gefunden:") for issue in consistency['issues']: print(f" ⚠️ {issue}") print("\n### WICHTIG:") print(" Die Koordinaten in der JXL-Datei wurden bereits von Trimble Access") print(" berechnet und sind fertig. Die Beobachtungen (Kreislesungen) sind") print(" rohe Messwerte, die nicht mit den berechneten Koordinaten konsistent") print(" verglichen werden können, da die Orientierungen stark variieren.") print("") print(" Eine Netzausgleichung mit diesen Daten ist nicht sinnvoll, da sie") print(" die bereits korrekten Koordinaten verschlechtern würde.") print("") print(" Empfehlung: Verwenden Sie die ausgeglichenen Koordinaten aus der JXL") print(" direkt, ohne weitere Ausgleichung.") # Ausgleichung durchführen (nur Residuen, keine Koordinatenänderung) print("\n### Starte Residuenanalyse (keine Koordinatenänderung)...") try: result = adj.adjust(mode="residuals_only") print(f"\n### Ergebnis:") print(f" Konvergiert: {result.converged}") print(f" Iterationen: {result.iterations}") print(f" Sigma-0 posteriori: {result.sigma_0_posteriori:.6f}") print(f" Redundanz: {result.redundancy}") # PUNKTEVERGLEICH print("\n" + "=" * 100) print("PUNKTEVERGLEICH: VORHER vs. NACHHER") print("=" * 100) print(f"{'Punkt':<10} {'X_vorher':>12} {'Y_vorher':>12} {'Z_vorher':>10} | {'X_nachher':>12} {'Y_nachher':>12} {'Z_nachher':>10} | {'ΔX':>10} {'ΔY':>10} {'ΔZ':>10} {'Δ3D':>10}") print("-" * 120) deviations = [] for name, pt in sorted(adj.points.items()): x_before, y_before, z_before = coords_before[name] x_after, y_after, z_after = pt.x, pt.y, pt.z dx = x_after - x_before dy = y_after - y_before dz = z_after - z_before d3d = math.sqrt(dx**2 + dy**2 + dz**2) deviations.append((name, dx, dy, dz, d3d, pt.is_fixed)) fixed_marker = "*" if pt.is_fixed else " " print(f"{name:<10}{fixed_marker} {x_before:>12.4f} {y_before:>12.4f} {z_before:>10.4f} | " f"{x_after:>12.4f} {y_after:>12.4f} {z_after:>10.4f} | " f"{dx:>10.4f} {dy:>10.4f} {dz:>10.4f} {d3d:>10.4f}") # PLAUSIBILITÄTSPRÜFUNG print("\n" + "=" * 80) print("PLAUSIBILITÄTSPRÜFUNG") print("=" * 80) # Sortiert nach größter Abweichung deviations_sorted = sorted(deviations, key=lambda x: x[4], reverse=True) # Warnungen critical_errors = [] warnings = [] for name, dx, dy, dz, d3d, is_fixed in deviations_sorted: if not is_fixed: if d3d > 1.0: critical_errors.append((name, d3d)) elif d3d > 0.1: warnings.append((name, d3d)) if critical_errors: print("\n🚨 KRITISCHE FEHLER (Abweichung > 1m):") for name, d3d in critical_errors: print(f" ❌ {name}: {d3d:.4f} m") if warnings: print("\n⚠️ WARNUNGEN (Abweichung > 10cm):") for name, d3d in warnings: print(f" ⚠ {name}: {d3d:.4f} m") # Statistik non_fixed_deviations = [d for d in deviations if not d[5]] if non_fixed_deviations: d3d_values = [d[4] for d in non_fixed_deviations] dx_values = [abs(d[1]) for d in non_fixed_deviations] dy_values = [abs(d[2]) for d in non_fixed_deviations] print("\n### Statistik (nur Neupunkte):") print(f" Anzahl Punkte: {len(non_fixed_deviations)}") print(f" Min Δ3D: {min(d3d_values):.6f} m") print(f" Max Δ3D: {max(d3d_values):.6f} m") print(f" Mittel Δ3D: {sum(d3d_values)/len(d3d_values):.6f} m") print(f" Max |ΔX|: {max(dx_values):.6f} m") print(f" Max |ΔY|: {max(dy_values):.6f} m") if not critical_errors and not warnings: print("\n✅ Alle Koordinaten unverändert (wie erwartet bei residuals_only)") # RESIDUEN-ANALYSE print("\n" + "=" * 80) print("RESIDUENANALYSE") print("=" * 80) dir_obs = [o for o in adj.observations if o.obs_type == 'direction'] dist_obs = [o for o in adj.observations if o.obs_type == 'distance'] dir_residuals = [o.residual * 1000 for o in dir_obs] # in mgon dist_residuals = [o.residual * 1000 for o in dist_obs] # in mm if dir_residuals: print(f"\n### Richtungsresiduen (in mgon):") print(f" Anzahl: {len(dir_residuals)}") print(f" Min: {min(dir_residuals):.2f} mgon") print(f" Max: {max(dir_residuals):.2f} mgon") print(f" RMSE: {math.sqrt(sum(r**2 for r in dir_residuals)/len(dir_residuals)):.2f} mgon") if dist_residuals: print(f"\n### Streckenresiduen (in mm):") print(f" Anzahl: {len(dist_residuals)}") print(f" Min: {min(dist_residuals):.2f} mm") print(f" Max: {max(dist_residuals):.2f} mm") print(f" RMSE: {math.sqrt(sum(r**2 for r in dist_residuals)/len(dist_residuals)):.2f} mm") # Zeige größte Residuen print(f"\n### Größte Richtungsresiduen:") sorted_dir = sorted(dir_obs, key=lambda x: abs(x.residual), reverse=True)[:5] for obs in sorted_dir: print(f" {obs.from_station} -> {obs.to_point}: {obs.residual*1000:.2f} mgon") print(f"\n### Größte Streckenresiduen:") sorted_dist = sorted(dist_obs, key=lambda x: abs(x.residual), reverse=True)[:5] for obs in sorted_dist: print(f" {obs.from_station} -> {obs.to_point}: {obs.residual*1000:.2f} mm") # Qualitätsbewertung rmse_dir = math.sqrt(sum(r**2 for r in dir_residuals)/len(dir_residuals)) if dir_residuals else 0 rmse_dist = math.sqrt(sum(r**2 for r in dist_residuals)/len(dist_residuals)) if dist_residuals else 0 print("\n### Qualitätsbewertung:") if rmse_dir < 10: print(f" ✅ Richtungen: SEHR GUT (RMSE < 10 mgon)") elif rmse_dir < 50: print(f" ✅ Richtungen: GUT (RMSE < 50 mgon)") elif rmse_dir < 100: print(f" ⚠️ Richtungen: AKZEPTABEL (RMSE < 100 mgon)") else: print(f" ❌ Richtungen: SCHLECHT (RMSE = {rmse_dir:.2f} mgon)") if rmse_dist < 5: print(f" ✅ Strecken: SEHR GUT (RMSE < 5 mm)") elif rmse_dist < 20: print(f" ✅ Strecken: GUT (RMSE < 20 mm)") elif rmse_dist < 50: print(f" ⚠️ Strecken: AKZEPTABEL (RMSE < 50 mm)") else: print(f" ❌ Strecken: SCHLECHT (RMSE = {rmse_dist:.2f} mm)") # Prüfe ob Problem besteht max_d3d = max(d[4] for d in non_fixed_deviations) if non_fixed_deviations else 0 if max_d3d > 1.0: print("\n" + "=" * 80) print("🔍 FEHLERANALYSE") print("=" * 80) # Prüfe berechnete vs. beobachtete Richtungen print("\n### Prüfung Richtungsbeobachtungen:") for obs in dir_obs[:3]: from_pt = adj.points.get(obs.from_station) to_pt = adj.points.get(obs.to_point) if from_pt and to_pt: dx = to_pt.x - from_pt.x dy = to_pt.y - from_pt.y # Berechne Azimut in Gon (aus X,Y) azimuth_calc = math.atan2(dx, dy) * 200.0 / math.pi if azimuth_calc < 0: azimuth_calc += 400.0 diff = obs.value - azimuth_calc while diff > 200: diff -= 400 while diff < -200: diff += 400 print(f" {obs.from_station} -> {obs.to_point}:") print(f" Beobachtet: {obs.value:.6f} gon") print(f" Berechnet: {azimuth_calc:.6f} gon") print(f" Differenz: {diff:.6f} gon ({diff*10000:.2f} mgon)") # Prüfe berechnete vs. beobachtete Strecken print("\n### Prüfung Streckenbeobachtungen:") for obs in dist_obs[:3]: from_pt = adj.points.get(obs.from_station) to_pt = adj.points.get(obs.to_point) if from_pt and to_pt: dx = to_pt.x - from_pt.x dy = to_pt.y - from_pt.y dz = to_pt.z - from_pt.z dist_calc_3d = math.sqrt(dx**2 + dy**2 + dz**2) dist_calc_2d = math.sqrt(dx**2 + dy**2) diff_3d = obs.value - dist_calc_3d diff_2d = obs.value - dist_calc_2d print(f" {obs.from_station} -> {obs.to_point}:") print(f" Beobachtet: {obs.value:.6f} m") print(f" Berechnet 3D: {dist_calc_3d:.6f} m (Diff: {diff_3d*1000:.2f} mm)") print(f" Berechnet 2D: {dist_calc_2d:.6f} m (Diff: {diff_2d*1000:.2f} mm)") except Exception as e: print(f"FEHLER: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()