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: bc81be13453e
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: 61bcfb600057
Choose a head ref
  • 6 commits
  • 6 files changed
  • 1 contributor

Commits on Feb 22, 2016

  1. Copy the full SHA
    1b410ab View commit details
  2. wavesynth: duration sign

    jordens committed Feb 22, 2016
    Copy the full SHA
    d7f5904 View commit details
  3. Copy the full SHA
    b327c50 View commit details
  4. Copy the full SHA
    269e9c6 View commit details
  5. Copy the full SHA
    94584bb View commit details
  6. Copy the full SHA
    61bcfb6 View commit details
19 changes: 17 additions & 2 deletions artiq/devices/pdq2/driver.py
Original file line number Diff line number Diff line change
@@ -128,6 +128,7 @@ class Pdq2:
PDQ DAC (a.k.a. QC_Waveform)
"""
num_dacs = 3
freq = 50e6

_escape = b"\xa5"
_commands = "RESET TRIGGER ARM DCM START".split()
@@ -146,6 +147,12 @@ def get_num_boards(self):
def get_num_channels(self):
return self.num_channels

def get_freq(self):
return self.freq

def set_freq(self, freq):
self.freq = float(freq)

def close(self):
self.dev.close()
del self.dev
@@ -172,6 +179,16 @@ def write_mem(self, channel, data, start_addr=0):
def flush(self):
self.dev.flush()

def park(self):
self.cmd("START", False)
self.cmd("TRIGGER", True)
self.flush()

def unpark(self):
self.cmd("TRIGGER", False)
self.cmd("START", True)
self.flush()

def program_segments(self, segments, data):
for i, line in enumerate(data):
dac_divider = line.get("dac_divider", 1)
@@ -197,8 +214,6 @@ def program(self, program, channels=None):
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
29 changes: 18 additions & 11 deletions artiq/devices/pdq2/mediator.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,7 @@
frame_setup = 20*ns
trigger_duration = 50*ns
sample_period = 10*ns
delay_margin_factor = 1.0001
channels_per_pdq2 = 9
delay_margin_factor = 1 + 1e-4


class FrameActiveError(Exception):
@@ -38,6 +37,7 @@ def __init__(self, frame, segment_number):
self.segment_number = segment_number

self.lines = []
self.duration = 0*s

# for @kernel
self.core = frame.pdq.core
@@ -48,12 +48,10 @@ def add_line(self, duration, channel_data, dac_divider=1):
if self.frame.pdq.armed:
raise ArmError()
self.lines.append((dac_divider, duration, channel_data))
self.duration += duration*sample_period/dac_divider

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

@kernel
def advance(self):
@@ -96,7 +94,7 @@ def create_segment(self, name=None):

def _arm(self):
self.segment_delays = [
seconds_to_mu(s.get_duration()*delay_margin_factor, self.core)
seconds_to_mu(s.duration*delay_margin_factor, self.core)
for s in self.segments]

def _invalidate(self):
@@ -172,6 +170,11 @@ def disarm(self):
frame._invalidate()
self.frames = []
self.armed = False
for dev in self.pdq2s:
dev.park()

def get_program(self):
return [f._get_program() for f in self.frames]

def arm(self):
if self.armed:
@@ -180,22 +183,26 @@ def arm(self):
frame._arm()
self.armed = True

full_program = [f._get_program() for f in self.frames]
for n, pdq2 in enumerate(self.pdq2s):
full_program = self.get_program()
n = 0
for pdq2 in self.pdq2s:
dn = pdq2.get_num_channels()
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],
"channel_data": full_line["channel_data"][n:n + dn],
"trigger": full_line["trigger"],
}
frame_program.append(line)
program.append(frame_program)
pdq2.program(program)
n += dn
for pdq2 in self.pdq2s:
pdq2.unpark()

def create_frame(self):
if self.armed:
29 changes: 3 additions & 26 deletions artiq/frontend/pdq2_client.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
# Copyright (C) 2012-2015 Robert Jordens <jordens@gmail.com>

import argparse
import time

from scipy import interpolate
import numpy as np
@@ -31,12 +30,6 @@ def get_argparser():
parser.add_argument("-o", "--order", default=3, type=int,
help="interpolation (0: const, 1: lin, 2: quad,"
" 3: cubic) [%(default)s]")
parser.add_argument("-r", "--reset", default=False,
action="store_true", help="do reset before")
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]")
verbosity_args(parser)
@@ -48,24 +41,10 @@ def main():
init_logger(args)
dev = Client(args.server, args.port, "pdq2")

if args.reset:
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

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

dev.cmd("START", False)
dev.cmd("ARM", True)
dev.cmd("TRIGGER", True)
dev.flush()

dt = np.diff(times.astype(np.int))
if args.order:
tck = interpolate.splrep(times, voltages, k=args.order, s=0)
@@ -84,12 +63,10 @@ def main():
})
program = [[] for i in range(args.frame)]
program.append(segment)
dev.park()
dev.program(program, [args.channel])

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


if __name__ == "__main__":
27 changes: 18 additions & 9 deletions artiq/frontend/pdq2_controller.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import argparse
import sys
import time

from artiq.devices.pdq2.driver import Pdq2
from artiq.protocols.pc_rpc import simple_server_loop
@@ -11,14 +12,15 @@
def get_argparser():
parser = argparse.ArgumentParser(description="PDQ2 controller")
simple_network_args(parser, 3252)
parser.add_argument(
"-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.")
parser.add_argument(
"--dump", default="pdq2_dump.bin",
help="file to dump pdq2 data into, for later simulation")
parser.add_argument("-d", "--device", default=None, help="serial port")
parser.add_argument("--simulation", action="store_true",
help="do not open any device but dump data")
parser.add_argument("--dump", default="pdq2_dump.bin",
help="file to dump simulation data into")
parser.add_argument("-r", "--reset", default=False,
action="store_true", help="reset device [%(default)s]")
parser.add_argument("-b", "--boards", default=3, type=int,
help="number of boards [%(default)s]")
verbosity_args(parser)
return parser

@@ -35,8 +37,15 @@ def main():

if args.simulation:
port = open(args.dump, "wb")
dev = Pdq2(url=args.device, dev=port)
dev = Pdq2(url=args.device, dev=port, num_boards=args.boards)
try:
if args.reset:
dev.write(b"\x00\x00") # flush any escape
dev.cmd("RESET", True)
dev.flush()
time.sleep(.1)
dev.cmd("ARM", True)
dev.park()
simple_server_loop({"pdq2": dev}, bind_address_from_args(args),
args.port, description="device=" + str(args.device))
finally:
12 changes: 6 additions & 6 deletions artiq/wavesynth/coefficients.py
Original file line number Diff line number Diff line change
@@ -139,7 +139,7 @@ def get_segment(self, start, stop, scale, *, cutoff=1e-12,
coefficients.shape[0])[:, None, None]
if cutoff:
coefficients[np.fabs(coefficients) < cutoff] = 0
return build_segment(durations, coefficients, target=target,
return build_segment(np.fabs(durations), coefficients, target=target,
variable=variable)

def extend_segment(self, segment, *args, **kwargs):
@@ -179,7 +179,7 @@ def crop_x(self, start, stop):
x = self.x[ia:ib]
return np.r_[start, x, stop]

def scale_x(self, x, scale, min_duration=10, min_length=20):
def scale_x(self, x, scale, min_duration=1, min_length=20):
"""Enforce, round, and scale x to device-dependent values.
Due to minimum duration and/or minimum segment length constraints
@@ -202,11 +202,11 @@ def scale_x(self, x, scale, min_duration=10, min_length=20):
dt = np.diff(t.astype(np.int))

