Discontinuities in Rx signal

WriteParam() works on currently active channel. You can probably solve it by placing WriteParam() after each calibrate (so twice). Or you can manually set active channel in LMS chip using LMS7_MAC parameter:
LMS_WriteParam(device,LMS7_MAC,1);
LMS_WriteParam(device,LMS7_DC_BYP_RXTSP,1);
LMS_WriteParam(device,LMS7_MAC,2);
LMS_WriteParam(device,LMS7_DC_BYP_RXTSP,1);

1 Like

Ignas,

Thank you very much, it’s almost perfect now.

The only thing that remained for me now is small packet loss that occur very stable in the first block of samples (returned by first LMS_RecvStream() called after LMS_StartStream()). As it’s obviously not related to DC corrector, I will start separate topic on it.

Hi all,

I think I’m getting a similar problem (the discontinuities) with my LimeSDR; see figure below.

The frequency of the weird sawtooth is proportional to the sampling rate. The sawtooth doesn’t start up for about 50ms; prior to this point, the waveform looks relatively normal.

Forgive me if this is a stupid question (still pretty new to SDR), but how do I implement the above fix in GNU Radio? I assume I need to set a particular parameter in the osmocom source block, but I don’t know which one?

I’m using GNURadio v3.7.11.1, with the following code:

from gnuradio import eng_notation
from gnuradio import gr
from gnuradio import blocks
from gnuradio import filter
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser
from gnuradio import analog
from gnuradio import digital
import osmosdr
import sip
import sys
import time
import rfid

SINE_TEST = False

class reader_top_block(gr.top_block):

  def __init__(self):
    gr.top_block.__init__(self)


    rt = gr.enable_realtime_scheduling()

    ######## Variables #########
    self.dac_rate = 1e6                 # DAC rate
    self.adc_rate = 100e6/50            # ADC rate (2MS/s complex samples)
    self.decim     = 5                    # Decimation (downsampling factor)
    self.ampl     = 0.6                  # Output signal amplitude (signal power vary for different RFX900 cards)
    self.freq     = 910e6                # Modulation frequency (can be set between 902-920)
    self.rx_gain   = 20                   # RX Gain (gain at receiver)
    self.tx_gain   = 0                    # RFX900 no Tx gain option



    # Each FM0 symbol consists of ADC_RATE/BLF samples (2e6/40e3 = 50 samples)
    # 10 samples per symbol after matched filtering and decimation
    self.num_taps     = [1] * 25 # matched to half symbol period

   ######## File sinks for debugging (1 for each block) #########
    self.file_sink_source         = blocks.file_sink(gr.sizeof_gr_complex*1, "../misc/data/source", False)
    self.file_sink_matched_filter = blocks.file_sink(gr.sizeof_gr_complex*1, "../misc/data/matched_filter", False)
    self.file_sink_gate           = blocks.file_sink(gr.sizeof_gr_complex*1, "../misc/data/gate", False)
    self.file_sink_decoder        = blocks.file_sink(gr.sizeof_gr_complex*1, "../misc/data/decoder", False)
    self.file_sink_reader         = blocks.file_sink(gr.sizeof_float*1,      "../misc/data/reader", False)

    if SINE_TEST :
        #File to dump signal that we want to disconnect
        self.file_sink_dump           = blocks.file_sink(gr.sizeof_gr_complex*1,      "../misc/data/dump", False)



    ######## Blocks #########
    self.matched_filter = filter.fir_filter_ccf(self.decim, self.num_taps)
    self.gate            = rfid.gate(int(self.adc_rate/self.decim))
    self.tag_decoder    = rfid.tag_decoder(int(self.adc_rate/self.decim))
    self.reader          = rfid.reader(int(self.adc_rate/self.decim),int(self.dac_rate))
    self.amp              = blocks.multiply_const_ff(self.ampl)
    self.to_complex      = blocks.float_to_complex(1)

    if SINE_TEST :
        self.sine_source = analog.sig_source_c(self.dac_rate, analog.GR_SIN_WAVE, 440, .5, 0)

    # Osmocom blocks
    self.u_source = osmosdr.source(args="numchan=" + str(1) + " " + 'driver=lime,soapy=0'  )
    self.u_source.set_sample_rate(self.adc_rate)
    self.u_source.set_center_freq(self.freq, 0)
    self.u_source.set_freq_corr(0, 0)
    #self.u_source.set_dc_offset_mode(0, 0)
    self.u_source.set_iq_balance_mode(0, 0)
    self.u_source.set_gain_mode(True, 0)
    self.u_source.set_gain(self.rx_gain, 0)
    self.u_source.set_if_gain(10, 0)
    self.u_source.set_bb_gain(10, 0)
    self.u_source.set_antenna("LNAL", 0)
    self.u_source.set_bandwidth(0, 1000000)

    self.u_sink =  osmosdr.sink(args="numchan=" + str(1) + " " + 'driver=lime,soapy=0' )
    self.u_sink.set_sample_rate(self.dac_rate)
    self.u_sink.set_center_freq(self.freq, 0)
    self.u_sink.set_freq_corr(0, 0)
    self.u_sink.set_gain(self.tx_gain, 0)
    self.u_sink.set_if_gain(15, 0)
    self.u_sink.set_bb_gain(15, 0)
    self.u_sink.set_antenna("BAND1", 0)
    self.u_sink.set_bandwidth(0, 1000000)

    ######## Connections #########
    self.connect(self.u_source, self.matched_filter)
    self.connect(self.matched_filter, self.gate)
    self.connect(self.gate, self.tag_decoder)
    self.connect((self.tag_decoder,0), self.reader)
    self.connect(self.reader, self.amp)
    self.connect(self.amp, self.to_complex)

    if SINE_TEST : 
        self.connect(self.to_complex, self.file_sink_dump)
        self.connect(self.sine_source, self.u_sink)
    else :
        self.connect(self.to_complex, self.u_sink)

    self.connect(self.u_source, self.file_sink_source)
    self.connect(self.gate, self.file_sink_gate)
    self.connect((self.tag_decoder,1), self.file_sink_decoder) # (Do not comment this line)
    self.connect(self.reader, self.file_sink_reader)
    self.connect(self.matched_filter, self.file_sink_matched_filter)

