Skip to content

DC offset and IQ Imbalance Correction

Ryan Thompson edited this page Oct 13, 2023 · 18 revisions

This page describes how to use the bladeRF's built-in DC offset and IQ imbalance corrections, as well as the automatic calibration & correction functionality provided by libbladeRF and the bladeRF-cli program.

Table of Contents

Overview

Direct conversion (homodyne or zero-IF) receivers have become very popular recently especially in the realm of software defined radio. There are many benefits to direct conversion receivers, but there are also some serious drawbacks, the largest being DC offset and IQ imbalances.

DC offset manifests itself as a large spike in the center of the spectrum. This happens in direct conversion receivers due to a few different factors. One is at the ADC where being off by a single LSB will yield a DC offset. Another is at the output of the low-pass filters where any DC bias will propagate through. The last is at the mixer where the local oscillator (LO) being on the center of the desired frequency will leak through to the receiver.

IQ imbalances occur due to the slightest mismatches in sections of the receiver chain when dealing with the I and Q signal paths. The LO is generated and then delayed by 90 degrees. When mixed with the original signal, the original LO produces the I signal and the 90-degree delayed LO produces the Q signal. In the analog domain, it is much harder to guarantee the delay is exactly 90 degrees. Similarly, the gain component is a slight mismatch in overall gain for each of the signal paths.

To make matters worse, these impairments need to be corrected over both frequency and temperature.

For further information, check out the following:

The LMS6002D transceiver provides DC offset cancellation, and the bladeRF HDL implements IQ imbalance corrections. Correction values for these can be manually specified via libbladeRF's bladerf_set_correction() function.

Automatic corrections

Currently, a table-based automatic DC calibration/correction is in the mainline codebase.

IQ imbalance auto calibration/correction is not currently implemented. However, you can manually adjust IQ balance parameters via bladerf_set_correction().

DC auto-calibration for a single frequency and gain

If you plan to be operating at a single frequency and gain, you can perform the following steps via bladeRF-cli. Note that you would need to do this each time you power up the device. See the next subsection if this is not sufficient.

  1. Run bladeRF-cli -i
  2. Configure the device for the desired frequency and gain settings.
    1. You may instead wish to do this from outside the CLI, using your favorite program for viewing the spectrum.
  3. Run cal lms
    1. This runs the LMS6002D's DC offset calibration routines. You only need to do this once after powering up the device. See the next section for a less involved approach.
  4. To automatically calibrate and set appropriate corrections the RX module, run cal dc rx
    1. Ideally, you should see the "error" values near zero, and certainly less than 10.
      1. Values any higher may indicate that it may not be possible to bring the DC offset close to zero for the current frequency and gain settings. If this happens, it is recommended that you confirm this to be the case via the manual approaches described later in this page. If you are able to manually tune the DC offset where the auto-calibration fails, please report it to developers with the settings you are using.
  5. To calibrate the TX module, run cal dc tx
    1. Again, you should see fairly low error values and the same comments apply if you find this not to be the case.
Example:
bladeRF> set frequency 455.55M

  Set RX frequency:  455550000Hz
  Set TX frequency:  455550000Hz

bladeRF> print rxvga2

  RXVGA2 Gain:   3dB

bladeRF> set rxvga2 8
bladeRF> cal lms
Calibrating LMS LPF tuning module...
    LPF tuning module: 23

Calibrating LMS TX LPF modules...
    TX LPF I filter: 35
    TX LPF Q filter: 33

Calibrating LMS RX LPF modules...
    RX LPF I filter: 25
    RX LPF Q filter: 25

Calibrating LMS RXVGA2 modules...
    RX VGA2 DC reference module: 27
    RX VGA2 stage 1, I channel: 31
    RX VGA2 stage 1, Q channel: 35
    RX VGA2 stage 2, I channel: 23
    RX VGA2 stage 2, Q channel: 29

bladeRF> cal dc rx
RX DC I Setting = -4, error ~= 0
RX DC Q Setting = 156, error ~= 0

Generating a DC offset table

bladeRF-cli may be used to generate a table of DC correction values over a range of frequency values. When a device is opened, libbladeRF can then automatically load this table from a known location on the host machine.

It is recommended that you allow the device to "warm up" to its normal operating temperature before generating a calibration table.

Currently, the DC offset table functionality is limited to variations in frequency; it does not yet account for the effects of various gain settings on the DC offset (but this is a planned task). For the time being, you can take a few different approaches:

  • Generate and keep separate DC calibration tables for the gain configurations you plan to operate at.
    • This would require that you move/rename files each time you want to use a different table.
  • Generate the DC calibration table at the max gain you intend to operate at.
    • This will not yield as nearly optimal results as having a separate correction table at each gain setting. However, you should see some degree of improvements for the lower gain settings.
The general procedure for generating a table is:
  1. Run bladeRF-cli -i
  2. Perform the LMS calibration routines via: cal lms
    1. See the above section for known issues with these routines
  3. Run cal table dc rx and to generate an RX DC offset correction table, and wait for this command to complete. It will take some time.
    1. You can speed up table generation by using larger frequency step sizes or a smaller frequency range. See help cal for more info.
  4. Upon completion of the above command, a calibration table file will be generated in the current working directory, named: <serial #>_dc_rx.tbl
  5. Move the aforementioned file to one of the following locations:
    1. Linux, OSX:
      1. ~/.config/Nuand/bladeRF
      2. ~/.Nuand/bladeRF
      3. ~/etc/Nuand/bladeRF
      4. ~/usr/share/Nuand/bladeRF
    2. Windows:
      1. %APPDATA%\Nuand\bladeRF
The next time you open the device, the table you generated will be loaded. The tables are located via their filename, so to disable the use of the table, you can simply remove or rename it. For example, you can append a .backup extension to the table filename.

Each time you tune to a different frequency, libbladeRF will look up and apply the closest correction value. Keep this in mind if you manually adjust the DC corrections at a particular frequency; the library will reset them underneath you if you change the device's frequency.

This table contains the LMS6002D parameters generated by cal lms, so you do not need to run cal lms while the table is in use. Because the LMS calibration values are tightly coupled with the generated correction values, attempting to generate or use a different LMS calibration would yield suboptimal results.

Example:

bladeRF> cal lms
Calibrating LMS LPF tuning module...
    LPF tuning module: 23

Calibrating LMS TX LPF modules...
    TX LPF I filter: 35
    TX LPF Q filter: 33

Calibrating LMS RX LPF modules...
    RX LPF I filter: 25
    RX LPF Q filter: 25

Calibrating LMS RXVGA2 modules...
    RX VGA2 DC reference module: 27
    RX VGA2 stage 1, I channel: 33
    RX VGA2 stage 1, Q channel: 35
    RX VGA2 stage 2, I channel: 23
    RX VGA2 stage 2, Q channel: 29

bladeRF> cal table dc rx
  Calibrating @ 3800000000 Hz... I=358  (avg. val: -1  ), Q=37   (avg. val: 0   )
Done.
bladeRF> q
$ mkdir -p ~/.config/Nuand/bladeRF
$ mv *_dc_rx.tbl ~/.config/Nuand/bladeRF/

Manually adjusting corrections

It is also possible to manually dial in the correction parameters required for a certain frequency and gain. Even if you are using the automatic corrections, you may find that you can dial in the correction parameters slightly better manually.

Correcting the TX module

Below is am image showing a spectrum containing a tone before (left) and after (right) manually adjusting the DC offset and IQ imbalance correction parameters.

Using a spectrum analyzer and osmocom_siggen

  1. Ensure the bladeRF's FPGA is loaded
  2. Run osmocom_siggen for the desired frequency:
osmocom_siggen -s 4M -f 450M --sine
  1. Specify a frequency offset for the sinusoid
With an uncalibrated device, you'll generally see the following a spectrum plot:
  1. A spike at DC
  2. An image of the tone at -F Hz

DC offset correction

  1. Move the DC Offset Correction Real slider until the amplitude DC spike reaches a minimum
  2. Move the DC Offset Correction Imag slider to further reduce the DC spike
  3. Repeat until the DC spike is sufficiently canceled
  4. Record these settings for reference as an initial starting point in the future.

IQ imbalance correction

  1. Move the IQ Imbalance Correction Mag slider until the amplitude of the image reaches a minimum
  2. Move the IQ Imbalance Phase slider to further reduce the amplitude of the image
  3. Repeat until the image spike is sufficiently canceled
  4. Record these settings for reference as an initial starting point in the future.
Note that you many need to re-tune the DC offset or IQ imbalance slightly after fine tuning other.

Correcting the RX module

Using GNU Radio and the bladeRF's RF loopback functionality

The RX-side can be tuned in a manner similar to what's described above for the TX procedure.

The basic procedure is to:

  • Enable RF loopback mode (via rf_lna1 for under 1.5GHz, or rf_lna2 for 1.5GHz or greater)
  • RX at some frequency f
  • Transmit a carrier at some frequency f + offset
  • View the received signal on an FFT plot
    • Adjust the DC offset parameters to reduce the spike at DC
    • Adjust the IQ imbalance parameters to reduce the image of the carrier from the TX side
An example GNU Radio script is provided here.

Using osmocom_fft and a signal generator

If you have access to a signal generator (or another SDR that's pretty well calibrated for TX), you can follow a procedure very similar to that for calibrating the TX module via osmocom_siggen and a spectrum analyzer.

  1. Run osmocom_fft --dc-offset-mode=0 --iq-balance-mode=0.
  2. Tune the bladeRF to some frequency f1
  3. Using the signal generator to generate a tone at some f2 = f1 + small_offset
  4. Follow the same general procedure used in the above "Using a spectrum analyzer and osmocom_siggen" section.