On 05/17/2021 09:11 PM, Zeng, Huacheng wrote:
Hi Marcus,

Thanks for your reply. I actually have read this note, and did not find a solution to my problem. In my project, I'm not seeking phase synchronization, but trying to achieve frequency synchronization (for ADC and carrier frequency). It seems that the two transmit data streams are misaligned in the time. That is, one data stream is about 20us (40 samples) ahead of the other data stream.

Based on my understanding, the two broads of X310 should be automatically synchronous for RF carrier frequency and ADC sampling frequency, since they are driven by the same LO. There might be phase offset between the two channels, but that is not my focus here.
Actually, the LOs of the two SBX are independently derived from the system reference clock, which itself can be derived from an external clock. Because each SBX board has two PLL synthesizers, they cannot be guaranteed to be in the same phase after tuning, unless that tuning happens at the same time, with a resynch pulse (which is what happens with timed tuning commands).

But that, I agree, has nothing to do with your observed problem.

Unless you actually need timed bursts, there's no reason to use the timed burst functions, and you should look at how the tx_samples_from_file and tx_timed_samples examples do things. Given your reported 40-sample offset, my suspicion is that your buffer management isn't quite correct and that you have an offset in the way your signals are placed into the buffers to be sent. Given your two-channel, single-streamer setup for TX, I cannot see the hardware inserting this delay.



Thanks,
Hua



On Mon, May 17, 2021 at 4:31 PM Marcus D. Leech <patchvonbr...@gmail.com <mailto:patchvonbr...@gmail.com>> wrote:

    On 05/17/2021 04:27 PM, Zeng, Huacheng wrote:
    Hi Marcus,

    Thank you for the reply. I am using SBX (40MHz) daughterboards
    for X310. For my software setting, I'm not sure what is the best
    way to present the details. So I copied my code below. Hopeful it
    is not messy for you to review.

    Thanks,
    Hua
    You should probably read these notes on synchronization:

    https://kb.ettus.com/Synchronization_and_MIMO_Capability_with_USRP_Devices

    Specifically, you'll need to use timed commands to tune your two
    card, so that the phase-resynch feature of the ADF4351 can
      be used to produce phase synchronization of the two LOs involved
    here.




    ============================================================

    int main() {
        sdr_para sp;
        sp.is_usrp_enabled = true;
        sp.is_debg_enabled = false;

        sp.ip_addrs =
    "addr=192.168.10.2,type=x300,master_clock_rate=200e6";
        sp.chan_num = 2;
        sp.chan_str = "0,1";
        sp.sync_opt = "internal"; //"pps", "mimo"
        sp.cen_freq = 915e6;
        sp.sam_rate = 2e6;
        sp.tx_ant_name = "TX/RX";
        sp.rx_ant_name = "RX2";
        sp.analg_bw = sp.sam_rate;
        sp.tx_gain = 15;
        sp.rx_gain = 0;

        sdr = new sdr_dev(sp);

        // transmit
        sdr -> usrp_transmit(buf, num_samps);

        // receiver
        sdr -> usrp_receive(buf, num_samps);

    }

    void sdr_dev::configure_usrp(sdr_para sp) {

        is_usrp_enabled = sp.is_usrp_enabled;
        is_debg_enabled = sp.is_debg_enabled;

        ip_addrs = sp.ip_addrs; //
        chan_str = sp.chan_str; // specify "0", "1", "0,1", etc
        chan_num = sp.chan_num;
        sync_opt = sp.sync_opt; //"pps", "mimo", "default"

        cen_freq = sp.cen_freq;
        sam_rate = sp.sam_rate;

        analg_bw = sp.analg_bw;
        tx_gain = sp.tx_gain;
        rx_gain = sp.rx_gain;

        tx_ant_name = sp.tx_ant_name;
        rx_ant_name = sp.rx_ant_name;

        seconds_in_future = 1.0;

        //create a usrp device
        uhd::set_thread_priority_safe();
        usrp = uhd::usrp::multi_usrp::make(ip_addrs);
        //cout << boost::format("Using Device: %s") %
    usrp->get_pp_string() << endl;

        //always select the subdevice first, the channel mapping
    affects the other settings
        // usrp->set_rx_subdev_spec(subdev); //sets across all mboards
        // usrp->set_tx_subdev_spec(subdev); //sets across all mboards

        // clock and time sync_opthronization
        if (sync_opt == "pps") {
            usrp -> set_clock_source("external");
            usrp -> set_time_source("external");
            usrp -> set_time_unknown_pps(uhd::time_spec_t(0.0));
            this_thread::sleep_for(chrono::seconds(1)); //wait for
    pps sync_opt pulse
        } else if (sync_opt == "mimo") {
            cout << "MIMO cable" << endl;
            UHD_ASSERT_THROW(usrp -> get_num_mboards() == 2);
            //make mboard 1 a slave over the MIMO Cable
            usrp -> set_clock_source("mimo", 1);
            usrp -> set_time_source("mimo", 1);
            //set time on the master (mboard 0)
            usrp -> set_time_now(uhd::time_spec_t(0.0), 0);
            //sleep a bit while the slave locks its time to the master
    this_thread::sleep_for(chrono::milliseconds(500));
        } else {
            usrp -> set_time_now(uhd::time_spec_t(1.0));
        }

        //set the center frequency
        uhd::tune_request_t tune_request(cen_freq);
        tune_request.args = uhd::device_addr_t("mode_n=integer");
        for (int ch = 0; ch < chan_num; ch++) {
            usrp -> set_rx_freq(tune_request, ch);
            usrp -> set_tx_freq(tune_request, ch);
            cout << boost::format("Actual RX Freq: %f MHz...") %
    (usrp -> get_rx_freq(ch) / 1e6) << endl;
            cout << boost::format("Actual TX Freq: %f MHz...") %
    (usrp -> get_tx_freq(ch) / 1e6) << endl;

            //set the rx sample rate (sets across all channels)
            usrp -> set_rx_rate(sam_rate, ch);
            usrp -> set_tx_rate(sam_rate, ch);
            cout << boost::format("Actual RX Rate: %f Msps...") %
    (usrp -> get_rx_rate(ch) / 1e6) << endl;
            cout << boost::format("Actual TX Rate: %f Msps...") %
    (usrp -> get_tx_rate(ch) / 1e6) << endl;

            //set antenna ...
            usrp -> set_rx_antenna(rx_ant_name, ch);
            usrp -> set_tx_antenna(tx_ant_name, ch);
            cout << "Rx antenna is " << usrp -> get_rx_antenna(ch) <<
    endl;
            cout << "Tx antenna is " << usrp -> get_tx_antenna(ch) <<
    endl;

            //set the rf gain
            usrp -> set_rx_gain(rx_gain, ch);
            usrp -> set_tx_gain(tx_gain, ch);
            cout << boost::format("Actual RX Gain: %f dB...") % usrp
    -> get_rx_gain(ch) << endl;
            cout << boost::format("Actual TX Gain: %f dB...") % usrp
    -> get_tx_gain(ch) << endl;

            //set the analog frontend filter bandwidth
            usrp -> set_rx_bandwidth(analg_bw, ch);
            usrp -> set_tx_bandwidth(analg_bw, ch);
            cout << boost::format("Actual RX Bandwidth: %f MHz...") %
    (usrp -> get_rx_bandwidth(ch) / 1e6) << endl;
            cout << boost::format("Actual TX Bandwidth: %f MHz...") %
    (usrp -> get_tx_bandwidth(ch) / 1e6) << endl;

            usrp -> set_rx_dc_offset(false, ch);

        }

        //detect which channels to use
        cout << "RX channel num: " << usrp -> get_rx_num_channels()
    << endl;
        cout << "TX channel num: " << usrp -> get_tx_num_channels()
    << endl;
        vector < string > channel_strings;
        boost::split(channel_strings, chan_str,
    boost::is_any_of("\"',"));
        for (size_t ch = 0; ch < channel_strings.size(); ch++) {
            size_t chan = stoi(channel_strings[ch]);
            if (chan >= usrp -> get_rx_num_channels()) {
                throw runtime_error("Invalid channel(s) specified.");
            } else {
    channel_nums.push_back(stoi(channel_strings[ch]));
            }
        }

        //create a receive streamer
        //linearly map channels (index0 = channel0, index1 =
    channel1, ...)
        uhd::stream_args_t stream_args("fc32"); //complex floats
        stream_args.channels = channel_nums;
        rx_stream = usrp -> get_rx_stream(stream_args);
        tx_stream = usrp -> get_tx_stream(stream_args);

        // pkt max size
        tx_max_num_samps = tx_stream -> get_max_num_samps();
        rx_max_num_samps = rx_stream -> get_max_num_samps();
        cout << "tx_max_num_samps = " << tx_max_num_samps << endl;
        cout << "rx_max_num_samps = " << rx_max_num_samps << endl;

        // issue command to receive data from usrp
        uhd::stream_cmd_t
    stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
        stream_cmd.num_samps = 0;
        stream_cmd.stream_now = false;
        stream_cmd.time_spec = usrp -> get_time_now() +
    uhd::time_spec_t(seconds_in_future);
        rx_stream -> issue_stream_cmd(stream_cmd); //tells all
    channels to stream

        //cout<<"time real: " <<stream_cmd.time_spec.get_real_secs()
    << endl;
        //cout<<"time full: " <<stream_cmd.time_spec.get_full_secs()
    << endl;
        //cout<<"time frac: " <<stream_cmd.time_spec.get_frac_secs()
    << endl;
        //the first call to recv() will block this many seconds
    before receiving
        timeout = seconds_in_future + 0.1; //timeout (delay before
    receive + padding)

        cout << "^^^^^^^^^^^^^^^^^^^^^^^^ complete SDR initialization
    ^^^^^^^^^^^^^^^^^^^^^" << endl;
    }

    sdr_dev::~sdr_dev() {}

    void sdr_dev::set_time_for_receiving(double sec_in_future) {

        // issue command to receive data from usrp
        uhd::stream_cmd_t
    stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
        stream_cmd.num_samps = 0;
        stream_cmd.stream_now = false;
        stream_cmd.time_spec = usrp -> get_time_now() +
    uhd::time_spec_t(sec_in_future);
        rx_stream -> issue_stream_cmd(stream_cmd);

    }

    size_t sdr_dev::receive(vector < complex < float > * >
    rx_buff_ptr, size_t requested_num_samps) {

        if (is_usrp_enabled == true)
            return usrp_receive(rx_buff_ptr, requested_num_samps);
        else
            return simu_receive(rx_buff_ptr, requested_num_samps);

    }

    // predefined functions
    size_t sdr_dev::usrp_receive(vector < complex < float > * >
    rx_buff_ptr, size_t requested_num_samps) {
        size_t acc_num_samps = 0;
        size_t total_num_samps = requested_num_samps;

        vector < complex < float > * > rx_buff_ptr_tmp = rx_buff_ptr;

        while (acc_num_samps < total_num_samps) {

            for (int i = 0; i < rx_buff_ptr.size(); i++)
    rx_buff_ptr_tmp[i] = & rx_buff_ptr[i][acc_num_samps];

            size_t num_rx_samps = rx_stream -> recv(rx_buff_ptr_tmp,
    total_num_samps - acc_num_samps, rx_md, timeout);

            //use a small timeout for subsequent packets
            timeout = 0.1;
            if (is_debg_enabled == true) {
                //handle the error code
                if (rx_md.error_code ==
    uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break;
                if (rx_md.error_code !=
    uhd::rx_metadata_t::ERROR_CODE_NONE) {
                    throw runtime_error(str(boost::format("Receiver
    error %s") % rx_md.strerror()));
                }
                cout << boost::format("Received packet: %u samples,
    %u full secs, %f frac secs")\ %
                    num_rx_samps\ %
                    rx_md.time_spec.get_full_secs()\ %
                    rx_md.time_spec.get_frac_secs()\ <<
                    endl;
            }
            acc_num_samps += num_rx_samps;
        }
        if (acc_num_samps < total_num_samps) {
            cerr << "Receive timeout before all samples received..."
    << endl;
        }

        return acc_num_samps;
    }

    size_t sdr_dev::transmit(vector < complex < float > * >
    tx_buff_ptr, size_t requested_num_samps) {

        if (is_usrp_enabled == true)
            return usrp_transmit(tx_buff_ptr, requested_num_samps);
        else
            return simu_transmit(tx_buff_ptr, requested_num_samps);

    }

    size_t sdr_dev::usrp_transmit(vector < complex < float > * >
    tx_buff_ptr, size_t requested_num_samps) {
        //setup metadata for the first packet
        tx_md.start_of_burst = true; // not clear what is the
    difference between "false" and "true"
        tx_md.end_of_burst = false;
        tx_md.has_time_spec = true; //??? should be true or false
        tx_md.time_spec = usrp -> get_time_now() +
    uhd::time_spec_t(0.001); //0.1

        //the first call to send() will block this many seconds
    before sending:
        timeout = seconds_in_future + 0.1; //timeout (delay before
    transmit + padding)

        vector < complex < float > * > tx_buff_ptr_tmp = tx_buff_ptr;

        size_t acc_num_samps = 0; //number of accumulated samples
        size_t total_num_samps = requested_num_samps;
        while (acc_num_samps < total_num_samps) {
            size_t samps_to_send = total_num_samps - acc_num_samps;
            if (samps_to_send > tx_max_num_samps) {
                samps_to_send = tx_max_num_samps;
            } else {
                //tx_md.end_of_burst = true;
            }

            for (int i = 0; i < tx_buff_ptr.size(); i++)
    tx_buff_ptr_tmp[i] = & tx_buff_ptr[i][acc_num_samps];

            //send a single packet
            size_t num_tx_samps = tx_stream -> send(tx_buff_ptr_tmp,
    samps_to_send, tx_md, timeout);
            //do not use time spec for subsequent packets
            tx_md.has_time_spec = false;
            tx_md.start_of_burst = false;

            if (num_tx_samps < samps_to_send) {
                cerr << "Send timeout..." << endl;
            }
            if (is_debg_enabled == true) {
                cout << boost::format("Sent packet: %u samples") %
    num_tx_samps << endl;
            }
            acc_num_samps += num_tx_samps;
        }

        //tx_md.end_of_burst = true;
        tx_stream -> send("", 0, tx_md);

        if (is_debg_enabled == true) {
            cout << endl << "Waiting for async_opt burst ACK... " <<
    flush;
            size_t acks = 0;
            //loop through all messages for the ACK packets (may have
    underflow messages in queue)
            while (acks < channel_nums.size() and tx_stream ->
    recv_async_msg(async_md, seconds_in_future)) {
                if (async_md.event_code ==
    uhd::async_metadata_t::EVENT_CODE_BURST_ACK) acks++;
            }

            if (acks < channel_nums.size()) {
                cout << "fail" << endl;
            } else {
                cout << "ack received" << endl;
            }
        }

        return acc_num_samps;
    }

    On Mon, May 17, 2021 at 3:24 PM Marcus D Leech
    <patchvonbr...@gmail.com <mailto:patchvonbr...@gmail.com>> wrote:

        You haven’t said what type of daughter cards you’re using.

        Nor exactly how you’re setting things up
        In your software.

        Sent from my iPhone

        On May 17, 2021, at 1:56 PM, Zeng, Huacheng
        <huacheng.z...@gmail.com <mailto:huacheng.z...@gmail.com>>
        wrote:

        
        An update - I update UHD to 4.0 version and run the code
        again. With this version I got some warning message (see
        below). Did I set up the X310 usrp improperly?


        [INFO] [UHD] linux; GNU C++ version 7.5.0; Boost_106501;
        UHD_4.0.0.HEAD-0-g90ce6062
        [INFO] [X300] X300 initialization sequence...
        [INFO] [X300] Maximum frame size: 1472 bytes.
        [INFO] [X300] Radio 1x clock: 200 MHz
        [WARNING] [RFNOC::GRAPH] One or more blocks timed out during
        flush!
        Actual RX Freq: 915.000000 MHz...
        Actual TX Freq: 915.000000 MHz...
        Actual RX Rate: 2.000000 Msps...
        Actual TX Rate: 2.000000 Msps...
        Rx antenna is RX2
        Tx antenna is TX/RX
        Actual RX Gain: 0.000000 dB...
        Actual TX Gain: 15.000000 dB...
        Actual RX Bandwidth: 2.000000 MHz...
        Actual TX Bandwidth: 2.000000 MHz...
        Actual RX Freq: 915.000000 MHz...
        Actual TX Freq: 915.000000 MHz...
        Actual RX Rate: 2.000000 Msps...
        Actual TX Rate: 2.000000 Msps...
        Rx antenna is RX2
        Tx antenna is TX/RX
        Actual RX Gain: 0.000000 dB...
        Actual TX Gain: 15.000000 dB...
        Actual RX Bandwidth: 2.000000 MHz...
        Actual TX Bandwidth: 2.000000 MHz...
        RX channel num: 2
        TX channel num: 2
        [WARNING] [0/Radio#0] Attempting to set tick rate to 0.
        Skipping.
        [WARNING] [0/Radio#1] Attempting to set tick rate to 0.
        Skipping.
        [WARNING] [0/Radio#1] Attempting to set tick rate to 0.
        Skipping.
        [WARNING] [0/Radio#0] Attempting to set tick rate to 0.
        Skipping.
        tx_max_num_samps = 364
        rx_max_num_samps = 364

        Thanks,
        Hua

        On Mon, May 17, 2021 at 12:04 PM Huacheng Zeng
        <zenghuach...@gmail.com <mailto:zenghuach...@gmail.com>> wrote:

            Hi all,

            I am using X310 as an MIMO transmitter to send two data
            streams. I observed from the received signal that the
            two data streams are misaligned in the time domain. I
            suspect that it is the X310's timing/frequency
            synchronization problem. Below is the output
            information. Is there any C++ API reference for setting
            up X310 as a MIMO transmitter/receiver? Any suggestions
            would be appreciated.

            Thanks,
            Hua


            [INFO] [UHD] linux; GNU C++ version 5.4.0 20160609;
            Boost_105800; UHD_3.13.1.HEAD-0-gbbce3e45
            --------------------------------------------------
            -- UHD Device 0
            --------------------------------------------------
            Device Address:
                serial: 31804F1
                addr: 192.168.10.2
                fpga: HG
                name:
                product: X310
                type: x300



            [INFO] [UHD] linux; GNU C++ version 5.4.0 20160609;
            Boost_105800; UHD_3.13.1.HEAD-0-gbbce3e45
            [INFO] [X300] X300 initialization sequence...
            [INFO] [X300] Maximum frame size: 1472 bytes.
            [INFO] [X300] Radio 1x clock: 200 MHz
            [INFO] [GPS] No GPSDO found
            [INFO] [0/DmaFIFO_0] Initializing block control (NOC ID:
            0xF1F0D00000000000)
            [INFO] [0/DmaFIFO_0] BIST passed (Throughput: *1292* MB/s)
            [INFO] [0/DmaFIFO_0] BIST passed (Throughput: *1299* MB/s)
            [INFO] [0/Radio_0] Initializing block control (NOC ID:
            0x12AD100000000001)
            [INFO] [0/Radio_1] Initializing block control (NOC ID:
            0x12AD100000000001)
            [INFO] [0/DDC_0] Initializing block control (NOC ID:
            0xDDC0000000000000)
            [INFO] [0/DDC_1] Initializing block control (NOC ID:
            0xDDC0000000000000)
            [INFO] [0/DUC_0] Initializing block control (NOC ID:
            0xD0C0000000000000)
            [INFO] [0/DUC_1] Initializing block control (NOC ID:
            0xD0C0000000000000)
            Actual RX Freq: 915.000000 MHz...
            Actual TX Freq: 915.000000 MHz...
            Actual RX Rate: 2.000000 Msps...
            Actual TX Rate: 2.000000 Msps...
            Rx antenna is RX2
            Tx antenna is TX/RX
            Actual RX Gain: 0.000000 dB...
            Actual TX Gain: 15.000000 dB...
            Actual RX Bandwidth: 2.000000 MHz...
            Actual TX Bandwidth: 2.000000 MHz...
            Actual RX Freq: 915.000000 MHz...
            Actual TX Freq: 915.000000 MHz...
            Actual RX Rate: 2.000000 Msps...
            Actual TX Rate: 2.000000 Msps...
            Rx antenna is RX2
            Tx antenna is TX/RX
            Actual RX Gain: 0.000000 dB...
            Actual TX Gain: 15.000000 dB...
            Actual RX Bandwidth: 2.000000 MHz...
            Actual TX Bandwidth: 2.000000 MHz...
            RX channel num: 2
            TX channel num: 2
            tx_max_num_samps = 364
            rx_max_num_samps = 364





            _______________________________________________
            USRP-users mailing list -- usrp-users@lists.ettus.com
            <mailto:usrp-users@lists.ettus.com>
            To unsubscribe send an email to
            usrp-users-le...@lists.ettus.com
            <mailto:usrp-users-le...@lists.ettus.com>

        _______________________________________________
        USRP-users mailing list -- usrp-users@lists.ettus.com
        <mailto:usrp-users@lists.ettus.com>
        To unsubscribe send an email to
        usrp-users-le...@lists.ettus.com
        <mailto:usrp-users-le...@lists.ettus.com>



_______________________________________________
USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-le...@lists.ettus.com

Reply via email to