Funkuhrsignalempfänger (DCF77) via Soundkarte

Published 10 October, 2013

Heute möchte ich mal ein kleines Projekt von mir vorstellen: Ein selbst gebastelter Empfänger für das Funkuhr-Signal, welches vom Längstwellensender DCF77 (bei Frankfurt) verbreitet wird. Das tolle daran ist, dass man ihn mit Haushaltsmitteln nachbasteln kann.

So habe ich für die finale Version nur einen Computer und einen alten Kopfhörer gebraucht. Das Projekt war für mich auch der Einstieg in die digitale Signalverarbeitung und das Software Defined Radio (SDR), da das unbearbeitete Signal direkt gesampelt und per Software verarbeitet wird.

Empfang

Das Signal wird über den Mikrofoneingang empfangen. Angeschlossen ist aber kein Mikrofon, sondern eine Antenne, welche quasi das gleiche wie ein Mikrofon macht (nur, dass die elektromagnetische Wellen statt akustische Wellen einfängt). Die Soundkarte muss hierfür jedoch mindestens eine Abtastrate von 155kHz (meistens 192kHz) haben, da DCF77 mit einer Frequenz von 77500 Hz sendet. Das Kabel der Kopfhörer wird hierfür einfach durchgeschnitten und oben etwas abisoliert.

Ich hab mit meinem Bruder verschiedene Arten von Antennen ausprobiert. Am effizientesten war es, wenn man einfach die Signalleitung mit den Fingern festhält, sodass der Körper als Antenne dient :-)

antenne

Verarbeitung (SDR)

Um den Empfang erstmal zu testen reicht es, das Signal mit Audacity aufzunehmen. Dafür muss die Samplerate vom Projekt auf 192000 Hz (höher geht natürlich auch) stehen. Danach stellt man die Ansicht von "Wellenform" auf "Spektrogramm" um und zoomt in den Bereich von 77 kHz. Bei mir sieht das dann etwa so aus:

spec

Bei 77,5 kHz sieht man deutlich das Signal vom DCF77. Das Signal funktioniert ähnlich wie ein Morse-Code. Es wird ein Trägersignal gesendet, welcher einmal in der Sekunde fast komplett "aussetzt". D.h. die Ampiltude des Signals wird auf 15% abgesenkt. Die Dauer dieser "Lücke" bestimmt den Wert. 100ms bedeutet im binären Sinn FALSE, 200ms bedeutet TRUE. Einmal pro Minute setzt das Signal nicht aus, um eine neue Minute zu signalisieren. Somit hat DCF77 eine Übertragungsrate von 59 Bit/min. Was genau welches Bit bedeutet, steht auf Wikipedia.

Mein Decoder muss also nur das Mikrofon aufnehmen, und hören, wie lange die Absenkungen bei 77,5 kHz dauern. Was nun folgt ist flüchtig angeeignetes Halbwissen, was in der Praxis aber sehr gut funktioniert hat. Als erstes habe ich einen kleinen Filter geschrieben, um alle Signale rauszufiltern, die später stören könnten. Diese entstehen beispielsweise durch das lokale Niederspannungsnetz (50 Hz), schlechte Netzteile, andere Sender, usw. Mein Filter funktionierte wie folgt:

Als erstes machte ich auf die gesampelten Werte eine Fouriertransformation, um das Spektrum zu erhalten. Anschließend habe ich den Real- und Imaginärteil von den Werten, welche nicht zu der Zielfrequenz gehörten ohne Rücksicht auf Verluste auf 0 gesetzt. Normalerweise würde man das mit einer Fensterfunktion machen, aber bei mir klappte es auch so ganz gut. Bei einer Abtastrate von 192 kHz hatte meine FFT eine Auflösung von 4096. Die Nyquist-Frequenz lag also bei 96 kHz. Jeder Wert der FFT umfasste demnach 192k/2/4096 = 23,4375 Hz. Der interessanteste FFT-Wert lag deshalb irgendwo bei Nummer 77500 / 23,4375 = 3.306,66. Von den beiden Seitenbändern wollte ich jeweils etwa 50 Hz behalten. Der Filter behielt somit lediglich etwa 4 von 4096 Werten. Die anderen wurden auf 0 gesetzt. Um nun eine Welle zurückzubekommen wendete ich auf die neuen Werte eine inverse FFT an. Das Zwischenergebnis: Ich habe ein Welle, welche nurnoch ein ganz kleines Spektrum aufweist (wenn man von leichten Störungen absieht). Dieses kleine Spektrum liegt jedoch immernoch bei 77,5 kHz und lässt sich noch nicht akustisch wiedergeben. Nunja, Fledermäuse könnten es vielleicht noch hören :-)

Runtermischen

Beim Runtermischen wird aus einem hochfrequenten Signal ein niederfrequentes gemacht. Das Prinzip davon ist eigentlich sehr einfach. Wenn beispielsweise aus einem 1500 Hz Signal ein 300 Hz Signal entstehen soll, dann wird ein 1200 Hz (1500 Hz - 300 Hz) Signal generiert und jedes Sample vom "originalen" Signal mit dem dazugehörigen Sample vom 1200 Hz Signal multipliziert. Hierbei sollte man darauf achten, dass an dieser Stelle ein Sample nur den Werte von -1.0 bis 1.0 annehmen kann, sonst ist das Signal am Ende übersteuert!

Hier ein kleines Beispiel:

mixer
Rot: Trägerfrequenz
Grün: Filterfrequenz
Blau: Produkt aus beiden Frequenzen

Wie man auf dem Bild sieht, entstehen durch das Mischen zwei neue Frequenzen. Das neue, niederfrequente und ein deutlich höheres. Das Höhere können wir hier nicht gebrauchen. Normalerweise würde man hier mit einem sogenannten IQ-Mischer arbeiten, welcher noch ein bisschen komplexer ist, die zweite Frequenz aber weitgehend vermeidet. In meinem Fall ist das aber irrelevant, weil die zweite Frequenz weit über der Nyquist-Frequenz liegt. Nunja, dadurch wird zwar die zweite Frequenz vermieden, aber es treten neue Störungen auf. Um das Problem zu umgehen habe ich zwei Dinge gemacht, welche eigentlich "unsauber" sind. Zum einen habe ich das Signal runtergesamplet (von 192kHz auf 48kHz, d.h. ich habe aus vier Samples eins gemacht) und anschließend den oben beschriebenen Filter nochmal angewendet, jedoch auf die neue Frequenz. Das runtersamplen war hier relativ praktisch um nichtmehr mit so großen Datenmengen arbeiten zu müssen (die 192 kHz Samples sind ja ziemlich unnütz, wenn das Zielsignal weit unter 10 kHz liegt).

Die Zielfrequenz war bei mir übrigens 500 Hz, damit man es auch schön hören kann. Die Frequenz vom Mischer war demnach exakt 77 kHz.

Der Rest des dekodieren war nun einfach. Beim letzten Filterschritt habe ich die inverse FFT weggelassen und direkt mit dem Spektrum weitergearbeitet. Ich habe alle relevanten Werte zusammenaddiert und in kleinen Blöcken analysiert. Ein Block war 1024 Byte groß (angepasst an die FFT-Größe). Bei 48 kHz sind das etwa 21ms pro Block. Zugegeben: Es hätte genauer sein können, hat aber gereicht. Über die letzten Blöcke wurde ein Durchschnitt berechnet, und sobald ein Block weit unter dem Durchschnitt war, wurde es als "aus" bzw. "auf 15% abgestuft" interpretiert. Die länge konnte dann einfach gemessen werden. Ein bisschen habe ich noch mit verschiedenen Arten von Filtern rumprobiert, damit eine kleine Störung im Signal nicht sofort die komplette Minute versaut.

Mit GUI sah das ganze dann so aus: dcf77

Viel Spaß! :-)