• Hallo Gast, wir suchen den Renner der Woche 🚴 - vielleicht hast du ein passendes Rennrad in deiner Garage? Alle Infos

GPS-Daten fehlen bei Jedermannrennen – kann ich Strecke und Aktivität kombinieren?

Jens2890

Neuer Benutzer
Registriert
26 November 2024
Beiträge
7
Reaktionspunkte
0
Hallo zusammen,


mir ist leider ein richtig dummer Fehler passiert: Ich bin bei einem Jedermannrennen mitgefahren, habe die Aktivität aber versehentlich als Indoor Cycling gestartet. Dadurch wurden keine GPS-Daten aufgezeichnet. 😞


Jetzt habe ich zwei GPX-Dateien:


  • Eine von meiner Aktivität, mit Zeitstempeln und Sensorwerten, aber ohne GPS-Koordinaten.
  • Eine zweite Datei mit der originalen Strecke, die die GPS-Daten enthält (vom Veranstalter).

Meine Frage:
Kann man diese beiden Dateien irgendwie kombinieren, sodass meine Aktivität mit den GPS-Daten der Strecke verknüpft wird?
Mir geht es nicht um die Leistungsdaten, sondern hauptsächlich darum, die Aktivität bei Sportograf korrekt zuordnen zu können.


Falls jemand eine Lösung oder ein Tool kennt, mit dem man das hinbekommt, wäre ich super dankbar!


Liebe Grüße

Jens
 

Anzeige

Re: GPS-Daten fehlen bei Jedermannrennen – kann ich Strecke und Aktivität kombinieren?
Frag ne KI.

ChatGPT kann Dir ein Python Skript dafür machen oder, jedenfalls hat es mir das angeboten, das auch gleich direkt für Dich übernehmen. Verrückte Welt...

Edit: Was für Sensor-Daten hast Du in Deiner gpx-Datei? Wenn man die zurückgelegte Strecke daraus ermitteln kann, könnte man die GPS-Position sogar so sehr genau interpolieren (lassen).
 
Zuletzt bearbeitet:
Versuch mal hier...

 
Frag ne KI.

ChatGPT kann Dir ein Python Skript dafür machen oder, jedenfalls hat es mir das angeboten, das auch gleich direkt für Dich übernehmen. Verrückte Welt...

Edit: Was für Sensor-Daten hast Du in Deiner gpx-Datei? Wenn man die zurückgelegte Strecke daraus ermitteln kann, könnte man die GPS-Position sogar so sehr genau interpolieren (lassen).

Dank Geschwindigkeitssensor ist die aufgezeichnete Distanz ziemlich genau (ca. 1 km Abweichung auf 100 km – inklusive etwas Rumgerolle am Start/Ziel).
Das müsste doch eine ziemlich gute Grundlage sein, um die Strecke mit meiner Aktivität zeitlich zu synchronisieren.
 
Versuch mal hier...


Ich versuche es mal. Hab gestern damit schon herumgespielt, aber war auch nicht so der bringer. Vielleicht bin ich auch einfcach zu doof dafür :D
 
Habe die KI mal nach einem Python Skript gefragt und das mit ihr ein wenig verfeinert. Das Skript rechnet für die Datenpunkte Deiner Activity und die der Veranstalter-Route die jeweils zurückgelegte Distanz und normiert die Werte der Veranstalter-Route so, dass deren Gesamtlänge mit der Deiner Acitivity übereinstimmt.

Die GPS Positionen der Datenpunkte Deiner Activity werden dann über die Distanz aus der Veranstalter-Route ermittelt. Dabei kannst Du wählen, ob Du lieber die exakten GPS-Koords aus der Veranstalter-Route nehmen willst (da die wahrscheinlich auf der Strecke liegen) oder zwischen den GPS-Koords interpolieren möchtest, was dann zu GPS-Koords führen kann, die außerhalb der Strecke liegen.

Nice dass die KI das vorher auch testet und festgestellt hat, dass man neben Python auch noch zwei Module braucht (zB "pip install gpxpy geopy" oder "apt install python3-geopy python3-gpxpy" to the rescue).


Hier der Python-Code (by Chat-GPT):
Code:
import argparse
import gpxpy
from geopy.distance import geodesic
from datetime import datetime
from xml.dom.minidom import parseString

def get_time_diff_seconds(t1, t2):
    return (t2 - t1).total_seconds() if t1 and t2 else 0

