language,gui: combine LinearScan and RandomScan into RangeScan. Closes #679

pull/231/merge
Chris Ballance 2017-03-30 23:04:17 +01:00 committed by Sébastien Bourdeauducq
parent 28211e0b32
commit 07c71bf020
3 changed files with 39 additions and 54 deletions

View File

@ -29,7 +29,7 @@ Release notes
* The "collision" and "busy" RTIO errors are reported through the log instead of
raising exceptions.
* Results are still saved when ``analyze`` raises an exception.
* LinearScan and RandomScan have been consolidated into RangeScan
2.2
---

View File

@ -229,6 +229,9 @@ class _RangeScan(LayoutWidget):
disable_scroll_wheel(stop)
self.addWidget(stop, 2, 1)
randomize = QtWidgets.QCheckBox("Randomize")
self.addWidget(randomize, 3, 1)
apply_properties(start)
start.setPrecision()
start.setRelativeStep()
@ -255,15 +258,22 @@ class _RangeScan(LayoutWidget):
if npoints.value() != value:
npoints.setValue(value)
def update_randomize(value):
state["randomize"] = value
if randomize.isChecked() != value:
randomize.setChecked(value)
scanner.startChanged.connect(update_start)
scanner.numChanged.connect(update_npoints)
scanner.stopChanged.connect(update_stop)
start.valueChanged.connect(update_start)
npoints.valueChanged.connect(update_npoints)
stop.valueChanged.connect(update_stop)
randomize.stateChanged.connect(update_randomize)
scanner.setStart(state["start"]/scale)
scanner.setNum(state["npoints"])
scanner.setStop(state["stop"]/scale)
randomize.setChecked(state["randomize"])
class _ExplicitScan(LayoutWidget):
@ -297,16 +307,14 @@ class ScanEntry(LayoutWidget):
state = argument["state"]
self.widgets = OrderedDict()
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
self.widgets["LinearScan"] = _RangeScan(procdesc, state["LinearScan"])
self.widgets["RandomScan"] = _RangeScan(procdesc, state["RandomScan"])
self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"])
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["LinearScan"] = QtWidgets.QRadioButton("Linear")
self.radiobuttons["RandomScan"] = QtWidgets.QRadioButton("Random")
self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range")
self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit")
scan_type = QtWidgets.QButtonGroup()
for n, b in enumerate(self.radiobuttons.values()):
@ -334,8 +342,8 @@ class ScanEntry(LayoutWidget):
state = {
"selected": "NoScan",
"NoScan": {"value": 0.0, "repetitions": 1},
"LinearScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
"RandomScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
"RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10,
"randomize": False},
"ExplicitScan": {"sequence": []}
}
if "default" in procdesc:
@ -348,10 +356,11 @@ class ScanEntry(LayoutWidget):
if ty == "NoScan":
state[ty]["value"] = default["value"]
state[ty]["repetitions"] = default["repetitions"]
elif ty == "LinearScan" or ty == "RandomScan":
elif ty == "RangeScan":
state[ty]["start"] = default["start"]
state[ty]["stop"] = default["stop"]
state[ty]["npoints"] = default["npoints"]
state[ty]["randomize"] = default["randomize"]
elif ty == "ExplicitScan":
state[ty]["sequence"] = default["sequence"]
else:

View File

@ -1,7 +1,7 @@
"""
Implementation and management of scan objects.
A scan object (e.g. :class:`artiq.language.scan.LinearScan`) represents a
A scan object (e.g. :class:`artiq.language.scan.RangeScan`) represents a
one-dimensional sweep of a numerical range. Multi-dimensional scans are
constructed by combining several scan objects, for example using
:class:`artiq.language.scan.MultiScanManager`.
@ -27,7 +27,7 @@ from artiq.language import units
__all__ = ["ScanObject",
"NoScan", "LinearScan", "RandomScan", "ExplicitScan",
"NoScan", "RangeScan", "ExplicitScan",
"Scannable", "MultiScanManager"]
@ -59,52 +59,28 @@ class NoScan(ScanObject):
"repetitions": self.repetitions}
class LinearScan(ScanObject):
"""A scan object that yields a fixed number of evenly
spaced values in a range."""
def __init__(self, start, stop, npoints):
self.start = start
self.stop = stop
self.npoints = npoints
@portable
def _gen(self):
if self.npoints == 0:
return
if self.npoints == 1:
yield self.start
else:
dx = (self.stop - self.start)/(self.npoints - 1)
for i in range(self.npoints):
yield i*dx + self.start
@portable
def __iter__(self):
return self._gen()
def __len__(self):
return self.npoints
def describe(self):
return {"ty": "LinearScan",
"start": self.start, "stop": self.stop,
"npoints": self.npoints}
class RandomScan(ScanObject):
"""A scan object that yields a fixed number of randomly ordered evenly
spaced values in a range."""
def __init__(self, start, stop, npoints, seed=None):
class RangeScan(ScanObject):
"""A scan object that yields a fixed number of evenly spaced values in a
range. If ``randomize`` is True the points are randomly ordered."""
def __init__(self, start, stop, npoints, randomize=False, seed=None):
self.start = start
self.stop = stop
self.npoints = npoints
self.randomize = randomize
self.seed = seed
self.sequence = list(LinearScan(start, stop, npoints))
if seed is None:
rf = random.random
if npoints == 0:
self.sequence = []
if npoints == 1:
self.sequence = [self.start]
else:
rf = Random(seed).random
random.shuffle(self.sequence, rf)
dx = (stop - start)/(npoints - 1)
self.sequence = [i*dx + start for i in range(npoints)]
if randomize:
if seed is not None:
random.seed(seed)
random.shuffle(self.sequence)
@portable
def __iter__(self):
@ -114,9 +90,10 @@ class RandomScan(ScanObject):
return self.npoints
def describe(self):
return {"ty": "RandomScan",
return {"ty": "RangeScan",
"start": self.start, "stop": self.stop,
"npoints": self.npoints,
"randomize": self.randomize,
"seed": self.seed}
@ -138,8 +115,7 @@ class ExplicitScan(ScanObject):
_ty_to_scan = {
"NoScan": NoScan,
"LinearScan": LinearScan,
"RandomScan": RandomScan,
"RangeScan": RangeScan,
"ExplicitScan": ExplicitScan
}