Skip to content

Stage

Classes

Stage(tem)

Stage control.

Source code in src/instamatic/microscope/components/stage.py
18
19
20
21
22
23
def __init__(self, tem: MicroscopeBase):
    super().__init__()
    self._tem = tem
    self._setter = self._tem.setStagePosition
    self._getter = self._tem.getStagePosition
    self._wait = True  # properties only

Attributes

a property writable

Primary rotation angle alpha expressed in degrees.

b property writable

Secondary rotation angle beta expressed in degrees.

name property

Get name of the class.

x property writable

Stage position X expressed in nm.

xy property writable

Stage position XY expressed as a tuple in nm.

y property writable

Stage position Y expressed in nm.

z property writable

Stage height Z expressed in nm.

Methods:

alpha_wobbler(delta=5.0, event=None)

Tilt the stage by plus/minus the value of delta (degrees) If event is not set, press Ctrl-C to interrupt.

Source code in src/instamatic/microscope/components/stage.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
def alpha_wobbler(self, delta: float_deg = 5.0, event=None) -> None:
    """Tilt the stage by plus/minus the value of delta (degrees) If event
    is not set, press Ctrl-C to interrupt."""

    a_center = self.a
    print(f"Wobbling 'alpha': {a_center:.2f}±{delta:.2f}")

    if event:
        while not event.is_set():
            self.a = a_center + delta
            self.a = a_center - delta
    else:
        print("(press 'Ctrl-C' to interrupt)")
        try:
            while True:
                self.a = a_center + delta
                self.a = a_center - delta
        except KeyboardInterrupt:
            pass

    print(f"Restoring 'alpha': {a_center:.2f}")
    self.a = a_center
    print(f'Print z={self.z}')
eliminate_backlash_a(target_angle=0.0, step=1.0, n_steps=3, settle_delay=0.2)

Eliminate backlash by relaxing the position. The routine will move in opposite direction of the targeted angle by n_steps*step, and walk up to the current tilt angle in n_steps. Based on Suloway et al., J. Struct. Biol. (2009), doi: 10.1016/j.jsb.2009.03.019.

target_angle: float, target angle for the rotation in degrees step: float, stepsize in degrees n_steps: int > 0, number of steps to walk up to current angle settle_delay: float, delay between movements in seconds to allow the stage to settle

Source code in src/instamatic/microscope/components/stage.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
def eliminate_backlash_a(
    self,
    target_angle: float_deg = 0.0,
    step: float_deg = 1.0,
    n_steps: int = 3,
    settle_delay: float = 0.200,
) -> None:
    """Eliminate backlash by relaxing the position. The routine will move
    in opposite direction of the targeted angle by `n_steps`*`step`, and
    walk up to the current tilt angle in `n_steps`. Based on Suloway et
    al., J. Struct. Biol. (2009), doi: 10.1016/j.jsb.2009.03.019.

    target_angle: float,
        target angle for the rotation in degrees
    step: float,
        stepsize in degrees
    n_steps: int > 0,
        number of steps to walk up to current angle
    settle_delay: float,
        delay between movements in seconds to allow the stage to settle
    """
    current = self.a

    if target_angle > current:
        s = +1
    elif target_angle < current:
        s = -1
    else:
        return

    n_steps += 1

    for i in reversed(range(n_steps)):
        self.a = current - s * i * step
        time.sleep(settle_delay)
eliminate_backlash_xy(step=10000, settle_delay=0.2)

Eliminate backlash by in XY by moving the stage away from the current position, and approaching it from the common direction. Uses set_xy_with_backlash_correction internally.

step: int, stepsize in nm settle_delay: float, delay between movements in seconds to allow the stage to settle

Source code in src/instamatic/microscope/components/stage.py
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
def eliminate_backlash_xy(
    self,
    step: int_nm = 10000,
    settle_delay: float = 0.200,
) -> None:
    """Eliminate backlash by in XY by moving the stage away from the
    current position, and approaching it from the common direction. Uses
    `set_xy_with_backlash_correction` internally.

    step: int,
        stepsize in nm
    settle_delay: float,
        delay between movements in seconds to allow the stage to settle
    """
    stage = self.get()
    self.set_xy_with_backlash_correction(
        x=stage.x, y=stage.y, step=step, settle_delay=settle_delay
    )
get()

Get stage positions x, y, z in nm and rotation axes a, b in deg.

Source code in src/instamatic/microscope/components/stage.py
114
115
116
def get(self) -> StagePositionTuple:
    """Get stage positions x, y, z in nm and rotation axes a, b in deg."""
    return StagePositionTuple(*self._getter())
get_rotation_speed()

Gets the stage (rotation) movement speed on the TEM.

Source code in src/instamatic/microscope/components/stage.py
149
150
151
def get_rotation_speed(self) -> NativeNumber:
    """Gets the stage (rotation) movement speed on the TEM."""
    return self._tem.getRotationSpeed()
is_moving()

Return 'True' if the stage is moving.

Source code in src/instamatic/microscope/components/stage.py
217
218
219
def is_moving(self) -> bool:
    """Return 'True' if the stage is moving."""
    return self._tem.isStageMoving()
move_along_optical_axis(delta_z)

See Stage.move_in_projection

Source code in src/instamatic/microscope/components/stage.py
175
176
177
178
179
180
181
def move_along_optical_axis(self, delta_z: int_nm) -> None:
    """See `Stage.move_in_projection`"""
    x, y, z, a, b = self.get()
    a = np.radians(a)
    y = y + delta_z * np.sin(a)
    z = z + delta_z * np.cos(a)
    self.set(y=y, z=z)
move_in_projection(delta_x, delta_y)

Y and z are always perpendicular to the sample stage. To achieve the movement in the projection plane instead, x and y should be broken down into the components z' and y'.

y = y' * cos(a) z = y' * sin(a)

z'| / z | / |/_____ y' \ a \ \ y

Source code in src/instamatic/microscope/components/stage.py
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
def move_in_projection(self, delta_x: int_nm, delta_y: int_nm) -> None:
    r"""Y and z are always perpendicular to the sample stage. To achieve the
    movement in the projection plane instead, x and y should be broken down
    into the components z' and y'.

    y = y' * cos(a)
    z = y' * sin(a)

    z'|  / z
      | /
      |/_____ y'
       \ a
        \
         \ y
    """
    x, y, z, a, b = self.get()
    a = np.radians(a)
    x = x + delta_x
    y = y + delta_y * np.cos(a)
    z = z - delta_y * np.sin(a)
    self.set(x=x, y=y, z=z)
move_xy_with_backlash_correction(shift_x=None, shift_y=None, step=5000, settle_delay=0.2, wait=True)

Move xy by given shifts in stage coordinates with backlash correction. This is done by moving backwards from the targeted position by step, before moving to the targeted position. This function is meant to be used when precise relative movements are needed, for example when a shift is calculated from an image. Based on Liu et al., Sci. Rep. (2016) DOI: 10.1038/srep29231.

shift_x, shift_y: float, relative movement in x and y (nm) step: float, stepsize in nm settle_delay: float, delay between movements in seconds to allow the stage to settle wait: bool, block until stage movement is complete (JEOL only)

