forked from M-Labs/artiq
Refactor, introduce experiment class, kernel decorator, parameters and channel objects
This commit is contained in:
parent
7409f095f1
commit
18ef03c545
|
@ -0,0 +1,70 @@
|
|||
import itertools
|
||||
|
||||
class Experiment:
|
||||
def __init__(self, *args, **kwargs):
|
||||
channels = self.channels.split()
|
||||
parameters = self.parameters.split()
|
||||
argnames = channels + parameters
|
||||
undef_args = list(argnames)
|
||||
|
||||
if len(argnames) < len(args):
|
||||
raise TypeError("__init__() takes {} positional arguments but {} were given".format(len(argnames), len(args)))
|
||||
for argname, value in itertools.chain(zip(argnames, args), kwargs.items()):
|
||||
if hasattr(self, argname):
|
||||
raise TypeError("__init__() got multiple values for argument '{}'".format(argname))
|
||||
if argname not in argnames:
|
||||
raise TypeError("__init__() got an unexpected keyword argument: '{}'".format(argname))
|
||||
setattr(self, argname, value)
|
||||
undef_args.remove(argname)
|
||||
if undef_args:
|
||||
raise TypeError("__init__() missing {} argument(s): ".format(len(undef_args),
|
||||
", ".join(["'"+s+"'" for s in undef_args])))
|
||||
|
||||
self.kernel_attr_ro = set(parameters)
|
||||
|
||||
def kernel(arg):
|
||||
if isinstance(arg, str):
|
||||
def real_decorator(function):
|
||||
def run_on_core(exp, *k_args, **k_kwargs):
|
||||
getattr(exp, arg).run(function, exp, *k_args, **k_kwargs)
|
||||
return run_on_core
|
||||
return real_decorator
|
||||
else:
|
||||
def run_on_core(exp, *k_args, **k_kwargs):
|
||||
exp.core.run(arg, exp, *k_args, **k_kwargs)
|
||||
return run_on_core
|
||||
|
||||
class _DummyTimeManager:
|
||||
def _not_implemented(self, *args, **kwargs):
|
||||
raise NotImplementedError("Attempted to interpret kernel without a time manager")
|
||||
|
||||
enter_sequential = _not_implemented
|
||||
exit = _not_implemented
|
||||
take_time = _not_implemented
|
||||
|
||||
_time_manager = _DummyTimeManager()
|
||||
|
||||
def set_time_manager(time_manager):
|
||||
global _time_manager
|
||||
_time_manager = time_manager
|
||||
|
||||
# global namespace for interpreted kernels
|
||||
|
||||
class _Sequential:
|
||||
def __enter__(self):
|
||||
_time_manager.enter_sequential()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
_time_manager.exit()
|
||||
sequential = _Sequential()
|
||||
|
||||
class _Parallel:
|
||||
def __enter__(self):
|
||||
_time_manager.enter_parallel()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
_time_manager.exit()
|
||||
parallel = _Parallel()
|
||||
|
||||
def delay(duration):
|
||||
_time_manager.take_time(duration.amount)
|
|
@ -0,0 +1,46 @@
|
|||
from random import Random
|
||||
|
||||
from artiq.language import units
|
||||
from artiq.sim import time
|
||||
|
||||
class Core:
|
||||
def run(self, function, *args, **kwargs):
|
||||
return function(*args, **kwargs)
|
||||
|
||||
class Input:
|
||||
def __init__(self, name, prng_seed=None, wait_max=20, count_max=100, wait_min=0, count_min=0):
|
||||
self.name = name
|
||||
self.wait_min = wait_min
|
||||
self.wait_max = wait_max
|
||||
self.count_min = count_min
|
||||
self.count_max = count_max
|
||||
self.prng = Random(prng_seed)
|
||||
|
||||
def wait_edge(self):
|
||||
duration = self.prng.randrange(self.wait_min, self.wait_max)*units.ms
|
||||
time.manager.event(("wait_edge", self.name, duration))
|
||||
time.manager.take_time(duration.amount)
|
||||
|
||||
def count_gate(self, duration):
|
||||
result = self.prng.randrange(self.count_min, self.count_max)
|
||||
units.check_unit(duration, units.base_s_unit)
|
||||
time.manager.event(("count_gate", self.name, duration, result))
|
||||
time.manager.take_time(duration.amount)
|
||||
return result
|
||||
|
||||
class WaveOutput:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def pulse(self, frequency, duration):
|
||||
units.check_unit(frequency, units.base_Hz_unit)
|
||||
units.check_unit(duration, units.base_s_unit)
|
||||
time.manager.event(("pulse", self.name, frequency, duration))
|
||||
time.manager.take_time(duration.amount)
|
||||
|
||||
class VoltageOutput:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def set(self, value):
|
||||
time.manager.event(("set_voltage", self.name, value))
|
|
@ -1,7 +1,6 @@
|
|||
from random import Random
|
||||
from operator import itemgetter
|
||||
|
||||
from artiq import units
|
||||
from artiq.language import units, experiment
|
||||
|
||||
class SequentialTimeContext:
|
||||
def __init__(self, current_time):
|
||||
|
@ -21,7 +20,7 @@ class ParallelTimeContext:
|
|||
if amount > self.block_duration:
|
||||
self.block_duration = amount
|
||||
|
||||
class TimeManager:
|
||||
class Manager:
|
||||
def __init__(self):
|
||||
self.stack = [SequentialTimeContext(0)]
|
||||
self.timeline = []
|
||||
|
@ -38,8 +37,8 @@ class TimeManager:
|
|||
old_context = self.stack.pop()
|
||||
self.take_time(old_context.block_duration)
|
||||
|
||||
def take_time(self, amount):
|
||||
self.stack[-1].take_time(amount)
|
||||
def take_time(self, duration):
|
||||
self.stack[-1].take_time(duration)
|
||||
|
||||
def event(self, description):
|
||||
self.timeline.append((self.stack[-1].current_time, description))
|
||||
|
@ -57,48 +56,5 @@ class TimeManager:
|
|||
prev_time = time
|
||||
return r
|
||||
|
||||
# global namespace for interpreted kernels
|
||||
|
||||
time_manager = TimeManager()
|
||||
prng = Random(42)
|
||||
|
||||
class _Sequential:
|
||||
def __enter__(self):
|
||||
time_manager.enter_sequential()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
time_manager.exit()
|
||||
sequential = _Sequential()
|
||||
|
||||
class _Parallel:
|
||||
def __enter__(self):
|
||||
time_manager.enter_parallel()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
time_manager.exit()
|
||||
parallel = _Parallel()
|
||||
|
||||
def delay(duration):
|
||||
units.check_unit(duration, units.base_s_unit)
|
||||
time_manager.take_time(duration.amount)
|
||||
|
||||
def wait_edge(input):
|
||||
duration = prng.randrange(17)*units.ms
|
||||
time_manager.event(("wait_edge", input, duration))
|
||||
time_manager.take_time(duration.amount)
|
||||
|
||||
def pulse(output, frequency, duration):
|
||||
units.check_unit(frequency, units.base_Hz_unit)
|
||||
units.check_unit(duration, units.base_s_unit)
|
||||
time_manager.event(("pulse", output, frequency, duration))
|
||||
time_manager.take_time(duration.amount)
|
||||
|
||||
def count_gate(input, duration):
|
||||
result = prng.randrange(100)
|
||||
units.check_unit(duration, units.base_s_unit)
|
||||
time_manager.event(("count_gate", input, duration, result))
|
||||
time_manager.take_time(duration.amount)
|
||||
return result
|
||||
|
||||
def set_dac_voltage(output):
|
||||
time_manager.event(("set_dac_voltage", output))
|
||||
manager = Manager()
|
||||
experiment.set_time_manager(manager)
|
|
@ -1,30 +1,51 @@
|
|||
from artiq.sim import *
|
||||
from artiq.units import *
|
||||
from artiq.language.units import *
|
||||
from artiq.language.experiment import *
|
||||
|
||||
def al_clock_probe(spectroscopy_freq, A1, A2):
|
||||
state_0_count = 0
|
||||
for count in range(100):
|
||||
wait_edge("mains_sync")
|
||||
delay(10*us)
|
||||
pulse("laser_cooling", 100*MHz, 100*us)
|
||||
delay(5*us)
|
||||
with parallel:
|
||||
pulse("spectroscopy", spectroscopy_freq, 100*us)
|
||||
with sequential:
|
||||
delay(50*us)
|
||||
set_dac_voltage("spectroscopy_b")
|
||||
delay(5*us)
|
||||
while True:
|
||||
class AluminumSpectroscopy(Experiment):
|
||||
channels = "core mains_sync laser_cooling spectroscopy spectroscopy_b state_detection pmt"
|
||||
parameters = "spectroscopy_freq photon_limit_low photon_limit_high"
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
state_0_count = 0
|
||||
for count in range(100):
|
||||
self.mains_sync.wait_edge()
|
||||
delay(10*us)
|
||||
self.laser_cooling.pulse(100*MHz, 100*us)
|
||||
delay(5*us)
|
||||
with parallel:
|
||||
pulse("state_detection", 100*MHz, 10*us)
|
||||
photon_count = count_gate("pmt", 10*us)
|
||||
if photon_count < A1 or photon_count > A2:
|
||||
break
|
||||
if photon_count < A1:
|
||||
state_0_count += 1
|
||||
return state_0_count
|
||||
self.spectroscopy.pulse(self.spectroscopy_freq, 100*us)
|
||||
with sequential:
|
||||
delay(50*us)
|
||||
self.spectroscopy_b.set(200)
|
||||
delay(5*us)
|
||||
while True:
|
||||
delay(5*us)
|
||||
with parallel:
|
||||
self.state_detection.pulse(100*MHz, 10*us)
|
||||
photon_count = self.pmt.count_gate(10*us)
|
||||
if photon_count < self.photon_limit_low or photon_count > self.photon_limit_high:
|
||||
break
|
||||
if photon_count < self.photon_limit_low:
|
||||
state_0_count += 1
|
||||
return state_0_count
|
||||
|
||||
if __name__ == "__main__":
|
||||
al_clock_probe(30*MHz, 3, 30)
|
||||
print(time_manager.format_timeline())
|
||||
from artiq.sim import devices as sd
|
||||
from artiq.sim import time
|
||||
|
||||
exp = AluminumSpectroscopy(
|
||||
core=sd.Core(),
|
||||
mains_sync=sd.Input("mains_sync"),
|
||||
laser_cooling=sd.WaveOutput("laser_cooling"),
|
||||
spectroscopy=sd.WaveOutput("spectroscopy"),
|
||||
spectroscopy_b=sd.VoltageOutput("spectroscopy_b"),
|
||||
state_detection=sd.WaveOutput("state_detection"),
|
||||
pmt=sd.Input("pmt"),
|
||||
|
||||
spectroscopy_freq=432*MHz,
|
||||
photon_limit_low=10,
|
||||
photon_limit_high=15
|
||||
)
|
||||
exp.run()
|
||||
print(time.manager.format_timeline())
|
||||
|
|
Loading…
Reference in New Issue