Skip to content

Commit 3863607

Browse files
Merge pull request #54 from rpanderson/dummy_pseudoclock_updates
Save clock instructions and add runviewer parser for DummyPseudoclock
2 parents 88eeefe + cdd34f8 commit 3863607

File tree

3 files changed

+165
-12
lines changed

3 files changed

+165
-12
lines changed

labscript_devices/DummyPseudoclock/labscript_devices.py

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,109 @@
1515
# and labscript. The device is a PseudoclockDevice, and can be the sole device
1616
# in a connection table or experiment.
1717

18-
import labscript_utils.h5_lock
19-
import h5py
20-
from labscript import PseudoclockDevice, Pseudoclock, ClockLine
18+
from labscript import PseudoclockDevice, Pseudoclock, ClockLine, config, LabscriptError
19+
import numpy as np
20+
21+
class _DummyPseudoclock(Pseudoclock):
22+
def add_device(self, device):
23+
if isinstance(device, ClockLine):
24+
# only allow one child
25+
if self.child_devices:
26+
raise LabscriptError('The pseudoclock of the DummyPseudoclock %s only supports 1 clockline, which is automatically created. Please use the clockline located at %s.clockline'%(self.parent_device.name, self.parent_device.name))
27+
Pseudoclock.add_device(self, device)
28+
else:
29+
raise LabscriptError('You have connected %s to %s (the Pseudoclock of %s), but %s only supports children that are ClockLines. Please connect your device to %s.clockline instead.'%(device.name, self.name, self.parent_device.name, self.name, self.parent_device.name))
2130

2231

2332
class DummyPseudoclock(PseudoclockDevice):
2433

2534
description = 'Dummy pseudoclock'
26-
clock_limit = 1e6
27-
clock_resolution = 1e-6
35+
clock_limit = 10e6
36+
clock_resolution = 25e-9
37+
trigger_delay = 350e-9
38+
wait_delay = 2.5e-6
39+
allowed_children = [_DummyPseudoclock]
40+
max_instructions = 1e5
2841

29-
def __init__(self, name='dummy_pseudoclock', BLACS_connection='dummy_connection', **kwargs):
42+
def __init__(
43+
self, name='dummy_pseudoclock', BLACS_connection='dummy_connection', **kwargs
44+
):
3045
self.BLACS_connection = BLACS_connection
3146
PseudoclockDevice.__init__(self, name, None, None, **kwargs)
32-
self.pseudoclock = Pseudoclock(self.name + '_pseudoclock', self, 'pseudoclock')
33-
self.clockline = ClockLine(name='clockline', pseudoclock=self.pseudoclock, connection='dummy')
47+
self._pseudoclock = _DummyPseudoclock(
48+
name=f'{name}_pseudoclock',
49+
pseudoclock_device=self,
50+
connection='pseudoclock',
51+
)
52+
self._clock_line = ClockLine(
53+
name=f'{name}_clock_line',
54+
pseudoclock=self.pseudoclock,
55+
connection='internal',
56+
)
57+
58+
@property
59+
def pseudoclock(self):
60+
return self._pseudoclock
61+
62+
@property
63+
def clockline(self):
64+
return self._clock_line
65+
66+
def add_device(self, device):
67+
if not self.child_devices and isinstance(device, Pseudoclock):
68+
PseudoclockDevice.add_device(self, device)
69+
elif isinstance(device, Pseudoclock):
70+
raise LabscriptError('The %s %s automatically creates a Pseudoclock because it only supports one. '%(self.description, self.name) +
71+
'Instead of instantiating your own Pseudoclock object, please use the internal' +
72+
' one stored in %s.pseudoclock'%self.name)
73+
else:
74+
raise LabscriptError('You have connected %s (class %s) to %s, but %s does not support children with that class.'%(device.name, device.__class__, self.name, self.name))
3475

