forked from M-Labs/artiq
experiment/gui: support reverse scan (closes #246)
This commit is contained in:
parent
2859382e11
commit
33da27a749
|
@ -10,9 +10,13 @@ Release notes
|
||||||
* Core device flash storage has moved due to increased runtime size.
|
* Core device flash storage has moved due to increased runtime size.
|
||||||
This requires reflashing the runtime and the flash storage filesystem image
|
This requires reflashing the runtime and the flash storage filesystem image
|
||||||
or erase and rewrite its entries.
|
or erase and rewrite its entries.
|
||||||
* RTIOCollisionError has been renamed to RTIOCollision
|
* ``RTIOCollisionError`` has been renamed to ``RTIOCollision``
|
||||||
* the new API for DDS batches is:
|
* the new API for DDS batches is::
|
||||||
with self.core_dds.batch:
|
with self.core_dds.batch:
|
||||||
...
|
...
|
||||||
with core_dds a device of type artiq.coredevice.dds.CoreDDS.
|
|
||||||
|
with ``core_dds`` a device of type ``artiq.coredevice.dds.CoreDDS``.
|
||||||
The dds_bus device should not be used anymore.
|
The dds_bus device should not be used anymore.
|
||||||
|
* LinearScan now supports scanning from high to low. Accordingly,
|
||||||
|
it's arguments ``min/max`` have been renamed to ``start/stop`` respectively.
|
||||||
|
Same for RandomScan (even though there direction matters little).
|
||||||
|
|
|
@ -154,52 +154,52 @@ class _RangeScan(LayoutWidget):
|
||||||
if procdesc["unit"]:
|
if procdesc["unit"]:
|
||||||
spinbox.setSuffix(" " + procdesc["unit"])
|
spinbox.setSuffix(" " + procdesc["unit"])
|
||||||
|
|
||||||
self.scanner = scanner = ScanWidget()
|
scanner = ScanWidget()
|
||||||
disable_scroll_wheel(scanner)
|
disable_scroll_wheel(scanner)
|
||||||
self.addWidget(scanner, 0, 0, -1, 1)
|
self.addWidget(scanner, 0, 0, -1, 1)
|
||||||
|
|
||||||
self.min = ScientificSpinBox()
|
start = ScientificSpinBox()
|
||||||
self.min.setStyleSheet("QDoubleSpinBox {color:blue}")
|
start.setStyleSheet("QDoubleSpinBox {color:blue}")
|
||||||
self.min.setMinimumSize(110, 0)
|
start.setMinimumSize(110, 0)
|
||||||
self.min.setSizePolicy(QtWidgets.QSizePolicy(
|
start.setSizePolicy(QtWidgets.QSizePolicy(
|
||||||
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
|
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
|
||||||
disable_scroll_wheel(self.min)
|
disable_scroll_wheel(start)
|
||||||
self.addWidget(self.min, 0, 1)
|
self.addWidget(start, 0, 1)
|
||||||
|
|
||||||
self.npoints = QtWidgets.QSpinBox()
|
npoints = QtWidgets.QSpinBox()
|
||||||
self.npoints.setMinimum(1)
|
npoints.setMinimum(1)
|
||||||
disable_scroll_wheel(self.npoints)
|
disable_scroll_wheel(npoints)
|
||||||
self.addWidget(self.npoints, 1, 1)
|
self.addWidget(npoints, 1, 1)
|
||||||
|
|
||||||
self.max = ScientificSpinBox()
|
stop = ScientificSpinBox()
|
||||||
self.max.setStyleSheet("QDoubleSpinBox {color:red}")
|
stop.setStyleSheet("QDoubleSpinBox {color:red}")
|
||||||
self.max.setMinimumSize(110, 0)
|
stop.setMinimumSize(110, 0)
|
||||||
disable_scroll_wheel(self.max)
|
disable_scroll_wheel(stop)
|
||||||
self.addWidget(self.max, 2, 1)
|
self.addWidget(stop, 2, 1)
|
||||||
|
|
||||||
def update_min(value):
|
def update_start(value):
|
||||||
state["min"] = value*scale
|
state["start"] = value*scale
|
||||||
scanner.setStart(value)
|
scanner.setStart(value)
|
||||||
|
|
||||||
def update_max(value):
|
def update_stop(value):
|
||||||
state["max"] = value*scale
|
state["stop"] = value*scale
|
||||||
scanner.setStop(value)
|
scanner.setStop(value)
|
||||||
|
|
||||||
def update_npoints(value):
|
def update_npoints(value):
|
||||||
state["npoints"] = value
|
state["npoints"] = value
|
||||||
scanner.setNum(value)
|
scanner.setNum(value)
|
||||||
|
|
||||||
scanner.startChanged.connect(self.min.setValue)
|
scanner.startChanged.connect(start.setValue)
|
||||||
scanner.numChanged.connect(self.npoints.setValue)
|
scanner.numChanged.connect(npoints.setValue)
|
||||||
scanner.stopChanged.connect(self.max.setValue)
|
scanner.stopChanged.connect(stop.setValue)
|
||||||
self.min.valueChanged.connect(update_min)
|
start.valueChanged.connect(update_start)
|
||||||
self.npoints.valueChanged.connect(update_npoints)
|
npoints.valueChanged.connect(update_npoints)
|
||||||
self.max.valueChanged.connect(update_max)
|
stop.valueChanged.connect(update_stop)
|
||||||
scanner.setStart(state["min"]/scale)
|
scanner.setStart(state["start"]/scale)
|
||||||
scanner.setNum(state["npoints"])
|
scanner.setNum(state["npoints"])
|
||||||
scanner.setStop(state["max"]/scale)
|
scanner.setStop(state["stop"]/scale)
|
||||||
apply_properties(self.min)
|
apply_properties(start)
|
||||||
apply_properties(self.max)
|
apply_properties(stop)
|
||||||
|
|
||||||
|
|
||||||
class _ExplicitScan(LayoutWidget):
|
class _ExplicitScan(LayoutWidget):
|
||||||
|
@ -266,8 +266,8 @@ class _ScanEntry(LayoutWidget):
|
||||||
state = {
|
state = {
|
||||||
"selected": "NoScan",
|
"selected": "NoScan",
|
||||||
"NoScan": {"value": 0.0},
|
"NoScan": {"value": 0.0},
|
||||||
"LinearScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
|
"LinearScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
|
||||||
"RandomScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
|
"RandomScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
|
||||||
"ExplicitScan": {"sequence": []}
|
"ExplicitScan": {"sequence": []}
|
||||||
}
|
}
|
||||||
if "default" in procdesc:
|
if "default" in procdesc:
|
||||||
|
@ -278,8 +278,8 @@ class _ScanEntry(LayoutWidget):
|
||||||
state["NoScan"]["value"] = default["value"]
|
state["NoScan"]["value"] = default["value"]
|
||||||
elif ty == "LinearScan" or ty == "RandomScan":
|
elif ty == "LinearScan" or ty == "RandomScan":
|
||||||
for d in state["LinearScan"], state["RandomScan"]:
|
for d in state["LinearScan"], state["RandomScan"]:
|
||||||
d["min"] = default["min"]
|
d["start"] = default["start"]
|
||||||
d["max"] = default["max"]
|
d["stop"] = default["stop"]
|
||||||
d["npoints"] = default["npoints"]
|
d["npoints"] = default["npoints"]
|
||||||
elif ty == "ExplicitScan":
|
elif ty == "ExplicitScan":
|
||||||
state["ExplicitScan"]["sequence"] = default["sequence"]
|
state["ExplicitScan"]["sequence"] = default["sequence"]
|
||||||
|
|
|
@ -11,7 +11,7 @@ Iterate on a scan object to scan it, e.g. ::
|
||||||
do_something(variable)
|
do_something(variable)
|
||||||
|
|
||||||
Iterating multiple times on the same scan object is possible, with the scan
|
Iterating multiple times on the same scan object is possible, with the scan
|
||||||
restarting at the minimum value each time. Iterating concurrently on the
|
yielding the same values each time. Iterating concurrently on the
|
||||||
same scan object (e.g. via nested loops) is also supported, and the
|
same scan object (e.g. via nested loops) is also supported, and the
|
||||||
iterators are independent from each other.
|
iterators are independent from each other.
|
||||||
|
|
||||||
|
@ -55,21 +55,23 @@ class NoScan(ScanObject):
|
||||||
|
|
||||||
|
|
||||||
class LinearScan(ScanObject):
|
class LinearScan(ScanObject):
|
||||||
"""A scan object that yields a fixed number of increasing evenly
|
"""A scan object that yields a fixed number of evenly
|
||||||
spaced values in a range."""
|
spaced values in a range."""
|
||||||
def __init__(self, min, max, npoints):
|
def __init__(self, start, stop, npoints):
|
||||||
if min > max:
|
self.start = start
|
||||||
raise ValueError("Scan minimum must be less than maximum")
|
self.stop = stop
|
||||||
self.min = min
|
|
||||||
self.max = max
|
|
||||||
self.npoints = npoints
|
self.npoints = npoints
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def _gen(self):
|
def _gen(self):
|
||||||
r = self.max - self.min
|
if self.npoints == 0:
|
||||||
d = self.npoints - 1
|
return
|
||||||
|
if self.npoints == 1:
|
||||||
|
yield self.start
|
||||||
|
else:
|
||||||
|
dx = (self.stop - self.start)/(self.npoints - 1)
|
||||||
for i in range(self.npoints):
|
for i in range(self.npoints):
|
||||||
yield r*i/d + self.min
|
yield i*dx + self.start
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
@ -80,19 +82,18 @@ class LinearScan(ScanObject):
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return {"ty": "LinearScan",
|
return {"ty": "LinearScan",
|
||||||
"min": self.min, "max": self.max, "npoints": self.npoints}
|
"start": self.start, "stop": self.stop,
|
||||||
|
"npoints": self.npoints}
|
||||||
|
|
||||||
|
|
||||||
class RandomScan(ScanObject):
|
class RandomScan(ScanObject):
|
||||||
"""A scan object that yields a fixed number of randomly ordered evenly
|
"""A scan object that yields a fixed number of randomly ordered evenly
|
||||||
spaced values in a range."""
|
spaced values in a range."""
|
||||||
def __init__(self, min, max, npoints, seed=0):
|
def __init__(self, start, stop, npoints, seed=0):
|
||||||
if min > max:
|
self.start = start
|
||||||
raise ValueError("Scan minimum must be less than maximum")
|
self.stop = stop
|
||||||
self.min = min
|
|
||||||
self.max = max
|
|
||||||
self.npoints = npoints
|
self.npoints = npoints
|
||||||
self.sequence = list(LinearScan(min, max, npoints))
|
self.sequence = list(LinearScan(start, stop, npoints))
|
||||||
shuffle(self.sequence, Random(seed).random)
|
shuffle(self.sequence, Random(seed).random)
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
|
@ -104,7 +105,8 @@ class RandomScan(ScanObject):
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return {"ty": "RandomScan",
|
return {"ty": "RandomScan",
|
||||||
"min": self.min, "max": self.max, "npoints": self.npoints}
|
"start": self.start, "stop": self.stop,
|
||||||
|
"npoints": self.npoints}
|
||||||
|
|
||||||
|
|
||||||
class ExplicitScan(ScanObject):
|
class ExplicitScan(ScanObject):
|
||||||
|
@ -142,8 +144,8 @@ class Scannable:
|
||||||
:param global_step: The step with which the value should be modified by
|
:param global_step: The step with which the value should be modified by
|
||||||
up/down buttons in a user interface. The default is the scale divided
|
up/down buttons in a user interface. The default is the scale divided
|
||||||
by 10.
|
by 10.
|
||||||
:param unit: A string representing the unit of the scanned variable, for user
|
:param unit: A string representing the unit of the scanned variable, for
|
||||||
interface (UI) purposes.
|
user interface (UI) purposes.
|
||||||
:param scale: The scale of value for UI purposes. The displayed value is
|
:param scale: The scale of value for UI purposes. The displayed value is
|
||||||
divided by the scale.
|
divided by the scale.
|
||||||
:param ndecimals: The number of decimals a UI should use.
|
:param ndecimals: The number of decimals a UI should use.
|
||||||
|
|
Loading…
Reference in New Issue