From 990d9989cb8bce26d7c3887858f29a91abff1c7b Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Thu, 14 Sep 2017 11:45:34 +1000 Subject: [PATCH 01/77] Add channel list validator. The channel list validator checks whether an object is an instance in a given channel list. --- qcodes/instrument/channel.py | 52 +++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/channel.py b/qcodes/instrument/channel.py index 9868effa5af..2ed862ad811 100644 --- a/qcodes/instrument/channel.py +++ b/qcodes/instrument/channel.py @@ -3,6 +3,7 @@ from .base import InstrumentBase, Instrument from .parameter import MultiParameter, ArrayParameter +from ..utils.validators import Validator from ..utils.metadata import Metadatable from ..utils.helpers import full_class @@ -108,7 +109,6 @@ def full_names(self): return self.names - class ChannelList(Metadatable): """ Container for channelized parameters that allows for sweeps over @@ -301,6 +301,15 @@ def insert(self, index: int, obj: InstrumentChannel): return self._channels.insert(index, obj) + def get_validator(self): + """ + Returns a validator that checks that the returned object is a channel + in this channel list + """ + if not self._locked: + raise AttributeError("Cannot create a validator for an unlocked channel list") + return ChannelListValidator(self) + def lock(self): """ Lock the channel list. Once this is done, the channel list is @@ -421,3 +430,44 @@ def __dir__(self) -> list: names += list(self._channels[0].functions.keys()) names += [channel.short_name for channel in self._channels] return sorted(set(names)) + + +class ChannelListValidator(Validator): + """ + A validator that checks that the returned object is a member of the + channel list with which the validator was constructed. + + This class will not normally be created directly, but created from a channel + list using the `ChannelList.get_validator` method. + + Args: + channel_list (ChannelList): the channel list that should be checked against. + The channel list must be locked and populated before it can be used to + construct a validator. + """ + def __init__(self, channel_list: ChannelList): + # Save the base parameter list + if not isinstance(channel_list, ChannelList): + raise ValueError("channel_list must be a ChannelList object containing the " + "channels that should be validated") + if not channel_list._locked: + raise AttributeError("Channel list must be locked before it can be used " + "to create a validator") + self._channel_list = channel_list + + def validate(self, value: InstrumentChannel, context: str): + """ + Checks to see that value is a member of the channel list referenced by this + validator + + Args: + value (InstrumentChannel): the value to be checked against the reference + channel list. + + context (string): the context of the call, used as part of the exception + raised. + """ + if value not in self._channel_list: + raise ValueError( + '{} is not part of the expected channel list; {}'.format( + repr(value), context)) \ No newline at end of file From 98e84b9e5421ad5ddc9f158e23779ad568b4437e Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Thu, 14 Sep 2017 11:47:11 +1000 Subject: [PATCH 02/77] Add nothing validator. The nothing validator will always fail, with an optional reason given at construction. --- qcodes/utils/validators.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py index f66f8256cca..88138faefb7 100644 --- a/qcodes/utils/validators.py +++ b/qcodes/utils/validators.py @@ -70,13 +70,27 @@ def __init__(self): def validate(self, value, context=''): pass # NOTE(giulioungaretti): why is_numeric? - # it allows fort set_step in parameter + # it allows for set_step in parameter # TODO(giulioungaretti): possible refactor is_numeric = True def __repr__(self): return '' +class Nothing(Validator): + """allow no value to pass""" + + def __init__(self, reason): + if reason: + self.reason = reason + else: + self.reason = "Nothing Validator" + + def validate(self, value, context=''): + raise TypeError("{}; {}".format(self.reason, context)) + + def __repr__(self): + return ''.format(self.reason) class Bool(Validator): """ From fbed338e5ed249c023312a41a22e6a16e0aba132 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Thu, 14 Sep 2017 11:47:58 +1000 Subject: [PATCH 03/77] Adds a complete yokogawa driver. --- qcodes/instrument_drivers/yokogawa/GS200.py | 335 +++++++++++++++++++- 1 file changed, 321 insertions(+), 14 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 26283396322..d6ad4c8f8c1 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,5 +1,132 @@ -from qcodes.instrument.visa import VisaInstrument -from qcodes.utils.validators import Numbers +from qcodes import VisaInstrument, InstrumentChannel +from qcodes.instrument.parameter import ManualParameter +from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints + +def float_int(val): + """ + Parses int that are returned in exponentiated form (i.e. 1E0) + """ + return int(float(val)) + +class GS200Exception(Exception): + pass + +class GS200_Monitor(InstrumentChannel): + def __init__(self, parent, name, present): + super().__init__(parent, name) + + # Is the feature installed in the instrument + self.present = present + # Start off with all disabled + self._enabled = False + self._output = False + # Set up monitoring paramters + if present: + self.add_parameter('enabled', + label='Measurement Enabled', + get_cmd=self.state, + set_cmd=lambda x: self.on() if x else self.off(), + val_mapping={ + 'off': 0, + 'on': 1, + }) + + # Note: Measurement will only run if source and measurement is enabled. + self.add_parameter('measure', + label='', unit='V/I', + get_cmd=self._get_measurement) + + self.add_parameter('NPLC', + label='NPLC', + unit='1/LineFreq', + vals=Ints(1, 25), + set_cmd=':SENS:NPLC {}', + set_parser=int, + get_cmd=':SENS:NPLC?', + get_parser=float_int) + self.add_parameter('delay', + label='Measurement Delay', + unit='ms', + vals=Ints(0, 999999), + set_cmd=':SENS:DEL {}', + set_parser=int, + get_cmd=':SENS:DEL?', + get_parser=float_int) + self.add_parameter('trigger', + label='Trigger Source', + set_cmd=':SENS:TRIG {}', + get_cmd=':SENS:TRIG?', + val_mapping={ + 'READY': 'READ', + 'READ': 'READ', + 'TIMER': 'TIM', + 'TIM': 'TIM', + 'COMMUNICATE': 'COMM', + 'IMMEDIATE': 'IMM', + 'IMM': 'IMM' + }) + self.add_parameter('interval', + label='Measurement Interal', + unit='s', + vals=Numbers(0.1, 3600), + set_cmd=':SENS:INT {}', + set_parser=float, + get_cmd=':SENS:INT?', + get_parser=float) + + self.add_function('on', call_cmd=self.on) + self.add_function('off', call_cmd=self.off) + + def off(self): + self.write(':SENS 0') + self._enabled = False + def on(self): + self.write(':SENS 1') + self._enabled = True + def state(self): + state = int(self.ask(':SENS?')) + self._enabled = bool(state) + return state + + def _get_measurement(self): + """ Check that measurements are enabled and then take a measurement """ + if not self._enabled or not self._output: + # Check if the output is on + self._output = self._output or self._parent.output.get() == 'on' + + if self._parent.auto_range.get() or (self._unit == 'VOLT' and self._range < 1): + # Measurements will not work with autorange, or when range is <1V + self._enabled = False + elif not self._enabled: + # Otherwise check if measurements are enabled + self._enabled = (self.enabled.get() == 'on') + # If enabled and output is on, then we can perform a measurement + if self._enabled and self._output: + return float(self.ask(':MEAS?')) + # Otherwise raise an exception + elif not self._output: + raise GS200Exception("Output is off") + elif self._parent.auto_range.get(): + raise GS200Exception("Measurements will not work when in autorange mode") + elif self._unit == "VOLT" and self._range < 1: + raise GS200Exception("Measurements will not work when range is <1V") + elif not self._enabled: + raise GS200Exception("Measurements are disabled") + + def _update_measurement_enabled(self, unit, output_range, output): + # Recheck measurement state next time we do a measurement + self._enabled = False + # Update output state + self._output = output + # Update units + self._range = output_range + self._unit = unit + if self._unit == 'VOLT': + self.measure.label = 'Source Current' + self.measure.unit = 'I' + else: + self.measure.label = 'Source Voltage' + self.measure.unit = 'V' class GS200(VisaInstrument): @@ -10,29 +137,209 @@ class GS200(VisaInstrument): name (str): What this instrument is called locally. address (str): The GPIB address of this instrument kwargs (dict): kwargs to be passed to VisaInstrument class - - TODO:(nataliejpg) - - add current functionality (mode settings) """ def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) + self.visa_handle.read_termination = "\r\n" + + self.add_parameter('output', + label='Output State', + get_cmd=self.state, + set_cmd=lambda x: self.on() if x else self.off(), + val_mapping={ + 'off': 0, + 'on': 1, + }) + + self.add_parameter('source_mode', + label='Source Mode', + get_cmd=':SOUR:FUNC?', + set_cmd=self._set_source_mode, + get_parser=self._get_source_mode, + vals=Enum('VOLT', 'CURR')) + self.add_parameter('range', + label='Source Range', + unit='?', # This will be set by the get/set parser + get_cmd=':SOUR:RANG?', + set_cmd=':SOUR:RANG {}', + get_parser=self._getset_range, + set_parser=self._getset_range) + self._auto_range = False + self.add_parameter('auto_range', + label='Auto Range', + set_cmd=self._set_auto_range, + get_cmd=lambda: self._auto_range, + vals=Bool()) + + # Note: Get and set for voltage/current will be updated by once + # range and mode are known self.add_parameter('voltage', label='Voltage', unit='V', - get_cmd=':SOURce:LEVel?', - set_cmd=':SOURce:LEVel:AUTO {:.4f}', + set_cmd=lambda x:0, get_cmd=lambda:0) + self.add_parameter('current', + label='Current', + unit='I', + set_cmd=lambda x:0, get_cmd=lambda:0) + + self.add_parameter('voltage_limit', + label='Voltage Protection Limit', + unit='V', + vals=Ints(1, 30), + get_cmd=":SOUR:PROT:VOLT?", + set_cmd=":SOUR:PROT:VOLT {}", + get_parser=float_int, + set_parser=int) + self.add_parameter('current_limit', + label='Current Protection Limit', + unit='I', + vals=Numbers(1e-3, 200e-3), + get_cmd=":SOUR:PROT:CURR?", + set_cmd=":SOUR:PROT:CURR {:.3f}", get_parser=float, - vals=Numbers(-10, 10)) + set_parser=float) + + self.add_parameter('four_wire', + label='Four Wire Sensing', + get_cmd=':SENS:REM?', + set_cmd=':SENS:REM {}', + val_mapping={ + 'off': 0, + 'on': 1, + }) + # Note: This feature can be used to remove common mode noise. + # Read the manual to see if you would like to use it + self.add_parameter('guard', + label='Guard Terminal', + get_cmd=':SENS:GUAR?', + set_cmd=':SENS:GUAR {}', + val_mapping={ + 'off': 0, + 'on': 1, + }) + # Return measured line frequency + self.add_parameter("line_freq", + label='Line Frequency', + unit="Hz", + get_cmd="SYST:LFR?", + get_parser=int) + + # Check if monitor is present, and if so enable measurement + monitor_present = '/MON' in self.ask("*OPT?") + measure = GS200_Monitor(self, 'measure', monitor_present) + self.add_submodule('measure', measure) + + # Reset function self.add_function('reset', call_cmd='*RST') + # Output functions + self.add_function('on', call_cmd=self.on) + self.add_function('off', call_cmd=self.off) - self.initialise() self.connect_message() - def initialise(self): - self.write(':SYST:DISP ON') - self.write(':SOUR:FUNC VOLT') - self.write(':SOUR:PROT:CURR MIN') - self.write(':OUTP:STAT ON') + # Update the source ranges and output state + # This will query mode and range + self.output.get() + self.source_mode.get() + + def on(self): + self.write('OUTPUT 1') + self.measure._output = True + + def off(self): + self.write('OUTPUT 0') + self.measure._output = False + + def state(self): + state = int(self.ask('OUTPUT?')) + self.measure._output = bool(state) + return state + + def _update_vals(self, source_mode=None, source_range=None): + # Update source mode + if source_mode is None: + source_mode = self.ask(":SOUR:FUNC?") + # Get source range if auto-range is off + if source_range is None and not self.auto_range.get(): + source_range = float(self.ask("SOUR:RANG?")) + + # Setup source based on what mode we are in + # Range is updated if auto-range is off + if source_mode == 'VOLT': + self.current._set_set(None, None) + self.current._set_get(None, None) + if self.auto_range.get(): + self.voltage._set_set(":SOUR:LEV:AUTO {:.5e}", float) + else: + self.voltage._set_set(":SOUR:LEV {:.5e}", float) + self.voltage._set_get(":SOUR:LEV?", float) + + self.current.set_validator(Nothing("Current cannot be set in voltage mode")) + if self.auto_range.get(): + self.voltage.set_validator(Numbers(-30, 30)) + else: + self.voltage.set_validator(Numbers(-source_range, source_range)) + + self.range.unit = "V" + else: + self.voltage._set_set(None, None) + self.voltage._set_get(None, None) + if self.auto_range.get(): + self.current._set_set(":SOUR:LEV:AUTO {:.5e}", float) + else: + self.current._set_set(":SOUR:LEV {:.5e}", float) + self.current._set_get(":SOUR:LEV?", float) + + self.voltage.set_validator(Nothing("Voltage cannot be set in current mode")) + if self.auto_range.get(): + self.current.set_validator(Numbers(-0.1, 0.1)) + else: + self.current.set_validator(Numbers(-source_range, source_range)) + + self.range.unit = "I" + + # Finally if measurements are enabled, update measurement units + # Source output is set to false and will be checked when a measurement is made + if self.measure.present: + self.measure._update_measurement_enabled(source_mode, source_range, False) + + def _set_auto_range(self, val): + # Store new autorange setting + self._auto_range = val + # Update validators + self._update_vals() + # Disable measurement if autorange is on + if self.measure.present: + self.measure._enabled &= val + + def _get_source_mode(self, val): + self._update_vals(source_mode=val) + return val + + def _set_source_mode(self, val): + # Cannot set source mode when the output is on + if self.output.get() == 'on': + raise GS200Exception("Cannot switch mode while source is on") + # Write the new mode to the instrument + self.write("SOUR:FUNC {}".format(val)) + # Update the parameters and validators appropriately + self._update_vals(source_mode=val) + + def _getset_range(self, val): + val = float(val) + + # Check appropriate range depending on source mode + source_mode = self.ask(":SOUR:FUNC?") + if source_mode == 'VOLT': + if val not in (10e-3, 100e-3, 1e0, 10e0, 30e0): + raise ValueError("Invalid voltage range") + else: + if val not in (1e-3, 10e-3, 100e-3, 200e-3): + raise ValueError("Invalid current range") + + # Update validators and parameters + self._update_vals(source_mode=source_mode, source_range=val) + return val \ No newline at end of file From c5c84131445a8ff6f6440003c214f55c69da90c8 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Thu, 14 Sep 2017 12:30:19 +1000 Subject: [PATCH 04/77] Add serial connection parameters to driver --- qcodes/instrument_drivers/Lakeshore/Model_336.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/Lakeshore/Model_336.py b/qcodes/instrument_drivers/Lakeshore/Model_336.py index 73e33ea452c..125462b4044 100644 --- a/qcodes/instrument_drivers/Lakeshore/Model_336.py +++ b/qcodes/instrument_drivers/Lakeshore/Model_336.py @@ -1,3 +1,6 @@ +from pyvisa.resources import SerialInstrument +import pyvisa.constants as vi_const + from qcodes import VisaInstrument, InstrumentChannel, ChannelList from qcodes.utils.validators import Enum, Strings @@ -27,7 +30,6 @@ def __init__(self, parent, name, channel): self.add_parameter('sensor_status', get_cmd='RDGST? {}'.format(self._channel), val_mapping={'OK': 0, 'Invalid Reading': 1, 'Temp Underrange': 16, 'Temp Overrange': 32, 'Sensor Units Zero': 64, 'Sensor Units Overrange': 128}, label='Sensor_Status') - self.add_parameter('sensor_name', get_cmd='INNAME? {}'.format(self._channel), get_parser=str, set_cmd='INNAME {},\"{{}}\"'.format(self._channel), vals=Strings(15), label='Sensor_Name') @@ -41,6 +43,13 @@ class Model_336(VisaInstrument): def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator="\r\n", **kwargs) + if isinstance(self.visa_handle, SerialInstrument): + # Set up serial connection parameters + self.visa_handle.baud_rate = 57600 + self.visa_handle.data_bits = 7 + self.visa_handle.stop_bits = vi_const.StopBits.one + self.visa_handle.flow_control = vi_const.VI_ASRL_FLOW_NONE + self.visa_handle.parity = vi_const.Parity.odd # Allow access to channels either by referring to the channel name # or through a channel list. From 44e747d5880b9380da09e02064e1b426241aab6f Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Thu, 14 Sep 2017 12:30:54 +1000 Subject: [PATCH 05/77] Add Model_372 driver without heater control --- .../instrument_drivers/Lakeshore/Model_372.py | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 qcodes/instrument_drivers/Lakeshore/Model_372.py diff --git a/qcodes/instrument_drivers/Lakeshore/Model_372.py b/qcodes/instrument_drivers/Lakeshore/Model_372.py new file mode 100644 index 00000000000..7646aab9ffb --- /dev/null +++ b/qcodes/instrument_drivers/Lakeshore/Model_372.py @@ -0,0 +1,232 @@ +from ctypes import LittleEndianStructure, Union, c_uint8 +from functools import partial +from pyvisa.resources import SerialInstrument +import pyvisa.constants as vi_const + +from qcodes import VisaInstrument, InstrumentChannel, ChannelList +from qcodes.utils.validators import Validator, Bool, Enum, Strings, Ints + +class SensorStatusBits(LittleEndianStructure): + """ + Sensor status bitfield + """ + _fields_ = ( + ("CS_OVL", c_uint8, 1), + ("VCM_OVL", c_uint8, 1), + ("VMIX_OVL", c_uint8, 1), + ("VDIF_OVL", c_uint8, 1), + ("R_OVER", c_uint8, 1), + ("R_UNDER", c_uint8, 1), + ("T_OVER", c_uint8, 1), + ("T_UNDER", c_uint8, 1) + ) +class SensorStatus(Union): + """ + Convert returned byte to sensor status bitfield + + Individual error conditions can be checked in the bitfield. e.g. + ```pyshell + >>> stat = SensorStatus(1) + >>> stat.b.CS_OVL + 1 + >>> stat.b.R_OVER + 0 + ``` + """ + _fields_ = (("b", SensorStatusBits), + ("asbyte", c_uint8)) + def __init__(self, bitfield): + self.asbyte = int(bitfield) + def is_error(self): + """ + Returns true if the sensor is showing an error + """ + return (self.asbyte != 0) + def __repr__(self): + errors = [] + for i, field in enumerate(self.b._fields_): + if (1 << i) & self.asbyte: + errors.append(field[0]) + if len(errors) == 0: + return "" + else: + return "".format("&&".join(errors)) + +class SensorSettingsValidator(Validator): + _STAT_VAL = Bool() + _DWELL_VAL = Ints(1, 200) + _PAUSE_VAL = Ints(3, 200) + _CURVE_VAL = Ints(0, 59) + _TEMP_VAL = Enum('positive', 'negative') + + def __init__(self): + pass + + def validate(self, val, context=''): + if not isinstance(val, SensorSettings): + raise TypeError("expecting a set of sensor settings; {}".format(context)) + """ Validate all parameters """ + self._STAT_VAL.validate(val.enabled) + self._DWELL_VAL.validate(val.dwell) + self._PAUSE_VAL.validate(val.pause) + self._CURVE_VAL.validate(val.curve) + self._TEMP_VAL.validate(val.tempco) + +class SensorSettings(object): + """ + Expand out the sensor status command `INSET` into it's constituent + parts, which can then be set and queried + """ + __slots__ = ('enabled', 'dwell', 'pause', 'curve', 'tempco') + _TEMPCO_MAP = {'positive': 1, 'negative': 2} + _INV_TEMPCO_MAP = {v: k for k, v in _TEMPCO_MAP.items()} + + def __init__(self, enabled, dwell, pause, curve, tempco): + self.enabled = enabled + self.dwell = dwell + self.pause = pause + # For now, this is just the curve ID, but it should be linked to the actual curve object + # TODO: link to curve object + self.curve = curve + self.tempco = tempco + + @classmethod + def parse_input(cls, inp, field=None): + """ Parse the output of the `INSET?` query """ + inset = inp.strip().split(',') + if field is None: + return SensorSettings(enabled=bool(int(inset[0])), + dwell=int(inset[1]), + pause=int(inset[2]), + curve=int(inset[3]), + tempco=cls._INV_TEMPCO_MAP[int(inset[4])]) + elif field == "enabled": + return bool(inset[0]) + elif field == "dwell": + return int(inset[1]) + elif field == "pause": + return int(inset[2]) + elif field == "curve": + return int(inset[3]) + else: + return cls._INV_TEMPCO_MAP[int(inset[4])] + + @classmethod + def parse_output(cls, val, parent=None, field=None): + """ Parse the output of the `INSET?` query """ + inset = parent.sensor_statset.get() + setattr(inset, field, val) + return inset + + @property + def set_format(self): + return "{},{},{},{},{}".format( + int(self.enabled), + self.dwell, + self.pause, + self.curve, + self._TEMPCO_MAP[self.tempco]) + + def __repr__(self): + return "SensorSettings(enabled={}, dwell={}, pause={}, curve={}, tempco={})".format( + self.enabled, self.dwell, self.pause, self.curve, self.tempco) + + +class SensorChannel(InstrumentChannel): + """ + A single sensor channel of a temperature controller + """ + + _CHANNEL_VAL = Ints(1, 16) + + def __init__(self, parent, name, channel): + super().__init__(parent, name) + + + # Validate the channel value + self._CHANNEL_VAL.validate(channel) + self._channel = channel # Channel on the temperature controller. Can be 1-16 + + # Add the various channel parameters + self.add_parameter('temperature', get_cmd='KRDG? {}'.format(self._channel), + get_parser=float, label='Temerature', unit='K') + self.add_parameter('sensor_raw', get_cmd='SRDG? {}'.format(self._channel), + get_parser=float, label='Raw Sensor Reading', unit='Ohms') + self.add_parameter('sensor_status', get_cmd='RDGST? {}'.format(self._channel), + label='Sensor Status', get_parser=SensorStatus) + self.add_parameter('sensor_name', get_cmd='INNAME? {}'.format(self._channel), + get_parser=str, set_cmd='INNAME {},\"{{}}\"'.format(self._channel), vals=Strings(15), + label='Sensor Name') + + self.add_parameter('sensor_statset', get_cmd='INSET? {}'.format(self._channel), + get_parser=SensorSettings.parse_input, set_cmd='INSET {},{{0.set_format}}'.format(self._channel), + vals=SensorSettingsValidator(), label='Sensor Settings') + status_parameters = ('enabled', 'dwell', 'pause', 'curve', 'tempco') + for param in status_parameters: + self.add_parameter('sensor_{}'.format(param), get_cmd='INSET? {}'.format(self._channel), + get_parser=partial(SensorSettings.parse_input, field=param), + set_cmd='INSET {},{{0.set_format}}'.format(self._channel), + set_parser=partial(SensorSettings.parse_output, parent=self, field=param), + vals=Bool(), label='Sensor {0.capitalize}'.format(param)) + + + +class Model_372(VisaInstrument): + """ + Lakeshore Model 336 Temperature Controller Driver + Controlled via sockets + """ + + _OFFON_MAP = {'off': 0, 'on': 1} + _INV_OFFON_MAP = {v: k for k, v in _OFFON_MAP.items()} + + def __init__(self, name, address, **kwargs): + super().__init__(name, address, terminator="\r\n", **kwargs) + if isinstance(self.visa_handle, SerialInstrument): + # Set up serial connection parameters + self.visa_handle.baud_rate = 57600 + self.visa_handle.data_bits = 7 + self.visa_handle.stop_bits = vi_const.StopBits.one + self.visa_handle.flow_control = vi_const.VI_ASRL_FLOW_NONE + self.visa_handle.parity = vi_const.Parity.odd + + # Allow access to channels either by referring to the channel name + # or through a channel list. + # i.e. Model_336.A.temperature() and Model_336.channels[0].temperature() + # refer to the same parameter. + channels = ChannelList(self, "TempSensors", SensorChannel, snapshotable=False) + for chan_name in range(1, 17): + channel = SensorChannel(self, 'Chan{}'.format(chan_name), chan_name) + channels.append(channel) + self.add_submodule('chan{}'.format(chan_name), channel) + channels.lock() + self.add_submodule("channels", channels) + + self.add_parameter('active_channel', get_cmd='SCAN?', set_cmd='SCAN {}', + get_parser=partial(self._parse_scan, "CHAN"), + set_parser=partial(self._set_scan, "CHAN"), + vals=self.channels.get_validator()) + self.add_parameter('scan', get_cmd='SCAN?', set_cmd='SCAN {}', + get_parser=partial(self._parse_scan, "SCAN"), + set_parser=partial(self._set_scan, "SCAN"), + vals=Enum('off', 'on')) + + self.connect_message() + + def _parse_scan(self, param, inp): + inp = inp.strip().split(',') + channel = self.channels[int(inp[0])-1] + scan = self._INV_OFFON_MAP[int(inp[1])] + if param == "CHAN": + return channel + else: + return scan + + def _set_scan(self, param, val): + if param =="CHAN": + channel = val._channel + scan = self._OFFON_MAP[self.scan.get()] + else: + channel = self.active_channel.get()._channel + scan = self._OFFON_MAP[val] + return "{},{}".format(channel, scan) \ No newline at end of file From 0384685df6c123504d3f9cd65335fea0ef69cc02 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 12:48:20 +1100 Subject: [PATCH 06/77] change nothing validator exception --- qcodes/utils/validators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py index 88138faefb7..352f620c5d3 100644 --- a/qcodes/utils/validators.py +++ b/qcodes/utils/validators.py @@ -87,7 +87,7 @@ def __init__(self, reason): self.reason = "Nothing Validator" def validate(self, value, context=''): - raise TypeError("{}; {}".format(self.reason, context)) + raise RuntimeError("{}; {}".format(self.reason, context)) def __repr__(self): return ''.format(self.reason) From cf9c464304221b22c5799cab972875f7ce6fdab3 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 12:48:35 +1100 Subject: [PATCH 07/77] Update yokogawa driver to use new style params --- qcodes/instrument_drivers/yokogawa/GS200.py | 36 ++++++++++----------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index d6ad4c8f8c1..c8aabbb7426 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -178,11 +178,15 @@ def __init__(self, name, address, **kwargs): self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=lambda x:0, get_cmd=lambda:0) + set_cmd=":SOUR:LEV {:.5e}", + get_cmd=":SOUR:LEV?", + vals=Nothing("")) self.add_parameter('current', label='Current', unit='I', - set_cmd=lambda x:0, get_cmd=lambda:0) + set_cmd=":SOUR:LEV {:.5e}", + get_cmd=":SOUR:LEV?", + vals=Nothing("")) self.add_parameter('voltage_limit', label='Voltage Protection Limit', @@ -269,35 +273,29 @@ def _update_vals(self, source_mode=None, source_range=None): # Setup source based on what mode we are in # Range is updated if auto-range is off if source_mode == 'VOLT': - self.current._set_set(None, None) - self.current._set_get(None, None) if self.auto_range.get(): - self.voltage._set_set(":SOUR:LEV:AUTO {:.5e}", float) + self.voltage.set_raw.cmd_str = ":SOUR:LEV:AUTO {:.5e}" else: - self.voltage._set_set(":SOUR:LEV {:.5e}", float) - self.voltage._set_get(":SOUR:LEV?", float) + self.voltage.set_raw.cmd_str = ":SOUR:LEV {:.5e}" - self.current.set_validator(Nothing("Current cannot be set in voltage mode")) + self.current.vals = Nothing("Current cannot be set in voltage mode") if self.auto_range.get(): - self.voltage.set_validator(Numbers(-30, 30)) + self.voltage.vals = Numbers(-30, 30) else: - self.voltage.set_validator(Numbers(-source_range, source_range)) + self.voltage.vals = Numbers(-source_range, source_range) self.range.unit = "V" else: - self.voltage._set_set(None, None) - self.voltage._set_get(None, None) if self.auto_range.get(): - self.current._set_set(":SOUR:LEV:AUTO {:.5e}", float) + self.current.set_raw.cmd_str = ":SOUR:LEV:AUTO {:.5e}" else: - self.current._set_set(":SOUR:LEV {:.5e}", float) - self.current._set_get(":SOUR:LEV?", float) + self.current.set_raw.cmd_str = ":SOUR:LEV {:.5e}" - self.voltage.set_validator(Nothing("Voltage cannot be set in current mode")) + self.voltage.vals = Nothing("Voltage cannot be set in current mode") if self.auto_range.get(): - self.current.set_validator(Numbers(-0.1, 0.1)) + self.current.vals = Numbers(-0.1, 0.1) else: - self.current.set_validator(Numbers(-source_range, source_range)) + self.current.vals = Numbers(-source_range, source_range) self.range.unit = "I" @@ -342,4 +340,4 @@ def _getset_range(self, val): # Update validators and parameters self._update_vals(source_mode=source_mode, source_range=val) - return val \ No newline at end of file + return val From f9876e9b25cecb1b4931fafd0f20de0289532578 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 12:52:18 +1100 Subject: [PATCH 08/77] Revert changes to Lakeshore drivers in this branch --- .../instrument_drivers/Lakeshore/Model_336.py | 11 +- .../instrument_drivers/Lakeshore/Model_372.py | 232 ------------------ 2 files changed, 1 insertion(+), 242 deletions(-) delete mode 100644 qcodes/instrument_drivers/Lakeshore/Model_372.py diff --git a/qcodes/instrument_drivers/Lakeshore/Model_336.py b/qcodes/instrument_drivers/Lakeshore/Model_336.py index 125462b4044..73e33ea452c 100644 --- a/qcodes/instrument_drivers/Lakeshore/Model_336.py +++ b/qcodes/instrument_drivers/Lakeshore/Model_336.py @@ -1,6 +1,3 @@ -from pyvisa.resources import SerialInstrument -import pyvisa.constants as vi_const - from qcodes import VisaInstrument, InstrumentChannel, ChannelList from qcodes.utils.validators import Enum, Strings @@ -30,6 +27,7 @@ def __init__(self, parent, name, channel): self.add_parameter('sensor_status', get_cmd='RDGST? {}'.format(self._channel), val_mapping={'OK': 0, 'Invalid Reading': 1, 'Temp Underrange': 16, 'Temp Overrange': 32, 'Sensor Units Zero': 64, 'Sensor Units Overrange': 128}, label='Sensor_Status') + self.add_parameter('sensor_name', get_cmd='INNAME? {}'.format(self._channel), get_parser=str, set_cmd='INNAME {},\"{{}}\"'.format(self._channel), vals=Strings(15), label='Sensor_Name') @@ -43,13 +41,6 @@ class Model_336(VisaInstrument): def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator="\r\n", **kwargs) - if isinstance(self.visa_handle, SerialInstrument): - # Set up serial connection parameters - self.visa_handle.baud_rate = 57600 - self.visa_handle.data_bits = 7 - self.visa_handle.stop_bits = vi_const.StopBits.one - self.visa_handle.flow_control = vi_const.VI_ASRL_FLOW_NONE - self.visa_handle.parity = vi_const.Parity.odd # Allow access to channels either by referring to the channel name # or through a channel list. diff --git a/qcodes/instrument_drivers/Lakeshore/Model_372.py b/qcodes/instrument_drivers/Lakeshore/Model_372.py deleted file mode 100644 index 7646aab9ffb..00000000000 --- a/qcodes/instrument_drivers/Lakeshore/Model_372.py +++ /dev/null @@ -1,232 +0,0 @@ -from ctypes import LittleEndianStructure, Union, c_uint8 -from functools import partial -from pyvisa.resources import SerialInstrument -import pyvisa.constants as vi_const - -from qcodes import VisaInstrument, InstrumentChannel, ChannelList -from qcodes.utils.validators import Validator, Bool, Enum, Strings, Ints - -class SensorStatusBits(LittleEndianStructure): - """ - Sensor status bitfield - """ - _fields_ = ( - ("CS_OVL", c_uint8, 1), - ("VCM_OVL", c_uint8, 1), - ("VMIX_OVL", c_uint8, 1), - ("VDIF_OVL", c_uint8, 1), - ("R_OVER", c_uint8, 1), - ("R_UNDER", c_uint8, 1), - ("T_OVER", c_uint8, 1), - ("T_UNDER", c_uint8, 1) - ) -class SensorStatus(Union): - """ - Convert returned byte to sensor status bitfield - - Individual error conditions can be checked in the bitfield. e.g. - ```pyshell - >>> stat = SensorStatus(1) - >>> stat.b.CS_OVL - 1 - >>> stat.b.R_OVER - 0 - ``` - """ - _fields_ = (("b", SensorStatusBits), - ("asbyte", c_uint8)) - def __init__(self, bitfield): - self.asbyte = int(bitfield) - def is_error(self): - """ - Returns true if the sensor is showing an error - """ - return (self.asbyte != 0) - def __repr__(self): - errors = [] - for i, field in enumerate(self.b._fields_): - if (1 << i) & self.asbyte: - errors.append(field[0]) - if len(errors) == 0: - return "" - else: - return "".format("&&".join(errors)) - -class SensorSettingsValidator(Validator): - _STAT_VAL = Bool() - _DWELL_VAL = Ints(1, 200) - _PAUSE_VAL = Ints(3, 200) - _CURVE_VAL = Ints(0, 59) - _TEMP_VAL = Enum('positive', 'negative') - - def __init__(self): - pass - - def validate(self, val, context=''): - if not isinstance(val, SensorSettings): - raise TypeError("expecting a set of sensor settings; {}".format(context)) - """ Validate all parameters """ - self._STAT_VAL.validate(val.enabled) - self._DWELL_VAL.validate(val.dwell) - self._PAUSE_VAL.validate(val.pause) - self._CURVE_VAL.validate(val.curve) - self._TEMP_VAL.validate(val.tempco) - -class SensorSettings(object): - """ - Expand out the sensor status command `INSET` into it's constituent - parts, which can then be set and queried - """ - __slots__ = ('enabled', 'dwell', 'pause', 'curve', 'tempco') - _TEMPCO_MAP = {'positive': 1, 'negative': 2} - _INV_TEMPCO_MAP = {v: k for k, v in _TEMPCO_MAP.items()} - - def __init__(self, enabled, dwell, pause, curve, tempco): - self.enabled = enabled - self.dwell = dwell - self.pause = pause - # For now, this is just the curve ID, but it should be linked to the actual curve object - # TODO: link to curve object - self.curve = curve - self.tempco = tempco - - @classmethod - def parse_input(cls, inp, field=None): - """ Parse the output of the `INSET?` query """ - inset = inp.strip().split(',') - if field is None: - return SensorSettings(enabled=bool(int(inset[0])), - dwell=int(inset[1]), - pause=int(inset[2]), - curve=int(inset[3]), - tempco=cls._INV_TEMPCO_MAP[int(inset[4])]) - elif field == "enabled": - return bool(inset[0]) - elif field == "dwell": - return int(inset[1]) - elif field == "pause": - return int(inset[2]) - elif field == "curve": - return int(inset[3]) - else: - return cls._INV_TEMPCO_MAP[int(inset[4])] - - @classmethod - def parse_output(cls, val, parent=None, field=None): - """ Parse the output of the `INSET?` query """ - inset = parent.sensor_statset.get() - setattr(inset, field, val) - return inset - - @property - def set_format(self): - return "{},{},{},{},{}".format( - int(self.enabled), - self.dwell, - self.pause, - self.curve, - self._TEMPCO_MAP[self.tempco]) - - def __repr__(self): - return "SensorSettings(enabled={}, dwell={}, pause={}, curve={}, tempco={})".format( - self.enabled, self.dwell, self.pause, self.curve, self.tempco) - - -class SensorChannel(InstrumentChannel): - """ - A single sensor channel of a temperature controller - """ - - _CHANNEL_VAL = Ints(1, 16) - - def __init__(self, parent, name, channel): - super().__init__(parent, name) - - - # Validate the channel value - self._CHANNEL_VAL.validate(channel) - self._channel = channel # Channel on the temperature controller. Can be 1-16 - - # Add the various channel parameters - self.add_parameter('temperature', get_cmd='KRDG? {}'.format(self._channel), - get_parser=float, label='Temerature', unit='K') - self.add_parameter('sensor_raw', get_cmd='SRDG? {}'.format(self._channel), - get_parser=float, label='Raw Sensor Reading', unit='Ohms') - self.add_parameter('sensor_status', get_cmd='RDGST? {}'.format(self._channel), - label='Sensor Status', get_parser=SensorStatus) - self.add_parameter('sensor_name', get_cmd='INNAME? {}'.format(self._channel), - get_parser=str, set_cmd='INNAME {},\"{{}}\"'.format(self._channel), vals=Strings(15), - label='Sensor Name') - - self.add_parameter('sensor_statset', get_cmd='INSET? {}'.format(self._channel), - get_parser=SensorSettings.parse_input, set_cmd='INSET {},{{0.set_format}}'.format(self._channel), - vals=SensorSettingsValidator(), label='Sensor Settings') - status_parameters = ('enabled', 'dwell', 'pause', 'curve', 'tempco') - for param in status_parameters: - self.add_parameter('sensor_{}'.format(param), get_cmd='INSET? {}'.format(self._channel), - get_parser=partial(SensorSettings.parse_input, field=param), - set_cmd='INSET {},{{0.set_format}}'.format(self._channel), - set_parser=partial(SensorSettings.parse_output, parent=self, field=param), - vals=Bool(), label='Sensor {0.capitalize}'.format(param)) - - - -class Model_372(VisaInstrument): - """ - Lakeshore Model 336 Temperature Controller Driver - Controlled via sockets - """ - - _OFFON_MAP = {'off': 0, 'on': 1} - _INV_OFFON_MAP = {v: k for k, v in _OFFON_MAP.items()} - - def __init__(self, name, address, **kwargs): - super().__init__(name, address, terminator="\r\n", **kwargs) - if isinstance(self.visa_handle, SerialInstrument): - # Set up serial connection parameters - self.visa_handle.baud_rate = 57600 - self.visa_handle.data_bits = 7 - self.visa_handle.stop_bits = vi_const.StopBits.one - self.visa_handle.flow_control = vi_const.VI_ASRL_FLOW_NONE - self.visa_handle.parity = vi_const.Parity.odd - - # Allow access to channels either by referring to the channel name - # or through a channel list. - # i.e. Model_336.A.temperature() and Model_336.channels[0].temperature() - # refer to the same parameter. - channels = ChannelList(self, "TempSensors", SensorChannel, snapshotable=False) - for chan_name in range(1, 17): - channel = SensorChannel(self, 'Chan{}'.format(chan_name), chan_name) - channels.append(channel) - self.add_submodule('chan{}'.format(chan_name), channel) - channels.lock() - self.add_submodule("channels", channels) - - self.add_parameter('active_channel', get_cmd='SCAN?', set_cmd='SCAN {}', - get_parser=partial(self._parse_scan, "CHAN"), - set_parser=partial(self._set_scan, "CHAN"), - vals=self.channels.get_validator()) - self.add_parameter('scan', get_cmd='SCAN?', set_cmd='SCAN {}', - get_parser=partial(self._parse_scan, "SCAN"), - set_parser=partial(self._set_scan, "SCAN"), - vals=Enum('off', 'on')) - - self.connect_message() - - def _parse_scan(self, param, inp): - inp = inp.strip().split(',') - channel = self.channels[int(inp[0])-1] - scan = self._INV_OFFON_MAP[int(inp[1])] - if param == "CHAN": - return channel - else: - return scan - - def _set_scan(self, param, val): - if param =="CHAN": - channel = val._channel - scan = self._OFFON_MAP[self.scan.get()] - else: - channel = self.active_channel.get()._channel - scan = self._OFFON_MAP[val] - return "{},{}".format(channel, scan) \ No newline at end of file From c4e748610c485ebf53b6ba4f9057dabd2de0707e Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 13:02:37 +1100 Subject: [PATCH 09/77] Add documentation to driver --- qcodes/instrument_drivers/yokogawa/GS200.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index c8aabbb7426..8d365341716 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -12,6 +12,15 @@ class GS200Exception(Exception): pass class GS200_Monitor(InstrumentChannel): + """ + Monitor part of the GS200. This is only enabled if it is + installed in the GS200 (it is an optional extra). + + The units will be automatically updated as required. + + To measure: + `GS200.measure.measure()` + """ def __init__(self, parent, name, present): super().__init__(parent, name) @@ -78,12 +87,15 @@ def __init__(self, parent, name, present): self.add_function('off', call_cmd=self.off) def off(self): + """Turn measurement off""" self.write(':SENS 0') self._enabled = False def on(self): + """Turn measurement on""" self.write(':SENS 1') self._enabled = True def state(self): + """Check measurement state""" state = int(self.ask(':SENS?')) self._enabled = bool(state) return state @@ -250,19 +262,23 @@ def __init__(self, name, address, **kwargs): self.source_mode.get() def on(self): + """Turn output on""" self.write('OUTPUT 1') self.measure._output = True def off(self): + """Turn output off""" self.write('OUTPUT 0') self.measure._output = False def state(self): + """Check state""" state = int(self.ask('OUTPUT?')) self.measure._output = bool(state) return state def _update_vals(self, source_mode=None, source_range=None): + """Update validators/units as source mode/range changes""" # Update source mode if source_mode is None: source_mode = self.ask(":SOUR:FUNC?") @@ -305,6 +321,7 @@ def _update_vals(self, source_mode=None, source_range=None): self.measure._update_measurement_enabled(source_mode, source_range, False) def _set_auto_range(self, val): + """Change commands when autoranging""" # Store new autorange setting self._auto_range = val # Update validators @@ -314,10 +331,12 @@ def _set_auto_range(self, val): self.measure._enabled &= val def _get_source_mode(self, val): + """Get output (VOLT/CURR) mode and update validators""" self._update_vals(source_mode=val) return val def _set_source_mode(self, val): + """Set output (VOLT/CURR) mode and update validators""" # Cannot set source mode when the output is on if self.output.get() == 'on': raise GS200Exception("Cannot switch mode while source is on") @@ -327,6 +346,7 @@ def _set_source_mode(self, val): self._update_vals(source_mode=val) def _getset_range(self, val): + """Update range and validators""" val = float(val) # Check appropriate range depending on source mode From e87fc8797575fdd91ca38fd646d96bb6855c7ef0 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 20:09:41 +1100 Subject: [PATCH 10/77] Make signature same as base class --- qcodes/instrument/channel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument/channel.py b/qcodes/instrument/channel.py index 2ed862ad811..b5815b93882 100644 --- a/qcodes/instrument/channel.py +++ b/qcodes/instrument/channel.py @@ -455,7 +455,7 @@ def __init__(self, channel_list: ChannelList): "to create a validator") self._channel_list = channel_list - def validate(self, value: InstrumentChannel, context: str): + def validate(self, value, context=''): """ Checks to see that value is a member of the channel list referenced by this validator @@ -470,4 +470,4 @@ def validate(self, value: InstrumentChannel, context: str): if value not in self._channel_list: raise ValueError( '{} is not part of the expected channel list; {}'.format( - repr(value), context)) \ No newline at end of file + repr(value), context)) From 8248a6bd4e92d74fde94c4f094f25d1edf0740f6 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Fri, 3 Nov 2017 20:09:57 +1100 Subject: [PATCH 11/77] Remove trailing whitespace, fix parser --- qcodes/instrument_drivers/yokogawa/GS200.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 8d365341716..c811b288cfe 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,12 +1,11 @@ from qcodes import VisaInstrument, InstrumentChannel -from qcodes.instrument.parameter import ManualParameter from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints def float_int(val): """ Parses int that are returned in exponentiated form (i.e. 1E0) """ - return int(float(val)) + return round(float(val)) class GS200Exception(Exception): pass @@ -52,18 +51,18 @@ def __init__(self, parent, name, present): set_cmd=':SENS:NPLC {}', set_parser=int, get_cmd=':SENS:NPLC?', - get_parser=float_int) + get_parser=float_int) self.add_parameter('delay', label='Measurement Delay', unit='ms', vals=Ints(0, 999999), - set_cmd=':SENS:DEL {}', + set_cmd=':SENS:DEL {}', set_parser=int, get_cmd=':SENS:DEL?', get_parser=float_int) self.add_parameter('trigger', label='Trigger Source', - set_cmd=':SENS:TRIG {}', + set_cmd=':SENS:TRIG {}', get_cmd=':SENS:TRIG?', val_mapping={ 'READY': 'READ', @@ -78,7 +77,7 @@ def __init__(self, parent, name, present): label='Measurement Interal', unit='s', vals=Numbers(0.1, 3600), - set_cmd=':SENS:INT {}', + set_cmd=':SENS:INT {}', set_parser=float, get_cmd=':SENS:INT?', get_parser=float) @@ -105,7 +104,7 @@ def _get_measurement(self): if not self._enabled or not self._output: # Check if the output is on self._output = self._output or self._parent.output.get() == 'on' - + if self._parent.auto_range.get() or (self._unit == 'VOLT' and self._range < 1): # Measurements will not work with autorange, or when range is <1V self._enabled = False @@ -185,7 +184,7 @@ def __init__(self, name, address, **kwargs): get_cmd=lambda: self._auto_range, vals=Bool()) - # Note: Get and set for voltage/current will be updated by once + # Note: Get and set for voltage/current will be updated by once # range and mode are known self.add_parameter('voltage', label='Voltage', From 06e559e617e0b7232d3c74833eef05f3b4d00ab7 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 7 Nov 2017 14:39:35 +0100 Subject: [PATCH 12/77] Changes Sohail --- qcodes/instrument_drivers/yokogawa/GS200.py | 43 +++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index c811b288cfe..78b1fcec5ec 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -89,10 +89,12 @@ def off(self): """Turn measurement off""" self.write(':SENS 0') self._enabled = False + def on(self): """Turn measurement on""" self.write(':SENS 1') self._enabled = True + def state(self): """Check measurement state""" state = int(self.ask(':SENS?')) @@ -152,7 +154,7 @@ class GS200(VisaInstrument): def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) - self.visa_handle.read_termination = "\r\n" + self.visa_handle.read_termination = "\n" self.add_parameter('output', label='Output State', @@ -169,9 +171,10 @@ def __init__(self, name, address, **kwargs): set_cmd=self._set_source_mode, get_parser=self._get_source_mode, vals=Enum('VOLT', 'CURR')) + self.add_parameter('range', label='Source Range', - unit='?', # This will be set by the get/set parser + unit='?', # This will be set by the get/set parser get_cmd=':SOUR:RANG?', set_cmd=':SOUR:RANG {}', get_parser=self._getset_range, @@ -189,14 +192,15 @@ def __init__(self, name, address, **kwargs): self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=":SOUR:LEV {:.5e}", - get_cmd=":SOUR:LEV?", - vals=Nothing("")) + set_cmd=self._output_setter_getter("VOLT", "setter"), + get_cmd=self._output_setter_getter("VOLT", "getter"), + vals=Numbers()) + self.add_parameter('current', label='Current', unit='I', - set_cmd=":SOUR:LEV {:.5e}", - get_cmd=":SOUR:LEV?", + set_cmd=self._output_setter_getter("CURR", "setter"), + get_cmd=self._output_setter_getter("CURR", "getter"), vals=Nothing("")) self.add_parameter('voltage_limit', @@ -360,3 +364,28 @@ def _getset_range(self, val): # Update validators and parameters self._update_vals(source_mode=source_mode, source_range=val) return val + + @staticmethod + def assert_output_type(output_type, mode): + + human_readable = { + "CURR": "current", + "VOLT": "voltage" + } + + if mode != output_type: + raise GS200Exception("Cannot set {} while in {} mode".format(human_readable[output_type], + human_readable[mode])) + + def _output_setter_getter(self, output_type, return_function): + + def setter(output): + self.assert_output_type(output_type, self.source_mode()) + self.write(":SOUR:LEV {:.5e}".format(output)) + + def getter(): + self.assert_output_type(output_type, self.source_mode()) + answer = self.ask(":SOUR:LEV?") + return float(answer) + + return {"setter": setter, "getter": getter}[return_function] From 33b0ae419b5b560dda2e7190c94b3e141a853a87 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 7 Nov 2017 16:13:44 +0100 Subject: [PATCH 13/77] Everything seems to be working, but code improvements needed --- qcodes/instrument_drivers/yokogawa/GS200.py | 74 +++++++++++---------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 78b1fcec5ec..1afcd83e5c3 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -169,7 +169,7 @@ def __init__(self, name, address, **kwargs): label='Source Mode', get_cmd=':SOUR:FUNC?', set_cmd=self._set_source_mode, - get_parser=self._get_source_mode, + get_parser=self._source_mode_get_parser, vals=Enum('VOLT', 'CURR')) self.add_parameter('range', @@ -192,15 +192,17 @@ def __init__(self, name, address, **kwargs): self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=self._output_setter_getter("VOLT", "setter"), - get_cmd=self._output_setter_getter("VOLT", "getter"), + set_cmd=":SOUR:LEV {:.5e}", + get_cmd=":SOUR:LEV?", + get_parser=self._output_get_parser("VOLT"), vals=Numbers()) self.add_parameter('current', label='Current', unit='I', - set_cmd=self._output_setter_getter("CURR", "setter"), - get_cmd=self._output_setter_getter("CURR", "getter"), + set_cmd=":SOUR:LEV {:.5e}", + get_cmd=":SOUR:LEV?", + get_parser=self._output_get_parser("CURR"), vals=Nothing("")) self.add_parameter('voltage_limit', @@ -253,10 +255,6 @@ def __init__(self, name, address, **kwargs): # Reset function self.add_function('reset', call_cmd='*RST') - # Output functions - self.add_function('on', call_cmd=self.on) - self.add_function('off', call_cmd=self.off) - self.connect_message() # Update the source ranges and output state @@ -333,7 +331,7 @@ def _set_auto_range(self, val): if self.measure.present: self.measure._enabled &= val - def _get_source_mode(self, val): + def _source_mode_get_parser(self, val): """Get output (VOLT/CURR) mode and update validators""" self._update_vals(source_mode=val) return val @@ -365,27 +363,35 @@ def _getset_range(self, val): self._update_vals(source_mode=source_mode, source_range=val) return val - @staticmethod - def assert_output_type(output_type, mode): - - human_readable = { - "CURR": "current", - "VOLT": "voltage" - } - - if mode != output_type: - raise GS200Exception("Cannot set {} while in {} mode".format(human_readable[output_type], - human_readable[mode])) - - def _output_setter_getter(self, output_type, return_function): - - def setter(output): - self.assert_output_type(output_type, self.source_mode()) - self.write(":SOUR:LEV {:.5e}".format(output)) - - def getter(): - self.assert_output_type(output_type, self.source_mode()) - answer = self.ask(":SOUR:LEV?") - return float(answer) - - return {"setter": setter, "getter": getter}[return_function] + def _output_get_parser(self, output_mode): + """ + Setting the current/voltage while in voltage/current mode will rightfully raise an error. However, we also + want to raise an error while trying to get the output when we are in the wrong output mode (e.g. getting the + current while in voltage mode and visa-versa) + + Parameters + ---------- + output_mode: str, ["Curr", "Volt"] + + Returns + ------- + output_parser: callable + The get parser for the current/voltage output + """ + + def assert_output_type(mode): + human_readable = { + "CURR": "current", + "VOLT": "voltage" + } + + if mode != output_mode: + raise GS200Exception("Cannot get {} while in {} mode".format(human_readable[output_mode], + human_readable[mode])) + + def output_parser(val): + mode = self.source_mode() + assert_output_type(mode) + return val + + return output_parser From a14bfda065f80d21e65f56fa3eea168c0ec61861 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 7 Nov 2017 18:40:41 +0100 Subject: [PATCH 14/77] lots of changes --- qcodes/instrument_drivers/yokogawa/GS200.py | 152 ++++++++++++-------- 1 file changed, 95 insertions(+), 57 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 1afcd83e5c3..2e3315a5bd0 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,15 +1,26 @@ from qcodes import VisaInstrument, InstrumentChannel -from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints +from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints, Validator -def float_int(val): + +def float_round(val): """ - Parses int that are returned in exponentiated form (i.e. 1E0) + Rounds a floating number represented as a string + + Parameters + ---------- + val: str + + Returns + ------- + int """ return round(float(val)) + class GS200Exception(Exception): pass + class GS200_Monitor(InstrumentChannel): """ Monitor part of the GS200. This is only enabled if it is @@ -51,7 +62,7 @@ def __init__(self, parent, name, present): set_cmd=':SENS:NPLC {}', set_parser=int, get_cmd=':SENS:NPLC?', - get_parser=float_int) + get_parser=float_round) self.add_parameter('delay', label='Measurement Delay', unit='ms', @@ -59,7 +70,7 @@ def __init__(self, parent, name, present): set_cmd=':SENS:DEL {}', set_parser=int, get_cmd=':SENS:DEL?', - get_parser=float_int) + get_parser=float_round) self.add_parameter('trigger', label='Trigger Source', set_cmd=':SENS:TRIG {}', @@ -142,6 +153,26 @@ def _update_measurement_enabled(self, unit, output_range, output): self.measure.unit = 'V' +class GS200RangeValidator(Validator): + def __init__(self, parent_instrument): + self._parent_instrument = parent_instrument + + def validate(self, value, context=''): + + mode = self._parent_instrument.source_mode() + + if mode == "CURR": + valid_values = [1e-3, 10e-3, 100e-3, 200e-3] + else: + valid_values = [10e-3, 100e-3, 1e0, 10e0, 30e0] + + if value not in valid_values: + raise ValueError("{} invalid range for mode {}".format(str(value), mode)) + + def __repr__(self): + return "GS200RangeValidator" + + class GS200(VisaInstrument): """ This is the qcodes driver for the Yokogawa GS200 voltage and current source @@ -169,7 +200,6 @@ def __init__(self, name, address, **kwargs): label='Source Mode', get_cmd=':SOUR:FUNC?', set_cmd=self._set_source_mode, - get_parser=self._source_mode_get_parser, vals=Enum('VOLT', 'CURR')) self.add_parameter('range', @@ -177,8 +207,9 @@ def __init__(self, name, address, **kwargs): unit='?', # This will be set by the get/set parser get_cmd=':SOUR:RANG?', set_cmd=':SOUR:RANG {}', - get_parser=self._getset_range, - set_parser=self._getset_range) + vals=GS200RangeValidator(self), + set_parser=self._range_set_parser, + get_parser=float) self._auto_range = False self.add_parameter('auto_range', @@ -203,7 +234,7 @@ def __init__(self, name, address, **kwargs): set_cmd=":SOUR:LEV {:.5e}", get_cmd=":SOUR:LEV?", get_parser=self._output_get_parser("CURR"), - vals=Nothing("")) + vals=Numbers()) self.add_parameter('voltage_limit', label='Voltage Protection Limit', @@ -211,8 +242,9 @@ def __init__(self, name, address, **kwargs): vals=Ints(1, 30), get_cmd=":SOUR:PROT:VOLT?", set_cmd=":SOUR:PROT:VOLT {}", - get_parser=float_int, + get_parser=float_round, set_parser=int) + self.add_parameter('current_limit', label='Current Protection Limit', unit='I', @@ -223,13 +255,13 @@ def __init__(self, name, address, **kwargs): set_parser=float) self.add_parameter('four_wire', - label='Four Wire Sensing', - get_cmd=':SENS:REM?', - set_cmd=':SENS:REM {}', - val_mapping={ + label='Four Wire Sensing', + get_cmd=':SENS:REM?', + set_cmd=':SENS:REM {}', + val_mapping={ 'off': 0, 'on': 1, - }) + }) # Note: This feature can be used to remove common mode noise. # Read the manual to see if you would like to use it self.add_parameter('guard', @@ -257,10 +289,9 @@ def __init__(self, name, address, **kwargs): self.add_function('reset', call_cmd='*RST') self.connect_message() - # Update the source ranges and output state - # This will query mode and range - self.output.get() - self.source_mode.get() + self.output("off") + self.source_mode("VOLT") + self.auto_range(True) def on(self): """Turn output on""" @@ -278,14 +309,20 @@ def state(self): self.measure._output = bool(state) return state - def _update_vals(self, source_mode=None, source_range=None): - """Update validators/units as source mode/range changes""" - # Update source mode + def _update_validators_and_units(self, source_mode=None, source_range=None): + """ + Update validators/units as source mode/range changes + + Parameters + ---------- + source_mode: str, ["CURR", "VOLT"] + source_range: float + """ if source_mode is None: - source_mode = self.ask(":SOUR:FUNC?") + source_mode = self.source_mode() # Get source range if auto-range is off - if source_range is None and not self.auto_range.get(): - source_range = float(self.ask("SOUR:RANG?")) + if source_range is None and not self.auto_range(): + source_range = self.range() # Setup source based on what mode we are in # Range is updated if auto-range is off @@ -322,52 +359,53 @@ def _update_vals(self, source_mode=None, source_range=None): self.measure._update_measurement_enabled(source_mode, source_range, False) def _set_auto_range(self, val): - """Change commands when autoranging""" - # Store new autorange setting + """ + Enable/disable auto range. Note that the instrument itself does not provide auto range. This is implemented + in software. + + Parameters + ---------- + val: bool + """ self._auto_range = val - # Update validators - self._update_vals() - # Disable measurement if autorange is on + self._update_validators_and_units() + # Disable measurement if auto range is on if self.measure.present: - self.measure._enabled &= val + self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? - def _source_mode_get_parser(self, val): - """Get output (VOLT/CURR) mode and update validators""" - self._update_vals(source_mode=val) - return val + def _set_source_mode(self, mode): + """ + Set output mode and update validators - def _set_source_mode(self, val): - """Set output (VOLT/CURR) mode and update validators""" - # Cannot set source mode when the output is on - if self.output.get() == 'on': + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + """ + if self.output() == 'on': raise GS200Exception("Cannot switch mode while source is on") - # Write the new mode to the instrument - self.write("SOUR:FUNC {}".format(val)) - # Update the parameters and validators appropriately - self._update_vals(source_mode=val) - def _getset_range(self, val): - """Update range and validators""" - val = float(val) + self.write("SOUR:FUNC {}".format(mode)) + self._update_validators_and_units(source_mode=mode) - # Check appropriate range depending on source mode - source_mode = self.ask(":SOUR:FUNC?") - if source_mode == 'VOLT': - if val not in (10e-3, 100e-3, 1e0, 10e0, 30e0): - raise ValueError("Invalid voltage range") - else: - if val not in (1e-3, 10e-3, 100e-3, 200e-3): - raise ValueError("Invalid current range") + def _range_set_parser(self, val): + """ + Update range and validators - # Update validators and parameters - self._update_vals(source_mode=source_mode, source_range=val) + Parameters + ---------- + val: float + The output set range is validated by the GS200RangeValidator + """ + val = float(val) + source_mode = self.source_mode() + self._update_validators_and_units(source_mode=source_mode, source_range=val) return val def _output_get_parser(self, output_mode): """ Setting the current/voltage while in voltage/current mode will rightfully raise an error. However, we also want to raise an error while trying to get the output when we are in the wrong output mode (e.g. getting the - current while in voltage mode and visa-versa) + current while in voltage mode and visa-versa). This will prevent user confusion Parameters ---------- From fcec4ec72ae7a58b32c0352d91025d1dc04cfd02 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 7 Nov 2017 19:45:14 +0100 Subject: [PATCH 15/77] Much simpler code --- qcodes/instrument_drivers/yokogawa/GS200.py | 124 +++++++++----------- 1 file changed, 55 insertions(+), 69 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 2e3315a5bd0..1feb6669cea 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,3 +1,5 @@ +from functools import partial + from qcodes import VisaInstrument, InstrumentChannel from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints, Validator @@ -223,18 +225,16 @@ def __init__(self, name, address, **kwargs): self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=":SOUR:LEV {:.5e}", - get_cmd=":SOUR:LEV?", - get_parser=self._output_get_parser("VOLT"), - vals=Numbers()) + set_cmd=partial(self._set_output, "VOLT"), + get_cmd=partial(self._get_output, "VOLT") + ) self.add_parameter('current', label='Current', unit='I', - set_cmd=":SOUR:LEV {:.5e}", - get_cmd=":SOUR:LEV?", - get_parser=self._output_get_parser("CURR"), - vals=Numbers()) + set_cmd=partial(self._set_output, "CURR"), + get_cmd=partial(self._get_output, "CURR") + ) self.add_parameter('voltage_limit', label='Voltage Protection Limit', @@ -309,7 +309,7 @@ def state(self): self.measure._output = bool(state) return state - def _update_validators_and_units(self, source_mode=None, source_range=None): + def _update_range_units(self, source_mode=None, source_range=None): """ Update validators/units as source mode/range changes @@ -327,30 +327,8 @@ def _update_validators_and_units(self, source_mode=None, source_range=None): # Setup source based on what mode we are in # Range is updated if auto-range is off if source_mode == 'VOLT': - if self.auto_range.get(): - self.voltage.set_raw.cmd_str = ":SOUR:LEV:AUTO {:.5e}" - else: - self.voltage.set_raw.cmd_str = ":SOUR:LEV {:.5e}" - - self.current.vals = Nothing("Current cannot be set in voltage mode") - if self.auto_range.get(): - self.voltage.vals = Numbers(-30, 30) - else: - self.voltage.vals = Numbers(-source_range, source_range) - self.range.unit = "V" else: - if self.auto_range.get(): - self.current.set_raw.cmd_str = ":SOUR:LEV:AUTO {:.5e}" - else: - self.current.set_raw.cmd_str = ":SOUR:LEV {:.5e}" - - self.voltage.vals = Nothing("Voltage cannot be set in current mode") - if self.auto_range.get(): - self.current.vals = Numbers(-0.1, 0.1) - else: - self.current.vals = Numbers(-source_range, source_range) - self.range.unit = "I" # Finally if measurements are enabled, update measurement units @@ -358,17 +336,58 @@ def _update_validators_and_units(self, source_mode=None, source_range=None): if self.measure.present: self.measure._update_measurement_enabled(source_mode, source_range, False) + def _set_output(self, mode, output_level): + """ + Set the output of the instrument. + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + The desired output mode. If the current output mode does not match the desired output, an exception is + raised + + output_level: float + """ + current_mode = self.source_mode() + if current_mode != mode: + raise ValueError("Cannot output {} while in {} mode".format(mode, current_mode)) + + auto_enabled = self.auto_range() + self_range = self.range() + + if not auto_enabled and abs(output_level) > abs(self_range): + raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( + self_range=self_range)) + + auto_str = {True: ":AUTO", False: ""}[auto_enabled] + cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) + self.write(cmd_str) + + def _get_output(self, mode): + """ + Get the output of an instrument + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + """ + current_mode = self.source_mode() + if current_mode != mode: + raise ValueError("Cannot measure {} while in {} mode".format(mode, current_mode)) + + answer = self.ask(":SOUR:LEV?") + return float(answer) + def _set_auto_range(self, val): """ - Enable/disable auto range. Note that the instrument itself does not provide auto range. This is implemented - in software. + Enable/disable auto range. Parameters ---------- val: bool """ self._auto_range = val - self._update_validators_and_units() + self._update_range_units() # Disable measurement if auto range is on if self.measure.present: self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? @@ -385,7 +404,7 @@ def _set_source_mode(self, mode): raise GS200Exception("Cannot switch mode while source is on") self.write("SOUR:FUNC {}".format(mode)) - self._update_validators_and_units(source_mode=mode) + self._update_range_units(source_mode=mode) def _range_set_parser(self, val): """ @@ -398,38 +417,5 @@ def _range_set_parser(self, val): """ val = float(val) source_mode = self.source_mode() - self._update_validators_and_units(source_mode=source_mode, source_range=val) + self._update_range_units(source_mode=source_mode, source_range=val) return val - - def _output_get_parser(self, output_mode): - """ - Setting the current/voltage while in voltage/current mode will rightfully raise an error. However, we also - want to raise an error while trying to get the output when we are in the wrong output mode (e.g. getting the - current while in voltage mode and visa-versa). This will prevent user confusion - - Parameters - ---------- - output_mode: str, ["Curr", "Volt"] - - Returns - ------- - output_parser: callable - The get parser for the current/voltage output - """ - - def assert_output_type(mode): - human_readable = { - "CURR": "current", - "VOLT": "voltage" - } - - if mode != output_mode: - raise GS200Exception("Cannot get {} while in {} mode".format(human_readable[output_mode], - human_readable[mode])) - - def output_parser(val): - mode = self.source_mode() - assert_output_type(mode) - return val - - return output_parser From 99dad44c99b5ee0424210c8a8b202d77bc17fd0e Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 8 Nov 2017 10:33:04 +0100 Subject: [PATCH 16/77] right before a big change --- qcodes/instrument_drivers/yokogawa/GS200.py | 210 ++++++++++++-------- 1 file changed, 131 insertions(+), 79 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 1feb6669cea..cb618c146c0 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -95,9 +95,6 @@ def __init__(self, parent, name, present): get_cmd=':SENS:INT?', get_parser=float) - self.add_function('on', call_cmd=self.on) - self.add_function('off', call_cmd=self.off) - def off(self): """Turn measurement off""" self.write(':SENS 0') @@ -133,13 +130,13 @@ def _get_measurement(self): elif not self._output: raise GS200Exception("Output is off") elif self._parent.auto_range.get(): - raise GS200Exception("Measurements will not work when in autorange mode") + raise GS200Exception("Measurements will not work when in auto range mode") elif self._unit == "VOLT" and self._range < 1: raise GS200Exception("Measurements will not work when range is <1V") elif not self._enabled: raise GS200Exception("Measurements are disabled") - def _update_measurement_enabled(self, unit, output_range, output): + def update_measurement_enabled(self, unit, output_range, output): # Recheck measurement state next time we do a measurement self._enabled = False # Update output state @@ -155,26 +152,6 @@ def _update_measurement_enabled(self, unit, output_range, output): self.measure.unit = 'V' -class GS200RangeValidator(Validator): - def __init__(self, parent_instrument): - self._parent_instrument = parent_instrument - - def validate(self, value, context=''): - - mode = self._parent_instrument.source_mode() - - if mode == "CURR": - valid_values = [1e-3, 10e-3, 100e-3, 200e-3] - else: - valid_values = [10e-3, 100e-3, 1e0, 10e0, 30e0] - - if value not in valid_values: - raise ValueError("{} invalid range for mode {}".format(str(value), mode)) - - def __repr__(self): - return "GS200RangeValidator" - - class GS200(VisaInstrument): """ This is the qcodes driver for the Yokogawa GS200 voltage and current source @@ -204,15 +181,26 @@ def __init__(self, name, address, **kwargs): set_cmd=self._set_source_mode, vals=Enum('VOLT', 'CURR')) - self.add_parameter('range', - label='Source Range', - unit='?', # This will be set by the get/set parser + self.add_parameter('voltage_range', + label='Voltage Source Range', + unit='V', + get_cmd=':SOUR:RANG?', + set_cmd=':SOUR:RANG {}', + vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0), + set_parser=partial(self._range_set_parser, "VOLT"), + get_parser=float) + + self.add_parameter('current_range', + label='Current Source Range', + unit='I', get_cmd=':SOUR:RANG?', set_cmd=':SOUR:RANG {}', - vals=GS200RangeValidator(self), - set_parser=self._range_set_parser, + vals=Enum(1e-3, 10e-3, 100e-3, 200e-3), + set_parser=partial(self._range_set_parser, "CURR"), get_parser=float) + self.range = self.voltage_range # This is changed through the source_mode interface + self._auto_range = False self.add_parameter('auto_range', label='Auto Range', @@ -220,22 +208,31 @@ def __init__(self, name, address, **kwargs): get_cmd=lambda: self._auto_range, vals=Bool()) - # Note: Get and set for voltage/current will be updated by once - # range and mode are known + # Note: For the parameters voltage and current, we are misusing the parsers + # as validators. This is the easiest way to ensure that the voltage/current settings + # are not accessed in the wrong mode. Additionally, some validation is also done in the set_output + # function as the validator conditions are dependent on the source mode and whether or not we are + # in auto range mode. self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=partial(self._set_output, "VOLT"), - get_cmd=partial(self._get_output, "VOLT") + set_cmd=self._set_output, + get_cmd=":SOUR:LEV?", + set_parser=partial(self._mode_parser, "VOLT"), + get_parser=partial(self._mode_parser, "VOLT") ) self.add_parameter('current', label='Current', unit='I', - set_cmd=partial(self._set_output, "CURR"), - get_cmd=partial(self._get_output, "CURR") + set_cmd=self._set_output, + get_cmd=":SOUR:LEV?", + set_parser=partial(self._mode_parser, "CURR"), + get_parser=partial(self._mode_parser, "CURR") ) + self.output_level = self.voltage # This is changed through the source_mode interface + self.add_parameter('voltage_limit', label='Voltage Protection Limit', unit='V', @@ -309,53 +306,85 @@ def state(self): self.measure._output = bool(state) return state - def _update_range_units(self, source_mode=None, source_range=None): + def ramp_voltage(self, ramp_to, step, delay): """ - Update validators/units as source mode/range changes + Ramp the voltage from the current level to the specified output Parameters ---------- - source_mode: str, ["CURR", "VOLT"] - source_range: float + ramp_to: float + The ramp target in Volt + step: float + The ramp steps in Volt + delay: float + The time between finishing one step and starting another in seconds. """ - if source_mode is None: - source_mode = self.source_mode() - # Get source range if auto-range is off - if source_range is None and not self.auto_range(): - source_range = self.range() + self._assert_mode("VOLT") + self._ramp_source(ramp_to, step, delay) - # Setup source based on what mode we are in - # Range is updated if auto-range is off - if source_mode == 'VOLT': - self.range.unit = "V" - else: - self.range.unit = "I" + def ramp_current(self, ramp_to, step, delay): + """ + Ramp the current from the current level to the specified output - # Finally if measurements are enabled, update measurement units - # Source output is set to false and will be checked when a measurement is made - if self.measure.present: - self.measure._update_measurement_enabled(source_mode, source_range, False) + Parameters + ---------- + ramp_to: float + The ramp target in Ampere + step: float + The ramp steps in Ampere + delay: float + The time between finishing one step and starting another in seconds. + """ + self._assert_mode("CURR") + self._ramp_source(ramp_to, step, delay) - def _set_output(self, mode, output_level): + def _ramp_source(self, ramp_to, step, delay): """ - Set the output of the instrument. + Ramp the output from the current level to the specified output Parameters ---------- - mode: str, ["CURR", "VOLT"] - The desired output mode. If the current output mode does not match the desired output, an exception is - raised + ramp_to: float + The ramp target in Volt/Ampere + step: float + The ramp steps in Volt/Ampere + delay: float + The time between finishing one step and starting another in seconds. + """ + saved_step = self.output_level.step + saved_inter_delay = self.output_level.inter_delay - output_level: float + self.output_level.step = step + self.output_level.inter_delay = delay + self.output_level(ramp_to) + + self.output_level.step = saved_step + self.output_level.inter_delay = saved_inter_delay + + def _get_set_output(self, mode, output_level=None): + self._assert_mode(mode) + if output_level is not None: + self._set_output(output_level) + else: + return float(self.ask(":SOUR:LEV?")) + + def _set_output(self, output_level): """ - current_mode = self.source_mode() - if current_mode != mode: - raise ValueError("Cannot output {} while in {} mode".format(mode, current_mode)) + Set the output of the instrument. + Parameters + ---------- + output_level: float + """ auto_enabled = self.auto_range() - self_range = self.range() - if not auto_enabled and abs(output_level) > abs(self_range): + if not auto_enabled: + self_range = self.range() + else: + mode = self.source_mode() + self_range = {"CURR": 200E-3, "VOLT": 30}[mode] + + if abs(output_level) > abs(self_range): raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( self_range=self_range)) @@ -363,20 +392,26 @@ def _set_output(self, mode, output_level): cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) self.write(cmd_str) - def _get_output(self, mode): + def _update_range_units(self, source_mode=None, source_range=None): """ - Get the output of an instrument + Update validators/units as source mode/range changes Parameters ---------- - mode: str, ["CURR", "VOLT"] + source_mode: str, ["CURR", "VOLT"] + source_range: float """ - current_mode = self.source_mode() - if current_mode != mode: - raise ValueError("Cannot measure {} while in {} mode".format(mode, current_mode)) + if source_mode is None: + source_mode = self.source_mode() + # Get source range if auto-range is off + if source_range is None and not self.auto_range(): + source_range = self.range() + + # Finally if measurements are enabled, update measurement units + # Source output is set to false and will be checked when a measurement is made + if self.measure.present: + self.measure.update_measurement_enabled(source_mode, source_range, False) - answer = self.ask(":SOUR:LEV?") - return float(answer) def _set_auto_range(self, val): """ @@ -392,6 +427,22 @@ def _set_auto_range(self, val): if self.measure.present: self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? + def _assert_mode(self, mode): + """ + Assert that we are in the correct mode to perform an operation + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + """ + current_mode = self.source_mode() + if current_mode != mode: + raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, current_mode)) + + def _mode_parser(self, mode, value): + self._assert_mode(mode) + return float(value) + def _set_source_mode(self, mode): """ Set output mode and update validators @@ -403,19 +454,20 @@ def _set_source_mode(self, mode): if self.output() == 'on': raise GS200Exception("Cannot switch mode while source is on") + self.range = {"VOLT": self.voltage_range, "CURR": self.current_range}[mode] + self.output_level = {"VOLT": self.voltage, "CURR": self.current}[mode] + self.write("SOUR:FUNC {}".format(mode)) self._update_range_units(source_mode=mode) - def _range_set_parser(self, val): + def _range_set_parser(self, mode, val): """ Update range and validators Parameters ---------- val: float - The output set range is validated by the GS200RangeValidator """ - val = float(val) - source_mode = self.source_mode() - self._update_range_units(source_mode=source_mode, source_range=val) + val = self._mode_parser(mode, val) + self._update_range_units(source_mode=mode, source_range=val) return val From ee3ff8bb0f3728f003ad8072c5400a2fc33d37c5 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 8 Nov 2017 11:03:54 +0100 Subject: [PATCH 17/77] not using parsers for validation anymore --- qcodes/instrument_drivers/yokogawa/GS200.py | 36 +++++++++------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index cb618c146c0..3e86c172cbd 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -208,27 +208,18 @@ def __init__(self, name, address, **kwargs): get_cmd=lambda: self._auto_range, vals=Bool()) - # Note: For the parameters voltage and current, we are misusing the parsers - # as validators. This is the easiest way to ensure that the voltage/current settings - # are not accessed in the wrong mode. Additionally, some validation is also done in the set_output - # function as the validator conditions are dependent on the source mode and whether or not we are - # in auto range mode. self.add_parameter('voltage', label='Voltage', unit='V', - set_cmd=self._set_output, - get_cmd=":SOUR:LEV?", - set_parser=partial(self._mode_parser, "VOLT"), - get_parser=partial(self._mode_parser, "VOLT") + set_cmd=partial(self._get_set_output, "VOLT"), + get_cmd=partial(self._get_set_output, "VOLT") ) self.add_parameter('current', label='Current', unit='I', - set_cmd=self._set_output, - get_cmd=":SOUR:LEV?", - set_parser=partial(self._mode_parser, "CURR"), - get_parser=partial(self._mode_parser, "CURR") + set_cmd=partial(self._get_set_output, "CURR"), + get_cmd=partial(self._get_set_output, "CURR") ) self.output_level = self.voltage # This is changed through the source_mode interface @@ -362,6 +353,15 @@ def _ramp_source(self, ramp_to, step, delay): self.output_level.inter_delay = saved_inter_delay def _get_set_output(self, mode, output_level=None): + """ + Get or set the output level. + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + output_level: float, optional + If missing, we assume that we are getting the current level. Else we are setting it + """ self._assert_mode(mode) if output_level is not None: self._set_output(output_level) @@ -412,7 +412,6 @@ def _update_range_units(self, source_mode=None, source_range=None): if self.measure.present: self.measure.update_measurement_enabled(source_mode, source_range, False) - def _set_auto_range(self, val): """ Enable/disable auto range. @@ -439,13 +438,9 @@ def _assert_mode(self, mode): if current_mode != mode: raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, current_mode)) - def _mode_parser(self, mode, value): - self._assert_mode(mode) - return float(value) - def _set_source_mode(self, mode): """ - Set output mode and update validators + Set output mode Parameters ---------- @@ -468,6 +463,7 @@ def _range_set_parser(self, mode, val): ---------- val: float """ - val = self._mode_parser(mode, val) + self._assert_mode(mode) + val = float(val) self._update_range_units(source_mode=mode, source_range=val) return val From bca5294154cf19b067c512b742ef228535ca2d26 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 8 Nov 2017 11:07:36 +0100 Subject: [PATCH 18/77] copied from other clone --- qcodes/instrument_drivers/yokogawa/GS200.py | 461 +++++++++++++++++++- 1 file changed, 446 insertions(+), 15 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 26283396322..3e86c172cbd 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,5 +1,155 @@ -from qcodes.instrument.visa import VisaInstrument -from qcodes.utils.validators import Numbers +from functools import partial + +from qcodes import VisaInstrument, InstrumentChannel +from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints, Validator + + +def float_round(val): + """ + Rounds a floating number represented as a string + + Parameters + ---------- + val: str + + Returns + ------- + int + """ + return round(float(val)) + + +class GS200Exception(Exception): + pass + + +class GS200_Monitor(InstrumentChannel): + """ + Monitor part of the GS200. This is only enabled if it is + installed in the GS200 (it is an optional extra). + + The units will be automatically updated as required. + + To measure: + `GS200.measure.measure()` + """ + def __init__(self, parent, name, present): + super().__init__(parent, name) + + # Is the feature installed in the instrument + self.present = present + # Start off with all disabled + self._enabled = False + self._output = False + # Set up monitoring paramters + if present: + self.add_parameter('enabled', + label='Measurement Enabled', + get_cmd=self.state, + set_cmd=lambda x: self.on() if x else self.off(), + val_mapping={ + 'off': 0, + 'on': 1, + }) + + # Note: Measurement will only run if source and measurement is enabled. + self.add_parameter('measure', + label='', unit='V/I', + get_cmd=self._get_measurement) + + self.add_parameter('NPLC', + label='NPLC', + unit='1/LineFreq', + vals=Ints(1, 25), + set_cmd=':SENS:NPLC {}', + set_parser=int, + get_cmd=':SENS:NPLC?', + get_parser=float_round) + self.add_parameter('delay', + label='Measurement Delay', + unit='ms', + vals=Ints(0, 999999), + set_cmd=':SENS:DEL {}', + set_parser=int, + get_cmd=':SENS:DEL?', + get_parser=float_round) + self.add_parameter('trigger', + label='Trigger Source', + set_cmd=':SENS:TRIG {}', + get_cmd=':SENS:TRIG?', + val_mapping={ + 'READY': 'READ', + 'READ': 'READ', + 'TIMER': 'TIM', + 'TIM': 'TIM', + 'COMMUNICATE': 'COMM', + 'IMMEDIATE': 'IMM', + 'IMM': 'IMM' + }) + self.add_parameter('interval', + label='Measurement Interal', + unit='s', + vals=Numbers(0.1, 3600), + set_cmd=':SENS:INT {}', + set_parser=float, + get_cmd=':SENS:INT?', + get_parser=float) + + def off(self): + """Turn measurement off""" + self.write(':SENS 0') + self._enabled = False + + def on(self): + """Turn measurement on""" + self.write(':SENS 1') + self._enabled = True + + def state(self): + """Check measurement state""" + state = int(self.ask(':SENS?')) + self._enabled = bool(state) + return state + + def _get_measurement(self): + """ Check that measurements are enabled and then take a measurement """ + if not self._enabled or not self._output: + # Check if the output is on + self._output = self._output or self._parent.output.get() == 'on' + + if self._parent.auto_range.get() or (self._unit == 'VOLT' and self._range < 1): + # Measurements will not work with autorange, or when range is <1V + self._enabled = False + elif not self._enabled: + # Otherwise check if measurements are enabled + self._enabled = (self.enabled.get() == 'on') + # If enabled and output is on, then we can perform a measurement + if self._enabled and self._output: + return float(self.ask(':MEAS?')) + # Otherwise raise an exception + elif not self._output: + raise GS200Exception("Output is off") + elif self._parent.auto_range.get(): + raise GS200Exception("Measurements will not work when in auto range mode") + elif self._unit == "VOLT" and self._range < 1: + raise GS200Exception("Measurements will not work when range is <1V") + elif not self._enabled: + raise GS200Exception("Measurements are disabled") + + def update_measurement_enabled(self, unit, output_range, output): + # Recheck measurement state next time we do a measurement + self._enabled = False + # Update output state + self._output = output + # Update units + self._range = output_range + self._unit = unit + if self._unit == 'VOLT': + self.measure.label = 'Source Current' + self.measure.unit = 'I' + else: + self.measure.label = 'Source Voltage' + self.measure.unit = 'V' class GS200(VisaInstrument): @@ -10,29 +160,310 @@ class GS200(VisaInstrument): name (str): What this instrument is called locally. address (str): The GPIB address of this instrument kwargs (dict): kwargs to be passed to VisaInstrument class - - TODO:(nataliejpg) - - add current functionality (mode settings) """ def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) + self.visa_handle.read_termination = "\n" + + self.add_parameter('output', + label='Output State', + get_cmd=self.state, + set_cmd=lambda x: self.on() if x else self.off(), + val_mapping={ + 'off': 0, + 'on': 1, + }) + + self.add_parameter('source_mode', + label='Source Mode', + get_cmd=':SOUR:FUNC?', + set_cmd=self._set_source_mode, + vals=Enum('VOLT', 'CURR')) + + self.add_parameter('voltage_range', + label='Voltage Source Range', + unit='V', + get_cmd=':SOUR:RANG?', + set_cmd=':SOUR:RANG {}', + vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0), + set_parser=partial(self._range_set_parser, "VOLT"), + get_parser=float) + + self.add_parameter('current_range', + label='Current Source Range', + unit='I', + get_cmd=':SOUR:RANG?', + set_cmd=':SOUR:RANG {}', + vals=Enum(1e-3, 10e-3, 100e-3, 200e-3), + set_parser=partial(self._range_set_parser, "CURR"), + get_parser=float) + + self.range = self.voltage_range # This is changed through the source_mode interface + + self._auto_range = False + self.add_parameter('auto_range', + label='Auto Range', + set_cmd=self._set_auto_range, + get_cmd=lambda: self._auto_range, + vals=Bool()) self.add_parameter('voltage', label='Voltage', unit='V', - get_cmd=':SOURce:LEVel?', - set_cmd=':SOURce:LEVel:AUTO {:.4f}', + set_cmd=partial(self._get_set_output, "VOLT"), + get_cmd=partial(self._get_set_output, "VOLT") + ) + + self.add_parameter('current', + label='Current', + unit='I', + set_cmd=partial(self._get_set_output, "CURR"), + get_cmd=partial(self._get_set_output, "CURR") + ) + + self.output_level = self.voltage # This is changed through the source_mode interface + + self.add_parameter('voltage_limit', + label='Voltage Protection Limit', + unit='V', + vals=Ints(1, 30), + get_cmd=":SOUR:PROT:VOLT?", + set_cmd=":SOUR:PROT:VOLT {}", + get_parser=float_round, + set_parser=int) + + self.add_parameter('current_limit', + label='Current Protection Limit', + unit='I', + vals=Numbers(1e-3, 200e-3), + get_cmd=":SOUR:PROT:CURR?", + set_cmd=":SOUR:PROT:CURR {:.3f}", get_parser=float, - vals=Numbers(-10, 10)) + set_parser=float) - self.add_function('reset', call_cmd='*RST') + self.add_parameter('four_wire', + label='Four Wire Sensing', + get_cmd=':SENS:REM?', + set_cmd=':SENS:REM {}', + val_mapping={ + 'off': 0, + 'on': 1, + }) + # Note: This feature can be used to remove common mode noise. + # Read the manual to see if you would like to use it + self.add_parameter('guard', + label='Guard Terminal', + get_cmd=':SENS:GUAR?', + set_cmd=':SENS:GUAR {}', + val_mapping={ + 'off': 0, + 'on': 1, + }) + + # Return measured line frequency + self.add_parameter("line_freq", + label='Line Frequency', + unit="Hz", + get_cmd="SYST:LFR?", + get_parser=int) - self.initialise() + # Check if monitor is present, and if so enable measurement + monitor_present = '/MON' in self.ask("*OPT?") + measure = GS200_Monitor(self, 'measure', monitor_present) + self.add_submodule('measure', measure) + + # Reset function + self.add_function('reset', call_cmd='*RST') self.connect_message() - def initialise(self): - self.write(':SYST:DISP ON') - self.write(':SOUR:FUNC VOLT') - self.write(':SOUR:PROT:CURR MIN') - self.write(':OUTP:STAT ON') + self.output("off") + self.source_mode("VOLT") + self.auto_range(True) + + def on(self): + """Turn output on""" + self.write('OUTPUT 1') + self.measure._output = True + + def off(self): + """Turn output off""" + self.write('OUTPUT 0') + self.measure._output = False + + def state(self): + """Check state""" + state = int(self.ask('OUTPUT?')) + self.measure._output = bool(state) + return state + + def ramp_voltage(self, ramp_to, step, delay): + """ + Ramp the voltage from the current level to the specified output + + Parameters + ---------- + ramp_to: float + The ramp target in Volt + step: float + The ramp steps in Volt + delay: float + The time between finishing one step and starting another in seconds. + """ + self._assert_mode("VOLT") + self._ramp_source(ramp_to, step, delay) + + def ramp_current(self, ramp_to, step, delay): + """ + Ramp the current from the current level to the specified output + + Parameters + ---------- + ramp_to: float + The ramp target in Ampere + step: float + The ramp steps in Ampere + delay: float + The time between finishing one step and starting another in seconds. + """ + self._assert_mode("CURR") + self._ramp_source(ramp_to, step, delay) + + def _ramp_source(self, ramp_to, step, delay): + """ + Ramp the output from the current level to the specified output + + Parameters + ---------- + ramp_to: float + The ramp target in Volt/Ampere + step: float + The ramp steps in Volt/Ampere + delay: float + The time between finishing one step and starting another in seconds. + """ + saved_step = self.output_level.step + saved_inter_delay = self.output_level.inter_delay + + self.output_level.step = step + self.output_level.inter_delay = delay + self.output_level(ramp_to) + + self.output_level.step = saved_step + self.output_level.inter_delay = saved_inter_delay + + def _get_set_output(self, mode, output_level=None): + """ + Get or set the output level. + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + output_level: float, optional + If missing, we assume that we are getting the current level. Else we are setting it + """ + self._assert_mode(mode) + if output_level is not None: + self._set_output(output_level) + else: + return float(self.ask(":SOUR:LEV?")) + + def _set_output(self, output_level): + """ + Set the output of the instrument. + + Parameters + ---------- + output_level: float + """ + auto_enabled = self.auto_range() + + if not auto_enabled: + self_range = self.range() + else: + mode = self.source_mode() + self_range = {"CURR": 200E-3, "VOLT": 30}[mode] + + if abs(output_level) > abs(self_range): + raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( + self_range=self_range)) + + auto_str = {True: ":AUTO", False: ""}[auto_enabled] + cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) + self.write(cmd_str) + + def _update_range_units(self, source_mode=None, source_range=None): + """ + Update validators/units as source mode/range changes + + Parameters + ---------- + source_mode: str, ["CURR", "VOLT"] + source_range: float + """ + if source_mode is None: + source_mode = self.source_mode() + # Get source range if auto-range is off + if source_range is None and not self.auto_range(): + source_range = self.range() + + # Finally if measurements are enabled, update measurement units + # Source output is set to false and will be checked when a measurement is made + if self.measure.present: + self.measure.update_measurement_enabled(source_mode, source_range, False) + + def _set_auto_range(self, val): + """ + Enable/disable auto range. + + Parameters + ---------- + val: bool + """ + self._auto_range = val + self._update_range_units() + # Disable measurement if auto range is on + if self.measure.present: + self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? + + def _assert_mode(self, mode): + """ + Assert that we are in the correct mode to perform an operation + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + """ + current_mode = self.source_mode() + if current_mode != mode: + raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, current_mode)) + + def _set_source_mode(self, mode): + """ + Set output mode + + Parameters + ---------- + mode: str, ["CURR", "VOLT"] + """ + if self.output() == 'on': + raise GS200Exception("Cannot switch mode while source is on") + + self.range = {"VOLT": self.voltage_range, "CURR": self.current_range}[mode] + self.output_level = {"VOLT": self.voltage, "CURR": self.current}[mode] + + self.write("SOUR:FUNC {}".format(mode)) + self._update_range_units(source_mode=mode) + + def _range_set_parser(self, mode, val): + """ + Update range and validators + + Parameters + ---------- + val: float + """ + self._assert_mode(mode) + val = float(val) + self._update_range_units(source_mode=mode, source_range=val) + return val From af5e994caa18ac5cf03bc8c584b651113cd4dcfd Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 14:40:55 +0100 Subject: [PATCH 19/77] For the main GS200 driver class: 1) Use google style docstrings 2) Use type hints --- qcodes/instrument_drivers/yokogawa/GS200.py | 103 ++++++++------------ 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 3e86c172cbd..d8db0f5cdd4 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,7 +1,9 @@ +from typing import Optional + from functools import partial from qcodes import VisaInstrument, InstrumentChannel -from qcodes.utils.validators import Numbers, Bool, Enum, Nothing, Ints, Validator +from qcodes.utils.validators import Numbers, Bool, Enum, Ints def float_round(val): @@ -162,7 +164,7 @@ class GS200(VisaInstrument): kwargs (dict): kwargs to be passed to VisaInstrument class """ - def __init__(self, name, address, **kwargs): + def __init__(self, name: str, address: str, **kwargs): super().__init__(name, address, **kwargs) self.visa_handle.read_termination = "\n" @@ -297,50 +299,38 @@ def state(self): self.measure._output = bool(state) return state - def ramp_voltage(self, ramp_to, step, delay): + def ramp_voltage(self, ramp_to: float, step: float, delay: float) -> None: """ Ramp the voltage from the current level to the specified output - Parameters - ---------- - ramp_to: float - The ramp target in Volt - step: float - The ramp steps in Volt - delay: float - The time between finishing one step and starting another in seconds. + Args: + ramp_to (float): The ramp target in Volt + step (float): The ramp steps in Volt + delay (float): The time between finishing one step and starting another in seconds. """ self._assert_mode("VOLT") self._ramp_source(ramp_to, step, delay) - def ramp_current(self, ramp_to, step, delay): + def ramp_current(self, ramp_to: float, step: float, delay: float) -> None: """ Ramp the current from the current level to the specified output - Parameters - ---------- - ramp_to: float - The ramp target in Ampere - step: float - The ramp steps in Ampere - delay: float - The time between finishing one step and starting another in seconds. + Args: + ramp_to (float): The ramp target in Ampere + step (float): The ramp steps in Ampere + delay (float): The time between finishing one step and starting another in seconds. """ self._assert_mode("CURR") self._ramp_source(ramp_to, step, delay) - def _ramp_source(self, ramp_to, step, delay): + def _ramp_source(self, ramp_to: float, step: float, delay: float) -> None: """ Ramp the output from the current level to the specified output - Parameters - ---------- - ramp_to: float - The ramp target in Volt/Ampere - step: float - The ramp steps in Volt/Ampere - delay: float - The time between finishing one step and starting another in seconds. + Args: + ramp_to (float): The ramp target in Volt/Ampere + step (float): The ramp steps in Volt/Ampere + delay (float): The time between finishing one step and starting another in seconds. """ saved_step = self.output_level.step saved_inter_delay = self.output_level.inter_delay @@ -352,15 +342,13 @@ def _ramp_source(self, ramp_to, step, delay): self.output_level.step = saved_step self.output_level.inter_delay = saved_inter_delay - def _get_set_output(self, mode, output_level=None): + def _get_set_output(self, mode: str, output_level: float=None) -> float: """ Get or set the output level. - Parameters - ---------- - mode: str, ["CURR", "VOLT"] - output_level: float, optional - If missing, we assume that we are getting the current level. Else we are setting it + Args: + mode (str): "CURR" or "VOLT" + output_level (float), If missing, we assume that we are getting the current level. Else we are setting it """ self._assert_mode(mode) if output_level is not None: @@ -368,13 +356,12 @@ def _get_set_output(self, mode, output_level=None): else: return float(self.ask(":SOUR:LEV?")) - def _set_output(self, output_level): + def _set_output(self, output_level: float) -> None: """ Set the output of the instrument. - Parameters - ---------- - output_level: float + Args: + output_level (float): output level in Volt or Ampere, depending on the current mode """ auto_enabled = self.auto_range() @@ -392,14 +379,13 @@ def _set_output(self, output_level): cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) self.write(cmd_str) - def _update_range_units(self, source_mode=None, source_range=None): + def _update_range_units(self, source_mode: str=None, source_range: float=None) -> None: """ Update validators/units as source mode/range changes - Parameters - ---------- - source_mode: str, ["CURR", "VOLT"] - source_range: float + Args: + source_mode (str): "CURR" or "VOLT" + source_range (float): """ if source_mode is None: source_mode = self.source_mode() @@ -412,13 +398,12 @@ def _update_range_units(self, source_mode=None, source_range=None): if self.measure.present: self.measure.update_measurement_enabled(source_mode, source_range, False) - def _set_auto_range(self, val): + def _set_auto_range(self, val: bool) -> None: """ Enable/disable auto range. - Parameters - ---------- - val: bool + Args: + val (bool): auto range on or off """ self._auto_range = val self._update_range_units() @@ -426,25 +411,23 @@ def _set_auto_range(self, val): if self.measure.present: self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? - def _assert_mode(self, mode): + def _assert_mode(self, mode: str) -> None: """ Assert that we are in the correct mode to perform an operation - Parameters - ---------- - mode: str, ["CURR", "VOLT"] + Args: + mode (str): "CURR" or "VOLT" """ current_mode = self.source_mode() if current_mode != mode: raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, current_mode)) - def _set_source_mode(self, mode): + def _set_source_mode(self, mode: str) -> None: """ Set output mode - Parameters - ---------- - mode: str, ["CURR", "VOLT"] + Args: + mode (str): "CURR" or "VOLT" """ if self.output() == 'on': raise GS200Exception("Cannot switch mode while source is on") @@ -455,13 +438,13 @@ def _set_source_mode(self, mode): self.write("SOUR:FUNC {}".format(mode)) self._update_range_units(source_mode=mode) - def _range_set_parser(self, mode, val): + def _range_set_parser(self, mode: str, val: float) -> float: """ Update range and validators - Parameters - ---------- - val: float + Args: + mode (str): "CURR" or "VOLT" + val (float): value to set """ self._assert_mode(mode) val = float(val) From 7038235fb3a5b5a39973c0cdbf029bcd6118e13e Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 15:15:58 +0100 Subject: [PATCH 20/77] Added type hints to the measurement module --- qcodes/instrument_drivers/yokogawa/GS200.py | 37 ++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index d8db0f5cdd4..2610ef34df6 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -34,16 +34,21 @@ class GS200_Monitor(InstrumentChannel): To measure: `GS200.measure.measure()` + + Args: + parent (GS200) + name (str): instrument name + present (bool): """ def __init__(self, parent, name, present): super().__init__(parent, name) - # Is the feature installed in the instrument self.present = present + # Start off with all disabled self._enabled = False self._output = False - # Set up monitoring paramters + # Set up monitoring parameters if present: self.add_parameter('enabled', label='Measurement Enabled', @@ -138,7 +143,13 @@ def _get_measurement(self): elif not self._enabled: raise GS200Exception("Measurements are disabled") - def update_measurement_enabled(self, unit, output_range, output): + def update_measurement_enabled(self, unit: str, output_range: float, output: bool): + """ + Args: + unit (str) + output_range (float) + output (bool) + """ # Recheck measurement state next time we do a measurement self._enabled = False # Update output state @@ -379,7 +390,7 @@ def _set_output(self, output_level: float) -> None: cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) self.write(cmd_str) - def _update_range_units(self, source_mode: str=None, source_range: float=None) -> None: + def _update_measurement_module(self, source_mode: str=None, source_range: float=None) -> None: """ Update validators/units as source mode/range changes @@ -387,16 +398,16 @@ def _update_range_units(self, source_mode: str=None, source_range: float=None) - source_mode (str): "CURR" or "VOLT" source_range (float): """ + if not self.measure.present: + return + if source_mode is None: source_mode = self.source_mode() # Get source range if auto-range is off if source_range is None and not self.auto_range(): source_range = self.range() - # Finally if measurements are enabled, update measurement units - # Source output is set to false and will be checked when a measurement is made - if self.measure.present: - self.measure.update_measurement_enabled(source_mode, source_range, False) + self.measure.update_measurement_enabled(source_mode, source_range, False) def _set_auto_range(self, val: bool) -> None: """ @@ -406,10 +417,12 @@ def _set_auto_range(self, val: bool) -> None: val (bool): auto range on or off """ self._auto_range = val - self._update_range_units() + self._update_measurement_module() # Disable measurement if auto range is on if self.measure.present: - self.measure._enabled &= val # TODO: Sebastian, can you explain what you are doing here? + # Disable the measurement module if auto range is enabled, because the measurement does not work in the + # 10mV/100mV ranges + self.measure._enabled &= not val def _assert_mode(self, mode: str) -> None: """ @@ -436,7 +449,7 @@ def _set_source_mode(self, mode: str) -> None: self.output_level = {"VOLT": self.voltage, "CURR": self.current}[mode] self.write("SOUR:FUNC {}".format(mode)) - self._update_range_units(source_mode=mode) + self._update_measurement_module(source_mode=mode) def _range_set_parser(self, mode: str, val: float) -> float: """ @@ -448,5 +461,5 @@ def _range_set_parser(self, mode: str, val: float) -> float: """ self._assert_mode(mode) val = float(val) - self._update_range_units(source_mode=mode, source_range=val) + self._update_measurement_module(source_mode=mode, source_range=val) return val From 6e8aceb3b0267abf229a62dc862434ce4787c9c5 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 17:10:35 +0100 Subject: [PATCH 21/77] cached the range value --- qcodes/instrument_drivers/yokogawa/GS200.py | 57 ++++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 2610ef34df6..73e77857a94 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -194,25 +194,33 @@ def __init__(self, name: str, address: str, **kwargs): set_cmd=self._set_source_mode, vals=Enum('VOLT', 'CURR')) + # When getting the mode internally in the driver, look up the mode as recorded by the _cashed_mode property, + # instead of calling source_mode(). This will prevent frequent VISA calls to the instrument. Calling + # _set_source_mode will change the chased value. + self._cashed_mode = "VOLT" + + # We want to cache the range value so communication with the instrument only happens when the set the + # range. Getting the range always returns the cached value. This value is adjusted when calling + # self._set_range_parser + self._cached_range_value = None + self.add_parameter('voltage_range', label='Voltage Source Range', unit='V', - get_cmd=':SOUR:RANG?', - set_cmd=':SOUR:RANG {}', - vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0), - set_parser=partial(self._range_set_parser, "VOLT"), - get_parser=float) + get_cmd=partial(self._get_range, "VOLT"), + set_cmd=partial(self._set_range, "VOLT"), + vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0)) self.add_parameter('current_range', label='Current Source Range', unit='I', - get_cmd=':SOUR:RANG?', - set_cmd=':SOUR:RANG {}', - vals=Enum(1e-3, 10e-3, 100e-3, 200e-3), - set_parser=partial(self._range_set_parser, "CURR"), - get_parser=float) + get_cmd=partial(self._get_range, "CURR"), + set_cmd=partial(self._set_range, "CURR"), + vals=Enum(1e-3, 10e-3, 100e-3, 200e-3) + ) - self.range = self.voltage_range # This is changed through the source_mode interface + # This is changed through the source_mode interface + self.range = self.voltage_range self._auto_range = False self.add_parameter('auto_range', @@ -235,7 +243,8 @@ def __init__(self, name: str, address: str, **kwargs): get_cmd=partial(self._get_set_output, "CURR") ) - self.output_level = self.voltage # This is changed through the source_mode interface + # This is changed through the source_mode interface + self.output_level = self.voltage self.add_parameter('voltage_limit', label='Voltage Protection Limit', @@ -379,7 +388,7 @@ def _set_output(self, output_level: float) -> None: if not auto_enabled: self_range = self.range() else: - mode = self.source_mode() + mode = self._cashed_mode self_range = {"CURR": 200E-3, "VOLT": 30}[mode] if abs(output_level) > abs(self_range): @@ -402,7 +411,7 @@ def _update_measurement_module(self, source_mode: str=None, source_range: float= return if source_mode is None: - source_mode = self.source_mode() + source_mode = self._cashed_mode # Get source range if auto-range is off if source_range is None and not self.auto_range(): source_range = self.range() @@ -431,9 +440,8 @@ def _assert_mode(self, mode: str) -> None: Args: mode (str): "CURR" or "VOLT" """ - current_mode = self.source_mode() - if current_mode != mode: - raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, current_mode)) + if self._cashed_mode != mode: + raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, self._cashed_mode)) def _set_source_mode(self, mode: str) -> None: """ @@ -450,8 +458,11 @@ def _set_source_mode(self, mode: str) -> None: self.write("SOUR:FUNC {}".format(mode)) self._update_measurement_module(source_mode=mode) + self._cashed_mode = mode + # The next time the range is asked, ask from instrument and update the cached value + self._cached_range_value = None - def _range_set_parser(self, mode: str, val: float) -> float: + def _set_range(self, mode: str, val: float) -> None: """ Update range and validators @@ -462,4 +473,12 @@ def _range_set_parser(self, mode: str, val: float) -> float: self._assert_mode(mode) val = float(val) self._update_measurement_module(source_mode=mode, source_range=val) - return val + self._cached_range_value = val + self.write(':SOUR:RANG {}'.format(str(val))) + + def _get_range(self, mode: str) -> None: + self._assert_mode(mode) + if self._cached_range_value is None: + self._cached_range_value = self.ask(":SOUR:RANG?") + + return self._cached_range_value From 932ea89fcf17f38622f3932855cc24c6e6b194fd Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 17:25:35 +0100 Subject: [PATCH 22/77] 1) Autorange is off at initialization 2) Added an example note book --- .../Qcodes example with Yokogawa.ipynb | 559 ++++++++++++++++++ qcodes/instrument_drivers/yokogawa/GS200.py | 2 +- 2 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb diff --git a/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb new file mode 100644 index 00000000000..9de867f3ff3 --- /dev/null +++ b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb @@ -0,0 +1,559 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\\\Users\\\\a-sochat\\\\development\\\\pysweep2.0\\pysweep\\data_storage\\qcodes.py:12: UserWarning: Your QOcDeS installation does not have the data set support. Make sure that your environment contains the right QCoDeS branch as data set support has not been merged yet in main. QCoDeS data set support is unavailable\n", + " \"Your QOcDeS installation does not have the data set support. Make sure that your environment \"\n" + ] + } + ], + "source": [ + "import sys\n", + "sys.path.append(r\"C:\\\\Users\\\\a-sochat\\\\development\\\\pysweep2.0\")\n", + "import numpy as np\n", + "import time \n", + "\n", + "import pysweep\n", + "from pysweep import measurement, sweep\n", + "from pysweep.data_plot import DataPlot\n", + "\n", + "import qcodes\n", + "from qcodes.instrument_drivers.yokogawa.GS200 import GS200" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Connected to: YOKOGAWA GS210 (serial:91T926460, firmware:2.02) in 0.17s\n" + ] + } + ], + "source": [ + "gs = GS200(\"gs200\", \"GPIB::1::INSTR\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets do some sanity checks " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.output(\"off\")\n", + "gs.source_mode(\"VOLT\")\n", + "gs.voltage(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try to put 1 V on the output " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.auto_range(True)\n", + "gs.voltage(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The instrument indeed goes to 1 V output. Next, assert that an error is raised if we try to get/set the current " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "exception correctly raised\n", + "exception correctly raised\n" + ] + } + ], + "source": [ + "try:\n", + " gs.current(0.001) # Set a current\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except: \n", + " print(\"exception correctly raised\")\n", + "\n", + "try:\n", + " gs.current() # Get the current\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except: \n", + " print(\"exception correctly raised\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.voltage(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The instrument indeed goes back to 0 V output " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.source_mode(\"CURR\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instrument does indeed go to current source mode" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.current(0.001)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The instrument does indeed show 1mA output. Note that because output is off, no actual current is flowing" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'off'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gs.output()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The instrument is indeed in off mode" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Put a 10kOhm resistor over the output and verify that the voltage across the resistor is 1E-3 * 10E3 = 10 V. " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.voltage_limit(30)\n", + "gs.output(\"on\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We verify that the voltage on the multmeter is indeed 10V. Let's verify that if we put a 5 volt voltage limit the voltage does indeed drop to 5 V" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.voltage_limit(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the voltage on the multimeter is indeed 5V " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.current(0.00)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The multimeter reads 0 mA again and the voltage across the resistor is 0 V " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.output(\"off\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The instrument turns output off. Next assert that exceptions are raised if we try to get/set the voltage while still being in current mode" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "exception correctly raised\n", + "exception correctly raised\n" + ] + } + ], + "source": [ + "try:\n", + " gs.volatge(0.0) # Set a voltage\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except: \n", + " print(\"exception correctly raised\")\n", + "\n", + "try:\n", + " gs.voltage() # Get the voltage\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except: \n", + " print(\"exception correctly raised\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, test that we get an exception if we turn off auto ranging and deliberately set the voltage outside of the chosen range" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "exception correctly raised\n" + ] + } + ], + "source": [ + "gs.auto_range(False)\n", + "gs.source_mode(\"VOLT\")\n", + "gs.range(10E-3)\n", + "\n", + "try:\n", + " gs.voltage(1.5)\n", + "except ValueError as exp:\n", + " print(\"exception correctly raised\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Verify that when auto range is true, we can set voltages without being worried about ranges" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.source_mode(\"VOLT\")\n", + "gs.auto_range(True)\n", + "gs.voltage(1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We verify that we can now set the output to 1.5V without problems. Let see if ramping from 0 to 5 volts with steps of 0.5 works. The delay between the steps shall be 1 second, so the entire ramp should take 10 seconds " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This took 10.0 seconds\n" + ] + } + ], + "source": [ + "tb = time.time()\n", + "gs.voltage(0)\n", + "gs.ramp_voltage(5, 0.5, 1)\n", + "te = time.time()\n", + "\n", + "print(\"This took {:.3} seconds\".format(te - tb))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now try to ramp the current while still in volt mode. This should raise an error" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "exception correctly raised\n" + ] + } + ], + "source": [ + "try:\n", + " gs.ramp_current(0, 1E-3, 1)\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except:\n", + " print(\"exception correctly raised\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'10E+0'" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gs.voltage_range()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "exception correctly raised\n" + ] + } + ], + "source": [ + "try:\n", + " gs.current_range()\n", + " print(\"Something has gone wrong\")\n", + " Assert(True)\n", + "except:\n", + " print(\"exception correctly raised\")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.source_mode(\"CURR\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1E-3'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gs.current_range()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "gs.current(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gs.auto_range()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 73e77857a94..f5fb4292047 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -301,7 +301,7 @@ def __init__(self, name: str, address: str, **kwargs): self.output("off") self.source_mode("VOLT") - self.auto_range(True) + self.auto_range(False) def on(self): """Turn output on""" From 63e79f8f2af95d7e9fae1a9b3742247b2aee6970 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 17:41:59 +0100 Subject: [PATCH 23/77] Solved a bug whereby an exception was raised when setting the voltage to zero when auto_range is False --- .../Qcodes example with Yokogawa.ipynb | 90 +++++++++---------- qcodes/instrument_drivers/yokogawa/GS200.py | 2 +- 2 files changed, 41 insertions(+), 51 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb index 9de867f3ff3..320af5b0006 100644 --- a/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb +++ b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb @@ -4,26 +4,11 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\\\Users\\\\a-sochat\\\\development\\\\pysweep2.0\\pysweep\\data_storage\\qcodes.py:12: UserWarning: Your QOcDeS installation does not have the data set support. Make sure that your environment contains the right QCoDeS branch as data set support has not been merged yet in main. QCoDeS data set support is unavailable\n", - " \"Your QOcDeS installation does not have the data set support. Make sure that your environment \"\n" - ] - } - ], + "outputs": [], "source": [ - "import sys\n", - "sys.path.append(r\"C:\\\\Users\\\\a-sochat\\\\development\\\\pysweep2.0\")\n", "import numpy as np\n", "import time \n", "\n", - "import pysweep\n", - "from pysweep import measurement, sweep\n", - "from pysweep.data_plot import DataPlot\n", - "\n", "import qcodes\n", "from qcodes.instrument_drivers.yokogawa.GS200 import GS200" ] @@ -55,16 +40,24 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "gs.output(\"off\")\n", "gs.source_mode(\"VOLT\")\n", + "gs.auto_range(False)\n", "gs.voltage(0)" ] }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "gs.auto_range(True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -74,13 +67,10 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true - }, + "execution_count": 7, + "metadata": {}, "outputs": [], "source": [ - "gs.auto_range(True)\n", "gs.voltage(1)" ] }, @@ -93,7 +83,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -123,7 +113,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "metadata": { "collapsed": true }, @@ -141,7 +131,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -159,7 +149,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "metadata": { "collapsed": true }, @@ -177,7 +167,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -186,7 +176,7 @@ "'off'" ] }, - "execution_count": 9, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -211,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 13, "metadata": { "collapsed": true }, @@ -230,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "metadata": { "collapsed": true }, @@ -248,7 +238,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "metadata": { "collapsed": true }, @@ -266,7 +256,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "metadata": { "collapsed": true }, @@ -284,7 +274,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -321,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -352,7 +342,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 19, "metadata": { "collapsed": true }, @@ -372,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -401,7 +391,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -423,16 +413,16 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'10E+0'" + "10.0" ] }, - "execution_count": 19, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -443,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -465,7 +455,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 24, "metadata": { "collapsed": true }, @@ -476,16 +466,16 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'1E-3'" + "0.001" ] }, - "execution_count": 22, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -496,7 +486,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 26, "metadata": { "collapsed": true }, @@ -507,7 +497,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -516,7 +506,7 @@ "True" ] }, - "execution_count": 24, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index f5fb4292047..532e53a5897 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -479,6 +479,6 @@ def _set_range(self, mode: str, val: float) -> None: def _get_range(self, mode: str) -> None: self._assert_mode(mode) if self._cached_range_value is None: - self._cached_range_value = self.ask(":SOUR:RANG?") + self._cached_range_value = float(self.ask(":SOUR:RANG?")) return self._cached_range_value From 544d917d8c959e9d04b83be09750f337b5c741a2 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 14 Nov 2017 17:44:31 +0100 Subject: [PATCH 24/77] added type hints on the init of GS200_Monitor --- qcodes/instrument_drivers/yokogawa/GS200.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 532e53a5897..cd6c84d8297 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -40,7 +40,7 @@ class GS200_Monitor(InstrumentChannel): name (str): instrument name present (bool): """ - def __init__(self, parent, name, present): + def __init__(self, parent: GS200, name: str, present: bool): super().__init__(parent, name) self.present = present From e14f12c5ab1cac5c42e0adf51bdb1d01dc47d826 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 15 Nov 2017 11:02:41 +0100 Subject: [PATCH 25/77] type hint of GS200_monitor of argument parent needs to be a string 'GS200' as the GS200 class is not defined until later --- qcodes/instrument_drivers/yokogawa/GS200.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index cd6c84d8297..99bdb45d66a 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -40,7 +40,7 @@ class GS200_Monitor(InstrumentChannel): name (str): instrument name present (bool): """ - def __init__(self, parent: GS200, name: str, present: bool): + def __init__(self, parent: 'GS200', name: str, present: bool): super().__init__(parent, name) self.present = present From 5b446e789ac82635d1e9a694adbf511d92e8ad90 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 15 Nov 2017 11:03:50 +0100 Subject: [PATCH 26/77] removed unused import --- qcodes/instrument_drivers/yokogawa/GS200.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 99bdb45d66a..2d04c79bd66 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -1,5 +1,3 @@ -from typing import Optional - from functools import partial from qcodes import VisaInstrument, InstrumentChannel From e65bc20deeed5da1f2315598209e6e3edf923b2b Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Wed, 15 Nov 2017 11:10:11 +0100 Subject: [PATCH 27/77] improved documentation --- qcodes/instrument_drivers/yokogawa/GS200.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 2d04c79bd66..b1ced3e3c9f 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -199,7 +199,7 @@ def __init__(self, name: str, address: str, **kwargs): # We want to cache the range value so communication with the instrument only happens when the set the # range. Getting the range always returns the cached value. This value is adjusted when calling - # self._set_range_parser + # self._set_range self._cached_range_value = None self.add_parameter('voltage_range', From de1f5f35f3bde6816b3c297aeb3e6858d4c665dd Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 12:08:41 +1100 Subject: [PATCH 28/77] Fix documentation/spelling cashed -> cached documentation style consistency --- qcodes/instrument_drivers/yokogawa/GS200.py | 28 ++++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index b1ced3e3c9f..42edaa40386 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -6,15 +6,13 @@ def float_round(val): """ - Rounds a floating number represented as a string + Rounds a floating number - Parameters - ---------- - val: str + Args: + val: number to be rounded - Returns - ------- - int + Returns: + Rounded integer """ return round(float(val)) @@ -192,10 +190,10 @@ def __init__(self, name: str, address: str, **kwargs): set_cmd=self._set_source_mode, vals=Enum('VOLT', 'CURR')) - # When getting the mode internally in the driver, look up the mode as recorded by the _cashed_mode property, + # When getting the mode internally in the driver, look up the mode as recorded by the _cached_mode property, # instead of calling source_mode(). This will prevent frequent VISA calls to the instrument. Calling # _set_source_mode will change the chased value. - self._cashed_mode = "VOLT" + self._cached_mode = "VOLT" # We want to cache the range value so communication with the instrument only happens when the set the # range. Getting the range always returns the cached value. This value is adjusted when calling @@ -270,7 +268,7 @@ def __init__(self, name: str, address: str, **kwargs): 'off': 0, 'on': 1, }) - # Note: This feature can be used to remove common mode noise. + # Note: The guard feature can be used to remove common mode noise. # Read the manual to see if you would like to use it self.add_parameter('guard', label='Guard Terminal', @@ -386,7 +384,7 @@ def _set_output(self, output_level: float) -> None: if not auto_enabled: self_range = self.range() else: - mode = self._cashed_mode + mode = self._cached_mode self_range = {"CURR": 200E-3, "VOLT": 30}[mode] if abs(output_level) > abs(self_range): @@ -409,7 +407,7 @@ def _update_measurement_module(self, source_mode: str=None, source_range: float= return if source_mode is None: - source_mode = self._cashed_mode + source_mode = self._cached_mode # Get source range if auto-range is off if source_range is None and not self.auto_range(): source_range = self.range() @@ -438,8 +436,8 @@ def _assert_mode(self, mode: str) -> None: Args: mode (str): "CURR" or "VOLT" """ - if self._cashed_mode != mode: - raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, self._cashed_mode)) + if self._cached_mode != mode: + raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, self._cached_mode)) def _set_source_mode(self, mode: str) -> None: """ @@ -456,7 +454,7 @@ def _set_source_mode(self, mode: str) -> None: self.write("SOUR:FUNC {}".format(mode)) self._update_measurement_module(source_mode=mode) - self._cashed_mode = mode + self._cached_mode = mode # The next time the range is asked, ask from instrument and update the cached value self._cached_range_value = None From af7a4d4f8f7b2ed9ce254a1ed10bf0f8ec8e75ba Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 12:35:45 +1100 Subject: [PATCH 29/77] Removed uselessly cached values from measure module --- qcodes/instrument_drivers/yokogawa/GS200.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 42edaa40386..2f8be277b20 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -139,17 +139,14 @@ def _get_measurement(self): elif not self._enabled: raise GS200Exception("Measurements are disabled") - def update_measurement_enabled(self, unit: str, output_range: float, output: bool): + def update_measurement_enabled(self, unit: str, output_range: float): """ Args: unit (str) output_range (float) - output (bool) """ # Recheck measurement state next time we do a measurement self._enabled = False - # Update output state - self._output = output # Update units self._range = output_range self._unit = unit @@ -412,7 +409,7 @@ def _update_measurement_module(self, source_mode: str=None, source_range: float= if source_range is None and not self.auto_range(): source_range = self.range() - self.measure.update_measurement_enabled(source_mode, source_range, False) + self.measure.update_measurement_enabled(source_mode, source_range) def _set_auto_range(self, val: bool) -> None: """ From 5ac50b8390d6511638a7dd8a96ac214c46a0507a Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 12:36:25 +1100 Subject: [PATCH 30/77] Unroll dictionaries to set parameters --- qcodes/instrument_drivers/yokogawa/GS200.py | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 2f8be277b20..406790900bd 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -379,16 +379,27 @@ def _set_output(self, output_level: float) -> None: auto_enabled = self.auto_range() if not auto_enabled: - self_range = self.range() + self_range = self._cached_range_value else: mode = self._cached_mode - self_range = {"CURR": 200E-3, "VOLT": 30}[mode] - - if abs(output_level) > abs(self_range): - raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( - self_range=self_range)) - - auto_str = {True: ":AUTO", False: ""}[auto_enabled] + if mode == "CURR": + self_range = 200E-3 + else: + self_range = 30 + + # Check we are not trying to set an out of range value + if self._cached_range_value is None or abs(output_level) > abs(self_range): + # Update range + self.range() + # If we are still out of range, raise a value error + if abs(output_level) > abs(self_range): + raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( + self_range=self_range)) + + if auto_enabled: + auto_str = ":AUTO" + else: + auto_str = "" cmd_str = ":SOUR:LEV{} {:.5e}".format(auto_str, output_level) self.write(cmd_str) @@ -446,8 +457,12 @@ def _set_source_mode(self, mode: str) -> None: if self.output() == 'on': raise GS200Exception("Cannot switch mode while source is on") - self.range = {"VOLT": self.voltage_range, "CURR": self.current_range}[mode] - self.output_level = {"VOLT": self.voltage, "CURR": self.current}[mode] + if mode == "VOLT": + self.range = self.voltage_range + self.output_level = self.voltage + else: + self.range = self.current_range + self.output_level = self.current self.write("SOUR:FUNC {}".format(mode)) self._update_measurement_module(source_mode=mode) From f68af7007cf94071cc564f362962502d29099d02 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 12:36:50 +1100 Subject: [PATCH 31/77] Add missing documentation --- qcodes/instrument_drivers/yokogawa/GS200.py | 27 +++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 406790900bd..4d3ffa415f3 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -341,8 +341,8 @@ def _ramp_source(self, ramp_to: float, step: float, delay: float) -> None: Ramp the output from the current level to the specified output Args: - ramp_to (float): The ramp target in Volt/Ampere - step (float): The ramp steps in Volt/Ampere + ramp_to (float): The ramp target in volts/amps + step (float): The ramp steps in volts/ampere delay (float): The time between finishing one step and starting another in seconds. """ saved_step = self.output_level.step @@ -430,21 +430,24 @@ def _set_auto_range(self, val: bool) -> None: val (bool): auto range on or off """ self._auto_range = val - self._update_measurement_module() # Disable measurement if auto range is on if self.measure.present: # Disable the measurement module if auto range is enabled, because the measurement does not work in the # 10mV/100mV ranges self.measure._enabled &= not val - def _assert_mode(self, mode: str) -> None: + def _assert_mode(self, mode: str, check: bool=True) -> None: """ - Assert that we are in the correct mode to perform an operation + Assert that we are in the correct mode to perform an operation. + If check is True, we double check the instrument if this check fails. Args: mode (str): "CURR" or "VOLT" """ if self._cached_mode != mode: + if check: + self._cached_mode = self.source_mode.get() + self._assert_mode(mode, check=False) raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, self._cached_mode)) def _set_source_mode(self, mode: str) -> None: @@ -472,7 +475,7 @@ def _set_source_mode(self, mode: str) -> None: def _set_range(self, mode: str, val: float) -> None: """ - Update range and validators + Update range Args: mode (str): "CURR" or "VOLT" @@ -484,9 +487,13 @@ def _set_range(self, mode: str, val: float) -> None: self._cached_range_value = val self.write(':SOUR:RANG {}'.format(str(val))) - def _get_range(self, mode: str) -> None: - self._assert_mode(mode) - if self._cached_range_value is None: - self._cached_range_value = float(self.ask(":SOUR:RANG?")) + def _get_range(self, mode: str, force_update: bool=False) -> None: + """ + Update range + Args: + mode (str): "CURR" or "VOLT" + """ + self._assert_mode(mode) + self._cached_range_value = float(self.ask(":SOUR:RANG?")) return self._cached_range_value From 3f3cea3ed0cf9f1b263c2dc7eca94007ad75bb59 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:12:14 +1100 Subject: [PATCH 32/77] Reorder cached value saves. Measure could occasionally read stale values --- qcodes/instrument_drivers/yokogawa/GS200.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 4d3ffa415f3..b93176efdad 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -389,8 +389,11 @@ def _set_output(self, output_level: float) -> None: # Check we are not trying to set an out of range value if self._cached_range_value is None or abs(output_level) > abs(self_range): - # Update range - self.range() + # Check that the range hasn't changed + if not auto_enabled: + # Update range + self.range() + self_range = self._cached_range_value # If we are still out of range, raise a value error if abs(output_level) > abs(self_range): raise ValueError("Desired output level not in range [-{self_range:.3}, {self_range:.3}]".format( @@ -468,10 +471,11 @@ def _set_source_mode(self, mode: str) -> None: self.output_level = self.current self.write("SOUR:FUNC {}".format(mode)) - self._update_measurement_module(source_mode=mode) self._cached_mode = mode # The next time the range is asked, ask from instrument and update the cached value self._cached_range_value = None + # Update the measurement mode + self._update_measurement_module(source_mode=mode) def _set_range(self, mode: str, val: float) -> None: """ @@ -487,9 +491,10 @@ def _set_range(self, mode: str, val: float) -> None: self._cached_range_value = val self.write(':SOUR:RANG {}'.format(str(val))) - def _get_range(self, mode: str, force_update: bool=False) -> None: + def _get_range(self, mode: str) -> None: """ - Update range + Update range. + Note: we do not use cached values here to ensure snapshots correctly update range. Args: mode (str): "CURR" or "VOLT" From dff0fa2686d98f1d5729bdbbf0da93358c41b32d Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:13:18 +1100 Subject: [PATCH 33/77] FIX: set_terminator should change read & write --- qcodes/instrument/visa.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py index 9bb0f754eb0..636f3d60445 100644 --- a/qcodes/instrument/visa.py +++ b/qcodes/instrument/visa.py @@ -101,6 +101,7 @@ def set_terminator(self, terminator): terminator (str): Character(s) to look for at the end of a read. eg. '\r\n'. """ + self.visa_handle.write_termination = terminator self.visa_handle.read_termination = terminator self._terminator = terminator From 9daf13e222af14dcd24de95cd439923a6d991481 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:14:29 +1100 Subject: [PATCH 34/77] Fix syntax errors in usage example Assert(True) -> assert(False) # throw an error if we use the wrong path other small structure changes --- .../Qcodes example with HP8753D.ipynb | 10 ++- .../Qcodes example with Yokogawa.ipynb | 88 +++++++++++-------- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with HP8753D.ipynb b/docs/examples/driver_examples/Qcodes example with HP8753D.ipynb index ecf144d942e..28d9a38b877 100644 --- a/docs/examples/driver_examples/Qcodes example with HP8753D.ipynb +++ b/docs/examples/driver_examples/Qcodes example with HP8753D.ipynb @@ -16,7 +16,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# allow in-notebook matplotlib plots\n", @@ -103,7 +105,9 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# Let's get a single trace of S21 with 10 averages\n", @@ -1039,7 +1043,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.0" + "version": "3.6.2" } }, "nbformat": 4, diff --git a/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb index 320af5b0006..5cea9affa7e 100644 --- a/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb +++ b/docs/examples/driver_examples/Qcodes example with Yokogawa.ipynb @@ -4,7 +4,15 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pyqtgraph plotting not supported, try \"from qcodes.plots.pyqtgraph import QtPlot\" to see the full error\n" + ] + } + ], "source": [ "import numpy as np\n", "import time \n", @@ -22,12 +30,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: YOKOGAWA GS210 (serial:91T926460, firmware:2.02) in 0.17s\n" + "Connected to: YOKOGAWA GS210 (serial:91T928108, firmware:2.02) in 0.08s\n" ] } ], "source": [ - "gs = GS200(\"gs200\", \"GPIB::1::INSTR\")" + "gs = GS200(\"gs200\", 'GPIB0::1::INSTR', terminator=\"\\n\")" ] }, { @@ -51,8 +59,10 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 4, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "gs.auto_range(True)" @@ -67,8 +77,10 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": 5, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "gs.voltage(1)" @@ -83,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -99,21 +111,21 @@ "try:\n", " gs.current(0.001) # Set a current\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except: \n", " print(\"exception correctly raised\")\n", "\n", "try:\n", " gs.current() # Get the current\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except: \n", " print(\"exception correctly raised\")" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "metadata": { "collapsed": true }, @@ -131,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "metadata": { "collapsed": true }, @@ -149,7 +161,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "metadata": { "collapsed": true }, @@ -167,7 +179,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -176,7 +188,7 @@ "'off'" ] }, - "execution_count": 12, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -201,7 +213,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 11, "metadata": { "collapsed": true }, @@ -220,7 +232,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 12, "metadata": { "collapsed": true }, @@ -238,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "metadata": { "collapsed": true }, @@ -256,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 14, "metadata": { "collapsed": true }, @@ -274,7 +286,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -290,14 +302,14 @@ "try:\n", " gs.volatge(0.0) # Set a voltage\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except: \n", " print(\"exception correctly raised\")\n", "\n", "try:\n", " gs.voltage() # Get the voltage\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except: \n", " print(\"exception correctly raised\")" ] @@ -311,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -342,7 +354,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 17, "metadata": { "collapsed": true }, @@ -362,7 +374,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -391,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -406,14 +418,14 @@ "try:\n", " gs.ramp_current(0, 1E-3, 1)\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except:\n", " print(\"exception correctly raised\")" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -422,7 +434,7 @@ "10.0" ] }, - "execution_count": 22, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -433,7 +445,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -448,14 +460,14 @@ "try:\n", " gs.current_range()\n", " print(\"Something has gone wrong\")\n", - " Assert(True)\n", + " assert(False)\n", "except:\n", " print(\"exception correctly raised\")" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 22, "metadata": { "collapsed": true }, @@ -466,7 +478,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -475,7 +487,7 @@ "0.001" ] }, - "execution_count": 25, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -486,7 +498,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 24, "metadata": { "collapsed": true }, @@ -497,7 +509,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -506,7 +518,7 @@ "True" ] }, - "execution_count": 27, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -541,7 +553,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.3" + "version": "3.6.2" } }, "nbformat": 4, From 3ef3a18ed863fc27f76dea28679733501fa1d58d Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:21:44 +1100 Subject: [PATCH 35/77] Remove trailing white space --- qcodes/instrument_drivers/yokogawa/GS200.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index b93176efdad..15b1cb56e13 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -9,7 +9,7 @@ def float_round(val): Rounds a floating number Args: - val: number to be rounded + val: number to be rounded Returns: Rounded integer @@ -493,7 +493,7 @@ def _set_range(self, mode: str, val: float) -> None: def _get_range(self, mode: str) -> None: """ - Update range. + Update range. Note: we do not use cached values here to ensure snapshots correctly update range. Args: From 1452494c5cecf8a7d5b10d041f276c34429fd9ce Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:22:07 +1100 Subject: [PATCH 36/77] Change read termination in initializer `GS200("gs200", "", terminator="\n") if necessary --- qcodes/instrument_drivers/yokogawa/GS200.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 15b1cb56e13..b7ec28b6458 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -170,7 +170,6 @@ class GS200(VisaInstrument): def __init__(self, name: str, address: str, **kwargs): super().__init__(name, address, **kwargs) - self.visa_handle.read_termination = "\n" self.add_parameter('output', label='Output State', From 72442a01d1acd9ff8e81cf0cb45535e7736a6597 Mon Sep 17 00:00:00 2001 From: Sebastian Pauka Date: Mon, 20 Nov 2017 14:24:04 +1100 Subject: [PATCH 37/77] Set read terminator in initialization --- qcodes/instrument_drivers/yokogawa/GS200.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index b7ec28b6458..59fb92eb28d 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -166,10 +166,11 @@ class GS200(VisaInstrument): name (str): What this instrument is called locally. address (str): The GPIB address of this instrument kwargs (dict): kwargs to be passed to VisaInstrument class + terminator (str): read terminator for reads/writes to the instrument. """ - def __init__(self, name: str, address: str, **kwargs): - super().__init__(name, address, **kwargs) + def __init__(self, name: str, address: str, terminator: str="\n", **kwargs): + super().__init__(name, address, terminator=terminator, *kwargs) self.add_parameter('output', label='Output State', From 5e4f33dbd596eebf434ec23bd082535fa06b6e2b Mon Sep 17 00:00:00 2001 From: sohailc Date: Tue, 21 Nov 2017 11:01:47 +0100 Subject: [PATCH 38/77] intermediate work --- .../stanford_research/SR865.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index a3ea49b4ee2..66fe26a4574 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -1,7 +1,96 @@ +import math + from qcodes import VisaInstrument +from qcodes.instrument.channel import InstrumentChannel from qcodes.utils.validators import Numbers, Ints, Enum +class SR865Buffer(InstrumentChannel): + """ + SR860 manual: + http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf + """ + def __init__(self, parent, name): + super().__init__(parent, name) + self._parent = parent + + self.add_parameter( + "capture_length", + label="get/set capture length", + get_cmd="CAPTURELEN?", + set_cmd="CAPTURELEN {}", + set_parser=self._set_capture_len_parser + ) + + self.add_parameter( + "capture_config", + label="capture configuration", + get_cmd="CAPTURECFG?", + set_cmd="CAPTURECFG {}", + val_mapping={ + "X": 0, + "XY": 1, + "RT": 2, + "XYRT": 3, + 0: 0, + 1: 1, + 2: 2, + 3: 3 + } + ) + + self.add_parameter( + "capture_rate_max", + label="capture rate maximum", + get_cmd="CAPTURERATEMAX?" + ) + + self.add_parameter( + "capture_rate_raw", + label="capture rate raw", + get_cmd="CAPTURERATE?", + set_cmd="CAPTURERATE {}", + val_mapping=Ints(min_value=0, max_value=20) + ) + + self.add_parameter( + "capture_rate", + label="capture rate in Hz", + get_cmd="CAPTURERATE?", + set_cmd="CAPTURERATE {}", + get_parser=self._get_capture_rate_parser, + set_parser=self._set_capture_rate_parser + ) + + @staticmethod + def _set_capture_len_parser(value): + + if value % 2: + print("the capture length needs to be even. Setting to {}".format(value+1)) + value += 1 + + if not 1 <= value <= 4096: + raise ValueError("the capture length should be between 1 and 4096") + + return value + + def _get_capture_rate_parser(self, value): + """ + See page 136 of the SR860 manual + """ + max_rate = self.capture_rate_max() + return max_rate / (2**value) + + def _set_capture_rate_parser(self, value): + max_rate = self.capture_rate_max() + n = math.log2(max_rate / value) + n = int(round(n)) + if not 0 <= n <= 20: + raise ValueError("The chosen frequency is invalid. Please consult the SR860 manual at page 136. The maximum" + " capture rate is {}".format(max_rate)) + return n + + class SR865(VisaInstrument): """ This is the code for Stanford_SR865 Lock-in Amplifier @@ -263,6 +352,9 @@ def __init__(self, name, address, reset=False, **kwargs): self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') + buffer = SR865Buffer(self, "{}_buffer".format(self.name)) + self.add_submodule("buffer", buffer) + self.input_config() self.connect_message() From 5df502337bc94039692db84b920c9c6ba33d727d Mon Sep 17 00:00:00 2001 From: sohailc Date: Tue, 21 Nov 2017 16:47:39 +0100 Subject: [PATCH 39/77] Seems to work nicely --- .../stanford_research/SR865.py | 135 +++++++++++++----- 1 file changed, 101 insertions(+), 34 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index 66fe26a4574..58d65768afe 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -1,4 +1,5 @@ -import math +import numpy as np +import time from qcodes import VisaInstrument from qcodes.instrument.channel import InstrumentChannel @@ -15,11 +16,12 @@ def __init__(self, parent, name): self._parent = parent self.add_parameter( - "capture_length", + "capture_length_in_kb", label="get/set capture length", get_cmd="CAPTURELEN?", set_cmd="CAPTURELEN {}", - set_parser=self._set_capture_len_parser + set_parser=self._set_capture_len_parser, + get_parser=int ) self.add_parameter( @@ -27,46 +29,66 @@ def __init__(self, parent, name): label="capture configuration", get_cmd="CAPTURECFG?", set_cmd="CAPTURECFG {}", - val_mapping={ - "X": 0, - "XY": 1, - "RT": 2, - "XYRT": 3, - 0: 0, - 1: 1, - 2: 2, - 3: 3 - } + set_parser=lambda value: {"X": 0, "X,Y": 1, "R,T": 2, "X,Y,R,T": 3}[value], + get_parser=lambda value: {"0": "X", "1": "X,Y", "2": "R,T", "3": "X,Y,R,T"}[value] ) self.add_parameter( "capture_rate_max", label="capture rate maximum", - get_cmd="CAPTURERATEMAX?" + get_cmd="CAPTURERATEMAX?", + get_parser=float ) self.add_parameter( - "capture_rate_raw", + "capture_rate", label="capture rate raw", get_cmd="CAPTURERATE?", set_cmd="CAPTURERATE {}", - val_mapping=Ints(min_value=0, max_value=20) + get_parser=float, + set_parser=self._set_capture_rate_parser ) + max_rate = self.capture_rate_max() + self.available_frequencies = [max_rate / 2 ** i for i in range(20)] + self.add_parameter( - "capture_rate", - label="capture rate in Hz", - get_cmd="CAPTURERATE?", - set_cmd="CAPTURERATE {}", - get_parser=self._get_capture_rate_parser, - set_parser=self._set_capture_rate_parser + "capture_status", + label="capture status", + get_cmd="CAPTURESTAT?" + ) + + self.add_parameter( + "count_capture_bytes", + label="capture bytes", + get_cmd="CAPTUREBYTES?" ) + self.add_parameter( + "count_capture_kilobytes", + label="capture kilobytes", + get_cmd="CAPTUREPROG?" + ) + + self.bytes_per_samples = 4 + + def capture_length(self): + """ + Return the capture length in number of samples per variable measured + """ + capture_len_kb = self.capture_length_in_kb() + config = self.capture_config() + n_variables = len(config.split(",")) + sample_count_total = capture_len_kb / self.bytes_per_samples * 1000 + sample_count_per_variable = sample_count_total / n_variables + + return int(sample_count_per_variable) + @staticmethod def _set_capture_len_parser(value): if value % 2: - print("the capture length needs to be even. Setting to {}".format(value+1)) + print("the capture length needs to be even. Setting to {}".format(value + 1)) value += 1 if not 1 <= value <= 4096: @@ -74,21 +96,66 @@ def _set_capture_len_parser(value): return value - def _get_capture_rate_parser(self, value): - """ - See page 136 of the SR860 manual - """ - max_rate = self.capture_rate_max() - return max_rate / (2**value) - def _set_capture_rate_parser(self, value): + value = float(value) max_rate = self.capture_rate_max() - n = math.log2(max_rate / value) - n = int(round(n)) - if not 0 <= n <= 20: + n = np.log2(max_rate / value) + n_round = int(round(n)) + + if not 0 <= n_round <= 20: raise ValueError("The chosen frequency is invalid. Please consult the SR860 manual at page 136. The maximum" " capture rate is {}".format(max_rate)) - return n + + set_frequency = max_rate / 2 ** n_round + if abs(value - set_frequency) > 1: + print("Warning: Setting capture rate to {:.5} Hz".format(set_frequency)) + available_frequencies = ", ".join([str(f) for f in self.available_frequencies]) + print("The available frequencies are: {}".format(available_frequencies)) + + return n_round + + def start_capture(self, acquisition_mode, trigger_mode): + """ + Start an acquisition. Please see page 137 of the manual for a detailed explanation. + + Args: + acquisition_mode (str): "ONE" | "CONT". + trigger_mode (str): IMM | TRIG | SAMP + """ + + if acquisition_mode not in ["ONE", "CONT"]: + raise ValueError("The acquisition mode needs to be either 'ONE' or 'CONT'") + + if trigger_mode not in ["IMM", "TRIG", "SAMP"]: + raise ValueError("The trigger mode needs to be either 'IMM', 'TRIG' or 'SAMP'") + + cmd_str = "CAPTURESTART {},{}".format(acquisition_mode, trigger_mode) + self.write(cmd_str) + + def stop_capture(self): + self.write("CAPTURESTOP") + + def capture_samples(self, sample_count): + + capture_rate = self.capture_rate() + capture_time = sample_count / capture_rate + + self.start_capture("CONT", "IMM") + time.sleep(capture_time) + self.stop_capture() + + capture_variables = self.capture_config().split(",") + n_variables = len(capture_variables) + + sample_size = int(np.ceil(n_variables * sample_count / 1024 * 4)) + values = self._parent.visa_handle.query_binary_values("CAPTUREGET? 0,{}".format(sample_size), + datatype='f', is_big_endian=False) + values = np.array(values) + values = values[values != 0] + + data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} + + return data class SR865(VisaInstrument): From 41e610b8156428c79fc2a653572b23363498e803 Mon Sep 17 00:00:00 2001 From: sohailc Date: Wed, 22 Nov 2017 10:30:51 +0100 Subject: [PATCH 40/77] Seems to work nicely --- .../stanford_research/SR865.py | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index 58d65768afe..6f930d5ae4b 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -70,19 +70,7 @@ def __init__(self, parent, name): get_cmd="CAPTUREPROG?" ) - self.bytes_per_samples = 4 - - def capture_length(self): - """ - Return the capture length in number of samples per variable measured - """ - capture_len_kb = self.capture_length_in_kb() - config = self.capture_config() - n_variables = len(config.split(",")) - sample_count_total = capture_len_kb / self.bytes_per_samples * 1000 - sample_count_per_variable = sample_count_total / n_variables - - return int(sample_count_per_variable) + self.bytes_per_sample = 4 @staticmethod def _set_capture_len_parser(value): @@ -140,15 +128,19 @@ def capture_samples(self, sample_count): capture_rate = self.capture_rate() capture_time = sample_count / capture_rate + capture_variables = self.capture_config().split(",") + n_variables = len(capture_variables) + + total_size_in_kb = int(np.ceil(n_variables * sample_count * self.bytes_per_sample / 1024)) + + if total_size_in_kb > 64: + raise ValueError("Too many samples. Either reduce the sample count or adjust the capture configuration") + self.start_capture("CONT", "IMM") time.sleep(capture_time) self.stop_capture() - capture_variables = self.capture_config().split(",") - n_variables = len(capture_variables) - - sample_size = int(np.ceil(n_variables * sample_count / 1024 * 4)) - values = self._parent.visa_handle.query_binary_values("CAPTUREGET? 0,{}".format(sample_size), + values = self._parent.visa_handle.query_binary_values("CAPTUREGET? 0,{}".format(total_size_in_kb), datatype='f', is_big_endian=False) values = np.array(values) values = values[values != 0] From 2e3d104dc1e7432a810b41186f9bdab6a3b40767 Mon Sep 17 00:00:00 2001 From: sohailc Date: Wed, 22 Nov 2017 16:09:13 +0100 Subject: [PATCH 41/77] 1) Added docstring to the buffer submodule of the SR86x driver 2) The SR860 and SR865 drivers are aliases of the SR86x driver --- .../stanford_research/SR860.py | 5 + .../stanford_research/SR865.py | 457 +--------------- .../stanford_research/SR86x.py | 494 ++++++++++++++++++ 3 files changed, 502 insertions(+), 454 deletions(-) create mode 100644 qcodes/instrument_drivers/stanford_research/SR860.py create mode 100644 qcodes/instrument_drivers/stanford_research/SR86x.py diff --git a/qcodes/instrument_drivers/stanford_research/SR860.py b/qcodes/instrument_drivers/stanford_research/SR860.py new file mode 100644 index 00000000000..0e9b77ed013 --- /dev/null +++ b/qcodes/instrument_drivers/stanford_research/SR860.py @@ -0,0 +1,5 @@ +from qcodes.instrument_drivers.stanford_research.SR86x import SR86x + + +class SR860(SR86x): + pass diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index 6f930d5ae4b..63532eb4e1b 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -1,456 +1,5 @@ -import numpy as np -import time +from qcodes.instrument_drivers.stanford_research.SR86x import SR86x -from qcodes import VisaInstrument -from qcodes.instrument.channel import InstrumentChannel -from qcodes.utils.validators import Numbers, Ints, Enum - -class SR865Buffer(InstrumentChannel): - """ - SR860 manual: - http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf - """ - def __init__(self, parent, name): - super().__init__(parent, name) - self._parent = parent - - self.add_parameter( - "capture_length_in_kb", - label="get/set capture length", - get_cmd="CAPTURELEN?", - set_cmd="CAPTURELEN {}", - set_parser=self._set_capture_len_parser, - get_parser=int - ) - - self.add_parameter( - "capture_config", - label="capture configuration", - get_cmd="CAPTURECFG?", - set_cmd="CAPTURECFG {}", - set_parser=lambda value: {"X": 0, "X,Y": 1, "R,T": 2, "X,Y,R,T": 3}[value], - get_parser=lambda value: {"0": "X", "1": "X,Y", "2": "R,T", "3": "X,Y,R,T"}[value] - ) - - self.add_parameter( - "capture_rate_max", - label="capture rate maximum", - get_cmd="CAPTURERATEMAX?", - get_parser=float - ) - - self.add_parameter( - "capture_rate", - label="capture rate raw", - get_cmd="CAPTURERATE?", - set_cmd="CAPTURERATE {}", - get_parser=float, - set_parser=self._set_capture_rate_parser - ) - - max_rate = self.capture_rate_max() - self.available_frequencies = [max_rate / 2 ** i for i in range(20)] - - self.add_parameter( - "capture_status", - label="capture status", - get_cmd="CAPTURESTAT?" - ) - - self.add_parameter( - "count_capture_bytes", - label="capture bytes", - get_cmd="CAPTUREBYTES?" - ) - - self.add_parameter( - "count_capture_kilobytes", - label="capture kilobytes", - get_cmd="CAPTUREPROG?" - ) - - self.bytes_per_sample = 4 - - @staticmethod - def _set_capture_len_parser(value): - - if value % 2: - print("the capture length needs to be even. Setting to {}".format(value + 1)) - value += 1 - - if not 1 <= value <= 4096: - raise ValueError("the capture length should be between 1 and 4096") - - return value - - def _set_capture_rate_parser(self, value): - value = float(value) - max_rate = self.capture_rate_max() - n = np.log2(max_rate / value) - n_round = int(round(n)) - - if not 0 <= n_round <= 20: - raise ValueError("The chosen frequency is invalid. Please consult the SR860 manual at page 136. The maximum" - " capture rate is {}".format(max_rate)) - - set_frequency = max_rate / 2 ** n_round - if abs(value - set_frequency) > 1: - print("Warning: Setting capture rate to {:.5} Hz".format(set_frequency)) - available_frequencies = ", ".join([str(f) for f in self.available_frequencies]) - print("The available frequencies are: {}".format(available_frequencies)) - - return n_round - - def start_capture(self, acquisition_mode, trigger_mode): - """ - Start an acquisition. Please see page 137 of the manual for a detailed explanation. - - Args: - acquisition_mode (str): "ONE" | "CONT". - trigger_mode (str): IMM | TRIG | SAMP - """ - - if acquisition_mode not in ["ONE", "CONT"]: - raise ValueError("The acquisition mode needs to be either 'ONE' or 'CONT'") - - if trigger_mode not in ["IMM", "TRIG", "SAMP"]: - raise ValueError("The trigger mode needs to be either 'IMM', 'TRIG' or 'SAMP'") - - cmd_str = "CAPTURESTART {},{}".format(acquisition_mode, trigger_mode) - self.write(cmd_str) - - def stop_capture(self): - self.write("CAPTURESTOP") - - def capture_samples(self, sample_count): - - capture_rate = self.capture_rate() - capture_time = sample_count / capture_rate - - capture_variables = self.capture_config().split(",") - n_variables = len(capture_variables) - - total_size_in_kb = int(np.ceil(n_variables * sample_count * self.bytes_per_sample / 1024)) - - if total_size_in_kb > 64: - raise ValueError("Too many samples. Either reduce the sample count or adjust the capture configuration") - - self.start_capture("CONT", "IMM") - time.sleep(capture_time) - self.stop_capture() - - values = self._parent.visa_handle.query_binary_values("CAPTUREGET? 0,{}".format(total_size_in_kb), - datatype='f', is_big_endian=False) - values = np.array(values) - values = values[values != 0] - - data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} - - return data - - -class SR865(VisaInstrument): - """ - This is the code for Stanford_SR865 Lock-in Amplifier - """ - _VOLT_TO_N = {1: 0, 500e-3: 1, 200e-3: 2, - 100e-3: 3, 50e-3: 4, 20e-3: 5, - 10e-3: 6, 5e-3: 7, 2e-3: 8, - 1e-3: 9, 500e-6: 10, 200e-6: 11, - 100e-6: 12, 50e-6: 13, 20e-6: 14, - 10e-6: 15, 5e-6: 16, 2e-6: 17, - 1e-6: 18, 500e-9: 19, 200e-9: 20, - 100e-9: 21, 50e-9: 22, 20e-9: 23, - 10e-9: 24, 5e-9: 25, 2e-9: 26, - 1e-9: 27} - _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()} - - _CURR_TO_N = {1e-6: 0, 500e-9: 1, 200e-9: 2, - 100e-9: 3, 50e-9: 4, 20e-9: 5, - 10e-9: 6, 5e-9: 7, 2e-9: 8, - 1e-9: 9, 500e-12: 10, 200e-12: 11, - 100e-12: 12, 50e-12: 13, 20e-12: 14, - 10e-12: 15, 5e-12: 16, 2e-12: 17, - 1e-12: 18, 500e-15: 19, 200e-15: 20, - 100e-15: 21, 50e-15: 22, 20e-15: 23, - 10e-15: 24, 5e-15: 25, 2e-15: 26, - 1e-15: 27} - _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()} - - _VOLT_ENUM = Enum(*_VOLT_TO_N.keys()) - _CURR_ENUM = Enum(*_CURR_TO_N.keys()) - - _INPUT_SIGNAL_TO_N = { - 'voltage': 0, - 'current': 1, - } - _N_TO_INPUT_SIGNAL = {v: k for k, v in _INPUT_SIGNAL_TO_N.items()} - - def __init__(self, name, address, reset=False, **kwargs): - super().__init__(name, address, terminator='\n', **kwargs) - # Reference commands - self.add_parameter(name='frequency', - label='Frequency', - unit='Hz', - get_cmd='FREQ?', - set_cmd='FREQ {}', - get_parser=float, - vals=Numbers(min_value=1e-3, max_value=2.5e6)) - self.add_parameter(name='sine_outdc', - label='Sine out dc level', - unit='V', - get_cmd='SOFF?', - set_cmd='SOFF {:.3f}', - get_parser=float, - vals=Numbers(min_value=-5, max_value=5)) - self.add_parameter(name='amplitude', - label='Amplitude', - unit='V', - get_cmd='SLVL?', - set_cmd='SLVL {}', - get_parser=float, - vals=Numbers(min_value=10e-9, max_value=2)) - self.add_parameter(name='harmonic', - label='Harmonic', - get_cmd='HARM?', - get_parser=int, - set_cmd='HARM {:d}', - vals=Ints(min_value=1, max_value=99)) - self.add_parameter(name='phase', - label='Phase', - unit='deg', - get_cmd='PHAS?', - set_cmd='PHAS {}', - get_parser=float, - vals=Numbers(min_value=-3.6e5, max_value=3.6e5)) - # Signal commands - self.add_parameter(name='sensitivity', - label='Sensitivity', - get_cmd='SCAL?', - set_cmd='SCAL {:d}', - get_parser=self._get_sensitivity, - set_parser=self._set_sensitivity - ) - self.add_parameter(name='filter_slope', - label='Filter slope', - unit='dB/oct', - get_cmd='OFSL?', - set_cmd='OFSL {}', - val_mapping={6: 0, - 12: 1, - 18: 2, - 24: 3}) - self.add_parameter(name='sync_filter', - label='Sync filter', - get_cmd='SYNC?', - set_cmd='SYNC {}', - val_mapping={'OFF': 0, - 'ON': 1}) - self.add_parameter(name='noise_bandwidth', - label='Noise bandwidth', - unit='Hz', - get_cmd='ENBW?', - get_parser=float) - self.add_parameter(name='signal_strength', - label='Signal strength indicator', - get_cmd='ILVL?', - get_parser=int) - self.add_parameter(name='signal_input', - label='Signal input', - get_cmd='IVMD?', - get_parser=self._get_input_config, - set_cmd='IVMD {}', - set_parser=self._set_input_config, - vals=Enum(*self._INPUT_SIGNAL_TO_N.keys())) - self.add_parameter(name='input_range', - label='Input range', - unit='V', - get_cmd='IRNG?', - set_cmd='IRNG {}', - val_mapping={1: 0, - 300e-3: 1, - 100e-3: 2, - 30e-3: 3, - 10e-3: 4}) - self.add_parameter(name='input_config', - label='Input configuration', - get_cmd='ISRC?', - set_cmd='ISRC {}', - val_mapping={'a': 0, - 'a-b': 1}) - self.add_parameter(name='input_shield', - label='Input shield', - get_cmd='IGND?', - set_cmd='IGND {}', - val_mapping={'float': 0, - 'ground': 1}) - self.add_parameter(name='input_gain', - label='Input gain', - unit='ohm', - get_cmd='ICUR?', - set_cmd='ICUR {}', - val_mapping={1e6: 0, - 100e6: 1}) - self.add_parameter(name='adv_filter', - label='Advanced filter', - get_cmd='ADVFILT?', - set_cmd='ADVFILT {}', - val_mapping={'OFF': 0, - 'ON': 1}) - self.add_parameter(name='input_coupling', - label='Input coupling', - get_cmd='ICPL?', - set_cmd='ICPL {}', - val_mapping={'ac': 0, 'dc': 1}) - self.add_parameter(name='time_constant', - label='Time constant', - unit='s', - get_cmd='OFLT?', - set_cmd='OFLT {}', - val_mapping={1e-6: 0, 3e-6: 1, - 10e-6: 2, 30e-6: 3, - 100e-6: 4, 300e-6: 5, - 1e-3: 6, 3e-3: 7, - 10e-3: 8, 30e-3: 9, - 100e-3: 10, 300e-3: 11, - 1: 12, 3: 13, - 10: 14, 30: 15, - 100: 16, 300: 17, - 1e3: 18, 3e3: 19, - 10e3: 20, 30e3: 21}) - # Auto functions - self.add_function('auto_range', call_cmd='ARNG') - self.add_function('auto_scale', call_cmd='ASCL') - self.add_function('auto_phase', call_cmd='APHS') - - # Data transfer - # first 4 parameters from a list of 16 below. - self.add_parameter('X', - label='In-phase Magnitude', - get_cmd='OUTP? 0', - get_parser=float, - unit='V') - self.add_parameter('Y', - label='Out-phase Magnitude', - get_cmd='OUTP? 1', - get_parser=float, - unit='V') - self.add_parameter('R', - label='Magnitude', - get_cmd='OUTP? 2', - get_parser=float, - unit='V') - self.add_parameter('P', - label='Phase', - get_cmd='OUTP? 3', - get_parser=float, - unit='deg') - - # CH1/CH2 Output Commands - self.add_parameter('X_offset', - label='X offset ', - unit='%', - get_cmd='COFP? 0', - set_cmd='COFP 0, {}', - get_parser=float, - vals=Numbers(min_value=-999.99, max_value=999.99)) - self.add_parameter('Y_offset', - label='Y offset', - unit='%', - get_cmd='COFP? 1', - set_cmd='COFP 1, {}', - get_parser=float, - vals=Numbers(min_value=-999.99, max_value=999.99)) - self.add_parameter('R_offset', - label='R offset', - unit='%', - get_cmd='COFP? 2', - set_cmd='COFP 2, {}', - get_parser=float, - vals=Numbers(min_value=-999.99, max_value=999.99)) - self.add_parameter('X_expand', - label='X expand multiplier', - get_cmd='CEXP? 0', - set_cmd='CEXP 0, {}', - val_mapping={'OFF': '0', - 'X10': '1', - 'X100': '2'}) - self.add_parameter('Y_expand', - label='Y expand multiplier', - get_cmd='CEXP? 1', - set_cmd='CEXP 1, {}', - val_mapping={'OFF': 0, - 'X10': 1, - 'X100': 2}) - self.add_parameter('R_expand', - label='R expand multiplier', - get_cmd='CEXP? 2', - set_cmd='CEXP 2, {}', - val_mapping={'OFF': 0, - 'X10': 1, - 'X100': 2}) - # Aux input/output - for i in [0, 1, 2, 3]: - self.add_parameter('aux_in{}'.format(i), - label='Aux input {}'.format(i), - get_cmd='OAUX? {}'.format(i), - get_parser=float, - unit='V') - - self.add_parameter('aux_out{}'.format(i), - label='Aux output {}'.format(i), - get_cmd='AUXV? {}'.format(i), - get_parser=float, - set_cmd='AUXV {0}, {{}}'.format(i), - unit='V') - - # Interface - self.add_function('reset', call_cmd='*RST') - - self.add_function('disable_front_panel', call_cmd='OVRM 0') - self.add_function('enable_front_panel', call_cmd='OVRM 1') - - buffer = SR865Buffer(self, "{}_buffer".format(self.name)) - self.add_submodule("buffer", buffer) - - self.input_config() - self.connect_message() - - def _set_units(self, unit): - for param in [self.X, self.Y, self.R, self.sensitivity]: - param.unit = unit - - def _get_input_config(self, s): - mode = self._N_TO_INPUT_SIGNAL[int(s)] - - if mode == 'voltage': - self.sensitivity.set_validator(self._VOLT_ENUM) - self._set_units('V') - else: - self.sensitivity.set_validator(self._CURR_ENUM) - self._set_units('A') - - return mode - - def _set_input_config(self, s): - if s == 'voltage': - self.sensitivity.set_validator(self._VOLT_ENUM) - self._set_units('V') - else: - self.sensitivity.set_validator(self._CURR_ENUM) - self._set_units('A') - - return self._INPUT_SIGNAL_TO_N[s] - - def _get_sensitivity(self, s): - if self.signal_input() == 'voltage': - return self._N_TO_VOLT[int(s)] - else: - return self._N_TO_CURR[int(s)] - - def _set_sensitivity(self, s): - if self.signal_input() == 'voltage': - return self._VOLT_TO_N[s] - else: - return self._CURR_TO_N[s] +class SR865(SR86x): + pass diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py new file mode 100644 index 00000000000..c6265032e5f --- /dev/null +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -0,0 +1,494 @@ +import numpy as np +import time + +import qcodes +from qcodes import VisaInstrument +from qcodes.instrument.channel import InstrumentChannel +from qcodes.utils.validators import Numbers, Ints, Enum + + +class SR86xBuffer(InstrumentChannel): + """ + The buffer module for the SR86x driver. This driver has been verified to work with the SR860 and SR865. + For reference, please consult the SR860 manual: http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf + """ + + def __init__(self, parent: qcodes.instrument, name: str): + super().__init__(parent, name) + self._parent = parent + + self.add_parameter( + "capture_length_in_kb", + label="get/set capture length", + get_cmd="CAPTURELEN?", + set_cmd="CAPTURELEN {}", + set_parser=self._set_capture_len_parser, + get_parser=int + ) + + self.add_parameter( # Configure which parameters we want to capture + "capture_config", + label="capture configuration", + get_cmd="CAPTURECFG?", + set_cmd="CAPTURECFG {}", + set_parser=lambda value: {"X": 0, "X,Y": 1, "R,T": 2, "X,Y,R,T": 3}[value], + get_parser=lambda value: {"0": "X", "1": "X,Y", "2": "R,T", "3": "X,Y,R,T"}[value] + ) + + self.add_parameter( + "capture_rate_max", + label="capture rate maximum", + get_cmd="CAPTURERATEMAX?", + get_parser=float + ) + + self.add_parameter( + "capture_rate", + label="capture rate raw", + get_cmd="CAPTURERATE?", + set_cmd="CAPTURERATE {}", + get_parser=float, + set_parser=self._set_capture_rate_parser + ) + + max_rate = self.capture_rate_max() + self.available_frequencies = [max_rate / 2 ** i for i in range(20)] + + self.add_parameter( # Are we capturing at the moment? + "capture_status", + label="capture status", + get_cmd="CAPTURESTAT?" + ) + + self.add_parameter( + "count_capture_bytes", + label="capture bytes", + get_cmd="CAPTUREBYTES?" + ) + + self.add_parameter( + "count_capture_kilobytes", + label="capture kilobytes", + get_cmd="CAPTUREPROG?" + ) + + self.bytes_per_sample = 4 + + @staticmethod + def _set_capture_len_parser(value: int) -> int: + + if value % 2: + print("the capture length needs to be even. Setting to {}".format(value + 1)) + value += 1 + + if not 1 <= value <= 4096: + raise ValueError("the capture length should be between 1 and 4096") + + return value + + def _set_capture_rate_parser(self, capture_rate_hz: float) -> int: + """ + According to the manual, the capture rate query returns a value in Hz, but then setting this value it is + expected to give a value n, where the capture rate in Hz is given by capture_rate_hz = max_rate / 2 ** n. + Please see page 136 of the manual. Here n is an integer in the range [0, 20] + + Args: + capture_rate_hz (float): The desired capture rate in Hz. If the desired rate is more then 1 Hz from the + nearest valid rate, a warning is issued and the nearest valid rate it used. + + Returns: + n_round (int) + """ + max_rate = self.capture_rate_max() + n = np.log2(max_rate / capture_rate_hz) + n_round = int(round(n)) + + if not 0 <= n_round <= 20: + raise ValueError("The chosen frequency is invalid. Please consult the SR860 manual at page 136. The maximum" + " capture rate is {}".format(max_rate)) + + nearest_valid_rate = max_rate / 2 ** n_round + if abs(capture_rate_hz - nearest_valid_rate) > 1: + print("Warning: Setting capture rate to {:.5} Hz".format(nearest_valid_rate)) + available_frequencies = ", ".join([str(f) for f in self.available_frequencies]) + print("The available frequencies are: {}".format(available_frequencies)) + + return n_round + + def start_capture(self, acquisition_mode: str, trigger_mode: str) -> None: + """ + Start an acquisition. Please see page 137 of the manual for a detailed explanation. + + Args: + acquisition_mode (str): "ONE" | "CONT". + trigger_mode (str): IMM | TRIG | SAMP + """ + + if acquisition_mode not in ["ONE", "CONT"]: + raise ValueError("The acquisition mode needs to be either 'ONE' or 'CONT'") + + if trigger_mode not in ["IMM", "TRIG", "SAMP"]: + raise ValueError("The trigger mode needs to be either 'IMM', 'TRIG' or 'SAMP'") + + cmd_str = "CAPTURESTART {},{}".format(acquisition_mode, trigger_mode) + self.write(cmd_str) + + def stop_capture(self): + """ + Stop a capture + """ + self.write("CAPTURESTOP") + + def read_capture_data(self, sample_count: int) -> dict: + """ + Read capture data from the buffer. + + Args: + sample_count (int): number of samples to read from the buffer + + Returns: + data (dict): The keys in the dictionary is the variables we have captures. For instance, if before the + capture we specify 'capture_config("X,Y")', then the keys will be "X" and "Y". + """ + capture_variables = self.capture_config().split(",") + n_variables = len(capture_variables) + + total_size_in_kb = int(np.ceil(n_variables * sample_count * self.bytes_per_sample / 1024)) + + if total_size_in_kb > 64: + raise ValueError("Number of samples specified is larger then the buffer size") + + values = self._parent.visa_handle.query_binary_values("CAPTUREGET? 0,{}".format(total_size_in_kb), + datatype='f', is_big_endian=False) + values = np.array(values) + values = values[values != 0] + + data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} + + return data + + def capture_samples(self, sample_count: int): + """ + Capture a number of samples. This convenience function provides an example how we use the start and stop + methods. We acquire the samples by sleeping for a time and then reading the buffer. + + Args: + sample_count (int) + + Returns: + dict + """ + capture_rate = self.capture_rate() + capture_time = sample_count / capture_rate + + self.start_capture("CONT", "IMM") + time.sleep(capture_time) + self.stop_capture() + + return self.read_capture_data(sample_count) + + +class SR86x(VisaInstrument): + """ + This is the code for Stanford_SR865 Lock-in Amplifier + """ + _VOLT_TO_N = {1: 0, 500e-3: 1, 200e-3: 2, + 100e-3: 3, 50e-3: 4, 20e-3: 5, + 10e-3: 6, 5e-3: 7, 2e-3: 8, + 1e-3: 9, 500e-6: 10, 200e-6: 11, + 100e-6: 12, 50e-6: 13, 20e-6: 14, + 10e-6: 15, 5e-6: 16, 2e-6: 17, + 1e-6: 18, 500e-9: 19, 200e-9: 20, + 100e-9: 21, 50e-9: 22, 20e-9: 23, + 10e-9: 24, 5e-9: 25, 2e-9: 26, + 1e-9: 27} + _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()} + + _CURR_TO_N = {1e-6: 0, 500e-9: 1, 200e-9: 2, + 100e-9: 3, 50e-9: 4, 20e-9: 5, + 10e-9: 6, 5e-9: 7, 2e-9: 8, + 1e-9: 9, 500e-12: 10, 200e-12: 11, + 100e-12: 12, 50e-12: 13, 20e-12: 14, + 10e-12: 15, 5e-12: 16, 2e-12: 17, + 1e-12: 18, 500e-15: 19, 200e-15: 20, + 100e-15: 21, 50e-15: 22, 20e-15: 23, + 10e-15: 24, 5e-15: 25, 2e-15: 26, + 1e-15: 27} + _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()} + + _VOLT_ENUM = Enum(*_VOLT_TO_N.keys()) + _CURR_ENUM = Enum(*_CURR_TO_N.keys()) + + _INPUT_SIGNAL_TO_N = { + 'voltage': 0, + 'current': 1, + } + _N_TO_INPUT_SIGNAL = {v: k for k, v in _INPUT_SIGNAL_TO_N.items()} + + def __init__(self, name, address, reset=False, **kwargs): + super().__init__(name, address, terminator='\n', **kwargs) + # Reference commands + self.add_parameter(name='frequency', + label='Frequency', + unit='Hz', + get_cmd='FREQ?', + set_cmd='FREQ {}', + get_parser=float, + vals=Numbers(min_value=1e-3, max_value=2.5e6)) + self.add_parameter(name='sine_outdc', + label='Sine out dc level', + unit='V', + get_cmd='SOFF?', + set_cmd='SOFF {:.3f}', + get_parser=float, + vals=Numbers(min_value=-5, max_value=5)) + self.add_parameter(name='amplitude', + label='Amplitude', + unit='V', + get_cmd='SLVL?', + set_cmd='SLVL {}', + get_parser=float, + vals=Numbers(min_value=10e-9, max_value=2)) + self.add_parameter(name='harmonic', + label='Harmonic', + get_cmd='HARM?', + get_parser=int, + set_cmd='HARM {:d}', + vals=Ints(min_value=1, max_value=99)) + self.add_parameter(name='phase', + label='Phase', + unit='deg', + get_cmd='PHAS?', + set_cmd='PHAS {}', + get_parser=float, + vals=Numbers(min_value=-3.6e5, max_value=3.6e5)) + # Signal commands + self.add_parameter(name='sensitivity', + label='Sensitivity', + get_cmd='SCAL?', + set_cmd='SCAL {:d}', + get_parser=self._get_sensitivity, + set_parser=self._set_sensitivity + ) + self.add_parameter(name='filter_slope', + label='Filter slope', + unit='dB/oct', + get_cmd='OFSL?', + set_cmd='OFSL {}', + val_mapping={6: 0, + 12: 1, + 18: 2, + 24: 3}) + self.add_parameter(name='sync_filter', + label='Sync filter', + get_cmd='SYNC?', + set_cmd='SYNC {}', + val_mapping={'OFF': 0, + 'ON': 1}) + self.add_parameter(name='noise_bandwidth', + label='Noise bandwidth', + unit='Hz', + get_cmd='ENBW?', + get_parser=float) + self.add_parameter(name='signal_strength', + label='Signal strength indicator', + get_cmd='ILVL?', + get_parser=int) + self.add_parameter(name='signal_input', + label='Signal input', + get_cmd='IVMD?', + get_parser=self._get_input_config, + set_cmd='IVMD {}', + set_parser=self._set_input_config, + vals=Enum(*self._INPUT_SIGNAL_TO_N.keys())) + self.add_parameter(name='input_range', + label='Input range', + unit='V', + get_cmd='IRNG?', + set_cmd='IRNG {}', + val_mapping={1: 0, + 300e-3: 1, + 100e-3: 2, + 30e-3: 3, + 10e-3: 4}) + self.add_parameter(name='input_config', + label='Input configuration', + get_cmd='ISRC?', + set_cmd='ISRC {}', + val_mapping={'a': 0, + 'a-b': 1}) + self.add_parameter(name='input_shield', + label='Input shield', + get_cmd='IGND?', + set_cmd='IGND {}', + val_mapping={'float': 0, + 'ground': 1}) + self.add_parameter(name='input_gain', + label='Input gain', + unit='ohm', + get_cmd='ICUR?', + set_cmd='ICUR {}', + val_mapping={1e6: 0, + 100e6: 1}) + self.add_parameter(name='adv_filter', + label='Advanced filter', + get_cmd='ADVFILT?', + set_cmd='ADVFILT {}', + val_mapping={'OFF': 0, + 'ON': 1}) + self.add_parameter(name='input_coupling', + label='Input coupling', + get_cmd='ICPL?', + set_cmd='ICPL {}', + val_mapping={'ac': 0, 'dc': 1}) + self.add_parameter(name='time_constant', + label='Time constant', + unit='s', + get_cmd='OFLT?', + set_cmd='OFLT {}', + val_mapping={1e-6: 0, 3e-6: 1, + 10e-6: 2, 30e-6: 3, + 100e-6: 4, 300e-6: 5, + 1e-3: 6, 3e-3: 7, + 10e-3: 8, 30e-3: 9, + 100e-3: 10, 300e-3: 11, + 1: 12, 3: 13, + 10: 14, 30: 15, + 100: 16, 300: 17, + 1e3: 18, 3e3: 19, + 10e3: 20, 30e3: 21}) + # Auto functions + self.add_function('auto_range', call_cmd='ARNG') + self.add_function('auto_scale', call_cmd='ASCL') + self.add_function('auto_phase', call_cmd='APHS') + + # Data transfer + # first 4 parameters from a list of 16 below. + self.add_parameter('X', + label='In-phase Magnitude', + get_cmd='OUTP? 0', + get_parser=float, + unit='V') + self.add_parameter('Y', + label='Out-phase Magnitude', + get_cmd='OUTP? 1', + get_parser=float, + unit='V') + self.add_parameter('R', + label='Magnitude', + get_cmd='OUTP? 2', + get_parser=float, + unit='V') + self.add_parameter('P', + label='Phase', + get_cmd='OUTP? 3', + get_parser=float, + unit='deg') + + # CH1/CH2 Output Commands + self.add_parameter('X_offset', + label='X offset ', + unit='%', + get_cmd='COFP? 0', + set_cmd='COFP 0, {}', + get_parser=float, + vals=Numbers(min_value=-999.99, max_value=999.99)) + self.add_parameter('Y_offset', + label='Y offset', + unit='%', + get_cmd='COFP? 1', + set_cmd='COFP 1, {}', + get_parser=float, + vals=Numbers(min_value=-999.99, max_value=999.99)) + self.add_parameter('R_offset', + label='R offset', + unit='%', + get_cmd='COFP? 2', + set_cmd='COFP 2, {}', + get_parser=float, + vals=Numbers(min_value=-999.99, max_value=999.99)) + self.add_parameter('X_expand', + label='X expand multiplier', + get_cmd='CEXP? 0', + set_cmd='CEXP 0, {}', + val_mapping={'OFF': '0', + 'X10': '1', + 'X100': '2'}) + self.add_parameter('Y_expand', + label='Y expand multiplier', + get_cmd='CEXP? 1', + set_cmd='CEXP 1, {}', + val_mapping={'OFF': 0, + 'X10': 1, + 'X100': 2}) + self.add_parameter('R_expand', + label='R expand multiplier', + get_cmd='CEXP? 2', + set_cmd='CEXP 2, {}', + val_mapping={'OFF': 0, + 'X10': 1, + 'X100': 2}) + # Aux input/output + for i in [0, 1, 2, 3]: + self.add_parameter('aux_in{}'.format(i), + label='Aux input {}'.format(i), + get_cmd='OAUX? {}'.format(i), + get_parser=float, + unit='V') + + self.add_parameter('aux_out{}'.format(i), + label='Aux output {}'.format(i), + get_cmd='AUXV? {}'.format(i), + get_parser=float, + set_cmd='AUXV {0}, {{}}'.format(i), + unit='V') + + # Interface + self.add_function('reset', call_cmd='*RST') + + self.add_function('disable_front_panel', call_cmd='OVRM 0') + self.add_function('enable_front_panel', call_cmd='OVRM 1') + + buffer = SR86xBuffer(self, "{}_buffer".format(self.name)) + self.add_submodule("buffer", buffer) + + self.input_config() + self.connect_message() + + def _set_units(self, unit): + for param in [self.X, self.Y, self.R, self.sensitivity]: + param.unit = unit + + def _get_input_config(self, s): + mode = self._N_TO_INPUT_SIGNAL[int(s)] + + if mode == 'voltage': + self.sensitivity.set_validator(self._VOLT_ENUM) + self._set_units('V') + else: + self.sensitivity.set_validator(self._CURR_ENUM) + self._set_units('A') + + return mode + + def _set_input_config(self, s): + if s == 'voltage': + self.sensitivity.set_validator(self._VOLT_ENUM) + self._set_units('V') + else: + self.sensitivity.set_validator(self._CURR_ENUM) + self._set_units('A') + + return self._INPUT_SIGNAL_TO_N[s] + + def _get_sensitivity(self, s): + if self.signal_input() == 'voltage': + return self._N_TO_VOLT[int(s)] + else: + return self._N_TO_CURR[int(s)] + + def _set_sensitivity(self, s): + if self.signal_input() == 'voltage': + return self._VOLT_TO_N[s] + else: + return self._CURR_TO_N[s] From 87f38cc83fdff0b1bea79cb95fbf2277db87dcbc Mon Sep 17 00:00:00 2001 From: sohailc Date: Wed, 22 Nov 2017 16:49:13 +0100 Subject: [PATCH 42/77] Added an example notebook for the SR86x --- ...le with SR86x with buffered readout .ipynb | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb diff --git a/docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb b/docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb new file mode 100644 index 00000000000..63bc56a2d9e --- /dev/null +++ b/docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import time \n", + "\n", + "import matplotlib.pyplot as plt \n", + "\n", + "import qcodes\n", + "from qcodes.instrument_drivers.stanford_research.SR860 import SR860" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Connected to: Stanford_Research_Systems SR860 (serial:003101, firmware:V1.47) in 0.08s\n" + ] + } + ], + "source": [ + "sr = SR860(\"sr\", \"GPIB0::4::INSTR\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "sr.buffer.capture_config(\"X,Y\")\n", + "data = sr.buffer.capture_samples(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEDCAYAAADOc0QpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xd8lfXd//HXB0LCCDshrCB7yh4iDizi3lar1n1rKbZq\n9XZbb7077lpHra2tUlpxoGIVUNCK1moVcSFhj7BXWEkIkAFknc/vjxz9pTGYACe5ck7ez8cjD874\nnut8Li/y9sv3+l7fy9wdERGJLQ2CLkBERCJP4S4iEoMU7iIiMUjhLiISgxTuIiIxSOEuIhKDAg13\nM5tiZplmtjxC23vUzFaY2Soz+6OZWTU/N9HMlpnZYjObZ2b9v6NtQzNbZGZvl3vtZTNbbWbLw/vU\nqMJnRppZqZldcuR796067jQzN7OkSG1TRGJH0D3354EzI7EhMxsDnAAMAo4FRgJjK7TpamYfVfLx\nV9x9oLsPAR4FnviOr/oZsKrCay8DfYGBQBPgxnLf2RB4BHjvcPbnu5hZKnAasCVS2xSR2BJouLv7\nXCCn/Gtm1sPM3jWzNDP7xMz6VndzQGMgHkgAGgG7qllHbrmnzcLb+hYz6wycA/ytwuff8TBgPtC5\n3Nu3ADOAzArbusvMvjKzpWb2i+rUWc7vgbsPVaeISNA998pMBm5x9+HAncDT1fmQu38O/BvYEf55\nz90r9rAPycx+ambrKeu533qIZk9SFqqhQ2yjEXA18G74eSfgImBShXanA72AUcAQYLiZnVzNOs8H\ntrn7kuq0F5H6KS7oAsozs0RgDPB6ueHyhPB7FwO/rORj29z9DDPrCfTj//ea3zezk919rpm9AXSj\nrFffxcwWh9v8wd2fA3D3PwN/NrMfAg8A11ao7Vwg093TzOyUQ+zC08Bcd/8k/PxJ4B53L60w/H96\n+GdR+HkiZWE/18z+BbSvZNs/B94P/3n6Ib5fRAQAC3ptGTPrCrzt7seaWQtgtbt3OILt3AU0dvdf\nhZ8/CBx090crfNfz7n7Kd2ynAbDH3VtWeP1hynrlJZQN/7QAZrr7VeH3HwKGAhe7eyj82kbg61RP\nAvYDE4CTgDXu/pfD3MeBwAfh7UDZ/8i2A6PcfefhbEtEYludGpYJj31vNLNLAazM4Gp+fAsw1szi\nwsMjY/n2ic9KmVmvck/PAdZWUtt97t7Z3bsClwMflgv2G4EzgCu+DvbwZ7q5e9fwZ6YDP3H3Nyk7\nufpf4X+pYGadzKxdVXW6+zJ3b1dumxnAMAW7iFQU9FTIacDnQB8zyzCzG4ArgRvMbAmwArigmpub\nDqwHlgFLgCXu/lY1P3tzeArlYuC/CQ/JmFlHM3unGp+fBKQAn4enUz74XY3d/Z/AK+H2y8K1N69m\nrSIiVQp8WEZERCKvTg3LiIhIZAQ2WyYpKcm7du0a1NeLiESltLS0bHdPrqpdYOHetWtXFixYENTX\ni4hEJTPbXJ12GpYREYlBCncRkRikcBcRiUEKdxGRGKRwFxGJQQp3EZEYVGW4m1ljM5tvZkvCl+h/\na+1xM7vOzLLCl94vDq+1IiIiAanOPPdCYJy754cX5JpnZnPc/YsK7f7u7jdHvkQRkdhQXBrir59s\nYEyPJIaktqrR76oy3MN3F8oPP20U/tGCNCIih2HRlj3cN3MZ6TvzmDi2JPhwh2/uA5oG9AT+7O5f\nVtLs++G7Ca0Bbnf3rZErU0Tqu5yCIv6xdDuZeYX0ad+cvu1b0C2pGQ0bWNUfDlBRSYjfzknnuc82\nktK8MZOvHs7pAyq7H09kVSvc3b0UGGJmrYA3zOxYd19erslbwDR3LzSzicALwLiK2zGzCZTdrIIu\nXbocdfEiEvs+W5/NlHkb+Wh1FiUhp4FBKDx20DwhjtE92nJyryTG9UuhU6smwRZbQVZeITe9lMaC\nzXu45vhjuOuMPjRv3KhWvvuwl/wN33GowN0fP8T7DYGcincyqmjEiBGutWVE5FCKSkI8/s/VTJ67\ngXbNE7hoaCcuHNqJ7snNWJeZz6odeaRt3sMna7PI2HOA+LgGPHBOP64efQwVbmsZiGUZ+5gwdQF7\n9xfz2KWDOHdQx4hs18zS3H1EVe2q7LmbWTJQ7O57zawJMB54pEKbDu6+I/z0fKp5ByQRkcpszC7g\n1mmLWLZtH1eN7sID5/SncaOG37w/oGNLBnRsySXDO+PubMwu4Fdvr+TBWSuYuyaLRy8ZTJtm8YHU\n7u689MVmfv2PVSQlJjD9puMZ0PE7+7o1ojrDMh2AF8I98gbAa+7+tpn9Eljg7rOBW83sfMruL5oD\nXFdTBYtIbPt3eia3TltEw4bGX64ezhlVjE+bGd2TE5ly3Uie+3QTv52TzplPzuXJy4YwpmdSLVVd\nJqegiLunL+Vfq3ZxSp9kfnfpYNomJtRqDV8L7E5MGpYRkfLcnUkfb+DR99Lp174Fk68ZTufWTQ97\nOyu27+PWaYvYkF3AxLE9+O/TetOoYc1er1kacmakZfD4P1ezd38x957Vl+tP6Fojw0MRG5YREalp\nRSUh7pmxlDcWbePcQR147JLBNIlvWPUHKzGgY0veuuVEfvnWSp75aD2frsvmwXP7M6JrmwhXXRbq\nH6Zn8th76azZlc/g1FY8d/3IQIZhKlLPXUQClV9Ywk0vpfHJ2mzuOK03N4/rGbEe7zvLdvC/s1eQ\nmVfIaf1TuOfMPvRsd/T3ok/fmcsbi7Yxa9F2duYepGvbptx9Zl/OOrZ9jZ/MrW7PXeEuIoHJzi/k\n+ue+YuWOXH578UAuHZEa8e/YX1TClHkbmfTxBgqKSji9fwoTTu7O8GMOrye/K/cgsxdvZ+aibaza\nkUtcA2Ns72QuHNqJM49tX+NDP19TuItInbZmVx43vrCAzLyDPH3lMMb1TanR79udX8hzn25i6heb\n2XegmMGdWzK+Xwon9U5mYKeW/3ExVEFhCdn5hWzNOcCn67P5ZG0WK7bn4g6DU1tx0ZCOnDe4YyAn\nSxXuIlJn/XPFTm7/+2KaJsQx+erhDO3Suta+e39RCa8vyOD1tK3fBHZCXAPiwz3v4lCIg8Whb9rH\nNTCGdWnNSb2SOHtQB3okJ9ZarZXRCVURqXNKQ85TH67lyX+tZXDnlvzl6hG0b9m4VmtoGh/HtWO6\ncu2YruzOL+TT9btZlrGX0nCeN2wAbZolkNw8gZQWCQzt0prEhOiLyuirWESi0o59B7j974v5YkMO\nFw/rxG8uGvgfFyYFoW1iAucP7sj5gyNz9WhdonAXkRrl7ry7fCf3vbGsbEmBSwfz/WGd6sQSAbFM\n4S4iNWbRlj08PCed+RtzGNipJX+4fAjdAx6zri8U7iIx5OsrJWcv2U5m3kGy84s4WFxKz3aJ9G3f\nnIGdWnLGgPa0a1Gz49wbswt47L103lm2k6TEBH514bFcPjK11qYLimbLiMQEd+eDVZk88m46azPz\n6dUuke7JzWibmEB8wwaszcxj1Y48cgqKaGBwQs8kvj+sM+cN7hjR9dCz8gr5wwdreHX+VuLjGvCj\nk7oz4eTuNIvCE5J1lWbLiNQToZBz38xl/H3BVronNWPSVcM4Y8C3r5R0d9ZnFTBr8TbeWLSN2/6+\nmOc+3cjDFw+if8cWR/z9RSUhPl6TxZuLtvH+ql2EQs4Vo7pw66m9SG4ezKJZop67SFQLhZx7Zizl\n9bQMfnJKD26v5iJZoZDz1tLt/OrtlezZX8x/ndCV0/q3p2+H5rSoxs0ktu09wNw1Wcxbm828ddns\nO1BMm2bxnD+4I9ccf4zG1WuQLmISiXGl4WCfnpbBbeN7cdv43oe9jb37i/jNO6t4bUHGN691bt2E\n0d3bclKvJI7v0fabsC8oLGHO8p28sWgbaZv3ANC+RWNO7JXEWce25+TeyRpTrwUKd5EYVhpy7p6+\nlBkLM7h9fG9+Nr7XUW1vV+5BVm7PZdXOXJZl7OOz9bvZd6C40ra9UxK5cGgnTu+fQo/kRE1prGUa\ncxeJUaUh567XlzBz0Tb++7Te3Hrq0QU7QEqLxqS0aMz3+rb75juWb9vHV5tyKApfuhnXwDihZxL9\nO7RQoEcBhbtIFCkNOXe+voQ3Fm3jztN7c/O4ow/2yjRsYAxObcXg1FY1sn2peQp3kSjy4KzlvLFo\nG3ed0Yeffq9n0OVIHaazHyJR4tX5W3j5yy38eGx3BbtUSeEuEgUWb93Lg7NWcFKvJO4+o2/Q5UgU\nULiL1HHZ+YXc9FIayc0T+OPlQyN6RanELo25i9Rh+4tK+PHUNHIKiphx0xhaN4sPuiSJEuq5i9RR\nxaUhfvLyQhZt2cOTlw3h2E4tgy5Jooh67iJ1UCg85fGj1Vk8fPFAzhrYIeiSJMqo5y5Sx7g7D85e\nzqzF27nrjD5cMapL0CVJFFK4i9Qh7s6Ds1bw0hdb+PHJ3fnJKT2CLkmilIZlROqIUKisx/51sN97\nVl9d5i9HTOEuUgcUlYR44M1lvLYgg4lje3DPmX0U7HJUFO4iAcvKK5vHvmDzHm4d15PbT+utYJej\npnAXCdCyjH1MmLqAPfuLeOqKoZw3uGPQJUmMULiLBCAUcqZ8upFH311NcvMEpk8co3nsElEKd5Fa\nlpVXyJ2vL+HjNVmM75fCo5cMoo2uPJUIU7iL1KKP12Rxx2tLyD1YzK8uGMBVo4/R+LrUCIW7SC0o\nKgnx2Hvp/PWTjfROSeSlG0fRt32LoMuSGKZwF6lB7s7ctdk8/M4q0nfmcdXoLjxwTn8aN2oYdGkS\n4xTuIjVkacZeHnk3nU/X7Sa1TRP+es0ITuufEnRZUk8o3KXeKywpZWvOfopLHQAzaNUknraJ8TRq\neHgrdIRCzsdrspg8dwOfb9hN66aNePDc/lw5ugsJceqtS+1RuEu9tG3vAX7//hqWZexjfVY+JSGv\ntF2bZvGc2DOJi4Z14qSeScQdIuy35uxn1uJtzFy4jQ3ZBbRv0Zj7z+7LFaO60Lxxo5rcFZFKKdyl\n3vlqUw43vZTG/qJSRndvy6n92tE7pTmNG5UFd8hhz/4isvOK2LpnP++v3MXsJdtp2yye9i0bf2t7\nxaUh1uzKB2BUtzbccmpPzh3U8bB7/SKRVGW4m1ljYC6QEG4/3d0fqtAmAXgRGA7sBi5z900Rr1bk\nKL3y5RYemr2c1NZNeXXC8fRsl1jlZ4pKQny0OpM5y3eSd7C4khbG+YM7csGQTqS2aRr5okWOQHV6\n7oXAOHfPN7NGwDwzm+PuX5RrcwOwx917mtnlwCPAZTVQr8gRm/Txen47J52xvZP54xVDadmkesMl\n8XENOH1Ae04f0L6GKxSJnCr/3ehl8sNPG4V/Kg5QXgC8EH48HTjVdGWG1CGvzt/Cb+ekc97gjky5\nbmS1g10kWlVrUNDMGprZYiATeN/dv6zQpBOwFcDdS4B9QNtKtjPBzBaY2YKsrKyjq1ykmt5dvoP7\n31jG2N7J/O7SwTRsoH6HxL5qhbu7l7r7EKAzMMrMjq3QpLLflm9NP3D3ye4+wt1HJCcnH361Iocp\nbXMOt05bzJDUVjxz1TDi43SSU+qHw/qb7u57gY+AMyu8lQGkAphZHNASyIlAfSJHbO/+Im55ZREd\nWjVmynUjaRqvyWFSf1QZ7maWbGatwo+bAOOB9ArNZgPXhh9fAnzo7pVPHBapBe7Ona8vJSu/kKeu\nGEqrplp1UeqX6nRlOgAvmFlDyv5n8Jq7v21mvwQWuPts4Flgqpmto6zHfnmNVSxSDS98tol/rdrF\nA+f0Y1DnVkGXI1Lrqgx3d18KDK3k9QfLPT4IXBrZ0kSOzIrt+/jNO+mc2rcdN5zYLehyRAKhs0sS\nUw4Wl3Lbq4tp1bQRj106WGulS72lM0wSUx5/bzVrM/N5/vqRuruR1GvquUvM+Hz9bp79dCNXje7C\nKX3aBV2OSKAU7hIT8g4Wc+frSzimTVPuP7tf0OWIBE7DMhL13J0H3lzOjn0HeH3iGM1nF0E9d4kB\nry/IYNbi7dw+vjfDj2kddDkidYLCXaLausw8Hpy9nDE92vKT7/UMuhyROkPhLlHrYHEpP315Ec3i\n43jysiFaEEykHA1OSlRyd+6buYzVu/J4/vqRtGvx7TskidRn6rlLVHrqw3W8sWgbd5zWW9MeRSqh\ncJeoM2vxNp54fw0XD+vEzeM0zi5SGYW7RJWvNuVw1/SljOrahocvHqjlBUQOQeEuUWPBphyumzKf\nzq2aMOnq4STENQy6JJE6S+EuUeGrTTlcO2U+KS0aM23CaK0bI1IFzZaROu/rHntKy8ZM+9FoUjQz\nRqRKCnep01Zuz+X6578ipUVjXv3RaE15FKkmDctInbV5dwHXPjefxIQ4pt54nIJd5DAo3KVOysw9\nyNXPzqekNMTUG0bRqVWToEsSiSoKd6lztuzezw/+8jnZ+YU8d/0oerZrHnRJIlFHY+5Sp6zYvo9r\np3xFSSjE1BuOY0iqbm4tciQU7lJnfLI2i5teWkiLxnG8OuF49dhFjoLCXQJXXBriiffXMOnj9fRq\nl8jz14+io8bYRY6Kwl0CtWX3fm55dRFLtu7lilGp/M+5/XUnJZEI0G+RBGbumixufmUhAE9fOYyz\nB3YIuCKR2KFwl1rn7jw7byO/eWcVvdo156/XjKBL26ZBlyUSUxTuUqvSNufw9L/X80F6JmcMSOGJ\nHwyhWYL+GopEmn6rpMaVhpz3V+5k8twNLNyyl5ZNGnHPmX358cndaaBb44nUCIW71Ah3J/dACbOX\nbONv8zayefd+Uts04RfnD+DSEZ110lSkhuk3TKqtNOQszdjLJ2uz+Wx9NvsOlHyrjbuTd7CE7PxC\nCktCAAxObcU9Z/bljAHtdRNrkVqicJcq5RQU8dIXm3nx881k5xdiBgM6tqBz68rnoicmxJGUGE9S\nYgLDj2nN8GNa645JIrVM4S6HVFhSyiNzVvPK/M0cLA7xvT7JXDSsMyf0aEvbxISgyxOR76Bwl0rl\nHSzmx1PT+Gz9bi4Z3pkJJ3end4qWAxCJFgp3+ZbMvINcN+Ur1uzK44kfDObiYZ2DLklEDpPCXf7D\nnoIiLp30OZm5hfzt2hGc0qdd0CWJyBFQuMs33J07X1/Cjr0HmTbhOIYf0ybokkTkCOlmHfKN5z7d\nxAfpmdx3dl8Fu0iUU7gLAMsy9vHwnFWM75fCdWO6Bl2OiBwlhbtQUFjCLdMWkpSYwGOXDNKcdJEY\nUGW4m1mqmf3bzFaZ2Qoz+1klbU4xs31mtjj882DNlCs14bH3VrM5Zz9PXjaE1s3igy5HRCKgOidU\nS4A73H2hmTUH0szsfXdfWaHdJ+5+buRLlJq0YFMOL3y+iWtGH8Nx3dsGXY6IREiVPXd33+HuC8OP\n84BVQKeaLkxq3sHiUu6ZsZSOLZtw95l9gy5HRCLosMbczawrMBT4spK3jzezJWY2x8wGHOLzE8xs\ngZktyMrKOuxiJbKe+nAt67MKePjigVpTXSTGVDvczSwRmAHc5u65Fd5eCBzj7oOBp4A3K9uGu092\n9xHuPiI5OflIa5YIWL0zj0kfb+CS4Z05ubeOhUisqVa4m1kjyoL9ZXefWfF9d8919/zw43eARmaW\nFNFKJWLcnV+8tYLEhDh+fna/oMsRkRpQndkyBjwLrHL3Jw7Rpn24HWY2Krzd3ZEsVCLnvRU7+Wz9\nbu44vbdmx4jEqOoMtJ4AXA0sM7PF4dfuB7oAuPsk4BLgJjMrAQ4Al7u710C9cpQOFpfy63+som/7\n5vxwVJegyxGRGlJluLv7POA7r2px9z8Bf4pUUVJz/jp3Axl7DvDKj44jrqGuYROJVfrtrke27z3A\n0x+t56xj2zOmh06JiMQyhXs98su3VuI49+skqkjMU7jXEx+m7+LdFTu59dRepLZpGnQ5IlLDFO71\nwIGiUh6ctYJe7RK58cTuQZcjIrVAlyXWA3/691oy9hzg1QmjiY/T/89F6gP9pse4tbvymDx3AxcP\n68RoLQwmUm8o3GNYaci5e8ZSEhPidBJVpJ5RuMew5z/bxKIte3novAEkJSYEXY6I1CKFe4zasns/\nj7+3mu/1SeaCIR2DLkdEapnCPQa5O/e9sZSGDYz/u2igbpsnUg8p3GPQ1C828+m63dx7Vl86tmoS\ndDkiEgCFe4xZsX0fv357Fd/rk6yFwUTqMYV7DCkoLOGWVxbRulkjHr90MA0aaDhGpL7SRUwx5H9m\nLWfT7gJevnE0bTU7RqReU889Rrz21VZmLtzGLeN6cXwPXawkUt8p3GPA0oy9PDBrOSf0bMst43oG\nXY6I1AEK9yi3O7+QiVPTSE5M4KkrhukGHCICaMw9qpWUhrhl2iKyC4qYMXEMbXQ/VBEJUzcviv36\nH6v4bP1u/u/CYxnYuWXQ5YhIHaJwj1Ivfr6J5z/bxH+d0I1LR6QGXY6I1DEK9yj00epM/nf2Csb3\na8fPz9FqjyLybQr3KJO+M5ebX1lE3/Yt+MPlQ2moC5VEpBIK9yiyNWc/1zw7n8SEOJ69bgTNEnQ+\nXEQqp3SIEll5hVz17JcUloR4feLxdGipBcFE5NDUc48CuQeLuWbKfDJzC3nu+pH0TmkedEkiUscp\n3Ou43IPFXPPsfNZl5jHp6uEM69I66JJEJApoWKYO23egrMe+cvs+/vzDYYztnRx0SSISJRTuddS+\nA8Vc8+yXrNyRy9NXDue0/ilBlyQiUUThXgdl5h7kminzWZ+VzzNXDme8gl1EDpPCvY7ZkJXPNVPm\ns6egiCnXjeSkXhqKEZHDp3CvQ9I27+FHLy7AgFcnHK/1YkTkiCnc64DSkDPp4/U88f4aOrVqwgv/\nNYpuSc2CLktEopjCPWBbc/Zz1/QlfLEhh/MGd+T/LjqWFo0bBV2WiEQ5hXtAlmbsZfLcDcxZvpOE\nuAY8dskgLhneGTOtFSMiR0/hXotyCop4e+l2Zi7cxuKte2meEMcNJ3bj+hO6ajkBEYkohXsNCoWc\n9J15zFuXxSdrs/l8/W5KQk7f9s154Jx+XDYyleYaghGRGqBwrwEHikqZvjCDKfM2sjG7AIDeKYnc\ncGI3LhzaiX4dWgRcoYjEOoV7BBWVhPjbvA38de4G9uwvZnDnljz6/UGc3DuZ9i0bB12eiNQjVYa7\nmaUCLwLtgRAw2d3/UKGNAX8Azgb2A9e5+8LIl1t3pW3O4b6Zy1izK59xfdsxcWwPRnZtrROkIhKI\n6vTcS4A73H2hmTUH0szsfXdfWa7NWUCv8M9xwDPhP+uFR99N55mP19OhRWOevXYEp/bTcgEiEqwq\nw93ddwA7wo/zzGwV0AkoH+4XAC+6uwNfmFkrM+sQ/mxMmzZ/C09/tJ5Lh3fmf88foLsjiUidcFjr\nuZtZV2Ao8GWFtzoBW8s9zwi/FtMWb93LQ7NWcFKvJH77/UEKdhGpM6od7maWCMwAbnP33IpvV/IR\nr2QbE8xsgZktyMrKOrxK65js/EJueimNdi0S+KNuVC0idUy1wt3MGlEW7C+7+8xKmmQAqeWedwa2\nV2zk7pPdfYS7j0hOjt7VDkMh52evLiKnoIhJVw2ndbP4oEsSEfkPVYZ7eCbMs8Aqd3/iEM1mA9dY\nmdHAvlgeb5/21RY+Xbebh84bwLGdtHKjiNQ91RkkPgG4GlhmZovDr90PdAFw90nAO5RNg1xH2VTI\n6yNfat2wY98BHn4nnTE92nLFqNSqPyAiEoDqzJaZR+Vj6uXbOPDTSBVVV7k7P39jOSWhEL+9eJDm\nsItInXVYs2Xqu9lLtvNheiZ3nt6HLm2bBl2OiMghKdyrKb+whF++tZIhqa24/oRuQZcjIvKdFO7V\nNGXeRnYXFPHQef017VFE6jyFezXsKSjir3M3cHr/FIZ2aR10OSIiVVK4V8MzH68nv6iEO8/oE3Qp\nIiLVonCvws59B3nhs01cNLQTvVOaB12OiEi1KNyr8McP1xJy5/bxvYMuRUSk2hTu32FTdgGvfbWV\nH47qQmobTX0UkeihcP8OT7y/hkYNG/DTcT2DLkVE5LAo3A9h5fZcZi/ZzvUndKVdc90iT0Sii8L9\nEH73z9W0aBzHj0/uEXQpIiKHTeFeiQWbcvggPZOJp/SgZdNGQZcjInLYFO4VuDuPvrea5OYJXDem\na9DliIgcEYV7BXPXZjN/Yw63jOtJ03jdNk9EopPCvZxQyHnsvXRS2zTh8pFdgi5HROSIKdzLmbN8\nJ8u35XL7+N7Ex+k/jYhELyVYWElpiN+9v5reKYlcMKRT0OWIiBwVhXvYjIUZbMgq4M7T+2hJXxGJ\negp34EBRKU/+ay1DUltxWv+UoMsRETlqCndg8twN7Nh3kHvP6qv7oopITKj34b5t7wGe+Xgd5wzs\nwOjubYMuR0QkIup9uD/8zirc4b6z+wZdiohIxNTrcP9yw27eXrqDiWN70Lm1lvQVkdhRb8O9NOT8\n4q2VdGzZmIljtTiYiMSWehvuUz/fxModudx/Tj+axDcMuhwRkYiql+GemXuQ3/1zDSf1SuKcgR2C\nLkdEJOLqZbj/6h+rKCwN8asLjtXURxGJSfUu3D9Zm8VbS7bz01N60jWpWdDliIjUiHoV7geLS3lw\n1gq6JTVj4indgy5HRKTG1KsFy3/59ko2Zhfwyo3HkRCnk6giErvqTc/9H0t38MqXW5g4tgdjeiYF\nXY6ISI2qF+G+Zfd+7p2xlKFdWnHH6b2DLkdEpMbFfLgXl4a4ZdpCzOCPlw+lUcOY32URkdgfc5/0\n0XqWZOzj6SuHkdpGSwyISP0Q093YtbvyeOrDdZwzqANn62IlEalHYjbcS0PO3TOW0jShIb84f0DQ\n5YiI1KqYDffnP9vEoi17eei8/iQlJgRdjohIrYrJcF+flc/j763me32SuVA3uxaReijmwj2/sIQf\nT02jSXxDfnPxQK0dIyL1UpXhbmZTzCzTzJYf4v1TzGyfmS0O/zwY+TKrx925e/oSNmTl86crhtKh\nZZOgShERCVR1pkI+D/wJePE72nzi7udGpKKjMHnuBt5ZtpP7z+6rq1BFpF6rsufu7nOBnFqo5ah8\nui6bR95N55xBHfjRSVoUTETqt0iNuR9vZkvMbI6ZHXLeoZlNMLMFZrYgKysrQl8NGXv2c/MrC+nZ\nLpFHvz8w8meIAAAFR0lEQVRI4+wiUu9FItwXAse4+2DgKeDNQzV098nuPsLdRyQnJ0fgq8uW8Z34\nUholpc5frh5Bs4SYv+hWRKRKRx3u7p7r7vnhx+8AjcysVga83Z0H3lzO8m25/P6yIXTTzTdERIAI\nhLuZtbfwOIiZjQpvc/fRbrc6Js/dwPS0DG49tRfj+6fUxleKiESFKscwzGwacAqQZGYZwENAIwB3\nnwRcAtxkZiXAAeByd/caqzjsta+28vCcdM4d1IHbTu1V018nIhJVqgx3d7+iivf/RNlUyVrz3oqd\n3DtzKSf1SuKJHwyhQQOdQBURKS/qrlD9fP1ubpm2iMGprfjL1cOJj4u6XRARqXFRl4xtE+M5rlsb\nnrtuJE3jNTNGRKQyUZeOvVOaM/WG44IuQ0SkTou6nruIiFRN4S4iEoMU7iIiMUjhLiISgxTuIiIx\nSOEuIhKDFO4iIjFI4S4iEoOsFtb4qvyLzbKAzUf48SQgO4LlRAPtc/2gfa4fjmafj3H3Km+IEVi4\nHw0zW+DuI4KuozZpn+sH7XP9UBv7rGEZEZEYpHAXEYlB0Rruk4MuIADa5/pB+1w/1Pg+R+WYu4iI\nfLdo7bmLiMh3ULiLiMSgqAt3MzvTzFab2TozuzfoemqCmaWa2b/NbJWZrTCzn4Vfb2Nm75vZ2vCf\nrYOuNZLMrKGZLTKzt8PPu5nZl+H9/buZxQddYySZWSszm25m6eFjfXw9OMa3h/9OLzezaWbWONaO\ns5lNMbNMM1te7rVKj6uV+WM4z5aa2bBI1RFV4W5mDYE/A2cB/YErzKx/sFXViBLgDnfvB4wGfhre\nz3uBD9y9F/BB+Hks+RmwqtzzR4Dfh/d3D3BDIFXVnD8A77p7X2AwZfses8fYzDoBtwIj3P1YoCFw\nObF3nJ8Hzqzw2qGO61lAr/DPBOCZSBURVeEOjALWufsGdy8CXgUuCLimiHP3He6+MPw4j7Jf+k6U\n7esL4WYvABcGU2HkmVln4Bzgb+HnBowDpoebxNr+tgBOBp4FcPcid99LDB/jsDigiZnFAU2BHcTY\ncXb3uUBOhZcPdVwvAF70Ml8ArcysQyTqiLZw7wRsLfc8I/xazDKzrsBQ4Esgxd13QNn/AIB2wVUW\ncU8CdwOh8PO2wF53Lwk/j7Vj3R3IAp4LD0X9zcyaEcPH2N23AY8DWygL9X1AGrF9nL92qONaY5kW\nbeFulbwWs3M5zSwRmAHc5u65QddTU8zsXCDT3dPKv1xJ01g61nHAMOAZdx8KFBBDQzCVCY8zXwB0\nAzoCzSgblqgolo5zVWrs73m0hXsGkFrueWdge0C11Cgza0RZsL/s7jPDL+/6+p9s4T8zg6ovwk4A\nzjezTZQNtY2jrCffKvzPd4i9Y50BZLj7l+Hn0ykL+1g9xgDjgY3unuXuxcBMYAyxfZy/dqjjWmOZ\nFm3h/hXQK3x2PZ6ykzGzA64p4sLjzc8Cq9z9iXJvzQauDT++FphV27XVBHe/z907u3tXyo7ph+5+\nJfBv4JJws5jZXwB33wlsNbM+4ZdOBVYSo8c4bAsw2syahv+Of73PMXucyznUcZ0NXBOeNTMa2Pf1\n8M1Rc/eo+gHOBtYA64GfB11PDe3jiZT902wpsDj8czZl49AfAGvDf7YJutYa2PdTgLfDj7sD84F1\nwOtAQtD1RXhfhwALwsf5TaB1rB9j4BdAOrAcmAokxNpxBqZRdk6hmLKe+Q2HOq6UDcv8OZxnyyib\nSRSROrT8gIhIDIq2YRkREakGhbuISAxSuIuIxCCFu4hIDFK4i4jEIIW7iEgMUriLiMSg/wduWEuQ\nUXdpIQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(data[\"X\"])\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\niILi7QAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(data[\"Y\"])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lets capture by sending triggers. We use the Yokogawa GS200 to send triggers, which is not yet in the main branch. Nevertheless, it should be clear from the example how the capturing works" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Connected to: YOKOGAWA GS210 (serial:91T926459, firmware:2.02) in 0.04s\n" + ] + } + ], + "source": [ + "from qcodes.instrument_drivers.yokogawa.GS200 import GS200\n", + "yo = GS200(\"yo\", \"USB0::0x0B21::0x0039::91T926459::INSTR\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def send_trigger(): \n", + " yo.voltage(5.0)\n", + " time.sleep(0.01)\n", + " yo.voltage(0.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def setup():\n", + " yo.auto_range(True)\n", + " yo.output(\"on\")\n", + " yo.voltage(0.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "n_samples = 100\n", + "\n", + "setup()\n", + "sr.buffer.start_capture(\"ONE\", \"SAMP\")\n", + "\n", + "for _ in range(n_samples): \n", + " send_trigger()\n", + "\n", + "sr.buffer.stop_capture()\n", + "\n", + "data = sr.buffer.read_capture_data(n_samples)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(data[\"X\"])\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 28e9ef5ec47d37a5863e5fbc11de06ec3c94b334 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Fri, 24 Nov 2017 10:39:35 +0100 Subject: [PATCH 43/77] Removed unnecessary and buggy test in the _assert_mode method. --- qcodes/instrument_drivers/yokogawa/GS200.py | 33 +++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/qcodes/instrument_drivers/yokogawa/GS200.py b/qcodes/instrument_drivers/yokogawa/GS200.py index 223d61abeed..7f6135c587e 100644 --- a/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/qcodes/instrument_drivers/yokogawa/GS200.py @@ -449,9 +449,6 @@ def _assert_mode(self, mode: str, check: bool=True) -> None: mode (str): "CURR" or "VOLT" """ if self._cached_mode != mode: - if check: - self._cached_mode = self.source_mode.get() - self._assert_mode(mode, check=False) raise ValueError("Cannot get/set {} settings while in {} mode".format(mode, self._cached_mode)) def _set_source_mode(self, mode: str) -> None: @@ -474,33 +471,39 @@ def _set_source_mode(self, mode: str) -> None: self.write("SOUR:FUNC {}".format(mode)) self._cached_mode = mode - # The next time the range is asked, ask from instrument and update the cached value - self._cached_range_value = None # Update the measurement mode self._update_measurement_module(source_mode=mode) - def _set_range(self, mode: str, val: float) -> None: + def _set_range(self, mode: str, range: float) -> None: """ Update range Args: mode (str): "CURR" or "VOLT" - val (float): value to set + range (float): range to set. For voltage we have the ranges [10e-3, 100e-3, 1e0, 10e0, 30e0]. For current + we have the ranges [1e-3, 10e-3, 100e-3, 200e-3]. If auto_range = False then setting the + output can only happen if the set value is smaller then the present range. """ self._assert_mode(mode) - val = float(val) - self._update_measurement_module(source_mode=mode, source_range=val) - self._cached_range_value = val - self.write(':SOUR:RANG {}'.format(str(val))) + range = float(range) + self._update_measurement_module(source_mode=mode, source_range=range) + self._cached_range_value = range + self.write(':SOUR:RANG {}'.format(str(range))) - def _get_range(self, mode: str) -> None: + def _get_range(self, mode: str) -> float: """ - Update range. - Note: we do not use cached values here to ensure snapshots correctly update range. + Query the present range. + Note: we do not return the cached value here to ensure snapshots correctly update range. In fact, we update the + cached value when calling this method. Args: mode (str): "CURR" or "VOLT" + + Returns: + range (float): For voltage we have the ranges [10e-3, 100e-3, 1e0, 10e0, 30e0]. For current we have the + ranges [1e-3, 10e-3, 100e-3, 200e-3]. If auto_range = False then setting the output can + only happen if the set value is smaller then the present range. """ self._assert_mode(mode) self._cached_range_value = float(self.ask(":SOUR:RANG?")) - return self._cached_range_value \ No newline at end of file + return self._cached_range_value From 763bc15d890b6820b2c2a123f22328c8ccd5f399 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Fri, 24 Nov 2017 17:45:56 +0100 Subject: [PATCH 44/77] Rename QCodes example with SR86x with buffered readout .ipynb to QCodes example with SR86x with buffered readout.ipynb --- ...pynb => QCodes example with SR86x with buffered readout.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/examples/driver_examples/{QCodes example with SR86x with buffered readout .ipynb => QCodes example with SR86x with buffered readout.ipynb} (100%) diff --git a/docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb b/docs/examples/driver_examples/QCodes example with SR86x with buffered readout.ipynb similarity index 100% rename from docs/examples/driver_examples/QCodes example with SR86x with buffered readout .ipynb rename to docs/examples/driver_examples/QCodes example with SR86x with buffered readout.ipynb From b04e887a93f8e390d02a399f0c0fd2b942e1d279 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Fri, 24 Nov 2017 17:46:53 +0100 Subject: [PATCH 45/77] Rename QCodes example with SR86x with buffered readout.ipynb to QCodes_example_with_SR86x_with_buffered_readout.ipynb --- ...pynb => QCodes_example_with_SR86x_with_buffered_readout.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/examples/driver_examples/{QCodes example with SR86x with buffered readout.ipynb => QCodes_example_with_SR86x_with_buffered_readout.ipynb} (100%) diff --git a/docs/examples/driver_examples/QCodes example with SR86x with buffered readout.ipynb b/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb similarity index 100% rename from docs/examples/driver_examples/QCodes example with SR86x with buffered readout.ipynb rename to docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb From 5033fdb46debeda5d6bf39517e8902607fe6aa22 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Mon, 27 Nov 2017 14:05:05 +0100 Subject: [PATCH 46/77] 1) Processed most of the PR comments. 2) The max frequency of the SR860 and SR865 are 5Khz and 4Mhz respectively. --- .../stanford_research/SR860.py | 3 +- .../stanford_research/SR865.py | 3 +- .../stanford_research/SR86x.py | 30 +++++++++++-------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR860.py b/qcodes/instrument_drivers/stanford_research/SR860.py index 0e9b77ed013..94c26efabff 100644 --- a/qcodes/instrument_drivers/stanford_research/SR860.py +++ b/qcodes/instrument_drivers/stanford_research/SR860.py @@ -2,4 +2,5 @@ class SR860(SR86x): - pass + def __init(self, name, address, reset=False, **kwargs): + super().__init__(name, address, max_frequency=5E3, reset=reset, **kwargs) diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index 63532eb4e1b..a0e1030648c 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -2,4 +2,5 @@ class SR865(SR86x): - pass + def __init(self, name, address, reset=False, **kwargs): + super().__init__(name, address, max_frequency=4E6, reset=reset, **kwargs) diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py index c6265032e5f..fc6d9f41059 100644 --- a/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -1,11 +1,14 @@ import numpy as np import time +import logging import qcodes from qcodes import VisaInstrument from qcodes.instrument.channel import InstrumentChannel from qcodes.utils.validators import Numbers, Ints, Enum +log = logging.getLogger(__name__) + class SR86xBuffer(InstrumentChannel): """ @@ -13,7 +16,7 @@ class SR86xBuffer(InstrumentChannel): For reference, please consult the SR860 manual: http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf """ - def __init__(self, parent: qcodes.instrument, name: str): + def __init__(self, parent: qcodes.instrument, name: str) ->None: super().__init__(parent, name) self._parent = parent @@ -23,7 +26,8 @@ def __init__(self, parent: qcodes.instrument, name: str): get_cmd="CAPTURELEN?", set_cmd="CAPTURELEN {}", set_parser=self._set_capture_len_parser, - get_parser=int + get_parser=int, + unit="kB" ) self.add_parameter( # Configure which parameters we want to capture @@ -31,8 +35,7 @@ def __init__(self, parent: qcodes.instrument, name: str): label="capture configuration", get_cmd="CAPTURECFG?", set_cmd="CAPTURECFG {}", - set_parser=lambda value: {"X": 0, "X,Y": 1, "R,T": 2, "X,Y,R,T": 3}[value], - get_parser=lambda value: {"0": "X", "1": "X,Y", "2": "R,T", "3": "X,Y,R,T"}[value] + val_mapping={"X": "0", "X,Y": "1", "R,T": "2", "X,Y,R,T": "3"} ) self.add_parameter( @@ -63,13 +66,15 @@ def __init__(self, parent: qcodes.instrument, name: str): self.add_parameter( "count_capture_bytes", label="capture bytes", - get_cmd="CAPTUREBYTES?" + get_cmd="CAPTUREBYTES?", + unit="B" ) self.add_parameter( "count_capture_kilobytes", label="capture kilobytes", - get_cmd="CAPTUREPROG?" + get_cmd="CAPTUREPROG?", + unit="kB" ) self.bytes_per_sample = 4 @@ -78,7 +83,7 @@ def __init__(self, parent: qcodes.instrument, name: str): def _set_capture_len_parser(value: int) -> int: if value % 2: - print("the capture length needs to be even. Setting to {}".format(value + 1)) + log.warning("the capture length needs to be even. Setting to {}".format(value + 1)) value += 1 if not 1 <= value <= 4096: @@ -109,9 +114,9 @@ def _set_capture_rate_parser(self, capture_rate_hz: float) -> int: nearest_valid_rate = max_rate / 2 ** n_round if abs(capture_rate_hz - nearest_valid_rate) > 1: - print("Warning: Setting capture rate to {:.5} Hz".format(nearest_valid_rate)) + log.warning("Warning: Setting capture rate to {:.5} Hz".format(nearest_valid_rate)) available_frequencies = ", ".join([str(f) for f in self.available_frequencies]) - print("The available frequencies are: {}".format(available_frequencies)) + log.warning("The available frequencies are: {}".format(available_frequencies)) return n_round @@ -167,7 +172,7 @@ def read_capture_data(self, sample_count: int) -> dict: return data - def capture_samples(self, sample_count: int): + def capture_samples(self, sample_count: int) ->dict: """ Capture a number of samples. This convenience function provides an example how we use the start and stop methods. We acquire the samples by sleeping for a time and then reading the buffer. @@ -225,8 +230,9 @@ class SR86x(VisaInstrument): } _N_TO_INPUT_SIGNAL = {v: k for k, v in _INPUT_SIGNAL_TO_N.items()} - def __init__(self, name, address, reset=False, **kwargs): + def __init__(self, name, address, max_frequency, reset=False, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) + self._max_frequency = max_frequency # Reference commands self.add_parameter(name='frequency', label='Frequency', @@ -234,7 +240,7 @@ def __init__(self, name, address, reset=False, **kwargs): get_cmd='FREQ?', set_cmd='FREQ {}', get_parser=float, - vals=Numbers(min_value=1e-3, max_value=2.5e6)) + vals=Numbers(min_value=1e-3, max_value=self._max_frequency)) self.add_parameter(name='sine_outdc', label='Sine out dc level', unit='V', From cd900a5d62c5bb456eb214b7f9a032453cc54f1c Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Mon, 27 Nov 2017 15:35:19 +0100 Subject: [PATCH 47/77] Added a QCoDeS parameter that stores the buffer readout --- .../stanford_research/SR86x.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py index fc6d9f41059..dd4493b089b 100644 --- a/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -78,6 +78,7 @@ def __init__(self, parent: qcodes.instrument, name: str) ->None: ) self.bytes_per_sample = 4 + self._capture_data = [] @staticmethod def _set_capture_len_parser(value: int) -> int: @@ -144,7 +145,13 @@ def stop_capture(self): """ self.write("CAPTURESTOP") - def read_capture_data(self, sample_count: int) -> dict: + def get_cached_capture_data(self) ->list: + """ + Retrieve the capture data from the last readout + """ + return self._capture_data + + def perform_capture_data(self, sample_count: int) -> dict: """ Read capture data from the buffer. @@ -169,6 +176,7 @@ def read_capture_data(self, sample_count: int) -> dict: values = values[values != 0] data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} + self._capture_data = data return data @@ -190,7 +198,7 @@ def capture_samples(self, sample_count: int) ->dict: time.sleep(capture_time) self.stop_capture() - return self.read_capture_data(sample_count) + return self.perform_capture_data(sample_count) class SR86x(VisaInstrument): @@ -458,6 +466,12 @@ def __init__(self, name, address, max_frequency, reset=False, **kwargs): buffer = SR86xBuffer(self, "{}_buffer".format(self.name)) self.add_submodule("buffer", buffer) + self.add_parameter( + 'buffer_values', + label="cached capture data", + get_cmd=self.buffer.get_cached_capture_data + ) + self.input_config() self.connect_message() From 8b1167d0b9fe259316863310b7f3278a3ae404d1 Mon Sep 17 00:00:00 2001 From: sohailc Date: Tue, 28 Nov 2017 11:04:19 +0100 Subject: [PATCH 48/77] Use of qcodes Measure not working for some reason... asking for help --- .../QCodes example with SR830.ipynb | 2 +- ...ple_with_SR86x_with_buffered_readout.ipynb | 164 ++++++++++++------ .../stanford_research/SR860.py | 2 +- .../stanford_research/SR865.py | 2 +- .../stanford_research/SR86x.py | 60 +++++-- tmp_debug.py | 32 ++++ 6 files changed, 200 insertions(+), 62 deletions(-) create mode 100644 tmp_debug.py diff --git a/docs/examples/driver_examples/QCodes example with SR830.ipynb b/docs/examples/driver_examples/QCodes example with SR830.ipynb index ac61b16d219..140cb0461fe 100644 --- a/docs/examples/driver_examples/QCodes example with SR830.ipynb +++ b/docs/examples/driver_examples/QCodes example with SR830.ipynb @@ -1005,7 +1005,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.3" + "version": "3.6.3" } }, "nbformat": 4, diff --git a/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb b/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb index 63bc56a2d9e..497d4892f09 100644 --- a/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb +++ b/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb @@ -2,28 +2,32 @@ "cells": [ { "cell_type": "code", - "execution_count": 12, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ + "import sys \n", + "sys.path.append(r\"C:\\Users\\Administrator\\Documents\\development\\qcodes_dev\")\n", + "\n", "import time \n", "\n", "import matplotlib.pyplot as plt \n", "\n", "import qcodes\n", - "from qcodes.instrument_drivers.stanford_research.SR860 import SR860" + "from qcodes.instrument_drivers.stanford_research.SR860 import SR860\n", + "from qcodes.instrument_drivers.QuTech.IVVI import IVVI" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Stanford_Research_Systems SR860 (serial:003101, firmware:V1.47) in 0.08s\n" + "Connected to: Stanford_Research_Systems SR860 (serial:003101, firmware:V1.47) in 0.15s\n" ] } ], @@ -33,7 +37,32 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initialized IVVI-rack in 0.03s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Administrator\\Documents\\development\\qcodes_dev\\qcodes\\instrument\\parameter.py:182: UserWarning: Delay kwarg is deprecated. Replace with inter_delay or post_delay as needed\n", + " warnings.warn(\"Delay kwarg is deprecated. Replace with \"\n" + ] + } + ], + "source": [ + "ivvi = IVVI(\"ivvi\", \"COM4\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -43,35 +72,34 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\nUXdpIQAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "100" ] }, + "execution_count": 5, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "plt.plot(data[\"X\"])\n", - "plt.show()" + "len(data[\"X\"])" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\niILi7QAAAABJRU5ErkJggg==\n", + "image/png": "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\n/wNJDeuWE8jqrgAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -79,88 +107,77 @@ } ], "source": [ - "plt.plot(data[\"Y\"])\n", + "plt.plot(data[\"X\"])\n", "plt.show()" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Lets capture by sending triggers. We use the Yokogawa GS200 to send triggers, which is not yet in the main branch. Nevertheless, it should be clear from the example how the capturing works" - ] - }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Connected to: YOKOGAWA GS210 (serial:91T926459, firmware:2.02) in 0.04s\n" - ] + "data": { + "image/png": "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\nZjaosizvHnppZKQWac21a5fnWKUfTRn5Rvk9p0uB/1JYfzPwZmAV8CzwBy1iIGm9pLqk+v79+1tl\nMTPrSz13z4h8pHFmYXk5sK9dHklV4BTgxXm2bZf+AnBqitFc1pGW0XAJ8FBEPNdIiIjnImIqIqaB\nz3H4Zb1Gvs0RUYuI2tKlS1tlMTPrS704m+5BYDjNchsiv+Q13pRnHLgivb4MuC/yT0qNA6NpJtxK\nYBh4oF3MtM32FIMU886jLKPhcpou0Uk6o7D4a8CjC9gPZmYDo9sjo2qnDBExKekq4C4gA7ZExE5J\n1wH1iBgHbgFukzRBPloZTdvulLQV2AVMAldGxBRAq5ipyKuBMUnXAw+n2BxlGa8Ffhn4zaZm/a6k\nVeSX855qsd7MbKB1ezaduvWoh+NdrVaLer1edjXMzLrir7/5LFd+6SG+9ol381Nvev1Rx5G0IyJq\nnfL5CQxmZnaYmZFRD03tNjOzAdOLs+nMzGzAZFnvzaYzM7MB45GRmZmVrhefTWdmZgOmWsm7B4+M\nzMysNB4ZmZlZ6WbvGXkCg5mZlcSfMzIzs9JVM8+mMzOzklV9z8jMzMqWeTadmZmVzSMjMzMrXebZ\ndGZmVjaPjMzMrHSZn01nZmZl8+eMzMysdB4ZmZlZ6RoPSu2pe0aSVkvaLWlC0oYW60+UdEdaf7+k\nFYV116T03ZIu7hRT0soU44kUc+hVlPGUpG9JekRSvZD+Bkl3pzLulnTaQneYmdkg6LnZdJIy4Ebg\nEmAEuFzSSFO2dcCBiDgb2ARsTNuOAKPAOcBq4CZJWYeYG4FNETEMHEixj7iMQt3+eUSsiohaIW0D\ncG8q4960bGZmSS/OpjsPmIiIPRHxCjAGrGnKswa4Nb3eBlwoSSl9LCIORcSTwESK1zJm2uaCFIMU\nc+1RljGfYqxiGWZmBlQqQuqte0bLgKcLy3tTWss8ETEJHASWzLNtu/QlwEspRnNZR1oGQABfk7RD\n0vpCnjdFxLMp1rPA6fPuATOzAVStqGsjo+oC8qhFWnPt2uVpl96qE5wv/9GUAfDOiNgn6XTgbkmP\nR8TftcjfUurA1gOcddZZC93MzKwvZBUx3UMjo73AmYXl5cC+dnkkVYFTgBfn2bZd+gvAqSlGc1lH\nWgYR0fj9PPAVZi/fPSfpjBTrDOD5Vg2PiM0RUYuI2tKlS1tlMTPrW9VKpafuGT0IDKdZbkPkkwXG\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "from qcodes.instrument_drivers.yokogawa.GS200 import GS200\n", - "yo = GS200(\"yo\", \"USB0::0x0B21::0x0039::91T926459::INSTR\")" + "plt.plot(data[\"Y\"])\n", + "plt.show()" ] }, { - "cell_type": "code", - "execution_count": 13, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "def send_trigger(): \n", - " yo.voltage(5.0)\n", - " time.sleep(0.01)\n", - " yo.voltage(0.0)" + "# Lets capture by sending triggers. We use the Yokogawa GS200 to send triggers, which is not yet in the main branch. Nevertheless, it should be clear from the example how the capturing works" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "def setup():\n", - " yo.auto_range(True)\n", - " yo.output(\"on\")\n", - " yo.voltage(0.0)" + "def send_trigger(): \n", + " ivvi.trigger()\n", + " time.sleep(0.1)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "n_samples = 100\n", - "\n", - "setup()\n", "sr.buffer.start_capture(\"ONE\", \"SAMP\")\n", "\n", + "time.sleep(0.1)\n", "for _ in range(n_samples): \n", " send_trigger()\n", "\n", "sr.buffer.stop_capture()\n", "\n", - "data = sr.buffer.read_capture_data(n_samples)" + "data = sr.buffer.get_capture_data(n_samples)" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAakAAAD8CAYAAADNGFurAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvXl4ldW1+P9ZmRMyAQmBDJBAwhCGMAREEbUoilqgrahQ\n61Rbhyv1e7X3/qr31t5btYO21t5abatFpbYqirXFWRRRARmCjGFMQoBMZB7JnPX747yhx5jknCQn\nOeck+/M858n77nfvtVcO4ayz1157LVFVDAaDwWDwRHzcrYDBYDAYDF1hjJTBYDAYPBZjpAwGg8Hg\nsRgjZTAYDAaPxRgpg8FgMHgsxkgZDAaDwWMxRspgMBgMHosxUgaDwWDwWIyRMhgMBoPH4uduBbyd\nqKgoTUxMdLcaBoPB4FXs3r27VFWjHfUzRqqPJCYmkpGR4W41DAaDwasQkZPO9DPuPoPBYDB4LMZI\nGQwGg8FjMUbKYDAYDB6LMVIGg8Fg8FiMkTIYDAaDx+KUkRKRJSJyVESyROT+Tp4Hisg66/kOEUm0\ne/aA1X5URK5wJFNE1ojIPhHZLyLrRSS0w1wrRERFJN26Xywiu0XkgPVzkV3fABF5RkSOicgREbmm\nt/oaDAaDYeBxaKRExBd4CrgSSAVWiUhqh263ARWqmgw8ATxqjU0FVgJTgSXA0yLi60Dmvaqapqoz\ngFPAajtdwoB7gB12c5cCS1V1OnAz8KLds/8GilV1ojXPJ73R19F7ZDAYDIb+wZmV1DwgS1VzVLUJ\neAVY3qHPcmCtdb0euFRExGp/RVUbVfUEkGXJ61KmqlYDWOODAfv69g8DjwEN7Q2qukdVC6zbTCBI\nRAKt++8Cv7D6talqaS/1NfSRs00tvLD1BCfL6tytisFg8CKcMVJxwGm7+zyrrdM+qtoCVAEjuxnb\nrUwReR4oAiYDT1pts4AEVX2rG12vAfaoaqOIRFptD4vIFyLymojE9FLfLyEit4tIhohklJSUdKOO\nAeBEaR3ffGob//vmIS77zSf874ZMyuua3K2WwWDwApwxUtJJmzrZp6fttgvVW4FY4DBwvYj4YHPL\n/bBLJUWmYnPb3WE1+QHxwFZVnQ18Dvy6l/p+uUH1GVVNV9X06GiHWT2GNNtzylj25BaKaxp4ctUs\nVsxJ4C+f5/LNp7dSUtPobvUMBoOH44yRygMS7O7jgYKu+oiIHxABlHcz1qFMVW0F1mFbHYUB04DN\nIpILzAc22AVPxANvADeparYlogw4a7UDvAbM7qW+hl7Q2qb8+B8HGREawJs/uJClabH84lvTee3O\n8ymubuTm53ZS3dDsbjUNBoMH44yR2gWkiEiSiARgCyzY0KHPBmxBCwArgE2qqlb7SiuaLglIAXZ2\nJVNsJMO5PamlwBFVrVLVKFVNVNVEYDuwTFUzLLfe28ADqrq1XSFr/jeBS6ymS4FDvdTX0AveOVBI\nVnEt/3nFJOKHh5xrnzNuBH/4zmyOnanh+2szaGhudaOWBoPBk3FopKw9m9XA+9jcb6+qaqaIPCQi\ny6xua4CRIpIF3Afcb43NBF7FZhzeA+5W1dauZGJzt60VkQPAAWAM8JADFVcDycCDIrLXeo2ynv0I\n+F8R2Q/cyL/chT3S19F7ZPgqbW3K7z46TsqoUK6aNuYrzy+ZNIrHr0tjx4ly7nl5Dy2tbW7Q0mAw\neDpiW0AYekt6erqaLOhf5a39Bax+aQ9PrprF0rTYLvs9v/UEP33zENenJ/DLa6ZjW0AbDIbBjojs\nVtV0R/1MqQ6Dy2lsaeW3H1qrqOlfXUXZc+uCJMrrmnhyUxYZJ8tJi4/kquljuCw1pttxBoNhaGDS\nIhlczi/eOUJWcS3/ddUUfH0cr4zuWzyRh5dPJXHkMD45VsIdf91NTkntAGhqMBg8HWOkDC7lg8wi\nXtiWy3cXJPG1yaMcDwBEhBvPT2TNLXN5798vIsDXhyc+PN7PmhoMBm/AGCmDyyisquc/1+9nelwE\nP7pyUq9kRIcFcuuCRN7cV8DhwmoXa2gwGLwNY6QMLuMPm7Opb2rlyVWzCPTrfcrDOy6aQFiQH49/\ncMyF2hkMBm/EGCmDS6g828RrGXksnxlLYtSwPsmKCPHn9oXj+fDwGfaernSRhgaDwRsxRsrgEv62\n4xT1za3ctjDJJfJuvTCJiGB//rg523Fng8EwaDFGytBnGltaeWFbLgtTopg8OtwlMkMD/bhx/jje\nP1REton0MxiGLMZIGXpNRV0TWcU1vLA1l5KaRr63cLxL5d+yIBF/Xx/+/FmOS+UaDAbvwRzmNfSK\n/Mp6LvnVxzS32jKWTB4dxkUpUS6dIyo0kGvnxPNaRh73Lp7IqLAgl8o3GAyej1lJGXrFzhNlNLcq\nD349lTU3p7P2u/P6JaXR9xeOp6WtjWc/Naspg2EoYlZShl6x51QlIQG+3HJBolNZJXpLYtQwVsyJ\n589bTnD+hJEsmmzSJRkMQwmzkjL0ij2nKkmLj+xXA9XOT5dNI3VMOP/v5b1kFZsgCoNhKGGMlKHH\n1De1criwmlljIwdkvuAAX565KZ0APx9ufzGDxhZTPcVgGCoYI2XoMQcLqmhpU2aNHT5gc8ZFBvOT\npanklNRxML9qwOY1GAzuxSkjJSJLROSoiGSJyP2dPA8UkXXW8x0ikmj37AGr/aiIXOFIpoisEZF9\nIrJfRNaLSGiHuVaIiNqVjl8sIrtF5ID1c5Fd383WHF8qhigiT9i1HRORSrsxrXbPOlYgNgB7TlUA\nMDNhYFZS7cwfPxKAvaeNkTIYhgoOAydExBd4ClgM5AG7RGSDqh6y63YbUKGqySKyEngUuF5EUrGV\nhp8KxAIfishEa0xXMu9V1Wpr7t9gq7z7S+s+DLgH2GE3dymwVFULRGQatmq/cXbPb1DVL1UlVNV7\n7X6/HwCz7B7Xq+pMR+/LUGbPqUoSRgQTHRY4oPPGhAcxOjyIfSZVksEwZHBmJTUPyFLVHFVtAl4B\nlnfosxxYa12vBy4VWzzycuAVVW1U1RNAliWvS5l2BkqAYMC+dPDDwGNAQ3uDqu5R1QLrNhMIEpGe\nfHquAl7uQf8hz55TlcxKGDhXnz1pCRHszzNGymAYKjhjpOKA03b3eXx5pfKlPqraAlQBI7sZ261M\nEXkeKAImA09abbOABFV9qxtdrwH2qGqjXdvzluvuQelwkEdExgFJwCa75iARyRCR7SLyjW7mGpIU\nVtVTVN0wYEETHUlLiCS37CyVZ5vcMr/BYBhYnDFSncUYq5N9etpuu1C9FZt78DA2t6EP8ATwwy6V\nFJmKzc14h13zDao6HVhovW7sMGwlsF5V7cPFxqpqOvBt4LciMqGTuW63DFlGSUlJVyoNSvacsq1i\nBjJowp6Z8TbjuC/P7EsZDEMBZ4xUHpBgdx8PFHTVR0T8gAigvJuxDmVahmMdttVRGDAN2CwiucB8\nYINd8EQ88AZwk6pm28nIt37WAC9hczPas5IOrr5216Gq5gCb+fJ+VXufZ1Q1XVXTo6OjOz4e1GzJ\nKiXQz4cpY8LcMv+0+AhEMPtSBsMQwRkjtQtIEZEkEQnA9sHeMeptA3Czdb0C2KSqarWvtKL/koAU\nYGdXMsVGMpzbk1oKHFHVKlWNUtVEVU0EtgPLVDVDRCKBt4EHVHVru0Ii4iciUda1P/B14KDd80nA\ncOBzu7bh7ftZ1tgFgH2AyJCmoq6Jv39hqxnVl6KGfSE8yJ8J0aHGSBkMQwSH0X2q2iIiq7FFzfkC\nz6lqpog8BGSo6gZgDfCiiGRhW0GttMZmisir2D7oW4C7211rXcj0AdaKSDg2l+A+4C4HKq4GkoEH\nReRBq+1yoA543zJQvsCHwLN241ZhC+qwd11OAf4kIm3YDPgvO0QxDmn+uv0kDc1tLs923lPS4iP5\n5FgJqtov+QINBoPnIF/+jDb0lPT0dM3IyHDc0ctpaG7lwkc3MS0ughdu7eg1HVhe/DyXB/+Zydb7\nFxEXGexWXQwGQ+8Qkd3W/n+3mIwTBqd4Y08+pbVN3O7mVRTYIvzA7EsZDEMBY6QMDlFV/vxZDlNj\nwzl/wkh3q8Pk0eEE+fuw80S5u1UxGAz9jDFSBofsPV1JdkkdN50/ziP2gAL8fLgwOYqNh85g3NUG\nw+DGGCmDQ/6xJ58APx+unD7G3aqcY3FqDPmV9RwurHG3KgaDoR8xRsrQLc2tbby1v5DLpowiPMjf\n3eqcY9HkGETgw8Nn3K2KwWDoR4yRMnTLluOllNU18Y2ZHTNhuZfosEBmJUSy8ZAxUgbDYMYYKUO3\nvLEnn8gQfy6ZNMrdqnyFxamjOZBfRWFVvbtVMRgM/YQxUoYuqW1s4YNDRVw9fQwBfp73p7I4NQaA\nDw8Xu1kTg8HQX3jeJ4/BY9h8tJiG5jaWe5irr50J0cNIihpmXH4GwyDGGClDl2TkVhAS4MtsN5Xl\ncISIcMXU0WzLKqW0ttHxAIPB4HUYI2XokoyT5cxMiMTP13P/TK6ZHUdLm/KPPfnuVsVgMPQDnvvp\nY3ArdY0tHC6sYc4499SNcpaUmDDSEiJZvzvPHOw1GAYhxkgZOmVfXiWtbcpsDzdSANfOiedIUQ0H\n86vdrYrBYHAxxkgZOuWLkxUAzE7wfCO1NC2WQD8f1u8+7W5VDAaDizFGytApGScrmBgTSkSI52SZ\n6IqIYH+umDqaf+wtILukloq6JuP6Mwx5nvzoOLf/JYN/7MmntrHF3er0GqeMlIgsEZGjIpIlIvd3\n8jxQRNZZz3eISKLdswes9qMicoUjmSKyRkT2ich+EVkvIqEd5lohImpXOn6xiOwWkQPWz0V2fTdb\nc+y1XqOs9ltEpMSu/Xt2Y24WkePW62aGIG1tyhcnKzx+P8qe69ITqKpv5tLHP2HWwxv5yT8z3a2S\nweA2nvk0m8c3HuPznDL+fd1e5v/8I68tbePQSImIL/AUcCWQCqwSkdQO3W4DKlQ1GXgCeNQam4qt\nSu9UYAnwtIj4OpB5r6qmqeoM4BS2yrvtuoQB9wA77OYuBZaq6nRsJexf7KDbDao603rZn/pcZ9f+\nZ0v+COB/gPOAecD/iIj3fFK7iOySWqobWpg91nt+9QXJI3n5+/N54vo0psdFsD2nzN0qGQwDhqpS\nXN3AqbKzvLTjFD9/5whXzxjDngcX89qd5xMe5Me/r9vL2SbvW1E5s5KaB2Spao6qNgGvAMs79FkO\nrLWu1wOXiq2mw3JsJdobVfUEkGXJ61KmqlYDWOODAXu/zcPAY0BDe4Oq7lHVAus2EwgSkUCnfvuv\ncgWwUVXLVbUC2IjNuA4pMqz9KG9aSYkI508YyTdnxbMwJYoTpXU0t7a5Wy2DYUB4cftJ5v38Iy76\n1cf81xsHuGDCSH5zXRp+vj7MTRzBr69LI7esjkfePuxuVXuMM0YqDrDfkc6z2jrto6otQBUwspux\n3coUkeeBImAy8KTVNgtIUNW3utH1GmCPqtqf7Hzecuk9KF8uhnSNnUsxoQe/66BnW3YZI4YFkBQ1\nzN2q9IqUmFBa2pSTZXXuVsVgGBA2HSkmfngwv742jT/cMJs1N88l0M/33PMLJkTx/YXjeWnHKTYd\n8a4MLc4Yqc6q3HXcle6qT0/bbReqtwKxwGHgehHxweZG/GGXSopMxeZmvMOu+QbLDbjQet1otb8J\nJFouxQ/51yrQmd8VEbldRDJEJKOkpKQrlbyS3286zpv7CliWFusRBQ57Q8qoMACOn6l1syYGQ//T\n0tpGRm4FF0+MZsWceK6cPobgAN+v9Pvh5RNJHhXKz985Qlub9wQWOWOk8oAEu/t4oKCrPiLiB0QA\n5d2MdShTVVuBddhWR2HANGCziOQC84ENdsET8cAbwE2qmm0nI9/6WQO8hM3NiKqW2a22ngXm9OB3\nRVWfUdV0VU2Pjo7u+Nhr+c3GY/z6g2N8a1YcP756irvV6TUTokMRgePFxkgZBj+HCqupbWzhvPEj\nu+0X6OfLDxYlk1Vcy0YvqsPmjJHaBaSISJKIBGALhNjQoc8GbEELACuATWqLAd4ArLSi/5KAFGBn\nVzLFRjKc25NaChxR1SpVjVLVRFVNBLYDy1Q1Q0QigbeBB1R1a7tCIuInIlHWtT/wdeCgdW9fYnYZ\nthUbwPvA5SIy3AqYuNxqG/QczK/idx8dZ8WceH51bZpHp0JyRHCAL/HDg42RMgwJdp4oB+C8pBEO\n+149fQxjR4Tw9OZsrzmm4eeog6q2iMhqbB/WvsBzqpopIg8BGaq6AVgDvCgiWdhWUCutsZki8ipw\nCGgB7rZWSHQh0wdYKyLh2Fxv+4C7HKi4GkgGHhSRB622y4E64H3LQPlic+s9az2/R0SWWTqVA7dY\n+paLyMPYjCjAQ6pa7ug9Ggy8ua8APx/hx1dPwdfHO9189iRHh3L8jCktbxj8bM8pJ3FkCDHhQQ77\n+vn6cPtF4/nxPw7yeXYZFyRHDYCGfUO8xZp6Kunp6ZqRkeFuNfqEqnLhox8zMSaU52+d5251XMLP\n3znMC9tyOfTTK7x6VWgwdEdbmzLr4Y1cMTWGx1akOTWmobmVhY99TMqoUP5623n4uOlLqYjsVtV0\nR/3M/14De09Xkl9Zz9UzYt2tistIHhVKU0sbpytM1V7D4OXomRqq6ps5L6n7/Sh7gvx9ufuSCWzL\nLuO+V/fS1OLZRzUcuvsMg5+39xcS4OtzrtLtYCBllC1RyfEzNV4bSm8wOGKHdWj9vPGO96PsufmC\nRM42t/LYe0cpqW3kmRvTGRbomebArKSGOG1tytsHCrloYhQRwZ6fp89ZktuNlAmeMAwyVJUjRdV8\nnl3GB4fOEBcZTPzwkB7JEBH+7ZJkHr82ja1ZZby881Q/adt3jJEa4uw5XUFhVQNfH0SuPoCwIH/G\nRASRZYyUYZCx8dAZlvz2M1Y9u51t2WUsTOl98MM1c+IZNzKEXbmeGx/mmes7w4Dx7oEiAvx8uGwQ\nufraSR4VyvFiE+FnGFw8+1kO8cOD+dWKNEICfJk0OqxP8uaMG84nR0tQVY88wG9WUkOcT4+XcF7S\nCEI91B/dF1JGhZFVXOtVp+sNhu7Yn1fJrtwKbrkgkfMnjCQtIZIg/69ml+gJcxNHUFbXRG7ZWRdp\n6VqMkRrCFFU1cOxMbZ/cBZ7M5NFhNDS3kVNqcvgZBgdrtpwgNNCP6+cmOO7sJOlWImlPdfkZIzWE\n+ey4Le/gwpTBk9rJnvRE23++9hP5BoM3U1TVwNv7C7kuPYGwINcFOU2IDiUi2J/duRUuk+lKjJEa\nwnx2vJSo0EAm99Gn7akkRQ0jKjSQHSdMbSmD9/PX7SdpU+XWBYkulevjI6SPG07GSc/8MmeM1BCl\nrU3ZklXKRSlRHrlZ6gpEhPPGj2BHTrnX5CkzGLri0+MlzE0cQcKInoWbO8OcxOFkl9RRXtfkctl9\nxRipIcqhwmrK65pYOHFw7ke1Mz9pBEXVDZwq98xNYYPBGRpbWjlcWM3MsZH9In9uou0w8O6Tnufy\nM0ZqiPKptR+1wAsSTPaF9vIFO3I805VhMDjDkcIamluVtPj+MVLT4yII8PUhwwODJwZf3LGhSxqa\nW/nHnnyqG5r5x558powJZ1SY48zJ3kzKqFBGDAtgx4lyrnNhRJTBMJDsz6sEYEZ8RL/ID/L3ZXp8\nBH/6NIeXdp4iNiKYF783zyM+H4yRGkI8+t4Rnt+ae+7+P6+Y5D5lBggRYV7iCBM8YfBq9uVVMXJY\nAHGRwf02x0+XTeXDw2cormnkpR2neO9gETedn9hv8zmLMVJDhEMF1azdlsu3zxvLf19lqxnV10OA\n3sK8pBG8l1lEfmV9v/4nNxj6i/15lcyIj+jXIKdpcRFMi7Ot1LZnl7Hx0BmPMFJmT2oI0Nam/OSf\nB4kMCeD/u2ISwwL9hoyBgn9liN6ebVZTBu+jrrGFrOJaZvTTflRnXJYaw/acMmoamgdszq5wykiJ\nyBIROSoiWSJyfyfPA0VknfV8h4gk2j17wGo/KiJXOJIpImtEZJ+I7BeR9SIS2mGuFSKiIpJu3S8W\nkd0icsD6uciu72Zrjr3Wa5TVfp+IHLLm+EhExtmNabXrv8GZ98fT+fuefDJOVnD/kslEhgS4W50B\nZ8rocOIig3lx+0kTim7wOg7mV9GmkJbQP/tRnXHZlBiaW5VPj5UO2Jxd4dBIiYgv8BRwJZAKrBKR\n1A7dbgMqVDUZeAJ41Bqbiq2U/FRgCfC0iPg6kHmvqqap6gzgFLby8O26hAH3ADvs5i4FlqrqdOBm\n4MUOut2gqjOtV7HVtgdIt+ZYDzxm17/erv8yR++Pp6OqPPVxFjPiI1gxJ97d6rgFHx/h3742gb2n\nK9l8rMTd6hgMPWJ/XhXAgK6kZo+NZHiIPx8ePjNgc3aFMyupeUCWquaoahPwCrC8Q5/lwFrrej1w\nqdicp8uBV1S1UVVPAFmWvC5lqmo1gDU+GLD/6vswNoPS0N6gqntUtcC6zQSCRCSwu19IVT9W1faD\nM9uBQfvpvSu3ghOlddx0fqLbykR7AtfOSSAuMpjfbjxmVlMGr2JfXiVxkcFEhXb7seZS/Hx9WDQ5\nhk1HimlpdW/lXmeMVBxw2u4+z2rrtI+qtgBVwMhuxnYrU0SeB4qAycCTVtssIEFV3+pG12uAPara\naNf2vOW6e1A633W8DXjX7j5IRDJEZLuIfKObubyCdbtOExrox1XTR7tbFbcS4OfDDxYlsy+vio+P\nFjseYDB4CPvzqvot9Lw7FqeOoqq+mV1uzunnjJHq7IO941fRrvr0tN12oXorEAscBq4XER9sbsQf\ndqmkyFRsbsY77JpvsNyAC63XjR3GfAdIB35l1zxWVdOBbwO/FZEJncx1u2XIMkpKPNd9VNPQzDsH\nClmaFktIgAnkvGZOPAkjgrnn5b0s+e2nfOfPOyiqanA80GBwE9UNzZwqP8t0NxiphSnRBPj58O7B\nwgGf2x5njFQeYH8KMh4o6KqPiPgBEUB5N2MdylTVVmAdttVRGDAN2CwiucB8YINd8EQ88AZwk6pm\n28nIt37WAC9hczNijbkM+G9gmf3Kq911qKo5wGZgVsc3RFWfUdV0VU2PjvbcDOJv7S+kvrmV69IH\nrTezR/j7+vD7VbO5YupoYsKD2JJVyuc57t8YNhi64rSVzitp5LABn3tYoB9XTx/D+t15VJ11X5Sf\nM0ZqF5AiIkkiEoAtEKJj1NsGbEELACuATWpz/G8AVlrRf0lACrCzK5liIxnO7UktBY6oapWqRqlq\noqomYttHWqaqGSISCbwNPKCqW9sVEhE/EYmyrv2BrwMHrftZwJ8sGcV2Y4a372dZYxcAh5x4jzyS\nVzNOMzEmlJkJA7fh6umkJUTy+HVpPHPTHHwETpSanH4GzyWvoh6A+OGuTyrrDN9fOJ6zTa38bedJ\nt8wPThgpa49pNfA+Nvfbq6qaKSIPiUh79NsaYKSIZAH3AfdbYzOBV7F90L8H3K2qrV3JxOYGXCsi\nB4ADwBjgIQcqrgaSgQc7hJoHAu+LyH5gL5APPGuN+RUQCrzWIdR8CpAhIvuAj4FfqqpXGqm8irPs\nOVXJijnxgzbLeV8I9PMlNjKYXFMQ0eDB/MtIuecQempsOAtTonhhay6NLa1u0cGpjQpVfQd4p0Pb\nT+yuG4Bruxj7M+BnTspsw7Z6caTPJXbXjwCPdNF1ThfjL+uifRsw3dH83kB72Op8K8Gq4askRQ3j\nZJkxUoORmoZmPjx8hrrGVppb26yXMm5kCFdPH+M1X9zyK+oZFuBLZIjrihz2lNsvGs+Na3byz70F\nXJc+8PkvzW76IOVAfhV+PsKkQVrQ0BWMGxnChr0FqKrXfGgZHJNdUsv3/5JBTknnX0DenV7EL6+Z\n7tLqtv1FXsVZ4oYHu/Xv88LkKKaMCefPn+UYI2VwHQfzq5gYE0ag39BJf9RTEkcOo7qhhYqzzYwY\nNvQycQxGNh05w/97eS8Bfj6s/e48powJI8DXB39fH3x9hBe25fKr94+SWVDFUzfMZmrswEfN9YS8\ninq37Ue1IyJcMzuOR94+TGlt44Ce1wKTu29QoqoczK9iepxn/wd0N0lRtoipXOPy83pUld9vOs5t\nazMYOzKEDT+4kIsnRjMqLIjIkIBz+SrvvHgCr9w+n4bmNr759Db+tsOzU2XlVZx1236UPZNHhwNw\nrKhmwOc2RmoQkl9ZT8XZZqa54WyFNzHOCus1wRPeTXNrG6tf2sOvPzjG0hmxrL/zgm6z3c9NHMHb\n91zI/PEj+e83DvKbjccGUFvnqW5oprqhxSOM1MTRthSqR88YI2VwAQfzbUET02LD3ayJZzN2RAg+\nYoyUt/PewSLePlDIf1w+kf9bOZPgAMcu7pGhgbxwy1yumBrD2m3ui1zrjnwrsi8u0r3uPoDo0ECG\nh/hzzBgpgys4mF+Nr48wZYwxUt0R4OdD3PBgcsvMWSlv5rXdecRGBHHXJck9CjDw8RFWzhtLdUOL\nR2T77oi7w8/tEbEFYR0x7j6DKziQX0XKqNAhVTOqtySOHGb2pLyYgsp6Pjtewoo58fj2IoHyhclR\njBgWwD/35veDdn0jr8L25ckTjBTApJgwjhXVDPgenjFSgwwTNNEzEkcO40RpnUdvnhu65u9f5KEK\nK+b0LjTa39eHq6aPts5UtbhYu76RV1FPsL+vx0SeThwdRl1TK/mV9QM6rzFSg4zCqgbK6prOlYE2\ndE9i1DBqrDB0g3ehqry2O4/540cwdmTv922WpcXR0NzmEbWT7MmvqHf7GSl7JsXYzlweHWCXnzFS\ng4xzQRPGSDlFovXhdsIET3gNZ5tayC2tY8O+Ak6WneXaXq6i2kkfN5zYiCD+ubdj3mz3klfpGeHn\n7Uy0EgMMdISfOcw7yNiVW46vj5BqgiacIjHqX2Hoc8YNd7M2Bke8vb+QH72+n1rLNRcW5MeVfayV\n5uMjLE2LZc2WE5ypbiAmPMgVqvaZvIp6j0oOHR7kT2xE0ICflTJGahDR0NzK+t15XDZllFNhuAZI\nGG4LQzc5/Dyb5tY2HnnrEGs/P8mssZF857xxDAv0IyUm1CW10m44bxxrtpzg6Y+z+OnyaS7QuG/U\nNDRTebbtQroyAAAgAElEQVTZ7dkmOjLRDRF+xkgNIjbsK6DibDM3X5DoblW8hvYw9Bzj7vNo1m7L\nZe3nJ7ntwiR+tGQyAX6u3akYOzKEa9PjeXnnae64eAKx3RwGHgjagxM8yd0Htn2pbVllNLe24e87\nMLtFZk9qkKCqrN2Wy8SYUM43mc97xKSYsAHfDDY4j6ry0o5TzBk3nAe/nupyA9XO6kUpKMrvP87q\nF/k94V8HeT3MSI0Oo6m1bUA9D8ZIDRK+OFVJZkE1N52f6DHRQN5C6phwsktqaWj2vKwDBvg8p4yc\n0jq+PW9sv84TFxnMyrljeXXX6XMVcd3FKWv+OA9bSU20Ivy++0IGq57Zzs/fOdzvczplpERkiYgc\nFZEsEbm/k+eBIrLOer5DRBLtnj1gtR8VkSscyRSRNSKyT0T2i8h6EQntMNcKEVG70vGLRWS3iByw\nfi6y67vZmsO+GGKv9PV01m7LJSzQj2/OinO3Kl5Hamw4bTrwobUG53hpxykigv25esaYfp/r7q8l\n4+sjPP7B0X6fqzs+zy4jLjKY6AHOOO6IKWPCufPiCUweHUZzaxulNY39PqfDPSkR8QWeAhYDecAu\nEdnQoWLtbUCFqiaLyErgUeB6EUnFVhp+KhALfCgiE60xXcm8V1Wrrbl/g63y7i+t+zDgHmCH3dyl\nwFJVLRCRadiq/dp/Ut+gqhkdfq0e6auqHv0V+2xTC+9lFrFybgLDAs02Y09pTx91uLCaNA+KpjJA\naW0j72cW8Z354wYkg8roiCC+tzCJpz7O5pYFSW6JrmtobmVLVinXzPa8qtq+PsL9V04e0DmdWUnN\nA7JUNUdVm4BXgOUd+iwH1lrX64FLxfbuLgdeUdVGVT0BZFnyupRpZ6AECAbsUwE8DDwGNLQ3qOoe\nVW0/4JAJBImIo68fPdXXo9mWVUZTSxuXp/YtFHeokjA8hNBAPw4VVrtbFUMHXsvIo7lVueG8/nX1\n2XPXJclEhQbyyFuH3JKJZHtOGWebWlk0ZdSAz+2JOGOk4oDTdvd5fHml8qU+qtoCVAEjuxnbrUwR\neR4oAiYDT1pts4AEVX2rG12vAfaoqv0a9HnL1feg/OtrSU/19Wg2HS1mWIAv85JGuFsVr8THR5g8\nOozDxkh5HH//Io+5icNJHjVwFaZDA/34j8snknGygn/szae+qZW2toEzVpuOFBPs72sCoCycMVKd\nrTc7/ot11aen7bYL1VuxudsOY3PD+QBPAD/sUkmRqdjcdnfYNd+gqtOBhdbrxl7q23Gu20UkQ0Qy\nSkpKulJpQFBVPj5SzIUpUf0W9TQUSI0N53BhzYB9GOWW1vHkR8e58v8+47o/fk5VvUnL1JETpXUc\nL67lqun9vxfVkWvTE5g8Oox71+1jyk/eY8pP3iOzoKrf51VVPjpczILkKJMg2sKZT7U8wD7vSDzQ\nMX/IuT4i4gdEAOXdjHUo09oHWodtdRQGTAM2i0guMB/YYBc8EQ+8Adykqtl2MvKtnzXAS/zLdddT\nfb+Eqj6jqumqmh4dHd3x8YBypKiGwqoGFk02roG+MGVMOLWNLZyu6P+orvczi7jsN5/w+MZjBPn7\nsOd0BTc/t5OaBmOo7Nl4qAiAxakxAz63r4+w9rvz+J+lqfznFZNoam1j0+Hifp/32Jla8ivrudS4\n+s7hjJHaBaSISJKIBGALLNjQoc8G4GbregWwSW3O3A3ASiuaLglIAXZ2JVNsJMO5PamlwBFVrVLV\nKFVNVNVEYDuwTFUzRCQSeBt4QFW3tiskIn4iEmVd+wNfBw72Ul+PZdMR23+cr00yf9R9IdUueKI/\n+ejwGVa/9AXT4yP4/IFFvPFvC3j6hjkczK/ilud3Ud/k0TE6A8oHmWdIHRPutqwLMeFB3Logibu/\nlsykmDB25pb3+5wfHbEluTVfOv+FQyNl7dmsxhY1dxh4VVUzReQhEVlmdVsDjBSRLOA+4H5rbCbw\nKnAIeA+4W1Vbu5KJzd22VkQOAAeAMcBDDlRcDSQDD3YINQ8E3heR/cBeIB94tjf6OnqP3MnHR4qZ\nFhfOKA/JN+atTBodho/AoYL+M1K7csu5669fMGVMOC/cOo8xEbYzMItTY/jdqlnsPlnBs5/l9Nv8\n3kRpbSO7T1W4ZRXVGfOSRrD7ZAUtrW39Os+mw8VMj4vwmPyBnoBT8cqq+g7wToe2n9hdNwDXdjH2\nZ8DPnJTZBixwQp9L7K4fAR7pouucLsb3WF9PpKKuiS9OVbD6a8nuVsXrCfL3ZXx0KIcK+++s1OMf\nHGXEsAD+8t15RAT7f+nZVdPHcOW00fzxk2xWzk0Y8l86Nh0uRtU9rr7OmJc0gr98fpLMgv47plDT\n0Mye05XcdfGEfpHvrZiddi9mx4ly2hQunuTefbHBQuqY8H5z92UWVLE9p5xbFiQSGdJ5EbsfLZlM\nc2sbv9l4rF908CY+OFREXGQwU2M9I5v/vERb5OyufnT57cgpp7VNuSDZRPXZY4yUF5NdUgvA5NGe\n8R/Z20mNDSe/sp7imgbHnXvIc1tyCfb3ZdXcrs/7JEYN48b5ibyacZojRUM3HL6qvpnPjpeyODXG\nYw6zjgoPInFkCDtO9J+R2ppdSqCfD7PHmpIx9hgj5cVkF9cSGxFksky4iPbN6vcOFrlUbnFNA2/u\nK+Da9HgiQvy77XvPpckMC/BjzWcnXKqDt1B5tokb1+ygtU09LsXXvKQR7Mot77djCtuyypibOMKE\nnnfAGCkvJruklgmjQh13NDjFxJgwJsaE8uY+11Zo/evnJ2lua+PWBUkO+0aGBDBzbOSA1+zxBEpr\nG1n5zHaOFNXwzE1zPC5F1bykkVSebeZ4ca3LZZfUNHL0TI1x9XWCMVJeiqqSXVLHhGhjpFzJ0hmx\n7MqtoLCq3mUyX/8in0smRpNkVQF2RPKoULKKawc0y4G7aW5t484Xd5NbVsdzN89l0WTPCJiwp31f\nqj9C0bdllwKwYEKUy2V7O8ZIeSnFNY3UNrYwIdq5Dz6Dc3w9LRawlSl3BSU1jeRX1rMg2fkPn4kx\nYdQ3t54rfDcU+M3GY2ScrOCxFWlcmOKZH9QJI4IZHR7E1uOlLpe9LauM8CA/psVFuFy2t2OMlJeS\nbbkczErKtSRFDWNaXLjLXH4H8isBmN6DD58Uy4V7vHhouPw2Hy3mD5uzWTUvgWXWlwRPRERYMm00\nm44UU3m2yaWyt2aXMn/8SHx9PCNQxJMwRspLaY/sM3tSrmfpjFj25VVxqqzvKZL251UhQo++IadY\nyVSPnXH93oenUVXfzH+8to/Jo8P4n6VT3a2OQ65Nj6eptY0NLty3PFV2lryKnq22hxLGSHkp2SV1\nhAb6MSrMs4qiDQbai+t9cKjvUX7786pIjg7tUQRmRIg/o8ICOT4EjNSTHx2nrK6JX1+b5hVRbVNj\nI0gdE85rGXkuk7n9RBkA508wQROdYYyUl5JdUsuE6GEec45kMBE/PISo0ECOnembu01V2Z9XxYz4\nnkepTYwJG/TuvpySWl7Ylsv16QletRdzbXo8B/KrXHaWbdeJcoaH+JNsXPedYoyUl5JdXMt480fd\nb4yPHkZOSV2fZBRWNVBa28iM+J5/AA+FCL+fv3OYIH9ffnj5JHer0iOWz4zD31dctpramVtOeuII\nfMx+VKcYI+WF1DW2UFDVYCL7+pEJ0cPIKe2bkdqfZ6s/1BsjNTEmjLNNrRS4MBTek9h46AwfHi5m\n9aJkor3MZT1iWACLU2P4+xd5fV5NFVc3cLLs7LnwdsNXMUbKCzlhfXiayL7+Y3xUKOV1TX2K4tqf\nV4mfjzBlTM/TVqXEWBF+g3BfKqeklvvW7WVqbDi3Lkh0tzq94q6LkxERrv7dFn7xzmEamntXLKH9\nzJWpqt01xkh5ISayr/8Zb61Ss/vg8tufV8Wk0WG9CggYrGHoNQ3N3P7ibvz9fPjTjXMI9PP8YInO\nmB4fwUf3Xcy1c+L506c5/OKdw72Ss+tEOSEBvh6TSNcTMUbKC8kursVHYNxI9xSDGwq07/fllPRu\nJWMLmqjslasPbOmRosMCB1UYuqryn6/t50RpHU99e7bbihm6iuHDAvjlNTP49nljeWnnKU6X9/zI\nws7cCmaPHY6fr/ko7grzznghhwprGDsixGu/hXoDCcOD8feVXu9LnSw7S3VDS68i+9qZGBPaL3ni\n3MVzW3N5L7OIB66cPKjCrX+wyOb6+91Hx3s0rqq+mSNF1cbV5wCnjJSILBGRoyKSJSL3d/I8UETW\nWc93iEii3bMHrPajInKFI5kiskZE9onIfhFZLyKhHeZaISIqIunW/WIR2S0iB6yfizrRb4OIHLS7\nX2dXxTdXRPZa7YkiUm/37I/OvD8Dyenys3x8tJjLpnhebrPBhJ+vD2NHhPR6JfXPvbbDnuf14QMo\nZVQYWWdqBkWE397Tlfzy3cMsTo3htgsdJ9r1JsZEBHPj/HG8/kXeOVe8M+w+WY4qzDVBE93i0EiJ\niC/wFHAlkAqsEpHUDt1uAypUNRl4AnjUGpsKrASmAkuAp0XE14HMe1U1TVVnAKewlYdv1yUMuAfY\nYTd3KbBUVacDNwMvdtD/W8CX/nJU9XpVnamqM4HXgb/bPc5uf6aqdzp6fwaaP32aja8I31s43t2q\nDHrGR4f2Kgy9obmVv3yey9cmRffpmMCUMWHUNbVyshduJE+irrGFu//2BTHhQfx6RdqgPNt31yUT\nCPL35WdvH6apxXGJ+eqGZl7/Ih9/X2HWWM/K9u5pOLOSmgdkqWqOqjYBrwDLO/RZDqy1rtcDl4rt\nL3E58IqqNqrqCSDLktelTFWtBrDGBwP2XyMfBh4DzlWlU9U9qtqeoyQTCBKRQEtGKHAfXZSXt+a4\nDnjZiffB7RRXN/BqRh7XzIlndMTQLi8+EIyPHsbJsrO09nAls353HmV1TdzRxzLg7a7Cfacr+yTH\n3azfnUd+ZT2PX5vmsJ6WtxIVGsh9iyey6Ugx1/7pc/IqOv9i0dLaxuMfHGXBLzbx9v5CVs4d6xWZ\nNtyJM0YqDjhtd59ntXXaR1VbgCpgZDdju5UpIs8DRcBk4EmrbRaQoKpvdaPrNcAeVW207h8GHge6\n+iq6EDijqvbO5CQR2SMin4jIws4GicjtIpIhIhklJSXdqONa1mw5QUtrG3debFZRA8GEqFCaWtu6\n/MDpjNY25c+f5ZAWH9EnVx/YIvyC/X3Zl+e9RqqtTXlhWy4zEyI5b/zg2YfqjO8tHM/TN8wmu7iW\nq3+3hcfeO3LuuAhAY0srd7/0BU9uyuKiSdG89YMLefgb09yosXfgTEKxztbmHb9adtWnq/bOjOM5\nmap6q+USfBK4XkTWYnMj3tKlkiJTsbkZL7fuZwLJqnqv/R5ZB1bx5VVUITBWVctEZA7wDxGZ2r66\ns9PvGeAZgPT09AHZMKhrbOGv20/y9RmxjBtpDvEOBO1h6DkldU6/5xsPFZFbdpanvj27z24tP18f\npsdFePVK6pPjJZworeP/Vs50tyoDwlXTxzBlTDgPvZnJHz/J5unN2UyLC+eilGgO5Ffx2fFS/mdp\nqlMFMA02nFlJ5QEJdvfxQMcUwOf6iIgfEAGUdzPWoUxVbQXWYVsdhQHTgM0ikgvMBzbYBU/EA28A\nN6lqtiXifGCO1X8LMFFENrfLt/T8ljVH+5yNqlpmXe8GsoGJ3bw3A8bhwmrqmlpZPtNzSxkMNtr3\nk3qyGf7sZydIGBHMkmmjXaLDjPgIMguqaW51vM/hiTy/NZdRYYFcOW2Mu1UZMJKihvH8rfPYdv+l\n/GjJZEL8/Xjm0xy2ZpXy2DUzjIHqIc4YqV1AiogkiUgAtkCIDR36bMAWtACwAtikqmq1r7Si/5KA\nFGBnVzLFRjKc2y9aChxR1SpVjVLVRFVNBLYDy1Q1Q0QigbeBB1R1a7tCqvoHVY21+l8IHFPVS+x0\nvsySfS4Bl4hEWys4RGS8pW+OE+9Rv3O40LaY6032AkPvGDEsgMgQf6fD0PfnVbL7ZAW3XJDksrpA\naQmRNLa0cdQLy8kfO1PDp8dKuHH+OAL8ht5pl9ERQdx1yQRevfN89vxkMZ8/cCnXzU1wPNDwJRy6\n+1S1RURWA+8DvsBzqpopIg8BGaq6AVgDvCgiWdhWUCutsZki8ipwCGgB7rZWSHQh0wdYKyLh2FyF\n+4C7HKi4GkgGHhSRB622y1W12MG4lXw1YOIi4CERaQFagTtV1fW1onvB4aIawoP8GGMCJgaU8VHD\nnA5Df2FrLsMCfLk2Pd5l86e1B0/kVXpFpvDm1jYeffcIm44Wk1NSR6CfD6vOG+tutdxOWJA/YUGD\nM2ikv3GqyI2qvgO806HtJ3bXDcC1XYz9GfAzJ2W2AQuc0OcSu+tH6CJ6z65PLjZ3oX3bLZ30ex1b\nSLrHcaSwmiljwgdl+K4nkxobzvrdeZypbiAmvOsvCMU1Dby5v4AbzhtHuAs/jBJGBDM8xJ99pyu5\n4bxxLpPbHzS3tnHPy3t492ARiyaP4hsz47h0yiiiQr0rgazBsxh6a3AvpK1NOVJUY1x9buD2hRNo\nbVN+88Gxbvu9tOMUza3KTee71pCICGkJkecyqnsqTS1t/Psre3n3YBE/vnoKz90yl3suTWFqrOev\n/gyejTFSXsDpirOcbWplypgwd6sy5Bg7MoSbz0/k1d2nz+0LdqS+qZW/bj/V58O7XTEjPpJjZ2qo\na2xxuey+0tam/HNvPpf95hPePlDIj6+eYg6aG1yKMVJewOFC26b55NFmJeUOVi9KJjzIn1+8e6TT\n57//+DiltY3829eS+2X+mQkRtCkczPeM1ZSqsvHQGR74+34WPvYx/++VvQwL9OOFW+caA2VwOcZI\neQGHC6vxEVshPMPAExkSwA8WJfPpsRKe+TT7S8+yimt55tMcvjU7rt9ysKXFR+Ij8PHRgTs43hXN\nrW3c//oBvv+XDN7aV8i0uHB+t2oWb//gQi6ZNMrd6hkGIU4FThjcy5GiahKjhhEcYNKnuIubL0jk\ni1MV/PydI5TUNPLAlVMQgZ/88yDB/r7811VT+m3ukaGBXJ46mpd3nuKeS5MJCRjY/7YFlfXkVdTT\n2qY8vTmLz46Xsvpryfz7ZSmmxISh3zFGygs4XFjDdC8IPx7M+Pv68OSq2USFZvLsZydYvzsPXx8f\nSmsbeeQb0/o9gu17C5N4L7OI17/I58b5Axfl19TSxtef3EJ5na1CsZ+P8Ng1M8x5H8OAYYyUh1Pb\n2MKp8rNcO8d1Z28MvcPXR/jpsqlMjQ1nX14VbW1K/PBgVs3r/3NAc8YNJy0+gue2nOCGeWPxcdFh\nYUdszymjvK6J/7pqMtPiIoiLDDZpuQwDijFSHk57pgETfu4ZiAjXzx3L9XMHft7bFo7nnpf38PHR\nYi4doHpi72cWERLgy03nJ5ps3Qa3YBzKHk572PNkE34+5Lly2mjGRASx9vOTAzJfW5stiu/iidHG\nQBnchjFSHk5uaR1B/j7ERQa7WxWDm/H39eHSKaPYe6oCW2rM/mXP6UqKaxq5YqprkuUaDL3BGCkP\np6CqntjIYJMOyQDYSspXN7RQUtPouHMf+eBQEX4+wtcmm9Byg/swRsrDKahsIDbCrKIMNlJG2TJa\nHC92vnxIb1BVPsg8w/kTRhIRbBKjGtyHMVIeTkFlPbGRJvO5wUZyjGWkzvRv6Y7jxbWcKK3jcuPq\nM7gZY6Q8mKaWNkpqG4k1+1EGi+jQQCKC/ft9JbV2Wy7+vsIVUwcmitBg6ApjpDyYM9UNqGLcfYZz\niAgpo0L71UgVVzfwWkYeK+bEMyrMrOIN7sUpIyUiS0TkqIhkicj9nTwPFJF11vMdIpJo9+wBq/2o\niFzhSKaIrBGRfSKyX0TWi0hoh7lWiIjalY5fLCK7ReSA9XNRJ/ptEJGDdvf/KyL5IrLXel3lSF93\nUFBZD2BWUoYvkRITSlY/GqlnP8uhpa2NOy+e0G9zGAzO4tBIWeXUnwKuBFKBVSKS2qHbbUCFqiYD\nTwCPWmNTsVXAnQosAZ4WEV8HMu9V1TRVnQGcwlZ5t12XMOAeYIfd3KXAUlWdjq2E/Ysd9P8W0Nn/\n6CdUdab1eqc7fR29R/1FQZXNSI0xe1IGO5JHhVFe10RZresj/CrqmvjbjlMsS4s1mSUMHoEzK6l5\nQJaq5qhqE/AKsLxDn+XAWut6PXCp2GKmlwOvqGqjqp4Asix5XcpU1WoAa3wwYH8g5GHgMaChvUFV\n96hqgXWbCQSJSKAlIxS4DweVezv8Hp3p6xYKKm2/pnH3Gezpzwi/F7blcraplbsu6Z+yIwZDT3HG\nSMUBp+3u86y2TvuoagtQBYzsZmy3MkXkeaAImAw8abXNAhJU9a1udL0G2KOq7V8xHwYeB8520ne1\n5VJ8TkSG9+B3HTAKKusZHuJvsp8bvkRKTP8YqZbWNl7eeYpFk0cxabTJcGLwDJwxUp2dIu143L2r\nPj1tt12o3grEAoeB60XEB5sb8YddKikyFZub8Q7rfiaQrKpvdNL9D8AEYCZQiM2Qdfd7dJzrdhHJ\nEJGMkpL+q/FTWNVg9qMMX2F0eBChgX5kuTgM/bOsUoprGrku3SQzNngOzhipPMA+L388UNBVHxHx\nAyKA8m7GOpSpqq3AOmyrozBgGrBZRHKB+cAGu+CJeOAN4CZVba9Kdz4wx+q/BZgoIpst2WdUtVVV\n24Bn+ZdLz5nfFVV9RlXTVTU9Ojq642OXUVBZzxjj6jN0QERI7ocIv9d35zE8xJ9Fk03YucFzcMZI\n7QJSRCRJRAKwBRZs6NBnA7agBYAVwCa1JRfbAKy0ov+SgBRgZ1cyxUYynNuTWgocUdUqVY1S1URV\nTQS2A8tUNUNEIoG3gQdUdWu7Qqr6B1WNtfpfCBxT1Uss2WPsdP8m0B7515W+biG/sp44EzRh6ARX\nh6FX1TfzwaEzLEuLJcDPnEwxeA4OS3WoaouIrAbeB3yB51Q1U0QeAjJUdQOwBnhRRLKwraBWWmMz\nReRV4BDQAtxtrZDoQqYPsFZEwrG53vYBdzlQcTWQDDwoIg9abZeranE3Yx6z3IEK5GK5CLvTd6Cp\naWimpqHFuPsMnZISE8pru/OoPNtEZEhAn+W9tb+AppY2VswxxQwNnoVT9aSsEO13OrT9xO66Abi2\ni7E/A37mpMw2YIET+lxid/0IDqL3VDUXm7uw/f7Gbvp2qu9AU1hli+wbY4yUoRMmxtgCGw7kV7Ew\npe8u59d35zExJpRpcaZumcGzMOt6D6X9IK9x9xk647ykkQT5+/DhoTN9lnW6/CxfnKrkW7PjTbZ9\ng8dhjJSH0n5GygROGDojOMCXi1Ki+eDQmT7Xlvr0uC1C9bIBqvZrMPQEY6Q8lMKqenx9hFFhge5W\nxeChLE6NobCqgYP51X2Ss+V4KbERQUyINhkmDJ6HMVIeSn5lPTFhgfj5mn8iQ+dcOiUGH7EVJ+wt\nrW3K1qxSLkyJMq4+g0diPgE9lMJKc5DX0D0jhgUwN3EEG/uwL7U/r5LqhhYudEHwhcHQHxgj5aHk\nVZ41kX0Gh1w+dTRHimo4WVbXq/FbjpciAhcmR7lYM4PBNRgj5YEUVTVwuryeabEmHNjQPZen2oId\n3j3YO5ffZ1mlTI0NZ8Swvp+1Mhj6A2OkPJBPj9mirS6eZFwwhu5JGBHC/PEj+N1HxzlS1LMAitrG\nFr44WcGFyebvzOC5GCPlgXxyvISY8EAmxZhM1AbH/N/KWYQG+vG9tRmU1zU5PW5rViktbcpFKcbV\nZ/BcnMo4YRg4WtuULcdLWZwaY6KtDE4REx7EMzelc92fPuf6P31Oamw4YUF+3HHRBBJGhHyl/7Ez\nNfxxczYb9hUwYlgAs8cN70SqweAZmJWUh7Evr5Kq+mYunmhcMAbnmZkQye9WzsTP14e9pyt5LSOP\n776wi7rGli/123u6kmW/38J7mUV8Z/44/nn3AoL8Tb0yg+diVlIexidHS0y0laFXLJk2hiXTbAn+\nt2aVcuOaHfzo9f08uWoWIsKpsrPc9sIuosMCef3OCxgVblJuGTwfY6Q8jE+Pl5AWH8lwE21l6AML\nkqP4jysm8dh7R/H39WF0RBDvHiikVZUXbp1nDJTBazBGyoOoPNvEvtOVrF6U4m5VDIOAuy6eQHZx\nHW/us9XtjAjx59mb0pkQHepmzQwG5zFGyoPYcaKcNsVEWxlcgojw+HVpPH5dmrtVMRh6jQmc8CAy\nC6rxEZgaG+FuVQwGg8EjcMpIicgSETkqIlkicn8nzwNFZJ31fIeIJNo9e8BqPyoiVziSKSJrRGSf\niOwXkfUiEtphrhUioiKSbt0vFpHdInLA+rmoE/02iMhBu/tficgRa443rBL0iEiiiNSLyF7r9Udn\n3h9XcaigmvHRoQQHmGgrg8FgACeMlIj4Ak8BVwKpwCoRSe3Q7TagQlWTgSeAR62xqdhKyU8FlgBP\ni4ivA5n3qmqaqs4ATmErD9+uSxhwD7DDbu5SYKmqTgduBl7soP+3gNoO+m4EpllzHAMesHuWraoz\nrdedjt4fV3KooIqpJhWSwWAwnMOZldQ8IEtVc1S1CXgFWN6hz3JgrXW9HrhUbCdRlwOvqGqjqp4A\nsix5XcpU1WoAa3wwYF/R7WHgMaChvUFV96hqgXWbCQSJSKAlIxS4jw7l5VX1A1VtP0CyHYh34n3o\nVyrqmiioaiB1jDFSBoPB0I4zRioOOG13n2e1ddrH+vCvAkZ2M7ZbmSLyPFAETAaetNpmAQmq+lY3\nul4D7FHVRuv+YeBx4Gw3Y74LvGt3nyQie0TkExFZ2NkAEbldRDJEJKOkpKQb0c5zuNCWdy3VrKQM\nBoPhHM4Yqc5y83SsV91Vn5622y5UbwVigcPA9SLig82N+MMulRSZis3NeId1PxNIVtU3uhnz30AL\n8DerqRAYq6qzsK3AXhKRr1gNVX1GVdNVNT062jWZITILLCNlVlIGg8FwDmeMVB6QYHcfDxR01UdE\n/HXaaw0AAArySURBVIAIoLybsQ5lqmorsA7b6igMmAZsFpFcYD6wwS54Ih54A7hJVbMtEecDc6z+\nW4CJIrK5Xb6I3Ax8HbhBVdWas1FVy6zr3UA2MNHB++MSDhVWMzo8iJGhply8wWAwtOOMkdoFpIhI\nkogEYAuE2NChzwZsQQsAK4BN1gf/BmClFf2XBKQAO7uSKTaS4dye1FLgiKpWqWqUqiaqaiK2faRl\nqpphRea9DTygqlvbFVLVP6hqrNX/QuCYql5iyV4C/MiScc4VKCLRVlAHIjLe0jfHifeozxwqqDau\nPoPBYOiAw8O8qtoiIquB9wFf4DlVzRSRh4AMVd0ArAFeFJEsbCuoldbYTBF5FTiEza12t7VCoguZ\nPsBay8UmwD7gLgcqrgaSgQdF5EGr7XJVLe5mzO+BQGCjlWl8uxXJdxHwkIi0AK3Anar6/7d37zFS\nlXcYx78PiyKKuuCFALstGGgteINuDLamMdoqeGFNa1OMicSS2DQarTVpIcY/WvtH7c3WVmmMNzRG\ntFTrxl4NapqagC61Iojoeqm7grKGBaXLxcVf/zjv2nGZGyCcM/b5JJOZ886Zs8++s8OP8847826q\n1Uf7avv7u+jq3crZ08bu7x9lZtZQlEa6bC+1tbVFZ2fnPh1jVc9m5vzmKRZdMoPZJ477mJKZmRWX\npJUR0VZrP3/jRAG8kCZN+JsmzMw+ykWqANasf5fDRwynZfTIvKOYmRWKi1QBdG3cyuSxoxg2zCvx\nmpmVcpEqgJ7N/XyqzDLfZmb/71ykcjaw6wPWb95O62gXKTOzoVykcrZhy3Z2fRB+P8rMrAwXqZz1\n9G0DoNXDfWZmu3GRyll3X/aFFx7uMzPbnYtUzno29TNMMK75kLyjmJkVjotUznr6tjHuyJEc1OSn\nwsxsKP/LmLPuvn5PmjAzq8BFKmfdm7bR4vejzMzKcpHK0Y6BXbz93nZax/hMysysHBepHK3fvJ0I\nz+wzM6vERSpH3Zuy6ed+T8rMrLy6ipSkWZLWSeqStKDM/SMkPZDuXyFpYsl9C1P7Oknn1DqmpDsk\nPSdplaSlkkYN+VkXSYqSpeO/ImmlpOfT9Zll8nVIWl2yPUbSY5JeTtejU7sk3ZwyrZI0o57+2Vsf\nfkbKH+Q1MyurZpFKy6nfAswGpgIXS5o6ZLf5QF9ETAZuAm5Mj51KtkrvNGAWcKukphrHvCYiTo6I\nk4A3yFbeHcxyOHAVsKLkZ78DXBARJ5ItYX/vkPxfBbYOybsAWBYRU4BlaZuUZ0q6XA4sqtU/+6Kn\nbxsHNYmxR/gzUmZm5dRzJnUq0BURr0bETmAJ0D5kn3Zgcbq9FDhL2brs7cCSiNgREa8BXel4FY8Z\nEe9CdlYDjARKlw6+AfgJsH2wISKejYj1aXMNcIikEekYo4DvAj+qkncxcGFJ+z2RWQ40S9pvS+V2\nb+pnfPNImrxEh5lZWfUUqQlAd8l2T2oru09EDABbgKOqPLbqMSXdBbwFHA/8OrVNB1oj4tEqWb8G\nPBsRO9L2DcDPgf4h+42NiA0p7wbg2D34XT823X3bPGnCzKyKeopUuf/mR5377Gl7diPiMmA8sBb4\nhqRhZMOI11YMKU0jG2b8Vto+BZgcEQ9Xeky5w1TLVfKzLpfUKamzt7d3Dw7/UW/29Xv6uZlZFfUU\nqR6gtWS7BVhfaR9Jw4EjgU1VHlvzmBGxC3iA7OzocOAE4ElJrwMzgY6SyRMtwMPApRHxSjrEacDn\n0/7/AD4j6cl039uDw3jpeuMe/K5ExG0R0RYRbcccc8zQu+vSv3OAd7bu9Ad5zcyqqKdIPQNMkTRJ\n0sFkEyE6huzTQTZpAeAi4PGIiNQ+N83+m0Q2IeHpSsdMs+smw4fvSV0AvBgRWyLi6IiYGBETgeXA\nnIjolNQM/BFYGBFPDQaKiEURMT7tfzrwUkScUSbvPOCRkvZLU46ZwJbBYcGP27adu5hz8nhOajly\nfxzezOwTYXitHSJiQNKVwF+BJuDOiFgj6YdAZ0R0AHcA90rqIjuDmpseu0bSg8ALwABwRTpDosIx\nhwGLJR1BNvT2HPDtGhGvBCYD10u6PrWdHREbqzzmx8CDkuaTzSD8emr/E3Au2QSPfuCyWv2zt44a\nNYKbL56+vw5vZvaJoOyEx/ZWW1tbdHZ25h3DzKyhSFoZEW219vM3TpiZWWG5SJmZWWG5SJmZWWG5\nSJmZWWG5SJmZWWG5SJmZWWG5SJmZWWH5c1L7SFIv8O99OMTRZMuNNCrnz08jZwfnz1ve+T8dETW/\nV85FKmeSOuv5QFtROX9+Gjk7OH/eGiW/h/vMzKywXKTMzKywXKTyd1veAfaR8+enkbOD8+etIfL7\nPSkzMyssn0mZmVlhuUjlRNIsSeskdUlakHeeWiS1SnpC0lpJayRdndrHSHpM0svpenTeWauR1CTp\nWUmPpu1Jklak/A+kRTgLSVKzpKWSXkzPw2mN1P+Srkl/O6sl3S/pkCL3v6Q7JW2UtLqkrWx/p4VS\nb06v51WSZuSX/MOs5fL/NP39rJL0cFo0dvC+hSn/Oknn5JN6dy5SOZDUBNwCzAamAhdLmppvqpoG\ngGsj4nPATOCKlHkBsCwipgDL0naRXQ2sLdm+Ebgp5e8D5ueSqj6/Av4SEccDJ5P9Hg3R/5ImAFcB\nbRFxAtlip3Mpdv/fDcwa0lapv2eTrTw+BbgcWHSAMlZzN7vnfww4ISJOAl4CFgKk1/JcYFp6zK3p\n36ncuUjl41SgKyJejYidwBKgPedMVUXEhoj4Z7r9Htk/kBPIci9Ouy0GLswnYW2SWoDzgNvTtoAz\ngaVpl8LmT6tVf4lsFWwiYmdEbKaB+p9sJfCRkoYDhwIbKHD/R8TfyVYaL1Wpv9uBeyKzHGiWNO7A\nJC2vXP6I+FtEDKTN5UBLut0OLImIHRHxGtnq5KcesLBVuEjlYwLQXbLdk9oagqSJwHRgBTA2IjZA\nVsiAY/NLVtMvge8BH6Tto4DNJS/aIj8PxwG9wF1puPJ2SYfRIP0fEW8CPwPeICtOW4CVNE7/D6rU\n3434mv4m8Od0u7D5XaTyoTJtDTHNUtIo4PfAdyLi3bzz1EvS+cDGiFhZ2lxm16I+D8OBGcCiiJgO\n/IeCDu2Vk967aQcmAeOBw8iGyIYqav/X0kh/S0i6jmwI/77BpjK7FSK/i1Q+eoDWku0WYH1OWeom\n6SCyAnVfRDyUmt8eHNZI1xvzylfDF4E5kl4nG149k+zMqjkNP0Gxn4ceoCciVqTtpWRFq1H6/8vA\naxHRGxHvAw8BX6Bx+n9Qpf5umNe0pHnA+cAl8b/PIBU2v4tUPp4BpqSZTQeTvWHZkXOmqtL7N3cA\nayPiFyV3dQDz0u15wCMHOls9ImJhRLRExESy/n48Ii4BngAuSrsVOf9bQLekz6ams4AXaJD+Jxvm\nmynp0PS3NJi/Ifq/RKX+7gAuTbP8ZgJbBocFi0TSLOD7wJyI6C+5qwOYK2mEpElkE0CeziPjbiLC\nlxwuwLlks2teAa7LO08deU8nO/1fBfwrXc4le19nGfByuh6Td9Y6fpczgEfT7ePIXoxdwO+AEXnn\nq5L7FKAzPQd/AEY3Uv8DPwBeBFYD9wIjitz/wP1k75+9T3amMb9Sf5MNl92SXs/Pk81iLGL+LrL3\nngZfw78t2f+6lH8dMDvv/IMXf+OEmZkVlof7zMyssFykzMyssFykzMyssFykzMyssFykzMyssFyk\nzMyssFykzMyssFykzMyssP4LdjhdskO0C6YAAAAASUVORK5CYII=\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZ0AAAD8CAYAAACsAHnpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvXl4XHd97//6zIxmkTSj0b5YsuV9TZw4JmQFkxAIS0gv\nBAhtgVLuhbakFEr7FMoN/RWS20J7f23JBUralJtLb0nStLQmoaRtQiAJiRM7jh2vsbzJlqx9GY2k\n2b/3jzNnPJZnlWa1v6/nyeOZM+ec+c5kdN7ns4tSCo1Go9FoSoGl3AvQaDQazeWDFh2NRqPRlAwt\nOhqNRqMpGVp0NBqNRlMytOhoNBqNpmRo0dFoNBpNydCio9FoNJqSoUVHo9FoNCVDi45Go9FoSoat\n3AuoNFpaWlRvb2+5l6HRaDRVxZ49e8aUUq3Z9tOis4De3l52795d7mVoNBpNVSEip3PZT7vXNBqN\nRlMytOhoNBqNpmRo0dFoNBpNydCio9FoNJqSoUVHo9FoNCVDi45Go9FoSoYWHY1Go9GUDC06Gk2Z\nmJwN8cO9Z9Ej4zWXE1p0NJoy8cO9A3z+0X282j9V7qVoNCUjJ9ERkdtF5KiI9InIF1O87hCRR+Ov\n7xKR3qTXvhTfflRE3pntnCLykIjsE5H9IvK4iNQveK+7RESJyPb489tEZI+IvB7/95akfe0i8qCI\nvCEiR0TkA/l8ORpNMRn2BQD40b7BMq9EoykdWUVHRKzAt4B3AZuAj4jIpgW7fRKYVEqtAf4C+Hr8\n2E3A3cBm4Hbg2yJizXLOzyultiqlrgT6gXuS1uIGPgvsSnrvMeAOpdQVwMeB7ye99mVgRCm1Lv4+\nP8v2eTWaUjE6EwTgif2DRKKxMq9GoykNuVg61wJ9SqkTSqkQ8Ahw54J97gQejj9+HLhVRCS+/RGl\nVFApdRLoi58v7TmVUj6A+PEuINnh/TXgG0DA3KCU2quUMm8VDwJOEXHEn/868Cfx/WJKqbEcPq9G\nUxJGZoJYLcKYP8SLJ8bLvRyNpiTkIjrLgDNJz8/Gt6XcRykVAaaB5gzHZjyniHwPGAI2AA/Et10N\n9Cilnsiw1g8Ae5VSQRHxxrd9TUReFZF/FJH2VAeJyKdEZLeI7B4dHc1weo2mcIzMBLhpTQtuh42d\nr2kXm+byIBfRkRTbFqbbpNsn3+3GA6U+AXQBh4EPi4gFw233hbSLFNmM4db7dHyTDegGXlBKbQNe\nBP481bFKqQeVUtuVUttbW7N25tZoCsLoTJCeJhfv2NzBTw4MEQhHy70kjabo5CI6Z4GepOfdwMLb\nssQ+ImIDGoCJDMdmPadSKgo8imG9uIEtwLMicgq4DtiZlEzQDfwQ+JhS6nj8FOPAXHw7wD8C23L4\nvBpN0QlFYkzOhWlzO7nzqi5mghGePaqtbM2lTy6i8wqwVkRWiogdIzFg54J9dmIE8QHuAp5RRvHB\nTuDueHbbSmAt8HK6c4rBGkjEdO4AjiilppVSLUqpXqVUL/AS8D6l1O64G+1J4EtKqRfMBcXf/0fA\njvimW4FDuX81Gk3xGPMbSQStbgc3rG6mpd7Ozn0DZV6VRlN8sg5xU0pFROQe4CnACvydUuqgiHwV\n2K2U2gk8BHxfRPowLJy748ceFJHHMC72EeAzcQuGNOe0AA+LiAfDBbcP+M0sS7wHWAPcKyL3xre9\nQyk1AvxBfF1/CYwCn8jta9FoistIPHOtze3AZrXwnis6eeSVM/iDEeoderai5tIlp1+3UurHwI8X\nbPtK0uMA8ME0x94P3J/jOWPAjTmsZ0fS4/uA+9Lsdxp4S7bzaTSlZiReo9PmdgJw09pWHn7xNH0j\nfq7q8WY6VKOpanRHAo2mDIwmudcA2j3Gv6YYaTSXKlp0NJoyMOILIgLN9XbgvMVjut00mksVLToa\nTRkYmQnSVGunxmr8CbbU2xHRoqO59NGio9GUgdGZYMK1BmCzWmiuszM6o91rmksbLToaTRkYnQnQ\n5nFesK3V7WTEpy0dzaWNFh2NpgyMzARprXdcsK3N7dDuNc0ljxYdjabExGKKMX+QNk8q0dHuNc2l\njRYdjabETM2HCUcVbe4FouNxMOYPEY3pSaKaSxctOhpNiTGtmdaFouN2Eo0pJmZD5ViWRlMStOho\nNCVmNNEC58JEAtPy0S42zaWMFh2NpsSYGWqp3Guga3U0lzZadDSaEmOKSir3GsCoTpvWXMJo0dFo\nSszoTJA6u5W6Bd2kW7V7TXMZoEVHoykxIzOBi6wcAGeNFY/Tpt1rmksaLToaTYkZnQlelERg0ubR\nXQk0lzZadDR54Q9G+OnRkXIvo6oZnQnS6rnY0gFdIKq59NGio8mLr/7oIJ/43isM67kviyZVCxwT\n3QpHc6mjRUeTM8eGZ3h8z1kA+ifmyrya6mQuFMEfjFzUAsekzeNkZCaIUpXVlWBiNsSDPz+uuyVo\nlowWHU3O/NlTRxERAM5o0VkU6QpDTdrcDkKRGL75SCmXlZXH95zhf/z4CLtOjpd7KZoqR4uOJide\n7Z/k3w8N8xtvXQXAmYn5Mq+oOklXo2NSqWnTBwZ8ADx7dLTMK9FUO1p0NFlRSvH1fztCS72d39qx\nhnaPgzOT2tJZDOctnXQxncocW31gYBqAZ3USiWaJaNHRZOXnx8bYdXKC375lLXUOGz2NtZzVorMo\nRuIJGGlFx1N5ls5MIMyJsVla3Q7eGPYzMKWtXM3i0aKjycrP3xjFWWPhI9cuB6CnqVa71xbJxGwI\nEWistad8PdH0s4JqdQ4NGq61T91suFa1taNZClp0NFk5OzlHd2Mtdpvxc+ludHFuep5wNFbmlVUf\nM8EI9XYbFoukfL3eYcNVY60o99qBuOjceXUX3Y0uHdfRLAktOpqsnJ2cp7vRlXje01hLTMG5qcpx\nAVUL/kCEeqct7esiQpunsmp1DgxM0+5x0OZ2smN9Ky/0jRGMRMu9LE2VokVHk5Wzk/P0NNYmnnc3\nueLbdVwnX/zBCO4MogPxAtEKKr49MDDNlq4GAHasa2MuFGX3qckyr0pTrWjR0WTEFwgzPR++yNIB\ndAbbIpgJRKh3ZBMdZyLLrdzMhSIcH/WzZZkhOjesacZutfDTIzquo1kcWnQ0GRmYNBIGupMsnc4G\nJ1aL6GSCRTATjFDvrMm4T2sFtcI5fM5HTJEQnVq7jTevauLZN3RcR7M4tOhoMnI2ITrnLR2b1UJn\ng1NbOovAHwjjzmbpeBz4gxFmg+XvSvD6WaM+54q46ADsWN9G34hfu1c1i0KLjiYjZrubZNExn5uC\npMmd3GI6lVMgemDQR0u9nfakXnFbuw0B6hvxl2tZmipGi44mI2cn53HVWGmqu7CupKexVvdfWwS5\nxHQ6GwzRqYTv98DANFuWNSR67gEsi9+A6CJRzWLQoqPJyNnJOXqaXBdcdMAoEB2ZCRII69TZXInG\nFHOhaMaUaYCtPV5sFuHFE+VtrhkIRzk24k9krpm0uZ3YLJKI92mys+f0JL/9g726tg0tOposGDU6\ntRdt70mkTesLT6744zGabJZOvcPGthWNPHesvMH6w+d8RGOKLcs8F2y3WoSOBieD2tLJCaUU9z95\niB/tG+SVkxPlXk7Z0aKjyYjRjcB10XZTiHQwOXdM0ckW0wG4eU0LBwZ8jPvLF9c5dM7oRLB5gaUD\nsMzr0u61HHnl1CSv9k8B8LRONdeio0nP9HwYXyCSUnTO1+qU58KjlCIUqS5XxUwgDIA7S8o0wM3r\nWgF44Xj5XGxD0wFEoMt78f//ZY0u7V7Lke8820dznZ03r2zimQyic2Bgmhv/9BmODPlKuLrSo0VH\nk5ZUNTombW4HdquFs2UIdr8xPMN7vvk87/nmcxU3YTMT/kBu7jUwUpQbXDU8V8Z6mPHZEI21dqwp\n+sR1e10M+QI6RpGFw+d8/PToKJ+4sZf3XNnJybFZToxenPUXjsb4/cf3MzA1f8n3ttOio0mL6TpL\nZelYLMKyRldJa3ViMcX3XjjJex94njeGZzg24ufI0EzJ3n+pzJgxnRzca1aLcOOaZp47NlY2YZ3w\nhy7KWjTp8rqIKRiuoHY9lch3nj1Ond3KR6/r5W3r2wBSWjsP/vwEh8/5cNgsvBZ3xV2qaNHRpOVs\nBkvH2O4qaVeC/+9HB/njHx3ipjUt/Os9NwLVNcnStHSyFYea3Ly2lSFfoGz1MBOz6UUnkTatXWxp\n6R+f44n9g/zqdStoqK2hp6mW9e1unj58oegcH/XzV08f411bOnjn5g72ndWig4jcLiJHRaRPRL6Y\n4nWHiDwaf32XiPQmvfal+PajIvLObOcUkYdEZJ+I7BeRx0WkfsF73SUiSkS2x5/fJiJ7ROT1+L+3\nJO37bPw9Xov/15bPl3O5c2Zyjjq7lcba1DGInqbSDXM7Mern7186zS+/eTkPfXw7m7sa2NjpqarZ\nLjOm6OQQ0wG4aU0LAM8dGyvamjIxPhukOZ3oeHWtTja+94uTWC3Cr9+0MrHtlo1tvHJqgul5I74X\niym+9M+v47RZ+OM7N7O1x8u56cAlbUFmFR0RsQLfAt4FbAI+IiKbFuz2SWBSKbUG+Avg6/FjNwF3\nA5uB24Fvi4g1yzk/r5TaqpS6EugH7klaixv4LLAr6b3HgDuUUlcAHwe+v2Btv6KUuir+X/VcoSoA\nM116YY2OSXeji8m5cCIrq5h88+ljOGxWPv/2dYn17Fjfyu7Tk/jiAfpKxx801pmLew0MUV/VUle2\n1OnJuXBG9xqg06bTEAhH+eHeAd65uYN2jzOx/e0b24jEFM8dGyUSjfHlf3mdl09O8OX3bKTN7eSq\nHi8Ar525dK2dXCyda4E+pdQJpVQIeAS4c8E+dwIPxx8/DtwqxpXhTuARpVRQKXUS6IufL+05lVI+\ngPjxLiDZof014BtA4jZAKbVXKTUYf3oQcIpI6lnAmrxYOEdnIaVKmz42PMO/7hvkYzesoDVpzPPb\n1rcRjSleKJMlkC/+QAQRqK2x5nzMTWtbeOnERMnn10Rjism5UFpLx1ljpaXeri2dNPz7oWGm5sLc\n/ablF2y/qqeRxtoantx/jt/4+1f5wctn+MzbVvOh7T0AbO7yYLPIZS86y4AzSc/Pxrel3EcpFQGm\ngeYMx2Y8p4h8DxgCNgAPxLddDfQopZ7IsNYPAHuVUsnFDd+Lu9bulXS37JqUpKvRMemKt2s5N11c\nV8BfPn2M2horn37L6gu2b1vuxe20VU1cJ9vU0FTcvLaV+XCUvSUOLk/NhVCKtJYOGC42XRycmkde\n7qe70cUNq5sv2G61CG9b38a/HRji6SPDfPXOzfz+OzckrHdnjZWNnR72Xeaik+ovZGE6Tbp98t1u\nPFDqE0AXcBj4sIhYMNx2X0i7SJHNGG69Tydt/pW42+3m+H8fTXPsp0Rkt4jsHh2tjgtYsZmeDzMT\niKRNIgDojLtYhoooOkeGfDy5/xyfuHHlRRdAm9XCzWtb+Nkbo1WROj0TyN7scyFmN4BSJxNMzIYA\naKpP7zTo8rq0ey0Fp8dn+cXxcT68vSflDcb7t3XT4KrhW7+8jY9d33vR61f1eNl/dpporPJ/04sh\nF9E5C/QkPe8GBtPtIyI2oAGYyHBs1nMqpaLAoxjWixvYAjwrIqeA64CdSckE3cAPgY8ppY4nnWMg\n/u8M8A8Ybr2LUEo9qJTarpTa3tramuGruHzIlC5t0uZ2IFJcS+c7zx7H7bDxX29emfL1HevaGPIF\nqiJ1Otuo6lS0uZ3UWKXkYyTG46KTzr0G57sSVIPgl5LHdp/BInDX9u6Ur9+0toXXvnIb776iM+Xr\nW3u8+IORlPU8lwK5iM4rwFoRWSkidozEgJ0L9tmJEcQHuAt4Rhm/xJ3A3fHstpXAWuDldOcUgzWQ\niOncARxRSk0rpVqUUr1KqV7gJeB9SqndIuIFngS+pJR6wVyQiNhEpCX+uAZ4L3Agz+/nsiVbujRA\njdVCa72Doeni3e0eGJjmxjUteGtTX/zeut64SfhpFWSx+YPZO0wvxGqRsrixEpZOJtFpdBEIxxL7\naiASjfGPu8+yY30bnQ3pb9gyefrNZIK9l6iLLavoxGM09wBPYbi7HlNKHRSRr4rI++K7PQQ0i0gf\n8LvAF+PHHgQeAw4BPwE+o5SKpjsnhtvtYRF5HXgd6AS+mmWJ9wBrgHsXpEY7gKdEZD/wGjAA/E1O\n38plRDSWup2MeZEzG3umo7PBWTRLRynFwNR8oiYkFe0eJ5s6PVUR18llamgquhtrS975IRdL53wG\n26Wb3psvzx4dZWQmyN1v6sm+cxpWtdThdtou2WSCnG67lFI/Bn68YNtXkh4HgA+mOfZ+4P4czxkD\nbsxhPTuSHt8H3Jdm12uynety5wuPvcbpiTn+6TduuMD//NqZKdxOGw2uzBfJjgYnJ0Zni7K2idkQ\ngXAsUROSjpvXtfDQcycJRqI4bLlnhpWamUA4o7syHT1NLv79YGn7cU34DdFpzOJeAxiYmuOK7oub\ngl5uKKX4658dp83t4G0bFl8SaLEIW7u9l2wyge5IUCYGp+b5aQV0nN3TP8ne/il27jsfUjt8zscT\n+wf55WuXZ3QDAHQ2uIqWSGCm42aydMDoghyJqaKJX6HwByI5dyNIpruxlvHZUEnHV0/MBvE4bdRY\n018iTAHVGWwGTx0cZvfpST739nUZv7dcuKrHy5GhGeZDl968Ki06ZeKBZ47x6w+/UtaRv4FwNHHB\n+LOnjiYGsv3ZU0dxO2z85o7VmQ4HDEtnJhhJdFAuJGaLlWyWzvp2NwBHKzyZYDExHTh/cS9lTcz4\nbIjmDJlrAA2uGmrtVl2rA4QiMf703w6ztq2eD6VJIMiHrT1eojHFgcHpAqyustCiUyb2nJ5EKfju\nz45n37lIHB/1oxT88puXMzA1z9+/dJqXTozzzJERfutta9IG75MxRysXo22HeTHryZDMALCypQ6b\nRTg6XLmik+vU0FSYyRylHF+dqe+aiYiR5KDTpuEfdp3m1Pgcf/jujdiWaOUAbF/RiLPGwv958XQB\nVldZaNEpA75AmGMjftwOG//y2kDZ/mhNK+vj1/dy89oWHnimj/uePESHx8mv3dCb0znMDJ1iBJPP\nTs5T77DhcWW+UNttFla31vNGBVs6/jz7riVTjimtuYgOxOfqXOai4wuE+aunj3HD6mZ2rC9MyUVj\nnZ1P3byKH+0bZM/pyYKcs1LQolMGXuufQin47+/dSEzBQ8+fLMs6+kb8WAR6W2r54rs24AuEOTDg\n43dvW4czx1YtpqVTjLjOwNQ8y7yurHElgHUd7oqu1ZmJ911bTEyntd6Bw2YpqaUzPhuiKQdLd5lX\nD3P725+fYGo+zB++e2NOv9Vc+fRbV9PmdvC1Jw4Ru4QKRbXolIE9pyexCLz7ik7u3NrFD17uZ7IM\ntQ59I35WNNfhsFnZ3NXAJ25YyZt6G3n/toVdjtLT5jH8/sVImx6YzJwuncz69noGpuaLElsqBP48\nZuksRETobixdrY5SisnZEE312UWny2s0fZ0LlS7JodJ4tX+KK7u9bFlW2Ay+OoeN33/nel47M8WP\n9i+sx69etOgUiP7xuZwzTV7tn2Rduxu3s4bf2LGauVCUh188VdT1paJvxM/q1vOTI75yxyYe+/T1\nefmkHTaj8eOQr/AXRNPSyYX1HUa7mGNlTMzIRD5TQ1PR01Rbsq4EvvkIkZjKWKNjYiY5XM5xncGp\nzI1xl8IHtnWzZZmHr//bkUsmk02LTgEIR2N8/Hsv84Hv/CJrx+VYTPFa/xTbVjQCsK7dzds3tvO/\nf3GKSAlH/0aiMU6Nz7Km7YJxRYtyD3RkKBANhKP87qOvcTzPlh4zgTDT8+E8LJ3KzmAzp4bm23vN\npJSWzvis0S83p5iO9/JOm04UMOd4c5QvFotw73s2MTgd4EPffZEXj48X5X1KiRadAlBjtXDvezdy\nZnKOOx54nl/0pW+1f2zEz0wwwjXLGxPb3rKuham5MJNzpXMNnZ6YIxxVF4nOYujwpK/VefnkBP+8\nd4An95/L65yJGp0c/5i7G13U2q2VKzqBpYlOT2Mt0/PhkswOyqUFjonZlaDYncYrlYnZEMFILNFx\nvRi8eVUzf3X3VYz7g3zkb17ik//7FUZngtkPrFC06BSIWza0s/Oem2iud/DRv3uZf9pzNuV+r/Yb\nmSimpQMkUpOn50sX1zEz1wohOpla4ew6adyZHRrMr6I+UaOTo6VjsQhr2928UaFp0+fda/lnr0HS\n7KISjAc/3wIn+1iqNrcDq0UuW/eambXZVSRLx+TOq5bxzO/t4A9u38AzR0f4/ounivp+xUSLTgFZ\n2VLHv3zmRjZ2unnw5ydS7vPq6Uma6uz0Np+vPfHGW81MldDSMUVndWvdks/V6XUyPZ86mLzrxAQA\nh87lKTrxi1h3Hn/M69vrK9bSyXdq6ELMtOlSxHXOjzXIbunYrBY6PM7LNm3a/NzFFh0wZu385o7V\nNNXaGaviJqtadApMvcPGW9e1cnzUn3La46v9k1zd470gduKtNUSnlO614yN+Ohuci6obWUi6tOlA\nOMq+s1PU2q30T8zllVk2MDmP3WqhJUtVfDLrOzyMz4YY81ee68GcGlpnX1xvuPNTWot/cZ/Iodln\nMp0NzsvY0snPDVwIGlw1TM9XZpZmLmjRKQIbOjxEYopjwxcGz6fmQhwfnb3AtQbgddkTr5eKYyP+\ngrjWwIjpwMV+/Vf7JwlHFR/YZrQFyaeO5uzUPF1eZ15TNs1kgkosEvUFjBY4i63jaKytoc5uLUmt\nzsRsiFq7NedaLWOY2+UZ0xmcmsdVY03cOJaChtoafFp0NMls7DTSdw8vcCmZI4e3Lb9QdBriP9hS\n3b3EYorjoxemSy+FzjRjq3edmMAi8LHrVwD5xXXyqdExWddhfJ5KLBL1BxfX7NPEqNWpLZmlk0sS\ngUmX18W56flLqoAxVwanjZujQhaFZqPBVVNSV3yh0aJTBFa21OGssXD43IUXv1f7J7FahK09FxaR\neZw2rBYp2Q/pnC/AXChaOEsn4V678IK46+Q4m7o8rGmrp6nOnp/oTM3T7c3cc20hrfUOmursFZlM\nsJipoQvpaXJlTckvBOOzoZxdawDLvE7CUVWRbs1iMzAVKEk8Jxmvdq9pFmK1COvb3RwZuvAiu+vE\nBJu7PNTaL7z4iIhx91Ki7LVCZq6BEeBsrK25wNIJRqLs7Z/izSubERE2dXpyTiYIhKOMzgTztnRE\nhHXt9RXZ+NMfjCw5fmZaOsUeDz0xG8zb0gEYvAzTpgeLWKOTDsPS0YkEmgVs7PRw+JwvcYGYC0XY\ne2aSG1a3pNzf66opWSJBoUUHoGPBXJ19Z6YJRmK8eWUTAJu6PBwdniGcQwGsKV6L+WNe3+7mjaGZ\ninP1zATCi+5GYNLd6MIfjBTdIp7wh2jKIV3a5PwE0csrmSAYMW6OSm3pNNTamQlGKu43nitadIrE\nxk4Pk3Nhhn2Gy+GVU0ZQ/YbVzSn3b6itYbqEouOtrcnLhZKNrgW1OrtOjCMC15qi0+khFInlNGgt\n3xqdZDZ1eZgNRTk5XlkD3YxR1Ut1rxU/g00pFZ+lswhL5zITHfMmq+Si46pBqfMFx9WGFp0isTCZ\n4BfHx6ixCtt7G1Pu31hrL5l77fionzWt9QUNfnY0OBlKmqmz6+QE69vdicLXTV3G93HoXPahVANT\nRtxiMZbONfHMwD2nKqsd/GKnhiZj9vcqZq3OXChKMBLLy73mcdqod9gqslZnLhTh28/2JQYUFpLz\nNTrF60aQCnOEfKmuF4VGi06RWN9hpO+acYwXj49zdU/jRfEcE28JM1IGp+YTd82ForPBycRsiEA4\nynwoyp7Tk1y36rxVt6qlDrvt4uSKVAxMzmOR8wkK+bCqpR5vbU3FzSBZ7NTQZMzZRcUYmGeSTwsc\nExGp2FqdH7x8hm/85GhRepaZaeKljumYxeTVmkywtL8CTVoaXDUs87o4fM7H9FyYAwPT/PYta9Pv\nX1sa0VFKMeILJkYSFIqO+AXx43/3MvvPTjMfjvLWdecHWtmsFta3u3PKYDs7NU+Hx7moOfMWi7Bt\neSN7+itHdCLRGHOh6JITCRpcNVjkvDAUg/E8C0NNKrFWRynFo6/0A8UZ9W2K7GJujpaCWWJRrWnT\n2tIpImYywUsnx4kpuHFN6iQCMApE/cFIToH2pTA1FyYUjdHuLuwfysZOw7IbmQnyoe3d/J9fv5a3\nbWi7YB8zgy1b9tVianSSuWZFI30j/orJ8JkNGq6dpcZ0rBbBW2svquhM5NFhOpmuChxb/dqZKd6I\nF2gXS3Ra3Q4ctsV1mVgs2tLRpGVTp5tnjgzz0yMjOGssXNXjTbuvN6lANJ/WL/kyPGPcjbZ7Cis6\nm7saOPK12zNWsW/q8vDo7jMM+4IZ7w4HpuYTsZnFYB77av8kt2xoX/R5CsVSpoYupKmuuKIz7s+9\n2Wcyy7xOxuPu1Vw7GRSbR185g6vGSp3DVhRBHJiaL3kSASTHdKpTdLSlU0Q2dnqIKfiX1wZ4U28T\ndlv6r9tbIpPZzKZrL7B7Dch6scklmSAaUwxNB5bkJ9/a7cVmEXYnJRMopTgwMF30GpdULGVq6EKa\n6uwJF1gxyKfZZzKVlsE2G4zwo32DvPfKTla31hVlXUaNTmldawCeuOhUayscLTpFxMxgC4Rjaetz\nTEo13sAMQhfa0skFM7ni6FD6gW6jM0EiMbWkO0iX3crmLs8FyQT/+xeneO8Dz/Odnx1f9HkXy1Jn\n6STTXGRLZ2IuhN1qybsx6XnRqYy4zpP7zzEbinL3tT0s87oSafiFQinF4FSArobSWzrOGivOGkvV\nute06BSR5U211Mb/eNPV55iYftrJ2eL+kEbiotPqLp4LLx0eZw1up+2idjnJ5Du8LR3bVjSy7+wU\n4WiMQDjKd549To1V+POnjvLzN0aXdO58Weqo6mSK7V6bmg3jra3JO51+WaIrQWVYOo+80s/q1jq2\nLW9kWaOLIV+goJN5p+bCzIejZXGvQXV3JdCiU0QsFmF9hxu308aWZQ0Z902414p89zLsC+KtrSmb\n371zQT24E2SaAAAgAElEQVTPQs5NF2Y+yTUrGgmEYxwa9PGDl/sZmQny3Y9ew7p2N7/9g70l6dZs\nstRR1ck019mZnAsRLVI1+uRciMba/IuG2z1ORCrDvdY3MsOr/VPc/abliAhdXhcxBcMFnLZZyjk6\nqfC67NrS0aTms7es5Y/u2Iw1S4t+071W7LuXYV+g4Jlr+bCwXc5CBgtUcGcmE/zi+DjfefY4b17Z\nxC0b2vnuR69BKcWnvr+nKAWDqVjq1NBkGuvsKFW8zKWpufCi2vTbbRba3I6KEJ1X4rG827d0AMWJ\nN5Vjjk4y1dxpWotOkXnbhjbuuqY7635uhw2LFD8NctgXKHiNTj50eBxpR1uDERNwO21LrmnpbHCx\nzOvifz1zjJGZIL/zdqNGakVzHV//wJUcPucrmZvNHF5XCEvHTGU2U5sLzWItHTC+80qI6Zwen6PG\nKgmxMYWhkHGdQt0cLZaG2urtNK1Fp0KwWKQkdy/DvmBZkghMOhpcjPqDaeuRBgrYtfeaFY3MhqJc\nu7KJ65O6I9y01kjqOJ5DH7hU/OL4GMfy6GTtDxpTQ2sXOTU0GTOV2UxtLjSTc2Ea6xYn+MsqpFan\nf2KWnsbahHfBFIZC1uoMTgdw2Cx51zMVigZX9Q5y06JTQXhrDX99sYjGFKP+YFHSpXOls8GJUkaW\nWioGC1j7YDYb/dytay8IjLudNbR7HBwfTZ9Fl4nfe2wff7TzYM77++bDuJcwNTSZ85ZO4X8nSimm\n5kIJV2++dHmdDEwVf/RCNk6Pz7G8+Xybp1q7jcbamoIKonlzVMrhbckYo1CqU3R0cWgFUezZ5+Oz\nQaIxRUdZLZ3zU0ZTicvg1DxXL09fRJsPH9rew8ZOT8pC01Ut9YsSnUg0xvBMkDF/iPlQFFcO1svI\nTJC2An3nZvfnYtTq+IMRIjFF4yJHL3d5XQQjMSZmQzQXscA5E0op+sfn2L7g/3mhOyacnZgrWxIB\nGNmuc6EooUgsY/1fJVJdq73EaSxy/7WReGFooS6Ai8EUvFTJBHOhCJNz4YL9MdttlrSdDVa31XF8\nxJ/3XfmY38gcC0VjvHxqIqdjhn0B2gqUom7GWyaLIDrmb2/xlk75a3Um58LMBCMsb667YPsyr6ug\n7rX+iQutqVJT6hH3hUSLTgXhLfJ4g3IWhpp0Jiydiy8Apezau7q1Hl8gkrfFkLzu53JMRBiZKVwc\nzW6z4HbYimLpmC67xSYSJAL2ZYzrnI7PUVqxoIt6V7xAtBCuP18gzORcmOUF7tSeDw1V3H9Ni04F\nUexEgmK2wMmVBlcNzhpLyvb8gyWsfVjdakxNPT6Sn4vNXHdLvYPn+8ay7l+Mrt5N9cUpEDXjiYt1\nr5nCOjJTPkunP15/tdAKWeZ1MRuK4ivA4LP+ceM9FgpbKTkvOtVXIKpFp4Lw1tYwE4gUtHI6mWFf\nABGK2lA0G8bsFVfKtGlTdDpL0Cp+dXxUd74ZbOa6379tGUeGZhIdHtJhdvVuK2BtVLG6EizVvdZU\nZ8ci59245eB0XBAWWiFm1/JCxHXMwuJCz6TKB23paApCY6L/WnF+SCMzAZrrHIuaU1NI2j2OlDGd\nwSljeFsp3H+dHieuGmveyQRD0wHsNgt3XNkFkNXaGZkpvHXZXKSmn0u1dKwWoaXeUVZL5/T4HO0e\nx0UdN7oKWKtzOo01VUq8Rb5WFBMtOhVEsVvhGDU65bNyTDobXClb4QxMBWhf5PC2fLFYhJUtdZzI\nV3R8ATo8TjZ3eWiqs/P8scyiU4w4mmHpFN6amIxbOuZd9GJo8zjSpsOXgv6JWVY01V203azVKURv\nuP6JORpra/AssYB5KSTGG1RhVwItOhVEsX9Iw75AWZMITDoanAz7AsQW9A8rZI1OLqxuq1+Ue63D\n48RiEW5c08JzfWMZg9Om6BQqew2gqc7B5Gy44PUwU3MhPE4btiWIfpvbmbDuysHCGh2TljoHdqul\nIEkOZybmLsqOKzWeeHeLS9bSEZHbReSoiPSJyBdTvO4QkUfjr+8Skd6k174U335URN6Z7Zwi8pCI\n7BOR/SLyuIjUL3ivu0REicj2+PPbRGSPiLwe//eWFOvbKSIHcvms5aTY/dcM0akES8dJOKouchEN\nTpdYdFrrODM5l1cPtmFfIFFrdPOaFkZnghzN0J3AvAAXNqZTQygaS8zpKRRGN4KlVdi31jvKJjrz\noSgjM8GUAX6LRYzi1UK418bnypq5Bsb4d7fDdmlaOiJiBb4FvAvYBHxERDYt2O2TwKRSag3wF8DX\n48duAu4GNgO3A98WEWuWc35eKbVVKXUl0A/ck7QWN/BZYFfSe48BdyilrgA+Dnx/wfrfDyyu9LzE\nNBZxkFs4GmPMHyroxW+xtKeo1YnFFOemAiXtZbW6tR6l4NR4btaOUopz04FEooPZTieTi23EF8Dj\ntOVURJorTfFWOIVOJlhKNwKTNo+DcX+waF2wM3FmMnOspRAFopFojIGpeZY3la8w1KShtjpb4eRi\n6VwL9CmlTiilQsAjwJ0L9rkTeDj++HHgVjH6Q9wJPKKUCiqlTgJ98fOlPadSygcQP94FJP96vwZ8\nA0hcrZRSe5VSg/GnBwGniDji56gHfhe4L4fPWXa8rrilU4Qf0mgioF1+0TEv2slxnbHZIKForKRd\ne8+nTecmOpNzYUKRWOI77PK6WN1ax3MZRGfYV7huBCbNdcXpSmA0+1xanKLN7SCmjO4XpcbMXFuR\nxvVliM7SkhwGpwJEYypl3KjUFLuDSbHIRXSWAWeSnp+Nb0u5j1IqAkwDzRmOzXhOEfkeMARsAB6I\nb7sa6FFKPZFhrR8A9iqlzF/814D/CWQcniIinxKR3SKye3S0tAO+knE7bYjAdBHca2ZsoaOh/O41\n0z2VPMzNvBiUchLjyhbjwpFrMoFpmSWndF+3qpk9pyfT3tmPzBTepZnov1bgpp+Ts+FFF4aamMMB\ny5E2na4w1GSZ18XwTCBts9lc6K+AdGmTau2/lovopOpot/AvLN0++W43Hij1CaALOAx8WEQsGG67\nL6RdpMhmDLfep+PPrwLWKKV+mO6YpPd7UCm1XSm1vbW1NdvuRSPRaboIPySzMLQS3GstdQ5sFrmg\nVqeUhaEmLruVZV5XzmnTQz5jje1JonPtyib8wQiHz/lSHjPsCxZ8flFCdAp8c2K415Zm6bTGP2s5\nMtj6J+ZwO21pP8MyrwulUrdgypXTE3FhK2O6tIm3Sscb5CI6Z4GepOfdwGC6fUTEBjQAExmOzXpO\npVQUeBTDenEDW4BnReQUcB2wMymZoBv4IfAxpdTx+CmuB66J7/88sE5Ens3h85YVr6smkbpaSMza\niUpwr1ksQrvHecEff7mGYuWTwTY0bVxIky2dN/UanaxfPnlxHzalFCMzAVoLbOmYTT8LGdMJRWLM\nhqJLtnTMLL1y1OqYAf50nZ+7CtCmp39iDrvVUhF/R9U6yC0X0XkFWCsiK0XEjpEYsHPBPjsxgvgA\ndwHPKCOfcydwdzy7bSWwFng53TnFYA0kYjp3AEeUUtNKqRalVK9Sqhd4CXifUmq3iHiBJ4EvKaVe\nMBeklPqOUqorvv9NwBtKqR15fj8lx1trL0r22rAvgNUiiXhAuelYMLZ6YGqeOrsVj6u0jc9Xt9Zx\nfDS3xp9D00bxamtSR4cur4vuRldK0ZmcCxOOqoJbOrV2G84aS0FFZ2qJhaEmpnutXJZOJgukJx78\nP51j4kgqzkzM0d3kyjoJuBQ0uOz45gufOl9ssopOPEZzD/AUhrvrMaXUQRH5qoi8L77bQ0CziPRh\nBO6/GD/2IPAYcAj4CfAZpVQ03Tkx3G4Pi8jrwOtAJ/DVLEu8B1gD3Csir8X/a8v9K6gsimUyD/uC\ntLkdWCrgjwXiorPA0ukqw3yS1a31zIWiKYtVF3JuOkCr23FRHcu1K5t45dTERX/8xbQum2rtBR3k\nNrnEFjgmzhorHqet5GnT0Zji7OQcyzME+Lsba3HYLPTl2W8vmUpIlzZpcBmp8/MlGrteKHK6rVRK\n/Rj48YJtX0l6HAA+mObY+4H7czxnDLgxh/XsSHp8H1my05RSpzDccxWP11XDiUVOtMyEMaa6/C4B\nkw6Pk2cOj6CUQkQYnEo9X6fYrGo1LlLHR2bpzJLEMOQL0JFin2t7m/jnVwc4PjrLmrbzZWWJOFoR\naqOMpp+Fu7Cfb4GzdEu4zeMseSLB4NQ84ajKaOlYLcLq1nqOLVJ0zFk96cZllJrk/mu19uoZjaY7\nElQYxXKvjfiCtBewKn6pdDY4mQ9H8c1H6Bvxc3R4JpFNVkrWt7sB0iYCJDM0HaAjhYCYE0pfWTBf\nJ9ECpwjJG011jqK415aaSABGXKfUMR0zqyxb5+e17fUcG16c6EyZs3oqxNLxVulMHS06FYa3tgZf\nETpNj8+GEgHoSsBMmz4zOcfnHt1Lnd3Kb+5YXfJ1NNc76Gly8dqZqaz7DvkCKa2hlS11tNTbL4rr\nmHGNYlg6zXX2gmavme61pXYkAEN0Rv2ltXTMAt9sTTjXttUzMDXP7CK6OSTGJlSI6FRr/zUtOhWG\ntwgty5VS+ObDeJbQyLHQmBlg//1fDnBgwMefvP/KsmUEbe32ZhUdfzDCTCCSco0iwrUrmy4SneF4\nN4KFHY8LQVOdvaB1OkvtMJ1Mq9vBiC9Y0gD3G0Mz1NqtWeu81rQZlu1iRpWb3aXTFZ+Wmmodb6BF\np8Iwx9AWYtiUSSAcIxSNLal7cKExL96vnZniw9t7uH1LR9nWclWPl4Gp+YwZV6kKQ5N5U28TA1Pz\nF6TjFrPBalOdndlQNK++cZmYmgtjt1lwFUAg29xOgpFYQX/D2TgyNMO6dnfWRJm17UbMLZ2LTSnF\nQ8+fZF+Km5Dzc3TK3wIHkkRHWzqapeB2GD+kmUDhfkjmnVAliU6b24lFoLe5lq/csbCVX2nZ2uMF\nYP/Z9NbO+Y4OqUUkEddJsnYKOaZ6IYkC0QLFdSZnjRY4hcgeNN2JpUqbVkpxdHiGDR3urPuuaKql\nxippkwkefeUMX3viEJ98ePdF6+8fn6Ol3lExQfsGHdPRFALTBeabL9xdYiWKjt1m4X9+aCsP/dqb\nqHOU9494c5cHq0UyutjM7gkdaURkQ4cHt8PGrmTRiaepF4OCi87c0lvgmLSWuEB0ZCbI1FyY9TmI\njs1qYVVLPX0jF3cGPzk2yx//6BBXdjfgC4T5vX/clxi/EQhHOTA4XRGdCEzcDhtWi2jR0SwNszjS\nd4lbOgD/5eruRNPNclJrt7Gu3Z1RdMw+ceksHatFePOqZp45MkwoEkt0IyhWmnqhm34WogWOSVuJ\nC0SPDhkCkovoAKxpvzhtOhyN8blH9mK3WfjuR6/h3vds5GdvjPJ3L5ykf3yOu/76Fxwc9PFLV3UV\nfP2LRcRomzVZpFEoxUKLToXhdl4e7rVK46qeBvadmUob/B7yBfDW1mRMCvjV65Yz7Auyc9/g+W4E\nRZpfZFo6kwWzdEIFtHQMoS1VrY4pOhs6PDntv7atnv6JC+coffPpY+w7O82fvP8KOhtc/Op1K3jH\npna+/pMjvOeB5+gfn+NvPradj17fW4yPsGiMKbJadDRLwJwIeKm71yqNq3q8+AIRTo2nbkg+FJ8Y\nmom3rmtlQ4ebB39+PJF4UKwGq83xmTpjBUpNnpoLL7kbgYnHacNhs5QsbfrI0AytbkdCiLOxts2N\nUucz2Aam5vn2s8f5wLZu3n1FJ2BYEd+4y8ioXNlSx5OfvZnbNrUX7TMslqY6e8FHXBQbLToVRp3d\nGG+gLZ3SYiYTvHZmMuXrQ0kTQ9MhInzqLat4Y9jPY7uNyR3FsnQ8LhutbgcHB7MXtWZDKcXUfLgg\n6dJgfA9tHgcjObQWKgRHh305JRGYmBlsZjucH+zqRynF529be8F+3lo7T3/hrfzrZ26siFEGqWjW\nlo5mqVgsgtthK2i6qSk6putOczFr29zU2q3sOzOd8vVzU9ktHYA7tnbR1eDk7186DRSvq7eIsG25\nl1f7U4tkPvgCEaIxVTD3GpRubHU0pjg27E90lsiF3uY6rBahb8RPKBLjkVf6uWVDG92NFwuLw2Yt\neT/AfGiutzNe4kLcpaJFpwLxuGoKmkjgmw/jdtoqojNupWK1CFuWNaRMJpieDzM+G6I3hzY9NVYL\nv37TSiLxrKfWIrYe2ra8kdPjc0t2sRWyBY5Jm9tZEtE5NT5LMBLLOYkAjMzJ3uZajg37+cnBIcb8\nIX71uhVFXGXxaKpzMDUfLngHk2KiRacCcTtrCh7T0a617FzV4+XQoI9Q5MI/YNP3n2um3d3XLsft\ntNHgypx4sFS2xRtP7u3P3sInE4kWOAW0dNo8jpJkr+WbRGCyts3NsZEZ/v7F0yxvquUta8s3vHEp\ntNTbUYqizOAqFlp0KhCP01bwlGktOtnZ2u0lFI1d1PzzeNz3n9xBOhP1Dht/cPsG7rqmu+BrTOaK\nZQ3YLLJkF1uiBU5dIS0dB9Pz4YJ1TEjHkaEZLHI+TpMra9vrOTE2y8unJviVNy+vmJEf+VLoeq1S\nUBmltZoLcDtrljTdcCHT82E8Op6Tla09DQDsOzuVSCwAOD46S41V6GnMvf1JKdw1zhorm5c18Orp\npYnOefdaAWM6SbU6xQzCHx3y0dtcl7dFuaatHqUMV9sHt/dkP6BCMbMYjbhO7i7GcqItnQrE47Lh\nK2CVsU9bOjmxzOuisbaGAwMXJhP0jfjpba67aHhbJbBtuZf9Z6eX5NOfnC2Ce82s1Smyi+3o0Exe\n8RyTtfHGn++9sjPnVOtKxOwcX01p05X3V6TB46wpeMq0Fp3siBjJBAcGLnSvnRj15+xaKzXbljcy\nH45yZOh8W5dTY7N5uWen5kKIFDalvhRjq+dCEU5PzC1KdNZ3uPn0W1bxuVvXFWFlpaO5Ct1rWnQq\nEI/Txkwwkuj7tFSm58OJ5oCazGxZ1sAbwzMEI0YsIhSJcXpiriLa9aTCTCYw4zqDU/O866+e4xPf\neyXn0QJjsyE8zpqCZjeeb4VTvFqdY8N+lCKvGh0Tq0X40rs3Zp2/U+l4a+2IUFVp01p0KhCPqwal\nwB9aegZbIBwlGKmssQaVzJauBiIxlciKOj0+SzSmKtbS6Wpw0u5xsCce17n/ycPMh6PsOT3Jj/af\ny+kcu09NcMWyhoKuq7negdUiDBWxQPTIkGGRrs8zc+1SwmoRGmurqyuBFp0KxB1vhTNTgAJRMzZU\nSQPcKhnz4mu62Myq9Uq1dIwi0UZe7Z/khb4xnnz9HJ+9dS2bOj386Y8PZ80eG/YFeGPYz01rWwq6\nLqtFaHM7GC5S/7VAOMqDPz9Bd6OrYiZ5lovmOjvjBRzoV2y06FQgZqZZIZIJdAuc/OhpcuF22jgw\naCQTmDU6q1orY1pkKrYtb+TMxDxf/Of99DS5+K0dq/nKHZsYnA7w4M9PZDz2+WNjANy0prCiA9Dm\ncSbmEBWa//VMH8dHZ/kf/+WKy77oudqafmrRqUDOd5peuqWjRSc/RIQtXQ2JDLbjo7N0NTjLPvMn\nE9tWGOndZybm+aP3bsZZY+W6Vc28a0sH33n2fPPRVDx3bJTmOjubOgvvourwODK+92I5ODjNX//M\naND5lnXVWdRZSFrqHYzN6piOZgkkZupoS6csXNHdwJFzM4SjMfpG/Kyu0HiOyeauBlw1Vt62vpVb\nN7Yltv/huzcSjSn+6uljKY9TSvF83zg3rmkpSnFkh8dZ8JhOJBrjD/5pP97aGu5978aCnrta0ZaO\nZsmY7rWZoBadcrC5y0MoGuON4RmOj/orNp5j4qyx8s+/dQPf/MjVFzSn7Gmq5fYtHfzHoaGUmZBH\nhmYY8wcLHs8xaW9wMhOIMFeAhBgwRPLP/v0oBwZ8fPXOLQUtZq1mmuvtTM1VT/81LToViLuAM3W0\n6OTPlngywX8eGmEuFK14SwdgY6cnZRfxHetbGfOHOHTu4hEIzx0bBeDmIomO2ZW7EC42pRT3P3mY\n7/7sBB+5djnv2tKx5HNeKiRqdapkgqgWnQrEXYREAnM4nCY7K5vrqLNb+dfXBgBYU+GWTiZujjey\n/Nkboxe99tyxMda01dPZkHt7n3xIiM4SXWyxmOLL/3KAv33+JL92Qy/3/9KWih43UGqa642aqGpx\nsWnRqUDsNgvOGgszwcJYOvUOW0W2cKlULBZhc1cDJ8ZmAVjdVrmZa9lodTvYsszDz45eKDqBcJSX\nT04UJWvNpD0+9G6pGWzffOYY/7Crn9/csZo/umNT1TbnLBZmG59qSZvWV6IKxeOsKZilo11r+bN5\nmZHN5XHaaK0v3kycUvDWda3s6Z+8oDXO7lOTBCMx3rKuiKLjMUVnaZlV//b6ENevauYPbt+gLZwU\nmO61pRSIPrF/kF/73sv4C3Cjmw0tOhWKx1VTsOJQXRiaP2aR6Oq2+qq/0L11XRvRmOIXfWOJbT8/\nNkqNVXjzyuaivW+9w0a9w7akmM64P8jR4ZmiJTtcCpjutaW0wjkw4OOFvjFqizj/yUSLToXiLtBM\nHcPS0fGcfDGTCao5nmOybbkXt9OWiOucHp/l+y+e5m3r24pef9TucSzJvbbr5AQA168unjhWO15X\nDRZZWkzn3PQ8nQ2ukrgutehUKNq9Vl5WtdRxxbIGbr4Eig9tVgs3rWnhZ0dHicUUv//4fmwW4Y/v\n3Fz09+5oWFqtzksnxqm1WwveG+5SwmIRmuqW1n9tcGqeLq+zgKtKjxadCsXttBWsI4EWnfyxWS38\n6Ldv4n1bu8q9lILw1nWtDE4HuPdfD/DyyQnufe+momWtJdPucTK8BPfai8fH2d7bRI1OhMlIU519\nSe61wakAXd7i/x5Ai07F4nHVFMS95puP6KmhmkS7mP+7q58d61v54PbijtI26fA4GZkJLmpMx5g/\nyLERP9etairCyi4tmusci3avRaIxhnwBlmnRubzxOGvwLdHSCUVizIej2tLR0OV1sb7djdtp40/e\nf0XJkiM6GpxEYmpRvcF2nYjHc1bpeE42muoX32l6ZCZINKZKYvkC6AhzheJ22ghFYgTC0bznv5sk\nuhHoAW4a4P//8NaSXlwgaWy1L5h4nCsvnRinzm5NJHVo0tOyhJjO4NQ8gI7pXO6Yac5LievoFjia\nZDZ3NXBlt7ek79nRsPhWOC+e0PGcXGmqczA9Hya8iP5rg/H/N9q9dpljtq1ZSlxnWg9w05SZxbbC\nGZ0J0jfi16nSOdJUbxSITi7C2jEtnU4tOpc3hRjk5tOWjqbMtNTbsUj+rXB2nRwH4Dodz8mJlnhX\ngrFFxHUGp+ZpcNVQX6KZUTmJjojcLiJHRaRPRL6Y4nWHiDwaf32XiPQmvfal+PajIvLObOcUkYdE\nZJ+I7BeRx0WkfsF73SUiSkS2x5/fJiJ7ROT1+L+3JO37k/i5DorIX4tI8cttC4Q5U0e71zTVjM1q\nodWd/zC3F4+PU++wsaWr8MPlLkXM/muLyWAbnJqns6E08RzIQXTiF+pvAe8CNgEfEZFNC3b7JDCp\nlFoD/AXw9fixm4C7gc3A7cC3RcSa5ZyfV0ptVUpdCfQD9yStxQ18FtiV9N5jwB1KqSuAjwPfT3rt\nQ0qprcAWoBX4YLbPWykkOk0XwL2mRUdTTvId5qaU4tmjo1y3qkk3qs2RRCucRWQJDkyVLl0acrN0\nrgX6lFInlFIh4BHgzgX73Ak8HH/8OHCrGDmZdwKPKKWCSqmTQF/8fGnPqZTyAcSPdwHJCf5fA74B\nJH7BSqm9SqnB+NODgFNEHMnnwsjSsy84V0XjKcDIai06mkqg3ePMy712cNDHwNQ879ikZ+bkSvMS\nOk2fm54vWWEo5CY6y4AzSc/Pxrel3EcpFQGmgeYMx2Y8p4h8DxgCNgAPxLddDfQopZ7IsNYPAHuV\nUgm5F5GngBFgBkMQq4Lzg9yWZunU2q06+0dTVgzRyf0O/D8ODSMCtySN3tZkpsFVg9UiKd1r3362\nj7/8zzdSHjcbjDA1F6440UlVRbbQYki3T77bjQdKfQLoAg4DHxYRC4bb7gtpFymyGcOt9+kLTqrU\nO4FOwAHckuJQRORTIrJbRHaPjl487Koc1NqtWC2yZPeatnI05aajwcn0fJhAOJrT/v9+aJjtKxpp\nqfKREqXEYhEaa+0XuTEfev4k3/jJUb759DEG4llqyZybLm2NDuQmOmeBnqTn3cBgun1ExAY0ABMZ\njs16TqVUFHgUw3pxY8RlnhWRU8B1wM6kZIJu4IfAx5RSxxd+AKVUANjJxW5B8/UHlVLblVLbW1sr\no8GjiCy5/5oWHU0l0J7H2OozE3McPufjtk3txV7WJcdVPQ08vucs9z95iGAkyr+9fo77njyUGNT3\nf186fdExA1PG/5NKs3ReAdaKyEoRsWMkBuxcsM9OjCA+wF3AM0opFd9+dzy7bSWwFng53TnFYA0k\nYjp3AEeUUtNKqRalVK9Sqhd4CXifUmq3iHiBJ4EvKaVeMBckIvUi0hl/bAPeDRzJ8/spK0vtND2t\nZ+loKoB8anX+8/AwALfpeE7ePPCRbfzqdcv5m+dO8r4HXuB3Hn2Nbcsb+duPb+eWDe08+soZgpEL\nrc3z3QgqSHTiMZp7gKcw3F2PKaUOishXReR98d0eAppFpA/4XeCL8WMPAo8Bh4CfAJ9RSkXTnRPD\n7fawiLwOvI7hFvtqliXeA6wB7hWR1+L/tQF1GEK2H9iHEdf565y+lQrB41qapePTlo6mAuhoMNxk\nuSQT/PvBYda21bOypXpHhJcLl93Kfb90BX/zse2MzBgZaX/zse04a6x87PoVjM+G+PHr5y44ZnBq\nHotAu7t0rsycqoGUUj8Gfrxg21eSHgdIk46slLofuD/Hc8aAG3NYz46kx/cB96XZ9U3ZzlXJuB1L\n6zQ9PR9mixYdTZkx3WupYgo/OTCEReC2Te1Mz4d5+dQEn37LqlIv8ZLitk3tPPcHtyCQGNJ305oW\nVpEj28gAAA1kSURBVLbU8f0XT/Nfrj7fYXxwKkCHx1nS1HTd8LOC8bhsnB6fW/TxU3Pa0tGUH7ez\nhg0dbv5x91n+282rEtmUJ8dmuecfXiUSU1y7solrVjQSjSnesVm71pbKwu4CFovwq9et4GtPHOLA\nwHSiiaoxvK10rjXQbXAqGvcSYjpzoQjz4SjN8Z5MGk05+cI71nNybJZ/2nM2se3PnzqK3Wbhy+/e\nSN+In+88e5w2t4MrdVfponDXNd24aqx8/8XzCQWDJa7RAS06Fc1SZuqYRWI67VRTCbx9YxtXL/fy\nV08fIxCO8tqZKZ58/Rz/9eZV/Le3rOKnv7eD375lDV9+z0YsltLM+rncaHDV8P5ty/jnvWc5Puon\nFlOcmwrQWcJ0adCiU9F4XDb8wQjRRU5dBKPhokZTbkSE33/nes5NB/j7l07zJz8+TEu9nU/F4zcN\nrhq+8I713HnVwrpzTSH53NvX4ayx8kf/epCx2SChaKykLXBAi05FY/Zf8y/C2jEtneY6beloKoMb\nVrdw05oW/uypo+w6OcHv3Lq2ZJ2NNQatbge/9471PN83xkPPnQSgq4RD/UCLTkWzlJk6CUunhKmQ\nGk02fv+d6wlGYqxsqePua5eXezmXJb/y5uVs6vTw3Z+fAEpbowNadCoaMx5zcNCXZc+LMUfXmo0A\nNZpKYGuPlz//4Fa+9cvbdE/AMmGzWvjaL21JPNfuNU2CG+O59d946kjeY2jH/EHqHTacNVUzQkhz\nmXDXNd1s0nNyyso1Kxr5yLXLafc4ErO7SoUWnQrGbrPwh+/eyInRWf5hV39ex475QzqJQKPRpOW+\nX9rCf/zuWzE6jpUOLToVzts3tnHD6mb+4j/fYHou99jOuD+YGOyk0Wg0C7FaJDG3q5Ro0alwRIT/\n/p5NTM+H+eYzx3I+btwf0vEcjUZTcWjRqQI2dXn48PYe/s+LpzgzkVtbnDF/UGeuaTSaikOLTpXw\nmbetIRxVPB1v/Z6JaEwxMReiRVs6Go2mwtCiUyX0NNXS0+TixRPjWfednAuhFDqmo9FoKg4tOlXE\n9auaeenEBLEsbXHOt8DRoqPRaCoLLTpVxPWrm5meD3PoXOZi0UQLHJ0yrdFoKgwtOlXE9auMWecv\nZXGx6WafGo2mUtGiU0V0NDhZ1VLHi8eziY4ea6DRaCoTLTpVxnWrm9l1coJIhrY44/4gtjIVfmk0\nGk0mtOhUGTesbsYfjHAgQxPQcX+Ipjq7Hoal0WgqDi06VcZ1q5oBMrrYxmeD2rWm0WgqEi06VUZL\nvYN17fX84vhY2n1G/SGduabRaCoSLTpVyA2rW9h9apJQJHVcZ9yvLR2NRlOZaNGpQq5b1cx8OMr+\ns1MpXx/XYw00Gk2FokWnCrl6uReAwymKRGeDEebDUd0CR6PRVCRadKqQNrcDZ42FU+MXd5xOdCPQ\nzT41Gk0FokWnChERepvrOD0+e9FrY7O675pGo6lctOhUKSuaa1NaOmMzWnQ0Gk3lokWnSultrqN/\nfI7ogo7T47O62adGo6lctOhUKSua6whFYwz5AhdsH483+2zSMR2NRlOBaNGpUnqbawE4PXZhXGfM\nH8LttOGssZZjWRqNRpMRLTpVyvK46CyM64zpwlCNRlPBaNGpUjobXNitlosy2Mb9IZ0urdFoKhYt\nOlWK1SL0NLk4rS0djUZTRWjRqWJ6m+s4tdDSmdXNPjUaTeWiRaeKWdFcx+nxOZQy0qbnQ1Em50La\n0tFoNBWLFp0qprellvlwlNF4QegLfWMoBW/qbSrzyjQajSY1WnSqmBXNdcD5DLanjwzjdti4dqUW\nHY1GU5lo0aliehNp07PEYoqnD4/wlnWt2G36f6tGo6lMcro6icjtInJURPpE5IspXneIyKPx13eJ\nSG/Sa1+Kbz8qIu/Mdk4ReUhE9onIfhF5XETqF7zXXSKiRGR7/PltIrJHRF6P/3tLfHutiDwpIkdE\n5KCI/Gm+X06l0+V1YbUIp8dnOTjoY2QmyC0b2sq9LI1Go0lLVtERESvwLeBdwCbgIyKyacFunwQm\nlVJrgL8Avh4/dhNwN7AZuB34tohYs5zz80qprUqpK4F+4J6ktbiBzwK7kt57DLhDKXUF8HHg+0mv\n/blSagNwNXCjiLwr2+etJmqsFrobXZwan+M/Dw9jEXibFh2NRlPB5GLpXAv0KaVOKKVCwCPAnQv2\nuRN4OP74ceBWEZH49keUUkGl1EmgL36+tOdUSvkA4se7gOSOll8DvgEkGo4ppfYqpQbjTw8CThFx\nKKXmlFI/je8TAl4FunP4vFXFiviIg6ePDLNteaPuuabRaCqaXERnGXAm6fnZ+LaU+yilIsA00Jzh\n2IznFJHvAUPABuCB+LargR6l1BMZ1voBYK9SKpi8UUS8wB3A0xmOrUp6m2t5Y9jPgQEft25sL/dy\nNBqNJiO5iI6k2KZy3Cff7cYDpT4BdAGHgQ+LiAXDbfeFtIsU2Yzh1vv0gu024AfAN5VSJ9Ic+ykR\n2S0iu0dHR9O9RUWyormOUCQGwK0btWtNo9FUNrmIzlmgJ+l5NzCYbp/4Rb4BmMhwbNZzKqWiwKMY\n1osb2AI8KyKngOuAnUnJBN3AD4GPKaWOL1jbg8AxpdRfpvuASqkHlVLblVLbW1tb0+1WkZgZbD1N\nLta21WfZW6PRaMpLLqLzCrBWRFaKiB0jMWDngn12YgTxAe4CnlFGmfxO4O54dttKYC3wcrpzisEa\nSMR07gCOKKWmlVItSqlepVQv8BLwPqXU7rjr7EngS0qpF5IXJSL3YQjg5/L6VqoIs1bn1g3tGF+Z\nRqPRVC62bDsopSIicg/wFGAF/k4pdVBEvgrsVkrtBB4Cvi8ifRgWzt3xYw+KyGPAISACfCZuwZDm\nnBbgYRHxYLjg9gG/mWWJ9wBrgHtF5N74tncAduDLwBHg1fgF+X8ppf42ly+mWljVUsdv7VjN3W9a\nXu6laDQaTVbE7NulMdi+fbvavXt3uZeh0Wg0VYWI7FFKbc+2ny5d12g0Gk3J0KKj0Wg0mpKhRUej\n0Wg0JUOLjkaj0WhKhhYdjUaj0ZQMLToajUajKRladDQajUZTMrToaDQajaZk6OLQBYjIKHB6kYe3\nYMz3uZy4HD8zXJ6f+3L8zHB5fu7FfOYVSqmszSu16BQQEdmdS0XupcTl+Jnh8vzcl+Nnhsvzcxfz\nM2v3mkaj0WhKhhYdjUaj0ZQMLTqF5cFyL6AMXI6fGS7Pz305fma4PD930T6zjuloNBqNpmRoS0ej\n0Wg0JUOLTgEQkdtF5KiI9InIF8u9nmIhIj0i8lMROSwiB0Xkd+Lbm0TkP0TkWPzfxnKvtdCIiFVE\n9orIE/HnK0VkV/wzPxqfgHtJISJeEXlc5P+1dz8hVlZxGMe/D05iGiEJRc0YJgyVBKVETH8IMRdZ\n0rQwSgpFEjdBKUZUm2jRIoj+SOFGTQNRwqRm1cYC2ySlQkm6CIucmhyh1DDQpKfFOZcuw70Ec+/7\nvnT4fWCYe8688J7Dc+f93XvOO3N1Imd+d+lZS9qUn9vHJO2RNKvErCXtkDQp6VhbX8ds8yc6b8nX\nt28kLenl3FF0eiRpBvAesAJYBKyWtKjZUVXmMrDZ9q3ACPBMnuuLwAHbw8CB3C7Nc8DxtvbrwFt5\nzr8DTzcyqmq9A3xq+xbgdtL8i81a0iDwLHCn7dtIn2r8BGVmvRN4cEpft2xXAMP5awOwtZcTR9Hp\n3V3A97ZP2r4E7AVGGx5TJWxP2D6SH/9BuggNkua7Kx+2C3i0mRFWQ9IQ8DCwLbcFLAP25UNKnPPV\nwP2kj6LH9iXbZyk8a2AAuFLSADAbmKDArG0fBH6b0t0t21HgAydfAnMlXT/dc0fR6d0gcKqtPZ77\niiZpAbAYOARcZ3sCUmECrm1uZJV4G3gB+Du35wFnbV/O7RIzXwicAd7Py4rbJM2h4Kxt/wy8AfxE\nKjbngMOUn3VLt2z7eo2LotM7degr+pZASVcBHwEbbZ9vejxVkrQSmLR9uL27w6GlZT4ALAG22l4M\nXKCgpbRO8h7GKHATcAMwh7S0NFVpWf+Xvj7fo+j0bhyY39YeAn5paCyVk3QFqeDstr0/d59uvd3O\n3yebGl8F7gUekfQjael0Gemdz9y8BANlZj4OjNs+lNv7SEWo5KyXAz/YPmP7L2A/cA/lZ93SLdu+\nXuOi6PTuK2A43+Eyk7TxONbwmCqR9zK2A8dtv9n2ozFgbX68Fvik7rFVxfZLtodsLyBl+5ntJ4HP\ngVX5sKLmDGD7V+CUpJtz1wPAdxScNWlZbUTS7Pxcb8256KzbdMt2DFiT72IbAc61luGmI/44tA8k\nPUR69TsD2GH7tYaHVAlJ9wFfAN/y7/7Gy6R9nQ+BG0m/uI/ZnrpJ+b8naSnwvO2VkhaS3vlcAxwF\nnrJ9scnx9ZukO0g3T8wETgLrSC9Ui81a0qvA46Q7NY8C60n7F0VlLWkPsJT036RPA68AH9Mh21yA\n3yXd7fYnsM7219M+dxSdEEIIdYnltRBCCLWJohNCCKE2UXRCCCHUJopOCCGE2kTRCSGEUJsoOiGE\nEGoTRSeEEEJtouiEEEKozT/pV4XpKA90XAAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -172,6 +189,55 @@ "plt.show()" ] }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(data[\"X\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "setting an array element with a sequence.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mmeas\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqcodes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mMeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msr\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuffer_values\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmeas\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\measure.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, use_threads, quiet, station, **kwargs)\u001b[0m\n\u001b[0;32m 83\u001b[0m \u001b[1;31m# run the measurement as if it were a Loop\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 84\u001b[0m self._dummyLoop.run(use_threads=use_threads,\n\u001b[1;32m---> 85\u001b[1;33m station=station, quiet=True)\n\u001b[0m\u001b[0;32m 86\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 87\u001b[0m \u001b[1;31m# look for arrays that are unnecessarily nested, and un-nest them\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, use_threads, quiet, station, progress_interval, set_active, *args, **kwargs)\u001b[0m\n\u001b[0;32m 736\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mquiet\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 737\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdatetime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnow\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Started at %Y-%m-%d %H:%M:%S'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 738\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_run_wrapper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 739\u001b[0m \u001b[0mds\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdata_set\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 740\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36m_run_wrapper\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 785\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_run_wrapper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 786\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 787\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_run_loop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 788\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 789\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'data_set'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36m_run_loop\u001b[1;34m(self, first_delay, action_indices, loop_indices, current_values, **ignore_kwargs)\u001b[0m\n\u001b[0;32m 869\u001b[0m f(first_delay=delay,\n\u001b[0;32m 870\u001b[0m \u001b[0mloop_indices\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mnew_indices\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 871\u001b[1;33m current_values=new_values)\n\u001b[0m\u001b[0;32m 872\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 873\u001b[0m \u001b[1;31m# after the first action, no delay is inherited\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\actions.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, loop_indices, **ignore_kwargs)\u001b[0m\n\u001b[0;32m 165\u001b[0m \u001b[0mout_dict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mparam_id\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparam_out\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 166\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 167\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstore\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mout_dict\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 168\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 169\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\data\\data_set.py\u001b[0m in \u001b[0;36mstore\u001b[1;34m(self, loop_indices, ids_values)\u001b[0m\n\u001b[0;32m 386\u001b[0m \"\"\"\n\u001b[0;32m 387\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0marray_id\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mids_values\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 388\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0marray_id\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 389\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlast_store\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 390\u001b[0m if (self.write_period is not None and\n", + "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\data\\data_array.py\u001b[0m in \u001b[0;36m__setitem__\u001b[1;34m(self, loop_indices, value)\u001b[0m\n\u001b[0;32m 339\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_update_modified_range\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmin_li\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmax_li\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 340\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 341\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__setitem__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 342\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 343\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__getitem__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mloop_indices\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mValueError\u001b[0m: setting an array element with a sequence." + ] + } + ], + "source": [ + "meas = qcodes.Measure(sr.buffer_values)\n", + "data = meas.run()" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/qcodes/instrument_drivers/stanford_research/SR860.py b/qcodes/instrument_drivers/stanford_research/SR860.py index 94c26efabff..cee0f174dbb 100644 --- a/qcodes/instrument_drivers/stanford_research/SR860.py +++ b/qcodes/instrument_drivers/stanford_research/SR860.py @@ -2,5 +2,5 @@ class SR860(SR86x): - def __init(self, name, address, reset=False, **kwargs): + def __init__(self, name, address, reset=False, **kwargs): super().__init__(name, address, max_frequency=5E3, reset=reset, **kwargs) diff --git a/qcodes/instrument_drivers/stanford_research/SR865.py b/qcodes/instrument_drivers/stanford_research/SR865.py index a0e1030648c..4db7686569c 100644 --- a/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/qcodes/instrument_drivers/stanford_research/SR865.py @@ -2,5 +2,5 @@ class SR865(SR86x): - def __init(self, name, address, reset=False, **kwargs): + def __init__(self, name, address, reset=False, **kwargs): super().__init__(name, address, max_frequency=4E6, reset=reset, **kwargs) diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py index dd4493b089b..fb20f9042b9 100644 --- a/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -6,10 +6,43 @@ from qcodes import VisaInstrument from qcodes.instrument.channel import InstrumentChannel from qcodes.utils.validators import Numbers, Ints, Enum +from qcodes.instrument.parameter import ArrayParameter log = logging.getLogger(__name__) +class SR86xBufferReadout(ArrayParameter): + def __init__(self, name, instrument, capture_parameter): + + super().__init__(name, + shape=(1,), # dummy initial shape + unit='V', + setpoint_names=('Time',), + setpoint_labels=('Time',), + setpoint_units=('s',), + docstring='Holds an acquired (part of the) data buffer of one channel.') + + self.name = name + self._instrument = instrument + self._capture_parameter = capture_parameter + + def get(self): + try: + capture_data = self._instrument.buffer.get_cached_capture_data(self._capture_parameter) + except KeyError: + raise ValueError(f"Cannot return data for parameter {self._capture_parameter}. Please prepare for " + f"readout by calling 'get_capture_data' with appropriate configuration settings") + + data_len = len(capture_data) + self.shape = (data_len, ) + self.setpoint_units = ('',) + self.setpoint_names = ('trig_events',) + self.setpoint_labels = ('Trigger event number',) + self.setpoints = (tuple(np.arange(0, data_len)),) + + return capture_data + + class SR86xBuffer(InstrumentChannel): """ The buffer module for the SR86x driver. This driver has been verified to work with the SR860 and SR865. @@ -78,7 +111,7 @@ def __init__(self, parent: qcodes.instrument, name: str) ->None: ) self.bytes_per_sample = 4 - self._capture_data = [] + self._capture_data = dict() @staticmethod def _set_capture_len_parser(value: int) -> int: @@ -145,13 +178,16 @@ def stop_capture(self): """ self.write("CAPTURESTOP") - def get_cached_capture_data(self) ->list: + def get_cached_capture_data(self, parameter: str) ->np.array: """ Retrieve the capture data from the last readout + + Args: + parameter (str) """ - return self._capture_data + return self._capture_data[parameter] - def perform_capture_data(self, sample_count: int) -> dict: + def get_capture_data(self, sample_count: int) -> dict: """ Read capture data from the buffer. @@ -166,6 +202,9 @@ def perform_capture_data(self, sample_count: int) -> dict: n_variables = len(capture_variables) total_size_in_kb = int(np.ceil(n_variables * sample_count * self.bytes_per_sample / 1024)) + # We will samples one kb more then strictly speaking required and trim the data length to the requested + # sample count. In this way, we are always sure that the user requested number of samples is returned. + total_size_in_kb += 1 if total_size_in_kb > 64: raise ValueError("Number of samples specified is larger then the buffer size") @@ -198,7 +237,7 @@ def capture_samples(self, sample_count: int) ->dict: time.sleep(capture_time) self.stop_capture() - return self.perform_capture_data(sample_count) + return self.get_capture_data(sample_count) class SR86x(VisaInstrument): @@ -466,11 +505,12 @@ def __init__(self, name, address, max_frequency, reset=False, **kwargs): buffer = SR86xBuffer(self, "{}_buffer".format(self.name)) self.add_submodule("buffer", buffer) - self.add_parameter( - 'buffer_values', - label="cached capture data", - get_cmd=self.buffer.get_cached_capture_data - ) + for parameter_name in ["X", "Y", "R", "T"]: + self.add_parameter( + f'buffer_values_{parameter_name}', + capture_parameter=parameter_name, + parameter_class=SR86xBufferReadout + ) self.input_config() self.connect_message() diff --git a/tmp_debug.py b/tmp_debug.py new file mode 100644 index 00000000000..99b73862854 --- /dev/null +++ b/tmp_debug.py @@ -0,0 +1,32 @@ +import time + + +import qcodes +from qcodes.instrument_drivers.stanford_research.SR860 import SR860 +from qcodes.instrument_drivers.QuTech.IVVI import IVVI + +def main(): + sr = SR860("sr", "GPIB0::4::INSTR") + ivvi = IVVI("ivvi", "COM4") + + sr.buffer.capture_config("X,Y") + + def send_trigger(): + ivvi.trigger() + time.sleep(0.1) + + n_samples = 100 + sr.buffer.start_capture("ONE", "SAMP") + + time.sleep(0.1) + for _ in range(n_samples): + send_trigger() + + sr.buffer.stop_capture() + sr.buffer.get_capture_data(n_samples) + meas = qcodes.Measure(sr.buffer_values_X) + data = meas.run() + + +if __name__ == "__main__": + main() From e9adfbd7588bd9c53ba8118d6d43c90f16212404 Mon Sep 17 00:00:00 2001 From: sohailc Date: Tue, 28 Nov 2017 11:55:27 +0100 Subject: [PATCH 49/77] qcodes Measure finally works --- .../stanford_research/SR86x.py | 47 +++++++++---------- tmp_debug.py | 2 +- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py index fb20f9042b9..91368d335af 100644 --- a/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -23,24 +23,25 @@ def __init__(self, name, instrument, capture_parameter): docstring='Holds an acquired (part of the) data buffer of one channel.') self.name = name - self._instrument = instrument + self._capture_data = None self._capture_parameter = capture_parameter - def get(self): - try: - capture_data = self._instrument.buffer.get_cached_capture_data(self._capture_parameter) - except KeyError: - raise ValueError(f"Cannot return data for parameter {self._capture_parameter}. Please prepare for " - f"readout by calling 'get_capture_data' with appropriate configuration settings") + def prepare_readout(self, capture_data): + self._capture_data = capture_data data_len = len(capture_data) - self.shape = (data_len, ) + self.shape = (data_len,) self.setpoint_units = ('',) self.setpoint_names = ('trig_events',) self.setpoint_labels = ('Trigger event number',) self.setpoints = (tuple(np.arange(0, data_len)),) - return capture_data + def get(self): + if self._capture_data is None: + raise ValueError(f"Cannot return data for parameter {self._capture_parameter}. Please prepare for " + f"readout by calling 'get_capture_data' with appropriate configuration settings") + + return self._capture_data class SR86xBuffer(InstrumentChannel): @@ -110,6 +111,13 @@ def __init__(self, parent: qcodes.instrument, name: str) ->None: unit="kB" ) + for parameter_name in ["X", "Y", "R", "T"]: + self.add_parameter( + f'buffer_values_{parameter_name}', + capture_parameter=parameter_name, + parameter_class=SR86xBufferReadout + ) + self.bytes_per_sample = 4 self._capture_data = dict() @@ -178,15 +186,6 @@ def stop_capture(self): """ self.write("CAPTURESTOP") - def get_cached_capture_data(self, parameter: str) ->np.array: - """ - Retrieve the capture data from the last readout - - Args: - parameter (str) - """ - return self._capture_data[parameter] - def get_capture_data(self, sample_count: int) -> dict: """ Read capture data from the buffer. @@ -215,7 +214,10 @@ def get_capture_data(self, sample_count: int) -> dict: values = values[values != 0] data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} - self._capture_data = data + + for capture_variable in capture_variables: + buffer_parameter = getattr(self, f"buffer_values_{capture_variable}") + buffer_parameter.prepare_readout(data[capture_variable]) return data @@ -505,13 +507,6 @@ def __init__(self, name, address, max_frequency, reset=False, **kwargs): buffer = SR86xBuffer(self, "{}_buffer".format(self.name)) self.add_submodule("buffer", buffer) - for parameter_name in ["X", "Y", "R", "T"]: - self.add_parameter( - f'buffer_values_{parameter_name}', - capture_parameter=parameter_name, - parameter_class=SR86xBufferReadout - ) - self.input_config() self.connect_message() diff --git a/tmp_debug.py b/tmp_debug.py index 99b73862854..d3473259af6 100644 --- a/tmp_debug.py +++ b/tmp_debug.py @@ -24,7 +24,7 @@ def send_trigger(): sr.buffer.stop_capture() sr.buffer.get_capture_data(n_samples) - meas = qcodes.Measure(sr.buffer_values_X) + meas = qcodes.Measure(sr.buffer.buffer_values_X) data = meas.run() From d18eaf018709e913e074242f9640da9e65001f28 Mon Sep 17 00:00:00 2001 From: sohail chatoor Date: Tue, 28 Nov 2017 13:13:37 +0100 Subject: [PATCH 50/77] 1) Names more logical 2) type hints 3) Doc strings --- .../stanford_research/SR86x.py | 46 +++++++++++++------ tmp_debug.py | 2 +- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py index 91368d335af..9faf0c73bb4 100644 --- a/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -2,7 +2,6 @@ import time import logging -import qcodes from qcodes import VisaInstrument from qcodes.instrument.channel import InstrumentChannel from qcodes.utils.validators import Numbers, Ints, Enum @@ -12,11 +11,24 @@ class SR86xBufferReadout(ArrayParameter): - def __init__(self, name, instrument, capture_parameter): + """ + The parameter array that holds read out data. We need this to be compatible with qcodes.Measure + + Args + ---- + name (str) + instrument (SR86x): This argument is unused, but needed because the add_parameter method of the Instrument + base class adds this as a kwarg. + """ + def __init__(self, name: str, instrument: 'SR86x') ->None: + + unit = "deg" + if name in ["X", "Y", "R"]: + unit = "V" super().__init__(name, shape=(1,), # dummy initial shape - unit='V', + unit=unit, setpoint_names=('Time',), setpoint_labels=('Time',), setpoint_units=('s',), @@ -24,21 +36,30 @@ def __init__(self, name, instrument, capture_parameter): self.name = name self._capture_data = None - self._capture_parameter = capture_parameter - def prepare_readout(self, capture_data): + def prepare_readout(self, capture_data: np.array) ->None: + """ + Prepare this parameter for readout. + + Args + ---- + capture_data (np.array) + """ self._capture_data = capture_data data_len = len(capture_data) self.shape = (data_len,) self.setpoint_units = ('',) - self.setpoint_names = ('trig_events',) - self.setpoint_labels = ('Trigger event number',) + self.setpoint_names = ('sample_nr',) + self.setpoint_labels = ('Sample number',) self.setpoints = (tuple(np.arange(0, data_len)),) - def get(self): + def get(self) ->None: + """ + Public method to access the capture data + """ if self._capture_data is None: - raise ValueError(f"Cannot return data for parameter {self._capture_parameter}. Please prepare for " + raise ValueError(f"Cannot return data for parameter {self.name}. Please prepare for " f"readout by calling 'get_capture_data' with appropriate configuration settings") return self._capture_data @@ -50,7 +71,7 @@ class SR86xBuffer(InstrumentChannel): For reference, please consult the SR860 manual: http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf """ - def __init__(self, parent: qcodes.instrument, name: str) ->None: + def __init__(self, parent: 'SR86x', name: str) ->None: super().__init__(parent, name) self._parent = parent @@ -113,8 +134,7 @@ def __init__(self, parent: qcodes.instrument, name: str) ->None: for parameter_name in ["X", "Y", "R", "T"]: self.add_parameter( - f'buffer_values_{parameter_name}', - capture_parameter=parameter_name, + parameter_name, parameter_class=SR86xBufferReadout ) @@ -216,7 +236,7 @@ def get_capture_data(self, sample_count: int) -> dict: data = {k: v for k, v in zip(capture_variables, values.reshape((-1, n_variables)).T)} for capture_variable in capture_variables: - buffer_parameter = getattr(self, f"buffer_values_{capture_variable}") + buffer_parameter = getattr(self, capture_variable) buffer_parameter.prepare_readout(data[capture_variable]) return data diff --git a/tmp_debug.py b/tmp_debug.py index d3473259af6..45dd8f29575 100644 --- a/tmp_debug.py +++ b/tmp_debug.py @@ -24,7 +24,7 @@ def send_trigger(): sr.buffer.stop_capture() sr.buffer.get_capture_data(n_samples) - meas = qcodes.Measure(sr.buffer.buffer_values_X) + meas = qcodes.Measure(sr.buffer.X) data = meas.run() From 4d6ddef9c5b9afacd5dd25ed9546b1a86e8add31 Mon Sep 17 00:00:00 2001 From: sohailc Date: Tue, 28 Nov 2017 13:20:32 +0100 Subject: [PATCH 51/77] Updated example notebook --- ...ple_with_SR86x_with_buffered_readout.ipynb | 852 +++++++++++++++++- tmp_debug.py | 32 - 2 files changed, 827 insertions(+), 57 deletions(-) delete mode 100644 tmp_debug.py diff --git a/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb b/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb index 497d4892f09..3e4cae95174 100644 --- a/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb +++ b/docs/examples/driver_examples/QCodes_example_with_SR86x_with_buffered_readout.ipynb @@ -2,10 +2,11 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ + "%matplotlib notebook\n", "import sys \n", "sys.path.append(r\"C:\\Users\\Administrator\\Documents\\development\\qcodes_dev\")\n", "\n", @@ -27,7 +28,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Stanford_Research_Systems SR860 (serial:003101, firmware:V1.47) in 0.15s\n" + "Connected to: Stanford_Research_Systems SR860 (serial:003101, firmware:V1.47) in 0.14s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Administrator\\Documents\\development\\qcodes_dev\\qcodes\\instrument\\parameter.py:207: UserWarning: Wrapping get method, original get method will not be directly accessible. It is recommended to define get_raw in your subclass instead.\n", + " warnings.warn('Wrapping get method, original get method will not '\n" ] } ], @@ -44,7 +53,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Initialized IVVI-rack in 0.03s\n" + "Initialized IVVI-rack in 0.02s\n" ] }, { @@ -97,9 +106,9 @@ "outputs": [ { "data": { - "image/png": "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\n/wNJDeuWE8jqrgAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaMAAAD8CAYAAADaOstiAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8FeXZ//HPlYQQloR9CWtQUARkkQi4ddGquGLrBm64\nL5Vqfeyi7WM321/V9qm1VmtVUEQFFLWmWkUr7pYlyBrWsAjIFrawZr9+f5xBj2mWoyZMcs73/Xrx\nypk5M/dccwby5Z65z4y5OyIiImFKCrsAERERhZGIiIROYSQiIqFTGImISOgURiIiEjqFkYiIhE5h\nJCIioVMYiYhI6BRGIiISupSwC2gs2rdv71lZWWGXISLSqMydO3ebu3eobTmFUYyysrLIzc0NuwwR\nkUbFzD6JZTmdphMRkdApjEREJHQKIxERCZ3CSEREQqcwEhGR0CmMREQkdAojEREJncJIRESqtKeo\nlF/l5LG7qLTet6UwEhGR/7KqYC/nPfQhk2Z+wpw1O+p9e7oDg4iIfMG/l2zhtqnzSU1J4plrhzPi\nsHb1vk2FkYiIAODu/P291dzz2jIGdmvFI5cNpUvrZodk2wojERGhrLyCX+bk8cysdZw9MJM/XjiI\ntCbJh2z7CiMRkQS3v6SMcc/OY8ayrdz4zcP5yelHkpRkh7QGhZGISAI7UFLO1U/OYfaaHdx93gAu\nH9EzlDoURiIiCaqotJxrn4oE0f0XD2bU4K6h1aIwEhFJQEWl5Vw/aS4frdrOHy8YFGoQgb5nJCKS\ncCoqnNufW8B7Kwq49/yBnD+0W9glKYxERBLNH95YzquLNvGzM/tyUXb3sMsBFEYiIgllyux1/O2d\nVVw6vAfXnXRY2OV8RmEkIpIgPszfxs//sZhvHtGBX5/bH7NDO3y7JgojEZEEsKnwAD+YPI/D2rfg\nr5cMISW5Yf36b1jViIhInSstr2Dcs/MoLi3nkcuHkp7WJOyS/ouGdouIxLl7X1vG3E928uCYIRze\noWXY5VRJPSMRkTg2PW8zj3+whrHH9eScQV3CLqdaCiMRkTi1ubCIn0xbyNFdW/Gzs44Ku5waKYxE\nROJQRYXzo+cXUFJWwQOjB9M05dDdgfuriCmMzGykmS03s3wzu6OK95ua2dTg/VlmlhX13p3B/OVm\ndnptbZrZeDNbYGYLzWyambWstK0LzMzNLDuYPtXM5prZouDnyVXUl2Nmi6Om25rZm2a2MvjZJpbP\nQUSksZjw4Ro+yN/GXWf347AGep0oWq1hZGbJwEPAGUA/YIyZ9au02DXATnfvDdwP3Bus2w8YDfQH\nRgIPm1lyLW3e5u6D3H0gsA4YF1VLOnALMCtq29uAc9z9aGAsMKlS/d8D9laq9w7gLXfvA7wVTIuI\nxIVlm3dz3+vL+c5RnRgzrGHcYaE2sfSMhgH57r7a3UuAKcCoSsuMAiYGr6cBp1jk21SjgCnuXuzu\na4D8oL1q23T33QDB+s0Aj9rO3cB9QNHBGe4+z903BpN5QJqZNQ3aaAn8D/DbGuqdCJwXw+cgItLg\nFZWW88Mp88lolsI95x/doL7YWpNYwqgrsD5qekMwr8pl3L0MKATa1bBujW2a2RPAZqAv8GAwbwjQ\n3d1fqaHW84F57l4cTN8N/B+wv9Jyndx9U1DvJqBjDW2KiDQaf5i+nGWb9/CHCwbRvmXTsMuJWSxh\nVFWseozLfNn5kRfuVwFdgKXAxWaWROT03+3VFmnWn8jpwRuC6cFAb3d/qbp1amNm15tZrpnlFhQU\nfNVmREQOiQ9WbmP8B2u44riefLtv4/o/dixhtAGIPunYDdhY3TJmlgK0AnbUsG6tbbp7OTCVSG8n\nHRgAvGNma4ERQE7UIIZuwEvAFe6+KmjiOGBosPwHwBFm9k7w3hYzywzWzQS2VrXj7v6ou2e7e3aH\nDh2qWkREpEHYua+E25+fz+EdWnDnGQ17GHdVYgmjOUAfM+tlZqlEBiTkVFomh8jgAYALgBnu7sH8\n0cFou15AH2B2dW1aRG/47JrROcAydy909/bunuXuWcBM4Fx3zzWz1sCrwJ3u/uHBgtz9b+7eJVj+\nRGCFu3+rinrHAi/H8DmIiDRI7s6dLy5ix74SHhg9hGapDXsYd1VqvR2Qu5eZ2ThgOpAMTHD3PDP7\nDZDr7jnAeGCSmeUT6RGNDtbNM7PngCVAGXBz0OOhmjaTgIlmlkHkVN4C4KZaShwH9AbuMrO7gnmn\nuXuVvZ3APcBzZnYNkRF7F9b2OYiINFRPz/yE1/M287Mz+zKga6uwy/lKLNKBkdpkZ2d7bm5u2GWI\niHzB4k8L+d7DH3FC73aMH3ssSUkNa/Scmc119+zaltMdGEREGqm9xWWMe/Zj2rRowv9dNLjBBdGX\nobt2i4g0Qu7Oz19axLod+5l83QjatkgNu6SvRT0jEZFG6IWPP+Xl+Rv54XeOYPhh7cIu52tTGImI\nNDJrtu3jFy8vZnivttz87d5hl1MnFEYiIo1ISVkFt0yeR2pKEn8ePZjkRnydKJquGYmINCJ/fGM5\niz4t5O+XDyWzVbOwy6kz6hmJiDQSL8//lEffW81lI3pwev/OYZdTpxRGIiKNwLx1O/nxtIUM69WW\nX5zdP+xy6pzCSESkgdu46wDXT5pL54w0HrlsKKkp8ferW9eMREQasP0lZVz3VC4HSsp55trhjf77\nRNWJv3gVEYkTFRXO/0xdwNJNu3lwzBCO6JQedkn1RmEkItJA3f/vFcENUI9qdM8n+rIURiIiDdDL\n8z/lwRn5XJzdnWtO7BV2OfVOYSQi0sDM/eTzkXN3nzeAyOPd4pvCSESkAVm3fT/XPZVLl1bxO3Ku\nKomxlyIijUDh/lKufHI2Fe48cdWwuB05VxWFkYhIA1BSVsGNT89lw44DPHp5Nr3atwi7pENK3zMS\nEQlZRYXz42kL+M/q7dx/8SCG9WobdkmHnHpGIiIhu3f6Ml6ev5Efn34k3x3SLexyQqEwEhEJ0ZMf\nruHv70Zufvr9bx0edjmhURiJiIQkZ8FGfv3KEk7t14lfn5sYQ7irozASEQnBv5ds4X+mzufYrLb8\nZfSQuHlI3lelMBIROcQ+zN/G95/9mP5dMhg/NptmqclhlxQ6hZGIyCGUu3YH1z2VS692LXjyqmGk\npzUJu6QGQWEkInKIfLxuJ2MnzKZTRhqTrhlGmwT6UmttFEYiIofAgvW7GDt+Nu3TmzL5uhF0zEgL\nu6QGRWEkIlLP5q/fxeXjZ9G6RRMmXzeCzq0URJUpjERE6tG7KwoY8+hMWjVvwrPXjqBL62Zhl9Qg\n6XZAIiL15OX5n3L7cwvo0ymdiVcfS8d09YiqE1PPyMxGmtlyM8s3szuqeL+pmU0N3p9lZllR790Z\nzF9uZqfX1qaZjTezBWa20MymmVnLStu6wMzczLKD6VPNbK6ZLQp+nhy17OtBW3lm9oiZJQfzB5nZ\nf4J1/mlmGbF/ZCIiNXN3Hno7n1unzCc7qw1TbxihIKpFrWEU/AJ/CDgD6AeMMbN+lRa7Btjp7r2B\n+4F7g3X7AaOB/sBI4GEzS66lzdvcfZC7DwTWAeOiakkHbgFmRW17G3COux8NjAUmRb13kbsPAgYA\nHYALg/mPA3cE67wE/Li2z0FEJBb7isv4/jMf84fpyzl3UBeevGoYGRq+XatYekbDgHx3X+3uJcAU\nYFSlZUYBE4PX04BTLHJfi1HAFHcvdvc1QH7QXrVtuvtugGD9ZoBHbedu4D6g6OAMd5/n7huDyTwg\nzcyaRrdF5HRkalRbRwLvBa/fBM6P4XMQEanRmm37+O7DHzI9bzM/P/MoHhg9mLQm+kJrLGIJo67A\n+qjpDcG8Kpdx9zKgEGhXw7o1tmlmTwCbgb7Ag8G8IUB3d3+lhlrPB+a5e3FUW9OBrcAeIkEJsBg4\nN3h9IdC9hjZFRGr12qJNnPPgB2zdU8xTVw/num8cltD3mvuyYgmjqj5Nj3GZLzs/8sL9KqALsBS4\n2MySiJz+u73aIs36Ezk9eMMXGnU/HcgEmgIHryddDdxsZnOBdKCkmjavN7NcM8stKCiobtMiksBK\nyir4zT+XcNMzH3N4x5a8estJnNinfdhlNTqxhNEGvthz6AZsrG4ZM0sBWgE7ali31jbdvRyYSqS3\nk07kus87ZrYWGAHkRA1i6Ebk2s8V7r6q8g64exGQw+enApe5+2nuPhSYDPzXOsFyj7p7trtnd+jQ\noapFRCSBbdx1gNGP/ocJH67hyuOzeP6G4+iqodtfSSxhNAfoY2a9zCyVyICEnErL5BAZPABwATDD\n3T2YPzoYbdcL6APMrq5Ni+gNn10zOgdY5u6F7t7e3bPcPQuYCZzr7rlm1hp4FbjT3T88WJCZtTSz\nzOB1CnAmsCyY7hj8TAL+F3gk5k9MRITI94fO+sv7LN+8hwfHDOFX5/YnNUVf3fyqav2ekbuXmdk4\nYDqQDExw9zwz+w2Q6+45wHhgkpnlE+kRjQ7WzTOz54AlQBlwc9DjoZo2k4CJwVBrAxYAN9VS4jig\nN3CXmd0VzDstWD8nGMyQDMzg89AZY2Y3B69fBJ6o7XMQEYHIsO0HZ+Rz/79XcETHdB6+7BgO79Cy\n9hWlRhbpwEhtsrOzPTc3N+wyRCRERaXl/HjaQv65YCPfHdKV//fdo/X4h1qY2Vx3z65tOd2BQUQk\nBlt3F3HdpLks3LCLn47sy43f1Gi5uqQwEhGpxYad+xnz2Ey27SnhkcuGcnr/zmGXFHcURiIiNVi3\nPRJEe4pKmXz9CAZ3bx12SXFJYSQiUo212/ZxyWMz2VdSzrPXjWBA11ZhlxS3FEYiIlXYuOsAlzw2\nkwOl5Uy+bgT9uuh+yvVJg+JFRCrZua+EKybMZk9RGU9fO1xBdAioZyQiEmVfcRlXPTmHdTv289TV\nw+jfRafmDgX1jEREAuUVzrhnP2bhhl08OGYIIw5rF3ZJCUM9IxGRwIMzVvL28gLuPm+Ahm8fYuoZ\niYgA768s4IG3VvK9Y7py2fAeYZeTcBRGIpLwNhUe4NYp8+nTsSW/PW+A7qwQAoWRiCS00vIKfvDs\nPIpLy/nbZUNpnqqrF2HQpy4iCe3e15aR+8lO/jJmiO6+HSL1jEQkYb2+eBOPf7CGscf15NxBXcIu\nJ6EpjEQkIa3dto8fP7+QQd1b87Ozjgq7nISnMBKRhFNUWs73n/mYpCTjoUuG0DRFzyQKm64ZiUjC\nuee1ZSzZtJsJV2bTrU3zsMsR1DMSkQTz1tItPPnRWq46IYuT+3YKuxwJKIxEJGFs3V3Ej6ct5KjM\nDO44o2/Y5UgUhZGIJISKCud/nlvA/pIyHhwzWNeJGhiFkYgkhEffX80H+dv45Tn96d0xPexypBKF\nkYjEvQXrd/HH6cs58+jOjD62e9jlSBUURiIS1/YWl3HLlHl0ykjj998dqPvONVAa2i0ice0X/1jM\n+h37mXrDcbRq3iTscqQa6hmJSNyaOmcdL877lB+c3Idjs9qGXY7UQGEkInFp4YZd3PVyHif1ac8t\np/QJuxyphcJIROLOjn0l3PT0x3Ro2ZQHRg8hOUnXiRo6XTMSkbhSXuHcMnkeBXuLeeHG42nbIjXs\nkiQG6hmJSFy5+5UlfJC/jd+OGsDR3VqFXY7ESGEkInFjwgdrePKjtVx3Ui8u0veJGpWYwsjMRprZ\ncjPLN7M7qni/qZlNDd6fZWZZUe/dGcxfbman19ammY03swVmttDMpplZy0rbusDM3Myyg+lTzWyu\nmS0Kfp4ctezrQVt5ZvaImSUH8web2Uwzm29muWY2LPaPTEQaojfyNnP3q0s4vX8n7jxDzydqbGoN\no+AX+EPAGUA/YIyZ9au02DXATnfvDdwP3Bus2w8YDfQHRgIPm1lyLW3e5u6D3H0gsA4YF1VLOnAL\nMCtq29uAc9z9aGAsMCnqvYvcfRAwAOgAXBjMvw/4tbsPBn4RTItII7Vwwy5unTKfgV1b8eeLh5Ck\nAQuNTiw9o2FAvruvdvcSYAowqtIyo4CJwetpwCkW+ZrzKGCKuxe7+xogP2iv2jbdfTdAsH4zwKO2\nczeR4Cg6OMPd57n7xmAyD0gzs6bRbREZqJEa1ZYDGcHrVsDB9UWkkVm3fT9XPzmHti1SeWxsNs1S\ndQPUxiiWMOoKrI+a3hDMq3IZdy8DCoF2NaxbY5tm9gSwGegLPBjMGwJ0d/dXaqj1fGCeuxdHtTUd\n2ArsIRKUAD8E/mBm64E/AndW1ZiZXR+cxsstKCioYbMiEoYd+0oY+8RsyiqciVcPo2N6WtglyVcU\nSxhV1d/1GJf5svMjL9yvAroAS4GLzSyJyOm/26st0qw/kdODN3yhUffTgUygKXDwetJNRE4Hdgdu\nA8ZX1aa7P+ru2e6e3aFDh+o2LSIhOFBSzjUT57Bx1wEevyKb3h1b1r6SNFixhNEGIHpYSjf++7TW\nZ8uYWQqRU187ali31jbdvRyYSqS3k07kus87ZrYWGAHkRA1i6Aa8BFzh7qsq74C7FwE5fH56cSzw\nYvD6eSKnDUWkkSgrr+AHk+cxf/0uHhg9hGzd6qfRiyWM5gB9zKyXmaUSGZCQU2mZHCK/4AEuAGa4\nuwfzRwej7XoBfYDZ1bVpEb3hs2tG5wDL3L3Q3du7e5a7ZwEzgXPdPdfMWgOvAne6+4cHCzKzlmaW\nGbxOAc4ElgVvbwS+Gbw+GVgZw+cgIg2Au/PLnDz+vXQLvzqnPyMHdA67JKkDtd6Bwd3LzGwcMB1I\nBia4e56Z/QbIdfccIqe5JplZPpEe0ehg3Twzew5YApQBNwc9HqppMwmYaGYZRE7lLSBySq0m44De\nwF1mdlcw77Rg/ZxgMEMyMAN4JHj/OuCBIKSKgOtr+xxEpGF4+J1VPDNrHTd+83DGHp8VdjlSRyzS\ngZHaZGdne25ubthliCS053LX85NpCzlvcBf+dNFgDeFuBMxsrrtn17ac7sAgIo3Cqws3cccLCzmp\nT3vuu2CQgijOKIxEpMF7e9lWbp0yj6E92/D3y4eSmqJfXfFGR1REGrSPVm3jxqfn0jcznfFXHkvz\nVD1sIB4pjESkwfpg5TaufnIOPds156mrh5ORpseGxyuFkYg0SO+uKOCaiXPIateCydeN0HOJ4pz6\nuyLS4Ly1dAs3Pf0xvTu25OlrhyuIEoB6RiLSoEybu4HrJ83lyM7pPHudgihRqGckIg3G399dxe9f\nW8YJvdvx98uzadlUv6IShY60iISuvML53atLmfDhGs4emMn/XTSIpil6FEQiURiJSKj2FJVyy+R5\nvL28gKtOyOKus/rpC60JSGEkIqFZv2M/10ycw+qCffzuuwO4dHjPsEuSkCiMROSQc3demvcpv3w5\nj6Qk46mrh3F87/ZhlyUhUhiJyCG1Y18JP39pEa8t3kx2zzb86aLB9GjXPOyyJGQKIxE5JMornKlz\n1vPHN5azp6iUn47sy/XfOIxkXR8SFEYicgjMWbuDX76cx5JNuxmW1ZZfj+rPUZkZYZclDYjCSETq\nzd7iMu55bSlPz1xHl1ZpPDhmCGcPzCTyIGeRzymMRKRevLuigJ+9uIiNhQe45sRe3H7aEbrjtlRL\nfzNEpE4V7i/l7leXMG3uBg7v0IJpNx7P0J5twi5LGjiFkYjUmTfyNvPzfyxmx74Svv+tw7nllD6k\nNdGdFKR2CiMR+dqKy8r5f68uZeJ/PuGozAyeuPJYBnRtFXZZ0ogojETka9mwcz83PzuPBet3cc2J\nvfjpyL56LLh8aQojEfnK5n6yg2sm5lJe7vzt0mM44+jMsEuSRkphJCJfyVtLt3Dzsx+T2aoZE648\nll7tW4RdkjRiCiMR+dKez13PHS8uol9mBk9cdSztWzYNuyRp5BRGIvKlPJe7np9MW8iJvdvzyOVD\n9QA8qRP6WyQiMXsjbzN3vLCQk/q05/Gx2XoAntQZDXkRkZjMWr2dcZPnMbBbax65bKiCSOqUwkhE\napW3sZBrJ+bSo21znrjyWFro1JzUMYWRiNTok+37GDthDulpKTx19TDatEgNuySJQzGFkZmNNLPl\nZpZvZndU8X5TM5savD/LzLKi3rszmL/czE6vrU0zG29mC8xsoZlNM7OWlbZ1gZm5mWUH06ea2Vwz\nWxT8PDlq2deDtvLM7BEzSw7mTzWz+cGftWY2P/aPTCRxbN1dxOXjZ1NeUcFT1wynS+tmYZckcarW\nMAp+gT8EnAH0A8aYWb9Ki10D7HT33sD9wL3Buv2A0UB/YCTwsJkl19Lmbe4+yN0HAuuAcVG1pAO3\nALOitr0NOMfdjwbGApOi3rvI3QcBA4AOwIUA7n6xuw9298HAC8CLtX0OIolmd1EpY5+Yw7a9xTxx\n1TB6d2xZ+0oiX1EsPaNhQL67r3b3EmAKMKrSMqOAicHracApFnlgyShgirsXu/saID9or9o23X03\nQLB+M8CjtnM3cB9QdHCGu89z943BZB6QZmZNo9siMmowtVJbB7dxETA5hs9BJGEUl5Vz/VO55G/d\nwyOXDWVw99ZhlyRxLpYw6gqsj5reEMyrchl3LwMKgXY1rFtjm2b2BLAZ6As8GMwbAnR391dqqPV8\nYJ67F0e1NR3YCuwhEpTRTgK2uPvKGtoUSSgVFc6Pnl/IzNU7+MMFg/jGER3CLkkSQCxhVNUjGT3G\nZb7s/MgL96uALsBS4GIzSyJy+u/2aos060/k9OANX2jU/XQgE2gKnFxptTHU0Csys+vNLNfMcgsK\nCqpbTCSu3PP6Mv65YCM/HdmX84ZU/n+nSP2IJYw2AN2jprsBG6tbxsxSgFbAjhrWrbVNdy8HphLp\n7aQTue7zjpmtBUYAOVGDGLoBLwFXuPuqyjvg7kVADlGnF4M6vxdso0ru/qi7Z7t7docO+t+hxL8n\nPlzDo++t5orjenLjNw8LuxxJILGE0Rygj5n1MrNUIgMSciotk0Nk8ADABcAMd/dg/uhgtF0voA8w\nu7o2LaI3fHY95xxgmbsXunt7d89y9yxgJnCuu+eaWWvgVeBOd//wYEFm1tLMMoPXKcCZwLKomr8T\ntL0hpk9KJM69tmgTv3llCaf168Qvz+lP5J+gyKFR6zfX3L3MzMYB04FkYIK755nZb4Bcd88BxgOT\nzCyfSI9odLBunpk9BywByoCbgx4P1bSZBEw0swwip/IWADfVUuI4oDdwl5ndFcw7LVg/JxjMkAzM\nAB6JWm80GrggAsDsNTu4dep8junRhr+MGUJykoJIDi2LdGCkNtnZ2Z6bmxt2GSJ1buWWPZz/t49o\nn96UF248Xl9qlTplZnPdPbu25XQHBpEEtqpgL5c8PoumTZKZeJXuriDhURiJJKi12/ZxyWMzcXee\nvXY43ds2D7skSWC626FIAlq3fT9jHptJabkz+boR9OmUHnZJkuAURiIJJn/rHi59fBbFZRU8e+0I\njuysIJLwKYxEEsjiTwu5YsJsksyYcv0I+nbOCLskEUBhJJIw5qzdwdVPzCGjWROevnY4vdq3CLsk\nkc9oAINIAvjXok1c+vgsOqQ35fkbj1MQSYOjnpFIHHN3xn+wht/9aynH9GjDY1dk01bDt6UBUhiJ\nxKnS8gp+888lTJr5CWce3Zk/XTSYtCbJYZclUiWFkUgcKthTzM3PfMzstTu44RuH8dORfUnSLX6k\nAVMYicSZ+et3ceOkuew6UMIDowczarAeAyENn8JIJE5UVESuD903fRkd09N44abj6d+lVdhlicRE\nYSQSBwr2FHP78wt4b0UBp/fvxL3nD6R1cw1UkMZDYSTSyL25ZAt3vriQPUVl/Pa8AVw6vIeeRSSN\njsJIpJHaU1TK3a8s4bncDfTLzOCZawfr1j7SaCmMRBqht5Zu4Rcv57Gp8AA3f/twbj3lCFJT9B12\nabwURiKNyKbCA/wqJ4/peVvo07Elz994HEN7tg27LJGvTWEk0gjs2FfC399bxVMffYLj/GTkkVx7\n4mHqDUncUBiJNGBb9xQx8aO1PPnhWvaXljNqUBduP+1IPQhP4o7CSKSBcXcWbihk4kdr+efCjZRV\nOGcdnckPv9OH3h01QEHik8JIpAHYsHM/764o4KNV25m1ejvb9pbQIjWZS4f35Mrjs8jSXbYlzimM\nREJQUeHMW7+LN/I28/byrazYsheAzhlpnNSnA8cd3o6RAzqTkdYk5EpFDg2FkcghtGzzbqbMXs/r\nizezeXcRTZKNYb3aclF2d751ZEcO79BCX1iVhKQwEqlnFRXOjGVbmfDhGj5atZ3UlCS+eUQHfnr0\nkZzctxOtmqn3I6IwEqlH768s4Pf/WsaSTbvJbJXGT0f2Zcyw7rpvnEglCiORepC/dQ+//ucS3l+5\njW5tmnH/xYM4e2AXmiTre0EiVVEYidShigpnwodruG/6cpqnJvO/Zx3F5cf1pGmKnrAqUhOFkUgd\n+XTXAX703AL+s3o73zmqI7//3kA6pDcNuyyRRkFhJFIH3l6+ldumzqe0rIJ7zz+ai7K7a1ScyJeg\nMBL5GsornPvfXMFf387nqMwMHr70GHrpC6oiX1pMV1PNbKSZLTezfDO7o4r3m5rZ1OD9WWaWFfXe\nncH85WZ2em1tmtl4M1tgZgvNbJqZtay0rQvMzM0sO5g+1czmmtmi4OfJUcu+HrSVZ2aPmFly1Hs/\nCLafZ2b3xfZxiXxu654iLnt8Fn99O5+Ls7vz0vePVxCJfEW19oyCX+APAacCG4A5Zpbj7kuiFrsG\n2Onuvc1sNHAvcLGZ9QNGA/2BLsC/zeyIYJ3q2rzN3XcH2/4TMA64J5hOB24BZkVtextwjrtvNLMB\nwHSga/DeRe6+2yLnS6YBFwJTzOzbwChgoLsXm1nHmD8xEWDW6u2MmzyPPUWl/OGCgVyY3T3skkQa\ntVh6RsOAfHdf7e4lwBQiv8ijjQImBq+nAacEATAKmOLuxe6+BsgP2qu2zaggMqAZ4FHbuRu4Dyg6\nOMPd57n7xmAyD0gzs6bRbREJ3dSotm4C7nH34mC5rTF8DiJUVDiPvLuKSx6fRXrTFP5x8wkKIpE6\nEEsYdQXWR01v4POex38t4+5lQCHQroZ1a2zTzJ4ANgN9gQeDeUOA7u7+Sg21ng/MOxgywXrTga3A\nHiJBCXCIV2E+AAALLklEQVQEcFJwSvFdMzu2qsbM7HozyzWz3IKCgho2K4mgcH8p10/K5Z7XljGy\nf2deHncCfTtnhF2WSFyIJYyqGhLkMS7zZedHXrhfReS03lIip/uSgPuB26st0qw/kdODN3yhUffT\ngUygKXDwelIK0AYYAfwYeM6qGPrk7o+6e7a7Z3fo0KG6TUsCWLhhF2c9+D7vrijgV+f046+XDCFd\nNzEVqTOxhNEGIPo8RDdgY3XLmFkK0ArYUcO6tbbp7uXAVCK9nXRgAPCOma0lEiI5UYMYugEvAVe4\n+6rKO+DuRUAOn59e3AC86BGzgQqgfS2fgySgsvIK/jpjJd97+CMqKpznbjiOK0/opWHbInUsljCa\nA/Qxs15mlkpkQEJOpWVygLHB6wuAGe7uwfzRwWi7XkAfYHZ1bVpEb/jsmtE5wDJ3L3T39u6e5e5Z\nwEzgXHfPNbPWwKvAne7+4cGCzKylmWUGr1OAM4Flwdv/IOglBQMqUokMhBD5zNpt+7jo7//hj2+s\nYOSAzvzr1pMY0qNN2GWJxKVaR9O5e5mZjSMySi0ZmODueWb2GyDX3XOA8cAkM8sn0iMaHaybZ2bP\nAUuAMuDmoMdDNW0mARPNLIPIqbwFRAYb1GQc0Bu4y8zuCuadFqyfEwxmSAZmAI8E708AJpjZYqAE\nGBuEpwglZRU89v5q/vLWSpqmJPHA6MGMGlz5MqmI1CXT7+DYZGdne25ubthlSD2buXo7d/1jMSu3\n7mVk/8786tz+dG6VFnZZIo2Wmc119+zaltMdGESA+et3cf+bK3h3RQFdWzdj/NhsTjmqU9hliSQM\nhZEktMWfFnL/myt4a9lW2jRvwh1n9OWK43rSPFX/NEQOJf2Lk4S0dNNu/vzvFUzP20JGWgo/Ou0I\nrjyhFy2b6p+ESBj0L08SRlFpOdPzNvPMrHXMXrOD9KYp/PA7fbj6xF5k6DtDIqFSGEncy9+6lymz\n1/HCxxvYub+UHm2b85ORR3LJsB56/LdIA6EwkrhTXuHkbSzko1XbmbFsK7PX7CAlyTi1XycuGd6D\nEw5vT1KSvrQq0pAojCR0xWXlzF+3i42FBzhQUkFRaTnlFZ9/5SApyUhrkkSzJsk0SU7i4M0Pyiuc\notJyikorKDxQytrt+1izbR/5W/ayp7gMgD4dW/LTkX25YGg3PXVVpAFTGEkoVhfs5fW8zXywchtz\nP9lJcVnF124zs1UaWe1aMGpIF47Nastxh7WjY4a+IyTSGCiM5JDZXFjEtLnreWXhJpZt3gNA387p\nXDq8J8cd3o7eHVvSrEkyaU2SSEn+/E5V5eVOUVk5B0rKKS3/PLTMjGapyaSlJNGiaQppTZL/a5si\n0jgojKReuTvvrdzG0zM/YcayrZRXONk92/CLs/sxckBnurRuFlM7rdBoN5F4pjCSenEwhP705goW\nrN9F+5apXHfSYYwZ1p2e7fRobhH5IoVRyPYVl7F2+z5WFexj2abdLNu8h1UFe9lXXE5xaTnF5RWk\nN02hdfMmtG2RymHtW3JUZjpHZWYwpEcbUlNiufH6oVNe4by5ZDOPvb+GuZ/spGvrZtzzvaP53jHd\nGlytItJwKIwOkbLyCrbuKWZ1wT7mrdvJ/PW7WLyxkC27P3soLSlJRu+OLTm6ayvS05pERo+lGHuK\nyti1v4Rte0t4Y8lmpuZGHpLbvmUqF2Z3Z/Sx4fc2tu0t5qWPP2Xif9ayYecBurZuxm/PG8BF2d0V\nQiJSK4VRPbv/zRVMmbOOgj3FRI1WpnfHlpzQuz2Hd2hJVrsW9GrfgsM7tqBpSs0X4d2drXuKmbdu\nFy98vIFH31vN395ZxbFZbRg5IJMzvsR1mK9rd1Ep7ywv4KWPN/Deym2UVzjDerXlf8/qx6n9OpGs\n7/KISIz0CIkYfdVHSDyfu545a3fQuVUzMlul0a1NMwZ2a02rZnVzQb6qEWqDu7fmjAGdOWNAJj3a\nNa+T7QAU7i9l2ebdzF+/i7eXbyV37U7KKpwurdIYNaQr3x3SlSM6pdfZ9kSk8Yv1ERIKoxg1hucZ\nrdm2j38t2sTrizez6NNCAA7r0IIh3dswpEdrjuycTueMNDplpFV76qyiwtm2r5jNhUWs27GfpZt2\ns2zTHpZu2s3GwqLPluvbOZ1v9+3IyX07MrRHG93RQESqpDCqY40hjKKt37Gf1xdvZtaaHcxbt5Pt\n+0q+8H5GWuR7OWlNkkkyKCqtoKisnL1FZZRFnU9MTjIO79CCvp0zOCozg6My0+mXmaEvk4pITBRG\ndayxhVE0d2f9jgOs2b6PzYUH2FRYxM59JZ8FUIVDWkoSaU2SaZmWQmarNDpnpNG1TTN6d2xZ63Us\nEZHq6Emv8hkzo0e75nV6/UhEpC5pzK2IiIROYSQiIqFTGImISOgURiIiEjqFkYiIhE5hJCIioVMY\niYhI6BRGIiISOt2BIUZmVgB88hVXbw9sq8NyGotE3O9E3GdIzP1OxH2GL7/fPd29Q20LKYwOATPL\njeV2GPEmEfc7EfcZEnO/E3Gfof72W6fpREQkdAojEREJncLo0Hg07AJCkoj7nYj7DIm534m4z1BP\n+61rRiIiEjr1jEREJHQKo3pmZiPNbLmZ5ZvZHWHXUx/MrLuZvW1mS80sz8xuDea3NbM3zWxl8LNN\n2LXWNTNLNrN5ZvZKMN3LzGYF+zzVzFLDrrGumVlrM5tmZsuCY35cvB9rM7st+Lu92Mwmm1laPB5r\nM5tgZlvNbHHUvCqPrUX8JfjdttDMjvk621YY1SMzSwYeAs4A+gFjzKxfuFXVizLgdnc/ChgB3Bzs\n5x3AW+7eB3grmI43twJLo6bvBe4P9nkncE0oVdWvB4DX3b0vMIjI/sftsTazrsAtQLa7DwCSgdHE\n57F+EhhZaV51x/YMoE/w53rgb19nwwqj+jUMyHf31e5eAkwBRoVcU51z903u/nHweg+RX05diezr\nxGCxicB54VRYP8ysG3AW8HgwbcDJwLRgkXjc5wzgG8B4AHcvcfddxPmxJvJU7GZmlgI0BzYRh8fa\n3d8DdlSaXd2xHQU85REzgdZmlvlVt60wql9dgfVR0xuCeXHLzLKAIcAsoJO7b4JIYAEdw6usXvwZ\n+AlQEUy3A3a5e1kwHY/H+zCgAHgiOD35uJm1II6Ptbt/CvwRWEckhAqBucT/sT6oumNbp7/fFEb1\ny6qYF7fDF82sJfAC8EN33x12PfXJzM4Gtrr73OjZVSwab8c7BTgG+Ju7DwH2EUen5KoSXCMZBfQC\nugAtiJyiqizejnVt6vTvu8Kofm0AukdNdwM2hlRLvTKzJkSC6Bl3fzGYveVgtz34uTWs+urBCcC5\nZraWyOnXk4n0lFoHp3IgPo/3BmCDu88KpqcRCad4PtbfAda4e4G7lwIvAscT/8f6oOqObZ3+flMY\n1a85QJ9g1E0qkYueOSHXVOeCayXjgaXu/qeot3KAscHrscDLh7q2+uLud7p7N3fPInJcZ7j7pcDb\nwAXBYnG1zwDuvhlYb2ZHBrNOAZYQx8eayOm5EWbWPPi7fnCf4/pYR6nu2OYAVwSj6kYAhQdP530V\n+tJrPTOzM4n8jzkZmODuvwu5pDpnZicC7wOL+Pz6yc+IXDd6DuhB5B/0he5e+eJoo2dm3wJ+5O5n\nm9lhRHpKbYF5wGXuXhxmfXXNzAYTGbSRCqwGriLyH9u4PdZm9mvgYiIjR+cB1xK5PhJXx9rMJgPf\nInJn7i3AL4F/UMWxDYL5r0RG3+0HrnL33K+8bYWRiIiETafpREQkdAojEREJncJIRERCpzASEZHQ\nKYxERCR0CiMREQmdwkhEREKnMBIRkdD9f70//4uIMuGpAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -118,9 +127,9 @@ "outputs": [ { "data": { - "image/png": "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\nZjaosizvHnppZKQWac21a5fnWKUfTRn5Rvk9p0uB/1JYfzPwZmAV8CzwBy1iIGm9pLqk+v79+1tl\nMTPrSz13z4h8pHFmYXk5sK9dHklV4BTgxXm2bZf+AnBqitFc1pGW0XAJ8FBEPNdIiIjnImIqIqaB\nz3H4Zb1Gvs0RUYuI2tKlS1tlMTPrS704m+5BYDjNchsiv+Q13pRnHLgivb4MuC/yT0qNA6NpJtxK\nYBh4oF3MtM32FIMU886jLKPhcpou0Uk6o7D4a8CjC9gPZmYDo9sjo2qnDBExKekq4C4gA7ZExE5J\n1wH1iBgHbgFukzRBPloZTdvulLQV2AVMAldGxBRAq5ipyKuBMUnXAw+n2BxlGa8Ffhn4zaZm/a6k\nVeSX855qsd7MbKB1ezaduvWoh+NdrVaLer1edjXMzLrir7/5LFd+6SG+9ol381Nvev1Rx5G0IyJq\nnfL5CQxmZnaYmZFRD03tNjOzAdOLs+nMzGzAZFnvzaYzM7MB45GRmZmVrhefTWdmZgOmWsm7B4+M\nzMysNB4ZmZlZ6WbvGXkCg5mZlcSfMzIzs9JVM8+mMzOzklV9z8jMzMqWeTadmZmVzSMjMzMrXebZ\ndGZmVjaPjMzMrHSZn01nZmZl8+eMzMysdB4ZmZlZ6RoPSu2pe0aSVkvaLWlC0oYW60+UdEdaf7+k\nFYV116T03ZIu7hRT0soU44kUc+hVlPGUpG9JekRSvZD+Bkl3pzLulnTaQneYmdkg6LnZdJIy4Ebg\nEmAEuFzSSFO2dcCBiDgb2ARsTNuOAKPAOcBq4CZJWYeYG4FNETEMHEixj7iMQt3+eUSsiohaIW0D\ncG8q4960bGZmSS/OpjsPmIiIPRHxCjAGrGnKswa4Nb3eBlwoSSl9LCIORcSTwESK1zJm2uaCFIMU\nc+1RljGfYqxiGWZmBlQqQuqte0bLgKcLy3tTWss8ETEJHASWzLNtu/QlwEspRnNZR1oGQABfk7RD\n0vpCnjdFxLMp1rPA6fPuATOzAVStqGsjo+oC8qhFWnPt2uVpl96qE5wv/9GUAfDOiNgn6XTgbkmP\nR8TftcjfUurA1gOcddZZC93MzKwvZBUx3UMjo73AmYXl5cC+dnkkVYFTgBfn2bZd+gvAqSlGc1lH\nWgYR0fj9PPAVZi/fPSfpjBTrDOD5Vg2PiM0RUYuI2tKlS1tlMTPrW9VKpafuGT0IDKdZbkPkkwXG\n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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -175,9 +184,9 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -215,29 +224,822 @@ "metadata": {}, "outputs": [ { - "ename": "ValueError", - "evalue": "setting an array element with a sequence.", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mmeas\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqcodes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mMeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msr\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuffer_values\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmeas\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\measure.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, use_threads, quiet, station, **kwargs)\u001b[0m\n\u001b[0;32m 83\u001b[0m \u001b[1;31m# run the measurement as if it were a Loop\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 84\u001b[0m self._dummyLoop.run(use_threads=use_threads,\n\u001b[1;32m---> 85\u001b[1;33m station=station, quiet=True)\n\u001b[0m\u001b[0;32m 86\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 87\u001b[0m \u001b[1;31m# look for arrays that are unnecessarily nested, and un-nest them\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, use_threads, quiet, station, progress_interval, set_active, *args, **kwargs)\u001b[0m\n\u001b[0;32m 736\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mquiet\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 737\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdatetime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnow\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Started at %Y-%m-%d %H:%M:%S'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 738\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_run_wrapper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 739\u001b[0m \u001b[0mds\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdata_set\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 740\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36m_run_wrapper\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 785\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_run_wrapper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 786\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 787\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_run_loop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 788\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 789\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'data_set'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\loops.py\u001b[0m in \u001b[0;36m_run_loop\u001b[1;34m(self, first_delay, action_indices, loop_indices, current_values, **ignore_kwargs)\u001b[0m\n\u001b[0;32m 869\u001b[0m f(first_delay=delay,\n\u001b[0;32m 870\u001b[0m \u001b[0mloop_indices\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mnew_indices\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 871\u001b[1;33m current_values=new_values)\n\u001b[0m\u001b[0;32m 872\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 873\u001b[0m \u001b[1;31m# after the first action, no delay is inherited\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\actions.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, loop_indices, **ignore_kwargs)\u001b[0m\n\u001b[0;32m 165\u001b[0m \u001b[0mout_dict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mparam_id\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparam_out\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 166\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 167\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstore\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mout_dict\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 168\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 169\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\data\\data_set.py\u001b[0m in \u001b[0;36mstore\u001b[1;34m(self, loop_indices, ids_values)\u001b[0m\n\u001b[0;32m 386\u001b[0m \"\"\"\n\u001b[0;32m 387\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0marray_id\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mids_values\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 388\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0marray_id\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 389\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlast_store\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 390\u001b[0m if (self.write_period is not None and\n", - "\u001b[1;32m~\\Documents\\development\\qcodes_dev\\qcodes\\data\\data_array.py\u001b[0m in \u001b[0;36m__setitem__\u001b[1;34m(self, loop_indices, value)\u001b[0m\n\u001b[0;32m 339\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_update_modified_range\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmin_li\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmax_li\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 340\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 341\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__setitem__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mloop_indices\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 342\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 343\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__getitem__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mloop_indices\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mValueError\u001b[0m: setting an array element with a sequence." + "name": "stdout", + "output_type": "stream", + "text": [ + "DataSet:\n", + " location = 'data/2017-11-28/#001_{name}_13-17-08'\n", + " | | | \n", + " Measured | X | X | (100,)\n", + "acquired at 2017-11-28 13:17:08\n" ] } ], "source": [ - "meas = qcodes.Measure(sr.buffer_values)\n", + "meas = qcodes.Measure(sr.buffer.X)\n", "data = meas.run()" ] }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fig1 = plt.figure()\n", + "ax1 = fig1.add_subplot(111)\n", + "ax1.plot(makesinewf(N, 1), lw=3, alpha=0.5, color=(0.8, 0.5, 0), label='Wave')\n", + "ax1.plot(m1, lw=3, alpha=0.5, color=(0.2, 0.4, 0), label='Marker 1')\n", + "ax1.plot(m2, lw=3, alpha=0.5, color=(0, 0.5, 0.8), label='Marker 2')\n", + "ax1.set_ylim([-1.1, 1.1])\n", + "ax1.set_xlabel('No. of waveform points')\n", + "plt.legend()\n", + "ax2 = ax1.twiny()\n", + "ax2.plot(np.arange(N)/1e3, wf, lw=0)\n", + "ax2.set_xlabel('Time (mu s)')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Approach A " + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(45, )" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "awg1.visa_handle.write('MMEMory:CDIRectory \"C:\\\\Users\\\\OEM\\\\Documents\"')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "noOfseqs = 40\n", + "\n", + "pckd_wfs = []\n", + "#pckd_wf = np.zeros(N, dtype='uint16')\n", + "\n", + "chan1_list = []\n", + "for ii in range(noOfseqs):\n", + " pckd_wf = awg1.pack_waveform(makesinewf(N, 1+ii), m1, m2)\n", + " pckd_wfs.append(pckd_wf)\n", + " chan1_list.append('segm{:03d}ch1'.format(ii))\n", + "wfname_l = np.array([chan1_list], dtype='str')\n", + "packed_wfs = {}\n", + "\n", + "#packed_wfs.update\n", + "for name, wf_dummy in zip(wfname_l[0], pckd_wfs):\n", + " packed_wfs.update({name: wf_dummy})\n", + "\n", + "#\n", + "nrep_l = [1]*noOfseqs\n", + "wait_l = [0]*noOfseqs\n", + "goto_l = list(np.arange(2, noOfseqs+1))+[1]\n", + "logic_jump = [0]*noOfseqs\n", + "channel_cfg = {}\n", + "awg_file = awg1.generate_awg_file(packed_wfs, wfname_l, nrep_l,\n", + " wait_l, goto_l, logic_jump, channel_cfg)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Transferred and loaded 40 10000-point waveforms in 6.195 seconds.\n" + ] + } + ], + "source": [ + "awgfilename = 'manySinesIncreasingFreq.awg'\n", + "t1 = time.time()\n", + "awg1.send_awg_file(awgfilename, awg_file)\n", + "loadfrom = '{}{}'.format(awg1.visa_handle.query('MMEMory:CDIRectory?').replace('\"','').replace('\\n', '\\\\'), awgfilename)\n", + "awg1.load_awg_file(loadfrom)\n", + "awg1.visa_handle.query('*IDN?') # a dummy query to get the timing right\n", + "t2 = time.time()\n", + "print('Transferred and loaded {} {}-point waveforms in {:0.3f} seconds.'.format(noOfseqs, N, t2-t1))\n", + "#awg1.load_awg_file(loadfrom)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "awg1.set_sqel_goto_target_index(3, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Running'" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# we need this to run\n", + "awg1.visa_handle.write('SOUR1:ROSC:SOUR INT')\n", + "awg1.visa_handle.write('OUTP1 ON')\n", + "awg1.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(20, )" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "filename = 'manySinesINcreasingFreq.awg'\n", + "loadfrom = '{}{}'.format(awg1.visa_handle.query('MMEMory:CDIRectory?').replace('\"','').replace('\\n', '\\\\'), filename)\n", + "awg1.visa_handle.write('MMEM:IMP {},{}'.format('mylist', loadfrom))\n", + "awg1.visa_handle.write('SOURce1:WAV {}'.format('mylist'))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "awg1.stop()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Approach B" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "awg1.delete_all_waveforms_from_list()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/william/.pyenv/versions/anaconda3-4.1.1/envs/qcodesmaster/lib/python3.5/site-packages/ipykernel/__main__.py:5: DeprecationWarning: tostring() is deprecated. Use tobytes() instead.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Transferred 20 10000-point waveforms in 27.037 seconds.\n" + ] + } + ], + "source": [ + "noOfwfs = 20\n", + "t1 = time.time()\n", + "for ii in range(noOfwfs):\n", + " wfmname = 'hiswaveform{:03d}'.format(ii)\n", + " awg1.send_waveform_to_list(makesinewf(N, 1+ii), m1, m2, wfmname, silent=True)\n", + " awg1.set_sqel_waveform(wfmname, 1, ii+1)\n", + "awg1.visa_handle.query('*IDN?') # a dummy query to get the timing right\n", + "t2 = time.time()\n", + "print('Transferred {} {}-point waveforms in {:0.3f} seconds.'.format(noOfwfs, N, t2-t1))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "upload time: 0.0010411739349365234\n", + "setting time: 0.298145055770874\n" + ] + } + ], + "source": [ + "awg1.upload_awg_file('testfile.awg', awg_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "awg1._rem_file_path = '\\\\\\\\AWG-3289382193\\\\WaveformLib'" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'TEKTRONIX,AWG5014C,B051039,SCPI:99.0 FW:4.6.0.7 \\n'" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "awg1.visa_handle.query('*IDN?')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/examples/driver_examples/Qcodes example with Tektronix AWG70002A.ipynb b/docs/examples/driver_examples/Qcodes example with Tektronix AWG70002A.ipynb new file mode 100644 index 00000000000..51fa06ff17e --- /dev/null +++ b/docs/examples/driver_examples/Qcodes example with Tektronix AWG70002A.ipynb @@ -0,0 +1,706 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# QCoDeS Example with Tektronix AWG70002A\n", + "\n", + "The Tektronix awg70002A can operate in two modes: function generator mode or AWG mode. This example notebook briefly covers both." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import numpy as np\n", + "from qcodes.instrument_drivers.tektronix.AWG70002A import AWG70002A" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Connected to: TEKTRONIX AWG70002A (serial:B020397, firmware:FV:5.3.0128.0) in 0.12s\n" + ] + } + ], + "source": [ + "awg = AWG70002A('awg', 'TCPIP0::172.20.2.243::inst0::INSTR', terminator='\\n')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "awg:\n", + "\tparameter value\n", + "--------------------------------------------------------------------------------\n", + "IDN :\t{'vendor': 'TEKTRONIX', 'model': 'AWG70002A', 'ser...\n", + "clock_external_frequency :\t6.25e+09 (Hz)\n", + "clock_source :\tInternal \n", + "current_directory :\t\"\\Users\\OEM\\Documents\" \n", + "mode :\tAWG \n", + "sample_rate :\t1e+09 (Sa/s)\n", + "timeout :\t10 (s)\n", + "awg_ch1:\n", + "\tparameter value\n", + "--------------------------------------------------------------------------------\n", + "awg_amplitude :\t0.3 (V)\n", + "fgen_amplitude :\t0.074 (V)\n", + "fgen_dclevel :\t0 (V)\n", + "fgen_frequency :\t1e+07 (Hz)\n", + "fgen_offset :\t0.12 (V)\n", + "fgen_period :\t1e-07 (s)\n", + "fgen_phase :\t25 (degrees)\n", + "fgen_signalpath :\tdirect \n", + "fgen_symmetry :\t50 (%)\n", + "fgen_type :\tEXPONENTIALDECAY \n", + "resolution :\t8 \n", + "state :\t0 \n", + "awg_ch2:\n", + "\tparameter value\n", + "--------------------------------------------------------------------------------\n", + "awg_amplitude :\t0.3 (V)\n", + "fgen_amplitude :\t0.5 (V)\n", + "fgen_dclevel :\t0 (V)\n", + "fgen_frequency :\t1e+07 (Hz)\n", + "fgen_offset :\t0 (V)\n", + "fgen_period :\t1e-07 (s)\n", + "fgen_phase :\t0 (degrees)\n", + "fgen_signalpath :\tdirect \n", + "fgen_symmetry :\t50 (%)\n", + "fgen_type :\tTRIANGLE \n", + "resolution :\t8 \n", + "state :\t0 \n" + ] + } + ], + "source": [ + "# Let's have a look at the available parameters\n", + "\n", + "awg.print_readable_snapshot(update=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Function Generator Style Operation" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set the intrument mode to function generator\n", + "awg.mode('FGEN')\n", + "\n", + "# Build some signal\n", + "awg.ch1.fgen_type('EXPONENTIALDECAY')\n", + "awg.ch1.fgen_frequency(10e6)\n", + "awg.ch1.fgen_amplitude(0.074)\n", + "awg.ch1.fgen_offset(0.12)\n", + "awg.ch1.fgen_phase(25)\n", + "\n", + "# Switch channel 1 on\n", + "awg.ch1.state(1)\n", + "\n", + "# Start outputting...\n", + "awg.play()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# switch off the output eventually\n", + "awg.stop()\n", + "\n", + "# and disable the channel\n", + "awg.ch1.state(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## AWG Style Operation\n", + "\n", + "The instrument can be operated as an awg where the user uploads arrays describing the waveforms.\n", + "\n", + "Each channel operates in one of three resolution modes:\n", + "\n", + "* 8 bit signal + 2 markers\n", + "* 9 bit signal + 1 marker\n", + "* 10 bit signal with no markers\n", + "\n", + "Waveforms can be sent to the waveform list via `.wfmx` files. A `.wfmx` file can contain marker data. If the resolution of the instrument does not allow for markers, these are simply ignored." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Making and sending waveforms to the waveform list" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# set the instrument in awg mode\n", + "awg.mode('AWG')\n", + "# set the resolution to 8 bits plus two markers\n", + "awg.ch1.resolution(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# clear the sequence list and waveform list (NOT ALWAYS A GOOD IDEA! BE CAREFUL!)\n", + "awg.clearSequenceList()\n", + "awg.clearWaveformList()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Let us make a sine, upload it and play it\n", + "\n", + "N = 50000 # minimal length allowed is 2400 points\n", + "\n", + "m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))\n", + "m2 = np.concatenate((np.zeros(int(N/2)), np.ones(int(N/2))))\n", + "\n", + "ramp = 0.075*np.linspace(0, 1, N)\n", + "\n", + "mysine = 0.1*np.sin(10*2*np.pi*np.linspace(0, 1, N)) + ramp\n", + "\n", + "data = np.array([mysine, m1, m2])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# The .wfmx file needs a name in the memory of the instrument\n", + "# The name of the waveform in the waveform list is that same name\n", + "# with no .wfmx extension\n", + "filename = 'examplewaveform1.wfmx'" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# now compile the binary file\n", + "wfmx_file = awg.makeWFMXFile(data, 0.350)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# and send it and load it into memory\n", + "awg.sendWFMXFile(wfmx_file, filename)\n", + "awg.loadWFMXFile(filename)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['examplewaveform1']" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The waveform is now in the waveform list\n", + "awg.waveformList" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# now assign it to channel 1\n", + "awg.ch1.setWaveform(filename.replace('.wfmx', ''))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Switch channel 1 on\n", + "awg.ch1.state(1)\n", + "\n", + "# Start outputting...\n", + "awg.play()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# switch off the output eventually\n", + "awg.stop()\n", + "\n", + "# and disable the channel\n", + "awg.ch1.state(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "awg.ch2.setWaveform(filename.replace('.wfmx', ''))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "awg.ch2.state(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Making and sending sequences\n", + "\n", + "Sequences are much better off being generated using the broadbean module, but for now let's reduce the number of moving parts and compose a little sequence by hand." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# set the instrument in awg mode\n", + "awg.mode('AWG')\n", + "# set the resolution to 8 bits plus two markers\n", + "awg.ch1.resolution(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Let's make a sequence where a sine plays on one channel while the other channel ramps\n", + "# and then the roles reverse\n", + "\n", + "# As a preparation, let's set both channels to 300 mV peak-to-peak\n", + "awg.ch1.awg_amplitude(0.3)\n", + "awg.ch2.awg_amplitude(0.3)\n", + "\n", + "N = 20000 # minimally 2400\n", + "\n", + "SR = 1e9\n", + "awg.sample_rate(SR) # set the sample rate on the instrument\n", + "ramp_target = 0.1 # ramp target (V)\n", + "\n", + "time = np.linspace(0, N/SR, N)\n", + "sinesignal = 0.15*np.sin(SR/N*2*np.pi*time)\n", + "m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))\n", + "m2 = np.concatenate((np.zeros(int(N/2)), np.zeros(int(N/2))))\n", + "rampsignal = np.linspace(0, ramp_target, N)\n", + "\n", + "# Then we compose and upload a .seqx file in 6 steps\n", + "\n", + "# Step 1: cast the waveform data into the .wfmx format\n", + "# To make a .wfmx, we need to know the amplitude of the output channel\n", + "ch1_amp = awg.ch1.awg_amplitude()\n", + "ch2_amp = awg.ch2.awg_amplitude()\n", + "\n", + "wfm_ch1_n1 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch1_amp)\n", + "wfm_ch1_n2 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch1_amp)\n", + "wfm_ch2_n1 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch2_amp)\n", + "wfm_ch2_n2 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch2_amp)\n", + "\n", + "# Step 2: decide on sequencing information\n", + "# This information is provided as lists of the same length as the \n", + "# sequence\n", + "trig_waits = [0, 0] # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "nreps = [2, 3] # 0 corresponds to infinite\n", + "event_jumps = [0, 0] # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "event_jump_to = [0, 0] # irrelevant if event-jump is 0, else the sequence pos. to jump to\n", + "go_to = [0, 1] # 0 means next\n", + "\n", + "# Step 3: make the .seqx file\n", + "# The sequence must be given a name\n", + "\n", + "seqname = 'tutorial_sequence'\n", + "\n", + "seqx = awg.makeSEQXFile(trig_waits,\n", + " nreps,\n", + " event_jumps,\n", + " event_jump_to,\n", + " go_to, [[wfm_ch1_n1, wfm_ch1_n2], [wfm_ch2_n1, wfm_ch2_n2]],\n", + " seqname)\n", + "\n", + "# Step 4: Transfer the seqx file\n", + "awg.sendSEQXFile(seqx, 'thursday.seqx')\n", + "\n", + "# Step 5: Load the seqx file\n", + "awg.loadSEQXFile('thursday.seqx')\n", + "# Now the sequence should appear in the sequencelist, but it is not yet assigned to channels\n", + "\n", + "# Step 6: Assign tracks from the sequence to the channels\n", + "# Unlike older/other AWG models, this can be done on a per-channel basis\n", + "awg.ch1.setSequenceTrack(seqname, 1)\n", + "awg.ch2.setSequenceTrack(seqname, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Now play it!\n", + "awg.ch1.state(1)\n", + "awg.ch2.state(1)\n", + "awg.play()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "awg.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Finally irreversibly tear down the instrument\n", + "awg.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Trying stuff that doesn't work\n", + "\n", + "## 1: only a single channel specified *DOES WORK*" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# clear the sequence list and waveform list (NOT ALWAYS A GOOD IDEA! BE CAREFUL!)\n", + "awg.clearSequenceList()\n", + "awg.clearWaveformList()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "\n", + "awg.ch1.awg_amplitude(0.3)\n", + "\n", + "\n", + "N = 20000 # minimally 2400\n", + "\n", + "SR = 1e9\n", + "awg.sample_rate(SR) # set the sample rate on the instrument\n", + "ramp_target = 0.1 # ramp target (V)\n", + "\n", + "time = np.linspace(0, N/SR, N)\n", + "sinesignal = 0.15*np.sin(SR/N*2*np.pi*time)\n", + "m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))\n", + "m2 = np.concatenate((np.zeros(int(N/2)), np.zeros(int(N/2))))\n", + "rampsignal = np.linspace(0, ramp_target, N)\n", + "\n", + "# Then we compose and upload a .seqx file in 6 steps\n", + "\n", + "# Step 1: cast the waveform data into the .wfmx format\n", + "# To make a .wfmx, we need to know the amplitude of the output channel\n", + "ch1_amp = awg.ch1.awg_amplitude()\n", + "\n", + "wfm_ch1_n1 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch1_amp)\n", + "wfm_ch1_n2 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch1_amp)\n", + "\n", + "# Step 2: decide on sequencing information\n", + "# This information is provided as lists of the same length as the \n", + "# sequence\n", + "trig_waits = [0, 0] # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "nreps = [2, 3] # 0 corresponds to infinite\n", + "event_jumps = [0, 0] # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "event_jump_to = [0, 0] # irrelevant if event-jump is 0, else the sequence pos. to jump to\n", + "go_to = [0, 1] # 0 means next\n", + "\n", + "# Step 3: make the .seqx file\n", + "# The sequence must be given a name\n", + "\n", + "seqname = 'single_channel_sequence'\n", + "\n", + "seqx = awg.makeSEQXFile(trig_waits,\n", + " nreps,\n", + " event_jumps,\n", + " event_jump_to,\n", + " go_to, [[wfm_ch1_n1, wfm_ch1_n2]],\n", + " seqname)\n", + "\n", + "# Step 4: Transfer the seqx file\n", + "awg.sendSEQXFile(seqx, 'singlechannel.seqx')\n", + "\n", + "# Step 5: Load the seqx file\n", + "awg.loadSEQXFile('singlechannel.seqx')\n", + "# Now the sequence should appear in the sequencelist, but it is not yet assigned to channels\n", + "\n", + "# Step 6: Assign tracks from the sequence to the channels\n", + "# Unlike older/other AWG models, this can be done on a per-channel basis\n", + "awg.ch1.setSequenceTrack(seqname, 1)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2: More than 10 waveforms crash stuff" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "\n", + "awg.ch1.awg_amplitude(0.3)\n", + "\n", + "\n", + "N = 20000 # minimally 2400\n", + "\n", + "SR = 1e9\n", + "awg.sample_rate(SR) # set the sample rate on the instrument\n", + "ramp_target = 0.1 # ramp target (V)\n", + "\n", + "time = np.linspace(0, N/SR, N)\n", + "sinesignal = 0.15*np.sin(SR/N*2*np.pi*time)\n", + "m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))\n", + "m2 = np.concatenate((np.zeros(int(N/2)), np.zeros(int(N/2))))\n", + "rampsignal = np.linspace(0, ramp_target, N)\n", + "\n", + "# Then we compose and upload a .seqx file in 6 steps\n", + "\n", + "# Step 1: cast the waveform data into the .wfmx format\n", + "# To make a .wfmx, we need to know the amplitude of the output channel\n", + "ch1_amp = awg.ch1.awg_amplitude()\n", + "\n", + "no_of_waveforms = 11\n", + "\n", + "wfm1 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch1_amp)\n", + "wfm2 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch1_amp)\n", + "\n", + "# Step 2: decide on sequencing information\n", + "# This information is provided as lists of the same length as the \n", + "# sequence\n", + "trig_waits = [0]*no_of_waveforms # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "nreps = [1]*no_of_waveforms # 0 corresponds to infinite\n", + "event_jumps = [0]*no_of_waveforms # 0: off, 1: trigA, 2: trigB, 3: EXT\n", + "event_jump_to = [0]*no_of_waveforms # irrelevant if event-jump is 0, else the sequence pos. to jump to\n", + "go_to = [0]*no_of_waveforms # 0 means next\n", + "\n", + "wfmxs = [[wfm1]*no_of_waveforms, [wfm2]*no_of_waveforms]\n", + "\n", + "# Step 3: make the .seqx file\n", + "# The sequence must be given a name\n", + "\n", + "seqname = 'big_sequence_{}'.format(no_of_waveforms)\n", + "\n", + "seqx = awg.makeSEQXFile(trig_waits,\n", + " nreps,\n", + " event_jumps,\n", + " event_jump_to,\n", + " go_to, wfmxs,\n", + " seqname)\n", + "\n", + "# Step 4: Transfer the seqx file\n", + "awg.sendSEQXFile(seqx, 'bigsequence{}.seqx'.format(no_of_waveforms))\n", + "\n", + "# Step 5: Load the seqx file\n", + "awg.loadSEQXFile('bigsequence{}.seqx'.format(no_of_waveforms))\n", + "# Now the sequence should appear in the sequencelist, but it is not yet assigned to channels\n", + "\n", + "# Step 6: Assign tracks from the sequence to the channels\n", + "# Unlike older/other AWG models, this can be done on a per-channel basis\n", + "awg.ch1.setSequenceTrack(seqname, 1)\n", + "\n", + "with open('bigsequence{}.seqx'.format(no_of_waveforms), 'wb') as fid:\n", + " fid.write(seqx)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.4" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "0.1/.25" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qcodes/instrument/sims/Tektronix_AWG70000A.yaml b/qcodes/instrument/sims/Tektronix_AWG70000A.yaml new file mode 100644 index 00000000000..e401e259140 --- /dev/null +++ b/qcodes/instrument/sims/Tektronix_AWG70000A.yaml @@ -0,0 +1,48 @@ +# SIMULATED INSTRUMENT FOR TEKTRONIX AWGS 70001A AND 70002A +spec: "1.0" + +devices: + device 1: # AWG 70001A + eom: + GPIB INSTR: + q: "\n" + r: "\n" + error: ERROR + dialogues: + - q: "*IDN?" + r: "QCoDeS, AWG70001A, 1000, 0.1" + + properties: + directory: + default: "C:" + getter: + q: "MMEMory:CDIRectory?" + r: "{}" + setter: + q: "MMEMory:CDIRectory {}" + r: OK + + device 2: # AWG 70002A + eom: + GPIB INSTR: + q: "\n" + r: "\n" + error: ERROR + dialogues: + - q: "*IDN?" + r: "QCoDeS, AWG70002A, 1000, 0.1" + properties: + directory: + default: "C:" + getter: + q: "MMEMory:CDIRectory?" + r: "{}" + setter: + q: "MMEMory:CDIRectory {}" + r: OK + +resources: + GPIB::1::INSTR: + device: device 1 + GPIB::2::INSTR: + device: device 2 diff --git a/qcodes/instrument_drivers/tektronix/AWG70000A.py b/qcodes/instrument_drivers/tektronix/AWG70000A.py new file mode 100644 index 00000000000..043743e4b59 --- /dev/null +++ b/qcodes/instrument_drivers/tektronix/AWG70000A.py @@ -0,0 +1,941 @@ +import xml.etree.ElementTree as ET +import datetime as dt +import numpy as np +import struct +import io +import zipfile as zf +import logging + +from dateutil.tz import time +from typing import List, Sequence + +from qcodes import Instrument, VisaInstrument, validators as vals +from qcodes.instrument.channel import InstrumentChannel +from qcodes.utils.validators import Validator + +log = logging.getLogger(__name__) + + +class SRValidator(Validator): + """ + Validator to validate the AWG clock sample rate + """ + + def __init__(self, awg: 'AWG70000A') -> None: + """ + Args: + awg: The parent instrument instance. We need this since sample + rate validation depends on many clock settings + """ + self.awg = awg + if self.awg.model == '70001A': + self._internal_validator = vals.Numbers(1.49e3, 50e9) + self._freq_multiplier = 4 + elif self.awg.model == '70002A': + self._internal_validator = vals.Numbers(1.49e3, 25e9) + self._freq_multiplier = 2 + # no other models are possible, since the __init__ of + # the AWG70000A raises an error if anything else is given + + def validate(self, value: float, context: str='') -> None: + if 'Internal' in self.awg.clock_source(): + self._internal_validator.validate(value) + else: + ext_freq = self.awg.clock_external_frequency() + # TODO: I'm not sure what the minimal allowed sample rate is + # in this case + validator = vals.Numbers(1.49e3, self._freq_multiplier*ext_freq) + validator.validate(value) + + +class AWGChannel(InstrumentChannel): + """ + Class to hold a channel of the AWG. + """ + + def __init__(self, parent: Instrument, name: str, channel: int) -> None: + """ + Args: + parent: The Instrument instance to which the channel is + to be attached. + name: The name used in the DataSet + channel: The channel number, either 1 or 2. + """ + + super().__init__(parent, name) + + self.channel = channel + + num_channels = self._parent.num_channels + + fg = 'function generator' + + if channel not in list(range(1, num_channels+1)): + raise ValueError('Illegal channel value.') + + self.add_parameter('state', + label='Channel {} state'.format(channel), + get_cmd='OUTPut{}:STATe?'.format(channel), + set_cmd='OUTPut{}:STATe {{}}'.format(channel), + vals=vals.Ints(0, 1), + get_parser=int) + + ################################################## + # FGEN PARAMETERS + + # TODO: Setting high and low will change this parameter's value + self.add_parameter('fgen_amplitude', + label='Channel {} {} amplitude'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:AMPLitude?'.format(channel), + set_cmd='FGEN:CHANnel{}:AMPLitude {{}}'.format(channel), + unit='V', + vals=vals.Numbers(0, 0.5), + get_parser=float) + + self.add_parameter('fgen_offset', + label='Channel {} {} offset'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:OFFSet?'.format(channel), + set_cmd='FGEN:CHANnel{}:OFFSet {{}}'.format(channel), + unit='V', + vals=vals.Numbers(0, 0.250), # depends on ampl. + get_parser=float) + + self.add_parameter('fgen_frequency', + label='Channel {} {} frequency'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:FREQuency?'.format(channel), + set_cmd='FGEN:CHANnel{}:FREQuency {{}}'.format(channel), + unit='Hz', + vals=vals.Numbers(1, 50000000), + get_parser=float) + + self.add_parameter('fgen_dclevel', + label='Channel {} {} DC level'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:DCLevel?'.format(channel), + set_cmd='FGEN:CHANnel{}:DCLevel {{}}'.format(channel), + unit='V', + vals=vals.Numbers(-0.25, 0.25), + get_parser=float) + + self.add_parameter('fgen_signalpath', + label='Channel {} {} signal path'.format(channel, fg), + set_cmd='FGEN:CHANnel{}:PATH {{}}'.format(channel), + get_cmd='FGEN:CHANnel{}:PATH?'.format(channel), + val_mapping={'direct': 'DIR', + 'DCamplified': 'DCAM', + 'AC': 'AC'} + ) + + self.add_parameter('fgen_period', + label='Channel {} {} period'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:PERiod?'.format(channel), + unit='s', + get_parser=float) + + self.add_parameter('fgen_phase', + label='Channel {} {} phase'.format(channel, fg), + get_cmd='FGEN:CHANnel{}:PHASe?'.format(channel), + set_cmd='FGEN:CHANnel{}:PHASe {{}}'.format(channel), + unit='degrees', + vals=vals.Numbers(-180, 180), + get_parser=float) + + self.add_parameter('fgen_symmetry', + label='Channel {} {} symmetry'.format(channel, fg), + set_cmd='FGEN:CHANnel{}:SYMMetry {{}}'.format(channel), + get_cmd='FGEN:CHANnel{}:SYMMetry?'.format(channel), + unit='%', + vals=vals.Numbers(0, 100), + get_parser=float) + + self.add_parameter('fgen_type', + label='Channel {} {} type'.format(channel, fg), + set_cmd='FGEN:CHANnel{}:TYPE {{}}'.format(channel), + get_cmd='FGEN:CHANnel{}:TYPE?'.format(channel), + val_mapping={'SINE': 'SINE', + 'SQUARE': 'SQU', + 'TRIANGLE': 'TRI', + 'NOISE': 'NOIS', + 'DC': 'DC', + 'GAUSSIAN': 'GAUSS', + 'EXPONENTIALRISE': 'EXPR', + 'EXPONENTIALDECAY': 'EXPD', + 'NONE': 'NONE'}) + + ################################################## + # AWG PARAMETERS + + # this command internally uses power in dBm + # the manual claims that this command only works in AC mode + # (OUTPut[n]:PATH is AC), but I've tested that it does what + # one would expect in DIR mode. + self.add_parameter( + 'awg_amplitude', + label='Channel {} AWG peak-to-peak amplitude'.format(channel), + set_cmd='SOURCe{}:VOLTage {{}}'.format(channel), + get_cmd='SOURce{}:VOLTage?'.format(channel), + unit='V', + get_parser=float, + vals=vals.Numbers(0.250, 0.500)) + + ################################################## + # MISC. + + self.add_parameter('resolution', + label='Channel {} bit resolution'.format(channel), + get_cmd='SOURce{}:DAC:RESolution?'.format(channel), + set_cmd='SOURce{}:DAC:RESolution {{}}'.format(channel), + vals=vals.Enum(8, 9, 10), + get_parser=int, + docstring=(""" + 8 bit resolution allows for two + markers, 9 bit resolution + allows for one, and 10 bit + does NOT allow for markers""")) + + def setWaveform(self, name: str) -> None: + """ + Select a waveform from the waveform list to output on this channel + + Args: + name: The name of the waveform + """ + if name not in self._parent.waveformList: + raise ValueError('No such waveform in the waveform list') + + self._parent.write('SOURce{}:CASSet:WAVeform "{}"'.format(self.channel, + name)) + + def setSequenceTrack(self, seqname: str, tracknr: int) -> None: + """ + Assign a track from a sequence to this channel. + + Args: + seqname: Name of the sequence in the sequence list + tracknr: Which track to use (1 or 2) + """ + args = (self.channel, seqname, tracknr) + self._parent.write('SOURCE{}:CASSet:SEQuence "{}", {}'.format(*args)) + + +class AWG70000A(VisaInstrument): + """ + The QCoDeS driver for Tektronix AWG70000A series AWG's. + + The drivers for AWG70001A and AWG70002A should be subclasses of this + general class. + """ + + def __init__(self, name: str, address: str, num_channels: int, + timeout: float=10, **kwargs) -> None: + """ + Args: + name: The name used internally by QCoDeS in the DataSet + address: The VISA resource name of the instrument + timeout: The VISA timeout time (in seconds) + num_channels: Number of channels on the AWG + """ + + self.num_channels = num_channels + + super().__init__(name, address, timeout=timeout, terminator='\n', + **kwargs) + + # The 'model' value begins with 'AWG' + self.model = self.IDN()['model'][3:] + + if self.model not in ['70001A', '70002A']: + raise ValueError('Unknown model type: {}. Are you using ' + 'the right driver for your instrument?' + ''.format(self.model)) + + self.add_parameter('current_directory', + label='Current file system directory', + set_cmd='MMEMory:CDIRectory "{}"', + get_cmd='MMEMory:CDIRectory?', + vals=vals.Strings()) + + self.add_parameter('mode', + label='Instrument operation mode', + set_cmd='INSTrument:MODE {}', + get_cmd='INSTrument:MODE?', + vals=vals.Enum('AWG', 'FGEN')) + + ################################################## + # Clock parameters + + self.add_parameter('sample_rate', + label='Clock sample rate', + set_cmd='CLOCk:SRATe {}', + get_cmd='CLOCk:SRATe?', + unit='Sa/s', + get_parser=float, + vals=SRValidator(self)) + + self.add_parameter('clock_source', + label='Clock source', + set_cmd='CLOCk:SOURce {}', + get_cmd='CLOCk:SOURce?', + val_mapping={'Internal': 'INT', + 'Internal, 10 MHZ ref.': 'EFIX', + 'Internal, variable ref.': 'EVAR', + 'External': 'EXT'}) + + self.add_parameter('clock_external_frequency', + label='External clock frequency', + set_cmd='CLOCk:ECLock:FREQuency {}', + get_cmd='CLOCk:ECLock:FREQuency?', + get_parser=float, + unit='Hz', + vals=vals.Numbers(6.25e9, 12.5e9)) + + for ch_num in range(1, num_channels+1): + ch_name = 'ch{}'.format(ch_num) + channel = AWGChannel(self, ch_name, ch_num) + self.add_submodule(ch_name, channel) + + # Folder on the AWG where to files are uplaoded by default + self.wfmxFileFolder = "\\Users\\OEM\\Documents" + self.seqxFileFolder = "\\Users\\OEM\Documents" + + self.current_directory(self.wfmxFileFolder) + + self.connect_message() + + def play(self) -> None: + """ + Run the AWG/Func. Gen. This command is equivalent to pressing the + play button on the front panel. + """ + self.write('AWGControl:RUN') + + def stop(self) -> None: + """ + Stop the output of the instrument. This command is equivalent to + pressing the stop button on the front panel. + """ + self.write('AWGControl:STOP') + + @property + def sequenceList(self) -> List[str]: + """ + Return the sequence list as a list of strings + """ + # There is no SLISt:LIST command, so we do it slightly differently + N = int(self.ask("SLISt:SIZE?")) + slist = [] + for n in range(1, N+1): + resp = self.ask("SLISt:NAME? {}".format(n)) + resp = resp.strip() + resp = resp.replace('"', '') + slist.append(resp) + + return slist + + @property + def waveformList(self) -> List[str]: + """ + Return the waveform list as a list of strings + """ + resp = self.ask("WLISt:LIST?") + resp = resp.strip() + resp = resp.replace('"', '') + resp = resp.split(',') + + return resp + + def clearSequenceList(self): + """ + Clear the sequence list + """ + self.write('SLISt:SEQuence:DELete ALL') + + def clearWaveformList(self): + """ + Clear the waveform list + """ + self.write('WLISt:WAVeform:DELete ALL') + + @staticmethod + def makeWFMXFile(data: np.ndarray, amplitude: float, + headeronly: bool=False) -> bytes: + """ + Compose a WFMX file + + Args: + data: A numpy array holding the data. Markers can be included. + amplitude: The peak-to-peak amplitude (V) assumed to be set on the + channel that will play this waveform. This information is + needed as the waveform must be rescaled to (-1, 1) where + -1 will correspond to the channel's min. voltage and 1 to the + channel's max. voltage. + headeronly: Only make the header (for debugging). Default: False. + + Returns: + The binary .wfmx file, ready to be sent to the instrument. + """ + + shape = np.shape(data) + if len(shape) == 1: + N = shape[0] + markers_included = False + elif len(shape) == 2: + N = shape[1] + markers_included = True + else: + raise ValueError('Input data has too many dimensions!') + + wfmx_hdr_str = AWG70000A._makeWFMXFileHeader(num_samples=N, + markers_included=markers_included) + wfmx_hdr = bytes(wfmx_hdr_str, 'ascii') + wfmx_data = AWG70000A._makeWFMXFileBinaryData(data, amplitude) + + wfmx = wfmx_hdr + + if not headeronly: + wfmx += wfmx_data + + return wfmx + + def sendSEQXFile(self, seqx: bytes, filename: str, + path: str=None) -> None: + """ + Send a binary seqx file to the AWG's memory + + Args: + seqx: The binary seqx file, preferably the output of + makeSEQXFile. + filename: The name of the file on the AWG disk, including the + extension. + path: The path to the directory where the file should be saved. If + omitted, seqxFileFolder will be used. + """ + if not path: + path = self.seqxFileFolder + + self._sendBinaryFile(seqx, filename, path) + + def sendWFMXFile(self, wfmx: bytes, filename: str, + path: str=None) -> None: + """ + Send a binary wfmx file to the AWG's memory + + Args: + wfmx: The binary wfmx file, preferably the output of + makeWFMXFile. + filename: The name of the file on the AWG disk, including the + extension. + path: The path to the directory where the file should be saved. If + omitted, seqxFileFolder will be used. + """ + if not path: + path = self.wfmxFileFolder + + self._sendBinaryFile(wfmx, filename, path) + + def _sendBinaryFile(self, binfile: bytes, filename: str, + path: str) -> None: + """ + Send a binary file to the AWG's mass memory (disk). + + Args: + binfile: The binary file to send. + filename: The name of the file on the AWG disk, including the + extension. + path: The path to the directory where the file should be saved. + """ + + name_str = 'MMEMory:DATA "{}"'.format(filename).encode('ascii') + len_file = len(binfile) + len_str = len(str(len_file)) # No. of digits needed to write length + size_str = (',#{}{}'.format(len_str, len_file)).encode('ascii') + + msg = name_str + size_str + binfile + + # IEEE 488.2 limit on a single write is 999,999,999 bytes + # TODO: If this happens, we should split the file + if len(msg) > 1e9-1: + raise ValueError('File too large to transfer') + + self.current_directory(path) + + self.visa_handle.write_raw(msg) + + def loadWFMXFile(self, filename: str, path: str=None) -> None: + """ + Loads a wfmx from memory into the waveform list + Only loading from the C: drive is supported + + Args: + filename: Name of the file (with extension) + path: Path to load from. If omitted, the default path + (self.wfmxFileFolder) is used. + """ + + if not path: + path = self.wfmxFileFolder + + pathstr = 'C:' + path + '\\' + filename + + self.write('MMEMory:OPEN "{}"'.format(pathstr)) + # the above command is overlapping, but we want a blocking command + self.ask("*OPC?") + + def loadSEQXFile(self, filename: str, path: str=None) -> None: + """ + Load a seqx file from instrument disk memory. All sequences in the file + are loaded into the sequence list. + + Args: + filename: The name of the sequence file + path: Path to load from. If omitted, the default path + (self.seqxFileFolder) is used. + """ + if not path: + path = self.seqxFileFolder + + pathstr = 'C:{}\\{}'.format(path, filename) + + self.write('MMEMory:OPEN:SASSet:SEQuence "{}"'.format(pathstr)) + # the above command is overlapping, but we want a blocking command + self.ask('*OPC?') + + @staticmethod + def _makeWFMXFileHeader(num_samples: int, + markers_included: bool) -> str: + """ + Compiles a valid XML header for a .wfmx file + There might be behaviour we can't capture + + We always use 9 digits for the number of header character + """ + offsetdigits = 9 + + if not isinstance(num_samples, int): + raise ValueError('num_samples must be of type int.') + + if num_samples < 2400: + raise ValueError('num_samples must be at least 2400.') + + # form the timestamp string + timezone = time.timezone + tz_m, _ = divmod(timezone, 60) # returns (minutes, seconds) + tz_h, tz_m = divmod(tz_m, 60) + if np.sign(tz_h) == -1: + signstr = '-' + tz_h *= -1 + else: + signstr = '+' + timestr = dt.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + timestr += signstr + timestr += '{:02.0f}:{:02.0f}'.format(tz_h, tz_m) + + hdr = ET.Element('DataFile', attrib={'offset': '0'*offsetdigits, + 'version': '0.1'}) + dsc = ET.SubElement(hdr, 'DataSetsCollection') + dsc.set("xmlns", "http://www.tektronix.com") + dsc.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") + dsc.set("xsi:schemaLocation", (r"http://www.tektronix.com file:///" + + r"C:\Program%20Files\Tektronix\AWG70000" + + r"\AWG\Schemas\awgDataSets.xsd")) + datasets = ET.SubElement(dsc, 'DataSets') + datasets.set('version', '1') + datasets.set("xmlns", "http://www.tektronix.com") + + # Description of the data + datadesc = ET.SubElement(datasets, 'DataDescription') + temp_elem = ET.SubElement(datadesc, 'NumberSamples') + temp_elem.text = '{:d}'.format(num_samples) + temp_elem = ET.SubElement(datadesc, 'SamplesType') + temp_elem.text = 'AWGWaveformSample' + temp_elem = ET.SubElement(datadesc, 'MarkersIncluded') + temp_elem.text = ('{}'.format(markers_included)).lower() + temp_elem = ET.SubElement(datadesc, 'NumberFormat') + temp_elem.text = 'Single' + temp_elem = ET.SubElement(datadesc, 'Endian') + temp_elem.text = 'Little' + temp_elem = ET.SubElement(datadesc, 'Timestamp') + temp_elem.text = timestr + + # Product specific information + prodspec = ET.SubElement(datasets, 'ProductSpecific') + prodspec.set('name', '') + temp_elem = ET.SubElement(prodspec, 'ReccSamplingRate') + temp_elem.set('units', 'Hz') + temp_elem.text = 'NaN' + temp_elem = ET.SubElement(prodspec, 'ReccAmplitude') + temp_elem.set('units', 'Volts') + temp_elem.text = 'NaN' + temp_elem = ET.SubElement(prodspec, 'ReccOffset') + temp_elem.set('units', 'Volts') + temp_elem.text = 'NaN' + temp_elem = ET.SubElement(prodspec, 'SerialNumber') + temp_elem = ET.SubElement(prodspec, 'SoftwareVersion') + temp_elem.text = '1.0.0917' + temp_elem = ET.SubElement(prodspec, 'UserNotes') + temp_elem = ET.SubElement(prodspec, 'OriginalBitDepth') + temp_elem.text = 'Floating' + temp_elem = ET.SubElement(prodspec, 'Thumbnail') + temp_elem = ET.SubElement(prodspec, 'CreatorProperties', + attrib={'name': ''}) + temp_elem = ET.SubElement(hdr, 'Setup') + + xmlstr = ET.tostring(hdr, encoding='unicode') + xmlstr = xmlstr.replace('><', '>\r\n<') + + # As the final step, count the length of the header and write this + # in the DataFile tag attribute 'offset' + + xmlstr = xmlstr.replace('0'*offsetdigits, + '{num:0{pad}d}'.format(num=len(xmlstr), + pad=offsetdigits)) + + return xmlstr + + @staticmethod + def _makeWFMXFileBinaryData(data: np.ndarray, amplitude: float) -> bytes: + """ + For the binary part. + + Note that currently only zero markers or two markers are supported; + one-marker data will break. + + Args: + data: Either a shape (N,) array with only a waveform or + a shape (3, N) array with waveform, marker1, marker2, i.e. + data = np.array([wfm, m1, m2]). The waveform data is assumed + to be in V. + amplitude: The peak-to-peak amplitude (V) assumed to be set on the + channel that will play this waveform. This information is + needed as the waveform must be rescaled to (-1, 1) where + -1 will correspond to the channel's min. voltage and 1 to the + channel's max. voltage. + """ + + channel_max = amplitude/2 + channel_min = -amplitude/2 + + shape = np.shape(data) + + if len(shape) == 1: + N = shape[0] + binary_marker = b'' + wfm = data + else: + N = shape[1] + M = shape[0] + wfm = data[0, :] + if M == 2: + markers = data[1, :] + elif M == 3: + m1 = data[1, :] + m2 = data[2, :] + markers = m1+2*m2 # This is how one byte encodes both markers + markers = markers.astype(int) + fmt = N*'B' # endian-ness doesn't matter for one byte + binary_marker = struct.pack(fmt, *markers) + + if wfm.max() > channel_max or wfm.min() < channel_min: + log.warning('Waveform exceeds specified channel range.' + ' The resulting waveform will be clipped. ' + 'Waveform min.: {} (V), waveform max.: {} (V),' + 'Channel min.: {} (V), channel max.: {} (V)' + ''.format(wfm.min(), wfm.max(), channel_min, + channel_max)) + + # the data must be such that channel_max becomes 1 and + # channel_min becomes -1 + scale = 2/amplitude + wfm = wfm*scale + + # TODO: Is this a fast method? + fmt = '<' + N*'f' + binary_wfm = struct.pack(fmt, *wfm) + binary_out = binary_wfm + binary_marker + + return binary_out + + @staticmethod + def makeSEQXFile(trig_waits: Sequence[int], + nreps: Sequence[int], + event_jumps: Sequence[int], + event_jump_to: Sequence[int], + go_to: Sequence[int], + wfms: Sequence[Sequence[bytes]], + seqname: str) -> bytes: + """ + Make a full .seqx file (bundle) + A .seqx file can presumably hold several sequences, but for now + we support only packing a single sequence + + For a single sequence, a .seqx file is a bundle of two files and + two folders: + + /Sequences + sequence.sml + + /Waveforms + wfm1.wfmx + wfm2.wfmx + ... + + setup.xml + userNotes.txt + + Args: + trig_waits: Wait for a trigger? If yes, you must specify the + trigger input. 0 for off, 1 for 'TrigA', 2 for 'TrigB', + 3 for 'Internal'. + nreps: No. of repetitions. 0 corresponds to infinite. + event_jumps: Jump when event triggered? If yes, you must specify + the trigger input. 0 for off, 1 for 'TrigA', 2 for 'TrigB', + 3 for 'Internal'. + event_jump_to: Jump target in case of event. 1-indexed, + 0 means next. Must be specified for all elements. + go_to: Which element to play next. 1-indexed, 0 means next. + wfms: Binary .wfmx files. Should be packed like + [[wfmch1pos1, wfmch1pos2, ...], [wfmch2pos1, ...], ...] + seqname: The name of the sequence. This name will appear in the + sequence list. Note that all spaces are converted to '_' + + Returns: + The binary .seqx file, ready to be sent to the instrument. + """ + + # input sanitising to avoid spaces in filenames + seqname = seqname.replace(' ', '_') + + (chans, elms) = np.shape(wfms) + wfm_names = [['wfmch{}pos{}'.format(ch, el) for el in range(1, elms+1)] + for ch in range(1, chans+1)] + + flat_wfmxs = [wfmx for lst in wfms for wfmx in lst] + flat_wfm_names = [name for lst in wfm_names for name in lst] + + sml_file = AWG70000A._makeSMLFile(trig_waits, nreps, + event_jumps, event_jump_to, + go_to, wfm_names, seqname) + + user_file = b'' + setup_file = AWG70000A._makeSetupFile(seqname) + + buffer = io.BytesIO() + + zipfile = zf.ZipFile(buffer, mode='a') + zipfile.writestr('Sequences/{}.sml'.format(seqname), sml_file) + + for (name, wfile) in zip(flat_wfm_names, flat_wfmxs): + zipfile.writestr('Waveforms/{}.wfmx'.format(name), wfile) + + zipfile.writestr('setup.xml', setup_file) + zipfile.writestr('userNotes.txt', user_file) + zipfile.close() + + buffer.seek(0) + seqx = buffer.getvalue() + buffer.close() + + return seqx + + @staticmethod + def _makeSetupFile(sequence: str) -> str: + """ + Make a setup.xml file. + + Args: + sequence: The name of the main sequence + + Returns: + The setup file as a string + """ + head = ET.Element('RSAPersist') + head.set('version', '0.1') + temp_elem = ET.SubElement(head, 'Application') + temp_elem.text = 'Pascal' + temp_elem = ET.SubElement(head, 'MainSequence') + temp_elem.text = sequence + prodspec = ET.SubElement(head, 'ProductSpecific') + prodspec.set('name', 'AWG70002A') + temp_elem = ET.SubElement(prodspec, 'SerialNumber') + temp_elem.text = 'B020397' + temp_elem = ET.SubElement(prodspec, 'SoftwareVersion') + temp_elem.text = '5.3.0128.0' + temp_elem = ET.SubElement(prodspec, 'CreatorProperties') + temp_elem.set('name', '') + + xmlstr = ET.tostring(head, encoding='unicode') + xmlstr = xmlstr.replace('><', '>\r\n<') + + return xmlstr + + @staticmethod + def _makeSMLFile(trig_waits: Sequence[int], + nreps: Sequence[int], + event_jumps: Sequence[int], + event_jump_to: Sequence[int], + go_to: Sequence[int], + wfm_names: Sequence[Sequence[str]], + seqname: str) -> str: + """ + Make an xml file describing a sequence. + + Args: + trig_waits: Wait for a trigger? If yes, you must specify the + trigger input. 0 for off, 1 for 'TrigA', 2 for 'TrigB', + 3 for 'Internal'. + nreps: No. of repetitions. 0 corresponds to infinite. + event_jumps: Jump when event triggered? If yes, you must specify + the trigger input. 0 for off, 1 for 'TrigA', 2 for 'TrigB', + 3 for 'Internal'. + event_jump_to: Jump target in case of event. 1-indexed, + 0 means next. Must be specified for all elements. + go_to: Which element to play next. 1-indexed, 0 means next. + wfm_names: The waveforms to use. Should be packed like + [[wfmch1pos1, wfmch1pos2, ...], [wfmch2pos1, ...], ...] + seqname: The name of the sequence. This name will appear in + the sequence list of the instrument. + + Returns: + A str containing the file contents, to be saved as an .sml file + """ + offsetdigits = 9 + + waitinputs = {0: 'None', 1: 'TrigA', 2: 'TrigB', 3: 'Internal'} + eventinputs = {0: 'None', 1: 'TrigA', 2: 'TrigB', 3: 'Internal'} + + inputlsts = [trig_waits, nreps, event_jump_to, go_to] + lstlens = [len(lst) for lst in inputlsts] + if lstlens.count(lstlens[0]) != len(lstlens): + raise ValueError('All input lists must have the same length!') + + if lstlens[0] == 0: + raise ValueError('Received empty sequence option lengths!') + + # hackish check of wmfs dimensions + if len(np.shape(wfm_names)) != 2: + raise ValueError('Wrong shape of wfm_names input argument.') + + if lstlens[0] != np.shape(wfm_names)[1]: + raise ValueError('Mismatch between number of waveforms and' + ' number of sequencing steps.') + + N = lstlens[0] + chans = np.shape(wfm_names)[0] + + # for easy indexing later + wfm_names_arr = np.array(wfm_names) + + # form the timestamp string + timezone = time.timezone + tz_m, _ = divmod(timezone, 60) + tz_h, tz_m = divmod(tz_m, 60) + if np.sign(tz_h) == -1: + signstr = '-' + tz_h *= -1 + else: + signstr = '+' + timestr = dt.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + timestr += signstr + timestr += '{:02.0f}:{:02.0f}'.format(tz_h, tz_m) + + datafile = ET.Element('DataFile', attrib={'offset': '0'*offsetdigits, + 'version': '0.1'}) + dsc = ET.SubElement(datafile, 'DataSetsCollection') + dsc.set("xmlns", "http://www.tektronix.com") + dsc.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") + dsc.set("xsi:schemaLocation", (r"http://www.tektronix.com file:///" + + r"C:\Program%20Files\Tektronix\AWG70000" + + r"\AWG\Schemas\awgSeqDataSets.xsd")) + datasets = ET.SubElement(dsc, 'DataSets') + datasets.set('version', '1') + datasets.set("xmlns", "http://www.tektronix.com") + + # Description of the data + datadesc = ET.SubElement(datasets, 'DataDescription') + temp_elem = ET.SubElement(datadesc, 'SequenceName') + temp_elem.text = seqname + temp_elem = ET.SubElement(datadesc, 'Timestamp') + temp_elem.text = timestr + temp_elem = ET.SubElement(datadesc, 'JumpTiming') + temp_elem.text = 'JumpImmed' # TODO: What does this control? + temp_elem = ET.SubElement(datadesc, 'RecSampleRate') + temp_elem.text = 'NaN' + temp_elem = ET.SubElement(datadesc, 'RepeatFlag') + temp_elem.text = 'false' + temp_elem = ET.SubElement(datadesc, 'PatternJumpTable') + temp_elem.set('Enabled', 'false') + temp_elem.set('Count', '65536') + steps = ET.SubElement(datadesc, 'Steps') + steps.set('StepCount', '{:d}'.format(N)) + steps.set('TrackCount', '{:d}'.format(chans)) + + for n in range(1, N+1): + step = ET.SubElement(steps, 'Step') + temp_elem = ET.SubElement(step, 'StepNumber') + temp_elem.text = '{:d}'.format(n) + # repetitions + rep = ET.SubElement(step, 'Repeat') + repcount = ET.SubElement(step, 'RepeatCount') + if nreps[n-1] == 0: + rep.text = 'Infinite' + repcount.text = '1' + elif nreps[n-1] == 1: + rep.text = 'Once' + repcount.text = '1' + else: + rep.text = 'RepeatCount' + repcount.text = '{:d}'.format(nreps[n-1]) + # trigger wait + temp_elem = ET.SubElement(step, 'WaitInput') + temp_elem.text = waitinputs[trig_waits[n-1]] + # event jump + temp_elem = ET.SubElement(step, 'EventJumpInput') + temp_elem.text = eventinputs[event_jumps[n-1]] + jumpto = ET.SubElement(step, 'EventJumpTo') + jumpstep = ET.SubElement(step, 'EventJumpToStep') + if event_jump_to[n-1] == 0: + jumpto.text = 'Next' + jumpstep.text = '1' + else: + jumpto.text = 'StepIndex' + jumpstep.text = '{:d}'.format(event_jump_to[n-1]) + # Go to + goto = ET.SubElement(step, 'GoTo') + gotostep = ET.SubElement(step, 'GoToStep') + if go_to[n-1] == 0: + goto.text = 'Next' + gotostep.text = '1' + else: + goto.text = 'StepIndex' + gotostep.text = '{:d}'.format(go_to[n-1]) + + assets = ET.SubElement(step, 'Assets') + for wfm in wfm_names_arr[:, n-1]: + asset = ET.SubElement(assets, 'Asset') + temp_elem = ET.SubElement(asset, 'AssetName') + temp_elem.text = wfm + temp_elem = ET.SubElement(asset, 'AssetType') + temp_elem.text = 'Waveform' + + flags = ET.SubElement(step, 'Flags') + for _ in range(chans): + flagset = ET.SubElement(flags, 'FlagSet') + for flg in ['A', 'B', 'C', 'D']: + temp_elem = ET.SubElement(flagset, 'Flag') + temp_elem.set('name', flg) + temp_elem.text = 'NoChange' + + temp_elem = ET.SubElement(datasets, 'ProductSpecific') + temp_elem.set('name', '') + temp_elem = ET.SubElement(datafile, 'Setup') + + xmlstr = ET.tostring(datafile, encoding='unicode') + xmlstr = xmlstr.replace('><', '>\r\n<') + + # As the final step, count the length of the header and write this + # in the DataFile tag attribute 'offset' + + xmlstr = xmlstr.replace('0'*offsetdigits, + '{num:0{pad}d}'.format(num=len(xmlstr), + pad=offsetdigits)) + + return xmlstr diff --git a/qcodes/instrument_drivers/tektronix/AWG70002A.py b/qcodes/instrument_drivers/tektronix/AWG70002A.py new file mode 100644 index 00000000000..b41ce5111fe --- /dev/null +++ b/qcodes/instrument_drivers/tektronix/AWG70002A.py @@ -0,0 +1,21 @@ +from .AWG70000A import AWG70000A + + +class AWG70002A(AWG70000A): + """ + The QCoDeS driver for Tektronix AWG70002A series AWG's. + + All the actual driver meat is in the superclass AWG70000A. + """ + + def __init__(self, name: str, address: str, + timeout: float=10, **kwargs) -> None: + """ + Args: + name: The name used internally by QCoDeS in the DataSet + address: The VISA resource name of the instrument + timeout: The VISA timeout time (in seconds). + """ + + super().__init__(name, address, num_channels=2, + timeout=timeout, **kwargs) diff --git a/qcodes/tests/drivers/test_tektronix_AWG70000A.py b/qcodes/tests/drivers/test_tektronix_AWG70000A.py new file mode 100644 index 00000000000..683838088d2 --- /dev/null +++ b/qcodes/tests/drivers/test_tektronix_AWG70000A.py @@ -0,0 +1,67 @@ +from io import StringIO + +import pytest +from hypothesis import given, settings +import hypothesis.strategies as hst +from lxml import etree + +from qcodes.instrument_drivers.tektronix.AWG70002A import AWG70002A +from qcodes.instrument_drivers.tektronix.AWG70000A import AWG70000A +import qcodes.instrument.sims as sims +visalib = sims.__file__.replace('__init__.py', 'Tektronix_AWG70000A.yaml@sim') + + +@pytest.fixture(scope='function') +def awg2(): + awg2_sim = AWG70002A('awg2_sim', + address='GPIB0::2::65535::INSTR', + visalib=visalib) + yield awg2_sim + + awg2_sim.close() + + +def test_init_awg2(awg2): + + idn_dict = awg2.IDN() + + assert idn_dict['vendor'] == 'QCoDeS' + + +@settings(deadline=1000, max_examples=25) +@given(N=hst.integers(1, 1000)) +def test_SML_successful_generation_vary_length(N): + + tw = [0]*N + nreps = [1]*N + ejs = [0]*N + ejt = [0]*N + goto = [0]*N + wfm_names = [['ch{}pos{}'.format(ch, pos) + for pos in range(N)] for ch in range(1, 3)] + + seqname = 'seq' + + smlstring = AWG70000A._makeSMLFile(tw, nreps, ejs, ejt, goto, + wfm_names, seqname) + + # This line will raise an exception if the XML is not valid + etree.parse(StringIO(smlstring)) + + +@given(num_samples=hst.integers(min_value=2400), + markers_included=hst.booleans()) +def test_WFMXHeader_succesful(num_samples, markers_included): + + xmlstr = AWG70000A._makeWFMXFileHeader(num_samples, markers_included) + etree.parse(StringIO(xmlstr)) + + +@given(num_samples=hst.integers(max_value=2399), + markers_included=hst.booleans()) +def test_WFMXHeader_failing(num_samples, markers_included): + with pytest.raises(ValueError): + AWG70000A._makeWFMXFileHeader(num_samples, markers_included) + + +# TODO: Add some failing tests for inproper input diff --git a/test_requirements.txt b/test_requirements.txt index 40bfea9e683..cd475aa5d3f 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -4,3 +4,4 @@ pytest codacy-coverage hypothesis pyvisa-sim +lxml From f35d0a45089498d3eb609fac2815ea16892b80b8 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 11 Dec 2017 15:12:07 +0100 Subject: [PATCH 74/77] Hypothesis timings (#912) * these tests are sometimes slower than 200 ms on travis * Travis can be really slow on this test so increase the time * more time for this one too --- qcodes/tests/drivers/test_ami430.py | 4 ++-- qcodes/tests/drivers/test_tektronix_AWG70000A.py | 2 +- qcodes/tests/test_combined_loop.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qcodes/tests/drivers/test_ami430.py b/qcodes/tests/drivers/test_ami430.py index 11bdff8b79e..892420034f9 100644 --- a/qcodes/tests/drivers/test_ami430.py +++ b/qcodes/tests/drivers/test_ami430.py @@ -199,7 +199,7 @@ def test_spherical_setpoints(current_driver, set_target): @given(set_target=random_coordinates["cylindrical"]) -@settings(max_examples=10) +@settings(max_examples=10, deadline=300) def test_cylindrical_setpoints(current_driver, set_target): """ Check that the individual x, y, z instruments are getting the set @@ -221,7 +221,7 @@ def test_cylindrical_setpoints(current_driver, set_target): @given(set_target=random_coordinates["cartesian"]) -@settings(max_examples=10) +@settings(max_examples=10, deadline=300) def test_measured(current_driver, set_target): """ Simply call the measurement methods and verify that no exceptions diff --git a/qcodes/tests/drivers/test_tektronix_AWG70000A.py b/qcodes/tests/drivers/test_tektronix_AWG70000A.py index 683838088d2..2e032c38837 100644 --- a/qcodes/tests/drivers/test_tektronix_AWG70000A.py +++ b/qcodes/tests/drivers/test_tektronix_AWG70000A.py @@ -28,7 +28,7 @@ def test_init_awg2(awg2): assert idn_dict['vendor'] == 'QCoDeS' -@settings(deadline=1000, max_examples=25) +@settings(deadline=1500, max_examples=25) @given(N=hst.integers(1, 1000)) def test_SML_successful_generation_vary_length(N): diff --git a/qcodes/tests/test_combined_loop.py b/qcodes/tests/test_combined_loop.py index 1ed15160dce..30bcc1c1adb 100644 --- a/qcodes/tests/test_combined_loop.py +++ b/qcodes/tests/test_combined_loop.py @@ -102,7 +102,7 @@ def inner(): min_size=2, max_size=2, unique=True).map(sorted), z_start_stop=hst.lists(hst.integers(min_value=-800, max_value=400), min_size=2, max_size=2, unique=True).map(sorted)) - @settings(max_examples=10, deadline=300) + @settings(max_examples=10, deadline=600) def testLoopCombinedParameterAndMore(self, npoints, x_start_stop, y_start_stop, z_start_stop): x_set = np.linspace(x_start_stop[0], x_start_stop[1], npoints) y_set = np.linspace(y_start_stop[0], y_start_stop[1], npoints) From 23893e76ccfbccf35217fba94a90bdd428268df2 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 12 Dec 2017 15:06:25 +0100 Subject: [PATCH 75/77] Use Codecov for coverage measurement (#913) * install codecov * upload to codecov --- .travis.yml | 4 +++- test_requirements.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2c9e622ee0f..a8a3fa16ffa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,14 +37,16 @@ before_script: # configure a headless display to test plot generation script: - cd qcodes - py.test --cov=qcodes --cov-report xml --cov-config=.coveragerc + # build docs with warnings as errors - | cd ../docs make SPHINXOPTS="-W" html-api - cd .. after_success: - # install dependencies for docs build + # upload code coverage - python-codacy-coverage -r qcodes/coverage.xml + - codecov # upload the docs - | if [[ $TRAVIS_REPO_SLUG == "QCoDeS/Qcodes" && $TRAVIS_BRANCH == "master" && $TRAVIS_PULL_REQUEST == "false" ]]; then diff --git a/test_requirements.txt b/test_requirements.txt index cd475aa5d3f..412bae83ec6 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -5,3 +5,4 @@ codacy-coverage hypothesis pyvisa-sim lxml +codecov From 8b3cf137419990fca3eb51a31823b21eb4f22920 Mon Sep 17 00:00:00 2001 From: dpfranke Date: Wed, 13 Dec 2017 08:18:21 +0100 Subject: [PATCH 76/77] Correct dac validators (#906) use the correct validator range (cf. d5a driver) and adjust naming --- qcodes/instrument_drivers/QuTech/D5a.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument_drivers/QuTech/D5a.py b/qcodes/instrument_drivers/QuTech/D5a.py index 152807f2f09..0499ec2c498 100644 --- a/qcodes/instrument_drivers/QuTech/D5a.py +++ b/qcodes/instrument_drivers/QuTech/D5a.py @@ -60,7 +60,7 @@ def __init__(self, name, spi_rack, module, inter_delay=0.1, dac_step=10e-3, self._span_set_map = { '4v uni': 0, '4v bi': 2, - '2.5v bi': 4, + '2v bi': 4, } self._span_get_map = {v: k for k, v in self._span_set_map.items()} @@ -117,9 +117,9 @@ def _set_span(self, dac, span_str): def _get_validator(self, dac): span = self.d5a.span[dac] if span == D5a_module.range_2V_bi: - validator = Numbers(-1 * self._gain, 1 * self._gain) - elif span == D5a_module.range_4V_bi: validator = Numbers(-2 * self._gain, 2 * self._gain) + elif span == D5a_module.range_4V_bi: + validator = Numbers(-4 * self._gain, 4 * self._gain) elif span == D5a_module.range_4V_uni: validator = Numbers(0, 4 * self._gain) else: From a7dbd3ac5f750b16fe3d044de3040ed8542e8e7a Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 14 Dec 2017 00:03:18 +1100 Subject: [PATCH 77/77] Feature/Replace qc.Loop with for loop using iPython magic (#723) * Added magic file * feat: add `register_magic` to config * feat: add magic to qcodes init, including config * fix: change measurement to line_cell_magic, display help when used as line magic * refactor: please the Codacy gods * fix: cleanup iPython check * fix: back to try: except * fix: forgot a loop reference * feat: add delay functionality * fix: for_opts should be for_code * feat: add check for python>=3.6 * doc: add mention of modified `for` syntax --- qcodes/__init__.py | 11 ++ qcodes/config/qcodesrc.json | 3 +- qcodes/config/qcodesrc_schema.json | 8 ++ qcodes/utils/magic.py | 159 +++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 qcodes/utils/magic.py diff --git a/qcodes/__init__.py b/qcodes/__init__.py index cfa0e3f04a6..0a1ad2d4f0b 100644 --- a/qcodes/__init__.py +++ b/qcodes/__init__.py @@ -67,3 +67,14 @@ from qcodes.utils import validators from qcodes.instrument_drivers.test import test_instruments, test_instrument + +try: + get_ipython() # Check if we are in iPython + from qcodes.utils.magic import register_magic_class + _register_magic = config.core.get('register_magic', False) + if _register_magic is not False: + register_magic_class(magic_commands=_register_magic) +except NameError: + pass +except RuntimeError as e: + print(e) \ No newline at end of file diff --git a/qcodes/config/qcodesrc.json b/qcodes/config/qcodesrc.json index 2d1a9cb9be6..908df5e4759 100644 --- a/qcodes/config/qcodesrc.json +++ b/qcodes/config/qcodesrc.json @@ -1,7 +1,8 @@ { "core":{ "loglevel": "DEBUG", - "default_fmt": "data/{date}/#{counter}_{name}_{time}" + "default_fmt": "data/{date}/#{counter}_{name}_{time}", + "register_magic": true }, "gui" :{ "notebook": true, diff --git a/qcodes/config/qcodesrc_schema.json b/qcodes/config/qcodesrc_schema.json index 885a658991c..a5d59c2b8fc 100644 --- a/qcodes/config/qcodesrc_schema.json +++ b/qcodes/config/qcodesrc_schema.json @@ -23,6 +23,14 @@ "INFO", "DEBUG" ] + }, + "register_magic" : { + "description": "Register QCoDeS magic when in iPython. Can be set to True, False, or a list of magic commands to be registered", + "anyOf" : [ + {"type": "boolean"}, + {"type": "array"} + ], + "default": true } }, "required":["loglevel" ] diff --git a/qcodes/utils/magic.py b/qcodes/utils/magic.py new file mode 100644 index 00000000000..f450dce97c4 --- /dev/null +++ b/qcodes/utils/magic.py @@ -0,0 +1,159 @@ +import sys +from IPython.core.magic import Magics, magics_class, line_cell_magic + +if sys.version_info < (3, 6): + raise RuntimeError('Magic only supported for Python version 3.6 and up') + +@magics_class +class QCoDeSMagic(Magics): + """Magics related to code management (loading, saving, editing, ...).""" + + def __init__(self, *args, **kwargs): + self._knowntemps = set() + super(QCoDeSMagic, self).__init__(*args, **kwargs) + + @line_cell_magic + def measurement(self, line, cell=None): + """ + Create qcodes.Loop measurement mimicking Python `for` syntax via + iPython magic. + Upon execution of a notebook cell, the code is transformed from the + for loop structure to a QCoDeS Loop before being executed. + Can be run by having %%measurement in the first line of a cell, + followed by the measurement name (see below for an example) + + The for loop syntax differs slightly from a Python `for` loop, + as it uses `for {iterable}` instead of `for {element} in {iterable}`. + The reason is that `{element}` cannot be accessed (yet) in QCoDeS loops. + + Comments (#) are ignored in the loop. + Any code after the loop will also be run, if separated by a blank + line from the loop. + The Loop object is by default stored in a variable named `loop`, + and the dataset in `data`, and these can be overridden using options. + Must be run in a Jupyter Notebook. + Delays can be provided in a loop by adding `-d {delay}` after `for` + + The following options can be passed along with the measurement name + (e.g. %%measurement -px -d data_name {measurement_name}): + -p : print transformed code + -x : Do not execute code + -d : Use custom name for dataset + -l : Use custom name for Loop + + An example for a loop cell is as follows: + + %%measurement {-options} {measurement_name} + for {sweep_vals}: + {measure_parameter1} + {measure_parameter2} + for -d 1 {sweep_vals2}: + {measure_parameter3} + + {Additional code} + ``` + + which will be internally transformed to: + + ``` + import qcodes + loop = qcodes.Loop({sweep_vals}).each( + {measure_parameter1}, + {measure_parameter2}, + qcodes.Loop({sweep_vals2}, delay=1).each( + {measure_parameter3})) + data = loop.get_data_set(name={measurement_name}) + + {Additional code} + ``` + + An explicit example of the line `for {sweep_vals}:` could be + `for sweep_parameter.sweep(0, 42, step=1):` + + """ + + if cell is None: + # No loop provided, print documentation + print(self.measurement.__doc__) + return + + # Parse line, get measurement name and any possible options + options, msmt_name = self.parse_options(line, 'pd:l:x') + data_name = options.get('d', 'data') + loop_name = options.get('l', 'loop') + + + lines = cell.splitlines() + assert lines[0][:3] == 'for', "Measurement must start with for loop" + + contents = f'import qcodes\n{loop_name} = ' + previous_level = 0 + for k, line in enumerate(lines): + line, level = line.lstrip(), int((len(line)-len(line.lstrip())) / 4) + + if not line: + # Empty line, end of loop + break + elif line[0] == '#': + # Ignore comment + continue + else: + line_representation = ' ' * level * 4 + if level < previous_level : + # Exiting inner loop, close bracket + line_representation += '),' * (previous_level - level) + line_representation += '\n' + ' ' * level * 4 + + if line[:3] == 'for': + # New loop + for_opts, for_code = self.parse_options(line[4:-1], 'd:') + if 'd' in for_opts: + # Delay option provided + line_representation += f'qcodes.Loop({for_code}, ' \ + f'delay={for_opts["d"]}).each(\n' + else: + line_representation += f'qcodes.Loop({for_code}).each(\n' + else: + # Action in current loop + line_representation += f'{line},\n' + contents += line_representation + + # Remember level for next iteration (might exit inner loop) + previous_level = level + + # Add closing brackets for any remaining loops + contents += ')' * previous_level + '\n' + # Add dataset + contents += f"{data_name} = {loop_name}.get_data_set(name='{msmt_name}')" + + for line in lines[k+1:]: + contents += '\n' + line + + if 'p' in options: + print(contents) + + if 'x' not in options: + # Execute contents + self.shell.run_cell(contents, store_history=True, silent=True) + + +def register_magic_class(cls=QCoDeSMagic, magic_commands=True): + """ + Registers a iPython magic class + Args: + cls: magic class to register + magic_commands (List): list of magic commands within the class to + register. If not specified, all magic commands are registered + + """ + + ip = get_ipython() + if ip is None: + raise RuntimeError('No iPython shell found') + else: + if magic_commands is not True: + # filter out any magic commands that are not in magic_commands + cls.magics = {line_cell: {key: val for key, val in magics.items() + if key in magic_commands} + for line_cell, magics in cls.magics.items()} + ip.magics_manager.register(cls) \ No newline at end of file