Example #1
0
/***********************************************************************
 * Setup function
 **********************************************************************/
static uhd::usrp::multi_usrp::sptr setup_usrp_for_cal(std::string &args, std::string &subdev, std::string &serial)
{
    std::cout << std::endl;
    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

    // Configure subdev
    if (!subdev.empty())
    {
        usrp->set_tx_subdev_spec(subdev);
        usrp->set_rx_subdev_spec(subdev);
    }
    std::cout << "Running calibration for " << usrp->get_tx_subdev_name(0);
    serial = get_serial(usrp, "tx");
    std::cout << "Daughterboard serial: " << serial;

    //set the antennas to cal
    if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL"))
        throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
    usrp->set_rx_antenna("CAL");
    usrp->set_tx_antenna("CAL");

    //fail if daughterboard has no serial
    check_for_empty_serial(usrp);

    //set optimum defaults
    set_optimum_defaults(usrp);

    return usrp;
}
/***********************************************************************
 * Main
 **********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
    std::string args;
    double tx_wave_freq, tx_wave_ampl, rx_offset;
    double freq_start, freq_stop, freq_step;
    size_t nsamps;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "help message")
        ("verbose", "enable some verbose")
        ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
        ("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz")
        ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
        ("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz")
        ("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)")
        ("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)")
        ("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz")
        ("nsamps", po::value<size_t>(&nsamps)->default_value(default_num_samps), "Samples per data capture")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    //print the help message
    if (vm.count("help")){
        std::cout << boost::format("USRP Generate TX DC Offset Calibration Table %s") % desc << std::endl;
        std::cout <<
            "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"
            << std::endl;
        return ~0;
    }

    //create a usrp device
    std::cout << std::endl;
    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

    //set the antennas to cal
    if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
        throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
    }
    usrp->set_rx_antenna("CAL");
    usrp->set_tx_antenna("CAL");

    //fail if daughterboard has no serial
    check_for_empty_serial(usrp, "TX", "tx", args);

    //set optimum defaults
    set_optimum_defaults(usrp);

    //create a receive streamer
    uhd::stream_args_t stream_args("fc32"); //complex floats
    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);

    //create a transmitter thread
    boost::thread_group threads;
    threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_freq, tx_wave_ampl));

    //re-usable buffer for samples
    std::vector<samp_type> buff;

    //store the results here
    std::vector<result_t> results;

    if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6;
    if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6;

    for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){
        const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset);

        //frequency constants for this tune event
        const double actual_rx_rate = usrp->get_rx_rate();
        const double actual_tx_freq = usrp->get_tx_freq();
        const double actual_rx_freq = usrp->get_rx_freq();
        const double bb_dc_freq = actual_tx_freq - actual_rx_freq;

        //capture initial uncorrected value
        usrp->set_tx_dc_offset(std::complex<double>(0, 0));
        capture_samples(usrp, rx_stream, buff, nsamps);
        const double initial_dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate);

        //bounds and results from searching
        double dc_i_start = -.01, dc_i_stop = .01, dc_i_step;
        double dc_q_start = -.01, dc_q_stop = .01, dc_q_step;
        double lowest_offset = 0, best_dc_i = 0, best_dc_q = 0;

        for (size_t i = 0; i < num_search_iters; i++){

            dc_i_step = (dc_i_stop - dc_i_start)/(num_search_steps-1);
            dc_q_step = (dc_q_stop - dc_q_start)/(num_search_steps-1);

            for (double dc_i = dc_i_start; dc_i <= dc_i_stop + dc_i_step/2; dc_i += dc_i_step){
            for (double dc_q = dc_q_start; dc_q <= dc_q_stop + dc_q_step/2; dc_q += dc_q_step){

                const std::complex<double> correction(dc_i, dc_q);
                usrp->set_tx_dc_offset(correction);

                //receive some samples
                capture_samples(usrp, rx_stream, buff, nsamps);

                const double dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate);

                if (dc_dbrms < lowest_offset){
                    lowest_offset = dc_dbrms;
                    best_dc_i = dc_i;
                    best_dc_q = dc_q;
                }

            }}

            //std::cout << "best_dc_i " << best_dc_i << std::endl;
            //std::cout << "best_dc_q " << best_dc_q << std::endl;
            //std::cout << "lowest_offset " << lowest_offset << std::endl;

            dc_i_start = best_dc_i - dc_i_step;
            dc_i_stop = best_dc_i + dc_i_step;
            dc_q_start = best_dc_q - dc_q_step;
            dc_q_stop = best_dc_q + dc_q_step;
        }

        if (lowest_offset < initial_dc_dbrms){ //most likely valid, keep result
            result_t result;
            result.freq = tx_lo;
            result.real_corr = best_dc_i;
            result.imag_corr = best_dc_q;
            result.best = lowest_offset;
            result.delta = initial_dc_dbrms - lowest_offset;
            results.push_back(result);
            if (vm.count("verbose")){
                std::cout << boost::format("TX DC: %f MHz: lowest offset %f dB, corrected %f dB") % (tx_lo/1e6) % result.best % result.delta << std::endl;
            }
            else std::cout << "." << std::flush;
        }

    }
    std::cout << std::endl;

    //stop the transmitter
    threads.interrupt_all();
    threads.join_all();

    store_results(usrp, results, "TX", "tx", "dc");

    return 0;
}