Calculate optimal extraction error due to cross-dispersion shift

Gaussian input

In [1]:
%pylab inline --no-import-all
matplotlib.rcParams['image.origin'] = 'lower'
matplotlib.rcParams['image.interpolation'] = 'nearest'

FWHM = 2
sig=FWHM/2.35
flux = 1
x = np.arange(-5,5,1)
gaussian_model = flux*np.exp(-x**2/2./sig**2)/sig/np.sqrt(2.*np.pi)
plt.plot(x,gaussian_model)
plt.xlabel('Pixels')
plt.ylabel('Flux per pixel (1D only)')

Populating the interactive namespace from numpy and matplotlib
Out[1]:
Text(0,0.5,u'Flux per pixel (1D only)')
../_images/notebooks_GaussianOverlap_2_2.png

Construct gaussian matched filter, offset by some amount

In [20]:
offset = 0.1
matched_filter = np.exp(-(x-offset)**2/2./sig**2)/sig/np.sqrt(2.*np.pi)
matched_filter /= np.sum(matched_filter**2)
print("Testing matched filter: measured:",np.sum(gaussian_model*matched_filter)," input: ",flux)
('Testing matched filter: measured:', 0.99677660015688285, ' input: ', 1)
In [21]:
matched_filter = np.exp(-(x-offset)**2/2./sig**2)/sig/np.sqrt(2.*np.pi)
print np.sum(matched_filter**2)
0.331882884126

Do this for a range of offsets

In [3]:
offsets = np.arange(0.0,2.,0.1)
measured_values = np.zeros(len(offsets))
for i in range(len(offsets)):
    offset = offsets[i]
    matched_filter = np.exp(-(x-offset)**2/2./sig**2)/sig/np.sqrt(2.*np.pi)
    matched_filter /= np.sum(matched_filter**2)
    measured_values[i] = np.sum(gaussian_model*matched_filter)

plt.plot(offsets,measured_values/flux)
plt.xlabel("Pixel offset")
plt.ylabel("Fraction of recovered flux")
mf = np.exp(-(offsets)**2/2./sig**2/2.)
plt.plot(offsets,mf)
Out[3]:
[<matplotlib.lines.Line2D at 0x10ca1cc90>]
../_images/notebooks_GaussianOverlap_7_1.png

Do this in 2D

In [4]:
from scipy.special import erf
size = 12
# add some static offset to reflect arbitrary sampling
_x = np.arange(size)-size//2+0.1
_y = np.arange(size)-size//2+0.4
_x, _y = np.meshgrid(_x, _y)
sigma = 2./2.35
psflet = (erf((_x + 0.5) / (np.sqrt(2) * sigma)) - \
    erf((_x - 0.5) / (np.sqrt(2) * sigma))) * \
    (erf((_y + 0.5) / (np.sqrt(2) * sigma)) - \
    erf((_y - 0.5) / (np.sqrt(2) * sigma)))

psflet /= np.sum(psflet)
psflet*=flux

plt.imshow(psflet)
print psflet[psflet/np.amax(psflet)>0.5]
f = psflet[psflet/np.amax(psflet)>0.5]
f /= np.sum(f)
print f
print (np.sum(f**2))
[ 0.09560103  0.15640978  0.10811484  0.17688322]
[ 0.17802505  0.29126107  0.20132785  0.32938603]
0.265553988831
../_images/notebooks_GaussianOverlap_9_1.png
In [5]:
offsets = np.arange(0.0,2.,0.1)
measured_values_psflet = np.zeros(len(offsets))
for i in range(len(offsets)):
    offset = offsets[i]
    matched_filter = (erf((_x + 0.5-offset) / (np.sqrt(2) * sigma)) - \
                            erf((_x - 0.5-offset) / (np.sqrt(2) * sigma))) * \
                            (erf((_y + 0.5) / (np.sqrt(2) * sigma)) - \
                            erf((_y - 0.5) / (np.sqrt(2) * sigma)))
    matched_filter /= np.sum(matched_filter)
    matched_filter /= np.sum(matched_filter**2)
    measured_values_psflet[i] = np.sum(psflet*matched_filter)

plt.plot(offsets,measured_values_psflet/flux)
plt.xlabel("Pixel offset")
plt.ylabel("Fraction of recovered flux")
plt.plot(offsets,measured_values)
plt.legend(["2D PSFLet fit","1D Gaussian fit"])
# mf = np.exp(-(offsets)**2/2./sig**2/2.)
#plt.plot(offsets,mf)
Out[5]:
<matplotlib.legend.Legend at 0x1157cfbd0>
../_images/notebooks_GaussianOverlap_10_1.png

Study the number of effective detector pixels

In [6]:
%pylab inline --no-import-all
matplotlib.rcParams['image.origin'] = 'lower'
matplotlib.rcParams['image.interpolation'] = 'nearest'
from scipy.special import erf
def psf(fwhm=2.,dx=0.,dy=0.,sizex=10,sizey=10):
    _x = np.arange(sizex)-sizex//2+dx
    _y = np.arange(sizey)-sizey//2+dy
    _x, _y = np.meshgrid(_x, _y)
    sigma = fwhm/2.35
    psflet = (erf((_x + 0.5) / (np.sqrt(2) * sigma)) - \
    erf((_x - 0.5) / (np.sqrt(2) * sigma))) * \
    (erf((_y + 0.5) / (np.sqrt(2) * sigma)) - \
    erf((_y - 0.5) / (np.sqrt(2) * sigma)))

    return psflet/np.sum(psflet)
Populating the interactive namespace from numpy and matplotlib
In [7]:
plt.imshow(psf(sizey=10,sizex=20))
Out[7]:
<matplotlib.image.AxesImage at 0x1158f1c10>
../_images/notebooks_GaussianOverlap_13_1.png
In [8]:
dy=0.5
dxmin = 0.5
microspec = psf(sizey=10,sizex=20,dy=dy,dx=dxmin)
dxlist = np.arange(dxmin)
plt.imshow(microspec)
plt.colorbar()
Out[8]:
<matplotlib.colorbar.Colorbar at 0x115a08d50>
../_images/notebooks_GaussianOverlap_15_1.png

Equivalent noise pixel computation for matched filtering

In [12]:
dy=0.2
dxmin = 0.2
p = psf(sizex=100,sizey=100,dy=dy,dx=dxmin)
p[p<np.amax(p)/2.]=0.0
print(np.sum(p)**2/np.sum(p**2))
V = np.sum(p)
sharpness = np.sum(p**2/V**2)
beta = 1./sharpness
print beta
2.90257591762
2.90257591762
In [15]:
N = 10000
vals=np.zeros(N)
dxlist = np.zeros(N)
dylist = np.zeros(N)

for i in range(N):
    dylist[i] = np.random.uniform(-0.5,0.5)
    dxlist[i] = np.random.uniform(-0.5,0.5)
    p = psf(sizex=20,sizey=20,dy=dylist[i],dx=dxlist[i])
    #p[p<np.amax(p)/2.]=0.0
    vals[i] = 1./np.sum(p**2)

In [16]:
plt.scatter(np.sqrt(dylist**2+dxlist**2),vals)
# do colorgrid
Out[16]:
<matplotlib.collections.PathCollection at 0x115e5add0>
../_images/notebooks_GaussianOverlap_19_1.png

Aperture photometry

signal within 2x2 pixel aperture