Senden von APRS Nachrichten mit CircuitPython und VHF-Modul

APRS gibt es im Amateurfunk bereits seit langer Zeit. Auf die Besonderheiten im speziellen gehe ich im weiteren Text ein. Zu jener Zeit gab es extra dafür konzipierte analoge integrierte Schaltungen (IC's) welche die benötigte Modulation des Senders übernommen haben. Diese sind heute leider nicht mehr verfügbar. Ich möchte jetzt nicht allzu tief in das APRS-Protokoll eingehen, es existieren sehr viele Infoseiten im Web dazu (siehe unter Links).

Seit geraumer Zeit verwende ich ein 2m-Handfunkgerät um gelegentlich einige Fahrten im Auto per APRS zu loggen. Eigentlich ist es dafür viel zu schade. Warum es nicht gegen ein selbst gebautes Gerät ersetzen?

Beim Einlesen in das Thema APRS merkt man aber schnell, dass man die Thematik in verschiedene Bereiche aufteilen muss, um den Überblick zu bewahren.

Funktionsweise von APRS.

Welche Protokolle kommen für die Übertragung zur Anwendung?

APRS verwendet das übergeordnete Kommunikationsprotokoll AX.25. Dieses ist ein sehr mächtiges Protokoll und APRS verwendet nur einen winzig kleinen Teil davon. Was aber nicht bedeutet das es einfach zu verwenden ist. Genau genommen ist AX.25 in der Lage Informationen zielgerichtet weiterzuleiten. Dieses Routing wird im Amateurfunk-APRS aber kaum/nicht verwendet. Die Meldungen, welche versendet werden haben kein bestimmtes Ziel und sollen von verschieden Arten von Repeatern abgewickelt werden.

Wie wird moduliert?

Die Übertragung der Daten erfolgt über zwei Töne von 1200Hz und 2200Hz. Als Modulation kommt ein spezielles Verfahren zum Einsatz, welches mir Anfangs etwas Kopfzerbrechen bereitet hat.

Die Modulation verwendet eine Symbolrate von 1200 Baud. Das bedeutet, 1200 Datenwerte pro Sekunde gesendet werden. Mit den beiden Tonfrequenzen von 1200Hz und 2200Hz ergeben sich folgende Zusammenhänge:

Wird ein 1200Hz Ton gesendet entspricht der Zeitraum eines Symbols einer Wellenlänge von 1200 Hz. Ein 2200Hz Ton wird während dieser 1/1200 Sekunde mit 1,83333 Wellenlängen übertragen. Die Definition verlangt, dass die Phase beim Tonwechsel erhalten bleibt. Dazu muss die Phase natürlich bekannt sein und bei der Erzeugung des nächsten Tones berücksichtigt werden. Auch wichtig! Es wird NICHT für Bit=1 der eine Ton und für Bit=0 der andere verwendet. Das hier verwendete Verfahren heisst NRZI und steht für "Non Zero Return Inverted encoding". Wird ein Bit=0 gesendet, erfolgt ein Tonwechsel. Für Bit=1 bleibt der Ton bestehen. Es spielt daher keine Rolle mit welchem Ton die Aussendung beginnt. Um die Synchronisation über mehrere 1-Bits zu erhalten, wird vom Sender nach dem fünften Bit=1 ein zusätzlicher Tonwechsel eingefügt. Dieser Wechsel, auch Bit-Stuffing genannt (würde einem Bit=0 entsprechen) wird vom mit zählendem Empfänger aber ignoriert. Er dient einzig dazu das Timing zu synchronisieren. Eine weitere Besonderheit besteht beim Beginn und Beenden einer Übertragung. Hier werden zur Signalisation am Anfang und Ende einer Nachricht mehrere gleiche Bytes (0x7E) übertragen, die nicht vom Bit-Stuffing verändert werden und daher vom Empfänger als Start und Endpunkt einer Nachricht erkannt werden können. Diese Bit-Kombination mit 6 x Bit=1 kommt somit in der eigentlichen Nachricht nicht vor.

Technische Umsetzung

Wie wird das modulierte Signal aufbereitet?

Das Herz der Schaltung ist ein Adafruit Feather-M4 Mikrokontroller mit 2MB Speicher, 192kB RAM und diverser Schnittstellen. Darunter auch ein zweikanaliger DAC mit bis zu 1Mbit Sampling-Rate. Der Feather M4 Mikrocontroller stellt einige interessante Funktionen bereit. So lassen sich zum Beispiel gespeicherte MP3 oder WAV-Dateien über den DAC auszugeben. Ebenso kann man eigene Signale als Array erzeugen und vom DAC mit der gewünschten Samplinmgrate ausgeben lassen. Das geschieht ohne CPU direkt über interne DMA Funktionen.

Wie bereits erwähnt, muss beim Tonwechsel die Phase fortgeführt werden. Ein einfaches Abspielen von Tönen gelingt hier nicht, da der Kontroller jeweils seinen Ton bei Phase = 0 Grad beginnt. Bei diesem Mikrokontroller wird das über die Funktion mit dem Abspielen eines Arrays genutzt. Der DAC hat eine Auflösung von 12bit. Um Speicher zu sparen werden nur 8bit verwendet. Somit passt ein Sample in ein Byte.

Für die weitere Vorgehensweise braucht es zuerst noch etwas Theorie. Um eine Sinuswelle ausgeben zu können muss man sich darauf festlegen, aus wie vielen Samples (Datenpunkten) diese bestehen soll. Bei xx Datenpunkten entsprächen für den 1200Hz Ton ein Sample jeweils eine Phasenverschiebung von 360 / xx. Für den 2200Hz Ton sind es 360 / xx * 2200 / 1200. Mit einem kleinen Tabellenprogramm lässt sich in Kürze eine passende Kombination herausfinden. Bei 30 Samples pro Symbol kommt man auf folgende Werte:

Bitrate 1200
Samples pro Bit 30
Samplingrate = 36000

Phasenwinkel:
Mark 1200Hz => 360 / 30 = 12 Grad
Space 2200Hz => 360 / 30 * (2200/1200) = 22 Grad

Da hier beide Phasenwinkel ganzzahlig sind, lassen sich die Sinuswerte für 0-359 Grad einfach vorberechnen und als statisches Array im Speicher ablegen. Für jedes Sample wird dann dessen Phasenversatz addiert und daraus der passende Sinuswert aus dem Array ausgelesen.

Update (13.03.2021)

Circuitpython hat im Feather-M4-Express ca. 160 kB RAM zur Verfügung. Es hat sich herausgestellt, dass bei 30 Samples pro Bit der Speicher nicht immer ausreicht. Da Circuitpython eine interpretierte Sprache ist, sind keine genauen Voraussagen zum Speichermanagement möglich. Die Reduzierung auf 15 Samples pro Bit haben soweit keine Einbussen bezüglich Detektierbarkeit gezeigt. Es empfiehlt sich auch die Komprimierung der Dateien mit dem MPY-CROSS Tool um unnötigen Balast aus den Dateien zu entfernen. Das Sendemodul DRA818V weist zudem einige Nachteile auf. So benötigt das Modul nach Setzen des PTT-Signals ca. 1 Sekunde bis das Audiosignal stabil ausgesendet wird. Nach dem Lösen der PTT sendet es noch einen niederfrequenten Zweiton aus (Roger-Beep?). Dieser lässt sich unterdrücken, wenn das Module in den Powersafe Modus versetzt wird. Die aktuelle Software berücksichtigt diese Umstände. Leider dauern die Aussendungen dadurch länger als nötig (ca. 1.5 Sekunden für den Vorlauf).

Welche Funktionen des Protokolls werden in der Software implementiert?

Da das Modul nur im Fahrzeug verwendet wird, werden nur Positions- und Umweltdaten versendet.

Wie wird das Signal ausgesendet?

Für die Aussendung wird das 2m HF-Modul DRA818V eingesetzt.

Hardware / Software

Der Prototyp enthält folgende Module:

Die Software basiert komplett auf CircuitPython. Die Bibliotheken für die Sensoren stammen von Adafruit.

Source

siehe GitHub Repository

APRS Dokumentation
Gute Dokumentation über die Eigenheiten von APRS

Bilder

APRS-Buddy

4-lagige Leiterplatte mit allen Komponenten zum Testen der Software