DCRC Charge Signal Control Test

RevE

Texas A&M University

In this test the charge channels readout and triggering will be tested.

  • First a single trace from each channel will be read and plotted
  • Then, you should connect a signal generator to the charge channel input in the miniBob, the code will use the trigger to locate, read and plot the trace

Note: if this is an exported file you can click on plots and comments to toggle display the source code.

In [1]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib
In [2]:
import DCRC_controls
import Trigger_Simulation.trigger_simulation as trig_sim
import trig_controls
import picoscope
import ipywidgets as widgets
from test_utilities import *
In [3]:
# Set up some plotting defaults
matplotlib.rc('figure', figsize=(6, 5*(4/6)), dpi=144)
matplotlib.rc('font', size=6)
matplotlib.rc('legend', scatterpoints=1)
colors=['#af1b1b','#c51e1e','#db2222',#red
        '#db7e22','#db7e22','#db7e22',#orange
        '#c5c51e','#dbdb22','#e0e036',#yellow
        '#72c51e','#8be036','#a5e762',#green
        '#1b65af','#227edb','#4c98e3']#blue
subcolors= ['#e98a72','#ec9b86','#f2bcae',
            '#ecce86', '#efd69a','#f2deae',
            '#ffc293','#ffd0ac','#ffdfc6',
            '#91c588','#b1d5aa','#c1debb',
            '#6672b4','#8891c5','#aab1d5']
width=4
nn=0

Connect and Initiate

Initiate connection and run some quick tests. The board is already assumed to be 'set-up' (likely with drec 1), but not fixed here to keep flexibility. It is even possible to execute that or any requirement in the "Command Machine" Cell.

In [4]:
DCRC = DCRC_controls.DCRC('165.91.180.60', 5003)
DCRC.open()

DCRC.write_reg(0x20, 0x10) # Make this DCRC the bus master
DCRC.enable_ADC() # Turn on digitization

# Check serial number etc.
IDinfo = DCRC.ID()
for key in IDinfo.keys():
    print('% 13s: % 15s'%(key, IDinfo[key]))
print()
print("FPGA Firmware version string:", DCRC.firmware_version())
  Module Type:       DCRC REVE
 Compile Date:     Mar 14 2019
Firmware Vers:            2.06
FPGA SumCheck:            AA54
FPGA BytCount:          915864
Serial number:              13

FPGA Firmware version string: e4c62d2 RevE
In [5]:
# Connect to the picoscope
scope = picoscope.picoscope()
scope.open()
In [6]:
times = linspace(0, 2*pi, 1000)
scope.setup_AWG(10000*sin(times), shots=-1)
scope.trigger_AWG()
In [7]:
DCRC.DCRC.send(b"drec 0\r")
DCRC.write_reg(0x440, 0)
time.sleep(0.5)
DCRC.DCRC.recv(32768)
pass
#print(DCRC.DCRC.recv(32768).decode())
In [11]:
qchan=12     # channel to read (12 to 15) Q0:15 Q1:14 Q2:13 Q3:12
nwds=20*4096      # number of words to read (decimal, will convert to hex)
#time.sleep(0.5)
DCRC.reset_ADC()
time.sleep(0.25)
thpulse=DCRC.readout(qchan, nwds, offset=8192)
fig = PlotPulse([thpulse], "Test Charge Trace", plabels=['Q'+str(qchan)])

Change charge offset and see its effects

Disconnect picoscope from DCRC

In [12]:
%%time
DCRC.write_reg(0x402, 0)
for qch in [0,1,2,3]:
#for qch in [0]:
    figure()
    for setting in [0x0000, 0xc000, 0xf000, 0xffff]:
        DCRC.reset_ADC()
        time.sleep(0.25)
        DCRC.write_reg(0x600 + qch, setting)
        time.sleep(0.25)
        dat = DCRC.readout(12 + qch, 2*625000, offset=128)
        plot(arange(2*625000)/2.5e6, dat)
        time.sleep(1)
    xlabel('Time [s]')
    ylabel('Charge ch %d trace [arb.]'%qch)
CPU times: user 10.5 s, sys: 1.28 s, total: 11.8 s
Wall time: 31.9 s

Trigger from Charge Pulser

