Marcus,
Thanks for the suggestion. I added set_subdev_spec('A:A A:B') for the 2
channel case, but the results are the same.
I also tried this code with a pair of X310s receiving. The results are
somewhat similar:
- Channel 0 (A:0) across 2 devices: no delay
- Channel 1 (B:0) across 2 devices: no delay
- Channels 0 and 1 (A:0 B:0) across 2 devices: channel 0 is in sync between
the two, but channel 1 is not - and channel 1 is not in sync with channel 0
on either device.
- Unlike with the B210s, the X310s both report the same time after
streaming.
I've done this in the past with many X310s (each with 2 channels) with
success, but that was with an older/pre-RFNoC UHD circa 2016. I'm using
pretty much the same code here. Anything else I can try to time sync
multiple devices?
-Michael
On Mon, Feb 24, 2020 at 9:07 PM Marcus D. Leech via USRP-users <
[email protected]> wrote:
> On 02/24/2020 05:10 PM, Michael Wentz via USRP-users wrote:
>
> Hi,
>
> I'm trying to synchronize multiple B210s to receive data at the same time.
> I'm only concerned about sample time alignment across devices, and am aware
> there is a phase offset that will need to be calibrated out separately.
> I've had success with 1 RX channel across 2 B210s, but something seems
> wrong when using 2 RX channels across 2 B210s.
>
> I've pasted a program below to help reproduce this issue. It uses 1 B210
> to TX noise and 2 separate B210s to RX at the same time. There is a 40 dB
> attenuator on the output of the transmitting B210, then a 4 way splitter,
> and equal length cables to both receivers on the other 2 B210s.
> Additionally, the 2 receiving B210s get 10 MHz and PPS from a common
> OctoClock-G.
>
> Here are 10 observations of sample offsets between devices (1 MSPS rate):
> Only channel 0 on both RX: [0,0,0,0,0,0,0,0,0,0]
> Only channel 1 on both RX: [0,0,0,0,0,0,0,0,0,0]
> Channels 0 and 1 simultaneously on both
> RX: [14,1,-126,48,2,-88,17,-204,-96,2]
>
> In the 2 channel case both channels on one device are always aligned, but
> are offset from the channels on the other device. Both of the receiving
> B210s show the same time last PPS when asked before the streams start. The
> times in the RX metadata also match. But after the streams stop, the
> devices respond with different times - neither of which are correct - and
> the difference between them matches what I'm measuring.
>
> I'm using UHD 3.14.1.1 and GNU Radio 3.8 on RHEL 7.7. Any ideas?
>
> Thanks,
> Michael
>
> ----------
>
> #!/usr/bin/env python3
>
> from gnuradio import gr, uhd, analog, blocks
> import time
> import numpy as np
>
> tx_serial = '30D1***'
> rx_serials = ['3153***', '3153***']
> rx_channels = [0, 1]
>
> n_rx = len(rx_serials)
> n_chan = len(rx_channels)
>
> class top_block(gr.top_block):
> def __init__(self):
> gr.top_block.__init__(self)
>
> # transmit path
> noise_src = analog.noise_source_c(analog.GR_GAUSSIAN, 0.1)
> tx_strm_args = uhd.stream_args(cpu_format='fc32', channels=[0])
> tx = uhd.usrp_sink('serial=' + tx_serial, tx_strm_args)
> tx.set_clock_rate(16e6)
> tx.set_samp_rate(1e6)
> tx.set_center_freq(1e9)
> tx.set_gain(40)
> tx.set_antenna('TX/RX')
> self.connect(noise_src, tx)
>
> # receive path
> rx_strm_args = uhd.stream_args(cpu_format='fc32',
> channels=rx_channels)
> self.rx = [None]*n_rx
> head = [None]*n_rx*n_chan
> file_sink = [None]*n_rx*n_chan
> for i in range(n_rx):
> self.rx[i] = uhd.usrp_source('serial=' + rx_serials[i],
> rx_strm_args)
> self.rx[i].set_clock_rate(16e6)
> self.rx[i].set_samp_rate(1e6)
> self.rx[i].set_center_freq(1e9)
> self.rx[i].set_gain(40)
> self.rx[i].set_antenna('RX2')
> self.rx[i].set_time_source('external')
> self.rx[i].set_clock_source('external')
> for j in range(n_chan):
> ch = i*n_chan + j
> head[ch] = blocks.head(2*gr.sizeof_float, 10000)
> f = 'rx_%d%d.dat' % (i, j)
> file_sink[ch] = blocks.file_sink(2*gr.sizeof_float, f)
> file_sink[ch].set_unbuffered(True)
> self.connect((self.rx[i], j), head[ch], file_sink[ch])
>
> # make sure 10 MHz ref is locked
> for i in range(n_rx):
> while not self.rx[i].get_mboard_sensor('ref_locked').to_bool():
> print('RX %d waiting for 10 MHz ref lock...' % i)
> time.sleep(1)
> print('RX %d 10 MHz ref locked' % i)
>
> # time sync the two receivers
> for i in range(n_rx):
> t = self.rx[i].get_time_last_pps().get_real_secs()
> print('RX %d time before align: %r' % (i, t))
> time_last_pps = self.rx[0].get_time_last_pps().get_real_secs()
> while time_last_pps ==
> self.rx[0].get_time_last_pps().get_real_secs():
> time.sleep(0.1)
> for i in range(n_rx):
> self.rx[i].set_time_next_pps(uhd.time_spec_t(0))
> time_last_pps = self.rx[0].get_time_last_pps().get_real_secs()
> while time_last_pps ==
> self.rx[0].get_time_last_pps().get_real_secs():
> time.sleep(0.1)
> for i in range(n_rx):
> t = self.rx[i].get_time_last_pps().get_real_secs()
> print('RX %d time after align: %r' % (i, t))
>
> # collect in the future
> rx_time = uhd.time_spec_t(2)
> for i in range(n_rx):
> self.rx[i].set_start_time(rx_time)
> self.rx[i].set_recv_timeout(3)
>
> # run flowgraph
> tb = top_block()
> tb.start()
> time.sleep(5)
> tb.stop()
>
> # print time
> t = tb.rx[0].get_time_last_pps().get_real_secs()
> while t == tb.rx[0].get_time_last_pps().get_real_secs():
> time.sleep(0.1)
> for i in range(n_rx):
> t = tb.rx[i].get_time_last_pps().get_real_secs()
> print('RX %d time after run: %r' % (i, t))
>
> # cross-correlate receivers and print delay
> y = [None]*n_rx*n_chan
> for i in range(n_rx):
> for j in range(n_chan):
> ch = i*n_chan + j
> y[ch] = np.fromfile('rx_%d%d.dat' % (i, j), dtype=np.complex64)
> r = np.correlate(y[0], y[ch], mode='full')
> max_lag = np.max([len(y[0]), len(y[ch])]) - 1
> lags = np.arange(-max_lag, max_lag+1)
> d = lags[np.argmax(np.abs(r))]
> print('RX %d, channel %d: %d samples' % (i, j, d))
>
>
> _______________________________________________
> USRP-users mailing
> [email protected]http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
>
> IN the two channel case, you should probably set the subdev spec to:
>
> A:A A:B
>
> I didn't set a set_rx_subdev_spec() in the code.
>
>
> _______________________________________________
> USRP-users mailing list
> [email protected]
> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
>
_______________________________________________
USRP-users mailing list
[email protected]
http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com