# This file is part of the scanning-squid package.
#
# Copyright (c) 2018 Logan Bishop-Van Horn
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from qcodes import VisaInstrument
import qcodes.utils.validators as vals
import logging
log = logging.getLogger(__name__)
[docs]class DG645(VisaInstrument):
"""Qcodes driver for SRS DG645 digital delay generator.
Not all instrument functionality is included here.
Logan Bishop-Van Horn (2018)
"""
def __init__(self, name, address, **kwargs):
super().__init__(name, address, terminator='\r\n', timeout=10, **kwargs)
self.channel_mapping = {
'T0': 0, 'T1': 1, 'A': 2, 'B': 3, 'C': 4,
'D': 5, 'E': 6, 'F': 7, 'G': 8, 'H': 9
}
self.output_mapping = {'T0': 0, 'AB': 1, 'CD': 2, 'EF': 3, 'GH': 4}
# self.display_mapping = {
# 'trig_rate': 0,
# 'trig_thresh': 1,
# 'trig_single_shot': 2,
# 'trig_line': 3,
# 'advanced_trig_enable': 4,
# 'trig_holdoff': 5,
# 'prescale_config': 6,
# 'burst_mode': 7,
# 'burst_delay': 8,
# 'burst_count': 9,
# 'burst_period': 10,
# 'channel_delay': 11,
# 'channel_output_levels': 12,
# 'channel_output_polarity': 13,
# 'burst_T0_config': 14
# }
self.prescale_mapping = {'trig': 0, 'AB': 1, 'CD': 2, 'EF': 3, 'GH': 4}
self.trig_mapping = {
'internal': 0,
'ext_rising': 1,
'ext_falling': 2,
'single_ext_rising': 3,
'single_ext_falling': 4,
'single': 5,
'line': 6
}
self.polarity_mapping = {'-': 0, '+': 1}
self.add_parameter('trig_holdoff',
label='Trigger holdoff',
unit='s',
get_cmd='HOLD?',
get_parser=float,
set_cmd='HOLD {}'
)
#: Prescale parameters
for k, v in self.prescale_mapping.items():
if v > 0:
self.add_parameter('phase_{}'.format(k),
label='Prescale phase factor {}'.format(k),
unit='',
get_cmd=lambda ch=k: self._get_phase_prescale(ch),
get_parser=int,
set_cmd=lambda val, ch=k: self._set_phase_prescale(val, channel=ch),
vals=vals.Ints(min_value=0)
)
self.add_parameter('prescale_{}'.format(v),
label='Prescale factor {}'.format(v),
unit='',
get_cmd=lambda ch=k: self._get_prescale(ch),
get_parser=int,
set_cmd=lambda val, ch=k: self._set_prescale(val, channel=ch),
vals=vals.Ints(min_value=0)
)
#: Trigger parameters
self.add_parameter('trig_level',
label='Trigger level',
unit='V',
get_cmd='TLVL?',
get_parser=float,
set_cmd='TLVL {}',
vals=vals.Numbers()
)
self.add_parameter('trig_rate',
label='Trigger rate',
unit='Hz',
get_cmd='TRAT?',
get_parser=float,
set_cmd='TRAT {}',
vals=vals.Numbers(min_value=0)
)
self.add_parameter('trig_source',
label='Trigger source',
unit='',
get_cmd=self._get_trig_source,
get_parser=str,
set_cmd=self._set_trig_source,
vals=vals.Enum(tuple(self.trig_mapping.keys()))
)
#: Burst parameters
self.add_parameter('burst_count',
label='Burst count',
unit='',
get_cmd='BURC?',
get_parser=int,
set_cmd='BURC {}',
vals=vals.Ints(min_value=0)
)
self.add_parameter('burst_delay',
label='Burst delay',
unit='s',
get_cmd='BURD?',
get_parser=float,
set_cmd='BURD {}',
vals=vals.Numbers(min_value=0)
)
self.add_parameter('burst_period',
label='Burst period',
unit='s',
get_cmd='BURP?',
get_parser=float,
set_cmd='BURC {}',
vals=vals.Numbers(min_value=100e-9, max_value=2000-10e-9)
)
self.add_parameter('burst_T0_config',
label='Burst T0 configuration',
unit='',
get_cmd='BURT?',
get_parser=int,
set_cmd='BURT {}',
vals=vals.Enum(0,1)
)
#: Channel parameters
for ch, idx in self.channel_mapping.items():
if idx > 1:
self.add_parameter('delay_{}'.format(ch),
label='{} delay'.format(ch),
unit='s',
get_cmd=lambda c=ch: self._get_delay(channel=c),
get_parser=str,
set_cmd=lambda src_delay, c=ch: self._set_delay(src_delay, target=c),
vals=vals.Strings()
)
self.add_parameter('channel_link_{}'.format(ch),
label='Channel linked to {}'.format(ch),
unit='',
get_cmd=lambda c=ch: self._get_link(channel=c),
get_parser=int,
set_cmd=lambda d, c=ch: self._set_link(d, channel=c),
vals=vals.Enum(tuple(k for k in self.channel_mapping if k != 'T1'))
)
#: Output parameters
for out, idx in self.output_mapping.items():
self.add_parameter('amp_out_{}'.format(out),
label='Output {} amplitude'.format(out),
unit='V',
get_cmd=lambda o=out: self._get_amp(output=o),
get_parser=float,
set_cmd=lambda lvl, o=out: self._set_amp(lvl, output=o),
vals=vals.Numbers()
)
self.add_parameter('offset_out_{}'.format(out),
label='Output {} offset'.format(out),
unit='V',
get_cmd=lambda o=out: self._get_offset(output=o),
get_parser=float,
set_cmd=lambda lvl, o=out: self._set_offset(lvl, output=o),
vals=vals.Numbers()
)
self.add_parameter('polarity_out_{}'.format(out),
label='Output {} polarity'.format(out),
unit='',
get_cmd=lambda o=out: self._get_polarity(output=o),
get_parser=int,
set_cmd=lambda lvl, o=out: self._set_offset(lvl, output=o),
vals=vals.Enum(0,1)
)
self.snapshot(update=True)
self.connect_message()
[docs] def calibrate(self) -> None:
"""Run auto-calibration routine.
"""
self.write('*CAL?')
self.wait()
[docs] def self_test(self) -> None:
"""Run self-test routine.
"""
self.write('*TST?')
self.wait()
[docs] def reset(self) -> None:
"""Reset instrument.
"""
log.info('Resetting {}.'.format(self.name))
self.write('*RST')
[docs] def save_settings(self, location: int) -> None:
"""Save instrument settings to given location.
Args:
location: Location to which to save the settings (in [1..9]).
"""
log.info('Saving instrument settings to location {}.'.format(location))
self.write('*SAV {}'.format(location))
[docs] def trigger(self) -> None:
"""Initiates a single trigger if instrument is in single shot mode.
"""
self.write('*TRG')
[docs] def wait(self) -> None:
"""Wait for all prior commands to execute before continuing.
"""
self.write('*WAI')
[docs] def local(self) -> None:
"""Go to local.
"""
self.write('LCAL')
[docs] def remote(self) -> None:
"""Go to remote.
"""
self.write('REMT')
def _get_phase_prescale(self, channel: str) -> str:
return self.ask('PHAS?{}'.format(self.prescale_mapping[channel]))
def _set_phase_prescale(self, value: int, channel: str=None) -> None:
self.write('PHAS {},{}'.format(self.prescale_mapping[channel], value))
def _get_prescale(self, channel: str) -> str:
return self.ask('PRES?{}'.format(self.prescale_mapping[channel]))
def _set_prescale(self, value: int, channel: str=None) -> None:
self.write('PRES {},{}'.format(self.prescale_mapping[channel], value))
def _set_trig_source(self, src: str) -> None:
self.write('TSRC {}'.format(self.trig_mapping[src]))
def _get_trig_source(self) -> str:
response = self.ask('TSRC?')
keys = self.trig_mapping.keys()
values = self.trig_mapping.values()
return list(keys)[list(values).index(int(response))]
def _get_delay(self, channel: str=None) -> str:
return self.ask('DLAY?{}'.format(self.channel_mapping[channel]))
def _set_delay(self, src_delay: str, target: str=None) -> None:
source, delay = [s.strip() for s in src_delay.split(',')]
self.write('DLAY {},{},{}'.format(self.channel_mapping[target],
self.channel_mapping[source],
delay))
def _get_amp(self, output: str=None) -> str:
return self.ask('LAMP?{}'.format(self.output_mapping[output]))
def _set_amp(self, lvl: float, output: str=None) -> None:
self.write('LAMP {},{}'.format(lvl, self.output_mapping[output]))
def _get_link(self, channel: str=None) -> str:
return self.ask('LINK?{}'.format(self.channel_mapping[channel]))
def _set_link(self, target: str, source: str=None) -> None:
self.write('LINK {},{}'.format(self.channel_mapping[source],
self.channel_mapping[target]))
def _get_offset(self, output: str=None) -> str:
return self.ask('LOFF?{}'.format(self.output_mapping[output]))
def _set_offset(self, off: float, output: str=None) -> None:
self.write('LOFF {},{}'.format(off, self.output_mapping[output]))
def _get_polarity(self, output: str=None) -> str:
return self.ask('LPOL?{}'.format(self.output_mapping[output]))
def _set_polarity(self, pol: int, output: str=None) -> None:
self.write('LPOL {},{}'.format(pol, self.output_mapping[output]))
[docs] def clear_instances(self):
"""Clear instances of DG645 Instruments.
"""
for instance in self.instances():
self.remove_instance(instance)