First commit

pull/1/head
Cees Bassa 2018-03-09 21:08:47 +01:00
parent f854f7be9f
commit b47057ad82
9 changed files with 1104 additions and 0 deletions

201
acquire.py 100644
View File

@ -0,0 +1,201 @@
#!/usr/bin/env python
import sys
import numpy as np
import cv2
import time
import ctypes
import multiprocessing
from astropy.time import Time
from astropy.io import fits
from sun import get_sunriseset
# Capture images
def capture(buf,z1,t1,z2,t2,device,nx,ny,nz,tend):
# Array flag
first=True
# Loop until reaching end time
while float(time.time())<tend:
# Get frames
for i in range(nz):
# Get frame
ret,frame=device.read()
# Skip lost frames
if ret==True:
# Store time
t=float(time.time())
# Convert image to grayscale
gray=np.asarray(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)).astype(np.uint8)
# Store buffer
z=gray
# Store results
if first:
z1[i]=z
t1[i]=t
else:
z2[i]=z
t2[i]=t
# Assign buffer ready
if first:
buf.value=1
else:
buf.value=2
# Swap flag
first=not first
print("Exiting capture")
def compress(buf,z1,t1,z2,t2,nx,ny,nz,tend):
# Flag to keep track of processed buffer
process_buf=1
# Start processing
while True:
# Wait for buffer to become available
while buf.value!=process_buf:
time.sleep(1.0)
# Process first buffer
if buf.value==1:
t=t1
z=z1.astype('float32')
process_buf=2
elif buf.value==2:
t=t2
z=z2.astype('float32')
process_buf=1
# Compute statistics
zmax=np.max(z,axis=0)
znum=np.argmax(z,axis=0)
zs1=np.sum(z,axis=0)-zmax
zs2=np.sum(z*z,axis=0)-zmax*zmax
zavg=zs1/float(nz-1)
zstd=np.sqrt((zs2-zs1*zavg)/float(nz-2))
# Convert to float and flip
zmax=np.flipud(zmax.astype('float32'))
znum=np.flipud(znum.astype('float32'))
zavg=np.flipud(zavg.astype('float32'))
zstd=np.flipud(zstd.astype('float32'))
# Format time
nfd="%s.%03d"%(time.strftime("%Y-%m-%dT%T", time.gmtime(t[0])),int((t[0]-np.floor(t[0]))*1000))
t0=Time(nfd,format='isot')
dt=t-t[0]
# Generate fits
fname="%s.fits"%nfd
# Format header
hdr=fits.Header()
hdr['DATE-OBS']="%s"%nfd
hdr['MJD-OBS']=t0.mjd
hdr['EXPTIME']=dt[-1]-dt[0]
hdr['NFRAMES']=nz
hdr['CRPIX1']=float(nx)/2.0
hdr['CRPIX2']=float(ny)/2.0
hdr['CRVAL1']=0.0
hdr['CRVAL2']=0.0
hdr['CD1_1']=1.0/3600.0
hdr['CD1_2']=0.0
hdr['CD2_1']=0.0
hdr['CD2_2']=1.0/3600.0
hdr['CTYPE1']="RA---TAN"
hdr['CTYPE2']="DEC--TAN"
hdr['CUNIT1']="deg"
hdr['CUNIT2']="deg"
hdr['CRRES1']=0.0
hdr['CRRES2']=0.0
hdr['EQUINIX']=2000.0
hdr['RADECSYS']="ICRS"
hdr['COSPAR']=4171
hdr['OBSERVER']="Cees Bassa"
for i in range(nz):
hdr['DT%04d'%i]=dt[i]
for i in range(10):
hdr['DUMY%03d'%i]=0.0
# Write fits file
hdu=fits.PrimaryHDU(data=np.array([zavg,zstd,zmax,znum]),header=hdr)
hdu.writeto(fname)
print("Compressed",fname)
# Exit on end of capture
if t[-1]>tend:
break
# Exiting
print("Exiting compress")
# Main function
if __name__ == '__main__':
# Current time
tnow=float(time.time())
tnow=1520573400.0
tnow=1520510226.281413,
# Get sunrise and sunset times
trise,tset=get_sunriseset(tnow,52.8344,6.3785,10,-6.0)
print(tnow,trise,tset)
# Wait until sunset
if (tset<trise) & (tnow<tset):
print("Waiting for sunset at %s"%time.strftime("%FT%T",time.gmtime(tset)))
sys.exit()
# Settings
devid=int(sys.argv[1])
nx=720
ny=576
nz=250
# Initialize device
device=cv2.VideoCapture(devid)
# Set properties
device.set(3,nx)
device.set(4,ny)
# Initialize arrays
z1base=multiprocessing.Array(ctypes.c_uint8,nx*ny*nz)
z1=np.ctypeslib.as_array(z1base.get_obj()).reshape(nz,ny,nx)
t1base=multiprocessing.Array(ctypes.c_double,nz)
t1=np.ctypeslib.as_array(t1base.get_obj())
z2base=multiprocessing.Array(ctypes.c_uint8,nx*ny*nz)
z2=np.ctypeslib.as_array(z2base.get_obj()).reshape(nz,ny,nx)
t2base=multiprocessing.Array(ctypes.c_double,nz)
t2=np.ctypeslib.as_array(t2base.get_obj())
buf=multiprocessing.Value('i',0)
tend=float(time.time())+31.0
# Set processes
pcapture=multiprocessing.Process(target=capture,args=(buf,z1,t1,z2,t2,device,nx,ny,nz,tend))
pcompress=multiprocessing.Process(target=compress,args=(buf,z1,t1,z2,t2,nx,ny,nz,tend))
# Start
pcapture.start()
pcompress.start()
# End
try:
pcapture.join()
pcompress.join()
except KeyboardInterrupt:
pcapture.terminate()
pcompress.terminate()
# Release device
device.release()

