def subtract_legendre_fit(array2d: np.ndarray,
                          keep_offset: bool = False,
                          deg: int = 1) -> Optional[np.ndarray]:
    """
    Use a legendre polynomial fit of degree legendre_deg in X and Y direction to correct background.
    legendre_deg = 0 ... subtract mean value
    legendre_deg = 1 ... subtract mean plane
    legendre_deg = 2 ... subtract simple curved mean surface
    legendre_deg = 3 ... also corrects "s-shaped" distortion
    ...
    """
    if deg == 0 and keep_offset:
        return array2d.copy()  # return a copy of input data
    n_row = np.linspace(-1, 1, array2d.shape[0])
    n_col = np.linspace(-1, 1, array2d.shape[1])
    mean_row = array2d.mean(axis=1)
    mean_col = array2d.mean(axis=0)

    fit_x = Legendre.fit(n_row, mean_row, deg)
    fit_y = Legendre.fit(n_col, mean_col, deg)

    result = array2d.copy()
    result = (result.transpose() -
              np.polynomial.legendre.legval(n_row, fit_x.coef)).transpose()
    result = result - np.polynomial.legendre.legval(n_col, fit_y.coef)
    if keep_offset:
        result = result + 2 * array2d.mean(
        )  # mean was subtracted 2 times (once for fit_x ans once for fit_y)
    else:
        result = result + array2d.mean()
    return result
示例#2
0
    def create(self, remake=False):
        '''
        Populate the wavelength calibration for this aperture,
        using input from the user to try to link up lines between
        the measured arc spectra and the known line wavelengths.
        '''

        self.speak("populating wavelength calibration")

        # loop through until we've decided we're converged
        self.notconverged = True
        while (self.notconverged):

            # set an initial guess matching wavelengths to my pixles
            #self.guessMatches()

            # do a fit
            if self.justloaded:
                self.justloaded = False
            else:
                # do an initial fit

                self.pixelstowavelengths = Legendre.fit(
                    x=self.pixel,
                    y=self.wavelength,
                    deg=self.polynomialdegree,
                    w=self.weights)
            # identify outliers
            limit = 1.48 * craftroom.oned.mad(self.residuals[self.good]) * 4
            limit = np.maximum(limit, 1.0)
            # outliers get reset each time (so don't lose at edges)
            outlier = np.abs(self.residuals) > limit
            # keep track of which are outlier
            for i, m in enumerate(self.matches):
                self.matches[i]['mine']['outlier'] = outlier[i]
            self.speak('points beyond {0} are outliers ({1})'.format(limit, i))

            self.pixelstowavelengths = Legendre.fit(x=self.pixel,
                                                    y=self.wavelength,
                                                    deg=self.polynomialdegree,
                                                    w=self.weights)

            self.plotWavelengthFit()
示例#3
0
def LDT(epoch,tdur,t,f,pad=0.2,deg=1):
    """
    Local detrending

    A simple function that subtracts a polynomial trend from the
    lightcurve excluding a region around the transit.

    pad : Extra number of days to notch out of the of the transit region.
    """
    bcont = abs(t - epoch) > tdur/2 + pad
    fcont = f[bcont]
    tcont = t[bcont]

    legtrend = Legendre.fit(tcont,fcont,deg,domain=[t.min(),t.max()])
    trend    = legtrend(t)
    return trend 
示例#4
0
def trace_polynomial(trace, m=1, maxorder=15):
    """Fit a polynomial to the trace of order m and return a
    dictionary containing the parameters and validity intervals.

    :param trace: astropy table containing modelled trace points.
    :param m: spectral order for which to fit a polynomial.
    :param maxorder: maximum polynomial order to use.

    :type trace: astropy.table.Table
    :type m: int
    :type maxorder: int

    :returns: pars - dictionary containg the polynomial solution.
    :rtype: dict
    """

    # TODO added arbitrary maxorder to deal with poor exrapolatian, revisit when extrapolation fixed.

    # Select the data for order m.
    mask = (trace['order'] == m)
    wave = trace['Wavelength'][mask]
    spatpix_ref = trace['xpos'][mask]
    specpix_ref = trace['ypos'][mask]

    # Find the edges of the domain.
    wavemin = np.amin(wave)
    wavemax = np.amax(wave)

    specmin = np.amin(specpix_ref)
    specmax = np.amax(specpix_ref)

    # Compute the polynomial parameters for x and y.
    order = 0
    while order <= maxorder:

        spatpol = Legendre.fit(np.log(wave), spatpix_ref, order)
        specpol = Legendre.fit(np.log(wave), specpix_ref, order)

        spatpixp_nat = spatpol(np.log(wave))
        specpixp_nat = specpol(np.log(wave))

        if np.all(np.abs(spatpix_ref - spatpixp_nat) < 0.5) & np.all(
                np.abs(specpix_ref - specpixp_nat) < 0.5):
            break

        order += 1

    # Compute the transform back to wavelength.
    wavegrid = wavemin + (wavemax - wavemin) * np.linspace(0., 1., 501)
    specgrid = specpol(np.log(wavegrid))
    wavepol = Legendre.fit(specgrid, np.log(wavegrid), order)

    # Add the parameters to a dictionary.
    pars = dict()
    pars['spat_coef'] = spatpol.coef
    pars['spat_domain'] = spatpol.domain
    pars['spec_coef'] = specpol.coef
    pars['spec_domain'] = specpol.domain
    pars['wave_coef'] = wavepol.coef
    pars['wave_domain'] = wavepol.domain

    return pars