Sample Rate Achieved with LimeSDR Mini

Hi,

I have been using LimeSDR Mini to implement WiFi 802.11 standard which using sample rate of 20 MSamples/s. When I am trying to check the sample-rate actually received, it is lower than that of 20 MSamples/s. I have developed a GNURadio flowgraph as well as API for implementing WiFi receiver. I am saving the raw data in file sink for say 10 sec. In order to calculate sample rate I am converting the filesize to number of samples using following conversion:

No. of Samples = File Size (in kB) *8 /64(since each sample is 32 bit complex number)

Dividing these number of samples with time will give me sample rate. Is this the correct way or am I missing something?

Could anyone please clarify the reason behind lower sample rate? Is it to do something with the LimeSDR Mini board or some software issues.

Thanks
SG

Hi @IF3191,

Would not trust this kind of sample rate evaluation, while GNU radio may be a bottleneck.
Tell me CGEN frequency and decimation you are using.

Hi!

The centre frequency is 2.472 GHz, oversampling set to 1 and sample rate to 20 MSamples/s. I am using C++ API code for WiFi Rx also. At API level I am running the code for 10 seconds and keeping the count for the number of samples being read and written to the buffer using the code similar to that in examples provided with Limesuite. Even this is also giving lower sample rate.

What could be possible reason behind it?

Thanks
SG

What USB connection are you using (USB2/USB3)?
Do you have a chance to share your code based on API?

Hi,

I am using USB 3 Connection. Following is the API Code where I have used the basixRX.cpp for reading and writing the samples to a buffer and then process the samples received samples using concepts of WiFi PHY layer processing:

@file   basicRX.cpp
@author Lime Microsystems (www.limemicro.com)
@brief  minimal RX example

*/
#include “lime/LimeSuite.h”
#include
#include
#include

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/program_options.hpp>
#include <fun_ofdm/receiver.h>
#include <fun_ofdm/receiver_chain.h>
#ifdef USE_GNU_PLOT
#include “gnuPlotPipe.h”
#endif

using namespace std;

//Device structure, should be initialize to NULL
lms_device_t* device = NULL;
int rx_count = 0;

int error()
{
if (device != NULL)
LMS_Close(device);
exit(-1);
}