In [13]:
DCRC.DCRC.send(b"drec 0\r")
time.sleep(0.5)
DCRC.DCRC.recv(32768)
pass
#print(DCRC.DCRC.recv(32768).decode())
In [14]:
DCRC.write_reg(0x402, 1)        # Enable Test Signal
DCRC.write_reg(0x403, 1)
DCRC.write_reg(0x404, 0)
#DCRC.write_reg(0x405, 0x002)
DCRC.write_reg(0x410, 0)
DCRC.write_reg(0x411, 0x900)    # Test signal frequency (MSB)
DCRC.write_reg(0x440, 1)        # Enable Charge Pulse Test
DCRC.write_reg(0x441, 0)        # Select one charge channel to test:0, 1, 2, 3
DCRC.write_reg(0x442, 0x500)    # set the amplitute: 0x000-0xFFF(0mV-5V in steps of 1.2mV)
In [15]:
time.sleep(0.5)
qchan=12
# channel to read (12 to 15)
nwds=16384*4 #48*4096      # number of words to read (decimal, will convert to hex)
#time.sleep(0.5)
DCRC.reset_ADC()
time.sleep(0.25)
thpulse=DCRC.readout(qchan, nwds, offset=8192)
fig = PlotPulse([thpulse], "Test Charge Trace_Pulser", plabels=['Q'+str(qchan)])
In [17]:
LC_coeffs = zeros((4,16), 'i8')
LC_coeffs[0,qchan] = -127 # only one phonon channel

raw_FIR_coeffs = zeros((4, 1024))
raw_FIR_coeffs[0, 0:10] = 3  # 10 baseline samples
raw_FIR_coeffs[0, 10:13] = -10 # 3 signal samples
FIR_coeffs = asarray(raw_FIR_coeffs * 3276, 'i8')

trig = trig_sim.Trigger(bits_phonon=16, bits_charge=16,
                        phonon_DF_R=16, phonon_DF_N=3, phonon_DF_M=1, phonon_start=0,
                        charge_DF_R=64, charge_DF_N=3, charge_DF_M=1, charge_start=0,
                        LC_coeffs=LC_coeffs, LC_bits_out=46,
                        LC_bits_coeff=8, LC_discard_MSBs=[0,0,0,0],
                        FIR_coeffs=FIR_coeffs, FIR_bits_out=32, 
                        FIR_bits_coeff=16, FIR_discard_MSBs=[0,0,0,0],
                        ThL_selectors=array([0,1,1,1,1,1,1,1], dtype='uint'),
                        ThL_activation_thresholds   = 32767*ones(8, int),
                        ThL_deactivation_thresholds = zeros(8, int),
                        PS_max_window_lengths=(2**31 - 1)*ones(4, dtype='uint'),
                        PS_saturated_pulse_offsets=zeros(4, dtype='uint'),
                        TrL_selectors=array([0,1,1,1,1,1,1,1], dtype='uint'),
                        TrL_enables=array([1,0,0,0,0,0,0,0], dtype=bool),
                        TrL_requires=zeros((8,16), bool), TrL_vetos=zeros((8, 16), bool),
                        TrL_prescales=ones(8, dtype='float'))

trig.ThL.ThLs[0].set_thresholds(9000, 0)
tc = trig_controls.Trig_Controls(DCRC, trig, verbose=False)
In [18]:
def get_atleast1_trig():
    trigs = array([])
    trys = 0
    while len(trigs) == 0:
        if trys >= 10:
            raise RuntimeError("Tried %d times, but recorded no triggers"%trys)
        DCRC.clear_trig_FIFO()
        scope.trigger_AWG()
        time.sleep(0.25)
        trigs = DCRC.read_trig_FIFO()
        trys += 1
    #DCRC.disable_ADC()
    return trigs
In [19]:
def readout_trig(one_trigger):
    downsample_offset = (one_trigger['timestamp']-7) % 16 + 7
    dat = [asarray(DCRC.readout(i, 16384, offset=one_trigger['timestamp'] - 8192 - downsample_offset), 'i8')
           for i in range(12)]
    dat.extend([asarray(DCRC.readout(i, 16384*4, offset=one_trigger['timestamp'] - 8192 - downsample_offset), 'i8')
           for i in range(12,16)])
    #dat.extend([zeros(4*16384, 'i8')]*4)
    
    trig.reset()
    trig.through_FIR.send(dat)
    FIRdat = trig.through_FIR.send(dat)
    return dat, FIRdat
