Anpassungen in Maxima

Anpassung an die von RTKCONV erzeugte OBS-Datei

 

Unterschiede in den RINEX-Dateien

Die mit den neueren Chips NEO-M8P-2 und ZED-F9P erzeugten ubx-Dateien können nicht mehr mit dem Programm teqc in RINEX-Dateien konvertiert werden, vielmehr kann nun das benutzerfreundlichere Programm RTKCONV verwendet werden. Leider lässt sich RTKCONV nicht umgekehrt zur Konvertierung der mit dem NEO-6P-Chip generierten Aufnahmen verwenden, da es die jeweiligen NAV-Dateien nicht erzeugt. Im Gegensatz zu den von teqc erzeugten RINEX-Beobachtungsdaten liefert RTKCONV diese Dateien allerdings in einer leicht veränderten Struktur, so dass wir die im Buch vorgestellten Transferfunktionen verändern müssen.

Zum Vergleich der Beginn einer traditionell mit teqc erstellten Beobachtungsdatei:

obs teqc

 

Im Unterschied dazu dieselbe Beobachtungsdatei, die von RTKCONV erstellt wurde:

obs RTKCONV

Die Beobachtungscluster werden in beiden Versionen immer von einer Einleitungszeile mit dem Aufnahmedatum und der Aufnahmezeit sowie der Anzahl der empfangenen Satelliten eingeleitet. Während in der teqc-Version darauf unmittelbar die Nummern der Satelliten folgen, schreibt RTKCONV diese Satellitennummern als erste Spalte in den Beobachtungsblock, so dass die Zeilen den einzelnen Satelliten schnell und eindeutig zugeordent werden können.

In der Einleitungszeile der RTKCONV-Version wird die Jahreszahl vierstellig angegeben, außerdem beginnt diese Zeile mit einem ">"-Zeichen. Dadurch erhöhen sich die Indices der weiteren Listenelemente um eins.

Die Pseudoentfernungen stehen in der teqc-Version in der dritten Spalte, während diese in der RTKCONV-Version direkt nach den Satellitennummern in der zweiten Spalte aufgeführt werden.

Diese strukturellen Unterschiede sind im Übrigen unabhängig von der in RTKCONV gewählten RINEX-Version, so dass für die Nutzung der neueren GPS-Chips die Maximafunktionen zum Erstellen der "obsmatrix" verändert werden müssen.

Die Navigationsdatei ist nur marginal verändert: Eine von RTKCONV erzeugte Navigationsdatei gibt die Satellitennummer immer dreistellig mit vorangstelltem "G" als Kennung für einen GPS-Satelliten an, außerdem wird die Jahreszahl des Datums wie in der Beobachtungsdatei vierstellig angegeben. Diese Unterschiede hat aber für den Einlesevorgang keine Auswirkung, sie wurden bereits mit der im Buch vorgestellten Funktion zum Erstellen der "navmatrix" berücksichtigt.

 

Anpassung einzelner Funktionen

Um jeweils beide Versionen der zu verändernden Funktionen behalten zu können, wird als Unterscheidungsmerkmal jeweils die Ziffer "8" an die neuen Versionen angehängt.

read_obstime()

Die Funktion zum Lesen der Beobachtungszeit muss aufgrund des in der Einleitungszeile vorangestellten ">"-Zeichens und der nun vierstellig angegebenen Jahreszahl verändert werden. Die Indices werden jeweils um eins erhöht und die Addition von 2000 zur Jahreszahl entfällt:

read_obstime8(zeile):=
gps_time(julday(zeile[2],zeile[3],zeile[4],zeile[5],zeile[6],zeile[7]));

read_satnr()

Zum Lesen der jeweiligen Satellitennummer und zur Überprüfung, ob es sich um einen GPS-Satelliten handelt, von welchem zudem Navigationsdaten vorliegen, muss die Funktion read_satnr() angepasst werden. Durch den einfacheren Aufbau der Beobachtungsdatei, wo nun Satellitennummer und Pseudoentfernung jeweils direkt nebeneinander in einer Zeile stehen, wird diese Funktion etwas einfacher:

