Source code for resistics.calibrate.data

import os
from datetime import datetime, timedelta
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from typing import List, Union

from resistics.common.base import ResisticsBase


[docs]class CalibrationData(ResisticsBase): """Class for holding calibration data Calibration data should be given in the frequency domain and has a magnitude and phase component (in radians). Calibration data is the impulse response for an instrument or sensor and is usually deconvolved (division in frequency domain) from the time data. Notes ----- Calibration data for magnetic channels is given in mV/nT. Because this is deconvolved from magnetic time data, which is in mV, the resultant magnetic time data is in nT. Attributes ---------- filename : str The filename the calibration data was read from numSamples : int The number of samples in the calibration data freqs : np.ndarray The frequency points where calibration data is defined magnitude : np.ndarray The magnitude data magnitudeUnit : str The magnitude unit, defaulted to mV/nT phase : np.ndarray The phase data in radians phaseUnit : str The phase unit, defaulted to radians chopper : bool Boolean flag to note whether chopper is on or not Methods ------- __init__(kwargs) Initialise the calibration data view(kwargs) View the calibration data printList() Class status returned as list of strings """ def __init__( self, filename: str, freqs: np.ndarray, magnitude: np.ndarray, phase: np.ndarray, staticGain: float = 1, chopper: bool = False, serial: int = 1, sensor: str = "", ) -> None: """Initialise and set object parameters Parameters ---------- filename : str The filename the calibration was read in from freqs : np.ndarray Array of frequencies for which the impulse response is defined magnitude : np.ndarray Magnitude of impulse response phase : np.ndarray Phase of impulse reponse in radians staticGain : float, optional The static gain to applied to the calibration data chopper : bool, optional Boolean flag for chopper on or off serial : int The serial number of the sensor or instrument which requires calibration sensor : str The sensor name of the sensor or instrument which requires calibration """ self.filename: str = filename self.freqs: np.ndarray = freqs self.magnitude: np.ndarray = magnitude self.magnitudeUnit = "mV/nT" self.phase: np.ndarray = phase self.phaseUnit = "radians" self.numSamples: int = len(freqs) self.staticGain: float = staticGain self.chopper: bool = chopper self.serial: int = serial self.sensor: bool = sensor
[docs] def view(self, **kwargs) -> Figure: """Plot of the calibration function Parameters ---------- staticgain : bool, optional Boolean flag for having static gain on, default is True degrees : bool, optional Plot phase in degreesm default is False fig : matplotlib.pyplot.figure, optional A figure object plotFonts : Dict, optional A dictionary of plot fonts label : str, optional Label for the plots xlim : List, optional Limits for the x axis ylim_mag : List, optional Limits for the magnitude y axis ylim_phase : List, optional Limits for the phase y axis legened : bool Boolean flag for adding a legend Returns ------- plt.figure Matplotlib figure object """ from resistics.common.plot import getViewFonts if "fig" in kwargs: fig = plt.figure(kwargs["fig"].number) else: fig = plt.figure(figsize=(8, 8)) plotFonts = kwargs["plotFonts"] if "plotFonts" in kwargs else getViewFonts() # static gain magnitude = self.magnitude if "staticgain" in kwargs and not kwargs["staticgain"]: magnitude = magnitude / self.staticGain # phase phaseUnit = self.phaseUnit phase = self.phase if "degrees" in kwargs and kwargs["degrees"]: phaseUnit = "degrees" phase = self.phase * (180 / np.pi) # plot magnitude plt.subplot(2, 1, 1) plt.title("Impulse response magnitude", fontsize=plotFonts["title"]) lab = kwargs["label"] if "label" in kwargs else self.filename plt.loglog(self.freqs, magnitude, label=lab) if "xlim" in kwargs: plt.xlim(kwargs["xlim"]) if "ylim_mag" in kwargs: plt.ylim(kwargs["ylim_mag"]) plt.xlabel("Frequency [Hz]") plt.ylabel("Magnitude [{}]".format(self.magnitudeUnit)) plt.grid(True) # legend if "legend" in kwargs and kwargs["legend"]: plt.legend(loc=2) # plot phase plt.subplot(2, 1, 2) plt.title("Impulse response phase", fontsize=plotFonts["title"]) lab = kwargs["label"] if "label" in kwargs else self.filename plt.semilogx(self.freqs, phase, label=lab) if "xlim" in kwargs: plt.xlim(kwargs["xlim"]) if "ylim_phase" in kwargs: plt.ylim(kwargs["ylim_phase"]) plt.xlabel("Frequency [Hz]") plt.ylabel("Phase [{}]".format(phaseUnit)) plt.grid(True) # legend if "legend" in kwargs and kwargs["legend"]: plt.legend(loc=3) # show if the figure is not in keywords if "fig" not in kwargs: plt.tight_layout(rect=[0, 0.02, 1, 0.96]) plt.show() return fig
[docs] def printList(self) -> List[str]: """Class information as a list of strings Returns ------- out : List[str] List of strings with information """ textLst = [] textLst.append("Filename = {}".format(self.filename)) textLst.append("Serial = {}".format(self.serial)) textLst.append("Sensor = {}".format(self.sensor)) textLst.append("Static gain = {:.2f}".format(self.staticGain)) textLst.append("Chopper = {}".format(self.chopper)) textLst.append("Number of frequency points = {:d}".format(self.numSamples)) textLst.append("Calibration data:") textLst.append( "\t{:>17s}\t{:>10s}\t{:>10s}".format( "Frequency [Hz]", "Mag. [mv/nT]", "Phase [rad]" ) ) for ii in range(0, self.numSamples): textLst.append( "\t{:17.8f}\t{:10.2f}\t{:10.2f}".format( self.freqs[ii], self.magnitude[ii], self.phase[ii] ) ) return textLst