3576
def generate_code(self, hdf5_file):
3677
PseudoclockDevice.generate_code(self, hdf5_file)
3778
group = self.init_device_group(hdf5_file)
38-
self.set_property('stop_time', self.stop_time, location='device_properties')
79+
80+
# Compress clock instructions with the same period
81+
# This will halve the number of instructions roughly,
82+
# since the DummyPseudoclock does not have a 'slow clock'
83+
reduced_instructions = []
84+
for instruction in self.pseudoclock.clock:
85+
if instruction == 'WAIT':
86+
# The following period and reps indicates a wait instruction
87+
reduced_instructions.append({'period': 0, 'reps': 1})
88+
continue
89+
reps = instruction['reps']
90+
# period is in quantised units:
91+
period = int(round(instruction['step'] / self.clock_resolution))
92+
if reduced_instructions and reduced_instructions[-1]['period'] == period:
93+
reduced_instructions[-1]['reps'] += reps
94+
else:
95+
reduced_instructions.append({'period': period, 'reps': reps})
96+
# The following period and reps indicates a stop instruction:
97+
reduced_instructions.append({'period': 0, 'reps': 0})
98+
if len(reduced_instructions) > self.max_instructions:
99+
raise LabscriptError(
100+
"%s %s has too many instructions. It has %d and can only support %d"
101+
% (
102+
self.description,
103+
self.name,
104+
len(reduced_instructions),
105+
self.max_instructions,
106+
)
107+
)
108+
# Store these instructions to the h5 file:
109+
dtypes = [('period', int), ('reps', int)]
110+
pulse_program = np.zeros(len(reduced_instructions), dtype=dtypes)
111+
for i, instruction in enumerate(reduced_instructions):
112+
pulse_program[i]['period'] = instruction['period']
113+
pulse_program[i]['reps'] = instruction['reps']
114+
group.create_dataset(
115+
'PULSE_PROGRAM', compression=config.compression, data=pulse_program
116+
)
117+
# TODO: is this needed, the PulseBlasters don't save it...
118+
self.set_property(
119+
'is_master_pseudoclock',
120+
self.is_master_pseudoclock,
121+
location='device_properties',
122+
)
123+
self.set_property('stop_time', self.stop_time, location='device_properties')

labscript_devices/DummyPseudoclock/register_classes.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
#####################################################################
1313
import labscript_devices
1414

15+
labscript_device_name = 'DummyPseudoclock'
16+
blacs_tab = 'labscript_devices.DummyPseudoclock.blacs_tabs.DummyPseudoclockTab'
17+
parser = 'labscript_devices.DummyPseudoclock.runviewer_parsers.DummyPseudoclockParser'
18+
1519
labscript_devices.register_classes(
16-
'DummyPseudoclock',
17-
BLACS_tab='labscript_devices.DummyPseudoclock.blacs_tabs.DummyPseudoclockTab',
18-
runviewer_parser=None, #TODO make a runviwer parser for Dummy pseudoclock!
20+
labscript_device_name=labscript_device_name,
21+
BLACS_tab=blacs_tab,
22+
runviewer_parser=parser,
1923
)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import labscript_utils.h5_lock # noqa: F401
2+
import h5py
3+
import numpy as np
4+
5+
6+
class DummyPseudoclockParser(object):
7+
clock_resolution = 25e-9
8+
trigger_delay = 350e-9
9+
wait_delay = 2.5e-6
10+
11+
def __init__(self, path, device):
12+
self.path = path
13+
self.name = device.name
14+
self.device = device
15+
16+
def get_traces(self, add_trace, clock=None):
17+
if clock is not None:
18+
times, clock_value = clock[0], clock[1]
19+
clock_indices = np.where((clock_value[1:] - clock_value[:-1]) == 1)[0] + 1
20+
# If initial clock value is 1, then this counts as a rising edge
21+
# (clock should be 0 before experiment) but this is not picked up
22+
# by the above code. So we insert it!
23+
if clock_value[0] == 1:
24+
clock_indices = np.insert(clock_indices, 0, 0)
25+
clock_ticks = times[clock_indices]
26+
27+
# get the pulse program
28+
with h5py.File(self.path, 'r') as f:
29+
pulse_program = f[f'devices/{self.name}/PULSE_PROGRAM'][:]
30+
31+
time = []
32+
states = []
33+
trigger_index = 0
34+
t = 0 if clock is None else clock_ticks[trigger_index] + self.trigger_delay
35+
trigger_index += 1
36+
37+
clock_factor = self.clock_resolution / 2.0
38+
39+
for row in pulse_program:
40+
if row['period'] == 0:
41+
# special case
42+
if row['reps'] == 1: # WAIT
43+
if clock is not None:
44+
t = clock_ticks[trigger_index] + self.trigger_delay
45+
trigger_index += 1
46+
else:
47+
t += self.wait_delay
48+
else:
49+
for i in range(row['reps']):
50+
for j in range(1, -1, -1):
51+
time.append(t)
52+
states.append(j)
53+
t += row['period'] * clock_factor
54+
55+
clock = (np.array(time), np.array(states))
56+
57+
clocklines_and_triggers = {}
58+
for pseudoclock_name, pseudoclock in self.device.child_list.items():
59+
for clock_line_name, clock_line in pseudoclock.child_list.items():
60+
if clock_line.parent_port == 'internal':
61+
clocklines_and_triggers[clock_line_name] = clock
62+
add_trace(clock_line_name, clock, self.name, clock_line.parent_port)
63+
64+
return clocklines_and_triggers

0 commit comments

Comments
 (0)