142
calibrate.py 100644
View File

@ -0,0 +1,142 @@
#!/usr/bin/env python
import os
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
from astropy import wcs
from scipy import optimize
def residual(a,x,y,z):
return z-(a[0]+a[1]*x+a[2]*y)
def offsets(ra0,de0,ra,de):
w=wcs.WCS(naxis=2)
w.wcs.crpix=np.array([0.0,0.0])
w.wcs.crval=np.array([ra0,de0])
w.wcs.cd=np.array([[1.0/3600.0,0.0],[0.0,1.0/3600.0]])
w.wcs.ctype=["RA---TAN","DEC--TAN"]
w.wcs.set_pv([(2,1,45.0)])
world=np.stack((ra,de),axis=-1)
pix=w.wcs_world2pix(world,1)
return pix[:,0],pix[:,1]
def read_pixel_catalog(fname):
d=np.loadtxt(fname)
x,y,mag=d[:,0],d[:,1],d[:,2]
return x,y,mag
def read_tycho2_catalog(maxmag=9.0):
hdu=fits.open("/home/bassa/code/python/satellite/astrometry-tycho2/build/tyc2.fits")
ra=hdu[1].data.field('RA')
de=hdu[1].data.field('DEC')
mag=hdu[1].data.field('MAG_VT')
c=mag<maxmag
print("Selected %d stars from Tycho-2 catalog with m<%.1f"%(np.sum(c),maxmag))
return ra[c],de[c],mag[c]
def match_catalogs(ra,de,x,y,xs,ys,rmin):
res=[]
for i in range(len(x)):
dx,dy=xs-x[i],ys-y[i]
r=np.sqrt(dx*dx+dy*dy)
if np.min(r)<rmin:
j=np.argmin(r)
res.append([ra[i],de[i],xs[j],ys[j]])
return np.array(res)
def fit_wcs(res,x0,y0):
ra,de,x,y=res[:,0],res[:,1],res[:,2],res[:,3]
ra0,de0=np.mean(ra),np.mean(de)
dx,dy=x-x0,y-y0
for i in range(5):
w=wcs.WCS(naxis=2)
w.wcs.crpix=np.array([0.0,0.0])
w.wcs.crval=np.array([ra0,de0])
w.wcs.cd=np.array([[1.0,0.0],[0.0,1.0]])
w.wcs.ctype=["RA---TAN","DEC--TAN"]
w.wcs.set_pv([(2,1,45.0)])
world=np.stack((ra,de),axis=-1)
pix=w.wcs_world2pix(world,1)
rx,ry=pix[:,0],pix[:,1]
ax,cov_q,infodict,mesg,ierr=optimize.leastsq(residual,[0.0,0.0,0.0],args=(dx,dy,rx),full_output=1)
ay,cov_q,infodict,mesg,ierr=optimize.leastsq(residual,[0.0,0.0,0.0],args=(dx,dy,ry),full_output=1)
ra0,de0=w.wcs_pix2world([[ax[0],ay[0]]],1)[0]
w=wcs.WCS(naxis=2)
w.wcs.crpix=np.array([x0,y0])
w.wcs.crval=np.array([ra0,de0])
w.wcs.cd=np.array([[ax[1],ax[2]],[ay[1],ay[2]]])
w.wcs.ctype=["RA---TAN","DEC--TAN"]
w.wcs.set_pv([(2,1,45.0)])
whdr={"CRPIX1":x0,"CRPIX2":y0,"CRVAL1":ra0,"CRVAL2":de0,"CD1_1":ax[1],"CD1_2":ax[2],"CD2_1":ay[1],"CD2_2":ay[2],"CTYPE1":"RA---TAN","CTYPE2":"DEC--TAN","CUNIT1":"DEG","CUNIT2":"DEG"}
return whdr
# FITS file
fname="2018-02-12T17:39:55.270.fits"
# Read fits
hdu=fits.open(fname)
# Fix to force WCS with two axes only
hdu[0].header["NAXIS"]=2
w=wcs.WCS(hdu[0].header)
# Read data
data=hdu[0].data
zavg,zstd,zmax,znum=data
ny,nx=zavg.shape
# Get extrema
vmin=np.mean(zavg)-2.0*np.std(zavg)
vmax=np.mean(zavg)+3.0*np.std(zavg)
# Read pixel catalog
xs,ys,ms=read_pixel_catalog(fname+".cat")
# Read Tycho2 catalog
ra,de,mag=read_tycho2_catalog(9.0)
# Convert to pixel coordinates
xc,yc=w.all_world2pix(ra,de,1)
c=(xc>0) & (xc<nx) & (yc>0) & (yc<ny)
xt,yt=xc[c],yc[c]
rat,det=ra[c],de[c]
# Match catalogs
res=match_catalogs(rat,det,xt,yt,xs,ys,10.0)
whdr=fit_wcs(res,nx//2,ny//2)
#hdu=fits.PrimaryHDU(header=w.to_header(),data=data)
#hdr=fits.Header()
hdr=hdu[0].header
for k,v in whdr.items():
hdr[k]=v
hdu=fits.PrimaryHDU(header=hdr,data=data)
hdu.writeto("test.fits",overwrite=True)
# Convert catalog stars
plt.figure(figsize=(10,8))
plt.imshow(zavg,origin="lower",aspect=1.0,interpolation="None",vmin=vmin,vmax=vmax)
plt.scatter(xs,ys,s=80,edgecolors="r",facecolors="none")
plt.scatter(xt,yt,s=150,edgecolors="y",facecolors="none")
#plt.scatter(xt[c],yt[c],s=50,edgecolors="k",facecolors="none")
#plt.xlim(0,720)
#plt.ylim(0,576)
plt.show()

366
extract_tracks.py 100644
View File

@ -0,0 +1,366 @@
#!/usr/bin/env python
import sys,os,glob
from stio import fourframe,satid,observation
import numpy as np
import ppgplot
import matplotlib.pyplot as plt
from scipy import optimize,ndimage
from astropy import wcs
from astropy.coordinates import SkyCoord
# Gaussian model
def model(a,nx,ny):
x,y=np.meshgrid(np.arange(nx),np.arange(ny))
dx,dy=(x-a[0])/a[2],(y-a[1])/a[2]
arg=-0.5*(dx**2+dy**2)
return a[3]*np.exp(arg)+a[4]
# Residual function
def residual(a,img):
ny,nx=img.shape
mod=model(a,nx,ny)
return (img-mod).ravel()
# Find peak
def peakfind(img,w=1.0):
# Find approximate location
ny,nx=img.shape
i=np.argmax(img)
y0=int(i/nx)
x0=i-y0*nx
# Image properties
imgavg=np.mean(img)
imgstd=np.std(img)
# Estimate
a=np.array([x0,y0,w,img[y0,x0]-imgavg,imgavg])
q,cov_q,infodict,mesg,ier=optimize.leastsq(residual,a,args=(img),full_output=1)
# Extract
xc,yc,w=q[0],q[1],q[2]
# Significance
sigma=(a[3]-imgavg)/(imgstd+1e-9)
return xc,yc,w,sigma
# Plot selection
def plot_selection(id,x0,y0,dt=2.0,w=10.0):
dx,dy=id.x1-id.x0,id.y1-id.y0
ang=np.arctan2(dy,dx)
r=np.sqrt(dx**2+dy**2)
drdt=r/(id.t1-id.t0)
sa,ca=np.sin(ang),np.cos(ang)
dx=np.array([-dt,-dt,dt,dt,-dt])*drdt
dy=np.array([w,-w,-w,w,w])
x=ca*dx-sa*dy+x0
y=sa*dx+ca*dy+y0
ppgplot.pgsci(7)
ppgplot.pgline(x,y)
return
# Check if point is inside selection
def inside_selection(id,x0,y0,xmid,ymid,dt=2.0,w=10.0):
dx,dy=id.x1-id.x0,id.y1-id.y0
ang=-np.arctan2(dy,dx)
r=np.sqrt(dx**2+dy**2)
drdt=r/(id.t1-id.t0)
sa,ca=np.sin(ang),np.cos(ang)
dx,dy=x0-xmid,y0-ymid
rm=ca*dx-sa*dy
wm=sa*dx+ca*dy
dtm=rm/drdt
if (abs(wm)<w) & (abs(dtm)<dt):
return True
else:
return False
# Get COSPAR ID
def get_cospar(norad):
f=open(os.getenv("ST_DATADIR")+"/data/desig.txt")
lines=f.readlines()
f.close()
try:
cospar=([line for line in lines if str(norad) in line])[0].split()[1]
except IndexError:
cospar="18500A"
return "%2s %s"%(cospar[0:2],cospar[2:])
# IOD position format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc)
def format_position(ra,de):
ram=60.0*ra/15.0
rah=int(np.floor(ram/60.0))
ram-=60.0*rah
des=np.sign(de)
dem=60.0*np.abs(de)
ded=int(np.floor(dem/60.0))
dem-=60.0*ded
if des==-1:
sign="-"
else:
sign="+"
return ("%02d%06.3f%c%02d%05.2f"%(rah,ram,sign,ded,dem)).replace(".","")
# Format IOD line
def format_iod_line(norad,cospar,site_id,t,ra,de):
pstr=format_position(ra,de)
tstr=t.replace("-","").replace("T","").replace(":","").replace(".","")
return "%05d %-9s %04d G %s 17 25 %s 37 S"%(norad,cospar,site_id,tstr,pstr)
# Extract tracks
def extract_tracks(fname,trkrmin,drdtmin,trksig,ntrkmin):
# Read four frame
ff=fourframe(fname)
# Skip saturated frames
if np.sum(ff.zavg>240.0)/float(ff.nx*ff.ny)>0.95:
return
# Read satelite IDs
try:
f=open(fname+".id")
except OSError:
print("Cannot open",fname+".id")
else:
lines=f.readlines()
f.close()
# ppgplot arrays
tr=np.array([-0.5,1.0,0.0,-0.5,0.0,1.0])
heat_l=np.array([0.0,0.2,0.4,0.6,1.0])
heat_r=np.array([0.0,0.5,1.0,1.0,1.0])
heat_g=np.array([0.0,0.0,0.5,1.0,1.0])
heat_b=np.array([0.0,0.0,0.0,0.3,1.0])
# Loop over identifications
for line in lines:
# Decode
id=satid(line)
# Skip slow moving objects
drdt=np.sqrt(id.dxdt**2+id.dydt**2)
if drdt<drdtmin:
continue
# Extract significant pixels
x,y,t,sig=ff.significant(trksig,id.x0,id.y0,id.dxdt,id.dydt,trkrmin)
# Fit tracks
if len(t)>ntrkmin:
# Get times
tmin=np.min(t)
tmax=np.max(t)
tmid=0.5*(tmax+tmin)
mjd=ff.mjd+tmid/86400.0
# Skip if no variance in time
if np.std(t-tmid)==0.0:
continue
# Very simple polynomial fit; no weighting, no cleaning
px=np.polyfit(t-tmid,x,1)
py=np.polyfit(t-tmid,y,1)
# Extract results
x0,y0=px[1],py[1]
dxdt,dydt=px[0],py[0]
xmin=x0+dxdt*(tmin-tmid)
ymin=y0+dydt*(tmin-tmid)
xmax=x0+dxdt*(tmax-tmid)
ymax=y0+dydt*(tmax-tmid)
cospar=get_cospar(id.norad)
obs=observation(ff,mjd,x0,y0)
iod_line="%s"%format_iod_line(id.norad,cospar,ff.site_id,obs.nfd,obs.ra,obs.de)
print(iod_line)
if id.catalog.find("classfd.tle")>0:
outfname="classfd.dat"
elif id.catalog.find("inttles.tle")>0:
outfname="inttles.dat"
else:
outfname="catalog.dat"
f=open(outfname,"a")
f.write("%s\n"%iod_line);
f.close()
# Plot
ppgplot.pgopen(fname.replace(".fits","")+"_%05d.png/png"%id.norad)
#ppgplot.pgopen("/xs")
ppgplot.pgpap(0.0,1.0)
ppgplot.pgsvp(0.1,0.95,0.1,0.8)
ppgplot.pgsch(0.8)
ppgplot.pgmtxt("T",6.0,0.0,0.0,"UT Date: %.23s COSPAR ID: %04d"%(ff.nfd,ff.site_id))
if (3600.0*ff.crres[0]<1e-3) | (3600.0*ff.crres[1]<1e-3) | (ff.crres[0]/ff.sx>2.0) | (ff.crres[1]/ff.sy>2.0):
ppgplot.pgsci(2)
else:
ppgplot.pgsci(1)
ppgplot.pgmtxt("T",4.8,0.0,0.0,"R.A.: %10.5f (%4.1f'') Decl.: %10.5f (%4.1f'')"%(ff.crval[0],3600.0*ff.crres[0],ff.crval[1],3600.0*ff.crres[1]))
ppgplot.pgsci(1)
ppgplot.pgmtxt("T",3.6,0.0,0.0,"FoV: %.2f\\(2218)x%.2f\\(2218) Scale: %.2f''x%.2f'' pix\\u-1\\d"%(ff.wx,ff.wy,3600.0*ff.sx,3600.0*ff.sy))
ppgplot.pgmtxt("T",2.4,0.0,0.0,"Stat: %5.1f+-%.1f (%.1f-%.1f)"%(np.mean(ff.zmax),np.std(ff.zmax),ff.vmin,ff.vmax))
ppgplot.pgmtxt("T",0.3,0.0,0.0,iod_line)
ppgplot.pgsch(1.0)
ppgplot.pgwnad(0.0,ff.nx,0.0,ff.ny)
ppgplot.pglab("x (pix)","y (pix)"," ")
ppgplot.pgctab(heat_l,heat_r,heat_g,heat_b,5,1.0,0.5)
ppgplot.pgimag(ff.zmax,ff.nx,ff.ny,0,ff.nx-1,0,ff.ny-1,ff.vmax,ff.vmin,tr)
ppgplot.pgbox("BCTSNI",0.,0,"BCTSNI",0.,0)
ppgplot.pgstbg(1)
ppgplot.pgsci(0)
if id.catalog.find("classfd.tle")>0:
ppgplot.pgsci(4)
elif id.catalog.find("inttles.tle")>0:
ppgplot.pgsci(3)
ppgplot.pgpt(np.array([x0]),np.array([y0]),4)
ppgplot.pgmove(xmin,ymin)
ppgplot.pgdraw(xmax,ymax)
ppgplot.pgsch(0.65)
ppgplot.pgtext(np.array([x0]),np.array([y0])," %05d"%id.norad)
ppgplot.pgsch(1.0)
ppgplot.pgsci(1)
ppgplot.pgend()
elif id.catalog.find("classfd.tle")>0:
# Track and stack
t=np.linspace(0.0,ff.texp)
x,y=id.x0+id.dxdt*t,id.y0+id.dydt*t
c=(x>0) & (x<ff.nx) & (y>0) & (y<ff.ny)
# Skip if no points selected
if np.sum(c)==0:
continue
# Compute track
tmid=np.mean(t[c])
mjd=ff.mjd+tmid/86400.0
xmid=id.x0+id.dxdt*tmid
ymid=id.y0+id.dydt*tmid
ztrk=ndimage.gaussian_filter(ff.track(id.dxdt,id.dydt,tmid),1.0)
vmin=np.mean(ztrk)-2.0*np.std(ztrk)
vmax=np.mean(ztrk)+6.0*np.std(ztrk)
# Select region
xmin=int(xmid-100)
xmax=int(xmid+100)
ymin=int(ymid-100)
ymax=int(ymid+100)
if xmin<0: xmin=0
if ymin<0: ymin=0
if xmax>ff.nx: xmax=ff.nx-1
if ymax>ff.ny: ymax=ff.ny-1
# Find peak
x0,y0,w,sigma=peakfind(ztrk[ymin:ymax,xmin:xmax])
x0+=xmin
y0+=ymin
# Skip if peak is not significant
if sigma<trksig:
continue
# Skip if point is outside selection area
if inside_selection(id,xmid,ymid,x0,y0)==False:
continue;
# Format IOD line
cospar=get_cospar(id.norad)
obs=observation(ff,mjd,x0,y0)
iod_line="%s"%format_iod_line(id.norad,cospar,ff.site_id,obs.nfd,obs.ra,obs.de)
print(iod_line)
if id.catalog.find("classfd.tle")>0:
outfname="classfd.dat"
elif id.catalog.find("inttles.tle")>0:
outfname="inttles.dat"
else:
outfname="catalog.dat"
f=open(outfname,"a")
f.write("%s\n"%iod_line);
f.close()
# Plot
ppgplot.pgopen(fname.replace(".fits","")+"_%05d.png/png"%id.norad)
ppgplot.pgpap(0.0,1.0)
ppgplot.pgsvp(0.1,0.95,0.1,0.8)
ppgplot.pgsch(0.8)
ppgplot.pgmtxt("T",6.0,0.0,0.0,"UT Date: %.23s COSPAR ID: %04d"%(ff.nfd,ff.site_id))
ppgplot.pgmtxt("T",4.8,0.0,0.0,"R.A.: %10.5f (%4.1f'') Decl.: %10.5f (%4.1f'')"%(ff.crval[0],3600.0*ff.crres[0],ff.crval[1],3600.0*ff.crres[1]))
ppgplot.pgmtxt("T",3.6,0.0,0.0,"FoV: %.2f\\(2218)x%.2f\\(2218) Scale: %.2f''x%.2f'' pix\\u-1\\d"%(ff.wx,ff.wy,3600.0*ff.sx,3600.0*ff.sy))
ppgplot.pgmtxt("T",2.4,0.0,0.0,"Stat: %5.1f+-%.1f (%.1f-%.1f)"%(np.mean(ff.zmax),np.std(ff.zmax),ff.vmin,ff.vmax))
ppgplot.pgmtxt("T",0.3,0.0,0.0,iod_line)
ppgplot.pgsch(1.0)
ppgplot.pgwnad(0.0,ff.nx,0.0,ff.ny)
ppgplot.pglab("x (pix)","y (pix)"," ")
ppgplot.pgctab(heat_l,heat_r,heat_g,heat_b,5,1.0,0.5)
ppgplot.pgimag(ztrk,ff.nx,ff.ny,0,ff.nx-1,0,ff.ny-1,vmax,vmin,tr)
ppgplot.pgbox("BCTSNI",0.,0,"BCTSNI",0.,0)
ppgplot.pgstbg(1)
plot_selection(id,xmid,ymid)
ppgplot.pgsci(0)
if id.catalog.find("classfd.tle")>0:
ppgplot.pgsci(4)
elif id.catalog.find("inttles.tle")>0:
ppgplot.pgsci(3)
ppgplot.pgpt(np.array([id.x0]),np.array([id.y0]),17)
ppgplot.pgmove(id.x0,id.y0)
ppgplot.pgdraw(id.x1,id.y1)
ppgplot.pgpt(np.array([x0]),np.array([y0]),4)
ppgplot.pgsch(0.65)
ppgplot.pgtext(np.array([id.x0]),np.array([id.y0])," %05d"%id.norad)
ppgplot.pgsch(1.0)
ppgplot.pgsci(1)
ppgplot.pgend()
if __name__ == '__main__':
# Minimum predicted velocity (pixels/s)
drdtmin=10.0
# Track selection region around prediction (pixels)
trkrmin=10.0
# Track selection sigma
trksig=5.0
# Minimum track points
ntrkmin=10
# extract_tracks("2018-02-26T05:26:15.801.fits",trkrmin,drdtmin,trksig,ntrkmin)
files=sorted(glob.glob("2*.fits"))
for file in files:
extract_tracks(file,trkrmin,drdtmin,trksig,ntrkmin)

49
hough.py 100644
View File

@ -0,0 +1,49 @@
import numpy as np
import matplotlib.pyplot as plt
from astropy.io import fits
import cv2
import sys
hdu=fits.open(sys.argv[1])
data=hdu[0].data
zavg,zstd,zmax,znum=data
zsig=(zmax-zavg)/(zstd+1e-9)
ny,nx=zsig.shape
tmp=np.zeros(nx*ny*3,dtype='uint8').reshape(ny,nx,3)
tmp[:,:,0]=zmax.astype('uint8')
tmp[:,:,1]=0.1*zmax.astype('uint8')
tmp[:,:,2]=0.1*zmax.astype('uint8')
img=cv2.cvtColor(tmp,cv2.COLOR_BGR2RGB)
mask=np.array(zsig>5.0,dtype='uint8')
tmp=np.zeros(nx*ny*3,dtype='uint8').reshape(ny,nx,3)
tmp[:,:,0]=255*mask
tmp[:,:,1]=255*mask
tmp[:,:,2]=255*mask
mat=cv2.cvtColor(tmp,cv2.COLOR_BGR2GRAY)
lines=cv2.HoughLines(mat,1,np.pi/180.0,200)
if lines is not None:
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1+10),(x2,y2+10),(0,0,255),2)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(mat,1,np.pi/180,100,minLineLength,maxLineGap)
if lines is not None:
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite(sys.argv[1]+'.jpg',img)

