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 (mirror2) (9.3 kb, 217 dls, today: 0)

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.

Trackback responses to this post

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