Add calibrate.py for astrometric solving

pull/17/head
Pierros Papadeas 2019-05-12 17:11:15 +03:00
parent c8d8256d2a
commit 550399a360
No known key found for this signature in database
GPG Key ID: 8DB97129D9982991
13 changed files with 367 additions and 309 deletions

View File

@ -205,7 +205,6 @@ if __name__ == '__main__':
logging.basicConfig(filename=os.path.join(path, "acquire.log"), logging.basicConfig(filename=os.path.join(path, "acquire.log"),
level=logging.DEBUG) level=logging.DEBUG)
# Set location # Set location
loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg, loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg,
lon=cfg.getfloat('Common', 'observer_lon')*u.deg, lon=cfg.getfloat('Common', 'observer_lon')*u.deg,
@ -218,7 +217,7 @@ if __name__ == '__main__':
# Get sunrise and sunset times # Get sunrise and sunset times
state, tset, trise = get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise) state, tset, trise = get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise)
# Start/end logic # Start/end logic
if state == "sun never rises": if state == "sun never rises":
logging.info("The sun never rises. Exiting program.") logging.info("The sun never rises. Exiting program.")

51
calibrate.py 100755
View File

@ -0,0 +1,51 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import configparser
import argparse
import subprocess
if __name__ == '__main__':
# Read commandline options
conf_parser = argparse.ArgumentParser(description='Plate solve FITS file' +
' and add WCS on header')
conf_parser.add_argument("-c", "--conf_file",
help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.",
metavar="FILE")
conf_parser.add_argument("-d", "--directory",
help="Specify directory of observations. If no" +
" directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".")
args = conf_parser.parse_args()
# Process commandline options and parse configuration
cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
if args.conf_file:
cfg.read([args.conf_file])
else:
cfg.read('configuration.ini')
path = args.file_dir
extension = 'fits'
files = sorted((f for f in os.listdir(path) if f.endswith('.' + extension)),
key=lambda x: os.path.getctime(os.path.join(path, x)))
if files:
file_for_astrometry = os.path.join(path, files[0])
print("Found " + file_for_astrometry + " for astrometric solving.")
sex_config = cfg.get('Astrometry', 'sex_config')
# Format command
command = "solve-field -O -y -u app -L 37 -H 40 --use-sextractor " + \
"--sextractor-config %s --downsample 2 --x-column X_IMAGE " % sex_config + \
"--y-column Y_IMAGE --sort-column MAG_AUTO --sort-ascending " + \
"%s" % file_for_astrometry
# Run sextractor
subprocess.run(command, shell=True, stderr=subprocess.STDOUT)
else:
print("No fits file found for astrometric solving.")

View File

@ -24,3 +24,6 @@ device_id = 0
camera_x = 720 # Camera horizontal pixel count camera_x = 720 # Camera horizontal pixel count
camera_y = 576 # Camera vertical pixel count camera_y = 576 # Camera vertical pixel count
camera_frames = 250 # Camera frames for each image (25fps*10sec=250) camera_frames = 250 # Camera frames for each image (25fps*10sec=250)
[Astrometry]
sex_config = /path/to/solve.sex

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import print_function from __future__ import print_function
import numpy as np
from astropy.io import ascii from astropy.io import ascii
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.dates as mdates import matplotlib.dates as mdates
@ -14,34 +13,43 @@ import os
if __name__ == "__main__": if __name__ == "__main__":
# Read commandline options # Read commandline options
conf_parser = argparse.ArgumentParser(description='Plot image statistics') conf_parser = argparse.ArgumentParser(description='Plot image statistics')
conf_parser.add_argument("-c", "--conf_file", conf_parser.add_argument("-c",
"--conf_file",
help="Specify configuration file. If no file" + help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.", " is specified 'configuration.ini' is used.",
metavar="FILE") metavar="FILE")
conf_parser.add_argument("-i", "--input", conf_parser.add_argument("-i",
"--input",
help="Specify file to be processed. If no file" + help="Specify file to be processed. If no file" +
" is specified ./imgstat.csv will be used.", " is specified ./imgstat.csv will be used.",
metavar='FILE', default="./imgstat.csv") metavar='FILE',
conf_parser.add_argument("-d", "--directory", default="./imgstat.csv")
conf_parser.add_argument("-d",
"--directory",
help="Specify directory of observations. If no" + help="Specify directory of observations. If no" +
" directory is specified parent will be used.", " directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".") metavar='DIR',
conf_parser.add_argument("-o", "--output", dest='file_dir',
help="Specify output file. Default is 'imgstat.png'", default=".")
metavar='FILE', default="./imgstat.png") conf_parser.add_argument(
"-o",
"--output",
help="Specify output file. Default is 'imgstat.png'",
metavar='FILE',
default="./imgstat.png")
args = conf_parser.parse_args() args = conf_parser.parse_args()
# Process commandline options and parse configuration # Process commandline options and parse configuration
cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';')) cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
if args.conf_file: if args.conf_file:
cfg.read([args.conf_file]) cfg.read([args.conf_file])
else: else:
cfg.read('configuration.ini') cfg.read('configuration.ini')
# Move to processing directory # Move to processing directory
os.chdir(args.file_dir) os.chdir(args.file_dir)
table = ascii.read(args.input, format="csv") table = ascii.read(args.input, format="csv")
t = Time(table['mjd'], format="mjd", scale="utc") t = Time(table['mjd'], format="mjd", scale="utc")
@ -49,13 +57,16 @@ if __name__ == "__main__":
pos = SkyCoord(ra=table['ra'], dec=table['de'], frame="icrs", unit="deg") pos = SkyCoord(ra=table['ra'], dec=table['de'], frame="icrs", unit="deg")
# Set location # Set location
loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg, loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat') * u.deg,
lon=cfg.getfloat('Common', 'observer_lon')*u.deg, lon=cfg.getfloat('Common', 'observer_lon') * u.deg,
height=cfg.getfloat('Common', 'observer_el')*u.m) height=cfg.getfloat('Common', 'observer_el') * u.m)
pa = pos.transform_to(AltAz(obstime=t, location=loc)) pa = pos.transform_to(AltAz(obstime=t, location=loc))
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(20, 10), sharex=True) fig, (ax1, ax2, ax3, ax4) = plt.subplots(4,
1,
figsize=(20, 10),
sharex=True)
date_format = mdates.DateFormatter("%F\n%H:%M:%S") date_format = mdates.DateFormatter("%F\n%H:%M:%S")
fig.autofmt_xdate(rotation=0, ha="center") fig.autofmt_xdate(rotation=0, ha="center")
@ -85,8 +96,6 @@ if __name__ == "__main__":
ax4.set_xlabel("Time (UTC)") ax4.set_xlabel("Time (UTC)")
ax4.set_ylabel("Residuals (arcseconds)") ax4.set_ylabel("Residuals (arcseconds)")
ax4.legend() ax4.legend()
plt.tight_layout() plt.tight_layout()
plt.savefig(args.output) plt.savefig(args.output)

View File

