Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1b7f71bda9f2
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b45ad9d1a33f
Choose a head ref
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Mar 22, 2015

  1. Copy the full SHA
    c18efa1 View commit details
  2. pdq2/mediator: rewrite, adapt to new PDQ RPC format, support anonymou…

    …s segments, support uploading to controllers
    sbourdeauducq committed Mar 22, 2015
    Copy the full SHA
    0b17408 View commit details
  3. Copy the full SHA
    b45ad9d View commit details
Showing with 165 additions and 117 deletions.
  1. +149 −80 artiq/devices/pdq2/mediator.py
  2. +9 −9 artiq/wavesynth/compute_samples.py
  3. +7 −28 examples/master/repository/transport.py
229 changes: 149 additions & 80 deletions artiq/devices/pdq2/mediator.py
Original file line number Diff line number Diff line change
@@ -6,109 +6,155 @@

frame_setup = 20*ns
trigger_duration = 50*ns
frame_wait = 20*ns
sample_period = 10*us # FIXME: check this
sample_period = 10*ns
delay_margin_factor = 1.0001
channels_per_pdq2 = 9


class FrameActiveError(Exception):
"""Raised when a frame is active and playback of a segment from another
frame is attempted."""
pass


class SegmentSequenceError(Exception):
"""Raised when attempting to play back a named segment which is not the
next in the sequence."""
pass


class FrameActiveError(Exception):
class InvalidatedError(Exception):
"""Raised when attemting to use a frame or segment that has been
invalidated (due to disarming the PDQ)."""
pass


class FrameCloseError(Exception):
class ArmError(Exception):
"""Raised when attempting to arm an already armed PDQ, to modify the
program of an armed PDQ, or to play a segment on a disarmed PDQ."""
pass


class _Segment:
def __init__(self, frame, sn, duration, host_data):
self.core = frame.core
def __init__(self, frame, segment_number):
self.frame = frame
self.sn = sn
self.duration = duration
self.host_data = host_data
self.segment_number = segment_number

self.lines = []

# for @kernel
self.core = frame.pdq.core

def add_line(self, duration, channel_data, dac_divider=1):
if self.frame.invalidated:
raise InvalidatedError
if self.frame.pdq.armed:
raise ArmError
self.lines.append((dac_divider, duration, channel_data))

def get_duration(self):
r = 0*s
for dac_divider, duration, _ in self.lines:
r += duration*sample_period/dac_divider
return r

@kernel
def advance(self):
if self.frame.pdq.current_frame != self.frame.fn:
raise FrameActiveError
if self.frame.pdq.next_sn != self.sn:
if self.frame.invalidated:
raise InvalidatedError
if not self.frame.pdq.armed:
raise ArmError
# If a frame is currently being played, check that we are next.
if (self.frame.pdq.current_frame >= 0
and self.frame.pdq.next_segment != self.segment_number):
raise SegmentSequenceError
self.frame.pdq.next_sn += 1

t = time_to_cycles(now())
self.frame.pdq.trigger.on(t)
self.frame.pdq.trigger.off(t + time_to_cycles(trigger_duration))
delay(self.duration)
self.frame.advance()


class _Frame:
def __init__(self, core):
self.core = core
def __init__(self, pdq, frame_number):
self.pdq = pdq
self.frame_number = frame_number
self.segments = []
self.segment_count = 0
self.closed = False

def append(self, t, u, trigger=False, name=None):
if self.closed:
raise FrameCloseError
sn = self.segment_count
duration = (t[-1] - t[0])*sample_period
segment = _Segment(self, sn, duration, (t, u, trigger))
if name is None:
# TODO
raise NotImplementedError("Anonymous segments are not supported yet")
else:

self.invalidated = False

# for @kernel
self.core = self.pdq.core

def create_segment(self, name=None):
if self.invalidated:
raise InvalidatedError
if self.pdq.armed:
raise ArmError
segment = _Segment(self, self.segment_count)
if name is not None:
if hasattr(self, name):
raise NameError("Segment name already exists")
setattr(self, name, segment)
self.segments.append(segment)
self.segment_count += 1
return segment

def close(self):
if self.closed:
raise FrameCloseError
self.closed = True
def _arm(self):
self.segment_delays = [
time_to_cycles(s.get_duration()*delay_margin_factor, self.core)
for s in self.segments]

def _invalidate(self):
self.invalidated = True

def _get_program(self):
r = []
for segment in self.segments:
segment_program = [
{
"dac_divider": dac_divider,
"duration": duration,
"channel_data": channel_data,
"wait_trigger": False,
"jump": False
} for dac_divider, duration, channel_data in segment.lines]
segment_program[-1]["wait_trigger"] = True
r += segment_program
r[-1]["wait_trigger"] = False
r[-1]["jump"] = True
return r

@kernel
def begin(self):
def advance(self):
if self.invalidated:
raise InvalidatedError
if not self.pdq.armed:
raise ArmError