In [20]:
DCRC.reset_ADC()
#DCRC.write_reg(0x0, 0x1)

# Configure the trigger for non-inverted pulses
qchan=12
LC_coeffs = zeros((4,16), 'i8')
LC_coeffs[0,qchan] = -127
trig.set_FIR_coeffs(FIR_coeffs)
tc.configure_trigger()
time.sleep(0.75)

trigs = get_atleast1_trig()
print('trigs:\n', trigs)
datatrigs = trigs[(trigs['trigword']!=0)&(trigs['trigbits']!=255)]
print('datatrigs:', 'Amplitude of datatrigs[0]', datatrigs[0]['amplitude'],'\n', datatrigs)
dat, FIRdat = readout_trig(datatrigs[0])
print('FIRdat:','(Max)', amax(FIRdat[0]),'\n','FIRdat[0]',FIRdat[0])
#asarray(thpulse, dtype='i8')
thpulses=[zeros(16384, dtype='i8')]*12 + [zeros(16384*4, dtype='i8')]*3 + [asarray(thpulse, dtype='i8')]
#print('thpulses:\n', thpulses)
#trig.reset()
FIRdat1=trig.through_FIR.send(thpulses)
print('FIRdat1:','(Max)', amax(FIRdat1[0]),'(Min)',amin(FIRdat[0]),'\n','FIRdat1[0]',FIRdat1[0])
assert amax(FIRdat[0]) == datatrigs[0]['amplitude']

PlotPulse([dat[qchan]], plttitle='Triggered charge pulse')
show()
close()

PlotPulse([FIRdat[0]], plttitle='FIR output')
show()
close()
trigs:
 [(1682007, 11708, 34181, 1) (1705431, 18097, 34181, 1)
 (1728615, 11962, 34181, 1) (1752039, 18090, 34181, 1)
 (1775223, 11598, 34181, 1) (1798647, 17975, 34181, 1)]
datatrigs: Amplitude of datatrigs[0] 11708 
 [(1682007, 11708, 34181, 1) (1705431, 18097, 34181, 1)
 (1728615, 11962, 34181, 1) (1752039, 18090, 34181, 1)
 (1775223, 11598, 34181, 1) (1798647, 17975, 34181, 1)]
FIRdat: (Max) 11708 
 FIRdat[0] [ 15  18   6 ... -16  -9   5]
FIRdat1: (Max) 15 (Min) -9396 
 FIRdat1[0] [   15 -1533 -8748 ...     0     0     0]

Test ALL Charge Channels with pulser

In [22]:
#qchs=[12,15,14,13]    # for RevE SN8

qchs=[12,15,14,13]

trig.set_FIR_coeffs(FIR_coeffs)
qch_pulses=zeros((len(qchs),65536), '>i2')
qchFIR_pulses = zeros((4,1024), '>i2')

for ii,tchan in enumerate(qchs):
    LC_coeffs = zeros((4, 16), 'i8')
    LC_coeffs[0, tchan] = -127
    trig.set_LC_coeffs(LC_coeffs)
    tc.configure_trigger()
    time.sleep(0.25)
    DCRC.write_reg(0x441, ii)
    time.sleep(0.25)
    
    nwds=16384*4 #48*4096      # number of words to read (decimal, will convert to hex)
    DCRC.reset_ADC()
    time.sleep(0.25)
    thpulse=DCRC.readout(tchan, nwds, offset=8192)
    
    trigs = get_atleast1_trig()
    datatrigs = trigs[(trigs['trigword']!=0)&(trigs['trigbits']!=255)]
    dat, FIRdat = readout_trig(datatrigs[0])
    #thpulses=[zeros(16384, dtype='i8')]*12 + [zeros(16384*4, dtype='i8')]*3 + [asarray(thpulse, dtype='i8')]
    #FIRdat1=trig.through_FIR.send(thpulses)
    assert amax(FIRdat[0]) == datatrigs[0]['amplitude']
    qch_pulses[ii] = dat[tchan]
    qchFIR_pulses[ii] = FIRdat[0]
    
