Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QDAC1: Allow slopes greater than 10V #209

Merged
merged 4 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 62 additions & 14 deletions qcodes_contrib_drivers/drivers/QDevil/QDAC1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# QCoDeS driver for the QDevil QDAC using channels
# Adapted by QDevil from the qdev QDac driver in qcodes
# Version 2.1 QDevil 2020-02-10
# Version 2.2 QDevil 2023-02-20

import logging
import time
Expand Down Expand Up @@ -82,7 +82,7 @@ def __init__(self, parent: "QDac", name: str, channum: int):
label=f'Channel {channum} voltage',
unit='V',
set_cmd=partial(self._parent._set_voltage, channum),
get_cmd=f'set {channum}',
get_cmd=partial(self._parent._get_voltage, channum),
get_parser=float,
# Initial range. Updated on init and during
# operation:
Expand Down Expand Up @@ -444,6 +444,17 @@ def snapshot_base(
# Channel gets/sets
#########################

def _get_voltage(self, chan: int) -> str:
"""
Clear the output from the instrument and ask for the current voltage

Args:
chan (int): The 1-indexed channel number
"""
self.clear_read_queue()
self.write(f'set {chan}')
return self._write_response

def _set_voltage(self, chan: int, v_set: float) -> None:
"""
set_cmd for the chXX_v parameter
Expand All @@ -455,25 +466,38 @@ def _set_voltage(self, chan: int, v_set: float) -> None:
If a finite slope has been assigned, a function generator will
ramp the voltage.
"""

slope = self._slopes.get(chan, None)
if slope:
# We need .get and not cache/get_latest in case a ramp
# was interrupted
v_start = self.channels[chan-1].v.get()
duration = abs(v_set-v_start)/slope
LOG.info(f'Slope: {slope}, time: {duration}')
# SYNCing happens inside ramp_voltages
self.ramp_voltages([chan], [v_start], [v_set], duration)
else: # Should not be necessary to wav here.
if not slope:
# Should not be necessary to wav here.
self.write('wav {ch} 0 0 0;set {ch} {voltage:.6f}'
.format(ch=chan, voltage=v_set))
return
# We need .get and not cache/get_latest in case a ramp
# was interrupted
v_start = self.channels[chan-1].v.get()
v_span = v_set - v_start
v_amplitude = abs(v_span)
s_duration = v_amplitude / slope
LOG.info(f'Slope: {slope}, time: {s_duration}')
if v_amplitude <= 10:
# SYNCing happens inside ramp_voltages
self.ramp_voltages([chan], [v_start], [v_set], s_duration)
return
# Divide sweep into two parts
v_half_span = v_span / 2
s_half_duration = s_duration / 2
v_half_way = v_start + v_half_span
self.ramp_voltages([chan], [v_start], [v_half_way], s_half_duration)
LOG.warning('Trying to ramp more than 10 volts. '
'Waiting for first ramp to finish')
time.sleep(s_half_duration)
self.ramp_voltages([chan], [v_half_way], [v_set], s_half_duration)

def _set_mode(self, chan: int, new_mode: Mode) -> None:
"""
set_cmd for the QDAC's mode (combined voltage and current sense range).
It is not possible to switch from voltage range without setting the
the volage to zero first or set the global mode_force parameter True.
the voltage to zero first or set the global mode_force parameter True.
"""
def _clipto(value: float, min_: float, max_: float) -> float:
errmsg = ("Voltage is outside the bounds of the new voltage range"
Expand Down Expand Up @@ -786,6 +810,8 @@ def write(self, cmd: str) -> None:
self.visa_handle.write(cmd)
for _ in range(cmd.count(';')+1):
self._write_response = self.visa_handle.read()
if self._write_response.startswith('Error: '):
LOG.warning(self._write_response)

def read(self) -> str:
return self.visa_handle.read()
Expand All @@ -794,6 +820,26 @@ def _wait_and_clear(self, delay: float = 0.5) -> None:
time.sleep(delay)
self.visa_handle.clear()

def clear_read_queue(self) -> Sequence[str]:
"""
Flush the VISA message queue of the instrument

Waits 1 ms between each read.

Returns:
Sequence[str]: Messages lingering in queue
"""
lingering = list()
with self.timeout.set_to(0.001):
while True:
try:
message = self.visa_handle.read()
except pyvisa.VisaIOError:
break
else:
lingering.append(message)
return lingering

def connect_message(self,
idn_param: str = 'IDN',
begin_time: Optional[float] = None) -> None:
Expand All @@ -808,7 +854,7 @@ def connect_message(self,

def _get_firmware_version(self) -> float:
"""
Check if the "version" command reponds. If so we probbaly have a QDevil
Check if the "version" command reponds. If so we probably have a QDevil
QDAC, and the version number is returned. Otherwise 0.0 is returned.
"""
self.write('version')
Expand Down Expand Up @@ -1067,6 +1113,8 @@ def ramp_voltages_2d(
msg = ''
for i in range(no_channels):
amplitude = v_endlist[i]-v_startlist[i]
# TODO: if amplitute is too large, then split into two parts.
# if abs(amplitude) > 10: ...
ch = channellist[i]
fg = self._assigned_fgs[ch].fg
if trigger > 0: # Trigger 0 is not a trigger
Expand Down
4 changes: 1 addition & 3 deletions qcodes_contrib_drivers/tests/QDevil/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Simulated instrument:
$ source venv/bin/activate
$ pytest qcodes_contrib_drivers/tests/QDevil/test_sim_qdac2_*.py

To silence warnings, use `-W ignore::DeprecationWarning`.

Real instrument:

$ source venv/bin/activate
Expand All @@ -29,4 +27,4 @@ Static types:
$ source venv/bin/activate
$ pip install --upgrade pip
$ pip install -e .[test]
$ pip install pyvisa-py==0.5.2
$ pip install pyvisa-py==0.5.2 jupyter pyserial