usrp-users@lists.ettus.com

Discussion and technical support related to USRP, UHD, RFNoC

View all threads

X440 - Phase alignment between two USRPs

EG
Eugene Grayver
Tue, Mar 3, 2026 7:36 PM

I have two X440 w/ X4_200 FPGA image.  I need to get consistent phase between channels on USRP1 and USRP2 across multiple runs.  I must be doing something wrong because I observe consistent phase between channels on any ONE USRP, but not across two.  The phase appears to be random between the two on each run.

Here's my setup:

Common 10 MHz and 1 PPS
*
Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external
*
I modified the 'stock' rx_samples_to_file as follows:
*
Usrp->set_time_next_pps(uhd::time_spec_t(0.0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
*
usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0));
// Set the rate, freq, gain, etc
std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S * 1000));
usrp->clear_command_time();
*
Each streamer is created in a separate thread
*
stream_cmd.stream_now = false;
// Time was reset to zero before thread was created
stream_cmd.time_spec  = uhd::time_spec_t(STREAM_START_S, 0);
rx_stream->issue_stream_cmd(stream_cmd);

What am I missing?  I assume commands apply to both USRPs since I create a multi_usrp.  Do I need to explicitly specify the motherboard for some of the commands?

Eugene Grayver, Ph.D.
Principal Engineer
310-336-1274

I have two X440 w/ X4_200 FPGA image. I need to get consistent phase between channels on USRP1 and USRP2 across multiple runs. I must be doing something wrong because I observe consistent phase between channels on any ONE USRP, but not across two. The phase appears to be random between the two on each run. Here's my setup: * Common 10 MHz and 1 PPS * Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external * I modified the 'stock' rx_samples_to_file as follows: * Usrp->set_time_next_pps(uhd::time_spec_t(0.0)); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); * usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0)); // Set the rate, freq, gain, etc std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S * 1000)); usrp->clear_command_time(); * Each streamer is created in a separate thread * stream_cmd.stream_now = false; // Time was reset to zero before thread was created stream_cmd.time_spec = uhd::time_spec_t(STREAM_START_S, 0); rx_stream->issue_stream_cmd(stream_cmd); What am I missing? I assume commands apply to both USRPs since I create a multi_usrp. Do I need to explicitly specify the motherboard for some of the commands? Eugene Grayver, Ph.D. Principal Engineer 310-336-1274
EG
Eugene Grayver
Tue, Mar 3, 2026 8:50 PM

I misread this statement.  I assumed that no retune happens if the freq/rate are the same across restarts (not reboots).  Disregard the previous email.
[cid:7de6267c-4b73-4777-b7a0-f9fd3b6bb878]


From: Eugene Grayver
Sent: Tuesday, March 3, 2026 11:36 AM
To: usrp-users usrp-users@lists.ettus.com
Subject: X440 - Phase alignment between two USRPs

I have two X440 w/ X4_200 FPGA image.  I need to get consistent phase between channels on USRP1 and USRP2 across multiple runs.  I must be doing something wrong because I observe consistent phase between channels on any ONE USRP, but not across two.  The phase appears to be random between the two on each run.

Here's my setup:

Common 10 MHz and 1 PPS
*
Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external
*
I modified the 'stock' rx_samples_to_file as follows:
*
Usrp->set_time_next_pps(uhd::time_spec_t(0.0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
*
usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0));
// Set the rate, freq, gain, etc
std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S * 1000));
usrp->clear_command_time();
*
Each streamer is created in a separate thread
*
stream_cmd.stream_now = false;
// Time was reset to zero before thread was created
stream_cmd.time_spec  = uhd::time_spec_t(STREAM_START_S, 0);
rx_stream->issue_stream_cmd(stream_cmd);

What am I missing?  I assume commands apply to both USRPs since I create a multi_usrp.  Do I need to explicitly specify the motherboard for some of the commands?

Eugene Grayver, Ph.D.
Principal Engineer
310-336-1274

I misread this statement. I assumed that no retune happens if the freq/rate are the same across restarts (not reboots). Disregard the previous email. [cid:7de6267c-4b73-4777-b7a0-f9fd3b6bb878] ________________________________ From: Eugene Grayver Sent: Tuesday, March 3, 2026 11:36 AM To: usrp-users <usrp-users@lists.ettus.com> Subject: X440 - Phase alignment between two USRPs I have two X440 w/ X4_200 FPGA image. I need to get consistent phase between channels on USRP1 and USRP2 across multiple runs. I must be doing something wrong because I observe consistent phase between channels on any ONE USRP, but not across two. The phase appears to be random between the two on each run. Here's my setup: * Common 10 MHz and 1 PPS * Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external * I modified the 'stock' rx_samples_to_file as follows: * Usrp->set_time_next_pps(uhd::time_spec_t(0.0)); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); * usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0)); // Set the rate, freq, gain, etc std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S * 1000)); usrp->clear_command_time(); * Each streamer is created in a separate thread * stream_cmd.stream_now = false; // Time was reset to zero before thread was created stream_cmd.time_spec = uhd::time_spec_t(STREAM_START_S, 0); rx_stream->issue_stream_cmd(stream_cmd); What am I missing? I assume commands apply to both USRPs since I create a multi_usrp. Do I need to explicitly specify the motherboard for some of the commands? Eugene Grayver, Ph.D. Principal Engineer 310-336-1274
CR
Chris Rogers
Tue, Mar 3, 2026 8:54 PM

The X440 has a clock board (
https://files.ettus.com/manual/page_usrp_x4xx.html#x4xx_too_clocking) which
uses the LMK04832 PLL (
https://www.ti.com/lit/ds/symlink/lmk04832.pdf?ts=1772540151834) to
actually generate the RFSoC sample clock from the 10 MHz input. This PLL
output will have a phase ambiguity WRT the 10 MHz input signal because of
PLL physics, and this is why you see a random relative phase run to run. It
looks like this chip supports a synchronization input to align output clock
edges and the X440 technically has a sync input port on the front, but I
dont know if these inputs are actually connected to each other. It could be
worth looking into what the X440 Sync In does... last I checked, it didn't
actually do anything but that was at least a year ago

On Tue, Mar 3, 2026 at 2:37 PM Eugene Grayver eugene.grayver@aero.org
wrote:

I have two X440 w/ X4_200 FPGA image.  I need to get consistent phase
between channels on USRP1 and USRP2 across multiple runs.  I must be doing
something wrong because I observe consistent phase between channels on any
ONE USRP, but not across two.  The phase appears to be random between the
two on each run.

Here's my setup:

- Common 10 MHz and 1 PPS
-
Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external
- I modified the 'stock' rx_samples_to_file as follows:
- Usrp->set_time_next_pps(uhd::time_spec_t(0.0));
   std::this_thread::sleep_for(std::chrono::milliseconds(1000));
   - usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0));
   // Set the rate, freq, gain, etc
   std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S
   * 1000));
   usrp->clear_command_time();
   - Each streamer is created in a separate thread
   -     stream_cmd.stream_now = false;
       // Time was reset to zero before thread was created
       stream_cmd.time_spec  = uhd::time_spec_t(STREAM_START_S, 0);
       rx_stream->issue_stream_cmd(stream_cmd);

What am I missing?  I assume commands apply to both USRPs since I create a
multi_usrp.  Do I need to explicitly specify the motherboard for some of
the commands?

Eugene Grayver, Ph.D.
Principal Engineer
310-336-1274


USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-leave@lists.ettus.com

The X440 has a clock board ( https://files.ettus.com/manual/page_usrp_x4xx.html#x4xx_too_clocking) which uses the LMK04832 PLL ( https://www.ti.com/lit/ds/symlink/lmk04832.pdf?ts=1772540151834) to actually generate the RFSoC sample clock from the 10 MHz input. This PLL output will have a phase ambiguity WRT the 10 MHz input signal because of PLL physics, and this is why you see a random relative phase run to run. It looks like this chip supports a synchronization input to align output clock edges and the X440 technically has a sync input port on the front, but I dont know if these inputs are actually connected to each other. It could be worth looking into what the X440 Sync In does... last I checked, it didn't actually do anything but that was at least a year ago On Tue, Mar 3, 2026 at 2:37 PM Eugene Grayver <eugene.grayver@aero.org> wrote: > I have two X440 w/ X4_200 FPGA image. I need to get consistent phase > between channels on USRP1 and USRP2 across multiple runs. I must be doing > something wrong because I observe consistent phase between channels on any > ONE USRP, but not across two. The phase appears to be random between the > two on each run. > > Here's my setup: > > - Common 10 MHz and 1 PPS > - > Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external > - I modified the 'stock' rx_samples_to_file as follows: > - Usrp->set_time_next_pps(uhd::time_spec_t(0.0)); > std::this_thread::sleep_for(std::chrono::milliseconds(1000)); > - usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0)); > // Set the rate, freq, gain, etc > std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S > * 1000)); > usrp->clear_command_time(); > - Each streamer is created in a separate thread > - stream_cmd.stream_now = false; > // Time was reset to zero before thread was created > stream_cmd.time_spec = uhd::time_spec_t(STREAM_START_S, 0); > rx_stream->issue_stream_cmd(stream_cmd); > > > What am I missing? I assume commands apply to both USRPs since I create a > multi_usrp. Do I need to explicitly specify the motherboard for some of > the commands? > > > Eugene Grayver, Ph.D. > Principal Engineer > 310-336-1274 > _______________________________________________ > USRP-users mailing list -- usrp-users@lists.ettus.com > To unsubscribe send an email to usrp-users-leave@lists.ettus.com >
MD
Michael Dickens
Wed, Mar 4, 2026 2:10 PM

(1) make sure you're using UHD 4.9. 4.9.0.[01] release is fine; the UHD-4.9
branch has some desirable fixes that will be part of the UHD 4.10 release,
so if you're building from source then go with this branch.

(2) Try first tuning ±1 GHz off of the desired RF Fc and then to the actual
desired RF Fc. Use timed commands for both to be safe; technically I think
the first doesn't have to be.

While the phase alignment (initial phase offset) will still be random, the
phase relationship between any 2 channels should now be repeatable. This
applies to 1,2, .... N X440 USRPs [though if using an OctoClock to
distribute GPSDO signals the channel to channel (C2C) phase coherence and
relationship will be tighter than using multiple OctoClock tiers. There
are, of course, other GPSDO signal distribution systems that have more than
8x replication.]

For the initial offset tune you should see something about "resetting
gearbox"; subsequent (re)tunes may or not show this info.

We will update the language that you note, which applies to UHD 4.8, with
the UHD 4.10 release as, when done correctly, one can attain channel to
channel (C2C) phase coherence and relationship between (re)tunes, UHD
instantiations, and device reboots.

Please try this and let us know how it goes.

Michael L Dickens, PhD
Emerson/NI/Ettus SDR RF Principal Application Engineer
Teams: +1-512-683-5305
Cell: +1-512-585-1391
michael.l.dickens@emerson.com michael.dickens@ni.com
michael.dickens@ettus.com

On Tue, Mar 3, 2026 at 3:55 PM Chris Rogers c1337rogers@gmail.com wrote:

The X440 has a clock board (
https://files.ettus.com/manual/page_usrp_x4xx.html#x4xx_too_clocking)
which uses the LMK04832 PLL (
https://www.ti.com/lit/ds/symlink/lmk04832.pdf?ts=1772540151834) to
actually generate the RFSoC sample clock from the 10 MHz input. This PLL
output will have a phase ambiguity WRT the 10 MHz input signal because of
PLL physics, and this is why you see a random relative phase run to run. It
looks like this chip supports a synchronization input to align output clock
edges and the X440 technically has a sync input port on the front, but I
dont know if these inputs are actually connected to each other. It could be
worth looking into what the X440 Sync In does... last I checked, it didn't
actually do anything but that was at least a year ago

On Tue, Mar 3, 2026 at 2:37 PM Eugene Grayver eugene.grayver@aero.org
wrote:

I have two X440 w/ X4_200 FPGA image.  I need to get consistent phase
between channels on USRP1 and USRP2 across multiple runs.  I must be doing
something wrong because I observe consistent phase between channels on any
ONE USRP, but not across two.  The phase appears to be random between the
two on each run.

Here's my setup:

- Common 10 MHz and 1 PPS
-
Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external
- I modified the 'stock' rx_samples_to_file as follows:
- Usrp->set_time_next_pps(uhd::time_spec_t(0.0));
   std::this_thread::sleep_for(std::chrono::milliseconds(1000));
   - usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0));
   // Set the rate, freq, gain, etc
   std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S
   * 1000));
   usrp->clear_command_time();
   - Each streamer is created in a separate thread
   -     stream_cmd.stream_now = false;
       // Time was reset to zero before thread was created
       stream_cmd.time_spec  = uhd::time_spec_t(STREAM_START_S, 0);
       rx_stream->issue_stream_cmd(stream_cmd);

What am I missing?  I assume commands apply to both USRPs since I create
a multi_usrp.  Do I need to explicitly specify the motherboard for some of
the commands?

Eugene Grayver, Ph.D.
Principal Engineer
310-336-1274


USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-leave@lists.ettus.com


USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-leave@lists.ettus.com

(1) make sure you're using UHD 4.9. 4.9.0.[01] release is fine; the UHD-4.9 branch has some desirable fixes that will be part of the UHD 4.10 release, so if you're building from source then go with this branch. (2) Try first tuning ±1 GHz off of the desired RF Fc and then to the actual desired RF Fc. Use timed commands for both to be safe; technically I think the first doesn't have to be. While the phase alignment (initial phase offset) will still be random, the phase relationship between any 2 channels should now be repeatable. This applies to 1,2, .... N X440 USRPs [though if using an OctoClock to distribute GPSDO signals the channel to channel (C2C) phase coherence and relationship will be tighter than using multiple OctoClock tiers. There are, of course, other GPSDO signal distribution systems that have more than 8x replication.] For the initial offset tune you should see something about "resetting gearbox"; subsequent (re)tunes may or not show this info. We will update the language that you note, which applies to UHD 4.8, with the UHD 4.10 release as, when done correctly, one can attain channel to channel (C2C) phase coherence and relationship between (re)tunes, UHD instantiations, and device reboots. Please try this and let us know how it goes. --- Michael L Dickens, PhD Emerson/NI/Ettus SDR RF Principal Application Engineer Teams: +1-512-683-5305 Cell: +1-512-585-1391 michael.l.dickens@emerson.com <michael.dickens@ni.com> michael.dickens@ettus.com On Tue, Mar 3, 2026 at 3:55 PM Chris Rogers <c1337rogers@gmail.com> wrote: > The X440 has a clock board ( > https://files.ettus.com/manual/page_usrp_x4xx.html#x4xx_too_clocking) > which uses the LMK04832 PLL ( > https://www.ti.com/lit/ds/symlink/lmk04832.pdf?ts=1772540151834) to > actually generate the RFSoC sample clock from the 10 MHz input. This PLL > output will have a phase ambiguity WRT the 10 MHz input signal because of > PLL physics, and this is why you see a random relative phase run to run. It > looks like this chip supports a synchronization input to align output clock > edges and the X440 technically has a sync input port on the front, but I > dont know if these inputs are actually connected to each other. It could be > worth looking into what the X440 Sync In does... last I checked, it didn't > actually do anything but that was at least a year ago > > On Tue, Mar 3, 2026 at 2:37 PM Eugene Grayver <eugene.grayver@aero.org> > wrote: > >> I have two X440 w/ X4_200 FPGA image. I need to get consistent phase >> between channels on USRP1 and USRP2 across multiple runs. I must be doing >> something wrong because I observe consistent phase between channels on any >> ONE USRP, but not across two. The phase appears to be random between the >> two on each run. >> >> Here's my setup: >> >> - Common 10 MHz and 1 PPS >> - >> Addr0=192.168.10.2,second_addr0=192.168.11.2,mgmt_addr0=192.168.1.10,addr1=192.168.15.2,second_addr1=192.168.16.2,mgmt_addr1=192.168.1.20,time_source=external,clock_source=external >> - I modified the 'stock' rx_samples_to_file as follows: >> - Usrp->set_time_next_pps(uhd::time_spec_t(0.0)); >> std::this_thread::sleep_for(std::chrono::milliseconds(1000)); >> - usrp->set_command_time(uhd::time_spec_t(COMMAND_START_S, 0)); >> // Set the rate, freq, gain, etc >> std::this_thread::sleep_for(std::chrono::milliseconds(COMMAND_START_S >> * 1000)); >> usrp->clear_command_time(); >> - Each streamer is created in a separate thread >> - stream_cmd.stream_now = false; >> // Time was reset to zero before thread was created >> stream_cmd.time_spec = uhd::time_spec_t(STREAM_START_S, 0); >> rx_stream->issue_stream_cmd(stream_cmd); >> >> >> What am I missing? I assume commands apply to both USRPs since I create >> a multi_usrp. Do I need to explicitly specify the motherboard for some of >> the commands? >> >> >> Eugene Grayver, Ph.D. >> Principal Engineer >> 310-336-1274 >> _______________________________________________ >> USRP-users mailing list -- usrp-users@lists.ettus.com >> To unsubscribe send an email to usrp-users-leave@lists.ettus.com >> > _______________________________________________ > USRP-users mailing list -- usrp-users@lists.ettus.com > To unsubscribe send an email to usrp-users-leave@lists.ettus.com >