Take successive readings spaced exponentially in time or space¶
Problem¶
Read a detector (or detectors) multiple times, with successive readings spaced 1, 2, 4, 8, 16, ... seconds apart. Or, similarly, move a motor is steps with an exponential spacing.
Approach¶
We will define an iterator that specifies the delays between readings.
Example Solution¶
Use the built-in function range
to generate sequential integers.
range(5) # generates 0, 1, 2, 3, 4
Modify each element like so:
(2**i for i in range(4)) # generates 1, 2, 4, 8, 16
The above is called a generator comprehension. It evaluates “lazily”, computing the result for one element at a time.
We can pass this expression to the delay
parameter of a count
plan.
from bluesky.plans import count
from bluesky.callbacks import LiveTable
plan = count([det], num=None, delay=(2**i for i in range(4)))
The setting num=None
means, “Run until the end of list of delays.”
Let’s attach a LiveTable
to the output and watch it in action. Notice
the readings’ timestamps.
In [1]: RE(plan, LiveTable([det]))
+-----------+------------+------------+
| seq_num | time | det |
+-----------+------------+------------+
| 1 | 17:01:14.7 | 0.00 |
| 2 | 17:01:15.7 | 0.00 |
| 3 | 17:01:17.7 | 0.00 |
| 4 | 17:01:21.7 | 0.00 |
| 5 | 17:01:29.7 | 0.00 |
+-----------+------------+------------+
generator count ['af83d1'] (scan num: 1)
Out[1]: ['af83d181-fd75-49f6-aeb2-22422d5333bf']
We could use the same principle to arrange readings in space instead of
time using a list_scan
.
from blusky.plans import list_scan
# Take readings with motor moved positioned at 1, 2, 4, 8, 16.
plan = list_scan([det], motor, (2**i for i in range(4)))
Next, instead of giving a specific number of readings, let’s run count
indefinitely — until interrupted by the user pressing Ctrl^C. Instead of
range
, which counts integers up to a given upper limit, we’ll use another
built in function, itertools.count
, which counts integers without bound.
import itertools
# This would run forever until interrupted (for example, with Ctrl^C).
plan = count([det], delay=(2**i for i in itertools.count(0)))
Note
Python provides many convenient tools for working with series (“iterators”). Many are available in the built-in module itertools, which is worth getting to know.