Skip to content

Commit

Permalink
gui,scan: add CenterScan Scannable variant
Browse files Browse the repository at this point in the history
* parametrized by center/span/step instead of
  start/stop/npoints which is more convenient in some applications
* no scan widget support so far

Signed-off-by: Robert Jördens <rj@quartiq.de>
  • Loading branch information
jordens committed Nov 14, 2018
1 parent f77a75a commit 4d62e4e
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
79 changes: 79 additions & 0 deletions artiq/gui/entries.py
Expand Up @@ -275,6 +275,78 @@ def update_randomize(value):
randomize.setChecked(state["randomize"])


class _CenterScan(LayoutWidget):
def __init__(self, procdesc, state):
LayoutWidget.__init__(self)

scale = procdesc["scale"]

def apply_properties(widget):
widget.setDecimals(procdesc["ndecimals"])
if procdesc["global_min"] is not None:
widget.setMinimum(procdesc["global_min"]/scale)
else:
widget.setMinimum(float("-inf"))
if procdesc["global_max"] is not None:
widget.setMaximum(procdesc["global_max"]/scale)
else:
widget.setMaximum(float("inf"))
if procdesc["global_step"] is not None:
widget.setSingleStep(procdesc["global_step"]/scale)
if procdesc["unit"]:
widget.setSuffix(" " + procdesc["unit"])

center = ScientificSpinBox()
disable_scroll_wheel(center)
apply_properties(center)
center.setPrecision()
center.setRelativeStep()
center.setValue(state["center"])
self.addWidget(center, 0, 1)
self.addWidget(QtWidgets.QLabel("Center:"), 0, 0)

span = ScientificSpinBox()
disable_scroll_wheel(span)
apply_properties(span)
span.setPrecision()
span.setRelativeStep()
span.setMinimum(0)
span.setValue(state["span"])
self.addWidget(span, 1, 1)
self.addWidget(QtWidgets.QLabel("Span:"), 1, 0)

step = ScientificSpinBox()
disable_scroll_wheel(step)
apply_properties(step)
step.setPrecision()
step.setRelativeStep()
step.setMinimum(0)
step.setValue(state["step"])
self.addWidget(step, 2, 1)
self.addWidget(QtWidgets.QLabel("Step:"), 2, 0)

randomize = QtWidgets.QCheckBox("Randomize")
self.addWidget(randomize, 3, 1)
randomize.setChecked(state["randomize"])

def update_center(value):
state["center"] = value*scale

def update_span(value):
state["span"] = value*scale

def update_step(value):
state["step"] = value*scale

def update_randomize(value):
state["randomize"] = value

center.valueChanged.connect(update_center)
span.valueChanged.connect(update_span)
step.valueChanged.connect(update_step)
randomize.stateChanged.connect(update_randomize)


class _ExplicitScan(LayoutWidget):
def __init__(self, state):
LayoutWidget.__init__(self)
Expand Down Expand Up @@ -307,13 +379,15 @@ def __init__(self, argument):
self.widgets = OrderedDict()
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"])
self.widgets["CenterScan"] = _CenterScan(procdesc, state["CenterScan"])
self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"])
for widget in self.widgets.values():
self.stack.addWidget(widget)

self.radiobuttons = OrderedDict()
self.radiobuttons["NoScan"] = QtWidgets.QRadioButton("No scan")
self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range")
self.radiobuttons["CenterScan"] = QtWidgets.QRadioButton("Center")
self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit")
scan_type = QtWidgets.QButtonGroup()
for n, b in enumerate(self.radiobuttons.values()):
Expand Down Expand Up @@ -343,6 +417,8 @@ def default_state(procdesc):
"NoScan": {"value": 0.0, "repetitions": 1},
"RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10,
"randomize": False},
"CenterScan": {"center": 0.*scale, "span": 100.*scale,
"step": 10.*scale, "randomize": False},
"ExplicitScan": {"sequence": []}
}
if "default" in procdesc:
Expand All @@ -361,6 +437,9 @@ def default_state(procdesc):
state[ty]["npoints"] = default["npoints"]
state[ty]["randomize"] = default["randomize"]
state[ty]["seed"] = default["seed"]
elif ty == "CenterScan":
for key in "center span step randomize seed".split():
state[ty][key] = default[key]
elif ty == "ExplicitScan":
state[ty]["sequence"] = default["sequence"]
else:
Expand Down
40 changes: 39 additions & 1 deletion artiq/language/scan.py
Expand Up @@ -27,7 +27,7 @@


__all__ = ["ScanObject",
"NoScan", "RangeScan", "ExplicitScan",
"NoScan", "RangeScan", "CenterScan", "ExplicitScan",
"Scannable", "MultiScanManager"]


Expand Down Expand Up @@ -93,6 +93,43 @@ def describe(self):
"seed": self.seed}


class CenterScan(ScanObject):
"""A scan object that yields evenly spaced values within a span around a
center. If ``step`` is finite, then ``center`` is always included.
Values outside ``span`` around center are never included.
If ``randomize`` is True the points are randomly ordered."""
def __init__(self, center, span, step, randomize=False, seed=None):
self.center = center
self.span = span
self.step = step
self.randomize = randomize
self.seed = seed

if step == 0.:
self.sequence = []
else:
n = 1 + int(span/(2.*step))
self.sequence = [center + sign*i*step
for i in range(n) for sign in [-1, 1]][1:]

if randomize:
rng = random.Random(seed)
random.shuffle(self.sequence, rng.random)

def __iter__(self):
return iter(self.sequence)

def __len__(self):
return len(self.sequence)

def describe(self):
return {"ty": "CenterScan",
"center": self.center, "step": self.step,
"span": self.span,
"randomize": self.randomize,
"seed": self.seed}


class ExplicitScan(ScanObject):
"""A scan object that yields values from an explicitly defined sequence."""
def __init__(self, sequence):
Expand All @@ -111,6 +148,7 @@ def describe(self):
_ty_to_scan = {
"NoScan": NoScan,
"RangeScan": RangeScan,
"CenterScan": CenterScan,
"ExplicitScan": ExplicitScan
}

Expand Down

0 comments on commit 4d62e4e

Please sign in to comment.