def add_distance_by_speed_with_time(gpx):
    total_distance = 0.0
    for segment in gpx.tracks[0].segments:
        prev = None
        for pt in segment.points:
            if prev:
                dt = get_time_diff_seconds(prev.time, pt.time)
                speed = float(pt.extensions.get("speed", 0))
                total_distance += speed * dt
            pt.extensions['distance'] = round(total_distance, 2)
            prev = pt
    return gpx

def add_distance_by_gps(gpx):
    total_distance = 0.0
    for segment in gpx.tracks[0].segments:
        prev = None
        for pt in segment.points:
            if prev:
                total_distance += geodesic(
                    (prev.latitude, prev.longitude), (pt.latitude, pt.longitude)
                ).meters
            pt.extensions['distance'] = round(total_distance, 2)
            prev = pt
    return gpx

def scale_route_distances(gpx_route, factor):
    for seg in gpx_route.tracks[0].segments:
        for pt in seg.points:
            pt.extensions['distance_scaled'] = round(float(pt.extensions['distance']) * factor, 2)
    return gpx_route

def find_surrounding_points(route_points, target_dist):
    prev, next = None, None
    for pt in route_points:
        dist = pt.extensions.get('distance_scaled', 0)
        if dist <= target_dist:
            prev = pt
        elif dist > target_dist:
            next = pt
            break
    return prev, next

def interpolate_coords(p1, p2, target_dist):
    d1 = p1.extensions['distance_scaled']
    d2 = p2.extensions['distance_scaled']
    ratio = (target_dist - d1) / (d2 - d1) if d2 != d1 else 0
    lat = p1.latitude + ratio * (p2.latitude - p1.latitude)
    lon = p1.longitude + ratio * (p2.longitude - p1.longitude)
    return lat, lon

def merge_gps_into_activity(gpx_activity, gpx_route, mode='nearest'):
    route_pts = [pt for seg in gpx_route.tracks[0].segments for pt in seg.points]
    for seg in gpx_activity.tracks[0].segments:
        for pt in seg.points:
            d = pt.extensions.get('distance', 0)
            prev, nxt = find_surrounding_points(route_pts, d)
            if not prev and not nxt:
                continue
            if mode == "nearest":
                if not prev:
                    chosen = nxt
                elif not nxt:
                    chosen = prev
                else:
                    d_prev = abs(prev.extensions['distance_scaled'] - d)
                    d_next = abs(nxt.extensions['distance_scaled'] - d)
                    chosen = prev if d_prev <= d_next else nxt
                pt.latitude = chosen.latitude
                pt.longitude = chosen.longitude
            elif mode == "interpolate" and prev and nxt:
                lat, lon = interpolate_coords(prev, nxt, d)
                pt.latitude = lat
                pt.longitude = lon
    return gpx_activity

def write_gpx_with_extensions(gpx, filename):
    xml = gpx.to_xml()
    dom = parseString(xml)
    trkpts = dom.getElementsByTagName("trkpt")
    i = 0
    for segment in gpx.tracks[0].segments:
        for pt in segment.points:
            ext_elem = dom.createElement("extensions")
            for key, value in pt.extensions.items():
                el = dom.createElement(key)
                el.appendChild(dom.createTextNode(str(value)))
                ext_elem.appendChild(el)
            trkpts[i].appendChild(ext_elem)
            i += 1
    with open(filename, "w", encoding="utf-8") as f:
        f.write(dom.toprettyxml(indent="  "))

def main():
    parser = argparse.ArgumentParser(description="Merge GPX activity with route GPS.")
    parser.add_argument('--activity', required=True, help="Path to activity GPX file")
    parser.add_argument('--route', required=True, help="Path to route GPX file")
    parser.add_argument('--mode', default="nearest", choices=["nearest", "interpolate"],
                        help="GPS assignment mode")
    args = parser.parse_args()

    with open(args.activity, "r") as f1, open(args.route, "r") as f2:
        gpx_act = gpxpy.parse(f1)
        gpx_rte = gpxpy.parse(f2)

    gpx_act = add_distance_by_speed_with_time(gpx_act)
    gpx_rte = add_distance_by_gps(gpx_rte)

    dist_act = gpx_act.tracks[0].segments[0].points[-1].extensions['distance']
    dist_rte = gpx_rte.tracks[0].segments[0].points[-1].extensions['distance']
    scale_factor = float(dist_act) / float(dist_rte)

    gpx_rte = scale_route_distances(gpx_rte, scale_factor)
    gpx_act = merge_gps_into_activity(gpx_act, gpx_rte, mode=args.mode)

    write_gpx_with_extensions(gpx_act, "gpx_activity_with_gps.gpx")
    write_gpx_with_extensions(gpx_rte, "gpx_route_scaled.gpx")

if __name__ == "__main__":
    main()
 
Zurück