int main(int argc, char** argv)
{
std::ofstream myfile(“wifi_rx.txt”, std::fstream::out | std::ofstream::trunc );
//Find devices
int n;
lms_info_str_t list[8]; //should be large enough to hold all detected devices
if ((n = LMS_GetDeviceList(list)) < 0) //NULL can be passed to only get number of devices
error();

cout << "Devices found: " << n << endl; //print number of devices
if (n < 1)
    return -1;

//open the first device
if (LMS_Open(&device, list[0], NULL))
    error();

//Initialize device with default configuration
//Do not use if you want to keep existing configuration
//Use LMS_LoadConfig(device, "/path/to/file.ini") to load config from INI
//if (LMS_Init(device) != 0)
    //error();

//Enable RX channel
//Channels are numbered starting at 0
if (LMS_EnableChannel(device, LMS_CH_RX, 0, true) != 0)
    error();

//Set center frequency to 800 MHz
if (LMS_SetLOFrequency(device, LMS_CH_RX, 0, 2472e6) != 0)
    error();

//Set sample rate to 8 MHz, ask to use 2x oversampling in RF
//This set sampling rate for all channels
if (LMS_SetSampleRate(device, 20e6, 1) != 0)
    error();

  //Configure LPF, bandwidth 8 MHz
if (LMS_SetLPFBW(device, LMS_CH_RX, 0, 20e6) != 0)
    error();

//Set RX gain
if (LMS_SetNormalizedGain(device, LMS_CH_RX, 0, 0.95) != 0)
    error();
//Print RX gain
float_type gain; //normalized gain
if (LMS_GetNormalizedGain(device, LMS_CH_RX, 0, &gain) != 0)
    error();
cout << "Normalized RX Gain: " << gain << endl;

unsigned int gaindB; //gain in dB
if (LMS_GetGaindB(device, LMS_CH_RX, 0, &gaindB) != 0)
    error();
cout << "RX Gain: " << gaindB << " dB" << endl;

//Enable test signal generation
//To receive data from RF, remove this line or change signal to LMS_TESTSIG_NONE
//if (LMS_SetTestSignal(device, LMS_CH_RX, 0, LMS_TESTSIG_NCODIV8, 0, 0) != 0)
  //  error();

//Streaming Setup

//Initialize stream
lms_stream_t streamId; //stream structure
streamId.channel = 0; //channel number
streamId.fifoSize = 2048 * 2048; //fifo size in samples
streamId.throughputVsLatency = 1.0; //optimize for max throughput
streamId.isTx = false; //RX channel
streamId.dataFmt = lms_stream_t::LMS_FMT_F32; //12-bit integers
if (LMS_SetupStream(device, &streamId) != 0)
    error();

//Initialize data buffers
const int sampleCnt = 1000000; //complex samples per buffer
//int16_t buffer[sampleCnt * 2]; //buffer to hold complex values (2*samples))
   float buffer[sampleCnt * 2]; //buffer to hold complex values (2*samples))
    std::vector<std::complex<double>> complex_buffer;

//Start streaming
LMS_StartStream(&streamId);

//Streaming

#ifdef USE_GNU_PLOT
GNUPlotPipe gp;
gp.write(“set size square\n set xrange[-2050:2050]\n set yrange[-2050:2050]\n”);
#endif
int count_samples=0;
int count = 0;
auto t1 = chrono::high_resolution_clock::now();
auto t2=t1;
int alp =0;
while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(10)) //run for 5 seconds
{
//Receive samples
int samplesRead = LMS_RecvStream(&streamId, buffer, sampleCnt, NULL, 1000);

//printf("Received %d samples\n", samplesRead);
 count_samples += samplesRead;

//  PROCESSING RECEIVED SAMPLES

//I and Q samples are interleaved in buffer: IQIQIQ…
complex_buffer.clear();
for(int i=0;i<sampleCnt;i++)
{
complex_buffer.push_back({buffer[2i],buffer[(2i) +1]});
}

 fun::receiver_chain * receiver1 = new fun::receiver_chain();

 int chunk_size =65536;

   for(int x = 0; x < complex_buffer.size(); x += chunk_size)
   {
       int start = x;
       int end = x + chunk_size;
       if(end > complex_buffer.size()) end = complex_buffer.size();
              std::vector<std::complex<double> > chunk(&complex_buffer[start], &complex_buffer[end]);

       std::vector<std::vector<unsigned char> > rec_frames = receiver1->process_samples(chunk);
            
       count += rec_frames.size();
       
       if(rec_frames.size() != 0){
            std::cout<<rec_frames.size()<<"   rec_frames"<<std::endl;
        }

       if(rec_frames.size())
       {
       		   for(int i = 0; i < rec_frames.size(); i++)
       		   {
            		alp = alp + rec_frames[i].size();
	       			for(int j = 0; j < rec_frames[i].size(); j++)
                           myfile<<rec_frames[i][j];
			    }
       				myfile<<"\n";
       }
   }
    
                 
		#ifdef USE_GNU_PLOT
		        //Plot samples
		        gp.write("plot '-' with points\n");
		        for (int j = 0; j < samplesRead; ++j)
		            gp.writef("%i %i\n", buffer[2 * j], buffer[2 * j + 1]);
		        gp.write("e\n");
		        gp.flush();
		#endif
   
   
 }
myfile.close();
printf("Received %d samples\n", count_samples);
printf("Sample Rate %d MSamples/s \n", count_samples/(10*1e6));
printf("Received %i packets\n", count);
printf("total no. of chars in rec_frames - %i",alp);
//Stop streaming
LMS_StopStream(&streamId); //stream is stopped but can be started again with LMS_StartStream()
LMS_DestroyStream(device, &streamId); //stream is deallocated and can no longer be used

//Close device
LMS_Close(device);

return 0;

}

It looks like issue with data saving to the file. If there is any delay in the receive-data save to file loop, then there is a chance to lost received data. Try to use RAM disk for this purpose.

Thanks for the reply.

Also I keep getting MCU error 5 while running it on GNURadio. Why is that happening?

Thanks and Regards
SG

Hi Zack!

I just checked the sample rate achieved without writing to the file. It is still lower than 20 MSamples/sec. Is it because I am processing these samples within the loop that some samples are being lost or some other issue?

If that is the case how should I prevent loss of samples while processing them in parallel?

Thanks
SG

Most likely.

Well, many options. Better machine, data processing code/algorithm optimization and so on.

1 Like