@ -10,6 +10,7 @@ import matplotlib.pyplot as plt
import matplotlib.dates as mdates import matplotlib.dates as mdates
from astropy.time import Time from astropy.time import Time
def generate_keogram(path): def generate_keogram(path):
# Get files # Get files
fnames = sorted(glob.glob(os.path.join(path, "processed/2*.fits"))) fnames = sorted(glob.glob(os.path.join(path, "processed/2*.fits")))
@ -17,13 +18,13 @@ def generate_keogram(path):
# Allocate arrays # Allocate arrays
nx = len(fnames) nx = len(fnames)
ny = cfg.getint('Camera', 'camera_y') ny = cfg.getint('Camera', 'camera_y')
ixmid = cfg.getint('Camera', 'camera_x')//2 ixmid = cfg.getint('Camera', 'camera_x') // 2
keogram = np.zeros(nx*ny).reshape(ny, nx) keogram = np.zeros(nx * ny).reshape(ny, nx)
mjds = np.zeros(nx) mjds = np.zeros(nx)
# Get data # Get data
for i, fname in enumerate(fnames): for i, fname in enumerate(fnames):
if i%10==0: if i % 10 == 0:
print(i, fname) print(i, fname)
# Read file # Read file
@ -41,15 +42,19 @@ def generate_keogram(path):
if __name__ == "__main__": if __name__ == "__main__":
# Read commandline options # Read commandline options
conf_parser = argparse.ArgumentParser(description='Process captured' + conf_parser = argparse.ArgumentParser(description='Process captured' +
' video frames.') ' video frames.')
conf_parser.add_argument("-c", "--conf_file", conf_parser.add_argument("-c",
"--conf_file",
help="Specify configuration file. If no file" + help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.", " is specified 'configuration.ini' is used.",
metavar="FILE") metavar="FILE")
conf_parser.add_argument("-d", "--directory", conf_parser.add_argument("-d",
"--directory",
help="Specify directory of observations. If no" + help="Specify directory of observations. If no" +
" directory is specified parent will be used.", " directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".") metavar='DIR',
dest='file_dir',
default=".")
args = conf_parser.parse_args() args = conf_parser.parse_args()
@ -71,16 +76,20 @@ if __name__ == "__main__":
# Time limits # Time limits
tmin = mdates.date2num(Time(np.min(mjds), format="mjd").datetime) tmin = mdates.date2num(Time(np.min(mjds), format="mjd").datetime)
tmax = mdates.date2num(Time(np.max(mjds), format="mjd").datetime) tmax = mdates.date2num(Time(np.max(mjds), format="mjd").datetime)
# Plot keogram # Plot keogram
fig, ax = plt.subplots(figsize=(15, 5)) fig, ax = plt.subplots(figsize=(15, 5))
ax.imshow(np.log10(keogram), aspect="auto", origin="lower", cmap="magma", extent=[tmin, tmax, 0, 1]) ax.imshow(np.log10(keogram),
aspect="auto",
origin="lower",
cmap="magma",
extent=[tmin, tmax, 0, 1])
ax.axes.get_yaxis().set_visible(False) ax.axes.get_yaxis().set_visible(False)
ax.xaxis_date() ax.xaxis_date()
date_format = mdates.DateFormatter("%F\n%H:%M:%S") date_format = mdates.DateFormatter("%F\n%H:%M:%S")
ax.xaxis.set_major_formatter(date_format) ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate(rotation=0, ha="center") fig.autofmt_xdate(rotation=0, ha="center")
plt.tight_layout() plt.tight_layout()
plt.savefig(os.path.join(args.file_dir, "keogram.png")) plt.savefig(os.path.join(args.file_dir, "keogram.png"))

View File

@ -23,15 +23,19 @@ import shutil
if __name__ == "__main__": if __name__ == "__main__":
# Read commandline options # Read commandline options
conf_parser = argparse.ArgumentParser(description='Process captured' + conf_parser = argparse.ArgumentParser(description='Process captured' +
' video frames.') ' video frames.')
conf_parser.add_argument("-c", "--conf_file", conf_parser.add_argument("-c",
"--conf_file",
help="Specify configuration file. If no file" + help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.", " is specified 'configuration.ini' is used.",
metavar="FILE") metavar="FILE")
conf_parser.add_argument("-d", "--directory", conf_parser.add_argument("-d",
"--directory",
help="Specify directory of observations. If no" + help="Specify directory of observations. If no" +
" directory is specified parent will be used.", " directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".") metavar='DIR',
dest='file_dir',
default=".")
args = conf_parser.parse_args() args = conf_parser.parse_args()
@ -47,9 +51,9 @@ if __name__ == "__main__":
warnings.simplefilter("ignore", AstropyWarning) warnings.simplefilter("ignore", AstropyWarning)
# Set location # Set location
loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg, loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat') * u.deg,
lon=cfg.getfloat('Common', 'observer_lon')*u.deg, lon=cfg.getfloat('Common', 'observer_lon') * u.deg,
height=cfg.getfloat('Common', 'observer_el')*u.m) height=cfg.getfloat('Common', 'observer_el') * u.m)
# Extract settings # Extract settings
# Minimum predicted velocity (pixels/s) # Minimum predicted velocity (pixels/s)
@ -70,7 +74,7 @@ if __name__ == "__main__":
# Statistics file # Statistics file
fstat = open("imgstat.csv", "w") fstat = open("imgstat.csv", "w")
fstat.write("fname,mjd,ra,de,rmsx,rmsy,mean,std,nstars,nused\n") fstat.write("fname,mjd,ra,de,rmsx,rmsy,mean,std,nstars,nused\n")
# Create output dirs # Create output dirs
path = args.file_dir path = args.file_dir
results_path = os.path.join(cfg.get('Common', 'results_path'), results_path = os.path.join(cfg.get('Common', 'results_path'),
@ -88,53 +92,55 @@ if __name__ == "__main__":
while True: while True:
# Get files # Get files
fnames = sorted(glob.glob("2*.fits")) fnames = sorted(glob.glob("2*.fits"))
# Loop over files # Loop over files
for fname in fnames: for fname in fnames:
# Generate star catalog # Generate star catalog
pix_catalog = generate_star_catalog(fname) pix_catalog = generate_star_catalog(fname)
# Calibrate astrometry # Calibrate astrometry
calibrate_from_reference(fname, "test.fits", calibrate_from_reference(fname, "test.fits", pix_catalog)
pix_catalog)
# Generate satellite predictions # Generate satellite predictions
generate_satellite_predictions(fname) generate_satellite_predictions(fname)
# Detect lines with 3D Hough transform # Detect lines with 3D Hough transform
ids = find_hough3d_lines(fname) ids = find_hough3d_lines(fname)
# Extract tracks # Extract tracks
extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, results_path) extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin,
results_path)
# Stars available and used # Stars available and used
nused = np.sum(pix_catalog.flag == 1) nused = np.sum(pix_catalog.flag == 1)
nstars = pix_catalog.nstars nstars = pix_catalog.nstars
# Get properties # Get properties
ff = fourframe(fname) ff = fourframe(fname)
# Write output # Write output
output = "%s %10.6f %10.6f %4d/%4d %5.1f %5.1f %6.2f +- %6.2f"%(ff.fname, ff.crval[0], ff.crval[1], nused, nstars, 3600.0*ff.crres[0], 3600.0*ff.crres[1], np.mean(ff.zavg), np.std(ff.zavg)) output = "%s %10.6f %10.6f %4d/%4d %5.1f %5.1f %6.2f +- %6.2f" % (
ff.fname, ff.crval[0], ff.crval[1], nused, nstars,
3600.0 * ff.crres[0], 3600.0 * ff.crres[1], np.mean(
ff.zavg), np.std(ff.zavg))
if is_calibrated(ff): if is_calibrated(ff):
print(colored(output, "green")) print(colored(output, "green"))
else: else:
print(colored(output, "red")) print(colored(output, "red"))
fstat.write(("%s,%.8lf,%.6f,%.6f,%.3f,%.3f,%.3f," + fstat.write(
"%.3f,%d,%d\n") % (ff.fname, ff.mjd, ff.crval[0], ("%s,%.8lf,%.6f,%.6f,%.3f,%.3f,%.3f," + "%.3f,%d,%d\n") %
ff.crval[1], 3600*ff.crres[0], (ff.fname, ff.mjd, ff.crval[0], ff.crval[1],
3600*ff.crres[1], np.mean(ff.zavg), 3600 * ff.crres[0], 3600 * ff.crres[1], np.mean(
np.std(ff.zavg), nstars, nused)) ff.zavg), np.std(ff.zavg), nstars, nused))
# Move processed files # Move processed files
shutil.move(fname, "processed") shutil.move(fname, "processed")
shutil.move(fname + ".png", "processed") shutil.move(fname + ".png", "processed")
shutil.move(fname + ".id", "processed") shutil.move(fname + ".id", "processed")
shutil.move(fname + ".cat", "processed") shutil.move(fname + ".cat", "processed")
# Sleep # Sleep
time.sleep(10) time.sleep(10)
# Close files # Close files
fstat.close() fstat.close()

