forked from M-Labs/artiq
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:
parent
f77a75ab17
commit
494ffca4d3
|
@ -275,6 +275,78 @@ class _RangeScan(LayoutWidget):
|
||||||
randomize.setChecked(state["randomize"])
|
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):
|
class _ExplicitScan(LayoutWidget):
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
LayoutWidget.__init__(self)
|
LayoutWidget.__init__(self)
|
||||||
|
@ -307,6 +379,7 @@ class ScanEntry(LayoutWidget):
|
||||||
self.widgets = OrderedDict()
|
self.widgets = OrderedDict()
|
||||||
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
|
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
|
||||||
self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"])
|
self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"])
|
||||||
|
self.widgets["CenterScan"] = _CenterScan(procdesc, state["CenterScan"])
|
||||||
self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"])
|
self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"])
|
||||||
for widget in self.widgets.values():
|
for widget in self.widgets.values():
|
||||||
self.stack.addWidget(widget)
|
self.stack.addWidget(widget)
|
||||||
|
@ -314,6 +387,7 @@ class ScanEntry(LayoutWidget):
|
||||||
self.radiobuttons = OrderedDict()
|
self.radiobuttons = OrderedDict()
|
||||||
self.radiobuttons["NoScan"] = QtWidgets.QRadioButton("No scan")
|
self.radiobuttons["NoScan"] = QtWidgets.QRadioButton("No scan")
|
||||||
self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range")
|
self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range")
|
||||||
|
self.radiobuttons["CenterScan"] = QtWidgets.QRadioButton("Center")
|
||||||
self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit")
|
self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit")
|
||||||
scan_type = QtWidgets.QButtonGroup()
|
scan_type = QtWidgets.QButtonGroup()
|
||||||
for n, b in enumerate(self.radiobuttons.values()):
|
for n, b in enumerate(self.radiobuttons.values()):
|
||||||
|
@ -343,6 +417,8 @@ class ScanEntry(LayoutWidget):
|
||||||
"NoScan": {"value": 0.0, "repetitions": 1},
|
"NoScan": {"value": 0.0, "repetitions": 1},
|
||||||
"RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10,
|
"RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10,
|
||||||
"randomize": False},
|
"randomize": False},
|
||||||
|
"CenterScan": {"center": 0.*scale, "span": 100.*scale,
|
||||||
|
"step": 10.*scale, "randomize": False},
|
||||||
"ExplicitScan": {"sequence": []}
|
"ExplicitScan": {"sequence": []}
|
||||||
}
|
}
|
||||||
if "default" in procdesc:
|
if "default" in procdesc:
|
||||||
|
@ -361,6 +437,9 @@ class ScanEntry(LayoutWidget):
|
||||||
state[ty]["npoints"] = default["npoints"]
|
state[ty]["npoints"] = default["npoints"]
|
||||||
state[ty]["randomize"] = default["randomize"]
|
state[ty]["randomize"] = default["randomize"]
|
||||||
state[ty]["seed"] = default["seed"]
|
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":
|
elif ty == "ExplicitScan":
|
||||||
state[ty]["sequence"] = default["sequence"]
|
state[ty]["sequence"] = default["sequence"]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -27,7 +27,7 @@ from artiq.language import units
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["ScanObject",
|
__all__ = ["ScanObject",
|
||||||
"NoScan", "RangeScan", "ExplicitScan",
|
"NoScan", "RangeScan", "CenterScan", "ExplicitScan",
|
||||||
"Scannable", "MultiScanManager"]
|
"Scannable", "MultiScanManager"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,6 +93,43 @@ class RangeScan(ScanObject):
|
||||||
"seed": self.seed}
|
"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):
|
class ExplicitScan(ScanObject):
|
||||||
"""A scan object that yields values from an explicitly defined sequence."""
|
"""A scan object that yields values from an explicitly defined sequence."""
|
||||||
def __init__(self, sequence):
|
def __init__(self, sequence):
|
||||||
|
@ -111,6 +148,7 @@ class ExplicitScan(ScanObject):
|
||||||
_ty_to_scan = {
|
_ty_to_scan = {
|
||||||
"NoScan": NoScan,
|
"NoScan": NoScan,
|
||||||
"RangeScan": RangeScan,
|
"RangeScan": RangeScan,
|
||||||
|
"CenterScan": CenterScan,
|
||||||
"ExplicitScan": ExplicitScan
|
"ExplicitScan": ExplicitScan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue