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. Thanks, Hua On Mon, May 17, 2021 at 4:31 PM Marcus D. Leech <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> > 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> >> 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> >> 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 >>> To unsubscribe send an email to 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 >> >> >
_______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com To unsubscribe send an email to usrp-users-le...@lists.ettus.com