4
setup.cfg 100644
View File

@ -0,0 +1,4 @@
[flake8]
max-complexity = 25
max-line-length = 99
ignore = F403, W504, E226, W503

View File

@ -207,6 +207,7 @@ def calibrate_from_reference(fname, ref, pix_catalog):
return w, rmsx, rmsy return w, rmsx, rmsy
def is_calibrated(ff): def is_calibrated(ff):
if (3600.0*ff.crres[0] < 1e-3) | \ if (3600.0*ff.crres[0] < 1e-3) | \
(3600.0*ff.crres[1] < 1e-3) | \ (3600.0*ff.crres[1] < 1e-3) | \

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function from __future__ import print_function
import os import os
import glob
import shutil import shutil
from stvid.stio import fourframe, satid, observation from stvid.stio import fourframe, satid, observation
from stvid.astrometry import is_calibrated from stvid.astrometry import is_calibrated
@ -11,33 +10,36 @@ from scipy import optimize, ndimage
from termcolor import colored from termcolor import colored
import datetime import datetime
# Gaussian model # Gaussian model
def model(a, nx, ny): def model(a, nx, ny):
x, y = np.meshgrid(np.arange(nx), np.arange(ny)) x, y = np.meshgrid(np.arange(nx), np.arange(ny))
dx, dy = (x-a[0])/a[2], (y-a[1])/a[2] dx, dy = (x - a[0]) / a[2], (y - a[1]) / a[2]
arg = -0.5*(dx**2+dy**2) arg = -0.5 * (dx**2 + dy**2)
return a[3]*np.exp(arg)+a[4] return a[3] * np.exp(arg) + a[4]
# Residual function # Residual function
def residual(a, img): def residual(a, img):
ny, nx = img.shape ny, nx = img.shape
mod = model(a, nx, ny) mod = model(a, nx, ny)
return (img-mod).ravel() return (img - mod).ravel()
# Find peak # Find peak
def peakfind(img, w=1.0): def peakfind(img, w=1.0):
# Find approximate location # Find approximate location
ny, nx = img.shape ny, nx = img.shape
i = np.argmax(img) i = np.argmax(img)
y0 = int(i/nx) y0 = int(i / nx)
x0 = i-y0*nx x0 = i - y0 * nx
# Image properties # Image properties
imgavg = np.mean(img) imgavg = np.mean(img)
imgstd = np.std(img) imgstd = np.std(img)
# Estimate # Estimate
a = np.array([x0, y0, w, img[y0, x0]-imgavg, imgavg]) a = np.array([x0, y0, w, img[y0, x0] - imgavg, imgavg])
q, cov_q, infodict, mesg, ier = optimize.leastsq(residual, q, cov_q, infodict, mesg, ier = optimize.leastsq(residual,
a, a,
args=(img), args=(img),
@ -47,82 +49,87 @@ def peakfind(img, w=1.0):
xc, yc, w = q[0], q[1], q[2] xc, yc, w = q[0], q[1], q[2]
# Significance # Significance
sigma = (a[3]-imgavg)/(imgstd+1e-9) sigma = (a[3] - imgavg) / (imgstd + 1e-9)
return xc, yc, w, sigma return xc, yc, w, sigma
# Plot selection # Plot selection
def plot_selection(id, x0, y0, dt=2.0, w=10.0): def plot_selection(id, x0, y0, dt=2.0, w=10.0):
dx, dy = id.x1-id.x0, id.y1-id.y0 dx, dy = id.x1 - id.x0, id.y1 - id.y0
ang = np.arctan2(dy, dx) ang = np.arctan2(dy, dx)
r = np.sqrt(dx**2+dy**2) r = np.sqrt(dx**2 + dy**2)
drdt = r/(id.t1-id.t0) drdt = r / (id.t1 - id.t0)
sa, ca = np.sin(ang), np.cos(ang) sa, ca = np.sin(ang), np.cos(ang)
dx = np.array([-dt, -dt, dt, dt, -dt])*drdt dx = np.array([-dt, -dt, dt, dt, -dt]) * drdt
dy = np.array([w, -w, -w, w, w]) dy = np.array([w, -w, -w, w, w])
x = ca*dx-sa*dy+x0 x = ca * dx - sa * dy + x0
y = sa*dx+ca*dy+y0 y = sa * dx + ca * dy + y0
ppg.pgsci(7) ppg.pgsci(7)
ppg.pgline(x, y) ppg.pgline(x, y)
return return
# Check if point is inside selection # Check if point is inside selection
def inside_selection(ident, tmid, x0, y0, dt=2.0, w=10.0): def inside_selection(ident, tmid, x0, y0, dt=2.0, w=10.0):
dx, dy = ident.x1-ident.x0, ident.y1-ident.y0 dx, dy = ident.x1 - ident.x0, ident.y1 - ident.y0
ang = -np.arctan2(dy, dx) ang = -np.arctan2(dy, dx)
r = np.sqrt(dx**2+dy**2) r = np.sqrt(dx**2 + dy**2)
drdt = r/(ident.t1-ident.t0) drdt = r / (ident.t1 - ident.t0)
sa, ca = np.sin(ang), np.cos(ang) sa, ca = np.sin(ang), np.cos(ang)
xmid = ident.x0+ident.dxdt*tmid xmid = ident.x0 + ident.dxdt * tmid
ymid = ident.y0+ident.dydt*tmid ymid = ident.y0 + ident.dydt * tmid
dx, dy = x0-xmid, y0-ymid dx, dy = x0 - xmid, y0 - ymid
rm = ca*dx-sa*dy rm = ca * dx - sa * dy
wm = sa*dx+ca*dy wm = sa * dx + ca * dy
dtm = rm/drdt dtm = rm / drdt
if (abs(wm) < w) & (abs(dtm) < dt): if (abs(wm) < w) & (abs(dtm) < dt):
return True return True
else: else:
return False return False
# Get COSPAR ID # Get COSPAR ID
def get_cospar(norad, nfd): def get_cospar(norad, nfd):
f = open(os.path.join(os.getenv("ST_DATADIR"), "data/desig.txt")) f = open(os.path.join(os.getenv("ST_DATADIR"), "data/desig.txt"))
lines = f.readlines() lines = f.readlines()
f.close() f.close()
try: try:
cospar = ([line for line in lines if str(norad) in line])[0].split()[1] cospar = ([line for line in lines if str(norad) in line])[0].split()[1]
except IndexError: except IndexError:
t = datetime.datetime.strptime(nfd[:-4], "%Y-%m-%dT%H:%M:%S") t = datetime.datetime.strptime(nfd[:-4], "%Y-%m-%dT%H:%M:%S")
doy = int(t.strftime("%y%j"))+500 doy = int(t.strftime("%y%j")) + 500
cospar = "%sA"%doy cospar = "%sA" % doy
return "%2s %s" % (cospar[0:2], cospar[2:]) return "%2s %s" % (cospar[0:2], cospar[2:])
# IOD position format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc) # IOD position format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc)
def format_position(ra, de): def format_position(ra, de):
ram = 60.0*ra/15.0 ram = 60.0 * ra / 15.0
rah = int(np.floor(ram/60.0)) rah = int(np.floor(ram / 60.0))
ram -= 60.0*rah ram -= 60.0 * rah
des = np.sign(de) des = np.sign(de)
dem = 60.0*np.abs(de) dem = 60.0 * np.abs(de)
ded = int(np.floor(dem/60.0)) ded = int(np.floor(dem / 60.0))
dem -= 60.0*ded dem -= 60.0 * ded
if des == -1: if des == -1:
sign = "-" sign = "-"
else: else:
sign = "+" sign = "+"
return ("%02d%06.3f%c%02d%05.2f" return ("%02d%06.3f%c%02d%05.2f" % (rah, ram, sign, ded, dem)).replace(
% (rah, ram, sign, ded, dem)).replace(".", "") ".", "")
# Format IOD line # Format IOD line
def format_iod_line(norad, cospar, site_id, t, ra, de): def format_iod_line(norad, cospar, site_id, t, ra, de):
@ -132,12 +139,10 @@ def format_iod_line(norad, cospar, site_id, t, ra, de):
.replace(":", "") \ .replace(":", "") \
.replace(".", "") .replace(".", "")
return "%05d %-9s %04d G %s 17 25 %s 37 S" % (norad, return "%05d %-9s %04d G %s 17 25 %s 37 S" % (norad, cospar, site_id, tstr,
cospar,
site_id,
tstr,
pstr) pstr)
def store_results(ident, fname, path, iod_line): def store_results(ident, fname, path, iod_line):
# Find destination # Find destination
if ident.catalog.find("classfd.tle") > 0: if ident.catalog.find("classfd.tle") > 0:
@ -159,31 +164,32 @@ def store_results(ident, fname, path, iod_line):
# Print iod line # Print iod line
print(colored(iod_line, color)) print(colored(iod_line, color))
# Copy files # Copy files
shutil.copy2(fname, dest) shutil.copy2(fname, dest)
shutil.copy2(fname + ".cat", dest) shutil.copy2(fname + ".cat", dest)
shutil.copy2(fname + ".id", dest) shutil.copy2(fname + ".id", dest)
shutil.copy2(fname + ".png", dest) shutil.copy2(fname + ".png", dest)
try: try:
shutil.move(fname.replace(".fits", "_%05d.png"%ident.norad), dest) shutil.move(fname.replace(".fits", "_%05d.png" % ident.norad), dest)
except: except Exception:
pass pass
# Write iodline # Write iodline
fp = open(outfname, "a") fp = open(outfname, "a")
fp.write("%s\n" % iod_line) fp.write("%s\n" % iod_line)
fp.close() fp.close()
return return
def plot_header(fname, ff, iod_line): def plot_header(fname, ff, iod_line):
# ppgplot arrays # ppgplot arrays
heat_l = np.array([0.0, 0.2, 0.4, 0.6, 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_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_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]) heat_b = np.array([0.0, 0.0, 0.0, 0.3, 1.0])
# Plot # Plot
ppg.pgopen(fname) ppg.pgopen(fname)
ppg.pgpap(0.0, 1.0) ppg.pgpap(0.0, 1.0)
@ -191,29 +197,21 @@ def plot_header(fname, ff, iod_line):
ppg.pgsch(0.8) ppg.pgsch(0.8)
ppg.pgmtxt("T", 6.0, 0.0, 0.0, ppg.pgmtxt("T", 6.0, 0.0, 0.0,
"UT Date: %.23s COSPAR ID: %04d" "UT Date: %.23s COSPAR ID: %04d" % (ff.nfd, ff.site_id))
% (ff.nfd, ff.site_id))
if is_calibrated(ff): if is_calibrated(ff):
ppg.pgsci(1) ppg.pgsci(1)
else: else:
ppg.pgsci(2) ppg.pgsci(2)
ppg.pgmtxt("T", 4.8, 0.0, 0.0, ppg.pgmtxt(
"R.A.: %10.5f (%4.1f'') Decl.: %10.5f (%4.1f'')" "T", 4.8, 0.0, 0.0, "R.A.: %10.5f (%4.1f'') Decl.: %10.5f (%4.1f'')" %
% (ff.crval[0], (ff.crval[0], 3600.0 * ff.crres[0], ff.crval[1], 3600.0 * ff.crres[1]))
3600.0*ff.crres[0],
ff.crval[1],
3600.0*ff.crres[1]))
ppg.pgsci(1) ppg.pgsci(1)
ppg.pgmtxt("T", 3.6, 0.0, 0.0, ppg.pgmtxt("T", 3.6, 0.0, 0.0, ("FoV: %.2f\\(2218)x%.2f\\(2218) "
("FoV: %.2f\\(2218)x%.2f\\(2218) " "Scale: %.2f''x%.2f'' pix\\u-1\\d") %
"Scale: %.2f''x%.2f'' pix\\u-1\\d") (ff.wx, ff.wy, 3600.0 * ff.sx, 3600.0 * ff.sy))
% (ff.wx, ff.wy, 3600.0*ff.sx, 3600.0*ff.sy)) ppg.pgmtxt(
ppg.pgmtxt("T", 2.4, 0.0, 0.0, "T", 2.4, 0.0, 0.0, "Stat: %5.1f+-%.1f (%.1f-%.1f)" %
"Stat: %5.1f+-%.1f (%.1f-%.1f)" (np.mean(ff.zmax), np.std(ff.zmax), ff.zmaxmin, ff.zmaxmax))
% (np.mean(ff.zmax),
np.std(ff.zmax),
ff.zmaxmin,
ff.zmaxmax))
ppg.pgmtxt("T", 0.3, 0.0, 0.0, iod_line) ppg.pgmtxt("T", 0.3, 0.0, 0.0, iod_line)
ppg.pgsch(1.0) ppg.pgsch(1.0)
@ -228,14 +226,14 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
ff = fourframe(fname) ff = fourframe(fname)
# Skip saturated frames # Skip saturated frames
if np.sum(ff.zavg > 240.0)/float(ff.nx*ff.ny) > 0.95: if np.sum(ff.zavg > 240.0) / float(ff.nx * ff.ny) > 0.95:
return return
# Read satelite IDs # Read satelite IDs
try: try:
f = open(fname+".id") f = open(fname + ".id")
except OSError: except OSError:
print("Cannot open", fname+".id") print("Cannot open", fname + ".id")
else: else:
lines = f.readlines() lines = f.readlines()
f.close() f.close()
@ -244,7 +242,7 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
# Parse identifications # Parse identifications
idents = [satid(line) for line in lines] idents = [satid(line) for line in lines]
# Identify unknowns # Identify unknowns
for ident0 in idents: for ident0 in idents:
if ident0.catalog == "unidentified": if ident0.catalog == "unidentified":
@ -264,67 +262,60 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
ident0.state = ident1.state ident0.state = ident1.state
ident1.state = "remove" ident1.state = "remove"
break break
# Loop over identifications # Loop over identifications
for ident in idents: for ident in idents:
# Skip superseded unknowns # Skip superseded unknowns
if ident.state == "remove": if ident.state == "remove":
continue continue
# Skip slow moving objects # Skip slow moving objects
drdt = np.sqrt(ident.dxdt**2+ident.dydt**2) drdt = np.sqrt(ident.dxdt**2 + ident.dydt**2)
if drdt < drdtmin: if drdt < drdtmin:
continue continue
# Extract significant pixels along a track # Extract significant pixels along a track
x, y, t, sig = ff.significant_pixels_along_track(trksig, x, y, t, sig = ff.significant_pixels_along_track(
ident.x0, trksig, ident.x0, ident.y0, ident.dxdt, ident.dydt, trkrmin)
ident.y0,
ident.dxdt,
ident.dydt,
trkrmin)
# Fit tracks # Fit tracks
if len(t) > ntrkmin: if len(t) > ntrkmin:
# Get times # Get times
tmin = np.min(t) tmin = np.min(t)
tmax = np.max(t) tmax = np.max(t)
tmid = 0.5*(tmax+tmin) tmid = 0.5 * (tmax + tmin)
mjd = ff.mjd+tmid/86400.0 mjd = ff.mjd + tmid / 86400.0
# Skip if no variance in time # Skip if no variance in time
if np.std(t-tmid) == 0.0: if np.std(t - tmid) == 0.0:
continue continue
# Very simple polynomial fit; no weighting, no cleaning # Very simple polynomial fit; no weighting, no cleaning
px = np.polyfit(t-tmid, x, 1) px = np.polyfit(t - tmid, x, 1)
py = np.polyfit(t-tmid, y, 1) py = np.polyfit(t - tmid, y, 1)
# Extract results # Extract results
x0, y0 = px[1], py[1] x0, y0 = px[1], py[1]
dxdt, dydt = px[0], py[0] dxdt, dydt = px[0], py[0]
xmin = x0+dxdt*(tmin-tmid) xmin = x0 + dxdt * (tmin - tmid)
ymin = y0+dydt*(tmin-tmid) ymin = y0 + dydt * (tmin - tmid)
xmax = x0+dxdt*(tmax-tmid) xmax = x0 + dxdt * (tmax - tmid)
ymax = y0+dydt*(tmax-tmid) ymax = y0 + dydt * (tmax - tmid)
cospar = get_cospar(ident.norad, ff.nfd) cospar = get_cospar(ident.norad, ff.nfd)
obs = observation(ff, mjd, x0, y0) obs = observation(ff, mjd, x0, y0)
iod_line = "%s" % format_iod_line(ident.norad, iod_line = "%s" % format_iod_line(ident.norad, cospar, ff.site_id,
cospar, obs.nfd, obs.ra, obs.de)
ff.site_id,
obs.nfd,
obs.ra,
obs.de)
# Create diagnostic plot # Create diagnostic plot
plot_header(fname.replace(".fits", "_%05d.png/png" % ident.norad), ff, iod_line) plot_header(fname.replace(".fits", "_%05d.png/png" % ident.norad),
ff, iod_line)
ppg.pgimag(ff.zmax, ff.nx, ff.ny, 0, ff.nx-1, ppg.pgimag(ff.zmax, ff.nx, ff.ny, 0, ff.nx - 1, 0, ff.ny - 1,
0, ff.ny-1, ff.zmaxmax, ff.zmaxmin, tr) ff.zmaxmax, ff.zmaxmin, tr)
ppg.pgbox("BCTSNI", 0., 0, "BCTSNI", 0., 0) ppg.pgbox("BCTSNI", 0., 0, "BCTSNI", 0., 0)
ppg.pgstbg(1) ppg.pgstbg(1)
ppg.pgsci(0) ppg.pgsci(0)
if ident.catalog.find("classfd.tle") > 0: if ident.catalog.find("classfd.tle") > 0:
ppg.pgsci(4) ppg.pgsci(4)
@ -338,7 +329,7 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
ppg.pgtext(np.array([x0]), np.array([y0]), " %05d" % ident.norad) ppg.pgtext(np.array([x0]), np.array([y0]), " %05d" % ident.norad)
ppg.pgsch(1.0) ppg.pgsch(1.0)
ppg.pgsci(1) ppg.pgsci(1)
ppg.pgend() ppg.pgend()
# Store results # Store results
@ -347,7 +338,7 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
elif ident.catalog.find("classfd.tle") > 0: elif ident.catalog.find("classfd.tle") > 0:
# Track and stack # Track and stack
t = np.linspace(0.0, ff.texp) t = np.linspace(0.0, ff.texp)
x, y = ident.x0+ident.dxdt*t, ident.y0+ident.dydt*t x, y = ident.x0 + ident.dxdt * t, ident.y0 + ident.dydt * t
c = (x > 0) & (x < ff.nx) & (y > 0) & (y < ff.ny) c = (x > 0) & (x < ff.nx) & (y > 0) & (y < ff.ny)
# Skip if no points selected # Skip if no points selected
@ -356,27 +347,27 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
# Compute track # Compute track
tmid = np.mean(t[c]) tmid = np.mean(t[c])
mjd = ff.mjd+tmid/86400.0 mjd = ff.mjd + tmid / 86400.0
xmid = ident.x0+ident.dxdt*tmid xmid = ident.x0 + ident.dxdt * tmid
ymid = ident.y0+ident.dydt*tmid ymid = ident.y0 + ident.dydt * tmid
ztrk = ndimage.gaussian_filter(ff.track(ident.dxdt, ident.dydt, tmid), ztrk = ndimage.gaussian_filter(
1.0) ff.track(ident.dxdt, ident.dydt, tmid), 1.0)
vmin = np.mean(ztrk)-2.0*np.std(ztrk) vmin = np.mean(ztrk) - 2.0 * np.std(ztrk)
vmax = np.mean(ztrk)+6.0*np.std(ztrk) vmax = np.mean(ztrk) + 6.0 * np.std(ztrk)
# Select region # Select region
xmin = int(xmid-100) xmin = int(xmid - 100)
xmax = int(xmid+100) xmax = int(xmid + 100)
ymin = int(ymid-100) ymin = int(ymid - 100)
ymax = int(ymid+100) ymax = int(ymid + 100)
if xmin < 0: if xmin < 0:
xmin = 0 xmin = 0
if ymin < 0: if ymin < 0:
ymin = 0 ymin = 0
if xmax > ff.nx: if xmax > ff.nx:
xmax = ff.nx-1 xmax = ff.nx - 1
if ymax > ff.ny: if ymax > ff.ny:
ymax = ff.ny-1 ymax = ff.ny - 1
# Find peak # Find peak
x0, y0, w, sigma = peakfind(ztrk[ymin:ymax, xmin:xmax]) x0, y0, w, sigma = peakfind(ztrk[ymin:ymax, xmin:xmax])
@ -394,20 +385,15 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
# Format IOD line # Format IOD line
cospar = get_cospar(ident.norad, ff.nfd) cospar = get_cospar(ident.norad, ff.nfd)
obs = observation(ff, mjd, x0, y0) obs = observation(ff, mjd, x0, y0)
iod_line = "%s" % format_iod_line(ident.norad, iod_line = "%s" % format_iod_line(ident.norad, cospar, ff.site_id,
cospar, obs.nfd, obs.ra, obs.de)
ff.site_id,
obs.nfd,
obs.ra,
obs.de)
# Create diagnostic plot # Create diagnostic plot
plot_header(fname.replace(".fits", "_%05d.png/png" % ident.norad), ff, iod_line) plot_header(fname.replace(".fits", "_%05d.png/png" % ident.norad),
ff, iod_line)
ppg.pgimag(ztrk, ff.nx, ff.ny, 0, ff.nx - 1, 0, ff.ny - 1, vmax,
ppg.pgimag(ztrk, ff.nx, ff.ny, 0, ff.nx-1, vmin, tr)
0, ff.ny-1, vmax, vmin, tr)
ppg.pgbox("BCTSNI", 0., 0, "BCTSNI", 0., 0) ppg.pgbox("BCTSNI", 0., 0, "BCTSNI", 0., 0)
ppg.pgstbg(1) ppg.pgstbg(1)
@ -423,8 +409,7 @@ def extract_tracks(fname, trkrmin, drdtmin, trksig, ntrkmin, path):
ppg.pgdraw(ident.x1, ident.y1) ppg.pgdraw(ident.x1, ident.y1)
ppg.pgpt(np.array([x0]), np.array([y0]), 4) ppg.pgpt(np.array([x0]), np.array([y0]), 4)
ppg.pgsch(0.65) ppg.pgsch(0.65)
ppg.pgtext(np.array([ident.x0]), ppg.pgtext(np.array([ident.x0]), np.array([ident.y0]),
np.array([ident.y0]),
" %05d" % ident.norad) " %05d" % ident.norad)
ppg.pgsch(1.0) ppg.pgsch(1.0)
ppg.pgsci(1) ppg.pgsci(1)

View File

@ -1,17 +1,17 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function from __future__ import print_function
import os
import subprocess import subprocess
from stvid.stio import fourframe from stvid.stio import fourframe
from stvid.stio import satid from stvid.stio import satid
from stvid.stio import observation
def generate_satellite_predictions(fname): def generate_satellite_predictions(fname):
# Format command # Format command
command = "satid %s %s.png/png" % (fname, fname) command = "satid %s %s.png/png" % (fname, fname)
# Run command # Run command
output = subprocess.check_output(command, shell=True, output = subprocess.check_output(command,
shell=True,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
return output return output
@ -28,9 +28,9 @@ def find_hough3d_lines(fname, ntrkmin=20, dr=8):
x, y, z, t, sig = ff.selection_mask(5.0, 40.0) x, y, z, t, sig = ff.selection_mask(5.0, 40.0)
# Skip if not enough points # Skip if not enough points
if len(t)<2: if len(t) < 2:
return [] return []
# Save points to temporary file # Save points to temporary file
with open("/tmp/hough.dat", "w") as f: with open("/tmp/hough.dat", "w") as f:
for i in range(len(t)): for i in range(len(t)):
@ -38,12 +38,13 @@ def find_hough3d_lines(fname, ntrkmin=20, dr=8):
f.close() f.close()
# Run 3D Hough line-finding algorithm # Run 3D Hough line-finding algorithm
command = "hough3dlines -dx %d -minvotes %d %s" % (dr, ntrkmin, "/tmp/hough.dat") command = "hough3dlines -dx %d -minvotes %d %s" % (dr, ntrkmin,
"/tmp/hough.dat")
try: try:
output = subprocess.check_output(command, output = subprocess.check_output(command,
shell=True, shell=True,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except: except Exception:
return [] return []
# Clean output (a bit cluncky) # Clean output (a bit cluncky)
@ -56,16 +57,18 @@ def find_hough3d_lines(fname, ntrkmin=20, dr=8):
# Generate identifications # Generate identifications
lines = [] lines = []
s = cleaned_output.split() s = cleaned_output.split()
for i in range(len(s)//7): for i in range(len(s) // 7):
# Extract points # Extract points
x0, y0, z0 = float(s[1+7*i]), float(s[2+7*i]), float(s[3+7*i]) x0, y0, z0 = float(s[1 + 7 * i]), float(s[2 + 7 * i]), float(s[3 +
dx, dy, dz = float(s[4+7*i]), float(s[5+7*i]), float(s[6+7*i]) 7 * i])
dx, dy, dz = float(s[4 + 7 * i]), float(s[5 + 7 * i]), float(s[6 +
7 * i])
# Reconstruct start and end points # Reconstruct start and end points
xmin = x0-z0*dx/(dz+1e-9) xmin = x0 - z0 * dx / (dz + 1e-9)
xmax = x0+(ff.nz-z0)*dx/(dz+1e-9) xmax = x0 + (ff.nz - z0) * dx / (dz + 1e-9)
ymin = y0-z0*dy/(dz+1e-9) ymin = y0 - z0 * dy / (dz + 1e-9)
ymax = y0+(ff.nz-z0)*dy/(dz+1e-9) ymax = y0 + (ff.nz - z0) * dy / (dz + 1e-9)
# Output line # Output line
line = "%.23s %8.3f %8.3f %8.3f %8.3f %8.5f %s unidentified sunlit\n" %\ line = "%.23s %8.3f %8.3f %8.3f %8.3f %8.5f %s unidentified sunlit\n" %\
@ -77,5 +80,5 @@ def find_hough3d_lines(fname, ntrkmin=20, dr=8):
for line in lines: for line in lines:
fp.write(line) fp.write(line)
fp.close() fp.close()
return [satid(line) for line in lines] return [satid(line) for line in lines]

View File

@ -22,7 +22,9 @@ class observation:
self.nfd = Time(self.mjd, format='mjd', scale='utc').isot self.nfd = Time(self.mjd, format='mjd', scale='utc').isot
# Correct for rotation # Correct for rotation
tobs = Time(ff.mjd+0.5*ff.texp/86400.0, format='mjd', scale='utc') tobs = Time(ff.mjd + 0.5 * ff.texp / 86400.0,
format='mjd',
scale='utc')
tobs.delta_ut1_utc = 0 tobs.delta_ut1_utc = 0
hobs = tobs.sidereal_time("mean", longitude=0.0).degree hobs = tobs.sidereal_time("mean", longitude=0.0).degree
tmid = Time(self.mjd, format='mjd', scale='utc') tmid = Time(self.mjd, format='mjd', scale='utc')
@ -31,7 +33,7 @@ class observation:
# Compute ra/dec # Compute ra/dec
world = ff.w.wcs_pix2world(np.array([[self.x0, self.y0]]), 1) world = ff.w.wcs_pix2world(np.array([[self.x0, self.y0]]), 1)
self.ra = world[0, 0]+hobs-hmid self.ra = world[0, 0] + hobs - hmid
self.de = world[0, 1] self.de = world[0, 1]
@ -50,15 +52,13 @@ class satid:
self.norad = int(s[6]) self.norad = int(s[6])
self.catalog = s[7] self.catalog = s[7]
self.state = s[8] self.state = s[8]
self.dxdt = (self.x1-self.x0)/(self.t1-self.t0) self.dxdt = (self.x1 - self.x0) / (self.t1 - self.t0)
self.dydt = (self.y1-self.y0)/(self.t1-self.t0) self.dydt = (self.y1 - self.y0) / (self.t1 - self.t0)
def __repr__(self): def __repr__(self):
return "%s %f %f %f -> %f %f %f %d %s %s" % (self.nfd, self.x0, return "%s %f %f %f -> %f %f %f %d %s %s" % (
self.y0, self.t0, self.nfd, self.x0, self.y0, self.t0, self.x1, self.y1, self.t1,
self.x1, self.y1, self.norad, self.catalog, self.state)
self.t1, self.norad,
self.catalog, self.state)
class fourframe: class fourframe:
@ -95,15 +95,15 @@ class fourframe:
self.zavg, self.zstd, self.zmax, self.znum = hdu[0].data self.zavg, self.zstd, self.zmax, self.znum = hdu[0].data
# Generate sigma frame # Generate sigma frame
self.zsig = (self.zmax-self.zavg)/(self.zstd+1e-9) self.zsig = (self.zmax - self.zavg) / (self.zstd + 1e-9)
# Frame properties # Frame properties
self.ny, self.nx = self.zavg.shape self.ny, self.nx = self.zavg.shape
self.nz = hdu[0].header['NFRAMES'] self.nz = hdu[0].header['NFRAMES']
# Read frame time oselfsets # Read frame time oselfsets
self.dt = np.array([hdu[0].header['DT%04d' % i] self.dt = np.array(
for i in range(self.nz)]) [hdu[0].header['DT%04d' % i] for i in range(self.nz)])
# Read header # Read header
self.mjd = hdu[0].header['MJD-OBS'] self.mjd = hdu[0].header['MJD-OBS']
@ -114,30 +114,29 @@ class fourframe:
self.fname = fname self.fname = fname
# Astrometry keywords # Astrometry keywords
self.crpix = np.array([hdu[0].header['CRPIX1'], self.crpix = np.array(
hdu[0].header['CRPIX2']]) [hdu[0].header['CRPIX1'], hdu[0].header['CRPIX2']])
self.crval = np.array([hdu[0].header['CRVAL1'], self.crval = np.array(
hdu[0].header['CRVAL2']]) [hdu[0].header['CRVAL1'], hdu[0].header['CRVAL2']])
self.cd = np.array([[hdu[0].header['CD1_1'], self.cd = np.array(
hdu[0].header['CD1_2']], [[hdu[0].header['CD1_1'], hdu[0].header['CD1_2']],
[hdu[0].header['CD2_1'], [hdu[0].header['CD2_1'], hdu[0].header['CD2_2']]])
hdu[0].header['CD2_2']]])
self.ctype = [hdu[0].header['CTYPE1'], hdu[0].header['CTYPE2']] self.ctype = [hdu[0].header['CTYPE1'], hdu[0].header['CTYPE2']]
self.cunit = [hdu[0].header['CUNIT1'], hdu[0].header['CUNIT2']] self.cunit = [hdu[0].header['CUNIT1'], hdu[0].header['CUNIT2']]
self.crres = np.array([hdu[0].header['CRRES1'], self.crres = np.array(
hdu[0].header['CRRES2']]) [hdu[0].header['CRRES1'], hdu[0].header['CRRES2']])
hdu.close() hdu.close()
# Compute image properties # Compute image properties
self.sx = np.sqrt(self.cd[0, 0]**2+self.cd[1, 0]**2) 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.sy = np.sqrt(self.cd[0, 1]**2 + self.cd[1, 1]**2)
self.wx = self.nx*self.sx self.wx = self.nx * self.sx
self.wy = self.ny*self.sy self.wy = self.ny * self.sy
self.zmaxmin = np.mean(self.zmax)-2.0*np.std(self.zmax) self.zmaxmin = np.mean(self.zmax) - 2.0 * np.std(self.zmax)
self.zmaxmax = np.mean(self.zmax)+6.0*np.std(self.zmax) self.zmaxmax = np.mean(self.zmax) + 6.0 * np.std(self.zmax)
self.zavgmin = np.mean(self.zavg)-2.0*np.std(self.zavg) self.zavgmin = np.mean(self.zavg) - 2.0 * np.std(self.zavg)
self.zavgmax = np.mean(self.zavg)+6.0*np.std(self.zavg) self.zavgmax = np.mean(self.zavg) + 6.0 * np.std(self.zavg)
# Setup WCS # Setup WCS
self.w = wcs.WCS(naxis=2) self.w = wcs.WCS(naxis=2)
@ -163,10 +162,10 @@ class fourframe:
def selection_mask(self, sigma, zstd): def selection_mask(self, sigma, zstd):
"""Create a selection mask""" """Create a selection mask"""
c1 = ndimage.uniform_filter(self.znum, 3, mode='constant') c1 = ndimage.uniform_filter(self.znum, 3, mode='constant')
c2 = ndimage.uniform_filter(self.znum*self.znum, 3, mode='constant') c2 = ndimage.uniform_filter(self.znum * self.znum, 3, mode='constant')
# Add epsilon to keep square root positive # Add epsilon to keep square root positive
z = np.sqrt(c2-c1*c1+1e-9) z = np.sqrt(c2 - c1 * c1 + 1e-9)
# Standard deviation mask # Standard deviation mask
c = z < zstd c = z < zstd
@ -177,7 +176,7 @@ class fourframe:
c = self.zsig < sigma c = self.zsig < sigma
m2 = np.zeros_like(self.zavg) m2 = np.zeros_like(self.zavg)
m2[~c] = 1.0 m2[~c] = 1.0
self.zsel = m1*m2 self.zsel = m1 * m2
# Generate points # Generate points
c = self.zsel == 1.0 c = self.zsel == 1.0
@ -189,12 +188,17 @@ class fourframe:
return x, y, inum, t, sig return x, y, inum, t, sig
def significant_pixels_along_track(self, sigma, x0, y0, def significant_pixels_along_track(self,
dxdt, dydt, rmin=10.0): sigma,
x0,
y0,
dxdt,
dydt,
rmin=10.0):
"""Extract significant pixels along a track""" """Extract significant pixels along a track"""
# Generate sigma frame # Generate sigma frame
zsig = (self.zmax-self.zavg)/(self.zstd+1e-9) zsig = (self.zmax - self.zavg) / (self.zstd + 1e-9)
# Select # Select
c = (zsig > sigma) c = (zsig > sigma)
@ -207,9 +211,9 @@ class fourframe:
t = np.array([self.dt[i] for i in inum]) t = np.array([self.dt[i] for i in inum])
# Predicted positions # Predicted positions
xr = x0+dxdt*t xr = x0 + dxdt * t
yr = y0+dydt*t yr = y0 + dydt * t
r = np.sqrt((x-xr)**2+(y-yr)**2) r = np.sqrt((x - xr)**2 + (y - yr)**2)
c = r < rmin c = r < rmin
return x[c], y[c], t[c], sig[c] return x[c], y[c], t[c], sig[c]
@ -218,7 +222,7 @@ class fourframe:
"""Extract significant pixels""" """Extract significant pixels"""
# Generate sigma frame # Generate sigma frame
zsig = (self.zmax-self.zavg)/(self.zstd+1e-9) zsig = (self.zmax - self.zavg) / (self.zstd + 1e-9)
# Select # Select
c = (zsig > sigma) c = (zsig > sigma)
@ -239,8 +243,8 @@ class fourframe:
# Loop over frames # Loop over frames
for i in range(self.nz): for i in range(self.nz):
dx = int(np.round(dxdt*(self.dt[i]-tref))) dx = int(np.round(dxdt * (self.dt[i] - tref)))
dy = int(np.round(dydt*(self.dt[i]-tref))) dy = int(np.round(dydt * (self.dt[i] - tref)))
# Skip if shift larger than image # Skip if shift larger than image
if np.abs(dx) >= self.nx: if np.abs(dx) >= self.nx:
@ -250,28 +254,23 @@ class fourframe:
# Extract range # Extract range
if dx >= 0: if dx >= 0:
i1min, i1max = dx, self.nx-1 i1min, i1max = dx, self.nx - 1
i2min, i2max = 0, self.nx-dx-1 i2min, i2max = 0, self.nx - dx - 1
else: else:
i1min, i1max = 0, self.nx+dx-1 i1min, i1max = 0, self.nx + dx - 1
i2min, i2max = -dx, self.nx-1 i2min, i2max = -dx, self.nx - 1
if dy >= 0: if dy >= 0:
j1min, j1max = dy, self.ny-1 j1min, j1max = dy, self.ny - 1
j2min, j2max = 0, self.ny-dy-1 j2min, j2max = 0, self.ny - dy - 1
else: else:
j1min, j1max = 0, self.ny+dy-1 j1min, j1max = 0, self.ny + dy - 1
j2min, j2max = -dy, self.ny-1 j2min, j2max = -dy, self.ny - 1
zsel = np.where(self.znum == i, self.zmax, 0.0) zsel = np.where(self.znum == i, self.zmax, 0.0)
ztrk[j2min:j2max, i2min:i2max] += zsel[j1min:j1max, i1min:i1max] ztrk[j2min:j2max, i2min:i2max] += zsel[j1min:j1max, i1min:i1max]
return ztrk return ztrk
def __repr__(self): def __repr__(self):
return "%s %dx%dx%d %s %.3f %d %s" % (self.fname, return "%s %dx%dx%d %s %.3f %d %s" % (self.fname, self.nx, self.ny,
self.nx, self.nz, self.nfd, self.texp,
self.ny, self.site_id, self.observer)
self.nz,
self.nfd,
self.texp,
self.site_id,
self.observer)

View File

@ -13,8 +13,8 @@ def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
# Get time # Get time
nmjd = 64 nmjd = 64
mjd0 = np.floor(tnow.mjd) mjd0 = np.floor(tnow.mjd)
mnow = tnow.mjd-mjd0 mnow = tnow.mjd - mjd0
mjd = np.linspace(mjd0-1.0, mjd0+3.0, nmjd) mjd = np.linspace(mjd0 - 1.0, mjd0 + 3.0, nmjd)
t = Time(mjd, format='mjd', scale='utc') t = Time(mjd, format='mjd', scale='utc')
# Get sun position # Get sun position
@ -28,8 +28,10 @@ def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
# Compute altitude extrema # Compute altitude extrema
de = np.mean(pos.dec) de = np.mean(pos.dec)
minalt = np.arcsin(np.sin(loc.lat)*np.sin(de)-np.cos(loc.lat)*np.cos(de)) minalt = np.arcsin(
maxalt = np.arcsin(np.sin(loc.lat)*np.sin(de)+np.cos(loc.lat)*np.cos(de)) np.sin(loc.lat) * np.sin(de) - np.cos(loc.lat) * np.cos(de))
maxalt = np.arcsin(
np.sin(loc.lat) * np.sin(de) + np.cos(loc.lat) * np.cos(de))
# Never sets, never rises? # Never sets, never rises?
if minalt > min(refalt_set, refalt_rise): if minalt > min(refalt_set, refalt_rise):
@ -38,55 +40,48 @@ def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
return "sun never rises", t[0], t[0] return "sun never rises", t[0], t[0]
# Prevent discontinuities in right ascension # Prevent discontinuities in right ascension
dra = pos[-1].ra-pos[0].ra dra = pos[-1].ra - pos[0].ra
ra = pos.ra.degree ra = pos.ra.degree
if dra < 0.0: if dra < 0.0:
c = pos.ra.degree < 180.0 c = pos.ra.degree < 180.0
ra[c] = pos[c].ra.degree+360.0 ra[c] = pos[c].ra.degree + 360.0
# Set up interpolating function # Set up interpolating function
fra = interpolate.interp1d(t.mjd, ra) fra = interpolate.interp1d(t.mjd, ra)
fde = interpolate.interp1d(t.mjd, pos.dec.degree) fde = interpolate.interp1d(t.mjd, pos.dec.degree)
# Get GMST # Get GMST
gmst0 = Time(mjd0, gmst0 = Time(mjd0, format='mjd',
format='mjd',
scale='utc').sidereal_time('mean', 'greenwich') scale='utc').sidereal_time('mean', 'greenwich')
# Get transit time # Get transit time
mtransit = np.mod((fra(mjd0)*u.degree-loc.lon-gmst0)/(360.0*u.degree), 1.0) mtransit = np.mod(
(fra(mjd0) * u.degree - loc.lon - gmst0) / (360.0 * u.degree), 1.0)
while True: while True:
gmst = gmst0+360.985647*u.deg*mtransit gmst = gmst0 + 360.985647 * u.deg * mtransit
ra = fra(mjd0+mtransit)*u.deg ra = fra(mjd0 + mtransit) * u.deg
ha = gmst+loc.lon-ra ha = gmst + loc.lon - ra
mtransit -= ha/(360.0*u.deg) mtransit -= ha / (360.0 * u.deg)
if np.abs(ha.degree) < 1e-9: if np.abs(ha.degree) < 1e-9:
break break
# Hour angle offset # Hour angle offset
ha0 = np.arccos((np.sin(refalt_set) ha0 = np.arccos(
- np.sin(loc.lat) (np.sin(refalt_set) - np.sin(loc.lat) * np.sin(np.mean(pos.dec))) /
* np.sin(np.mean(pos.dec))) (np.cos(loc.lat) * np.cos(np.mean(pos.dec))))
/ (np.cos(loc.lat)
* np.cos(np.mean(pos.dec))))
# Get set time # Get set time
mset = mtransit+ha0/(360.0*u.deg) mset = mtransit + ha0 / (360.0 * u.deg)
while True: while True:
gmst = gmst0+360.985647*u.deg*mset gmst = gmst0 + 360.985647 * u.deg * mset
ra = fra(mjd0+mset)*u.deg ra = fra(mjd0 + mset) * u.deg
de = fde(mjd0+mset)*u.deg de = fde(mjd0 + mset) * u.deg
ha = gmst+loc.lon-ra ha = gmst + loc.lon - ra
alt = np.arcsin(np.sin(loc.lat) alt = np.arcsin(
* np.sin(de) np.sin(loc.lat) * np.sin(de) +
+ np.cos(loc.lat) np.cos(loc.lat) * np.cos(de) * np.cos(ha))
* np.cos(de) dm = (alt - refalt_set) / (360.0 * u.deg * np.cos(de) *
* np.cos(ha)) np.cos(loc.lat) * np.sin(ha))
dm = (alt-refalt_set)/(360.0
* u.deg
* np.cos(de)
* np.cos(loc.lat)
* np.sin(ha))
mset += dm mset += dm
# Break loop or find sunset on next day # Break loop or find sunset on next day
@ -97,25 +92,20 @@ def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
mset += 1.0 mset += 1.0
# Set set time # Set set time
tset = Time(mjd0+mset.value, format='mjd', scale='utc') tset = Time(mjd0 + mset.value, format='mjd', scale='utc')
# Get rise time # Get rise time
mrise = mtransit-ha0/(360.0*u.deg) mrise = mtransit - ha0 / (360.0 * u.deg)
while True: while True:
gmst = gmst0+360.985647*u.deg*mrise gmst = gmst0 + 360.985647 * u.deg * mrise
ra = fra(mjd0+mrise)*u.deg ra = fra(mjd0 + mrise) * u.deg
de = fde(mjd0+mrise)*u.deg de = fde(mjd0 + mrise) * u.deg
ha = gmst+loc.lon-ra ha = gmst + loc.lon - ra
alt = np.arcsin(np.sin(loc.lat) alt = np.arcsin(
* np.sin(de) np.sin(loc.lat) * np.sin(de) +
+ np.cos(loc.lat) np.cos(loc.lat) * np.cos(de) * np.cos(ha))
* np.cos(de) dm = (alt - refalt_rise) / (360.0 * u.deg * np.cos(de) *
* np.cos(ha)) np.cos(loc.lat) * np.sin(ha))
dm = (alt-refalt_rise)/(360.0
* u.deg
* np.cos(de)
* np.cos(loc.lat)
* np.sin(ha))
mrise += dm mrise += dm
# Break loop or find sunrise on next day # Break loop or find sunrise on next day
@ -126,6 +116,6 @@ def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
mrise += 1.0 mrise += 1.0
# Set rise time # Set rise time
trise = Time(mjd0+mrise.value, format='mjd', scale='utc') trise = Time(mjd0 + mrise.value, format='mjd', scale='utc')
return "sun rises and sets", tset, trise return "sun rises and sets", tset, trise

View File

@ -3,7 +3,6 @@ from __future__ import print_function
import configparser import configparser
import argparse import argparse
from spacetrack import SpaceTrackClient from spacetrack import SpaceTrackClient
import subprocess
from shutil import copyfile from shutil import copyfile
import datetime import datetime
from io import BytesIO from io import BytesIO