def test_custom_model(amplitude=4, frequency=1): def sine_model(x, amplitude=4, frequency=1): """ Model function """ return amplitude * np.sin(2 * np.pi * frequency * x) def sine_deriv(x, amplitude=4, frequency=1): """ Jacobian of model function, e.g. derivative of the function with respect to the *parameters* """ da = np.sin(2 * np.pi * frequency * x) df = 2 * np.pi * x * amplitude * np.cos(2 * np.pi * frequency * x) return np.vstack((da, df)) SineModel = models.custom_model(sine_model, fit_deriv=sine_deriv) x = np.linspace(0, 4, 50) sin_model = SineModel() y = sin_model.evaluate(x, 5., 2.) y_prime = sin_model.fit_deriv(x, 5., 2.) np.random.seed(0) data = sin_model(x) + np.random.rand(len(x)) - 0.5 fitter = fitting.LevMarLSQFitter() model = fitter(sin_model, x, data) assert np.all((np.array([model.amplitude.value, model.frequency.value]) - np.array([amplitude, frequency])) < 0.001)
def get_varying_conv_gaussian_model(g_list): # VaryingConvolutionGaussian def _f(x, y, a_0=1, a_1=0, a_2=0, a_3=0, b_0=0., b_1=0, b_2=0, b_3=0, # b_4=0, b_5=0, # c_0=0.25, c_1=0, c_2=0, c_3=0): """ b : shift c : sigma """ from astropy.modeling.utils import poly_map_domain domain = [0, 2047] window = [-1, 1] #dw = window[1] - window[0] x = poly_map_domain(x, domain, window) # y = poly_map_domain(y, [0, 1], window) # a_0 = a_2 + 1 # so that it always 1 at the center a_coeffs = [a_0, a_1, a_2, a_3] a = models.Chebyshev1D.clenshaw(x, a_coeffs) #b_0 = b_2 # so that the curve passes through 0 at the center b_coeffs = [b_0, b_1, b_2, b_3] b = models.Chebyshev1D.clenshaw(x, b_coeffs) c_0 = c_2 c_coeffs = [c_0, c_1, c_2, c_3] c = models.Chebyshev1D.clenshaw(x, c_coeffs) #z1, z2, z3, z4 = [poly_map_domain(z, [0, 1], window) for z in [z1, z2, z3, z4]] #w1, w2, w3, w4 = [w*dw for w in [w1, w2, w3, w4]] y_b = y - b shifted_y = [y_b - g1.mean.value for g1 in g_list] c2 = c**2 broadened_sigma2 = [c2 + g1.stddev**2 for g1 in g_list] # argument for the exponetial function d_list = [-yy**2/s2/2. for (yy, s2) in zip(shifted_y, broadened_sigma2)] _ = np.sum([g1.amplitude*np.exp(d) for (g1, d) in zip(g_list, d_list)], axis=0) return a * _ VaryingConvolutionGaussian = models.custom_model(_f) return VaryingConvolutionGaussian
def norm_pdf_t(x): return np.exp(-0.5 * x * x) / M_SQRT_2_PI def gauss_box_model(x, amplitude=1.0, location=0.0, s=1.0, d=0.5): '''Integrate a Gaussian profile.''' m2 = (x + d - location) / s m1 = (x - d - location) / s return amplitude * (norm.cdf(m2) - norm.cdf(m1)) def gauss_box_model_deriv(x, amplitude=1.0, location=0.0, s=1.0, d=0.5): '''Integrate a Gaussian profile.''' z2 = (x + d - location) / s z1 = (x - d - location) / s da = norm.cdf(z2) - norm.cdf(z1) fp2 = norm_pdf_t(z2) fp1 = norm_pdf_t(z1) dl = -amplitude / s * (fp2 - fp1) ds = -amplitude / s * (fp2 * z2 - fp1 * z1) dd = amplitude / s * (fp2 + fp1) return (da, dl, ds, dd) GaussBox = custom_model( gauss_box_model, func_fit_deriv=gauss_box_model_deriv)
d_x = 2 * amplitude * \ sinc((x-mean)/width) * ( x * np.cos((x-mean)/width) - np.sin((x - mean) / width)) / ((x - mean) / width) ** 2 d_x = np.asarray(d_x) d_amplitude = sinc((x-mean)/width)**2 d_x[x_is_zero] = 0 d_mean = d_x*(-1/width) d_width = d_x*(-(x-mean)/(width)**2) return [d_amplitude, d_mean, d_width] _SincSquareModel = models.custom_model(sinc_square_model, fit_deriv=sinc_square_deriv) class SincSquareModel(_SincSquareModel): def __reduce__(cls): members = dict(cls.__dict__) return (type(cls), (), members) def fit_sinc(x, y, amp=1.5, mean=0., width=1., tied={}, fixed={}, bounds={}, obs_length=None): """ Fit a sinc function to x,y values. Parameters ----------
np.exp((-(1 / (stddev**2)) * (x - mean)**2)) * (x - mean) / (stddev**2)) d_stddev = (2 * amplitude * np.exp((-(1 / (stddev**2)) * (x - mean)**2)) * ((x - mean)**2) / (stddev**3)) d_const = np.zeros_like(x) d_amplitude2 = np.exp((-(1 / (stddev2**2)) * (x - mean2)**2)) d_mean2 = (2 * amplitude2 * np.exp((-(1 / (stddev2**2)) * (x - mean2)**2)) * (x - mean) / (stddev2**2)) d_stddev2 = (2 * amplitude2 * np.exp((-(1 / (stddev2**2)) * (x - mean2)**2)) * ((x - mean2)**2) / (stddev2**3)) return [d_amplitude, d_mean, d_stddev, d_const, d_amplitude2, d_mean2, d_stddev2] LineAbsModel = custom_model(lineabs_model, fit_deriv=lineabs_deriv) '''This class is just Gaussian + constant. Can be removed once astropy supports fitting of composite models. Also (known bug, but not fixed yet), fitting does not work with bounds. However, without bounds the fit will just put the gauss in the sharpest spike. Workaround set in eval method. ''' def line_model(x, amplitude=1, mean=1, stddev=1, const=1): if stddev < 0.1: stddev = 0.25 return const + amplitude * np.exp((-(1 / (2. * stddev**2)) * (x - mean)**2)) def line_deriv(x, amplitude=1, mean=1, stddev=1, const=1):
class Ellipsoid3D(models.custom_model(ellipsoid)): @property def bounding_box(self): return ((self.z0 - self.c, self.z0 + self.c), (self.y0 - self.b, self.y0 + self.b), (self.x0 - self.a, self.x0 + self.a))