forked from M-Labs/artiq
Basic simulation of Al spectroscopy
This commit is contained in:
commit
c3c83f86b6
|
@ -0,0 +1,104 @@
|
||||||
|
from random import Random
|
||||||
|
from operator import itemgetter
|
||||||
|
|
||||||
|
from artiq import units
|
||||||
|
|
||||||
|
class SequentialTimeContext:
|
||||||
|
def __init__(self, current_time):
|
||||||
|
self.current_time = current_time
|
||||||
|
self.block_duration = 0
|
||||||
|
|
||||||
|
def take_time(self, amount):
|
||||||
|
self.current_time += amount
|
||||||
|
self.block_duration += amount
|
||||||
|
|
||||||
|
class ParallelTimeContext:
|
||||||
|
def __init__(self, current_time):
|
||||||
|
self.current_time = current_time
|
||||||
|
self.block_duration = 0
|
||||||
|
|
||||||
|
def take_time(self, amount):
|
||||||
|
if amount > self.block_duration:
|
||||||
|
self.block_duration = amount
|
||||||
|
|
||||||
|
class TimeManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.stack = [SequentialTimeContext(0)]
|
||||||
|
self.timeline = []
|
||||||
|
|
||||||
|
def enter_sequential(self):
|
||||||
|
new_context = SequentialTimeContext(self.stack[-1].current_time)
|
||||||
|
self.stack.append(new_context)
|
||||||
|
|
||||||
|
def enter_parallel(self):
|
||||||
|
new_context = ParallelTimeContext(self.stack[-1].current_time)
|
||||||
|
self.stack.append(new_context)
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
old_context = self.stack.pop()
|
||||||
|
self.take_time(old_context.block_duration)
|
||||||
|
|
||||||
|
def take_time(self, amount):
|
||||||
|
self.stack[-1].take_time(amount)
|
||||||
|
|
||||||
|
def event(self, description):
|
||||||
|
self.timeline.append((self.stack[-1].current_time, description))
|
||||||
|
|
||||||
|
def format_timeline(self):
|
||||||
|
r = ""
|
||||||
|
prev_time = 0
|
||||||
|
for time, description in sorted(self.timeline, key=itemgetter(0)):
|
||||||
|
t = units.Quantity(time, units.base_s_unit)
|
||||||
|
dt = units.Quantity(time-prev_time, units.base_s_unit)
|
||||||
|
r += "@{:10} (+{:10}) ".format(str(t), str(dt))
|
||||||
|
for item in description:
|
||||||
|
r += "{:16}".format(str(item))
|
||||||
|
r += "\n"
|
||||||
|
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))
|
|
@ -0,0 +1,52 @@
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
_prefixes_str = "pnum_kM"
|
||||||
|
|
||||||
|
Unit = namedtuple("Unit", "base_prefix name")
|
||||||
|
|
||||||
|
class DimensionError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Quantity:
|
||||||
|
def __init__(self, amount, unit):
|
||||||
|
self.amount = int(amount)
|
||||||
|
self.unit = unit
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
r_amount = self.amount
|
||||||
|
r_prefix = self.unit.base_prefix
|
||||||
|
if r_amount:
|
||||||
|
while not r_amount % 1000 and r_prefix < len(_prefixes_str):
|
||||||
|
r_amount //= 1000
|
||||||
|
r_prefix += 1
|
||||||
|
return str(r_amount) + " " + _prefixes_str[r_prefix] + self.unit.name
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if self.unit != other.unit:
|
||||||
|
raise DimensionError
|
||||||
|
return Quantity(self.amount + other.amount, self.unit)
|
||||||
|
__radd__ = __add__
|
||||||
|
|
||||||
|
def __rmul__(self, other):
|
||||||
|
if isinstance(other, Quantity):
|
||||||
|
return NotImplemented
|
||||||
|
return Quantity(self.amount*other, self.unit)
|
||||||
|
|
||||||
|
def check_unit(value, unit):
|
||||||
|
if not isinstance(value, Quantity) or value.unit != unit:
|
||||||
|
raise DimensionError
|
||||||
|
|
||||||
|
def _register_unit(base_prefix, name, prefixes):
|
||||||
|
base_prefix_exp = _prefixes_str.index(base_prefix)
|
||||||
|
unit = Unit(base_prefix_exp, name)
|
||||||
|
globals()["base_"+name+"_unit"] = unit
|
||||||
|
for prefix in prefixes:
|
||||||
|
prefix_exp = _prefixes_str.index(prefix)
|
||||||
|
exp_d = prefix_exp - base_prefix_exp
|
||||||
|
assert(exp_d >= 0)
|
||||||
|
quantity = Quantity(1000**exp_d, unit)
|
||||||
|
full_name = prefix + name if prefix != "_" else name
|
||||||
|
globals()[full_name] = quantity
|
||||||
|
|
||||||
|
_register_unit("p", "s", "pnum_")
|
||||||
|
_register_unit("_", "Hz", "_kM")
|
|
@ -0,0 +1,29 @@
|
||||||
|
from artiq.sim import *
|
||||||
|
from artiq.units import *
|
||||||
|
|
||||||
|
def al_clock_probe(spectroscopy_freq, A1, A2):
|
||||||
|
state_0_count = 0
|
||||||
|
for count in range(100):
|
||||||
|
wait_edge("mains_sync")
|
||||||
|
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:
|
||||||
|
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
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
al_clock_probe(30*MHz, 3, 30)
|
||||||
|
print(time_manager.format_timeline())
|
Loading…
Reference in New Issue