On 13/06/2023 13:50, Michael Toussaint wrote:
Hi Marcus,

Yes, the cables are identical, we also experimented with Phase stable test cables but did not see any improvement. We understand there will be some residual phase errors, but the RF coming out with a 2.64ns delta or ~135 degree phase shift @ 144MHz seems like more than that. Is that level of offset to be expected, if so is there a procedure to calibrate that out to align the RF?
For RX, you'd send a tone into all ports, and measure the phase offset and insert appropriate phase-rotations to compensate.

But, from what I understand, that shouldn't be necessary with the N321.  The LO comes out and is then distributed to the
  mixers via the LO distribution, which should be phase-matched.

Does the apparent phase offset change with different versions of UHD?   That is, if you step forward/backward a rev or two,   does that change things?    (I'm thinking here of timing differences in the DUC setups that would be software/firmware-linked,
  rather than hardware-linked).



Understand that the phase drift measurements are the change over time. Do you know if Measured Performance results, from https://kb.ettus.com/USRP_N320/N321_LO_Distribution, where generated on Rx channels (e.g. by injecting a tone to a N321 and a N320 and measuring the phase difference of the IQ over time) or on Tx channels (e.g. N321 and N320 transmitting a tone and using some type of test equipment to measure the phase offset of the RF over time) or is there some other way? I'd just like to repeat the process to see if I can repeat the results or see if there is something I am doing wrong.
I don't know how those tests were done, nor who did them within Ettus/NI R&D.


Thanks,

Michael Toussaint


On Thu, Jun 8, 2023 at 6:53 PM Marcus D. Leech <patchvonbr...@gmail.com> wrote:

    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 = Trueand they called it
                    puppy love

                            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')
                                breakand they called it puppy love

                    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