Source code for sofia_redux.spectroscopy.interpflagspec

# Licensed under a 3-clause BSD style license - see LICENSE.rst

from sofia_redux.toolkit.utilities.func import bitset
from sofia_redux.toolkit.interpolate import findidx
import numpy as np

__all__ = ['interpflagspec']


[docs] def interpflagspec(x, y, xout, nbits=8, cval=0): """ Performs a linear interpolation on a bit-set flag array Parameters ---------- x : array_like of float (N,) independent values of spectrum y : array_like of int (N,) dependent values of the bit-set flag array xout : (array_like of float) or float (M,) new independent values of spectrum nbits : int, optional The number of bits to scan through. The assumption is that they are sequential starting with the first bit. cval : float, optional Value to fill in requested interpolation points outside the data range. Returns ------- numpy.ndarray (int) (M,) new dependent values of the bit-set flag array at `xout`. """ if not hasattr(xout, '__len__'): isarr = False xout = [xout] else: isarr = True x, y, xout = np.array(x), np.array(y), np.array(xout) if x.shape != y.shape: raise ValueError("x and y array shape mismatch") try: y = y.astype(int) except (ValueError, TypeError): raise ValueError("y must be convertable to %s" % int) mask = np.isfinite(x) np.logical_and(mask, np.isfinite(y), out=mask) if not mask.any(): return np.full(xout.shape, cval) x, y = x[mask], y[mask] idx = findidx(x, xout, left=np.nan, right=np.nan) mask = np.isfinite(idx) nvalid = mask.sum() if nvalid == 0: return np.full(xout.shape, cval) xout, yout = xout[mask], np.zeros(nvalid, dtype=int) left = np.floor(idx[mask]).astype(int) right = np.ceil(idx[mask]).astype(int) on_point = left == right # points where no interpolation is required ipoints = ~on_point # points where interpolation is required left, center, right = left[ipoints], left[on_point], right[ipoints] m = (xout[ipoints] - x[left]) / (x[right] - x[left]) tmp = np.empty(nvalid, dtype=int) for bit in range(nbits): bset = bitset(y, np.array([bit]), skip_checks=True) tmp[:] = 0 if np.any(on_point): tmp[on_point] = bset[center] if np.any(ipoints): dy = bset[right] - bset[left] bset = bset[left] + (m * dy) tmp[ipoints] = np.ceil(bset, out=bset).astype(int) yout += tmp * (2 ** bit) np.mod(yout, 256, out=yout) if not isarr: return yout[0] else: result = np.full(mask.shape, cval) result[mask] = yout return result