Source code for ramCOH.raman.neon

"""
======
Neon
======
The neon module provides a Raman processing class for processing neon emission spectra.
"""

import itertools as it
from typing import Optional

import numpy as np
import numpy.typing as npt

from ramCOH.raman.baseclass import RamanProcessing
from ramCOH.raman.baseline_regions import default_birs
from ramCOH.signal_processing import functions as f


[docs]class Neon(RamanProcessing): """ A subclass of :py:class:`~ramCOH.raman.baseclass.RamanProcessing`, extended with methods for Raman streching and offset correction. Attributes ---------- emission_peaks : array of float theoretical neon emission lines (cm\ :sup:`-1`) observed_peaks : array of float observed neon emission lines (cm\ :sup:`-1`) correction_factor : float stretching correction factor (cm\ :sup:`-1`) offset : float offset correction factor (cm\ :sup:`-1`) """ # Baseline regions birs_default = default_birs["neon"] emission_peaks: Optional[npt.NDArray] = None observed_peaks: Optional[npt.NDArray] = None correction_factor: Optional[float] = None offset: Optional[float] = None def __init__(self, x: npt.NDArray, y: npt.NDArray, laser: float): super().__init__(x=x, y=y, laser=laser) def deconvolve( self, peak_height=2, residuals_theshold=10, min_amplitude=8, min_peak_width=2, fit_window=4, max_iterations=3, noise=None, **kwargs, ): """ :meta private: """ return super().deconvolve( peak_prominence=peak_height, residuals_threshold=residuals_theshold, baseline0=True, min_amplitude=min_amplitude, min_peak_width=min_peak_width, fit_window=fit_window, noise=noise, max_iterations=max_iterations, **kwargs, )
[docs] def neonCorrection( self, left_nm=565.666, right_nm=574.83, search_window=6, **kwargs ): """ Calculate stretching and offset correction factors between observed and theoretical Neon emission lines. Compare theoretical neon emission lines near the calibration lines ``left_nm`` and ``right_nm`` with observed peaks. Correction for stretching is calculated as the ratio of the inter calibration line distances of theoretical and observed lines. Offset correction is calculated as the difference between the observed and theoretical position of ``left_nm``. Results are stored in :py:attr:`~ramCOH.raman.neon.Neon.correction_factor` and :py:attr:`~ramCOH.raman.neon.Neon.offset`. Parameters ---------- left_nm : float, default 565.666 position of the left calibration line in nm right_nm : float, default 574.83 position of the right calibration line in nm search_window : int Half-width (cm\ :sup:`-1`) of the peak search window around theoretical emission lines . """ laser = kwargs.get("laser", self.laser) if self.peaks is None: raise NameError("peaks not found, run fitPeaks first") neon_emission = f.neonEmission(laser=laser) left = np.round( np.float( neon_emission.iloc[:, 4][ np.isclose(left_nm, neon_emission.iloc[:, 1], atol=0.001) ] ), 2, ) right = np.round( np.float( neon_emission.iloc[:, 4][ np.isclose(right_nm, neon_emission.iloc[:, 1], atol=0.001) ] ), 2, ) # All emission lines within spectrum limits neon_emission_trimmed = np.array( neon_emission.iloc[:, 4][ (neon_emission.iloc[:, 4] > self.x.min()) & (neon_emission.iloc[:, 4] < self.x.max()) ] ) # theoretical emission line positions with a match found in spectrum self.emission_peaks = np.array([]) # measured emission line positions self.observerd_peaks = np.array([]) for i, j in self.peaks.items(): peak = j["center"] emission_check = np.isclose( peak, neon_emission_trimmed, atol=search_window, rtol=0 ) if emission_check.sum() == 1: self.emission_peaks = np.append( self.emission_peaks, neon_emission_trimmed[emission_check].tolist() ) self.observerd_peaks = np.append(self.observerd_peaks, peak) elif emission_check.sum() > 1: raise RuntimeError( f"multiple emission line fits found at {peak: .2f} cm$^{-1}$" ) # find correction factor for the calibration lines if not np.isin([left, right], np.round(self.emission_peaks, 2)).sum() == 2: raise RuntimeError("calibration lines not found in spectrum") # boolean array for the location of left and right calibration lines calibration_lines = np.array( np.isclose(left, self.emission_peaks, atol=0.001) + np.isclose(right, self.emission_peaks, atol=0.001) ) # boolean to index calibration_lines = list( it.compress(range(len(calibration_lines)), calibration_lines) ) # indices for differenced array calibration_lines = np.unique(calibration_lines - np.array([0, 1])) self.correction_factor = np.float( np.sum(np.diff(self.emission_peaks)[calibration_lines]) / np.sum(np.diff(self.observerd_peaks)[calibration_lines]) ) self.offset = np.float( self.observerd_peaks[np.isclose(left, self.observerd_peaks, atol=10)] - self.emission_peaks[np.isclose(left, self.emission_peaks, atol=0.1)] )