t = time_to_cycles(now()) - time_to_cycles(trigger_duration/2)

if self.pdq.current_frame >= 0:
raise FrameActiveError
self.pdq.current_frame = self.fn
self.pdq.next_sn = 0

t = (time_to_cycles(now())
- time_to_cycles(frame_setup + trigger_duration + frame_wait))
self.pdq.frame0.set_value(t, self.fn & 1)
self.pdq.frame1.set_value(t, (self.fn & 2) >> 1)
self.pdq.frame2.set_value(t, (self.fn & 4) >> 2)
t += time_to_cycles(frame_setup)
# PDQ is in the middle of a frame. Check it is us.
if self.frame.pdq.current_frame != self.frame_number:
raise FrameActiveError
else:
# PDQ is in the jump table - set the selection signals
# to play our first segment.
self.pdq.current_frame = self.frame_number
self.pdq.next_segment = 0
t2 = t - time_to_cycles(frame_setup)
self.pdq.frame0.set_value(t2, self.frame_number & 1)
self.pdq.frame1.set_value(t2, (self.frame_number & 2) >> 1)
self.pdq.frame2.set_value(t2, (self.frame_number & 4) >> 2)

self.pdq.trigger.on(t)
self.pdq.trigger.off(t + time_to_cycles(trigger_duration))

@kernel
def advance(self):
# TODO
raise NotImplementedError

@kernel
def finish(self):
if self.pdq.current_frame != self.fn:
raise FrameActiveError
if self.pdq.next_sn != self.segment_count:
raise FrameActiveError
self.pdq.current_frame = -1
self.pdq.next_sn = -1

def _prepare(self, pdq, fn):
if not self.closed:
raise FrameCloseError
self.pdq = pdq
self.fn = fn
delay(cycles_to_time(self.segment_delays[self.pdq.next_segment]))
self.pdq.next_segment += 1

def _invalidate(self):
del self.pdq
del self.fn
# test for end of frame
if self.pdq.next_segment == self.segment_count:
self.pdq.current_frame = -1
self.pdq.next_segment = -1


class CompoundPDQ2(AutoDB):
@@ -131,19 +177,42 @@ def build(self):

self.frames = []
self.current_frame = -1
self.next_sn = -1

def create_frame(self):
return _Frame(self.core)
self.next_segment = -1
self.armed = False

def prepare(self, *frames):
# prevent previous frames and their segments from
# being (incorrectly) used again
def disarm(self):
for frame in self.frames:
frame._invalidate()
self.frames = []
self.armed = False

self.frames = list(frames)
for fn, frame in enumerate(frames):
frame._prepare(self, fn)
def arm(self):
if self.armed:
raise ArmError
for frame in self.frames:
frame._arm()

full_program = [f._get_program() for f in self.frames]
for n, pdq2 in enumerate(self.pdq2s):
program = []
for full_frame_program in full_program:
frame_program = []
for full_line in full_frame_program:
line = {
"dac_divider": full_line["dac_divider"],
"duration": full_line["duration"],
"channel_data": full_line["channel_data"]
[n*channels_per_pdq2:(n+1)*channels_per_pdq2],
"wait_trigger": full_line["wait_trigger"],
"jump": full_line["jump"]
}
frame_program.append(line)
program.append(frame_program)
pdq2.program(program)

# TODO: upload to PDQ2 devices
def create_frame(self):
if self.armed:
raise ArmError
r = _Frame(self, len(self.frames))
self.frames.append(r)
return r
18 changes: 9 additions & 9 deletions artiq/wavesynth/compute_samples.py
Original file line number Diff line number Diff line change
@@ -110,9 +110,9 @@ def trigger(self, selection=None):
def main():
program = [
[
# segment 0
# frame 0
{
# segment 0, line 0
# frame 0, segment 0, line 0
"dac_divider": 1,
"duration": 100,
"channel_data": [
@@ -127,7 +127,7 @@ def main():
"jump": False
},
{
# segment 1, line 1
# frame 0, segment 0, line 1
"dac_divider": 1,
"duration": 100,
"channel_data": [
@@ -143,9 +143,9 @@ def main():
},
],
[
# segment 1
# frame 1
{
# segment 1, line 0
# frame 1, segment 0, line 0
"dac_divider": 1,
"duration": 100,
"channel_data": [
@@ -160,7 +160,7 @@ def main():
"jump": False
},
{
# segment 1, line 1
# frame 1, segment 0, line 1
"dac_divider": 1,
"duration": 100,
"channel_data": [
@@ -176,9 +176,9 @@ def main():
}
],
[
# segment 2
# frame 2
{
# segment 2, line 0
# frame 2, segment 0, line 0
"dac_divider": 1,
"duration": 84,
"channel_data": [
@@ -193,7 +193,7 @@ def main():
"jump": False
},
{
# segment 2, line 1
# frame 2, segment 1, line 0
"dac_divider": 1,
"duration": 116,
"channel_data": [
Loading