Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat cm m5180 improvements #121

Merged
merged 3 commits into from
Mar 29, 2022
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 38 additions & 57 deletions qcodes_contrib_drivers/drivers/CopperMountain/M5180.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
# Simon Zihlmannr <[email protected]>, february/march 2021
import logging
import numpy as np
from typing import Tuple, Optional, Any
import cmath, math
from typing import Tuple, Any

from qcodes import VisaInstrument
from qcodes.utils.validators import Numbers, Enum, Ints
from qcodes.utils.validators import Numbers, Enum, Ints, Bool
from qcodes.utils.helpers import create_on_off_val_mapping

from qcodes.instrument.parameter import (
MultiParameter,
ManualParameter,
ParamRawDataType
)

Expand Down Expand Up @@ -104,17 +106,13 @@ def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]:

class PointMagPhase(MultiParameter):
"""
Returns the first point of a sweep (at start frequency).
Returns the average Sxx of a frequency sweep.
Work around for a CW mode where only one point is read.
Ideally, npts is set to 2 and stop = start + 1 (in Hz), this will maximize
the measurement speed.
npts=2 and stop = start + 1 (in Hz) is required.
"""

def __init__(self,
name: str,
start: float,
stop: float,
npts: int,
instrument: "M5180",
**kwargs: Any,
) -> None:
Expand All @@ -123,10 +121,7 @@ def __init__(self,

Args:
name (str): Name of point measurement
start (float): Start frequency (frequency at which it will measure)
stop (float): Stop frequency, ideally start - 1 Hz
npts (int): Number of points of the sweep, ideally 2
instrument: Instrument to which sweep is bound to.
instrument: Instrument to which parameter is bound to.
"""

super().__init__(
Expand All @@ -140,39 +135,27 @@ def __init__(self,
f"{instrument.short_name} {name} phase",
),
units=("dB", "rad"),
setpoint_units=(("Hz",), ("Hz",)),
setpoint_labels=(
(f"{instrument.short_name} frequency",),
(f"{instrument.short_name} frequency",),
),
setpoint_names=(
(f"{instrument.short_name}_frequency",),
(f"{instrument.short_name}_frequency",),
),
shapes=((npts,), (npts,),),
setpoints=((), (),),
shapes=((), (),),
**kwargs,
)
self.set_sweep(start, stop, npts)

def set_sweep(self, start: float, stop: float, npts: int) -> None:
"""Updates the setpoints and shapes based on start, stop and npts.

Args:
start (float): start frequency
stop (float): stop frequency, not used
npts (int): number of points, not used
"""
f = tuple(np.linspace(int(start), int(stop), num=npts))
self.setpoints = ((start,), (start,))
self.shapes = ((), ())

def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]:
"""Gets data from instrument

Returns:
Tuple[ParamRawDataType, ...]: magnitude, phase
"""

assert isinstance(self.instrument, M5180)
# check that npts, start and stop fullfill requirements if point_check_sweep_first is True.
if self.instrument.point_check_sweep_first:
if self.instrument.npts() != 2:
raise ValueError('Npts is not 2 but {}. Please set it to 2'.format(self.instrument.npts()))
if self.instrument.stop() - self.instrument.start() != 1:
raise ValueError('Stop-start is not 1 Hz but {} Hz. Please adjust'
'start or stop.'.format(self.instrument.stop()-self.instrument.start()))

self.instrument.write('CALC1:PAR:COUN 1') # 1 trace
self.instrument.write('CALC1:PAR1:DEF {}'.format(self.name[-3:]))
self.instrument.trigger_source('bus') # set the trigger to bus
Expand All @@ -182,15 +165,15 @@ def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]:
# get data from instrument
self.instrument.write('CALC1:TRAC1:FORM SMITH') # ensure correct format
sxx_raw = self.instrument.ask("CALC1:TRAC1:DATA:FDAT?")
self.instrument.write('CALC1:TRAC1:FORM MLOG')

# Get data as numpy array
sxx = np.fromstring(sxx_raw, dtype=float, sep=',')
sxx = sxx[0::2] + 1j*sxx[1::2]

# Return only the first point of the trace, which will have "start" as
# Return the average of the trace, which will have "start" as
# its setpoint
return self.instrument._db(sxx[0]), np.angle(sxx[0])
sxx_mean = np.mean(sxx)
return 20*math.log10(abs(sxx_mean)), cmath.phase(sxx_mean)


class M5180(VisaInstrument):
Expand All @@ -204,7 +187,7 @@ def __init__(self, name : str,
timeout : int=100000,
**kwargs):
"""
QCoDeS driver for the VNA S5180 from Copper Mountain.
QCoDeS driver for the VNA M5180 from Copper Mountain.
This driver only uses one channel.

Args:
Expand Down Expand Up @@ -315,7 +298,7 @@ def __init__(self, name : str,
set_cmd=self._set_start,
unit='Hz',
vals=Numbers(min_value=300e3,
max_value=18e9))
max_value=18e9-1))

self.add_parameter(name='stop',
label='Stop Frequency',
Expand All @@ -332,17 +315,17 @@ def __init__(self, name : str,
get_cmd='SENS1:FREQ:CENT?',
set_cmd=self._set_center,
unit='Hz',
vals=Numbers(min_value=100e3,
max_value=18e9))
vals=Numbers(min_value=100e3+1,
max_value=18e9-1))

self.add_parameter(name='span',
label='Frequency Span',
get_parser=float,
get_cmd='SENS1:FREQ:SPAN?',
set_cmd=self._set_span,
unit='Hz',
vals=Numbers(min_value=100e3,
max_value=18e9))
vals=Numbers(min_value=1,
max_value=18e9-1))

self.add_parameter('npts',
label='Number of points',
Expand Down Expand Up @@ -403,29 +386,27 @@ def __init__(self, name : str,
parameter_class=FrequencySweepMagPhase)

self.add_parameter(name='point_s11',
start=self.start(),
stop=self.stop(),
npts=self.npts(),
parameter_class=PointMagPhase)

self.add_parameter(name='point_s12',
start=self.start(),
stop=self.stop(),
npts=self.npts(),
parameter_class=PointMagPhase)

self.add_parameter(name='point_s21',
start=self.start(),
stop=self.stop(),
npts=self.npts(),
parameter_class=PointMagPhase)

self.add_parameter(name='point_s22',
start=self.start(),
stop=self.stop(),
npts=self.npts(),
parameter_class=PointMagPhase)

self.add_parameter(name="point_check_sweep_first",
parameter_class=ManualParameter,
initial_value=True,
vals=Bool(),
docstring="Parameter that enables a few commands, which are called"
"before each get of a point_sxx parameter checking whether the vna"
"is setup correctly. Is recommended to be True, but can be turned"
"off if one wants to minimize overhead.",
)

self.connect_message()

def _set_start(self, val: float) -> None:
Expand Down Expand Up @@ -586,7 +567,7 @@ def update_lin_traces(self) -> None:
stop = self.stop()
npts = self.npts()
for _, parameter in self.parameters.items():
if isinstance(parameter, (FrequencySweepMagPhase, PointMagPhase)):
if isinstance(parameter, (FrequencySweepMagPhase)):
try:
parameter.set_sweep(start, stop, npts)
except AttributeError:
Expand Down