valid = np.absolute(dt) >= min_duration
dt = dt[valid]
t = t[np.r_[True, valid]]
if dt.shape[0] == 1:
if not np.any(valid):
valid[0] = True
dt[0] = max(dt[0], min_length)
x_sample = t[:-1]*scale
dt = dt[valid]
x_sample = t[:-1][valid]*scale
return x_sample, dt

def __call__(self, x):
26 changes: 13 additions & 13 deletions examples/master/repository/coredevice_examples/transport.py
Original file line number Diff line number Diff line change
@@ -6,13 +6,6 @@
from artiq.wavesynth.coefficients import SplineSource


transport = SplineSource(
x=np.linspace(0, 10, 101), # waveform time
y=np.random.rand(4*3*3, 101)*1e-6, # waveform data,
# 4 devices, 3 board each, 3 dacs each
)


class Transport(EnvExperiment):
"""Transport"""

@@ -23,19 +16,26 @@ def build(self):
self.setattr_device("electrodes")

self.setattr_argument("wait_at_stop", NumberValue(100*us))
self.setattr_argument("speed", NumberValue(1.5))
self.setattr_argument("speed", NumberValue(1/(10*us)))
self.setattr_argument("repeats", NumberValue(100))
self.setattr_argument("bins", NumberValue(100))

t = np.linspace(0, 10, 101) # waveform time
u = 1 - np.cos(np.pi*t/t[-1])
# 4 devices, 3 board each, 3 dacs each
u = np.arange(4*3*3)[:, None]*.1 + u
self.data = SplineSource(x=t, y=u)

def calc_waveforms(self, stop):
scale = self.speed/(50*MHz)
self.electrodes.disarm()
self.tf = self.electrodes.create_frame()
to_stop = self.tf.create_segment("to_stop")
from_stop = self.tf.create_segment("from_stop")
transport.extend_segment(to_stop, 0, stop, scale=self.speed)
self.data.extend_segment(self.tf.create_segment("to_stop"),
0, stop, scale=scale)
# append the reverse transport (from stop to 0)
# both durations are the same in this case
transport.extend_segment(from_stop, 0, stop, scale=self.speed)
self.data.extend_segment(self.tf.create_segment("from_stop"),
stop, 0, scale=scale)
# distributes frames to the sub-devices in CompoundPDQ2
# and uploads them
self.electrodes.arm()
@@ -91,7 +91,7 @@ def scan(self, stops):

def run(self):
# scan transport endpoint
stops = range(10, len(transport.x), 10)
stops = np.linspace(0, 10, 10)
self.scan(stops)