read_satnr8(eintrag):=block(
[zeichenkette,z,e,navsatlist],
zeichenkette:string(eintrag),
satnr:if charat(zeichenkette,1)="G" then
   (
   z:eval_string(charat(zeichenkette,2)),
   e:eval_string(charat(zeichenkette,3)),
   z*10+e
   )
   else 0,
navsatlist:make_navsatlist(),
if member(satnr,navsatlist) then satnr else 0
);

make_obslist()

Die Beobachtungen eines Zeitpunkts werden durch die Funktion make_obslist() in einer Liste zusammengefasst. Auch diese Funktion wird leicht verändert:

make_obslist8(rinex_obsdata,z_nr):=block(
[satanzahl,beobachtungen,sat_nr],
satanzahl:rinex_obs[z_nr][9],
time:read_obstime8(rinex_obsdata[z_nr]),
beobachtungen:[time,satanzahl],
for i:z_nr+1 thru z_nr+satanzahl do
   (
   sat_nr:read_satnr8(rinex_obsdata[i][1]),
   prange:rinex_obsdata[i][2],
      if sat_nr#0 then beobachtungen:endcons([sat_nr,prange],beobachtungen)
   ),
beobachtungen
);

make_obsmatrix()

Damit wird auch eine neue Version der Funktion für die Zusammenstellung aller Beobachtungszeitpunkte in der globalen Datenstruktur obsmatrix nötig:

make_obsmatrix8(rinex_obsdata):=block(
[z_nr,ranges_at_time,num_sats,svlist],
obsmatrix:[],
z_nr:1,
while z_nr<length(rinex_obsdata) do

   (
   ranges_at_time:make_obslist8(rinex_obsdata,z_nr),
   obsmatrix:endcons(ranges_at_time,obsmatrix),
   num_sats:rinex_obsdata[z_nr][9],
   z_nr:z_nr+num_sats+1
   ),
svlist:[],
print(length(obsmatrix),"Beobachtungen"),
for obs in obsmatrix do
   (
   for i:3 thru length(obs) do
   svlist:endcons(obs[i][1],svlist),
   print(obs[1][2],sort(svlist)),
   svlist:[]
   ),
obsmatrix);

einlesen()

Schließlich ändern wir noch die Funktion einlesen() zum komfortablen Einlesen der Daten in Maxima. Dort muss lediglich der Aufruf der veränderten Funktion make_obsmatrix8() angepasst werden:

einlesen8():=block(
name:read_name(),
pfad:make_path(name),
rinex_nav:read_rinex(pfad[1]),
make_navmatrix(rinex_nav),
rinex_obs:read_rinex(pfad[2]),
make_obsmatrix8(rinex_obs),
return(true));
Da diese angepassten Funktionen aufgrund der Verwendung des ublox NEO-M8P-2 nötig wurden, sind eben diese Funktionen durch Anhängen der Ziffer "8" an den usrprünglichen Funktionsnamen unterscheid- und zuordenbar.
 
Anpassung an die OBS-Dateien aus Misra/Enge: GPS

Auf der Homepage zum Buch von Misra und Enge sind RINEX-Dateien von drei Orten (Durmid Hill, Piegeon Point und Vandenberg) eingestellt. Diese Daten sind allerdings sehr umfangreich: Es sind jeweils über einen ganzen Tag Aufnahmen im Halbminutentakt und damit 24 x 60 x 2 = 2.880 Messungen in einer Beobachtungsdatei enthalten. Auch die Navigationsdatei enthält die Ephemeriden aller empfangenen Satelliten im Zweistundentakt. Diese exorbitanten Datenmengen sprengen unseren Rahmen bei weitem. Um nun nicht unzählige Maxima-Funktionen anpassen zu müssen, kürzen wir besser die vorliegenden und uns interessierenden Dateien. Für die beiden Dateien vb091800.nav und vb091800.obs  aus dem Verzeichnis Data/Vandenberg/September_18_2000 wurde eine mögliche Kürzung beispielhaft durchgeführt. Die gekürzten Dateien vb091800_nav.txt und vb091800_obs.txt sind über den Menüpunkt Empfängerpositionen erreichbar.

