Using an “iPod” FM Transmitter and a standard radio receiver with a headphone jack, I set out to make a simple radio modem. The idea is that I have here a transmitter and receiver and all I have to do is connect the transmitter to the audio out on one computer, and the receiver to the microphone or line-in jack on another, modulate the input to the transmitter and demodulate it on the other side to transmit binary data. Initially, I wanted to use AFSK (audio frequency shift keying) but, to get a working proof of concept, I decided to use Amplitude shift keying since I thought it would be easier to get off the ground.
To start, I wrote a separate program for the sending and receiving side so I could work the bugs out of both, then later I will integrate the two. For the transmitting side, I used the SDL library to create and play the output signal. The program will be a sort of one way “chat”, where the one user will type in a string, hit return and then it will be transmitted. The sending program loops through the string bit by bit and sends a tone for a 1 and silence for a 0. The period of each tone or silence is 1/(BAUD rate) and I arbitrarily chose the frequency of the tone to be 12kHz, and I initially set the BAUD rate slow, so that I could hear it and detect problems, but now I have it running well at 9600 BAUD. Both, the capture and playback operate at 48,000 samples/second, since this is the fastest (and native) speed of my sound card’s clock.
The receiving side uses the ALSA library for capture since SDL does not natively support audio capture. The program constantly reads in and process data from the sound card. It takes an average power over the last 5 samples and tries to discriminate between a 0 and 1. When the program first starts, it reads in 500 average power samples and uses this as the noise level. After that, every 1/BAUD seconds it tests the current average power, if it is greater than the noise offset + a (arbitrary for now) threshold, then it is a one, otherwise, it is a zero. The program is constantly shifting in bits until it reads a 0xAB, which is the start sequence. The next 2 bytes it reads in is taken as an unsigned 16 bit value (everything is lsb first) representing the length of the incoming message (so there is no stop sequence). After this value is read in, it reads in that many bytes and then prints the message on screen.
The programs for sending and receiving are a hack at the moment. Some problems I am having right now include a non-robust protocol (no error checking) and problems sending large files. On the receiving side, there are two possible errors that can occur. Misinterpreting a bit and getting out of sync by one bit. The first problem simply changes the bytes value, which could theoretically be handled if I had some error checking. The latter issue of getting off by one bit, causes chaos for the remainder of the message. Especially bad is if the length value at the beginning of the message is bad, then it tries to read in an arbitrarily large number of bytes. If the start sequence is missed, then the message is simply ignored. Also, the current setup is finicky about the volume of the input. For testing, I use an audio patch cable between the output and input of my computer, and I keep the volume around %54. When I use the radio, I have to play around with the volume knob a bit to find a good level for reliable transmitting.
Initially, the range of the transmitter was very short, 15 feet or less depending on the surroundings. I popped open the case and saw the “antenna” which was a coil printed on the PCB. At the end of the coil was a small through hole that I soldered on a copper wire antenna that was about 1/4 wavelength. This dramatically improved the range to several hundred feet! So you may want to try this if you are thinking about doing it.
Download the code + binaries here
This requires a Linux system with the SDL and ALSA development libraries to compile. I have compiled the sender program on Windows as well since it uses SDL, but it had some issues and did not work correctly. To get this working for you, it might take a bit of fiddling with the volume of the output, the radio and the recording level on the input. Also, it is important to get the tuner on the radio as close as possible. The way I tested it was to play some song over the radio since it was easier to tell if it was distorted by being slightly out of tune.