Homepage

Willkommen

Digitales für den Unterricht

Medienbildung für alle (2001)

GrandOrgue-Orgelsoftware

Eine statische Website mit pmWiki erstellen - zur Programmierung dieser Seite

Wichtige Hinweise

GPX-Tracks lesen und konvertieren mit Perl

- Alle Angaben ohne Gewähr -

1. Das gpx-Dateiformat

Das gpx-Dateiformat ist eine Ausprägung von xml, die dazu gemacht ist, Ortsmarkierungen und "Tracks", die ein gps-Logger liefert, zu speichern. Zu jedem Ortspunkt eines Tracks werden in der gpx-Datei Längen- und Breitengrad, Höhe über Normalnull und Zeit gespeichert. In der Praxis sieht ein solcher Punkt dann so aus:

<trkpt lat="50.633218288" lon="6.476848125">
  <ele>200.091675</ele>
  <time>2011-10-30T13:21:55Z</time>
</trkpt>

2. Das Problem

Um eine als gpx-Datei (eine fiktive Musterdatei steht hier zum Download bereit - bitte als Muster.gpx abspeichern) gespeicherte Bewegung analysieren zu können, soll sie in ein Format gebracht werxen, dass mit jeder beliebigen Tabellenkalkulation eingelesen werden kann; das csv-Format ist hier besonders geeignet. Für die Umwandlung soll ein Perl-Skript sorgen, das leicht an die besonderen Anforderungen des Nutzers angepasst werden kann.

3. Zugriff auf eine gpx-Datei mit XML::Twig1)

Es gibt eine Reihe von Perl-Modulen, die Perl-Skripte in die Lage versetzen, einfach mit xml-, also insbesondere auch mit gpx-Daten umzugehen. Hier ist - letztlich mehr oder minder zufällig - die Entscheidung zugunsten von XML::Twig gefallen. Ein erstes Beispiel zeigt den Zugriff auf eine gpx-Datei mit XML::Twig:

#!/usr/bin/perl -w
# gpx2con.pl
# Aufruf: perl gpx2con.pl Muster.gpx
use strict;
use XML::Twig;
use Date::Parse;
#
my $datei = $ARGV[0];
my $twig_handlers = {'trkpt' => \&behandlung};
my $twig = new XML::Twig(TwigRoots => {trkpt => 1},
                    TwigHandlers => $twig_handlers);
$twig->parsefile($datei);
#
sub behandlung{
  my ($twig, $wert) = @_;
  my $lat = $wert->att('lat');
  print $lat . ";";
  my $lon = $wert->att('lon');
  print $lon . ";";
  my $ele = $wert->first_child('ele')->text();
  print $ele . ";";
  my $isotime = $wert->first_child('time')->text();
  my $time = str2time($isotime);
  print $time . "\n";
}

Das Skript (hier zum Download) gibt Längengrad, Breitengrad, Höhe und Zeit (in Sekunden seit ...) im Terminal (Standardausgabe) aus. Auf den ersten Blick fällt auf, dass Längen- und Breitengrad prinzipiell anders behandelt werden als Höhe und Zeit: Breiten- und Längengrad werden als Attribute (att) des jeweiligen TRKPTs (Trackpoints) behandelt, Höhe und Zeit sind Kinder (first_child) des jeweiligenTRKPTs bzw. GPS-Punktes.

4. Die Rundum-sorglos-Lösung

Das eben dargestellte Skript tut eigentlich schon alles, was notwendig ist, um eine csv-Datei und damit eine Tabellenkalkulationsdatei zu erzeugen. Speichert man die (Standard-)Ausgabe per Ausgabeumleitung oder mittels Copy&Paste als Datei ab, ist man schon am Ziel. Nun ist aber Perl dazu gemacht, Textdateien - und csv-Dateien sind letztlich Texte - komfortabel zu bearbeiten; so liegt es also nahe gleich beim Übertragen der Daten das zu erledigen, was eine Tabellenkalkulation auch nicht besser kann:

  • Dezimalpunkte durch Dezimalkommas ersetzen, falls mit deutschen Sprachkonventionen gearbeitet werden soll,
  • weitere Werte berechnen, etwa die Entfernung zwischen zwei aufeinander folgenden Wegpunkten,
  • eine "Kopfzeile" einfügen, die beschreibt, was in der jeweiligen Spalte steht.

All das leistet das nachfolgende Perl-Skript:

#!/usr/bin/perl -w
# gpx2csv.pl, Stand 06.01.2013
# ---------------------------------
# Aufruf: perl gpx2csv Muster.gpx #
# ---------------------------------
use strict;
use XML::Twig;
use Date::Parse;
use Math::BigFloat;
use Math::Trig;
#
our $count=0;
our $lat; our $latrad; our $lat0rad;
our $lon; our $lonrad; our $lon0rad;
our $ele;
our $time; our $time0;
our $zeit=0; our $zeit0=0;
our $isotime;
our $vzeit=0;
our $weg=0; 
our $dweg=0;
our $v;
#
open ZIEL, ">", $ARGV[0] . ".csv";
print ZIEL "lat;lon;ele;time;t[s];s[m];t_v[s];v[m/s]" . "\n";
my $datei = $ARGV[0];
#
my $twig_handlers = {'trkpt' => \&behandlung};
my $twig = new XML::Twig(TwigRoots => {trkpt => 1},
                    TwigHandlers => $twig_handlers);
$twig->parsefile($datei);
print $datei . " in csv-Datei konvertiert\n";
#---#
sub behandlung{
  my ($twig, $wert) = @_;
  $lat = $wert->att('lat');
  $lon = $wert->att('lon');
  if ($count>0){
    $lat0rad=$latrad;
    $lon0rad=$lonrad;
    $zeit0=$zeit;
  };
  $latrad=pi*($lat/180);
  $lonrad=pi*($lon/180);
  if ($count>0){
    $dweg=6378388*acos(sin($lat0rad)*sin($latrad)
          +cos($lat0rad)*cos($latrad)*cos($lonrad-$lon0rad));
    $weg=$weg+$dweg
  }  
  $_ = $lat;   s/\./,/g;
  print ".";   
  print ZIEL $_ . ";";
  $_ = $lon;   s/\./,/g;
  print "."; 
  print ZIEL $_ . ";";
  $ele = $wert->first_child('ele')->text();
  $_ = $ele;   s/\./,/g;
  print ".";   
  print ZIEL $_ . ";";
  $isotime = $wert->first_child('time')->text();
  $time = str2time($isotime);
  if ($count==0){$time0 = $time};
  $zeit=$time-$time0;
  $_ = $time;   s/\./,/g;
  print ".";
  print ZIEL $_ . ";";
  $_ = $zeit;   s/\./,/g;
  print ".";
  print ZIEL $_ . ";";
  $_ = $weg;   s/\./,/g;
  print ".";
  print ZIEL $_ . ";";
  if (($count>0) && ($zeit != $zeit0)){
    $vzeit=($zeit+$zeit0)/2;
    $_ = $vzeit; s/\./,/g;
    print ZIEL $_ . ";";
    $v=$dweg/($zeit-$zeit0);
    $_ = $v;   s/\./,/g;
    print "..\n";
    print ZIEL $_ . "\n"
    }
  else {
    print "..\n";
    print ZIEL ";\n"
    };
  if ($count==0){$count++};
}

Das Skript (hier zum Download) liefert folgende Werte:

  • den Breitengrad (lat),
  • den Längengrad (lon),
  • die Höhe über Normalnull (ele),
  • die Zeit (time) in Sekunden seit dem 1. Januar 1970 (Unix-Zeit),
  • die seit dem ersten Trackpoint vergangene Zeit (t[s]),
  • der seit dem ersten Trackpoint (=Ausgangspunkt) zurückgelegte Weg (s[m]) als Summe der einzelnen Wegstücke (und nicht als Entfernung vom Ausgangspunkt),
  • die seit dem ersten Trackpoint vergangene Zeit (t_v[s]) - und zwar für den Zeitpunkt, dem die nachfolgend aufgeführte Geschwindigkeit v "in etwa" zuzuordnen ist,
  • die Durchschnittsgeschwindigkeit (v[m/s]) für das Teilstück zwischen dem vorigen und dem aktuellen Trackpont.

Das Ergebnis der Umwandlung kann problemlos mit einer Tabellenkalkulation, etwa mit LibreOffice oder OpenOffice, weiterbearbeitet werden. (Das Ergebnis kann z.B. so aussehen, wie es die hier hinterlegte pdf-Datei zeigt. Dass das erstellte Diagramm sich so "sauber" darstellt, liegt daran, dass die gpx-Datei fiktiv, also am Schreibtisch "zusammengebastelt" ist.)

5. Literaturhinweise

1) Diese Darstellung fasst im Wesentlichen nur zusammen, was in verschiedenen Internetquellen (siehe Literaturliste) zum Thema zu finden ist; den Autoren verdanke ich die Vorschläge zur Lösung meines Problems - mögliche Fehler und Ungenauigkeiten habe ich verursacht.


www.nadenau.de, page last modified on October 01, 2014, at 10:00 PM