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: e3e42216a203
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: d713c62b502e
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Feb 21, 2016

  1. pdq2.mediator: cleanup/style

    jordens committed Feb 21, 2016
    Copy the full SHA
    294eac1 View commit details
  2. Copy the full SHA
    7c246b3 View commit details
  3. Copy the full SHA
    d713c62 View commit details
Showing with 69 additions and 107 deletions.
  1. +28 −43 artiq/devices/pdq2/driver.py
  2. +3 −4 artiq/devices/pdq2/mediator.py
  3. +35 −56 artiq/frontend/pdq2_client.py
  4. +3 −4 artiq/frontend/pdq2_controller.py
71 changes: 28 additions & 43 deletions artiq/devices/pdq2/driver.py
Original file line number Diff line number Diff line change
@@ -23,12 +23,13 @@ class Segment:

def __init__(self):
self.data = b""
self.addr = None

def line(self, typ, duration, data, trigger=False, silence=False,
aux=False, shift=0, jump=False, clear=False, wait=False):
assert len(data) % 2 == 0, data
assert len(data)//2 <= 14
#assert dt*(1 << shift) > 1 + len(data)//2
# assert dt*(1 << shift) > 1 + len(data)//2
header = (
1 + len(data)//2 | (typ << 4) | (trigger << 6) | (silence << 7) |
(aux << 8) | (shift << 9) | (jump << 13) | (clear << 14) |
@@ -92,7 +93,7 @@ def __init__(self):
self.segments = []

def clear(self):
del self.segments[:]
self.segments.clear()

def new_segment(self):
segment = Segment()
@@ -149,10 +150,6 @@ def close(self):
self.dev.close()
del self.dev

def clear_all(self):
for channel in self.channels:
channel.clear()

def write(self, data):
logger.debug("> %r", data)
written = self.dev.write(data)
@@ -172,30 +169,11 @@ def write_mem(self, channel, data, start_addr=0):
data = data.replace(self._escape, self._escape + self._escape)
self.write(data)

def write_channel(self, channel):
self.write_mem(self.channels.index(channel),
channel.serialize())

def write_all(self):
for channel in self.channels:
self.write_mem(self.channels.index(channel),
channel.serialize())

def write_table(self, channel):
# no segment placement
# no segment writing
self.write_mem(channel, self.channels[channel].table())

def write_segment(self, channel, segment):
# no collision check
s = self.channels[channel].segments[segment]
self.write_mem(channel, s.data, s.adr)

def program_frame(self, frame_data):
segments = [c.new_segment() for c in self.channels]
for segment in segments:
segment.line(typ=3, data=b"", trigger=True, duration=10, aux=1)
for i, line in enumerate(frame_data): # segments are concatenated
def flush(self):
self.dev.flush()

def program_segments(self, segments, data):
for i, line in enumerate(data):
dac_divider = line.get("dac_divider", 1)
shift = int(log(dac_divider, 2))
if 2**shift != dac_divider:
@@ -210,19 +188,26 @@ def program_frame(self, frame_data):
getattr(segment, target)(
shift=shift, duration=duration, trigger=trigger,
**target_data)
# append an empty line to stall the memory reader before jumping
# through the frame table (`wait` does not prevent reading
# the next line)
for segment in segments:
segment.line(typ=3, data=b"", trigger=True, duration=1,
jump=True, aux=1)
return segments

def program(self, program):
self.clear_all()
for frame_data in program:
self.program_frame(frame_data)
self.write_all()

def program(self, program, channels=None):
if channels is None:
channels = range(self.num_channels)
chs = [self.channels[i] for i in channels]
for channel in chs:
channel.clear()
for frame in program:
segments = [c.new_segment() for c in chs]
for segment in segments:
segment.line(typ=3, data=b"", trigger=True, duration=1, aux=1)
self.program_segments(segments, frame)
# append an empty line to stall the memory reader before jumping
# through the frame table (`wait` does not prevent reading
# the next line)
for segment in segments:
segment.line(typ=3, data=b"", trigger=True, duration=1, aux=1,
jump=True)
for channel, ch in zip(channels, chs):
self.write_mem(channel, ch.serialize())

def ping(self):
return True
7 changes: 3 additions & 4 deletions artiq/devices/pdq2/mediator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from artiq.language.core import *
from artiq.language.units import *
from artiq.language import *


frame_setup = 20*ns
@@ -63,8 +62,8 @@ def advance(self):
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):
if (self.frame.pdq.current_frame >= 0 and
self.frame.pdq.next_segment != self.segment_number):
raise SegmentSequenceError()
self.frame.advance()

