This project allows one to transmit message using an FM transmitter and a Software Defined Radio. This is not particularly useful. However, this project did help me learn about Software Defined Radios and basic signal processing.
sounddevice is used to play signals on the sound card and use the FM transmitter:
pyrtlsdr is used to receive IQ samples from the SDR.
rtl-sdr is required to use pyrtlsdr.
scipy is used for signal processing functions.
PyQtGraph is used for real time graphing:
To encode messages, we first convert the string to bits. Next we, encapsulate the message in a very simple header, shown below.
[ 1 1 1 1 1 0/1 0/1 0/1 0/1 0/1 0/1 ... ]
^ ^ ^ ^ ^ ^ ^ ^ ^
preamble id frag checksum message
To transmit our header and message, we use Manchester encoding to represent each bit as a change from low to high or high to low. Then we create an AM signal from this encoding. Finally, we play the AM signal on the sound card, which sends it out of the FM transmitter. To make life easier for the receiver, we will only send messages on second boundaries. This will make it easier for the receiver to know if a transmission is taking place, as he/she only has to start capturing samples on second boundaries. Note, this makes syncing the clocks of the sender and receiver critical.
To receive the signal, we first have to determine if a transmission is taking place. To do so, we first tune our SDR to the frequency agreed upon by the sender and receiver. As discussed in the Transmitting section, we will record samples starting at second boundaries. Next, we compute the Fast Fourier Transform of the captured samples. This decomposes the captured signal into its constituent frequencies. If the FFT at the agreed upon frequency is greater than some threshold, then we know a transmission is taking place.
Once we know a transmission is taking place. We must decode the signal to retrieve the message. To do so, we first FM demodulate the signal to get the AM signal.
Next, we take the absolute value of the AM signal and find the envelope.
Next, we use thresholding to create a square wave.
Finally, we decode the manchester encoded square wave to get the header and message as an array of bits. We then calculate a simple checksum (bit parity) and check the message id is the same as expected. If the fragment bit is set, we know that we should continue to wait for more transmissions. Otherwise, we print the message received.
PyQtGraph is used to graph the FFT and AM signal of the samples received. The graphing server creates a ZMQ socket to receive samples from the process that receives IQ samples from the SDR and decodes the messages.