diff --git a/qcodes_contrib_drivers/drivers/CopperMountain/M5180.py b/qcodes_contrib_drivers/drivers/CopperMountain/M5180.py index 4f993867a..22e017ab9 100644 --- a/qcodes_contrib_drivers/drivers/CopperMountain/M5180.py +++ b/qcodes_contrib_drivers/drivers/CopperMountain/M5180.py @@ -149,7 +149,7 @@ def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]: 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.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: @@ -173,7 +173,79 @@ def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]: # Return the average of the trace, which will have "start" as # its setpoint sxx_mean = np.mean(sxx) - return 20*math.log10(abs(sxx_mean)), cmath.phase(sxx_mean) + return 20*math.log10(abs(sxx_mean)), (cmath.phase(sxx_mean)) + + + +class PointIQ(MultiParameter): + """ + Returns the average Sxx of a frequency sweep, in terms of I and Q. + Work around for a CW mode where only one point is read. + npts=2 and stop = start + 1 (in Hz) is required. + """ + + def __init__(self, + name: str, + instrument: "M5180", + **kwargs: Any, + ) -> None: + """I and Q measurement of a single point at start + frequency. + + Args: + name (str): Name of point measurement + instrument: Instrument to which parameter is bound to. + """ + + super().__init__( + name, + instrument=instrument, + names=( + f"{instrument.short_name}_{name}_i", + f"{instrument.short_name}_{name}_q"), + labels=( + f"{instrument.short_name} {name} i", + f"{instrument.short_name} {name} q", + ), + units=("V", "V"), + setpoints=((), (),), + shapes=((), (),), + **kwargs, + ) + + def get_raw(self) -> Tuple[ParamRawDataType, ParamRawDataType]: + """Gets data from instrument + + Returns: + Tuple[ParamRawDataType, ...]: I, Q + """ + + 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 + self.instrument.write('TRIG:SEQ:SING') # Trigger a single sweep + self.instrument.ask('*OPC?') # Wait for measurement to complete + + # get data from instrument + self.instrument.write('CALC1:TRAC1:FORM SMITH') # ensure correct format + sxx_raw = self.instrument.ask("CALC1:TRAC1:DATA:FDAT?") + + # Get data as numpy array + sxx = np.fromstring(sxx_raw, dtype=float, sep=',') + + # Return the average of the trace, which will have "start" as + # its setpoint + return np.mean(sxx[0::2]), np.mean(sxx[1::2]) + class M5180(VisaInstrument): @@ -397,6 +469,18 @@ def __init__(self, name : str, self.add_parameter(name='point_s22', parameter_class=PointMagPhase) + self.add_parameter(name='point_s11_iq', + parameter_class=PointIQ) + + self.add_parameter(name='point_s12_iq', + parameter_class=PointIQ) + + self.add_parameter(name='point_s21_iq', + parameter_class=PointIQ) + + self.add_parameter(name='point_s22_iq', + parameter_class=PointIQ) + self.add_parameter(name="point_check_sweep_first", parameter_class=ManualParameter, initial_value=True,