-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'thorlab_drivers' of github.com:julienbarrier/Qcodes_con…
…trib_drivers into thorlab_drivers
- Loading branch information
Showing
2 changed files
with
206 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# This Python file uses the following encoding: utf-8 | ||
# Loick Le Guevel, 2019 | ||
# Etienne Dumur <[email protected]>, 2021 | ||
# Simon Zihlmann <[email protected]>, 2021 | ||
# Victor Millory <[email protected]>, 2021 | ||
|
||
from typing import Union, Tuple, Any | ||
from functools import partial | ||
|
@@ -42,7 +44,10 @@ def __init__(self, parent: Instrument, | |
get_cmd=partial(self._parent._get_voltage, chan_num), | ||
get_parser=float, | ||
set_cmd=partial(self._parent._set_voltage, chan_num), | ||
vals=vals.Numbers(-50, 50) | ||
inter_delay=self._parent._v_inter_delay, | ||
post_delay=self._parent._v_post_delay, | ||
step=self._parent._v_step, | ||
vals=vals.Numbers(-12, 12) | ||
) | ||
|
||
self.add_parameter('i', | ||
|
@@ -70,6 +75,7 @@ def __init__(self, parent: Instrument, | |
get_parser=str, | ||
set_cmd=partial(self._parent._set_output_function, chan_num), | ||
set_parser=str, | ||
initial_value='exp', | ||
vals=vals.Enum('ramp', 'exp') | ||
) | ||
|
||
|
@@ -79,55 +85,75 @@ def __init__(self, parent: Instrument, | |
set_cmd=partial(self._parent._set_chan_range, chan_num), | ||
set_parser=float, | ||
get_cmd=partial(self._parent._get_chan_range, chan_num), | ||
get_parser=float) | ||
get_parser=float, | ||
vals=vals.Numbers(1.2, 12) | ||
) | ||
|
||
self.add_parameter('state', | ||
docstring='State of the channel {on, off}.', | ||
get_cmd=partial(self._parent._get_chan_state, chan_num), | ||
set_cmd=partial(self._parent._set_chan_state, chan_num), | ||
val_mapping=create_on_off_val_mapping(on_val='1', | ||
off_val='0')) | ||
off_val='0') | ||
) | ||
|
||
self.add_parameter('pos_sat', | ||
get_cmd=partial(self._parent._get_chan_pos_sat, chan_num), | ||
get_parser=str, | ||
set_cmd=partial(self._parent._set_chan_pos_sat, chan_num), | ||
set_parser=str,) | ||
set_parser=str, | ||
initial_value=12 | ||
) | ||
|
||
self.add_parameter('neg_sat', | ||
get_cmd=partial(self._parent._get_chan_neg_sat, chan_num), | ||
get_parser=str, | ||
set_cmd=partial(self._parent._set_chan_neg_sat, chan_num), | ||
set_parser=str,) | ||
set_parser=str, | ||
initial_value=-12 | ||
) | ||
|
||
self.add_parameter('bilt_name', | ||
set_cmd=partial(self._parent._set_chan_name, chan_num), | ||
set_parser=str, | ||
initial_value=f'Chan{chan_num:02d}') | ||
initial_value=f'Chan{chan_num:02d}' | ||
) | ||
|
||
self.add_parameter('synchronous_enable', | ||
docstring='Is the channel in synchronous mode.', | ||
get_cmd=None, | ||
get_parser=bool, | ||
set_cmd=None, | ||
vals=vals.Bool(), | ||
initial_value=True) | ||
initial_value=False | ||
) | ||
|
||
self.add_parameter('synchronous_delay', | ||
docstring='Time between to voltage measurement in second.', | ||
get_cmd=None, | ||
get_parser=float, | ||
set_cmd=None, | ||
vals=vals.Numbers(1e-3, 10), | ||
initial_value=1e-3) | ||
initial_value=1e-3 | ||
) | ||
|
||
self.add_parameter('synchronous_threshold', | ||
docstring='Threshold to unblock communication in volt.', | ||
get_cmd=None, | ||
get_parser=float, | ||
set_cmd=None, | ||
vals=vals.Numbers(0, 1e-3), | ||
initial_value=1e-5) | ||
initial_value=1e-5 | ||
) | ||
|
||
self.add_parameter('v_autorange', | ||
docstring='If the voltage autorange is activated.', | ||
get_cmd=partial(self._parent._get_chan_v_autorange, chan_num), | ||
get_parser=bool, | ||
set_cmd=partial(self._parent._set_chan_v_autorange, chan_num), | ||
vals=vals.Bool(), | ||
initial_value=False | ||
) | ||
|
||
|
||
def start(self) -> None: | ||
|
@@ -143,7 +169,11 @@ def stop(self) -> None: | |
""" | ||
self._parent._set_chan_state(self.chan_num, '0') | ||
|
||
|
||
def clear_alarm(self) -> None: | ||
""" | ||
Clear the alarm and warnings of the channel. | ||
""" | ||
self._parent._clear_chan_alarm(self.chan_num) | ||
|
||
class iTestMultiChannelParameter(MultiChannelInstrumentParameter): | ||
""" | ||
|
@@ -162,9 +192,12 @@ def __init__(self,name:str, | |
address:str, | ||
num_chans:int=16, | ||
init_start:bool=False, | ||
synchronous_enable:bool=True, | ||
synchronous_enable:bool=False, | ||
synchronous_delay:float=1, | ||
synchronous_threshold:float=1e-5, | ||
v_inter_delay:float=5e-3, | ||
v_post_delay:float=45e-3, # settling time to 99% | ||
v_step:float=20e-3, | ||
**kwargs: Any) -> None: | ||
""" | ||
Instantiate the instrument. | ||
|
@@ -173,15 +206,18 @@ def __init__(self,name:str, | |
name: The instrument name used by qcodes | ||
address: The VISA name of the resource | ||
num_chans: Number of channels to assign. Default: 16 | ||
init_start: If true set all channels to 0V, 1.2V range and switch | ||
then on. | ||
init_start: If true: set all channels to 0V, 12V range, exponential mode and switch | ||
them on. | ||
synchronous_enable: If true, block the communication until the set voltage | ||
is reached. The communication is block through a simple while loop | ||
with a waiting time "synchronous_delay" at each iteration until the | ||
set voltage and the measured voltage difference is below | ||
"synchronous_threshold". | ||
synchronous_delay: Time between to voltage measurement in second. | ||
synchronous_threshold: Threshold to unblock communication in volt. | ||
v_inter_delay: delay in units of s between setting new value of the voltage parameter, defaults to 5e-3. | ||
v_post_delay: delay in units of s after setting voltage parameter to final value, defaults to 45e-3. | ||
v_step: max step size of the voltage parameter in units of V, defaults to 20e-3. | ||
Returns: | ||
ITest object | ||
|
@@ -193,6 +229,9 @@ def __init__(self,name:str, | |
|
||
self.idn = self.get_idn() | ||
self.num_chans = num_chans | ||
self._v_inter_delay = v_inter_delay | ||
self._v_post_delay = v_post_delay | ||
self._v_step = v_step | ||
self.chan_range = range(1,self.num_chans+1) | ||
|
||
# Create the channels | ||
|
@@ -205,9 +244,6 @@ def __init__(self,name:str, | |
|
||
channel = iTestChannel(self, name='chan{:02}'.format(i), | ||
chan_num=i) | ||
channel.synchronous_enable(synchronous_enable) | ||
channel.synchronous_delay(synchronous_delay) | ||
channel.synchronous_threshold(synchronous_threshold) | ||
channels.append(channel) | ||
self.add_submodule('ch{:02}'.format(i),channel) | ||
|
||
|
@@ -216,13 +252,16 @@ def __init__(self,name:str, | |
|
||
if init_start: | ||
for channel in self.channels: | ||
channel.stop() | ||
channel.v.set(0) | ||
channel.v_range(1.2) | ||
channel.v_range(12) | ||
channel.v_autorange(False) | ||
channel.synchronous_enable(False) | ||
channel.output_mode('exp') | ||
channel.start() | ||
|
||
self.connect_message() | ||
|
||
|
||
def _set_voltage(self, chan:int, | ||
v_set:float) -> None: | ||
""" | ||
|
@@ -241,7 +280,6 @@ def _set_voltage(self, chan:int, | |
sleep(self.channels[chan-1].synchronous_delay()) | ||
v = self._get_voltage(chan) | ||
|
||
|
||
def _get_voltage(self, chan:int) -> float: | ||
""" | ||
Get cmd for the chXX_v parameter | ||
|
@@ -256,7 +294,6 @@ def _get_voltage(self, chan:int) -> float: | |
|
||
return float(self.ask('{}MEAS:VOLT?'.format(chan_id))) | ||
|
||
|
||
def _get_current(self, chan:int) -> float: | ||
""" | ||
Get cmd for the chXX_i parameter | ||
|
@@ -271,7 +308,6 @@ def _get_current(self, chan:int) -> float: | |
|
||
return float(self.ask('{}MEAS:CURR?'.format(chan_id))) | ||
|
||
|
||
def _set_ramp_slope(self, chan:int, | ||
slope:float) -> None: | ||
""" | ||
|
@@ -284,7 +320,6 @@ def _set_ramp_slope(self, chan:int, | |
chan_id = self.chan_to_id(chan) | ||
self.write('{}VOLT:SLOP {:.8f}'.format(chan_id, slope)) | ||
|
||
|
||
def _get_ramp_slope(self, chan:int) -> str: | ||
""" | ||
Get slope of chXX | ||
|
@@ -298,7 +333,6 @@ def _get_ramp_slope(self, chan:int) -> str: | |
chan_id = self.chan_to_id(chan) | ||
return self.ask('{}VOLT:SLOP?'.format(chan_id)) | ||
|
||
|
||
def _set_output_function(self, chan:int, | ||
outf:str) -> None: | ||
""" | ||
|
@@ -319,7 +353,6 @@ def _set_output_function(self, chan:int, | |
|
||
self.write(chan_id + 'trig:input ' + mode) | ||
|
||
|
||
def _get_output_function(self, chan:int) -> str: | ||
""" | ||
Get output volage update function | ||
|
@@ -339,7 +372,6 @@ def _get_output_function(self, chan:int) -> str: | |
else: | ||
raise ValueError('Got unexpected output function mode: {}.'.format(mode)) | ||
|
||
|
||
def _set_chan_range(self, chan:int, | ||
volt: float) -> None: | ||
""" | ||
|
@@ -350,8 +382,16 @@ def _set_chan_range(self, chan:int, | |
volt : Voltage range (1.2 or 12) | ||
""" | ||
chan_id = self.chan_to_id(chan) | ||
self.write(chan_id + 'VOLT:RANGE ' + str(volt)) | ||
|
||
if self._get_chan_state(chan)=='1': | ||
print('Channel {} is on and therefore the range cannot be changed. Turn it off first.'.format(chan)) | ||
else: | ||
# update the pos and neg saturation parameter | ||
self._set_chan_pos_sat(chan, abs(volt)) | ||
self._set_chan_neg_sat(chan, -abs(volt)) | ||
# self.channels[chan-1].v.vals=vals.Numbers(-abs(volt), abs(volt)) #does not work, throws an error at init since channels are not yet attached to instrument | ||
# --> solve problem by moving all the communication functions to the level of the channel and not on the leel of instrument. Like this other parameters from the same channel are easily accessible via self.parameter | ||
# change the range | ||
self.write(chan_id + 'VOLT:RANGE ' + str(volt)) | ||
|
||
def _get_chan_range(self, chan:int) -> str: | ||
""" | ||
|
@@ -367,6 +407,35 @@ def _get_chan_range(self, chan:int) -> str: | |
|
||
return self.ask(chan_id + 'VOLT:RANGE?')[:-2] | ||
|
||
def _get_chan_v_autorange(self, chan:int) -> bool: | ||
""" | ||
Get the channel voltage autorange state | ||
Args: | ||
chan: The 1-indexed channel number | ||
Returns: | ||
chXX_v_autorange parameter | ||
""" | ||
chan_id = self.chan_to_id(chan) | ||
v_autorange_state = self.ask('{}VOLT:RANGE:AUTO?'.format(chan_id)) | ||
|
||
if v_autorange_state in ['1', '0'] : | ||
return True if v_autorange_state=='1' else False | ||
else: | ||
raise ValueError('Unknown state output: {}'.format(v_autorange_state)) | ||
return False | ||
|
||
def _set_chan_v_autorange(self, chan:int, state:bool) -> None: | ||
""" | ||
Set channel voltage autorange state | ||
Args: | ||
chan: The 1-indexed channel number | ||
state: power state | ||
""" | ||
chan_id = self.chan_to_id(chan) | ||
self.write(chan_id + 'VOLT:RANGE:AUTO {}'.format('1' if(state) else '0') ) | ||
|
||
def _set_chan_pos_sat(self, chan:int, | ||
pos_sat: Union[float, str]) -> None: | ||
|
@@ -376,7 +445,6 @@ def _set_chan_pos_sat(self, chan:int, | |
elif isinstance(pos_sat,str): | ||
self.write(chan_id + 'VOLT:SAT:POS MAX') | ||
|
||
|
||
def _set_chan_neg_sat(self, chan:int, | ||
neg_sat: Union[float, str]) -> None: | ||
chan_id = self.chan_to_id(chan) | ||
|
@@ -385,17 +453,14 @@ def _set_chan_neg_sat(self, chan:int, | |
elif isinstance(neg_sat,str): | ||
self.write(chan_id + 'VOLT:SAT:NEG MIN') | ||
|
||
|
||
def _get_chan_pos_sat(self, chan:int) -> str: | ||
chan_id = self.chan_to_id(chan) | ||
return self.ask(chan_id + 'VOLT:SAT:POS ?') | ||
|
||
|
||
def _get_chan_neg_sat(self, chan:int) -> str: | ||
chan_id = self.chan_to_id(chan) | ||
return self.ask(chan_id + 'VOLT:SAT:NEG ?') | ||
|
||
|
||
def _get_chan_state(self, chan:int) -> str: | ||
""" | ||
Get channel power state | ||
|
@@ -414,7 +479,6 @@ def _get_chan_state(self, chan:int) -> str: | |
else: | ||
raise ValueError('Unknown state output: {}'.format(state)) | ||
|
||
|
||
def _set_chan_state(self, chan:int, | ||
state:str) -> None: | ||
""" | ||
|
@@ -427,7 +491,6 @@ def _set_chan_state(self, chan:int, | |
chan_id = self.chan_to_id(chan) | ||
self.write(chan_id + 'OUTP ' + state) | ||
|
||
|
||
def _set_chan_name(self, chan:int, | ||
name: str) -> None: | ||
""" | ||
|
@@ -440,6 +503,16 @@ def _set_chan_name(self, chan:int, | |
chan_id = self.chan_to_id(chan) | ||
self.write(chan_id + 'chan:name "{}"'.format(name)) | ||
|
||
def _clear_chan_alarm(self, chan:int) -> None: | ||
""" | ||
Clear the alarm/warning for a given channel | ||
Args: | ||
chan: The 1-indexed channel number | ||
""" | ||
chan_id = self.chan_to_id(chan) | ||
self.write(chan_id + 'LIM:CLEAR') | ||
self.write(chan_id + 'STAT:CLEAR') | ||
|
||
def chan_to_ic(self, chan:int) -> Tuple[int, int]: | ||
""" | ||
|
@@ -455,8 +528,21 @@ def chan_to_ic(self, chan:int) -> Tuple[int, int]: | |
c = chan-(i-1)*4 | ||
return i,c | ||
|
||
|
||
def chan_to_id(self, chan:int) -> str: | ||
i,c = self.chan_to_ic(chan) | ||
|
||
return 'i{};c{};'.format(i,c) | ||
|
||
def set_dacs_zero(self) -> None: | ||
""" | ||
Ramp all voltages to zero. | ||
""" | ||
for ch in self.channels: | ||
ch.v(0) | ||
|
||
def print_dac_voltages(self) -> None: | ||
""" | ||
Prints the voltage of all channels to cmdl. | ||
""" | ||
for ch in self.channels: | ||
print('voltage on {}:{} {}'.format(ch.name, ch.v(), ch.v.unit)) |
Oops, something went wrong.