RF loopback lock

I have my mini sdr v2 connected with an RF cable from TX to RX. I am trying various different frequencies to see if my applications ‘locks’ on TX and RX frequencies that are not the same.

So far I get lock when the TX/RX frequency is the same as expected.

I also get an unstable lock (I expected no lock) using the following TX/RX frequencies:
Radio Setup Transmitter

Radio Setup: TX Freq 100000000

Radio Setup: TX BW 5000000

Radio Setup: TX Sample Rate 2194286

Radio Setup: TX Gain 30

Radio Setup Receiver

Radio Setup: RX Freq 10000000

Radio Setup: RX BW 1400100

Radio Setup: RX Sample Rate 2194286

Radio Setup: RX Gain 10

I expected that we would get no lock whatsoever with the difference in frequencies.

It would be usefull to know what it means to “lock” in your application, how it works.

Besides that, with your given parameters, there are nuances:
It is expected that Rx and Tx sampling rates would be identical.
The LMS7002M chip LO can be as low as 30MHz, to get lower to your Rx 10MHz, it would need to apply digital up/down conversion, which would require a change in sampling rate to be at least 40MHz.
So the unstable lock that you’re experiencing might be that the system is running with a different parameters than you expect.

Hi,

I have my own measurements of lock. But a lock means that I am receiving the data I expect to receive in the format and order I expect it.

I have done more testing and it appears that about the only way I can avoid lock is to set the transmitter to 30e6 and the receiver to 3.5e9 and take off the RF cable.

If I do 1.0e9 and 1.3e9 I get lock, if I do 2.0e9 and 1.0e9 I get lock, and several other combinations. Most of the time the lock comes and goes, but with the USRP I never get lock in RF loopback unless the TX/RX frequencies are the same (or very close).

M-

In that case I can’t really help more without seeing the code that performs the configuration, or understading how your algorithms works. Do you configure the low pass filters?

Considering such wide frequency differences, then it must be an analog part nuances, RF leakage, harmonics… or how your algorithm deals with them.

I do set the bandwidth:
int LimeSDR::set_tx_bandwidth(double val) {
float_type call_hz = convert_value_to_range(val, &tx_bandwidth_range );
fprintf(stdout,“%s:%d Set TX bandwidth %lf \n”,func,LINE, call_hz);
int ret = LMS_SetLPFBW(lms_device, LMS_CH_TX, 0, call_hz );
if (ret <0) {
fprintf(stderr,“%s:%d error setting TX bandwidth ("%s") \n”, func,LINE, LMS_GetLastErrorMessage());
ret = -1;
}
else
{
lms_tx_bandwidth = call_hz;
ret = 0;
}
//fprintf(stdout,“%s:%d set tx bandwidth to %lf \n”, func,LINE,get_tx_bandwidth() );

return ret;
}
set_tx_bandwidth:569 Set TX bandwidth 5000000.000000
Filter calibrated. Filter order-4th, filter bandwidth set to 5 MHz.Real pole 1st order filter set to 2.5 MHz. Preemphasis filter not active

It seems there is some “tribal knowledge” here. It would be nice to have a function that one could call like LMS_AdjustParmeters( float_type samplerate, float_type frequency, float_type bandwidth_in, float_type *samplerate_out, float_type *frequency_out, float_type *bandwidth_out ) …

that adjusts the parameters to the correct values for LMS7002M.

M-

Indeed, there are some conditional limitations of the hardware on the edge cases. And the legacy API is troublesome when it comes to them, as each function is focused on single parameter change, while some of the underlying parameters are dependent on each other, so their configuration order matters.

Closest to that would be in the new LimeSuiteNG API SDRDevice::Configure(), it takes all the configuration parameters at once and sets everything up in expected order and reports if the expected configuration cannot be achieved, and logs a reason why.

Good to know… which I had known sooner. I wen through the example code and it sets config.rx.lpf to zero. So they don’t use bandwidth… Also the antenna selection is manual, I assume I can make it AUTO.
config.tx.path and config.rx.path .

Is there a way to build NG without GNU Radio?

setting config.rx.lpf to 0, makes it bypassed.
At this moment, there is no AUTO option for atenna selection, but I intend to add it.

If GNU Radio is not installed in the system, LimeSuiteNG will not compile a plugin for it. If GNU Radio is installled, then you can disable plugin compilation in LimeSuiteNG with cmake option:
"cmake .. -DENABLE_GNURADIO=off"

For USRP there is a ‘bandwidth’ parameter that is set. Does the Lime SDR V2 mini, need bandwidth? If so where does one set it? (I mean when using the LimeSuite NG)

Here is what I get back when I query the bandwidth parameters of the antenna.

