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
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()
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
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