Zunächst ist es sinnvoll, sich auf eine Zwei-Stunden-Periode des Aufnahmetags festzulegen, innerhalb derer einige Messungen ausgewertet werden sollen. Für die genannten Beispiele wurde die Periode von 12 bis 14 Uhr gewählt. Dies bedeutet, dass in der Navigationsdatei nur diejenigen Ephemerideneinträge belassen werden, welche eine Ausgabezeit von 12 Uhr haben. Dabei muss man ggf. auch Ausgaben von 13:59 Uhr tolerieren. Allerdings darf jeder Satellit im gewählten Zeitfenster nur einmal auftreten, es darf keine Doubletten geben. Alle vorhergehenden Einträge ab 0 Uhr bis 10 Uhr und alle folgenden Einträge ab 14 Uhr werden in der RINEX-NAV-Datei gelöscht. Dabei muss allerdings der Header erhalten bleiben, da sonst das Einlesen über Maxima mit den bereits erstellten Funktionen nicht korrekt arbeitet. Schließlich muss man auch darauf achten, dass am Ende der gekürzten Datei nicht noch Leerzeilen vorhanden sind!

Hat man sich nun durch Auswahl der Ephemeriden auf einen Zwei-Stunden-Zeitraum festgelegt, so sollte man in der Beobachtungsdatei aus eben diesem Zeitraum einige wenige aufeinanderfolgende Aufnahmen auswählen (2 – 3 sind schon völlig ausreichend) und alle zeitlich davor und dahinterliegenden Aufnahmen konsequent löschen! in der Beispieldatei sind sechs Aufnahmezeitpunkte von 12:06:00 bis 12:08:30 enthalten. Auch in der Beobachtungsdatei muss der Header ganz am Anfang erhalten bleiben!

Die Beobachtungsdaten von Pigeon Point und Vandenberg sind alle genau gleich strukturiert:

vandenberg obs

Zunächst fällt auf, dass in den hier blau umrandeten Einleitungszeilen zu den einzelnen Messungen Leerzeichen zwischen dem Großbuchstaben "G" und der Satellitennummer enthalten sind. Dies ist bei allen einstelligen Satellitennummern der Fall. Erst in späteren Jahren wurde im RINEX-Format statt des Leerzeichens eine führende Null vorangestellt. Um unsere Maxima-Einlesedateien nicht verändern zu müssen, ist es einfacher, diese Veränderung per "Suchen und Ersetzen" im Texteditor innerhalb der bereits gekürzten Beobachtungsdatei vorzunehmen. Man lässt nach "G " (G und Leerzeichen) suchen und durch "G0" (G und Ziffer Null) ersetzen. Damit hat man dieses Problem elegant aus der Welt geschafft.

Als nächstes fällt auf, dass für jeden Satellit jeweils sieben Messwerte angegeben sind und daher ein Zeilenumbruch innerhalb der Werte eines Satelliten vorkommt. Die beiden letzten Werte in der Folgezeile sind sowohl positiv als auch negativ, außerdem kann es sich bei diesen Werten offensichtlich nicht um die von uns benötigten Pseudoranges handeln. Wir löschen somit konsequent die kompletten Zeilen mit den oben rot hinterlegten Werte in allen Messungen der gekürzten Beobachtungsdatei!

Bei genauerem Hinschauen stellt man fest, dass je drei der verbliebenen fünf Zahlen fast identische Werte aufweisen und es sich dabei um unsere Pseudoentfernungen handeln könnte. Dies führt zu der Frage, welche Messwerte denn für jeden Satelliten aufgeführt sind. Hierüber gibt der Header Auskunft: Aus der oben grün umrandeten Angabe geht hervor, dass jeweils sieben Beobachtungsdaten angegeben sind und zwar in der Reihenfolge: C1 L1 L2 P1 P2 D1 D2

Um zu erfahren, welche Daten konkret aufgeführt sind, zieht man die Rinex-Spezifikation RINEX.txt im Verzeichnis Documents heran. Dort erfährt man die folgende Zuordnung:

C1 : Pseudorange using C/A-Code on L1
L1, L2: Phase measurements on L1 and L2
P1, P2: Pseudorange using P-Code on L1, L2
D1, D2: Doppler frequency on L1 and L2

Die Zeilen mit den beiden letzten Angaben haben wir somit zurecht gelöscht, da es sich hierbei um nicht von uns benötigte Angaben zur Dopplerfrequenz handelt.

