TX DC calibration not working

For example setup, I use:

  1. set TX frequency to 2400.0 MHz
  2. set RX frequency to 2399.9 MHz
  3. set sample rate to 1 MHz
  4. setup gains, antennas, etc (BAND2, LNAH)
  5. enable on-board (not on-chip!) channel loopback
  6. run FFT
  7. run different signals. Single tone is built-in into LimeSuite, zero signal is 2048 bytes long file filled with zero bytes.

Observe level at +100 KHz on the receiver.

External high quality spectrum analyzer shows basically the same picture of this spike-to-noise relation.

Are you running calibration from your own code?
From LimeSuite code I see it’s not using external loopback when “PC” method is selected in GUI.

what are RxTSP digital RSSI values at these conditions? Calibrations are not using FFT, they rely on RSSI values, so its measured value is more suspectable to be affected by nearby signals/noise as the measured Tx DC signal level drops close to noise floor.

RSSI are fine.
For example, with SXT=2400.100, SXR=2400.000 (to remove RX DC influence) I’ve got those results:

Automatic calibration:
DCCMP_TXB = -2
DCCMP_TXA = -492
RSSI = 0x00101
peak = -54 dBFS (using LimeSDR FFT viewer)

After manual adjustments of gain (analog gains, not digital this time).
DCCMP_TXB = -56
DCCMP_TXA = -408
RSSI = 0x00049
peak = -72 (using LimeSDR FFT viewer)

RSSI dropped almost 3 times, and signal about 20 dB lower.

Every clue gives hint about something wrong with calibration itself.

PC" method is using external calibration:

Look at function:
int LMS7002M::CalibrateTx(float_type bandwidth_Hz, bool useExtLoopback)

( https://github.com/myriadrf/LimeSuite/blob/master/src/lms7002m/LMS7002M_RxTxCalibrations.cpp )

Argument “useExtLoopback” is 0 for MCU and 1 for PC.
On-board loopback is automatically switched ON on LimeSDR.

Correct about that function, but currently GUI uses the API function LMS_Calibrate() which always passes false to the useExtLoopback parameter.

Isn’t this one used?

Yes, but looking further inside it calls:


which calls the original calibration function, and the flag is interpreted basicaly just as whether to use MCU or not, external loopback parameter is always false.

Anyway, that external loopback calibration was experimental and used with the older chip version and measurements were done using FFT on PC, I’m not sure if it is still usable with the latest chip version.

I should get the board after couple of days, will check out whats going on in there

Can we print out values that this function is called with, for example in debug mode?
I have board near me ready for tests, I can test the results.

As ricardas said, external loopback not used.

But the problem remains.

I’ve created my own calibration procedure, which almost eliminates DC using any loopback.
I’ve able to get DC down to -110 dBm (as measured by spectrum analyzer), while manual adjustments give another -10 dB decrease (uo tp -120 dBm). For now, LimeSDR can’t even measure such low signal to go down from -110 to -120 automatically (some filtering required, I’ll do it later). So, in future, I think, I’ll be able to suppress DC to almost undetectable levels.
Haven’t tested and implemented gain and phase calibrations yet.

The point is, stock calibration doesn’t calibrate properly, even if it’s technically possible. Even using internal loopback.

Another point is that, stock calibration always use internal loopback, while technically nothing prevents it from switching to external on-board.

Good to hear that you managed to craft your own calibration procedure which actually works :wink: Hope you’ll share it when you’ll finish it, coz frankly, I gotta feeling that present automatic calibration is a mess. For some reason noone from Lime is looking into it, though (it may be SoapyLMS7 issue - recently it has been discovered that it does not make use of some calibration functions, as noted here).

@DreamNik,

Did you look at RX calibration routine results in similar manner? Don’t you have impression that the situation with RX calibration is close to TX one? I try to use LimeSDR RX to measure just empty carrier level from external generator, and I can’t succeed because of unstability of measured level which as I suspect might derive from IQ imbalance after calibration. DC level isn’t eliminated after RX calibration too, it’s why I’m interested if you checked RX also.

Can you share your calibration routine code? Having read quite a number of topics on calibration problems here (including ones with broken cal caching system) remaining without the answers, it looks like it’s not on Lime’s priority list. Which to be honest looks very strange to me…

I haven’t checked RX DC calibration.

Yes, basically it should be the same.

Source code currently not available, but in general procedure is:

  1. backup parameters
  2. tune RX from TX by offset sampleRate/4
  3. write zeros to TX (continuously)
  4. enable RX RSSI
  5. calibrate TX DC AI:
  6. measure RSSI with min. gain
  7. measure RSSI with max. gain
  8. if RSSI with min gain is better, shift “max” gain to 3/4 of current spacing between min and max
  9. repeat 6…8 until min=max
  10. jitter gain a little bit with RSSI averaging
  11. repeat 5…10 for other gains

As you can see, this is kind of brute force approach.
It’s better to use golden ratio and enable all GFIR tuned to specific band.

RX DC will be the basically the same, just different gains. To turn TX off or not, I haven’t decided yet, need more testing which one would be better.

Just a side note, dBm should not be used to judge calibration effectiveness, what you should be using is dBC.

Thank you for the algorithm! I’m just not sure I completely understood the whole idea. Sorry, I’m not so deep in SDR internals yet. Can you please elaborate a bit about what is its output (result of steps 5-10) and on all those gains that are mentioned:

  1. By what means do you do step 5 - calling MCU calibration routine?
  2. Are all of gains in steps 6, 7, 8, 9, 10 all tx gains? If yes, than if I get it right, you search for a tx gain level which gives you best DC level. But how can I eliminate DC at the gain level that I need?
  3. What “other gains” do you mean in step 11? May be you meant other frequencies?

By what means do you do step 5 - calling MCU calibration routine?

Step 5 is just title for steps 6…10. Maybe I’ve should used different notation.

Are all of gains in steps 6, 7, 8, 9, 10 all tx gains?

Yes, they are TX DC I, DC Q, Gain I, Gain Q and Phase.

If yes, than if I get it right, you search for a tx gain level which gives you best DC level.

Yes, just plain old binary-like search algorithm.

But how can I eliminate DC at the gain level that I need?

If you mean at different PAD gains, then you need to re-calibrate (or cache) calibration values for each PAD gain settings, as the offset drifts slightly with different PAD and fronteng gain settings.

What “other gains” do you mean in step 11? May be you meant other frequencies?

I meant that procedure 6…10 is repeated, but with respect to DC I, DC Q, Gain I, Gain Q and Phase.

1 Like

I’ve noticed that last version of stock calibration routine does a better job.
Still, about 10 dB worse than what I’m using.
Maybe i’ll try to implement fine calibration routine, which will tune gains and offsets obtained from stock calibration to their best. By the way, mine current implementation runs for about 5 seconds, which is very long, compared to stock calibration. 2-step calibration seems good compromise: coarse calibration (stock), and then optional fine tune calibration.

Stock calibration is essentialy doing the same, except it does true binary search and makes sure that Rx gain is not saturating receiver. Are you running your algorithm with internal loopback or external?

I’m updating the code for external loopback option, and it gives ~10dB better results, varies by frequency, but achieves DC level around -65 dBC

@DreamNik:

Thank you, it’s pretty clear now! Also glad to hear from @ricardas that he’s working on external loopback, hopefully there will be no need to do it myself…

Yes, mine is basically the same as stock. The reason I’ve made one is that previous stock calibration didn’t worked at all. Every calibration gave completely different results. New stock calibration does very good job.
I’ve ran algorithm by using internal, on-board, and external (U.FL-U.FL) loopbacks.
All of them were pretty close.