Transferring a text file over the air with LimeSDR mini
We have seen the LimeSDR mini several times on this blog. So far, we have only seen how it can generate analog modulation to transmit voice and what not. Being an SDR capable to transmit practically anything, we can even transmit binary data. Speaking of binary, we will have to jump into digital modulation techniques. In this article, I will demonstrate how I used the LimeSDR mini to transmit a small CSV text file over the air. For this experiment, I will use three things. One of them is obviously the LimeSDR mini. The second one is our friend GNURadio and the third being an RTL-SDR to receive it on the other side.
The transmitter setup
The setup will be quite simple and I won’t go into too many technical details. My choice of modulation will be Binary Phase shift Keying (BPSK) and my GNU Radio flow graph will tell you how I did it.
Here, we start with the File source that provides an output in byte format. The ‘Packet Encoder’ accepts the byte and encodes the data in ‘1 bit’ per symbol format. Further, the constellation modulator maps the bit to corresponding phase shifts known as symbols. In case of BPSK modulation, the phase shifts between two symbols are going to be \(180^o\) apart. If we were to use QPSK modulation, the packet encoder would have to provide ‘2 bits’ per symbol. Correspondingly, the Constellation modulator would map the symbols \(90^o\) apart. Remember, the modulated bits are simply mapped to their respective phases represented as either \(1 and -1[latex].[caption id="attachment_6393" align="alignnone" width="800"] Phase vs. symbol. This is what we call a constellation diagram.[/caption]
I am sure you must have seen the QPSK constellation while downloading Meteor-M2 images with your RTL-SDR setup.
A little math
To understand this process better, imagine that you have a sine wave. Multiplying it with [latex]+1\) will result in,
\(+1 \times sin(2\pi ft) = sin(2\pi ft)\)
Whereas, multiplying it with \(-1\) will result in,
\(-1 \times sin(2\pi ft) = -sin(2\pi ft)\)
The negative sign on the sine indicates a \(180^o\) phase shift. Correspondingly, we would see the following waveform.
The phase shift or rather the symbols now need to be mounted on a carrier. To do that, we multiply the symbols with a 20kHz sine wave. It could be any frequency in the nyquist range. After doing do, we will change the sampling rate to match the sampling rate of the LimeSDR DAC. The rational resampler block interpolates the modulated signal by 20 times to achieve the LimeSDR sampling rate of 2.048MHz. I chose the sampling rate of the LimeSDR to be an integer multiple of the base band sampling rate to reduce the complications. Notice that the LimeSDR sink is set to up-conversion mode. We will be transmitting the data on 435MHz.
The receiver setup
On the receiving end, I am using an RTL-SDR with a sampling rate set to 1.024MHz. The gains are set to automatic and the RF value set to 435MHz. Again, on the receiving side, we decimate the data stream from RTL-SDR. Further, multiply it with a 20kHz source to center the constellation around DC. The received data could also contain unwanted signals which need to be filtered out. The low pass filter takes care of that. Furthermore, the polyphase clock sync block synchronizes the sampling time such that we get the maximum possible signal to noise ratio. The costas loop is meant for fine frequency correction which is necessary for correct demodulation of digital signals. An uncorrected frequency will result in the phase rotating constantly leading to no demodulation happening altogether. The costas loop basically locks onto the received signal’s carrier and outputs a good demodulated constellation.
After the Costas Loop, you can see the LMS DD Equalizer block. What this does is basically tries to compensate the multipath effects. In case you don’t know, whenever we transmit a signal, it will travel wherever it can and even bounce of multiple walls, objects, moving vehicles and so on before finally arriving at the receiving antenna. Correspondingly, all these paths vary in distance resulting in a shifted versions of the signal arriving at the receiver. The Equalizer block tries to minimize the effect of multipath propagation.
Furthermore, we demodulate the carrier and end up with bits. Remember, we have enabled differential encoding in the transmitter and we need to decode it to retrieve the original bit pattern. The differential decoder does that job and passes the data further to the packet decoder and then to the File sink. To elaborate, the File Sink block requires the data to be 8 bits in size. The Packet decoder block packs the 1 bit per symbol into 8 bits before sending it to the File sink.
If you wish to read more about this in detail, you can follow this link to GNURadio official guide.
While transmitting the file, the receiver often drops the initial few bytes of data. This happens because the receiver algorithms, especially the clock sync and the costas loop require time to converge. For testing the setup, I chose a small CSV file and transmitted it. Except for losing the initial couple of bytes, the transmission was flawless.
I used an online tool to compare the transmitted and received files and here is the result below. We are able to receive correct data over the air and the comparison of two files prove it.
When trying this with QPSK, the packet encoder does not work correctly every time. It took me several tries to make it work. Apparently, the initial convergence time plays a significant role in QPSK transmission especially when you are using the packet encoder block which is known to be flawed. Perhaps, I will have to find an alternative to that. Finally, this is the link to the GRC file which contains both, the TX as well as the RX blocks. Simply enable or disable them as per your need.
If you don’t have a LimeSDR mini, you could try this setup on a PlutoSDR or even HackRF one. In case you have neither of those, go ahead and buy one from Aliexpress.
Hii.. This is bindu.. can i use the same code with 2 limesdr by changing the rtl-sdr source to limesuite source
Yes you can.
please help me to receive the file by using two limesdr
But i’m not receiving any data
I downloaded your .grc file and I use HackRfone and Rtlsdr. It is working well but, it is not writing from input.txt file to output.txt file. Do you have any suggestion ?
Can you try increasing the preamble length and trying again? Are you able to see two discrete clusters on the constellation at the RX end?
Thank you for the detailed write-up! I’ve added a QT GUI Constellation Sink block right after the Rational Resampler and it’s showing me dots forming rounds and rounds in the centre. I wanted to see the constellation of BPSK modulation before transmission. May I know if that’s the correct way to do it?
Hi Grace, you cannot see a constellation after the re-sampler. You can try seeing it after the Constellation modulator block.
I tried your flowgraph with a B200 and a B210. There is no output to the receiver file. I am getting four clusters at the RX end constellation. Any suggestions to fix it?
I just wanted to update my previous comment. I am getting the BPSK constellation in the plot after the LMS DD Equalizer, but I am not getting any written into file in the File sink. Any suggestions to fix this? What could be going wrong?
Any upate to my previous comment. I got the BPSK working. I works really fine. I am now trying to get the QPSK to work. Have you ever tried it before? I made some changes to the flowgraph, I am getting the QPSK constellation after the equalizer, but nothing gets written into to the file in the file sink. Any suggestion to fix it? I would really appreciate it.
Were you able to successfully transmit and receive the text file using QPSK? I have been trying to do it, but the packet encoder does not give out any output. I’m getting a clean QPSK constellation in the constellation plot. Any suggestions to fix it? How did you get it working? I would really appreciate your help. I’m kinda desperate to get it working.
I did try with QPSK but the GNU Radio’s packet encoded gave problems. The receiver did generate the QPSK constellation very well but I wasn’t able to get the bits written to file.
I try to do it from limesdr to limesdr. It work very well but I have some problem. When I config repeat in file source = No I can’t receive anything. Can you help or advice me how to fix it ?
2 How to fix number of repeat?
I dont exactly know why that might be happening.
I have been looking at your code and I have some quick questions. Would it be possible to discuss it with you over email?
Hi salil, can I change a transmit and receive frequency to 1GHz?
Sure you can. No problem at all. In fact you can do this over any frequency.
Hi Salil, can I transfer other type of file extensions such as .jpg using your flow graph design?
Yes absolutely. Any file will work. Afterall, its all binary no matter the extension.
Thanks Salil, but I already test with one .jpg file extensions, the file was corrupted, is there any way on the block parameters that the value need to be adjusted?
I think you guys may be having issues because Packet Encoder/Decoder sucks so much it’s been deprecated in recent releases. You are supposed to use other methods to do that, but there’s not much useful information out there on it.
Hi, I tried to use hackrf one-to-text transmission with this configuration.GNU radio version 3.9.2 with me. There is no packet encoder/decoder. What will be the solution for this? Could you please help me to solve this?
I used hackrf to transmit a text file while using osmocom sink and osmocom source instead of LimSUite Sink and RTL-SDR source respectively. But I received nothing.Why is that?
When use the hackRF one is it needed to change the sampling rates? I tried this but nothing receive
I have used two HackRFs.When running it gives “The blks2.packet_decoder block is deprecated”.Anyone can help me to clarify the reason for this??
how can i adapt this for a sdr to sdr model?