On 08/06/2023 21:41, Michael Toussaint wrote:
Hi Rob,

Yes, 0.57 degrees is definitely within my measurement error. But, shouldn't the N321 synchronize the phase of the LO's too?
If you're sharing LOs, there's no "synchronizing the LOs".  A single LO is shared through a switching matrix to each of the   relevant mixers.  There'll be some residual phase-error, since effective path-length will never be precisely matched--even   with careful board layout, internal temperature differentials and batch differences in electronic components in the switching   matrix, and even the mixers involved, will yield (usually small) mutual phase errors.

Presumably the length of your LO-sharing cables are all the same, of the same type, and from the same manufacturer
  (and, preferrably, from the same cable batch).




Is there documentation available of how to repeat the results in the "Measured Performance" section of https://kb.ettus.com/USRP_N320/N321_LO_Distribution (e.g. code examples and or test setup to measure the phase drift)? It shows less than 0.1 degree of phase error, I'd like to just repeat that test to confirm everything is working correctly, and see what might be causing the deltas.
Note that phase-drift measurements measure the *change* in relative phase between channels over time.  Not, I think, the   absolute phase-offset between channels.  In a shared-LO setup (ignoring any bugs or mis-configurations of the DUCs, etc), the   absolute phase-offset between channels is repeatable and (largely) static.  Dominated by physical processes like temperature   drift and (worse) differential temperature drift in analog components like cables, circuit-board traces, component temperatures,
  etc.



Thanks,

Michael


On Wed, Jun 7, 2023 at 12:22 PM Rob Kossler <rkoss...@nd.edu> wrote:

    Hi Michael,
    I don't have any ideas for reducing a time delay offset. But, I
    still wonder if the problem could actually be just a phase offset.

    With a relative delay of 2.5ns and a bandwidth of 4 MHz, the
    amount of phase variation you would see is 0.57 degrees.  That is
    not easy to see.  On the other hand, if your bandwidth increased
    to 200 MHz, you would see phase variation of 28.6 degrees (if the
    delay offset is 2.5 ns).
    Rob


    On Tue, Jun 6, 2023 at 9:38 PM Michael Toussaint
    <mtoussa...@chaosinc.com> wrote:

        Hi Rob,

        The signal is actually sweeping over 4MHz, but is just super
        zoomed into a small piece to show the time delta so it looks
        CW. The time difference appears to be the same (within my
        ability to measure) across the band so I am assuming it is a
        time delay offset.

        Any suggestions on how to reduce this time delay offset?

        Thanks,

        Michael Toussaint


        On Mon, Jun 5, 2023 at 8:51 PM Rob Kossler <rkoss...@nd.edu>
        wrote:

            Hi Michael,
            Either a delay offset OR a phase offset will show itself
            as a relative phase.  In order to distinguish between a
            delay offset and a phase offset, your signal must have
            appreciable bandwidth.  It appears that your signal is
            CW.  It is entirely possible that your delay offset is
            zero.  Does this make sense?
            Rob

            On Mon, Jun 5, 2023 at 5:32 PM Michael Toussaint
            <mtoussa...@chaosinc.com> wrote:

                Could you share how you're setting up LO sharing in
                your code, as well as how you're setting the system
                clock on the N321?

                The functions "configure_channels" and
                "set_lo_hw_exports" are used to set up the LO sharing.

                The functions "sync_sources" and "sync_all_devices"
                are used to set up the system clock on the N321.

                How do you measure the relative delay?

                We are measuring the offset of the LO's by just
                measuring the phase difference of ithe RF coming out
                of the Ettus with an Oscilloscope (picture attached as
                Scope_Trace_SingleStream_LO.png
                
<https://mail.google.com/mail/u/0?ui=2&ik=34abf4583b&attid=0.1&permmsgid=msg-a:r-1207093291428225864&view=att&disp=safe&realattid=f_lijcykt50>).
                Yellow is Channel 1, Green is Channel 2; using a
                single streamer we still appear to have a 2.64ns delta
                or ~135 degree phase shift.

                Thanks Marcus and Rob for your assistance.

                Michael Toussaint

                def sync_sources(usrp):
                logging.info <http://logging.info/>('Setting Sync
                Sources')

                usrp.set_sync_source(clock_source = 'gpsdo',
                 time_source = 'gpsdo')

                def sync_all_devices(hw_info):
                logging.info <http://logging.info/>('Syncing All Devices')

                    mb_with_gps_locked = -1

                    while 1:
                        time.sleep(1.0)

                        all_ref_locked = True

                        for board in
                range(hw_info.usrp.get_num_mboards()):
                            all_ref_locked = all_ref_locked and \
                hw_info.usrp.get_mboard_sensor('ref_locked',
                             board).to_bool()

                            if (mb_with_gps_locked == -1) and \
                hw_info.usrp.get_mboard_sensor('gps_locked',
                             board).to_bool():
                                mb_with_gps_locked = board

                        if all_ref_locked:
                logging.info <http://logging.info/>('All Devices are
                REF locked')
                            break

                logging.info <http://logging.info/>('GPS Locked on MB
                #%d', mb_with_gps_locked)

                    time.sleep(1.0)
                hw_info.usrp.set_time_next_pps(
                        uhd.types.TimeSpec(
                hw_info.usrp.get_mboard_sensor('gps_time',
                     mb_with_gps_locked).to_int() +
                     1.0)
                    )
                    time.sleep(1.0)


                def configure_channels(usrp, rf_type, hw_info):
                    rf_channel_index = None
                    set_rf_rate = None
                    set_rf_freq = None
                    set_rf_gain = None
                    set_rf_lo_source = None
                    get_rf_lo_source = None
                    get_rf_lo_freq = None
                    get_rf_lo_freq_range = None

                    if (rf_type == 'rx'):
                        if (len(hw_info.rx_channel_index) > 0):
                            rf_channel_index = hw_info.rx_channel_index
                            set_rf_rate = usrp.set_rx_rate
                            set_rf_freq = usrp.set_rx_freq
                            set_rf_gain = usrp.set_rx_gain
                            set_rf_lo_source = usrp.set_rx_lo_source
                            get_rf_lo_source = usrp.get_rx_lo_source
                            get_rf_lo_freq = usrp.get_rx_lo_freq
                            get_rf_lo_freq_range =
                usrp.get_rx_lo_freq_range
                        else:
                            return
                    elif (rf_type == 'tx'):
                i       if (len(hw_info.tx_channel_index) > 0):
                            rf_channel_index = hw_info.tx_channel_index
                            set_rf_rate = usrp.set_tx_rate
                            set_rf_freq = usrp.set_tx_freq
                            set_rf_gain = usrp.set_tx_gain
                            set_rf_lo_source = usrp.set_tx_lo_source
                            get_rf_lo_source = usrp.get_tx_lo_source
                            get_rf_lo_freq = usrp.get_tx_lo_freq
                            get_rf_lo_freq_range =
                usrp.get_tx_lo_freq_range
                i       else:
                            return

                logging.info <http://logging.info/>('Configuring %s
                Channels', rf_type.upper())

                    for rf_ch_name, rf_ch_index in
                rf_channel_index.items():
                logging.info <http://logging.info/>('Configuring %s
                channel %s (channel #%d)',
                 rf_type.upper(), rf_ch_name, rf_ch_index)

                        ch_def = hw_info.channel_def[rf_ch_name]

                        # LO Channel Setup
                        current_lo_name = 'unknown'
                        current_lo_src = 'unknown'

                        if ch_def.lo_inputs is not None:
                logging.info <http://logging.info/>('  Setting %s LO
                for Channel %s (#%d)',
                 rf_type.upper(), rf_ch_name, rf_ch_index)

                set_rf_lo_source(ch_def.lo_inputs.source,
                ch_def.lo_inputs.name <http://ch_def.lo_inputs.name/>,
                 rf_ch_index)
                            current_lo_name = ch_def.lo_inputs.name
                <http://ch_def.lo_inputs.name/>

                logging.info <http://logging.info/>('    (#%d)
                Requested %s LO name %s, src %s',
                 rf_ch_index,
                 rf_type.upper(),
                ch_def.lo_inputs.name <http://ch_def.lo_inputs.name/>,
                 ch_def.lo_inputs.source)
                        else:
                logging.info <http://logging.info/>('  No %s LO inputs
                for Channel %s (#%d)',
                 rf_type.upper(), rf_ch_name, rf_ch_index)

                            current_lo_name = 'lo1'

                        current_lo_src = get_rf_lo_source(current_lo_name,
                        rf_ch_index)

                logging.info <http://logging.info/>('    (#%d) Current
                %s LO name %s, src %s',
                                     rf_ch_index,
                 rf_type.upper(),
                 current_lo_name,
                 current_lo_src)

                        rf_lo_freq = get_rf_lo_freq(current_lo_name,
                  rf_ch_index)

                logging.info <http://logging.info/>('    (#%d) [%s]
                Current %s LO freq %d',
                 rf_ch_index,
                 current_lo_name,
                 rf_type.upper(),
                 rf_lo_freq)

                        rf_lo_freq_range = get_rf_lo_freq_range(
                            current_lo_name, rf_ch_index)

                        temp = '    (#%d) [%s] Current %s LO freq
                range' + \
                            ' [%d, %d] step %d'

                logging.info <http://logging.info/>(temp,
                                     rf_ch_index,
                 current_lo_name,
                 rf_type.upper(),
                 rf_lo_freq_range.start(),
                 rf_lo_freq_range.stop(),
                 rf_lo_freq_range.step())

                logging.info <http://logging.info/>('  Setting
                Sampling Rate %s', hw_info.fs)
                        set_rf_rate(hw_info.fs, rf_ch_index)

                logging.info <http://logging.info/>('  Setting Center
                Freq %s', hw_info.fc)
                        tr =
                set_rf_freq(uhd.libpyuhd.types.tune_request(hw_info.fc),
                 rf_ch_index)

                logging.info <http://logging.info/>('    (#%d) %s Tune
                Result:',
                                     rf_ch_index, rf_type.upper())
                        log_tune_result(tr)

                logging.info <http://logging.info/>('  Setting %s
                Gain: %2.3f db',
                 rf_type.upper(),
                                     ch_def.gain)
                        set_rf_gain(ch_def.gain, rf_ch_index)

                def set_lo_hw_exports(usrp, node_name, dirx,
                lo_enabled, output_array):
                    """Set LO HW Exports"""
                    if (lo_enabled is None) or (output_array is None):
                        return

                logging.info <http://logging.info/>('Setting %s LO
                Export Enabled for %s',
                                 dirx.upper(), node_name)

                    if dirx.lower() == 'rx':
                usrp.set_rx_lo_export_enabled(lo_enabled, 'lo1', 0)
                        enable_val = usrp.get_rx_lo_export_enabled('lo1')
                    elif dirx.lower() == 'tx':
                usrp.set_tx_lo_export_enabled(lo_enabled, 'lo1', 0)
                        enable_val = usrp.get_tx_lo_export_enabled('lo1')
                    else:
                        logging.warning('Invalid direction %s', dirx)
                        return

                logging.info <http://logging.info/>('  %s LO Export
                Enabled = %s, requested %s',
                                 dirx.upper(), enable_val, lo_enabled)

                    temp_path = 'blocks/0/Radio#0/dboard/' + \
                f'{dirx.lower()}_frontends/' + \
                '0/los/lo1/lo_distribution/LO_OUT_{}/export'

                logging.info <http://logging.info/>('Setting %s LO HW
                Outputs for %s',
                                 dirx.upper(), node_name)

                    for out_num in range(len(output_array)):
                        hw_lo_export_path = temp_path.format(out_num)

                        if usrp.get_tree().exists(hw_lo_export_path):
                usrp.get_tree().access_bool(hw_lo_export_path).set(
                output_array[out_num])

                logging.info <http://logging.info/>('  %s LO HW Export
                Out[%d] = %s, %s %s',
                 dirx.upper(), out_num,
                 usrp.get_tree().access_bool(
                hw_lo_export_path).get(),
                'requested',
                output_array[out_num])
                        else:
                            logging.warning('  %s LO HW Export Out[%d]
                does not exist',
                dirx.upper(), out_num)


                On Thu, May 25, 2023 at 6:45 AM Rob Kossler
                <rkoss...@nd.edu> wrote:

                    On Thu, May 25, 2023 at 3:54 AM Michael Toussaint
                    <mtoussa...@chaosinc.com> wrote:
                    >
                    > Used a single streamer and saw the delay
                    slightly improve to between 2.5 - 3 ns.
                    >
                    > Any other suggestions to improve the delay to
                    match the results from the knowledge base,
                    https://kb.ettus.com/USRP_N320/N321_LO_Distribution?

                    How do you measure the relative delay?






_______________________________________________
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