Source code in src/instamatic/microscope/components/stage.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
def move_xy_with_backlash_correction(
    self,
    shift_x: Optional[int_nm] = None,
    shift_y: Optional[int_nm] = None,
    step: int_nm = 5000,
    settle_delay: float = 0.200,
    wait=True,
) -> None:
    """Move xy by given shifts in stage coordinates with backlash
    correction. This is done by moving backwards from the targeted position
    by `step`, before moving to the targeted position. This function is
    meant to be used when precise relative movements are needed, for
    example when a shift is calculated from an image. Based on Liu et al.,
    Sci. Rep. (2016) DOI: 10.1038/srep29231.

    shift_x, shift_y: float,
        relative movement in x and y (nm)
    step: float,
        stepsize in nm
    settle_delay: float,
        delay between movements in seconds to allow the stage to settle
    wait: bool,
        block until stage movement is complete (JEOL only)
    """
    stage = self.get()

    if shift_x:
        target_x = stage.x + shift_x
        if target_x > stage.x:
            pre_x = stage.x - step
        else:  # if target_x < stage.x:
            pre_x = stage.x + step
    else:
        pre_x = None
        target_x = None

    if shift_y:
        target_y = stage.y + shift_y
        if target_y > stage.y:
            pre_y = stage.y - step
        else:  # if target_y < stage.y:
            pre_y = stage.y + step
    else:
        pre_y = None
        target_y = None

    self.set(x=pre_x, y=pre_y)
    if settle_delay:
        time.sleep(settle_delay)

    self.set(x=target_x, y=target_y, wait=wait)
    if settle_delay:
        time.sleep(settle_delay)
neutral()

Reset the position of the stage to the 0-position.

Source code in src/instamatic/microscope/components/stage.py
213
214
215
def neutral(self) -> None:
    """Reset the position of the stage to the 0-position."""
    self.set(x=0, y=0, z=0, a=0.0, b=0.0)
no_wait()

Context manager that prevents blocking stage position calls on properties.

Usage: with ctrl.stage.no_wait(): ctrl.stage.x += 1000 ctrl.stage.y += 1000

Source code in src/instamatic/microscope/components/stage.py
225
226
227
228
229
230
231
232
233
234
235
236
237
@contextmanager
def no_wait(self) -> Generator[None, None, None]:
    """Context manager that prevents blocking stage position calls on
    properties.

    Usage:
        with ctrl.stage.no_wait():
            ctrl.stage.x += 1000
            ctrl.stage.y += 1000
    """
    self._wait = False
    yield
    self._wait = True
relax_xy(step=100)

Relax the stage by moving it in the opposite direction from the last movement.

Source code in src/instamatic/microscope/components/stage.py
268
269
270
271
def relax_xy(self, step: int = 100) -> None:
    """Relax the stage by moving it in the opposite direction from the last
    movement."""
    pass
rotation_speed(speed)

Context manager that sets the rotation speed for the duration of the with statement (JEOL, Tecnai only).

Usage: with ctrl.stage.rotation_speed(1): ctrl.stage.a = 40.0

Source code in src/instamatic/microscope/components/stage.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
@contextmanager
def rotation_speed(self, speed: AnyNumber) -> Generator[None, None, None]:
    """Context manager that sets the rotation speed for the duration of the
    `with` statement (JEOL, Tecnai only).

    Usage:
        with ctrl.stage.rotation_speed(1):
            ctrl.stage.a = 40.0
    """
    try:
        current_speed = self._tem.getRotationSpeed()
    except BaseException:
        yield  # on error
    else:
        if current_speed != speed:
            self.set_rotation_speed(speed)
            yield  # default flow
            self.set_rotation_speed(current_speed)
        else:
            yield  # if requested speed is the same as current
set(x=None, y=None, z=None, a=None, b=None, wait=True)

Wait: bool, block until stage movement is complete (JEOL only)

Source code in src/instamatic/microscope/components/stage.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def set(
    self,
    x: Optional[int_nm] = None,
    y: Optional[int_nm] = None,
    z: Optional[int_nm] = None,
    a: Optional[float_deg] = None,
    b: Optional[float_deg] = None,
    wait: bool = True,
) -> None:
    """Wait: bool, block until stage movement is complete (JEOL only)"""
    self._setter(
        round(x) if x is not None else None,
        round(y) if y is not None else None,
        round(z) if z is not None else None,
        float(a) if a is not None else None,
        float(b) if b is not None else None,
        wait=wait,
    )
