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: c8fba45db554
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: 07a58dc0da63
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Jun 21, 2015

  1. Copy the full SHA
    e94e7c6 View commit details
  2. wavesynth: cleanup, refactor

    jordens committed Jun 21, 2015
    Copy the full SHA
    07a58dc View commit details
Showing with 30 additions and 35 deletions.
  1. +4 −4 artiq/test/coefficients.py
  2. +25 −30 artiq/wavesynth/coefficients.py
  3. +1 −1 examples/master/ddb.pyon
8 changes: 4 additions & 4 deletions artiq/test/coefficients.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ def setUp(self):
self.s = coefficients.SplineSource(self.x, self.y, order=4)

def test_get_segment(self):
return list(self.s.get_segment_data(1.5, 3.2, 1/100.))
return list(self.s.get_segment_data(start=1.5, stop=3.2, scale=.01))

def test_synth(self):
d = self.test_get_segment()
@@ -32,7 +32,7 @@ def test_run(self):

@unittest.skip("manual/visual test")
def test_plot(self):
import cairoplot
import matplotlib.pyplot as plt
y = self.test_run()
x = list(range(len(y)))
cairoplot.scatter_plot("plot.png", [x, y])
plt.step(np.arange(len(y)), y)
plt.show()
55 changes: 25 additions & 30 deletions artiq/wavesynth/coefficients.py
Original file line number Diff line number Diff line change
@@ -5,11 +5,19 @@

class UnivariateMultiSpline:
"""Multidimensional wrapper around `scipy.interpolate.sp*` functions.
`scipy.inteprolate.splprep` unfortunately does only up to 12 dimsions.
`scipy.inteprolate.splprep` is limited to 12 dimensions.
"""
def __init__(self, x, y, order=4):
def __init__(self, x, y, *, x0=None, order=4, **kwargs):
self.order = order
self.s = [splrep(x, yi, k=order - 1) for yi in y]
self.x = x
self.s = []
for i, yi in enumerate(y):
if x0 is not None:
yi = self.upsample_knots(x0[i], yi, x)
self.s.append(splrep(x, yi, k=order - 1, **kwargs))

def upsample_knots(self, x0, y0, x):
return splev(x, splrep(x0, y0, k=self.order - 1))

def lev(self, x, *a, **k):
return np.array([splev(x, si) for si in self.s])
@@ -30,20 +38,6 @@ def __call__(self, x, use_alde=True):
return np.array([self.lev(x, der=i) for i in range(self.order)])


class UnivariateMultiSparseSpline(UnivariateMultiSpline):
def __init__(self, d, x0=None, order=4):
self.order = order
self.n = sorted(set(n for x, n, y in d))
self.s = []
for n in self.n:
x, y = np.array([(x, y) for x, ni, y in d if n == ni]).T
if x0 is not None:
y0 = splev(x0, splrep(x, y, k=order - 1))
x, y = x0, y0
s = splrep(x, y, k=order - 1)
self.s.append(s)


def pad_const(x, n, axis=0):
"""Prefix and postfix the array `x` by `n` repetitions of the first and
last value along `axis`.
@@ -58,28 +52,28 @@ def pad_const(x, n, axis=0):


def build_segment(durations, coefficients, target="bias",
variable="amplitude"):
variable="amplitude", compress=True):
"""Build a wavesynth-style segment from homogeneous duration and
coefficient data.
:param durations: 1D sequence of line durations.
:param coefficients: 3D array with shape `(n, m, len(x))`,
:param coefficients: 3D array with shape `(n, m, len(durations))`,
with `n` being the interpolation order + 1 and `m` the number of
channels.
:param target: The target component of the channel to affect.
:param variable: The variable within the target component.
:param compress: If `True`, skip zero high order coefficients.
"""
for dxi, yi in zip(durations, coefficients.transpose()):
d = {"duration": int(dxi)}
d["channel_data"] = cd = []
cd = []
for yij in yi:
cdj = []
for yijk in reversed(yij):
if cdj or abs(yijk):
if cdj or abs(yijk) or not compress:
cdj.append(float(yijk))
cdj.reverse()
cd.append({target: {variable: cdj}})
yield d
yield {"duration": int(dxi), "channel_data": cd}


class CoefficientSource:
@@ -125,7 +119,7 @@ def __call__(self, x, **kwargs):
with `n` being the number of channels."""
raise NotImplementedError

def get_segment_data(self, start, stop, scale, cutoff=1e-12,
def get_segment_data(self, start, stop, scale, *, cutoff=1e-12,
target="bias", variable="amplitude"):
"""Build wavesynth segment data.
@@ -154,7 +148,7 @@ def extend_segment(self, segment, trigger=True, *args, **kwargs):
"""
for i, line in enumerate(self.get_segment_data(*args, **kwargs)):
if i == 0:
line["trigger"] = True
line["trigger"] = trigger
segment.add_line(**line)


@@ -176,7 +170,7 @@ def __init__(self, x, y, order=4, pad_dx=1.):
self.y = pad_const(self.y, order, axis=1)

assert self.y.shape[1] == self.x.shape[0]
self.spline = UnivariateMultiSpline(self.x, self.y, order)
self.spline = UnivariateMultiSpline(self.x, self.y, order=order)

def crop_x(self, start, stop):
ia, ib = np.searchsorted(self.x, (start, stop))
@@ -187,7 +181,8 @@ def crop_x(self, start, stop):
return np.r_[start, x, stop]

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
this method may drop samples from `x_sample` or adjust `durations` to
comply. But `x_sample` and `durations` should be kept consistent.
@@ -235,14 +230,14 @@ def __init__(self, x, y, components, order=4, pad_dx=1.):
self.y = pad_const(self.y, order, axis=2)

assert self.y.shape[2] == self.x.shape[0]
self.splines = [UnivariateMultiSpline(self.x, yi, order)
self.splines = [UnivariateMultiSpline(self.x, yi, order=order)
for yi in self.y]

# need to resample/upsample the shim splines to the master spline knots
# shim knot spacings can span an master spline knot and thus would
# cross a highest order derivative boundary
self.components = UnivariateMultiSparseSpline(
components, self.x, order)
y0, x0 = zip(*components)
self.components = UnivariateMultiSpline(self.x, y0, x0=x0, order=order)

def __call__(self, t, gain={}, offset={}):
der = list((set(self.components.n) | set(offset))
2 changes: 1 addition & 1 deletion examples/master/ddb.pyon
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@
"arguments": {
"pdq2_devices": ["qc_q1_0", "qc_q1_1", "qc_q1_2", "qc_q1_3"],
"rtio_trigger": 7,
"rtio_frame": (2, 3, 4)
"rtio_frame": [2, 3, 4]
},
"comment": "Conflicts with dds2 and ttl0-2"
},