Ejemplo n.º 1
0
def _find_gap_voltage(volt_v, curr_a, **kw):
    """Find gap voltage.

    Args:
        volt_v (ndarray): voltage, in V
        curr_a (ndarray): current, in A

    Keyword Args:
        vgap_threshold (float): the current at the gap voltage

    Returns:
        float: gap voltage

    """

    # Unpack keyword arguments
    vgap_threshold = kw.get('vgap_threshold', PARAMS['vgap_threshold'])

    # Method 1: current threshold
    if vgap_threshold is not None:
        idx = np.abs(curr_a - vgap_threshold).argmin()
        vgap = volt_v[idx]
        return vgap

    # Method 2: max derivative
    vstep = volt_v[1] - volt_v[0]
    mask = (1.5e-3 < volt_v) & (volt_v < 3.5e-3)
    der = slope(volt_v[mask], curr_a[mask])
    der = gauss_conv(der, sigma=0.2e-3 / vstep)
    vgap = volt_v[mask][der.argmax()]

    return vgap
Ejemplo n.º 2
0
def _find_gap_voltage(volt_v, curr_a, **kw):
    """Find gap voltage.

    Args:
        volt_v (ndarray): voltage, in V
        curr_a (ndarray): current, in A

    Keyword Args:
        vrn (list): Voltage range over which to calculate the normal
            resistance, in units [V]
        debug (bool): plot for debugging purposes

    Returns:
        float: gap voltage

    """

    # Unpack keyword arguments
    vrn = kw.get('vrn', PARAMS['vrn'])
    debug = kw.get('debug', PARAMS['debug'])

    # Normal resistance slope
    mask = (vrn[0] < volt_v) & (volt_v < vrn[1])
    vtmp, itmp = volt_v[mask], curr_a[mask]
    prn = np.polyfit(vtmp, itmp, 1)

    # Find max derivative in I-V curve
    vstep = volt_v[1] - volt_v[0]
    mask = 2e-3 < volt_v
    der = slope(volt_v[mask], curr_a[mask])
    der = gauss_conv(der, sigma=0.2e-3 / vstep)
    vgap = volt_v[mask][der.argmax()]

    # Fit line around max derivative
    mask = (vgap - 0.1e-4 < volt_v) & (volt_v < vgap + 0.1e-4)
    vtmp, itmp = volt_v[mask], curr_a[mask]
    pgap = np.polyfit(vtmp, itmp, 1)

    # Find "corner" in I-V curve
    vcorner = (pgap[1] - prn[1]) / (prn[0] - pgap[0])
    icorner = pgap[0] * vcorner + pgap[1]

    # Find gap
    igap = icorner / 2
    vgap = (igap - pgap[1]) / pgap[0]

    if debug:
        plt.figure()
        plt.plot(volt_v * 1e3, curr_a * 1e6)
        plt.plot(volt_v * 1e3, np.polyval(prn, volt_v) * 1e6, 'k--')
        plt.plot(volt_v * 1e3, np.polyval(pgap, volt_v) * 1e6, 'r--')
        plt.plot([vcorner * 1e3], [icorner * 1e6], 'r*')
        plt.plot([vgap * 1e3], [igap * 1e6], 'k*')
        plt.xlim([volt_v.min() * 1e3, volt_v.max() * 1e3])
        plt.ylim([curr_a.min() * 1e6, curr_a.max() * 1e6])
        plt.show()

    return vgap
Ejemplo n.º 3
0
def _sample_curve(voltage, current, max_npts, smear):
    """Sample curve. Sample more often when the curve is curvier.

    Args:
        voltage (ndarray): DC bias voltage
        current (ndarray): current (either DC tunneling or KK)
        max_npts (int): maximum number of sample points
        smear (float): smear current (only for sampling purposes)

    Returns:
        list: indices of sample points

    """

    # Second derivative
    dd_current = np.abs(slope(voltage, slope(voltage, current)))

    # Cumulative sum of second derivative
    v_step = voltage[1] - voltage[0]
    cumsum = np.cumsum(gauss_conv(dd_current, sigma=smear / v_step))

    # Build sampling array
    idx_list = [0]
    # Add indices based on curvy-ness
    cumsum_last = 0.
    voltage_last = voltage[0]
    for idx, v in enumerate(voltage):
        condition1 = abs(v) < 0.05 or abs(v - 1) < 0.1 or abs(v + 1) < 0.1
        condition2 = v - voltage_last >= 1.
        condition3 = (cumsum[idx] - cumsum_last) * max_npts / cumsum[-1] > 1
        condition4 = idx < 3 or idx > len(voltage) - 4
        if condition1 or condition2 or condition3 or condition4:
            if idx != idx_list[-1]:
                idx_list.append(idx)
            voltage_last = v
            cumsum_last = cumsum[idx]
    # Add 10 to start/end
    for i in range(0, int(1 / VSTEP), int(1 / VSTEP / 10)):
        idx_list.append(i)
    for i in range(
            len(voltage) - int(1 / VSTEP) - 1, len(voltage),
            int(1 / VSTEP / 10)):
        idx_list.append(i)
    # Add 30 pts to middle
    ind_low = np.abs(voltage + 1.).argmin()
    ind_high = np.abs(voltage - 1.).argmin()
    npts = ind_high - ind_low
    for i in range(ind_low, ind_high, npts // 30):
        idx_list.append(i)

    idx_list = list(set(idx_list))
    idx_list.sort()

    return idx_list
Ejemplo n.º 4
0
    def __init__(self, **params):

        params = _default_params(params)

        if params['verbose']:
            print("Generating response function:")

        # Reflect about y-axis
        voltage = np.copy(VINIT)
        current = iv.perfect(voltage)

        if params['v_smear'] is None:

            voltage = np.r_[-voltage[::-1][:-1], voltage]
            current = np.r_[-current[::-1][:-1], current]

            # KK transform
            current_kk = iv.perfect_kk(voltage)

            # Place interpolations into hidden attributes
            self._f_idc = iv.perfect
            self._f_ikk = iv.perfect_kk
            self._f_didc = None
            self._f_dikk = None

            # Save DC I-V curve and KK transform as attributes
            self.voltage = voltage
            self.current = current
            self.voltage_kk = voltage
            self.current_kk = current_kk

        # Smear IV curve (optional)
        else:

            tmp = np.zeros_like(voltage)
            idx = np.abs(voltage - 1.).argmin()
            tmp[idx] = 1.

            v_step = voltage[1] - voltage[0]
            current = gauss_conv(tmp, sigma=params['v_smear']/v_step) + \
                      iv.perfect(voltage)
            if params['verbose']:
                print(" - Voltage smear: {:.4f}".format(params['v_smear']))

            RespFn.__init__(self, voltage, current, **params)
Ejemplo n.º 5
0
    def __init__(self, voltage, current, **params):

        params = _default_params(params)

        if params['verbose']:
            print("Generating response function:")

        assert voltage[0] == 0., "First voltage value must be zero"
        assert voltage[-1] > 5, "Voltage must extend to at least 5"

        # Reflect about y-axis
        voltage = np.r_[-voltage[::-1][:-1], voltage]
        current = np.r_[-current[::-1][:-1], current]

        # Smear DC I-V curve (optional)
        if params['v_smear'] is not None:
            v_step = voltage[1] - voltage[0]
            current = gauss_conv(current - voltage,
                                 sigma=params['v_smear'] / v_step) + voltage
            if params['verbose']:
                print(" - Voltage smear: {:.4f}".format(params['v_smear']))

        # Calculate Kramers-Kronig (KK) transform
        current_kk = kk_trans(voltage, current, params['kk_n'])

        # Interpolate
        f_interp = _setup_interpolation(voltage, current, current_kk, **params)

        # Place interpolation objects into hidden attributes
        self._f_idc = f_interp[0]
        self._f_ikk = f_interp[1]
        self._f_didc = f_interp[2]
        self._f_dikk = f_interp[3]

        # Save DC I-V curve and KK transform as attributes
        self.voltage = voltage
        self.current = current
        self.voltage_kk = voltage
        self.current_kk = current_kk
Ejemplo n.º 6
0
    params['t_cold'] = args.tcold

# Plot data
if args.verbose:
    print(' - Generating figure')
fig, ax = plt.subplots(figsize=(args.width, args.height))

for filename in args.file:
    if args.verbose:
        print("   - Importing: " + filename)
    # Import and plot noise temperature
    data = if_response(filename, ifresp_delimiter=args.delimiter)
    freq, tn = data[0], data[1]
    # Filter
    if args.filter is not None:
        tn = gauss_conv(tn, args.filter)
    plt.plot(freq, tn, label=filename)

# Figure properties
if args.verbose:
    print(' - Customizing figure')
plt.xlabel(r'Frequency (GHz)')
plt.ylabel(r'Noise Temperature (K)')
if args.xmax is not None:
    plt.xlim([0, args.xmax])
if args.ymax is not None:
    plt.ylim([0, args.ymax])
else:
    plt.ylim([0, 500])
plt.legend(loc=0)
if args.title is not None:
Ejemplo n.º 7
0
def _load_if(ifdata, dc, **kwargs):
    """Import IF data.

    Args:
        ifdata: IF data. A Numpy array. The data
            should have two columns: the first for voltage, and the second
            for IF power.
        dc (qmix.exp.iv_data.DCIVData): DC I-V metadata.

    Keyword arguments:
        v_fmt (str): units for voltage ('V', 'mV', 'uV')
        ifdata_sigma (float): Standard deviation of Gaussian used for
            filtering, in units [V]
        ifdata_npts (float): evenly interpolate data to have this many data
            points
        rseries (float): series resistance of measurement system

    Returns: IF data (in matrix form)

    """

    # Unpack keyword arguments
    v_multiplier = kwargs.get('v_multiplier', PARAMS['v_multiplier'])
    sigma = kwargs.get('ifdata_sigma', PARAMS['ifdata_sigma'])
    vmax = kwargs.get('vmax', PARAMS['vmax'])
    npts = kwargs.get('ifdata_npts', PARAMS['ifdata_npts'])
    rseries = kwargs.get('rseries', PARAMS['rseries'])
    v_fmt = kwargs.get('v_fmt', PARAMS['v_fmt'])

    # Import raw IF data
    ifdata = ifdata.copy()
    assert isinstance(ifdata, np.ndarray), 'IF data should be a Numpy array.'
    assert ifdata.ndim == 2, 'IF data should be 2-dimensional.'
    assert ifdata.shape[1] == 2, 'IF data should have 2 columns.'

    # Units for voltage
    ifdata[:, 0] *= _vfmt_dict[v_fmt]

    # Clean
    ifdata = remove_nans_matrix(ifdata)
    ifdata = ifdata[np.argsort(ifdata[:, 0])]
    ifdata = remove_doubles_matrix(ifdata)

    # Correct errors in experimental system
    ifdata[:, 0] *= v_multiplier

    # Correct for offset
    ifdata[:, 0] = ifdata[:, 0] - dc.offset[0]

    # Correct for series resistance
    if rseries is not None:
        v = ifdata[:, 0]
        rstatic = dc.vraw / dc.iraw
        rstatic[rstatic < 0] = 0.
        rstatic = np.interp(v, dc.vraw, rstatic)
        iraw = np.interp(v, dc.vraw, dc.iraw)
        rj = rstatic - rseries
        v0 = iraw * rj
        ifdata[:, 0] = v0

    # Normalize voltage to gap voltage
    ifdata[:, 0] /= dc.vgap

    # Set to common voltage (so that data can be stacked)
    v, p = ifdata[:, 0], ifdata[:, 1]
    # assert v.max() > vmax / dc.vgap, \
    #     'vmax ({0}) outside data range ({1})'.format(vmax / dc.vgap, v.max())
    # assert v.min() < 0., 'V=0 not included in IF data'
    v_out = np.linspace(0, vmax / dc.vgap, npts)
    p_out = np.interp(v_out, v, p, left=0, right=0)
    ifdata = np.vstack((v_out, p_out)).T

    # Smooth IF data
    if sigma is not None:
        step = (ifdata[1, 0] - ifdata[0, 0]) * dc.vgap
        # Backwards compatibility
        if sigma > 0.5:
            sigma = sigma * step
        ifdata[:, 1] = gauss_conv(ifdata[:, 1], sigma / step)

    return ifdata
Ejemplo n.º 8
0
def _correct_offset(volt_v, curr_a, **kw):
    """Find and correct any I/V offset.

    The experimental data often has an offset in both V and I. This can be
    corrected by using the leakage current. This is found by looking at the
    derivative and correcting based on where the peak of the derivative is.

    Args:
        volt_v (ndarray): voltage, in V
        curr_a (ndarray): current, in A

    Keyword Args:
        voffset: voltage offset, in V
        ioffset: current offset, in A
        voffset_range (list): Voltage range over which to search for offset,
            in units [V].
        voffset_sigma: std dev of Gaussian filter when searching for offset

    Returns:
        tuple: corrected voltage, corrected current, I/V offset

    """

    # Unpack keyword arguments
    voffset_range = kw.get('voffset_range', PARAMS['voffset_range'])
    voffset_sigma = kw.get('voffset_sigma', PARAMS['voffset_sigma'])
    voffset = kw.get('voffset', PARAMS['voffset'])
    ioffset = kw.get('ioffset', PARAMS['ioffset'])

    if voffset is None:  # Find voffset and ioffset

        # Search over a limited voltage range
        if isinstance(voffset_range, tuple):
            mask = (voffset_range[0] < volt_v) & (volt_v < voffset_range[1])
        else:  # if int or float
            mask = (-voffset_range < volt_v) & (volt_v < voffset_range)
        v = volt_v[mask]
        i = curr_a[mask]

        # Find derivative of I-V curve
        vstep = v[1] - v[0]
        sigma = voffset_sigma / vstep
        der = slope(v, i)
        der_smooth = gauss_conv(der, sigma=sigma)

        # Offset is at max derivative
        idx = der_smooth.argmax()
        voffset = v[idx]
        # ioffset = np.interp(voffset, v, i)
        ioffset = (np.interp(voffset - 0.1e-3, v, i) +
                   np.interp(voffset + 0.1e-3, v, i)) / 2

    if ioffset is None:  # Find ioffset

        ioffset = np.interp(voffset, volt_v, curr_a)

    # Correct for the offset
    volt_v -= voffset
    curr_a -= ioffset

    return volt_v, curr_a, (voffset, ioffset)
Ejemplo n.º 9
0
def _load_if(ifdata, dc, **kwargs):
    """Import IF data.

    Args:
        ifdata: IF data. Either a CSV data file or a Numpy array. The data
            should have two columns: the first for voltage, and the second
            for IF power. If you are using a CSV file, the properties of 
            the CSV file can be set through additional keyword arguments
            (see below).
        dc (qmix.exp.iv_data.DCIVData): DC I-V metadata. 

    Keyword arguments:
        delimiter (str): delimiter used in data files
        v_fmt (str): units for voltage ('V', 'mV', 'uV')
        usecols (tuple): columns for voltage and current (e.g., ``(0,1)``)
        ifdata_sigma (float): Standard deviation of Gaussian used for 
            filtering, in units [V]
        ifdata_npts (float): evenly interpolate data to have this many data 
            points
        rseries (float): series resistance of measurement system
        skip_header: number of rows to skip at the beginning of the file

    Returns: IF data (in matrix form)

    """

    # Unpack keyword arguments
    v_multiplier = kwargs.get('v_multiplier', PARAMS['v_multiplier'])
    skip_header = kwargs.get('skip_header', PARAMS['skip_header'])
    sigma = kwargs.get('ifdata_sigma', PARAMS['ifdata_sigma'])
    vmax = kwargs.get('vmax', PARAMS['vmax'])
    npts = kwargs.get('ifdata_npts', PARAMS['ifdata_npts'])
    delim = kwargs.get('delimiter', PARAMS['delimiter'])
    usecols = kwargs.get('usecols', PARAMS['usecols'])
    rseries = kwargs.get('rseries', PARAMS['rseries'])
    v_fmt = kwargs.get('v_fmt', PARAMS['v_fmt'])

    # Import raw IF data
    if isinstance(ifdata, str):  # assume CSV data file
        ifdata = np.genfromtxt(ifdata,
                               delimiter=delim,
                               usecols=usecols,
                               skip_header=skip_header)
    elif isinstance(ifdata, np.ndarray):  # Numpy array
        ifdata = ifdata.copy()
        assert ifdata.ndim == 2, 'I-V data should be 2-dimensional.'
        assert ifdata.shape[1] == 2, 'I-V data should have 2 columns.'
    else:
        raise ValueError("Input data type not recognized.")

    # Units for voltage
    ifdata[:, 0] *= _vfmt_dict[v_fmt]

    # Clean
    ifdata = remove_nans_matrix(ifdata)
    ifdata = ifdata[np.argsort(ifdata[:, 0])]
    ifdata = remove_doubles_matrix(ifdata)

    # Correct errors in experimental system
    ifdata[:, 0] *= v_multiplier

    # Correct for offset
    ifdata[:, 0] = ifdata[:, 0] - dc.offset[0]

    # Correct for series resistance
    if rseries is not None:
        v = ifdata[:, 0]
        rstatic = dc.vraw / dc.iraw
        rstatic[rstatic < 0] = 0.
        rstatic = np.interp(v, dc.vraw, rstatic)
        iraw = np.interp(v, dc.vraw, dc.iraw)
        rj = rstatic - rseries
        v0 = iraw * rj
        ifdata[:, 0] = v0

    # Normalize voltage to gap voltage
    ifdata[:, 0] /= dc.vgap

    # Set to common voltage (so that data can be stacked)
    v, p = ifdata[:, 0], ifdata[:, 1]
    assert v.max() > vmax / dc.vgap, \
        'vmax ({0}) outside data range ({1})'.format(vmax / dc.vgap, v.max())
    assert v.min() < 0., 'V=0 not included in IF data'
    v_out = np.linspace(0, vmax / dc.vgap, npts)
    p_out = np.interp(v_out, v, p)
    ifdata = np.vstack((v_out, p_out)).T

    # Smooth IF data
    if sigma is not None:
        step = (ifdata[1, 0] - ifdata[0, 0]) * dc.vgap
        # Backwards compatibility
        if sigma > 0.5:
            sigma = sigma * step
        ifdata[:, 1] = gauss_conv(ifdata[:, 1], sigma / step)

    return ifdata