Problem with 2500MHz - 2600MHz band

I would like to transmit signal at one port (I found that TXx_2 has better power performance above 2GHz than TXx_1) and receive at 2RX ports (1TX2RX/MISO). I have to cover the frequency range from about 700MHz to more than 3 GHz, so that without external microwave switch I take signal from ‘LNAW’ chain.

In order to test it, I connected TX1_2 via attenuator and divider to RX1_W and RX2_W.

I’ve tested it in GNURadio GUI and I’ve noticed that for few frequencies it is not possible to receive clean signal. Unfortunately in grc after starting flowchart I can see only information about changing frequency, so I’ve also written a simple SoapySDR script based on MeausureDelay.py in order to catch any error/warning.

For few frequencies (e.g. between 2500MHz and 2600MHz) I can’t calibrate Tx and Rx and it results in poor signal and logs:

  • [ERROR] Tx Calibration: MCU error 4 (SXT tune failed)
  • [ERROR] Rx calibration: MCU error 5 (Loopback signal weak: not connected/insufficient gain?)
  • [ERROR] Rx calibration: MCU error 5 (Loopback signal weak: not connected/insufficient gain?)

For example one of the ‘problematic’ frequency is 2580 MHz. 2480 MHz and 2680 MHz is OK.

The working solution is:
If I set default parameters in LimeSuite, set desired frequency (SXR, SXT), perform calibration, I will not have that problem (with the same gain settings). But for different ‘problematic’ frequency I have to repeat that process.
But I have to perform that kind of wideband measurement many times, so it is very uncomfortable.

What is the reason for that?

Is it possible to force default parameters and perform calibration from python, instead of using LimeSuite GUI?

I’ve tested the same cables, attenuator, SoapySDR script with BladeRF micro 2.0 and USRP x310 and I have no problem with that frequency range.

My board passes a quick test.

Would you suggest what is the better way to have 1TX2RX with LimeSDR-USB board?

Correct CW pulse response - frequency 2680MHz:

Response - f=2580MHz (sometimes is only noise):

Code for test with soapy:
#!/usr/bin/env python
"""Jaco: simple transmit on TX0 and receive on RX0 and RX2
"""

import argparse
import os
import time
import math
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert
import SoapySDR
from SoapySDR import * #SOAPY_SDR_ constants
import jaco2 as jaco
from scipy import signal
import os

#region DEVICE
sdr = SoapySDR.Device("driver=lime")
#endregion

#region PARAMETERS
print "--NO CHANN TX:      " + str(sdr.getNumChannels(SOAPY_SDR_TX))
print "--NO CHANN RX:      " + str(sdr.getNumChannels(SOAPY_SDR_RX))
print "--GAINS RX:         " + str(sdr.listGains(SOAPY_SDR_RX,0))
print "--GAINS TX:         " + str(sdr.listGains(SOAPY_SDR_TX,0))
print sdr.listTimeSources()

print "--BW RX RANGE:      " + str(sdr.listBandwidths(SOAPY_SDR_RX,0))
print "--ANTENNAS RX:      " + str(sdr.listAntennas(SOAPY_SDR_RX,0))
print "--ANTENNAS TX:      " + str(sdr.listAntennas(SOAPY_SDR_TX,0))
print "--FREQS RX:         " + str(sdr.listFrequencies(SOAPY_SDR_RX,0))
print "--FREQS TX:         " + str(sdr.listFrequencies(SOAPY_SDR_TX,0))
print "--GAINS RX RNG:     " + str(sdr.getGainRange(SOAPY_SDR_RX,0))
print "--GAINS TX RNG:     " + str(sdr.getGainRange(SOAPY_SDR_TX,0))
#endregion



rx_chan_0 = 0
rx_chan_1 = 1
tx_chan_0 = 0

rate = 10e6
rx_ant = "LNAW"
tx_ant = "BAND2"

freq = 2520.0e6
rx_bw = 10000000
tx_bw = 10000000
num_tx_samps = 4096
num_rx_samps = 3*4096

sdr.setAntenna(SOAPY_SDR_RX, rx_chan_0, rx_ant)
sdr.setAntenna(SOAPY_SDR_RX, rx_chan_1, rx_ant)
sdr.setAntenna(SOAPY_SDR_TX, tx_chan_0, tx_ant)

sdr.setFrequency(SOAPY_SDR_RX, rx_chan_0, freq)
sdr.setFrequency(SOAPY_SDR_RX, rx_chan_1, freq)
sdr.setFrequency(SOAPY_SDR_TX, tx_chan_0, freq)

