gui,scan: add CenterScan Scannable variant

* 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>
This commit is contained in:
Robert Jördens 2018-11-14 21:47:22 +01:00 committed by Sébastien Bourdeauducq
parent f77a75ab17
commit 494ffca4d3
2 changed files with 118 additions and 1 deletions

View File

@ -275,6 +275,78 @@ class _RangeScan(LayoutWidget):
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)
@ -307,6 +379,7 @@ class ScanEntry(LayoutWidget):
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)
@ -314,6 +387,7 @@ class ScanEntry(LayoutWidget):
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()):
@ -343,6 +417,8 @@ class ScanEntry(LayoutWidget):
"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:
@ -361,6 +437,9 @@ class ScanEntry(LayoutWidget):
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:

View File

@ -27,7 +27,7 @@ from artiq.language import units
__all__ = ["ScanObject",
"NoScan", "RangeScan", "ExplicitScan",
"NoScan", "RangeScan", "CenterScan", "ExplicitScan",
"Scannable", "MultiScanManager"]
@ -93,6 +93,43 @@ class RangeScan(ScanObject):
"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):
@ -111,6 +148,7 @@ class ExplicitScan(ScanObject):
_ty_to_scan = {
"NoScan": NoScan,
"RangeScan": RangeScan,
"CenterScan": CenterScan,
"ExplicitScan": ExplicitScan
}