if __name__ == '__main__':

  main_block = reader_top_block()
  main_block.start()

  while(1):
    inp = raw_input("'Q' to quit \n")
    if (inp == "q" or inp == "Q"):
      break

  main_block.reader.print_results()
  main_block.stop()

Thanks a lot!

DasSidG

EDIT: Fixed code formatting

@IgnasJ Sorry to bother you, but I’m still struggling with this; after digging through the LimeSuite source code a bit I tried editing the setDCOffsetMode function in https://github.com/myriadrf/LimeSuite/blob/stable/SoapyLMS7/Settings.cpp; I commented out the ‘if’ statement and just wrote ‘rfic->SetRxDCRemoval(false)’ instead; (I also tried it with true). However, this didn’t seem to have any effect; could it be that the LimeSDR just starts up with the DC corrector applied, and so this function is never being called because nothing is trying to change the DC corrector status? Or am I looking in the wrong place for how to fix this issue?

Thanks,

DasSidG

Rx calibration after completion enables rxtsp dc corrector.

Hi ricardas, thanks for your quick reply!

Please forgive my questions - I’m still pretty new to SDR and LimeSDR. When you say ‘after completion’, what exactly is being ‘completed’ which enables the rxtsp dc corrector? Are you saying that the function that I’ve edited should be being called, as the rx calibration routine calls it? Or is the rx calibration something that happens elsewhere, and so I need to somehow explicitly call this function (or something similar) to turn off the rxtsp dc corrector after the rx calibration has happened? If it is the latter, do you have any suggestions of where I could put it to ensure that it is called after rx calibration?

Thanks,

DasSidG

Enabling Rx DC correctors is part of the calibration procedure, so after calibration is done, all the correctors will be enabled.

You can disable DC corrector anytime after calibration.
try adding rfic->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 1); after

Thanks again for your quick response - I wasn’t able to access my hardware over the weekend so I’ve only just been able to come in and test your suggestion.

Unfortunately, adding the line you suggested above didn’t seem to make any difference. I assume I was meant to add it after the whole ‘if(rfic->CalibrateRx(bw, false) != 0)’ statement (i.e. in between lines 1311 and 1312 above. but not actually inside the if(rfic->CalibrateRx(bw, false) != 0) block). I tried it both ways anyway and neither seemed to change what I was seeing.

I tried adding the equivalent line to the CALIBRATE_TX statement as well (with DC_BYP_RXTSP changed to DC_BYP_TXTSP), in case it was somehow being generated in my transmit rather than my receive (the transmit is effectively coupled back to the receive through an attenuator), and also did this in the _EXT_LOOPBACK versions of the above statements as well for good measure. However, none of this got rid of the large sawtooth oscillation.

Below are a couple more pictures of what I’m getting, in case it helps.

The first picture is a picture of the whole capture. There’s an initial region of higher amplitude for the first ~1100ms, then the sawtooth momentarily reverses direction, and then continues at a lower amplitude after that.

The second picture zooms in on the region where the transition at ~1100 ms happens. The two small regions where it looks like a ‘H’ at 1100 ms and just after are the signal I’m actually looking for - the application is an RFID reader. the taller bars are the reader modulation, and the smaller section in the middle is the backscattered response from a tag. In the regions between any kind of modulation, the LimeSDR should be transmitting a constant amplitude sinusoid at 910 MHz. However, I do not believe it is the RFID blocks that I am using in GNURadio which are causing the issue - the same library has been used by others on USRP devices with success, and when I tried the same hardware with just outputting a sine wave i still got the sawtooth response (my output is effectively coupled back to my input with around 36 dB attenuation).

In case it’s relevant, I’m using LNAL for the RX, and BAND1 for the TX.

Thanks for your help!

DasSidG

@ricardas I no longer believe it is an issue with the DC corrector. I’ve made a new post about it here.

So my issue actually was the DC corrector in the end. The reason the fix didn’t work earlier is that I put it in the wrong place in the code. Turns out that the activateStream function (in Streaming.cpp) also carries out RX and TX calibration, which then turns the DC corrector back on. So to fix this, I added the following code here

for (size_t channel = 0; channel < 1; channel++)
{
    SoapySDR::logf(SOAPY_SDR_INFO, "Disabling DC corrector");
    auto rfic = getRFIC(channel);
    rfic->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 1);
}

great advice…! It solve my problem!!
and probably calibration also be needed, I guess…
After Calibration, using your code, it worked in my cpp program. thank you.

Is below commant correct?

LMS_WriteParam(device,LMS7_MAC,1); //Does it mean change ch 0 setting?
LMS_WriteParam(device,LMS7_DC_BYP_RXTSP,1); // set DC_BYP off
LMS_WriteParam(device,LMS7_MAC,2); // change to ch 1 setting??
LMS_WriteParam(device,LMS7_DC_BYP_RXTSP,1); //set DC BYP off

Hi changyul,

Not sure whether you’re replying to myself or Ignas here. I believe that MAC changes whether we are writing to the SXT (transmit) registers or SXR (receive) registers, so not whether it is channel 0 or channel 1. This is discussed a bit more in this post.

The code you have shown here is identical (aside from the comments) to what Ignas wrote earlier in the thread, so I suspect it should be fine. Setting MAC to 1 and then disabling the DC corrector will disable the DC corrector in the receive chain. Setting MAC to 2 and then disabling the DC corrector will do it for the transmit chain. So the code you have there should disable the DC corrector in both the transmit and receive, but I suspect for one of the channels.

Take the above with a grain of salt as I by no means know what I am talking about!

EDIT: I was slightly incorrect in what I said above, see Ignas’ post below:

It is correct if you want to disable automatic digital DC corrector on both RX channels.

You can also try increasing DC corrector window size without disabling it:
LMS_WriteParam(device,LMS7_MAC,1); //select channel 0 (A)
LMS_WriteParam(device,LMS7_DCCORR_AVG_RXTSP,6); // set DC corrector window size 2^18
LMS_WriteParam(device,LMS7_MAC,2); //select channel 1 (B)
LMS_WriteParam(device,LMS7_DCCORR_AVG_RXTSP,6); //set DC corrector windows size 2^18

DCCORR_AVG[2:0] (default 0): Number of samples to average for Automatic DC corrector. Number of samples to average is 2^(DCCORR_AVG + 12).

Usually MAC is used to change between A/B channel, it only changes between Tx and Rx in SX(R/T) registers.

Ah ok, thanks for the correction! I’ve edited my post to reflect this.

So I am having a similar problem when receiving a signal whose amplitude is below the noise floor.

The signal is a chirp that begins at sample 20603 and lasts for 10880 samples. Strangely here we see a massive increase in amplitude of the samples very shortly after the signal arrives. Im still just streaming noise but now at a larger amplitude. What in the LimeSDR could be causing this to happen?

I have tried increasing the DC CORR averaging window to 2^(12+7) which has had some improvement (before it used to be choppy) but I am still left with the above output.

Thanks.