This page was generated from docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb. Interactive online version: Binder badge.

QCoDeS Example with DynaCool PPMS

This notebook explains how to control the DynaCool PPMS from QCoDeS.

For this setup to work, the proprietary PPMS Dynacool application (or, alternatively Simulate PPMS Dynacool) must be running on some PC. On that same PC, the server.py script (found in qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/private) must be running. The script can be run from the command line with no arguments and will run under python 3.6+.

The architecture is as follows:

The QCoDeS driver sends strings via VISA to the server who passes those same strings on to the CommandHandler (found in qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/commandhandler). The CommandHandler makes the calls into the proprietary API. The QCoDeS driver can thus be called on any machine that can communicate with the machine hosting the server.

Apart from that, the driver is really simple. For this notebook, we used the Simulate PPMS Dynacool application running on the same machine as QCoDeS.

[1]:
%matplotlib notebook
from qcodes.instrument_drivers.QuantumDesign import DynaCool

To instantiate the driver, simply provide the address and port in the standard VISA format. The connect message is not too pretty, but there does not seem to be a way to query serial and firmware versions.

[2]:
dynacool = DynaCool("dynacool", address="TCPIP0::127.0.0.1::5000::SOCKET")
Connected to:  QuantumDesign dynacool (serial:N/A, firmware:N/A) in 0.13s

To get an overview over all available parameters, use print_readable_snapshot.

A value of “Not available” means (for this driver) that the parameter has been deprecated.

[3]:
dynacool.print_readable_snapshot(update=True)
dynacool:
        parameter           value
--------------------------------------------------------------------------------
IDN                  :  {'vendor': ' QuantumDesign', 'model': 'dynacool', 'ser...
chamber_state        :  sealed
chamber_temperature  :  298.7 (K)
field                :  Not available (T)
field_approach       :  linear
field_measured       :  1 (T)
field_ramp           :  None (T)
field_rate           :  0 (T/s)
field_setpoint       :  Not available (T)
field_target         :  1 (T)
magnet_state         :  holding
temperature          :  298.7 (K)
temperature_rate     :  0 (K/s)
temperature_setpoint :  298.7 (K)
temperature_settling :  fast settle
temperature_state    :  near
timeout              :  5 (s)

Temperature Control

As soon as ANY of the temperature rate, the temperature setpoint, or the temperature settling mode parameters has been set, the system will start moving to the given temperature setpoint at the given rate using the given settling mode.

The system can continuously be queried for its temperature.

[4]:
from time import sleep

import matplotlib.pyplot as plt
import numpy as np

# example 1

dynacool.temperature_rate(0.1)
dynacool.temperature_setpoint(dynacool.temperature() - 1.3)

temps = []

while dynacool.temperature_state() == "tracking":
    temp = dynacool.temperature()
    temps.append(temp)
    sleep(0.75)
    print(f"Temperature is now {temp} K")
Temperature is now 298.70001220703125 K
Temperature is now 298.6000061035156 K
Temperature is now 298.5 K
Temperature is now 298.5 K
Temperature is now 298.3999938964844 K
Temperature is now 298.29998779296875 K
Temperature is now 298.1999816894531 K
Temperature is now 298.1999816894531 K
Temperature is now 298.0999755859375 K
Temperature is now 297.9999694824219 K
[5]:
plt.figure()
timeax = np.linspace(0, len(temps) * 0.2, len(temps))
plt.plot(timeax, temps, "-o")
plt.xlabel("Time (s)")
plt.ylabel("Temperature (K)")
[5]:
Text(0, 0.5, 'Temperature (K)')

Field Control

The field has five related parameters:

  • field_measured: The (read-only) field strength right now.

  • field_target: The target field that the ramp method will ramp to when called. Setting this parameter does not trigger a ramp

  • field_rate: The field ramp rate with initial value of 0.

  • field_approach: The approach that the system should use to ramp. By default it is set to linear.

  • field_ramp: This is a convenience parameter that sets the target field and then triggers a blocking ramp.

The idea is that the user first sets the field_target and then ramps the field to that target using the ramp method. The ramp method takes a mode argument that controls whether the ramp is blocking or non-blocking.

Using the simulation software, the field change is instanteneous irrespective of rate. We nevertheless include two examples of ramping here.

A blocking ramp

First, we set a field target:

[6]:
field_now = dynacool.field_measured()
target = field_now + 1
dynacool.field_target(target)

Note that the field has not changed yet:

[7]:
assert dynacool.field_measured() == field_now

And now we ramp:

[8]:
dynacool.ramp(mode="blocking")

The ramping will take some finite time on a real instrument. The field value is now at the target field:

[9]:
print(f"Field value: {dynacool.field_measured()} T")
print(f"Field target: {dynacool.field_target()} T")
Field value: 2.0 T
Field target: 2.0 T

A non-blocking ramp

The non-blocking ramp is very similar to the the blocking ramp.

[10]:
field_now = dynacool.field_measured()
target = field_now - 0.5
dynacool.field_target(target)

assert dynacool.field_measured() == field_now

dynacool.ramp(mode="non-blocking")
# Here you can do stuff while the magnet ramps

print(f"Field value: {dynacool.field_measured()} T")
print(f"Field target: {dynacool.field_target()} T")
Field value: 1.5 T
Field target: 1.5 T

Using the field_ramp parameter

The field_ramp parameter sets the target field and ramp when being set.

[11]:
print(f"Now the field is {dynacool.field_measured()} T...")
print(f"...and the field target is {dynacool.field_target()} T.")
Now the field is 1.5 T...
...and the field target is 1.5 T.
[12]:
dynacool.field_ramp(1)
[13]:
print(f"Now the field is {dynacool.field_measured()} T...")
print(f"...and the field target is {dynacool.field_target()} T.")
Now the field is 1.0 T...
...and the field target is 1 T.
[ ]: