Multi-Device Synchronization

This example illustrates how to resynchronize multiple Red Pitaya-125 via the daisy chain connectors (gen 1: SATA, gen 2: USB-C) to an accuracy of +/- 1 clk cycle between neighboring devices.

In detail, a pair of Red Pitaya-125 are resynchronized and after a variable hold time output a gaussian pulse on their RF outputs. Both pulses are acquired on the RF inputs of the first device and the corresponding arrival times are estimated, expecting a spread of +/- 1 clk cycle at low hold times but increasing at larger timescales due to relative drifts in the frequency of the Red Pitaya reference clocks.

Required hardware connection (see README for IO Names and Pin Mapping):

  • SMA cable between rp_0.rf_out_0 <-> rp_0.rf_in_0

  • SMA cable between rp_1.rf_out_0 <-> rp_0.rf_in_1

  • SATA / USB-C cable rp_0.daisy_0 <-> rp_1.daisy_1

Imports

import time 
import numpy as np
from matplotlib import pyplot as plt
from openlabctrl.device import Rp_125_14_Z7010
from openlabctrl.sequence import IoSequence
from openlabctrl.frame import IoSyncFrame, ParamIoSyncFrame
from openlabctrl.io.scope import ScopeSource

Device instances

rp_0 = Rp_125_14_Z7010(ip="192.168.1.143", label="rp_0", daisy_0_en=True, daisy_1_en=False)
rp_1 = Rp_125_14_Z7010(ip="192.168.1.155", label="rp_1", daisy_0_en=False, daisy_1_en=True)

IO Sequences & IO Frames instances

seq = IoSequence(device_list=[rp_0, rp_1])
fr_0 = ParamIoSyncFrame(device_type=Rp_125_14_Z7010, trig=None)
fr_1 = ParamIoSyncFrame(device_type=Rp_125_14_Z7010, trig=None)
fr_2 = ParamIoSyncFrame(device_type=Rp_125_14_Z7010, trig=None)
fr_3 = ParamIoSyncFrame(device_type=Rp_125_14_Z7010, trig=None)

Frame definitions

def rf_init(fr: IoSyncFrame):
    fr.reset()
    fr.rf_out_0.frequency(0)
    fr.rf_out_0.phase(0)
    fr.rf_out_0.amplitude(0)
    fr.rf_out_0.phase_reset()
    fr.rf_out_1.frequency(0)
    fr.rf_out_1.phase(0)
    fr.rf_out_1.amplitude(0)
    fr.rf_out_1.phase_reset()

def delay(fr: IoSyncFrame, delay: int):
    fr.reset()
    fr.delay(delay)

def rf_io(fr: IoSyncFrame, waveform:np.ndarray):
    fr.reset()
    fr.scope_0.source(ScopeSource.RF_IN_0)
    fr.scope_1.source(ScopeSource.RF_IN_1)
    fr.scope_0.decimation(1)
    fr.scope_1.decimation(1)
    fr.scope_0.acquire(samples=len(waveform), label="acq_ch_0")
    fr.scope_1.acquire(samples=len(waveform), label="acq_ch_1")

    for data in waveform:
        fr.rf_out_0.amplitude(data)
        fr.rf_out_1.amplitude(data)
    fr.rf_out_0.amplitude(0)
    fr.rf_out_1.amplitude(0)

def rf_o(fr: IoSyncFrame, waveform:np.ndarray):
    fr.reset()
    for data in waveform:
        fr.rf_out_0.amplitude(data)
        fr.rf_out_1.amplitude(data)
    fr.rf_out_0.amplitude(0)
    fr.rf_out_1.amplitude(0)




fr_0.set_frame_function(rf_init)
fr_1.set_frame_function(delay)
fr_2.set_frame_function(rf_io)
fr_3.set_frame_function(rf_o)
    

Sequence definition

seq.reset()
seq.add_frame(frame=fr_0, device=rp_0, label="rf init")
seq.add_frame(frame=fr_0, device=rp_1, label="rf init")
seq.add_rsync()
seq.add_frame(frame=fr_1, device=rp_0, label="delay")
seq.add_frame(frame=fr_1, device=rp_1, label="delay")
seq.add_frame(frame=fr_2, device=rp_0, label="RF in/out")
seq.add_frame(frame=fr_3, device=rp_1, label="RF out")

print(seq.sequence_description())
+--------------------+--------------------+
| rp_0@192.168.1.143 | rp_1@192.168.1.155 |
+--------------------+--------------------+
| rf init            | rf init            |
|-rsync_0--------------rsync_0------------|
| delay              | delay              |
| RF in/out          | RF out             |
+--------------------+--------------------+
NOTE: Frames with (*) are triggered by external trigger source.

Run scan

delay_list = 1 << np.arange(25)
waveform = 0.5 * np.exp(-np.linspace(-5, 5, 100)**2)

rp_acq = rp_0 #Select which device is used to acquire
rp_acq_id = rp_acq.get_uid()
clk_freq = rp_acq.CLK_FREQ #125 MH



for delay in delay_list:    
    fr_1.set_frame_parameter(delay=delay)
    fr_2.set_frame_parameter(waveform=waveform)
    fr_3.set_frame_parameter(waveform=waveform)
    
    seq.upload()
    seq.start()
    seq.wait()
    
    scope_dict = seq.get_scope()
      
    data_in_1_list = scope_dict[rp_acq_id]["RF in/out"]["scope_0"]["acq_ch_0"]["data"]
    data_in_2_list = scope_dict[rp_acq_id]["RF in/out"]["scope_1"]["acq_ch_1"]["data"]

    idx_max_1 = np.argmax(data_in_1_list)
    idx_max_2 = np.argmax(data_in_2_list)

    # Calculate cross-correlation to find max overlap
    correlation = np.correlate(data_in_1_list, data_in_2_list, mode='full')
    max_overlap_index = np.argmax(correlation)
    max_overlap_index = max_overlap_index - (len(data_in_1_list) - 1)  # Adjust index to account for 'full' mode
    print(f"Delay: {delay} ({delay/clk_freq:.9f} s) -> idx_max_1: {idx_max_1}, idx_max_2: {idx_max_2}")
    plt.figure(figsize=(4, 3))
    plt.plot(data_in_1_list, label="Ch1")
    plt.plot(data_in_2_list, label="Ch2")
    plt.legend(loc=1)
    plt.show()
    
