The tracks of two or more satellites can be used to determine the horizontal and vertical offsets between ccd's if the satellites cross these ccd's in a single exposure.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from astropy.io import fits
plt.rcParams['image.cmap'] = 'viridis_r'
Let us first retrieve the RawScienceFrames for two neightbouring ccd's, in this case ESO_CCD_#75 and ESO_CCD_#76, for which we know there are two satellite tracks that span both ccd's (Thank's Gert!)
rawname = 'OMEGACAM.2011-08-31T09:35:54.666_{ext}.fits'
#RawScienceFrame(pathname=rawname.format(ext=7)).retrieve()
#RawScienceFrame(pathname=rawname.format(ext=8)).retrieve()
h7 = fits.open(rawname.format(ext=7))[0].header
h8 = fits.open(rawname.format(ext=8))[0].header
print h7['CRPIX1'] - h8['CRPIX1']
print h7['CRPIX2'] - h8['CRPIX2']
c7 = fits.open(rawname.format(ext=7))[0].data[:4100,48:2096]
c8 = fits.open(rawname.format(ext=8))[0].data[:4100,48:2096]
Now that we've retrieved the RawScienceFrames we can have a look and see where the satellite tracks are.
fig, (fig7,fig8) = plt.subplots(nrows=1,ncols=2,figsize=(14,8))
fig7.set_title(h7['CHIP_ID'])
fig7.imshow(c7,vmin=250,vmax=420)
fig7.annotate('t1',xy=(1070,3410),xycoords='data',xytext=(-30,-50),textcoords='offset points',size=20,arrowprops=dict(arrowstyle='->'))
fig7.annotate('t1a',xy=(0,4000),xycoords='data',xytext=(30,50),textcoords='offset points',size=10,arrowprops=dict(arrowstyle='->'))
fig7.annotate('t1b',xy=(2048,2850),xycoords='data',xytext=(-30,-50),textcoords='offset points',size=10,arrowprops=dict(arrowstyle='->'))
fig7.annotate('t2',xy=(2048,100),xycoords='data',xytext=(-50,15),textcoords='offset points',size=20,arrowprops=dict(arrowstyle='->'))
fig8.set_title(h8['CHIP_ID'])
fig8.imshow(c8,vmin=250,vmax=420)
fig8.annotate('t1',xy=(1070,2160),xycoords='data',xytext=(-30,-40),textcoords='offset points',size=20,arrowprops=dict(arrowstyle='->'))
fig8.annotate('t1c',xy=(0,2790),xycoords='data',xytext=(30,50),textcoords='offset points',size=10,arrowprops=dict(arrowstyle='->'))
fig8.annotate('t1d',xy=(2048,1600),xycoords='data',xytext=(-30,-50),textcoords='offset points',size=10,arrowprops=dict(arrowstyle='->'))
fig8.annotate('t2',xy=(400,1300),xycoords='data',xytext=(50,-50),textcoords='offset points',size=20,arrowprops=dict(arrowstyle='->'))
As you can see, there are two satellite tracks:
Assuming that the satellite tracks continue from one ccd to the next and they form straight lines, there are a few things we need to know to determine the relative position of the ccd's.
Label the points where each individual satellite track intersects the borders of the ccd's, from left to right: a, b for ESO_CCD_#75 and c, d for ESO_CCD_#76. Then we have
def find_horizontal_intersection(ccd, xslice, ypos, subplot=None):
# Note that in the numpy array the y-axis comes first and the x-axis follows.
crosscut = ccd[ypos,xslice]
# Find the location of the peak. Assume it's the local maximum in the cross-cut
peakposx = xslice.start + np.argmax(crosscut)
if subplot > 0:
ax = plt.subplot(subplot)
# Show the cross-cut and mark its local maximum
ax.plot(np.arange(xslice.start,xslice.stop), crosscut, '.')
ax.plot([peakposx,peakposx], ax.get_ylim(), 'r')
return float(peakposx), float(ypos)
def find_vertical_intersection(ccd, xpos, yslice, subplot=None):
# Note that in the numpy array the y-axis comes first and the x-axis follows.
crosscut = ccd[yslice,xpos]
# Find the location of the peak. Assume it's the local maximum in the cross-cut
peakposy = yslice.start + np.argmax(crosscut)
if subplot > 0:
# Show the cross-cut and mark its local maximum
ax = plt.subplot(subplot)
ax.plot(np.arange(yslice.start,yslice.stop), crosscut, '.')
ax.plot([peakposy,peakposy], ax.get_ylim(), 'r')
return float(xpos), float(peakposy)
f, figs = plt.subplots(nrows=4,ncols=2,figsize=(14,8))
t1ax,t1ay = find_vertical_intersection(c7, 0, slice(3910,4099), subplot=421)
t1bx,t1by = find_vertical_intersection(c7, 2047, slice(2700,2900), subplot=422)
t1cx,t1cy = find_vertical_intersection(c8, 0, slice(2650,2850), subplot=423)
t1dx,t1dy = find_vertical_intersection(c8, 2045, slice(1450,1650), subplot=424)
t2ax,t2ay = find_horizontal_intersection(c7, slice(1900,2048), 0, subplot=425)
t2bx,t2by = find_vertical_intersection(c7, 2047, slice(0,200), subplot=426)
t2cx,t2cy = find_vertical_intersection(c8, 0, slice(300,500), subplot=427)
t2dx,t2dy = find_horizontal_intersection(c8, slice(1300,1500), 4099, subplot=428)
t2ax += 2
t2by -= 3
t2cy += 1
#t1ay+=130
#t1by+=130
#t2ay+=130
#t2by+=130
plt.figure(figsize=(12,8))
dx = 2048 - (-88.5)
dy = - (-3.59)
assert t1bx == t2bx
assert t1cx == t2cx
a1c, b1c = np.polyfit([t1cx,t1dx], [t1cy,t1dy], 1)
a2c, b2c = np.polyfit([t2cx,t2dx], [t2cy,t2dy], 1)
a1a, b1a = np.polyfit([t1ax,t1bx], [t1ay,t1by], 1)
a2a, b2a = np.polyfit([t2ax,t2bx], [t2ay,t2by], 1)
plt.plot([t1ax,t1bx],[t1ay,t1by],'b')
plt.plot([t2ax,t2bx],[t2ay,t2by],'g')
plt.plot([dx+t1cx,dx+t1dx],[dy+t1cy,dy+t1dy],'b')
plt.plot([dx+t2cx,dx+t2dx],[dy+t2cy,dy+t2dy],'g')
plt.plot([dx+t1cx-88.5,dx+t1cx],[dy+a1c*(t1cx-88.5)+b1c,dy+t1cy],'o-r')
plt.plot([dx+t2cx-88.5,dx+t2cx],[dy+a2c*(t2cx-88.5)+b2c,dy+t2cy],'o-r')
print 'The slopes in t1 should be similar in each ccd: {a1a:5.2f}, {a1c:5.2f}'.format(**vars())
print 'The slopes in t2 should be similar in each ccd: {a2a:5.2f}, {a2c:5.2f}'.format(**vars())
x = ((t1by - t2by) - (b1c - b2c)) / (a1c - a2c)
y = a1c*x + b1c - t1by
print a1c*x+b1c-t1by, a2c*x+b2c-t2by
print 'Horizontal and vertical offset of ESO_CCD_#75 w.r.t. ESO_CCD_#76: {xoffset:6.2f}, {yoffset:5.2f}'.format(xoffset=x,yoffset=y)
# t1by, a1c*x + b1c + 3.4, t2by, a2c*x + b2c + 3.4
x = ((t1cy - t2cy) - (b1a - b2a)) / (a1a - a2a)
y = a1a*x + b1a - t1cy
print 'Horizontal and vertical offset of ESO_CCD_#76 w.r.t. ESO_CCD_#75: {offset:6.2f}, {yoffset:5.2f}'.format(offset=x-2048,yoffset=y)
import mpld3
mpld3.display()