91 changes: 35 additions & 56 deletions artiq/frontend/pdq2_client.py
Original file line number Diff line number Diff line change
@@ -28,25 +28,17 @@ def get_argparser():
parser.add_argument("-u", "--voltages",
default="(1-np.cos(t/t[-1]*2*np.pi))/2",
help="sample voltages (V) [%(default)s]")
parser.add_argument("-a", "--aux", default=False, action="store_true",
help="axiliary digital output [%(default)%s]")
parser.add_argument("-o", "--order", default=3, type=int,
help="interpolation (0: const, 1: lin, 2: quad,"
" 3: cubic) [%(default)s]")
parser.add_argument("-p", "--plot", help="plot to file [%(default)s]")
parser.add_argument("-r", "--reset", default=False,
action="store_true", help="do reset before")
parser.add_argument("-m", "--dcm", default=False, action="store_true",
help="100MHz clock [%(default)s]")
parser.add_argument("-m", "--multiplier", default=False,
action="store_true", help="100MHz clock [%(default)s]")
parser.add_argument("-n", "--disarm", default=False, action="store_true",
help="disarm group [%(default)s]")
parser.add_argument("-e", "--free", default=False, action="store_true",
help="software trigger [%(default)s]")
parser.add_argument("-x", "--demo", default=False, action="store_true",
help="demo mode: pulse and chirp, 1V*ch+0.1V*frame"
" [%(default)s]")
parser.add_argument("-b", "--bit", default=False,
action="store_true", help="do bit test")
verbosity_args(parser)
return parser

@@ -60,57 +52,44 @@ def main():
dev.write(b"\x00\x00") # flush any escape
dev.cmd("RESET", True)
time.sleep(.1)

dev.cmd("DCM", args.multiplier)
freq = 50e6
if args.multiplier:
freq *= 2

times = np.around(eval(args.times, globals(), {})*freq)
voltages = eval(args.voltages, globals(), dict(t=times/freq))

dev.cmd("START", False)
dev.cmd("ARM", False)
dev.cmd("DCM", args.dcm)
freq = 100e6 if args.dcm else 50e6
dev.set_freq(freq)
times = eval(args.times, globals(), {})
voltages = eval(args.voltages, globals(), dict(t=times))
dev.cmd("ARM", True)
dev.cmd("TRIGGER", True)
dev.flush()

if args.demo:
for ch, channel in enumerate(dev.channels):
entry = []
for fr in range(dev.channels[0].num_frames):
vi = .1*fr + ch + voltages
entry.append(channel.segment(times, vi, order=args.order,
end=False, aux=args.aux))
pi = 2*np.pi*(-.5 + .01*fr + .1*ch + 0*voltages)
fi = 10e6*times/times[-1]
channel.segment(2*times, voltages, pi, fi, trigger=False,
silence=True, aux=args.aux)
dev.write_channel(channel, entry)
elif args.bit:
v = [-1, 0, -1]
# for i in range(15):
# v.extend([(1 << i) - 1, 1 << i])
v = np.array(v)*dev.channels[0].max_out/dev.channels[0].max_val
t = np.arange(len(v))
for channel in dev.channels:
s = channel.segment(t, v, order=0, shift=15, stop=False,
trigger=False)
dev.write_channel(channel, [s for i in range(channel.num_frames)])
dt = np.diff(times.astype(np.int))
if args.order:
tck = interpolate.splrep(times, voltages, k=args.order, s=0)
u = interpolate.spalde(times, tck)
else:
c = dev.channels[args.channel]
map = [None] * c.num_frames
map[args.frame] = c.segment(times, voltages, order=args.order,
aux=args.aux)
dev.write_channel(c, map)
u = voltages[:, None]
segment = []
for dti, ui in zip(dt, u):
segment.append({
"duration": int(dti),
"channel_data": [{
"bias": {
"amplitude": [float(uij) for uij in ui]
}
}]
})
program = [[] for i in range(args.frame)]
program.append(segment)
dev.program(program, [args.channel])

dev.cmd("START", True)
dev.cmd("ARM", not args.disarm)
dev.cmd("TRIGGER", args.free)

if args.plot:
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
ax.plot(times, voltages, "xk", label="points")
if args.order > 0:
spline = interpolate.splrep(times, voltages, k=args.order)
ttimes = np.arange(0, times[-1], 1/freq)
vvoltages = interpolate.splev(ttimes, spline)
ax.plot(ttimes, vvoltages, ",b", label="interpolation")
fig.savefig(args.plot)
dev.cmd("ARM", not args.disarm)
dev.cmd("START", True)
dev.flush()


if __name__ == "__main__":
7 changes: 3 additions & 4 deletions artiq/frontend/pdq2_controller.py
Original file line number Diff line number Diff line change
@@ -12,8 +12,7 @@ def get_argparser():
parser = argparse.ArgumentParser(description="PDQ2 controller")
simple_network_args(parser, 3252)
parser.add_argument(
"-d", "--device", default=None,
help="serial port.")
"-d", "--device", default=None, help="serial port.")
parser.add_argument(
"--simulation", action="store_true",
help="Put the driver in simulation mode, even if --device is used.")
@@ -38,8 +37,8 @@ def main():
port = open(args.dump, "wb")
dev = Pdq2(url=args.device, dev=port)
try:
simple_server_loop({"pdq2": dev}, bind_address_from_args(args), args.port,
description="device=" + str(args.device))
simple_server_loop({"pdq2": dev}, bind_address_from_args(args),
args.port, description="device=" + str(args.device))
finally:
dev.close()