sdr.setSampleRate(SOAPY_SDR_RX, rx_chan_0, rate)
sdr.setSampleRate(SOAPY_SDR_TX, tx_chan_0, rate)
sdr.setSampleRate(SOAPY_SDR_RX, rx_chan_1, rate)



# sdr.setBandwidth(SOAPY_SDR_RX, rx_chan_0, rx_bw)
# sdr.setBandwidth(SOAPY_SDR_RX, rx_chan_1, rx_bw)
# sdr.setBandwidth(SOAPY_SDR_TX, tx_chan_0, tx_bw)

#region GAIN RANGE

#--GAIN LNA RX:      0, 30
#--GAIN PGA RX:      -12, 19
#--GAIN TIA RX:      0, 12
#--GAIN PAD TX:      0, 52
#--GAIN IAMP TX:     -12, 12

#endregion

# sdr.setGain(SOAPY_SDR_RX, rx_chan_0, 'LNA', 20)
# sdr.setGain(SOAPY_SDR_RX, rx_chan_0, 'PGA', 3)
# sdr.setGain(SOAPY_SDR_RX, rx_chan_0, 'TIA', 12)

# sdr.setGain(SOAPY_SDR_RX, rx_chan_1, 'LNA', 20)
# sdr.setGain(SOAPY_SDR_RX, rx_chan_1, 'PGA', 3)
# sdr.setGain(SOAPY_SDR_RX, rx_chan_1, 'TIA', 12)

# sdr.setGain(SOAPY_SDR_TX, tx_chan_0, 'PAD', 10)
# sdr.setGain(SOAPY_SDR_TX, tx_chan_0, 'IAMP',0)

sdr.setGain(SOAPY_SDR_TX, tx_chan_0, 40)
sdr.setGain(SOAPY_SDR_RX, rx_chan_0, 30)
sdr.setGain(SOAPY_SDR_RX, rx_chan_1, 30)




rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [rx_chan_0,rx_chan_1])
tx_stream = sdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [tx_chan_0])

time.sleep(1)


gol_len = 64
fc = 156250*3
sig = jaco.generate_golay_preamble(rate/2, gol_len, 1, 200, fc)
sdr.activateStream(tx_stream)

tx_time_0 = int(sdr.getHardwareTime() + 0.05e9) #100ms
print tx_time_0
tx_flags = SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST
status_0 = sdr.writeStream(tx_stream, [sig], len(sig), tx_flags, tx_time_0)

if status_0.ret != len(sig):
raise Exception('transmit failed %s' % str(status_0))


rx_buff_0s_0 = np.array([0], np.complex64)
rx_buff_0s_1 = np.array([0], np.complex64)
rx_flags = SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST

receive_time = int(tx_time_0 - (num_rx_samps/rate) * 1e9 / 4.0)
sdr.activateStream(rx_stream, rx_flags, receive_time, num_rx_samps)


rx_time_0 = None


while True:
rx_buff_0 = np.array([0] * 1024, np.complex64)
rx_buff_1 = np.array([0] * 1024, np.complex64)
timeout_us = int(5e5)
status_0 = sdr.readStream(rx_stream, [rx_buff_0,rx_buff_1], len(rx_buff_0), timeoutUs=timeout_us)


if status_0.ret > 0 and rx_buff_0s_0.size:
    rx_time_0 = status_0.timeNs
    if (status_0.flags & SOAPY_SDR_HAS_TIME) == 0:
        raise Exception('receive fail - no timestamp on first readStream %s' % (str(status_0)))


if status_0.ret > 0:
    rx_buff_0s_0 = np.concatenate((rx_buff_0s_0, rx_buff_0[:status_0.ret]))
    rx_buff_0s_1 = np.concatenate((rx_buff_0s_1, rx_buff_1[:status_0.ret]))
else:
    break


sdr.deactivateStream(tx_stream)
sdr.closeStream(rx_stream)
sdr.closeStream(tx_stream)



sig_r0 = rx_buff_0s_0 - np.mean(rx_buff_0s_0)
sig_r1 = rx_buff_0s_1 - np.mean(rx_buff_0s_1)


fig, axarr = plt.subplots(2, sharex=True)
axarr[0].plot(np.abs(sig_r0))
axarr[0].plot(rx_buff_0s_0.real - np.mean(rx_buff_0s_0.real))
axarr[0].plot(rx_buff_0s_0.imag - np.mean(rx_buff_0s_0.imag))
axarr[1].plot(np.abs(sig_r1))
axarr[1].plot(rx_buff_0s_1.real - np.mean(rx_buff_0s_1.real))
axarr[1].plot(rx_buff_0s_1.imag - np.mean(rx_buff_0s_1.imag))

plt.show()