DSP tutorial: RTTY encoder

This example is similar to the FSK encoder one, the main difference is that it uses a start and two stop bits, and encodes the message using the Baudot code to produce an RTTY signal. You can decode the sound generated with this encoder easily using a radio amateur digital mode app like FLdigi, MixW or DM780.

The generated RTTY signal’s parameters are:

  • Freq0: 915 Hz
  • Freq1: 1085 Hz
  • Baud rate: 45.45
  • Start bits: 1
  • Stop bits: 2

An RTTY signal looks like this:

Image taken from this page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
private static void playBit(int bit) {
        int samplesNeeded = (int)Math.round(SAMPLERATE/BITSPERSEC);
        double[] abBufferDouble = new double[samplesNeeded];
   
        for (int j = 0; j < samplesNeeded; j++) {
            oscPhase += (2 * Math.PI * (bit == 0 ? FREQ0 : FREQ1)) / SAMPLERATE;
   
            abBufferDouble[j] = Math.sin(oscPhase) * 0.2;
               
            if (oscPhase >= 2 * Math.PI)
                oscPhase -= 2 * Math.PI;
        }
        sdl.write(getBytesFromDoubles(abBufferDouble, samplesNeeded), 0, samplesNeeded*sdl.getFormat().getFrameSize());
    }

    public static void playStopBits() {
        System.out.print(" 1");
        playBit(1); // stop bit
        System.out.print(1);
        playBit(1); // stop bit
    }
   
    public static void switchToLetterMode() {
        System.out.print("LTRS: 0 ");
        playBit(0); // start bit

        for (int i = 0; i < 5; i++) {
            System.out.print(1);
            playBit(1);
        }

        playStopBits();
        mode = RTTYMode.letters;
        System.out.println();
    }

    public static void switchToSymbolMode() {
        System.out.print("FIGS: 0 ");
        playBit(0); // start bit

        System.out.print(1);
        playBit(1);
        System.out.print(1);
        playBit(1);
        System.out.print(0);
        playBit(0);
        System.out.print(1);
        playBit(1);
        System.out.print(1);
        playBit(1);

        playStopBits();
        mode = RTTYMode.symbols;
        System.out.println();
    }

    public static void main(String[] args) {
        AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, SAMPLERATE, 16, 1, 2, SAMPLERATE, false);
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat, BUFFERSIZE);

        try {
            sdl = (SourceDataLine)AudioSystem.getLine(info);
            sdl.open(audioFormat, BUFFERSIZE);
        } catch (LineUnavailableException e2) {
            e2.printStackTrace();
        }
        sdl.start();

        // initializing tone
        for (int i = 0; i < 16; i++)
            playBit(0);

        for (;;) {
            switchToLetterMode();

            for (int msgPos = 0; msgPos < msg.length(); msgPos++) {
                char c = Character.toUpperCase(msg.charAt(msgPos));
                int foundAt = -1;
                for (int i = 0; i < RTTYLetters.length; i++) {
                    if (RTTYLetters[i] == c) {
                        foundAt = i;
                        if (mode != RTTYMode.letters)
                            switchToLetterMode();
                        break;
                    }
                }
                if (foundAt < 0) {
                    for (int i = 0; i < RTTYSymbols.length; i++) {
                        if (RTTYSymbols[i] == c) {
                            foundAt = i;
                            if (mode != RTTYMode.symbols)
                                switchToSymbolMode();
                            break;
                        }
                    }
                    if (foundAt < 0)
                        foundAt = 4; // sending space if character is not in the baudot table
                }

                if (c == '\n')
                    System.out.print("NL");
                else
                    System.out.print(c);
                System.out.print(" (" + foundAt + "): 1 ");

                playBit(0); // start bit
                for (int charBitPos = 0; charBitPos < 5; charBitPos++) {
                    int bit = ((foundAt & (1 << charBitPos)) == 0 ? 0 : 1);
                    System.out.print(bit);
                    playBit(bit);
                }
                playStopBits();
                System.out.println();
            }
        }
        //sdl.drain();
        //sdl.close();
    }

download (9.3 kb)

Jörg Hagedorn 2018-12-12 20:48:04

Hallo,
herzlichen Dank für Software. Ich möchte damit meinen Navtex Empfänger testen.
Gruss
Jörg

 

[…] but finally under the advice of some Ham radio enthusiast friends of mine I implemented the RTTY line protocol running at 150 baud, which in practice gives me maybe about 10 bytes per second. It’s not […]

 
Name (required)
E-mail (required - never shown publicly)
Webpage URL
Comment:
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

About me

Nonoo
I'm Nonoo. This is my blog about music, sounds, filmmaking, amateur radio, computers, programming, electronics and other things I'm obsessed with. ... »

Twitter

Listening now

My favorite artists