channel_tabs = widgets.Tab()
display(channel_tabs)
channel_tabs.children = [widgets.Output() for i in range(len(qchs))]
for ii, tchan in enumerate(qchs):
    channel_tabs.set_title(ii, 'qCh.%d'%tchan)
    with channel_tabs.children[ii]:
        PlotPulse(qch_pulses[ii], plttitle='Triggered Charge Pulse. Charge Channel %d'%tchan)
        show()
        close()
        PlotPulse(qchFIR_pulses[ii], plttitle='FIR output. Charge Channel %d'%tchan)
        show()
        close()

II. Trigger Test with Input Pulses

Connect the scope

In [23]:
@vectorize
def make_charge_pulse(t):
    if t < 0:
        return 0.
    else:
        return exp(-t/650e-6) - exp(-t/100e-6)
    
charge_times = (arange(16384)-8192) * 32 / 2.5e6
#charge_times = (arange(16384) - 8192) / 625e3
charge_pulse = make_charge_pulse(charge_times)
charge_pulse /= amax(charge_pulse)

plot(charge_pulse)
Out[23]:
[<matplotlib.lines.Line2D at 0x7fa6935b0400>]
In [53]:
# Define configurations for reading input signal
qchan=15        # channel to read (0 to 11)
nwds=8192       # number of words to read (decimal, will convert to hex)
nqchans=4       # number of charge channels

DCRC.DCRC.send(b"drec 0\r")
time.sleep(0.5)
DCRC.DCRC.recv(32768)
DCRC.write_reg(0x440, 0)
pass
#print(DCRC.DCRC.recv(32768).decode())
In [54]:
time.sleep(0.4)
scope.setup_AWG((charge_pulse)* 100 * 32768, shots=9)
scope.trigger_AWG()
DCRC.reset_ADC()

time.sleep(0.5)
thpulse = DCRC.readout(qchan, 40*4096, offset=4096)  #16384
PlotPulse([thpulse], "Test Charge Pulse", plabels=['Q'+str(qchan-12)])
pass
In [55]:
LC_coeffs = zeros((4,16), 'i8')
LC_coeffs[0,qchan] = 127 # only one channel

raw_FIR_coeffs = zeros((4, 1024))
raw_FIR_coeffs[0, 0:10] = 3  # 10 baseline samples
raw_FIR_coeffs[0, 10:13] = -10 # 3 signal samples
FIR_coeffs = asarray(raw_FIR_coeffs * 3276, 'i8')

trig = trig_sim.Trigger(bits_phonon=16, bits_charge=16,
                        phonon_DF_R=16, phonon_DF_N=3, phonon_DF_M=1, phonon_start=0,
                        charge_DF_R=64, charge_DF_N=3, charge_DF_M=1, charge_start=0,
                        LC_coeffs=LC_coeffs, LC_bits_out=46,
                        LC_bits_coeff=8, LC_discard_MSBs=[0,0,0,0],
                        FIR_coeffs=FIR_coeffs, FIR_bits_out=32, 
                        FIR_bits_coeff=16, FIR_discard_MSBs=[0,0,0,0],
                        ThL_selectors=array([0,1,1,1,1,1,1,1], dtype='uint'),
                        ThL_activation_thresholds   = 32767*ones(8, int),
                        ThL_deactivation_thresholds = zeros(8, int),
                        PS_max_window_lengths=(2**31 - 1)*ones(4, dtype='uint'),
                        PS_saturated_pulse_offsets=zeros(4, dtype='uint'),
                        TrL_selectors=array([0,1,1,1,1,1,1,1], dtype='uint'),
                        TrL_enables=array([1,0,0,0,0,0,0,0], dtype=bool),
                        TrL_requires=zeros((8,16), bool), TrL_vetos=zeros((8, 16), bool),
                        TrL_prescales=ones(8, dtype='float'))

trig.ThL.ThLs[0].set_thresholds(500, 0)
tc = trig_controls.Trig_Controls(DCRC, trig, verbose=False)
In [56]:
def get_atleast1_trig():
    trigs = array([])
    trys = 0
    while len(trigs) == 0:
        if trys >= 10:
            raise RuntimeError("Tried %d times, but recorded no triggers"%trys)
        DCRC.clear_trig_FIFO()
        scope.trigger_AWG()
        time.sleep(0.25)
        trigs = DCRC.read_trig_FIFO()
        trys += 1
    return trigs
