高斯拟合无法为此PSF返回正确的参数

时间:2018-09-10 23:12:02

标签: python arrays python-3.x data-fitting astronomy

要测试我的2D高斯拟合代码中明亮物体的图像,我将其运行在WISE团队构建并拟合的点扩散函数(PSF)上。他们在他们的网站上列出了每个频段的中央PSF参数:沿长轴和短轴的FWHM,以及位置角度(这是与y轴的夹角)。所有信息都可在此处使用:WISE PSF information,但以下是中央PSF的那些参数的图像,以及频段3的PSF的相应图像。 WISE PSF parameters

WISE central PSF for W3

因此,我已经在频段3中为中央PSF下载了相应的FITS图像(所有图像都可以通过上面的链接下载),并尝试在其上运行代码。但是,我的代码没有返回我期望的参数,并且参数会根据我是否适合子图像(并取决于其大小)或整个图像而变化,这令人担忧。

我想知道是否有一种方法可以使我的高斯拟合代码恢复最准确的参数-也许另一种拟合方法会更有效。但是我最担心的是,我的高斯拟合的输出参数可能变得如此明显地错误。下面是我的代码。

from scipy import optimize
import numpy as np
from astropy.io import fits

image = 'wise-w3-psf-wpro-09x09-05x05.fits' #WISE central PSF
stacked_image = fits.getdata(image)

# Center of image (the PSF is centered)
x0 = np.shape(stacked_image)[1]//2
y0 = np.shape(stacked_image)[0]//2

# Normalize image so peak = 1
def normalize(image):
    image *= 1/np.max(image)
    return image

stacked_image = normalize(stacked_image)

def gaussian_func(xy, x0, y0, sigma_x, sigma_y, amp, theta, offset):
    x, y = xy

    a = (np.cos(theta))**2/(2*sigma_x**2) + (np.sin(theta))**2/(2*sigma_y**2)
    b = -np.sin(2*theta)/(4*sigma_x**2) + np.sin(2*theta)/(4*sigma_y**2)
    c = (np.sin(theta))**2/(2*sigma_x**2) + (np.cos(theta))**2/(2*sigma_y**2)

    inner = a * (x-x0)**2
    inner += 2*b*(x-x0)*(y-y0)
    inner += c * (y-y0)**2
    return (offset + amp * np.exp(-inner)).ravel()

def Sigma2width(sigma):
    return 2 * np.sqrt(2*np.log(2)) * sigma

def generate(data_set):
    xvec = np.arange(0, np.shape(data_set)[1], 1)
    yvec = np.arange(0, np.shape(data_set)[0], 1)
    X, Y = np.meshgrid(xvec, yvec)
    return X, Y


# METHOD 1: Fit subimage of PSF to Gaussian

# Guesses
theta_guess = np.deg2rad(96) #I believe that the angle in the Gaussian corresponds to CCW from the x-axis (so use WISE position angle + 90 degrees)
sigma_x = 5
sigma_y = 4
amp = 1 #I know this is true since I normalized it
subimage = stacked_image[y0-50:y0+50, x0-50:x0+50]

offset = np.min(subimage)
guesses = [np.shape(subimage)[1]//2, np.shape(subimage)[0]//2, sigma_x, sigma_y, amp, theta_guess, offset]

xx, yy = generate(subimage)
pred_params, uncert_cov = optimize.curve_fit(gaussian_func, (xx.ravel(), yy.ravel()), subimage.ravel(), p0=guesses)
width_x, width_y = Sigma2width(np.abs(pred_params[2]))*0.275, Sigma2width(np.abs(pred_params[3]))*0.275 #multiply by pixel scale factor (available on website) to get FWHMs in arcseconds

x_0, y_0 = pred_params[0]+(x0-50), pred_params[1]+(y0-50) #add back origin
theta_deg = np.rad2deg(pred_params[5])
pred_params[5] = theta_deg
pred_params[0] = x_0
pred_params[1] = y_0

if theta_deg < 90:
    pos_angle = theta_deg+90
elif theta_deg >= 90:
    pos_angle = theta_deg-90

print('PREDICTED FWHM x, y in arcsecs:', width_x, width_y)
print('FIT PARAMS [x0, y0, sigma_x, sigma_y, amp, theta, offset]:', pred_params)
print('POSITION ANGLE:', pos_angle)

# Output: PREDICTED FWHM x, y in arcsecs: 6.4917 5.4978
# FIT PARAMS [x0, y0, sigma_x, sigma_y, amp, theta, offset]: [3.195e+02 3.189e+02 1.002e+01 8.489e+00 8.695e-01 8.655e+01 2.613e-02]
# POSITION ANGLE: 176.556


# METHOD 2: Fit whole image to Gaussian

# Guesses
theta_guess = np.deg2rad(96)
sigma_x = 5
sigma_y = 4
amp = 1
offset = np.median(stacked_image)
guesses = [x0, y0, sigma_x, sigma_y, amp, theta_guess, offset]

# Sigmas - manual estimation
ylim, xlim = np.shape(stacked_image)
x, y = np.arange(0, xlim, 1), np.arange(0, ylim, 1)
ypix, xpix = np.where(stacked_image==amp)

y_range = np.take(stacked_image, ypix[0], axis=0)
x_range = np.take(stacked_image, xpix[0], axis=1)

xx, yy = generate(stacked_image)
pred_params, uncert_cov = optimize.curve_fit(gaussian_func, (xx.ravel(), yy.ravel()), stacked_image.ravel(), p0=guesses)
width_x, width_y = Sigma2width(np.abs(pred_params[2]))*0.275, Sigma2width(np.abs(pred_params[3]))*0.275 #in arcsecs
theta = pred_params[5]

print('PREDICTED FWHM x, y in arcsecs:', width_x, width_y)
print('FIT PARAMS [x0, y0, sigma_x, sigma_y, amp, theta, offset]:', pred_params)

# Output: 
# PREDICTED FWHM x, y in arcsecs: 7.088 6.106
# FIT PARAMS [x0, y0, sigma_x, sigma_y, amp, theta, offset]: [3.195e+02 3.190e+02 1.095e+01 9.429e+00 8.378e-01 1.521e+00 7.998e-04]

if theta < 90:
    pos_angle = 90+np.rad2deg(theta)
elif theta >= 90:
    pos_angle = 90-np.rad2deg(theta)

print('POSITION ANGLE:', pos_angle)

# POSITION ANGLE: 177.147

您可以在(四舍五入的)输出中看到我的高斯拟合返回的振幅甚至都不为1,其他参数(FWHM和角度)也与表中显示的正确参数不匹配。 / p>

如果我适合一个子图像,则我制作的子图像的振幅似乎越来越接近(但从未达到)1,但是与实际值相比,FWHM可能会变得太小。为什么我没有得到正确的结果,如何使拟合结果尽可能准确?

0 个答案:

没有答案