W dniu 26.02.2018 o 12:43, Piotr Krysik via USRP-users pisze: > W dniu 26.02.2018 o 11:29, Piotr Krysik via USRP-users pisze: >> W dniu 25.02.2018 o 20:08, Marcus D. Leech via USRP-users pisze: >>> OK, so (and apologies if this was in your previous data) what is the >>> average magnitude of the time discrepancy? >> Usually it was about few hundreds us (random). I will try to perform >> more measurements. >> > I measured some values of the delay - they are in the attachment. > Usually the offset is larger than what I said. It's about ~10ms. > > What is interesting is that the values I got in these measurements were > always positive. Hi Marcus,
I've finally found out what the reason for the large offset is !! One of USRPs B210 changes master clock rate AFTER setting the internal time counter. I've found it out when I printed USRPs time at the end of time setting function and seen this: ... -- Asking for clock rate 32.000000 MHz... -- Actually got clock rate 32.000000 MHz. -- Performing timer loopback test... pass -- Performing timer loopback test... pass set_min_output_buffer on block 2 to 10000000 USRP1 time: 1.003918125 USRP2 time: 1.004056625 -- Asking for clock rate 16.000000 MHz... Asking for clock rate 16.000000 MHz... -- Actually got clock rate 16.000000 MHz. -- Performing timer loopback test... -- Actually got clock rate 16.000000 MHz. -- Performing timer loopback test... pass -- Performing timer loopback test... pass -- Performing timer loopback test... pass -- pass ... Whole part below "USRP2 time: 1.004056625" shouldn't be there. The device at that moment is changing its master clock rate from 32MHz to 16MHz. So what I did was setting master clock rate explicitly to 16MHz. *This solved the issue*. Many thanks for your advices that stimulated me to think about solution the problem. I'm attaching the recorder to the post, so others will be able to start synchronizing their B210s from something that works. Best Regards, Piotr Krysik
recorder.grc
Description: application/gnuradio-grc
#!/usr/bin/env python2 # -*- coding: utf-8 -*- from recorder_grc import * import time class recorder(recorder_grc): def __init__(self, fc=1000e6, gain1=30, gain2=30, samp_rate=1e6, start_time="", rec_len=1, gain3=30, gain4=30, serial1="", serial2=""): super(recorder, self).__init__(fc=fc, gain1=gain1, gain2=gain2, samp_rate=samp_rate, rec_len=rec_len, gain3=gain3, serial1=serial1, serial2=serial2) self.set_time_unknown_pps_costam(uhd.time_spec(0.0)) self.uhd_usrp_source_0.set_start_time(uhd.time_spec(3.0)) self.uhd_usrp_source_0_0.set_start_time(uhd.time_spec(3.0)) def set_time_unknown_pps_costam(self, time_spec): time.sleep(4.0) time_last_pps = self.uhd_usrp_source_0.get_time_last_pps() while(self.uhd_usrp_source_0.get_time_last_pps() == time_last_pps): time.sleep(0.01) self.uhd_usrp_source_0.set_time_next_pps(time_spec) self.uhd_usrp_source_0_0.set_time_next_pps(time_spec) time.sleep(2.0) print "USRP1 time: ",self.uhd_usrp_source_0.get_time_now().get_real_secs() print "USRP2 time: ",self.uhd_usrp_source_0_0.get_time_now().get_real_secs() if __name__ == '__main__': main(top_block_cls=recorder)
#!/usr/bin/env python2 # -*- coding: utf-8 -*- ################################################## # GNU Radio Python Flow Graph # Title: Recorder Grc # Generated: Mon Feb 26 14:57:51 2018 ################################################## from gnuradio import blocks from gnuradio import eng_notation from gnuradio import gr from gnuradio import uhd from gnuradio.eng_option import eng_option from gnuradio.filter import firdes from optparse import OptionParser import time class recorder_grc(gr.top_block): def __init__(self, fc=1000e6, gain1=20, gain2=20, gain3=20, gain4=20, rec_len=4, samp_rate=1e6, serial1='3094DB1', serial2='30AD35A'): gr.top_block.__init__(self, "Recorder Grc") ################################################## # Parameters ################################################## self.fc = fc self.gain1 = gain1 self.gain2 = gain2 self.gain3 = gain3 self.gain4 = gain4 self.rec_len = rec_len self.samp_rate = samp_rate self.serial1 = serial1 self.serial2 = serial2 ################################################## # Blocks ################################################## self.uhd_usrp_source_0_0 = uhd.usrp_source( ",".join(("serial="+serial2, '')), uhd.stream_args( cpu_format="fc32", channels=range(2), ), ) self.uhd_usrp_source_0_0.set_clock_rate(16e6, uhd.ALL_MBOARDS) self.uhd_usrp_source_0_0.set_clock_source('external', 0) self.uhd_usrp_source_0_0.set_time_source('external', 0) self.uhd_usrp_source_0_0.set_samp_rate(samp_rate) self.uhd_usrp_source_0_0.set_center_freq(fc, 0) self.uhd_usrp_source_0_0.set_gain(gain3, 0) self.uhd_usrp_source_0_0.set_antenna('TX/RX', 0) self.uhd_usrp_source_0_0.set_bandwidth(1e6, 0) self.uhd_usrp_source_0_0.set_center_freq(fc, 1) self.uhd_usrp_source_0_0.set_gain(gain4, 1) self.uhd_usrp_source_0_0.set_antenna('RX2', 1) self.uhd_usrp_source_0_0.set_bandwidth(1e6, 1) (self.uhd_usrp_source_0_0).set_min_output_buffer(10000000) self.uhd_usrp_source_0 = uhd.usrp_source( ",".join(("serial="+serial1, '')), uhd.stream_args( cpu_format="fc32", channels=range(2), ), ) self.uhd_usrp_source_0.set_clock_rate(16e6, uhd.ALL_MBOARDS) self.uhd_usrp_source_0.set_clock_source('external', 0) self.uhd_usrp_source_0.set_time_source('external', 0) self.uhd_usrp_source_0.set_samp_rate(samp_rate) self.uhd_usrp_source_0.set_center_freq(fc, 0) self.uhd_usrp_source_0.set_gain(gain1, 0) self.uhd_usrp_source_0.set_antenna('RX2', 0) self.uhd_usrp_source_0.set_bandwidth(1e6, 0) self.uhd_usrp_source_0.set_center_freq(fc, 1) self.uhd_usrp_source_0.set_gain(gain2, 1) self.uhd_usrp_source_0.set_antenna('RX2', 1) self.uhd_usrp_source_0.set_bandwidth(1e6, 1) (self.uhd_usrp_source_0).set_min_output_buffer(10000000) self.blocks_tag_debug_0_0 = blocks.tag_debug(gr.sizeof_gr_complex*1, '', ""); self.blocks_tag_debug_0_0.set_display(True) self.blocks_tag_debug_0 = blocks.tag_debug(gr.sizeof_gr_complex*1, '', ""); self.blocks_tag_debug_0.set_display(True) self.blocks_head_0_0_1 = blocks.head(gr.sizeof_gr_complex*1, int(samp_rate*rec_len)) self.blocks_head_0_0_0 = blocks.head(gr.sizeof_gr_complex*1, int(samp_rate*rec_len)) self.blocks_head_0_0 = blocks.head(gr.sizeof_gr_complex*1, int(samp_rate*rec_len)) self.blocks_head_0 = blocks.head(gr.sizeof_gr_complex*1, int(samp_rate*rec_len)) self.blocks_file_sink_0_1 = blocks.file_sink(gr.sizeof_gr_complex*1, 'ch2.sfile', False) self.blocks_file_sink_0_1.set_unbuffered(True) self.blocks_file_sink_0_0_0 = blocks.file_sink(gr.sizeof_gr_complex*1, 'ch4.sfile', False) self.blocks_file_sink_0_0_0.set_unbuffered(True) self.blocks_file_sink_0_0 = blocks.file_sink(gr.sizeof_gr_complex*1, 'ch3.sfile', False) self.blocks_file_sink_0_0.set_unbuffered(True) self.blocks_file_sink_0 = blocks.file_sink(gr.sizeof_gr_complex*1, 'ch1.sfile', False) self.blocks_file_sink_0.set_unbuffered(True) ################################################## # Connections ################################################## self.connect((self.blocks_head_0, 0), (self.blocks_file_sink_0, 0)) self.connect((self.blocks_head_0_0, 0), (self.blocks_file_sink_0_0, 0)) self.connect((self.blocks_head_0_0_0, 0), (self.blocks_file_sink_0_1, 0)) self.connect((self.blocks_head_0_0_1, 0), (self.blocks_file_sink_0_0_0, 0)) self.connect((self.uhd_usrp_source_0, 0), (self.blocks_head_0, 0)) self.connect((self.uhd_usrp_source_0, 1), (self.blocks_head_0_0_0, 0)) self.connect((self.uhd_usrp_source_0, 0), (self.blocks_tag_debug_0, 0)) self.connect((self.uhd_usrp_source_0_0, 0), (self.blocks_head_0_0, 0)) self.connect((self.uhd_usrp_source_0_0, 1), (self.blocks_head_0_0_1, 0)) self.connect((self.uhd_usrp_source_0_0, 0), (self.blocks_tag_debug_0_0, 0)) def get_fc(self): return self.fc def set_fc(self, fc): self.fc = fc self.uhd_usrp_source_0_0.set_center_freq(self.fc, 0) self.uhd_usrp_source_0_0.set_center_freq(self.fc, 1) self.uhd_usrp_source_0.set_center_freq(self.fc, 0) self.uhd_usrp_source_0.set_center_freq(self.fc, 1) def get_gain1(self): return self.gain1 def set_gain1(self, gain1): self.gain1 = gain1 self.uhd_usrp_source_0.set_gain(self.gain1, 0) def get_gain2(self): return self.gain2 def set_gain2(self, gain2): self.gain2 = gain2 self.uhd_usrp_source_0.set_gain(self.gain2, 1) def get_gain3(self): return self.gain3 def set_gain3(self, gain3): self.gain3 = gain3 self.uhd_usrp_source_0_0.set_gain(self.gain3, 0) def get_gain4(self): return self.gain4 def set_gain4(self, gain4): self.gain4 = gain4 self.uhd_usrp_source_0_0.set_gain(self.gain4, 1) def get_rec_len(self): return self.rec_len def set_rec_len(self, rec_len): self.rec_len = rec_len self.blocks_head_0_0_1.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0_0_0.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0_0.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0.set_length(int(self.samp_rate*self.rec_len)) def get_samp_rate(self): return self.samp_rate def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.uhd_usrp_source_0_0.set_samp_rate(self.samp_rate) self.uhd_usrp_source_0.set_samp_rate(self.samp_rate) self.blocks_head_0_0_1.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0_0_0.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0_0.set_length(int(self.samp_rate*self.rec_len)) self.blocks_head_0.set_length(int(self.samp_rate*self.rec_len)) def get_serial1(self): return self.serial1 def set_serial1(self, serial1): self.serial1 = serial1 def get_serial2(self): return self.serial2 def set_serial2(self, serial2): self.serial2 = serial2 def argument_parser(): parser = OptionParser(usage="%prog: [options]", option_class=eng_option) parser.add_option( "-f", "--fc", dest="fc", type="eng_float", default=eng_notation.num_to_str(1000e6), help="Set fc [default=%default]") parser.add_option( "", "--gain1", dest="gain1", type="eng_float", default=eng_notation.num_to_str(20), help="Set gain1 [default=%default]") parser.add_option( "", "--gain2", dest="gain2", type="eng_float", default=eng_notation.num_to_str(20), help="Set gain2 [default=%default]") parser.add_option( "", "--gain3", dest="gain3", type="eng_float", default=eng_notation.num_to_str(20), help="Set gain3 [default=%default]") parser.add_option( "", "--gain4", dest="gain4", type="eng_float", default=eng_notation.num_to_str(20), help="Set gain4 [default=%default]") parser.add_option( "-T", "--rec-len", dest="rec_len", type="eng_float", default=eng_notation.num_to_str(4), help="Set rec_len [default=%default]") parser.add_option( "", "--samp-rate", dest="samp_rate", type="eng_float", default=eng_notation.num_to_str(1e6), help="Set samp_rate [default=%default]") parser.add_option( "", "--serial1", dest="serial1", type="string", default='3094DB1', help="Set 3094DB1 [default=%default]") parser.add_option( "", "--serial2", dest="serial2", type="string", default='30AD35A', help="Set 30AD35A [default=%default]") return parser def main(top_block_cls=recorder_grc, options=None): if options is None: options, _ = argument_parser().parse_args() tb = top_block_cls(fc=options.fc, gain1=options.gain1, gain2=options.gain2, gain3=options.gain3, gain4=options.gain4, rec_len=options.rec_len, samp_rate=options.samp_rate, serial1=options.serial1, serial2=options.serial2) tb.start() tb.wait() if __name__ == '__main__': main()
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com