Source code for physicslab.experiment.hall

"""
Hall measurement.

Induced voltage perpendicular to both current and magnetic field.
"""


import numpy as np
import pandas as pd

from scipy.constants import e as elementary_charge

from physicslab.electricity import Carrier_concentration, Mobility, Resistance
from physicslab.ui import plot_grid
from physicslab.utility import _ColumnsBase, squarificate, get_name


[docs]def process(data, thickness=None, sheet_resistance=None): """ Bundle method. Parameter :attr:`data` must include voltage, current and magnetic field. See :class:`Columns` for details and column names. The optional parameters allows to calculate additional quantities: `concentration` and `mobility`. Supplying `None` for :attr:`data` returns :class:`pandas.Series` of the same columns with values being units. :param data: Measured data. If None, return units instead :type data: pandas.DataFrame or None :param thickness: Sample dimension perpendicular to the plane marked by the electrical contacts, defaults to None :type thickness: float, optional :param sheet_resistance: Defaults to None :type sheet_resistance: float, optional :return: Derived quantities listed in :meth:`Columns.process` or units :rtype: pandas.Series """ if data is None: from physicslab.experiment import UNITS import physicslab.electricity as el name = UNITS sheet_density = el.Carrier_sheet_concentration.UNIT conductivity_type = '<str>' residual = 'T^2' # Squared y-axis while fitting. concentration = el.Carrier_concentration.UNIT mobility = el.Mobility.UNIT else: name = get_name(data) measurement = Measurement(data) (concentration, mobility) = [np.nan] * 2 sheet_density, conductivity_type, residual = measurement.analyze() if thickness is not None: concentration = Carrier_concentration.from_sheet_density( sheet_density, thickness) if sheet_resistance is not None: mobility = Mobility.from_sheets(sheet_density, sheet_resistance) return pd.Series( data=(sheet_density, conductivity_type, residual, concentration, mobility), index=Columns.process(), name=name)
[docs]class Columns(_ColumnsBase): """ Bases: :class:`physicslab.utility._ColumnsBase` Column names. """ MAGNETICFIELD = 'B' HALLVOLTAGE = 'VH' CURRENT = 'I' SHEET_DENSITY = 'sheet_density' # Carrier. CONDUCTIVITY_TYPE = 'conductivity_type' RESIDUAL = 'residual' CONCENTRATION = 'concentration' MOBILITY = 'mobility'
[docs] @classmethod def mandatory(cls): """ Get the current mandatory column names. :rtype: set(str) """ return {cls.MAGNETICFIELD, cls.HALLVOLTAGE, cls.CURRENT}
[docs] @classmethod def process(cls): """ Get the current values of the :func:`process` output column names. :rtype: lits(str) """ return [cls.SHEET_DENSITY, cls.CONDUCTIVITY_TYPE, cls.RESIDUAL, cls.CONCENTRATION, cls.MOBILITY]
[docs]class Measurement: """ Hall measurement. :param pandas.DataFrame data: Voltage-current-magnetic field triples. :raises ValueError: If :attr:`data` is missing a mandatory column """ def __init__(self, data): if not Columns.mandatory().issubset(data.columns): raise ValueError('Missing mandatory column. See Columns class.') self.data = data def is_valid(self): # Is hall measurement linear enough? raise NotImplementedError() @staticmethod def _conductivity_type(hall_voltage): """ Find conductivity type based on sign of hall voltage. :param float hall_voltage: Hall voltage :return: Either "p" or "n" :rtype: str """ if hall_voltage > 0: return 'p' else: return 'n'
[docs] def analyze(self): """ Compute sheet density and determine conductivity type. :return: Sheet density, conductivity type, fit residual :rtype: tuple(float, str, float) """ self.data['hall_resistance'] = Resistance.from_ohms_law( self.data[Columns.HALLVOLTAGE], self.data[Columns.CURRENT]) coefficients_full = np.polynomial.polynomial.polyfit( self.data['hall_resistance'], self.data[Columns.MAGNETICFIELD], deg=1, full=True) slope = coefficients_full[0][1] # Constant can be found at [0][0]. fit_residual = coefficients_full[1][0][0] signed_sheet_density = slope / -elementary_charge sheet_density = abs(signed_sheet_density) conductivity_type = self._conductivity_type(signed_sheet_density) return sheet_density, conductivity_type, fit_residual
[docs]def plot(data_list, results): """ Plot all the measurements in a grid :param data_list: :type data_list: list[pandas.DataFrame] :param results: Analysis data from :func:`physicslab.experiment.process` :type results: pandas.DataFrame :return: Same objects as from :meth:`matplotlib.pyplot.subplots` :rtype: tuple[~matplotlib.figure.Figure, numpy.ndarray[~matplotlib.axes.Axes]] """ df = pd.DataFrame(data=squarificate(data_list)) df.name = 'Hall effect' def plot_value(ax, value: pd.DataFrame): ax.plot(value[Columns.MAGNETICFIELD], value[Columns.HALLVOLTAGE], label=get_name(value), c='k') ax.legend() fig, axs = plot_grid(df, plot_value, title='auto', xlabel='Magnetic field / T', ylabel='Hall voltage / V', subplots_adjust_kw={'hspace': 0}, sharex=True) return fig, axs