In [57]:
def readout_trig(one_trigger):
    downsample_offset = (one_trigger['timestamp']-7) % 16 + 7
    dat = ([asarray(DCRC.readout(i, 16384, offset=one_trigger['timestamp'] - 8192 - downsample_offset), 'i8')
           for i in range(12)]+
           [asarray(DCRC.readout(i, 65536, offset=one_trigger['timestamp'] - 8192 - downsample_offset), 'i8')
           for i in range(12,16)])
    # dat.extend([zeros(4*16384, 'i8')]*4)
    
    trig.reset()
    trig.through_FIR.send(dat)
    FIRdat = trig.through_FIR.send(dat)
    return dat, FIRdat
In [58]:
#scope.setup_AWG(charge_pulse * 32000, shots=1)
DCRC.reset_ADC()
#DCRC.write_reg(0x0, 0x1)

# Configure the trigger for non-inverted pulses
trig.set_FIR_coeffs(FIR_coeffs)
tc.configure_trigger()
time.sleep(0.75)

trigs = get_atleast1_trig()
dat, FIRdat = readout_trig(trigs[0])
#assert amax(FIRdat[0]) == trigs[0]['amplitude']

PlotPulse([dat[qchan]], plttitle='Triggered charge pulse')
show()
close()

PlotPulse([FIRdat[0]], plttitle='FIR output')
show()
close()
In [64]:
qtrig_pulses = zeros((4,16384*4), '>i2')
qtrigFIR_pulses = zeros((4,1024), '>i2')
LC_coeffs = zeros((4, 16), 'i8')
LC_coeffs[0, 12] = 127
trig.set_LC_coeffs(LC_coeffs)
tc.configure_trigger()
time.sleep(0.25)
#qchs=[12,14,15,13]
#qchs=[12,13,14,15]
qchs=[12,13,14,15]
register=[0,3,2,1]
reg_qchs=[12,15,14,13]
#minibob=[3,2,1,0]
minibob=[3,2,1,0]

for i in range(len(qchs)):
    LC_coeffs = zeros((4, 16), 'i8')
    LC_coeffs[0, qchs[i]] = 127
    trig.set_LC_coeffs(LC_coeffs)
    tc.configure_trigger()
    time.sleep(0.25)
    keepgoing = input("Is the signal input connected to Q{}, and already triggering? (y/n)".format(minibob[i]))
    if keepgoing.strip() not in ['y', 'yes']: break
    try:
        trigs = get_atleast1_trig()
    except:
        flag=1
        continue
    datatrigs = trigs[(trigs['trigword']!=0)&(trigs['trigbits']!=255)]
    dat, FIRdat = readout_trig(datatrigs[0])
    assert amax(FIRdat[0]) == datatrigs[0]['amplitude']
    #dat, FIRdat = readout_trig(trigs[0])
    #assert amax(FIRdat[0]) == trigs[0]['amplitude']
    qtrig_pulses[i] = dat[qchs[i]]
    qtrigFIR_pulses[i] = FIRdat[0]
    if flag==1:
        flag=0
        print("Channel {} is not triggered".format(tchan))
    
qtrig_tabs = widgets.Tab()
display(qtrig_tabs)
qtrig_tabs.children = [widgets.Output() for ii in range(len(qchs))]
for j,qchan in enumerate(qchs):
    qtrig_tabs.set_title(j, "qCh.%d"%qchan)
    with qtrig_tabs.children[j]:
        PlotPulse(qtrig_pulses[j], plttitle="Triggered Input Pulse, Charge Channel {}".format(qchan))
        show()
        close()
        PlotPulse(qtrigFIR_pulses[j], plttitle="FIR Output, Charge Channel {}".format(qchan))
        show()
        close()
Is the signal input connected to Q3, and already triggering? (y/n)y
Is the signal input connected to Q2, and already triggering? (y/n)y
Is the signal input connected to Q1, and already triggering? (y/n)y
Is the signal input connected to Q0, and already triggering? (y/n)y
In [ ]:
 
In [ ]: