Skip to content

Commit

Permalink
experiment/gui: support reverse scan (closes #246)
Browse files Browse the repository at this point in the history
jordens committed Mar 17, 2016
1 parent 2859382 commit 33da27a
Showing 3 changed files with 67 additions and 61 deletions.
10 changes: 7 additions & 3 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
@@ -10,9 +10,13 @@ Release notes
* Core device flash storage has moved due to increased runtime size.
This requires reflashing the runtime and the flash storage filesystem image
or erase and rewrite its entries.
* RTIOCollisionError has been renamed to RTIOCollision
* the new API for DDS batches is:
* ``RTIOCollisionError`` has been renamed to ``RTIOCollision``
* the new API for DDS batches is::
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.
* 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).
74 changes: 37 additions & 37 deletions artiq/gui/entries.py
Original file line number Diff line number Diff line change
@@ -154,52 +154,52 @@ def apply_properties(spinbox):
if procdesc["unit"]:
spinbox.setSuffix(" " + procdesc["unit"])

self.scanner = scanner = ScanWidget()
scanner = ScanWidget()
disable_scroll_wheel(scanner)
self.addWidget(scanner, 0, 0, -1, 1)

self.min = ScientificSpinBox()
self.min.setStyleSheet("QDoubleSpinBox {color:blue}")
self.min.setMinimumSize(110, 0)
self.min.setSizePolicy(QtWidgets.QSizePolicy(
start = ScientificSpinBox()
start.setStyleSheet("QDoubleSpinBox {color:blue}")
start.setMinimumSize(110, 0)
start.setSizePolicy(QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
disable_scroll_wheel(self.min)
self.addWidget(self.min, 0, 1)

self.npoints = QtWidgets.QSpinBox()
self.npoints.setMinimum(1)
disable_scroll_wheel(self.npoints)
self.addWidget(self.npoints, 1, 1)

self.max = ScientificSpinBox()
self.max.setStyleSheet("QDoubleSpinBox {color:red}")
self.max.setMinimumSize(110, 0)
disable_scroll_wheel(self.max)
self.addWidget(self.max, 2, 1)

def update_min(value):
state["min"] = value*scale
disable_scroll_wheel(start)
self.addWidget(start, 0, 1)

npoints = QtWidgets.QSpinBox()
npoints.setMinimum(1)
disable_scroll_wheel(npoints)
self.addWidget(npoints, 1, 1)

stop = ScientificSpinBox()
stop.setStyleSheet("QDoubleSpinBox {color:red}")
stop.setMinimumSize(110, 0)
disable_scroll_wheel(stop)
self.addWidget(stop, 2, 1)

def update_start(value):
state["start"] = value*scale
scanner.setStart(value)

def update_max(value):
state["max"] = value*scale
def update_stop(value):
state["stop"] = value*scale
scanner.setStop(value)

def update_npoints(value):
state["npoints"] = value
scanner.setNum(value)

scanner.startChanged.connect(self.min.setValue)
scanner.numChanged.connect(self.npoints.setValue)
scanner.stopChanged.connect(self.max.setValue)
self.min.valueChanged.connect(update_min)
self.npoints.valueChanged.connect(update_npoints)
self.max.valueChanged.connect(update_max)
scanner.setStart(state["min"]/scale)
scanner.startChanged.connect(start.setValue)
scanner.numChanged.connect(npoints.setValue)
scanner.stopChanged.connect(stop.setValue)
start.valueChanged.connect(update_start)
npoints.valueChanged.connect(update_npoints)
stop.valueChanged.connect(update_stop)
scanner.setStart(state["start"]/scale)
scanner.setNum(state["npoints"])
scanner.setStop(state["max"]/scale)
apply_properties(self.min)
apply_properties(self.max)
scanner.setStop(state["stop"]/scale)
apply_properties(start)
apply_properties(stop)


class _ExplicitScan(LayoutWidget):
@@ -266,8 +266,8 @@ def default_state(procdesc):
state = {
"selected": "NoScan",
"NoScan": {"value": 0.0},
"LinearScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
"RandomScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
"LinearScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
"RandomScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10},
"ExplicitScan": {"sequence": []}
}
if "default" in procdesc:
@@ -278,8 +278,8 @@ def default_state(procdesc):
state["NoScan"]["value"] = default["value"]
elif ty == "LinearScan" or ty == "RandomScan":
for d in state["LinearScan"], state["RandomScan"]:
d["min"] = default["min"]
d["max"] = default["max"]
d["start"] = default["start"]
d["stop"] = default["stop"]
d["npoints"] = default["npoints"]
elif ty == "ExplicitScan":
state["ExplicitScan"]["sequence"] = default["sequence"]
44 changes: 23 additions & 21 deletions artiq/language/scan.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
do_something(variable)
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
iterators are independent from each other.
@@ -55,21 +55,23 @@ def describe(self):


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."""
def __init__(self, min, max, npoints):
if min > max:
raise ValueError("Scan minimum must be less than maximum")
self.min = min
self.max = max
def __init__(self, start, stop, npoints):
self.start = start
self.stop = stop
self.npoints = npoints

@portable
def _gen(self):
r = self.max - self.min
d = self.npoints - 1
for i in range(self.npoints):
yield r*i/d + self.min
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):
@@ -80,19 +82,18 @@ def __len__(self):

def describe(self):
return {"ty": "LinearScan",
"min": self.min, "max": self.max, "npoints": self.npoints}
"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, min, max, npoints, seed=0):
if min > max:
raise ValueError("Scan minimum must be less than maximum")
self.min = min
self.max = max
def __init__(self, start, stop, npoints, seed=0):
self.start = start
self.stop = stop
self.npoints = npoints
self.sequence = list(LinearScan(min, max, npoints))
self.sequence = list(LinearScan(start, stop, npoints))
shuffle(self.sequence, Random(seed).random)

@portable
@@ -104,7 +105,8 @@ def __len__(self):

def describe(self):
return {"ty": "RandomScan",
"min": self.min, "max": self.max, "npoints": self.npoints}
"start": self.start, "stop": self.stop,
"npoints": self.npoints}


class ExplicitScan(ScanObject):
@@ -142,8 +144,8 @@ class Scannable:
: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
by 10.
:param unit: A string representing the unit of the scanned variable, for user
interface (UI) purposes.
:param unit: A string representing the unit of the scanned variable, for
user interface (UI) purposes.
:param scale: The scale of value for UI purposes. The displayed value is
divided by the scale.
:param ndecimals: The number of decimals a UI should use.

0 comments on commit 33da27a

Please sign in to comment.