Geführte FSK-Modulation am SDR      

Elektronik-Labor  Lernpakete  Projekte  HF  



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.




Elektronik-Labor  Lernpakete  Projekte  HF