Skip to content

Commit 4a4096f

Browse files
committed
Save clock instructions (mock PineBlaster) and add runviewer_parser
1 parent 535c9b3 commit 4a4096f

File tree

3 files changed

+147
-12
lines changed

3 files changed

+147
-12
lines changed

labscript_devices/DummyPseudoclock/labscript_devices.py

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,90 @@
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
2120

2221

2322
class DummyPseudoclock(PseudoclockDevice):
2423

2524
description = 'Dummy pseudoclock'
26-
clock_limit = 1e6
27-
clock_resolution = 1e-6
25+
clock_limit = 10e6
26+
clock_resolution = 25e-9
27+
clock_type = 'fast clock'
28+
trigger_delay = 350e-9
29+
wait_delay = 2.5e-6
30+
allowed_children = None
31+
max_instructions = 1e5
2832

29-
def __init__(self, name='dummy_pseudoclock', BLACS_connection='dummy_connection', **kwargs):
33+
def __init__(
34+
self, name='dummy_pseudoclock', BLACS_connection='dummy_connection', **kwargs
35+
):
3036
self.BLACS_connection = BLACS_connection
3137
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')
38+
self._pseudoclock = Pseudoclock(
39+
name=f'{name}_pseudoclock',
40+
pseudoclock_device=self,
41+
connection='pseudoclock',
42+
)
43+
self._clock_line = ClockLine(
44+
name=f'{name}_clock_line',
45+
pseudoclock=self.pseudoclock,
46+
connection='internal',
47+
)
48+
49+
@property
50+
def pseudoclock(self):
51+
return self._pseudoclock
52+
53+
@property
54+
def clockline(self):
55+
return self._clock_line
3456

3557
def generate_code(self, hdf5_file):
3658
PseudoclockDevice.generate_code(self, hdf5_file)
3759
group = self.init_device_group(hdf5_file)
38-
self.set_property('stop_time', self.stop_time, location='device_properties')
60+
61+
# Compress clock instructions with the same period
62+
# This will halve the number of instructions roughly,
63+
# since the DummyPseudoclock does not have a 'slow clock'
64+
reduced_instructions = []
65+
for instruction in self.pseudoclock.clock:
66+
if instruction == 'WAIT':
67+
# The following period and reps indicates a wait instruction
68+
reduced_instructions.append({'period': 0, 'reps': 1})
69+
continue
70+
reps = instruction['reps']
71+
# period is in quantised units:
72+
period = int(round(instruction['step'] / self.clock_resolution))
73+
if reduced_instructions and reduced_instructions[-1]['period'] == period:
74+
reduced_instructions[-1]['reps'] += reps
75+
else:
76+
reduced_instructions.append({'period': period, 'reps': reps})
77+
# The following period and reps indicates a stop instruction:
78+
reduced_instructions.append({'period': 0, 'reps': 0})
79+
if len(reduced_instructions) > self.max_instructions:
80+
raise LabscriptError(
81+
"%s %s has too many instructions. It has %d and can only support %d"
82+
% (
83+
self.description,
84+
self.name,
85+
len(reduced_instructions),
86+
self.max_instructions,
87+
)
88+
)
89+
# Store these instructions to the h5 file:
90+
dtypes = [('period', int), ('reps', int)]
91+
pulse_program = np.zeros(len(reduced_instructions), dtype=dtypes)
92+
for i, instruction in enumerate(reduced_instructions):
93+
pulse_program[i]['period'] = instruction['period']
94+
pulse_program[i]['reps'] = instruction['reps']
95+
group.create_dataset(
96+
'PULSE_PROGRAM', compression=config.compression, data=pulse_program
97+
)
98+
# TODO: is this needed, the PulseBlasters don't save it...
99+
self.set_property(
100+
'is_master_pseudoclock',
101+
self.is_master_pseudoclock,
102+
location='device_properties',
103+
)
104+
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: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
clock_type = 'fast clock'
9+
trigger_delay = 350e-9
10+
wait_delay = 2.5e-6
11+
12+
def __init__(self, path, device):
13+
self.path = path
14+
self.name = device.name
15+
self.device = device
16+
17+
def get_traces(self, add_trace, clock=None):
18+
if clock is not None:
19+
times, clock_value = clock[0], clock[1]
20+
clock_indices = np.where((clock_value[1:] - clock_value[:-1]) == 1)[0] + 1
21+
# If initial clock value is 1, then this counts as a rising edge
22+
# (clock should be 0 before experiment) but this is not picked up
23+
# by the above code. So we insert it!
24+
if clock_value[0] == 1:
25+
clock_indices = np.insert(clock_indices, 0, 0)
26+
clock_ticks = times[clock_indices]
27+
28+
# get the pulse program
29+
with h5py.File(self.path, 'r') as f:
30+
pulse_program = f[f'devices/{self.name}/PULSE_PROGRAM'][:]
31+
32+
time = []
33+
states = []
34+
trigger_index = 0
35+
t = 0 if clock is None else clock_ticks[trigger_index] + self.trigger_delay
36+
trigger_index += 1
37+
38+
clock_factor = self.clock_resolution / 2.0
39+
40+
for row in pulse_program:
41+
if row['period'] == 0:
42+
# special case
43+
if row['reps'] == 1: # WAIT
44+
if clock is not None:
45+
t = clock_ticks[trigger_index] + self.trigger_delay
46+
trigger_index += 1
47+
else:
48+
t += self.wait_delay
49+
else:
50+
for i in range(row['reps']):
51+
for j in range(1, -1, -1):
52+
time.append(t)
53+
states.append(j)
54+
t += row['period'] * clock_factor
55+
56+
clock = (np.array(time), np.array(states))
57+
58+
clocklines_and_triggers = {}
59+
for pseudoclock_name, pseudoclock in self.device.child_list.items():
60+
for clock_line_name, clock_line in pseudoclock.child_list.items():
61+
if clock_line.parent_port == 'internal':
62+
clocklines_and_triggers[clock_line_name] = clock
63+
add_trace(clock_line_name, clock, self.name, clock_line.parent_port)
64+
65+
return clocklines_and_triggers

0 commit comments

Comments
 (0)