diff --git a/src/experiment_prototype/experiment_prototype.py b/src/experiment_prototype/experiment_prototype.py index 7c0eef52c..afc2658bd 100644 --- a/src/experiment_prototype/experiment_prototype.py +++ b/src/experiment_prototype/experiment_prototype.py @@ -141,6 +141,10 @@ class ExperimentPrototype: requires tuning time to set, it cannot be modified after instantiation. :type rxctrfreq: float + :param lo_lock_wait: Determines if the usrp driver will wait for the local oscillator + to reach a locked state before continuing when tuning the tx and + rx center frequencies. Otherwise a default time delay is used + :type lo_lock_wait: bool :param comment_string: Description of experiment for data files. This should be used to describe your overall experiment design. Another comment string exists for every slice added, to describe information that is @@ -157,7 +161,7 @@ class ExperimentPrototype: """ def __init__(self, cpid, output_rx_rate=default_output_rx_rate, rx_bandwidth=default_rx_bandwidth, - tx_bandwidth=5.0e6, txctrfreq=12000.0, rxctrfreq=12000.0, comment_string=''): + tx_bandwidth=5.0e6, txctrfreq=12000.0, rxctrfreq=12000.0, lo_lock_wait=False, comment_string=''): if not isinstance(cpid, int): errmsg = 'CPID must be a unique int' raise ExperimentException(errmsg) @@ -249,6 +253,8 @@ def __init__(self, cpid, output_rx_rate=default_output_rx_rate, rx_bandwidth=def clock_divider = math.ceil(rxctrfreq*1e3/clock_multiples) self.__rxctrfreq = (clock_divider * clock_multiples)/1e3 + self.__lo_lock_wait = bool(lo_lock_wait) + # This is experiment-wide transmit metadata necessary to build the pulses. This data # cannot change within the experiment and is used in the scan classes to pass information # to where the samples are built. @@ -569,6 +575,17 @@ def rx_minfreq(self): log.warning(f"Minimum receive frequency set to 1 kHz") return 1000 # Hz + @property + def lo_lock_wait(self): + """ + True or false statement indicating if the usrp driver will wait for the local oscillator + to reach a locked stated, or otherwise use a default time delay. + + :returns: lo_lock_wait + :rtype: bool + """ + return self.__lo_lock_wait + @property def interface(self): """ diff --git a/src/radar_control.py b/src/radar_control.py index 611252a0e..3c4d97e3a 100644 --- a/src/radar_control.py +++ b/src/radar_control.py @@ -35,7 +35,8 @@ TIME_PROFILE = False -def setup_driver(radctrl_to_driver, driver_to_radctrl_iden, txctrfreq, rxctrfreq, txrate, rxrate): +def setup_driver(radctrl_to_driver, driver_to_radctrl_iden, txctrfreq, rxctrfreq, txrate, rxrate, + lo_lock_wait=False): """ First packet sent to driver for setup. @@ -49,6 +50,7 @@ def setup_driver(radctrl_to_driver, driver_to_radctrl_iden, txctrfreq, rxctrfreq """ driverpacket = DriverPacket() + driverpacket.lo_lock_wait = lo_lock_wait driverpacket.txcenterfreq = txctrfreq * 1000 # convert to Hz driverpacket.rxcenterfreq = rxctrfreq * 1000 # convert to Hz driverpacket.txrate = txrate @@ -60,7 +62,8 @@ def setup_driver(radctrl_to_driver, driver_to_radctrl_iden, txctrfreq, rxctrfreq def data_to_driver(radctrl_to_driver, driver_to_radctrl_iden, samples_array, txctrfreq, rxctrfreq, txrate, rxrate, - numberofreceivesamples, seqtime, SOB, EOB, timing, seqnum, align_sequences, repeat=False): + numberofreceivesamples, seqtime, SOB, EOB, timing, seqnum, align_sequences, repeat=False, + lo_lock_wait=False): """ Place data in the driver packet and send it via zeromq to the driver. @@ -88,6 +91,8 @@ def data_to_driver(radctrl_to_driver, driver_to_radctrl_iden, samples_array, txc :param repeat: a boolean indicating whether the pulse is the exact same as the last pulse in the sequence, in which case we will save the time and not send the samples list and other params that will be the same. + :param lo_lock_wait: a boolean indicating if the usrp driver should wait for the local oscillator to reach + a locked state when tuning the center frequency. If not then a default time delay is used in while tuning """ driverpacket = DriverPacket() @@ -98,6 +103,7 @@ def data_to_driver(radctrl_to_driver, driver_to_radctrl_iden, samples_array, txc driverpacket.numberofreceivesamples = numberofreceivesamples driverpacket.seqtime = seqtime driverpacket.align_sequences = align_sequences + driverpacket.lo_lock_wait = lo_lock_wait if repeat: # antennas empty @@ -496,7 +502,7 @@ def main(): # Wait for acknowledgment that USRP object is set up. setup_driver(radar_control_to_driver, options.driver_to_radctrl_identity, experiment.txctrfreq, experiment.rxctrfreq, experiment.txrate, - experiment.rxrate) + experiment.rxrate, lo_lock_wait=experiment.lo_lock_wait) first_aveperiod = True next_scan_start = None @@ -743,7 +749,8 @@ def send_pulses(): pulse_transmit_data['timing'], seqnum_start + num_sequences, sequence.align_sequences, - repeat=pulse_transmit_data['isarepeat']) + repeat=pulse_transmit_data['isarepeat'], + lo_lock_wait=experiment.lo_lock_wait) if TIME_PROFILE: pulses_to_driver_time = datetime.utcnow() - start_time diff --git a/src/usrp_drivers/usrp.cpp b/src/usrp_drivers/usrp.cpp index 19e1dee42..8ec716a01 100644 --- a/src/usrp_drivers/usrp.cpp +++ b/src/usrp_drivers/usrp.cpp @@ -144,7 +144,7 @@ double USRP::get_tx_rate(uint32_t channel) * used and what order they are in. To synchronize tuning of all boxes, timed commands are used so * that everything is done at once. */ -double USRP::set_tx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay) +double USRP::set_tx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay, bool lo_lock_wait) { uhd::tune_request_t tune_request(freq); @@ -154,8 +154,15 @@ double USRP::set_tx_center_freq(double freq, std::vector chs, uhd::time_ } clear_command_time(); - auto duration = std::chrono::duration(tune_delay.get_real_secs()); - std::this_thread::sleep_for(duration); + // Wait for the LO to settle, or wait for a predefined delay time + if ( lo_lock_wait ) { + while ( not usrp_->get_tx_sensor("lo_locked").to_bool() ) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } else { + auto duration = std::chrono::duration(tune_delay.get_real_secs()); + std::this_thread::sleep_for(duration); + } //check for varying USRPs for (auto &channel : chs) { @@ -274,7 +281,7 @@ double USRP::get_rx_rate(uint32_t channel) * used. To synchronize tuning of all boxes, timed commands are used so that everything is done at * once. */ -double USRP::set_rx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay) +double USRP::set_rx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay, bool lo_lock_wait) { uhd::tune_request_t tune_request(freq); @@ -284,8 +291,15 @@ double USRP::set_rx_center_freq(double freq, std::vector chs, uhd::time_ } clear_command_time(); - auto duration = std::chrono::duration(tune_delay.get_real_secs()); - std::this_thread::sleep_for(duration); + // Wait for the LO to settle, or wait for a predefined delay time + if ( lo_lock_wait ){ + while ( not usrp_->get_rx_sensor("lo_locked").to_bool() ) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } else { + auto duration = std::chrono::duration(tune_delay.get_real_secs()); + std::this_thread::sleep_for(duration); + } //check for varying USRPs for (auto &channel : chs) { diff --git a/src/usrp_drivers/usrp.hpp b/src/usrp_drivers/usrp.hpp index c95d8c33e..3d86c7608 100644 --- a/src/usrp_drivers/usrp.hpp +++ b/src/usrp_drivers/usrp.hpp @@ -25,14 +25,14 @@ class USRP{ void set_tx_subdev(std::string tx_subdev); double set_tx_rate(std::vector chs); double get_tx_rate(uint32_t channel=0); - double set_tx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay); + double set_tx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay, bool lo_lock_wait); double get_tx_center_freq(uint32_t channel=0); void set_main_rx_subdev(std::string main_subdev); void set_interferometer_rx_subdev(std::string interferometer_subdev, uint32_t interferometer_antenna_count); double set_rx_rate(std::vector rx_chs); double get_rx_rate(uint32_t channel=0); - double set_rx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay); + double set_rx_center_freq(double freq, std::vector chs, uhd::time_spec_t tune_delay, bool lo_lock_wait); double get_rx_center_freq(uint32_t channel=0); void set_time_source(std::string source, std::string clk_addr); void check_ref_locked(); diff --git a/src/usrp_drivers/usrp_driver.cpp b/src/usrp_drivers/usrp_driver.cpp index e2d97514a..a222549c1 100644 --- a/src/usrp_drivers/usrp_driver.cpp +++ b/src/usrp_drivers/usrp_driver.cpp @@ -187,6 +187,11 @@ void transmit(zmq::context_t &driver_c, USRP &usrp_d, const DriverOptions &drive DEBUG_MSG(COLOR_BLUE("TRANSMIT") << " burst flags: SOB " << driver_packet.sob() << " EOB " << driver_packet.eob()); + // Draven added these to keep tabs on the frequencies when they might be switched + DEBUG_MSG(COLOR_RED("TRANSMIT") << " TX borealis center freq " << tx_center_freq << + " vs driver center freq " << driver_packet.txcenterfreq()); + DEBUG_MSG(COLOR_RED("TRANSMIT") << " RX borealis center freq " << rx_center_freq << + " vs driver center freq " << driver_packet.rxcenterfreq()); TIMEIT_IF_TRUE_OR_DEBUG(false, COLOR_BLUE("TRANSMIT") << " center freq ", [&]() { @@ -198,7 +203,8 @@ void transmit(zmq::context_t &driver_c, USRP &usrp_d, const DriverOptions &drive driver_packet.txcenterfreq()); tx_center_freq = usrp_d.set_tx_center_freq(driver_packet.txcenterfreq(), tx_channels, - uhd::time_spec_t(TUNING_DELAY)); + uhd::time_spec_t(TUNING_DELAY), + driver_packet.lo_lock_wait()); } } @@ -210,7 +216,8 @@ void transmit(zmq::context_t &driver_c, USRP &usrp_d, const DriverOptions &drive driver_packet.rxcenterfreq()); rx_center_freq = usrp_d.set_rx_center_freq(driver_packet.rxcenterfreq(), receive_channels, - uhd::time_spec_t(TUNING_DELAY)); + uhd::time_spec_t(TUNING_DELAY), + driver_packet.lo_lock_wait()); } } @@ -638,10 +645,27 @@ int32_t UHD_SAFE_MAIN(int32_t argc, char *argv[]) { USRP usrp_d(driver_options, driver_packet.txrate(), driver_packet.rxrate()); auto tune_delay = uhd::time_spec_t(TUNING_DELAY); - usrp_d.set_tx_center_freq(driver_packet.txcenterfreq(), driver_options.get_transmit_channels(), - tune_delay); - usrp_d.set_rx_center_freq(driver_packet.rxcenterfreq(), driver_options.get_receive_channels(), - tune_delay); + + // Added debug messages and timing to track initial N200 tuning during debug + DEBUG_MSG(COLOR_GREEN("STARTUP") << " center freqs: TX = " << driver_packet.txcenterfreq() << + " RX = " << driver_packet.rxcenterfreq()); + if (driver_packet.lo_lock_wait() == true) + { + DEBUG_MSG(COLOR_GREEN("STARTUP") << " Tuning will wait for lo lock "); + } else { + DEBUG_MSG(COLOR_GREEN("STARTUP") << " Tuning Delay is set to " << TUNING_DELAY); + } + + TIMEIT_IF_TRUE_OR_DEBUG(false, COLOR_GREEN("STARTUP") << " Initial tuning to center freq (tx & rx) ", + [&]() { + + usrp_d.set_tx_center_freq(driver_packet.txcenterfreq(), driver_options.get_transmit_channels(), + tune_delay, driver_packet.lo_lock_wait()); + usrp_d.set_rx_center_freq(driver_packet.rxcenterfreq(), driver_options.get_receive_channels(), + tune_delay, driver_packet.lo_lock_wait()); + }() + + ); auto driver_ready_msg = std::string("DRIVER_READY"); diff --git a/src/utils/protobuf/driverpacket.proto b/src/utils/protobuf/driverpacket.proto index 888a4e4c9..4cac3668a 100644 --- a/src/utils/protobuf/driverpacket.proto +++ b/src/utils/protobuf/driverpacket.proto @@ -15,6 +15,7 @@ message DriverPacket { bool SOB = 10; bool EOB = 11; bool align_sequences = 12; + bool lo_lock_wait = 13; message SamplesBuffer { repeated float real = 1;