Gleich der Wert C1 in der ersten Spalte ist somit der von uns benötigte Pseudoentfernungswert, welcher aus dem C/A-Code der öffentlichen L1-Frequenz gewonnen wurde.

Dann folgen zwei Werte, welche sich auf die Messung der Codephase der Trägerwelle beziehen. Diese sind für uns ebenfalls uninteressant.

Die Aufnahmen wurden offensichtlich mit militärischen Empfängern gemacht. Die geht aus den nächsten Daten P1 und P2 hervor. Dabei handelt es sich ebenfalls um Pseudoentfernungen, welche im ersten Fall allerdings aus dem P-Code der L1 Frequenz und im zweiten Fall aus dem P-Code der L2-Frequenz gewonnen wurden. Wir erinnern uns, dass der verschlüsselte P-Code nur von militärischen Empfängern ausgewertet werden kann. Für uns könnte es interessant sein, Positionsbestimmungen mit diesen verschiedenen Pseudoentfernungen vorzunehmen und die Ergebnisse miteinander zu vergleichen. Dies insbesondere bei Dateien, bei welchen die Selective Availability noch eingeschaltet war. Dies geht jeweils aus der Datei readme.txt hervor, welche sich im Verzeichnis der RINEX-Dateien befindet.

Aufgrund unserer Vorarbeiten und der etwas anderen Anordnung der Pseudoentfernungen in der Beobachtungsdatei müssen wir nur eine Maxima-Funktion ändern. Es handelt sich dabei um die Funktion read_prange_rinex(), mit welcher die Pseudoentfernungen aus der RINEX-Datei ausgelesen werden. Diese Funktion hat im Original die Form:

read_prange_rinex(rinex_obsdata,cluster,i):=block(
[prange],
prange:rinex_obsdata[cluster+i][2],
if prange<10 then prange:rinex_obsdata[cluster+i][3],
prange);

Wir können diese Funktion zum Einlesen dieser Dateien kürzer fassen:

read_prange_rinex(rinex_obsdata,cluster,i):=
rinex_obsdata[cluster+i][1];

So wie diese Funktion hier mit dem Index [1] angegeben ist, wird der "übliche", aus dem C/A-Code gewonnene Wert für die Pseudoentfernung ausgelesen. Verwendet man stattdessen den Index [4], so erhält man den aus dem P-Code und der L1-Frequenz ermittelten Pseudorangewert und mit [5] erhält man den Pseudorange aus dem P-Code und der L2-Frequenz.

Für das Experimentieren mit den Daten aus dem Buch von Misra und Enge ist es am sinnvollsten, zunächst die vorhandene Maxima-Bibliothek zu laden und dann die Funktion read_prange_rinex() mit der eben vorgestellten Fassung zu überschreiben. 

Die Beobachtungsdaten von Durmid Hill weichen leider ebenfalls ein wenig vom eben vorgestellten Format ab. Zunächst sind diese Dateien für unsere Zwecke ebenfalls viel zu umfangreich und müssen, genau wie oben dargestellt, gekürzt werden!

Dann wurde eine Konvertierung verwendet, die ausschließlich GPS-Satelliten voraussetzt, so dass darauf verzichtet wurde, den Buchstabe "G" jeweils den Satellitennummern voranzustellen. Es dürfte wieder am Einfachsten sein, diese Ersetzungen in der gekürzten Beobachtungsdatei von Hand vorzunehmen. Dabei muss darauf geachtet werden, dass für jede Satellitenbezeichnung genau drei Stellen zur Verfügung stehen. Statt "1" also "G01", statt "13" eben "G13" usf.

durmid hill
Die uns interessierenden Pseudoentfernungen stehen in der dritten (C1), vierten (P1)  bzw. fünften (P2) Spalte. Je nachdem, mit welchen Pseudoentfernungen man rechnen will, muss die zugehörige Spaltennummer als Index in der Funktion read_prange_rinex() angegeben werden.

Bilder

Haftungsausschluss / Disclaimer

Ich übernehme keine Gewähr für die Aktualität, Richtigkeit und Vollständigkeit der auf dieser Webseite bereitgestellten Informationen. Gleiches gilt für die Inhalte externer Websites, auf die meine Webseite verweist, bzw. mit der diese Webseite verlinkt ist.

DATENSCHUTZ    IMPRESSUM