configure:202 antenna 0 (NONE)
configure:204 rx ant 0 NONE bandwidth range min 0.000000 max 0.000000 step 0.000000
configure:202 antenna 1 (LNAH)
configure:204 rx ant 1 LNAH bandwidth range min 2000000000.000000 max 2600000000.000000 step 0.000000
configure:202 antenna 2 (LNAL_NC)
configure:204 rx ant 2 LNAL_NC bandwidth range min 0.000000 max 0.000000 step 0.000000
configure:202 antenna 3 (LNAW)
configure:204 rx ant 3 LNAW bandwidth range min 700000000.000000 max 900000000.000000 step 0.000000
configure:202 antenna 4 (Auto)
configure:204 rx ant 4 Auto bandwidth range min 0.000000 max 0.000000 step 0.000000
configure:214 TX antenna 0 (NONE)
configure:216 tx ant 0 NONE bandwidth range min 0.000000 max 0.000000 step 0.000000
configure:214 TX antenna 1 (BAND1)
configure:216 tx ant 1 BAND1 bandwidth range min 2000000000.000000 max 2600000000.000000 step 0.000000
configure:214 TX antenna 2 (BAND2)
configure:216 tx ant 2 BAND2 bandwidth range min 30000000.000000 max 1900000000.000000 step 0.000000
configure:214 TX antenna 3 (Auto)
configure:216 tx ant 3 Auto bandwidth range min 0.000000 max 0.000000 step 0.000000

Is the Lime SDR supposed to go from 30 Mhz to 3.5 Ghz? If so I don’t see that in the antenna BW ranges…

Also I noticed that the config.rx.calibration and config.tx.calibration is false. Does this mean that calibration is done after the config by the code following?

I would assume that “bandwidth” is the sampling rate. in NG config.channel[0].rx.sampleRate

LMS7002M LO (local oscilator) supported range is 30 MHz to 3.5GHz. But the antennas have their own frequency ranges, because they have RF matching networks that are made to maximize efficiency for specific frequencies. Antennas are not limited to those ranges, but outside of them their efficiency will drop.

you can set config.rx.calibration to true and the calibration will be done as part of the initial configuration, or you can leave it false, and perform calibration at later time if necessary.

Hmmm. I am not an RF expert, but with USRP the bandwidth setting is separate from sampling rate. Also my code is setting the bandwidth based on a calculation that is different from sample rate. You mentioned that there is no AUTO setting for the NG Config API. So I need to know where the missing band sections should be assigned to which antenna. I will assume for now that the lower missing bands should be assigned to the lower band antennas and visa-versa for the higher missing bands.

I wrote these routines to do manual selection of the antenna. Does this look right?

typedef struct {
const char *name;
int number;
double min;
double max;
} ANTENNA_DESC;

ANTENNA_DESC rx_antennas = {
{ “LNAW”, 3, 700000000.000000, 900000000.000000 },
{ “LNAH”, 1, 2000000000.000000, 2600000000.000000 }
};

ANTENNA_DESC tx_antennas = {
{ “BAND2”, 2, 30000000.000000, 1900000000.000000}
{ “BAND1”, 1, 2000000000.000000, 2600000000.000000},
};

int
get_tx_antenna(double freq )
{
int ret_antenna = 0;
if (freq < tx_antenna[0].min)
ret_antenna = tx_antenna[0].number;
else if ((freq>= tx_antenna[0].min) && (freq<= tx_antenna[0].max))
ret_antenna = tx_antenna[0].number;
else if ((freq > tx_antenna[0].max) && (freq < tx_antenna[0].min))
{
double half = (tx_anntenna[1].min - tx_antenna[0].max) / 2.0
if ((freq > tx_antenna[0].max) && (freq <= (tx_antenna[0].max + half)))
ret_antenna = tx_antenna[0].number;
else
ret_antenna = tx_antenna[1].number;
}
else if ((freq>= tx_antenna[1].min) && (freq<= tx_antenna[1].max))
ret_antenna = tx_antenna[1].number;
else // over the max value of the second antenna
ret_antenna = tx_antenna[1].number;

return ret_antenna;

}

int
get_rx_antenna(double freq )
{
int ret_antenna = 0;
if (freq < rx_antenna[0].min)
ret_antenna = rx_antenna[0].number;
else if ((freq>= rx_antenna[0].min) && (freq<= rx_antenna[0].max))
ret_antenna = rx_antenna[0].number;
else if ((freq > rx_antenna[0].max) && (freq < rx_antenna[0].min))
{
double half = (rx_anntenna[1].min - rx_antenna[0].max) / 2.0
if ((freq > rx_antenna[0].max) && (freq <= (rx_antenna[0].max + half)))
ret_antenna = rx_antenna[0].number;
else
ret_antenna = rx_antenna[1].number;
}
else if ((freq>= rx_antenna[1].min) && (freq<= rx_antenna[1].max))
ret_antenna = rx_antenna[1].number;
else // over the max value of the second antenna
ret_antenna = rx_antenna[1].number;

return ret_antenna;

}