def convolve_spectrum(target_spec, header, kernel_type='gaussian', pix_width=pix_width, kernel_width=slit_width, double_smooth=False): #pix_width =3 #pix_width =20 fluxes = np.copy(target_spec[1]) wavelengths = np.copy(target_spec[0]) if kernel_type == 'gaussian': #see_sig = float(header['SEE_SIG']) #sigma value of gaussian fit to do the #see_sig= sdss_scale_factor*see_sig see_sig = pix_width #see_kernel = conv.Gaussian1DKernel(see_sig, x_size = int(slit_width), mode = 'oversample') if int(kernel_width) % 2 == 0: kernel_width = kernel_width + 1 else: pass see_kernel = conv.Gaussian1DKernel(see_sig, x_size=int(kernel_width), mode='oversample') see_kernel.normalize() spec_conv = conv.convolve(fluxes, see_kernel) elif kernel_type == 'sdss_match': see_sig = float( header['SEE_SIG']) #sigma value of gaussian fit to do the conv_see_sig = np.sqrt(see_sig**2 - sdss_see_sig**2) print('sdss_see_sig', sdss_see_sig) print('see_sig', see_sig) print('conv_see_sig', conv_see_sig) #see_sig= sdss_scale_factor*see_sig conv_see_sig = conv_see_sig * sdss_scale_factor #see_kernel = conv.Gaussian1DKernel(see_sig, mode = 'oversample') see_kernel = conv.Gaussian1DKernel(conv_see_sig, mode='oversample') see_kernel.normalize() spec_conv = conv.convolve(fluxes, see_kernel) pix_kernel = conv.Box1DKernel(width=int(sdss_scale_factor * pix_width), mode='oversample') pix_kernel.normalize() spec_conv = conv.convolve(spec_conv, pix_kernel) elif kernel_type == 'box': pix_kernel = conv.Box1DKernel(width=int(pix_width), mode='oversample') pix_kernel.normalize() spec_conv = conv.convolve(fluxes, pix_kernel) else: print('something wrong with convolution attempt') pass spec_out = np.vstack([wavelengths, spec_conv]) return spec_out
def mkolam(lam, dlsf, dslitlam, ofile, filfile, abmag): # Returns object "ofile" spectrum for a given LSF FWHM, and slit width. # The result is sampled in wavelength at the instrument pixel dispersion # Result does not include slitlosses. Normalized to ABmag in filter in "filfile" c=2.99792458e18 # Speed of light in [A/s] data=ascii.read(ofile, names=['col1', 'col2']) lam0=data['col1'] olam0=data['col2'] # interpolate to regular grid (finer between original file grid and lam) ddisp0=np.amin([np.median(lam0[1:len(lam0)-1]-lam0[0:len(lam0)-2]), np.median(lam[1:len(lam)-1]-lam[0:len(lam)-2])]) lam1=np.arange(np.amin(lam0), np.amax(lam0), ddisp0) f=interp1d(lam0, olam0, fill_value='extrapolate') olam1=f(lam1) # convolve with LSF (Gaussian of FWHM=dlsf) gauss=conv.Gaussian1DKernel(stddev=dlsf/2.355/ddisp0, x_size=round_up_to_odd(10*dlsf/2.355/ddisp0)) olam2=conv.convolve(olam1, gauss.array, boundary='extend') # convolve with slit (Top Hat of width=dslit) box=conv.Box1DKernel(dslitlam/ddisp0) olam3=conv.convolve(olam2, box.array, boundary='extend') # read filter curve and interpolate to object lambda grid datafil=ascii.read(filfile, names=['col1', 'col2']) lamfil0=datafil['col1'] tfil0=datafil['col2'] f=interp1d(lamfil0, tfil0, fill_value='extrapolate') tfil1=f(lam1) tfil1[lam1<=lamfil0.min()]=0 tfil1[lam1>=lamfil0.max()]=0 lameff=np.trapz(lam1*tfil1*lam1, lam1)/np.trapz(tfil1*lam1, lam1) # normalize to ABmag in filter "filfile" monoflam0=np.trapz(olam3*tfil1*lam1, lam1)/np.trapz(tfil1*lam1, lam1) monoflam1=10.0**(-0.4*(abmag+48.6))*c/lameff**2 olam4=olam3*monoflam1/monoflam0 # interpolate to lam f=interp1d(lam1, olam4, fill_value='extrapolate') return f(lam)
def mkslam(lam, dlsf, dslitlam, sfile): # Returns sky surface brightness spectrum for a given moon phase, LSF FWHM, and slit width. # The result is convolved with LSF+slit and sampled at wavelengths in lam data = ascii.read(sfile) # trim to lrange only lam0 = data['col1'][(data['col1'] > np.amin(lam)) * (data['col1'] < np.amax(lam))] slam0 = data['col2'][(data['col1'] > np.amin(lam)) * (data['col1'] < np.amax(lam))] # interpolate to regular grid ddisp0 = np.median(lam0[1:len(lam0) - 1] - lam0[0:len(lam0) - 2]) lam1 = np.arange(np.amin(lam0), np.amax(lam0), ddisp0) f = interp1d(lam0, slam0, fill_value='extrapolate') slam1 = f(lam1) # convolve with LSF (Gaussian of FWHM=dlsf) gauss = conv.Gaussian1DKernel(stddev=dlsf / 2.355 / ddisp0, x_size=round_up_to_odd(10 * dlsf / 2.355 / ddisp0)) slam2 = conv.convolve(slam1, gauss.array, boundary='extend') # convolve with slit (Top Hat of width=dslit) box = conv.Box1DKernel(dslitlam / ddisp0) slam3 = conv.convolve(slam2, box.array, boundary='extend') # interpolate to lam f = interp1d(lam1, slam3, fill_value='extrapolate') return f(lam)
def mkklam(lam, dlsf, dslitlam, klamfile): # Returns atmospheric extinction coefficient sampled at wavelengths in "lam" # The klam curve is convolved to the spectrograph LSF and the slit width before sampling it #data=ascii.read('/Users/gblancm/work/LCO/lcoetc/database/sky/klam.dat') data = ascii.read(klamfile) # trim to lrange only lam0 = data['col1'][(data['col1'] > np.amin(lam)) * (data['col1'] < np.amax(lam))] klam0 = data['col2'][(data['col1'] > np.amin(lam)) * (data['col1'] < np.amax(lam))] # interpolate to regular grid ddisp0 = np.median(lam0[1:len(lam0) - 1] - lam0[0:len(lam0) - 2]) lam1 = np.arange(np.amin(lam0), np.amax(lam0), ddisp0) f = interp1d(lam0, klam0, fill_value='extrapolate') klam1 = f(lam1) # convolve with LSF (Gaussian of FWHM=dlsf) gauss = conv.Gaussian1DKernel(stddev=dlsf / 2.355 / ddisp0, x_size=round_up_to_odd(10 * dlsf / 2.355 / ddisp0)) klam2 = conv.convolve(klam1, gauss.array, boundary='extend') # convolve with slit (Top Hat of width=dslit) box = conv.Box1DKernel(dslitlam / ddisp0) klam3 = conv.convolve(klam2, box.array, boundary='extend') # interpolate to lam f = interp1d(lam1, klam3, fill_value='extrapolate') return f(lam)
def box_smooth(spectrum, width): """ Smooth a `~specutils.Spectrum1D` instance based on a `astropy.convolution.Box1DKernel` kernel. Parameters ---------- spectrum : `~specutils.Spectrum1D` The spectrum object to which the smoothing will be applied. width : number The width of the kernel, in pixels, as defined in `astropy.convolution.Box1DKernel` Returns ------- spectrum : `~specutils.Spectrum1D` Output `~specutils.Spectrum1D` which a copy of the one passed in with the updated flux. Raises ------ ValueError In the case that ``width`` is not the correct type or value. """ # Parameter checks if not isinstance(width, (int, float)) or width <= 0: raise ValueError('The width parameter, {}, must be a number greater than 0'.format( width)) # Create the gaussian kernel box1d_kernel = convolution.Box1DKernel(width) # Call and return the convolution smoothing. return convolution_smooth(spectrum, box1d_kernel)
def smooth(values): #kern = convolution.Gaussian1DKernel(config.smooth_parameter) kern = convolution.Box1DKernel(config.smooth_parameter) print "smooth with:", kern return convolution.convolve(values, kern, normalize_kernel=True, boundary="extend")
def to_new_fwhm_box1d(ll, ss, width, nsamp=3): """ Use box kernel to convolve down and resample spectrum """ nres = np.round(width/dl) npix = np.int(np.round(nres/nsamp)) # print("Width of {0:1.4f} is {1:1.2f} pix".format(width, nres)) kernel = CC.Box1DKernel(nres) sp = scipy_convolve(ss, kernel, mode='same', method='direct') return ll, sp, npix
def Signal_Analysis(x, y, params): #Create fit using initial parameters #Stop fit from wandering onto random spikes of noise bound_centre = (params[0] - 15, params[0] + 15) bound_width = (params[3] - 2, params[3] + 30) #bound_amp = (0,params[1]),'amplitude_L': bound_amp bound_parameters = {'x_o': bound_centre, 'fwhm_G': bound_width} fit_init = models.Voigt1D(params[0], params[1], params[2], params[3], bounds=bound_parameters) fit = fitting.LevMarLSQFitter() fitted_model = fit(fit_init, x, y) #Get value for fit peak (amplitude_L is not applicable) peak = abs(min(fitted_model(x))) #Post-Processing #Formula for voight width is found Olivero 1977 fwhm_V = (fitted_model.fwhm_L / 2) + m.sqrt((fitted_model.fwhm_L**2) / 4 + fitted_model.fwhm_G**2) window_length = (1 / 3) * fwhm_V if window_length > 1: box_window = convolution.Box1DKernel(window_length) y = convolution.convolve(y, box_window) else: window_length = 2 box_window = convolution.Box1DKernel(window_length) y = convolution.convolve(y, box_window) #Signal-to-Noise baseline = y - fitted_model( x ) #not cheating....just to find the sigma of the non-peak reason lazily noise = stats.mad_std(baseline) snr = abs(peak) / noise if snr > 4: peak = min(y) snr = abs(peak) / noise else: pass return y, fitted_model, snr
def to_new_fwhm_box1d(ll, ss, width, nsamp=3): """ Use box kernel to convolve down and resample spectrum """ dl = np.median(np.diff(ll)) nres = width / dl # The number of pixels in ll that constitute a slit # The number of pixels in ll that make one pixel in the observed spectrum npix = np.int(np.round(nres / nsamp)) print("Width of {0:1.4f} is {1:1.2f} pix".format(width, nres)) kernel = CC.Box1DKernel(np.round(nres)) sp = scipy_convolve(ss, kernel, mode='same', method='direct') return ll, sp, npix
def mklinelam(lam, dlsf, dslitlam, linelam, lineflux, linefwhm): instsigma=np.sqrt(dlsf**2+dslitlam**2)/2.355 # rough estimate of instrumental sigma sigma=np.max([linefwhm/2.355, instsigma/2]) # set floor of line width to half instrumental to avoid sampling problems linelam1=lineflux/(np.sqrt(2)*sigma)*np.exp(-1*(lam-linelam)**2/(2*sigma**2)) # convolve with LSF (Gaussian of FWHM=dlsf) ddisp0=np.median(lam[1:len(lam)-1]-lam[0:len(lam)-2]) gauss=conv.Gaussian1DKernel(stddev=dlsf/2.355/ddisp0, x_size=round_up_to_odd(10*dlsf/2.355/ddisp0)) linelam2=conv.convolve(linelam1, gauss.array, boundary='extend') # convolve with slit (Top Hat of width=dslit) box=conv.Box1DKernel(dslitlam/ddisp0) linelam3=conv.convolve(linelam2, box.array, boundary='extend') return linelam3
def mklinelam(lam, dlsf, dslitlam, linelam, lineflux, linefwhm): sigma = linefwhm / 2.355 linelam1 = lineflux / (np.sqrt(2) * sigma) * np.exp(-1 * (lam - linelam)**2 / (2 * sigma**2)) # convolve with LSF (Gaussian of FWHM=dlsf) ddisp0 = np.median(lam[1:len(lam) - 1] - lam[0:len(lam) - 2]) gauss = conv.Gaussian1DKernel(stddev=dlsf / 2.355 / ddisp0, x_size=round_up_to_odd(10 * dlsf / 2.355 / ddisp0)) linelam2 = conv.convolve(linelam1, gauss.array, boundary='extend') # convolve with slit (Top Hat of width=dslit) box = conv.Box1DKernel(dslitlam / ddisp0) linelam3 = conv.convolve(linelam2, box.array, boundary='extend') return linelam3
def test_smooth_box_good(simulated_spectra, width): """ Test Box1DKernel smoothing with correct parmaeters. Width values need to be a number greater than 0. """ # Create the original spectrum spec1 = simulated_spectra.s1_um_mJy_e1 flux_original = spec1.flux # Calculate the smoothed flux using Astropy box_kernel = convolution.Box1DKernel(width) flux_smoothed_astropy = convolution.convolve(flux_original, box_kernel) # Calculate the box smoothed spec1_smoothed = box_smooth(spec1, width) compare_flux(spec1_smoothed.flux.value, flux_smoothed_astropy, flux_original.value) # Check the input and output units assert spec1.wavelength.unit == spec1_smoothed.wavelength.unit assert spec1.flux.unit == spec1_smoothed.flux.unit
def __smoothData(self, spec): windowsize = 3 kernel = astcov.Box1DKernel(windowsize) sspec = astcov.convolve(spec, kernel) return sspec
def pre_whiten(time, flux, unc_flux, period, kind="supersmoother", which="phased", phaser=None): """Phase a lightcurve and then smooth it. Inputs ------ time, flux, unc_flux: array_like period: float period to whiten by kind: string, optional type of smoothing to use. Defaults to "supersmoother." Other types are "boxcar", "linear" which: string, optional whether to smooth the "phased" lightcurve (default) or the "full" lightcurve. phaser: Float, optional (default=None) if kind="boxcar", phaser is the Half-width of the smoothing window. if kind="supersmoother", phaser is alpha (the "bass enhancement"). Outputs ------- white_flux, white_unc, smoothed_flux: arrays """ # print(which, period, phaser) # phase the LC by the period if period is not None: # phased_time = utils.phase(time, period) phased_time = (time % period) else: phased_time = time if kind.lower() == "supersmoother": if phaser is None: logging.info("Phaser not set! " "Set phaser=alpha (bass-enhancement value " "for supersmoother) if desired.") if which.lower() == "phased": # Instantiate the supersmoother model object with the input period model = supersmoother.SuperSmoother(period=period) # Set up base arrays for phase for the fit x_vals = np.linspace(0, max(phased_time) * 1.001, 1000) # Run a fit for the y phase y_fit = model.fit(phased_time, flux, unc_flux).predict(x_vals) elif which.lower() == "full": # Instantiate the supersmoother model object with the input period model = supersmoother.SuperSmoother(alpha=phaser) # Set up base arrays for time for the fit x_vals = np.linspace(min(time), max(time), 1000) # run a fit for the y values y_fit = model.fit(time, flux, unc_flux).predict(x_vals) else: logging.warning("unknown which %s !!!", which) elif kind.lower() == "boxcar": if phaser is None: logging.info("Phaser not set! " "Set phaser to the width of the smoothing " "box in pixels!") if which.lower() == "phased": # sort the phases sort_locs = np.argsort(phased_time) x_vals = phased_time[sort_locs] flux_to_fit = flux[sort_locs] elif which.lower() == "full": x_vals = time flux_to_fit = flux else: logging.warning("unknown which %s !!!", which) # Use astropy's convolution function! boxcar_kernel = convolution.Box1DKernel(width=phaser, mode="linear_interp") y_fit = convolution.convolve(flux_to_fit, boxcar_kernel, boundary="wrap") elif kind == "linear": if which != "full": logging.warning("Linear smoothing only allowed for full " "lightcurve! Switching to full mode.") which = "full" # Fit a line to the data pars = np.polyfit(time, flux, deg=1) m, b = pars smoothed_flux = m * time + b else: logging.warning("unknown kind %s !!!", kind) if (kind == "supersmoother") or (kind == "boxcar"): # Interpolate back onto the original time array interp_func = interpolate.interp1d(x_vals, y_fit) if which.lower() == "phased": # try: smoothed_flux = interp_func(phased_time) # except ValueError: # # print(min(x_vals),max(x_vals)) # # print(min(phased_time),max(phased_time)) # smoothed_flux = np.ones_like(phased_time) # smoothed_flux[1:-1] = interp_func(phased_time[1:-1]) # smoothed_flux[0] = smoothed_flux[1] # smoothed_flux[-1] = smoothed_flux[-2] elif which.lower() == "full": smoothed_flux = interp_func(time) else: logging.warning("unknown which %s !!!", which) # Whiten the input flux by subtracting the smoothed version # The smoothed flux represents the "bulk trend" white_flux = flux - smoothed_flux white_unc = unc_flux return white_flux, white_unc, smoothed_flux
def smooth_spec(x): kernel = convolution.Box1DKernel(nsmooth) return convolution.convolve(x, kernel)