Test integrity of the samples

Dear All
I would like to test the integrity of the samples coming from the card. Also is it possible to replace the RF signals with a digital ramp to test this continuity? On other cards: RTL-SDR example, it is possible to check this point.

Thank you

int [LMS7_Device::SetTestSignal](file:///home/auvray/Kersig/LimeSuite/build/html/classlime_1_1LMS7__Device.html#ae5095160b4cd92edb85091ba7168316e)(bool dir_tx, unsigned chan, lms_testsig_t sig, int16_t dc_i, int16_t dc_q)

{

lime::LMS7002M* lms = [SelectChannel](file:///home/auvray/Kersig/LimeSuite/build/html/classlime_1_1LMS7__Device.html#af05de0af1cdcc5fd7e96ca7990508e3a)(chan);

if (dir_tx == false)

{

if (lms->Modify_SPI_Reg_bits(LMS7param(INSEL_RXTSP), sig != LMS_TESTSIG_NONE, true) != 0)

return -1;

if (sig == LMS_TESTSIG_NCODIV8 || sig == LMS_TESTSIG_NCODIV8F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFCW_RXTSP), 1);

else if (sig == LMS_TESTSIG_NCODIV4 || sig == LMS_TESTSIG_NCODIV4F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFCW_RXTSP), 2);

if (sig == LMS_TESTSIG_NCODIV8 || sig == LMS_TESTSIG_NCODIV4)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFC_RXTSP), 0);

else if (sig == LMS_TESTSIG_NCODIV8F || sig == LMS_TESTSIG_NCODIV4F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFC_RXTSP), 1);

lms->Modify_SPI_Reg_bits(LMS7param(TSGMODE_RXTSP), sig == LMS_TESTSIG_DC);

}

else

{

if (lms->Modify_SPI_Reg_bits(LMS7param(INSEL_TXTSP), sig != LMS_TESTSIG_NONE) != 0)

return -1;

if (sig == LMS_TESTSIG_NCODIV8 || sig == LMS_TESTSIG_NCODIV8F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFCW_TXTSP), 1);

else if (sig == LMS_TESTSIG_NCODIV4 || sig == LMS_TESTSIG_NCODIV4F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFCW_TXTSP), 2);

if (sig == LMS_TESTSIG_NCODIV8 || sig == LMS_TESTSIG_NCODIV4)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFC_TXTSP), 0);

else if (sig == LMS_TESTSIG_NCODIV8F || sig == LMS_TESTSIG_NCODIV4F)

lms->Modify_SPI_Reg_bits(LMS7param(TSGFC_TXTSP), 1);

lms->Modify_SPI_Reg_bits(LMS7param(TSGMODE_TXTSP), sig == LMS_TESTSIG_DC);

}

if (sig == LMS_TESTSIG_DC)

return lms->LoadDC_REG_IQ(dir_tx, dc_i, dc_q);

return 0;

}

Anybody to help me?
In fact I would like to be sure there is no lost sample for the acquisition.
Please somebody to share with me?

David

I share with you a SingleRx program with some modifications to see the behavior of the FIFO and the reception.
If I put a time delay I see that I do not have the right bit rate, if I remove the time delay, the average bit rate calculated with the sum of the samples received at the user level and the time between the start of the streamer and the end of program is ok.
In the case where the flow is kb, I observe that the fifo is always almost full and an overrun variable other than 0.
Question:

  1. What
    matches overrun?
  2. How to ensure that there is no loss of samples?

Thank you

/**
@file singleRX.cpp
@author Lime Microsystems (www.limemicro.com)
@brief RX example
*/
//#define USE_GNU_PLOT = 1
#include “lime/LimeSuite.h”
#include
#include
#ifdef USE_GNU_PLOT
#include “gnuPlotPipe.h”
#endif
#include
#include <unistd.h>
#include <time.h>
#include <stdio.h>

using namespace std;

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

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

double GetTickcount(void);

int main(int argc, char** argv)
{

//Find devices
//First we find number of devices, then allocate large enough list,  and then populate the list
int n;
if ((n = LMS_GetDeviceList(NULL)) < 0)//Pass NULL to only obtain number of devices
    error();
cout << "Devices found: " << n << endl;
if (n < 1)
    return -1;

lms_info_str_t* list = new lms_info_str_t[n];   //allocate device list

if (LMS_GetDeviceList(list) < 0)                //Populate device list
    error();

for (int i = 0; i < n; i++)                     //print device list
    cout << i << ": " << list[i] << endl;
cout << endl;

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



delete [] list;                                 //free device list

//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, 800e6) != 0)
    error();

//print currently set center frequency
float_type freq;
if (LMS_GetLOFrequency(device, LMS_CH_RX, 0, &freq) != 0)
    error();
cout << "\nCenter frequency: " << freq / 1e6 << " MHz\n";

//select antenna port
lms_name_t antenna_list[10];    //large enough list for antenna names.
                                //Alternatively, NULL can be passed to LMS_GetAntennaList() to obtain number of antennae
if ((n = LMS_GetAntennaList(device, LMS_CH_RX, 0, antenna_list)) < 0)
    error();

cout << "Available antennae:\n";            //print available antennae names
for (int i = 0; i < n; i++)
    cout << i << ": " << antenna_list[i] << endl;

if ((n = LMS_GetAntenna(device, LMS_CH_RX, 0)) < 0) //get currently selected antenna index
    error();
//print antenna index and name
cout << "Automatically selected antenna: " << n << ": " << antenna_list[n] << endl;

if (LMS_SetAntenna(device, LMS_CH_RX, 0, LMS_PATH_LNAW) != 0) // manually select antenna
    error();

if ((n = LMS_GetAntenna(device, LMS_CH_RX, 0)) < 0) //get currently selected antenna index
    error();

//print antenna index and name
cout << "Manually selected antenna: " << n << ": " << antenna_list[n] << endl;

//Set sample rate to 1 MHz, preferred oversampling in RF 8x
//This set sampling rate for all channels
if (LMS_SetSampleRate(device, 1e6, 8) != 0)
    error();
//print resulting sampling rates (interface to host , and ADC)
float_type rate, rf_rate;
if (LMS_GetSampleRate(device, LMS_CH_RX, 0, &rate, &rf_rate) != 0)  //NULL can be passed
    error();
cout << "\nHost interface sample rate: " << rate / 1e6 << " MHz\nRF ADC sample rate: " << rf_rate / 1e6 << "MHz\n\n";

//Example of getting allowed parameter value range
//There are also functions to get other parameter ranges (check LimeSuite.h)

//Get allowed LPF bandwidth range
lms_range_t range;
if (LMS_GetLPFBWRange(device,LMS_CH_RX,&range)!=0)
    error();

cout << "RX LPF bandwitdh range: " << range.min / 1e6 << " - " << range.max / 1e6 << " MHz\n\n";

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

//Set RX gain
if (LMS_SetNormalizedGain(device, LMS_CH_RX, 0, 0.7) != 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;

//Perform automatic calibration
if (LMS_Calibrate(device, LMS_CH_RX, 0, 8e6, 0) != 0)
    error();

//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_NCODIV4, 0, 0) != 0)
    error();

//Streaming Setup

//Initialize stream
lms_stream_t streamId;
streamId.channel = 0; //channel number
streamId.fifoSize = 1024 * 1024; //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; //32-bit floats

if (LMS_SetupStream(device, &streamId) != 0)
    error();

//Data buffers
const int bufersize = 10000; //complex samples per buffer
float buffer[bufersize * 2]; //must hold I+Q values of each sample
//Start streaming

float startTick;
lms_stream_status_t status;
int samplesRead;
int nb_samplesRead =0;


LMS_GetStreamStatus(&streamId, &status);
cout << "timestamp avant start: " << status.timestamp << endl; ;
cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;
startTick = GetTickcount() ;
LMS_StartStream(&streamId);
LMS_GetStreamStatus(&streamId, &status);
cout << "timestamp après start lecture: " << status.timestamp << endl; ;
cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;

#ifdef USE_GNU_PLOT
GNUPlotPipe gp;
gp.write(“set size square\n set xrange[-1:1]\n set yrange[-1:1]\n”);
#endif

float startTickCount, transferTime_sec;

auto t1 = chrono::high_resolution_clock::now();
auto t2 = t1;

while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(10)) //run for 10 seconds
{

    LMS_GetStreamStatus(&streamId, &status);
    cout << "timestamp avant lecture: " << status.timestamp << endl; ;
    cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;
    samplesRead = LMS_RecvStream(&streamId, buffer, bufersize, NULL, 1000);
    nb_samplesRead = nb_samplesRead + samplesRead;
    LMS_GetStreamStatus(&streamId, &status);
    cout << "samplesRead  : " << samplesRead  << endl;
    cout << "timestamp apres lecture: " << status.timestamp << endl; ;
    cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;

#ifdef USE_GNU_PLOT
gp.write(“plot ‘-’ with points\n”);
for (int j = 0; j < samplesRead; ++j)
gp.writef("%f %f\n", buffer[2 * j], buffer[2 * j + 1]);
gp.write(“e\n”);
gp.flush();
LMS_GetStreamStatus(&streamId, &status);
//Receive samples
cout << "timestamp gnu plot: " << status.timestamp << endl; ;
cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;
cout << "droppedPackets: " << status.droppedPackets << endl; ;
cout << "overrun: " << status.overrun << endl; ;
//cout << "RX fifo: " << 100 * status.fifoFilledCount / status.fifoSize << “%” << endl; //percentage of FIFO filled

#endif
startTickCount = GetTickcount() ;
usleep(1e5);
transferTime_sec = (GetTickcount() - startTickCount) ;
cout << "time : " << transferTime_sec/1000 << endl; ;
LMS_GetStreamStatus(&streamId, &status);
//Receive samples
cout << "timestamp 2: " << status.timestamp << endl; ;
cout << "fifoFilledCount: " << status.fifoFilledCount << endl; ;
cout << "droppedPackets: " << status.droppedPackets << endl; ;
cout << "overrun: " << status.overrun << endl; ;
//Get stream status

    //I and Q samples are interleaved in buffer: IQIQIQ...
/*
	INSERT CODE FOR PROCESSING RECEIVED SAMPLES
*/

    //Print stats (once per second)
    if (chrono::high_resolution_clock::now() - t2 > chrono::seconds(1))
    {
        //Plot samples


        t2 = chrono::high_resolution_clock::now();

        //Get stream status
        LMS_GetStreamStatus(&streamId, &status);
        cout << "RX data rate: " << status.linkRate / 1e6 << " MB/s\n"; //link data rate
        cout << "RX fifo: " << 100 * status.fifoFilledCount / status.fifoSize << "%" << endl; //percentage of FIFO filled
    }
}

 cout << "nb_samplesRead: " << nb_samplesRead << endl;
 transferTime_sec = (GetTickcount() - startTick) /1000;
 cout << "transferTime_sec: " << transferTime_sec << endl;
cout << "debit: " << nb_samplesRead*2*2/transferTime_sec/1e6 <<  "Mbytes/s" << endl;
//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;

}
double GetTickcount(void)
{

struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now))
    return 0;
return now.tv_sec*1000.0+now.tv_nsec/1000000.0;

}

Hello @auvray,

Per my understanding, the number of overruns indicates a number of packages that were overwritten in the internal LimeSDR incoming buffer after last check. More details you can find in the source code:

As far as I concerned you need to call the LMS_GetStreamStatus every time after the LMS_RecvStream one and check the following:

  • droppedPackets is zero, which means that no packages has been lost between a board and host;
  • overrun is zero, which means that you take data from the LimeSDR buffer quickly enough.

As I can see from the sources the underrun value reflects non critical issues (when requested data isn’t available), so it shouldn’t be considered as an error and it can be ignored in scope of your question.

Also some useful information can be found in the API comments:

Hope it helps.

2 Likes

Thanks for all

I appreciated

David