set_a_with_speed(a, speed, wait=False)

Rotate to angle a with speed (JEOL, Tecnai only).

wait: bool, block until stage movement is complete.

Source code in src/instamatic/microscope/components/stage.py
82
83
84
85
86
87
88
89
90
91
def set_a_with_speed(self, a: float, speed: AnyNumber, wait: bool = False) -> None:
    """Rotate to angle `a` with speed (JEOL, Tecnai only).

    wait: bool, block until stage movement is complete.
    """
    with self.rotation_speed(speed):
        self.set(a=a, wait=False)
    # Do not wait on `set` to return to normal rotation speed quickly
    if wait:
        self.wait()
set_rotation_speed(speed=1)

Sets the stage (rotation) movement speed on the TEM.

Source code in src/instamatic/microscope/components/stage.py
78
79
80
def set_rotation_speed(self, speed: AnyNumber = 1) -> None:
    """Sets the stage (rotation) movement speed on the TEM."""
    self._tem.setRotationSpeed(value=native(speed))
set_with_speed(x=None, y=None, z=None, a=None, b=None, wait=True, speed=1.0)

Note that this function only works on FEI machines.

wait: ignored, but necessary for compatibility with JEOL API speed: float, set stage rotation with specified speed (FEI only)

Source code in src/instamatic/microscope/components/stage.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def set_with_speed(
    self,
    x: Optional[int_nm] = None,
    y: Optional[int_nm] = None,
    z: Optional[int_nm] = None,
    a: Optional[float_deg] = None,
    b: Optional[float_deg] = None,
    wait: bool = True,
    speed: float = 1.0,
) -> None:
    """Note that this function only works on FEI machines.

    wait: ignored, but necessary for compatibility with JEOL API
    speed: float, set stage rotation with specified speed (FEI only)
    """
    self._setter(
        round(x) if x is not None else None,
        round(y) if y is not None else None,
        round(z) if z is not None else None,
        float(a) if a is not None else None,
        float(b) if b is not None else None,
        wait=wait,
        speed=native(speed),
    )
set_xy_with_backlash_correction(x=None, y=None, step=10000, settle_delay=0.2)

Move to new x/y position with backlash correction. This is done by approaching the target x/y position always from the same direction.

SerialEM uses the same approach (x first, y second, step=10000).

step: float, stepsize in nm settle_delay: float, delay between movements in seconds to allow the stage to settle

Source code in src/instamatic/microscope/components/stage.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def set_xy_with_backlash_correction(
    self,
    x: Optional[int_nm] = None,
    y: Optional[int_nm] = None,
    step: int_nm = 10000,
    settle_delay: float = 0.200,
) -> None:
    """Move to new x/y position with backlash correction. This is done by
    approaching the target x/y position always from the same direction.

    SerialEM uses the same approach (x first, y second, step=10000).

    step: float,
        stepsize in nm
    settle_delay: float,
        delay between movements in seconds to allow the stage to settle
    """
    wait = True
    if (x is None) or (y is None):
        current_x, current_y = self.xy
        x = current_x if x is None else x
        y = current_y if y is None else y
    self.set(x=x - step, y=y - step)
    if settle_delay:
        time.sleep(settle_delay)

    self.set(x=x, y=y, wait=wait)
    if settle_delay:
        time.sleep(settle_delay)
stop()

This will halt the stage preemptively if wait=False is passed to Stage.set.

Source code in src/instamatic/microscope/components/stage.py
239
240
241
242
def stop(self) -> None:
    """This will halt the stage preemptively if `wait=False` is passed to
    Stage.set."""
    self._tem.stopStage()
wait()

Blocking call that waits for stage movement to finish.

Source code in src/instamatic/microscope/components/stage.py
221
222
223
def wait(self) -> None:
    """Blocking call that waits for stage movement to finish."""
    self._tem.waitForStage()

Functions: