LimeSDR-XTRX Calibration with LimeSuiteNG

I’m trying to best make use of the Calibrate() method exposed in /src/include/limesuiteng/sdrdevice.h so that my transmitter program can retune, recalibrate, and proceed. I’m getting the following error whenever I call it:

Low calibration test signal level (RSSI: 0x00002), expected to be more than (RSSI: 0x00B21). Calibration results might be impacted. Try re-calibrating or adjusting the TX gains.

From what I’ve read, I saw that the device is set up to use an internal RF loopback to perform the calibration, so something must be wrong with how I’ve configured the device for the receiver side to not see any power at all in the loopback.

    m_device = DeviceRegistry::makeDevice(m_handles.at(0));
    if (!m_device)
        throw std::runtime_error("[ERR] Failed to connect to Lime device");

    m_device->SetMessageLogCallback(LimeLogCallback);
    m_device->Init();

    SDRConfig config{};
    const int c = 0;
    config.channel[c].rx.enabled         = false;
    config.channel[c].rx.centerFrequency = m_sdr_params.rx_frequency;
    config.channel[c].rx.sampleRate      = m_sdr_params.rx_samplerate;
    config.channel[c].rx.oversample      = 1;
    config.channel[c].rx.lpf             = 0;
    config.channel[c].rx.path            = 2;
    config.channel[c].rx.calibrate       = CalibrationFlag::NONE;

    config.channel[c].tx.enabled         = true;
    config.channel[c].tx.centerFrequency = m_sdr_params.tx_frequency; // 75 MHz
    config.channel[c].tx.sampleRate      = m_sdr_params.tx_samplerate; // 100 MSPS
    config.channel[c].tx.oversample      = 1;
    config.channel[c].tx.path            = 2;
    config.channel[c].tx.calibrate       = CalibrationFlag::DCIQ;

    m_device->Configure(config, m_chip_index);

    m_stream_cfg = StreamConfig{};
    m_stream_cfg.channels[TRXDir::Rx] = { 0 };
    m_stream_cfg.channels[TRXDir::Tx] = { 0 };
    m_stream_cfg.format     = DataFormat::I16;
    m_stream_cfg.linkFormat = DataFormat::I12;

    m_stream = m_device->StreamCreate(m_stream_cfg, m_chip_index);
    m_stream_running = false;

    m_device->SetGain(m_chip_index, TRXDir::Tx, m_channel,
                      eGainTypes::PAD, m_sdr_params.tx_gain); // 30.0

    // Gets the current DC corrector status from device RF chip TSP.
    // (false = bypass the corrector, true = use the corrector)
    m_device->SetDCOffsetMode(m_chip_index, TRXDir::Tx, m_channel, true);
    m_device->Calibrate(m_chip_index, TRXDir::Tx, m_channel, m_sdr_params.tx_samplerate);

Following this initialization block I can send samples to the device to transmit, which works well, though both the LO leakage/DC tone is still present, as is an IQ imbalance image, so I’m unsure if the first call here to Calibrate is effective. Attempts to call the Calibrate function fail every time when I run the wrapper function:

void sdr_controller::set_tx_calibration()
{
    std::lock_guard<std::mutex> lk(m_device_lock);
    try {
        std::cout << "[INFO] Performing TX Calibration..." << std::endl;
        m_device->Calibrate(m_chip_index, TRXDir::Tx, m_channel, m_sdr_params.tx_samplerate);
        return;
    } catch (const std::exception& e) {
        std::cout << "[ERR] set_tx_calibration: " << e.what() << std::endl;
        return;
    }
}

Whenever I do run this, I notice that the signal that I was previously transmitting is overwritten by what looks like a few quick tones transmitted by the XTRX, so an attempt is evidently being made, but resulting in failure.

How should I revise the code I have, or the surrounding procedure to have a better chance of success with the new Calibrate method? Incidentally, does the Calibrate method tune all the different DC/IQ parameters? In a separate old thread, I read that the calibration parameters include an analog-based DC correction, as well as a digital-based DC correction, written to different registers on the LMS chip. As for the IQ balance parameters, what exactly is being set when you use SetIQBalance()?

Thank you!