In [1]:
from spirack import SPI_rack, S5k_module
import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook
import ipywidgets as ip
Open SPI rack connection and unlock (necessary after bootup of the controller module).
In [2]:
spi = SPI_rack("COM4", 1000000, 1)
spi.unlock()
Create new S5k module object at correct address and set clock source to internal clock and divide by 20. For all settings a 10 MHz external clock is assumed. The clock can be divided by all even numbers between 2-510.
In [11]:
s5k = S5k_module(spi, 3)
s5k.set_clock_source('internal')
s5k.set_clock_division(10)
Set the fast ramping DACs (1-4) to AWG (RAM readout) mode. This allows us to create a ramp of ~80 us. The slow ramp DACs (9-12) should be set to sawtooth mode. This allows for the creation of ~8 ms ramps.
In [12]:
for DAC in range(1,5):
s5k.set_waveform_mode(DAC, 'AWG')
s5k.set_digital_gain(DAC, 0.5)
for DAC in range(9,13):
s5k.set_waveform_mode(DAC, 'sawtooth')
s5k.set_digital_gain(DAC, 0.5)
The sawtooth ramp time length is given by: $$t_{saw} = \frac{2^{14}\cdot n}{f_{ext}}$$
Where $f_{ext}$ is the external clock frequency and $n$ the amount of clock ticks per sawtooth step. For a sawtooth ramp time of ~8ms with an external clock of 10 MHz this gives $n=5$: $$t_{saw} = \frac{2^{14}\cdot 5}{10^6} = 8.192 \text{ ms}$$
So we set the DACs (that are set to sawtooth) to a stepsize of n=5 and a ramp-up sawtooth.
In [13]:
for DAC in range(9,13):
s5k.set_sawtooth_parameters(DAC, 'ramp_up', 5)
If we want the fast ramp to be 100 times shorter than the slow ramp it has to be 81.92 $\mu s$. At a sample rate of 10 MHz, this gives 819.2 -> 819 samples. This gives a fast sawtooth time of 81.9 $\mu s$. This has a downside that the two waveforms don't exactly fit in time. If we make it a division by a power of two: 128 times as small, it will fit better. Dividing by 128 gives 64 $\mu s$ which would give 640 samples at 10 MHz.
In [17]:
wv_len = 640
max_val = 2047
min_val = -2048
waveform_data = ((max_val-min_val)/wv_len) * np.arange(0, wv_len) + min_val
# Need to be integer values, smarter to cast after calculation for rounding errors
waveform_data = waveform_data.astype(int)
plt.figure()
plt.plot(waveform_data)
plt.title("Fast ramp RAM")
plt.xlabel("Samples")
plt.ylabel("RAM values")
plt.show()
The waveform only needs to be uploaded once to the chip containing the DACs that generate the fast ramp. This is a shared memory and we simply point all the DACs to use the same piece of memory.
In [18]:
s5k.upload_waveform(1, waveform_data, 0, set_pattern_length=True)
for DAC in range(1,5):
s5k.set_RAM_address(DAC, 0, len(waveform_data)-1)
Set run_module to true to set all the modules to running and give a hardware trigger via the backplane. This hardware trigger is mirrored to the front to be able to trigger a digitizer. The digitizer/acquisition system should be set to trigger on the falling edge: the module outputs low if it is running and high if it is idle.
In [19]:
s5k.run_module(True)
For a demo: knobs for the gain of all the DACs.
In [20]:
def set_gain(DAC, value):
s5k.set_digital_gain(DAC, value)
DACs = [1,2,3,4,9,10,11,12]
sliders = [ip.widgets.FloatSlider(value=0.5, min=-1.0, max=1.0, step=0.01, description='DAC'+str(i)) for i in DACs]
for i in range(0,len(DACs)):
ip.interact(set_gain, DAC=ip.fixed(DACs[i]), value=sliders[i])
In [ ]:
spi.close()