Welcome to the FlexRadio Community! Please review the new Community Rules and other important new Community information on the Message Board.
How to Receive Technical Support::
If you are needing assistance with FlexRadio products, please refer to the product documentation or check the Help Center for known solutions. Need technical support from FlexRadio? It's as simple as creating a HelpDesk ticket.

Antenna Diversity for FT8 — double your stations with a single SCU

mikewanne
mikewanne Member
Hi everyone,

I'd like to share a simple idea that gave me surprisingly good results on my FLEX-8400M.

THE IDEA

FT8 works in fixed 15-second slots. Stations repeat their calls for several minutes. I wrote a small Python program that switches between ANT1 and ANT2 every FT8 cycle and accumulates the decoded stations across both antennas.

Since the 8400M has only one SCU, you can't listen on both antennas simultaneously. But you don't need to — FT8 gives you time. Just alternate, and merge the results.

WHY IT WORKS

Radio waves rotate their polarization traveling through the ionosphere. Some signals arrive vertically polarized, some horizontally. A single antenna only catches one part. By alternating between two antennas with different polarization/pattern, you catch both.

MY RESULTS

Setup: FLEX-8400M, ANT1 = multiband dipole (vertical, 10cm from wall), ANT2 = rain gutter (horizontal). Yes, a rain gutter.

40m band, K=4, conditions Fair/Poor:
- Normal (ANT1 only): 13 stations
- Diversity (ANT1 + ANT2 alternating): 43 stations

20m band:
- Normal: 8 stations
- Diversity: 26 stations (including VK3DMP Australia at 14,000 km — on the rain gutter)

These numbers are reproducible. I've tested on two different machines (Mac Mini M2 and iMac Pro) on different days with consistent results.

HOW IT WORKS (TECHNICALLY)

- At each 15s cycle start: switch rxant (ANT1/ANT2) via SmartSDR TCP API
- Antenna command sent in a separate thread (non-blocking, keepalive stays alive)
- Single slice, single decoder, single audio stream — no second SCU needed
- After decode: accumulate stations by callsign, keep best SNR
- Stations not heard for 2 minutes are removed
- TX always stays on ANT1

The core logic is about 20 lines of Python. No hardware modification needed. Works on any FlexRadio with two antenna ports, even single-SCU models.

THE CODE

Full source code is on GitHub, MIT license — free for everyone:
https://github.com/mikewanne/SimpleFT8

It's a standalone FT8 client that talks directly to the FLEX via SmartSDR TCP API + VITA-49 UDP. No SmartSDR needed. RX and TX both work (30+ PSKReporter spots confirmed).

This is a proof-of-concept, not a finished product. Rough edges, no unit tests, built in a week. But the diversity concept works and the results speak for themselves.

WHAT I'D LIKE TO KNOW

- Has anyone tried something similar?
- Would be interesting to see results from other antenna combinations (beam + vertical, two dipoles at different angles, etc.)
- If any software developer wants to integrate this into their app — go for it, MIT license, no restrictions

Screenshots are in the GitHub README (English + German).

---

Hallo zusammen,

ich moechte eine einfache Idee teilen, die auf meinem FLEX-8400M ueberraschend gute Ergebnisse gebracht hat.

DIE IDEE

FT8 arbeitet in festen 15-Sekunden-Slots. Stationen wiederholen ihre Rufe ueber mehrere Minuten. Ich habe ein kleines Python-Programm geschrieben, das bei jedem FT8-Zyklus zwischen ANT1 und ANT2 wechselt und die dekodierten Stationen ueber beide Antennen akkumuliert.

Da der 8400M nur eine SCU hat, kann man nicht gleichzeitig auf beiden Antennen hoeren. Muss man aber auch nicht — FT8 gibt einem die Zeit. Einfach abwechseln und die Ergebnisse zusammenfuehren.

WARUM ES FUNKTIONIERT

Funkwellen drehen ihre Polarisation auf dem Weg durch die Ionosphaere zufaellig. Manche Signale kommen vertikal polarisiert an, manche horizontal. Eine einzelne Antenne faengt immer nur einen Teil. Mit zwei Antennen unterschiedlicher Polarisation/Abstrahlcharakteristik faengt man beide Seiten.

MEINE ERGEBNISSE

Setup: FLEX-8400M, ANT1 = Multiband-Dipol (vertikal, 10cm Wandabstand), ANT2 = Regenrinne (horizontal). Ja, eine Regenrinne.

40m-Band, K=4, Bedingungen Fair/Poor:
- Normal (nur ANT1): 13 Stationen
- Diversity (ANT1 + ANT2 abwechselnd): 43 Stationen

20m-Band:
- Normal: 8 Stationen
- Diversity: 26 Stationen (darunter VK3DMP Australien mit 14.000 km — ueber die Regenrinne)

Die Zahlen sind reproduzierbar. Getestet auf zwei verschiedenen Rechnern (Mac Mini M2 und iMac Pro) an verschiedenen Tagen mit konsistenten Ergebnissen.

WIE ES TECHNISCH FUNKTIONIERT

- Bei jedem 15s-Zyklusstart: rxant umschalten (ANT1/ANT2) ueber SmartSDR TCP API
- Antennenbefehl in separatem Thread (non-blocking, Keepalive laeuft weiter)
- Ein Slice, ein Decoder, ein Audio-Stream — keine zweite SCU noetig
- Nach dem Dekodieren: Stationen per Callsign akkumulieren, besten SNR behalten
- Stationen die 2 Minuten nicht mehr gehoert werden, werden entfernt
- TX bleibt immer auf ANT1

Die Kernlogik sind ca. 20 Zeilen Python. Keine Hardware-Modifikation noetig. Funktioniert auf jedem FlexRadio mit zwei Antennenanschluessen, auch mit nur einer SCU.

DER CODE

Vollstaendiger Quellcode auf GitHub, MIT-Lizenz — frei fuer jeden:
https://github.com/mikewanne/SimpleFT8

Das ist ein eigenstaendiger FT8-Client der direkt ueber SmartSDR TCP API + VITA-49 UDP mit dem FLEX kommuniziert. Kein SmartSDR noetig. RX und TX funktionieren (30+ PSKReporter-Spots bestaetigt).

Das ist eine Machbarkeitsstudie, kein fertiges Produkt. Raue Kanten, keine Unit-Tests, in einer Woche gebaut. Aber das Diversity-Konzept funktioniert und die Ergebnisse sprechen fuer sich.

WAS MICH INTERESSIERT

- Hat jemand etwas Aehnliches versucht?
- Wuerde mich interessieren welche Ergebnisse andere Antennenkombinationen bringen (Beam + Vertikal, zwei Dipole in verschiedenen Winkeln, etc.)
- Wenn ein Software-Entwickler das in seine App einbauen moechte — gerne, MIT-Lizenz, keine Einschraenkungen

Screenshots sind im GitHub README (Englisch + Deutsch).

73 de DA1MHH
Mike, Herne (JO31 was an error rendering this rich post.
2 votes

Active · Last Updated

Comments

  • mikewanne
    mikewanne Member
    Github Link https://github.com/mikewanne/SimpleFT8?tab=readme-ov-file
  • reed
    reed Member ✭✭

    This doesn't make sense to me. FT8 transmissions are approximately 15s long. Normally you transmit in one 15s slot, then receive in the next 15s slot. I would have thought the antenna switch would flip ever 30s, so that you could decode all slot1 and slot2 stations on ANT1, then switch to ANT2 and listen again in both slots.

    In the current implementation, suppose that your ANT2 hears me really well, and your ANT1 barely hears me at all. Then if I'm transmitting in slot 1, the program always listens on ANT1 during slot 1 and never hears me, rendering the antenna switching pointless.

  • mikewanne
    mikewanne Member
    DEUTSCH:

    Hallo OM,

    SimpleFT8 nutzt Temporal Polarization Diversity, um mit zwei
    angeschlossenen Antennen den Empfang zu optimieren.

    ANT1 ist die Sendeantenne (TX), ANT2 ist eine reine Empfangsantenne.
    ANT2 kann jede verfügbare zweite Antenne sein: Regenrinne,
    Balkongeländer, Wurfantenne oder gespannter Draht. Da verschiedene
    Bänder unterschiedliche Polarisationen (vertikal/horizontal) und
    optimale Längen haben, kann diese zweite Antenne auf bestimmten
    Bändern sogar besser empfangen als die Hauptantenne.

    Automatische Neueinmessung: beim Start UND alle 80 Zyklen (~20 Min).
    Nötig weil sich die Bedingungen ständig ändern: Wetter (Nässe,
    Schnee), Ausbreitung, Tageszeit, Band.

    Vier Betriebsmodi über 10 Zyklen (E=gerader Slot, O=ungerader Slot):

    100% ANT1 (Normalbetrieb):
    E O E O E O E O E O
    A1 A1 A1 A1 A1 A1 A1 A1 A1 A1

    70:30 (ANT1 besser):
    E O E O E O E O E O
    A1 A1 A2 A1 A1 A2 A1 A1 A2 A1
    → A2 deckt Pos. 2(E), 5(O), 8(E) — beide Slot-Typen abgedeckt

    50:50 (gleich gut):
    E O E O E O E O E O
    A1 A2 A1 A2 A1 A2 A1 A2 A1 A2

    30:70 (ANT2 besser):
    E O E O E O E O E O
    A2 A2 A1 A2 A2 A1 A2 A2 A1 A2
    → A1 deckt Pos. 2(E), 5(O), 8(E) — beide Slot-Typen abgedeckt

    Der UCB1-Algorithmus entscheidet welches Verhältnis gesetzt wird —
    basierend auf akkumulierten SNR-Scores über 8 Messzyklen. Ziel ist
    besserer Empfang mit vorhandener Hardware, ohne externen Umschalter,
    vollautomatisch.

    73 de DA1MHH

    ---
    ENGLISH:

    Hello OM,

    SimpleFT8 uses Temporal Polarization Diversity to optimize reception
    with two connected antennas.

    ANT1 is the transmit antenna (TX only), ANT2 is receive-only.
    ANT2 can be anything: rain gutter, balcony railing, random wire,
    or a wire thrown over a fence. Since different bands have different
    polarizations (vertical/horizontal) and optimal lengths, this second
    simple antenna can sometimes outperform the main antenna on specific
    bands.

    Automatic re-calibration: at startup AND every 80 cycles (~20 min).
    Necessary because conditions change constantly: weather (moisture,
    snow), propagation, time of day, band in use.

    Four operating modes over 10 cycles (E=even slot, O=odd slot):

    100% ANT1 (Normal mode):
    E O E O E O E O E O
    A1 A1 A1 A1 A1 A1 A1 A1 A1 A1

    70:30 (ANT1 better):
    E O E O E O E O E O
    A1 A1 A2 A1 A1 A2 A1 A1 A2 A1
    → A2 covers pos. 2(E), 5(O), 8(E) — BOTH slot types covered

    50:50 (equal):
    E O E O E O E O E O
    A1 A2 A1 A2 A1 A2 A1 A2 A1 A2

    30:70 (ANT2 better):
    E O E O E O E O E O
    A2 A2 A1 A2 A2 A1 A2 A2 A1 A2
    → A1 covers pos. 2(E), 5(O), 8(E) — BOTH slot types covered

    The UCB1 algorithm decides which ratio to apply, based on
    accumulated SNR scores over 8 measurement cycles. Goal: better
    reception using existing hardware, no external switch needed,
    fully automatic.


    P.S. For full technical details, source code, and measurement
    results (+37% decoded stations with Diversity on 40m):
    https://github.com/mikewanne/SimpleFT8
    MIT license, free to use and extend.

    73 de DA1MHH
  • reed
    reed Member ✭✭

    In 50:50 mode, why not do A1 A1 A2 A2 A1 A1 A2 A2?

  • mikewanne
    mikewanne Member
    **@reed** — you were completely right, in both comments. And I apologize for not catching it immediately.

    Your Comment 1 described the exact bug: if a station transmits on Slot 1 and ANT2 is the only antenna that hears them well, the old A1-A2-A1-A2 pattern would permanently assign Slot 1 to ANT1 — that station would never be decoded. The diversity would be pointless for that station.

    Your Comment 2 gave the exact fix.

    **What changed in v0.24.2 (just pushed):**
    Old 50:50: `("A1","A2")[cycle % 2]` → Even-slot stations locked to ANT1, Odd-slot stations locked to ANT2
    New 50:50: `("A1","A1","A2","A2")[cycle % 4]` → every antenna covers one Even AND one Odd slot per 4-cycle block

    Now every station — regardless of its Even/Odd slot — is heard on both antennas within 60 seconds. That's genuine temporal diversity.

    One-line fix, real improvement. Thank you for pushing on it.

    ---

    **Deutsch:** Du hattest in beiden Kommentaren vollständig recht — und ich entschuldige mich, dass ich es nicht sofort erkannt habe. Dein Kommentar 1 beschrieb den genauen Fehler, dein Kommentar 2 den exakten Fix. In v0.24.2 ist das jetzt korrigiert: A1-A1-A2-A2 stellt sicher, dass jede Antenne beide Slot-Typen abdeckt. Danke schön ,mein Fehler. Mnchmalsieht man den Wald vorlauter bäumen nicht. ;-)
  • reed
    reed Member ✭✭

    Makes sense now! I'm glad it was an easy change!

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.