Positionsbestimmung mittels VOR und SDR

Positionsbestimmung mittels VOR und SDR

VORs (oder auch Drehfunkfeuer) sind Sendeanlagen, die jeweils ein rotierendes und ein ungerichtetes Signal aussenden. Anhand der Verschiebung zwischen beiden Signalen kann ein Flugzeug seine Aktuelle Position bestimmen (genauer gesagt die Richtung im Verhältnis zum VOR). Die genaue Funktionsweise ist hier sehr gut beschrieben: https://de.wikipedia.org/wiki/Drehfunkfeuer.

VOR Ottersberg

Nachdem ich bei einer kleineren Fahrradtour in der Umgebung von München eine dieser selten gewordenen Anlagen entdeckt habe, hat es mich sofort gereizt, einige Experimente mit meinem SDR durchzuführen.

Innerhalb der letzten Wochen war ich bereits 3x in Ottersberg und habe diverse Messungen vorgenommen. Dafür habe ich neben meinem Laptop das SDR SDRplay RSP1A (https://www.sdrplay.com/rsp1a/) benutzt.

Das Signal eines VORs ist relativ komplex aufgebaut. In der Mitte befindet sich das Referenzsignal mit einer AM Modulation, das rotierende Signal auf zwei Seitenbändern ist FM moduliert. Zusätzlich wird der Name der VOR Station in Morsecode ausgesendet (ca. 1 kHz AM).

VOR Spektrum

Zur Signalverarbeitung verwende ich das Tool GNU Radio.
Das empfangene Signal wird demoduliert, gefiltert, der DC Anteil geblockt und die Peaks des rotierenden Signals und des Referenzsignals werden detektiert und schließlich in 2 Dateien geschrieben.

Vorverarbeitung
Peak detection

In der Ausgabe sind die beiden verschobenen Signalbestandteile sehr gut zu erkennen:

Oben: Signale und Peaks, Unten: Spektrum

Um schließlich die Richtung aus dem Signal zu ermitteln habe ich ein kleines Python-Programm geschrieben, das die Peaks einliest, das Verhältnis bestimmt, in Grad umrechnet und grafisch darstellt:

import statistics
from PIL import Image, ImageDraw
import math

ref = open('ref.bin', 'rb')
var = open('var.bin', 'rb')

ref_bytes = ref.read()
var_bytes = var.read()

counter = 0
refCounter = 0

delays = []
refDelays = []

items = min(len(ref_bytes), len(var_bytes))

for i in range(items):
    r = ref_bytes[i]
    v = var_bytes[i]

    counter = counter + 1
    refCounter = refCounter + 1

    if r == 1:
        refDelays.append(refCounter)

        counter = 0
        refCounter = 0

    if v == 1:
        delays.append(counter)

med = statistics.median(delays)
medRef = statistics.median(refDelays)

ang = med / medRef * 360
print(ang)

map_image = Image.open("map.png")

w, h = map_image.size

draw = ImageDraw.Draw(map_image)
draw.ellipse((w / 2 - 5, h / 2 - 5, w / 2 + 5, h / 2 + 5))

# Calculate line
arc = math.radians(ang)
leng = 500
draw.line((w / 2, h / 2, w / 2 + math.sin(arc) * leng, h / 2 - math.cos(arc) * leng), width = 3, fill = (255, 255, 0))

map_image.show()

Das Ergebnis sind folgende Grafiken. Der Punkt, an dem die Messung vorgenommen wurde, wurde jeweils rot eingezeichnet:

Auch wenn die Abweichung bei einer Messung wirklich groß war, betrachte ich das Expermiment durchaus als gelungen. Man darf nicht vergessen, dass der Sender stark nach oben gerichtet und nicht für Bodennavigation ausgelegt ist.

Show Comments