30
iod.py 100644
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python
class iod:
"""IOD Observation"""
def __init__(self,line):
s=line.split()
self.iodline=line
self.norad=int(s[0])
self.cospar="%s %s"%(s[1],s[2])
self.site=int(s[3])
self.conditions=s[4]
self.datestring=s[5]
def __repr__(self):
return "%05d %s %04d %s %s"%(self.norad,self.cospar,self.site,self.conditions,self.datestring)
iodlines=["10529 77 112D 4553 G 20120511214446298 17 25 2034286+472232 37 R",
"10529 77 112D 4553 G 20120511214452938 17 25 2038653+454274 37 S",
"23862 96 029D 4553 G 20120511221706217 17 25 2121225+480700 37 S",
"23862 96 029D 4553 G 20120511221726241 17 25 2122590+453398 37 R"]
obslist=[iod(line) for line in iodlines]
print(type(obslist),type(obslist[0]))
for obs in obslist:
print(obs)

69
plot.py 100644
View File

@ -0,0 +1,69 @@
#!/usr/bin/env python
import numpy as np
import sys
from astropy.io import fits
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fname="2018-02-12T17:39:55.270.fits"
# Read fits
hdu=fits.open(fname)
# Read data
data=hdu[0].data
zavg,zstd,zmax,znum=data
# Read header
ny,nx=zavg.shape
nz=hdu[0].header['NFRAMES']
dt=[hdu[0].header['DT%04d'%i] for i in range(nz)]
# Sigma frame
zsig=(zmax-zavg)/(zstd+1e-9)
# Position
xm,ym=np.meshgrid(np.arange(nx),np.arange(ny))
# Selection width
w=10
sigma=5.0
# Selection
c=(zsig>sigma) & (xm>w) & (xm<nx-w) & (ym>w) & (ym<ny-w)
x=np.ravel(xm[c])
y=np.ravel(ym[c])
inum=np.ravel(znum[c]).astype('int')
sig=np.ravel(zsig[c])
t=np.array([dt[i] for i in inum])
# Load predictions
d=np.loadtxt(fname+".id",usecols=(1,2,3,4,5,6))
x0=d[:,0]
y0=d[:,1]
t0=np.zeros_like(x0)
x1=d[:,2]
y1=d[:,3]
t1=d[:,4]
for i in range(len(x0)):
xr=x0[i]+(x1[i]-x0[i])*(t-t0[i])/(t1[i]-t0[i])
yr=y0[i]+(y1[i]-y0[i])*(t-t0[i])/(t1[i]-t0[i])
r=np.sqrt((x-xr)**2+(y-yr)**2)
c=r<10.0
print(i,np.sum(c))
plt.figure()
plt.plot([x0[i],x1[i]],[y0[i],y1[i]],'r')
plt.scatter(x[c],y[c],c=t[c],s=10.0*(sig[c]-sigma))
plt.scatter(x,y,c=t,s=1)
plt.show()
#fig=plt.figure()
#ax=fig.add_subplot(111,projection='3d')
#ax.scatter(x,y,t,c=t,s=10*(sig-5))
#for i in range(len(x0)):
# ax.plot([x0[i],x1[i]],[y0[i],y1[i]],[t0[i],t1[i]],'k')
#plt.show()

191
stio.py 100644
View File

@ -0,0 +1,191 @@
#!/usr/bin/env python
import numpy as np
from astropy.io import fits
from astropy.time import Time
from astropy import wcs
class observation:
"""Satellite observation"""
def __init__(self,ff,mjd,x0,y0):
"""Define an observation"""
# Store
self.mjd=mjd
self.x0=x0
self.y0=y0
# Get times
self.nfd=Time(self.mjd,format='mjd',scale='utc').isot
# Correct for rotation
tobs=Time(ff.mjd+0.5*ff.texp/86400.0,format='mjd',scale='utc')
tobs.delta_ut1_utc=0
hobs=tobs.sidereal_time("mean",longitude=0.0).degree
tmid=Time(self.mjd,format='mjd',scale='utc')
tmid.delta_ut1_utc=0
hmid=tmid.sidereal_time("mean",longitude=0.0).degree
# Compute ra/dec
world=ff.w.wcs_pix2world(np.array([[self.x0,self.y0]]),1)
self.ra=world[0,0]+hobs-hmid
self.de=world[0,1]
class satid:
"""Satellite identifications"""
def __init__(self,line):
s=line.split()
self.nfd=s[0]
self.x0=float(s[1])
self.y0=float(s[2])
self.t0=0.0
self.x1=float(s[3])
self.y1=float(s[4])
self.t1=float(s[5])
self.norad=int(s[6])
self.catalog=s[7]
self.state=s[8]
self.dxdt=(self.x1-self.x0)/(self.t1-self.t0)
self.dydt=(self.y1-self.y0)/(self.t1-self.t0)
def __repr__(self):
return "%s %f %f %f -> %f %f %f %d %s %s"%(self.nfd,self.x0,self.y0,self.t0,self.x1,self.y1,self.t1,self.norad,self.catalog,self.state)
class fourframe:
"""Four frame class"""
def __init__(self,fname=None):
if fname==None:
# Initialize empty fourframe
self.nx=0
self.ny=0
self.nz=0
self.mjd=-1
self.nfd=None
self.zavg=None
self.zstd=None
self.zmax=None
self.znum=None
self.dt=None
self.site_id=0
self.observer=None
self.texp=0.0
self.fname=None
self.crpix=np.array([0.0,0.0])
self.crval=np.array([0.0,0.0])
self.cd=np.array([[1.0,0.0],[0.0,1.0]])
self.ctype=["RA---TAN","DEC--TAN"]
self.cunit=np.array(["deg","deg"])
self.crres=np.array([0.0,0.0])
else:
# Read FITS file
hdu=fits.open(fname)
# Read image planes
self.zavg,self.zstd,self.zmax,self.znum=hdu[0].data
# Frame properties
self.ny,self.nx=self.zavg.shape
self.nz=hdu[0].header['NFRAMES']
# Read frame time oselfsets
self.dt=np.array([hdu[0].header['DT%04d'%i] for i in range(self.nz)])
# Read header
self.mjd=hdu[0].header['MJD-OBS']
self.nfd=hdu[0].header['DATE-OBS']
self.site_id=hdu[0].header['COSPAR']
self.observer=hdu[0].header['OBSERVER']
self.texp=hdu[0].header['EXPTIME']
self.fname=fname
# Astrometry keywords
self.crpix=np.array([hdu[0].header['CRPIX1'],hdu[0].header['CRPIX2']])
self.crval=np.array([hdu[0].header['CRVAL1'],hdu[0].header['CRVAL2']])
self.cd=np.array([[hdu[0].header['CD1_1'],hdu[0].header['CD1_2']],
[hdu[0].header['CD2_1'],hdu[0].header['CD2_2']]])
self.ctype=[hdu[0].header['CTYPE1'],hdu[0].header['CTYPE2']]
self.cunit=[hdu[0].header['CUNIT1'],hdu[0].header['CUNIT2']]
self.crres=np.array([hdu[0].header['CRRES1'],hdu[0].header['CRRES2']])
# Compute image properties
self.sx=np.sqrt(self.cd[0,0]**2+self.cd[1,0]**2)
self.sy=np.sqrt(self.cd[0,1]**2+self.cd[1,1]**2)
self.wx=self.nx*self.sx
self.wy=self.ny*self.sy
self.vmin=np.mean(self.zmax)-2.0*np.std(self.zmax)
self.vmax=np.mean(self.zmax)+6.0*np.std(self.zmax)
# Setup WCS
self.w=wcs.WCS(naxis=2)
self.w.wcs.crpix=self.crpix
self.w.wcs.crval=self.crval
self.w.wcs.cd=self.cd
self.w.wcs.ctype=self.ctype
self.w.wcs.set_pv([(2,1,45.0)])
def significant(self,sigma,x0,y0,dxdt,dydt,rmin=10.0):
"""Extract significant points"""
# Generate sigma frame
zsig=(self.zmax-self.zavg)/(self.zstd+1e-9)
# Select
c=(zsig>sigma)
# Positions
xm,ym=np.meshgrid(np.arange(self.nx),np.arange(self.ny))
x,y=np.ravel(xm[c]),np.ravel(ym[c])
inum=np.ravel(self.znum[c]).astype('int')
sig=np.ravel(zsig[c])
t=np.array([self.dt[i] for i in inum])
# Predicted positions
xr=x0+dxdt*t
yr=y0+dydt*t
r=np.sqrt((x-xr)**2+(y-yr)**2)
c=r<rmin
return x[c],y[c],t[c],sig[c]
def track(self,dxdt,dydt,tref):
"""Track and stack"""
# Empty frame
ztrk=np.zeros_like(self.zavg)
# Loop over frames
for i in range(self.nz):
dx=int(np.round(dxdt*(self.dt[i]-tref)))
dy=int(np.round(dydt*(self.dt[i]-tref)))
# Skip if shift larger than image
if np.abs(dx)>=self.nx:
continue
if np.abs(dy)>=self.ny:
continue
# Extract range
if dx>=0:
i1min,i1max=dx,self.nx-1
i2min,i2max=0,self.nx-dx-1
else:
i1min,i1max=0,self.nx+dx-1
i2min,i2max=-dx,self.nx-1
if dy>=0:
j1min,j1max=dy,self.ny-1
j2min,j2max=0,self.ny-dy-1
else:
j1min,j1max=0,self.ny+dy-1
j2min,j2max=-dy,self.ny-1
zsel=np.where(self.znum==i,self.zmax,0.0)
ztrk[j2min:j2max,i2min:i2max]+=zsel[j1min:j1max,i1min:i1max]
return ztrk
def __repr__(self):
return "%s %dx%dx%d %s %.3f %d %s"%(self.fname,self.nx,self.ny,self.nz,self.nfd,self.texp,self.site_id,self.observer)

45
sun.py 100644
View File

@ -0,0 +1,45 @@
#!/usr/bin/env python
from astropy.coordinates import SkyCoord,EarthLocation,AltAz,get_sun
from astropy.time import Time
import astropy.units as u
import numpy as np
from scipy import optimize,interpolate
import time
def get_sunriseset(t,lat,lon,height,refalt):
loc=EarthLocation(lat=lat*u.deg,lon=lon*u.deg,height=height*u.m)
t0=Time(t,format='unix')
print(t0.isot)
# Compute solar position every 10 minutes
t=Time(t0.mjd+np.arange(160)/160.0,format='mjd',scale='utc')
psun=get_sun(t)
hor=psun.transform_to(AltAz(obstime=t,location=loc))
# Interpolating function
alt_diff=hor.alt.deg-refalt
f=interpolate.interp1d(t.mjd,alt_diff)
# Find sunrise/sunset
sign=alt_diff[1:]*alt_diff[:-1]
idx=np.where(sign<0.0)[0]
print(idx)
for i in idx:
# Set
if alt_diff[i]>alt_diff[i+1]:
tset=Time(optimize.bisect(f,t[i].mjd,t[i+1].mjd),format='mjd',scale='utc')
# Rise
else:
trise=Time(optimize.bisect(f,t[i].mjd,t[i+1].mjd),format='mjd',scale='utc')
return trise.unix,tset.unix
if __name__ == '__main__':
lat,lon,height=52.8344,6.3785,10
t=float(time.time())
t=1520573400.0
print(t,type(t))
trise,tset=get_sunriseset(t,lat,lon,height,-6.0)
print(t,trise,tset)

11
vis.py 100644
View File

@ -0,0 +1,11 @@
#!/usr/bin/env python
from skyfield.positionlib import ICRF
from skyfield.api import load,Topos
ts=load.timescale()
t=ts.now()
observer=Topos(latitude_degrees=52.8344,longitude_degrees=6.3785,elevation_m=10.0)
p=ICRF([0.0,0.0,0.0],observer_data=observer,t=t)
q=p.from_altaz(alt_degrees=30.0,az_degrees=30.0)
print(p,q)