def __init__(self, sigma): if self._erf is None: try: from scipy.special import erf self.__class__._erf = erf except (ValueError, ImportError): raise ImportError("Gaussian PSF model requires scipy.") x_0 = 0 y_0 = 0 amplitude = 1 constraints = {'fixed': {'x_0': True, 'y_0': True, 'sigma': True}} super(GaussianPSF, self).__init__(param_dim=1, sigma=sigma, x_0=x_0, y_0=y_0, amplitude=amplitude, **constraints) # Default size is 8 * sigma self.shape = (int(8 * sigma) + 1, int(8 * sigma) + 1) self.fitter = fitting.NonLinearLSQFitter() # Fix position per default self.x_0.fixed = True self.y_0.fixed = True
def gaussian_fit(x, y, order=0, **p0): """ Fit a Gaussian + polynomial to the data. Parameters ---------- x : array_like y : array_like order : int (optional) The order of the Polynomial model. Defaults to constant (order=0). **p0 Initial conditions for the model fit. """ if len(x) != len(y): raise ValueError("x and y must have the sample shape!") # TODO: when astropy.modeling allows combining models, fix this if order > 0: raise NotImplementedError() #g = custom_model_1d(_gaussian_constant_model) g = GaussianPolynomial() default_p0 = dict(b=min(y), m=0., log10_amp=np.log10(max(y)), stddev=0.5, mean=float(np.mean(x))) for k, v in default_p0.items(): setattr(g, k, p0.get(k, v)) fit = fitting.NonLinearLSQFitter(g) fit(x, y) return g
def plotStatistcs(data): """ Plot statistics of the background pixels. Assumes that the input contains only the background pixel values as a 1D array. :return: None """ #search for best bandwidth # print 'searching for the best KDE bandwidth' # grid = GridSearchCV(KernelDensity(), # {'bandwidth': np.linspace(0.1, 1.0, 15)}, n_jobs=-1, # cv=20) # 20-fold cross-validation # grid.fit(data.copy()) # print grid.best_params_ #derive KDE print 'deriving KDE' x_grid = np.linspace(data.min(), data.max(), 200) #pdf = kde_sklearn(data.copy(), x_grid, bandwidth=grid.best_params_['bandwidth']) #pdf = kde_sklearn(data.copy(), x_grid) pdf = kde_statsmodels_u(data.copy().astype(np.float64), x_grid, bandwidth=1.5) #plot data fig, axarr = plt.subplots(1, 2, sharey=True) ax1 = axarr[0] ax2 = axarr[1] fig.subplots_adjust(wspace=0) ax1.set_title('Background Pixels') ax2.set_title('Models') d = ax1.hist(data, bins=np.linspace(data.min(), data.max()), normed=True, alpha=0.7) ax1.plot(x_grid, pdf, 'r-', label='Gaussian KDE') # Gaussian fit x = [0.5 * (d[1][i] + d[1][i+1]) for i in xrange(len(d[1])-1)] y = d[0] g_init = models.Gaussian1D(amplitude=1., mean=np.mean(data), stddev=np.std(data)) f2 = fitting.NonLinearLSQFitter() g = f2(g_init, x, y) ax2.plot(x, g(x), 'b-', label='Gaussian Fit') ax2.plot(x_grid, pdf, 'r-', label='Gaussian KDE', alpha=0.7) ax1.set_ylabel('PDF') ax1.set_xticks(ax1.get_xticks()[:-1]) ax2.set_xticks(ax2.get_xticks()[1:]) plt.legend(shadow=True, fancybox=True) plt.savefig('backgroundStatistics.pdf') plt.close()
def make_normalized_flat(self, overwrite=False): """ Make a normalized Flat frame by fitting and dividing out the flat lamp spectrum. TODO: right now, this just fits a 1D polynomial. could do a 2D fit to the image instead... Parameters ---------- overwrite : bool (optional) """ # TODO: I can't get this 2D fit to work... # x, y = np.mgrid[:shp[0], :shp[1]] # p = models.Polynomial2DModel(degree=13) # fit = fitting.LinearLSQFitter(p) # fit(x, y, master_flat) # smooth_flat = p(x,y) cache_file = os.path.join(self.redux_path, "normalized_flat.fits") if os.path.exists(cache_file) and overwrite: os.remove(cache_file) if not os.path.exists(cache_file): # collapse the flat to 1D, fit a polynomial master_flat_1d = np.median(self.master_flat, axis=1) p = models.Polynomial1DModel(degree=15) fit = fitting.NonLinearLSQFitter(p) pix = np.arange(len(master_flat_1d)) fit(pix, master_flat_1d) smooth_flat = p(pix) # normalize the flat n_flat = self.master_flat / smooth_flat[:, np.newaxis] hdu = fits.PrimaryHDU(n_flat) hdu.writeto(cache_file) else: n_flat = fits.getdata(cache_file) return n_flat
def __init__(self, prf_array, normalize=True, subsampling=1): # Array shape and dimension check if subsampling == 1: if prf_array.ndim == 2: prf_array = np.array([[prf_array]]) if prf_array.ndim != 4: raise TypeError('Array must have 4 dimensions.') if prf_array.shape[:2] != (subsampling, subsampling): raise TypeError('Incompatible subsampling and array size') if np.isnan(prf_array).any(): raise Exception("Array contains NaN values. Can't create PRF.") # Normalize if requested if normalize: for i in range(prf_array.shape[0]): for j in range(prf_array.shape[1]): prf_array[i, j] /= prf_array[i, j].sum() # Set PRF asttributes self._prf_array = prf_array self.subsampling = subsampling constraints = {'fixed': {'x_0': True, 'y_0': True}} x_0 = 0 y_0 = 0 amplitude = 1 super(DiscretePRF, self).__init__(param_dim=1, x_0=x_0, y_0=y_0, amplitude=amplitude, **constraints) self.linear = True self.fitter = fitting.NonLinearLSQFitter() # Fix position per default self.x_0.fixed = True self.y_0.fixed = True
def plotPRNU(data, xmin=700, xmax=1700, ymin=3500, ymax=4500, order=3, smooth=3.): """ Generate and plot maps of PRNU, ratios of PRNU maps, and show the PRNU as a function of wavelength. """ number_of_subplots = math.ceil(len(data.keys()) / 2.) plt.figure(figsize=(8, 13)) plt.subplots_adjust(wspace=0.05, hspace=0.15, left=0.01, right=0.99, top=0.95, bottom=0.05) #loop over data from shortest wavelength to the longest w = [] prnu = [] dat = {} for i, wave in enumerate(sorted(data.keys())): tmp = data[wave][ymin:ymax, xmin:xmax] tmp /= np.median(tmp) #meshgrid representing data x, y = np.mgrid[:tmp.shape[1], :tmp.shape[0]] #fit a polynomial 2d surface to remove the illumination profile p_init = models.Polynomial2D(degree=order) f = fitting.NonLinearLSQFitter() p = f(p_init, x, y, tmp) #normalize data tmp /= p(x, y) print tmp.max(), tmp.min() #sigma clipped std to reject dead pixels etc. prn = np.std(sigma_clip(tmp, 6.)) * 100. print 'PRNU:', prn, 'per cent at lambda =', wave, 'nm' w.append(int(wave)) prnu.append(prn) if int(wave) > 750 and int(wave) < 850: reference = tmp.copy() dat[wave] = tmp.copy() #Gaussian smooth to enhance structures for plotting tmp = gaussian_filter(tmp, smooth) ax = plt.subplot(number_of_subplots, 2, i + 1) ax.imshow(tmp, interpolation='none', origin='lower', vmin=0.995, vmax=1.003) ax.set_title(r'$\lambda =$ ' + str(int(wave)) + 'nm') plt.axis('off') #write to file fileIO.writeFITS(tmp, str(int(wave)) + '.fits', int=False) plt.savefig('PRNUmaps.png') plt.close() #ratio images plt.figure(figsize=(8, 13)) plt.subplots_adjust(wspace=0.05, hspace=0.15, left=0.01, right=0.99, top=0.95, bottom=0.05) for i, wave in enumerate(sorted(dat.keys())): tmp = dat[wave] #divide by the reference tmp /= reference #Gaussian smooth to enhance structures for plotting tmp = gaussian_filter(tmp, smooth) ax = plt.subplot(number_of_subplots, 2, i + 1) ax.imshow(tmp, interpolation='none', origin='lower', vmin=0.995, vmax=1.003) ax.set_title(r'$\lambda =$ ' + str(int(wave)) + 'nm') plt.axis('off') plt.savefig('PRNURationmaps.png') plt.close()
def plotWavelengthDependency(data, xmin=700, xmax=1700, ymin=3500, ymax=4500, order=3, samples=10): #loop over data from shortest wavelength to the longest dat = {} for i, wave in enumerate(sorted(data.keys())): tmp = data[wave][ymin:ymax, xmin:xmax] tmp /= np.median(tmp) #meshgrid representing data x, y = np.mgrid[:tmp.shape[1], :tmp.shape[0]] #fit a polynomial 2d surface to remove the illumination profile p_init = models.Polynomial2D(degree=order) f = fitting.NonLinearLSQFitter() p = f(p_init, x, y, tmp) #normalize data tmp /= p(x, y) #select sub regions to calculate the PRNU in prnu = [] ydim, xdim = tmp.shape ylen = ydim / samples xlen = xdim / samples for a in range(samples): for b in range(samples): area = tmp[a * ylen:(a + 1) * ylen, b * xlen:(b + 1) * xlen] prn = np.std(sigma_clip(area, 6.)) * 100. prnu.append(prn) dat[int(wave)] = prnu #calculate the mean for each wavelength and std w = [] mean = [] std = [] for wave in sorted(dat.keys()): m = np.mean(dat[wave]) s = np.std(dat[wave]) w.append(wave) mean.append(m) std.append(s) print wave, m, s #polynomial fit to PRNU datra z2 = np.polyfit(w, mean, 2) p2 = np.poly1d(z2) z3 = np.polyfit(w, mean, 3) p3 = np.poly1d(z3) x = np.linspace(500, 950) #wavelength dependency plot plt.title('Wavelength Dependency of the PRNU') plt.plot(x, p2(x), 'b-', label='2nd order fit') plt.plot(x, p3(x), 'g--', label='3rd order fit') plt.errorbar(w, mean, yerr=3 * np.asarray(std), c='r', fmt='o', label='data, $3\sigma$ errors') plt.xlabel(r'Wavelength $\lambda$ [nm]') plt.ylabel(r'PRNU $[\%]$') plt.xlim(500, 950) plt.ylim(0.4, 0.8) plt.legend(shadow=True, fancybox=True, scatterpoints=1, numpoints=1) plt.savefig('PRNUwave.pdf') plt.close()
def normaliseFlat(data, output, order=5, mask=True, method='boxcar'): """ Normalise each quadrant separately. If limit set use to to generate a mask. """ #split to quadrants Q0 = data[7:2052, 57:2098].copy() Q2 = data[2543:4592, 57:2098].copy() Q1 = data[7:2052, 2505:4545].copy() Q3 = data[2543:4592, 2505:4545].copy() Qs = [Q0, Q1, Q2, Q3] res = [] for tmp in Qs: if mask: print 'Using masked 2D arrays (not applied in spline fitting)...' # median = np.median(tmp) # msk = (tmp > median*0.88) & (tmp < 40000.) # #note the inversion of the mask before applying, as for numpy masked arrays True means masking # #while in my selection above True means good data # t = np.ma.MaskedArray(tmp, mask=~msk) t = sigma_clip( tmp, sig=3. ) #this can be used to generate automatically a masked array else: print 'No 2D masking applied...' t = tmp.copy() if method is 'surface': print 'Fitting a surface to model the illumination profile' #meshgrid representing data x, y = np.mgrid[:t.shape[0], :t.shape[1]] #fit a polynomial 2d surface to remove the illumination profile p_init = models.Polynomial2D(degree=order) f = fitting.NonLinearLSQFitter() p = f(p_init, x, y, t) #normalize data and save it to res list tmp /= p(x, y) elif method is 'boxcar': size = 15 #this is very small, so will probably smooth out some actual PRNU, but needed to remove dust specs print 'Using a boxcar smoothed image to model the illumination profile' #will have to convert masked array to NaN array as convolve does not support masks t = t.filled(np.nan) box_2D_kernel = Box2DKernel(size) if size > 50: model = convolve_fft(t, box_2D_kernel) else: model = convolve(t, box_2D_kernel) #faster for small kernels tmp /= model elif method is 'spline': spacing = 27 print 'Fitting 1D splines to each row to model the illumination profile' for i, line in enumerate(tmp): #Initializes the instance with dummy xnodes Spline = splineFitting.SplineFitting([ 0, ]) #filter dead pixels from the data y = line.copy() median = np.median(y) y = y[ y > median * 0.92] #this is pretty aggressive masking, but needed because of no dead pixel map x = np.arange(len(y)) #Median filter the data medianFiltered = signal.medfilt(y, 25) #Spline nodes and initial guess for y positions from median filtered xnods = np.arange(0, len(y), spacing) ynods = medianFiltered[xnods] #Updates dummy xnodes in Spline instance with real deal Spline.xnodes = xnods #Do the fitting fittedYnodes, success = Spline.doFit(ynods, x, y) #normalize the line with the fit tmp[i, :] /= Spline.fitfunc(np.arange(len(line)), fittedYnodes) else: print 'No fitting method selected, will exit...' sys.exit(-9) res.append(tmp) print np.mean(tmp), np.median(tmp), np.std(tmp) #save out out = np.zeros_like(data) out[7:2052, 57:2098] = res[0] out[7:2052, 2505:4545] = res[1] out[2543:4592, 57:2098] = res[2] out[2543:4592, 2505:4545] = res[3] fileIO.writeFITS(out, output + 'FlatField%s.fits' % (method), int=False) return out