Geführte FSK-Modulation am SDR
Mein SDR-Transceiver
ist nicht SSB-fähig, aber mit einer kleinen Software-Erweiterung kann
er nun wie ein üblicher SSB-Transceiver angesteuert werden. Ein
Programm wie WSJT-X liefert ein Audiosignal am Ausgang der Soundkarte,
dass üblicherweise an den Mikrofoneingang eines SSB-Transceivers gelegt
wird. Dort wird es dann auf die HF hochgemischt. Bei WSPR, FT8 und
vielen anderen digitalen Betriebsarten wird ein FSK-Signal mit mehreren
Frequenzen verwendet. Zu einer Zeit wird nur eine Frequenz ausgegeben.
Deshalb hatte ich schon länger überlegt, ob man die Aufgabe nicht auch
mit einer PLL lösen könnte. Dabei bestand aber das Risiko, dass die
Nachsteuerung bei der niedrigen Vergleichsfrequenz im NF-Bereich zu
langsam werden könnte. Und der Aufwand wäre recht groß geworden.
Aber jetzt hatte ich eine neue Idee. Der Arduino misst die Frequenz und
stellt den VFO des Senders auf die Sollfrequenz ein, z.B. auf 7074 kHz
+ NF, weil ja das obere Seitenband verwendet wird. Die Sendefrequenz
wird damit dem NF-Signal permanent nachgeführt. Als ich mit dem
Projekt angefangen habe, war noch nicht sicher, dass es funktionieren
würde. Vor allem muss die Audiofrequenz schnell genug und genau genug
gemessen werden. Als Audio-Eingang verwende ich den Port A2 (PA2) des
Arduino Uno, der noch frei war. Es handelt sich zwar um einen
Analogeingang, ich verwende ihn aber als digitalen Eingang. Das
sinusförmige Audiosignal wird über einen Spannungsteiler mit 220 k nach
Vcc und 100 k nach GND so angehoben, dass es deutlich über die
Eingangsschwelle kommt.
Das Programm soll dann die Zeit für eine vollständige Schwingung messen
und daraus die Frequenz berechnen. Ein Vorversuch mit Bascom sollte
zeigen, ob die nötige Auflösung zu erreichen ist
Dim D As Word
dim f as single
Config Timer1 = Timer , Prescale = 1
start Timer1
do
while pinc.2=0 : wend
waitus 10
while pinc.2=1 : wend
Timer1 =0
waitus 10
while pinc.2=0 : wend
waitus 10
while pinc.2=1 : wend
d=Timer1
f= 16000000/d
print f
waitms 500
loop
Hier
wird der Timer1 mit seiner Auflösung von 16-Bit mit 16 MHz
getaktet und als Uhr verwendet. Eine while-Schleife wartet zuerst auf
einen 1-Zustand, eine zweite auf einen 0-Zustand. Damit hat man den
Anfang einer Periode, und der Timer1 wird auf Null gesetzt. Dann folgen
zwei gleiche Abfrageschleifen um die nächste Flanke am Ende der
Periode zu erkennen. In dem Moment wird der Timer1 ausgelesen. Wenn die
Frequenz genau 1 kHz war, bekommt man das Ergebnis 16000. Mit der
Division f = 16000000/d erhält man dann 1000,0 Hz. Bei einem Versuch
mit einem analogen Sinusgenerator wurde eine Auflösung von ca. 0,1 Hz
und ein Flattern in der Größenordnung 1 Hz erkennt. Das würde für FT8
reichen.
Bei den ersten Versuchen kam es zu vereinzelten Ausreißern. Die
Vermutung war, dass die langsam ansteigende Sinusspannung an der Flanke
in Flattern erzeugen kann. Deshalb wurden Wartezeiten von 10 µs jeweils
nach einer Schleife eingesetzt. In 10 µs sollte die Spannung weit genug
vom Umschaltpunkt entfernt sein. Die Messung war dann fehlerfrei.
Zum Einbau in den Transceiver musste alles mit Arduino-C geschrieben
werden. Und es kam noch eine Aufgabe hinzu: Die VOX-Funktion. Der
Sender soll automatisch starten, wenn das NF-Signal erscheint und
automatisch wieder auf Empfangen umschalten, wenn das Signal endet. Für
den Start reagiert das Programm auf einen ersten High-Zustand am Port.
if (digitalRead(A2) == 1){
digitalWrite (txOn,1); //Relais
digitalWrite (keyOut,1); //keyOut
TCCR1A = 0x00;
TCCR1B = 1; // Timer1 Timer 16 MHz
TCNT1 = 0;
si5351.output_enable(SI5351_CLK2, 1);
si5351.output_enable(SI5351_CLK1, 0); //RX off
word timeout = 0;
word timer1 = 0;
unsigned long codefreq =0;
while (timeout < 1000) {
if (digitalRead(A2) == 1){
while (digitalRead(A2) == 1);
delayMicroseconds(50);
while (digitalRead(A2) == 0){
if (TCNT1> 65000) {break;}
}
TCNT1 = 0x0000;
delayMicroseconds(50);
while (digitalRead(A2) == 1);
delayMicroseconds(50);
while (digitalRead(A2) == 0){
if (TCNT1> 65000) {break;}
}
timer1 = TCNT1;
if (timer1 < 65000){
codefreq = 1600000000/timer1;
si5351.set_freq((freqTX * 100 + codefreq), SI5351_CLK2);
}
// codefreq = codefreq / 100;
// timer1 = codefreq;
// Serial.println (timer1);
timeout = 0;
}
else{
delayMicroseconds(10);
timeout++; //1000 * 10 µs = 10 ms ohne Signal
}
}
// Turn off the output
si5351.output_enable(SI5351_CLK2, 0);
si5351.output_enable(SI5351_CLK1, 1); //RX on
digitalWrite (txOn,0); //Relais
digitalWrite (keyOut,0); //keyOut
}
Das Programm bleibt dann in einer Schleife, in der jeweils die
Frequenz gemessen und dann mit si5351.set_freq((freqTX * 100 +
codefreq), SI5351_CLK2); an den Ausgang übergeben wird. Nach jedem
Durchlauf ist es zufällig, ob schon der nächste High-Zustand des
NF-Signals anliegt. Immer wenn ein Low-Zustand erkannt wird, wird ein
Timeout-Zähler erhöht. Wenn länger kein Signal kommt, wird der Sender
abgeschaltet.
Zuerst gab es noch Probleme mit dem Abschalten, weil die letzte
Schwingung in einer Flankenschleife enden konnte, in der das Programm
dann hängen blieb. Dagegen half eine Abfrage des Timers: if (TCNT1>
65000) {break;} Wenn also der Timer ca. 4 ms misst, wird die Schleife
verlassen. Die tiefste mögliche Frequenz liegt damit bei 250 Hz, was
für die Aufgabe ausreicht. Der Transceiver wird nun zuverlässig über
die VOX-Funktion gesteuert. Alles kann nun mit WSJT-X bedient
werden. Nur die FT8.Freqeunz muss ich noch extern einstellen, z.B. 7074
kHz für das 40m-Band.
Wenn
man sich das erzeugte FT-Signal anhört, ist keinen Unterschied zu einem
über einen SSB-Transceiver erzeugtes Signal zu hören. Aber ob es auch
korrekt dekodiert wird, blieb noch spannend. Als ich dann an einem
Zweitgerät die korrekte Nachricht "CQ DK7JD JO31" sehen konnte, war ich
begeistert. Mein Eigenbau-QRP-Gerät macht nun das gleiche wie mein
SSB-Transceiver TS520-S, wenn auch mit deutlich weniger Sendeleistung.
Dafür aber ist das Eigenbaugerät frequenzstabiler, und es kann auch die
neuen Amateurfunkbänder verwenden. Die geringere Leistung scheint bei
FT8 nicht viel auszumachen. Gestern war ich auf mehreren Bändern zwischen 80 m und 15 m
unterwegs, und die Signale wurden in ganz Europa empfangen. Und auf
jeden Fall macht es mit einem Eigenbau doppelt so viel Spaß.
Zur Sicherheit habe ich dann noch mal nachgemessen, wie lange es
dauert, bis die Frequenz wieder neu nachgesteuert wird. Bei einem
NF-Signal von 1 kHz waren es 6 ms. Für die Frequenzmessung wurden 2 ms
gebraucht, für die Steuerung des PLL-Chips SI5351 noch einmal 4 ms. Bei
einer NF-Frequenz von 500 Hz dauerte es insgesamt 8 ms, weil die
Periodenmessung nun 4 ms beansprucht. Weil eine FT8-Periode 159 ms
dauert, wird die Frequenz bei 8-ms-Intervallen insgesamt 20 Mal
nachgesteuert. Das ist mehr als genug, und ich vermute, dass kleine
Streuungen im Messergebnis sich in der Zeit ausmitteln.
Und noch einen Vorteil hat diese neue Modulationsmethode: Wie in
SSB-Transceiver muss das Gerät gar nicht wissen, was da gesendet wird.
Es muss noch getestet werden, aber ich vermute, dass recht viele
digitale Modi mit diesem Gerät funktionieren. FT4 und JS8 wurden schon
erfolgreich getestet. Nur WSPR funktionierte mit dieser Methode noch
nicht, weil dazu eine noch bessere Auflösung erforderlich ist. Eine
Verbesserung ist möglicherweise mit der Timer1 Input Capture Unit
erreichbar. Das werde ich im nächsten Schritt versuchen.