Delay: 1 (0.000000008 s) -> idx_max_1: 61, idx_max_2: 58
../_images/8af4286801b649bd35783953a796d1b388b78729b7d37a0206185dec1f9d6b8c.png
Delay: 2 (0.000000016 s) -> idx_max_1: 61, idx_max_2: 59
../_images/8b2d727339a2699a6904832bfda4b9fe70bc5396ebacc3b58f06d398c957b5b9.png
Delay: 4 (0.000000032 s) -> idx_max_1: 61, idx_max_2: 59
../_images/aecd85336e43d0cb12d111f026e61b6abcdfded0213eebed1bd1de83e4055277.png
Delay: 8 (0.000000064 s) -> idx_max_1: 61, idx_max_2: 59
../_images/219c9f5ee463548f63b158bdd4bd3734e6b69c443a265d4acde1eee3d978107c.png
Delay: 16 (0.000000128 s) -> idx_max_1: 61, idx_max_2: 58
../_images/6f2c9415777883b13ac596a4f1f4f914778b3cd382a33a274bd532a43f1426c0.png
Delay: 32 (0.000000256 s) -> idx_max_1: 61, idx_max_2: 59
../_images/39ae18e2897e2c81d69427e565dae081c74cc16131bb682a637f0d8f57a8abd8.png
Delay: 64 (0.000000512 s) -> idx_max_1: 61, idx_max_2: 59
../_images/5f831bff4625d36c915bca5e0ae0614fd643a6f764da52dec44bba88ac0499b5.png
Delay: 128 (0.000001024 s) -> idx_max_1: 61, idx_max_2: 58
../_images/21e5dc5def438e7592ade4e0ba10b3724f4913bdcc506477d11b1b5dbbb4b6da.png
Delay: 256 (0.000002048 s) -> idx_max_1: 61, idx_max_2: 58
../_images/cc138f25696fff3bc222ed7a418eb81847cea95c8f0450210a7f766c760858db.png
Delay: 512 (0.000004096 s) -> idx_max_1: 61, idx_max_2: 59
../_images/2b7d13b975d9474b84c47c50073059455c846bc9ea6077d7e8e3911c35a8dd90.png
Delay: 1024 (0.000008192 s) -> idx_max_1: 61, idx_max_2: 58
../_images/e8e8ed4d43bf641d28502eded4c1bd4394e4d6d2a967578d3fe855db11b0ccdd.png
Delay: 2048 (0.000016384 s) -> idx_max_1: 61, idx_max_2: 59
../_images/d393ed1433185d7be18627db057fcaa396374674a7f91684758d2cf8814a504e.png
Delay: 4096 (0.000032768 s) -> idx_max_1: 61, idx_max_2: 58
../_images/7e62d5035cfaf50847a0f6b5088b00e2e0d9fb244f22bb77597f4dc38fa8d8c6.png
Delay: 8192 (0.000065536 s) -> idx_max_1: 61, idx_max_2: 59
../_images/e5ca740ada608b2997e9bf314eeeb33f3621381c759cf5a63c9eef3c8bf8634c.png
Delay: 16384 (0.000131072 s) -> idx_max_1: 61, idx_max_2: 58
../_images/f08ff09685e6cfe81951e72512852c8bfaab157cc0fa1a3cd7b0e11c707f7cf0.png
Delay: 32768 (0.000262144 s) -> idx_max_1: 61, idx_max_2: 58
../_images/cc19f768f945be2cae500a926e1aeb6be9f5de86490cf5a38c4a977eb3a6f204.png
Delay: 65536 (0.000524288 s) -> idx_max_1: 61, idx_max_2: 59
../_images/372aafcb19a05341c0f0bad7b775134ea26f82eb49a971f43f0f499dc69ee1b0.png
Delay: 131072 (0.001048576 s) -> idx_max_1: 61, idx_max_2: 58
../_images/b52653f4f0d380f51e518aad786bb31add3f61cd56147777d630373023943310.png
Delay: 262144 (0.002097152 s) -> idx_max_1: 61, idx_max_2: 58
../_images/abe679900d173e36ada80942200899b1f61d277efdea4c59b9416a93e65785f5.png
Delay: 524288 (0.004194304 s) -> idx_max_1: 61, idx_max_2: 57
../_images/39b8cd147d082058cb344638c8834566454b93af3e2a9067d511a7ec9169fec1.png
Delay: 1048576 (0.008388608 s) -> idx_max_1: 61, idx_max_2: 56
../_images/f4a0717f3fe1548bd44734ff2f657b4e481492729880b98017e78ffb8ad4b92c.png
Delay: 2097152 (0.016777216 s) -> idx_max_1: 61, idx_max_2: 53
../_images/746d1ee222b8445aed4b7f5e6b243899a4d663b907b8f3e080d05bbe314071f8.png
Delay: 4194304 (0.033554432 s) -> idx_max_1: 61, idx_max_2: 47
../_images/5a1639b5b135e080702c164981b0e45a4aa515dc6916ae361e7921de4c1bd265.png
Delay: 8388608 (0.067108864 s) -> idx_max_1: 61, idx_max_2: 36
../_images/f1561568979160098655e9e29ad659efc75780a1c63ae3327f90ab602b175dc9.png
Delay: 16777216 (0.134217728 s) -> idx_max_1: 61, idx_max_2: 13
../_images/fcb3b32dd75b2c53c2a29c01cfd75db74c03535c3ac63d754b8dcb970f26bc69.png